feat(Details): 新增投票详情页管理功能和评论优化

- 添加投票详情页的管理功能,包括隐藏、推荐、精华和删除操作
- 优化评论组件,支持多图上传和显示
- 新增投币功能组件
- 更新API接口调用方式,适配新后端接口
- 完善用户权限管理逻辑
- 修复样式问题和交互体验
This commit is contained in:
DESKTOP-RQ919RC\Pc
2025-11-11 19:05:46 +08:00
parent ad6d186301
commit 68000d7e43
14 changed files with 839 additions and 226 deletions

12
app.vue
View File

@@ -49,6 +49,8 @@ let isNeedLogin = ref(true); // 是否需要登录状态
let isGetLoginState = ref(true); // 在获取登录状态 false 代表没有已经确定了 let isGetLoginState = ref(true); // 在获取登录状态 false 代表没有已经确定了
let realname = ref(1); // 是否已经实名 let realname = ref(1); // 是否已经实名
let userInfoWin = ref({}); let userInfoWin = ref({});
let permissions = ref([]);
let ismanager = ref(false);
provide("userInfoWin", userInfoWin); provide("userInfoWin", userInfoWin);
@@ -81,12 +83,15 @@ const goLogin = () => {
const getUserInfoWin = () => { const getUserInfoWin = () => {
const checkUser = () => { const checkUser = () => {
const user = window.userInfoWin; const user = window.userInfoWin;
if (!user) return; if (!user) return;
document.removeEventListener("getUser", checkUser); document.removeEventListener("getUser", checkUser);
realname.value = user.realname; realname.value = user.realname;
userInfoWin.value = user; userInfoWin.value = user;
if (user?.uin > 0 || user?.uid > 0) isNeedLogin.value = false; if (user?.uin > 0 || user?.uid > 0) isNeedLogin.value = false;
permissions.value = user?.authority || [];
ismanager.value = permissions.value.indexOf("topic:manager") >= 0;
}; };
document.addEventListener("getUser", checkUser); document.addEventListener("getUser", checkUser);
}; };
@@ -106,6 +111,9 @@ provide("goLogin", goLogin);
provide("isGetLoginState", isGetLoginState); provide("isGetLoginState", isGetLoginState);
provide("realname", realname); provide("realname", realname);
provide("openAttest", openAttest); provide("openAttest", openAttest);
provide("permissions", permissions);
provide("ismanager", ismanager);
</script> </script>
<style lang="less"> <style lang="less">
* { * {
@@ -261,6 +269,7 @@ input::-webkit-contacts-auto-fill-button {
.options-popup-btn { .options-popup-btn {
justify-content: space-between; justify-content: space-between;
.options-popup-item { .options-popup-item {
font-size: 13px; font-size: 13px;
width: 160px; width: 160px;
@@ -275,6 +284,7 @@ input::-webkit-contacts-auto-fill-button {
color: #fff; color: #fff;
margin-left: 20px; margin-left: 20px;
} }
&.options-no { &.options-no {
background-color: #fff; background-color: #fff;
border-color: rgba(170, 170, 170, 1); border-color: rgba(170, 170, 170, 1);

View File

@@ -167,6 +167,7 @@
background-color: transparent; background-color: transparent;
min-height: 80px; min-height: 80px;
padding-bottom: 11px; padding-bottom: 11px;
max-height: 400px;
} }
.input-box .top .input-textarea * { .input-box .top .input-textarea * {
background: transparent !important; background: transparent !important;
@@ -187,10 +188,13 @@
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px dotted rgba(215, 215, 215, 0.501961); border-bottom: 1px dotted rgba(215, 215, 215, 0.501961);
padding-left: 14px; padding-left: 14px;
padding-top: 10px;
overflow: auto;
} }
.input-box .picture-box .picture { .input-box .picture-box .picture {
position: relative; position: relative;
width: fit-content; width: fit-content;
margin-right: 10px;
} }
.input-box .picture-box .picture .img { .input-box .picture-box .picture .img {
height: 60px; height: 60px;

View File

@@ -194,6 +194,7 @@
background-color: transparent; background-color: transparent;
min-height: 80px; min-height: 80px;
padding-bottom: 11px; padding-bottom: 11px;
max-height: 400px;
// &.placeholder::after { // &.placeholder::after {
// content: "说说你的看法…"; // content: "说说你的看法…";
// color: #7f7f7f; // color: #7f7f7f;
@@ -223,10 +224,13 @@
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px dotted rgba(215, 215, 215, 0.501961); border-bottom: 1px dotted rgba(215, 215, 215, 0.501961);
padding-left: 14px; padding-left: 14px;
padding-top: 10px;
overflow: auto;
.picture { .picture {
position: relative; position: relative;
width: fit-content; width: fit-content;
margin-right: 10px;
.img { .img {
height: 60px; height: 60px;

View File

@@ -25,6 +25,7 @@
.content .header .label { .content .header .label {
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 15px; margin-bottom: 15px;
font-weight: 400;
} }
.content .header .label .item { .content .header .label .item {
font-size: 14px; font-size: 14px;
@@ -48,6 +49,77 @@
color: #ffffff; color: #ffffff;
background-color: #04b0d5; background-color: #04b0d5;
} }
.content .header .view {
font-size: 12px;
color: #aaaaaa;
margin-right: 15px;
font-weight: 400;
}
.content .header .view .icon {
width: 13px;
height: 8px;
margin-right: 5px;
}
.content .header .btn {
width: 24px;
height: 16px;
background-color: #f2f2f2;
border-radius: 150px;
cursor: pointer;
font-weight: 400;
}
.content .header .btn .icon {
width: 18px;
height: 18px;
}
.content .header .mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 12;
background-color: rgba(0, 0, 0, 0.1);
}
.content .header .operate {
position: absolute;
top: 23px;
right: 0;
width: 80px;
background-color: #f2f2f2;
border-radius: 8px;
padding: 5px;
z-index: 13;
font-weight: 400;
}
.content .header .operate::after {
content: "";
width: calc(100% - 10px);
height: calc(100% - 10px);
position: absolute;
top: 50%;
left: 50%;
display: block;
transform: translate(-50%, -50%);
background-color: #fbfbfb;
z-index: -1;
}
.content .header .operate .item {
text-align: center;
font-size: 14px;
color: #333333;
padding: 14px 0;
cursor: pointer;
}
.content .header .operate .item:first-of-type {
padding-top: 14px;
}
.content .header .operate .item:last-of-type {
padding-top: 14px;
}
.content .header .operate .item:not(:last-of-type) {
border-bottom: 1px dotted #d7d7d7;
}
.content .left { .content .left {
width: 658px; width: 658px;
min-height: calc(100vh - 165px); min-height: calc(100vh - 165px);

View File

@@ -26,6 +26,7 @@
.label { .label {
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 15px; margin-bottom: 15px;
font-weight: 400;
.item { .item {
font-size: 14px; font-size: 14px;
@@ -53,6 +54,88 @@
} }
} }
} }
.view {
font-size: 12px;
color: #aaaaaa;
margin-right: 15px;
font-weight: 400;
.icon {
width: 13px;
height: 8px;
margin-right: 5px;
}
}
.btn {
width: 24px;
height: 16px;
background-color: rgba(242, 242, 242, 1);
border-radius: 150px;
cursor: pointer;
font-weight: 400;
.icon {
width: 18px;
height: 18px;
}
}
.mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 12;
background-color: rgba(0, 0, 0, 0.1);
}
.operate {
position: absolute;
top: 23px;
right: 0;
width: 80px;
background-color: rgba(242, 242, 242, 1);
border-radius: 8px;
padding: 5px;
z-index: 13;
font-weight: 400;
&::after {
content: "";
width: calc(100% - 10px);
height: calc(100% - 10px);
position: absolute;
top: 50%;
left: 50%;
display: block;
transform: translate(-50%, -50%);
background-color: rgba(251, 251, 251, 1);
z-index: -1;
}
.item {
text-align: center;
font-size: 14px;
color: #333333;
padding: 14px 0;
cursor: pointer;
&:first-of-type {
padding-top: 14px;
}
&:last-of-type {
padding-top: 14px;
}
&:not(:last-of-type) {
border-bottom: 1px dotted #d7d7d7;
}
}
}
} }
.left { .left {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

View File

@@ -14,33 +14,31 @@
</el-popover> </el-popover>
</div> </div>
<div class="floor-left flexacenter"> <div class="floor-left flexacenter">
<div class="item flexacenter" style="cursor: auto">
<img class="icon" src="@/assets/img/eye-icon-black.svg" />
<div>{{ info["views"] }}</div>
</div>
<div class="item flexacenter" @click="handleLike"> <div class="item flexacenter" @click="handleLike">
<img class="icon pitch" v-if="islike == 1" src="@/assets/img/like-red-pitch.png" /> <img class="icon pitch" v-if="islike == 1" src="@/assets/img/like-red-pitch.png" />
<img class="icon" v-else src="@/assets/img/like-icon.png" /> <img class="icon" v-else src="@/assets/img/like-icon.png" />
<div>{{ info["likes"] || "" }}</div> <div>{{ topicInfo["likes"] || "" }}</div>
</div> </div>
<div class="item flexacenter" @click="handleCollect()"> <div class="item flexacenter" @click="handleCollect()">
<img class="icon" v-if="iscollection == 1" src="@/assets/img/collect-icon-colours.svg" /> <img class="icon" v-if="iscollection == 1" src="@/assets/img/collect-icon-colours.svg" />
<img class="icon" v-else src="@/assets/img/collect-icon.png" /> <img class="icon" v-else src="@/assets/img/collect-icon.png" />
<div>{{ info["favs"] || "收藏" }}</div> <div>{{ topicInfo["collections"] || "收藏" }}</div>
</div> </div>
<div class="item flexacenter" style="cursor: auto"> <div class="item flexacenter" style="cursor: auto">
<img class="icon" src="@/assets/img/discuss-icon.png" /> <img class="icon" src="@/assets/img/discuss-icon.png" />
<div>{{ commentComments }}</div> <div>{{ commentTotalCount || "讨论" }}</div>
</div> </div>
<div class="item flexacenter" style="cursor: auto"> <div class="item flexacenter" style="cursor: auto" @click="openBi()">
<img class="icon" src="@/assets/img/discuss-icon.png" /> <img class="icon" src="@/assets/img/bi-black-icon.png" />
<div>{{ commentComments }}</div> <div>{{ topicInfo.coins || "投币" }}</div>
</div> </div>
<ClientOnly> <ClientOnly>
<el-popover placement="bottom" width="628px" trigger="click" popper-style="padding: 0;border-radius: 10px;" v-model:visible="transmitBoxState"> <el-popover placement="bottom" width="628px" trigger="click" popper-style="padding: 0;border-radius: 10px;" v-model:visible="transmitBoxState">
<template #reference> <template #reference>
<div class="item flexacenter" @click="handleShare"><img class="icon" src="@/assets/img/transmit-icon.png" />转发</div> <div class="item flexacenter" @click="handleShare">
<img class="icon" src="@/assets/img/transmit-icon.png" />转发
</div>
</template> </template>
<div class="transmit-box flexflex"> <div class="transmit-box flexflex">
@@ -51,7 +49,9 @@
<div class="transmit-headline">{{ info["title"] }}</div> <div class="transmit-headline">{{ info["title"] }}</div>
<div class="transmit-url">{{ getFullUrl() }}</div> <div class="transmit-url">{{ getFullUrl() }}</div>
</div> </div>
<div class="transmit-web-btn flexcenter" @click="copyText(`${info['title']} + ${getFullUrl()}`)">复制链接</div> <div class="transmit-web-btn flexcenter" @click="copyText(`${info['title']} + ${getFullUrl()}`)">
复制链接
</div>
</div> </div>
<div class="transmit-right transmit-mini"> <div class="transmit-right transmit-mini">
<div class="transmit-title">转发小程序版</div> <div class="transmit-title">转发小程序版</div>
@@ -86,6 +86,8 @@
</div> </div>
</div> </div>
<Like v-if="isLikeGif"></Like> <Like v-if="isLikeGif"></Like>
<bi-card :coins="topicInfo.coins" :token="topicToken"></bi-card>
</template> </template>
<script setup> <script setup>
@@ -94,8 +96,11 @@ import { ElMessage } from "element-plus";
let props = defineProps({ let props = defineProps({
ripostecount: Object, ripostecount: Object,
commentComments: Number, commentComments: Number,
}); });
let topicInfo = inject("topicInfo");
const respondShowState = ref(false); const respondShowState = ref(false);
let openAttest = inject("openAttest"); let openAttest = inject("openAttest");
@@ -110,6 +115,7 @@ let islike = inject("islike");
let iscollection = inject("iscollection"); let iscollection = inject("iscollection");
let qrcode = inject("qrcode"); let qrcode = inject("qrcode");
let token = inject("token"); let token = inject("token");
let topicToken = inject("topicToken");
const topHeadRef = inject("topHeadRef"); const topHeadRef = inject("topHeadRef");
const isLoaded = inject("isLoaded"); const isLoaded = inject("isLoaded");
@@ -158,14 +164,14 @@ const handleCollect = () => {
topHeadRef.value.count = {}; topHeadRef.value.count = {};
operateCollectHttp({ token: token.value }).then((res) => { operateCollectHttp({ token: topicToken.value }).then((res) => {
if (res.code != 200) { if (res.code != 200) {
ElMessage.error(res["message"]); ElMessage.error(res["message"]);
return; return;
} }
let data = res.data; let data = res.data;
info.value["favs"] = data["count"]; topicInfo.value["collections"] = data["collections"];
iscollection.value = data["status"]; iscollection.value = data["status"];
ElMessage.success(res["message"]); ElMessage.success(res["message"]);
@@ -195,7 +201,7 @@ const handleLike = () => {
return; return;
} }
operateLikeHttp({ token: token.value }).then((res) => { operateLikeHttp({ token: topicToken.value }).then((res) => {
if (res.code != 200) { if (res.code != 200) {
ElMessage.error(res.message); ElMessage.error(res.message);
return; return;
@@ -204,7 +210,7 @@ const handleLike = () => {
let data = res.data; let data = res.data;
const status = data["status"]; const status = data["status"];
info.value["likes"] = data["count"]; topicInfo.value["likes"] = data["likes"];
islike.value = status; islike.value = status;
ElMessage.success(res.message); ElMessage.success(res.message);
@@ -227,7 +233,7 @@ const emit = defineEmits(["closeDiscussInputFields"]);
// // 点击底部调用关闭讨论输入框 // // 点击底部调用关闭讨论输入框
const closeDiscussInputFields = () => emit("closeDiscussInputFields"); const closeDiscussInputFields = () => emit("closeDiscussInputFields");
onMounted(() => {}); onMounted(() => { });
watch(isLoaded, (newValue, oldValue) => { watch(isLoaded, (newValue, oldValue) => {
if (newValue === true) { if (newValue === true) {
@@ -262,6 +268,15 @@ onBeforeUnmount(() => {
const randomBottomEmojis = inject("randomBottomEmojis"); const randomBottomEmojis = inject("randomBottomEmojis");
const selectEomji = inject("selectEomji"); const selectEomji = inject("selectEomji");
const jointriposte = inject("jointriposte"); const jointriposte = inject("jointriposte");
const openBi = () => {
if (isNeedLogin.value) {
goLogin();
return;
}
BiComponent.initComponent();
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@@ -281,12 +296,15 @@ const jointriposte = inject("jointriposte");
-webkit-box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098); -webkit-box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098); box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.192156862745098);
display: none; display: none;
&.show { &.show {
display: flex; display: flex;
animation: animafloor 1s forwards; animation: animafloor 1s forwards;
animation-timing-function: cubic-bezier(0.98, -0.2, 0.55, 0.97); /* 先快后慢的时间曲线 */ animation-timing-function: cubic-bezier(0.98, -0.2, 0.55, 0.97);
/* 先快后慢的时间曲线 */
animation-fill-mode: both; animation-fill-mode: both;
} }
.floor-content { .floor-content {
width: 1200px; width: 1200px;
height: 100%; height: 100%;
@@ -294,6 +312,7 @@ const jointriposte = inject("jointriposte");
padding: 0 30px; padding: 0 30px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.floor-left { .floor-left {
margin-left: 30px; margin-left: 30px;
// flex: 1; // flex: 1;
@@ -301,8 +320,8 @@ const jointriposte = inject("jointriposte");
.item { .item {
cursor: pointer; cursor: pointer;
color: #aaaaaa; color: #333333;
font-size: 13px; font-size: 14px;
margin-right: 50px; margin-right: 50px;
.icon { .icon {
@@ -316,9 +335,11 @@ const jointriposte = inject("jointriposte");
0% { 0% {
transform: scale(1); transform: scale(1);
} }
50% { 50% {
transform: scale(1.2); transform: scale(1.2);
} }
100% { 100% {
transform: scale(1); transform: scale(1);
} }
@@ -365,6 +386,7 @@ const jointriposte = inject("jointriposte");
border-radius: 152px; border-radius: 152px;
background-color: #fff; background-color: #fff;
border: 1px solid rgba(215, 215, 215, 1); border: 1px solid rgba(215, 215, 215, 1);
.avatar { .avatar {
width: 28px; width: 28px;
height: 28px; height: 28px;
@@ -378,6 +400,7 @@ const jointriposte = inject("jointriposte");
outline: none; outline: none;
padding: 0 12px; padding: 0 12px;
font-size: 14px; font-size: 14px;
/deep/ .el-input__wrapper { /deep/ .el-input__wrapper {
box-shadow: none; box-shadow: none;
padding: 0; padding: 0;
@@ -390,6 +413,7 @@ const jointriposte = inject("jointriposte");
background-color: var(--main-color); background-color: var(--main-color);
border-radius: 20px; border-radius: 20px;
cursor: pointer; cursor: pointer;
.comment-btn-icon { .comment-btn-icon {
width: 14px; width: 14px;
height: 15px; height: 15px;
@@ -417,6 +441,7 @@ const jointriposte = inject("jointriposte");
.respond-box { .respond-box {
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
.respond-item { .respond-item {
font-family: "emojifont"; font-family: "emojifont";
font-size: 18px; font-size: 18px;

View File

@@ -8,10 +8,11 @@
<div class="top flexflex"> <div class="top flexflex">
<textarea ref="editInputRef" class="input-textarea flex1" maxlength="500" v-model="editInput" @focus="judgeLogin" @input="autoResize" @paste="handleInputPaste" placeholder="说说你的想法或疑问…"></textarea> <textarea ref="editInputRef" class="input-textarea flex1" maxlength="500" v-model="editInput" @focus="judgeLogin" @input="autoResize" @paste="handleInputPaste" placeholder="说说你的想法或疑问…"></textarea>
</div> </div>
<div class="picture-box" v-if="editPicture.url">
<div class="picture"> <div class="picture-box flexacenter" v-if="editPicture.length != 0">
<img class="close" @click="closeEditFileUpload()" src="@/assets/img/close-icon.png" /> <div class="picture" v-for="(item, index) in editPicture" :key="item.url">
<img class="img" @click="handleAnswerText" :src="editPicture.base64 || editPicture.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> </div>
@@ -61,10 +62,10 @@
<img class="avatar" v-if="userInfoWin.avatar" :src="userInfoWin.avatar" /> <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> <textarea class="input-textarea flex1" maxlength="500" v-model="commentInputTop" @focus="judgeLogin" @input="autoResize" @paste="handleInputPaste" placeholder="说说你的想法或疑问…"></textarea>
</div> </div>
<div class="picture-box" v-if="picture.url"> <div class="picture-box flexacenter" v-if="picture.length != 0">
<div class="picture"> <div class="picture" v-for="(item, index) in picture" :key="index">
<img class="close" @click="closeFileUpload()" src="@/assets/img/close-icon.png" /> <img class="close" @click="closePictureUpload(index)" src="@/assets/img/close-icon.png" />
<img class="img" @click="handleAnswerText" :src="picture.base64 || picture.url" /> <img class="img" @click="handleAnswerText" :src="item.url" />
</div> </div>
</div> </div>
<div class="bottom flexacenter"> <div class="bottom flexacenter">
@@ -98,15 +99,15 @@
<div class="comment-item flexflex" v-for="(item, index) in commentList" :key="item.id"> <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']"> <el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false" v-model:visible="item['popoverState']">
<template #reference> <template #reference>
<img class="comment-avatar" :src="item['avatar']" /> <img class="comment-avatar" :src="item.avatar || item.user['avatar']" />
</template> </template>
<div class="avatar-box flexflex" v-if="item['uin']"> <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['uin'])"> <a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(item.uin || item.user['uin'], item.uid || item.user['uid'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" /> <img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息 发送信息
</a> </a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(item['uin'])"> <a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(item.uin || item.user['uin'], item.uid || item.user['uid'])">
<img class="avatar-icon" src="@/assets/img/homepage-icon.png" /> <img class="avatar-icon" src="@/assets/img/homepage-icon.png" />
TA的主页 TA的主页
</a> </a>
@@ -115,11 +116,10 @@
<div class="comment-content flex1"> <div class="comment-content flex1">
<div class="comment-header flexacenter"> <div class="comment-header flexacenter">
<div class="comment-header-left flexacenter"> <div class="comment-header-left flexacenter">
<div class="comments-username" @click="openAvatarPopover(index)">{{ item["nickname"] }}</div> <div class="comments-username" @click="openAvatarPopover(index)">{{ item.nickname || item.user["nickname"] || "匿名用户" }}</div>
<div class="comments-time">{{ item["timestampnow"] || handleDate(item["timestamp"]) }}</div> <div class="comments-time">{{ item["timestamp"] }}</div>
<div class="comments-identity" v-if="item['isauthor']">作者</div> <div class="comments-identity" v-if="item['isauthor'] == 1">作者</div>
<!-- <img class="comments-title" v-if="item['groupid'] === 14" src="@/assets/img/title.png" /> --> <img class="comments-title" v-if="item.groupimage || item?.user?.groupimage" :src="item.groupimage || item?.user?.groupimage" :alt="item?.user?.grouptitle" style="height: 18px" />
<img class="comments-title" v-if="item['groupimage']" :src="item.groupimage" :alt="item.grouptitle" />
</div> </div>
<div class="comment-header-right flexacenter"> <div class="comment-header-right flexacenter">
<div class="menu-box flexacenter"> <div class="menu-box flexacenter">
@@ -130,7 +130,6 @@
<div class="item flexcenter" v-if="permissions.includes('comment.delete')" @click="commentDelete(item['token'], index)">删除</div> <div class="item flexcenter" v-if="permissions.includes('comment.delete')" @click="commentDelete(item['token'], index)">删除</div>
</div> </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" /> <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)"> <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-if="item['islike'] == 1" src="@/assets/img/like-red-pitch.png" />
@@ -139,19 +138,22 @@
</div> </div>
</div> </div>
</div> </div>
<!-- shutAnswerCommentsChild openAnswerCommentsChild -->
<div class="comment-text" v-if="item['content']" @click="!item['childState'] ? openAnswerCommentsChild(index) : closeAnswerCommentsChild()">{{ item["content"] }}</div> <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" /> <!-- <img class="comments-img" @click="handleAnswerText" :src="item.image?.base64 || item.image?.url" v-if="item.image?.url" /> -->
<div class="comments-img-box">
<img class="comments-img" v-for="(item, index) in item.attachments.images" @click="handleAnswerText" :src="item.thumb || item.url" />
</div>
<div class="alreadyVoted" v-if="item.voteoption">已投{{ item.voteoption }}</div> <div class="alreadyVoted" v-if="item.voteoption">已投{{ item.voteoption }}</div>
<div class="input-box" v-if="item['childState']"> <div class="input-box" v-if="item['childState']">
<img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" /> <img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" />
<div class="top flexflex"> <div class="top flexflex">
<textarea class="input-textarea flex1" maxlength="500" placeholder="说说你的想法或疑问…" v-model="item['commentInput']" @input="autoResize" @paste="handleInputPaste($event, index)"></textarea> <textarea class="input-textarea flex1" maxlength="500" placeholder="说说你的想法或疑问…" v-model="item['commentInput']" @input="autoResize" @paste="handleInputPaste($event, index)"></textarea>
</div> </div>
<div class="picture-box" v-if="item.picture?.url">
<div class="picture"> <div class="picture-box flexacenter" v-if="item?.picture?.length != 0" style="width: 440px;">
<img class="close" @click="closeFileUpload(index)" src="@/assets/img/close-icon.png" /> <div class="picture" v-for="it in item.picture" :key="it.url">
<img class="img" @click="handleAnswerText" :src="item.picture?.base64 || item.picture.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> </div>
<div class="bottom flexacenter"> <div class="bottom flexacenter">
@@ -176,30 +178,21 @@
<div class="btn" @click="submitAnswerComments(item['commentInput'], index)">发送</div> <div class="btn" @click="submitAnswerComments(item['commentInput'], index)">发送</div>
</div> </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="child-comments" v-if="item['child'].length > 0">
<div class="comment-item flexflex" v-for="(ite, i) in item['child']" :key="ite.id"> <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']"> <el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false" v-model:visible="ite['popoverState']">
<template #reference> <template #reference>
<img class="comment-avatar" :src="ite['avatar']" /> <img class="comment-avatar" :src="ite.avatar || ite.user['avatar']" />
</template> </template>
<div class="avatar-box flexflex" v-if="ite['uin']"> <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['uin'])"> <a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(ite.uin || ite.user['uin'], ite.uid || ite.user['uid'])">
<img class="avatar-icon" src="@/assets/img/send-messages-icon.png" /> <img class="avatar-icon" src="@/assets/img/send-messages-icon.png" />
发送信息 发送信息
</a> </a>
<a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(ite['uin'])"> <a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(ite.uin || ite.user['uin'], ite.uid || ite.user['uid'])">
<img class="avatar-icon" src="@/assets/img/homepage-icon.png" /> <img class="avatar-icon" src="@/assets/img/homepage-icon.png" />
TA的主页 TA的主页
</a> </a>
@@ -208,10 +201,10 @@
<div class="comment-content flex1"> <div class="comment-content flex1">
<div class="comment-header flexacenter"> <div class="comment-header flexacenter">
<div class="comment-header-left flexacenter"> <div class="comment-header-left flexacenter">
<div class="comments-username" @click="openAvatarPopover(index, i)">{{ ite["nickname"] }}</div> <div class="comments-username" @click="openAvatarPopover(index, i)">{{ ite.nickname || ite.user["nickname"] || "匿名用户" }}</div>
<div class="comments-time">{{ ite["timestampnow"] || handleDate(ite["timestamp"]) }}</div> <div class="comments-time">{{ ite["timestamp"] }}</div>
<div class="comments-identity" v-if="ite['isauthor']">作者</div> <div class="comments-identity" v-if="ite['isauthor']">作者</div>
<img class="comments-title" v-if="ite['groupimage']" :src="ite.groupimage" :alt="ite.grouptitle" /> <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>
<div class="comment-header-right flexacenter"> <div class="comment-header-right flexacenter">
<div class="menu-box flexacenter"> <div class="menu-box flexacenter">
@@ -234,19 +227,24 @@
<div class="comments-reply" v-if="ite?.reply?.nickname">@{{ ite?.reply?.nickname }}</div> <div class="comments-reply" v-if="ite?.reply?.nickname">@{{ ite?.reply?.nickname }}</div>
{{ ite["content"] }} {{ ite["content"] }}
</div> </div>
<img class="comments-img" @click="handleAnswerText" :src="ite.image?.base64 || ite.image?.url" v-if="ite.image?.url" /> <!-- <img class="comments-img" @click="handleAnswerText" :src="ite.image?.base64 || ite.image?.url" v-if="ite.image?.url" /> -->
<div class="comments-img-box">
<img class="comments-img" v-for="(item, index) in ite.attachments.images" @click="handleAnswerText" :src="ite.thumb || ite.url" />
</div>
<div class="alreadyVoted" v-if="ite.voteoption">已投{{ ite.voteoption }}</div> <div class="alreadyVoted" v-if="ite.voteoption">已投{{ ite.voteoption }}</div>
<div class="input-box" v-if="ite['childState']"> <div class="input-box" v-if="ite['childState']">
<img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" /> <img class="cross" @click="closeAnswerCommentsChild()" src="@/assets/img/cross-icon.png" />
<div class="top flexflex"> <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> <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>
<div class="picture-box" v-if="ite.picture?.url">
<div class="picture"> <div class="picture-box flexacenter" v-if="ite.picture?.length != 0" style="width: 408px;">
<img class="close" @click="closeFileUpload(index, i)" src="@/assets/img/close-icon.png" /> <div class="picture" v-for="it in ite.picture" :key="it.url">
<img class="img" @click="handleAnswerText" :src="ite.picture.base64 || ite.picture.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> </div>
<div class="bottom flexacenter"> <div class="bottom flexacenter">
<div class="operate flexacenter"> <div class="operate flexacenter">
<div class="item" :class="{ pitch: ite.emojiState }"> <div class="item" :class="{ pitch: ite.emojiState }">
@@ -348,14 +346,7 @@ watch(
onMounted(() => window.addEventListener("scroll", handleScroll)); onMounted(() => window.addEventListener("scroll", handleScroll));
let permissions = ref([]); let permissions = inject("permissions");
onMounted(() => {
setTimeout(() => {
permissions.value = window["permissions"] || [];
// permissions.value = ["comment.edit", "comment.delete"]
}, 1000);
});
const sendMessage = inject("sendMessage"); const sendMessage = inject("sendMessage");
const TAHomePage = inject("TAHomePage"); const TAHomePage = inject("TAHomePage");
@@ -378,7 +369,7 @@ const getCommentList = () => {
commentListHttp({ commentListHttp({
page: commentPage.value, page: commentPage.value,
childlimit: 1, childlimit: 3,
limit: 10, limit: 10,
token: props.token, token: props.token,
}) })
@@ -386,6 +377,21 @@ const getCommentList = () => {
if (res.code != 200) return; if (res.code != 200) return;
let data = res.data; 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(element.created_at, 4);
el["isReplyBoxShow"] = 0;
});
}
});
commentCount.value = data["count"]; commentCount.value = data["count"];
if (data["count"] == 0) isEmptyState.value = true; if (data["count"] == 0) isEmptyState.value = true;
else isEmptyState.value = false; else isEmptyState.value = false;
@@ -431,10 +437,10 @@ const commentLike = (index, i) => {
if (i != null) { if (i != null) {
targetCommentList[index]["child"][i].islike = status; targetCommentList[index]["child"][i].islike = status;
targetCommentList[index]["child"][i].likenum = data["likenum"]; targetCommentList[index]["child"][i].likenum = data["count"];
} else { } else {
targetCommentList[index].islike = status; targetCommentList[index].islike = status;
targetCommentList[index].likenum = data["likenum"]; targetCommentList[index].likenum = data["count"];
} }
ElMessage.success(res.message); ElMessage.success(res.message);
@@ -487,7 +493,7 @@ let openAttest = inject("openAttest");
const realname = inject("realname"); const realname = inject("realname");
// 提交回答-评论 // 提交回答-评论
const submitAnswerComments = (content, index, i) => { const submitAnswerComments = (content = "", index, i) => {
console.log("submitAnswerComments", submitAnswerComments); console.log("submitAnswerComments", submitAnswerComments);
if (realname.value == 0 && userInfoWin.value.uin > 0) { if (realname.value == 0 && userInfoWin.value.uin > 0) {
@@ -521,12 +527,16 @@ const submitAnswerComments = (content, index, i) => {
// ElMessage.error("请填写评论内容") // ElMessage.error("请填写评论内容")
// return // return
// } // }
const attachments = {
images: image,
};
detailsSubmitommentListHttp({ detailsSubmitommentListHttp({
content, content,
token: props.token, token: props.token,
parentid, replyid: parentid,
image: image ? { aid: image.aid, url: image.url } : null, attachments,
}).then((res) => { }).then((res) => {
if (res.code != 200) { if (res.code != 200) {
ElMessage.error(res.message); ElMessage.error(res.message);
@@ -534,6 +544,7 @@ const submitAnswerComments = (content, index, i) => {
} }
let data = res.data; let data = res.data;
const timestamp = strtimeago(new Date());
if (i != null) { if (i != null) {
// console.log("targetCommentList[index]", targetCommentList[index]) // console.log("targetCommentList[index]", targetCommentList[index])
@@ -551,10 +562,13 @@ const submitAnswerComments = (content, index, i) => {
}, },
voteoption: haveVotedValue.value || null, voteoption: haveVotedValue.value || null,
...data, ...data,
// ...data.data attachments,
timestampnow: "刚刚", picture: [],
uin: data.data?.uin, timestamp,
image,
uin: userInfoWin.value.uin,
uid: userInfoWin.value.uid,
}; };
targetCommentList[index]["child"].unshift(targetData); targetCommentList[index]["child"].unshift(targetData);
@@ -567,12 +581,12 @@ const submitAnswerComments = (content, index, i) => {
islike: 0, islike: 0,
likenum: 0, likenum: 0,
...data, ...data,
// ...data.data, timestamp,
timestampnow: "刚刚",
uin: data.data?.uin,
child: [], child: [],
voteoption: haveVotedValue.value || null, voteoption: haveVotedValue.value || null,
image, attachments,
uin: userInfoWin.value.uin,
uid: userInfoWin.value.uid,
}; };
if (index != null) { if (index != null) {
targetCommentList[index]["commentInput"] = ""; targetCommentList[index]["commentInput"] = "";
@@ -597,7 +611,7 @@ const submitAnswerComments = (content, index, i) => {
closeAnswerCommentsChild(); closeAnswerCommentsChild();
picture.value = {}; picture.value = [];
if (bottomNavigationState) { if (bottomNavigationState) {
bottomNavigationState = false; bottomNavigationState = false;
@@ -620,7 +634,7 @@ const alsoCommentsData = (index, ind) => {
let page = targetCommentItem["childPage"] ?? 1; let page = targetCommentItem["childPage"] ?? 1;
detailsChildCommentListHttp({ detailsChildCommentListHttp({
childlimit: 1, childlimit: 3,
limit: 10, limit: 10,
page, page,
parentid, parentid,
@@ -628,22 +642,32 @@ const alsoCommentsData = (index, ind) => {
}).then((res) => { }).then((res) => {
if (res.code != 200) return; if (res.code != 200) return;
let data = res.data; let data = res.data;
let childData = targetCommentItem.child.concat(data.data);
const filteredData = childData.filter((obj, index, self) => { data.data.forEach((element, index) => {
// 检查当前对象在数组中的第一个索引是否与当前索引相等 element.timestamp = strtimeago(element.created_at, 4);
return self.findIndex((item) => item.id == obj.id) == index; element["isReplyBoxShow"] = 0;
}); element["picture"] = [];
})
// let childData = targetCommentItem.child.concat(data.data);
targetCommentItem.child = filteredData; // const filteredData = childData.filter((obj, index, self) => {
targetCommentItem["childnum"] = data.count; // // 检查当前对象在数组中的第一个索引是否与当前索引相等
// return self.findIndex((item) => item.id == obj.id) == index;
// });
if (targetCommentItem.child.length == data["count"]) page = 0; // targetCommentItem.child = filteredData;
else page++; // targetCommentItem["childnum"] = data.count;
targetCommentItem["childPage"] = page; // if (targetCommentItem.child.length == data["count"]) page = 0;
// else page++;
commentList.value[index] = targetCommentItem; // targetCommentItem["childPage"] = page;
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;
// commentList.value[index] = targetCommentItem;
}); });
}; };
@@ -740,12 +764,11 @@ const postCommentFocusBlur = () => {
}, 200); }, 200);
}; };
let picture = ref({}); let picture = ref([]);
let emojiState = ref(false); let emojiState = ref(false);
let emojiMaskState = ref(false); let emojiMaskState = ref(false);
// , "🤝", "🙏", "💪", "❤️", "💔", "🌹", "🥀", "🎉", "🎁", "🧧", "🌙", "⭐", "🌍", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹"];
const emojiData = ["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵‍💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"]; const emojiData = ["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵‍💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"];
// 打开 Emoji // 打开 Emoji
@@ -844,6 +867,8 @@ const handleInputPaste = (event, index, ii) => {
} }
} }
}; };
const maxPicture = ref(10);
const handleFileUpload = (event, index, i) => { const handleFileUpload = (event, index, i) => {
closeEmoji(); closeEmoji();
@@ -859,19 +884,36 @@ const handleFileUpload = (event, index, i) => {
return; 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;
}
console.log("target", target);
if (target.length >= maxPicture.value) {
creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`);
return;
}
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
const base64 = e.target.result; const base64 = e.target.result;
uploadImg(file).then((res) => { uploadImg(file).then((res) => {
const obj = { const obj = {
base64, aid: res.aid || "",
...res, url: res.url || "",
}; };
if (editCommentState.value) editPicture.value = obj; target.push(obj);
if (editCommentState.value) editPicture.value = target;
else { else {
if (i != undefined) commentList.value[index].child[i]["picture"] = obj; if (i != undefined) commentList.value[index].child[i]["picture"] = target;
else if (index != undefined) commentList.value[index]["picture"] = obj; else if (index != undefined) commentList.value[index]["picture"] = target;
else picture.value = obj; else picture.value = target;
} }
ElMessage.success("上传成功"); ElMessage.success("上传成功");
}); });
@@ -880,12 +922,22 @@ const handleFileUpload = (event, index, i) => {
}; };
// 删除上传的图片 // 删除上传的图片
const closeFileUpload = (index, i) => { const closeFileUpload = (aid, index, i) => {
if (i != undefined) commentList.value[index].child[i]["picture"] = {}; let target = [];
else if (index != undefined) commentList.value[index]["picture"] = {};
else picture.value = {}; 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;
}; };
const closePictureUpload = (index) => picture.value.splice(index, 1);
// 上传图片 获取图片url // 上传图片 获取图片url
const uploadImg = (file) => { const uploadImg = (file) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -1100,15 +1152,18 @@ defineExpose({ changeCommentVoteoption, wipeCommentVoteoption, reviewsComment, b
.automatic-reviews-popup { .automatic-reviews-popup {
border-radius: 10px !important; border-radius: 10px !important;
padding: 0 !important; padding: 0 !important;
.automatic-header { .automatic-header {
padding: 20px; padding: 20px;
border-bottom: 1px dotted #ebebeb; border-bottom: 1px dotted #ebebeb;
.automatic-title { .automatic-title {
font-weight: 650; font-weight: 650;
font-size: 18px; font-size: 18px;
color: #000000; color: #000000;
margin-bottom: 12px; margin-bottom: 12px;
} }
.automatic-have { .automatic-have {
background-color: rgba(246, 246, 246, 1); background-color: rgba(246, 246, 246, 1);
font-size: 12px; font-size: 12px;
@@ -1131,9 +1186,11 @@ defineExpose({ changeCommentVoteoption, wipeCommentVoteoption, reviewsComment, b
width: fit-content; width: fit-content;
} }
} }
.automatic-bottom { .automatic-bottom {
justify-content: flex-end; justify-content: flex-end;
padding: 0 10px 10px; padding: 0 10px 10px;
.automatic-send { .automatic-send {
background-color: var(--main-color); background-color: var(--main-color);
color: #fff; color: #fff;
@@ -1148,15 +1205,18 @@ defineExpose({ changeCommentVoteoption, wipeCommentVoteoption, reviewsComment, b
.emoji-popover { .emoji-popover {
box-sizing: border-box; box-sizing: border-box;
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
padding: 0px !important; padding: 0px !important;
border-radius: 10px !important; border-radius: 10px !important;
border: 1px solid #ebebeb !important; border: 1px solid #ebebeb !important;
.el-popper__arrow { .el-popper__arrow {
z-index: 1; z-index: 1;
&:before { &:before {
background-color: #fff; background-color: #fff;
border-top-color: #fff !important; border-top-color: #fff !important;

View File

@@ -37,5 +37,6 @@ onUnmounted(() => {
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: 120px; width: 120px;
height: 120px; height: 120px;
z-index: 10;
} }
</style> </style>

View File

@@ -11,22 +11,26 @@ export const detailsHttp = (query) => {
// 详情数据 - 获取评论数据 // 详情数据 - 获取评论数据
export const commentListHttp = (params) => { export const commentListHttp = (params) => {
return Http.post("/api/comment/lists", params); // return Http.post("/api/comment/lists", params);
return Http.get("https://api.gter.net/v2/api/forum/getCommentList", params);
}; };
// 评论相关 - 评论点赞 // 评论相关 - 评论点赞
export const detailsLikeCommentHttp = (query) => { export const detailsLikeCommentHttp = (query) => {
return Http.post("/api/comment/like", query); // return Http.post("/api/comment/like", query);
return Http.post("https://api.gter.net/v2/api/forum/likeComment", query);
}; };
// 详情数据 - 获取子评论数据 // 详情数据 - 获取子评论数据
export const detailsChildCommentListHttp = (query) => { export const detailsChildCommentListHttp = (query) => {
return Http.post("/api/comment/childrenList", query); // return Http.post("/api/comment/childrenList", query);
return Http.post("https://api.gter.net/v2/api/forum/childrenList", query);
}; };
// 详情数据 - 提交评论 // 详情数据 - 提交评论
export const detailsSubmitommentListHttp = (query) => { export const detailsSubmitommentListHttp = (query) => {
return Http.post("/api/comment/submit", query); // return Http.post("/api/comment/submit", query);
return Http.postV2("https://api.gter.net/v2/api/forum/postComment", query);
}; };
// 详情数据 - 提交评论 // 详情数据 - 提交评论
@@ -56,12 +60,14 @@ export const deleteHttp = (query) => {
// 操作-点赞 // 操作-点赞
export const operateLikeHttp = (query) => { export const operateLikeHttp = (query) => {
return Http.post("/api/operate/like", query); // return Http.post("/api/operate/like", query);
return Http.post("https://api.gter.net/v2/api/forum/postTopicLike", query);
}; };
// 数据操作 - 收藏 // 数据操作 - 收藏
export const operateCollectHttp = (query) => { export const operateCollectHttp = (query) => {
return Http.post("/api/operate/collect", query); // return Http.post("/api/operate/collect", query);
return Http.post("https://api.gter.net/v2/api/forum/postTopicCollect", query);
}; };
// 数据操作 - 投票操作 // 数据操作 - 投票操作
@@ -101,7 +107,8 @@ export const MyUserCollectHttp = (query) => {
// 评论相关 - 举报 Comment related // 评论相关 - 举报 Comment related
export const commentReportHttp = (query) => { export const commentReportHttp = (query) => {
return Http.post("/api/comment/report", query); // return Http.post("/api/comment/report", query);
return Http.postV2("https://api.gter.net/v2/api/forum/postTopicReport", query);
}; };
// 回应相关 - 回应列表 // 回应相关 - 回应列表
@@ -130,3 +137,28 @@ export const commonUploadConfigHttp = (query) => {
export const commentDeleteHttp = (query) => { export const commentDeleteHttp = (query) => {
return Http.post("/api/comment/commentDelete", query); return Http.post("/api/comment/commentDelete", query);
}; };
// 详情数据 - 投票详情
export const topicDetailHttp = (query) => {
return Http.get("https://api.gter.net/v2/api/forum/getTopicDetails", query);
};
export const topicRecommendHttp = (query) => {
return Http.post("https://api.gter.net/v2/api/forum/setTopicRecommend", query);
};
export const topicEssenceHttp = (query) => {
return Http.post("https://api.gter.net/v2/api/forum/setTopicBest", query);
};
export const topicDeleteHttp = (query) => {
return Http.del("https://api.gter.net/v2/api/forum/deleteTopic", query);
};
export const topicHideHttp = (query) => {
return Http.post("https://api.gter.net/v2/api/forum/setTopicHide", query);
};
export const topicgetOperationHttp = (query) => {
return Http.post("https://api.gter.net/v2/api/forum/getTopicOperation", query);
};

View File

@@ -1,115 +1,256 @@
// 处理时间 // 处理时间
export const handleDate = (dateTimeStamp = new Date()) => { export const handleDate = (dateTimeStamp = new Date()) => {
dateTimeStamp = dateTimeStamp ? dateTimeStamp : null dateTimeStamp = dateTimeStamp ? dateTimeStamp : null;
if (!dateTimeStamp) return '刚刚' if (!dateTimeStamp) return "刚刚";
var timestamp = new Date(dateTimeStamp) var timestamp = new Date(dateTimeStamp);
timestamp = timestamp.getTime() timestamp = timestamp.getTime();
var minute = 1000 * 60 var minute = 1000 * 60;
var hour = minute * 60 var hour = minute * 60;
var day = hour * 24 var day = hour * 24;
var now = new Date().getTime() var now = new Date().getTime();
var diffValue = now - timestamp var diffValue = now - timestamp;
var result var result;
if (diffValue < 0) return if (diffValue < 0) return;
var dayC = diffValue / day var dayC = diffValue / day;
var hourC = diffValue / (hour + 1) var hourC = diffValue / (hour + 1);
var minC = diffValue / minute var minC = diffValue / minute;
if (dayC >= 7) { if (dayC >= 7) {
let date = new Date(timestamp) let date = new Date(timestamp);
let Y = date.getFullYear() + "-" let Y = date.getFullYear() + "-";
let M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-" let M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
let D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " " let D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
// let h = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":" // let h = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":"
// let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes() // let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()
result = "" + Y + M + D result = "" + Y + M + D;
} else if (dayC >= 1) result = "" + Math.round(dayC) + "天前" } else if (dayC >= 1) result = "" + Math.round(dayC) + "天前";
else if (hourC >= 1) result = "" + Math.round(hourC) + "小时前" else if (hourC >= 1) result = "" + Math.round(hourC) + "小时前";
else if (minC >= 1) result = "" + Math.round(minC) + "分钟前" else if (minC >= 1) result = "" + Math.round(minC) + "分钟前";
else result = "刚刚" else result = "刚刚";
return result return result;
} };
// 处理 截止时间 // 处理 截止时间
export const handleDeadline = (dateTimeStamp = new Date()) => { export const handleDeadline = (dateTimeStamp = new Date()) => {
if (typeof dateTimeStamp == "number") dateTimeStamp = dateTimeStamp ? dateTimeStamp * 1000 : null if (typeof dateTimeStamp == "number") dateTimeStamp = dateTimeStamp ? dateTimeStamp * 1000 : null;
if (typeof dateTimeStamp == "string" && dateTimeStamp.match(/^\d{4}-\d{2}-\d{2}$/)) dateTimeStamp += " 23:59:59"; if (typeof dateTimeStamp == "string" && dateTimeStamp.match(/^\d{4}-\d{2}-\d{2}$/)) dateTimeStamp += " 23:59:59";
var timestamp = new Date(dateTimeStamp);
timestamp = timestamp.getTime();
var minute = 1000 * 60;
var hour = minute * 60;
var day = hour * 24;
var now = new Date().getTime();
var diffValue = timestamp - now;
var result;
if (diffValue < 0) return "投票已";
var timestamp = new Date(dateTimeStamp) var dayC = diffValue / day;
timestamp = timestamp.getTime() var hourC = diffValue / (hour + 1);
var minute = 1000 * 60 var minC = diffValue / minute;
var hour = minute * 60 if (dayC >= 1) result = "" + Math.round(dayC) + "天后";
var day = hour * 24 else if (hourC >= 1) result = "" + Math.round(hourC) + "小时后";
var now = new Date().getTime() else if (minC >= 1) result = "" + Math.round(minC) + "分钟后";
var diffValue = timestamp - now
var result
if (diffValue < 0) return "投票已"
var dayC = diffValue / day return result;
var hourC = diffValue / (hour + 1) };
var minC = diffValue / minute
if (dayC >= 1) result = "" + Math.round(dayC) + "天后"
else if (hourC >= 1) result = "" + Math.round(hourC) + "小时后"
else if (minC >= 1) result = "" + Math.round(minC) + "分钟后"
return result
}
export const timestampToDate = (timestamp) => { export const timestampToDate = (timestamp) => {
var date = new Date(timestamp); var date = new Date(timestamp);
var year = date.getFullYear(); var year = date.getFullYear();
var month = ("0" + (date.getMonth() + 1)).slice(-2); // Months are zero based. Add leading 0. var month = ("0" + (date.getMonth() + 1)).slice(-2); // Months are zero based. Add leading 0.
var day = ("0" + date.getDate()).slice(-2); // Add leading 0. var day = ("0" + date.getDate()).slice(-2); // Add leading 0.
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
} };
// isblank 是否需要 新标签页 默认是新标签页 // isblank 是否需要 新标签页 默认是新标签页
export const goToURL = (url, isblank = true) => { export const goToURL = (url, isblank = true) => {
if (typeof document !== "object") return if (typeof document !== "object") return;
let aTab = document.createElement('a') let aTab = document.createElement("a");
document.body.appendChild(aTab) document.body.appendChild(aTab);
aTab.setAttribute('href', url) aTab.setAttribute("href", url);
if (isblank) aTab.setAttribute('target', "_blank") if (isblank) aTab.setAttribute("target", "_blank");
aTab.click() aTab.click();
} };
export const colourValue = [{ export const colourValue = [
main: "rgba(44, 186, 230, 1)", {
bg: "rgba(234, 245, 248, 1)", main: "rgba(44, 186, 230, 1)",
bc: "rgba(213, 235, 242, 1)", bg: "rgba(234, 245, 248, 1)",
}, { bc: "rgba(213, 235, 242, 1)",
main: "rgba(49, 215, 46, 1)", },
bg: "rgba(244, 247, 244, 1)", {
bc: "rgba(225, 244, 225, 1)", main: "rgba(49, 215, 46, 1)",
}, { bg: "rgba(244, 247, 244, 1)",
main: "rgba(106, 117, 217, 1)", bc: "rgba(225, 244, 225, 1)",
bg: "rgba(237, 238, 247, 1)", },
bc: "rgba(227, 228, 246, 1)", {
}, { main: "rgba(106, 117, 217, 1)",
main: "rgba(172, 183, 46, 1)", bg: "rgba(237, 238, 247, 1)",
bg: "rgba(245, 246, 228, 1)", bc: "rgba(227, 228, 246, 1)",
bc: "rgba(238, 238, 215, 1)", },
}, { {
main: "rgba(38, 223, 190, 1)", main: "rgba(172, 183, 46, 1)",
bg: "rgba(237, 247, 245, 1)", bg: "rgba(245, 246, 228, 1)",
bc: "rgba(220, 244, 239, 1)", bc: "rgba(238, 238, 215, 1)",
}, { },
main: "rgba(242, 122, 71, 1)", {
bg: "rgba(255, 244, 239, 1)", main: "rgba(38, 223, 190, 1)",
bc: "rgba(249, 231, 224, 1)", bg: "rgba(237, 247, 245, 1)",
}] bc: "rgba(220, 244, 239, 1)",
},
{
main: "rgba(242, 122, 71, 1)",
bg: "rgba(255, 244, 239, 1)",
bc: "rgba(249, 231, 224, 1)",
},
];
export const base62ToDecimal = base62 => { export const base62ToDecimal = (base62) => {
const base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" const base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
let decimal = 0 let decimal = 0;
for (let i = 0; i < base62.length; i++) { for (let i = 0; i < base62.length; i++) {
decimal += base.indexOf(base62[i]) * Math.pow(62, base62.length - i - 1) decimal += base.indexOf(base62[i]) * Math.pow(62, base62.length - i - 1);
} }
return decimal return decimal;
} };
export const managerHide = (token, state, type = "offer") => {
return new Promise((resolve, reject) => {
const obj = {
offer: "Offer",
offer_summary: "总结",
interviewexperience: "面经",
thread: "帖子",
question: "帖子",
vote: "投票",
};
const isConfirmed = confirm(`确定要${state == 0 ? "隐藏" : "显示"}${obj[type]}吗?`);
if (isConfirmed) {
topicHideHttp({
token,
hidden: Number(state !== 1),
}).then((res) => {
const data = res.data;
creationAlertBox("success", res.message || "");
resolve(data.hidden);
});
}
});
};
// 推荐
export const managerRecommend = (token, state) => {
return new Promise((resolve, reject) => {
const post = () => {
topicRecommendHttp({
token,
recommend: state == 1 ? 0 : 1,
}).then((res) => {
const data = res.data;
creationAlertBox("success", res.message || "");
resolve(data.recommend);
});
};
if (state == 1) {
const isConfirmed = confirm(`确定要取消推荐吗?`);
if (isConfirmed) post();
else resolve(state);
} else post();
});
};
// 精华
export const managerEssence = (token, state) => {
return new Promise((resolve, reject) => {
const post = () => {
topicEssenceHttp({
token,
best: state == 1 ? 0 : 1,
}).then((res) => {
const data = res.data;
creationAlertBox("success", res.message || "");
resolve(data.best);
});
};
if (state == 1) {
const isConfirmed = confirm(`确定要取消精华吗?`);
if (isConfirmed) post();
else resolve(state);
} else post();
});
};
// 删除
export const managerDelete = (token) => {
return new Promise((resolve, reject) => {
const post = () => {
topicDeleteHttp({
token,
}).then((res) => {
creationAlertBox("success", res.message || "");
resolve();
});
};
const isConfirmed = confirm(`确定要删除吗?`);
if (!isConfirmed) reject();
else post();
});
};
export const strtimeago = (dateStr, type = 1) => {
dateStr = dateStr + ""; // 反之传入的不是字符串
dateStr = dateStr.replaceAll("-", "/"); // 修改格式
var minute = 1000 * 60; // 把分,时,天,周,半个月,一个月用毫秒表示
var hour = minute * 60;
var day = hour * 24;
var now = new Date().getTime(); // 获取当前时间毫秒
let objectTime = new Date(dateStr).getTime();
var diffValue = now - objectTime; // 时间差
if (diffValue < 0) return "刚刚";
var minC = diffValue / minute; // 计算时间差的分,时,天,周,月
var hourC = diffValue / hour;
var dayC = diffValue / day;
const diffInMilliseconds = now - objectTime;
const diffInYears = diffInMilliseconds / (1000 * 60 * 60 * 24 * 365);
const diffInMonths = diffInYears * 12;
let result = "";
if (dayC >= 7) {
var datetime = new Date(dateStr);
var Nyear = datetime.getFullYear();
var Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
var Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
var Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
var Nmin = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
if (type == 4) {
if (new Date().getFullYear() !== Nyear) result = `${Nyear}${Nmonth}${Ndate}`;
else result = `${Nmonth}${Ndate}${Nhour}:${Nmin}`;
}
if (type == 1) result = Nyear + "-" + Nmonth + "-" + Ndate;
if (type == 2) {
result = `${Nmonth}${Ndate}${Nhour}:${Nmin}`;
if (new Date().getFullYear() !== Nyear) result = `${Nyear}${result}`;
}
if (type == 3) {
if (diffInYears >= 1) result = Math.floor(diffInYears) + "年前";
else if (diffInMonths >= 1) result = Math.floor(diffInMonths) + "个月前";
else result = parseInt(dayC) + "天前";
}
} else if (dayC >= 1) result = parseInt(dayC) + "天前";
else if (hourC >= 1 && hourC <= 24) result = parseInt(hourC) + "小时前";
else if (minC >= 1 && minC <= 60) result = parseInt(minC) + "分钟前";
else result = "刚刚";
return result;
};

View File

@@ -1,4 +1,5 @@
<template> <template>
<Head> <Head>
<Title>{{ `${seo["title"] || "投票"} - 寄托天下出国留学网` }}</Title> <Title>{{ `${seo["title"] || "投票"} - 寄托天下出国留学网` }}</Title>
<Meta name="keyword" :content="seo['keyword']" /> <Meta name="keyword" :content="seo['keyword']" />
@@ -7,13 +8,39 @@
<TopHead ref="topHeadRef"></TopHead> <TopHead ref="topHeadRef"></TopHead>
<div class="content flexflex" :style="{ '--main-color': colourValue[uniqidIndex]['main'], '--bg-color': colourValue[uniqidIndex]['bg'], '--bc-color': colourValue[uniqidIndex]['bc'] }"> <div class="content flexflex" :style="{ '--main-color': colourValue[uniqidIndex]['main'], '--bg-color': colourValue[uniqidIndex]['bg'], '--bc-color': colourValue[uniqidIndex]['bc'] }">
<div class="header flexflex"> <div class="header flexflex">
<div class="label flexflex" v-if="sectionn?.length || tags?.length || info.recommend == 1 || info.best == 1"> <div class="label flexflex" v-if="sectionn?.length || tags?.length || topicInfo.recommend == 1 || topicInfo.best == 1">
<img class="item icon" v-if="info.recommend == 1" src="@/assets/img/recommend-icon.png" /> <img class="item icon" v-if="topicInfo.recommend == 1" src="@/assets/img/recommend-icon.png" />
<img class="item icon" v-if="info.best == 1" src="@/assets/img/essence-icon.png" /> <img class="item icon" v-if="topicInfo.best == 1" src="@/assets/img/essence-icon.png" />
<a class="item blue" v-for="(item, index) in sectionn" :key="item" :href="'/section/' + item.uniqid" target="_blank">{{ item.name }}</a> <a class="item blue" v-for="(item, index) in sectionn" :key="item" :href="`https://f.gter.net/section/${item.uniqid}`" target="_blank">{{ item.name }}</a>
<a class="item" v-for="(item, index) in tags" :key="item" :href="'/tag/' + item" target="_blank">{{ item }}</a> <a class="item" v-for="(item, index) in tags" :key="item" :href="`https://f.gter.net/tag/${item}?type=vote`" target="_blank">{{ item }}</a>
</div>
<div class="flexacenter" style="position: relative;">
<div class="flex1">{{ info.title }}</div>
<div class="view flexacenter">
<img class="icon" src="@/assets/img/eye-icon.svg" />
<div class="text">{{ topicInfo.views }}</div>
</div>
<div class="btn flexcenter" @click.stop="cutShow">
<img class="icon" src="@/assets/img/dot-dot-dot-gray.png" />
</div>
<div v-if="show">
<div class="mask" @click.stop="cutShow"></div>
<div class="operate">
<div class="item" @click.stop="report">举报</div>
<template v-if="ismanager">
<div class="item" @click.stop="hide">{{ topicInfo.hidden == 0 ? "隐藏" : "显示" }}</div>
<div class="item" @click.stop="recommend">{{ topicInfo.recommend == 1 ? "取消" : "" }}推荐</div>
<div class="item" @click.stop="essence">{{ topicInfo.best == 1 ? "取消" : "" }}精华</div>
</template>
<template v-if="ismyself">
<div class="item" @click.stop="deleteItem">删除</div>
</template>
</div>
</div>
</div> </div>
<span>{{ info.title }}</span>
</div> </div>
<div class="left"> <div class="left">
<div class="info flexacenter"> <div class="info flexacenter">
@@ -96,8 +123,7 @@
回应 回应
<div class="respond-amount">{{ ripostecount.total || 0 }}</div> <div class="respond-amount">{{ ripostecount.total || 0 }}</div>
<div v-if="ripostecount.user > 0" class="respond-list-btn" @click="openPopList"> <div v-if="ripostecount.user > 0" class="respond-list-btn" @click="openPopList">
<span class="respond-list-btn-amount">{{ ripostecount.user }}</span <span class="respond-list-btn-amount">{{ ripostecount.user }}</span>人回应
>人回应
<img class="respond-list-btn-icon" src="@/assets/img/arrowsRight.svg" /> <img class="respond-list-btn-icon" src="@/assets/img/arrowsRight.svg" />
</div> </div>
</div> </div>
@@ -125,7 +151,7 @@
</div> </div>
</template> </template>
<DetailsComments ref="commentsRef" :token="token" @update:commentComments="commentComments = $event"></DetailsComments> <DetailsComments ref="commentsRef" :token="topicToken" @update:commentComments="commentComments = $event"></DetailsComments>
</div> </div>
<DetailsArea @closeDiscussInputFields="closeDiscussInputFields" :ripostecount="ripostecount" :commentComments="commentComments"></DetailsArea> <DetailsArea @closeDiscussInputFields="closeDiscussInputFields" :ripostecount="ripostecount" :commentComments="commentComments"></DetailsArea>
</div> </div>
@@ -147,8 +173,7 @@
</div> </div>
<template v-else> <template v-else>
<div class="respond-pop-title"> <div class="respond-pop-title">
<span class="respond-pop-amount">{{ ripostecount.user }}</span <span class="respond-pop-amount">{{ ripostecount.user }}</span>人回应
>人回应
<img class="respond-title-icon" @click="closePopList()" src="@/assets/img/cross-grey.png" /> <img class="respond-title-icon" @click="closePopList()" src="@/assets/img/cross-grey.png" />
</div> </div>
<div class="respond-list"> <div class="respond-list">
@@ -166,6 +191,9 @@
</template> </template>
</div> </div>
</div> </div>
<Report v-if="reportAlertShow" :reportToken="reportToken"></Report>
</template> </template>
<script setup> <script setup>
@@ -414,9 +442,9 @@ const getDetails = async () => {
info.value = data["info"]; info.value = data["info"];
isvote.value = data["isvote"]; isvote.value = data["isvote"];
iscollection.value = data["iscollection"]; // iscollection.value = data["iscollection"];
islike.value = data["islike"]; // islike.value = data["islike"];
ismyself.value = data["ismyself"]; // ismyself.value = data["ismyself"];
option.value = data["option"]; option.value = data["option"];
qrcode.value = data.share?.qrcode; qrcode.value = data.share?.qrcode;
token.value = data["token"]; token.value = data["token"];
@@ -429,9 +457,77 @@ const getDetails = async () => {
}); });
getRiposte(); getRiposte();
const topic = data.topic
console.log("topic", topic);
getTopicDetail(topic.uniqid);
}); });
}; };
let topicToken = ref("");
let topicInfo = ref({});
let sectionn = ref([]);
let tags = ref([]);
provide("topicInfo", topicInfo);
provide("topicToken", topicToken);
const getTopicDetail = (uniqid) => {
topicDetailHttp({ uniqid }).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message);
return;
}
let data = res.data;
topicToken.value = data.token;
console.log("topicDetail", data);
const targetInfo = data.info;
if (!targetInfo.hidden) targetInfo.hidden = 0;
const sectionNameSet = new Set(targetInfo.sectionn.map((item) => item.name));
if (targetInfo.tags) {
const newTag = targetInfo?.tags.filter((tagName) => !sectionNameSet.has(tagName));
tags.value = newTag;
}
sectionn.value = targetInfo.sectionn;
topicInfo.value = targetInfo;
// ismyself.value = data.ismyself;
if (data.islogin) getTopicOperation();
});
}
const getTopicOperation = () => {
topicgetOperationHttp({
token: topicToken.value,
actions: ["like", "collection"],
})
.then((res) => {
console.log("res", res);
const data = res.data;
const like = data.like;
const collection = data.collection;
islike.value = like.status;
iscollection.value = collection.status;
})
.catch((err) => {
console.log("err", err);
});
};
provide("getDetails", getDetails); provide("getDetails", getDetails);
// 点击发送信息 // 点击发送信息
@@ -447,10 +543,10 @@ const TAHomePage = (uin) => {
}; };
// 跳转 url // 跳转 url
const redirectToExternalWebsite = (url) => { const redirectToExternalWebsite = (url, target = "_blank") => {
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.target = "_blank"; link.target = target;
link.click(); link.click();
}; };
@@ -688,6 +784,68 @@ const selectEomjiListPop = (key) => {
}); });
}; };
let show = ref(false);
let ismanager = inject("ismanager");
const cutShow = () => {
show.value = !show.value; // 修改为切换显示状态
};
let reportAlertShow = ref(false);
let reportToken = ref("");
provide("reportAlertShow", reportAlertShow);
// 点击打开举报
const report = (token) => {
if (isNeedLogin.value) {
goLogin();
return;
}
cutShow()
reportToken.value = topicToken.value;
reportAlertShow.value = true;
};
// 隐藏
const hide = () => {
const target = topicInfo.value;
managerHide(topicToken.value, target.hidden, "vote").then((value) => {
target.hidden = value;
topicInfo.value = target;
cutShow();
});
};
// 推荐
const recommend = () => {
const target = topicInfo.value;
managerRecommend(topicToken.value, target.recommend).then((value) => {
target.recommend = value;
topicInfo.value = target;
cutShow();
});
};
// 精华
const essence = () => {
const target = topicInfo.value;
managerEssence(topicToken.value, target.best).then((value) => {
target.best = value;
topicInfo.value = target;
cutShow();
});
};
const deleteItem = () => {
managerDelete(token)
.then(() => redirectToExternalWebsite("/", "_self"))
.finally(() => cutShow());
};
const { $cache } = useNuxtApp(); const { $cache } = useNuxtApp();
try { try {
@@ -716,7 +874,7 @@ try {
}); });
} }
} }
} catch (error) {} } catch (error) { }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@@ -727,11 +885,13 @@ try {
.default-popup { .default-popup {
.el-dialog__header { .el-dialog__header {
padding: 0; padding: 0;
.el-dialog__headerbtn { .el-dialog__headerbtn {
width: 36px; width: 36px;
height: 36px; height: 36px;
} }
} }
.el-dialog__body { .el-dialog__body {
padding: 0; padding: 0;
} }

View File

@@ -11,7 +11,7 @@ axios.interceptors.request.use(
async (config) => { async (config) => {
// 开发时登录用的,可以直接替换小程序的 authorization // 开发时登录用的,可以直接替换小程序的 authorization
if (process.env.NODE_ENV !== "production") { if (process.env.NODE_ENV !== "production") {
const miucms_session = "20c7981bcd7b24e373e462ee60a8d326"; const miucms_session = "01346a38444d71aaadb3adad52b52c39";
document.cookie = "miucms_session=" + miucms_session; document.cookie = "miucms_session=" + miucms_session;
config["headers"]["authorization"] = miucms_session; config["headers"]["authorization"] = miucms_session;
} }
@@ -98,6 +98,26 @@ const postV2 = (url, params) => {
}); });
}; };
const del = (url, params) => {
return new Promise((resolve, reject) => {
//是将对象 序列化成URL的形式以&进行拼接
axios
.delete(url, params)
.then((res) => {
let data = res.data;
if (data.code == 401 && !process.server) goLogin();
resolve(data);
})
.catch((err) => {
if (err.data.code == 401) {
goLogin();
resolve(err.data);
} else reject(err.data);
});
});
};
// 打开登录 // 打开登录
const goLogin = () => { const goLogin = () => {
if (typeof ajax_login === "function") ajax_login(); if (typeof ajax_login === "function") ajax_login();
@@ -107,4 +127,5 @@ export default {
get, get,
post, post,
postV2, postV2,
del,
}; };