604 lines
15 KiB
Vue
604 lines
15 KiB
Vue
<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/getComment?',
|
||
pictrue: '/imageComment/getComment?',
|
||
model: '/ModelComment/getComment?',
|
||
})
|
||
// 点赞
|
||
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: any, index: number) {
|
||
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 v-if="props.type !== 'pictrue'" class="text-[#999]">
|
||
{{ commentCount }}
|
||
</div>
|
||
</div>
|
||
<div v-if="props.type !== 'pictrue'" class="flex items-center">
|
||
<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>
|