|
|
<template> <view class="activity-list"> <view class="tab-box"> <view class="tab-item" :class="{ active: currentTab === 0 }" @click="switchTab(0)" > 未开始 </view> <view class="tab-item" :class="{ active: currentTab === 1 }" @click="switchTab(1)" > 进行中 </view> <view class="tab-item" :class="{ active: currentTab === 2 }" @click="switchTab(2)" > 已结束 </view> </view>
<scroll-view scroll-y @scrolltolower="onScrollLower" lower-threshold="150" class="scroll-view" > <view v-if="loading" class="loading-box"> <text class="loading-text">加载中...</text> </view>
<view class="activity-item" v-for="item in activityList" :key="item.id" > <view class="activity-info"> <view class="title-row"> <text class="title">{{ item.fondsName }}</text> </view> <view class="item-info"> <text class="label">入馆日期</text> <text class="value">{{ item.visitDate }}</text> </view> <view class="item-info"> <text class="label">入馆时间</text> <text class="value">{{ item.visitTime }}-{{ item.endTimeHm }}</text> </view> <!-- <view class="item-info"> <text class="label">所在馆</text> <text class="value">{{ item.fondsName }}</text> </view> --> <view class="btn-box" v-if="item.status === 0"> <button class="activity-btn" type="primary" @click.stop="cancelAppoint(item)"> 取消预约 </button> </view> </view> </view>
<view v-if="!loading && noMore && activityList.length > 0" class="nomore-box"> <text class="nomore-text">没有更多数据了</text> </view>
<view class="empty-box" v-if="!loading && activityList.length === 0"> <uni-icons type="empty" size="80" color="#ccc"></uni-icons> <text class="empty-text">{{ getEmptyText() }}</text> </view> </scroll-view> </view></template>
<script>import { FetchMyReservation, FetchCancelReservation } from '@/api/reservation';import { getOpenId } from '@/utils/storage';import config from '@/utils/config';
export default { data() { return { currentTab: 0, activityList: [], refreshing: false, loading: false, noMore: false, page: 0, pageSize: 10 }; }, onLoad() { this.getActivityList(true); }, onPullDownRefresh() { if (this.loading) { uni.stopPullDownRefresh() return } this.getActivityList(true).finally(() => { uni.stopPullDownRefresh() }) }, methods: { formatTsToDate(ts) { const d = new Date(ts); const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; }, formatTimeHm(timeStr) { if (!timeStr) return '' return timeStr.substring(0, 5) }, switchTab(index) { this.currentTab = index; this.page = 0; this.noMore = false; this.activityList = []; this.getActivityList(true); },
async fetchMyReservation() { const openId = await getOpenId(); const res = await FetchMyReservation({ libcode: config.LIB_CODE, openId: openId, page: this.page, size: this.pageSize, status: this.currentTab }) console.log('我的预约', res) if (res.code === 200 && Array.isArray(res.data.content)) { const list = res.data.content.map(raw => { return { id: raw.id, fondsName: raw.fondsName || '', visitDate: this.formatTsToDate(raw.specificDate), visitTime: this.formatTimeHm(raw.startTime), endTimeHm: this.formatTimeHm(raw.endTime), status: Number(this.currentTab), startTimeRaw: raw.startTime, endTimeRaw: raw.endTime, specificDate: raw.specificDate } }) // 分页判断(和活动预约逻辑保持一致)
const currentPage = res.data.number ?? 0; const totalPage = res.data.totalPages ?? 0; return { list, noMore: currentPage >= totalPage - 1 } } return { list: [], noMore: true } },
async getActivityList(isRefresh = false) { if (this.loading) return; if (isRefresh) { this.page = 0; this.noMore = false; this.refreshing = true; } else { if (this.noMore) return; } this.loading = true; try { const { list, noMore } = await this.fetchMyReservation(); this.noMore = noMore; if (isRefresh) { this.activityList = list; } else { this.activityList = [...this.activityList, ...list]; } } catch (e) { console.error('获取我的预约异常', e) uni.showToast({ title: '获取预约列表失败', icon: 'none' }) if (isRefresh) this.activityList = []; } finally { this.refreshing = false; this.loading = false; } },
onScrollLower() { if (this.loading || this.noMore) return; this.page += 1; this.getActivityList(false); },
async cancelAppoint(item) { uni.showModal({ title: '提示', content: `确定要取消当前时间段的预约吗?`, success: async (res) => { if (res.confirm) { const res = await FetchCancelReservation({ id: item.id }) if (res.code === 200) { uni.showToast({ title: '取消成功', icon: 'success' }); this.getActivityList(true); } else { uni.showToast({ title: res.msg || '取消预约失败', icon: 'none' }) } } } }) }, getEmptyText() { const textMap = { 0: '未开始', 1: '进行中', 2: '已结束' } return `暂无${textMap[this.currentTab]}的预约~` } },};</script>
<style lang="scss" scoped>.activity-list { padding: 0; height: 100vh; box-sizing: border-box; background-color: #f5f5f5; display: flex; flex-direction: column;}
.tab-box { display: flex; background-color: #fff; margin-bottom: 10px; position: sticky; top: 0; z-index: 99;}.tab-item { flex: 1; text-align: center; padding: 12px 0; font-size: 15px; color: #666; position: relative;}.tab-item.active { color: #01a4fe; font-weight: bold;}.tab-item.active::after { content: ''; position: absolute; width: 30px; height: 3px; background-color: #01a4fe; bottom: 0; left: 50%; transform: translateX(-50%); border-radius: 2px;}
.scroll-view { flex: 1; height: 0; padding: 0 12px; box-sizing: border-box;}
.loading-box { padding: 20px 0; text-align: center;}.loading-text { font-size: 14px; color: #999;}
.nomore-box { padding: 15px 0; text-align: center;}.nomore-text { font-size: 13px; color: #999;}
.empty-box { height: calc(100vh - 180px); display: flex; flex-direction: column; align-items: center; justify-content: center;}.empty-text { margin-top: 16px; font-size: 14px; color: #999;}
.activity-item { background: #fff; border-radius: 12px; margin-bottom: 12px; overflow: hidden; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06); cursor: pointer; transition: transform 0.2s;
&:active { transform: scale(0.98); }}
.activity-info { display: flex; flex-direction: column; align-items: flex-start; padding: 16px; .title { font-size: 16px; font-weight: bold; color: #222; margin-bottom: 12px; display: block; } .item-info { width: 100%; display: flex; justify-content: space-between; padding: 4px 0; font-size: 14px; .label { color: #666; width: 72px; } .value { color: #333; flex: 1; text-align: right; } }}
.status-tag { padding: 2px 8px; border-radius: 4px; font-size: 12px;}.status-tag.status-0 { color: #01a4fe; background: #e6f7ff;}.status-tag.status-1 { color: #00b42a; background: #e6ffed;}.status-tag.status-2 { color: #999; background: #f5f5f5;}
.btn-box { width: 100%; display: flex; justify-content: flex-end; margin-top: 10px; padding-top: 10px; border-top: 1px solid #e5e5e5; }
.activity-btn { background-color: #01a4fe; font-size: 13px; border-radius: 6px; padding: 0 14px; height: 28px; line-height: 28px;}</style>
|