@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.
- package/dist/ag-ui/types/constants.d.ts +1 -0
- package/dist/ag-ui/types/file.d.ts +13 -0
- package/dist/ag-ui/types/index.d.ts +1 -0
- package/dist/ag-ui/types/messages.d.ts +4 -0
- package/dist/components/chat-message/assistant-message/assistant-message.vue.d.ts +12 -1
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-file-card.vue.d.ts +12 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/artifact-preview-host.vue.d.ts +11 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/preview-strategy.d.ts +8 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/code-preview.vue.d.ts +8 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/html-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/image-preview.vue.d.ts +7 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/markdown-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/txt-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/url-iframe-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/use-artifact-preview-loader.d.ts +22 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue.d.ts +13 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/message-artifacts.vue.d.ts +9 -0
- package/dist/components/chat-message/interrupt-message/user-question/use-user-question.d.ts +7 -2
- package/dist/components/chat-message/user-message/user-message.vue.d.ts +15 -2
- package/dist/components/file-icon/file-icon.vue.d.ts +7 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/message-tools/message-time/format-message-time.d.ts +8 -0
- package/dist/components/message-tools/message-time/message-time.vue.d.ts +8 -0
- package/dist/components/message-tools/message-tools.vue.d.ts +11 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/use-artifact-preview.d.ts +49 -0
- package/dist/composables/use-container-scroll.d.ts +9 -2
- package/dist/composables/use-custom-tab.d.ts +7 -3
- package/dist/composables/use-global-config.d.ts +3 -0
- package/dist/composables/use-message-group.d.ts +505 -0
- package/dist/icons/file-icons.d.ts +4 -0
- package/dist/icons/file.d.ts +6 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons/tools.d.ts +3 -0
- package/dist/index.css +1 -1
- package/dist/index.js +3203 -2368
- package/dist/index.js.map +1 -1
- package/dist/lang/lang.d.ts +9 -1
- package/dist/mcp/generated/docs/activity-message.md +122 -97
- package/dist/mcp/generated/docs/assistant-message.md +146 -75
- package/dist/mcp/generated/docs/chat-container.md +121 -38
- package/dist/mcp/generated/docs/chat-input.md +2 -10
- package/dist/mcp/generated/docs/constants.md +3 -1
- package/dist/mcp/generated/docs/content-render.md +2 -10
- package/dist/mcp/generated/docs/execution-summary.md +3 -3
- package/dist/mcp/generated/docs/file-artifact-panel.md +293 -0
- package/dist/mcp/generated/docs/file-icon.md +111 -0
- package/dist/mcp/generated/docs/info-message.md +29 -12
- package/dist/mcp/generated/docs/interrupt.md +1 -0
- package/dist/mcp/generated/docs/loading-message.md +36 -17
- package/dist/mcp/generated/docs/message-container.md +27 -23
- package/dist/mcp/generated/docs/message-render.md +47 -59
- package/dist/mcp/generated/docs/message-time.md +180 -0
- package/dist/mcp/generated/docs/message-tools.md +47 -12
- package/dist/mcp/generated/docs/messages.md +9 -0
- package/dist/mcp/generated/docs/reasoning-message.md +17 -20
- package/dist/mcp/generated/docs/tool-message.md +61 -45
- package/dist/mcp/generated/docs/toolcall-render.md +18 -10
- package/dist/mcp/generated/docs/use-artifact-preview.md +234 -0
- package/dist/mcp/generated/docs/use-container-scroll.md +6 -2
- package/dist/mcp/generated/docs/use-custom-tab.md +25 -8
- package/dist/mcp/generated/docs/use-global-config.md +15 -5
- package/dist/mcp/generated/docs/use-message-group.md +37 -5
- package/dist/mcp/generated/docs/user-message.md +191 -121
- package/dist/mcp/generated/docs/user-question-card.md +6 -3
- package/dist/mcp/generated/index.json +144 -18
- package/dist/mcp/index.js +0 -0
- package/dist/utils/file-type.d.ts +14 -0
- package/dist/utils/index.d.ts +1 -0
- 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
|
-
|
|
24
|
+
加载等待状态组件:`AiLoading`(18px)+ 默认文案「请求中...」。可通过默认插槽自定义文案。
|
|
24
25
|
|
|
25
|
-
>
|
|
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
|
-
<
|
|
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 {
|
|
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
|
-
|
|
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
|
-
`
|
|
84
|
+
`useMessageGroup` 构建分组时,若**最后一条为用户消息**且 **`renderMode !== RenderMode.Share`**,自动在末尾追加 Loading 组:
|
|
71
85
|
|
|
72
86
|
```typescript
|
|
73
|
-
//
|
|
74
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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`
|
|
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'`
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
|
227
|
-
| --------- | --------------- | ------------ |
|
|
228
|
-
| `content` | `string` | 消息内容 |
|
|
229
|
-
| `status` | `MessageStatus` | 当前消息状态 |
|
|
229
|
+
| 参数 | 类型 | 说明 |
|
|
230
|
+
| --------- | -------- | ---------------------------- |
|
|
231
|
+
| `content` | `string` | 消息内容(运行时保证) |
|
|
230
232
|
|
|
231
|
-
## 与 MessageContainer 配合
|
|
233
|
+
## 与 MessageContainer / ChatContainer 配合
|
|
232
234
|
|
|
233
|
-
|
|
235
|
+
自定义 `ChatContainer` 的 `#message` 时,插槽参数只有 `message` / `messageToolsStatus` / `onInterruptResume`。用户消息工具相关回调需由外层自行绑定透传,否则删除/编辑/复制/引用会失效(AI 消息工具栏在 `MessageContainer` 内渲染,不受 `#message` 影响):
|
|
234
236
|
|
|
235
237
|
```vue
|
|
236
238
|
<template>
|
|
237
|
-
<
|
|
239
|
+
<ChatContainer
|
|
238
240
|
:messages="messages"
|
|
239
241
|
:message-status="messageStatus"
|
|
240
242
|
:on-agent-action="handleAgentAction"
|
|
241
243
|
:on-user-action="handleUserAction"
|
|
242
|
-
|
|
244
|
+
:common-tippy-options="commonTippyOptions"
|
|
243
245
|
>
|
|
244
|
-
<template #
|
|
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="
|
|
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
|
|
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
|
-
</
|
|
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 }`
|
|
286
|
-
| codeHeader | `{ language: string; token: Token[] }`
|
|
287
|
-
| default | `{ content: string
|
|
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
|
-
|
|
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` 全局配置
|