@liujitcn/kratos-admin-system 0.0.52 → 0.0.54
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/dist/package/declarations/src/api/base/v1/sse.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/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 +12 -6
- package/dist/package/src/components/tenant-project-grant/ProjectGrantDialog.vue +22 -7
- 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/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/dashboard/index.vue +201 -53
- 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
|
@@ -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
|
|
|
@@ -208,22 +208,33 @@ async function requestProjectGrantTable(params: Record<string, unknown>) {
|
|
|
208
208
|
|
|
209
209
|
/** 打开项目授权新增或编辑弹窗。 */
|
|
210
210
|
async function handleOpenDialog(row?: BaseTenantProjectGrant) {
|
|
211
|
-
resetForm();
|
|
212
|
-
dialog.editing = Boolean(row);
|
|
213
|
-
dialog.titleKey = row ? "common.action.edit_resource" : "common.action.create_resource";
|
|
214
211
|
loading.value = true;
|
|
215
212
|
try {
|
|
216
|
-
await
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
213
|
+
await formDialogRef.value?.open({
|
|
214
|
+
load: async () => {
|
|
215
|
+
await loadTenantOptions(true);
|
|
216
|
+
const nextForm = {
|
|
217
|
+
tenant_id: row?.tenant_id ?? (isDefaultTenant.value ? undefined : Number(tenantOptions.value[0]?.value) || undefined),
|
|
218
|
+
subject_type: row?.subject_type ?? DEFAULT_SUBJECT_TYPE,
|
|
219
|
+
subject_id: row?.subject_id,
|
|
220
|
+
project_id: row && !(row.project_id.length === 1 && row.project_id[0] === 0) ? [...row.project_id] : [],
|
|
221
|
+
all: Boolean(row && row.project_id.length === 1 && row.project_id[0] === 0)
|
|
222
|
+
} satisfies ProjectGrantFormState;
|
|
223
|
+
const [projects, subjects] = await Promise.all([
|
|
224
|
+
requestProjectOptions(nextForm.tenant_id),
|
|
225
|
+
requestSubjectOptions(nextForm.tenant_id, nextForm.subject_type)
|
|
226
|
+
]);
|
|
227
|
+
return { nextForm, projects, subjects };
|
|
228
|
+
},
|
|
229
|
+
commit: ({ nextForm, projects, subjects }) => {
|
|
230
|
+
resetForm();
|
|
231
|
+
dialog.editing = Boolean(row);
|
|
232
|
+
dialog.titleKey = row ? "common.action.edit_resource" : "common.action.create_resource";
|
|
233
|
+
Object.assign(formData, nextForm);
|
|
234
|
+
projectOptions.value = projects;
|
|
235
|
+
subjectOptions.value = subjects;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
227
238
|
} finally {
|
|
228
239
|
loading.value = false;
|
|
229
240
|
}
|
|
@@ -231,28 +242,34 @@ async function handleOpenDialog(row?: BaseTenantProjectGrant) {
|
|
|
231
242
|
|
|
232
243
|
/** 加载目标租户项目选项。 */
|
|
233
244
|
async function loadProjectOptions() {
|
|
234
|
-
projectOptions.value = formData.tenant_id
|
|
235
|
-
|
|
236
|
-
|
|
245
|
+
projectOptions.value = await requestProjectOptions(formData.tenant_id);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** 请求目标租户项目选项。 */
|
|
249
|
+
async function requestProjectOptions(tenantId?: number) {
|
|
250
|
+
if (!tenantId) return [];
|
|
251
|
+
return (await defBaseTenantProjectService.OptionBaseTenantProject({ tenant_id: toRequestTenantId(tenantId) })).list ?? [];
|
|
237
252
|
}
|
|
238
253
|
|
|
239
254
|
/** 根据授权类型加载岗位、角色、部门或用户主体选项。 */
|
|
240
255
|
async function loadSubjectOptions() {
|
|
241
|
-
subjectOptions.value =
|
|
242
|
-
|
|
243
|
-
|
|
256
|
+
subjectOptions.value = await requestSubjectOptions(formData.tenant_id, formData.subject_type);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** 请求指定租户和主体类型的主体选项。 */
|
|
260
|
+
async function requestSubjectOptions(tenantId: number | undefined, subjectType: BaseTenantProjectGrantSubjectType) {
|
|
261
|
+
if (!tenantId || subjectType === BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_UNSPECIFIED) return [];
|
|
262
|
+
switch (subjectType) {
|
|
244
263
|
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_POST:
|
|
245
|
-
|
|
246
|
-
return;
|
|
264
|
+
return (await defBasePostService.OptionBasePost({ tenant_id: tenantId })).list ?? [];
|
|
247
265
|
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_ROLE:
|
|
248
|
-
|
|
249
|
-
return;
|
|
266
|
+
return (await defBaseRoleService.OptionBaseRole({ tenant_id: tenantId })).list ?? [];
|
|
250
267
|
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_DEPT:
|
|
251
|
-
|
|
252
|
-
return;
|
|
268
|
+
return ((await defBaseDeptService.OptionBaseDept({ tenant_id: tenantId })).list ?? []) as unknown as ProFormOption[];
|
|
253
269
|
case BaseTenantProjectGrantSubjectType.BASE_TENANT_PROJECT_GRANT_SUBJECT_TYPE_USER:
|
|
254
|
-
|
|
270
|
+
return (await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: tenantId })).list ?? [];
|
|
255
271
|
}
|
|
272
|
+
return [];
|
|
256
273
|
}
|
|
257
274
|
|
|
258
275
|
/** 切换目标租户时重置主体和项目选择。 */
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
|
-
import { onBeforeMount, ref,
|
|
25
|
+
import { nextTick, onBeforeMount, ref, watch } from "vue";
|
|
26
26
|
import { useVModel } from "@vueuse/core";
|
|
27
27
|
import { ElTree } from "element-plus";
|
|
28
28
|
import { defBaseDeptService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_dept";
|
|
@@ -43,14 +43,9 @@ const emits = defineEmits(["nodeClick"]);
|
|
|
43
43
|
|
|
44
44
|
const baseDeptId = useVModel(props, "modelValue", emits);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
() =>
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
flush: "post" // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
|
52
|
-
}
|
|
53
|
-
);
|
|
46
|
+
watch([name, baseDeptList], () => {
|
|
47
|
+
void nextTick(() => baseDeptTreeRef.value?.filter(name.value));
|
|
48
|
+
}, { flush: "post" });
|
|
54
49
|
|
|
55
50
|
/**
|
|
56
51
|
* 部门筛选
|
|
@@ -169,7 +169,7 @@ const formData = reactive<BaseUserFormState>({
|
|
|
169
169
|
/** 密码 */
|
|
170
170
|
pwd: "",
|
|
171
171
|
/** 性别 */
|
|
172
|
-
gender:
|
|
172
|
+
gender: 1,
|
|
173
173
|
/** 头像 */
|
|
174
174
|
avatar: "",
|
|
175
175
|
/** 用户状态 */
|
|
@@ -649,23 +649,30 @@ function refreshTable() {
|
|
|
649
649
|
* 加载用户表单依赖的角色和部门选项。
|
|
650
650
|
*/
|
|
651
651
|
async function loadFormOptions() {
|
|
652
|
+
const options = await requestFormOptions();
|
|
653
|
+
baseRoleOptions.value = options.roleOptions;
|
|
654
|
+
updateUndeletableRoleIds(baseRoleOptions.value);
|
|
655
|
+
basePostOptions.value = options.postOptions;
|
|
656
|
+
basedDeptOptions.value = options.deptOptions;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** 请求用户表单依赖的角色和部门选项。 */
|
|
660
|
+
async function requestFormOptions(tenantId = formData.tenant_id) {
|
|
652
661
|
// 默认租户必须先选择目标租户,避免角色和部门选项跨租户混用。
|
|
653
|
-
if (isDefaultTenant.value && !
|
|
654
|
-
|
|
655
|
-
basePostOptions.value = [];
|
|
656
|
-
basedDeptOptions.value = [];
|
|
657
|
-
return;
|
|
662
|
+
if (isDefaultTenant.value && !tenantId) {
|
|
663
|
+
return { roleOptions: [], postOptions: [], deptOptions: [] };
|
|
658
664
|
}
|
|
659
|
-
const
|
|
665
|
+
const requestTenantId = toRequestTenantId(tenantId);
|
|
660
666
|
const [optionBaseRoleResponse, optionBaseDeptResponse, optionBasePostResponse] = await Promise.all([
|
|
661
|
-
defBaseRoleService.OptionBaseRole({ tenant_id:
|
|
662
|
-
defBaseDeptService.OptionBaseDept({ tenant_id:
|
|
663
|
-
defBasePostService.OptionBasePost({ tenant_id:
|
|
667
|
+
defBaseRoleService.OptionBaseRole({ tenant_id: requestTenantId }),
|
|
668
|
+
defBaseDeptService.OptionBaseDept({ tenant_id: requestTenantId }),
|
|
669
|
+
defBasePostService.OptionBasePost({ tenant_id: requestTenantId })
|
|
664
670
|
]);
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
671
|
+
return {
|
|
672
|
+
roleOptions: optionBaseRoleResponse.list || [],
|
|
673
|
+
postOptions: optionBasePostResponse.list || [],
|
|
674
|
+
deptOptions: optionBaseDeptResponse.list || []
|
|
675
|
+
};
|
|
669
676
|
}
|
|
670
677
|
|
|
671
678
|
/**
|
|
@@ -682,18 +689,22 @@ async function handleFormTenantChange() {
|
|
|
682
689
|
* 打开用户弹窗,并加载角色和部门下拉选项。
|
|
683
690
|
*/
|
|
684
691
|
async function handleOpenDialog(id?: number) {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
692
|
+
await formDialogRef.value?.open({
|
|
693
|
+
load: async () => {
|
|
694
|
+
await loadTenantOptions();
|
|
695
|
+
const data = id ? await defBaseUserService.GetBaseUser({ id }) : undefined;
|
|
696
|
+
const options = await requestFormOptions(data?.tenant_id);
|
|
697
|
+
return { data, options };
|
|
698
|
+
},
|
|
699
|
+
commit: ({ data, options }) => {
|
|
700
|
+
resetForm();
|
|
701
|
+
dialog.editing = Boolean(id);
|
|
702
|
+
if (data) Object.assign(formData, data);
|
|
703
|
+
baseRoleOptions.value = options.roleOptions;
|
|
704
|
+
updateUndeletableRoleIds(baseRoleOptions.value);
|
|
705
|
+
basePostOptions.value = options.postOptions;
|
|
706
|
+
basedDeptOptions.value = options.deptOptions;
|
|
707
|
+
}
|
|
697
708
|
});
|
|
698
709
|
}
|
|
699
710
|
|
|
@@ -701,7 +712,7 @@ async function handleOpenDialog(id?: number) {
|
|
|
701
712
|
* 关闭用户弹窗并恢复默认表单值。
|
|
702
713
|
*/
|
|
703
714
|
function handleCloseDialog() {
|
|
704
|
-
|
|
715
|
+
formDialogRef.value?.close();
|
|
705
716
|
resetForm();
|
|
706
717
|
}
|
|
707
718
|
|
|
@@ -724,7 +735,7 @@ function resetForm() {
|
|
|
724
735
|
formData.id_type = BaseUserIDType.BASE_USER_ID_TYPE_UNSPECIFIED;
|
|
725
736
|
formData.id_code = "";
|
|
726
737
|
formData.pwd = "";
|
|
727
|
-
formData.gender =
|
|
738
|
+
formData.gender = 1;
|
|
728
739
|
formData.avatar = "";
|
|
729
740
|
formData.status = Status.STATUS_ENABLE;
|
|
730
741
|
formData.remark = "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="table-box">
|
|
3
3
|
<ProTable ref="proTable" row-key="id" :columns="columns" :header-actions="headerActions" :request-api="requestTable" />
|
|
4
|
-
<ProDialog v-model="detailVisible" :title="detail?.title" width="720px" destroy-on-close :show-footer="false">
|
|
4
|
+
<ProDialog ref="detailDialogRef" v-model="detailVisible" :title="detail?.title" width="720px" destroy-on-close :show-footer="false">
|
|
5
5
|
<div v-if="detail" class="message-detail">
|
|
6
6
|
<div class="message-meta">
|
|
7
7
|
<span class="message-category" :style="{ color: detail.category_color || undefined }">
|
|
@@ -56,6 +56,7 @@ defineOptions({ name: "NotificationInbox", inheritAttrs: false });
|
|
|
56
56
|
|
|
57
57
|
const proTable = ref<ProTableInstance>();
|
|
58
58
|
const router = useRouter();
|
|
59
|
+
const detailDialogRef = ref<InstanceType<typeof ProDialog>>();
|
|
59
60
|
const detailVisible = ref(false);
|
|
60
61
|
const detail = ref<Notification>();
|
|
61
62
|
const categoryOptions = ref<NotificationCategory[]>([]);
|
|
@@ -177,8 +178,12 @@ async function loadCategoryOptions() {
|
|
|
177
178
|
|
|
178
179
|
/** 打开消息详情并标记已读。 */
|
|
179
180
|
async function openDetail(row: Notification) {
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
await detailDialogRef.value?.open({
|
|
182
|
+
load: () => defNotificationService.GetNotification({ id: row.id }),
|
|
183
|
+
commit: data => {
|
|
184
|
+
detail.value = data;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
182
187
|
if (!row.read_at) {
|
|
183
188
|
await defNotificationService.MarkNotificationRead({ ids: [row.id] });
|
|
184
189
|
proTable.value?.getTableList();
|
|
@@ -120,7 +120,7 @@ const submitLoading = ref(false);
|
|
|
120
120
|
const avatarSrc = ref(defaultAvatar);
|
|
121
121
|
const accountForm = reactive<Pick<UserProfileForm, "nick_name" | "gender" | "email" | "id_type" | "id_code">>({
|
|
122
122
|
nick_name: "",
|
|
123
|
-
gender:
|
|
123
|
+
gender: 1,
|
|
124
124
|
email: "",
|
|
125
125
|
id_type: BaseUserIDType.BASE_USER_ID_TYPE_UNSPECIFIED,
|
|
126
126
|
id_code: ""
|
|
@@ -95,7 +95,7 @@ const columns = computed<ColumnProps[]>(() => [
|
|
|
95
95
|
prop: "key",
|
|
96
96
|
label: t("system.cache.field.key"),
|
|
97
97
|
minWidth: 280,
|
|
98
|
-
search: { el: "input", props: { clearable: true } },
|
|
98
|
+
search: { el: "input", key: "keyword", props: { clearable: true } },
|
|
99
99
|
render: scope => h("code", { class: "cache-key-cell", title: scope.row.key }, scope.row.key)
|
|
100
100
|
},
|
|
101
101
|
{
|