index.vue 9.5 KB

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