index.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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="onDownPc"
  10. @mousemove="onMovePc"
  11. @mouseup="onEnd"
  12. @touchstart.stop="onDownApp"
  13. @touchmove.stop="onMoveApp"
  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 class="layout-lock-screen-date-box-minutes">{{ 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-img">
  31. <img src="https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500" />
  32. </div>
  33. <div class="layout-lock-screen-login-box-name">Administrator</div>
  34. <div class="layout-lock-screen-login-box-value">
  35. <el-input placeholder="请输入密码" ref="layoutLockScreenInputRef" v-model="state.lockScreenPassword" @keyup.enter.native.stop="onLockScreenSubmit()">
  36. <template #append>
  37. <el-button @click="onLockScreenSubmit">
  38. <el-icon class="el-input__icon">
  39. <ele-Right />
  40. </el-icon>
  41. </el-button>
  42. </template>
  43. </el-input>
  44. </div>
  45. </div>
  46. <div class="layout-lock-screen-login-icon">
  47. <SvgIcon name="ele-Microphone" :size="20" />
  48. <SvgIcon name="ele-AlarmClock" :size="20" />
  49. <SvgIcon name="ele-SwitchButton" :size="20" />
  50. </div>
  51. </div>
  52. </transition>
  53. </div>
  54. </div>
  55. </template>
  56. <script setup lang="ts" name="layoutLockScreen">
  57. import { nextTick, onMounted, reactive, ref, onUnmounted } from 'vue';
  58. import { formatDate } from '/@/utils/formatTime';
  59. import { Local } from '/@/utils/storage';
  60. import { storeToRefs } from 'pinia';
  61. import { useThemeConfig } from '/@/stores/themeConfig';
  62. // 定义变量内容
  63. const layoutLockScreenDateRef = ref<HtmlType>();
  64. const layoutLockScreenInputRef = ref();
  65. const storesThemeConfig = useThemeConfig();
  66. const { themeConfig } = storeToRefs(storesThemeConfig);
  67. const state = reactive({
  68. transparency: 1,
  69. downClientY: 0,
  70. moveDifference: 0,
  71. isShowLoockLogin: false,
  72. isFlags: false,
  73. querySelectorEl: '' as HtmlType,
  74. time: {
  75. hm: '',
  76. s: '',
  77. mdq: '',
  78. },
  79. setIntervalTime: 0,
  80. isShowLockScreen: false,
  81. isShowLockScreenIntervalTime: 0,
  82. lockScreenPassword: '',
  83. });
  84. // 鼠标按下 pc
  85. const onDownPc = (down: MouseEvent) => {
  86. state.isFlags = true;
  87. state.downClientY = down.clientY;
  88. };
  89. // 鼠标按下 app
  90. const onDownApp = (down: TouchEvent) => {
  91. state.isFlags = true;
  92. state.downClientY = down.touches[0].clientY;
  93. };
  94. // 鼠标移动 pc
  95. const onMovePc = (move: MouseEvent) => {
  96. state.moveDifference = move.clientY - state.downClientY;
  97. onMove();
  98. };
  99. // 鼠标移动 app
  100. const onMoveApp = (move: TouchEvent) => {
  101. state.moveDifference = move.touches[0].clientY - state.downClientY;
  102. onMove();
  103. };
  104. // 鼠标移动事件
  105. const onMove = () => {
  106. if (state.isFlags) {
  107. const el = <HTMLElement>state.querySelectorEl;
  108. const opacitys = (state.transparency -= 1 / 200);
  109. if (state.moveDifference >= 0) return false;
  110. el.setAttribute('style', `top:${state.moveDifference}px;cursor:pointer;opacity:${opacitys};`);
  111. if (state.moveDifference < -400) {
  112. el.setAttribute('style', `top:${-el.clientHeight}px;cursor:pointer;transition:all 0.3s ease;`);
  113. state.moveDifference = -el.clientHeight;
  114. setTimeout(() => {
  115. el && el.parentNode?.removeChild(el);
  116. }, 300);
  117. }
  118. if (state.moveDifference === -el.clientHeight) {
  119. state.isShowLoockLogin = true;
  120. layoutLockScreenInputRef.value.focus();
  121. }
  122. }
  123. };
  124. // 鼠标松开
  125. const onEnd = () => {
  126. state.isFlags = false;
  127. state.transparency = 1;
  128. if (state.moveDifference >= -400) {
  129. (<HTMLElement>state.querySelectorEl).setAttribute('style', `top:0px;opacity:1;transition:all 0.3s ease;`);
  130. }
  131. };
  132. // 获取要拖拽的初始元素
  133. const initGetElement = () => {
  134. nextTick(() => {
  135. state.querySelectorEl = layoutLockScreenDateRef.value;
  136. });
  137. };
  138. // 时间初始化
  139. const initTime = () => {
  140. state.time.hm = formatDate(new Date(), 'HH:MM');
  141. state.time.s = formatDate(new Date(), 'SS');
  142. state.time.mdq = formatDate(new Date(), 'mm月dd日,WWW');
  143. };
  144. // 时间初始化定时器
  145. const initSetTime = () => {
  146. initTime();
  147. state.setIntervalTime = window.setInterval(() => {
  148. initTime();
  149. }, 1000);
  150. };
  151. // 锁屏时间定时器
  152. const initLockScreen = () => {
  153. if (themeConfig.value.isLockScreen) {
  154. state.isShowLockScreenIntervalTime = window.setInterval(() => {
  155. if (themeConfig.value.lockScreenTime <= 1) {
  156. state.isShowLockScreen = true;
  157. setLocalThemeConfig();
  158. return false;
  159. }
  160. themeConfig.value.lockScreenTime--;
  161. }, 1000);
  162. } else {
  163. clearInterval(state.isShowLockScreenIntervalTime);
  164. }
  165. };
  166. // 存储布局配置
  167. const setLocalThemeConfig = () => {
  168. themeConfig.value.isDrawer = false;
  169. Local.set('themeConfig', themeConfig.value);
  170. };
  171. // 密码输入点击事件
  172. const onLockScreenSubmit = () => {
  173. themeConfig.value.isLockScreen = false;
  174. themeConfig.value.lockScreenTime = 30;
  175. setLocalThemeConfig();
  176. };
  177. // 页面加载时
  178. onMounted(() => {
  179. initGetElement();
  180. initSetTime();
  181. initLockScreen();
  182. });
  183. // 页面卸载时
  184. onUnmounted(() => {
  185. window.clearInterval(state.setIntervalTime);
  186. window.clearInterval(state.isShowLockScreenIntervalTime);
  187. });
  188. </script>
  189. <style scoped lang="scss">
  190. .layout-lock-screen-fixed {
  191. position: fixed;
  192. top: 0;
  193. left: 0;
  194. width: 100%;
  195. height: 100%;
  196. }
  197. .layout-lock-screen-filter {
  198. filter: blur(1px);
  199. }
  200. .layout-lock-screen-mask {
  201. background: var(--el-color-white);
  202. @extend .layout-lock-screen-fixed;
  203. z-index: 9999990;
  204. }
  205. .layout-lock-screen-img {
  206. @extend .layout-lock-screen-fixed;
  207. background-image: url('https://img-blog.csdnimg.cn/afa9c317667f47d5bea34b85af45979e.png#pic_center');
  208. background-size: 100% 100%;
  209. z-index: 9999991;
  210. }
  211. .layout-lock-screen {
  212. @extend .layout-lock-screen-fixed;
  213. z-index: 9999992;
  214. &-date {
  215. position: absolute;
  216. left: 0;
  217. top: 0;
  218. width: 100%;
  219. height: 100%;
  220. color: var(--el-color-white);
  221. z-index: 9999993;
  222. user-select: none;
  223. &-box {
  224. position: absolute;
  225. left: 30px;
  226. bottom: 50px;
  227. &-time {
  228. font-size: 100px;
  229. color: var(--el-color-white);
  230. }
  231. &-info {
  232. font-size: 40px;
  233. color: var(--el-color-white);
  234. }
  235. &-minutes {
  236. font-size: 16px;
  237. }
  238. }
  239. &-top {
  240. width: 40px;
  241. height: 40px;
  242. line-height: 40px;
  243. border-radius: 100%;
  244. border: 1px solid var(--el-border-color-light, #ebeef5);
  245. background: rgba(255, 255, 255, 0.1);
  246. color: var(--el-color-white);
  247. opacity: 0.8;
  248. position: absolute;
  249. right: 30px;
  250. bottom: 50px;
  251. text-align: center;
  252. overflow: hidden;
  253. transition: all 0.3s ease;
  254. i {
  255. transition: all 0.3s ease;
  256. }
  257. &-text {
  258. opacity: 0;
  259. position: absolute;
  260. top: 150%;
  261. font-size: 12px;
  262. color: var(--el-color-white);
  263. left: 50%;
  264. line-height: 1.2;
  265. transform: translate(-50%, -50%);
  266. transition: all 0.3s ease;
  267. width: 35px;
  268. }
  269. &:hover {
  270. border: 1px solid rgba(255, 255, 255, 0.5);
  271. background: rgba(255, 255, 255, 0.2);
  272. box-shadow: 0 0 12px 0 rgba(255, 255, 255, 0.5);
  273. color: var(--el-color-white);
  274. opacity: 1;
  275. transition: all 0.3s ease;
  276. i {
  277. transform: translateY(-40px);
  278. transition: all 0.3s ease;
  279. }
  280. .layout-lock-screen-date-top-text {
  281. opacity: 1;
  282. top: 50%;
  283. transition: all 0.3s ease;
  284. }
  285. }
  286. }
  287. }
  288. &-login {
  289. position: relative;
  290. z-index: 9999994;
  291. width: 100%;
  292. height: 100%;
  293. left: 0;
  294. top: 0;
  295. display: flex;
  296. flex-direction: column;
  297. justify-content: center;
  298. color: var(--el-color-white);
  299. &-box {
  300. text-align: center;
  301. margin: auto;
  302. &-img {
  303. width: 180px;
  304. height: 180px;
  305. margin: auto;
  306. img {
  307. width: 100%;
  308. height: 100%;
  309. border-radius: 100%;
  310. }
  311. }
  312. &-name {
  313. font-size: 26px;
  314. margin: 15px 0 30px;
  315. }
  316. }
  317. &-icon {
  318. position: absolute;
  319. right: 30px;
  320. bottom: 30px;
  321. i {
  322. font-size: 20px;
  323. margin-left: 15px;
  324. cursor: pointer;
  325. opacity: 0.8;
  326. &:hover {
  327. opacity: 1;
  328. }
  329. }
  330. }
  331. }
  332. }
  333. :deep(.el-input-group__append) {
  334. background: var(--el-color-white);
  335. padding: 0px 15px;
  336. }
  337. :deep(.el-input__inner) {
  338. border-right-color: var(--el-border-color-extra-light);
  339. &:hover {
  340. border-color: var(--el-border-color-extra-light);
  341. }
  342. }
  343. </style>