@blueking/chat-x 0.0.48-beta.1 → 0.0.49-beta.10

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 (70) hide show
  1. package/dist/ag-ui/types/constants.d.ts +1 -0
  2. package/dist/ag-ui/types/file.d.ts +13 -0
  3. package/dist/ag-ui/types/index.d.ts +1 -0
  4. package/dist/ag-ui/types/messages.d.ts +4 -0
  5. package/dist/components/chat-message/assistant-message/assistant-message.vue.d.ts +12 -1
  6. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-file-card.vue.d.ts +12 -0
  7. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/artifact-preview-host.vue.d.ts +11 -0
  8. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/preview-strategy.d.ts +8 -0
  9. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/code-preview.vue.d.ts +8 -0
  10. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/html-preview.vue.d.ts +6 -0
  11. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/image-preview.vue.d.ts +7 -0
  12. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/markdown-preview.vue.d.ts +6 -0
  13. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/txt-preview.vue.d.ts +6 -0
  14. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/url-iframe-preview.vue.d.ts +6 -0
  15. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/use-artifact-preview-loader.d.ts +22 -0
  16. package/dist/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue.d.ts +13 -0
  17. package/dist/components/chat-message/assistant-message/message-artifacts/message-artifacts.vue.d.ts +9 -0
  18. package/dist/components/chat-message/interrupt-message/user-question/use-user-question.d.ts +7 -2
  19. package/dist/components/chat-message/user-message/user-message.vue.d.ts +15 -2
  20. package/dist/components/file-icon/file-icon.vue.d.ts +7 -0
  21. package/dist/components/index.d.ts +3 -1
  22. package/dist/components/message-tools/message-time/format-message-time.d.ts +8 -0
  23. package/dist/components/message-tools/message-time/message-time.vue.d.ts +8 -0
  24. package/dist/components/message-tools/message-tools.vue.d.ts +11 -1
  25. package/dist/composables/index.d.ts +1 -0
  26. package/dist/composables/use-artifact-preview.d.ts +49 -0
  27. package/dist/composables/use-container-scroll.d.ts +9 -2
  28. package/dist/composables/use-custom-tab.d.ts +7 -3
  29. package/dist/composables/use-global-config.d.ts +3 -0
  30. package/dist/composables/use-message-group.d.ts +505 -0
  31. package/dist/icons/file-icons.d.ts +4 -0
  32. package/dist/icons/file.d.ts +6 -0
  33. package/dist/icons/index.d.ts +2 -0
  34. package/dist/icons/tools.d.ts +3 -0
  35. package/dist/index.css +1 -1
  36. package/dist/index.js +3203 -2368
  37. package/dist/index.js.map +1 -1
  38. package/dist/lang/lang.d.ts +9 -1
  39. package/dist/mcp/generated/docs/activity-message.md +122 -97
  40. package/dist/mcp/generated/docs/assistant-message.md +146 -75
  41. package/dist/mcp/generated/docs/chat-container.md +121 -38
  42. package/dist/mcp/generated/docs/chat-input.md +2 -10
  43. package/dist/mcp/generated/docs/constants.md +3 -1
  44. package/dist/mcp/generated/docs/content-render.md +2 -10
  45. package/dist/mcp/generated/docs/execution-summary.md +3 -3
  46. package/dist/mcp/generated/docs/file-artifact-panel.md +293 -0
  47. package/dist/mcp/generated/docs/file-icon.md +111 -0
  48. package/dist/mcp/generated/docs/info-message.md +29 -12
  49. package/dist/mcp/generated/docs/interrupt.md +1 -0
  50. package/dist/mcp/generated/docs/loading-message.md +36 -17
  51. package/dist/mcp/generated/docs/message-container.md +27 -23
  52. package/dist/mcp/generated/docs/message-render.md +47 -59
  53. package/dist/mcp/generated/docs/message-time.md +180 -0
  54. package/dist/mcp/generated/docs/message-tools.md +47 -12
  55. package/dist/mcp/generated/docs/messages.md +9 -0
  56. package/dist/mcp/generated/docs/reasoning-message.md +17 -20
  57. package/dist/mcp/generated/docs/tool-message.md +61 -45
  58. package/dist/mcp/generated/docs/toolcall-render.md +18 -10
  59. package/dist/mcp/generated/docs/use-artifact-preview.md +234 -0
  60. package/dist/mcp/generated/docs/use-container-scroll.md +6 -2
  61. package/dist/mcp/generated/docs/use-custom-tab.md +25 -8
  62. package/dist/mcp/generated/docs/use-global-config.md +15 -5
  63. package/dist/mcp/generated/docs/use-message-group.md +37 -5
  64. package/dist/mcp/generated/docs/user-message.md +191 -121
  65. package/dist/mcp/generated/docs/user-question-card.md +6 -3
  66. package/dist/mcp/generated/index.json +144 -18
  67. package/dist/mcp/index.js +0 -0
  68. package/dist/utils/file-type.d.ts +14 -0
  69. package/dist/utils/index.d.ts +1 -0
  70. package/package.json +20 -21
@@ -12,46 +12,60 @@
12
12
  <!-- FULL DOC -->
13
13
 
14
14
  # LoadingMessage 加载中消息
15
+
15
16
  ## 源码事实
16
17
 
17
18
  - **源码位置**:`src/components/chat-message/loading-message/loading-message.vue`
18
19
  - **能力域**:消息系统
19
20
  - **能力说明**:消息列表中的加载占位,默认使用 AiLoading,也支持默认插槽覆盖。
20
21
 
21
- > **能力域**:消息系统
22
+ > **导出说明**:`LoadingMessage` **未**从包入口导出。消费方经 `MessageRender`(`role: 'loading'`)或由 `MessageContainer` 自动注入。下文 `LoadingMessageComp` 为文档站内部示例。
22
23
 
23
- 加载等待状态组件,展示 AI 正在处理请求时的过渡动画。由旋转渐变环 + 脉冲星形图标(蓝→紫→粉渐变)和"请求中..."文案组成。支持通过默认插槽自定义加载文案。
24
+ 加载等待状态组件:`AiLoading`(18px)+ 默认文案「请求中...」。可通过默认插槽自定义文案。
24
25
 
25
- > **提示**:此组件通常**不需要手动使用**,`MessageContainer` 会在满足条件时自动注入。
26
+ > **提示**:通常**不需要手动使用**,`MessageContainer` / `useMessageGroup` 会在满足条件时自动注入。
26
27
 
27
28
  ## 渲染效果
28
29
 
29
30
  ## 基础用法
30
31
 
31
- 组件无 Props,直接引入渲染即可:
32
+ 组件无 Props。文档站内部示例:
33
+
34
+ ```vue
35
+ <template>
36
+ <LoadingMessageComp />
37
+ </template>
38
+ ```
39
+
40
+ 消费方经 `MessageRender`:
32
41
 
33
42
  ```vue
34
43
  <template>
35
- <LoadingMessage />
44
+ <MessageRender
45
+ :message="{
46
+ id: 'loading',
47
+ messageId: '',
48
+ role: MessageRole.Loading,
49
+ content: '',
50
+ status: MessageStatus.Pending,
51
+ }"
52
+ />
36
53
  </template>
37
54
 
38
55
  <script setup lang="ts">
39
- import { LoadingMessage } from '@blueking/chat-x';
56
+ import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
40
57
  </script>
41
58
  ```
42
59
 
43
60
  ## 自定义加载文案
44
61
 
45
- 通过默认插槽可覆盖默认的"请求中..."文案:
62
+ 通过默认插槽覆盖「请求中...」:
46
63
 
47
64
  ```vue
48
65
  <template>
49
- <LoadingMessage>正在思考中,请稍候...</LoadingMessage>
66
+ <!-- 文档站内部示例 -->
67
+ <LoadingMessageComp>正在思考中,请稍候...</LoadingMessageComp>
50
68
  </template>
51
-
52
- <script setup lang="ts">
53
- import { LoadingMessage } from '@blueking/chat-x';
54
- </script>
55
69
  ```
56
70
 
57
71
  ## 动画说明
@@ -67,15 +81,18 @@
67
81
 
68
82
  ## 在 MessageContainer 中的自动注入
69
83
 
70
- `MessageContainer` 在构建消息分组列表时,检测到**消息列表最后一条为用户消息**(`role === 'user'`)时,自动在末尾追加一个 Loading 消息组:
84
+ `useMessageGroup` 构建分组时,若**最后一条为用户消息**且 **`renderMode !== RenderMode.Share`**,自动在末尾追加 Loading 组:
71
85
 
72
86
  ```typescript
73
- // MessageContainer 内部逻辑(简化)
74
- if (messages.at(-1)?.role === MessageRole.User) {
87
+ // use-message-group.ts(简化)
88
+ const shouldAppendLoading =
89
+ messages.at(-1)?.role === MessageRole.User && renderMode !== RenderMode.Share;
90
+
91
+ if (shouldAppendLoading) {
75
92
  list.push({
76
93
  messages: [
77
94
  {
78
- role: MessageRole.Loading, // 'loading'
95
+ role: MessageRole.Loading,
79
96
  content: '',
80
97
  status: MessageStatus.Pending,
81
98
  id: 'loading',
@@ -87,7 +104,8 @@ if (messages.at(-1)?.role === MessageRole.User) {
87
104
  }
88
105
  ```
89
106
 
90
- 当下一条 AI 消息(`role: 'assistant'`)到来后,最后一条不再是用户消息,Loading 组自动消失。
107
+ - 下一条 AI 消息到来后,末尾不再是 user,Loading 组自动消失
108
+ - **分享预览**(`renderMode === RenderMode.Share`)**不会**注入 Loading,避免分享页出现「请求中」占位
91
109
 
92
110
  **触发示例**:
93
111
 
@@ -127,6 +145,7 @@ if (messages.at(-1)?.role === MessageRole.User) {
127
145
  - **默认插槽**:可通过默认插槽自定义加载文案,未传入时显示内置的 "请求中..."
128
146
  - **i18n 支持**:默认文案 "请求中..." 通过内置 `t()` 函数处理,英文环境自动显示 "Requesting..."
129
147
  - **选择模式**:`MessageContainer` 开启 `enableSelection` 时,Loading 消息组不显示复选框
148
+ - **分享模式**:`renderMode === RenderMode.Share` 时不自动注入 Loading
130
149
  - **自动生命周期**:Loading 组随消息列表变化自动插入/移除,无需手动控制
131
150
 
132
151
  ## API
@@ -26,7 +26,7 @@
26
26
  - **消息分组**:将连续的非用户消息合并为一组,每组共享一个工具栏
27
27
  - **Tool 消息关联**:自动将 `role: 'tool'` 消息注入到对应 Assistant 消息的 toolCall 中
28
28
  - **Loading 自动注入**:末尾为用户消息时,自动追加 Loading 动画组
29
- - **滚动管理**:`messageStatus` 为流式、等待响应或请求中(`streaming` / `pending` / `fetching`)时显示「停止生成」,离开底部时显示「返回底部」;`renderMode` 为 `Share` 时不显示「停止生成」
29
+ - **滚动管理**:`messageStatus` 为流式、等待响应或请求中(`streaming` / `pending` / `fetching`)时显示「停止生成」,离开底部时显示「返回底部」;`renderMode` 为 `Share` 时不显示「停止生成」。挂载时通过 `jumpToBottom()` 瞬时贴底,避免切换会话时从顶部平滑滚到底部的动画
30
30
  - **多选模式**:支持按消息组勾选,用户消息与 AI 回复联动选中
31
31
 
32
32
  ## 基础用法
@@ -124,10 +124,29 @@
124
124
  - `renderMode === RenderMode.Share`(分享预览模式)
125
125
  - 消息组的 `pause` 为 `true`(来源于 `message.property?.extra?.pause`)
126
126
  - 多选模式(`enableSelection`)开启且消息组不是 Loading 类型
127
+ - AI 消息组的时间通过 `MessageTools` 的 `#append` 插槽渲染在工具图标右侧,取值为组内**最后一条**带 `createdAt` 的消息(即本轮回答完成时间);组内 `reasoning` / `activity` 等子消息不单独展示时间,全组都没有 `createdAt` 时不展示
127
128
  - `renderMode === RenderMode.Test` 时,工具栏会过滤掉「分享」按钮,其余正常
128
129
  - `renderMode === RenderMode.Share` 时,`message-group-messages` 自动添加 `message-group-enabled-selection` 类名(与 `enableSelection: true` 一致的多选视觉效果)
129
130
  - Loading 消息组的 `type` 是 `MessageRole.Loading`,不显示工具栏和多选 Checkbox
130
131
 
132
+ ## DOM 定位标识
133
+
134
+ 为方便业务方通过 `document.querySelector` 定位消息(埋点、自动化测试、外部滚动锚定等),渲染结构上固定输出两层标识:
135
+
136
+ | 层级 | 选择器 | 值 |
137
+ | -------- | ------------------------------------- | --------------------------------------------------- |
138
+ | 消息组 | `.message-group[data-message-group-id]` | `MessageGroup.uid`(与外层 `id` 同值) |
139
+ | 单条消息 | `.ai-message-item[data-message-id]` | `message.id`,缺失时回退 `message.uid`;两者都无则不输出该属性 |
140
+
141
+ ```js
142
+ // 定位某条消息
143
+ document.querySelector('[data-message-id="123"]');
144
+ // 定位某个消息组下的全部消息
145
+ document.querySelectorAll('[data-message-group-id="xxx"] [data-message-id]');
146
+ ```
147
+
148
+ `.ai-message-item` 是 `MessageContainer` 统一包裹的容器,`#default` 插槽自定义渲染的消息同样被它包裹,因此无论用默认 `MessageRender` 还是自定义渲染,标识都一致存在。
149
+
131
150
  ## 等待响应(Loading 自动注入)
132
151
 
133
152
  当 `messages` 末尾为 `role: 'user'` 时,自动追加 Loading 消息组,展示 AI 正在处理的加载动画(`renderMode` 为 `Share` 时不追加,且 `MessageContainer` 会过滤 Loading 组):
@@ -533,10 +552,11 @@ AI 回复状态为 `error` 时,消息以错误样式展示:
533
552
  | 按钮 | 显示条件 | 点击行为 |
534
553
  | ------------ | ---------------------------------------------------------------------------------------------- | ---------------------- |
535
554
  | 「停止生成」 | `messageStatus` 为 `streaming`、`pending`、`fetching` 或 `stop-loading`(停止中 loading 态),且 `renderMode` 不为 `Share` | 触发 `@stop-streaming` |
536
- | 「返回底部」 | `debouncedShowScrollBottomBtn`(距底部 > 100px,且防抖 300ms 后才显示/隐藏) | 滚动到消息列表底部 |
555
+ | 「返回底部」 | `debouncedShowScrollBottomBtn`(距底部 > 100px,且防抖 300ms 后才显示/隐藏) | 平滑滚动到消息列表底部(显式 `toScrollBottom('smooth')`) |
537
556
 
538
557
  > **防抖说明**:「返回底部」按钮的显隐使用 300ms 防抖,避免快速滚动时按钮频繁闪烁。隐藏时立即生效(无防抖),显示时延迟 300ms。
539
558
 
559
+ > **首屏 / 切换会话贴底**:`MessageContainer` 挂载时若已有消息组,会立即调用 `jumpToBottom()`,并在下一帧再补一次,避免历史消息渲染过程中出现「从顶部滚到底部」的动画。流式输出场景下的小幅跟随仍由 markdown 挂载触发的 `toScrollBottom()`(距底较近时走 smooth)完成。
540
560
  ## API
541
561
 
542
562
  ### Props
@@ -613,32 +633,16 @@ enum MessageToolsStatus {
613
633
  Hidden = 'hidden',
614
634
  }
615
635
 
616
- // 消息角色
617
- enum MessageRole {
618
- User = 'user',
619
- Assistant = 'assistant',
620
- Tool = 'tool',
621
- Reasoning = 'reasoning',
622
- Activity = 'activity',
623
- Info = 'info',
624
- Interrupt = 'interrupt',
625
- Loading = 'loading',
626
- }
627
-
628
- // 消息状态
629
- enum MessageStatus {
630
- Pending = 'pending',
631
- Streaming = 'streaming',
632
- Complete = 'complete',
633
- Error = 'error',
634
- Stop = 'stop',
635
- Disabled = 'disabled',
636
- }
636
+ // 消息角色 / 消息状态完整枚举见常量文档,勿在此维护副本
637
+ // MessageRole、MessageStatus → ../../types/constants
637
638
  ```
638
639
 
640
+ > `MessageRole` / `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。
641
+
639
642
  ## 关联组件
640
643
 
641
644
  - [MessageRender](/components/message/message-render) — 按组渲染每条消息时委托使用
645
+ - [MessageTime](/components/feedback/message-time) — AI 消息组工具栏右侧的时间
642
646
  - [InterruptMessage 中断消息](/components/agent/interrupt-message) — `role: 'interrupt'` 的渲染与 `onInterruptResume` 透传
643
647
  - [ChatInput](/components/input/chat-input) — 常与输入区组合构成完整对话界面
644
648
  - [LoadingMessage](/components/message/loading-message) — 末尾为用户消息时自动追加加载组
@@ -13,15 +13,16 @@
13
13
  <!-- FULL DOC -->
14
14
 
15
15
  # MessageRender 消息渲染器
16
+
16
17
  ## 源码事实
17
18
 
18
19
  - **源码位置**:`src/components/chat-message/message-render/message-render.vue`
19
20
  - **能力域**:消息系统
20
- - **能力说明**:按 message.role 分发到用户、助手、工具、推理、活动、中断等消息组件。
21
+ - **能力说明**:按 `message.role` 分发到用户、助手、工具、推理、活动、中断等消息组件。
21
22
 
22
- > **能力域**:消息系统
23
+ > **导出说明**:`MessageRender` **已**从 `@blueking/chat-x` 包入口导出,消费方可直接 import。下文 `MessageRenderComp` 为文档站相对路径 demo,与包入口行为一致。
23
24
 
24
- 统一的消息渲染入口,通过 `message.role` 字段自动派发到对应的子组件。整个渲染过程由一个 `computed` 属性完成,无额外状态。
25
+ 统一的消息渲染入口,通过 `message.role` 派发到对应子组件;由单个 `computed` 完成,无额外状态。
25
26
 
26
27
  ## 渲染架构
27
28
 
@@ -151,7 +152,7 @@ MessageRender
151
152
 
152
153
  ### 流式输出(streaming)
153
154
 
154
- `status: 'streaming'` 时,`AssistantMessage` 内部展示打字光标,内容可实时追加:
155
+ `status: 'streaming'` 时,默认回退的 `ContentRender` / `MarkdownContent` 会按流式规则补全未闭合语法;内容由外部逐步追加:
155
156
 
156
157
  ```vue
157
158
  <script setup lang="ts">
@@ -202,65 +203,74 @@ MessageRender
202
203
 
203
204
  ## 自定义内容渲染(default slot)
204
205
 
205
- `default` slot **仅对 `role: 'assistant'` 生效**,用于替换默认的 `ContentRender`。未提供 slot 时回退渲染 `<ContentRender :content="message.content" :status="message.status" />`。
206
+ `default` slot **仅对 `role: 'assistant'` 生效**,用于替换默认的 `ContentRender`。
207
+
208
+ 未提供 slot 时,内部回退为:
209
+
210
+ ```ts
211
+ h(ContentRender, { content: message.content || '', status: message.status }, /* codeHeader */)
212
+ ```
213
+
214
+ 自定义 slot 时,运行时参数来自 `AssistantMessage` 的 `v-bind`,**仅保证 `{ content }`**。需要 `status` 时请从外层 `message.status` 读取(不要依赖 slot 内的 `status`)。
206
215
 
207
216
  ```vue
208
217
  <template>
209
- <MessageRender
210
- :message="message"
211
- :on-action="handleAction"
212
- >
213
- <template #default="{ content, status }">
214
- <!-- 完全接管内容区域渲染 -->
218
+ <MessageRender :message="message">
219
+ <template #default="{ content }">
215
220
  <MyMarkdownRenderer
216
221
  :content="content"
217
- :streaming="status === 'streaming'"
222
+ :streaming="message.status === 'streaming'"
218
223
  />
219
224
  </template>
220
225
  </MessageRender>
221
226
  </template>
222
227
  ```
223
228
 
224
- slot 参数类型与 `AssistantMessage` 的 slot 保持一致(`Partial<AssistantMessage>`),主要使用:
225
-
226
- | 参数 | 类型 | 说明 |
227
- | --------- | --------------- | ------------ |
228
- | `content` | `string` | 消息内容 |
229
- | `status` | `MessageStatus` | 当前消息状态 |
229
+ | 参数 | 类型 | 说明 |
230
+ | --------- | -------- | ---------------------------- |
231
+ | `content` | `string` | 消息内容(运行时保证) |
230
232
 
231
- ## 与 MessageContainer 配合
233
+ ## 与 MessageContainer / ChatContainer 配合
232
234
 
233
- 在 `MessageContainer` 的 `default` slot 中使用,可替换默认的 `MessageRender` 渲染逻辑:
235
+ 自定义 `ChatContainer` 的 `#message` 时,插槽参数只有 `message` / `messageToolsStatus` / `onInterruptResume`。用户消息工具相关回调需由外层自行绑定透传,否则删除/编辑/复制/引用会失效(AI 消息工具栏在 `MessageContainer` 内渲染,不受 `#message` 影响):
234
236
 
235
237
  ```vue
236
238
  <template>
237
- <MessageContainer
239
+ <ChatContainer
238
240
  :messages="messages"
239
241
  :message-status="messageStatus"
240
242
  :on-agent-action="handleAgentAction"
241
243
  :on-user-action="handleUserAction"
242
- @stop-streaming="handleStopStreaming"
244
+ :common-tippy-options="commonTippyOptions"
243
245
  >
244
- <template #default="{ message, messageToolsStatus }">
245
- <!-- 自定义 MessageRender 的行为 -->
246
+ <template #message="{ message, messageToolsStatus, onInterruptResume }">
246
247
  <MessageRender
247
248
  :message="message"
248
249
  :message-tools-status="messageToolsStatus"
249
250
  :on-action="handleUserAction"
250
- :on-input-confirm="handleInputConfirm"
251
+ :on-input-confirm="(content, docSchema) => handleUserInputConfirm(message, content, docSchema)"
252
+ :on-shortcut-confirm="formModel => handleUserShortcutConfirm(message, formModel)"
253
+ :tippy-options="commonTippyOptions"
254
+ :on-interrupt-resume="onInterruptResume"
251
255
  >
252
256
  <template
253
257
  v-if="message.role === 'assistant'"
254
- #default="{ content, status }"
258
+ #default="{ content }"
255
259
  >
256
260
  <MyCustomContent
257
261
  :content="content"
258
- :status="status"
262
+ :status="message.status"
263
+ />
264
+ </template>
265
+ <template #codeHeader="{ language, token }">
266
+ <MyCodeActions
267
+ :language="language"
268
+ :token="token"
259
269
  />
260
270
  </template>
261
271
  </MessageRender>
262
272
  </template>
263
- </MessageContainer>
273
+ </ChatContainer>
264
274
  </template>
265
275
  ```
266
276
 
@@ -280,11 +290,11 @@ slot 参数类型与 `AssistantMessage` 的 slot 保持一致(`Partial<Assista
280
290
 
281
291
  ### Slots
282
292
 
283
- | 插槽名 | 参数 | 说明 |
284
- | ---------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
285
- | answeredQuestion | `{ item, index, status }` | 自定义 UserQuestion 已回答回显,透传给 InterruptMessageRender → UserQuestionAnsweredCard 的 `#answer` |
286
- | codeHeader | `{ language: string; token: Token[] }` | 代码块头部自定义操作区域,透传给 ContentRender → MarkdownContent → CodeContent;**仅对 assistant 生效** |
287
- | default | `{ content: string, status: MessageStatus }` | 替换 AssistantMessage 的内容区域渲染;**仅对 `role: 'assistant'` 生效** |
293
+ | 插槽名 | 参数 | 说明 |
294
+ | ---------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------- |
295
+ | answeredQuestion | `{ item, index, status }` | 自定义 UserQuestion 已回答回显,透传给 InterruptMessageRender → UserQuestionAnsweredCard 的 `#answer` |
296
+ | codeHeader | `{ language: string; token: Token[] }` | 代码块头部自定义操作区域,透传给 ContentRender → MarkdownContent → CodeContent;**仅对 assistant 生效** |
297
+ | default | `{ content: string }` | 替换 AssistantMessage 内容区;**仅对 assistant 生效**;运行时仅保证 `content`(`status` 请读外层 message) |
288
298
 
289
299
  ## 消息类型映射
290
300
 
@@ -305,34 +315,12 @@ slot 参数类型与 `AssistantMessage` 的 slot 保持一致(`Partial<Assista
305
315
  ```typescript
306
316
  import { MessageRole, MessageStatus, MessageToolsStatus, type Message, type IToolBtn } from '@blueking/chat-x';
307
317
 
308
- // 消息角色
309
- enum MessageRole {
310
- User = 'user',
311
- Assistant = 'assistant',
312
- Info = 'info',
313
- Reasoning = 'reasoning',
314
- Tool = 'tool',
315
- Activity = 'activity',
316
- Loading = 'loading',
317
- }
318
-
319
- // 消息状态
320
- enum MessageStatus {
321
- Pending = 'pending',
322
- Streaming = 'streaming',
323
- Complete = 'complete',
324
- Error = 'error',
325
- Stop = 'stop',
326
- Disabled = 'disabled',
327
- }
328
-
329
- // 工具按钮状态(仅转发给 UserMessage)
330
- enum MessageToolsStatus {
331
- Disabled = 'disabled',
332
- Hidden = 'hidden',
333
- }
318
+ // MessageRole / MessageStatus 完整枚举见 ../../types/constants
319
+ // MessageToolsStatus:Disabled | Hidden(仅转发给 UserMessage)
334
320
  ```
335
321
 
322
+ > `MessageRole` / `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。
323
+
336
324
  ## 关联组件
337
325
 
338
326
  - [MessageContainer](/components/setup/message-container) — 内部按组调用以渲染每条消息
@@ -0,0 +1,180 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ 按 createdAt 展示消息时间,四档格式:今天 `12:00`、昨天 `昨天 12:00`、今年内更早 `3-12 12:00`、非今年 `2025-3-12 12:00`; 时区取 props.timezone,未传时回退 injectGlobalConfig().timezone(由 ChatContainer 的 timezone prop 注入),都没有则用浏览器时区; 无值或非法时间不渲染任何 DOM。通常通过 MessageTools 的 prepend / append 插槽使用。 源码位置:src/components/message-tools/message-time/message-time.vue。
5
+
6
+ ### 关联组件
7
+ - **message-tools** — 通过 prepend / append 插槽嵌入工具栏
8
+ - **user-message** — 用户消息在工具栏左侧展示时间
9
+ - **message-container** — AI 消息组在工具栏右侧展示本轮回答时间
10
+
11
+ ---
12
+ <!-- FULL DOC -->
13
+
14
+ # MessageTime 消息时间
15
+
16
+ ## 源码事实
17
+
18
+ - **源码位置**:`src/components/message-tools/message-time/message-time.vue`
19
+ - **格式化工具**:`src/components/message-tools/message-time/format-message-time.ts`
20
+ - **能力域**:工具与反馈
21
+ - **能力说明**:按「今天 / 昨天 / 今年内 / 跨年」四档格式展示消息创建时间。
22
+
23
+ > **能力域**:工具与反馈
24
+
25
+ 展示单条消息(或一组 AI 回答)的创建时间。组件本身只负责格式化与渲染一段文本,**位置由使用方决定**——项目内通过 `MessageTools` 的 `prepend` / `append` 插槽嵌入工具栏。
26
+
27
+ ## 格式规则
28
+
29
+ 时间按与「今天」的日历日差值分四档,同一档内时分固定 `HH:mm`(24 小时制,补零),月日**不补零**:
30
+
31
+ | 档位 | 判定条件 | 输出示例 |
32
+ | ------------ | ---------------------- | --------------- |
33
+ | 今天 | 与今天同一日历日 | `12:00` |
34
+ | 昨天 | 与今天相差 1 个日历日 | `昨天 12:00` |
35
+ | 今年内更早 | 相差 ≥ 2 天且年份相同 | `3-12 12:00` |
36
+ | 非今年 | 年份不同 | `2025-3-12 12:00` |
37
+
38
+ - 分档与展示取**同一时区**的日历日:既避免「昨天 23:59」与「今天 00:01」因毫秒差不足一天被判成同一天,也避免按浏览器时区分档、按配置时区显示时分导致的错位
39
+ - `昨天` 走 `t('昨天')` 国际化,英文环境输出 `Yesterday 12:00`
40
+
41
+ ## 基础用法
42
+
43
+ `createdAt` 接受 ISO 字符串或毫秒时间戳:
44
+
45
+ ```vue
46
+ <template>
47
+ <MessageTime :created-at="message.createdAt" />
48
+ </template>
49
+
50
+ <script setup lang="ts">
51
+ import { MessageTime } from '@blueking/chat-x';
52
+
53
+ const message = {
54
+ id: '1',
55
+ messageId: '1',
56
+ role: 'user',
57
+ content: '你好',
58
+ status: 'completed',
59
+ createdAt: '2026-08-17T04:00:00.000Z',
60
+ };
61
+ </script>
62
+ ```
63
+
64
+ > **无值不渲染**:`createdAt` 为空、为空字符串或无法解析成合法时间时,组件不渲染任何 DOM(`v-if`),使用方无需额外判空。
65
+
66
+ ## 时区配置
67
+
68
+ 时区按以下优先级取值,均未配置时使用**浏览器时区**:
69
+
70
+ ```
71
+ props.timezone
72
+ └─ 未传 → injectGlobalConfig()?.timezone(由 ChatContainer 的 timezone prop 注入)
73
+ └─ 未配置 → 浏览器时区
74
+ ```
75
+
76
+ ```vue
77
+ <template>
78
+ <!-- 整个会话统一按北京时间展示 -->
79
+ <ChatContainer
80
+ :messages="messages"
81
+ timezone="Asia/Shanghai"
82
+ />
83
+ </template>
84
+ ```
85
+
86
+ ```vue
87
+ <template>
88
+ <!-- 单个实例覆盖全局配置 -->
89
+ <MessageTime
90
+ :created-at="message.createdAt"
91
+ timezone="UTC"
92
+ />
93
+ </template>
94
+ ```
95
+
96
+ - 取值为 [IANA 时区名](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)(如 `Asia/Shanghai`、`UTC`、`America/New_York`)
97
+ - 传入非法时区名时回退到浏览器时区,不会导致渲染失败
98
+ - 同一时区的 `Intl.DateTimeFormat` 实例内部有缓存,长会话中不会为每条消息重复构造
99
+
100
+ ## 在消息工具栏中的使用
101
+
102
+ `MessageTools` 提供 `prepend`(工具图标左侧)与 `append`(工具图标右侧)两个插槽,项目内的时间位置即由此决定:
103
+
104
+ | 场景 | 插槽 | 时间取值 |
105
+ | ------------ | --------- | -------------------------------------------- |
106
+ | 用户消息 | `prepend` | 该条消息的 `createdAt` |
107
+ | AI 消息组 | `append` | 组内**最后一条**带 `createdAt` 的消息,即本轮回答完成时间 |
108
+
109
+ ```vue
110
+ <template>
111
+ <MessageTools :on-action="handleAction">
112
+ <template #append>
113
+ <MessageTime :created-at="createdAt" />
114
+ </template>
115
+ </MessageTools>
116
+ </template>
117
+
118
+ <script setup lang="ts">
119
+ import { MessageTime, MessageTools } from '@blueking/chat-x';
120
+ </script>
121
+ ```
122
+
123
+ > 组内 `reasoning` / `activity` 等子消息不单独展示时间,一个 AI 回答组只显示一次。
124
+
125
+ ## API
126
+
127
+ ### Props
128
+
129
+ | 属性名 | 类型 | 必填 | 默认值 | 说明 |
130
+ | --------- | ------------------ | ---- | ------ | -------------------------------------------------------------------- |
131
+ | createdAt | `number \| string` | 否 | — | 消息创建时间,ISO 字符串或毫秒时间戳;无值或非法时不渲染 |
132
+ | timezone | `string` | 否 | — | IANA 时区名;优先于全局配置,两者都未配置时按浏览器时区展示 |
133
+
134
+ ### Events / Slots / Expose
135
+
136
+ 无。
137
+
138
+ ### 全局配置依赖
139
+
140
+ 通过 `injectGlobalConfig()` 读取 `timezone`。祖先需已调用 `useGlobalConfig()`(通常由 `ChatContainer` 的 `timezone` prop 注册);无 Provider 时按浏览器时区展示。
141
+
142
+ ## 类型定义
143
+
144
+ ```typescript
145
+ export type MessageTimeProps = {
146
+ createdAt?: number | string;
147
+ timezone?: string;
148
+ };
149
+
150
+ // 独立可用的格式化函数(组件内部使用,未从包入口导出)
151
+ declare const formatMessageTime: (createdAt?: number | string, timezone?: string) => string;
152
+ ```
153
+
154
+ ## 样式说明
155
+
156
+ ```scss
157
+ .ai-message-time {
158
+ flex: none;
159
+ font-size: var(--ai-font-size, 12px);
160
+ line-height: 16px;
161
+ color: $color-text-secondary;
162
+ white-space: nowrap;
163
+ }
164
+ ```
165
+
166
+ - 字号跟随 `--ai-font-size`(`ChatContainer` 的 `size` 档位),颜色使用次要文本语义色
167
+ - `flex: none` + `nowrap` 保证在工具栏 flex 布局中不被压缩换行
168
+
169
+ ## 注意事项
170
+
171
+ 1. **时间来源**:`createdAt` 由消息层(`chat-helper`)写入 `BaseMessage`,组件不参与取数
172
+ 2. **不做相对时间**:不提供「几分钟前」这类相对描述,四档格式固定
173
+ 3. **空值语义**:不渲染而非渲染占位,工具栏侧的 `prepend` / `append` 包裹容器会因 `:empty` 收起,不留多余间距
174
+
175
+ ## 关联组件
176
+
177
+ - [MessageTools](/components/feedback/message-tools) — 通过 `prepend` / `append` 插槽嵌入
178
+ - [UserMessage](/components/message/user-message) — 用户消息时间位置
179
+ - [MessageContainer](/components/setup/message-container) — AI 消息组时间位置
180
+ - [useGlobalConfig](/composables/use-global-config) — `timezone` 全局配置