index.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <template>
  2. <div v-show="state.isShowLockScreen">
  3. <div class="layout-lock-screen-mask"></div>
  4. <div class="layout-lock-screen-img" :class="{ 'layout-lock-screen-filter': state.isShowLoockLogin }"></div>
  5. <div class="layout-lock-screen">
  6. <div
  7. class="layout-lock-screen-date"
  8. ref="layoutLockScreenDateRef"
  9. @mousedown="onDown"
  10. @mousemove="onMove"
  11. @mouseup="onEnd"
  12. @touchstart.stop="onDown"
  13. @touchmove.stop="onMove"
  14. @touchend.stop="onEnd"
  15. >
  16. <div class="layout-lock-screen-date-box">
  17. <div class="layout-lock-screen-date-box-time">
  18. {{ state.time.hm }}:<span>{{ state.time.s }}</span>
  19. </div>
  20. <div class="layout-lock-screen-date-box-info">{{ state.time.mdq }}</div>
  21. </div>
  22. <div class="layout-lock-screen-date-top">
  23. <SvgIcon name="ele-Top" />
  24. <div class="layout-lock-screen-date-top-text">上滑解锁</div>
  25. </div>
  26. </div>
  27. <transition name="el-zoom-in-center">
  28. <div v-show="state.isShowLoockLogin" class="layout-lock-screen-login">
  29. <div class="layout-lock-screen-login-box">
  30. <div class="layout-lock-screen-login-box-name">{{ userInfos.name }}</div>
  31. <div class="layout-lock-screen-login-box-value">
  32. <el-input
  33. placeholder="请输入密码"
  34. ref="layoutLockScreenInputRef"
  35. v-model="state.lockScreenPassword"
  36. @keyup.enter.native.stop="onLockScreenSubmit()"
  37. clearable
  38. >
  39. <template #append>
  40. <el-button @click="onLockScreenSubmit">
  41. <el-icon class="el-input__icon">
  42. <ele-Right />
  43. </el-icon>
  44. </el-button>
  45. </template>
  46. </el-input>
  47. </div>
  48. </div>
  49. <div class="layout-lock-screen-login-icon">
  50. <!-- <SvgIcon name="ele-Microphone" :size="20" />
  51. <SvgIcon name="ele-AlarmClock" :size="20" /> -->
  52. <SvgIcon name="ele-SwitchButton" size="20px" @click="fogetPwd" />
  53. </div>
  54. </div>
  55. </transition>
  56. </div>
  57. </div>
  58. </template>
  59. <script setup lang="ts" name="layoutLockScreen">
  60. import {nextTick, onMounted, onUnmounted, reactive, ref} from 'vue';
  61. import {formatDate} from '/@/utils/formatTime';
  62. import {Cookie, Local, Session} from '/@/utils/storage';
  63. import {storeToRefs} from 'pinia';
  64. import {useThemeConfig} from '/@/stores/themeConfig';
  65. import {useUserInfo} from '/@/stores/userInfo';
  66. import {ElMessage, ElMessageBox} from 'element-plus';
  67. // 定义接口来定义对象的类型
  68. interface LockScreenState {
  69. transparency: number;
  70. downClientY: number;
  71. moveDifference: number;
  72. isShowLoockLogin: boolean;
  73. isFlags: boolean;
  74. querySelectorEl: HTMLElement | string;
  75. time: {
  76. hm: string;
  77. s: string;
  78. mdq: string;
  79. };
  80. setIntervalTime: number;
  81. isShowLockScreen: boolean;
  82. isShowLockScreenIntervalTime: number;
  83. lockScreenPassword: string;
  84. }
  85. // 定义变量内容
  86. const layoutLockScreenInputRef = ref<RefType>();
  87. const storesThemeConfig = useThemeConfig();
  88. const { themeConfig } = storeToRefs(storesThemeConfig);
  89. const storesUserInfo = useUserInfo();
  90. const {userInfos} = storeToRefs(storesUserInfo);
  91. const state = reactive<LockScreenState>({
  92. transparency: 1,
  93. downClientY: 0,
  94. moveDifference: 0,
  95. isShowLoockLogin: false,
  96. isFlags: false,
  97. querySelectorEl: '',
  98. time: {
  99. hm: '',
  100. s: '',
  101. mdq: '',
  102. },
  103. setIntervalTime: 0,
  104. isShowLockScreen: false,
  105. isShowLockScreenIntervalTime: 0,
  106. lockScreenPassword: '',
  107. });
  108. // 鼠标按下
  109. const onDown = (down: any) => {
  110. state.isFlags = true;
  111. state.downClientY = down.touches ? down.touches[0].clientY : down.clientY;
  112. };
  113. // 鼠标移动
  114. const onMove = (move: any) => {
  115. if (state.isFlags) {
  116. const el = <HTMLElement>state.querySelectorEl;
  117. const opacitys = (state.transparency -= 1 / 200);
  118. if (move.touches) {
  119. state.moveDifference = move.touches[0].clientY - state.downClientY;
  120. } else {
  121. state.moveDifference = move.clientY - state.downClientY;
  122. }
  123. if (state.moveDifference >= 0) return false;
  124. el.setAttribute('style', `top:${state.moveDifference}px;cursor:pointer;opacity:${opacitys};`);
  125. if (state.moveDifference < -400) {
  126. el.setAttribute('style', `top:${-el.clientHeight}px;cursor:pointer;transition:all 0.3s ease;`);
  127. state.moveDifference = -el.clientHeight;
  128. setTimeout(() => {
  129. el && el.parentNode?.removeChild(el);
  130. }, 300);
  131. }
  132. if (state.moveDifference === -el.clientHeight) {
  133. state.isShowLoockLogin = true;
  134. layoutLockScreenInputRef.value.focus();
  135. }
  136. }
  137. };
  138. // 鼠标松开
  139. const onEnd = () => {
  140. state.isFlags = false;
  141. state.transparency = 1;
  142. if (state.moveDifference >= -400) {
  143. (<HTMLElement>state.querySelectorEl).setAttribute('style', `top:0px;opacity:1;transition:all 0.3s ease;`);
  144. }
  145. };
  146. const layoutLockScreenDateRef = ref<RefType>();
  147. // 获取要拖拽的初始元素
  148. const initGetElement = () => {
  149. nextTick(() => {
  150. state.querySelectorEl = layoutLockScreenDateRef.value;
  151. });
  152. };
  153. // 时间初始化
  154. const initTime = () => {
  155. state.time.hm = formatDate(new Date(), 'HH:MM');
  156. state.time.s = formatDate(new Date(), 'SS');
  157. state.time.mdq = formatDate(new Date(), 'mm月dd日,WWW');
  158. };
  159. // 时间初始化定时器
  160. const initSetTime = () => {
  161. initTime();
  162. state.setIntervalTime = window.setInterval(() => {
  163. initTime();
  164. }, 1000);
  165. };
  166. // 锁屏时间定时器
  167. const initLockScreen = () => {
  168. state.isShowLockScreen = true;
  169. setLocalThemeConfig();
  170. };
  171. // 存储布局配置
  172. const setLocalThemeConfig = () => {
  173. themeConfig.value.isDrawer = false;
  174. Local.set('themeConfig', themeConfig.value);
  175. };
  176. // 密码输入点击事件
  177. const onLockScreenSubmit = () => {
  178. if (Session.get('lockPwd') != state.lockScreenPassword) {
  179. ElMessage({
  180. message: '锁屏密码错误,请重试',
  181. type: 'warning',
  182. });
  183. return;
  184. }
  185. themeConfig.value.isLockScreen = false;
  186. Local.set('themeConfig', themeConfig.value);
  187. };
  188. const fogetPwd = () => {
  189. ElMessageBox.confirm(`忘记密码重新进入系统,是否继续?`, '提示', {
  190. confirmButtonText: '确认',
  191. cancelButtonText: '取消',
  192. type: 'warning',
  193. draggable: true,
  194. cancelButtonClass: 'default-button',
  195. autofocus: false,
  196. })
  197. .then(() => {
  198. setLocalThemeConfig();
  199. // 清除缓存/token等
  200. Session.clear();
  201. Cookie.clear();
  202. Local.clear();
  203. window.location.reload();
  204. })
  205. .catch(() => {});
  206. };
  207. // 页面加载时
  208. onMounted(() => {
  209. initGetElement();
  210. initSetTime();
  211. initLockScreen();
  212. });
  213. // 页面卸载时
  214. onUnmounted(() => {
  215. window.clearInterval(state.setIntervalTime);
  216. window.clearInterval(state.isShowLockScreenIntervalTime);
  217. });
  218. </script>
  219. <style scoped lang="scss">
  220. .layout-lock-screen-fixed {
  221. position: fixed;
  222. top: 0;
  223. left: 0;
  224. width: 100%;
  225. height: 100%;
  226. }
  227. .layout-lock-screen-filter {
  228. filter: blur(3px);
  229. }
  230. .layout-lock-screen-mask {
  231. background: var(--el-color-white);
  232. @extend .layout-lock-screen-fixed;
  233. z-index: 9;
  234. }
  235. .layout-lock-screen-img {
  236. @extend .layout-lock-screen-fixed;
  237. //background-image: url(https://i.hd-r.cn/e4a19d84364f185266666765ac21a5db.jpg);
  238. background-image: url(/@/assets/images/login/bg.png);
  239. background-size: calc(100vw + 1px) calc(100vh + 1px);
  240. z-index: 99;
  241. }
  242. .layout-lock-screen {
  243. @extend .layout-lock-screen-fixed;
  244. z-index: 999;
  245. &-date {
  246. position: absolute;
  247. left: 0;
  248. top: 0;
  249. width: 100%;
  250. height: 100%;
  251. color: var(--el-color-white);
  252. z-index: 9999;
  253. user-select: none;
  254. &-box {
  255. position: absolute;
  256. left: 30px;
  257. bottom: 50px;
  258. &-time {
  259. font-size: 100px;
  260. color: var(--el-color-white);
  261. }
  262. &-info {
  263. font-size: 40px;
  264. color: var(--el-color-white);
  265. }
  266. &-minutes {
  267. font-size: 16px;
  268. }
  269. }
  270. &-top {
  271. width: 40px;
  272. height: 40px;
  273. line-height: 40px;
  274. border-radius: 100%;
  275. border: 1px solid var(--el-border-color-light, #ebeef5);
  276. background: rgba(255, 255, 255, 0.1);
  277. color: var(--el-color-white);
  278. opacity: 0.8;
  279. position: absolute;
  280. right: 30px;
  281. bottom: 50px;
  282. text-align: center;
  283. overflow: hidden;
  284. transition: all 0.3s ease;
  285. i {
  286. transition: all 0.3s ease;
  287. }
  288. &-text {
  289. opacity: 0;
  290. position: absolute;
  291. top: 150%;
  292. font-size: 12px;
  293. color: var(--el-color-white);
  294. left: 50%;
  295. line-height: 1.2;
  296. transform: translate(-50%, -50%);
  297. transition: all 0.3s ease;
  298. width: 35px;
  299. }
  300. &:hover {
  301. border: 1px solid rgba(255, 255, 255, 0.5);
  302. background: rgba(255, 255, 255, 0.2);
  303. box-shadow: 0 0 12px 0 rgba(255, 255, 255, 0.5);
  304. color: var(--el-color-white);
  305. opacity: 1;
  306. transition: all 0.3s ease;
  307. i {
  308. transform: translateY(-40px);
  309. transition: all 0.3s ease;
  310. }
  311. .layout-lock-screen-date-top-text {
  312. opacity: 1;
  313. top: 50%;
  314. transition: all 0.3s ease;
  315. }
  316. }
  317. }
  318. }
  319. &-login {
  320. position: relative;
  321. z-index: 9999994;
  322. width: 100%;
  323. height: 100%;
  324. left: 0;
  325. top: 0;
  326. display: flex;
  327. flex-direction: column;
  328. justify-content: center;
  329. color: var(--el-color-white);
  330. &-box {
  331. text-align: center;
  332. margin: auto;
  333. &-img {
  334. width: 180px;
  335. height: 180px;
  336. margin: auto;
  337. img {
  338. width: 100%;
  339. height: 100%;
  340. border-radius: 100%;
  341. }
  342. }
  343. &-name {
  344. font-size: 26px;
  345. margin: 15px 0 30px;
  346. }
  347. }
  348. &-icon {
  349. position: absolute;
  350. right: 30px;
  351. bottom: 30px;
  352. i {
  353. font-size: 20px;
  354. margin-left: 15px;
  355. cursor: pointer;
  356. opacity: 0.8;
  357. &:hover {
  358. opacity: 1;
  359. }
  360. }
  361. }
  362. }
  363. }
  364. :deep(.el-input-group__append) {
  365. background: var(--el-color-white);
  366. padding: 0px 15px;
  367. }
  368. :deep(.el-input__inner) {
  369. border-right-color: var(--el-border-color-extra-light);
  370. &:hover {
  371. border-color: var(--el-border-color-extra-light);
  372. }
  373. }
  374. </style>