mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-08-24 03:47:16 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39c34a9048 |
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-prize-container">
|
<div class="post-prize-container" v-if="lottery">
|
||||||
<div class="prize-content">
|
<div class="prize-content">
|
||||||
<div class="prize-info">
|
<div class="prize-info">
|
||||||
<div class="prize-info-left">
|
<div class="prize-info-left">
|
||||||
@@ -79,30 +79,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onBeforeUnmount } from 'vue'
|
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { toast } from '~/main'
|
|
||||||
import { getToken, authState } from '~/utils/auth'
|
import { getToken, authState } from '~/utils/auth'
|
||||||
|
import { toast } from '~/main'
|
||||||
|
import { useRuntimeConfig } from '#imports'
|
||||||
import { useIsMobile } from '~/utils/screen'
|
import { useIsMobile } from '~/utils/screen'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
lottery: {
|
lottery: { type: Object, required: true },
|
||||||
type: Object,
|
postId: { type: [String, Number], required: true },
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
postId: {
|
|
||||||
type: [String, Number],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
|
||||||
|
|
||||||
const loggedIn = computed(() => authState.loggedIn)
|
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
|
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(() => {
|
const lotteryEnded = computed(() => {
|
||||||
@@ -115,8 +105,7 @@ const hasJoined = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const countdown = ref('00:00:00')
|
const countdown = ref('00:00:00')
|
||||||
let countdownTimer = null
|
let timer = null
|
||||||
|
|
||||||
const updateCountdown = () => {
|
const updateCountdown = () => {
|
||||||
if (!props.lottery || !props.lottery.endTime) {
|
if (!props.lottery || !props.lottery.endTime) {
|
||||||
countdown.value = '00:00:00'
|
countdown.value = '00:00:00'
|
||||||
@@ -125,9 +114,9 @@ const updateCountdown = () => {
|
|||||||
const diff = new Date(props.lottery.endTime).getTime() - Date.now()
|
const diff = new Date(props.lottery.endTime).getTime() - Date.now()
|
||||||
if (diff <= 0) {
|
if (diff <= 0) {
|
||||||
countdown.value = '00:00:00'
|
countdown.value = '00:00:00'
|
||||||
if (countdownTimer) {
|
if (timer) {
|
||||||
clearInterval(countdownTimer)
|
clearInterval(timer)
|
||||||
countdownTimer = null
|
timer = null
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,30 +125,28 @@ const updateCountdown = () => {
|
|||||||
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
||||||
countdown.value = `${h}:${m}:${s}`
|
countdown.value = `${h}:${m}:${s}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const startCountdown = () => {
|
const startCountdown = () => {
|
||||||
if (!import.meta.client) return
|
|
||||||
if (countdownTimer) clearInterval(countdownTimer)
|
|
||||||
updateCountdown()
|
updateCountdown()
|
||||||
countdownTimer = setInterval(updateCountdown, 1000)
|
if (timer) clearInterval(timer)
|
||||||
|
timer = setInterval(updateCountdown, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.lottery?.endTime,
|
() => props.lottery?.endTime,
|
||||||
() => {
|
() => {
|
||||||
if (props.lottery && props.lottery.endTime) {
|
if (props.lottery && props.lottery.endTime) startCountdown()
|
||||||
startCountdown()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
|
||||||
)
|
)
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.lottery && props.lottery.endTime) startCountdown()
|
||||||
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (countdownTimer) clearInterval(countdownTimer)
|
if (timer) clearInterval(timer)
|
||||||
})
|
})
|
||||||
|
|
||||||
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
||||||
|
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
const joinLottery = async () => {
|
const joinLottery = async () => {
|
||||||
const token = getToken()
|
const token = getToken()
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -313,4 +300,11 @@ const joinLottery = async () => {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.join-prize-button,
|
||||||
|
.join-prize-button-disabled {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-poll-container">
|
<div class="post-poll-container" v-if="poll">
|
||||||
<div class="poll-top-container">
|
<div class="poll-top-container">
|
||||||
<div class="poll-options-container">
|
<div class="poll-options-container">
|
||||||
<div v-if="showPollResult || pollEnded || hasVoted">
|
<div v-if="showPollResult || pollEnded || hasVoted">
|
||||||
@@ -70,26 +70,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onBeforeUnmount } from 'vue'
|
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { toast } from '~/main'
|
|
||||||
import { getToken, authState } from '~/utils/auth'
|
import { getToken, authState } from '~/utils/auth'
|
||||||
|
import { toast } from '~/main'
|
||||||
|
import { useRuntimeConfig } from '#imports'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
poll: {
|
poll: { type: Object, required: true },
|
||||||
type: Object,
|
postId: { type: [String, Number], required: true },
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
postId: {
|
|
||||||
type: [String, Number],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const loggedIn = computed(() => authState.loggedIn)
|
||||||
const API_BASE_URL = config.public.apiBaseUrl
|
|
||||||
|
|
||||||
const showPollResult = ref(false)
|
const showPollResult = ref(false)
|
||||||
|
|
||||||
const pollParticipants = computed(() => props.poll?.participants || [])
|
const pollParticipants = computed(() => props.poll?.participants || [])
|
||||||
@@ -109,17 +101,15 @@ const pollEnded = computed(() => {
|
|||||||
return new Date(props.poll.endTime).getTime() <= Date.now()
|
return new Date(props.poll.endTime).getTime() <= Date.now()
|
||||||
})
|
})
|
||||||
const hasVoted = computed(() => {
|
const hasVoted = computed(() => {
|
||||||
if (!authState.loggedIn) 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))
|
||||||
})
|
})
|
||||||
|
|
||||||
watch([hasVoted, pollEnded], ([voted, ended]) => {
|
watch([hasVoted, pollEnded], ([voted, ended]) => {
|
||||||
if (voted || ended) showPollResult.value = true
|
if (voted || ended) showPollResult.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
const countdown = ref('00:00:00')
|
const countdown = ref('00:00:00')
|
||||||
let countdownTimer = null
|
let timer = null
|
||||||
|
|
||||||
const updateCountdown = () => {
|
const updateCountdown = () => {
|
||||||
if (!props.poll || !props.poll.endTime) {
|
if (!props.poll || !props.poll.endTime) {
|
||||||
countdown.value = '00:00:00'
|
countdown.value = '00:00:00'
|
||||||
@@ -128,9 +118,9 @@ const updateCountdown = () => {
|
|||||||
const diff = new Date(props.poll.endTime).getTime() - Date.now()
|
const diff = new Date(props.poll.endTime).getTime() - Date.now()
|
||||||
if (diff <= 0) {
|
if (diff <= 0) {
|
||||||
countdown.value = '00:00:00'
|
countdown.value = '00:00:00'
|
||||||
if (countdownTimer) {
|
if (timer) {
|
||||||
clearInterval(countdownTimer)
|
clearInterval(timer)
|
||||||
countdownTimer = null
|
timer = null
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -139,30 +129,28 @@ const updateCountdown = () => {
|
|||||||
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0')
|
||||||
countdown.value = `${h}:${m}:${s}`
|
countdown.value = `${h}:${m}:${s}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const startCountdown = () => {
|
const startCountdown = () => {
|
||||||
if (!import.meta.client) return
|
|
||||||
if (countdownTimer) clearInterval(countdownTimer)
|
|
||||||
updateCountdown()
|
updateCountdown()
|
||||||
countdownTimer = setInterval(updateCountdown, 1000)
|
if (timer) clearInterval(timer)
|
||||||
|
timer = setInterval(updateCountdown, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.poll?.endTime,
|
() => props.poll?.endTime,
|
||||||
() => {
|
() => {
|
||||||
if (props.poll && props.poll.endTime) {
|
if (props.poll && props.poll.endTime) startCountdown()
|
||||||
startCountdown()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
|
||||||
)
|
)
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.poll && props.poll.endTime) startCountdown()
|
||||||
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (countdownTimer) clearInterval(countdownTimer)
|
if (timer) clearInterval(timer)
|
||||||
})
|
})
|
||||||
|
|
||||||
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
const gotoUser = (id) => navigateTo(`/users/${id}`, { replace: true })
|
||||||
|
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const API_BASE_URL = config.public.apiBaseUrl
|
||||||
const voteOption = async (idx) => {
|
const voteOption = async (idx) => {
|
||||||
const token = getToken()
|
const token = getToken()
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -185,6 +173,16 @@ const voteOption = async (idx) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.post-poll-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: var(--lottery-background-color);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.poll-option-button {
|
.poll-option-button {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
@@ -272,7 +270,6 @@ const voteOption = async (idx) => {
|
|||||||
.poll-left-time-title {
|
.poll-left-time-title {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
margin-right: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-left-time-value {
|
.poll-left-time-value {
|
||||||
@@ -281,21 +278,6 @@ const voteOption = async (idx) => {
|
|||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-poll-container {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
background-color: var(--lottery-background-color);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poll-question {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poll-option-progress {
|
.poll-option-progress {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: rgb(187, 187, 187);
|
background-color: rgb(187, 187, 187);
|
||||||
@@ -321,13 +303,6 @@ const voteOption = async (idx) => {
|
|||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-vote-button {
|
|
||||||
margin-top: 5px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
cursor: pointer;
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poll-participants {
|
.poll-participants {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -1032,7 +1032,120 @@ onMounted(async () => {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-menu-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-info-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-top: 10px;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-content-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
border-bottom: 1px solid var(--normal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar-container {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar-item {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar-item-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-content-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-medal {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 4px;
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-time {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-content-text {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-footer-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reactions-viewer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reactions-viewer-item-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 2px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reactions-viewer-item {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.make-reaction-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-link:hover {
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-editor-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.post-page-main-container {
|
.post-page-main-container {
|
||||||
@@ -1084,8 +1197,5 @@ onMounted(async () => {
|
|||||||
.loading-container {
|
.loading-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user