@liujitcn/kratos-admin-core 0.0.31 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +10 -4
  2. package/dist/package/declarations/src/api/base/{config.d.ts → v1/config.d.ts} +1 -1
  3. package/dist/package/declarations/src/api/base/{file.d.ts → v1/file.d.ts} +3 -1
  4. package/dist/package/declarations/src/api/base/{language.d.ts → v1/language.d.ts} +1 -1
  5. package/dist/package/declarations/src/api/base/{login.d.ts → v1/login.d.ts} +2 -2
  6. package/dist/package/declarations/src/api/base/{mfa.d.ts → v1/mfa.d.ts} +3 -3
  7. package/dist/package/declarations/src/api/base/{oauth.d.ts → v1/oauth.d.ts} +1 -1
  8. package/dist/package/declarations/src/api/system/{auth.d.ts → admin/v1/auth.d.ts} +2 -2
  9. package/dist/package/declarations/src/api/system/{base_dict.d.ts → admin/v1/base_dict.d.ts} +1 -1
  10. package/dist/package/declarations/src/api/system/{base_tenant.d.ts → admin/v1/base_tenant.d.ts} +2 -2
  11. package/dist/package/declarations/src/components/ProTable/index.vue.d.ts +114 -0
  12. package/dist/package/declarations/src/components/TreeFilter/index.vue.d.ts +84 -76
  13. package/dist/package/declarations/src/components/Upload/File.vue.d.ts +1 -1
  14. package/dist/package/declarations/src/components/Upload/Files.vue.d.ts +1 -1
  15. package/dist/package/declarations/src/components/Upload/Img.vue.d.ts +1 -1
  16. package/dist/package/declarations/src/components/Upload/Imgs.vue.d.ts +1 -1
  17. package/dist/package/declarations/src/components/WangEditor/index.vue.d.ts +2 -0
  18. package/dist/package/declarations/src/documentTitle.d.ts +2 -0
  19. package/dist/package/declarations/src/format.d.ts +1 -1
  20. package/dist/package/declarations/src/index.d.ts +2 -1
  21. package/dist/package/declarations/src/locales/generated.d.ts +68 -0
  22. package/dist/package/declarations/src/modules/index.d.ts +1 -3
  23. package/dist/package/declarations/src/request.d.ts +1 -1
  24. package/dist/package/declarations/src/routers/index.d.ts +1 -1
  25. package/dist/package/declarations/src/rpc/base/v1/login.d.ts +5 -3
  26. package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +13 -0
  27. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +0 -101
  28. package/dist/package/declarations/src/rpc/system/common/v1/common.d.ts +26 -0
  29. package/dist/package/declarations/src/stores/interface/index.d.ts +6 -1
  30. package/dist/package/declarations/src/stores/modules/user.d.ts +2 -4
  31. package/dist/package/declarations/src/utils/passwordStrength.d.ts +1 -12
  32. package/dist/package/declarations/src/utils/request.d.ts +13 -2
  33. package/dist/package/declarations/src/utils/utils.d.ts +4 -0
  34. package/dist/package/src/api/base/{config.ts → v1/config.ts} +2 -2
  35. package/dist/package/src/api/base/{file.ts → v1/file.ts} +20 -24
  36. package/dist/package/src/api/base/{language.ts → v1/language.ts} +2 -2
  37. package/dist/package/src/api/base/{login.ts → v1/login.ts} +3 -3
  38. package/dist/package/src/api/base/{mfa.ts → v1/mfa.ts} +4 -4
  39. package/dist/package/src/api/base/{oauth.ts → v1/oauth.ts} +2 -2
  40. package/dist/package/src/api/system/{auth.ts → admin/v1/auth.ts} +3 -3
  41. package/dist/package/src/api/system/{base_dict.ts → admin/v1/base_dict.ts} +2 -2
  42. package/dist/package/src/api/system/{base_tenant.ts → admin/v1/base_tenant.ts} +3 -3
  43. package/dist/package/src/bootstrap.ts +6 -5
  44. package/dist/package/src/components/CronExpression/index.vue +4 -3
  45. package/dist/package/src/components/Dialog/ProDialog.vue +1 -0
  46. package/dist/package/src/components/ImportExcel/index.vue +4 -2
  47. package/dist/package/src/components/MarkdownPreview/index.vue +1 -1
  48. package/dist/package/src/components/PasswordStrength/index.vue +1 -1
  49. package/dist/package/src/components/ProTable/components/TableColumn.vue +14 -6
  50. package/dist/package/src/components/ProTable/index.vue +3 -3
  51. package/dist/package/src/components/RichTextPreview/index.vue +12 -1
  52. package/dist/package/src/components/SelectIcon/index.vue +3 -2
  53. package/dist/package/src/components/Upload/File.vue +2 -2
  54. package/dist/package/src/components/Upload/Files.vue +2 -2
  55. package/dist/package/src/components/Upload/Img.vue +7 -5
  56. package/dist/package/src/components/Upload/Imgs.vue +6 -5
  57. package/dist/package/src/components/WangEditor/index.vue +10 -7
  58. package/dist/package/src/documentTitle.ts +8 -0
  59. package/dist/package/src/format.ts +1 -1
  60. package/dist/package/src/index.ts +2 -1
  61. package/dist/package/src/layouts/components/Header/components/Avatar.vue +7 -6
  62. package/dist/package/src/layouts/components/Header/components/InfoDialog.vue +3 -2
  63. package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +3 -2
  64. package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +16 -8
  65. package/dist/package/src/layouts/components/LockScreen.vue +175 -52
  66. package/dist/package/src/layouts/components/Tabs/index.vue +12 -3
  67. package/dist/package/src/layouts/components/ThemeDrawer/index.scss +4 -4
  68. package/dist/package/src/locales/en-US.json +15 -2
  69. package/dist/package/src/locales/ja-JP.json +15 -2
  70. package/dist/package/src/locales/zh-CN.json +15 -2
  71. package/dist/package/src/locales/zh-TW.json +15 -2
  72. package/dist/package/src/modules/index.ts +2 -4
  73. package/dist/package/src/request.ts +3 -0
  74. package/dist/package/src/routers/index.ts +15 -14
  75. package/dist/package/src/rpc/base/v1/config.ts +1 -1
  76. package/dist/package/src/rpc/base/v1/file.ts +1 -1
  77. package/dist/package/src/rpc/base/v1/language.ts +1 -1
  78. package/dist/package/src/rpc/base/v1/login.ts +5 -3
  79. package/dist/package/src/rpc/base/v1/mfa.ts +1 -1
  80. package/dist/package/src/rpc/base/v1/oauth.ts +1 -1
  81. package/dist/package/src/rpc/base/v1/oauth_client.ts +1 -1
  82. package/dist/package/src/rpc/common/v1/common.ts +1 -1
  83. package/dist/package/src/rpc/common/v1/enum.ts +1 -1
  84. package/dist/package/src/rpc/common/v1/types.ts +1 -1
  85. package/dist/package/src/rpc/google/protobuf/empty.ts +1 -1
  86. package/dist/package/src/rpc/google/protobuf/wrappers.ts +1 -1
  87. package/dist/package/src/rpc/system/admin/v1/auth.ts +14 -1
  88. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +1 -113
  89. package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +1 -1
  90. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +1 -1
  91. package/dist/package/src/rpc/system/admin/v1/common.ts +1 -1
  92. package/dist/package/src/rpc/system/common/v1/common.ts +35 -0
  93. package/dist/package/src/stores/interface/index.ts +6 -1
  94. package/dist/package/src/stores/modules/auth.ts +1 -1
  95. package/dist/package/src/stores/modules/config.ts +2 -2
  96. package/dist/package/src/stores/modules/dict.ts +1 -1
  97. package/dist/package/src/stores/modules/user.ts +21 -22
  98. package/dist/package/src/styles/element.scss +35 -4
  99. package/dist/package/src/typings/global.d.ts +6 -0
  100. package/dist/package/src/utils/passwordCrypto.ts +169 -12
  101. package/dist/package/src/utils/passwordStrength.ts +7 -24
  102. package/dist/package/src/utils/request.ts +155 -36
  103. package/dist/package/src/utils/tenant.ts +1 -1
  104. package/dist/package/src/utils/utils.ts +25 -6
  105. package/dist/package/src/views/login/components/LoginForm.vue +36 -21
  106. package/dist/package/src/views/login/index.scss +2 -2
  107. package/dist/package/types/generated/auto-imports.d.ts +2 -0
  108. package/package.json +2 -1
  109. package/types/generated/auto-imports.d.ts +2 -0
  110. package/vite.config.ts +24 -1
@@ -6,6 +6,7 @@
6
6
 
7
7
  export * from "./modules";
8
8
  export * from "./locales";
9
- export { defLanguageService } from "./api/base/language";
9
+ export { defLanguageService } from "./api/base/v1/language";
10
+ export { setAdminDocumentTitle } from "./documentTitle";
10
11
  export { kratosAdminModule } from "./modules/kratosAdmin";
11
12
  export { bootstrapAdminApp } from "./bootstrap";
@@ -23,7 +23,7 @@
23
23
  @click.stop="handleUserMenuAction(action.path)"
24
24
  >
25
25
  <el-icon v-if="action.icon"><component :is="action.icon" /></el-icon>
26
- <span>{{ action.labelKey ? t(action.labelKey) : action.label }}</span>
26
+ <span>{{ t(action.labelKey) }}</span>
27
27
  </button>
28
28
  <button class="action-btn action-btn--lock" type="button" @click.stop="lockScreen">
29
29
  <el-icon><Lock /></el-icon>
@@ -146,7 +146,7 @@ const lockScreen = () => {
146
146
  padding: 16px;
147
147
  background: linear-gradient(180deg, #ffffff 0%, #f7f9fc 100%);
148
148
  border: 1px solid rgb(15 23 42 / 8%);
149
- border-radius: 12px;
149
+ border-radius: var(--admin-page-radius);
150
150
  box-shadow: 0 16px 40px rgb(15 23 42 / 14%);
151
151
  &__summary {
152
152
  display: flex;
@@ -230,11 +230,12 @@ const lockScreen = () => {
230
230
  }
231
231
  }
232
232
  &--lock {
233
- color: var(--el-text-color-regular);
234
- background: var(--el-fill-color-light);
233
+ color: var(--el-color-warning-dark-2);
234
+ background: var(--el-color-warning-light-9);
235
235
  &:hover {
236
- background: var(--el-fill-color);
237
- box-shadow: 0 8px 18px rgb(15 23 42 / 10%);
236
+ color: var(--el-color-warning-dark-2);
237
+ background: var(--el-color-warning-light-8);
238
+ box-shadow: 0 8px 18px rgb(230 162 60 / 14%);
238
239
  }
239
240
  }
240
241
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-dialog v-model="dialogVisible" :title="t('core.layout.info')" width="500px" draggable>
2
+ <ProDialog v-model="dialogVisible" :title="t('core.layout.info')" width="500px" draggable>
3
3
  <span>{{ t("core.layout.info_content") }}</span>
4
4
  <template #footer>
5
5
  <span class="dialog-footer">
@@ -7,11 +7,12 @@
7
7
  <el-button type="primary" @click="dialogVisible = false">{{ t("common.action.confirm") }}</el-button>
8
8
  </span>
9
9
  </template>
10
- </el-dialog>
10
+ </ProDialog>
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
14
  import { useLocaleStore } from "../../../../locales";
15
+ import ProDialog from "../../../../components/Dialog/ProDialog.vue";
15
16
 
16
17
  const { t } = useLocaleStore();
17
18
  import { ref } from "vue";
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-dialog v-model="dialogVisible" :title="t('core.layout.password_change')" width="500px" draggable>
2
+ <ProDialog v-model="dialogVisible" :title="t('core.layout.password_change')" width="500px" draggable>
3
3
  <span>{{ t("core.layout.password_content") }}</span>
4
4
  <template #footer>
5
5
  <span class="dialog-footer">
@@ -7,11 +7,12 @@
7
7
  <el-button type="primary" @click="dialogVisible = false">{{ t("common.action.confirm") }}</el-button>
8
8
  </span>
9
9
  </template>
10
- </el-dialog>
10
+ </ProDialog>
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
14
  import { useLocaleStore } from "../../../../locales";
15
+ import ProDialog from "../../../../components/Dialog/ProDialog.vue";
15
16
 
16
17
  const { t } = useLocaleStore();
17
18
  import { ref } from "vue";
@@ -3,7 +3,14 @@
3
3
  <el-tooltip effect="dark" :content="t('core.header.menu_search')" placement="bottom" :show-after="200">
4
4
  <i :class="'iconfont icon-sousuo'" class="toolBar-icon" @click="handleOpen"></i>
5
5
  </el-tooltip>
6
- <el-dialog class="search-dialog" v-model="isShowSearch" :width="600" :show-close="false" top="10vh">
6
+ <ProDialog
7
+ class="search-dialog"
8
+ v-model="isShowSearch"
9
+ :width="600"
10
+ :show-close="false"
11
+ :show-footer="false"
12
+ top="10vh"
13
+ >
7
14
  <el-input
8
15
  v-model="searchMenu"
9
16
  ref="menuInputRef"
@@ -30,7 +37,7 @@
30
37
  </div>
31
38
  </div>
32
39
  <el-empty v-else class="mt20 mb20" :image-size="100" :description="t('core.header.menu_search_empty')" />
33
- </el-dialog>
40
+ </ProDialog>
34
41
  </div>
35
42
  </template>
36
43
 
@@ -44,6 +51,7 @@ import { useDebounceFn } from "@vueuse/core";
44
51
  import type { RouteItem } from "../../../../rpc/system/admin/v1/auth";
45
52
  import { getRouteMetaHidden, getRouteMetaIcon, getRouteMetaTitle, getRouteTarget, isExternalPath } from "../../../../utils";
46
53
  import { useLocaleStore } from "../../../../locales";
54
+ import ProDialog from "../../../../components/Dialog/ProDialog.vue";
47
55
 
48
56
  /** 可被菜单搜索展示的路由项。 */
49
57
  interface SearchRouteItem extends RouteItem {
@@ -152,11 +160,11 @@ const handleClickMenu = () => {
152
160
 
153
161
  <style scoped lang="scss">
154
162
  .search-menu {
155
- :deep(.el-dialog) {
156
- border-radius: 4px;
157
- .el-dialog__header {
158
- display: none;
159
- }
163
+ :global(.search-dialog) {
164
+ border-radius: var(--admin-page-radius);
165
+ }
166
+ :global(.search-dialog .el-dialog__header) {
167
+ display: none;
160
168
  }
161
169
  .menu-list {
162
170
  max-height: 515px;
@@ -174,7 +182,7 @@ const handleClickMenu = () => {
174
182
  cursor: pointer;
175
183
  background-color: transparent;
176
184
  border: 1px solid var(--el-border-color);
177
- border-radius: 6px;
185
+ border-radius: var(--admin-page-radius);
178
186
  transition: all 0.2s ease;
179
187
  .menu-lf {
180
188
  display: flex;
@@ -24,7 +24,8 @@
24
24
  :aria-label="t('core.layout.lock_screen_password_placeholder')"
25
25
  />
26
26
  <p v-if="setupError" class="lock-form-error">{{ setupError }}</p>
27
- <el-button class="lock-submit" type="primary" size="large" native-type="submit" :loading="settingLock">
27
+ <el-button class="lock-submit lock-submit--lock" size="large" native-type="submit" :loading="settingLock">
28
+ <el-icon><Lock /></el-icon>
28
29
  {{ t("core.layout.lock_screen_action") }}
29
30
  </el-button>
30
31
  </form>
@@ -47,7 +48,6 @@
47
48
  <div class="lock-avatar lock-avatar--unlock">
48
49
  <img :src="avatarSrc" :alt="t('core.layout.avatar')" @error="handleAvatarError" />
49
50
  </div>
50
- <div class="lock-user-name">{{ displayName }}</div>
51
51
  <form class="lock-form" @submit.prevent="handleUnlock">
52
52
  <el-input
53
53
  ref="unlockInputRef"
@@ -76,8 +76,20 @@
76
76
  </button>
77
77
  </section>
78
78
  </div>
79
- <div class="lock-screen__clock" aria-live="polite">
80
- <time class="lock-screen__time">{{ timeText }}</time>
79
+ <div class="lock-screen__clock" :class="{ 'lock-screen__clock--compact': lockScreenStore.unlockVisible }" aria-live="polite">
80
+ <div v-if="lockScreenStore.unlockVisible" class="lock-screen__compact-time" :aria-label="`${periodText} ${hourText}:${minuteText}`">
81
+ <time class="lock-screen__compact-time-value">{{ hourText }}:{{ minuteText }}</time>
82
+ <span class="lock-screen__compact-period">{{ periodText }}</span>
83
+ </div>
84
+ <div v-else class="lock-screen__time-grid" :aria-label="`${periodText} ${hourText}:${minuteText}`">
85
+ <div class="lock-screen__time-card">
86
+ <span class="lock-screen__period">{{ periodText }}</span>
87
+ <time class="lock-screen__time-value">{{ hourText }}</time>
88
+ </div>
89
+ <div class="lock-screen__time-card">
90
+ <time class="lock-screen__time-value">{{ minuteText }}</time>
91
+ </div>
92
+ </div>
81
93
  <time class="lock-screen__date">{{ dateText }}</time>
82
94
  </div>
83
95
  </div>
@@ -108,20 +120,23 @@ const unlockInputRef = ref<{ focus?: () => void }>();
108
120
  let clockTimer: number | undefined;
109
121
 
110
122
  const displayName = computed(() => userStore.userInfo.nick_name || userStore.userInfo.user_name || t("core.layout.not_set"));
111
- const timeText = computed(() => {
112
- return new Intl.DateTimeFormat(locale.value, {
113
- hour: "2-digit",
114
- minute: "2-digit",
115
- hour12: false
116
- }).format(now.value);
117
- });
123
+
124
+ /** 当前小时,使用 24 小时制并补齐两位。 */
125
+ const hourText = computed(() => String(now.value.getHours()).padStart(2, "0"));
126
+
127
+ /** 当前分钟,补齐两位。 */
128
+ const minuteText = computed(() => String(now.value.getMinutes()).padStart(2, "0"));
129
+
130
+ /** 当前时间所属的上午或下午时段。 */
131
+ const periodText = computed(() => (now.value.getHours() < 12 ? "AM" : "PM"));
132
+
133
+ /** 按“日期 星期”格式展示当前本地日期。 */
118
134
  const dateText = computed(() => {
119
- return new Intl.DateTimeFormat(locale.value, {
120
- year: "numeric",
121
- month: "2-digit",
122
- day: "2-digit",
123
- weekday: "long"
124
- }).format(now.value);
135
+ const year = now.value.getFullYear();
136
+ const month = String(now.value.getMonth() + 1).padStart(2, "0");
137
+ const day = String(now.value.getDate()).padStart(2, "0");
138
+ const weekday = new Intl.DateTimeFormat(locale.value, { weekday: "long" }).format(now.value);
139
+ return `${year}-${month}-${day} ${weekday}`;
125
140
  });
126
141
 
127
142
  watch(
@@ -240,23 +255,23 @@ const handleAvatarError = () => {
240
255
  background: rgb(0 0 0 / 60%);
241
256
  }
242
257
  .lock-setup-dialog {
243
- width: min(720px, 100%);
258
+ width: min(600px, 100%);
244
259
  overflow: hidden;
245
260
  color: var(--el-text-color-primary);
246
261
  background: var(--el-bg-color-overlay);
247
262
  border: 1px solid var(--el-border-color);
248
- border-radius: 16px;
263
+ border-radius: var(--admin-page-radius);
249
264
  box-shadow: 0 24px 80px rgb(0 0 0 / 28%);
250
265
  }
251
266
  .lock-dialog-header {
252
267
  display: flex;
253
268
  align-items: center;
254
269
  justify-content: space-between;
255
- padding: 26px 32px;
270
+ padding: 20px 24px;
256
271
  border-bottom: 1px solid var(--el-border-color-light);
257
272
  h2 {
258
273
  margin: 0;
259
- font-size: 28px;
274
+ font-size: 24px;
260
275
  line-height: 1.25;
261
276
  }
262
277
  }
@@ -280,7 +295,7 @@ const handleAvatarError = () => {
280
295
  display: flex;
281
296
  flex-direction: column;
282
297
  align-items: center;
283
- padding: 36px 32px 44px;
298
+ padding: 30px 28px 36px;
284
299
  }
285
300
  .lock-avatar {
286
301
  overflow: hidden;
@@ -294,8 +309,8 @@ const handleAvatarError = () => {
294
309
  object-fit: cover;
295
310
  }
296
311
  &--setup {
297
- width: 168px;
298
- height: 168px;
312
+ width: 136px;
313
+ height: 136px;
299
314
  }
300
315
  &--unlock {
301
316
  width: 132px;
@@ -303,27 +318,38 @@ const handleAvatarError = () => {
303
318
  }
304
319
  }
305
320
  .lock-user-name {
306
- margin-top: 20px;
307
- font-size: 24px;
321
+ margin-top: 16px;
322
+ font-size: 22px;
308
323
  font-weight: 600;
309
324
  line-height: 1.35;
310
325
  color: var(--el-text-color-primary);
311
326
  }
312
327
  .lock-form {
313
- width: min(100%, 560px);
314
- margin-top: 34px;
328
+ width: min(100%, 480px);
329
+ margin-top: 28px;
315
330
  }
316
331
  .lock-input {
317
332
  :deep(.el-input__wrapper) {
318
- min-height: 58px;
319
- padding: 0 18px;
320
- background: transparent;
333
+ box-sizing: border-box;
334
+ height: 48px;
335
+ padding: 0 14px;
336
+ background: var(--el-fill-color-blank);
321
337
  border: 1px solid var(--el-border-color);
322
- border-radius: 12px;
338
+ border-radius: var(--admin-page-radius);
323
339
  box-shadow: none;
340
+ transition:
341
+ border-color var(--el-transition-duration),
342
+ box-shadow var(--el-transition-duration);
343
+ }
344
+ :deep(.el-input__wrapper:hover) {
345
+ border-color: var(--el-border-color-hover);
346
+ }
347
+ :deep(.el-input__wrapper.is-focus) {
348
+ border-color: var(--el-color-primary);
349
+ box-shadow: 0 0 0 2px var(--el-color-primary-light-8);
324
350
  }
325
351
  :deep(.el-input__inner) {
326
- font-size: 18px;
352
+ font-size: 16px;
327
353
  }
328
354
  }
329
355
  .lock-form-error {
@@ -334,9 +360,24 @@ const handleAvatarError = () => {
334
360
  }
335
361
  .lock-submit {
336
362
  width: 100%;
337
- min-height: 56px;
338
- margin-top: 28px;
339
- border-radius: 10px;
363
+ height: 48px;
364
+ margin-top: 20px;
365
+ font-weight: 600;
366
+ border-radius: var(--admin-page-radius);
367
+ }
368
+ .lock-submit--lock {
369
+ --el-button-text-color: var(--el-text-color-regular);
370
+ --el-button-bg-color: var(--el-fill-color-light);
371
+ --el-button-border-color: transparent;
372
+ --el-button-hover-text-color: var(--el-text-color-primary);
373
+ --el-button-hover-bg-color: var(--el-fill-color);
374
+ --el-button-hover-border-color: var(--el-border-color-light);
375
+ --el-button-active-text-color: var(--el-text-color-primary);
376
+ --el-button-active-bg-color: var(--el-fill-color-dark);
377
+ --el-button-active-border-color: var(--el-border-color);
378
+ --el-button-disabled-text-color: var(--el-text-color-placeholder);
379
+ --el-button-disabled-bg-color: var(--el-fill-color-light);
380
+ --el-button-disabled-border-color: transparent;
340
381
  }
341
382
  .lock-screen {
342
383
  position: fixed;
@@ -348,6 +389,8 @@ const handleAvatarError = () => {
348
389
  background: var(--el-bg-color-page);
349
390
  }
350
391
  .lock-screen__trigger-wrap {
392
+ position: relative;
393
+ z-index: 1;
351
394
  display: flex;
352
395
  align-items: flex-start;
353
396
  justify-content: center;
@@ -366,7 +409,7 @@ const handleAvatarError = () => {
366
409
  cursor: pointer;
367
410
  background: transparent;
368
411
  border: 0;
369
- border-radius: 10px;
412
+ border-radius: var(--admin-page-radius);
370
413
  &:hover,
371
414
  &:focus-visible {
372
415
  color: var(--el-text-color-primary);
@@ -395,7 +438,7 @@ const handleAvatarError = () => {
395
438
  cursor: pointer;
396
439
  background: transparent;
397
440
  border: 0;
398
- border-radius: 6px;
441
+ border-radius: var(--admin-page-radius);
399
442
  &:hover,
400
443
  &:focus-visible {
401
444
  color: var(--el-text-color-primary);
@@ -409,42 +452,122 @@ const handleAvatarError = () => {
409
452
  }
410
453
  .lock-screen__clock {
411
454
  position: absolute;
412
- right: 24px;
413
- bottom: clamp(22px, 6vh, 64px);
414
- left: 24px;
455
+ inset: clamp(108px, 15vh, 150px) clamp(20px, 8vw, 180px) clamp(18px, 3vh, 36px);
415
456
  display: flex;
416
457
  flex-direction: column;
458
+ gap: clamp(18px, 3vh, 30px);
417
459
  align-items: center;
460
+ justify-content: center;
418
461
  pointer-events: none;
419
462
  }
420
- .lock-screen__time {
421
- font-size: clamp(44px, 8vw, 88px);
463
+ .lock-screen__clock--compact {
464
+ inset: auto 24px clamp(18px, 4vh, 36px);
465
+ gap: 10px;
466
+ }
467
+ .lock-screen__compact-time {
468
+ display: flex;
469
+ gap: 8px;
470
+ align-items: baseline;
471
+ font-variant-numeric: tabular-nums;
472
+ color: var(--el-text-color-primary);
473
+ }
474
+ .lock-screen__compact-time-value {
475
+ font-size: 30px;
476
+ font-weight: 400;
477
+ line-height: 1;
478
+ letter-spacing: 0;
479
+ }
480
+ .lock-screen__compact-period {
481
+ font-size: 16px;
482
+ line-height: 1;
483
+ }
484
+ .lock-screen__time-grid {
485
+ display: grid;
486
+ flex: 1;
487
+ grid-template-columns: repeat(2, minmax(0, 1fr));
488
+ gap: clamp(20px, 4vw, 72px);
489
+ width: min(100%, 1536px);
490
+ min-height: 0;
491
+ }
492
+ .lock-screen__time-card {
493
+ position: relative;
494
+ display: grid;
495
+ place-items: center;
496
+ min-width: 0;
497
+ overflow: hidden;
498
+ color: var(--el-text-color-primary);
499
+ background: var(--el-fill-color-light);
500
+ border: 1px solid var(--el-border-color-lighter);
501
+ border-radius: var(--admin-page-radius);
502
+ }
503
+ .lock-screen__period {
504
+ position: absolute;
505
+ top: clamp(16px, 3vh, 28px);
506
+ left: clamp(16px, 2vw, 28px);
507
+ font-size: 18px;
508
+ font-weight: 600;
509
+ line-height: 1;
510
+ color: var(--el-text-color-regular);
511
+ }
512
+ .lock-screen__time-value {
513
+ font-size: clamp(112px, 31vh, 272px);
422
514
  font-weight: 300;
515
+ font-variant-numeric: tabular-nums;
423
516
  line-height: 1;
517
+ letter-spacing: 0;
424
518
  }
425
519
  .lock-screen__date {
426
- margin-top: 14px;
427
- font-size: clamp(17px, 2.4vw, 26px);
520
+ flex: none;
521
+ font-size: clamp(20px, 3vh, 30px);
522
+ font-variant-numeric: tabular-nums;
428
523
  line-height: 1.35;
429
- color: var(--el-text-color-secondary);
524
+ color: var(--el-text-color-primary);
525
+ letter-spacing: 0;
430
526
  }
431
527
 
432
528
  @media (width <= 600px) {
433
529
  .lock-dialog-header {
434
- padding: 20px 22px;
530
+ padding: 18px 20px;
435
531
  h2 {
436
- font-size: 24px;
532
+ font-size: 22px;
437
533
  }
438
534
  }
439
535
  .lock-dialog-body {
440
- padding: 28px 20px 32px;
536
+ padding: 24px 20px 28px;
441
537
  }
442
538
  .lock-avatar--setup {
443
- width: 132px;
444
- height: 132px;
539
+ width: 112px;
540
+ height: 112px;
445
541
  }
446
542
  .lock-screen__clock {
447
- bottom: 28px;
543
+ inset: 108px 16px 24px;
544
+ gap: 16px;
545
+ }
546
+ .lock-screen__clock--compact {
547
+ inset: auto 16px 24px;
548
+ gap: 8px;
549
+ }
550
+ .lock-screen__time-grid {
551
+ flex: none;
552
+ gap: 12px;
553
+ height: min(42vh, 220px);
554
+ }
555
+ .lock-screen__period {
556
+ top: 12px;
557
+ left: 12px;
558
+ font-size: 14px;
559
+ }
560
+ .lock-screen__time-value {
561
+ font-size: clamp(72px, 17vh, 120px);
562
+ }
563
+ .lock-screen__date {
564
+ font-size: 18px;
565
+ }
566
+ .lock-screen__compact-time-value {
567
+ font-size: 26px;
568
+ }
569
+ .lock-screen__compact-period {
570
+ font-size: 14px;
448
571
  }
449
572
  }
450
573
  </style>
@@ -18,7 +18,7 @@
18
18
 
19
19
  <script setup lang="ts">
20
20
  import Sortable from "sortablejs";
21
- import { ref, computed, watch, onMounted } from "vue";
21
+ import { ref, computed, watch, onBeforeUnmount, onMounted, nextTick } from "vue";
22
22
  import { useRoute, useRouter } from "vue-router";
23
23
  import { useGlobalStore } from "../../../stores/modules/global";
24
24
  import { useTabsStore } from "../../../stores/modules/tabs";
@@ -39,6 +39,7 @@ const { locale, t } = useLocaleStore();
39
39
  const tabsMenuValue = ref(getAdminTabPath(route));
40
40
  const tabsMenuList = computed(() => tabStore.tabsMenuList);
41
41
  const tabsIcon = computed(() => globalStore.tabsIcon);
42
+ let tabsSortable: Sortable | undefined;
42
43
 
43
44
  /** 获取当前路由标签标题,兼容静态路由的多语言标题键。 */
44
45
  const getCurrentRouteTitle = () => {
@@ -47,8 +48,13 @@ const getCurrentRouteTitle = () => {
47
48
  };
48
49
 
49
50
  onMounted(() => {
50
- tabsDrop();
51
51
  initTabs();
52
+ void nextTick(tabsDrop);
53
+ });
54
+
55
+ onBeforeUnmount(() => {
56
+ tabsSortable?.destroy();
57
+ tabsSortable = undefined;
52
58
  });
53
59
 
54
60
  // 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
@@ -96,7 +102,10 @@ const initTabs = () => {
96
102
 
97
103
  // tabs 拖拽排序
98
104
  const tabsDrop = () => {
99
- Sortable.create(document.querySelector(".el-tabs__nav") as HTMLElement, {
105
+ const tabsNav = document.querySelector<HTMLElement>(".el-tabs__nav");
106
+ if (!tabsNav) return;
107
+ tabsSortable?.destroy();
108
+ tabsSortable = Sortable.create(tabsNav, {
100
109
  draggable: ".el-tabs__item",
101
110
  animation: 300,
102
111
  onEnd({ newIndex, oldIndex }) {
@@ -38,21 +38,21 @@
38
38
  height: 70px;
39
39
  padding: 6px;
40
40
  cursor: pointer;
41
- border-radius: 5px;
41
+ border-radius: var(--admin-page-radius);
42
42
  box-shadow: 0 0 5px 1px var(--el-border-color-dark);
43
43
  transition: all 0.2s;
44
44
  .layout-dark {
45
45
  background-color: var(--el-color-primary);
46
- border-radius: 3px;
46
+ border-radius: var(--admin-page-radius);
47
47
  }
48
48
  .layout-light {
49
49
  background-color: var(--el-color-primary-light-5);
50
- border-radius: 3px;
50
+ border-radius: var(--admin-page-radius);
51
51
  }
52
52
  .layout-content {
53
53
  background-color: var(--el-color-primary-light-8);
54
54
  border: 1px dashed var(--el-color-primary);
55
- border-radius: 3px;
55
+ border-radius: var(--admin-page-radius);
56
56
  }
57
57
  .el-icon {
58
58
  position: absolute;
@@ -33,6 +33,7 @@
33
33
  "common.validation.phone_required": "Enter a phone number",
34
34
  "common.title.notice": "Notice",
35
35
  "common.title.warning": "Confirmation",
36
+ "common.confirm.delete": "Delete this item?",
36
37
  "common.placeholder.input": "Enter a value",
37
38
  "common.placeholder.input_content": "Enter content",
38
39
  "common.placeholder.select": "Select a value",
@@ -143,6 +144,7 @@
143
144
  "core.layout.home": "Home",
144
145
  "core.layout.info": "Personal information",
145
146
  "core.layout.password_change": "Change password",
147
+ "core.layout.password_change_required": "Your password has expired. Please change it before continuing.",
146
148
  "core.layout.unnamed_menu": "Unnamed menu",
147
149
  "core.layout.lock_screen": "Lock screen",
148
150
  "core.layout.lock_screen_action": "Lock",
@@ -197,8 +199,15 @@
197
199
  "core.oauth.wechatmp": "WeChat Official Account",
198
200
  "core.oauth.wechatwork": "WeCom",
199
201
  "core.oauth.unknown": "Unknown provider",
200
- "core.password.error": "Password must contain uppercase and lowercase letters, a number, and a special character, and be at least 8 characters long",
202
+ "core.password.error": "Password does not meet the active password policy",
201
203
  "core.password.crypto_unsupported": "Password encryption is not supported in this environment",
204
+ "core.password.crypto_secure_context": "Password encryption requires localhost or HTTPS. Please use a secure address.",
205
+ "core.password.base64_decode_unsupported": "Base64 decoding is not supported in this environment",
206
+ "core.password.base64_encode_unsupported": "Base64 encoding is not supported in this environment",
207
+ "core.password.encrypt_failed": "Password encryption failed",
208
+ "core.password.password_too_long": "Password exceeds the supported length",
209
+ "core.password.public_key_invalid": "Invalid public key",
210
+ "core.password.random_failed": "Failed to generate random data",
202
211
  "core.password.required": "Password is required",
203
212
  "core.password.verify_title": "Verify password",
204
213
  "core.password.verify_label": "Current password",
@@ -207,7 +216,7 @@
207
216
  "core.password.strength.high": "High",
208
217
  "core.password.strength.low": "Low",
209
218
  "core.password.strength.medium": "Medium",
210
- "core.password.tip": "Use at least 8 characters with uppercase and lowercase letters, a number, and a special character. The password must reach high strength before submission.",
219
+ "core.password.tip": "Password requirements follow the active password policy.",
211
220
  "core.theme.accordion": "Accordion menu",
212
221
  "core.theme.aside_inverted": "Dark sidebar",
213
222
  "core.theme.aside_inverted_tip": "Use dark colors for the sidebar",
@@ -291,11 +300,15 @@
291
300
  "common.dialog.resource_field": "{field}: {value}",
292
301
  "common.dialog.status_change": "{action} this {resource}?\n{field}: {value}",
293
302
  "common.field.created_at": "Created at",
303
+ "common.field.department": "Department",
304
+ "common.field.post": "Position",
294
305
  "common.field.remark": "Remarks",
306
+ "common.field.role": "Role",
295
307
  "common.field.sort": "Sort order",
296
308
  "common.field.status": "Status",
297
309
  "common.field.tenant": "Tenant",
298
310
  "common.field.updated_at": "Updated at",
311
+ "common.field.user": "User",
299
312
  "common.message.create_success": "{resource} created",
300
313
  "common.message.delete_success": "{resource} deleted",
301
314
  "common.message.load_children_failed": "Failed to load child {resource}",