提交 faf0bfab 作者: ZhangLingKun

功能:贴子详情

上级 0c0ee289
流水线 #8162 已通过 于阶段
in 5 分 44 秒
...@@ -989,7 +989,7 @@ export type AllCommentListType = InterListFunction< ...@@ -989,7 +989,7 @@ export type AllCommentListType = InterListFunction<
* 用户id * 用户id
*/ */
userAccountId?: number; userAccountId?: number;
status: number; status: boolean;
replyCount: number; replyCount: number;
userAccountVO: { userAccountVO: {
userImg: string; userImg: string;
...@@ -999,3 +999,97 @@ export type AllCommentListType = InterListFunction< ...@@ -999,3 +999,97 @@ export type AllCommentListType = InterListFunction<
}; };
} }
>; >;
// 话题-评论下的回复
export type ReplyListType = InterListFunction<
{
/**
* 动态id
*/
dynamicId: number;
/**
* 评论id
*/
id: number;
},
{
/**
* 评论内容
*/
content?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 动态id
*/
dynamicId?: number;
/**
* id
*/
id: number;
/**
* 评论点赞数
*/
likeCount?: number;
/**
* pid
*/
pid: number;
/**
* 回复id
*/
reviewId?: number;
/**
* 更新时间
*/
updateTime?: string;
/**
* 用户id
*/
userAccountId?: number;
status: number;
userAccountVO: {
userImg: string;
userName: string;
nickName: string;
id: number;
};
}
>;
// 发表评论
export type PublishCommentType = InterFunction<
{
content: string;
dynamicId: number;
rootPath?: string;
/**
* pid(注意:单纯评论就为0,有回复就上级id)
*/
pid?: number;
/**
* 评论id(注意:单纯评论就为0 ,有回复就评论id)
*/
reviewId?: number;
},
{}
>;
// 话题-评论/回复点赞,取消
export type ReviewLikesType = InterFunction<
{
/**
* id
*/
id: number;
/**
* status
*/
status: boolean;
},
{}
>;
// 论坛点赞或取消点赞
export type LikeOrCancelType = InterFunction<
{ dynamicId: number; userId?: number },
null
>;
...@@ -12,14 +12,18 @@ import { ...@@ -12,14 +12,18 @@ import {
GetSecondDistrictInfo, GetSecondDistrictInfo,
IndustryListPagesType, IndustryListPagesType,
LeaseGoodsListType, LeaseGoodsListType,
LikeOrCancelType,
ListBannerImgType, ListBannerImgType,
ListBrandInfoType, ListBrandInfoType,
ListCompanyInfoByCoopIdType, ListCompanyInfoByCoopIdType,
ListNewsType, ListNewsType,
ListTenderInfoType, ListTenderInfoType,
NewDetailsType, NewDetailsType,
PublishCommentType,
RecommendGoodsType, RecommendGoodsType,
ReplyListType,
RequirementsListType, RequirementsListType,
ReviewLikesType,
} from '@/api/interface/home'; } from '@/api/interface/home';
import request from '@/api/request'; import request from '@/api/request';
...@@ -111,4 +115,20 @@ export class HomeAPI { ...@@ -111,4 +115,20 @@ export class HomeAPI {
// 话题-所有评论 // 话题-所有评论
static getAllCommentList: AllCommentListType = (params) => static getAllCommentList: AllCommentListType = (params) =>
request.post('/release/gambit/allCommentList', params); request.post('/release/gambit/allCommentList', params);
// 话题-评论下的回复
static getReplyList: ReplyListType = (data) =>
request.post('/release/gambit/replyList', data);
// 论坛-评论-发表
static publishComment: PublishCommentType = (data) =>
request.post('/release/dynamic/comment', data);
// 话题-评论/回复点赞,取消
static reviewLikes: ReviewLikesType = (params) =>
request.get('/release/dynamic/reviewLikes', { params });
// 论坛-点赞或取消点赞
static likeOrCancel: LikeOrCancelType = (params) =>
request.get('/release/dynamic/likeOrCancel', { params });
} }
import React from 'react'; import React, { useState } from 'react';
import { LikeOutlined, MessageOutlined } from '@ant-design/icons'; import {
import { Button } from 'antd'; DownOutlined,
LikeOutlined,
MessageOutlined,
UpOutlined,
} from '@ant-design/icons';
import { App, Button, Input } from 'antd';
import styled from 'styled-components'; import styled from 'styled-components';
import { HomeAPI } from '@/api';
import { InterListType } from '@/api/interface'; import { InterListType } from '@/api/interface';
import { AllCommentListType } from '@/api/interface/home'; import { AllCommentListType, ReplyListType } from '@/api/interface/home';
// 详情类型 // 详情类型
type DetailType = InterListType<AllCommentListType>[0]; type DetailType = InterListType<AllCommentListType>[0];
// 列表类型
type ListType = InterListType<ReplyListType>;
const ForumCommentItem: React.FC<{ detail: DetailType }> = ({ detail }) => { const ForumCommentItem: React.FC<{
detail: DetailType;
reply?: ListType;
origin?: DetailType;
onRefresh?: () => void;
}> = ({ detail, reply, origin, onRefresh }) => {
// 静态组件
const { message } = App.useApp();
// 是否显示回复输入
const [isInput, setIsInput] = useState(false);
// 是否展开评论列表
const [isReply, setIsReply] = useState(false);
// 回复列表
const [replyList, setReplyList] = useState<ListType>([]);
// 获取回复列表
const getReplyList = async () => {
const res = await HomeAPI.getReplyList({
dynamicId: detail?.dynamicId,
id: detail?.id,
pageNo: 1,
pageSize: 999,
});
if (res && res.code === '200') {
// console.log('回复列表 ===>', res.result?.list);
setReplyList(res.result?.list || []);
}
};
// 展开评论列表
const handleReply = async (e: Boolean) => {
setIsReply(!e);
if (!e) {
getReplyList().then();
} else {
setReplyList([]);
}
};
// 获取@人的名字
const getReplyName = () => {
if (!reply) return undefined;
const item = reply?.find((i) => i?.id === detail?.pid);
return item ? (
<>
回复&nbsp;
<Button type={'link'} className="px-0">
@{item?.userAccountVO?.nickName}
</Button>
&nbsp;
</>
) : undefined;
};
// 获取@人的名字
const getReplyNameStr = () => {
if (!reply) return `回复 @${detail?.userAccountVO?.nickName} `;
const item = reply?.find((i) => i?.id === detail?.pid);
return item
? `回复 @${item?.userAccountVO?.nickName} `
: `回复 @${detail?.userAccountVO?.nickName} `;
};
// 回复数据
const [replyText, setReplyText] = useState<string>();
// 提交数据
const handleSubmit = async () => {
if (!replyText) {
await message.warning('请输入内容');
return;
}
// 提交数据
const res = await HomeAPI.publishComment({
content: replyText,
dynamicId: detail?.dynamicId,
pid: detail?.id,
reviewId: origin?.id || detail?.id,
});
if (res && res.code === '200') {
message.success('回复成功');
setReplyText(undefined);
setIsInput(false);
onRefresh?.();
}
};
// 点赞
const handleReviewLikes = async () => {
const res = await HomeAPI.reviewLikes({
id: detail?.id,
status: !detail?.status,
});
if (res && res.code === '200') {
message.success(!detail?.status ? '点赞成功' : '取消点赞');
onRefresh?.();
}
};
return ( return (
<ForumCommentWrap> <ForumCommentWrap>
<img <img
...@@ -21,18 +119,68 @@ const ForumCommentItem: React.FC<{ detail: DetailType }> = ({ detail }) => { ...@@ -21,18 +119,68 @@ const ForumCommentItem: React.FC<{ detail: DetailType }> = ({ detail }) => {
{detail?.userAccountVO?.nickName || {detail?.userAccountVO?.nickName ||
`云享飞用户_${detail?.userAccountId}`} `云享飞用户_${detail?.userAccountId}`}
</div> </div>
<div className="text">{detail?.content}</div> <div className="text">
{getReplyName()}
{detail?.content}
</div>
<div className="action"> <div className="action">
<div className="date">{detail?.createTime}</div> <div className="date">{detail?.createTime}</div>
<div className="button"> <div className="button">
<Button type={'link'} icon={<MessageOutlined />}> <Button
回复 type={'text'}
icon={<MessageOutlined />}
onClick={() => setIsInput(!isInput)}
>
{isInput ? '取消回复' : '回复'}
</Button> </Button>
<Button type={'link'} icon={<LikeOutlined />}> <Button
type={'text'}
icon={<LikeOutlined />}
className={!detail?.status ? 'text-333' : 'text-primary'}
onClick={handleReviewLikes}
>
&nbsp;{detail?.likeCount || 0} &nbsp;{detail?.likeCount || 0}
</Button> </Button>
</div> </div>
</div> </div>
{isInput && (
<div className="textarea">
<Input.TextArea
placeholder={getReplyNameStr()}
showCount
style={{ height: 86 }}
maxLength={140}
onChange={(e) => setReplyText(e.target.value)}
/>
<div className="action">
<Button type="primary" shape="round" onClick={handleSubmit}>
发布
</Button>
</div>
</div>
)}
{!!replyList?.length &&
replyList?.map((n, m) => (
<ForumCommentItem
detail={n as any}
key={m}
reply={replyList}
origin={detail}
onRefresh={getReplyList}
/>
))}
{!!detail?.replyCount && (
<div className="flex">
<div className="reply" onClick={() => handleReply(isReply)}>
{!isReply ? `展开${detail?.replyCount}条回复` : `收起`}
</div>
{!isReply ? (
<DownOutlined className="ml-1 text-xs text-999" />
) : (
<UpOutlined className="ml-1 text-xs text-999" />
)}
</div>
)}
</div> </div>
</ForumCommentWrap> </ForumCommentWrap>
); );
...@@ -47,10 +195,12 @@ const ForumCommentWrap = styled.div` ...@@ -47,10 +195,12 @@ const ForumCommentWrap = styled.div`
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: flex-start; justify-content: flex-start;
margin-bottom: 1.5rem; &:not(:first-child) {
margin-top: 1rem;
}
.image { .image {
width: 2.5rem; width: 2.25rem;
height: 2.5rem; height: 2.25rem;
border-radius: 50%; border-radius: 50%;
margin-right: 1rem; margin-right: 1rem;
} }
...@@ -76,5 +226,23 @@ const ForumCommentWrap = styled.div` ...@@ -76,5 +226,23 @@ const ForumCommentWrap = styled.div`
color: #999999; color: #999999;
} }
} }
.textarea {
position: relative;
width: 100%;
box-sizing: border-box;
margin-top: 0.5rem;
.action {
margin-top: 1.5rem;
width: 100%;
display: flex;
justify-content: flex-end;
}
}
.reply {
cursor: pointer;
&:hover {
color: #ff392b;
}
}
} }
`; `;
import React from 'react'; import React, { useEffect, useState } from 'react';
import { import {
ExportOutlined, ExportOutlined,
LikeOutlined, LikeOutlined,
MessageOutlined, MessageOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Image } from 'antd'; import { App, Button, Image } from 'antd';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { HomeAPI } from '@/api';
import { InterListType } from '@/api/interface'; import { InterListType } from '@/api/interface';
import { ForumListType } from '@/api/interface/home'; import { ForumListType } from '@/api/interface/home';
import { RootState } from '@/store';
import { setGlobalData } from '@/store/module/globalData'; import { setGlobalData } from '@/store/module/globalData';
import { SystemState } from '@/store/module/system';
// 详情类型 // 详情类型
type DetailType = InterListType<ForumListType>[0]; type DetailType = InterListType<ForumListType>[0];
const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({ const ForumItemView: React.FC<{
detail, detail: DetailType;
isDetail = false, isDetail?: Boolean;
}) => { hiddenMedia?: Boolean;
onRefresh?: () => void;
}> = ({ detail, isDetail = false, onRefresh, hiddenMedia = false }) => {
// 静态组件
const { message } = App.useApp();
// 路由钩子 // 路由钩子
const router = useRouter(); const router = useRouter();
// system
const system = useSelector((state: RootState) => state.system) as SystemState;
// store // store
const dispatch = useDispatch(); const dispatch = useDispatch();
// 缓存贴子的数据
const [forumDetail, setForumDetail] = useState<DetailType>();
// 获取帖子的媒体信息 0图片 1视频 // 获取帖子的媒体信息 0图片 1视频
const getForumMedia = (type: number) => { const getForumMedia = (type: number) => {
return detail?.mediaVO?.filter((i) => i?.type === type)?.slice(0, 4); return detail?.mediaVO?.filter((i) => i?.type === type)?.slice(0, 4);
...@@ -38,6 +49,32 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({ ...@@ -38,6 +49,32 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({
router.push(`/forum/detail/${detail?.id}`).then(); router.push(`/forum/detail/${detail?.id}`).then();
} }
}; };
// 点赞
const handleReviewLikes = async () => {
// 如果未登录,则弹出登录框
if (!system?.token) {
dispatch(setGlobalData({ loginModalVisible: true }));
return;
}
const res = await HomeAPI.likeOrCancel({
dynamicId: detail?.id,
});
if (res && res.code === '200') {
message.success(!forumDetail?.likes ? '点赞成功' : '取消点赞');
setForumDetail({
...detail,
likes: !forumDetail?.likes,
likesCount: !forumDetail?.likes
? Number(forumDetail?.likesCount) + 1
: Number(forumDetail?.likesCount) - 1,
});
}
};
// 监听变化
useEffect(() => {
if (!detail) return;
setForumDetail(detail);
}, [detail]);
return ( return (
<ForumItemWrap> <ForumItemWrap>
<div className="relative mb-2 flex w-full items-center justify-start"> <div className="relative mb-2 flex w-full items-center justify-start">
...@@ -64,6 +101,7 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({ ...@@ -64,6 +101,7 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({
))} ))}
<span>{detail?.description}</span> <span>{detail?.description}</span>
</div> </div>
{!hiddenMedia && (
<div className="forum-media flex w-full flex-wrap items-start justify-start"> <div className="forum-media flex w-full flex-wrap items-start justify-start">
{getForumMedia(0)?.length {getForumMedia(0)?.length
? getForumMedia(0)?.map((i, j) => ( ? getForumMedia(0)?.map((i, j) => (
...@@ -89,18 +127,27 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({ ...@@ -89,18 +127,27 @@ const ForumItemView: React.FC<{ detail: DetailType; isDetail?: Boolean }> = ({
)) ))
: undefined} : undefined}
</div> </div>
)}
<div className="forum-action flex pb-2 text-777"> <div className="forum-action flex pb-2 text-777">
<div className="action-item mr-8 flex" onClick={() => handleAction(1)}> <div className="action-item mr-6" onClick={() => handleAction(1)}>
<LikeOutlined /> <Button
<div className="ml-1">{detail?.likesCount}</div> type={'text'}
icon={<LikeOutlined />}
className={!forumDetail?.likes ? 'text-333' : 'text-primary'}
onClick={handleReviewLikes}
>
&nbsp;{forumDetail?.likesCount}
</Button>
</div> </div>
<div className="action-item mr-8 flex" onClick={() => handleAction(2)}> <div className="action-item mr-6" onClick={() => handleAction(2)}>
<MessageOutlined /> <Button type={'text'} icon={<MessageOutlined />}>
<div className="ml-1">{detail?.commentCount}</div> &nbsp;{forumDetail?.commentCount}
</Button>
</div> </div>
<div className="action-item mr-8 flex" onClick={() => handleAction(3)}> <div className="action-item mr-6" onClick={() => handleAction(3)}>
<ExportOutlined /> <Button type={'text'} icon={<ExportOutlined />}>
<div className="ml-1">{detail?.transpond}</div> &nbsp;{forumDetail?.transpond || 0}
</Button>
</div> </div>
</div> </div>
</ForumItemWrap> </ForumItemWrap>
......
import React from 'react';
import styled from 'styled-components';
import { InterListType } from '@/api/interface';
import { AllCommentListType } from '@/api/interface/home';
// 详情类型
type DetailType = InterListType<AllCommentListType>[0];
const ForumReplyItem = () => {
return (
<ForumReplyWrap>
<div>ForumReplyItem</div>
</ForumReplyWrap>
);
};
export default ForumReplyItem;
// 样式
const ForumReplyWrap = styled.div`
position: relative;
width: 100%;
box-sizing: border-box;
display: flex;
align-items: flex-start;
justify-content: flex-start;
margin-bottom: 1.5rem;
.image {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
margin-right: 1rem;
}
.content {
position: relative;
width: calc(100% - 3.5rem);
box-sizing: border-box;
}
`;
...@@ -8,6 +8,7 @@ import { AllCommentListType, ForumDetailType } from '@/api/interface/home'; ...@@ -8,6 +8,7 @@ import { AllCommentListType, ForumDetailType } from '@/api/interface/home';
import ForumCommentItem from '@/components/forumCommentItem'; import ForumCommentItem from '@/components/forumCommentItem';
import ForumItemView from '@/components/forumItem'; import ForumItemView from '@/components/forumItem';
import LayoutView from '@/components/layout'; import LayoutView from '@/components/layout';
import DetailForumList from '@/pages/forum/detail/comp/_detailForumList';
import { wrapper } from '@/store'; import { wrapper } from '@/store';
import { setGlobalData } from '@/store/module/globalData'; import { setGlobalData } from '@/store/module/globalData';
import { UserInfoState } from '@/store/module/userInfo'; import { UserInfoState } from '@/store/module/userInfo';
...@@ -58,7 +59,7 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({ ...@@ -58,7 +59,7 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({
{ totalPage: number; totalCount: number } & PaginationProps { totalPage: number; totalCount: number } & PaginationProps
>({ >({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 999,
totalPage: 0, totalPage: 0,
totalCount: 0, totalCount: 0,
}); });
...@@ -75,8 +76,9 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({ ...@@ -75,8 +76,9 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({
if (res && res.code === '200') { if (res && res.code === '200') {
const { list, totalPage, pageNo, pageSize, totalCount } = const { list, totalPage, pageNo, pageSize, totalCount } =
res.result || {}; res.result || {};
console.log('评论列表 ===>', list); // console.log('评论列表 ===>', list);
setCommentList((prevList) => [...prevList, ...(list || [])]); setCommentList(list || []);
// setCommentList((prevList) => [...prevList, ...(list || [])]);
pagination.totalPage = totalPage; pagination.totalPage = totalPage;
setPagination({ pageNo, pageSize, totalPage, totalCount }); setPagination({ pageNo, pageSize, totalPage, totalCount });
} }
...@@ -115,11 +117,17 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({ ...@@ -115,11 +117,17 @@ const ForumDetailPage: React.FC<{ forumDetail: DetailType }> = ({
<div className="detail-list"> <div className="detail-list">
<div className="list-title">评论列表</div> <div className="list-title">评论列表</div>
{commentList?.map((i, j) => ( {commentList?.map((i, j) => (
<ForumCommentItem key={j} detail={i} /> <ForumCommentItem
key={j}
detail={i}
onRefresh={getAllCommentList}
/>
))} ))}
</div> </div>
</div> </div>
<div className="forum-order">45345</div> <div className="forum-order">
<DetailForumList />
</div>
</div> </div>
</ForumDetailWrap> </ForumDetailWrap>
</LayoutView> </LayoutView>
...@@ -183,6 +191,7 @@ const ForumDetailWrap = styled.div` ...@@ -183,6 +191,7 @@ const ForumDetailWrap = styled.div`
.detail-list { .detail-list {
position: relative; position: relative;
width: 100%; width: 100%;
margin-bottom: 2rem;
.list-title { .list-title {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
...@@ -193,7 +202,6 @@ const ForumDetailWrap = styled.div` ...@@ -193,7 +202,6 @@ const ForumDetailWrap = styled.div`
.forum-order { .forum-order {
position: relative; position: relative;
width: 30%; width: 30%;
background: lightgreen;
} }
} }
`; `;
import React, { useEffect, useState } from 'react';
import { Affix } from 'antd';
import styled from 'styled-components';
import { HomeAPI } from '@/api';
import { InterListType, PaginationProps } from '@/api/interface';
import { ForumListType } from '@/api/interface/home';
import ForumItemView from '@/components/forumItem';
// 列表类型
type ListType = InterListType<ForumListType>;
const DetailForumList = () => {
// 翻页数据
const [pagination, setPagination] = useState<
{ totalPage: number } & PaginationProps
>({
pageNo: 1,
pageSize: 5,
totalPage: 0,
});
// 论坛列表
const [forumList, setForumList] = useState<ListType>([]);
// 获取论坛列表
const getForumList = async () => {
const res = await HomeAPI.getForumList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
});
if (res && res.code === '200') {
const { list, totalPage, pageNo, pageSize } = res.result || {};
setForumList((prevList) => [...prevList, ...(list || [])]);
pagination.totalPage = totalPage;
setPagination({ pageNo, pageSize, totalPage });
}
};
// 组件挂载
useEffect(() => {
getForumList().then();
}, []);
return (
<Affix offsetTop={58}>
<DetailForumWrap>
<div className="mb-4 text-base font-bold">最新动态</div>
<div className="list scroll-view w-full">
{forumList?.map((i, j) => (
<ForumItemView key={j} detail={i} hiddenMedia={true} />
))}
</div>
</DetailForumWrap>
</Affix>
);
};
export default DetailForumList;
// 样式
const DetailForumWrap = styled.div`
position: relative;
width: 100%;
box-sizing: border-box;
.list {
position: relative;
box-sizing: border-box;
height: 70vh;
overflow: hidden;
overflow-y: scroll;
}
`;
...@@ -12,6 +12,9 @@ const themeConfig: ThemeConfig = { ...@@ -12,6 +12,9 @@ const themeConfig: ThemeConfig = {
colorLinkHover: '#e1251b', colorLinkHover: '#e1251b',
contentFontSize: 12, contentFontSize: 12,
}, },
Input: {
colorBgContainer: '#F5F5F6',
},
}, },
}; };
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论