Merge branch 'yongpxu-dev' into develop
This commit is contained in:
26
Cunkebao/dist/.vite/manifest.json
vendored
26
Cunkebao/dist/.vite/manifest.json
vendored
@@ -1,14 +1,18 @@
|
||||
{
|
||||
"_charts-DN1cefc8.js": {
|
||||
"file": "assets/charts-DN1cefc8.js",
|
||||
"_charts-aNYyX7D2.js": {
|
||||
"file": "assets/charts-aNYyX7D2.js",
|
||||
"name": "charts",
|
||||
"imports": [
|
||||
"_ui-5V-xZWkf.js",
|
||||
"_ui-DZwp85UP.js",
|
||||
"_vendor-Bq99rrm8.js"
|
||||
]
|
||||
},
|
||||
"_ui-5V-xZWkf.js": {
|
||||
"file": "assets/ui-5V-xZWkf.js",
|
||||
"_ui-D0C0OGrH.css": {
|
||||
"file": "assets/ui-D0C0OGrH.css",
|
||||
"src": "_ui-D0C0OGrH.css"
|
||||
},
|
||||
"_ui-DZwp85UP.js": {
|
||||
"file": "assets/ui-DZwp85UP.js",
|
||||
"name": "ui",
|
||||
"imports": [
|
||||
"_vendor-Bq99rrm8.js"
|
||||
@@ -17,10 +21,6 @@
|
||||
"assets/ui-D0C0OGrH.css"
|
||||
]
|
||||
},
|
||||
"_ui-D0C0OGrH.css": {
|
||||
"file": "assets/ui-D0C0OGrH.css",
|
||||
"src": "_ui-D0C0OGrH.css"
|
||||
},
|
||||
"_utils-Ft3ushmX.js": {
|
||||
"file": "assets/utils-Ft3ushmX.js",
|
||||
"name": "utils",
|
||||
@@ -33,18 +33,18 @@
|
||||
"name": "vendor"
|
||||
},
|
||||
"index.html": {
|
||||
"file": "assets/index-9Clf2a7g.js",
|
||||
"file": "assets/index-CCIZs36L.js",
|
||||
"name": "index",
|
||||
"src": "index.html",
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"_vendor-Bq99rrm8.js",
|
||||
"_ui-5V-xZWkf.js",
|
||||
"_ui-DZwp85UP.js",
|
||||
"_utils-Ft3ushmX.js",
|
||||
"_charts-DN1cefc8.js"
|
||||
"_charts-aNYyX7D2.js"
|
||||
],
|
||||
"css": [
|
||||
"assets/index-CK1wd128.css"
|
||||
"assets/index-DRrzDMi4.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
8
Cunkebao/dist/index.html
vendored
8
Cunkebao/dist/index.html
vendored
@@ -11,13 +11,13 @@
|
||||
</style>
|
||||
<!-- 引入 uni-app web-view SDK(必须) -->
|
||||
<script type="text/javascript" src="/websdk.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-9Clf2a7g.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CCIZs36L.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-Bq99rrm8.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ui-5V-xZWkf.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ui-DZwp85UP.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/utils-Ft3ushmX.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/charts-DN1cefc8.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/charts-aNYyX7D2.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/ui-D0C0OGrH.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CK1wd128.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DRrzDMi4.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -43,33 +43,91 @@
|
||||
.headerRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.suanli {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 20px;
|
||||
border: 1px solid #e9ecef;
|
||||
|
||||
.suanliIcon {
|
||||
font-size: 24px;
|
||||
font-size: 16px;
|
||||
color: #ffc107;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #f0f0f0;
|
||||
.messageButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #e9ecef;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.userSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
border-radius: 24px;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #e9ecef;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.userNickname {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #e9ecef;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.username {
|
||||
|
||||
@@ -28,10 +28,10 @@ const Login: React.FC = () => {
|
||||
const { login, login2 } = useUserStore();
|
||||
const [verify, setVerify] = useState<{
|
||||
verifyCodeImage: string;
|
||||
verifyCode: string;
|
||||
verifySessionId: string;
|
||||
}>({
|
||||
verifyCodeImage: "",
|
||||
verifyCode: "",
|
||||
verifySessionId: "",
|
||||
});
|
||||
// 倒计时效果
|
||||
useEffect(() => {
|
||||
@@ -45,7 +45,7 @@ const Login: React.FC = () => {
|
||||
const res = await getVerifyCode();
|
||||
setVerify({
|
||||
verifyCodeImage: res.verifyCodeImage,
|
||||
verifyCode: res.verifyCode,
|
||||
verifySessionId: res.verifySessionId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ const Login: React.FC = () => {
|
||||
// 添加typeId参数
|
||||
const loginParams = {
|
||||
...values,
|
||||
typeId: activeTab as number,
|
||||
verifySessionId: verify.verifySessionId,
|
||||
};
|
||||
|
||||
const response =
|
||||
@@ -98,10 +98,10 @@ const Login: React.FC = () => {
|
||||
|
||||
response
|
||||
.then(res => {
|
||||
const { member, kefuData, deviceTotal } = res;
|
||||
const { member, kefuData } = res;
|
||||
// 清空WebSocket连接状态
|
||||
useWebSocketStore.getState().clearConnectionState();
|
||||
login(res.token, member, deviceTotal);
|
||||
login(res.token, member);
|
||||
const { self, token } = kefuData;
|
||||
login2(token.access_token);
|
||||
setUserInfo(self);
|
||||
@@ -218,7 +218,7 @@ const Login: React.FC = () => {
|
||||
)}
|
||||
{activeTab == 1 && verify.verifyCodeImage && (
|
||||
<Form.Item
|
||||
name="verificationCode"
|
||||
name="verifyCode"
|
||||
label="验证码"
|
||||
rules={[{ required: true, message: "请输入验证码" }]}
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@ import request2 from "@/api/request2";
|
||||
|
||||
// 密码登录
|
||||
export function loginWithPassword(params: any) {
|
||||
return request("/v1/auth/login", params, "POST");
|
||||
return request("/v1/kefu/login", params, "POST");
|
||||
}
|
||||
|
||||
// 验证码登录
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import { BarChartOutlined, RobotOutlined } from "@ant-design/icons";
|
||||
// 菜单项接口
|
||||
export interface MenuItem {
|
||||
id: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
icon: React.ReactNode;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
// 菜单列表数据
|
||||
export const menuList: MenuItem[] = [
|
||||
{
|
||||
id: "dashboard",
|
||||
title: "数据面板",
|
||||
icon: "📊",
|
||||
path: "/pc/dashboard",
|
||||
id: "wechat",
|
||||
title: "AI智能客服",
|
||||
icon: <RobotOutlined className="menuIcon" style={{ fontSize: 20 }} />,
|
||||
path: "/pc/weChat",
|
||||
},
|
||||
{
|
||||
id: "wechat",
|
||||
title: "微信管理",
|
||||
icon: "💬",
|
||||
path: "/pc/weChat",
|
||||
id: "powerCenter",
|
||||
title: "功能中心",
|
||||
icon: <BarChartOutlined className="menuIcon" style={{ fontSize: 20 }} />,
|
||||
path: "/pc/powerCenter",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -29,10 +30,6 @@ export const drawerMenuData = {
|
||||
appName: "触客宝",
|
||||
appDesc: "AI智能营销系统",
|
||||
},
|
||||
primaryButton: {
|
||||
title: "AI智能客服",
|
||||
icon: "🔒",
|
||||
},
|
||||
footer: {
|
||||
balanceIcon: "⚡",
|
||||
balanceLabel: "算力余额",
|
||||
@@ -1,3 +1,32 @@
|
||||
/**
|
||||
* NavCommon 组件样式文件
|
||||
*
|
||||
* 文件结构说明:
|
||||
* 1. Header 区域样式 - 顶部导航栏相关样式
|
||||
* - headerLeft: 左侧菜单按钮和标题
|
||||
* - headerRight: 右侧用户信息、算力显示、消息按钮等
|
||||
*
|
||||
* 2. Drawer 抽屉区域样式 - 左侧菜单抽屉相关样式
|
||||
* - drawerContent: 抽屉内容容器
|
||||
* - drawerHeader: 抽屉头部(Logo区域)
|
||||
* - drawerBody: 抽屉主体(主要按钮和菜单项)
|
||||
* - drawerFooter: 抽屉底部(余额显示)
|
||||
*
|
||||
* 3. 消息抽屉区域样式 - 右侧消息中心抽屉相关样式
|
||||
* - messageContent: 消息列表容器
|
||||
* - messageItem: 单个消息项样式
|
||||
*
|
||||
* 4. 兼容样式 - 保持向后兼容的独立样式类
|
||||
*
|
||||
* 5. 响应式设计 - 移动端适配样式
|
||||
*
|
||||
* 样式组织原则:
|
||||
* - 按照 tsx 文件中的嵌套结构组织样式
|
||||
* - 使用 SCSS 嵌套语法体现 DOM 层级关系
|
||||
* - 相关样式就近放置,便于维护
|
||||
*/
|
||||
|
||||
// ===== Header 区域样式 =====
|
||||
.header {
|
||||
background: #fff;
|
||||
padding: 0 16px;
|
||||
@@ -7,69 +36,124 @@
|
||||
justify-content: space-between;
|
||||
height: 64px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.headerLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
// Header 左侧区域
|
||||
.headerLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.menuButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
.menuButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
// Header 右侧区域
|
||||
.headerRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
.userInfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
.suanli {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
|
||||
.headerRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.suanliIcon {
|
||||
font-size: 20px;
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
color: #52c41a;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.suanli {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
.suanliIcon {
|
||||
font-size: 24px;
|
||||
.avatar {
|
||||
border: 2px solid #e9ecef;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.messageButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 80px;
|
||||
transition: all 0.3s;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
border: 1px solid #e9ecef;
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0px 12px rgba(24, 144, 255, 0.15);
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.userSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.userNickname {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #f0f0f0;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #1890ff;
|
||||
}
|
||||
// 兼容旧样式(避免破坏性更改)
|
||||
.bell {
|
||||
cursor: pointer;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.username {
|
||||
@@ -79,7 +163,8 @@
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
// 抽屉样式
|
||||
// ===== Drawer 抽屉区域样式 =====
|
||||
// 左侧菜单抽屉
|
||||
.drawer {
|
||||
:global(.ant-drawer-header) {
|
||||
background: #fafafa;
|
||||
@@ -89,142 +174,264 @@
|
||||
:global(.ant-drawer-body) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.drawerContent {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.drawerHeader {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.logoSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.logoIcon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.logoText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.appName {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.appDesc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
.drawerBody {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.primaryButton {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.buttonIcon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.menuSection {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.menuItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.menuIcon {
|
||||
font-size: 20px;
|
||||
margin-right: 12px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drawerFooter {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
.balanceSection {
|
||||
// 抽屉头部
|
||||
.drawerHeader {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-bottom: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.balanceIcon {
|
||||
color: #666;
|
||||
.suanliIcon {
|
||||
font-size: 20px;
|
||||
|
||||
.logoSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.logoIcon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: linear-gradient(135deg, #3b81f6 0%, #9035ea 100%);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.logoText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.appName {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.appDesc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.anticon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// 抽屉内容容器
|
||||
.drawerContent {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f8f9fa;
|
||||
|
||||
// 抽屉主体内容
|
||||
.drawerBody {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
.primaryButton {
|
||||
background: linear-gradient(135deg, #3d80f6 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.buttonIcon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单区域
|
||||
.menuSection {
|
||||
padding: 0px 20px;
|
||||
.menuItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-radius: 8px;
|
||||
margin: 4px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.menuIcon {
|
||||
font-size: 20px;
|
||||
margin-right: 12px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&.menuItemActive {
|
||||
background: linear-gradient(to right, #3b82f6, #9333ea);
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
|
||||
span {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.menuIcon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to right, #3b82f6, #9333ea);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.balanceText {
|
||||
color: #3d9c0d;
|
||||
// 抽屉底部
|
||||
.drawerFooter {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
|
||||
.balanceSection {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.balanceIcon {
|
||||
color: #666;
|
||||
|
||||
.suanliIcon {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.balanceText {
|
||||
color: #3d9c0d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 消息抽屉区域样式 =====
|
||||
.messageDrawer {
|
||||
:global(.ant-drawer-header) {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
:global(.ant-drawer-body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.messageContent {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.messageItem {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.messageAvatar {
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.messageInfo {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.messageTitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.messageType {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.messageStatus {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.messageText {
|
||||
font-size: 13px;
|
||||
color: #595959;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 8px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.messageTime {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
.messageActions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
|
||||
:global(.ant-btn) {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 兼容样式 =====
|
||||
.balanceLabel {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
@@ -237,22 +444,3 @@
|
||||
color: #52c41a;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.header {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
width: 280px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import React, { useState } from "react";
|
||||
import { Layout, Drawer, Avatar, Space, Button } from "antd";
|
||||
import { MenuOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { Layout, Drawer, Avatar, Space, Button, Badge, Dropdown } from "antd";
|
||||
import {
|
||||
MenuOutlined,
|
||||
UserOutlined,
|
||||
BellOutlined,
|
||||
CloseOutlined,
|
||||
LogoutOutlined,
|
||||
UserSwitchOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
import { useUserStore } from "@/store/module/user";
|
||||
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
// import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { drawerMenuData, menuList } from "./index.data";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
@@ -19,10 +27,12 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
onMenuClick,
|
||||
}) => {
|
||||
const [drawerVisible, setDrawerVisible] = useState(false);
|
||||
const [messageDrawerVisible, setMessageDrawerVisible] = useState(false);
|
||||
const [messageCount] = useState(3); // 模拟消息数量
|
||||
const navigate = useNavigate();
|
||||
const { userInfo } = useCkChatStore();
|
||||
const { user } = useUserStore();
|
||||
console.log(user);
|
||||
const location = useLocation();
|
||||
// const { userInfo } = useCkChatStore();
|
||||
const { user, logout } = useUserStore();
|
||||
|
||||
// 处理菜单图标点击
|
||||
const handleMenuClick = () => {
|
||||
@@ -35,6 +45,49 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
setDrawerVisible(false);
|
||||
};
|
||||
|
||||
// 处理消息中心点击
|
||||
const handleMessageClick = () => {
|
||||
setMessageDrawerVisible(true);
|
||||
};
|
||||
|
||||
// 处理消息抽屉关闭
|
||||
const handleMessageDrawerClose = () => {
|
||||
setMessageDrawerVisible(false);
|
||||
};
|
||||
|
||||
// 处理退出登录
|
||||
const handleLogout = () => {
|
||||
logout(); // 清除localStorage中的token和用户状态
|
||||
navigate("/login"); // 跳转到登录页面
|
||||
};
|
||||
|
||||
// 用户菜单项
|
||||
const userMenuItems = [
|
||||
{
|
||||
key: "userInfo",
|
||||
label: (
|
||||
<div style={{ fontWeight: "bold", color: "#188eee" }}>
|
||||
{user.username}({user.account})
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "profile",
|
||||
icon: <UserSwitchOutlined style={{ fontSize: 16 }} />,
|
||||
label: "个人资料",
|
||||
onClick: () => {
|
||||
console.log("个人资料点击");
|
||||
// TODO: 跳转到个人资料页面
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "logout",
|
||||
icon: <LogoutOutlined style={{ fontSize: 14 }} />,
|
||||
label: "退出登录",
|
||||
onClick: handleLogout,
|
||||
},
|
||||
];
|
||||
|
||||
// 默认抽屉内容
|
||||
const defaultDrawerContent = (
|
||||
<div className={styles.drawerContent}>
|
||||
@@ -52,30 +105,30 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className={styles.anticon} onClick={handleDrawerClose}>
|
||||
<CloseOutlined />
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.drawerBody}>
|
||||
<div className={styles.primaryButton}>
|
||||
<div className={styles.buttonIcon}>
|
||||
{drawerMenuData.primaryButton.icon}
|
||||
</div>
|
||||
<span>{drawerMenuData.primaryButton.title}</span>
|
||||
</div>
|
||||
<div className={styles.menuSection}>
|
||||
{menuList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={styles.menuItem}
|
||||
onClick={() => {
|
||||
if (item.path) {
|
||||
navigate(item.path);
|
||||
setDrawerVisible(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={styles.menuIcon}>{item.icon}</div>
|
||||
<span>{item.title}</span>
|
||||
</div>
|
||||
))}
|
||||
{menuList.map((item, index) => {
|
||||
const isActive = location.pathname === item.path;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`${styles.menuItem} ${isActive ? styles.menuItemActive : ""}`}
|
||||
onClick={() => {
|
||||
if (item.path) {
|
||||
navigate(item.path);
|
||||
setDrawerVisible(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={styles.menuIcon}>{item.icon}</div>
|
||||
<span>{item.title}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.drawerFooter}>
|
||||
@@ -113,26 +166,119 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
<span className={styles.suanliIcon}>⚡</span>
|
||||
9307.423
|
||||
</span>
|
||||
<Avatar
|
||||
size={40}
|
||||
icon={<UserOutlined />}
|
||||
src={user?.avatar}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<Dropdown
|
||||
menu={{ items: userMenuItems }}
|
||||
placement="bottomRight"
|
||||
trigger={["click"]}
|
||||
>
|
||||
<div className={styles.userSection}>
|
||||
<Avatar
|
||||
size={40}
|
||||
icon={<UserOutlined />}
|
||||
src={user?.avatar}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
</div>
|
||||
</Dropdown>
|
||||
<div className={styles.messageButton} onClick={handleMessageClick}>
|
||||
<Badge count={messageCount} size="small">
|
||||
<BellOutlined style={{ fontSize: 20 }} />
|
||||
</Badge>
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
</Header>
|
||||
|
||||
<Drawer
|
||||
title="菜单"
|
||||
placement="left"
|
||||
onClose={handleDrawerClose}
|
||||
open={drawerVisible}
|
||||
width={300}
|
||||
className={styles.drawer}
|
||||
closable={false}
|
||||
>
|
||||
{defaultDrawerContent}
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
title="通知中心"
|
||||
placement="right"
|
||||
onClose={handleMessageDrawerClose}
|
||||
open={messageDrawerVisible}
|
||||
width={400}
|
||||
className={styles.messageDrawer}
|
||||
extra={
|
||||
<Space>
|
||||
<Button type="text" size="small">
|
||||
全部已读
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<div className={styles.messageContent}>
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#87d068" }}>
|
||||
林
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>新消息</span>
|
||||
<div className={styles.messageStatus}></div>
|
||||
</div>
|
||||
<div className={styles.messageText}>
|
||||
林秀杰:关于自由主时间特惠,原价1999元,现在只需1699元
|
||||
</div>
|
||||
<div className={styles.messageTime}>
|
||||
03-05
|
||||
<Button type="link" size="small">
|
||||
回复
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#f56a00" }}>
|
||||
E
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>群提醒</span>
|
||||
<div className={styles.messageStatus}></div>
|
||||
</div>
|
||||
<div className={styles.messageText}>
|
||||
Eric在「云归营私域银行项目群」中@了您
|
||||
</div>
|
||||
<div className={styles.messageTime}>03-05</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#1890ff" }}>
|
||||
李
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>好友申请</span>
|
||||
</div>
|
||||
<div className={styles.messageText}>李翔想请求添加您为好友</div>
|
||||
<div className={styles.messageTime}>03-04</div>
|
||||
<div className={styles.messageActions}>
|
||||
<Button type="primary" size="small">
|
||||
接受
|
||||
</Button>
|
||||
<Button size="small">拒绝</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const AiTraining: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>AI模型训练</h1>
|
||||
<p>自定义AI模型训练,打造专属智能客服助手</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>AI模型训练功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AiTraining;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const AutoGreeting: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>自动打招呼</h1>
|
||||
<p>智能识别新好友,自动发送个性化欢迎消息</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>自动打招呼功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoGreeting;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const CommunicationRecord: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>沟通记录</h1>
|
||||
<p>完整记录客户沟通历史,支持多维度查询分析</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>沟通记录功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommunicationRecord;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const ContentManagement: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>内容管理</h1>
|
||||
<p>素材管理、数据词汇库、关键词自动回复</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>内容管理功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentManagement;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const CustomerManagement: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>客户好友管理</h1>
|
||||
<p>统一管理客户信息和好友关系,提升服务效率</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>客户好友管理功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomerManagement;
|
||||
119
Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx
Normal file
119
Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import React from "react";
|
||||
import {
|
||||
AimOutlined,
|
||||
SendOutlined,
|
||||
CalendarOutlined,
|
||||
TagsOutlined,
|
||||
UserOutlined,
|
||||
MessageOutlined,
|
||||
FileTextOutlined,
|
||||
RobotOutlined,
|
||||
UserAddOutlined,
|
||||
AppstoreOutlined,
|
||||
SoundOutlined,
|
||||
TeamOutlined,
|
||||
FolderOutlined,
|
||||
BarChartOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
export interface FeatureCard {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
color: string;
|
||||
path?: string;
|
||||
isNew?: boolean;
|
||||
}
|
||||
|
||||
export interface TabItem {
|
||||
key: string;
|
||||
label: string;
|
||||
icon?: React.ReactNode;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export const featureCards: FeatureCard[] = [
|
||||
{
|
||||
id: "precision-send",
|
||||
title: "精准群发",
|
||||
description: "基于客户标签和行为数据进行精准群发",
|
||||
icon: <AimOutlined />,
|
||||
color: "#ff6b35",
|
||||
path: "/pc/powerCenter/precision-send",
|
||||
},
|
||||
{
|
||||
id: "sop-send",
|
||||
title: "SOP群发",
|
||||
description: "使用触客宝SOP标准化流程进行批量消息发送",
|
||||
icon: <SendOutlined />,
|
||||
color: "#4285f4",
|
||||
path: "/pc/powerCenter/sop-send",
|
||||
},
|
||||
{
|
||||
id: "moments-marketing",
|
||||
title: "朋友圈营销",
|
||||
description: "AI智能生成朋友圈内容,提升品牌曝光度",
|
||||
icon: <CalendarOutlined />,
|
||||
color: "#34a853",
|
||||
path: "/pc/powerCenter/moments-marketing",
|
||||
},
|
||||
{
|
||||
id: "tag-management",
|
||||
title: "标签管理",
|
||||
description: "智能客户标签分类,精准用户画像分析",
|
||||
icon: <TagsOutlined />,
|
||||
color: "#9c27b0",
|
||||
path: "/pc/powerCenter/tag-management",
|
||||
},
|
||||
{
|
||||
id: "customer-management",
|
||||
title: "客户好友管理",
|
||||
description: "统一管理客户信息和好友关系,提升服务效率",
|
||||
icon: <UserOutlined />,
|
||||
color: "#6366f1",
|
||||
path: "/pc/powerCenter/customer-management",
|
||||
},
|
||||
{
|
||||
id: "communication-record",
|
||||
title: "沟通记录",
|
||||
description: "完整记录客户沟通历史,支持多维度查询分析",
|
||||
icon: <MessageOutlined />,
|
||||
color: "#06b6d4",
|
||||
path: "/pc/powerCenter/communication-record",
|
||||
},
|
||||
{
|
||||
id: "content-management",
|
||||
title: "内容管理",
|
||||
description: "素材管理、数据词汇库、关键词自动回复",
|
||||
icon: <FileTextOutlined />,
|
||||
color: "#f59e0b",
|
||||
path: "/pc/powerCenter/content-management",
|
||||
},
|
||||
{
|
||||
id: "ai-training",
|
||||
title: "AI模型训练",
|
||||
description: "自定义AI模型训练,打造专属智能客服助手",
|
||||
icon: <RobotOutlined />,
|
||||
color: "#ec4899",
|
||||
path: "/pc/powerCenter/ai-training",
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
id: "auto-greeting",
|
||||
title: "自动打招呼",
|
||||
description: "智能识别新好友,自动发送个性化欢迎消息",
|
||||
icon: <UserAddOutlined />,
|
||||
color: "#10b981",
|
||||
path: "/pc/powerCenter/auto-greeting",
|
||||
},
|
||||
];
|
||||
|
||||
export const tabItems: TabItem[] = [
|
||||
{ key: "all", label: "全部功能", icon: <AppstoreOutlined /> },
|
||||
{ key: "marketing", label: "营销推广", icon: <SoundOutlined /> },
|
||||
{ key: "customer", label: "客户管理", icon: <TeamOutlined /> },
|
||||
{ key: "ai", label: "AI智能", icon: <RobotOutlined /> },
|
||||
{ key: "content", label: "内容管理", icon: <FolderOutlined /> },
|
||||
{ key: "data", label: "数据分析", icon: <BarChartOutlined /> },
|
||||
];
|
||||
237
Touchkebao/src/pages/pc/ckbox/powerCenter/index.module.scss
Normal file
237
Touchkebao/src/pages/pc/ckbox/powerCenter/index.module.scss
Normal file
@@ -0,0 +1,237 @@
|
||||
.powerCenter {
|
||||
padding: 24px;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 32px;
|
||||
background: white;
|
||||
padding: 24px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.headerLeft {
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.headerRight {
|
||||
.tabs {
|
||||
.tab {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e0e0e0;
|
||||
color: #666;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.activeTab {
|
||||
border-radius: 8px;
|
||||
background: #1890ff;
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cardGrid {
|
||||
.featureCard {
|
||||
border-radius: 16px;
|
||||
border: none;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
height: 200px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.cardContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
|
||||
.iconWrapper {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
position: relative;
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.cardInfo {
|
||||
.cardTitle {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin: 0 0 8px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
|
||||
.newBadge {
|
||||
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.cardDescription {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 1200px) {
|
||||
.powerCenter {
|
||||
.header {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
|
||||
.headerRight {
|
||||
width: 100%;
|
||||
|
||||
.tabs {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.powerCenter {
|
||||
padding: 16px;
|
||||
|
||||
.header {
|
||||
padding: 16px;
|
||||
|
||||
.headerLeft {
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cardGrid {
|
||||
.featureCard {
|
||||
height: 160px;
|
||||
|
||||
.cardContent {
|
||||
.iconWrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.cardInfo {
|
||||
.cardTitle {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.cardDescription {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 卡片颜色主题
|
||||
.featureCard {
|
||||
// 精准群发 - 橙色
|
||||
&[data-color="#ff6b35"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #ff6b35, #f7931e);
|
||||
}
|
||||
|
||||
// SOP群发 - 蓝色
|
||||
&[data-color="#4285f4"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #4285f4, #1a73e8);
|
||||
}
|
||||
|
||||
// 朋友圈营销 - 绿色
|
||||
&[data-color="#34a853"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #34a853, #137333);
|
||||
}
|
||||
|
||||
// 标签管理 - 紫色
|
||||
&[data-color="#9c27b0"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #9c27b0, #7b1fa2);
|
||||
}
|
||||
|
||||
// 客户管理 - 靛蓝
|
||||
&[data-color="#6366f1"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #6366f1, #4f46e5);
|
||||
}
|
||||
|
||||
// 沟通记录 - 青色
|
||||
&[data-color="#06b6d4"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #06b6d4, #0891b2);
|
||||
}
|
||||
|
||||
// 内容管理 - 黄色
|
||||
&[data-color="#f59e0b"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
}
|
||||
|
||||
// AI训练 - 粉色
|
||||
&[data-color="#ec4899"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #ec4899, #db2777);
|
||||
}
|
||||
|
||||
// 自动打招呼 - 翠绿
|
||||
&[data-color="#10b981"] .iconWrapper {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
}
|
||||
}
|
||||
103
Touchkebao/src/pages/pc/ckbox/powerCenter/index.tsx
Normal file
103
Touchkebao/src/pages/pc/ckbox/powerCenter/index.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React, { useState, useMemo } from "react";
|
||||
import { Card, Row, Col, Button, Space } from "antd";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { featureCards, tabItems, FeatureCard } from "./index.data";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const PowerCenter: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [activeTab, setActiveTab] = useState("all");
|
||||
|
||||
const handleCardClick = (card: FeatureCard) => {
|
||||
if (card.path) {
|
||||
navigate(card.path);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabClick = (tabKey: string) => {
|
||||
setActiveTab(tabKey);
|
||||
};
|
||||
|
||||
// 根据选中的标签过滤功能卡片
|
||||
const filteredCards = useMemo(() => {
|
||||
if (activeTab === "all") {
|
||||
return featureCards;
|
||||
}
|
||||
|
||||
const categoryMap: { [key: string]: string[] } = {
|
||||
marketing: ["precision-send", "sop-send", "moments-marketing"],
|
||||
customer: ["customer-management", "tag-management"],
|
||||
ai: ["ai-training", "auto-greeting"],
|
||||
content: ["content-management"],
|
||||
data: ["communication-record"],
|
||||
};
|
||||
|
||||
const categoryIds = categoryMap[activeTab] || [];
|
||||
return featureCards.filter(card => categoryIds.includes(card.id));
|
||||
}, [activeTab]);
|
||||
|
||||
return (
|
||||
<div className={styles.powerCenter}>
|
||||
{/* 页面头部 */}
|
||||
<div className={styles.header}>
|
||||
<div className={styles.headerLeft}>
|
||||
<h1 className={styles.title}>功能中心</h1>
|
||||
<p className={styles.subtitle}>触客宝AI私域营销系统 - 所有功能一览</p>
|
||||
</div>
|
||||
<div className={styles.headerRight}>
|
||||
<Space className={styles.tabs}>
|
||||
{tabItems.map(item => (
|
||||
<Button
|
||||
key={item.key}
|
||||
type={activeTab === item.key ? "primary" : "text"}
|
||||
className={
|
||||
activeTab === item.key ? styles.activeTab : styles.tab
|
||||
}
|
||||
onClick={() => handleTabClick(item.key)}
|
||||
icon={item.icon}
|
||||
>
|
||||
{item.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 功能卡片网格 */}
|
||||
<div className={styles.cardGrid}>
|
||||
<Row gutter={[24, 24]}>
|
||||
{filteredCards.map(card => (
|
||||
<Col key={card.id} xs={24} sm={12} md={8} lg={6} xl={6}>
|
||||
<Card
|
||||
className={styles.featureCard}
|
||||
hoverable
|
||||
onClick={() => handleCardClick(card)}
|
||||
bodyStyle={{ padding: "24px" }}
|
||||
>
|
||||
<div className={styles.cardContent}>
|
||||
<div
|
||||
className={styles.iconWrapper}
|
||||
style={{ backgroundColor: card.color }}
|
||||
>
|
||||
<div className={styles.icon}>{card.icon}</div>
|
||||
</div>
|
||||
<div className={styles.cardInfo}>
|
||||
<h3 className={styles.cardTitle}>
|
||||
{card.title}
|
||||
{card.isNew && (
|
||||
<span className={styles.newBadge}>新功能</span>
|
||||
)}
|
||||
</h3>
|
||||
<p className={styles.cardDescription}>{card.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PowerCenter;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const MomentsMarketing: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>朋友圈营销</h1>
|
||||
<p>AI智能生成朋友圈内容,提升品牌曝光度</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>朋友圈营销功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MomentsMarketing;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const PrecisionSend: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>精准群发</h1>
|
||||
<p>基于客户标签和行为数据进行精准群发</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>精准群发功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrecisionSend;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
21
Touchkebao/src/pages/pc/ckbox/powerCenter/sop-send/index.tsx
Normal file
21
Touchkebao/src/pages/pc/ckbox/powerCenter/sop-send/index.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const SopSend: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>SOP群发</h1>
|
||||
<p>使用触客宝SOP标准化流程进行批量消息发送</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>SOP群发功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SopSend;
|
||||
@@ -0,0 +1,43 @@
|
||||
.container {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const TagManagement: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<h1>标签管理</h1>
|
||||
<p>智能客户标签分类,精准用户画像分析</p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{/* 功能内容待开发 */}
|
||||
<div className={styles.placeholder}>
|
||||
<p>标签管理功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TagManagement;
|
||||
@@ -26,26 +26,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({ contract }) => {
|
||||
const onToggleProfile = () => {
|
||||
setShowProfile(!showProfile);
|
||||
};
|
||||
const chatMenu = (
|
||||
<Menu>
|
||||
<Menu.Item key="profile" icon={<UserOutlined />}>
|
||||
查看资料
|
||||
</Menu.Item>
|
||||
<Menu.Item key="call" icon={<PhoneOutlined />}>
|
||||
语音通话
|
||||
</Menu.Item>
|
||||
<Menu.Item key="video" icon={<VideoCameraOutlined />}>
|
||||
视频通话
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Item key="pin">置顶聊天</Menu.Item>
|
||||
<Menu.Item key="mute">消息免打扰</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Item key="clear" danger>
|
||||
清空聊天记录
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<Layout className={styles.chatWindow}>
|
||||
@@ -76,13 +56,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({ contract }) => {
|
||||
className={styles.headerButton}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Dropdown overlay={chatMenu} trigger={["click"]}>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<MoreOutlined />}
|
||||
className={styles.headerButton}
|
||||
/>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Header>
|
||||
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import CkboxPage from "@/pages/pc/ckbox";
|
||||
import WeChatPage from "@/pages/pc/ckbox/weChat";
|
||||
import Dashboard from "@/pages/pc/ckbox/dashboard";
|
||||
|
||||
import PowerCenter from "@/pages/pc/ckbox/powerCenter";
|
||||
import PrecisionSend from "@/pages/pc/ckbox/powerCenter/precision-send";
|
||||
import SopSend from "@/pages/pc/ckbox/powerCenter/sop-send";
|
||||
import MomentsMarketing from "@/pages/pc/ckbox/powerCenter/moments-marketing";
|
||||
import TagManagement from "@/pages/pc/ckbox/powerCenter/tag-management";
|
||||
import CustomerManagement from "@/pages/pc/ckbox/powerCenter/customer-management";
|
||||
import CommunicationRecord from "@/pages/pc/ckbox/powerCenter/communication-record";
|
||||
import ContentManagement from "@/pages/pc/ckbox/powerCenter/content-management";
|
||||
import AiTraining from "@/pages/pc/ckbox/powerCenter/ai-training";
|
||||
import AutoGreeting from "@/pages/pc/ckbox/powerCenter/auto-greeting";
|
||||
const ckboxRoutes = [
|
||||
{
|
||||
path: "/pc",
|
||||
@@ -16,6 +25,46 @@ const ckboxRoutes = [
|
||||
path: "weChat",
|
||||
element: <WeChatPage />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter",
|
||||
element: <PowerCenter />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/precision-send",
|
||||
element: <PrecisionSend />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/sop-send",
|
||||
element: <SopSend />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/moments-marketing",
|
||||
element: <MomentsMarketing />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/tag-management",
|
||||
element: <TagManagement />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/customer-management",
|
||||
element: <CustomerManagement />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/communication-record",
|
||||
element: <CommunicationRecord />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/content-management",
|
||||
element: <ContentManagement />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/ai-training",
|
||||
element: <AiTraining />,
|
||||
},
|
||||
{
|
||||
path: "powerCenter/auto-greeting",
|
||||
element: <AutoGreeting />,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -16,7 +16,6 @@ export interface User {
|
||||
updateTime: string | null;
|
||||
lastLoginIp: string;
|
||||
lastLoginTime: number;
|
||||
deviceTotal: number; // 设备总数
|
||||
}
|
||||
|
||||
interface UserState {
|
||||
@@ -28,7 +27,7 @@ interface UserState {
|
||||
setToken: (token: string) => void;
|
||||
setToken2: (token2: string) => void;
|
||||
clearUser: () => void;
|
||||
login: (token: string, userInfo: User, deviceTotal: number) => void;
|
||||
login: (token: string, userInfo: User) => void;
|
||||
login2: (token2: string) => void;
|
||||
logout: () => void;
|
||||
}
|
||||
@@ -44,7 +43,7 @@ export const useUserStore = createPersistStore<UserState>(
|
||||
setToken2: token2 => set({ token2 }),
|
||||
clearUser: () =>
|
||||
set({ user: null, token: null, token2: null, isLoggedIn: false }),
|
||||
login: (token, userInfo, deviceTotal) => {
|
||||
login: (token, userInfo) => {
|
||||
// 只将token存储到localStorage
|
||||
localStorage.setItem("token", token);
|
||||
|
||||
@@ -64,7 +63,6 @@ export const useUserStore = createPersistStore<UserState>(
|
||||
updateTime: userInfo.updateTime,
|
||||
lastLoginIp: userInfo.lastLoginIp,
|
||||
lastLoginTime: userInfo.lastLoginTime,
|
||||
deviceTotal: deviceTotal,
|
||||
};
|
||||
set({ user, token, isLoggedIn: true });
|
||||
|
||||
|
||||
7
Touchkebao/src/utils/icon.tsx
Normal file
7
Touchkebao/src/utils/icon.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createFromIconfontCN } from "@ant-design/icons";
|
||||
|
||||
const IconFont = createFromIconfontCN({
|
||||
scriptUrl: "//at.alicdn.com/t/c/font_4272168_343o7l1hnhb.js",
|
||||
});
|
||||
|
||||
export default IconFont;
|
||||
Reference in New Issue
Block a user