mcwl-pc/app/components/BaseComment.vue

600 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script setup lang="ts">
// import { NConfigProvider, NInfiniteScroll, NInput } from 'naive-ui'
import {
ThumbsUp
} from 'lucide-vue-next';
const props = defineProps({
height: {
type: Number,
default: 800,
},
type: {
type: String,
default: '',
},
detailsInfo: {
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.detailsInfo.id,
})
function commentParamsInit() {
commentParams.value.content = ''
commentParams.value.replyUserId = ''
commentParams.value.parentId = ''
}
const isShowSend = ref(false)
const publicWord = ref('')
const sortType = ref(1)
// 获取列表
const urlList = ref({
workflow: '/WorkFlowComment/comment?',
pictrue: '/imageComment/comment?',
model: '/ModelComment/comment?',
})
// 点赞
const likeList = ref({
workflow: '/WorkFlowComment/commentLike?',
pictrue: '/imageComment/commentLike?',
model:'ModelComment/commentLike?'
})
// 发送评论
const sendMessageList = ref({
workflow: '/WorkFlowComment/comment',
pictrue: '/imageComment/comment',
model: '/ModelComment/comment',
})
// 删除
const deleteList = ref({
workflow: '/WorkFlowComment/commentDelete?',
pictrue: '/imageComment/commentDelete?',
model: '/ModelComment/commentDelete?',
})
// 查条数
const commentNumUrl = ref({
workflow: '/WorkFlowComment/commentCount?workFlowId',
model: '/ModelComment/commentCount?modelId',
})
const commentCount = ref(0)
// 评论列表
const commentList = ref([])
async function getCommentList() {
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()
function handleBlur(ele) {
// 默认评价
if (!ele) {
isShowSend.value = !!publicWord.value
}
else {
ele.isShowSend = !!ele.word
}
}
// 发送评论
async function sendMessage(ele, index) {
if (ele && ele.userId) {
try {
if (ele.word) {
commentParams.value.content = ele.word
commentParams.value.parentId = commentList.value[index].commentId
commentParams.value.replyUserId = ele.commentId
if(props.type === 'pictrue'){
commentParams.value.modelImageId = props.detailsInfo.id
}else if(props.type === 'model'){
commentParams.value.modelId = props.detailsInfo.id
}
const res = await request.post(sendMessageList.value[props.type], commentParams.value)
if (res.code === 200) {
message.success('评论成功!')
getCommentList()
getCommentNum()
commentParamsInit()
}
}
else {
message.warning('评论不能为空!')
}
}
catch (error) {
console.log(error)
}
}
else {
try {
if (publicWord.value) {
commentParams.value.parentId = ''
commentParams.value.content = publicWord.value
commentParams.value.replyUserId = ''
if(props.type === 'pictrue'){
commentParams.value.modelImageId = props.detailsInfo.id
}else if(props.type === 'model'){
commentParams.value.modelId = props.detailsInfo.id
}
const res = await request.post(sendMessageList.value[props.type], commentParams.value)
if (res.code === 200) {
message.success('评论成功!')
publicWord.value = ''
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(item:any) {
await request.get(`${likeList.value[props.type]}commentId=${item.commentId}`)
if (item.isLike === 0) {
item.isLike = 1
item.likeNum++
message.success('点赞成功!')
}
else {
item.isLike = 0
item.likeNum--
message.success('取消点赞成功!')
}
}
// 显示回复框
function handleMessage(item:any) {
if (!item.isShowInput) {
item.word = ''
}
item.isShowInput = !item.isShowInput
}
// 删除评论
async function handleDel(item:any) {
try {
const res = await request.get(`${deleteList.value[props.type]}commentId=${item.commentId}`)
if (res.code === 200) {
message.success('删除成功!')
getCommentList()
getCommentNum()
}
}
catch (error) {
console.log(error)
}
}
function changeType(type: string) {
sortType.value = type
getCommentList()
}
</script>
<template>
<div class="base-comment">
<div class="flex justify-between items-center mb-4">
<div class="flex items-center">
<div class="left text-[20px] mr-2">
讨论
</div>
<div class="text-[#999]" v-if="props.type !== 'pictrue'">
{{ commentCount }}
</div>
</div>
<div class="flex items-center" v-if="props.type !== 'pictrue'">
<div class="cursor-pointer" :class="sortType === 0 ? '' : 'text-[#999]'" @click="changeType(0)">
最热
</div>
<div class="cursor-pointer" :class="sortType === 1 ? '' : 'text-[#999]'" @click="changeType(1)">
最新
</div>
</div>
</div>
<div class="header-wrap">
<div v-if="userStore.userInfo.avatar" class="left">
<img
alt="avatar"
:src="userStore.userInfo.avatar"
>
</div>
<div class="input-wrap">
<NConfigProvider inline-theme-disabled style="width:100%">
<NInput
v-model:value="publicWord"
type="textarea"
:autosize="{ minRows: 1 }"
placeholder="善语结善缘,恶言伤人心~"
class="text"
@focus="isShowSend = true"
@blur="handleBlur"
/>
</NConfigProvider>
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage">
<span v-if="isShowSend">发送</span>
</div>
</div>
</div>
<div
v-for="(item, index) in commentList"
:key="index"
class="px-4"
>
<div class="nav-wrap">
<div class="left-img">
<img :src="item.userAvatar">
</div>
<div class="right">
<div class="name">
{{ item.userName }}
</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">
<!-- <img v-if="item.focus" src="@/assets/img/heart.png" alt=""> -->
<ThumbsUp size="16" class="mr-1" :color="item.isLike !== 0 ? '#ff0000' : '#000000'" @click="handleFocus(item)" />
<!-- <img v-else src="@/assets/img/heart.png" alt="" @click="handleFocus(item)"> -->
<span style="vertical-align: middle">{{ item.likeNum }}</span>
</div>
<span class="cursor-pointer m-r16" @click="handleMessage(item)">回复</span>
<span v-if="item.userId === userStore.userInfo.userId" class="cursor-pointer" @click="handleDel(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(item, index)">
<span v-if="item.isShowSend">发送</span>
</div>
</div>
</div>
</div>
<div class="child-wrap">
<div v-for="(ele, subIndex) in item.contentList" :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>回复</span>
<span class="u-name">@{{ ele.userName }}</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(ele)" />
<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(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(ele, index)">
<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: 46px 0 118px;
}
</style>