@liujitcn/kratos-admin-system 0.0.55 → 0.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/package/declarations/src/api/system/admin/v1/base_redact_storage_policy.d.ts +3 -1
  2. package/dist/package/declarations/src/locales/generated.d.ts +0 -4
  3. package/dist/package/declarations/src/rpc/base/v1/ai_session.d.ts +4 -0
  4. package/dist/package/declarations/src/rpc/base/v1/config.d.ts +11 -1
  5. package/dist/package/declarations/src/rpc/base/v1/notification.d.ts +2 -0
  6. package/dist/package/declarations/src/rpc/system/admin/v1/base_api.d.ts +4 -0
  7. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n_custom.d.ts +6 -0
  8. package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +2 -0
  9. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +6 -0
  10. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_storage_policy.d.ts +27 -2
  11. package/dist/package/declarations/src/rpc/system/admin/v1/base_third_account.d.ts +2 -0
  12. package/dist/package/declarations/src/rpc/system/admin/v1/oauth_client.d.ts +2 -0
  13. package/dist/package/src/api/system/admin/v1/base_redact_storage_policy.ts +7 -0
  14. package/dist/package/src/locales/en-US.json +0 -1
  15. package/dist/package/src/locales/ja-JP.json +0 -1
  16. package/dist/package/src/locales/zh-CN.json +0 -1
  17. package/dist/package/src/locales/zh-TW.json +0 -1
  18. package/dist/package/src/rpc/base/v1/ai_session.ts +4 -0
  19. package/dist/package/src/rpc/base/v1/config.ts +13 -1
  20. package/dist/package/src/rpc/base/v1/notification.ts +2 -0
  21. package/dist/package/src/rpc/system/admin/v1/base_api.ts +7 -1
  22. package/dist/package/src/rpc/system/admin/v1/base_i18n_custom.ts +8 -0
  23. package/dist/package/src/rpc/system/admin/v1/base_message.ts +2 -0
  24. package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +8 -0
  25. package/dist/package/src/rpc/system/admin/v1/base_redact_storage_policy.ts +34 -4
  26. package/dist/package/src/rpc/system/admin/v1/base_third_account.ts +2 -0
  27. package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +2 -0
  28. package/dist/package/src/views/ai/chat/message.ts +3 -0
  29. package/dist/package/src/views/base/api-log/index.vue +3 -0
  30. package/dist/package/src/views/base/area/index.vue +6 -2
  31. package/dist/package/src/views/base/data-access-log/index.vue +4 -1
  32. package/dist/package/src/views/base/file/index.vue +1 -1
  33. package/dist/package/src/views/base/i18n-custom/index.vue +32 -4
  34. package/dist/package/src/views/base/job/log.vue +0 -1
  35. package/dist/package/src/views/base/login-log/index.vue +2 -9
  36. package/dist/package/src/views/base/menu/index.vue +0 -1
  37. package/dist/package/src/views/base/operation-log/index.vue +5 -2
  38. package/dist/package/src/views/base/permission-log/index.vue +3 -0
  39. package/dist/package/src/views/base/policy-evaluation-log/index.vue +3 -0
  40. package/dist/package/src/views/base/redact-output-policy/index.vue +30 -9
  41. package/dist/package/src/views/base/redact-storage-policy/index.vue +19 -11
  42. package/dist/package/src/views/base/tenant/index.vue +5 -0
  43. package/dist/package/src/views/profile/components/login-log.vue +0 -1
  44. package/dist/package/src/views/profile/components/session.vue +18 -12
  45. package/package.json +2 -2
@@ -8,6 +8,7 @@ import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTabl
8
8
  import { t } from "@liujitcn/kratos-admin-core";
9
9
  import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
10
10
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
11
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
11
12
  import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/log/LogTable.vue";
12
13
  import {
13
14
  createLogEnumOptions,
@@ -26,6 +27,7 @@ import type { BaseDataAccessLog, PageBaseDataAccessLogRequest } from "@liujitcn/
26
27
  defineOptions({ name: "BaseDataAccessLog", inheritAttrs: false });
27
28
 
28
29
  const page = ref<InstanceType<typeof LogTable>>();
30
+ const { tenantColumns } = useTenantScope();
29
31
  const resultOptions = computed(() => createLogEnumOptions([
30
32
  [BaseLogResult.BASE_LOG_RESULT_UNSPECIFIED, t("system.base.log.result.unspecified")],
31
33
  [BaseLogResult.BASE_LOG_RESULT_SUCCESS, t("system.base.log.result.success")],
@@ -42,6 +44,7 @@ const accessTypeOptions = computed(() => createLogEnumOptions([
42
44
  [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_IMPORT, t("system.base.log.access_type.import")]
43
45
  ]));
44
46
  const columns = computed<ColumnProps[]>(() => [
47
+ ...tenantColumns({ label: t("common.field.tenant") }),
45
48
  { prop: "resource_type", label: t("system.base.log.field.resource_type"), minWidth: 150, search: { el: "input" } },
46
49
  { prop: "table_name", label: t("system.base.log.field.table_name"), minWidth: 150 },
47
50
  { prop: "access_type", label: t("system.base.log.field.access_type"), minWidth: 120, search: { el: "select", enum: accessTypeOptions.value }, render: scope => logEnumLabel(accessTypeOptions.value, (scope.row as BaseDataAccessLog).access_type) },
@@ -64,7 +67,7 @@ const config = computed<LogTableConfig>(() => ({
64
67
  { key: "user_id", label: t("system.base.log.field.user_id") },
65
68
  { key: "user_name", label: t("system.base.log.field.user_name") },
66
69
  { key: "resource_type", label: t("system.base.log.field.resource_type") },
67
- { key: "resource_id", label: t("system.base.log.field.resource_id"), align: "left" },
70
+ { key: "resource_id", label: t("system.base.log.field.resource_id") },
68
71
  { key: "access_type", label: t("system.base.log.field.access_type"), enum: accessTypeOptions.value },
69
72
  { key: "data_source", label: t("system.base.log.field.data_source") },
70
73
  { key: "table_name", label: t("system.base.log.field.table_name") },
@@ -113,12 +113,12 @@ onMounted(() => {
113
113
  });
114
114
 
115
115
  const columns = computed<ColumnProps[]>(() => [
116
+ ...tenantColumns({ label: t("common.field.tenant"), minWidth: 100 }),
116
117
  { prop: "file_name", label: t("system.base.file.field.name"), minWidth: 220, search: { el: "input" } },
117
118
  { prop: "extension", label: t("system.base.file.field.extension"), width: 100, search: { el: "input" } },
118
119
  { prop: "mime_type", label: t("system.base.file.field.mime"), minWidth: 180 },
119
120
  { prop: "size", label: t("system.base.file.field.size"), width: 120, align: "right", render: scope => formatFileSize((scope.row as BaseFile).size) },
120
121
  { prop: "content_hash", label: t("system.base.file.field.hash"), minWidth: 220 },
121
- ...tenantColumns({ label: t("system.base.file.field.tenant"), minWidth: 100 }),
122
122
  { prop: "created_at", align: "center", label: t("common.field.created_at"), minWidth: 180 },
123
123
  {
124
124
  prop: "operation",
@@ -3,6 +3,7 @@
3
3
  <div class="table-box">
4
4
  <ProTable
5
5
  ref="proTable"
6
+ :key="isDefaultTenant ? 'default-tenant' : 'normal-tenant'"
6
7
  row-key="id"
7
8
  :columns="columns"
8
9
  :header-actions="headerActions"
@@ -24,7 +25,7 @@
24
25
  </template>
25
26
 
26
27
  <script setup lang="ts">
27
- import { computed, reactive, ref } from "vue";
28
+ import { computed, onMounted, reactive, ref } from "vue";
28
29
  import { ElMessage, ElMessageBox } from "element-plus";
29
30
  import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
30
31
  import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
@@ -33,6 +34,7 @@ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog
33
34
  import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
34
35
  import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
35
36
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
37
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
36
38
  import {
37
39
  getCurrentLocale,
38
40
  getDefaultLocaleText,
@@ -52,13 +54,20 @@ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
52
54
 
53
55
  defineOptions({ name: "BaseI18nCustom", inheritAttrs: false });
54
56
 
57
+ /** 自定义翻译表单状态,平台管理员新增时选择目标租户。 */
58
+ type BaseI18nCustomFormState = Omit<BaseI18nCustomForm, "tenant_id"> & {
59
+ /** 租户ID。 */
60
+ tenant_id?: number;
61
+ };
62
+
55
63
  const { BUTTONS } = useAuthButtons();
56
64
  const proTable = ref<ProTableInstance>();
57
65
  const formDialogRef = ref<InstanceType<typeof FormDialog>>();
58
66
  const enabledLanguages = ref<Array<{ language_code: string; native_name?: string; language_name?: string }>>([]);
59
67
  const dialog = reactive({ editing: false, visible: false });
60
- const formData = reactive<BaseI18nCustomForm>({
68
+ const formData = reactive<BaseI18nCustomFormState>({
61
69
  id: 0,
70
+ tenant_id: undefined,
62
71
  site: BaseConfigSite.BASE_CONFIG_SITE_ADMIN,
63
72
  key: "",
64
73
  locale: getCurrentLocale(),
@@ -86,13 +95,26 @@ const statusOptions = computed<ProFormOption[]>(() => [
86
95
  ]);
87
96
 
88
97
  const rules = computed(() => ({
98
+ tenant_id: [
99
+ {
100
+ required: true,
101
+ message: t("common.validation.required_select", { field: t("common.field.tenant") }),
102
+ trigger: "change"
103
+ }
104
+ ],
89
105
  site: [{ required: true, message: t("system.base.i18n_custom.placeholder.site"), trigger: "change" }],
90
106
  key: [{ required: true, message: t("system.base.i18n_custom.placeholder.key"), trigger: "blur" }],
91
107
  locale: [{ required: true, message: t("system.base.i18n_custom.placeholder.locale"), trigger: "change" }],
92
108
  value: [{ required: true, message: t("system.base.i18n_custom.placeholder.value"), trigger: "blur" }]
93
109
  }));
94
110
 
111
+ const { isDefaultTenant, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
112
+ onMounted(() => {
113
+ if (isDefaultTenant.value) void loadTenantOptions();
114
+ });
115
+
95
116
  const formFields = computed<ProFormField[]>(() => [
117
+ tenantFormField({ label: t("common.field.tenant"), disabledOnEdit: true }),
96
118
  {
97
119
  prop: "site",
98
120
  label: t("system.base.i18n_custom.field.site"),
@@ -130,6 +152,7 @@ const formFields = computed<ProFormField[]>(() => [
130
152
 
131
153
  const columns = computed<ColumnProps[]>(() => [
132
154
  { type: "selection", width: 55 },
155
+ ...tenantColumns({ label: t("common.field.tenant"), order: 1 }),
133
156
  { prop: "key", label: t("system.base.i18n_custom.field.key"), minWidth: 250, search: { el: "input" } },
134
157
  {
135
158
  prop: "site",
@@ -214,7 +237,10 @@ const headerActions = computed<HeaderActionProps[]>(() => [
214
237
  /** 请求国际化自定义翻译分页列表。 */
215
238
  async function requestBaseI18nCustomTable(params: PageBaseI18nCustomRequest) {
216
239
  enabledLanguages.value = await loadLanguages();
217
- const data = await defBaseI18nCustomService.PageBaseI18nCustom(buildPageRequest(params));
240
+ const data = await defBaseI18nCustomService.PageBaseI18nCustom({
241
+ ...buildPageRequest(params),
242
+ tenant_id: toRequestTenantId(params.tenant_id)
243
+ });
218
244
  return { data: { list: data.items ?? [], total: data.total } };
219
245
  }
220
246
 
@@ -236,7 +262,8 @@ async function handleOpenDialog(id?: number) {
236
262
  await formDialogRef.value?.open({
237
263
  load: async () => ({
238
264
  languages: await loadLanguages(),
239
- data: id ? await defBaseI18nCustomService.GetBaseI18nCustom({ id }) : undefined
265
+ data: id ? await defBaseI18nCustomService.GetBaseI18nCustom({ id }) : undefined,
266
+ tenants: await loadTenantOptions()
240
267
  }),
241
268
  commit: ({ languages, data }) => {
242
269
  enabledLanguages.value = languages;
@@ -257,6 +284,7 @@ function resetForm() {
257
284
  formDialogRef.value?.clearValidate();
258
285
  Object.assign(formData, {
259
286
  id: 0,
287
+ tenant_id: undefined,
260
288
  site: BaseConfigSite.BASE_CONFIG_SITE_ADMIN,
261
289
  key: "",
262
290
  locale: getCurrentLocale(),
@@ -97,7 +97,6 @@ const columns = computed<ColumnProps[]>(() => [
97
97
  prop: "job_id",
98
98
  label: t("system.base.job.field.name"),
99
99
  minWidth: 180,
100
- align: "left",
101
100
  search: {
102
101
  el: "select",
103
102
  defaultValue: initialJobID > 0 ? initialJobID : undefined,
@@ -5,7 +5,7 @@
5
5
  <script setup lang="ts">
6
6
  import { computed, ref } from "vue";
7
7
  import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
8
- import { requestTenantCodeOptions, useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
8
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
9
9
  import { t } from "@liujitcn/kratos-admin-core";
10
10
  import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
11
11
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
@@ -40,15 +40,8 @@ const loginTypeOptions = computed(() =>
40
40
  );
41
41
 
42
42
  const columns = computed<ColumnProps[]>(() => [
43
+ ...tenantColumns({ label: t("common.field.tenant"), minWidth: 140 }),
43
44
  { prop: "user_name", label: t("system.base.log.field.user_name"), minWidth: 130 },
44
- ...tenantColumns({
45
- prop: "tenant_code",
46
- label: t("system.base.log.field.tenant_code"),
47
- minWidth: 120,
48
- searchEl: "select",
49
- enum: requestTenantCodeOptions,
50
- render: scope => String((scope.row as BaseLoginLog).tenant_code ?? "")
51
- }),
52
45
  {
53
46
  prop: "login_type",
54
47
  label: t("system.base.log.field.login_type"),
@@ -313,7 +313,6 @@ const columns = computed<ColumnProps[]>(() => [
313
313
  prop: "meta.title",
314
314
  label: t("system.base.menu.field.name"),
315
315
  minWidth: 220,
316
- align: "right",
317
316
  search: { el: "input", key: "title" },
318
317
  showOverflowTooltip: false,
319
318
  render: scope => renderMenuTitleCell(scope as unknown as RenderScope<BaseMenu>)
@@ -8,6 +8,7 @@ import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTabl
8
8
  import { t } from "@liujitcn/kratos-admin-core";
9
9
  import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
10
10
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
11
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
11
12
  import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/log/LogTable.vue";
12
13
  import { logDateSearch, logDetailColumn, logEnumLabel, createLogEnumOptions, requestLogTrace } from "@liujitcn/kratos-admin-system/components/log/log";
13
14
  import { defBaseOperationLogService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_operation_log";
@@ -18,6 +19,7 @@ import type { BaseOperationLog, PageBaseOperationLogRequest } from "@liujitcn/kr
18
19
  defineOptions({ name: "BaseOperationLog", inheritAttrs: false });
19
20
 
20
21
  const page = ref<InstanceType<typeof LogTable>>();
22
+ const { tenantColumns } = useTenantScope();
21
23
  const resultOptions = computed(() => createLogEnumOptions([
22
24
  [BaseLogResult.BASE_LOG_RESULT_UNSPECIFIED, t("system.base.log.result.unspecified")],
23
25
  [BaseLogResult.BASE_LOG_RESULT_SUCCESS, t("system.base.log.result.success")],
@@ -36,8 +38,9 @@ const actionOptions = computed(() => createLogEnumOptions([
36
38
  [BaseOperationAction.BASE_OPERATION_ACTION_OTHER, t("system.base.log.operation_action.other")]
37
39
  ]));
38
40
  const columns = computed<ColumnProps[]>(() => [
41
+ ...tenantColumns({ label: t("common.field.tenant") }),
39
42
  { prop: "resource_type", label: t("system.base.log.field.resource_type"), minWidth: 150, search: { el: "input" } },
40
- { prop: "resource_id", label: t("system.base.log.field.resource_id"), minWidth: 120, align: "left" },
43
+ { prop: "resource_id", label: t("system.base.log.field.resource_id"), minWidth: 120 },
41
44
  { prop: "resource_name", label: t("system.base.log.field.resource_name"), minWidth: 160 },
42
45
  { prop: "action", label: t("system.base.log.field.action"), minWidth: 110, search: { el: "select", enum: actionOptions.value }, render: scope => logEnumLabel(actionOptions.value, (scope.row as BaseOperationLog).action) },
43
46
  { prop: "result", label: t("system.base.log.field.result"), minWidth: 110, search: { el: "select", enum: resultOptions.value }, render: scope => logEnumLabel(resultOptions.value, (scope.row as BaseOperationLog).result) },
@@ -58,7 +61,7 @@ const config = computed<LogTableConfig>(() => ({
58
61
  { key: "user_id", label: t("system.base.log.field.user_id") },
59
62
  { key: "user_name", label: t("system.base.log.field.user_name") },
60
63
  { key: "resource_type", label: t("system.base.log.field.resource_type") },
61
- { key: "resource_id", label: t("system.base.log.field.resource_id"), align: "left" },
64
+ { key: "resource_id", label: t("system.base.log.field.resource_id") },
62
65
  { key: "resource_name", label: t("system.base.log.field.resource_name") },
63
66
  { key: "action", label: t("system.base.log.field.action"), enum: actionOptions.value },
64
67
  { key: "result", label: t("system.base.log.field.result"), enum: resultOptions.value },
@@ -8,6 +8,7 @@ import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTabl
8
8
  import { t } from "@liujitcn/kratos-admin-core";
9
9
  import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
10
10
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
11
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
11
12
  import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/log/LogTable.vue";
12
13
  import { logDateSearch, logDetailColumn, logEnumLabel, createLogEnumOptions, requestLogTrace } from "@liujitcn/kratos-admin-system/components/log/log";
13
14
  import { defBasePermissionLogService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_permission_log";
@@ -18,6 +19,7 @@ import type { BasePermissionLog, PageBasePermissionLogRequest } from "@liujitcn/
18
19
  defineOptions({ name: "BasePermissionLog", inheritAttrs: false });
19
20
 
20
21
  const page = ref<InstanceType<typeof LogTable>>();
22
+ const { tenantColumns } = useTenantScope();
21
23
  const resultOptions = computed(() => createLogEnumOptions([
22
24
  [BaseLogResult.BASE_LOG_RESULT_UNSPECIFIED, t("system.base.log.result.unspecified")],
23
25
  [BaseLogResult.BASE_LOG_RESULT_SUCCESS, t("system.base.log.result.success")],
@@ -42,6 +44,7 @@ const actionOptions = computed(() => createLogEnumOptions([
42
44
  [BasePermissionAction.BASE_PERMISSION_ACTION_ASSIGN, t("system.base.log.permission_action.assign")]
43
45
  ]));
44
46
  const columns = computed<ColumnProps[]>(() => [
47
+ ...tenantColumns({ label: t("common.field.tenant") }),
45
48
  { prop: "target_type", label: t("system.base.log.field.target_type"), minWidth: 120, search: { el: "select", enum: targetOptions.value }, render: scope => logEnumLabel(targetOptions.value, (scope.row as BasePermissionLog).target_type) },
46
49
  { prop: "target_name", label: t("system.base.log.field.target_name"), minWidth: 180, search: { el: "input" } },
47
50
  { prop: "action", label: t("system.base.log.field.action"), minWidth: 110, search: { el: "select", enum: actionOptions.value }, render: scope => logEnumLabel(actionOptions.value, (scope.row as BasePermissionLog).action) },
@@ -8,6 +8,7 @@ import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTabl
8
8
  import { t } from "@liujitcn/kratos-admin-core";
9
9
  import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
10
10
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
11
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
11
12
  import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/log/LogTable.vue";
12
13
  import {
13
14
  createLogEnumOptions,
@@ -25,6 +26,7 @@ import type { BasePolicyEvaluationLog, PageBasePolicyEvaluationLogRequest } from
25
26
  defineOptions({ name: "BasePolicyEvaluationLog", inheritAttrs: false });
26
27
 
27
28
  const page = ref<InstanceType<typeof LogTable>>();
29
+ const { tenantColumns } = useTenantScope();
28
30
  const decisionOptions = computed(() => createLogEnumOptions([
29
31
  [BasePolicyDecision.BASE_POLICY_DECISION_UNSPECIFIED, t("system.base.log.policy_decision.unspecified")],
30
32
  [BasePolicyDecision.BASE_POLICY_DECISION_ALLOW, t("system.base.log.policy_decision.allow")],
@@ -38,6 +40,7 @@ const evaluationTypeOptions = computed(() => createLogEnumOptions([
38
40
  [BasePolicyEvaluationType.BASE_POLICY_EVALUATION_TYPE_FILTER_PROJECTS, t("system.base.log.evaluation_type.filter_projects")]
39
41
  ]));
40
42
  const columns = computed<ColumnProps[]>(() => [
43
+ ...tenantColumns({ label: t("common.field.tenant") }),
41
44
  { prop: "resource", label: t("system.base.log.field.resource"), minWidth: 320, search: { el: "input" } },
42
45
  { prop: "action", label: t("system.base.log.field.action"), minWidth: 100 },
43
46
  { prop: "engine", label: t("system.base.log.field.engine"), minWidth: 100 },
@@ -98,7 +98,7 @@
98
98
  </template>
99
99
 
100
100
  <script setup lang="ts">
101
- import { computed, defineComponent, h, reactive, ref } from "vue";
101
+ import { computed, defineComponent, h, onMounted, reactive, ref } from "vue";
102
102
  import type { FormRules } from "element-plus";
103
103
  import type { ColumnProps, EnumProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
104
104
  import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
@@ -106,6 +106,7 @@ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog
106
106
  import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
107
107
  import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
108
108
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
109
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
109
110
  import { t } from "@liujitcn/kratos-admin-core";
110
111
  import { defBaseApiService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_api";
111
112
  import { defBaseRedactRuleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_redact_rule";
@@ -156,8 +157,10 @@ interface OutputFieldRow extends ProFormOption {
156
157
  rule_params: string;
157
158
  }
158
159
 
159
- /** 出库脱敏表单状态。 */
160
- interface OutputFormState extends BaseRedactOutputPolicyForm {
160
+ /** 出库脱敏表单状态,新增时租户保持未选择。 */
161
+ interface OutputFormState extends Omit<BaseRedactOutputPolicyForm, "tenant_id"> {
162
+ /** 租户ID。 */
163
+ tenant_id?: number;
161
164
  /** 当前选择的 API ID。 */
162
165
  api_id?: number;
163
166
  /** API 返回字段表格。 */
@@ -200,9 +203,14 @@ const ParameterNumber = defineComponent({
200
203
 
201
204
  defineOptions({ name: "BaseRedactOutputPolicy", inheritAttrs: false });
202
205
  const { BUTTONS } = useAuthButtons();
206
+ const { isDefaultTenant, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
207
+ onMounted(() => {
208
+ void loadTenantOptions();
209
+ });
203
210
  const table = ref<ProTableInstance>();
204
211
  const dialogRef = ref<InstanceType<typeof FormDialog>>();
205
212
  const apiCatalog = ref<BaseApi[]>([]);
213
+ let apiCatalogRequest: Promise<BaseApi[]> | undefined;
206
214
  const ruleOptions = ref<ProFormOption[]>([]);
207
215
  const ruleCatalog = ref<BaseRedactRule[]>([]);
208
216
  const dialog = reactive({ visible: false, titleKey: "common.action.create_resource" });
@@ -227,6 +235,7 @@ const modeOptions = computed<ProFormOption[]>(() => [
227
235
  ]);
228
236
  const configuredFieldCount = computed(() => form.field_rows.filter(isConfiguredRow).length);
229
237
  const fields = computed<ProFormField[]>(() => [
238
+ tenantFormField({ label: t("common.field.tenant"), disabledOnEdit: true }),
230
239
  { prop: "service_name", label: t("system.base.redact_output_policy.field.service_name"), component: "select", options: serviceOptions.value, props: { filterable: true, clearable: true, placeholder: t("system.base.redact_output_policy.placeholder.service"), onChange: handleServiceChange } },
231
240
  { prop: "api_id", label: t("system.base.redact_output_policy.field.api"), component: "select", options: interfaceOptions.value.map(api => ({ label: apiLabel(api), value: api.id })), props: { filterable: true, clearable: true, disabled: !form.service_name, placeholder: t("system.base.redact_output_policy.placeholder.api"), onChange: handleApiChange } },
232
241
  { prop: "field_rows", label: t("system.base.redact_output_policy.field.response_field"), component: "slot", slotName: "field_rows", colSpan: 24, visible: () => form.api_id !== undefined },
@@ -234,6 +243,7 @@ const fields = computed<ProFormField[]>(() => [
234
243
  { prop: "remark", label: t("common.field.remark"), component: "textarea" }
235
244
  ]);
236
245
  const rules = computed<FormRules>(() => ({
246
+ tenant_id: [{ required: isDefaultTenant.value, message: t("common.validation.required_select", { field: t("common.field.tenant") }), trigger: "change" }],
237
247
  service_name: [{ required: true, message: t("system.base.redact_output_policy.validation.service_name"), trigger: "change" }],
238
248
  api_id: [{ required: true, message: t("system.base.redact_output_policy.validation.api"), trigger: "change" }],
239
249
  field_rows: [{ validator: (_rule, value: OutputFieldRow[], callback) => isConfiguredRowList(value) ? callback() : callback(new Error(t("system.base.redact_output_policy.validation.configured_fields"))), trigger: "change" }]
@@ -241,6 +251,7 @@ const rules = computed<FormRules>(() => ({
241
251
  const modeEnums = computed<EnumProps[]>(() => modeOptions.value);
242
252
  const columns = computed<ColumnProps[]>(() => [
243
253
  { type: "selection", width: 55 },
254
+ ...tenantColumns({ label: t("common.field.tenant"), order: 1 }),
244
255
  { prop: "service_name", label: t("system.base.redact_output_policy.field.service_name"), minWidth: 220, search: { el: "input" }, render: scope => serviceLabels.value.get(scope.row.service_name) ?? scope.row.service_name },
245
256
  { prop: "operation", label: t("system.base.redact_output_policy.field.api"), minWidth: 260, search: { el: "input" }, render: scope => operationLabels.value.get(scope.row.operation) ?? scope.row.operation },
246
257
  { prop: "message_ref", label: t("system.base.redact_output_policy.field.message_ref"), minWidth: 220 },
@@ -253,11 +264,21 @@ const columns = computed<ColumnProps[]>(() => [
253
264
  const headerActions = computed<HeaderActionProps[]>(() => [{ label: t("common.action.create"), type: "success", icon: CirclePlus, hidden: () => !BUTTONS.value["base:redact-output-policy:create"], onClick: () => openDialog() }, { label: t("common.action.delete"), type: "danger", icon: Delete, hidden: () => !BUTTONS.value["base:redact-output-policy:delete"], disabled: scope => !scope.selectedList.length, onClick: scope => deleteItems(scope.selectedList as BaseRedactOutputPolicy[]) }]);
254
265
 
255
266
  /** 请求出库脱敏策略分页列表。 */
256
- async function requestTable(params: PageBaseRedactOutputPolicyRequest) { const data = await defBaseRedactOutputPolicyService.PageBaseRedactOutputPolicy(buildPageRequest(params)); return { data: { list: data.base_redact_output_policies ?? [], total: data.total } }; }
267
+ async function requestTable(params: PageBaseRedactOutputPolicyRequest) { const data = await defBaseRedactOutputPolicyService.PageBaseRedactOutputPolicy({ ...buildPageRequest(params), tenant_id: toRequestTenantId(params.tenant_id) }); return { data: { list: data.base_redact_output_policies ?? [], total: data.total } }; }
257
268
  /** 加载 API 选项。 */
258
269
  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 ?? []; }
270
+ /** 请求具备租户响应字段的 GET API 选项。 */
271
+ async function requestApis() {
272
+ if (!apiCatalogRequest) {
273
+ apiCatalogRequest = defBaseApiService.OptionBaseApi({ include_public: true, tenant_response: true })
274
+ .then(data => (data.base_apis ?? []).filter(isGetApi))
275
+ .catch(error => {
276
+ apiCatalogRequest = undefined;
277
+ throw error;
278
+ });
279
+ }
280
+ return apiCatalogRequest;
281
+ }
261
282
  /** 加载脱敏规则选项。 */
262
283
  async function loadRules() { const rules = await requestRules(); ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; }
263
284
  /** 请求脱敏规则选项。 */
@@ -275,13 +296,13 @@ function collectFields(schema: BaseApiDocSchema, parentRef: string, parentPath:
275
296
  /** 规范化 OpenAPI 引用名称。 */
276
297
  function normalizeRef(ref?: string) { const parts = (ref ?? "").split("/"); return parts[parts.length - 1] || ""; }
277
298
  /** 打开新增或编辑弹窗。 */
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"; } }); }
299
+ async function openDialog(id?: number) { await dialogRef.value?.open({ load: async () => { await loadTenantOptions(); 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"; } }); }
279
300
  /** 重置弹窗表单。 */
280
301
  function resetForm() { dialog.visible = false; dialogRef.value?.resetFields(); Object.assign(form, defaultForm()); }
281
302
  /** 保存表格中已配置的全部字段。 */
282
303
  async function submit() { const valid = await dialogRef.value?.validate(); if (!valid || !isConfiguredRowList(form.field_rows)) return; const rows = form.field_rows.filter(isConfiguredRow); const createPolicies = rows.filter(row => !row.id).map(buildPayload); const updatePolicies = rows.filter(row => Boolean(row.id)).map(buildPayload); const requests: Promise<unknown>[] = []; if (createPolicies.length) requests.push(defBaseRedactOutputPolicyService.CreateBaseRedactOutputPolicy({ base_redact_output_policy: createPolicies })); if (updatePolicies.length) requests.push(defBaseRedactOutputPolicyService.UpdateBaseRedactOutputPolicy({ base_redact_output_policy: updatePolicies })); await Promise.all(requests); ElMessage.success(t("system.base.redact_output_policy.message.batch_save_success", { count: rows.length })); resetForm(); table.value?.getTableList(); }
283
304
  /** 将表格行转换为出库策略请求。 */
284
- function buildPayload(row: OutputFieldRow): BaseRedactOutputPolicyForm { syncRowParams(row); return { id: row.id, operation: form.operation, service_name: form.service_name, message_ref: row.message_ref, field_path: row.field_path, mode: row.mode, rule_id: row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE ? row.rule_id ?? 0 : 0, rule_params: row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE ? row.rule_params : "{}", status: form.status, remark: form.remark }; }
305
+ function buildPayload(row: OutputFieldRow): BaseRedactOutputPolicyForm { syncRowParams(row); return { id: row.id, tenant_id: form.tenant_id ?? 0, operation: form.operation, service_name: form.service_name, message_ref: row.message_ref, field_path: row.field_path, mode: row.mode, rule_id: row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE ? row.rule_id ?? 0 : 0, rule_params: row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE ? row.rule_params : "{}", status: form.status, remark: form.remark }; }
285
306
  /** 将已保存的策略回填到对应字段行。 */
286
307
  function applyPolicy(row: OutputFieldRow, data: BaseRedactOutputPolicyForm) { row.id = data.id; row.mode = data.mode || BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL; row.rule_id = data.rule_id || undefined; row.rule_params = data.rule_params; if (row.rule_id) { const rule = ruleCatalog.value.find(item => item.id === row.rule_id); row.rule_type = rule?.rule_type ?? ""; row.params = rule ? parseParams(row.rule_type, row.rule_params, rule.rule) : {}; } }
287
308
  /** 处理行模式变更。 */
@@ -319,7 +340,7 @@ function parseParams(ruleType: string, raw: string, fallbackRaw = ""): RuleParam
319
340
  /** 创建空的出库字段行。 */
320
341
  function createFieldRow(option: Pick<OutputFieldRow, "label" | "value" | "message_ref" | "field_path"> & { description?: string }): OutputFieldRow { return { ...option, id: 0, mode: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL, rule_id: undefined, rule_type: "", params: {}, rule_params: "{}" }; }
321
342
  /** 创建默认出库表单。 */
322
- function defaultForm(): OutputFormState { return { id: 0, api_id: undefined, field_rows: [], service_name: "", operation: "", message_ref: "", field_path: "", mode: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL, rule_id: 0, rule_params: "{}", status: Status.STATUS_ENABLE, remark: "" }; }
343
+ function defaultForm(): OutputFormState { return { id: 0, tenant_id: undefined, api_id: undefined, field_rows: [], service_name: "", operation: "", message_ref: "", field_path: "", mode: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL, rule_id: 0, rule_params: "{}", status: Status.STATUS_ENABLE, remark: "" }; }
323
344
  /** 修改出库策略状态。 */
324
345
  async function changeStatus(row: BaseRedactOutputPolicy) { const next = row.status === Status.STATUS_ENABLE ? Status.STATUS_DISABLE : Status.STATUS_ENABLE; try { await ElMessageBox.confirm(t("common.dialog.status_change", { action: t(next === Status.STATUS_ENABLE ? "common.status.enabled" : "common.status.disabled"), resource: t("system.base.redact_output_policy.title"), field: t("system.base.redact_output_policy.field.field_path"), value: row.field_path }), t("common.title.warning"), { type: "warning" }); await defBaseRedactOutputPolicyService.SetBaseRedactOutputPolicyStatus({ id: row.id, status: next }); table.value?.getTableList(); return true; } catch { return false; } }
325
346
  /** 删除选中的出库策略。 */
@@ -84,7 +84,7 @@
84
84
  </template>
85
85
 
86
86
  <script setup lang="ts">
87
- import { computed, defineComponent, h, reactive, ref } from "vue";
87
+ import { computed, defineComponent, h, onMounted, reactive, ref } from "vue";
88
88
  import type { FormRules } from "element-plus";
89
89
  import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
90
90
  import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
@@ -92,12 +92,11 @@ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog
92
92
  import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
93
93
  import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
94
94
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
95
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
95
96
  import { t } from "@liujitcn/kratos-admin-core";
96
97
  import { defBaseTableSourceService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_table_source";
97
- import { defCodeGenTableService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/code_gen_table";
98
98
  import { defBaseRedactRuleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_redact_rule";
99
99
  import { defBaseRedactStoragePolicyService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_redact_storage_policy";
100
- import type { CodeGenDatabaseTable } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/code_gen_table";
101
100
  import type { BaseRedactRule } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_redact_rule";
102
101
  import type { BaseRedactStoragePolicy, BaseRedactStoragePolicyForm, PageBaseRedactStoragePolicyRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_redact_storage_policy";
103
102
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
@@ -140,8 +139,10 @@ interface StorageColumnRow extends ProFormOption {
140
139
  rule_params: string;
141
140
  }
142
141
 
143
- /** 入库脱敏表单状态。 */
144
- interface StorageFormState extends BaseRedactStoragePolicyForm {
142
+ /** 入库脱敏表单状态,新增时租户保持未选择。 */
143
+ interface StorageFormState extends Omit<BaseRedactStoragePolicyForm, "tenant_id"> {
144
+ /** 租户ID。 */
145
+ tenant_id?: number;
145
146
  /** 当前选择的字段表格。 */
146
147
  column_rows: StorageColumnRow[];
147
148
  }
@@ -179,6 +180,10 @@ const ParameterNumber = defineComponent({
179
180
 
180
181
  defineOptions({ name: "BaseRedactStoragePolicy", inheritAttrs: false });
181
182
  const { BUTTONS } = useAuthButtons();
183
+ const { isDefaultTenant, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
184
+ onMounted(() => {
185
+ void loadTenantOptions();
186
+ });
182
187
  const table = ref<ProTableInstance>();
183
188
  const dialogRef = ref<InstanceType<typeof FormDialog>>();
184
189
  const sourceOptions = ref<ProFormOption[]>([]);
@@ -192,6 +197,7 @@ let columnsRequestRevision = 0;
192
197
  const statusOptions = computed<ProFormOption[]>(() => [{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE }, { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }]);
193
198
  const configuredFieldCount = computed(() => form.column_rows.filter(row => Boolean(row.rule_id)).length);
194
199
  const fields = computed<ProFormField[]>(() => [
200
+ tenantFormField({ label: t("common.field.tenant"), disabledOnEdit: true }),
195
201
  { prop: "source_name", label: t("system.base.redact_storage_policy.field.source_name"), component: "select", props: { filterable: true, disabled: Boolean(form.id), onChange: handleSourceChange }, options: sourceOptions.value },
196
202
  { prop: "table_name", label: t("system.base.redact_storage_policy.field.table_name"), component: "select", props: { filterable: true, disabled: Boolean(form.id) || !form.source_name, onChange: handleTableChange }, options: tableOptions.value },
197
203
  { prop: "column_rows", label: t("system.base.redact_storage_policy.field.column_name"), component: "slot", slotName: "column_rows", colSpan: 24, visible: () => Boolean(form.table_name) },
@@ -199,12 +205,14 @@ const fields = computed<ProFormField[]>(() => [
199
205
  { prop: "remark", label: t("common.field.remark"), component: "textarea" }
200
206
  ]);
201
207
  const rules = computed<FormRules>(() => ({
208
+ tenant_id: [{ required: isDefaultTenant.value, message: t("common.validation.required_select", { field: t("common.field.tenant") }), trigger: "change" }],
202
209
  source_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.source_name"), trigger: "change" }],
203
210
  table_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.table_name"), trigger: "change" }],
204
211
  column_rows: [{ validator: (_rule, value: StorageColumnRow[], callback) => value?.some(row => Boolean(row.rule_id)) ? callback() : callback(new Error(t("system.base.redact_storage_policy.validation.configured_fields"))), trigger: "change" }]
205
212
  }));
206
213
  const columns = computed<ColumnProps[]>(() => [
207
214
  { type: "selection", width: 55 },
215
+ ...tenantColumns({ label: t("common.field.tenant"), order: 1 }),
208
216
  { prop: "source_name", label: t("system.base.redact_storage_policy.field.source_name"), minWidth: 130, search: { el: "input" } },
209
217
  { prop: "table_name", label: t("system.base.redact_storage_policy.field.table_name"), minWidth: 180, search: { el: "input" }, render: scope => tableLabel(scope.row as BaseRedactStoragePolicy) },
210
218
  { prop: "column_name", label: t("system.base.redact_storage_policy.field.column_name"), minWidth: 150, search: { el: "input" } },
@@ -215,7 +223,7 @@ const columns = computed<ColumnProps[]>(() => [
215
223
  const headerActions = computed<HeaderActionProps[]>(() => [{ label: t("common.action.create"), type: "success", icon: CirclePlus, hidden: () => !BUTTONS.value["base:redact-storage-policy:create"], onClick: () => openDialog() }, { label: t("common.action.delete"), type: "danger", icon: Delete, hidden: () => !BUTTONS.value["base:redact-storage-policy:delete"], disabled: scope => !scope.selectedList.length, onClick: scope => deleteItems(scope.selectedList as BaseRedactStoragePolicy[]) }]);
216
224
 
217
225
  /** 请求入库脱敏策略分页列表。 */
218
- async function requestTable(params: PageBaseRedactStoragePolicyRequest) { const data = await defBaseRedactStoragePolicyService.PageBaseRedactStoragePolicy(buildPageRequest(params)); return { data: { list: data.base_redact_storage_policies ?? [], total: data.total } }; }
226
+ async function requestTable(params: PageBaseRedactStoragePolicyRequest) { const data = await defBaseRedactStoragePolicyService.PageBaseRedactStoragePolicy({ ...buildPageRequest(params), tenant_id: toRequestTenantId(params.tenant_id) }); return { data: { list: data.base_redact_storage_policies ?? [], total: data.total } }; }
219
227
  /** 加载脱敏规则选项。 */
220
228
  async function loadRules() { const rules = await requestRules(); ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; }
221
229
  /** 请求脱敏规则选项。 */
@@ -231,15 +239,15 @@ async function requestSourceOptions() { const data = await defBaseTableSourceSer
231
239
  /** 加载指定数据源的数据表选项。 */
232
240
  async function loadTables(sourceName = form.source_name) { tableOptions.value = await requestTables(sourceName); }
233
241
  /** 请求指定数据源的数据表选项。 */
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 })); }
242
+ async function requestTables(sourceName: string) { if (!sourceName) return []; const data = await defBaseRedactStoragePolicyService.ListBaseRedactStorageTable({ source_name: sourceName }); return (data.tables ?? []).map(item => ({ label: item.comment && item.comment !== item.name ? `${item.comment}(${item.name})` : item.name, value: item.name })); }
235
243
  /** 预加载数据表中文注释,供列表显示。 */
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; }
244
+ 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 defBaseRedactStoragePolicyService.ListBaseRedactStorageTable({ source_name: sourceName }); for (const item of data.tables ?? []) { if (item.comment) comments.set(`${sourceName}\x00${item.name}`, item.comment); } })); tableCommentMap.value = comments; }
237
245
  /** 加载并过滤数据库字段。 */
238
246
  async function loadColumns() { const revision = ++columnsRequestRevision; const rows = await requestColumns(form.source_name, form.table_name); if (revision === columnsRequestRevision) form.column_rows = rows; }
239
247
  /** 请求并转换数据库字段。 */
240
248
  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 })); }
241
249
  /** 打开新增或编辑弹窗。 */
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"; } }); }
250
+ async function openDialog(id?: number) { await dialogRef.value?.open({ load: async () => { await loadTenantOptions(); 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"; } }); }
243
251
  /** 重置弹窗表单。 */
244
252
  function resetForm() { dialog.visible = false; dialogRef.value?.resetFields(); Object.assign(form, defaultForm()); sourceOptions.value = []; tableOptions.value = []; }
245
253
  /** 保存表格中已配置的全部字段。 */
@@ -260,7 +268,7 @@ async function submit() {
260
268
  table.value?.getTableList();
261
269
  }
262
270
  /** 将表格行转换为入库策略请求。 */
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 }; }
271
+ function buildPayload(row: StorageColumnRow): BaseRedactStoragePolicyForm { syncRowParams(row); return { id: row.id, tenant_id: form.tenant_id ?? 0, 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 }; }
264
272
  /** 将已保存的策略回填到对应字段行。 */
265
273
  function applyPolicy(row: StorageColumnRow, data: BaseRedactStoragePolicyForm) { row.id = data.id; row.rule_id = data.rule_id || undefined; row.rule_params = data.rule_params; if (row.rule_id) { const rule = ruleCatalog.value.find(item => item.id === row.rule_id); row.rule_type = rule?.rule_type ?? ""; row.params = rule ? parseParams(row.rule_type, row.rule_params, rule.rule) : {}; } }
266
274
  /** 处理行规则变更。 */
@@ -288,7 +296,7 @@ async function changeStatus(row: BaseRedactStoragePolicy) { const next = row.sta
288
296
  /** 删除选中的入库策略。 */
289
297
  function deleteItems(selected?: BaseRedactStoragePolicy | BaseRedactStoragePolicy[] | number | string | Array<number | string>) { const items = Array.isArray(selected) ? selected.filter((item): item is BaseRedactStoragePolicy => typeof item === "object") : selected && typeof selected === "object" ? [selected] : []; const ids = items.length ? items.map(item => item.id) : normalizeSelectedIds(selected as number | string | Array<number | string>); if (!ids.length) { ElMessage.warning(t("common.message.select_delete_item")); return; } ElMessageBox.confirm(t("common.dialog.delete_selected", { resource: t("system.base.redact_storage_policy.title") }), t("common.title.warning"), { type: "warning" }).then(async () => { await defBaseRedactStoragePolicyService.DeleteBaseRedactStoragePolicy({ id: ids.join(",") }); ElMessage.success(t("common.message.delete_success", { resource: t("system.base.redact_storage_policy.title") })); table.value?.getTableList(); }); }
290
298
  /** 创建默认入库表单。 */
291
- function defaultForm(): StorageFormState { return { id: 0, source_name: "", table_name: "", column_name: "", column_rows: [], rule_id: 0, rule_params: "{}", status: Status.STATUS_ENABLE, remark: "" }; }
299
+ function defaultForm(): StorageFormState { return { id: 0, tenant_id: undefined, source_name: "", table_name: "", column_name: "", column_rows: [], rule_id: 0, rule_params: "{}", status: Status.STATUS_ENABLE, remark: "" }; }
292
300
 
293
301
  /** 格式化列表中的数据表名称。 */
294
302
  function tableLabel(row: BaseRedactStoragePolicy) { const comment = tableCommentMap.value.get(`${row.source_name}\x00${row.table_name}`); return comment && comment !== row.table_name ? `${comment}(${row.table_name})` : row.table_name; }
@@ -105,6 +105,7 @@ import type {
105
105
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
106
106
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
107
107
  import { copyText } from "@liujitcn/kratos-admin-core/security";
108
+ import { invalidateTenantOptions } from "@liujitcn/kratos-admin-core/tenant";
108
109
  import { t } from "@liujitcn/kratos-admin-core";
109
110
 
110
111
  defineOptions({
@@ -370,9 +371,11 @@ async function handleSubmit() {
370
371
  const submitData = JSON.parse(JSON.stringify(formData)) as BaseTenantForm;
371
372
  if (submitData.id) {
372
373
  await defBaseTenantService.UpdateBaseTenant({ base_tenant: submitData });
374
+ invalidateTenantOptions();
373
375
  ElMessage.success(t("common.message.update_success", { resource: t("common.field.tenant") }));
374
376
  } else {
375
377
  const response = await defBaseTenantService.CreateBaseTenant({ base_tenant: submitData });
378
+ invalidateTenantOptions();
376
379
  ElMessage.success(t("common.message.create_success", { resource: t("common.field.tenant") }));
377
380
  handleCloseDialog();
378
381
  refreshTable();
@@ -436,6 +439,7 @@ async function handleBeforeSetStatus(row: BaseTenant) {
436
439
  }
437
440
  );
438
441
  await defBaseTenantService.SetBaseTenantStatus({ id: row.id, status: nextStatus });
442
+ invalidateTenantOptions();
439
443
  ElMessage.success(t("common.message.status_success", { action: text }));
440
444
  refreshTable();
441
445
  return true;
@@ -481,6 +485,7 @@ function handleDelete(selected?: number | string | Array<number | string> | Base
481
485
  }).then(
482
486
  () => {
483
487
  defBaseTenantService.DeleteBaseTenant({ id: tenantIds }).then(() => {
488
+ invalidateTenantOptions();
484
489
  ElMessage.success(t("common.message.delete_success", { resource: t("common.field.tenant") }));
485
490
  refreshTable();
486
491
  });
@@ -69,7 +69,6 @@ const columns = computed<ColumnProps[]>(() => [
69
69
  prop: "device_id",
70
70
  label: t("system.profile.login_log.field.device_id"),
71
71
  minWidth: 160,
72
- align: "left",
73
72
  render: scope => (scope.row as BaseLoginLog).device_id || (scope.row as BaseLoginLog).user_agent || "--"
74
73
  },
75
74
  { prop: "reason", label: t("system.profile.login_log.field.reason"), minWidth: 180 }