UniApp:会员码图片兜底、海报下载 Promise、账单移除公排退款、 佣金状态与资产页 NavBar、资产接口 total_points_earned。 后端:推荐人须自报单才得周期佣金;升级前快照等级再发积分; 积分按报单商品数量倍乘;伞下级差按伞下基数传递;直推/伞下任务 统计补充 refund_status;周期佣金在事务内锁推荐人行防竞态; 新增 hjf:verify-agent-config 命令做等级与任务 e2e 验收。 Made-with: Cursor
275 lines
8.6 KiB
Vue
275 lines
8.6 KiB
Vue
<template>
|
|
<view class="brokerage-page" :style="colorStyle">
|
|
<!-- #ifdef MP -->
|
|
<NavBar titleText="佣金状态" :iconColor="iconColor" :textColor="iconColor" showBack :isScrolling="isScrolling"></NavBar>
|
|
<!-- #endif -->
|
|
<!-- 顶部渐变区域 -->
|
|
<view class="header-gradient">
|
|
<view class="header-gradient__circle header-gradient__circle--1"></view>
|
|
<view class="header-gradient__circle header-gradient__circle--2"></view>
|
|
|
|
<view class="header-card">
|
|
<view class="header-card__label">累计佣金收入</view>
|
|
<view class="header-card__amount">
|
|
<text class="header-card__currency">¥</text>
|
|
<text class="header-card__value">{{ progressData.total_brokerage || '0.00' }}</text>
|
|
</view>
|
|
<!-- 佣金周期进度环 -->
|
|
<HjfQueueProgress
|
|
:cycle-current="progressData.cycle_current || 0"
|
|
:cycle-total="progressData.cycle_total || 3"
|
|
:cycle-rates="progressData.cycle_rates || [20, 30, 50]"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 佣金记录列表 -->
|
|
<view class="records-section">
|
|
<view class="section-header">
|
|
<view class="section-header__bar"></view>
|
|
<text class="section-header__title">佣金记录</text>
|
|
<text class="section-header__more" @tap="goToCommissionDetail">查看全部</text>
|
|
</view>
|
|
|
|
<view v-if="loading" class="loading-wrap">
|
|
<view class="loading-dot loading-dot--1"></view>
|
|
<view class="loading-dot loading-dot--2"></view>
|
|
<view class="loading-dot loading-dot--3"></view>
|
|
</view>
|
|
|
|
<view v-else-if="records.length === 0" class="empty-wrap">
|
|
<emptyPage title="暂无佣金记录" src="/statics/images/noOrder.gif" />
|
|
</view>
|
|
|
|
<view v-else class="record-list">
|
|
<view
|
|
v-for="(item, index) in records"
|
|
:key="item.id || index"
|
|
class="record-item"
|
|
>
|
|
<view class="record-item__left">
|
|
<view class="record-item__avatar-wrap">
|
|
<image
|
|
class="record-item__avatar"
|
|
:src="item.avatar || '/statics/images/avatar.png'"
|
|
mode="aspectFill"
|
|
/>
|
|
</view>
|
|
<view class="record-item__info">
|
|
<text class="record-item__name">{{ item.nickname || '用户' }}</text>
|
|
<text class="record-item__time">{{ item.time }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="record-item__right">
|
|
<text class="record-item__amount">+¥{{ item.number }}</text>
|
|
<text class="record-item__type">{{ item.title || '推荐佣金' }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 上拉加载 -->
|
|
<view v-if="records.length > 0" class="load-more">
|
|
<text v-if="loadingMore" class="load-more__text">加载中...</text>
|
|
<text v-else-if="finished" class="load-more__text">—— 没有更多了 ——</text>
|
|
</view>
|
|
|
|
<!-- 佣金到账通知 -->
|
|
<HjfRefundNotice
|
|
:visible="showNotice"
|
|
:amount="noticeData.amount"
|
|
:order-id="noticeData.orderId"
|
|
@close="showNotice = false"
|
|
/>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { getBrokerageProgress } from '@/api/hjfQueue.js';
|
|
import HjfQueueProgress from '@/components/HjfQueueProgress.vue';
|
|
import HjfRefundNotice from '@/components/HjfRefundNotice.vue';
|
|
import emptyPage from '@/components/emptyPage.vue';
|
|
import colors from '@/mixins/color.js';
|
|
import { spreadOrder } from '@/api/user.js';
|
|
// #ifdef MP
|
|
import NavBar from '@/components/NavBar.vue';
|
|
// #endif
|
|
|
|
export default {
|
|
name: 'BrokerageStatus',
|
|
mixins: [colors],
|
|
components: {
|
|
HjfQueueProgress,
|
|
HjfRefundNotice,
|
|
emptyPage,
|
|
// #ifdef MP
|
|
NavBar,
|
|
// #endif
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
iconColor: '#FFFFFF',
|
|
isScrolling: false,
|
|
progressData: {},
|
|
records: [],
|
|
loading: false,
|
|
loadingMore: false,
|
|
finished: false,
|
|
page: 1,
|
|
limit: 15,
|
|
showNotice: false,
|
|
noticeData: { amount: 0, orderId: '' }
|
|
};
|
|
},
|
|
|
|
onPageScroll(e) {
|
|
if (e.scrollTop > 50) {
|
|
this.isScrolling = true;
|
|
this.iconColor = '#333333';
|
|
} else {
|
|
this.isScrolling = false;
|
|
this.iconColor = '#FFFFFF';
|
|
}
|
|
},
|
|
|
|
onLoad() {
|
|
this.loadProgress();
|
|
this.loadRecords();
|
|
},
|
|
|
|
onReachBottom() {
|
|
if (!this.loadingMore && !this.finished) this.loadRecords();
|
|
},
|
|
|
|
methods: {
|
|
loadProgress() {
|
|
getBrokerageProgress()
|
|
.then(res => {
|
|
if (res && res.data) this.progressData = res.data;
|
|
})
|
|
.catch(() => {});
|
|
},
|
|
|
|
loadRecords() {
|
|
if (this.loading || this.loadingMore || this.finished) return;
|
|
const isFirst = this.page === 1;
|
|
if (isFirst) this.loading = true; else this.loadingMore = true;
|
|
|
|
spreadOrder({ page: this.page, limit: this.limit, category: 'now_money', type: 'brokerage' })
|
|
.then(res => {
|
|
const list = (res && res.data && res.data.list) ? res.data.list : [];
|
|
if (list.length < this.limit) this.finished = true;
|
|
if (isFirst) this.records = list;
|
|
else this.records = [...this.records, ...list];
|
|
this.page++;
|
|
})
|
|
.catch(() => {
|
|
if (isFirst) this.records = [];
|
|
})
|
|
.finally(() => {
|
|
this.loading = false;
|
|
this.loadingMore = false;
|
|
});
|
|
},
|
|
|
|
goToCommissionDetail() {
|
|
uni.navigateTo({ url: '/pages/users/user_spread_money/index' });
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.brokerage-page {
|
|
min-height: 100vh;
|
|
background: #f4f5f7;
|
|
padding-bottom: 60rpx;
|
|
}
|
|
|
|
.header-gradient {
|
|
background: linear-gradient(135deg, var(--view-theme, #e93323) 0%, var(--view-gradient, #f76b1c) 100%);
|
|
padding: 40rpx 30rpx 56rpx;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
.header-gradient__circle {
|
|
position: absolute;
|
|
border-radius: 50%;
|
|
background: #fff;
|
|
opacity: 0.07;
|
|
}
|
|
.header-gradient__circle--1 { width: 400rpx; height: 400rpx; top: -150rpx; right: -80rpx; }
|
|
.header-gradient__circle--2 { width: 240rpx; height: 240rpx; bottom: -60rpx; left: -50rpx; }
|
|
|
|
.header-card {
|
|
position: relative;
|
|
z-index: 1;
|
|
background: rgba(255,255,255,0.14);
|
|
border-radius: 28rpx;
|
|
padding: 36rpx 32rpx;
|
|
}
|
|
.header-card__label { font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 8rpx; }
|
|
.header-card__amount { display: flex; align-items: baseline; margin-bottom: 28rpx; }
|
|
.header-card__currency { font-size: 36rpx; color: #fff; font-weight: 600; margin-right: 4rpx; }
|
|
.header-card__value { font-size: 72rpx; font-weight: 700; color: #fff; line-height: 1; }
|
|
|
|
.records-section {
|
|
margin: -16rpx 20rpx 0;
|
|
position: relative;
|
|
z-index: 2;
|
|
background: #fff;
|
|
border-radius: 24rpx;
|
|
padding: 0 0 20rpx;
|
|
overflow: hidden;
|
|
box-shadow: 0 4rpx 24rpx rgba(0,0,0,0.06);
|
|
}
|
|
.section-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 28rpx 30rpx 20rpx;
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
}
|
|
.section-header__bar {
|
|
width: 6rpx; height: 28rpx; border-radius: 3rpx;
|
|
background: var(--view-theme, #e93323); margin-right: 14rpx;
|
|
}
|
|
.section-header__title { font-size: 30rpx; font-weight: 600; color: #333; flex: 1; }
|
|
.section-header__more { font-size: 24rpx; color: var(--view-theme, #e93323); }
|
|
|
|
.loading-wrap {
|
|
display: flex; justify-content: center; align-items: center; gap: 12rpx;
|
|
padding: 60rpx 0;
|
|
}
|
|
.loading-dot {
|
|
width: 14rpx; height: 14rpx; border-radius: 50%;
|
|
background: var(--view-theme, #e93323);
|
|
animation: dot-bounce 1.2s infinite ease-in-out;
|
|
}
|
|
.loading-dot--2 { animation-delay: 0.2s; }
|
|
.loading-dot--3 { animation-delay: 0.4s; }
|
|
@keyframes dot-bounce {
|
|
0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
|
|
40% { opacity: 1; transform: scale(1.2); }
|
|
}
|
|
|
|
.empty-wrap { padding: 40rpx 0; }
|
|
|
|
.record-item {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 28rpx 30rpx;
|
|
border-bottom: 1rpx solid #f8f8f8;
|
|
}
|
|
.record-item__left { display: flex; align-items: center; gap: 20rpx; }
|
|
.record-item__avatar-wrap { width: 76rpx; height: 76rpx; border-radius: 50%; overflow: hidden; flex-shrink: 0; }
|
|
.record-item__avatar { width: 100%; height: 100%; }
|
|
.record-item__name { font-size: 28rpx; color: #333; font-weight: 500; display: block; }
|
|
.record-item__time { font-size: 22rpx; color: #999; display: block; margin-top: 6rpx; }
|
|
.record-item__right { text-align: right; }
|
|
.record-item__amount { font-size: 34rpx; font-weight: 700; color: #e93323; display: block; }
|
|
.record-item__type { font-size: 22rpx; color: #aaa; display: block; margin-top: 4rpx; }
|
|
|
|
.load-more { padding: 32rpx 0 20rpx; text-align: center; }
|
|
.load-more__text { font-size: 24rpx; color: #bbb; }
|
|
</style>
|