- sidebar H5: React18+TypeScript+Vite+AntDesignMobile, 学员画像/话术推荐/一键发送 - admin后台: React18+AntDesign, 登录/数据看板/话术库管理CRUD - kb-admin-service: 话术CRUD API、分页查询 - analytics-service: 数据统计Dashboard API - 所有服务的Dockerfile + nginx.conf + 完整docker-compose编排
95 lines
3.4 KiB
TypeScript
95 lines
3.4 KiB
TypeScript
import { useEffect, useState } from 'react'
|
||
import { Button, Toast, SpinLoading } from 'antd-mobile'
|
||
import type { Recommendation } from '../types'
|
||
|
||
export default function ScriptRecommend() {
|
||
const [scripts, setScripts] = useState<Recommendation[]>([])
|
||
const [loading, setLoading] = useState(false)
|
||
|
||
useEffect(() => {
|
||
loadRecommendations()
|
||
}, [])
|
||
|
||
const loadRecommendations = async () => {
|
||
setLoading(true)
|
||
try {
|
||
// TODO: 调用真实API
|
||
// const res = await fetch('/api/v1/recommend/get?sessionId=xxx&...')
|
||
// const data = await res.json()
|
||
|
||
// 模拟数据
|
||
setScripts([
|
||
{
|
||
utteranceId: 'UTT-S03-001',
|
||
title: '推荐3D场景UE地编就业班(零基础)',
|
||
content: '根据您的情况,我强烈推荐我们的【3D场景UE地编就业班】!\n\n为什么适合您:\n✅ 零基础入学:从软件操作开始教,无需任何基础\n✅ 六大模块系统学习\n✅ 5个月培训+2个月企业实训\n\n就业数据:往期学员平均薪资12-18K,就业推荐率95%+',
|
||
successRate: 0.72,
|
||
source: '规则匹配'
|
||
},
|
||
{
|
||
utteranceId: 'UTT-S04-003',
|
||
title: '强调实战教学模式',
|
||
content: '我们的教学模式是业内独一无二的"5+2"模式:\n\n📚 5个月技能培训 + 2个月企业实训\n\n这意味着什么?\n✅ 毕业时您已经有真实项目经验\n✅ 实训期间进入合作企业,表现优秀可直接留用\n✅ 500+合作企业就业推荐网络',
|
||
successRate: 0.74,
|
||
source: '热门推荐'
|
||
}
|
||
])
|
||
} catch (e) {
|
||
Toast.show({ content: '加载失败', icon: 'fail' })
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handleSend = (script: Recommendation) => {
|
||
// 调用企微JS-SDK发送消息
|
||
if (typeof (window as any).wx !== 'undefined') {
|
||
(window as any).wx.invoke('sendChatMessage', {
|
||
msgtype: 'text',
|
||
text: { content: script.content }
|
||
}, (res: any) => {
|
||
if (res.err_msg === 'sendChatMessage:ok') {
|
||
Toast.show({ content: '发送成功', icon: 'success' })
|
||
} else {
|
||
Toast.show({ content: '发送失败: ' + res.err_msg, icon: 'fail' })
|
||
}
|
||
})
|
||
} else {
|
||
// 浏览器调试环境,复制到剪贴板
|
||
navigator.clipboard.writeText(script.content)
|
||
Toast.show({ content: '已复制到剪贴板', icon: 'success' })
|
||
}
|
||
}
|
||
|
||
if (loading) {
|
||
return (
|
||
<div style={{ padding: 40, textAlign: 'center' }}>
|
||
<SpinLoading />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div>
|
||
{scripts.map(script => (
|
||
<div key={script.utteranceId} className="script-card">
|
||
<div className="script-title">{script.title}</div>
|
||
<div className="script-content">{script.content}</div>
|
||
<div className="script-meta">
|
||
<span>成功率: {(script.successRate * 100).toFixed(0)}%</span>
|
||
<span>来源: {script.source}</span>
|
||
</div>
|
||
<div className="script-actions">
|
||
<Button color="primary" size="small" onClick={() => handleSend(script)}>
|
||
一键发送
|
||
</Button>
|
||
<Button size="small" fill="outline" onClick={() => navigator.clipboard.writeText(script.content)}>
|
||
复制
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)
|
||
}
|