实现系统设置页面:基本设置、渠道管理、分配规则、权限、自动回复、工作时间、通知
This commit is contained in:
@@ -1,6 +1,231 @@
|
|||||||
const Settings = () => (
|
import { useState } from 'react'
|
||||||
<div className="h-full flex items-center justify-center text-neutral-400 text-center">
|
import { Form, Input, Switch, Select, Button, Card, Table, Tag, message } from 'antd'
|
||||||
<div><div className="text-lg mb-1">系统设置</div><div className="text-sm">开发中...</div></div>
|
import { LinkOutlined, WechatOutlined, PhoneOutlined, MailOutlined, MobileOutlined, CopyOutlined } from '@ant-design/icons'
|
||||||
</div>
|
|
||||||
)
|
const channelTypes = [
|
||||||
|
{ key: 'web', icon: <LinkOutlined />, label: '网页聊天', status: true, code: 'WK_8a3f2e', script: '<script src="https://cs.example.com/widget.js" data-id="WK_8a3f2e"></script>' },
|
||||||
|
{ key: 'wechat', icon: <WechatOutlined />, label: '微信公众号', status: true, code: 'WX_c7b9d1', script: '' },
|
||||||
|
{ key: 'app', icon: <MobileOutlined />, label: 'APP 内嵌', status: false, code: '', script: '' },
|
||||||
|
{ key: 'phone', icon: <PhoneOutlined />, label: '电话客服', status: false, code: '', script: '' },
|
||||||
|
{ key: 'email', icon: <MailOutlined />, label: '邮件工单', status: true, code: 'EM_f2a8c3', script: '' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const Settings = () => {
|
||||||
|
const [activeTab, setActiveTab] = useState('basic')
|
||||||
|
const [basicForm] = Form.useForm()
|
||||||
|
const [autoReplyForm] = Form.useForm()
|
||||||
|
|
||||||
|
const tabItems = [
|
||||||
|
{ key: 'basic', label: '基本设置' },
|
||||||
|
{ key: 'channels', label: '渠道管理' },
|
||||||
|
{ key: 'assignment', label: '分配规则' },
|
||||||
|
{ key: 'permission', label: '权限管理' },
|
||||||
|
{ key: 'autoreply', label: '自动回复' },
|
||||||
|
{ key: 'worktime', label: '工作时间' },
|
||||||
|
{ key: 'notify', label: '通知设置' },
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full flex">
|
||||||
|
{/* 左侧导航 */}
|
||||||
|
<div className="w-[200px] flex-shrink-0 bg-white border-r border-neutral-200 py-4">
|
||||||
|
<div className="px-4 mb-3">
|
||||||
|
<span className="text-xs text-neutral-400 font-medium">系统设置</span>
|
||||||
|
</div>
|
||||||
|
{tabItems.map(item => (
|
||||||
|
<div
|
||||||
|
key={item.key}
|
||||||
|
className={`px-4 py-2 text-sm cursor-pointer transition-colors ${activeTab === item.key ? 'bg-blue-50 text-blue-600 font-medium border-r-2 border-blue-500' : 'text-neutral-600 hover:bg-neutral-50'}`}
|
||||||
|
onClick={() => setActiveTab(item.key)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 右侧内容 */}
|
||||||
|
<div className="flex-1 overflow-auto p-6">
|
||||||
|
{/* 基本设置 */}
|
||||||
|
{activeTab === 'basic' && (
|
||||||
|
<Card title="基本设置" className="max-w-2xl">
|
||||||
|
<Form form={basicForm} layout="vertical" initialValues={{ name: '示例公司', nickname: '客服小助手', timezone: 'Asia/Shanghai', language: 'zh-CN' }}>
|
||||||
|
<Form.Item name="name" label="租户名称" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="公司名称" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="nickname" label="客服昵称">
|
||||||
|
<Input placeholder="客服在访客端显示的昵称" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="timezone" label="时区">
|
||||||
|
<Select options={[{ value: 'Asia/Shanghai', label: '东八区 (UTC+8)' }, { value: 'Asia/Tokyo', label: '东京 (UTC+9)' }]} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="language" label="语言">
|
||||||
|
<Select options={[{ value: 'zh-CN', label: '简体中文' }]} disabled />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" onClick={() => message.success('保存成功')}>保存设置</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 渠道管理 */}
|
||||||
|
{activeTab === 'channels' && (
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<h3 className="text-base font-semibold text-neutral-800">渠道管理</h3>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
{channelTypes.map(ch => (
|
||||||
|
<Card key={ch.key} size="small" className="!rounded-lg" title={
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-blue-500">{ch.icon}</span>
|
||||||
|
<span className="text-sm font-medium">{ch.label}</span>
|
||||||
|
<Tag color={ch.status ? 'green' : 'default'} className="ml-2">{ch.status ? '已启用' : '未启用'}</Tag>
|
||||||
|
</div>
|
||||||
|
}>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{ch.code && <div className="flex items-center justify-between text-sm"><span className="text-neutral-400">渠道ID</span><code className="text-xs bg-neutral-100 px-2 py-0.5 rounded">{ch.code}</code></div>}
|
||||||
|
{ch.script && (
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-neutral-400 mb-1">接入代码</div>
|
||||||
|
<div className="bg-neutral-50 border border-neutral-200 rounded p-2 flex items-center justify-between">
|
||||||
|
<code className="text-xs text-neutral-600 break-all">{ch.script}</code>
|
||||||
|
<CopyOutlined className="text-neutral-400 cursor-pointer hover:text-blue-500 ml-2 flex-shrink-0" onClick={() => message.success('已复制')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-sm text-neutral-400">启用状态</span>
|
||||||
|
<Switch defaultChecked={ch.status} size="small" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 分配规则 */}
|
||||||
|
{activeTab === 'assignment' && (
|
||||||
|
<Card title="客服分配规则" className="max-w-2xl">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="p-4 border border-neutral-200 rounded-lg">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-neutral-800">轮询分配</div>
|
||||||
|
<div className="text-xs text-neutral-400 mt-1">按在线客服顺序轮流分配会话,保证公平性</div>
|
||||||
|
</div>
|
||||||
|
<Switch defaultChecked />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border border-neutral-200 rounded-lg">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-neutral-800">负载均衡</div>
|
||||||
|
<div className="text-xs text-neutral-400 mt-1">优先分配给当前会话数最少的客服</div>
|
||||||
|
</div>
|
||||||
|
<Switch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border border-neutral-200 rounded-lg">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-neutral-800">熟客优先</div>
|
||||||
|
<div className="text-xs text-neutral-400 mt-1">回头客优先分配给上次接待的客服</div>
|
||||||
|
</div>
|
||||||
|
<Switch defaultChecked />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button type="primary" onClick={() => message.success('保存成功')}>保存规则</Button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 权限管理 */}
|
||||||
|
{activeTab === 'permission' && (
|
||||||
|
<Card title="权限管理" className="max-w-3xl">
|
||||||
|
<Table
|
||||||
|
dataSource={[
|
||||||
|
{ key: '1', role: '租户管理员', members: 2, permissions: '全部权限', status: true },
|
||||||
|
{ key: '2', role: '客服主管', members: 3, permissions: '会话管理、数据统计、知识库管理', status: true },
|
||||||
|
{ key: '3', role: '一线客服', members: 8, permissions: '会话接待、客户管理、知识库查看', status: true },
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
{ title: '角色', dataIndex: 'role', key: 'role' },
|
||||||
|
{ title: '成员数', dataIndex: 'members', key: 'members' },
|
||||||
|
{ title: '权限范围', dataIndex: 'permissions', key: 'permissions' },
|
||||||
|
{ title: '状态', dataIndex: 'status', key: 'status', render: (v: boolean) => <Tag color={v ? 'green' : 'default'}>{v ? '启用' : '禁用'}</Tag> },
|
||||||
|
{ title: '操作', key: 'op', render: () => <Button type="link" size="small">编辑</Button> },
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
size="middle"
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 自动回复 */}
|
||||||
|
{activeTab === 'autoreply' && (
|
||||||
|
<Card title="自动回复设置" className="max-w-2xl">
|
||||||
|
<Form form={autoReplyForm} layout="vertical" initialValues={{ welcome: '您好!欢迎来到客服云,请问有什么可以帮您的?', offline: '当前无客服在线,请留下联系方式,我们会尽快回复您。' }}>
|
||||||
|
<Form.Item name="welcome" label="欢迎语">
|
||||||
|
<Input.TextArea rows={3} placeholder="访客打开聊天窗口后自动发送的欢迎语" maxLength={500} showCount />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="offline" label="离线留言提示">
|
||||||
|
<Input.TextArea rows={3} placeholder="无客服在线时自动回复的提示语" maxLength={500} showCount />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" onClick={() => message.success('保存成功')}>保存设置</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 工作时间 */}
|
||||||
|
{activeTab === 'worktime' && (
|
||||||
|
<Card title="工作时间设置" className="max-w-2xl">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-neutral-700 mb-2">每周工作时段</div>
|
||||||
|
{['周一', '周二', '周三', '周四', '周五', '周六', '周日'].map(day => (
|
||||||
|
<div key={day} className="flex items-center gap-4 py-2 border-b border-neutral-50 last:border-0">
|
||||||
|
<span className="text-sm text-neutral-600 w-12">{day}</span>
|
||||||
|
<Select defaultValue={day === '周六' || day === '周日' ? undefined : '09:00-18:00'} placeholder="休息" className="w-36" size="small" allowClear options={['09:00-18:00', '08:00-17:00', '10:00-19:00', '全天'].map(v => ({ value: v, label: v }))} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium text-neutral-700 mb-2">非工作时间提示语</div>
|
||||||
|
<Input placeholder="当前非工作时间,我们将在工作时段尽快回复您" />
|
||||||
|
</div>
|
||||||
|
<Button type="primary" onClick={() => message.success('保存成功')}>保存设置</Button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 通知设置 */}
|
||||||
|
{activeTab === 'notify' && (
|
||||||
|
<Card title="通知设置" className="max-w-2xl">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{[ { label: '新会话提醒', desc: '有新访客发起会话时桌面通知' },
|
||||||
|
{ label: '消息声音', desc: '收到新消息时播放提示音' },
|
||||||
|
{ label: '离线消息通知', desc: '非工作时间收到的留言邮件通知' },
|
||||||
|
{ label: '日报推送', desc: '每日客服数据汇总邮件' },
|
||||||
|
{ label: '周报推送', desc: '每周客服数据汇总邮件' },
|
||||||
|
].map((item, i) => (
|
||||||
|
<div key={i} className="flex items-center justify-between py-2 border-b border-neutral-50 last:border-0">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-neutral-700">{item.label}</div>
|
||||||
|
<div className="text-xs text-neutral-400">{item.desc}</div>
|
||||||
|
</div>
|
||||||
|
<Switch defaultChecked={i < 3} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default Settings
|
export default Settings
|
||||||
|
|||||||
Reference in New Issue
Block a user