mcwl-pc/app/components/PlanetComment.vue

668 lines
18 KiB
Vue

<script setup lang="ts">
// import { NConfigProvider, NInfiniteScroll, NInput } from 'naive-ui'
import {
EllipsisVertical,
Star,
ThumbsUp,
} from 'lucide-vue-next'
import { watch } from 'vue'
interface LikeParams {
id: string | number
commentId?: string | number
communityId?: string | number
tenantId?: string | number
publishId?: string | number
}
const props = defineProps({
isMy: {
type: Number,
default: 0,
},
height: {
type: Number,
default: 800,
},
type: {
type: String,
default: '',
},
publishListParams: {
type: Object,
default: () => ({}),
},
})
// const $props = defineProps(['headUrl', 'dataList', 'height'])
const userStore = useUserStore()
const message = useMessage()
// 发布评论
const commentParams = ref({
content: '',
parentId: '',
replyUserId: '',
userId: userStore?.userInfo?.userId,
workFlowId: props.publishListParams.id,
})
function commentParamsInit() {
commentParams.value.content = ''
commentParams.value.replyUserId = ''
commentParams.value.parentId = ''
}
const isShowSend = ref(false)
const publicWord = ref('')
// 评论列表
const commentList = ref([])
async function getCommentList() {
try {
const url = props.publishListParams.isMy === 1 ? '/personHome/getPersonHomeList' : '/publish/publishList'
const res = await request.post(url, props.publishListParams)
if (res.code === 200) {
for (let i = 0; i < res.rows.length; i++) {
res.rows[i].isShowInput = false
res.rows[i].isShowSend = false
if (res.rows[i].contentList && res.rows[i].contentList.length > 0) {
for (let j = 0; j < res.rows[i].contentList.length; j++) {
res.rows[i].contentList[j].isShowInput = false
res.rows[i].contentList[j].isShowSend = false
}
}
}
commentList.value = res.rows
}
}
catch (error) {
console.error(error)
}
// try {
// let url = ''
// if (props.type === 'workflow') {
// url = `${urlList.value[props.type]}commentId=${props.detailsInfo.id}&sortType=${sortType.value}`
// }
// else if (props.type === 'pictrue') {
// url = `${urlList.value[props.type]}imageId=${props.detailsInfo.id}&sortType=${sortType.value}`
// }
// else {
// url = `${urlList.value[props.type]}modelId=${props.detailsInfo.id}&sortType=${sortType.value}`
// }
// const res = await request.get(url)
// for (let i = 0; i < res.data.length; i++) {
// res.data[i].isShowInput = false
// res.data[i].isShowSend = false
// if (res.data[i].contentList.length > 0) {
// for (let j = 0; j < res.data[i].contentList.length; j++) {
// res.data[i].contentList[j].isShowInput = false
// res.data[i].contentList[j].isShowSend = false
// }
// }
// }
// commentList.value = res.data
// }
// catch (error) {
// console.log(error)
// }
}
// getCommentList()
// 监听 publishListParams 变化
watch(
() => props.publishListParams,
() => {
if (props.publishListParams.type !== 999) {
if (props.publishListParams.communityId && props.publishListParams.tenantId) {
getCommentList()
}
}
},
{ deep: true, immediate: true },
)
function handleBlur(ele) {
// 默认评价
if (!ele) {
isShowSend.value = !!publicWord.value
}
else {
ele.isShowSend = !!ele.word
}
}
// 发送评论
async function sendMessage(type: string, ele: any, index: number, subIndex?: number) {
if (ele && ele.userId) {
try {
if (ele.word) {
commentParams.value.content = ele.word
commentParams.value.publishId = commentList.value[index].id
if (type === 'sub') {
commentParams.value.parentId = commentList.value[index].commentList[subIndex].id
}
else {
commentParams.value.parentId = commentList.value[index].id
}
commentParams.value.communityId = props.publishListParams.communityId
commentParams.value.tenantId = props.publishListParams.tenantId
const res = await request.post(`/publishComment/save`, commentParams.value)
if (res.code === 200) {
ele.word = ''
message.success('评论成功!')
getCommentList()
// getCommentNum()
commentParamsInit()
}
}
else {
message.warning('评论不能为空!')
}
}
catch (error) {
console.log(error)
}
}
}
// 查询条数
// async function getCommentNum() {
// if (props.type !== 'pictrue') {
// try {
// const res = await request.get(`${commentNumUrl.value[props.type]}=${props.detailsInfo.id}`)
// if (res.code === 200) {
// commentCount.value = res.data
// }
// }
// catch (error) {
// console.log(error)
// }
// }
// }
// getCommentNum()
// 点赞/取消点赞
async function handleFocus(type: string, item: any) {
const params: LikeParams = { id: '' }
if (type === 'parent') {
params.communityId = item.item.communityId
params.publishId = item.item.id
params.tenantId = item.item.tenantId
}
else {
const { id, communityId, tenantId } = item.sub
params.commentId = id
params.communityId = communityId
params.tenantId = tenantId
params.publishId = item.item.id
}
try {
const url = type === 'sub' ? '/publishComment/like' : '/PublishLike/like'
const res = await request.post(url, params)
if (res.code === 200) {
// message.success('删除成功!')
getCommentList()
}
}
catch (error) {
console.log(error)
}
// const { id, communityId, tenantId, operatorId } = item
// const res = await request.post(`PublishLike/like`, { commentId: id, communityId, tenantId, operatorId })
// if (res.code === 200) {
// if (item.isLike === 0) {
// item.isLike = 1
// item.likeNum++
// message.success('点赞成功!')
// }
// else {
// item.isLike = 0
// item.likeNum--
// message.success('取消点赞成功!')
// }
// }
}
// 收藏/取消收藏handleCollect
async function handleCollect(item: any) {
const params = {
publishId: item.id,
communityId: item.communityId,
tenantId: item.tenantId,
}
try {
const res = await request.post('/publish/collect', params)
if (res.code === 200) {
// message.success('删除成功!')
getCommentList()
}
}
catch (error) {
console.log(error)
}
}
// 显示回复框
function handleMessage(item: any) {
if (!item.isShowInput) {
item.word = ''
}
item.isShowInput = !item.isShowInput
}
// 删除评论
async function handleDel(type: string, item: any) {
const params = {}
if (type === 'parent') {
params.publishId = item.item.id
params.communityId = item.item.communityId
}
else {
const { id, communityId, tenantId } = item.sub
params.id = id
params.communityId = communityId
params.tenantId = tenantId
params.publishId = item.item.id
}
try {
const url = type === 'sub' ? '/publishComment/delete' : '/publish/remove'
const res = await request.post(url, params)
if (res.code === 200) {
message.success('删除成功!')
getCommentList()
}
}
catch (error) {
console.log(error)
}
}
async function handleSelect(event: any, type: string, item: any) {
event.stopPropagation() // 阻止事件冒泡
if (type === 'choiceness') {
try {
const res = await request.get(`publish/elite?publishId=${item.id}&communityId=${item.communityId}`)
if (res.code === 200) {
message.success(item.isElite === 1 ? '取消精选成功!' : '精选成功!')
getCommentList()
}
}
catch (error) {
console.log(error)
}
}
else if (type === 'complaint') {
console.log('投诉')
}
else if (type === 'delete') {
console.log('删除')
}
}
</script>
<template>
<div class="bg-white py-4 rounded min-h-[320px]">
<div
v-for="(item, index) in commentList"
:key="index"
class="px-4"
>
<div class="nav-wrap">
<div class="left-img">
<img :src="item.avatar">
</div>
<div class="right">
<div class="name flex justify-between items-center relative">
<span>{{ item.userName }}</span>
<img
v-if="item.isElite === 1"
class="cursor-pointer absolute right-0 top-[4px] w-10 h-10"
src="@/assets/img/elite.png"
alt=""
@click="showActivityList"
>
<div class="relative group">
<span>
<EllipsisVertical size="16" class="cursor-pointer rotate-90" />
</span>
<div
class="absolute right-0 top-[4px] hidden group-hover:block text-gray-500 text-[12px] bg-white rounded-lg text-center px-2 py-2 w-20 mt-2 shadow-lg z-10"
>
<!-- v-if="props.publishListParams.type === 0" -->
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'choiceness', item)"
>
{{ item.isElite === 1 ? '取消精选' : '精选' }}
</div>
<!-- <template v-if="userStore?.userInfo?.userId === detailsInfo.userId"> -->
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'complaint', item)"
>
投诉
</div>
<!-- <div
v-if="props.publishListParams.type === 0"
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'delete')"
>
删除
</div> -->
<!-- </template> -->
</div>
</div>
</div>
<div class="des">
{{ item.content }}
</div>
<div class="star-wrap">
<span class="time">{{ item.createTime }}</span>
<div class="star-operator">
<div class="icon-wrap">
<ThumbsUp size="16" class="mr-1" :color="item.isLike !== 0 ? '#ff0000' : '#000000'" @click="handleFocus('parent', { item })" />
<span style="vertical-align: middle">{{ item.likeNum }}</span>
</div>
<div class="icon-wrap">
<Star size="16" class="mr-1" :color="item.isCollect !== 0 ? '#ff0000' : '#000000'" @click="handleCollect(item)" />
</div>
<span class="cursor-pointer m-r16" @click="handleMessage(item)">回复</span>
<span class="cursor-pointer" @click="handleDel('parent', { item })">删除</span>
</div>
</div>
<!-- 父项评论回复操作 -->
<div v-if="item.isShowInput" class="input-wrap" style="margin-top: 10px;">
<NConfigProvider inline-theme-disabled style="width:100%">
<NInput
v-model:value="item.word"
type="textarea"
:autosize="{ minRows: 1 }"
:placeholder="`回复: @${item.userName}`"
class="text"
@focus="item.isShowSend = true"
@blur="handleBlur(item)"
/>
</NConfigProvider>
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage('parent', item, index)">
<span v-if="item.isShowSend">发送</span>
</div>
</div>
</div>
</div>
<div class="child-wrap">
<div v-for="(ele, subIndex) in item.commentList" :key="subIndex" class="child-wrap-item">
<div class="left-img">
<img :src="ele.userAvatar">
</div>
<div class="right">
<div class="name">
{{ ele.userName }}
<!-- <div v-if="ele.userId === props.detailsInfo.userId" class="author">
作者
</div> -->
</div>
<div class="des">
<span v-if="ele.replyUserName">
<span>回复</span>
<span class="u-name">@{{ ele.replyUserName }}</span>
</span>
{{ ele.content }}
</div>
<div class="star-wrap">
<span class="time">{{ ele.createTime }}</span>
<div class="star-operator">
<div class="icon-wrap">
<ThumbsUp size="16" class="mr-1" :color="ele.isLike !== 0 ? '#ff0000' : '#000000'" @click="handleFocus('sub', { sub: ele, item })" />
<span style="vertical-align: middle">{{ ele.likeNum }}</span>
</div>
<span class="cursor-pointer m-r16" @click="handleMessage(ele)">回复</span>
<span v-if="item.userId === userStore?.userInfo?.userId" class="cursor-pointer" @click="handleDel('sub', { item, sub: ele })">删除</span>
</div>
</div>
<!-- 子项评论回复操作 -->
<div v-if="ele.isShowInput" class="input-wrap" style="margin-top: 10px;">
<NConfigProvider inline-theme-disabled style="width:100%">
<NInput
v-model:value="ele.word"
type="textarea"
:autosize="{ minRows: 1 }"
:placeholder="`回复: @${ele.userName}`"
class="text"
@focus="ele.isShowSend = true"
@blur="handleBlur(ele)"
/>
</NConfigProvider>
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage('sub', ele, index, subIndex)">
<span v-if="ele.isShowSend">发送</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="no-more">
暂时没有更多评论
</div>
</div>
</template>
<style scoped lang="scss">
.header-wrap {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
.left {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
border: 1px solid #2d28ff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.right {
}
}
.input-wrap {
display: flex;
align-items: center;
line-height: 1.55;
border-radius: 8px;
caret-color: #999;
font-size: 14px;
background: #f2f5f9;
padding: 10px 12px;
flex: 1;
:deep(.n-input) {
--n-padding-left: 0 !important;
--n-border: 0 !important;
--n-border-hover: 0 !important;
--n-border-focus: 0 !important;
--n-box-shadow-focus: unset;
--n-padding-vertical: 0px !important;
&::hover {
border: 0;
}
&:active,
&:focus {
border: 0 !important;
}
background-color: transparent;
}
.send-btn {
margin-left: 16px;
margin-right: 16px;
flex-shrink: 0;
color: #999;
font-size: 14px;
cursor: pointer;
&.active {
color: #222;
}
}
}
.nav-wrap {
margin: 10px 0;
display: flex;
font-size: 14px;
// align-items: center;
.left-img {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.right {
width: 100%;
.name {
margin-top: 10px;
margin-bottom: 7px;
font-weight: 500;
color: #333;
}
.des {
line-height: 1.25;
}
.star-wrap {
margin-top: 4px;
display: flex;
align-items: center;
justify-content: space-between;
.time {
color: #999;
font-size: 12px;
}
.star-operator {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
cursor: pointer;
.icon-wrap {
display: flex;
align-items: center;
margin-right: 16px;
cursor: pointer;
img {
width: 16px;
height: 16px;
margin-right: 3px;
}
}
.m-r16 {
margin-right: 16px;
}
}
}
}
}
.child-wrap {
padding-left: 52px;
.child-wrap-item {
display: flex;
font-size: 14px;
margin-top: 16px;
// align-items: center;
.left-img {
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 12px;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.right {
width: 100%;
.name {
margin-bottom: 7px;
font-weight: 500;
color: #333;
display: flex;
align-items: center;
.author {
margin-left: 8px;
color: #fff;
background: linear-gradient(90deg, #2d28ff, #1a7dff);
padding: 3px 4px;
font-size: 12px;
line-height: 12px;
border-radius: 4px;
}
}
.des {
line-height: 1.5;
// display: flex;
align-items: center;
.u-name {
color: #1880ff;
margin-right: 6px;
}
}
.star-wrap {
margin-top: 4px;
display: flex;
align-items: center;
justify-content: space-between;
.time {
color: #999;
font-size: 12px;
}
.star-operator {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
cursor: pointer;
.icon-wrap {
display: flex;
align-items: center;
margin-right: 16px;
cursor: pointer;
img {
width: 16px;
height: 16px;
margin-right: 3px;
}
}
.m-r16 {
margin-right: 16px;
}
}
}
}
}
}
.no-more {
color: #999;
font-size: 14px;
text-align: center;
padding: 20px 0;
}
</style>