Files
Neo-ZQYY/apps/miniprogram - 副本/miniprogram/pages/board-coach/board-coach.ts

264 lines
8.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 助教看板页 — 排序×技能×时间三重筛选4 种维度卡片
// TODO: 联调时替换 mock 数据为真实 API 调用
export {}
/** 排序维度 → 卡片模板映射 */
type DimType = 'perf' | 'salary' | 'sv' | 'task'
const SORT_TO_DIM: Record<string, DimType> = {
perf_desc: 'perf',
perf_asc: 'perf',
salary_desc: 'salary',
salary_asc: 'salary',
sv_desc: 'sv',
task_desc: 'task',
}
const SORT_OPTIONS = [
{ value: 'perf_desc', text: '定档业绩最高' },
{ value: 'perf_asc', text: '定档业绩最低' },
{ value: 'salary_desc', text: '工资最高' },
{ value: 'salary_asc', text: '工资最低' },
{ value: 'sv_desc', text: '客源储值最高' },
{ value: 'task_desc', text: '任务完成最多' },
]
const SKILL_OPTIONS = [
{ value: 'all', text: '不限' },
{ value: 'chinese', text: '🎱 中式/追分' },
{ value: 'snooker', text: '斯诺克' },
{ value: 'mahjong', text: '🀄 麻将/棋牌' },
{ value: 'karaoke', text: '🎤 团建/K歌' },
]
const TIME_OPTIONS = [
{ value: 'month', text: '本月' },
{ value: 'quarter', text: '本季度' },
{ value: 'last_month', text: '上月' },
{ value: 'last_3m', text: '前3个月(不含本月)' },
{ value: 'last_quarter', text: '上季度' },
{ value: 'last_6m', text: '最近6个月(不含本月,不支持客源储值最高)' },
]
/** 等级 → 样式类映射 */
const LEVEL_CLASS: Record<string, string> = {
'星级': 'level--star',
'高级': 'level--high',
'中级': 'level--mid',
'初级': 'level--low',
}
/** 技能 → 样式类映射 */
const SKILL_CLASS: Record<string, string> = {
'🎱': 'skill--chinese',
'斯': 'skill--snooker',
'🀄': 'skill--mahjong',
'🎤': 'skill--karaoke',
}
interface CoachItem {
id: string
name: string
initial: string
avatarGradient: string
level: string
levelClass: string
skills: Array<{ text: string; cls: string }>
topCustomers: string[]
// 定档业绩维度
perfHours: string
perfHoursBefore?: string
perfGap?: string
perfReached: boolean
// 工资维度
salary: string
salaryPerfHours: string
salaryPerfBefore?: string
// 客源储值维度
svAmount: string
svCustomerCount: string
svConsume: string
// 任务维度
taskRecall: string
taskCallback: string
}
/** Mock 数据(忠于 H5 原型 6 位助教) */
const MOCK_COACHES: CoachItem[] = [
{
id: 'c1', name: '小燕', initial: '小',
avatarGradient: 'avatar--blue',
level: '星级', levelClass: LEVEL_CLASS['星级'],
skills: [{ text: '🎱', cls: SKILL_CLASS['🎱'] }],
topCustomers: ['💖 王先生', '💖 李女士', '💛 赵总'],
perfHours: '86.2h', perfHoursBefore: '92.0h', perfGap: '距升档 13.8h', perfReached: false,
salary: '¥12,680', salaryPerfHours: '86.2h', salaryPerfBefore: '92.0h',
svAmount: '¥45,200', svCustomerCount: '18', svConsume: '¥8,600',
taskRecall: '18', taskCallback: '14',
},
{
id: 'c2', name: '泡芙', initial: '泡',
avatarGradient: 'avatar--green',
level: '高级', levelClass: LEVEL_CLASS['高级'],
skills: [{ text: '斯', cls: SKILL_CLASS['斯'] }],
topCustomers: ['💖 陈先生', '💛 刘女士', '💛 黄总'],
perfHours: '72.5h', perfHoursBefore: '78.0h', perfGap: '距升档 7.5h', perfReached: false,
salary: '¥10,200', salaryPerfHours: '72.5h', salaryPerfBefore: '78.0h',
svAmount: '¥38,600', svCustomerCount: '15', svConsume: '¥6,200',
taskRecall: '15', taskCallback: '13',
},
{
id: 'c3', name: 'Amy', initial: 'A',
avatarGradient: 'avatar--pink',
level: '星级', levelClass: LEVEL_CLASS['星级'],
skills: [{ text: '🎱', cls: SKILL_CLASS['🎱'] }, { text: '斯', cls: SKILL_CLASS['斯'] }],
topCustomers: ['💖 张先生', '💛 周女士', '💛 吴总'],
perfHours: '68.0h', perfHoursBefore: '72.5h', perfGap: '距升档 32.0h', perfReached: false,
salary: '¥9,800', salaryPerfHours: '68.0h', salaryPerfBefore: '72.5h',
svAmount: '¥32,100', svCustomerCount: '14', svConsume: '¥5,800',
taskRecall: '12', taskCallback: '13',
},
{
id: 'c4', name: 'Mia', initial: 'M',
avatarGradient: 'avatar--amber',
level: '中级', levelClass: LEVEL_CLASS['中级'],
skills: [{ text: '🀄', cls: SKILL_CLASS['🀄'] }],
topCustomers: ['💛 赵先生', '💛 吴女士', '💛 孙总'],
perfHours: '55.0h', perfGap: '距升档 5.0h', perfReached: false,
salary: '¥7,500', salaryPerfHours: '55.0h',
svAmount: '¥28,500', svCustomerCount: '12', svConsume: '¥4,100',
taskRecall: '10', taskCallback: '10',
},
{
id: 'c5', name: '糖糖', initial: '糖',
avatarGradient: 'avatar--purple',
level: '初级', levelClass: LEVEL_CLASS['初级'],
skills: [{ text: '🎱', cls: SKILL_CLASS['🎱'] }],
topCustomers: ['💛 钱先生', '💛 孙女士', '💛 周总'],
perfHours: '42.0h', perfHoursBefore: '45.0h', perfReached: true,
salary: '¥6,200', salaryPerfHours: '42.0h', salaryPerfBefore: '45.0h',
svAmount: '¥22,000', svCustomerCount: '10', svConsume: '¥3,500',
taskRecall: '8', taskCallback: '10',
},
{
id: 'c6', name: '露露', initial: '露',
avatarGradient: 'avatar--cyan',
level: '中级', levelClass: LEVEL_CLASS['中级'],
skills: [{ text: '🎤', cls: SKILL_CLASS['🎤'] }],
topCustomers: ['💛 郑先生', '💛 冯女士', '💛 陈总'],
perfHours: '38.0h', perfGap: '距升档 22.0h', perfReached: false,
salary: '¥5,100', salaryPerfHours: '38.0h',
svAmount: '¥18,300', svCustomerCount: '9', svConsume: '¥2,800',
taskRecall: '6', taskCallback: '9',
},
]
Page({
data: {
pageState: 'loading' as 'loading' | 'empty' | 'normal',
activeTab: 'coach' as 'finance' | 'customer' | 'coach',
selectedSort: 'perf_desc',
sortOptions: SORT_OPTIONS,
selectedSkill: 'all',
skillOptions: SKILL_OPTIONS,
selectedTime: 'month',
timeOptions: TIME_OPTIONS,
/** 当前维度类型,控制卡片模板 */
dimType: 'perf' as DimType,
coaches: [] as CoachItem[],
allCoaches: [] as CoachItem[],
/** 筛选栏可见性(滚动隐藏/显示) */
filterBarVisible: true,
},
_lastScrollTop: 0,
_scrollAcc: 0,
_scrollDir: null as 'up' | 'down' | null,
onLoad() {
this.loadData()
},
onPullDownRefresh() {
this.loadData()
setTimeout(() => wx.stopPullDownRefresh(), 500)
},
/** 滚动隐藏/显示筛选栏 */
onPageScroll(e: { scrollTop: number }) {
const y = e.scrollTop
const delta = y - this._lastScrollTop
this._lastScrollTop = y
if (y <= 8) {
if (!this.data.filterBarVisible) this.setData({ filterBarVisible: true })
this._scrollAcc = 0
this._scrollDir = null
return
}
if (Math.abs(delta) <= 2) return
const dir = delta > 0 ? 'down' : 'up'
if (dir !== this._scrollDir) {
this._scrollDir = dir
this._scrollAcc = 0
}
this._scrollAcc += Math.abs(delta)
const threshold = dir === 'up' ? 12 : 24
if (this._scrollAcc < threshold) return
const visible = dir === 'up'
if (this.data.filterBarVisible !== visible) {
this.setData({ filterBarVisible: visible })
}
this._scrollAcc = 0
},
loadData() {
this.setData({ pageState: 'loading' })
setTimeout(() => {
const data = MOCK_COACHES
if (!data || data.length === 0) {
this.setData({ pageState: 'empty' })
return
}
this.setData({ allCoaches: data, coaches: data, pageState: 'normal' })
}, 400)
},
onTabChange(e: WechatMiniprogram.TouchEvent) {
const tab = e.currentTarget.dataset.tab as string
if (tab === 'finance') {
wx.switchTab({ url: '/pages/board-finance/board-finance' })
} else if (tab === 'customer') {
wx.navigateTo({ url: '/pages/board-customer/board-customer' })
}
},
onSortChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
const val = e.detail.value
this.setData({
selectedSort: val,
dimType: SORT_TO_DIM[val] || 'perf',
})
},
onSkillChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
this.setData({ selectedSkill: e.detail.value })
},
onTimeChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
this.setData({ selectedTime: e.detail.value })
},
onCoachTap(e: WechatMiniprogram.TouchEvent) {
const id = e.currentTarget.dataset.id as string
wx.navigateTo({ url: '/pages/coach-detail/coach-detail?id=' + id })
},
})