From ba3b1534f8a85fd731da2a09c029852377484151 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 31 Aug 2026 17:29:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(settings):=20=E7=B3=BB=E7=BB=9F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=95=8C=E9=9D=A2=E9=87=8D=E6=9E=84=E4=B8=8E=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E8=A7=84=E8=8C=83=E5=AF=B9=E9=BD=90=EF=BC=88=E5=88=86?= =?UTF-8?q?=E7=BB=84=E4=BE=A7=E8=BE=B9=E6=A0=8F=E3=80=81=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=BC=8F=E5=AE=BD=E5=B1=8F=E5=8D=A1=E7=89=87=E4=B8=8E=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=BE=8E=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/agent/Settings.tsx | 599 +++++++++++++++++++------------ 1 file changed, 378 insertions(+), 221 deletions(-) diff --git a/web/src/pages/agent/Settings.tsx b/web/src/pages/agent/Settings.tsx index b2bbb35..07d4ec3 100644 --- a/web/src/pages/agent/Settings.tsx +++ b/web/src/pages/agent/Settings.tsx @@ -130,17 +130,46 @@ const statusLabel: Record = { disabled: { text: '已禁用', className: 'bg-red-50 text-red-600' }, } -const tabItems: { key: string; label: string; desc: string; icon: ReactNode }[] = [ - { key: 'basic', label: '基本设置', desc: '租户展示名称、默认昵称与时区', icon: }, - { key: 'channels', label: '渠道管理', desc: '配置客户服务接入渠道与嵌入代码', icon: }, - { key: 'staff', label: '坐席账号', desc: '管理客服/主管账号与坐席配额', icon: }, - { key: 'assignment', label: '客服分配规则', desc: '自动分配策略与并发上限', icon: }, - { key: 'tags', label: '客户标签', desc: '维护标签库,坐席为客户打标时选择', icon: }, - { key: 'autoreply', label: '自动回复', desc: '多段欢迎语(含图片)与离线留言提示', icon: }, - { key: 'worktime', label: '工作时间', desc: '在线服务时段与非工作时间提示', icon: }, - { key: 'notify', label: '通知设置', desc: '新会话、留言与日报偏好', icon: }, +export interface TabItem { + key: string + label: string + desc: string + icon: ReactNode +} + +export interface TabGroup { + groupName: string + items: TabItem[] +} + +const tabGroups: TabGroup[] = [ + { + groupName: '企业与渠道', + items: [ + { key: 'basic', label: '基本设置', desc: '租户展示名称、默认昵称与时区', icon: }, + { key: 'channels', label: '渠道管理', desc: '配置客户服务接入渠道与嵌入代码', icon: }, + { key: 'staff', label: '坐席账号', desc: '管理客服/主管账号与坐席配额', icon: }, + ], + }, + { + groupName: '规则与路由', + items: [ + { key: 'assignment', label: '客服分配规则', desc: '自动分配策略与并发上限', icon: }, + { key: 'tags', label: '客户标签', desc: '维护标签库,坐席为客户打标时选择', icon: }, + { key: 'worktime', label: '工作时间', desc: '在线服务时段与非工作时间提示', icon: }, + ], + }, + { + groupName: '自动化与通知', + items: [ + { key: 'autoreply', label: '自动回复', desc: '多段欢迎语(含图片)与离线留言提示', icon: }, + { key: 'notify', label: '通知设置', desc: '新会话、留言与日报偏好', icon: }, + ], + }, ] +const tabItems: TabItem[] = tabGroups.flatMap(g => g.items) + const Settings = () => { const { user } = useAuth() const isAdmin = usePermission('settings.basic') @@ -415,38 +444,47 @@ const Settings = () => { ) : null + const currentGroup = tabGroups.find(g => g.items.some(i => i.key === activeTab)) + return (
{/* 左侧设置导航 — 顶栏 56px */} -
-
-
-

{currentTab.desc}

- +
+
{activeTab === 'basic' && ( -
+
{loadingSettings && !settings ? ( -
+
) : (
{ timezone: values.timezone, })} > - - - - - - - - - - - - +
+

企业展示档案

+

配置访客端看到的租户品牌名称与在线客服默认身份

+
+ +
+ 租户名称} + rules={[{ required: true, message: '请输入租户名称' }, { min: 1, max: 100 }]} + extra={公司或品牌名称,展示于访客端聊天窗口顶部} + > + + + + 客服默认昵称} + extra={未设置个人独立昵称的坐席将默认以此名称展示} + > + + +
+ +
+

区域与本地化

+

定义系统的标准服务时区与工作台界面语言

+
+ +
+ 服务时区} + extra={影响营业时间判断、会话统计与历史报表生成} + > + + +
+ +
+ 配置保存后将实时对访客端与坐席工作台生效 + +
)}
@@ -523,34 +610,40 @@ const Settings = () => { {loadingChannels ? (
) : channels.length === 0 ? ( -
+
- +
) : ( -
+
{channels.map(ch => { const meta = typeMeta[ch.type] || { icon: , label: ch.name || ch.type, desc: '' } const enabled = ch.status === 'enabled' return (
-
+
{meta.icon}
-
-

+
+

{ch.name || meta.label}

{enabled ? '已启用' : '未启用'} @@ -564,21 +657,21 @@ const Settings = () => { />
{meta.desc && ( -

{meta.desc}

+

{meta.desc}

)} {ch.channel_key && (
- 渠道 ID - + 渠道 ID + {ch.channel_key}
)} {ch.type === 'web' && ch.script_code && ( -
-
接入代码
-
- +
+
网站嵌入代码
+
+ {ch.script_code.replace( 'src="/widget.js"', `src="${window.location.origin}/widget.js"`, @@ -586,8 +679,8 @@ const Settings = () => {
)} {ch.type !== 'web' && ( -
+
本期仅网页渠道可完整接入,其他类型预留开关。
)} @@ -609,11 +702,11 @@ const Settings = () => { )} {missingTypes.length > 0 && channels.length > 0 && ( -
-
可添加渠道类型
-
+
+
可添加其他渠道
+
{missingTypes.map(t => ( - ))} @@ -624,27 +717,27 @@ const Settings = () => { )} {activeTab === 'assignment' && ( -
+
{loadingSettings ? (
) : ( <> -
-
-
+
+
+
-
自动分配规则
-
- 工作时间内,访客进线会按下列策略分配给在线一线客服; - 非工作时间或无可接坐席时进入排队/留言。人工领取与转接不受此策略限制。 +
自动分配规则
+
+ 工作时间内,访客进线会按下列策略自动分配给在线一线客服; + 非工作时间或无可接坐席时进入排队或离线留言。人工领取与内部转接不受此策略限制。
-
+
{ > 分配策略} rules={[{ required: true, message: '请选择策略' }]} - extra="负载最低:优先进行中会话更少的坐席;轮询:在可接坐席中依次分配,更均匀。" + extra={负载最低:优先分配给进行中会话最少的坐席;轮询:在可接坐席中均匀依次分发。} > + - {isAdmin ? ( - - ) : ( -

仅租户管理员可修改分配规则

- )} + +
+ {isAdmin ? ( + + ) : ( +

仅租户管理员可修改分配规则

+ )} +
-
-
说明
-

· 候选范围:角色为客服、状态为「在线」的账号(忙碌/离线不参与自动分配)。

-

· 技能组 / 渠道专属坐席将在后续版本支持。

+
+
使用说明
+

· 自动分发候选范围:角色为客服、当前状态为「在线」的账号(忙碌/离线状态不参与自动分发)。

+

· 专属坐席组与渠道绑定策略将在后续版本逐步上线。

)} @@ -713,40 +815,40 @@ const Settings = () => { {activeTab === 'staff' && (
{!canViewStaff ? ( -
+
仅管理员或主管可查看坐席列表
) : loadingStaff ? (
) : ( <> -
-
-
坐席占用
-
+
+
+
坐席配额占用
+
{seatUsed} - / {seatLimit} + / {seatLimit}
-
- 启用中的管理员、主管、客服各占 1 个坐席。禁用账号释放配额。角色:客服接待会话;主管可看统计与客户;管理员可改系统设置。 +
+ 启用中的管理员、主管、客服各占 1 个坐席。禁用账号可即刻释放坐席配额。
{staffList.length === 0 ? ( - + ) : ( -
+
- - - - - - + + + + + + {isAdmin && ( - + )} @@ -754,29 +856,29 @@ const Settings = () => { {staffList.map(s => { const st = statusLabel[s.status] || statusLabel.offline return ( - - - - + + + - - {isAdmin && ( -
账号昵称角色状态创建时间
账号昵称角色状态创建时间操作操作
{s.username}{s.nickname || '—'} - +
{s.username}{s.nickname || '—'} + {roleLabel[s.role] || s.role} - + + {st.text} + {s.created_at ? s.created_at.slice(0, 16) : '—'} e.stopPropagation()}> -
+
e.stopPropagation()}> +
@@ -823,9 +925,9 @@ const Settings = () => { )} {activeTab === 'autoreply' && ( -
+
{loadingSettings && !settings ? ( -
+
) : (
{ }, '自动回复已保存') }} > -
-
+
+
-
欢迎语(多段)
-

- 访客打开窗口且尚无消息时按顺序展示;可混排富文本与图片,最多 {MAX_WELCOME_SEGMENTS} 段。 - 选中文字可设置颜色、字号、加粗等(仅欢迎语;正常聊天仍为 Markdown)。 +

欢迎语(多段混合展示)

+

+ 访客首次进入聊天窗口时按序自动推送;支持图文混排,最多可添加 {MAX_WELCOME_SEGMENTS} 段。

@@ -872,11 +973,11 @@ const Settings = () => { {welcomeSegments.map((seg, idx) => (
-
- - 第 {idx + 1} 段 · {seg.type === 'image' ? '图片' : '文本'} +
+ + 第 {idx + 1} 段 · {seg.type === 'image' ? '图片消息' : '富文本消息'}
@@ -978,10 +1083,11 @@ const Settings = () => {
))}
-
+
- - - - - - + +
+ 离线留言提示语} + rules={[{ max: 500 }]} + extra={当座席全部离线或在非工作时段进线时向访客展示} + > + + +
+ +
+ 更新自动回复后实时对新访客生效 + +
)}
)} {activeTab === 'worktime' && ( -
+
{loadingSettings && !settings ? ( -
+
) : (
{ }, '工作时间已保存') }} > -

- 每天可设为休息、全天或自定义时段(支持跨午夜,如 22:00-06:00)。 - 非工作时间访客将看到下方提示并可留言。 -

-
+
+

营业与服务时间段

+

+ 设定每周工作日在线服务时间;非服务时间系统将向访客展示非工作时间提示。 +

+
+ +
-
+ +
{weekDays.map((day, i) => (
- {day.label} + {day.label} - - - + + 非工作时间提示语} + rules={[{ max: 500 }]} + > + + +
+ 时段以系统时区为准 + +
)}
)} {activeTab === 'notify' && ( -
+
{loadingSettings && !settings ? ( -
+
) : (
{ notify_daily_report: values.notify_daily_report, }, '通知设置已保存')} > -
+
+

通知推送偏好

+

配置各类关键业务事件的系统通知与推送规则

+
+ +
{[ { name: 'notify_new_session', title: '新会话提醒', desc: '有新访客进线时提醒;浏览器通知与声音可在工作台铃铛中配置' }, - { name: 'notify_offline_leave', title: '离线留言通知', desc: '访客提交离线留言时提醒' }, - { name: 'notify_daily_report', title: '日报推送', desc: '每日服务数据摘要' }, + { name: 'notify_offline_leave', title: '离线留言通知', desc: '访客在离线时段提交留言时发送系统提醒' }, + { name: 'notify_daily_report', title: '服务日报推送', desc: '每日定时汇总推送坐席接待与满意度数据摘要' }, ].map(item => (
-
-
{item.title}
-
{item.desc}
+
+
{item.title}
+
{item.desc}
@@ -1223,26 +1368,36 @@ const Settings = () => {
))}
- - - + +
+ +
)}
)} {activeTab === 'tags' && ( -
-
+
+
-

- 在此创建标签后,客户管理与工作台中员工只能从列表选择,不能随意输入新标签。 +

客户标签库

+

+ 维护企业标准标签体系,坐席可在客户管理与工作台快捷打标。

{loadingTags ? ( -
+
) : customerTags.length === 0 ? ( - + ) : ( -
+
{customerTags.map(tag => { const style = tagColorStyle(tag.color) return (
{tag.name} -
-