@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
|
@@ -144,14 +144,17 @@ async function requestBaseLanguageTable(params: PageBaseLanguageRequest) {
|
|
|
144
144
|
async function handleOpenDialog(id?: number) {
|
|
145
145
|
resetForm();
|
|
146
146
|
dialog.editing = Boolean(id);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
await formDialogRef.value?.open({
|
|
148
|
+
load: () => (id ? defBaseLanguageService.GetBaseLanguage({ id }) : undefined),
|
|
149
|
+
commit: data => {
|
|
150
|
+
if (data) Object.assign(formData, data);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
/** 关闭语言编辑弹窗。 */
|
|
153
156
|
function handleCloseDialog() {
|
|
154
|
-
|
|
157
|
+
formDialogRef.value?.close();
|
|
155
158
|
resetForm();
|
|
156
159
|
}
|
|
157
160
|
|
|
@@ -442,23 +442,34 @@ async function requestTable(params: Record<string, unknown>) {
|
|
|
442
442
|
|
|
443
443
|
/** 打开登录策略表单。 */
|
|
444
444
|
async function openDialog(id?: number) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
445
|
+
await formDialogRef.value?.open({
|
|
446
|
+
load: async () => {
|
|
447
|
+
await loadTenantOptions();
|
|
448
|
+
const detail = id ? await defBaseLoginPolicyService.GetBaseLoginPolicy({ id }) : undefined;
|
|
449
|
+
const loadedUserOptions =
|
|
450
|
+
detail?.scope_type === BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_USER && detail.tenant_id
|
|
451
|
+
? await requestUserOptions(detail.tenant_id)
|
|
452
|
+
: [];
|
|
453
|
+
return { detail, loadedUserOptions };
|
|
454
|
+
},
|
|
455
|
+
commit: ({ detail, loadedUserOptions }) => {
|
|
456
|
+
Object.assign(formData, defaultForm());
|
|
457
|
+
dialog.titleKey = id ? "common.action.edit" : "common.action.create";
|
|
458
|
+
if (detail) Object.assign(formData, detail, { initial_password: "", rules: detail.rules ?? [] });
|
|
459
|
+
userOptions.value = loadedUserOptions;
|
|
453
460
|
}
|
|
454
|
-
}
|
|
455
|
-
dialog.visible = true;
|
|
461
|
+
});
|
|
456
462
|
}
|
|
457
463
|
|
|
458
464
|
/** 加载指定租户的用户选项。 */
|
|
459
465
|
async function loadUserOptions(tenantId: number) {
|
|
466
|
+
userOptions.value = await requestUserOptions(tenantId);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** 请求指定租户的用户选项。 */
|
|
470
|
+
async function requestUserOptions(tenantId: number) {
|
|
460
471
|
const response = await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: tenantId });
|
|
461
|
-
|
|
472
|
+
return response.list ?? [];
|
|
462
473
|
}
|
|
463
474
|
|
|
464
475
|
/** 提交登录策略表单。 */
|
|
@@ -1053,8 +1053,10 @@ function buildSubmitPayload(): BaseMenuForm {
|
|
|
1053
1053
|
/** 加载菜单树选项和 API 列表,确保弹窗打开时相关数据已可用。 */
|
|
1054
1054
|
async function loadDialogResources() {
|
|
1055
1055
|
const [menuData, apiData] = await Promise.all([defBaseMenuService.TreeBaseMenu({}), defBaseApiService.OptionBaseApi({})]);
|
|
1056
|
-
|
|
1057
|
-
|
|
1056
|
+
return {
|
|
1057
|
+
menuOptions: buildMenuOptions(menuData.base_menus ?? []),
|
|
1058
|
+
apiList: apiData.base_apis ?? []
|
|
1059
|
+
};
|
|
1058
1060
|
}
|
|
1059
1061
|
|
|
1060
1062
|
/** 根据关键字递归过滤菜单树,保留匹配节点及其父级。 */
|
|
@@ -1108,24 +1110,29 @@ function refreshTable() {
|
|
|
1108
1110
|
* parentMenu 为新增时的固定父节点,menuId 为编辑时的菜单 ID。
|
|
1109
1111
|
*/
|
|
1110
1112
|
async function handleOpenDialog(parentMenu?: BaseMenu, menuId?: number) {
|
|
1111
|
-
await
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1113
|
+
await formDialogRef.value?.open({
|
|
1114
|
+
load: async () => {
|
|
1115
|
+
await loadEnabledBaseLanguages();
|
|
1116
|
+
const [resources, data] = await Promise.all([
|
|
1117
|
+
loadDialogResources(),
|
|
1118
|
+
menuId ? defBaseMenuService.GetBaseMenu({ id: menuId }) : Promise.resolve(undefined)
|
|
1119
|
+
]);
|
|
1120
|
+
return { resources, data };
|
|
1121
|
+
},
|
|
1122
|
+
commit: ({ resources, data }) => {
|
|
1123
|
+
menuOptions.value = resources.menuOptions;
|
|
1124
|
+
apiList.value = resources.apiList;
|
|
1125
|
+
dialog.parentLocked = Boolean(parentMenu || menuId);
|
|
1126
|
+
dialog.editing = Boolean(menuId);
|
|
1127
|
+
dialog.parentType = parentMenu?.type ?? BaseMenuType.BASE_MENU_TYPE_UNSPECIFIED;
|
|
1128
|
+
resetForm(data ?? (menuId ? undefined : { parent_id: parentMenu?.id }));
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1124
1131
|
}
|
|
1125
1132
|
|
|
1126
1133
|
/** 关闭菜单弹窗并显式重置表单与校验状态。 */
|
|
1127
1134
|
function handleCloseDialog() {
|
|
1128
|
-
|
|
1135
|
+
formDialogRef.value?.close();
|
|
1129
1136
|
dialog.parentType = BaseMenuType.BASE_MENU_TYPE_UNSPECIFIED;
|
|
1130
1137
|
dialog.parentLocked = true;
|
|
1131
1138
|
resetForm();
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
</template>
|
|
48
48
|
</FormDialog>
|
|
49
49
|
<ProDialog
|
|
50
|
+
ref="contentDialogRef"
|
|
50
51
|
v-model="content.visible"
|
|
51
52
|
:title="content.data?.base_message?.title || t('system.base.message.content.title')"
|
|
52
53
|
width="760px"
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
</template>
|
|
69
70
|
</ProDialog>
|
|
70
71
|
<ProDialog
|
|
72
|
+
ref="detailDialogRef"
|
|
71
73
|
v-model="detail.visible"
|
|
72
74
|
:title="t('system.base.message.send_detail.title')"
|
|
73
75
|
width="min(1200px, calc(100vw - 32px))"
|
|
@@ -112,7 +114,9 @@
|
|
|
112
114
|
<el-table-column prop="include_children" :label="t('system.base.message.field.include_children')" width="120">
|
|
113
115
|
<template #default="scope">{{ scope.row.include_children ? t("common.value.yes") : t("common.value.no") }}</template>
|
|
114
116
|
</el-table-column>
|
|
115
|
-
<el-table-column prop="status" :label="t('common.field.status')" width="120"
|
|
117
|
+
<el-table-column prop="status" :label="t('common.field.status')" width="120">
|
|
118
|
+
<template #default="scope">{{ optionLabel(dispatchStatusOptions, scope.row.status) }}</template>
|
|
119
|
+
</el-table-column>
|
|
116
120
|
<el-table-column prop="matched_total" :label="t('system.base.message.field.matched_total')" width="110" align="right" />
|
|
117
121
|
<el-table-column prop="inserted_total" :label="t('system.base.message.field.inserted_total')" width="110" align="right" />
|
|
118
122
|
<el-table-column prop="attempt_count" :label="t('system.base.message.field.attempt_count')" width="90" align="right" />
|
|
@@ -190,6 +194,8 @@ const { BUTTONS } = useAuthButtons();
|
|
|
190
194
|
const { isDefaultTenant, tenantColumns, tenantFormField, loadTenantOptions } = useTenantScope();
|
|
191
195
|
const proTable = ref<ProTableInstance>();
|
|
192
196
|
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
197
|
+
const contentDialogRef = ref<InstanceType<typeof ProDialog>>();
|
|
198
|
+
const detailDialogRef = ref<InstanceType<typeof ProDialog>>();
|
|
193
199
|
const categoryOptions = ref<ProFormOption[]>([]);
|
|
194
200
|
const dialog = reactive({ visible: false, titleKey: "common.action.create" });
|
|
195
201
|
const content = reactive<{ visible: boolean; loading: boolean; data?: BaseMessageDetail }>({ visible: false, loading: false });
|
|
@@ -219,6 +225,13 @@ const statusOptions = computed<ProFormOption[]>(() => [
|
|
|
219
225
|
{ label: t("system.base.message.status.published"), value: MessageStatus.MESSAGE_STATUS_PUBLISHED },
|
|
220
226
|
{ label: t("system.base.message.status.revoked"), value: MessageStatus.MESSAGE_STATUS_REVOKED }
|
|
221
227
|
]);
|
|
228
|
+
const dispatchStatusOptions = computed<ProFormOption[]>(() => [
|
|
229
|
+
{ label: t("system.base.message.dispatch_status.pending"), value: MessageDispatchStatus.MESSAGE_DISPATCH_STATUS_PENDING },
|
|
230
|
+
{ label: t("system.base.message.dispatch_status.running"), value: MessageDispatchStatus.MESSAGE_DISPATCH_STATUS_RUNNING },
|
|
231
|
+
{ label: t("system.base.message.dispatch_status.succeeded"), value: MessageDispatchStatus.MESSAGE_DISPATCH_STATUS_SUCCEEDED },
|
|
232
|
+
{ label: t("system.base.message.dispatch_status.failed"), value: MessageDispatchStatus.MESSAGE_DISPATCH_STATUS_FAILED },
|
|
233
|
+
{ label: t("system.base.message.dispatch_status.cancelled"), value: MessageDispatchStatus.MESSAGE_DISPATCH_STATUS_CANCELLED }
|
|
234
|
+
]);
|
|
222
235
|
onMounted(() => {
|
|
223
236
|
void loadCategoryOptions();
|
|
224
237
|
void loadTenantOptions();
|
|
@@ -539,26 +552,42 @@ async function requestTable(params: Record<string, unknown>) {
|
|
|
539
552
|
|
|
540
553
|
/** 加载消息分类选项。 */
|
|
541
554
|
async function loadCategoryOptions() {
|
|
555
|
+
categoryOptions.value = await requestCategoryOptions();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** 请求消息分类选项。 */
|
|
559
|
+
async function requestCategoryOptions() {
|
|
542
560
|
const result = await defBaseMessageCategoryService.OptionBaseMessageCategory({});
|
|
543
|
-
|
|
561
|
+
return result.list.map(item => ({ label: item.label, value: item.value, disabled: item.disabled }));
|
|
544
562
|
}
|
|
545
563
|
|
|
546
564
|
/** 打开消息草稿表单。 */
|
|
547
565
|
async function openDialog(id?: number) {
|
|
548
|
-
await
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
566
|
+
await formDialogRef.value?.open({
|
|
567
|
+
load: async () => {
|
|
568
|
+
await loadTenantOptions();
|
|
569
|
+
const [detail, categories] = await Promise.all([
|
|
570
|
+
id ? defBaseMessageService.GetBaseMessage({ id }) : Promise.resolve(undefined),
|
|
571
|
+
requestCategoryOptions()
|
|
572
|
+
]);
|
|
573
|
+
return { detail, categories };
|
|
574
|
+
},
|
|
575
|
+
commit: ({ detail, categories }) => {
|
|
576
|
+
Object.assign(formState, defaultForm());
|
|
577
|
+
dialog.titleKey = id ? "common.action.edit" : "common.action.create";
|
|
578
|
+
categoryOptions.value = categories;
|
|
579
|
+
if (detail) {
|
|
580
|
+
Object.assign(formState, detail.form);
|
|
581
|
+
formState.audiences = detail.form?.audiences?.map(item => ({ ...item })) ?? [defaultAudience()];
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
});
|
|
558
585
|
}
|
|
559
586
|
|
|
560
587
|
/** 提交消息草稿。 */
|
|
561
588
|
async function handleSubmit() {
|
|
589
|
+
const valid = await formDialogRef.value?.validate();
|
|
590
|
+
if (!valid) return;
|
|
562
591
|
const audiences = formState.audiences.length > 0 ? formState.audiences.map(item => ({ ...item })) : [defaultAudience()];
|
|
563
592
|
const payload: BaseMessageForm = {
|
|
564
593
|
...formState,
|
|
@@ -576,21 +605,27 @@ async function handleSubmit() {
|
|
|
576
605
|
|
|
577
606
|
/** 打开发送详情并加载投递进度。 */
|
|
578
607
|
async function openDetail(id: number) {
|
|
579
|
-
|
|
580
|
-
|
|
608
|
+
await detailDialogRef.value?.open({
|
|
609
|
+
load: () => defBaseMessageService.GetBaseMessage({ id }),
|
|
610
|
+
commit: data => {
|
|
611
|
+
detail.data = data;
|
|
612
|
+
}
|
|
613
|
+
});
|
|
581
614
|
}
|
|
582
615
|
|
|
583
616
|
/** 打开消息正文并单独展示内容。 */
|
|
584
617
|
async function openContent(id: number) {
|
|
585
|
-
content.visible = true;
|
|
586
|
-
content.loading = true;
|
|
587
|
-
content.data = undefined;
|
|
588
618
|
try {
|
|
589
|
-
|
|
619
|
+
await contentDialogRef.value?.open({
|
|
620
|
+
load: () => defBaseMessageService.GetBaseMessage({ id }),
|
|
621
|
+
commit: data => {
|
|
622
|
+
content.data = data;
|
|
623
|
+
content.loading = false;
|
|
624
|
+
}
|
|
625
|
+
});
|
|
590
626
|
} catch {
|
|
591
|
-
content.visible = false;
|
|
592
|
-
} finally {
|
|
593
627
|
content.loading = false;
|
|
628
|
+
contentDialogRef.value?.close();
|
|
594
629
|
}
|
|
595
630
|
}
|
|
596
631
|
|
|
@@ -604,7 +639,16 @@ async function retryDispatch(id: number) {
|
|
|
604
639
|
|
|
605
640
|
/** 删除草稿消息。 */
|
|
606
641
|
async function handleDelete(value: BaseMessage | BaseMessage[] | number | number[]) {
|
|
607
|
-
const
|
|
642
|
+
const idList = Array.isArray(value)
|
|
643
|
+
? value.map(item => (typeof item === "object" ? item.id : item))
|
|
644
|
+
: typeof value === "object"
|
|
645
|
+
? [value.id]
|
|
646
|
+
: normalizeSelectedIds(value);
|
|
647
|
+
const ids = idList.filter(item => item !== undefined && item !== null && item !== "");
|
|
648
|
+
if (!ids.length) {
|
|
649
|
+
ElMessage.warning(t("common.message.select_delete_item"));
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
608
652
|
await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" });
|
|
609
653
|
await defBaseMessageService.DeleteBaseMessage({ id: ids.join(",") });
|
|
610
654
|
ElMessage.success(t("common.message.operation_success"));
|
|
@@ -302,14 +302,20 @@ async function requestTable(params: Record<string, unknown>) {
|
|
|
302
302
|
|
|
303
303
|
/** 打开消息分类表单。 */
|
|
304
304
|
async function openDialog(id?: number) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
305
|
+
await formDialogRef.value?.open({
|
|
306
|
+
load: () => (id ? defBaseMessageCategoryService.GetBaseMessageCategory({ id }) : undefined),
|
|
307
|
+
commit: data => {
|
|
308
|
+
Object.assign(formData, defaultForm());
|
|
309
|
+
dialog.titleKey = id ? "common.action.edit" : "common.action.create";
|
|
310
|
+
if (data) Object.assign(formData, data);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
309
313
|
}
|
|
310
314
|
|
|
311
315
|
/** 提交消息分类表单。 */
|
|
312
316
|
async function handleSubmit() {
|
|
317
|
+
const valid = await formDialogRef.value?.validate();
|
|
318
|
+
if (!valid) return;
|
|
313
319
|
const payload = formData as BaseMessageCategoryForm;
|
|
314
320
|
if (payload.id) await defBaseMessageCategoryService.UpdateBaseMessageCategory({ base_message_category: payload });
|
|
315
321
|
else await defBaseMessageCategoryService.CreateBaseMessageCategory({ base_message_category: payload });
|
|
@@ -266,12 +266,17 @@ async function loadApiOptions() {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
async function handleOpenDialog(id?: number) {
|
|
269
|
-
await loadTenantOptions();
|
|
270
|
-
await loadApiOptions();
|
|
271
269
|
resetForm();
|
|
272
270
|
dialog.titleKey = id ? "common.action.edit" : "common.action.create";
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
await formDialogRef.value?.open({
|
|
272
|
+
load: async () => ({
|
|
273
|
+
data: id ? await defOauthClientService.GetOauthClient({ id }) : undefined,
|
|
274
|
+
resources: await Promise.all([loadTenantOptions(), loadApiOptions()])
|
|
275
|
+
}),
|
|
276
|
+
commit: ({ data }) => {
|
|
277
|
+
if (data) Object.assign(formData, data);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
275
280
|
}
|
|
276
281
|
|
|
277
282
|
function resetForm() {
|
|
@@ -289,7 +294,7 @@ function resetForm() {
|
|
|
289
294
|
}
|
|
290
295
|
|
|
291
296
|
function handleCloseDialog() {
|
|
292
|
-
|
|
297
|
+
formDialogRef.value?.close();
|
|
293
298
|
resetForm();
|
|
294
299
|
}
|
|
295
300
|
|
|
@@ -369,6 +374,11 @@ function handleDelete(selected?: number | string | Array<number | string> | Oaut
|
|
|
369
374
|
}
|
|
370
375
|
|
|
371
376
|
async function handleCopyCredentials(row: OauthClient) {
|
|
377
|
+
await ElMessageBox.confirm(
|
|
378
|
+
t("system.base.oauth_client.confirm.rotate_credentials"),
|
|
379
|
+
t("common.title.warning"),
|
|
380
|
+
{ type: "warning" }
|
|
381
|
+
);
|
|
372
382
|
const credentials = await defOauthClientService.RotateOauthClientCredentials({ id: row.id });
|
|
373
383
|
const content = [
|
|
374
384
|
`${t("system.base.oauth_client.field.client_id")}:${credentials.client_id}`,
|
|
@@ -249,15 +249,21 @@ function refreshTable() {
|
|
|
249
249
|
/** 打开岗位编辑弹窗。 */
|
|
250
250
|
async function handleOpenDialog(id?: number) {
|
|
251
251
|
resetForm();
|
|
252
|
-
await loadTenantOptions();
|
|
253
252
|
dialog.titleKey = id ? "common.action.edit_resource" : "common.action.create_resource";
|
|
254
|
-
|
|
255
|
-
|
|
253
|
+
await formDialogRef.value?.open({
|
|
254
|
+
load: async () => ({
|
|
255
|
+
data: id ? await defBasePostService.GetBasePost({ id }) : undefined,
|
|
256
|
+
tenants: await loadTenantOptions()
|
|
257
|
+
}),
|
|
258
|
+
commit: ({ data }) => {
|
|
259
|
+
if (data) Object.assign(formData, data);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
256
262
|
}
|
|
257
263
|
|
|
258
264
|
/** 关闭岗位弹窗并清理表单。 */
|
|
259
265
|
function handleCloseDialog() {
|
|
260
|
-
|
|
266
|
+
formDialogRef.value?.close();
|
|
261
267
|
resetForm();
|
|
262
268
|
}
|
|
263
269
|
|
|
@@ -207,6 +207,7 @@ const ruleOptions = ref<ProFormOption[]>([]);
|
|
|
207
207
|
const ruleCatalog = ref<BaseRedactRule[]>([]);
|
|
208
208
|
const dialog = reactive({ visible: false, titleKey: "common.action.create_resource" });
|
|
209
209
|
const form = reactive<OutputFormState>(defaultForm());
|
|
210
|
+
let responseFieldsRequestRevision = 0;
|
|
210
211
|
const statusOptions = computed<ProFormOption[]>(() => [{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE }, { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }]);
|
|
211
212
|
const serviceOptions = computed<ProFormOption[]>(() => {
|
|
212
213
|
const services = new Map<string, string>();
|
|
@@ -254,21 +255,27 @@ const headerActions = computed<HeaderActionProps[]>(() => [{ label: t("common.ac
|
|
|
254
255
|
/** 请求出库脱敏策略分页列表。 */
|
|
255
256
|
async function requestTable(params: PageBaseRedactOutputPolicyRequest) { const data = await defBaseRedactOutputPolicyService.PageBaseRedactOutputPolicy(buildPageRequest(params)); return { data: { list: data.base_redact_output_policies ?? [], total: data.total } }; }
|
|
256
257
|
/** 加载 API 选项。 */
|
|
257
|
-
async function loadApis() {
|
|
258
|
+
async function loadApis() { apiCatalog.value = await requestApis(); }
|
|
259
|
+
/** 请求 API 选项。 */
|
|
260
|
+
async function requestApis() { const data = await defBaseApiService.OptionBaseApi({ include_public: true }); return data.base_apis ?? []; }
|
|
258
261
|
/** 加载脱敏规则选项。 */
|
|
259
|
-
async function loadRules() { const
|
|
262
|
+
async function loadRules() { const rules = await requestRules(); ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; }
|
|
263
|
+
/** 请求脱敏规则选项。 */
|
|
264
|
+
async function requestRules() { const data = await defBaseRedactRuleService.PageBaseRedactRule({ code: "", name: "", rule_type: "", page_num: 1, page_size: 100 }); const catalog = data.base_redact_rules ?? []; return { catalog, options: catalog.map(item => ({ label: `${item.name} (${item.code})`, value: item.id, disabled: item.status !== Status.STATUS_ENABLE })) }; }
|
|
260
265
|
/** 服务变更后清空接口和返回字段。 */
|
|
261
|
-
function handleServiceChange(serviceName?: string) { form.service_name = serviceName ?? ""; form.api_id = undefined; form.operation = ""; form.message_ref = ""; form.field_path = ""; form.field_rows = []; }
|
|
266
|
+
function handleServiceChange(serviceName?: string) { responseFieldsRequestRevision += 1; form.service_name = serviceName ?? ""; form.api_id = undefined; form.operation = ""; form.message_ref = ""; form.field_path = ""; form.field_rows = []; }
|
|
262
267
|
/** API 变更后重新加载返回字段。 */
|
|
263
268
|
async function handleApiChange(apiId?: number) { const api = interfaceOptions.value.find(item => item.id === apiId); form.service_name = api?.service_name ?? form.service_name; form.operation = api?.operation ?? ""; form.field_rows = []; if (apiId !== undefined) await loadResponseFields(apiId); }
|
|
264
269
|
/** 加载 API 返回字段并初始化表格行。 */
|
|
265
|
-
async function loadResponseFields(apiId: number) { const
|
|
270
|
+
async function loadResponseFields(apiId: number) { const revision = ++responseFieldsRequestRevision; const rows = await requestResponseFields(apiId); if (revision === responseFieldsRequestRevision) form.field_rows = rows; }
|
|
271
|
+
/** 请求 API 返回字段并转换为表格行。 */
|
|
272
|
+
async function requestResponseFields(apiId: number) { const doc = await defBaseRedactOutputPolicyService.GetBaseRedactOutputFieldDoc({ api_id: apiId }); const rows: OutputFieldRow[] = []; for (const response of doc.responses ?? []) { if (response.body) collectFields(response.body, "", "", rows, true); } return [...new Map(rows.map(item => [String(item.value), item])).values()]; }
|
|
266
273
|
/** 递归收集可配置的返回叶子字段。 */
|
|
267
274
|
function collectFields(schema: BaseApiDocSchema, parentRef: string, parentPath: string, result: OutputFieldRow[], root: boolean) { const schemaRef = normalizeRef(schema.ref); const messageRef = schemaRef || parentRef; const startsNewMessage = Boolean(schemaRef && parentRef && schemaRef !== parentRef); const rootContainer = root || (!parentRef && (schema.name === "body" || schema.name === "body[]")); const path = rootContainer || startsNewMessage ? "" : schema.name ? (parentPath ? `${parentPath}.${schema.name}` : schema.name) : parentPath; if (!schema.children?.length) { const fieldName = path.split(".").pop()?.toLowerCase() ?? ""; if (path && !OUTPUT_SYSTEM_FIELD_NAMES.has(fieldName)) result.push(createFieldRow({ label: `${messageRef}.${path}${schema.description ? ` (${schema.description})` : ""}`, value: `${messageRef}\u0000${path}`, message_ref: messageRef, field_path: path, description: schema.description })); return; } for (const child of schema.children) collectFields(child, messageRef, path, result, false); }
|
|
268
275
|
/** 规范化 OpenAPI 引用名称。 */
|
|
269
276
|
function normalizeRef(ref?: string) { const parts = (ref ?? "").split("/"); return parts[parts.length - 1] || ""; }
|
|
270
277
|
/** 打开新增或编辑弹窗。 */
|
|
271
|
-
async function openDialog(id?: number) {
|
|
278
|
+
async function openDialog(id?: number) { await dialogRef.value?.open({ load: async () => { const [apis, rules, data] = await Promise.all([requestApis(), requestRules(), id !== undefined ? defBaseRedactOutputPolicyService.GetBaseRedactOutputPolicy({ id }) : Promise.resolve(undefined)]); const api = data ? apis.find(item => item.operation === data.operation) : undefined; const rows = api ? await requestResponseFields(api.id) : []; return { apis, rules, data, rows }; }, commit: ({ apis, rules, data, rows }) => { resetForm(); apiCatalog.value = apis; ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; if (data) { Object.assign(form, data); const api = apis.find(item => item.operation === data.operation); if (api) { form.service_name = api.service_name; form.api_id = api.id; form.field_rows = rows; const row = form.field_rows.find(item => item.message_ref === data.message_ref && item.field_path === data.field_path); if (row) applyPolicy(row, data); } } dialog.titleKey = id !== undefined ? "common.action.edit_resource" : "common.action.create_resource"; } }); }
|
|
272
279
|
/** 重置弹窗表单。 */
|
|
273
280
|
function resetForm() { dialog.visible = false; dialogRef.value?.resetFields(); Object.assign(form, defaultForm()); }
|
|
274
281
|
/** 保存表格中已配置的全部字段。 */
|
|
@@ -212,13 +212,14 @@ async function requestTable(params: PageBaseRedactRuleRequest) {
|
|
|
212
212
|
|
|
213
213
|
/** 打开新增或编辑弹窗。 */
|
|
214
214
|
async function openDialog(id?: number) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
215
|
+
await dialogRef.value?.open({
|
|
216
|
+
load: () => (id !== undefined ? defBaseRedactRuleService.GetBaseRedactRule({ id }) : undefined),
|
|
217
|
+
commit: data => {
|
|
218
|
+
resetForm();
|
|
219
|
+
if (data) Object.assign(form, data, { params: parseRuleParams(data.rule_type, data.rule) });
|
|
220
|
+
dialog.titleKey = id !== undefined ? "common.action.edit_resource" : "common.action.create_resource";
|
|
221
|
+
}
|
|
222
|
+
});
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
/** 重置规则编辑表单。 */
|
|
@@ -188,6 +188,7 @@ const ruleOptions = ref<ProFormOption[]>([]);
|
|
|
188
188
|
const ruleCatalog = ref<BaseRedactRule[]>([]);
|
|
189
189
|
const dialog = reactive({ visible: false, titleKey: "common.action.create_resource" });
|
|
190
190
|
const form = reactive<StorageFormState>(defaultForm());
|
|
191
|
+
let columnsRequestRevision = 0;
|
|
191
192
|
const statusOptions = computed<ProFormOption[]>(() => [{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE }, { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }]);
|
|
192
193
|
const configuredFieldCount = computed(() => form.column_rows.filter(row => Boolean(row.rule_id)).length);
|
|
193
194
|
const fields = computed<ProFormField[]>(() => [
|
|
@@ -216,25 +217,48 @@ const headerActions = computed<HeaderActionProps[]>(() => [{ label: t("common.ac
|
|
|
216
217
|
/** 请求入库脱敏策略分页列表。 */
|
|
217
218
|
async function requestTable(params: PageBaseRedactStoragePolicyRequest) { const data = await defBaseRedactStoragePolicyService.PageBaseRedactStoragePolicy(buildPageRequest(params)); return { data: { list: data.base_redact_storage_policies ?? [], total: data.total } }; }
|
|
218
219
|
/** 加载脱敏规则选项。 */
|
|
219
|
-
async function loadRules() { const
|
|
220
|
+
async function loadRules() { const rules = await requestRules(); ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; }
|
|
221
|
+
/** 请求脱敏规则选项。 */
|
|
222
|
+
async function requestRules() { const data = await defBaseRedactRuleService.PageBaseRedactRule({ code: "", name: "", rule_type: "", page_num: 1, page_size: 100 }); const catalog = data.base_redact_rules ?? []; return { catalog, options: catalog.map(item => ({ label: `${item.name} (${item.code})`, value: item.id, disabled: item.status !== Status.STATUS_ENABLE })) }; }
|
|
220
223
|
/** 数据源变更后清空下级选择并加载数据表。 */
|
|
221
|
-
async function handleSourceChange(sourceName: string) { form.source_name = sourceName; form.table_name = ""; form.column_name = ""; form.column_rows = []; tableOptions.value = []; await loadTables(); }
|
|
224
|
+
async function handleSourceChange(sourceName: string) { columnsRequestRevision += 1; form.source_name = sourceName; form.table_name = ""; form.column_name = ""; form.column_rows = []; tableOptions.value = []; await loadTables(); }
|
|
222
225
|
/** 数据表变更后加载字段表格。 */
|
|
223
|
-
async function handleTableChange(tableName: string) { form.table_name = tableName; form.column_name = ""; form.column_rows = []; await loadColumns(); }
|
|
226
|
+
async function handleTableChange(tableName: string) { columnsRequestRevision += 1; form.table_name = tableName; form.column_name = ""; form.column_rows = []; await loadColumns(); }
|
|
224
227
|
/** 加载数据源选项。 */
|
|
225
|
-
async function loadSourceOptions() {
|
|
228
|
+
async function loadSourceOptions() { sourceOptions.value = await requestSourceOptions(); }
|
|
229
|
+
/** 请求数据源选项。 */
|
|
230
|
+
async function requestSourceOptions() { const data = await defBaseTableSourceService.OptionBaseTableSource({}); return (data.value ?? []).map(value => ({ label: value, value })); }
|
|
226
231
|
/** 加载指定数据源的数据表选项。 */
|
|
227
|
-
async function loadTables(sourceName = form.source_name) {
|
|
232
|
+
async function loadTables(sourceName = form.source_name) { tableOptions.value = await requestTables(sourceName); }
|
|
233
|
+
/** 请求指定数据源的数据表选项。 */
|
|
234
|
+
async function requestTables(sourceName: string) { if (!sourceName) return []; const data = await defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: sourceName }); return (data.tables ?? []).map((item: CodeGenDatabaseTable) => ({ label: item.comment ? `${item.comment}(${item.name})` : item.name, value: item.name })); }
|
|
228
235
|
/** 预加载数据表中文注释,供列表显示。 */
|
|
229
236
|
async function loadTableComments() { await loadSourceOptions(); const comments = new Map<string, string>(); await Promise.all(sourceOptions.value.map(async option => { const sourceName = String(option.value); const data = await defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: sourceName }); for (const item of data.tables ?? []) { if (item.comment) comments.set(`${sourceName}\x00${item.name}`, item.comment); } })); tableCommentMap.value = comments; }
|
|
230
237
|
/** 加载并过滤数据库字段。 */
|
|
231
|
-
async function loadColumns() {
|
|
238
|
+
async function loadColumns() { const revision = ++columnsRequestRevision; const rows = await requestColumns(form.source_name, form.table_name); if (revision === columnsRequestRevision) form.column_rows = rows; }
|
|
239
|
+
/** 请求并转换数据库字段。 */
|
|
240
|
+
async function requestColumns(sourceName: string, tableName: string) { if (!sourceName || !tableName) return []; const data = await defBaseRedactStoragePolicyService.ListBaseRedactStorageColumn({ source_name: sourceName, table_name: tableName }); return (data.columns ?? []).filter(item => !STORAGE_AUDIT_COLUMN_NAMES.has(item.name.toLowerCase())).map(item => createColumnRow({ label: item.name, value: item.name, name: item.name, comment: item.comment, db_type: item.db_type })); }
|
|
232
241
|
/** 打开新增或编辑弹窗。 */
|
|
233
|
-
async function openDialog(id?: number) {
|
|
242
|
+
async function openDialog(id?: number) { await dialogRef.value?.open({ load: async () => { const [sources, rules, data] = await Promise.all([requestSourceOptions(), requestRules(), id !== undefined ? defBaseRedactStoragePolicyService.GetBaseRedactStoragePolicy({ id }) : Promise.resolve(undefined)]); const sourceName = data?.source_name ?? ""; const tables = await requestTables(sourceName); const columns = data ? await requestColumns(sourceName, data.table_name) : []; return { sources, rules, data, tables, columns }; }, commit: ({ sources, rules, data, tables, columns }) => { resetForm(); sourceOptions.value = sources; tableOptions.value = tables; ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; if (data) { Object.assign(form, data); form.column_rows = columns; const row = form.column_rows.find(item => item.name === data.column_name); if (row) applyPolicy(row, data); } dialog.titleKey = id !== undefined ? "common.action.edit_resource" : "common.action.create_resource"; } }); }
|
|
234
243
|
/** 重置弹窗表单。 */
|
|
235
244
|
function resetForm() { dialog.visible = false; dialogRef.value?.resetFields(); Object.assign(form, defaultForm()); sourceOptions.value = []; tableOptions.value = []; }
|
|
236
245
|
/** 保存表格中已配置的全部字段。 */
|
|
237
|
-
async function submit() {
|
|
246
|
+
async function submit() {
|
|
247
|
+
const valid = await dialogRef.value?.validate();
|
|
248
|
+
const rows = form.column_rows.filter(row => Boolean(row.rule_id));
|
|
249
|
+
const removedIds = form.column_rows.filter(row => row.id > 0 && !row.rule_id).map(row => row.id);
|
|
250
|
+
if (!valid || (!rows.length && !removedIds.length)) return;
|
|
251
|
+
const createPolicies = rows.filter(row => !row.id).map(buildPayload);
|
|
252
|
+
const updatePolicies = rows.filter(row => Boolean(row.id)).map(buildPayload);
|
|
253
|
+
const requests: Promise<unknown>[] = [];
|
|
254
|
+
if (createPolicies.length) requests.push(defBaseRedactStoragePolicyService.CreateBaseRedactStoragePolicy({ base_redact_storage_policy: createPolicies }));
|
|
255
|
+
if (updatePolicies.length) requests.push(defBaseRedactStoragePolicyService.UpdateBaseRedactStoragePolicy({ base_redact_storage_policy: updatePolicies }));
|
|
256
|
+
if (removedIds.length) requests.push(defBaseRedactStoragePolicyService.DeleteBaseRedactStoragePolicy({ id: removedIds.join(",") }));
|
|
257
|
+
await Promise.all(requests);
|
|
258
|
+
ElMessage.success(t("system.base.redact_storage_policy.message.batch_save_success", { count: rows.length }));
|
|
259
|
+
resetForm();
|
|
260
|
+
table.value?.getTableList();
|
|
261
|
+
}
|
|
238
262
|
/** 将表格行转换为入库策略请求。 */
|
|
239
263
|
function buildPayload(row: StorageColumnRow): BaseRedactStoragePolicyForm { syncRowParams(row); return { id: row.id, source_name: form.source_name, table_name: form.table_name, column_name: row.name, rule_id: row.rule_id ?? 0, rule_params: row.rule_params, status: form.status, remark: form.remark }; }
|
|
240
264
|
/** 将已保存的策略回填到对应字段行。 */
|
|
@@ -392,10 +392,13 @@ function refreshTable() {
|
|
|
392
392
|
* 按目标角色加载可分配的菜单权限树数据。
|
|
393
393
|
*/
|
|
394
394
|
async function loadMenuPermOptions(roleId?: number) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
395
|
+
menuPermOptions.value = await requestMenuPermOptions(roleId);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** 请求指定角色可分配的菜单权限树。 */
|
|
399
|
+
async function requestMenuPermOptions(roleId?: number) {
|
|
400
|
+
const optionBaseMenuRes = await defBaseMenuService.OptionBaseMenu({ role_id: roleId });
|
|
401
|
+
return optionBaseMenuRes.list ?? [];
|
|
399
402
|
}
|
|
400
403
|
|
|
401
404
|
/**
|
|
@@ -410,25 +413,29 @@ async function handleFormTenantChange() {
|
|
|
410
413
|
* 打开角色弹窗。
|
|
411
414
|
*/
|
|
412
415
|
async function handleOpenDialog(roleId?: number) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
416
|
+
await formDialogRef.value?.open({
|
|
417
|
+
load: async () => {
|
|
418
|
+
await loadTenantOptions();
|
|
419
|
+
const [data, menuOptions] = await Promise.all([
|
|
420
|
+
roleId ? defBaseRoleService.GetBaseRole({ id: roleId }) : Promise.resolve(undefined),
|
|
421
|
+
requestMenuPermOptions(roleId)
|
|
422
|
+
]);
|
|
423
|
+
return { data, menuOptions };
|
|
424
|
+
},
|
|
425
|
+
commit: ({ data, menuOptions }) => {
|
|
426
|
+
resetForm();
|
|
427
|
+
dialog.editing = Boolean(roleId);
|
|
428
|
+
menuPermOptions.value = menuOptions;
|
|
429
|
+
if (data) Object.assign(formData, data);
|
|
430
|
+
}
|
|
431
|
+
});
|
|
425
432
|
}
|
|
426
433
|
|
|
427
434
|
/**
|
|
428
435
|
* 关闭角色弹窗并恢复默认表单值。
|
|
429
436
|
*/
|
|
430
437
|
function handleCloseDialog() {
|
|
431
|
-
|
|
438
|
+
formDialogRef.value?.close();
|
|
432
439
|
resetForm();
|
|
433
440
|
}
|
|
434
441
|
|
|
@@ -329,18 +329,19 @@ function isProtectedManagementTenant(row?: BaseTenant) {
|
|
|
329
329
|
async function handleOpenDialog(tenantId?: number) {
|
|
330
330
|
resetForm();
|
|
331
331
|
dialog.titleKey = tenantId ? "common.action.edit_resource" : "common.action.create_resource";
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
332
|
+
await formDialogRef.value?.open({
|
|
333
|
+
load: () => (tenantId ? defBaseTenantService.GetBaseTenant({ id: tenantId }) : undefined),
|
|
334
|
+
commit: data => {
|
|
335
|
+
if (data) Object.assign(formData, data);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
337
338
|
}
|
|
338
339
|
|
|
339
340
|
/**
|
|
340
341
|
* 关闭租户弹窗并恢复默认表单值。
|
|
341
342
|
*/
|
|
342
343
|
function handleCloseDialog() {
|
|
343
|
-
|
|
344
|
+
formDialogRef.value?.close();
|
|
344
345
|
resetForm();
|
|
345
346
|
}
|
|
346
347
|
|