后端功能增强:全局异常处理、API控制器、JSP视图和单元测试

- 添加 GlobalExceptionHandler 全局异常处理
- 添加 ApiController REST API 控制器
- 更新 WebConfig 跨域配置和 ProductRepository 查询方法
- 新增 monitor/product-detail/profile JSP 视图页面
- 添加 FlashSaleServiceTest 秒杀服务单元测试
- 更新 application.yml 配置
This commit is contained in:
2026-03-05 20:30:48 +08:00
parent 923e877759
commit 989c2741a2
63 changed files with 15508 additions and 1 deletions

View File

@@ -0,0 +1,71 @@
<template>
<div class="countdown-timer">
<template v-if="timeLeft > 0">
<el-icon class="text-red-500 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;
.time-block {
@apply px-2 py-1 bg-red-50 text-red-600 rounded;
}
.separator {
@apply mx-1 text-red-500 font-bold;
}
}
</style>