chore: 添加AI聊天对话框
This commit is contained in:
271
components/ai-chat-message/README.md
Normal file
271
components/ai-chat-message/README.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# AI智能客服组件
|
||||
|
||||
一个功能完整的AI智能客服对话组件,支持多种消息类型和交互功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 支持对话上下文管理
|
||||
- ✅ 支持多种消息类型:文本、Markdown、文件、音频、视频、链接、商品卡片
|
||||
- ✅ 支持语音输入和录音
|
||||
- ✅ 支持图片、文件、位置等附件发送
|
||||
- ✅ 支持消息操作按钮(点赞、踩等)
|
||||
- ✅ 支持历史消息加载
|
||||
- ✅ 响应式设计,适配多端
|
||||
|
||||
## 安装使用
|
||||
|
||||
### 1. 引入组件
|
||||
|
||||
在 `pages.json` 中注册组件:
|
||||
|
||||
```json
|
||||
{
|
||||
"usingComponents": {
|
||||
"ai-chat-message": "/components/ai-chat-message/ai-chat-message"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 在页面中使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="container">
|
||||
<ai-chat-message
|
||||
ref="chat"
|
||||
:initial-messages="messages"
|
||||
@message-sent="onMessageSent"
|
||||
@ai-response="onAIResponse"
|
||||
@action-click="onActionClick" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
id: 1,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '您好!我是AI智能客服,有什么可以帮助您的吗?',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onMessageSent(message) {
|
||||
console.log('用户发送消息:', message)
|
||||
},
|
||||
onAIResponse(message) {
|
||||
console.log('AI回复消息:', message)
|
||||
},
|
||||
onActionClick({ action, message }) {
|
||||
console.log('操作点击:', action, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Props 配置
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| initialMessages | Array | [] | 初始消息列表 |
|
||||
| userAvatar | String | '/static/images/default-avatar.png' | 用户头像 |
|
||||
| aiAvatar | String | '/static/images/ai-avatar.png' | AI头像 |
|
||||
| showLoadMore | Boolean | true | 是否显示加载更多 |
|
||||
| maxMessages | Number | 100 | 最大消息数量 |
|
||||
|
||||
## Events 事件
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| message-sent | message | 用户发送消息 |
|
||||
| ai-response | message | AI回复消息 |
|
||||
| action-click | {action, message} | 操作按钮点击 |
|
||||
| history-loaded | messages | 历史消息加载完成 |
|
||||
| file-preview | message | 文件预览 |
|
||||
| audio-play | message | 音频播放 |
|
||||
| audio-pause | message | 音频暂停 |
|
||||
| video-play | message | 视频播放 |
|
||||
| video-pause | message | 视频暂停 |
|
||||
| link-open | message | 链接打开 |
|
||||
| product-view | message | 商品查看 |
|
||||
| input-change | value | 输入内容变化 |
|
||||
|
||||
## 消息类型格式
|
||||
|
||||
### 文本消息
|
||||
```javascript
|
||||
{
|
||||
id: 1,
|
||||
role: 'user', // 或 'ai'
|
||||
type: 'text',
|
||||
content: '消息内容',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### Markdown消息
|
||||
```javascript
|
||||
{
|
||||
id: 2,
|
||||
role: 'ai',
|
||||
type: 'markdown',
|
||||
content: '# 标题\n**粗体** *斜体* `代码`',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### 文件消息
|
||||
```javascript
|
||||
{
|
||||
id: 3,
|
||||
role: 'ai',
|
||||
type: 'file',
|
||||
fileName: '文档.pdf',
|
||||
fileSize: 1024000,
|
||||
url: '文件地址',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### 音频消息
|
||||
```javascript
|
||||
{
|
||||
id: 4,
|
||||
role: 'ai',
|
||||
type: 'audio',
|
||||
title: '语音消息',
|
||||
duration: 60, // 秒
|
||||
url: '音频地址',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### 视频消息
|
||||
```javascript
|
||||
{
|
||||
id: 5,
|
||||
role: 'ai',
|
||||
type: 'video',
|
||||
title: '产品介绍',
|
||||
duration: 120, // 秒
|
||||
url: '视频地址',
|
||||
cover: '封面图',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### 链接消息
|
||||
```javascript
|
||||
{
|
||||
id: 6,
|
||||
role: 'ai',
|
||||
type: 'link',
|
||||
title: '帮助文档',
|
||||
description: '详细的使用说明',
|
||||
url: 'https://example.com',
|
||||
image: '缩略图',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
### 商品卡片
|
||||
```javascript
|
||||
{
|
||||
id: 7,
|
||||
role: 'ai',
|
||||
type: 'product',
|
||||
title: '商品名称',
|
||||
price: 299,
|
||||
description: '商品描述',
|
||||
image: '商品图片',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
```
|
||||
|
||||
## 方法
|
||||
|
||||
通过 ref 调用组件方法:
|
||||
|
||||
```javascript
|
||||
// 添加消息
|
||||
this.$refs.chat.addMessage(message)
|
||||
|
||||
// 清空消息
|
||||
this.$refs.chat.clearMessages()
|
||||
|
||||
// 滚动到底部
|
||||
this.$refs.chat.scrollToBottom()
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
组件使用 SCSS 编写,可以通过 CSS 变量进行主题定制:
|
||||
|
||||
```css
|
||||
.ai-chat-container {
|
||||
--primary-color: #ff4544;
|
||||
--bg-color: #f8f8f8;
|
||||
--text-color: #333;
|
||||
}
|
||||
```
|
||||
|
||||
## 方法
|
||||
|
||||
通过 ref 调用组件方法:
|
||||
|
||||
```javascript
|
||||
// 添加消息
|
||||
this.$refs.chat.addMessage(message)
|
||||
|
||||
// 清空消息
|
||||
this.$refs.chat.clearMessages()
|
||||
|
||||
// 滚动到底部
|
||||
this.$refs.chat.scrollToBottom()
|
||||
|
||||
// 开始语音输入
|
||||
this.$refs.chat.startVoiceInput()
|
||||
|
||||
// 停止语音输入
|
||||
this.$refs.chat.stopVoiceInput()
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
组件使用 SCSS 编写,可以通过 CSS 变量进行主题定制:
|
||||
|
||||
```css
|
||||
.ai-chat-container {
|
||||
--primary-color: #ff4544;
|
||||
--bg-color: #f8f8f8;
|
||||
--text-color: #333;
|
||||
--border-color: #eeeeee;
|
||||
--user-bg: #e6f7ff;
|
||||
--ai-bg: #f6f6f6;
|
||||
}
|
||||
```
|
||||
|
||||
## 图标字体
|
||||
|
||||
组件使用自定义图标字体,需要在页面中引入:
|
||||
|
||||
```html
|
||||
<style>
|
||||
@import url('/components/ai-chat-message/iconfont.css');
|
||||
</style>
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 组件已适配项目中已有的 `ns-loading` 组件
|
||||
2. 需要配置对应的图标字体文件
|
||||
3. 音频播放功能在 H5 和 APP 端支持较好
|
||||
4. 文件预览功能依赖平台能力
|
||||
5. 语音输入功能需要用户授权麦克风权限
|
||||
6
components/ai-chat-message/ai-chat-message.json
Normal file
6
components/ai-chat-message/ai-chat-message.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"ns-loading": "../ns-loading/ns-loading"
|
||||
}
|
||||
}
|
||||
1424
components/ai-chat-message/ai-chat-message.vue
Normal file
1424
components/ai-chat-message/ai-chat-message.vue
Normal file
File diff suppressed because it is too large
Load Diff
288
components/ai-chat-message/demo.vue
Normal file
288
components/ai-chat-message/demo.vue
Normal file
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<view class="demo-container">
|
||||
<view class="demo-header">
|
||||
<text class="demo-title">AI智能客服组件演示</text>
|
||||
</view>
|
||||
|
||||
<ai-chat-message
|
||||
ref="chat"
|
||||
:initial-messages="demoMessages"
|
||||
user-avatar="/static/images/demo-user.png"
|
||||
ai-avatar="/static/images/demo-ai.png"
|
||||
@message-sent="onMessageSent"
|
||||
@ai-response="onAIResponse"
|
||||
@action-click="onActionClick"
|
||||
@file-preview="onFilePreview"
|
||||
@audio-play="onAudioPlay"
|
||||
@video-play="onVideoPlay"
|
||||
@link-open="onLinkOpen"
|
||||
@product-view="onProductView" />
|
||||
|
||||
<view class="demo-controls">
|
||||
<button class="control-btn" @click="addTextMessage">添加文本消息</button>
|
||||
<button class="control-btn" @click="addMarkdownMessage">添加Markdown</button>
|
||||
<button class="control-btn" @click="addFileMessage">添加文件</button>
|
||||
<button class="control-btn" @click="addAudioMessage">添加音频</button>
|
||||
<button class="control-btn" @click="addVideoMessage">添加视频</button>
|
||||
<button class="control-btn" @click="addLinkMessage">添加链接</button>
|
||||
<button class="control-btn" @click="addProductMessage">添加商品</button>
|
||||
<button class="control-btn" @click="clearMessages">清空消息</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
demoMessages: [
|
||||
{
|
||||
id: 1,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '您好!我是AI智能客服演示程序,我可以展示多种消息类型。请点击下方的按钮体验不同功能!',
|
||||
timestamp: Date.now() - 300000,
|
||||
actions: [
|
||||
{ id: 1, text: '开始体验', type: 'like' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 添加文本消息
|
||||
addTextMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '这是一个文本消息示例,支持**粗体**、*斜体*和`代码`格式。也可以包含换行符\n这是第二行内容。',
|
||||
timestamp: Date.now(),
|
||||
actions: [
|
||||
{ id: 1, text: '有帮助', type: 'like' },
|
||||
{ id: 2, text: '没帮助', type: 'dislike' }
|
||||
]
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加Markdown消息
|
||||
addMarkdownMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'markdown',
|
||||
content: `# Markdown文档示例
|
||||
|
||||
## 二级标题
|
||||
|
||||
这是一个支持**粗体**、*斜体*和\`代码\`的Markdown消息。
|
||||
|
||||
### 功能特性
|
||||
- ✅ 支持标题层级
|
||||
- ✅ 支持列表展示
|
||||
- ✅ 支持代码高亮
|
||||
- ✅ 支持链接跳转
|
||||
|
||||
[查看详细文档](https://example.com)\n\n**注意:** 这是一个演示内容,实际使用时可以集成真实的文档系统。`,
|
||||
timestamp: Date.now(),
|
||||
actions: [
|
||||
{ id: 1, text: '查看文档', type: 'like' }
|
||||
]
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加文件消息
|
||||
addFileMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'file',
|
||||
fileName: '产品介绍文档.pdf',
|
||||
fileSize: 2048000,
|
||||
url: 'https://example.com/document.pdf',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加音频消息
|
||||
addAudioMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'audio',
|
||||
title: '产品功能介绍',
|
||||
duration: 89,
|
||||
url: 'https://example.com/audio.mp3',
|
||||
timestamp: Date.now(),
|
||||
playing: false,
|
||||
currentTime: 0
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加视频消息
|
||||
addVideoMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'video',
|
||||
title: '产品演示视频',
|
||||
duration: 180,
|
||||
url: 'https://example.com/video.mp4',
|
||||
cover: '/static/images/video-cover.jpg',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加链接消息
|
||||
addLinkMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'link',
|
||||
title: '帮助中心',
|
||||
description: '详细的产品使用说明和常见问题解答',
|
||||
url: 'https://example.com/help',
|
||||
image: '/static/images/link-thumbnail.jpg',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 添加商品消息
|
||||
addProductMessage() {
|
||||
const message = {
|
||||
id: Date.now(),
|
||||
role: 'ai',
|
||||
type: 'product',
|
||||
title: '智能手表 X1',
|
||||
price: 1299,
|
||||
description: '全新一代智能手表,支持心率监测、运动追踪、消息提醒等功能',
|
||||
image: '/static/images/product-demo.jpg',
|
||||
timestamp: Date.now(),
|
||||
actions: [
|
||||
{ id: 1, text: '立即购买', type: 'like' },
|
||||
{ id: 2, text: '查看详情', type: 'dislike' }
|
||||
]
|
||||
}
|
||||
this.$refs.chat.messages.push(message)
|
||||
},
|
||||
|
||||
// 清空消息
|
||||
clearMessages() {
|
||||
this.$refs.chat.messages = [
|
||||
{
|
||||
id: 1,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '消息已清空,可以重新开始体验!',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 事件处理
|
||||
onMessageSent(message) {
|
||||
console.log('用户发送消息:', message)
|
||||
uni.showToast({
|
||||
title: '消息发送成功',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
|
||||
onAIResponse(message) {
|
||||
console.log('AI回复消息:', message)
|
||||
},
|
||||
|
||||
onActionClick({ action, message }) {
|
||||
console.log('操作点击:', action, message)
|
||||
uni.showToast({
|
||||
title: `点击了: ${action.text}`,
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
onFilePreview(message) {
|
||||
console.log('文件预览:', message)
|
||||
uni.showToast({
|
||||
title: '正在打开文件...',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
onAudioPlay(message) {
|
||||
console.log('音频播放:', message)
|
||||
},
|
||||
|
||||
onVideoPlay(message) {
|
||||
console.log('视频播放:', message)
|
||||
},
|
||||
|
||||
onLinkOpen(message) {
|
||||
console.log('链接打开:', message)
|
||||
uni.showToast({
|
||||
title: '正在打开链接...',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
onProductView(message) {
|
||||
console.log('商品查看:', message)
|
||||
uni.showToast({
|
||||
title: '正在查看商品...',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.demo-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
background-color: #ff4544;
|
||||
color: white;
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
|
||||
.demo-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-controls {
|
||||
background-color: white;
|
||||
padding: 20rpx;
|
||||
border-top: 2rpx solid #eeeeee;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
|
||||
.control-btn {
|
||||
flex: 1;
|
||||
min-width: 150rpx;
|
||||
height: 60rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
border: none;
|
||||
|
||||
&:active {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user