mcwl-pc/app/components/PlanetQuestionComment.vue

705 lines
19 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 {
ThumbsUp,
} from 'lucide-vue-next'
import { watch } from 'vue'
interface LikeParams {
id: string | number
communityId?: string | number
tenantId?: string | number
publishId?: string | number
}
const props = defineProps({
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 showQuestionModal = ref(false)
const questionItem = ref({})
function handleShowQuestion(item: any) {
questionItem.value = item
showQuestionModal.value = true
}
const questionContent = ref('')
// 发布评论
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 res = await request.post(`/question/list`, 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) {
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.id = item.item.id
}
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/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('取消点赞成功!')
// }
// }
}
// 显示回复框
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 handlePublish() {
const params = {
content: questionContent.value,
questionId: questionItem.value.id,
communityId: questionItem.value.communityId,
tenantId: questionItem.value.tenantId,
}
try {
const res = await request.post('questionComment/comment', params)
if (res.code === 200) {
message.success('回答成功!')
getCommentList()
showQuestionModal.value = false
questionContent.value = ''
}
}
catch (error) {
console.log(error)
}
}
</script>
<template>
<div class="bg-white py-4 rounded min-h-[320px]">
<!-- <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.questionUserAvatar">
</div>
<div class="right">
<div class="name">
{{ item.questionUserName }}
</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>
<span class="cursor-pointer m-r16" @click="handleMessage(item)">回复</span>
<span v-if="item.userId === userStore?.userInfo?.userId" class="cursor-pointer" @click="handleDel('parent', { item })">删除</span>
</div> -->
</div>
<div v-if="item.questionUrl" class="flex flex-wrap gap-2">
<img v-for="(ele, index) in item.questionUrl.split(',')" :key="index" class="w-16 h-16 rounded-md" :src="ele">
</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.avatar">
</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 class="flex justify-center items-center text-sm my-4">
<div v-if="item.amount" class="cursor-pointer" @click="handleShowQuestion(item)">
<span class="text-blue-500">回答该问题可获得</span>
<span class="text-[#ffa820]">{{ item.amount }}积分</span>
</div>
<div v-else class="cursor-pointer" @click="handleShowQuestion(item)">
<span class="text-blue-500">回答该问题</span>
</div>
</div>
</div>
<div class="no-more">
暂时没有更多评论
</div>
<n-modal
v-model:show="showQuestionModal"
:style="{ width: '640px' }"
preset="dialog"
transform-origin="center"
class="custom-modal"
:show-icon="false"
>
<div class="bg-white rounded-lg px-6">
<div class="flex items-center justify-between pb-4">
<div class="flex items-center">
<div class="flex items-center">
回答<img class="w-4 h-4 rounded-full mx-2" :src="questionItem.questionUserAvatar">
</div>
<span>{{ questionItem.questionUserName }}</span>
<span>发起的咨询</span>
</div>
</div>
<n-form
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<n-form-item path="content" :show-label="false">
<n-input
v-model:value="questionContent"
type="textarea"
placeholder="请输入提问内容"
:required="true"
:autosize="{ minRows: 5, maxRows: 10 }"
class="rounded-lg"
/>
</n-form-item>
<div class="flex items-center justify-between my-4">
<div class="flex items-center justify-end gap-8 w-full">
<n-button
type="primary"
class="!px-8 rounded"
:theme-overrides="{
common: {
primaryColor: '#3f7ef7',
primaryColorHover: '#3f7ef7',
},
}"
@click="handlePublish"
>
回答
</n-button>
</div>
</div>
</n-form>
</div>
</n-modal>
</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>