diff --git a/web/src/pages/agent/ChatHistory.tsx b/web/src/pages/agent/ChatHistory.tsx index 4e8e249..80c3c3f 100644 --- a/web/src/pages/agent/ChatHistory.tsx +++ b/web/src/pages/agent/ChatHistory.tsx @@ -1,6 +1,182 @@ -const ChatHistory = () => ( -
-
对话记录
开发中...
-
-) +import { useState } from 'react' +import { Input, Select, DatePicker, Tag, Empty } from 'antd' +import { SearchOutlined, UserOutlined } from '@ant-design/icons' +import type { Dayjs } from 'dayjs' + +interface ChatRecord { + id: string + visitorName: string + avatar?: string + lastMessage: string + time: string + status: 'active' | 'ended' | 'archived' + channel: string + agent: string + satisfaction?: number + messages: { sender: string; content: string; time: string; type: 'message' | 'system' | 'action' }[] +} + +const mockRecords: ChatRecord[] = [ + { + id: '1', visitorName: '张三', lastMessage: '好的谢谢,问题已解决', time: '10:45', status: 'ended', channel: '网页', agent: '客服小王', + satisfaction: 5, + messages: [ + { sender: '张三', content: '你好,我的订单怎么还没发货?', time: '10:30', type: 'message' }, + { sender: '客服小王', content: '您好,请提供一下您的订单号,我帮您查看', time: '10:31', type: 'message' }, + { sender: '张三', content: '订单号 AB20260714001', time: '10:32', type: 'message' }, + { sender: '系统', content: '客服小王查看了客户资料', time: '10:32', type: 'system' }, + { sender: '客服小王', content: '您好,您的订单已经在配送中,预计明天到达', time: '10:35', type: 'message' }, + { sender: '张三', content: '好的谢谢,问题已解决', time: '10:45', type: 'message' }, + { sender: '系统', content: '客服小王结束会话,原因:已解决', time: '10:45', type: 'action' }, + ], + }, + { + id: '2', visitorName: '李四', lastMessage: '这个功能怎么用?', time: '09:20', status: 'ended', channel: '微信', agent: '客服小李', + satisfaction: 4, + messages: [ + { sender: '李四', content: '这个功能怎么用?', time: '09:15', type: 'message' }, + { sender: '客服小李', content: '您好,请问您咨询的是哪个功能?', time: '09:16', type: 'message' }, + { sender: '李四', content: '就是那个批量导入', time: '09:17', type: 'message' }, + { sender: '系统', content: '客服小李使用了知识库条目"批量导入指南"', time: '09:18', type: 'action' }, + { sender: '客服小李', content: '批量导入功能在设置→数据管理中,支持 CSV 和 Excel 格式,点击即可上传', time: '09:19', type: 'message' }, + { sender: '李四', content: '明白了,谢谢', time: '09:20', type: 'message' }, + { sender: '系统', content: '客服小李结束会话,原因:已解决', time: '09:20', type: 'action' }, + ], + }, + { + id: '3', visitorName: '王五', lastMessage: '你们的价格比其他家贵很多', time: '08:50', status: 'active', channel: 'APP', agent: '客服小张', + messages: [ + { sender: '王五', content: '你们的价格比其他家贵很多', time: '08:45', type: 'message' }, + { sender: '客服小张', content: '您好,我们的产品在功能完整性和服务支持上有明显优势', time: '08:46', type: 'message' }, + { sender: '王五', content: '具体说说看', time: '08:47', type: 'message' }, + { sender: '客服小张', content: '我们有7×24小时在线客服、免费知识库搭建、数据报表分析等增值服务', time: '08:48', type: 'message' }, + { sender: '系统', content: '客服小张将会话转接给客服主管', time: '08:49', type: 'action' }, + { sender: '王五', content: '那还可以', time: '08:50', type: 'message' }, + ], + }, + { + id: '4', visitorName: '匿名访客342', lastMessage: '请问可以试用吗', time: '07-11 16:30', status: 'archived', channel: '网页', agent: '客服小王', + satisfaction: 3, + messages: [ + { sender: '匿名访客342', content: '请问可以试用吗', time: '16:25', type: 'message' }, + { sender: '客服小王', content: '可以的,我们提供7天免费试用', time: '16:26', type: 'message' }, + { sender: '系统', content: '客服小王结束会话,原因:已解决', time: '16:30', type: 'action' }, + ], + }, +] + +const statusColors: Record = { active: 'blue', ended: 'green', archived: 'default' } +const statusLabels: Record = { active: '进行中', ended: '已结束', archived: '已归档' } + +const ChatHistory = () => { + const [search, setSearch] = useState('') + const [channelFilter, setChannelFilter] = useState() + const [agentFilter, setAgentFilter] = useState() + const [statusFilter, setStatusFilter] = useState() + const [dateRange, setDateRange] = useState<[Dayjs | null, Dayjs | null]>([null, null]) + const [selectedId, setSelectedId] = useState('1') + + const filtered = mockRecords.filter(r => { + if (search && !r.visitorName.includes(search)) return false + if (channelFilter && r.channel !== channelFilter) return false + if (agentFilter && r.agent !== agentFilter) return false + if (statusFilter && r.status !== statusFilter) return false + return true + }) + + const selected = mockRecords.find(r => r.id === selectedId) + + return ( +
+ {/* 左侧列表 */} +
+
+ } placeholder="搜索访客名称..." value={search} onChange={e => setSearch(e.target.value)} allowClear size="small" /> +
+ ({ value: v, label: statusLabels[v] }))} /> +
+
+ } placeholder="搜索客户名称、手机号、邮箱" value={search} onChange={e => setSearch(e.target.value)} className="w-64" allowClear /> + ({ value: v, label: statusMap[v].text }))} allowClear /> + } placeholder="搜索标题或内容..." value={search} onChange={e => setSearch(e.target.value)} className="w-56" size="small" allowClear /> +
+ +
+ +
+ }} + /> + + + + setModalOpen(false)} + onOk={() => form.submit()} + width={640} + > +
setModalOpen(false)} className="mt-4"> + + + + + + + +
+ + ) +} + export default Knowledge diff --git a/web/src/pages/agent/Statistics.tsx b/web/src/pages/agent/Statistics.tsx index ec9fa7f..1bb762c 100644 --- a/web/src/pages/agent/Statistics.tsx +++ b/web/src/pages/agent/Statistics.tsx @@ -1,6 +1,140 @@ -const Statistics = () => ( -
-
数据统计
开发中...
-
-) +import { useState } from 'react' +import { Card, Segmented, Row, Col } from 'antd' +import { ArrowUpOutlined, ArrowDownOutlined, ClockCircleOutlined, SmileOutlined, CheckCircleOutlined, MessageOutlined } from '@ant-design/icons' +import { Column, Line, Pie, Bar } from '@ant-design/charts' + +const kpiData = [ + { label: '总会话量', value: '12,580', change: 12.5, icon: , color: '#2563eb' }, + { label: '平均响应时长', value: '32s', change: -8.3, icon: , color: '#16a34a' }, + { label: '客户满意度', value: '4.8/5', change: 2.1, icon: , color: '#d97706' }, + { label: '首次解决率', value: '86%', change: 5.7, icon: , color: '#0891b2' }, +] + +const sessionTrendData = [ + { date: '07-08', count: 420 }, { date: '07-09', count: 380 }, { date: '07-10', count: 450 }, + { date: '07-11', count: 520 }, { date: '07-12', count: 490 }, { date: '07-13', count: 550 }, + { date: '07-14', count: 610 }, +] + +const responseDistribution = [ + { range: '0-10s', count: 320 }, { range: '10-30s', count: 450 }, { range: '30-60s', count: 280 }, + { range: '1-3min', count: 180 }, { range: '>3min', count: 50 }, +] + +const channelData = [ + { type: '网页', value: 45 }, { type: '微信', value: 28 }, { type: 'APP', value: 18 }, + { type: '电话工单', value: 6 }, { type: '邮件', value: 3 }, +] + +const agentPerformance = [ + { name: '客服小王', conversations: 420, avgResponse: 28, satisfaction: 4.9 }, + { name: '客服小李', conversations: 380, avgResponse: 35, satisfaction: 4.7 }, + { name: '客服小张', conversations: 350, avgResponse: 42, satisfaction: 4.5 }, + { name: '客服小赵', conversations: 290, avgResponse: 30, satisfaction: 4.8 }, + { name: '客服小刘', conversations: 220, avgResponse: 55, satisfaction: 4.2 }, +] + +const Statistics = () => { + const [timeRange, setTimeRange] = useState('week') + + return ( +
+
+

数据统计

+ setTimeRange(v as string)} + options={[ + { value: 'today', label: '今日' }, + { value: 'week', label: '本周' }, + { value: 'month', label: '本月' }, + ]} + /> +
+ + {/* KPI 卡片 */} + + {kpiData.map((kpi, i) => ( +
+ +
+ {kpi.label} + {kpi.icon} +
+
{kpi.value}
+
= 0 ? 'text-green-600' : 'text-red-500'}`}> + {kpi.change >= 0 ? : } + {Math.abs(kpi.change)}% 较上期 +
+
+ + ))} + + + {/* 图表区 */} + + + + + + + + + + + + + + + + + + + + + + + + ) +} + export default Statistics