279 lines
7.9 KiB
JavaScript
279 lines
7.9 KiB
JavaScript
/**
|
||
* 排行榜 POST /yonghu/phbhqsj
|
||
* 参数: shenfen(dashou|guanshi|zuzhang|shangjia), riqi(今日|本周|本月|总榜|昨日|上周|上月)
|
||
*/
|
||
import request from '../../utils/request.js'
|
||
import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js'
|
||
|
||
const ROLE_LIST = [
|
||
{ key: 'dashou', label: '打手' },
|
||
{ key: 'guanshi', label: '管事' },
|
||
{ key: 'zuzhang', label: '组长' },
|
||
{ key: 'shangjia', label: '商家' },
|
||
]
|
||
|
||
const DATE_LIST = [
|
||
{ key: '今日', label: '今日' },
|
||
{ key: '本周', label: '本周' },
|
||
{ key: '本月', label: '本月' },
|
||
{ key: '总榜', label: '总榜' },
|
||
{ key: '昨日', label: '昨日' },
|
||
{ key: '上周', label: '上周' },
|
||
{ key: '上月', label: '上月' },
|
||
]
|
||
|
||
const ROLE_META = {
|
||
dashou: {
|
||
title: '打手排行榜',
|
||
sortField: 'chengjiao_zonge',
|
||
sortLabel: '分红总额',
|
||
metrics: [
|
||
{ field: 'jiedan_zongliang', label: '接单量', type: 'int' },
|
||
{ field: 'jiedan_zonge', label: '接单额', type: 'money' },
|
||
{ field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
|
||
],
|
||
},
|
||
guanshi: {
|
||
title: '管事排行榜',
|
||
sortField: 'shouru_zonge',
|
||
sortLabel: '收入总额',
|
||
metrics: [
|
||
{ field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' },
|
||
{ field: 'chongzhi_dashou_shu', label: '充值', type: 'int' },
|
||
],
|
||
},
|
||
zuzhang: {
|
||
title: '组长排行榜',
|
||
sortField: 'shouru_zonge',
|
||
sortLabel: '收入总额',
|
||
metrics: [
|
||
{ field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' },
|
||
{ field: 'fenyong_jine', label: '分佣', type: 'money' },
|
||
],
|
||
},
|
||
shangjia: {
|
||
title: '商家排行榜',
|
||
sortField: 'jiesuan_jine',
|
||
sortLabel: '成交总额',
|
||
metrics: [
|
||
{ field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' },
|
||
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
|
||
{ field: 'paifa_jine', label: '派单额', type: 'money' },
|
||
],
|
||
},
|
||
}
|
||
|
||
function isInvalidAvatarPath(path) {
|
||
if (path === null || path === undefined) return true
|
||
if (typeof path !== 'string') return true
|
||
const s = path.trim()
|
||
return !s || s === 'null' || s === 'undefined' || s === 'none'
|
||
}
|
||
|
||
function getDefaultAvatar(app) {
|
||
return getDefaultAvatarUrl(app)
|
||
}
|
||
|
||
function buildAvatar(path, app) {
|
||
app = app || getApp()
|
||
if (isInvalidAvatarPath(path)) return getDefaultAvatar(app)
|
||
return resolveAvatarUrl(path, app) || getDefaultAvatar(app)
|
||
}
|
||
|
||
Page({
|
||
data: {
|
||
imgUrls: {},
|
||
roleList: ROLE_LIST,
|
||
dateList: DATE_LIST,
|
||
currentRole: 'dashou',
|
||
currentDate: '今日',
|
||
roleMeta: ROLE_META.dashou,
|
||
sortLabel: '分红总额',
|
||
isLoading: true,
|
||
rankList: [],
|
||
topThree: [],
|
||
restList: [],
|
||
isEmpty: false,
|
||
defaultAvatar: '',
|
||
},
|
||
|
||
onLoad(options) {
|
||
const type = options.type || options.rankType || 'dashou'
|
||
const validRole = ROLE_META[type] ? type : 'dashou'
|
||
this.initPage()
|
||
this.applyRole(validRole, false)
|
||
this.fetchRankList()
|
||
},
|
||
|
||
onPullDownRefresh() {
|
||
this.fetchRankList().finally(() => wx.stopPullDownRefresh())
|
||
},
|
||
|
||
initPage() {
|
||
this.syncDefaultAvatar()
|
||
const g = getApp().globalData
|
||
const base = (g.ossImageUrl || '') + 'beijing/paihangbang/'
|
||
this.setData({
|
||
imgUrls: {
|
||
pageBg: base + 'page-bg.jpg',
|
||
cardBg: base + 'list-card-bg.png',
|
||
emptyIcon: base + 'empty.png',
|
||
refreshIcon: base + 'icon-refresh.png',
|
||
},
|
||
})
|
||
},
|
||
|
||
/** 与 app.js 一致:ossImageUrl + morentouxiang,配置异步加载后 onShow 再同步 */
|
||
syncDefaultAvatar() {
|
||
const def = getDefaultAvatar()
|
||
if (def && def !== this.data.defaultAvatar) {
|
||
this.setData({ defaultAvatar: def })
|
||
} else if (!this.data.defaultAvatar && def) {
|
||
this.setData({ defaultAvatar: def })
|
||
}
|
||
},
|
||
|
||
/** 配置晚于页面加载时,补全空头像 */
|
||
ensureAvatars() {
|
||
const def = getDefaultAvatar()
|
||
if (!def) return
|
||
const g = getApp().globalData
|
||
const oss = g.ossImageUrl || ''
|
||
const { rankList, topThree, restList } = this.data
|
||
if (!rankList.length) {
|
||
if (def !== this.data.defaultAvatar) this.setData({ defaultAvatar: def })
|
||
return
|
||
}
|
||
const isValidUrl = (url) => {
|
||
if (!url || typeof url !== 'string') return false
|
||
if (url.startsWith('http://') || url.startsWith('https://')) return true
|
||
return !!(oss && url.indexOf(oss) === 0)
|
||
}
|
||
const fix = (item) => ({
|
||
...item,
|
||
avatar: isValidUrl(item.avatar) ? item.avatar : def,
|
||
})
|
||
this.setData({
|
||
defaultAvatar: def,
|
||
rankList: rankList.map(fix),
|
||
topThree: topThree.map(fix),
|
||
restList: restList.map(fix),
|
||
})
|
||
},
|
||
|
||
applyRole(role, reload = true) {
|
||
const meta = ROLE_META[role]
|
||
wx.setNavigationBarTitle({ title: meta.title })
|
||
this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel })
|
||
if (reload) this.fetchRankList()
|
||
},
|
||
|
||
onRoleTap(e) {
|
||
const role = e.currentTarget.dataset.role
|
||
if (!role || role === this.data.currentRole) return
|
||
this.applyRole(role)
|
||
},
|
||
|
||
onDateTap(e) {
|
||
const date = e.currentTarget.dataset.date
|
||
if (!date || date === this.data.currentDate) return
|
||
this.setData({ currentDate: date })
|
||
this.fetchRankList()
|
||
},
|
||
|
||
onRefreshTap() {
|
||
this.fetchRankList()
|
||
},
|
||
|
||
formatMoney(val) {
|
||
const n = parseFloat(val)
|
||
return Number.isNaN(n) ? '0.00' : n.toFixed(2)
|
||
},
|
||
|
||
formatInt(val) {
|
||
const n = parseInt(val, 10)
|
||
return Number.isNaN(n) ? '0' : String(n)
|
||
},
|
||
|
||
normalizeItem(raw, index, role) {
|
||
const meta = ROLE_META[role]
|
||
const app = getApp()
|
||
const uid = raw.yonghuid || raw.uid || ''
|
||
const nicheng = raw.nicheng || raw.nick || '用户'
|
||
const def = getDefaultAvatar(app)
|
||
const avatar = buildAvatar(raw.touxiang || raw.avatar, app) || def
|
||
const metrics = meta.metrics.map((m) => {
|
||
const v = raw[m.field]
|
||
return {
|
||
label: m.label,
|
||
value: m.type === 'money' ? this.formatMoney(v) : this.formatInt(v),
|
||
}
|
||
})
|
||
return {
|
||
mingci: raw.mingci || index + 1,
|
||
uid,
|
||
nicheng,
|
||
avatar,
|
||
mainValue: this.formatMoney(raw[meta.sortField]),
|
||
mainLabel: meta.sortLabel,
|
||
metrics,
|
||
}
|
||
},
|
||
|
||
async fetchRankList() {
|
||
this.setData({ isLoading: true, isEmpty: false })
|
||
try {
|
||
const res = await request({
|
||
url: '/yonghu/phbhqsj',
|
||
method: 'POST',
|
||
data: { shenfen: this.data.currentRole, riqi: this.data.currentDate },
|
||
})
|
||
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 (!Array.isArray(list)) list = []
|
||
const role = this.data.currentRole
|
||
const normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
||
this.setData({
|
||
rankList: normalized,
|
||
topThree: normalized.slice(0, 3),
|
||
restList: normalized.slice(3),
|
||
isEmpty: normalized.length === 0,
|
||
isLoading: false,
|
||
})
|
||
this.ensureAvatars()
|
||
} catch (e) {
|
||
console.error('排行榜加载失败', e)
|
||
wx.showToast({ title: '加载失败', icon: 'none' })
|
||
this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false })
|
||
}
|
||
},
|
||
|
||
onAvatarError(e) {
|
||
const { zone, index } = e.currentTarget.dataset
|
||
const fallback = getDefaultAvatar()
|
||
if (!fallback) return
|
||
const key = zone === 'top' ? `topThree[${index}].avatar` : `restList[${index}].avatar`
|
||
this.setData({ [key]: fallback })
|
||
},
|
||
|
||
registerNotificationComponent() {
|
||
const app = getApp()
|
||
const comp = this.selectComponent('#global-notification')
|
||
if (comp?.showNotification) {
|
||
app.globalData.globalNotification = {
|
||
show: (d) => comp.showNotification(d),
|
||
hide: () => comp.hideNotification(),
|
||
}
|
||
}
|
||
},
|
||
|
||
onShow() {
|
||
this.syncDefaultAvatar()
|
||
this.ensureAvatars()
|
||
this.registerNotificationComponent()
|
||
},
|
||
})
|