mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-05-11 13:17:29 +08:00
1.追加:投票结束查看倒计时时间
2.修改:倒计时样式 3.优化:抽奖和投票倒计时代码统一
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
<div class="prize-count">x {{ lottery.prizeCount }}</div>
|
<div class="prize-count">x {{ lottery.prizeCount }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="prize-end-time prize-info-right">
|
<div class="prize-end-time prize-info-right">
|
||||||
<div v-if="!isMobile" class="prize-end-time-title">离结束还有</div>
|
<div v-if="!isMobile" class="prize-end-time-title"><i class="fas fa-stopwatch"></i>距离结束还有</div>
|
||||||
<div class="prize-end-time-value">{{ countdown }}</div>
|
<div class="prize-end-time-value">{{ countdown }}</div>
|
||||||
<div v-if="!isMobile" class="join-prize-button-container-desktop">
|
<div v-if="!isMobile" class="join-prize-button-container-desktop">
|
||||||
<div
|
<div
|
||||||
@@ -84,6 +84,7 @@ import { getToken, authState } from '~/utils/auth'
|
|||||||
import { toast } from '~/main'
|
import { toast } from '~/main'
|
||||||
import { useRuntimeConfig } from '#imports'
|
import { useRuntimeConfig } from '#imports'
|
||||||
import { useIsMobile } from '~/utils/screen'
|
import { useIsMobile } from '~/utils/screen'
|
||||||
|
import { useCountdown } from '~/composables/useCountdown'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
lottery: { type: Object, required: true },
|
lottery: { type: Object, required: true },
|
||||||
@@ -95,54 +96,14 @@ const isMobile = useIsMobile()
|
|||||||
const loggedIn = computed(() => authState.loggedIn)
|
const loggedIn = computed(() => authState.loggedIn)
|
||||||
const lotteryParticipants = computed(() => props.lottery?.participants || [])
|
const lotteryParticipants = computed(() => props.lottery?.participants || [])
|
||||||
const lotteryWinners = computed(() => props.lottery?.winners || [])
|
const lotteryWinners = computed(() => props.lottery?.winners || [])
|
||||||
const lotteryEnded = computed(() => {
|
// 倒计时和结束flg
|
||||||
if (!props.lottery || !props.lottery.endTime) return false
|
const { countdown, isEnded } = useCountdown(props.lottery?.endTime)
|
||||||
return new Date(props.lottery.endTime).getTime() <= Date.now()
|
const lotteryEnded = computed(() => isEnded.value)
|
||||||
})
|
|
||||||
const hasJoined = computed(() => {
|
const hasJoined = computed(() => {
|
||||||
if (!loggedIn.value) return false
|
if (!loggedIn.value) return false
|
||||||
return lotteryParticipants.value.some((p) => p.id === Number(authState.userId))
|
return lotteryParticipants.value.some((p) => p.id === Number(authState.userId))
|
||||||
})
|
})
|
||||||
|
|
||||||
const countdown = ref('00:00:00')
|
|
||||||
let timer = null
|
|
||||||
const updateCountdown = () => {
|
|
||||||
if (!props.lottery || !props.lottery.endTime) {
|
|
||||||
countdown.value = '00:00:00'
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const diff = new Date(props.lottery.endTime).getTime() - Date.now()
|
|
||||||
if (diff <= 0) {
|
|
||||||
countdown.value = '00:00:00'
|
|
||||||
if (timer) {
|
|
||||||
clearInterval(timer)
|
|
||||||
timer = null
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const h = String(Math.floor(diff / 3600000)).padStart(2, '0')
|
|
||||||
const m = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0')
|
|
||||||
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
|
||||||
countdown.value = `${h}:${m}:${s}`
|
|
||||||
}
|
|
||||||
const startCountdown = () => {
|
|
||||||
updateCountdown()
|
|
||||||
if (timer) clearInterval(timer)
|
|
||||||
timer = setInterval(updateCountdown, 1000)
|
|
||||||
}
|
|
||||||
watch(
|
|
||||||
() => props.lottery?.endTime,
|
|
||||||
() => {
|
|
||||||
if (props.lottery && props.lottery.endTime) startCountdown()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
onMounted(() => {
|
|
||||||
if (props.lottery && props.lottery.endTime) startCountdown()
|
|
||||||
})
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (timer) clearInterval(timer)
|
|
||||||
})
|
|
||||||
|
|
||||||
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<div class="poll-option-title" v-else>单选</div>
|
<div class="poll-option-title" v-else>单选</div>
|
||||||
|
|
||||||
<div class="poll-left-time">
|
<div class="poll-left-time">
|
||||||
<div class="poll-left-time-title">离结束还有</div>
|
<div class="poll-left-time-title"><i class="fas fa-stopwatch"></i>距离结束还有</div>
|
||||||
<div class="poll-left-time-value">{{ countdown }}</div>
|
<div class="poll-left-time-value">{{ countdown }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -107,7 +107,11 @@
|
|||||||
<i class="fas fa-stopwatch"></i> 投票已结束
|
<i class="fas fa-stopwatch"></i> 投票已结束
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="poll-option-hint">
|
<div v-else class="poll-option-hint">
|
||||||
<i class="fas fa-stopwatch"></i> 您已投票,等待结束查看结果
|
<div>您已投票,等待结束查看结果</div>
|
||||||
|
<div class="poll-left-time">
|
||||||
|
<div class="poll-left-time-title"><i class="fas fa-stopwatch"></i>距离结束还有</div>
|
||||||
|
<div class="poll-left-time-value">{{ countdown }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,6 +122,7 @@ import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
|
|||||||
import { getToken, authState } from '~/utils/auth'
|
import { getToken, authState } from '~/utils/auth'
|
||||||
import { toast } from '~/main'
|
import { toast } from '~/main'
|
||||||
import { useRuntimeConfig } from '#imports'
|
import { useRuntimeConfig } from '#imports'
|
||||||
|
import { useCountdown } from '~/composables/useCountdown'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
poll: { type: Object, required: true },
|
poll: { type: Object, required: true },
|
||||||
@@ -140,10 +145,9 @@ const pollPercentages = computed(() =>
|
|||||||
})
|
})
|
||||||
: [],
|
: [],
|
||||||
)
|
)
|
||||||
const pollEnded = computed(() => {
|
// 倒计时
|
||||||
if (!props.poll || !props.poll.endTime) return false
|
const { countdown, isEnded } = useCountdown(props.poll?.endTime)
|
||||||
return new Date(props.poll.endTime).getTime() <= Date.now()
|
const pollEnded = computed(() => isEnded.value)
|
||||||
})
|
|
||||||
const hasVoted = computed(() => {
|
const hasVoted = computed(() => {
|
||||||
if (!loggedIn.value) return false
|
if (!loggedIn.value) return false
|
||||||
return pollParticipants.value.some((p) => p.id === Number(authState.userId))
|
return pollParticipants.value.some((p) => p.id === Number(authState.userId))
|
||||||
@@ -152,45 +156,6 @@ watch([hasVoted, pollEnded], ([voted, ended]) => {
|
|||||||
if (voted || ended) showPollResult.value = true
|
if (voted || ended) showPollResult.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
const countdown = ref('00:00:00')
|
|
||||||
let timer = null
|
|
||||||
const updateCountdown = () => {
|
|
||||||
if (!props.poll || !props.poll.endTime) {
|
|
||||||
countdown.value = '00:00:00'
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const diff = new Date(props.poll.endTime).getTime() - Date.now()
|
|
||||||
if (diff <= 0) {
|
|
||||||
countdown.value = '00:00:00'
|
|
||||||
if (timer) {
|
|
||||||
clearInterval(timer)
|
|
||||||
timer = null
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const h = String(Math.floor(diff / 3600000)).padStart(2, '0')
|
|
||||||
const m = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0')
|
|
||||||
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
|
||||||
countdown.value = `${h}:${m}:${s}`
|
|
||||||
}
|
|
||||||
const startCountdown = () => {
|
|
||||||
updateCountdown()
|
|
||||||
if (timer) clearInterval(timer)
|
|
||||||
timer = setInterval(updateCountdown, 1000)
|
|
||||||
}
|
|
||||||
watch(
|
|
||||||
() => props.poll?.endTime,
|
|
||||||
() => {
|
|
||||||
if (props.poll && props.poll.endTime) startCountdown()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
onMounted(() => {
|
|
||||||
if (props.poll && props.poll.endTime) startCountdown()
|
|
||||||
})
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (timer) clearInterval(timer)
|
|
||||||
})
|
|
||||||
|
|
||||||
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
|
|||||||
51
frontend_nuxt/composables/useCountdown.ts
Normal file
51
frontend_nuxt/composables/useCountdown.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用倒计时 composable
|
||||||
|
* @param endTime 截止时间字符串或 Date 对象
|
||||||
|
* @returns { countdown, isEnded }
|
||||||
|
*/
|
||||||
|
export function useCountdown(endTime?: string | Date) {
|
||||||
|
const countdown = ref('')
|
||||||
|
const isEnded = ref(false)
|
||||||
|
let timer: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
if (!endTime) {
|
||||||
|
countdown.value = ''
|
||||||
|
isEnded.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const diff = new Date(endTime).getTime() - Date.now()
|
||||||
|
if (diff <= 0) {
|
||||||
|
countdown.value = '已结束'
|
||||||
|
isEnded.value = true
|
||||||
|
if (timer) clearInterval(timer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 计算天、时、分、秒
|
||||||
|
const days = Math.floor(diff / (24 * 3600 * 1000))
|
||||||
|
const hours = Math.floor((diff % (24 * 3600 * 1000)) / 3600000)
|
||||||
|
const minutes = Math.floor((diff % 3600000) / 60000)
|
||||||
|
const seconds = Math.floor((diff % 60000) / 1000)
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
countdown.value = `${days}天 ${hours}小时 ${minutes}分 ${seconds}秒`
|
||||||
|
} else if (hours > 0) {
|
||||||
|
countdown.value = `${hours}小时 ${minutes}分 ${seconds}秒`
|
||||||
|
} else {
|
||||||
|
countdown.value = `${minutes}分 ${seconds}秒`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
update()
|
||||||
|
timer = setInterval(update, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (timer) clearInterval(timer)
|
||||||
|
})
|
||||||
|
|
||||||
|
return { countdown, isEnded }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user