225 lines
4.9 KiB
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>
|