清除数据
This commit is contained in:
286
community-fresh-group-buy-frontend/src/pages/flashsale/index.vue
Normal file
286
community-fresh-group-buy-frontend/src/pages/flashsale/index.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="flashsale-page">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<!-- 页面标题 -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold mb-2 flex items-center">
|
||||
<el-icon class="page-icon mr-2">
|
||||
<Lightning/>
|
||||
</el-icon>
|
||||
限时活动
|
||||
</h1>
|
||||
<p class="text-gray-600">限时抢购,先到先得</p>
|
||||
</div>
|
||||
|
||||
<!-- 筛选栏 -->
|
||||
<div class="bg-white rounded-lg shadow-sm p-4 mb-6">
|
||||
<div class="flex flex-wrap gap-4 items-center">
|
||||
<!-- 状态筛选 -->
|
||||
<el-radio-group v-model="filters.status" @change="loadFlashSales">
|
||||
<el-radio-button label="">全部</el-radio-button>
|
||||
<el-radio-button label="UPCOMING">即将开始</el-radio-button>
|
||||
<el-radio-button label="ACTIVE">进行中</el-radio-button>
|
||||
<el-radio-button label="ENDED">已结束</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
||||
<!-- 排序 -->
|
||||
<el-select
|
||||
v-model="filters.sort"
|
||||
placeholder="排序方式"
|
||||
style="width: 150px"
|
||||
@change="loadFlashSales"
|
||||
>
|
||||
<el-option label="开始时间" value="startTime"/>
|
||||
<el-option label="结束时间" value="endTime"/>
|
||||
<el-option label="价格从低到高" value="flashPrice"/>
|
||||
<el-option label="折扣力度" value="discount"/>
|
||||
</el-select>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<el-input
|
||||
v-model="filters.keyword"
|
||||
clearable
|
||||
placeholder="搜索商品名称"
|
||||
style="width: 200px"
|
||||
@keyup.enter="loadFlashSales"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="cursor-pointer" @click="loadFlashSales">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<!-- 刷新按钮 -->
|
||||
<el-button @click="handleRefresh">
|
||||
<el-icon class="mr-1">
|
||||
<Refresh/>
|
||||
</el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
||||
<div class="stat-card tone-1">
|
||||
<div class="stat-value">{{ statistics.upcoming }}</div>
|
||||
<div class="stat-label">即将开始</div>
|
||||
<el-icon :size="30" class="stat-icon">
|
||||
<Clock/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stat-card tone-2">
|
||||
<div class="stat-value">{{ statistics.active }}</div>
|
||||
<div class="stat-label">正在进行</div>
|
||||
<el-icon :size="30" class="stat-icon">
|
||||
<Lightning/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stat-card tone-3">
|
||||
<div class="stat-value">{{ statistics.participated }}</div>
|
||||
<div class="stat-label">我的参与</div>
|
||||
<el-icon :size="30" class="stat-icon">
|
||||
<Trophy/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stat-card tone-4">
|
||||
<div class="stat-value">{{ statistics.success }}</div>
|
||||
<div class="stat-label">抢购成功</div>
|
||||
<el-icon :size="30" class="stat-icon">
|
||||
<SuccessFilled/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 限时活动列表 -->
|
||||
<div v-if="loading" class="text-center py-12">
|
||||
<el-icon :size="40" class="animate-spin">
|
||||
<Loading/>
|
||||
</el-icon>
|
||||
<p class="mt-2 text-gray-500">加载中...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="flashSales.length === 0" class="text-center py-12">
|
||||
<el-empty description="暂无限时活动"/>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
<FlashSaleCard
|
||||
v-for="item in flashSales"
|
||||
:key="item.id"
|
||||
:data="item"
|
||||
@participate="handleParticipate"
|
||||
@refresh="loadFlashSales"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="mt-8 flex justify-center">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.size"
|
||||
:page-sizes="[12, 24, 36, 48]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="loadFlashSales"
|
||||
@current-change="loadFlashSales"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, onMounted} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import FlashSaleCard from '@/components/business/FlashSaleCard.vue'
|
||||
import {flashsaleApi} from '@/api/modules/flashsale'
|
||||
import {useUserStore} from '@/stores/user'
|
||||
import type {FlashSale} from '@/types/api'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 数据状态
|
||||
const loading = ref(false)
|
||||
const flashSales = ref<FlashSale[]>([])
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
status: '',
|
||||
sort: 'startTime',
|
||||
keyword: ''
|
||||
})
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
size: 12,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 统计信息
|
||||
const statistics = reactive({
|
||||
upcoming: 0,
|
||||
active: 0,
|
||||
participated: 0,
|
||||
success: 0
|
||||
})
|
||||
|
||||
// 加载限时活动
|
||||
const loadFlashSales = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await flashsaleApi.getList({
|
||||
...filters,
|
||||
page: pagination.page - 1,
|
||||
size: pagination.size
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
flashSales.value = res.data.content
|
||||
pagination.total = res.data.totalElements
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载限时活动失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载统计信息(从后端获取真实数据)
|
||||
const loadStatistics = async () => {
|
||||
try {
|
||||
const res = await flashsaleApi.getStatistics()
|
||||
if (res.success) {
|
||||
statistics.upcoming = res.data.upcoming ?? 0
|
||||
statistics.active = res.data.active ?? 0
|
||||
statistics.participated = res.data.participated ?? 0
|
||||
statistics.success = res.data.success ?? 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载统计信息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 参与限时
|
||||
const handleParticipate = async (flashSaleId: number) => {
|
||||
if (!userStore.isLoggedIn) {
|
||||
ElMessage.warning('请先登录')
|
||||
router.push('/login')
|
||||
return
|
||||
}
|
||||
|
||||
// 先检查资格
|
||||
try {
|
||||
const res = await flashsaleApi.checkEligibility(flashSaleId)
|
||||
if (res.success && res.data.eligible) {
|
||||
// 确认对话框
|
||||
await ElMessageBox.confirm(
|
||||
'确定要参与这个限时活动吗?',
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '立即抢购',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
|
||||
// 跳转到详情页参与
|
||||
router.push(`/flashsale/${flashSaleId}`)
|
||||
} else {
|
||||
ElMessage.warning(res.data.reason || '您暂时无法参与此活动')
|
||||
}
|
||||
} catch (error) {
|
||||
// 用户取消或错误
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = () => {
|
||||
loadFlashSales()
|
||||
loadStatistics()
|
||||
ElMessage.success('已刷新')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadFlashSales()
|
||||
loadStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flashsale-page {
|
||||
min-height: calc(100vh - 60px);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.page-icon {
|
||||
color: #44443f;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
@apply relative overflow-hidden rounded-lg p-4;
|
||||
background: #fffaf2;
|
||||
color: #171715;
|
||||
border: 1px solid #d8cebf;
|
||||
box-shadow: 0 10px 24px rgba(23, 22, 20, 0.04);
|
||||
|
||||
.stat-value {
|
||||
@apply text-2xl font-bold;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
@apply text-sm mt-1;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
@apply absolute right-4 bottom-4;
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user