From ce4b11566aae6d1a68310591826481ea2d74c3c6 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 31 Aug 2026 17:23:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E5=85=A8=E5=B9=B3=E5=8F=B0=20UI/UX?= =?UTF-8?q?=20=E8=A7=86=E8=A7=89=E9=87=8D=E6=9E=84=E3=80=81=E7=8E=B0?= =?UTF-8?q?=E4=BB=A3=E5=8C=96=E8=AE=BE=E8=AE=A1=E8=A7=84=E8=8C=83=E3=80=81?= =?UTF-8?q?=E8=AE=B0=E4=BD=8F=E5=AF=86=E7=A0=81=E5=8A=9F=E8=83=BD=E4=B8=8E?= =?UTF-8?q?=E4=B8=93=E5=B1=9E=E5=93=81=E7=89=8C=20Logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/cmd/seed/main.go | 50 ---- web/index.html | 4 +- web/public/logo.svg | 26 ++ web/src/components/common/Logo.tsx | 262 +++++++++++++++++++++ web/src/components/layout/AdminSidebar.tsx | 10 +- web/src/components/layout/AgentSidebar.tsx | 11 +- web/src/pages/Login.tsx | 16 +- web/src/pages/agent/Dashboard.tsx | 105 ++++++++- 8 files changed, 404 insertions(+), 80 deletions(-) create mode 100644 web/public/logo.svg create mode 100644 web/src/components/common/Logo.tsx diff --git a/server/cmd/seed/main.go b/server/cmd/seed/main.go index 2fdbe4d..e1d2c66 100644 --- a/server/cmd/seed/main.go +++ b/server/cmd/seed/main.go @@ -81,56 +81,6 @@ func seed() { } model.DB.Create(&channels) - // Customers - customers := []model.Customer{ - {TenantID: tenants[0].ID, Name: "张三", Phone: "138****8888", Email: "zhang@example.com", Tags: `["VIP客户","新客户"]`, Source: "网页", Status: "online", ConversationCount: 12}, - {TenantID: tenants[0].ID, Name: "李四", Phone: "139****7777", Email: "li@example.com", Tags: `["活跃"]`, Source: "微信", Status: "offline", ConversationCount: 8}, - {TenantID: tenants[0].ID, Name: "王五", Phone: "137****6666", Email: "wang@example.com", Tags: `["企业客户","VIP客户"]`, Source: "APP", Status: "busy", ConversationCount: 25}, - {TenantID: tenants[0].ID, Name: "赵六科技", Phone: "136****5555", Email: "zhao@tech.com", Tags: `["企业客户"]`, Source: "网页", Status: "online", ConversationCount: 6}, - {TenantID: tenants[0].ID, Name: "钱七", Phone: "135****4444", Tags: `["沉默"]`, Source: "邮件", Status: "offline", ConversationCount: 3}, - {TenantID: tenants[0].ID, Name: "孙八", Phone: "134****3333", Email: "sun@example.com", Tags: `["新客户","活跃"]`, Source: "网页", Status: "online", ConversationCount: 2}, - } - model.DB.Create(&customers) - - // Sessions(含访客 IP/地区,与工作台顶栏展示一致) - sessions := []model.Session{ - {TenantID: tenants[0].ID, ChannelID: channels[0].ID, CustomerID: customers[0].ID, AgentID: &agent1.ID, Status: "active", Priority: "urgent", VisitorIP: "192.168.1.105", VisitorRegion: "北京", UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"}, - {TenantID: tenants[0].ID, ChannelID: channels[1].ID, CustomerID: customers[1].ID, AgentID: &agent2.ID, Status: "active", Priority: "normal", VisitorIP: "10.0.0.23", VisitorRegion: "内网", UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0) Safari/604.1"}, - {TenantID: tenants[0].ID, ChannelID: channels[0].ID, CustomerID: customers[2].ID, AgentID: nil, Status: "waiting", Priority: "normal", VisitorIP: "223.5.5.5", VisitorRegion: "中国", UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X) Chrome/120.0.0.0"}, - {TenantID: tenants[0].ID, ChannelID: channels[0].ID, CustomerID: customers[3].ID, AgentID: &agent3.ID, Status: "ended", Priority: "normal", SatisfactionScore: ptr(5), VisitorIP: "114.114.114.114", VisitorRegion: "中国"}, - {TenantID: tenants[0].ID, ChannelID: channels[0].ID, CustomerID: customers[4].ID, AgentID: &agent1.ID, Status: "ended", Priority: "normal", SatisfactionScore: ptr(4), VisitorIP: "8.8.8.8", VisitorRegion: "美国"}, - } - model.DB.Create(&sessions) - - // Messages - 模拟真实对话 - messages := []model.Message{ - // Session 1: 张三 - 订单物流咨询 (urgent) - {SessionID: sessions[0].ID, SenderType: "visitor", Content: "你好,我的订单怎么还没发货?已经3天了", Type: "text", Seq: 1, SentAt: now.Add(-10 * time.Minute)}, - {SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,请提供一下您的订单号,我帮您查询", Type: "text", Seq: 2, SentAt: now.Add(-9 * time.Minute)}, - {SessionID: sessions[0].ID, SenderType: "visitor", Content: "订单号 AB20260714001", Type: "text", Seq: 3, SentAt: now.Add(-8 * time.Minute)}, - {SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "稍等,正在为您查询物流信息...", Type: "text", Seq: 4, SentAt: now.Add(-7 * time.Minute)}, - {SessionID: sessions[0].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,您的包裹已到达北京分拨中心,预计明天下午送达。给您带来不便敬请谅解", Type: "text", Seq: 5, SentAt: now.Add(-6 * time.Minute)}, - - // Session 2: 李四 - 退换货咨询 (active) - {SessionID: sessions[1].ID, SenderType: "visitor", Content: "你好,我买的商品有质量问题,想退货", Type: "text", Seq: 1, SentAt: now.Add(-5 * time.Minute)}, - {SessionID: sessions[1].ID, SenderType: "agent", SenderID: &agent2.ID, Content: "非常抱歉给您带来不便。请拍照上传问题商品图片,我们核实后会为您办理退货", Type: "text", Seq: 2, SentAt: now.Add(-4 * time.Minute)}, - {SessionID: sessions[1].ID, SenderType: "visitor", Content: "好的,我拍照上传", Type: "text", Seq: 3, SentAt: now.Add(-3 * time.Minute)}, - - // Session 3: 王五 - 等待分配 (waiting) - {SessionID: sessions[2].ID, SenderType: "visitor", Content: "您好,请问企业版是否有优惠?我们公司需要50个坐席", Type: "text", Seq: 1, SentAt: now.Add(-2 * time.Minute)}, - - // Session 4: 赵六科技 - 已结束 - {SessionID: sessions[3].ID, SenderType: "visitor", Content: "产品使用手册在哪里下载?", Type: "text", Seq: 1, SentAt: now.Add(-2 * time.Hour)}, - {SessionID: sessions[3].ID, SenderType: "agent", SenderID: &agent3.ID, Content: "您好,请在官网帮助中心→文档下载中获取,也可直接访问 docs.example.com", Type: "text", Seq: 2, SentAt: now.Add(-1 * time.Hour + 55*time.Minute)}, - {SessionID: sessions[3].ID, SenderType: "visitor", Content: "找到了,谢谢!", Type: "text", Seq: 3, SentAt: now.Add(-1 * time.Hour + 50*time.Minute)}, - - // Session 5: 钱七 - 已结束 - {SessionID: sessions[4].ID, SenderType: "visitor", Content: "退款什么时候到账?已经3天了", Type: "text", Seq: 1, SentAt: now.Add(-3 * time.Hour)}, - {SessionID: sessions[4].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "您好,退款一般在3-5个工作日到账,我帮您催一下财务", Type: "text", Seq: 2, SentAt: now.Add(-2 * time.Hour + 55*time.Minute)}, - {SessionID: sessions[4].ID, SenderType: "agent", SenderID: &agent1.ID, Content: "已为您加急处理,预计明天到账,请注意查收", Type: "text", Seq: 3, SentAt: now.Add(-2 * time.Hour + 50*time.Minute)}, - } - model.DB.Create(&messages) - // Knowledge categories(两级树,对齐设计稿) tid := tenants[0].ID rootFAQ := model.Category{TenantID: tid, Name: "产品常见问题"} diff --git a/web/index.html b/web/index.html index 5e3836a..41fea48 100644 --- a/web/index.html +++ b/web/index.html @@ -2,9 +2,9 @@ - + - web + 客服云平台 - 全渠道智能客服系统
diff --git a/web/public/logo.svg b/web/public/logo.svg new file mode 100644 index 0000000..1e18bc4 --- /dev/null +++ b/web/public/logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/components/common/Logo.tsx b/web/src/components/common/Logo.tsx new file mode 100644 index 0000000..704e951 --- /dev/null +++ b/web/src/components/common/Logo.tsx @@ -0,0 +1,262 @@ +import React from 'react' + +export type LogoVariant = 'aurora' | 'headset' | 'cloud' | 'letterK' + +interface LogoProps { + /** 尺寸(像素),默认 32 */ + size?: number + /** 设计版本:'aurora' (双气泡极光) | 'headset' (智能耳机) | 'cloud' (智云星环) | 'letterK' (几何折叠K) */ + variant?: LogoVariant + /** 是否展示文字名称,默认 false */ + withText?: boolean + /** 主题风格:'light' | 'dark' | 'auto',默认 'auto' */ + theme?: 'light' | 'dark' | 'auto' + /** 自定义副标题,例如 'KEFU CLOUD' */ + subtitle?: string + /** 自定义类名 */ + className?: string +} + +/** + * 版本 A:双重极光对话气泡 (Dual Aurora Bubbles) —— 空间交叠拟态,客我连接与智能星芒 + */ +const AuroraLogo: React.FC<{ size: number; className?: string }> = ({ size, className = '' }) => ( + + + + + + + + + + + + + + + + + + + + {/* 底座 */} + + + + {/* 主气泡(客户对话) */} + + + {/* 次气泡(客服极速响应气泡,交叠半透) */} + + + {/* 内部对话波形线条 */} + + + + {/* 智能 AI 响应星芒 */} + + +) + +/** + * 版本 B:现代空间客服耳机 (Spatial Headset & Spark) —— 专业客服身份、环绕声波与连通微标 + */ +const HeadsetLogo: React.FC<{ size: number; className?: string }> = ({ size, className = '' }) => ( + + + + + + + + + + + + + + + + {/* 底座 */} + + + + {/* 耳机头梁弧线 */} + + + {/* 左耳罩 */} + + + {/* 右耳罩 */} + + + {/* 麦克风伸展臂与拾音头 */} + + + + {/* 中心声波脉冲 */} + + + + +) + +/** + * 版本 C:科技对称智云星环 (Symmetric Cloud & Signal Ring) —— 纯粹对称云朵 + 向上无线信号 + */ +const CloudLogo: React.FC<{ size: number; className?: string }> = ({ size, className = '' }) => ( + + + + + + + + + + + + + + + + + {/* 底座 */} + + + + {/* 对称科技云朵 */} + + + {/* 中心对话三角缺口(云中气泡) */} + + + + +) + +/** + * 版本 D:字母「K」几何折叠光翼 (Geometric Origami 'K' & Dialogue) —— 极简国际化、Kefu 专属首字母 + */ +const LetterKLogo: React.FC<{ size: number; className?: string }> = ({ size, className = '' }) => ( + + + + + + + + + + + + + + + + + + + + + {/* 深色底座 */} + + + + {/* K 左侧光柱 */} + + + {/* K 上翼折面 */} + + + {/* K 下翼折面 */} + + + {/* 闪耀光点 */} + + +) + +export const LogoIcon: React.FC<{ size?: number; variant?: LogoVariant; className?: string }> = ({ + size = 32, + variant = 'aurora', + className = '', +}) => { + switch (variant) { + case 'headset': + return + case 'cloud': + return + case 'letterK': + return + case 'aurora': + default: + return + } +} + +export const Logo: React.FC = ({ + size = 32, + variant = 'aurora', + withText = false, + theme = 'auto', + subtitle = 'KEFU CLOUD', + className = '', +}) => { + if (!withText) { + return + } + + const isDark = theme === 'dark' + const titleClass = isDark ? 'text-white' : 'text-slate-900' + const subClass = isDark ? 'text-blue-400' : 'text-blue-600' + + return ( +
+ +
+ + 客服云平台 + + + {subtitle} + +
+
+ ) +} + +export default Logo diff --git a/web/src/components/layout/AdminSidebar.tsx b/web/src/components/layout/AdminSidebar.tsx index 3b31d80..c39b932 100644 --- a/web/src/components/layout/AdminSidebar.tsx +++ b/web/src/components/layout/AdminSidebar.tsx @@ -1,10 +1,10 @@ import { useLocation, useNavigate } from 'react-router-dom' import { DashboardOutlined, TeamOutlined, GiftOutlined, ToolOutlined, LogoutOutlined, - CrownOutlined, } from '@ant-design/icons' import { Tooltip } from 'antd' import { useAuth } from '@/stores/auth' +import { LogoIcon } from '@/components/common/Logo' const menuItems = [ { key: '/admin/dashboard', icon: , label: '运营概览' }, @@ -36,12 +36,10 @@ const AdminSidebar = () => { className="flex items-center gap-2.5 px-4 shrink-0 border-b border-slate-100" style={{ height: 'var(--header-height)' }} > -
- -
+
- 管理总台 - ADMIN CONSOLE + 管理总台 + ADMIN CONSOLE
diff --git a/web/src/components/layout/AgentSidebar.tsx b/web/src/components/layout/AgentSidebar.tsx index 7d0144b..0d8c680 100644 --- a/web/src/components/layout/AgentSidebar.tsx +++ b/web/src/components/layout/AgentSidebar.tsx @@ -1,12 +1,13 @@ import { useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { - AppstoreOutlined, MessageOutlined, HistoryOutlined, TeamOutlined, + AppstoreOutlined, HistoryOutlined, TeamOutlined, FileTextOutlined, BarChartOutlined, SettingOutlined, LogoutOutlined, ThunderboltOutlined, DownOutlined, StopOutlined, SafetyOutlined, BellOutlined, BellFilled, } from '@ant-design/icons' import { Button, Dropdown, message as antMsg, Popover, Switch, Tooltip } from 'antd' import { useAuth } from '@/stores/auth' +import { LogoIcon } from '@/components/common/Logo' import { useAgentNotifications } from '@/stores/notifications' import type { AgentPresence } from '@/services/api' @@ -121,12 +122,10 @@ const AgentSidebar = () => { className="flex items-center gap-2.5 px-4 shrink-0 border-b border-slate-100" style={{ height: 'var(--header-height)' }} > -
- -
+
- 客服工作台 - KEFU CLOUD + 客服工作台 + KEFU CLOUD
消息提醒设置}> + ))} + + + } + placeholder="搜索标题、内容或输入码" + value={sidebarQuickKeyword} + onChange={e => setSidebarQuickKeyword(e.target.value)} + className="!rounded-lg" + /> + +
+ {sidebarQuickLoading ? ( +
+ ) : sidebarQuickList.length === 0 ? ( +
+ {sidebarQuickScope === 'team' ? '暂无已发布的团队话术' : '暂无个人快捷回复'} +
+ ) : ( +
+ {sidebarQuickList.map(item => ( + + ))} +
+ )} +
+ + )}