feat(朋友圈): 重构朋友圈功能,支持好友朋友圈展示和加载更多

- 删除无用的sendMessages.ts文件
- 修改FriendsCircleItem接口,将snsId类型改为number
- 重构weChat store,支持批量添加朋友圈数据
- 优化朋友圈样式,修复图片浮动问题
- 重构api.ts,简化请求参数处理
- 在msgManage.ts中添加朋友圈数据处理逻辑
- 完全重构FriendsCicle组件,支持好友朋友圈展示和加载更多功能
This commit is contained in:
超级老白兔
2025-09-17 14:57:58 +08:00
parent c9eb19a064
commit 680c16c7da
8 changed files with 121 additions and 268 deletions

View File

@@ -15,18 +15,7 @@ export interface FetchMomentParams {
// 获取朋友圈数据
export const fetchFriendsCircleData = async (params: FetchMomentParams) => {
const { sendCommand } = useWebSocketStore.getState();
const requestData = {
cmdType: "CmdFetchMoment",
wechatAccountId: params.wechatAccountId,
wechatFriendId: params.wechatFriendId || 0,
createTimeSec: params.createTimeSec || Math.floor(Date.now() / 1000),
prevSnsId: params.prevSnsId || 0,
count: params.count || 10,
isTimeline: params.isTimeline || false,
seq: params.seq || Date.now(),
};
sendCommand("CmdFetchMoment", requestData);
sendCommand("CmdFetchMoment", params);
};
// 点赞朋友圈

View File

@@ -37,7 +37,7 @@ export interface FriendsCircleItem {
createTime: number;
likeList: LikeItem[];
momentEntity: MomentEntity;
snsId: string;
snsId: number;
type: number;
}
@@ -47,10 +47,3 @@ export interface ApiResponse {
total: number;
hasMore: boolean;
}
// 分页参数类型
export interface PaginationParams {
pageNum: number;
pageSize: number;
type: "my" | "square";
}

View File

@@ -168,7 +168,11 @@
/* 图片容器 */
.imageContainer {
margin: 8px 0;
&::after {
content: "";
display: table;
clear: both;
}
.contentImage {
width: 60px;
height: 60px;
@@ -178,6 +182,7 @@
margin-bottom: 8px;
cursor: pointer;
transition: transform 0.2s;
float: left;
&:hover {
transform: scale(1.05);

View File

@@ -1,6 +1,5 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { Avatar, Button, Collapse, Spin, Modal } from "antd";
import { useWebSocketStore } from "@/store/module/websocket/websocket";
import {
HeartOutlined,
ChromeOutlined,
@@ -8,241 +7,75 @@ import {
LoadingOutlined,
CloseOutlined,
} from "@ant-design/icons";
import { InfiniteScroll } from "antd-mobile";
import dayjs from "dayjs";
import styles from "./index.module.scss";
import { FriendsCircleItem, PaginationParams } from "./index.data";
import { FriendsCircleItem } from "./index.data";
import { fetchFriendsCircleData } from "./api";
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
import { useWeChatStore } from "@/store/module/weChat/weChat";
// 模拟朋友圈数据
const mockFriendsCircleData: FriendsCircleItem[] = [
{
commentList: [
{
commentArg: 2,
commentId1: 0,
commentId2: 35,
commentTime: 1758011325,
content: "测试评论",
nickName: "老坑爹- 解放双手,释放时间",
wechatId: "wxid_480es52qsj2812",
},
],
createTime: 1757258659,
likeList: [
{
createTime: 1757315556,
nickName: "老坑爹- 解放双手,释放时间",
wechatId: "wxid_480es52qsj2812",
},
],
momentEntity: {
content: "没看到血月[旺柴]",
createTime: 1757258659,
lat: 0,
lng: 0,
location: "",
objectType: 1,
picSize: 0,
resUrls: [
"https://ac-weremote-s2.oss-cn-shenzhen.aliyuncs.com/weremote/chat-logs/5E2C38F5A275450D935F3ECEC076124E/aa6d4c2f7b1fe24d04d34f4f409883e6/sns/wxid_480es52qsj2812/-3705790026851937712/-3705790026851937712-14740954047910318662.jpg",
],
snsId: "-3705790026851937712",
urls: ["/sns/3/3/snst_14740954047910318662"],
userName: "wxid_dlhi90odctcl22",
},
snsId: "-3705790026851937712",
type: 1,
},
{
commentList: [],
createTime: 1757258600,
likeList: [],
momentEntity: {
content:
"🎉🎊🎈欢迎小伙伴加入单群聊客宝地盘思慕斯蛋糕的小伙伴们的支持与信任!!!",
createTime: 1757258600,
lat: 0,
lng: 0,
location: "",
objectType: 1,
picSize: 0,
resUrls: ["/public/assets/face/1.png"],
snsId: "-3705790026851937713",
urls: ["/sns/3/3/snst_14740954047910318663"],
userName: "wxid_dlhi90odctcl23",
},
snsId: "-3705790026851937713",
type: 1,
},
{
commentList: [],
createTime: 1757258500,
likeList: [],
momentEntity: {
content: "一整年卡1好的产品有用户的好评是买卖说的再多不如用户的有说服力",
createTime: 1757258500,
lat: 0,
lng: 0,
location: "",
objectType: 1,
picSize: 0,
resUrls: ["/public/assets/face/1.png"],
snsId: "-3705790026851937714",
urls: ["/sns/3/3/snst_14740954047910318664"],
userName: "wxid_dlhi90odctcl24",
},
snsId: "-3705790026851937714",
type: 1,
},
];
interface FriendsCircleProps {
wechatFriendId: number;
}
const FriendsCircle: React.FC = () => {
const FriendsCircle: React.FC<FriendsCircleProps> = ({ wechatFriendId }) => {
const currentKf = useCkChatStore(state =>
state.kfUserList.find(kf => kf.id === state.kfSelected),
);
const { clearMomentCommon } = useWeChatStore();
const { clearMomentCommon, updateMomentCommonLoading } = useWeChatStore();
const MomentCommon = useWeChatStore(state => state.MomentCommon);
const MomentCommonLoading = useWeChatStore(
state => state.MomentCommonLoading,
);
// 页面重新渲染时重置MomentCommonLoading状态
useEffect(() => {
updateMomentCommonLoading(false);
}, []);
// 状态管理
const [myCircleData, setMyCircleData] = useState<FriendsCircleItem[]>([]);
const [squareData, setSquareData] = useState<FriendsCircleItem[]>([]);
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<string[]>([]);
// 图片预览相关状态
const [previewVisible, setPreviewVisible] = useState(false);
const [previewImages, setPreviewImages] = useState<string[]>([]);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const { sendCommand } = useWebSocketStore.getState();
// const handleSend = async () => {
// const params = {
// wechatAccountId: contract.wechatAccountId,
// wechatChatroomId: contract?.chatroomId ? contract.id : 0,
// wechatFriendId: contract?.chatroomId ? 0 : contract.id,
// msgSubType: 0,
// msgType: 1,
// content: inputValue,
// };
// sendCommand("CmdSendMessage", params);
// };
// 模拟API调用函数
const fetchFriendsCircleData = async (params: PaginationParams) => {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 1000));
const { pageNum, pageSize, type } = params;
const startIndex = (pageNum - 1) * pageSize;
// 使用模拟数据
const allData = mockFriendsCircleData;
const typeData = type === "my" ? allData.slice(0, 1) : allData;
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 loadMomentData = async (loadMore: boolean = false) => {
updateMomentCommonLoading(true);
// 加载数据;
const requestData = {
cmdType: "CmdFetchMoment",
wechatAccountId: currentKf?.id || 0,
wechatFriendId: wechatFriendId || 0,
createTimeSec: Math.floor(dayjs().subtract(2, "month").valueOf() / 1000),
prevSnsId: loadMore
? 0
: MomentCommon[MomentCommon.length - 1]?.snsId || 0,
count: 10,
isTimeline: expandedKeys.includes("1"),
seq: Date.now(),
};
await fetchFriendsCircleData(requestData);
};
// 处理折叠面板展开/收起
const handleCollapseChange = (keys: string | string[]) => {
clearMomentCommon();
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);
}
});
console.log("MomentCommonLoading", MomentCommonLoading);
if (!MomentCommonLoading && keys.length > 0) {
clearMomentCommon();
loadMomentData(false);
}
};
const handleLike = (id: string) => {
const handleLike = (id: number) => {
console.log("点赞:", id);
};
const handleComment = (id: string) => {
const handleComment = (id: number) => {
console.log("评论:", id);
};
@@ -289,7 +122,7 @@ const FriendsCircle: React.FC = () => {
// 获取用户昵称
const getUserNickName = (item: FriendsCircleItem) => {
// 优先从点赞列表或评论列表中获取昵称
if (item.likeList.length > 0) {
if (item?.likeList?.length > 0) {
return item.likeList[0].nickName;
}
if (item.commentList.length > 0) {
@@ -298,13 +131,13 @@ const FriendsCircle: React.FC = () => {
return item.momentEntity.userName;
};
const renderNormalItem = (item: FriendsCircleItem, isNotMy?: boolean) => {
const nickName = getUserNickName(item);
const content = item.momentEntity.content;
const images = item.momentEntity.resUrls;
const time = formatTime(item.createTime);
const likesCount = item.likeList.length;
const commentsCount = item.commentList.length;
const renderNormalItem = (monent: FriendsCircleItem, isNotMy?: boolean) => {
// const nickName = getUserNickName(monent);
const content = monent?.momentEntity?.content || "";
const images = monent?.momentEntity?.resUrls || [];
const time = formatTime(monent.createTime);
const likesCount = monent?.likeList?.length || 0;
const commentsCount = monent?.commentList?.length || 0;
return (
<div className={styles.circleItem}>
@@ -316,7 +149,7 @@ const FriendsCircle: React.FC = () => {
<div className={styles.itemWrap}>
<div className={styles.itemHeader}>
<div className={styles.userInfo}>
<div className={styles.username}>{nickName}</div>
{/* <div className={styles.username}>{nickName}</div> */}
</div>
</div>
@@ -343,7 +176,7 @@ const FriendsCircle: React.FC = () => {
type="text"
size="small"
icon={<HeartOutlined />}
onClick={() => handleLike(item.snsId)}
onClick={() => handleLike(monent.snsId)}
className={styles.actionButton}
>
{likesCount > 0 && <span>{likesCount}</span>}
@@ -352,7 +185,7 @@ const FriendsCircle: React.FC = () => {
type="text"
size="small"
icon={<MessageOutlined />}
onClick={() => handleComment(item.snsId)}
onClick={() => handleComment(monent.snsId)}
className={styles.actionButton}
>
{commentsCount > 0 && <span>{commentsCount}</span>}
@@ -361,17 +194,20 @@ const FriendsCircle: React.FC = () => {
</div>
{/* 点赞和评论区域 */}
{(item.likeList.length > 0 || item.commentList.length > 0) && (
{(monent?.likeList?.length > 0 ||
monent?.commentList?.length > 0) && (
<div className={styles.interactionArea}>
{/* 点赞列表 */}
{item.likeList.length > 0 && (
{monent?.likeList?.length > 0 && (
<div className={styles.likeArea}>
<HeartOutlined className={styles.likeIcon} />
<span className={styles.likeList}>
{item.likeList.map((like, index) => (
<span key={like.wechatId}>
{monent?.likeList?.map((like, index) => (
<span
key={`${like.wechatId}-${like.createTime}-${index}`}
>
{like.nickName}
{index < item.likeList.length - 1 && "、"}
{index < (monent?.likeList?.length || 0) - 1 && "、"}
</span>
))}
</span>
@@ -379,9 +215,9 @@ const FriendsCircle: React.FC = () => {
)}
{/* 评论列表 */}
{item.commentList.length > 0 && (
{monent?.commentList?.length > 0 && (
<div className={styles.commentArea}>
{item.commentList.map(comment => (
{monent?.commentList?.map(comment => (
<div
key={`${comment.wechatId}-${comment.commentTime}`}
className={styles.commentItem}
@@ -409,24 +245,32 @@ const FriendsCircle: React.FC = () => {
<div className={styles.myCircleContent}>
{MomentCommon.length > 0 ? (
<>
{MomentCommon.map(item => (
<div key={item.snsId} className={styles.itemWrapper}>
{renderNormalItem(item, false)}
{MomentCommon.map((v, index) => (
<div
key={`${v.snsId}-${v.createTime}-${index}`}
className={styles.itemWrapper}
>
{renderNormalItem(v, false)}
</div>
))}
<InfiniteScroll
loadMore={loadMoreMyCircle}
hasMore={myCircleHasMore}
threshold={10}
>
{myCircleLoading && (
<div className={styles.loadingMore}>
<Spin indicator={<LoadingOutlined spin />} /> ...
</div>
)}
</InfiniteScroll>
{MomentCommonLoading && (
<div className={styles.loadingMore}>
<Spin indicator={<LoadingOutlined spin />} /> ...
</div>
)}
{!MomentCommonLoading && (
<div style={{ textAlign: "center" }}>
<Button
size="small"
type="primary"
onClick={() => loadMomentData(true)}
>
...
</Button>
</div>
)}
</>
) : myCircleLoading ? (
) : MomentCommonLoading ? (
<div className={styles.loadingMore}>
<Spin indicator={<LoadingOutlined spin />} /> ...
</div>
@@ -462,6 +306,20 @@ const FriendsCircle: React.FC = () => {
),
children: renderMomentCommon(),
},
...(wechatFriendId
? [
{
key: "3",
label: (
<div className={styles.collapseHeader}>
<ChromeOutlined style={{ fontSize: 20 }} />
<span className={styles.specialText}></span>
</div>
),
children: renderMomentCommon(),
},
]
: []),
];
return (

View File

@@ -20,7 +20,7 @@ export interface WeChatState {
MomentCommon: FriendsCircleItem[];
// MomentCommon 相关方法
clearMomentCommon: () => void;
addMomentCommon: (moment: FriendsCircleItem) => void;
addMomentCommon: (moment: FriendsCircleItem[]) => void;
updateMomentCommon: (moments: FriendsCircleItem[]) => void;
MomentCommonLoading: boolean;

View File

@@ -24,8 +24,9 @@ export const useWeChatStore = create<WeChatState>()(
messagesLoading: false,
isLoadingData: false,
currentGroupMembers: [],
MomentCommon: [],
MomentCommonLoading: false,
MomentCommon: [], //朋友圈数据
MomentCommonLoading: false, //朋友圈数据是否正在加载
// MomentCommon 相关方法
updateMomentCommonLoading: (loading: boolean) => {
set({ MomentCommonLoading: loading });
@@ -284,7 +285,7 @@ export const useWeChatStore = create<WeChatState>()(
addMomentCommon: moment => {
set(state => ({
MomentCommon: [...state.MomentCommon, moment],
MomentCommon: [...state.MomentCommon, ...moment],
}));
},

View File

@@ -6,10 +6,11 @@ import { Messages } from "./msg.data";
import { useWeChatStore } from "../weChat/weChat";
// 消息处理器类型定义
type MessageHandler = (message: WebSocketMessage) => void;
const setVideoUrl = useWeChatStore.getState().setVideoUrl;
const addMessage = useWeChatStore.getState().addMessage;
const receivedMsg = useWeChatStore.getState().receivedMsg;
const updateMomentCommonLoading =
useWeChatStore.getState().updateMomentCommonLoading;
const addMomentCommon = useWeChatStore.getState().addMomentCommon;
// 消息处理器映射
const messageHandlers: Record<string, MessageHandler> = {
// 微信账号存活状态响应
@@ -80,6 +81,12 @@ const messageHandlers: Record<string, MessageHandler> = {
// setVideoUrl(message.friendMessageId, message.url);
},
CmdFetchMomentResult: message => {
console.log("朋友圈数据结果", message);
addMomentCommon(message.result);
updateMomentCommonLoading(false);
},
// 可以继续添加更多处理器...
};