<template> <Head> <Title>{{ `${seo["title"] || "投票"} - 寄托天下出国留学网` }}</Title> <Meta name="keyword" :content="seo['keyword']" /> <Meta name="description" :content="seo['description']" /> </Head> <TopHead></TopHead> <div class="content flexflex" :style="{ '--main-color': colourValue[uniqidIndex]['main'], '--bg-color': colourValue[uniqidIndex]['bg'], '--bc-color': colourValue[uniqidIndex]['bc'] }"> <div class="header flexacenter"> <span>{{ info.title }}</span> <span class="views flexcenter"> <img class="eye-icon" src="@/assets/img/eye-icon.svg" /> {{ info.views }} </span> </div> <div class="left"> <div class="info flexacenter"> <div class="info-left flexacenter"> <el-popover placement="bottom-start" :width="140" trigger="click" popper-class="avatar-box-popper" :show-arrow="false"> <template #reference> <div class="flexcenter"> <img class="avatar" v-if="info.avatar" :src="info.avatar" /> <div class="username">{{ info.nickname }}</div> </div> </template> <div class="avatar-box flexflex" v-if="info['uin']"> <a class="avatar-item flexcenter" target="_blank" @click.prevent="sendMessage(info['uin'])"> <img class="avatar-icon" src="@/assets/img/send-messages-icon.png" /> 发送信息 </a> <a class="avatar-item flexcenter" target="_blank" @click.prevent="TAHomePage(info['uin'])"> <img class="avatar-icon" src="@/assets/img/homepage-icon.png" /> TA的主页 </a> </div> </el-popover> <div class="post-time">{{ handleDate(info.releasetime) }}发布</div> </div> <div class="info-right flexacenter" v-if="info['status'] == 1"> <div class="cut-off">{{ handleDeadline(info.deadline) }}结束</div> <div class="state">进行中</div> </div> <div class="info-right flexacenter" v-else> <div class="cut-off" v-if="info.deadline">已于{{ info.deadline }}结束</div> <div class="state over">已结束</div> </div> </div> <div class="message">{{ info.message }}</div> <div class="hint">{{ info.status == 1 && isvote == 0 ? `已有 ${info.votes || ""} 人参与,` : `共有 ${info.votes || 0} 人参与` }} {{ `${isvote == 1 ? "你已投票" : info.status == 1 ? "参与投票即可查看实时结果" : ""}` }}</div> <div class="option-list flexflex" v-if="info['status'] == 1 && isvote == 0"> <div class="option-item flexflex" v-for="(item, index) in option" :key="item.id" @click="handleVote(item.id, index)"> <div class="serial flexcenter">{{ index + 1 }}</div> <span class="flex1">{{ item.value }} </span> </div> </div> <div class="option-area" v-else> <div class="option-item flexflex" :class="{ 'pitch': item.selected }" v-for="(item, index) in option" :key="item.id" @click="handleUnvoteVote(index, item.selected)"> <div class="flexflex" style="padding: 2px 0px;"> <div class="option-number flexcenter">{{ index + 1 }}</div> <img class="tick-icon" src="@/assets/img/tick-black.svg" /> <div class="option-content flex1">{{ item.value }}</div> </div> <div class="option-progress flexacenter"> <div class="option-progress-step" :style="{ width: item.percentage + '%' }"></div> <div class="option-progress-value">{{ item.count }}</div> </div> </div> </div> </div> <div class="right"><DetailsComments :token="token"></DetailsComments></div> </div> <DetailsArea></DetailsArea> <el-dialog class="options-popup" v-model="cancelPopoverState" width="488px" align-center> <div class="options-popup-text">您要取消投票吗?</div> <div class="options-popup-btn flexflex"> <div class="options-popup-item options-no flexcenter" @click="unvoteVote">取消投票</div> <div class="options-popup-item options-yes flexcenter" @click="cancelPopoverState = false">不取消</div> </div> </el-dialog> </template> <script setup> useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=mj" }, { src: "https://app.gter.net/bottom?tpl=footer", body: true }] }) import { useRoute, useRouter } from "vue-router" import { ElMessage } from "element-plus" const route = useRoute() const router = useRouter() let isNeedLogin = inject("isNeedLogin") const goLogin = inject("goLogin") let id = route.params.id const uniqidEnd = id.charAt(id.length - 1) const uniqidIndex = base62ToDecimal(uniqidEnd) % 6 onMounted(() => { getDetails() clearBottom() }) let info = ref({}) let qrcode = ref("") // 分享二维码 let iscollection = ref(0) // 是否收藏 let islike = ref(0) // 是否点赞 let ismyself = ref(0) // 是否是作者 let detailsLoading = ref(false) // 详情加载中 let isvote = ref(0) // 是否已经投票 let option = ref([]) let token = ref("") let cancelPopoverState = ref(false) // 取消投票弹窗 provide("info", info) provide("islike", islike) provide("iscollection", iscollection) provide("token", token) provide("qrcode", qrcode) const getDetails = () => { detailsHttp({ uniqid: id }).then(res => { if (res.code != 200) { ElMessage.error(res.message) router.push("/index.html") return } let data = res.data info.value = data["info"] isvote.value = data["isvote"] iscollection.value = data["iscollection"] islike.value = data["islike"] ismyself.value = data["ismyself"] option.value = data["option"] qrcode.value = data.share?.qrcode token.value = data["token"] seo.value = data.seo }) } provide("getDetails", getDetails) // 点击发送信息 const sendMessage = uin => { redirectToExternalWebsite(`https://bbs.gter.net/home.php?mod=space&showmsg=1&uid=${uin}`) } // 点击ta的主页 const TAHomePage = uin => { redirectToExternalWebsite(`https://bbs.gter.net/home.php?mod=space&uid=${uin}`) } // 跳转 url const redirectToExternalWebsite = url => { const link = document.createElement("a") link.href = url link.target = "_blank" link.click() } provide("sendMessage", sendMessage) provide("TAHomePage", TAHomePage) // 处理点进投票 const handleVote = (token, index) => { operationCollectHttp({ token }).then(res => { if (res.code != 200) { ElMessage.error(res.message) return } let data = res.data let optionList = data["optionList"] || [] optionList[index]["selected"] = 1 option.value = optionList isvote.value = 1 info.value.votes = data["votes"] ElMessage.success(res.message) }) } let unvoteVoteIndex = null // 选项下标 // 点击 取消投票 const handleUnvoteVote = (index, selected) => { if (selected == 0) return cancelPopoverState.value = true unvoteVoteIndex = index } const unvoteVote = () => { const token = option.value[unvoteVoteIndex].id unvoteCollectHttp({ token }).then(res => { if (res.code != 200) { ElMessage.error(res.message) return } let data = res.data let optionList = data["optionList"] || [] optionList[unvoteVoteIndex]["selected"] = 0 option.value = optionList isvote.value = 0 info.value.votes = data["votes"] cancelPopoverState.value = false }) } const clearAllData = () => { info.value = {} qrcode.value = "" iscollection.value = 0 islike.value = 0 ismyself.value = 0 isvote.value = 0 option.value = [] } provide("clearAllData", clearAllData) // 取消了同页面的收藏 const unbookmarkSamePage = () => { iscollection.value = 0 info.value.favs-- } provide("unbookmarkSamePage", unbookmarkSamePage) // 删除同页面的投票需要跳转到 首页 const unbookmark = () => router.push("/index.html") provide("unbookmark", unbookmark) let seo = ref({}) // 清除底部的次数 let clearBottomCount = 0 // 清除 底部 const clearBottom = () => { const indexFooter = document.querySelector("section.index-footer") if (!indexFooter) { clearBottomCount++ setTimeout(() => clearBottom(), 200) return } if (clearBottomCount == 5) return indexFooter.style.display = "none" } </script> <style scoped lang="less"> .content { width: 1200px; // height: 500px; margin: 0 auto; border-radius: 16px; background: #fff; flex-wrap: wrap; // min-height: 100vh; --main-color: rgba(44, 186, 230, 1); --bg-color: rgba(234, 245, 248, 1); --bc-color: rgba(213, 235, 242, 1); .header { width: 100%; height: 80px; padding: 0 30px; border-bottom: 1px solid #ebebeb; font-weight: 650; font-size: 20px; color: #000000; line-height: 20px; justify-content: space-between; .views { font-size: 12px; color: #aaa; font-weight: 400; .eye-icon { margin-right: 5px; } } } .left { width: 658px; // height: 500px; padding: 30px 42px 100px 30px; border-right: 16px solid #f6f6f6; .info { font-size: 13px; justify-content: space-between; margin-bottom: 24px; .info-left { .avatar { width: 24px; height: 24px; margin-right: 10px; cursor: pointer; border-radius: 50%; } .username { color: #333; margin-right: 10px; cursor: pointer; } .post-time { line-height: 22px; color: #aaa; } } .info-right { .cut-off { color: #aaa; } .state { height: 20px; line-height: 20px; padding: 0 7px; color: #fff; background: var(--main-color); border-radius: 25px; font-size: 12px; margin-left: 10px; &.over { background: rgba(51, 51, 51, 1); } } } } .message { font-size: 14px; line-height: 24px; color: #333; margin-bottom: 30px; word-wrap: break-word; } .hint { font-size: 13px; line-height: 22px; color: #aaaaaa; margin-bottom: 16px; } .tick-icon { width: 14px; height: 14px; margin-top: 3px; margin-right: 6px; } .option-list { flex-direction: column; .option-item { width: 570px; // height: 40px; // background-color: var(--bg-color); border: 1px solid var(--bc-color); border-radius: 10px; word-break: break-all; font-size: 14px; line-height: 20px; color: #333333; padding: 9px 15px; cursor: pointer; position: relative; overflow: hidden; z-index: 1; &::after { background-color: var(--bg-color); content: ""; width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: -1; // border: 1px solid var(--bc-color); } &:hover::after { background-color: var(--main-color); opacity: 0.156862745098039; } &:not(:last-of-type) { margin-bottom: 10px; } &.pitch { .option-number { display: none; } .tick-icon { display: block; } .option-content { color: #000000; font-weight: 650; } } .serial { width: 14px; height: 14px; border-radius: 50%; background: var(--main-color); font-size: 11px; color: #ffffff; margin-top: 3px; margin-right: 6px; } } } .option-area { width: 570px; // height: 318px; background-color: var(--bg-color); border: 1px solid var(--bc-color); border-radius: 10px; padding: 8px 0; .option-item { padding: 7px 15px 10px; flex-direction: column; word-break: break-all; cursor: no-drop; &:not(:last-of-type) { border-bottom: 1px solid var(--bc-color); } &.pitch { cursor: pointer; .option-number { display: none; } .tick-icon { display: block; } .option-content { font-weight: 650; color: #000000; } } .option-number { font-size: 11px; color: #ffffff; width: 14px; height: 14px; background-color: var(--main-color); border-radius: 50%; margin-right: 6px; margin-top: 3px; } .tick-icon { display: none; } .option-content { font-size: 14px; color: #333; line-height: 20px; word-break: break-word; } .option-progress { height: 5px; width: 100%; justify-content: flex-end; // display: none; margin-top: 3px; .option-progress-step { width: 24%; background-color: var(--main-color); opacity: 0.49803922; height: 4px; border-radius: 66px; margin-right: 14px; } .option-progress-value { font-size: 12px; color: var(--main-color); line-height: 20px; } } } } } .right { flex: 1; padding-top: 22px; padding-left: 42px; } } </style> <style lang="less"> .options-popup { border-radius: 10px; .el-dialog__header { padding: 0; .el-dialog__headerbtn { width: 36px; height: 36px; } } padding: 44px 74px; .el-dialog__body { padding: 0; } .options-popup-text { font-size: 14px; color: #333333; text-align: center; margin-bottom: 71px; } .options-popup-btn { justify-content: space-between; .options-popup-item { font-size: 13px; width: 160px; height: 40px; border-radius: 150px; border: 1px solid; cursor: pointer; &.options-yes { background-color: rgba(114, 219, 134, 1); border-color: rgba(114, 219, 134, 1); color: #fff; } &.options-no { background-color: #fff; border-color: rgba(170, 170, 170, 1); color: #333; } } } } </style>