feat: 排行榜奖励展示、俱乐部分榜切换与手动领取
- 集团总榜/本俱乐部榜切换,奖金仅在本俱乐部榜行内展示 - 待领取底栏与规则说明,对接 phbjlxx/phbjllq/phbjlphb Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import { CLUB_ID } from '../../config/club-config.js'
|
||||
|
||||
const IS_XZJ = CLUB_ID === 'xzj'
|
||||
const RANK_API = IS_XZJ ? '/yonghu/xzjphbhqsj' : '/yonghu/phbhqsj'
|
||||
const CLOSED_DATES = ['昨日', '上周', '上月']
|
||||
|
||||
const ROLE_LIST = [
|
||||
{ key: 'dashou', label: '接单员' },
|
||||
@@ -145,6 +146,8 @@ Page({
|
||||
dateList: DATE_LIST,
|
||||
currentRole: 'dashou',
|
||||
currentDate: '今日',
|
||||
fanwei: 'jituan',
|
||||
myClubId: CLUB_ID || 'xq',
|
||||
roleMeta: ROLE_META.dashou,
|
||||
sortLabel: '分红总额',
|
||||
isLoading: true,
|
||||
@@ -153,6 +156,9 @@ Page({
|
||||
restList: [],
|
||||
isEmpty: false,
|
||||
defaultAvatar: '',
|
||||
rewardInfo: null,
|
||||
showClaimBar: false,
|
||||
claimLoading: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
@@ -239,6 +245,60 @@ Page({
|
||||
this.fetchRankList()
|
||||
},
|
||||
|
||||
onScopeTap(e) {
|
||||
const fanwei = e.currentTarget.dataset.fanwei
|
||||
if (!fanwei || fanwei === this.data.fanwei) return
|
||||
this.setData({ fanwei })
|
||||
this.fetchRankList()
|
||||
},
|
||||
|
||||
onShowRules() {
|
||||
const r = this.data.rewardInfo
|
||||
if (!r || !r.tiers || !r.tiers.length) {
|
||||
wx.showToast({ title: '暂无奖励规则', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const lines = r.tiers.map((t) => {
|
||||
const label = t.label || `第${t.rank_from}${t.rank_to > t.rank_from ? '-' + t.rank_to : ''}名`
|
||||
return `${label}:¥${t.amount}`
|
||||
})
|
||||
const tip = r.period_status === 'open' ? '(本期进行中,结束后可领取)' : ''
|
||||
wx.showModal({
|
||||
title: `${r.title || '排行榜奖励'}${tip}`,
|
||||
content: [
|
||||
`俱乐部:${r.club_id || this.data.myClubId}`,
|
||||
`排序:${r.sort_label || ''}`,
|
||||
...lines,
|
||||
r.description || '',
|
||||
].filter(Boolean).join('\n'),
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
|
||||
async onClaimTap() {
|
||||
const claim = this.data.rewardInfo && this.data.rewardInfo.my_claim
|
||||
if (!claim || !claim.claim_id || this.data.claimLoading) return
|
||||
this.setData({ claimLoading: true })
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/phbjllq',
|
||||
method: 'POST',
|
||||
data: { claim_id: claim.claim_id },
|
||||
})
|
||||
const body = res?.data || {}
|
||||
if (body.code === 200) {
|
||||
wx.showToast({ title: `已领取 ¥${claim.amount}`, icon: 'success' })
|
||||
await this.fetchRewardInfo()
|
||||
} else {
|
||||
wx.showToast({ title: body.msg || '领取失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '领取失败', icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ claimLoading: false })
|
||||
}
|
||||
},
|
||||
|
||||
onRefreshTap() {
|
||||
this.fetchRankList()
|
||||
},
|
||||
@@ -267,8 +327,8 @@ Page({
|
||||
value: m.type === 'money' ? this.formatMoney(v) : this.formatInt(v),
|
||||
}
|
||||
})
|
||||
const sortRaw = raw[meta.sortField]
|
||||
const mainType = meta.mainType || 'money'
|
||||
const sortRaw = raw[meta.sortField] ?? raw.metric_value
|
||||
const mainType = raw.metric_label ? (Number.isInteger(Number(sortRaw)) && !String(sortRaw).includes('.') ? 'int' : 'money') : (meta.mainType || 'money')
|
||||
const mainValue = mainType === 'money'
|
||||
? this.formatMoney(sortRaw)
|
||||
: this.formatInt(sortRaw)
|
||||
@@ -277,30 +337,101 @@ Page({
|
||||
uid,
|
||||
nicheng,
|
||||
avatar,
|
||||
clubName: raw.club_name || raw.club_id || '',
|
||||
rewardAmount: raw.reward_amount || 0,
|
||||
mainType,
|
||||
mainPrefix: mainType === 'money' ? '¥' : '',
|
||||
mainValue,
|
||||
mainLabel: meta.sortLabel,
|
||||
mainLabel: raw.metric_label || meta.sortLabel,
|
||||
metrics,
|
||||
}
|
||||
},
|
||||
|
||||
async fetchRankList() {
|
||||
this.setData({ isLoading: true, isEmpty: false })
|
||||
applyRewardToList(list, rewardInfo, fanwei) {
|
||||
if (fanwei !== 'club') return list
|
||||
if (!rewardInfo || !rewardInfo.rank_rewards) return list
|
||||
const map = rewardInfo.rank_rewards
|
||||
return list.map((item) => ({
|
||||
...item,
|
||||
rewardAmount: map[item.mingci] || item.rewardAmount || 0,
|
||||
}))
|
||||
},
|
||||
|
||||
async fetchRewardInfo() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: RANK_API,
|
||||
url: '/yonghu/phbjlxx',
|
||||
method: 'POST',
|
||||
data: { shenfen: this.data.currentRole, riqi: this.data.currentDate },
|
||||
data: {
|
||||
shenfen: this.data.currentRole,
|
||||
riqi: this.data.currentDate,
|
||||
club_id: this.data.myClubId,
|
||||
},
|
||||
})
|
||||
const body = res?.data || {}
|
||||
const ok = body.code === 200 || body.code === 0
|
||||
let list = ok && body.data
|
||||
? (body.data.list || body.data.paihang_list || body.data.rank_list || [])
|
||||
: []
|
||||
if (body.code !== 200 || !body.data) return
|
||||
const rewardInfo = body.data
|
||||
const showClaimBar = !!(rewardInfo.my_claim && rewardInfo.my_claim.status === 'pending')
|
||||
const { rankList, fanwei } = this.data
|
||||
const merged = this.applyRewardToList(rankList, rewardInfo, fanwei)
|
||||
this.setData({
|
||||
rewardInfo,
|
||||
showClaimBar,
|
||||
rankList: merged,
|
||||
topThree: merged.slice(0, 3),
|
||||
restList: merged.slice(3),
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn('奖励信息加载失败', e)
|
||||
}
|
||||
},
|
||||
|
||||
async fetchRankList() {
|
||||
this.setData({ isLoading: true, isEmpty: false, showClaimBar: false })
|
||||
try {
|
||||
const { currentRole, currentDate, fanwei, myClubId } = this.data
|
||||
let list = []
|
||||
let rewardFromRank = null
|
||||
|
||||
if (fanwei === 'club') {
|
||||
const res = await request({
|
||||
url: '/yonghu/phbjlphb',
|
||||
method: 'POST',
|
||||
data: {
|
||||
shenfen: currentRole,
|
||||
riqi: currentDate,
|
||||
fanwei: 'club',
|
||||
club_id: myClubId,
|
||||
},
|
||||
})
|
||||
const body = res?.data || {}
|
||||
if (body.code === 200 && body.data) {
|
||||
list = body.data.list || []
|
||||
rewardFromRank = body.data.reward || null
|
||||
if (body.data.sort_label) {
|
||||
this.setData({ sortLabel: body.data.sort_label })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const res = await request({
|
||||
url: RANK_API,
|
||||
method: 'POST',
|
||||
data: { shenfen: currentRole, riqi: currentDate },
|
||||
})
|
||||
const body = res?.data || {}
|
||||
const ok = body.code === 200 || body.code === 0
|
||||
list = ok && body.data
|
||||
? (body.data.list || body.data.paihang_list || body.data.rank_list || [])
|
||||
: []
|
||||
}
|
||||
|
||||
if (!Array.isArray(list)) list = []
|
||||
const role = this.data.currentRole
|
||||
const normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
||||
const role = currentRole
|
||||
let normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
||||
if (rewardFromRank) {
|
||||
normalized = this.applyRewardToList(normalized, rewardFromRank, 'club')
|
||||
this.setData({ rewardInfo: rewardFromRank, showClaimBar: !!(rewardFromRank.my_claim && rewardFromRank.my_claim.status === 'pending') })
|
||||
}
|
||||
this.setData({
|
||||
rankList: normalized,
|
||||
topThree: normalized.slice(0, 3),
|
||||
@@ -309,6 +440,9 @@ Page({
|
||||
isLoading: false,
|
||||
})
|
||||
this.ensureAvatars()
|
||||
if (!rewardFromRank) {
|
||||
await this.fetchRewardInfo()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('排行榜加载失败', e)
|
||||
wx.showToast({ title: '加载失败', icon: 'none' })
|
||||
|
||||
@@ -25,6 +25,22 @@
|
||||
>{{item.label}}</view>
|
||||
</view>
|
||||
<text class="sort-tip">{{currentDate}} · 按{{sortLabel}} · TOP50</text>
|
||||
|
||||
<view class="scope-row">
|
||||
<view class="scope-chip {{fanwei === 'jituan' ? 'on' : ''}}" data-fanwei="jituan" bindtap="onScopeTap">集团总榜</view>
|
||||
<view class="scope-chip {{fanwei === 'club' ? 'on' : ''}}" data-fanwei="club" bindtap="onScopeTap">本俱乐部榜</view>
|
||||
</view>
|
||||
|
||||
<view class="reward-banner" wx:if="{{rewardInfo && rewardInfo.scheme_enabled}}" bindtap="onShowRules">
|
||||
<view class="reward-banner-main">
|
||||
<text class="reward-tag">🏆 {{rewardInfo.title || '排行榜奖励'}}</text>
|
||||
<text class="reward-club">俱乐部 {{rewardInfo.club_id || myClubId}}</text>
|
||||
<text class="reward-status" wx:if="{{rewardInfo.period_status === 'open'}}">进行中 · 结束后可领</text>
|
||||
<text class="reward-status pending" wx:elif="{{rewardInfo.my_claim}}">待领取 ¥{{rewardInfo.my_claim.amount}}</text>
|
||||
<text class="reward-status claimed" wx:elif="{{rewardInfo.my_claimed}}">已领取 ¥{{rewardInfo.my_claimed.amount}}</text>
|
||||
</view>
|
||||
<text class="reward-link">规则 ›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="state-wrap" wx:if="{{isLoading}}">
|
||||
@@ -54,6 +70,7 @@
|
||||
<view class="p-amount">
|
||||
<text class="p-money">{{topThree[1].mainPrefix}}{{topThree[1].mainValue}}</text>
|
||||
<text class="p-label">{{topThree[1].mainLabel}}</text>
|
||||
<text class="p-reward" wx:if="{{topThree[1].rewardAmount > 0}}">奖 ¥{{topThree[1].rewardAmount}}</text>
|
||||
</view>
|
||||
<view class="p-metrics">
|
||||
<text class="p-metric" wx:for="{{topThree[1].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||
@@ -72,6 +89,7 @@
|
||||
<view class="p-amount">
|
||||
<text class="p-money p-money-first">{{topThree[0].mainPrefix}}{{topThree[0].mainValue}}</text>
|
||||
<text class="p-label">{{topThree[0].mainLabel}}</text>
|
||||
<text class="p-reward" wx:if="{{topThree[0].rewardAmount > 0}}">奖 ¥{{topThree[0].rewardAmount}}</text>
|
||||
</view>
|
||||
<view class="p-metrics">
|
||||
<text class="p-metric" wx:for="{{topThree[0].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||
@@ -90,6 +108,7 @@
|
||||
<view class="p-amount">
|
||||
<text class="p-money">{{topThree[2].mainPrefix}}{{topThree[2].mainValue}}</text>
|
||||
<text class="p-label">{{topThree[2].mainLabel}}</text>
|
||||
<text class="p-reward" wx:if="{{topThree[2].rewardAmount > 0}}">奖 ¥{{topThree[2].rewardAmount}}</text>
|
||||
</view>
|
||||
<view class="p-metrics">
|
||||
<text class="p-metric" wx:for="{{topThree[2].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||
@@ -114,7 +133,7 @@
|
||||
<image class="lc-avatar" src="{{item.avatar || defaultAvatar}}" mode="aspectFill" data-zone="rest" data-index="{{index}}" binderror="onAvatarError" />
|
||||
<view class="lc-info">
|
||||
<text class="lc-name">{{item.nicheng}}</text>
|
||||
<text class="lc-uid">ID {{item.uid}}</text>
|
||||
<text class="lc-uid">ID {{item.uid}}<text wx:if="{{item.clubName && fanwei === 'jituan'}}"> · {{item.clubName}}</text></text>
|
||||
<view class="lc-tags">
|
||||
<text class="lc-tag" wx:for="{{item.metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||
</view>
|
||||
@@ -122,6 +141,7 @@
|
||||
<view class="lc-score">
|
||||
<text class="lc-money">{{item.mainPrefix}}{{item.mainValue}}</text>
|
||||
<text class="lc-label">{{item.mainLabel}}</text>
|
||||
<text class="lc-reward" wx:if="{{item.rewardAmount > 0}}">奖¥{{item.rewardAmount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -129,6 +149,14 @@
|
||||
|
||||
<view class="bottom-gap"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="claim-bar" wx:if="{{showClaimBar && rewardInfo.my_claim}}">
|
||||
<view class="claim-text">
|
||||
<text class="claim-title">🎉 第{{rewardInfo.my_claim.mingci}}名 · 待领取</text>
|
||||
<text class="claim-amount">¥{{rewardInfo.my_claim.amount}}</text>
|
||||
</view>
|
||||
<button class="claim-btn" loading="{{claimLoading}}" bindtap="onClaimTap">立即领取</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
|
||||
@@ -107,8 +107,102 @@ page {
|
||||
}
|
||||
|
||||
.sort-tip {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: rgba(255,255,255,0.3);
|
||||
color: rgba(255,255,255,0.45);
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.scope-row {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.scope-chip {
|
||||
padding: 10rpx 24rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255,255,255,0.65);
|
||||
background: rgba(20, 26, 40, 0.75);
|
||||
border: 1rpx solid rgba(255,255,255,0.12);
|
||||
}
|
||||
|
||||
.scope-chip.on {
|
||||
color: #fff;
|
||||
background: rgba(255, 193, 7, 0.35);
|
||||
border-color: rgba(255, 193, 7, 0.5);
|
||||
}
|
||||
|
||||
.reward-banner {
|
||||
margin-top: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: linear-gradient(135deg, rgba(255,193,7,0.2), rgba(107,163,247,0.15));
|
||||
border: 1rpx solid rgba(255,193,7,0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.reward-banner-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.reward-tag { font-size: 28rpx; font-weight: 600; color: #ffd666; }
|
||||
.reward-club { font-size: 22rpx; color: rgba(255,255,255,0.7); }
|
||||
.reward-status { font-size: 22rpx; color: rgba(255,255,255,0.55); }
|
||||
.reward-status.pending { color: #52c41a; font-weight: 600; }
|
||||
.reward-status.claimed { color: #8c8c8c; }
|
||||
.reward-link { font-size: 24rpx; color: #8EB8FF; }
|
||||
|
||||
.p-reward {
|
||||
display: block;
|
||||
margin-top: 6rpx;
|
||||
font-size: 22rpx;
|
||||
color: #ffd666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.lc-reward {
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
font-size: 22rpx;
|
||||
color: #ffd666;
|
||||
}
|
||||
|
||||
.claim-bar {
|
||||
position: fixed;
|
||||
left: 0; right: 0; bottom: 0;
|
||||
z-index: 100;
|
||||
padding: 20rpx 28rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||
background: linear-gradient(180deg, rgba(13,17,23,0.2), rgba(13,17,23,0.95));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-top: 1rpx solid rgba(255,193,7,0.3);
|
||||
}
|
||||
|
||||
.claim-text { display: flex; flex-direction: column; }
|
||||
.claim-title { font-size: 26rpx; color: #fff; }
|
||||
.claim-amount { font-size: 36rpx; font-weight: 700; color: #ffd666; }
|
||||
|
||||
.claim-btn {
|
||||
margin: 0;
|
||||
padding: 0 40rpx;
|
||||
height: 72rpx;
|
||||
line-height: 72rpx;
|
||||
font-size: 28rpx;
|
||||
background: linear-gradient(135deg, #ffc107, #ff9800);
|
||||
color: #1a1a1a;
|
||||
border-radius: 999rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.bottom-gap {
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
/* ========== 状态 ========== */
|
||||
@@ -463,5 +557,3 @@ page {
|
||||
font-size: 20rpx;
|
||||
color: rgba(255,255,255,0.32);
|
||||
}
|
||||
|
||||
.bottom-gap { height: 48rpx; }
|
||||
|
||||
Reference in New Issue
Block a user