@blueking/chat-x 0.0.5 → 0.0.6

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 (80) hide show
  1. package/dist/mcp/generated/docs/activity-message.md +428 -0
  2. package/dist/mcp/generated/docs/ai-image.md +227 -0
  3. package/dist/mcp/generated/docs/ai-loading.md +129 -0
  4. package/dist/mcp/generated/docs/ai-selection.md +436 -0
  5. package/dist/mcp/generated/docs/animation-text.md +199 -0
  6. package/dist/mcp/generated/docs/assistant-message.md +424 -0
  7. package/dist/mcp/generated/docs/chat-container.md +365 -0
  8. package/dist/mcp/generated/docs/chat-input.md +625 -0
  9. package/dist/mcp/generated/docs/cite-content.md +138 -0
  10. package/dist/mcp/generated/docs/code-content.md +199 -0
  11. package/dist/mcp/generated/docs/common-error-content.md +70 -0
  12. package/dist/mcp/generated/docs/constants.md +216 -0
  13. package/dist/mcp/generated/docs/content-render.md +238 -0
  14. package/dist/mcp/generated/docs/delete-tool.md +188 -0
  15. package/dist/mcp/generated/docs/desc-panel.md +139 -0
  16. package/dist/mcp/generated/docs/execution-summary.md +126 -0
  17. package/dist/mcp/generated/docs/file-content.md +300 -0
  18. package/dist/mcp/generated/docs/file-upload-btn.md +174 -0
  19. package/dist/mcp/generated/docs/flow-message.md +305 -0
  20. package/dist/mcp/generated/docs/highlight-keyword.md +144 -0
  21. package/dist/mcp/generated/docs/image-content.md +178 -0
  22. package/dist/mcp/generated/docs/image-preview-group.md +181 -0
  23. package/dist/mcp/generated/docs/image-preview.md +224 -0
  24. package/dist/mcp/generated/docs/info-message.md +124 -0
  25. package/dist/mcp/generated/docs/key-value-content.md +124 -0
  26. package/dist/mcp/generated/docs/latex-content.md +196 -0
  27. package/dist/mcp/generated/docs/loading-message.md +171 -0
  28. package/dist/mcp/generated/docs/markdown-content.md +186 -0
  29. package/dist/mcp/generated/docs/markdown-latex.md +208 -0
  30. package/dist/mcp/generated/docs/markdown-mermaid.md +250 -0
  31. package/dist/mcp/generated/docs/mermaid-content.md +185 -0
  32. package/dist/mcp/generated/docs/message-container.md +534 -0
  33. package/dist/mcp/generated/docs/message-render.md +329 -0
  34. package/dist/mcp/generated/docs/message-tools.md +376 -0
  35. package/dist/mcp/generated/docs/messages.md +472 -0
  36. package/dist/mcp/generated/docs/overflow-tips.md +209 -0
  37. package/dist/mcp/generated/docs/reasoning-message.md +233 -0
  38. package/dist/mcp/generated/docs/reference-content.md +132 -0
  39. package/dist/mcp/generated/docs/scroll-btn.md +155 -0
  40. package/dist/mcp/generated/docs/selection-footer.md +75 -0
  41. package/dist/mcp/generated/docs/shortcut-btn.md +202 -0
  42. package/dist/mcp/generated/docs/shortcut-btns.md +264 -0
  43. package/dist/mcp/generated/docs/shortcut-render.md +418 -0
  44. package/dist/mcp/generated/docs/text-content.md +74 -0
  45. package/dist/mcp/generated/docs/theme.md +388 -0
  46. package/dist/mcp/generated/docs/tool-btn.md +254 -0
  47. package/dist/mcp/generated/docs/tool-message.md +217 -0
  48. package/dist/mcp/generated/docs/toolcall-render.md +299 -0
  49. package/dist/mcp/generated/docs/use-animation-text.md +198 -0
  50. package/dist/mcp/generated/docs/use-clipboard.md +206 -0
  51. package/dist/mcp/generated/docs/use-command-selection.md +128 -0
  52. package/dist/mcp/generated/docs/use-container-scroll.md +56 -0
  53. package/dist/mcp/generated/docs/use-custom-tab.md +122 -0
  54. package/dist/mcp/generated/docs/use-global-config.md +154 -0
  55. package/dist/mcp/generated/docs/use-menu-keydown.md +164 -0
  56. package/dist/mcp/generated/docs/use-message-group.md +175 -0
  57. package/dist/mcp/generated/docs/use-observer-visible-list.md +189 -0
  58. package/dist/mcp/generated/docs/use-parent-scrolling.md +46 -0
  59. package/dist/mcp/generated/docs/user-feedback.md +229 -0
  60. package/dist/mcp/generated/docs/user-message.md +347 -0
  61. package/dist/mcp/generated/index.json +1311 -0
  62. package/dist/mcp/index.d.ts +2 -0
  63. package/dist/mcp/index.js +42 -0
  64. package/dist/mcp/index.js.map +1 -0
  65. package/dist/mcp/server.d.ts +2 -0
  66. package/dist/mcp/server.js +43 -0
  67. package/dist/mcp/server.js.map +1 -0
  68. package/dist/mcp/tools/get-component-doc.d.ts +19 -0
  69. package/dist/mcp/tools/get-component-doc.js +60 -0
  70. package/dist/mcp/tools/get-component-doc.js.map +1 -0
  71. package/dist/mcp/tools/list-components.d.ts +35 -0
  72. package/dist/mcp/tools/list-components.js +147 -0
  73. package/dist/mcp/tools/list-components.js.map +1 -0
  74. package/dist/mcp/tools/search-docs.d.ts +14 -0
  75. package/dist/mcp/tools/search-docs.js +82 -0
  76. package/dist/mcp/tools/search-docs.js.map +1 -0
  77. package/dist/mcp/utils/doc-loader.d.ts +35 -0
  78. package/dist/mcp/utils/doc-loader.js +64 -0
  79. package/dist/mcp/utils/doc-loader.js.map +1 -0
  80. package/package.json +5 -7
@@ -0,0 +1,305 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ FlowMessage 用于展示 BkFlow/流水线类流程的执行统计、节点分组与节点详情(含 Tab 详情)。消息类型为 flow,需在业务布局中显式嵌入; 标准 MessageRender 角色分发未包含 flow。与 Activity 的 FlowAgent 模式同属流程可视化但组件与数据模型不同。
5
+
6
+ ### 关联组件
7
+ - **activity-message** — Activity 的 flow-agent 模式同样展示流程执行,场景互补
8
+ - **message-container** — 嵌入对话列表时需与消息容器等配合布局
9
+ - **execution-summary** — 对话级执行摘要与单条流程消息可共同构成执行态 UI
10
+
11
+ ---
12
+ <!-- FULL DOC -->
13
+
14
+ # FlowMessage 流程消息
15
+
16
+ > **层级**:分子组件 · **功能域**:消息展示
17
+
18
+ 流程消息组件,用于展示流程编排(如标准运维 / CI/CD 流水线)的执行状态和节点详情。包含执行统计摘要、节点组列表、节点详情面板,提供完整的流程执行可视化能力。
19
+
20
+ ## 组件结构
21
+
22
+ ```
23
+ flow-message
24
+ ├── flow-message__stats(执行情况摘要栏)
25
+ │ ├── 执行中:N (蓝色)
26
+ │ ├── 成功:N (绿色)
27
+ │ ├── 失败:N (红色)
28
+ │ └── 挂起:N (橙色)
29
+ ├── flow-message__groups
30
+ │ └── FlowNodeGroup × N(可折叠的节点组)
31
+ │ ├── 组标题栏(折叠图标 + 状态图标 + 名称 + 耗时)
32
+ │ └── FlowNodeItem × N(节点列表)
33
+ │ ├── 状态图标 + 名称 + 耗时
34
+ │ └── 详情入口(点击 → Teleport FlowDetail)
35
+ ├── flow-message__extra(额外文本,可选)
36
+ └── <Teleport>
37
+ └── FlowDetail(节点详情面板)
38
+ ├── 基础信息 Tab
39
+ └── 输入/输出参数 Tab
40
+ ```
41
+
42
+ ## 基础用法
43
+
44
+ ```vue
45
+ <template>
46
+ <FlowMessage :content="content" />
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ const content = {
51
+ stats: { running: 1, success: 3, failed: 0, pending: 2 },
52
+ groups: [
53
+ {
54
+ id: 'group-1',
55
+ name: '部署阶段',
56
+ status: 'running',
57
+ duration: 120,
58
+ nodes: [
59
+ { id: 'node-1', name: '代码拉取', status: 'success', duration: 30 },
60
+ { id: 'node-2', name: '编译构建', status: 'success', duration: 60 },
61
+ { id: 'node-3', name: '部署上线', status: 'running', duration: 30 },
62
+ ],
63
+ },
64
+ ],
65
+ };
66
+ </script>
67
+ ```
68
+
69
+ **渲染效果**
70
+
71
+ ## 执行统计
72
+
73
+ 顶部摘要栏展示四种状态的节点数量,数量 ≥ 100 时显示为 `99+`:
74
+
75
+ | 状态 | 颜色 | 说明 |
76
+ | ------ | ---- | --------------- |
77
+ | 执行中 | 蓝色 | `stats.running` |
78
+ | 成功 | 绿色 | `stats.success` |
79
+ | 失败 | 红色 | `stats.failed` |
80
+ | 挂起 | 橙色 | `stats.pending` |
81
+
82
+ ## 带额外内容
83
+
84
+ `extraContent` 以灰色背景文本块显示在节点组下方,适合展示执行总结或错误提示:
85
+
86
+ ```vue
87
+ <script setup lang="ts">
88
+ const content = {
89
+ stats: { running: 0, success: 5, failed: 1, pending: 0 },
90
+ groups: [
91
+ {
92
+ id: 'group-1',
93
+ name: '测试阶段',
94
+ status: 'failed',
95
+ nodes: [
96
+ { id: 'node-1', name: '单元测试', status: 'success', duration: 45 },
97
+ { id: 'node-2', name: '集成测试', status: 'failed', duration: 120 },
98
+ ],
99
+ },
100
+ ],
101
+ extraContent: '流程执行失败,请检查集成测试节点的错误日志。',
102
+ };
103
+ </script>
104
+ ```
105
+
106
+ **渲染效果**
107
+
108
+ ## 节点详情
109
+
110
+ 节点数据包含 `detail` 字段时,点击节点右侧入口可打开详情面板。详情面板通过 `<Teleport>` 渲染到 `ChatContainer` 的侧边栏插槽区域(`#ai-blueking-message-slot`),包含:
111
+
112
+ - **基础信息**:流程模板、节点名称、步骤名称、执行方案、失败处理、超时控制等
113
+ - **输入参数**:`name` + `value` 键值对列表
114
+ - **输出参数**:`name` + `description` + `key` 列表
115
+
116
+ ```vue
117
+ <script setup lang="ts">
118
+ const content = {
119
+ stats: { running: 0, success: 1, failed: 0, pending: 0 },
120
+ groups: [
121
+ {
122
+ id: 'group-1',
123
+ name: '部署阶段',
124
+ status: 'success',
125
+ duration: 90,
126
+ nodes: [
127
+ {
128
+ id: 'node-1',
129
+ name: '部署上线',
130
+ status: 'success',
131
+ duration: 90,
132
+ detail: {
133
+ baseInfo: {
134
+ flowTemplate: '标准部署流程',
135
+ nodeName: '部署上线',
136
+ stepName: '执行部署',
137
+ executePlan: '蓝绿部署',
138
+ isOptional: false,
139
+ failureHandler: '自动回滚',
140
+ timeoutControl: '600s',
141
+ useLatestVersion: true,
142
+ },
143
+ inputParams: [
144
+ { name: 'env', value: 'production' },
145
+ { name: 'version', value: 'v1.2.3' },
146
+ ],
147
+ outputParams: [{ name: '部署结果', description: '部署是否成功', key: 'deploy_result' }],
148
+ },
149
+ },
150
+ ],
151
+ },
152
+ ],
153
+ };
154
+ </script>
155
+ ```
156
+
157
+ **渲染效果**
158
+
159
+ ## 节点状态图标
160
+
161
+ 每个节点根据 `status` 渲染不同的状态图标:
162
+
163
+ | 状态 | 图标 | 颜色 |
164
+ | --------- | -------- | ---- |
165
+ | `running` | 旋转加载 | 蓝色 |
166
+ | `success` | 对勾 | 绿色 |
167
+ | `failed` | 叉号 | 红色 |
168
+ | `pending` | 时钟 | 橙色 |
169
+
170
+ ## 在 MessageContainer 中的使用
171
+
172
+ `FlowMessage` 由 `MessageRender` 根据 `role: 'flow'` 自动调度渲染,通常不需要手动引入:
173
+
174
+ ```vue
175
+ <script setup lang="ts">
176
+ import { MessageContainer, type Message } from '@blueking/chat-x';
177
+
178
+ const messages: Message[] = [
179
+ {
180
+ id: '1',
181
+ messageId: '1',
182
+ role: 'flow',
183
+ status: 'complete',
184
+ content: {
185
+ stats: { running: 0, success: 2, failed: 0, pending: 0 },
186
+ groups: [
187
+ {
188
+ id: 'g1',
189
+ name: '构建阶段',
190
+ status: 'success',
191
+ duration: 180,
192
+ nodes: [
193
+ { id: 'n1', name: '代码编译', status: 'success', duration: 120 },
194
+ { id: 'n2', name: '单元测试', status: 'success', duration: 60 },
195
+ ],
196
+ },
197
+ ],
198
+ },
199
+ },
200
+ ];
201
+ </script>
202
+ ```
203
+
204
+ ## API
205
+
206
+ ### Props
207
+
208
+ 组件 Props 继承自 `Partial<FlowMessage>` 类型:
209
+
210
+ | 属性名 | 类型 | 说明 |
211
+ | --------- | -------------------- | ------------ |
212
+ | content | `FlowMessageContent` | 流程消息内容 |
213
+ | status | `MessageStatus` | 消息状态 |
214
+ | id | `string` | 客户端 ID |
215
+ | messageId | `number \| string` | 消息唯一标识 |
216
+
217
+ ## 类型定义
218
+
219
+ ```typescript
220
+ // 流程消息内容
221
+ interface FlowMessageContent {
222
+ stats: FlowExecutionStats;
223
+ groups: FlowNodeGroup[];
224
+ extraContent?: string;
225
+ }
226
+
227
+ // 执行统计
228
+ interface FlowExecutionStats {
229
+ running: number;
230
+ success: number;
231
+ failed: number;
232
+ pending: number;
233
+ }
234
+
235
+ // 节点组
236
+ interface FlowNodeGroup {
237
+ id: string;
238
+ name: string;
239
+ status: FlowNodeStatus;
240
+ duration?: number;
241
+ nodes: FlowNode[];
242
+ }
243
+
244
+ // 节点
245
+ interface FlowNode {
246
+ id: string;
247
+ name: string;
248
+ status: FlowNodeStatus;
249
+ duration?: number;
250
+ detail?: FlowNodeDetail;
251
+ }
252
+
253
+ // 节点状态
254
+ enum FlowNodeStatus {
255
+ Running = 'running',
256
+ Success = 'success',
257
+ Failed = 'failed',
258
+ Pending = 'pending',
259
+ }
260
+
261
+ // 节点详情
262
+ interface FlowNodeDetail {
263
+ baseInfo: FlowNodeBaseInfo;
264
+ inputParams: FlowNodeParam[];
265
+ outputParams: FlowNodeOutput[];
266
+ }
267
+
268
+ // 节点基础信息
269
+ interface FlowNodeBaseInfo {
270
+ flowTemplate: string;
271
+ nodeName: string;
272
+ stepName: string;
273
+ executePlan: string;
274
+ isOptional: boolean;
275
+ failureHandler: string;
276
+ timeoutControl: string;
277
+ useLatestVersion: boolean;
278
+ }
279
+
280
+ // 节点参数
281
+ interface FlowNodeParam {
282
+ name: string;
283
+ value: string;
284
+ }
285
+
286
+ // 节点输出
287
+ interface FlowNodeOutput {
288
+ name: string;
289
+ description: string;
290
+ key: string;
291
+ }
292
+ ```
293
+
294
+ ## 使用场景
295
+
296
+ - 展示标准运维(SOPS)流程的执行过程和状态
297
+ - 展示 CI/CD 流水线的节点执行情况
298
+ - 可视化任务编排的执行进度和结果
299
+ - 查看流程节点的详细配置、输入参数和输出参数
300
+
301
+ ## 关联组件
302
+
303
+ - [ActivityMessage](./activity-message.md) — FlowAgent 活动消息与流程编排展示场景相近
304
+ - [MessageContainer](./message-container.md) — 嵌入消息列表时的容器
305
+ - [ExecutionSummary](./execution-summary.md) — 对话级执行摘要
@@ -0,0 +1,144 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ HighlightKeyword 为函数式组件,从 inject 读取关键词并将匹配片段包在带样式 span 中,用于对话内搜索与列表过滤高亮。 ToolcallRender、DescPanel、FlowAgent 等场景组合使用。
5
+
6
+ ### 关联组件
7
+ - **toolcall-render** — 工具调用标题与状态文案高亮
8
+ - **desc-panel** — 工具详情键值与描述文本高亮
9
+ - **execution-summary** — 执行摘要搜索过滤与列表高亮
10
+
11
+ ---
12
+ <!-- FULL DOC -->
13
+
14
+ # HighlightKeyword 关键词高亮
15
+
16
+ > **层级**:原子组件 · **功能域**:辅助组件
17
+
18
+ 函数式组件,用于在文本中高亮匹配的搜索关键词。通过 `useKeywordInject` 从上层注入关键词,自动将匹配部分包裹在带高亮样式的 `<span>` 中。
19
+
20
+ 主要配合 `ExecutionSummary` 的搜索功能使用,实现搜索结果的视觉高亮。
21
+
22
+ ## 工作原理
23
+
24
+ ```
25
+ props.text + inject(keyword)
26
+
27
+ ├── keyword 为空 → 直接渲染原文本
28
+
29
+ └── keyword 非空
30
+ ├── 正则 split 文本为 parts[]
31
+ ├── parts.length === 1 → 无匹配,渲染原文本
32
+ └── parts.length > 1 → 匹配部分用 <span class="highlight"> 包裹
33
+ ```
34
+
35
+ 组件使用 `defineComponent` + `h()` 渲染函数实现,不依赖模板。
36
+
37
+ ## 基础用法
38
+
39
+ ```vue
40
+ <template>
41
+ <HighlightKeyword :text="text" />
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import { HighlightKeyword } from '@blueking/chat-x';
46
+
47
+ const text = '这是一段包含 Vue 3 Composition API 的示例文本';
48
+ </script>
49
+ ```
50
+
51
+ > **注意**:关键词通过 `useKeywordProvider` / `useKeywordInject`(`provide/inject`)注入,不通过 props 传入。上层需先调用 `useKeywordProvider()` 设置关键词。
52
+
53
+ **渲染效果**(在输入框中输入关键词,观察文本高亮变化)
54
+
55
+ ## 关键词高亮示例
56
+
57
+ 预设关键词为 `API`,文本中所有匹配部分会以高亮背景显示:
58
+
59
+ ## 与 ExecutionSummary 配合
60
+
61
+ `ExecutionSummary` 内部通过 `useKeywordProvider` 提供搜索关键词,后代组件中的 `HighlightKeyword` 自动响应:
62
+
63
+ ```
64
+ ExecutionSummary
65
+ ├── useKeywordProvider(keyword) ← Input 绑定
66
+ └── MessageRender
67
+ └── AssistantMessage
68
+ └── ToolcallRender
69
+ └── HighlightKeyword(:text) ← inject(keyword)
70
+ ```
71
+
72
+ ## 配套 Composables
73
+
74
+ ### useKeywordProvider
75
+
76
+ 在上层组件中创建关键词并 `provide`,后代组件通过 `useKeywordInject` 消费:
77
+
78
+ ```typescript
79
+ import { useKeywordProvider } from '@blueking/chat-x';
80
+
81
+ const { keyword } = useKeywordProvider();
82
+ keyword.value = '搜索词';
83
+ ```
84
+
85
+ ### useKeywordInject
86
+
87
+ 在后代组件中注入关键词,返回 `ComputedRef<string> | undefined`:
88
+
89
+ ```typescript
90
+ import { useKeywordInject } from '@blueking/chat-x';
91
+
92
+ const keyword = useKeywordInject();
93
+ console.log(keyword?.value); // 当前搜索关键词
94
+ ```
95
+
96
+ ### useKeywordMatch
97
+
98
+ 用于判断组件的可搜索文本是否与当前关键词匹配。内部调用 `useKeywordInject` 获取关键词,根据传入的文本提取函数判断是否命中:
99
+
100
+ ```typescript
101
+ import { useKeywordMatch } from '@blueking/chat-x';
102
+
103
+ const { keywordMatched } = useKeywordMatch(() => [props.title, props.description, props.content]);
104
+
105
+ // keywordMatched.value === true 表示命中搜索
106
+ // keywordMatched.value === false 表示未命中(可据此隐藏组件)
107
+ // keyword 为空时始终返回 true
108
+ ```
109
+
110
+ `useKeywordMatch` 的典型用途是在 `ExecutionSummary` 的搜索过滤中,让组件自行判断是否匹配搜索词,与 `HighlightKeyword` 配合实现搜索 + 高亮。
111
+
112
+ ## API
113
+
114
+ ### Props
115
+
116
+ | 属性名 | 类型 | 必填 | 说明 |
117
+ | ------ | -------- | ---- | ---------- |
118
+ | text | `string` | ✓ | 待高亮文本 |
119
+
120
+ ### 依赖注入
121
+
122
+ | 注入项 | 提供方 | 说明 |
123
+ | ------- | -------------------- | ---------------------- |
124
+ | keyword | `useKeywordProvider` | 搜索关键词,响应式更新 |
125
+
126
+ ### 配套 Composables
127
+
128
+ | 函数名 | 参数 | 返回值 | 说明 |
129
+ | -------------------- | ----------------------------------------------- | ------------------------------------------ | --------------------------------------------- |
130
+ | `useKeywordProvider` | — | `{ keyword: ShallowRef<string> }` | 创建并 `provide` 关键词,用于上层组件 |
131
+ | `useKeywordInject` | — | `ComputedRef<string> \| undefined` | 注入关键词,用于后代组件 |
132
+ | `useKeywordMatch` | `getSearchTexts: () => (string \| undefined)[]` | `{ keywordMatched: ComputedRef<boolean> }` | 判断组件文本是否匹配关键词,空关键词返回 true |
133
+
134
+ ### CSS 类名
135
+
136
+ | 类名 | 说明 |
137
+ | ----------------------- | ----------------------------------- |
138
+ | `.ai-highlight-keyword` | 匹配文本的高亮样式(背景色 + 圆角) |
139
+
140
+ ## 关联组件
141
+
142
+ - [ToolcallRender](../molecular/toolcall-render.md) — 工具调用头部高亮
143
+ - [DescPanel](./desc-panel.md) — 详情面板键值高亮
144
+ - [ExecutionSummary](../molecular/execution-summary.md) — 执行摘要搜索
@@ -0,0 +1,178 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ ImageContent 在 Markdown 解析到图片 token 时渲染,对流式拼接中的 URL 做防抖与预加载,并用模块级缓存避免重复闪烁。 三态展示加载中、成功与失败,通常由 MarkdownContent 自动挂载而非业务直接引用。
5
+
6
+ ### 关联组件
7
+ - **markdown-content** — 解析图片 token 后挂载本组件
8
+
9
+ ---
10
+ <!-- FULL DOC -->
11
+
12
+ # ImageContent 图片渲染
13
+
14
+ > **层级**:原子组件 · **功能域**:文件与图片
15
+
16
+ Markdown Token 层的图片渲染原子组件,被 `MarkdownContent` 在解析到图片 token 时自动调用,通常无需手动引入。
17
+
18
+ 核心能力:**流式 URL 防闪烁**(debounce 稳定判断 + throttle 预加载)、**全局缓存**(模块级 `Set` 跨实例共享)、**三态渲染**(加载中 / 成功 / 失败)。
19
+
20
+ ## 组件结构
21
+
22
+ ```
23
+ span.md-image-wrapper(inline-block,vertical-align: middle)
24
+ ├── [showLoading] span.md-image-loading(inline-flex,gap: 6px,padding: 4px 8px,bg: #f5f7fa)
25
+ │ ├── bkui-vue Loading(spin,mini,primary)
26
+ │ └── "图片加载中..."
27
+ ├── [showError] span.md-image-error(同上,color: #ea3636,bg: #fee)
28
+ │ ├── span.md-image-error-icon → ⚠️(font-size: 14px)
29
+ │ └── span.md-image-error-text → alt || "图片加载失败"
30
+ └── [else] img.md-image(max-width: 100%,height: auto,loading="lazy")
31
+ :src="src" :alt="alt"
32
+ ```
33
+
34
+ > **错误文本**:优先显示 `alt`,未传 `alt` 时才显示 "图片加载失败"。
35
+
36
+ ## 状态机
37
+
38
+ 组件内部维护三个 `shallowRef`:`isLoading`、`hasError`、`isUrlStable`,以及两个 computed 控制显示:
39
+
40
+ ```
41
+ showLoading 为 true 的条件(按优先级):
42
+ 1. isCached(全局缓存命中)→ false,直接显示图片
43
+ 2. !isValidUrl → true(URL 无效或正在输入中)
44
+ 3. isLoading → true(正在预加载)
45
+ 4. !isUrlStable && hasError → true(URL 仍在变化,忽略旧错误)
46
+
47
+ showError 为 true 的条件(需全部满足):
48
+ isUrlStable && hasError && !isLoading
49
+ ```
50
+
51
+ ### URL 有效性(isValidUrl)
52
+
53
+ ```
54
+ src 被判定为无效的情况(显示 Loading):
55
+ · 空字符串 / '#' / '#)'
56
+ · 以 '#' 或 '#)' 结尾(Markdown 语法补全占位符)
57
+ · 无协议且不是相对路径/带图片扩展名的路径
58
+ · https?:// 开头但域名中无 '.' 且不是 localhost
59
+
60
+ 合法 URL 格式:
61
+ · https?://、// → 协议 URL(域名需含 '.' 或为 localhost)
62
+ · data:、blob: → Data URL / Blob URL
63
+ · /path 或 ./path → 绝对/相对路径
64
+ · image.png、a.jpg?v=1 → 带图片扩展名的文件名
65
+ ```
66
+
67
+ ### 流式防抖与节流
68
+
69
+ | 机制 | 参数 | 作用 |
70
+ | --------------------------- | ------------------------- | ---------------------------------------------------------------- |
71
+ | `markUrlStable`(debounce) | 500ms | URL 停止变化 500ms 后置 `isUrlStable = true`,此后才允许显示错误 |
72
+ | `preloadImage`(throttle) | 100ms,leading + trailing | 限制 `new Image()` 预加载频率,流式输入时不会每个字符都发请求 |
73
+
74
+ ### 全局缓存
75
+
76
+ `loadedImageCache` 是**模块级 `Set<string>`**,所有 `ImageContent` 实例共享:
77
+
78
+ - 图片加载成功后 → `loadedImageCache.add(url)`
79
+ - 组件初始化时若命中缓存 → `isLoading = false`,`isUrlStable = true`,跳过所有预加载逻辑,直接渲染 `<img>`
80
+ - 页面刷新后缓存清空(仅内存缓存)
81
+
82
+ ## 基础用法
83
+
84
+ ```vue
85
+ <template>
86
+ <ImageContent
87
+ src="https://picsum.photos/seed/demo/400/200"
88
+ alt="示例图片"
89
+ />
90
+ </template>
91
+
92
+ <script setup lang="ts">
93
+ import { ImageContent } from '@blueking/chat-x';
94
+ </script>
95
+ ```
96
+
97
+ ## 加载失败
98
+
99
+ URL 稳定后(500ms 无变化)加载失败,显示 `⚠️ + alt文本`(无 alt 时显示"图片加载失败"):
100
+
101
+ ## Data URL
102
+
103
+ 支持 Base64 / SVG Data URL,不经过 `isValidUrl` 的网络检测,直接进入预加载:
104
+
105
+ ```vue
106
+ <template>
107
+ <ImageContent
108
+ src="data:image/svg+xml,..."
109
+ alt="内联 SVG"
110
+ />
111
+ </template>
112
+ ```
113
+
114
+ ## 流式输入防闪烁
115
+
116
+ 流式 Markdown 渲染时 URL 逐字符拼接,组件通过 debounce + throttle 避免频繁请求和闪烁:
117
+
118
+ ```vue
119
+ <template>
120
+ <button
121
+ @click="simulateStreaming"
122
+ :disabled="isStreaming"
123
+ >
124
+ {{ isStreaming ? '输入中...' : '模拟流式输入' }}
125
+ </button>
126
+ <ImageContent
127
+ :src="streamingUrl"
128
+ alt="流式图片"
129
+ />
130
+ </template>
131
+
132
+ <script setup lang="ts">
133
+ import { ref } from 'vue';
134
+ import { ImageContent } from '@blueking/chat-x';
135
+
136
+ const streamingUrl = ref('');
137
+ const isStreaming = ref(false);
138
+
139
+ const simulateStreaming = async () => {
140
+ const url = 'https://picsum.photos/seed/chat-x-stream/400/200';
141
+ streamingUrl.value = '';
142
+ isStreaming.value = true;
143
+ for (let i = 0; i <= url.length; i++) {
144
+ await new Promise(r => setTimeout(r, 60));
145
+ streamingUrl.value = url.slice(0, i);
146
+ }
147
+ isStreaming.value = false;
148
+ };
149
+ </script>
150
+ ```
151
+
152
+ **流式过程中的状态变化**:
153
+
154
+ ```
155
+ URL = '' → isValidUrl=false → showLoading=true(Loading)
156
+ URL = 'https://' → isValidUrl=false → showLoading=true(域名不完整)
157
+ URL = 'https://p…' → isValidUrl=false → showLoading=true(域名无 '.')
158
+ URL = 完整 URL → isValidUrl=true → throttle 触发 preloadImage
159
+ debounce 500ms → isUrlStable=true
160
+ onload → cache → showLoading=false → 显示图片
161
+ ```
162
+
163
+ ## API
164
+
165
+ ### Props
166
+
167
+ | 属性名 | 类型 | 必填 | 说明 |
168
+ | ------ | -------- | ---- | ---------------------------------------------------------------------------- |
169
+ | src | `string` | ✓ | 图片 URL,支持 https / http / // / data: / blob: / 相对路径 / 带扩展名文件名 |
170
+ | alt | `string` | — | 替代文本;加载失败时优先显示此文本,未传时显示"图片加载失败" |
171
+
172
+ ## 使用场景
173
+
174
+ `ImageContent` 由 `MarkdownContent` 在渲染 `image` token 时自动调用,通常不需要手动引入。如需在 Markdown 以外的场景渲染带流式防抖保护的图片,可单独使用。
175
+
176
+ ## 关联组件
177
+
178
+ - [MarkdownContent](./markdown-content.md) — 图片 token 渲染入口