diff --git a/pages/accept-order/accept-order.js b/pages/accept-order/accept-order.js index 749dfe7..c23fe70 100644 --- a/pages/accept-order/accept-order.js +++ b/pages/accept-order/accept-order.js @@ -1,8 +1,14 @@ // pages/qiangdan/qiangdan.js const app = getApp(); import request from '../../utils/request.js'; +import { normalizeOrderTags } from '../../utils/order-tags.js'; +import { refreshDashouMembership, userHasHuiyuan } from '../../utils/dashou-profile.js'; +import { getDefaultAvatarUrl } from '../../utils/avatar.js'; +import { warmupPindaoConfig } from '../../utils/miniapp-icons.js'; import PopupService from '../../services/popupService.js'; import { reconnectForRole } from '../../utils/role-tab-bar.js'; +import { ensurePhoneAuth } from '../../utils/phone-auth.js'; +import { fetchGonggaoLunbo, isGonggaoCacheValid } from '../../utils/display-config.js'; Page({ data: { @@ -29,7 +35,7 @@ Page({ // 4. 刷新控制字段 scrollViewRefreshing: false, lastRefreshTime: 0, - refreshCooldown: 2000, + refreshCooldown: 0, isLoadingMore: false, // 5. 切换类型冷却 @@ -46,13 +52,59 @@ Page({ // 商品轮播展示(只读 globalData,无额外接口) lunboList: [], + gonggao: '', + + examRequired: false, + examPassed: false, + _examChecked: false, }, - async onLoad(options) { - this.syncShopBannerFromGlobal(); + async onLoad() { + if (app.globalData._acceptOrderSessionReady && app.globalData._acceptOrderPageCache) { + const cache = app.globalData._acceptOrderPageCache; + this.setData({ ...cache }); + if ((!cache.lunboList || cache.lunboList.length === 0) && !cache.gonggao && isGonggaoCacheValid(app)) { + const lunboList = this.processLunboUrls(app.globalData.shangpinlunbo); + const gonggao = app.globalData.shangpingonggao || ''; + this.setData({ lunboList, gonggao }); + this.persistPageCache({ lunboList, gonggao }); + } + this.loadGlobalStatus(); + this.registerNotificationComponent(); + await this.syncDashouProfileFromServer(); + this._skipShowRefresh = true; + return; + } + this.loadGlobalStatus(); - await this.loadShangpinLeixing(); - PopupService.checkAndShow(this, 'jiedan'); + const banner = await this.loadGonggaoAndLunbo(false); + await this.syncDashouProfileFromServer(); + await this.loadShangpinLeixing(true, false, false); + this.persistPageCache(banner); + app.globalData._acceptOrderSessionReady = true; + + if (!app.globalData._acceptOrderPopupDone) { + PopupService.checkAndShow(this, 'jiedan'); + app.globalData._acceptOrderPopupDone = true; + } + this._skipShowRefresh = true; + }, + + persistPageCache(extra = {}) { + const d = this.data; + app.globalData._acceptOrderPageCache = { + shangpinleixing: d.shangpinleixing, + xuanzhongLeixingId: d.xuanzhongLeixingId, + dingdanList: d.dingdanList, + page: d.page, + hasMore: d.hasMore, + bankuaiBiaoqian: d.bankuaiBiaoqian, + xuanzhongBiaoqianId: d.xuanzhongBiaoqianId, + lunboList: extra.lunboList ?? d.lunboList, + gonggao: extra.gonggao ?? d.gonggao, + lastRefreshTime: d.lastRefreshTime, + ossImageUrl: d.ossImageUrl, + }; }, onHide: function () { @@ -62,63 +114,84 @@ Page({ } }, - onShow() { - this.syncShopBannerFromGlobal(); + async onShow() { + if (!app.globalData._dashouPhoneChecked) { + const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' }); + if (!phoneOk) return; + app.globalData._dashouPhoneChecked = true; + } + this.registerNotificationComponent(); - this.loadGlobalStatus(); + await this.syncDashouProfileFromServer(); + warmupPindaoConfig(app); + if (wx.getStorageSync('uid')) { reconnectForRole('dashou'); if (app.startImWhenReady) app.startImWhenReady(); - this.refreshDashouProfileSilent(); } - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); + + await this.checkExamStatus(false); + + if (this._skipShowRefresh) { + this._skipShowRefresh = false; + return; + } + + if (app.globalData._acceptOrderSessionReady && !this._silentRefreshRunning) { + this._silentRefreshRunning = true; + this.silentRefreshOnShow().finally(() => { + this._silentRefreshRunning = false; + }); } }, - /** 同步点单端已加载的商品轮播图,仅展示用 */ - syncShopBannerFromGlobal() { - const oss = app.globalData.ossImageUrl || ''; - const lunboList = (app.globalData.shangpinlunbo || []).map((url) => { + /** 进入页面静默刷新(无 loading 遮罩、不清空列表) */ + async silentRefreshOnShow() { + try { + const banner = await this.loadGonggaoAndLunbo(true); + await this.syncDashouProfileFromServer(); + const leixingId = this.data.xuanzhongLeixingId; + if (leixingId) { + await this.loadDingdanList(true, true); + await this.loadBankuaiBiaoqian(); + } + this.loadGlobalStatus(); + this.persistPageCache(banner); + } catch (e) { + console.error('静默刷新失败:', e); + } + }, + + /** 公告 + 轮播(首次/下拉强制拉接口,其余读 globalData 或页面缓存) */ + processLunboUrls(urlList) { + const oss = app.globalData.ossImageUrl || this.data.ossImageUrl || ''; + return (urlList || []).map((url) => { if (!url) return ''; return url.startsWith('http') ? url : oss + url; }).filter(Boolean); - this.setData({ lunboList }); }, - async refreshDashouProfileSilent() { - try { - const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' }); - if (!res || res.data.code != 200) return; - const data = res.data.data || {}; - const patch = { - dashouNicheng: data.dashounicheng || '', - zhanghaoStatus: data.zhanghaostatus || '', - dashouzhuangtai: data.dashouzhuangtai || '', - yajin: data.yajin || 0, - jifen: data.jifen || 0, - clumber: data.clumber || [], - }; - Object.assign(app.globalData, { - dashouNicheng: patch.dashouNicheng, - zhanghaoStatus: patch.zhanghaoStatus, - dashouzhuangtai: patch.dashouzhuangtai, - yajin: patch.yajin, - jinfen: patch.jifen, - clumber: patch.clumber, - }); - if (data.dashoustatus !== undefined) { - wx.setStorageSync('dashoustatus', data.dashoustatus); - app.globalData.dashoustatus = data.dashoustatus; + async loadGonggaoAndLunbo(forceFetch = false) { + let lunboRaw = app.globalData.shangpinlunbo || []; + let gonggaoText = app.globalData.shangpingonggao || ''; + + if (forceFetch || !isGonggaoCacheValid(app)) { + try { + const data = await fetchGonggaoLunbo(app, 'accept_order'); + if (data) { + lunboRaw = data.shangpinlunbo || app.globalData.shangpinlunbo || []; + gonggaoText = data.shangpingonggao || app.globalData.shangpingonggao || ''; + } + } catch (e) { + lunboRaw = app.globalData.shangpinlunbo || []; + gonggaoText = app.globalData.shangpingonggao || ''; } - this.setData({ - zhuanghaoStatus: patch.zhanghaoStatus, - dashouzhuangtai: patch.dashouzhuangtai, - huiyuanList: patch.clumber, - yajin: patch.yajin, - jifen: patch.jifen, - }); - } catch (e) {} + } + + const lunboList = this.processLunboUrls(lunboRaw); + const gonggao = gonggaoText; + this.setData({ lunboList, gonggao }); + return { lunboList, gonggao }; }, registerNotificationComponent() { @@ -144,9 +217,22 @@ Page({ }); }, + /** 拉取最新打手信息(会员/押金/积分),并刷新订单卡片上的会员展示 */ + async syncDashouProfileFromServer() { + if (!wx.getStorageSync('token')) return; + await refreshDashouMembership(app); + this.loadGlobalStatus(); + if (this.data.dingdanList && this.data.dingdanList.length) { + this.setData({ + dingdanList: this.data.dingdanList.map((item) => this.processDingdanItem(item)), + }); + } + }, + // 加载商品类型 - async loadShangpinLeixing() { - wx.showLoading({ title: '加载商品类型...' }); + async loadShangpinLeixing(autoLoadOrders = false, preserveSelection = false, showLoading = true) { + if (showLoading) wx.showLoading({ title: '加载商品类型...' }); + const prevId = this.data.xuanzhongLeixingId; try { const res = await request({ url: '/dingdan/dsqdhqddlx', @@ -163,14 +249,16 @@ Page({ else if (Array.isArray(data)) list = data; } const processedList = this.processTupianUrl(list); + const firstId = processedList[0]?.id || null; + const keepPrev = preserveSelection && prevId && processedList.some((i) => i.id === prevId); + const selectedId = keepPrev ? prevId : firstId; this.setData({ shangpinleixing: processedList, - xuanzhongLeixingId: processedList[0]?.id || null + xuanzhongLeixingId: selectedId, }); - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - // 🆕 加载板块标签 - this.loadBankuaiBiaoqian(); + if (autoLoadOrders && selectedId) { + await this.loadDingdanList(true); + await this.loadBankuaiBiaoqian(); } } else { wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' }); @@ -178,7 +266,7 @@ Page({ } catch (error) { wx.showToast({ title: '网络错误,加载失败', icon: 'none' }); } finally { - wx.hideLoading(); + if (showLoading) wx.hideLoading(); } }, @@ -245,8 +333,8 @@ Page({ xuanzhongBiaoqianId: 0 // 重置标签筛选 }); await this.loadDingdanList(true); - // 🆕 切换类型后加载新标签 await this.loadBankuaiBiaoqian(); + this.persistPageCache(); } catch (error) { console.error('切换类型失败:', error); } finally { @@ -266,19 +354,24 @@ Page({ hasMore: true }); await this.loadDingdanList(true); + this.persistPageCache(); }, // 加载订单列表 - async loadDingdanList(isRefresh = false) { - if (this.data.isLoading || !this.data.xuanzhongLeixingId) return; + async loadDingdanList(isRefresh = false, silent = false) { + if ((!silent && this.data.isLoading) || !this.data.xuanzhongLeixingId) return; + if (silent && this._listRequesting) return; const loadPage = isRefresh ? 1 : this.data.page; if (!isRefresh && !this.data.hasMore) return; - this.setData({ - isLoading: true, - isLoadingMore: !isRefresh - }); + if (!silent) { + this.setData({ + isLoading: true, + isLoadingMore: !isRefresh, + }); + } + this._listRequesting = true; try { const res = await request({ @@ -298,6 +391,7 @@ Page({ isLoadingMore: false, scrollViewRefreshing: false }); + this._listRequesting = false; if (res.data.code === 200 || res.data.code === 0) { const newList = res.data.data.list || []; @@ -313,6 +407,7 @@ Page({ page: loadPage, hasMore: hasMore }); + this.persistPageCache(); if (isRefresh) { this.setData({ lastRefreshTime: Date.now() }); @@ -327,20 +422,28 @@ Page({ isLoadingMore: false, scrollViewRefreshing: false }); - wx.showToast({ title: '网络请求失败', icon: 'none' }); + this._listRequesting = false; + if (!silent) { + wx.showToast({ title: '网络请求失败', icon: 'none' }); + } } }, // 处理单条订单数据(包含标签、会员判断) processDingdanItem(item) { const ossUrl = app.globalData.ossImageUrl || ''; + const leixing = this.data.shangpinleixing.find((l) => l.id == item.leixing_id); let fullTupianUrl = ''; - if (item.tupian) { - fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; + // 卡片左上角优先用订单类型图,没有再退回默认图(不用商品图/头像顶替类型) + if (leixing && leixing.full_tupian_url) { + fullTupianUrl = leixing.full_tupian_url; + } else if (leixing && leixing.tupian_url) { + fullTupianUrl = leixing.tupian_url.startsWith('http') + ? leixing.tupian_url + : ossUrl + leixing.tupian_url; } else { - const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id); - fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png'; + fullTupianUrl = '/images/default-order.png'; } const isZhiding = item.zhuangtai === 7; @@ -353,25 +456,32 @@ Page({ } const zhidingNicheng = item.zhiding_nicheng || ''; - // 🆕 判断用户是否有订单所需的会员(仅当订单要求会员类型且存在huiyuan_id) + // 订单要求指定会员时,核对用户是否持有该会员类型 let hasRequiredMember = true; if (item.yaoqiuleixing == 1 && item.huiyuan_id) { - const userHasIt = this.data.huiyuanList.some(h => h.huiyuanid == item.huiyuan_id); - hasRequiredMember = userHasIt; + hasRequiredMember = userHasHuiyuan(this.data.huiyuanList, item.huiyuan_id); } + let shangjiaAvatar = getDefaultAvatarUrl(app); + const sjAvatar = (item.sj_avatar || '').trim(); + if (sjAvatar) { + shangjiaAvatar = sjAvatar.startsWith('http') ? sjAvatar : ossUrl + sjAvatar; + } + + const tags = normalizeOrderTags(item) + return { ...item, full_tupian_url: fullTupianUrl, + leixing_icon_url: fullTupianUrl, + shangjia_avatar_full: shangjiaAvatar, isZhiding: isZhiding, isPingtai: item.pingtai == 1, isShangjia: item.pingtai == 2, zhiding_avatar_full: zhidingAvatar, zhiding_nicheng: zhidingNicheng, - // 🆕 三层标签(后端返回,直接保留) - xuqiu_biaoqian: item.xuqiu_biaoqian || [], - dashou_biaoqian: item.dashou_biaoqian || [], - shangjia_biaoqian: item.shangjia_biaoqian || [], + ...tags, + shangjia_youzhi: !!item.shangjia_youzhi, // 🆕 是否有查看价格的权限 hasRequiredMember: hasRequiredMember, }; @@ -409,11 +519,50 @@ Page({ }); }, + /** 抢单前考试状态(仅更新状态,不自动跳转考试页) */ + async checkExamStatus() { + try { + const res = await request({ + url: '/jituan/dashou-exam/status', + method: 'POST', + header: { 'content-type': 'application/json' }, + }); + const body = res?.data; + if (body && (body.code === 200 || body.code === 0) && body.data) { + const d = body.data; + this.setData({ + examRequired: !!d.exam_required, + examPassed: !!d.exam_passed, + }); + } + } catch (e) { + console.error('考试状态检查失败', e); + } + return true; + }, + // 抢单按钮(原封不动) async onQiangdanTap(e) { const dingdanItem = e.currentTarget.dataset.item; if (!dingdanItem) return; + await this.checkExamStatus(); + + if (this.data.examRequired && !this.data.examPassed) { + wx.showModal({ + title: '须通过接单考试', + content: '抢单前需先通过接单考试,是否现在去考试?', + confirmText: '去考试', + cancelText: '暂不', + success: (r) => { + if (r.confirm) { + wx.navigateTo({ url: '/pages/dashou-exam/dashou-exam' }); + } + }, + }); + return; + } + // 校验1: 打手身份 if (!this.data.dashoustatus || this.data.dashoustatus != 1) { wx.showToast({ title: '请先开启接单员身份', icon: 'none' }); @@ -438,7 +587,7 @@ Page({ } // 校验5: 会员要求 if (dingdanItem.yaoqiuleixing == 1) { - const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); + const hasHuiyuan = userHasHuiyuan(this.data.huiyuanList, dingdanItem.huiyuan_id); if (!hasHuiyuan) { wx.showToast({ title: '未开通对应会员,无法抢单', @@ -504,6 +653,7 @@ Page({ item => item.dingdan_id !== dingdanItem.dingdan_id ); that.setData({ dingdanList: newList }); + that.persistPageCache(); } else { wx.showToast({ title: qiangdanRes.data.msg || '抢单失败', @@ -535,42 +685,14 @@ Page({ }, onReachBottom() { - const now = Date.now(); - const lastTime = this.data.lastRefreshTime; - const cooldown = this.data.refreshCooldown; - - if (now - lastTime < cooldown) { - wx.showToast({ - title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - if (this.data.isLoading || this.data.isLoadingMore) return; - if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) { this.setData({ page: this.data.page + 1 }); this.loadDingdanList(false); } }, - onPullDownRefresh() { - const now = Date.now(); - const lastTime = this.data.lastRefreshTime; - const cooldown = this.data.refreshCooldown; - - if (now - lastTime < cooldown) { - this.setData({ scrollViewRefreshing: false }); - wx.showToast({ - title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - + async onPullDownRefresh() { if (this.data.isLoading) { this.setData({ scrollViewRefreshing: false }); return; @@ -578,14 +700,25 @@ Page({ this.setData({ scrollViewRefreshing: true, - lastRefreshTime: now, + lastRefreshTime: Date.now(), page: 1, - hasMore: true + hasMore: true, }); - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - } else { + try { + const banner = await this.loadGonggaoAndLunbo(true); + await this.syncDashouProfileFromServer(); + await this.loadShangpinLeixing(false, true, false); + const leixingId = this.data.xuanzhongLeixingId; + if (leixingId) { + await this.loadBankuaiBiaoqian(); + await this.loadDingdanList(true); + } + this.loadGlobalStatus(); + this.persistPageCache(banner); + } catch (e) { + console.error('下拉刷新失败:', e); + } finally { this.setData({ scrollViewRefreshing: false }); } } diff --git a/pages/accept-order/accept-order.json b/pages/accept-order/accept-order.json index e7e7be0..d496762 100644 --- a/pages/accept-order/accept-order.json +++ b/pages/accept-order/accept-order.json @@ -1,6 +1,8 @@ { "navigationBarTitleText": "抢单大厅", "navigationBarBackgroundColor": "#f7dc51", + "backgroundColor": "#f7dc51", + "backgroundColorTop": "#f7dc51", "navigationBarTextStyle": "black", "enablePullDownRefresh": false, "backgroundTextStyle": "dark", diff --git a/pages/accept-order/accept-order.wxml b/pages/accept-order/accept-order.wxml index 389b531..4088337 100644 --- a/pages/accept-order/accept-order.wxml +++ b/pages/accept-order/accept-order.wxml @@ -1,4 +1,4 @@ - + @@ -38,6 +38,12 @@ + + + + {{gonggao}} + + @@ -74,7 +80,7 @@ - + @@ -190,16 +196,6 @@ - - - 指定 - - - - {{item.zhiding_nicheng || '指定接单员'}} - - - @@ -212,6 +208,20 @@ + + + + 指定 + + {{item.zhiding_nicheng || '指定接单员'}} + + + + + + + + @@ -226,9 +236,9 @@ - + - 备注:{{item.beizhu}} + 备注:{{item.beizhu || '暂无'}} @@ -236,10 +246,10 @@ 需求标签 - - - - + + + + @@ -260,6 +270,81 @@ + + + + + + + + + + + + + {{item.jieshao || '暂无介绍'}} + + 优质商家 + + + + + + + 指定 + + {{item.zhiding_nicheng || '指定接单员'}} + + + + + + + + + + {{item.dashou_fencheng || 0}} + + + 未开通会员 + + + 商家备注:{{item.beizhu || '暂无'}} + + + + + + + + + + + + + + + + + + + + + + + {{item.sjnicheng || '未知商家'}} + 发布于 {{item.creat_time}} + + + 抢单 + + + 商家派单 + + + + + @@ -276,19 +361,23 @@ - - - 指定 - - - - {{item.zhiding_nicheng || '指定接单员'}} - - + + + + 指定 + + {{item.zhiding_nicheng || '指定接单员'}} + + + + + + + - + {{item.sjnicheng || '未知商家'}} @@ -318,24 +407,33 @@ - + - 商家备注:{{item.beizhu}} + 商家备注:{{item.beizhu || '暂无'}} - + - - - + + + + - + - + + + + + + + + + diff --git a/pages/accept-order/accept-order.wxss b/pages/accept-order/accept-order.wxss index cecbb2b..394b5ff 100644 --- a/pages/accept-order/accept-order.wxss +++ b/pages/accept-order/accept-order.wxss @@ -1,5 +1,11 @@ -/* pages/qiangdan/qiangdan.wxss - 高级机甲风格重构版(对称优化) */ +/* pages/qiangdan/qiangdan.wxss - 逍遥梦抢单页 */ @import '../../styles/dashou-xym-theme.wxss'; +@import '../../styles/dashou-xym-order-card.wxss'; + +page { + background-color: #f7dc51; +} + .qiangdan-page { height: 100vh; display: flex; @@ -126,6 +132,7 @@ flex: 1; height: 0; -webkit-overflow-scrolling: touch; + background: transparent; } .scroll-bottom-spacer { @@ -763,5 +770,3 @@ margin-left: auto; max-width: 50%; } - -@import '../../styles/dashou-xym-order-card.wxss'; diff --git a/pages/fighter-order-detail/fighter-order-detail.js b/pages/fighter-order-detail/fighter-order-detail.js index 1703829..0051b27 100644 --- a/pages/fighter-order-detail/fighter-order-detail.js +++ b/pages/fighter-order-detail/fighter-order-detail.js @@ -1,741 +1,741 @@ -// pages/fighter-order-detail/fighter-order-detail.js - 【最终版:提交前公告弹窗 + 修改图片至少保留一张】 -const app = getApp() -import request from '../../utils/request.js' -const COS = require('../../utils/cos-wx-sdk-v5.js') - -Page({ - data: { - jibenShuju: { - dingdan_id: '', - tupian: '', - jieshao: '', - create_time: '', - jine: '', - nicheng: '', - beizhu: '', - zhuangtai: 0, - fadanpingtai: 0 - }, - xiangxiShuju: { - shangjia_id: '', - shangjia_nicheng: '', - shangjia_liuyan: '', - tuikuan_liyou: '', - chufa_liyou: '', - chufa_zhuangtai: 0, - chufa_jieguo: '', - bohui_liyou: '', - dashou_jiaofu: [], - dashou_liuyan: '', - laoban_id: '' - }, - zhuangtaiYanseMap: { - 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0', - 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1' - }, - zhuangtaiWenziMap: { - 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中', - 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中' - }, - isLoading: true, - isSubmitting: false, - liuyan: '', - xuanzhongTupian: [], - shangchuanJindu: 0, - shangchuanZongshu: 0, - jinduWidth: '0%', - showWanzhengJieshao: false, - wanzhengJieshao: '', - showWanzhengBeizhu: false, - wanzhengBeizhu: '', - ossImageUrl: '', - morentouxiang: '', - showRefundInfo: false, - - // 修改功能所需字段 - isModifying: false, - originalDashouJiaofu: [], - originalDashouLiuyan: '', - remainingOriginals: [], - modifiedLiuyan: '', - deletedImages: [], - newImages: [], - isConfirming: false, - modifyUploadProgress: { total: 0, current: 0, width: '0%' } - }, - - onLoad(options) { - wx.setNavigationBarTitle({ title: '订单详情' }) - this.initGlobalData() - this.jiexiTiaozhuanCanshu(options) - }, - onHide() { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } - }, - - onShow() { - this.registerNotificationComponent(); - }, - - registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - initGlobalData() { - const app = getApp() - const ossImageUrl = app.globalData.ossImageUrl || 'https://your-oss-domain.com/' - const morentouxiang = app.globalData.morentouxiang || '/images/default-avatar.png' - this.setData({ ossImageUrl, morentouxiang }) - }, - - jiexiTiaozhuanCanshu(options) { - try { - const dingdanDataStr = options.dingdanData || '' - if (!dingdanDataStr) { - wx.showToast({ title: '订单数据错误', icon: 'none' }) - setTimeout(() => wx.navigateBack(), 1500) - return - } - const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr)) - let tupianUrl = dingdanData.tupian || '' - if (!tupianUrl) tupianUrl = this.getTupianUrl() - let jine = parseFloat(dingdanData.jine || 0) - if (isNaN(jine)) jine = 0 - const formattedJine = jine.toFixed(2) - this.setData({ - 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '', - 'jibenShuju.tupian': tupianUrl, - 'jibenShuju.jieshao': dingdanData.jieshao || '', - 'jibenShuju.create_time': dingdanData.create_time || '', - 'jibenShuju.jine': formattedJine, - 'jibenShuju.nicheng': dingdanData.nicheng || '', - 'jibenShuju.beizhu': dingdanData.beizhu || '', - 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0, - 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0, - isLoading: false - }) - this.jiazaiXiangxiShuju(dingdanData.dingdan_id) - } catch (error) { - console.error('解析订单数据失败:', error) - wx.showToast({ title: '数据解析失败', icon: 'none' }) - setTimeout(() => wx.navigateBack(), 1500) - } - }, - - getTupianUrl() { - const cacheTouxiang = wx.getStorageSync('touxiang') || '' - let tupianPath = cacheTouxiang || app.globalData.morentouxiang || '' - const ossImageUrl = app.globalData.ossImageUrl || '' - if (tupianPath && ossImageUrl) { - if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1) - return ossImageUrl + tupianPath - } - return '' - }, - - async jiazaiXiangxiShuju(dingdanId) { - if (!dingdanId) return - wx.showLoading({ title: '加载中...', mask: true }) - try { - const res = await request({ - url: '/dingdan/dsddxq', - method: 'POST', - data: { dingdan_id: dingdanId }, - header: { 'content-type': 'application/json' } - }) - wx.hideLoading() - if (res && res.data.code === 0 && res.data.data) { - const data = res.data.data - let dashouJiaofuList = data.dashou_jiaofu || [] - dashouJiaofuList = dashouJiaofuList.map(imgUrl => { - if (imgUrl && !imgUrl.startsWith('http')) { - const ossImageUrl = app.globalData.ossImageUrl || '' - if (imgUrl.startsWith('/')) imgUrl = imgUrl.substring(1) - return ossImageUrl + imgUrl - } - return imgUrl - }) - this.setData({ - 'xiangxiShuju.shangjia_id': data.shangjia_id || '', - 'xiangxiShuju.shangjia_nicheng': data.shangjia_nicheng || '', - 'xiangxiShuju.shangjia_liuyan': data.shangjia_liuyan || '', - 'xiangxiShuju.tuikuan_liyou': data.tuikuan_liyou || '', - 'xiangxiShuju.chufa_liyou': data.chufa_liyou || '', - 'xiangxiShuju.chufa_zhuangtai': data.chufa_zhuangtai || 0, - 'xiangxiShuju.chufa_jieguo': data.chufa_jieguo || '', - 'xiangxiShuju.bohui_liyou': data.bohui_liyou || '', - 'xiangxiShuju.dashou_jiaofu': dashouJiaofuList, - 'xiangxiShuju.dashou_liuyan': data.dashou_liuyan || '', - 'xiangxiShuju.laoban_id': data.laoban_id || '', - 'jibenShuju.zhuangtai': data.zhuangtai || 0, - 'jibenShuju.beizhu': data.beizhu || '', - 'liuyan': data.dashou_liuyan || '', - 'jibenShuju.fadanpingtai': data.fadanpingtai || 0 - }) - const currentStatus = data.zhuangtai || 0 - const showRefund = [4,5,6].includes(currentStatus) - this.setData({ showRefundInfo: showRefund }) - } else { - const errorMsg = res?.data?.msg || '获取订单详情失败' - wx.showToast({ title: errorMsg, icon: 'none', duration: 2000 }) - } - } catch (error) { - console.error('加载详细数据失败:', error) - wx.hideLoading() - wx.showToast({ title: '加载数据失败,请重试', icon: 'none', duration: 2000 }) - } - }, - - // ========== 原有提交功能(部分修改) ========== - xuanzeTupian() { - if (this.data.isSubmitting) return - const shengyu = 9 - this.data.xuanzhongTupian.length - if (shengyu <= 0) { - wx.showToast({ title: '最多只能选择9张图片', icon: 'none' }) - return - } - wx.chooseImage({ - count: shengyu, - sizeType: ['compressed'], - sourceType: ['album', 'camera'], - success: (res) => { - const newTupian = [...this.data.xuanzhongTupian, ...res.tempFilePaths] - this.setData({ xuanzhongTupian: newTupian.slice(0, 9) }) - } - }) - }, - shanchuTupian(e) { - const index = e.currentTarget.dataset.index - const newTupian = [...this.data.xuanzhongTupian] - newTupian.splice(index, 1) - this.setData({ xuanzhongTupian: newTupian }) - }, - yulanTupian(e) { - const currentUrl = e.currentTarget.dataset.url - const urls = e.currentTarget.dataset.urls || [] - if (!currentUrl) return - wx.previewImage({ current: currentUrl, urls: urls.length > 0 ? urls : [currentUrl] }) - }, - getFileExtension(filePath) { - const lastDotIndex = filePath.lastIndexOf('.') - if (lastDotIndex === -1) return '.jpg' - const ext = filePath.substring(lastDotIndex).toLowerCase() - const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'] - return allowedExts.includes(ext) ? ext : '.jpg' - }, - shuruLiuyan(e) { - const liuyan = e.detail.value.slice(0, 50) - this.setData({ liuyan }) - }, - chakanWanzhengJieshao() { - this.setData({ showWanzhengJieshao: true, wanzhengJieshao: this.data.jibenShuju.jieshao || '无' }) - }, - guanbiWanzhengJieshao() { this.setData({ showWanzhengJieshao: false }) }, - chakanWanzhengBeizhu() { - this.setData({ showWanzhengBeizhu: true, wanzhengBeizhu: this.data.jibenShuju.beizhu || '无' }) - }, - guanbiWanzhengBeizhu() { this.setData({ showWanzhengBeizhu: false }) }, - async fuzhiWenben(e) { - const text = e.currentTarget.dataset.text - if (!text) return - try { - await wx.setClipboardData({ data: text }) - wx.showToast({ title: '复制成功', icon: 'success', duration: 1500 }) - } catch (error) { - console.error('复制失败:', error) - wx.showToast({ title: '复制失败', icon: 'none' }) - } - }, - goToKefu() { - const kefuLink = app.globalData.kefuConfig?.link || ''; - const corpId = app.globalData.kefuConfig?.enterpriseId || ''; - - if (!kefuLink || !corpId) { - wx.showToast({ - title: '客服配置未加载', - icon: 'none' - }); - return; - } - - wx.openCustomerServiceChat({ - extInfo: { url: kefuLink }, - corpId: corpId, - success: (res) => { - console.log('跳转客服成功', res); - }, - fail: (err) => { - console.error('跳转客服失败', err); - wx.showToast({ - title: '暂时无法连接客服', - icon: 'none' - }); - } - }); - }, - - // ===== 联系老板(订单群 groupId 即订单号,与商家端 sjddxq 一致) ===== - goToChatWithBoss() { - const uid = wx.getStorageSync('uid') - if (!uid) { - wx.showToast({ title: '用户信息缺失', icon: 'none' }) - return - } - - const orderId = this.data.jibenShuju.dingdan_id - if (!orderId) { - wx.showToast({ title: '订单ID缺失', icon: 'none' }) - return - } - - const targetUserId = 'Ds' + uid - const connected = wx.goEasy && wx.goEasy.getConnectionStatus && wx.goEasy.getConnectionStatus() === 'connected' - const currentUserId = wx.goEasy?.im?.userId - if (!connected || currentUserId !== targetUserId) { - if (app.ensureConnection) app.ensureConnection() - wx.showToast({ title: '连接中,请稍后再试', icon: 'none' }) - return - } - - const orderIdStr = String(orderId) - const groupName = (this.data.jibenShuju.nicheng || '订单') + '的订单群' - const isCross = this.data.jibenShuju.fadanpingtai || 0 - - wx.goEasy.im.subscribeGroup({ - groupIds: [orderIdStr], - onSuccess: () => { - const param = { - groupId: orderIdStr, - orderId: orderIdStr, - groupName, - groupAvatar: '', - isCross, - } - wx.navigateTo({ - url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)), - }) - }, - onFailed: (err) => { - console.error('订阅群组失败', err) - wx.showToast({ title: '连接群聊失败', icon: 'none' }) - }, - }) - }, - - async getCOSZhengshu() { - try { - const res = await request({ - url: '/dingdan/dsscpz', - method: 'POST', - data: { dingdan_id: this.data.jibenShuju.dingdan_id } - }) - if (res && res.data.code === 0 && res.data.data) return res.data.data - else throw new Error(res?.data?.msg || '获取上传凭证失败') - } catch (error) { - console.error('获取COS凭证失败:', error) - throw error - } - }, - - initCOSClient(tokenData) { - const credentials = tokenData.credentials || tokenData - const bucket = tokenData.bucket || 'julebu-1361527063' - const region = tokenData.region || 'ap-shanghai' - const cos = new COS({ - SimpleUploadMethod: 'putObject', - getAuthorization: async (options, callback) => { - const authParams = { - TmpSecretId: credentials.tmpSecretId, - TmpSecretKey: credentials.tmpSecretKey, - SecurityToken: credentials.sessionToken || '', - StartTime: tokenData.startTime || Math.floor(Date.now() / 1000), - ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200) - } - callback(authParams) - } - }) - return { cos, bucket, region } - }, - - async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) { - return new Promise((resolve) => { - const timeoutId = setTimeout(() => resolve({ status: 'optimistic_success', key: cosKey }), 2000) - cosInstance.uploadFile({ - Bucket: bucket, - Region: region, - Key: cosKey, - FilePath: filePath, - onProgress: (progressInfo) => { - const percent = Math.round(progressInfo.percent * 100) - if (percent === 100) { - clearTimeout(timeoutId) - resolve({ status: 'optimistic_success', key: cosKey }) - } - } - }) - }) - }, - - async piliangShangchuanTupian() { - const total = this.data.xuanzhongTupian.length - this.setData({ shangchuanZongshu: total, shangchuanJindu: 0, jinduWidth: '0%' }) - wx.showLoading({ title: '正在准备...', mask: true }) - const preGeneratedUrls = [] - for (let i = 0; i < total; i++) { - const timestamp = Date.now() + i - const random = Math.floor(Math.random() * 10000) - const fileExt = this.getFileExtension(this.data.xuanzhongTupian[i]) - const fileName = `${timestamp}_${random}${fileExt}` - const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}` - preGeneratedUrls.push(cosKey) - } - let cosClient, bucket, region - try { - const tokenData = await this.getCOSZhengshu() - const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData) - cosClient = cos - bucket = cosBucket - region = cosRegion - } catch (error) { - wx.hideLoading() - wx.showToast({ title: '上传初始化失败', icon: 'none' }) - return [] - } - const uploadTasks = [] - for (let i = 0; i < total; i++) { - const task = this.shangchuanDanZhangTupian( - this.data.xuanzhongTupian[i], - preGeneratedUrls[i], - i, - cosClient, - bucket, - region - ).then((result) => { - const currentDone = i + 1 - const jinduPercent = ((currentDone / total) * 100).toFixed(0) - this.setData({ shangchuanJindu: currentDone, jinduWidth: `${jinduPercent}%` }) - return result - }) - uploadTasks.push(task) - } - wx.showLoading({ title: `上传中...`, mask: true }) - await Promise.all(uploadTasks) - wx.hideLoading() - return preGeneratedUrls - }, - - tijiaoDingdan() { - this.showAnnouncementAndConfirm() - }, - - async showAnnouncementAndConfirm() { - try { - const res = await request({ - url: '/peizhi/tanchuang', - method: 'POST', - data: { pageKey: 'dsddxq' } - }) - if (res.statusCode !== 200 || res.data.code !== 0) { - this.showOriginalConfirmAndSubmit() - return - } - const { popups = [], serverTime } = res.data.data - if (!popups.length) { - this.showOriginalConfirmAndSubmit() - return - } - const popup = popups[0] - const popupComp = this.selectComponent('#popupNotice') - if (!popupComp) { - console.error('未找到弹窗组件 #popupNotice') - this.showOriginalConfirmAndSubmit() - return - } - const showData = { - popupId: popup.popup_id, - title: popup.title || '', - duration: popup.duration || 0, - images: popup.images || [], - showMuteCheckbox: false, - serverTime: serverTime - } - popupComp.show(showData, (result) => { - this.showOriginalConfirmAndSubmit() - }) - } catch (error) { - console.error('获取公告配置失败', error) - this.showOriginalConfirmAndSubmit() - } - }, - - showOriginalConfirmAndSubmit() { - if (this.data.isSubmitting) { - wx.showToast({ title: '正在提交中', icon: 'none' }) - return - } - if (this.data.jibenShuju.zhuangtai !== 2) { - wx.showToast({ title: '订单状态不可提交', icon: 'none' }) - return - } - if (this.data.xuanzhongTupian.length === 0) { - wx.showToast({ title: '请至少上传一张图片', icon: 'none' }) - return - } - wx.showModal({ - title: '⚠️ 提交确认', - content: '在提交订单之前,请确保您已在接单员端页面认真阅读接单员规则。如有漏交图片,订单被退款,概不申诉。', - confirmText: '我已阅读', - cancelText: '我再想想', - success: (res) => { - if (res.confirm) this._doSubmit() - }, - fail: (err) => { - console.error('弹窗失败', err) - wx.showToast({ title: '系统异常,请重试', icon: 'none' }) - } - }) - }, - - async _doSubmit() { - this.setData({ isSubmitting: true }) - wx.showLoading({ title: '开始提交...', mask: true }) - try { - const tupianUrls = await this.piliangShangchuanTupian() - if (!tupianUrls || tupianUrls.length === 0) throw new Error('无法生成上传路径') - wx.showLoading({ title: '提交订单数据...', mask: true }) - const res = await request({ - url: '/dingdan/dstijiao', - method: 'POST', - data: { - dingdan_id: this.data.jibenShuju.dingdan_id, - liuyan: this.data.liuyan || '', - jiaofu_tupian_urls: tupianUrls - }, - header: { 'content-type': 'application/json' } - }) - wx.hideLoading() - this.setData({ isSubmitting: false }) - if (res && res.data.code === 0) { - const ossImageUrl = app.globalData.ossImageUrl || '' - const fullUrls = tupianUrls.map(url => { - if (url && !url.startsWith('http')) { - if (url.startsWith('/')) url = url.substring(1) - return ossImageUrl + url - } - return url - }) - this.setData({ - 'jibenShuju.zhuangtai': 8, - 'xiangxiShuju.dashou_liuyan': this.data.liuyan || '', - 'xiangxiShuju.dashou_jiaofu': fullUrls, - xuanzhongTupian: [], - liuyan: '', - shangchuanJindu: 0, - shangchuanZongshu: 0, - jinduWidth: '0%', - }) - if (app.globalData.dashouzhuangtai != 1) app.globalData.dashouzhuangtai = 1 - wx.showToast({ title: '提交成功!', icon: 'success', duration: 2000 }) - setTimeout(() => wx.navigateBack(), 1500) - } else { - const errorMsg = res?.data?.msg || '提交失败' - wx.showToast({ title: errorMsg, icon: 'none' }) - } - } catch (error) { - console.error('提交失败:', error) - wx.hideLoading() - this.setData({ isSubmitting: false }) - wx.showToast({ title: error.message || '提交失败', icon: 'none' }) - } - }, - - // ========== 修改功能(增加最少一张图片校验) ========== - extractRelativePath(fullUrl) { - const ossImageUrl = this.data.ossImageUrl - if (fullUrl.startsWith(ossImageUrl)) return fullUrl.substring(ossImageUrl.length) - return fullUrl - }, - enterModify() { - const { dashou_jiaofu, dashou_liuyan } = this.data.xiangxiShuju - this.setData({ - isModifying: true, - originalDashouJiaofu: dashou_jiaofu.slice(), - remainingOriginals: dashou_jiaofu.slice(), - originalDashouLiuyan: dashou_liuyan || '', - modifiedLiuyan: dashou_liuyan || '', - deletedImages: [], - newImages: [] - }) - }, - cancelModify() { - this.setData({ - isModifying: false, - originalDashouJiaofu: [], - remainingOriginals: [], - originalDashouLiuyan: '', - modifiedLiuyan: '', - deletedImages: [], - newImages: [] - }) - }, - handleDeleteImage(e) { - const fullUrl = e.currentTarget.dataset.url - const { originalDashouJiaofu, remainingOriginals, deletedImages, newImages } = this.data - if (originalDashouJiaofu.includes(fullUrl)) { - const newRemaining = remainingOriginals.filter(url => url !== fullUrl) - this.setData({ - remainingOriginals: newRemaining, - deletedImages: [...deletedImages, fullUrl] - }) - } else { - const index = newImages.indexOf(fullUrl) - if (index > -1) { - const newImagesCopy = [...newImages] - newImagesCopy.splice(index, 1) - this.setData({ newImages: newImagesCopy }) - } - } - }, - handleAddImage() { - if (this.data.isConfirming) return - const currentCount = this.getCurrentImageCount() - const maxCount = 9 - currentCount - if (maxCount <= 0) { - wx.showToast({ title: '最多9张图片', icon: 'none' }) - return - } - wx.chooseImage({ - count: maxCount, - sizeType: ['compressed'], - sourceType: ['album', 'camera'], - success: (res) => { - const newImages = [...this.data.newImages, ...res.tempFilePaths] - this.setData({ newImages: newImages.slice(0, 9) }) - } - }) - }, - getCurrentImageCount() { - const { remainingOriginals, newImages } = this.data - return remainingOriginals.length + newImages.length - }, - onModifyLiuyanInput(e) { - this.setData({ modifiedLiuyan: e.detail.value.slice(0, 50) }) - }, - - async confirmModify() { - if (this.data.isConfirming) return - const { dingdan_id } = this.data.jibenShuju - const { remainingOriginals, deletedImages, newImages, modifiedLiuyan, originalDashouLiuyan } = this.data - const hasLiuyanChange = modifiedLiuyan !== originalDashouLiuyan - const hasDelete = deletedImages.length > 0 - const hasAdd = newImages.length > 0 - - if (!hasLiuyanChange && !hasDelete && !hasAdd) { - wx.showToast({ title: '没有修改内容', icon: 'none' }) - return - } - - const finalImageCount = remainingOriginals.length + newImages.length - if (finalImageCount === 0) { - wx.showToast({ title: '至少保留一张图片', icon: 'none' }) - return - } - - this.setData({ isConfirming: true }) - wx.showLoading({ title: '提交修改...', mask: true }) - try { - const tokenData = await this.getCOSZhengshu() - const { cos, bucket, region } = this.initCOSClient(tokenData) - - let newImageRelativePaths = [] - if (hasAdd) { - const total = newImages.length - this.setData({ 'modifyUploadProgress.total': total, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' }) - const preGeneratedKeys = [] - for (let i = 0; i < total; i++) { - const timestamp = Date.now() + i - const random = Math.floor(Math.random() * 10000) - const fileExt = this.getFileExtension(newImages[i]) - const fileName = `${timestamp}_${random}${fileExt}` - const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}` - preGeneratedKeys.push(cosKey) - } - const uploadTasks = [] - for (let i = 0; i < total; i++) { - const task = this.shangchuanDanZhangTupian( - newImages[i], - preGeneratedKeys[i], - i, - cos, - bucket, - region - ).then((result) => { - const currentDone = i + 1 - const jinduPercent = ((currentDone / total) * 100).toFixed(0) - this.setData({ - 'modifyUploadProgress.current': currentDone, - 'modifyUploadProgress.width': `${jinduPercent}%` - }) - return result.key - }) - uploadTasks.push(task) - } - wx.showLoading({ title: `上传中...`, mask: true }) - newImageRelativePaths = await Promise.all(uploadTasks) - wx.hideLoading() - this.setData({ 'modifyUploadProgress.total': 0, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' }) - } - - const deletedRelativePaths = deletedImages.map(fullUrl => this.extractRelativePath(fullUrl)) - - const res = await request({ - url: '/dingdan/dsxiugaidd', - method: 'POST', - data: { - dingdan_id, - liuyan: modifiedLiuyan, - deleted_images: deletedRelativePaths, - new_images: newImageRelativePaths - }, - header: { 'content-type': 'application/json' } - }) - wx.hideLoading() - this.setData({ isConfirming: false }) - if (res && res.data.code === 0) { - const ossImageUrl = this.data.ossImageUrl - const newFullUrls = newImageRelativePaths.map(rel => ossImageUrl + rel) - const newDashouJiaofu = [...remainingOriginals, ...newFullUrls] - this.setData({ - 'xiangxiShuju.dashou_jiaofu': newDashouJiaofu, - 'xiangxiShuju.dashou_liuyan': modifiedLiuyan, - isModifying: false, - originalDashouJiaofu: [], - remainingOriginals: [], - originalDashouLiuyan: '', - deletedImages: [], - newImages: [], - modifiedLiuyan: '' - }) - wx.showToast({ title: '修改成功', icon: 'success' }) - } else { - const errorMsg = res?.data?.msg || '修改失败' - wx.showToast({ title: errorMsg, icon: 'none' }) - } - } catch (error) { - console.error('修改失败:', error) - wx.hideLoading() - this.setData({ isConfirming: false }) - wx.showToast({ title: error.message || '修改失败', icon: 'none' }) - } - } +// pages/fighter-order-detail/fighter-order-detail.js - 【最终版:提交前公告弹窗 + 修改图片至少保留一张】 +const app = getApp() +import request from '../../utils/request.js' +const COS = require('../../utils/cos-wx-sdk-v5.min.js') + +Page({ + data: { + jibenShuju: { + dingdan_id: '', + tupian: '', + jieshao: '', + create_time: '', + jine: '', + nicheng: '', + beizhu: '', + zhuangtai: 0, + fadanpingtai: 0 + }, + xiangxiShuju: { + shangjia_id: '', + shangjia_nicheng: '', + shangjia_liuyan: '', + tuikuan_liyou: '', + chufa_liyou: '', + chufa_zhuangtai: 0, + chufa_jieguo: '', + bohui_liyou: '', + dashou_jiaofu: [], + dashou_liuyan: '', + laoban_id: '' + }, + zhuangtaiYanseMap: { + 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0', + 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1' + }, + zhuangtaiWenziMap: { + 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中', + 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中' + }, + isLoading: true, + isSubmitting: false, + liuyan: '', + xuanzhongTupian: [], + shangchuanJindu: 0, + shangchuanZongshu: 0, + jinduWidth: '0%', + showWanzhengJieshao: false, + wanzhengJieshao: '', + showWanzhengBeizhu: false, + wanzhengBeizhu: '', + ossImageUrl: '', + morentouxiang: '', + showRefundInfo: false, + + // 修改功能所需字段 + isModifying: false, + originalDashouJiaofu: [], + originalDashouLiuyan: '', + remainingOriginals: [], + modifiedLiuyan: '', + deletedImages: [], + newImages: [], + isConfirming: false, + modifyUploadProgress: { total: 0, current: 0, width: '0%' } + }, + + onLoad(options) { + wx.setNavigationBarTitle({ title: '订单详情' }) + this.initGlobalData() + this.jiexiTiaozhuanCanshu(options) + }, + onHide() { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } + }, + + onShow() { + this.registerNotificationComponent(); + }, + + registerNotificationComponent() { + const app = getApp(); + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + initGlobalData() { + const app = getApp() + const ossImageUrl = app.globalData.ossImageUrl || 'https://your-oss-domain.com/' + const morentouxiang = app.globalData.morentouxiang || '/images/default-avatar.png' + this.setData({ ossImageUrl, morentouxiang }) + }, + + jiexiTiaozhuanCanshu(options) { + try { + const dingdanDataStr = options.dingdanData || '' + if (!dingdanDataStr) { + wx.showToast({ title: '订单数据错误', icon: 'none' }) + setTimeout(() => wx.navigateBack(), 1500) + return + } + const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr)) + let tupianUrl = dingdanData.tupian || '' + if (!tupianUrl) tupianUrl = this.getTupianUrl() + let jine = parseFloat(dingdanData.jine || 0) + if (isNaN(jine)) jine = 0 + const formattedJine = jine.toFixed(2) + this.setData({ + 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '', + 'jibenShuju.tupian': tupianUrl, + 'jibenShuju.jieshao': dingdanData.jieshao || '', + 'jibenShuju.create_time': dingdanData.create_time || '', + 'jibenShuju.jine': formattedJine, + 'jibenShuju.nicheng': dingdanData.nicheng || '', + 'jibenShuju.beizhu': dingdanData.beizhu || '', + 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0, + 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0, + isLoading: false + }) + this.jiazaiXiangxiShuju(dingdanData.dingdan_id) + } catch (error) { + console.error('解析订单数据失败:', error) + wx.showToast({ title: '数据解析失败', icon: 'none' }) + setTimeout(() => wx.navigateBack(), 1500) + } + }, + + getTupianUrl() { + const cacheTouxiang = wx.getStorageSync('touxiang') || '' + let tupianPath = cacheTouxiang || app.globalData.morentouxiang || '' + const ossImageUrl = app.globalData.ossImageUrl || '' + if (tupianPath && ossImageUrl) { + if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1) + return ossImageUrl + tupianPath + } + return '' + }, + + async jiazaiXiangxiShuju(dingdanId) { + if (!dingdanId) return + wx.showLoading({ title: '加载中...', mask: true }) + try { + const res = await request({ + url: '/dingdan/dsddxq', + method: 'POST', + data: { dingdan_id: dingdanId }, + header: { 'content-type': 'application/json' } + }) + wx.hideLoading() + if (res && res.data.code === 0 && res.data.data) { + const data = res.data.data + let dashouJiaofuList = data.dashou_jiaofu || [] + dashouJiaofuList = dashouJiaofuList.map(imgUrl => { + if (imgUrl && !imgUrl.startsWith('http')) { + const ossImageUrl = app.globalData.ossImageUrl || '' + if (imgUrl.startsWith('/')) imgUrl = imgUrl.substring(1) + return ossImageUrl + imgUrl + } + return imgUrl + }) + this.setData({ + 'xiangxiShuju.shangjia_id': data.shangjia_id || '', + 'xiangxiShuju.shangjia_nicheng': data.shangjia_nicheng || '', + 'xiangxiShuju.shangjia_liuyan': data.shangjia_liuyan || '', + 'xiangxiShuju.tuikuan_liyou': data.tuikuan_liyou || '', + 'xiangxiShuju.chufa_liyou': data.chufa_liyou || '', + 'xiangxiShuju.chufa_zhuangtai': data.chufa_zhuangtai || 0, + 'xiangxiShuju.chufa_jieguo': data.chufa_jieguo || '', + 'xiangxiShuju.bohui_liyou': data.bohui_liyou || '', + 'xiangxiShuju.dashou_jiaofu': dashouJiaofuList, + 'xiangxiShuju.dashou_liuyan': data.dashou_liuyan || '', + 'xiangxiShuju.laoban_id': data.laoban_id || '', + 'jibenShuju.zhuangtai': data.zhuangtai || 0, + 'jibenShuju.beizhu': data.beizhu || '', + 'liuyan': data.dashou_liuyan || '', + 'jibenShuju.fadanpingtai': data.fadanpingtai || 0 + }) + const currentStatus = data.zhuangtai || 0 + const showRefund = [4,5,6].includes(currentStatus) + this.setData({ showRefundInfo: showRefund }) + } else { + const errorMsg = res?.data?.msg || '获取订单详情失败' + wx.showToast({ title: errorMsg, icon: 'none', duration: 2000 }) + } + } catch (error) { + console.error('加载详细数据失败:', error) + wx.hideLoading() + wx.showToast({ title: '加载数据失败,请重试', icon: 'none', duration: 2000 }) + } + }, + + // ========== 原有提交功能(部分修改) ========== + xuanzeTupian() { + if (this.data.isSubmitting) return + const shengyu = 9 - this.data.xuanzhongTupian.length + if (shengyu <= 0) { + wx.showToast({ title: '最多只能选择9张图片', icon: 'none' }) + return + } + wx.chooseImage({ + count: shengyu, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const newTupian = [...this.data.xuanzhongTupian, ...res.tempFilePaths] + this.setData({ xuanzhongTupian: newTupian.slice(0, 9) }) + } + }) + }, + shanchuTupian(e) { + const index = e.currentTarget.dataset.index + const newTupian = [...this.data.xuanzhongTupian] + newTupian.splice(index, 1) + this.setData({ xuanzhongTupian: newTupian }) + }, + yulanTupian(e) { + const currentUrl = e.currentTarget.dataset.url + const urls = e.currentTarget.dataset.urls || [] + if (!currentUrl) return + wx.previewImage({ current: currentUrl, urls: urls.length > 0 ? urls : [currentUrl] }) + }, + getFileExtension(filePath) { + const lastDotIndex = filePath.lastIndexOf('.') + if (lastDotIndex === -1) return '.jpg' + const ext = filePath.substring(lastDotIndex).toLowerCase() + const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'] + return allowedExts.includes(ext) ? ext : '.jpg' + }, + shuruLiuyan(e) { + const liuyan = e.detail.value.slice(0, 50) + this.setData({ liuyan }) + }, + chakanWanzhengJieshao() { + this.setData({ showWanzhengJieshao: true, wanzhengJieshao: this.data.jibenShuju.jieshao || '无' }) + }, + guanbiWanzhengJieshao() { this.setData({ showWanzhengJieshao: false }) }, + chakanWanzhengBeizhu() { + this.setData({ showWanzhengBeizhu: true, wanzhengBeizhu: this.data.jibenShuju.beizhu || '无' }) + }, + guanbiWanzhengBeizhu() { this.setData({ showWanzhengBeizhu: false }) }, + async fuzhiWenben(e) { + const text = e.currentTarget.dataset.text + if (!text) return + try { + await wx.setClipboardData({ data: text }) + wx.showToast({ title: '复制成功', icon: 'success', duration: 1500 }) + } catch (error) { + console.error('复制失败:', error) + wx.showToast({ title: '复制失败', icon: 'none' }) + } + }, + goToKefu() { + const kefuLink = app.globalData.kefuConfig?.link || ''; + const corpId = app.globalData.kefuConfig?.enterpriseId || ''; + + if (!kefuLink || !corpId) { + wx.showToast({ + title: '客服配置未加载', + icon: 'none' + }); + return; + } + + wx.openCustomerServiceChat({ + extInfo: { url: kefuLink }, + corpId: corpId, + success: (res) => { + console.log('跳转客服成功', res); + }, + fail: (err) => { + console.error('跳转客服失败', err); + wx.showToast({ + title: '暂时无法连接客服', + icon: 'none' + }); + } + }); + }, + + // ===== 联系老板(订单群 groupId 即订单号,与商家端 sjddxq 一致) ===== + goToChatWithBoss() { + const uid = wx.getStorageSync('uid') + if (!uid) { + wx.showToast({ title: '用户信息缺失', icon: 'none' }) + return + } + + const orderId = this.data.jibenShuju.dingdan_id + if (!orderId) { + wx.showToast({ title: '订单ID缺失', icon: 'none' }) + return + } + + const targetUserId = 'Ds' + uid + const connected = wx.goEasy && wx.goEasy.getConnectionStatus && wx.goEasy.getConnectionStatus() === 'connected' + const currentUserId = wx.goEasy?.im?.userId + if (!connected || currentUserId !== targetUserId) { + if (app.ensureConnection) app.ensureConnection() + wx.showToast({ title: '连接中,请稍后再试', icon: 'none' }) + return + } + + const orderIdStr = String(orderId) + const groupName = (this.data.jibenShuju.nicheng || '订单') + '的订单群' + const isCross = this.data.jibenShuju.fadanpingtai || 0 + + wx.goEasy.im.subscribeGroup({ + groupIds: [orderIdStr], + onSuccess: () => { + const param = { + groupId: orderIdStr, + orderId: orderIdStr, + groupName, + groupAvatar: '', + isCross, + } + wx.navigateTo({ + url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)), + }) + }, + onFailed: (err) => { + console.error('订阅群组失败', err) + wx.showToast({ title: '连接群聊失败', icon: 'none' }) + }, + }) + }, + + async getCOSZhengshu() { + try { + const res = await request({ + url: '/dingdan/dsscpz', + method: 'POST', + data: { dingdan_id: this.data.jibenShuju.dingdan_id } + }) + if (res && res.data.code === 0 && res.data.data) return res.data.data + else throw new Error(res?.data?.msg || '获取上传凭证失败') + } catch (error) { + console.error('获取COS凭证失败:', error) + throw error + } + }, + + initCOSClient(tokenData) { + const credentials = tokenData.credentials || tokenData + const bucket = tokenData.bucket || 'julebu-1361527063' + const region = tokenData.region || 'ap-shanghai' + const cos = new COS({ + SimpleUploadMethod: 'putObject', + getAuthorization: async (options, callback) => { + const authParams = { + TmpSecretId: credentials.tmpSecretId, + TmpSecretKey: credentials.tmpSecretKey, + SecurityToken: credentials.sessionToken || '', + StartTime: tokenData.startTime || Math.floor(Date.now() / 1000), + ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200) + } + callback(authParams) + } + }) + return { cos, bucket, region } + }, + + async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) { + return new Promise((resolve) => { + const timeoutId = setTimeout(() => resolve({ status: 'optimistic_success', key: cosKey }), 2000) + cosInstance.uploadFile({ + Bucket: bucket, + Region: region, + Key: cosKey, + FilePath: filePath, + onProgress: (progressInfo) => { + const percent = Math.round(progressInfo.percent * 100) + if (percent === 100) { + clearTimeout(timeoutId) + resolve({ status: 'optimistic_success', key: cosKey }) + } + } + }) + }) + }, + + async piliangShangchuanTupian() { + const total = this.data.xuanzhongTupian.length + this.setData({ shangchuanZongshu: total, shangchuanJindu: 0, jinduWidth: '0%' }) + wx.showLoading({ title: '正在准备...', mask: true }) + const preGeneratedUrls = [] + for (let i = 0; i < total; i++) { + const timestamp = Date.now() + i + const random = Math.floor(Math.random() * 10000) + const fileExt = this.getFileExtension(this.data.xuanzhongTupian[i]) + const fileName = `${timestamp}_${random}${fileExt}` + const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}` + preGeneratedUrls.push(cosKey) + } + let cosClient, bucket, region + try { + const tokenData = await this.getCOSZhengshu() + const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData) + cosClient = cos + bucket = cosBucket + region = cosRegion + } catch (error) { + wx.hideLoading() + wx.showToast({ title: '上传初始化失败', icon: 'none' }) + return [] + } + const uploadTasks = [] + for (let i = 0; i < total; i++) { + const task = this.shangchuanDanZhangTupian( + this.data.xuanzhongTupian[i], + preGeneratedUrls[i], + i, + cosClient, + bucket, + region + ).then((result) => { + const currentDone = i + 1 + const jinduPercent = ((currentDone / total) * 100).toFixed(0) + this.setData({ shangchuanJindu: currentDone, jinduWidth: `${jinduPercent}%` }) + return result + }) + uploadTasks.push(task) + } + wx.showLoading({ title: `上传中...`, mask: true }) + await Promise.all(uploadTasks) + wx.hideLoading() + return preGeneratedUrls + }, + + tijiaoDingdan() { + this.showAnnouncementAndConfirm() + }, + + async showAnnouncementAndConfirm() { + try { + const res = await request({ + url: '/peizhi/tanchuang', + method: 'POST', + data: { pageKey: 'dsddxq' } + }) + if (res.statusCode !== 200 || res.data.code !== 0) { + this.showOriginalConfirmAndSubmit() + return + } + const { popups = [], serverTime } = res.data.data + if (!popups.length) { + this.showOriginalConfirmAndSubmit() + return + } + const popup = popups[0] + const popupComp = this.selectComponent('#popupNotice') + if (!popupComp) { + console.error('未找到弹窗组件 #popupNotice') + this.showOriginalConfirmAndSubmit() + return + } + const showData = { + popupId: popup.popup_id, + title: popup.title || '', + duration: popup.duration || 0, + images: popup.images || [], + showMuteCheckbox: false, + serverTime: serverTime + } + popupComp.show(showData, (result) => { + this.showOriginalConfirmAndSubmit() + }) + } catch (error) { + console.error('获取公告配置失败', error) + this.showOriginalConfirmAndSubmit() + } + }, + + showOriginalConfirmAndSubmit() { + if (this.data.isSubmitting) { + wx.showToast({ title: '正在提交中', icon: 'none' }) + return + } + if (this.data.jibenShuju.zhuangtai !== 2) { + wx.showToast({ title: '订单状态不可提交', icon: 'none' }) + return + } + if (this.data.xuanzhongTupian.length === 0) { + wx.showToast({ title: '请至少上传一张图片', icon: 'none' }) + return + } + wx.showModal({ + title: '⚠️ 提交确认', + content: '在提交订单之前,请确保您已在接单员端页面认真阅读接单员规则。如有漏交图片,订单被退款,概不申诉。', + confirmText: '我已阅读', + cancelText: '我再想想', + success: (res) => { + if (res.confirm) this._doSubmit() + }, + fail: (err) => { + console.error('弹窗失败', err) + wx.showToast({ title: '系统异常,请重试', icon: 'none' }) + } + }) + }, + + async _doSubmit() { + this.setData({ isSubmitting: true }) + wx.showLoading({ title: '开始提交...', mask: true }) + try { + const tupianUrls = await this.piliangShangchuanTupian() + if (!tupianUrls || tupianUrls.length === 0) throw new Error('无法生成上传路径') + wx.showLoading({ title: '提交订单数据...', mask: true }) + const res = await request({ + url: '/dingdan/dstijiao', + method: 'POST', + data: { + dingdan_id: this.data.jibenShuju.dingdan_id, + liuyan: this.data.liuyan || '', + jiaofu_tupian_urls: tupianUrls + }, + header: { 'content-type': 'application/json' } + }) + wx.hideLoading() + this.setData({ isSubmitting: false }) + if (res && res.data.code === 0) { + const ossImageUrl = app.globalData.ossImageUrl || '' + const fullUrls = tupianUrls.map(url => { + if (url && !url.startsWith('http')) { + if (url.startsWith('/')) url = url.substring(1) + return ossImageUrl + url + } + return url + }) + this.setData({ + 'jibenShuju.zhuangtai': 8, + 'xiangxiShuju.dashou_liuyan': this.data.liuyan || '', + 'xiangxiShuju.dashou_jiaofu': fullUrls, + xuanzhongTupian: [], + liuyan: '', + shangchuanJindu: 0, + shangchuanZongshu: 0, + jinduWidth: '0%', + }) + if (app.globalData.dashouzhuangtai != 1) app.globalData.dashouzhuangtai = 1 + wx.showToast({ title: '提交成功!', icon: 'success', duration: 2000 }) + setTimeout(() => wx.navigateBack(), 1500) + } else { + const errorMsg = res?.data?.msg || '提交失败' + wx.showToast({ title: errorMsg, icon: 'none' }) + } + } catch (error) { + console.error('提交失败:', error) + wx.hideLoading() + this.setData({ isSubmitting: false }) + wx.showToast({ title: error.message || '提交失败', icon: 'none' }) + } + }, + + // ========== 修改功能(增加最少一张图片校验) ========== + extractRelativePath(fullUrl) { + const ossImageUrl = this.data.ossImageUrl + if (fullUrl.startsWith(ossImageUrl)) return fullUrl.substring(ossImageUrl.length) + return fullUrl + }, + enterModify() { + const { dashou_jiaofu, dashou_liuyan } = this.data.xiangxiShuju + this.setData({ + isModifying: true, + originalDashouJiaofu: dashou_jiaofu.slice(), + remainingOriginals: dashou_jiaofu.slice(), + originalDashouLiuyan: dashou_liuyan || '', + modifiedLiuyan: dashou_liuyan || '', + deletedImages: [], + newImages: [] + }) + }, + cancelModify() { + this.setData({ + isModifying: false, + originalDashouJiaofu: [], + remainingOriginals: [], + originalDashouLiuyan: '', + modifiedLiuyan: '', + deletedImages: [], + newImages: [] + }) + }, + handleDeleteImage(e) { + const fullUrl = e.currentTarget.dataset.url + const { originalDashouJiaofu, remainingOriginals, deletedImages, newImages } = this.data + if (originalDashouJiaofu.includes(fullUrl)) { + const newRemaining = remainingOriginals.filter(url => url !== fullUrl) + this.setData({ + remainingOriginals: newRemaining, + deletedImages: [...deletedImages, fullUrl] + }) + } else { + const index = newImages.indexOf(fullUrl) + if (index > -1) { + const newImagesCopy = [...newImages] + newImagesCopy.splice(index, 1) + this.setData({ newImages: newImagesCopy }) + } + } + }, + handleAddImage() { + if (this.data.isConfirming) return + const currentCount = this.getCurrentImageCount() + const maxCount = 9 - currentCount + if (maxCount <= 0) { + wx.showToast({ title: '最多9张图片', icon: 'none' }) + return + } + wx.chooseImage({ + count: maxCount, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const newImages = [...this.data.newImages, ...res.tempFilePaths] + this.setData({ newImages: newImages.slice(0, 9) }) + } + }) + }, + getCurrentImageCount() { + const { remainingOriginals, newImages } = this.data + return remainingOriginals.length + newImages.length + }, + onModifyLiuyanInput(e) { + this.setData({ modifiedLiuyan: e.detail.value.slice(0, 50) }) + }, + + async confirmModify() { + if (this.data.isConfirming) return + const { dingdan_id } = this.data.jibenShuju + const { remainingOriginals, deletedImages, newImages, modifiedLiuyan, originalDashouLiuyan } = this.data + const hasLiuyanChange = modifiedLiuyan !== originalDashouLiuyan + const hasDelete = deletedImages.length > 0 + const hasAdd = newImages.length > 0 + + if (!hasLiuyanChange && !hasDelete && !hasAdd) { + wx.showToast({ title: '没有修改内容', icon: 'none' }) + return + } + + const finalImageCount = remainingOriginals.length + newImages.length + if (finalImageCount === 0) { + wx.showToast({ title: '至少保留一张图片', icon: 'none' }) + return + } + + this.setData({ isConfirming: true }) + wx.showLoading({ title: '提交修改...', mask: true }) + try { + const tokenData = await this.getCOSZhengshu() + const { cos, bucket, region } = this.initCOSClient(tokenData) + + let newImageRelativePaths = [] + if (hasAdd) { + const total = newImages.length + this.setData({ 'modifyUploadProgress.total': total, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' }) + const preGeneratedKeys = [] + for (let i = 0; i < total; i++) { + const timestamp = Date.now() + i + const random = Math.floor(Math.random() * 10000) + const fileExt = this.getFileExtension(newImages[i]) + const fileName = `${timestamp}_${random}${fileExt}` + const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}` + preGeneratedKeys.push(cosKey) + } + const uploadTasks = [] + for (let i = 0; i < total; i++) { + const task = this.shangchuanDanZhangTupian( + newImages[i], + preGeneratedKeys[i], + i, + cos, + bucket, + region + ).then((result) => { + const currentDone = i + 1 + const jinduPercent = ((currentDone / total) * 100).toFixed(0) + this.setData({ + 'modifyUploadProgress.current': currentDone, + 'modifyUploadProgress.width': `${jinduPercent}%` + }) + return result.key + }) + uploadTasks.push(task) + } + wx.showLoading({ title: `上传中...`, mask: true }) + newImageRelativePaths = await Promise.all(uploadTasks) + wx.hideLoading() + this.setData({ 'modifyUploadProgress.total': 0, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' }) + } + + const deletedRelativePaths = deletedImages.map(fullUrl => this.extractRelativePath(fullUrl)) + + const res = await request({ + url: '/dingdan/dsxiugaidd', + method: 'POST', + data: { + dingdan_id, + liuyan: modifiedLiuyan, + deleted_images: deletedRelativePaths, + new_images: newImageRelativePaths + }, + header: { 'content-type': 'application/json' } + }) + wx.hideLoading() + this.setData({ isConfirming: false }) + if (res && res.data.code === 0) { + const ossImageUrl = this.data.ossImageUrl + const newFullUrls = newImageRelativePaths.map(rel => ossImageUrl + rel) + const newDashouJiaofu = [...remainingOriginals, ...newFullUrls] + this.setData({ + 'xiangxiShuju.dashou_jiaofu': newDashouJiaofu, + 'xiangxiShuju.dashou_liuyan': modifiedLiuyan, + isModifying: false, + originalDashouJiaofu: [], + remainingOriginals: [], + originalDashouLiuyan: '', + deletedImages: [], + newImages: [], + modifiedLiuyan: '' + }) + wx.showToast({ title: '修改成功', icon: 'success' }) + } else { + const errorMsg = res?.data?.msg || '修改失败' + wx.showToast({ title: errorMsg, icon: 'none' }) + } + } catch (error) { + console.error('修改失败:', error) + wx.hideLoading() + this.setData({ isConfirming: false }) + wx.showToast({ title: error.message || '修改失败', icon: 'none' }) + } + } }) \ No newline at end of file diff --git a/pages/fighter-orders/fighter-orders.js b/pages/fighter-orders/fighter-orders.js index 8323223..5d778af 100644 --- a/pages/fighter-orders/fighter-orders.js +++ b/pages/fighter-orders/fighter-orders.js @@ -49,7 +49,14 @@ Page(createPage({ onLoad() { wx.setNavigationBarTitle({ title: '我的接单' }); - this.loadShangpinLeixing(); + this.loadShangpinLeixing().then(() => { + if (this.data.xuanzhongLeixingId) { + return this.loadCurrentStatusOrders(true); + } + }).finally(() => { + this._ordersSessionReady = true; + this._skipShowRefresh = true; + }); this.registerNotificationComponent(); }, @@ -59,8 +66,15 @@ Page(createPage({ reconnectForRole('dashou'); if (app.startImWhenReady) app.startImWhenReady(); } - if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) { - this.loadCurrentStatusOrders(true); + if (this._skipShowRefresh) { + this._skipShowRefresh = false; + return; + } + if (this._ordersSessionReady && this.data.xuanzhongLeixingId && !this._silentRefreshRunning) { + this._silentRefreshRunning = true; + this.loadCurrentStatusOrders(true, true).finally(() => { + this._silentRefreshRunning = false; + }); } }, @@ -141,17 +155,21 @@ Page(createPage({ }, // 加载订单(核心) - async loadCurrentStatusOrders(isRefresh = false) { + async loadCurrentStatusOrders(isRefresh = false, silent = false) { const key = this.data.currentStatusKey; const tabData = this.data.dsDingdanShuju[key]; - if (tabData.isLoading) return; + if (tabData.isLoading && !silent) return; + if (silent && this._listRequesting) return; const page = isRefresh ? 1 : tabData.page; - this.setData({ - [`dsDingdanShuju.${key}.isLoading`]: true, - isLoading: true, - isLoadingMore: !isRefresh - }); + if (!silent) { + this.setData({ + [`dsDingdanShuju.${key}.isLoading`]: true, + isLoading: true, + isLoadingMore: !isRefresh, + }); + } + this._listRequesting = true; try { const apiUrl = this.data.orderType === 'peihu' @@ -208,14 +226,20 @@ Page(createPage({ } } catch (err) { console.error('加载订单失败', err); - wx.showToast({ title: err.message || '加载失败', icon: 'none' }); - this.setData({ - [`dsDingdanShuju.${key}.isLoading`]: false, - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false - }); - this.refreshCurrentListView(); + if (!silent) { + wx.showToast({ title: err.message || '加载失败', icon: 'none' }); + } + if (!silent) { + this.setData({ + [`dsDingdanShuju.${key}.isLoading`]: false, + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + this.refreshCurrentListView(); + } + } finally { + this._listRequesting = false; } }, diff --git a/pages/fighter-orders/fighter-orders.json b/pages/fighter-orders/fighter-orders.json index 60b86d2..44bcb57 100644 --- a/pages/fighter-orders/fighter-orders.json +++ b/pages/fighter-orders/fighter-orders.json @@ -1,6 +1,7 @@ { "usingComponents": { - "global-notification": "/components/global-notification/global-notification" + "global-notification": "/components/global-notification/global-notification", + "tab-bar": "/tab-bar/index" }, "navigationBarTitleText": "我的接单", "enablePullDownRefresh": false, diff --git a/pages/fighter-rank/fighter-rank.js b/pages/fighter-rank/fighter-rank.js index 7d72942..452b687 100644 --- a/pages/fighter-rank/fighter-rank.js +++ b/pages/fighter-rank/fighter-rank.js @@ -1,9 +1,14 @@ /** - * 排行榜 POST /yonghu/phbhqsj - * 参数: shenfen(dashou|guanshi|zuzhang|shangjia), riqi(今日|本周|本月|总榜|昨日|上周|上月) + * 排行榜 + * 默认 POST /yonghu/phbhqsj + * 星之界(xzj) POST /yonghu/xzjphbhqsj(邀请人数排序等专用规则) */ import request from '../../utils/request.js' import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js' +import { CLUB_ID } from '../../config/club-config.js' + +const IS_XZJ = CLUB_ID === 'xzj' +const RANK_API = IS_XZJ ? '/yonghu/xzjphbhqsj' : '/yonghu/phbhqsj' const ROLE_LIST = [ { key: 'dashou', label: '接单员' }, @@ -27,6 +32,7 @@ const ROLE_META = { title: '接单员排行榜', sortField: 'chengjiao_zonge', sortLabel: '分红总额', + mainType: 'money', metrics: [ { field: 'jiedan_zongliang', label: '接单量', type: 'int' }, { field: 'jiedan_zonge', label: '接单额', type: 'money' }, @@ -37,6 +43,7 @@ const ROLE_META = { title: '管事排行榜', sortField: 'shouru_zonge', sortLabel: '收入总额', + mainType: 'money', metrics: [ { field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' }, { field: 'chongzhi_dashou_shu', label: '充值', type: 'int' }, @@ -46,6 +53,7 @@ const ROLE_META = { title: '组长排行榜', sortField: 'shouru_zonge', sortLabel: '收入总额', + mainType: 'money', metrics: [ { field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' }, { field: 'fenyong_jine', label: '分佣', type: 'money' }, @@ -55,6 +63,7 @@ const ROLE_META = { title: '商家排行榜', sortField: 'jiesuan_jine', sortLabel: '成交总额', + mainType: 'money', metrics: [ { field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' }, { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' }, @@ -63,6 +72,55 @@ const ROLE_META = { }, } +/** 星之界专用展示与排序字段 */ +const XZJ_ROLE_META = { + dashou: { + title: '接单员排行榜', + sortField: 'chengjiao_zonge', + sortLabel: '成交金额', + mainType: 'money', + metrics: [ + { field: 'jiedan_zongliang', label: '接单量', type: 'int' }, + { field: 'jiedan_zonge', label: '接单额', type: 'money' }, + { field: 'chengjiao_zongliang', label: '成交量', type: 'int' }, + ], + }, + guanshi: { + title: '管事排行榜', + sortField: 'yaoqing_dashou_shu', + sortLabel: '邀请人数', + mainType: 'int', + metrics: [ + { field: 'wuxiao_yaoqing_dashou_shu', label: '无效邀请', type: 'int' }, + { field: 'chongzhi_dashou_shu', label: '有效人数', type: 'int' }, + { field: 'shouru_zonge', label: '收入金额', type: 'money' }, + ], + }, + zuzhang: { + title: '组长排行榜', + sortField: 'yaoqing_guanshi_shu', + sortLabel: '邀请人数', + mainType: 'int', + metrics: [ + { field: 'wuxiao_yaoqing_guanshi_shu', label: '无效邀请', type: 'int' }, + { field: 'youxiao_guanshi_shu', label: '有效人数', type: 'int' }, + { field: 'shouru_zonge', label: '收入金额', type: 'money' }, + ], + }, + shangjia: { + title: '商家排行榜', + sortField: 'paifa_jine', + sortLabel: '派单流水', + mainType: 'money', + metrics: [ + { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' }, + { field: 'paifa_jine', label: '派单流水', type: 'money' }, + ], + }, +} + +const ACTIVE_ROLE_META = IS_XZJ ? XZJ_ROLE_META : ROLE_META + function isInvalidAvatarPath(path) { if (path === null || path === undefined) return true if (typeof path !== 'string') return true @@ -99,7 +157,7 @@ Page({ onLoad(options) { const type = options.type || options.rankType || 'dashou' - const validRole = ROLE_META[type] ? type : 'dashou' + const validRole = ACTIVE_ROLE_META[type] ? type : 'dashou' this.initPage() this.applyRole(validRole, false) this.fetchRankList() @@ -162,7 +220,7 @@ Page({ }, applyRole(role, reload = true) { - const meta = ROLE_META[role] + const meta = ACTIVE_ROLE_META[role] wx.setNavigationBarTitle({ title: meta.title }) this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel }) if (reload) this.fetchRankList() @@ -196,7 +254,7 @@ Page({ }, normalizeItem(raw, index, role) { - const meta = ROLE_META[role] + const meta = ACTIVE_ROLE_META[role] const app = getApp() const uid = raw.yonghuid || raw.uid || '' const nicheng = raw.nicheng || raw.nick || '用户' @@ -209,12 +267,19 @@ Page({ value: m.type === 'money' ? this.formatMoney(v) : this.formatInt(v), } }) + const sortRaw = raw[meta.sortField] + const mainType = meta.mainType || 'money' + const mainValue = mainType === 'money' + ? this.formatMoney(sortRaw) + : this.formatInt(sortRaw) return { mingci: raw.mingci || index + 1, uid, nicheng, avatar, - mainValue: this.formatMoney(raw[meta.sortField]), + mainType, + mainPrefix: mainType === 'money' ? '¥' : '', + mainValue, mainLabel: meta.sortLabel, metrics, } @@ -224,7 +289,7 @@ Page({ this.setData({ isLoading: true, isEmpty: false }) try { const res = await request({ - url: '/yonghu/phbhqsj', + url: RANK_API, method: 'POST', data: { shenfen: this.data.currentRole, riqi: this.data.currentDate }, }) diff --git a/pages/fighter-rank/fighter-rank.wxml b/pages/fighter-rank/fighter-rank.wxml index 8c4db95..e486bee 100644 --- a/pages/fighter-rank/fighter-rank.wxml +++ b/pages/fighter-rank/fighter-rank.wxml @@ -52,7 +52,7 @@ {{topThree[1].nicheng}} ID {{topThree[1].uid}} - ¥{{topThree[1].mainValue}} + {{topThree[1].mainPrefix}}{{topThree[1].mainValue}} {{topThree[1].mainLabel}} @@ -70,7 +70,7 @@ {{topThree[0].nicheng}} ID {{topThree[0].uid}} - ¥{{topThree[0].mainValue}} + {{topThree[0].mainPrefix}}{{topThree[0].mainValue}} {{topThree[0].mainLabel}} @@ -88,7 +88,7 @@ {{topThree[2].nicheng}} ID {{topThree[2].uid}} - ¥{{topThree[2].mainValue}} + {{topThree[2].mainPrefix}}{{topThree[2].mainValue}} {{topThree[2].mainLabel}} @@ -120,7 +120,7 @@ - ¥{{item.mainValue}} + {{item.mainPrefix}}{{item.mainValue}} {{item.mainLabel}} diff --git a/pages/fighter-recharge/fighter-recharge.js b/pages/fighter-recharge/fighter-recharge.js index ebb1da2..9e7b957 100644 --- a/pages/fighter-recharge/fighter-recharge.js +++ b/pages/fighter-recharge/fighter-recharge.js @@ -1,975 +1,1018 @@ -// pages/dashou-chongzhi/index.js -import request from '../../utils/request'; -// 引入弹窗服务(路径根据实际调整) -import PopupService from '../../services/popupService.js'; - -Page({ - data: { - // ========== 全局数据 ========== - clubmber: [], // 会员列表(注意:全局变量中是 clumber,这里保持原样) - yajin: 0, // 押金 - jifen: 0, // 积分(注意:全局变量中是 jinfen) - jifenProgress: 0, // 积分进度条角度 - - // ========== 会员商品列表 ========== - huiyuanList: [], // 从后端获取的会员列表 - currentHuiyuanIndex: 0, // 当前选中的会员索引 - currentHuiyuan: {}, // 当前选中的会员详情 - - // ========== 押金充值相关 ========== - showYajinModal: false, // 显示押金弹窗 - yajinAmount: '100', // 押金金额 - - // ========== 支付相关 ========== - payLoading: false, // 支付加载状态 - loadingText: '支付中...', - - // ========== 订单ID记录 ========== - currentDingdanid: '', // 当前操作的订单ID - - // ========== 计算高度 ========== - huiyuanListHeight: 120, - - // ========== 会员详情规则 ========== - detailRules: [ - '会员有效期为30天,从购买当天开始计算', - '会员期间享受优先接单特权', - '可享受专属客服服务', - '会员到期前3天会有提醒', - '支持随时续费,续费天数叠加' - ], - - // ========== 新增:跳转参数处理 ========== - // 用于接收从其他页面跳转过来的参数,决定是否自动滚动 - jumpParams: {}, - - // ========== 新增:支付方式选择 ========== - showPayMethodModal: false, // 支付方式选择弹窗 - currentBuyType: null, // 当前购买类型:1会员 2押金 3积分 - currentHuiyuanId: null, // 当前选中的会员ID(用于会员购买) - currentYajinAmount: null, // 当前押金金额(用于押金购买) - - // ========== 新增:余额抵扣身份选择 ========== - showBalanceModal: false, // 余额抵扣身份选择弹窗 - balanceOptions: [], // 后端返回的身份列表 - selectedBalanceId: null, // 选中的身份ID - - // ========== 新增:余额抵扣确认弹窗 ========== - showConfirmModal: false, // 余额抵扣确认弹窗 - selectedBalanceInfo: null, // 选中的身份详情(用于确认弹窗) - - // ========== 新增:会员详情弹窗 ========== - showMemberModal: false, - currentMemberDetail: null, - }, - - // ========== 生命周期函数 ========== - onLoad(options) { - //console.log('页面加载,跳转参数:', options); - - // ✅ 新增:保存跳转参数 - this.setData({ - jumpParams: options || {} - }); - - this.initPage(); - }, - - // pages/submit/submit.js 中添加 onHide 方法(如果已有则合并内容) -onHide() { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } - }, - - onShow() { - // 每次显示页面都刷新数据 - this.registerNotificationComponent(); - this.loadFromGlobalData(); - this.checkAndRefreshData(); - - // 调用统一弹窗组件检查并展示公告 - PopupService.checkAndShow(this, 'dashouchongzhi'); - }, - - // 注册通知组件(原有,保持不变) - registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - - if (notificationComp && notificationComp.showNotification) { - - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - onReady() { - // ✅ 新增:页面渲染完成后处理自动滚动 - this.handleAutoScroll(); - }, - - // ========== 初始化页面 ========== - async initPage() { - // 从全局数据加载 - this.loadFromGlobalData(); - - // 获取会员商品列表 - await this.fetchHuiyuanList(); - - // 计算会员列表高度 - this.calculateHuiyuanHeight(); - }, - - // ========== 从全局变量加载数据 ========== - loadFromGlobalData() { - const app = getApp(); - const globalData = app.globalData || {}; - - // ✅ 重要:保持字段对应关系 - // 全局变量中是 clumber,页面中是 clubmber - // 全局变量中是 jinfen,页面中是 jifen - this.setData({ - clubmber: globalData.clumber || [], - yajin: globalData.yajin || 0, - jifen: globalData.jinfen || 0 // ✅ 注意:这里从 jinfen 读取 - }); - - // 计算积分进度条 - this.calculateJifenProgress(); - }, - - // ========== 计算积分进度条角度 ========== - calculateJifenProgress() { - const jifen = this.data.jifen || 0; - const progress = (jifen / 10) * 360; // 满分10分 - this.setData({ - jifenProgress: progress - }); - }, - - // ========== 计算会员列表高度 ========== - calculateHuiyuanHeight() { - const clubmber = this.data.clubmber || []; - - const itemHeight = 100; // 每个会员标签高度 - const maxHeight = 300; // 最大高度(3个会员) - - let height = clubmber.length * itemHeight; - height = Math.min(height, maxHeight); - - this.setData({ - huiyuanListHeight: height - }); - }, - - // ========== 获取会员商品列表 ========== - async fetchHuiyuanList() { - try { - const res = await request({ - url: '/shangpin/dshyhq', - method: 'POST', - data: {} - }); - - if (res.data.code === 200) { - const huiyuanList = res.data.data || []; - - // 处理数据,标记已购买的会员 - const processedList = this.processHuiyuanList(huiyuanList); - - this.setData({ - huiyuanList: processedList, - currentHuiyuan: processedList[0] || {} - }); - } else { - wx.showToast({ - title: res.data.message || '获取会员列表失败', - icon: 'none' - }); - } - } catch (error) { - console.error('获取会员列表失败:', error); - wx.showToast({ - title: '网络错误,请重试', - icon: 'none' - }); - } - }, - - // ========== 处理会员列表,标记已购买的会员 ========== - processHuiyuanList(huiyuanList) { - const clubmber = this.data.clubmber || []; - - return huiyuanList.map(item => { - // 检查是否已购买(注意:会员ID字段是 id) - const boughtItem = clubmber.find(c => c.huiyuanid === item.id); - - return { - ...item, - isBought: !!boughtItem, - buyInfo: boughtItem || null - }; - }); - }, - - // ========== Swiper切换事件 ========== - onSwiperChange(e) { - const current = e.detail.current; - const huiyuanList = this.data.huiyuanList || []; - - this.setData({ - currentHuiyuanIndex: current, - currentHuiyuan: huiyuanList[current] || {} - }); - }, - - // ========== 手动选择会员 ========== - selectHuiyuan(e) { - const index = e.currentTarget.dataset.index; - const huiyuanList = this.data.huiyuanList || []; - - this.setData({ - currentHuiyuanIndex: index, - currentHuiyuan: huiyuanList[index] || {} - }); - }, - - // ========== 格式化到期时间 ========== - formatDaoqiTime(daoqi) { - if (!daoqi) return ''; - - try { - // 如果是标准日期格式,格式化为 YYYY-MM-DD - if (daoqi.includes(' ')) { - const dateStr = daoqi.split(' ')[0]; - const dateParts = dateStr.split('-'); - if (dateParts.length === 3) { - return `${dateParts[0]}-${dateParts[1]}-${dateParts[2]}`; - } - } - return daoqi; - } catch (error) { - console.error('格式化到期时间错误:', error); - return daoqi; - } - }, - - // ========== 计算剩余时间 ========== - formatRemainTime(daoqi) { - if (!daoqi) return ''; - - try { - const now = new Date(); - const end = new Date(daoqi); - const diff = end - now; - - if (diff <= 0) return '已过期'; - - const days = Math.floor(diff / (1000 * 60 * 60 * 24)); - if (days > 0) { - return `${days}天`; - } - - const hours = Math.floor(diff / (1000 * 60 * 60)); - if (hours > 0) { - return `${hours}小时`; - } - - return '即将到期'; - } catch (error) { - console.error('计算剩余时间错误:', error); - return '时间错误'; - } - }, - - // ========== 处理自动滚动 ========== - handleAutoScroll() { - const { jumpParams } = this.data; - - if (!jumpParams || !jumpParams.needScroll) return; - - setTimeout(() => { - let scrollTop = 0; - - if (jumpParams.scrollTo === 'bottom') { - scrollTop = 2000; - } else if (jumpParams.scrollTo === 'member') { - return; - } - - if (scrollTop > 0) { - wx.pageScrollTo({ - scrollTop: scrollTop, - duration: 300 - }); - } - }, 800); - }, - - // ========== 押金充值相关 ========== - showYajinModal() { - this.setData({ - showYajinModal: true, - yajinAmount: '100' - }); - }, - - hideYajinModal() { - this.setData({ - showYajinModal: false - }); - }, - - onYajinInput(e) { - let value = e.detail.value; - value = value.replace(/[^\d]/g, ''); - - if (value) { - const num = parseInt(value); - if (num < 1) value = '1'; - if (num > 10000) value = '10000'; - } - - this.setData({ - yajinAmount: value - }); - }, - - setYajinAmount(e) { - const amount = e.currentTarget.dataset.amount; - this.setData({ - yajinAmount: amount - }); - }, - - async handleYajinPay() { - const amount = this.data.yajinAmount; - - if (!amount || amount < 1 || amount > 10000) { - wx.showToast({ - title: '请输入1-10000元的金额', - icon: 'none' - }); - return; - } - - this.showLoading('发起支付中...'); - - try { - const res = await request({ - url: '/shangpin/yajingoumai', - method: 'POST', - data: { - jine: parseInt(amount) - } - }); - - if (res.data.code === 200) { - const payParams = res.data.payParams; - const dingdanid = res.data.dingdanid; - - this.setData({ - currentDingdanid: dingdanid - }); - - await this.wechatPay(payParams, 'yajin'); - } else { - wx.showToast({ - title: res.data.message || '支付发起失败', - icon: 'none' - }); - } - } catch (error) { - console.error('押金支付失败:', error); - wx.showToast({ - title: '支付失败,请重试', - icon: 'none' - }); - } finally { - this.hideLoading(); - } - }, - - // ========== 积分充值相关 ========== - // 🔥 修改点1:增加积分已满的硬拦截,不弹任何提示,直接返回 - onJifenClick(e) { - // 优先判断积分是否已满(10分为满分) - if (this.data.jifen >= 10) { - // 积分已满,不弹窗,不提示,静默返回 - return; - } - - // 检查是否有会员 - const clubmber = this.data.clubmber || []; - if (clubmber.length === 0) { - wx.showToast({ - title: '请先购买会员才能充值积分', - icon: 'none', - duration: 3000 - }); - return; - } - - // 积分未满,正常打开支付方式选择 - this.setData({ - currentBuyType: 3, - showPayMethodModal: true - }); - }, - - // ========== 会员购买相关 ========== - async handleHuiyuanBuy(e) { - const huiyuanId = e.currentTarget.dataset.id; - - if (!huiyuanId) { - wx.showToast({ - title: '会员信息错误', - icon: 'none' - }); - return; - } - - this.showLoading('发起会员支付中...'); - - try { - const res = await request({ - url: '/shangpin/huiyuangm', - method: 'POST', - data: { - huiyuanid: huiyuanId - } - }); - - if (res.data.code === 200) { - const payParams = res.data.payParams; - const dingdanid = res.data.dingdanid; - - this.setData({ - currentDingdanid: dingdanid - }); - - await this.wechatPay(payParams, 'huiyuan', huiyuanId); - } else { - wx.showToast({ - title: res.data.message || '会员支付发起失败', - icon: 'none' - }); - } - } catch (error) { - console.error('会员支付失败:', error); - wx.showToast({ - title: '支付失败,请重试', - icon: 'none' - }); - } finally { - this.hideLoading(); - } - }, - - // ========== 积分购买(微信支付)—— 已替换为正确的后端接口 ========== - async handleJifenBuy(e) { - const disabled = e.currentTarget.dataset.disabled; - - // 检查积分是否已满 - if (disabled === 'true') { - wx.showToast({ title: '积分已满,无需补充', icon: 'none' }); - return; - } - - // 检查是否有会员 - const clubmber = this.data.clubmber || []; - if (clubmber.length === 0) { - wx.showToast({ title: '请先购买会员才能充值积分', icon: 'none', duration: 3000 }); - return; - } - - this.showLoading('发起积分支付中...'); - - try { - const res = await request({ - url: '/shangpin/jifenbc', // 正确的积分下单接口 - method: 'POST', - data: {} - }); - - if (res.data.code === 200) { - const payParams = res.data.payParams; - const dingdanid = res.data.dingdanid; - - this.setData({ currentDingdanid: dingdanid }); - await this.wechatPay(payParams, 'jifen'); - } else { - wx.showToast({ title: res.data.message || '积分支付发起失败', icon: 'none' }); - } - } catch (error) { - wx.showToast({ title: '支付失败,请重试', icon: 'none' }); - } finally { - this.hideLoading(); - } - }, - - // ========== 微信支付封装 ========== - async wechatPay(payParams, payType, extraData = null) { - return new Promise((resolve, reject) => { - if (!payParams || !payParams.timeStamp || !payParams.paySign) { - wx.showToast({ - title: '支付参数错误', - icon: 'none' - }); - reject(new Error('支付参数错误')); - return; - } - - this.showLoading('调起支付中...'); - - wx.requestPayment({ - timeStamp: payParams.timeStamp, - nonceStr: payParams.nonceStr, - package: payParams.package, - signType: payParams.signType || 'MD5', - paySign: payParams.paySign, - success: async () => { - this.hideLoading(); - - wx.showToast({ - title: '支付成功!确认中...', - icon: 'none', - duration: 2000 - }); - - try { - await this.startPolling(payType, extraData); - resolve(); - } catch (error) { - reject(error); - } - }, - fail: async (res) => { - this.hideLoading(); - - let errorMsg = '支付失败'; - if (res.errMsg.includes('cancel')) { - errorMsg = '您取消了支付'; - } else if (res.errMsg.includes('fail')) { - errorMsg = '支付失败,请重试'; - } - - wx.showToast({ - title: errorMsg, - icon: 'none' - }); - - try { - await this.handlePayFailure(payType, extraData); - } catch (error) { - console.error('支付失败通知失败:', error); - } - - reject(new Error(res.errMsg)); - } - }); - }); - }, - - // ========== 开始轮询支付结果 ========== - async startPolling(payType, extraData = null) { - const maxRetries = 10; - const interval = 2000; - const dingdanid = this.data.currentDingdanid; - - if (!dingdanid) { - wx.showToast({ - title: '订单号缺失', - icon: 'none' - }); - return; - } - - this.showLoading('确认支付结果中...'); - - for (let i = 0; i < maxRetries; i++) { - try { - const pollResult = await this.checkPayStatus(payType, dingdanid, extraData); - - if (pollResult.success) { - this.hideLoading(); - await this.updateAfterPayment(payType, extraData, pollResult.data); - - wx.showToast({ - title: this.getSuccessMessage(payType), - icon: 'success', - duration: 2000 - }); - - return; - } - - await this.sleep(interval); - } catch (error) { - console.error(`轮询失败第${i + 1}次:`, error); - } - } - - this.hideLoading(); - wx.showToast({ - title: '支付确认超时,请联系客服', - icon: 'none' - }); - }, - - // ========== 检查支付状态 ========== - async checkPayStatus(payType, dingdanid, extraData = null) { - let url = ''; - let data = { dingdanid: dingdanid }; - - switch (payType) { - case 'yajin': - url = '/shangpin/yajinlunxun'; - break; - case 'jifen': - url = '/shangpin/jifenlunxun'; - break; - case 'huiyuan': - url = '/shangpin/huiyuanlx'; - data.huiyuanid = extraData; - break; - default: - throw new Error('未知的支付类型'); - } - - try { - const res = await request({ - url, - method: 'POST', - data - }); - - return { - success: res.data.code === 200, - data: res.data - }; - } catch (error) { - console.error('检查支付状态失败:', error); - return { - success: false, - data: null - }; - } - }, - - // ========== 支付失败处理 ========== - async handlePayFailure(payType, extraData = null) { - let url = ''; - let data = { dingdanid: this.data.currentDingdanid }; - - switch (payType) { - case 'yajin': - url = '/shangpin/yajinshibai'; - break; - case 'jifen': - url = '/shangpin/jifenshibai'; - break; - case 'huiyuan': - url = '/shangpin/huiyuanshibai'; - data.huiyuanid = extraData; - break; - default: - return; - } - - try { - await request({ - url, - method: 'POST', - data - }); - } catch (error) { - console.error('支付失败通知失败:', error); - } - }, - - // ========== 支付成功后更新数据 ========== - async updateAfterPayment(payType, extraData = null, responseData = null) { - const app = getApp(); - - switch (payType) { - case 'yajin': - if (responseData && responseData.yajin !== undefined) { - app.globalData.yajin = responseData.yajin; - } - await this.refreshYajinData(); - break; - - case 'jifen': - if (responseData && responseData.jifen !== undefined) { - app.globalData.jinfen = responseData.jifen; - } - await this.refreshJifenData(); - break; - - case 'huiyuan': - if (responseData && responseData.huiyuan) { - app.globalData.jinfen = responseData.jifen; - await this.updateClubmberData(responseData.huiyuan); - } - await this.refreshHuiyuanData(extraData); - break; - } - - this.loadFromGlobalData(); - }, - - // ========== 刷新押金数据 ========== - async refreshYajinData() { - this.loadFromGlobalData(); - }, - - // ========== 刷新积分数据 ========== - async refreshJifenData() { - this.loadFromGlobalData(); - }, - - // ========== 刷新会员数据 ========== - async refreshHuiyuanData(huiyuanId) { - this.loadFromGlobalData(); - await this.fetchHuiyuanList(); - }, - - // ========== 更新会员数据到全局变量 ========== - async updateClubmberData(huiyuanData) { - const app = getApp(); - const globalClubmber = app.globalData.clumber || []; - - const { huiyuanid, huiyuanming, daoqi } = huiyuanData; - - const index = globalClubmber.findIndex(item => item.huiyuanid === huiyuanid); - - if (index >= 0) { - globalClubmber[index].daoqi = daoqi; - } else { - globalClubmber.push({ - huiyuanid: huiyuanid, - huiyuanming: huiyuanming, - daoqi: daoqi - }); - } - - app.globalData.clumber = globalClubmber; - - this.setData({ - clubmber: [...globalClubmber] - }); - }, - - // ========== 检查并刷新数据 ========== - async checkAndRefreshData() { - this.loadFromGlobalData(); - }, - - // ========== 工具方法 ========== - getSuccessMessage(payType) { - switch (payType) { - case 'yajin': return '押金充值成功'; - case 'jifen': return '积分补充成功'; - case 'huiyuan': return '会员购买成功'; - default: return '支付成功'; - } - }, - - showLoading(text = '加载中...') { - this.setData({ - payLoading: true, - loadingText: text - }); - }, - - hideLoading() { - this.setData({ - payLoading: false - }); - }, - - sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - }, - - // ========== 新增功能(余额抵扣等) ========== - onBuyHuiyuanClick(e) { - const huiyuanId = e.currentTarget.dataset.id; - this.setData({ - currentBuyType: 1, - currentHuiyuanId: huiyuanId, - showPayMethodModal: true - }); - }, - - onYajinClick() { - this.showYajinModal(); - }, - - onYajinConfirm() { - const amount = this.data.yajinAmount; - if (!amount || amount < 1 || amount > 10000) { - wx.showToast({ title: '请输入1-10000元的金额', icon: 'none' }); - return; - } - this.hideYajinModal(); - this.setData({ - currentBuyType: 2, - currentYajinAmount: amount, - showPayMethodModal: true - }); - }, - - hidePayMethodModal() { - this.setData({ showPayMethodModal: false }); - }, - - // 🔥 修改点2:选择支付方式时再次校验积分状态(防止异步过程中积分变化) - onPayMethodSelect(e) { - const method = e.currentTarget.dataset.method; - const { currentBuyType, currentHuiyuanId, currentYajinAmount, jifen } = this.data; - this.hidePayMethodModal(); - - // 如果是积分购买,且积分已满,直接拒绝 - if (currentBuyType === 3 && jifen >= 10) { - wx.showToast({ - title: '积分已满,无需补充', - icon: 'none' - }); - return; - } - - if (method === 'wx') { - if (currentBuyType === 1) { - this.handleHuiyuanBuy({ currentTarget: { dataset: { id: currentHuiyuanId } } }); - } else if (currentBuyType === 2) { - this.setData({ yajinAmount: currentYajinAmount }, () => { - this.handleYajinPay(); - }); - } else if (currentBuyType === 3) { - // ✅ 调用已修正的积分支付函数 - this.handleJifenBuy({ currentTarget: { dataset: { disabled: 'false' } } }); - } - } else if (method === 'balance') { - this.fetchBalanceOptions(); - } - }, - - // 🔥 修改点3:请求余额抵扣选项前校验积分状态 - async fetchBalanceOptions() { - const { currentBuyType, currentHuiyuanId, currentYajinAmount, jifen } = this.data; - - // 如果是积分购买,且积分已满,拒绝发起余额抵扣 - if (currentBuyType === 3 && jifen >= 10) { - wx.showToast({ - title: '积分已满,无需补充', - icon: 'none' - }); - return; - } - - this.showLoading('获取抵扣信息...'); - - try { - const res = await request({ - url: '/shangpin/czhqdy', - method: 'POST', - data: { - leixing: currentBuyType, - huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined, - yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined, - } - }); - if (res.data.code === 200) { - const options = res.data.data || []; - this.setData({ - balanceOptions: options, - showBalanceModal: true - }); - } else { - wx.showToast({ title: res.data.message || '获取失败', icon: 'none' }); - } - } catch (error) { - console.error('获取抵扣身份失败:', error); - wx.showToast({ title: '网络错误', icon: 'none' }); - } finally { - this.hideLoading(); - } - }, - - hideBalanceModal() { - this.setData({ showBalanceModal: false }); - }, - - onBalanceSelect(e) { - const identityId = e.currentTarget.dataset.id; - const selected = this.data.balanceOptions.find(opt => opt.id === identityId); - if (!selected) return; - - this.setData({ - selectedBalanceId: identityId, - selectedBalanceInfo: selected, - showConfirmModal: true, - showBalanceModal: false - }); - }, - - hideConfirmModal() { - this.setData({ showConfirmModal: false }); - }, - - async confirmBalancePay() { - const { selectedBalanceId, currentBuyType, currentHuiyuanId, currentYajinAmount } = this.data; - if (!selectedBalanceId) return; - - this.hideConfirmModal(); - this.showLoading('抵扣支付中...'); - - try { - const res = await request({ - url: '/shangpin/dsqrgmdh', - method: 'POST', - data: { - leixing: currentBuyType, - shenfen_id: selectedBalanceId, - huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined, - yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined, - } - }); - - if (res.data.code === 200) { - const responseData = res.data.data || {}; - await this.updateAfterPayment( - currentBuyType === 1 ? 'huiyuan' : (currentBuyType === 2 ? 'yajin' : 'jifen'), - currentBuyType === 1 ? currentHuiyuanId : null, - responseData - ); - wx.showToast({ title: '购买成功', icon: 'success' }); - } else { - wx.showToast({ title: res.data.message || '购买失败', icon: 'none' }); - } - } catch (error) { - console.error('抵扣支付失败:', error); - wx.showToast({ title: '网络错误', icon: 'none' }); - } finally { - this.hideLoading(); - } - }, - - showMemberDetail(e) { - const item = e.currentTarget.dataset.item; - this.setData({ - currentMemberDetail: item, - showMemberModal: true - }); - }, - - hideMemberModal() { - this.setData({ showMemberModal: false }); - }, +// pages/dashou-chongzhi/index.js +import request from '../../utils/request'; +import PopupService from '../../services/popupService.js'; +import { ensurePhoneAuth } from '../../utils/phone-auth.js'; + +Page({ + data: { + // ========== 全局数据 ========== + clubmber: [], // 会员列表(注意:全局变量中是 clumber,这里保持原样) + yajin: 0, // 押金 + jifen: 0, // 积分(注意:全局变量中是 jinfen) + jifenProgress: 0, // 积分进度条角度 + + // ========== 会员商品列表 ========== + huiyuanList: [], // 从后端获取的会员列表 + currentHuiyuanIndex: 0, // 当前选中的会员索引 + currentHuiyuan: {}, // 当前选中的会员详情 + + // ========== 押金充值相关 ========== + showYajinModal: false, // 显示押金弹窗 + yajinAmount: '100', // 押金金额 + + // ========== 支付相关 ========== + payLoading: false, // 支付加载状态 + loadingText: '支付中...', + + // ========== 订单ID记录 ========== + currentDingdanid: '', // 当前操作的订单ID + + // ========== 计算高度 ========== + huiyuanListHeight: 120, + + // ========== 会员详情规则 ========== + detailRules: [], + + // ========== 新增:跳转参数处理 ========== + // 用于接收从其他页面跳转过来的参数,决定是否自动滚动 + jumpParams: {}, + + // ========== 新增:支付方式选择 ========== + showPayMethodModal: false, // 支付方式选择弹窗 + currentBuyType: null, // 当前购买类型:1会员 2押金 3积分 + currentHuiyuanId: null, // 当前选中的会员ID(用于会员购买) + currentBuyIsTrial: false, // 正式/体验:仅体验禁余额抵扣 + currentYajinAmount: null, // 当前押金金额(用于押金购买) + + // ========== 新增:余额抵扣身份选择 ========== + showBalanceModal: false, // 余额抵扣身份选择弹窗 + balanceOptions: [], // 后端返回的身份列表 + selectedBalanceId: null, // 选中的身份ID + + // ========== 新增:余额抵扣确认弹窗 ========== + showConfirmModal: false, // 余额抵扣确认弹窗 + selectedBalanceInfo: null, // 选中的身份详情(用于确认弹窗) + + // ========== 新增:会员详情弹窗 ========== + showMemberModal: false, + currentMemberDetail: null, + }, + + // ========== 生命周期函数 ========== + onLoad(options) { + //console.log('页面加载,跳转参数:', options); + + // ✅ 新增:保存跳转参数 + this.setData({ + jumpParams: options || {} + }); + + this.initPage(); + }, + + // pages/submit/submit.js 中添加 onHide 方法(如果已有则合并内容) +onHide() { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } + }, + + async onShow() { + const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' }); + if (!phoneOk) return; + + // 每次显示页面都刷新数据 + this.registerNotificationComponent(); + this.loadFromGlobalData(); + this.checkAndRefreshData(); + + // 调用统一弹窗组件检查并展示公告 + PopupService.checkAndShow(this, 'dashouchongzhi'); + }, + + // 注册通知组件(原有,保持不变) + registerNotificationComponent() { + const app = getApp(); + const notificationComp = this.selectComponent('#global-notification'); + + if (notificationComp && notificationComp.showNotification) { + + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + onReady() { + // ✅ 新增:页面渲染完成后处理自动滚动 + this.handleAutoScroll(); + }, + + // ========== 初始化页面 ========== + async initPage() { + // 从全局数据加载 + this.loadFromGlobalData(); + + // 获取会员商品列表 + await this.fetchHuiyuanList(); + + // 计算会员列表高度 + this.calculateHuiyuanHeight(); + }, + + // ========== 从全局变量加载数据 ========== + loadFromGlobalData() { + const app = getApp(); + const globalData = app.globalData || {}; + + // ✅ 重要:保持字段对应关系 + // 全局变量中是 clumber,页面中是 clubmber + // 全局变量中是 jinfen,页面中是 jifen + const rawClubmber = globalData.clumber || []; + const clubmber = rawClubmber.filter((c) => c && c.huiyuanid); + + this.setData({ + clubmber: clubmber, + yajin: globalData.yajin || 0, + jifen: globalData.jinfen || 0 // ✅ 注意:这里从 jinfen 读取 + }); + + // 计算积分进度条 + this.calculateJifenProgress(); + }, + + // ========== 计算积分进度条角度 ========== + calculateJifenProgress() { + const jifen = this.data.jifen || 0; + const progress = (jifen / 10) * 360; // 满分10分 + this.setData({ + jifenProgress: progress + }); + }, + + // ========== 计算会员列表高度 ========== + calculateHuiyuanHeight() { + const clubmber = this.data.clubmber || []; + + const itemHeight = 100; // 每个会员标签高度 + const maxHeight = 300; // 最大高度(3个会员) + + let height = clubmber.length * itemHeight; + height = Math.min(height, maxHeight); + + this.setData({ + huiyuanListHeight: height + }); + }, + + // ========== 获取会员商品列表 ========== + async fetchHuiyuanList() { + try { + const res = await request({ + url: '/shangpin/dshyhq', + method: 'POST', + data: {} + }); + + if (res.data.code === 200) { + const huiyuanList = res.data.data || []; + + // 处理数据,标记已购买的会员 + const processedList = this.processHuiyuanList(huiyuanList); + + const currentHuiyuan = processedList[0] || {}; + this.setData({ + huiyuanList: processedList, + currentHuiyuan, + detailRules: this.buildDetailRules(currentHuiyuan) + }); + } else { + wx.showToast({ + title: res.data.message || '获取会员列表失败', + icon: 'none' + }); + } + } catch (error) { + console.error('获取会员列表失败:', error); + wx.showToast({ + title: '网络错误,请重试', + icon: 'none' + }); + } + }, + + // ========== 处理会员列表,标记已购买的会员 ========== + processHuiyuanList(huiyuanList) { + const clubmber = this.data.clubmber || []; + + return huiyuanList.map(item => { + // 检查是否已购买(注意:会员ID字段是 id) + const boughtItem = clubmber.find(c => c.huiyuanid === item.id); + + return { + ...item, + isBought: !!boughtItem, + buyInfo: boughtItem || null + }; + }); + }, + + // ========== Swiper切换事件 ========== + onSwiperChange(e) { + const current = e.detail.current; + const huiyuanList = this.data.huiyuanList || []; + const currentHuiyuan = huiyuanList[current] || {}; + + this.setData({ + currentHuiyuanIndex: current, + currentHuiyuan, + detailRules: this.buildDetailRules(currentHuiyuan) + }); + }, + + // ========== 手动选择会员 ========== + selectHuiyuan(e) { + const index = e.currentTarget.dataset.index; + const huiyuanList = this.data.huiyuanList || []; + + const currentHuiyuan = huiyuanList[index] || {}; + this.setData({ + currentHuiyuanIndex: index, + currentHuiyuan, + detailRules: this.buildDetailRules(currentHuiyuan) + }); + }, + + buildDetailRules(huiyuan = {}) { + const formalDays = huiyuan.formal_days || 30; + const rules = [ + `正式会员有效期为${formalDays}天,从购买当天开始计算`, + '会员期间享受优先接单特权', + '支持随时续费,未过期续费天数叠加,已过期从今天重新计算' + ]; + if (huiyuan.can_buy_trial) { + rules.push(`体验会员终身仅可购买1次(${huiyuan.trial_days || 0}天),体验期仅限制佣金提现`); + } + if (huiyuan.trial_enabled && !huiyuan.can_buy_trial) { + rules.push('您已使用过该会员的体验资格'); + } + rules.push('体验会员仅支持微信支付;正式会员可使用佣金、分红或押金抵扣'); + return rules; + }, + + // ========== 格式化到期时间 ========== + formatDaoqiTime(daoqi) { + if (!daoqi) return ''; + + try { + // 如果是标准日期格式,格式化为 YYYY-MM-DD + if (daoqi.includes(' ')) { + const dateStr = daoqi.split(' ')[0]; + const dateParts = dateStr.split('-'); + if (dateParts.length === 3) { + return `${dateParts[0]}-${dateParts[1]}-${dateParts[2]}`; + } + } + return daoqi; + } catch (error) { + console.error('格式化到期时间错误:', error); + return daoqi; + } + }, + + // ========== 计算剩余时间 ========== + formatRemainTime(daoqi) { + if (!daoqi) return ''; + + try { + const now = new Date(); + const end = new Date(daoqi); + const diff = end - now; + + if (diff <= 0) return '已过期'; + + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + if (days > 0) { + return `${days}天`; + } + + const hours = Math.floor(diff / (1000 * 60 * 60)); + if (hours > 0) { + return `${hours}小时`; + } + + return '即将到期'; + } catch (error) { + console.error('计算剩余时间错误:', error); + return '时间错误'; + } + }, + + // ========== 处理自动滚动 ========== + handleAutoScroll() { + const { jumpParams } = this.data; + + if (!jumpParams || !jumpParams.needScroll) return; + + setTimeout(() => { + let scrollTop = 0; + + if (jumpParams.scrollTo === 'bottom') { + scrollTop = 2000; + } else if (jumpParams.scrollTo === 'member') { + return; + } + + if (scrollTop > 0) { + wx.pageScrollTo({ + scrollTop: scrollTop, + duration: 300 + }); + } + }, 800); + }, + + // ========== 押金充值相关 ========== + showYajinModal() { + this.setData({ + showYajinModal: true, + yajinAmount: '100' + }); + }, + + hideYajinModal() { + this.setData({ + showYajinModal: false + }); + }, + + onYajinInput(e) { + let value = e.detail.value; + value = value.replace(/[^\d]/g, ''); + + if (value) { + const num = parseInt(value); + if (num < 1) value = '1'; + if (num > 10000) value = '10000'; + } + + this.setData({ + yajinAmount: value + }); + }, + + setYajinAmount(e) { + const amount = e.currentTarget.dataset.amount; + this.setData({ + yajinAmount: amount + }); + }, + + async handleYajinPay() { + const amount = this.data.yajinAmount; + + if (!amount || amount < 1 || amount > 10000) { + wx.showToast({ + title: '请输入1-10000元的金额', + icon: 'none' + }); + return; + } + + this.showLoading('发起支付中...'); + + try { + const res = await request({ + url: '/shangpin/yajingoumai', + method: 'POST', + data: { + jine: parseInt(amount) + } + }); + + if (res.data.code === 200) { + const payParams = res.data.payParams; + const dingdanid = res.data.dingdanid; + + this.setData({ + currentDingdanid: dingdanid + }); + + await this.wechatPay(payParams, 'yajin'); + } else { + wx.showToast({ + title: res.data.message || '支付发起失败', + icon: 'none' + }); + } + } catch (error) { + console.error('押金支付失败:', error); + wx.showToast({ + title: '支付失败,请重试', + icon: 'none' + }); + } finally { + this.hideLoading(); + } + }, + + // ========== 积分充值相关 ========== + // 🔥 修改点1:增加积分已满的硬拦截,不弹任何提示,直接返回 + onJifenClick(e) { + // 优先判断积分是否已满(10分为满分) + if (this.data.jifen >= 10) { + // 积分已满,不弹窗,不提示,静默返回 + return; + } + + // 检查是否有会员 + const clubmber = this.data.clubmber || []; + if (clubmber.length === 0) { + wx.showToast({ + title: '请先购买会员才能充值积分', + icon: 'none', + duration: 3000 + }); + return; + } + + // 积分未满,正常打开支付方式选择 + this.setData({ + currentBuyType: 3, + showPayMethodModal: true + }); + }, + + // ========== 会员购买相关 ========== + async handleHuiyuanBuy(e) { + const huiyuanId = e.currentTarget.dataset.id; + const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true'; + + if (!huiyuanId) { + wx.showToast({ + title: '会员信息错误', + icon: 'none' + }); + return; + } + + this.showLoading('发起会员支付中...'); + + try { + const res = await request({ + url: '/shangpin/huiyuangm', + method: 'POST', + data: { + huiyuanid: huiyuanId, + is_trial: isTrial + } + }); + + if (res.data.code === 200) { + const payParams = res.data.payParams; + const dingdanid = res.data.dingdanid; + + this.setData({ + currentDingdanid: dingdanid + }); + + await this.wechatPay(payParams, 'huiyuan', huiyuanId); + } else { + wx.showToast({ + title: res.data.message || '会员支付发起失败', + icon: 'none' + }); + } + } catch (error) { + console.error('会员支付失败:', error); + wx.showToast({ + title: '支付失败,请重试', + icon: 'none' + }); + } finally { + this.hideLoading(); + } + }, + + // ========== 积分购买(微信支付)—— 已替换为正确的后端接口 ========== + async handleJifenBuy(e) { + const disabled = e.currentTarget.dataset.disabled; + + // 检查积分是否已满 + if (disabled === 'true') { + wx.showToast({ title: '积分已满,无需补充', icon: 'none' }); + return; + } + + // 检查是否有会员 + const clubmber = this.data.clubmber || []; + if (clubmber.length === 0) { + wx.showToast({ title: '请先购买会员才能充值积分', icon: 'none', duration: 3000 }); + return; + } + + this.showLoading('发起积分支付中...'); + + try { + const res = await request({ + url: '/shangpin/jifenbc', // 正确的积分下单接口 + method: 'POST', + data: {} + }); + + if (res.data.code === 200) { + const payParams = res.data.payParams; + const dingdanid = res.data.dingdanid; + + this.setData({ currentDingdanid: dingdanid }); + await this.wechatPay(payParams, 'jifen'); + } else { + wx.showToast({ title: res.data.message || '积分支付发起失败', icon: 'none' }); + } + } catch (error) { + wx.showToast({ title: '支付失败,请重试', icon: 'none' }); + } finally { + this.hideLoading(); + } + }, + + // ========== 微信支付封装 ========== + async wechatPay(payParams, payType, extraData = null) { + return new Promise((resolve, reject) => { + if (!payParams || !payParams.timeStamp || !payParams.paySign) { + wx.showToast({ + title: '支付参数错误', + icon: 'none' + }); + reject(new Error('支付参数错误')); + return; + } + + this.showLoading('调起支付中...'); + + wx.requestPayment({ + timeStamp: payParams.timeStamp, + nonceStr: payParams.nonceStr, + package: payParams.package, + signType: payParams.signType || 'MD5', + paySign: payParams.paySign, + success: async () => { + this.hideLoading(); + + wx.showToast({ + title: '支付成功!确认中...', + icon: 'none', + duration: 2000 + }); + + try { + await this.startPolling(payType, extraData); + resolve(); + } catch (error) { + reject(error); + } + }, + fail: async (res) => { + this.hideLoading(); + + let errorMsg = '支付失败'; + if (res.errMsg.includes('cancel')) { + errorMsg = '您取消了支付'; + } else if (res.errMsg.includes('fail')) { + errorMsg = '支付失败,请重试'; + } + + wx.showToast({ + title: errorMsg, + icon: 'none' + }); + + try { + await this.handlePayFailure(payType, extraData); + } catch (error) { + console.error('支付失败通知失败:', error); + } + + reject(new Error(res.errMsg)); + } + }); + }); + }, + + // ========== 开始轮询支付结果 ========== + async startPolling(payType, extraData = null) { + const maxRetries = 10; + const interval = 2000; + const dingdanid = this.data.currentDingdanid; + + if (!dingdanid) { + wx.showToast({ + title: '订单号缺失', + icon: 'none' + }); + return; + } + + this.showLoading('确认支付结果中...'); + + for (let i = 0; i < maxRetries; i++) { + try { + const pollResult = await this.checkPayStatus(payType, dingdanid, extraData); + + if (pollResult.success) { + this.hideLoading(); + await this.updateAfterPayment(payType, extraData, pollResult.data); + + wx.showToast({ + title: this.getSuccessMessage(payType), + icon: 'success', + duration: 2000 + }); + + return; + } + + await this.sleep(interval); + } catch (error) { + console.error(`轮询失败第${i + 1}次:`, error); + } + } + + this.hideLoading(); + wx.showToast({ + title: '支付确认超时,请联系客服', + icon: 'none' + }); + }, + + // ========== 检查支付状态 ========== + async checkPayStatus(payType, dingdanid, extraData = null) { + let url = ''; + let data = { dingdanid: dingdanid }; + + switch (payType) { + case 'yajin': + url = '/shangpin/yajinlunxun'; + break; + case 'jifen': + url = '/shangpin/jifenlunxun'; + break; + case 'huiyuan': + url = '/shangpin/huiyuanlx'; + data.huiyuanid = extraData; + break; + default: + throw new Error('未知的支付类型'); + } + + try { + const res = await request({ + url, + method: 'POST', + data + }); + + return { + success: res.data.code === 200, + data: res.data + }; + } catch (error) { + console.error('检查支付状态失败:', error); + return { + success: false, + data: null + }; + } + }, + + // ========== 支付失败处理 ========== + async handlePayFailure(payType, extraData = null) { + let url = ''; + let data = { dingdanid: this.data.currentDingdanid }; + + switch (payType) { + case 'yajin': + url = '/shangpin/yajinshibai'; + break; + case 'jifen': + url = '/shangpin/jifenshibai'; + break; + case 'huiyuan': + url = '/shangpin/huiyuanshibai'; + data.huiyuanid = extraData; + break; + default: + return; + } + + try { + await request({ + url, + method: 'POST', + data + }); + } catch (error) { + console.error('支付失败通知失败:', error); + } + }, + + // ========== 支付成功后更新数据 ========== + async updateAfterPayment(payType, extraData = null, responseData = null) { + const app = getApp(); + + switch (payType) { + case 'yajin': + if (responseData && responseData.yajin !== undefined) { + app.globalData.yajin = responseData.yajin; + } + await this.refreshYajinData(); + break; + + case 'jifen': + if (responseData && responseData.jifen !== undefined) { + app.globalData.jinfen = responseData.jifen; + } + await this.refreshJifenData(); + break; + + case 'huiyuan': + if (responseData && responseData.huiyuan) { + app.globalData.jinfen = responseData.jifen; + await this.updateClubmberData(responseData.huiyuan); + } + await this.refreshHuiyuanData(extraData); + break; + } + + this.loadFromGlobalData(); + }, + + // ========== 刷新押金数据 ========== + async refreshYajinData() { + this.loadFromGlobalData(); + }, + + // ========== 刷新积分数据 ========== + async refreshJifenData() { + this.loadFromGlobalData(); + }, + + // ========== 刷新会员数据 ========== + async refreshHuiyuanData(huiyuanId) { + this.loadFromGlobalData(); + await this.fetchHuiyuanList(); + }, + + // ========== 更新会员数据到全局变量 ========== + async updateClubmberData(huiyuanData) { + const app = getApp(); + const globalClubmber = app.globalData.clumber || []; + + const { huiyuanid, huiyuanming, daoqi } = huiyuanData; + + const index = globalClubmber.findIndex(item => item.huiyuanid === huiyuanid); + + if (index >= 0) { + globalClubmber[index].daoqi = daoqi; + } else { + globalClubmber.push({ + huiyuanid: huiyuanid, + huiyuanming: huiyuanming, + daoqi: daoqi + }); + } + + app.globalData.clumber = globalClubmber; + + this.setData({ + clubmber: [...globalClubmber] + }); + }, + + // ========== 检查并刷新数据 ========== + async checkAndRefreshData() { + this.loadFromGlobalData(); + }, + + // ========== 工具方法 ========== + getSuccessMessage(payType) { + switch (payType) { + case 'yajin': return '押金充值成功'; + case 'jifen': return '积分补充成功'; + case 'huiyuan': return '会员购买成功'; + default: return '支付成功'; + } + }, + + showLoading(text = '加载中...') { + this.setData({ + payLoading: true, + loadingText: text + }); + }, + + hideLoading() { + this.setData({ + payLoading: false + }); + }, + + sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + }, + + // ========== 新增功能(余额抵扣等) ========== + onBuyHuiyuanClick(e) { + const huiyuanId = e.currentTarget.dataset.id; + const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true'; + + if (isTrial) { + this.handleHuiyuanBuy(e); + return; + } + + this.setData({ + currentBuyType: 1, + currentHuiyuanId: huiyuanId, + currentBuyIsTrial: false, + showPayMethodModal: true + }); + }, + + onYajinClick() { + this.showYajinModal(); + }, + + onYajinConfirm() { + const amount = this.data.yajinAmount; + if (!amount || amount < 1 || amount > 10000) { + wx.showToast({ title: '请输入1-10000元的金额', icon: 'none' }); + return; + } + this.hideYajinModal(); + this.setData({ + currentBuyType: 2, + currentYajinAmount: amount, + showPayMethodModal: true + }); + }, + + hidePayMethodModal() { + this.setData({ showPayMethodModal: false }); + }, + + // 🔥 修改点2:选择支付方式时再次校验积分状态(防止异步过程中积分变化) + onPayMethodSelect(e) { + const method = e.currentTarget.dataset.method; + const { currentBuyType, currentHuiyuanId, currentYajinAmount, jifen } = this.data; + this.hidePayMethodModal(); + + // 如果是积分购买,且积分已满,直接拒绝 + if (currentBuyType === 3 && jifen >= 10) { + wx.showToast({ + title: '积分已满,无需补充', + icon: 'none' + }); + return; + } + + if (method === 'wx') { + if (currentBuyType === 1) { + this.handleHuiyuanBuy({ + currentTarget: { dataset: { id: currentHuiyuanId, trial: 'false' } } + }); + } else if (currentBuyType === 2) { + this.setData({ yajinAmount: currentYajinAmount }, () => { + this.handleYajinPay(); + }); + } else if (currentBuyType === 3) { + // ✅ 调用已修正的积分支付函数 + this.handleJifenBuy({ currentTarget: { dataset: { disabled: 'false' } } }); + } + } else if (method === 'balance') { + this.fetchBalanceOptions(); + } + }, + + // 🔥 修改点3:请求余额抵扣选项前校验积分状态 + async fetchBalanceOptions() { + const { currentBuyType, currentHuiyuanId, currentYajinAmount, currentBuyIsTrial, jifen } = this.data; + + if (currentBuyType === 1 && currentBuyIsTrial) { + wx.showToast({ title: '体验会员仅支持微信支付', icon: 'none' }); + return; + } + + // 如果是积分购买,且积分已满,拒绝发起余额抵扣 + if (currentBuyType === 3 && jifen >= 10) { + wx.showToast({ + title: '积分已满,无需补充', + icon: 'none' + }); + return; + } + + this.showLoading('获取抵扣信息...'); + + try { + const res = await request({ + url: '/shangpin/czhqdy', + method: 'POST', + data: { + leixing: currentBuyType, + huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined, + is_trial: currentBuyType === 1 ? false : undefined, + yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined, + } + }); + if (res.data.code === 200) { + const options = res.data.data || []; + this.setData({ + balanceOptions: options, + showBalanceModal: true + }); + } else { + wx.showToast({ title: res.data.message || '获取失败', icon: 'none' }); + } + } catch (error) { + console.error('获取抵扣身份失败:', error); + wx.showToast({ title: '网络错误', icon: 'none' }); + } finally { + this.hideLoading(); + } + }, + + hideBalanceModal() { + this.setData({ showBalanceModal: false }); + }, + + onBalanceSelect(e) { + const identityId = e.currentTarget.dataset.id; + const selected = this.data.balanceOptions.find(opt => opt.id === identityId); + if (!selected) return; + + this.setData({ + selectedBalanceId: identityId, + selectedBalanceInfo: selected, + showConfirmModal: true, + showBalanceModal: false + }); + }, + + hideConfirmModal() { + this.setData({ showConfirmModal: false }); + }, + + async confirmBalancePay() { + const { selectedBalanceId, currentBuyType, currentHuiyuanId, currentYajinAmount, currentBuyIsTrial } = this.data; + if (!selectedBalanceId) return; + + this.hideConfirmModal(); + this.showLoading('抵扣支付中...'); + + try { + const res = await request({ + url: '/shangpin/dsqrgmdh', + method: 'POST', + data: { + leixing: currentBuyType, + shenfen_id: selectedBalanceId, + huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined, + is_trial: currentBuyType === 1 ? currentBuyIsTrial : undefined, + yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined, + } + }); + + if (res.data.code === 200) { + const responseData = res.data.data || {}; + await this.updateAfterPayment( + currentBuyType === 1 ? 'huiyuan' : (currentBuyType === 2 ? 'yajin' : 'jifen'), + currentBuyType === 1 ? currentHuiyuanId : null, + responseData + ); + wx.showToast({ title: '购买成功', icon: 'success' }); + } else { + wx.showToast({ title: res.data.message || '购买失败', icon: 'none' }); + } + } catch (error) { + console.error('抵扣支付失败:', error); + wx.showToast({ title: '网络错误', icon: 'none' }); + } finally { + this.hideLoading(); + } + }, + + showMemberDetail(e) { + const item = e.currentTarget.dataset.item; + this.setData({ + currentMemberDetail: item, + showMemberModal: true + }); + }, + + hideMemberModal() { + this.setData({ showMemberModal: false }); + }, }); \ No newline at end of file diff --git a/pages/fighter-recharge/fighter-recharge.wxml b/pages/fighter-recharge/fighter-recharge.wxml index a5187df..42fa21e 100644 --- a/pages/fighter-recharge/fighter-recharge.wxml +++ b/pages/fighter-recharge/fighter-recharge.wxml @@ -47,6 +47,12 @@ 已拥有 + + 可购体验 + + + 体验已用/不可购 + {{item.mingzi}} @@ -56,7 +62,11 @@ ¥ {{item.jiage}} - /30天 + /{{item.formal_days || 30}}天 + + + 体验 + ¥{{item.trial_price}}/{{item.trial_days}}天 @@ -107,20 +117,27 @@ 价格: ¥{{currentHuiyuan.jiage}} + /{{currentHuiyuan.formal_days || 30}}天 已激活,{{currentHuiyuan.buyInfo.daoqi}}后到期 - 激活会员特权 + 正式会员支持微信或余额抵扣 + + 体验版仅微信支付 ¥{{currentHuiyuan.trial_price}}/{{currentHuiyuan.trial_days}}天,终身1次 + + + 本俱乐部尚未为该会员开启体验版,请联系管理员在后台配置 + + bindtap="onBuyHuiyuanClick" data-id="{{currentHuiyuan.id}}" data-trial="false"> - {{currentHuiyuan.isBought ? '立即续费' : '立即激活'}} + {{currentHuiyuan.isBought ? '正式续费' : '购买正式版'}} @@ -128,6 +145,16 @@ + + + 购买体验版 + diff --git a/pages/fighter-recharge/fighter-recharge.wxss b/pages/fighter-recharge/fighter-recharge.wxss index 2f808eb..08f6d12 100644 --- a/pages/fighter-recharge/fighter-recharge.wxss +++ b/pages/fighter-recharge/fighter-recharge.wxss @@ -1,4 +1,5 @@ -/* pages/dashou-chongzhi/index.wxss - 完整保留原有样式,仅删除导航栏相关,调整间距和字体 */ +/* pages/dashou-chongzhi/index.wxss - 逍遥梦主题覆盖 + 机甲基础样式 */ +@import '../../styles/dashou-xym-recharge-theme.wxss'; /* ==================== 基础样式 ==================== */ .page-container { @@ -676,6 +677,32 @@ box-shadow: 0 0 15rpx rgba(255, 107, 157, 0.4); z-index: 20; } + + .vip-badge.trial-badge { + top: 60rpx; + background: linear-gradient(135deg, #ffb347, #ff7043); + } + + .vip-badge.trial-off-badge { + top: 60rpx; + background: rgba(120, 120, 120, 0.85); + box-shadow: none; + } + + .vip-trial-price { + margin-top: 8rpx; + font-size: 22rpx; + color: #ffb347; + } + + .trial-price-label { + margin-right: 8rpx; + color: #a0c8ff; + } + + .trial-price-value { + font-weight: 600; + } .vip-title { margin-bottom: 25rpx; @@ -855,11 +882,35 @@ /* 购买区域 */ .buy-section { display: flex; - align-items: center; - justify-content: space-between; + flex-direction: column; + align-items: stretch; + gap: 20rpx; padding-top: 25rpx; border-top: 1px solid rgba(64, 156, 255, 0.2); } + + .buy-action { + display: flex; + flex-direction: column; + gap: 16rpx; + align-items: flex-end; + } + + .price-days { + font-size: 22rpx; + color: #a0c8ff; + } + + .trial-hint { + margin-top: 6rpx; + color: #ffb347; + } + + .trial-warn { + margin-top: 6rpx; + color: #ff8a8a; + font-size: 22rpx; + } .buy-info { display: flex; @@ -928,6 +979,11 @@ background: linear-gradient(135deg, #1e4b8f, #409cff); } + .tech-buy-btn.trial-buy-btn .buy-btn-bg { + background: linear-gradient(135deg, rgba(255, 179, 71, 0.35), rgba(255, 120, 80, 0.45)); + border: 1px solid rgba(255, 179, 71, 0.6); + } + .tech-buy-btn.renew .buy-btn-bg { background: linear-gradient(135deg, #0f2c5c, #36cfc9); } @@ -1702,6 +1758,4 @@ display: flex !important; align-items: center !important; justify-content: center !important; - } - -@import '../../styles/dashou-xym-recharge-theme.wxss'; \ No newline at end of file + } \ No newline at end of file diff --git a/pages/fighter/fighter.js b/pages/fighter/fighter.js index 99a60b9..37d72c3 100644 --- a/pages/fighter/fighter.js +++ b/pages/fighter/fighter.js @@ -2,9 +2,25 @@ import { createPage, request, isRoleStatusActive, isCenterPageActive, syncRoleStatuses, syncProfileFields, syncGroupFields, ensureRoleOnCenterPage, clearCacheAndEnterNormal, lockPrimaryRole, migrateLegacyCenterRole, enterLockedRole, parseSceneOptions } from '../../utils/base-page.js' import { resolveAvatarUrl } from '../../utils/avatar.js' import { openPrivateChat, buildInviterPeerId } from '../../utils/im-user.js' +import { isStaffMode, getStaffContext } from '../../utils/staff-api.js' +import { ensurePhoneAuth } from '../../utils/phone-auth.js' +import { + ICON_KEYS, + resolveMiniappIcon, + resolveConfiguredIcon, + refreshPindaoConfig, + getPindaoConfig, + resolvePindaoImages, + warmupPindaoConfig, + PINDAO_ICON_FALLBACK, +} from '../../utils/miniapp-icons.js' const PLATFORM_INVITE_CODE = '0000008RffVgKHMj7kQC' +/** 会员/保证金横幅 COS 兜底(后台未上传时仍显示) */ +const FIGHTER_BANNER_VIP_FALLBACK = 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/20260512123427531240452.png' +const FIGHTER_BANNER_DEPOSIT_FALLBACK = 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/202605121234283091d3980.png' + Page(createPage({ data: { // 图片路径对象 @@ -41,6 +57,7 @@ Page(createPage({ zuzhangInviterCache: null, chenghaoList: [], guanshiChenghaoList: [], + identityTagList: [], gszhstatus: '', yaoqingzongshu: 0, fenyongzonge: '0.00', @@ -65,13 +82,25 @@ Page(createPage({ statusBar: 20, navBar: 44, + pindaoVisible: false, + pindaoTitle: '频道', + pindaoChannelNo: '', + examEnabled: false, + examPassed: false, + pindaoImages: [], + + scrollViewRefreshing: false, + showRechargeBanners: false, + showPindaoEntry: true, }, _buildImgUrls(ossImageUrl) { + const app = getApp(); const dsBase = ossImageUrl + 'beijing/dashouduan/'; const iconBase = ossImageUrl + 'beijing/dashouduan/dashoutubiaobeijing/'; const gsBase = ossImageUrl + 'beijing/guanshiduan/'; const khBase = ossImageUrl + 'beijing/kaohe/'; + const icon = (key, fallback) => resolveMiniappIcon(app, key, fallback); return { pageBg: dsBase + 'page-bg.jpg', userCardBg: dsBase + 'user-card-bg.png', @@ -83,7 +112,7 @@ Page(createPage({ listBg: dsBase + 'list-card-bg.png', topBg: iconBase + 'top-bg.jpg', cardBg: iconBase + 'card-bg.jpg', - iconRefresh: gsBase + 'icon-refresh.png', + iconRefresh: icon(ICON_KEYS.ICON_REFRESH, gsBase + 'icon-refresh.png'), iconCopy: gsBase + 'icon-copy.png', iconVip: dsBase + 'icon-vip.png', iconArrowLight: dsBase + 'icon-arrow-light.png', @@ -118,6 +147,7 @@ Page(createPage({ iconSwitch: '/images/_exit.png', iconKefu: ossImageUrl + 'beijing/tubiao/grzx_kefu.jpg', iconKuaishou: ossImageUrl + 'beijing/tubiao/grzx_guanzhualong.jpg', + iconPindao: icon(ICON_KEYS.MINE_PINDAO, ossImageUrl + PINDAO_ICON_FALLBACK), iconKaoheDafen: khBase + 'daofen.png', iconKaoheJilu: khBase + 'jilu.png', iconKaoheZhongxin: khBase + 'zhongxin.png', @@ -128,8 +158,8 @@ Page(createPage({ kefuBannerBg: dsBase + 'kefu-banner-bg.png', totalAssetBg: dsBase + 'total-asset-bg.png', authPanelBg: dsBase + 'auth-panel-bg.png', - bannerVip: 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/20260512123427531240452.png', - bannerDeposit: 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/202605121234283091d3980.png', + bannerVip: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER) || FIGHTER_BANNER_VIP_FALLBACK, + bannerDeposit: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT) || FIGHTER_BANNER_DEPOSIT_FALLBACK, }; }, @@ -177,9 +207,28 @@ Page(createPage({ } } this.checkColdStartPopup('dashouduan'); + this.syncConfiguredAssets(); }, - onShow() { + syncConfiguredAssets() { + const app = getApp(); + const bannerVip = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER) || FIGHTER_BANNER_VIP_FALLBACK; + const bannerDeposit = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT) || FIGHTER_BANNER_DEPOSIT_FALLBACK; + const imgUrls = { ...this.data.imgUrls, bannerVip, bannerDeposit }; + this.setData({ + imgUrls, + showRechargeBanners: !!(bannerVip || bannerDeposit), + showPindaoEntry: this.data.isDashou || this.data.isGuanshi || this.data.isZuzhang || this.data.isKaoheguan, + }); + }, + + async onShow() { + if (!app.globalData._dashouPhoneChecked) { + const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' }); + if (!phoneOk) return; + app.globalData._dashouPhoneChecked = true; + } + migrateLegacyCenterRole(getApp()); lockPrimaryRole('dashou', getApp()); wx.setStorageSync('isJinpai', 0); @@ -190,16 +239,17 @@ Page(createPage({ this.setData({ inviterCache, zuzhangInviterCache }); this.registerNotificationComponent(); + warmupPindaoConfig(app); this.checkRoleStatuses(); + this.syncConfiguredAssets(); if (isCenterPageActive(this, 'isDashou', 'dashoustatus')) { if (!this.data.isDashou) this.setData({ isDashou: true }); ensureRoleOnCenterPage(this, 'dashou'); - setTimeout(() => this.refreshAllInfo(false), 300); + this.loadExamStatus(); } else if (isRoleStatusActive(wx.getStorageSync('guanshistatus')) || isRoleStatusActive(wx.getStorageSync('zuzhangstatus')) || isRoleStatusActive(wx.getStorageSync('kaoheguanstatus'))) { ensureRoleOnCenterPage(this, 'dashou'); - setTimeout(() => this.refreshAllInfo(false), 300); } const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; @@ -277,12 +327,17 @@ Page(createPage({ tag: d.shangjiaCertified ? '进入商家端' : '去认证', done: d.shangjiaCertified, }); + list.push({ + type: 'staff', + name: '商家客服', + icon: img.iconKefu || img.iconShangjia, + tag: isStaffMode() ? '进入工作台' : '去入驻', + done: isStaffMode(), + }); if (!d.isGuanshi) { list.push({ type: 'guanshi', name: '管事', icon: img.iconGuanshiAuth, tag: '去认证' }); } - if (!d.isZuzhang) { - list.push({ type: 'zuzhang', name: '组长', icon: img.iconZuzhangAuth, tag: '去认证' }); - } + // 组长由后台添加,前端不再展示「组长认证」入口 if (!d.isDashou) { list.push({ type: 'dashou', name: '接单员', icon: img.iconDashouAuth, tag: '去认证' }); } @@ -293,35 +348,37 @@ Page(createPage({ }, async refreshAllInfo(showToast = true) { - this.throttledRefresh(async () => { - this.setData({ isLoading: true }); - try { - this.checkRoleStatuses(); - const results = await Promise.allSettled([ - this._fetchDashouInfoSilent(), - this.fetchChenghaoList(), - this._fetchGuanshiInfoSilent(), - this.fetchGuanshiChenghaoList(), - this._fetchZuzhangInfoSilent(), - this._fetchKaoheguanInfoSilent(), - ]); - this.checkRoleStatuses(); - const dashouOk = results[0].status === 'fulfilled'; - if (showToast) { - wx.showToast({ - title: dashouOk ? '刷新成功' : '刷新失败', - icon: dashouOk ? 'success' : 'none', - duration: 1500, - }); - } - } catch (e) { - if (showToast) { - wx.showToast({ title: '刷新失败', icon: 'none' }); - } - } finally { - this.setData({ isLoading: false }); + if (this._profileRefreshing) return; + this._profileRefreshing = true; + this.setData({ isLoading: true }); + try { + this.checkRoleStatuses(); + const results = await Promise.allSettled([ + this._fetchDashouInfoSilent(), + this.fetchChenghaoList(), + this._fetchGuanshiInfoSilent(), + this.fetchGuanshiChenghaoList(), + this._fetchZuzhangInfoSilent(), + this._fetchKaoheguanInfoSilent(), + this.loadIdentityTags(), + ]); + this.checkRoleStatuses(); + const dashouOk = results[0].status === 'fulfilled'; + if (showToast) { + wx.showToast({ + title: dashouOk ? '刷新成功' : '刷新失败', + icon: dashouOk ? 'success' : 'none', + duration: 1500, + }); } - }, 3000); + } catch (e) { + if (showToast) { + wx.showToast({ title: '刷新失败', icon: 'none' }); + } + } finally { + this._profileRefreshing = false; + this.setData({ isLoading: false }); + } }, refreshDashouInfo() { @@ -332,6 +389,34 @@ Page(createPage({ this.refreshAllInfo(true); }, + onPullDownRefresh() { + this.setData({ scrollViewRefreshing: true }); + Promise.all([ + this.refreshAllInfo(false), + this.loadExamStatus(), + ]).finally(() => { + this.setData({ scrollViewRefreshing: false }); + wx.stopPullDownRefresh(); + }); + }, + + async loadIdentityTags() { + try { + const res = await request({ url: '/jituan/identity-tag/my-tags', method: 'POST' }); + if (res && res.data && (res.data.code === 0 || res.data.code === 200)) { + const d = res.data.data || {}; + const merged = [ + ...(d.dashou || []), + ...(d.zuzhang || []), + ...(d.guanshi || []), + ]; + this.setData({ identityTagList: merged }); + } + } catch (e) { + /* 静默 */ + } + }, + async _fetchDashouInfoSilent() { const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' }); if (res && res.data.code == 200) { @@ -1015,6 +1100,14 @@ Page(createPage({ onTapAuthItem(e) { const type = e.currentTarget.dataset.type; + if (type === 'staff') { + if (isStaffMode()) { + enterLockedRole('shangjia', getApp()); + } else { + wx.navigateTo({ url: '/pages/staff-join/staff-join' }); + } + return; + } if (type === 'shangjia') { this.onTapShangjiaAuth(); return; @@ -1038,6 +1131,21 @@ Page(createPage({ wx.navigateTo({ url: '/pages/verify/verify?type=shangjia' }); }, goToReceiveOrder() { wx.navigateTo({ url: '/pages/accept-order/accept-order' }) }, + goToDashouExam() { wx.navigateTo({ url: '/pages/dashou-exam/dashou-exam' }) }, + + async loadExamStatus() { + try { + const res = await request({ url: '/jituan/dashou-exam/status', method: 'POST' }); + const body = res?.data; + if (body && (body.code === 200 || body.code === 0) && body.data) { + const d = body.data; + this.setData({ + examEnabled: !!d.exam_enabled, + examPassed: !!d.exam_passed, + }); + } + } catch (e) { /* 静默 */ } + }, goToMyOrders() { wx.navigateTo({ url: '/pages/fighter-orders/fighter-orders' }) }, goToMyPunishment() { wx.navigateTo({ url: '/pages/penalty/penalty/penalty' }) }, goToRecharge() { wx.navigateTo({ url: '/pages/fighter-recharge/fighter-recharge' }) }, @@ -1045,7 +1153,33 @@ Page(createPage({ const type = e?.currentTarget?.dataset?.type || 'dashou'; wx.navigateTo({ url: `/pages/fighter-rank/fighter-rank?type=${type}` }); }, - goToGuanzhuKs() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) }, + goToGuanzhuKs() { + wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }); + }, + + openPindaoModal() { + const app = getApp(); + const cfg = getPindaoConfig(app); + const images = resolvePindaoImages(app); + this.setData({ + pindaoVisible: true, + pindaoTitle: cfg.title || '频道', + pindaoChannelNo: cfg.channel_no || '', + pindaoImages: images, + }); + refreshPindaoConfig(app).then(({ cfg: latest, images: latestImages }) => { + if (!this.data.pindaoVisible) return; + this.setData({ + pindaoTitle: latest.title || '频道', + pindaoChannelNo: latest.channel_no || '', + pindaoImages: latestImages, + }); + }).catch(() => {}); + }, + + closePindaoModal() { + this.setData({ pindaoVisible: false }); + }, goToKaoheDafen() { wx.navigateTo({ url: '/pages/assess-score/assess-score' }) }, goToKaoheJilu() { wx.navigateTo({ url: '/pages/assess-log/assess-log' }) }, goToKaoheZhongxin() { wx.navigateTo({ url: '/pages/assess-center/assess-center' }) }, diff --git a/pages/fighter/fighter.json b/pages/fighter/fighter.json index 8458bf8..a31615c 100644 --- a/pages/fighter/fighter.json +++ b/pages/fighter/fighter.json @@ -2,7 +2,8 @@ "usingComponents": { "global-notification": "/components/global-notification/global-notification", "chenghao-tag": "/components/chenghao-tag/chenghao-tag", - "tab-bar": "/tab-bar/index" + "tab-bar": "/tab-bar/index", + "pindao-modal": "/components/pindao-modal/pindao-modal" }, "navigationStyle": "custom", "backgroundColor": "#fff8e1", diff --git a/pages/fighter/fighter.wxml b/pages/fighter/fighter.wxml index 8f9bf1a..b9f6e40 100644 --- a/pages/fighter/fighter.wxml +++ b/pages/fighter/fighter.wxml @@ -26,14 +26,23 @@ - 我的 + + 我的 + - - - - - + - + + + + - + @@ -70,6 +82,11 @@ + + + + + @@ -85,10 +102,14 @@ - - @@ -217,6 +242,7 @@ 在线客服 关注快手 + 频道 联系邀请人 用户规则 返回点单端 @@ -236,3 +262,10 @@ + diff --git a/pages/fighter/fighter.wxss b/pages/fighter/fighter.wxss index d10bfb2..120d290 100644 --- a/pages/fighter/fighter.wxss +++ b/pages/fighter/fighter.wxss @@ -40,6 +40,19 @@ page { justify-content: center; } +.nav-bar-actions { + position: relative; + justify-content: center; +} + +.nav-refresh-ico { + position: absolute; + right: 24rpx; + width: 44rpx; + height: 44rpx; + padding: 8rpx; +} + .nav-title { font-size: 34rpx; font-weight: 700; @@ -134,6 +147,20 @@ page { opacity: 0.6; } +.user-header-actions { + display: flex; + align-items: center; + gap: 16rpx; + flex-shrink: 0; +} + +.header-action-ico { + width: 48rpx; + height: 48rpx; + padding: 6rpx; + flex-shrink: 0; +} + .setting-ico { width: 53rpx; height: 53rpx; @@ -233,6 +260,23 @@ page { margin-right: 2%; } +.recharge-text-row { + margin: 20rpx 24rpx 0; + gap: 16rpx; +} + +.recharge-text-btn { + flex: 1; + text-align: center; + padding: 22rpx 12rpx; + border-radius: 16rpx; + font-size: 28rpx; + font-weight: 600; + color: #492f00; + background: linear-gradient(180deg, #fff8e1, #ffe8b8); + border: 1rpx solid rgba(201, 169, 98, 0.45); +} + .freeze-row { margin: 16rpx 30rpx 0; padding: 20rpx 10rpx; @@ -356,11 +400,35 @@ page { .order-nav { padding: 10rpx 0 20rpx; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-items: flex-start; } .nav-item { - width: 25%; + width: 20%; + box-sizing: border-box; padding: 10rpx 0; + position: relative; +} + +.exam-tag { + font-size: 20rpx; + margin-top: 4rpx; + padding: 2rpx 10rpx; + border-radius: 8rpx; +} + +.exam-tag-pass { + color: #52c41a; + background: rgba(82, 196, 26, 0.12); +} + +.exam-tag-pending { + color: #fa8c16; + background: rgba(250, 140, 16, 0.12); } .nav-icon { diff --git a/pages/merchant-home/merchant-home.js b/pages/merchant-home/merchant-home.js index ec6ca8c..b6e59a7 100644 --- a/pages/merchant-home/merchant-home.js +++ b/pages/merchant-home/merchant-home.js @@ -11,6 +11,15 @@ import { fetchMerchantOrderStats, applyOrderStatsToHome } from '../../utils/merc const app = getApp(); +const XYM_HOME_FALLBACK = { + noticeIco: 'https://bintao.xmxym88.com/xcx/bintao/38.png', + statCardBg: 'https://bintao.xmxym88.com/xcx/bintao/3.png', + kefuKeyBtn: 'https://bintao.xmxym88.com/xcx/bintao/13.png', + kefuListBtn: 'https://bintao.xmxym88.com/xcx/bintao/21.png', + iconRegular: 'https://bintao.xmxym88.com/xcx/bintao/74.png', + iconCustom: 'https://bintao.xmxym88.com/xcx/bintao/76.png', +}; + /** 与订单页「全部」Tab 一致的状态筛选 */ const ALL_ORDER_ZHUANGTAI = [1, 2, 3, 4, 5, 6, 7, 8]; const RECENT_ORDER_SIZE = 5; @@ -30,12 +39,12 @@ Page(createPage({ gonggao: '', swiperCurrent: 0, imgUrls: { - noticeIco: '', - statCardBg: '', - kefuKeyBtn: '', - kefuListBtn: '', - iconRegular: '', - iconCustom: '', + noticeIco: XYM_HOME_FALLBACK.noticeIco, + statCardBg: XYM_HOME_FALLBACK.statCardBg, + kefuKeyBtn: XYM_HOME_FALLBACK.kefuKeyBtn, + kefuListBtn: XYM_HOME_FALLBACK.kefuListBtn, + iconRegular: XYM_HOME_FALLBACK.iconRegular, + iconCustom: XYM_HOME_FALLBACK.iconCustom, }, stats: { pendingCount: 0, @@ -155,12 +164,12 @@ Page(createPage({ const icon = (key, fallback) => resolveMiniappIcon(app, key, fallback); this.setData({ imgUrls: { - noticeIco: icon(ICON_KEYS.MERCHANT_HOME_NOTICE, `${homeDir}notice.png`), - statCardBg: icon(ICON_KEYS.MERCHANT_HOME_STAT_BG, `${ossBase}beijing/shangjiaduan/stat_card_bg.png`), - kefuKeyBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_KEY, `${homeDir}kefu_key.png`), - kefuListBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_LIST, `${homeDir}kefu_list.png`), - iconRegular: icon(ICON_KEYS.MERCHANT_HOME_REGULAR, `${homeDir}regular_dispatch.png`), - iconCustom: icon(ICON_KEYS.MERCHANT_HOME_CUSTOM, `${homeDir}custom_dispatch.png`), + noticeIco: icon(ICON_KEYS.MERCHANT_HOME_NOTICE, XYM_HOME_FALLBACK.noticeIco), + statCardBg: icon(ICON_KEYS.MERCHANT_HOME_STAT_BG, `${ossBase}beijing/shangjiaduan/stat_card_bg.png`) || XYM_HOME_FALLBACK.statCardBg, + kefuKeyBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_KEY, XYM_HOME_FALLBACK.kefuKeyBtn), + kefuListBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_LIST, XYM_HOME_FALLBACK.kefuListBtn), + iconRegular: icon(ICON_KEYS.MERCHANT_HOME_REGULAR, XYM_HOME_FALLBACK.iconRegular), + iconCustom: icon(ICON_KEYS.MERCHANT_HOME_CUSTOM, XYM_HOME_FALLBACK.iconCustom), }, }); }, diff --git a/pages/merchant-home/merchant-home.wxml b/pages/merchant-home/merchant-home.wxml index 49adef1..d8f66be 100644 --- a/pages/merchant-home/merchant-home.wxml +++ b/pages/merchant-home/merchant-home.wxml @@ -45,8 +45,8 @@ - - + + @@ -74,28 +74,6 @@ {{stats.pendingAmount}} - - - 成交总量 - {{stats.completedCount}} - - - - 成交总额(元) - {{stats.completedAmount}} - - - - - 退款总量 - {{stats.refundCount}} - - - - 退款总额(元) - {{stats.refundAmount}} - - 今日派单(数) diff --git a/pages/merchant-home/merchant-home.wxss b/pages/merchant-home/merchant-home.wxss index 4a6d535..bfe38b0 100644 --- a/pages/merchant-home/merchant-home.wxss +++ b/pages/merchant-home/merchant-home.wxss @@ -102,6 +102,10 @@ page { height: 56rpx; flex-shrink: 0; margin-right: 12rpx; + background-image: url('https://bintao.xmxym88.com/xcx/bintao/38.png'); + background-size: contain; + background-repeat: no-repeat; + background-position: center; } .sj-notice-txt { @@ -136,6 +140,14 @@ page { background-repeat: no-repeat; } +.sj-fadan-img-btn--left { + background-image: url('https://bintao.xmxym88.com/xcx/bintao/74.png'); +} + +.sj-fadan-img-btn--right { + background-image: url('https://bintao.xmxym88.com/xcx/bintao/76.png'); +} + .sj-fadan-big-btn { flex: 1; height: 128rpx; @@ -179,8 +191,10 @@ page { left: 0; right: 0; bottom: 0; + background-image: url('https://bintao.xmxym88.com/xcx/bintao/3.png'); background-size: 100% auto; background-repeat: no-repeat; + background-position: center top; pointer-events: none; z-index: 0; } diff --git a/pages/merchant-orders/merchant-orders.wxml b/pages/merchant-orders/merchant-orders.wxml index dd9ec81..ebff337 100644 --- a/pages/merchant-orders/merchant-orders.wxml +++ b/pages/merchant-orders/merchant-orders.wxml @@ -47,7 +47,11 @@ - {{selectedStaffLabel}} + + 客服 + {{selectedStaffLabel}} + + 清除 @@ -63,12 +67,6 @@ - - 派单 {{orderStats.dispatch_count}} / ¥{{orderStats.dispatch_amount}} - 成交 {{orderStats.completed_count}} / ¥{{orderStats.completed_amount}} - 退款 {{orderStats.refund_count}} / ¥{{orderStats.refund_amount}} - 待结 {{orderStats.pending_count}} / ¥{{orderStats.pending_amount}} - {{item.name}} diff --git a/pages/merchant-orders/merchant-orders.wxss b/pages/merchant-orders/merchant-orders.wxss index 8b6334a..1ea29ad 100644 --- a/pages/merchant-orders/merchant-orders.wxss +++ b/pages/merchant-orders/merchant-orders.wxss @@ -154,39 +154,77 @@ page { border-radius: 24rpx; } + /* ========== 客服筛选 ========== */ .staff-filter-row { display: flex; align-items: center; - gap: 16rpx; - padding: 12rpx 24rpx; + padding: 0 24rpx 16rpx; background: #fff; border-bottom: 1rpx solid #f0f0f0; + gap: 16rpx; + flex-shrink: 0; } .staff-filter-pill { - padding: 10rpx 24rpx; - background: #f0f7ff; - color: #1565C0; - border-radius: 24rpx; - font-size: 24rpx; + display: inline-flex; + align-items: center; + max-width: 100%; + padding: 12rpx 24rpx; + border-radius: 32rpx; + background: #f7f7f7; + border: 1rpx solid #eee; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); } - .staff-filter-clear { - font-size: 24rpx; + .staff-filter-pill--active { + background: linear-gradient(180deg, #fff8e1, #ffe9b8); + border-color: #e8c547; + box-shadow: 0 4rpx 12rpx rgba(232, 197, 71, 0.25); + } + .staff-filter-tag { + flex-shrink: 0; + font-size: 22rpx; + font-weight: 700; + color: #8a6d2b; + padding: 4rpx 12rpx; + margin-right: 12rpx; + border-radius: 16rpx; + background: rgba(255, 255, 255, 0.65); + } + .staff-filter-pill--active .staff-filter-tag { + background: rgba(255, 255, 255, 0.85); + color: #492f00; + } + .staff-filter-value { + flex: 1; + min-width: 0; + font-size: 26rpx; + font-weight: 600; + color: #333; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .staff-filter-pill--active .staff-filter-value { + color: #492f00; + } + .staff-filter-arrow { + flex-shrink: 0; + margin-left: 8rpx; + font-size: 22rpx; color: #999; } - .sidebar-stats { - padding: 12rpx 8rpx 16rpx; - margin-bottom: 8rpx; - border-bottom: 1rpx solid #eee; + .staff-filter-pill--active .staff-filter-arrow { + color: #8a6d2b; } - .sb-line { - display: block; - font-size: 20rpx; - color: #888; - line-height: 1.6; - word-break: break-all; + .staff-filter-clear { + flex-shrink: 0; + font-size: 24rpx; + color: #c9a227; + padding: 10rpx 16rpx; + border-radius: 24rpx; + background: #fff8e8; + border: 1rpx solid #f0d89a; } - .sb-line.accent { color: #E65100; font-weight: 600; } - + /* ========== 待结算提示条(保留原样式) ========== */ .sj-pending-tip { margin: 20rpx 24rpx; diff --git a/pages/merchant/merchant.js b/pages/merchant/merchant.js index fcb530e..caecd17 100644 --- a/pages/merchant/merchant.js +++ b/pages/merchant/merchant.js @@ -499,6 +499,7 @@ Page(createPage({ }, goToRanking() { wx.navigateTo({ url: '/pages/fighter-rank/fighter-rank?type=shangjia' }); }, goToMessages() { wx.navigateTo({ url: '/pages/merchant-penalty/merchant-penalty' }); }, + goToDataStats() { wx.navigateTo({ url: '/pages/merchant-data-stats/merchant-data-stats' }); }, }, { roleConfig: { role: 'shangjia', diff --git a/pages/merchant/merchant.wxml b/pages/merchant/merchant.wxml index a62bc70..0e3586d 100644 --- a/pages/merchant/merchant.wxml +++ b/pages/merchant/merchant.wxml @@ -96,54 +96,19 @@ - - 经营数据 - - - {{orderStats.pending_count}} - 待结算(单) - ¥{{orderStats.pending_amount}} - - - {{orderStats.completed_count}} - 成交总量 - ¥{{orderStats.completed_amount}} - - - - - {{orderStats.refund_count}} - 退款总量 - ¥{{orderStats.refund_amount}} - - - {{orderStats.dispatch_count}} - 发单总量 - ¥{{orderStats.dispatch_amount}} - - - {{jinriliushui}} - 今日流水 - - - {{jinyueliushui}} - 今月流水 - - - - 处罚待处理:罚单 {{penaltyStats.fakuan_pending}}(¥{{penaltyStats.fakuan_pending_amount}})· 积分 {{penaltyStats.jifen_pending}} - - - + + {{jinriliushui}} + 今日流水 + + + {{jinyueliushui}} + 今月流水 + {{jinridingdan}} 今日派单 - - {{jinrituikuan}} - 今日退款 - @@ -183,6 +148,10 @@ 链接派单 + + + 经营数据 + 客服邀请码 diff --git a/pages/merchant/merchant.wxss b/pages/merchant/merchant.wxss index 4522637..5592375 100644 --- a/pages/merchant/merchant.wxss +++ b/pages/merchant/merchant.wxss @@ -181,40 +181,6 @@ page { margin-top: 16rpx; } -.data-board { margin-top: 16rpx; padding-bottom: 8rpx; } -.data-highlight { - display: flex; - padding: 8rpx 0 16rpx; - border-bottom: 1rpx solid #f0f0f0; - margin-bottom: 12rpx; -} -.data-hl-item { flex: 1; text-align: center; } -.data-hl-num { font-size: 40rpx; font-weight: 700; color: #333; display: block; } -.data-hl-num.accent { color: #E65100; } -.data-hl-lbl { font-size: 24rpx; color: #888; display: block; margin-top: 4rpx; } -.data-hl-sub { font-size: 22rpx; color: #1565C0; display: block; margin-top: 4rpx; } -.data-grid { - display: flex; - flex-wrap: wrap; -} -.data-cell { - width: 50%; - box-sizing: border-box; - padding: 12rpx 8rpx; - text-align: center; -} -.data-cell-num { font-size: 30rpx; font-weight: 600; color: #333; display: block; } -.data-cell-lbl { font-size: 22rpx; color: #999; display: block; margin-top: 4rpx; } -.data-cell-sub { font-size: 20rpx; color: #1565C0; display: block; } -.penalty-mini { - margin-top: 8rpx; - padding-top: 12rpx; - border-top: 1rpx solid #f0f0f0; - font-size: 22rpx; - color: #888; - text-align: center; -} - .unreg-area { flex: 1; padding: 40rpx 0 16rpx;