2025-01-21 19:06:13 +08:00

609 lines
26 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="answer-discuss">
<div class="header flexacenter">
回答&讨论
<span class="num">{{ commentCount || '' }}</span>
</div>
<div class="input-box">
<div class="top flexflex">
<img class="avatar" src="https://axure-file.lanhuapp.com/md5__61e148c1ead80d48108f4e5a7f93abc3.svg" />
<div class="input-textarea flex1" ref="inputTextareaRef" :class="{ 'placeholder': isPlaceholderVisible }" contenteditable="true" @focus="clearPlaceholder()" @blur="setPlaceholder($event)" @paste="handleInputPaste"></div>
</div>
<div class="picture-box" v-if="picture.url">
<div class="picture">
<img class="close" @click="closeFileUpload()" src="/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="/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">
<input class="file" type="file" @change="handleFileUpload($event)" accept=".png, .jpg, .jpeg" />
<img class="icon" src="/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片。</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments()">发送</div>
</div>
</div>
<div class="comments-box">
<div class="comments-item" v-for="(item, index) in commentList" :key="index">
<div class="comments-header flexacenter">
<div class="comments-header-left flexacenter">
<img class="comments-avatar" :src="item['avatar']" />
<div class="comments-username">{{ item["nickname"] }}</div>
<div class="comments-time">{{ handleDate(item["timestamp"]) }}</div>
<!-- <div class="comments-identity" v-if="item['questioner'] == 1">提问者</div>
<div class="comments-identity" v-else-if="item['isauthor'] == 1">回答者</div> -->
<div class="comments-identity" v-if="item['isauthor'] == 1">提问者</div>
<div class="avatar-box flexflex" v-if="item['avatarState']">
<a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(item['uin'])">
<img class="avatar-icon" src="@/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(item['uin'])">
<img class="avatar-icon" src="@/img/homepage-icon.png" />
TA的主页
</a>
<div class="avatar-mask"></div>
</div>
</div>
<div class="comments-header-right flexacenter">
<div class="menu-box flexacenter" @click="openMenuState(index)">
<img class="menu-icon" src="/img/menu-icon-gray.svg" />
<div class="report-box flexcenter">举报</div>
</div>
<img class="comment-icon" @click="openAnswerCommentsChild(index)" src="/img/comment-icon-gray.svg" />
<div class="flexacenter like-box" @click="operateAnswerCommentsLike(item.token, index)">
<img class="like-icon" v-if="item['islike'] == 0" src="/img/like-icon-gray.png" />
<img class="like-icon" v-else src="/img/like-icon-colours.png" />
<div class="like-quantity">{{ item["likenum"] || "" }}</div>
</div>
</div>
</div>
<div class="comments-content">
<div class="comments-text">{{ item["content"] }}</div>
<img class="comments-img" @click="handleAnswerText" :src="item.image?.base64 || item.image?.url" v-if="item.image?.url" />
<div class="input-box" v-if="item['childState']">
<img class="cross" @click="closeAnswerCommentsChild(index)" src="/img/cross-icon.png" />
<div class="top flexflex">
<div class="input-textarea flex1" :class="{ 'placeholder': item.isPlaceholderVisible }" contenteditable="true" @focus="clearPlaceholder(index)" @blur="setPlaceholder($event, index)" @paste="handleInputPaste($event, index)"></div>
</div>
<div class="picture-box" v-if="item.picture?.url">
<div class="picture">
<img class="close" @click="closeFileUpload(index)" src="/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="/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="/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(index)">发送</div>
</div>
</div>
</div>
<div class="child-comments" v-if="item['child'].length != 0">
<div class="comments-item" v-for="(ite, i) in item['child']" :key="ite.id">
<div class="comments-header flexacenter">
<div class="comments-header-left flexacenter">
<img class="comments-avatar" :src="ite['avatar']" />
<div class="comments-username">{{ ite["nickname"] }}</div>
<div class="comments-time">{{ handleDate(ite["timestamp"]) }}</div>
<div class="comments-identity" v-if="ite['questioner'] == 1">提问者</div>
<div class="comments-identity" v-else-if="ite['isauthor'] == 1">回答者</div>
<div class="avatar-box flexflex" v-if="ite['avatarState']">
<a class="avatar-item flexcenter" target="_blank">
<img class="avatar-icon" src="@/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank">
<img class="avatar-icon" src="@/img/homepage-icon.png" />
TA的主页
</a>
<div class="avatar-mask"></div>
</div>
</div>
<div class="comments-header-right flexacenter">
<div class="menu-box flexacenter">
<img class="menu-icon" src="/img/menu-icon-gray.svg" />
<div class="report-box flexcenter">举报</div>
</div>
<img class="comment-icon" @click="openAnswerCommentsChild(index, i)" src="/img/comment-icon-gray.svg" />
<div class="flexacenter like-box" @click="operateAnswerCommentsLike(ite.token, index, i)">
<img class="like-icon" v-if="ite['islike'] == 0" src="/img/like-icon-gray.png" />
<img class="like-icon" v-else src="/img/like-icon-colours.png" />
<div class="like-quantity">{{ ite["likenum"] || "" }}</div>
</div>
</div>
</div>
<div class="comments-content">
<div class="comments-text">
<!-- <div class="comments-reply" v-if="JSON.stringify(ite['reply']) != '[]'">@{{ ite["reply"]["nickname"] }}</div> -->
<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="input-box" v-if="ite['childState']">
<img class="cross" @click="closeAnswerCommentsChild(index)" src="/img/cross-icon.png" />
<div class="top flexflex">
<div class="input-placeholder" v-if="ite.isPlaceholderVisible">回复{{ ite["nickname"] }}</div>
<div class="input-textarea flex1" contenteditable="true" @focus="clearPlaceholder(index, i)" @blur="setPlaceholder($event, index, i)" @paste="handleInputPaste($event, index, i)"></div>
</div>
<div class="picture-box" v-if="ite.picture?.url">
<div class="picture">
<img class="close" @click="closeFileUpload(index, i)" src="/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="/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="/img/picture-icon.png" alt="" />
<span class="file-hint">最多可上传1张图片支持在输入框中直接粘贴图片</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(index, i)">发送</div>
</div>
</div>
</div>
</div>
<div class="comments-also flexacenter" v-if="item['childnum'] > item['child'].length" @click="alsoCommentsData(index, i)">
<div class>还有{{ item["childnum"] - item.child.length }}条回复</div>
<img class="also-icon" src="/img/arrow-circular-gray.png" />
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
token: String,
})
onMounted(() => {
// getComment()
})
const $ajax = inject("$ajax")
const $ajaxGET = inject("$ajaxGET")
const detailsToken = inject("detailsToken")
const handleDate = inject("handleDate")
const isNeedLogin = inject("isNeedLogin")
const handleMsg = inject("handleMsg")
const uploadImg = inject("uploadImg")
const handleAnswerText = inject("handleAnswerText")
const emojiMaskState = inject("emojiMaskState")
const commentList = ref([])
let commentCount = ref(0)
let commentTotalCount = ref(0)
let commentPage = ref(1)
let isgetCommentSate = false // 请求评论状态
let alreadyCommentIdList = []
const getComment = () => {
if (commentPage.value == 0 || isgetCommentSate) return
isgetCommentSate = true
$ajax("/api/comment/lists", {
token: detailsToken.value,
page: commentPage.value,
limit: 1500,
})
.then(res => {
if (res.code != 200) return
let data = res.data
data.data.forEach((element, index) => {
element["isReplyBoxShow"] = 0
element["isPlaceholderVisible"] = true
// element.timestamp = util.timeformat(element.timestamp, 2)
if (element.child.length > 0) {
element.child.forEach(el => {
// el.timestamp = util.timeformat(el.timestamp, 2)
el["isReplyBoxShow"] = 0
el["isPlaceholderVisible"] = true
})
}
})
if (commentPage.value > 1) {
let alreadyCommentIdList = alreadyCommentIdList
for (let index = 0; index < data.data.length; index++) {
if (alreadyCommentIdList.includes(data.data[index].id)) {
data.data.splice(index, 1)
index--
}
}
}
commentList.value = commentList.value.concat(data.data)
// console.log("commentList", commentList.value)
commentCount.value = data.count
commentTotalCount.value = data.comments
commentPage.value = data.count > commentList.length ? commentPage.value + 1 : 0
// console.log("commentList", commentList)
// this.setData({
// commentList,
// commentCount: data.count,
// commentTotalCount: data.comments,
// commentPage: data.count > commentList.length ? this.data.commentPage + 1 : 0,
// })
})
.finally(() => {
isgetCommentSate = false
})
}
// 监听 detailsToken 的变化
watch(
detailsToken,
(newValue, oldValue) => {
if (newValue !== oldValue) {
commentPage.value = 1
commentList.value = []
getComment()
}
},
{ immediate: true }
)
let picture = ref({})
const handleFileUpload = (event, index, i) => {
closeEmoji()
const file = event.target.files[0] // 获取选择的文件
if (file) {
const reader = new FileReader()
reader.onload = e => {
const base64 = e.target.result
uploadImg(base64).then(res => {
console.log("base64", base64)
const obj = {
base64,
...res,
}
if (i != undefined) commentList.value[index].child[i]["picture"] = obj
else if (index != undefined) commentList.value[index]["picture"] = obj
else picture.value = obj
handleMsg("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 = {}
}
//
let emojiState = ref(false)
const emojiData = ["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❤️", "💔", "🌹", "🥀", "🎉", "🎁", "🧧", "🌙", "⭐", "🌍", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹"]
// 打开 Emoji
const openEmoji = (index, i) => {
if (i != undefined) commentList.value[index].child[i]["emojiState"] = true
else if (index != undefined) commentList.value[index]["emojiState"] = true
else emojiState.value = true
console.log("emojiMaskState", emojiMaskState)
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
}
defineExpose({
closeEmoji,
})
// 选择 Emoji
const selectEmoji = (key, index, i) => {
closeEmoji()
console.log("key", key)
if (i != undefined) {
const commentInput = document.querySelector(".comments-box .input-textarea")
commentInput.innerText += key
commentList.value[index].child[i]["isPlaceholderVisible"] = false
} else if (index != undefined) {
const commentInput = document.querySelector(".comments-box .input-textarea")
commentInput.innerText += key
commentList.value[index]["isPlaceholderVisible"] = false
} else {
inputTextareaRef.value.innerHTML += key
isPlaceholderVisible.value = false
}
}
let isPlaceholderVisible = ref(true)
const clearPlaceholder = (index, i) => {
if (i != undefined) commentList.value[index].child[i]["isPlaceholderVisible"] = false
else if (index != undefined) commentList.value[index]["isPlaceholderVisible"] = false
else isPlaceholderVisible.value = false
}
const setPlaceholder = (event, index, i) => {
if (event.target.innerHTML == "<br>") event.target.innerHTML = ""
const html = event.target.innerHTML
if (!html) {
if (i != undefined) commentList.value[index].child[i]["isPlaceholderVisible"] = true
else if (index != undefined) commentList.value[index]["isPlaceholderVisible"] = true
else isPlaceholderVisible.value = true
}
}
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() // 获取文件
const reader = new FileReader()
reader.onload = e => {
const base64 = e.target.result
uploadImg(base64).then(res => {
const obj = {
base64,
...res,
}
if (i != undefined) commentList.value[index].child[ii]["picture"] = obj
else if (index != undefined) commentList.value[index]["picture"] = obj
else picture.value = obj
handleMsg("success", "上传成功")
})
}
reader.readAsDataURL(file)
}
}
}
let inputTextareaRef = ref(null)
// 提交回答-评论
const submitAnswerComments = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
let content = ""
let parentid = null
let token = detailsToken.value
let image = {}
if (i != null) {
const commentInput = document.querySelector(".comments-box .input-textarea")
content = commentInput.innerText
parentid = commentList.value[index]["child"][i]["id"]
image = commentList.value[index]["child"][i]["picture"]
} else if (index != null) {
const commentInput = document.querySelector(".comments-box .input-textarea")
content = commentInput.innerText
parentid = commentList.value[index]["id"]
image = commentList.value[index]["picture"]
} else {
content = inputTextareaRef.value.innerText
image = picture.value
}
$ajax("/api/comment/submit", {
content,
token,
parentid,
image,
}).then(res => {
if (res.code != 200) return
let data = res.data
if (i != null) {
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
reply: {
nickname: commentList.value[index]["child"][i]["nickname"],
},
...data,
isPlaceholderVisible: true,
image,
}
commentList.value[index]["child"].push(targetData)
commentList.value[index]["childnum"]++
} else if (index != null) {
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
reply: [],
...data,
isPlaceholderVisible: true,
image,
}
commentList.value[index]["child"].unshift(targetData)
commentList.value[index]["childnum"]++
} else {
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
...data,
child: [],
isPlaceholderVisible: true,
image,
}
commentList.value.unshift(targetData)
commentCount.value++
inputTextareaRef.value.innerHTML = ""
picture.value = {}
}
// targetAnswerList[index]["commentnum"] = data["count"]
closeAnswerCommentsChild()
handleMsg("success", res["message"] || "操作成功")
})
}
// 回答-评论 点赞
const operateAnswerCommentsLike = (token, index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
$ajax("/api/comment/like", {
token,
}).then(res => {
if (res.code != 200) return
let data = res.data
console.log("i", i)
if (i != undefined) {
commentList.value[index].child[i]["islike"] = data["status"]
commentList.value[index].child[i]["likenum"] = data["likenum"]
} else {
commentList.value[index]["islike"] = data["status"]
commentList.value[index]["likenum"] = data["likenum"]
}
handleMsg("success", res["message"] || "操作成功")
})
}
// 打开 回答-评论 的子评论
const openAnswerCommentsChild = (index, i) => {
// console.log("isNeedLogin", isNeedLogin)
if (isNeedLogin.value) {
goLogin()
return
}
closeAnswerCommentsChild()
if (i == null) commentList.value[index]["childState"] = true
else commentList.value[index]["child"][i]["childState"] = true
}
// 关闭 回答-评论 的子评论
const closeAnswerCommentsChild = () => {
commentList.value.forEach(ele => {
ele["childState"] = false
if (ele["child"] && ele["child"].length != 0) {
ele["child"].forEach(el => {
el["childState"] = false
})
}
})
}
// 获取剩下的子评论
const alsoCommentsData = (index, i) => {
// const targetAnswerList = [...answerList.value]
const parentid = commentList.value[index]["id"]
const token = detailsToken.value
$ajax("/api/comment/childrenList", {
token,
parentid,
limit: 20,
page: 1,
childlimit: 1,
}).then(res => {
if (res.code != 200) return
let data = res.data
let merged = [...commentList.value[index]["child"], ...data.data.filter(item2 => !commentList.value[index]["child"].find(item1 => item1.id == item2.id))]
console.log("merged1", merged)
merged.forEach(element => {
element["isPlaceholderVisible"] = true
})
commentList.value[index]["child"] = merged
// answerList.value = targetAnswerList
})
}
const handleMenuState = inject("handleMenuState")
const openMenuState = (index, i) => {
if (isNeedLogin.value) {
goLogin()
return
}
let reportToken = ""
if (i === undefined) reportToken = commentList.value[index]["token"]
else reportToken = commentList.value[index]["child"][i]["token"]
handleMenuState(reportToken)
}
</script>
<style scoped></style>