460 lines
14 KiB
Vue
460 lines
14 KiB
Vue
<template>
|
|
<view class="flex items-center pb-36rpx">
|
|
<image
|
|
src="@img/chef/1330.png"
|
|
mode="aspectFill"
|
|
class="w-44rpx h-44rpx shrink-0 mr-12rpx"
|
|
/>
|
|
{{ t('common.comment') }}({{ props.tableTotal }})
|
|
</view>
|
|
<template v-if="dataList && dataList.length">
|
|
<view class="c_comment" v-for="(item1, index1) in dataList" :key="item1.id">
|
|
<!-- 一级评论 -->
|
|
<CommonComp
|
|
:data="item1"
|
|
@likeClick="() => likeClick({ item1, index1 })"
|
|
@replyClick="() => replyClick({ item1, index1 })"
|
|
@deleteClick="() => deleteClick({ item1, index1 })"
|
|
/>
|
|
<view class="children_item bg-#F5F7FB rounded-16rpx" v-if="item1.childrenShow && item1.childrenShow.length> 0">
|
|
<!-- 二级评论 -->
|
|
<CommonComp
|
|
v-for="(item2, index2) in item1.childrenShow"
|
|
:key="item2.id"
|
|
:data="item2"
|
|
:pData="item1"
|
|
@likeClick="() => likeClick({ item1, index1, item2, index2 })"
|
|
@replyClick="() => replyClick({ item1, index1, item2, index2 })"
|
|
@deleteClick="() => deleteClick({ item1, index1, item2, index2 })"
|
|
/>
|
|
</view>
|
|
<view class="flex items-center pl-100rpx text-#666 pt-10rpx" v-if="item1.children || item1.commentCount> 0">
|
|
<!-- 展开二级评论 -->
|
|
<view
|
|
class="flex items-center"
|
|
@click="expandReply(item1)"
|
|
>
|
|
<text>{{ t('pages-user.recipe.expandReply') }}</text>
|
|
<wd-icon name="chevron-down" class="mt-4rpx" size="22px"></wd-icon>
|
|
</view>
|
|
<!-- 折叠二级评论 -->
|
|
<view
|
|
class="flex items-center"
|
|
@click="shrinkReply(item1)"
|
|
>
|
|
<text>{{ t('pages-user.recipe.collapseReply') }}</text>
|
|
<wd-icon name="chevron-up" class="mt-4rpx" size="22px"></wd-icon>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<!-- 空盒子 -->
|
|
<view class="empty_box" v-else>
|
|
<view class="py-100rpx center">
|
|
<image class="w-250rpx h-250rpx" src="@img/chef/100.png"></image>
|
|
</view>
|
|
</view>
|
|
<!-- 评论弹窗 -->
|
|
<wd-popup ref="cPopupRef" v-model="cPopupShow" custom-style="border-radius:16rpx 16rpx 0 0;" position="bottom" @change="popChange">
|
|
<view class="w-full rounded-16rpx px-30rpx py-16rpx">
|
|
<view class="flex items-center">
|
|
<template v-if="Object.keys(replyTemp).length">
|
|
<text class="text_aid">{{ t('pages-user.recipe.replyTo') }}</text>
|
|
<image class="w-68rpx h-68rpx rounded-50% mx-10rpx" :src="replyTemp.item2 ? replyTemp.item2.user_avatar : replyTemp.item1.user_avatar" />
|
|
<text class="text_main">{{ replyTemp.item2 ? replyTemp.item2.user_name : replyTemp.item1.user_name }}</text>
|
|
</template>
|
|
</view>
|
|
<view class="w-full flex-center-sb gap-30rpx bg-white py-12rpx">
|
|
<view class="w-full h-74rpx center bg-#F6F6F6 rounded-16rpx px-28rpx">
|
|
<wd-input
|
|
no-border
|
|
clearable
|
|
:focus-when-clear="false"
|
|
confirm-type="send"
|
|
use-prefix-slot
|
|
custom-class="flex items-center !text-30rpx !bg-transparent flex-1"
|
|
placeholderStyle="font-size: 30rpx;color: #6D6D6D; font-weight: 500;"
|
|
@confirm="sendClick"
|
|
v-model="commentValue"
|
|
:placeholder="commentPlaceholder"
|
|
>
|
|
</wd-input>
|
|
</view>
|
|
<wd-button @click="sendClick" class="!h-74rpx !w-120rpx !rounded-16rpx !bg-#333 !text-white !text-30rpx">{{ t('common.send') }}</wd-button>
|
|
</view>
|
|
</view>
|
|
</wd-popup>
|
|
<wd-message-box/>
|
|
</template>
|
|
|
|
<script setup>
|
|
import CommonComp from "./componets/common";
|
|
import {appCommentDeleteCommentIdDelete, appCommentPublishCommentPost, appCommentReplyListPost} from "@/service";
|
|
|
|
import {useMessage} from "wot-design-uni";
|
|
import {formatTimestampWithMonthName} from "@/utils/utils";
|
|
const message = useMessage();
|
|
const { t } = useI18n();
|
|
|
|
const props = defineProps({
|
|
/** 登陆用户信息
|
|
* id: number // 登陆用户id
|
|
* user_name: number // 登陆用户名
|
|
* user_avatar: string // 登陆用户头像地址
|
|
*/
|
|
myInfo: {
|
|
type: Object,
|
|
default: () => {},
|
|
},
|
|
/** 文章作者信息
|
|
* id: number // 文章作者id
|
|
* user_name: number // 文章作者名
|
|
* user_avatar: string // 文章作者头像地址
|
|
*/
|
|
userInfo: {
|
|
type: Object,
|
|
default: () => {},
|
|
},
|
|
/** 评论列表
|
|
* id: number // 评论id
|
|
* parent_id: number // 父级评论id
|
|
* reply_id: number // 被回复人评论id
|
|
* reply_name: string // 被回复人名称
|
|
* user_name: string // 用户名
|
|
* user_avatar: string // 评论者头像地址
|
|
* user_content: string // 评论内容
|
|
* is_like: boolean // 是否点赞
|
|
* like_count: number // 点赞数统计
|
|
* create_time: string // 创建时间
|
|
*/
|
|
tableData: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
// 评论总数
|
|
tableTotal: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
// 评论删除模式
|
|
// bind - 当被删除的一级评论存在回复评论, 那么该评论内容变更显示为[当前评论内容已被移除]
|
|
// only - 仅删除当前评论(后端删除相关联的回复评论, 否则总数显示不对)
|
|
// all - 删除所有评论包括回复评论
|
|
deleteMode: {
|
|
type: String,
|
|
default: "all",
|
|
},
|
|
});
|
|
const emit = defineEmits([
|
|
"update:tableTotal",
|
|
"likeFun", // 点赞事件
|
|
"replyFun", // 回复事件
|
|
"deleteFun", // 删除事件
|
|
]);
|
|
|
|
// 渲染数据(前端的格式)
|
|
let dataList = ref([]);
|
|
watch(
|
|
() => props.tableData,
|
|
(newVal) => {
|
|
if (newVal.length !== dataList.value.length) {
|
|
let temp = props.tableData;
|
|
dataList.value = treeTransForm(temp);
|
|
}
|
|
},
|
|
{ deep: true, immediate: true }
|
|
);
|
|
|
|
// 数据转换
|
|
function treeTransForm(data) {
|
|
let newData = JSON.parse(JSON.stringify(data));
|
|
let result = [];
|
|
let map = {};
|
|
newData.forEach((item, i) => {
|
|
item.owner = item.user_id === props.myInfo.user_id; // 是否为当前登陆用户 可以对自己的评论进行删除 不能回复
|
|
// item.author = item.user_id === props.userInfo.user_id; // 是否为作者 显示标记
|
|
map[item.id] = item;
|
|
});
|
|
newData.forEach((item) => {
|
|
let parent = map[item.parent_id];
|
|
if (parent) {
|
|
(parent.children || (parent.children = [])).push(item); // 所有回复
|
|
if (parent.children.length === 1) {
|
|
(parent.childrenShow = []).push(item); // 显示的回复
|
|
}
|
|
} else {
|
|
result.push(item);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
// 点赞
|
|
let setLike = (item) => {
|
|
item.is_like = !item.is_like;
|
|
item.like_count = item.is_like ? item.like_count + 1 : item.like_count - 1;
|
|
};
|
|
function likeClick({ item1, index1, item2, index2 }) {
|
|
let item = item2 || item1;
|
|
setLike(item);
|
|
emit("likeFun", { params: item }, (res) => {
|
|
// 请求后端失败, 重置点赞
|
|
setLike(item);
|
|
});
|
|
}
|
|
|
|
// 回复
|
|
let cPopupRef = ref(null); // 弹窗实例
|
|
const cPopupShow = ref(false); // 弹窗显示状态
|
|
let replyTemp = reactive({}); // 临时数据
|
|
function replyClick({ item1, index1, item2, index2 }) {
|
|
replyTemp = JSON.parse(JSON.stringify({ item1, index1, item2, index2 }));
|
|
cPopupShow.value = true;
|
|
}
|
|
|
|
// 发起新评论
|
|
let isNewComment = ref(false); // 是否为新评论
|
|
defineExpose({ newCommentFun });
|
|
function newCommentFun() {
|
|
isNewComment.value = true;
|
|
cPopupShow.value = true;
|
|
}
|
|
|
|
// 评论弹窗
|
|
let focus = ref(false);
|
|
function popChange(e) {
|
|
// 关闭弹窗
|
|
if (!e.show) {
|
|
commentValue.value = ""; // 清空输入框值
|
|
replyTemp = {}; // 清空被回复人信息
|
|
isNewComment.value = false; // 恢复是否为新评论默认值
|
|
}
|
|
focus.value = e.show;
|
|
}
|
|
let commentValue = ref(""); // 输入框值
|
|
let commentPlaceholder = ref("说点什么..."); // 输入框占位符
|
|
|
|
// 发送评论
|
|
function sendClick({ item1, index1, item2, index2 } = replyTemp) {
|
|
console.log('replyTemp', replyTemp.item1)
|
|
console.log('replyTemp', replyTemp.item2)
|
|
const data = replyTemp.item2 || replyTemp.item1
|
|
appCommentPublishCommentPost({
|
|
body: {
|
|
topId: replyTemp.item2 ? replyTemp.item1.id : data.id,
|
|
parentId:data.id,
|
|
targetId: data.target_id,
|
|
targetType: 1,
|
|
content: commentValue.value,
|
|
}
|
|
}).then(res=> {
|
|
console.log(res)
|
|
emit("update");
|
|
cPopupShow.value = false;
|
|
commentValue.value = ""; // 清空输入框值
|
|
// shrinkReply(replyTemp.item1)
|
|
dataList.value.forEach((item, i) => {
|
|
if (item.id === replyTemp.item1.id) {
|
|
shrinkReply(item)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
function expandReply(item1) {
|
|
// item1.childrenShow = item1.children
|
|
console.log(item1)
|
|
appCommentReplyListPost({
|
|
params: {
|
|
pageNum: 1,
|
|
pageSize: 100,
|
|
},
|
|
body: {
|
|
parentId: item1.id,
|
|
}
|
|
}).then(res=> {
|
|
console.log('回复列表', res)
|
|
item1.children = res.rows.map(item => {
|
|
let userInfo = {}
|
|
// 普通用户
|
|
if (+item.userPort === 1) {
|
|
userInfo.user_id = item.userVo.id
|
|
userInfo.user_name = `${item.userVo.firstName} ${item.userVo.surname}`
|
|
userInfo.user_avatar = item.userVo.avatar
|
|
} else {
|
|
userInfo.user_id = item.merchantVo.userId
|
|
userInfo.user_name = item.merchantVo.merchantName
|
|
userInfo.user_avatar = item.merchantVo.logo
|
|
}
|
|
return {
|
|
id: item.id,
|
|
topId: item.topId,
|
|
parent_id: null, // 评论父级的id
|
|
reply_id: null, // 被回复评论的id
|
|
reply_name: item.parentUserVo ? `${item.parentUserVo.firstName} ${item.parentUserVo.surname}` : null, // 被回复人名称
|
|
target_id: item1.target_id,
|
|
commentCount: item.commentCount,
|
|
user_id: userInfo.user_id, // 用户id
|
|
user_name: userInfo.user_name, // 用户名
|
|
user_avatar: userInfo.user_avatar, // 用户头像地址
|
|
user_content: item.content, // 用户评论内容
|
|
create_time: formatTimestampWithMonthName(item.createTime), // 创建时间
|
|
owner: userInfo.user_id === props.myInfo.user_id, // 是否为当前登陆用户 可以对自己的评论进行删除 不能回复
|
|
}
|
|
})
|
|
item1.childrenShow = item1.children
|
|
})
|
|
}
|
|
|
|
function shrinkReply(item1) {
|
|
item1.childrenShow = []
|
|
}
|
|
|
|
// 删除
|
|
const delPopupRef = ref(null);
|
|
let delTemp = reactive({}); // 临时数据
|
|
function deleteClick({ item1, index1, item2, index2 }) {
|
|
console.log('删123除', item1, index1, item2, index2)
|
|
message
|
|
.confirm({
|
|
title: t("common.prompt.system-prompt"),
|
|
msg: `${t("common.prompt.system-prompt-delete")}`,
|
|
confirmButtonText: t("common.yes"),
|
|
cancelButtonText: t("common.no"),
|
|
cancelButtonProps: {
|
|
customClass:
|
|
"!h-88rpx !w-258rpx !min-w-auto !text-30rpx !lh-42rpx !font-bold !border-#666666 !rounded-20rpx",
|
|
},
|
|
confirmButtonProps: {
|
|
customClass:
|
|
"!h-88rpx !w-258rpx !min-w-auto !text-30rpx !lh-42rpx !font-bold !bg-primary !rounded-20rpx",
|
|
},
|
|
})
|
|
.then(async () => {
|
|
appCommentDeleteCommentIdDelete({
|
|
params: {
|
|
id: item2.id ? item2.id : item1.id,
|
|
}
|
|
}).then(res=> {
|
|
console.log('删除成功', res)
|
|
emit("deleteFun");
|
|
shrinkReply(item1)
|
|
})
|
|
})
|
|
.catch(() => {
|
|
});
|
|
}
|
|
|
|
// 展开评论if
|
|
function expandTxtShow({ item1, index1 }) {
|
|
return item1.childrenShow?.length && item1.children.length - item1.childrenShow.length;
|
|
}
|
|
// 展开更多评论
|
|
function expandReplyFun({ item1, index1 }) {
|
|
let csLen = dataList.value[index1].childrenShow.length;
|
|
dataList.value[index1].childrenShow.push(
|
|
...dataList.value[index1].children.slice(csLen, csLen + 6) // 截取5条评论
|
|
);
|
|
}
|
|
|
|
// 收起评论if
|
|
function shrinkTxtShow({ item1, index1 }) {
|
|
return item1.childrenShow?.length >= 2 && item1.children.length - item1.childrenShow.length === 0;
|
|
}
|
|
// 收起更多评论
|
|
function shrinkReplyFun({ item1, index1 }) {
|
|
let csLen = dataList.value[index1].childrenShow.length;
|
|
dataList.value[index1].childrenShow = [];
|
|
dataList.value[index1].childrenShow.push(
|
|
...dataList.value[index1].children.slice(0, 1) // 截取1条评论
|
|
);
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
////////////////////////
|
|
.center {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
////////////////////////
|
|
.c_total {
|
|
//padding: 20rpx 30rpx 0 30rpx;
|
|
font-size: 28rpx;
|
|
}
|
|
.empty_box {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
flex-direction: column;
|
|
padding: 150rpx 10rpx;
|
|
font-size: 28rpx;
|
|
.txt {
|
|
//color: $uni-text-color-disable;
|
|
}
|
|
.click {
|
|
//color: $uni-color-primary;
|
|
}
|
|
}
|
|
.c_comment {
|
|
//padding: 20rpx 30rpx;
|
|
font-size: 28rpx;
|
|
|
|
.children_item {
|
|
padding: 20rpx 30rpx;
|
|
margin-top: 10rpx;
|
|
margin-left: 80rpx;
|
|
//background-color: $uni-bg-color-grey;
|
|
.expand_reply,
|
|
.shrink_reply {
|
|
margin-top: 10rpx;
|
|
margin-left: 80rpx;
|
|
.txt {
|
|
font-weight: 600;
|
|
//color: $uni-color-primary;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.c_popup_box {
|
|
background-color: #fff;
|
|
.reply_text {
|
|
@extend .center;
|
|
padding: 20rpx 20rpx 0 20rpx;
|
|
font-size: 26rpx;
|
|
.text_aid {
|
|
//color: $uni-text-color-grey;
|
|
margin-right: 5rpx;
|
|
}
|
|
.user_avatar {
|
|
width: 48rpx;
|
|
height: 48rpx;
|
|
border-radius: 50%;
|
|
margin-right: 6rpx;
|
|
margin-left: 12rpx;
|
|
}
|
|
.text_main {
|
|
}
|
|
}
|
|
.content {
|
|
@extend .center;
|
|
.text_area {
|
|
flex: 1;
|
|
padding: 20rpx;
|
|
}
|
|
.send_btn {
|
|
@extend .center;
|
|
justify-content: center;
|
|
width: 120rpx;
|
|
height: 60rpx;
|
|
border-radius: 20rpx;
|
|
font-size: 28rpx;
|
|
color: #fff;
|
|
//background-color: $uni-color-primary;
|
|
margin-right: 20rpx;
|
|
margin-left: 5rpx;
|
|
}
|
|
}
|
|
}
|
|
</style>
|