@liujitcn/kratos-admin-system 0.0.61 → 0.0.64

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 (97) hide show
  1. package/README.md +16 -1
  2. package/dist/package/declarations/src/api/base/v1/ai_provider.d.ts +7 -0
  3. package/dist/package/declarations/src/api/system/admin/v1/ai_provider.d.ts +18 -0
  4. package/dist/package/declarations/src/api/system/admin/v1/base_api_rate_limit_policy.d.ts +19 -0
  5. package/dist/package/declarations/src/api/system/admin/v1/base_message_provider.d.ts +21 -0
  6. package/dist/package/declarations/src/api/system/admin/v1/base_message_template.d.ts +16 -0
  7. package/dist/package/declarations/src/api/system/admin/v1/base_oauth_provider.d.ts +18 -0
  8. package/dist/package/declarations/src/api/system/admin/v1/base_rate_limit_rule.d.ts +21 -0
  9. package/dist/package/declarations/src/components/api/ApiTransfer.vue.d.ts +35 -0
  10. package/dist/package/declarations/src/components/api/apiTransfer.d.ts +13 -0
  11. package/dist/package/declarations/src/components/i18n/DynamicI18nCell.vue.d.ts +2 -2
  12. package/dist/package/declarations/src/components/i18n/dynamicI18n.d.ts +3 -4
  13. package/dist/package/declarations/src/locales/generated.d.ts +900 -0
  14. package/dist/package/declarations/src/rpc/base/v1/ai_message.d.ts +4 -0
  15. package/dist/package/declarations/src/rpc/base/v1/ai_provider.d.ts +22 -0
  16. package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +20 -0
  17. package/dist/package/declarations/src/rpc/google/protobuf/struct.d.ts +81 -0
  18. package/dist/package/declarations/src/rpc/system/admin/v1/ai_provider.d.ts +110 -0
  19. package/dist/package/declarations/src/rpc/system/admin/v1/base_api_rate_limit_policy.d.ts +137 -0
  20. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n.d.ts +4 -23
  21. package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +4 -4
  22. package/dist/package/declarations/src/rpc/system/admin/v1/base_message_category.d.ts +19 -0
  23. package/dist/package/declarations/src/rpc/system/admin/v1/base_message_provider.d.ts +126 -0
  24. package/dist/package/declarations/src/rpc/system/admin/v1/base_message_template.d.ts +99 -0
  25. package/dist/package/declarations/src/rpc/system/admin/v1/base_oauth_provider.d.ts +133 -0
  26. package/dist/package/declarations/src/rpc/system/admin/v1/base_rate_limit_rule.d.ts +144 -0
  27. package/dist/package/declarations/src/utils/persisted-message.d.ts +4 -0
  28. package/dist/package/declarations/src/utils/rateLimit.d.ts +24 -0
  29. package/dist/package/declarations/src/views/ai/chat/components/ChatPanel.vue.d.ts +11 -2
  30. package/dist/package/declarations/src/views/ai/chat/components/XSender.vue.d.ts +9 -0
  31. package/dist/package/declarations/src/views/base/ai-provider/index.vue.d.ts +3 -0
  32. package/dist/package/declarations/src/views/base/api-rate-limit-policy/index.vue.d.ts +3 -0
  33. package/dist/package/declarations/src/views/base/message-provider/index.vue.d.ts +3 -0
  34. package/dist/package/declarations/src/views/base/message-template/index.vue.d.ts +3 -0
  35. package/dist/package/declarations/src/views/base/oauth-provider/index.vue.d.ts +3 -0
  36. package/dist/package/declarations/src/views/base/rate-limit-rule/index.vue.d.ts +3 -0
  37. package/dist/package/src/api/base/v1/ai_provider.ts +22 -0
  38. package/dist/package/src/api/system/admin/v1/ai_provider.ts +50 -0
  39. package/dist/package/src/api/system/admin/v1/base_api_rate_limit_policy.ts +51 -0
  40. package/dist/package/src/api/system/admin/v1/base_message_provider.ts +57 -0
  41. package/dist/package/src/api/system/admin/v1/base_message_template.ts +44 -0
  42. package/dist/package/src/api/system/admin/v1/base_oauth_provider.ts +50 -0
  43. package/dist/package/src/api/system/admin/v1/base_rate_limit_rule.ts +58 -0
  44. package/dist/package/src/components/ai/Ai.vue +1 -1
  45. package/dist/package/src/components/api/ApiTransfer.vue +117 -0
  46. package/dist/package/src/components/api/apiTransfer.ts +27 -0
  47. package/dist/package/src/components/i18n/DynamicI18nCell.vue +8 -8
  48. package/dist/package/src/components/i18n/DynamicI18nEditor.vue +6 -3
  49. package/dist/package/src/components/i18n/dynamicI18n.ts +4 -5
  50. package/dist/package/src/components/tenant-project/TenantProjectManager.vue +2 -1
  51. package/dist/package/src/locales/en-US.json +229 -4
  52. package/dist/package/src/locales/ja-JP.json +229 -4
  53. package/dist/package/src/locales/zh-CN.json +229 -4
  54. package/dist/package/src/locales/zh-TW.json +229 -4
  55. package/dist/package/src/rpc/base/v1/ai_message.ts +7 -1
  56. package/dist/package/src/rpc/base/v1/ai_provider.ts +33 -0
  57. package/dist/package/src/rpc/base/v1/oauth.ts +16 -0
  58. package/dist/package/src/rpc/google/protobuf/struct.ts +80 -0
  59. package/dist/package/src/rpc/system/admin/v1/ai_provider.ts +129 -0
  60. package/dist/package/src/rpc/system/admin/v1/base_api_rate_limit_policy.ts +160 -0
  61. package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +4 -24
  62. package/dist/package/src/rpc/system/admin/v1/base_message.ts +4 -4
  63. package/dist/package/src/rpc/system/admin/v1/base_message_category.ts +20 -0
  64. package/dist/package/src/rpc/system/admin/v1/base_message_provider.ts +150 -0
  65. package/dist/package/src/rpc/system/admin/v1/base_message_template.ts +117 -0
  66. package/dist/package/src/rpc/system/admin/v1/base_oauth_provider.ts +156 -0
  67. package/dist/package/src/rpc/system/admin/v1/base_rate_limit_rule.ts +167 -0
  68. package/dist/package/src/utils/persisted-message.ts +21 -0
  69. package/dist/package/src/utils/rateLimit.ts +140 -0
  70. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +36 -4
  71. package/dist/package/src/views/ai/chat/components/XSender.vue +112 -1
  72. package/dist/package/src/views/ai/chat/index.vue +30 -1
  73. package/dist/package/src/views/base/ai-provider/index.vue +512 -0
  74. package/dist/package/src/views/base/api-rate-limit-policy/index.vue +428 -0
  75. package/dist/package/src/views/base/backup-management/archive-record/index.vue +2 -0
  76. package/dist/package/src/views/base/backup-management/archive-restore/index.vue +2 -1
  77. package/dist/package/src/views/base/backup-management/backup-record/index.vue +2 -0
  78. package/dist/package/src/views/base/backup-management/backup-restore/index.vue +2 -1
  79. package/dist/package/src/views/base/config/index.vue +12 -13
  80. package/dist/package/src/views/base/dict/index.vue +2 -3
  81. package/dist/package/src/views/base/dict/item.vue +2 -3
  82. package/dist/package/src/views/base/job/index.vue +2 -3
  83. package/dist/package/src/views/base/job/log.vue +3 -2
  84. package/dist/package/src/views/base/menu/index.vue +27 -83
  85. package/dist/package/src/views/base/message/index.vue +9 -3
  86. package/dist/package/src/views/base/message-category/index.vue +34 -3
  87. package/dist/package/src/views/base/message-provider/index.vue +164 -0
  88. package/dist/package/src/views/base/message-template/index.vue +105 -0
  89. package/dist/package/src/views/base/migration/index.vue +1 -1
  90. package/dist/package/src/views/base/oauth-client/index.vue +6 -6
  91. package/dist/package/src/views/base/oauth-provider/index.vue +274 -0
  92. package/dist/package/src/views/base/rate-limit-rule/index.vue +322 -0
  93. package/dist/package/src/views/base/redact-output-policy/index.vue +1 -1
  94. package/dist/package/src/views/base/redact-rule/index.vue +12 -2
  95. package/dist/package/src/views/base/redact-storage-policy/index.vue +4 -0
  96. package/dist/package/src/views/base/tenant/index.vue +3 -3
  97. package/package.json +2 -2
@@ -0,0 +1,322 @@
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="720px"
9
+ :model="form"
10
+ :fields="fields"
11
+ :rules="rules"
12
+ @confirm="submit"
13
+ @close="resetForm"
14
+ >
15
+ <template #parameters>
16
+ <div v-if="form.rule_type === BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_TOKEN_BUCKET" class="parameter-grid">
17
+ <div class="parameter-item">
18
+ <span class="parameter-label">
19
+ <span>{{ t("system.base.rate_limit_rule.field.tokens_per_second") }}</span>
20
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.tokens_per_second')" placement="top" effect="light">
21
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
22
+ </el-tooltip>
23
+ </span>
24
+ <el-input-number v-model="form.params.tokens_per_second" :min="0" :max="1000000" :precision="3" :step="1" controls-position="right" />
25
+ </div>
26
+ <div class="parameter-item">
27
+ <span class="parameter-label">
28
+ <span>{{ t("system.base.rate_limit_rule.field.burst") }}</span>
29
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.burst')" placement="top" effect="light">
30
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
31
+ </el-tooltip>
32
+ </span>
33
+ <el-input-number v-model="form.params.burst" :min="0" :max="1000000" :precision="0" controls-position="right" />
34
+ </div>
35
+ </div>
36
+ <div v-else-if="windowedAlgorithms.includes(form.rule_type)" class="parameter-grid">
37
+ <div class="parameter-item">
38
+ <span class="parameter-label">
39
+ <span>{{ t("system.base.rate_limit_rule.field.limit") }}</span>
40
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.limit')" placement="top" effect="light">
41
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
42
+ </el-tooltip>
43
+ </span>
44
+ <el-input-number v-model="form.params.limit" :min="1" :max="form.rule_type === BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_SLIDING_WINDOW_LOG ? 10000 : 1000000" :precision="0" controls-position="right" />
45
+ </div>
46
+ <div class="parameter-item">
47
+ <span class="parameter-label">
48
+ <span>{{ t("system.base.rate_limit_rule.field.window_seconds") }}</span>
49
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.window_seconds')" placement="top" effect="light">
50
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
51
+ </el-tooltip>
52
+ </span>
53
+ <el-input-number v-model="form.params.window_seconds" :min="1" :max="86400" :precision="0" controls-position="right" />
54
+ </div>
55
+ </div>
56
+ <div v-else-if="form.rule_type === BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_LEAKY_BUCKET" class="parameter-grid">
57
+ <div class="parameter-item">
58
+ <span class="parameter-label">
59
+ <span>{{ t("system.base.rate_limit_rule.field.leak_rate_per_second") }}</span>
60
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.leak_rate_per_second')" placement="top" effect="light">
61
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
62
+ </el-tooltip>
63
+ </span>
64
+ <el-input-number v-model="form.params.leak_rate_per_second" :min="0.001" :max="1000000" :precision="3" :step="1" controls-position="right" />
65
+ </div>
66
+ <div class="parameter-item">
67
+ <span class="parameter-label">
68
+ <span>{{ t("system.base.rate_limit_rule.field.capacity") }}</span>
69
+ <el-tooltip :content="t('system.base.rate_limit_rule.tooltip.capacity')" placement="top" effect="light">
70
+ <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
71
+ </el-tooltip>
72
+ </span>
73
+ <el-input-number v-model="form.params.capacity" :min="1" :max="1000000" :precision="0" controls-position="right" />
74
+ </div>
75
+ </div>
76
+ </template>
77
+ </FormDialog>
78
+ </div>
79
+ </template>
80
+
81
+ <script setup lang="ts">
82
+ import { computed, reactive, ref } from "vue";
83
+ import { ElMessage, ElMessageBox } from "element-plus";
84
+ import type { FormRules } from "element-plus";
85
+ import { CirclePlus, Delete, EditPen, QuestionFilled } from "@element-plus/icons-vue";
86
+ import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
87
+ import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
88
+ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
89
+ import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
90
+ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
91
+ import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
92
+ import { t } from "@liujitcn/kratos-admin-core";
93
+ import { defBaseRateLimitRuleService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_rate_limit_rule";
94
+ import { BaseRateLimitAlgorithm } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_rate_limit_rule";
95
+ import type { BaseRateLimitRule, BaseRateLimitRuleForm, PageBaseRateLimitRuleRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_rate_limit_rule";
96
+ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
97
+ import { defaultRateLimitParams, parseRateLimitParams, rateLimitAlgorithmLabelKey, rateLimitAlgorithmTooltipKey, rateLimitSummaryKey, rateLimitSummaryParams, serializeRateLimitParams, type RateLimitParams } from "../../../utils/rateLimit";
98
+
99
+ /** 限流规则表单状态。 */
100
+ interface RuleFormState extends BaseRateLimitRuleForm {
101
+ /** 当前算法对应的可编辑参数。 */
102
+ params: RateLimitParams;
103
+ }
104
+
105
+ defineOptions({ name: "BaseRateLimitRule", inheritAttrs: false });
106
+
107
+ const { BUTTONS } = useAuthButtons();
108
+ const table = ref<ProTableInstance>();
109
+ const dialogRef = ref<InstanceType<typeof FormDialog>>();
110
+ const dialog = reactive({ visible: false, titleKey: "common.action.create_resource" });
111
+ const form = reactive<RuleFormState>(defaultForm());
112
+ const windowedAlgorithms = [
113
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_FIXED_WINDOW,
114
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_SLIDING_WINDOW_COUNTER,
115
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_SLIDING_WINDOW_LOG
116
+ ];
117
+ const algorithmOptions = computed<ProFormOption[]>(() => [
118
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_TOKEN_BUCKET,
119
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_FIXED_WINDOW,
120
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_SLIDING_WINDOW_COUNTER,
121
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_SLIDING_WINDOW_LOG,
122
+ BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_LEAKY_BUCKET
123
+ ].map(value => ({ label: t(rateLimitAlgorithmLabelKey(value)), value })));
124
+ const statusOptions = computed<ProFormOption[]>(() => [
125
+ { label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
126
+ { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
127
+ ]);
128
+ const fields = computed<ProFormField[]>(() => [
129
+ { prop: "code", label: t("system.base.rate_limit_rule.field.code"), component: "input", props: { disabled: Boolean(form.id) } },
130
+ { prop: "name", label: t("system.base.rate_limit_rule.field.name"), component: "input" },
131
+ { prop: "rule_type", label: t("system.base.rate_limit_rule.field.rule_type"), labelTooltip: t(rateLimitAlgorithmTooltipKey(form.rule_type)), component: "select", options: algorithmOptions.value, props: { disabled: Boolean(form.id), onChange: handleAlgorithmChange } },
132
+ { prop: "parameters", label: t("system.base.rate_limit_rule.field.parameters"), labelTooltip: t("system.base.rate_limit_rule.tooltip.parameters"), component: "slot", slotName: "parameters", colSpan: 24 },
133
+ { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value },
134
+ { prop: "remark", label: t("common.field.remark"), component: "textarea" }
135
+ ]);
136
+ const rules = computed<FormRules>(() => ({
137
+ code: [{ required: true, message: t("system.base.rate_limit_rule.validation.code"), trigger: "blur" }],
138
+ name: [{ required: true, message: t("system.base.rate_limit_rule.validation.name"), trigger: "blur" }]
139
+ }));
140
+ const columns = computed<ColumnProps[]>(() => [
141
+ { type: "selection", width: 55 },
142
+ { prop: "code", label: t("system.base.rate_limit_rule.field.code"), minWidth: 190, search: { el: "input" } },
143
+ { prop: "name", label: t("system.base.rate_limit_rule.field.name"), minWidth: 190, search: { el: "input" } },
144
+ { prop: "rule_type", label: t("system.base.rate_limit_rule.field.rule_type"), width: 190, render: scope => algorithmLabel((scope.row as BaseRateLimitRule).rule_type) },
145
+ { prop: "default_params", label: t("system.base.rate_limit_rule.field.parameters"), minWidth: 260, render: scope => paramsSummary((scope.row as BaseRateLimitRule).rule_type, (scope.row as BaseRateLimitRule).default_params) },
146
+ {
147
+ prop: "status",
148
+ label: t("common.field.status"),
149
+ width: 100,
150
+ cellType: "status",
151
+ statusProps: {
152
+ activeValue: Status.STATUS_ENABLE,
153
+ inactiveValue: Status.STATUS_DISABLE,
154
+ activeText: t("common.status.enabled"),
155
+ inactiveText: t("common.status.disabled"),
156
+ disabled: () => !BUTTONS.value["base:rate-limit-rule:status"],
157
+ beforeChange: scope => changeStatus(scope.row as BaseRateLimitRule)
158
+ }
159
+ },
160
+ {
161
+ prop: "actions",
162
+ label: t("common.field.operation"),
163
+ cellType: "actions",
164
+ actions: [
165
+ { label: t("common.action.edit"), type: "primary", link: true, icon: EditPen, hidden: () => !BUTTONS.value["base:rate-limit-rule:update"], onClick: scope => openDialog((scope.row as BaseRateLimitRule).id) },
166
+ { label: t("common.action.delete"), type: "danger", link: true, icon: Delete, hidden: () => !BUTTONS.value["base:rate-limit-rule:delete"], onClick: scope => deleteItems(scope.row as BaseRateLimitRule) }
167
+ ]
168
+ }
169
+ ]);
170
+ const headerActions = computed<HeaderActionProps[]>(() => [
171
+ { label: t("common.action.create"), type: "success", icon: CirclePlus, hidden: () => !BUTTONS.value["base:rate-limit-rule:create"], onClick: () => openDialog() },
172
+ { label: t("common.action.delete"), type: "danger", icon: Delete, hidden: () => !BUTTONS.value["base:rate-limit-rule:delete"], disabled: scope => !scope.selectedList.length, onClick: scope => deleteItems(scope.selectedList as BaseRateLimitRule[]) }
173
+ ]);
174
+
175
+ /** 请求限流规则列表。 */
176
+ async function requestTable(params: PageBaseRateLimitRuleRequest) {
177
+ const data = await defBaseRateLimitRuleService.PageBaseRateLimitRule(buildPageRequest(params));
178
+ return { data: { list: data.base_rate_limit_rules ?? [], total: data.total } };
179
+ }
180
+
181
+ /** 打开新增或编辑限流规则弹窗。 */
182
+ async function openDialog(id?: number) {
183
+ await dialogRef.value?.open({
184
+ load: () => (id !== undefined ? defBaseRateLimitRuleService.GetBaseRateLimitRule({ id }) : undefined),
185
+ commit: data => {
186
+ resetForm();
187
+ if (data) Object.assign(form, data, { params: parseRateLimitParams(data.rule_type, data.default_params) });
188
+ dialog.titleKey = id !== undefined ? "common.action.edit_resource" : "common.action.create_resource";
189
+ }
190
+ });
191
+ }
192
+
193
+ /** 重置限流规则表单。 */
194
+ function resetForm() {
195
+ dialog.visible = false;
196
+ dialogRef.value?.resetFields();
197
+ Object.assign(form, defaultForm());
198
+ }
199
+
200
+ /** 校验并保存限流规则模板。 */
201
+ async function submit() {
202
+ const params = serializeRateLimitParams(form.rule_type, form.params);
203
+ if (!params) {
204
+ ElMessage.warning(t("system.base.rate_limit_rule.validation.parameters"));
205
+ return;
206
+ }
207
+ form.default_params = JSON.stringify(params);
208
+ const valid = await dialogRef.value?.validate();
209
+ if (!valid) return;
210
+ const payload: BaseRateLimitRuleForm = {
211
+ id: form.id,
212
+ code: form.code,
213
+ name: form.name,
214
+ rule_type: form.rule_type,
215
+ default_params: form.default_params,
216
+ status: form.status,
217
+ remark: form.remark
218
+ };
219
+ if (form.id) await defBaseRateLimitRuleService.UpdateBaseRateLimitRule({ base_rate_limit_rule: payload });
220
+ else await defBaseRateLimitRuleService.CreateBaseRateLimitRule({ base_rate_limit_rule: payload });
221
+ ElMessage.success(t(form.id ? "common.message.update_success" : "common.message.create_success", { resource: t("system.base.rate_limit_rule.title") }));
222
+ resetForm();
223
+ table.value?.getTableList();
224
+ }
225
+
226
+ /** 确认并切换限流规则状态。 */
227
+ async function changeStatus(row: BaseRateLimitRule) {
228
+ const next = row.status === Status.STATUS_ENABLE ? Status.STATUS_DISABLE : Status.STATUS_ENABLE;
229
+ try {
230
+ await ElMessageBox.confirm(
231
+ t("common.dialog.status_change", {
232
+ action: t(next === Status.STATUS_ENABLE ? "common.status.enabled" : "common.status.disabled"),
233
+ resource: t("system.base.rate_limit_rule.title"),
234
+ field: t("system.base.rate_limit_rule.field.code"),
235
+ value: row.code
236
+ }),
237
+ t("common.title.warning"),
238
+ { type: "warning" }
239
+ );
240
+ await defBaseRateLimitRuleService.SetBaseRateLimitRuleStatus({ id: row.id, status: next });
241
+ table.value?.getTableList();
242
+ return true;
243
+ } catch {
244
+ return false;
245
+ }
246
+ }
247
+
248
+ /** 删除未被接口策略引用的限流规则。 */
249
+ async function deleteItems(selected?: BaseRateLimitRule | BaseRateLimitRule[] | number | string | Array<number | string>) {
250
+ const items = Array.isArray(selected) ? selected.filter((item): item is BaseRateLimitRule => typeof item === "object") : selected && typeof selected === "object" ? [selected] : [];
251
+ const ids = items.length ? items.map(item => item.id) : normalizeSelectedIds(selected as number | string | Array<number | string>);
252
+ if (!ids.length) {
253
+ ElMessage.warning(t("common.message.select_delete_item"));
254
+ return;
255
+ }
256
+ try {
257
+ await ElMessageBox.confirm(t("common.dialog.delete_selected", { resource: t("system.base.rate_limit_rule.title") }), t("common.title.warning"), { type: "warning" });
258
+ await defBaseRateLimitRuleService.DeleteBaseRateLimitRule({ id: ids.join(",") });
259
+ ElMessage.success(t("common.message.delete_success", { resource: t("system.base.rate_limit_rule.title") }));
260
+ table.value?.getTableList();
261
+ } catch {
262
+ return;
263
+ }
264
+ }
265
+
266
+ /** 格式化规则参数摘要。 */
267
+ function paramsSummary(algorithm: BaseRateLimitAlgorithm, raw: string) {
268
+ return t(rateLimitSummaryKey(algorithm), rateLimitSummaryParams(algorithm, raw));
269
+ }
270
+
271
+ /** 返回限流算法显示名称。 */
272
+ function algorithmLabel(algorithm: BaseRateLimitAlgorithm) { return t(rateLimitAlgorithmLabelKey(algorithm)); }
273
+
274
+ /** 切换算法时清空其他算法的参数。 */
275
+ function handleAlgorithmChange(algorithm: BaseRateLimitAlgorithm) { form.params = defaultRateLimitParams(algorithm); }
276
+
277
+ /** 返回限流规则表单初始值。 */
278
+ function defaultForm(): RuleFormState {
279
+ const rule_type = BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_TOKEN_BUCKET;
280
+ return { id: 0, code: "", name: "", rule_type, default_params: "", status: Status.STATUS_ENABLE, remark: "", params: defaultRateLimitParams(rule_type) };
281
+ }
282
+ </script>
283
+
284
+ <style scoped>
285
+ .parameter-grid {
286
+ display: grid;
287
+ grid-template-columns: repeat(2, minmax(0, 1fr));
288
+ gap: 12px;
289
+ }
290
+
291
+ .parameter-item {
292
+ display: flex;
293
+ align-items: center;
294
+ gap: 8px;
295
+ min-width: 0;
296
+ }
297
+
298
+ .parameter-label {
299
+ display: inline-flex;
300
+ flex: none;
301
+ align-items: center;
302
+ gap: 4px;
303
+ color: var(--el-text-color-regular);
304
+ font-size: 12px;
305
+ }
306
+
307
+ .parameter-help {
308
+ color: var(--el-text-color-placeholder);
309
+ cursor: help;
310
+ }
311
+
312
+ .parameter-item :deep(.el-input-number) {
313
+ width: 100%;
314
+ min-width: 0;
315
+ }
316
+
317
+ @media (max-width: 760px) {
318
+ .parameter-grid {
319
+ grid-template-columns: minmax(0, 1fr);
320
+ }
321
+ }
322
+ </style>
@@ -282,7 +282,7 @@ async function requestApis() {
282
282
  /** 加载脱敏规则选项。 */
283
283
  async function loadRules() { const rules = await requestRules(); ruleCatalog.value = rules.catalog; ruleOptions.value = rules.options; }
284
284
  /** 请求脱敏规则选项。 */
285
- async function requestRules() { const data = await defBaseRedactRuleService.PageBaseRedactRule({ code: "", name: "", rule_type: "", page_num: 1, page_size: 100 }); const catalog = data.base_redact_rules ?? []; return { catalog, options: catalog.map(item => ({ label: `${item.name} (${item.code})`, value: item.id, disabled: item.status !== Status.STATUS_ENABLE })) }; }
285
+ async function requestRules() { const data = await defBaseRedactRuleService.PageBaseRedactRule({ code: "", name: "", rule_type: "", page_num: 1, page_size: 100 }); const catalog = (data.base_redact_rules ?? []).filter(item => item.rule_type !== "ENCRYPT"); return { catalog, options: catalog.map(item => ({ label: `${item.name} (${item.code})`, value: item.id, disabled: item.status !== Status.STATUS_ENABLE })) }; }
286
286
  /** 服务变更后清空接口和返回字段。 */
287
287
  function handleServiceChange(serviceName?: string) { responseFieldsRequestRevision += 1; form.service_name = serviceName ?? ""; form.api_id = undefined; form.operation = ""; form.message_ref = ""; form.field_path = ""; form.field_rows = []; }
288
288
  /** API 变更后重新加载返回字段。 */
@@ -103,6 +103,15 @@
103
103
  <el-input v-model="form.params.char" maxlength="8" />
104
104
  </div>
105
105
  </div>
106
+ <div v-else-if="form.rule_type === 'ENCRYPT'" class="parameter-grid parameter-grid--single">
107
+ <div class="parameter-item parameter-item--wide">
108
+ <span>{{ t("system.base.redact_rule.parameter.algo") }}</span>
109
+ <el-select v-model="form.params.algorithm" class="parameter-control">
110
+ <el-option label="AES-GCM" value="AES_GCM" />
111
+ <el-option label="SM4-GCM" value="SM4_GCM" />
112
+ </el-select>
113
+ </div>
114
+ </div>
106
115
  <div v-else class="rule-empty">{{ t("system.base.redact_rule.message.no_parameters") }}</div>
107
116
  </div>
108
117
  </template>
@@ -141,6 +150,7 @@ interface RuleParams {
141
150
  keep_octets?: number;
142
151
  mask_query?: boolean;
143
152
  char?: string;
153
+ algorithm?: string;
144
154
  }
145
155
 
146
156
  interface RuleFormState extends BaseRedactRuleForm {
@@ -159,7 +169,7 @@ const statusOptions = computed(() => [
159
169
  { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
160
170
  ]);
161
171
  /** 运行时支持的规则类型选项。 */
162
- const ruleTypeOptions = ["MASK", "EMAIL", "REGEX", "TRUNCATE", "HASH", "UUID", "IP", "URL", "FIXED_LENGTH"].map(value => ({ label: value, value }));
172
+ const ruleTypeOptions = ["MASK", "EMAIL", "REGEX", "TRUNCATE", "HASH", "UUID", "IP", "URL", "FIXED_LENGTH", "ENCRYPT"].map(value => ({ label: value, value }));
163
173
  const fields = computed<ProFormField[]>(() => [
164
174
  { prop: "code", label: t("system.base.redact_rule.field.code"), component: "input", props: { disabled: Boolean(form.id) } },
165
175
  { prop: "name", label: t("system.base.redact_rule.field.name"), component: "input", props: { disabled: Boolean(form.id) } },
@@ -302,7 +312,7 @@ function syncRule() {
302
312
  /** 切换规则类型时重置参数。 */
303
313
  function handleRuleTypeChange(ruleType?: string) {
304
314
  form.rule_type = ruleType ?? "";
305
- form.params = {};
315
+ form.params = ruleType === "ENCRYPT" ? { algorithm: "AES_GCM" } : {};
306
316
  }
307
317
 
308
318
  /** 解析数据库规则 JSON 中当前类型的参数。 */
@@ -72,6 +72,9 @@
72
72
  <template v-else-if="row.rule_type === 'FIXED_LENGTH'">
73
73
  <ParameterText v-model="row.params.char" :label="t('system.base.redact_rule.parameter.char')" />
74
74
  </template>
75
+ <template v-else-if="row.rule_type === 'ENCRYPT'">
76
+ <div class="parameter-item"><span>{{ t("system.base.redact_rule.parameter.algo") }}</span><el-select v-model="row.params.algorithm" class="parameter-control" size="small"><el-option label="AES-GCM" value="AES_GCM" /><el-option label="SM4-GCM" value="SM4_GCM" /></el-select></div>
77
+ </template>
75
78
  </div>
76
79
  <span v-else class="empty-value">--</span>
77
80
  </template>
@@ -117,6 +120,7 @@ interface RuleParams {
117
120
  keep_octets?: number;
118
121
  mask_query?: boolean;
119
122
  char?: string;
123
+ algorithm?: string;
120
124
  }
121
125
 
122
126
  /** 入库字段表格行。 */
@@ -404,9 +404,9 @@ function handleCloseCredentialsDialog() {
404
404
  /** 复制租户编号、管理员账号和初始密码。 */
405
405
  async function handleCopyCredentials() {
406
406
  const content = [
407
- `${t("system.base.tenant.field.code")}:${credentialsDialog.tenant_code}`,
408
- `${t("system.base.user.field.user_name")}:${credentialsDialog.admin_user_name}`,
409
- `${t("system.base.user.field.password")}:${credentialsDialog.initial_password}`
407
+ `${t("system.base.tenant.field.code")}: ${credentialsDialog.tenant_code}`,
408
+ `${t("system.base.user.field.user_name")}: ${credentialsDialog.admin_user_name}`,
409
+ `${t("system.base.user.field.password")}: ${credentialsDialog.initial_password}`
410
410
  ].join("\n");
411
411
  await copyText(content);
412
412
  ElMessage.success(t("core.clipboard.success"));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@liujitcn/kratos-admin-system",
3
3
  "private": false,
4
- "version": "0.0.61",
4
+ "version": "0.0.64",
5
5
  "type": "module",
6
6
  "description": "kratos-admin system management module",
7
7
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "sortablejs": "^1.15.2",
17
17
  "swagger-ui-dist": "^5.32.15",
18
18
  "vue-element-plus-x": "^2.0.3",
19
- "@liujitcn/kratos-admin-core": "0.0.61"
19
+ "@liujitcn/kratos-admin-core": "0.0.64"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@element-plus/icons-vue": "^2.3.1",