@blueking/chat-x 0.0.51 → 0.0.52-dev.2

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 (199) hide show
  1. package/README.md +15 -8
  2. package/dist/ag-ui/types/contents.d.ts +2 -0
  3. package/dist/ag-ui/types/messages.d.ts +6 -1
  4. package/dist/common/constants.d.ts +2 -0
  5. package/dist/components/ai-buttons/add-menu-btn/add-menu-btn.vue.d.ts +24 -0
  6. package/dist/components/chat-content/collapsible-content/collapsible-content.vue.d.ts +28 -0
  7. package/dist/components/chat-content/file-content/upload-file-item.vue.d.ts +5 -2
  8. package/dist/components/chat-content/file-content/upload-image-item.vue.d.ts +1 -0
  9. package/dist/components/chat-content/flow-agent-content/use-flow-node-actions.d.ts +1 -1
  10. package/dist/components/chat-input/ai-slash-input/ai-slash-input.vue.d.ts +21 -10
  11. package/dist/components/chat-input/ai-slash-input/command.d.ts +6 -3
  12. package/dist/components/chat-input/ai-slash-input/constants.d.ts +2 -0
  13. package/dist/components/chat-input/ai-slash-input/use-menu-trigger.d.ts +17 -0
  14. package/dist/components/chat-input/build-default-placeholder.d.ts +9 -3
  15. package/dist/components/chat-input/chat-input.vue.d.ts +30 -18
  16. package/dist/components/chat-input/input-menu/constants.d.ts +60 -0
  17. package/dist/components/chat-input/input-menu/index.d.ts +4 -0
  18. package/dist/components/chat-input/input-menu/input-menu-option.vue.d.ts +14 -0
  19. package/dist/components/chat-input/input-menu/input-menu-panel.vue.d.ts +17 -0
  20. package/dist/components/chat-input/input-menu/use-input-menu.d.ts +22 -0
  21. package/dist/components/chat-input/model-selector/types.d.ts +3 -2
  22. package/dist/components/chat-message/message-container/message-container.vue.d.ts +1 -1
  23. package/dist/components/chat-message/user-message/user-message.vue.d.ts +1 -1
  24. package/dist/components/mention/create-mention-tippy.d.ts +27 -0
  25. package/dist/components/mention/index.d.ts +4 -0
  26. package/dist/components/{chat-input/ai-slash-input/ai-prompt-list/ai-prompt-list.vue.d.ts → mention/mention-popover.vue.d.ts} +3 -2
  27. package/dist/components/{chat-input/ai-slash-input/ai-skill-list/ai-skill-list.vue.d.ts → mention/mention-tag.vue.d.ts} +7 -3
  28. package/dist/components/{chat-input/ai-slash-input/ai-slash-menu/ai-slash-menu.vue.d.ts → mention/mention-text.vue.d.ts} +3 -3
  29. package/dist/components/resource-icon/index.d.ts +1 -0
  30. package/dist/components/resource-icon/resource-icon.vue.d.ts +11 -0
  31. package/dist/composables/index.d.ts +1 -0
  32. package/dist/composables/use-artifact-preview.d.ts +5 -2
  33. package/dist/composables/use-common.d.ts +0 -9
  34. package/dist/composables/use-global-config.d.ts +4 -0
  35. package/dist/composables/use-input-mention.d.ts +13 -0
  36. package/dist/composables/use-message-group.d.ts +1011 -72
  37. package/dist/icons/index.d.ts +1 -0
  38. package/dist/icons/input.d.ts +21 -0
  39. package/dist/icons/menu-item.d.ts +22 -0
  40. package/dist/index.css +1 -1
  41. package/dist/index.js +5116 -4595
  42. package/dist/index.js.map +1 -1
  43. package/dist/lang/lang.d.ts +13 -3
  44. package/dist/mcp/generated/docs/activity-message.md +3 -3
  45. package/dist/mcp/generated/docs/add-menu-btn.md +91 -0
  46. package/dist/mcp/generated/docs/ai-selection.md +1 -1
  47. package/dist/mcp/generated/docs/ai-slash-input.md +72 -26
  48. package/dist/mcp/generated/docs/assistant-message.md +7 -1
  49. package/dist/mcp/generated/docs/chat-container.md +45 -6
  50. package/dist/mcp/generated/docs/chat-input.md +327 -483
  51. package/dist/mcp/generated/docs/collapsible-content.md +78 -0
  52. package/dist/mcp/generated/docs/constants.md +36 -3
  53. package/dist/mcp/generated/docs/execution-summary.md +1 -23
  54. package/dist/mcp/generated/docs/file-artifact-panel.md +24 -5
  55. package/dist/mcp/generated/docs/file-content.md +4 -0
  56. package/dist/mcp/generated/docs/file-upload-btn.md +15 -12
  57. package/dist/mcp/generated/docs/flow-agent-content.md +10 -12
  58. package/dist/mcp/generated/docs/input-menu-panel.md +166 -0
  59. package/dist/mcp/generated/docs/mention-tag.md +83 -0
  60. package/dist/mcp/generated/docs/mention-text.md +86 -0
  61. package/dist/mcp/generated/docs/message-container.md +1 -1
  62. package/dist/mcp/generated/docs/message-render.md +1 -1
  63. package/dist/mcp/generated/docs/message-tools.md +15 -4
  64. package/dist/mcp/generated/docs/messages.md +3 -0
  65. package/dist/mcp/generated/docs/model-selector.md +4 -2
  66. package/dist/mcp/generated/docs/overflow-tips.md +3 -3
  67. package/dist/mcp/generated/docs/resource-icon.md +102 -0
  68. package/dist/mcp/generated/docs/text-content.md +7 -3
  69. package/dist/mcp/generated/docs/theme.md +27 -35
  70. package/dist/mcp/generated/docs/use-artifact-preview.md +7 -3
  71. package/dist/mcp/generated/docs/use-command-selection.md +1 -1
  72. package/dist/mcp/generated/docs/use-container-scroll.md +2 -1
  73. package/dist/mcp/generated/docs/use-flow-node-actions.md +8 -15
  74. package/dist/mcp/generated/docs/use-global-config.md +11 -4
  75. package/dist/mcp/generated/docs/use-input-mention.md +119 -0
  76. package/dist/mcp/generated/docs/use-menu-keydown.md +15 -16
  77. package/dist/mcp/generated/docs/use-message-group.md +3 -6
  78. package/dist/mcp/generated/docs/user-message.md +39 -17
  79. package/dist/mcp/generated/index.json +233 -81
  80. package/dist/types/editor.d.ts +0 -29
  81. package/dist/types/index.d.ts +1 -0
  82. package/dist/types/input-menu.d.ts +46 -0
  83. package/dist/utils/artifact-tags.d.ts +36 -0
  84. package/dist/utils/collect-message-artifacts.d.ts +14 -0
  85. package/dist/utils/file.d.ts +3 -3
  86. package/dist/utils/index.d.ts +2 -1
  87. package/dist/utils/upload-file.d.ts +6 -1
  88. package/package.json +4 -3
  89. package/skills/blueking-chat-x/SKILL.md +143 -0
  90. package/skills/blueking-chat-x/references/_index.md +153 -0
  91. package/skills/blueking-chat-x/references/components/activity-layout.md +134 -0
  92. package/skills/blueking-chat-x/references/components/activity-message.md +486 -0
  93. package/skills/blueking-chat-x/references/components/add-menu-btn.md +88 -0
  94. package/skills/blueking-chat-x/references/components/ai-image.md +230 -0
  95. package/skills/blueking-chat-x/references/components/ai-loading.md +131 -0
  96. package/skills/blueking-chat-x/references/components/ai-selection.md +439 -0
  97. package/skills/blueking-chat-x/references/components/ai-slash-input.md +102 -0
  98. package/skills/blueking-chat-x/references/components/animation-text.md +202 -0
  99. package/skills/blueking-chat-x/references/components/assistant-message.md +504 -0
  100. package/skills/blueking-chat-x/references/components/chat-container.md +912 -0
  101. package/skills/blueking-chat-x/references/components/chat-input.md +614 -0
  102. package/skills/blueking-chat-x/references/components/cite-content.md +142 -0
  103. package/skills/blueking-chat-x/references/components/code-content.md +211 -0
  104. package/skills/blueking-chat-x/references/components/collapsible-content.md +76 -0
  105. package/skills/blueking-chat-x/references/components/common-error-content.md +73 -0
  106. package/skills/blueking-chat-x/references/components/content-render.md +233 -0
  107. package/skills/blueking-chat-x/references/components/delete-tool.md +191 -0
  108. package/skills/blueking-chat-x/references/components/desc-panel.md +162 -0
  109. package/skills/blueking-chat-x/references/components/detail-section.md +91 -0
  110. package/skills/blueking-chat-x/references/components/execution-summary.md +150 -0
  111. package/skills/blueking-chat-x/references/components/file-artifact-panel.md +307 -0
  112. package/skills/blueking-chat-x/references/components/file-content.md +340 -0
  113. package/skills/blueking-chat-x/references/components/file-icon.md +109 -0
  114. package/skills/blueking-chat-x/references/components/file-upload-btn.md +162 -0
  115. package/skills/blueking-chat-x/references/components/flow-agent-content.md +266 -0
  116. package/skills/blueking-chat-x/references/components/flow-agent-node-detail.md +236 -0
  117. package/skills/blueking-chat-x/references/components/highlight-keyword.md +146 -0
  118. package/skills/blueking-chat-x/references/components/image-content.md +182 -0
  119. package/skills/blueking-chat-x/references/components/image-preview-group.md +184 -0
  120. package/skills/blueking-chat-x/references/components/image-preview.md +226 -0
  121. package/skills/blueking-chat-x/references/components/info-message.md +144 -0
  122. package/skills/blueking-chat-x/references/components/input-attachment.md +49 -0
  123. package/skills/blueking-chat-x/references/components/input-info-alert.md +42 -0
  124. package/skills/blueking-chat-x/references/components/input-menu-panel.md +162 -0
  125. package/skills/blueking-chat-x/references/components/interrupt-message.md +212 -0
  126. package/skills/blueking-chat-x/references/components/key-value-content.md +128 -0
  127. package/skills/blueking-chat-x/references/components/knowledge-rag-content.md +122 -0
  128. package/skills/blueking-chat-x/references/components/latex-content.md +200 -0
  129. package/skills/blueking-chat-x/references/components/loading-message.md +192 -0
  130. package/skills/blueking-chat-x/references/components/markdown-content.md +232 -0
  131. package/skills/blueking-chat-x/references/components/mention-tag.md +79 -0
  132. package/skills/blueking-chat-x/references/components/mention-text.md +83 -0
  133. package/skills/blueking-chat-x/references/components/mermaid-content.md +189 -0
  134. package/skills/blueking-chat-x/references/components/message-container.md +645 -0
  135. package/skills/blueking-chat-x/references/components/message-loading.md +118 -0
  136. package/skills/blueking-chat-x/references/components/message-render.md +327 -0
  137. package/skills/blueking-chat-x/references/components/message-time.md +177 -0
  138. package/skills/blueking-chat-x/references/components/message-tools.md +427 -0
  139. package/skills/blueking-chat-x/references/components/model-selector.md +157 -0
  140. package/skills/blueking-chat-x/references/components/preview-toolbar.md +42 -0
  141. package/skills/blueking-chat-x/references/components/questions-container.md +85 -0
  142. package/skills/blueking-chat-x/references/components/reasoning-message.md +232 -0
  143. package/skills/blueking-chat-x/references/components/reference-content.md +135 -0
  144. package/skills/blueking-chat-x/references/components/reference-doc-content.md +109 -0
  145. package/skills/blueking-chat-x/references/components/resource-icon.md +98 -0
  146. package/skills/blueking-chat-x/references/components/scroll-btn.md +159 -0
  147. package/skills/blueking-chat-x/references/components/selection-footer.md +78 -0
  148. package/skills/blueking-chat-x/references/components/selection-question.md +88 -0
  149. package/skills/blueking-chat-x/references/components/shortcut-btn.md +204 -0
  150. package/skills/blueking-chat-x/references/components/shortcut-btns.md +266 -0
  151. package/skills/blueking-chat-x/references/components/shortcut-render.md +424 -0
  152. package/skills/blueking-chat-x/references/components/simple-table.md +101 -0
  153. package/skills/blueking-chat-x/references/components/text-content.md +80 -0
  154. package/skills/blueking-chat-x/references/components/tool-approval-card.md +183 -0
  155. package/skills/blueking-chat-x/references/components/tool-btn.md +317 -0
  156. package/skills/blueking-chat-x/references/components/tool-message.md +235 -0
  157. package/skills/blueking-chat-x/references/components/toolcall-render.md +348 -0
  158. package/skills/blueking-chat-x/references/components/user-feedback.md +233 -0
  159. package/skills/blueking-chat-x/references/components/user-message.md +444 -0
  160. package/skills/blueking-chat-x/references/components/user-question-answered-card.md +104 -0
  161. package/skills/blueking-chat-x/references/components/user-question-card.md +231 -0
  162. package/skills/blueking-chat-x/references/components/user-question-choice.md +105 -0
  163. package/skills/blueking-chat-x/references/components/user-question-option.md +42 -0
  164. package/skills/blueking-chat-x/references/components/vnode-renderer.md +122 -0
  165. package/skills/blueking-chat-x/references/composables/use-animation-text.md +196 -0
  166. package/skills/blueking-chat-x/references/composables/use-artifact-preview.md +235 -0
  167. package/skills/blueking-chat-x/references/composables/use-clipboard.md +203 -0
  168. package/skills/blueking-chat-x/references/composables/use-command-selection.md +150 -0
  169. package/skills/blueking-chat-x/references/composables/use-container-scroll.md +57 -0
  170. package/skills/blueking-chat-x/references/composables/use-custom-tab.md +158 -0
  171. package/skills/blueking-chat-x/references/composables/use-flow-node-actions.md +164 -0
  172. package/skills/blueking-chat-x/references/composables/use-full-screen.md +112 -0
  173. package/skills/blueking-chat-x/references/composables/use-global-config.md +155 -0
  174. package/skills/blueking-chat-x/references/composables/use-input-mention.md +115 -0
  175. package/skills/blueking-chat-x/references/composables/use-menu-keydown.md +161 -0
  176. package/skills/blueking-chat-x/references/composables/use-message-group.md +244 -0
  177. package/skills/blueking-chat-x/references/composables/use-observer-visible-list.md +188 -0
  178. package/skills/blueking-chat-x/references/composables/use-parent-scrolling.md +46 -0
  179. package/skills/blueking-chat-x/references/directives/index.md +61 -0
  180. package/skills/blueking-chat-x/references/directives/overflow-tips.md +205 -0
  181. package/skills/blueking-chat-x/references/icons/index.md +185 -0
  182. package/skills/blueking-chat-x/references/plugins/index.md +56 -0
  183. package/skills/blueking-chat-x/references/plugins/markdown-container.md +55 -0
  184. package/skills/blueking-chat-x/references/plugins/markdown-latex.md +205 -0
  185. package/skills/blueking-chat-x/references/plugins/markdown-mermaid.md +247 -0
  186. package/skills/blueking-chat-x/references/theme/theme.md +423 -0
  187. package/skills/blueking-chat-x/references/types/constants.md +340 -0
  188. package/skills/blueking-chat-x/references/types/index.md +120 -0
  189. package/skills/blueking-chat-x/references/types/interrupt.md +379 -0
  190. package/skills/blueking-chat-x/references/types/messages.md +556 -0
  191. package/skills/blueking-chat-x/references/types/schema.md +91 -0
  192. package/skills/blueking-chat-x/references/utils/index.md +196 -0
  193. package/skills/blueking-chat-x/scripts/generate-references.mjs +536 -0
  194. package/dist/components/chat-input/ai-slash-editor/ai-slash-editor.vue.d.ts +0 -28
  195. package/dist/components/chat-input/ai-slash-editor/theme.d.ts +0 -24
  196. package/dist/mcp/generated/docs/ai-prompt-list.md +0 -45
  197. package/dist/mcp/generated/docs/ai-skill-list.md +0 -75
  198. package/dist/mcp/generated/docs/ai-slash-editor.md +0 -43
  199. package/dist/mcp/generated/docs/ai-slash-menu.md +0 -42
@@ -1,53 +1,50 @@
1
1
  <!-- AI SUMMARY -->
2
2
  ## 快速了解
3
3
 
4
- 聊天输入区,组合富文本输入、快捷指令、附件、引用、发送/停止等交互。 源码位置:src/components/chat-input/chat-input.vue。
4
+ 聊天输入区,组合富文本输入、统一菜单、快捷指令、附件、引用、发送/停止等交互。 菜单数据由单一 menuSources 提供,按 type 分发到 `/` `@` `\` 与左下角 + 号四种触发方式。 源码位置:src/components/chat-input/chat-input.vue。
5
5
 
6
6
  ### 关联组件
7
- - **shortcut-btns** — 底部附件区默认展示的快捷指令列表
8
- - **shortcut-btn** — 已选快捷指令以单按钮形式展示并可关闭
9
- - **shortcut-render** — 快捷指令含 components 时由外层唤起表单渲染
10
- - **chat-container** — 顶层聊天布局中作为输入区子组件
7
+ - **ai-slash-input** — 内部富文本编辑区,负责触发符识别与标签插入
8
+ - **input-menu-panel** — 输入框正上方的统一菜单面板
9
+ - **add-menu-btn** — 左下角 + 号,唤起聚合菜单
10
+ - **mention-tag** — 菜单选中的资源以标签形式嵌入编辑器
11
11
  - **model-selector** — 传入 models 后在发送按钮左侧默认展示模型选择器
12
+ - **shortcut-btns** — 底部附件区默认展示的快捷指令列表
12
13
  - **cite-content** — 消息引用区展示选中的上下文片段
14
+ - **chat-container** — 顶层聊天布局中作为输入区子组件
13
15
 
14
16
  ---
15
17
  <!-- FULL DOC -->
16
18
 
17
19
  # ChatInput 聊天输入框
18
- ## 源码事实
19
-
20
- - **源码位置**:`src/components/chat-input/chat-input.vue`
21
- - **能力域**:输入交互
22
- - **能力说明**:聊天输入区,组合富文本输入、快捷指令、附件、引用、发送/停止等交互。
23
20
 
24
21
  > **能力域**:输入交互
25
22
 
26
- 聊天消息输入框组件,支持快捷指令选择、资源 `@` 引用、Prompt `/` 模板、消息引用、文件上传(拖拽/粘贴/点击)等功能。
23
+ ## 源码事实
24
+
25
+ - **源码位置**:`src/components/chat-input/chat-input.vue`
26
+ - **能力说明**:聊天输入区,组合富文本输入、统一菜单、快捷指令、附件、引用、发送/停止等交互。
27
+ - **菜单数据源唯一**:`menuSources` 一份数组按 `type` 分发到 `/`、`@`、`\` 三个触发符与左下角 + 号,组件内部不再区分 `skills` / `prompts` / `resources`。
27
28
 
28
29
  ## 组件结构
29
30
 
30
31
  ```
31
- ai-chat-input-container(padding: 0 16px 16px,底部间距 16px
32
- ├── slot#top(容器顶部,在输入框框体外侧)
33
- ├── slot#interrupt(容器顶部,在输入框框体外侧,通常展示中断/审批提示)
34
- └── chat-input(框体,受 inputMaxHeight 控制)
35
- ├── slot#input-header(默认:cite 不为空时渲染引用区)
36
- ├── slot#files(默认:有上传文件时渲染文件预览区)
37
- ├── AiSlashInput(富文本编辑器,/ 触发 Prompt,@ 触发资源)
38
- └── InputAttachment(底部工具栏,高度固定 40px
39
- ├── FileUploadBtn(仅当 supportUpload 为 true 时显示,在 slot#attachment 外部)
40
- ├── 分隔线(仅当 supportUpload 为 true 且有快捷指令时显示)
41
- ├── slot#attachment(默认:ShortcutBtns 或已选 ShortcutBtn + 关闭图标)
42
- ├── slot#before-send(默认:传入 models 时渲染 ModelSelector)
43
- └── slot#send-icon(默认:发送/停止图标,仅替换图标,按钮容器保留)
32
+ ai-chat-input-container(padding: 0 16px 16px)
33
+ ├── slot#top(框体外顶部)
34
+ ├── slot#interrupt(框体外顶部,位于 top 之后)
35
+ └── chat-input-wrapper(相对定位;宽度 168px ~ 1000px)
36
+ ├── InputMenuPanel(绝对定位于框体上方 8px、与框体等宽,菜单激活且有条目时渲染)
37
+ └── chat-input(框体,min-height 110px,max-height 由 inputMaxHeight 控制)
38
+ ├── slot#input-header(默认:cite 非空时渲染 CiteContent)
39
+ ├── slot#files(默认:有上传文件时渲染 FileContent
40
+ ├── AiSlashInput(富文本编辑区,默认保持 4 行高度)
41
+ └── InputAttachment(底部工具栏,固定 32px 高)
42
+ ├── slot#default 隐藏 file input + AddMenuBtn(+ 号)+ 分隔线 + slot#attachment
43
+ ├── slot#before-send slot#model-selector(默认 ModelSelector)
44
+ └── slot#send-icon(默认:发送 / 停止图标)
44
45
  ```
45
46
 
46
- > **注意**:`slot#attachment` 只替换快捷指令区,`FileUploadBtn` 在其外部,使用该 slot 不会移除上传按钮。`slot#send-icon` 只替换图标,按钮的点击处理和样式仍由组件控制。
47
-
48
- ### AiSlashInput 与 modelValue 同步
49
-
50
- 内部编辑器 `AiSlashInput` 在 **`modelValue` 由外部异步更新**(例如从历史会话回填、父组件重置)且与当前文档不一致时,会通过 `useCommandSelection` 提供的 `GetDocSnapshot` 读取编辑器快照,与 `docToString(modelValue)` 比对后,必要时执行 `ReplaceAll` 将编辑器内容同步为新的 `modelValue`,避免内外状态脱节。
47
+ > `slot#attachment` 只替换快捷指令区,`AddMenuBtn` 在其外部,使用该插槽不会移除 + 号。`slot#send-icon` 只替换图标,点击逻辑与按钮样式仍由组件控制。
51
48
 
52
49
  ## 基础用法
53
50
 
@@ -55,6 +52,7 @@ ai-chat-input-container(padding: 0 16px 16px,底部间距 16px)
55
52
  <template>
56
53
  <ChatInput
57
54
  v-model="inputValue"
55
+ :menu-sources="menuSources"
58
56
  :message-status="messageStatus"
59
57
  :on-send-message="handleSendMessage"
60
58
  :on-stop-sending="handleStopSending"
@@ -63,13 +61,22 @@ ai-chat-input-container(padding: 0 16px 16px,底部间距 16px)
63
61
 
64
62
  <script setup lang="ts">
65
63
  import { ref } from 'vue';
66
- import { ChatInput, MessageStatus, type TagSchema } from '@blueking/chat-x';
64
+ import { ChatInput, MessageStatus, type IInputMenuItem, type TagSchema } from '@blueking/chat-x';
67
65
 
68
66
  const inputValue = ref('');
69
67
  const messageStatus = ref(MessageStatus.Complete);
70
68
 
69
+ const menuSources: IInputMenuItem[] = [
70
+ { id: 'translate', type: 'skill', name: '翻译', description: '把选中的文本翻译成目标语言' },
71
+ { id: 'database-server', type: 'mcp', name: 'database-server' },
72
+ { id: 'weather', type: 'tool', name: '天气查询' },
73
+ { id: 'kb-api', type: 'knowledgebase', name: 'API 接口文档' },
74
+ { id: 'prompt-article', type: 'prompt', name: '写文章', content: '帮我写一篇关于 {topic} 的文章' },
75
+ ];
76
+
71
77
  const handleSendMessage = async (content: string, docSchema: TagSchema) => {
72
78
  // content:纯文本字符串(无文件时)或 InputContent[] 数组(有文件时)
79
+ // docSchema:当前编辑器文档,含标签结构,可持久化用于回显
73
80
  messageStatus.value = MessageStatus.Streaming;
74
81
  // ... 发送 AI 请求
75
82
  messageStatus.value = MessageStatus.Complete;
@@ -81,270 +88,234 @@ ai-chat-input-container(padding: 0 16px 16px,底部间距 16px)
81
88
  </script>
82
89
  ```
83
90
 
84
- **渲染效果**(输入 `/` 唤出 Prompt,输入 `@` 唤出资源菜单)
91
+ **渲染效果**(输入 `/` `@` `\` 或点击左下角 + 号唤出菜单)
85
92
 
86
- ## 发送状态(messageStatus
93
+ ## 统一菜单(menuSources
87
94
 
88
- `messageStatus` 控制底部工具栏的按钮渲染,但**输入框为空且没有附件时始终自动置灰禁用**,无论 `messageStatus` 传入什么值。
95
+ ### 触发方式与分组
89
96
 
90
- | `messageStatus` | 输入框有内容或已有附件时按钮表现 | 输入框空且无附件时 |
91
- | ----------------------------- | ------------------------------------------------------ | ------------------------ |
92
- | `complete` / `stop` / `error` | 蓝色发送按钮,点击触发 `onSendMessage` | 灰色禁用 |
93
- | `streaming` / `pending` / `fetching` | 蓝色停止按钮(Loading 图标),点击触发 `onStopSending` | 蓝色停止按钮(仍可点击) |
94
- | `disabled` | 灰色禁用,点击无效 | 灰色禁用 |
95
-
96
- > **实现细节**:组件内部用 `messageState` 计算属性决定实际按钮状态:当 `messageStatus` 为 `pending`、`streaming` 或 `fetching` 时直接使用该状态(确保停止按钮始终可用);否则**已有上传附件时视为可发送**(纯附件消息无需输入文字);再否则当输入为空或仅含空白字符时强制为 `disabled`,其余情况使用 `messageStatus` 的值。`fetching` 时按 Enter **不会**触发发送(避免请求中与 Loading 占位阶段重复提交)。
97
+ 菜单面板固定展示在输入框**正上方**并与输入框等宽(不跟随光标),最大高度 400px,超出滚动。四种触发方式共用同一份 `menuSources`,各自展示的分组不同:
97
98
 
98
- > **纯附件消息**:只上传附件不输入文字时,`onSendMessage` `content` 只含 `binary` 项,**不会**附带空文本段。
99
+ | 触发方式 | 分组顺序 | 说明 |
100
+ | ---------------- | -------------------------------------------------------------- | ------------------------------------------ |
101
+ | `/` | Skill、MCP、工具 | 智能体能力 |
102
+ | `@` | 知识库、会话产物 | 可引用的上下文资源 |
103
+ | `\` | Prompt | 提示词模板 |
104
+ | + 号(`plus`) | 添加、Skill、MCP、工具、知识库、会话产物、Prompt | 聚合全部分组,「添加」组下方有分隔线 |
99
105
 
100
- ### onSendMessage 第三参数 options(UserQuestion 上下文)
106
+ 分组与 `type` 的对应关系:
101
107
 
102
- `ChatInput` 自身调用 `onSendMessage` 时只传前两个参数。当组件被 [ChatContainer](/components/setup/chat-container) 包裹且存在待回答 `UserQuestion` 中断时,容器会在用户点击发送时注入第三个参数:
108
+ | 分组标题 | 覆盖的 `type` | 备注 |
109
+ | ---------- | -------------------------- | ------------------------------------------------ |
110
+ | 添加 | `file` | 组件内置项,只出现在 + 号菜单 |
111
+ | Skill | `skill` | 插入后序列化为 `/<id>` |
112
+ | MCP | `mcp` | |
113
+ | 工具 | `tool` | |
114
+ | 知识库 | `knowledgebase`、`doc` | 后端两种历史命名合并为一个分组 |
115
+ | 会话产物 | `artifact` | 无数据时不展示该分组 |
116
+ | Prompt | `prompt` | 选中后整体替换输入框内容 |
103
117
 
104
- | 字段 | 类型 | 说明 |
105
- | ----------- | ------------------ | -------------------------------------------------------------------- |
106
- | `interrupt` | `Interrupt` | 当前激活的 `UserQuestionInterrupt` |
107
- | `payload` | `InterruptResume` | skip resume(`status: 'cancelled'`,`payload.answers` 为空数组) |
108
-
109
- 此场景下容器**不会**自动清空 `modelValue`,业务侧需在 `onSendMessage` 内自行处理消息发送与 `resumeAgent` 的先后顺序。结构化作答仍通过 `UserQuestionCard` → `onInterruptResume` 完成。
110
-
111
- ```typescript
112
- const handleSendMessage = async (
113
- content: UserMessage['content'],
114
- docSchema: TagSchema,
115
- options?: { interrupt?: Interrupt; payload?: InterruptResume },
116
- ) => {
117
- if (options?.interrupt && options?.payload) {
118
- await resumeAgent({ interruptId: options.interrupt.id, resume: options.payload });
119
- return;
120
- }
121
- await sendMessage(content, docSchema);
122
- };
123
- ```
124
-
125
- ### sendDisabledTip(业务阻塞发送)
118
+ ### 关键行为
126
119
 
127
- 当业务侧需要临时阻止发送但仍允许用户输入时,可传入 `sendDisabledTip`。组件会置灰发送按钮,按钮 tooltip 展示该文案,并拦截点击发送、按 Enter 发送和 `triggerSendMessage()`:
120
+ - **过滤**:触发符之后输入的文本作为关键字,按 `name` 不区分大小写包含匹配。+ 号菜单的关键字取「唤起时光标位置 当前光标」之间的文本。
121
+ - **折叠**:每个分组默认展示 `menuGroupItemLimit`(默认 4)条,超出折叠为「更多 +N」,点击展开;关键字或触发方式变化后折叠状态重置。
122
+ - **去重**:已插入编辑器的标签按 `type:id` 从候选中剔除,不会重复出现。
123
+ - **空面板不弹出**:初始化或搜索后没有任何匹配条目时,面板不会展示。空分组也不会被算进结果(见 [InputMenuPanel](/components/input/input-menu-panel))。
124
+ - **内置「文件」项**:`supportUpload` 为 `true` 时注入,**不要**写进 `menuSources`。选中后唤起隐藏文件选择器并走 `onUpload`;`accept` 与入队校验见 [文件上传](#file-upload)。
125
+ - **+ 号显隐**:`supportUpload` 为 `false` 且 `menuSources` 为空时不渲染 + 号。
126
+ - **选中动作**:`prompt` 整体替换输入框内容(取 `content`,缺省取 `name`);`file` 唤起文件选择器;其余类型插入资源标签并补一个空格。
128
127
 
129
128
  ```vue
130
129
  <template>
131
130
  <ChatInput
132
- v-model="inputValue"
133
- message-status="complete"
134
- :send-disabled-tip="interruptTip"
131
+ :model-value="inputValue"
132
+ :menu-sources="menuSources"
133
+ :menu-group-item-limit="6"
134
+ :message-status="messageStatus"
135
135
  :on-send-message="handleSendMessage"
136
- :on-stop-sending="handleStopSending"
137
- >
138
- <template #interrupt>
139
- <div class="input-alert">{{ interruptTip }}</div>
140
- </template>
141
- </ChatInput>
136
+ @update:model-value="handleModelValueUpdate"
137
+ />
142
138
  </template>
139
+
140
+ <script setup lang="ts">
141
+ import { ref } from 'vue';
142
+ import { ChatInput, MessageStatus, type IInputMenuItem, type TagSchema } from '@blueking/chat-x';
143
+
144
+ const inputValue = ref<string | TagSchema>('');
145
+
146
+ const handleModelValueUpdate = (value: string | TagSchema, selectedResourceList: IInputMenuItem[]) => {
147
+ inputValue.value = value;
148
+ // selectedResourceList 为当前编辑器内已插入的菜单条目(能在 menuSources 中反查到的部分)
149
+ console.log('已选资源:', selectedResourceList);
150
+ };
151
+ </script>
143
152
  ```
144
153
 
145
- **渲染效果**
154
+ > `v-model` 仍可用(Vue 自动绑定第一个参数);需要 `selectedResourceList` 时改用 `@update:model-value` 显式监听。
146
155
 
147
- ### Complete(可发送)
156
+ ### 图标
148
157
 
149
- ### Streaming(流式输出中,显示停止按钮)
158
+ 条目的 `icon` 支持图片 URL 字符串或 Vue 组件,缺省时由 [ResourceIcon](/components/helper/resource-icon) 按 `type` 兜底(`artifact` 按文件名后缀推导)。
150
159
 
151
- ### Disabled(禁用)
160
+ ::: warning 组件形式的图标不会随标签保留
161
+ 插入编辑器后,标签会把图标序列化到 DOM 属性上(这样文档可以脱离 `menuSources` 独立还原),因此只有字符串 URL 能被保留;传 Vue 组件时标签内会回退为类型默认图标。
162
+ :::
152
163
 
153
- ## 引用消息(v-model:cite)
164
+ ### 发送后的文本形态
154
165
 
155
- 通过 `v-model:cite` 绑定引用内容,引用区域显示在编辑器上方,用户可点击关闭按钮取消引用。发送时通过 `onSendMessage` 的第一个参数获取输入内容,引用内容需自行通过 `cite` 变量读取:
166
+ 标签在发送文本中按类型序列化:`skill` 输出 `/<id>`,其余类型输出 `@<name>`。因此 `skill` `id` 需要是后端可识别的编码。
156
167
 
157
- ```vue
158
- <template>
159
- <ChatInput
160
- v-model="inputValue"
161
- v-model:cite="citeContent"
162
- :message-status="messageStatus"
163
- :on-send-message="handleSendMessage"
164
- :on-stop-sending="handleStopSending"
165
- />
166
- </template>
168
+ ## 从 skills / prompts / resources 迁移
167
169
 
168
- <script setup lang="ts">
169
- import { ref } from 'vue';
170
- import { ChatInput, MessageStatus, type TagSchema } from '@blueking/chat-x';
170
+ 旧版三个数据源与 `AiSkillList` / `AiPromptList` / `AiSlashMenu` 三个菜单组件已移除,统一为 `menuSources`:
171
171
 
172
- const inputValue = ref('');
173
- const citeContent = ref('被引用的消息内容...');
174
- const messageStatus = ref(MessageStatus.Complete);
172
+ | API | 新写法 |
173
+ | ---------------------------------------- | ----------------------------------------------------------------------------------- |
174
+ | `skills: ISkillListItem[]` | `menuSources` 中 `type: 'skill'`;`skill_code` → `id`,`skill_name` → `name` |
175
+ | `prompts: string[]` | `type: 'prompt'`;`name` 为菜单展示名,`content` 为插入正文 |
176
+ | `resources: IAiSlashMenuItem[]` | `type` 取 `tool` / `mcp` / `knowledgebase` / `doc` / `artifact` |
177
+ | `resources` 中的 `type: 'shortcut'` | 不再进入菜单,快捷指令走 `shortcuts` + `shortcutId` |
178
+ | `ISkillListItem` / `IAiSlashMenuItem` | 统一为 `IInputMenuItem`(`resourceTypeMap`、`ResourceType` 一并移除) |
179
+ | `\` 唤出 Prompt、`/` 唤出 Skill | 触发符不变,`@` 新增「会话产物」分组,并新增 + 号聚合菜单 |
175
180
 
176
- const handleSendMessage = async (content: string, docSchema: TagSchema) => {
177
- console.log('输入内容:', content);
178
- console.log('引用内容:', citeContent.value); // 自行读取引用内容
179
- citeContent.value = ''; // 发送后清空引用
180
- };
181
+ ```typescript
182
+ //
183
+ const skills = [{ skill_code: 'translate', skill_name: '翻译', description: '翻译文本', icon: '' }];
184
+ const prompts = ['帮我写一篇关于 {topic} 的文章'];
185
+ const resources = [{ id: 'tool1', name: '天气查询', type: 'tool', icon: '' }];
186
+
187
+ // 新
188
+ const menuSources: IInputMenuItem[] = [
189
+ { id: 'translate', type: 'skill', name: '翻译', description: '翻译文本' },
190
+ { id: 'prompt-article', type: 'prompt', name: '写文章', content: '帮我写一篇关于 {topic} 的文章' },
191
+ { id: 'tool1', type: 'tool', name: '天气查询' },
192
+ ];
193
+ ```
181
194
 
182
- const handleStopSending = async () => {
183
- messageStatus.value = MessageStatus.Stop;
184
- };
185
- </script>
195
+ ## 占位符
196
+
197
+ 未传 `placeholder` 时,按 `menuSources` 中**实际存在的类型**动态拼接提示行(没有对应资源就不显示该行),最后一行始终保留:
198
+
199
+ ```
200
+ 输入 "/" 唤出 Skill,工具,MCP // menuSources 含 skill / tool / mcp 任一
201
+ 输入 "@" 唤出会话产物,知识库 // 含 knowledgebase / doc / artifact 任一
202
+ 输入 "\" 唤出 Prompt // 含 prompt
203
+ 通过 Shift + Enter 进行换行输入 // 始终显示
186
204
  ```
187
205
 
188
- **渲染效果**(顶部引用区,点击右侧 × 关闭引用)
206
+ 显式传入 `placeholder`(含空字符串)时完全覆盖上述文案,支持用 `\n` 换行。
189
207
 
190
- ## Skill 列表(`/` 触发)
208
+ ## 发送状态(messageStatus)
191
209
 
192
- 通过 `skills` 传入 Skill 列表,用户在编辑器中输入 `/` 唤出 [AiSkillList](/components/input/ai-skill-list) 菜单,支持按名称/编码模糊搜索,选择后以 Skill 标签嵌入编辑器。无 icon 或 icon 加载失败时展示首字母 fallback。已插入的 Skill 不会再出现在下拉菜单中(自动去重)。
210
+ `messageStatus` 控制底部按钮渲染,但**输入框为空且没有附件时始终置灰禁用**,无论传入什么值。
193
211
 
194
- ```vue
195
- <script setup lang="ts">
196
- import type { ISkillListItem } from '@blueking/chat-x';
212
+ | `messageStatus` | 有内容或已有附件 | 空且无附件 |
213
+ | ------------------------------------ | ------------------------------------------------------ | ------------------------ |
214
+ | `complete` / `stop` / `error` | 蓝色发送按钮,点击触发 `onSendMessage` | 灰色禁用 |
215
+ | `streaming` / `pending` / `fetching` | 蓝色停止按钮(Loading 图标),点击触发 `onStopSending` | 蓝色停止按钮(仍可点击) |
216
+ | `disabled` | 灰色禁用,点击无效 | 灰色禁用 |
197
217
 
198
- const skills: ISkillListItem[] = [
199
- { skill_code: 'translate', skill_name: '翻译', description: '翻译文本', icon: '' },
200
- { skill_code: 'summarize', skill_name: '总结', description: '总结内容', icon: 'https://example.com/icon.png' },
201
- ];
202
- </script>
203
- ```
218
+ 内部由 `messageState` 计算:`pending` / `streaming` / `fetching` 直接沿用传入状态(保证停止按钮始终可用);否则**已有上传附件即视为可发送**(纯附件消息无需文字);再否则输入为空或仅空白字符时强制为 `disabled`。`fetching` 时按 Enter **不会**触发发送,避免请求中重复提交。
204
219
 
205
- ## Prompt 模板(`\` 触发)
220
+ ### onSendMessage 第三参数 options(UserQuestion 上下文)
206
221
 
207
- 通过 `prompts` 传入字符串数组,用户在编辑器中输入 `\` 唤出 Prompt 菜单,支持模糊搜索,选择后自动填入编辑器:
222
+ `ChatInput` 自身调用 `onSendMessage` 时只传前两个参数。当组件被 [ChatContainer](/components/setup/chat-container) 包裹且存在待回答 `UserQuestion` 中断时,容器会在用户点击发送时注入第三个参数:
208
223
 
209
- ```vue
210
- <script setup lang="ts">
211
- const prompts = [
212
- '帮我写一篇关于 {topic} 的文章',
213
- '解释一下这段代码的作用',
214
- '请用简洁的语言总结以下内容',
215
- '将以下内容翻译成英文',
216
- '帮我优化这段代码',
217
- ];
218
- </script>
224
+ | 字段 | 类型 | 说明 |
225
+ | ----------- | ----------------- | ---------------------------------------------------------------- |
226
+ | `interrupt` | `Interrupt` | 当前激活的 `UserQuestionInterrupt` |
227
+ | `payload` | `InterruptResume` | skip resume(`status: 'cancelled'`,`payload.answers` 为空数组) |
228
+
229
+ 此场景下容器**不会**自动清空 `modelValue`,业务侧需在 `onSendMessage` 内自行处理消息发送与 `resumeAgent` 的先后顺序。结构化作答仍通过 `UserQuestionCard` → `onInterruptResume` 完成。
230
+
231
+ ```typescript
232
+ const handleSendMessage = async (
233
+ content: UserMessage['content'],
234
+ docSchema: TagSchema,
235
+ options?: { interrupt?: Interrupt; payload?: InterruptResume },
236
+ ) => {
237
+ if (options?.interrupt && options?.payload) {
238
+ await resumeAgent({ interruptId: options.interrupt.id, resume: options.payload });
239
+ return;
240
+ }
241
+ await sendMessage(content, docSchema);
242
+ };
219
243
  ```
220
244
 
221
- ## 资源 `@` 引用(`@` 触发)
245
+ ### sendDisabledTip(业务阻塞发送)
246
+
247
+ 需要临时阻止发送但仍允许输入时传入 `sendDisabledTip`:置灰发送按钮、按钮 tooltip 展示该文案,并拦截点击发送、Enter 发送与 `triggerSendMessage()`。
222
248
 
223
- 通过 `resources` 传入资源列表,用户输入 `@` 唤出资源选择菜单。资源按 `type` 分组展示,选中后以 Tag 标签形式嵌入编辑器。已选中的资源不会再出现在下拉菜单中(自动去重)。
249
+ ## 引用消息(v-model:cite)
224
250
 
225
- 通过监听 `@update:model-value` 事件的第二个参数 `selectedResourceList` 可以获取当前编辑器中已选中的资源列表:
251
+ 通过 `v-model:cite` 绑定引用内容,引用区显示在编辑器上方,用户可点击关闭取消引用。发送时引用内容需自行读取 `cite` 变量,`onSendMessage` 的 `content` 不包含它。
226
252
 
227
253
  ```vue
228
254
  <template>
229
255
  <ChatInput
230
- :model-value="inputValue"
256
+ v-model="inputValue"
257
+ v-model:cite="citeContent"
231
258
  :message-status="messageStatus"
232
- :prompts="prompts"
233
- :resources="resources"
234
259
  :on-send-message="handleSendMessage"
235
- :on-stop-sending="handleStopSending"
236
- @update:model-value="handleModelValueUpdate"
237
260
  />
238
261
  </template>
239
262
 
240
263
  <script setup lang="ts">
241
- import { ref } from 'vue';
242
- import { ChatInput, MessageStatus, type TagSchema, type IAiSlashMenuItem } from '@blueking/chat-x';
243
-
244
- const inputValue = ref('');
245
- const messageStatus = ref(MessageStatus.Complete);
246
-
247
- const resources: IAiSlashMenuItem[] = [
248
- { id: 'tool1', name: '天气查询', type: 'tool', icon: 'icon-tool' },
249
- { id: 'tool2', name: '代码执行', type: 'tool', icon: 'icon-tool' },
250
- { id: 'mcp1', name: 'db-server', type: 'mcp', icon: 'icon-mcp' },
251
- { id: 'doc1', name: 'API 文档', type: 'doc', icon: 'icon-doc' },
252
- { id: 'sc1', name: '翻译助手', type: 'shortcut', icon: 'icon-shortcut' },
253
- ];
254
-
255
- const handleModelValueUpdate = (value: string | TagSchema, selectedResourceList: IAiSlashMenuItem[]) => {
256
- inputValue.value = value;
257
- // selectedResourceList 为当前编辑器中已选中的 @ 资源列表
258
- console.log('已选资源:', selectedResourceList);
259
- };
260
-
261
- const handleSendMessage = async (content: string, docSchema: TagSchema) => {
262
- console.log('发送内容(含 @ 引用):', docSchema);
263
- };
264
-
265
- const handleStopSending = async () => {
266
- messageStatus.value = MessageStatus.Stop;
264
+ const handleSendMessage = async (content: string) => {
265
+ console.log('引用内容:', citeContent.value);
266
+ citeContent.value = ''; // 发送后自行清空
267
267
  };
268
268
  </script>
269
269
  ```
270
270
 
271
- > 基础用法 demo 已集成 Prompt 和资源功能,可在上方输入框中体验 `/` 和 `@` 操作。
272
- >
273
- > **注意**:`v-model` 仍可使用(Vue 自动取第一个参数绑定),但如需获取 `selectedResourceList`,应使用 `@update:model-value` 显式监听。
274
-
275
271
  ## 快捷指令
276
272
 
277
- 通过 `shortcuts` 传入快捷指令列表,底部工具栏展示快捷指令按钮;通过 `shortcutId` + `shortcuts` 配合控制选中状态:
273
+ `shortcuts` 传入列表,底部工具栏展示快捷指令按钮;`shortcutId` 控制选中态:
278
274
 
279
- - `shortcutId` 为空 → 显示所有快捷指令按钮列表
280
- - `shortcutId` 匹配某个 `shortcut.id` → 隐藏列表,显示已选指令 + 关闭图标
275
+ - `shortcutId` 为空 → 显示全部快捷指令按钮
276
+ - `shortcutId` 命中某个 `shortcut.id` → 收起列表,显示已选指令 + 关闭图标
281
277
 
282
278
  ```vue
283
279
  <template>
284
280
  <ChatInput
285
281
  v-model="inputValue"
286
- :message-status="messageStatus"
287
282
  :shortcuts="shortcuts"
288
283
  :shortcut-id="selectedShortcutId"
289
284
  :on-send-message="handleSendMessage"
290
- :on-stop-sending="handleStopSending"
291
285
  @select-shortcut="selectedShortcutId = $event.id"
292
286
  @delete-shortcut="selectedShortcutId = ''"
293
287
  />
294
288
  </template>
295
-
296
- <script setup lang="ts">
297
- import { ref } from 'vue';
298
- import { ChatInput, MessageStatus, type TagSchema, type Shortcut } from '@blueking/chat-x';
299
-
300
- const inputValue = ref('');
301
- const messageStatus = ref(MessageStatus.Complete);
302
- const selectedShortcutId = ref('');
303
-
304
- const shortcuts: Shortcut[] = [
305
- { id: 'translate', name: '翻译' },
306
- { id: 'explain', name: '解释代码' },
307
- { id: 'summarize', name: '总结' },
308
- ];
309
-
310
- const handleSendMessage = async (content: string, docSchema: TagSchema) => {
311
- console.log('发送内容:', content, '当前快捷指令:', selectedShortcutId.value);
312
- };
313
-
314
- const handleStopSending = async () => {
315
- messageStatus.value = MessageStatus.Stop;
316
- };
317
- </script>
318
289
  ```
319
290
 
320
- **渲染效果**(底部显示快捷指令按钮,点击选中后按钮变为已选状态)
321
-
322
291
  ## 文件上传 {#file-upload}
323
292
 
324
- `supportUpload` 默认为 `true`,底部工具栏自动显示文件上传按钮。传入 `onUpload` 回调后即可处理文件上传:
293
+ `supportUpload` 默认 `true`。附件入口有三条路径:**+ 号菜单的「文件」项**、**拖拽到输入框**、**粘贴(Ctrl+V)**。`type: 'file'` 是组件内置动作项,不要写进 `menuSources`。
294
+
295
+ 选中「文件」后唤起隐藏 `input[type=file]`,与拖拽 / 粘贴共用同一套 `handleUpload` / `onUpload`。系统选择器与入队校验都走 `accept` prop(默认 `DEFAULT_UPLOAD_ACCEPT`,含图片 / 文档 / 文本 / 代码扩展名)。
325
296
 
326
- - 底部工具栏出现文件上传按钮(在快捷指令左侧)
327
- - 支持**点击选择**、**拖拽上传**、**粘贴上传**(Ctrl+V)
328
- - `onUpload` 一次选择传入**全部** `File[]`,返回同序的结果数组(也可对单文件返回单个对象);元素为 `{ download_url?: string; id?: string; status?: 'failed' | 'success' }`
297
+ - `onUpload` 一次选择传入**全部** `File[]`,返回同序的结果数组(也可对单文件返回单个对象);元素为 `{ download_url?: string; id?: string; path?: string; status?: 'failed' | 'success' }`
329
298
  - 文件自动去重(基于 `name + size + lastModified` 复合键),不会重复上传
299
+ - 上传成功后将响应 `path` 保存为附件的 `outputId`(`id` 缺省时也以 `path` 回填)。**展示名始终取本地 `File.name`(编辑态回填时取 `filename`),选中即可见、不等上传返回,上传完成后也不会跳变**;`artifact` 标签的 `label` 与 `@` 菜单条目名同源于此。具有 `outputId` 的文件立即进入 `@` / `+` 的「会话产物」菜单和容器预览侧栏;发送时保留 `outputId`,已发送附件与助手产物共用引用、预览和下载能力。仅有 `id`、URL 或文件名的旧附件不作为会话产物收集。
300
+ - 取消附件时立即从 UI 移除,并触发 `deleteFile` 事件(模板使用 `@delete-file`),参数为 `Partial<UploadFile>`。业务方可根据 `file.id` 调用删除接口;组件不等待接口结果,成功或失败均不恢复附件。上传中 / 上传失败的附件也会触发事件,此时 `id` 可能为空,由业务方决定是否调用接口。发送后清空列表不会触发此事件。
330
301
  - **上传中或存在失败附件时禁止发送**(点击、Enter、`triggerSendMessage` 均拦截)。失败附件需用户删除后才能再发;不要把附件 Pending 映射成 `MessageStatus.Pending`
331
- - 发送成功后,`uploadFiles` 自动清空
302
+ - 拖拽只响应从系统拖入的文件(编辑器内部标签拖动不会误触发),悬停时框体切换为蓝色描边 + 浅蓝底
303
+ - 发送成功后待发送列表自动清空;文件加入列表后光标自动回到输入区
332
304
 
333
- **个数、大小与格式校验(与 `FileUploadBtn` 分工)**:
305
+ **个数、大小与格式校验**:
334
306
 
335
307
  - 列表最多保留 **`MAX_UPLOAD_FILES`(9)** 个待发送附件;已满时再次选择/拖入/粘贴文件会弹出 **bkui-vue `Message` 错误提示**(`formatUploadNotAddedMessage`),且不会继续入队。
336
- - 在未满的前提下:空文件、单文件大小 **`>= MAX_UPLOAD_FILE_SIZE`(约 2.4MB)** 会被跳过并弹出超大小/个数提示。与已有文件重复的项只去重、不弹这条误导文案。
308
+ - 在未满的前提下:空文件、单文件大小 **`>= MAX_UPLOAD_FILE_SIZE`(20MB,即 `20 * 1024 * 1024` 字节)** 会被跳过并弹出超大小/个数提示。与已有文件重复的项只去重、不弹这条误导文案。
337
309
  - **文件类型**:默认使用 `DEFAULT_UPLOAD_ACCEPT`(图片 / 文档 / 文本 / 代码扩展名列表)。系统文件选择框带 `accept` 过滤;选择后、拖拽、粘贴仍会再按扩展名校验,不支持的格式弹出「因格式不支持未添加」并不会入队。可通过 `accept` prop 覆盖(空字符串表示不限制)。
338
- - `FileUploadBtn` 仅在按钮层过滤**空文件与单文件超大**,把合法文件以数组形式 `upload` 上来;**个数上限、重复校验与类型校验**在 `ChatInput` 的 `handleUpload` 中统一处理,避免与按钮层各弹一条提示。
310
+ - 个数上限、重复、大小与类型校验都在 `ChatInput` 的 `handleUpload` 中统一处理(含 + 号菜单唤起的系统文件选择器、拖拽和粘贴)。
339
311
 
340
- **发送内容格式**(有文件时):
312
+ **发送内容格式**(有文件时 `content` 变为数组):
341
313
 
342
314
  ```typescript
343
- // onSendMessage 的 content 参数变为数组:
344
315
  [
345
- { type: 'binary', url: '...', mimeType: 'image/png', filename: 'a.png' },
346
- { type: 'binary', url: '...', mimeType: 'application/pdf', filename: 'b.pdf' },
347
- // 若输入框也有文字,则最后追加:
316
+ { type: 'binary', url: '...', mimeType: 'image/png', filename: 'a.png', size: 10240 },
317
+ { type: 'binary', url: '...', mimeType: 'application/pdf', filename: 'b.pdf', size: 20480 },
318
+ // 输入框有实际文字时才追加文本段,纯附件消息不带空文本
348
319
  { type: 'text', text: '请帮我分析这两个文件' },
349
320
  ];
350
321
  ```
@@ -353,6 +324,7 @@ const handleSendMessage = async (
353
324
  <template>
354
325
  <ChatInput
355
326
  v-model="inputValue"
327
+ :accept="DEFAULT_UPLOAD_ACCEPT"
356
328
  :message-status="messageStatus"
357
329
  :on-send-message="handleSendMessage"
358
330
  :on-stop-sending="handleStopSending"
@@ -362,11 +334,19 @@ const handleSendMessage = async (
362
334
 
363
335
  <script setup lang="ts">
364
336
  import { ref } from 'vue';
365
- import { ChatInput, MessageStatus, type UserMessage, type TagSchema } from '@blueking/chat-x';
337
+ import {
338
+ ChatInput,
339
+ DEFAULT_UPLOAD_ACCEPT,
340
+ MessageStatus,
341
+ type TagSchema,
342
+ type UserMessage,
343
+ } from '@blueking/chat-x';
366
344
 
367
345
  const inputValue = ref('');
368
346
  const messageStatus = ref(MessageStatus.Complete);
369
347
 
348
+ // accept 约束「文件」项 / 拖拽 / 粘贴以及入队校验(默认已含图片扩展名)。
349
+
370
350
  const handleSendMessage = async (content: UserMessage['content'], docSchema: TagSchema) => {
371
351
  if (Array.isArray(content)) {
372
352
  // 有文件时 content 为数组
@@ -384,7 +364,7 @@ const handleSendMessage = async (
384
364
  messageStatus.value = MessageStatus.Stop;
385
365
  };
386
366
 
387
- // 一次选择多个文件只回调一次,按文件顺序返回结果
367
+ // 「文件」选中后走这里:一次选择多个文件只回调一次,按文件顺序返回结果
388
368
  const handleUpload = async (files: File[]) => {
389
369
  const formData = new FormData();
390
370
  files.forEach(file => formData.append('files', file));
@@ -394,104 +374,82 @@ const handleSendMessage = async (
394
374
  </script>
395
375
  ```
396
376
 
397
- **渲染效果**(底部出现文件上传按钮,支持点击、拖拽、粘贴上传)
377
+ **渲染效果**(点击左下角 +,「添加」分组里选「文件」)
398
378
 
399
- ## 预设上传文件(defaultUploadFiles)
379
+ ### 预设上传文件(defaultUploadFiles)
400
380
 
401
- 通过 `defaultUploadFiles` 设置初始已上传的文件列表,文件出现在文件预览区,随下次发送一起携带:
381
+ 设置初始已上传文件,出现在文件预览区并随下次发送一起携带:
402
382
 
403
- ```vue
404
- <script setup lang="ts">
405
- import { type UploadFile, UploadStatus } from '@blueking/chat-x';
406
-
407
- const defaultFiles: UploadFile[] = [
408
- {
409
- type: 'binary',
410
- url: 'https://example.com/report.pdf',
411
- filename: 'report.pdf',
412
- mimeType: 'application/pdf',
413
- status: UploadStatus.Success,
414
- },
415
- ];
416
- </script>
383
+ ```typescript
384
+ import { type UploadFile, UploadStatus } from '@blueking/chat-x';
385
+
386
+ const defaultFiles: UploadFile[] = [
387
+ {
388
+ type: 'binary',
389
+ url: 'https://example.com/report.pdf',
390
+ filename: 'report.pdf',
391
+ mimeType: 'application/pdf',
392
+ status: UploadStatus.Success,
393
+ },
394
+ ];
417
395
  ```
418
396
 
419
- ## 自定义占位符
397
+ ## 模型选择
420
398
 
421
- 未传入 `placeholder` 时,组件会按 `skills` / `prompts` / `resources` 是否非空动态生成提示行。传入后完全覆盖,支持多行(换行用 `\n`):
399
+ 传入 `models` 后在发送按钮左侧展示 [ModelSelector](/components/input/model-selector)。选中值(模型的 `llm_name`)通过 `v-model:selected-model` 双向绑定,`@model-change` 可获取完整模型对象,能力标签由组件依据 `property` 自动派生。
422
400
 
423
401
  ```vue
424
402
  <template>
425
403
  <ChatInput
426
404
  v-model="inputValue"
427
- :message-status="messageStatus"
428
- :placeholder="placeholder"
405
+ v-model:selected-model="selectedModel"
406
+ :models="models"
429
407
  :on-send-message="handleSendMessage"
430
- :on-stop-sending="handleStopSending"
408
+ @model-change="handleModelChange"
431
409
  />
432
410
  </template>
433
-
434
- <script setup lang="ts">
435
- // 多行占位符
436
- const placeholder = `你好,我是 AI 小鲸!
437
- 输入 "/" 唤出 Prompt
438
- 输入 "@" 唤出工具
439
- 按 Shift + Enter 换行`;
440
- </script>
441
411
  ```
442
412
 
443
- **渲染效果**
413
+ 也可通过 `#model-selector` 插槽完全自定义,插槽参数为 `{ models, selectedModel }`:
444
414
 
445
- ## 自定义插槽
446
-
447
- 组件提供 6 个插槽用于自定义各区域内容:
415
+ ```vue
416
+ <template>
417
+ <ChatInput v-model="inputValue" :models="models">
418
+ <template #model-selector="{ models, selectedModel }">
419
+ <span>当前:{{ selectedModel || '未选择' }}(共 {{ models.length }} 个)</span>
420
+ </template>
421
+ </ChatInput>
422
+ </template>
423
+ ```
448
424
 
449
- | 插槽名 | 位置 | 默认行为 |
450
- | -------------- | ------------------------------------------ | ------------------------------------------ |
451
- | `top` | 框体外部顶部(`.chat-input` 上方) | 无 |
452
- | `interrupt` | 框体外部顶部,位于 `top` 之后 | 无,通常用于展示审批/中断提示 |
453
- | `input-header` | 框体内部顶部(编辑器上方) | `cite` 不为空时渲染引用区(`CiteContent`) |
454
- | `files` | 文件预览区 | 有上传文件时渲染 `FileContent` |
455
- | `attachment` | 底部工具栏快捷指令区(FileUploadBtn 右侧) | 快捷指令按钮列表 / 已选快捷指令 |
456
- | `send-icon` | 发送按钮内的图标 | 发送图标 / 停止图标(按钮容器由组件控制) |
425
+ ## 自定义插槽
457
426
 
458
427
  ```vue
459
428
  <template>
460
- <ChatInput
461
- v-model="inputValue"
462
- :message-status="messageStatus"
463
- :on-send-message="handleSendMessage"
464
- :on-stop-sending="handleStopSending"
465
- >
466
- <!-- 框体外顶部,适合展示模型信息、Token 消耗等 -->
429
+ <ChatInput v-model="inputValue" :on-send-message="handleSendMessage">
430
+ <!-- 框体外顶部,适合展示模型信息、Token 消耗 -->
467
431
  <template #top>
468
432
  <div class="input-tips">当前模型: GPT-4 · 剩余 Token: 12,800</div>
469
433
  </template>
470
434
 
471
- <!-- 框体外顶部,适合展示中断、审批等业务提示 -->
435
+ <!-- 框体外顶部,适合展示中断、审批提示 -->
472
436
  <template #interrupt>
473
437
  <div class="input-alert">当前会话有待审批单,暂时不能继续发送</div>
474
438
  </template>
475
439
 
476
- <!-- 替换引用区,可自定义引用样式 -->
440
+ <!-- 替换引用区 -->
477
441
  <template #input-header>
478
442
  <div class="custom-header">自定义头部内容</div>
479
443
  </template>
480
444
 
481
445
  <!-- 替换文件预览区,接收 files 参数 -->
482
446
  <template #files="{ files }">
483
- <div class="custom-files">
484
- <span
485
- v-for="file in files"
486
- :key="file.filename"
487
- >{{ file.filename }}</span
488
- >
489
- </div>
447
+ <span v-for="file in files" :key="file.filename">{{ file.filename }}</span>
490
448
  </template>
491
449
 
492
- <!-- 替换快捷指令区(FileUploadBtn 仍在左侧) -->
450
+ <!-- 替换快捷指令区(+ 号仍在左侧) -->
493
451
  <template #attachment>
494
- <button @click="handleCustomAction">🎯 自定义操作</button>
452
+ <button @click="handleCustomAction">自定义操作</button>
495
453
  </template>
496
454
 
497
455
  <!-- 替换发送按钮图标(点击逻辑不变) -->
@@ -502,72 +460,15 @@ const handleSendMessage = async (
502
460
  </template>
503
461
  ```
504
462
 
505
- **渲染效果**(顶部自定义模型信息与中断提示)
506
-
507
- ## 模型选择
508
-
509
- 传入 `models` 后,会在发送按钮左侧展示 [ModelSelector](/components/input/model-selector)。选中值(模型的 `llm_name`)通过 `v-model:selected-model` 双向绑定,`@model-change` 可获取完整模型对象。能力标签由组件依据 `property` 自动派生。
510
-
511
- ```vue
512
- <template>
513
- <ChatInput
514
- v-model="inputValue"
515
- v-model:selected-model="selectedModel"
516
- :message-status="messageStatus"
517
- :models="models"
518
- :on-send-message="handleSendMessage"
519
- @model-change="handleModelChange"
520
- />
521
- </template>
522
-
523
- <script setup lang="ts">
524
- import { ref } from 'vue';
525
- import { ChatInput, MessageStatus, type IModelOption, type TagSchema } from '@blueking/chat-x';
526
-
527
- const inputValue = ref('');
528
- // 选中值为 llm_name
529
- const selectedModel = ref('GPT-4');
530
- const messageStatus = ref(MessageStatus.Complete);
531
- const models: IModelOption[] = [
532
- { id: 1, llm_name: 'GPT-4', property: { support_thinking: true } },
533
- { id: 2, llm_name: 'Claude 3', property: {} },
534
- ];
535
-
536
- const handleSendMessage = async (content: string, docSchema: TagSchema) => {
537
- /* 发送时可读取 selectedModel.value */
538
- };
539
-
540
- const handleModelChange = (model: IModelOption) => {
541
- console.log('切换模型:', model);
542
- };
543
- </script>
544
- ```
545
-
546
- 也可通过 `#model-selector` 插槽完全自定义选择器,插槽参数为 `{ models, selectedModel }`:
547
-
548
- ```vue
549
- <template>
550
- <ChatInput v-model="inputValue" :models="models">
551
- <template #model-selector="{ models, selectedModel }">
552
- <span>当前:{{ selectedModel || '未选择' }}(共 {{ models.length }} 个)</span>
553
- </template>
554
- </ChatInput>
555
- </template>
556
- ```
557
-
558
463
  ## Expose(模板引用)
559
464
 
560
- 通过 `ref` 获取组件实例后可调用以下方法:
561
-
562
465
  ```vue
563
466
  <template>
564
- <ChatInput
565
- ref="chatInputRef"
566
- v-model="inputValue"
567
- :on-send-message="handleSendMessage"
568
- />
467
+ <ChatInput ref="chatInputRef" v-model="inputValue" :on-send-message="handleSendMessage" />
569
468
  <button @click="chatInputRef?.focus()">聚焦输入框</button>
570
- <button @click="chatInputRef?.triggerSendMessage()">手动发送</button>
469
+ <button @click="chatInputRef?.insertMention({ id: 'output-1', type: 'artifact', name: '巡检报告.pdf' })">
470
+ 引用产物
471
+ </button>
571
472
  </template>
572
473
 
573
474
  <script setup lang="ts">
@@ -575,130 +476,129 @@ const handleSendMessage = async (
575
476
  import { ChatInput } from '@blueking/chat-x';
576
477
 
577
478
  const chatInputRef = useTemplateRef<InstanceType<typeof ChatInput>>('chatInputRef');
578
- const inputValue = ref('');
579
- const handleSendMessage = async (content: string) => {
580
- /* ... */
581
- };
582
479
  </script>
583
480
  ```
584
481
 
482
+ > 在 [ChatContainer](/components/setup/chat-container) 内部时,消息区与侧栏可以直接用 [useInputMention](/composables/use-input-mention) 把资源「@ 进输入框」,无需自行持有 `ChatInput` 实例。
483
+
585
484
  ## API
586
485
 
587
486
  ### Props
588
487
 
589
- | 属性名 | 类型 | 默认值 | 必填 | 说明 |
590
- | ------------------ | -------------------------------------------------------------------------- | -------- | ---- | ------------------------------------------------------- |
591
- | modelValue | `string \| TagSchema` | - | ✅ | 编辑器的值,支持 `v-model` |
592
- | selectedModel | `string` | - | - | 当前选中模型的 `llm_name`,支持 `v-model:selected-model` |
593
- | messageStatus | `MessageStatus` | - | - | 消息状态,控制按钮;输入为空时内部强制 `disabled` |
594
- | cite | `string` | `''` | - | 引用内容,支持 `v-model:cite`,不为空时显示引用区 |
595
- | skills | `ISkillListItem[]` | `[]` | - | Skill 列表,输入 `/` 触发,选中后插入 Skill 标签 |
596
- | prompts | `string[]` | `[]` | - | Prompt 模板列表,输入 `\` 触发 |
597
- | resources | `IAiSlashMenuItem[]` | `[]` | - | 资源列表,输入 `@` 触发,按 `type` 分组展示 |
598
- | shortcuts | `Shortcut[]` | - | - | 快捷指令列表,显示在底部工具栏 |
599
- | models | `IModelOption[]` | - | - | 可选模型列表,传入后在发送按钮左侧展示模型选择器 |
600
- | shortcutId | `string` | - | - | 当前选中的快捷指令 ID,匹配时列表收起为已选样式 |
601
- | placeholder | `string` | 动态默认 | - | 编辑器占位符,支持多行;未传时按 skills/prompts/resources 动态拼接 |
602
- | inputMaxHeight | `number` | `280` | - | 框体最大高度(px),有文件时自动加上文件预览区高度 |
603
- | defaultUploadFiles | `UploadFile[]` | - | - | 预设已上传的文件列表 |
604
- | sendDisabledTip | `string` | - | - | 业务阻塞发送时的 tooltip 提示;传入后发送按钮置灰,点击、Enter 与 `triggerSendMessage()` 均不会发送 |
605
- | supportUpload | `boolean` | `true` | - | 是否显示文件上传按钮 |
606
- | accept | `string` | `DEFAULT_UPLOAD_ACCEPT` | - | 文件选择框过滤类型,同时用于选择/拖拽/粘贴后的扩展名校验;空字符串表示不限制 |
607
- | tippyOptions | `AITippyProps` | | - | 透传给 FileUploadBtn InputAttachment tooltip 配置 |
608
- | onSendMessage | `(content: UserMessage['content'], docSchema: TagSchema, options?: { interrupt?: Interrupt; payload?: InterruptResume }) => Promise<void>` | - | - | 发送消息回调,无文件时 content 为字符串,有文件时为数组;经 [ChatContainer](/components/setup/chat-container) 使用时,存在待回答 UserQuestion 会传入第三参数 `options` |
609
- | onStopSending | `() => Promise<void>` | - | - | 停止发送回调,点击停止按钮时触发 |
488
+ | 属性名 | 类型 | 默认值 | 必填 | 说明 |
489
+ | ------------------ | ---------------------------------------------------- | -------- | ---- | -------------------------------------------------------------------- |
490
+ | modelValue | `string \| TagSchema` | - | ✅ | 编辑器的值,支持 `v-model` |
491
+ | menuSources | `IInputMenuItem[]` | `[]` | - | 统一菜单数据源,按 `type` 分发到 `/` `@` `\` 与 + 号 |
492
+ | menuGroupItemLimit | `number` | `4` | - | 每个分组默认展示条数,超出折叠为「更多 +N」 |
493
+ | selectedModel | `string` | - | - | 当前选中模型的 `llm_name`,支持 `v-model:selected-model` |
494
+ | cite | `string` | `''` | - | 引用内容,支持 `v-model:cite`,不为空时显示引用区 |
495
+ | messageStatus | `MessageStatus` | - | - | 消息状态,控制按钮;输入为空且无附件时内部强制 `disabled` |
496
+ | shortcuts | `Shortcut[]` | - | - | 快捷指令列表,显示在底部工具栏 |
497
+ | shortcutId | `string` | - | - | 当前选中的快捷指令 ID,命中时列表收起为已选样式 |
498
+ | models | `IModelOption[]` | - | - | 可选模型列表,非空时在发送按钮左侧展示模型选择器 |
499
+ | placeholder | `string` | 动态默认 | - | 编辑器占位符,支持多行;未传时按 `menuSources` 的类型动态拼接 |
500
+ | inputMaxHeight | `number` | `280` | - | 框体最大高度(px),有文件时自动叠加文件预览区高度 |
501
+ | defaultUploadFiles | `UploadFile[]` | - | - | 预设已上传的文件列表 |
502
+ | sendDisabledTip | `string` | - | - | 阻塞发送时的 tooltip;传入后点击、Enter 与 `triggerSendMessage()` 均不发送 |
503
+ | supportUpload | `boolean` | `true` | - | 是否开启上传能力(内置「文件」菜单项、拖拽与粘贴) |
504
+ | accept | `string` | `DEFAULT_UPLOAD_ACCEPT` | - | 「文件」项 / 拖拽 / 粘贴的过滤类型,同时用于入队后的扩展名校验;空字符串表示不限制 |
505
+ | tippyOptions | `AITippyProps` | - | - | 透传给 AddMenuBtn、InputAttachment、ModelSelector 的 tooltip 配置 |
506
+ | onSendMessage | `(content: UserMessage['content'], docSchema: TagSchema, options?: { interrupt?: Interrupt; payload?: InterruptResume }) => Promise<void>` | - | - | 发送回调;无文件时 `content` 为字符串,有文件时为数组;第三参数由 [ChatContainer](/components/setup/chat-container) UserQuestion 场景注入 |
507
+ | onStopSending | `() => Promise<void>` | - | - | 停止发送回调 |
610
508
  | onUpload | `(files: File[]) => Promise<ChatInputUploadResult \| ChatInputUploadResult[]>` | - | - | 文件上传回调(一次选择批量传入);上传中/失败附件会阻塞发送 |
611
509
 
612
- ### 默认占位符
613
-
614
- 未传入 `placeholder` 时,根据当前 `skills` / `prompts` / `resources` 是否非空动态拼接(有对应能力才显示该行),始终保留换行提示:
615
-
616
- ```
617
- 输入 "/" 唤出 Skill // 仅当 skills 非空
618
- 输入 "\" 唤出 Prompt // 仅当 prompts 非空
619
- 输入 "@" 唤出 工具和 MCP // 仅当 resources 非空
620
- 通过 Shift + Enter 进行换行输入 // 始终显示
621
- ```
622
-
623
- 显式传入 `placeholder`(含空字符串)时完全覆盖上述默认文案。三种列表都为空时,只显示换行提示。
624
-
625
510
  ### Events
626
511
 
627
- | 事件名 | 参数 | 触发时机 |
628
- | ----------------- | ------------------------------------------------------------------------ | --------------------------------------------------------- |
629
- | update:modelValue | `(value: string \| TagSchema, selectedResourceList: IAiSlashMenuItem[])` | 编辑器值变化时触发;第二个参数为当前已选中的 `@` 资源列表 |
630
- | modelChange | `(model: IModelOption)` | 用户切换模型时触发 |
631
- | selectShortcut | `(shortcut: Shortcut)` | 点击底部快捷指令按钮 |
632
- | deleteShortcut | - | 点击已选快捷指令旁的关闭按钮 |
512
+ | 事件名 | 参数 | 触发时机 |
513
+ | ----------------- | --------------------------------------------------------------------- | ------------------------------------------------------------ |
514
+ | update:modelValue | `(value: string \| TagSchema, selectedResourceList: IInputMenuItem[])` | 编辑器值变化;第二参数为文档中能在 `menuSources` 反查到的条目 |
515
+ | modelChange | `(model: IModelOption)` | 用户切换模型 |
516
+ | selectShortcut | `(shortcut: Shortcut)` | 点击底部快捷指令按钮 |
517
+ | deleteShortcut | - | 点击已选快捷指令旁的关闭按钮 |
518
+ | deleteFile | `(file: Partial<UploadFile>)` | 用户取消附件;携带文件 `id`、状态等信息,UI 立即移除,不等待删除接口 |
633
519
 
634
520
  ### Slots
635
521
 
636
- | 插槽名 | 参数 | 说明 |
637
- | ------------ | ---------------------------------- | ---------------------------------------------------------- |
638
- | top | - | 框体(`.chat-input`)外部顶部,适合展示模型/Token 信息 |
639
- | interrupt | - | 框体外部顶部,位于 `top` 后,适合展示审批/中断提示 |
640
- | input-header | - | 框体内顶部,替换引用区(`CiteContent`) |
641
- | files | `{ files: Partial<UploadFile>[] }` | 文件预览区 |
642
- | attachment | - | 底部快捷指令区,`FileUploadBtn` 在其左侧,不受此 slot 影响 |
643
- | model-selector | `{ models: IModelOption[]; selectedModel: string \| undefined }` | 发送按钮左侧模型选择区,默认渲染 ModelSelector |
644
- | send-icon | - | 发送按钮内图标,按钮的点击逻辑和样式仍由组件控制 |
522
+ | 插槽名 | 参数 | 说明 |
523
+ | -------------- | ---------------------------------------------------------------- | -------------------------------------------------------- |
524
+ | top | - | 框体外部顶部,适合展示模型 / Token 信息 |
525
+ | interrupt | - | 框体外部顶部,位于 `top` 之后,适合展示审批 / 中断提示 |
526
+ | input-header | - | 框体内顶部,替换引用区(`CiteContent`) |
527
+ | files | `{ files: Partial<UploadFile>[] }` | 文件预览区 |
528
+ | attachment | - | 底部快捷指令区,`AddMenuBtn` 在其左侧,不受此插槽影响 |
529
+ | model-selector | `{ models: IModelOption[]; selectedModel: string \| undefined }` | 发送按钮左侧模型选择区,默认渲染 `ModelSelector` |
530
+ | send-icon | - | 发送按钮内图标,点击逻辑与样式仍由组件控制 |
645
531
 
646
532
  ### Expose
647
533
 
648
- | 方法名 | 类型 | 说明 |
649
- | ------------------ | ------------ | ---------------- |
650
- | focus | `() => void` | 聚焦编辑器 |
651
- | triggerSendMessage | `() => void` | 手动触发发送逻辑 |
534
+ `uploadedArtifacts`:只读 `AIFileInfo[]`,包含输入框中已上传且具有 `outputId` 的附件;供容器合并到侧栏预览列表,取消或发送后同步更新。
535
+
536
+ | 方法名 | 类型 | 说明 |
537
+ | ------------------ | --------------------------------- | ------------------------------------------------ |
538
+ | focus | `() => void` | 聚焦编辑器并把光标置于末尾 |
539
+ | insertMention | `(item: IInputMenuItem) => void` | 把条目以标签形式追加到文档末尾(不依赖当前光标) |
540
+ | triggerSendMessage | `() => void` | 手动触发发送逻辑 |
652
541
 
653
542
  ## 键盘快捷键
654
543
 
655
- | 快捷键 | 说明 |
656
- | --------------- | ---------------------------------------- |
657
- | `Enter` | 发送消息(输入为空或仅空白字符时不触发) |
658
- | `Shift + Enter` | 换行 |
659
- | `/` | 唤出 Prompt 列表 |
660
- | `@` | 唤出资源列表 |
661
- | `↑` / `↓` | 在 Prompt / 资源菜单中导航 |
662
- | `Esc` | 关闭 Prompt / 资源菜单 |
544
+ | 快捷键 | 说明 |
545
+ | --------------- | ------------------------------------------------ |
546
+ | `Enter` | 发送消息;菜单展开时改为选中当前高亮条目 |
547
+ | `Shift + Enter` | 换行 |
548
+ | `/` `@` `\` | 唤出对应菜单 |
549
+ | `↑` / `↓` | 在菜单条目间导航 |
550
+ | `Esc` | 关闭菜单 |
551
+
552
+ > 点击输入区之外(`mousedown` 捕获阶段)同样会关闭菜单。
663
553
 
664
554
  ## 类型定义
665
555
 
666
556
  > `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。与输入区相关:`pending` / `streaming` / `fetching` → 停止按钮;`complete` / `completed` / `error` / `stop` → 发送;`disabled` → 置灰。
667
557
 
668
558
  ```typescript
669
- import type { UserMessage } from '@blueking/chat-x';
559
+ import type { Component } from 'vue';
560
+
561
+ // 菜单可选项类型;file 为组件内置动作项,不由业务方提供
562
+ type MenuItemType = 'file' | 'skill' | 'mcp' | 'tool' | 'knowledgebase' | 'doc' | 'artifact' | 'prompt';
563
+
564
+ // 菜单触发方式;plus 由左下角 + 号唤起
565
+ type MenuTrigger = '/' | '@' | '\\' | 'plus';
566
+
567
+ interface IInputMenuItem {
568
+ id: string;
569
+ name: string;
570
+ type: MenuItemType;
571
+ /** Prompt 全文;选中 prompt 时整体替换输入框内容 */
572
+ content?: string;
573
+ /** 描述文案,有值时 hover 弹出气泡说明 */
574
+ description?: string;
575
+ disabled?: boolean;
576
+ /** 图标 URL 或 Vue 组件;缺省按 type 回退,artifact 按文件名后缀推导 */
577
+ icon?: Component | string;
578
+ }
670
579
 
671
580
  // 上传状态
672
581
  enum UploadStatus {
673
- Pending = 'pending', // 上传中
674
- Success = 'success', // 上传成功
675
- Error = 'error', // 上传失败
582
+ Pending = 'pending',
583
+ Success = 'success',
584
+ Error = 'error',
676
585
  }
677
586
 
678
587
  // 上传文件
679
588
  type UploadFile = {
680
589
  type: 'binary';
681
- url?: string; // 上传成功后的下载地址
682
- filename?: string; // 文件名
683
- mimeType?: string; // MIME 类型
684
- file?: File; // 原始 File 对象
685
- status?: UploadStatus; // 上传状态
590
+ url?: string;
591
+ filename?: string;
592
+ mimeType?: string;
593
+ file?: File;
594
+ status?: UploadStatus;
686
595
  };
687
596
 
688
- // 资源菜单项(@ 触发)
689
- interface IAiSlashMenuItem {
690
- id: string;
691
- name: string;
692
- icon: string;
693
- type: 'tool' | 'mcp' | 'doc' | 'shortcut'; // 分组类型
694
- }
695
-
696
597
  // onSendMessage 的 content 参数
697
598
  type SendContent =
698
- | string // 无文件时:纯文本
599
+ | string
699
600
  | Array<
700
- // 有文件时:数组
701
- { type: 'binary'; url?: string; mimeType: string; filename: string } | { type: 'text'; text: string }
601
+ { type: 'binary'; url?: string; mimeType: string; filename: string; size?: number } | { type: 'text'; text: string }
702
602
  >;
703
603
 
704
604
  // onSendMessage 完整签名(第三参数由 ChatContainer 在 UserQuestion 场景注入)
@@ -709,70 +609,14 @@ type OnSendMessage = (
709
609
  ) => Promise<void>;
710
610
  ```
711
611
 
712
- ## 完整集成示例
713
-
714
- ```vue
715
- <template>
716
- <ChatInput
717
- v-model="inputValue"
718
- v-model:cite="citeContent"
719
- :message-status="messageStatus"
720
- :prompts="prompts"
721
- :resources="resources"
722
- :shortcuts="shortcuts"
723
- :shortcut-id="shortcutId"
724
- :on-send-message="handleSendMessage"
725
- :on-stop-sending="handleStopSending"
726
- :on-upload="handleUpload"
727
- @select-shortcut="shortcutId = $event.id"
728
- @delete-shortcut="shortcutId = ''"
729
- />
730
- </template>
731
-
732
- <script setup lang="ts">
733
- import { ref } from 'vue';
734
- import { ChatInput, MessageStatus, type TagSchema, type Shortcut } from '@blueking/chat-x';
735
-
736
- const inputValue = ref('');
737
- const citeContent = ref('');
738
- const messageStatus = ref(MessageStatus.Complete);
739
- const shortcutId = ref('');
740
-
741
- const prompts = ['帮我写一篇关于 {topic} 的文章', '解释一下这段代码'];
742
- const resources = [{ id: 'tool1', name: '天气查询', type: 'tool', icon: '' }];
743
- const shortcuts: Shortcut[] = [
744
- { id: 'translate', name: '翻译' },
745
- { id: 'explain', name: '解释' },
746
- ];
747
-
748
- const handleSendMessage = async (content, docSchema: TagSchema) => {
749
- messageStatus.value = MessageStatus.Streaming;
750
- try {
751
- await callAI(content, { cite: citeContent.value, shortcut: shortcutId.value });
752
- } finally {
753
- messageStatus.value = MessageStatus.Complete;
754
- citeContent.value = '';
755
- }
756
- };
757
-
758
- const handleStopSending = async () => {
759
- messageStatus.value = MessageStatus.Stop;
760
- abortAICall();
761
- };
762
-
763
- const handleUpload = async (files: File[]) => {
764
- const formData = new FormData();
765
- files.forEach(file => formData.append('files', file));
766
- const res = await fetch('/api/upload', { method: 'POST', body: formData });
767
- return res.json();
768
- };
769
- </script>
770
- ```
771
-
772
612
  ## 关联组件
773
613
 
774
- - [ShortcutBtns](/components/input/shortcut-btns) — 底部附件区默认快捷指令列表
775
- - [ShortcutBtn](/components/input/shortcut-btn) — 已选快捷指令单按钮展示
776
- - [ShortcutRender](/components/input/shortcut-render) — 含表单的快捷指令表单渲染
614
+ - [AiSlashInput](/components/input/ai-slash-input) — 内部富文本编辑区与标签插入
615
+ - [InputMenuPanel](/components/input/input-menu-panel) — 统一菜单面板与分组折叠逻辑
616
+ - [AddMenuBtn](/components/input/add-menu-btn) — 左下角 + 号聚合菜单入口
617
+ - [MentionTag](/components/rendering/mention-tag) — 编辑器与消息中的资源标签
618
+ - [ModelSelector](/components/input/model-selector) — 模型下拉选择器
619
+ - [ShortcutBtns](/components/input/shortcut-btns) / [ShortcutBtn](/components/input/shortcut-btn) — 快捷指令按钮
620
+ - [CiteContent](/components/rendering/cite-content) — 引用区内容展示
777
621
  - [ChatContainer](/components/setup/chat-container) — 顶层布局中包裹输入区
778
- - [CiteContent](/components/rendering/cite-content) — 消息引用区内容展示
622
+ - [useInputMention](/composables/use-input-mention) — 从消息区 / 侧栏把资源插入输入框