From fc0ee9a4d10ba9bb57c89c748da295fcf2b786c0 Mon Sep 17 00:00:00 2001 From: XingQue Date: Sat, 27 Jun 2026 06:04:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=A4=87=E4=BB=BD=EF=BC=9A?= =?UTF-8?q?=E5=95=86=E5=AE=B6UI=E8=B0=83=E6=95=B4=E5=89=8D=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E5=AE=8C=E6=95=B4=E7=89=88=E6=9C=AC=EF=BC=88=E6=9C=AA?= =?UTF-8?q?=E6=8E=A8=E9=80=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- app.json | 4 + pages/accept-order/accept-order.js | 353 +-- pages/accept-order/accept-order.json | 2 - pages/accept-order/accept-order.wxml | 170 +- pages/accept-order/accept-order.wxss | 11 +- .../fighter-order-detail.js | 1480 ++++++------ pages/fighter-orders/fighter-orders.js | 60 +- pages/fighter-orders/fighter-orders.json | 3 +- pages/fighter-rank/fighter-rank.js | 79 +- pages/fighter-rank/fighter-rank.wxml | 8 +- pages/fighter-recharge/fighter-recharge.js | 1991 ++++++++--------- pages/fighter-recharge/fighter-recharge.wxml | 35 +- pages/fighter-recharge/fighter-recharge.wxss | 66 +- pages/fighter/fighter.js | 206 +- pages/fighter/fighter.json | 3 +- pages/fighter/fighter.wxml | 61 +- pages/fighter/fighter.wxss | 70 +- .../merchant-data-stats.js | 67 + .../merchant-data-stats.json | 5 + .../merchant-data-stats.wxml | 56 + .../merchant-data-stats.wxss | 84 + .../merchant-kefu-list/merchant-kefu-list.js | 32 +- .../merchant-kefu-list.wxml | 12 +- .../merchant-kefu-list.wxss | 13 + pages/order-pool/order-pool.js | 172 +- pages/order-pool/order-pool.json | 19 +- pages/order-pool/order-pool.wxml | 545 +++-- pages/order-pool/order-pool.wxss | 847 +++++-- 28 files changed, 3190 insertions(+), 3264 deletions(-) create mode 100644 pages/merchant-data-stats/merchant-data-stats.js create mode 100644 pages/merchant-data-stats/merchant-data-stats.json create mode 100644 pages/merchant-data-stats/merchant-data-stats.wxml create mode 100644 pages/merchant-data-stats/merchant-data-stats.wxss diff --git a/app.json b/app.json index 3ee0210..b1fe7c8 100644 --- a/app.json +++ b/app.json @@ -109,6 +109,10 @@ "root": "pages/manager-rank", "pages": ["manager-rank"] }, + { + "root": "pages/merchant-data-stats", + "pages": ["merchant-data-stats"] + }, { "root": "pages/merchant-dispatch", "pages": ["merchant-dispatch"] diff --git a/pages/accept-order/accept-order.js b/pages/accept-order/accept-order.js index c23fe70..749dfe7 100644 --- a/pages/accept-order/accept-order.js +++ b/pages/accept-order/accept-order.js @@ -1,14 +1,8 @@ // 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: { @@ -35,7 +29,7 @@ Page({ // 4. 刷新控制字段 scrollViewRefreshing: false, lastRefreshTime: 0, - refreshCooldown: 0, + refreshCooldown: 2000, isLoadingMore: false, // 5. 切换类型冷却 @@ -52,59 +46,13 @@ Page({ // 商品轮播展示(只读 globalData,无额外接口) lunboList: [], - gonggao: '', - - examRequired: false, - examPassed: false, - _examChecked: false, }, - 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; - } - + async onLoad(options) { + this.syncShopBannerFromGlobal(); this.loadGlobalStatus(); - 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, - }; + await this.loadShangpinLeixing(); + PopupService.checkAndShow(this, 'jiedan'); }, onHide: function () { @@ -114,84 +62,63 @@ Page({ } }, - async onShow() { - if (!app.globalData._dashouPhoneChecked) { - const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' }); - if (!phoneOk) return; - app.globalData._dashouPhoneChecked = true; - } - + onShow() { + this.syncShopBannerFromGlobal(); this.registerNotificationComponent(); - await this.syncDashouProfileFromServer(); - warmupPindaoConfig(app); - + this.loadGlobalStatus(); if (wx.getStorageSync('uid')) { reconnectForRole('dashou'); if (app.startImWhenReady) app.startImWhenReady(); + this.refreshDashouProfileSilent(); } - - 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; - }); + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); } }, - /** 进入页面静默刷新(无 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) => { + /** 同步点单端已加载的商品轮播图,仅展示用 */ + syncShopBannerFromGlobal() { + const oss = app.globalData.ossImageUrl || ''; + const lunboList = (app.globalData.shangpinlunbo || []).map((url) => { if (!url) return ''; return url.startsWith('http') ? url : oss + url; }).filter(Boolean); + this.setData({ lunboList }); }, - 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 || ''; + 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; } - } - - const lunboList = this.processLunboUrls(lunboRaw); - const gonggao = gonggaoText; - this.setData({ lunboList, gonggao }); - return { lunboList, gonggao }; + this.setData({ + zhuanghaoStatus: patch.zhanghaoStatus, + dashouzhuangtai: patch.dashouzhuangtai, + huiyuanList: patch.clumber, + yajin: patch.yajin, + jifen: patch.jifen, + }); + } catch (e) {} }, registerNotificationComponent() { @@ -217,22 +144,9 @@ 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(autoLoadOrders = false, preserveSelection = false, showLoading = true) { - if (showLoading) wx.showLoading({ title: '加载商品类型...' }); - const prevId = this.data.xuanzhongLeixingId; + async loadShangpinLeixing() { + wx.showLoading({ title: '加载商品类型...' }); try { const res = await request({ url: '/dingdan/dsqdhqddlx', @@ -249,16 +163,14 @@ 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: selectedId, + xuanzhongLeixingId: processedList[0]?.id || null }); - if (autoLoadOrders && selectedId) { - await this.loadDingdanList(true); - await this.loadBankuaiBiaoqian(); + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + // 🆕 加载板块标签 + this.loadBankuaiBiaoqian(); } } else { wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' }); @@ -266,7 +178,7 @@ Page({ } catch (error) { wx.showToast({ title: '网络错误,加载失败', icon: 'none' }); } finally { - if (showLoading) wx.hideLoading(); + wx.hideLoading(); } }, @@ -333,8 +245,8 @@ Page({ xuanzhongBiaoqianId: 0 // 重置标签筛选 }); await this.loadDingdanList(true); + // 🆕 切换类型后加载新标签 await this.loadBankuaiBiaoqian(); - this.persistPageCache(); } catch (error) { console.error('切换类型失败:', error); } finally { @@ -354,24 +266,19 @@ Page({ hasMore: true }); await this.loadDingdanList(true); - this.persistPageCache(); }, // 加载订单列表 - async loadDingdanList(isRefresh = false, silent = false) { - if ((!silent && this.data.isLoading) || !this.data.xuanzhongLeixingId) return; - if (silent && this._listRequesting) return; + async loadDingdanList(isRefresh = false) { + if (this.data.isLoading || !this.data.xuanzhongLeixingId) return; const loadPage = isRefresh ? 1 : this.data.page; if (!isRefresh && !this.data.hasMore) return; - if (!silent) { - this.setData({ - isLoading: true, - isLoadingMore: !isRefresh, - }); - } - this._listRequesting = true; + this.setData({ + isLoading: true, + isLoadingMore: !isRefresh + }); try { const res = await request({ @@ -391,7 +298,6 @@ Page({ isLoadingMore: false, scrollViewRefreshing: false }); - this._listRequesting = false; if (res.data.code === 200 || res.data.code === 0) { const newList = res.data.data.list || []; @@ -407,7 +313,6 @@ Page({ page: loadPage, hasMore: hasMore }); - this.persistPageCache(); if (isRefresh) { this.setData({ lastRefreshTime: Date.now() }); @@ -422,28 +327,20 @@ Page({ isLoadingMore: false, scrollViewRefreshing: false }); - this._listRequesting = false; - if (!silent) { - wx.showToast({ title: '网络请求失败', icon: 'none' }); - } + 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 (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; + if (item.tupian) { + fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; } else { - fullTupianUrl = '/images/default-order.png'; + const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id); + fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png'; } const isZhiding = item.zhuangtai === 7; @@ -456,32 +353,25 @@ Page({ } const zhidingNicheng = item.zhiding_nicheng || ''; - // 订单要求指定会员时,核对用户是否持有该会员类型 + // 🆕 判断用户是否有订单所需的会员(仅当订单要求会员类型且存在huiyuan_id) let hasRequiredMember = true; if (item.yaoqiuleixing == 1 && item.huiyuan_id) { - hasRequiredMember = userHasHuiyuan(this.data.huiyuanList, item.huiyuan_id); + const userHasIt = this.data.huiyuanList.some(h => h.huiyuanid == item.huiyuan_id); + hasRequiredMember = userHasIt; } - 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, - ...tags, - shangjia_youzhi: !!item.shangjia_youzhi, + // 🆕 三层标签(后端返回,直接保留) + xuqiu_biaoqian: item.xuqiu_biaoqian || [], + dashou_biaoqian: item.dashou_biaoqian || [], + shangjia_biaoqian: item.shangjia_biaoqian || [], // 🆕 是否有查看价格的权限 hasRequiredMember: hasRequiredMember, }; @@ -519,50 +409,11 @@ 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' }); @@ -587,7 +438,7 @@ Page({ } // 校验5: 会员要求 if (dingdanItem.yaoqiuleixing == 1) { - const hasHuiyuan = userHasHuiyuan(this.data.huiyuanList, dingdanItem.huiyuan_id); + const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); if (!hasHuiyuan) { wx.showToast({ title: '未开通对应会员,无法抢单', @@ -653,7 +504,6 @@ Page({ item => item.dingdan_id !== dingdanItem.dingdan_id ); that.setData({ dingdanList: newList }); - that.persistPageCache(); } else { wx.showToast({ title: qiangdanRes.data.msg || '抢单失败', @@ -685,14 +535,42 @@ 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); } }, - async onPullDownRefresh() { + 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; + } + if (this.data.isLoading) { this.setData({ scrollViewRefreshing: false }); return; @@ -700,25 +578,14 @@ Page({ this.setData({ scrollViewRefreshing: true, - lastRefreshTime: Date.now(), + lastRefreshTime: now, page: 1, - hasMore: true, + hasMore: true }); - 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 { + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + } else { this.setData({ scrollViewRefreshing: false }); } } diff --git a/pages/accept-order/accept-order.json b/pages/accept-order/accept-order.json index d496762..e7e7be0 100644 --- a/pages/accept-order/accept-order.json +++ b/pages/accept-order/accept-order.json @@ -1,8 +1,6 @@ { "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 4088337..389b531 100644 --- a/pages/accept-order/accept-order.wxml +++ b/pages/accept-order/accept-order.wxml @@ -1,4 +1,4 @@ - + @@ -38,12 +38,6 @@ - - - - {{gonggao}} - - @@ -80,7 +74,7 @@ - + @@ -196,6 +190,16 @@ + + + 指定 + + + + {{item.zhiding_nicheng || '指定接单员'}} + + + @@ -208,20 +212,6 @@ - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - - @@ -236,9 +226,9 @@ - + - 备注:{{item.beizhu || '暂无'}} + 备注:{{item.beizhu}} @@ -246,10 +236,10 @@ 需求标签 - - - - + + + + @@ -270,81 +260,6 @@ - - - - - - - - - - - - - {{item.jieshao || '暂无介绍'}} - - 优质商家 - - - - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - - - - {{item.dashou_fencheng || 0}} - - - 未开通会员 - - - 商家备注:{{item.beizhu || '暂无'}} - - - - - - - - - - - - - - - - - - - - - - - {{item.sjnicheng || '未知商家'}} - 发布于 {{item.creat_time}} - - - 抢单 - - - 商家派单 - - - - - @@ -361,23 +276,19 @@ - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - + + + 指定 + + + + {{item.zhiding_nicheng || '指定接单员'}} + + - + {{item.sjnicheng || '未知商家'}} @@ -407,33 +318,24 @@ - + - 商家备注:{{item.beizhu || '暂无'}} + 商家备注:{{item.beizhu}} - + - + + + - - - - + - - - - + - - - - - diff --git a/pages/accept-order/accept-order.wxss b/pages/accept-order/accept-order.wxss index 394b5ff..cecbb2b 100644 --- a/pages/accept-order/accept-order.wxss +++ b/pages/accept-order/accept-order.wxss @@ -1,11 +1,5 @@ -/* 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; @@ -132,7 +126,6 @@ page { flex: 1; height: 0; -webkit-overflow-scrolling: touch; - background: transparent; } .scroll-bottom-spacer { @@ -770,3 +763,5 @@ page { 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 0051b27..1703829 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.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' }) - } - } +// 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' }) + } + } }) \ No newline at end of file diff --git a/pages/fighter-orders/fighter-orders.js b/pages/fighter-orders/fighter-orders.js index 5d778af..8323223 100644 --- a/pages/fighter-orders/fighter-orders.js +++ b/pages/fighter-orders/fighter-orders.js @@ -49,14 +49,7 @@ Page(createPage({ onLoad() { wx.setNavigationBarTitle({ title: '我的接单' }); - this.loadShangpinLeixing().then(() => { - if (this.data.xuanzhongLeixingId) { - return this.loadCurrentStatusOrders(true); - } - }).finally(() => { - this._ordersSessionReady = true; - this._skipShowRefresh = true; - }); + this.loadShangpinLeixing(); this.registerNotificationComponent(); }, @@ -66,15 +59,8 @@ Page(createPage({ reconnectForRole('dashou'); if (app.startImWhenReady) app.startImWhenReady(); } - 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; - }); + if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) { + this.loadCurrentStatusOrders(true); } }, @@ -155,21 +141,17 @@ Page(createPage({ }, // 加载订单(核心) - async loadCurrentStatusOrders(isRefresh = false, silent = false) { + async loadCurrentStatusOrders(isRefresh = false) { const key = this.data.currentStatusKey; const tabData = this.data.dsDingdanShuju[key]; - if (tabData.isLoading && !silent) return; - if (silent && this._listRequesting) return; + if (tabData.isLoading) return; const page = isRefresh ? 1 : tabData.page; - if (!silent) { - this.setData({ - [`dsDingdanShuju.${key}.isLoading`]: true, - isLoading: true, - isLoadingMore: !isRefresh, - }); - } - this._listRequesting = true; + this.setData({ + [`dsDingdanShuju.${key}.isLoading`]: true, + isLoading: true, + isLoadingMore: !isRefresh + }); try { const apiUrl = this.data.orderType === 'peihu' @@ -226,20 +208,14 @@ Page(createPage({ } } catch (err) { console.error('加载订单失败', err); - 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; + wx.showToast({ title: err.message || '加载失败', icon: 'none' }); + this.setData({ + [`dsDingdanShuju.${key}.isLoading`]: false, + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + this.refreshCurrentListView(); } }, diff --git a/pages/fighter-orders/fighter-orders.json b/pages/fighter-orders/fighter-orders.json index 44bcb57..60b86d2 100644 --- a/pages/fighter-orders/fighter-orders.json +++ b/pages/fighter-orders/fighter-orders.json @@ -1,7 +1,6 @@ { "usingComponents": { - "global-notification": "/components/global-notification/global-notification", - "tab-bar": "/tab-bar/index" + "global-notification": "/components/global-notification/global-notification" }, "navigationBarTitleText": "我的接单", "enablePullDownRefresh": false, diff --git a/pages/fighter-rank/fighter-rank.js b/pages/fighter-rank/fighter-rank.js index 452b687..7d72942 100644 --- a/pages/fighter-rank/fighter-rank.js +++ b/pages/fighter-rank/fighter-rank.js @@ -1,14 +1,9 @@ /** - * 排行榜 - * 默认 POST /yonghu/phbhqsj - * 星之界(xzj) POST /yonghu/xzjphbhqsj(邀请人数排序等专用规则) + * 排行榜 POST /yonghu/phbhqsj + * 参数: shenfen(dashou|guanshi|zuzhang|shangjia), riqi(今日|本周|本月|总榜|昨日|上周|上月) */ 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: '接单员' }, @@ -32,7 +27,6 @@ const ROLE_META = { title: '接单员排行榜', sortField: 'chengjiao_zonge', sortLabel: '分红总额', - mainType: 'money', metrics: [ { field: 'jiedan_zongliang', label: '接单量', type: 'int' }, { field: 'jiedan_zonge', label: '接单额', type: 'money' }, @@ -43,7 +37,6 @@ 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' }, @@ -53,7 +46,6 @@ const ROLE_META = { title: '组长排行榜', sortField: 'shouru_zonge', sortLabel: '收入总额', - mainType: 'money', metrics: [ { field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' }, { field: 'fenyong_jine', label: '分佣', type: 'money' }, @@ -63,7 +55,6 @@ 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' }, @@ -72,55 +63,6 @@ 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 @@ -157,7 +99,7 @@ Page({ onLoad(options) { const type = options.type || options.rankType || 'dashou' - const validRole = ACTIVE_ROLE_META[type] ? type : 'dashou' + const validRole = ROLE_META[type] ? type : 'dashou' this.initPage() this.applyRole(validRole, false) this.fetchRankList() @@ -220,7 +162,7 @@ Page({ }, applyRole(role, reload = true) { - const meta = ACTIVE_ROLE_META[role] + const meta = ROLE_META[role] wx.setNavigationBarTitle({ title: meta.title }) this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel }) if (reload) this.fetchRankList() @@ -254,7 +196,7 @@ Page({ }, normalizeItem(raw, index, role) { - const meta = ACTIVE_ROLE_META[role] + const meta = ROLE_META[role] const app = getApp() const uid = raw.yonghuid || raw.uid || '' const nicheng = raw.nicheng || raw.nick || '用户' @@ -267,19 +209,12 @@ 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, - mainType, - mainPrefix: mainType === 'money' ? '¥' : '', - mainValue, + mainValue: this.formatMoney(raw[meta.sortField]), mainLabel: meta.sortLabel, metrics, } @@ -289,7 +224,7 @@ Page({ this.setData({ isLoading: true, isEmpty: false }) try { const res = await request({ - url: RANK_API, + url: '/yonghu/phbhqsj', 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 e486bee..8c4db95 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].mainPrefix}}{{topThree[1].mainValue}} + ¥{{topThree[1].mainValue}} {{topThree[1].mainLabel}} @@ -70,7 +70,7 @@ {{topThree[0].nicheng}} ID {{topThree[0].uid}} - {{topThree[0].mainPrefix}}{{topThree[0].mainValue}} + ¥{{topThree[0].mainValue}} {{topThree[0].mainLabel}} @@ -88,7 +88,7 @@ {{topThree[2].nicheng}} ID {{topThree[2].uid}} - {{topThree[2].mainPrefix}}{{topThree[2].mainValue}} + ¥{{topThree[2].mainValue}} {{topThree[2].mainLabel}} @@ -120,7 +120,7 @@ - {{item.mainPrefix}}{{item.mainValue}} + ¥{{item.mainValue}} {{item.mainLabel}} diff --git a/pages/fighter-recharge/fighter-recharge.js b/pages/fighter-recharge/fighter-recharge.js index 9e7b957..ebb1da2 100644 --- a/pages/fighter-recharge/fighter-recharge.js +++ b/pages/fighter-recharge/fighter-recharge.js @@ -1,1018 +1,975 @@ -// 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 }); - }, +// 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 }); + }, }); \ No newline at end of file diff --git a/pages/fighter-recharge/fighter-recharge.wxml b/pages/fighter-recharge/fighter-recharge.wxml index 42fa21e..a5187df 100644 --- a/pages/fighter-recharge/fighter-recharge.wxml +++ b/pages/fighter-recharge/fighter-recharge.wxml @@ -47,12 +47,6 @@ 已拥有 - - 可购体验 - - - 体验已用/不可购 - {{item.mingzi}} @@ -62,11 +56,7 @@ ¥ {{item.jiage}} - /{{item.formal_days || 30}}天 - - - 体验 - ¥{{item.trial_price}}/{{item.trial_days}}天 + /30天 @@ -117,27 +107,20 @@ 价格: ¥{{currentHuiyuan.jiage}} - /{{currentHuiyuan.formal_days || 30}}天 已激活,{{currentHuiyuan.buyInfo.daoqi}}后到期 - 正式会员支持微信或余额抵扣 - - 体验版仅微信支付 ¥{{currentHuiyuan.trial_price}}/{{currentHuiyuan.trial_days}}天,终身1次 - - - 本俱乐部尚未为该会员开启体验版,请联系管理员在后台配置 - + 激活会员特权 + bindtap="onBuyHuiyuanClick" data-id="{{currentHuiyuan.id}}"> - {{currentHuiyuan.isBought ? '正式续费' : '购买正式版'}} + {{currentHuiyuan.isBought ? '立即续费' : '立即激活'}} @@ -145,16 +128,6 @@ - - - 购买体验版 - diff --git a/pages/fighter-recharge/fighter-recharge.wxss b/pages/fighter-recharge/fighter-recharge.wxss index 08f6d12..2f808eb 100644 --- a/pages/fighter-recharge/fighter-recharge.wxss +++ b/pages/fighter-recharge/fighter-recharge.wxss @@ -1,5 +1,4 @@ -/* pages/dashou-chongzhi/index.wxss - 逍遥梦主题覆盖 + 机甲基础样式 */ -@import '../../styles/dashou-xym-recharge-theme.wxss'; +/* pages/dashou-chongzhi/index.wxss - 完整保留原有样式,仅删除导航栏相关,调整间距和字体 */ /* ==================== 基础样式 ==================== */ .page-container { @@ -677,32 +676,6 @@ 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; @@ -882,35 +855,11 @@ /* 购买区域 */ .buy-section { display: flex; - flex-direction: column; - align-items: stretch; - gap: 20rpx; + align-items: center; + justify-content: space-between; 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; @@ -979,11 +928,6 @@ 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); } @@ -1758,4 +1702,6 @@ display: flex !important; align-items: center !important; justify-content: center !important; - } \ No newline at end of file + } + +@import '../../styles/dashou-xym-recharge-theme.wxss'; \ No newline at end of file diff --git a/pages/fighter/fighter.js b/pages/fighter/fighter.js index 1a5954d..99a60b9 100644 --- a/pages/fighter/fighter.js +++ b/pages/fighter/fighter.js @@ -2,18 +2,6 @@ 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' @@ -53,7 +41,6 @@ Page(createPage({ zuzhangInviterCache: null, chenghaoList: [], guanshiChenghaoList: [], - identityTagList: [], gszhstatus: '', yaoqingzongshu: 0, fenyongzonge: '0.00', @@ -78,25 +65,13 @@ 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', @@ -108,7 +83,7 @@ Page(createPage({ listBg: dsBase + 'list-card-bg.png', topBg: iconBase + 'top-bg.jpg', cardBg: iconBase + 'card-bg.jpg', - iconRefresh: icon(ICON_KEYS.ICON_REFRESH, gsBase + 'icon-refresh.png'), + iconRefresh: gsBase + 'icon-refresh.png', iconCopy: gsBase + 'icon-copy.png', iconVip: dsBase + 'icon-vip.png', iconArrowLight: dsBase + 'icon-arrow-light.png', @@ -143,7 +118,6 @@ 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', @@ -154,8 +128,8 @@ Page(createPage({ kefuBannerBg: dsBase + 'kefu-banner-bg.png', totalAssetBg: dsBase + 'total-asset-bg.png', authPanelBg: dsBase + 'auth-panel-bg.png', - bannerVip: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER), - bannerDeposit: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT), + 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', }; }, @@ -203,28 +177,9 @@ Page(createPage({ } } this.checkColdStartPopup('dashouduan'); - this.syncConfiguredAssets(); }, - syncConfiguredAssets() { - const app = getApp(); - const bannerVip = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER); - const bannerDeposit = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT); - 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; - } - + onShow() { migrateLegacyCenterRole(getApp()); lockPrimaryRole('dashou', getApp()); wx.setStorageSync('isJinpai', 0); @@ -235,17 +190,16 @@ 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'); - this.loadExamStatus(); + setTimeout(() => this.refreshAllInfo(false), 300); } 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]; @@ -323,17 +277,12 @@ 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: '去认证' }); } @@ -344,37 +293,35 @@ Page(createPage({ }, async refreshAllInfo(showToast = true) { - 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, - }); + 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 }); } - } catch (e) { - if (showToast) { - wx.showToast({ title: '刷新失败', icon: 'none' }); - } - } finally { - this._profileRefreshing = false; - this.setData({ isLoading: false }); - } + }, 3000); }, refreshDashouInfo() { @@ -385,34 +332,6 @@ 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) { @@ -1096,14 +1015,6 @@ 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; @@ -1127,21 +1038,6 @@ 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' }) }, @@ -1149,33 +1045,7 @@ 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' }); - }, - - 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 }); - }, + goToGuanzhuKs() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) }, 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 a31615c..8458bf8 100644 --- a/pages/fighter/fighter.json +++ b/pages/fighter/fighter.json @@ -2,8 +2,7 @@ "usingComponents": { "global-notification": "/components/global-notification/global-notification", "chenghao-tag": "/components/chenghao-tag/chenghao-tag", - "tab-bar": "/tab-bar/index", - "pindao-modal": "/components/pindao-modal/pindao-modal" + "tab-bar": "/tab-bar/index" }, "navigationStyle": "custom", "backgroundColor": "#fff8e1", diff --git a/pages/fighter/fighter.wxml b/pages/fighter/fighter.wxml index b9f6e40..8f9bf1a 100644 --- a/pages/fighter/fighter.wxml +++ b/pages/fighter/fighter.wxml @@ -26,23 +26,14 @@ - - 我的 - + 我的 - + + + + + - - - - + - + @@ -82,11 +70,6 @@ - - - - - @@ -102,14 +85,10 @@ - - - - 充值会员 - 充值保证金 + + @@ -144,7 +123,7 @@ 接单服务 - + 抢单大厅 @@ -157,11 +136,6 @@ 考核金牌 - - - 接单考试 - {{examPassed ? '已通过' : '待考试'}} - @@ -221,6 +195,7 @@ 考核打分 考核记录 考核中心 + 考核提现 @@ -242,7 +217,6 @@ 在线客服 关注快手 - 频道 联系邀请人 用户规则 返回点单端 @@ -262,10 +236,3 @@ - diff --git a/pages/fighter/fighter.wxss b/pages/fighter/fighter.wxss index 120d290..d10bfb2 100644 --- a/pages/fighter/fighter.wxss +++ b/pages/fighter/fighter.wxss @@ -40,19 +40,6 @@ 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; @@ -147,20 +134,6 @@ 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; @@ -260,23 +233,6 @@ 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; @@ -400,35 +356,11 @@ 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: 20%; - box-sizing: border-box; + width: 25%; 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-data-stats/merchant-data-stats.js b/pages/merchant-data-stats/merchant-data-stats.js new file mode 100644 index 0000000..2721567 --- /dev/null +++ b/pages/merchant-data-stats/merchant-data-stats.js @@ -0,0 +1,67 @@ +import { createPage, request } from '../../utils/base-page.js'; +import { fetchMerchantOrderStats, applyOrderStatsToPage } from '../../utils/merchant-order-stats.js'; + +Page(createPage({ + data: { + statusBar: 20, + loading: true, + canViewFinance: true, + orderStats: { + pending_count: 0, + pending_amount: '0.00', + completed_count: 0, + completed_amount: '0.00', + refund_count: 0, + refund_amount: '0.00', + dispatch_count: 0, + dispatch_amount: '0.00', + }, + penaltyStats: { + fakuan_pending: 0, + fakuan_pending_amount: '0.00', + jifen_pending: 0, + }, + jinriliushui: '0.00', + jinyueliushui: '0.00', + jinridingdan: 0, + jinrituikuan: 0, + }, + + onLoad() { + const sys = wx.getSystemInfoSync(); + this.setData({ statusBar: sys.statusBarHeight || 20 }); + this.loadData(); + }, + + onPullDownRefresh() { + this.loadData().finally(() => wx.stopPullDownRefresh()); + }, + + async loadData() { + this.setData({ loading: true }); + try { + const statsData = await fetchMerchantOrderStats(request, {}); + applyOrderStatsToPage(this, statsData); + try { + const res = await request({ url: '/yonghu/shangjiaxinxi', method: 'POST' }); + if (res.data && res.data.code === 200) { + const d = res.data.data || {}; + this.setData({ + jinriliushui: d.jinriliushui || '0.00', + jinyueliushui: d.jinyueliushui || '0.00', + jinridingdan: d.jinripaidan || 0, + jinrituikuan: d.jinrituikuan || 0, + }); + } + } catch (e) { + console.warn('商家流水加载失败', e); + } + } finally { + this.setData({ loading: false }); + } + }, + + goBack() { + wx.navigateBack(); + }, +})); diff --git a/pages/merchant-data-stats/merchant-data-stats.json b/pages/merchant-data-stats/merchant-data-stats.json new file mode 100644 index 0000000..2cfa46f --- /dev/null +++ b/pages/merchant-data-stats/merchant-data-stats.json @@ -0,0 +1,5 @@ +{ + "navigationStyle": "custom", + "enablePullDownRefresh": true, + "usingComponents": {} +} diff --git a/pages/merchant-data-stats/merchant-data-stats.wxml b/pages/merchant-data-stats/merchant-data-stats.wxml new file mode 100644 index 0000000..b815939 --- /dev/null +++ b/pages/merchant-data-stats/merchant-data-stats.wxml @@ -0,0 +1,56 @@ + + + + + 经营数据 + + + + + + + + {{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}} + 今月流水 + + + {{jinridingdan}} + 今日派单 + + + {{jinrituikuan}} + 今日退款 + + + + 处罚待处理:罚单 {{penaltyStats.fakuan_pending}}(¥{{penaltyStats.fakuan_pending_amount}})· 积分 {{penaltyStats.jifen_pending}} + + + + diff --git a/pages/merchant-data-stats/merchant-data-stats.wxss b/pages/merchant-data-stats/merchant-data-stats.wxss new file mode 100644 index 0000000..f9d7bdd --- /dev/null +++ b/pages/merchant-data-stats/merchant-data-stats.wxss @@ -0,0 +1,84 @@ +@import '../../styles/shangjia-xym-common.wxss'; + +page { background: #fff8e1; } + +.sub-scroll { height: calc(100vh - 120rpx); } + +.data-panel { padding: 24rpx; margin-top: 16rpx; } + +.data-highlight { + margin-bottom: 24rpx; + gap: 16rpx; +} + +.data-hl-item { + flex: 1; + text-align: center; + background: #fff; + border-radius: 16rpx; + padding: 20rpx 12rpx; +} + +.data-hl-num { + display: block; + font-size: 40rpx; + font-weight: 700; + color: #333; +} + +.data-hl-num.accent { color: #e65100; } + +.data-hl-lbl { + display: block; + font-size: 24rpx; + color: #888; + margin-top: 8rpx; +} + +.data-hl-sub { + display: block; + font-size: 22rpx; + color: #999; + margin-top: 4rpx; +} + +.data-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16rpx; +} + +.data-cell { + background: #fff; + border-radius: 16rpx; + padding: 20rpx 16rpx; + text-align: center; +} + +.data-cell-num { + display: block; + font-size: 32rpx; + font-weight: 600; + color: #333; +} + +.data-cell-lbl { + display: block; + font-size: 22rpx; + color: #888; + margin-top: 6rpx; +} + +.data-cell-sub { + display: block; + font-size: 20rpx; + color: #aaa; + margin-top: 4rpx; +} + +.penalty-mini { + margin-top: 20rpx; + font-size: 24rpx; + color: #666; + line-height: 1.5; +} diff --git a/pages/merchant-kefu-list/merchant-kefu-list.js b/pages/merchant-kefu-list/merchant-kefu-list.js index 8364979..8507c85 100644 --- a/pages/merchant-kefu-list/merchant-kefu-list.js +++ b/pages/merchant-kefu-list/merchant-kefu-list.js @@ -34,6 +34,10 @@ Page({ list: [], + displayList: [], + + searchKeyword: '', + isOwner: false, }, @@ -124,7 +128,9 @@ Page({ const raw = (res.data.data && res.data.data.list) || []; - this.setData({ list: this.formatList(raw) }); + this._allList = this.formatList(raw); + + this.applySearchFilter(); } @@ -140,9 +146,31 @@ Page({ goBack() { wx.navigateBack(); }, + applySearchFilter() { + const kw = (this.data.searchKeyword || '').trim().toLowerCase(); + const all = this._allList || []; + if (!kw) { + this.setData({ list: all, displayList: all }); + return; + } + const filtered = all.filter((item) => { + const uid = String(item.uid || '').toLowerCase(); + const remark = String(item.merchant_remark || '').toLowerCase(); + const nick = String(item.nickname || '').toLowerCase(); + return uid.includes(kw) || remark.includes(kw) || nick.includes(kw); + }); + this.setData({ list: all, displayList: filtered }); + }, + onSearchInput(e) { + this.setData({ searchKeyword: e.detail.value || '' }); + this.applySearchFilter(); + }, - goBack() { wx.navigateBack(); }, + clearSearch() { + this.setData({ searchKeyword: '' }); + this.applySearchFilter(); + }, goStaffOrders(e) { const id = e.currentTarget.dataset.id; diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxml b/pages/merchant-kefu-list/merchant-kefu-list.wxml index a4684eb..ab260ae 100644 --- a/pages/merchant-kefu-list/merchant-kefu-list.wxml +++ b/pages/merchant-kefu-list/merchant-kefu-list.wxml @@ -12,11 +12,17 @@ - + + + + + + + - + @@ -153,7 +159,7 @@ - 暂无客服成员 + 暂无客服成员 操作日志 › diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxss b/pages/merchant-kefu-list/merchant-kefu-list.wxss index 12a8fce..9d21e0f 100644 --- a/pages/merchant-kefu-list/merchant-kefu-list.wxss +++ b/pages/merchant-kefu-list/merchant-kefu-list.wxss @@ -155,3 +155,16 @@ font-size: 22rpx; color: #bbb; } + +.filter-row { margin-bottom: 8rpx; } +.search-box { + display: flex; + align-items: center; + background: #fff; + border-radius: 32rpx; + padding: 12rpx 20rpx; + box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); +} +.search-icon { width: 32rpx; height: 32rpx; margin-right: 12rpx; } +.search-input { flex: 1; font-size: 26rpx; } +.search-clear { padding: 8rpx; color: #999; font-size: 24rpx; } diff --git a/pages/order-pool/order-pool.js b/pages/order-pool/order-pool.js index ddef7b8..8c6206a 100644 --- a/pages/order-pool/order-pool.js +++ b/pages/order-pool/order-pool.js @@ -1,9 +1,7 @@ // pages/order-pool/order-pool.js const app = getApp(); import request from '../../utils/request.js'; -import { normalizeOrderTags } from '../../utils/order-tags.js'; import PopupService from '../../services/popupService.js'; -import { ICON_KEYS, resolveMiniappIcon, MERCHANT_GOLD_BANNER_FALLBACK } from '../../utils/miniapp-icons.js'; Page({ data: { @@ -30,7 +28,7 @@ Page({ // 4. 刷新控制字段 scrollViewRefreshing: false, lastRefreshTime: 0, - refreshCooldown: 0, + refreshCooldown: 2000, isLoadingMore: false, // 5. 切换类型冷却时间控制 @@ -47,34 +45,12 @@ Page({ // 商品轮播展示(只读 globalData,无额外接口) lunboList: [], - gonggao: '', - - // 标签筛选 - bankuaiBiaoqian: [], - xuanzhongBiaoqianId: 0, - - iconRefresh: '', - goldBannerUrl: '', }, async onLoad(options) { - const oss = app.globalData.ossImageUrl || ''; - this.syncConfiguredIcons(oss); this.syncShopBannerFromGlobal(); this.loadGlobalStatus(); - const needLoadOrders = !app.globalData._acceptOrderDataLoaded; - this.checkAuthorization(false, needLoadOrders); - if (needLoadOrders && this.data.xuanzhongLeixingId) { - app.globalData._acceptOrderDataLoaded = true; - } - }, - - syncConfiguredIcons(oss) { - const ossBase = oss || app.globalData.ossImageUrl || ''; - this.setData({ - iconRefresh: resolveMiniappIcon(app, ICON_KEYS.ICON_REFRESH, ossBase + 'beijing/guanshiduan/icon-refresh.png'), - goldBannerUrl: resolveMiniappIcon(app, ICON_KEYS.MERCHANT_GOLD_BANNER, MERCHANT_GOLD_BANNER_FALLBACK), - }); + this.checkAuthorization(); }, // 页面隐藏时清理弹窗视图 onHide: function () { @@ -86,10 +62,9 @@ Page({ onShow() { this.syncShopBannerFromGlobal(); - this.syncConfiguredIcons(); this.registerNotificationComponent(); this.loadGlobalStatus(); - this.checkAuthorization(true); + this.checkAuthorization(); }, registerNotificationComponent() { @@ -102,17 +77,14 @@ Page({ } }, - /** 同步轮播与公告(仅读缓存) */ + /** 同步点单端已加载的商品轮播图,仅展示用 */ syncShopBannerFromGlobal() { const oss = app.globalData.ossImageUrl || ''; const lunboList = (app.globalData.shangpinlunbo || []).map((url) => { if (!url) return ''; return url.startsWith('http') ? url : oss + url; }).filter(Boolean); - this.setData({ - lunboList, - gonggao: app.globalData.shangpingonggao || '', - }); + this.setData({ lunboList }); }, loadGlobalStatus() { @@ -136,7 +108,7 @@ Page({ }); }, - checkAuthorization(skipReload = false, loadOrdersOnAuth = false) { + checkAuthorization() { const { dashoustatus, zhuanghaoStatus } = this.data; const isDashouValid = (dashoustatus && dashoustatus == 1) || false; @@ -151,19 +123,16 @@ Page({ this.setData({ unauthorizedMsg: msg || '无法使用抢单功能' }); } else { this.setData({ showUnauthorized: false }); - if (!skipReload) { - if (!this.data.shangpinleixing.length) { - this.loadShangpinLeixing(loadOrdersOnAuth); - } else if (loadOrdersOnAuth && this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - this.loadBankuaiBiaoqian(); - } - PopupService.checkAndShow(this, 'jiedanchi'); + if (!this.data.shangpinleixing.length) { + this.loadShangpinLeixing(); + } else if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); } + PopupService.checkAndShow(this, 'jiedanchi'); } }, - async loadShangpinLeixing(autoLoadOrders = false) { + async loadShangpinLeixing() { wx.showLoading({ title: '加载商品类型...' }); try { const res = await request({ @@ -191,9 +160,8 @@ Page({ shangpinleixing: processedList, xuanzhongLeixingId: processedList[0]?.id || null }); - if (autoLoadOrders && this.data.xuanzhongLeixingId) { + if (this.data.xuanzhongLeixingId) { this.loadDingdanList(true); - this.loadBankuaiBiaoqian(); } } else { wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none', duration: 2000 }); @@ -214,38 +182,6 @@ Page({ })); }, - async loadBankuaiBiaoqian() { - const leixingId = this.data.xuanzhongLeixingId; - if (!leixingId) return; - try { - const res = await request({ - url: '/dengji/bkqhbq', - method: 'POST', - data: { leixing_id: leixingId } - }); - if (res && res.data.code === 0) { - this.setData({ - bankuaiBiaoqian: res.data.data.biaoqian_list || [], - xuanzhongBiaoqianId: 0 - }); - } - } catch (e) { - // 标签加载失败不影响主流程 - } - }, - - async selectBiaoqian(e) { - const id = e.currentTarget.dataset.id; - if (id === this.data.xuanzhongBiaoqianId) return; - this.setData({ - xuanzhongBiaoqianId: id, - dingdanList: [], - page: 1, - hasMore: true - }); - await this.loadDingdanList(true); - }, - async selectLeixing(e) { const now = Date.now(); if (now - this.data.lastSwitchTime < this.data.switchCooldown) { @@ -266,11 +202,9 @@ Page({ xuanzhongLeixingId: leixingId, dingdanList: [], page: 1, - hasMore: true, - xuanzhongBiaoqianId: 0 + hasMore: true }); await this.loadDingdanList(true); - await this.loadBankuaiBiaoqian(); } catch (error) { console.error('切换类型失败:', error); } finally { @@ -297,8 +231,7 @@ Page({ data: { leixing_id: this.data.xuanzhongLeixingId, page: loadPage, - page_size: this.data.pageSize, - biaoqian_id: this.data.xuanzhongBiaoqianId || undefined + page_size: this.data.pageSize } }); @@ -343,56 +276,30 @@ Page({ processDingdanItem(item) { const ossUrl = app.globalData.ossImageUrl || ''; - const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); - - const leixing = this.data.shangpinleixing.find((l) => l.id == item.leixing_id); - let leixingIconUrl = ''; - if (leixing && leixing.full_tupian_url) { - leixingIconUrl = leixing.full_tupian_url; - } else if (leixing && leixing.tupian_url) { - leixingIconUrl = leixing.tupian_url.startsWith('http') - ? leixing.tupian_url - : ossUrl + leixing.tupian_url; + let fullTupianUrl = ''; + if (item.tupian) { + fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; } else { - leixingIconUrl = '/images/default-order.png'; + const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id); + fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png'; } const isZhiding = item.zhuangtai === 7; let zhidingAvatar = ''; if (item.zhiding_avatar) { - zhidingAvatar = !item.zhiding_avatar.startsWith('http') - ? ossUrl + item.zhiding_avatar - : item.zhiding_avatar; + zhidingAvatar = !item.zhiding_avatar.startsWith('http') ? ossUrl + item.zhiding_avatar : item.zhiding_avatar; } const zhidingNicheng = item.zhiding_nicheng || ''; - let shangjiaAvatar = defaultAvatar; - const sjAvatar = (item.sj_avatar || '').trim(); - if (sjAvatar) { - shangjiaAvatar = sjAvatar.startsWith('http') ? sjAvatar : ossUrl + sjAvatar; - } - - let hasRequiredMember = true; - if (item.yaoqiuleixing == 1 && item.huiyuan_id) { - hasRequiredMember = this.data.huiyuanList.some((h) => h.huiyuanid == item.huiyuan_id); - } - - const tags = normalizeOrderTags(item); - return { ...item, - full_tupian_url: leixingIconUrl, - leixing_icon_url: leixingIconUrl, - shangjia_avatar_full: shangjiaAvatar, - isZhiding, + full_tupian_url: fullTupianUrl, + isZhiding: isZhiding, isPingtai: item.pingtai == 1, isShangjia: item.pingtai == 2, zhiding_avatar_full: zhidingAvatar, - zhiding_nicheng: zhidingNicheng, - ...tags, - shangjia_youzhi: !!item.shangjia_youzhi, - hasRequiredMember, + zhiding_nicheng: zhidingNicheng }; }, @@ -515,6 +422,15 @@ Page({ }, onReachBottom() { + const now = Date.now(); + if (now - this.data.lastRefreshTime < this.data.refreshCooldown) { + wx.showToast({ + title: `操作太快,请${Math.ceil((this.data.refreshCooldown - (now - this.data.lastRefreshTime)) / 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 }); @@ -522,24 +438,24 @@ Page({ } }, - onTapRefresh() { - if (!this.data.xuanzhongLeixingId) { - wx.showToast({ title: '请先选择订单类型', icon: 'none' }); + onPullDownRefresh() { + const now = Date.now(); + if (now - this.data.lastRefreshTime < this.data.refreshCooldown) { + this.setData({ scrollViewRefreshing: false }); + wx.showToast({ + title: `操作太快,请${Math.ceil((this.data.refreshCooldown - (now - this.data.lastRefreshTime)) / 1000)}秒后再试`, + icon: 'none', + duration: 1500 + }); return; } - if (this.data.isLoading) return; - this.setData({ page: 1, hasMore: true, scrollViewRefreshing: true }); - this.loadDingdanList(true); - }, - - onPullDownRefresh() { if (this.data.isLoading) { this.setData({ scrollViewRefreshing: false }); return; } - this.setData({ + this.setData({ scrollViewRefreshing: true, - lastRefreshTime: Date.now(), + lastRefreshTime: now }); if (this.data.xuanzhongLeixingId) { this.setData({ page: 1, hasMore: true }); diff --git a/pages/order-pool/order-pool.json b/pages/order-pool/order-pool.json index cf99ffb..ea51a5d 100644 --- a/pages/order-pool/order-pool.json +++ b/pages/order-pool/order-pool.json @@ -1,12 +1,9 @@ { - "navigationBarTitleText": "接单池", - "navigationBarBackgroundColor": "#f7dc51", - "navigationBarTextStyle": "black", - "enablePullDownRefresh": false, - "backgroundTextStyle": "dark", - "backgroundColor": "#fff8e1", - "usingComponents": { - "chenghao-tag": "/components/chenghao-tag/chenghao-tag", - "global-notification": "/components/global-notification/global-notification" - } -} + "navigationBarTitleText": "接单池", + "enablePullDownRefresh": false, + "backgroundTextStyle": "dark", + "backgroundColor": "#f5f7fa", + "usingComponents": { + "global-notification": "/components/global-notification/global-notification" + } + } \ No newline at end of file diff --git a/pages/order-pool/order-pool.wxml b/pages/order-pool/order-pool.wxml index 32e4bed..69d5832 100644 --- a/pages/order-pool/order-pool.wxml +++ b/pages/order-pool/order-pool.wxml @@ -1,5 +1,6 @@ - + + @@ -16,310 +17,266 @@ + - - + + + + + + + + + - - - 正在刷新... - 下拉刷新订单 - - - - - - {{gonggao}} - - - - - - - - - + + + + + + + + + + {{item.jieshao}} + - - + + + - - - - - - + + + + + + + + 正在刷新... + 下拉刷新订单 + + + + + + + + 请先选择上方订单类型 + + + + + 当前类型暂无待抢订单 + + + + + + + + + {{item.creat_time}} + + 平台订单 + + + + + 指定 + + {{item.zhiding_nicheng || '指定接单员'}} + UID: {{item.zhiding_uid || '未知'}} + + + + + + + 介绍: + {{item.jieshao || '暂无介绍'}} + [点击查看] + + + + + - - - {{item.jieshao}} + 备注: + {{item.beizhu}} + [点击查看] - + + + + + + 分佣 + {{item.dashou_fencheng || 0}} + + + + 立即抢单 + + + + + + + + + + {{item.creat_time}} + + 商家发单 + + + + + 指定 + + {{item.zhiding_nicheng || '指定接单员'}} + UID: {{item.zhiding_uid || '未知'}} + + + + + + {{item.sjnicheng || '未知商家'}} + + + + + 订单介绍: + {{item.jieshao || '暂无介绍'}} + [点击查看] + + + + + 商家备注: + {{item.beizhu}} + [点击查看] + + + + + + + 分佣 + {{item.dashou_fencheng || 0}} + + + + 立即抢单 + + + + + + + + + 加载更多订单中... - + + 没有更多订单了 + + + + + + + + 订单加载中... - - - - - - - 全部 - - - - - - - - - - - - - - - - - 请先选择上方订单类型 - - - - 当前类型暂无待抢订单 - - - - - - - {{item.creat_time}} - 平台订单 - - - - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - - - - - {{item.jieshao || '暂无介绍'}} - - - - - {{item.dashou_fencheng || 0}} - - - 未开通会员 - - - 备注:{{item.beizhu || '暂无'}} - - - 需求标签 - - - - - - - - 平台派单 - 抢单 - - - - - - - - - - - - - - - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - - - - - {{item.jieshao || '暂无介绍'}} - - 优质商家 - - - - - - {{item.dashou_fencheng || 0}} - - - 未开通会员 - - - 商家备注:{{item.beizhu || '暂无'}} - - - - - - - - - - - - - - - - - - - - - - - {{item.sjnicheng || '未知商家'}} - 发布于 {{item.creat_time}} - - - 抢单 - - - 商家派单 - - - - - - - - - {{item.creat_time}} - 商家发单 - - - - - - - 指定 - - {{item.zhiding_nicheng || '指定接单员'}} - - - - - - - - - - {{item.jieshao || '暂无介绍'}} - - - - - {{item.dashou_fencheng || 0}} - - - 未开通会员 - - - 商家备注:{{item.beizhu || '暂无'}} - - - - - - - - - - - - - - - - - - - - 商家派单 - 抢单 - - - - - - - - 加载更多订单中... - - - —— 没有更多订单了 —— - - - - - - - - - 订单加载中... - + \ No newline at end of file diff --git a/pages/order-pool/order-pool.wxss b/pages/order-pool/order-pool.wxss index fe94886..648f067 100644 --- a/pages/order-pool/order-pool.wxss +++ b/pages/order-pool/order-pool.wxss @@ -1,188 +1,665 @@ -/* pages/order-pool/order-pool.wxss 抢单池(逍遥梦风格) */ +/* pages/qiangdan/qiangdan.wxss */ @import '../../styles/dashou-xym-theme.wxss'; -@import '../../styles/dashou-xym-order-card.wxss'; - .qiangdan-page { - height: 100vh; - display: flex; - flex-direction: column; - overflow: hidden; - position: relative; -} + height: 100vh; + display: flex; + flex-direction: column; + background-color: #f5f7fa; + overflow: hidden; + position: relative; + } + + /* 授权提示页 */ + .unauthorized-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: radial-gradient(ellipse at top, #0b0f1a, #03050a); + z-index: 100; + } + + .unauthorized-card { + width: 600rpx; + padding: 60rpx 40rpx; + background: linear-gradient(145deg, #1a1f30, #0f1422); + border-radius: 60rpx; + position: relative; + overflow: hidden; + border: 2rpx solid rgba(0, 247, 255, 0.3); + box-shadow: 0 30rpx 60rpx rgba(0, 0, 0, 0.8), 0 0 30rpx rgba(0, 247, 255, 0.2); + } + + .card-glow { + position: absolute; + top: -20%; + left: -20%; + width: 140%; + height: 140%; + background: radial-gradient(circle at 30% 30%, rgba(0, 247, 255, 0.2), transparent 60%); + animation: rotateGlow 10s linear infinite; + z-index: 0; + } + + @keyframes rotateGlow { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + .card-content-unauth { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + align-items: center; + color: #ffffff; + } + + .icon-lock { + position: relative; + width: 72rpx; + height: 52rpx; + margin-bottom: 30rpx; + background: linear-gradient(180deg, #fae04d, #ffc0a3); + border-radius: 10rpx; + box-shadow: 0 8rpx 24rpx rgba(180, 130, 20, 0.25); + } -.page-main-scroll { - flex: 1; - height: 0; - -webkit-overflow-scrolling: touch; -} - -.scroll-bottom-spacer { - height: 24rpx; -} - -.refresher-container { - height: 100rpx; - display: flex; - align-items: center; - justify-content: center; -} - -.leixing-scroll { - width: 100%; - white-space: nowrap; -} - -.leixing-container { - display: inline-flex; - padding: 0 30rpx; - gap: 20rpx; -} - -.leixing-item { - display: inline-flex; - flex-direction: column; - align-items: center; - position: relative; -} - -.biaoqian-scroll { - white-space: nowrap; - height: 80rpx; -} - -.biaoqian-container { - display: inline-flex; - gap: 16rpx; - padding-right: 20rpx; -} - -.biaoqian-item { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0 12rpx; - border-radius: 20rpx; -} - -.quanbu-text { - font-size: 26rpx; - padding: 0 12rpx; -} - -.xuqiu-tags-row { - display: flex; - align-items: center; - margin-top: 12rpx; - padding: 0 10rpx; -} - -.xuqiu-label { - font-size: 24rpx; - margin-right: 12rpx; - flex-shrink: 0; -} - -.biaoqian-inline-scroll { - flex: 1; - white-space: nowrap; -} - -.empty-tip { - padding: 160rpx 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.tip-icon { - width: 180rpx; - height: 180rpx; - opacity: 0.5; - margin-bottom: 30rpx; -} - -.loading-more, -.no-more { - padding: 40rpx 0; - text-align: center; -} - -.loading-spinner { - width: 90rpx; - height: 90rpx; - border: 6rpx solid rgba(255, 208, 97, 0.3); - border-top: 6rpx solid #ffd061; - border-radius: 50%; - animation: spin 1s linear infinite; - margin-bottom: 30rpx; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* 未授权页 */ -.unauthorized-container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - z-index: 100; -} - -.unauthorized-card { - width: 600rpx; - padding: 60rpx 40rpx; - border-radius: 60rpx; - position: relative; - overflow: hidden; -} - -.card-content-unauth { - position: relative; - z-index: 2; - display: flex; - flex-direction: column; - align-items: center; -} - -.icon-lock { - width: 72rpx; - height: 52rpx; - margin-bottom: 30rpx; - background: linear-gradient(180deg, #fae04d, #ffc0a3); - border-radius: 10rpx; -} - -.title { - font-size: 36rpx; - font-weight: 700; - margin-bottom: 16rpx; -} - -.message { - font-size: 28rpx; - margin-bottom: 12rpx; -} - -.description { - font-size: 24rpx; - margin-bottom: 40rpx; - text-align: center; -} - -.btn-register { - padding: 24rpx 80rpx; - position: relative; - overflow: hidden; -} - -.btn-register .btn-text { - font-size: 30rpx; - font-weight: 700; -} + .icon-lock::before { + content: ''; + position: absolute; + top: -34rpx; + left: 50%; + transform: translateX(-50%); + width: 44rpx; + height: 36rpx; + border: 8rpx solid #ffd061; + border-bottom: none; + border-radius: 22rpx 22rpx 0 0; + box-sizing: border-box; + } + + .title { + font-size: 48rpx; + font-weight: 700; + letter-spacing: 4rpx; + margin-bottom: 20rpx; + text-shadow: 0 0 15rpx #00f7ff; + background: linear-gradient(135deg, #ffffff, #aaddff); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + .message { + font-size: 32rpx; + color: #ffaa00; + margin-bottom: 16rpx; + font-weight: 600; + text-shadow: 0 0 10rpx #ffaa00; + } + + .description { + font-size: 28rpx; + color: #a0b0d0; + margin-bottom: 50rpx; + text-align: center; + } + + .btn-register { + position: relative; + padding: 24rpx 80rpx; + background: linear-gradient(145deg, #2a3050, #181e38); + border-radius: 60rpx; + overflow: hidden; + border: 2rpx solid #00f7ff; + box-shadow: 0 10rpx 30rpx rgba(0, 247, 255, 0.4); + transition: transform 0.2s; + } + + .btn-register:active { + transform: scale(0.96); + } + + .btn-text { + font-size: 32rpx; + color: #fff; + font-weight: 700; + letter-spacing: 4rpx; + position: relative; + z-index: 2; + text-shadow: 0 0 10rpx #00f7ff; + } + + .btn-shine { + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + to right, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.2) 50%, + rgba(255, 255, 255, 0) 100% + ); + transform: rotate(30deg); + animation: btn-shimmer 2.8s infinite linear; + z-index: 1; + } + + @keyframes btn-shimmer { + 0% { transform: translateX(-100%) rotate(30deg); } + 100% { transform: translateX(100%) rotate(30deg); } + } + + /* 原有样式 */ + .leixing-quyu { + padding: 30rpx 0 20rpx; + background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); + border-bottom: 1rpx solid #eaeaea; + position: relative; + z-index: 10; + flex-shrink: 0; + } + + .leixing-scroll { + width: 100%; + white-space: nowrap; + height: 180rpx; + } + + .leixing-container { + display: inline-flex; + padding: 0 30rpx; + } + + .leixing-item { + display: inline-flex; + flex-direction: column; + align-items: center; + width: 160rpx; + margin-right: 24rpx; + position: relative; + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + } + + .leixing-active { + transform: translateY(-6rpx); + } + + .guangyun-effect { + position: absolute; + top: -12rpx; + left: -12rpx; + right: -12rpx; + bottom: -12rpx; + background: radial-gradient(circle at center, rgba(82, 196, 26, 0.15) 0%, transparent 70%); + border-radius: 40rpx; + z-index: 0; + animation: guangyun-pulse 2s infinite ease-in-out; + } + + @keyframes guangyun-pulse { + 0%, 100% { opacity: 0.6; transform: scale(1); } + 50% { opacity: 0.9; transform: scale(1.05); } + } + + .leixing-tupian { + width: 120rpx; + height: 120rpx; + border-radius: 28rpx; + z-index: 1; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; + } + + .leixing-active .leixing-tupian { + box-shadow: 0 16rpx 40rpx rgba(82, 196, 26, 0.3); + border: 4rpx solid #52c41a; + } + + .leixing-jieshao { + margin-top: 16rpx; + font-size: 24rpx; + color: #666; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + z-index: 1; + } + + .leixing-active .leixing-jieshao { + color: #52c41a; + font-weight: 600; + } + + .fenge-xian { + height: 16rpx; + background: linear-gradient(to bottom, #f0f2f5, #f8f9fa); + flex-shrink: 0; + } + + .dingdan-container { + flex: 1; + overflow: hidden; + } + + .dingdan-scroll-view { + height: 100%; + -webkit-overflow-scrolling: touch; + } + + .refresher-container { + height: 100rpx; + display: flex; + align-items: center; + justify-content: center; + } + + .refreshing-text, + .pull-down-text { + font-size: 26rpx; + color: #999; + } + + .empty-tip { + padding: 120rpx 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .tip-icon { + width: 160rpx; + height: 160rpx; + opacity: 0.4; + margin-bottom: 30rpx; + } + + .tip-text { + font-size: 28rpx; + color: #aaa; + } + + .dingdan-card { + margin: 20rpx 24rpx; + border-radius: 20rpx; + padding: 28rpx; + position: relative; + overflow: hidden; + box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.06); + transition: all 0.2s ease; + border: 1rpx solid rgba(0, 0, 0, 0.08); + } + + .dingdan-card:active { + transform: scale(0.995); + } + + .pingtai-card { + background: linear-gradient(145deg, #f8fff8 0%, #f0f9f0 100%); + } + + .shangjia-card { + background: linear-gradient(145deg, #f9f0ff 0%, #f3e8ff 100%); + } + + .card-top { + display: flex; + align-items: center; + margin-bottom: 20rpx; + padding-bottom: 16rpx; + border-bottom: 1rpx dashed #e0e0e0; + } + + .creat-time { + font-size: 26rpx; + color: #555; + font-weight: 500; + } + + .top-line { + flex: 1; + height: 1rpx; + background: linear-gradient(to right, transparent, #ddd, transparent); + margin: 0 20rpx; + } + + .pingtai-tag { + font-size: 24rpx; + color: #666; + padding: 6rpx 16rpx; + background: rgba(0, 0, 0, 0.04); + border-radius: 20rpx; + } + + .zhiding-row { + display: flex; + align-items: center; + margin-bottom: 20rpx; + padding: 10rpx 16rpx; + background: rgba(255, 77, 79, 0.08); + border-radius: 12rpx; + border-left: 4rpx solid #ff4d4f; + gap: 10rpx; + } + + .zhiding-icon { + font-size: 26rpx; + margin-right: 4rpx; + } + + .zhiding-avatar { + width: 48rpx; + height: 48rpx; + border-radius: 50%; + border: 2rpx solid #ff4d4f; + object-fit: cover; + } + + .zhiding-nicheng { + font-size: 24rpx; + color: #ff4d4f; + font-weight: 500; + max-width: 120rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .zhiding-uid { + font-size: 24rpx; + color: #ff4d4f; + font-weight: 400; + flex: 1; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .card-content { + display: flex; + margin-bottom: 20rpx; + } + + .neirong-tupian { + width: 140rpx; + height: 140rpx; + border-radius: 50%; + margin-right: 24rpx; + flex-shrink: 0; + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.08); + object-fit: cover; + } + + .jieshao-box { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + min-height: 140rpx; + padding: 16rpx 0; + } + + .jieshao-label { + font-size: 26rpx; + color: #333; + font-weight: 600; + margin-bottom: 8rpx; + } + + .jieshao-text { + font-size: 26rpx; + color: #666; + line-height: 1.4; + } + + .jieshao-ellipsis .jieshao-text { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + overflow: hidden; + text-overflow: ellipsis; + } + + .shangjia-info { + display: flex; + align-items: center; + margin-bottom: 20rpx; + } + + .shangjia-touxiang { + width: 90rpx; + height: 90rpx; + border-radius: 50%; + margin-right: 20rpx; + border: 2rpx solid rgba(114, 46, 209, 0.15); + box-shadow: 0 6rpx 18rpx rgba(114, 46, 209, 0.12); + object-fit: cover; + } + + .shangjia-nicheng { + font-size: 28rpx; + color: #333; + font-weight: 600; + } + + .shangjia-jieshao, + .shangjia-beizhu { + margin-bottom: 16rpx; + padding: 14rpx 18rpx; + background: rgba(255, 255, 255, 0.6); + border-radius: 12rpx; + } + + .shangjia-jieshao .jieshao-label, + .shangjia-beizhu .beizhu-label { + display: block; + margin-bottom: 6rpx; + font-size: 24rpx; + } + + .shangjia-jieshao .jieshao-text, + .shangjia-beizhu .beizhu-text { + font-size: 24rpx; + color: #555; + line-height: 1.4; + } + + .shangjia-jieshao.jieshao-ellipsis .jieshao-text { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + } + + .shangjia-beizhu.beizhu-ellipsis .beizhu-text { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + } + + .beizhu-box { + margin-bottom: 20rpx; + padding: 14rpx 18rpx; + background: rgba(255, 255, 255, 0.6); + border-radius: 12rpx; + } + + .beizhu-label { + font-size: 24rpx; + color: #333; + font-weight: 600; + margin-bottom: 6rpx; + display: block; + } + + .beizhu-text { + font-size: 24rpx; + color: #666; + line-height: 1.4; + } + + .beizhu-ellipsis .beizhu-text { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + } + + .view-more { + display: block; + font-size: 22rpx; + color: #1890ff; + margin-top: 6rpx; + text-align: right; + } + + .card-bottom { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 20rpx; + border-top: 1rpx solid rgba(0, 0, 0, 0.06); + } + + .fenyong-box { + display: flex; + align-items: baseline; + } + + .fenyong-icon { + font-size: 30rpx; + margin-right: 10rpx; + } + + .fenyong-text { + font-size: 24rpx; + color: #999; + margin-right: 6rpx; + } + + .fenyong-price { + font-size: 40rpx; + color: #ff4d4f; + font-weight: 700; + margin-right: 4rpx; + } + + .fenyong-unit { + font-size: 24rpx; + color: #999; + } + + .qiangdan-btn { + position: relative; + padding: 18rpx 40rpx; + border-radius: 50rpx; + overflow: hidden; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12); + } + + .pingtai-btn { + background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); + } + + .shangjia-btn { + background: linear-gradient(135deg, #722ed1 0%, #9254de 100%); + } + + .btn-text { + font-size: 28rpx; + color: white; + font-weight: 600; + letter-spacing: 1rpx; + position: relative; + z-index: 2; + } + + .btn-shine { + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + to right, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0) 100% + ); + transform: rotate(30deg); + animation: btn-shimmer 3s infinite linear; + z-index: 1; + } + + @keyframes btn-shimmer { + 0% { transform: translateX(-100%) rotate(30deg); } + 100% { transform: translateX(100%) rotate(30deg); } + } + + .qiangdan-btn:active { + transform: scale(0.96); + } + + .loading-more, + .no-more { + padding: 30rpx 0; + text-align: center; + } + + .loading-text { + font-size: 26rpx; + color: #999; + } + + .no-more-text { + font-size: 26rpx; + color: #ccc; + } + + .loading-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.9); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .loading-spinner { + width: 70rpx; + height: 70rpx; + border: 6rpx solid #f0f0f0; + border-top: 6rpx solid #52c41a; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 24rpx; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + .loading-mask-text { + font-size: 28rpx; + color: #666; + } \ No newline at end of file