@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.
- package/dist/package/declarations/src/api/system/admin/v1/base_redact_storage_policy.d.ts +3 -1
- package/dist/package/declarations/src/locales/generated.d.ts +0 -4
- package/dist/package/declarations/src/rpc/base/v1/ai_session.d.ts +4 -0
- package/dist/package/declarations/src/rpc/base/v1/config.d.ts +11 -1
- package/dist/package/declarations/src/rpc/base/v1/notification.d.ts +2 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_api.d.ts +4 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n_custom.d.ts +6 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +2 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +6 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_storage_policy.d.ts +27 -2
- package/dist/package/declarations/src/rpc/system/admin/v1/base_third_account.d.ts +2 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/oauth_client.d.ts +2 -0
- package/dist/package/src/api/system/admin/v1/base_redact_storage_policy.ts +7 -0
- package/dist/package/src/locales/en-US.json +0 -1
- package/dist/package/src/locales/ja-JP.json +0 -1
- package/dist/package/src/locales/zh-CN.json +0 -1
- package/dist/package/src/locales/zh-TW.json +0 -1
- package/dist/package/src/rpc/base/v1/ai_session.ts +4 -0
- package/dist/package/src/rpc/base/v1/config.ts +13 -1
- package/dist/package/src/rpc/base/v1/notification.ts +2 -0
- package/dist/package/src/rpc/system/admin/v1/base_api.ts +7 -1
- package/dist/package/src/rpc/system/admin/v1/base_i18n_custom.ts +8 -0
- package/dist/package/src/rpc/system/admin/v1/base_message.ts +2 -0
- package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +8 -0
- package/dist/package/src/rpc/system/admin/v1/base_redact_storage_policy.ts +34 -4
- package/dist/package/src/rpc/system/admin/v1/base_third_account.ts +2 -0
- package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +2 -0
- package/dist/package/src/views/ai/chat/message.ts +3 -0
- package/dist/package/src/views/base/api-log/index.vue +3 -0
- package/dist/package/src/views/base/area/index.vue +6 -2
- package/dist/package/src/views/base/data-access-log/index.vue +4 -1
- package/dist/package/src/views/base/file/index.vue +1 -1
- package/dist/package/src/views/base/i18n-custom/index.vue +32 -4
- package/dist/package/src/views/base/job/log.vue +0 -1
- package/dist/package/src/views/base/login-log/index.vue +2 -9
- package/dist/package/src/views/base/menu/index.vue +0 -1
- package/dist/package/src/views/base/operation-log/index.vue +5 -2
- package/dist/package/src/views/base/permission-log/index.vue +3 -0
- package/dist/package/src/views/base/policy-evaluation-log/index.vue +3 -0
- package/dist/package/src/views/base/redact-output-policy/index.vue +30 -9
- package/dist/package/src/views/base/redact-storage-policy/index.vue +19 -11
- package/dist/package/src/views/base/tenant/index.vue +5 -0
- package/dist/package/src/views/profile/components/login-log.vue +0 -1
- package/dist/package/src/views/profile/components/session.vue +18 -12
- 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")
|
|
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<
|
|
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(
|
|
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(),
|
|
@@ -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 {
|
|
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
|
|
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")
|
|
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
|
-
/**
|
|
260
|
-
async function requestApis() {
|
|
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
|
|
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
|
|
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 }
|