@liujitcn/kratos-admin-system 0.0.32 → 0.0.34

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 (99) hide show
  1. package/dist/package/declarations/src/api/system/admin/v1/base_redact_output_policy.d.ts +19 -0
  2. package/dist/package/declarations/src/api/system/{base_redact_rule.d.ts → admin/v1/base_redact_rule.d.ts} +1 -1
  3. package/dist/package/declarations/src/api/system/admin/v1/base_redact_storage_policy.d.ts +19 -0
  4. package/dist/package/declarations/src/locales/generated.d.ts +292 -0
  5. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +135 -0
  6. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_rule.d.ts +0 -4
  7. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_storage_policy.d.ts +114 -0
  8. package/dist/package/src/api/system/admin/v1/base_redact_output_policy.ts +51 -0
  9. package/dist/package/src/api/system/{base_redact_rule.ts → admin/v1/base_redact_rule.ts} +1 -1
  10. package/dist/package/src/api/system/admin/v1/base_redact_storage_policy.ts +51 -0
  11. package/dist/package/src/locales/en-US.json +74 -1
  12. package/dist/package/src/locales/ja-JP.json +74 -1
  13. package/dist/package/src/locales/zh-CN.json +74 -1
  14. package/dist/package/src/locales/zh-TW.json +74 -1
  15. package/dist/package/src/rpc/base/v1/ai_message.ts +1 -1
  16. package/dist/package/src/rpc/base/v1/ai_session.ts +1 -1
  17. package/dist/package/src/rpc/base/v1/ai_tool.ts +1 -1
  18. package/dist/package/src/rpc/base/v1/config.ts +1 -1
  19. package/dist/package/src/rpc/base/v1/login.ts +1 -1
  20. package/dist/package/src/rpc/base/v1/notification.ts +1 -1
  21. package/dist/package/src/rpc/base/v1/oauth.ts +1 -1
  22. package/dist/package/src/rpc/base/v1/oauth_client.ts +1 -1
  23. package/dist/package/src/rpc/base/v1/sse.ts +1 -1
  24. package/dist/package/src/rpc/common/v1/analytics.ts +1 -1
  25. package/dist/package/src/rpc/common/v1/common.ts +1 -1
  26. package/dist/package/src/rpc/common/v1/enum.ts +1 -1
  27. package/dist/package/src/rpc/common/v1/types.ts +1 -1
  28. package/dist/package/src/rpc/google/protobuf/empty.ts +1 -1
  29. package/dist/package/src/rpc/google/protobuf/timestamp.ts +1 -1
  30. package/dist/package/src/rpc/system/admin/v1/auth.ts +1 -1
  31. package/dist/package/src/rpc/system/admin/v1/base_api.ts +1 -1
  32. package/dist/package/src/rpc/system/admin/v1/base_api_log.ts +1 -1
  33. package/dist/package/src/rpc/system/admin/v1/base_area.ts +1 -1
  34. package/dist/package/src/rpc/system/admin/v1/base_config.ts +1 -1
  35. package/dist/package/src/rpc/system/admin/v1/base_dashboard.ts +1 -1
  36. package/dist/package/src/rpc/system/admin/v1/base_data_access_log.ts +1 -1
  37. package/dist/package/src/rpc/system/admin/v1/base_dept.ts +1 -1
  38. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +1 -1
  39. package/dist/package/src/rpc/system/admin/v1/base_dict_item.ts +1 -1
  40. package/dist/package/src/rpc/system/admin/v1/base_file.ts +1 -1
  41. package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +1 -1
  42. package/dist/package/src/rpc/system/admin/v1/base_job.ts +1 -1
  43. package/dist/package/src/rpc/system/admin/v1/base_job_log.ts +1 -1
  44. package/dist/package/src/rpc/system/admin/v1/base_language.ts +1 -1
  45. package/dist/package/src/rpc/system/admin/v1/base_log.ts +1 -1
  46. package/dist/package/src/rpc/system/admin/v1/base_login_log.ts +1 -1
  47. package/dist/package/src/rpc/system/admin/v1/base_login_policy.ts +1 -1
  48. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +1 -1
  49. package/dist/package/src/rpc/system/admin/v1/base_message.ts +1 -1
  50. package/dist/package/src/rpc/system/admin/v1/base_message_category.ts +1 -1
  51. package/dist/package/src/rpc/system/admin/v1/base_migration.ts +1 -1
  52. package/dist/package/src/rpc/system/admin/v1/base_operation_log.ts +1 -1
  53. package/dist/package/src/rpc/system/admin/v1/base_permission_log.ts +1 -1
  54. package/dist/package/src/rpc/system/admin/v1/base_policy_evaluation_log.ts +1 -1
  55. package/dist/package/src/rpc/system/admin/v1/base_post.ts +1 -1
  56. package/dist/package/src/rpc/system/admin/v1/base_redact_common.ts +1 -1
  57. package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +157 -0
  58. package/dist/package/src/rpc/system/admin/v1/base_redact_rule.ts +1 -5
  59. package/dist/package/src/rpc/system/admin/v1/base_redact_storage_policy.ts +137 -0
  60. package/dist/package/src/rpc/system/admin/v1/base_role.ts +1 -1
  61. package/dist/package/src/rpc/system/admin/v1/base_session.ts +1 -1
  62. package/dist/package/src/rpc/system/admin/v1/base_table_archive.ts +1 -1
  63. package/dist/package/src/rpc/system/admin/v1/base_table_archive_record.ts +1 -1
  64. package/dist/package/src/rpc/system/admin/v1/base_table_archive_restore.ts +1 -1
  65. package/dist/package/src/rpc/system/admin/v1/base_table_backup.ts +1 -1
  66. package/dist/package/src/rpc/system/admin/v1/base_table_backup_record.ts +1 -1
  67. package/dist/package/src/rpc/system/admin/v1/base_table_backup_restore.ts +1 -1
  68. package/dist/package/src/rpc/system/admin/v1/base_table_source.ts +1 -1
  69. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +1 -1
  70. package/dist/package/src/rpc/system/admin/v1/base_third_account.ts +1 -1
  71. package/dist/package/src/rpc/system/admin/v1/base_user.ts +1 -1
  72. package/dist/package/src/rpc/system/admin/v1/cache.ts +1 -1
  73. package/dist/package/src/rpc/system/admin/v1/code_gen.ts +1 -1
  74. package/dist/package/src/rpc/system/admin/v1/code_gen_column.ts +1 -1
  75. package/dist/package/src/rpc/system/admin/v1/code_gen_proto.ts +1 -1
  76. package/dist/package/src/rpc/system/admin/v1/code_gen_table.ts +1 -1
  77. package/dist/package/src/rpc/system/admin/v1/common.ts +1 -1
  78. package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +1 -1
  79. package/dist/package/src/rpc/system/admin/v1/ops_monitoring.ts +1 -1
  80. package/dist/package/src/rpc/system/admin/v1/project_document.ts +1 -1
  81. package/dist/package/src/rpc/system/admin/v1/runtime_log.ts +1 -1
  82. package/dist/package/src/rpc/system/common/v1/common.ts +1 -1
  83. package/dist/package/src/rpc/system/config/v1/system_config.ts +1 -1
  84. package/dist/package/src/views/base/redact-output-policy/index.vue +324 -0
  85. package/dist/package/src/views/base/redact-rule/index.vue +339 -29
  86. package/dist/package/src/views/base/redact-storage-policy/index.vue +276 -0
  87. package/package.json +2 -2
  88. package/dist/package/declarations/src/api/system/base_redact_field.d.ts +0 -20
  89. package/dist/package/declarations/src/api/system/base_redact_policy.d.ts +0 -19
  90. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_field.d.ts +0 -161
  91. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_policy.d.ts +0 -150
  92. package/dist/package/src/api/system/base_redact_field.ts +0 -25
  93. package/dist/package/src/api/system/base_redact_policy.ts +0 -24
  94. package/dist/package/src/rpc/system/admin/v1/base_redact_field.ts +0 -182
  95. package/dist/package/src/rpc/system/admin/v1/base_redact_policy.ts +0 -174
  96. package/dist/package/src/views/base/redact-field/index.vue +0 -59
  97. package/dist/package/src/views/base/redact-policy/index.vue +0 -92
  98. /package/dist/package/declarations/src/views/base/{redact-field → redact-output-policy}/index.vue.d.ts +0 -0
  99. /package/dist/package/declarations/src/views/base/{redact-policy → redact-storage-policy}/index.vue.d.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/code_gen.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/code_gen_column.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/code_gen_proto.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/code_gen_table.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/common.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/oauth_client.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/ops_monitoring.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/project_document.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/admin/v1/runtime_log.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/common/v1/common.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.11.8
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: system/config/v1/system_config.proto
6
6
 
@@ -0,0 +1,324 @@
1
+ <template>
2
+ <div class="table-box">
3
+ <ProTable ref="table" row-key="id" :columns="columns" :header-actions="headerActions" :request-api="requestTable" />
4
+ <FormDialog
5
+ v-model="dialog.visible"
6
+ ref="dialogRef"
7
+ :title="t(dialog.titleKey)"
8
+ width="1180px"
9
+ top="3vh"
10
+ label-width="150px"
11
+ destroy-on-close
12
+ :model="form"
13
+ :fields="fields"
14
+ :rules="rules"
15
+ @confirm="submit"
16
+ @close="resetForm"
17
+ >
18
+ <template #field_rows>
19
+ <div class="field-table">
20
+ <div class="field-table__summary">
21
+ {{ t("system.base.redact_output_policy.message.configured_fields", { count: configuredFieldCount }) }}
22
+ </div>
23
+ <el-table :data="form.field_rows" row-key="value" border height="500">
24
+ <el-table-column :label="t('system.base.redact_output_policy.field.response_field')" min-width="280">
25
+ <template #default="{ row }">
26
+ <div class="field-cell">
27
+ <div class="field-cell__title">{{ row.field_path }}</div>
28
+ <div class="field-cell__meta">{{ row.message_ref }}<span v-if="row.description"> · {{ row.description }}</span></div>
29
+ </div>
30
+ </template>
31
+ </el-table-column>
32
+ <el-table-column :label="t('system.base.redact_output_policy.field.mode')" width="170">
33
+ <template #default="{ row }">
34
+ <el-select v-model="row.mode" class="table-control" size="small" @change="handleModeChange(row)">
35
+ <el-option v-for="option in modeOptions" :key="String(option.value)" :label="option.label" :value="option.value" />
36
+ </el-select>
37
+ </template>
38
+ </el-table-column>
39
+ <el-table-column :label="t('system.base.redact_output_policy.field.rule')" width="250">
40
+ <template #default="{ row }">
41
+ <el-select
42
+ v-model="row.rule_id"
43
+ class="table-control"
44
+ size="small"
45
+ clearable
46
+ :disabled="row.mode !== BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE"
47
+ @change="handleRuleChange(row)"
48
+ >
49
+ <el-option v-for="option in ruleOptions" :key="String(option.value)" :label="option.label" :value="option.value" :disabled="option.disabled" />
50
+ </el-select>
51
+ </template>
52
+ </el-table-column>
53
+ <el-table-column :label="t('system.base.redact_output_policy.field.parameters')" min-width="460">
54
+ <template #default="{ row }">
55
+ <div v-if="isRuleRow(row)" class="parameter-grid">
56
+ <template v-if="row.rule_type === 'MASK'">
57
+ <ParameterNumber v-model="row.params.keep_first" :label="t('system.base.redact_rule.parameter.keep_first')" />
58
+ <ParameterNumber v-model="row.params.keep_last" :label="t('system.base.redact_rule.parameter.keep_last')" />
59
+ <ParameterText v-model="row.params.mask_char" :label="t('system.base.redact_rule.parameter.mask_char')" />
60
+ </template>
61
+ <template v-else-if="row.rule_type === 'EMAIL'">
62
+ <ParameterNumber v-model="row.params.keep_local_first" :label="t('system.base.redact_rule.parameter.keep_local_first')" />
63
+ <div class="parameter-item"><span>{{ t("system.base.redact_rule.parameter.mask_domain") }}</span><el-switch v-model="row.params.mask_domain" /></div>
64
+ <ParameterText v-model="row.params.mask_char" :label="t('system.base.redact_rule.parameter.mask_char')" />
65
+ </template>
66
+ <template v-else-if="row.rule_type === 'REGEX'">
67
+ <ParameterText v-model="row.params.pattern" :label="t('system.base.redact_rule.parameter.pattern')" />
68
+ <ParameterText v-model="row.params.replacement" :label="t('system.base.redact_rule.parameter.replacement')" />
69
+ </template>
70
+ <template v-else-if="row.rule_type === 'TRUNCATE'">
71
+ <ParameterNumber v-model="row.params.length" :label="t('system.base.redact_rule.parameter.length')" />
72
+ <ParameterText v-model="row.params.suffix" :label="t('system.base.redact_rule.parameter.suffix')" />
73
+ </template>
74
+ <template v-else-if="row.rule_type === 'HASH'">
75
+ <div class="parameter-item"><span>{{ t("system.base.redact_rule.parameter.algo") }}</span><el-select v-model="row.params.algo" class="parameter-control" size="small"><el-option label="MD5" value="MD5" /><el-option label="SHA1" value="SHA1" /><el-option label="SHA256" value="SHA256" /></el-select></div>
76
+ </template>
77
+ <template v-else-if="row.rule_type === 'IP'">
78
+ <ParameterNumber v-model="row.params.keep_octets" :label="t('system.base.redact_rule.parameter.keep_octets')" />
79
+ <ParameterText v-model="row.params.mask_char" :label="t('system.base.redact_rule.parameter.mask_char')" />
80
+ </template>
81
+ <template v-else-if="row.rule_type === 'URL'">
82
+ <div class="parameter-item"><span>{{ t("system.base.redact_rule.parameter.mask_query") }}</span><el-switch v-model="row.params.mask_query" /></div>
83
+ <ParameterText v-model="row.params.mask_char" :label="t('system.base.redact_rule.parameter.mask_char')" />
84
+ </template>
85
+ <template v-else-if="row.rule_type === 'FIXED_LENGTH'">
86
+ <ParameterText v-model="row.params.char" :label="t('system.base.redact_rule.parameter.char')" />
87
+ </template>
88
+ </div>
89
+ <span v-else class="empty-value">--</span>
90
+ </template>
91
+ </el-table-column>
92
+ </el-table>
93
+ </div>
94
+ </template>
95
+ </FormDialog>
96
+ </div>
97
+ </template>
98
+
99
+ <script setup lang="ts">
100
+ import { computed, defineComponent, h, reactive, ref } from "vue";
101
+ import type { FormRules } from "element-plus";
102
+ import type { ColumnProps, EnumProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
103
+ import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
104
+ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
105
+ import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
106
+ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
107
+ import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
108
+ import { t } from "@liujitcn/kratos-admin-core";
109
+ import { defBaseApiService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_api";
110
+ import { defBaseRedactRuleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_redact_rule";
111
+ import { defBaseRedactOutputPolicyService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_redact_output_policy";
112
+ import type { BaseApi, BaseApiDocSchema } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_api";
113
+ import type { BaseRedactRule } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_redact_rule";
114
+ import type { BaseRedactOutputPolicy, BaseRedactOutputPolicyForm, PageBaseRedactOutputPolicyRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_redact_output_policy";
115
+ import { BaseRedactOutputPolicyMode } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_redact_output_policy";
116
+ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
117
+
118
+ /** 脱敏规则参数。 */
119
+ interface RuleParams {
120
+ keep_first?: number;
121
+ keep_last?: number;
122
+ mask_char?: string;
123
+ keep_local_first?: number;
124
+ mask_domain?: boolean;
125
+ pattern?: string;
126
+ replacement?: string;
127
+ length?: number;
128
+ suffix?: string;
129
+ algo?: string;
130
+ keep_octets?: number;
131
+ mask_query?: boolean;
132
+ char?: string;
133
+ }
134
+
135
+ /** 出库字段表格行。 */
136
+ interface OutputFieldRow extends ProFormOption {
137
+ /** Proto 消息名称。 */
138
+ message_ref: string;
139
+ /** Proto 字段路径。 */
140
+ field_path: string;
141
+ /** 字段描述。 */
142
+ description?: string;
143
+ /** 已有策略 ID。 */
144
+ id: number;
145
+ /** 处理模式。 */
146
+ mode: BaseRedactOutputPolicyMode;
147
+ /** 脱敏规则 ID。 */
148
+ rule_id?: number;
149
+ /** 脱敏规则类型。 */
150
+ rule_type: string;
151
+ /** 脱敏规则参数对象。 */
152
+ params: RuleParams;
153
+ /** 脱敏规则参数 JSON。 */
154
+ rule_params: string;
155
+ }
156
+
157
+ /** 出库脱敏表单状态。 */
158
+ interface OutputFormState extends BaseRedactOutputPolicyForm {
159
+ /** 当前选择的 API ID。 */
160
+ api_id?: number;
161
+ /** API 返回字段表格。 */
162
+ field_rows: OutputFieldRow[];
163
+ }
164
+
165
+ /** 出库表格行事件使用的最小字段视图。 */
166
+ interface OutputTableRow {
167
+ /** 处理模式。 */
168
+ mode?: BaseRedactOutputPolicyMode;
169
+ /** 脱敏规则 ID。 */
170
+ rule_id?: number;
171
+ /** 脱敏规则类型。 */
172
+ rule_type?: string;
173
+ /** 脱敏规则参数对象。 */
174
+ params?: RuleParams;
175
+ /** 脱敏规则参数 JSON。 */
176
+ rule_params?: string;
177
+ }
178
+
179
+ const OUTPUT_SYSTEM_FIELD_NAMES = new Set([
180
+ "id", "created_at", "created_by", "updated_at", "updated_by", "deleted_at", "deleted_by",
181
+ "create_time", "creator", "creator_id", "update_time", "updater", "updater_id", "delete_time", "deleter", "deleter_id"
182
+ ]);
183
+
184
+ const ParameterText = defineComponent({
185
+ props: { modelValue: { type: [String, Number], default: "" }, label: { type: String, required: true } },
186
+ emits: ["update:modelValue"],
187
+ setup(props, { emit }) {
188
+ return () => h("div", { class: "parameter-item" }, [h("span", props.label), h("input", { class: "el-input__inner", value: props.modelValue, onInput: (event: Event) => emit("update:modelValue", (event.target as HTMLInputElement).value) })]);
189
+ }
190
+ });
191
+ const ParameterNumber = defineComponent({
192
+ props: { modelValue: { type: Number, default: 0 }, label: { type: String, required: true } },
193
+ emits: ["update:modelValue"],
194
+ setup(props, { emit }) {
195
+ return () => h("div", { class: "parameter-item" }, [h("span", props.label), h("input", { class: "el-input__inner", type: "number", min: 0, value: props.modelValue, onInput: (event: Event) => emit("update:modelValue", Number((event.target as HTMLInputElement).value)) })]);
196
+ }
197
+ });
198
+
199
+ defineOptions({ name: "BaseRedactOutputPolicy", inheritAttrs: false });
200
+ const { BUTTONS } = useAuthButtons();
201
+ const table = ref<ProTableInstance>();
202
+ const dialogRef = ref<InstanceType<typeof FormDialog>>();
203
+ const apiCatalog = ref<BaseApi[]>([]);
204
+ const ruleOptions = ref<ProFormOption[]>([]);
205
+ const ruleCatalog = ref<BaseRedactRule[]>([]);
206
+ const dialog = reactive({ visible: false, titleKey: "common.action.create_resource" });
207
+ const form = reactive<OutputFormState>(defaultForm());
208
+ const statusOptions = computed<ProFormOption[]>(() => [{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE }, { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }]);
209
+ const serviceOptions = computed<ProFormOption[]>(() => {
210
+ const services = new Map<string, string>();
211
+ for (const item of apiCatalog.value) {
212
+ if (!isGetApi(item)) continue;
213
+ if (item.service_name && !services.has(item.service_name)) services.set(item.service_name, serviceLabel(item.service_name));
214
+ }
215
+ return [...services.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([value, label]) => ({ label, value }));
216
+ });
217
+ const interfaceOptions = computed(() => apiCatalog.value.filter(item => item.service_name === form.service_name && isGetApi(item)));
218
+ const serviceLabels = computed(() => new Map(apiCatalog.value.map(item => [item.service_name, item.service_desc || item.service_name])));
219
+ const operationLabels = computed(() => new Map(apiCatalog.value.map(item => [item.operation, item.desc || item.operation])));
220
+ const modeOptions = computed<ProFormOption[]>(() => [
221
+ { label: t("system.base.redact_output_policy.mode.rule"), value: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE },
222
+ { label: t("system.base.redact_output_policy.mode.hide"), value: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_HIDE },
223
+ { label: t("system.base.redact_output_policy.mode.full"), value: BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL }
224
+ ]);
225
+ const configuredFieldCount = computed(() => form.field_rows.filter(isConfiguredRow).length);
226
+ const fields = computed<ProFormField[]>(() => [
227
+ { 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 } },
228
+ { 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 } },
229
+ { 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 },
230
+ { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value },
231
+ { prop: "remark", label: t("common.field.remark"), component: "textarea" }
232
+ ]);
233
+ const rules = computed<FormRules>(() => ({
234
+ service_name: [{ required: true, message: t("system.base.redact_output_policy.validation.service_name"), trigger: "change" }],
235
+ api_id: [{ required: true, message: t("system.base.redact_output_policy.validation.api"), trigger: "change" }],
236
+ field_rows: [{ validator: (_rule, value: OutputFieldRow[], callback) => isConfiguredRowList(value) ? callback() : callback(new Error(t("system.base.redact_output_policy.validation.configured_fields"))), trigger: "change" }]
237
+ }));
238
+ const modeEnums = computed<EnumProps[]>(() => modeOptions.value);
239
+ const columns = computed<ColumnProps[]>(() => [
240
+ { type: "selection", width: 55 },
241
+ { 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 },
242
+ { 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 },
243
+ { prop: "message_ref", label: t("system.base.redact_output_policy.field.message_ref"), minWidth: 220 },
244
+ { prop: "field_path", label: t("system.base.redact_output_policy.field.field_path"), minWidth: 160 },
245
+ { prop: "mode", label: t("system.base.redact_output_policy.field.mode"), width: 110, enum: modeEnums.value, isFilterEnum: true },
246
+ { prop: "rule_name", label: t("system.base.redact_output_policy.field.rule"), width: 150 },
247
+ { prop: "status", label: t("common.field.status"), width: 100, cellType: "status", statusProps: { activeValue: Status.STATUS_ENABLE, inactiveValue: Status.STATUS_DISABLE, activeText: t("common.status.enabled"), inactiveText: t("common.status.disabled"), disabled: () => !BUTTONS.value["base:redact-output-policy:status"], beforeChange: scope => changeStatus(scope.row as BaseRedactOutputPolicy) } },
248
+ { prop: "actions", label: t("common.field.operation"), width: 150, fixed: "right", cellType: "actions", actions: [{ label: t("common.action.edit"), type: "primary", link: true, icon: EditPen, hidden: () => !BUTTONS.value["base:redact-output-policy:update"], onClick: scope => openDialog((scope.row as BaseRedactOutputPolicy).id) }, { label: t("common.action.delete"), type: "danger", link: true, icon: Delete, hidden: () => !BUTTONS.value["base:redact-output-policy:delete"], onClick: scope => deleteItems(scope.row as BaseRedactOutputPolicy) }] }
249
+ ]);
250
+ 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[]) }]);
251
+
252
+ /** 请求出库脱敏策略分页列表。 */
253
+ async function requestTable(params: PageBaseRedactOutputPolicyRequest) { const data = await defBaseRedactOutputPolicyService.PageBaseRedactOutputPolicy(buildPageRequest(params)); return { data: { list: data.base_redact_output_policies ?? [], total: data.total } }; }
254
+ /** 加载 API 选项。 */
255
+ async function loadApis() { const data = await defBaseApiService.OptionBaseApi({ include_public: true }); apiCatalog.value = data.base_apis ?? []; }
256
+ /** 加载脱敏规则选项。 */
257
+ async function loadRules() { const data = await defBaseRedactRuleService.PageBaseRedactRule({ code: "", name: "", rule_type: "", page_num: 1, page_size: 100 }); ruleCatalog.value = data.base_redact_rules ?? []; ruleOptions.value = ruleCatalog.value.map(item => ({ label: `${item.name} (${item.code})`, value: item.id, disabled: item.status !== Status.STATUS_ENABLE })); }
258
+ /** 服务变更后清空接口和返回字段。 */
259
+ function handleServiceChange(serviceName?: string) { form.service_name = serviceName ?? ""; form.api_id = undefined; form.operation = ""; form.message_ref = ""; form.field_path = ""; form.field_rows = []; }
260
+ /** API 变更后重新加载返回字段。 */
261
+ async function handleApiChange(apiId?: number) { const api = interfaceOptions.value.find(item => item.id === apiId); form.service_name = api?.service_name ?? form.service_name; form.operation = api?.operation ?? ""; form.field_rows = []; if (apiId !== undefined) await loadResponseFields(apiId); }
262
+ /** 加载 API 返回字段并初始化表格行。 */
263
+ async function loadResponseFields(apiId: number) { const api = apiCatalog.value.find(item => item.id === apiId); if (!api) return; const doc = await defBaseApiService.GetBaseApiDoc({ id: apiId }); const rows: OutputFieldRow[] = []; for (const response of doc.responses ?? []) { if (response.body) collectFields(response.body, "", "", rows, true); } form.field_rows = [...new Map(rows.map(item => [String(item.value), item])).values()]; }
264
+ /** 递归收集可配置的返回叶子字段。 */
265
+ function collectFields(schema: BaseApiDocSchema, parentRef: string, parentPath: string, result: OutputFieldRow[], root: boolean) { const schemaRef = normalizeRef(schema.ref); const messageRef = schemaRef || parentRef; const startsNewMessage = Boolean(schemaRef && parentRef && schemaRef !== parentRef); const rootContainer = root || (!parentRef && (schema.name === "body" || schema.name === "body[]")); const path = rootContainer || startsNewMessage ? "" : schema.name ? (parentPath ? `${parentPath}.${schema.name}` : schema.name) : parentPath; if (!schema.children?.length) { const fieldName = path.split(".").pop()?.toLowerCase() ?? ""; if (path && !OUTPUT_SYSTEM_FIELD_NAMES.has(fieldName)) result.push(createFieldRow({ label: `${messageRef}.${path}${schema.description ? ` (${schema.description})` : ""}`, value: `${messageRef}\u0000${path}`, message_ref: messageRef, field_path: path, description: schema.description })); return; } for (const child of schema.children) collectFields(child, messageRef, path, result, false); }
266
+ /** 规范化 OpenAPI 引用名称。 */
267
+ function normalizeRef(ref?: string) { const parts = (ref ?? "").split("/"); return parts[parts.length - 1] || ""; }
268
+ /** 打开新增或编辑弹窗。 */
269
+ async function openDialog(id?: number) { resetForm(); await Promise.all([loadApis(), loadRules()]); if (id !== undefined) { const data = await defBaseRedactOutputPolicyService.GetBaseRedactOutputPolicy({ id }); Object.assign(form, data); const api = apiCatalog.value.find(item => item.operation === data.operation); if (api) { form.service_name = api.service_name; form.api_id = api.id; await loadResponseFields(api.id); 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"; dialog.visible = true; }
270
+ /** 重置弹窗表单。 */
271
+ function resetForm() { dialog.visible = false; dialogRef.value?.resetFields(); Object.assign(form, defaultForm()); }
272
+ /** 保存表格中已配置的全部字段。 */
273
+ 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(); }
274
+ /** 将表格行转换为出库策略请求。 */
275
+ 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 }; }
276
+ /** 将已保存的策略回填到对应字段行。 */
277
+ 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 = parseParams(row.rule_type, row.rule_params); } }
278
+ /** 处理行模式变更。 */
279
+ function handleModeChange(row: OutputTableRow) { if (row.mode !== BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE) { row.rule_id = undefined; row.rule_type = ""; row.params = {}; row.rule_params = "{}"; } }
280
+ /** 处理行规则变更。 */
281
+ function handleRuleChange(row: OutputTableRow) { const rule = ruleCatalog.value.find(item => item.id === row.rule_id); row.rule_type = rule?.rule_type ?? ""; row.params = rule ? parseParams(rule.rule_type, rule.rule) : {}; row.rule_params = rule ? rule.rule : "{}"; }
282
+ /** 同步单行规则参数。 */
283
+ function syncRowParams(row: OutputFieldRow) { const rule = ruleCatalog.value.find(item => item.id === row.rule_id); if (rule) { row.rule_type = rule.rule_type; row.rule_params = JSON.stringify({ [rule.rule_type.toLowerCase()]: row.params }); } }
284
+ /** 判断一行是否已经配置处理方式。 */
285
+ function isConfiguredRow(row: OutputFieldRow) { return row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_HIDE || row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_FULL || (row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE && Boolean(row.rule_id)); }
286
+ /** 判断字段表格是否至少配置了一行。 */
287
+ function isConfiguredRowList(rows: OutputFieldRow[] | undefined) { return Boolean(rows?.some(isConfiguredRow)); }
288
+ /** 判断字段行是否使用规则模板。 */
289
+ function isRuleRow(row: OutputTableRow) { return row.mode === BaseRedactOutputPolicyMode.BASE_REDACT_OUTPUT_POLICY_MODE_RULE && Boolean(row.rule_id); }
290
+ /** 格式化 API 下拉项。 */
291
+ function apiLabel(api: BaseApi) { return api.desc && api.desc !== api.operation ? `${api.desc}(${api.operation})` : api.operation; }
292
+ /** 判断接口是否为 GET 请求。 */
293
+ function isGetApi(api: BaseApi) { return api.method.toUpperCase() === "GET"; }
294
+ /** 格式化服务下拉项。 */
295
+ function serviceLabel(serviceName: string) { const service = apiCatalog.value.find(item => item.service_name === serviceName); return service?.service_desc && service.service_desc !== serviceName ? `${service.service_desc}(${serviceName})` : serviceName; }
296
+ /** 解析规则参数。 */
297
+ function parseParams(ruleType: string, raw: string): RuleParams { try { const value = JSON.parse(raw) as Record<string, RuleParams>; return value[ruleType.toLowerCase()] ?? defaultParams(ruleType); } catch { return defaultParams(ruleType); } }
298
+ /** 返回规则默认参数。 */
299
+ function defaultParams(ruleType: string): RuleParams { switch (ruleType) { case "MASK": return { keep_first: 3, keep_last: 4, mask_char: "*" }; case "EMAIL": return { keep_local_first: 2, mask_domain: false, mask_char: "*" }; case "REGEX": return { pattern: "(?s).+", replacement: "[REDACTED]" }; case "TRUNCATE": return { length: 10, suffix: "..." }; case "HASH": return { algo: "SHA256" }; case "IP": return { keep_octets: 2, mask_char: "x" }; case "URL": return { mask_query: true, mask_char: "*" }; case "FIXED_LENGTH": return { char: "X" }; default: return {}; } }
300
+ /** 创建空的出库字段行。 */
301
+ 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: "{}" }; }
302
+ /** 创建默认出库表单。 */
303
+ 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: "" }; }
304
+ /** 修改出库策略状态。 */
305
+ 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; } }
306
+ /** 删除选中的出库策略。 */
307
+ function deleteItems(selected?: BaseRedactOutputPolicy | BaseRedactOutputPolicy[] | number | string | Array<number | string>) { const items = Array.isArray(selected) ? selected.filter((item): item is BaseRedactOutputPolicy => 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_output_policy.title") }), t("common.title.warning"), { type: "warning" }).then(async () => { await defBaseRedactOutputPolicyService.DeleteBaseRedactOutputPolicy({ id: ids.join(",") }); ElMessage.success(t("common.message.delete_success", { resource: t("system.base.redact_output_policy.title") })); table.value?.getTableList(); }); }
308
+
309
+ void loadApis();
310
+ </script>
311
+
312
+ <style scoped lang="scss">
313
+ .field-table { width: 100%; }
314
+ .field-table__summary { margin-bottom: 8px; color: var(--el-text-color-secondary); line-height: 1.5; }
315
+ .field-cell { min-width: 0; line-height: 1.35; }
316
+ .field-cell__title { overflow: hidden; color: var(--el-text-color-regular); text-overflow: ellipsis; white-space: nowrap; }
317
+ .field-cell__meta { overflow: hidden; color: var(--el-text-color-secondary); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
318
+ .table-control { width: 100%; }
319
+ .parameter-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; min-width: 420px; }
320
+ .parameter-item { display: flex; flex-direction: column; gap: 4px; min-width: 0; color: var(--el-text-color-regular); font-size: 12px; }
321
+ .parameter-control { width: 100%; }
322
+ .empty-value { color: var(--el-text-color-secondary); }
323
+ @media (max-width: 900px) { .parameter-grid { grid-template-columns: minmax(0, 1fr); min-width: 0; } }
324
+ </style>