AI Component 组件文档



概述
ai-component
是一个智能聊天组件,专为泉城路商圈大屏系统设计。该组件提供了与 AI 助手的交互功能,支持实时对话、流式响应、快捷问题等功能。
主要功能
1. 智能对话
- 支持与 AI 助手进行实时对话
- 流式响应显示,提供更好的用户体验
- 支持 Markdown 格式的消息渲染
2. 快捷问题
- 提供预设的快捷问题按钮
- 支持一键发送常用问题
- 动态加载快捷问题列表
3. 界面交互
- 支持展开/收起功能
- 可拖拽移动位置
- 响应式设计,适配不同屏幕尺寸
4. 消息类型支持
- 文本消息(支持 Markdown)
- 图片消息
- HTML 富文本消息
组件结构
Template 结构
vue
<template>
<div class="ai-chat-widget" :class="{ 'collapsed': isCollapsed }">
<!-- 聊天头部 -->
<div class="chat-header">
<span>我是小智,泉城路商圈的专属AI助手!</span>
<div class="header-actions">
<button class="collapse-btn" @click="toggleCollapse">
{{ isCollapsed ? '展开' : '收起' }}
</button>
</div>
</div>
<!-- 聊天内容区域 -->
<div class="chat-content" :class="{ 'hidden': isCollapsed }">
<!-- 消息列表 -->
<div class="chat-body" ref="chatBody">
<!-- 消息项 -->
</div>
<!-- 快捷问题 -->
<div class="quick-actions">
<!-- 快捷问题按钮 -->
</div>
<!-- 输入区域 -->
<div class="chat-input">
<!-- 输入框和发送按钮 -->
</div>
</div>
</div>
</template>
数据属性
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
input |
String | "" |
用户输入的消息内容 |
isCollapsed |
Boolean | false |
是否收起状态 |
messages |
Array | [{ role: "ai", type: "text", text: "大家好,我是小智..." }] |
消息列表 |
chatId |
String | '' |
会话ID |
quickQuestions |
Array | [] |
快捷问题列表 |
aiLoading |
Boolean | false |
AI 是否正在加载中 |
消息对象结构
javascript
{
role: "ai" | "user", // 消息角色
type: "text" | "image" | "html", // 消息类型
text: String, // 文本内容
url: String, // 图片URL(当type为image时)
html: String, // HTML内容(当type为html时)
completed: Boolean // 是否完成(用于流式响应)
}
核心方法
1. 消息发送
send()
发送用户输入的消息
javascript
send() {
if (!this.input.trim() || this.aiLoading) return;
this.aiLoading = true;
this.addMessage("user", "text", this.input);
this.getAIReply(this.input);
this.input = "";
}
sendQuick(q)
发送快捷问题
javascript
sendQuick(q) {
if (this.aiLoading) return;
this.aiLoading = true;
this.addMessage("user", "text", q);
this.getAIReply(q);
}
2. 消息管理
addMessage(role, type, content)
添加消息到聊天列表
javascript
addMessage(role, type, content) {
if (type === "text") {
let text = String(content);
// 过滤 <think> 标签
text = text.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
this.messages.push({ role, type, text });
} else if (type === "image") {
this.messages.push({ role, type, url: content });
} else if (type === "html") {
this.messages.push({ role, type, html: content });
}
this.$nextTick(() => {
this.$refs.chatBody.scrollTop = this.$refs.chatBody.scrollHeight;
});
}
3. AI 交互
getAIReply(question)
获取 AI 回复(流式响应)
javascript
async getAIReply(question) {
try {
// 创建空的AI消息
const aiMsg = { role: "ai", type: "text", text: "", completed: false };
this.messages.push(aiMsg);
// 发送请求
const url = `${JAVAHOST}/system/dpwd/chatMessageStream?message=${question}&chatId=${this.chatId}&token=${getToken()}`;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"token": getToken()
},
body: JSON.stringify({ token: getToken() })
});
// 处理流式响应
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
let done = false;
let chunk = "";
while ((!done) {
const { value, done:doneReading } = await reader.read();
done = doneReading;
if (value) {
chunk += decoder.decode(value, { stream: true });
const lines = chunk.split('\n');
chunk = lines.pop() || ''
for (const line of lines) {
if (line.trim() === '') continue;
if (line.startsWith('data:')) {
const jsonStr = line.slice(5).trim();
if (jsonStr.trim() === '[DONE]') continue;
if (jsonStr.trim() === '') continue;
try {
let data
try {
data = JSON.parse(jsonStr);
} catch (e) {
console.error('jsonStr---------',jsonStr)
}
if(data && data.content && data.content!='n'){
const content = data.content;
buffer += content;
aiMsg.text = buffer;
this.$forceUpdate(); // 强制刷新视图
this.$nextTick(() => {
this.$refs.chatBody.scrollTop = this.$refs.chatBody.scrollHeight;
});
}
} catch (e) {
console.error('解析JSON数据出错:', e, jsonStr);
}
}
}
aiMsg.completed = true;
this.$forceUpdate();
this.aiLoading = false;
} catch (error) {
console.error('AI回复出错:', error);
this.aiLoading = false;
}
}
4. 界面控制
toggleCollapse()
切换展开/收起状态
javascript
toggleCollapse() {
this.isCollapsed = !this.isCollapsed;
}
shouldShowDisclaimer(index)
判断是否显示免责声明
javascript
shouldShowDisclaimer(index) {
const current = this.messages[index];
if (!current || current.role !== 'ai') return false;
if (index === 0) return false; // 第一个不展示
const prev = this.messages[index - 1];
return !!prev && prev.role === 'user' && current.completed === true;
}
API 接口
1. 获取快捷问题
javascript
getQuestion({ token: getToken() })
2. 获取会话ID
javascript
getchatId({ token: getToken() })
3. 流式聊天
javascript
chatMessageStream({
message: question,
chatId: this.chatId,
token: getToken()
})
样式特性
1. 现代化设计
- 渐变背景和阴影效果
- 圆角设计和毛玻璃效果
- 响应式动画过渡
2. 消息样式
- AI 消息:蓝色渐变背景,左对齐
- 用户消息:深色背景,右对齐
- 支持 Markdown 渲染
3. 交互反馈
- 按钮悬停效果
- 加载状态指示
- 滚动条美化
技术依赖
1. Vue 相关
- Vue.js 2.x
- Vuex (状态管理)
2. Markdown 渲染
@kangc/v-md-editor
highlight.js
(代码高亮)
3. 工具库
fetch
API (HTTP 请求)TextDecoder
(流式数据处理)
使用示例
1. 在父组件中引入
vue
<template>
<div>
<ai-component />
</div>
</template>
<script>
import AiComponent from '@/components/ai/index.vue'
export default {
components: {
AiComponent
}
}
</script>
2. 拖拽功能集成
vue
<template>
<div @mousedown="onAIMouseDown" class="ai-drag-header">
<ai-component />
</div>
</template>
配置选项
1. 组件尺寸
- 默认宽度:380px
- 最大高度:600px
- 消息区域最大高度:400px
2. 样式定制
- 支持通过 CSS 变量自定义主题色
- 可调整圆角、阴影等视觉效果
- 支持响应式断点设置
注意事项
1. 性能优化
- 流式响应使用
$forceUpdate()
强制刷新 - 消息列表自动滚动到底部
- 防抖处理避免频繁请求
2. 错误处理
- 网络请求异常处理
- 流式数据解析错误处理
- 用户输入验证
3. 安全考虑
- 过滤
<think>
标签内容 - 输入内容转义处理
- 免责声明显示