lock-screen.vue 4.3 KB

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