- 删除所有 JSP 页面(20个文件),前端完全迁移至 Vue 3 SPA - 完善评价系统:ReviewDialog 组件、用户评价历史页、评价状态检查API - 新增通知系统:Notification 实体/仓库/服务/控制器,NotificationCenter 接入真实API - 新增拼团模块:GroupBuying 全套后端和前端页面 - 修复 review check API 参数双重包装导致请求格式错误 - 修复通知 API 路径缺少 /api 前缀和响应格式处理 - MessageListenerService 集成 NotificationService 创建持久化通知 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
1.7 KiB
Vue
80 lines
1.7 KiB
Vue
<template>
|
|
<div class="countdown-timer">
|
|
<template v-if="timeLeft > 0">
|
|
<el-icon class="countdown-icon mr-1"><Clock /></el-icon>
|
|
<span class="time-block">{{ hours.toString().padStart(2, '0') }}</span>
|
|
<span class="separator">:</span>
|
|
<span class="time-block">{{ minutes.toString().padStart(2, '0') }}</span>
|
|
<span class="separator">:</span>
|
|
<span class="time-block">{{ seconds.toString().padStart(2, '0') }}</span>
|
|
</template>
|
|
<span v-else class="text-gray-400">已结束</span>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
|
|
const props = defineProps<{
|
|
endTime: number
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
finish: []
|
|
}>()
|
|
|
|
const timeLeft = ref(0)
|
|
let timer: number | null = null
|
|
|
|
const hours = computed(() => Math.floor(timeLeft.value / 3600))
|
|
const minutes = computed(() => Math.floor((timeLeft.value % 3600) / 60))
|
|
const seconds = computed(() => timeLeft.value % 60)
|
|
|
|
const updateTime = () => {
|
|
const now = Date.now()
|
|
const remaining = Math.max(0, Math.floor((props.endTime - now) / 1000))
|
|
timeLeft.value = remaining
|
|
|
|
if (remaining === 0 && timer) {
|
|
clearInterval(timer)
|
|
timer = null
|
|
emit('finish')
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
updateTime()
|
|
if (timeLeft.value > 0) {
|
|
timer = setInterval(updateTime, 1000)
|
|
}
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
if (timer) {
|
|
clearInterval(timer)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.countdown-timer {
|
|
@apply flex items-center justify-center text-lg font-mono;
|
|
|
|
.countdown-icon {
|
|
color: #5e5e58;
|
|
}
|
|
|
|
.time-block {
|
|
@apply px-2 py-1 rounded;
|
|
background: #fff;
|
|
color: #171715;
|
|
border: 1px solid #171715;
|
|
}
|
|
|
|
.separator {
|
|
@apply mx-1 font-bold;
|
|
color: #5e5e58;
|
|
}
|
|
}
|
|
</style>
|