Files
lucky_shop/pages_tool/member/card_log.vue
ZF sun 2e535b9d93 refactor(member pages): unify onShow login redirect logic
1. extract common onShow login check to dedicated method redirectTologinOnShowLifecycle
2. add fallback callback for login failure to navigate back on wechat mini program
3. update all page login redirect calls to use the new unified method
4. add debug logs for redirect and auth flow tracing
2026-06-27 18:25:53 +08:00

314 lines
6.9 KiB
Vue

<template>
<view :style="themeColor">
<!-- 顶部统计 -->
<view class="stat-header">
<view class="stat-item">
<view class="stat-value">{{ cardStat.total_consume }}</view>
<view class="stat-label">{{ $lang('totalConsume') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<view class="stat-value">{{ cardStat.balance }}</view>
<view class="stat-label">{{ $lang('cardBalance') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<view class="stat-value">{{ cardStat.total_recharge }}</view>
<view class="stat-label">{{ $lang('totalRecharge') }}{{ $lang('statUnit', { unit: $lang('yuanSuffix') }) }}</view>
</view>
</view>
<!-- 筛选 tab -->
<scroll-view class="filter-tab" :scroll-x="true" :show-scrollbar="false">
<view v-for="(item, index) in filterList" :key="index"
class="tab-item" :class="{ active: currentFilter === item.value }"
@click="onFilterChange(item.value)">
<text>{{ item.label }}</text>
</view>
</scroll-view>
<!-- 列表 -->
<mescroll-uni @getData="getData" ref="mescroll">
<block slot="list">
<block v-if="logList.length > 0">
<view class="log-list">
<view class="log-item" v-for="(item, index) in logList" :key="index" @click="goDetail(item)">
<view class="log-icon" :class="item.type">
<text class="iconfont" :class="getIconClass(item.type)"></text>
</view>
<view class="log-info">
<view class="log-title">{{ item.title }}</view>
<view class="log-desc">{{ item.desc }}</view>
<view class="log-time">{{ formatTime(item.create_time) }}</view>
</view>
<view class="log-amount">
<text :class="item.amount > 0 ? 'income' : 'expense'">
{{ item.amount > 0 ? '+' : '' }}{{ $lang('amountWithUnit', { amount: item.amount }) }}
</text>
</view>
</view>
</view>
</block>
<block v-else>
<ns-empty :isIndex="false" :text="$lang('emptyTips')"></ns-empty>
</block>
</block>
</mescroll-uni>
<ns-login ref="login"></ns-login>
<loading-cover ref="loadingCover"></loading-cover>
</view>
</template>
<script>
export default {
data() {
return {
cardStat: {
total_consume: '0.00',
balance: '0.00',
total_recharge: '0.00'
},
logList: [],
filterList: [
{ label: this.$lang('filterAll'), value: 'all' },
{ label: this.$lang('filterIncome'), value: 'income' },
{ label: this.$lang('filterExpense'), value: 'expense' },
{ label: this.$lang('filterRecharge'), value: 'recharge' },
{ label: this.$lang('filterConsume'), value: 'consume' },
{ label: this.$lang('filterGift'), value: 'gift' }
],
currentFilter: 'all'
};
},
onLoad() {},
onShow() {
if (!this.storeToken) {
this.redirectTologinOnShowLifecycle('/pages_tool/member/card_log');
return;
}
this.loadStat();
},
methods: {
// 加载统计数据
loadStat() {
this.$api.sendRequest({
url: '/api/membercard/stat',
success: res => {
if (res.code == 0 && res.data) {
this.cardStat = res.data;
}
}
});
},
// 筛选切换
onFilterChange(value) {
this.currentFilter = value;
this.$refs.mescroll.refresh();
},
// 获取图标 class
getIconClass(type) {
const iconMap = {
recharge: 'icon-chongzhi',
consume: 'icon-xiaofei',
gift: 'icon-liwu',
refund: 'icon-tuikuan'
};
return iconMap[type] || 'icon-jifen';
},
// 格式化时间
formatTime(timestamp) {
return this.$util.timeStampTurnTime(timestamp);
},
// 跳转详情
goDetail(item) {
if (item.related_type === 'order') {
this.$util.redirectTo('/pages_order/detail', { order_id: item.related_id });
}
},
// 获取列表数据
getData(mescroll) {
this.$api.sendRequest({
url: '/api/membercard/logPage',
data: {
page_size: mescroll.size,
page: mescroll.num,
type: this.currentFilter
},
success: res => {
let newArr = [];
if (res.code == 0 && res.data) {
newArr = res.data.list;
} else {
this.$util.showToast({
title: res.message
});
}
mescroll.endSuccess(newArr.length);
if (mescroll.num == 1) {
this.logList = [];
}
this.logList = this.logList.concat(newArr);
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
},
fail: res => {
mescroll.endErr();
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
}
});
}
}
};
</script>
<style lang="scss" scoped>
.stat-header {
display: flex;
align-items: center;
padding: 30rpx;
background: linear-gradient(135deg, #e3b66b 0%, #d4a04a 100%);
color: #fff;
.stat-item {
flex: 1;
text-align: center;
.stat-value {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
opacity: 0.85;
}
}
.stat-divider {
width: 1rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.3);
}
}
.filter-tab {
width: 100%;
white-space: nowrap;
background: #fff;
border-bottom: 1rpx solid $color-line;
.tab-item {
display: inline-block;
padding: 24rpx 32rpx;
font-size: $font-size-base;
color: $color-tip;
position: relative;
&.active {
color: $color-base-text;
font-weight: 500;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
background: $color-base-text;
border-radius: 2rpx;
}
}
}
}
.log-list {
padding: 0 32rpx;
background: #fff;
.log-item {
display: flex;
align-items: center;
padding: 28rpx 0;
border-bottom: 1rpx solid $color-line;
&:last-child {
border-bottom: none;
}
.log-icon {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
font-size: 32rpx;
&.recharge {
background: rgba(76, 175, 80, 0.1);
color: #4caf50;
}
&.consume {
background: rgba(244, 67, 54, 0.1);
color: #f44336;
}
&.gift {
background: rgba(255, 152, 0, 0.1);
color: #ff9800;
}
&.refund {
background: rgba(33, 150, 243, 0.1);
color: #2196f3;
}
}
.log-info {
flex: 1;
overflow: hidden;
.log-title {
font-size: $font-size-base;
color: $color-base-text;
font-weight: 500;
margin-bottom: 8rpx;
}
.log-desc {
font-size: $font-size-activity-tag;
color: $color-tip;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.log-time {
font-size: $font-size-activity-tag;
color: $color-tip;
}
}
.log-amount {
margin-left: 20rpx;
font-size: $font-size-toolbar;
font-weight: 500;
.income {
color: #4caf50;
}
.expense {
color: $color-base-text;
}
}
}
}
</style>