398 lines
12 KiB
Vue
398 lines
12 KiB
Vue
<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-no.svg" />
|
|
<img v-else class="vote-data-icon" src="@/assets/img/like-yes.png" /> {{ item["likes"] }}
|
|
</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", 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: 13px;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.empty-box {
|
|
width: 1200px;
|
|
height: 540px;
|
|
background-color: rgba(255, 255, 255, 1);
|
|
border-radius: 16px;
|
|
margin: 0 auto;
|
|
}
|
|
</style>
|