@legendzd/ai-agent-vue 1.0.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 +679 -0
- package/dist/ai-agent-vue.css +2 -0
- package/dist/favicon.svg +1 -0
- package/dist/icons.svg +24 -0
- package/dist/index.cjs +239 -0
- package/dist/index.mjs +68891 -0
- package/dist/src/api/agent.d.ts +21 -0
- package/dist/src/components/AIIcon.vue.d.ts +3 -0
- package/dist/src/components/AgentButton.vue.d.ts +13 -0
- package/dist/src/components/AgentHistoryList.vue.d.ts +18 -0
- package/dist/src/components/AgentWindow.vue.d.ts +8 -0
- package/dist/src/components/ChatMessage.vue.d.ts +7 -0
- package/dist/src/components/HistoryPopover.vue.d.ts +15 -0
- package/dist/src/components/OrbCircle.vue.d.ts +14 -0
- package/dist/src/composables/useAgentSetup.d.ts +24 -0
- package/dist/src/composables/useClickOutside.d.ts +7 -0
- package/dist/src/composables/useSpeechRecognition.d.ts +22 -0
- package/dist/src/plugin/index.d.ts +1 -0
- package/dist/src/stores/chat.d.ts +406 -0
- package/dist/src/stores/pinia.d.ts +7 -0
- package/dist/src/types/agent.d.ts +136 -0
- package/dist/src/utils/echart.d.ts +84 -0
- package/dist/src/utils/echarts-zh-cn-locale.d.ts +1 -0
- package/dist/src/views/AgentChat.vue.d.ts +59 -0
- package/dist/src/views/AgentChatFull.vue.d.ts +56 -0
- package/dist/src/views/AgentChatMobile.vue.d.ts +62 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
# @legendzd/ai-agent-vue
|
|
2
|
+
|
|
3
|
+
可嵌入的 AI 智能体 Vue 3 插件 — 三种布局模板(弹窗/全屏/手机端)、多实例隔离、SSE 流式对话、Markdown/图表/数据表格渲染、历史记录切换。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- **三种布局模板** — 按钮弹窗(AgentChatPopup)、完整 Web 窗口(AgentChatFull)、手机端(AgentChatMobile),引入即用
|
|
8
|
+
- **多实例隔离** — 通过 `instanceId` 创建独立对话实例,不同用户/场景互不干扰
|
|
9
|
+
- **零配置即插即用** — 内置 Pinia + 持久化,宿主应用无需额外安装状态管理
|
|
10
|
+
- **会话管理** — 自动创建会话、历史记录、一键切换/新建对话
|
|
11
|
+
- **SSE 流式对话** — 支持 status/sql/data/chart_config/sources/analysis_chunk 等富事件类型
|
|
12
|
+
- **富内容渲染** — Markdown 代码高亮、SQL 可展开复制、结构化数据表格、ECharts 图表、来源标签
|
|
13
|
+
- **深色/浅色主题** — 通过 CSS 变量一键切换或自定义覆盖,所有布局均支持
|
|
14
|
+
- **语音输入** — 基于浏览器 Web Speech API,可配置语言
|
|
15
|
+
- **组件实例 API** — 通过 ref 直接访问对话数据、控制会话
|
|
16
|
+
- **组件拆分** — AgentWindow、AgentHistoryList 等可独立使用,通过 instanceId 关联状态
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @legendzd/ai-agent-vue
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> 仅需 Vue 3.3+ 作为 peer dependency,其余依赖(Pinia、ECharts 等)已内置。
|
|
25
|
+
|
|
26
|
+
## 快速开始
|
|
27
|
+
|
|
28
|
+
### 方式一:插件注册(推荐)
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// main.ts
|
|
32
|
+
import { createApp } from 'vue'
|
|
33
|
+
import { AgentPlugin } from '@legendzd/ai-agent-vue'
|
|
34
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
35
|
+
import App from './App.vue'
|
|
36
|
+
|
|
37
|
+
const app = createApp(App)
|
|
38
|
+
app.use(AgentPlugin, {
|
|
39
|
+
apiUrl: 'http://your-server/api/v2',
|
|
40
|
+
userId: 'user123',
|
|
41
|
+
})
|
|
42
|
+
app.mount('#app')
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
在模板中直接使用(插件注册后组件全局可用):
|
|
46
|
+
|
|
47
|
+
```vue
|
|
48
|
+
<template>
|
|
49
|
+
<!-- 按钮弹窗布局(默认) -->
|
|
50
|
+
<AgentChat />
|
|
51
|
+
|
|
52
|
+
<!-- 等价于 -->
|
|
53
|
+
<AgentChatPopup />
|
|
54
|
+
</template>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 方式二:组件直接引入
|
|
58
|
+
|
|
59
|
+
```vue
|
|
60
|
+
<script setup>
|
|
61
|
+
import { AgentChat } from '@legendzd/ai-agent-vue'
|
|
62
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<AgentChat :config="{
|
|
67
|
+
apiUrl: 'http://your-server/api/v2',
|
|
68
|
+
userId: 'user123',
|
|
69
|
+
headerTitle: 'AI 助手',
|
|
70
|
+
}" />
|
|
71
|
+
</template>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 布局模板
|
|
75
|
+
|
|
76
|
+
插件提供三种布局模板,共享相同的聊天功能,区别仅在外壳布局和交互方式。
|
|
77
|
+
|
|
78
|
+
### AgentChatPopup — 按钮弹窗
|
|
79
|
+
|
|
80
|
+
右下角浮动按钮 + 弹出式聊天窗口,适合嵌入任意页面。
|
|
81
|
+
|
|
82
|
+
```vue
|
|
83
|
+
<AgentChatPopup :config="{
|
|
84
|
+
apiUrl: 'http://your-server/api/v2',
|
|
85
|
+
userId: 'user123',
|
|
86
|
+
}" />
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
特有行为:
|
|
90
|
+
- 浮动按钮点击后弹出/收起聊天窗口
|
|
91
|
+
- 窗口 `position: fixed`,不占用页面布局空间
|
|
92
|
+
- 通过 `toggleWindow()` / `windowVisible` 控制窗口显隐
|
|
93
|
+
|
|
94
|
+
### AgentChatFull — 完整 Web 窗口
|
|
95
|
+
|
|
96
|
+
左侧历史侧栏 + 右侧聊天窗口,适合作为独立聊天页面使用。
|
|
97
|
+
|
|
98
|
+
```vue
|
|
99
|
+
<AgentChatFull
|
|
100
|
+
:config="{ apiUrl: 'http://your-server/api/v2', userId: 'user123' }"
|
|
101
|
+
:show-sidebar="true"
|
|
102
|
+
sidebar-width="280px"
|
|
103
|
+
sidebar-position="left"
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
特有 Props:
|
|
108
|
+
|
|
109
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| `showSidebar` | `boolean` | `true` | 是否显示历史侧栏 |
|
|
112
|
+
| `sidebarWidth` | `string` | `'280px'` | 侧栏宽度 |
|
|
113
|
+
| `sidebarPosition` | `'left' \| 'right'` | `'left'` | 侧栏位置 |
|
|
114
|
+
|
|
115
|
+
布局说明:
|
|
116
|
+
- 窗口 `position: relative`,填满父容器(需确保父容器有明确宽高)
|
|
117
|
+
- 侧栏可配置左/右、宽度、是否显示
|
|
118
|
+
- 适合 `<div style="width:100%;height:100vh">` 等全屏容器
|
|
119
|
+
|
|
120
|
+
### AgentChatMobile — 手机端
|
|
121
|
+
|
|
122
|
+
全屏聊天 + 底部抽屉式历史面板,适配移动端安全区域。
|
|
123
|
+
|
|
124
|
+
```vue
|
|
125
|
+
<AgentChatMobile
|
|
126
|
+
:config="{ apiUrl: 'http://your-server/api/v2', userId: 'user123' }"
|
|
127
|
+
safe-area-top="env(safe-area-inset-top, 0px)"
|
|
128
|
+
safe-area-bottom="env(safe-area-inset-bottom, 0px)"
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
特有 Props:
|
|
133
|
+
|
|
134
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
135
|
+
|---|---|---|---|
|
|
136
|
+
| `safeAreaTop` | `string` | `'env(safe-area-inset-top, 0px)'` | 顶部安全区 |
|
|
137
|
+
| `safeAreaBottom` | `string` | `'env(safe-area-inset-bottom, 0px)'` | 底部安全区 |
|
|
138
|
+
|
|
139
|
+
布局说明:
|
|
140
|
+
- 使用 `100dvh` 全屏高度,自动适配移动浏览器地址栏
|
|
141
|
+
- 自动增大触控区域(输入框 3rem、发送按钮 2.5rem、头部 3.5rem)
|
|
142
|
+
- 历史记录从底部滑出抽屉,带遮罩和拖拽把手
|
|
143
|
+
- 适配刘海屏/底部横条安全区域
|
|
144
|
+
- 暴露 `drawerVisible` / `toggleDrawer()` 控制历史抽屉
|
|
145
|
+
|
|
146
|
+
### 三种布局对比
|
|
147
|
+
|
|
148
|
+
| 特性 | AgentChatPopup | AgentChatFull | AgentChatMobile |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
| 触发方式 | 浮动按钮 → 弹窗 | 直接展示 | 直接展示 |
|
|
151
|
+
| 窗口定位 | fixed 浮动 | relative 填满容器 | relative 填满视口 |
|
|
152
|
+
| 历史记录 | 头部气泡弹出 | 左/右侧栏常驻 | 底部抽屉滑出 |
|
|
153
|
+
| 适用场景 | 嵌入任意页面 | 独立聊天页面 | 移动端 App |
|
|
154
|
+
| 自定义参数 | 按钮位置/大小 | 侧栏宽度/位置/显隐 | 安全区/触控尺寸 |
|
|
155
|
+
|
|
156
|
+
### 布局样式自定义
|
|
157
|
+
|
|
158
|
+
所有布局都支持通过 `config.theme` 覆盖 CSS 变量:
|
|
159
|
+
|
|
160
|
+
```vue
|
|
161
|
+
<!-- Full 布局自定义侧栏样式 -->
|
|
162
|
+
<AgentChatFull :config="{
|
|
163
|
+
apiUrl: '...',
|
|
164
|
+
theme: {
|
|
165
|
+
'--agent-sidebar-width': '320px',
|
|
166
|
+
'--agent-header-bg': '#2563eb',
|
|
167
|
+
}
|
|
168
|
+
}" />
|
|
169
|
+
|
|
170
|
+
<!-- Mobile 布局自定义触控尺寸 -->
|
|
171
|
+
<AgentChatMobile :config="{
|
|
172
|
+
apiUrl: '...',
|
|
173
|
+
theme: {
|
|
174
|
+
'--agent-input-min-height': '3.5rem',
|
|
175
|
+
'--agent-send-size': '3rem',
|
|
176
|
+
}
|
|
177
|
+
}" />
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
布局特有 CSS 变量:
|
|
181
|
+
|
|
182
|
+
| 变量 | 默认值 | 说明 | 适用布局 |
|
|
183
|
+
|---|---|---|---|
|
|
184
|
+
| `--agent-sidebar-width` | `17.5rem` | 历史侧栏宽度 | Full |
|
|
185
|
+
| `--agent-sidebar-bg` | `var(--agent-window-bg)` | 侧栏背景 | Full |
|
|
186
|
+
| `--agent-sidebar-border-color` | `#253354` / `#e2e8f0` | 侧栏边框色 | Full |
|
|
187
|
+
| `--agent-safe-area-top` | `env(safe-area-inset-top, 0px)` | 顶部安全区 | Mobile |
|
|
188
|
+
| `--agent-safe-area-bottom` | `env(safe-area-inset-bottom, 0px)` | 底部安全区 | Mobile |
|
|
189
|
+
| `--agent-window-position` | `fixed` | 窗口定位方式 | 所有(自动覆盖) |
|
|
190
|
+
|
|
191
|
+
## 多实例使用
|
|
192
|
+
|
|
193
|
+
通过 `instanceId` 创建多个独立对话实例,每个实例拥有独立的会话、消息和历史记录。
|
|
194
|
+
|
|
195
|
+
### 场景一:不同用户
|
|
196
|
+
|
|
197
|
+
```vue
|
|
198
|
+
<script setup>
|
|
199
|
+
import { AgentChatPopup } from '@legendzd/ai-agent-vue'
|
|
200
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
201
|
+
</script>
|
|
202
|
+
|
|
203
|
+
<template>
|
|
204
|
+
<!-- 用户 A 的对话 -->
|
|
205
|
+
<AgentChatPopup :config="{
|
|
206
|
+
apiUrl: 'http://your-server/api/v2',
|
|
207
|
+
userId: 'user-a',
|
|
208
|
+
instanceId: 'user-a',
|
|
209
|
+
}" />
|
|
210
|
+
|
|
211
|
+
<!-- 用户 B 的对话(独立会话/消息/历史) -->
|
|
212
|
+
<AgentChatPopup :config="{
|
|
213
|
+
apiUrl: 'http://your-server/api/v2',
|
|
214
|
+
userId: 'user-b',
|
|
215
|
+
instanceId: 'user-b',
|
|
216
|
+
theme: {
|
|
217
|
+
'--agent-btn-bottom': '6rem', // 避免与用户A的按钮重叠
|
|
218
|
+
'--agent-btn-right': '1.75rem',
|
|
219
|
+
}
|
|
220
|
+
}" />
|
|
221
|
+
</template>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 场景二:不同业务场景
|
|
225
|
+
|
|
226
|
+
```vue
|
|
227
|
+
<script setup>
|
|
228
|
+
import { AgentChatFull } from '@legendzd/ai-agent-vue'
|
|
229
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
230
|
+
</script>
|
|
231
|
+
|
|
232
|
+
<template>
|
|
233
|
+
<!-- 数据分析助手 -->
|
|
234
|
+
<AgentChatFull
|
|
235
|
+
instance-id="analytics"
|
|
236
|
+
:config="{
|
|
237
|
+
apiUrl: 'http://your-server/api/v2',
|
|
238
|
+
userId: 'user123',
|
|
239
|
+
headerTitle: '数据分析助手',
|
|
240
|
+
promptTemplateId: 1,
|
|
241
|
+
}"
|
|
242
|
+
/>
|
|
243
|
+
</template>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 场景三:混合布局 + 共享实例
|
|
247
|
+
|
|
248
|
+
不同布局组件通过相同的 `instanceId` 共享同一份对话数据:
|
|
249
|
+
|
|
250
|
+
```vue
|
|
251
|
+
<script setup>
|
|
252
|
+
import { ref } from 'vue'
|
|
253
|
+
import { AgentChatPopup, AgentChatFull, AgentChatMobile } from '@legendzd/ai-agent-vue'
|
|
254
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
255
|
+
|
|
256
|
+
const layout = ref('popup')
|
|
257
|
+
const sharedConfig = {
|
|
258
|
+
apiUrl: 'http://your-server/api/v2',
|
|
259
|
+
userId: 'user123',
|
|
260
|
+
instanceId: 'shared-chat', // 相同 ID 共享数据
|
|
261
|
+
}
|
|
262
|
+
</script>
|
|
263
|
+
|
|
264
|
+
<template>
|
|
265
|
+
<div>
|
|
266
|
+
<button @click="layout = 'popup'">弹窗</button>
|
|
267
|
+
<button @click="layout = 'full'">全屏</button>
|
|
268
|
+
<button @click="layout = 'mobile'">手机</button>
|
|
269
|
+
|
|
270
|
+
<AgentChatPopup v-if="layout === 'popup'" :config="sharedConfig" />
|
|
271
|
+
<AgentChatFull v-else-if="layout === 'full'" :config="sharedConfig" />
|
|
272
|
+
<AgentChatMobile v-else :config="sharedConfig" />
|
|
273
|
+
</div>
|
|
274
|
+
</template>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 场景四:组件拆分独立使用
|
|
278
|
+
|
|
279
|
+
`AgentWindow` 和 `AgentHistoryList` 可脱离布局模板独立使用,通过 `instanceId` 关联状态:
|
|
280
|
+
|
|
281
|
+
```vue
|
|
282
|
+
<script setup>
|
|
283
|
+
import { AgentWindow, AgentHistoryList } from '@legendzd/ai-agent-vue'
|
|
284
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
285
|
+
</script>
|
|
286
|
+
|
|
287
|
+
<template>
|
|
288
|
+
<div style="display:flex;height:100vh;">
|
|
289
|
+
<!-- 左侧:自定义历史面板 -->
|
|
290
|
+
<aside style="width:240px;border-right:1px solid #e2e8f0;">
|
|
291
|
+
<AgentHistoryList
|
|
292
|
+
instance-id="my-chat"
|
|
293
|
+
:config="{ apiUrl: 'http://your-server/api/v2', userId: 'user123' }"
|
|
294
|
+
@select="(id) => console.log('切换到', id)"
|
|
295
|
+
@new-chat="() => console.log('新建聊天')"
|
|
296
|
+
/>
|
|
297
|
+
</aside>
|
|
298
|
+
|
|
299
|
+
<!-- 右侧:聊天窗口 -->
|
|
300
|
+
<main style="flex:1;">
|
|
301
|
+
<AgentWindow instance-id="my-chat" />
|
|
302
|
+
</main>
|
|
303
|
+
</div>
|
|
304
|
+
</template>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 编程式多实例管理
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
import {
|
|
311
|
+
getOrCreateChatInstance,
|
|
312
|
+
getChatInstance,
|
|
313
|
+
destroyChatInstance,
|
|
314
|
+
chatStore,
|
|
315
|
+
} from '@legendzd/ai-agent-vue'
|
|
316
|
+
|
|
317
|
+
// 创建或获取实例(传入配置会初始化实例)
|
|
318
|
+
const instanceA = getOrCreateChatInstance('user-a', {
|
|
319
|
+
apiUrl: 'http://your-server/api/v2',
|
|
320
|
+
userId: 'user-a',
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// 获取已存在的实例(不传配置)
|
|
324
|
+
const existing = getChatInstance('user-a')
|
|
325
|
+
|
|
326
|
+
// chatStore 是 'default' 实例的快捷方式
|
|
327
|
+
console.log(chatStore.sessionId)
|
|
328
|
+
console.log(chatStore.messages)
|
|
329
|
+
|
|
330
|
+
// 销毁实例(清理内存)
|
|
331
|
+
destroyChatInstance('user-a')
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## 配置项(AgentPluginOptions)
|
|
335
|
+
|
|
336
|
+
所有字段均为可选,可通过 `app.use(AgentPlugin, options)` 或 `<组件 :config="options">` 传入。
|
|
337
|
+
|
|
338
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
339
|
+
|---|---|---|---|
|
|
340
|
+
| `apiUrl` | `string` | — | API 基础地址,配置到 `http://host:port/api/v2` 级别 |
|
|
341
|
+
| `getAccessToken` | `() => string` | — | 认证 token 获取函数(惰性调用) |
|
|
342
|
+
| `getSession` | `() => string` | — | 认证 session 获取函数 |
|
|
343
|
+
| `getUserId` | `() => string` | — | 用户 ID 获取函数(动态场景优先使用) |
|
|
344
|
+
| `userId` | `string` | — | 用户 ID 静态值(简化用法,`getUserId` 优先) |
|
|
345
|
+
| `llmProviderId` | `number` | — | LLM 提供商 ID |
|
|
346
|
+
| `promptTemplateId` | `number` | — | 提示词模板 ID |
|
|
347
|
+
| `customPrompt` | `string` | — | 自定义提示词 |
|
|
348
|
+
| `headerTitle` | `string` | `'AI 智能助手'` | 窗口标题 |
|
|
349
|
+
| `emptyText` | `string` | `'有什么可以帮助你的?'` | 空状态提示 |
|
|
350
|
+
| `placeholder` | `string` | `'输入消息... (Enter 发送,Shift+Enter 换行)'` | 输入框占位文本 |
|
|
351
|
+
| `mode` | `'dark' \| 'light'` | `'dark'` | 主题模式 |
|
|
352
|
+
| `theme` | `Record<string, string>` | — | CSS 变量覆盖,如 `{ '--agent-btn-bg': '#2563eb' }` |
|
|
353
|
+
| `enableVoice` | `boolean` | `true` | 是否启用语音输入(浏览器不支持时自动隐藏) |
|
|
354
|
+
| `voiceLang` | `string` | `'zh-CN'` | 语音识别语言 |
|
|
355
|
+
| `instanceId` | `string` | `'default'` | 实例 ID,用于多实例隔离 |
|
|
356
|
+
|
|
357
|
+
### userId 两种写法
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
// 静态值(简单场景)
|
|
361
|
+
{ userId: 'user123' }
|
|
362
|
+
|
|
363
|
+
// 函数(动态场景,如从 store 获取登录用户)
|
|
364
|
+
{ getUserId: () => userStore.userId }
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
API 层优先使用 `getUserId()`,若未提供则 fallback 到 `userId` 静态值。
|
|
368
|
+
|
|
369
|
+
### config prop 合并规则
|
|
370
|
+
|
|
371
|
+
组件同时支持顶层 props 和 `config` prop,`config` 优先:
|
|
372
|
+
|
|
373
|
+
```vue
|
|
374
|
+
<!-- 两种写法等价 -->
|
|
375
|
+
<AgentChat :config="{ apiUrl: '...', userId: 'user123' }" />
|
|
376
|
+
<AgentChat apiUrl="..." user-id="user123" />
|
|
377
|
+
|
|
378
|
+
<!-- config 优先级高于顶层 props -->
|
|
379
|
+
<AgentChat
|
|
380
|
+
user-id="fallback"
|
|
381
|
+
:config="{ userId: 'priority' }"
|
|
382
|
+
/>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## 组件实例 API
|
|
386
|
+
|
|
387
|
+
通过 `ref` 获取组件实例后,可直接访问对话数据和控制方法:
|
|
388
|
+
|
|
389
|
+
```vue
|
|
390
|
+
<script setup>
|
|
391
|
+
import { ref } from 'vue'
|
|
392
|
+
import { AgentChat } from '@legendzd/ai-agent-vue'
|
|
393
|
+
import '@legendzd/ai-agent-vue/dist/style.css'
|
|
394
|
+
|
|
395
|
+
const chatRef = ref()
|
|
396
|
+
</script>
|
|
397
|
+
|
|
398
|
+
<template>
|
|
399
|
+
<AgentChat ref="chatRef" :config="{ apiUrl: '...', userId: 'user123' }" />
|
|
400
|
+
<button @click="chatRef?.toggleWindow()">打开/关闭窗口</button>
|
|
401
|
+
<button @click="chatRef?.newChat()">新建聊天</button>
|
|
402
|
+
<p>当前会话: {{ chatRef?.sessionId }}</p>
|
|
403
|
+
<p>消息数: {{ chatRef?.messages?.length }}</p>
|
|
404
|
+
</template>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 暴露的属性和方法
|
|
408
|
+
|
|
409
|
+
所有布局模板均暴露以下接口:
|
|
410
|
+
|
|
411
|
+
| 名称 | 类型 | 说明 |
|
|
412
|
+
|---|---|---|
|
|
413
|
+
| `sessionId` | `Ref<string>` | 当前会话 ID |
|
|
414
|
+
| `sessions` | `Ref<SessionInfo[]>` | 历史会话列表 |
|
|
415
|
+
| `messages` | `Ref<ChatMessage[]>` | 当前对话消息列表 |
|
|
416
|
+
| `isStreaming` | `Ref<boolean>` | 是否正在流式接收 |
|
|
417
|
+
| `isSessionLoading` | `Ref<boolean>` | 是否正在加载会话 |
|
|
418
|
+
| `initSession()` | `() => Promise<void>` | 初始化会话 |
|
|
419
|
+
| `loadSessions()` | `() => Promise<void>` | 加载/刷新历史会话列表 |
|
|
420
|
+
| `switchSession(id)` | `(id: string) => void` | 切换到指定会话 |
|
|
421
|
+
| `newChat()` | `() => Promise<void>` | 新建聊天(创建新会话并清空消息) |
|
|
422
|
+
| `clearMessages()` | `() => void` | 清空当前对话消息 |
|
|
423
|
+
|
|
424
|
+
各布局特有暴露:
|
|
425
|
+
|
|
426
|
+
| 名称 | 类型 | 适用布局 | 说明 |
|
|
427
|
+
|---|---|---|---|
|
|
428
|
+
| `windowVisible` | `Ref<boolean>` | Popup | 窗口是否可见(可读写) |
|
|
429
|
+
| `toggleWindow()` | `() => void` | Popup | 切换窗口显示/隐藏 |
|
|
430
|
+
| `drawerVisible` | `Ref<boolean>` | Mobile | 历史抽屉是否可见(可读写) |
|
|
431
|
+
| `toggleDrawer()` | `() => void` | Mobile | 切换历史抽屉显隐 |
|
|
432
|
+
|
|
433
|
+
## 主题定制
|
|
434
|
+
|
|
435
|
+
### 切换深色/浅色模式
|
|
436
|
+
|
|
437
|
+
```vue
|
|
438
|
+
<AgentChat :config="{ mode: 'light' }" />
|
|
439
|
+
<AgentChatFull :config="{ mode: 'light' }" />
|
|
440
|
+
<AgentChatMobile :config="{ mode: 'light' }" />
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 覆盖 CSS 变量
|
|
444
|
+
|
|
445
|
+
```vue
|
|
446
|
+
<AgentChat :config="{
|
|
447
|
+
theme: {
|
|
448
|
+
'--agent-btn-bg': '#2563eb',
|
|
449
|
+
'--agent-window-width': '480px',
|
|
450
|
+
'--agent-header-bg': 'transparent',
|
|
451
|
+
}
|
|
452
|
+
}" />
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 可用的 CSS 变量
|
|
456
|
+
|
|
457
|
+
#### 按钮
|
|
458
|
+
|
|
459
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
460
|
+
|---|---|---|
|
|
461
|
+
| `--agent-btn-size` | `3.25rem` | 按钮尺寸 |
|
|
462
|
+
| `--agent-btn-bg` | `#514a9d` | 按钮背景色 |
|
|
463
|
+
| `--agent-btn-bg-hover` | `#24c6dc` | 按钮悬停背景色 |
|
|
464
|
+
| `--agent-btn-icon-color` | `#fff` | 按钮图标颜色 |
|
|
465
|
+
| `--agent-btn-border-radius` | `50%` | 按钮圆角 |
|
|
466
|
+
| `--agent-btn-shadow` | `0 0.25rem 0.875rem rgba(81,74,157,0.45)` | 按钮阴影 |
|
|
467
|
+
| `--agent-btn-shadow-hover` | `0 0.375rem 1.25rem rgba(36,198,220,0.45)` | 按钮悬停阴影 |
|
|
468
|
+
| `--agent-btn-bottom` | `1.75rem` | 按钮底边距 |
|
|
469
|
+
| `--agent-btn-right` | `1.75rem` | 按钮右边距 |
|
|
470
|
+
| `--agent-btn-left` | `unset` | 按钮左边距 |
|
|
471
|
+
| `--agent-btn-top` | `unset` | 按钮顶边距 |
|
|
472
|
+
|
|
473
|
+
#### 窗口
|
|
474
|
+
|
|
475
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
476
|
+
|---|---|---|
|
|
477
|
+
| `--agent-window-position` | `fixed` | 窗口定位方式 |
|
|
478
|
+
| `--agent-window-width` | `26.25rem` | 窗口宽度 |
|
|
479
|
+
| `--agent-window-height` | `38.75rem` | 窗口高度 |
|
|
480
|
+
| `--agent-window-bg` | `rgba(20,27,45,0.78)` | 窗口背景 |
|
|
481
|
+
| `--agent-window-border-radius` | `0.5rem` | 窗口圆角 |
|
|
482
|
+
| `--agent-window-shadow` | `0 0.75rem 2.5rem rgba(0,0,0,0.4)` | 窗口阴影 |
|
|
483
|
+
| `--agent-window-bottom` | `6rem` | 窗口底边距 |
|
|
484
|
+
| `--agent-window-right` | `1.75rem` | 窗口右边距 |
|
|
485
|
+
|
|
486
|
+
#### 头部
|
|
487
|
+
|
|
488
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
489
|
+
|---|---|---|
|
|
490
|
+
| `--agent-header-height` | `3.25rem` | 头部高度 |
|
|
491
|
+
| `--agent-header-bg` | `linear-gradient(135deg,#514a9d,#24c6dc)` | 头部背景 |
|
|
492
|
+
| `--agent-header-text-color` | `#fff` | 头部文字颜色 |
|
|
493
|
+
| `--agent-header-font-size` | `0.9375rem` | 头部字号 |
|
|
494
|
+
|
|
495
|
+
#### 消息
|
|
496
|
+
|
|
497
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
498
|
+
|---|---|---|
|
|
499
|
+
| `--agent-msg-user-bg` | `#514a9d` | 用户消息背景 |
|
|
500
|
+
| `--agent-msg-user-text` | `#fff` | 用户消息文字颜色 |
|
|
501
|
+
| `--agent-msg-assistant-bg` | `#1a2340` | AI 消息背景 |
|
|
502
|
+
| `--agent-msg-assistant-text` | `#e2e8f0` | AI 消息文字颜色 |
|
|
503
|
+
| `--agent-msg-font-size` | `0.875rem` | 消息字号 |
|
|
504
|
+
| `--agent-msg-max-width` | `80%` | 消息最大宽度 |
|
|
505
|
+
|
|
506
|
+
#### 输入框
|
|
507
|
+
|
|
508
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
509
|
+
|---|---|---|
|
|
510
|
+
| `--agent-input-bg` | `#6b819c52` | 输入框背景 |
|
|
511
|
+
| `--agent-input-border-color` | `#253354` | 输入框边框色 |
|
|
512
|
+
| `--agent-input-focus-border-color` | `#24c6dc` | 输入框聚焦边框色 |
|
|
513
|
+
| `--agent-input-text-color` | `#e2e8f0` | 输入框文字颜色 |
|
|
514
|
+
| `--agent-input-placeholder-color` | `#5a6b8a` | 占位符颜色 |
|
|
515
|
+
| `--agent-input-min-height` | `2.75rem` | 输入框最小高度 |
|
|
516
|
+
|
|
517
|
+
#### 发送按钮
|
|
518
|
+
|
|
519
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
520
|
+
|---|---|---|
|
|
521
|
+
| `--agent-send-bg` | `#24c6dc` | 发送按钮背景 |
|
|
522
|
+
| `--agent-send-bg-hover` | `#1fb1c7` | 发送按钮悬停背景 |
|
|
523
|
+
| `--agent-send-bg-disabled` | `#1a3a4a` | 发送按钮禁用背景 |
|
|
524
|
+
| `--agent-send-size` | `2rem` | 发送按钮尺寸 |
|
|
525
|
+
|
|
526
|
+
#### 辅助色
|
|
527
|
+
|
|
528
|
+
| 变量 | 默认值(深色) | 说明 |
|
|
529
|
+
|---|---|---|
|
|
530
|
+
| `--agent-loading-dot-color` | `#24c6dc` | 加载动画/状态提示颜色 |
|
|
531
|
+
| `--agent-empty-color` | `#5a6b8a` | 空状态文字颜色 |
|
|
532
|
+
| `--agent-error-color` | `#f87171` | 错误文字颜色 |
|
|
533
|
+
| `--agent-error-bg` | `rgba(248,113,113,0.1)` | 错误背景色 |
|
|
534
|
+
| `--agent-code-block-bg` | `#0d1117` | 代码块背景 |
|
|
535
|
+
| `--agent-table-border` | `#253354` | 表格边框色 |
|
|
536
|
+
| `--agent-table-header-bg` | `#1a2340` | 表头背景 |
|
|
537
|
+
|
|
538
|
+
## API 端点约定
|
|
539
|
+
|
|
540
|
+
`apiUrl` 配置到 `http://host:port/api/v2` 级别,插件自动拼接以下路径:
|
|
541
|
+
|
|
542
|
+
| 功能 | 方法 | 完整路径 |
|
|
543
|
+
|---|---|---|
|
|
544
|
+
| 创建会话 | POST | `${apiUrl}/agent/chat/session` |
|
|
545
|
+
| 流式对话 | POST | `${apiUrl}/agent/chat/chat/stream` |
|
|
546
|
+
| 获取历史 | GET | `${apiUrl}/agent/chat/sessions?userId=xxx` |
|
|
547
|
+
|
|
548
|
+
### SSE 事件类型
|
|
549
|
+
|
|
550
|
+
流式对话接口返回的 SSE 事件格式:
|
|
551
|
+
|
|
552
|
+
```json
|
|
553
|
+
{ "type": "status", "content": "正在查询数据..." }
|
|
554
|
+
{ "type": "sql", "content": "SELECT * FROM ..." }
|
|
555
|
+
{ "type": "data", "content": [{"col1": "val1", "col2": 100}] }
|
|
556
|
+
{ "type": "chart_config", "content": { /* ECharts 配置对象 */ }
|
|
557
|
+
{ "type": "sources", "content": [{ "id": "db", "title": "数据库" }] }
|
|
558
|
+
{ "type": "analysis_chunk", "content": "正在分析..." }
|
|
559
|
+
{ "type": "done", "report_id": 123, "title": "分析报告" }
|
|
560
|
+
{ "type": "error", "message": "分析失败" }
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
## 编程式 API
|
|
564
|
+
|
|
565
|
+
除组件方式外,插件也导出了底层 API 和 Store,供高级场景使用:
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
import {
|
|
569
|
+
// 布局组件
|
|
570
|
+
AgentChat,
|
|
571
|
+
AgentChatPopup,
|
|
572
|
+
AgentChatFull,
|
|
573
|
+
AgentChatMobile,
|
|
574
|
+
|
|
575
|
+
// 子组件
|
|
576
|
+
AgentWindow,
|
|
577
|
+
AgentHistoryList,
|
|
578
|
+
|
|
579
|
+
// API 方法
|
|
580
|
+
createChatSession,
|
|
581
|
+
getChatSessions,
|
|
582
|
+
streamChat,
|
|
583
|
+
setAgentOptions,
|
|
584
|
+
getAgentOptions,
|
|
585
|
+
|
|
586
|
+
// Store 工具
|
|
587
|
+
chatStore,
|
|
588
|
+
getOrCreateChatInstance,
|
|
589
|
+
getChatInstance,
|
|
590
|
+
destroyChatInstance,
|
|
591
|
+
|
|
592
|
+
// 类型
|
|
593
|
+
type AgentPluginOptions,
|
|
594
|
+
type AgentLayoutMode,
|
|
595
|
+
type AgentFullLayoutProps,
|
|
596
|
+
type AgentMobileLayoutProps,
|
|
597
|
+
type ChatMessage,
|
|
598
|
+
type SessionInfo,
|
|
599
|
+
type SourceInfo,
|
|
600
|
+
type StreamCallbacks,
|
|
601
|
+
type StreamEvent,
|
|
602
|
+
type StreamEventType,
|
|
603
|
+
type StreamRequestData,
|
|
604
|
+
type ChatStoreInstance,
|
|
605
|
+
} from '@legendzd/ai-agent-vue'
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 手动发起流式请求
|
|
609
|
+
|
|
610
|
+
```ts
|
|
611
|
+
import { streamChat, setAgentOptions } from '@legendzd/ai-agent-vue'
|
|
612
|
+
|
|
613
|
+
setAgentOptions({ apiUrl: 'http://your-server/api/v2' })
|
|
614
|
+
|
|
615
|
+
const controller = streamChat(
|
|
616
|
+
{ sessionId: 'xxx', query: '你好', userId: 'user123' },
|
|
617
|
+
{
|
|
618
|
+
onStatus: (text) => console.log('状态:', text),
|
|
619
|
+
onAnalysisChunk: (chunk) => process.stdout.write(chunk),
|
|
620
|
+
onChartConfig: (config) => renderChart(config),
|
|
621
|
+
onDone: (reportId, title) => console.log('完成:', title),
|
|
622
|
+
onError: (msg) => console.error('错误:', msg),
|
|
623
|
+
onComplete: () => console.log('流结束'),
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
// 取消请求
|
|
628
|
+
controller.abort()
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### 直接访问 Store
|
|
632
|
+
|
|
633
|
+
```ts
|
|
634
|
+
import { chatStore, getOrCreateChatInstance } from '@legendzd/ai-agent-vue'
|
|
635
|
+
|
|
636
|
+
// 默认实例
|
|
637
|
+
console.log(chatStore.sessionId)
|
|
638
|
+
console.log(chatStore.messages)
|
|
639
|
+
|
|
640
|
+
// 指定实例
|
|
641
|
+
const instanceA = getOrCreateChatInstance('user-a', {
|
|
642
|
+
apiUrl: 'http://your-server/api/v2',
|
|
643
|
+
userId: 'user-a',
|
|
644
|
+
})
|
|
645
|
+
console.log(instanceA.sessionId)
|
|
646
|
+
|
|
647
|
+
// 操作
|
|
648
|
+
await chatStore.initSession()
|
|
649
|
+
await chatStore.loadSessions()
|
|
650
|
+
await chatStore.newChat()
|
|
651
|
+
chatStore.switchSession('some-session-id')
|
|
652
|
+
chatStore.clearMessages()
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
## 开发
|
|
656
|
+
|
|
657
|
+
```bash
|
|
658
|
+
# 安装依赖
|
|
659
|
+
npm install
|
|
660
|
+
|
|
661
|
+
# 启动开发服务器(含三种布局切换 Demo)
|
|
662
|
+
npm run dev
|
|
663
|
+
|
|
664
|
+
# 构建生产版本(应用模式)
|
|
665
|
+
npm run build
|
|
666
|
+
|
|
667
|
+
# 构建库版本(npm 包)
|
|
668
|
+
npm run build:lib
|
|
669
|
+
|
|
670
|
+
# 预览生产构建
|
|
671
|
+
npm run preview
|
|
672
|
+
|
|
673
|
+
# 代码格式化
|
|
674
|
+
npm run format
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
## License
|
|
678
|
+
|
|
679
|
+
MIT
|