@liujitcn/kratos-admin-system 0.0.59 → 0.0.60

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.
@@ -1577,6 +1577,8 @@ export declare const LOCALE_MESSAGES: {
1577
1577
  "system.base.i18n_custom.placeholder.remark": string;
1578
1578
  "system.base.i18n_custom.message.confirm_status": string;
1579
1579
  "system.base.i18n_custom.message.confirm_delete": string;
1580
+ "system.dashboard.last_7_days": string;
1581
+ "system.dashboard.total": string;
1580
1582
  };
1581
1583
  readonly 'en-US': {
1582
1584
  "system.base.config.tab.basic": string;
@@ -3156,6 +3158,8 @@ export declare const LOCALE_MESSAGES: {
3156
3158
  "system.base.i18n_custom.placeholder.remark": string;
3157
3159
  "system.base.i18n_custom.message.confirm_status": string;
3158
3160
  "system.base.i18n_custom.message.confirm_delete": string;
3161
+ "system.dashboard.last_7_days": string;
3162
+ "system.dashboard.total": string;
3159
3163
  };
3160
3164
  readonly 'ja-JP': {
3161
3165
  "system.base.config.tab.basic": string;
@@ -4735,6 +4739,8 @@ export declare const LOCALE_MESSAGES: {
4735
4739
  "system.base.i18n_custom.placeholder.remark": string;
4736
4740
  "system.base.i18n_custom.message.confirm_status": string;
4737
4741
  "system.base.i18n_custom.message.confirm_delete": string;
4742
+ "system.dashboard.last_7_days": string;
4743
+ "system.dashboard.total": string;
4738
4744
  };
4739
4745
  readonly 'zh-TW': {
4740
4746
  "system.base.config.tab.basic": string;
@@ -6314,6 +6320,8 @@ export declare const LOCALE_MESSAGES: {
6314
6320
  "system.base.i18n_custom.placeholder.remark": string;
6315
6321
  "system.base.i18n_custom.message.confirm_status": string;
6316
6322
  "system.base.i18n_custom.message.confirm_delete": string;
6323
+ "system.dashboard.last_7_days": string;
6324
+ "system.dashboard.total": string;
6317
6325
  };
6318
6326
  };
6319
6327
  export type GeneratedLocale = keyof typeof LOCALE_MESSAGES;
@@ -186,7 +186,9 @@ function openAction() {
186
186
 
187
187
  /** 解析收件箱分类图标,未知图标使用默认图标。 */
188
188
  function resolveNotificationIcon(icon: string) {
189
- return notificationIcons[icon as keyof typeof notificationIcons] ?? CollectionTag;
189
+ // 使用自有属性判定,避免原型链上的属性(如 constructor)被误判为合法图标键。
190
+ if (!Object.hasOwn(notificationIcons, icon)) return CollectionTag;
191
+ return notificationIcons[icon as keyof typeof notificationIcons];
190
192
  }
191
193
  </script>
192
194
 
@@ -1575,5 +1575,7 @@
1575
1575
  "system.base.i18n_custom.placeholder.value": "Enter custom text",
1576
1576
  "system.base.i18n_custom.placeholder.remark": "Enter a remark",
1577
1577
  "system.base.i18n_custom.message.confirm_status": "Are you sure you want to {action} \"{name}\"?",
1578
- "system.base.i18n_custom.message.confirm_delete": "Are you sure you want to delete custom translation \"{name}\"?"
1578
+ "system.base.i18n_custom.message.confirm_delete": "Are you sure you want to delete custom translation \"{name}\"?",
1579
+ "system.dashboard.last_7_days": "Last 7 days",
1580
+ "system.dashboard.total": "Total {count}"
1579
1581
  }
@@ -1575,5 +1575,7 @@
1575
1575
  "system.base.i18n_custom.placeholder.value": "カスタム文言を入力してください",
1576
1576
  "system.base.i18n_custom.placeholder.remark": "備考を入力してください",
1577
1577
  "system.base.i18n_custom.message.confirm_status": "「{name}」を{action}しますか?",
1578
- "system.base.i18n_custom.message.confirm_delete": "カスタム翻訳「{name}」を削除しますか?"
1578
+ "system.base.i18n_custom.message.confirm_delete": "カスタム翻訳「{name}」を削除しますか?",
1579
+ "system.dashboard.last_7_days": "直近7日間",
1580
+ "system.dashboard.total": "合計 {count}"
1579
1581
  }
@@ -1575,5 +1575,7 @@
1575
1575
  "system.base.i18n_custom.placeholder.value": "请输入自定义文案",
1576
1576
  "system.base.i18n_custom.placeholder.remark": "请输入备注",
1577
1577
  "system.base.i18n_custom.message.confirm_status": "确定将“{name}”{action}吗?",
1578
- "system.base.i18n_custom.message.confirm_delete": "确定删除自定义翻译“{name}”吗?"
1578
+ "system.base.i18n_custom.message.confirm_delete": "确定删除自定义翻译“{name}”吗?",
1579
+ "system.dashboard.last_7_days": "近 7 天",
1580
+ "system.dashboard.total": "总计 {count}"
1579
1581
  }
@@ -1575,5 +1575,7 @@
1575
1575
  "system.base.i18n_custom.placeholder.value": "請輸入自訂文案",
1576
1576
  "system.base.i18n_custom.placeholder.remark": "請輸入備註",
1577
1577
  "system.base.i18n_custom.message.confirm_status": "確定要將「{name}」{action}嗎?",
1578
- "system.base.i18n_custom.message.confirm_delete": "確定要刪除自訂翻譯「{name}」嗎?"
1578
+ "system.base.i18n_custom.message.confirm_delete": "確定要刪除自訂翻譯「{name}」嗎?",
1579
+ "system.dashboard.last_7_days": "近 7 天",
1580
+ "system.dashboard.total": "總計 {count}"
1579
1581
  }
@@ -105,6 +105,8 @@ const starterShortcuts = ref<AiShortcut[]>([]);
105
105
  const messages = ref<Record<string, ChatMessageItem[]>>({});
106
106
  const pendingDeltaMap = new Map<string, AiStreamPayload>();
107
107
  const runningStreamTaskMap = new Map<string, AiStreamTask>();
108
+ /** 每个会话最近一次消息列表请求的序号,用于丢弃晚到的旧列表响应。 */
109
+ const loadMessagesSeq = new Map<string, number>();
108
110
  let pendingDeltaFrame = 0;
109
111
  let speakingMessageID = "";
110
112
  let createSessionPromise: Promise<string | undefined> | undefined;
@@ -192,6 +194,8 @@ async function sendAiPayload(payload: SubmitPayload) {
192
194
  // 同一个会话内仍然串行发送,避免历史上下文和消息顺序被并发请求打乱。
193
195
  if (isSessionSending(sessionID)) return false;
194
196
 
197
+ // 使该会话仍在途的消息列表请求失效,避免其晚到后整体覆盖刚发送的本地气泡。
198
+ invalidateLoadMessages(sessionID);
195
199
  const localUserMessage = createLocalUserMessage(payload);
196
200
  const thinkingMessage = createThinkingMessage({ sessionID });
197
201
  messages.value[sessionID] = sortMessages([...(messages.value[sessionID] ?? []), localUserMessage, thinkingMessage]);
@@ -650,22 +654,29 @@ async function loadAiShortcuts() {
650
654
  }
651
655
  }
652
656
 
657
+ /** 使指定会话仍在途的消息列表请求失效。 */
658
+ function invalidateLoadMessages(sessionID: string) {
659
+ loadMessagesSeq.set(sessionID, (loadMessagesSeq.get(sessionID) ?? 0) + 1);
660
+ }
661
+
653
662
  /** 加载指定会话的消息记录。 */
654
663
  async function loadMessages(sessionID: string, options?: { force?: boolean }) {
655
664
  if (!sessionID) return;
656
665
  if (!options?.force && isSessionSending(sessionID) && messages.value[sessionID]?.length) return;
657
666
 
667
+ const requestId = (loadMessagesSeq.get(sessionID) ?? 0) + 1;
668
+ loadMessagesSeq.set(sessionID, requestId);
658
669
  loadingSessionID.value = sessionID;
659
670
  try {
660
671
  const response = await defAiMessageService.ListAiMessage({ session_id: sessionID });
661
- if (loadingSessionID.value !== sessionID) return;
672
+ if (loadMessagesSeq.get(sessionID) !== requestId) return;
662
673
  messages.value[sessionID] = normalizeMessageList(response?.messages);
663
674
  } catch {
664
- if (loadingSessionID.value === sessionID) {
675
+ if (loadMessagesSeq.get(sessionID) === requestId) {
665
676
  messages.value[sessionID] = [];
666
677
  }
667
678
  } finally {
668
- if (loadingSessionID.value === sessionID) {
679
+ if (loadMessagesSeq.get(sessionID) === requestId && loadingSessionID.value === sessionID) {
669
680
  loadingSessionID.value = "";
670
681
  }
671
682
  }
@@ -22,7 +22,7 @@
22
22
  <template #header
23
23
  ><div class="chart-heading">
24
24
  <span>{{ t("system.dashboard.login_trend") }}</span
25
- ><small>近 7 天</small>
25
+ ><small>{{ t("system.dashboard.last_7_days") }}</small>
26
26
  </div></template
27
27
  >
28
28
  <div class="chart-wrap"><ECharts :option="loginTrendOption" height="285" /></div>
@@ -31,7 +31,7 @@
31
31
  <template #header
32
32
  ><div class="chart-heading">
33
33
  <span>{{ t("system.dashboard.login_distribution") }}</span
34
- ><small>总计 {{ loginDistributionTotal }}</small>
34
+ ><small>{{ t("system.dashboard.total", { count: loginDistributionTotal }) }}</small>
35
35
  </div></template
36
36
  >
37
37
  <div class="chart-wrap"><ECharts :option="loginDistributionOption" height="265" /></div>
@@ -40,7 +40,7 @@
40
40
  <template #header
41
41
  ><div class="chart-heading">
42
42
  <span>{{ t("system.dashboard.operation_distribution") }}</span
43
- ><small>总计 {{ operationDistributionTotal }}</small>
43
+ ><small>{{ t("system.dashboard.total", { count: operationDistributionTotal }) }}</small>
44
44
  </div></template
45
45
  >
46
46
  <div class="chart-wrap"><ECharts :option="operationDistributionOption" height="265" /></div>
@@ -388,14 +388,20 @@ watch(
388
388
  }
389
389
  );
390
390
 
391
+ /** 用户选项请求序号,用于丢弃快速切换租户时晚到的旧列表。 */
392
+ let userOptionsRequestId = 0;
393
+
391
394
  watch(
392
395
  () => formData.tenant_id,
393
396
  async tenantId => {
394
397
  if (formData.scope_type !== BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_USER || !tenantId) {
398
+ userOptionsRequestId += 1;
395
399
  userOptions.value = [];
396
400
  return;
397
401
  }
402
+ const requestId = ++userOptionsRequestId;
398
403
  const response = await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: tenantId });
404
+ if (requestId !== userOptionsRequestId || formData.tenant_id !== tenantId) return;
399
405
  userOptions.value = response.list ?? [];
400
406
  }
401
407
  );
@@ -243,6 +243,19 @@ watch(
243
243
  }
244
244
  );
245
245
 
246
+ /** 校验受众列表:至少包含一条有效受众(租户全员天然有效,其余类型需填写有效 ID)。 */
247
+ function validateAudiences(_rule: unknown, value: unknown, callback: (error?: Error) => void) {
248
+ const audiences = Array.isArray(value) ? (value as BaseMessageAudienceForm[]) : [];
249
+ const hasValidAudience = audiences.some(
250
+ audience => audience.type === MessageAudienceType.MESSAGE_AUDIENCE_TYPE_TENANT || Number(audience.id) > 0
251
+ );
252
+ if (hasValidAudience) {
253
+ callback();
254
+ return;
255
+ }
256
+ callback(new Error(t("system.base.message.validation.audience_id")));
257
+ }
258
+
246
259
  const rules = computed(() => ({
247
260
  tenant_id: isDefaultTenant.value
248
261
  ? [
@@ -274,7 +287,7 @@ const rules = computed(() => ({
274
287
  trigger: "blur"
275
288
  }
276
289
  ],
277
- audiences: [{ required: true, message: t("system.base.message.validation.audience_id"), trigger: "change" }]
290
+ audiences: [{ validator: validateAudiences, trigger: "change" }]
278
291
  }));
279
292
 
280
293
  const formFields = computed<ProFormField[]>(() => [
@@ -328,7 +341,7 @@ const formFields = computed<ProFormField[]>(() => [
328
341
  component: "slot",
329
342
  slotName: "audiences",
330
343
  colSpan: 24,
331
- rules: [{ required: true, message: t("system.base.message.validation.audience_id"), trigger: "change" }]
344
+ rules: [{ validator: validateAudiences, trigger: "change" }]
332
345
  },
333
346
  {
334
347
  prop: "action_type",
@@ -208,7 +208,12 @@ const rules = computed<FormRules>(() => ({
208
208
  tenant_id: [{ required: isDefaultTenant.value, message: t("common.validation.required_select", { field: t("common.field.tenant") }), trigger: "change" }],
209
209
  source_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.source_name"), trigger: "change" }],
210
210
  table_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.table_name"), trigger: "change" }],
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" }]
211
+ column_rows: [{ validator: (_rule, value: StorageColumnRow[], callback) => {
212
+ const hasRule = value?.some(row => Boolean(row.rule_id));
213
+ // 编辑态下清空规则(存在 id 但 rule_id 为空)需放行,交由提交逻辑删除旧策略。
214
+ const hasRemoval = value?.some(row => row.id > 0 && !row.rule_id);
215
+ hasRule || hasRemoval ? callback() : callback(new Error(t("system.base.redact_storage_policy.validation.configured_fields")));
216
+ }, trigger: "change" }]
212
217
  }));
213
218
  const columns = computed<ColumnProps[]>(() => [
214
219
  { type: "selection", width: 55 },
@@ -232,7 +232,9 @@ async function remove(row: Notification) {
232
232
 
233
233
  /** 解析收件箱分类图标,未知图标使用默认图标。 */
234
234
  function resolveNotificationIcon(icon: string) {
235
- return notificationIcons[icon as keyof typeof notificationIcons] ?? CollectionTag;
235
+ // 使用自有属性判定,避免原型链上的属性(如 constructor)被误判为合法图标键。
236
+ if (!Object.hasOwn(notificationIcons, icon)) return CollectionTag;
237
+ return notificationIcons[icon as keyof typeof notificationIcons];
236
238
  }
237
239
  </script>
238
240
 
@@ -80,6 +80,9 @@ const tableId = computed(() => {
80
80
  /** 当前代码预览页标题。 */
81
81
  const pageTitle = computed(() => table.value?.comment || table.value?.name || t("system.code.gen.preview.title.code"));
82
82
 
83
+ /** 代码预览加载序号,用于丢弃旧表晚到的响应。 */
84
+ let codePreviewRequestId = 0;
85
+
83
86
  // 路由生成对象变化时重新载入对应代码预览。
84
87
  watch(
85
88
  tableId,
@@ -91,6 +94,7 @@ watch(
91
94
 
92
95
  /** 加载当前表配置与固定项目路径下的代码预览。 */
93
96
  async function loadCodePreview() {
97
+ const requestId = ++codePreviewRequestId;
94
98
  table.value = undefined;
95
99
  files.value = [];
96
100
  previewError.value = "";
@@ -99,9 +103,11 @@ async function loadCodePreview() {
99
103
  loading.value = true;
100
104
  try {
101
105
  const currentTable = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
106
+ if (requestId !== codePreviewRequestId) return;
102
107
  table.value = currentTable;
103
108
  try {
104
109
  const preview = await defCodeGenService.PreviewCodeGen({ table_id: tableId.value, output_paths: undefined });
110
+ if (requestId !== codePreviewRequestId) return;
105
111
  files.value = preview.files ?? [];
106
112
  missingI18ns.value = preview.missing_i18ns ?? [];
107
113
  if (missingI18ns.value.length) {
@@ -111,12 +117,14 @@ async function loadCodePreview() {
111
117
  }
112
118
  if (!files.value.length && !previewError.value) previewError.value = t("system.code.gen.preview.message.no_preview_files");
113
119
  } catch {
120
+ if (requestId !== codePreviewRequestId) return;
114
121
  // 预览错误在页面内转成可操作提示,避免全局错误弹窗只显示“系统出错”。
115
122
  previewError.value = t("system.code.gen.preview.message.load_failed");
116
123
  }
124
+ if (requestId !== codePreviewRequestId) return;
117
125
  syncWorkspaceTitle();
118
126
  } finally {
119
- loading.value = false;
127
+ if (requestId === codePreviewRequestId) loading.value = false;
120
128
  }
121
129
  }
122
130
 
@@ -694,6 +694,9 @@ const dictionaryItemsForEditor = computed(
694
694
  /** 当前选项编辑器中的静态数据。 */
695
695
  const staticOptionsForEditor = computed(() => staticOptions.get(optionDialog.cacheKey) ?? []);
696
696
 
697
+ /** 字段配置加载序号,用于丢弃旧表晚到的响应,避免覆盖成旧表配置。 */
698
+ let columnQueryRequestId = 0;
699
+
697
700
  // 路由生成对象变化时重新加载字段配置。
698
701
  watch(tableId, () => {
699
702
  void handleQuery();
@@ -706,6 +709,7 @@ watch(canEdit, () => {
706
709
 
707
710
  /** 查询生成对象字段配置。 */
708
711
  async function handleQuery() {
712
+ const requestId = ++columnQueryRequestId;
709
713
  loading.value = true;
710
714
  try {
711
715
  destroyColumnSortable();
@@ -717,14 +721,16 @@ async function handleQuery() {
717
721
  defCodeGenTableService.GetCodeGenTable({ id: tableId.value }),
718
722
  defCodeGenColumnService.ListCodeGenColumn({ table_id: tableId.value })
719
723
  ]);
724
+ if (requestId !== columnQueryRequestId) return;
720
725
  Object.assign(formData, table);
721
726
  // 字段配置和预览都保留数据库完整字段快照,由用户决定是否调整默认配置。
722
727
  columns.value = (response.code_gen_columns ?? []).map(normalizeColumn);
723
728
  syncWorkspaceTitle();
724
729
  await nextTick();
730
+ if (requestId !== columnQueryRequestId) return;
725
731
  initColumnSortable();
726
732
  } finally {
727
- loading.value = false;
733
+ if (requestId === columnQueryRequestId) loading.value = false;
728
734
  }
729
735
  }
730
736
 
@@ -344,6 +344,9 @@ const treeParentOptions = computed<ProFormOption[]>(() => {
344
344
  return [{ label: t("system.code.gen.preview.value.top_level"), value: 0 }, ...mapPreviewRowsToOptions(treeRows)];
345
345
  });
346
346
 
347
+ /** 页面预览加载序号,用于丢弃旧表晚到的响应。 */
348
+ let previewRequestId = 0;
349
+
347
350
  // 路由生成对象变化时重新载入对应预览。
348
351
  watch(tableId, () => {
349
352
  void loadPreview();
@@ -397,8 +400,8 @@ async function requestPreviewTable(params: Record<string, any>) {
397
400
  if (pageType.value === "tree" && snapshot.value?.table.parent_column) {
398
401
  return { data: buildCodeGenPreviewTree(rows, primaryColumn.value, snapshot.value.table.parent_column) };
399
402
  }
400
- const pageNum = Number(params.pageNum ?? 1);
401
- const pageSize = Number(params.pageSize ?? 10);
403
+ const pageNum = Number(params.page_num ?? 1);
404
+ const pageSize = Number(params.page_size ?? 10);
402
405
  const start = (pageNum - 1) * pageSize;
403
406
  return { data: { list: rows.slice(start, start + pageSize), total: rows.length } };
404
407
  }
@@ -421,6 +424,7 @@ function refreshTable() {
421
424
 
422
425
  /** 加载当前表、字段和 Proto 配置并创建页面预览。 */
423
426
  async function loadPreview() {
427
+ const requestId = ++previewRequestId;
424
428
  loading.value = true;
425
429
  try {
426
430
  snapshot.value = null;
@@ -429,12 +433,14 @@ async function loadPreview() {
429
433
  databaseTables.value = [];
430
434
  if (!tableId.value) return;
431
435
  const table = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
436
+ if (requestId !== previewRequestId) return;
432
437
  const [columnResponse, protoResponse, dictionaryResponse, databaseTableResponse] = await Promise.all([
433
438
  defCodeGenColumnService.ListCodeGenColumn({ table_id: tableId.value }),
434
439
  defCodeGenProtoService.ListCodeGenProto({ table_id: tableId.value }),
435
440
  defBaseDictService.OptionBaseDict({}),
436
441
  defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: table.source_name })
437
442
  ]);
443
+ if (requestId !== previewRequestId) return;
438
444
  snapshot.value = { table, columns: columnResponse.code_gen_columns ?? [] };
439
445
  protoChecks.value = protoResponse.code_gen_protos ?? [];
440
446
  dictionaries.value = dictionaryResponse.base_dicts ?? [];
@@ -442,7 +448,7 @@ async function loadPreview() {
442
448
  createMockRows();
443
449
  syncWorkspaceTitle();
444
450
  } finally {
445
- loading.value = false;
451
+ if (requestId === previewRequestId) loading.value = false;
446
452
  }
447
453
  }
448
454
 
@@ -312,6 +312,9 @@ const configDialogLoading = computed(() => {
312
312
  return !!tableName && loadingTargetColumns.has(tableName);
313
313
  });
314
314
 
315
+ /** Proto 配置加载序号,用于丢弃旧表晚到的响应。 */
316
+ let protoQueryRequestId = 0;
317
+
315
318
  // 路由生成对象变化时重新加载 Proto 配置。
316
319
  watch(tableId, () => {
317
320
  void handleQuery();
@@ -321,6 +324,7 @@ watch(tableId, () => {
321
324
  * 查询生成对象字段与 Proto 配置。
322
325
  */
323
326
  async function handleQuery() {
327
+ const requestId = ++protoQueryRequestId;
324
328
  loading.value = true;
325
329
  try {
326
330
  Object.assign(formData, createDefaultCodeGenTableForm());
@@ -329,15 +333,19 @@ async function handleQuery() {
329
333
  Object.keys(targetColumnOptions).forEach(key => delete targetColumnOptions[key]);
330
334
  if (!tableId.value) return;
331
335
  const table = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
336
+ if (requestId !== protoQueryRequestId) return;
332
337
  const tableResponse = await defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: table.source_name });
338
+ if (requestId !== protoQueryRequestId) return;
333
339
  Object.assign(formData, table);
334
340
  databaseTables.value = tableResponse.tables ?? [];
335
341
  const columnResponse = await defCodeGenColumnService.ListCodeGenDatabaseColumn({ source_name: formData.source_name, table_name: formData.name });
342
+ if (requestId !== protoQueryRequestId) return;
336
343
  targetColumnOptions[formData.name] = createColumnOptions(columnResponse.columns ?? []);
337
- await loadProtoChecks();
344
+ await loadProtoChecks(requestId);
345
+ if (requestId !== protoQueryRequestId) return;
338
346
  syncWorkspaceTitle();
339
347
  } finally {
340
- loading.value = false;
348
+ if (requestId === protoQueryRequestId) loading.value = false;
341
349
  }
342
350
  }
343
351
 
@@ -356,9 +364,10 @@ function syncWorkspaceTitle() {
356
364
  /**
357
365
  * 自动检查当前生成对象需要的 Proto 能力。
358
366
  */
359
- async function loadProtoChecks() {
367
+ async function loadProtoChecks(requestId: number) {
360
368
  if (!formData.id) return;
361
369
  const data = await defCodeGenProtoService.ListCodeGenProto({ table_id: formData.id });
370
+ if (requestId !== protoQueryRequestId) return;
362
371
  protoChecks.value = (data.code_gen_protos ?? []).map(item => ({
363
372
  ...item,
364
373
  config: normalizeCodeGenProtoConfig(item.config)
@@ -470,7 +470,11 @@ onActivated(() => {
470
470
  }
471
471
  });
472
472
 
473
- onDeactivated(stopRuntimeSubscription);
473
+ onDeactivated(() => {
474
+ // 使隐藏前仍在途的实时控制台请求失效,避免其在组件失活后重建无人清理的订阅。
475
+ activeRequestId += 1;
476
+ stopRuntimeSubscription();
477
+ });
474
478
 
475
479
  onBeforeUnmount(() => {
476
480
  if (filterTimer) clearTimeout(filterTimer);
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.59",
4
+ "version": "0.0.60",
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.59"
19
+ "@liujitcn/kratos-admin-core": "0.0.60"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@element-plus/icons-vue": "^2.3.1",