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