diff --git a/frontend_nuxt/pages/posts/[id]/index.vue b/frontend_nuxt/pages/posts/[id]/index.vue index be2e9da9f..180a87a2d 100644 --- a/frontend_nuxt/pages/posts/[id]/index.vue +++ b/frontend_nuxt/pages/posts/[id]/index.vue @@ -77,67 +77,35 @@ -
+
- prize + prize
-
ChatGPT Plus For 1 month
-
x 12
+
{{ lottery.prizeDescription }}
+
x {{ lottery.prizeCount }}
离结束还有
-
12:00:00
- -
+
{{ countdown }}
+
参与抽奖
+
+
已参与
+
- avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - avatar - -
+ avatar +
获奖者: - avatar + avatar
@@ -258,6 +226,7 @@ export default { document.title = defaultTitle if (metaDescriptionEl) metaDescriptionEl.setAttribute('content', defaultDescription) window.removeEventListener('scroll', updateCurrentIndex) + if (countdownTimer) clearInterval(countdownTimer) }) } @@ -267,6 +236,45 @@ export default { const loggedIn = computed(() => authState.loggedIn) const isAdmin = computed(() => authState.role === 'ADMIN') const isAuthor = computed(() => authState.username === author.value.username) + const lottery = ref(null) + const countdown = ref('00:00:00') + let countdownTimer = null + const lotteryParticipants = computed(() => lottery.value?.participants || []) + const lotteryWinners = computed(() => lottery.value?.winners || []) + const lotteryEnded = computed(() => { + if (!lottery.value || !lottery.value.endTime) return false + return new Date(lottery.value.endTime).getTime() <= Date.now() + }) + const hasJoined = computed(() => { + if (!loggedIn.value) return false + return lotteryParticipants.value.some(p => p.id === Number(authState.userId)) + }) + const updateCountdown = () => { + if (!lottery.value || !lottery.value.endTime) { + countdown.value = '00:00:00' + return + } + const diff = new Date(lottery.value.endTime).getTime() - Date.now() + if (diff <= 0) { + countdown.value = '00:00:00' + if (countdownTimer) { + clearInterval(countdownTimer) + countdownTimer = 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 = () => { + if (!process.client) return + if (countdownTimer) clearInterval(countdownTimer) + updateCountdown() + countdownTimer = setInterval(updateCountdown, 1000) + } + const gotoUser = id => router.push(`/users/${id}`) const articleMenuItems = computed(() => { const items = [] if (isAuthor.value || isAdmin.value) { @@ -401,6 +409,8 @@ export default { status.value = data.status pinnedAt.value = data.pinnedAt postTime.value = TimeManager.format(data.createdAt) + lottery.value = data.lottery || null + if (lottery.value && lottery.value.endTime) startCountdown() await nextTick() } catch (e) { console.error(e) @@ -617,6 +627,24 @@ export default { } } + const joinLottery = async () => { + const token = getToken() + if (!token) { + toast.error('请先登录') + return + } + const res = await fetch(`${API_BASE_URL}/api/posts/${postId}/lottery/join`, { + method: 'POST', + headers: { Authorization: `Bearer ${token}` } + }) + if (res.ok) { + toast.success('已参与抽奖') + await fetchPost() + } else { + toast.error('操作失败') + } + } + const fetchCommentSorts = () => { return Promise.resolve([ { id: 'NEWEST', name: '最新', icon: 'fas fa-clock' }, @@ -704,10 +732,12 @@ export default { copyPostLink, subscribePost, unsubscribePost, + joinLottery, renderMarkdown, isWaitingFetchingPost, isWaitingPostingComment, gotoProfile, + gotoUser, subscribed, loggedIn, isAuthor, @@ -728,9 +758,14 @@ export default { pinnedAt, commentSort, fetchCommentSorts, - isFetchingComments - , - getMedalTitle + isFetchingComments, + getMedalTitle, + lottery, + countdown, + lotteryParticipants, + lotteryWinners, + lotteryEnded, + hasJoined } } }