@blueking/chat-x 0.0.5 → 0.0.7

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 (85) hide show
  1. package/dist/components/ai-selection/ai-selection.vue.d.ts +2 -2
  2. package/dist/components/index.d.ts +2 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.js +6 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp/generated/docs/activity-message.md +428 -0
  7. package/dist/mcp/generated/docs/ai-image.md +227 -0
  8. package/dist/mcp/generated/docs/ai-loading.md +129 -0
  9. package/dist/mcp/generated/docs/ai-selection.md +436 -0
  10. package/dist/mcp/generated/docs/animation-text.md +199 -0
  11. package/dist/mcp/generated/docs/assistant-message.md +424 -0
  12. package/dist/mcp/generated/docs/chat-container.md +402 -0
  13. package/dist/mcp/generated/docs/chat-input.md +625 -0
  14. package/dist/mcp/generated/docs/cite-content.md +138 -0
  15. package/dist/mcp/generated/docs/code-content.md +199 -0
  16. package/dist/mcp/generated/docs/common-error-content.md +70 -0
  17. package/dist/mcp/generated/docs/constants.md +216 -0
  18. package/dist/mcp/generated/docs/content-render.md +238 -0
  19. package/dist/mcp/generated/docs/delete-tool.md +188 -0
  20. package/dist/mcp/generated/docs/desc-panel.md +139 -0
  21. package/dist/mcp/generated/docs/execution-summary.md +126 -0
  22. package/dist/mcp/generated/docs/file-content.md +300 -0
  23. package/dist/mcp/generated/docs/file-upload-btn.md +174 -0
  24. package/dist/mcp/generated/docs/flow-message.md +305 -0
  25. package/dist/mcp/generated/docs/highlight-keyword.md +144 -0
  26. package/dist/mcp/generated/docs/image-content.md +178 -0
  27. package/dist/mcp/generated/docs/image-preview-group.md +181 -0
  28. package/dist/mcp/generated/docs/image-preview.md +224 -0
  29. package/dist/mcp/generated/docs/info-message.md +124 -0
  30. package/dist/mcp/generated/docs/key-value-content.md +124 -0
  31. package/dist/mcp/generated/docs/latex-content.md +196 -0
  32. package/dist/mcp/generated/docs/loading-message.md +171 -0
  33. package/dist/mcp/generated/docs/markdown-content.md +186 -0
  34. package/dist/mcp/generated/docs/markdown-latex.md +208 -0
  35. package/dist/mcp/generated/docs/markdown-mermaid.md +250 -0
  36. package/dist/mcp/generated/docs/mermaid-content.md +185 -0
  37. package/dist/mcp/generated/docs/message-container.md +534 -0
  38. package/dist/mcp/generated/docs/message-render.md +329 -0
  39. package/dist/mcp/generated/docs/message-tools.md +376 -0
  40. package/dist/mcp/generated/docs/messages.md +472 -0
  41. package/dist/mcp/generated/docs/overflow-tips.md +209 -0
  42. package/dist/mcp/generated/docs/reasoning-message.md +233 -0
  43. package/dist/mcp/generated/docs/reference-content.md +132 -0
  44. package/dist/mcp/generated/docs/scroll-btn.md +155 -0
  45. package/dist/mcp/generated/docs/selection-footer.md +75 -0
  46. package/dist/mcp/generated/docs/shortcut-btn.md +202 -0
  47. package/dist/mcp/generated/docs/shortcut-btns.md +264 -0
  48. package/dist/mcp/generated/docs/shortcut-render.md +418 -0
  49. package/dist/mcp/generated/docs/text-content.md +74 -0
  50. package/dist/mcp/generated/docs/theme.md +388 -0
  51. package/dist/mcp/generated/docs/tool-btn.md +254 -0
  52. package/dist/mcp/generated/docs/tool-message.md +217 -0
  53. package/dist/mcp/generated/docs/toolcall-render.md +299 -0
  54. package/dist/mcp/generated/docs/use-animation-text.md +198 -0
  55. package/dist/mcp/generated/docs/use-clipboard.md +206 -0
  56. package/dist/mcp/generated/docs/use-command-selection.md +128 -0
  57. package/dist/mcp/generated/docs/use-container-scroll.md +56 -0
  58. package/dist/mcp/generated/docs/use-custom-tab.md +122 -0
  59. package/dist/mcp/generated/docs/use-global-config.md +154 -0
  60. package/dist/mcp/generated/docs/use-menu-keydown.md +164 -0
  61. package/dist/mcp/generated/docs/use-message-group.md +175 -0
  62. package/dist/mcp/generated/docs/use-observer-visible-list.md +189 -0
  63. package/dist/mcp/generated/docs/use-parent-scrolling.md +46 -0
  64. package/dist/mcp/generated/docs/user-feedback.md +229 -0
  65. package/dist/mcp/generated/docs/user-message.md +347 -0
  66. package/dist/mcp/generated/index.json +1311 -0
  67. package/dist/mcp/index.d.ts +2 -0
  68. package/dist/mcp/index.js +42 -0
  69. package/dist/mcp/index.js.map +1 -0
  70. package/dist/mcp/server.d.ts +2 -0
  71. package/dist/mcp/server.js +43 -0
  72. package/dist/mcp/server.js.map +1 -0
  73. package/dist/mcp/tools/get-component-doc.d.ts +19 -0
  74. package/dist/mcp/tools/get-component-doc.js +60 -0
  75. package/dist/mcp/tools/get-component-doc.js.map +1 -0
  76. package/dist/mcp/tools/list-components.d.ts +35 -0
  77. package/dist/mcp/tools/list-components.js +147 -0
  78. package/dist/mcp/tools/list-components.js.map +1 -0
  79. package/dist/mcp/tools/search-docs.d.ts +14 -0
  80. package/dist/mcp/tools/search-docs.js +82 -0
  81. package/dist/mcp/tools/search-docs.js.map +1 -0
  82. package/dist/mcp/utils/doc-loader.d.ts +35 -0
  83. package/dist/mcp/utils/doc-loader.js +64 -0
  84. package/dist/mcp/utils/doc-loader.js.map +1 -0
  85. package/package.json +5 -7
@@ -0,0 +1,625 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ ChatInput 是聊天主输入区,集成富文本编辑(/ 提示词模板、@ 资源引用)、消息引用、附件上传与快捷指令入口。 通过 prompts、resources、shortcuts 等 props 配置能力,配合 messageStatus 控制发送、流式与停止。 内部组合 ShortcutBtns、FileUploadBtn 等,与 ShortcutRender 联动完成含表单的快捷指令流程。
5
+
6
+ ### 关联组件
7
+ - **shortcut-btns** — 底部附件区默认展示的快捷指令列表
8
+ - **shortcut-btn** — 已选快捷指令以单按钮形式展示并可关闭
9
+ - **shortcut-render** — 快捷指令含 components 时由外层唤起表单渲染
10
+ - **chat-container** — 顶层聊天布局中作为输入区子组件
11
+ - **cite-content** — 消息引用区展示选中的上下文片段
12
+
13
+ ---
14
+ <!-- FULL DOC -->
15
+
16
+ # ChatInput 聊天输入框
17
+
18
+ > **层级**:分子组件 · **功能域**:输入交互
19
+
20
+ 聊天消息输入框组件,支持快捷指令选择、资源 `@` 引用、Prompt `/` 模板、消息引用、文件上传(拖拽/粘贴/点击)等功能。
21
+
22
+ ## 组件结构
23
+
24
+ ```
25
+ chat-input-container
26
+ ├── slot#top(容器顶部,在输入框框体外侧)
27
+ └── chat-input(框体,受 inputMaxHeight 控制)
28
+ ├── slot#input-header(默认:cite 不为空时渲染引用区)
29
+ ├── slot#files(默认:有上传文件时渲染文件预览区)
30
+ ├── AiSlashInput(富文本编辑器,/ 触发 Prompt,@ 触发资源)
31
+ └── InputAttachment(底部工具栏,高度固定 40px)
32
+ ├── FileUploadBtn(仅当 supportUpload 为 true 时显示,在 slot#attachment 外部)
33
+ ├── 分隔线(仅当 supportUpload 为 true 且有快捷指令时显示)
34
+ ├── slot#attachment(默认:ShortcutBtns 或已选 ShortcutBtn + 关闭图标)
35
+ └── slot#send-icon(默认:发送/停止图标,仅替换图标,按钮容器保留)
36
+ ```
37
+
38
+ > **注意**:`slot#attachment` 只替换快捷指令区,`FileUploadBtn` 在其外部,使用该 slot 不会移除上传按钮。`slot#send-icon` 只替换图标,按钮的点击处理和样式仍由组件控制。
39
+
40
+ ## 基础用法
41
+
42
+ ```vue
43
+ <template>
44
+ <ChatInput
45
+ v-model="inputValue"
46
+ :message-status="messageStatus"
47
+ :on-send-message="handleSendMessage"
48
+ :on-stop-sending="handleStopSending"
49
+ />
50
+ </template>
51
+
52
+ <script setup lang="ts">
53
+ import { ref } from 'vue';
54
+ import { ChatInput, MessageStatus, type TagSchema } from '@blueking/chat-x';
55
+
56
+ const inputValue = ref('');
57
+ const messageStatus = ref(MessageStatus.Complete);
58
+
59
+ const handleSendMessage = async (content: string, docSchema: TagSchema) => {
60
+ // content:纯文本字符串(无文件时)或 InputContent[] 数组(有文件时)
61
+ messageStatus.value = MessageStatus.Streaming;
62
+ // ... 发送 AI 请求
63
+ messageStatus.value = MessageStatus.Complete;
64
+ };
65
+
66
+ const handleStopSending = async () => {
67
+ messageStatus.value = MessageStatus.Stop;
68
+ };
69
+ </script>
70
+ ```
71
+
72
+ **渲染效果**(输入 `/` 唤出 Prompt,输入 `@` 唤出资源菜单)
73
+
74
+ ## 发送状态(messageStatus)
75
+
76
+ `messageStatus` 控制底部工具栏的按钮渲染,但**输入框为空时始终自动置灰禁用**,无论 `messageStatus` 传入什么值。
77
+
78
+ | `messageStatus` | 输入框有内容时按钮表现 | 输入框空时 |
79
+ | ----------------------------- | ------------------------------------------------------ | ------------------------ |
80
+ | `complete` / `stop` / `error` | 蓝色发送按钮,点击触发 `onSendMessage` | 灰色禁用 |
81
+ | `streaming` / `pending` | 蓝色停止按钮(Loading 图标),点击触发 `onStopSending` | 蓝色停止按钮(仍可点击) |
82
+ | `disabled` | 灰色禁用,点击无效 | 灰色禁用 |
83
+
84
+ > **实现细节**:组件内部用 `messageState` 计算属性决定实际按钮状态:当 `messageStatus` 为 `pending` 或 `streaming` 时直接使用该状态(确保停止按钮始终可用);否则当输入为空或仅含空白字符时强制为 `disabled`,其余情况使用 `messageStatus` 的值。
85
+
86
+ ### Complete(可发送)
87
+
88
+ ### Streaming(流式输出中,显示停止按钮)
89
+
90
+ ### Disabled(禁用)
91
+
92
+ ## 引用消息(v-model:cite)
93
+
94
+ 通过 `v-model:cite` 绑定引用内容,引用区域显示在编辑器上方,用户可点击关闭按钮取消引用。发送时通过 `onSendMessage` 的第一个参数获取输入内容,引用内容需自行通过 `cite` 变量读取:
95
+
96
+ ```vue
97
+ <template>
98
+ <ChatInput
99
+ v-model="inputValue"
100
+ v-model:cite="citeContent"
101
+ :message-status="messageStatus"
102
+ :on-send-message="handleSendMessage"
103
+ :on-stop-sending="handleStopSending"
104
+ />
105
+ </template>
106
+
107
+ <script setup lang="ts">
108
+ import { ref } from 'vue';
109
+ import { ChatInput, MessageStatus, type TagSchema } from '@blueking/chat-x';
110
+
111
+ const inputValue = ref('');
112
+ const citeContent = ref('被引用的消息内容...');
113
+ const messageStatus = ref(MessageStatus.Complete);
114
+
115
+ const handleSendMessage = async (content: string, docSchema: TagSchema) => {
116
+ console.log('输入内容:', content);
117
+ console.log('引用内容:', citeContent.value); // 自行读取引用内容
118
+ citeContent.value = ''; // 发送后清空引用
119
+ };
120
+
121
+ const handleStopSending = async () => {
122
+ messageStatus.value = MessageStatus.Stop;
123
+ };
124
+ </script>
125
+ ```
126
+
127
+ **渲染效果**(顶部引用区,点击右侧 × 关闭引用)
128
+
129
+ ## Prompt 模板(`/` 触发)
130
+
131
+ 通过 `prompts` 传入字符串数组,用户在编辑器中输入 `/` 唤出 Prompt 菜单,支持模糊搜索,选择后自动填入编辑器:
132
+
133
+ ```vue
134
+ <script setup lang="ts">
135
+ const prompts = [
136
+ '帮我写一篇关于 {topic} 的文章',
137
+ '解释一下这段代码的作用',
138
+ '请用简洁的语言总结以下内容',
139
+ '将以下内容翻译成英文',
140
+ '帮我优化这段代码',
141
+ ];
142
+ </script>
143
+ ```
144
+
145
+ ## 资源 `@` 引用(`@` 触发)
146
+
147
+ 通过 `resources` 传入资源列表,用户输入 `@` 唤出资源选择菜单。资源按 `type` 分组展示,选中后以 Tag 标签形式嵌入编辑器。已选中的资源不会再出现在下拉菜单中(自动去重)。
148
+
149
+ 通过监听 `@update:model-value` 事件的第二个参数 `selectedResourceList` 可以获取当前编辑器中已选中的资源列表:
150
+
151
+ ```vue
152
+ <template>
153
+ <ChatInput
154
+ :model-value="inputValue"
155
+ :message-status="messageStatus"
156
+ :prompts="prompts"
157
+ :resources="resources"
158
+ :on-send-message="handleSendMessage"
159
+ :on-stop-sending="handleStopSending"
160
+ @update:model-value="handleModelValueUpdate"
161
+ />
162
+ </template>
163
+
164
+ <script setup lang="ts">
165
+ import { ref } from 'vue';
166
+ import { ChatInput, MessageStatus, type TagSchema, type IAiSlashMenuItem } from '@blueking/chat-x';
167
+
168
+ const inputValue = ref('');
169
+ const messageStatus = ref(MessageStatus.Complete);
170
+
171
+ const resources: IAiSlashMenuItem[] = [
172
+ { id: 'tool1', name: '天气查询', type: 'tool', icon: 'icon-tool' },
173
+ { id: 'tool2', name: '代码执行', type: 'tool', icon: 'icon-tool' },
174
+ { id: 'mcp1', name: 'db-server', type: 'mcp', icon: 'icon-mcp' },
175
+ { id: 'doc1', name: 'API 文档', type: 'doc', icon: 'icon-doc' },
176
+ { id: 'sc1', name: '翻译助手', type: 'shortcut', icon: 'icon-shortcut' },
177
+ ];
178
+
179
+ const handleModelValueUpdate = (value: string | TagSchema, selectedResourceList: IAiSlashMenuItem[]) => {
180
+ inputValue.value = value;
181
+ // selectedResourceList 为当前编辑器中已选中的 @ 资源列表
182
+ console.log('已选资源:', selectedResourceList);
183
+ };
184
+
185
+ const handleSendMessage = async (content: string, docSchema: TagSchema) => {
186
+ console.log('发送内容(含 @ 引用):', docSchema);
187
+ };
188
+
189
+ const handleStopSending = async () => {
190
+ messageStatus.value = MessageStatus.Stop;
191
+ };
192
+ </script>
193
+ ```
194
+
195
+ > 基础用法 demo 已集成 Prompt 和资源功能,可在上方输入框中体验 `/` 和 `@` 操作。
196
+ >
197
+ > **注意**:`v-model` 仍可使用(Vue 自动取第一个参数绑定),但如需获取 `selectedResourceList`,应使用 `@update:model-value` 显式监听。
198
+
199
+ ## 快捷指令
200
+
201
+ 通过 `shortcuts` 传入快捷指令列表,底部工具栏展示快捷指令按钮;通过 `shortcutId` + `shortcuts` 配合控制选中状态:
202
+
203
+ - `shortcutId` 为空 → 显示所有快捷指令按钮列表
204
+ - `shortcutId` 匹配某个 `shortcut.id` → 隐藏列表,显示已选指令 + 关闭图标
205
+
206
+ ```vue
207
+ <template>
208
+ <ChatInput
209
+ v-model="inputValue"
210
+ :message-status="messageStatus"
211
+ :shortcuts="shortcuts"
212
+ :shortcut-id="selectedShortcutId"
213
+ :on-send-message="handleSendMessage"
214
+ :on-stop-sending="handleStopSending"
215
+ @select-shortcut="selectedShortcutId = $event.id"
216
+ @delete-shortcut="selectedShortcutId = ''"
217
+ />
218
+ </template>
219
+
220
+ <script setup lang="ts">
221
+ import { ref } from 'vue';
222
+ import { ChatInput, MessageStatus, type TagSchema, type Shortcut } from '@blueking/chat-x';
223
+
224
+ const inputValue = ref('');
225
+ const messageStatus = ref(MessageStatus.Complete);
226
+ const selectedShortcutId = ref('');
227
+
228
+ const shortcuts: Shortcut[] = [
229
+ { id: 'translate', name: '翻译' },
230
+ { id: 'explain', name: '解释代码' },
231
+ { id: 'summarize', name: '总结' },
232
+ ];
233
+
234
+ const handleSendMessage = async (content: string, docSchema: TagSchema) => {
235
+ console.log('发送内容:', content, '当前快捷指令:', selectedShortcutId.value);
236
+ };
237
+
238
+ const handleStopSending = async () => {
239
+ messageStatus.value = MessageStatus.Stop;
240
+ };
241
+ </script>
242
+ ```
243
+
244
+ **渲染效果**(底部显示快捷指令按钮,点击选中后按钮变为已选状态)
245
+
246
+ ## 文件上传
247
+
248
+ `supportUpload` 默认为 `true`,底部工具栏自动显示文件上传按钮。传入 `onUpload` 回调后即可处理文件上传:
249
+
250
+ - 底部工具栏出现文件上传按钮(在快捷指令左侧)
251
+ - 支持**点击选择**、**拖拽上传**、**粘贴上传**(Ctrl+V)
252
+ - `onUpload` 每次传入**单个** `File`,返回 `{ download_url?: string }`
253
+ - 文件自动去重(基于 `name + size + lastModified` 复合键),不会重复上传
254
+ - 发送成功后,`uploadFiles` 自动清空
255
+
256
+ **发送内容格式**(有文件时):
257
+
258
+ ```typescript
259
+ // onSendMessage 的 content 参数变为数组:
260
+ [
261
+ { type: 'binary', url: '...', mimeType: 'image/png', filename: 'a.png' },
262
+ { type: 'binary', url: '...', mimeType: 'application/pdf', filename: 'b.pdf' },
263
+ // 若输入框也有文字,则最后追加:
264
+ { type: 'text', text: '请帮我分析这两个文件' },
265
+ ];
266
+ ```
267
+
268
+ ```vue
269
+ <template>
270
+ <ChatInput
271
+ v-model="inputValue"
272
+ :message-status="messageStatus"
273
+ :on-send-message="handleSendMessage"
274
+ :on-stop-sending="handleStopSending"
275
+ :on-upload="handleUpload"
276
+ />
277
+ </template>
278
+
279
+ <script setup lang="ts">
280
+ import { ref } from 'vue';
281
+ import { ChatInput, MessageStatus, type UserMessage, type TagSchema } from '@blueking/chat-x';
282
+
283
+ const inputValue = ref('');
284
+ const messageStatus = ref(MessageStatus.Complete);
285
+
286
+ const handleSendMessage = async (content: UserMessage['content'], docSchema: TagSchema) => {
287
+ if (Array.isArray(content)) {
288
+ // 有文件时 content 为数组
289
+ content.forEach(item => {
290
+ if (item.type === 'binary') console.log('文件:', item.filename, item.url);
291
+ if (item.type === 'text') console.log('文字:', item.text);
292
+ });
293
+ } else {
294
+ // 无文件时 content 为纯字符串
295
+ console.log('文字:', content);
296
+ }
297
+ };
298
+
299
+ const handleStopSending = async () => {
300
+ messageStatus.value = MessageStatus.Stop;
301
+ };
302
+
303
+ // 每次传入单个 File,需返回 { download_url: string }
304
+ const handleUpload = async (file: File) => {
305
+ const formData = new FormData();
306
+ formData.append('file', file);
307
+ const res = await fetch('/api/upload', { method: 'POST', body: formData });
308
+ return res.json(); // { download_url: '...' }
309
+ };
310
+ </script>
311
+ ```
312
+
313
+ **渲染效果**(底部出现文件上传按钮,支持点击、拖拽、粘贴上传)
314
+
315
+ ## 预设上传文件(defaultUploadFiles)
316
+
317
+ 通过 `defaultUploadFiles` 设置初始已上传的文件列表,文件出现在文件预览区,随下次发送一起携带:
318
+
319
+ ```vue
320
+ <script setup lang="ts">
321
+ import { type UploadFile, UploadStatus } from '@blueking/chat-x';
322
+
323
+ const defaultFiles: UploadFile[] = [
324
+ {
325
+ type: 'binary',
326
+ url: 'https://example.com/report.pdf',
327
+ filename: 'report.pdf',
328
+ mimeType: 'application/pdf',
329
+ status: UploadStatus.Success,
330
+ },
331
+ ];
332
+ </script>
333
+ ```
334
+
335
+ ## 自定义占位符
336
+
337
+ 通过 `placeholder` 自定义占位符文案,支持多行(换行用 `\n`):
338
+
339
+ ```vue
340
+ <template>
341
+ <ChatInput
342
+ v-model="inputValue"
343
+ :message-status="messageStatus"
344
+ :placeholder="placeholder"
345
+ :on-send-message="handleSendMessage"
346
+ :on-stop-sending="handleStopSending"
347
+ />
348
+ </template>
349
+
350
+ <script setup lang="ts">
351
+ // 多行占位符
352
+ const placeholder = `你好,我是 AI 小鲸!
353
+ 输入 "/" 唤出 Prompt
354
+ 输入 "@" 唤出工具
355
+ 按 Shift + Enter 换行`;
356
+ </script>
357
+ ```
358
+
359
+ **渲染效果**
360
+
361
+ ## 自定义插槽
362
+
363
+ 组件提供 5 个插槽用于自定义各区域内容:
364
+
365
+ | 插槽名 | 位置 | 默认行为 |
366
+ | -------------- | ------------------------------------------ | ------------------------------------------ |
367
+ | `top` | 框体外部顶部(`.chat-input` 上方) | 无 |
368
+ | `input-header` | 框体内部顶部(编辑器上方) | `cite` 不为空时渲染引用区(`CiteContent`) |
369
+ | `files` | 文件预览区 | 有上传文件时渲染 `FileContent` |
370
+ | `attachment` | 底部工具栏快捷指令区(FileUploadBtn 右侧) | 快捷指令按钮列表 / 已选快捷指令 |
371
+ | `send-icon` | 发送按钮内的图标 | 发送图标 / 停止图标(按钮容器由组件控制) |
372
+
373
+ ```vue
374
+ <template>
375
+ <ChatInput
376
+ v-model="inputValue"
377
+ :message-status="messageStatus"
378
+ :on-send-message="handleSendMessage"
379
+ :on-stop-sending="handleStopSending"
380
+ >
381
+ <!-- 框体外顶部,适合展示模型信息、Token 消耗等 -->
382
+ <template #top>
383
+ <div class="input-tips">当前模型: GPT-4 · 剩余 Token: 12,800</div>
384
+ </template>
385
+
386
+ <!-- 替换引用区,可自定义引用样式 -->
387
+ <template #input-header>
388
+ <div class="custom-header">自定义头部内容</div>
389
+ </template>
390
+
391
+ <!-- 替换文件预览区,接收 files 参数 -->
392
+ <template #files="{ files }">
393
+ <div class="custom-files">
394
+ <span
395
+ v-for="file in files"
396
+ :key="file.filename"
397
+ >{{ file.filename }}</span
398
+ >
399
+ </div>
400
+ </template>
401
+
402
+ <!-- 替换快捷指令区(FileUploadBtn 仍在左侧) -->
403
+ <template #attachment>
404
+ <button @click="handleCustomAction">🎯 自定义操作</button>
405
+ </template>
406
+
407
+ <!-- 替换发送按钮图标(点击逻辑不变) -->
408
+ <template #send-icon>
409
+ <span>🚀</span>
410
+ </template>
411
+ </ChatInput>
412
+ </template>
413
+ ```
414
+
415
+ **渲染效果**(顶部自定义模型信息提示)
416
+
417
+ ## Expose(模板引用)
418
+
419
+ 通过 `ref` 获取组件实例后可调用以下方法:
420
+
421
+ ```vue
422
+ <template>
423
+ <ChatInput
424
+ ref="chatInputRef"
425
+ v-model="inputValue"
426
+ :on-send-message="handleSendMessage"
427
+ />
428
+ <button @click="chatInputRef?.focus()">聚焦输入框</button>
429
+ <button @click="chatInputRef?.triggerSendMessage()">手动发送</button>
430
+ </template>
431
+
432
+ <script setup lang="ts">
433
+ import { useTemplateRef } from 'vue';
434
+ import { ChatInput } from '@blueking/chat-x';
435
+
436
+ const chatInputRef = useTemplateRef<InstanceType<typeof ChatInput>>('chatInputRef');
437
+ const inputValue = ref('');
438
+ const handleSendMessage = async (content: string) => {
439
+ /* ... */
440
+ };
441
+ </script>
442
+ ```
443
+
444
+ ## API
445
+
446
+ ### Props
447
+
448
+ | 属性名 | 类型 | 默认值 | 必填 | 说明 |
449
+ | ------------------ | -------------------------------------------------------------------------- | -------- | ---- | ------------------------------------------------------- |
450
+ | modelValue | `string \| TagSchema` | - | ✅ | 编辑器的值,支持 `v-model` |
451
+ | messageStatus | `MessageStatus` | - | - | 消息状态,控制按钮;输入为空时内部强制 `disabled` |
452
+ | cite | `string` | `''` | - | 引用内容,支持 `v-model:cite`,不为空时显示引用区 |
453
+ | prompts | `string[]` | `[]` | - | Prompt 模板列表,输入 `/` 触发 |
454
+ | resources | `IAiSlashMenuItem[]` | `[]` | - | 资源列表,输入 `@` 触发,按 `type` 分组展示 |
455
+ | shortcuts | `Shortcut[]` | - | - | 快捷指令列表,显示在底部工具栏 |
456
+ | shortcutId | `string` | - | - | 当前选中的快捷指令 ID,匹配时列表收起为已选样式 |
457
+ | placeholder | `string` | 见默认值 | - | 编辑器占位符,支持多行 |
458
+ | inputMaxHeight | `number` | `200` | - | 框体最大高度(px),有文件时自动加上文件预览区高度 |
459
+ | defaultUploadFiles | `UploadFile[]` | - | - | 预设已上传的文件列表 |
460
+ | supportUpload | `boolean` | `true` | - | 是否显示文件上传按钮 |
461
+ | tippyOptions | `AITippyProps` | — | - | 透传给 FileUploadBtn 和 InputAttachment 的 tooltip 配置 |
462
+ | onSendMessage | `(content: UserMessage['content'], docSchema: TagSchema) => Promise<void>` | - | - | 发送消息回调,无文件时 content 为字符串,有文件时为数组 |
463
+ | onStopSending | `() => Promise<void>` | - | - | 停止发送回调,点击停止按钮时触发 |
464
+ | onUpload | `(file: File) => Promise<{ download_url?: string }>` | - | - | 文件上传回调(每次单文件) |
465
+
466
+ ### 默认占位符
467
+
468
+ ```
469
+ 输入 "/"唤出 Prompt
470
+ 输入"@"唤出工具
471
+ 通过 Shift + Enter 进行换行输入
472
+ ```
473
+
474
+ ### Events
475
+
476
+ | 事件名 | 参数 | 触发时机 |
477
+ | ----------------- | ------------------------------------------------------------------------ | --------------------------------------------------------- |
478
+ | update:modelValue | `(value: string \| TagSchema, selectedResourceList: IAiSlashMenuItem[])` | 编辑器值变化时触发;第二个参数为当前已选中的 `@` 资源列表 |
479
+ | selectShortcut | `(shortcut: Shortcut)` | 点击底部快捷指令按钮 |
480
+ | deleteShortcut | - | 点击已选快捷指令旁的关闭按钮 |
481
+
482
+ ### Slots
483
+
484
+ | 插槽名 | 参数 | 说明 |
485
+ | ------------ | ---------------------------------- | ---------------------------------------------------------- |
486
+ | top | - | 框体(`.chat-input`)外部顶部,适合展示模型/Token 信息 |
487
+ | input-header | - | 框体内顶部,替换引用区(`CiteContent`) |
488
+ | files | `{ files: Partial<UploadFile>[] }` | 文件预览区 |
489
+ | attachment | - | 底部快捷指令区,`FileUploadBtn` 在其左侧,不受此 slot 影响 |
490
+ | send-icon | - | 发送按钮内图标,按钮的点击逻辑和样式仍由组件控制 |
491
+
492
+ ### Expose
493
+
494
+ | 方法名 | 类型 | 说明 |
495
+ | ------------------ | ------------ | ---------------- |
496
+ | focus | `() => void` | 聚焦编辑器 |
497
+ | triggerSendMessage | `() => void` | 手动触发发送逻辑 |
498
+
499
+ ## 键盘快捷键
500
+
501
+ | 快捷键 | 说明 |
502
+ | --------------- | ---------------------------------------- |
503
+ | `Enter` | 发送消息(输入为空或仅空白字符时不触发) |
504
+ | `Shift + Enter` | 换行 |
505
+ | `/` | 唤出 Prompt 列表 |
506
+ | `@` | 唤出资源列表 |
507
+ | `↑` / `↓` | 在 Prompt / 资源菜单中导航 |
508
+ | `Esc` | 关闭 Prompt / 资源菜单 |
509
+
510
+ ## 类型定义
511
+
512
+ ```typescript
513
+ import type { UserMessage } from '@blueking/chat-x';
514
+
515
+ // 消息状态
516
+ enum MessageStatus {
517
+ Pending = 'pending', // 等待中(显示停止按钮)
518
+ Streaming = 'streaming', // 流式输出中(显示停止按钮)
519
+ Complete = 'complete', // 完成(显示发送按钮)
520
+ Error = 'error', // 错误(显示发送按钮)
521
+ Stop = 'stop', // 已停止(显示发送按钮)
522
+ Disabled = 'disabled', // 禁用(发送按钮置灰)
523
+ }
524
+
525
+ // 上传状态
526
+ enum UploadStatus {
527
+ Pending = 'pending', // 上传中
528
+ Success = 'success', // 上传成功
529
+ Error = 'error', // 上传失败
530
+ }
531
+
532
+ // 上传文件
533
+ type UploadFile = {
534
+ type: 'binary';
535
+ url?: string; // 上传成功后的下载地址
536
+ filename?: string; // 文件名
537
+ mimeType?: string; // MIME 类型
538
+ file?: File; // 原始 File 对象
539
+ status?: UploadStatus; // 上传状态
540
+ };
541
+
542
+ // 资源菜单项(@ 触发)
543
+ interface IAiSlashMenuItem {
544
+ id: string;
545
+ name: string;
546
+ icon: string;
547
+ type: 'tool' | 'mcp' | 'doc' | 'shortcut'; // 分组类型
548
+ }
549
+
550
+ // onSendMessage 的 content 参数
551
+ type SendContent =
552
+ | string // 无文件时:纯文本
553
+ | Array<
554
+ // 有文件时:数组
555
+ { type: 'binary'; url?: string; mimeType: string; filename: string } | { type: 'text'; text: string }
556
+ >;
557
+ ```
558
+
559
+ ## 完整集成示例
560
+
561
+ ```vue
562
+ <template>
563
+ <ChatInput
564
+ v-model="inputValue"
565
+ v-model:cite="citeContent"
566
+ :message-status="messageStatus"
567
+ :prompts="prompts"
568
+ :resources="resources"
569
+ :shortcuts="shortcuts"
570
+ :shortcut-id="shortcutId"
571
+ :on-send-message="handleSendMessage"
572
+ :on-stop-sending="handleStopSending"
573
+ :on-upload="handleUpload"
574
+ @select-shortcut="shortcutId = $event.id"
575
+ @delete-shortcut="shortcutId = ''"
576
+ />
577
+ </template>
578
+
579
+ <script setup lang="ts">
580
+ import { ref } from 'vue';
581
+ import { ChatInput, MessageStatus, type TagSchema, type Shortcut } from '@blueking/chat-x';
582
+
583
+ const inputValue = ref('');
584
+ const citeContent = ref('');
585
+ const messageStatus = ref(MessageStatus.Complete);
586
+ const shortcutId = ref('');
587
+
588
+ const prompts = ['帮我写一篇关于 {topic} 的文章', '解释一下这段代码'];
589
+ const resources = [{ id: 'tool1', name: '天气查询', type: 'tool', icon: '' }];
590
+ const shortcuts: Shortcut[] = [
591
+ { id: 'translate', name: '翻译' },
592
+ { id: 'explain', name: '解释' },
593
+ ];
594
+
595
+ const handleSendMessage = async (content, docSchema: TagSchema) => {
596
+ messageStatus.value = MessageStatus.Streaming;
597
+ try {
598
+ await callAI(content, { cite: citeContent.value, shortcut: shortcutId.value });
599
+ } finally {
600
+ messageStatus.value = MessageStatus.Complete;
601
+ citeContent.value = '';
602
+ }
603
+ };
604
+
605
+ const handleStopSending = async () => {
606
+ messageStatus.value = MessageStatus.Stop;
607
+ abortAICall();
608
+ };
609
+
610
+ const handleUpload = async (file: File) => {
611
+ const formData = new FormData();
612
+ formData.append('file', file);
613
+ const res = await fetch('/api/upload', { method: 'POST', body: formData });
614
+ return res.json(); // { download_url: '...' }
615
+ };
616
+ </script>
617
+ ```
618
+
619
+ ## 关联组件
620
+
621
+ - [ShortcutBtns](../atomic/shortcut-btns.md) — 底部附件区默认快捷指令列表
622
+ - [ShortcutBtn](../atomic/shortcut-btn.md) — 已选快捷指令单按钮展示
623
+ - [ShortcutRender](./shortcut-render.md) — 含表单的快捷指令表单渲染
624
+ - [ChatContainer](./chat-container.md) — 顶层布局中包裹输入区
625
+ - [CiteContent](../atomic/cite-content.md) — 消息引用区内容展示