704 lines
19 KiB
Vue
704 lines
19 KiB
Vue
<template>
|
||
<view class="kefu-demo">
|
||
<view class="header">
|
||
<text class="title">智能客服接口演示</text>
|
||
</view>
|
||
|
||
<view class="content">
|
||
<!-- 聊天接口测试 -->
|
||
<view class="section">
|
||
<view class="section-title">1. 智能客服聊天接口</view>
|
||
<view class="input-group">
|
||
<input
|
||
v-model="chatMessage"
|
||
placeholder="输入消息内容"
|
||
class="input"
|
||
/>
|
||
<button @click="testChat" class="btn primary">发送消息</button>
|
||
</view>
|
||
<view class="result" v-if="chatResult">
|
||
<text class="result-title">回复结果:</text>
|
||
<text class="result-content">{{ chatResult }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 创建会话接口测试 -->
|
||
<view class="section">
|
||
<view class="section-title">2. 创建新会话接口</view>
|
||
<button @click="testCreateConversation" class="btn primary">创建新会话</button>
|
||
<view class="result" v-if="conversationInfo">
|
||
<text class="result-title">会话信息:</text>
|
||
<text class="result-content">会话ID: {{ conversationInfo.conversationId }}</text>
|
||
<text class="result-content">创建时间: {{ conversationInfo.createdAt }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 获取历史记录接口测试 -->
|
||
<view class="section">
|
||
<view class="section-title">3. 获取会话历史接口</view>
|
||
<input
|
||
v-model="conversationId"
|
||
placeholder="输入会话ID"
|
||
class="input"
|
||
/>
|
||
<button @click="testGetHistory" class="btn primary">获取历史记录</button>
|
||
<view class="result" v-if="historyData">
|
||
<text class="result-title">历史记录 ({{ historyData.total }}条):</text>
|
||
<view class="message-list">
|
||
<view
|
||
v-for="msg in historyData.messages"
|
||
:key="msg.id"
|
||
class="message-item"
|
||
>
|
||
<text class="message-role">{{ msg.role }}:</text>
|
||
<text class="message-content">{{ msg.content }}</text>
|
||
<text class="message-time">{{ msg.created_at }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 健康检查测试 -->
|
||
<view class="section">
|
||
<view class="section-title">4. 系统健康检查</view>
|
||
<view class="input-group">
|
||
<input
|
||
v-model="checkType"
|
||
placeholder="检查类型:full/basic/ai_service"
|
||
class="input"
|
||
/>
|
||
<button @click="testHealthCheck" class="btn primary">健康检查</button>
|
||
</view>
|
||
<view class="result" v-if="healthResult">
|
||
<text class="result-title">健康检查结果:</text>
|
||
<text class="result-content">状态: {{ healthResult.status }}</text>
|
||
<text class="result-content">检查ID: {{ healthResult.checkId }}</text>
|
||
<text class="result-content">时间: {{ healthResult.timestamp }}</text>
|
||
<text class="result-content">通过检查: {{ healthResult.passed_checks }}/{{ healthResult.total_checks }}</text>
|
||
<view class="components-status" v-if="healthResult.components">
|
||
<text class="result-title">组件状态:</text>
|
||
<view v-for="(component, key) in healthResult.components" :key="key" class="component-item">
|
||
<text class="component-name">{{ key }}: {{ component.status }}</text>
|
||
<text class="component-message">{{ component.message }}</text>
|
||
<text class="component-time">响应时间: {{ component.response_time_ms }}ms</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务配置信息测试 -->
|
||
<view class="section">
|
||
<view class="section-title">5. 获取服务配置信息</view>
|
||
<button @click="testGetServiceInfo" class="btn primary">获取配置信息</button>
|
||
<view class="result" v-if="serviceInfoResult">
|
||
<text class="result-title">服务配置:</text>
|
||
<text class="result-content">服务名称: {{ serviceInfoResult.serviceInfo?.name }}</text>
|
||
<text class="result-content">服务版本: {{ serviceInfoResult.serviceInfo?.version }}</text>
|
||
<text class="result-content">启用状态: {{ serviceInfoResult.serviceInfo?.enabled ? '已启用' : '未启用' }}</text>
|
||
<view class="features-list" v-if="serviceInfoResult.features">
|
||
<text class="result-title">可用功能:</text>
|
||
<view v-for="(enabled, feature) in serviceInfoResult.features" :key="feature" class="feature-item">
|
||
<text class="feature-name">{{ feature }}: {{ enabled ? '✓' : '✗' }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="endpoints-list" v-if="serviceInfoResult.endpoints">
|
||
<text class="result-title">API端点:</text>
|
||
<view v-for="(endpoint, name) in serviceInfoResult.endpoints" :key="name" class="endpoint-item">
|
||
<text class="endpoint-name">{{ name }}: {{ endpoint }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 清除会话测试 -->
|
||
<view class="section">
|
||
<view class="section-title">6. 清除会话历史</view>
|
||
<view class="input-group">
|
||
<input
|
||
v-model="clearConversationId"
|
||
placeholder="会话ID(可选)"
|
||
class="input"
|
||
/>
|
||
<button @click="testClearConversation" class="btn primary">清除会话</button>
|
||
</view>
|
||
<view class="result" v-if="clearResult">
|
||
<text class="result-title">清除结果:</text>
|
||
<text class="result-content">删除消息数: {{ clearResult.deletedMessages }}</text>
|
||
<text class="result-content">删除会话数: {{ clearResult.deletedConversations }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 流式聊天测试 -->
|
||
<view class="section">
|
||
<view class="section-title">7. 流式聊天测试</view>
|
||
<view class="input-group">
|
||
<input
|
||
v-model="streamMessage"
|
||
placeholder="输入消息内容"
|
||
class="input"
|
||
/>
|
||
<button @click="testStreamChat" class="btn primary">开始流式聊天</button>
|
||
</view>
|
||
<view class="result" v-if="streamResult">
|
||
<text class="result-title">流式回复:</text>
|
||
<text class="stream-content">{{ streamResult }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 完整服务检查测试 -->
|
||
<view class="section">
|
||
<view class="section-title">8. 完整服务检查</view>
|
||
<button @click="testFullServiceCheck" class="btn primary">完整服务检查</button>
|
||
</view>
|
||
|
||
<!-- 服务状态测试(兼容) -->
|
||
<view class="section">
|
||
<view class="section-title">9. 服务状态检查(兼容)</view>
|
||
<button @click="testServiceStatus" class="btn primary">服务状态检查</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import kefuService from '@/common/js/kefu-service.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
chatMessage: '',
|
||
chatResult: '',
|
||
conversationId: '',
|
||
conversationInfo: null,
|
||
historyData: null,
|
||
streamMessage: '',
|
||
streamResult: '',
|
||
currentConversationId: '',
|
||
// 新增数据
|
||
checkType: 'full',
|
||
healthResult: null,
|
||
serviceInfoResult: null,
|
||
clearConversationId: '',
|
||
clearResult: null
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 测试聊天接口
|
||
async testChat() {
|
||
if (!this.chatMessage.trim()) {
|
||
uni.showToast({
|
||
title: '请输入消息内容',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '发送中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.chatWithAI(
|
||
this.chatMessage,
|
||
this.currentConversationId,
|
||
false
|
||
)
|
||
|
||
if (response.success) {
|
||
this.chatResult = response.reply
|
||
this.currentConversationId = response.conversationId
|
||
uni.showToast({
|
||
title: '发送成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '发送失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('聊天测试失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试创建会话接口
|
||
async testCreateConversation() {
|
||
uni.showLoading({
|
||
title: '创建中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.createNewConversation()
|
||
|
||
if (response.success) {
|
||
this.conversationInfo = response
|
||
this.currentConversationId = response.conversationId
|
||
uni.showToast({
|
||
title: '创建成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '创建失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('创建会话失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试获取历史记录接口
|
||
async testGetHistory() {
|
||
if (!this.conversationId.trim() && !this.currentConversationId) {
|
||
uni.showToast({
|
||
title: '请先创建会话或输入会话ID',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.getChatHistory(
|
||
this.conversationId || this.currentConversationId,
|
||
20,
|
||
0
|
||
)
|
||
|
||
if (response.success) {
|
||
this.historyData = response
|
||
uni.showToast({
|
||
title: '加载成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '加载失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('获取历史记录失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试健康检查
|
||
async testHealthCheck() {
|
||
uni.showLoading({
|
||
title: '检查中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.healthCheck(this.checkType)
|
||
|
||
if (response.success) {
|
||
this.healthResult = response
|
||
uni.showToast({
|
||
title: '检查完成',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '检查失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('健康检查失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试获取服务配置信息
|
||
async testGetServiceInfo() {
|
||
uni.showLoading({
|
||
title: '获取中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.getServiceInfo()
|
||
|
||
if (response.success) {
|
||
this.serviceInfoResult = response
|
||
uni.showToast({
|
||
title: '获取成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '获取失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('获取服务配置失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试清除会话
|
||
async testClearConversation() {
|
||
if (!this.clearConversationId.trim() && !this.currentConversationId) {
|
||
uni.showToast({
|
||
title: '请输入会话ID或先创建会话',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '清除中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.clearConversation(
|
||
this.clearConversationId || this.currentConversationId
|
||
)
|
||
|
||
if (response.success) {
|
||
this.clearResult = response
|
||
uni.showToast({
|
||
title: '清除成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: response.message || '清除失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('清除会话失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试流式聊天
|
||
async testStreamChat() {
|
||
if (!this.streamMessage.trim()) {
|
||
uni.showToast({
|
||
title: '请输入消息内容',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
this.streamResult = ''
|
||
|
||
try {
|
||
await kefuService.chatWithStream(
|
||
this.streamMessage,
|
||
this.currentConversationId,
|
||
// 开始回调
|
||
(startData) => {
|
||
console.log('流式聊天开始:', startData)
|
||
},
|
||
// 消息回调
|
||
(messageData) => {
|
||
this.streamResult += messageData.content || ''
|
||
},
|
||
// 完成回调
|
||
(completeData) => {
|
||
uni.showToast({
|
||
title: '流式聊天完成',
|
||
icon: 'success'
|
||
})
|
||
},
|
||
// 错误回调
|
||
(errorData) => {
|
||
console.error('流式聊天错误:', errorData)
|
||
uni.showToast({
|
||
title: '聊天失败',
|
||
icon: 'none'
|
||
})
|
||
},
|
||
// 结束回调
|
||
(endData) => {
|
||
console.log('流式聊天结束:', endData)
|
||
}
|
||
)
|
||
} catch (error) {
|
||
console.error('流式聊天失败:', error)
|
||
uni.showToast({
|
||
title: '请求失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 测试完整服务检查
|
||
async testFullServiceCheck() {
|
||
uni.showLoading({
|
||
title: '检查中...'
|
||
})
|
||
|
||
try {
|
||
const response = await kefuService.fullServiceCheck('full')
|
||
|
||
if (response.available) {
|
||
uni.showModal({
|
||
title: '服务状态',
|
||
content: '服务正常,所有组件运行良好',
|
||
showCancel: false
|
||
})
|
||
} else {
|
||
uni.showModal({
|
||
title: '服务状态',
|
||
content: response.reason || '服务异常',
|
||
showCancel: false
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('完整服务检查失败:', error)
|
||
uni.showToast({
|
||
title: '检查失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 测试服务状态(兼容旧版本)
|
||
async testServiceStatus() {
|
||
try {
|
||
const status = await kefuService.checkServiceStatus()
|
||
uni.showModal({
|
||
title: '服务状态',
|
||
content: status.available ? '服务正常' : `服务异常: ${status.reason}`,
|
||
showCancel: false
|
||
})
|
||
} catch (error) {
|
||
console.error('检查服务状态失败:', error)
|
||
uni.showToast({
|
||
title: '检查失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.kefu-demo {
|
||
padding: 20rpx;
|
||
background-color: #f5f5f5;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.header {
|
||
text-align: center;
|
||
margin-bottom: 30rpx;
|
||
|
||
.title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.content {
|
||
.section {
|
||
background-color: white;
|
||
border-radius: 10rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.input-group {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
|
||
.input {
|
||
flex: 1;
|
||
border: 1rpx solid #ddd;
|
||
border-radius: 8rpx;
|
||
padding: 20rpx;
|
||
margin-right: 20rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
|
||
.btn {
|
||
padding: 20rpx 40rpx;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
|
||
&.primary {
|
||
background-color: #007aff;
|
||
color: white;
|
||
}
|
||
}
|
||
|
||
.result {
|
||
margin-top: 20rpx;
|
||
padding: 20rpx;
|
||
background-color: #f8f8f8;
|
||
border-radius: 8rpx;
|
||
|
||
.result-title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
display: block;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.result-content {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
display: block;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.stream-content {
|
||
font-size: 26rpx;
|
||
color: #007aff;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.components-status {
|
||
margin-top: 10rpx;
|
||
|
||
.component-item {
|
||
margin-bottom: 10rpx;
|
||
padding: 10rpx;
|
||
background-color: white;
|
||
border-radius: 4rpx;
|
||
border-left: 3rpx solid #007aff;
|
||
|
||
.component-name {
|
||
font-size: 24rpx;
|
||
color: #007aff;
|
||
font-weight: bold;
|
||
display: block;
|
||
margin-bottom: 3rpx;
|
||
}
|
||
|
||
.component-message {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
display: block;
|
||
margin-bottom: 3rpx;
|
||
}
|
||
|
||
.component-time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
display: block;
|
||
}
|
||
}
|
||
}
|
||
|
||
.features-list {
|
||
margin-top: 10rpx;
|
||
|
||
.feature-item {
|
||
margin-bottom: 5rpx;
|
||
|
||
.feature-name {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
display: block;
|
||
}
|
||
}
|
||
}
|
||
|
||
.endpoints-list {
|
||
margin-top: 10rpx;
|
||
|
||
.endpoint-item {
|
||
margin-bottom: 5rpx;
|
||
|
||
.endpoint-name {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
display: block;
|
||
word-break: break-all;
|
||
}
|
||
}
|
||
}
|
||
|
||
.message-list {
|
||
.message-item {
|
||
margin-bottom: 15rpx;
|
||
padding: 15rpx;
|
||
background-color: white;
|
||
border-radius: 6rpx;
|
||
border-left: 4rpx solid #007aff;
|
||
|
||
.message-role {
|
||
font-size: 24rpx;
|
||
color: #007aff;
|
||
font-weight: bold;
|
||
display: block;
|
||
margin-bottom: 5rpx;
|
||
}
|
||
|
||
.message-content {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
display: block;
|
||
margin-bottom: 5rpx;
|
||
}
|
||
|
||
.message-time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
display: block;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |