// 助教看板页 — 排序×技能×时间三重筛选,4 种维度卡片 // TODO: 联调时替换 mock 数据为真实 API 调用 export {} /** 排序维度 → 卡片模板映射 */ type DimType = 'perf' | 'salary' | 'sv' | 'task' const SORT_TO_DIM: Record = { 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 = { '星级': 'level--star', '高级': 'level--high', '中级': 'level--mid', '初级': 'level--low', } /** 技能 → 样式类映射 */ const SKILL_CLASS: Record = { '🎱': '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 }) }, })