lock-screen.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <script setup lang="ts">
  2. import { computed, reactive, ref, watchEffect } from 'vue';
  3. import { LockKeyhole } from '@vben/icons';
  4. import { $t, useI18n } from '@vben/locales';
  5. import { storeToRefs, useLockStore } from '@vben/stores';
  6. import {
  7. VbenAvatar,
  8. VbenButton,
  9. VbenInputPassword,
  10. } from '@vben-core/shadcn-ui';
  11. import { useDateFormat, useNow } from '@vueuse/core';
  12. interface Props {
  13. avatar?: string;
  14. }
  15. defineOptions({
  16. name: 'LockScreen',
  17. });
  18. withDefaults(defineProps<Props>(), {
  19. avatar: '',
  20. });
  21. defineEmits<{ toLogin: [] }>();
  22. const { locale } = useI18n();
  23. const lockStore = useLockStore();
  24. const now = useNow();
  25. const meridiem = useDateFormat(now, 'A');
  26. const hour = useDateFormat(now, 'HH');
  27. const minute = useDateFormat(now, 'mm');
  28. const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });
  29. const showUnlockForm = ref(false);
  30. const validPass = ref(true);
  31. const { lockScreenPassword } = storeToRefs(lockStore);
  32. const formState = reactive({
  33. password: '',
  34. submitted: false,
  35. });
  36. const passwordStatus = computed(() => {
  37. if (formState.submitted && !formState.password) {
  38. return 'error';
  39. }
  40. if (formState.submitted && !validPass.value) {
  41. return 'error';
  42. }
  43. return 'default';
  44. });
  45. const errorTip = computed(() => {
  46. return lockScreenPassword?.value === undefined || !formState.password
  47. ? $t('widgets.lockScreen.placeholder')
  48. : $t('widgets.lockScreen.errorPasswordTip');
  49. });
  50. watchEffect(() => {
  51. if (!formState.password) {
  52. validPass.value = true;
  53. }
  54. });
  55. function handleSubmit() {
  56. formState.submitted = true;
  57. if (passwordStatus.value !== 'default') {
  58. return;
  59. }
  60. if (lockScreenPassword?.value !== formState.password) {
  61. validPass.value = false;
  62. return;
  63. }
  64. lockStore.unlockScreen();
  65. }
  66. function toggleUnlockForm() {
  67. showUnlockForm.value = !showUnlockForm.value;
  68. }
  69. </script>
  70. <template>
  71. <div class="bg-background fixed z-[2000] size-full">
  72. <transition name="slide-left">
  73. <div v-show="!showUnlockForm" class="size-full">
  74. <div
  75. class="flex-col-center text-foreground/80 hover:text-foreground group my-4 cursor-pointer text-xl font-semibold"
  76. @click="toggleUnlockForm"
  77. >
  78. <LockKeyhole
  79. class="size-5 transition-all duration-300 group-hover:scale-125"
  80. />
  81. <span>{{ $t('widgets.lockScreen.unlock') }}</span>
  82. </div>
  83. <div class="flex h-full justify-center px-[10%]">
  84. <div
  85. class="bg-accent flex-center relative mb-14 mr-20 h-4/5 w-2/5 flex-auto rounded-3xl text-center text-[260px]"
  86. >
  87. <span class="absolute left-4 top-4 text-xl font-semibold">
  88. {{ meridiem }}
  89. </span>
  90. {{ hour }}
  91. </div>
  92. <div
  93. class="bg-accent flex-center mb-14 h-4/5 w-2/5 flex-auto rounded-3xl text-center text-[260px]"
  94. >
  95. {{ minute }}
  96. </div>
  97. </div>
  98. </div>
  99. </transition>
  100. <transition name="slide-right">
  101. <div
  102. v-if="showUnlockForm"
  103. class="flex-center size-full"
  104. @keypress.enter.prevent="handleSubmit"
  105. >
  106. <div class="flex-col-center mb-10 w-[300px]">
  107. <VbenAvatar :src="avatar" class="enter-x mb-6 size-20" />
  108. <div class="enter-x mb-2 w-full items-center">
  109. <VbenInputPassword
  110. v-model="formState.password"
  111. :autofocus="true"
  112. :error-tip="errorTip"
  113. :label="$t('widgets.lockScreen.password')"
  114. :placeholder="$t('widgets.lockScreen.placeholder')"
  115. :status="passwordStatus"
  116. name="password"
  117. required
  118. type="password"
  119. />
  120. </div>
  121. <VbenButton class="enter-x w-full" @click="handleSubmit">
  122. {{ $t('widgets.lockScreen.entry') }}
  123. </VbenButton>
  124. <VbenButton
  125. class="enter-x my-2 w-full"
  126. variant="ghost"
  127. @click="$emit('toLogin')"
  128. >
  129. {{ $t('widgets.lockScreen.backToLogin') }}
  130. </VbenButton>
  131. <VbenButton
  132. class="enter-x mr-2 w-full"
  133. variant="ghost"
  134. @click="toggleUnlockForm"
  135. >
  136. {{ $t('common.back') }}
  137. </VbenButton>
  138. </div>
  139. </div>
  140. </transition>
  141. <div
  142. class="enter-y absolute bottom-5 w-full text-center xl:text-xl 2xl:text-3xl"
  143. >
  144. <div v-if="showUnlockForm" class="enter-x mb-2 text-3xl">
  145. {{ hour }}:{{ minute }} <span class="text-lg">{{ meridiem }}</span>
  146. </div>
  147. <div class="text-3xl">{{ date }}</div>
  148. </div>
  149. </div>
  150. </template>