@liujitcn/kratos-admin-core 0.0.19 → 0.0.21

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 +2 -2
  2. package/dist/package/declarations/src/api/base/language.d.ts +8 -0
  3. package/dist/package/declarations/src/components/Dialog/ProDialog.vue.d.ts +1 -0
  4. package/dist/package/declarations/src/components/LocaleSwitch/index.vue.d.ts +3 -0
  5. package/dist/package/declarations/src/index.d.ts +2 -0
  6. package/dist/package/declarations/src/locales/index.d.ts +63 -0
  7. package/dist/package/declarations/src/modules/index.d.ts +7 -2
  8. package/dist/package/declarations/src/request.d.ts +1 -0
  9. package/dist/package/declarations/src/routers/modules/staticRouter.d.ts +1 -0
  10. package/dist/package/declarations/src/rpc/base/v1/config.d.ts +2 -0
  11. package/dist/package/declarations/src/rpc/base/v1/language.d.ts +26 -0
  12. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +79 -0
  13. package/dist/package/declarations/src/rpc/system/admin/v1/base_translation.d.ts +102 -0
  14. package/dist/package/declarations/src/stores/interface/index.d.ts +2 -0
  15. package/dist/package/declarations/src/stores/runtime.d.ts +1 -0
  16. package/dist/package/declarations/src/utils/dict.d.ts +2 -2
  17. package/dist/package/declarations/src/utils/index.d.ts +1 -1
  18. package/dist/package/declarations/src/utils/oauthProvider.d.ts +2 -0
  19. package/dist/package/declarations/src/utils/passwordStrength.d.ts +0 -7
  20. package/dist/package/src/App.vue +10 -1
  21. package/dist/package/src/api/base/language.ts +20 -0
  22. package/dist/package/src/api/base/oauth.ts +0 -1
  23. package/dist/package/src/api/system/auth.ts +0 -1
  24. package/dist/package/src/bootstrap.ts +57 -2
  25. package/dist/package/src/components/CronExpression/index.vue +80 -82
  26. package/dist/package/src/components/Dialog/FormDialog.vue +9 -4
  27. package/dist/package/src/components/Dialog/ProDialog.vue +10 -4
  28. package/dist/package/src/components/Dict/index.vue +5 -2
  29. package/dist/package/src/components/ECharts/config/index.ts +6 -1
  30. package/dist/package/src/components/ErrorMessage/index.vue +3 -1
  31. package/dist/package/src/components/ImportExcel/index.vue +29 -18
  32. package/dist/package/src/components/LocaleSwitch/index.vue +28 -0
  33. package/dist/package/src/components/PasswordStrength/index.vue +8 -5
  34. package/dist/package/src/components/ProForm/components/DynamicList.vue +8 -3
  35. package/dist/package/src/components/ProForm/components/KvList.vue +14 -6
  36. package/dist/package/src/components/ProTable/components/ColSetting.vue +7 -5
  37. package/dist/package/src/components/ProTable/components/TableColumn.vue +2 -1
  38. package/dist/package/src/components/ProTable/index.vue +36 -11
  39. package/dist/package/src/components/SearchForm/components/SearchFormItem.vue +9 -4
  40. package/dist/package/src/components/SearchForm/index.vue +6 -3
  41. package/dist/package/src/components/SelectFilter/index.vue +4 -1
  42. package/dist/package/src/components/SelectIcon/index.vue +8 -4
  43. package/dist/package/src/components/TreeFilter/index.vue +14 -6
  44. package/dist/package/src/components/Upload/File.vue +18 -13
  45. package/dist/package/src/components/Upload/Files.vue +22 -15
  46. package/dist/package/src/components/Upload/Img.vue +14 -11
  47. package/dist/package/src/components/Upload/Imgs.vue +15 -12
  48. package/dist/package/src/components/WangEditor/index.vue +12 -4
  49. package/dist/package/src/directives/modules/copy.ts +2 -1
  50. package/dist/package/src/hooks/useDownload.ts +3 -2
  51. package/dist/package/src/hooks/useHandleData.ts +5 -4
  52. package/dist/package/src/hooks/useTheme.ts +2 -1
  53. package/dist/package/src/hooks/useTime.ts +11 -2
  54. package/dist/package/src/index.ts +2 -0
  55. package/dist/package/src/layouts/components/Header/ToolBarRight.vue +2 -0
  56. package/dist/package/src/layouts/components/Header/components/AssemblySize.vue +8 -6
  57. package/dist/package/src/layouts/components/Header/components/Avatar.vue +11 -9
  58. package/dist/package/src/layouts/components/Header/components/Breadcrumb.vue +10 -2
  59. package/dist/package/src/layouts/components/Header/components/Fullscreen.vue +4 -2
  60. package/dist/package/src/layouts/components/Header/components/InfoDialog.vue +6 -3
  61. package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +6 -3
  62. package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +5 -3
  63. package/dist/package/src/layouts/components/Header/components/ThemeSetting.vue +3 -1
  64. package/dist/package/src/layouts/components/Tabs/components/MoreButton.vue +9 -7
  65. package/dist/package/src/layouts/components/ThemeDrawer/index.vue +27 -24
  66. package/dist/package/src/locales/README.md +15 -0
  67. package/dist/package/src/locales/en-US.json +258 -0
  68. package/dist/package/src/locales/es-ES.json +258 -0
  69. package/dist/package/src/locales/fr-FR.json +258 -0
  70. package/dist/package/src/locales/index.ts +223 -0
  71. package/dist/package/src/locales/ja-JP.json +258 -0
  72. package/dist/package/src/locales/ko-KR.json +258 -0
  73. package/dist/package/src/locales/zh-CN.json +258 -0
  74. package/dist/package/src/locales/zh-TW.json +258 -0
  75. package/dist/package/src/modules/index.ts +7 -2
  76. package/dist/package/src/modules/kratosAdmin.ts +19 -1
  77. package/dist/package/src/request.ts +8 -1
  78. package/dist/package/src/routers/index.ts +4 -1
  79. package/dist/package/src/routers/modules/dynamicRouter.ts +3 -2
  80. package/dist/package/src/routers/modules/staticRouter.ts +8 -4
  81. package/dist/package/src/rpc/base/v1/config.ts +2 -0
  82. package/dist/package/src/rpc/base/v1/language.ts +37 -0
  83. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +81 -0
  84. package/dist/package/src/rpc/system/admin/v1/base_translation.ts +117 -0
  85. package/dist/package/src/stores/interface/index.ts +2 -0
  86. package/dist/package/src/stores/modules/config.ts +5 -1
  87. package/dist/package/src/stores/modules/user.ts +2 -1
  88. package/dist/package/src/stores/runtime.ts +1 -0
  89. package/dist/package/src/utils/color.ts +5 -4
  90. package/dist/package/src/utils/dict.ts +27 -4
  91. package/dist/package/src/utils/eleValidate.ts +3 -2
  92. package/dist/package/src/utils/errorHandler.ts +9 -8
  93. package/dist/package/src/utils/index.ts +7 -6
  94. package/dist/package/src/utils/oauthProvider.ts +15 -10
  95. package/dist/package/src/utils/passwordCrypto.ts +3 -2
  96. package/dist/package/src/utils/passwordStrength.ts +1 -16
  97. package/dist/package/src/utils/request.ts +13 -8
  98. package/dist/package/src/views/error/403.vue +3 -1
  99. package/dist/package/src/views/error/404.vue +3 -1
  100. package/dist/package/src/views/error/500.vue +3 -1
  101. package/dist/package/src/views/error/pending.vue +5 -2
  102. package/dist/package/src/views/login/components/LoginForm.vue +53 -27
  103. package/dist/package/src/views/login/index.scss +6 -0
  104. package/dist/package/src/views/login/index.vue +2 -0
  105. package/dist/package/types/generated/auto-imports.d.ts +129 -111
  106. package/dist/package/types/generated/components.d.ts +67 -67
  107. package/package.json +3 -1
  108. package/types/generated/auto-imports.d.ts +129 -111
  109. package/types/generated/components.d.ts +67 -67
  110. package/vite.config.ts +8 -0
@@ -19,15 +19,15 @@
19
19
  <div class="upload-handle" @click.stop>
20
20
  <div v-if="!self_disabled" class="handle-icon" @click="editImg">
21
21
  <el-icon><Edit /></el-icon>
22
- <span>编辑</span>
22
+ <span>{{ t("common.action.edit") }}</span>
23
23
  </div>
24
24
  <div class="handle-icon" @click="imgViewVisible = true">
25
25
  <el-icon><ZoomIn /></el-icon>
26
- <span>查看</span>
26
+ <span>{{ t("common.action.view") }}</span>
27
27
  </div>
28
28
  <div v-if="!self_disabled" class="handle-icon" @click="deleteImg">
29
29
  <el-icon><Delete /></el-icon>
30
- <span>删除</span>
30
+ <span>{{ t("common.action.delete") }}</span>
31
31
  </div>
32
32
  </div>
33
33
  </template>
@@ -54,6 +54,9 @@ import { defFileService } from "../../api/base/file";
54
54
  import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
55
55
  import type { UploadProps, UploadRequestOptions } from "element-plus";
56
56
  import type { FileInfo } from "../../rpc/base/v1/file";
57
+ import { useLocaleStore } from "../../locales";
58
+
59
+ const { t } = useLocaleStore();
57
60
 
58
61
  /** 单图上传组件属性。 */
59
62
  interface UploadFileProps {
@@ -141,15 +144,15 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
141
144
  const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType);
142
145
  if (!imgType)
143
146
  ElNotification({
144
- title: "温馨提示",
145
- message: "上传图片不符合所需的格式!",
147
+ title: t("common.title.warning"),
148
+ message: t("core.upload.imageFormatInvalid"),
146
149
  type: "warning"
147
150
  });
148
151
  if (!imgSize)
149
152
  setTimeout(() => {
150
153
  ElNotification({
151
- title: "温馨提示",
152
- message: `上传图片大小不能超过 ${props.fileSize}M!`,
154
+ title: t("common.title.warning"),
155
+ message: t("core.upload.imageSizeExceeded", { size: props.fileSize }),
153
156
  type: "warning"
154
157
  });
155
158
  }, 0);
@@ -161,8 +164,8 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
161
164
  * */
162
165
  const uploadSuccess = () => {
163
166
  ElNotification({
164
- title: "温馨提示",
165
- message: "图片上传成功!",
167
+ title: t("common.title.notice"),
168
+ message: t("core.upload.imageSuccess"),
166
169
  type: "success"
167
170
  });
168
171
  };
@@ -172,8 +175,8 @@ const uploadSuccess = () => {
172
175
  * */
173
176
  const uploadError = () => {
174
177
  ElNotification({
175
- title: "温馨提示",
176
- message: "图片上传失败,请您重新上传!",
178
+ title: t("common.title.warning"),
179
+ message: t("core.upload.imageFailed"),
177
180
  type: "error"
178
181
  });
179
182
  };
@@ -27,11 +27,11 @@
27
27
  <div class="upload-handle" @click.stop>
28
28
  <div class="handle-icon" @click="handlePictureCardPreview(file)">
29
29
  <el-icon><ZoomIn /></el-icon>
30
- <span>查看</span>
30
+ <span>{{ t("common.action.view") }}</span>
31
31
  </div>
32
32
  <div v-if="!self_disabled" class="handle-icon" @click="handleRemove(file)">
33
33
  <el-icon><Delete /></el-icon>
34
- <span>删除</span>
34
+ <span>{{ t("common.action.delete") }}</span>
35
35
  </div>
36
36
  </div>
37
37
  </template>
@@ -50,6 +50,9 @@ import { defFileService } from "../../api/base/file";
50
50
  import type { UploadProps, UploadFile, UploadUserFile, UploadRequestOptions } from "element-plus";
51
51
  import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
52
52
  import type { FileInfo } from "../../rpc/base/v1/file";
53
+ import { useLocaleStore } from "../../locales";
54
+
55
+ const { t } = useLocaleStore();
53
56
 
54
57
  /** 多图上传组件属性。 */
55
58
  interface UploadFileProps {
@@ -107,15 +110,15 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
107
110
  const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType);
108
111
  if (!imgType)
109
112
  ElNotification({
110
- title: "温馨提示",
111
- message: "上传图片不符合所需的格式!",
113
+ title: t("common.title.warning"),
114
+ message: t("core.upload.imageFormatInvalid"),
112
115
  type: "warning"
113
116
  });
114
117
  if (!imgSize)
115
118
  setTimeout(() => {
116
119
  ElNotification({
117
- title: "温馨提示",
118
- message: `上传图片大小不能超过 ${props.fileSize}M!`,
120
+ title: t("common.title.warning"),
121
+ message: t("core.upload.imageSizeExceeded", { size: props.fileSize }),
119
122
  type: "warning"
120
123
  });
121
124
  }, 0);
@@ -153,8 +156,8 @@ const uploadSuccess = (response: FileInfo | undefined, uploadFile: UploadFile) =
153
156
  // 调用 el-form 内部的校验方法(可自动校验)
154
157
  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string]);
155
158
  ElNotification({
156
- title: "温馨提示",
157
- message: "图片上传成功!",
159
+ title: t("common.title.notice"),
160
+ message: t("core.upload.imageSuccess"),
158
161
  type: "success"
159
162
  });
160
163
  };
@@ -173,8 +176,8 @@ const handleRemove = (file: UploadFile) => {
173
176
  * */
174
177
  const uploadError = () => {
175
178
  ElNotification({
176
- title: "温馨提示",
177
- message: "图片上传失败,请您重新上传!",
179
+ title: t("common.title.warning"),
180
+ message: t("core.upload.imageFailed"),
178
181
  type: "error"
179
182
  });
180
183
  };
@@ -184,8 +187,8 @@ const uploadError = () => {
184
187
  * */
185
188
  const handleExceed = () => {
186
189
  ElNotification({
187
- title: "温馨提示",
188
- message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
190
+ title: t("common.title.warning"),
191
+ message: t("core.upload.imageLimitExceeded", { limit: props.limit }),
189
192
  type: "warning"
190
193
  });
191
194
  };
@@ -6,7 +6,7 @@
6
6
  class="editor-content"
7
7
  :style="{ height }"
8
8
  :mode="mode"
9
- :default-config="editorConfig"
9
+ :default-config="resolvedEditorConfig"
10
10
  @on-created="handleCreated"
11
11
  @on-blur="handleBlur"
12
12
  />
@@ -20,6 +20,9 @@ import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
20
20
  import { defFileService } from "../../api/base/file";
21
21
  import "@wangeditor/editor/dist/css/style.css";
22
22
  import { formContextKey, formItemContextKey } from "element-plus";
23
+ import { useLocaleStore } from "../../locales";
24
+
25
+ const { t } = useLocaleStore();
23
26
 
24
27
  // 富文本 DOM 元素
25
28
  const editorRef = shallowRef();
@@ -47,7 +50,6 @@ const props = withDefaults(defineProps<RichEditorProps>(), {
47
50
  },
48
51
  editorConfig: () => {
49
52
  return {
50
- placeholder: "请输入内容...",
51
53
  MENU_CONF: {}
52
54
  };
53
55
  },
@@ -56,6 +58,12 @@ const props = withDefaults(defineProps<RichEditorProps>(), {
56
58
  hideToolBar: false,
57
59
  disabled: false
58
60
  });
61
+ const editorMenuConfig = props.editorConfig.MENU_CONF ?? {};
62
+ const resolvedEditorConfig = computed(() => ({
63
+ ...props.editorConfig,
64
+ placeholder: props.editorConfig.placeholder || t("common.placeholder.inputContent"),
65
+ MENU_CONF: editorMenuConfig
66
+ }));
59
67
 
60
68
  // 获取 el-form 组件上下文
61
69
  const formContext = inject(formContextKey, void 0);
@@ -91,7 +99,7 @@ const valueHtml = computed({
91
99
  * @param insertFn 上传成功后的回调函数(插入到富文本编辑器中)
92
100
  * */
93
101
  type InsertFnTypeImg = (url: string, alt?: string, href?: string) => void;
94
- props.editorConfig.MENU_CONF!["uploadImage"] = {
102
+ editorMenuConfig["uploadImage"] = {
95
103
  async customUpload(file: File, insertFn: InsertFnTypeImg) {
96
104
  if (!uploadImgValidate(file)) return;
97
105
  try {
@@ -115,7 +123,7 @@ const uploadImgValidate = (file: File): boolean => {
115
123
  * @param insertFn 上传成功后的回调函数(插入到富文本编辑器中)
116
124
  * */
117
125
  type InsertFnTypeVideo = (url: string, poster?: string) => void;
118
- props.editorConfig.MENU_CONF!["uploadVideo"] = {
126
+ editorMenuConfig["uploadVideo"] = {
119
127
  async customUpload(file: File, insertFn: InsertFnTypeVideo) {
120
128
  if (!uploadVideoValidate(file)) return;
121
129
  try {
@@ -6,6 +6,7 @@
6
6
 
7
7
  import type { Directive, DirectiveBinding } from "vue";
8
8
  import { ElMessage } from "element-plus";
9
+ import { t } from "../../locales";
9
10
  /** 复制指令绑定后挂载复制内容的元素类型。 */
10
11
  interface ElType extends HTMLElement {
11
12
  copyData: string | number;
@@ -29,7 +30,7 @@ async function handleClick(this: any) {
29
30
  await navigator.clipboard.writeText(this.copyData);
30
31
  ElMessage({
31
32
  type: "success",
32
- message: "复制成功"
33
+ message: t("core.clipboard.success")
33
34
  });
34
35
  } catch (err) {
35
36
  console.error("复制操作不被支持或失败: ", err);
@@ -1,4 +1,5 @@
1
1
  import { ElNotification } from "element-plus";
2
+ import { t } from "../locales";
2
3
 
3
4
  /**
4
5
  * @description 接收数据流生成 blob,创建链接,下载文件
@@ -17,8 +18,8 @@ export const useDownload = async (
17
18
  ) => {
18
19
  if (isNotify) {
19
20
  ElNotification({
20
- title: "温馨提示",
21
- message: "如果数据庞大会导致下载缓慢哦,请您耐心等待!",
21
+ title: t("common.title.notice"),
22
+ message: t("core.download.largeFileNotice"),
22
23
  type: "info",
23
24
  duration: 3000
24
25
  });
@@ -1,5 +1,6 @@
1
1
  import { ElMessageBox, ElMessage } from "element-plus";
2
2
  import { HandleData } from "./interface";
3
+ import { t } from "../locales";
3
4
 
4
5
  /**
5
6
  * @description 操作单条数据信息 (二次确认【删除、禁用、启用、重置密码】)
@@ -16,9 +17,9 @@ export const useHandleData = (
16
17
  confirmType: HandleData.MessageType = "warning"
17
18
  ) => {
18
19
  return new Promise((resolve, reject) => {
19
- ElMessageBox.confirm(`是否${message}?`, "温馨提示", {
20
- confirmButtonText: "确定",
21
- cancelButtonText: "取消",
20
+ ElMessageBox.confirm(t("core.data.confirmAction", { action: message }), t("common.title.warning"), {
21
+ confirmButtonText: t("common.action.confirm"),
22
+ cancelButtonText: t("common.action.cancel"),
22
23
  type: confirmType,
23
24
  draggable: true
24
25
  })
@@ -27,7 +28,7 @@ export const useHandleData = (
27
28
  if (!res) return reject(false);
28
29
  ElMessage({
29
30
  type: "success",
30
- message: `${message}成功!`
31
+ message: t("core.data.operationSuccess", { action: message })
31
32
  });
32
33
  resolve(true);
33
34
  })
@@ -7,6 +7,7 @@ import { getLightColor, getDarkColor } from "../utils/color";
7
7
  import { menuTheme } from "../styles/theme/menu";
8
8
  import { asideTheme } from "../styles/theme/aside";
9
9
  import { headerTheme } from "../styles/theme/header";
10
+ import { t } from "../locales";
10
11
 
11
12
  /**
12
13
  * @description 全局主题 hooks
@@ -29,7 +30,7 @@ export const useTheme = () => {
29
30
  const changePrimary = (val: string | null) => {
30
31
  if (!val) {
31
32
  val = DEFAULT_PRIMARY;
32
- ElMessage({ type: "success", message: `主题颜色已重置为 ${DEFAULT_PRIMARY}` });
33
+ ElMessage({ type: "success", message: t("core.theme.primaryReset", { color: DEFAULT_PRIMARY }) });
33
34
  }
34
35
  // 计算主题颜色变化
35
36
  document.documentElement.style.setProperty("--el-color-primary", val);
@@ -1,4 +1,5 @@
1
1
  import { ref } from "vue";
2
+ import { getCurrentLocale } from "../locales";
2
3
 
3
4
  /**
4
5
  * @description 获取本地时间
@@ -18,7 +19,7 @@ export const useTime = () => {
18
19
  const date = new Date();
19
20
  year.value = date.getFullYear();
20
21
  month.value = date.getMonth() + 1;
21
- week.value = "日一二三四五六".charAt(date.getDay());
22
+ week.value = new Intl.DateTimeFormat(getCurrentLocale(), { weekday: "short" }).format(date);
22
23
  day.value = date.getDate();
23
24
  hour.value =
24
25
  (date.getHours() + "")?.padStart(2, "0") ||
@@ -29,7 +30,15 @@ export const useTime = () => {
29
30
  second.value =
30
31
  (date.getSeconds() + "")?.padStart(2, "0") ||
31
32
  new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getSeconds());
32
- nowTime.value = `${year.value}年${month.value}月${day.value} ${hour.value}:${minute.value}:${second.value}`;
33
+ nowTime.value = new Intl.DateTimeFormat(getCurrentLocale(), {
34
+ year: "numeric",
35
+ month: "2-digit",
36
+ day: "2-digit",
37
+ hour: "2-digit",
38
+ minute: "2-digit",
39
+ second: "2-digit",
40
+ hour12: false
41
+ }).format(date);
33
42
  };
34
43
 
35
44
  updateTime();
@@ -5,5 +5,7 @@
5
5
  /// <reference path="../types/generated/components.d.ts" />
6
6
 
7
7
  export * from "./modules";
8
+ export * from "./locales";
9
+ export { defLanguageService } from "./api/base/language";
8
10
  export { kratosAdminModule } from "./modules/kratosAdmin";
9
11
  export { bootstrapAdminApp } from "./bootstrap";
@@ -2,6 +2,7 @@
2
2
  <div class="tool-bar-ri">
3
3
  <div class="header-icon">
4
4
  <component :is="tool.component" v-for="tool in headerTools" :id="tool.name" :key="tool.name" />
5
+ <LocaleSwitch id="localeSwitch" />
5
6
  <AssemblySize id="assemblySize" />
6
7
  <SearchMenu id="searchMenu" />
7
8
  <ThemeSetting id="themeSetting" />
@@ -18,6 +19,7 @@ import SearchMenu from "./components/SearchMenu.vue";
18
19
  import ThemeSetting from "./components/ThemeSetting.vue";
19
20
  import Fullscreen from "./components/Fullscreen.vue";
20
21
  import Avatar from "./components/Avatar.vue";
22
+ import LocaleSwitch from "../../../components/LocaleSwitch/index.vue";
21
23
 
22
24
  const headerTools = getAdminHeaderTools();
23
25
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-tooltip effect="dark" content="组件大小" placement="bottom" :show-after="200">
2
+ <el-tooltip effect="dark" :content="t('core.header.sizeSelect')" placement="bottom" :show-after="200">
3
3
  <el-dropdown trigger="click" @command="setAssemblySize">
4
4
  <i :class="'iconfont icon-contentright'" class="toolBar-icon"></i>
5
5
  <template #dropdown>
@@ -22,15 +22,17 @@
22
22
  import { computed } from "vue";
23
23
  import { useGlobalStore } from "../../../../stores/modules/global";
24
24
  import { AssemblySizeType } from "../../../../stores/interface";
25
+ import { useLocaleStore } from "../../../../locales";
25
26
 
26
27
  const globalStore = useGlobalStore();
27
28
  const assemblySize = computed(() => globalStore.assemblySize);
29
+ const { t } = useLocaleStore();
28
30
 
29
- const assemblySizeList = [
30
- { label: "默认", value: "default" },
31
- { label: "大型", value: "large" },
32
- { label: "小型", value: "small" }
33
- ];
31
+ const assemblySizeList = computed(() => [
32
+ { label: t("core.header.size.default"), value: "default" },
33
+ { label: t("core.header.size.large"), value: "large" },
34
+ { label: t("core.header.size.small"), value: "small" }
35
+ ]);
34
36
 
35
37
  const setAssemblySize = (item: AssemblySizeType) => {
36
38
  if (assemblySize.value === item) return;
@@ -23,11 +23,11 @@
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.label }}</span>
26
+ <span>{{ action.labelKey ? t(action.labelKey) : action.label }}</span>
27
27
  </button>
28
28
  <button class="action-btn action-btn--danger" type="button" @click="logout">
29
29
  <el-icon><SwitchButton /></el-icon>
30
- <span>退出登录</span>
30
+ <span>{{ t("common.action.logout") }}</span>
31
31
  </button>
32
32
  </div>
33
33
  </div>
@@ -46,16 +46,18 @@ import type { DropdownInstance } from "element-plus";
46
46
  import defaultAvatar from "../../../../assets/images/avatar.png";
47
47
  import { navigateTo } from "../../../../utils/router";
48
48
  import { getAdminUserMenuActions } from "../../../../modules";
49
+ import { useLocaleStore } from "../../../../locales";
49
50
 
50
51
  const router = useRouter();
51
52
  const userStore = useUserStore();
52
53
  const authStore = useAuthStore();
53
54
  const userMenuActions = getAdminUserMenuActions();
54
55
  const dropdownRef = ref<DropdownInstance>();
56
+ const { t } = useLocaleStore();
55
57
  const avatarSrc = ref(defaultAvatar);
56
- const displayName = computed(() => userStore.userInfo.nick_name || userStore.userInfo.user_name || "未设置");
57
- const roleName = computed(() => userStore.userInfo.role_name || "未分配角色");
58
- const deptName = computed(() => userStore.userInfo.dept_name || "未分配部门");
58
+ const displayName = computed(() => userStore.userInfo.nick_name || userStore.userInfo.user_name || t("core.layout.notSet"));
59
+ const roleName = computed(() => userStore.userInfo.role_name || t("core.layout.roleUnassigned"));
60
+ const deptName = computed(() => userStore.userInfo.dept_name || t("core.layout.departmentUnassigned"));
59
61
  const profileSummary = computed(() => `${roleName.value} / ${deptName.value}`);
60
62
  const availableUserMenuActions = computed(() => {
61
63
  return userMenuActions.flatMap(action => {
@@ -84,9 +86,9 @@ watch(
84
86
 
85
87
  /** 退出登录并清理当前登录态。 */
86
88
  const logout = () => {
87
- ElMessageBox.confirm("您是否确认退出登录?", "温馨提示", {
88
- confirmButtonText: "确定",
89
- cancelButtonText: "取消",
89
+ ElMessageBox.confirm(t("core.layout.logoutConfirm"), t("common.title.warning"), {
90
+ confirmButtonText: t("common.action.confirm"),
91
+ cancelButtonText: t("common.action.cancel"),
90
92
  type: "warning"
91
93
  }).then(async () => {
92
94
  // 1.执行退出登录接口并清理本地状态
@@ -94,7 +96,7 @@ const logout = () => {
94
96
 
95
97
  // 2.重定向到登录页
96
98
  router.replace(LOGIN_URL);
97
- ElMessage.success("退出登录成功!");
99
+ ElMessage.success(t("core.layout.logoutSuccess"));
98
100
  });
99
101
  };
100
102
 
@@ -29,18 +29,26 @@ import { useGlobalStore } from "../../../../stores/modules/global";
29
29
  import type { RouteItem } from "../../../../rpc/system/admin/v1/auth";
30
30
  import { BaseMenuType } from "../../../../rpc/system/common/v1/enum";
31
31
  import { getRouteMetaIcon, getRouteMetaTitle, getRouteTarget, isExternalPath } from "../../../../utils";
32
+ import { useLocaleStore } from "../../../../locales";
32
33
 
33
34
  const route = useRoute();
34
35
  const router = useRouter();
35
36
  const authStore = useAuthStore();
36
37
  const globalStore = useGlobalStore();
38
+ const { t } = useLocaleStore();
37
39
 
38
40
  const breadcrumbList = computed(() => {
39
41
  let breadcrumbData = authStore.breadcrumbListGet[route.matched[route.matched.length - 1].path] ?? [];
40
42
  // 🙅‍♀️不需要首页面包屑可删除以下判断
41
- if (breadcrumbData[0]?.path !== HOME_URL && getRouteMetaTitle(breadcrumbData[0]?.meta) !== "首页") {
43
+ if (breadcrumbData[0]?.path !== HOME_URL) {
42
44
  breadcrumbData = [
43
- { path: HOME_URL, name: "home", type: BaseMenuType.MENU, meta: { icon: "HomeFilled", title: "首页", params: [] }, children: [] },
45
+ {
46
+ path: HOME_URL,
47
+ name: "home",
48
+ type: BaseMenuType.MENU,
49
+ meta: { icon: "HomeFilled", title: t("core.layout.home"), params: [] },
50
+ children: []
51
+ },
44
52
  ...breadcrumbData
45
53
  ];
46
54
  }
@@ -10,9 +10,11 @@
10
10
  import { computed, onMounted, ref } from "vue";
11
11
  import { ElMessage } from "element-plus";
12
12
  import screenfull from "screenfull";
13
+ import { useLocaleStore } from "../../../../locales";
13
14
 
14
15
  const isFullscreen = ref(screenfull.isFullscreen);
15
- const fullscreenTooltip = computed(() => (isFullscreen.value ? "退出全屏" : "全屏"));
16
+ const { t } = useLocaleStore();
17
+ const fullscreenTooltip = computed(() => (isFullscreen.value ? t("core.header.fullscreenExit") : t("core.header.fullscreen")));
16
18
 
17
19
  onMounted(() => {
18
20
  screenfull.on("change", () => {
@@ -22,7 +24,7 @@ onMounted(() => {
22
24
  });
23
25
 
24
26
  const handleFullScreen = () => {
25
- if (!screenfull.isEnabled) ElMessage.warning("当前您的浏览器不支持全屏 ❌");
27
+ if (!screenfull.isEnabled) ElMessage.warning(t("core.header.fullscreenUnsupported"));
26
28
  screenfull.toggle();
27
29
  };
28
30
  </script>
@@ -1,16 +1,19 @@
1
1
  <template>
2
- <el-dialog v-model="dialogVisible" title="个人信息" width="500px" draggable>
2
+ <el-dialog v-model="dialogVisible" :title="t('core.layout.info')" width="500px" draggable>
3
3
  <span>This is userInfo</span>
4
4
  <template #footer>
5
5
  <span class="dialog-footer">
6
- <el-button @click="dialogVisible = false">取消</el-button>
7
- <el-button type="primary" @click="dialogVisible = false">确认</el-button>
6
+ <el-button @click="dialogVisible = false">{{ t("common.action.cancel") }}</el-button>
7
+ <el-button type="primary" @click="dialogVisible = false">{{ t("common.action.confirm") }}</el-button>
8
8
  </span>
9
9
  </template>
10
10
  </el-dialog>
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
+ import { useLocaleStore } from "../../../../locales";
15
+
16
+ const { t } = useLocaleStore();
14
17
  import { ref } from "vue";
15
18
 
16
19
  const dialogVisible = ref(false);
@@ -1,16 +1,19 @@
1
1
  <template>
2
- <el-dialog v-model="dialogVisible" title="修改密码" width="500px" draggable>
2
+ <el-dialog v-model="dialogVisible" :title="t('core.layout.passwordChange')" width="500px" draggable>
3
3
  <span>This is Password</span>
4
4
  <template #footer>
5
5
  <span class="dialog-footer">
6
- <el-button @click="dialogVisible = false">取消</el-button>
7
- <el-button type="primary" @click="dialogVisible = false">确认</el-button>
6
+ <el-button @click="dialogVisible = false">{{ t("common.action.cancel") }}</el-button>
7
+ <el-button type="primary" @click="dialogVisible = false">{{ t("common.action.confirm") }}</el-button>
8
8
  </span>
9
9
  </template>
10
10
  </el-dialog>
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
+ import { useLocaleStore } from "../../../../locales";
15
+
16
+ const { t } = useLocaleStore();
14
17
  import { ref } from "vue";
15
18
 
16
19
  const dialogVisible = ref(false);
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div class="search-menu">
3
- <el-tooltip effect="dark" content="菜单搜索" placement="bottom" :show-after="200">
3
+ <el-tooltip effect="dark" :content="t('core.header.menuSearch')" placement="bottom" :show-after="200">
4
4
  <i :class="'iconfont icon-sousuo'" class="toolBar-icon" @click="handleOpen"></i>
5
5
  </el-tooltip>
6
6
  <el-dialog class="search-dialog" v-model="isShowSearch" :width="600" :show-close="false" top="10vh">
7
7
  <el-input
8
8
  v-model="searchMenu"
9
9
  ref="menuInputRef"
10
- placeholder="菜单搜索:支持菜单名称、路径"
10
+ :placeholder="t('core.header.menuSearchPlaceholder')"
11
11
  size="large"
12
12
  clearable
13
13
  :prefix-icon="Search"
@@ -29,7 +29,7 @@
29
29
  <i :class="'iconfont icon-huiche'" class="menu-enter" @click="handleOpen"></i>
30
30
  </div>
31
31
  </div>
32
- <el-empty v-else class="mt20 mb20" :image-size="100" description="暂无菜单" />
32
+ <el-empty v-else class="mt20 mb20" :image-size="100" :description="t('core.header.menuSearchEmpty')" />
33
33
  </el-dialog>
34
34
  </div>
35
35
  </template>
@@ -43,6 +43,7 @@ import { useRouter } from "vue-router";
43
43
  import { useDebounceFn } from "@vueuse/core";
44
44
  import type { RouteItem } from "../../../../rpc/system/admin/v1/auth";
45
45
  import { getRouteMetaHidden, getRouteMetaIcon, getRouteMetaTitle, getRouteTarget, isExternalPath } from "../../../../utils";
46
+ import { useLocaleStore } from "../../../../locales";
46
47
 
47
48
  /** 可被菜单搜索展示的路由项。 */
48
49
  interface SearchRouteItem extends RouteItem {
@@ -51,6 +52,7 @@ interface SearchRouteItem extends RouteItem {
51
52
 
52
53
  const router = useRouter();
53
54
  const authStore = useAuthStore();
55
+ const { t } = useLocaleStore();
54
56
  const menuList = computed<SearchRouteItem[]>(() => {
55
57
  return authStore.flatMenuListGet.filter((item): item is SearchRouteItem => {
56
58
  return Boolean(item.path) && !getRouteMetaHidden(item.meta);
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="theme-setting">
3
- <el-tooltip effect="dark" content="主题设置" placement="bottom" :show-after="200">
3
+ <el-tooltip effect="dark" :content="t('core.header.theme')" placement="bottom" :show-after="200">
4
4
  <i :class="'iconfont icon-zhuti'" class="toolBar-icon" @click="openDrawer"></i>
5
5
  </el-tooltip>
6
6
  </div>
@@ -8,6 +8,8 @@
8
8
 
9
9
  <script setup lang="ts">
10
10
  import mittBus from "../../../../utils/mittBus";
11
+ import { useLocaleStore } from "../../../../locales";
12
+ const { t } = useLocaleStore();
11
13
  const openDrawer = () => {
12
14
  mittBus.emit("openThemeDrawer");
13
15
  };
@@ -6,25 +6,25 @@
6
6
  <template #dropdown>
7
7
  <el-dropdown-menu>
8
8
  <el-dropdown-item @click="refresh">
9
- <el-icon><Refresh /></el-icon>刷新当前
9
+ <el-icon><Refresh /></el-icon>{{ t("core.tabs.refresh") }}
10
10
  </el-dropdown-item>
11
11
  <el-dropdown-item @click="maximize">
12
- <el-icon><FullScreen /></el-icon>最大化
12
+ <el-icon><FullScreen /></el-icon>{{ t("core.tabs.maximize") }}
13
13
  </el-dropdown-item>
14
14
  <el-dropdown-item divided @click="closeCurrentTab">
15
- <el-icon><Remove /></el-icon>关闭当前
15
+ <el-icon><Remove /></el-icon>{{ t("core.tabs.closeCurrent") }}
16
16
  </el-dropdown-item>
17
17
  <el-dropdown-item @click="tabStore.closeTabsOnSide(currentTabPath, 'left')">
18
- <el-icon><DArrowLeft /></el-icon>关闭左侧
18
+ <el-icon><DArrowLeft /></el-icon>{{ t("core.tabs.closeLeft") }}
19
19
  </el-dropdown-item>
20
20
  <el-dropdown-item @click="tabStore.closeTabsOnSide(currentTabPath, 'right')">
21
- <el-icon><DArrowRight /></el-icon>关闭右侧
21
+ <el-icon><DArrowRight /></el-icon>{{ t("core.tabs.closeRight") }}
22
22
  </el-dropdown-item>
23
23
  <el-dropdown-item divided @click="tabStore.closeMultipleTab(currentTabPath)">
24
- <el-icon><CircleClose /></el-icon>关闭其他
24
+ <el-icon><CircleClose /></el-icon>{{ t("core.tabs.closeOther") }}
25
25
  </el-dropdown-item>
26
26
  <el-dropdown-item @click="closeAllTab">
27
- <el-icon><FolderDelete /></el-icon>关闭全部
27
+ <el-icon><FolderDelete /></el-icon>{{ t("core.tabs.closeAll") }}
28
28
  </el-dropdown-item>
29
29
  </el-dropdown-menu>
30
30
  </template>
@@ -39,12 +39,14 @@ import { useTabsStore } from "../../../../stores/modules/tabs";
39
39
  import { useGlobalStore } from "../../../../stores/modules/global";
40
40
  import { useKeepAliveStore } from "../../../../stores/modules/keepAlive";
41
41
  import { useRoute, useRouter } from "vue-router";
42
+ import { useLocaleStore } from "../../../../locales";
42
43
 
43
44
  const route = useRoute();
44
45
  const router = useRouter();
45
46
  const tabStore = useTabsStore();
46
47
  const globalStore = useGlobalStore();
47
48
  const keepAliveStore = useKeepAliveStore();
49
+ const { t } = useLocaleStore();
48
50
  const currentTabPath = computed(() => getAdminTabPath(route));
49
51
 
50
52
  // refresh current page