huangye-parking/miniapp/pages/points/detail.vue

225 lines
4.9 KiB
Vue

<template>
<view class="detail-page">
<NavBar title="积分明细" />
<!-- 类型标签 -->
<view class="tabs">
<view
class="tab-item"
:class="{ active: currentType === 'all' }"
@click="switchType('all')"
>全部</view>
<view
class="tab-item"
:class="{ active: currentType === 'income' }"
@click="switchType('income')"
>收入</view>
<view
class="tab-item"
:class="{ active: currentType === 'expense' }"
@click="switchType('expense')"
>支出</view>
</view>
<!-- 门店筛选 -->
<view class="filter-area">
<picker :range="storeOptions" range-key="label" @change="onStoreChange">
<view class="store-picker">
<text>{{ currentStoreName }}</text>
<text class="arrow"></text>
</view>
</picker>
</view>
<!-- 积分明细列表 -->
<view class="record-list">
<view class="record-item" v-for="(record, index) in records" :key="record.id">
<view class="record-left">
<text class="record-reason">{{ record.reason }}</text>
<text class="record-time">{{ formatTime(record.createdAt) }}</text>
<text v-if="record.couponName" class="record-extra">优惠券:{{ record.couponName }}</text>
<text v-if="record.storeName" class="record-extra">兑换门店:{{ record.storeName }}</text>
</view>
<text class="record-amount" :class="record.amount > 0 ? 'income' : 'expense'">
{{ record.amount > 0 ? '+' : '' }}{{ record.amount }}积分
</text>
</view>
<view v-if="!records.length && !loading" class="empty-tip">暂无积分记录</view>
</view>
</view>
</template>
<script>
import { getRecords } from '@/api/points'
import { getStores } from '@/api/store'
import NavBar from '@/components/NavBar.vue'
export default {
components: { NavBar },
data() {
return {
loading: false,
currentType: 'all',
currentStoreId: '',
currentStoreName: '全部门店',
storeOptions: [{ label: '全部门店', value: '' }],
records: []
}
},
onLoad() {
this.loadStores()
this.loadRecords()
},
methods: {
/** 加载门店列表用于筛选 */
async loadStores() {
try {
const res = await getStores()
const stores = res.data || res || []
this.storeOptions = [
{ label: '全部门店', value: '' },
...stores.map(s => ({ label: s.name, value: s.id }))
]
} catch (err) {
console.error('加载门店列表失败:', err)
}
},
/** 加载积分明细 */
async loadRecords() {
this.loading = true
try {
const params = {}
if (this.currentType !== 'all') params.type = this.currentType
if (this.currentStoreId) params.storeId = this.currentStoreId
const res = await getRecords(params)
this.records = res.data || res || []
} catch (err) {
console.error('加载积分明细失败:', err)
} finally {
this.loading = false
}
},
/** 切换类型标签 */
switchType(type) {
this.currentType = type
this.loadRecords()
},
/** 门店筛选变更 */
onStoreChange(e) {
const idx = e.detail.value
const option = this.storeOptions[idx]
this.currentStoreId = option.value
this.currentStoreName = option.label
this.loadRecords()
},
/** 格式化时间 */
formatTime(t) {
if (!t) return ''
return t.replace('T', ' ').substring(0, 16)
}
}
}
</script>
<style scoped>
.detail-page {
padding: 20rpx;
}
.tabs {
display: flex;
gap: 20rpx;
margin-bottom: 24rpx;
padding: 0 8rpx;
}
.tab-item {
padding: 16rpx 40rpx;
font-size: 28rpx;
color: #666;
background: #f5f5f5;
border-radius: 40rpx;
border: 2rpx solid transparent;
}
.tab-item.active {
color: #F5C800;
font-weight: bold;
background: #FFF7D4;
border-color: #FFD900;
}
.filter-area {
margin-bottom: 16rpx;
}
.store-picker {
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
padding: 16rpx 24rpx;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
}
.arrow {
font-size: 20rpx;
color: #999;
}
.record-list {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
}
.record-item {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 28rpx 24rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.record-item:last-child {
border-bottom: none;
}
.record-left {
flex: 1;
min-width: 0;
}
.record-reason {
display: block;
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.record-time {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 6rpx;
}
.record-extra {
display: block;
font-size: 24rpx;
color: #999;
line-height: 1.6;
}
.record-amount {
font-size: 32rpx;
font-weight: bold;
flex-shrink: 0;
margin-left: 20rpx;
}
.record-amount.income {
color: #25D003;
}
.record-amount.expense {
color: #FF3E3E;
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
</style>