diff --git a/Touchkebao/src/pages/pc/ckbox/components/NavCommon/Notice.tsx b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/Notice.tsx new file mode 100644 index 00000000..1249a6d7 --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/Notice.tsx @@ -0,0 +1,431 @@ +import React, { useEffect, useState } from "react"; +import { Drawer, Avatar, Space, Button, Badge, Empty, Tabs, Tag } from "antd"; +import { BellOutlined } from "@ant-design/icons"; +import { + noticeList, + readMessage, + readAll, + friendRequestList as fetchFriendRequestListApi, +} from "./api"; +import styles from "./index.module.scss"; + +interface MessageItem { + id: number; + type: number; + companyId: number; + userId: number; + bindId: number; + title: string; + message: string; + isRead: number; + createTime: string; + readTime: string; + friendData: { + nickname: string; + avatar: string; + }; +} + +interface FriendRequestItem { + taskId: number; + phone: string; + wechatId: string; + adder?: { + avatar?: string; + nickname?: string; + username?: string; + accountNickname?: string; + accountRealName?: string; + }; + status?: { + code?: number; + text?: string; + }; + time?: { + addTime?: string; + addTimeStamp?: number; + updateTime?: string; + updateTimeStamp?: number; + passTime?: string; + passTimeStamp?: number; + }; + friend?: { + nickname?: string; + isPassed?: boolean; + }; + other?: { + msgContent?: string; + remark?: string; + from?: string; + labels?: string[]; + }; +} + +const DEFAULT_QUERY = { page: 1, limit: 20 }; + +const Notice: React.FC = () => { + const [messageDrawerVisible, setMessageDrawerVisible] = useState(false); + const [activeTab, setActiveTab] = useState("messages"); + const [messageList, setMessageList] = useState([]); + const [messageCount, setMessageCount] = useState(0); + const [loading, setLoading] = useState(false); + const [friendRequestList, setFriendRequestList] = useState< + FriendRequestItem[] + >([]); + const [friendRequestLoading, setFriendRequestLoading] = useState(false); + + const fetchMessageList = async () => { + try { + setLoading(true); + const response = await noticeList(DEFAULT_QUERY); + if (response?.list) { + setMessageList(response.list); + const unreadCount = response.list.filter( + (item: MessageItem) => item.isRead === 0, + ).length; + setMessageCount(unreadCount); + } + } catch (error) { + console.error("获取消息列表失败:", error); + } finally { + setLoading(false); + } + }; + + const refreshUnreadCount = async () => { + try { + const response = await noticeList(DEFAULT_QUERY); + if (response && typeof response.noRead === "number") { + setMessageCount(response.noRead); + } + } catch (error) { + console.error("获取未读消息数失败:", error); + } + }; + + useEffect(() => { + fetchMessageList(); + const timer = window.setInterval(refreshUnreadCount, 30 * 1000); + return () => { + window.clearInterval(timer); + }; + }, []); + + const handleMessageClick = () => { + setMessageDrawerVisible(true); + fetchMessageList(); + fetchFriendRequestList(); + }; + + const handleTabChange = (key: string) => { + setActiveTab(key); + if (key === "friendRequests") { + fetchFriendRequestList(); + } + }; + + const handleMessageDrawerClose = () => { + setMessageDrawerVisible(false); + }; + + const handleReadMessage = async (messageId: number) => { + try { + await readMessage({ id: messageId }); + setMessageList(prev => { + const updated = prev.map(item => + item.id === messageId ? { ...item, isRead: 1 } : item, + ); + const unreadCount = updated.filter(item => item.isRead === 0).length; + setMessageCount(unreadCount); + return updated; + }); + } catch (error) { + console.error("标记消息已读失败:", error); + } + }; + + const handleReadAll = async () => { + try { + await readAll(); + setMessageList(prev => prev.map(item => ({ ...item, isRead: 1 }))); + setMessageCount(0); + } catch (error) { + console.error("全部已读失败:", error); + } + }; + + const fetchFriendRequestList = async () => { + try { + setFriendRequestLoading(true); + const response = await fetchFriendRequestListApi(DEFAULT_QUERY); + if (response?.list) { + setFriendRequestList(response.list); + } + } catch (error) { + console.error("获取好友添加记录失败:", error); + } finally { + setFriendRequestLoading(false); + } + }; + + const formatTime = (timeStr?: string) => { + if (!timeStr) { + return "-"; + } + const date = new Date(timeStr); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (days === 0) { + return date.toLocaleTimeString("zh-CN", { + hour: "2-digit", + minute: "2-digit", + }); + } else if (days === 1) { + return "昨天"; + } else if (days < 7) { + return `${days}天前`; + } else { + return date.toLocaleDateString("zh-CN", { + month: "2-digit", + day: "2-digit", + }); + } + }; + + const getStatusText = (statusCode?: number, statusText?: string) => { + if (statusText) { + return statusText; + } + switch (statusCode) { + case 0: + return "待处理"; + case 1: + return "已同意"; + case 2: + return "已拒绝"; + default: + return "未知"; + } + }; + + const getStatusColor = (statusCode?: number) => { + switch (statusCode) { + case 0: + return "#1890ff"; + case 1: + return "#52c41a"; + case 2: + return "#ff4d4f"; + default: + return "#999"; + } + }; + + const getFriendRequestKey = (item: FriendRequestItem) => { + return ( + item.taskId?.toString() || + item.wechatId || + item.phone || + `${item.adder?.username || "unknown"}-${item.time?.addTime || "time"}` + ); + }; + + const getAddedUserName = (item: FriendRequestItem) => { + return ( + item.friend?.nickname || + item.phone || + item.wechatId || + item.adder?.nickname || + "未知好友" + ); + }; + + const getAdderName = (item: FriendRequestItem) => { + return ( + item.adder?.nickname || + item.adder?.username || + item.adder?.accountNickname || + item.adder?.accountRealName || + "未知添加人" + ); + }; + + return ( + <> +
+ + + +
+ + + + + ) + } + > +
+ + {loading ? ( +
+ 加载中... +
+ ) : messageList.length === 0 ? ( + + ) : ( + messageList.map(item => ( +
handleReadMessage(item.id)} + > +
+ + {item.friendData?.nickname?.charAt(0) || "U"} + +
+
+
+ + {item.title} + + {item.isRead === 0 && ( +
+ )} +
+
+ {item.message} +
+ {item.isRead === 0 && ( +
+ {formatTime(item.createTime)} + +
+ )} +
+
+ )) + )} +
+ ), + }, + { + key: "friendRequests", + label: "好友添加记录", + children: ( +
+ {friendRequestLoading ? ( +
+ 加载中... +
+ ) : friendRequestList.length === 0 ? ( + + ) : ( + friendRequestList.map(item => ( +
+
+ + {item.adder?.nickname?.charAt(0) || "U"} + +
+
+
+ + 添加好友: + {getAddedUserName(item)} + + + {getStatusText( + item.status?.code, + item.status?.text, + )} + +
+
+ 申请人:{getAdderName(item)} +
+
+ 验证信息:{item.other?.msgContent || "无"} +
+ +
+ {item.other?.remark && ( + + 备注:{item.other.remark} + + )} +
+
+ {formatTime(item.time?.addTime)} +
+
+
+ )) + )} +
+ ), + }, + ]} + /> + +
+ + ); +}; + +export default Notice; diff --git a/Touchkebao/src/pages/pc/ckbox/components/NavCommon/api.ts b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/api.ts index f814b6b9..dd665a02 100644 --- a/Touchkebao/src/pages/pc/ckbox/components/NavCommon/api.ts +++ b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/api.ts @@ -14,3 +14,8 @@ export const readMessage = (params: { id: number }) => { export const readAll = () => { return request(`/v1/kefu/notice/readAll`, undefined, "PUT"); }; + +// 好友添加任务列表 +export const friendRequestList = (params: { page: number; limit: number }) => { + return request(`/v1/kefu/wechatFriend/addTaskList`, params, "GET"); +}; diff --git a/Touchkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx index fcd3f7a4..dce087d4 100644 --- a/Touchkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx @@ -1,29 +1,18 @@ -import React, { useState, useEffect } from "react"; -import { - Layout, - Drawer, - Avatar, - Space, - Button, - Badge, - Dropdown, - Empty, - message, -} from "antd"; +import React, { useState } from "react"; +import { Layout, Avatar, Space, Button, Dropdown, message } from "antd"; import { BarChartOutlined, UserOutlined, - BellOutlined, LogoutOutlined, ThunderboltOutlined, SettingOutlined, SendOutlined, ClearOutlined, } from "@ant-design/icons"; -import { noticeList, readMessage, readAll } from "./api"; import { useUserStore } from "@/store/module/user"; import { useNavigate, useLocation } from "react-router-dom"; import styles from "./index.module.scss"; +import Notice from "./Notice"; const { Header } = Layout; @@ -32,40 +21,12 @@ interface NavCommonProps { onMenuClick?: () => void; } -// 消息数据类型 -interface MessageItem { - id: number; - type: number; - companyId: number; - userId: number; - bindId: number; - title: string; - message: string; - isRead: number; - createTime: string; - readTime: string; - friendData: { - nickname: string; - avatar: string; - }; -} - const NavCommon: React.FC = ({ title = "触客宝" }) => { - const [messageDrawerVisible, setMessageDrawerVisible] = useState(false); - const [messageList, setMessageList] = useState([]); - const [messageCount, setMessageCount] = useState(0); - const [loading, setLoading] = useState(false); const [clearingCache, setClearingCache] = useState(false); const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useUserStore(); - // 初始化时获取消息列表 - useEffect(() => { - fetchMessageList(); - setInterval(IntervalMessageCount, 30 * 1000); - }, []); - // 处理菜单图标点击:在两个路由之间切换 const handleMenuClick = () => { if (!location.pathname.startsWith("/pc/powerCenter")) { @@ -74,48 +35,6 @@ const NavCommon: React.FC = ({ title = "触客宝" }) => { navigate("/pc/weChat"); } }; - // 定时器获取消息条数 - const IntervalMessageCount = async () => { - try { - const response = await noticeList({ page: 1, limit: 20 }); - if (response && response.noRead) { - setMessageCount(response.noRead); - } - } catch (error) { - console.error("获取消息列表失败:", error); - } - }; - // 获取消息列表 - const fetchMessageList = async () => { - try { - setLoading(true); - const response = await noticeList({ page: 1, limit: 20 }); - if (response && response.list) { - setMessageList(response.list); - // 计算未读消息数量 - const unreadCount = response.list.filter( - (item: MessageItem) => item.isRead === 0, - ).length; - setMessageCount(unreadCount); - } - } catch (error) { - console.error("获取消息列表失败:", error); - } finally { - setLoading(false); - } - }; - - // 处理消息中心点击 - const handleMessageClick = () => { - setMessageDrawerVisible(true); - fetchMessageList(); - }; - - // 处理消息抽屉关闭 - const handleMessageDrawerClose = () => { - setMessageDrawerVisible(false); - }; - // 处理退出登录 const handleLogout = () => { logout(); // 清除localStorage中的token和用户状态 @@ -215,61 +134,6 @@ const NavCommon: React.FC = ({ title = "触客宝" }) => { } }; - // 处理消息已读 - const handleReadMessage = async (messageId: number) => { - try { - await readMessage({ id: messageId }); // 这里需要根据实际API调整参数 - // 更新本地状态 - setMessageList(prev => - prev.map(item => - item.id === messageId ? { ...item, isRead: 1 } : item, - ), - ); - // 重新计算未读数量 - const unreadCount = - messageList.filter(item => item.isRead === 0).length - 1; - setMessageCount(Math.max(0, unreadCount)); - } catch (error) { - console.error("标记消息已读失败:", error); - } - }; - - // 处理全部已读 - const handleReadAll = async () => { - try { - await readAll(); // 这里需要根据实际API调整参数 - // 更新本地状态 - setMessageList(prev => prev.map(item => ({ ...item, isRead: 1 }))); - setMessageCount(0); - } catch (error) { - console.error("全部已读失败:", error); - } - }; - - // 格式化时间 - const formatTime = (timeStr: string) => { - const date = new Date(timeStr); - const now = new Date(); - const diff = now.getTime() - date.getTime(); - const days = Math.floor(diff / (1000 * 60 * 60 * 24)); - - if (days === 0) { - return date.toLocaleTimeString("zh-CN", { - hour: "2-digit", - minute: "2-digit", - }); - } else if (days === 1) { - return "昨天"; - } else if (days < 7) { - return `${days}天前`; - } else { - return date.toLocaleDateString("zh-CN", { - month: "2-digit", - day: "2-digit", - }); - } - }; - // 用户菜单项 const userMenuItems = [ { @@ -333,11 +197,7 @@ const NavCommon: React.FC = ({ title = "触客宝" }) => { {user?.tokens} -
- - - -
+ = ({ title = "触客宝" }) => { - - - - - } - > -
- {loading ? ( -
- 加载中... -
- ) : messageList.length === 0 ? ( - - ) : ( - messageList.map(item => ( -
handleReadMessage(item.id)} - > -
- - {item.friendData?.nickname?.charAt(0) || "U"} - -
-
-
- {item.title} - {item.isRead === 0 && ( -
- )} -
-
{item.message}
- {item.isRead === 0 && ( -
- {formatTime(item.createTime)} - -
- )} -
-
- )) - )} -
-
); };