<template> <Head> <Title>投票 - 寄托天下出国留学网</Title> </Head> <TopHead></TopHead> <div class="search-info flexacenter" v-if="keyword"> <div class="flexacenter" @click="closeKeyword"> {{ keyword }} <img class="round-fork-fork" src="@/assets/img/round-fork-fork.png" /> </div> <div class="halving-line"></div> <div class="search-result">共 {{ count }} 条搜索数据</div> </div> <div class="vote-list-box" :class="{ 'firstdata': firstdataState }" ref="gridContainer" v-loading="loading"> <a class="vote-item" target="_blank" :href="`/details/${item['uniqid']}?colorI=${index % 6}`" v-for="(item, index) in list" :key="index" :class="{ 'isvote': item['isvote'] == 1 || item['status'] == 0 }" :style="{ '--main-color': colourValue[index % 6]['main'], '--bg-color': colourValue[index % 6]['bg'], '--bc-color': colourValue[index % 6]['bc'] }"> <div class="vote-title"> <div class="vote-state" v-if="item['status'] == 1">进行中</div> <div class="vote-state finish" v-else>已结束</div> {{ item["title"] }} </div> <div class="vote-explain">{{ item["message"] }}</div> <div class="vote-option-list flexflex"> <div class="vote-option-item flexflex" :class="{ 'pitch': item.selected == 1 }" v-for="(item, index) in item?.option" :key="index"> <div class="flexflex" style="padding: 2px 0;"> <div class="vote-option-number flexcenter">{{ index + 1 }}</div> <img class="tick-icon" src="@/assets/img/tick-black.svg" /> <div class="vote-option-content flex1">{{ item["value"] }}</div> </div> <div class="vote-option-progress flexacenter"> <div class="vote-option-progress-step" :style="{ width: item['percentage'] + '%' }"></div> <div class="vote-option-progress-value">{{ item["count"] }}</div> </div> </div> </div> <div class="vote-data flexacenter"> <div class="vote-data-left flexacenter"> {{ item.votes }}人参与 <template v-if="item['deadline']">| {{ handleDeadline(item["deadline"]) }}结束</template> </div> <div class="vote-data-right flexacenter"> <div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/eye-icon.svg" /> {{ item.views }}</div> <div class="vote-data-item flexacenter" @click.stop.prevent="handleLike(item['token'], index)"> <img v-if="item['islike'] == 0" class="vote-data-icon" src="@/assets/img/like-icon-gray.png" /> <img v-else class="vote-data-icon" src="@/assets/img/like-yes.png" /> {{ item["likes"] }} <!-- <img class="vote-data-icon" src="@/assets/img/expression-icon.png" /> {{ item["ripostes"] }} --> </div> <div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/comment-icon.svg" /> {{ item["comments"] }}</div> </div> </div> </a> <div class="empty-box flexcenter" v-if="keyword && list.length == 0 && !loading"><Empty :isNeedIssue="true"></Empty></div> </div> </template> <script setup> useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=vote" }, { src: "https://app.gter.net/bottom?tpl=footer,popupnotification", body: true }] }) let isNeedLogin = inject("isNeedLogin") const goLogin = inject("goLogin") import { useRoute } from "vue-router" const route = useRoute() const router = useRouter() let keyword = ref("") let page = ref(1) // 投票页数从 1 开始 let count = ref(0) let list = ref([]) let loading = ref(false) // 加载中 const firstdataState = ref(true) keyword.value = route.query["keyword"] const gridContainer = ref(null) let masonryInstance = null onMounted(async () => { let Masonry = await import("masonry-layout") masonryInstance = new Masonry.default(gridContainer.value, { itemSelector: ".vote-item", gutter: 22.5, }) getList() window.addEventListener("scroll", handleScroll) }) const getList = () => { if (page.value == 0 || loading.value) return loading.value = true getListHttp({ page: page.value, keyword: keyword.value, limit: 20 }) .then(res => { if (res.code != 200) { page.value = 0 ElMessage.error(res.message) return } let data = res.data list.value = list.value.concat(data.data) count.value = data.count if (data.count > list.value.length) page.value++ else page.value = 0 firstdataState.value = false // data.data.forEach((element, index) => { // // let uniqidEnd = element["uniqid"].charAt(element["uniqid"].length - 1) // // element["uniqidIndex"] = base62ToDecimal(uniqidEnd) % 6 // element["uniqidIndex"] = index % 6 // }) nextTick(() => { masonryInstance.reloadItems() masonryInstance.layout() }) }) .finally(() => (loading.value = false)) } const handleScroll = () => { const scrollTop = document.documentElement.scrollTop || document.body.scrollTop const scrollHeight = document.documentElement.scrollHeight const clientHeight = document.documentElement.clientHeight // 列表下 滑动到底部 获取新数据 if (scrollTop + clientHeight >= scrollHeight - 40) getList() } // 处理点赞 const handleLike = (token, index) => { if (isNeedLogin.value) { goLogin() return } operateLikeHttp({ token }).then(res => { if (res.code != 200) { ElMessage.error(res.message) return } let data = res.data list.value[index].likes = data["count"] list.value[index].islike = data["status"] ElMessage.success(res.message) }) } // 使用 process.client 判断是否在浏览器环境下 const isServer = computed(() => { return process.server // 使用 process.client 判断是否在浏览器环境下 }) // 点击关闭搜索 const closeKeyword = () => router.push("./index.html") watch( () => route.query, () => { keyword.value = route.query["keyword"] page.value = 1 list.value = [] count.value = 0 getList() } ) try { if (process.server) { await getListHttp({ page: 1, keyword: keyword.value }).then(res => { let data = res.data // data.data.forEach((element, index) => { // let uniqidEnd = element["uniqid"].charAt(element["uniqid"].length - 1) // element["uniqidIndex"] = base62ToDecimal(uniqidEnd) % 6 // element["uniqidIndex"] = index % 6 // }) list.value = list.value.concat(data.data) count.value = data.count }) } } catch (error) {} </script> <style lang="less" scoped> .vote-item { --main-color: rgba(44, 186, 230, 1); --bg-color: rgba(234, 245, 248, 1); --bc-color: rgba(213, 235, 242, 1); } .search-info { font-size: 14px; color: #72db86; width: 1200px; margin: 0 auto 31px; .round-fork-fork { width: 14px; height: 14px; margin-left: 8px; cursor: pointer; } .halving-line { width: 1px; height: 13px; background-color: #d7d7d7; margin: 0 20px; } .search-result { font-size: 13px; color: #7f7f7f; } } .vote-list-box { width: 1200px; margin: 0 auto; display: flex; flex-wrap: wrap; min-height: 100vh; &.firstdata { .vote-item { margin-right: 22.5px; &:nth-of-type(3n) { margin-right: 0; } } } .vote-item { width: 385px; background-color: rgba(255, 255, 255, 1); border-radius: 16px; padding: 25px 22px 24px; margin-bottom: 20px; cursor: pointer; &:hover { -moz-box-shadow: 0px 0px 5px 2px rgba(216, 216, 216, 0.48); -webkit-box-shadow: 0px 0px 5px 2px rgba(216, 216, 216, 0.48); box-shadow: 0px 0px 5px 2px rgba(216, 216, 216, 0.48); } &.isvote { .vote-option-list { .vote-option-item { .vote-option-progress { display: flex; } } } } .vote-title { .vote-state { background-color: var(--main-color); border-radius: 25px; font-size: 12px; margin-right: 6px; height: 20px; color: #ffffff; padding: 0 6px; display: inline-flex; justify-content: center; align-items: center; &.finish { color: #ffffff; background: #000; } } font-weight: 650; font-style: normal; font-size: 16px; color: #000000; line-height: 26px; margin-bottom: 10px; word-break: break-all; } .vote-explain { color: #555555; line-height: 22px; font-size: 13px; word-break: break-word; margin-bottom: 14px; } .vote-option-list { width: 340px; background-color: var(--bg-color); border: 1px solid var(--bc-color); border-radius: 13px; flex-direction: column; padding: 8px 0; margin-bottom: 16px; .vote-option-item { padding: 10px 15px; flex-direction: column; &:not(:last-of-type) { border-bottom: 1px solid var(--bc-color); } &.pitch { .vote-option-number { display: none; } .tick-icon { display: block; } .vote-option-content { color: #000; font-weight: 650; } } .vote-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 { width: 14px; height: 14px; margin-top: 3px; margin-right: 6px; display: none; } .vote-option-content { font-size: 14px; color: #333; line-height: 20px; word-break: break-word; } .vote-option-progress { height: 5px; width: 100%; justify-content: flex-end; display: none; margin-top: 5px; .vote-option-progress-step { // background-color: rgba(49, 215, 46, 0.498039215686275); background-color: var(--main-color); opacity: 0.49039; // width: 150px; height: 4px; border-radius: 66px; margin-right: 14px; } .vote-option-progress-value { font-size: 12px; color: var(--main-color); line-height: 20px; } } } } .vote-data { justify-content: space-between; font-size: 12px; color: #aaaaaa; line-height: 22px; .vote-data-item { margin-left: 16px; .vote-data-icon { width: 14px; cursor: pointer; } } } } } .empty-box { width: 1200px; height: 540px; background-color: rgba(255, 255, 255, 1); border-radius: 16px; margin: 0 auto; } </style>