Files
PC-vote/components/DetailsArea.vue
DESKTOP-RQ919RC\Pc 68000d7e43 feat(Details): 新增投票详情页管理功能和评论优化
- 添加投票详情页的管理功能,包括隐藏、推荐、精华和删除操作
- 优化评论组件,支持多图上传和显示
- 新增投币功能组件
- 更新API接口调用方式,适配新后端接口
- 完善用户权限管理逻辑
- 修复样式问题和交互体验
2025-11-11 19:05:46 +08:00

588 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div class="floor-area flexacenter" :class="{ show: isLoaded }" @click="closeDiscussInputFields()">
<div class="floor-content flexacenter">
<div class="floor-right flexacenter" @mouseenter="handleFloorRight(true)" @mouseleave="handleFloorRight(false)">
手机查看该投票
<img class="arrows-icon" src="@/assets/img/arrows-icon.png" />
<el-popover placement="bottom" width="160px" trigger="hover" v-model:visible="floorRightState" popper-style="padding: 24px;border-radius: 18px;">
<template #reference>
<div class="QR-code-ball flexcenter">
<img class="" src="@/assets/img/QR-code-icon.svg" />
</div>
</template>
<img class="examine-code" :src="qrcode" />
</el-popover>
</div>
<div class="floor-left flexacenter">
<div class="item flexacenter" @click="handleLike">
<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" />
<div>{{ topicInfo["likes"] || "赞" }}</div>
</div>
<div class="item flexacenter" @click="handleCollect()">
<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" />
<div>{{ topicInfo["collections"] || "收藏" }}</div>
</div>
<div class="item flexacenter" style="cursor: auto">
<img class="icon" src="@/assets/img/discuss-icon.png" />
<div>{{ commentTotalCount || "讨论" }}</div>
</div>
<div class="item flexacenter" style="cursor: auto" @click="openBi()">
<img class="icon" src="@/assets/img/bi-black-icon.png" />
<div>{{ topicInfo.coins || "投币" }}</div>
</div>
<ClientOnly>
<el-popover placement="bottom" width="628px" trigger="click" popper-style="padding: 0;border-radius: 10px;" v-model:visible="transmitBoxState">
<template #reference>
<div class="item flexacenter" @click="handleShare">
<img class="icon" src="@/assets/img/transmit-icon.png" />转发
</div>
</template>
<div class="transmit-box flexflex">
<img class="cross-icon" @click.stop="transmitBoxState = false" src="@/assets/img/cross-icon.png" />
<div class="transmit-left transmit-web">
<div class="transmit-title">转发网页版</div>
<div class="transmit-content">
<div class="transmit-headline">{{ info["title"] }}</div>
<div class="transmit-url">{{ getFullUrl() }}</div>
</div>
<div class="transmit-web-btn flexcenter" @click="copyText(`${info['title']} + ${getFullUrl()}`)">
复制链接
</div>
</div>
<div class="transmit-right transmit-mini">
<div class="transmit-title">转发小程序版</div>
<div class="transmit-content flexcenter">
<img class="transmit-mini-img" :src="qrcode" />
<div class="flexcenter">
<img class="give-sweep" src="@/assets/img/give-sweep.png" />
扫码转发该投票
</div>
</div>
</div>
</div>
</el-popover>
</ClientOnly>
</div>
<!-- <div class="floor-middle" ref="floormiddle" @mouseover="closeMouseOver" @mouseout="openAutoCarousel" :class="{ 'floor-middle-respond': respondShowState }">
<div v-if="!respondShowState" class="flexacenter comment-box">
<img v-if="userInfoWin?.avatar" class="avatar" :src="userInfoWin?.avatar" />
<el-input class="comment-input flex1" name="14752869" v-model="floorCommentInput" placeholder="说说你的想法或疑问…" @keydown.enter="floorCommentBtn('input')" maxlength="500" show-word-limit autocomplete="off" @focus="closeMouseOver()"></el-input>
<div class="comment-btn flexcenter" @click="floorCommentBtn('input')">
<img class="comment-btn-icon" src="@/assets/img/arrow-white.svg" />
</div>
</div>
<div class="flexacenter respond">
<div class="respond-title">给个回应</div>
<div class="respond-box flex1">
<div class="respond-item" v-for="item in randomBottomEmojis" :key="item" v-html="jointriposte(item)" @click="selectEomji(item)"></div>
</div>
<RespondAdd type="bottom" :respondShowState="respondShowState" @update:respondShowState="respondShowState = $event"></RespondAdd>
</div>
</div> -->
</div>
</div>
<Like v-if="isLikeGif"></Like>
<bi-card :coins="topicInfo.coins" :token="topicToken"></bi-card>
</template>
<script setup>
import { ElMessage } from "element-plus";
let props = defineProps({
ripostecount: Object,
commentComments: Number,
});
let topicInfo = inject("topicInfo");
const respondShowState = ref(false);
let openAttest = inject("openAttest");
const realname = inject("realname");
let isNeedLogin = inject("isNeedLogin");
const goLogin = inject("goLogin");
const userInfoWin = inject("userInfoWin");
let info = inject("info");
let islike = inject("islike");
let iscollection = inject("iscollection");
let qrcode = inject("qrcode");
let token = inject("token");
let topicToken = inject("topicToken");
const topHeadRef = inject("topHeadRef");
const isLoaded = inject("isLoaded");
const floormiddle = ref(null);
// 获取完整 url
const getFullUrl = () => {
if (typeof window === "undefined") return;
return window.location.href;
};
// 复制
let copyText = (text) => {
if (navigator.clipboard) {
copyText = () => {
navigator.clipboard.writeText(text);
ElMessage.success("复制成功");
};
} else {
copyText = () => {
var tempInput = document.createElement("input");
tempInput.value = text;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand("copy");
document.body.removeChild(tempInput);
ElMessage.success("复制成功");
};
}
copyText();
};
let floorRightState = ref(false); // 右下角 的二维码显示状态
// 处理右下角 鼠标经过箭头 展示二维码
const handleFloorRight = (value) => {
floorRightState.value = value;
};
// 点击 收藏
const handleCollect = () => {
if (isNeedLogin.value) {
goLogin();
return;
}
topHeadRef.value.count = {};
operateCollectHttp({ token: topicToken.value }).then((res) => {
if (res.code != 200) {
ElMessage.error(res["message"]);
return;
}
let data = res.data;
topicInfo.value["collections"] = data["collections"];
iscollection.value = data["status"];
ElMessage.success(res["message"]);
});
};
const isBrowser = computed(() => {
return process.client; // 使用 process.client 判断是否在浏览器环境下
});
let isLikeGif = ref(false);
// 点赞
const handleLike = () => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
openAttest();
return;
}
if (isNeedLogin.value) {
goLogin();
return;
}
if (islike.value) {
ElMessage.error("不可取消点赞");
return;
}
operateLikeHttp({ token: topicToken.value }).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message);
return;
}
let data = res.data;
const status = data["status"];
topicInfo.value["likes"] = data["likes"];
islike.value = status;
ElMessage.success(res.message);
if (status) {
isLikeGif.value = true;
setTimeout(() => (isLikeGif.value = false), 2000);
}
});
};
// 底部转发弹窗显示 状态
let transmitBoxState = ref(false);
const floorCommentInput = inject("floorCommentInput");
const floorCommentBtn = inject("floorCommentBtn");
const emit = defineEmits(["closeDiscussInputFields"]);
// // 点击底部调用关闭讨论输入框
const closeDiscussInputFields = () => emit("closeDiscussInputFields");
onMounted(() => { });
watch(isLoaded, (newValue, oldValue) => {
if (newValue === true) {
openAutoCarousel();
}
});
let floormiddleIndex = 0; // 0起
let floormiddleTimer = null;
// 开启自动轮播
const openAutoCarousel = () => {
return;
floormiddleTimer = setInterval(() => {
floormiddleIndex = +!floormiddleIndex;
floormiddle.value.scrollTo({
top: floormiddleIndex * 40,
behavior: "smooth",
});
}, 2000);
};
// 鼠标移入 关闭 自动滚动
const closeMouseOver = () => {
clearInterval(floormiddleTimer);
};
onBeforeUnmount(() => {
clearInterval(floormiddleTimer);
});
const randomBottomEmojis = inject("randomBottomEmojis");
const selectEomji = inject("selectEomji");
const jointriposte = inject("jointriposte");
const openBi = () => {
if (isNeedLogin.value) {
goLogin();
return;
}
BiComponent.initComponent();
}
</script>
<style scoped lang="less">
.floor-area {
position: fixed;
left: 0;
bottom: 0;
// bottom: 50%;
width: 100vw;
min-width: 1200px;
height: 70px;
z-index: 11;
background: -webkit-linear-gradient(270deg, rgba(255, 255, 255, 1) 0%, rgba(242, 242, 242, 1) 100%);
background: -moz-linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(242, 242, 242, 1) 100%);
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(242, 242, 242, 1) 100%);
-moz-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);
display: none;
&.show {
display: flex;
animation: animafloor 1s forwards;
animation-timing-function: cubic-bezier(0.98, -0.2, 0.55, 0.97);
/* 先快后慢的时间曲线 */
animation-fill-mode: both;
}
.floor-content {
width: 1200px;
height: 100%;
margin: 0 auto;
padding: 0 30px;
display: flex;
justify-content: space-between;
.floor-left {
margin-left: 30px;
// flex: 1;
justify-content: space-between;
.item {
cursor: pointer;
color: #333333;
font-size: 14px;
margin-right: 50px;
.icon {
width: 16px;
margin-right: 5px;
// animation: anima 1s forwards;
animation: liftAndReset 0.3s forwards;
}
@keyframes liftAndReset {
0% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
// :nth-of-type(1) {
// animation-delay: 1s;
// }
// :nth-of-type(2) {
// animation-delay: 2s;
// }
&.operate-item {
position: relative;
display: flex;
justify-content: center;
}
}
}
.floor-right {
color: #7f7f7f;
font-size: 13px;
cursor: pointer;
.arrows-icon {
width: 12px;
height: 12px;
margin: 0 10px;
}
.QR-code-ball {
width: 40px;
height: 40px;
background-color: rgba(235, 235, 235, 1);
border-radius: 20px;
cursor: pointer;
}
}
.comment-box {
width: 471px;
height: 40px;
border-radius: 152px;
background-color: #fff;
border: 1px solid rgba(215, 215, 215, 1);
.avatar {
width: 28px;
height: 28px;
border-radius: 50%;
margin-left: 6px;
}
.comment-input {
height: 100%;
border: none;
outline: none;
padding: 0 12px;
font-size: 14px;
/deep/ .el-input__wrapper {
box-shadow: none;
padding: 0;
}
}
.comment-btn {
width: 40px;
height: 40px;
background-color: var(--main-color);
border-radius: 20px;
cursor: pointer;
.comment-btn-icon {
width: 14px;
height: 15px;
}
}
}
.respond {
padding-left: 18px;
width: 471px;
height: 40px;
background-color: rgba(255, 255, 255, 1);
border: 1px solid rgba(235, 235, 235, 1);
border-radius: 208px;
position: relative;
.respond-title {
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
color: #555555;
line-height: 20px;
}
.respond-box {
display: flex;
justify-content: space-around;
.respond-item {
font-family: "emojifont";
font-size: 18px;
line-height: 40px;
cursor: pointer;
}
}
/deep/ .respond-add {
width: 40px;
height: 40px;
border-radius: 50%;
// background-color: var(--main-color);
.respond-add-icon {
width: 16px;
height: 16px;
}
&.angle::after {
top: -17px;
bottom: auto;
transform: translateX(-50%) rotate(225deg);
}
}
}
.floor-middle {
display: flex;
flex-direction: column;
height: 40px;
overflow: hidden;
&.floor-middle-respond {
overflow: visible;
// overflow: hidden;
}
}
}
}
.transmit-box {
width: 628px;
border-radius: 10px;
justify-content: space-between;
padding: 40px 35px 42px;
// z-index: 3;
cursor: auto;
.cross-icon {
width: 22px;
height: 22px;
position: absolute;
top: 6px;
right: 6px;
cursor: pointer;
padding: 6px;
}
.transmit-title {
font-weight: 650;
font-size: 16px;
color: #000000;
line-height: 24px;
margin-bottom: 24px;
}
.transmit-content {
border: 1px solid rgba(242, 242, 242, 1);
border-radius: 16px;
}
.transmit-web {
.transmit-content {
width: 300px;
font-size: 14px;
line-height: 24px;
padding: 14px 16px;
margin-bottom: 32px;
.transmit-headline {
color: #333333;
}
.transmit-url {
color: #aaaaaa;
word-wrap: break-word;
}
}
.transmit-web-btn {
width: 120px;
height: 38px;
background-color: rgba(114, 219, 134, 1);
border-radius: 8px;
font-size: 14px;
color: #fff;
cursor: pointer;
}
}
.transmit-mini {
.transmit-content {
flex-direction: column;
padding: 22px 44px;
.transmit-mini-img {
width: 90px;
height: 90px;
margin-bottom: 21px;
}
color: #555555;
font-size: 13px;
.give-sweep {
width: 12px;
height: 12px;
margin-right: 8px;
}
}
}
}
.examine-code {
width: 113px;
height: 113px;
}
@keyframes animafloor {
0% {
transform: translate3d(-100%, 0, 0);
}
90% {
left: 20px;
}
100% {
transform: translateZ(0);
}
}
</style>