PC-vote/components/DetailsComments.vue
2025-03-21 15:49:12 +08:00

1056 lines
44 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="comment-box">
<!-- 编辑评论 -->
<div v-if="editCommentState" class="edit-comment flexcenter">
<div class="box">
<div class="text">编辑评论</div>
<div class="input-box">
<div class="top flexflex">
<textarea ref="editInputRef" class="input-textarea flex1" maxlength="500" v-model="editInput" @focus="judgeLogin" @input="autoResize" @paste="handleInputPaste" placeholder="说说你的想法或疑问…"></textarea>
</div>
<div class="picture-box" v-if="editPicture.url">
<div class="picture">
<img class="close" @click="closeEditFileUpload()" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="editPicture.base64 || editPicture.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ 'pitch': editEmojiState }">
<img class="icon" src="@/assets/img/smiling-face.png" @click="openEditEmoji()" alt="" />
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEditEmoji(item)">{{ item }}</div>
</div>
</div>
<div class="item flexacenter" @click="judgeLogin()">
<input class="file" type="file" @change="handleFileUpload($event)" accept=".png, .jpg, .jpeg" />
<img class="icon" style="border-radius: 0;" src="@/assets/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片。</span>
</div>
</div>
</div>
</div>
<div class="btn-list flexacenter">
<div class="btn" @click="closeEdit()">取消</div>
<div class="btn send" @click="postEditComment()">发送</div>
</div>
</div>
</div>
<div class="comment-title flexacenter">
讨论
<span class="comment-amount">{{ commentComments || "" }}</span>
</div>
<!-- <div class="post-comment" ref="postInputRef" :class="{ 'post-comment-focus': postCommentFocusState }" @click="loginJudgment()">
<div class="post-comment-input">
<el-input class="post-input flex1" type="textarea" :autosize="postCommentFocusState" :maxlength="500" show-word-limit placeholder="说说你的想法或疑问…" v-model="commentInputTop" @blur="postCommentFocusBlur" @focus="postCommentFocusState = true"></el-input>
</div>
<div class="post-ok flexcenter" @click="submitAnswerComments(commentInputTop)">发送</div>
</div> -->
<div class="input-box">
<div class="top flexflex">
<img class="avatar" v-if="userInfoWin.avatar" :src="userInfoWin.avatar" />
<textarea class="input-textarea flex1" maxlength="500" v-model="commentInputTop" @focus="judgeLogin" @input="autoResize" @paste="handleInputPaste" placeholder="说说你的想法或疑问…"></textarea>
</div>
<div class="picture-box" v-if="picture.url">
<div class="picture">
<img class="close" @click="closeFileUpload()" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="picture.base64 || picture.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ 'pitch': emojiState }">
<img class="icon" src="@/assets/img/smiling-face.png" @click="openEmoji()" alt="" />
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item)">{{ item }}</div>
</div>
</div>
<div class="item flexacenter" @click="judgeLogin()">
<input class="file" type="file" @change="handleFileUpload($event)" accept=".png, .jpg, .jpeg" />
<img class="icon" src="@/assets/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片。</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(commentInputTop)">发送</div>
</div>
</div>
<div class="empty-box" v-if="isEmptyState">
<Empty hint="说说你的观点吧"></Empty>
</div>
<template v-else>
<div class="comment-list">
<div class="comment-item flexflex" v-for="(item, index) in commentList" :key="item.id">
<el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false" v-model:visible="item['popoverState']">
<template #reference>
<img class="comment-avatar" :src="item['avatar']" />
</template>
<div class="avatar-box flexflex" v-if="item['uin']">
<a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(item['uin'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(item['uin'])">
<img class="avatar-icon" src="@/assets/img/homepage-icon.png" />
TA的主页
</a>
</div>
</el-popover>
<div class="comment-content flex1">
<div class="comment-header flexacenter">
<div class="comment-header-left flexacenter">
<div class="comments-username" @click="openAvatarPopover(index)">{{ item["nickname"] }}</div>
<div class="comments-time">{{ item["timestampnow"] || handleDate(item["timestamp"]) }}</div>
<div class="comments-identity" v-if="item['isauthor']">作者</div>
<!-- <img class="comments-title" v-if="item['groupid'] === 14" src="@/assets/img/title.png" /> -->
<img class="comments-title" v-if="item['groupimage']" :src="item.groupimage" :alt="item.grouptitle" />
</div>
<div class="comment-header-right flexacenter">
<div class="menu-box flexacenter">
<img class="menu-icon" src="@/assets/img/menu-icon-gray.svg" />
<div class="operate-box">
<div class="item flexcenter" @click="report(item['token'])">举报</div>
<div class="item flexcenter" v-if="permissions.includes('comment.edit')" @click="openEdit(item['token'], index)">编辑</div>
<div class="item flexcenter" v-if="permissions.includes('comment.delete')" @click="commentDelete(item['token'], index)">删除</div>
</div>
</div>
<!-- <img class="comment-icon" title="回复" @click="openAnswerCommentsChild(index)" src="@/assets/img/comment-icon-gray.svg" /> -->
<img class="comment-icon" title="回复" @click="!item['childState'] ? openAnswerCommentsChild(index) : closeAnswerCommentsChild()" src="@/assets/img/comment-icon-gray.svg" />
<div class="flexacenter like-box" @click="commentLike(index)">
<img class="like-icon" v-if="item['islike'] == 1" src="@/assets/img/like-icon-colours.png" />
<img class="like-icon" v-else src="@/assets/img/like-icon-gray.png" />
<div class="like-quantity">{{ item["likenum"] || 0 }}</div>
</div>
</div>
</div>
<!-- shutAnswerCommentsChild openAnswerCommentsChild -->
<div class="comment-text" v-if="item['content']" @click="!item['childState'] ? openAnswerCommentsChild(index) : closeAnswerCommentsChild()">{{ item["content"] }}</div>
<img class="comments-img" @click="handleAnswerText" :src="item.image?.base64 || item.image?.url" v-if="item.image?.url" />
<div class="alreadyVoted" v-if="item.voteoption">已投:{{ item.voteoption }}</div>
<div class="input-box" v-if="item['childState']">
<img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" />
<div class="top flexflex">
<textarea class="input-textarea flex1" maxlength="500" placeholder="说说你的想法或疑问…" v-model="item['commentInput']" @input="autoResize" @paste="handleInputPaste($event, index)"></textarea>
</div>
<div class="picture-box" v-if="item.picture?.url">
<div class="picture">
<img class="close" @click="closeFileUpload(index)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="item.picture?.base64 || item.picture.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ 'pitch': item.emojiState }">
<img class="icon" src="@/assets/img/smiling-face.png" @click="openEmoji(index)" alt="" />
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item, index)">{{ item }}</div>
</div>
</div>
<div class="item flexacenter">
<input class="file" type="file" @change="handleFileUpload($event, index)" accept=".png, .jpg, .jpeg" />
<img class="icon" src="@/assets/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片。</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(item['commentInput'], index)">发送</div>
</div>
</div>
<!-- <div class="comments-input-masking" @click="closeAnswerCommentsChild()" v-if="item['childState']"></div>
<div class="comments-input-box" :class="{ 'comments-input-box-show': item['childState'] }">
<div class="comments-input">
<el-input v-model="commentInput" type="textarea" placeholder="回复" :maxlength="500" show-word-limit></el-input>
<div class="operate-bottom flexacenter">
<div class="comments-btn comments-btn-cancel flexcenter" @click="closeAnswerCommentsChild()">取消</div>
<div class="comments-btn flexcenter" @click="submitAnswerComments(commentInput, index)">发送</div>
</div>
</div>
</div> -->
<!-- 子评论 -->
<div class="child-comments" v-if="item['child'].length > 0">
<div class="comment-item flexflex" v-for="(ite, i) in item['child']" :key="ite.id">
<el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false" v-model:visible="ite['popoverState']">
<template #reference>
<img class="comment-avatar" :src="ite['avatar']" />
</template>
<div class="avatar-box flexflex" v-if="ite['uin']">
<a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(ite['uin'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(ite['uin'])">
<img class="avatar-icon" src="@/assets/img/homepage-icon.png" />
TA的主页
</a>
</div>
</el-popover>
<div class="comment-content flex1">
<div class="comment-header flexacenter">
<div class="comment-header-left flexacenter">
<div class="comments-username" @click="openAvatarPopover(index, i)">{{ ite["nickname"] }}</div>
<div class="comments-time">{{ ite["timestampnow"] || handleDate(ite["timestamp"]) }}</div>
<div class="comments-identity" v-if="ite['isauthor']">作者</div>
<img class="comments-title" v-if="ite['groupimage']" :src="ite.groupimage" :alt="ite.grouptitle" />
</div>
<div class="comment-header-right flexacenter">
<div class="menu-box flexacenter">
<img class="menu-icon" src="@/assets/img/menu-icon-gray.svg" />
<div class="operate-box">
<div class="item flexcenter" @click="report(ite['token'])">举报</div>
<div class="item flexcenter" v-if="permissions.includes('comment.edit')" @click="openEdit(ite['token'], index, i)">编辑</div>
<div class="item flexcenter" v-if="permissions.includes('comment.delete')" @click="commentDelete(ite['token'], index, i)">删除</div>
</div>
</div>
<img class="comment-icon" title="回复" @click="!ite['childState'] ? openAnswerCommentsChild(index, i) : closeAnswerCommentsChild()" src="@/assets/img/comment-icon-gray.svg" />
<div class="flexacenter like-box" @click="commentLike(index, i)">
<img class="like-icon" v-if="ite['islike'] == 1" src="@/assets/img/like-icon-colours.png" />
<img class="like-icon" v-else src="@/assets/img/like-icon-gray.png" />
<div class="like-quantity">{{ ite["likenum"] || 0 }}</div>
</div>
</div>
</div>
<div class="comment-text" v-if="ite['content']" @click="!ite['childState'] ? openAnswerCommentsChild(index, i) : closeAnswerCommentsChild()">
<div class="comments-reply" v-if="ite?.reply?.nickname">@{{ ite?.reply?.nickname }}</div>
{{ ite["content"] }}
</div>
<img class="comments-img" @click="handleAnswerText" :src="ite.image?.base64 || ite.image?.url" v-if="ite.image?.url" />
<div class="alreadyVoted" v-if="ite.voteoption">已投:{{ ite.voteoption }}</div>
<div class="input-box" v-if="ite['childState']">
<img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" />
<div class="top flexflex">
<textarea class="input-textarea flex1" maxlength="500" :placeholder="'回复“' + (ite['nickname'] || '匿名用户') + '”:'" v-model="ite['commentInput']" @input="autoResize" @paste="handleInputPaste($event, index)"></textarea>
</div>
<div class="picture-box" v-if="ite.picture?.url">
<div class="picture">
<img class="close" @click="closeFileUpload(index, i)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="ite.picture.base64 || ite.picture.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ 'pitch': ite.emojiState }">
<img class="icon" src="@/assets/img/smiling-face.png" @click="openEmoji(index, i)" alt="" />
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item, index, i)">{{ item }}</div>
</div>
</div>
<div class="item flexacenter">
<input class="file" type="file" @change="handleFileUpload($event, index, i)" accept=".png, .jpg, .jpeg" />
<img class="icon" src="@/assets/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片。</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(ite['commentInput'], index, i)">发送</div>
</div>
</div>
<!-- <div class="comments-input-masking" @click="closeAnswerCommentsChild()" v-if="ite['childState']"></div>
<div class="comments-input-box" :class="{ 'comments-input-box-show': ite['childState'] }">
<div class="comments-input">
<el-input v-model="commentInput" type="textarea" placeholder="回复" :maxlength="500" show-word-limit></el-input>
<div class="operate-bottom flexacenter">
<div class="comments-btn comments-btn-cancel flexcenter" @click="closeAnswerCommentsChild()">取消</div>
<div class="comments-btn flexcenter" @click="submitAnswerComments(commentInput, index, i)">发送</div>
</div>
</div>
</div> -->
</div>
</div>
</div>
<!-- 还有几个 -->
<div class="comments-also flexacenter" v-if="item['childnum'] > item['child'].length" @click="alsoCommentsData(index)">
<div class="">还有{{ item["childnum"] - item["child"].length }}条回复</div>
<img class="also-icon" src="@/assets/img/arrow-circular-gray.png" />
</div>
</div>
</div>
</div>
<div class="comment-end" v-if="commentPage == 0 && commentList.length != 0">· End ·</div>
</template>
</div>
<Report v-if="reportAlertShow" :reportToken="reportToken"></Report>
<!-- 投票后自动评论 -->
<el-dialog class="default-popup automatic-reviews-popup" v-model="reviewsPopoverState" width="720px" align-center autosize :close-on-click-modal="false">
<div class="automatic-header">
<div class="automatic-title">说说您的投票理由</div>
<div class="automatic-have">已投{{ haveVotedValue }}</div>
</div>
<el-input class="automatic-input" placeholder="请输入…" v-model="reviewsPopoverInput" type="textarea" maxlength="500" show-word-limit></el-input>
<div class="automatic-bottom flexflex">
<div class="automatic-send flexcenter" @click="submitAnswerComments(reviewsPopoverInput)">发送</div>
</div>
</el-dialog>
<!-- 大图 -->
<div class="detail-image-mask flexcenter" v-if="dialogSrc" @click="dialogSrc = ''">
<div class="detail-image flexcenter">
<img class="detail-img" :src="dialogSrc" />
</div>
</div>
<el-dialog v-model="dialogVisible" title="提示" width="500">
<span>确定删除该讨论吗</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmCommentDelete"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessage } from "element-plus"
import { isEmpty } from "element-plus/es/utils"
let haveVotedValue = inject("haveVotedValue")
let isNeedLogin = inject("isNeedLogin")
const goLogin = inject("goLogin")
const props = defineProps({ token: String })
const userInfoWin = inject("userInfoWin")
watch(
() => props.token,
() => getCommentList(),
{ immediate: false }
)
onMounted(() => window.addEventListener("scroll", handleScroll))
let permissions = ref([])
onMounted(() => {
setTimeout(() => {
permissions.value = window["permissions"] || []
// permissions.value = ["comment.edit", "comment.delete"]
}, 1000)
})
const sendMessage = inject("sendMessage")
const TAHomePage = inject("TAHomePage")
let postCommentFocusState = ref(false)
let commentCount = ref(0)
let commentComments = ref(0) // 所有的评论数
let commentPage = ref(1)
let commentList = ref([])
let commentLoading = false
let isEmptyState = ref(false) // 评论是否为空
const emit = defineEmits(["update:commentComments"])
// 获取详情评论数据
const getCommentList = () => {
if (commentPage.value == 0 || commentLoading || !props.token) return
commentLoading = true
commentListHttp({
page: commentPage.value,
childlimit: 1,
limit: 10,
token: props.token,
})
.then(res => {
if (res.code != 200) return
let data = res.data
commentCount.value = data["count"]
if (data["count"] == 0) isEmptyState.value = true
else isEmptyState.value = false
commentList.value = commentList.value.concat(data["data"])
commentComments.value = data["comments"]
emit("update:commentComments", data["comments"])
if (commentList.value.length == data["count"]) commentPage.value = 0
else commentPage.value++
})
.finally(() => (commentLoading = false))
}
// 评论点赞
const commentLike = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
const targetCommentList = [...commentList.value]
let token = ""
if (i != null) token = targetCommentList[index]["child"][i].token
else token = targetCommentList[index].token
detailsLikeCommentHttp({ token }).then(res => {
if (res.code != 200) return
let data = res.data
if (i != null) {
targetCommentList[index]["child"][i].islike = data["status"]
targetCommentList[index]["child"][i].likenum = data["likenum"]
} else {
targetCommentList[index].islike = data["status"]
targetCommentList[index].likenum = data["likenum"]
}
ElMessage.success(res.message)
})
}
// 打开 回答-评论 的子评论
const openAnswerCommentsChild = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
closeAnswerCommentsChild()
if (i == null) commentList.value[index]["childState"] = true
else commentList.value[index]["child"][i]["childState"] = true
}
// 关闭 回答-评论 的子评论 isempty 是否需要清空输入框 默认需要清空
const closeAnswerCommentsChild = () => {
commentList.value.forEach(ele => {
ele["childState"] = false
if (ele["child"] && ele["child"].length != 0) ele["child"].forEach(el => (el["childState"] = false))
})
}
// 讨论的输入框
let commentInputTop = ref("")
let commentInput = ref("")
// 提交回答-评论
const submitAnswerComments = (content, index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
const targetCommentList = [...commentList.value]
// let content = ""
let parentid = null
// if (index == null) content = commentInputTop.value
// else content = commentInput.value
let image = {}
if (i != null) {
parentid = targetCommentList[index]["child"][i]["id"]
image = commentList.value[index]["child"][i]["picture"] || {}
} else if (index != null) {
parentid = targetCommentList[index]["id"]
image = commentList.value[index]["picture"] || {}
} else image = picture.value
// if (!content) {
// ElMessage.error("请填写评论内容")
// return
// }
detailsSubmitommentListHttp({
content,
token: props.token,
parentid,
image: image ? { aid: image.aid, url: image.url } : null,
}).then(res => {
if (res.code != 200) {
ElMessage.error(res.message)
return
}
let data = res.data
if (i != null) {
// console.log("targetCommentList[index]", targetCommentList[index])
targetCommentList[index]["child"][i]["commentInput"] = ""
targetCommentList[index]["child"][i]["picture"] = {}
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
reply: {
nickname: targetCommentList[index]["child"][i]["nickname"],
},
voteoption: haveVotedValue.value || null,
...data,
// ...data.data
timestampnow: "刚刚",
uin: data.data?.uin,
image,
}
targetCommentList[index]["child"].unshift(targetData)
targetCommentList[index]["childnum"]++
} else {
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
...data,
// ...data.data,
timestampnow: "刚刚",
uin: data.data?.uin,
child: [],
voteoption: haveVotedValue.value || null,
image,
}
if (index != null) {
targetCommentList[index]["commentInput"] = ""
targetCommentList[index]["picture"] = {}
targetCommentList[index]["child"].unshift(targetData)
targetCommentList[index]["childnum"]++
} else {
targetCommentList.unshift(targetData)
commentCount.value++
}
}
commentComments.value++
commentList.value = targetCommentList
// 请求 输入框的数据
commentInputTop.value = ""
commentInput.value = ""
reviewsPopoverInput.value = ""
reviewsPopoverState.value = false
isEmptyState.value = false // 取消有可能的 没有评论
closeAnswerCommentsChild()
picture.value = {}
if (bottomNavigationState) {
bottomNavigationState = false
floorCommentBtn("back")
}
ElMessage.success(res.message)
})
}
// 获取剩下的子评论
const alsoCommentsData = (index, ind) => {
if (isNeedLogin.value) {
goLogin()
return
}
let targetCommentItem = { ...commentList.value[index] }
const token = targetCommentItem["token"]
const parentid = targetCommentItem["id"]
let page = targetCommentItem["childPage"] ?? 1
detailsChildCommentListHttp({
childlimit: 1,
limit: 10,
page,
parentid,
token: props.token,
}).then(res => {
if (res.code != 200) return
let data = res.data
let childData = targetCommentItem.child.concat(data.data)
const filteredData = childData.filter((obj, index, self) => {
// 检查当前对象在数组中的第一个索引是否与当前索引相等
return self.findIndex(item => item.id == obj.id) == index
})
targetCommentItem.child = filteredData
targetCommentItem["childnum"] = data.count
if (targetCommentItem.child.length == data["count"]) page = 0
else page++
targetCommentItem["childPage"] = page
commentList.value[index] = targetCommentItem
})
}
let reportAlertShow = ref(false)
let reportToken = ref("")
// 点击打开举报
const report = token => {
if (isNeedLogin.value) {
goLogin()
return
}
reportToken.value = token
reportAlertShow.value = true
}
// 打开评论的 信息框
const openAvatarPopover = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
if (i != null) commentList.value[index]["child"][i]["popoverState"] = true
else commentList.value[index]["popoverState"] = true
}
// 监听滚动到底部
const handleScroll = () => {
// return
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
const scrollHeight = document.documentElement.scrollHeight
const clientHeight = document.documentElement.clientHeight
// 列表下 滑动到底部 获取新数据
if (scrollTop + clientHeight >= scrollHeight - 40) getCommentList()
}
provide("reportAlertShow", reportAlertShow)
// 登录判断
const loginJudgment = () => {
if (isNeedLogin.value) goLogin()
}
// 修改投票的值
const changeCommentVoteoption = voteoption => {
const uin = window["userInfoWin"]["uin"]
commentList.value.forEach(element => {
if (uin == element["uin"]) element["voteoption"] = voteoption
element.child.forEach(el => {
if (uin == element["uin"]) el["voteoption"] = voteoption
})
})
}
// 修改投票的值
const wipeCommentVoteoption = () => {
const uin = window["userInfoWin"]["uin"]
commentList.value.forEach(element => {
if (uin == element["uin"]) element["voteoption"] = null
element.child.forEach(el => {
if (uin == element["uin"]) el["voteoption"] = null
})
})
}
let reviewsPopoverState = ref(false) // 自动投票弹窗状态
let reviewsPopoverInput = ref("") // 自动投票理由
// 调用自动评论
const reviewsComment = value => {
reviewsPopoverState.value = true
}
let bottomNavigationState = false
// 底部导航栏的 评论
const bottomNavigationBar = value => {
bottomNavigationState = true
submitAnswerComments(value)
}
const floorCommentBtn = inject("floorCommentBtn")
const postInputRef = ref(null)
const postCommentFocusBlur = () => {
const refref = postInputRef.value
setTimeout(() => {
postCommentFocusState.value = false
nextTick(() => {
let targetDom = refref.querySelector(".el-textarea__inner")
targetDom.style.height = "41px"
})
}, 200)
}
let picture = ref({})
let emojiState = ref(false)
let emojiMaskState = ref(false)
const emojiData = ["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❤️", "💔", "🌹", "🥀", "🎉", "🎁", "🧧", "🌙", "⭐", "🌍", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹"]
// 打开 Emoji
const openEmoji = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
if (i != undefined) commentList.value[index].child[i]["emojiState"] = true
else if (index != undefined) commentList.value[index]["emojiState"] = true
else {
closeEmoji()
closeAnswerCommentsChild()
emojiState.value = true
}
emojiMaskState.value = true
}
// 关闭 Emoji
const closeEmoji = (index, i) => {
commentList.value.forEach(ele => {
ele["emojiState"] = false
if (ele["child"] && ele["child"].length != 0) {
ele["child"].forEach(el => {
el["emojiState"] = false
})
}
})
emojiState.value = false
emojiMaskState.value = false
editEmojiState.value = false
}
// 选择 Emoji
const selectEmoji = (key, index, i) => {
closeEmoji()
if (i != undefined) {
if (!commentList.value[index]["child"][i]["commentInput"]) commentList.value[index]["child"][i]["commentInput"] = ""
commentList.value[index]["child"][i]["commentInput"] += key
} else if (index != undefined) {
if (!commentList.value[index]["commentInput"]) commentList.value[index]["commentInput"] = ""
commentList.value[index]["commentInput"] += key
} else {
commentInputTop.value += key
}
}
// 自动输入框增高
const autoResize = e => {
e.target.style.height = "auto" // 重置高度
e.target.style.height = `${e.target.scrollHeight}px` // 设置为内容高度
}
const maxSize = 20 * 1024 * 1024 // 20MB
const handleInputPaste = (event, index, ii) => {
const items = event.clipboardData.items // 获取粘贴的内容
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (item.type.startsWith("image/")) {
event.preventDefault()
const file = item.getAsFile() // 获取文件
if (file.size > maxSize) {
ElMessage({
message: "文件大小不能超过 20MB",
type: "error",
})
return
}
const reader = new FileReader()
reader.onload = e => {
const base64 = e.target.result
uploadImg(base64).then(res => {
const obj = {
base64,
...res,
}
if (editCommentState.value) editPicture.value = obj
else {
if (ii != undefined) commentList.value[index].child[ii]["picture"] = obj
else if (index != undefined) commentList.value[index]["picture"] = obj
else picture.value = obj
}
ElMessage({
message: "上传成功",
type: "success",
})
})
}
reader.readAsDataURL(file)
}
}
}
const handleFileUpload = (event, index, i) => {
closeEmoji()
const file = event.target.files[0] // 获取选择的文件
if (!file) return
if (file.size > maxSize) {
ElMessage({
message: "文件大小不能超过 20MB",
type: "error",
})
return
}
const reader = new FileReader()
reader.onload = e => {
const base64 = e.target.result
uploadImg(base64).then(res => {
const obj = {
base64,
...res,
}
if (editCommentState.value) editPicture.value = obj
else {
if (i != undefined) commentList.value[index].child[i]["picture"] = obj
else if (index != undefined) commentList.value[index]["picture"] = obj
else picture.value = obj
}
ElMessage({
message: "上传成功",
type: "success",
})
})
}
reader.readAsDataURL(file)
}
// 删除上传的图片
const closeFileUpload = (index, i) => {
if (i != undefined) commentList.value[index].child[i]["picture"] = {}
else if (index != undefined) commentList.value[index]["picture"] = {}
else picture.value = {}
}
// 上传图片 获取图片url
const uploadImg = base64 => {
return new Promise((resolve, reject) => {
// detailLoading.value = true
commonUploadHttp({
data: base64,
}).then(res => {
if (res.code != 200) {
ElMessage({
message: res.message || "上传失败",
type: "error",
})
return
}
let data = res.data
resolve(data)
})
})
}
let dialogSrc = ref("") // 大图的src
// 处理点击答案图片 展开大图
const handleAnswerText = e => {
if (e.target.tagName === "IMG") {
var src = e.target.getAttribute("src")
dialogSrc.value = src
window.addEventListener("keydown", handleKeydown)
}
}
// 大图的监听 esc 键盘按钮
const handleKeydown = event => {
if (event.key !== "Escape") return
dialogSrc.value = ""
window.removeEventListener("keydown", handleKeydown) // 取消监听
}
let dialogVisible = ref(false)
let commemtDelete = {}
// 点击删除
const commentDelete = (token, index, i) => {
commemtDelete = {
token,
index,
i,
}
dialogVisible.value = true
}
const confirmCommentDelete = () => {
commentDeleteHttp({
token: commemtDelete.token,
}).then(res => {
if (res.code != 200) {
ElMessage.error(res.message)
return
}
if (commemtDelete.i >= 0) {
commentList.value[commemtDelete.index].child.splice(commemtDelete.i, 1)
commentList.value[commemtDelete.index].childnum -= 1
} else {
commentComments.value -= commentList.value[commemtDelete.index].childnum
commentList.value.splice(commemtDelete.index, 1)
}
commentComments.value -= 1
dialogVisible.value = false
ElMessage.success(res.message || "操作成功")
})
}
const judgeLogin = () => {
if (isNeedLogin.value) goLogin()
}
let editCommentState = ref(false)
let editToken = ""
let editPicture = ref({})
let editInput = ref("")
let editEmojiState = ref(false)
const editInputRef = ref(null)
const openEdit = (token, index, i) => {
const list = JSON.parse(JSON.stringify(commentList.value))
let target = {}
if (i != null) target = list[index]["child"][i]
else target = list[index]
// console.log(token, index, i, target)
editToken = target.token || ""
editInput.value = target.content || ""
editPicture.value = target.image || {}
editCommentState.value = true
nextTick(() => {
// console.log("editInput.value", editInputRef.value)
editInputRef.value.style.height = `${editInputRef.value.scrollHeight}px`
})
}
const closeEdit = () => {
editPicture.value = {}
editToken = ""
editInput.value = ""
editCommentState.value = false
}
// 打开 Emoji
const openEditEmoji = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
editEmojiState.value = true
}
const selectEditEmoji = key => {
closeEmoji()
editInput.value += key
}
const postEditComment = () => {
if (isNeedLogin.value) {
goLogin()
return
}
const image = editPicture.value
commentsEditSubmit({
content: editInput.value,
token: editToken,
image: image ? { aid: image.aid, url: image.url } : null,
}).then(res => {
if (res.code != 200) {
ElMessage.error(res.message)
return
}
commentList.value.forEach(element => {
if (element.token == editToken) {
element["content"] = editInput.value
element["image"] = image
}
element.child &&
element.child.forEach(ele => {
if (ele.token == editToken) {
ele["content"] = editInput.value
ele["image"] = image
}
})
})
editPicture.value = {}
editToken = ""
editCommentState.value = false
editEmojiState.value = false
ElMessage.success(res.message)
})
}
const closeEditFileUpload = () => (editPicture.value = {})
defineExpose({ changeCommentVoteoption, wipeCommentVoteoption, reviewsComment, bottomNavigationBar, closeAnswerCommentsChild })
</script>
<style scoped lang="less">
@import url(@/assets/css/DetailsComments.css);
</style>
<style lang="less">
.automatic-reviews-popup {
border-radius: 10px !important;
.automatic-header {
padding: 20px;
border-bottom: 1px dotted #ebebeb;
.automatic-title {
font-weight: 650;
font-size: 18px;
color: #000000;
margin-bottom: 12px;
}
.automatic-have {
background-color: rgba(246, 246, 246, 1);
font-size: 12px;
color: #aaa;
width: fit-content;
}
}
.automatic-input {
.el-textarea__inner {
min-height: 256px !important;
box-shadow: none;
padding: 20px;
resize: none;
}
.el-input__count {
left: 10px;
bottom: -40px;
width: fit-content;
}
}
.automatic-bottom {
justify-content: flex-end;
padding: 0 10px 10px;
.automatic-send {
background-color: var(--main-color);
color: #fff;
font-size: 16px;
width: 100px;
height: 40px;
border-radius: 6px;
cursor: pointer;
}
}
}
</style>