@liujitcn/kratos-admin-system 0.0.64 → 0.0.66

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 (50) hide show
  1. package/README.md +5 -3
  2. package/dist/package/declarations/src/api/base/v1/ai_knowledge.d.ts +7 -0
  3. package/dist/package/declarations/src/api/system/admin/v1/ai_provider.d.ts +5 -1
  4. package/dist/package/declarations/src/api/system/admin/v1/ai_query.d.ts +10 -0
  5. package/dist/package/declarations/src/api/system/admin/v1/ai_session.d.ts +9 -0
  6. package/dist/package/declarations/src/locales/generated.d.ts +1405 -1089
  7. package/dist/package/declarations/src/rpc/base/v1/ai_knowledge.d.ts +22 -0
  8. package/dist/package/declarations/src/rpc/base/v1/ai_message.d.ts +2 -0
  9. package/dist/package/declarations/src/rpc/base/v1/ai_provider.d.ts +13 -6
  10. package/dist/package/declarations/src/rpc/system/admin/v1/ai_provider.d.ts +85 -4
  11. package/dist/package/declarations/src/rpc/system/admin/v1/ai_query.d.ts +73 -0
  12. package/dist/package/declarations/src/rpc/system/admin/v1/ai_session.d.ts +114 -0
  13. package/dist/package/declarations/src/views/ai/chat/components/ChatPanel.vue.d.ts +9 -2
  14. package/dist/package/declarations/src/views/ai/chat/components/XSender.vue.d.ts +7 -0
  15. package/dist/package/declarations/src/views/ai/chat/modelDisplay.d.ts +5 -0
  16. package/dist/package/declarations/src/views/ai/chat/modelSelection.d.ts +9 -0
  17. package/dist/package/declarations/src/views/ai/query/index.vue.d.ts +3 -0
  18. package/dist/package/declarations/src/views/ai/session/index.vue.d.ts +3 -0
  19. package/dist/package/src/api/base/v1/ai_knowledge.ts +22 -0
  20. package/dist/package/src/api/system/admin/v1/ai_provider.ts +14 -0
  21. package/dist/package/src/api/system/admin/v1/ai_query.ts +25 -0
  22. package/dist/package/src/api/system/admin/v1/ai_session.ts +25 -0
  23. package/dist/package/src/components/account/ChangePasswordForm.vue +1 -1
  24. package/dist/package/src/components/tenant-project/TenantProjectSelect.vue +21 -4
  25. package/dist/package/src/locales/en-US.json +351 -272
  26. package/dist/package/src/locales/ja-JP.json +351 -272
  27. package/dist/package/src/locales/zh-CN.json +361 -282
  28. package/dist/package/src/locales/zh-TW.json +351 -272
  29. package/dist/package/src/rpc/base/v1/ai_knowledge.ts +33 -0
  30. package/dist/package/src/rpc/base/v1/ai_message.ts +2 -0
  31. package/dist/package/src/rpc/base/v1/ai_provider.ts +14 -6
  32. package/dist/package/src/rpc/system/admin/v1/ai_provider.ts +93 -4
  33. package/dist/package/src/rpc/system/admin/v1/ai_query.ts +89 -0
  34. package/dist/package/src/rpc/system/admin/v1/ai_session.ts +131 -0
  35. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +22 -1
  36. package/dist/package/src/views/ai/chat/components/XSender.vue +367 -71
  37. package/dist/package/src/views/ai/chat/index.vue +46 -8
  38. package/dist/package/src/views/ai/chat/modelDisplay.ts +67 -0
  39. package/dist/package/src/views/ai/chat/modelSelection.ts +31 -0
  40. package/dist/package/src/views/ai/query/index.vue +222 -0
  41. package/dist/package/src/views/ai/session/index.vue +422 -0
  42. package/dist/package/src/views/base/ai-provider/index.vue +301 -154
  43. package/dist/package/src/views/base/api-rate-limit-policy/index.vue +4 -3
  44. package/dist/package/src/views/base/message-provider/index.vue +9 -5
  45. package/dist/package/src/views/base/message-template/index.vue +2 -2
  46. package/dist/package/src/views/base/oauth-provider/index.vue +2 -2
  47. package/dist/package/src/views/base/rate-limit-rule/index.vue +8 -3
  48. package/dist/package/src/views/base/tenant-project-grant/index.vue +9 -4
  49. package/dist/package/src/views/tool/code-gen/config.ts +1 -0
  50. package/package.json +2 -2
@@ -30,7 +30,7 @@
30
30
  <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
31
31
  </el-tooltip>
32
32
  </span>
33
- <el-input-number v-model="form.params.tokens_per_second" :min="0" :max="1000000" :precision="3" :step="1" controls-position="right" />
33
+ <el-input-number v-model="form.params.tokens_per_second" :min="0.001" :max="1000000" :precision="3" :step="1" controls-position="right" />
34
34
  </div>
35
35
  <div class="parameter-item">
36
36
  <span class="parameter-label">
@@ -39,7 +39,7 @@
39
39
  <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
40
40
  </el-tooltip>
41
41
  </span>
42
- <el-input-number v-model="form.params.burst" :min="0" :max="1000000" :precision="0" controls-position="right" />
42
+ <el-input-number v-model="form.params.burst" :min="1" :max="1000000" :precision="0" controls-position="right" />
43
43
  </div>
44
44
  </div>
45
45
  <div v-else-if="windowedAlgorithms.includes(form.rule_type)" class="parameter-grid">
@@ -262,7 +262,8 @@ function resetForm() {
262
262
  /** 根据所选模板加载默认参数。 */
263
263
  function handleRuleChange(ruleId?: number) {
264
264
  const selected = ruleCatalog.value.find(rule => rule.id === Number(ruleId));
265
- form.rule_type = selected?.rule_type ?? BaseRateLimitAlgorithm.BASE_RATE_LIMIT_ALGORITHM_UNSPECIFIED;
265
+ // 模板缺失时保留当前算法类型,避免编辑态参数区空白导致无法保存。
266
+ if (selected) form.rule_type = selected.rule_type;
266
267
  form.params = selected ? parseRateLimitParams(form.rule_type, selected.default_params) : defaultRateLimitParams(form.rule_type);
267
268
  }
268
269
 
@@ -59,8 +59,8 @@ const statusOptions = computed<ProFormOption[]>(() => [
59
59
  ]);
60
60
 
61
61
  const rules = computed(() => ({
62
- provider: [{ required: true, message: t("system.base.message_provider.placeholder.provider"), trigger: "blur" }],
63
- name: [{ required: true, message: t("system.base.message_provider.placeholder.name"), trigger: "blur" }]
62
+ provider: [{ required: true, message: t("system.base.message_provider.validation.provider"), trigger: "blur" }],
63
+ name: [{ required: true, message: t("system.base.message_provider.validation.name"), trigger: "blur" }]
64
64
  }));
65
65
 
66
66
  const formFields = computed<ProFormField[]>(() => [
@@ -68,8 +68,8 @@ const formFields = computed<ProFormField[]>(() => [
68
68
  { prop: "name", label: t("system.base.message_provider.field.name"), component: "input", props: { maxlength: 50 } },
69
69
  { prop: "description", label: t("system.base.message_provider.field.description"), component: "input", colSpan: 24, props: { maxlength: 255 } },
70
70
  { prop: "icon", label: t("system.base.message_provider.field.icon"), component: "input", props: { maxlength: 100 } },
71
- { prop: "client_id", label: t("system.base.message_provider.field.client_id"), component: "input", props: { maxlength: 255 } },
72
- { prop: "client_secret", label: t("system.base.message_provider.field.client_secret"), component: "input", props: { type: "password", showPassword: true, maxlength: 1024, placeholder: dialog.editing ? t("system.base.message_provider.placeholder.keep_secret") : "" } },
71
+ { prop: "client_id", label: t("system.base.message_provider.field.client_id"), component: "input", props: { maxlength: 255, autocomplete: "off" } },
72
+ { prop: "client_secret", label: t("system.base.message_provider.field.client_secret"), component: "input", props: { type: "password", showPassword: true, maxlength: 1024, autocomplete: "new-password", placeholder: dialog.editing ? t("system.base.message_provider.placeholder.keep_secret") : "" } },
73
73
  { prop: "config_items", label: t("system.base.message_provider.field.config"), component: "kv-list", props: { keyInputProps: { maxlength: 128 } } },
74
74
  { prop: "sort", label: t("common.field.sort"), component: "input-number", props: { min: 0, precision: 0 } },
75
75
  { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
@@ -131,7 +131,11 @@ async function handleSubmit() {
131
131
  async function handleDelete(value: BaseMessageProvider | number | number[]) {
132
132
  const ids = (Array.isArray(value) ? value : typeof value === "object" ? [value.id] : normalizeSelectedIds(value)).join(",");
133
133
  if (!ids) return;
134
- await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" });
134
+ try {
135
+ await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" });
136
+ } catch {
137
+ return;
138
+ }
135
139
  await defBaseMessageProviderService.DeleteBaseMessageProvider({ id: ids });
136
140
  await proTable.value?.getTableList();
137
141
  ElMessage.success(t("common.message.operation_success"));
@@ -60,7 +60,7 @@ const contentFormatOptions = computed<ProFormOption[]>(() => [
60
60
  ]);
61
61
  const categoryOptions = computed<ProFormOption[]>(() => categories.value.map(item => ({ label: item.name, value: item.id })));
62
62
  const providerOptions = computed<ProFormOption[]>(() => providers.value.map(item => ({ label: item.name, value: item.id, disabled: item.status !== 1 })));
63
- const rules = computed(() => ({ category_id: [{ required: true, message: t("system.base.message_template.placeholder.category"), trigger: "change" }], provider_id: [{ required: true, message: t("system.base.message_template.placeholder.provider"), trigger: "change" }], title: [{ required: true, message: t("system.base.message_template.placeholder.title"), trigger: "blur" }] }));
63
+ const rules = computed(() => ({ category_id: [{ required: true, message: t("system.base.message_template.validation.category"), trigger: "change" }], provider_id: [{ required: true, message: t("system.base.message_template.validation.provider"), trigger: "change" }], title: [{ required: true, message: t("system.base.message_template.validation.title"), trigger: "blur" }] }));
64
64
  const formFields = computed<ProFormField[]>(() => [
65
65
  { prop: "category_id", label: t("system.base.message_template.field.category"), component: "select", options: categoryOptions.value, props: { disabled: dialog.editing, filterable: true } },
66
66
  { prop: "provider_id", label: t("system.base.message_template.field.provider"), component: "select", options: providerOptions.value, props: { disabled: dialog.editing, filterable: true } },
@@ -97,7 +97,7 @@ async function loadOptions() {
97
97
  async function requestTable(params: Record<string, unknown>) { const data = await defBaseMessageTemplateService.PageBaseMessageTemplate(buildPageRequest<PageBaseMessageTemplateRequest>(params as unknown as PageBaseMessageTemplateRequest)); return { data: { list: data.base_message_templates ?? [], total: data.total } }; }
98
98
  async function openDialog(id?: number) { await loadOptions(); await formDialogRef.value?.open({ load: () => (id ? defBaseMessageTemplateService.GetBaseMessageTemplate({ id }) : undefined), commit: data => { Object.assign(formData, defaultForm(), data ?? {}); dialog.editing = Boolean(id); formData.config_items = configToItems(formData.config); } }); }
99
99
  async function handleSubmit() { if (!(await formDialogRef.value?.validate())) return; const config = configItemsToMap(formData.config_items); if (!config) return; const payload = JSON.parse(JSON.stringify(formData)) as BaseMessageTemplateForm & { config_items?: ConfigItem[] }; delete payload.config_items; payload.config = config; if (payload.id) await defBaseMessageTemplateService.UpdateBaseMessageTemplate({ base_message_template: payload }); else await defBaseMessageTemplateService.CreateBaseMessageTemplate({ base_message_template: payload }); ElMessage.success(t("common.message.operation_success")); dialog.visible = false; await proTable.value?.getTableList(); }
100
- async function handleDelete(value: BaseMessageTemplate | number | number[]) { const ids = (Array.isArray(value) ? value : typeof value === "object" ? [value.id] : normalizeSelectedIds(value)).join(","); if (!ids) return; await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" }); await defBaseMessageTemplateService.DeleteBaseMessageTemplate({ id: ids }); await proTable.value?.getTableList(); ElMessage.success(t("common.message.operation_success")); }
100
+ async function handleDelete(value: BaseMessageTemplate | number | number[]) { const ids = (Array.isArray(value) ? value : typeof value === "object" ? [value.id] : normalizeSelectedIds(value)).join(","); if (!ids) return; try { await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" }); } catch { return; } await defBaseMessageTemplateService.DeleteBaseMessageTemplate({ id: ids }); await proTable.value?.getTableList(); ElMessage.success(t("common.message.operation_success")); }
101
101
  function handleClose() { Object.assign(formData, defaultForm()); formDialogRef.value?.resetFields(); }
102
102
  function contentFormatLabel(value: MessageContentFormat) { return contentFormatOptions.value.find(item => item.value === value)?.label ?? ""; }
103
103
  function configToItems(config: Record<string, any> | undefined): ConfigItem[] { return Object.entries(config ?? {}).map(([key, value]) => ({ key, value: typeof value === "string" ? value : JSON.stringify(value) })); }
@@ -102,8 +102,8 @@ const formFields = computed<ProFormField[]>(() => [
102
102
  { prop: "name", suffixSlotName: "nameI18ns", label: t("system.base.oauth_provider.field.name"), component: "input", colSpan: 12, props: { maxlength: 50, placeholder: t("system.base.oauth_provider.placeholder.name") } },
103
103
  { prop: "description", suffixSlotName: "descriptionI18ns", label: t("system.base.oauth_provider.field.description"), component: "input", colSpan: 24, props: { maxlength: 255, placeholder: t("system.base.oauth_provider.placeholder.description") } },
104
104
  { prop: "icon", label: t("system.base.oauth_provider.field.icon"), component: "input", colSpan: 12, props: { maxlength: 255, placeholder: t("system.base.oauth_provider.placeholder.icon") } },
105
- { prop: "client_id", label: t("system.base.oauth_provider.field.client_id"), component: "input", colSpan: 12, props: { maxlength: 255, placeholder: t("system.base.oauth_provider.placeholder.client_id") } },
106
- { prop: "client_secret", label: t("system.base.oauth_provider.field.client_secret"), component: "input", colSpan: 12, props: { type: "password", showPassword: true, maxlength: 512, placeholder: dialog.editing ? t("system.base.oauth_provider.placeholder.keep_secret") : t("system.base.oauth_provider.placeholder.client_secret") } },
105
+ { prop: "client_id", label: t("system.base.oauth_provider.field.client_id"), component: "input", colSpan: 12, props: { maxlength: 255, autocomplete: "off", placeholder: t("system.base.oauth_provider.placeholder.client_id") } },
106
+ { prop: "client_secret", label: t("system.base.oauth_provider.field.client_secret"), component: "input", colSpan: 12, props: { type: "password", showPassword: true, maxlength: 512, autocomplete: "new-password", placeholder: dialog.editing ? t("system.base.oauth_provider.placeholder.keep_secret") : t("system.base.oauth_provider.placeholder.client_secret") } },
107
107
  { prop: "redirect_uri", label: t("system.base.oauth_provider.field.redirect_uri"), component: "input", colSpan: 12, props: { maxlength: 512, placeholder: t("system.base.oauth_provider.placeholder.redirect_uri") } },
108
108
  { prop: "scopes", label: t("system.base.oauth_provider.field.scopes"), component: "dynamic-list", colSpan: 12, props: { inputProps: { maxlength: 128, placeholder: t("system.base.oauth_provider.placeholder.scopes") } } },
109
109
  { prop: "config_items", label: t("system.base.oauth_provider.field.config"), component: "kv-list", colSpan: 12, props: { keyInputProps: { maxlength: 128 } } },
@@ -21,7 +21,7 @@
21
21
  <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
22
22
  </el-tooltip>
23
23
  </span>
24
- <el-input-number v-model="form.params.tokens_per_second" :min="0" :max="1000000" :precision="3" :step="1" controls-position="right" />
24
+ <el-input-number v-model="form.params.tokens_per_second" :min="0.001" :max="1000000" :precision="3" :step="1" controls-position="right" />
25
25
  </div>
26
26
  <div class="parameter-item">
27
27
  <span class="parameter-label">
@@ -30,7 +30,7 @@
30
30
  <el-icon class="parameter-help" tabindex="0"><QuestionFilled /></el-icon>
31
31
  </el-tooltip>
32
32
  </span>
33
- <el-input-number v-model="form.params.burst" :min="0" :max="1000000" :precision="0" controls-position="right" />
33
+ <el-input-number v-model="form.params.burst" :min="1" :max="1000000" :precision="0" controls-position="right" />
34
34
  </div>
35
35
  </div>
36
36
  <div v-else-if="windowedAlgorithms.includes(form.rule_type)" class="parameter-grid">
@@ -125,10 +125,15 @@ const statusOptions = computed<ProFormOption[]>(() => [
125
125
  { label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
126
126
  { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
127
127
  ]);
128
+ /** 当前算法说明提示,未选择算法时为空避免渲染空 tooltip。 */
129
+ const ruleTypeTooltip = computed(() => {
130
+ const key = rateLimitAlgorithmTooltipKey(form.rule_type);
131
+ return key ? t(key) : undefined;
132
+ });
128
133
  const fields = computed<ProFormField[]>(() => [
129
134
  { prop: "code", label: t("system.base.rate_limit_rule.field.code"), component: "input", props: { disabled: Boolean(form.id) } },
130
135
  { 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 } },
136
+ { prop: "rule_type", label: t("system.base.rate_limit_rule.field.rule_type"), labelTooltip: ruleTypeTooltip.value, component: "select", options: algorithmOptions.value, props: { disabled: Boolean(form.id), onChange: handleAlgorithmChange } },
132
137
  { 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
138
  { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value },
134
139
  { prop: "remark", label: t("common.field.remark"), component: "textarea" }
@@ -150,9 +150,12 @@ const columns = computed<ColumnProps[]>(() => [
150
150
  showOverflowTooltip: true,
151
151
  render: scope => {
152
152
  const row = scope.row as BaseTenantProjectGrant;
153
- return row.project_id.length === 1 && row.project_id[0] === 0
153
+ // proto3 JSON 会省略空数组字段,project_id / project_names 可能为 undefined。
154
+ const projectIds = row.project_id ?? [];
155
+ const projectNames = row.project_names ?? [];
156
+ return projectIds.length === 1 && projectIds[0] === 0
154
157
  ? t("system.base.tenant_project_grant.all_projects")
155
- : row.project_names.join(", ") || row.project_id.join(", ") || t("common.value.none");
158
+ : projectNames.join(", ") || projectIds.join(", ") || t("common.value.none");
156
159
  }
157
160
  },
158
161
  {
@@ -213,12 +216,14 @@ async function handleOpenDialog(row?: BaseTenantProjectGrant) {
213
216
  await formDialogRef.value?.open({
214
217
  load: async () => {
215
218
  await loadTenantOptions(true);
219
+ // proto3 JSON 会省略空数组字段,行数据里的 project_id 可能为 undefined。
220
+ const rowProjectIds = row?.project_id ?? [];
216
221
  const nextForm = {
217
222
  tenant_id: row?.tenant_id ?? (isDefaultTenant.value ? undefined : Number(tenantOptions.value[0]?.value) || undefined),
218
223
  subject_type: row?.subject_type ?? DEFAULT_SUBJECT_TYPE,
219
224
  subject_id: row?.subject_id,
220
- project_id: row && !(row.project_id.length === 1 && row.project_id[0] === 0) ? [...row.project_id] : [],
221
- all: Boolean(row && row.project_id.length === 1 && row.project_id[0] === 0)
225
+ project_id: row && !(rowProjectIds.length === 1 && rowProjectIds[0] === 0) ? [...rowProjectIds] : [],
226
+ all: Boolean(row && rowProjectIds.length === 1 && rowProjectIds[0] === 0)
222
227
  } satisfies ProjectGrantFormState;
223
228
  const [projects, subjects] = await Promise.all([
224
229
  requestProjectOptions(nextForm.tenant_id),
@@ -74,6 +74,7 @@ const codeGenFormComponentLabelKeys: Record<ProFormComponentType, string> = {
74
74
  input: "system.code.gen.component.input",
75
75
  password: "system.code.gen.component.password",
76
76
  textarea: "system.code.gen.component.textarea",
77
+ "yaml-editor": "system.code.gen.component.yaml_editor",
77
78
  "input-number": "system.code.gen.component.input_number",
78
79
  "color-picker": "system.code.gen.component.color_picker",
79
80
  segmented: "system.code.gen.component.segmented",
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.64",
4
+ "version": "0.0.66",
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.64"
19
+ "@liujitcn/kratos-admin-core": "0.0.66"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@element-plus/icons-vue": "^2.3.1",