diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/api.ts b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/api.ts new file mode 100644 index 00000000..8da04005 --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/api.ts @@ -0,0 +1,6 @@ +import request2 from "@/api/request2"; +import request from "@/api/request"; +// 静音聊天会话 +// export const muteChatSession = (chatId: string): Promise => { +// return request2(`/v1/chats/${chatId}/mute`, {}, "PUT"); +// }; diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.module.scss index d033c10c..876ccf6e 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.module.scss +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.module.scss @@ -1,230 +1,248 @@ +/* ===== 组件根容器 ===== */ .friendsCircle { height: 100%; overflow-y: auto; padding: 0; background-color: #f5f5f5; -} -.itemWrapper { - margin-bottom: 1px; -} - -// 可折叠组件样式 -.collapseContainer { - margin-bottom: 1px; - - :global(.ant-collapse-item) { - border-bottom: 1px solid #e8e8e8; - - &:last-child { - border-bottom: 1px solid #e8e8e8; - } + /* 滚动条样式 */ + &::-webkit-scrollbar { + width: 6px; } - - :global(.ant-collapse-header) { - padding: 12px 16px !important; - background-color: #ffffff; - + + &::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 3px; + } + + &::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 3px; + &:hover { - background-color: #f8f8f8; + background: #a8a8a8; } } - - :global(.ant-collapse-content-box) { - padding: 16px; - background-color: #ffffff; - } -} -.collapseHeader { - display: flex; - align-items: center; - gap: 12px; -} - -.specialAvatar { - background-color: #1890ff; -} - -.groupAvatars { - display: flex; - position: relative; - width: 32px; - height: 32px; - - .groupAvatar { - position: absolute; - border: 1px solid #fff; - background-color: #52c41a; - - &:nth-child(1) { - top: 0; - left: 0; - z-index: 4; - } - - &:nth-child(2) { - top: 0; - right: 0; - z-index: 3; - } - - &:nth-child(3) { - bottom: 0; - left: 0; - z-index: 2; - } - - &:nth-child(4) { - bottom: 0; - right: 0; - z-index: 1; - } - } -} - -.specialText { - font-size: 16px; - color: #333; - font-weight: 400; -} - -.myCircleContent, -.squareContent { - padding: 0; - - .itemWrapper { + /* ===== 折叠面板样式 ===== */ + .collapseContainer { margin-bottom: 1px; - - &:last-child { - margin-bottom: 0; + + :global(.ant-collapse-item) { + border-bottom: 1px solid #e8e8e8; + + &:last-child { + border-bottom: 1px solid #e8e8e8; + } + } + + :global(.ant-collapse-header) { + padding: 12px 16px !important; + background-color: #ffffff; + + &:hover { + background-color: #f8f8f8; + } + } + + :global(.ant-collapse-content-box) { + padding: 16px; + background-color: #ffffff; + } + + /* 折叠面板头部 */ + .collapseHeader { + display: flex; + align-items: center; + gap: 6px; + + /* 特殊头像样式 */ + .specialAvatar { + background-color: #1890ff; + } + + /* 群组头像样式 */ + .groupAvatars { + display: flex; + position: relative; + width: 32px; + height: 32px; + + .groupAvatar { + position: absolute; + border: 1px solid #fff; + background-color: #52c41a; + + &:nth-child(1) { + top: 0; + left: 0; + z-index: 4; + } + + &:nth-child(2) { + top: 0; + right: 0; + z-index: 3; + } + + &:nth-child(3) { + bottom: 0; + left: 0; + z-index: 2; + } + + &:nth-child(4) { + bottom: 0; + right: 0; + z-index: 1; + } + } + } + + /* 特殊文本样式 */ + .specialText { + font-size: 16px; + color: #333; + font-weight: 400; + } } } - - // 当内容为空时的样式 - .emptyText { - padding: 20px; - text-align: center; - color: #999; - font-size: 14px; - margin: 0; + + /* ===== 内容区域样式 ===== */ + .myCircleContent, + .squareContent { + padding: 0; + + /* 项目包装器 */ + .itemWrapper { + margin-bottom: 1px; + + &:last-child { + margin-bottom: 0; + } + + /* ===== 朋友圈项目样式 ===== */ + .circleItem { + background-color: #ffffff; + margin-bottom: 20px; + display: flex; + /* 头像样式 */ + .avatar { + margin-right: 10px; + } + /* 项目头部 */ + .itemHeader { + display: flex; + align-items: flex-start; + gap: 12px; + margin-bottom: 12px; + + /* 用户信息 */ + .userInfo { + flex: 1; + + .username { + font-size: 14px; + font-weight: 500; + color: #333; + line-height: 1.4; + } + } + } + + /* 项目内容 */ + .itemContent { + margin-bottom: 12px; + font-size: 12px; + .contentText { + color: #333; + line-height: 1.6; + margin-bottom: 8px; + word-wrap: break-word; + } + + /* 图片容器 */ + .imageContainer { + margin: 8px 0; + + .contentImage { + width: 60px; + height: 60px; + object-fit: cover; + border-radius: 4px; + margin-right: 8px; + margin-bottom: 8px; + } + } + + /* 蓝色链接 */ + .blueLink { + color: #1890ff; + cursor: pointer; + &:hover { + text-decoration: underline; + } + } + } + + /* 项目底部 */ + .itemFooter { + display: flex; + align-items: center; + justify-content: space-between; + + /* 时间信息 */ + .timeInfo { + font-size: 12px; + color: #999; + } + + /* 操作按钮区域 */ + .actions { + display: flex; + align-items: center; + gap: 8px; + + .actionButton { + padding: 4px 8px; + color: #666; + + &:hover { + color: #1890ff; + background-color: #f0f8ff; + } + + .anticon { + font-size: 14px; + } + } + } + } + } + } + + /* 空状态样式 */ + .emptyText { + padding: 20px; + text-align: center; + color: #999; + font-size: 14px; + margin: 0; + } + + /* 加载更多样式 */ + .loadingMore { + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + color: #666; + font-size: 14px; + gap: 8px; + + .anticon { + margin-right: 4px; + } + } } } - - - -// 普通朋友圈项目样式 -.circleItem { - background-color: #ffffff; - padding: 16px; - border-bottom: 1px solid #e8e8e8; -} - -.itemHeader { - display: flex; - align-items: flex-start; - gap: 12px; - margin-bottom: 12px; -} - -.avatar { - flex-shrink: 0; -} - -.userInfo { - flex: 1; -} - -.username { - font-size: 16px; - font-weight: 500; - color: #333; - line-height: 1.4; -} - -.itemContent { - margin-left: 52px; - margin-bottom: 12px; -} - -.contentText { - font-size: 14px; - color: #333; - line-height: 1.6; - margin-bottom: 8px; - word-wrap: break-word; -} - -.imageContainer { - margin: 8px 0; -} - -.contentImage { - width: 60px; - height: 60px; - object-fit: cover; - border-radius: 4px; - margin-right: 8px; - margin-bottom: 8px; -} - -.blueLink { - color: #1890ff; - font-size: 14px; - cursor: pointer; - - &:hover { - text-decoration: underline; - } -} - -.itemFooter { - display: flex; - align-items: center; - justify-content: space-between; - margin-left: 52px; -} - -.timeInfo { - font-size: 12px; - color: #999; -} - -.actions { - display: flex; - align-items: center; - gap: 8px; -} - -.actionButton { - padding: 4px 8px; - color: #666; - - &:hover { - color: #1890ff; - background-color: #f0f8ff; - } - - .anticon { - font-size: 14px; - } -} - -// 滚动条样式 -.friendsCircle::-webkit-scrollbar { - width: 6px; -} - -.friendsCircle::-webkit-scrollbar-track { - background: #f1f1f1; - border-radius: 3px; -} - -.friendsCircle::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: 3px; - - &:hover { - background: #a8a8a8; - } -} \ No newline at end of file diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.tsx index 8c5b92a2..da7693ad 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/FriendsCicle/index.tsx @@ -1,6 +1,13 @@ -import React from "react"; -import { Avatar, Button, Collapse } from "antd"; -import { HeartOutlined, MessageOutlined } from "@ant-design/icons"; +import React, { useState, useEffect } from "react"; +import { Avatar, Button, Collapse, Spin } from "antd"; +import { + HeartOutlined, + ChromeOutlined, + MessageOutlined, + LoadingOutlined, + AppstoreOutlined, +} from "@ant-design/icons"; +import { InfiniteScroll } from "antd-mobile"; import styles from "./index.module.scss"; // 朋友圈数据类型定义 @@ -15,6 +22,20 @@ interface FriendsCircleItem { comments?: number; } +// API响应类型 +interface ApiResponse { + list: FriendsCircleItem[]; + total: number; + hasMore: boolean; +} + +// 分页参数类型 +interface PaginationParams { + pageNum: number; + pageSize: number; + type: "my" | "square"; +} + // 模拟朋友圈数据 const mockFriendsCircleData: FriendsCircleItem[] = [ { @@ -76,6 +97,123 @@ const mockFriendsCircleData: FriendsCircleItem[] = [ ]; const FriendsCircle: React.FC = () => { + // 状态管理 + const [myCircleData, setMyCircleData] = useState([]); + const [squareData, setSquareData] = useState([]); + const [myCircleLoading, setMyCircleLoading] = useState(false); + const [squareLoading, setSquareLoading] = useState(false); + const [myCircleHasMore, setMyCircleHasMore] = useState(true); + const [squareHasMore, setSquareHasMore] = useState(true); + const [myCirclePage, setMyCirclePage] = useState(1); + const [squarePage, setSquarePage] = useState(1); + const [expandedKeys, setExpandedKeys] = useState([]); + + // 模拟API调用函数 + const fetchFriendsCircleData = async ( + params: PaginationParams, + ): Promise => { + // 模拟网络延迟 + await new Promise(resolve => setTimeout(resolve, 1000)); + + const { pageNum, pageSize, type } = params; + const startIndex = (pageNum - 1) * pageSize; + + // 使用原有的模拟数据 + const allData = mockFriendsCircleData.slice(2); // 排除前两个特殊项 + const typeData = type === "my" ? allData.slice(0, 2) : allData.slice(2); + const paginatedData = typeData.slice(startIndex, startIndex + pageSize); + + return { + list: paginatedData, + total: typeData.length, + hasMore: startIndex + pageSize < typeData.length, + }; + }; + + // 加载我的朋友圈数据 + const loadMyCircleData = async ( + pageNum: number = 1, + reset: boolean = false, + ) => { + setMyCircleLoading(true); + try { + const response = await fetchFriendsCircleData({ + pageNum, + pageSize: 10, + type: "my", + }); + + if (reset) { + setMyCircleData(response.list); + } else { + setMyCircleData(prev => [...prev, ...response.list]); + } + + setMyCircleHasMore(response.hasMore); + setMyCirclePage(pageNum); + } catch (error) { + console.error("加载我的朋友圈失败:", error); + } finally { + setMyCircleLoading(false); + } + }; + + // 加载朋友圈广场数据 + const loadSquareData = async ( + pageNum: number = 1, + reset: boolean = false, + ) => { + setSquareLoading(true); + try { + const response = await fetchFriendsCircleData({ + pageNum, + pageSize: 10, + type: "square", + }); + + if (reset) { + setSquareData(response.list); + } else { + setSquareData(prev => [...prev, ...response.list]); + } + + setSquareHasMore(response.hasMore); + setSquarePage(pageNum); + } catch (error) { + console.error("加载朋友圈广场失败:", error); + } finally { + setSquareLoading(false); + } + }; + + // 加载更多我的朋友圈 + const loadMoreMyCircle = async () => { + if (!myCircleHasMore || myCircleLoading) return; + await loadMyCircleData(myCirclePage + 1); + }; + + // 加载更多朋友圈广场 + const loadMoreSquare = async () => { + if (!squareHasMore || squareLoading) return; + await loadSquareData(squarePage + 1); + }; + + // 处理折叠面板展开/收起 + const handleCollapseChange = (keys: string | string[]) => { + const keyArray = Array.isArray(keys) ? keys : [keys]; + setExpandedKeys(keyArray); + + // 当展开时加载数据 + keyArray.forEach(key => { + if (key === "1" && myCircleData.length === 0) { + loadMyCircleData(1, true); + } + if (key === "2" && squareData.length === 0) { + loadSquareData(1, true); + } + }); + }; + const handleLike = (id: string) => { console.log("点赞:", id); }; @@ -84,18 +222,88 @@ const FriendsCircle: React.FC = () => { console.log("评论:", id); }; - const renderMyFriendsCircle = () => { - // 显示部分朋友圈数据作为"我的朋友圈" - const myCircleData = mockFriendsCircleData.slice(2, 4); + const renderNormalItem = (item: FriendsCircleItem, isNotMy?: boolean) => { + return ( +
+ {isNotMy && ( +
+ +
+ )} +
+
+
+
{item.username}
+
+
+
+
{item.content}
+ {item.images && item.images.length > 0 && ( +
+ {item.images.map((image, index) => ( + + ))} +
+ )} + +
查看图片
+
+ +
+
{item.time}
+
+
+
+
+
+ ); + }; + + const renderMyFriendsCircle = () => { return (
{myCircleData.length > 0 ? ( - myCircleData.map(item => ( -
- {renderNormalItem(item)} -
- )) + <> + {myCircleData.map(item => ( +
+ {renderNormalItem(item, false)} +
+ ))} + + {myCircleLoading && ( +
+ } /> 加载中... +
+ )} +
+ + ) : myCircleLoading ? ( +
+ } /> 加载中... +
) : (

暂无我的朋友圈内容

)} @@ -104,17 +312,31 @@ const FriendsCircle: React.FC = () => { }; const renderFriendsSquare = () => { - // 显示剩余的朋友圈数据作为"朋友圈广场" - const squareData = mockFriendsCircleData.slice(4); - return (
{squareData.length > 0 ? ( - squareData.map(item => ( -
- {renderNormalItem(item)} -
- )) + <> + {squareData.map(item => ( +
+ {renderNormalItem(item, true)} +
+ ))} + + {squareLoading && ( +
+ } /> 加载中... +
+ )} +
+ + ) : squareLoading ? ( +
+ } /> 加载中... +
) : (

暂无朋友圈广场内容

)} @@ -127,7 +349,7 @@ const FriendsCircle: React.FC = () => { key: "1", label: (
- + 我的朋友圈
), @@ -137,12 +359,7 @@ const FriendsCircle: React.FC = () => { key: "2", label: (
-
- - - - -
+ 朋友圈广场
), @@ -150,58 +367,6 @@ const FriendsCircle: React.FC = () => { }, ]; - const renderNormalItem = (item: FriendsCircleItem) => { - return ( -
-
- -
-
{item.username}
-
-
- -
-
{item.content}
- - {item.images && item.images.length > 0 && ( -
- {item.images.map((image, index) => ( - 朋友圈图片 - ))} -
- )} - -
查看图片
-
- -
-
{item.time}
-
-
-
-
- ); - }; - return (
{/* 可折叠的特殊模块,包含所有朋友圈数据 */} @@ -209,6 +374,8 @@ const FriendsCircle: React.FC = () => { items={collapseItems} className={styles.collapseContainer} ghost + activeKey={expandedKeys} + onChange={handleCollapseChange} />
);