@liujitcn/kratos-admin-system 0.0.51 → 0.0.53
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 +1 -1
- package/dist/package/declarations/src/api/base/v1/sse.d.ts +1 -1
- package/dist/package/declarations/src/components/tenant-project/TenantProjectManager.vue.d.ts +1 -2
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager-data.d.ts +10 -0
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager.d.ts +8 -3
- package/dist/package/declarations/src/index.d.ts +1 -1
- package/dist/package/declarations/src/locales/generated.d.ts +32 -0
- package/dist/package/declarations/src/rpc/base/v1/ai_search.d.ts +26 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +0 -1
- package/dist/package/declarations/src/views/ai/chat/components/speech-recognition.d.ts +6 -2
- package/dist/package/src/api/base/v1/sse.ts +19 -12
- package/dist/package/src/components/log/LogTable.vue +25 -18
- package/dist/package/src/components/notification/Notification.vue +14 -7
- package/dist/package/src/components/tenant-project/TenantProjectManager.vue +106 -62
- package/dist/package/src/components/tenant-project/tenant-project-manager-data.ts +39 -1
- package/dist/package/src/components/tenant-project/tenant-project-manager.ts +19 -4
- package/dist/package/src/components/tenant-project-grant/ProjectGrantDialog.vue +22 -7
- package/dist/package/src/index.ts +2 -0
- package/dist/package/src/locales/en-US.json +8 -0
- package/dist/package/src/locales/ja-JP.json +8 -0
- package/dist/package/src/locales/zh-CN.json +8 -0
- package/dist/package/src/locales/zh-TW.json +8 -0
- package/dist/package/src/rpc/base/v1/ai_search.ts +37 -0
- package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +0 -1
- package/dist/package/src/views/ai/chat/components/XSender.vue +1 -36
- package/dist/package/src/views/ai/chat/components/speech-recognition.ts +28 -7
- package/dist/package/src/views/ai/chat/index.vue +16 -7
- package/dist/package/src/views/base/api-log/index.vue +1 -1
- package/dist/package/src/views/base/area/index.vue +15 -9
- package/dist/package/src/views/base/backup-management/archive-config/index.vue +22 -10
- package/dist/package/src/views/base/backup-management/backup-config/index.vue +13 -6
- package/dist/package/src/views/base/config/index.vue +38 -14
- package/dist/package/src/views/base/dept/index.vue +31 -25
- package/dist/package/src/views/base/dict/index.vue +12 -8
- package/dist/package/src/views/base/dict/item.vue +12 -8
- package/dist/package/src/views/base/i18n-custom/index.vue +13 -7
- package/dist/package/src/views/base/job/index.vue +12 -8
- package/dist/package/src/views/base/job/log.vue +14 -9
- package/dist/package/src/views/base/language/index.vue +7 -4
- package/dist/package/src/views/base/login-policy/index.vue +22 -11
- package/dist/package/src/views/base/menu/index.vue +23 -16
- package/dist/package/src/views/base/message/index.vue +65 -21
- package/dist/package/src/views/base/message-category/index.vue +10 -4
- package/dist/package/src/views/base/oauth-client/index.vue +15 -5
- package/dist/package/src/views/base/post/index.vue +10 -4
- package/dist/package/src/views/base/redact-output-policy/index.vue +12 -5
- package/dist/package/src/views/base/redact-rule/index.vue +8 -7
- package/dist/package/src/views/base/redact-storage-policy/index.vue +32 -8
- package/dist/package/src/views/base/role/index.vue +24 -17
- package/dist/package/src/views/base/tenant/index.vue +7 -6
- package/dist/package/src/views/base/tenant-project-grant/index.vue +44 -27
- package/dist/package/src/views/base/user/components/dept-tree.vue +4 -9
- package/dist/package/src/views/base/user/index.vue +39 -28
- package/dist/package/src/views/message/inbox/index.vue +8 -3
- package/dist/package/src/views/profile/components/base.vue +1 -1
- package/dist/package/src/views/profile/index.vue +1 -1
- package/dist/package/src/views/tool/cache/index.vue +1 -1
- package/dist/package/src/views/tool/code-gen/columns/index.vue +35 -16
- package/dist/package/src/views/tool/code-gen/table/index.vue +58 -31
- package/package.json +2 -2
|
@@ -5,6 +5,7 @@ export type SpeechResultList = ArrayLike<{
|
|
|
5
5
|
0?: {
|
|
6
6
|
transcript: string;
|
|
7
7
|
};
|
|
8
|
+
isFinal?: boolean;
|
|
8
9
|
length: number;
|
|
9
10
|
}>;
|
|
10
11
|
|
|
@@ -17,6 +18,7 @@ export type SpeechRecognitionError = {
|
|
|
17
18
|
|
|
18
19
|
type SpeechRecognitionResultEvent = {
|
|
19
20
|
results: SpeechResultList;
|
|
21
|
+
resultIndex: number;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
type SpeechRecognitionInstance = {
|
|
@@ -49,13 +51,28 @@ type SpeechRecognitionOptions = {
|
|
|
49
51
|
onResult?: (text: string) => void;
|
|
50
52
|
};
|
|
51
53
|
|
|
52
|
-
/**
|
|
53
|
-
export function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
/** 增量累积语音识别结果,避免连续模式下 interim 结果重复计入已确认文本。 */
|
|
55
|
+
export function accumulateSpeechResultText(
|
|
56
|
+
results: SpeechResultList,
|
|
57
|
+
resultIndex: number,
|
|
58
|
+
previousFinalText: string
|
|
59
|
+
): { finalText: string; text: string } {
|
|
60
|
+
let finalText = previousFinalText;
|
|
61
|
+
let interimText = "";
|
|
62
|
+
for (let index = resultIndex; index < results.length; index++) {
|
|
63
|
+
const result = results[index];
|
|
64
|
+
const transcript = result?.[0]?.transcript ?? "";
|
|
65
|
+
if (result?.isFinal) {
|
|
66
|
+
finalText += transcript;
|
|
67
|
+
} else {
|
|
68
|
+
interimText += transcript;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Chrome 连续模式下 interim 结果会累计包含已确认的 final 文本,去除重复前缀。
|
|
72
|
+
if (interimText && finalText && interimText.startsWith(finalText)) {
|
|
73
|
+
interimText = interimText.slice(finalText.length);
|
|
57
74
|
}
|
|
58
|
-
return text;
|
|
75
|
+
return { finalText, text: finalText + interimText };
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
/** 创建浏览器语音识别实例,并统一结果、状态和卸载处理。 */
|
|
@@ -64,6 +81,7 @@ export function useSpeechRecognition({ onError, onStart, onEnd, onResult }: Spee
|
|
|
64
81
|
const value = ref("");
|
|
65
82
|
let recognition: SpeechRecognitionInstance | null = null;
|
|
66
83
|
let recognitionSession = 0;
|
|
84
|
+
let finalText = "";
|
|
67
85
|
|
|
68
86
|
/** 获取当前浏览器支持的语音识别构造函数。 */
|
|
69
87
|
function resolveRecognitionConstructor() {
|
|
@@ -84,6 +102,7 @@ export function useSpeechRecognition({ onError, onStart, onEnd, onResult }: Spee
|
|
|
84
102
|
const nextRecognition = new RecognitionConstructor();
|
|
85
103
|
const currentSession = ++recognitionSession;
|
|
86
104
|
recognition = nextRecognition;
|
|
105
|
+
finalText = "";
|
|
87
106
|
const isCurrentRecognition = () => recognition === nextRecognition && recognitionSession === currentSession;
|
|
88
107
|
nextRecognition.continuous = true;
|
|
89
108
|
nextRecognition.interimResults = true;
|
|
@@ -96,7 +115,9 @@ export function useSpeechRecognition({ onError, onStart, onEnd, onResult }: Spee
|
|
|
96
115
|
};
|
|
97
116
|
nextRecognition.onresult = event => {
|
|
98
117
|
if (!isCurrentRecognition()) return;
|
|
99
|
-
|
|
118
|
+
const accumulated = accumulateSpeechResultText(event.results, event.resultIndex, finalText);
|
|
119
|
+
finalText = accumulated.finalText;
|
|
120
|
+
value.value = accumulated.text;
|
|
100
121
|
onResult?.(value.value);
|
|
101
122
|
};
|
|
102
123
|
nextRecognition.onerror = error => {
|
|
@@ -107,6 +107,7 @@ const pendingDeltaMap = new Map<string, AiStreamPayload>();
|
|
|
107
107
|
const runningStreamTaskMap = new Map<string, AiStreamTask>();
|
|
108
108
|
let pendingDeltaFrame = 0;
|
|
109
109
|
let speakingMessageID = "";
|
|
110
|
+
let createSessionPromise: Promise<string | undefined> | undefined;
|
|
110
111
|
|
|
111
112
|
/** 当前会话的流式任务状态。 */
|
|
112
113
|
type AiStreamTask = {
|
|
@@ -728,13 +729,21 @@ async function ensureActiveSession() {
|
|
|
728
729
|
|
|
729
730
|
/** 创建新的助手会话,并同步到本地列表。 */
|
|
730
731
|
async function createSession(options?: { title?: string }) {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
732
|
+
if (createSessionPromise) return createSessionPromise;
|
|
733
|
+
createSessionPromise = (async () => {
|
|
734
|
+
const response = await defAiSessionService.CreateAiSession({
|
|
735
|
+
title: options?.title || t("system.ai.chat.value.new_conversation"),
|
|
736
|
+
terminal: Terminal.TERMINAL_ADMIN
|
|
737
|
+
});
|
|
738
|
+
const normalizedSession = normalizeSession(response.session);
|
|
739
|
+
upsertSession(normalizedSession);
|
|
740
|
+
return normalizedSession.id;
|
|
741
|
+
})();
|
|
742
|
+
try {
|
|
743
|
+
return await createSessionPromise;
|
|
744
|
+
} finally {
|
|
745
|
+
createSessionPromise = undefined;
|
|
746
|
+
}
|
|
738
747
|
}
|
|
739
748
|
|
|
740
749
|
/** 使用当前消息内容生成一个易识别的分支会话标题。 */
|
|
@@ -35,7 +35,7 @@ const resultOptions = computed(() =>
|
|
|
35
35
|
])
|
|
36
36
|
);
|
|
37
37
|
const columns = computed<ColumnProps[]>(() => [
|
|
38
|
-
{ prop: "operation", label: t("system.base.log.field.operation"), minWidth: 320, search: { el: "input" } },
|
|
38
|
+
{ prop: "operation", label: t("system.base.log.field.operation"), minWidth: 320, search: { el: "input", key: "keyword" } },
|
|
39
39
|
{ prop: "method", label: t("system.base.log.field.method"), minWidth: 90 },
|
|
40
40
|
{ prop: "status_code", label: t("system.base.log.field.status_code"), minWidth: 100, align: "right" },
|
|
41
41
|
{
|
|
@@ -113,7 +113,9 @@ async function loadParentIdFormTreeOptions(
|
|
|
113
113
|
resolve(normalizeLazyTreeOptions((response.list ?? []) as GeneratedTreeOption[]));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
void loadFormOptions()
|
|
116
|
+
void loadFormOptions().then(options => {
|
|
117
|
+
parentIdFormOptions.value = options;
|
|
118
|
+
});
|
|
117
119
|
|
|
118
120
|
/** 行政区域表单字段配置。 */
|
|
119
121
|
const formFields = computed<ProFormField[]>(() => [
|
|
@@ -218,7 +220,7 @@ async function loadFormOptions() {
|
|
|
218
220
|
const parentIdFormResponse = await defBaseAreaService.OptionBaseArea({ parent_id: 0, lazy: true } as Parameters<
|
|
219
221
|
typeof defBaseAreaService.OptionBaseArea
|
|
220
222
|
>[0]);
|
|
221
|
-
|
|
223
|
+
return [
|
|
222
224
|
{ label: t("system.base.area.value.root"), value: 0 },
|
|
223
225
|
...normalizeLazyTreeOptions((parentIdFormResponse.list ?? []) as GeneratedTreeOption[]).filter(
|
|
224
226
|
option => Number(option.value) !== 0
|
|
@@ -231,19 +233,23 @@ async function loadFormOptions() {
|
|
|
231
233
|
*/
|
|
232
234
|
async function handleOpenDialog(id?: number) {
|
|
233
235
|
resetForm();
|
|
234
|
-
await loadFormOptions();
|
|
235
236
|
dialog.titleKey = id ? "system.base.area.action.edit" : "system.base.area.action.create";
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
await formDialogRef.value?.open({
|
|
238
|
+
load: async () => ({
|
|
239
|
+
options: await loadFormOptions(),
|
|
240
|
+
data: id ? await defBaseAreaService.GetBaseArea({ id }) : undefined
|
|
241
|
+
}),
|
|
242
|
+
commit: ({ options, data }) => {
|
|
243
|
+
parentIdFormOptions.value = options;
|
|
244
|
+
if (data) Object.assign(formData, data);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
241
247
|
}
|
|
242
248
|
/**
|
|
243
249
|
* 关闭行政区域弹窗。
|
|
244
250
|
*/
|
|
245
251
|
function handleCloseDialog() {
|
|
246
|
-
|
|
252
|
+
formDialogRef.value?.close();
|
|
247
253
|
resetForm();
|
|
248
254
|
}
|
|
249
255
|
/**
|
|
@@ -83,13 +83,21 @@ function refresh() { proTable.value?.getTableList(); }
|
|
|
83
83
|
function defaultForm(): BaseTableArchiveForm { return { id: 0, source_name: "", table_name: "", archive_mode: BaseTableArchiveMode.BASE_TABLE_ARCHIVE_MODE_INTERNAL_DATABASE, online_retention_days: 180, archive_retention_days: 3650, batch_size: 5000, delete_after_verify: false, oss_prefix: "archive", status: Status.STATUS_ENABLE }; }
|
|
84
84
|
function resetForm() { dialog.visible = false; formDialogRef.value?.resetFields(); Object.assign(formData, defaultForm()); }
|
|
85
85
|
async function openDialog(id?: number) {
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
await formDialogRef.value?.open({
|
|
87
|
+
load: async () => {
|
|
88
|
+
await loadSourceOptions();
|
|
89
|
+
const data = id ? await defBaseTableArchiveService.GetBaseTableArchive({ id }) : undefined;
|
|
90
|
+
const form = { ...defaultForm(), ...(data ?? {}) };
|
|
91
|
+
if (!form.source_name) form.source_name = String(sourceOptions.value[0]?.value ?? "");
|
|
92
|
+
const loadedTableOptions = form.source_name ? await requestTableOptions(form.source_name) : [];
|
|
93
|
+
return { form, loadedTableOptions };
|
|
94
|
+
},
|
|
95
|
+
commit: ({ form, loadedTableOptions }) => {
|
|
96
|
+
Object.assign(formData, form);
|
|
97
|
+
dialog.editing = Boolean(id);
|
|
98
|
+
tableOptions.value = loadedTableOptions;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
93
101
|
}
|
|
94
102
|
async function loadSourceOptions() {
|
|
95
103
|
if (sourceOptions.value.length || loadingSources.value) return;
|
|
@@ -107,12 +115,16 @@ async function handleSourceChange(value: string | number | boolean | undefined)
|
|
|
107
115
|
await loadTableOptions(formData.source_name);
|
|
108
116
|
}
|
|
109
117
|
async function loadTableOptions(sourceName: string) {
|
|
110
|
-
tableOptions.value =
|
|
111
|
-
|
|
118
|
+
tableOptions.value = await requestTableOptions(sourceName);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** 请求指定数据源下的数据表选项。 */
|
|
122
|
+
async function requestTableOptions(sourceName: string) {
|
|
123
|
+
if (!sourceName) return [];
|
|
112
124
|
loadingTables.value = true;
|
|
113
125
|
try {
|
|
114
126
|
const data = await defBaseTableSourceService.OptionBaseTable({ source_name: sourceName });
|
|
115
|
-
|
|
127
|
+
return (data.value ?? []).map(value => ({ label: value, value }));
|
|
116
128
|
} finally {
|
|
117
129
|
loadingTables.value = false;
|
|
118
130
|
}
|
|
@@ -68,12 +68,19 @@ function refresh() { proTable.value?.getTableList(); }
|
|
|
68
68
|
function defaultForm(): BaseTableBackupForm { return { id: 0, source_name: "", backup_type: BaseTableBackupType.BASE_TABLE_BACKUP_TYPE_FULL, oss_prefix: "backup/database", retention_count: 7, status: Status.STATUS_ENABLE }; }
|
|
69
69
|
function resetForm() { dialog.visible = false; formDialogRef.value?.resetFields(); Object.assign(formData, defaultForm()); }
|
|
70
70
|
async function openDialog(id?: number) {
|
|
71
|
-
await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
await formDialogRef.value?.open({
|
|
72
|
+
load: async () => {
|
|
73
|
+
await loadSourceOptions();
|
|
74
|
+
const data = id ? await defBaseTableBackupService.GetBaseTableBackup({ id }) : undefined;
|
|
75
|
+
const form = { ...defaultForm(), ...(data ?? {}) };
|
|
76
|
+
if (!form.source_name) form.source_name = String(sourceOptions.value[0]?.value ?? "");
|
|
77
|
+
return form;
|
|
78
|
+
},
|
|
79
|
+
commit: form => {
|
|
80
|
+
Object.assign(formData, form);
|
|
81
|
+
dialog.editing = Boolean(id);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
77
84
|
}
|
|
78
85
|
async function loadSourceOptions() {
|
|
79
86
|
if (sourceOptions.value.length || loadingSources.value) return;
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
/>
|
|
11
11
|
|
|
12
12
|
<ProDialog
|
|
13
|
+
ref="dialogRef"
|
|
13
14
|
v-model="dialog.visible"
|
|
14
15
|
class="system-config-dialog"
|
|
15
16
|
:title="t(dialog.titleKey, { resource: t('system.base.config.resource') })"
|
|
16
|
-
width="min(
|
|
17
|
+
width="min(1280px, calc(100vw - 32px))"
|
|
17
18
|
top="4vh"
|
|
18
19
|
:confirm-loading="saving"
|
|
19
20
|
@confirm="handleSubmit"
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
:rules="rules"
|
|
33
34
|
:col-span="12"
|
|
34
35
|
:gutter="24"
|
|
36
|
+
label-width="10em"
|
|
35
37
|
label-position="right"
|
|
36
38
|
scroll-to-error
|
|
37
39
|
>
|
|
@@ -96,6 +98,7 @@
|
|
|
96
98
|
:fields="localizedFormFields"
|
|
97
99
|
:col-span="12"
|
|
98
100
|
:gutter="24"
|
|
101
|
+
label-width="10em"
|
|
99
102
|
label-position="right"
|
|
100
103
|
scroll-to-error
|
|
101
104
|
/>
|
|
@@ -160,6 +163,7 @@ defineOptions({
|
|
|
160
163
|
|
|
161
164
|
const { BUTTONS } = useAuthButtons();
|
|
162
165
|
const proTable = ref<ProTableInstance>();
|
|
166
|
+
const dialogRef = ref<InstanceType<typeof ProDialog>>();
|
|
163
167
|
const basicFormRef = ref<ProFormInstance>();
|
|
164
168
|
const activeTab = ref("basic");
|
|
165
169
|
|
|
@@ -635,29 +639,48 @@ function refreshTable() {
|
|
|
635
639
|
* 打开系统配置弹窗。
|
|
636
640
|
*/
|
|
637
641
|
async function handleOpenDialog(configId?: number) {
|
|
638
|
-
await loadEnabledBaseLanguages();
|
|
639
642
|
resetForm();
|
|
640
643
|
dialog.titleKey = configId ? "common.action.edit_resource" : "common.action.create_resource";
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
644
|
+
await dialogRef.value?.open({
|
|
645
|
+
load: async () => ({
|
|
646
|
+
data: configId ? await defBaseConfigService.GetBaseConfig({ id: configId }) : undefined,
|
|
647
|
+
languages: await loadEnabledBaseLanguages()
|
|
648
|
+
}),
|
|
649
|
+
commit: ({ data }) => {
|
|
650
|
+
if (data) {
|
|
651
|
+
Object.assign(formData, data);
|
|
652
|
+
if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM) loadFormValue(formData.value);
|
|
653
|
+
}
|
|
654
|
+
activeTab.value = configId && formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM ? "form" : "basic";
|
|
645
655
|
}
|
|
646
|
-
}
|
|
647
|
-
activeTab.value = configId && formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM ? "form" : "basic";
|
|
648
|
-
dialog.visible = true;
|
|
656
|
+
});
|
|
649
657
|
}
|
|
650
658
|
|
|
651
659
|
/** 按注册定义创建独立模型,并用已保存的配置值覆盖默认值。 */
|
|
652
660
|
function loadFormValue(value?: string) {
|
|
653
661
|
const definition = formDefinition.value;
|
|
662
|
+
const parsed = value ? parseJSONValue(value) : {};
|
|
654
663
|
formValue.value =
|
|
655
|
-
formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM && definition
|
|
656
|
-
? Object.assign(definition.createModel(),
|
|
657
|
-
: {};
|
|
664
|
+
formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM && definition && isJSONObject(parsed)
|
|
665
|
+
? Object.assign(definition.createModel(), parsed)
|
|
666
|
+
: definition?.createModel() ?? {};
|
|
658
667
|
valueFormRef.value?.clearValidate();
|
|
659
668
|
}
|
|
660
669
|
|
|
670
|
+
/** 安全解析运行配置 JSON,脏数据回退到表单默认模型。 */
|
|
671
|
+
function parseJSONValue(value: string): unknown {
|
|
672
|
+
try {
|
|
673
|
+
return JSON.parse(value);
|
|
674
|
+
} catch {
|
|
675
|
+
return undefined;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/** 判断运行配置 JSON 是否为可合并对象。 */
|
|
680
|
+
function isJSONObject(value: unknown): value is Record<string, unknown> {
|
|
681
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
682
|
+
}
|
|
683
|
+
|
|
661
684
|
/** 按字段声明恢复运行配置提交值的 JSON 类型。 */
|
|
662
685
|
function normalizeRuntimeConfigValue() {
|
|
663
686
|
if (!formDefinition.value) return;
|
|
@@ -669,7 +692,8 @@ function normalizeRuntimeConfigValue() {
|
|
|
669
692
|
} else if (field.valueType === "boolean" && typeof value === "string") {
|
|
670
693
|
setRuntimeConfigFieldValue(field.prop, value === "true");
|
|
671
694
|
} else if (field.valueType === "json" && typeof value === "string" && value !== "") {
|
|
672
|
-
|
|
695
|
+
const parsed = parseJSONValue(value);
|
|
696
|
+
if (parsed !== undefined) setRuntimeConfigFieldValue(field.prop, parsed);
|
|
673
697
|
}
|
|
674
698
|
}
|
|
675
699
|
}
|
|
@@ -690,7 +714,7 @@ function setRuntimeConfigFieldValue(prop: string, value: unknown) {
|
|
|
690
714
|
* 关闭系统配置弹窗并恢复默认表单值。
|
|
691
715
|
*/
|
|
692
716
|
function handleCloseDialog() {
|
|
693
|
-
|
|
717
|
+
dialogRef.value?.close();
|
|
694
718
|
resetForm();
|
|
695
719
|
}
|
|
696
720
|
|
|
@@ -301,16 +301,15 @@ function refreshTable() {
|
|
|
301
301
|
/**
|
|
302
302
|
* 加载部门下拉树数据,供弹窗选择上级部门。
|
|
303
303
|
*/
|
|
304
|
-
async function
|
|
304
|
+
async function requestDeptOptions(tenantId = formData.tenant_id) {
|
|
305
305
|
// 默认租户未选择目标租户时仅保留顶级部门,避免混入其他租户的部门树。
|
|
306
|
-
if (isDefaultTenant.value && !
|
|
307
|
-
|
|
308
|
-
return;
|
|
306
|
+
if (isDefaultTenant.value && !tenantId) {
|
|
307
|
+
return [{ value: 0, label: t("system.base.dept.value.root"), disabled: false, has_children: true, children: [] }];
|
|
309
308
|
}
|
|
310
309
|
const optionBaseDeptResponse = await defBaseDeptService.OptionBaseDept({
|
|
311
|
-
tenant_id: toRequestTenantId(
|
|
310
|
+
tenant_id: toRequestTenantId(tenantId)
|
|
312
311
|
});
|
|
313
|
-
|
|
312
|
+
return [
|
|
314
313
|
{
|
|
315
314
|
value: 0,
|
|
316
315
|
label: t("system.base.dept.value.root"),
|
|
@@ -321,6 +320,11 @@ async function loadDeptOptions() {
|
|
|
321
320
|
];
|
|
322
321
|
}
|
|
323
322
|
|
|
323
|
+
/** 加载部门下拉树数据并更新表单选项。 */
|
|
324
|
+
async function loadDeptOptions() {
|
|
325
|
+
deptOptions.value = await requestDeptOptions();
|
|
326
|
+
}
|
|
327
|
+
|
|
324
328
|
/**
|
|
325
329
|
* 切换表单租户时重新加载对应租户的上级部门树。
|
|
326
330
|
*/
|
|
@@ -333,31 +337,33 @@ async function handleFormTenantChange() {
|
|
|
333
337
|
* 打开部门弹窗。
|
|
334
338
|
*/
|
|
335
339
|
async function handleOpenDialog(parent_id?: number, deptId?: number, tenantId?: number) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
340
|
+
await formDialogRef.value?.open({
|
|
341
|
+
load: async () => {
|
|
342
|
+
await loadTenantOptions();
|
|
343
|
+
const data = deptId ? await defBaseDeptService.GetBaseDept({ id: deptId }) : undefined;
|
|
344
|
+
const options = await requestDeptOptions(data?.tenant_id ?? tenantId);
|
|
345
|
+
return { data, options };
|
|
346
|
+
},
|
|
347
|
+
commit: ({ data, options }) => {
|
|
348
|
+
resetForm();
|
|
349
|
+
deptOptions.value = options;
|
|
350
|
+
dialog.titleKey = deptId ? "common.action.edit_resource" : "common.action.create_resource";
|
|
351
|
+
if (data) {
|
|
352
|
+
Object.assign(formData, data);
|
|
353
|
+
} else {
|
|
354
|
+
// 从部门行新增子部门时,继承父部门租户并加载同租户上级部门树。
|
|
355
|
+
formData.tenant_id = tenantId;
|
|
356
|
+
formData.parent_id = parent_id ?? 0;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
});
|
|
354
360
|
}
|
|
355
361
|
|
|
356
362
|
/**
|
|
357
363
|
* 关闭部门弹窗。
|
|
358
364
|
*/
|
|
359
365
|
function handleCloseDialog() {
|
|
360
|
-
|
|
366
|
+
formDialogRef.value?.close();
|
|
361
367
|
resetForm();
|
|
362
368
|
}
|
|
363
369
|
|
|
@@ -247,22 +247,26 @@ function refreshTable() {
|
|
|
247
247
|
* 打开字典编辑弹窗。
|
|
248
248
|
*/
|
|
249
249
|
async function handleOpenDialog(dictId?: number) {
|
|
250
|
-
await loadEnabledBaseLanguages();
|
|
251
250
|
resetForm();
|
|
252
251
|
dialog.editing = Boolean(dictId);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
252
|
+
await formDialogRef.value?.open({
|
|
253
|
+
load: async () => ({
|
|
254
|
+
data: dictId ? await defBaseDictService.GetBaseDict({ id: dictId }) : undefined,
|
|
255
|
+
languages: await loadEnabledBaseLanguages()
|
|
256
|
+
}),
|
|
257
|
+
commit: ({ data }) => {
|
|
258
|
+
if (!data) return;
|
|
259
|
+
Object.assign(formData, data);
|
|
260
|
+
i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
259
263
|
}
|
|
260
264
|
|
|
261
265
|
/**
|
|
262
266
|
* 关闭字典弹窗并恢复表单初始值。
|
|
263
267
|
*/
|
|
264
268
|
function handleCloseDialog() {
|
|
265
|
-
|
|
269
|
+
formDialogRef.value?.close();
|
|
266
270
|
resetForm();
|
|
267
271
|
}
|
|
268
272
|
|
|
@@ -310,22 +310,26 @@ function refreshTable() {
|
|
|
310
310
|
* 打开字典项编辑弹窗。
|
|
311
311
|
*/
|
|
312
312
|
async function handleOpenDialog(dictItemId?: number) {
|
|
313
|
-
await loadEnabledBaseLanguages();
|
|
314
313
|
resetForm();
|
|
315
314
|
dialog.editing = Boolean(dictItemId);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
315
|
+
await formDialogRef.value?.open({
|
|
316
|
+
load: async () => ({
|
|
317
|
+
data: dictItemId ? await defBaseDictItemService.GetBaseDictItem({ id: dictItemId }) : undefined,
|
|
318
|
+
languages: await loadEnabledBaseLanguages()
|
|
319
|
+
}),
|
|
320
|
+
commit: ({ data }) => {
|
|
321
|
+
if (!data) return;
|
|
322
|
+
Object.assign(formData, data);
|
|
323
|
+
i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
322
326
|
}
|
|
323
327
|
|
|
324
328
|
/**
|
|
325
329
|
* 关闭字典项弹窗并恢复默认值。
|
|
326
330
|
*/
|
|
327
331
|
function handleCloseDialog() {
|
|
328
|
-
|
|
332
|
+
formDialogRef.value?.close();
|
|
329
333
|
resetForm();
|
|
330
334
|
}
|
|
331
335
|
|
|
@@ -213,14 +213,14 @@ const headerActions = computed<HeaderActionProps[]>(() => [
|
|
|
213
213
|
|
|
214
214
|
/** 请求国际化自定义翻译分页列表。 */
|
|
215
215
|
async function requestBaseI18nCustomTable(params: PageBaseI18nCustomRequest) {
|
|
216
|
-
await loadLanguages();
|
|
216
|
+
enabledLanguages.value = await loadLanguages();
|
|
217
217
|
const data = await defBaseI18nCustomService.PageBaseI18nCustom(buildPageRequest(params));
|
|
218
218
|
return { data: { list: data.items ?? [], total: data.total } };
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/** 加载启用语言选项。 */
|
|
222
222
|
async function loadLanguages() {
|
|
223
|
-
|
|
223
|
+
return loadEnabledBaseLanguages();
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/** 返回语言显示名称。 */
|
|
@@ -231,17 +231,23 @@ function getLanguageLabel(locale: string) {
|
|
|
231
231
|
|
|
232
232
|
/** 打开国际化自定义翻译编辑弹窗。 */
|
|
233
233
|
async function handleOpenDialog(id?: number) {
|
|
234
|
-
await loadLanguages();
|
|
235
234
|
resetForm();
|
|
236
235
|
dialog.editing = Boolean(id);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
236
|
+
await formDialogRef.value?.open({
|
|
237
|
+
load: async () => ({
|
|
238
|
+
languages: await loadLanguages(),
|
|
239
|
+
data: id ? await defBaseI18nCustomService.GetBaseI18nCustom({ id }) : undefined
|
|
240
|
+
}),
|
|
241
|
+
commit: ({ languages, data }) => {
|
|
242
|
+
enabledLanguages.value = languages;
|
|
243
|
+
if (data) Object.assign(formData, data);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
240
246
|
}
|
|
241
247
|
|
|
242
248
|
/** 关闭编辑弹窗并重置表单。 */
|
|
243
249
|
function handleCloseDialog() {
|
|
244
|
-
|
|
250
|
+
formDialogRef.value?.close();
|
|
245
251
|
resetForm();
|
|
246
252
|
}
|
|
247
253
|
|
|
@@ -368,22 +368,26 @@ function refreshTable() {
|
|
|
368
368
|
* 打开定时任务弹窗。
|
|
369
369
|
*/
|
|
370
370
|
async function handleOpenDialog(jobId?: number) {
|
|
371
|
-
await loadEnabledBaseLanguages();
|
|
372
371
|
resetForm();
|
|
373
372
|
dialog.editing = Boolean(jobId);
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
373
|
+
await formDialogRef.value?.open({
|
|
374
|
+
load: async () => ({
|
|
375
|
+
data: jobId ? await defBaseJobService.GetBaseJob({ id: jobId }) : undefined,
|
|
376
|
+
languages: await loadEnabledBaseLanguages()
|
|
377
|
+
}),
|
|
378
|
+
commit: ({ data }) => {
|
|
379
|
+
if (!data) return;
|
|
380
|
+
Object.assign(formData, data);
|
|
381
|
+
i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
380
384
|
}
|
|
381
385
|
|
|
382
386
|
/**
|
|
383
387
|
* 关闭定时任务弹窗并恢复默认表单值。
|
|
384
388
|
*/
|
|
385
389
|
function handleCloseDialog() {
|
|
386
|
-
|
|
390
|
+
formDialogRef.value?.close();
|
|
387
391
|
resetForm();
|
|
388
392
|
}
|
|
389
393
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="table-box">
|
|
3
3
|
<ProTable ref="proTable" row-key="id" :columns="columns" :request-api="requestBaseJobLogTable" />
|
|
4
4
|
|
|
5
|
-
<ProDialog v-model="dialog.visible" :title="t('system.base.job.log.title.detail')" width="1200px" @close="handleCloseDialog">
|
|
5
|
+
<ProDialog ref="dialogRef" v-model="dialog.visible" :title="t('system.base.job.log.title.detail')" width="1200px" @close="handleCloseDialog">
|
|
6
6
|
<div class="detail-container">
|
|
7
7
|
<el-descriptions :title="t('system.base.job.log.section.basic')" border :column="2">
|
|
8
8
|
<el-descriptions-item :label="t('common.field.status')">
|
|
@@ -60,6 +60,7 @@ defineOptions({
|
|
|
60
60
|
|
|
61
61
|
const route = useRoute();
|
|
62
62
|
const proTable = ref<ProTableInstance>();
|
|
63
|
+
const dialogRef = ref<InstanceType<typeof ProDialog>>();
|
|
63
64
|
const initialJobID = Number(route.query.jobId ?? 0);
|
|
64
65
|
|
|
65
66
|
const dialog = reactive({
|
|
@@ -180,21 +181,25 @@ async function requestBaseJobLogTable(params: PageBaseJobLogRequest) {
|
|
|
180
181
|
/**
|
|
181
182
|
* 打开定时任务日志详情弹窗。
|
|
182
183
|
*/
|
|
183
|
-
function handleOpenDialog(logId?: number) {
|
|
184
|
+
async function handleOpenDialog(logId?: number) {
|
|
184
185
|
resetDetail();
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
try {
|
|
187
|
+
await dialogRef.value?.open({
|
|
188
|
+
load: () => (logId ? defBaseJobLogService.GetBaseJobLog({ id: logId }) : undefined),
|
|
189
|
+
commit: data => {
|
|
190
|
+
if (data) Object.assign(detail, data);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
} catch {
|
|
194
|
+
dialogRef.value?.close();
|
|
195
|
+
}
|
|
191
196
|
}
|
|
192
197
|
|
|
193
198
|
/**
|
|
194
199
|
* 关闭定时任务日志详情弹窗。
|
|
195
200
|
*/
|
|
196
201
|
function handleCloseDialog() {
|
|
197
|
-
|
|
202
|
+
dialogRef.value?.close();
|
|
198
203
|
resetDetail();
|
|
199
204
|
}
|
|
200
205
|
|