diff --git a/Cunkebao/src/pages/pc/ckbox/api.ts b/Cunkebao/src/pages/pc/ckbox/api.ts deleted file mode 100644 index 98bc336a..00000000 --- a/Cunkebao/src/pages/pc/ckbox/api.ts +++ /dev/null @@ -1,246 +0,0 @@ -import request from "@/api/request2"; -import { - MessageData, - ChatHistoryResponse, - MessageType, - OnlineStatus, - MessageStatus, - FileUploadResponse, - EmojiData, - QuickReply, - ChatSettings, -} from "./data"; - -//读取聊天信息 -//kf.quwanzhi.com:9991/api/WechatFriend/clearUnreadCount - -export function WechatGroup(params) { - return request("/api/WechatGroup/list", params, "GET"); -} - -//获取聊天记录-1 清除未读 -export function clearUnreadCount(params) { - return request("/api/WechatFriend/clearUnreadCount", params, "PUT"); -} - -//更新配置 -export function updateConfig(params) { - return request("/api/WechatFriend/updateConfig", params, "PUT"); -} -//获取聊天记录-2 获取列表 -export function getChatMessages(params: { - wechatAccountId: number; - wechatFriendId?: number; - wechatChatroomId?: number; - From: number; - To: number; - Count: number; - olderData: boolean; -}) { - return request("/api/FriendMessage/SearchMessage", params, "GET"); -} -export function getChatroomMessages(params: { - wechatAccountId: number; - wechatFriendId?: number; - wechatChatroomId?: number; - From: number; - To: number; - Count: number; - olderData: boolean; -}) { - return request("/api/ChatroomMessage/SearchMessage", params, "GET"); -} - -//获取群列表 -export function getGroupList(params: { prevId: number; count: number }) { - return request( - "/api/wechatChatroom/listExcludeMembersByPage?", - params, - "GET", - ); -} - -//获取群成员 -export function getGroupMembers(params: { id: number }) { - return request( - "/api/WechatChatroom/listMembersByWechatChatroomId", - params, - "GET", - ); -} - -//触客宝登陆 -export function loginWithToken(params: any) { - return request( - "/token", - params, - "POST", - { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }, - 1000, - ); -} - -// 获取触客宝用户信息 -export function getChuKeBaoUserInfo() { - return request("/api/account/self", {}, "GET"); -} - -// 获取联系人列表 -export const getContactList = (params: { prevId: number; count: number }) => { - return request("/api/wechatFriend/list", params, "GET"); -}; - -//获取控制终端列表 -export const getControlTerminalList = params => { - return request("/api/wechataccount", params, "GET"); -}; - -// 获取聊天历史 -export const getChatHistory = ( - chatId: string, - page: number = 1, - pageSize: number = 50, -): Promise => { - return request(`/v1/chats/${chatId}/messages`, { page, pageSize }, "GET"); -}; - -// 发送消息 -export const sendMessage = ( - chatId: string, - content: string, - type: MessageType = MessageType.TEXT, -): Promise => { - return request(`/v1/chats/${chatId}/messages`, { content, type }, "POST"); -}; - -// 发送文件消息 -export const sendFileMessage = ( - chatId: string, - file: File, - type: MessageType, -): Promise => { - const formData = new FormData(); - formData.append("file", file); - formData.append("type", type); - return request(`/v1/chats/${chatId}/messages/file`, formData, "POST"); -}; - -// 标记消息为已读 -export const markMessageAsRead = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/read`, {}, "PUT"); -}; - -// 标记聊天为已读 -export const markChatAsRead = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/read`, {}, "PUT"); -}; - -// 添加群组成员 -export const addGroupMembers = ( - groupId: string, - memberIds: string[], -): Promise => { - return request(`/v1/groups/${groupId}/members`, { memberIds }, "POST"); -}; - -// 移除群组成员 -export const removeGroupMembers = ( - groupId: string, - memberIds: string[], -): Promise => { - return request(`/v1/groups/${groupId}/members`, { memberIds }, "DELETE"); -}; - -// 获取在线状态 -export const getOnlineStatus = (userId: string): Promise => { - return request(`/v1/users/${userId}/status`, {}, "GET"); -}; - -// 获取消息状态 -export const getMessageStatus = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/status`, {}, "GET"); -}; - -// 上传文件 -export const uploadFile = (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - return request("/v1/upload", formData, "POST"); -}; - -// 获取表情包列表 -export const getEmojiList = (): Promise => { - return request("/v1/emojis", {}, "GET"); -}; - -// 获取快捷回复列表 -export const getQuickReplies = (): Promise => { - return request("/v1/quick-replies", {}, "GET"); -}; - -// 添加快捷回复 -export const addQuickReply = (data: { - content: string; - category: string; -}): Promise => { - return request("/v1/quick-replies", data, "POST"); -}; - -// 删除快捷回复 -export const deleteQuickReply = (id: string): Promise => { - return request(`/v1/quick-replies/${id}`, {}, "DELETE"); -}; - -// 获取聊天设置 -export const getChatSettings = (): Promise => { - return request("/v1/chat/settings", {}, "GET"); -}; - -// 更新聊天设置 -export const updateChatSettings = ( - settings: Partial, -): Promise => { - return request("/v1/chat/settings", settings, "PUT"); -}; - -// 删除聊天会话 -export const deleteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}`, {}, "DELETE"); -}; - -// 置顶聊天会话 -export const pinChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/pin`, {}, "PUT"); -}; - -// 取消置顶聊天会话 -export const unpinChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/unpin`, {}, "PUT"); -}; - -// 静音聊天会话 -export const muteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/mute`, {}, "PUT"); -}; - -// 取消静音聊天会话 -export const unmuteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/unmute`, {}, "PUT"); -}; - -// 转发消息 -export const forwardMessage = ( - messageId: string, - targetChatIds: string[], -): Promise => { - return request("/v1/messages/forward", { messageId, targetChatIds }, "POST"); -}; - -// 撤回消息 -export const recallMessage = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/recall`, {}, "PUT"); -}; diff --git a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.data.ts b/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.data.ts deleted file mode 100644 index f42e11af..00000000 --- a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.data.ts +++ /dev/null @@ -1,44 +0,0 @@ -// 菜单项接口 -export interface MenuItem { - id: string; - title: string; - icon: string; - path?: string; -} - -// 菜单列表数据 -export const menuList: MenuItem[] = [ - { - id: "dashboard", - title: "数据面板", - icon: "📊", - path: "/ckbox/dashboard", - }, - { - id: "wechat", - title: "微信管理", - icon: "💬", - path: "/ckbox/weChat", - }, -]; - -// 抽屉菜单配置数据 -export const drawerMenuData = { - header: { - logoIcon: "✨", - appName: "触客宝", - appDesc: "AI智能营销系统", - }, - primaryButton: { - title: "AI智能客服", - icon: "🔒", - }, - footer: { - balanceIcon: "⚡", - balanceLabel: "算力余额", - balanceValue: "9307.423", - }, -}; - -// 导出默认配置 -export default drawerMenuData; diff --git a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.module.scss b/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.module.scss deleted file mode 100644 index 6bf58b79..00000000 --- a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.module.scss +++ /dev/null @@ -1,316 +0,0 @@ -.header { - background: #fff; - padding: 0 16px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - display: flex; - align-items: center; - justify-content: space-between; - height: 64px; - border-bottom: 1px solid #f0f0f0; -} - -.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; - - &:hover { - background-color: #f5f5f5; - } - - .anticon { - font-size: 18px; - color: #666; - } -} - -.title { - font-size: 18px; - color: #333; - margin: 0; -} - -.headerRight { - display: flex; - align-items: center; - gap: 16px; -} - -.userInfo { - display: flex; - align-items: center; - gap: 16px; - padding: 8px 0; - - .suanli { - 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: 16px; - color: #ffc107; - } - } -} - -.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 { - font-size: 14px; - color: #333; - font-weight: 500; - margin-left: 8px; -} - -// 抽屉样式 -.drawer { - :global(.ant-drawer-header) { - background: #fafafa; - border-bottom: 1px solid #f0f0f0; - } - - :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 { - display: flex; - justify-content: space-between; - align-items: center; - .balanceIcon { - color: #666; - .suanliIcon { - font-size: 20px; - } - } - - .balanceText { - color: #3d9c0d; - } - } -} - -.balanceLabel { - font-size: 12px; - color: #999; - margin: 0; -} - -.balanceAmount { - font-size: 18px; - font-weight: 600; - 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; - } -} diff --git a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx deleted file mode 100644 index 500099fa..00000000 --- a/Cunkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React, { useState } from "react"; -import { Layout, Drawer, Avatar, Dropdown, Space, Button } from "antd"; -import { - MenuOutlined, - UserOutlined, - LogoutOutlined, - SettingOutlined, -} from "@ant-design/icons"; -import type { MenuProps } from "antd"; -import { useCkChatStore } from "@/store/module/ckchat/ckchat"; -import { useNavigate } from "react-router-dom"; -import { drawerMenuData, menuList } from "./index.data"; -import styles from "./index.module.scss"; - -const { Header } = Layout; - -interface NavCommonProps { - title?: string; - onMenuClick?: () => void; -} - -const NavCommon: React.FC = ({ - title = "触客宝", - onMenuClick, -}) => { - const [drawerVisible, setDrawerVisible] = useState(false); - const navigate = useNavigate(); - const { userInfo } = useCkChatStore(); - - // 处理菜单图标点击 - const handleMenuClick = () => { - setDrawerVisible(true); - onMenuClick?.(); - }; - - // 处理抽屉关闭 - const handleDrawerClose = () => { - setDrawerVisible(false); - }; - - // 默认抽屉内容 - const defaultDrawerContent = ( -
-
-
-
- {drawerMenuData.header.logoIcon} -
-
-
- {drawerMenuData.header.appName} -
-
- {drawerMenuData.header.appDesc} -
-
-
-
-
-
-
- {drawerMenuData.primaryButton.icon} -
- {drawerMenuData.primaryButton.title} -
-
- {menuList.map((item, index) => ( -
{ - if (item.path) { - navigate(item.path); - setDrawerVisible(false); - } - }} - > -
{item.icon}
- {item.title} -
- ))} -
-
-
-
-
- - {drawerMenuData.footer.balanceIcon} - - {drawerMenuData.footer.balanceLabel} -
-
- {drawerMenuData.footer.balanceValue} -
-
-
-
- ); - - return ( - <> -
-
-
- -
- - - - 9307.423 - - } - src={userInfo?.account?.avatar} - className={styles.avatar} - /> - -
-
- - - {defaultDrawerContent} - - - ); -}; - -export default NavCommon; diff --git a/Cunkebao/src/pages/pc/ckbox/dashboard/index.module.scss b/Cunkebao/src/pages/pc/ckbox/dashboard/index.module.scss deleted file mode 100644 index 96fdbab6..00000000 --- a/Cunkebao/src/pages/pc/ckbox/dashboard/index.module.scss +++ /dev/null @@ -1,193 +0,0 @@ -.monitoring { - padding: 24px; - background-color: #f5f5f5; - min-height: 100vh; - - .header { - margin-bottom: 24px; - - h2 { - margin: 0 0 8px 0; - color: #262626; - font-size: 24px; - font-weight: 600; - } - - p { - margin: 0; - color: #8c8c8c; - font-size: 14px; - } - } - - .statsRow { - margin-bottom: 24px; - - .statCard { - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - transition: all 0.3s ease; - - &:hover { - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); - transform: translateY(-2px); - } - } - } - - .progressRow { - margin-bottom: 24px; - - .progressCard, - .metricsCard { - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - height: 280px; - - .ant-card-body { - height: calc(100% - 57px); - display: flex; - flex-direction: column; - justify-content: space-between; - } - } - - .progressItem { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - - span { - display: block; - margin-bottom: 8px; - color: #595959; - font-size: 14px; - } - } - - .metricItem { - display: flex; - justify-content: space-between; - align-items: center; - padding: 16px 0; - border-bottom: 1px solid #f0f0f0; - - &:last-child { - border-bottom: none; - } - - span { - color: #595959; - font-size: 14px; - } - - .metricValue { - display: flex; - align-items: center; - gap: 8px; - - span { - font-weight: 600; - font-size: 16px; - color: #262626; - } - } - } - } - - .chartsRow { - margin-top: 24px; - } - - .chartCard { - .ant-card-head { - background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); - color: white; - - .ant-card-head-title { - color: white; - font-weight: 600; - } - } - - .ant-card-body { - padding: 20px; - } - - // 图表容器样式 - .g2-tooltip { - background: rgba(0, 0, 0, 0.8); - border-radius: 6px; - color: white; - } - } - - .tableRow { - margin-top: 24px; - } - - .tableCard { - .ant-card-head { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - - .ant-card-head-title { - color: white; - } - } - } - - .tableCard { - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - - .ant-table { - .ant-table-thead > tr > th { - background-color: #fafafa; - border-bottom: 1px solid #f0f0f0; - font-weight: 600; - } - - .ant-table-tbody > tr { - &:hover { - background-color: #f5f5f5; - } - } - } - } -} - -// 响应式设计 -@media (max-width: 768px) { - .monitoring { - padding: 16px; - - .header { - h2 { - font-size: 20px; - } - } - - .progressRow { - .progressCard, - .metricsCard { - height: auto; - margin-bottom: 16px; - } - } - } -} - -@media (max-width: 576px) { - .monitoring { - padding: 12px; - - .statsRow { - .statCard { - margin-bottom: 12px; - } - } - } -} \ No newline at end of file diff --git a/Cunkebao/src/pages/pc/ckbox/dashboard/index.tsx b/Cunkebao/src/pages/pc/ckbox/dashboard/index.tsx deleted file mode 100644 index b6f0c923..00000000 --- a/Cunkebao/src/pages/pc/ckbox/dashboard/index.tsx +++ /dev/null @@ -1,476 +0,0 @@ -import React from "react"; -import { Card, Row, Col, Statistic, Progress, Table, Tag } from "antd"; -import { - UserOutlined, - MessageOutlined, - TeamOutlined, - TrophyOutlined, - ArrowUpOutlined, - ArrowDownOutlined, -} from "@ant-design/icons"; -import * as echarts from "echarts"; -import ReactECharts from "echarts-for-react"; -import styles from "./index.module.scss"; - -interface DashboardProps { - // 预留接口属性 -} - -const Dashboard: React.FC = () => { - // 模拟数据 - const statsData = [ - { - title: "在线设备数", - value: 128, - prefix: , - suffix: "台", - valueStyle: { color: "#3f8600" }, - }, - { - title: "今日消息量", - value: 2456, - prefix: , - suffix: "条", - valueStyle: { color: "#1890ff" }, - }, - { - title: "活跃群组", - value: 89, - prefix: , - suffix: "个", - valueStyle: { color: "#722ed1" }, - }, - { - title: "成功率", - value: 98.5, - prefix: , - suffix: "%", - valueStyle: { color: "#f5222d" }, - }, - ]; - - const tableColumns = [ - { - title: "设备名称", - dataIndex: "deviceName", - key: "deviceName", - }, - { - title: "状态", - dataIndex: "status", - key: "status", - render: (status: string) => ( - {status} - ), - }, - { - title: "消息数", - dataIndex: "messageCount", - key: "messageCount", - }, - { - title: "最后活跃时间", - dataIndex: "lastActive", - key: "lastActive", - }, - ]; - - const tableData = [ - { - key: "1", - deviceName: "设备001", - status: "在线", - messageCount: 245, - lastActive: "2024-01-15 14:30:25", - }, - { - key: "2", - deviceName: "设备002", - status: "离线", - messageCount: 156, - lastActive: "2024-01-15 12:15:10", - }, - { - key: "3", - deviceName: "设备003", - status: "在线", - messageCount: 389, - lastActive: "2024-01-15 14:28:45", - }, - ]; - - // 图表数据 - const lineData = [ - { time: "00:00", value: 120 }, - { time: "02:00", value: 132 }, - { time: "04:00", value: 101 }, - { time: "06:00", value: 134 }, - { time: "08:00", value: 190 }, - { time: "10:00", value: 230 }, - { time: "12:00", value: 210 }, - { time: "14:00", value: 220 }, - { time: "16:00", value: 165 }, - { time: "18:00", value: 127 }, - { time: "20:00", value: 82 }, - { time: "22:00", value: 91 }, - ]; - - const columnData = [ - { type: "消息发送", value: 27 }, - { type: "消息接收", value: 25 }, - { type: "群组管理", value: 18 }, - { type: "设备监控", value: 15 }, - { type: "数据同步", value: 10 }, - { type: "其他", value: 5 }, - ]; - - const pieData = [ - { type: "在线设备", value: 128 }, - { type: "离线设备", value: 32 }, - { type: "维护中", value: 8 }, - ]; - - const areaData = [ - { time: "1月", value: 3000 }, - { time: "2月", value: 4000 }, - { time: "3月", value: 3500 }, - { time: "4月", value: 5000 }, - { time: "5月", value: 4900 }, - { time: "6月", value: 6000 }, - ]; - - // ECharts配置 - const lineOption = { - title: { - text: "24小时消息趋势", - left: "center", - textStyle: { - color: "#333", - fontSize: 16, - }, - }, - tooltip: { - trigger: "axis", - backgroundColor: "rgba(0,0,0,0.8)", - textStyle: { - color: "#fff", - }, - }, - grid: { - left: "3%", - right: "4%", - bottom: "3%", - containLabel: true, - }, - xAxis: { - type: "category", - data: lineData.map(item => item.time), - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - yAxis: { - type: "value", - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - series: [ - { - data: lineData.map(item => item.value), - type: "line", - smooth: true, - lineStyle: { - color: "#1890ff", - width: 3, - }, - itemStyle: { - color: "#1890ff", - }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: "rgba(24, 144, 255, 0.3)" }, - { offset: 1, color: "rgba(24, 144, 255, 0.1)" }, - ]), - }, - }, - ], - }; - - const columnOption = { - title: { - text: "功能使用分布", - left: "center", - textStyle: { - color: "#333", - fontSize: 16, - }, - }, - tooltip: { - trigger: "axis", - backgroundColor: "rgba(0,0,0,0.8)", - textStyle: { - color: "#fff", - }, - }, - grid: { - left: "3%", - right: "4%", - bottom: "3%", - containLabel: true, - }, - xAxis: { - type: "category", - data: columnData.map(item => item.type), - axisLabel: { - rotate: 45, - }, - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - yAxis: { - type: "value", - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - series: [ - { - data: columnData.map(item => item.value), - type: "bar", - itemStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: "#52c41a" }, - { offset: 1, color: "#389e0d" }, - ]), - }, - }, - ], - }; - - const pieOption = { - title: { - text: "设备状态分布", - left: "center", - textStyle: { - color: "#333", - fontSize: 16, - }, - }, - tooltip: { - trigger: "item", - backgroundColor: "rgba(0,0,0,0.8)", - textStyle: { - color: "#fff", - }, - }, - legend: { - orient: "vertical", - left: "left", - }, - series: [ - { - name: "设备状态", - type: "pie", - radius: "50%", - data: pieData.map(item => ({ name: item.type, value: item.value })), - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: "rgba(0, 0, 0, 0.5)", - }, - }, - itemStyle: { - borderRadius: 5, - borderColor: "#fff", - borderWidth: 2, - }, - }, - ], - }; - - const areaOption = { - title: { - text: "月度数据趋势", - left: "center", - textStyle: { - color: "#333", - fontSize: 16, - }, - }, - tooltip: { - trigger: "axis", - backgroundColor: "rgba(0,0,0,0.8)", - textStyle: { - color: "#fff", - }, - }, - grid: { - left: "3%", - right: "4%", - bottom: "3%", - containLabel: true, - }, - xAxis: { - type: "category", - data: areaData.map(item => item.time), - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - yAxis: { - type: "value", - axisLine: { - lineStyle: { - color: "#ccc", - }, - }, - }, - series: [ - { - data: areaData.map(item => item.value), - type: "line", - smooth: true, - lineStyle: { - color: "#722ed1", - width: 3, - }, - itemStyle: { - color: "#722ed1", - }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: "rgba(114, 46, 209, 0.6)" }, - { offset: 1, color: "rgba(114, 46, 209, 0.1)" }, - ]), - }, - }, - ], - }; - - return ( -
-
-

数据监控看板

-

实时监控系统运行状态和数据指标

-
- - {/* 统计卡片 */} - - {statsData.map((stat, index) => ( - - - - - - ))} - - - {/* 进度指标 */} - - - -
- CPU使用率 - -
-
- 内存使用率 - -
-
- 磁盘使用率 - -
-
- - - -
- 消息处理速度 -
- 1,245 - -
-
-
- 错误率 -
- 0.2% - -
-
-
- 响应时间 -
- 125ms - -
-
-
- -
- - {/* 图表区域 */} - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* 设备状态表格 */} - - - - - - - - - ); -}; - -export default Dashboard; diff --git a/Cunkebao/src/pages/pc/ckbox/data.ts b/Cunkebao/src/pages/pc/ckbox/data.ts deleted file mode 100644 index 0444a312..00000000 --- a/Cunkebao/src/pages/pc/ckbox/data.ts +++ /dev/null @@ -1,323 +0,0 @@ -// 消息列表数据接口 - 支持weChatGroup和contracts两种数据类型 -export interface MessageListData { - serverId: number | string; // 服务器ID作为主键 - id?: number; // 接口数据的原始ID字段 - - // 数据类型标识 - dataType: "weChatGroup" | "contracts"; // 数据类型:微信群组或联系人 - - // 通用字段(两种类型都有的字段) - wechatAccountId: number; // 微信账号ID - tenantId: number; // 租户ID - accountId: number; // 账号ID - nickname: string; // 昵称 - avatar?: string; // 头像 - groupId: number; // 分组ID - config?: { - chat: boolean; - }; // 配置信息 - labels?: string[]; // 标签列表 - unreadCount: number; // 未读消息数 - - // 联系人特有字段(当dataType为'contracts'时使用) - wechatId?: string; // 微信ID - alias?: string; // 别名 - conRemark?: string; // 备注 - quanPin?: string; // 全拼 - gender?: number; // 性别 - region?: string; // 地区 - addFrom?: number; // 添加来源 - phone?: string; // 电话 - signature?: string; // 签名 - extendFields?: any; // 扩展字段 - city?: string; // 城市 - lastUpdateTime?: string; // 最后更新时间 - isPassed?: boolean; // 是否通过 - thirdParty?: any; // 第三方 - additionalPicture?: string; // 附加图片 - desc?: string; // 描述 - lastMessageTime?: number; // 最后消息时间 - duplicate?: boolean; // 是否重复 - - // 微信群组特有字段(当dataType为'weChatGroup'时使用) - chatroomId?: string; // 群聊ID - chatroomOwner?: string; // 群主 - chatroomAvatar?: string; // 群头像 - notice?: string; // 群公告 - selfDisplyName?: string; // 自己在群里的显示名称 - - [key: string]: any; // 兼容其他字段 -} - -//联系人标签分组 -export interface ContactGroupByLabel { - id: number; - accountId?: number; - groupName: string; - tenantId?: number; - count: number; - [key: string]: any; -} -//终端用户数据接口 -export interface KfUserListData { - id: number; - tenantId: number; - wechatId: string; - nickname: string; - alias: string; - avatar: string; - gender: number; - region: string; - signature: string; - bindQQ: string; - bindEmail: string; - bindMobile: string; - createTime: string; - currentDeviceId: number; - isDeleted: boolean; - deleteTime: string; - groupId: number; - memo: string; - wechatVersion: string; - labels: string[]; - lastUpdateTime: string; - isOnline?: boolean; - [key: string]: any; -} - -// 账户信息接口 -export interface CkAccount { - id: number; - realName: string; - nickname: string | null; - memo: string | null; - avatar: string; - userName: string; - secret: string; - accountType: number; - departmentId: number; - useGoogleSecretKey: boolean; - hasVerifyGoogleSecret: boolean; -} - -//群聊数据接口 -export interface weChatGroup { - id?: number; - wechatAccountId: number; - tenantId: number; - accountId: number; - chatroomId: string; - chatroomOwner: string; - conRemark: string; - nickname: string; - chatroomAvatar: string; - groupId: number; - config?: { - chat: boolean; - }; - labels?: string[]; - unreadCount: number; - notice: string; - selfDisplyName: string; - wechatChatroomId: number; - serverId?: number; - [key: string]: any; -} - -// 联系人数据接口 -export interface ContractData { - id?: number; - serverId?: number; - wechatAccountId: number; - wechatId: string; - alias: string; - conRemark: string; - nickname: string; - quanPin: string; - avatar?: string; - gender: number; - region: string; - addFrom: number; - phone: string; - labels: string[]; - signature: string; - accountId: number; - extendFields: null; - city?: string; - lastUpdateTime: string; - isPassed: boolean; - tenantId: number; - groupId: number; - thirdParty: null; - additionalPicture: string; - desc: string; - config?: { - chat: boolean; - }; - lastMessageTime: number; - unreadCount: number; - duplicate: boolean; - [key: string]: any; -} - -//聊天记录接口 -export interface ChatRecord { - id: number; - wechatFriendId: number; - wechatAccountId: number; - tenantId: number; - accountId: number; - synergyAccountId: number; - content: string; - msgType: number; - msgSubType: number; - msgSvrId: string; - isSend: boolean; - createTime: string; - isDeleted: boolean; - deleteTime: string; - sendStatus: number; - wechatTime: number; - origin: number; - msgId: number; - recalled: boolean; - sender?: { - chatroomNickname: string; - isAdmin: boolean; - isDeleted: boolean; - nickname: string; - ownerWechatId: string; - wechatId: string; - [key: string]: any; - }; - [key: string]: any; -} - -/** - * 微信好友基本信息接口 - * 包含主要字段和兼容性字段 - */ -export interface WechatFriend { - // 主要字段 - id: number; // 好友ID - wechatAccountId: number; // 微信账号ID - wechatId: string; // 微信ID - nickname: string; // 昵称 - conRemark: string; // 备注名 - avatar: string; // 头像URL - gender: number; // 性别:1-男,2-女,0-未知 - region: string; // 地区 - phone: string; // 电话 - labels: string[]; // 标签列表 - [key: string]: any; -} - -// 消息类型枚举 -export enum MessageType { - TEXT = "text", - IMAGE = "image", - VOICE = "voice", - VIDEO = "video", - FILE = "file", - LOCATION = "location", -} - -// 消息数据接口 -export interface MessageData { - id: string; - senderId: string; - senderName: string; - content: string; - type: MessageType; - timestamp: string; - isRead: boolean; - replyTo?: string; - forwardFrom?: string; -} - -// 聊天会话类型 -export type ChatType = "private" | "group"; - -// 聊天会话接口 -export interface ChatSession { - id: string; - type: ChatType; - name: string; - avatar?: string; - lastMessage: string; - lastTime: string; - unreadCount: number; - online: boolean; - members?: string[]; - pinned?: boolean; - muted?: boolean; -} - -// 聊天历史响应接口 -export interface ChatHistoryResponse { - messages: MessageData[]; - hasMore: boolean; - total: number; -} - -// 发送消息请求接口 -export interface SendMessageRequest { - chatId: string; - content: string; - type: MessageType; - replyTo?: string; -} - -// 搜索联系人请求接口 -export interface SearchContactRequest { - keyword: string; - limit?: number; -} - -// 在线状态接口 -export interface OnlineStatus { - userId: string; - online: boolean; - lastSeen: string; -} - -// 消息状态接口 -export interface MessageStatus { - messageId: string; - status: "sending" | "sent" | "delivered" | "read" | "failed"; - timestamp: string; -} - -// 文件上传响应接口 -export interface FileUploadResponse { - url: string; - filename: string; - size: number; - type: string; -} - -// 表情包接口 -export interface EmojiData { - id: string; - name: string; - url: string; - category: string; -} - -// 快捷回复接口 -export interface QuickReply { - id: string; - content: string; - category: string; - useCount: number; -} - -// 聊天设置接口 -export interface ChatSettings { - autoReply: boolean; - autoReplyMessage: string; - notification: boolean; - sound: boolean; - theme: "light" | "dark"; - fontSize: "small" | "medium" | "large"; -} diff --git a/Cunkebao/src/pages/pc/ckbox/index.module.scss b/Cunkebao/src/pages/pc/ckbox/index.module.scss deleted file mode 100644 index 9b37437e..00000000 --- a/Cunkebao/src/pages/pc/ckbox/index.module.scss +++ /dev/null @@ -1,198 +0,0 @@ -.ckboxLayout { - height: 100vh; - background: #fff; - display: flex; - flex-direction: column; - - .header { - background: #1890ff; - color: #fff; - height: 64px; - line-height: 64px; - padding: 0 24px; - font-size: 18px; - font-weight: bold; - } - - .verticalSider { - background: #2e2e2e; - border-right: 1px solid #f0f0f0; - overflow: hidden; - } - - .sider { - background: #fff; - border-right: 1px solid #f0f0f0; - overflow: auto; - } - - .sidebar { - height: 100%; - display: flex; - flex-direction: column; - - .searchBar { - padding: 16px; - border-bottom: 1px solid #f0f0f0; - background: #fff; - - :global(.ant-input) { - border-radius: 20px; - background: #f5f5f5; - border: none; - - &:focus { - background: #fff; - border: 1px solid #1890ff; - box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); - } - } - } - - .tabs { - flex: 1; - display: flex; - flex-direction: column; - - :global(.ant-tabs-content) { - flex: 1; - overflow: hidden; - } - - :global(.ant-tabs-tabpane) { - height: 100%; - overflow: hidden; - } - - :global(.ant-tabs-nav) { - margin: 0; - padding: 0 16px; - background: #fff; - border-bottom: 1px solid #f0f0f0; - - :global(.ant-tabs-tab) { - padding: 12px 16px; - margin: 0; - - &:hover { - color: #1890ff; - } - - &.ant-tabs-tab-active { - .ant-tabs-tab-btn { - color: #1890ff; - } - } - } - - :global(.ant-tabs-ink-bar) { - background: #1890ff; - } - } - } - - .emptyState { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 200px; - color: #8c8c8c; - - p { - margin-top: 16px; - font-size: 14px; - } - } - } - - .mainContent { - background: #f5f5f5; - display: flex; - flex-direction: column; - overflow: auto; - - .chatContainer { - height: 100%; - display: flex; - flex-direction: column; - - .chatToolbar { - background: #fff; - border-bottom: 1px solid #f0f0f0; - padding: 8px 16px; - display: flex; - justify-content: flex-end; - align-items: center; - min-height: 48px; - } - } - - .welcomeScreen { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - background: #fff; - - .welcomeContent { - text-align: center; - color: #8c8c8c; - - h2 { - margin: 24px 0 12px 0; - color: #262626; - font-size: 24px; - font-weight: 600; - } - - p { - font-size: 16px; - margin: 0; - } - } - } - } -} - -// 响应式设计 -@media (max-width: 768px) { - .ckboxLayout { - .sidebar { - .searchBar { - padding: 12px; - } - - .tabs { - :global(.ant-tabs-nav) { - padding: 0 12px; - - :global(.ant-tabs-tab) { - padding: 10px 12px; - } - } - } - } - - .mainContent { - .chatContainer { - .chatToolbar { - padding: 6px 12px; - min-height: 40px; - } - } - - .welcomeScreen { - .welcomeContent { - h2 { - font-size: 20px; - } - - p { - font-size: 14px; - } - } - } - } - } -} diff --git a/Cunkebao/src/pages/pc/ckbox/index.tsx b/Cunkebao/src/pages/pc/ckbox/index.tsx deleted file mode 100644 index 2ff2022a..00000000 --- a/Cunkebao/src/pages/pc/ckbox/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import Layout from "@/components/Layout/Layout"; -import { Outlet } from "react-router-dom"; -import NavCommon from "./components/NavCommon"; -import styles from "./index.module.scss"; -const CkboxPage: React.FC = () => { - return ( - - } - > - - - ); -}; - -export default CkboxPage; diff --git a/Cunkebao/src/pages/pc/ckbox/main.ts b/Cunkebao/src/pages/pc/ckbox/main.ts deleted file mode 100644 index 19f6cf62..00000000 --- a/Cunkebao/src/pages/pc/ckbox/main.ts +++ /dev/null @@ -1,307 +0,0 @@ -import { - asyncKfUserList, - asyncContractList, - asyncChatSessions, - asyncWeChatGroup, - asyncCountLables, - useCkChatStore, -} from "@/store/module/ckchat/ckchat"; -import { useWebSocketStore } from "@/store/module/websocket/websocket"; - -import { - loginWithToken, - getControlTerminalList, - getContactList, - getGroupList, -} from "./api"; - -import { useUserStore } from "@/store/module/user"; - -import { - KfUserListData, - ContractData, - weChatGroup, -} from "@/pages/pc/ckbox/data"; - -import { WechatGroup } from "./api"; -const { login2 } = useUserStore.getState(); -//获取触客宝基础信息 -export const chatInitAPIdata = async () => { - try { - //获取联系人列表 - const contractList = await getAllContactList(); - - //获取联系人列表 - asyncContractList(contractList); - - //获取群列表 - const groupList = await getAllGroupList(); - - await asyncWeChatGroup(groupList); - - // 提取不重复的wechatAccountId组 - const uniqueWechatAccountIds: number[] = getUniqueWechatAccountIds( - contractList, - groupList, - ); - - //获取控制终端列表 - const kfUserList: KfUserListData[] = - await getControlTerminalListByWechatAccountIds(uniqueWechatAccountIds); - - //获取用户列表 - await asyncKfUserList(kfUserList); - - //获取标签列表 - const countLables = await getCountLables(); - await asyncCountLables(countLables); - - //获取消息会话列表并按lastUpdateTime排序 - const filterUserSessions = contractList?.filter( - v => v?.config && v.config?.chat, - ); - const filterGroupSessions = groupList?.filter( - v => v?.config && v.config?.chat, - ); - //排序功能 - const sortedSessions = [...filterUserSessions, ...filterGroupSessions].sort( - (a, b) => { - // 如果lastUpdateTime不存在,则将其排在最后 - if (!a.lastUpdateTime) return 1; - if (!b.lastUpdateTime) return -1; - - // 首先按时间降序排列(最新的在前面) - const timeCompare = - new Date(b.lastUpdateTime).getTime() - - new Date(a.lastUpdateTime).getTime(); - - // 如果时间相同,则按未读消息数量降序排列 - if (timeCompare === 0) { - // 如果unreadCount不存在,则将其排在后面 - const aUnread = a.unreadCount || 0; - const bUnread = b.unreadCount || 0; - return bUnread - aUnread; // 未读消息多的排在前面 - } - - return timeCompare; - }, - ); - //会话数据同步 - asyncChatSessions(sortedSessions); - - return { - contractList, - groupList, - kfUserList, - }; - } catch (error) { - console.error("获取联系人列表失败:", error); - return []; - } -}; -//发起soket连接 -export const initSocket = () => { - // 检查WebSocket是否已经连接 - const { status } = useWebSocketStore.getState(); - - // 如果已经连接或正在连接,则不重复连接 - if (["connected", "connecting"].includes(status)) { - console.log("WebSocket已连接或正在连接,跳过重复连接", { status }); - return; - } - - // 从store获取token和accountId - const { token2 } = useUserStore.getState(); - const { getAccountId } = useCkChatStore.getState(); - const Token = token2; - const accountId = getAccountId(); - // 使用WebSocket store初始化连接 - const { connect } = useWebSocketStore.getState(); - - // 连接WebSocket - connect({ - accessToken: Token, - accountId: Number(accountId), - client: "kefu-client", - cmdType: "CmdSignIn", - seq: +new Date(), - }); -}; - -export const getCountLables = async () => { - const LablesRes = await Promise.all( - [1, 2].map(item => - WechatGroup({ - groupType: item, - }), - ), - ); - const [friend, group] = LablesRes; - const countLables = [ - ...[ - { - id: 0, - groupName: "默认群分组", - groupType: 2, - }, - ], - ...group, - ...friend, - ...[ - { - id: 0, - groupName: "未分组", - groupType: 1, - }, - ], - ]; - - return countLables; -}; -/** - * 根据标签组织联系人 - * @param contractList 联系人列表 - * @param countLables 标签列表 - * @returns 按标签分组的联系人 - */ - -//获取控制终端列表 -export const getControlTerminalListByWechatAccountIds = ( - WechatAccountIds: number[], -) => { - return Promise.all( - WechatAccountIds.map(id => getControlTerminalList({ id: id })), - ); -}; -// 递归获取所有联系人列表 -export const getAllContactList = async () => { - try { - let allContacts = []; - let prevId = 0; - const count = 1000; - let hasMore = true; - - while (hasMore) { - const contractList = await getContactList({ - prevId, - count, - }); - - if ( - !contractList || - !Array.isArray(contractList) || - contractList.length === 0 - ) { - hasMore = false; - break; - } - - allContacts = [...allContacts, ...contractList]; - - // 如果返回的数据少于请求的数量,说明已经没有更多数据了 - if (contractList.length < count) { - hasMore = false; - } else { - // 获取最后一条数据的id作为下一次请求的prevId - const lastContact = contractList[contractList.length - 1]; - prevId = lastContact.id; - } - } - return allContacts; - } catch (error) { - console.error("获取所有联系人列表失败:", error); - return []; - } -}; - -// 提取不重复的wechatAccountId组 -export const getUniqueWechatAccountIds = ( - contacts: ContractData[], - groupList: weChatGroup[], -) => { - if (!contacts || !Array.isArray(contacts) || contacts.length === 0) { - return []; - } - - // 使用Set来存储不重复的wechatAccountId - const uniqueAccountIdsSet = new Set(); - - // 遍历联系人列表,将每个wechatAccountId添加到Set中 - contacts.forEach(contact => { - if (contact && contact.wechatAccountId) { - uniqueAccountIdsSet.add(contact.wechatAccountId); - } - }); - - // 遍历联系人列表,将每个wechatAccountId添加到Set中 - groupList.forEach(group => { - if (group && group.wechatAccountId) { - uniqueAccountIdsSet.add(group.wechatAccountId); - } - }); - - // 将Set转换为数组并返回 - return Array.from(uniqueAccountIdsSet); -}; -// 递归获取所有群列表 -export const getAllGroupList = async () => { - try { - let allContacts = []; - let prevId = 0; - const count = 1000; - let hasMore = true; - - while (hasMore) { - const contractList = await getGroupList({ - prevId, - count, - }); - - if ( - !contractList || - !Array.isArray(contractList) || - contractList.length === 0 - ) { - hasMore = false; - break; - } - - allContacts = [...allContacts, ...contractList]; - - // 如果返回的数据少于请求的数量,说明已经没有更多数据了 - if (contractList.length < count) { - hasMore = false; - } else { - // 获取最后一条数据的id作为下一次请求的prevId - const lastContact = contractList[contractList.length - 1]; - prevId = lastContact.id; - } - } - - return allContacts; - } catch (error) { - console.error("获取所有群列表失败:", error); - return []; - } -}; - -//获取token -const getToken = () => { - return new Promise((resolve, reject) => { - const params = { - grant_type: "password", - password: "kr123456", - username: "kr_xf3", - // username: "karuo", - // password: "zhiqun1984", - }; - loginWithToken(params) - .then(res => { - login2(res.access_token); - resolve(res.access_token); - }) - .catch(err => { - reject(err); - }); - }); -}; diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/api.ts b/Cunkebao/src/pages/pc/ckbox/weChat/api.ts deleted file mode 100644 index af476f26..00000000 --- a/Cunkebao/src/pages/pc/ckbox/weChat/api.ts +++ /dev/null @@ -1,287 +0,0 @@ -import request from "@/api/request2"; -import { - MessageData, - ChatHistoryResponse, - MessageType, - OnlineStatus, - MessageStatus, - FileUploadResponse, - EmojiData, - QuickReply, - ChatSettings, -} from "./data"; - -//读取聊天信息 -//kf.quwanzhi.com:9991/api/WechatFriend/clearUnreadCount -function jsonToQueryString(json) { - const params = new URLSearchParams(); - for (const key in json) { - if (Object.prototype.hasOwnProperty.call(json, key)) { - params.append(key, json[key]); - } - } - return params.toString(); -} -//转移客户 -export function WechatFriendAllot(params: { - wechatFriendId?: number; - wechatChatroomId?: number; - toAccountId: number; - notifyReceiver: boolean; - comment: string; -}) { - return request( - "/api/wechatFriend/allot?" + jsonToQueryString(params), - undefined, - "PUT", - ); -} - -//获取可转移客服列表 -export function getTransferableAgentList() { - return request("/api/account/myDepartmentAccountsForTransfer", {}, "GET"); -} - -// 微信好友列表 -export function WechatFriendRebackAllot(params: { - wechatFriendId?: number; - wechatChatroomId?: number; -}) { - return request( - "/api/wechatFriend/rebackAllot?" + jsonToQueryString(params), - undefined, - "PUT", - ); -} - -// 微信群列表 -export function WechatGroup(params) { - return request("/api/WechatGroup/list", params, "GET"); -} - -//获取聊天记录-1 清除未读 -export function clearUnreadCount(params) { - return request("/api/WechatFriend/clearUnreadCount", params, "PUT"); -} - -//更新配置 -export function updateConfig(params) { - return request("/api/WechatFriend/updateConfig", params, "PUT"); -} -//获取聊天记录-2 获取列表 -export function getChatMessages(params: { - wechatAccountId: number; - wechatFriendId?: number; - wechatChatroomId?: number; - From: number; - To: number; - Count: number; - olderData: boolean; -}) { - return request("/api/FriendMessage/SearchMessage", params, "GET"); -} -export function getChatroomMessages(params: { - wechatAccountId: number; - wechatFriendId?: number; - wechatChatroomId?: number; - From: number; - To: number; - Count: number; - olderData: boolean; -}) { - return request("/api/ChatroomMessage/SearchMessage", params, "GET"); -} - -//获取群列表 -export function getGroupList(params: { prevId: number; count: number }) { - return request( - "/api/wechatChatroom/listExcludeMembersByPage?", - params, - "GET", - ); -} - -//获取群成员 -export function getGroupMembers(params: { id: number }) { - return request( - "/api/WechatChatroom/listMembersByWechatChatroomId", - params, - "GET", - ); -} - -//触客宝登陆 -export function loginWithToken(params: any) { - return request( - "/token", - params, - "POST", - { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }, - 1000, - ); -} - -// 获取触客宝用户信息 -export function getChuKeBaoUserInfo() { - return request("/api/account/self", {}, "GET"); -} - -// 获取联系人列表 -export const getContactList = (params: { prevId: number; count: number }) => { - return request("/api/wechatFriend/list", params, "GET"); -}; - -//获取控制终端列表 -export const getControlTerminalList = params => { - return request("/api/wechataccount", params, "GET"); -}; - -// 获取聊天历史 -export const getChatHistory = ( - chatId: string, - page: number = 1, - pageSize: number = 50, -): Promise => { - return request(`/v1/chats/${chatId}/messages`, { page, pageSize }, "GET"); -}; - -// 发送消息 -export const sendMessage = ( - chatId: string, - content: string, - type: MessageType = MessageType.TEXT, -): Promise => { - return request(`/v1/chats/${chatId}/messages`, { content, type }, "POST"); -}; - -// 发送文件消息 -export const sendFileMessage = ( - chatId: string, - file: File, - type: MessageType, -): Promise => { - const formData = new FormData(); - formData.append("file", file); - formData.append("type", type); - return request(`/v1/chats/${chatId}/messages/file`, formData, "POST"); -}; - -// 标记消息为已读 -export const markMessageAsRead = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/read`, {}, "PUT"); -}; - -// 标记聊天为已读 -export const markChatAsRead = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/read`, {}, "PUT"); -}; - -// 添加群组成员 -export const addGroupMembers = ( - groupId: string, - memberIds: string[], -): Promise => { - return request(`/v1/groups/${groupId}/members`, { memberIds }, "POST"); -}; - -// 移除群组成员 -export const removeGroupMembers = ( - groupId: string, - memberIds: string[], -): Promise => { - return request(`/v1/groups/${groupId}/members`, { memberIds }, "DELETE"); -}; - -// 获取在线状态 -export const getOnlineStatus = (userId: string): Promise => { - return request(`/v1/users/${userId}/status`, {}, "GET"); -}; - -// 获取消息状态 -export const getMessageStatus = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/status`, {}, "GET"); -}; - -// 上传文件 -export const uploadFile = (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - return request("/v1/upload", formData, "POST"); -}; - -// 获取表情包列表 -export const getEmojiList = (): Promise => { - return request("/v1/emojis", {}, "GET"); -}; - -// 获取快捷回复列表 -export const getQuickReplies = (): Promise => { - return request("/v1/quick-replies", {}, "GET"); -}; - -// 添加快捷回复 -export const addQuickReply = (data: { - content: string; - category: string; -}): Promise => { - return request("/v1/quick-replies", data, "POST"); -}; - -// 删除快捷回复 -export const deleteQuickReply = (id: string): Promise => { - return request(`/v1/quick-replies/${id}`, {}, "DELETE"); -}; - -// 获取聊天设置 -export const getChatSettings = (): Promise => { - return request("/v1/chat/settings", {}, "GET"); -}; - -// 更新聊天设置 -export const updateChatSettings = ( - settings: Partial, -): Promise => { - return request("/v1/chat/settings", settings, "PUT"); -}; - -// 删除聊天会话 -export const deleteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}`, {}, "DELETE"); -}; - -// 置顶聊天会话 -export const pinChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/pin`, {}, "PUT"); -}; - -// 取消置顶聊天会话 -export const unpinChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/unpin`, {}, "PUT"); -}; - -// 静音聊天会话 -export const muteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/mute`, {}, "PUT"); -}; - -// 取消静音聊天会话 -export const unmuteChatSession = (chatId: string): Promise => { - return request(`/v1/chats/${chatId}/unmute`, {}, "PUT"); -}; - -// 转发消息 -export const forwardMessage = ( - messageId: string, - targetChatIds: string[], -): Promise => { - return request("/v1/messages/forward", { messageId, targetChatIds }, "POST"); -}; - -// 撤回消息 -export const recallMessage = (messageId: string): Promise => { - return request(`/v1/messages/${messageId}/recall`, {}, "PUT"); -}; diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/ChatWindow.module.scss b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/ChatWindow.module.scss deleted file mode 100644 index ceeff66e..00000000 --- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/ChatWindow.module.scss +++ /dev/null @@ -1,404 +0,0 @@ -.chatWindow { - height: 100%; - display: flex; - flex-direction: row; -} - -.chatMain { - flex: 1; - display: flex; - flex-direction: column; - min-width: 0; -} - -.chatHeader { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 16px; - background: #fff; - border-bottom: 1px solid #f0f0f0; - height: 64px; - min-height: 64px; - flex-shrink: 0; - gap: 16px; // 确保信息区域和按钮区域有足够间距 - - .chatHeaderInfo { - display: flex; - align-items: center; - gap: 12px; - flex: 1; - min-width: 0; // 防止flex子元素溢出 - - :global(.ant-avatar) { - flex-shrink: 0; - width: 40px; - height: 40px; - } - - .chatHeaderDetails { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - min-width: 0; - - .chatHeaderName { - font-size: 16px; - font-weight: 600; - color: #262626; - display: flex; - align-items: center; - gap: 8px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-right: 30px; - - .chatHeaderOnlineStatus { - font-size: 12px; - color: #52c41a; - font-weight: normal; - flex-shrink: 0; // 防止在线状态被压缩 - } - } - - .chatHeaderType { - font-size: 12px; - color: #8c8c8c; - margin-top: 2px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .chatHeaderSubInfo { - display: flex; - gap: 12px; - margin-top: 2px; - font-size: 12px; - overflow: hidden; - - .chatHeaderRemark { - color: #1890ff; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .chatHeaderWechatId { - color: #8c8c8c; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - - .headerButton { - color: #8c8c8c; - border: none; - padding: 8px; - - &:hover { - color: #1890ff; - background: #f5f5f5; - } - } -} - -.chatContent { - flex: 1; - overflow: visible; - background: #f5f5f5; - display: flex; - flex-direction: column; - - .messagesContainer { - height: 100%; - overflow-y: auto; - padding: 16px; - - .loadingContainer { - display: flex; - justify-content: center; - align-items: center; - height: 100px; - color: #8c8c8c; - } - } -} - -// 右侧个人资料卡片 -.profileSider { - background: #fff; - border-left: 1px solid #f0f0f0; - display: flex; - flex-direction: column; - height: 100%; - flex-shrink: 0; - - .profileSiderContent { - display: flex; - flex-direction: column; - height: 100%; - - .profileHeader { - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px; - border-bottom: 1px solid #f0f0f0; - background: #fafafa; - flex-shrink: 0; - - h3 { - margin: 0; - font-size: 16px; - font-weight: 600; - color: #262626; - } - - .closeButton { - color: #8c8c8c; - border: none; - padding: 4px; - - &:hover { - color: #1890ff; - background: #f5f5f5; - } - } - } - - .profileContent { - flex: 1; - overflow-y: auto; - padding: 16px; - height: 0; // 确保flex子元素能够正确计算高度 - - .profileCard { - margin-bottom: 16px; - border-radius: 8px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - - &:last-child { - margin-bottom: 0; - } - - :global(.ant-card-head) { - border-bottom: 1px solid #f0f0f0; - padding: 0 16px; - - :global(.ant-card-head-title) { - font-size: 14px; - font-weight: 600; - color: #262626; - } - } - - :global(.ant-card-body) { - padding: 16px; - } - } - - .profileBasic { - display: flex; - align-items: center; - gap: 16px; - - :global(.ant-avatar) { - flex-shrink: 0; - width: 48px; - height: 48px; - } - - .profileInfo { - flex: 1; - min-width: 0; - overflow: hidden; - - h4 { - margin: 0 0 8px 0; - font-size: 18px; - font-weight: 600; - color: #262626; - } - - .profileNickname { - margin: 0 0 8px 0; - font-size: 18px; - font-weight: 600; - color: #262626; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - cursor: pointer; - } - - .profileStatus { - margin: 0 0 4px 0; - font-size: 12px; - color: #52c41a; - } - - .profilePosition { - margin: 0; - font-size: 12px; - color: #8c8c8c; - } - - .profileRemark { - margin: 0 0 4px 0; - font-size: 12px; - color: #1890ff; - - :global(.ant-input) { - font-size: 12px; - } - - :global(.ant-btn) { - padding: 0; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - } - } - - .profileWechatId { - margin: 0; - font-size: 12px; - color: #8c8c8c; - } - } - } - - .contractInfo { - .contractItem { - align-items: center; - margin-bottom: 12px; - font-size: 14px; - color: #262626; - - &:last-child { - margin-bottom: 0; - } - - :global(.anticon) { - color: #8c8c8c; - font-size: 16px; - width: 16px; - } - - .contractItemText { - padding-left: 10px; - } - } - } - - .tagsContainer { - display: flex; - flex-wrap: wrap; - gap: 6px; - - :global(.ant-tag) { - margin: 0; - border-radius: 12px; - font-size: 12px; - } - } - - .bioText { - margin: 0; - font-size: 14px; - line-height: 1.6; - color: #595959; - } - - .profileActions { - margin-top: 24px; - } - } - } -} - -.messageTime { - text-align: center; - padding: 4px 0; - font-size: 12px; - color: #999; - margin: 20px 0; -} - -// 响应式设计 -@media (max-width: 1200px) { - .profileSider { - width: 260px !important; - } -} - -@media (max-width: 768px) { - .chatWindow { - flex-direction: column; - } - - .profileSider { - width: 100% !important; - height: 300px; - border-left: none; - border-top: 1px solid #f0f0f0; - } - - .chatHeader { - padding: 0 12px; - height: 56px; - min-height: 56px; - - .chatHeaderInfo { - .chatHeaderDetails { - .chatHeaderName { - font-size: 14px; - } - } - } - } - - .chatContent { - .messagesContainer { - padding: 12px; - } - } - - .profileContent { - padding: 12px; - - .profileCard { - margin-bottom: 12px; - - :global(.ant-card-body) { - padding: 12px; - } - } - - .profileBasic { - gap: 12px; - - .profileInfo { - h4 { - font-size: 16px; - } - } - } - - .contractInfo { - .contractItem { - font-size: 13px; - margin-bottom: 10px; - } - } - } -} diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss deleted file mode 100644 index 36977bd1..00000000 --- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss +++ /dev/null @@ -1,181 +0,0 @@ -// MessageEnter 组件样式 - 微信风格 -.chatFooter { - background: #f7f7f7; - border-top: 1px solid #e1e1e1; - padding: 0; - height: auto; - min-height: 100px; -} - -.inputContainer { - padding: 8px 12px; - display: flex; - flex-direction: column; - gap: 6px; -} - -.inputToolbar { - display: flex; - justify-content: space-between; - align-items: center; - padding: 4px 0; - border-bottom: none; -} - -.leftTool { - display: flex; - gap: 2px; - align-items: center; -} - -.toolbarButton { - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 4px; - color: #666; - font-size: 16px; - transition: all 0.15s; - border: none; - background: transparent; - - &:hover { - background: #e6e6e6; - color: #333; - } - - &:active { - background: #d9d9d9; - } -} - -.rightTool { - display: flex; - gap: 12px; - align-items: center; -} - -.rightToolItem { - display: flex; - align-items: center; - gap: 3px; - color: #666; - font-size: 11px; - cursor: pointer; - padding: 3px 6px; - border-radius: 3px; - transition: all 0.15s; - - &:hover { - background: #e6e6e6; - color: #333; - } -} - -.inputArea { - display: flex; - flex-direction: column; - padding: 4px 0; -} - -.inputWrapper { - border: 1px solid #d1d1d1; - border-radius: 4px; - background: #fff; - overflow: hidden; - - &:focus-within { - border-color: #07c160; - } -} - -.messageInput { - width: 100%; - border: none; - resize: none; - font-size: 13px; - line-height: 1.4; - padding: 8px 10px; - background: transparent; - - &:focus { - box-shadow: none; - outline: none; - } - - &::placeholder { - color: #b3b3b3; - } -} - -.sendButtonArea { - padding: 8px 10px; - display: flex; - justify-content: flex-end; -} - -.sendButton { - height: 32px; - border-radius: 4px; - font-weight: normal; - min-width: 60px; - font-size: 13px; - background: #07c160; - border-color: #07c160; - - &:hover { - background: #06ad56; - border-color: #06ad56; - } - - &:active { - background: #059748; - border-color: #059748; - } - - &:disabled { - background: #b3b3b3; - border-color: #b3b3b3; - opacity: 1; - } -} - -.inputHint { - font-size: 11px; - color: #999; - text-align: right; - margin-top: 2px; -} - -// 响应式设计 -@media (max-width: 768px) { - .inputContainer { - padding: 8px 12px; - } - - .inputToolbar { - flex-wrap: wrap; - gap: 8px; - } - - .rightTool { - gap: 8px; - } - - .rightToolItem { - font-size: 11px; - padding: 2px 6px; - } - - .inputArea { - flex-direction: column; - gap: 8px; - } - - .sendButton { - align-self: flex-end; - min-width: 60px; - } -} diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/chatRecord/index.tsx b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/chatRecord/index.tsx deleted file mode 100644 index 3068e42d..00000000 --- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/chatRecord/index.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import React, { useState } from "react"; -import { Button, Modal, Input, DatePicker, message } from "antd"; -import { MessageOutlined } from "@ant-design/icons"; -import dayjs from "dayjs"; -import { useWeChatStore } from "@/store/module/weChat/weChat"; - -const { RangePicker } = DatePicker; - -interface ChatRecordProps { - className?: string; - disabled?: boolean; -} - -const ChatRecord: React.FC = ({ - className, - disabled = false, -}) => { - const [visible, setVisible] = useState(false); - const [searchContent, setSearchContent] = useState(""); - const [dateRange, setDateRange] = useState<[dayjs.Dayjs, dayjs.Dayjs] | null>( - null, - ); - const [loading, setLoading] = useState(false); - const SearchMessage = useWeChatStore(state => state.SearchMessage); - - // 打开弹窗 - const openModal = () => { - setVisible(true); - }; - - // 关闭弹窗并重置状态 - const closeModal = () => { - setVisible(false); - setSearchContent(""); - setDateRange(null); - setLoading(false); - }; - - // 执行查找 - const handleSearch = async () => { - if (!dateRange) { - message.warning("请选择时间范围"); - return; - } - - try { - setLoading(true); - const [From, To] = dateRange; - const searchData = { - From: From.unix() * 1000, - To: To.unix() * 1000, - keyword: searchContent.trim(), - }; - await SearchMessage(searchData); - - message.success("查找完成"); - closeModal(); - } catch (error) { - console.error("查找失败:", error); - message.error("查找失败,请重试"); - } finally { - setLoading(false); - } - }; - - return ( - <> -
- - 聊天记录 -
- - - - - , - ]} - > -
- {/* 时间范围选择 */} -
-
- 时间范围 -
- -
- - {/* 查找内容输入 */} -
-
- 查找内容 -
- setSearchContent(e.target.value)} - size="large" - maxLength={100} - showCount - disabled={loading} - /> -
-
-
- - ); -}; - -export default ChatRecord; diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/toContract/index.tsx b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/toContract/index.tsx deleted file mode 100644 index be2f9cb2..00000000 --- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/toContract/index.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React, { useState } from "react"; -import { Button, Modal, Select, Input, message } from "antd"; -import { ShareAltOutlined } from "@ant-design/icons"; -import { - getTransferableAgentList, - WechatFriendAllot, - WechatFriendRebackAllot, -} from "@/pages/pc/ckbox/weChat/api"; -import { useCurrentContact } from "@/store/module/weChat/weChat"; -import { useCkChatStore } from "@/store/module/ckchat/ckchat"; -import { contractService, weChatGroupService } from "@/utils/db"; -const { TextArea } = Input; -const { Option } = Select; - -interface ToContractProps { - className?: string; - disabled?: boolean; -} -interface DepartItem { - id: number; - userName: string; - realName: string; - nickname: string; - avatar: string; - memo: string; - departmentId: number; - alive: boolean; -} - -const ToContract: React.FC = ({ - className, - disabled = false, -}) => { - const currentContact = useCurrentContact(); - const [visible, setVisible] = useState(false); - const [selectedTarget, setSelectedTarget] = useState(null); - const [comment, setComment] = useState(""); - const [loading, setLoading] = useState(false); - const [customerServiceList, setCustomerServiceList] = useState( - [], - ); - const deleteChatSession = useCkChatStore(state => state.deleteChatSession); - // 打开弹窗 - const openModal = () => { - setVisible(true); - getTransferableAgentList().then(data => { - setCustomerServiceList(data); - }); - }; - - // 关闭弹窗并重置状态 - const closeModal = () => { - setVisible(false); - setSelectedTarget(null); - setComment(""); - setLoading(false); - }; - - // 确定转给他人 - const handleConfirm = async () => { - if (!selectedTarget) { - message.warning("请选择目标客服"); - return; - } - - try { - setLoading(true); - - console.log(currentContact); - - // 调用转接接口 - if (currentContact) { - if ("chatroomId" in currentContact && currentContact.chatroomId) { - await WechatFriendAllot({ - wechatChatroomId: currentContact.id, - toAccountId: selectedTarget as number, - notifyReceiver: true, - comment: comment.trim(), - }); - } else { - await WechatFriendAllot({ - wechatFriendId: currentContact.id, - toAccountId: selectedTarget as number, - notifyReceiver: true, - comment: comment.trim(), - }); - } - } - - message.success("转接成功"); - try { - // 删除聊天会话 - deleteChatSession(currentContact.id); - // 删除本地数据库记录 - if ("chatroomId" in currentContact) { - await weChatGroupService.delete(currentContact.id); - } else { - await contractService.delete(currentContact.id); - } - } catch (deleteError) { - console.error("删除本地数据失败:", deleteError); - } - closeModal(); - } catch (error) { - console.error("转接失败:", error); - message.error("转接失败,请重试"); - } finally { - setLoading(false); - } - }; - - // 一键转回 - const handleReturn = async () => { - try { - setLoading(true); - - // 调用转回接口 - if (currentContact) { - if ("chatroomId" in currentContact && currentContact.chatroomId) { - await WechatFriendRebackAllot({ - wechatChatroomId: currentContact.id, - }); - } else { - await WechatFriendRebackAllot({ - wechatFriendId: currentContact.id, - }); - } - } - - message.success("转回成功"); - try { - // 删除聊天会话 - deleteChatSession(currentContact.id); - // 删除本地数据库记录 - if ("chatroomId" in currentContact) { - await weChatGroupService.delete(currentContact.id); - } else { - await contractService.delete(currentContact.id); - } - } catch (deleteError) { - console.error("删除本地数据失败:", deleteError); - } - closeModal(); - } catch (error) { - console.error("转回失败:", error); - message.error("转回失败,请重试"); - } finally { - setLoading(false); - } - }; - - return ( - <> -
- - 转给他人 -
- - - -
- - -
- , - ]} - > -
- {/* 目标客服选择 */} -
-
- 目标客服 -
- -
- - {/* 附言输入 */} -
-
- 附言 -
-