@liujitcn/kratos-admin-system 0.0.51 → 0.0.53

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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/package/declarations/src/api/base/v1/sse.d.ts +1 -1
  3. package/dist/package/declarations/src/components/tenant-project/TenantProjectManager.vue.d.ts +1 -2
  4. package/dist/package/declarations/src/components/tenant-project/tenant-project-manager-data.d.ts +10 -0
  5. package/dist/package/declarations/src/components/tenant-project/tenant-project-manager.d.ts +8 -3
  6. package/dist/package/declarations/src/index.d.ts +1 -1
  7. package/dist/package/declarations/src/locales/generated.d.ts +32 -0
  8. package/dist/package/declarations/src/rpc/base/v1/ai_search.d.ts +26 -0
  9. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +0 -1
  10. package/dist/package/declarations/src/views/ai/chat/components/speech-recognition.d.ts +6 -2
  11. package/dist/package/src/api/base/v1/sse.ts +19 -12
  12. package/dist/package/src/components/log/LogTable.vue +25 -18
  13. package/dist/package/src/components/notification/Notification.vue +14 -7
  14. package/dist/package/src/components/tenant-project/TenantProjectManager.vue +106 -62
  15. package/dist/package/src/components/tenant-project/tenant-project-manager-data.ts +39 -1
  16. package/dist/package/src/components/tenant-project/tenant-project-manager.ts +19 -4
  17. package/dist/package/src/components/tenant-project-grant/ProjectGrantDialog.vue +22 -7
  18. package/dist/package/src/index.ts +2 -0
  19. package/dist/package/src/locales/en-US.json +8 -0
  20. package/dist/package/src/locales/ja-JP.json +8 -0
  21. package/dist/package/src/locales/zh-CN.json +8 -0
  22. package/dist/package/src/locales/zh-TW.json +8 -0
  23. package/dist/package/src/rpc/base/v1/ai_search.ts +37 -0
  24. package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +0 -1
  25. package/dist/package/src/views/ai/chat/components/XSender.vue +1 -36
  26. package/dist/package/src/views/ai/chat/components/speech-recognition.ts +28 -7
  27. package/dist/package/src/views/ai/chat/index.vue +16 -7
  28. package/dist/package/src/views/base/api-log/index.vue +1 -1
  29. package/dist/package/src/views/base/area/index.vue +15 -9
  30. package/dist/package/src/views/base/backup-management/archive-config/index.vue +22 -10
  31. package/dist/package/src/views/base/backup-management/backup-config/index.vue +13 -6
  32. package/dist/package/src/views/base/config/index.vue +38 -14
  33. package/dist/package/src/views/base/dept/index.vue +31 -25
  34. package/dist/package/src/views/base/dict/index.vue +12 -8
  35. package/dist/package/src/views/base/dict/item.vue +12 -8
  36. package/dist/package/src/views/base/i18n-custom/index.vue +13 -7
  37. package/dist/package/src/views/base/job/index.vue +12 -8
  38. package/dist/package/src/views/base/job/log.vue +14 -9
  39. package/dist/package/src/views/base/language/index.vue +7 -4
  40. package/dist/package/src/views/base/login-policy/index.vue +22 -11
  41. package/dist/package/src/views/base/menu/index.vue +23 -16
  42. package/dist/package/src/views/base/message/index.vue +65 -21
  43. package/dist/package/src/views/base/message-category/index.vue +10 -4
  44. package/dist/package/src/views/base/oauth-client/index.vue +15 -5
  45. package/dist/package/src/views/base/post/index.vue +10 -4
  46. package/dist/package/src/views/base/redact-output-policy/index.vue +12 -5
  47. package/dist/package/src/views/base/redact-rule/index.vue +8 -7
  48. package/dist/package/src/views/base/redact-storage-policy/index.vue +32 -8
  49. package/dist/package/src/views/base/role/index.vue +24 -17
  50. package/dist/package/src/views/base/tenant/index.vue +7 -6
  51. package/dist/package/src/views/base/tenant-project-grant/index.vue +44 -27
  52. package/dist/package/src/views/base/user/components/dept-tree.vue +4 -9
  53. package/dist/package/src/views/base/user/index.vue +39 -28
  54. package/dist/package/src/views/message/inbox/index.vue +8 -3
  55. package/dist/package/src/views/profile/components/base.vue +1 -1
  56. package/dist/package/src/views/profile/index.vue +1 -1
  57. package/dist/package/src/views/tool/cache/index.vue +1 -1
  58. package/dist/package/src/views/tool/code-gen/columns/index.vue +35 -16
  59. package/dist/package/src/views/tool/code-gen/table/index.vue +58 -31
  60. package/package.json +2 -2
package/README.md CHANGED
@@ -153,7 +153,7 @@ export const adminModules = [systemAdminModule];
153
153
 
154
154
  跨模块跳转使用 Vue Router;复用 System 代码时只引用 `package.json#exports` 公开的 npm 子路径。
155
155
 
156
- 租户项目管理组件通过 `TenantProjectManager` 公开。外部业务模块可以传入 `extraColumns`、`extraActions` 和 `loadExtraData`:追加列继续使用 `ColumnProps`,数据加载器接收当前页的 `tenant_id + project_id` 集合,单条操作回调接收同一组双键以及项目基础数据。组件也会透传表格具名插槽,并向行插槽增加 `tenantProject` 上下文;保存业务配置后可通过组件实例的 `refresh()` 刷新列表。按外部业务字段搜索或排序时,应由外部接口参与分页查询,不能只在当前页加载后过滤。
156
+ 租户项目管理组件通过 `TenantProjectManager` 公开。默认租户创建项目时在表单中选择目标租户,普通租户由服务端自动使用当前租户;默认租户查询全部项目,普通租户按项目授权范围查询。外部业务模块可以传入 `extraColumns`、`extraActions` 和 `loadExtraData`:扩展列可通过 `after` 指定插入到哪个基础字段后面,列的同名表格插槽会沿用该位置,未配置时默认插入备注后面,例如 `{ prop: "address", after: "name" }` 配合 `#address` 插槽即可把内容放到项目名称后面;数据加载器接收当前页的 `tenant_id + project_id` 集合,单条操作回调接收同一组双键以及项目基础数据。组件也会透传表格具名插槽,并向行插槽增加 `tenantProject` 上下文;保存业务配置后可通过组件实例的 `refresh()` 刷新列表。按外部业务字段搜索或排序时,应由外部接口参与分页查询,不能只在当前页加载后过滤。
157
157
 
158
158
  外部项目可以在自己的页面中包装该组件,并通过菜单将项目管理页面的 `component` 指向包装页面:
159
159
 
@@ -17,7 +17,7 @@ export declare class SseServiceImpl {
17
17
  /** 创建或复用 SSE 订阅连接。 */
18
18
  SubscribeSse(request: SubscribeSseRequest): SharedSseConnection | null;
19
19
  /** 释放 SSE 共享连接。 */
20
- ReleaseSse(request: SubscribeSseRequest): void;
20
+ ReleaseSse(request: SubscribeSseRequest, connection?: SharedSseConnection): void;
21
21
  /** 构建 SSE 订阅地址。 */
22
22
  private buildSubscribeURL;
23
23
  /** 构建 SSE 共享连接键。 */
@@ -1,4 +1,3 @@
1
- import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
2
1
  import { type TenantProjectAction, type TenantProjectManagerProps } from "./tenant-project-manager";
3
2
  /** 刷新项目表格。 */
4
3
  declare function refreshTable(): Promise<void>;
@@ -16,7 +15,7 @@ declare const __VLS_base: import("vue").DefineComponent<TenantProjectManagerProp
16
15
  }, string, import("vue").PublicProps, Readonly<TenantProjectManagerProps> & Readonly<{
17
16
  "onExtra-data-error"?: ((error: unknown) => any) | undefined;
18
17
  }>, {
19
- extraColumns: ColumnProps[];
18
+ extraColumns: import("./tenant-project-manager").TenantProjectExtraColumn[];
20
19
  extraActions: TenantProjectAction[];
21
20
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
22
21
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,4 +1,9 @@
1
1
  import type { BaseTenantProject } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project";
2
+ /** 租户项目表格列的最小结构,用于在不依赖表格组件的情况下排列扩展列。 */
3
+ type TenantProjectColumnLike = {
4
+ prop?: string;
5
+ type?: string;
6
+ };
2
7
  /** 租户项目业务数据查询键。 */
3
8
  export interface TenantProjectKey {
4
9
  /** 租户 ID。 */
@@ -8,7 +13,12 @@ export interface TenantProjectKey {
8
13
  }
9
14
  /** 租户项目扩展数据,外层键由租户 ID 和项目 ID 组成。 */
10
15
  export type TenantProjectExtraData = Record<string, Record<string, unknown>>;
16
+ /** 按基础字段位置排列租户项目管理的扩展列。 */
17
+ export declare function arrangeTenantProjectColumns<T extends TenantProjectColumnLike>(baseColumns: T[], extraColumns: Array<T & {
18
+ after?: string;
19
+ }>): T[];
11
20
  /** 创建租户项目扩展数据的稳定键。 */
12
21
  export declare function tenantProjectKey(tenantId: number, projectId: number): string;
13
22
  /** 将外部业务字段合并到项目行,同时保护公共项目字段。 */
14
23
  export declare function mergeTenantProjectExtraData(project: BaseTenantProject, extra?: Record<string, unknown>): BaseTenantProject & Record<string, unknown>;
24
+ export {};
@@ -1,7 +1,7 @@
1
1
  import type { BaseTenantProject, PageBaseTenantProjectRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project";
2
2
  import type { ColumnProps, TableActionProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
3
3
  import type { TenantProjectExtraData, TenantProjectKey } from "./tenant-project-manager-data";
4
- export { mergeTenantProjectExtraData, tenantProjectKey, type TenantProjectExtraData, type TenantProjectKey } from "./tenant-project-manager-data";
4
+ export { arrangeTenantProjectColumns, mergeTenantProjectExtraData, tenantProjectKey, type TenantProjectExtraData, type TenantProjectKey } from "./tenant-project-manager-data";
5
5
  /** 租户项目单条业务上下文。 */
6
6
  export interface TenantProjectContext<TData extends Record<string, unknown> = Record<string, unknown>> extends TenantProjectKey {
7
7
  /** 公共项目基础数据。 */
@@ -29,10 +29,15 @@ export type TenantProjectAction = Omit<TableActionProps, "disabled" | "hidden" |
29
29
  /** 执行项目扩展操作。 */
30
30
  onClick: (context: TenantProjectContext, params?: Record<string, any>) => void | Promise<void>;
31
31
  };
32
+ /** 租户项目管理的扩展列配置。 */
33
+ export type TenantProjectExtraColumn = ColumnProps & {
34
+ /** 插入到指定基础字段后面,未配置时默认插入备注字段后面。 */
35
+ after?: string;
36
+ };
32
37
  /** 租户项目管理组件属性。 */
33
38
  export interface TenantProjectManagerProps {
34
- /** 追加到基础列表的表格列。 */
35
- extraColumns?: ColumnProps[];
39
+ /** 追加到基础列表的表格列,可通过 after 指定插入位置。 */
40
+ extraColumns?: TenantProjectExtraColumn[];
36
41
  /** 追加到基础操作列的业务操作。 */
37
42
  extraActions?: TenantProjectAction[];
38
43
  /** 加载当前页外部业务字段。 */
@@ -1,5 +1,5 @@
1
1
  export { ADMIN_AI_EXTENSION, getAdminAiExtension } from "./ai";
2
2
  export type { AdminAiExtension } from "./ai";
3
3
  export { default as TenantProjectManager } from "./components/tenant-project/TenantProjectManager.vue";
4
- export { mergeTenantProjectExtraData, tenantProjectKey, type TenantProjectAction, type TenantProjectContext, type TenantProjectExtraData, type TenantProjectExtraDataLoadContext, type TenantProjectExtraDataLoader, type TenantProjectKey, type TenantProjectManagerProps } from "./components/tenant-project/tenant-project-manager";
4
+ export { mergeTenantProjectExtraData, arrangeTenantProjectColumns, tenantProjectKey, type TenantProjectAction, type TenantProjectContext, type TenantProjectExtraColumn, type TenantProjectExtraData, type TenantProjectExtraDataLoadContext, type TenantProjectExtraDataLoader, type TenantProjectKey, type TenantProjectManagerProps } from "./components/tenant-project/tenant-project-manager";
5
5
  export { systemAdminModule } from "./module";
@@ -399,6 +399,8 @@ export declare const LOCALE_MESSAGES: {
399
399
  "system.base.log.field.os": string;
400
400
  "system.base.log.field.path": string;
401
401
  "system.base.log.field.project": string;
402
+ "system.base.log.field.role_code": string;
403
+ "system.base.log.field.role_id": string;
402
404
  "system.base.log.field.reason": string;
403
405
  "system.base.log.field.reason_code": string;
404
406
  "system.base.log.field.referer": string;
@@ -649,6 +651,11 @@ export declare const LOCALE_MESSAGES: {
649
651
  "system.base.message.content_format.plain": string;
650
652
  "system.base.message.detail.action": string;
651
653
  "system.base.message.detail.title": string;
654
+ "system.base.message.dispatch_status.pending": string;
655
+ "system.base.message.dispatch_status.running": string;
656
+ "system.base.message.dispatch_status.succeeded": string;
657
+ "system.base.message.dispatch_status.failed": string;
658
+ "system.base.message.dispatch_status.cancelled": string;
652
659
  "system.base.message.field.action_target": string;
653
660
  "system.base.message.field.action_type": string;
654
661
  "system.base.message.field.attempt_count": string;
@@ -761,6 +768,7 @@ export declare const LOCALE_MESSAGES: {
761
768
  "system.base.migration.title.list": string;
762
769
  "system.base.migration.value.default_module": string;
763
770
  "system.base.oauth_client.action.copy_credentials": string;
771
+ "system.base.oauth_client.confirm.rotate_credentials": string;
764
772
  "system.base.oauth_client.field.api": string;
765
773
  "system.base.oauth_client.field.client_id": string;
766
774
  "system.base.oauth_client.field.client_name": string;
@@ -1971,6 +1979,8 @@ export declare const LOCALE_MESSAGES: {
1971
1979
  "system.base.log.field.os": string;
1972
1980
  "system.base.log.field.path": string;
1973
1981
  "system.base.log.field.project": string;
1982
+ "system.base.log.field.role_code": string;
1983
+ "system.base.log.field.role_id": string;
1974
1984
  "system.base.log.field.reason": string;
1975
1985
  "system.base.log.field.reason_code": string;
1976
1986
  "system.base.log.field.referer": string;
@@ -2221,6 +2231,11 @@ export declare const LOCALE_MESSAGES: {
2221
2231
  "system.base.message.content_format.plain": string;
2222
2232
  "system.base.message.detail.action": string;
2223
2233
  "system.base.message.detail.title": string;
2234
+ "system.base.message.dispatch_status.pending": string;
2235
+ "system.base.message.dispatch_status.running": string;
2236
+ "system.base.message.dispatch_status.succeeded": string;
2237
+ "system.base.message.dispatch_status.failed": string;
2238
+ "system.base.message.dispatch_status.cancelled": string;
2224
2239
  "system.base.message.field.action_target": string;
2225
2240
  "system.base.message.field.action_type": string;
2226
2241
  "system.base.message.field.attempt_count": string;
@@ -2333,6 +2348,7 @@ export declare const LOCALE_MESSAGES: {
2333
2348
  "system.base.migration.title.list": string;
2334
2349
  "system.base.migration.value.default_module": string;
2335
2350
  "system.base.oauth_client.action.copy_credentials": string;
2351
+ "system.base.oauth_client.confirm.rotate_credentials": string;
2336
2352
  "system.base.oauth_client.field.api": string;
2337
2353
  "system.base.oauth_client.field.client_id": string;
2338
2354
  "system.base.oauth_client.field.client_name": string;
@@ -3543,6 +3559,8 @@ export declare const LOCALE_MESSAGES: {
3543
3559
  "system.base.log.field.os": string;
3544
3560
  "system.base.log.field.path": string;
3545
3561
  "system.base.log.field.project": string;
3562
+ "system.base.log.field.role_code": string;
3563
+ "system.base.log.field.role_id": string;
3546
3564
  "system.base.log.field.reason": string;
3547
3565
  "system.base.log.field.reason_code": string;
3548
3566
  "system.base.log.field.referer": string;
@@ -3793,6 +3811,11 @@ export declare const LOCALE_MESSAGES: {
3793
3811
  "system.base.message.content_format.plain": string;
3794
3812
  "system.base.message.detail.action": string;
3795
3813
  "system.base.message.detail.title": string;
3814
+ "system.base.message.dispatch_status.pending": string;
3815
+ "system.base.message.dispatch_status.running": string;
3816
+ "system.base.message.dispatch_status.succeeded": string;
3817
+ "system.base.message.dispatch_status.failed": string;
3818
+ "system.base.message.dispatch_status.cancelled": string;
3796
3819
  "system.base.message.field.action_target": string;
3797
3820
  "system.base.message.field.action_type": string;
3798
3821
  "system.base.message.field.attempt_count": string;
@@ -3905,6 +3928,7 @@ export declare const LOCALE_MESSAGES: {
3905
3928
  "system.base.migration.title.list": string;
3906
3929
  "system.base.migration.value.default_module": string;
3907
3930
  "system.base.oauth_client.action.copy_credentials": string;
3931
+ "system.base.oauth_client.confirm.rotate_credentials": string;
3908
3932
  "system.base.oauth_client.field.api": string;
3909
3933
  "system.base.oauth_client.field.client_id": string;
3910
3934
  "system.base.oauth_client.field.client_name": string;
@@ -5115,6 +5139,8 @@ export declare const LOCALE_MESSAGES: {
5115
5139
  "system.base.log.field.os": string;
5116
5140
  "system.base.log.field.path": string;
5117
5141
  "system.base.log.field.project": string;
5142
+ "system.base.log.field.role_code": string;
5143
+ "system.base.log.field.role_id": string;
5118
5144
  "system.base.log.field.reason": string;
5119
5145
  "system.base.log.field.reason_code": string;
5120
5146
  "system.base.log.field.referer": string;
@@ -5365,6 +5391,11 @@ export declare const LOCALE_MESSAGES: {
5365
5391
  "system.base.message.content_format.plain": string;
5366
5392
  "system.base.message.detail.action": string;
5367
5393
  "system.base.message.detail.title": string;
5394
+ "system.base.message.dispatch_status.pending": string;
5395
+ "system.base.message.dispatch_status.running": string;
5396
+ "system.base.message.dispatch_status.succeeded": string;
5397
+ "system.base.message.dispatch_status.failed": string;
5398
+ "system.base.message.dispatch_status.cancelled": string;
5368
5399
  "system.base.message.field.action_target": string;
5369
5400
  "system.base.message.field.action_type": string;
5370
5401
  "system.base.message.field.attempt_count": string;
@@ -5477,6 +5508,7 @@ export declare const LOCALE_MESSAGES: {
5477
5508
  "system.base.migration.title.list": string;
5478
5509
  "system.base.migration.value.default_module": string;
5479
5510
  "system.base.oauth_client.action.copy_credentials": string;
5511
+ "system.base.oauth_client.confirm.rotate_credentials": string;
5480
5512
  "system.base.oauth_client.field.api": string;
5481
5513
  "system.base.oauth_client.field.client_id": string;
5482
5514
  "system.base.oauth_client.field.client_name": string;
@@ -0,0 +1,26 @@
1
+ /** AI 助手联网搜索请求 */
2
+ export interface SearchAiWebRequest {
3
+ /** 搜索关键词 */
4
+ query: string;
5
+ /** 返回结果数量:0 表示默认5条,最大10条 */
6
+ limit: number;
7
+ }
8
+ /** AI 助手联网搜索响应 */
9
+ export interface SearchAiWebResponse {
10
+ /** 搜索结果列表 */
11
+ items: SearchAiWebItem[];
12
+ }
13
+ /** AI 助手联网搜索结果 */
14
+ export interface SearchAiWebItem {
15
+ /** 结果标题 */
16
+ title: string;
17
+ /** 结果链接 */
18
+ url: string;
19
+ /** 结果摘要 */
20
+ snippet: string;
21
+ }
22
+ /** Base AI 助手联网搜索服务 */
23
+ export interface AiSearchService {
24
+ /** 联网搜索公开信息并返回结果摘要 */
25
+ SearchAiWeb(request: SearchAiWebRequest): Promise<SearchAiWebResponse>;
26
+ }
@@ -121,7 +121,6 @@ export interface BaseRedactOutputPolicy {
121
121
  }
122
122
  /** 查询可出库脱敏字段请求。 */
123
123
  export interface GetBaseRedactOutputFieldDocRequest {
124
- /** 接口ID */
125
124
  api_id: number;
126
125
  }
127
126
  /** Admin出库脱敏策略服务。 */
@@ -3,6 +3,7 @@ export type SpeechResultList = ArrayLike<{
3
3
  0?: {
4
4
  transcript: string;
5
5
  };
6
+ isFinal?: boolean;
6
7
  length: number;
7
8
  }>;
8
9
  /** 语音识别错误的最小结构,兼容浏览器事件和不支持错误。 */
@@ -21,8 +22,11 @@ type SpeechRecognitionOptions = {
21
22
  /** 识别结果回调。 */
22
23
  onResult?: (text: string) => void;
23
24
  };
24
- /** 收集一次识别事件中的完整文本。 */
25
- export declare function collectSpeechResultText(results: SpeechResultList): string;
25
+ /** 增量累积语音识别结果,避免连续模式下 interim 结果重复计入已确认文本。 */
26
+ export declare function accumulateSpeechResultText(results: SpeechResultList, resultIndex: number, previousFinalText: string): {
27
+ finalText: string;
28
+ text: string;
29
+ };
26
30
  /** 创建浏览器语音识别实例,并统一结果、状态和卸载处理。 */
27
31
  export declare function useSpeechRecognition({ onError, onStart, onEnd, onResult }?: SpeechRecognitionOptions): {
28
32
  loading: globalThis.Ref<boolean, boolean>;
@@ -61,10 +61,10 @@ export class SseServiceImpl {
61
61
  }
62
62
 
63
63
  /** 释放 SSE 共享连接。 */
64
- ReleaseSse(request: SubscribeSseRequest) {
64
+ ReleaseSse(request: SubscribeSseRequest, connection?: SharedSseConnection) {
65
65
  const connectionKey = this.buildConnectionKey(request);
66
66
  const cachedConnection = this.sharedConnections.get(connectionKey);
67
- if (!cachedConnection) {
67
+ if (!cachedConnection || (connection && cachedConnection !== connection)) {
68
68
  return;
69
69
  }
70
70
  cachedConnection.refCount -= 1;
@@ -77,10 +77,9 @@ export class SseServiceImpl {
77
77
 
78
78
  /** 构建 SSE 订阅地址。 */
79
79
  private buildSubscribeURL(request: SubscribeSseRequest) {
80
- const url = new URL(SSE_URL, window.location.origin);
81
- url.searchParams.set("stream", request.stream);
80
+ const url = new URL(`${SSE_URL}/${encodeURIComponent(request.stream)}`, window.location.origin);
82
81
  if (request.channel_id) {
83
- url.searchParams.set("channel", request.channel_id);
82
+ url.searchParams.set("channel_id", request.channel_id);
84
83
  }
85
84
  return url.toString();
86
85
  }
@@ -100,19 +99,27 @@ export class SseServiceImpl {
100
99
  try {
101
100
  const accessToken = await getRequestAccessToken();
102
101
  if (!accessToken) {
103
- this.sharedConnections.delete(connectionKey);
102
+ if (this.sharedConnections.get(connectionKey) === connection) this.sharedConnections.delete(connectionKey);
104
103
  return;
105
104
  }
106
105
 
106
+ const headers: Record<string, string> = {
107
+ Accept: EventStreamContentType,
108
+ Authorization: accessToken,
109
+ ...getLocaleRequestHeaders()
110
+ };
107
111
  await fetchEventSource(url, {
108
112
  method: "GET",
109
113
  signal: controller.signal,
110
114
  openWhenHidden: true,
111
- headers: {
112
- Accept: EventStreamContentType,
113
- Authorization: accessToken,
114
- ...getLocaleRequestHeaders()
115
+ fetch: async (input, init) => {
116
+ const token = await getRequestAccessToken();
117
+ if (!token) return new Response(null, { status: 401 });
118
+ const requestHeaders = new Headers(init?.headers);
119
+ requestHeaders.set("Authorization", token);
120
+ return window.fetch(input, { ...init, headers: requestHeaders });
115
121
  },
122
+ headers,
116
123
  async onopen(response) {
117
124
  const contentType = response.headers.get("content-type") ?? "";
118
125
  if (response.ok && contentType.startsWith(EventStreamContentType)) {
@@ -161,7 +168,7 @@ export class SseServiceImpl {
161
168
  } else if (error instanceof SsePermissionError) {
162
169
  ElMessage.error(error.message);
163
170
  }
164
- this.sharedConnections.delete(connectionKey);
171
+ if (this.sharedConnections.get(connectionKey) === connection) this.sharedConnections.delete(connectionKey);
165
172
  }
166
173
  }
167
174
  }
@@ -199,6 +206,6 @@ export function subscribeSseEvent<T>(
199
206
  if (currentListeners && currentListeners.size === 0) {
200
207
  connection.listeners.delete(eventName);
201
208
  }
202
- defSseService.ReleaseSse(request);
209
+ defSseService.ReleaseSse(request, connection);
203
210
  };
204
211
  }
@@ -2,7 +2,7 @@
2
2
  <div class="table-box">
3
3
  <ProTable ref="proTable" row-key="id" :columns="resolvedColumns" :request-api="requestTable" />
4
4
 
5
- <ProDialog v-model="dialog.visible" :title="config.detailTitle" width="1280px" @close="handleCloseDialog">
5
+ <ProDialog ref="dialogRef" v-model="dialog.visible" :title="config.detailTitle" width="1280px" @close="handleCloseDialog">
6
6
  <el-descriptions border :column="2" class="detail-container">
7
7
  <el-descriptions-item
8
8
  v-for="field in config.detailFields"
@@ -93,6 +93,7 @@ export interface LogTableConfig {
93
93
 
94
94
  const props = defineProps<{ config: LogTableConfig }>();
95
95
  const proTable = ref<ProTableInstance>();
96
+ const dialogRef = ref<InstanceType<typeof ProDialog>>();
96
97
  const detail = reactive<Record<string, unknown>>({});
97
98
  const dialog = reactive({ visible: false });
98
99
  const traceItems = ref<BaseLogTraceItem[]>([]);
@@ -107,27 +108,33 @@ async function requestTable(params: Record<string, unknown>) {
107
108
 
108
109
  /** 打开审计详情弹窗。 */
109
110
  async function handleOpenDialog(id: string) {
110
- const value = await props.config.get(id);
111
- Object.keys(detail).forEach(key => delete detail[key]);
112
- Object.assign(detail, value);
113
- dialog.visible = true;
114
- traceItems.value = [];
115
- const requestID = String(detail.request_id ?? "");
116
- const traceID = String(detail.trace_id ?? "");
117
- if (!props.config.trace || (!requestID && !traceID)) return;
118
- traceLoading.value = true;
119
- try {
120
- traceItems.value = await props.config.trace(requestID, traceID);
121
- } catch {
122
- traceItems.value = [];
123
- } finally {
124
- traceLoading.value = false;
125
- }
111
+ await dialogRef.value?.open({
112
+ load: async () => {
113
+ const value = await props.config.get(id);
114
+ const requestID = String(value.request_id ?? "");
115
+ const traceID = String(value.trace_id ?? "");
116
+ let traces: BaseLogTraceItem[] = [];
117
+ if (props.config.trace && (requestID || traceID)) {
118
+ try {
119
+ traces = await props.config.trace(requestID, traceID);
120
+ } catch {
121
+ traces = [];
122
+ }
123
+ }
124
+ return { value, traces };
125
+ },
126
+ commit: ({ value, traces }) => {
127
+ Object.keys(detail).forEach(key => delete detail[key]);
128
+ Object.assign(detail, value);
129
+ traceItems.value = traces;
130
+ traceLoading.value = false;
131
+ }
132
+ });
126
133
  }
127
134
 
128
135
  /** 关闭并清理审计详情弹窗。 */
129
136
  function handleCloseDialog() {
130
- dialog.visible = false;
137
+ dialogRef.value?.close();
131
138
  Object.keys(detail).forEach(key => delete detail[key]);
132
139
  traceItems.value = [];
133
140
  traceLoading.value = false;
@@ -38,7 +38,7 @@
38
38
  <el-button class="notification-more" text @click="openInbox">{{ t("system.notification.action.view_all") }}</el-button>
39
39
  </div>
40
40
  </el-popover>
41
- <ProDialog v-model="detailVisible" :title="detail?.title" width="720px" destroy-on-close :show-footer="false">
41
+ <ProDialog ref="detailDialogRef" v-model="detailVisible" :title="detail?.title" width="720px" destroy-on-close :show-footer="false">
42
42
  <div v-if="detail" class="notification-detail">
43
43
  <div class="notification-detail-meta">
44
44
  <span class="notification-detail-category" :style="{ color: detail.category_color || undefined }">
@@ -82,6 +82,7 @@ import {
82
82
 
83
83
  const router = useRouter();
84
84
  const popoverVisible = ref(false);
85
+ const detailDialogRef = ref<InstanceType<typeof ProDialog>>();
85
86
  const unreadTotal = ref(0);
86
87
  const latestDeliveryID = ref(0);
87
88
  const notifications = ref<Notification[]>([]);
@@ -154,12 +155,18 @@ async function markAllRead() {
154
155
  async function openNotification(row: Notification) {
155
156
  popoverVisible.value = false;
156
157
  const wasUnread = !row.read_at;
157
- const [notification] = await Promise.all([
158
- defNotificationService.GetNotification({ id: row.id }),
159
- wasUnread ? defNotificationService.MarkNotificationRead({ ids: [row.id] }) : Promise.resolve()
160
- ]);
161
- detail.value = notification;
162
- detailVisible.value = true;
158
+ await detailDialogRef.value?.open({
159
+ load: async () => {
160
+ const [notification] = await Promise.all([
161
+ defNotificationService.GetNotification({ id: row.id }),
162
+ wasUnread ? defNotificationService.MarkNotificationRead({ ids: [row.id] }) : Promise.resolve()
163
+ ]);
164
+ return notification;
165
+ },
166
+ commit: notification => {
167
+ detail.value = notification;
168
+ }
169
+ });
163
170
  notifications.value = notifications.value.filter(item => item.id !== row.id);
164
171
  if (wasUnread) unreadTotal.value = Math.max(0, unreadTotal.value - 1);
165
172
  }