Files
PC-vote/components/DetailsComments.vue
DESKTOP-RQ919RC\Pc 982e5781eb 重新打包
2025-11-19 14:51:00 +08:00

1206 lines
49 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 flexacenter" v-if="editPicture.length != 0">
<div class="picture" v-for="item in editPicture" :key="item.url">
<img class="close" @click="closeEditFileUpload(item.aid)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="item.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ pitch: editEmojiState }" style="z-index: 2">
<el-popover placement="left-start" popper-class="emoji-popover" :width="584" trigger="click" v-model:visible="editEmojiState" :teleported="false">
<template #reference>
<img class="icon" src="@/assets/img/smiling-face.png" alt="" />
</template>
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEditEmoji(item)">{{ item }}</div>
</div>
</el-popover>
</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">最多可上传{{ maxPicture }}张图片支持在输入框中直接粘贴图片</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 || 0 }}</span>
</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 flexacenter" v-if="picture.length != 0" style="width: 470px">
<div class="picture" v-for="(item, index) in picture" :key="index">
<img class="close" @click="closeFileUpload(item.aid)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="item.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ pitch: emojiState }">
<el-popover placement="left" popper-class="emoji-popover" :width="625" trigger="click" v-model:visible="emojiState" :teleported="false">
<template #reference>
<img class="icon" src="@/assets/img/smiling-face.png" alt="" />
</template>
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item)">{{ item }}</div>
</div>
</el-popover>
</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">最多可上传{{ maxPicture }}张图片支持在输入框中直接粘贴图片</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(commentInputTop)">发送</div>
</div>
</div>
<div class="empty-box" v-if="commentComments == 0">
<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 || item.user['avatar']" />
</template>
<div class="avatar-box flexflex" v-if="item.uin || item.user['uin'] || item.uid || item.user['uid']">
<a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(item.uniqid || item.user['uniqid'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(item.uniqid || item.user['uniqid'])">
<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 || item.user["nickname"] || "匿名用户" }}</div>
<div class="comments-time">{{ item["timestamp"] }}</div>
<div class="comments-identity" v-if="item['isauthor'] == 1">作者</div>
<img class="comments-title" v-if="item.groupimage || item?.user?.groupimage" :src="item.groupimage || item?.user?.groupimage" :alt="item?.user?.grouptitle" style="height: 18px" />
</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="!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-red-pitch.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>
<div class="comment-text" v-if="item['content']" @click="!item['childState'] ? openAnswerCommentsChild(index) : closeAnswerCommentsChild()">{{ item["content"] }}</div>
<div class="comments-img-box flexacenter" v-if="item.attachments?.images?.length != 0" style="overflow: auto; width: 440px">
<img class="comments-img" v-for="(item, index) in item?.attachments?.images" :key="index" @click="handleAnswerText" :src="item.thumb || item.url" />
</div>
<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 flexacenter" v-if="item?.picture?.length != 0" style="width: 440px">
<div class="picture" v-for="it in item.picture" :key="it.url">
<img class="close" @click="closeFileUpload(it.aid, index)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="it.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ pitch: item.emojiState }">
<el-popover placement="left" popper-class="emoji-popover" :width="625" trigger="click" v-model:visible="item.emojiState" :teleported="false">
<template #reference>
<img class="icon" src="@/assets/img/smiling-face.png" alt="" />
</template>
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item, index)">{{ item }}</div>
</div>
</el-popover>
</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">最多可上传{{ maxPicture }}张图片支持在输入框中直接粘贴图片</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(item['commentInput'], index)">发送</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 || ite.user['avatar']" />
</template>
<div class="avatar-box flexflex" v-if="ite.uin || ite.user['uin'] || ite.uid || ite.user['uid']">
<a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(ite.uniqid || ite.user['uniqid'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息
</a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(ite.uniqid || ite.user['uniqid'])">
<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 || ite.user["nickname"] || "匿名用户" }}</div>
<div class="comments-time">{{ ite["timestamp"] }}</div>
<div class="comments-identity" v-if="ite['isauthor']">作者</div>
<img class="comments-title" v-if="ite.groupimage || ite.user?.groupimage" :src="ite.groupimage || ite.user?.groupimage" :alt="ite?.user?.grouptitle" style="height: 18px" />
</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-red-pitch.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>
<div class="comments-img-box flexacenter" v-if="ite.attachments?.images?.length != 0" style="overflow: auto; width: 410px">
<img class="comments-img" v-for="(item, index) in ite.attachments?.images" :key="index" @click="handleAnswerText" :src="item.thumb || item.url" />
</div>
<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'] || ite.user['nickname'] || '匿名用户') + '”:'" v-model="ite['commentInput']" @input="autoResize" @paste="handleInputPaste($event, index)"></textarea>
</div>
<div class="picture-box flexacenter" v-if="ite.picture?.length != 0" style="width: 408px">
<div class="picture" v-for="it in ite.picture" :key="it.url">
<img class="close" @click="closeFileUpload(it.aid, index, i)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="it.url" />
</div>
</div>
<div class="bottom flexacenter">
<div class="operate flexacenter">
<div class="item" :class="{ pitch: ite.emojiState }">
<el-popover placement="left" popper-class="emoji-popover" :width="625" trigger="click" v-model:visible="ite.emojiState" :teleported="false">
<template #reference>
<img class="icon" src="@/assets/img/smiling-face.png" alt="" />
</template>
<div class="emoji-box">
<div class="emoji-icon" v-for="item in emojiData" :key="item" @click="selectEmoji(item, index, i)">{{ item }}</div>
</div>
</el-popover>
</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">最多可上传{{ maxPicture }}张图片支持在输入框中直接粘贴图片</span>
</div>
</div>
<div class="btn" @click="submitAnswerComments(ite['commentInput'], index, i)">发送</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" :reportType="reportType"></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>
<Like v-if="isLikeGif"></Like>
</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);
checkWConfig();
});
const checkWConfig = () => {
const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {};
if (wConfig.time) {
const time = new Date(wConfig.time);
const now = new Date();
if (now - time > 24 * 60 * 60 * 1000) getWConfig();
else {
const config = wConfig.config || {};
maxPicture.value = config.topic_image_count;
}
} else getWConfig();
};
const getWConfig = () => {
getWConfigHttp().then((res) => {
if (res.code != 200) return;
let data = res["data"] || {};
const config = data.config || {};
maxPicture.value = config.topic_image_count;
data.time = new Date().toISOString();
localStorage.setItem("wConfig", JSON.stringify(data));
});
};
let permissions = inject("permissions");
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: 3,
limit: 10,
token: props.token,
})
.then((res) => {
if (res.code != 200) return;
let data = res.data;
data.data.forEach((element, index) => {
element.timestamp = strtimeago(element.created_at, 4);
element["picture"] = [];
element["isReplyBoxShow"] = 0;
if (element.child.length > 0) {
element.child.forEach((el) => {
el["picture"] = [];
el.timestamp = strtimeago(el.created_at, 4);
el["isReplyBoxShow"] = 0;
});
}
});
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["commentcount"];
emit("update:commentComments", data["commentcount"]);
if (commentList.value.length == data["count"]) commentPage.value = 0;
else commentPage.value++;
})
.finally(() => (commentLoading = false));
};
// 点赞
let isLikeGif = ref(false);
// 评论点赞
const commentLike = (index, i) => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
openAttest();
return;
}
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;
const status = data["status"];
if (i != null) {
targetCommentList[index]["child"][i].islike = status;
targetCommentList[index]["child"][i].likenum = data["count"];
} else {
targetCommentList[index].islike = status;
targetCommentList[index].likenum = data["count"];
}
ElMessage.success(res.message);
if (status) {
isLikeGif.value = false;
nextTick(() => {
isLikeGif.value = true;
setTimeout(() => (isLikeGif.value = false), 2000);
});
}
});
};
// 打开 回答-评论 的子评论
const openAnswerCommentsChild = (index, i) => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
openAttest();
return;
}
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 = () => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
openAttest();
return;
}
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("");
let openAttest = inject("openAttest");
const realname = inject("realname");
// 提交回答-评论
const submitAnswerComments = (content = "", index, i) => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
openAttest();
return;
}
if (isNeedLogin.value) {
goLogin();
return;
}
const targetCommentList = [...commentList.value];
let parentid = null;
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;
const attachments = {
images: image,
};
detailsSubmitommentListHttp({
content,
token: props.token,
replyid: parentid,
attachments,
}).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message);
return;
}
let data = res.data;
const timestamp = strtimeago(new Date());
if (i != null) {
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,
attachments,
picture: [],
timestamp,
uin: userInfoWin.value.uin,
uid: userInfoWin.value.uid,
};
targetCommentList[index]["child"].unshift(targetData);
targetCommentList[index]["childnum"]++;
} else {
let targetData = {
id: data["commentid"],
content,
isauthor: 1,
islike: 0,
likenum: 0,
...data,
timestamp,
child: [],
voteoption: haveVotedValue.value || null,
attachments,
uin: userInfoWin.value.uin,
uid: userInfoWin.value.uid,
picture: [],
childnum: 0,
};
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 = data.count || 0;
emit("update:commentComments", data.count || 0);
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 parentid = targetCommentItem["id"];
let page = targetCommentItem["childPage"] ?? 1;
detailsChildCommentListHttp({
childlimit: 3,
limit: 2000,
page: 1,
parentid,
token: props.token,
}).then((res) => {
if (res.code != 200) return;
let data = res.data;
data.data.forEach((element, index) => {
element.timestamp = strtimeago(element.created_at, 4);
element["isReplyBoxShow"] = 0;
element["picture"] = [];
});
let merged = [...commentList.value[index]["child"], ...data.data.filter((item2) => !commentList.value[index]["child"].find((item1) => item1.id == item2.id))];
commentList.value[index]["child"] = merged;
});
};
let reportAlertShow = ref(false);
let reportToken = ref("");
let reportType = ref("");
// 点击打开举报
const report = (token) => {
if (isNeedLogin.value) {
goLogin();
return;
}
reportToken.value = token;
reportType.value = "comment";
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 = ["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵‍💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"];
// 打开 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;
}
let target = [];
if (editCommentState.value) target = editPicture.value;
else {
if (ii != undefined) target = commentList.value[index].child[ii]["picture"];
else if (index != undefined) target = commentList.value[index]["picture"];
else target = picture.value;
}
if (target.length >= maxPicture.value) {
creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`);
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const base64 = e.target.result;
uploadImg(file).then((res) => {
const obj = {
aid: res.aid || "",
url: res.url || "",
};
target.push(obj);
if (editCommentState.value) editPicture.value = target;
else {
if (ii != undefined) commentList.value[index].child[ii]["picture"] = target;
else if (index != undefined) commentList.value[index]["picture"] = target;
else picture.value = target;
}
ElMessage.success("上传成功");
});
};
reader.readAsDataURL(file);
}
}
};
const maxPicture = ref(10);
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;
}
let target = [];
if (editCommentState.value) target = editPicture.value;
else {
if (i != undefined) target = commentList.value[index].child[i]["picture"];
else if (index != undefined) target = commentList.value[index]["picture"];
else target = picture.value;
}
if (target.length >= maxPicture.value) {
creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`);
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const base64 = e.target.result;
uploadImg(file).then((res) => {
const obj = {
aid: res.aid || "",
url: res.url || "",
};
target.push(obj);
if (editCommentState.value) editPicture.value = target;
else {
if (i != undefined) commentList.value[index].child[i]["picture"] = target;
else if (index != undefined) commentList.value[index]["picture"] = target;
else picture.value = target;
}
ElMessage.success("上传成功");
});
};
reader.readAsDataURL(file);
};
// 删除上传的图片
const closeFileUpload = (aid, index, i) => {
let target = [];
if (i != undefined) target = [...commentList.value[index].child[i]["picture"]];
else if (index != undefined) target = [...commentList.value[index]["picture"]];
else target = [...picture.value];
let sub = target.findIndex((item) => item.aid == aid);
if (sub != -1) target.splice(sub, 1);
if (i != undefined) commentList.value[index].child[i]["picture"] = target;
else if (index != undefined) commentList.value[index]["picture"] = target;
else picture.value = target;
};
// 上传图片 获取图片url
const uploadImg = (file) => {
return new Promise((resolve, reject) => {
const upload = () => {
let config = uploadConfig;
const formData = new FormData();
formData.append(config.requestName, file); // 文件数据
formData.append("type", "image"); // 文件名
formData.append("data", config.params.data); // 文件名
commonUploadHttp(config.url, formData).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message || "上传失败");
return;
}
let data = res.data;
resolve(data);
});
};
if (uploadConfig) upload();
else getUploadConfig().then(() => upload());
});
};
let uploadConfig = null;
const getUploadConfig = () => {
return new Promise((resolve, reject) => {
commonUploadConfigHttp().then((res) => {
let data = res.data;
uploadConfig = data;
resolve();
});
});
};
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;
emit("update:commentComments", commentComments.value);
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];
editToken = target.token || "";
editInput.value = target.content || "";
editPicture.value = target.attachments?.images || [];
editCommentState.value = true;
nextTick(() => {
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;
const attachments = {
images: image,
};
commentsEditSubmit({
content: editInput.value,
token: editToken,
attachments,
}).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message);
return;
}
commentList.value.forEach((element) => {
if (element.token == editToken) {
element["content"] = editInput.value;
element["attachments"] = attachments;
}
element.child &&
element.child.forEach((ele) => {
if (ele.token == editToken) {
ele["content"] = editInput.value;
ele["attachments"] = attachments;
}
});
});
editPicture.value = [];
editToken = "";
editCommentState.value = false;
editEmojiState.value = false;
ElMessage.success(res.message);
});
};
const closeEditFileUpload = (aid) => {
let target = editPicture.value;
let sub = target.findIndex((item) => item.aid == aid);
if (sub != -1) target.splice(sub, 1);
editPicture.value = target;
};
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;
padding: 0 !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;
}
}
}
.emoji-popover {
box-sizing: border-box;
* {
box-sizing: border-box;
}
padding: 0px !important;
border-radius: 10px !important;
border: 1px solid #ebebeb !important;
.el-popper__arrow {
z-index: 1;
&:before {
background-color: #fff;
border-top-color: #fff !important;
border-left-color: #fff !important;
}
}
}
</style>