@liujitcn/kratos-admin-system 0.0.54 → 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 (48) 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_file.d.ts +2 -4
  8. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n_custom.d.ts +6 -0
  9. package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +2 -0
  10. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +6 -0
  11. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_storage_policy.d.ts +27 -2
  12. package/dist/package/declarations/src/rpc/system/admin/v1/base_third_account.d.ts +2 -0
  13. package/dist/package/declarations/src/rpc/system/admin/v1/oauth_client.d.ts +2 -0
  14. package/dist/package/src/api/system/admin/v1/base_redact_storage_policy.ts +7 -0
  15. package/dist/package/src/locales/en-US.json +0 -1
  16. package/dist/package/src/locales/ja-JP.json +0 -1
  17. package/dist/package/src/locales/zh-CN.json +0 -1
  18. package/dist/package/src/locales/zh-TW.json +0 -1
  19. package/dist/package/src/rpc/base/v1/ai_session.ts +4 -0
  20. package/dist/package/src/rpc/base/v1/config.ts +13 -1
  21. package/dist/package/src/rpc/base/v1/notification.ts +2 -0
  22. package/dist/package/src/rpc/system/admin/v1/base_api.ts +7 -1
  23. package/dist/package/src/rpc/system/admin/v1/base_file.ts +2 -4
  24. package/dist/package/src/rpc/system/admin/v1/base_i18n_custom.ts +8 -0
  25. package/dist/package/src/rpc/system/admin/v1/base_message.ts +2 -0
  26. package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +8 -0
  27. package/dist/package/src/rpc/system/admin/v1/base_redact_storage_policy.ts +34 -4
  28. package/dist/package/src/rpc/system/admin/v1/base_third_account.ts +2 -0
  29. package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +2 -0
  30. package/dist/package/src/views/ai/chat/message.ts +3 -0
  31. package/dist/package/src/views/base/api-log/index.vue +3 -0
  32. package/dist/package/src/views/base/area/index.vue +6 -2
  33. package/dist/package/src/views/base/config/index.vue +14 -1
  34. package/dist/package/src/views/base/data-access-log/index.vue +4 -1
  35. package/dist/package/src/views/base/file/index.vue +1 -1
  36. package/dist/package/src/views/base/i18n-custom/index.vue +32 -4
  37. package/dist/package/src/views/base/job/log.vue +0 -1
  38. package/dist/package/src/views/base/login-log/index.vue +2 -9
  39. package/dist/package/src/views/base/menu/index.vue +0 -1
  40. package/dist/package/src/views/base/operation-log/index.vue +5 -2
  41. package/dist/package/src/views/base/permission-log/index.vue +3 -0
  42. package/dist/package/src/views/base/policy-evaluation-log/index.vue +3 -0
  43. package/dist/package/src/views/base/redact-output-policy/index.vue +30 -9
  44. package/dist/package/src/views/base/redact-storage-policy/index.vue +19 -11
  45. package/dist/package/src/views/base/tenant/index.vue +5 -0
  46. package/dist/package/src/views/profile/components/login-log.vue +0 -1
  47. package/dist/package/src/views/profile/components/session.vue +18 -12
  48. 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 { BaseApiLog, PageBaseApiLogRequest } from "@liujitcn/kratos-admin-s
26
27
  defineOptions({ name: "BaseApiLog", inheritAttrs: false });
27
28
 
28
29
  const page = ref<InstanceType<typeof LogTable>>();
30
+ const { tenantColumns } = useTenantScope();
29
31
  const resultOptions = computed(() =>
30
32
  createLogEnumOptions([
31
33
  [BaseLogResult.BASE_LOG_RESULT_UNSPECIFIED, t("system.base.log.result.unspecified")],
@@ -35,6 +37,7 @@ const resultOptions = computed(() =>
35
37
  ])
36
38
  );
37
39
  const columns = computed<ColumnProps[]>(() => [
40
+ ...tenantColumns({ label: t("common.field.tenant") }),
38
41
  { prop: "operation", label: t("system.base.log.field.operation"), minWidth: 320, search: { el: "input", key: "keyword" } },
39
42
  { prop: "method", label: t("system.base.log.field.method"), minWidth: 90 },
40
43
  { prop: "status_code", label: t("system.base.log.field.status_code"), minWidth: 100, align: "right" },
@@ -143,7 +143,7 @@ const formFields = computed<ProFormField[]>(() => [
143
143
  /** 行政区域表格列配置。 */
144
144
  const columns = computed<ColumnProps[]>(() => [
145
145
  { type: "selection", width: 55 },
146
- { prop: "name", label: t("system.base.area.field.name"), align: "left", search: { el: "input" } },
146
+ { prop: "name", label: t("system.base.area.field.name"), search: { el: "input" } },
147
147
  {
148
148
  prop: "operation",
149
149
  label: t("common.field.operation"),
@@ -192,7 +192,11 @@ const headerActions = computed<HeaderActionProps[]>(() => [
192
192
  * 请求行政区域列表,并适配 ProTable 固定列表字段。
193
193
  */
194
194
  async function requestBaseAreaTable(params: TreeBaseAreaRequest) {
195
- const data = await defBaseAreaService.TreeBaseArea({ ...params, parent_id: params.parent_id ?? 0 });
195
+ const data = await defBaseAreaService.TreeBaseArea({
196
+ ...params,
197
+ parent_id: params.parent_id ?? 0,
198
+ lazy: true
199
+ });
196
200
  return { data: data.base_areas ?? [] };
197
201
  }
198
202
 
@@ -44,7 +44,11 @@
44
44
  />
45
45
  </template>
46
46
  <template #imageValue>
47
- <UploadImg v-model:image-url="formData.value" upload-type="config" />
47
+ <UploadImg
48
+ v-model:image-url="formData.value"
49
+ upload-type="config"
50
+ :access-mode="configImageAccessMode"
51
+ />
48
52
  </template>
49
53
  <template #richTextValue>
50
54
  <WangEditor v-model:value="formData.value" upload-type="config" />
@@ -135,6 +139,7 @@ import type {
135
139
  } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_config";
136
140
  import type { BaseI18n } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
137
141
  import { BaseConfigSite } from "@liujitcn/kratos-admin-system/rpc/base/v1/config";
142
+ import { BaseFileAccessMode } from "@liujitcn/kratos-admin-core/rpc/base/v1/file";
138
143
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
139
144
  import { BaseConfigType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_config";
140
145
  import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
@@ -364,6 +369,14 @@ const BASE_CONFIG_DICT_CODE_MAP: Record<string, string> = {
364
369
  /** 当前字典类配置对应的字典编码,未配置映射时允许退回手动输入。 */
365
370
  const dictValueCode = computed(() => BASE_CONFIG_DICT_CODE_MAP[formData.key] ?? "");
366
371
 
372
+ /** 需要匿名访问的系统图片配置键,其他图片配置继续按默认授权模式上传。 */
373
+ const PUBLIC_IMAGE_CONFIG_KEYS = new Set(["adminLogo", "appLogo", "background"]);
374
+ const configImageAccessMode = computed(() =>
375
+ PUBLIC_IMAGE_CONFIG_KEYS.has(formData.key)
376
+ ? BaseFileAccessMode.BASE_FILE_ACCESS_MODE_PUBLIC
377
+ : BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED
378
+ );
379
+
367
380
  /** 系统配置表单字段配置。 */
368
381
  const formFields = computed<ProFormField[]>(() => [
369
382
  {
@@ -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
  /** 删除选中的出库策略。 */