feat(朋友圈): 添加朋友圈功能相关组件和状态管理
- 新增朋友圈数据类型定义和接口 - 在状态管理中添加朋友圈相关状态 - 实现朋友圈图片预览功能 - 优化朋友圈样式和交互体验
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// 评论数据类型
|
||||
export interface CommentItem {
|
||||
commentArg: number;
|
||||
commentId1: number;
|
||||
commentId2: number;
|
||||
commentTime: number;
|
||||
content: string;
|
||||
nickName: string;
|
||||
wechatId: string;
|
||||
}
|
||||
|
||||
// 点赞数据类型
|
||||
export interface LikeItem {
|
||||
createTime: number;
|
||||
nickName: string;
|
||||
wechatId: string;
|
||||
}
|
||||
|
||||
// 朋友圈实体数据类型
|
||||
export interface MomentEntity {
|
||||
content: string;
|
||||
createTime: number;
|
||||
lat: number;
|
||||
lng: number;
|
||||
location: string;
|
||||
objectType: number;
|
||||
picSize: number;
|
||||
resUrls: string[];
|
||||
snsId: string;
|
||||
urls: string[];
|
||||
userName: string;
|
||||
}
|
||||
|
||||
// 朋友圈数据类型定义
|
||||
export interface FriendsCircleItem {
|
||||
commentList: CommentItem[];
|
||||
createTime: number;
|
||||
likeList: LikeItem[];
|
||||
momentEntity: MomentEntity;
|
||||
snsId: string;
|
||||
type: number;
|
||||
}
|
||||
|
||||
// API响应类型
|
||||
export interface ApiResponse {
|
||||
list: FriendsCircleItem[];
|
||||
total: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
// 分页参数类型
|
||||
export interface PaginationParams {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
type: "my" | "square";
|
||||
}
|
||||
@@ -172,6 +172,12 @@
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,3 +309,95 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 图片预览Modal样式 ===== */
|
||||
.imagePreviewModal {
|
||||
:global(.ant-modal-content) {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:global(.ant-modal-header) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global(.ant-modal-close) {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1001;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
:global(.ant-modal-body) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.previewContainer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
|
||||
.previewImage {
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.navButton {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s;
|
||||
z-index: 1000;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
transform: translateY(-50%) scale(1.1);
|
||||
}
|
||||
|
||||
&.prevButton {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
&.nextButton {
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.imageCounter {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,17 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Avatar, Button, Collapse, Spin } from "antd";
|
||||
import { Avatar, Button, Collapse, Spin, Modal } from "antd";
|
||||
import { useWebSocketStore } from "@/store/module/websocket/websocket";
|
||||
import {
|
||||
HeartOutlined,
|
||||
ChromeOutlined,
|
||||
MessageOutlined,
|
||||
LoadingOutlined,
|
||||
AppstoreOutlined,
|
||||
CloseOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { InfiniteScroll } from "antd-mobile";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
// 评论数据类型
|
||||
interface CommentItem {
|
||||
commentArg: number;
|
||||
commentId1: number;
|
||||
commentId2: number;
|
||||
commentTime: number;
|
||||
content: string;
|
||||
nickName: string;
|
||||
wechatId: string;
|
||||
}
|
||||
|
||||
// 点赞数据类型
|
||||
interface LikeItem {
|
||||
createTime: number;
|
||||
nickName: string;
|
||||
wechatId: string;
|
||||
}
|
||||
|
||||
// 朋友圈实体数据类型
|
||||
interface MomentEntity {
|
||||
content: string;
|
||||
createTime: number;
|
||||
lat: number;
|
||||
lng: number;
|
||||
location: string;
|
||||
objectType: number;
|
||||
picSize: number;
|
||||
resUrls: string[];
|
||||
snsId: string;
|
||||
urls: string[];
|
||||
userName: string;
|
||||
}
|
||||
|
||||
// 朋友圈数据类型定义
|
||||
interface FriendsCircleItem {
|
||||
commentList: CommentItem[];
|
||||
createTime: number;
|
||||
likeList: LikeItem[];
|
||||
momentEntity: MomentEntity;
|
||||
snsId: string;
|
||||
type: number;
|
||||
}
|
||||
|
||||
// API响应类型
|
||||
interface ApiResponse {
|
||||
list: FriendsCircleItem[];
|
||||
total: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
// 分页参数类型
|
||||
interface PaginationParams {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
type: "my" | "square";
|
||||
}
|
||||
|
||||
import { FriendsCircleItem, PaginationParams } from "./index.data";
|
||||
// 模拟朋友圈数据
|
||||
const mockFriendsCircleData: FriendsCircleItem[] = [
|
||||
{
|
||||
@@ -162,10 +107,26 @@ const FriendsCircle: React.FC = () => {
|
||||
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,
|
||||
): Promise<ApiResponse> => {
|
||||
const fetchFriendsCircleData = async (params: PaginationParams) => {
|
||||
// 模拟网络延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
@@ -276,6 +237,34 @@ const FriendsCircle: React.FC = () => {
|
||||
console.log("评论:", id);
|
||||
};
|
||||
|
||||
// 处理图片预览
|
||||
const handleImagePreview = (images: string[], index: number) => {
|
||||
setPreviewImages(images);
|
||||
setCurrentImageIndex(index);
|
||||
setPreviewVisible(true);
|
||||
};
|
||||
|
||||
// 关闭图片预览
|
||||
const handleClosePreview = () => {
|
||||
setPreviewVisible(false);
|
||||
setPreviewImages([]);
|
||||
setCurrentImageIndex(0);
|
||||
};
|
||||
|
||||
// 切换到上一张图片
|
||||
const handlePrevImage = () => {
|
||||
setCurrentImageIndex(prev =>
|
||||
prev > 0 ? prev - 1 : previewImages.length - 1,
|
||||
);
|
||||
};
|
||||
|
||||
// 切换到下一张图片
|
||||
const handleNextImage = () => {
|
||||
setCurrentImageIndex(prev =>
|
||||
prev < previewImages.length - 1 ? prev + 1 : 0,
|
||||
);
|
||||
};
|
||||
|
||||
// 格式化时间戳
|
||||
const formatTime = (timestamp: number) => {
|
||||
const date = new Date(timestamp * 1000);
|
||||
@@ -331,14 +320,11 @@ const FriendsCircle: React.FC = () => {
|
||||
key={index}
|
||||
src={image}
|
||||
className={styles.contentImage}
|
||||
onClick={() => handleImagePreview(images, index)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{images && images.length > 0 && (
|
||||
<div className={styles.blueLink}>查看图片</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.itemFooter}>
|
||||
@@ -508,6 +494,58 @@ const FriendsCircle: React.FC = () => {
|
||||
activeKey={expandedKeys}
|
||||
onChange={handleCollapseChange}
|
||||
/>
|
||||
|
||||
{/* 图片预览Modal */}
|
||||
<Modal
|
||||
open={previewVisible}
|
||||
footer={null}
|
||||
onCancel={handleClosePreview}
|
||||
width="100vw"
|
||||
style={{ top: 0, paddingBottom: 0 }}
|
||||
bodyStyle={{
|
||||
padding: 0,
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.9)",
|
||||
}}
|
||||
closeIcon={<CloseOutlined style={{ color: "white", fontSize: 24 }} />}
|
||||
className={styles.imagePreviewModal}
|
||||
>
|
||||
<div className={styles.previewContainer}>
|
||||
{previewImages.length > 0 && (
|
||||
<>
|
||||
<img
|
||||
src={previewImages[currentImageIndex]}
|
||||
alt="预览图片"
|
||||
className={styles.previewImage}
|
||||
/>
|
||||
|
||||
{previewImages.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
className={`${styles.navButton} ${styles.prevButton}`}
|
||||
onClick={handlePrevImage}
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
<button
|
||||
className={`${styles.navButton} ${styles.nextButton}`}
|
||||
onClick={handleNextImage}
|
||||
>
|
||||
›
|
||||
</button>
|
||||
|
||||
<div className={styles.imageCounter}>
|
||||
{currentImageIndex + 1} / {previewImages.length}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -24,6 +24,11 @@ export const useWeChatStore = create<WeChatState>()(
|
||||
messagesLoading: false,
|
||||
isLoadingData: false,
|
||||
currentGroupMembers: [],
|
||||
MomentOfKf: [], //客服自己的朋友圈
|
||||
MomentOfSquare: [], //朋友圈广场
|
||||
MomentOfFriend: [], //好友的朋友圈
|
||||
//============方法列表============
|
||||
|
||||
//清空当前联系人
|
||||
clearCurrentContact: () => {
|
||||
set({ currentContract: null, currentMessages: [] });
|
||||
|
||||
Reference in New Issue
Block a user