后端功能增强:全局异常处理、API控制器、JSP视图和单元测试
- 添加 GlobalExceptionHandler 全局异常处理 - 添加 ApiController REST API 控制器 - 更新 WebConfig 跨域配置和 ProductRepository 查询方法 - 新增 monitor/product-detail/profile JSP 视图页面 - 添加 FlashSaleServiceTest 秒杀服务单元测试 - 更新 application.yml 配置
This commit is contained in:
260
flash-sale-frontend/src/pages/home/index.vue
Normal file
260
flash-sale-frontend/src/pages/home/index.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div class="home-page">
|
||||
<!-- 轮播图 -->
|
||||
<el-carousel height="400px" :interval="5000" arrow="hover">
|
||||
<el-carousel-item v-for="item in banners" :key="item.id">
|
||||
<div class="banner-content" :style="{ background: item.bgColor }">
|
||||
<div class="container mx-auto px-4 h-full">
|
||||
<div class="flex items-center h-full">
|
||||
<div class="w-1/2">
|
||||
<h1 class="text-4xl font-bold text-white mb-4">
|
||||
<el-icon :size="40"><Lightning /></el-icon>
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
<p class="text-xl text-white mb-6">{{ item.subtitle }}</p>
|
||||
<div class="space-x-4">
|
||||
<el-button size="large" type="primary" @click="router.push(item.link)">
|
||||
{{ item.buttonText }}
|
||||
</el-button>
|
||||
<el-button size="large" @click="router.push('/products')">
|
||||
浏览商品
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/2 text-center">
|
||||
<el-icon :size="200" class="text-white opacity-50">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<!-- 正在秒杀 -->
|
||||
<section class="mb-12">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold flex items-center">
|
||||
<el-icon class="text-red-500 mr-2"><Lightning /></el-icon>
|
||||
正在秒杀
|
||||
</h2>
|
||||
<el-button text @click="router.push('/flashsale')">
|
||||
查看全部
|
||||
<el-icon class="ml-1"><ArrowRight /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="loadingFlashSales" class="text-center py-8">
|
||||
<el-icon :size="40" class="animate-spin"><Loading /></el-icon>
|
||||
<p class="mt-2 text-gray-500">加载中...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="activeFlashSales.length === 0" class="text-center py-8">
|
||||
<el-empty description="暂无进行中的秒杀活动" />
|
||||
</div>
|
||||
|
||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<FlashSaleCard
|
||||
v-for="item in activeFlashSales"
|
||||
:key="item.id"
|
||||
:data="item"
|
||||
@participate="handleParticipate"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 热门商品 -->
|
||||
<section class="mb-12">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold flex items-center">
|
||||
<el-icon class="text-orange-500 mr-2"><Star /></el-icon>
|
||||
热门商品
|
||||
</h2>
|
||||
<el-button text @click="router.push('/products')">
|
||||
查看全部
|
||||
<el-icon class="ml-1"><ArrowRight /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="loadingProducts" class="text-center py-8">
|
||||
<el-icon :size="40" class="animate-spin"><Loading /></el-icon>
|
||||
<p class="mt-2 text-gray-500">加载中...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="hotProducts.length === 0" class="text-center py-8">
|
||||
<el-empty description="暂无热门商品" />
|
||||
</div>
|
||||
|
||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<ProductCard
|
||||
v-for="item in hotProducts"
|
||||
:key="item.id"
|
||||
:data="item"
|
||||
@add-to-cart="handleAddToCart"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 系统特性 -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-center mb-8">系统特性</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div class="feature-card">
|
||||
<el-icon :size="40" class="text-red-500 mb-4"><Lightning /></el-icon>
|
||||
<h3 class="text-lg font-semibold mb-2">秒杀抢购</h3>
|
||||
<p class="text-gray-600">高并发秒杀系统,支持大量用户同时抢购</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<el-icon :size="40" class="text-green-500 mb-4"><Lock /></el-icon>
|
||||
<h3 class="text-lg font-semibold mb-2">防超卖</h3>
|
||||
<p class="text-gray-600">分布式锁机制,确保库存数据一致性</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<el-icon :size="40" class="text-blue-500 mb-4"><Coin /></el-icon>
|
||||
<h3 class="text-lg font-semibold mb-2">Redis缓存</h3>
|
||||
<p class="text-gray-600">五种数据类型应用,毫秒级响应</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<el-icon :size="40" class="text-orange-500 mb-4"><Speedometer /></el-icon>
|
||||
<h3 class="text-lg font-semibold mb-2">接口限流</h3>
|
||||
<p class="text-gray-600">多种限流策略,防止恶意刷单</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import FlashSaleCard from '@/components/business/FlashSaleCard.vue'
|
||||
import ProductCard from '@/components/business/ProductCard.vue'
|
||||
import { flashsaleApi } from '@/api/modules/flashsale'
|
||||
import { productApi } from '@/api/modules/product'
|
||||
import { useCartStore } from '@/stores/cart'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import type { FlashSale, Product } from '@/types/api'
|
||||
|
||||
const router = useRouter()
|
||||
const cartStore = useCartStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 轮播图数据
|
||||
const banners = [
|
||||
{
|
||||
id: 1,
|
||||
title: '秒杀系统',
|
||||
subtitle: '基于Redis集群构建的高并发秒杀系统',
|
||||
buttonText: '立即抢购',
|
||||
link: '/flashsale',
|
||||
bgColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
icon: 'Lightning'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '防超卖机制',
|
||||
subtitle: '采用分布式锁和Lua脚本,确保数据一致性',
|
||||
buttonText: '了解更多',
|
||||
link: '/flashsale',
|
||||
bgColor: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
|
||||
icon: 'Lock'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '高性能缓存',
|
||||
subtitle: 'Redis集群架构,毫秒级响应',
|
||||
buttonText: '查看商品',
|
||||
link: '/products',
|
||||
bgColor: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
|
||||
icon: 'Speedometer'
|
||||
}
|
||||
]
|
||||
|
||||
// 数据状态
|
||||
const loadingFlashSales = ref(false)
|
||||
const loadingProducts = ref(false)
|
||||
const activeFlashSales = ref<FlashSale[]>([])
|
||||
const hotProducts = ref<Product[]>([])
|
||||
|
||||
// 加载秒杀活动
|
||||
const loadFlashSales = async () => {
|
||||
loadingFlashSales.value = true
|
||||
try {
|
||||
const res = await flashsaleApi.getActive(4)
|
||||
if (res.success) {
|
||||
activeFlashSales.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载秒杀活动失败:', error)
|
||||
} finally {
|
||||
loadingFlashSales.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载热门商品
|
||||
const loadProducts = async () => {
|
||||
loadingProducts.value = true
|
||||
try {
|
||||
const res = await productApi.getHot(8)
|
||||
if (res.success) {
|
||||
hotProducts.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载热门商品失败:', error)
|
||||
} finally {
|
||||
loadingProducts.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 参与秒杀
|
||||
const handleParticipate = async (flashSaleId: number) => {
|
||||
if (!userStore.isLoggedIn) {
|
||||
ElMessage.warning('请先登录')
|
||||
router.push('/login')
|
||||
return
|
||||
}
|
||||
|
||||
// 跳转到秒杀详情页
|
||||
router.push(`/flashsale/${flashSaleId}`)
|
||||
}
|
||||
|
||||
// 添加到购物车
|
||||
const handleAddToCart = async (productId: number) => {
|
||||
if (!userStore.isLoggedIn) {
|
||||
ElMessage.warning('请先登录')
|
||||
router.push('/login')
|
||||
return
|
||||
}
|
||||
|
||||
await cartStore.addToCart(productId)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadFlashSales()
|
||||
loadProducts()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.home-page {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.banner-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
@apply bg-white p-6 rounded-lg shadow-md text-center hover:shadow-lg transition-shadow;
|
||||
}
|
||||
|
||||
:deep(.el-carousel__item) {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user