@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.
- package/README.md +2 -2
- package/dist/package/declarations/src/api/base/language.d.ts +8 -0
- package/dist/package/declarations/src/components/Dialog/ProDialog.vue.d.ts +1 -0
- package/dist/package/declarations/src/components/LocaleSwitch/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/index.d.ts +2 -0
- package/dist/package/declarations/src/locales/index.d.ts +63 -0
- package/dist/package/declarations/src/modules/index.d.ts +7 -2
- package/dist/package/declarations/src/request.d.ts +1 -0
- package/dist/package/declarations/src/routers/modules/staticRouter.d.ts +1 -0
- package/dist/package/declarations/src/rpc/base/v1/config.d.ts +2 -0
- package/dist/package/declarations/src/rpc/base/v1/language.d.ts +26 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +79 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_translation.d.ts +102 -0
- package/dist/package/declarations/src/stores/interface/index.d.ts +2 -0
- package/dist/package/declarations/src/stores/runtime.d.ts +1 -0
- package/dist/package/declarations/src/utils/dict.d.ts +2 -2
- package/dist/package/declarations/src/utils/index.d.ts +1 -1
- package/dist/package/declarations/src/utils/oauthProvider.d.ts +2 -0
- package/dist/package/declarations/src/utils/passwordStrength.d.ts +0 -7
- package/dist/package/src/App.vue +10 -1
- package/dist/package/src/api/base/language.ts +20 -0
- package/dist/package/src/api/base/oauth.ts +0 -1
- package/dist/package/src/api/system/auth.ts +0 -1
- package/dist/package/src/bootstrap.ts +57 -2
- package/dist/package/src/components/CronExpression/index.vue +80 -82
- package/dist/package/src/components/Dialog/FormDialog.vue +9 -4
- package/dist/package/src/components/Dialog/ProDialog.vue +10 -4
- package/dist/package/src/components/Dict/index.vue +5 -2
- package/dist/package/src/components/ECharts/config/index.ts +6 -1
- package/dist/package/src/components/ErrorMessage/index.vue +3 -1
- package/dist/package/src/components/ImportExcel/index.vue +29 -18
- package/dist/package/src/components/LocaleSwitch/index.vue +28 -0
- package/dist/package/src/components/PasswordStrength/index.vue +8 -5
- package/dist/package/src/components/ProForm/components/DynamicList.vue +8 -3
- package/dist/package/src/components/ProForm/components/KvList.vue +14 -6
- package/dist/package/src/components/ProTable/components/ColSetting.vue +7 -5
- package/dist/package/src/components/ProTable/components/TableColumn.vue +2 -1
- package/dist/package/src/components/ProTable/index.vue +36 -11
- package/dist/package/src/components/SearchForm/components/SearchFormItem.vue +9 -4
- package/dist/package/src/components/SearchForm/index.vue +6 -3
- package/dist/package/src/components/SelectFilter/index.vue +4 -1
- package/dist/package/src/components/SelectIcon/index.vue +8 -4
- package/dist/package/src/components/TreeFilter/index.vue +14 -6
- package/dist/package/src/components/Upload/File.vue +18 -13
- package/dist/package/src/components/Upload/Files.vue +22 -15
- package/dist/package/src/components/Upload/Img.vue +14 -11
- package/dist/package/src/components/Upload/Imgs.vue +15 -12
- package/dist/package/src/components/WangEditor/index.vue +12 -4
- package/dist/package/src/directives/modules/copy.ts +2 -1
- package/dist/package/src/hooks/useDownload.ts +3 -2
- package/dist/package/src/hooks/useHandleData.ts +5 -4
- package/dist/package/src/hooks/useTheme.ts +2 -1
- package/dist/package/src/hooks/useTime.ts +11 -2
- package/dist/package/src/index.ts +2 -0
- package/dist/package/src/layouts/components/Header/ToolBarRight.vue +2 -0
- package/dist/package/src/layouts/components/Header/components/AssemblySize.vue +8 -6
- package/dist/package/src/layouts/components/Header/components/Avatar.vue +11 -9
- package/dist/package/src/layouts/components/Header/components/Breadcrumb.vue +10 -2
- package/dist/package/src/layouts/components/Header/components/Fullscreen.vue +4 -2
- package/dist/package/src/layouts/components/Header/components/InfoDialog.vue +6 -3
- package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +6 -3
- package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +5 -3
- package/dist/package/src/layouts/components/Header/components/ThemeSetting.vue +3 -1
- package/dist/package/src/layouts/components/Tabs/components/MoreButton.vue +9 -7
- package/dist/package/src/layouts/components/ThemeDrawer/index.vue +27 -24
- package/dist/package/src/locales/README.md +15 -0
- package/dist/package/src/locales/en-US.json +258 -0
- package/dist/package/src/locales/es-ES.json +258 -0
- package/dist/package/src/locales/fr-FR.json +258 -0
- package/dist/package/src/locales/index.ts +223 -0
- package/dist/package/src/locales/ja-JP.json +258 -0
- package/dist/package/src/locales/ko-KR.json +258 -0
- package/dist/package/src/locales/zh-CN.json +258 -0
- package/dist/package/src/locales/zh-TW.json +258 -0
- package/dist/package/src/modules/index.ts +7 -2
- package/dist/package/src/modules/kratosAdmin.ts +19 -1
- package/dist/package/src/request.ts +8 -1
- package/dist/package/src/routers/index.ts +4 -1
- package/dist/package/src/routers/modules/dynamicRouter.ts +3 -2
- package/dist/package/src/routers/modules/staticRouter.ts +8 -4
- package/dist/package/src/rpc/base/v1/config.ts +2 -0
- package/dist/package/src/rpc/base/v1/language.ts +37 -0
- package/dist/package/src/rpc/system/admin/v1/base_dict.ts +81 -0
- package/dist/package/src/rpc/system/admin/v1/base_translation.ts +117 -0
- package/dist/package/src/stores/interface/index.ts +2 -0
- package/dist/package/src/stores/modules/config.ts +5 -1
- package/dist/package/src/stores/modules/user.ts +2 -1
- package/dist/package/src/stores/runtime.ts +1 -0
- package/dist/package/src/utils/color.ts +5 -4
- package/dist/package/src/utils/dict.ts +27 -4
- package/dist/package/src/utils/eleValidate.ts +3 -2
- package/dist/package/src/utils/errorHandler.ts +9 -8
- package/dist/package/src/utils/index.ts +7 -6
- package/dist/package/src/utils/oauthProvider.ts +15 -10
- package/dist/package/src/utils/passwordCrypto.ts +3 -2
- package/dist/package/src/utils/passwordStrength.ts +1 -16
- package/dist/package/src/utils/request.ts +13 -8
- package/dist/package/src/views/error/403.vue +3 -1
- package/dist/package/src/views/error/404.vue +3 -1
- package/dist/package/src/views/error/500.vue +3 -1
- package/dist/package/src/views/error/pending.vue +5 -2
- package/dist/package/src/views/login/components/LoginForm.vue +53 -27
- package/dist/package/src/views/login/index.scss +6 -0
- package/dist/package/src/views/login/index.vue +2 -0
- package/dist/package/types/generated/auto-imports.d.ts +129 -111
- package/dist/package/types/generated/components.d.ts +67 -67
- package/package.json +3 -1
- package/types/generated/auto-imports.d.ts +129 -111
- package/types/generated/components.d.ts +67 -67
- 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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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:
|
|
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 = "
|
|
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 =
|
|
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="
|
|
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: "
|
|
31
|
-
{ label: "
|
|
32
|
-
{ label: "
|
|
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
|
|
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
|
|
43
|
+
if (breadcrumbData[0]?.path !== HOME_URL) {
|
|
42
44
|
breadcrumbData = [
|
|
43
|
-
{
|
|
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
|
|
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="
|
|
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"
|
|
7
|
-
<el-button type="primary" @click="dialogVisible = false"
|
|
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="
|
|
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"
|
|
7
|
-
<el-button type="primary" @click="dialogVisible = false"
|
|
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="
|
|
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="
|
|
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
|