From 296e41a8a78f5e6f76a5e68738dca1aa3214d7a0 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 13 Jun 2026 10:44:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=20pages=20=E5=90=8D?= =?UTF-8?q?=E4=B8=BA=E6=8B=BC=E9=9F=B3=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 827 +++--- app.json | 212 +- app.wxss | 889 +++++- .../global-notification.js | 729 +++-- components/popup-notice/popup-notice.js | 8 +- components/popup-notice/popup-notice.wxml | 3 +- components/popup-notice/popup-notice.wxss | 2 +- custom-tab-bar/index.js | 218 +- custom-tab-bar/index.wxml | 48 +- .../accept-order.js} | 1152 ++++---- .../accept-order.json} | 0 .../accept-order.wxml} | 0 .../accept-order.wxss} | 0 .../assess-center.js} | 478 ++-- .../assess-center.json} | 0 .../assess-center.wxml} | 0 .../assess-center.wxss} | 3 +- .../assess-gold.js} | 920 +++---- .../assess-gold.json} | 0 .../assess-gold.wxml} | 268 +- .../assess-gold.wxss} | 768 +++--- .../assess-log.js} | 296 +- .../assess-log.json} | 0 .../assess-log.wxml} | 258 +- .../assess-log.wxss} | 525 ++-- .../assess-score.js} | 414 +-- .../assess-score.json} | 0 .../assess-score.wxml} | 234 +- .../assess-score.wxss} | 0 .../kaoheguan.js => assessor/assessor.js} | 434 +-- .../kaoheguan.json => assessor/assessor.json} | 0 .../kaoheguan.wxml => assessor/assessor.wxml} | 254 +- .../kaoheguan.wxss => assessor/assessor.wxss} | 1022 +++---- .../fenlei.js => category/category.js} | 783 +++--- .../fenlei.json => category/category.json} | 0 .../fenlei.wxml => category/category.wxml} | 432 +-- .../fenlei.wxss => category/category.wxss} | 2388 ++++++++--------- .../components/fakuan-list/fakuan-list.json | 6 - pages/{liaotian/liaotian.js => chat/chat.js} | 0 .../kefuliaotian.json => chat/chat.json} | 0 .../liaotian.wxml => chat/chat.wxml} | 0 .../liaotian.wxss => chat/chat.wxss} | 0 .../kefuliaotian.js => cs-chat/cs-chat.js} | 16 +- .../liaotian.json => cs-chat/cs-chat.json} | 0 .../cs-chat.wxml} | 0 .../cs-chat.wxss} | 0 pages/{xiugai/xiugai.js => edit/edit.js} | 453 ++-- pages/{xiugai/xiugai.json => edit/edit.json} | 0 pages/{xiugai/xiugai.wxml => edit/edit.wxml} | 136 +- pages/{xiugai/xiugai.wxss => edit/edit.wxss} | 779 +++--- .../escort-orders.js} | 130 +- .../escort-orders.json} | 0 pages/escort-orders/escort-orders.wxml | 2 + pages/escort-orders/escort-orders.wxss | 1 + .../express-order.js} | 1234 ++++----- .../express-order.json} | 0 .../express-order.wxml} | 458 ++-- .../express-order.wxss} | 442 +-- .../fighter-edit.js} | 0 .../fighter-edit.json} | 0 .../fighter-edit.wxml} | 0 .../fighter-edit.wxss} | 0 .../fighter-msg.js} | 1366 +++++----- .../fighter-msg.json} | 0 .../fighter-msg.wxml} | 630 ++--- .../fighter-msg.wxss} | 1924 ++++++------- .../fighter-order-detail.js} | 1480 +++++----- .../fighter-order-detail.json} | 0 .../fighter-order-detail.wxml} | 0 .../fighter-order-detail.wxss} | 1176 ++++---- .../fighter-orders.js} | 612 ++--- .../fighter-orders.json} | 0 .../fighter-orders.wxml} | 0 .../fighter-orders.wxss} | 4 +- .../fighter-rank.js} | 0 .../fighter-rank.json} | 0 .../fighter-rank.wxml} | 0 .../fighter-rank.wxss} | 2 - .../fighter-recharge.js} | 1948 +++++++------- .../fighter-recharge.json} | 0 .../fighter-recharge.wxml} | 0 .../fighter-recharge.wxss} | 0 .../fighter-rules.js} | 0 .../fighter-rules.json} | 0 .../fighter-rules.wxml} | 0 .../fighter-rules.wxss} | 0 .../dashouduan.js => fighter/fighter.js} | 2372 ++++++++-------- .../dashouduan.json => fighter/fighter.json} | 0 .../dashouduan.wxml => fighter/fighter.wxml} | 0 .../dashouduan.wxss => fighter/fighter.wxss} | 97 +- .../gold-fighter.js} | 624 ++--- .../gold-fighter.json} | 0 .../gold-fighter.wxml} | 0 .../gold-fighter.wxss} | 1218 ++++----- .../group-chat.js} | 23 +- .../group-chat.json} | 0 .../group-chat.wxml} | 0 .../group-chat.wxss} | 0 pages/index/index.js | 789 +++--- pages/index/index.wxml | 1 - pages/index/index.wxss | 958 +++---- .../invite-fighter.js} | 0 .../invite-fighter.json} | 0 .../invite-fighter.wxml} | 0 .../invite-fighter.wxss} | 0 .../invite-manager.js} | 0 .../invite-manager.json} | 0 .../invite-manager.wxml} | 0 .../invite-manager.wxss} | 0 pages/jiedanchi2/jiedanchi2.wxml | 2 - pages/jiedanchi2/jiedanchi2.wxss | 1 - .../leader-bonus-log.js} | 0 .../leader-bonus-log.json} | 0 .../leader-bonus-log.wxml} | 0 .../leader-bonus-log.wxss} | 0 .../zuzhangduan.js => leader/leader.js} | 448 ++-- .../zuzhangduan.json => leader/leader.json} | 0 .../zuzhangduan.wxml => leader/leader.wxml} | 214 +- .../zuzhangduan.wxss => leader/leader.wxss} | 1122 ++++---- .../manager-assign.js} | 178 +- .../manager-assign.json} | 0 .../manager-assign.wxml} | 0 .../manager-assign.wxss} | 188 +- .../manager-rank.js} | 0 .../manager-rank.json} | 0 .../manager-rank.wxml} | 0 .../manager-rank.wxss} | 0 .../guanshiduan.js => manager/manager.js} | 1355 +++++----- .../guanshiduan.json => manager/manager.json} | 0 .../guanshiduan.wxml => manager/manager.wxml} | 0 .../guanshiduan.wxss => manager/manager.wxss} | 15 +- .../merchant-dispatch.js} | 834 +++--- .../merchant-dispatch.json} | 0 .../merchant-dispatch.wxml} | 316 +-- .../merchant-dispatch.wxss} | 746 ++--- .../merchant-msg.js} | 0 .../merchant-msg.json} | 0 .../merchant-msg.wxml} | 0 .../merchant-msg.wxss} | 0 .../merchant-order-detail.js} | 1668 ++++++------ .../merchant-order-detail.json} | 0 .../merchant-order-detail.wxml} | 706 ++--- .../merchant-order-detail.wxss} | 368 +-- .../merchant-orders.js} | 652 ++--- .../merchant-orders.json} | 0 .../merchant-orders.wxml} | 268 +- .../merchant-orders.wxss} | 856 +++--- .../merchant-rank.js} | 0 .../merchant-rank.json} | 0 .../merchant-rank.wxml} | 0 .../merchant-rank.wxss} | 0 .../merchant-recharge.js} | 0 .../merchant-recharge.json} | 0 .../merchant-recharge.wxml} | 0 .../merchant-recharge.wxss} | 0 .../shangjiaduan.js => merchant/merchant.js} | 724 +++-- .../merchant.json} | 0 .../merchant.wxml} | 0 .../merchant.wxss} | 891 +++--- .../xiaoxi.js => messages/messages.js} | 808 +++--- .../xiaoxi.json => messages/messages.json} | 0 .../xiaoxi.wxml => messages/messages.wxml} | 0 .../xiaoxi.wxss => messages/messages.wxss} | 14 +- pages/{wode/wode.js => mine/mine.js} | 336 +-- pages/{wode/wode.json => mine/mine.json} | 0 pages/{wode/wode.wxml => mine/mine.wxml} | 0 pages/{wode/wode.wxss => mine/mine.wxss} | 7 +- .../my-fighter.js} | 350 +-- .../my-fighter.json} | 0 .../my-fighter.wxml} | 0 .../my-fighter.wxss} | 0 .../order-detail.js} | 0 .../order-detail.json} | 0 .../order-detail.wxml} | 404 +-- .../order-detail.wxss} | 2 +- .../jiedanchi.js => order-pool/order-pool.js} | 922 ++++--- .../order-pool.json} | 0 .../order-pool.wxml} | 0 .../order-pool.wxss} | 4 +- pages/order-pool2/order-pool2.js | 39 + .../order-pool2.json} | 0 pages/order-pool2/order-pool2.wxml | 2 + pages/order-pool2/order-pool2.wxss | 1 + .../{dingdan/dingdan.js => orders/orders.js} | 558 ++-- .../sjddxq.json => orders/orders.json} | 0 .../dingdan.wxml => orders/orders.wxml} | 222 +- .../dingdan.wxss => orders/orders.wxss} | 450 ++-- pages/peihuDingdan/peihuDingdan.wxml | 2 - pages/peihuDingdan/peihuDingdan.wxss | 1 - .../components/fakuan-list/fakuan-list.js | 0 .../components/fakuan-list/fakuan-list.json | 6 + .../components/fakuan-list/fakuan-list.wxml | 0 .../components/fakuan-list/fakuan-list.wxss | 0 .../components/fakuan-pay/fakuan-pay.js | 0 .../components/fakuan-pay/fakuan-pay.json | 0 .../components/fakuan-pay/fakuan-pay.wxml | 0 .../components/fakuan-pay/fakuan-pay.wxss | 0 .../components/jifen-list/jifen-list.js | 0 .../components/jifen-list/jifen-list.json | 0 .../components/jifen-list/jifen-list.wxml | 0 .../components/jifen-list/jifen-list.wxss | 0 .../cfss.js => penalty/penalty/penalty.js} | 198 +- .../penalty/penalty.json} | 18 +- .../penalty/penalty.wxml} | 134 +- .../penalty/penalty.wxss} | 240 +- .../jiedanchi2.js => pick-user/pick-user.js} | 130 +- .../xuanren.json => pick-user/pick-user.json} | 0 .../xuanren.wxml => pick-user/pick-user.wxml} | 0 pages/pick-user/pick-user.wxss | 1 + pages/{haibao/haibao.js => poster/poster.js} | 560 ++-- .../haibao.json => poster/poster.json} | 0 .../haibao.wxml => poster/poster.wxml} | 0 .../haibao.wxss => poster/poster.wxss} | 0 .../product-detail.js} | 542 ++-- .../product-detail.json} | 0 .../product-detail.wxml} | 222 +- .../product-detail.wxss} | 733 +++-- .../recharge-log.js} | 0 .../recharge-log.json} | 0 .../recharge-log.wxml} | 0 .../recharge-log.wxss} | 0 pages/{tijiao/tijiao.js => submit/submit.js} | 1092 ++++---- .../wodedashou.json => submit/submit.json} | 0 .../tijiao.wxml => submit/submit.wxml} | 246 +- .../tijiao.wxss => submit/submit.wxss} | 558 ++-- .../renzheng.js => verify/verify.js} | 336 +-- .../renzheng.json => verify/verify.json} | 0 .../renzheng.wxml => verify/verify.wxml} | 56 +- .../renzheng.wxss => verify/verify.wxss} | 3 - .../components/mode1/mode1.js | 966 +++---- .../components/mode1/mode1.json | 0 .../components/mode1/mode1.wxml | 264 +- .../components/mode1/mode1.wxss | 846 +++--- .../components/mode2/mode2.js | 1284 ++++----- .../components/mode2/mode2.json | 0 .../components/mode2/mode2.wxml | 0 .../components/mode2/mode2.wxss | 0 .../tixian.js => withdraw/withdraw.js} | 145 +- .../tixian.json => withdraw/withdraw.json} | 0 .../tixian.wxml => withdraw/withdraw.wxml} | 64 +- .../tixian.wxss => withdraw/withdraw.wxss} | 84 +- pages/xuanren/xuanren.js | 66 - pages/xuanren/xuanren.wxss | 1 - utils/chat-core.js | 800 +++--- utils/im-user.js | 156 +- utils/primary-role.js | 210 +- utils/request.js | 146 +- utils/role-tab-bar.js | 510 ++-- utils/xiaoxilj.js | 428 +-- 249 files changed, 29660 insertions(+), 29505 deletions(-) rename pages/{jiedan/jiedan.js => accept-order/accept-order.js} (96%) rename pages/{jiedan/jiedan.json => accept-order/accept-order.json} (100%) rename pages/{jiedan/jiedan.wxml => accept-order/accept-order.wxml} (100%) rename pages/{jiedan/jiedan.wxss => accept-order/accept-order.wxss} (100%) rename pages/{kaohe_zhongxin/kaohe_zhongxin.js => assess-center/assess-center.js} (95%) rename pages/{kaohe_zhongxin/kaohe_zhongxin.json => assess-center/assess-center.json} (100%) rename pages/{kaohe_zhongxin/kaohe_zhongxin.wxml => assess-center/assess-center.wxml} (100%) rename pages/{kaohe_zhongxin/kaohe_zhongxin.wxss => assess-center/assess-center.wxss} (99%) rename pages/{kaohe_jinpai/kaohe_jinpai.js => assess-gold/assess-gold.js} (96%) rename pages/{kaohe_jinpai/kaohe_jinpai.json => assess-gold/assess-gold.json} (100%) rename pages/{kaohe_jinpai/kaohe_jinpai.wxml => assess-gold/assess-gold.wxml} (97%) rename pages/{kaohe_jinpai/kaohe_jinpai.wxss => assess-gold/assess-gold.wxss} (94%) rename pages/{kaohe_jilu/kaohe_jilu.js => assess-log/assess-log.js} (93%) rename pages/{kaohe_jilu/kaohe_jilu.json => assess-log/assess-log.json} (100%) rename pages/{kaohe_jilu/kaohe_jilu.wxml => assess-log/assess-log.wxml} (97%) rename pages/{kaohe_jilu/kaohe_jilu.wxss => assess-log/assess-log.wxss} (94%) rename pages/{kaohe_dafen/kaohe_dafen.js => assess-score/assess-score.js} (96%) rename pages/{kaohe_dafen/kaohe_dafen.json => assess-score/assess-score.json} (100%) rename pages/{kaohe_dafen/kaohe_dafen.wxml => assess-score/assess-score.wxml} (97%) rename pages/{kaohe_dafen/kaohe_dafen.wxss => assess-score/assess-score.wxss} (100%) rename pages/{kaoheguan/kaoheguan.js => assessor/assessor.js} (91%) rename pages/{kaoheguan/kaoheguan.json => assessor/assessor.json} (100%) rename pages/{kaoheguan/kaoheguan.wxml => assessor/assessor.wxml} (97%) rename pages/{kaoheguan/kaoheguan.wxss => assessor/assessor.wxss} (95%) rename pages/{fenlei/fenlei.js => category/category.js} (77%) rename pages/{fenlei/fenlei.json => category/category.json} (100%) rename pages/{fenlei/fenlei.wxml => category/category.wxml} (94%) rename pages/{fenlei/fenlei.wxss => category/category.wxss} (93%) delete mode 100644 pages/cfss/components/fakuan-list/fakuan-list.json rename pages/{liaotian/liaotian.js => chat/chat.js} (100%) rename pages/{kefuliaotian/kefuliaotian.json => chat/chat.json} (100%) rename pages/{liaotian/liaotian.wxml => chat/chat.wxml} (100%) rename pages/{liaotian/liaotian.wxss => chat/chat.wxss} (100%) rename pages/{kefuliaotian/kefuliaotian.js => cs-chat/cs-chat.js} (97%) rename pages/{liaotian/liaotian.json => cs-chat/cs-chat.json} (100%) rename pages/{kefuliaotian/kefuliaotian.wxml => cs-chat/cs-chat.wxml} (100%) rename pages/{kefuliaotian/kefuliaotian.wxss => cs-chat/cs-chat.wxss} (100%) rename pages/{xiugai/xiugai.js => edit/edit.js} (91%) rename pages/{xiugai/xiugai.json => edit/edit.json} (100%) rename pages/{xiugai/xiugai.wxml => edit/edit.wxml} (95%) rename pages/{xiugai/xiugai.wxss => edit/edit.wxss} (86%) rename pages/{peihuDingdan/peihuDingdan.js => escort-orders/escort-orders.js} (88%) rename pages/{jiedanchi2/jiedanchi2.json => escort-orders/escort-orders.json} (100%) create mode 100644 pages/escort-orders/escort-orders.wxml create mode 100644 pages/escort-orders/escort-orders.wxss rename pages/{jisufd/jisufd.js => express-order/express-order.js} (96%) rename pages/{jisufd/jisufd.json => express-order/express-order.json} (100%) rename pages/{jisufd/jisufd.wxml => express-order/express-order.wxml} (97%) rename pages/{jisufd/jisufd.wxss => express-order/express-order.wxss} (98%) rename pages/{dashouxiugai/dashouxiugai.js => fighter-edit/fighter-edit.js} (100%) rename pages/{dashouxiugai/dashouxiugai.json => fighter-edit/fighter-edit.json} (100%) rename pages/{dashouxiugai/dashouxiugai.wxml => fighter-edit/fighter-edit.wxml} (100%) rename pages/{dashouxiugai/dashouxiugai.wxss => fighter-edit/fighter-edit.wxss} (100%) rename pages/{dashouxiaoxi/dashouxiaoxi.js => fighter-msg/fighter-msg.js} (96%) rename pages/{dashouxiaoxi/dashouxiaoxi.json => fighter-msg/fighter-msg.json} (100%) rename pages/{dashouxiaoxi/dashouxiaoxi.wxml => fighter-msg/fighter-msg.wxml} (97%) rename pages/{dashouxiaoxi/dashouxiaoxi.wxss => fighter-msg/fighter-msg.wxss} (94%) rename pages/{dsddxq/dsddxq.js => fighter-order-detail/fighter-order-detail.js} (96%) rename pages/{dingdan/dingdan.json => fighter-order-detail/fighter-order-detail.json} (100%) rename pages/{dsddxq/dsddxq.wxml => fighter-order-detail/fighter-order-detail.wxml} (100%) rename pages/{dsddxq/dsddxq.wxss => fighter-order-detail/fighter-order-detail.wxss} (94%) rename pages/{dashoudingdan/dashoudingdan.js => fighter-orders/fighter-orders.js} (95%) rename pages/{dashoudingdan/dashoudingdan.json => fighter-orders/fighter-orders.json} (100%) rename pages/{dashoudingdan/dashoudingdan.wxml => fighter-orders/fighter-orders.wxml} (100%) rename pages/{dashoudingdan/dashoudingdan.wxss => fighter-orders/fighter-orders.wxss} (99%) rename pages/{dashoupaihang/dashoupaihang.js => fighter-rank/fighter-rank.js} (100%) rename pages/{dashoupaihang/dashoupaihang.json => fighter-rank/fighter-rank.json} (100%) rename pages/{dashoupaihang/dashoupaihang.wxml => fighter-rank/fighter-rank.wxml} (100%) rename pages/{dashoupaihang/dashoupaihang.wxss => fighter-rank/fighter-rank.wxss} (99%) rename pages/{dashouchongzhi/dashouchongzhi.js => fighter-recharge/fighter-recharge.js} (96%) rename pages/{dashouchongzhi/dashouchongzhi.json => fighter-recharge/fighter-recharge.json} (100%) rename pages/{dashouchongzhi/dashouchongzhi.wxml => fighter-recharge/fighter-recharge.wxml} (100%) rename pages/{dashouchongzhi/dashouchongzhi.wxss => fighter-recharge/fighter-recharge.wxss} (100%) rename pages/{dashouguize/dashouguize.js => fighter-rules/fighter-rules.js} (100%) rename pages/{dashouguize/dashouguize.json => fighter-rules/fighter-rules.json} (100%) rename pages/{dashouguize/dashouguize.wxml => fighter-rules/fighter-rules.wxml} (100%) rename pages/{dashouguize/dashouguize.wxss => fighter-rules/fighter-rules.wxss} (100%) rename pages/{dashouduan/dashouduan.js => fighter/fighter.js} (91%) rename pages/{dashouduan/dashouduan.json => fighter/fighter.json} (100%) rename pages/{dashouduan/dashouduan.wxml => fighter/fighter.wxml} (100%) rename pages/{dashouduan/dashouduan.wxss => fighter/fighter.wxss} (90%) rename pages/{jinpaids/jinpaids.js => gold-fighter/gold-fighter.js} (87%) rename pages/{jinpaids/jinpaids.json => gold-fighter/gold-fighter.json} (100%) rename pages/{jinpaids/jinpaids.wxml => gold-fighter/gold-fighter.wxml} (100%) rename pages/{jinpaids/jinpaids.wxss => gold-fighter/gold-fighter.wxss} (95%) rename pages/{qunliaotian/qunliaotian.js => group-chat/group-chat.js} (96%) rename pages/{qunliaotian/qunliaotian.json => group-chat/group-chat.json} (100%) rename pages/{qunliaotian/qunliaotian.wxml => group-chat/group-chat.wxml} (100%) rename pages/{qunliaotian/qunliaotian.wxss => group-chat/group-chat.wxss} (100%) rename pages/{yaoqingdashou/yaoqingdashou.js => invite-fighter/invite-fighter.js} (100%) rename pages/{yaoqingdashou/yaoqingdashou.json => invite-fighter/invite-fighter.json} (100%) rename pages/{yaoqingdashou/yaoqingdashou.wxml => invite-fighter/invite-fighter.wxml} (100%) rename pages/{yaoqingdashou/yaoqingdashou.wxss => invite-fighter/invite-fighter.wxss} (100%) rename pages/{yqguanshi/yqguanshi.js => invite-manager/invite-manager.js} (100%) rename pages/{yqguanshi/yqguanshi.json => invite-manager/invite-manager.json} (100%) rename pages/{yqguanshi/yqguanshi.wxml => invite-manager/invite-manager.wxml} (100%) rename pages/{yqguanshi/yqguanshi.wxss => invite-manager/invite-manager.wxss} (100%) delete mode 100644 pages/jiedanchi2/jiedanchi2.wxml delete mode 100644 pages/jiedanchi2/jiedanchi2.wxss rename pages/{zzfhjilu/zzfhjilu.js => leader-bonus-log/leader-bonus-log.js} (100%) rename pages/{zzfhjilu/zzfhjilu.json => leader-bonus-log/leader-bonus-log.json} (100%) rename pages/{zzfhjilu/zzfhjilu.wxml => leader-bonus-log/leader-bonus-log.wxml} (100%) rename pages/{zzfhjilu/zzfhjilu.wxss => leader-bonus-log/leader-bonus-log.wxss} (100%) rename pages/{zuzhangduan/zuzhangduan.js => leader/leader.js} (88%) rename pages/{zuzhangduan/zuzhangduan.json => leader/leader.json} (100%) rename pages/{zuzhangduan/zuzhangduan.wxml => leader/leader.wxml} (95%) rename pages/{zuzhangduan/zuzhangduan.wxss => leader/leader.wxss} (93%) rename pages/{guanzhual/guanzhual.js => manager-assign/manager-assign.js} (94%) rename pages/{guanzhual/guanzhual.json => manager-assign/manager-assign.json} (100%) rename pages/{guanzhual/guanzhual.wxml => manager-assign/manager-assign.wxml} (100%) rename pages/{guanzhual/guanzhual.wxss => manager-assign/manager-assign.wxss} (92%) rename pages/{guanshipaihang/guanshipaihang.js => manager-rank/manager-rank.js} (100%) rename pages/{guanshipaihang/guanshipaihang.json => manager-rank/manager-rank.json} (100%) rename pages/{guanshipaihang/guanshipaihang.wxml => manager-rank/manager-rank.wxml} (100%) rename pages/{guanshipaihang/guanshipaihang.wxss => manager-rank/manager-rank.wxss} (100%) rename pages/{guanshiduan/guanshiduan.js => manager/manager.js} (91%) rename pages/{guanshiduan/guanshiduan.json => manager/manager.json} (100%) rename pages/{guanshiduan/guanshiduan.wxml => manager/manager.wxml} (100%) rename pages/{guanshiduan/guanshiduan.wxss => manager/manager.wxss} (95%) rename pages/{sjpaidan/sjpaidan.js => merchant-dispatch/merchant-dispatch.js} (96%) rename pages/{sjpaidan/sjpaidan.json => merchant-dispatch/merchant-dispatch.json} (100%) rename pages/{sjpaidan/sjpaidan.wxml => merchant-dispatch/merchant-dispatch.wxml} (95%) rename pages/{sjpaidan/sjpaidan.wxss => merchant-dispatch/merchant-dispatch.wxss} (95%) rename pages/{sjxiaoxi/sjxiaoxi.js => merchant-msg/merchant-msg.js} (100%) rename pages/{sjxiaoxi/sjxiaoxi.json => merchant-msg/merchant-msg.json} (100%) rename pages/{sjxiaoxi/sjxiaoxi.wxml => merchant-msg/merchant-msg.wxml} (100%) rename pages/{sjxiaoxi/sjxiaoxi.wxss => merchant-msg/merchant-msg.wxss} (100%) rename pages/{sjddxq/sjddxq.js => merchant-order-detail/merchant-order-detail.js} (96%) rename pages/{dingdanxiangqing/dingdanxiangqing.json => merchant-order-detail/merchant-order-detail.json} (100%) rename pages/{sjddxq/sjddxq.wxml => merchant-order-detail/merchant-order-detail.wxml} (97%) rename pages/{sjddxq/sjddxq.wxss => merchant-order-detail/merchant-order-detail.wxss} (96%) rename pages/{sjdingdan/sjdingdan.js => merchant-orders/merchant-orders.js} (95%) rename pages/{sjdingdan/sjdingdan.json => merchant-orders/merchant-orders.json} (100%) rename pages/{sjdingdan/sjdingdan.wxml => merchant-orders/merchant-orders.wxml} (97%) rename pages/{sjdingdan/sjdingdan.wxss => merchant-orders/merchant-orders.wxss} (94%) rename pages/{sjpaihang/sjpaihang.js => merchant-rank/merchant-rank.js} (100%) rename pages/{sjpaihang/sjpaihang.json => merchant-rank/merchant-rank.json} (100%) rename pages/{sjpaihang/sjpaihang.wxml => merchant-rank/merchant-rank.wxml} (100%) rename pages/{sjpaihang/sjpaihang.wxss => merchant-rank/merchant-rank.wxss} (100%) rename pages/{sjchongzhi/sjchongzhi.js => merchant-recharge/merchant-recharge.js} (100%) rename pages/{sjchongzhi/sjchongzhi.json => merchant-recharge/merchant-recharge.json} (100%) rename pages/{sjchongzhi/sjchongzhi.wxml => merchant-recharge/merchant-recharge.wxml} (100%) rename pages/{sjchongzhi/sjchongzhi.wxss => merchant-recharge/merchant-recharge.wxss} (100%) rename pages/{shangjiaduan/shangjiaduan.js => merchant/merchant.js} (81%) rename pages/{shangjiaduan/shangjiaduan.json => merchant/merchant.json} (100%) rename pages/{shangjiaduan/shangjiaduan.wxml => merchant/merchant.wxml} (100%) rename pages/{shangjiaduan/shangjiaduan.wxss => merchant/merchant.wxss} (75%) rename pages/{xiaoxi/xiaoxi.js => messages/messages.js} (92%) rename pages/{xiaoxi/xiaoxi.json => messages/messages.json} (100%) rename pages/{xiaoxi/xiaoxi.wxml => messages/messages.wxml} (100%) rename pages/{xiaoxi/xiaoxi.wxss => messages/messages.wxss} (73%) rename pages/{wode/wode.js => mine/mine.js} (89%) rename pages/{wode/wode.json => mine/mine.json} (100%) rename pages/{wode/wode.wxml => mine/mine.wxml} (100%) rename pages/{wode/wode.wxss => mine/mine.wxss} (96%) rename pages/{wodedashou/wodedashou.js => my-fighter/my-fighter.js} (95%) rename pages/{dsddxq/dsddxq.json => my-fighter/my-fighter.json} (100%) rename pages/{wodedashou/wodedashou.wxml => my-fighter/my-fighter.wxml} (100%) rename pages/{wodedashou/wodedashou.wxss => my-fighter/my-fighter.wxss} (100%) rename pages/{dingdanxiangqing/dingdanxiangqing.js => order-detail/order-detail.js} (100%) rename pages/{shangpinxiangqing/shangpinxiangqing.json => order-detail/order-detail.json} (100%) rename pages/{dingdanxiangqing/dingdanxiangqing.wxml => order-detail/order-detail.wxml} (97%) rename pages/{dingdanxiangqing/dingdanxiangqing.wxss => order-detail/order-detail.wxss} (99%) rename pages/{jiedanchi/jiedanchi.js => order-pool/order-pool.js} (92%) rename pages/{jiedanchi/jiedanchi.json => order-pool/order-pool.json} (100%) rename pages/{jiedanchi/jiedanchi.wxml => order-pool/order-pool.wxml} (100%) rename pages/{jiedanchi/jiedanchi.wxss => order-pool/order-pool.wxss} (98%) create mode 100644 pages/order-pool2/order-pool2.js rename pages/{peihuDingdan/peihuDingdan.json => order-pool2/order-pool2.json} (100%) create mode 100644 pages/order-pool2/order-pool2.wxml create mode 100644 pages/order-pool2/order-pool2.wxss rename pages/{dingdan/dingdan.js => orders/orders.js} (90%) rename pages/{sjddxq/sjddxq.json => orders/orders.json} (100%) rename pages/{dingdan/dingdan.wxml => orders/orders.wxml} (95%) rename pages/{dingdan/dingdan.wxss => orders/orders.wxss} (66%) delete mode 100644 pages/peihuDingdan/peihuDingdan.wxml delete mode 100644 pages/peihuDingdan/peihuDingdan.wxss rename pages/{cfss => penalty}/components/fakuan-list/fakuan-list.js (100%) create mode 100644 pages/penalty/components/fakuan-list/fakuan-list.json rename pages/{cfss => penalty}/components/fakuan-list/fakuan-list.wxml (100%) rename pages/{cfss => penalty}/components/fakuan-list/fakuan-list.wxss (100%) rename pages/{cfss => penalty}/components/fakuan-pay/fakuan-pay.js (100%) rename pages/{cfss => penalty}/components/fakuan-pay/fakuan-pay.json (100%) rename pages/{cfss => penalty}/components/fakuan-pay/fakuan-pay.wxml (100%) rename pages/{cfss => penalty}/components/fakuan-pay/fakuan-pay.wxss (100%) rename pages/{cfss => penalty}/components/jifen-list/jifen-list.js (100%) rename pages/{cfss => penalty}/components/jifen-list/jifen-list.json (100%) rename pages/{cfss => penalty}/components/jifen-list/jifen-list.wxml (100%) rename pages/{cfss => penalty}/components/jifen-list/jifen-list.wxss (100%) rename pages/{cfss/cfss/cfss.js => penalty/penalty/penalty.js} (95%) rename pages/{cfss/cfss/cfss.json => penalty/penalty/penalty.json} (56%) rename pages/{cfss/cfss/cfss.wxml => penalty/penalty/penalty.wxml} (96%) rename pages/{cfss/cfss/cfss.wxss => penalty/penalty/penalty.wxss} (93%) rename pages/{jiedanchi2/jiedanchi2.js => pick-user/pick-user.js} (89%) rename pages/{xuanren/xuanren.json => pick-user/pick-user.json} (100%) rename pages/{xuanren/xuanren.wxml => pick-user/pick-user.wxml} (100%) create mode 100644 pages/pick-user/pick-user.wxss rename pages/{haibao/haibao.js => poster/poster.js} (96%) rename pages/{haibao/haibao.json => poster/poster.json} (100%) rename pages/{haibao/haibao.wxml => poster/poster.wxml} (100%) rename pages/{haibao/haibao.wxss => poster/poster.wxss} (100%) rename pages/{shangpinxiangqing/shangpinxiangqing.js => product-detail/product-detail.js} (64%) rename pages/{tijiao/tijiao.json => product-detail/product-detail.json} (100%) rename pages/{shangpinxiangqing/shangpinxiangqing.wxml => product-detail/product-detail.wxml} (84%) rename pages/{shangpinxiangqing/shangpinxiangqing.wxss => product-detail/product-detail.wxss} (87%) rename pages/{czjilu/czjilu.js => recharge-log/recharge-log.js} (100%) rename pages/{czjilu/czjilu.json => recharge-log/recharge-log.json} (100%) rename pages/{czjilu/czjilu.wxml => recharge-log/recharge-log.wxml} (100%) rename pages/{czjilu/czjilu.wxss => recharge-log/recharge-log.wxss} (100%) rename pages/{tijiao/tijiao.js => submit/submit.js} (95%) rename pages/{wodedashou/wodedashou.json => submit/submit.json} (100%) rename pages/{tijiao/tijiao.wxml => submit/submit.wxml} (96%) rename pages/{tijiao/tijiao.wxss => submit/submit.wxss} (94%) rename pages/{renzheng/renzheng.js => verify/verify.js} (89%) rename pages/{renzheng/renzheng.json => verify/verify.json} (100%) rename pages/{renzheng/renzheng.wxml => verify/verify.wxml} (95%) rename pages/{renzheng/renzheng.wxss => verify/verify.wxss} (95%) rename pages/{tixian => withdraw}/components/mode1/mode1.js (97%) rename pages/{tixian => withdraw}/components/mode1/mode1.json (100%) rename pages/{tixian => withdraw}/components/mode1/mode1.wxml (98%) rename pages/{tixian => withdraw}/components/mode1/mode1.wxss (95%) rename pages/{tixian => withdraw}/components/mode2/mode2.js (97%) rename pages/{tixian => withdraw}/components/mode2/mode2.json (100%) rename pages/{tixian => withdraw}/components/mode2/mode2.wxml (100%) rename pages/{tixian => withdraw}/components/mode2/mode2.wxss (100%) rename pages/{tixian/tixian.js => withdraw/withdraw.js} (80%) rename pages/{tixian/tixian.json => withdraw/withdraw.json} (100%) rename pages/{tixian/tixian.wxml => withdraw/withdraw.wxml} (92%) rename pages/{tixian/tixian.wxss => withdraw/withdraw.wxss} (53%) delete mode 100644 pages/xuanren/xuanren.js delete mode 100644 pages/xuanren/xuanren.wxss diff --git a/app.js b/app.js index 96aded3..811ef86 100644 --- a/app.js +++ b/app.js @@ -1,415 +1,414 @@ -// app.js - 稳健生产版本(修复 GoEasy 初始化错误 + 配置100%加载) -import GoEasy from './static/lib/goeasy-2.13.24.esm.min'; -const ChatCore = require('./utils/chat-core'); -import { check } from './utils/phone-auth'; -import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role'; - - -// ===== 三端固定首页(与 custom-tab-bar 一致) ===== -const roleDefaultPage = PRIMARY_DEFAULT_PAGES; - -App({ - globalData: { - - hasShownPopupOnColdStart: false, - - apiBaseUrl: 'https://www.abas.asia/hqhd', - ossImageUrl: '', - morentouxiang: '', - dashouguize: '', - - shangpinliebiao: [], - shangpinzhuanqu: [], - shangpinleixing: [], - shangpinlunbo: [], - shangpingonggao: '', - lunbozhanwei: '/images/lunbozhanwei.jpg', - - dingdanTiaoshu: { - daifuwu: 0, - fuwuzhong: 0, - yiwancheng: 0, - yituikuan: 0 - }, - - dashouqun: '', - dashouqunid: '', - guanshiqun: '', - guanshiqunid: '', - - appId:'wx0e4be86faac4a8d1', - - shangjiastatus: 0, - dashoustatus: 0, - guanshistatus: 0, - dashouNicheng: '', - zhanghaoStatus: null, - dashouzhuangtai: null, - yongjin: null, - zonge: null, - yajin: null, - chenghao: '', - jinfen: null, - clumber: [{ - huiyuanid: '', - huiyuanming: '', - daoqi: '' - }], - chengjiaoliang: null, - zaixianZhuangtai: null, - - guanshi: { - nicheng: '', - uid: '', - touxiang: '', - gszhstatus: '', - yaoqingzongshu: 0, - fenyongzonge: '0.00', - fenyongtixian: '0.00' - }, - - shangjia: { - sjzhzhuangtai: '', - sjyue: '', - fadanzong: null, - tuikuanzong: null, - riliushui: '', - yueliushui: '' - }, - - liaotian_liebiao: [], - xshenfen: 1, - - goEasyConfig: null, - kefuConfig: { - link: '', - enterpriseId: '' - }, - - cosConfig: { - bucket: '', - region: 'ap-shanghai', - uploadPathPrefix: 'order/' - }, - - goEasyConnection: { - status: 'disconnected', - userId: '', - identityType: '', - lastConnectTime: 0, - autoReconnect: true, - reconnectAttempts: 0, - maxReconnectAttempts: 5, - heartbeatInterval: null, - cacheKeys: { - savedConnection: 'savedGoEasyConnection', - userId: 'goEasyUserId', - identityType: 'currentGoEasyIdentity', - connectTime: 'goEasyConnectTime' - }, - config: { - heartbeatInterval: 20000, - reconnectDelay: 3000, - offlineTimeout: 30000, - cacheValidityHours: 12 - } - }, - - messageManager: { - unreadTotal: 0, - unreadMap: {}, - latestMessages: [], - notificationQueue: [], - notificationVisible: false, - lastNotificationTime: 0, - notificationCooldown: 3000, - tabBarIndex: 2, - showTabBarBadge: true, - customTabBar: true, - tabBarBadgeText: 0, - soundEnabled: true, - vibrationEnabled: true, - doNotDisturb: false, - doNotDisturbStart: '22:00', - doNotDisturbEnd: '08:00', - notificationStyle: { - position: 'top', - duration: 3000, - backgroundColor: '#00f7ff', - textColor: '#ffffff', - borderRadius: '16rpx', - boxShadow: '0 10rpx 30rpx rgba(0, 247, 255, 0.3)' - }, - currentNotification: null, - cacheKeys: { - messageSettings: 'messageSettings', - unreadTotal: 'messageUnreadTotal', - latestMessages: 'latestMessages', - notificationMuted: 'notificationMuted' - } - }, - - pageState: { - currentPage: '', - isInChatPage: false, - currentChatId: '', - lastPageUpdate: 0 - }, - - eventListeners: {}, - debugMode: false, - currentUser: null, - currentRole: 'normal', - primaryRole: 'normal' - }, - - // ========== 核心启动流程 ========== - async onLaunch() { - // ---------- ① 立即隐藏“返回首页”按钮 ---------- - wx.hideHomeButton(); - wx.onAppRoute((res) => { - wx.hideHomeButton(); - const path = (res && res.path) || ''; - if (path === 'pages/guanshiduan/guanshiduan' || path === 'pages/zuzhangduan/zuzhangduan') { - migrateLegacyCenterRole(this); - lockPrimaryRole('dashou', this); - } - }); - - // ---------- ② 恢复主端并跳转(旧管事/组长标识自动归打手端) ---------- - migrateLegacyCenterRole(this); - const savedRole = getPrimaryRole(this); - lockPrimaryRole(savedRole, this); - - const targetPage = roleDefaultPage[savedRole] || '/pages/index/index'; - if (savedRole !== 'normal') { - setTimeout(() => { - wx.reLaunch({ url: targetPage }); - }, 0); - } - - // ---------- ③ 立刻应用本地缓存配置 ---------- - const cachedConfig = this.readConfigFromStorage(); - if (cachedConfig) { - this.applyDynamicConfig(cachedConfig); - } - - // ---------- ④ 初始化基础设施 ---------- - this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化 - ChatCore.initGlobalMessageSystem(this); - this.initCurrentUser(); - - // ---------- ⑤ 建立连接 ---------- - const saved = this.getSavedConnection(); - console.log('【启动】缓存身份:', saved ? saved.identityType : '无', - 'userId:', saved ? saved.userId : '无'); - setTimeout(() => { - if (this.startImWhenReady) this.startImWhenReady(); - else if (this.ensureConnection) this.ensureConnection(); - }, 300); - - // ---------- ⑥ 后台静默获取最新配置 ---------- - this.fetchConfigSafely() - .then(latestConfig => { - this.saveConfigToStorage(latestConfig); - this.applyDynamicConfig(latestConfig); - this.initGoEasyWithConfig(); - this.initCurrentUser(); - if (this.startImWhenReady) this.startImWhenReady(); - else if (this.connectForCurrentRole) this.connectForCurrentRole(); - console.log('远程配置更新完成'); - }) - .catch(err => { - console.warn('远程配置获取失败,继续使用本地缓存', err); - }); - - // ---------- ⑦ 手机号认证检查 ---------- - try { - const needAuth = await check(); - if (needAuth) { - wx.reLaunch({ url: '/pages/phone-auth/phone-auth' }); - return; - } - } catch (e) {} - }, - - // ========== 连接管理方法 ========== - getSavedConnection() { - try { - const saved = wx.getStorageSync( - this.globalData.goEasyConnection.cacheKeys.savedConnection - ); - return saved || null; - } catch (e) { - return null; - } - }, - - // ========== 配置缓存读写 ========== - CONFIG_CACHE_KEY: 'app_dynamic_config', - - readConfigFromStorage() { - try { - const data = wx.getStorageSync(this.CONFIG_CACHE_KEY); - if (data && typeof data === 'object') { - return data; - } - } catch (e) {} - return null; - }, - - saveConfigToStorage(config) { - try { - if (config && typeof config === 'object') { - wx.setStorageSync(this.CONFIG_CACHE_KEY, config); - } - } catch (e) {} - }, - - // ========== 安全获取远程配置(永不报错) ========== - fetchConfigSafely() { - return new Promise((resolve) => { - wx.request({ - url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq', - method: 'POST', - header: { 'content-type': 'application/json' }, - success: (res) => { - if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) { - resolve(res.data.data); - } else { - console.warn('远程配置接口返回异常,使用已有配置'); - resolve(this.readConfigFromStorage() || {}); - } - }, - fail: (err) => { - console.warn('远程配置网络请求失败,使用已有配置', err); - resolve(this.readConfigFromStorage() || {}); - } - }); - }); - }, - - // ========== 原有方法(保留,仅增强) ========== - fetchDynamicConfig() { - return new Promise((resolve, reject) => { - wx.request({ - url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq', - method: 'POST', - header: { 'content-type': 'application/json' }, - success: (res) => { - if (res.statusCode === 200 && res.data && res.data.code === 0) { - resolve(res.data.data); - } else { - reject(new Error(res.data?.msg || '接口返回错误')); - } - }, - fail: reject - }); - }); - }, - - applyDynamicConfig(config) { - if (!config || typeof config !== 'object') return; - - if (config.cos) { - this.globalData.ossImageUrl = config.cos.ossImageUrl || ''; - this.globalData.cosConfig = { - bucket: config.cos.bucket || '', - region: config.cos.region || 'ap-shanghai', - uploadPathPrefix: config.cos.uploadPathPrefix || 'order/' - }; - } - - if (config.goEasy) { - this.globalData.goEasyConfig = { - host: config.goEasy.host || 'hangzhou.goeasy.io', - appkey: config.goEasy.appkey || '' - }; - } - - if (config.otherConfig) { - this.globalData.morentouxiang = config.otherConfig.morentouxiang || ''; - this.globalData.dashouguize = config.otherConfig.dashouguize || ''; - } - - if (config.kefu) { - this.globalData.kefuConfig = { - link: config.kefu.link || '', - enterpriseId: config.kefu.enterpriseId || '' - }; - } - }, - - // 🔥 关键修复:只在有效 appkey 时初始化,且避免重复初始化 - initGoEasyWithConfig() { - const cfg = this.globalData.goEasyConfig; - if (!cfg || !cfg.appkey) { - console.warn('GoEasy appkey 未配置,聊天功能将在配置就绪后自动恢复'); - return; - } - - // 如果已经初始化过,就不再重复创建实例 - if (wx.goEasy && wx.GoEasy) { - console.log('GoEasy 已初始化,跳过'); - return; - } - - try { - wx.goEasy = GoEasy.getInstance({ - host: cfg.host || 'hangzhou.goeasy.io', - appkey: cfg.appkey, - modules: ['im', 'pubsub'] - }); - wx.GoEasy = GoEasy; - console.log('GoEasy 初始化成功'); - if (this.startImWhenReady && wx.getStorageSync('uid')) { - setTimeout(() => this.startImWhenReady(), 100); - } - } catch (error) { - console.error('GoEasy 初始化失败:', error); - } - }, - - initCurrentUser() { - const uid = wx.getStorageSync('uid'); - if (uid) { - this.globalData.currentUser = { - id: uid, - name: '用户' + uid.substring(0, 6), - avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang - }; - } - }, - - emitEvent(eventName, data) { - if (this.globalData.eventListeners[eventName]) { - this.globalData.eventListeners[eventName].forEach(callback => { - try { callback(data); } catch (error) { console.error(error); } - }); - } - }, - - /** 切换当前角色并通知 custom-tab-bar 立即刷新(Storage + globalData + 事件) */ - setCurrentRole(role) { - if (!role) return; - this.globalData.currentRole = role; - wx.setStorageSync('currentRole', role); - this.emitEvent('currentRoleChanged', { role }); - }, - - on(eventName, callback) { - if (!this.globalData.eventListeners[eventName]) { - this.globalData.eventListeners[eventName] = []; - } - this.globalData.eventListeners[eventName].push(callback); - }, - - off(eventName, callback) { - if (this.globalData.eventListeners[eventName]) { - const index = this.globalData.eventListeners[eventName].indexOf(callback); - if (index > -1) { - this.globalData.eventListeners[eventName].splice(index, 1); - } - } - } +// app.js +import GoEasy from './static/lib/goeasy-2.13.24.esm.min'; +const ChatCore = require('./utils/chat-core'); +import { check } from './utils/phone-auth'; +import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role'; + +// 三端固定首页 +const roleDefaultPage = PRIMARY_DEFAULT_PAGES; + +App({ + globalData: { + + hasShownPopupOnColdStart: false, + + apiBaseUrl: 'https://www.abas.asia/hqhd', + ossImageUrl: '', + morentouxiang: '', + dashouguize: '', + + shangpinliebiao: [], + shangpinzhuanqu: [], + shangpinleixing: [], + shangpinlunbo: [], + shangpingonggao: '', + lunbozhanwei: '/images/lunbozhanwei.jpg', + + dingdanTiaoshu: { + daifuwu: 0, + fuwuzhong: 0, + yiwancheng: 0, + yituikuan: 0 + }, + + dashouqun: '', + dashouqunid: '', + guanshiqun: '', + guanshiqunid: '', + + appId:'wx0e4be86faac4a8d1', + + shangjiastatus: 0, + dashoustatus: 0, + guanshistatus: 0, + dashouNicheng: '', + zhanghaoStatus: null, + dashouzhuangtai: null, + yongjin: null, + zonge: null, + yajin: null, + chenghao: '', + jinfen: null, + clumber: [{ + huiyuanid: '', + huiyuanming: '', + daoqi: '' + }], + chengjiaoliang: null, + zaixianZhuangtai: null, + + guanshi: { + nicheng: '', + uid: '', + touxiang: '', + gszhstatus: '', + yaoqingzongshu: 0, + fenyongzonge: '0.00', + fenyongtixian: '0.00' + }, + + shangjia: { + sjzhzhuangtai: '', + sjyue: '', + fadanzong: null, + tuikuanzong: null, + riliushui: '', + yueliushui: '' + }, + + liaotian_liebiao: [], + xshenfen: 1, + + goEasyConfig: null, + kefuConfig: { + link: '', + enterpriseId: '' + }, + + cosConfig: { + bucket: '', + region: 'ap-shanghai', + uploadPathPrefix: 'order/' + }, + + goEasyConnection: { + status: 'disconnected', + userId: '', + identityType: '', + lastConnectTime: 0, + autoReconnect: true, + reconnectAttempts: 0, + maxReconnectAttempts: 5, + heartbeatInterval: null, + cacheKeys: { + savedConnection: 'savedGoEasyConnection', + userId: 'goEasyUserId', + identityType: 'currentGoEasyIdentity', + connectTime: 'goEasyConnectTime' + }, + config: { + heartbeatInterval: 20000, + reconnectDelay: 3000, + offlineTimeout: 30000, + cacheValidityHours: 12 + } + }, + + messageManager: { + unreadTotal: 0, + unreadMap: {}, + latestMessages: [], + notificationQueue: [], + notificationVisible: false, + lastNotificationTime: 0, + notificationCooldown: 3000, + tabBarIndex: 2, + showTabBarBadge: true, + customTabBar: true, + tabBarBadgeText: 0, + soundEnabled: true, + vibrationEnabled: true, + doNotDisturb: false, + doNotDisturbStart: '22:00', + doNotDisturbEnd: '08:00', + notificationStyle: { + position: 'top', + duration: 3000, + backgroundColor: '#00f7ff', + textColor: '#ffffff', + borderRadius: '16rpx', + boxShadow: '0 10rpx 30rpx rgba(0, 247, 255, 0.3)' + }, + currentNotification: null, + cacheKeys: { + messageSettings: 'messageSettings', + unreadTotal: 'messageUnreadTotal', + latestMessages: 'latestMessages', + notificationMuted: 'notificationMuted' + } + }, + + pageState: { + currentPage: '', + isInChatPage: false, + currentChatId: '', + lastPageUpdate: 0 + }, + + eventListeners: {}, + debugMode: false, + currentUser: null, + currentRole: 'normal', + primaryRole: 'normal' + }, + + // 核心启动流程 + async onLaunch() { + // ① 隐藏返回首页按钮 + wx.hideHomeButton(); + wx.onAppRoute((res) => { + wx.hideHomeButton(); + const path = (res && res.path) || ''; + if (path === 'pages/manager/manager' || path === 'pages/leader/leader') { + migrateLegacyCenterRole(this); + lockPrimaryRole('dashou', this); + } + }); + + // ② 恢复主端并跳转 + migrateLegacyCenterRole(this); + const savedRole = getPrimaryRole(this); + lockPrimaryRole(savedRole, this); + + const targetPage = roleDefaultPage[savedRole] || '/pages/index/index'; + if (savedRole !== 'normal') { + setTimeout(() => { + wx.reLaunch({ url: targetPage }); + }, 0); + } + + // ③ 应用本地缓存配置 + const cachedConfig = this.readConfigFromStorage(); + if (cachedConfig) { + this.applyDynamicConfig(cachedConfig); + } + + // ④ 初始化 + this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化 + ChatCore.initGlobalMessageSystem(this); + this.initCurrentUser(); + + // ⑤ 建立连接 + const saved = this.getSavedConnection(); + console.log('【启动】缓存身份:', saved ? saved.identityType : '无', + 'userId:', saved ? saved.userId : '无'); + setTimeout(() => { + if (this.startImWhenReady) this.startImWhenReady(); + else if (this.ensureConnection) this.ensureConnection(); + }, 300); + + // ⑥ 获取远程配置 + this.fetchConfigSafely() + .then(latestConfig => { + this.saveConfigToStorage(latestConfig); + this.applyDynamicConfig(latestConfig); + this.initGoEasyWithConfig(); + this.initCurrentUser(); + if (this.startImWhenReady) this.startImWhenReady(); + else if (this.connectForCurrentRole) this.connectForCurrentRole(); + console.log('远程配置更新完成'); + }) + .catch(err => { + console.warn('远程配置获取失败,继续使用本地缓存', err); + }); + + // ⑦ 手机号认证检查 + try { + const needAuth = await check(); + if (needAuth) { + wx.reLaunch({ url: '/pages/phone-auth/phone-auth' }); + return; + } + } catch (e) {} + }, + + // 连接管理方法 + getSavedConnection() { + try { + const saved = wx.getStorageSync( + this.globalData.goEasyConnection.cacheKeys.savedConnection + ); + return saved || null; + } catch (e) { + return null; + } + }, + + // 配置缓存读写 + CONFIG_CACHE_KEY: 'app_dynamic_config', + + readConfigFromStorage() { + try { + const data = wx.getStorageSync(this.CONFIG_CACHE_KEY); + if (data && typeof data === 'object') { + return data; + } + } catch (e) {} + return null; + }, + + saveConfigToStorage(config) { + try { + if (config && typeof config === 'object') { + wx.setStorageSync(this.CONFIG_CACHE_KEY, config); + } + } catch (e) {} + }, + + // 获取远程配置 + fetchConfigSafely() { + return new Promise((resolve) => { + wx.request({ + url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq', + method: 'POST', + header: { 'content-type': 'application/json' }, + success: (res) => { + if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) { + resolve(res.data.data); + } else { + console.warn('远程配置接口返回异常,使用已有配置'); + resolve(this.readConfigFromStorage() || {}); + } + }, + fail: (err) => { + console.warn('远程配置网络请求失败,使用已有配置', err); + resolve(this.readConfigFromStorage() || {}); + } + }); + }); + }, + + // 获取远程配置 + fetchDynamicConfig() { + return new Promise((resolve, reject) => { + wx.request({ + url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq', + method: 'POST', + header: { 'content-type': 'application/json' }, + success: (res) => { + if (res.statusCode === 200 && res.data && res.data.code === 0) { + resolve(res.data.data); + } else { + reject(new Error(res.data?.msg || '接口返回错误')); + } + }, + fail: reject + }); + }); + }, + + applyDynamicConfig(config) { + if (!config || typeof config !== 'object') return; + + if (config.cos) { + this.globalData.ossImageUrl = config.cos.ossImageUrl || ''; + this.globalData.cosConfig = { + bucket: config.cos.bucket || '', + region: config.cos.region || 'ap-shanghai', + uploadPathPrefix: config.cos.uploadPathPrefix || 'order/' + }; + } + + if (config.goEasy) { + this.globalData.goEasyConfig = { + host: config.goEasy.host || 'hangzhou.goeasy.io', + appkey: config.goEasy.appkey || '' + }; + } + + if (config.otherConfig) { + this.globalData.morentouxiang = config.otherConfig.morentouxiang || ''; + this.globalData.dashouguize = config.otherConfig.dashouguize || ''; + } + + if (config.kefu) { + this.globalData.kefuConfig = { + link: config.kefu.link || '', + enterpriseId: config.kefu.enterpriseId || '' + }; + } + }, + + // 仅在有效 appkey 时初始化 + initGoEasyWithConfig() { + const cfg = this.globalData.goEasyConfig; + if (!cfg || !cfg.appkey) { + console.warn('GoEasy appkey 未配置,聊天功能将在配置就绪后自动恢复'); + return; + } + + // 避免重复初始化 + if (wx.goEasy && wx.GoEasy) { + console.log('GoEasy 已初始化,跳过'); + return; + } + + try { + wx.goEasy = GoEasy.getInstance({ + host: cfg.host || 'hangzhou.goeasy.io', + appkey: cfg.appkey, + modules: ['im', 'pubsub'] + }); + wx.GoEasy = GoEasy; + console.log('GoEasy 初始化成功'); + if (this.startImWhenReady && wx.getStorageSync('uid')) { + setTimeout(() => this.startImWhenReady(), 100); + } + } catch (error) { + console.error('GoEasy 初始化失败:', error); + } + }, + + initCurrentUser() { + const uid = wx.getStorageSync('uid'); + if (uid) { + this.globalData.currentUser = { + id: uid, + name: '用户' + uid.substring(0, 6), + avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang + }; + } + }, + + emitEvent(eventName, data) { + if (this.globalData.eventListeners[eventName]) { + this.globalData.eventListeners[eventName].forEach(callback => { + try { callback(data); } catch (error) { console.error(error); } + }); + } + }, + + /** 切换角色并通知刷新 */ + setCurrentRole(role) { + if (!role) return; + this.globalData.currentRole = role; + wx.setStorageSync('currentRole', role); + this.emitEvent('currentRoleChanged', { role }); + }, + + on(eventName, callback) { + if (!this.globalData.eventListeners[eventName]) { + this.globalData.eventListeners[eventName] = []; + } + this.globalData.eventListeners[eventName].push(callback); + }, + + off(eventName, callback) { + if (this.globalData.eventListeners[eventName]) { + const index = this.globalData.eventListeners[eventName].indexOf(callback); + if (index > -1) { + this.globalData.eventListeners[eventName].splice(index, 1); + } + } + } }); \ No newline at end of file diff --git a/app.json b/app.json index ee7781d..3c5f34c 100644 --- a/app.json +++ b/app.json @@ -1,107 +1,107 @@ -{ - "pages": [ - "pages/index/index", - "pages/fenlei/fenlei", - "pages/xuanren/xuanren", - "pages/xiaoxi/xiaoxi", - "pages/wode/wode", - "pages/shangpinxiangqing/shangpinxiangqing", - "pages/tijiao/tijiao", - "pages/xiugai/xiugai", - "pages/dashouduan/dashouduan", - "pages/shangjiaduan/shangjiaduan", - "pages/guanshiduan/guanshiduan", - "pages/dingdan/dingdan", - "pages/dingdanxiangqing/dingdanxiangqing", - "pages/dashouguize/dashouguize", - "pages/dashouxiugai/dashouxiugai", - "pages/dashoupaihang/dashoupaihang", - "pages/dashouchongzhi/dashouchongzhi", - "pages/dashouxiaoxi/dashouxiaoxi", - "pages/dashoudingdan/dashoudingdan", - "pages/jiedan/jiedan", - "pages/tixian/tixian", - "pages/yaoqingdashou/yaoqingdashou", - "pages/wodedashou/wodedashou", - "pages/czjilu/czjilu", - "pages/guanshipaihang/guanshipaihang", - "pages/sjpaidan/sjpaidan", - "pages/sjdingdan/sjdingdan", - "pages/sjxiaoxi/sjxiaoxi", - "pages/sjpaihang/sjpaihang", - "pages/sjchongzhi/sjchongzhi", - "pages/sjddxq/sjddxq", - "pages/dsddxq/dsddxq", - "pages/liaotian/liaotian", - "pages/jisufd/jisufd", - "pages/jiedanchi/jiedanchi", - "pages/haibao/haibao", - "pages/jinpaids/jinpaids", - "pages/zuzhangduan/zuzhangduan", - "pages/guanzhual/guanzhual", - "pages/zzfhjilu/zzfhjilu", - "pages/yqguanshi/yqguanshi", - "pages/jiedanchi2/jiedanchi2", - "pages/qunliaotian/qunliaotian", - "pages/kefuliaotian/kefuliaotian", - "pages/renzheng/renzheng", - "components/global-notification/global-notification", - "components/popup-notice/popup-notice", - "components/order-card/order-card", - "components/order-sender/order-sender", - "pages/cfss/cfss/cfss", - "pages/cfss/components/fakuan-list/fakuan-list", - "pages/cfss/components/jifen-list/jifen-list", - "pages/cfss/components/fakuan-pay/fakuan-pay", - "pages/phone-auth/phone-auth", - "components/chenghao-tag/chenghao-tag", - "pages/kaoheguan/kaoheguan", - "pages/kaohe_dafen/kaohe_dafen", - "pages/kaohe_jilu/kaohe_jilu", - "pages/kaohe_zhongxin/kaohe_zhongxin", - "pages/kaohe_jinpai/kaohe_jinpai", - "pages/peihuDingdan/peihuDingdan", - "pages/tixian/components/mode1/mode1", - "pages/tixian/components/mode2/mode2" - - - ], - - "usingComponents": { - "popup-notice": "/components/popup-notice/popup-notice", - "custom-tab-bar": "/custom-tab-bar/index" - }, - - "window": { - "navigationBarTextStyle": "black", - "navigationStyle": "default", - "backgroundTextStyle": "light", - "navigationBarBackgroundColor": "#fff", - "navigationBarTitleText": "星阙网络" - }, - "tabBar": { - "custom": true, - "list": [ - - - { - "pagePath": "pages/jiedanchi/jiedanchi", - "text": "接单池", - "iconPath": "/images/jiedanchi.png", - "selectedIconPath": "/images/jiedanchi.png" - }, - { - "pagePath": "pages/jiedanchi2/jiedanchi2", - "text": "接单池", - "iconPath": "/images/jiedanchi.png", - "selectedIconPath": "/images/jiedanchi.png" - } - - ] - }, - - - "style": "v2", - "sitemapLocation": "sitemap.json", - "lazyCodeLoading": "requiredComponents" +{ + "pages": [ + "pages/index/index", + "pages/category/category", + "pages/pick-user/pick-user", + "pages/messages/messages", + "pages/mine/mine", + "pages/product-detail/product-detail", + "pages/submit/submit", + "pages/edit/edit", + "pages/fighter/fighter", + "pages/merchant/merchant", + "pages/manager/manager", + "pages/orders/orders", + "pages/order-detail/order-detail", + "pages/fighter-rules/fighter-rules", + "pages/fighter-edit/fighter-edit", + "pages/fighter-rank/fighter-rank", + "pages/fighter-recharge/fighter-recharge", + "pages/fighter-msg/fighter-msg", + "pages/fighter-orders/fighter-orders", + "pages/accept-order/accept-order", + "pages/withdraw/withdraw", + "pages/invite-fighter/invite-fighter", + "pages/my-fighter/my-fighter", + "pages/recharge-log/recharge-log", + "pages/manager-rank/manager-rank", + "pages/merchant-dispatch/merchant-dispatch", + "pages/merchant-orders/merchant-orders", + "pages/merchant-msg/merchant-msg", + "pages/merchant-rank/merchant-rank", + "pages/merchant-recharge/merchant-recharge", + "pages/merchant-order-detail/merchant-order-detail", + "pages/fighter-order-detail/fighter-order-detail", + "pages/chat/chat", + "pages/express-order/express-order", + "pages/order-pool/order-pool", + "pages/poster/poster", + "pages/gold-fighter/gold-fighter", + "pages/leader/leader", + "pages/manager-assign/manager-assign", + "pages/leader-bonus-log/leader-bonus-log", + "pages/invite-manager/invite-manager", + "pages/order-pool2/order-pool2", + "pages/group-chat/group-chat", + "pages/cs-chat/cs-chat", + "pages/verify/verify", + "components/global-notification/global-notification", + "components/popup-notice/popup-notice", + "components/order-card/order-card", + "components/order-sender/order-sender", + "pages/penalty/penalty/penalty", + "pages/penalty/components/fakuan-list/fakuan-list", + "pages/penalty/components/jifen-list/jifen-list", + "pages/penalty/components/fakuan-pay/fakuan-pay", + "pages/phone-auth/phone-auth", + "components/chenghao-tag/chenghao-tag", + "pages/assessor/assessor", + "pages/assess-score/assess-score", + "pages/assess-log/assess-log", + "pages/assess-center/assess-center", + "pages/assess-gold/assess-gold", + "pages/escort-orders/escort-orders", + "pages/withdraw/components/mode1/mode1", + "pages/withdraw/components/mode2/mode2" + + + ], + + "usingComponents": { + "popup-notice": "/components/popup-notice/popup-notice", + "custom-tab-bar": "/custom-tab-bar/index" + }, + + "window": { + "navigationBarTextStyle": "black", + "navigationStyle": "default", + "backgroundTextStyle": "light", + "navigationBarBackgroundColor": "#fff", + "navigationBarTitleText": "星阙网络" + }, + "tabBar": { + "custom": true, + "list": [ + + + { + "pagePath": "pages/order-pool/order-pool", + "text": "接单池", + "iconPath": "/images/jiedanchi.png", + "selectedIconPath": "/images/jiedanchi.png" + }, + { + "pagePath": "pages/order-pool2/order-pool2", + "text": "接单池", + "iconPath": "/images/jiedanchi.png", + "selectedIconPath": "/images/jiedanchi.png" + } + + ] + }, + + + "style": "v2", + "sitemapLocation": "sitemap.json", + "lazyCodeLoading": "requiredComponents" } \ No newline at end of file diff --git a/app.wxss b/app.wxss index 06c6fc9..958f5ce 100644 --- a/app.wxss +++ b/app.wxss @@ -1,10 +1,889 @@ -/**app.wxss**/ -.container { - height: 100%; +/* app.wxss — 全局共享样式 */ + +/* ========== CSS 变量 ========== */ +page { + --color-price: #ff4444; + --color-text-main: #333; + --color-text-gray: #999; + --color-border-light: #f0f0f0; + --bg-white: #ffffff; + --bg-gray-hover: #f5f5f5; + + --radius-lg: 30rpx; + --radius-normal: 25rpx; + --radius-full: 50%; + + --padding-base: 40rpx; + --shadow-modal: 0 20rpx 60rpx rgba(0, 0, 0, 0.2); + + box-sizing: border-box; +} + +/* ========== 动画 ========== */ +@keyframes spin { + to { transform: rotate(360deg); } +} + +@keyframes pulse { + 0%, 100% { opacity: 0.8; transform: scale(1); } + 50% { opacity: 1; transform: scale(1.2); } +} + +@keyframes modalShow { + from { opacity: 0; transform: scale(0.9); } + to { opacity: 1; transform: scale(1); } +} + +@keyframes marquee { + 0% { transform: translateX(100%); } + 100% { transform: translateX(-100%); } +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +@keyframes slideUp { + from { transform: translateY(100%); } + to { transform: translateY(0); } +} + +@keyframes slideDown { + from { transform: translateY(0); } + to { transform: translateY(100%); } +} + +/* ========== 加载提示 ========== */ +.loading-toast { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(10px); + padding: 30rpx 50rpx; + border-radius: var(--radius-normal); display: flex; flex-direction: column; align-items: center; + z-index: 999; +} + +.loading-spinner { + width: 60rpx; + height: 60rpx; + border: 6rpx solid rgba(255, 255, 255, 0.3); + border-top-color: #fff; + border-radius: var(--radius-full); + animation: spin 1s linear infinite; + margin-bottom: 20rpx; +} + +.loading-text { + font-size: 26rpx; + color: #fff; +} + +/* ========== 价格组件 ========== */ +.price-wrap { + color: var(--color-price); + font-weight: bold; +} +.price-icon { + font-size: 24rpx; + margin-right: 2rpx; +} +.price-integer { + font-size: 32rpx; +} +.price-decimal { + font-size: 24rpx; +} + +/* ========== 弹窗基础 ========== */ +.modal-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(5px); + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-content { + width: 600rpx; + background: var(--bg-white); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-modal); + z-index: 1001; + animation: modalShow 0.3s ease-out; +} + +.modal-header { + padding: var(--padding-base); + border-bottom: 2rpx solid var(--color-border-light); + display: flex; justify-content: space-between; - padding: 200rpx 0; + align-items: center; +} + +.modal-title { + font-size: 32rpx; + font-weight: bold; + color: var(--color-text-main); +} + +.modal-close { + font-size: 40rpx; + color: var(--color-text-gray); + width: 60rpx; + height: 60rpx; + display: flex; + justify-content: center; + align-items: center; + border-radius: var(--radius-full); + flex-shrink: 0; +} +.modal-close:active { + background: var(--bg-gray-hover); +} + +.modal-body { + max-height: 600rpx; + padding: var(--padding-base); + overflow-y: auto; +} + +.modal-text { + font-size: 28rpx; + color: var(--color-text-main); + line-height: 1.6; + white-space: normal; + word-break: break-word; +} + +/* ========== Flex 工具类 ========== */ +.flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +.flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +.flex-column { + display: flex; + flex-direction: column; +} + +.flex-column-center { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.flex-1 { + flex: 1; + min-width: 0; +} + +.flex-shrink-0 { + flex-shrink: 0; +} + +.flex-wrap { + flex-wrap: wrap; +} + +/* ========== 文本工具类 ========== */ +.text-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-ellipsis-2 { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; +} + +.text-ellipsis-3 { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + overflow: hidden; + text-overflow: ellipsis; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-bold { + font-weight: bold; +} + +.text-gray { + color: var(--color-text-gray); +} + +.text-main { + color: var(--color-text-main); +} + +/* ========== 安全区域 ========== */ +.safe-bottom { + padding-bottom: env(safe-area-inset-bottom); +} + +.safe-bottom-fixed { + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding-bottom: env(safe-area-inset-bottom); +} + +/* ========== 通用卡片 ========== */ +.card { + background: var(--bg-white); + border-radius: var(--radius-lg); + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); + overflow: hidden; +} + +.card-padding { + padding: var(--padding-base); +} + +/* ========== 毛玻璃 ========== */ +.glass { + background: rgba(255, 255, 255, 0.72); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} + +.glass-dark { + background: rgba(0, 0, 0, 0.55); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} + +/* ========== 圆形头像 ========== */ +.avatar-circle { + border-radius: var(--radius-full); + border: 2rpx solid #fff; + object-fit: cover; + flex-shrink: 0; +} + +.avatar-sm { + width: 64rpx; + height: 64rpx; +} + +.avatar-md { + width: 88rpx; + height: 88rpx; +} + +.avatar-lg { + width: 120rpx; + height: 120rpx; +} + +/* ========== 红点/角标 ========== */ +.badge-dot { + position: absolute; + top: -6rpx; + right: -6rpx; + width: 16rpx; + height: 16rpx; + background: #fa5151; + border-radius: var(--radius-full); + border: 2rpx solid #fff; +} + +.badge-num { + position: absolute; + top: -10rpx; + right: -10rpx; + min-width: 32rpx; + height: 32rpx; + line-height: 32rpx; + padding: 0 8rpx; + background: #fa5151; + color: #fff; + font-size: 20rpx; + font-weight: 600; + border-radius: 16rpx; + text-align: center; + border: 2rpx solid #fff; +} + +/* ========== 空状态 ========== */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 120rpx 40rpx; +} + +.empty-icon { + width: 200rpx; + height: 200rpx; + margin-bottom: 30rpx; + opacity: 0.5; +} + +.empty-text { + font-size: 30rpx; + color: var(--color-text-gray); + margin-bottom: 10rpx; +} + +.empty-subtext { + font-size: 26rpx; + color: #ccc; +} + +/* ========== 分割线 ========== */ +.divider { + height: 2rpx; + background: var(--color-border-light); + margin: 20rpx 0; +} + +.divider-light { + height: 1rpx; + background: rgba(0, 0, 0, 0.04); + margin: 16rpx 0; +} + +.divider-gradient { + height: 2rpx; + background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1), transparent); + margin: 20rpx 0; +} + +/* ========== 固定底部按钮区 ========== */ +.fixed-bottom { + position: fixed; + left: 0; + right: 0; + bottom: 0; + padding: 20rpx 30rpx; + padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); + background: linear-gradient(transparent, rgba(255, 255, 255, 0.95) 30%); + z-index: 100; +} + +/* ========== 列表项 ========== */ +.list-item { + display: flex; + align-items: center; + padding: 24rpx 28rpx; + border-bottom: 1rpx solid rgba(0, 0, 0, 0.04); +} + +.list-item:last-child { + border-bottom: none; +} + +.list-icon { + width: 36rpx; + height: 36rpx; + margin-right: 16rpx; + flex-shrink: 0; +} + +.list-text { + flex: 1; + font-size: 28rpx; + color: var(--color-text-main); +} + +.list-arrow { + width: 20rpx; + height: 20rpx; + opacity: 0.4; + flex-shrink: 0; +} + +/* ========== 标签 ========== */ +.tag { + display: inline-flex; + align-items: center; + padding: 4rpx 14rpx; + border-radius: 999rpx; + font-size: 20rpx; + font-weight: 600; + line-height: 1.4; +} + +.tag-primary { + background: rgba(64, 156, 255, 0.1); + color: #409cff; +} + +.tag-success { + background: rgba(82, 196, 26, 0.1); + color: #52c41a; +} + +.tag-warning { + background: rgba(250, 173, 20, 0.1); + color: #faad14; +} + +.tag-danger { + background: rgba(255, 77, 79, 0.1); + color: #ff4d4f; +} + +.tag-gold { + background: rgba(201, 169, 98, 0.1); + color: #C9A962; +} + +/* ========== 页面容器 ========== */ +.page-container { + min-height: 100vh; + position: relative; +} + +.page-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; + pointer-events: none; +} + +/* ========== 按钮 ========== */ +.btn { + display: flex; + align-items: center; + justify-content: center; + border-radius: 48rpx; + font-weight: 600; + text-align: center; + border: none; + position: relative; + overflow: hidden; + transition: all 0.2s ease; +} + +.btn:active { + transform: scale(0.98); +} + +/* 主按钮(全宽) */ +.btn-primary { + width: 100%; + height: 96rpx; + line-height: 96rpx; + font-size: 34rpx; + color: #fff; +} + +.btn-primary--gold { + background: linear-gradient(135deg, #C9A962, #D4B56A); + box-shadow: 0 8rpx 20rpx rgba(201, 169, 98, 0.3); +} + +.btn-primary--green { + background: linear-gradient(135deg, #52c41a, #389e0d); + box-shadow: 0 8rpx 20rpx rgba(82, 196, 26, 0.3); +} + +.btn-primary--blue { + background: linear-gradient(135deg, #409cff, #3080e0); + box-shadow: 0 8rpx 20rpx rgba(64, 156, 255, 0.3); +} + +.btn-primary--orange { + background: linear-gradient(135deg, #ffb347, #ff8c1a); + box-shadow: 0 8rpx 20rpx rgba(255, 140, 26, 0.3); +} + +.btn-primary--purple { + background: linear-gradient(135deg, #6a11cb, #2575fc); + box-shadow: 0 8rpx 20rpx rgba(106, 17, 203, 0.3); +} + +.btn-primary--red { + background: linear-gradient(135deg, #ff4d4f, #cf1322); + box-shadow: 0 8rpx 20rpx rgba(255, 77, 79, 0.3); +} + +/* 次要按钮 */ +.btn-secondary { + background: rgba(0, 0, 0, 0.04); + color: var(--color-text-main); + font-size: 28rpx; + padding: 16rpx 32rpx; +} + +.btn-secondary:active { + background: rgba(0, 0, 0, 0.08); +} + +/* 小型按钮 */ +.btn-sm { + padding: 14rpx 32rpx; + font-size: 26rpx; + color: #fff; + border-radius: 40rpx; +} + +.btn-sm--gold { + background: linear-gradient(135deg, #ffcc00, #ffaa00); + box-shadow: 0 6rpx 16rpx rgba(255, 170, 0, 0.3); +} + +.btn-sm--green { + background: linear-gradient(135deg, #52c41a, #389e0d); + box-shadow: 0 6rpx 16rpx rgba(82, 196, 26, 0.3); +} + +.btn-sm--blue { + background: linear-gradient(135deg, #409cff, #3080e0); + box-shadow: 0 6rpx 16rpx rgba(64, 156, 255, 0.3); +} + +.btn-sm--red { + background: linear-gradient(135deg, #ff4d4f, #cf1322); + box-shadow: 0 6rpx 16rpx rgba(255, 77, 79, 0.3); +} + +.btn-sm--dark { + background: linear-gradient(135deg, #3d4f66, #2c3e50); + box-shadow: 0 6rpx 16rpx rgba(44, 62, 80, 0.3); +} + +/* 幽灵按钮(描边) */ +.btn-ghost { + background: transparent; + border: 2rpx solid currentColor; + padding: 14rpx 32rpx; + font-size: 26rpx; + font-weight: 600; +} + +.btn-ghost--primary { + color: #409cff; + border-color: #409cff; +} + +.btn-ghost--gold { + color: #C9A962; + border-color: #C9A962; +} + +/* 禁用状态 */ +.btn[disabled], +.btn-disabled { + opacity: 0.5; + pointer-events: none; +} + +/* ========== 输入框 ========== */ +.input-rounded { + width: 100%; + height: 88rpx; + background: #fff; + border-radius: 44rpx; + padding: 0 32rpx; + font-size: 28rpx; + color: var(--color-text-main); box-sizing: border-box; -} + border: none; +} + +.input-rounded--dark { + background: rgba(255, 255, 255, 0.15); + color: #fff; + border: 1rpx solid rgba(255, 255, 255, 0.3); +} + +.input-rounded--dark::placeholder { + color: rgba(255, 255, 255, 0.5); +} + +.input-inline { + flex: 1; + font-size: 32rpx; + color: var(--color-text-main); + height: 50rpx; + line-height: 50rpx; + border: none; + background: transparent; +} + +.input-box { + background: #F7F3ED; + border-radius: 24rpx; + padding: 0 24rpx; +} + +/* ========== 搜索框 ========== */ +.search-box { + display: flex; + align-items: center; + background: #f0f0f0; + border-radius: 40rpx; + padding: 0 20rpx; + height: 68rpx; +} + +.search-box--glass { + background: rgba(255, 255, 255, 0.85); + backdrop-filter: blur(20px); + border: 1rpx solid rgba(255, 255, 255, 0.3); + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06); + height: 84rpx; + border-radius: 50rpx; + padding: 0 28rpx; +} + +.search-input { + flex: 1; + height: 100%; + font-size: 28rpx; + margin-left: 10rpx; +} + +.search-icon { + width: 32rpx; + height: 32rpx; + opacity: 0.5; + flex-shrink: 0; +} + +/* ========== Tab 标签栏 ========== */ +.tab-bar { + display: flex; + background: #fff; + border-bottom: 1rpx solid #f0f0f0; +} + +.tab-item { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + padding: 24rpx 0; + position: relative; + color: #666; + font-size: 28rpx; + transition: color 0.3s; +} + +.tab-item--active { + color: var(--color-price); + font-weight: 600; +} + +.tab-indicator { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 60rpx; + height: 6rpx; + background: var(--color-price); + border-radius: 3rpx; +} + +/* 胶囊式 Tab */ +.tab-capsule { + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 60rpx; + padding: 0 30rpx; + margin-right: 20rpx; + border-radius: 30rpx; + background: #f5f5f5; + color: #666; + font-size: 28rpx; + flex-shrink: 0; + transition: all 0.3s ease; +} + +.tab-capsule--active { + background: #e8f5e9; + color: #2e7d32; + font-weight: 500; + box-shadow: 0 4rpx 12rpx rgba(46, 125, 50, 0.1); +} + +/* ========== 加载遮罩 ========== */ +.loading-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +.loading-mask--dark { + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(10px); +} + +.loading-mask--light { + background: rgba(255, 255, 255, 0.85); +} + +/* 旋转器尺寸变体 */ +.spinner { + border-radius: var(--radius-full); + animation: spin 0.8s linear infinite; +} + +.spinner--sm { + width: 40rpx; + height: 40rpx; + border: 3rpx solid rgba(0, 0, 0, 0.08); + border-top-color: var(--color-text-main); +} + +.spinner--md { + width: 60rpx; + height: 60rpx; + border: 5rpx solid rgba(0, 0, 0, 0.08); + border-top-color: var(--color-text-main); +} + +.spinner--lg { + width: 80rpx; + height: 80rpx; + border: 6rpx solid rgba(0, 0, 0, 0.08); + border-top-color: var(--color-text-main); +} + +.spinner--white { + border-color: rgba(255, 255, 255, 0.3); + border-top-color: #fff; +} + +/* ========== 刷新按钮 ========== */ +.refresh-btn { + position: fixed; + top: 36rpx; + right: 32rpx; + width: 56rpx; + height: 56rpx; + border-radius: var(--radius-full); + display: flex; + align-items: center; + justify-content: center; + z-index: 20; +} + +.refresh-btn--light { + background: rgba(255, 255, 255, 0.8); + backdrop-filter: blur(12rpx); + border: 1rpx solid rgba(255, 255, 255, 0.6); + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05); +} + +.refresh-btn--dark { + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(10rpx); +} + +.refresh-icon { + width: 28rpx; + height: 28rpx; +} + +/* ========== 状态标签 ========== */ +.status-tag { + display: inline-flex; + align-items: center; + padding: 6rpx 16rpx; + border-radius: 20rpx; + font-size: 24rpx; + font-weight: 500; + white-space: nowrap; +} + +.status-tag--danger { + background: #fff5f5; + color: #ff6b6b; +} + +.status-tag--success { + background: #f0fff0; + color: #52c41a; +} + +.status-tag--warning { + background: #fffbe6; + color: #faad14; +} + +.status-tag--info { + background: #e6f7ff; + color: #1890ff; +} + +.status-tag--default { + background: #f5f5f5; + color: #999; +} + +/* ========== 加载更多 ========== */ +.load-more { + display: flex; + align-items: center; + justify-content: center; + padding: 40rpx 0; +} + +.load-more-text { + font-size: 26rpx; + color: var(--color-text-gray); +} + +.no-more { + text-align: center; + padding: 40rpx 0; + font-size: 26rpx; + color: #ccc; +} diff --git a/components/global-notification/global-notification.js b/components/global-notification/global-notification.js index f6a2b5a..29820d6 100644 --- a/components/global-notification/global-notification.js +++ b/components/global-notification/global-notification.js @@ -1,368 +1,363 @@ -const { resolveAvatarUrl } = require('../../utils/avatar.js'); - -Component({ - properties: { - position: { - type: String, - value: 'top' - }, - duration: { - type: Number, - value: 3000 - }, - showProgress: { - type: Boolean, - value: true - }, - showMuteButton: { - type: Boolean, - value: true - }, - showTime: { - type: Boolean, - value: true - }, - swipeToClose: { - type: Boolean, - value: true - }, - swipeThreshold: { - type: Number, - value: 50 - } - }, - - data: { - show: false, - title: '', - message: '', - avatar: '', - notificationData: null, - progress: 100, - progressInterval: null, - positionClass: 'top', - - // 滑动相关 - touchStartY: 0, - touchStartX: 0, - currentY: 0, - currentX: 0, - isSwiping: false, - swipingClass: '', - swipeStyle: '', - swipeDistance: 0, - - // 静音状态 - isMuted: false, - - // 自动隐藏计时器 - autoHideTimeout: null - }, - - lifetimes: { - attached() { - this.loadMuteSetting(); - this.setData({ - positionClass: this.properties.position - }); - this.setupDirectEventListeners(); - }, - - detached() { - this.clearTimers(); - } - }, - - methods: { - setupDirectEventListeners() { - const app = getApp(); - if (app) { - const self = this; - const globalNotification = { - show: (data) => { - if (self && self.showNotification) { - self.showNotification(data); - } - }, - hide: () => { - if (self && self.hideNotification) { - self.hideNotification(); - } - }, - isMuted: () => { - return self.data.isMuted; - } - }; - app.globalData.globalNotification = globalNotification; - } - }, - - loadMuteSetting() { - try { - const isMuted = wx.getStorageSync('notificationMuted') || false; - this.setData({ isMuted }); - } catch (error) { - console.warn('加载静音设置失败:', error); - } - }, - - saveMuteSetting(isMuted) { - try { - wx.setStorageSync('notificationMuted', isMuted); - } catch (error) { - console.warn('保存静音设置失败:', error); - } - }, - - showNotification(data) { - if (!data) return; - if (this.data.isMuted) return; - - this.clearTimers(); - - const app = getApp(); - let avatar = resolveAvatarUrl( - data.avatar || data.message?.senderData?.avatar, - app - ); - - this.setData({ - show: true, - title: data.senderName || '新消息', - message: data.content || '[消息内容]', - avatar: avatar, - notificationData: data, - progress: 100, - swipingClass: '', - swipeStyle: '' - }); - - if (this.properties.showProgress) { - this.startProgressBar(this.properties.duration); - } - - this.data.autoHideTimeout = setTimeout(() => { - this.hideNotification(); - }, this.properties.duration); - }, - - hideNotification() { - this.clearTimers(); - this.setData({ - show: false, - progress: 100, - swipingClass: '', - swipeStyle: '' - }); - this.triggerEvent('hide'); - }, - - startProgressBar(duration) { - const interval = 100; - const steps = duration / interval; - const stepValue = 100 / steps; - - let currentProgress = 100; - this.data.progressInterval = setInterval(() => { - currentProgress -= stepValue; - if (currentProgress <= 0) { - currentProgress = 0; - this.setData({ progress: currentProgress }); - clearInterval(this.data.progressInterval); - } else { - this.setData({ progress: currentProgress }); - } - }, interval); - }, - - clearTimers() { - if (this.data.autoHideTimeout) { - clearTimeout(this.data.autoHideTimeout); - this.data.autoHideTimeout = null; - } - if (this.data.progressInterval) { - clearInterval(this.data.progressInterval); - this.data.progressInterval = null; - } - }, - - onTouchStart(e) { - if (!this.properties.swipeToClose) return; - const touch = e.touches[0]; - this.setData({ - touchStartY: touch.clientY, - touchStartX: touch.clientX, - currentY: touch.clientY, - currentX: touch.clientX, - isSwiping: false - }); - this.clearTimers(); - }, - - onTouchMove(e) { - if (!this.properties.swipeToClose) return; - const touch = e.touches[0]; - const deltaY = touch.clientY - this.data.touchStartY; - const deltaX = touch.clientX - this.data.touchStartX; - const absDeltaY = Math.abs(deltaY); - const absDeltaX = Math.abs(deltaX); - - if (absDeltaY > 10 && absDeltaY > absDeltaX) { - this.setData({ - isSwiping: true, - currentY: touch.clientY, - swipingClass: deltaY < 0 ? 'swiping-up' : 'swiping', - swipeDistance: Math.abs(deltaY), - swipeStyle: `--swipe-distance: ${Math.abs(deltaY)}rpx;` - }); - e.stopPropagation(); - } - }, - - onTouchEnd(e) { - if (!this.properties.swipeToClose || !this.data.isSwiping) { - this.restartAutoHide(); - return; - } - const deltaY = this.data.currentY - this.data.touchStartY; - const absDeltaY = Math.abs(deltaY); - if (absDeltaY > this.properties.swipeThreshold) { - this.hideNotification(); - } else { - this.setData({ - swipingClass: '', - swipeStyle: 'transition: transform 0.3s ease; transform: translateY(0);' - }); - setTimeout(() => { - this.setData({ - swipingClass: '', - swipeStyle: '' - }); - }, 300); - this.restartAutoHide(); - } - this.setData({ isSwiping: false }); - }, - - restartAutoHide() { - const remainingTime = (this.data.progress / 100) * this.properties.duration; - if (remainingTime > 0) { - this.data.autoHideTimeout = setTimeout(() => { - this.hideNotification(); - }, remainingTime); - } - }, - - onTap() { - const { notificationData } = this.data; - if (!notificationData) return; - this.triggerEvent('tap', notificationData); - this.hideNotification(); - this.navigateToChatPage(notificationData); - }, - - onClose(e) { - e.stopPropagation(); - this.triggerEvent('close'); - this.hideNotification(); - }, - - onMute(e) { - e.stopPropagation(); - const newMutedState = !this.data.isMuted; - this.setData({ isMuted: newMutedState }); - this.saveMuteSetting(newMutedState); - - const app = getApp(); - if (app && app.toggleDoNotDisturb) { - app.toggleDoNotDisturb(newMutedState); - } - this.triggerEvent('mute', { muted: newMutedState }); - wx.showToast({ - title: newMutedState ? '已开启免打扰' : '已关闭免打扰', - icon: 'success', - duration: 1500 - }); - - if (newMutedState) { - this.hideNotification(); - } - }, - - formatTime(timestamp) { - if (!timestamp) return ''; - const date = new Date(timestamp); - const now = new Date(); - const diff = now - date; - if (diff < 60 * 1000) return '刚刚'; - if (diff < 60 * 60 * 1000) return Math.floor(diff / (60 * 1000)) + '分钟前'; - if (date.toDateString() === now.toDateString()) { - return date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'); - } - const yesterday = new Date(now); - yesterday.setDate(yesterday.getDate() - 1); - if (date.toDateString() === yesterday.toDateString()) { - return '昨天 ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'); - } - return (date.getMonth() + 1) + '月' + date.getDate() + '日'; - }, - - navigateToChatPage(data) { - if (!data || !data.message) { - console.warn('通知数据无效,无法跳转'); - return; - } - - const msg = data.message; - let path = ''; - let queryParam = null; - - // 根据 notificationType 或消息字段判断 - if (data.notificationType === 'cs' || msg.teamId) { - // 客服消息 - const teamId = data.teamId || msg.teamId; - path = '/pages/kefuliaotian/kefuliaotian'; - queryParam = { teamId: teamId }; - } else if (data.notificationType === 'group' || msg.groupId) { - // 群聊消息 - const groupId = data.groupId || msg.groupId; - const orderId = data.orderId || msg.orderId || ''; - const groupName = data.groupName || '订单群聊'; - const groupAvatar = data.groupAvatar || ''; - const isCross = data.isCross || msg.isCross || 0; - path = '/pages/qunliaotian/qunliaotian'; - queryParam = { - groupId, - orderId, - groupName, - groupAvatar, - isCross - }; - } else { - // 默认私聊 - const toUserId = data.senderId || msg.senderId; - const toName = data.senderName || '用户'; - const toAvatar = data.avatar || ''; - path = '/pages/liaotian/liaotian'; - queryParam = { - toUserId, - toName, - toAvatar - }; - } - - if (path && queryParam) { - const encoded = encodeURIComponent(JSON.stringify(queryParam)); - wx.navigateTo({ - url: `${path}?data=${encoded}`, - fail: (err) => { - console.error('通知跳转失败:', err); - wx.switchTab({ url: '/pages/xiaoxi/xiaoxi' }); - } - }); - } else { - wx.switchTab({ url: '/pages/xiaoxi/xiaoxi' }); - } - } - } +const { resolveAvatarUrl } = require('../../utils/avatar.js'); + +Component({ + properties: { + position: { + type: String, + value: 'top' + }, + duration: { + type: Number, + value: 3000 + }, + showProgress: { + type: Boolean, + value: true + }, + showMuteButton: { + type: Boolean, + value: true + }, + showTime: { + type: Boolean, + value: true + }, + swipeToClose: { + type: Boolean, + value: true + }, + swipeThreshold: { + type: Number, + value: 50 + } + }, + + data: { + show: false, + title: '', + message: '', + avatar: '', + notificationData: null, + progress: 100, + progressInterval: null, + positionClass: 'top', + + touchStartY: 0, + touchStartX: 0, + currentY: 0, + currentX: 0, + isSwiping: false, + swipingClass: '', + swipeStyle: '', + swipeDistance: 0, + + // 静音状态 + isMuted: false, + + // 自动隐藏计时器 + autoHideTimeout: null + }, + + lifetimes: { + attached() { + this.loadMuteSetting(); + this.setData({ + positionClass: this.properties.position + }); + this.setupDirectEventListeners(); + }, + + detached() { + this.clearTimers(); + } + }, + + methods: { + setupDirectEventListeners() { + const app = getApp(); + if (app) { + const self = this; + const globalNotification = { + show: (data) => { + if (self && self.showNotification) { + self.showNotification(data); + } + }, + hide: () => { + if (self && self.hideNotification) { + self.hideNotification(); + } + }, + isMuted: () => { + return self.data.isMuted; + } + }; + app.globalData.globalNotification = globalNotification; + } + }, + + loadMuteSetting() { + try { + const isMuted = wx.getStorageSync('notificationMuted') || false; + this.setData({ isMuted }); + } catch (error) { + console.warn('加载静音设置失败:', error); + } + }, + + saveMuteSetting(isMuted) { + try { + wx.setStorageSync('notificationMuted', isMuted); + } catch (error) { + console.warn('保存静音设置失败:', error); + } + }, + + showNotification(data) { + if (!data) return; + if (this.data.isMuted) return; + + this.clearTimers(); + + const app = getApp(); + let avatar = resolveAvatarUrl( + data.avatar || data.message?.senderData?.avatar, + app + ); + + this.setData({ + show: true, + title: data.senderName || '新消息', + message: data.content || '[消息内容]', + avatar: avatar, + notificationData: data, + progress: 100, + swipingClass: '', + swipeStyle: '' + }); + + if (this.properties.showProgress) { + this.startProgressBar(this.properties.duration); + } + + this.data.autoHideTimeout = setTimeout(() => { + this.hideNotification(); + }, this.properties.duration); + }, + + hideNotification() { + this.clearTimers(); + this.setData({ + show: false, + progress: 100, + swipingClass: '', + swipeStyle: '' + }); + this.triggerEvent('hide'); + }, + + startProgressBar(duration) { + const interval = 100; + const steps = duration / interval; + const stepValue = 100 / steps; + + let currentProgress = 100; + this.data.progressInterval = setInterval(() => { + currentProgress -= stepValue; + if (currentProgress <= 0) { + currentProgress = 0; + this.setData({ progress: currentProgress }); + clearInterval(this.data.progressInterval); + } else { + this.setData({ progress: currentProgress }); + } + }, interval); + }, + + clearTimers() { + if (this.data.autoHideTimeout) { + clearTimeout(this.data.autoHideTimeout); + this.data.autoHideTimeout = null; + } + if (this.data.progressInterval) { + clearInterval(this.data.progressInterval); + this.data.progressInterval = null; + } + }, + + onTouchStart(e) { + if (!this.properties.swipeToClose) return; + const touch = e.touches[0]; + this.setData({ + touchStartY: touch.clientY, + touchStartX: touch.clientX, + currentY: touch.clientY, + currentX: touch.clientX, + isSwiping: false + }); + this.clearTimers(); + }, + + onTouchMove(e) { + if (!this.properties.swipeToClose) return; + const touch = e.touches[0]; + const deltaY = touch.clientY - this.data.touchStartY; + const deltaX = touch.clientX - this.data.touchStartX; + const absDeltaY = Math.abs(deltaY); + const absDeltaX = Math.abs(deltaX); + + if (absDeltaY > 10 && absDeltaY > absDeltaX) { + this.setData({ + isSwiping: true, + currentY: touch.clientY, + swipingClass: deltaY < 0 ? 'swiping-up' : 'swiping', + swipeDistance: Math.abs(deltaY), + swipeStyle: `--swipe-distance: ${Math.abs(deltaY)}rpx;` + }); + e.stopPropagation(); + } + }, + + onTouchEnd(e) { + if (!this.properties.swipeToClose || !this.data.isSwiping) { + this.restartAutoHide(); + return; + } + const deltaY = this.data.currentY - this.data.touchStartY; + const absDeltaY = Math.abs(deltaY); + if (absDeltaY > this.properties.swipeThreshold) { + this.hideNotification(); + } else { + this.setData({ + swipingClass: '', + swipeStyle: 'transition: transform 0.3s ease; transform: translateY(0);' + }); + setTimeout(() => { + this.setData({ + swipingClass: '', + swipeStyle: '' + }); + }, 300); + this.restartAutoHide(); + } + this.setData({ isSwiping: false }); + }, + + restartAutoHide() { + const remainingTime = (this.data.progress / 100) * this.properties.duration; + if (remainingTime > 0) { + this.data.autoHideTimeout = setTimeout(() => { + this.hideNotification(); + }, remainingTime); + } + }, + + onTap() { + const { notificationData } = this.data; + if (!notificationData) return; + this.triggerEvent('tap', notificationData); + this.hideNotification(); + this.navigateToChatPage(notificationData); + }, + + onClose(e) { + e.stopPropagation(); + this.triggerEvent('close'); + this.hideNotification(); + }, + + onMute(e) { + e.stopPropagation(); + const newMutedState = !this.data.isMuted; + this.setData({ isMuted: newMutedState }); + this.saveMuteSetting(newMutedState); + + const app = getApp(); + if (app && app.toggleDoNotDisturb) { + app.toggleDoNotDisturb(newMutedState); + } + this.triggerEvent('mute', { muted: newMutedState }); + wx.showToast({ + title: newMutedState ? '已开启免打扰' : '已关闭免打扰', + icon: 'success', + duration: 1500 + }); + + if (newMutedState) { + this.hideNotification(); + } + }, + + formatTime(timestamp) { + if (!timestamp) return ''; + const date = new Date(timestamp); + const now = new Date(); + const diff = now - date; + if (diff < 60 * 1000) return '刚刚'; + if (diff < 60 * 60 * 1000) return Math.floor(diff / (60 * 1000)) + '分钟前'; + if (date.toDateString() === now.toDateString()) { + return date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'); + } + const yesterday = new Date(now); + yesterday.setDate(yesterday.getDate() - 1); + if (date.toDateString() === yesterday.toDateString()) { + return '昨天 ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'); + } + return (date.getMonth() + 1) + '月' + date.getDate() + '日'; + }, + + navigateToChatPage(data) { + if (!data || !data.message) { + console.warn('通知数据无效,无法跳转'); + return; + } + + const msg = data.message; + let path = ''; + let queryParam = null; + + if (data.notificationType === 'cs' || msg.teamId) { + const teamId = data.teamId || msg.teamId; + path = '/pages/cs-chat/cs-chat'; + queryParam = { teamId: teamId }; + } else if (data.notificationType === 'group' || msg.groupId) { + const groupId = data.groupId || msg.groupId; + const orderId = data.orderId || msg.orderId || ''; + const groupName = data.groupName || '订单群聊'; + const groupAvatar = data.groupAvatar || ''; + const isCross = data.isCross || msg.isCross || 0; + path = '/pages/group-chat/group-chat'; + queryParam = { + groupId, + orderId, + groupName, + groupAvatar, + isCross + }; + } else { + const toUserId = data.senderId || msg.senderId; + const toName = data.senderName || '用户'; + const toAvatar = data.avatar || ''; + path = '/pages/chat/chat'; + queryParam = { + toUserId, + toName, + toAvatar + }; + } + + if (path && queryParam) { + const encoded = encodeURIComponent(JSON.stringify(queryParam)); + wx.navigateTo({ + url: `${path}?data=${encoded}`, + fail: (err) => { + console.error('通知跳转失败:', err); + wx.switchTab({ url: '/pages/messages/messages' }); + } + }); + } else { + wx.switchTab({ url: '/pages/messages/messages' }); + } + } + } }); \ No newline at end of file diff --git a/components/popup-notice/popup-notice.js b/components/popup-notice/popup-notice.js index 5cfc83c..e2bba0f 100644 --- a/components/popup-notice/popup-notice.js +++ b/components/popup-notice/popup-notice.js @@ -18,7 +18,6 @@ Component({ isFullscreen: false, timer: null, - // 悬浮窗相关数据 isMinimized: false, floatX: 20, floatY: 200, @@ -163,7 +162,7 @@ Component({ this.setData({ muteChecked: e.detail.value.length > 0 }); }, - // 🆕 替换原有的 onPreviewImage,改用自定义预览(不触发 onShow) + // 自定义图片预览 onCustomPreview(e) { const index = e.currentTarget.dataset.index; const urls = this.data.processedImages.map(img => img.url); @@ -174,7 +173,6 @@ Component({ }); }, - // 🆕 关闭自定义预览 onCloseCustomPreview() { this.setData({ showCustomPreview: false, @@ -225,7 +223,7 @@ Component({ if (app.globalData.morentouxiang) { avatarUrl = app.globalData.morentouxiang; } else { - // 使用内嵌的默认头像 base64(灰色圆形),确保绝对显示,不依赖外部图片 + // 默认头像 avatarUrl = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI1MCIgZmlsbD0iI2NjY2NjYyIvPjxwYXRoIGQ9Ik01MCAyNWMtMTMuOCAwLTI1IDExLjItMjUgMjUgMCAzLjIgMS4yIDYuMSAzLjIgOC4zQzM0LjQgNzAuNyA0Mi4xIDc1IDUwIDc1czE1LjYtNC4zIDIxLjgtMTEuN0M3My44IDU2LjEgNzUgNTMuMiA3NSA1MGMwLTEzLjgtMTEuMi0yNS0yNS0yNXoiIGZpbGw9IiNmZmZmZmYiLz48L3N2Zz4='; } @@ -319,7 +317,7 @@ Component({ return false; }, - // 🆕 阻止事件冒泡(用于预览遮罩内部点击不关闭) + // 阻止事件冒泡 stopPropagation() {} } }); \ No newline at end of file diff --git a/components/popup-notice/popup-notice.wxml b/components/popup-notice/popup-notice.wxml index c95e3ba..5c20321 100644 --- a/components/popup-notice/popup-notice.wxml +++ b/components/popup-notice/popup-notice.wxml @@ -1,6 +1,5 @@ - @@ -83,7 +82,7 @@ - { - if (data.badgeText !== undefined) { - this.setData({ badgeText: data.badgeText }); - } - }; - this._roleListener = () => this.refresh(); - app.on('tabBarBadgeChanged', this._badgeListener); - app.on('currentRoleChanged', this._roleListener); - }, - detached() { - if (this._badgeListener) app.off('tabBarBadgeChanged', this._badgeListener); - if (this._roleListener) app.off('currentRoleChanged', this._roleListener); - }, - }, - - pageLifetimes: { - show() { - this.refresh(); - const globalBadge = app.globalData.messageManager?.tabBarBadgeText || ''; - if (this.data.badgeText !== globalBadge) { - this.setData({ badgeText: globalBadge }); - } - this._syncUnreadWithDebounce(); - }, - }, - - methods: { - _syncUnreadWithDebounce() { - if (this._syncTimer) clearTimeout(this._syncTimer); - this._syncTimer = setTimeout(() => { - if (app && app.loadConversations) app.loadConversations(); - }, 300); - }, - - refresh() { - const token = wx.getStorageSync('token'); - let role = getTabRole(app); - if (!token) { - role = 'normal'; - } - app.globalData.currentRole = role; - wx.setStorageSync('currentRole', role); - - let cfg = roleCfg[role]; - if (!cfg) { - cfg = roleCfg.normal; - role = 'normal'; - } - - const list = cfg.tabList.map((v, i) => ({ ...v, index: i })); - const pages = getCurrentPages(); - const curRoute = pages.length ? pages[pages.length - 1].route : ''; - let idx = list.findIndex((t) => t.pagePath === curRoute); - if (idx === -1) idx = 0; - this.setData({ currentRole: role, tabList: list, selectedIndex: idx }); - }, - - switchTab(e) { - const path = e.currentTarget.dataset.path; - const idx = e.currentTarget.dataset.index; - if (idx === this.data.selectedIndex) return; - wx.redirectTo({ url: '/' + path }); - }, - }, -}); +// custom-tab-bar/index.js — 三端固定,无身份切换 +const app = getApp(); +import { getTabRole } from '../utils/primary-role.js'; + +const roleCfg = { + normal: { + name: '点单老板', + tabList: [ + { pagePath: 'pages/index/index', text: '商城', iconPath: '/images/zhuye.png', selectedIconPath: '/images/zhuye.png' }, + { pagePath: 'pages/category/category', text: '分类', iconPath: '/images/fenlei.png', selectedIconPath: '/images/fenlei.png' }, + { pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' }, + { pagePath: 'pages/mine/mine', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }, + ], + }, + dashou: { + name: '打手', + tabList: [ + { pagePath: 'pages/accept-order/accept-order', text: '接单池', iconPath: '/images/jiedanchi.png', selectedIconPath: '/images/jiedanchi.png' }, + { pagePath: 'pages/fighter-orders/fighter-orders', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' }, + { pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' }, + { pagePath: 'pages/fighter/fighter', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }, + ], + }, + shangjia: { + name: '商家', + tabList: [ + { pagePath: 'pages/merchant-orders/merchant-orders', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' }, + { pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' }, + { pagePath: 'pages/merchant/merchant', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }, + ], + }, +}; + +Component({ + data: { + selectedIndex: 0, + tabList: [], + currentRole: 'normal', + badgeText: '', + }, + + lifetimes: { + attached() { + this.refresh(); + this._badgeListener = (data) => { + if (data.badgeText !== undefined) { + this.setData({ badgeText: data.badgeText }); + } + }; + this._roleListener = () => this.refresh(); + app.on('tabBarBadgeChanged', this._badgeListener); + app.on('currentRoleChanged', this._roleListener); + }, + detached() { + if (this._badgeListener) app.off('tabBarBadgeChanged', this._badgeListener); + if (this._roleListener) app.off('currentRoleChanged', this._roleListener); + }, + }, + + pageLifetimes: { + show() { + this.refresh(); + const globalBadge = app.globalData.messageManager?.tabBarBadgeText || ''; + if (this.data.badgeText !== globalBadge) { + this.setData({ badgeText: globalBadge }); + } + this._syncUnreadWithDebounce(); + }, + }, + + methods: { + _syncUnreadWithDebounce() { + if (this._syncTimer) clearTimeout(this._syncTimer); + this._syncTimer = setTimeout(() => { + if (app && app.loadConversations) app.loadConversations(); + }, 300); + }, + + refresh() { + const token = wx.getStorageSync('token'); + let role = getTabRole(app); + if (!token) { + role = 'normal'; + } + app.globalData.currentRole = role; + wx.setStorageSync('currentRole', role); + + let cfg = roleCfg[role]; + if (!cfg) { + cfg = roleCfg.normal; + role = 'normal'; + } + + const list = cfg.tabList.map((v, i) => ({ ...v, index: i })); + const pages = getCurrentPages(); + const curRoute = pages.length ? pages[pages.length - 1].route : ''; + let idx = list.findIndex((t) => t.pagePath === curRoute); + if (idx === -1) idx = 0; + this.setData({ currentRole: role, tabList: list, selectedIndex: idx }); + }, + + switchTab(e) { + const path = e.currentTarget.dataset.path; + const idx = e.currentTarget.dataset.index; + if (idx === this.data.selectedIndex) return; + wx.redirectTo({ url: '/' + path }); + }, + }, +}); diff --git a/custom-tab-bar/index.wxml b/custom-tab-bar/index.wxml index 523432e..cd9976f 100644 --- a/custom-tab-bar/index.wxml +++ b/custom-tab-bar/index.wxml @@ -1,24 +1,24 @@ - - - - - - - {{badgeText}} - - - {{item.text}} - - - - - + + + + + + + {{badgeText}} + + + {{item.text}} + + + + + diff --git a/pages/jiedan/jiedan.js b/pages/accept-order/accept-order.js similarity index 96% rename from pages/jiedan/jiedan.js rename to pages/accept-order/accept-order.js index 403bf0f..804d2a6 100644 --- a/pages/jiedan/jiedan.js +++ b/pages/accept-order/accept-order.js @@ -1,577 +1,577 @@ -// pages/qiangdan/qiangdan.js -const app = getApp(); -import request from '../../utils/request.js'; -import PopupService from '../../services/popupService.js'; -import { reconnectForRole } from '../../utils/role-tab-bar.js'; - -Page({ - data: { - // 1. 商品类型相关 - shangpinleixing: [], - xuanzhongLeixingId: null, - - // 2. 订单列表与分页相关 - dingdanList: [], - page: 1, - pageSize: 5, - hasMore: true, - isLoading: false, - - // 3. 全局状态字段 - dashoustatus: null, - zhuanghaoStatus: null, - dashouzhuangtai: null, - uid: null, - huiyuanList: [], - yajin: 0, - jifen: 0, - - // 4. 刷新控制字段 - scrollViewRefreshing: false, - lastRefreshTime: 0, - refreshCooldown: 2000, - isLoadingMore: false, - - // 5. 切换类型冷却 - lastSwitchTime: 0, - switchCooldown: 1500, - isSwitching: false, - - // 6. OSS地址 - ossImageUrl: app.globalData.ossImageUrl || '', - - // 🆕 7. 标签筛选相关 - bankuaiBiaoqian: [], // 当前商品类型所属板块的全部标签 - xuanzhongBiaoqianId: 0, // 0=全部 - }, - - async onLoad(options) { - this.loadGlobalStatus(); - await this.loadShangpinLeixing(); - PopupService.checkAndShow(this, 'jiedan'); - }, - - onHide: function () { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } - }, - - onShow() { - this.registerNotificationComponent(); - this.loadGlobalStatus(); - if (wx.getStorageSync('uid')) { - reconnectForRole('dashou'); - if (app.startImWhenReady) app.startImWhenReady(); - this.refreshDashouProfileSilent(); - } - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - } - }, - - 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; - } - this.setData({ - zhuanghaoStatus: patch.zhanghaoStatus, - dashouzhuangtai: patch.dashouzhuangtai, - huiyuanList: patch.clumber, - yajin: patch.yajin, - jifen: patch.jifen, - }); - } catch (e) {} - }, - - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - loadGlobalStatus() { - const globalData = app.globalData; - this.setData({ - dashoustatus: wx.getStorageSync('dashoustatus'), - zhuanghaoStatus: globalData.zhanghaoStatus, - dashouzhuangtai: globalData.dashouzhuangtai, - uid: wx.getStorageSync('uid'), - huiyuanList: globalData.clumber || [], - yajin: globalData.yajin || 0, - jifen: globalData.jinfen || 0 - }); - }, - - // 加载商品类型 - async loadShangpinLeixing() { - wx.showLoading({ title: '加载商品类型...' }); - try { - const res = await request({ - url: '/dingdan/dsqdhqddlx', - method: 'POST', - header: { 'content-type': 'application/json' } - }); - if (res.statusCode === 200 && res.data) { - const data = res.data; - let list = []; - if (data.code === 200 || data.code === 0) { - if (data.data && Array.isArray(data.data.list)) list = data.data.list; - else if (data.data && Array.isArray(data.data)) list = data.data; - else if (Array.isArray(data.list)) list = data.list; - else if (Array.isArray(data)) list = data; - } - const processedList = this.processTupianUrl(list); - this.setData({ - shangpinleixing: processedList, - xuanzhongLeixingId: processedList[0]?.id || null - }); - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - // 🆕 加载板块标签 - this.loadBankuaiBiaoqian(); - } - } else { - wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' }); - } - } catch (error) { - wx.showToast({ title: '网络错误,加载失败', icon: 'none' }); - } finally { - wx.hideLoading(); - } - }, - - // 处理图片URL - processTupianUrl(list) { - const ossUrl = app.globalData.ossImageUrl || ''; - return list.map(item => ({ - ...item, - full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http') - ? ossUrl + item.tupian_url - : (item.tupian_url || '/images/default-type.png') - })); - }, - - // 🆕 加载板块标签 - 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 selectLeixing(e) { - const now = Date.now(); - const lastSwitchTime = this.data.lastSwitchTime; - const switchCooldown = this.data.switchCooldown; - - if (now - lastSwitchTime < switchCooldown) { - wx.showToast({ - title: `操作太快,请${Math.ceil((switchCooldown - (now - lastSwitchTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - if (this.data.isSwitching) return; - - const leixingId = e.currentTarget.dataset.id; - if (leixingId === this.data.xuanzhongLeixingId) return; - - this.setData({ isSwitching: true, lastSwitchTime: now }); - wx.showLoading({ title: '切换中...' }); - - try { - this.setData({ - xuanzhongLeixingId: leixingId, - dingdanList: [], - page: 1, - hasMore: true, - xuanzhongBiaoqianId: 0 // 重置标签筛选 - }); - await this.loadDingdanList(true); - // 🆕 切换类型后加载新标签 - await this.loadBankuaiBiaoqian(); - } catch (error) { - console.error('切换类型失败:', error); - } finally { - this.setData({ isSwitching: false }); - wx.hideLoading(); - } - }, - - // 🆕 选择标签筛选 - 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 loadDingdanList(isRefresh = false) { - if (this.data.isLoading || !this.data.xuanzhongLeixingId) return; - - const loadPage = isRefresh ? 1 : this.data.page; - if (!isRefresh && !this.data.hasMore) return; - - this.setData({ - isLoading: true, - isLoadingMore: !isRefresh - }); - - try { - const res = await request({ - url: '/dingdan/ddhq', - method: 'POST', - data: { - leixing_id: this.data.xuanzhongLeixingId, - page: loadPage, - page_size: this.data.pageSize, - // 🆕 传递标签筛选参数(0时不传) - biaoqian_id: this.data.xuanzhongBiaoqianId || undefined - } - }); - - this.setData({ - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false - }); - - if (res.data.code === 200 || res.data.code === 0) { - const newList = res.data.data.list || []; - const hasMore = res.data.data.has_more || false; - - // 🆕 处理每条订单,增加 hasRequiredMember 字段 - const processedList = newList.map(item => this.processDingdanItem(item)); - const updatedList = isRefresh ? processedList : [...this.data.dingdanList, ...processedList]; - updatedList.sort((a, b) => (b.creat_time || '').localeCompare(a.creat_time || '')); - - this.setData({ - dingdanList: updatedList, - page: loadPage, - hasMore: hasMore - }); - - if (isRefresh) { - this.setData({ lastRefreshTime: Date.now() }); - } - } else { - wx.showToast({ title: res.data.msg || '加载失败', icon: 'none' }); - } - } catch (error) { - console.error('加载订单失败:', error); - this.setData({ - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false - }); - wx.showToast({ title: '网络请求失败', icon: 'none' }); - } - }, - - // 处理单条订单数据(包含标签、会员判断) - processDingdanItem(item) { - const ossUrl = app.globalData.ossImageUrl || ''; - let fullTupianUrl = ''; - - if (item.tupian) { - fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; - } else { - 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; - } - const zhidingNicheng = item.zhiding_nicheng || ''; - - // 🆕 判断用户是否有订单所需的会员(仅当订单要求会员类型且存在huiyuan_id) - let hasRequiredMember = true; - if (item.yaoqiuleixing == 1 && item.huiyuan_id) { - const userHasIt = this.data.huiyuanList.some(h => h.huiyuanid == item.huiyuan_id); - hasRequiredMember = userHasIt; - } - - return { - ...item, - full_tupian_url: fullTupianUrl, - isZhiding: isZhiding, - isPingtai: item.pingtai == 1, - isShangjia: item.pingtai == 2, - zhiding_avatar_full: zhidingAvatar, - zhiding_nicheng: zhidingNicheng, - // 🆕 三层标签(后端返回,直接保留) - xuqiu_biaoqian: item.xuqiu_biaoqian || [], - dashou_biaoqian: item.dashou_biaoqian || [], - shangjia_biaoqian: item.shangjia_biaoqian || [], - // 🆕 是否有查看价格的权限 - hasRequiredMember: hasRequiredMember, - }; - }, - - // 跳转到充值页面(原封不动) - goToChongzhiPage(failureType, huiyuanId = null, requiredYajin = 0) { - let url = '/pages/dashouchongzhi/dashouchongzhi'; - let params = {}; - - switch (failureType) { - case 'huiyuan': - params = { needScroll: '0', scrollTo: 'member' }; - break; - case 'yajin': - params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin }; - break; - case 'jifen': - params = { needScroll: '1', scrollTo: 'bottom' }; - break; - } - - if (huiyuanId) params.huiyuanId = huiyuanId; - - const queryString = Object.keys(params) - .map(key => `${key}=${encodeURIComponent(params[key])}`) - .join('&'); - - wx.navigateTo({ - url: `${url}?${queryString}`, - fail: (err) => { - console.error('跳转失败:', err); - wx.showToast({ title: '跳转失败,请稍后重试', icon: 'none' }); - } - }); - }, - - // 抢单按钮(原封不动) - async onQiangdanTap(e) { - const dingdanItem = e.currentTarget.dataset.item; - if (!dingdanItem) return; - - // 校验1: 打手身份 - if (!this.data.dashoustatus || this.data.dashoustatus != 1) { - wx.showToast({ title: '请先开启打手身份', icon: 'none' }); - return; - } - // 校验2: 账号状态 - if (this.data.zhuanghaoStatus != 1) { - wx.showToast({ title: '账号异常,无法接单', icon: 'none' }); - return; - } - // 校验3: 打手接单状态 - if (this.data.dashouzhuangtai != 1) { - wx.showToast({ title: '您有订单正在接待中', icon: 'none' }); - return; - } - // 校验4: 指定订单 - if (dingdanItem.isZhiding) { - if (!this.data.uid || this.data.uid != dingdanItem.zhiding_uid) { - wx.showToast({ title: '此订单为指定单', icon: 'none' }); - return; - } - } - // 校验5: 会员要求 - if (dingdanItem.yaoqiuleixing == 1) { - const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); - if (!hasHuiyuan) { - wx.showToast({ - title: '未开通对应会员,无法抢单', - icon: 'none', - duration: 2000 - }); - setTimeout(() => { - this.goToChongzhiPage('huiyuan', dingdanItem.huiyuan_id); - }, 500); - return; - } - } - // 校验6: 押金要求 - if (dingdanItem.yaoqiuleixing == 2) { - if (this.data.yajin < dingdanItem.yajin) { - wx.showToast({ - title: `押金不足,需${dingdanItem.yajin}`, - icon: 'none', - duration: 2000 - }); - setTimeout(() => { - this.goToChongzhiPage('yajin', null, dingdanItem.yajin); - }, 500); - return; - } - } - // 校验7: 积分要求 - if (this.data.jifen < 5) { - wx.showToast({ - title: '积分不足,至少需要5积分', - icon: 'none', - duration: 2000 - }); - setTimeout(() => { - this.goToChongzhiPage('jifen'); - }, 500); - return; - } - - // 确认框 - const that = this; - wx.showModal({ - title: '确认抢单', - content: `确定要抢此订单吗?${dingdanItem.isZhiding ? '(指定订单)' : ''}`, - success: async function (res) { - if (res.confirm) { - wx.showLoading({ title: '抢单中...', mask: true }); - try { - const qiangdanRes = await request({ - url: '/dingdan/qiangdan', - method: 'POST', - data: { dingdan_id: dingdanItem.dingdan_id } - }); - wx.hideLoading(); - - if (qiangdanRes.data.code === 200 || qiangdanRes.data.code === 0) { - that.showQiangdanSuccessEffect(); - if (app.globalData) { - app.globalData.dashouzhuangtai = 0; - that.setData({ dashouzhuangtai: 0 }); - } - const newList = that.data.dingdanList.filter( - item => item.dingdan_id !== dingdanItem.dingdan_id - ); - that.setData({ dingdanList: newList }); - } else { - wx.showToast({ - title: qiangdanRes.data.msg || '抢单失败', - icon: 'none' - }); - } - } catch (error) { - wx.hideLoading(); - console.error('抢单请求失败:', error); - wx.showToast({ title: '网络错误,抢单失败', icon: 'none' }); - } - } - } - }); - }, - - showQiangdanSuccessEffect() { - wx.showToast({ title: '抢单成功!', icon: 'success', duration: 2000 }); - }, - - onViewDetail(e) { - const { type, content } = e.currentTarget.dataset; - wx.showModal({ - title: type === 'jieshao' ? '订单介绍' : '订单备注', - content: content, - showCancel: false, - confirmText: '知道了' - }); - }, - - onReachBottom() { - const now = Date.now(); - const lastTime = this.data.lastRefreshTime; - const cooldown = this.data.refreshCooldown; - - if (now - lastTime < cooldown) { - wx.showToast({ - title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - - if (this.data.isLoading || this.data.isLoadingMore) return; - - if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) { - this.setData({ page: this.data.page + 1 }); - this.loadDingdanList(false); - } - }, - - onPullDownRefresh() { - const now = Date.now(); - const lastTime = this.data.lastRefreshTime; - const cooldown = this.data.refreshCooldown; - - if (now - lastTime < cooldown) { - this.setData({ scrollViewRefreshing: false }); - wx.showToast({ - title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - - if (this.data.isLoading) { - this.setData({ scrollViewRefreshing: false }); - return; - } - - this.setData({ - scrollViewRefreshing: true, - lastRefreshTime: now, - page: 1, - hasMore: true - }); - - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - } else { - this.setData({ scrollViewRefreshing: false }); - } - } +// pages/qiangdan/qiangdan.js +const app = getApp(); +import request from '../../utils/request.js'; +import PopupService from '../../services/popupService.js'; +import { reconnectForRole } from '../../utils/role-tab-bar.js'; + +Page({ + data: { + // 1. 商品类型相关 + shangpinleixing: [], + xuanzhongLeixingId: null, + + // 2. 订单列表与分页相关 + dingdanList: [], + page: 1, + pageSize: 5, + hasMore: true, + isLoading: false, + + // 3. 全局状态字段 + dashoustatus: null, + zhuanghaoStatus: null, + dashouzhuangtai: null, + uid: null, + huiyuanList: [], + yajin: 0, + jifen: 0, + + // 4. 刷新控制字段 + scrollViewRefreshing: false, + lastRefreshTime: 0, + refreshCooldown: 2000, + isLoadingMore: false, + + // 5. 切换类型冷却 + lastSwitchTime: 0, + switchCooldown: 1500, + isSwitching: false, + + // 6. OSS地址 + ossImageUrl: app.globalData.ossImageUrl || '', + + // 🆕 7. 标签筛选相关 + bankuaiBiaoqian: [], // 当前商品类型所属板块的全部标签 + xuanzhongBiaoqianId: 0, // 0=全部 + }, + + async onLoad(options) { + this.loadGlobalStatus(); + await this.loadShangpinLeixing(); + PopupService.checkAndShow(this, 'jiedan'); + }, + + onHide: function () { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } + }, + + onShow() { + this.registerNotificationComponent(); + this.loadGlobalStatus(); + if (wx.getStorageSync('uid')) { + reconnectForRole('dashou'); + if (app.startImWhenReady) app.startImWhenReady(); + this.refreshDashouProfileSilent(); + } + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + } + }, + + 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; + } + this.setData({ + zhuanghaoStatus: patch.zhanghaoStatus, + dashouzhuangtai: patch.dashouzhuangtai, + huiyuanList: patch.clumber, + yajin: patch.yajin, + jifen: patch.jifen, + }); + } catch (e) {} + }, + + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + loadGlobalStatus() { + const globalData = app.globalData; + this.setData({ + dashoustatus: wx.getStorageSync('dashoustatus'), + zhuanghaoStatus: globalData.zhanghaoStatus, + dashouzhuangtai: globalData.dashouzhuangtai, + uid: wx.getStorageSync('uid'), + huiyuanList: globalData.clumber || [], + yajin: globalData.yajin || 0, + jifen: globalData.jinfen || 0 + }); + }, + + // 加载商品类型 + async loadShangpinLeixing() { + wx.showLoading({ title: '加载商品类型...' }); + try { + const res = await request({ + url: '/dingdan/dsqdhqddlx', + method: 'POST', + header: { 'content-type': 'application/json' } + }); + if (res.statusCode === 200 && res.data) { + const data = res.data; + let list = []; + if (data.code === 200 || data.code === 0) { + if (data.data && Array.isArray(data.data.list)) list = data.data.list; + else if (data.data && Array.isArray(data.data)) list = data.data; + else if (Array.isArray(data.list)) list = data.list; + else if (Array.isArray(data)) list = data; + } + const processedList = this.processTupianUrl(list); + this.setData({ + shangpinleixing: processedList, + xuanzhongLeixingId: processedList[0]?.id || null + }); + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + // 🆕 加载板块标签 + this.loadBankuaiBiaoqian(); + } + } else { + wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' }); + } + } catch (error) { + wx.showToast({ title: '网络错误,加载失败', icon: 'none' }); + } finally { + wx.hideLoading(); + } + }, + + // 处理图片URL + processTupianUrl(list) { + const ossUrl = app.globalData.ossImageUrl || ''; + return list.map(item => ({ + ...item, + full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http') + ? ossUrl + item.tupian_url + : (item.tupian_url || '/images/default-type.png') + })); + }, + + // 🆕 加载板块标签 + 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 selectLeixing(e) { + const now = Date.now(); + const lastSwitchTime = this.data.lastSwitchTime; + const switchCooldown = this.data.switchCooldown; + + if (now - lastSwitchTime < switchCooldown) { + wx.showToast({ + title: `操作太快,请${Math.ceil((switchCooldown - (now - lastSwitchTime)) / 1000)}秒后再试`, + icon: 'none', + duration: 1500 + }); + return; + } + if (this.data.isSwitching) return; + + const leixingId = e.currentTarget.dataset.id; + if (leixingId === this.data.xuanzhongLeixingId) return; + + this.setData({ isSwitching: true, lastSwitchTime: now }); + wx.showLoading({ title: '切换中...' }); + + try { + this.setData({ + xuanzhongLeixingId: leixingId, + dingdanList: [], + page: 1, + hasMore: true, + xuanzhongBiaoqianId: 0 // 重置标签筛选 + }); + await this.loadDingdanList(true); + // 🆕 切换类型后加载新标签 + await this.loadBankuaiBiaoqian(); + } catch (error) { + console.error('切换类型失败:', error); + } finally { + this.setData({ isSwitching: false }); + wx.hideLoading(); + } + }, + + // 🆕 选择标签筛选 + 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 loadDingdanList(isRefresh = false) { + if (this.data.isLoading || !this.data.xuanzhongLeixingId) return; + + const loadPage = isRefresh ? 1 : this.data.page; + if (!isRefresh && !this.data.hasMore) return; + + this.setData({ + isLoading: true, + isLoadingMore: !isRefresh + }); + + try { + const res = await request({ + url: '/dingdan/ddhq', + method: 'POST', + data: { + leixing_id: this.data.xuanzhongLeixingId, + page: loadPage, + page_size: this.data.pageSize, + // 🆕 传递标签筛选参数(0时不传) + biaoqian_id: this.data.xuanzhongBiaoqianId || undefined + } + }); + + this.setData({ + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + + if (res.data.code === 200 || res.data.code === 0) { + const newList = res.data.data.list || []; + const hasMore = res.data.data.has_more || false; + + // 🆕 处理每条订单,增加 hasRequiredMember 字段 + const processedList = newList.map(item => this.processDingdanItem(item)); + const updatedList = isRefresh ? processedList : [...this.data.dingdanList, ...processedList]; + updatedList.sort((a, b) => (b.creat_time || '').localeCompare(a.creat_time || '')); + + this.setData({ + dingdanList: updatedList, + page: loadPage, + hasMore: hasMore + }); + + if (isRefresh) { + this.setData({ lastRefreshTime: Date.now() }); + } + } else { + wx.showToast({ title: res.data.msg || '加载失败', icon: 'none' }); + } + } catch (error) { + console.error('加载订单失败:', error); + this.setData({ + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + wx.showToast({ title: '网络请求失败', icon: 'none' }); + } + }, + + // 处理单条订单数据(包含标签、会员判断) + processDingdanItem(item) { + const ossUrl = app.globalData.ossImageUrl || ''; + let fullTupianUrl = ''; + + if (item.tupian) { + fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; + } else { + 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; + } + const zhidingNicheng = item.zhiding_nicheng || ''; + + // 🆕 判断用户是否有订单所需的会员(仅当订单要求会员类型且存在huiyuan_id) + let hasRequiredMember = true; + if (item.yaoqiuleixing == 1 && item.huiyuan_id) { + const userHasIt = this.data.huiyuanList.some(h => h.huiyuanid == item.huiyuan_id); + hasRequiredMember = userHasIt; + } + + return { + ...item, + full_tupian_url: fullTupianUrl, + isZhiding: isZhiding, + isPingtai: item.pingtai == 1, + isShangjia: item.pingtai == 2, + zhiding_avatar_full: zhidingAvatar, + zhiding_nicheng: zhidingNicheng, + // 🆕 三层标签(后端返回,直接保留) + xuqiu_biaoqian: item.xuqiu_biaoqian || [], + dashou_biaoqian: item.dashou_biaoqian || [], + shangjia_biaoqian: item.shangjia_biaoqian || [], + // 🆕 是否有查看价格的权限 + hasRequiredMember: hasRequiredMember, + }; + }, + + // 跳转到充值页面(原封不动) + goToChongzhiPage(failureType, huiyuanId = null, requiredYajin = 0) { + let url = '/pages/fighter-recharge/fighter-recharge'; + let params = {}; + + switch (failureType) { + case 'huiyuan': + params = { needScroll: '0', scrollTo: 'member' }; + break; + case 'yajin': + params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin }; + break; + case 'jifen': + params = { needScroll: '1', scrollTo: 'bottom' }; + break; + } + + if (huiyuanId) params.huiyuanId = huiyuanId; + + const queryString = Object.keys(params) + .map(key => `${key}=${encodeURIComponent(params[key])}`) + .join('&'); + + wx.navigateTo({ + url: `${url}?${queryString}`, + fail: (err) => { + console.error('跳转失败:', err); + wx.showToast({ title: '跳转失败,请稍后重试', icon: 'none' }); + } + }); + }, + + // 抢单按钮(原封不动) + async onQiangdanTap(e) { + const dingdanItem = e.currentTarget.dataset.item; + if (!dingdanItem) return; + + // 校验1: 打手身份 + if (!this.data.dashoustatus || this.data.dashoustatus != 1) { + wx.showToast({ title: '请先开启打手身份', icon: 'none' }); + return; + } + // 校验2: 账号状态 + if (this.data.zhuanghaoStatus != 1) { + wx.showToast({ title: '账号异常,无法接单', icon: 'none' }); + return; + } + // 校验3: 打手接单状态 + if (this.data.dashouzhuangtai != 1) { + wx.showToast({ title: '您有订单正在接待中', icon: 'none' }); + return; + } + // 校验4: 指定订单 + if (dingdanItem.isZhiding) { + if (!this.data.uid || this.data.uid != dingdanItem.zhiding_uid) { + wx.showToast({ title: '此订单为指定单', icon: 'none' }); + return; + } + } + // 校验5: 会员要求 + if (dingdanItem.yaoqiuleixing == 1) { + const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); + if (!hasHuiyuan) { + wx.showToast({ + title: '未开通对应会员,无法抢单', + icon: 'none', + duration: 2000 + }); + setTimeout(() => { + this.goToChongzhiPage('huiyuan', dingdanItem.huiyuan_id); + }, 500); + return; + } + } + // 校验6: 押金要求 + if (dingdanItem.yaoqiuleixing == 2) { + if (this.data.yajin < dingdanItem.yajin) { + wx.showToast({ + title: `押金不足,需${dingdanItem.yajin}`, + icon: 'none', + duration: 2000 + }); + setTimeout(() => { + this.goToChongzhiPage('yajin', null, dingdanItem.yajin); + }, 500); + return; + } + } + // 校验7: 积分要求 + if (this.data.jifen < 5) { + wx.showToast({ + title: '积分不足,至少需要5积分', + icon: 'none', + duration: 2000 + }); + setTimeout(() => { + this.goToChongzhiPage('jifen'); + }, 500); + return; + } + + // 确认框 + const that = this; + wx.showModal({ + title: '确认抢单', + content: `确定要抢此订单吗?${dingdanItem.isZhiding ? '(指定订单)' : ''}`, + success: async function (res) { + if (res.confirm) { + wx.showLoading({ title: '抢单中...', mask: true }); + try { + const qiangdanRes = await request({ + url: '/dingdan/qiangdan', + method: 'POST', + data: { dingdan_id: dingdanItem.dingdan_id } + }); + wx.hideLoading(); + + if (qiangdanRes.data.code === 200 || qiangdanRes.data.code === 0) { + that.showQiangdanSuccessEffect(); + if (app.globalData) { + app.globalData.dashouzhuangtai = 0; + that.setData({ dashouzhuangtai: 0 }); + } + const newList = that.data.dingdanList.filter( + item => item.dingdan_id !== dingdanItem.dingdan_id + ); + that.setData({ dingdanList: newList }); + } else { + wx.showToast({ + title: qiangdanRes.data.msg || '抢单失败', + icon: 'none' + }); + } + } catch (error) { + wx.hideLoading(); + console.error('抢单请求失败:', error); + wx.showToast({ title: '网络错误,抢单失败', icon: 'none' }); + } + } + } + }); + }, + + showQiangdanSuccessEffect() { + wx.showToast({ title: '抢单成功!', icon: 'success', duration: 2000 }); + }, + + onViewDetail(e) { + const { type, content } = e.currentTarget.dataset; + wx.showModal({ + title: type === 'jieshao' ? '订单介绍' : '订单备注', + content: content, + showCancel: false, + confirmText: '知道了' + }); + }, + + onReachBottom() { + const now = Date.now(); + const lastTime = this.data.lastRefreshTime; + const cooldown = this.data.refreshCooldown; + + if (now - lastTime < cooldown) { + wx.showToast({ + title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, + icon: 'none', + duration: 1500 + }); + return; + } + + if (this.data.isLoading || this.data.isLoadingMore) return; + + if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) { + this.setData({ page: this.data.page + 1 }); + this.loadDingdanList(false); + } + }, + + onPullDownRefresh() { + const now = Date.now(); + const lastTime = this.data.lastRefreshTime; + const cooldown = this.data.refreshCooldown; + + if (now - lastTime < cooldown) { + this.setData({ scrollViewRefreshing: false }); + wx.showToast({ + title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`, + icon: 'none', + duration: 1500 + }); + return; + } + + if (this.data.isLoading) { + this.setData({ scrollViewRefreshing: false }); + return; + } + + this.setData({ + scrollViewRefreshing: true, + lastRefreshTime: now, + page: 1, + hasMore: true + }); + + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + } else { + this.setData({ scrollViewRefreshing: false }); + } + } }); \ No newline at end of file diff --git a/pages/jiedan/jiedan.json b/pages/accept-order/accept-order.json similarity index 100% rename from pages/jiedan/jiedan.json rename to pages/accept-order/accept-order.json diff --git a/pages/jiedan/jiedan.wxml b/pages/accept-order/accept-order.wxml similarity index 100% rename from pages/jiedan/jiedan.wxml rename to pages/accept-order/accept-order.wxml diff --git a/pages/jiedan/jiedan.wxss b/pages/accept-order/accept-order.wxss similarity index 100% rename from pages/jiedan/jiedan.wxss rename to pages/accept-order/accept-order.wxss diff --git a/pages/kaohe_zhongxin/kaohe_zhongxin.js b/pages/assess-center/assess-center.js similarity index 95% rename from pages/kaohe_zhongxin/kaohe_zhongxin.js rename to pages/assess-center/assess-center.js index 9f45455..c6a3fe5 100644 --- a/pages/kaohe_zhongxin/kaohe_zhongxin.js +++ b/pages/assess-center/assess-center.js @@ -1,240 +1,240 @@ -// pages/shenhedating/shenhedating.js -const app = getApp(); -import request from '../../utils/request.js'; - -Page({ - data: { - // 模块列表 [{bankuai_id, mingcheng, count, is_related}] - moduleList: [], - xuanzhongBankuaiId: 0, // 0代表全部 - // 审核记录列表 - recordList: [], - page: 1, - pageSize: 5, - hasMore: true, - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false, - lastRefreshTime: 0, - refreshCooldown: 2000, - // 弹窗控制 - showRuleModal: false, - currentRuleContent: '', - showBeizhuModal: false, - currentBeizhuContent: '', - // 加载状态 - loadingModules: false - }, - - onLoad() { - this.loadModules(); - }, - - onShow() { - this.registerNotificationComponent(); - }, - - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - // 加载板块模块 - async loadModules() { - this.setData({ loadingModules: true }); - try { - const res = await request({ url: '/dengji/shdthqmk', method: 'POST' }); - if (res && res.data.code === 0) { - const modules = res.data.data.modules || []; - this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 }); - this.loadRecords(true); - } else { - wx.showToast({ title: '加载模块失败', icon: 'none' }); - } - } catch (e) { - wx.showToast({ title: '网络错误', icon: 'none' }); - } finally { - this.setData({ loadingModules: false }); - } - }, - - // 选择模块(含全部) - selectModule(e) { - const bankuaiId = e.currentTarget.dataset.id; - if (bankuaiId === this.data.xuanzhongBankuaiId) return; - this.setData({ - xuanzhongBankuaiId: bankuaiId, - recordList: [], - page: 1, - hasMore: true - }); - this.loadRecords(true); - }, - - // 加载审核记录 - async loadRecords(isRefresh = false) { - if (this.data.isLoading) return; - const page = isRefresh ? 1 : this.data.page; - if (!isRefresh && !this.data.hasMore) return; - - this.setData({ isLoading: true, isLoadingMore: !isRefresh }); - - try { - const res = await request({ - url: '/dengji/hqshsj', - method: 'POST', - data: { - bankuai_id: this.data.xuanzhongBankuaiId || undefined, - page: page, - page_size: this.data.pageSize - } - }); - - this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false }); - - if (res && res.data.code === 0) { - const list = res.data.data.list || []; - const hasMore = res.data.data.has_more; - const ossUrl = app.globalData.ossImageUrl || ''; - const processedList = list.map(item => { - let avatar = item.shenqingren_avatar || ''; - if (avatar && !avatar.startsWith('http')) { - avatar = ossUrl + avatar; - } - return { ...item, shenqingren_avatar: avatar }; - }); - const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList]; - this.setData({ recordList: newList, page: page + 1, hasMore: hasMore }); - if (isRefresh) this.setData({ lastRefreshTime: Date.now() }); - } else { - wx.showToast({ title: '加载记录失败', icon: 'none' }); - } - } catch (e) { - this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false }); - wx.showToast({ title: '网络错误', icon: 'none' }); - } - }, - - // 上拉加载更多 - onReachBottom() { - const now = Date.now(); - if (now - this.data.lastRefreshTime < this.data.refreshCooldown || - this.data.isLoading || this.data.isLoadingMore) return; - if (this.data.hasMore) { - this.loadRecords(false); - } - }, - - // 下拉刷新 - onPullDownRefresh() { - const now = Date.now(); - if (now - this.data.lastRefreshTime < this.data.refreshCooldown || this.data.isLoading) { - this.setData({ scrollViewRefreshing: false }); - return; - } - this.setData({ scrollViewRefreshing: true, lastRefreshTime: now, page: 1, hasMore: true }); - this.loadRecords(true); - }, - - // 查看规则详情 - showRuleDetail(e) { - const content = e.currentTarget.dataset.content; - this.setData({ showRuleModal: true, currentRuleContent: content }); - }, - hideRuleDetail() { - this.setData({ showRuleModal: false, currentRuleContent: '' }); - }, - - // 查看备注详情 - showBeizhuDetail(e) { - const content = e.currentTarget.dataset.content; - this.setData({ showBeizhuModal: true, currentBeizhuContent: content || '无' }); - }, - hideBeizhuDetail() { - this.setData({ showBeizhuModal: false, currentBeizhuContent: '' }); - }, - - // 抢单 - async onShouShen(e) { - const jiluId = e.currentTarget.dataset.jiluid; - const bankuaiId = e.currentTarget.dataset.bankuaiid; - if (!jiluId) { - wx.showToast({ title: '记录ID异常,无法接单', icon: 'none' }); - return; - } - - const that = this; - wx.showModal({ - title: '确认审核', - content: '确定要审核此用户吗?审核后请前往游戏进行审核,并严格评分。', - confirmColor: '#c9a558', - success: async (res) => { - if (res.confirm) { - wx.showLoading({ title: '接单中...', mask: true }); - try { - const qdRes = await request({ - url: '/dengji/shqd', - method: 'POST', - data: { jilu_id: jiluId } - }); - if (qdRes && qdRes.data.code === 0) { - // 抢单成功,弹出联系打手弹窗 - wx.showModal({ - title: '接待成功', - content: '请认真考核,点击联系他查看打手信息并打分。', - showCancel: false, - confirmText: '联系他', - confirmColor: '#c9a558', - success: (modalRes) => { - if (modalRes.confirm) { - wx.navigateTo({ - url: '/pages/kaohe_dafen/kaohe_dafen?jilu_id=' + jiluId - }); - } - } - }); - const newList = that.data.recordList.filter(r => r.jilu_id !== jiluId); - that.setData({ recordList: newList }); - // 对应板块待审核数减1 - const bkId = qdRes.data.data ? qdRes.data.data.bankuai_id : bankuaiId; - if (bkId) { - const newModules = that.data.moduleList.map(m => { - if (m.bankuai_id === bkId && m.count > 0) { - return { ...m, count: m.count - 1 }; - } - return m; - }); - that.setData({ moduleList: newModules }); - } - } else { - const errMsg = qdRes?.data?.msg || '接单失败,请重试'; - wx.showModal({ - title: '接单失败', - content: errMsg, - showCancel: false, - confirmText: '知道了', - confirmColor: '#c9a558' - }); - } - } catch (e) { - wx.showModal({ - title: '提示', - content: '网络错误,请重试', - showCancel: false, - confirmText: '知道了' - }); - } finally { - wx.hideLoading(); - } - } - } - }); - }, - - noop() {} +// pages/shenhedating/shenhedating.js +const app = getApp(); +import request from '../../utils/request.js'; + +Page({ + data: { + // 模块列表 [{bankuai_id, mingcheng, count, is_related}] + moduleList: [], + xuanzhongBankuaiId: 0, // 0代表全部 + // 审核记录列表 + recordList: [], + page: 1, + pageSize: 5, + hasMore: true, + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false, + lastRefreshTime: 0, + refreshCooldown: 2000, + // 弹窗控制 + showRuleModal: false, + currentRuleContent: '', + showBeizhuModal: false, + currentBeizhuContent: '', + // 加载状态 + loadingModules: false + }, + + onLoad() { + this.loadModules(); + }, + + onShow() { + this.registerNotificationComponent(); + }, + + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + // 加载板块模块 + async loadModules() { + this.setData({ loadingModules: true }); + try { + const res = await request({ url: '/dengji/shdthqmk', method: 'POST' }); + if (res && res.data.code === 0) { + const modules = res.data.data.modules || []; + this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 }); + this.loadRecords(true); + } else { + wx.showToast({ title: '加载模块失败', icon: 'none' }); + } + } catch (e) { + wx.showToast({ title: '网络错误', icon: 'none' }); + } finally { + this.setData({ loadingModules: false }); + } + }, + + // 选择模块(含全部) + selectModule(e) { + const bankuaiId = e.currentTarget.dataset.id; + if (bankuaiId === this.data.xuanzhongBankuaiId) return; + this.setData({ + xuanzhongBankuaiId: bankuaiId, + recordList: [], + page: 1, + hasMore: true + }); + this.loadRecords(true); + }, + + // 加载审核记录 + async loadRecords(isRefresh = false) { + if (this.data.isLoading) return; + const page = isRefresh ? 1 : this.data.page; + if (!isRefresh && !this.data.hasMore) return; + + this.setData({ isLoading: true, isLoadingMore: !isRefresh }); + + try { + const res = await request({ + url: '/dengji/hqshsj', + method: 'POST', + data: { + bankuai_id: this.data.xuanzhongBankuaiId || undefined, + page: page, + page_size: this.data.pageSize + } + }); + + this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false }); + + if (res && res.data.code === 0) { + const list = res.data.data.list || []; + const hasMore = res.data.data.has_more; + const ossUrl = app.globalData.ossImageUrl || ''; + const processedList = list.map(item => { + let avatar = item.shenqingren_avatar || ''; + if (avatar && !avatar.startsWith('http')) { + avatar = ossUrl + avatar; + } + return { ...item, shenqingren_avatar: avatar }; + }); + const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList]; + this.setData({ recordList: newList, page: page + 1, hasMore: hasMore }); + if (isRefresh) this.setData({ lastRefreshTime: Date.now() }); + } else { + wx.showToast({ title: '加载记录失败', icon: 'none' }); + } + } catch (e) { + this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false }); + wx.showToast({ title: '网络错误', icon: 'none' }); + } + }, + + // 上拉加载更多 + onReachBottom() { + const now = Date.now(); + if (now - this.data.lastRefreshTime < this.data.refreshCooldown || + this.data.isLoading || this.data.isLoadingMore) return; + if (this.data.hasMore) { + this.loadRecords(false); + } + }, + + // 下拉刷新 + onPullDownRefresh() { + const now = Date.now(); + if (now - this.data.lastRefreshTime < this.data.refreshCooldown || this.data.isLoading) { + this.setData({ scrollViewRefreshing: false }); + return; + } + this.setData({ scrollViewRefreshing: true, lastRefreshTime: now, page: 1, hasMore: true }); + this.loadRecords(true); + }, + + // 查看规则详情 + showRuleDetail(e) { + const content = e.currentTarget.dataset.content; + this.setData({ showRuleModal: true, currentRuleContent: content }); + }, + hideRuleDetail() { + this.setData({ showRuleModal: false, currentRuleContent: '' }); + }, + + // 查看备注详情 + showBeizhuDetail(e) { + const content = e.currentTarget.dataset.content; + this.setData({ showBeizhuModal: true, currentBeizhuContent: content || '无' }); + }, + hideBeizhuDetail() { + this.setData({ showBeizhuModal: false, currentBeizhuContent: '' }); + }, + + // 抢单 + async onShouShen(e) { + const jiluId = e.currentTarget.dataset.jiluid; + const bankuaiId = e.currentTarget.dataset.bankuaiid; + if (!jiluId) { + wx.showToast({ title: '记录ID异常,无法接单', icon: 'none' }); + return; + } + + const that = this; + wx.showModal({ + title: '确认审核', + content: '确定要审核此用户吗?审核后请前往游戏进行审核,并严格评分。', + confirmColor: '#c9a558', + success: async (res) => { + if (res.confirm) { + wx.showLoading({ title: '接单中...', mask: true }); + try { + const qdRes = await request({ + url: '/dengji/shqd', + method: 'POST', + data: { jilu_id: jiluId } + }); + if (qdRes && qdRes.data.code === 0) { + // 抢单成功,弹出联系打手弹窗 + wx.showModal({ + title: '接待成功', + content: '请认真考核,点击联系他查看打手信息并打分。', + showCancel: false, + confirmText: '联系他', + confirmColor: '#c9a558', + success: (modalRes) => { + if (modalRes.confirm) { + wx.navigateTo({ + url: '/pages/assess-score/assess-score?jilu_id=' + jiluId + }); + } + } + }); + const newList = that.data.recordList.filter(r => r.jilu_id !== jiluId); + that.setData({ recordList: newList }); + // 对应板块待审核数减1 + const bkId = qdRes.data.data ? qdRes.data.data.bankuai_id : bankuaiId; + if (bkId) { + const newModules = that.data.moduleList.map(m => { + if (m.bankuai_id === bkId && m.count > 0) { + return { ...m, count: m.count - 1 }; + } + return m; + }); + that.setData({ moduleList: newModules }); + } + } else { + const errMsg = qdRes?.data?.msg || '接单失败,请重试'; + wx.showModal({ + title: '接单失败', + content: errMsg, + showCancel: false, + confirmText: '知道了', + confirmColor: '#c9a558' + }); + } + } catch (e) { + wx.showModal({ + title: '提示', + content: '网络错误,请重试', + showCancel: false, + confirmText: '知道了' + }); + } finally { + wx.hideLoading(); + } + } + } + }); + }, + + noop() {} }); \ No newline at end of file diff --git a/pages/kaohe_zhongxin/kaohe_zhongxin.json b/pages/assess-center/assess-center.json similarity index 100% rename from pages/kaohe_zhongxin/kaohe_zhongxin.json rename to pages/assess-center/assess-center.json diff --git a/pages/kaohe_zhongxin/kaohe_zhongxin.wxml b/pages/assess-center/assess-center.wxml similarity index 100% rename from pages/kaohe_zhongxin/kaohe_zhongxin.wxml rename to pages/assess-center/assess-center.wxml diff --git a/pages/kaohe_zhongxin/kaohe_zhongxin.wxss b/pages/assess-center/assess-center.wxss similarity index 99% rename from pages/kaohe_zhongxin/kaohe_zhongxin.wxss rename to pages/assess-center/assess-center.wxss index 586c429..be8ff31 100644 --- a/pages/kaohe_zhongxin/kaohe_zhongxin.wxss +++ b/pages/assess-center/assess-center.wxss @@ -245,8 +245,7 @@ animation: spin 0.8s linear infinite; margin-bottom: 20rpx; } - @keyframes spin { to { transform: rotate(360deg); } } - + /* 弹窗 */ .modal-mask { position: fixed; diff --git a/pages/kaohe_jinpai/kaohe_jinpai.js b/pages/assess-gold/assess-gold.js similarity index 96% rename from pages/kaohe_jinpai/kaohe_jinpai.js rename to pages/assess-gold/assess-gold.js index ed6fcb4..5c0df6a 100644 --- a/pages/kaohe_jinpai/kaohe_jinpai.js +++ b/pages/assess-gold/assess-gold.js @@ -1,461 +1,461 @@ -// pages/kaohe_jinpai/kaohe_jinpai.js -const app = getApp(); -import request from '../../utils/request.js'; - -Page({ - data: { - activeTab: 'all_tags', - plateList: [], // 第一个接口返回的所有板块及标签(含 fee_list) - myTags: [], - recordList: [], - recordPage: 1, - recordHasMore: true, - recordLoading: false, - recordFilter: 'pending', - showApplyModal: false, - selectedTag: null, - applyGameNick: '', - applyRemark: '', - applyFee: 0, - applyJiluId: '', - isReapply: false, - payLoading: false, - ossImageUrl: app.globalData.ossImageUrl || '', - - // 新增:考核官相关 - kaoheguanList: [], // 所有可选的考核官 - showKaoheguanModal: false, // 考核官选择弹窗 - selectedKaoheguanId: '', // 已选择的考核官ID - selectedKaoheguanInfo: null, // 已选择的考核官信息(用于展示) - searchKeyword: '', // 搜索关键词 - filteredKaoheguanList: [], // 搜索过滤后的列表 - }, - - onLoad() { - this.fetchAllTags(); - this.fetchMyRecords(true); - }, - - switchTab(e) { - const tab = e.currentTarget.dataset.tab; - if (tab === this.data.activeTab) return; - this.setData({ activeTab: tab }); - if (tab === 'my_records') this.fetchMyRecords(true); - }, - - // 获取所有板块及标签(含费用列表),缓存到 plateList,同时获取考核官列表 - async fetchAllTags() { - try { - const res = await request({ url: '/dengji/dskhhq', method: 'POST' }); - if (res.data.code === 0) { - const { plate_list, my_tags, kaoheguan_list } = res.data.data; - // 拼接考核官头像为完整URL - const ossUrl = this.data.ossImageUrl; - const processedKgList = (kaoheguan_list || []).map(kg => ({ - ...kg, - avatar: kg.avatar && !kg.avatar.startsWith('http') ? ossUrl + kg.avatar : kg.avatar, - })); - this.setData({ - plateList: plate_list || [], - myTags: my_tags || [], - kaoheguanList: processedKgList // 使用拼接后的列表 - }); - } - } catch (e) {} - }, - - // 获取我的考核记录,并根据 plateList 计算本次/预计下次费用 - async fetchMyRecords(isRefresh = false) { - if (this.data.recordLoading) return; - const page = isRefresh ? 1 : this.data.recordPage; - this.setData({ recordLoading: true }); - try { - const res = await request({ - url: '/dengji/dskhjl', - method: 'POST', - data: { status: this.data.recordFilter, page, page_size: 5 } - }); - if (res.data.code === 0) { - const { list, has_more } = res.data.data; - - // 从 plateList 构建标签ID -> 完整标签对象的映射(用于精确匹配费用) - const tagMap = {}; - this.data.plateList.forEach(plate => { - (plate.tags || []).forEach(tag => { - tagMap[tag.id] = tag; // tag 包含 fee_list - }); - }); - - // 处理每条记录:优先使用 tag_obj.id 匹配,其次 chenghao_id - const processed = list.map(item => { - // 尝试多种方式获取标签ID - const tagId = (item.tag_obj && item.tag_obj.id) || item.chenghao_id; - const tag = tagMap[tagId] || item.tag_obj || {}; - const feeList = tag.fee_list || []; - let currentFee = 0; - let nextFee = 0; - if (feeList.length > 0) { - const cishu = item.cishu; - const cur = feeList.find(f => f.cishu === cishu); - currentFee = cur ? cur.feiyong : feeList[feeList.length - 1].feiyong; - const nextCishu = cishu + 1; - const nxt = feeList.find(f => f.cishu === nextCishu); - nextFee = nxt ? nxt.feiyong : feeList[feeList.length - 1].feiyong; - } - return { - ...item, - current_fee: currentFee, - next_fee: nextFee, - tag_obj: tag // 使用匹配到的完整标签对象,保证后续“再次考核”能拿到费用 - }; - }); - - const newList = isRefresh ? processed : [...this.data.recordList, ...processed]; - this.setData({ - recordList: newList, - recordPage: page + 1, - recordHasMore: has_more, - recordLoading: false - }); - } else { - this.setData({ recordLoading: false }); - } - } catch (e) { - this.setData({ recordLoading: false }); - } - }, - - filterRecord(e) { - const filter = e.currentTarget.dataset.filter; - if (filter === this.data.recordFilter) return; - this.setData({ recordFilter: filter, recordList: [], recordPage: 1, recordHasMore: true }); - this.fetchMyRecords(true); - }, - - onReachBottom() { - if (this.data.activeTab === 'my_records' && this.data.recordHasMore) { - this.fetchMyRecords(false); - } - }, - - // 打开申请考核弹窗,费用完全基于 plateList 中的标签数据 - openApplyModal(e) { - const { tag, jiluid, reapply } = e.currentTarget.dataset; - // 查找完整标签对象,保证 fee_list 存在 - let fullTag = tag; - if (fullTag && fullTag.fee_list === undefined) { - const found = this.findTagInPlateList(fullTag.id); - if (found) fullTag = found; - } - if (!fullTag) { - const found = this.findTagInPlateList(tag); - if (found) fullTag = found; - } - - let fee = 0; - if (fullTag) { - let nextCishu = 0; - // 再次申请时,基于原记录次数计算下一次考核次数 - if (reapply && jiluid) { - const record = this.data.recordList.find(r => r.jilu_id === jiluid); - if (record) { - nextCishu = record.cishu + 1; - } else { - nextCishu = (fullTag.my_cishu || 0) + 1; - } - } else { - nextCishu = (fullTag.my_cishu || 0) + 1; - } - const feeList = fullTag.fee_list || []; - const exact = feeList.find(f => f.cishu === nextCishu); - if (exact) { - fee = exact.feiyong; - } else if (feeList.length > 0) { - fee = feeList[feeList.length - 1].feiyong; - } - } - // 检查再次申请时原记录是否有考核官,若有则不允许指定 - let canSpecify = true; - let originalShenheguanId = ''; - if (reapply && jiluid) { - const record = this.data.recordList.find(r => r.jilu_id === jiluid); - if (record && record.shenheguan_id) { - canSpecify = false; // 已有考核官,不能指定新的 - originalShenheguanId = record.shenheguan_id; - } - } - this.setData({ - showApplyModal: true, - selectedTag: fullTag || null, - applyGameNick: '', - applyRemark: '', - applyFee: fee, - applyJiluId: jiluid || '', - isReapply: reapply || false, - selectedKaoheguanId: '', // 重置 - selectedKaoheguanInfo: null, - canSpecify: canSpecify, // 新增 - originalShenheguanId: originalShenheguanId, // 新增 - }); - }, - - // 辅助方法:从 plateList 查找指定 id 的标签 - findTagInPlateList(tagId) { - if (!tagId) return null; - for (const plate of this.data.plateList) { - for (const t of (plate.tags || [])) { - if (t.id === tagId) return t; - } - } - return null; - }, - - closeApplyModal() { - this.setData({ showApplyModal: false }); - }, - - // 实时更新游戏昵称 - onNickInput(e) { - this.setData({ applyGameNick: e.detail.value }); - }, - - // 实时更新备注 - onRemarkInput(e) { - this.setData({ applyRemark: e.detail.value }); - }, - - // 新增:打开考核官选择弹窗 - openKaoheguanModal() { - if (!this.data.canSpecify) { - wx.showToast({ title: '已有考核官,无法重新指定', icon: 'none' }); - return; - } - // 根据费用筛选可选考核官 - let all = [...this.data.kaoheguanList]; - if (this.data.applyFee > 0) { - all = all.filter(kg => kg.is_renzheng); - } - this.setData({ - showKaoheguanModal: true, - filteredKaoheguanList: all, - searchKeyword: '', - }); - }, - - // 关闭考核官选择弹窗 - closeKaoheguanModal() { - this.setData({ showKaoheguanModal: false }); - }, - - // 搜索输入 - onSearchInput(e) { - const value = e.detail.value.trim(); - this.setData({ searchKeyword: value }); - this.filterKaoheguanList(value); - }, - - // 过滤考核官列表 - filterKaoheguanList(keyword) { - let all = [...this.data.kaoheguanList]; - if (this.data.applyFee > 0) { - all = all.filter(kg => kg.is_renzheng); - } - if (keyword) { - all = all.filter(kg => - kg.yonghuid.includes(keyword) || - (kg.dashou_nick && kg.dashou_nick.includes(keyword)) - ); - } - this.setData({ filteredKaoheguanList: all }); - }, - - // 选择一个考核官 - selectKaoheguan(e) { - const kg = e.currentTarget.dataset.kg; - if (kg.shenhe_zhuangtai !== 0) { - wx.showToast({ title: '该考核官正忙,无法指定', icon: 'none' }); - return; - } - this.setData({ - selectedKaoheguanId: kg.yonghuid, - selectedKaoheguanInfo: kg, - showKaoheguanModal: false, - }); - }, - - // 取消已选择的考核官 - clearSelectedKaoheguan() { - this.setData({ - selectedKaoheguanId: '', - selectedKaoheguanInfo: null, - }); - }, - - // 提交申请 - async submitApply() { - const { applyGameNick, applyRemark, applyFee, selectedTag, isReapply, applyJiluId, selectedKaoheguanId } = this.data; - if (!applyGameNick || !applyGameNick.trim()) { - wx.showToast({ title: '请输入游戏昵称', icon: 'none' }); - return; - } - if (!applyRemark || !applyRemark.trim()) { - wx.showToast({ title: '请填写备注', icon: 'none' }); - return; - } - if (applyFee > 0) { - await this.startPayProcess(); - } else { - await this.doFreeApply(); - } - }, - - // 支付流程 - async startPayProcess() { - this.setData({ payLoading: true }); - try { - const res = await request({ - url: '/yonghu/khzf', - method: 'POST', - data: { - tag_id: this.data.selectedTag.id, - game_nick: this.data.applyGameNick, - remark: this.data.applyRemark, - reapply: this.data.isReapply, - jilu_id: this.data.applyJiluId, - shenheguan_id: this.data.selectedKaoheguanId, // 新增 - } - }); - if (res.data.code !== 200) throw new Error(res.data.message || '下单失败'); - const payParams = res.data.payParams; - const dingdanid = res.data.dingdanid; - wx.requestPayment({ - timeStamp: payParams.timeStamp, - nonceStr: payParams.nonceStr, - package: payParams.package, - signType: payParams.signType || 'MD5', - paySign: payParams.paySign, - success: async () => { - await this.pollPayStatus(dingdanid); - }, - fail: () => { - wx.showToast({ title: '支付取消或失败', icon: 'none' }); - request({ url: '/yonghu/khzfsb', method: 'POST', data: { dingdanid } }).catch(()=>{}); - } - }); - } catch (e) { - wx.showToast({ title: e.message || '支付异常', icon: 'none' }); - } finally { - this.setData({ payLoading: false }); - } - }, - - // 轮询支付结果 - async pollPayStatus(dingdanid) { - for (let i = 0; i < 10; i++) { - try { - const res = await request({ url: '/yonghu/khzffc', method: 'POST', data: { dingdanid } }); - if (res.data.code === 200) { - wx.showToast({ title: '申请成功', icon: 'success' }); - this.closeApplyModal(); - this.fetchAllTags(); - this.setData({ recordList: [], recordPage: 1 }); - this.fetchMyRecords(true); - return; - } - } catch (e) {} - await new Promise(r => setTimeout(r, 2000)); - } - wx.showToast({ title: '支付确认超时', icon: 'none' }); - }, - - // 免费申请 - async doFreeApply() { - try { - const res = await request({ - url: '/dengji/dssqkh', - method: 'POST', - data: { - tag_id: this.data.selectedTag.id, - game_nick: this.data.applyGameNick, - remark: this.data.applyRemark, - reapply: this.data.isReapply, - jilu_id: this.data.applyJiluId, - shenheguan_id: this.data.selectedKaoheguanId, // 新增 - } - }); - if (res.data.code === 0) { - wx.showToast({ title: '申请成功', icon: 'success' }); - this.closeApplyModal(); - this.fetchAllTags(); - this.setData({ recordList: [], recordPage: 1 }); - this.fetchMyRecords(true); - } else { - wx.showToast({ title: res.data.msg || '申请失败', icon: 'none' }); - } - } catch (e) { - wx.showToast({ title: '网络错误', icon: 'none' }); - } - }, - - // 联系考核官(私聊) - contactKaoheguan(e) { - const item = e.currentTarget.dataset.item; - if (!item) return; - if (!item.shenheguan_id) { - wx.showToast({ title: '暂无考核官信息', icon: 'none' }); - return; - } - const uid = wx.getStorageSync('uid'); - if (!uid) { - wx.showToast({ title: '用户信息缺失', icon: 'none' }); - return; - } - if (app.globalData.currentRole !== 'dashou') { - app.globalData.currentRole = 'dashou'; - wx.setStorageSync('currentRole', 'dashou'); - } - if (app.connectForCurrentRole) { - app.connectForCurrentRole(); - } else if (app.ensureConnection) { - app.ensureConnection(); - } - const ossImageUrl = this.data.ossImageUrl || app.globalData.ossImageUrl || ''; - let fullAvatar = item.shenheguan_avatar || ''; - if (fullAvatar && !fullAvatar.startsWith('http')) { - fullAvatar = ossImageUrl + fullAvatar; - } - if (!fullAvatar) { - fullAvatar = ossImageUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); - } - const param = { - toUserId: 'Kh' + item.shenheguan_id, - toName: '考核官' + item.shenheguan_id, - toAvatar: fullAvatar - }; - wx.navigateTo({ - url: '/pages/liaotian/liaotian?data=' + encodeURIComponent(JSON.stringify(param)), - fail: (err) => { - wx.showToast({ title: '打开聊天失败', icon: 'none' }); - } - }); - }, - - showTagDetail(e) { - const tag = e.currentTarget.dataset.tag; - const feeStr = this.formatFeeList(tag.fee_list); - wx.showModal({ - title: tag.name, - content: `规则:${tag.rule || '暂无'}\n${tag.jinpai ? '【可同时开启金牌】' : ''}\n费用:${feeStr}`, - showCancel: false, - confirmText: '知道了' - }); - }, - - formatFeeList(feeList) { - if (!feeList || feeList.length === 0) return '暂无'; - let str = feeList.map(f => `第${f.cishu}次:¥${f.feiyong}`).join(';'); - const last = feeList[feeList.length - 1]; - str += `;第${last.cishu}次及以上:¥${last.feiyong}`; - return str; - }, +// pages/assess-gold/assess-gold.js +const app = getApp(); +import request from '../../utils/request.js'; + +Page({ + data: { + activeTab: 'all_tags', + plateList: [], // 第一个接口返回的所有板块及标签(含 fee_list) + myTags: [], + recordList: [], + recordPage: 1, + recordHasMore: true, + recordLoading: false, + recordFilter: 'pending', + showApplyModal: false, + selectedTag: null, + applyGameNick: '', + applyRemark: '', + applyFee: 0, + applyJiluId: '', + isReapply: false, + payLoading: false, + ossImageUrl: app.globalData.ossImageUrl || '', + + // 新增:考核官相关 + kaoheguanList: [], // 所有可选的考核官 + showKaoheguanModal: false, // 考核官选择弹窗 + selectedKaoheguanId: '', // 已选择的考核官ID + selectedKaoheguanInfo: null, // 已选择的考核官信息(用于展示) + searchKeyword: '', // 搜索关键词 + filteredKaoheguanList: [], // 搜索过滤后的列表 + }, + + onLoad() { + this.fetchAllTags(); + this.fetchMyRecords(true); + }, + + switchTab(e) { + const tab = e.currentTarget.dataset.tab; + if (tab === this.data.activeTab) return; + this.setData({ activeTab: tab }); + if (tab === 'my_records') this.fetchMyRecords(true); + }, + + // 获取所有板块及标签(含费用列表),缓存到 plateList,同时获取考核官列表 + async fetchAllTags() { + try { + const res = await request({ url: '/dengji/dskhhq', method: 'POST' }); + if (res.data.code === 0) { + const { plate_list, my_tags, kaoheguan_list } = res.data.data; + // 拼接考核官头像为完整URL + const ossUrl = this.data.ossImageUrl; + const processedKgList = (kaoheguan_list || []).map(kg => ({ + ...kg, + avatar: kg.avatar && !kg.avatar.startsWith('http') ? ossUrl + kg.avatar : kg.avatar, + })); + this.setData({ + plateList: plate_list || [], + myTags: my_tags || [], + kaoheguanList: processedKgList // 使用拼接后的列表 + }); + } + } catch (e) {} + }, + + // 获取我的考核记录,并根据 plateList 计算本次/预计下次费用 + async fetchMyRecords(isRefresh = false) { + if (this.data.recordLoading) return; + const page = isRefresh ? 1 : this.data.recordPage; + this.setData({ recordLoading: true }); + try { + const res = await request({ + url: '/dengji/dskhjl', + method: 'POST', + data: { status: this.data.recordFilter, page, page_size: 5 } + }); + if (res.data.code === 0) { + const { list, has_more } = res.data.data; + + // 从 plateList 构建标签ID -> 完整标签对象的映射(用于精确匹配费用) + const tagMap = {}; + this.data.plateList.forEach(plate => { + (plate.tags || []).forEach(tag => { + tagMap[tag.id] = tag; // tag 包含 fee_list + }); + }); + + // 处理每条记录:优先使用 tag_obj.id 匹配,其次 chenghao_id + const processed = list.map(item => { + // 尝试多种方式获取标签ID + const tagId = (item.tag_obj && item.tag_obj.id) || item.chenghao_id; + const tag = tagMap[tagId] || item.tag_obj || {}; + const feeList = tag.fee_list || []; + let currentFee = 0; + let nextFee = 0; + if (feeList.length > 0) { + const cishu = item.cishu; + const cur = feeList.find(f => f.cishu === cishu); + currentFee = cur ? cur.feiyong : feeList[feeList.length - 1].feiyong; + const nextCishu = cishu + 1; + const nxt = feeList.find(f => f.cishu === nextCishu); + nextFee = nxt ? nxt.feiyong : feeList[feeList.length - 1].feiyong; + } + return { + ...item, + current_fee: currentFee, + next_fee: nextFee, + tag_obj: tag // 使用匹配到的完整标签对象,保证后续“再次考核”能拿到费用 + }; + }); + + const newList = isRefresh ? processed : [...this.data.recordList, ...processed]; + this.setData({ + recordList: newList, + recordPage: page + 1, + recordHasMore: has_more, + recordLoading: false + }); + } else { + this.setData({ recordLoading: false }); + } + } catch (e) { + this.setData({ recordLoading: false }); + } + }, + + filterRecord(e) { + const filter = e.currentTarget.dataset.filter; + if (filter === this.data.recordFilter) return; + this.setData({ recordFilter: filter, recordList: [], recordPage: 1, recordHasMore: true }); + this.fetchMyRecords(true); + }, + + onReachBottom() { + if (this.data.activeTab === 'my_records' && this.data.recordHasMore) { + this.fetchMyRecords(false); + } + }, + + // 打开申请考核弹窗,费用完全基于 plateList 中的标签数据 + openApplyModal(e) { + const { tag, jiluid, reapply } = e.currentTarget.dataset; + // 查找完整标签对象,保证 fee_list 存在 + let fullTag = tag; + if (fullTag && fullTag.fee_list === undefined) { + const found = this.findTagInPlateList(fullTag.id); + if (found) fullTag = found; + } + if (!fullTag) { + const found = this.findTagInPlateList(tag); + if (found) fullTag = found; + } + + let fee = 0; + if (fullTag) { + let nextCishu = 0; + // 再次申请时,基于原记录次数计算下一次考核次数 + if (reapply && jiluid) { + const record = this.data.recordList.find(r => r.jilu_id === jiluid); + if (record) { + nextCishu = record.cishu + 1; + } else { + nextCishu = (fullTag.my_cishu || 0) + 1; + } + } else { + nextCishu = (fullTag.my_cishu || 0) + 1; + } + const feeList = fullTag.fee_list || []; + const exact = feeList.find(f => f.cishu === nextCishu); + if (exact) { + fee = exact.feiyong; + } else if (feeList.length > 0) { + fee = feeList[feeList.length - 1].feiyong; + } + } + // 检查再次申请时原记录是否有考核官,若有则不允许指定 + let canSpecify = true; + let originalShenheguanId = ''; + if (reapply && jiluid) { + const record = this.data.recordList.find(r => r.jilu_id === jiluid); + if (record && record.shenheguan_id) { + canSpecify = false; // 已有考核官,不能指定新的 + originalShenheguanId = record.shenheguan_id; + } + } + this.setData({ + showApplyModal: true, + selectedTag: fullTag || null, + applyGameNick: '', + applyRemark: '', + applyFee: fee, + applyJiluId: jiluid || '', + isReapply: reapply || false, + selectedKaoheguanId: '', // 重置 + selectedKaoheguanInfo: null, + canSpecify: canSpecify, // 新增 + originalShenheguanId: originalShenheguanId, // 新增 + }); + }, + + // 辅助方法:从 plateList 查找指定 id 的标签 + findTagInPlateList(tagId) { + if (!tagId) return null; + for (const plate of this.data.plateList) { + for (const t of (plate.tags || [])) { + if (t.id === tagId) return t; + } + } + return null; + }, + + closeApplyModal() { + this.setData({ showApplyModal: false }); + }, + + // 实时更新游戏昵称 + onNickInput(e) { + this.setData({ applyGameNick: e.detail.value }); + }, + + // 实时更新备注 + onRemarkInput(e) { + this.setData({ applyRemark: e.detail.value }); + }, + + // 新增:打开考核官选择弹窗 + openKaoheguanModal() { + if (!this.data.canSpecify) { + wx.showToast({ title: '已有考核官,无法重新指定', icon: 'none' }); + return; + } + // 根据费用筛选可选考核官 + let all = [...this.data.kaoheguanList]; + if (this.data.applyFee > 0) { + all = all.filter(kg => kg.is_renzheng); + } + this.setData({ + showKaoheguanModal: true, + filteredKaoheguanList: all, + searchKeyword: '', + }); + }, + + // 关闭考核官选择弹窗 + closeKaoheguanModal() { + this.setData({ showKaoheguanModal: false }); + }, + + // 搜索输入 + onSearchInput(e) { + const value = e.detail.value.trim(); + this.setData({ searchKeyword: value }); + this.filterKaoheguanList(value); + }, + + // 过滤考核官列表 + filterKaoheguanList(keyword) { + let all = [...this.data.kaoheguanList]; + if (this.data.applyFee > 0) { + all = all.filter(kg => kg.is_renzheng); + } + if (keyword) { + all = all.filter(kg => + kg.yonghuid.includes(keyword) || + (kg.dashou_nick && kg.dashou_nick.includes(keyword)) + ); + } + this.setData({ filteredKaoheguanList: all }); + }, + + // 选择一个考核官 + selectKaoheguan(e) { + const kg = e.currentTarget.dataset.kg; + if (kg.shenhe_zhuangtai !== 0) { + wx.showToast({ title: '该考核官正忙,无法指定', icon: 'none' }); + return; + } + this.setData({ + selectedKaoheguanId: kg.yonghuid, + selectedKaoheguanInfo: kg, + showKaoheguanModal: false, + }); + }, + + // 取消已选择的考核官 + clearSelectedKaoheguan() { + this.setData({ + selectedKaoheguanId: '', + selectedKaoheguanInfo: null, + }); + }, + + // 提交申请 + async submitApply() { + const { applyGameNick, applyRemark, applyFee, selectedTag, isReapply, applyJiluId, selectedKaoheguanId } = this.data; + if (!applyGameNick || !applyGameNick.trim()) { + wx.showToast({ title: '请输入游戏昵称', icon: 'none' }); + return; + } + if (!applyRemark || !applyRemark.trim()) { + wx.showToast({ title: '请填写备注', icon: 'none' }); + return; + } + if (applyFee > 0) { + await this.startPayProcess(); + } else { + await this.doFreeApply(); + } + }, + + // 支付流程 + async startPayProcess() { + this.setData({ payLoading: true }); + try { + const res = await request({ + url: '/yonghu/khzf', + method: 'POST', + data: { + tag_id: this.data.selectedTag.id, + game_nick: this.data.applyGameNick, + remark: this.data.applyRemark, + reapply: this.data.isReapply, + jilu_id: this.data.applyJiluId, + shenheguan_id: this.data.selectedKaoheguanId, // 新增 + } + }); + if (res.data.code !== 200) throw new Error(res.data.message || '下单失败'); + const payParams = res.data.payParams; + const dingdanid = res.data.dingdanid; + wx.requestPayment({ + timeStamp: payParams.timeStamp, + nonceStr: payParams.nonceStr, + package: payParams.package, + signType: payParams.signType || 'MD5', + paySign: payParams.paySign, + success: async () => { + await this.pollPayStatus(dingdanid); + }, + fail: () => { + wx.showToast({ title: '支付取消或失败', icon: 'none' }); + request({ url: '/yonghu/khzfsb', method: 'POST', data: { dingdanid } }).catch(()=>{}); + } + }); + } catch (e) { + wx.showToast({ title: e.message || '支付异常', icon: 'none' }); + } finally { + this.setData({ payLoading: false }); + } + }, + + // 轮询支付结果 + async pollPayStatus(dingdanid) { + for (let i = 0; i < 10; i++) { + try { + const res = await request({ url: '/yonghu/khzffc', method: 'POST', data: { dingdanid } }); + if (res.data.code === 200) { + wx.showToast({ title: '申请成功', icon: 'success' }); + this.closeApplyModal(); + this.fetchAllTags(); + this.setData({ recordList: [], recordPage: 1 }); + this.fetchMyRecords(true); + return; + } + } catch (e) {} + await new Promise(r => setTimeout(r, 2000)); + } + wx.showToast({ title: '支付确认超时', icon: 'none' }); + }, + + // 免费申请 + async doFreeApply() { + try { + const res = await request({ + url: '/dengji/dssqkh', + method: 'POST', + data: { + tag_id: this.data.selectedTag.id, + game_nick: this.data.applyGameNick, + remark: this.data.applyRemark, + reapply: this.data.isReapply, + jilu_id: this.data.applyJiluId, + shenheguan_id: this.data.selectedKaoheguanId, // 新增 + } + }); + if (res.data.code === 0) { + wx.showToast({ title: '申请成功', icon: 'success' }); + this.closeApplyModal(); + this.fetchAllTags(); + this.setData({ recordList: [], recordPage: 1 }); + this.fetchMyRecords(true); + } else { + wx.showToast({ title: res.data.msg || '申请失败', icon: 'none' }); + } + } catch (e) { + wx.showToast({ title: '网络错误', icon: 'none' }); + } + }, + + // 联系考核官(私聊) + contactKaoheguan(e) { + const item = e.currentTarget.dataset.item; + if (!item) return; + if (!item.shenheguan_id) { + wx.showToast({ title: '暂无考核官信息', icon: 'none' }); + return; + } + const uid = wx.getStorageSync('uid'); + if (!uid) { + wx.showToast({ title: '用户信息缺失', icon: 'none' }); + return; + } + if (app.globalData.currentRole !== 'dashou') { + app.globalData.currentRole = 'dashou'; + wx.setStorageSync('currentRole', 'dashou'); + } + if (app.connectForCurrentRole) { + app.connectForCurrentRole(); + } else if (app.ensureConnection) { + app.ensureConnection(); + } + const ossImageUrl = this.data.ossImageUrl || app.globalData.ossImageUrl || ''; + let fullAvatar = item.shenheguan_avatar || ''; + if (fullAvatar && !fullAvatar.startsWith('http')) { + fullAvatar = ossImageUrl + fullAvatar; + } + if (!fullAvatar) { + fullAvatar = ossImageUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); + } + const param = { + toUserId: 'Kh' + item.shenheguan_id, + toName: '考核官' + item.shenheguan_id, + toAvatar: fullAvatar + }; + wx.navigateTo({ + url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)), + fail: (err) => { + wx.showToast({ title: '打开聊天失败', icon: 'none' }); + } + }); + }, + + showTagDetail(e) { + const tag = e.currentTarget.dataset.tag; + const feeStr = this.formatFeeList(tag.fee_list); + wx.showModal({ + title: tag.name, + content: `规则:${tag.rule || '暂无'}\n${tag.jinpai ? '【可同时开启金牌】' : ''}\n费用:${feeStr}`, + showCancel: false, + confirmText: '知道了' + }); + }, + + formatFeeList(feeList) { + if (!feeList || feeList.length === 0) return '暂无'; + let str = feeList.map(f => `第${f.cishu}次:¥${f.feiyong}`).join(';'); + const last = feeList[feeList.length - 1]; + str += `;第${last.cishu}次及以上:¥${last.feiyong}`; + return str; + }, }); \ No newline at end of file diff --git a/pages/kaohe_jinpai/kaohe_jinpai.json b/pages/assess-gold/assess-gold.json similarity index 100% rename from pages/kaohe_jinpai/kaohe_jinpai.json rename to pages/assess-gold/assess-gold.json diff --git a/pages/kaohe_jinpai/kaohe_jinpai.wxml b/pages/assess-gold/assess-gold.wxml similarity index 97% rename from pages/kaohe_jinpai/kaohe_jinpai.wxml rename to pages/assess-gold/assess-gold.wxml index 6d89494..626ebe9 100644 --- a/pages/kaohe_jinpai/kaohe_jinpai.wxml +++ b/pages/assess-gold/assess-gold.wxml @@ -1,135 +1,135 @@ - - - - - 考核标签 - 我的考核 - - - - - - - {{item.mingcheng}} - - - - 金牌 - - - {{item.cishu}}次 ¥{{item.feiyong}} - ≥{{item.fee_list.length}}次 ¥{{item.fee_list[item.fee_list.length-1].feiyong}} - - 申请考核 - 已拥有 - - - - - - - - - 进行中/未通过 - 已通过 - - - - - {{item.chenghao_name}} - {{item.statusText}} - - - 板块:{{item.bankuai_name}} - 考核官:{{item.shenheguan_id || '待分配'}} - - 联系考核官 - - 游戏ID:{{item.dashou_youxi_id}} - 备注:{{item.dashou_beizhu}} - 第{{item.cishu}}次考核 · 共缴 ¥{{item.total_fee}} - - - - 本次考核费用:¥{{item.current_fee}} - 预计下次费用:¥{{item.next_fee}} - - - 上次拒绝原因:{{item.last_fail_reason}} - - - 再次考核 - - 加载中... - —— 没有更多了 —— - - - - - - - 申请考核 - {{selectedTag.name}} - - 游戏昵称 - - - - 备注 - - {{countdown}}秒后可确认 - - 取消 - 确认拒绝 - - - - - - - - 确认转移考核 - 转移后,您将无法继续考核此订单,可在考核中心重新接待。 - {{countdown}}秒后可确认 - - 取消 - 确认转移 - - - - + + + + + + + + + + + UID {{item.shenqingren_id}} + {{item.create_time}} + + 联系 + + + + + + 板块 + {{item.bankuai_mingcheng}} + + + 标签 + + (开启金牌) + + + 规则 + {{item.guize_neirong}} + + + + 打手游戏昵称 + {{item.dashou_youxi_id}} + + + 备注 + {{item.dashou_beizhu}} + + + 次数 + {{item.cishu}} + + + 待收考核费 + ¥{{item.daishou_fei}} + + + + + + 上次拒绝原因: + {{item.last_fail_reason}} + + + + + 我的游戏昵称 + + 保存 + + + + + 合格 + 不合格 + 转移 + + + + 加载中... + —— 已加载全部 —— + 暂无待考核记录 + + + + + + + + 确认通过考核 + 通过后,该用户将获得对应标签,请认真审核后操作。 + {{countdown}}秒后可确认 + + 取消 + 确认通过 + + + + + + + + 拒绝通过 + + {{countdown}}秒后可确认 + + 取消 + 确认拒绝 + + + + + + + + 确认转移考核 + 转移后,您将无法继续考核此订单,可在考核中心重新接待。 + {{countdown}}秒后可确认 + + 取消 + 确认转移 + + + + \ No newline at end of file diff --git a/pages/kaohe_dafen/kaohe_dafen.wxss b/pages/assess-score/assess-score.wxss similarity index 100% rename from pages/kaohe_dafen/kaohe_dafen.wxss rename to pages/assess-score/assess-score.wxss diff --git a/pages/kaoheguan/kaoheguan.js b/pages/assessor/assessor.js similarity index 91% rename from pages/kaoheguan/kaoheguan.js rename to pages/assessor/assessor.js index 689ca22..a62d4ed 100644 --- a/pages/kaoheguan/kaoheguan.js +++ b/pages/assessor/assessor.js @@ -1,218 +1,218 @@ -// pages/kaoheguan/kaoheguan.js -// 只新增了两个字段的接收,其余所有代码未变 -import request from '../../utils/request.js'; -import { - isRoleStatusActive, - isCenterPageActive, - syncRoleStatuses, - ensureRoleOnCenterPage, -} from '../../utils/role-tab-bar.js'; -const app = getApp(); - -Page({ - data: { - isKaoheguan: false, - isLoading: false, - inviteCode: '', - statusText: '用户尚未注册或账号已被封禁', - uid: '', - avatarUrl: '', - icons: { - refresh: '', - tixian: '', - daofen: '', - jilu: '', - zhongxin: '', - bgImage: '' - }, - kaoheData: { - shenheZongshu: 0, - tongguoZongshu: 0, - yue: '0.00', - zonge: '0.00', - shenheZhuangtai: 0, - bankuaiList: [], - isRenzheng: false, // 🆕 是否认证 - pendingShenheCount: 0 // 🆕 审核中数量 - }, - lastRefreshTime: 0, - canRefresh: true, - planetPaused: { - top: false, - bottom: false, - left: false, - right: false - } - }, - - _planetTimers: {}, - - onLoad() { - wx.redirectTo({ url: '/pages/dashouduan/dashouduan' }); - return; - const ossUrl = app.globalData.ossImageUrl || ''; - const iconBase = 'beijing/kaohe/'; - this.setData({ - 'icons.refresh': ossUrl + iconBase + 'shuaxin.png', - 'icons.tixian': ossUrl + iconBase + 'tixian.png', - 'icons.daofen': ossUrl + iconBase + 'daofen.png', - 'icons.jilu': ossUrl + iconBase + 'jilu.png', - 'icons.zhongxin': ossUrl + iconBase + 'zhongxin.png', - 'icons.bgImage': ossUrl + iconBase + 'top_bg.jpg' - }); - - const kaoheguanstatus = wx.getStorageSync('kaoheguanstatus'); - if (isRoleStatusActive(kaoheguanstatus)) { - this.loadUserInfo(); - this.setData({ isKaoheguan: true }); - this.getKaoheguanInfo(); - ensureRoleOnCenterPage(this, 'kaoheguan'); - } else { - this.setData({ isKaoheguan: false }); - } - }, - - onReady() { - if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) { - ensureRoleOnCenterPage(this, 'kaoheguan'); - } - }, - - onShow() { - if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) { - if (!this.data.isKaoheguan) this.setData({ isKaoheguan: true }); - ensureRoleOnCenterPage(this, 'kaoheguan'); - this.refreshKaoheInfo(); - } - }, - - loadUserInfo() { - const uid = wx.getStorageSync('uid') || ''; - const touxiang = wx.getStorageSync('touxiang') || ''; - const ossUrl = app.globalData.ossImageUrl || ''; - const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); - let avatarUrl = defaultAvatar; - if (touxiang) { - avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang); - } - this.setData({ uid, avatarUrl }); - }, - - async getKaoheguanInfo() { - this.setData({ isLoading: true }); - try { - const res = await request({ url: '/dengji/khgsx', method: 'POST' }); - if (res && res.data.code === 200) { - const data = res.data.data; - if (data.zhuangtai === 0 || data.zhuangtai === 2) { - wx.setStorageSync('kaoheguanstatus', 0); - this.setData({ isKaoheguan: false, isLoading: false, statusText: '用户尚未注册或账号已被封禁' }); - return; - } - wx.setStorageSync('kaoheguanstatus', 1); - this.setData({ - isKaoheguan: true, - isLoading: false, - kaoheData: { - shenheZongshu: data.shenhe_zongshu || 0, - tongguoZongshu: data.tongguo_zongshu || 0, - yue: data.yue || '0.00', - zonge: data.zonge || '0.00', - shenheZhuangtai: data.shenhe_zhuangtai || 0, - bankuaiList: data.bankuai_list || [], - isRenzheng: data.is_renzheng || false, // 🆕 - pendingShenheCount: data.pending_shenhe_count || 0 // 🆕 - } - }); - ensureRoleOnCenterPage(this, 'kaoheguan'); - } else { - wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' }); - this.setData({ isLoading: false }); - } - } catch (error) { - console.error('获取考核官信息失败:', error); - wx.showToast({ title: '网络错误', icon: 'none' }); - this.setData({ isLoading: false }); - } - }, - - onInviteCodeInput(e) { - this.setData({ inviteCode: e.detail.value.trim() }); - }, - - async onRegister() { - const { inviteCode } = this.data; - if (!inviteCode) { - wx.showToast({ title: '请输入邀请码', icon: 'none', duration: 2000 }); - return; - } - if (inviteCode.length > 100) { - wx.showToast({ title: '邀请码不能超过100位', icon: 'none', duration: 2000 }); - return; - } - this.setData({ isLoading: true }); - try { - const res = await request({ - url: '/dengji/khgzc', - method: 'POST', - data: { inviteCode: inviteCode } - }); - if (res && res.data.code === 200) { - const data = res.data.data || {}; - syncRoleStatuses(data); - if (!Object.prototype.hasOwnProperty.call(data, 'kaoheguanstatus')) { - wx.setStorageSync('kaoheguanstatus', 1); - } - wx.showToast({ title: '注册成功', icon: 'success', duration: 2000 }); - this.loadUserInfo(); - await this.getKaoheguanInfo(); - ensureRoleOnCenterPage(this, 'kaoheguan'); - } else { - wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none', duration: 2000 }); - this.setData({ isLoading: false }); - } - } catch (error) { - console.error('注册失败:', error); - wx.showToast({ title: '网络错误', icon: 'none' }); - this.setData({ isLoading: false }); - } - }, - - refreshKaoheInfo() { - const now = Date.now(); - const lastTime = this.data.lastRefreshTime; - const canRefresh = this.data.canRefresh; - if (!canRefresh || (now - lastTime < 3000)) return; - this.setData({ lastRefreshTime: now, canRefresh: false }); - this.getKaoheguanInfo(); - setTimeout(() => this.setData({ canRefresh: true }), 3000); - }, - - goToWithdraw() { - const yue = this.data.kaoheData.yue || 0; - wx.navigateTo({ - url: `/pages/tixian/tixian?amount=${yue}&from=kaoheguan` - }); - }, - goToDafen() { wx.navigateTo({ url: '/pages/kaohe_dafen/kaohe_dafen' }); }, - goToJilu() { wx.navigateTo({ url: '/pages/kaohe_jilu/kaohe_jilu' }); }, - goToZhongxin() { wx.navigateTo({ url: '/pages/kaohe_zhongxin/kaohe_zhongxin' }); }, - - onPlanetTouch(e) { - const id = e.currentTarget.dataset.id; - if (this._planetTimers[id]) { - clearTimeout(this._planetTimers[id]); - this._planetTimers[id] = null; - } - const paused = `planetPaused.${id}`; - this.setData({ [paused]: true }); - }, - - onPlanetLeave(e) { - const id = e.currentTarget.dataset.id; - this._planetTimers[id] = setTimeout(() => { - const paused = `planetPaused.${id}`; - this.setData({ [paused]: false }); - }, 5000); - } +// pages/assessor/assessor.js +// 只新增了两个字段的接收,其余所有代码未变 +import request from '../../utils/request.js'; +import { + isRoleStatusActive, + isCenterPageActive, + syncRoleStatuses, + ensureRoleOnCenterPage, +} from '../../utils/role-tab-bar.js'; +const app = getApp(); + +Page({ + data: { + isKaoheguan: false, + isLoading: false, + inviteCode: '', + statusText: '用户尚未注册或账号已被封禁', + uid: '', + avatarUrl: '', + icons: { + refresh: '', + tixian: '', + daofen: '', + jilu: '', + zhongxin: '', + bgImage: '' + }, + kaoheData: { + shenheZongshu: 0, + tongguoZongshu: 0, + yue: '0.00', + zonge: '0.00', + shenheZhuangtai: 0, + bankuaiList: [], + isRenzheng: false, // 🆕 是否认证 + pendingShenheCount: 0 // 🆕 审核中数量 + }, + lastRefreshTime: 0, + canRefresh: true, + planetPaused: { + top: false, + bottom: false, + left: false, + right: false + } + }, + + _planetTimers: {}, + + onLoad() { + wx.redirectTo({ url: '/pages/fighter/fighter' }); + return; + const ossUrl = app.globalData.ossImageUrl || ''; + const iconBase = 'beijing/kaohe/'; + this.setData({ + 'icons.refresh': ossUrl + iconBase + 'shuaxin.png', + 'icons.tixian': ossUrl + iconBase + 'tixian.png', + 'icons.daofen': ossUrl + iconBase + 'daofen.png', + 'icons.jilu': ossUrl + iconBase + 'jilu.png', + 'icons.zhongxin': ossUrl + iconBase + 'zhongxin.png', + 'icons.bgImage': ossUrl + iconBase + 'top_bg.jpg' + }); + + const kaoheguanstatus = wx.getStorageSync('kaoheguanstatus'); + if (isRoleStatusActive(kaoheguanstatus)) { + this.loadUserInfo(); + this.setData({ isKaoheguan: true }); + this.getKaoheguanInfo(); + ensureRoleOnCenterPage(this, 'kaoheguan'); + } else { + this.setData({ isKaoheguan: false }); + } + }, + + onReady() { + if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) { + ensureRoleOnCenterPage(this, 'kaoheguan'); + } + }, + + onShow() { + if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) { + if (!this.data.isKaoheguan) this.setData({ isKaoheguan: true }); + ensureRoleOnCenterPage(this, 'kaoheguan'); + this.refreshKaoheInfo(); + } + }, + + loadUserInfo() { + const uid = wx.getStorageSync('uid') || ''; + const touxiang = wx.getStorageSync('touxiang') || ''; + const ossUrl = app.globalData.ossImageUrl || ''; + const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); + let avatarUrl = defaultAvatar; + if (touxiang) { + avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang); + } + this.setData({ uid, avatarUrl }); + }, + + async getKaoheguanInfo() { + this.setData({ isLoading: true }); + try { + const res = await request({ url: '/dengji/khgsx', method: 'POST' }); + if (res && res.data.code === 200) { + const data = res.data.data; + if (data.zhuangtai === 0 || data.zhuangtai === 2) { + wx.setStorageSync('kaoheguanstatus', 0); + this.setData({ isKaoheguan: false, isLoading: false, statusText: '用户尚未注册或账号已被封禁' }); + return; + } + wx.setStorageSync('kaoheguanstatus', 1); + this.setData({ + isKaoheguan: true, + isLoading: false, + kaoheData: { + shenheZongshu: data.shenhe_zongshu || 0, + tongguoZongshu: data.tongguo_zongshu || 0, + yue: data.yue || '0.00', + zonge: data.zonge || '0.00', + shenheZhuangtai: data.shenhe_zhuangtai || 0, + bankuaiList: data.bankuai_list || [], + isRenzheng: data.is_renzheng || false, // 🆕 + pendingShenheCount: data.pending_shenhe_count || 0 // 🆕 + } + }); + ensureRoleOnCenterPage(this, 'kaoheguan'); + } else { + wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' }); + this.setData({ isLoading: false }); + } + } catch (error) { + console.error('获取考核官信息失败:', error); + wx.showToast({ title: '网络错误', icon: 'none' }); + this.setData({ isLoading: false }); + } + }, + + onInviteCodeInput(e) { + this.setData({ inviteCode: e.detail.value.trim() }); + }, + + async onRegister() { + const { inviteCode } = this.data; + if (!inviteCode) { + wx.showToast({ title: '请输入邀请码', icon: 'none', duration: 2000 }); + return; + } + if (inviteCode.length > 100) { + wx.showToast({ title: '邀请码不能超过100位', icon: 'none', duration: 2000 }); + return; + } + this.setData({ isLoading: true }); + try { + const res = await request({ + url: '/dengji/khgzc', + method: 'POST', + data: { inviteCode: inviteCode } + }); + if (res && res.data.code === 200) { + const data = res.data.data || {}; + syncRoleStatuses(data); + if (!Object.prototype.hasOwnProperty.call(data, 'kaoheguanstatus')) { + wx.setStorageSync('kaoheguanstatus', 1); + } + wx.showToast({ title: '注册成功', icon: 'success', duration: 2000 }); + this.loadUserInfo(); + await this.getKaoheguanInfo(); + ensureRoleOnCenterPage(this, 'kaoheguan'); + } else { + wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none', duration: 2000 }); + this.setData({ isLoading: false }); + } + } catch (error) { + console.error('注册失败:', error); + wx.showToast({ title: '网络错误', icon: 'none' }); + this.setData({ isLoading: false }); + } + }, + + refreshKaoheInfo() { + const now = Date.now(); + const lastTime = this.data.lastRefreshTime; + const canRefresh = this.data.canRefresh; + if (!canRefresh || (now - lastTime < 3000)) return; + this.setData({ lastRefreshTime: now, canRefresh: false }); + this.getKaoheguanInfo(); + setTimeout(() => this.setData({ canRefresh: true }), 3000); + }, + + goToWithdraw() { + const yue = this.data.kaoheData.yue || 0; + wx.navigateTo({ + url: `/pages/withdraw/withdraw?amount=${yue}&from=kaoheguan` + }); + }, + goToDafen() { wx.navigateTo({ url: '/pages/assess-score/assess-score' }); }, + goToJilu() { wx.navigateTo({ url: '/pages/assess-log/assess-log' }); }, + goToZhongxin() { wx.navigateTo({ url: '/pages/assess-center/assess-center' }); }, + + onPlanetTouch(e) { + const id = e.currentTarget.dataset.id; + if (this._planetTimers[id]) { + clearTimeout(this._planetTimers[id]); + this._planetTimers[id] = null; + } + const paused = `planetPaused.${id}`; + this.setData({ [paused]: true }); + }, + + onPlanetLeave(e) { + const id = e.currentTarget.dataset.id; + this._planetTimers[id] = setTimeout(() => { + const paused = `planetPaused.${id}`; + this.setData({ [paused]: false }); + }, 5000); + } }); \ No newline at end of file diff --git a/pages/kaoheguan/kaoheguan.json b/pages/assessor/assessor.json similarity index 100% rename from pages/kaoheguan/kaoheguan.json rename to pages/assessor/assessor.json diff --git a/pages/kaoheguan/kaoheguan.wxml b/pages/assessor/assessor.wxml similarity index 97% rename from pages/kaoheguan/kaoheguan.wxml rename to pages/assessor/assessor.wxml index 0c1d239..0e6853e 100644 --- a/pages/kaoheguan/kaoheguan.wxml +++ b/pages/assessor/assessor.wxml @@ -1,128 +1,128 @@ - - - - - - - - - - - - - - 考核官 - {{statusText}} - - - 即刻入驻 - - - - - - - - - - - 考核官 - - {{uid}} - - - - - {{kaoheData.isRenzheng ? '已认证' : '未认证'}} - - - - - - - - - - - {{item.mingcheng}} - - - - - - - - {{kaoheData.yue}}元 - 可提现余额 - - - - - - - - {{kaoheData.shenheZongshu}} - 审核总数 - - - - {{kaoheData.tongguoZongshu}} - 通过总数 - - - - {{kaoheData.zonge}}元 - 累计赚取 - - - - - - - - - - 考核中心 - - - - - - 考核打分 - - {{kaoheData.pendingShenheCount}} - - - - - - 考核记录 - - - - - - 立即提现 - - - - - - - - - - 加载中... - - - - + + + + + + + + + + + + + + 考核官 + {{statusText}} + + + 即刻入驻 + + + + + + + + + + + 考核官 + + {{uid}} + + + + + {{kaoheData.isRenzheng ? '已认证' : '未认证'}} + + + + + + + + + + + {{item.mingcheng}} + + + + + + + + {{kaoheData.yue}}元 + 可提现余额 + + + + + + + + {{kaoheData.shenheZongshu}} + 审核总数 + + + + {{kaoheData.tongguoZongshu}} + 通过总数 + + + + {{kaoheData.zonge}}元 + 累计赚取 + + + + + + + + + + 考核中心 + + + + + + 考核打分 + + {{kaoheData.pendingShenheCount}} + + + + + + 考核记录 + + + + + + 立即提现 + + + + + + + + + + 加载中... + + + + \ No newline at end of file diff --git a/pages/kaoheguan/kaoheguan.wxss b/pages/assessor/assessor.wxss similarity index 95% rename from pages/kaoheguan/kaoheguan.wxss rename to pages/assessor/assessor.wxss index b1f152c..b2ccc62 100644 --- a/pages/kaoheguan/kaoheguan.wxss +++ b/pages/assessor/assessor.wxss @@ -1,512 +1,512 @@ -/* pages/kaoheguan/kaoheguan.wxss — 完整版:适度背景 + 整体下移 */ - -page { - background: #0a0c14; - color: #e0e6f0; - font-family: 'SF Pro Display', 'PingFang SC', system-ui; - height: 100vh; - overflow: hidden; - } - - /* 根容器:让出自定义导航栏与底部 TabBar 空间 */ - .universe-root { - position: relative; - width: 100%; - height: 100vh; - display: flex; - flex-direction: column; - overflow-y: auto; - overflow-x: hidden; - padding-top: calc(88rpx + env(safe-area-inset-top)); - padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); - box-sizing: border-box; - z-index: 1; - } - - /* ========== 全屏背景图(适度弱化) ========== */ - .full-bg { - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - z-index: 0; - opacity: 1; /* 从0.15调整到0.3,若隐若现但不抢夺内容 */ - pointer-events: none; - object-fit: cover; - filter: blur(1px); /* 轻微模糊,增加梦幻感 */ - } - - /* ========== 动态星空(Canvas) ========== */ - .starfield-canvas { - position: fixed; - top: 0; left: 0; - width: 100vw; height: 100vh; - pointer-events: none; - z-index: 0; - opacity: 0.35; - } - - /* ========== 极光飘带 ========== */ - .aurora-ribbon { - position: fixed; - top: -10%; - left: -30%; - width: 160%; - height: 60%; - background: radial-gradient(ellipse at 50% 50%, rgba(100, 140, 255, 0.12) 0%, transparent 70%); - pointer-events: none; - z-index: 0; - animation: drift 20s ease-in-out infinite alternate; - } - - @keyframes drift { - 0% { transform: translate(0, 0) rotate(0deg); } - 100% { transform: translate(10%, 5%) rotate(3deg); } - } - - /* ========== 舒缓流星 ========== */ - /* 流星1:右上 → 左下,缓慢,间隔10秒 */ - .universe-root::before { - content: ""; - position: fixed; - top: 5%; - right: -2%; - width: 2rpx; - height: 85rpx; - background: linear-gradient(to bottom, rgba(255, 255, 255, 0.6), transparent); - transform: rotate(-35deg); - animation: meteor1 10s 0s linear infinite; - pointer-events: none; - z-index: 1; - opacity: 0; - } - - /* 流星2:稍有不同的角度与延迟 */ - .universe-root::after { - content: ""; - position: fixed; - top: 10%; - right: -5%; - width: 2rpx; - height: 70rpx; - background: linear-gradient(to bottom, rgba(200, 210, 255, 0.55), transparent); - transform: rotate(-28deg); - animation: meteor2 11s 4s linear infinite; - pointer-events: none; - z-index: 1; - opacity: 0; - } - - @keyframes meteor1 { - 0% { - opacity: 0; - transform: translate(0, 0) rotate(-35deg); - } - 10% { - opacity: 0.5; - } - 28% { - opacity: 0; - transform: translate(-500rpx, 450rpx) rotate(-35deg); - } - 100% { - opacity: 0; - transform: translate(-500rpx, 450rpx) rotate(-35deg); - } - } - - @keyframes meteor2 { - 0% { - opacity: 0; - transform: translate(0, 0) rotate(-28deg); - } - 8% { - opacity: 0.45; - } - 25% { - opacity: 0; - transform: translate(-480rpx, 420rpx) rotate(-28deg); - } - 100% { - opacity: 0; - transform: translate(-480rpx, 420rpx) rotate(-28deg); - } - } - - /* ========== 未注册状态 ========== */ - .unreg-floating { - position: relative; - z-index: 10; - flex: 1; - display: flex; - align-items: center; - justify-content: center; - } - .unreg-core { - width: 80%; - max-width: 640rpx; - background: rgba(255,255,255,0.04); - backdrop-filter: blur(30px); - border-radius: 50rpx; - padding: 80rpx 50rpx 60rpx; - border: 1rpx solid rgba(255,255,255,0.1); - display: flex; - flex-direction: column; - align-items: center; - } - .unreg-icon { width: 100rpx; height: 100rpx; margin-bottom: 20rpx; } - .unreg-title { font-size: 42rpx; font-weight: 700; color: #fff; margin-bottom: 12rpx; } - .unreg-desc { font-size: 28rpx; color: #8590b0; margin-bottom: 50rpx; text-align: center; } - .unreg-input { width: 100%; height: 90rpx; background: rgba(255,255,255,0.08); border-radius: 30rpx; padding: 0 30rpx; color: #fff; font-size: 30rpx; box-sizing: border-box; margin-bottom: 30rpx; } - .unreg-placeholder { color: rgba(255,255,255,0.3); } - .unreg-btn { width: 100%; height: 90rpx; background: linear-gradient(135deg, #4f6ef6, #8b5cf6); border-radius: 45rpx; display: flex; align-items: center; justify-content: center; transition: transform 0.2s; } - .unreg-btn:active { transform: scale(0.98); } - .unreg-btn-text { font-size: 34rpx; font-weight: 600; color: #fff; } - - /* ========== 已注册状态(整体下移) ========== */ - .orbit-zone { - position: relative; - z-index: 10; - flex: 1; - padding: 80rpx 30rpx 0; /* 顶部从40rpx增加到60rpx,整体下移 */ - display: flex; - flex-direction: column; - } - - /* 身份条 */ - .top-identity { - display: flex; - align-items: center; - margin-bottom: 40rpx; - position: relative; - z-index: 2; - } - .identity-avatar { - width: 90rpx; height: 90rpx; border-radius: 50%; - border: 2rpx solid rgba(255,255,255,0.2); - margin-right: 20rpx; - } - .identity-info { flex: 1; } - .identity-name { font-size: 36rpx; font-weight: 700; color: #fff; } - .identity-uid { - display: flex; align-items: center; margin-top: 8rpx; - } - .uid-txt { font-size: 24rpx; color: #9098b0; font-family: monospace; } - .status-indicator { - width: 12rpx; height: 12rpx; border-radius: 50%; - background: #4ade80; margin-left: 12rpx; - transition: background 0.3s; - } - .status-indicator.active { background: #fbbf24; } - .refresh-touch { - width: 60rpx; height: 60rpx; - background: rgba(255,255,255,0.06); - border-radius: 20rpx; - display: flex; align-items: center; justify-content: center; - transition: background 0.2s; - } - .refresh-touch:active { background: rgba(255,255,255,0.15); } - .refresh-icon { width: 36rpx; height: 36rpx; } - - /* 板块标签云 */ - .plate-cloud { margin-bottom: 30rpx; } - .plate-cloud-scroll { white-space: nowrap; } - .plate-chip { - display: inline-block; - padding: 8rpx 24rpx; - border-radius: 30rpx; - background: rgba(79,110,246,0.1); - color: #a5b4fc; - font-size: 26rpx; - margin-right: 16rpx; - border: 1rpx solid rgba(79,110,246,0.3); - box-shadow: 0 0 12rpx rgba(79,110,246,0.1); - transition: all 0.3s; - } - .plate-chip:active { transform: scale(0.95); background: rgba(79,110,246,0.2); } - - /* 中央余额星球 */ - .balance-planet { - position: relative; - width: 280rpx; - height: 280rpx; - margin: 20rpx auto 30rpx; - display: flex; - align-items: center; - justify-content: center; - } - .planet-ring { - position: absolute; - width: 280rpx; - height: 280rpx; - border-radius: 50%; - border: 2rpx solid rgba(79,110,246,0.4); - animation: ringRotate 12s linear infinite; - } - @keyframes ringRotate { to { transform: rotate(360deg); } } - .planet-body { - width: 210rpx; - height: 210rpx; - border-radius: 50%; - background: radial-gradient(circle at 30% 30%, rgba(79,110,246,0.3), rgba(15,15,30,0.8)); - backdrop-filter: blur(10px); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - border: 1rpx solid rgba(255,255,255,0.1); - transition: transform 0.3s; - } - .balance-planet:active .planet-body { transform: scale(0.95); } - .planet-num { - font-size: 52rpx; - font-weight: 900; - color: #fff; - text-shadow: 0 0 30rpx rgba(79,110,246,0.8); - animation: numGlow 2s ease-in-out infinite alternate; - } - @keyframes numGlow { - from { text-shadow: 0 0 20rpx rgba(79,110,246,0.6); } - to { text-shadow: 0 0 40rpx rgba(79,110,246,1); } - } - .planet-label { - font-size: 24rpx; - color: #a5b4fc; - margin-top: 8rpx; - } - .planet-glow { - position: absolute; - width: 300rpx; - height: 300rpx; - border-radius: 50%; - background: radial-gradient(circle, rgba(79,110,246,0.2), transparent 70%); - animation: planetPulse 4s ease-in-out infinite; - pointer-events: none; - } - @keyframes planetPulse { - 0%, 100% { opacity: 0.3; transform: scale(1); } - 50% { opacity: 0.8; transform: scale(1.08); } - } - - /* 流星数据条 */ - .meteor-stats { - display: flex; - justify-content: space-around; - align-items: center; - margin-bottom: 30rpx; - padding: 20rpx 0; - position: relative; - } - .meteor-item { - display: flex; - flex-direction: column; - align-items: center; - flex: 1; - } - .meteor-num { - font-size: 36rpx; - font-weight: 800; - background: linear-gradient(135deg, #a5b4fc, #4f6ef6); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - transition: all 0.3s; - } - .meteor-item:active .meteor-num { transform: scale(1.1); } - .meteor-label { - font-size: 22rpx; - color: #64748b; - margin-top: 10rpx; - } - .meteor-divider { - width: 2rpx; - height: 40rpx; - background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.15), transparent); - } - - /* ========== 十字星阵功能区 ========== */ - .star-cross { - position: relative; - width: 520rpx; - height: 520rpx; - margin: 40rpx auto 50rpx; - } - - /* 按钮公共样式 */ - .cross-item { - position: absolute; - width: 150rpx; - height: 150rpx; - background: radial-gradient(circle at 30% 30%, rgba(79,110,246,0.25), rgba(0,0,0,0.25)); - border-radius: 50%; - border: 1rpx solid rgba(255,255,255,0.12); - backdrop-filter: blur(10px); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - transition: transform 0.2s, box-shadow 0.2s; - z-index: 5; - overflow: visible; - } - - /* 行星光环 */ - .orbit-ring { - position: absolute; - top: -8rpx; - left: -8rpx; - right: -8rpx; - bottom: -8rpx; - border-radius: 50%; - border: 2rpx solid rgba(79,110,246,0.5); - border-top-color: transparent; - border-bottom-color: transparent; - animation: spinRing 4s linear infinite; - pointer-events: none; - } - .pause-spin .orbit-ring { - animation-play-state: paused; - } - - @keyframes spinRing { - to { transform: rotate(360deg); } - } - - .cross-item:active { - transform: scale(0.95); - box-shadow: 0 0 30rpx rgba(79,110,246,0.6); - } - - /* 图标强化 */ - .cross-icon { - width: 58rpx; - height: 58rpx; - margin-bottom: 8rpx; - filter: drop-shadow(0 0 14rpx rgba(79,110,246,0.9)) - drop-shadow(0 0 28rpx rgba(99,102,241,0.7)); - animation: iconFloat 3s ease-in-out infinite; - z-index: 2; - } - - @keyframes iconFloat { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-3rpx); } - } - - .cross-text { - font-size: 24rpx; - color: #e0e6f0; - font-weight: 600; - z-index: 2; - } - - /* 上 */ - .cross-top { top: 0; left: 50%; transform: translateX(-50%); } - /* 下 */ - .cross-bottom { bottom: 0; left: 50%; transform: translateX(-50%); } - /* 左 */ - .cross-left { left: 0; top: 50%; transform: translateY(-50%); } - /* 右 */ - .cross-right { right: 0; top: 50%; transform: translateY(-50%); } - - /* 中央五角星(固定,仅呼吸) */ - .pentagram { - position: absolute; - top: 50%; - left: 50%; - width: 0; height: 0; - transform: translate(-50%, -50%); - border-left: 36rpx solid transparent; - border-right: 36rpx solid transparent; - border-bottom: 84rpx solid rgba(79,110,246,0.85); - filter: drop-shadow(0 0 18rpx rgba(79,110,246,0.7)); - animation: star-pulse 2s ease-in-out infinite; - } - .pentagram::before { - content: ""; - position: absolute; - top: 36rpx; - left: -36rpx; - width: 0; height: 0; - border-left: 36rpx solid transparent; - border-right: 36rpx solid transparent; - border-bottom: 84rpx solid rgba(79,110,246,0.85); - transform: rotate(72deg); - } - .pentagram::after { - content: ""; - position: absolute; - top: 36rpx; - left: -36rpx; - width: 0; height: 0; - border-left: 36rpx solid transparent; - border-right: 36rpx solid transparent; - border-bottom: 84rpx solid rgba(79,110,246,0.85); - transform: rotate(-72deg); - } - - @keyframes star-pulse { - 0%, 100% { opacity: 0.8; } - 50% { opacity: 1; } - } - - /* ========== 加载星门 ========== */ - .loading-portal { - position: fixed; top: 0; left: 0; right: 0; bottom: 0; - background: rgba(10,12,20,0.95); - backdrop-filter: blur(15px); - display: flex; flex-direction: column; - align-items: center; justify-content: center; - z-index: 999; - } - .portal-ring { - width: 100rpx; height: 100rpx; - border-radius: 50%; - border: 3rpx solid rgba(79,110,246,0.2); - border-top-color: #4f6ef6; - animation: portalSpin 1s linear infinite; - margin-bottom: 30rpx; - } - @keyframes portalSpin { to { transform: rotate(360deg); } } - .portal-text { font-size: 28rpx; color: #64748b; } - -/* ========== 🆕 以下为新增样式,绝无任何修改 ========== */ - -/* 认证状态标签 */ -.renzheng-tag { - font-size: 22rpx; - padding: 4rpx 12rpx; - border-radius: 20rpx; - margin-top: 8rpx; - display: inline-block; -} -.renzheng-tag.authed { - background: rgba(76, 175, 80, 0.15); - color: #4caf50; - border: 1rpx solid rgba(76, 175, 80, 0.4); -} -.renzheng-tag.unauth { - background: rgba(244, 67, 54, 0.1); - color: #f44336; - border: 1rpx solid rgba(244, 67, 54, 0.4); -} - -/* 红色角标 */ -.badge { - position: absolute; - top: -4rpx; - right: -8rpx; - min-width: 36rpx; - height: 36rpx; - background: #f44336; - color: #fff; - font-size: 22rpx; - font-weight: 600; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - padding: 0 8rpx; - box-shadow: 0 2rpx 8rpx rgba(244, 67, 54, 0.4); - z-index: 10; +/* pages/assessor/assessor.wxss — 完整版:适度背景 + 整体下移 */ + +page { + background: #0a0c14; + color: #e0e6f0; + font-family: 'SF Pro Display', 'PingFang SC', system-ui; + height: 100vh; + overflow: hidden; + } + + /* 根容器:让出自定义导航栏与底部 TabBar 空间 */ + .universe-root { + position: relative; + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + overflow-y: auto; + overflow-x: hidden; + padding-top: calc(88rpx + env(safe-area-inset-top)); + padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); + box-sizing: border-box; + z-index: 1; + } + + /* ========== 全屏背景图(适度弱化) ========== */ + .full-bg { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 0; + opacity: 1; /* 从0.15调整到0.3,若隐若现但不抢夺内容 */ + pointer-events: none; + object-fit: cover; + filter: blur(1px); /* 轻微模糊,增加梦幻感 */ + } + + /* ========== 动态星空(Canvas) ========== */ + .starfield-canvas { + position: fixed; + top: 0; left: 0; + width: 100vw; height: 100vh; + pointer-events: none; + z-index: 0; + opacity: 0.35; + } + + /* ========== 极光飘带 ========== */ + .aurora-ribbon { + position: fixed; + top: -10%; + left: -30%; + width: 160%; + height: 60%; + background: radial-gradient(ellipse at 50% 50%, rgba(100, 140, 255, 0.12) 0%, transparent 70%); + pointer-events: none; + z-index: 0; + animation: drift 20s ease-in-out infinite alternate; + } + + @keyframes drift { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(10%, 5%) rotate(3deg); } + } + + /* ========== 舒缓流星 ========== */ + /* 流星1:右上 → 左下,缓慢,间隔10秒 */ + .universe-root::before { + content: ""; + position: fixed; + top: 5%; + right: -2%; + width: 2rpx; + height: 85rpx; + background: linear-gradient(to bottom, rgba(255, 255, 255, 0.6), transparent); + transform: rotate(-35deg); + animation: meteor1 10s 0s linear infinite; + pointer-events: none; + z-index: 1; + opacity: 0; + } + + /* 流星2:稍有不同的角度与延迟 */ + .universe-root::after { + content: ""; + position: fixed; + top: 10%; + right: -5%; + width: 2rpx; + height: 70rpx; + background: linear-gradient(to bottom, rgba(200, 210, 255, 0.55), transparent); + transform: rotate(-28deg); + animation: meteor2 11s 4s linear infinite; + pointer-events: none; + z-index: 1; + opacity: 0; + } + + @keyframes meteor1 { + 0% { + opacity: 0; + transform: translate(0, 0) rotate(-35deg); + } + 10% { + opacity: 0.5; + } + 28% { + opacity: 0; + transform: translate(-500rpx, 450rpx) rotate(-35deg); + } + 100% { + opacity: 0; + transform: translate(-500rpx, 450rpx) rotate(-35deg); + } + } + + @keyframes meteor2 { + 0% { + opacity: 0; + transform: translate(0, 0) rotate(-28deg); + } + 8% { + opacity: 0.45; + } + 25% { + opacity: 0; + transform: translate(-480rpx, 420rpx) rotate(-28deg); + } + 100% { + opacity: 0; + transform: translate(-480rpx, 420rpx) rotate(-28deg); + } + } + + /* ========== 未注册状态 ========== */ + .unreg-floating { + position: relative; + z-index: 10; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + } + .unreg-core { + width: 80%; + max-width: 640rpx; + background: rgba(255,255,255,0.04); + backdrop-filter: blur(30px); + border-radius: 50rpx; + padding: 80rpx 50rpx 60rpx; + border: 1rpx solid rgba(255,255,255,0.1); + display: flex; + flex-direction: column; + align-items: center; + } + .unreg-icon { width: 100rpx; height: 100rpx; margin-bottom: 20rpx; } + .unreg-title { font-size: 42rpx; font-weight: 700; color: #fff; margin-bottom: 12rpx; } + .unreg-desc { font-size: 28rpx; color: #8590b0; margin-bottom: 50rpx; text-align: center; } + .unreg-input { width: 100%; height: 90rpx; background: rgba(255,255,255,0.08); border-radius: 30rpx; padding: 0 30rpx; color: #fff; font-size: 30rpx; box-sizing: border-box; margin-bottom: 30rpx; } + .unreg-placeholder { color: rgba(255,255,255,0.3); } + .unreg-btn { width: 100%; height: 90rpx; background: linear-gradient(135deg, #4f6ef6, #8b5cf6); border-radius: 45rpx; display: flex; align-items: center; justify-content: center; transition: transform 0.2s; } + .unreg-btn:active { transform: scale(0.98); } + .unreg-btn-text { font-size: 34rpx; font-weight: 600; color: #fff; } + + /* ========== 已注册状态(整体下移) ========== */ + .orbit-zone { + position: relative; + z-index: 10; + flex: 1; + padding: 80rpx 30rpx 0; /* 顶部从40rpx增加到60rpx,整体下移 */ + display: flex; + flex-direction: column; + } + + /* 身份条 */ + .top-identity { + display: flex; + align-items: center; + margin-bottom: 40rpx; + position: relative; + z-index: 2; + } + .identity-avatar { + width: 90rpx; height: 90rpx; border-radius: 50%; + border: 2rpx solid rgba(255,255,255,0.2); + margin-right: 20rpx; + } + .identity-info { flex: 1; } + .identity-name { font-size: 36rpx; font-weight: 700; color: #fff; } + .identity-uid { + display: flex; align-items: center; margin-top: 8rpx; + } + .uid-txt { font-size: 24rpx; color: #9098b0; font-family: monospace; } + .status-indicator { + width: 12rpx; height: 12rpx; border-radius: 50%; + background: #4ade80; margin-left: 12rpx; + transition: background 0.3s; + } + .status-indicator.active { background: #fbbf24; } + .refresh-touch { + width: 60rpx; height: 60rpx; + background: rgba(255,255,255,0.06); + border-radius: 20rpx; + display: flex; align-items: center; justify-content: center; + transition: background 0.2s; + } + .refresh-touch:active { background: rgba(255,255,255,0.15); } + .refresh-icon { width: 36rpx; height: 36rpx; } + + /* 板块标签云 */ + .plate-cloud { margin-bottom: 30rpx; } + .plate-cloud-scroll { white-space: nowrap; } + .plate-chip { + display: inline-block; + padding: 8rpx 24rpx; + border-radius: 30rpx; + background: rgba(79,110,246,0.1); + color: #a5b4fc; + font-size: 26rpx; + margin-right: 16rpx; + border: 1rpx solid rgba(79,110,246,0.3); + box-shadow: 0 0 12rpx rgba(79,110,246,0.1); + transition: all 0.3s; + } + .plate-chip:active { transform: scale(0.95); background: rgba(79,110,246,0.2); } + + /* 中央余额星球 */ + .balance-planet { + position: relative; + width: 280rpx; + height: 280rpx; + margin: 20rpx auto 30rpx; + display: flex; + align-items: center; + justify-content: center; + } + .planet-ring { + position: absolute; + width: 280rpx; + height: 280rpx; + border-radius: 50%; + border: 2rpx solid rgba(79,110,246,0.4); + animation: ringRotate 12s linear infinite; + } + @keyframes ringRotate { to { transform: rotate(360deg); } } + .planet-body { + width: 210rpx; + height: 210rpx; + border-radius: 50%; + background: radial-gradient(circle at 30% 30%, rgba(79,110,246,0.3), rgba(15,15,30,0.8)); + backdrop-filter: blur(10px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + border: 1rpx solid rgba(255,255,255,0.1); + transition: transform 0.3s; + } + .balance-planet:active .planet-body { transform: scale(0.95); } + .planet-num { + font-size: 52rpx; + font-weight: 900; + color: #fff; + text-shadow: 0 0 30rpx rgba(79,110,246,0.8); + animation: numGlow 2s ease-in-out infinite alternate; + } + @keyframes numGlow { + from { text-shadow: 0 0 20rpx rgba(79,110,246,0.6); } + to { text-shadow: 0 0 40rpx rgba(79,110,246,1); } + } + .planet-label { + font-size: 24rpx; + color: #a5b4fc; + margin-top: 8rpx; + } + .planet-glow { + position: absolute; + width: 300rpx; + height: 300rpx; + border-radius: 50%; + background: radial-gradient(circle, rgba(79,110,246,0.2), transparent 70%); + animation: planetPulse 4s ease-in-out infinite; + pointer-events: none; + } + @keyframes planetPulse { + 0%, 100% { opacity: 0.3; transform: scale(1); } + 50% { opacity: 0.8; transform: scale(1.08); } + } + + /* 流星数据条 */ + .meteor-stats { + display: flex; + justify-content: space-around; + align-items: center; + margin-bottom: 30rpx; + padding: 20rpx 0; + position: relative; + } + .meteor-item { + display: flex; + flex-direction: column; + align-items: center; + flex: 1; + } + .meteor-num { + font-size: 36rpx; + font-weight: 800; + background: linear-gradient(135deg, #a5b4fc, #4f6ef6); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + transition: all 0.3s; + } + .meteor-item:active .meteor-num { transform: scale(1.1); } + .meteor-label { + font-size: 22rpx; + color: #64748b; + margin-top: 10rpx; + } + .meteor-divider { + width: 2rpx; + height: 40rpx; + background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.15), transparent); + } + + /* ========== 十字星阵功能区 ========== */ + .star-cross { + position: relative; + width: 520rpx; + height: 520rpx; + margin: 40rpx auto 50rpx; + } + + /* 按钮公共样式 */ + .cross-item { + position: absolute; + width: 150rpx; + height: 150rpx; + background: radial-gradient(circle at 30% 30%, rgba(79,110,246,0.25), rgba(0,0,0,0.25)); + border-radius: 50%; + border: 1rpx solid rgba(255,255,255,0.12); + backdrop-filter: blur(10px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + transition: transform 0.2s, box-shadow 0.2s; + z-index: 5; + overflow: visible; + } + + /* 行星光环 */ + .orbit-ring { + position: absolute; + top: -8rpx; + left: -8rpx; + right: -8rpx; + bottom: -8rpx; + border-radius: 50%; + border: 2rpx solid rgba(79,110,246,0.5); + border-top-color: transparent; + border-bottom-color: transparent; + animation: spinRing 4s linear infinite; + pointer-events: none; + } + .pause-spin .orbit-ring { + animation-play-state: paused; + } + + @keyframes spinRing { + to { transform: rotate(360deg); } + } + + .cross-item:active { + transform: scale(0.95); + box-shadow: 0 0 30rpx rgba(79,110,246,0.6); + } + + /* 图标强化 */ + .cross-icon { + width: 58rpx; + height: 58rpx; + margin-bottom: 8rpx; + filter: drop-shadow(0 0 14rpx rgba(79,110,246,0.9)) + drop-shadow(0 0 28rpx rgba(99,102,241,0.7)); + animation: iconFloat 3s ease-in-out infinite; + z-index: 2; + } + + @keyframes iconFloat { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-3rpx); } + } + + .cross-text { + font-size: 24rpx; + color: #e0e6f0; + font-weight: 600; + z-index: 2; + } + + /* 上 */ + .cross-top { top: 0; left: 50%; transform: translateX(-50%); } + /* 下 */ + .cross-bottom { bottom: 0; left: 50%; transform: translateX(-50%); } + /* 左 */ + .cross-left { left: 0; top: 50%; transform: translateY(-50%); } + /* 右 */ + .cross-right { right: 0; top: 50%; transform: translateY(-50%); } + + /* 中央五角星(固定,仅呼吸) */ + .pentagram { + position: absolute; + top: 50%; + left: 50%; + width: 0; height: 0; + transform: translate(-50%, -50%); + border-left: 36rpx solid transparent; + border-right: 36rpx solid transparent; + border-bottom: 84rpx solid rgba(79,110,246,0.85); + filter: drop-shadow(0 0 18rpx rgba(79,110,246,0.7)); + animation: star-pulse 2s ease-in-out infinite; + } + .pentagram::before { + content: ""; + position: absolute; + top: 36rpx; + left: -36rpx; + width: 0; height: 0; + border-left: 36rpx solid transparent; + border-right: 36rpx solid transparent; + border-bottom: 84rpx solid rgba(79,110,246,0.85); + transform: rotate(72deg); + } + .pentagram::after { + content: ""; + position: absolute; + top: 36rpx; + left: -36rpx; + width: 0; height: 0; + border-left: 36rpx solid transparent; + border-right: 36rpx solid transparent; + border-bottom: 84rpx solid rgba(79,110,246,0.85); + transform: rotate(-72deg); + } + + @keyframes star-pulse { + 0%, 100% { opacity: 0.8; } + 50% { opacity: 1; } + } + + /* ========== 加载星门 ========== */ + .loading-portal { + position: fixed; top: 0; left: 0; right: 0; bottom: 0; + background: rgba(10,12,20,0.95); + backdrop-filter: blur(15px); + display: flex; flex-direction: column; + align-items: center; justify-content: center; + z-index: 999; + } + .portal-ring { + width: 100rpx; height: 100rpx; + border-radius: 50%; + border: 3rpx solid rgba(79,110,246,0.2); + border-top-color: #4f6ef6; + animation: portalSpin 1s linear infinite; + margin-bottom: 30rpx; + } + @keyframes portalSpin { to { transform: rotate(360deg); } } + .portal-text { font-size: 28rpx; color: #64748b; } + +/* ========== 🆕 以下为新增样式,绝无任何修改 ========== */ + +/* 认证状态标签 */ +.renzheng-tag { + font-size: 22rpx; + padding: 4rpx 12rpx; + border-radius: 20rpx; + margin-top: 8rpx; + display: inline-block; +} +.renzheng-tag.authed { + background: rgba(76, 175, 80, 0.15); + color: #4caf50; + border: 1rpx solid rgba(76, 175, 80, 0.4); +} +.renzheng-tag.unauth { + background: rgba(244, 67, 54, 0.1); + color: #f44336; + border: 1rpx solid rgba(244, 67, 54, 0.4); +} + +/* 红色角标 */ +.badge { + position: absolute; + top: -4rpx; + right: -8rpx; + min-width: 36rpx; + height: 36rpx; + background: #f44336; + color: #fff; + font-size: 22rpx; + font-weight: 600; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + padding: 0 8rpx; + box-shadow: 0 2rpx 8rpx rgba(244, 67, 54, 0.4); + z-index: 10; } \ No newline at end of file diff --git a/pages/fenlei/fenlei.js b/pages/category/category.js similarity index 77% rename from pages/fenlei/fenlei.js rename to pages/category/category.js index 9cbf998..a95e8d7 100644 --- a/pages/fenlei/fenlei.js +++ b/pages/category/category.js @@ -1,452 +1,331 @@ -// pages/fenlei/fenlei.js -const app = getApp() - -Page({ - /** - * 页面的初始数据 - */ - data: { - // 全局变量引用 - ossImageUrl: '', - - // 搜索相关 - searchText: '', - showSearchResult: false, - searchResults: [], - isSearching: false, - - // 页面数据 - shangpinleixing: [], - shangpinzhuanqu: [], - shangpinliebiao: [], - - // 状态控制 - selectedLeixingId: null, - selectedZhuanquId: null, - filteredZhuanquList: [], // 当前类型下的专区列表 - filteredShangpinList: [], // 当前专区下的商品列表 - zhuanquByLeixing: {}, // 类型->专区映射对象 - shangpinByZhuanqu: {}, // 专区->商品映射对象 - zhuanquGoodsCount: {}, // 专区商品数量统计 - - // UI状态 - isLoading: false, - hasInitialized: false - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - // 获取全局变量 - this.setData({ - ossImageUrl: app.globalData.ossImageUrl - }) - - // 初始化数据 - this.initPageData() - }, - onShow() { - // 原有代码... - - // 🆕 注册通知组件 - this.registerNotificationComponent(); -}, - -// 🆕 新增:注册通知组件 -registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - - if (notificationComp && notificationComp.showNotification) { - console.log('🏪 商城页面注册通知组件'); - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } -}, - - /** - * 初始化页面数据 - */ - initPageData() { - const that = this - this.setData({ isLoading: true }) - - // 检查全局变量是否已有数据 - if (app.globalData.shangpinleixing && app.globalData.shangpinleixing.length > 0) { - this.initFromGlobalData() - } else { - this.loadAllShangpinData() - } - }, - - /** - * 从全局变量初始化数据 - */ - initFromGlobalData() { - const leixingList = app.globalData.shangpinleixing || [] - const zhuanquList = app.globalData.shangpinzhuanqu || [] - const shangpinList = app.globalData.shangpinliebiao || [] - - // 构建映射关系对象 - const zhuanquByLeixing = {} - const shangpinByZhuanqu = {} - const zhuanquGoodsCount = {} - - // 1. 构建专区映射 (按类型分组) - zhuanquList.forEach(zhuanqu => { - const leixingId = zhuanqu.leixing_id - if (!zhuanquByLeixing[leixingId]) { - zhuanquByLeixing[leixingId] = [] - } - zhuanquByLeixing[leixingId].push(zhuanqu) - }) - - // 2. 构建商品映射 (按专区分组)并统计数量 - shangpinList.forEach(shangpin => { - const zhuanquId = shangpin.zhuanqu_id - if (zhuanquId) { - if (!shangpinByZhuanqu[zhuanquId]) { - shangpinByZhuanqu[zhuanquId] = [] - zhuanquGoodsCount[zhuanquId] = 0 - } - - // 处理价格显示 - const jiage = parseFloat(shangpin.jiage) || 0 - const priceInteger = Math.floor(jiage) - let priceDecimal = '00' - - const decimalPart = (jiage - priceInteger).toFixed(2) - if (decimalPart > 0) { - priceDecimal = decimalPart.toString().split('.')[1] - } - - shangpinByZhuanqu[zhuanquId].push({ - id: shangpin.id, - biaoqian: shangpin.biaoqian, - jiage: jiage, - priceInteger: priceInteger, - priceDecimal: priceDecimal, - tupian_url: shangpin.tupian_url, - duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0 - }) - - zhuanquGoodsCount[zhuanquId] += 1 - } - }) - - // 设置初始选中状态(第一个类型和第一个专区) - const firstLeixing = leixingList[0] - let firstZhuanquId = null - - if (firstLeixing && zhuanquByLeixing[firstLeixing.id]) { - firstZhuanquId = zhuanquByLeixing[firstLeixing.id][0]?.id || null - } - - this.setData({ - shangpinleixing: leixingList, - shangpinzhuanqu: zhuanquList, - shangpinliebiao: shangpinList, - zhuanquByLeixing: zhuanquByLeixing, - shangpinByZhuanqu: shangpinByZhuanqu, - zhuanquGoodsCount: zhuanquGoodsCount, - selectedLeixingId: firstLeixing?.id || null, - selectedZhuanquId: firstZhuanquId - }, () => { - // 筛选数据 - this.filterData() - this.setData({ isLoading: false, hasInitialized: true }) - }) - }, - - /** - * 加载所有商品数据 - */ - loadAllShangpinData() { - const that = this - wx.request({ - url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/', - method: 'POST', - header: { - 'content-type': 'application/json' - }, - success(res) { - if (res.statusCode === 200 && res.data) { - const data = res.data - - // 存储到全局变量 - app.globalData.shangpinleixing = data.shangpinleixing || [] - app.globalData.shangpinzhuanqu = data.shangpinzhuanqu || [] - app.globalData.shangpinliebiao = data.shangpinliebiao || [] - - // 从全局变量初始化 - that.initFromGlobalData() - } else { - that.handleLoadError() - } - }, - fail(error) { - console.error('加载商品数据失败:', error) - that.handleLoadError() - } - }) - }, - - /** - * 处理加载错误 - */ - handleLoadError() { - wx.showToast({ - title: '加载失败,请重试', - icon: 'none' - }) - this.setData({ isLoading: false }) - }, - - /** - * 筛选数据 - */ - filterData() { - const { selectedLeixingId, selectedZhuanquId, zhuanquByLeixing, shangpinByZhuanqu } = this.data - - // 1. 筛选专区列表 - const filteredZhuanquList = zhuanquByLeixing[selectedLeixingId] || [] - - // 2. 筛选商品列表 - let filteredShangpinList = [] - if (selectedZhuanquId) { - filteredShangpinList = shangpinByZhuanqu[selectedZhuanquId] || [] - } else if (filteredZhuanquList.length > 0) { - // 如果没有选中的专区,默认显示第一个专区的商品 - const firstZhuanquId = filteredZhuanquList[0].id - filteredShangpinList = shangpinByZhuanqu[firstZhuanquId] || [] - this.setData({ selectedZhuanquId: firstZhuanquId }) - } - - this.setData({ - filteredZhuanquList: filteredZhuanquList, - filteredShangpinList: filteredShangpinList - }) - }, - - /** - * 选择商品类型 - */ - selectLeixing(e) { - const leixingId = e.currentTarget.dataset.id - - if (this.data.selectedLeixingId === leixingId) { - return - } - - // 获取该类型下的第一个专区 - const zhuanquList = this.data.zhuanquByLeixing[leixingId] || [] - const firstZhuanquId = zhuanquList.length > 0 ? zhuanquList[0].id : null - - this.setData({ - selectedLeixingId: leixingId, - selectedZhuanquId: firstZhuanquId - }, () => { - this.filterData() - }) - }, - - /** - * 选择商品专区 - */ - selectZhuanqu(e) { - const zhuanquId = e.currentTarget.dataset.id - - if (this.data.selectedZhuanquId === zhuanquId) { - return - } - - this.setData({ - selectedZhuanquId: zhuanquId - }, () => { - // 筛选商品列表 - const filteredShangpinList = this.data.shangpinByZhuanqu[zhuanquId] || [] - this.setData({ - filteredShangpinList: filteredShangpinList - }) - }) - }, - - /** - * 搜索框输入事件 - */ - onSearchInput(e) { - this.setData({ - searchText: e.detail.value - }) - }, - - /** - * 点击搜索按钮 - */ - onSearchTap() { - const searchText = this.data.searchText.trim() - if (!searchText) { - wx.showToast({ - title: '请输入搜索内容', - icon: 'none' - }) - return - } - - // 开始搜索 - this.startSearch(searchText) - }, - - /** - * 键盘搜索事件(回车键) - */ - onSearchConfirm(e) { - const searchText = e.detail.value.trim() - if (!searchText) { - wx.showToast({ - title: '请输入搜索内容', - icon: 'none' - }) - return - } - - this.setData({ - searchText: searchText - }) - - // 开始搜索 - this.startSearch(searchText) - }, - - /** - * 执行搜索 - */ - startSearch(searchText) { - this.setData({ - isSearching: true, - showSearchResult: true - }) - - // 本地搜索 - const allShangpin = this.data.shangpinliebiao - const results = [] - - for (const item of allShangpin) { - if (item.biaoqian && item.biaoqian.toLowerCase().includes(searchText.toLowerCase())) { - // 处理价格显示 - const jiage = parseFloat(item.jiage) || 0 - const priceInteger = Math.floor(jiage) - let priceDecimal = '00' - - const decimalPart = (jiage - priceInteger).toFixed(2) - if (decimalPart > 0) { - priceDecimal = decimalPart.toString().split('.')[1] - } - - results.push({ - id: item.id, - biaoqian: item.biaoqian, - jiage: jiage, - priceInteger: priceInteger, - priceDecimal: priceDecimal, - tupian_url: item.tupian_url, - leixing_name: this.getLeixingName(item.leixing_id), - zhuanqu_name: this.getZhuanquName(item.zhuanqu_id) - }) - } - } - - this.setData({ - searchResults: results, - isSearching: false - }) - }, - - /** - * 清空搜索 - */ - onClearSearch() { - this.setData({ - searchText: '', - showSearchResult: false, - searchResults: [] - }) - }, - - /** - * 根据类型ID获取类型名称 - */ - getLeixingName(leixingId) { - const leixingList = this.data.shangpinleixing - for (const item of leixingList) { - if (item.id === leixingId) { - return item.jieshao - } - } - return '' - }, - - /** - * 根据专区ID获取专区名称 - */ - getZhuanquName(zhuanquId) { - const zhuanquList = this.data.shangpinzhuanqu - for (const item of zhuanquList) { - if (item.id === zhuanquId) { - return item.mingzi - } - } - return '' - }, - - /** - * 跳转到商品详情页 - */ - goToDetail(e) { - const shangpinId = e.currentTarget.dataset.id - if (!shangpinId) return - - wx.navigateTo({ - url: `/pages/shangpinxiangqing/shangpinxiangqing?id=${shangpinId}` - }) - }, - - /** - * 刷新所有数据 - */ - onRefresh() { - wx.showLoading({ - title: '刷新中...', - mask: true - }) - - // 清空全局变量 - app.globalData.shangpinleixing = [] - app.globalData.shangpinzhuanqu = [] - app.globalData.shangpinliebiao = [] - - this.loadAllShangpinData() - - setTimeout(() => { - wx.hideLoading() - wx.showToast({ - title: '刷新成功', - icon: 'success', - duration: 1500 - }) - }, 1000) - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - return { - title: '阿龙电竞 - 商品分类', - path: '/pages/fenlei/fenlei' - } - } -}) \ No newline at end of file +// pages/category/category.js +const app = getApp() + +Page({ + data: { + ossImageUrl: '', + searchText: '', + showSearchResult: false, + searchResults: [], + isSearching: false, + shangpinleixing: [], + shangpinzhuanqu: [], + shangpinliebiao: [], + selectedLeixingId: null, + selectedZhuanquId: null, + filteredZhuanquList: [], + filteredShangpinList: [], + zhuanquByLeixing: {}, + shangpinByZhuanqu: {}, + zhuanquGoodsCount: {}, + isLoading: false, + hasInitialized: false + }, + + onLoad(options) { + this.setData({ + ossImageUrl: app.globalData.ossImageUrl + }) + this.initPageData() + }, + + 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() + }; + } + }, + + initPageData() { + const that = this + this.setData({ isLoading: true }) + if (app.globalData.shangpinleixing && app.globalData.shangpinleixing.length > 0) { + this.initFromGlobalData() + } else { + this.loadAllShangpinData() + } + }, + + initFromGlobalData() { + const leixingList = app.globalData.shangpinleixing || [] + const zhuanquList = app.globalData.shangpinzhuanqu || [] + const shangpinList = app.globalData.shangpinliebiao || [] + + const zhuanquByLeixing = {} + const shangpinByZhuanqu = {} + const zhuanquGoodsCount = {} + + zhuanquList.forEach(zhuanqu => { + const leixingId = zhuanqu.leixing_id + if (!zhuanquByLeixing[leixingId]) { + zhuanquByLeixing[leixingId] = [] + } + zhuanquByLeixing[leixingId].push(zhuanqu) + }) + + shangpinList.forEach(shangpin => { + const zhuanquId = shangpin.zhuanqu_id + if (zhuanquId) { + if (!shangpinByZhuanqu[zhuanquId]) { + shangpinByZhuanqu[zhuanquId] = [] + zhuanquGoodsCount[zhuanquId] = 0 + } + const jiage = parseFloat(shangpin.jiage) || 0 + const priceInteger = Math.floor(jiage) + let priceDecimal = '00' + const decimalPart = (jiage - priceInteger).toFixed(2) + if (decimalPart > 0) { + priceDecimal = decimalPart.toString().split('.')[1] + } + shangpinByZhuanqu[zhuanquId].push({ + id: shangpin.id, + biaoqian: shangpin.biaoqian, + jiage: jiage, + priceInteger: priceInteger, + priceDecimal: priceDecimal, + tupian_url: shangpin.tupian_url, + duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0 + }) + zhuanquGoodsCount[zhuanquId] += 1 + } + }) + + const firstLeixing = leixingList[0] + let firstZhuanquId = null + if (firstLeixing && zhuanquByLeixing[firstLeixing.id]) { + firstZhuanquId = zhuanquByLeixing[firstLeixing.id][0]?.id || null + } + + this.setData({ + shangpinleixing: leixingList, + shangpinzhuanqu: zhuanquList, + shangpinliebiao: shangpinList, + zhuanquByLeixing: zhuanquByLeixing, + shangpinByZhuanqu: shangpinByZhuanqu, + zhuanquGoodsCount: zhuanquGoodsCount, + selectedLeixingId: firstLeixing?.id || null, + selectedZhuanquId: firstZhuanquId + }, () => { + this.filterData() + this.setData({ isLoading: false, hasInitialized: true }) + }) + }, + + loadAllShangpinData() { + const that = this + wx.request({ + url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/', + method: 'POST', + header: { + 'content-type': 'application/json' + }, + success(res) { + if (res.statusCode === 200 && res.data) { + const data = res.data + app.globalData.shangpinleixing = data.shangpinleixing || [] + app.globalData.shangpinzhuanqu = data.shangpinzhuanqu || [] + app.globalData.shangpinliebiao = data.shangpinliebiao || [] + that.initFromGlobalData() + } else { + that.handleLoadError() + } + }, + fail(error) { + console.error('加载商品数据失败:', error) + that.handleLoadError() + } + }) + }, + + handleLoadError() { + wx.showToast({ + title: '加载失败,请重试', + icon: 'none' + }) + this.setData({ isLoading: false }) + }, + + filterData() { + const { selectedLeixingId, selectedZhuanquId, zhuanquByLeixing, shangpinByZhuanqu } = this.data + const filteredZhuanquList = zhuanquByLeixing[selectedLeixingId] || [] + let filteredShangpinList = [] + if (selectedZhuanquId) { + filteredShangpinList = shangpinByZhuanqu[selectedZhuanquId] || [] + } else if (filteredZhuanquList.length > 0) { + const firstZhuanquId = filteredZhuanquList[0].id + filteredShangpinList = shangpinByZhuanqu[firstZhuanquId] || [] + this.setData({ selectedZhuanquId: firstZhuanquId }) + } + this.setData({ + filteredZhuanquList: filteredZhuanquList, + filteredShangpinList: filteredShangpinList + }) + }, + + selectLeixing(e) { + const leixingId = e.currentTarget.dataset.id + if (this.data.selectedLeixingId === leixingId) { + return + } + const zhuanquList = this.data.zhuanquByLeixing[leixingId] || [] + const firstZhuanquId = zhuanquList.length > 0 ? zhuanquList[0].id : null + this.setData({ + selectedLeixingId: leixingId, + selectedZhuanquId: firstZhuanquId + }, () => { + this.filterData() + }) + }, + + selectZhuanqu(e) { + const zhuanquId = e.currentTarget.dataset.id + if (this.data.selectedZhuanquId === zhuanquId) { + return + } + this.setData({ + selectedZhuanquId: zhuanquId + }, () => { + const filteredShangpinList = this.data.shangpinByZhuanqu[zhuanquId] || [] + this.setData({ + filteredShangpinList: filteredShangpinList + }) + }) + }, + + onSearchInput(e) { + this.setData({ + searchText: e.detail.value + }) + }, + + onSearchTap() { + const searchText = this.data.searchText.trim() + if (!searchText) { + wx.showToast({ + title: '请输入搜索内容', + icon: 'none' + }) + return + } + this.startSearch(searchText) + }, + + onSearchConfirm(e) { + const searchText = e.detail.value.trim() + if (!searchText) { + wx.showToast({ + title: '请输入搜索内容', + icon: 'none' + }) + return + } + this.setData({ + searchText: searchText + }) + this.startSearch(searchText) + }, + + startSearch(searchText) { + this.setData({ + isSearching: true, + showSearchResult: true + }) + const allShangpin = this.data.shangpinliebiao + const results = [] + for (const item of allShangpin) { + if (item.biaoqian && item.biaoqian.toLowerCase().includes(searchText.toLowerCase())) { + const jiage = parseFloat(item.jiage) || 0 + const priceInteger = Math.floor(jiage) + let priceDecimal = '00' + const decimalPart = (jiage - priceInteger).toFixed(2) + if (decimalPart > 0) { + priceDecimal = decimalPart.toString().split('.')[1] + } + results.push({ + id: item.id, + biaoqian: item.biaoqian, + jiage: jiage, + priceInteger: priceInteger, + priceDecimal: priceDecimal, + tupian_url: item.tupian_url, + leixing_name: this.getLeixingName(item.leixing_id), + zhuanqu_name: this.getZhuanquName(item.zhuanqu_id) + }) + } + } + this.setData({ + searchResults: results, + isSearching: false + }) + }, + + onClearSearch() { + this.setData({ + searchText: '', + showSearchResult: false, + searchResults: [] + }) + }, + + getLeixingName(leixingId) { + const leixingList = this.data.shangpinleixing + for (const item of leixingList) { + if (item.id === leixingId) { + return item.jieshao + } + } + return '' + }, + + getZhuanquName(zhuanquId) { + const zhuanquList = this.data.shangpinzhuanqu + for (const item of zhuanquList) { + if (item.id === zhuanquId) { + return item.mingzi + } + } + return '' + }, + + goToDetail(e) { + const shangpinId = e.currentTarget.dataset.id + if (!shangpinId) return + wx.navigateTo({ + url: `/pages/product-detail/product-detail?id=${shangpinId}` + }) + }, + + onRefresh() { + wx.showLoading({ + title: '刷新中...', + mask: true + }) + app.globalData.shangpinleixing = [] + app.globalData.shangpinzhuanqu = [] + app.globalData.shangpinliebiao = [] + this.loadAllShangpinData() + setTimeout(() => { + wx.hideLoading() + wx.showToast({ + title: '刷新成功', + icon: 'success', + duration: 1500 + }) + }, 1000) + }, + + onShareAppMessage() { + return { + title: '阿龙电竞 - 商品分类', + path: '/pages/category/category' + } + } +}) diff --git a/pages/fenlei/fenlei.json b/pages/category/category.json similarity index 100% rename from pages/fenlei/fenlei.json rename to pages/category/category.json diff --git a/pages/fenlei/fenlei.wxml b/pages/category/category.wxml similarity index 94% rename from pages/fenlei/fenlei.wxml rename to pages/category/category.wxml index 6f015fa..208f034 100644 --- a/pages/fenlei/fenlei.wxml +++ b/pages/category/category.wxml @@ -1,217 +1,217 @@ - - - - - - - - - - - - - - 搜索 - - - - - - - - - - - - - - - {{item.jieshao}} - - - - - - - - - - - - - - - - {{item.mingzi}} - ({{zhuanquGoodsCount[item.id] || 0}}) - - - - - - - - 暂无专区 - - - - - - - - - - - - - - - - {{item.biaoqian}} - - - - - ¥ - {{item.priceInteger}} - .{{item.priceDecimal}} - - - 了解详情 - - - - - - - - - - - 该专区暂无商品 - - - - - — 已加载全部商品 — - - - - - - - - - - - 搜索结果 - ({{searchResults.length}}个) - - - - - - - - - - - - - - {{item.biaoqian}} - - {{item.leixing_name}} - · - {{item.zhuanqu_name}} - - - ¥ - {{item.priceInteger}} - .{{item.priceDecimal}} - - - - - - - - 未找到相关商品 - - - - - - - 搜索中... - - - - - - - - - - - - - 加载中... - - - - - - + + + + + + + + + + + + + + 搜索 + + + + + + + + + + + + + + + {{item.jieshao}} + + + + + + + + + + + + + + + + {{item.mingzi}} + ({{zhuanquGoodsCount[item.id] || 0}}) + + + + + + + + 暂无专区 + + + + + + + + + + + + + + + + {{item.biaoqian}} + + + + + ¥ + {{item.priceInteger}} + .{{item.priceDecimal}} + + + 了解详情 + + + + + + + + + + + 该专区暂无商品 + + + + + — 已加载全部商品 — + + + + + + + + + + + 搜索结果 + ({{searchResults.length}}个) + + + + + + + + + + + + + + {{item.biaoqian}} + + {{item.leixing_name}} + · + {{item.zhuanqu_name}} + + + ¥ + {{item.priceInteger}} + .{{item.priceDecimal}} + + + + + + + + 未找到相关商品 + + + + + + + 搜索中... + + + + + + + + + + + + + 加载中... + + + + + + \ No newline at end of file diff --git a/pages/fenlei/fenlei.wxss b/pages/category/category.wxss similarity index 93% rename from pages/fenlei/fenlei.wxss rename to pages/category/category.wxss index d4a3420..9ce1023 100644 --- a/pages/fenlei/fenlei.wxss +++ b/pages/category/category.wxss @@ -1,1215 +1,1175 @@ -/* pages/fenlei/fenlei.wxss */ -.fenlei-page { - width: 100%; - height: 100vh; - background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); - display: flex; - flex-direction: column; - position: relative; - overflow: hidden; - } - - /* 1. 毛玻璃搜索框区域(固定) */ - .search-container { - padding: 24rpx 32rpx; - background: transparent; - flex-shrink: 0; - position: relative; - z-index: 100; - } - - .search-box { - display: flex; - align-items: center; - background: rgba(255, 255, 255, 0.85); - backdrop-filter: blur(30rpx); - -webkit-backdrop-filter: blur(30rpx); - border-radius: 50rpx; - padding: 0 28rpx; - height: 84rpx; - box-shadow: - 0 8rpx 32rpx rgba(31, 38, 135, 0.1), - inset 0 1rpx 0 rgba(255, 255, 255, 0.8); - border: 1rpx solid rgba(255, 255, 255, 0.3); - position: relative; - overflow: hidden; - } - - .search-box::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.1)); - border-radius: 50rpx; - z-index: -1; - } - - .search-icon { - width: 34rpx; - height: 34rpx; - margin-right: 18rpx; - opacity: 0.6; - } - - .search-input { - flex: 1; - height: 100%; - font-size: 28rpx; - color: #222; - font-weight: 400; - } - - .search-placeholder { - color: #aaa; - font-size: 28rpx; - } - - .search-btn { - background: linear-gradient(135deg, #ffcc00, #ffaa00); - border-radius: 40rpx; - padding: 14rpx 32rpx; - margin-left: 20rpx; - position: relative; - overflow: hidden; - box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.3); - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - } - - .search-btn:active { - transform: scale(0.95); - box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4); - } - - .search-btn-text { - font-size: 26rpx; - color: white; - font-weight: 600; - position: relative; - z-index: 1; - } - - .search-btn-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); - transform: translateX(-100%); - transition: transform 0.6s; - } - - .search-btn:active .search-btn-glow { - transform: translateX(100%); - } - - .search-clear { - width: 36rpx; - height: 36rpx; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-left: 16rpx; - opacity: 0.6; - transition: opacity 0.3s; - } - - .search-clear:active { - opacity: 1; - } - - .clear-icon { - width: 24rpx; - height: 24rpx; - } - - /* 2. 商品类型选择区域(固定)- 恢复原大小 */ - .leixing-container { - padding: 0 32rpx 24rpx; - flex-shrink: 0; - position: relative; - } - - .leixing-bg-glow { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 300rpx; - height: 300rpx; - background: radial-gradient(circle, rgba(255, 204, 0, 0.1) 0%, transparent 70%); - z-index: -1; - } - - .leixing-scroll { - white-space: nowrap; - height: 180rpx; /* 恢复原大小 */ - } - - .leixing-list { - display: inline-flex; - padding-right: 32rpx; - } - - .leixing-item { - display: inline-flex; - flex-direction: column; - align-items: center; - margin-right: 48rpx; /* 增加间距 */ - position: relative; - padding: 12rpx; - } - - .leixing-image-box { - width: 100rpx; /* 恢复原大小 */ - height: 100rpx; /* 恢复原大小 */ - border-radius: 50%; - position: relative; - margin-bottom: 16rpx; - overflow: hidden; - background: white; - box-shadow: - 0 12rpx 30rpx rgba(0, 0, 0, 0.12), - 0 4rpx 8rpx rgba(0, 0, 0, 0.06); - transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); - } - - .leixing-active .leixing-image-box { - transform: scale(1.12); - box-shadow: - 0 18rpx 40rpx rgba(255, 204, 0, 0.3), - 0 8rpx 16rpx rgba(255, 170, 0, 0.2); - } - - .leixing-image { - width: 100%; - height: 100%; - border-radius: 50%; - object-fit: cover; - } - - .leixing-glow { - position: absolute; - top: -3rpx; - left: -3rpx; - right: -3rpx; - bottom: -3rpx; - border-radius: 50%; - background: linear-gradient(135deg, #ffcc00, #ffaa00, #ff8800); - opacity: 0; - transition: opacity 0.4s; - z-index: -1; - filter: blur(10rpx); - } - - .leixing-glow-active { - opacity: 0.6; - animation: glowPulse 2s infinite; - } - - .leixing-sparkle { - position: absolute; - top: 50%; - left: 50%; - width: 20rpx; - height: 20rpx; - background: white; - border-radius: 50%; - transform: translate(-50%, -50%) scale(0); - opacity: 0; - pointer-events: none; - } - - .sparkle-animation { - animation: sparkleFlash 1.5s infinite; - } - - .leixing-text { - font-size: 24rpx; - color: #555; /* 颜色加深 */ - font-weight: 500; - transition: all 0.3s; - white-space: nowrap; - } - - .leixing-active .leixing-text { - color: #ff9900; - font-weight: 600; - transform: translateY(-2rpx); - text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2); - } - - .leixing-active-bar { - position: absolute; - bottom: -4rpx; - width: 44rpx; - height: 4rpx; - background: linear-gradient(90deg, #ffcc00, #ffaa00); - border-radius: 2rpx; - opacity: 0; - transform: scaleX(0); - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - box-shadow: 0 2rpx 8rpx rgba(255, 170, 0, 0.4); - } - - .leixing-active-bar-show { - opacity: 1; - transform: scaleX(1); - } - - .leixing-border-effect { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 50%; - border: 2rpx solid transparent; - opacity: 0; - pointer-events: none; - } - - .border-effect-active { - opacity: 1; - border-color: rgba(255, 204, 0, 0.5); - animation: borderGlow 2s infinite; - } - - /* 3. 左右分栏布局(可滚动区域) */ - .main-container { - flex: 1; - display: flex; - height: calc(100vh - 300rpx); - overflow: hidden; - } - - /* 左边:商品专区列表 */ - .zhuanqu-left { - width: 200rpx; - background: rgba(255, 255, 255, 0.7); - backdrop-filter: blur(10rpx); - border-right: 1rpx solid rgba(0, 0, 0, 0.08); - flex-shrink: 0; - position: relative; - } - - .zhuanqu-list { - padding: 0; - } - - .zhuanqu-item { - position: relative; - padding: 32rpx 0; - border-bottom: 1rpx solid rgba(0, 0, 0, 0.05); - transition: all 0.3s; - } - - .zhuanqu-item:active { - background: rgba(255, 204, 0, 0.05); - } - - .zhuanqu-item-content { - display: flex; - flex-direction: column; - align-items: center; - padding: 0 20rpx; - } - - .zhuanqu-name { - font-size: 26rpx; - color: #444; /* 颜色加深 */ - text-align: center; - line-height: 1.4; - margin-bottom: 8rpx; - transition: all 0.3s; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - overflow: hidden; - font-weight: 500; - } - - .zhuanqu-active .zhuanqu-name { - color: #ff9900; - font-weight: 600; - text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2); - } - - .zhuanqu-count { - font-size: 22rpx; - color: #888; - transition: all 0.3s; - } - - .zhuanqu-active .zhuanqu-count { - color: #ffaa00; - font-weight: 500; - } - - .zhuanqu-active-indicator { - position: absolute; - right: 0; - top: 50%; - transform: translateY(-50%); - width: 6rpx; - height: 44rpx; - background: linear-gradient(180deg, #ffcc00, #ffaa00); - border-radius: 3rpx 0 0 3rpx; - opacity: 0; - transition: all 0.3s; - overflow: hidden; - } - - .zhuanqu-indicator-glow { - opacity: 1; - animation: indicatorGlow 2s infinite; - box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.5); - } - - .indicator-sparkle { - position: absolute; - top: 0; - left: 0; - right: 0; - height: 10rpx; - background: rgba(255, 255, 255, 0.6); - animation: sparkleMove 1.5s infinite; - } - - .zhuanqu-hover-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(90deg, transparent, rgba(255, 204, 0, 0.05), transparent); - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - } - - .zhuanqu-item:active .zhuanqu-hover-glow { - opacity: 1; - } - - .zhuanqu-click-effect { - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 204, 0, 0.1); - transform: translate(-50%, -50%); - opacity: 0; - pointer-events: none; - } - - .zhuanqu-item:active .zhuanqu-click-effect { - animation: rippleEffect 0.6s ease-out; - } - - .zhuanqu-empty { - display: flex; - flex-direction: column; - align-items: center; - padding: 120rpx 0; - } - - .zhuanqu-empty-icon { - width: 120rpx; - height: 120rpx; - opacity: 0.2; - margin-bottom: 28rpx; - } - - .zhuanqu-empty-text { - font-size: 26rpx; - color: #999; - } - - /* 右边:商品列表(紧凑布局) */ - .shangpin-right { - flex: 1; - background: #fafafa; - } - - .shangpin-list { - padding: 0; - } - - .shangpin-item { - background: white; - padding: 28rpx 30rpx 22rpx; /* 底部距离缩小 */ - position: relative; - display: flex; - align-items: flex-start; - min-height: 140rpx; - overflow: hidden; - } - - .shangpin-item:active { - background: rgba(0, 0, 0, 0.02); - } - - .shangpin-image-box { - margin-right: 24rpx; - flex-shrink: 0; - position: relative; - } - - .shangpin-image { - width: 120rpx; - height: 120rpx; - border-radius: 14rpx; - background: #f5f5f5; - object-fit: cover; - } - - .shangpin-image-glow { - position: absolute; - top: -4rpx; - left: -4rpx; - right: -4rpx; - bottom: -4rpx; - border-radius: 18rpx; - background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent); - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - } - - .shangpin-item:active .shangpin-image-glow { - opacity: 0.5; - } - - .image-corner { - position: absolute; - top: 0; - right: 0; - width: 20rpx; - height: 20rpx; - background: linear-gradient(135deg, #ffcc00, transparent 70%); - border-radius: 0 14rpx 0 0; - } - - .shangpin-info { - flex: 1; - display: flex; - flex-direction: column; - height: 120rpx; - justify-content: space-between; - padding-top: 2rpx; /* 标题与图片顶部对齐 */ - } - - .shangpin-title { - margin-bottom: 0; - position: relative; - } - - .shangpin-title-text { - font-size: 30rpx; - font-weight: 500; - color: #222; /* 黑色加深 */ - line-height: 1.4; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; - overflow: hidden; - } - - .title-underline { - position: absolute; - bottom: -4rpx; - left: 0; - width: 0; - height: 2rpx; - background: linear-gradient(90deg, #ffcc00, #ffaa00); - transition: width 0.3s; - } - - .shangpin-item:active .title-underline { - width: 40rpx; - } - - .shangpin-footer { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: auto; - } - - .shangpin-price { - display: flex; - align-items: baseline; - position: relative; - } - - .price-icon { - font-size: 24rpx; - color: #ff6600; - font-weight: 500; - } - - .price-integer { - font-size: 36rpx; /* 适当调整大小 */ - color: #ff6600; - font-weight: 600; - margin-left: 2rpx; - } - - .price-decimal { - font-size: 24rpx; - color: #ff6600; - font-weight: 500; - } - - .price-glow { - position: absolute; - top: 50%; - left: 50%; - width: 80rpx; - height: 80rpx; - background: radial-gradient(circle, rgba(255, 102, 0, 0.1) 0%, transparent 70%); - transform: translate(-50%, -50%); - opacity: 0; - pointer-events: none; - } - - .shangpin-item:active .price-glow { - animation: priceGlow 0.6s; - } - - .detail-btn { - position: relative; - padding: 12rpx 28rpx; - background: linear-gradient(135deg, #ffcc00, #ffaa00); - border-radius: 40rpx; - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - overflow: hidden; - box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.2); - display: flex; - align-items: center; - justify-content: center; - min-width: 120rpx; - } - - .detail-btn:active { - transform: scale(0.95); - box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4); - } - - .detail-btn-text { - font-size: 24rpx; - color: white; - font-weight: 500; - position: relative; - z-index: 2; - line-height: 1; - } - - .btn-glow-effect { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); - transform: translateX(-100%); - transition: transform 0.6s; - } - - .detail-btn:active .btn-glow-effect { - transform: translateX(100%); - } - - .btn-halo { - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 255, 255, 0.3); - transform: translate(-50%, -50%); - opacity: 0; - pointer-events: none; - } - - .detail-btn:active .btn-halo { - animation: buttonHalo 0.6s ease-out; - } - - .btn-star { - position: absolute; - width: 6rpx; - height: 6rpx; - background: white; - border-radius: 50%; - opacity: 0; - pointer-events: none; - } - - .detail-btn:active .btn-star { - animation: starSparkle 0.8s ease-out; - } - - .item-divider { - position: absolute; - left: 30rpx; - right: 30rpx; - bottom: 0; - height: 1rpx; - background: linear-gradient(90deg, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.08)); - } - - .item-hover-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.03), transparent); - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - } - - .shangpin-item:active .item-hover-glow { - opacity: 1; - } - - .item-ripple-effect { - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(255, 204, 0, 0.1); - transform: translate(-50%, -50%); - opacity: 0; - pointer-events: none; - } - - .shangpin-item:active .item-ripple-effect { - animation: rippleEffect 0.6s ease-out; - } - - .shangpin-empty { - display: flex; - flex-direction: column; - align-items: center; - padding: 150rpx 0; - } - - .shangpin-empty-icon { - width: 180rpx; - height: 180rpx; - opacity: 0.15; - margin-bottom: 36rpx; - } - - .shangpin-empty-text { - font-size: 28rpx; - color: #999; - margin-bottom: 40rpx; - } - - .shangpin-empty-btn { - background: linear-gradient(135deg, #ffcc00, #ffaa00); - color: white; - font-size: 26rpx; - font-weight: 500; - padding: 16rpx 44rpx; - border-radius: 40rpx; - box-shadow: 0 8rpx 24rpx rgba(255, 170, 0, 0.3); - transition: all 0.3s; - } - - .shangpin-empty-btn:active { - transform: scale(0.95); - box-shadow: 0 4rpx 16rpx rgba(255, 170, 0, 0.4); - } - - .load-more { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx 0; - } - - .load-more-line { - width: 60rpx; - height: 1rpx; - background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1), transparent); - } - - .load-more-text { - font-size: 24rpx; - color: #bbb; - margin: 0 20rpx; - } - - /* 搜索结果弹窗 */ - .search-results-container { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 2000; - display: flex; - } - - .search-mask { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(5rpx); - } - - .search-results-content { - position: absolute; - top: 100rpx; - left: 32rpx; - right: 32rpx; - bottom: 100rpx; - background: rgba(255, 255, 255, 0.95); - backdrop-filter: blur(30rpx); - border-radius: 24rpx; - box-shadow: - 0 20rpx 60rpx rgba(0, 0, 0, 0.2), - inset 0 1rpx 0 rgba(255, 255, 255, 0.8); - border: 1rpx solid rgba(255, 255, 255, 0.3); - display: flex; - flex-direction: column; - overflow: hidden; - } - - .search-results-header { - padding: 32rpx; - border-bottom: 1rpx solid rgba(0, 0, 0, 0.06); - display: flex; - align-items: center; - justify-content: space-between; - flex-shrink: 0; - } - - .search-header-left { - display: flex; - align-items: baseline; - } - - .search-results-title { - font-size: 34rpx; - font-weight: 600; - color: #333; - } - - .search-results-count { - font-size: 24rpx; - color: #999; - margin-left: 12rpx; - } - - .search-close { - width: 44rpx; - height: 44rpx; - border-radius: 50%; - background: rgba(0, 0, 0, 0.05); - display: flex; - align-items: center; - justify-content: center; - transition: all 0.3s; - } - - .search-close:active { - background: rgba(0, 0, 0, 0.1); - transform: scale(0.9); - } - - .close-icon { - width: 20rpx; - height: 20rpx; - opacity: 0.6; - } - - .search-results-list { - flex: 1; - height: 100%; /* 新增:修复滚动问题的关键代码 */ - } - - .search-result-item { - display: flex; - padding: 28rpx 32rpx; - border-bottom: 1rpx solid rgba(0, 0, 0, 0.04); - position: relative; - transition: all 0.3s; - } - - .search-result-item:active { - background: rgba(0, 0, 0, 0.02); - transform: translateY(-2rpx); - } - - .search-result-left { - margin-right: 24rpx; - position: relative; - } - - .search-result-image { - width: 120rpx; - height: 120rpx; - border-radius: 16rpx; - background: #f5f5f5; - object-fit: cover; - } - - .search-image-glow { - position: absolute; - top: -4rpx; - left: -4rpx; - right: -4rpx; - bottom: -4rpx; - border-radius: 20rpx; - background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent); - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - } - - .search-result-item:active .search-image-glow { - opacity: 0.5; - } - - .search-result-right { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - } - - .search-result-title { - font-size: 28rpx; - font-weight: 500; - color: #333; - line-height: 1.4; - margin-bottom: 16rpx; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - overflow: hidden; - } - - .search-result-info { - display: flex; - gap: 12rpx; - margin-bottom: 20rpx; - } - - .info-tag { - padding: 6rpx 12rpx; - background: rgba(255, 204, 0, 0.1); - border-radius: 6rpx; - } - - .search-result-category { - font-size: 22rpx; - color: #666; - } - - .search-result-zhuanqu { - font-size: 22rpx; - color: #888; - } - - .search-result-price { - display: flex; - align-items: baseline; - } - - .search-item-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.05), transparent); - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - } - - .search-result-item:active .search-item-glow { - opacity: 1; - } - - .search-empty { - display: flex; - flex-direction: column; - align-items: center; - padding: 160rpx 0; - } - - .search-empty-icon { - width: 160rpx; - height: 160rpx; - opacity: 0.2; - margin-bottom: 36rpx; - } - - .search-empty-text { - font-size: 30rpx; - color: #999; - margin-bottom: 16rpx; - } - - .search-empty-tip { - font-size: 24rpx; - color: #bbb; - } - - .search-loading { - display: flex; - flex-direction: column; - align-items: center; - padding: 160rpx 0; - } - - .search-spinner { - width: 60rpx; - height: 60rpx; - position: relative; - margin-bottom: 24rpx; - } - - .spinner-circle { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border: 4rpx solid transparent; - border-top-color: #ffcc00; - border-radius: 50%; - animation: spin 1s linear infinite; - } - - .search-loading-text { - font-size: 26rpx; - color: #999; - } - - /* 全局加载状态 */ - .loading-toast { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.7); - backdrop-filter: blur(10rpx); - display: flex; - align-items: center; - justify-content: center; - z-index: 3000; - } - - .loading-content { - background: rgba(255, 255, 255, 0.1); - backdrop-filter: blur(20rpx); - padding: 60rpx 80rpx; - border-radius: 24rpx; - display: flex; - flex-direction: column; - align-items: center; - position: relative; - border: 1rpx solid rgba(255, 255, 255, 0.1); - } - - .loading-spinner { - width: 80rpx; - height: 80rpx; - position: relative; - margin-bottom: 30rpx; - } - - .spinner-ring { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border: 4rpx solid rgba(255, 255, 255, 0.2); - border-radius: 50%; - } - - .spinner-dot { - position: absolute; - top: 0; - left: 50%; - width: 12rpx; - height: 12rpx; - background: #ffcc00; - border-radius: 50%; - transform: translateX(-50%); - animation: spin 1s linear infinite; - } - - .loading-text { - font-size: 28rpx; - color: white; - font-weight: 500; - } - - .loading-glow { - position: absolute; - top: 50%; - left: 50%; - width: 200rpx; - height: 200rpx; - background: radial-gradient(circle, rgba(255, 204, 0, 0.2) 0%, transparent 70%); - transform: translate(-50%, -50%); - z-index: -1; - } - - /* 动画定义 */ - @keyframes glowPulse { - 0%, 100% { - opacity: 0.4; - transform: scale(1); - } - 50% { - opacity: 0.8; - transform: scale(1.05); - } - } - - @keyframes sparkleFlash { - 0%, 100% { - opacity: 0; - transform: translate(-50%, -50%) scale(0); - } - 50% { - opacity: 1; - transform: translate(-50%, -50%) scale(1); - filter: blur(0); - } - } - - @keyframes borderGlow { - 0%, 100% { - border-color: rgba(255, 204, 0, 0.3); - } - 50% { - border-color: rgba(255, 204, 0, 0.8); - } - } - - @keyframes indicatorGlow { - 0%, 100% { - box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.3); - } - 50% { - box-shadow: 0 0 30rpx rgba(255, 204, 0, 0.8); - } - } - - @keyframes sparkleMove { - 0% { - transform: translateY(-100%); - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - transform: translateY(400%); - opacity: 0; - } - } - - @keyframes rippleEffect { - 0% { - width: 0; - height: 0; - opacity: 0.5; - } - 100% { - width: 200rpx; - height: 200rpx; - opacity: 0; - } - } - - @keyframes priceGlow { - 0% { - opacity: 0; - transform: translate(-50%, -50%) scale(0.5); - } - 50% { - opacity: 0.6; - transform: translate(-50%, -50%) scale(1); - } - 100% { - opacity: 0; - transform: translate(-50%, -50%) scale(1.5); - } - } - - @keyframes buttonHalo { - 0% { - width: 0; - height: 0; - opacity: 0.6; - } - 100% { - width: 200rpx; - height: 200rpx; - opacity: 0; - } - } - - @keyframes starSparkle { - 0% { - opacity: 0; - transform: translate(0, 0) scale(0); - } - 20% { - opacity: 1; - transform: translate(-40rpx, -30rpx) scale(1); - } - 40% { - opacity: 1; - transform: translate(30rpx, -20rpx) scale(1); - } - 60% { - opacity: 1; - transform: translate(-20rpx, 40rpx) scale(1); - } - 80% { - opacity: 1; - transform: translate(40rpx, 20rpx) scale(1); - } - 100% { - opacity: 0; - transform: translate(0, 0) scale(0); - } - } - - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } +/* pages/category/category.wxss */ +.fenlei-page { + width: 100%; + height: 100vh; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + display: flex; + flex-direction: column; + position: relative; + overflow: hidden; + } + + /* 1. 毛玻璃搜索框区域(固定) */ + .search-container { + padding: 24rpx 32rpx; + background: transparent; + flex-shrink: 0; + position: relative; + z-index: 100; + } + + .search-box { + backdrop-filter: blur(30rpx); + -webkit-backdrop-filter: blur(30rpx); + box-shadow: + 0 8rpx 32rpx rgba(31, 38, 135, 0.1), + inset 0 1rpx 0 rgba(255, 255, 255, 0.8); + position: relative; + overflow: hidden; + } + + .search-box::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.1)); + border-radius: 50rpx; + z-index: -1; + } + + .search-icon { + width: 34rpx; + height: 34rpx; + margin-right: 18rpx; + opacity: 0.6; + } + + .search-input { + margin-left: 0; + color: #222; + font-weight: 400; + } + + .search-placeholder { + color: #aaa; + font-size: 28rpx; + } + + .search-btn { + margin-left: 20rpx; + box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.3); + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + } + + .search-btn:active { + transform: scale(0.95); + box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4); + } + + .search-btn-text { + font-size: 26rpx; + color: white; + font-weight: 600; + position: relative; + z-index: 1; + } + + .search-btn-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); + transform: translateX(-100%); + transition: transform 0.6s; + } + + .search-btn:active .search-btn-glow { + transform: translateX(100%); + } + + .search-clear { + width: 36rpx; + height: 36rpx; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-left: 16rpx; + opacity: 0.6; + transition: opacity 0.3s; + } + + .search-clear:active { + opacity: 1; + } + + .clear-icon { + width: 24rpx; + height: 24rpx; + } + + /* 2. 商品类型选择区域(固定) */ + .leixing-container { + padding: 0 32rpx 24rpx; + flex-shrink: 0; + position: relative; + } + + .leixing-bg-glow { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 300rpx; + height: 300rpx; + background: radial-gradient(circle, rgba(255, 204, 0, 0.1) 0%, transparent 70%); + z-index: -1; + } + + .leixing-scroll { + white-space: nowrap; + height: 180rpx; /* 恢复原大小 */ + } + + .leixing-list { + display: inline-flex; + padding-right: 32rpx; + } + + .leixing-item { + display: inline-flex; + flex-direction: column; + align-items: center; + margin-right: 48rpx; /* 增加间距 */ + position: relative; + padding: 12rpx; + } + + .leixing-image-box { + width: 100rpx; /* 恢复原大小 */ /* 恢复原大小 */ + height: 100rpx; /* 恢复原大小 */ /* 恢复原大小 */ + border-radius: 50%; + position: relative; + margin-bottom: 16rpx; + overflow: hidden; + background: white; + box-shadow: + 0 12rpx 30rpx rgba(0, 0, 0, 0.12), + 0 4rpx 8rpx rgba(0, 0, 0, 0.06); + transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); + } + + .leixing-active .leixing-image-box { + transform: scale(1.12); + box-shadow: + 0 18rpx 40rpx rgba(255, 204, 0, 0.3), + 0 8rpx 16rpx rgba(255, 170, 0, 0.2); + } + + .leixing-image { + width: 100%; + height: 100%; + border-radius: 50%; + object-fit: cover; + } + + .leixing-glow { + position: absolute; + top: -3rpx; + left: -3rpx; + right: -3rpx; + bottom: -3rpx; + border-radius: 50%; + background: linear-gradient(135deg, #ffcc00, #ffaa00, #ff8800); + opacity: 0; + transition: opacity 0.4s; + z-index: -1; + filter: blur(10rpx); + } + + .leixing-glow-active { + opacity: 0.6; + animation: glowPulse 2s infinite; + } + + .leixing-sparkle { + position: absolute; + top: 50%; + left: 50%; + width: 20rpx; + height: 20rpx; + background: white; + border-radius: 50%; + transform: translate(-50%, -50%) scale(0); + opacity: 0; + pointer-events: none; + } + + .sparkle-animation { + animation: sparkleFlash 1.5s infinite; + } + + .leixing-text { + font-size: 24rpx; + color: #555; + font-weight: 500; + transition: all 0.3s; + white-space: nowrap; + } + + .leixing-active .leixing-text { + color: #ff9900; + font-weight: 600; + transform: translateY(-2rpx); + text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2); + } + + .leixing-active-bar { + position: absolute; + bottom: -4rpx; + width: 44rpx; + height: 4rpx; + background: linear-gradient(90deg, #ffcc00, #ffaa00); + border-radius: 2rpx; + opacity: 0; + transform: scaleX(0); + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + box-shadow: 0 2rpx 8rpx rgba(255, 170, 0, 0.4); + } + + .leixing-active-bar-show { + opacity: 1; + transform: scaleX(1); + } + + .leixing-border-effect { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 50%; + border: 2rpx solid transparent; + opacity: 0; + pointer-events: none; + } + + .border-effect-active { + opacity: 1; + border-color: rgba(255, 204, 0, 0.5); + animation: borderGlow 2s infinite; + } + + /* 3. 左右分栏布局(可滚动区域) */ + .main-container { + flex: 1; + display: flex; + height: calc(100vh - 300rpx); + overflow: hidden; + } + + /* 左边:商品专区列表 */ + .zhuanqu-left { + width: 200rpx; + background: rgba(255, 255, 255, 0.7); + backdrop-filter: blur(10rpx); + border-right: 1rpx solid rgba(0, 0, 0, 0.08); + flex-shrink: 0; + position: relative; + } + + .zhuanqu-list { + padding: 0; + } + + .zhuanqu-item { + position: relative; + padding: 32rpx 0; + border-bottom: 1rpx solid rgba(0, 0, 0, 0.05); + transition: all 0.3s; + } + + .zhuanqu-item:active { + background: rgba(255, 204, 0, 0.05); + } + + .zhuanqu-item-content { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 20rpx; + } + + .zhuanqu-name { + font-size: 26rpx; + color: #444; + text-align: center; + line-height: 1.4; + margin-bottom: 8rpx; + transition: all 0.3s; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + font-weight: 500; + } + + .zhuanqu-active .zhuanqu-name { + color: #ff9900; + font-weight: 600; + text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2); + } + + .zhuanqu-count { + font-size: 22rpx; + color: #888; + transition: all 0.3s; + } + + .zhuanqu-active .zhuanqu-count { + color: #ffaa00; + font-weight: 500; + } + + .zhuanqu-active-indicator { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 6rpx; + height: 44rpx; + background: linear-gradient(180deg, #ffcc00, #ffaa00); + border-radius: 3rpx 0 0 3rpx; + opacity: 0; + transition: all 0.3s; + overflow: hidden; + } + + .zhuanqu-indicator-glow { + opacity: 1; + animation: indicatorGlow 2s infinite; + box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.5); + } + + .indicator-sparkle { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 10rpx; + background: rgba(255, 255, 255, 0.6); + animation: sparkleMove 1.5s infinite; + } + + .zhuanqu-hover-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent, rgba(255, 204, 0, 0.05), transparent); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .zhuanqu-item:active .zhuanqu-hover-glow { + opacity: 1; + } + + .zhuanqu-click-effect { + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 204, 0, 0.1); + transform: translate(-50%, -50%); + opacity: 0; + pointer-events: none; + } + + .zhuanqu-item:active .zhuanqu-click-effect { + animation: rippleEffect 0.6s ease-out; + } + + .zhuanqu-empty { + display: flex; + flex-direction: column; + align-items: center; + padding: 120rpx 0; + } + + .zhuanqu-empty-icon { + width: 120rpx; + height: 120rpx; + opacity: 0.2; + margin-bottom: 28rpx; + } + + .zhuanqu-empty-text { + font-size: 26rpx; + color: #999; + } + + /* 右边:商品列表(紧凑布局) */ + .shangpin-right { + flex: 1; + background: #fafafa; + } + + .shangpin-list { + padding: 0; + } + + .shangpin-item { + background: white; + padding: 28rpx 30rpx 22rpx; + position: relative; + display: flex; + align-items: flex-start; + min-height: 140rpx; + overflow: hidden; + } + + .shangpin-item:active { + background: rgba(0, 0, 0, 0.02); + } + + .shangpin-image-box { + margin-right: 24rpx; + flex-shrink: 0; + position: relative; + } + + .shangpin-image { + width: 120rpx; + height: 120rpx; + border-radius: 14rpx; + background: #f5f5f5; + object-fit: cover; + } + + .shangpin-image-glow { + position: absolute; + top: -4rpx; + left: -4rpx; + right: -4rpx; + bottom: -4rpx; + border-radius: 18rpx; + background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .shangpin-item:active .shangpin-image-glow { + opacity: 0.5; + } + + .image-corner { + position: absolute; + top: 0; + right: 0; + width: 20rpx; + height: 20rpx; + background: linear-gradient(135deg, #ffcc00, transparent 70%); + border-radius: 0 14rpx 0 0; + } + + .shangpin-info { + flex: 1; + display: flex; + flex-direction: column; + height: 120rpx; + justify-content: space-between; + padding-top: 2rpx; /* 标题与图片顶部对齐 */ + } + + .shangpin-title { + margin-bottom: 0; + position: relative; + } + + .shangpin-title-text { + font-size: 30rpx; + font-weight: 500; + color: #222; /* 黑色加深 */ + line-height: 1.4; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; + } + + .title-underline { + position: absolute; + bottom: -4rpx; + left: 0; + width: 0; + height: 2rpx; + background: linear-gradient(90deg, #ffcc00, #ffaa00); + transition: width 0.3s; + } + + .shangpin-item:active .title-underline { + width: 40rpx; + } + + .shangpin-footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: auto; + } + + .shangpin-price { + display: flex; + align-items: baseline; + position: relative; + } + + .price-icon { + font-size: 24rpx; + color: #ff6600; + font-weight: 500; + } + + .price-integer { + font-size: 36rpx; /* 适当调整大小 */ + color: #ff6600; + font-weight: 600; + margin-left: 2rpx; + } + + .price-decimal { + font-size: 24rpx; + color: #ff6600; + font-weight: 500; + } + + .price-glow { + position: absolute; + top: 50%; + left: 50%; + width: 80rpx; + height: 80rpx; + background: radial-gradient(circle, rgba(255, 102, 0, 0.1) 0%, transparent 70%); + transform: translate(-50%, -50%); + opacity: 0; + pointer-events: none; + } + + .shangpin-item:active .price-glow { + animation: priceGlow 0.6s; + } + + .detail-btn { + position: relative; + padding: 12rpx 28rpx; + background: linear-gradient(135deg, #ffcc00, #ffaa00); + border-radius: 40rpx; + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + overflow: hidden; + box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; + min-width: 120rpx; + } + + .detail-btn:active { + transform: scale(0.95); + box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4); + } + + .detail-btn-text { + font-size: 24rpx; + color: white; + font-weight: 500; + position: relative; + z-index: 2; + line-height: 1; + } + + .btn-glow-effect { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); + transform: translateX(-100%); + transition: transform 0.6s; + } + + .detail-btn:active .btn-glow-effect { + transform: translateX(100%); + } + + .btn-halo { + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 255, 255, 0.3); + transform: translate(-50%, -50%); + opacity: 0; + pointer-events: none; + } + + .detail-btn:active .btn-halo { + animation: buttonHalo 0.6s ease-out; + } + + .btn-star { + position: absolute; + width: 6rpx; + height: 6rpx; + background: white; + border-radius: 50%; + opacity: 0; + pointer-events: none; + } + + .detail-btn:active .btn-star { + animation: starSparkle 0.8s ease-out; + } + + .item-divider { + position: absolute; + left: 30rpx; + right: 30rpx; + bottom: 0; + height: 1rpx; + background: linear-gradient(90deg, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.08)); + } + + .item-hover-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.03), transparent); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .shangpin-item:active .item-hover-glow { + opacity: 1; + } + + .item-ripple-effect { + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 204, 0, 0.1); + transform: translate(-50%, -50%); + opacity: 0; + pointer-events: none; + } + + .shangpin-item:active .item-ripple-effect { + animation: rippleEffect 0.6s ease-out; + } + + .shangpin-empty { + display: flex; + flex-direction: column; + align-items: center; + padding: 150rpx 0; + } + + .shangpin-empty-icon { + width: 180rpx; + height: 180rpx; + opacity: 0.15; + margin-bottom: 36rpx; + } + + .shangpin-empty-text { + font-size: 28rpx; + color: #999; + margin-bottom: 40rpx; + } + + .shangpin-empty-btn { + background: linear-gradient(135deg, #ffcc00, #ffaa00); + color: white; + font-size: 26rpx; + font-weight: 500; + padding: 16rpx 44rpx; + border-radius: 40rpx; + box-shadow: 0 8rpx 24rpx rgba(255, 170, 0, 0.3); + transition: all 0.3s; + } + + .shangpin-empty-btn:active { + transform: scale(0.95); + box-shadow: 0 4rpx 16rpx rgba(255, 170, 0, 0.4); + } + + .load-more-line { + width: 60rpx; + height: 1rpx; + background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1), transparent); + } + + .load-more-text { + font-size: 24rpx; + color: #bbb; + margin: 0 20rpx; + } + + /* 搜索结果弹窗 */ + .search-results-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 2000; + display: flex; + } + + .search-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(5rpx); + } + + .search-results-content { + position: absolute; + top: 100rpx; + left: 32rpx; + right: 32rpx; + bottom: 100rpx; + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(30rpx); + border-radius: 24rpx; + box-shadow: + 0 20rpx 60rpx rgba(0, 0, 0, 0.2), + inset 0 1rpx 0 rgba(255, 255, 255, 0.8); + border: 1rpx solid rgba(255, 255, 255, 0.3); + display: flex; + flex-direction: column; + overflow: hidden; + } + + .search-results-header { + padding: 32rpx; + border-bottom: 1rpx solid rgba(0, 0, 0, 0.06); + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + } + + .search-header-left { + display: flex; + align-items: baseline; + } + + .search-results-title { + font-size: 34rpx; + font-weight: 600; + color: #333; + } + + .search-results-count { + font-size: 24rpx; + color: #999; + margin-left: 12rpx; + } + + .search-close { + width: 44rpx; + height: 44rpx; + border-radius: 50%; + background: rgba(0, 0, 0, 0.05); + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s; + } + + .search-close:active { + background: rgba(0, 0, 0, 0.1); + transform: scale(0.9); + } + + .close-icon { + width: 20rpx; + height: 20rpx; + opacity: 0.6; + } + + .search-results-list { + flex: 1; + height: 100%; + } + + .search-result-item { + display: flex; + padding: 28rpx 32rpx; + border-bottom: 1rpx solid rgba(0, 0, 0, 0.04); + position: relative; + transition: all 0.3s; + } + + .search-result-item:active { + background: rgba(0, 0, 0, 0.02); + transform: translateY(-2rpx); + } + + .search-result-left { + margin-right: 24rpx; + position: relative; + } + + .search-result-image { + width: 120rpx; + height: 120rpx; + border-radius: 16rpx; + background: #f5f5f5; + object-fit: cover; + } + + .search-image-glow { + position: absolute; + top: -4rpx; + left: -4rpx; + right: -4rpx; + bottom: -4rpx; + border-radius: 20rpx; + background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .search-result-item:active .search-image-glow { + opacity: 0.5; + } + + .search-result-right { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + } + + .search-result-title { + font-size: 28rpx; + font-weight: 500; + color: #333; + line-height: 1.4; + margin-bottom: 16rpx; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + } + + .search-result-info { + display: flex; + gap: 12rpx; + margin-bottom: 20rpx; + } + + .info-tag { + padding: 6rpx 12rpx; + background: rgba(255, 204, 0, 0.1); + border-radius: 6rpx; + } + + .search-result-category { + font-size: 22rpx; + color: #666; + } + + .search-result-zhuanqu { + font-size: 22rpx; + color: #888; + } + + .search-result-price { + display: flex; + align-items: baseline; + } + + .search-item-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.05), transparent); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .search-result-item:active .search-item-glow { + opacity: 1; + } + + .search-empty { + display: flex; + flex-direction: column; + align-items: center; + padding: 160rpx 0; + } + + .search-empty-icon { + width: 160rpx; + height: 160rpx; + opacity: 0.2; + margin-bottom: 36rpx; + } + + .search-empty-text { + font-size: 30rpx; + color: #999; + margin-bottom: 16rpx; + } + + .search-empty-tip { + font-size: 24rpx; + color: #bbb; + } + + .search-loading { + display: flex; + flex-direction: column; + align-items: center; + padding: 160rpx 0; + } + + .search-spinner { + width: 60rpx; + height: 60rpx; + position: relative; + margin-bottom: 24rpx; + } + + .spinner-circle { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 4rpx solid transparent; + border-top-color: #ffcc00; + border-radius: 50%; + animation: spin 1s linear infinite; + } + + .search-loading-text { + font-size: 26rpx; + color: #999; + } + + /* 全局加载状态 */ + .loading-toast { + backdrop-filter: blur(10rpx); + z-index: 3000; + } + + .loading-content { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(20rpx); + padding: 60rpx 80rpx; + border-radius: 24rpx; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + border: 1rpx solid rgba(255, 255, 255, 0.1); + } + + .loading-spinner { + width: 80rpx; + height: 80rpx; + position: relative; + margin-bottom: 30rpx; + } + + .spinner-ring { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 4rpx solid rgba(255, 255, 255, 0.2); + border-radius: 50%; + } + + .spinner-dot { + position: absolute; + top: 0; + left: 50%; + width: 12rpx; + height: 12rpx; + background: #ffcc00; + border-radius: 50%; + transform: translateX(-50%); + animation: spin 1s linear infinite; + } + + .loading-text { + font-size: 28rpx; + font-weight: 500; + } + + .loading-glow { + position: absolute; + top: 50%; + left: 50%; + width: 200rpx; + height: 200rpx; + background: radial-gradient(circle, rgba(255, 204, 0, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%); + z-index: -1; + } + + /* 动画定义 */ + @keyframes glowPulse { + 0%, 100% { + opacity: 0.4; + transform: scale(1); + } + 50% { + opacity: 0.8; + transform: scale(1.05); + } + } + + @keyframes sparkleFlash { + 0%, 100% { + opacity: 0; + transform: translate(-50%, -50%) scale(0); + } + 50% { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + filter: blur(0); + } + } + + @keyframes borderGlow { + 0%, 100% { + border-color: rgba(255, 204, 0, 0.3); + } + 50% { + border-color: rgba(255, 204, 0, 0.8); + } + } + + @keyframes indicatorGlow { + 0%, 100% { + box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.3); + } + 50% { + box-shadow: 0 0 30rpx rgba(255, 204, 0, 0.8); + } + } + + @keyframes sparkleMove { + 0% { + transform: translateY(-100%); + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + transform: translateY(400%); + opacity: 0; + } + } + + @keyframes rippleEffect { + 0% { + width: 0; + height: 0; + opacity: 0.5; + } + 100% { + width: 200rpx; + height: 200rpx; + opacity: 0; + } + } + + @keyframes priceGlow { + 0% { + opacity: 0; + transform: translate(-50%, -50%) scale(0.5); + } + 50% { + opacity: 0.6; + transform: translate(-50%, -50%) scale(1); + } + 100% { + opacity: 0; + transform: translate(-50%, -50%) scale(1.5); + } + } + + @keyframes buttonHalo { + 0% { + width: 0; + height: 0; + opacity: 0.6; + } + 100% { + width: 200rpx; + height: 200rpx; + opacity: 0; + } + } + + @keyframes starSparkle { + 0% { + opacity: 0; + transform: translate(0, 0) scale(0); + } + 20% { + opacity: 1; + transform: translate(-40rpx, -30rpx) scale(1); + } + 40% { + opacity: 1; + transform: translate(30rpx, -20rpx) scale(1); + } + 60% { + opacity: 1; + transform: translate(-20rpx, 40rpx) scale(1); + } + 80% { + opacity: 1; + transform: translate(40rpx, 20rpx) scale(1); + } + 100% { + opacity: 0; + transform: translate(0, 0) scale(0); + } } \ No newline at end of file diff --git a/pages/cfss/components/fakuan-list/fakuan-list.json b/pages/cfss/components/fakuan-list/fakuan-list.json deleted file mode 100644 index d192c45..0000000 --- a/pages/cfss/components/fakuan-list/fakuan-list.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "component": true, - "usingComponents": { - "fakuan-pay": "/pages/cfss/components/fakuan-pay/fakuan-pay" - } -} \ No newline at end of file diff --git a/pages/liaotian/liaotian.js b/pages/chat/chat.js similarity index 100% rename from pages/liaotian/liaotian.js rename to pages/chat/chat.js diff --git a/pages/kefuliaotian/kefuliaotian.json b/pages/chat/chat.json similarity index 100% rename from pages/kefuliaotian/kefuliaotian.json rename to pages/chat/chat.json diff --git a/pages/liaotian/liaotian.wxml b/pages/chat/chat.wxml similarity index 100% rename from pages/liaotian/liaotian.wxml rename to pages/chat/chat.wxml diff --git a/pages/liaotian/liaotian.wxss b/pages/chat/chat.wxss similarity index 100% rename from pages/liaotian/liaotian.wxss rename to pages/chat/chat.wxss diff --git a/pages/kefuliaotian/kefuliaotian.js b/pages/cs-chat/cs-chat.js similarity index 97% rename from pages/kefuliaotian/kefuliaotian.js rename to pages/cs-chat/cs-chat.js index 1e8f232..645fcd6 100644 --- a/pages/kefuliaotian/kefuliaotian.js +++ b/pages/cs-chat/cs-chat.js @@ -41,10 +41,8 @@ Page({ teamName = p.teamName || '客服'; teamAvatar = p.teamAvatar || ''; } catch (e) { - console.error('解析客服页面参数失败', e); } } - // 默认头像使用全局配置 if (!teamAvatar) { teamAvatar = app.globalData.ossImageUrl + app.globalData.morentouxiang; } @@ -171,7 +169,7 @@ Page({ this.setData({ messages: msgs }); }, - // ---------- 历史消息 + 永久欢迎语 ---------- + // 历史消息 loadHistory(refresh) { if (!refresh && !this.data.hasMore) return Promise.resolve(); return new Promise((resolve) => { @@ -209,7 +207,7 @@ Page({ const unique = []; for (const m of final) { if (!ids.has(m.messageId)) { ids.add(m.messageId); unique.push(m); } } - // 强制在第一行插入欢迎语(如果不存在) + // 插入欢迎语 const welcomeId = 'welcome-cs'; if (!unique.some(m => m.messageId === welcomeId)) { const welcome = this.createWelcomeMessage(); @@ -249,7 +247,7 @@ Page({ }; }, - // ---------- 接收新客服消息 ---------- + // 接收新客服消息 listenNewMsg() { if (this._msgHandler) wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CS_MESSAGE_RECEIVED, this._msgHandler); this._msgHandler = (msg) => { @@ -310,7 +308,7 @@ Page({ wx.goEasy.im.on(wx.GoEasy.IM_EVENT.MESSAGE_DELETED, this._deleteHandler); }, - // ---------- 面板控制 ---------- + // 面板控制 togglePlusPanel() { this.setData({ showPlusPanel: !this.data.showPlusPanel, showEmojiPanel: false }); }, closePlusPanel() { this.setData({ showPlusPanel: false }); }, openEmojiFromPlus() { this.setData({ showPlusPanel: false, showEmojiPanel: true }); }, @@ -318,7 +316,7 @@ Page({ insertEmoji(e) { this.setData({ inputText: this.data.inputText + e.currentTarget.dataset.emoji }); }, closeEmojiPanel() { this.setData({ showEmojiPanel: false }); }, - // ---------- 发送消息 ---------- + // 发送消息 onInput(e) { this.setData({ inputText: e.detail.value }); }, chooseImage() { const that = this; @@ -409,7 +407,7 @@ Page({ }); }, - // ---------- 订单发送 ---------- + // 订单发送 openOrderSender() { this.setData({ showOrderSender: true, showPlusPanel: false }); }, closeOrderSender() { this.setData({ showOrderSender: false }); }, onSendOrder(e) { @@ -445,7 +443,7 @@ Page({ updateMsg(id, status) { this.setData({ messages: this.data.messages.map(m => m.messageId === id ? { ...m, status } : m) }); }, needShow(ts) { const ms = this.data.messages; if (!ms.length) return true; const last = ms[ms.length-1]; return (ts - last.timestamp) / 60000 > 5; }, - // ---------- 消息操作 ---------- + // 消息操作 onBubbleTap(e) { const msgId = e.currentTarget.dataset.messageid; const text = e.currentTarget.dataset.text; diff --git a/pages/liaotian/liaotian.json b/pages/cs-chat/cs-chat.json similarity index 100% rename from pages/liaotian/liaotian.json rename to pages/cs-chat/cs-chat.json diff --git a/pages/kefuliaotian/kefuliaotian.wxml b/pages/cs-chat/cs-chat.wxml similarity index 100% rename from pages/kefuliaotian/kefuliaotian.wxml rename to pages/cs-chat/cs-chat.wxml diff --git a/pages/kefuliaotian/kefuliaotian.wxss b/pages/cs-chat/cs-chat.wxss similarity index 100% rename from pages/kefuliaotian/kefuliaotian.wxss rename to pages/cs-chat/cs-chat.wxss diff --git a/pages/xiugai/xiugai.js b/pages/edit/edit.js similarity index 91% rename from pages/xiugai/xiugai.js rename to pages/edit/edit.js index 4615e24..5970c5b 100644 --- a/pages/xiugai/xiugai.js +++ b/pages/edit/edit.js @@ -1,228 +1,227 @@ -// pages/xiugai/xiugai.js -const app = getApp() -import upload from '../../utils/upload.js' - -Page({ - data: { - avatarUrl: '', - uid: '', - nicheng: '', - phone: '', - originalAvatar: '', - originalNicheng: '', - isSaving: false, - hasChanges: false, - newAvatarFile: null, - isLoading: true, - isAvatarActive: false, - nicknameError: '' - }, - - onLoad() { - wx.setNavigationBarTitle({ title: '编辑资料' }) - this.loadUserData() - }, - - onShow() { - this.registerNotificationComponent(); - }, - - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - // 加载用户数据(手机号只读,不参与修改逻辑) - loadUserData() { - try { - const uid = wx.getStorageSync('uid') || '' - const nicheng = wx.getStorageSync('nicheng') || '' - const phone = wx.getStorageSync('phone') || '' - const touxiang = wx.getStorageSync('touxiang') || '' - - const ossImageUrl = app.globalData.ossImageUrl || '' - const defaultAvatar = app.globalData.morentouxiang || '' - - let avatarUrl = '' - if (touxiang) { - avatarUrl = touxiang.startsWith('http') ? touxiang : `${ossImageUrl}${touxiang}` - } else if (defaultAvatar) { - avatarUrl = defaultAvatar.startsWith('http') ? defaultAvatar : `${ossImageUrl}${defaultAvatar}` - } - - this.setData({ - avatarUrl, - uid, - nicheng, - phone, // 仅展示 - originalAvatar: touxiang, - originalNicheng: nicheng, - isLoading: false - }) - } catch (error) { - console.error('加载用户数据失败:', error) - this.setData({ isLoading: false }) - wx.showToast({ title: '加载数据失败', icon: 'none' }) - } - }, - - // 微信头像选择(未改动) - onChooseAvatar(e) { - const avatarTempPath = e.detail.avatarUrl - this.setData({ - avatarUrl: avatarTempPath, - newAvatarFile: avatarTempPath - }, () => { - this.checkChanges() - }) - }, - - chooseAvatar() { - // 仅保留动画效果(透明按钮已触发 onChooseAvatar) - this.setData({ isAvatarActive: true }) - setTimeout(() => { - this.setData({ isAvatarActive: false }) - }, 500) - }, - - // 昵称输入(未改动) - onNicknameInput(e) { - const value = e.detail.value.trim() - this.setData({ - nicheng: value, - nicknameError: '' - }, () => { - this.checkChanges() - }) - }, - - // 检查变化(只比较昵称和头像) - checkChanges() { - const { originalNicheng, nicheng, newAvatarFile } = this.data; - const hasChanges = (nicheng !== originalNicheng) || (newAvatarFile !== null); - this.setData({ hasChanges }); - }, - - // 保存(不包含手机号逻辑) - async onSave() { - if (!this.data.hasChanges) { - wx.showToast({ title: '没有需要保存的更改', icon: 'none' }); - return; - } - if (this.data.isSaving) return; - - // 验证数据(昵称) - if (!this.validateData()) return; - - this.setData({ isSaving: true }); - wx.showLoading({ title: '保存中...', mask: true }); - - try { - const formData = {}; - if (this.data.nicheng !== this.data.originalNicheng) { - formData.nicheng = this.data.nicheng; - } - - const res = await upload({ - url: '/yonghu/xiugai', - formData, - filePath: this.data.newAvatarFile, - fileName: 'avatar' - }); - - if (res.statusCode === 200 && res.data) { - const response = res.data; - if (response.code === 0) { - await this.handleUpdateSuccess(response.data); - } else { - throw new Error(response.msg || '保存失败'); - } - } else { - throw new Error('网络错误'); - } - } catch (error) { - console.error('保存失败:', error); - if (error.message.includes('认证失败') || error.message.includes('401')) { - wx.showModal({ - title: '提示', - content: '登录已过期,请重新登录', - complete: (res) => { - if (res.confirm) { - wx.removeStorageSync('token'); - wx.removeStorageSync('userInfo'); - wx.switchTab({ url: '/pages/wode/wode' }); - } - } - }); - } else { - wx.showToast({ title: error.message || '保存失败', icon: 'none' }); - } - } finally { - wx.hideLoading(); - this.setData({ isSaving: false }); - } - }, - - // 验证数据(只验证昵称) - validateData() { - const { nicheng } = this.data; - let hasError = false; - this.setData({ nicknameError: '' }); - - if (nicheng && nicheng.length > 20) { - this.setData({ nicknameError: '昵称不能超过20个字符' }); - hasError = true; - } - if (nicheng !== this.data.originalNicheng && nicheng.trim() === '') { - this.setData({ nicknameError: '昵称不能为空' }); - hasError = true; - } - if (hasError) { - if (this.data.nicknameError) { - wx.showToast({ title: this.data.nicknameError, icon: 'none' }); - } - return false; - } - return true; - }, - - // 更新成功处理(不再处理手机号) - async handleUpdateSuccess(updateData) { - if (updateData.touxiang !== undefined && updateData.touxiang !== null) { - wx.setStorageSync('touxiang', updateData.touxiang); - } - if (updateData.nicheng !== undefined && updateData.nicheng !== null) { - wx.setStorageSync('nicheng', updateData.nicheng); - } - - if (updateData.nicheng) { - app.globalData.userNicheng = updateData.nicheng; - } - - const ossImageUrl = app.globalData.ossImageUrl || ''; - let avatarUrl = this.data.avatarUrl; - if (updateData.touxiang) { - avatarUrl = updateData.touxiang.startsWith('http') ? - updateData.touxiang : `${ossImageUrl}${updateData.touxiang}`; - } - - this.setData({ - avatarUrl, - originalAvatar: updateData.touxiang || this.data.originalAvatar, - originalNicheng: updateData.nicheng || this.data.originalNicheng, - newAvatarFile: null, - hasChanges: false - }); - - wx.showToast({ - title: '保存成功', - icon: 'success', - duration: 2000 - }); - } +// pages/edit/edit.js +const app = getApp() +import upload from '../../utils/upload.js' + +Page({ + data: { + avatarUrl: '', + uid: '', + nicheng: '', + phone: '', + originalAvatar: '', + originalNicheng: '', + isSaving: false, + hasChanges: false, + newAvatarFile: null, + isLoading: true, + isAvatarActive: false, + nicknameError: '' + }, + + onLoad() { + wx.setNavigationBarTitle({ title: '编辑资料' }) + this.loadUserData() + }, + + onShow() { + this.registerNotificationComponent(); + }, + + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + // 加载用户数据 + loadUserData() { + try { + const uid = wx.getStorageSync('uid') || '' + const nicheng = wx.getStorageSync('nicheng') || '' + const phone = wx.getStorageSync('phone') || '' + const touxiang = wx.getStorageSync('touxiang') || '' + + const ossImageUrl = app.globalData.ossImageUrl || '' + const defaultAvatar = app.globalData.morentouxiang || '' + + let avatarUrl = '' + if (touxiang) { + avatarUrl = touxiang.startsWith('http') ? touxiang : `${ossImageUrl}${touxiang}` + } else if (defaultAvatar) { + avatarUrl = defaultAvatar.startsWith('http') ? defaultAvatar : `${ossImageUrl}${defaultAvatar}` + } + + this.setData({ + avatarUrl, + uid, + nicheng, + phone, + originalAvatar: touxiang, + originalNicheng: nicheng, + isLoading: false + }) + } catch (error) { + console.error('加载用户数据失败:', error) + this.setData({ isLoading: false }) + wx.showToast({ title: '加载数据失败', icon: 'none' }) + } + }, + + // 微信头像选择 + onChooseAvatar(e) { + const avatarTempPath = e.detail.avatarUrl + this.setData({ + avatarUrl: avatarTempPath, + newAvatarFile: avatarTempPath + }, () => { + this.checkChanges() + }) + }, + + chooseAvatar() { + this.setData({ isAvatarActive: true }) + setTimeout(() => { + this.setData({ isAvatarActive: false }) + }, 500) + }, + + // 昵称输入 + onNicknameInput(e) { + const value = e.detail.value.trim() + this.setData({ + nicheng: value, + nicknameError: '' + }, () => { + this.checkChanges() + }) + }, + + // 检查变化 + checkChanges() { + const { originalNicheng, nicheng, newAvatarFile } = this.data; + const hasChanges = (nicheng !== originalNicheng) || (newAvatarFile !== null); + this.setData({ hasChanges }); + }, + + // 保存 + async onSave() { + if (!this.data.hasChanges) { + wx.showToast({ title: '没有需要保存的更改', icon: 'none' }); + return; + } + if (this.data.isSaving) return; + + // 验证数据 + if (!this.validateData()) return; + + this.setData({ isSaving: true }); + wx.showLoading({ title: '保存中...', mask: true }); + + try { + const formData = {}; + if (this.data.nicheng !== this.data.originalNicheng) { + formData.nicheng = this.data.nicheng; + } + + const res = await upload({ + url: '/yonghu/xiugai', + formData, + filePath: this.data.newAvatarFile, + fileName: 'avatar' + }); + + if (res.statusCode === 200 && res.data) { + const response = res.data; + if (response.code === 0) { + await this.handleUpdateSuccess(response.data); + } else { + throw new Error(response.msg || '保存失败'); + } + } else { + throw new Error('网络错误'); + } + } catch (error) { + console.error('保存失败:', error); + if (error.message.includes('认证失败') || error.message.includes('401')) { + wx.showModal({ + title: '提示', + content: '登录已过期,请重新登录', + complete: (res) => { + if (res.confirm) { + wx.removeStorageSync('token'); + wx.removeStorageSync('userInfo'); + wx.switchTab({ url: '/pages/mine/mine' }); + } + } + }); + } else { + wx.showToast({ title: error.message || '保存失败', icon: 'none' }); + } + } finally { + wx.hideLoading(); + this.setData({ isSaving: false }); + } + }, + + // 验证数据 + validateData() { + const { nicheng } = this.data; + let hasError = false; + this.setData({ nicknameError: '' }); + + if (nicheng && nicheng.length > 20) { + this.setData({ nicknameError: '昵称不能超过20个字符' }); + hasError = true; + } + if (nicheng !== this.data.originalNicheng && nicheng.trim() === '') { + this.setData({ nicknameError: '昵称不能为空' }); + hasError = true; + } + if (hasError) { + if (this.data.nicknameError) { + wx.showToast({ title: this.data.nicknameError, icon: 'none' }); + } + return false; + } + return true; + }, + + // 更新成功处理 + async handleUpdateSuccess(updateData) { + if (updateData.touxiang !== undefined && updateData.touxiang !== null) { + wx.setStorageSync('touxiang', updateData.touxiang); + } + if (updateData.nicheng !== undefined && updateData.nicheng !== null) { + wx.setStorageSync('nicheng', updateData.nicheng); + } + + if (updateData.nicheng) { + app.globalData.userNicheng = updateData.nicheng; + } + + const ossImageUrl = app.globalData.ossImageUrl || ''; + let avatarUrl = this.data.avatarUrl; + if (updateData.touxiang) { + avatarUrl = updateData.touxiang.startsWith('http') ? + updateData.touxiang : `${ossImageUrl}${updateData.touxiang}`; + } + + this.setData({ + avatarUrl, + originalAvatar: updateData.touxiang || this.data.originalAvatar, + originalNicheng: updateData.nicheng || this.data.originalNicheng, + newAvatarFile: null, + hasChanges: false + }); + + wx.showToast({ + title: '保存成功', + icon: 'success', + duration: 2000 + }); + } }); \ No newline at end of file diff --git a/pages/xiugai/xiugai.json b/pages/edit/edit.json similarity index 100% rename from pages/xiugai/xiugai.json rename to pages/edit/edit.json diff --git a/pages/xiugai/xiugai.wxml b/pages/edit/edit.wxml similarity index 95% rename from pages/xiugai/xiugai.wxml rename to pages/edit/edit.wxml index d5156be..49d217d 100644 --- a/pages/xiugai/xiugai.wxml +++ b/pages/edit/edit.wxml @@ -1,69 +1,69 @@ - - - - - - - - - - - - 点击更换头像 - - - - - - - - - UID - {{uid || '••••••'}} - - - - - 昵称 - - - {{nicknameError}} - - - - - - 手机号 - {{phone || '未绑定'}} - - - - - - - - + + + + + + + + + + + + 点击更换头像 + + + + + + + + + UID + {{uid || '••••••'}} + + + + + 昵称 + + + {{nicknameError}} + + + + + + 手机号 + {{phone || '未绑定'}} + + + + + + + + \ No newline at end of file diff --git a/pages/xiugai/xiugai.wxss b/pages/edit/edit.wxss similarity index 86% rename from pages/xiugai/xiugai.wxss rename to pages/edit/edit.wxss index 4e176e4..f98b51a 100644 --- a/pages/xiugai/xiugai.wxss +++ b/pages/edit/edit.wxss @@ -1,401 +1,380 @@ -/* pages/xiugai/xiugai.wxss */ -page { - background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%); - min-height: 100vh; -} - -.xiugai-page { - padding: 30rpx 40rpx 100rpx; -} - -/* ============ 头像区域样式 ============ */ -.avatar-section { - position: relative; - display: flex; - justify-content: center; - margin-bottom: 60rpx; - padding-top: 30rpx; -} - -.avatar-container { - position: relative; - display: flex; - flex-direction: column; - align-items: center; -} - -/* 头像包装器:精确居中,包含头像+光晕 */ -.avatar-image-wrapper { - position: relative; - width: 200rpx; - height: 200rpx; - flex-shrink: 0; - display: flex; - align-items: center; - justify-content: center; -} - -/* 头像图片 */ -.avatar-image { - width: 200rpx; - height: 200rpx; - border-radius: 50%; - border: 6rpx solid #fff; - background-color: #f8f9fa; - z-index: 2; - position: relative; - animation: gentleBreath 4s ease-in-out infinite; - box-shadow: - 0 0 0 1rpx rgba(0, 200, 83, 0.3), - 0 15rpx 40rpx rgba(0, 200, 83, 0.15); - box-sizing: border-box; /* 关键:边框向内计算,不占宽度 */ -} - -/* ✅ 光晕精确居中:已计算头像 6rpx 边框的偏移量 */ -.avatar-halo { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); /* 强制居中,无视任何偏差 */ - width: 228rpx; /* 精确计算:200 + 6*2(边框) + 8*2(外延) = 228 */ - height: 228rpx; - border-radius: 50%; - background: transparent; - border: 3rpx solid transparent; - animation: gentleGlow 2s ease-in-out infinite, colorShift 3s ease-in-out infinite; - opacity: 0; - z-index: 1; - pointer-events: none; -} - -/* ✅ 像素点环绕也强制居中 */ -.avatar-image-wrapper::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 230rpx; - height: 230rpx; - border-radius: 50%; - background: - radial-gradient(circle at 30% 30%, rgba(0, 200, 83, 0.1) 0%, transparent 50%), - radial-gradient(circle at 70% 70%, rgba(100, 221, 23, 0.1) 0%, transparent 50%); - animation: pixelOrbit 4s linear infinite; - z-index: 0; - pointer-events: none; -} - -/* 温和的呼吸动画 */ -@keyframes gentleBreath { - 0%, 100% { - transform: scale(1); - box-shadow: - 0 0 0 2rpx rgba(0, 200, 83, 0.4), - 0 15rpx 40rpx rgba(0, 200, 83, 0.2); - } - 50% { - transform: scale(1.03); - box-shadow: - 0 0 0 5rpx rgba(0, 200, 83, 0.6), - 0 20rpx 50rpx rgba(0, 200, 83, 0.3); - } -} - -/* 光晕动画 */ -@keyframes gentleGlow { - 0%, 100% { - opacity: 0; - transform: translate(-50%, -50%) scale(0.98); - } - 50% { - opacity: 1; - transform: translate(-50%, -50%) scale(1.05); - } -} - -@keyframes colorShift { - 0% { - border-color: rgba(0, 200, 83, 0.5); - } - 33% { - border-color: rgba(100, 221, 23, 0.5); - } - 66% { - border-color: rgba(0, 255, 153, 0.5); - } - 100% { - border-color: rgba(0, 200, 83, 0.5); - } -} - -@keyframes pixelOrbit { - 0% { - transform: translate(-50%, -50%) rotate(0deg); - } - 100% { - transform: translate(-50%, -50%) rotate(360deg); - } -} - -/* 更换提示 */ -.avatar-hint { - margin-top: 25rpx; - font-size: 28rpx; - color: #666; - padding: 12rpx 30rpx; - background: rgba(255, 255, 255, 0.9); - border-radius: 25rpx; - border: 1rpx solid #eee; - box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.05); - position: relative; - overflow: hidden; -} - -.avatar-hint::before { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 2rpx; - background: linear-gradient(90deg, transparent, #00C853, transparent); - animation: hintGlow 2s ease-in-out infinite; -} - -@keyframes hintGlow { - 0%, 100% { - opacity: 0.3; - } - 50% { - opacity: 1; - } -} - -/* 点击特效 */ -.avatar-container.active .avatar-image { - animation: clickScale 0.5s ease; -} - -@keyframes clickScale { - 0%, 100% { - transform: scale(1); - } - 50% { - transform: scale(0.95); - } -} - -/* 下载状态 */ -.avatar-container.downloading .avatar-image { - opacity: 0.7; - filter: grayscale(30%); -} - -/* 透明功能按钮 */ -.avatar-trigger-button { - position: absolute; - top: 30rpx; - left: 50%; - transform: translateX(-50%); - width: 200rpx; - height: 200rpx; - border-radius: 50%; - z-index: 100; - background: transparent; - border: none; - padding: 0; - margin: 0; - opacity: 0; - line-height: 1; - font-size: 0; -} - -.avatar-trigger-button::after { - border: none; -} - -/* ============ 表单区域 ============ */ -.form-section { - background: white; - border-radius: 25rpx; - overflow: hidden; - margin-bottom: 50rpx; - box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.08); - border: 1rpx solid #f0f0f0; -} - -.form-item { - display: flex; - align-items: center; - padding-left: 40rpx; - border-bottom: 1rpx solid #f0f0f0; - min-height: 110rpx; -} - -.form-item:last-child { - border-bottom: none; -} - -.item-label { - width: 150rpx; - font-size: 32rpx; - color: #333; - font-weight: 500; - flex-shrink: 0; -} - -.item-value.readonly { - flex: 1; - font-size: 32rpx; - color: #666; -} - -.item-input { - flex: 1; - font-size: 32rpx; - color: #333; - height: 50rpx; - line-height: 50rpx; -} - -.placeholder { - color: #ccc; - font-size: 30rpx; -} - -.input-container { - flex: 1; - display: flex; - flex-direction: column; -} - -.item-input.error { - border-bottom: 2rpx solid #ff4d4f; - animation: shake 0.5s; -} - -@keyframes shake { - 0%, 100% { transform: translateX(0); } - 10%, 30%, 50%, 70%, 90% { transform: translateX(-2rpx); } - 20%, 40%, 60%, 80% { transform: translateX(2rpx); } -} - -.error-hint { - font-size: 24rpx; - color: #ff4d4f; - margin-top: 8rpx; - padding-left: 10rpx; - animation: fadeIn 0.3s; -} - -.phone-hint { - font-size: 24rpx; - color: #00C853; - margin-top: 8rpx; - padding-left: 10rpx; - animation: fadeIn 0.3s; -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(-10rpx); } - to { opacity: 1; transform: translateY(0); } -} - -/* ============ 保存按钮 ============ */ -.save-btn { - width: 100%; - height: 100rpx; - line-height: 100rpx; - border-radius: 50rpx; - background: linear-gradient(135deg, #00C853 0%, #64DD17 100%); - color: white; - font-size: 34rpx; - font-weight: 500; - border: none; - position: relative; - overflow: hidden; - box-shadow: 0 15rpx 40rpx rgba(0, 200, 83, 0.25); - margin-top: 30rpx; -} - -.save-btn[disabled] { - background: linear-gradient(135deg, #cccccc 0%, #aaaaaa 100%); - color: #999; - box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1); -} - -.btn-content { - position: relative; - z-index: 2; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; -} - -.btn-sparkle { - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent 0%, - rgba(255, 255, 255, 0.2) 50%, - transparent 100% - ); - animation: sparkleMove 2.5s ease-in-out infinite; - z-index: 1; -} - -@keyframes sparkleMove { - 0% { left: -100%; } - 100% { left: 100%; } -} - -.btn-hover { - opacity: 0.9; - transform: scale(0.98); -} - -/* ============ 手机号获取按钮 ============ */ -.phone-row { - flex: 1; - display: flex; - align-items: center; - justify-content: space-between; -} - -.phone-value { - font-size: 32rpx; - color: #333; - flex: 1; -} - -.get-phone-btn { - flex-shrink: 0; - margin-left: 20rpx; - padding: 10rpx 24rpx; - background: #4a6cf7; - color: #fff; - font-size: 26rpx; - border-radius: 40rpx; - border: none; - line-height: 1.4; - height: 60rpx; - display: flex; - align-items: center; - justify-content: center; -} - -.phone-btn-hover { - opacity: 0.8; -} - -.safe-area { - height: 100rpx; - width: 100%; +/* pages/edit/edit.wxss */ +page { + background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%); + min-height: 100vh; +} + +.xiugai-page { + padding: 30rpx 40rpx 100rpx; +} + +/* 头像区域样式 */ +.avatar-section { + position: relative; + display: flex; + justify-content: center; + margin-bottom: 60rpx; + padding-top: 30rpx; +} + +.avatar-container { + position: relative; + display: flex; + flex-direction: column; + align-items: center; +} + +/* 头像包装器 */ +.avatar-image-wrapper { + position: relative; + width: 200rpx; + height: 200rpx; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; +} + +/* 头像图片 */ +.avatar-image { + width: 200rpx; + height: 200rpx; + border-radius: 50%; + border: 6rpx solid #fff; + background-color: #f8f9fa; + z-index: 2; + position: relative; + animation: gentleBreath 4s ease-in-out infinite; + box-shadow: + 0 0 0 1rpx rgba(0, 200, 83, 0.3), + 0 15rpx 40rpx rgba(0, 200, 83, 0.15); + box-sizing: border-box; +} + +/* 光晕 */ +.avatar-halo { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 228rpx; + height: 228rpx; + border-radius: 50%; + background: transparent; + border: 3rpx solid transparent; + animation: gentleGlow 2s ease-in-out infinite, colorShift 3s ease-in-out infinite; + opacity: 0; + z-index: 1; + pointer-events: none; +} + +/* 像素点环绕 */ +.avatar-image-wrapper::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 230rpx; + height: 230rpx; + border-radius: 50%; + background: + radial-gradient(circle at 30% 30%, rgba(0, 200, 83, 0.1) 0%, transparent 50%), + radial-gradient(circle at 70% 70%, rgba(100, 221, 23, 0.1) 0%, transparent 50%); + animation: pixelOrbit 4s linear infinite; + z-index: 0; + pointer-events: none; +} + +/* 温和的呼吸动画 */ +@keyframes gentleBreath { + 0%, 100% { + transform: scale(1); + box-shadow: + 0 0 0 2rpx rgba(0, 200, 83, 0.4), + 0 15rpx 40rpx rgba(0, 200, 83, 0.2); + } + 50% { + transform: scale(1.03); + box-shadow: + 0 0 0 5rpx rgba(0, 200, 83, 0.6), + 0 20rpx 50rpx rgba(0, 200, 83, 0.3); + } +} + +/* 光晕动画 */ +@keyframes gentleGlow { + 0%, 100% { + opacity: 0; + transform: translate(-50%, -50%) scale(0.98); + } + 50% { + opacity: 1; + transform: translate(-50%, -50%) scale(1.05); + } +} + +@keyframes colorShift { + 0% { + border-color: rgba(0, 200, 83, 0.5); + } + 33% { + border-color: rgba(100, 221, 23, 0.5); + } + 66% { + border-color: rgba(0, 255, 153, 0.5); + } + 100% { + border-color: rgba(0, 200, 83, 0.5); + } +} + +@keyframes pixelOrbit { + 0% { + transform: translate(-50%, -50%) rotate(0deg); + } + 100% { + transform: translate(-50%, -50%) rotate(360deg); + } +} + +/* 更换提示 */ +.avatar-hint { + margin-top: 25rpx; + font-size: 28rpx; + color: #666; + padding: 12rpx 30rpx; + background: rgba(255, 255, 255, 0.9); + border-radius: 25rpx; + border: 1rpx solid #eee; + box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.05); + position: relative; + overflow: hidden; +} + +.avatar-hint::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 2rpx; + background: linear-gradient(90deg, transparent, #00C853, transparent); + animation: hintGlow 2s ease-in-out infinite; +} + +@keyframes hintGlow { + 0%, 100% { + opacity: 0.3; + } + 50% { + opacity: 1; + } +} + +/* 点击特效 */ +.avatar-container.active .avatar-image { + animation: clickScale 0.5s ease; +} + +@keyframes clickScale { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(0.95); + } +} + +/* 下载状态 */ +.avatar-container.downloading .avatar-image { + opacity: 0.7; + filter: grayscale(30%); +} + +/* 透明功能按钮 */ +.avatar-trigger-button { + position: absolute; + top: 30rpx; + left: 50%; + transform: translateX(-50%); + width: 200rpx; + height: 200rpx; + border-radius: 50%; + z-index: 100; + background: transparent; + border: none; + padding: 0; + margin: 0; + opacity: 0; + line-height: 1; + font-size: 0; +} + +.avatar-trigger-button::after { + border: none; +} + +/* 表单区域 */ +.form-section { + border-radius: 25rpx; + margin-bottom: 50rpx; + box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f0f0f0; +} + +.form-item { + display: flex; + align-items: center; + padding-left: 40rpx; + border-bottom: 1rpx solid #f0f0f0; + min-height: 110rpx; +} + +.form-item:last-child { + border-bottom: none; +} + +.item-label { + width: 150rpx; + font-size: 32rpx; + color: #333; + font-weight: 500; + flex-shrink: 0; +} + +.item-value.readonly { + flex: 1; + font-size: 32rpx; + color: #666; +} + +/* .item-input — 与全局 .input-inline 完全相同,已移除 */ + +.placeholder { + color: #ccc; + font-size: 30rpx; +} + +.input-container { + flex: 1; + display: flex; + flex-direction: column; +} + +.item-input.error { + border-bottom: 2rpx solid #ff4d4f; + animation: shake 0.5s; +} + +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 10%, 30%, 50%, 70%, 90% { transform: translateX(-2rpx); } + 20%, 40%, 60%, 80% { transform: translateX(2rpx); } +} + +.error-hint { + font-size: 24rpx; + color: #ff4d4f; + margin-top: 8rpx; + padding-left: 10rpx; + animation: fadeIn 0.3s; +} + +.phone-hint { + font-size: 24rpx; + color: #00C853; + margin-top: 8rpx; + padding-left: 10rpx; + animation: fadeIn 0.3s; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(-10rpx); } + to { opacity: 1; transform: translateY(0); } +} + +/* 保存按钮 */ +.save-btn { + height: 100rpx; + line-height: 100rpx; + border-radius: 50rpx; + background: linear-gradient(135deg, #00C853 0%, #64DD17 100%); + font-weight: 500; + box-shadow: 0 15rpx 40rpx rgba(0, 200, 83, 0.25); + margin-top: 30rpx; +} + +.save-btn[disabled] { + background: linear-gradient(135deg, #cccccc 0%, #aaaaaa 100%); + color: #999; + box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1); +} + +.btn-content { + position: relative; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +} + +.btn-sparkle { + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 255, 255, 0.2) 50%, + transparent 100% + ); + animation: sparkleMove 2.5s ease-in-out infinite; + z-index: 1; +} + +@keyframes sparkleMove { + 0% { left: -100%; } + 100% { left: 100%; } +} + +.btn-hover { + opacity: 0.9; + transform: scale(0.98); +} + +/* 手机号获取按钮 */ +.phone-row { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; +} + +.phone-value { + font-size: 32rpx; + color: #333; + flex: 1; +} + +.get-phone-btn { + flex-shrink: 0; + margin-left: 20rpx; + padding: 10rpx 24rpx; + background: #4a6cf7; + line-height: 1.4; + height: 60rpx; +} + +.phone-btn-hover { + opacity: 0.8; +} + +.safe-area { + height: 100rpx; + width: 100%; } \ No newline at end of file diff --git a/pages/peihuDingdan/peihuDingdan.js b/pages/escort-orders/escort-orders.js similarity index 88% rename from pages/peihuDingdan/peihuDingdan.js rename to pages/escort-orders/escort-orders.js index 3215f4f..4937dd7 100644 --- a/pages/peihuDingdan/peihuDingdan.js +++ b/pages/escort-orders/escort-orders.js @@ -1,66 +1,66 @@ -// pages/peihuDingdan/peihuDingdan.js -Page({ - - /** - * 页面的初始数据 - */ - data: { - - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - - } +// pages/escort-orders/escort-orders.js +Page({ + + /** + * 页面的初始数据 + */ + data: { + + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad(options) { + + }, + + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady() { + + }, + + /** + * 生命周期函数--监听页面显示 + */ + onShow() { + + }, + + /** + * 生命周期函数--监听页面隐藏 + */ + onHide() { + + }, + + /** + * 生命周期函数--监听页面卸载 + */ + onUnload() { + + }, + + /** + * 页面相关事件处理函数--监听用户下拉动作 + */ + onPullDownRefresh() { + + }, + + /** + * 页面上拉触底事件的处理函数 + */ + onReachBottom() { + + }, + + /** + * 用户点击右上角分享 + */ + onShareAppMessage() { + + } }) \ No newline at end of file diff --git a/pages/jiedanchi2/jiedanchi2.json b/pages/escort-orders/escort-orders.json similarity index 100% rename from pages/jiedanchi2/jiedanchi2.json rename to pages/escort-orders/escort-orders.json diff --git a/pages/escort-orders/escort-orders.wxml b/pages/escort-orders/escort-orders.wxml new file mode 100644 index 0000000..e89d6c3 --- /dev/null +++ b/pages/escort-orders/escort-orders.wxml @@ -0,0 +1,2 @@ + +pages/escort-orders/escort-orders.wxml \ No newline at end of file diff --git a/pages/escort-orders/escort-orders.wxss b/pages/escort-orders/escort-orders.wxss new file mode 100644 index 0000000..28f808d --- /dev/null +++ b/pages/escort-orders/escort-orders.wxss @@ -0,0 +1 @@ +/* pages/escort-orders/escort-orders.wxss */ \ No newline at end of file diff --git a/pages/jisufd/jisufd.js b/pages/express-order/express-order.js similarity index 96% rename from pages/jisufd/jisufd.js rename to pages/express-order/express-order.js index 49ae9cb..5c14b45 100644 --- a/pages/jisufd/jisufd.js +++ b/pages/express-order/express-order.js @@ -1,618 +1,618 @@ -// pages/jisufd/jisufd.js -import request from '../../utils/request.js' - -const PAGE_SIZE = 50 -const LINK_PAGE_SIZE = 5 - -Page({ - data: { - sjyue: '0.00', - shangpinList: [], // 最终展示的商品类型列表(已倒序) - selectedTypeId: null, - selectedHuiyuanId: null, - selectedYaoqiuleixing: null, - currentTypeChenghaoList: [], - - searchParams: { keyword: '', minPrice: '', labelId: '' }, - searchLabelName: '', - isSearchMode: false, - - templateList: [], - currentPage: 1, - hasMoreData: true, - isLoadingMore: false, - - linkMap: {}, - - showDetailModal: false, - showAddModal: false, - showDeleteConfirm: false, - showNewLinkConfirm: false, - - currentTemplate: null, - currentTemplateIndex: -1, - - isEditing: false, - editJieshao: '', - editJiage: '', - editLabelId: '', - editLabelName: '', - editCommissionEnabled: false, - editCommissionValue: '', - - addJieshao: '', - addJiage: '', - addLabelId: '', - addLabelName: '', - addCommissionEnabled: false, - addCommissionValue: '', - - detailLinkFilter: 0, - detailLinkList: [], - detailLinkPage: 1, - detailLinkHasMore: true, - isLoadingLinks: false, - - isLoading: false - }, - - onLoad() { - this.loadShangjiaYue() - this.loadShangpinTypes() - }, - - onShow() { - this.registerNotificationComponent() - this.loadShangjiaYue() - }, - - registerNotificationComponent() { - const app = getApp() - const comp = this.selectComponent('#global-notification') - if (comp && comp.showNotification) { - app.globalData.globalNotification = { - show: data => comp.showNotification(data), - hide: () => comp.hideNotification() - } - } - }, - - loadShangjiaYue() { - const app = getApp() - const data = app.globalData.shangjia || {} - this.setData({ sjyue: data.sjyue || '0.00' }) - }, - - async loadShangpinTypes() { - this.setData({ isLoading: true }) - try { - const res = await request({ url: '/dingdan/sjspleixing', method: 'POST' }) - if (res && res.data.code === 200) { - let list = res.data.data || [] - // 强制倒序排列 - list.reverse() - this.setData({ shangpinList: list, isLoading: false }) - if (list.length > 0) { - this.setSelectedType(list[0]) - } - } - } catch (e) { - console.error(e) - this.setData({ isLoading: false }) - wx.showToast({ title: '加载类型失败', icon: 'error' }) - } - }, - - setSelectedType(item) { - this.setData({ - selectedTypeId: item.id, - selectedHuiyuanId: item.huiyuan_id, - selectedYaoqiuleixing: item.yaoqiuleixing, - currentTypeChenghaoList: item.chenghaoList || [] - }, () => { - this.resetAndLoadTemplates() - }) - }, - - resetAndLoadTemplates() { - this.setData({ - templateList: [], - currentPage: 1, - hasMoreData: true, - isSearchMode: false, - searchParams: { keyword: '', minPrice: '', labelId: '' }, - searchLabelName: '' - }) - this.loadTemplates() - }, - - async loadTemplates() { - const { selectedTypeId, currentPage, isSearchMode, searchParams, linkMap } = this.data - if (!selectedTypeId) { - wx.showToast({ title: '请先选择订单类型', icon: 'none' }) - return - } - if (currentPage === 1) this.setData({ isLoading: true }) - else this.setData({ isLoadingMore: true }) - - try { - const postData = { - shangpinTypeId: selectedTypeId, - page: currentPage, - pageSize: PAGE_SIZE, - getType: isSearchMode ? 1 : 2 - } - if (isSearchMode) { - if (searchParams.keyword) postData.keyword = searchParams.keyword.trim() - if (searchParams.minPrice) postData.minPrice = searchParams.minPrice - if (searchParams.labelId) postData.labelId = searchParams.labelId - } - - const res = await request({ url: '/peizhi/sjddmblb', method: 'POST', data: postData }) - if (res && res.data.code === 200) { - const data = res.data.data || {} - const newTemplates = data.list || [] - const existingIds = new Set(this.data.templateList.map(item => item.mobanId)) - const uniqueNew = newTemplates.filter(item => !existingIds.has(item.mobanId)) - - const processed = uniqueNew.map(item => { - const mobanId = item.mobanId || item.id - const cached = linkMap[mobanId] || {} - return { - ...item, - hasGenerated: cached.hasGenerated || !!item.linkUrl, - isCopied: cached.isCopied || false, - linkUrl: cached.linkUrl || item.linkUrl || '', - mobanId: mobanId, - jieshao: item.jieshao || item.moban_jieshao, - jiage: item.jiage || item.price, - fabushuliang: item.fabushuliang || item.fabu_shuliang || 0, - labelId: item.labelId, - labelName: item.labelName || '', - commissionEnabled: item.commissionEnabled, - commissionValue: item.commissionValue - } - }) - - this.setData({ - templateList: currentPage === 1 ? processed : [...this.data.templateList, ...processed], - hasMoreData: data.hasMore !== false && processed.length === PAGE_SIZE, - isLoading: false, - isLoadingMore: false - }) - } else { - this.setData({ isLoading: false, isLoadingMore: false, hasMoreData: false }) - } - } catch (e) { - console.error(e) - this.setData({ isLoading: false, isLoadingMore: false }) - wx.showToast({ title: '加载模板失败', icon: 'error' }) - } - }, - - // ---------- 搜索相关 ---------- - onSearchKeywordInput(e) { this.setData({ 'searchParams.keyword': e.detail.value }) }, - onSearchMinPriceInput(e) { this.setData({ 'searchParams.minPrice': e.detail.value }) }, - onSearchLabelChange(e) { - const idx = e.detail.value - const label = this.data.currentTypeChenghaoList[idx] - this.setData({ - 'searchParams.labelId': label ? label.id : '', - searchLabelName: label ? label.mingcheng : '' - }) - }, - onSearchConfirm() { - const { searchParams } = this.data - if (!searchParams.keyword && !searchParams.minPrice && !searchParams.labelId) { - this.resetAndLoadTemplates() - return - } - this.setData({ - isSearchMode: true, - currentPage: 1, - templateList: [], - hasMoreData: true - }, () => this.loadTemplates()) - }, - onClearSearch() { this.resetAndLoadTemplates() }, - - // ---------- 卡片生成链接 ---------- - async onGenerateLink(e) { - const { id } = e.currentTarget.dataset - const idx = this.data.templateList.findIndex(item => item.mobanId === id) - if (idx === -1) return - await this.generateLinkForTemplate(this.data.templateList[idx], idx) - }, - - onCopyLink(e) { - const { id } = e.currentTarget.dataset - const idx = this.data.templateList.findIndex(item => item.mobanId === id) - if (idx === -1) return - const template = this.data.templateList[idx] - if (!template.linkUrl) { - wx.showToast({ title: '请先生成链接', icon: 'none' }) - return - } - wx.setClipboardData({ - data: template.linkUrl, - success: () => { - const { linkMap } = this.data - const mobanId = template.mobanId - const updatedLinkMap = { ...linkMap } - if (updatedLinkMap[mobanId]) updatedLinkMap[mobanId].isCopied = true - const updatedList = [...this.data.templateList] - updatedList[idx].isCopied = true - this.setData({ linkMap: updatedLinkMap, templateList: updatedList }) - wx.showToast({ title: '链接已复制', icon: 'success' }) - } - }) - }, - - async generateLinkForTemplate(template, templateIndex) { - const { selectedTypeId, linkMap } = this.data - if (!selectedTypeId) { - wx.showToast({ title: '请选择订单类型', icon: 'none' }) - return - } - wx.showLoading({ title: '生成中...', mask: true }) - try { - const res = await request({ - url: '/peizhi/sjljhq', - method: 'POST', - data: { mobanId: template.mobanId, shangpinTypeId: selectedTypeId } - }) - if (res && res.data.code === 200) { - const data = res.data.data || {} - const mobanId = template.mobanId - const updatedLinkMap = { ...linkMap } - updatedLinkMap[mobanId] = { - hasGenerated: true, - linkUrl: data.linkUrl || '', - isCopied: false, - newBalance: data.newBalance - } - const updatedList = [...this.data.templateList] - updatedList[templateIndex] = { - ...updatedList[templateIndex], - hasGenerated: true, - linkUrl: data.linkUrl || '', - isCopied: false, - newBalance: data.newBalance - } - if (data.newBalance) { - const app = getApp() - if (app.globalData.shangjia) app.globalData.shangjia.sjyue = data.newBalance - this.setData({ sjyue: data.newBalance }) - } - this.setData({ linkMap: updatedLinkMap, templateList: updatedList }) - wx.showToast({ title: '链接生成成功', icon: 'success' }) - } else { - wx.showToast({ title: res.data.msg || '生成失败', icon: 'error' }) - } - } catch (e) { - wx.showToast({ title: '生成失败', icon: 'error' }) - } finally { - wx.hideLoading() - } - }, - - onCardTap(e) { - const { target } = e - if (target.className && (target.className.includes('btn') || target.className.includes('action'))) return - const { item } = e.currentTarget.dataset - if (!item) return - const idx = this.data.templateList.findIndex(t => t.mobanId === item.mobanId) - this.setData({ - currentTemplate: item, - currentTemplateIndex: idx, - showDetailModal: true, - isEditing: false, - editJieshao: item.jieshao || '', - editJiage: item.jiage || '', - editLabelId: item.labelId || '', - editLabelName: item.labelName || '', - editCommissionEnabled: item.commissionEnabled || false, - editCommissionValue: item.commissionValue || '', - detailLinkFilter: 0, - detailLinkList: [], - detailLinkPage: 1, - detailLinkHasMore: true - }) - this.loadDetailLinks() - }, - - hideDetailModal() { this.setData({ showDetailModal: false, isEditing: false }) }, - showAddModal() { - this.setData({ - showAddModal: true, - addJieshao: '', addJiage: '', addLabelId: '', addLabelName: '', - addCommissionEnabled: false, addCommissionValue: '' - }) - }, - hideAddModal() { this.setData({ showAddModal: false }) }, - hideDeleteConfirm() { this.setData({ showDeleteConfirm: false }) }, - hideNewLinkConfirm() { this.setData({ showNewLinkConfirm: false }) }, - - // ---------- 链接筛选与加载 ---------- - onToggleLinkFilter() { - const newFilter = this.data.detailLinkFilter === 0 ? 1 : 0 - this.setData({ - detailLinkFilter: newFilter, - detailLinkList: [], - detailLinkPage: 1, - detailLinkHasMore: true - }, () => this.loadDetailLinks()) - }, - - async loadDetailLinks() { - const { currentTemplate, detailLinkFilter, detailLinkPage, isLoadingLinks } = this.data - if (!currentTemplate || isLoadingLinks) return - this.setData({ isLoadingLinks: true }) - try { - const res = await request({ - url: '/peizhi/hqsjlslj', - method: 'POST', - data: { - mobanId: currentTemplate.mobanId, - used: detailLinkFilter, - page: detailLinkPage, - pageSize: LINK_PAGE_SIZE - } - }) - if (res && res.data.code === 200) { - const data = res.data.data || {} - const newLinks = data.list || [] - const merged = detailLinkPage === 1 ? newLinks : [...this.data.detailLinkList, ...newLinks] - this.setData({ - detailLinkList: merged, - detailLinkHasMore: newLinks.length === LINK_PAGE_SIZE, - isLoadingLinks: false - }) - } else { - this.setData({ isLoadingLinks: false }) - } - } catch (e) { - this.setData({ isLoadingLinks: false }) - wx.showToast({ title: '加载链接失败', icon: 'error' }) - } - }, - - onLoadMoreLinks() { - if (!this.data.detailLinkHasMore || this.data.isLoadingLinks) return - this.setData({ detailLinkPage: this.data.detailLinkPage + 1 }, () => this.loadDetailLinks()) - }, - - onCopyLinkItem(e) { - const url = e.currentTarget.dataset.url - if (!url) return - wx.setClipboardData({ data: url, success: () => wx.showToast({ title: '已复制', icon: 'success' }) }) - }, - - // ---------- 弹窗内操作 ---------- - onGenerateLinkModal() { - const { currentTemplate, currentTemplateIndex } = this.data - if (!currentTemplate) return - if (currentTemplate.hasGenerated && !currentTemplate.isCopied) { - this.setData({ showNewLinkConfirm: true }) - return - } - this.generateLinkForTemplate(currentTemplate, currentTemplateIndex) - }, - - onCopyLinkModal() { - const { currentTemplate, linkMap } = this.data - if (!currentTemplate || !currentTemplate.linkUrl) { - wx.showToast({ title: '请先生成链接', icon: 'none' }) - return - } - wx.setClipboardData({ - data: currentTemplate.linkUrl, - success: () => { - const mobanId = currentTemplate.mobanId - const updatedLinkMap = { ...linkMap } - if (updatedLinkMap[mobanId]) updatedLinkMap[mobanId].isCopied = true - const updatedList = [...this.data.templateList] - if (this.data.currentTemplateIndex !== -1) { - updatedList[this.data.currentTemplateIndex].isCopied = true - } - const updatedCurrent = { ...currentTemplate, isCopied: true } - this.setData({ linkMap: updatedLinkMap, templateList: updatedList, currentTemplate: updatedCurrent }) - wx.showToast({ title: '链接已复制', icon: 'success' }) - } - }) - }, - - // ---------- 编辑 ---------- - onEditTemplate() { - if (!this.data.isEditing) this.setData({ isEditing: true }) - else this.saveTemplateEdit() - }, - onEditJieshaoInput(e) { this.setData({ editJieshao: e.detail.value }) }, - onEditJiageInput(e) { this.setData({ editJiage: e.detail.value }) }, - onEditLabelChange(e) { - const idx = e.detail.value - const label = this.data.currentTypeChenghaoList[idx] - this.setData({ editLabelId: label ? label.id : '', editLabelName: label ? label.mingcheng : '' }) - }, - onEditCommissionToggle() { this.setData({ editCommissionEnabled: !this.data.editCommissionEnabled }) }, - onEditCommissionValueInput(e) { this.setData({ editCommissionValue: e.detail.value }) }, - - async saveTemplateEdit() { - const { currentTemplate, selectedTypeId, editJieshao, editJiage, editLabelId, editCommissionEnabled, editCommissionValue } = this.data - if (!currentTemplate || !selectedTypeId) return - if (editCommissionEnabled && (!editCommissionValue || isNaN(parseFloat(editCommissionValue)))) { - wx.showToast({ title: '请输入有效佣金金额', icon: 'none' }) - return - } - wx.showLoading({ title: '保存中...', mask: true }) - try { - const res = await request({ - url: '/peizhi/sjddmbgx', - method: 'POST', - data: { - mobanId: currentTemplate.mobanId, - shangpinTypeId: selectedTypeId, - jieshao: editJieshao, - jiage: editJiage, - labelId: editLabelId || '', - commissionEnabled: editCommissionEnabled, - commissionValue: editCommissionValue - } - }) - if (res && res.data.code === 200) { - const updatedList = [...this.data.templateList] - const idx = this.data.currentTemplateIndex - if (idx !== -1) { - updatedList[idx] = { - ...updatedList[idx], - jieshao: editJieshao, - jiage: editJiage, - labelId: editLabelId, - labelName: this.getLabelNameById(editLabelId), - commissionEnabled: editCommissionEnabled, - commissionValue: editCommissionValue - } - this.setData({ templateList: updatedList, currentTemplate: updatedList[idx], isEditing: false }) - } - wx.showToast({ title: '修改成功', icon: 'success' }) - } else { - wx.showToast({ title: res.data.msg || '修改失败', icon: 'error' }) - } - } catch (e) { - wx.showToast({ title: '修改失败', icon: 'error' }) - } finally { wx.hideLoading() } - }, - - onDeleteTemplate() { this.setData({ showDeleteConfirm: true }) }, - - async confirmDeleteTemplate() { - const { currentTemplate, selectedTypeId, linkMap } = this.data - if (!currentTemplate || !selectedTypeId) return - wx.showLoading({ title: '删除中...', mask: true }) - try { - const res = await request({ - url: '/peizhi/sjddmbsc', - method: 'POST', - data: { mobanId: currentTemplate.mobanId, shangpinTypeId: selectedTypeId } - }) - if (res && res.data.code === 200) { - const updatedLinkMap = { ...linkMap } - delete updatedLinkMap[currentTemplate.mobanId] - const updatedList = [...this.data.templateList] - updatedList.splice(this.data.currentTemplateIndex, 1) - this.setData({ - linkMap: updatedLinkMap, - templateList: updatedList, - showDetailModal: false, - showDeleteConfirm: false, - currentTemplate: null, - currentTemplateIndex: -1 - }) - wx.showToast({ title: '删除成功', icon: 'success' }) - } else { - wx.showToast({ title: res.data.msg || '删除失败', icon: 'error' }) - } - } catch (e) { - wx.showToast({ title: '删除失败', icon: 'error' }) - } finally { wx.hideLoading() } - }, - - async confirmNewLink() { - const { currentTemplate, currentTemplateIndex } = this.data - if (!currentTemplate) return - this.setData({ showNewLinkConfirm: false }) - await this.generateLinkForTemplate(currentTemplate, currentTemplateIndex) - }, - - // ---------- 添加模板 ---------- - onAddJieshaoInput(e) { this.setData({ addJieshao: e.detail.value }) }, - onAddJiageInput(e) { this.setData({ addJiage: e.detail.value }) }, - onAddLabelChange(e) { - const idx = e.detail.value - const label = this.data.currentTypeChenghaoList[idx] - this.setData({ addLabelId: label ? label.id : '', addLabelName: label ? label.mingcheng : '' }) - }, - onAddCommissionToggle() { this.setData({ addCommissionEnabled: !this.data.addCommissionEnabled }) }, - onAddCommissionValueInput(e) { this.setData({ addCommissionValue: e.detail.value }) }, - - async onAddTemplate() { - const { selectedTypeId, addJieshao, addJiage, addLabelId, addCommissionEnabled, addCommissionValue } = this.data - if (!selectedTypeId) { - wx.showToast({ title: '请选择订单类型', icon: 'none' }) - return - } - if (!addJieshao.trim()) { - wx.showToast({ title: '请输入订单介绍', icon: 'none' }) - return - } - if (!addJiage || isNaN(parseFloat(addJiage)) || parseFloat(addJiage) <= 0) { - wx.showToast({ title: '请输入有效的价格', icon: 'none' }) - return - } - if (addCommissionEnabled && (!addCommissionValue || isNaN(parseFloat(addCommissionValue)))) { - wx.showToast({ title: '请输入有效的佣金金额', icon: 'none' }) - return - } - - wx.showLoading({ title: '添加中...', mask: true }) - try { - const res = await request({ - url: '/peizhi/sjtjddmb', - method: 'POST', - data: { - shangpinTypeId: selectedTypeId, - jieshao: addJieshao.trim(), - jiage: addJiage, - labelId: addLabelId || '', - commissionEnabled: addCommissionEnabled, - commissionValue: addCommissionValue - } - }) - if (res && res.data.code === 200) { - const data = res.data.data || {} - const newTemplate = { - mobanId: data.mobanId, - jieshao: addJieshao, - jiage: addJiage, - fabushuliang: 0, - hasGenerated: false, - isCopied: false, - linkUrl: '', - labelId: addLabelId, - labelName: this.getLabelNameById(addLabelId), - commissionEnabled: addCommissionEnabled, - commissionValue: addCommissionValue - } - this.setData({ - templateList: [newTemplate, ...this.data.templateList], - showAddModal: false, - addJieshao: '', addJiage: '', addLabelId: '', addLabelName: '', - addCommissionEnabled: false, addCommissionValue: '' - }) - wx.showToast({ title: '添加成功', icon: 'success' }) - } else { - wx.showToast({ title: res.data.msg || '添加失败', icon: 'error' }) - } - } catch (e) { - wx.showToast({ title: '添加失败', icon: 'error' }) - } finally { wx.hideLoading() } - }, - - getLabelNameById(labelId) { - if (!labelId) return '' - const list = this.data.currentTypeChenghaoList - const found = list.find(item => item.id == labelId) - return found ? found.mingcheng : '' - }, - - onScrollToLower() { - const { hasMoreData, isLoadingMore, isSearchMode } = this.data - if (!hasMoreData || isLoadingMore || isSearchMode) return - this.setData({ currentPage: this.data.currentPage + 1 }, () => this.loadTemplates()) - }, - - onSelectType(e) { - const { id, item } = e.currentTarget.dataset - this.setSelectedType(item) - } +// pages/express-order/express-order.js +import request from '../../utils/request.js' + +const PAGE_SIZE = 50 +const LINK_PAGE_SIZE = 5 + +Page({ + data: { + sjyue: '0.00', + shangpinList: [], // 最终展示的商品类型列表(已倒序) + selectedTypeId: null, + selectedHuiyuanId: null, + selectedYaoqiuleixing: null, + currentTypeChenghaoList: [], + + searchParams: { keyword: '', minPrice: '', labelId: '' }, + searchLabelName: '', + isSearchMode: false, + + templateList: [], + currentPage: 1, + hasMoreData: true, + isLoadingMore: false, + + linkMap: {}, + + showDetailModal: false, + showAddModal: false, + showDeleteConfirm: false, + showNewLinkConfirm: false, + + currentTemplate: null, + currentTemplateIndex: -1, + + isEditing: false, + editJieshao: '', + editJiage: '', + editLabelId: '', + editLabelName: '', + editCommissionEnabled: false, + editCommissionValue: '', + + addJieshao: '', + addJiage: '', + addLabelId: '', + addLabelName: '', + addCommissionEnabled: false, + addCommissionValue: '', + + detailLinkFilter: 0, + detailLinkList: [], + detailLinkPage: 1, + detailLinkHasMore: true, + isLoadingLinks: false, + + isLoading: false + }, + + onLoad() { + this.loadShangjiaYue() + this.loadShangpinTypes() + }, + + onShow() { + this.registerNotificationComponent() + this.loadShangjiaYue() + }, + + registerNotificationComponent() { + const app = getApp() + const comp = this.selectComponent('#global-notification') + if (comp && comp.showNotification) { + app.globalData.globalNotification = { + show: data => comp.showNotification(data), + hide: () => comp.hideNotification() + } + } + }, + + loadShangjiaYue() { + const app = getApp() + const data = app.globalData.shangjia || {} + this.setData({ sjyue: data.sjyue || '0.00' }) + }, + + async loadShangpinTypes() { + this.setData({ isLoading: true }) + try { + const res = await request({ url: '/dingdan/sjspleixing', method: 'POST' }) + if (res && res.data.code === 200) { + let list = res.data.data || [] + // 强制倒序排列 + list.reverse() + this.setData({ shangpinList: list, isLoading: false }) + if (list.length > 0) { + this.setSelectedType(list[0]) + } + } + } catch (e) { + console.error(e) + this.setData({ isLoading: false }) + wx.showToast({ title: '加载类型失败', icon: 'error' }) + } + }, + + setSelectedType(item) { + this.setData({ + selectedTypeId: item.id, + selectedHuiyuanId: item.huiyuan_id, + selectedYaoqiuleixing: item.yaoqiuleixing, + currentTypeChenghaoList: item.chenghaoList || [] + }, () => { + this.resetAndLoadTemplates() + }) + }, + + resetAndLoadTemplates() { + this.setData({ + templateList: [], + currentPage: 1, + hasMoreData: true, + isSearchMode: false, + searchParams: { keyword: '', minPrice: '', labelId: '' }, + searchLabelName: '' + }) + this.loadTemplates() + }, + + async loadTemplates() { + const { selectedTypeId, currentPage, isSearchMode, searchParams, linkMap } = this.data + if (!selectedTypeId) { + wx.showToast({ title: '请先选择订单类型', icon: 'none' }) + return + } + if (currentPage === 1) this.setData({ isLoading: true }) + else this.setData({ isLoadingMore: true }) + + try { + const postData = { + shangpinTypeId: selectedTypeId, + page: currentPage, + pageSize: PAGE_SIZE, + getType: isSearchMode ? 1 : 2 + } + if (isSearchMode) { + if (searchParams.keyword) postData.keyword = searchParams.keyword.trim() + if (searchParams.minPrice) postData.minPrice = searchParams.minPrice + if (searchParams.labelId) postData.labelId = searchParams.labelId + } + + const res = await request({ url: '/peizhi/sjddmblb', method: 'POST', data: postData }) + if (res && res.data.code === 200) { + const data = res.data.data || {} + const newTemplates = data.list || [] + const existingIds = new Set(this.data.templateList.map(item => item.mobanId)) + const uniqueNew = newTemplates.filter(item => !existingIds.has(item.mobanId)) + + const processed = uniqueNew.map(item => { + const mobanId = item.mobanId || item.id + const cached = linkMap[mobanId] || {} + return { + ...item, + hasGenerated: cached.hasGenerated || !!item.linkUrl, + isCopied: cached.isCopied || false, + linkUrl: cached.linkUrl || item.linkUrl || '', + mobanId: mobanId, + jieshao: item.jieshao || item.moban_jieshao, + jiage: item.jiage || item.price, + fabushuliang: item.fabushuliang || item.fabu_shuliang || 0, + labelId: item.labelId, + labelName: item.labelName || '', + commissionEnabled: item.commissionEnabled, + commissionValue: item.commissionValue + } + }) + + this.setData({ + templateList: currentPage === 1 ? processed : [...this.data.templateList, ...processed], + hasMoreData: data.hasMore !== false && processed.length === PAGE_SIZE, + isLoading: false, + isLoadingMore: false + }) + } else { + this.setData({ isLoading: false, isLoadingMore: false, hasMoreData: false }) + } + } catch (e) { + console.error(e) + this.setData({ isLoading: false, isLoadingMore: false }) + wx.showToast({ title: '加载模板失败', icon: 'error' }) + } + }, + + // ---------- 搜索相关 ---------- + onSearchKeywordInput(e) { this.setData({ 'searchParams.keyword': e.detail.value }) }, + onSearchMinPriceInput(e) { this.setData({ 'searchParams.minPrice': e.detail.value }) }, + onSearchLabelChange(e) { + const idx = e.detail.value + const label = this.data.currentTypeChenghaoList[idx] + this.setData({ + 'searchParams.labelId': label ? label.id : '', + searchLabelName: label ? label.mingcheng : '' + }) + }, + onSearchConfirm() { + const { searchParams } = this.data + if (!searchParams.keyword && !searchParams.minPrice && !searchParams.labelId) { + this.resetAndLoadTemplates() + return + } + this.setData({ + isSearchMode: true, + currentPage: 1, + templateList: [], + hasMoreData: true + }, () => this.loadTemplates()) + }, + onClearSearch() { this.resetAndLoadTemplates() }, + + // ---------- 卡片生成链接 ---------- + async onGenerateLink(e) { + const { id } = e.currentTarget.dataset + const idx = this.data.templateList.findIndex(item => item.mobanId === id) + if (idx === -1) return + await this.generateLinkForTemplate(this.data.templateList[idx], idx) + }, + + onCopyLink(e) { + const { id } = e.currentTarget.dataset + const idx = this.data.templateList.findIndex(item => item.mobanId === id) + if (idx === -1) return + const template = this.data.templateList[idx] + if (!template.linkUrl) { + wx.showToast({ title: '请先生成链接', icon: 'none' }) + return + } + wx.setClipboardData({ + data: template.linkUrl, + success: () => { + const { linkMap } = this.data + const mobanId = template.mobanId + const updatedLinkMap = { ...linkMap } + if (updatedLinkMap[mobanId]) updatedLinkMap[mobanId].isCopied = true + const updatedList = [...this.data.templateList] + updatedList[idx].isCopied = true + this.setData({ linkMap: updatedLinkMap, templateList: updatedList }) + wx.showToast({ title: '链接已复制', icon: 'success' }) + } + }) + }, + + async generateLinkForTemplate(template, templateIndex) { + const { selectedTypeId, linkMap } = this.data + if (!selectedTypeId) { + wx.showToast({ title: '请选择订单类型', icon: 'none' }) + return + } + wx.showLoading({ title: '生成中...', mask: true }) + try { + const res = await request({ + url: '/peizhi/sjljhq', + method: 'POST', + data: { mobanId: template.mobanId, shangpinTypeId: selectedTypeId } + }) + if (res && res.data.code === 200) { + const data = res.data.data || {} + const mobanId = template.mobanId + const updatedLinkMap = { ...linkMap } + updatedLinkMap[mobanId] = { + hasGenerated: true, + linkUrl: data.linkUrl || '', + isCopied: false, + newBalance: data.newBalance + } + const updatedList = [...this.data.templateList] + updatedList[templateIndex] = { + ...updatedList[templateIndex], + hasGenerated: true, + linkUrl: data.linkUrl || '', + isCopied: false, + newBalance: data.newBalance + } + if (data.newBalance) { + const app = getApp() + if (app.globalData.shangjia) app.globalData.shangjia.sjyue = data.newBalance + this.setData({ sjyue: data.newBalance }) + } + this.setData({ linkMap: updatedLinkMap, templateList: updatedList }) + wx.showToast({ title: '链接生成成功', icon: 'success' }) + } else { + wx.showToast({ title: res.data.msg || '生成失败', icon: 'error' }) + } + } catch (e) { + wx.showToast({ title: '生成失败', icon: 'error' }) + } finally { + wx.hideLoading() + } + }, + + onCardTap(e) { + const { target } = e + if (target.className && (target.className.includes('btn') || target.className.includes('action'))) return + const { item } = e.currentTarget.dataset + if (!item) return + const idx = this.data.templateList.findIndex(t => t.mobanId === item.mobanId) + this.setData({ + currentTemplate: item, + currentTemplateIndex: idx, + showDetailModal: true, + isEditing: false, + editJieshao: item.jieshao || '', + editJiage: item.jiage || '', + editLabelId: item.labelId || '', + editLabelName: item.labelName || '', + editCommissionEnabled: item.commissionEnabled || false, + editCommissionValue: item.commissionValue || '', + detailLinkFilter: 0, + detailLinkList: [], + detailLinkPage: 1, + detailLinkHasMore: true + }) + this.loadDetailLinks() + }, + + hideDetailModal() { this.setData({ showDetailModal: false, isEditing: false }) }, + showAddModal() { + this.setData({ + showAddModal: true, + addJieshao: '', addJiage: '', addLabelId: '', addLabelName: '', + addCommissionEnabled: false, addCommissionValue: '' + }) + }, + hideAddModal() { this.setData({ showAddModal: false }) }, + hideDeleteConfirm() { this.setData({ showDeleteConfirm: false }) }, + hideNewLinkConfirm() { this.setData({ showNewLinkConfirm: false }) }, + + // ---------- 链接筛选与加载 ---------- + onToggleLinkFilter() { + const newFilter = this.data.detailLinkFilter === 0 ? 1 : 0 + this.setData({ + detailLinkFilter: newFilter, + detailLinkList: [], + detailLinkPage: 1, + detailLinkHasMore: true + }, () => this.loadDetailLinks()) + }, + + async loadDetailLinks() { + const { currentTemplate, detailLinkFilter, detailLinkPage, isLoadingLinks } = this.data + if (!currentTemplate || isLoadingLinks) return + this.setData({ isLoadingLinks: true }) + try { + const res = await request({ + url: '/peizhi/hqsjlslj', + method: 'POST', + data: { + mobanId: currentTemplate.mobanId, + used: detailLinkFilter, + page: detailLinkPage, + pageSize: LINK_PAGE_SIZE + } + }) + if (res && res.data.code === 200) { + const data = res.data.data || {} + const newLinks = data.list || [] + const merged = detailLinkPage === 1 ? newLinks : [...this.data.detailLinkList, ...newLinks] + this.setData({ + detailLinkList: merged, + detailLinkHasMore: newLinks.length === LINK_PAGE_SIZE, + isLoadingLinks: false + }) + } else { + this.setData({ isLoadingLinks: false }) + } + } catch (e) { + this.setData({ isLoadingLinks: false }) + wx.showToast({ title: '加载链接失败', icon: 'error' }) + } + }, + + onLoadMoreLinks() { + if (!this.data.detailLinkHasMore || this.data.isLoadingLinks) return + this.setData({ detailLinkPage: this.data.detailLinkPage + 1 }, () => this.loadDetailLinks()) + }, + + onCopyLinkItem(e) { + const url = e.currentTarget.dataset.url + if (!url) return + wx.setClipboardData({ data: url, success: () => wx.showToast({ title: '已复制', icon: 'success' }) }) + }, + + // ---------- 弹窗内操作 ---------- + onGenerateLinkModal() { + const { currentTemplate, currentTemplateIndex } = this.data + if (!currentTemplate) return + if (currentTemplate.hasGenerated && !currentTemplate.isCopied) { + this.setData({ showNewLinkConfirm: true }) + return + } + this.generateLinkForTemplate(currentTemplate, currentTemplateIndex) + }, + + onCopyLinkModal() { + const { currentTemplate, linkMap } = this.data + if (!currentTemplate || !currentTemplate.linkUrl) { + wx.showToast({ title: '请先生成链接', icon: 'none' }) + return + } + wx.setClipboardData({ + data: currentTemplate.linkUrl, + success: () => { + const mobanId = currentTemplate.mobanId + const updatedLinkMap = { ...linkMap } + if (updatedLinkMap[mobanId]) updatedLinkMap[mobanId].isCopied = true + const updatedList = [...this.data.templateList] + if (this.data.currentTemplateIndex !== -1) { + updatedList[this.data.currentTemplateIndex].isCopied = true + } + const updatedCurrent = { ...currentTemplate, isCopied: true } + this.setData({ linkMap: updatedLinkMap, templateList: updatedList, currentTemplate: updatedCurrent }) + wx.showToast({ title: '链接已复制', icon: 'success' }) + } + }) + }, + + // ---------- 编辑 ---------- + onEditTemplate() { + if (!this.data.isEditing) this.setData({ isEditing: true }) + else this.saveTemplateEdit() + }, + onEditJieshaoInput(e) { this.setData({ editJieshao: e.detail.value }) }, + onEditJiageInput(e) { this.setData({ editJiage: e.detail.value }) }, + onEditLabelChange(e) { + const idx = e.detail.value + const label = this.data.currentTypeChenghaoList[idx] + this.setData({ editLabelId: label ? label.id : '', editLabelName: label ? label.mingcheng : '' }) + }, + onEditCommissionToggle() { this.setData({ editCommissionEnabled: !this.data.editCommissionEnabled }) }, + onEditCommissionValueInput(e) { this.setData({ editCommissionValue: e.detail.value }) }, + + async saveTemplateEdit() { + const { currentTemplate, selectedTypeId, editJieshao, editJiage, editLabelId, editCommissionEnabled, editCommissionValue } = this.data + if (!currentTemplate || !selectedTypeId) return + if (editCommissionEnabled && (!editCommissionValue || isNaN(parseFloat(editCommissionValue)))) { + wx.showToast({ title: '请输入有效佣金金额', icon: 'none' }) + return + } + wx.showLoading({ title: '保存中...', mask: true }) + try { + const res = await request({ + url: '/peizhi/sjddmbgx', + method: 'POST', + data: { + mobanId: currentTemplate.mobanId, + shangpinTypeId: selectedTypeId, + jieshao: editJieshao, + jiage: editJiage, + labelId: editLabelId || '', + commissionEnabled: editCommissionEnabled, + commissionValue: editCommissionValue + } + }) + if (res && res.data.code === 200) { + const updatedList = [...this.data.templateList] + const idx = this.data.currentTemplateIndex + if (idx !== -1) { + updatedList[idx] = { + ...updatedList[idx], + jieshao: editJieshao, + jiage: editJiage, + labelId: editLabelId, + labelName: this.getLabelNameById(editLabelId), + commissionEnabled: editCommissionEnabled, + commissionValue: editCommissionValue + } + this.setData({ templateList: updatedList, currentTemplate: updatedList[idx], isEditing: false }) + } + wx.showToast({ title: '修改成功', icon: 'success' }) + } else { + wx.showToast({ title: res.data.msg || '修改失败', icon: 'error' }) + } + } catch (e) { + wx.showToast({ title: '修改失败', icon: 'error' }) + } finally { wx.hideLoading() } + }, + + onDeleteTemplate() { this.setData({ showDeleteConfirm: true }) }, + + async confirmDeleteTemplate() { + const { currentTemplate, selectedTypeId, linkMap } = this.data + if (!currentTemplate || !selectedTypeId) return + wx.showLoading({ title: '删除中...', mask: true }) + try { + const res = await request({ + url: '/peizhi/sjddmbsc', + method: 'POST', + data: { mobanId: currentTemplate.mobanId, shangpinTypeId: selectedTypeId } + }) + if (res && res.data.code === 200) { + const updatedLinkMap = { ...linkMap } + delete updatedLinkMap[currentTemplate.mobanId] + const updatedList = [...this.data.templateList] + updatedList.splice(this.data.currentTemplateIndex, 1) + this.setData({ + linkMap: updatedLinkMap, + templateList: updatedList, + showDetailModal: false, + showDeleteConfirm: false, + currentTemplate: null, + currentTemplateIndex: -1 + }) + wx.showToast({ title: '删除成功', icon: 'success' }) + } else { + wx.showToast({ title: res.data.msg || '删除失败', icon: 'error' }) + } + } catch (e) { + wx.showToast({ title: '删除失败', icon: 'error' }) + } finally { wx.hideLoading() } + }, + + async confirmNewLink() { + const { currentTemplate, currentTemplateIndex } = this.data + if (!currentTemplate) return + this.setData({ showNewLinkConfirm: false }) + await this.generateLinkForTemplate(currentTemplate, currentTemplateIndex) + }, + + // ---------- 添加模板 ---------- + onAddJieshaoInput(e) { this.setData({ addJieshao: e.detail.value }) }, + onAddJiageInput(e) { this.setData({ addJiage: e.detail.value }) }, + onAddLabelChange(e) { + const idx = e.detail.value + const label = this.data.currentTypeChenghaoList[idx] + this.setData({ addLabelId: label ? label.id : '', addLabelName: label ? label.mingcheng : '' }) + }, + onAddCommissionToggle() { this.setData({ addCommissionEnabled: !this.data.addCommissionEnabled }) }, + onAddCommissionValueInput(e) { this.setData({ addCommissionValue: e.detail.value }) }, + + async onAddTemplate() { + const { selectedTypeId, addJieshao, addJiage, addLabelId, addCommissionEnabled, addCommissionValue } = this.data + if (!selectedTypeId) { + wx.showToast({ title: '请选择订单类型', icon: 'none' }) + return + } + if (!addJieshao.trim()) { + wx.showToast({ title: '请输入订单介绍', icon: 'none' }) + return + } + if (!addJiage || isNaN(parseFloat(addJiage)) || parseFloat(addJiage) <= 0) { + wx.showToast({ title: '请输入有效的价格', icon: 'none' }) + return + } + if (addCommissionEnabled && (!addCommissionValue || isNaN(parseFloat(addCommissionValue)))) { + wx.showToast({ title: '请输入有效的佣金金额', icon: 'none' }) + return + } + + wx.showLoading({ title: '添加中...', mask: true }) + try { + const res = await request({ + url: '/peizhi/sjtjddmb', + method: 'POST', + data: { + shangpinTypeId: selectedTypeId, + jieshao: addJieshao.trim(), + jiage: addJiage, + labelId: addLabelId || '', + commissionEnabled: addCommissionEnabled, + commissionValue: addCommissionValue + } + }) + if (res && res.data.code === 200) { + const data = res.data.data || {} + const newTemplate = { + mobanId: data.mobanId, + jieshao: addJieshao, + jiage: addJiage, + fabushuliang: 0, + hasGenerated: false, + isCopied: false, + linkUrl: '', + labelId: addLabelId, + labelName: this.getLabelNameById(addLabelId), + commissionEnabled: addCommissionEnabled, + commissionValue: addCommissionValue + } + this.setData({ + templateList: [newTemplate, ...this.data.templateList], + showAddModal: false, + addJieshao: '', addJiage: '', addLabelId: '', addLabelName: '', + addCommissionEnabled: false, addCommissionValue: '' + }) + wx.showToast({ title: '添加成功', icon: 'success' }) + } else { + wx.showToast({ title: res.data.msg || '添加失败', icon: 'error' }) + } + } catch (e) { + wx.showToast({ title: '添加失败', icon: 'error' }) + } finally { wx.hideLoading() } + }, + + getLabelNameById(labelId) { + if (!labelId) return '' + const list = this.data.currentTypeChenghaoList + const found = list.find(item => item.id == labelId) + return found ? found.mingcheng : '' + }, + + onScrollToLower() { + const { hasMoreData, isLoadingMore, isSearchMode } = this.data + if (!hasMoreData || isLoadingMore || isSearchMode) return + this.setData({ currentPage: this.data.currentPage + 1 }, () => this.loadTemplates()) + }, + + onSelectType(e) { + const { id, item } = e.currentTarget.dataset + this.setSelectedType(item) + } }) \ No newline at end of file diff --git a/pages/jisufd/jisufd.json b/pages/express-order/express-order.json similarity index 100% rename from pages/jisufd/jisufd.json rename to pages/express-order/express-order.json diff --git a/pages/jisufd/jisufd.wxml b/pages/express-order/express-order.wxml similarity index 97% rename from pages/jisufd/jisufd.wxml rename to pages/express-order/express-order.wxml index 5d0fc2a..fe89a26 100644 --- a/pages/jisufd/jisufd.wxml +++ b/pages/express-order/express-order.wxml @@ -1,230 +1,230 @@ - - - - - 可用余额 - - {{sjyue}} - - - 生成链接将从此余额扣除 - - - - - 选择订单类型 - - - - {{item.jieshao}} - - - - - - - - - 🔍 - - - 搜索 - - - - - 金额≥ - - - - 标签 - - - {{searchLabelName || '全部'}} - - - - 清空 - - - - - - - - - - - {{item.jieshao || '无介绍'}} - - - - - - 价格: - {{item.jiage || '0.00'}}元 - - - - {{item.hasGenerated ? '获取新链接' : '生成链接'}} - - - {{item.isCopied ? '已复制' : '一键复制'}} - - - - - - - 添加模板 - 点击创建新模板 - - - ... - 没有更多模板了 - 暂无模板 - - - - - - - - × - 模板详情 - - - 订单介绍 - {{currentTemplate.jieshao || '无介绍'}} - - - 关联标签 - - - - 价格{{currentTemplate.jiage || '0.00'}}元 - | - 发布数量{{currentTemplate.fabushuliang || 0}}次 - | - 模板ID{{currentTemplate.mobanId || 'N/A'}} - - - 佣金要求 - {{currentTemplate.commissionValue}}元(建议≤50) - - - - 链接状态: - 未使用 - 已使用 - - - - - {{item.lianjie}} - {{item.is_used ? '已使用' : '未使用'}} - 复制 - - - - 获取更多链接 - - 加载中... - 暂无链接 - - - - {{currentTemplate.hasGenerated ? '获取新链接' : '生成链接'}} - {{currentTemplate.isCopied ? '已复制' : '复制链接'}} - {{isEditing ? '保存修改' : '立即修改'}} - 删除模板 - - - - - 订单介绍 - - {{jiesuan.liuyan.length}}/50 - - - 确认结算 - - - - - - - 上线速度标准 - - - {{item.label}}({{item.value}}分) - {{item.explain}} - - - 关闭 - - - - - - - 服务态度标准 - - - {{item.label}}({{item.value}}分) - {{item.explain}} - - - 关闭 - - - - - - - 确认结算订单? - 结算后订单将变为已完成,确认无误后再点击按钮({{countdown}}s) - 确认结算 - 取消 - - + + + + + + 加载中... + + + + + + + + {{jibenShuju.jieshao || '暂无描述'}} + + + + + 订单信息 + + 游戏昵称 + {{jibenShuju.nicheng}} + 复制 + + + 备注 + {{jibenShuju.beizhu}} + + + 订单ID + {{jibenShuju.dingdanId}} + 复制 + + + 价格 + ¥{{jibenShuju.jine}} + + + 状态 + {{zhuangtaiWenziMap[jibenShuju.zhuangtai] || '未知'}} + + + 创建时间 + {{jibenShuju.chuangjianshijian}} + + + 更新时间 + {{jibenShuju.updateTime}} + + + + + + 服务打手 + + 头像 + + + + 昵称 + {{xiangxiShuju.dashouNicheng || '未设置'}} + + + 打手ID + {{xiangxiShuju.dashou}} + 复制 + + + 接单时间 + {{xiangxiShuju.jiedanTime}} + + + 提交时间 + {{xiangxiShuju.tijiaoTime}} + + + 联系打手 + + + + + 交付截图 + + + + + + + + 打手留言 + {{xiangxiShuju.dashouliuyan}} + + + + + 我的评价 + + 上线速度 + {{speedText}} + + + 服务态度 + {{attitudeText}} + + + 翻车次数 + {{xiangxiShuju.fancheCishu}} + + + 我的留言 + {{xiangxiShuju.laobanPingjia}} + + + + + + 订单结算 + + + + 翻车次数 + + 填写该订单翻车次数,用于评价打手实力 + + + + + + 上线速度 + 标准详情 + + + + {{item.label}} + + + + {{speedExplain}} + + + + + + 服务态度 + 标准详情 + + + + {{item.label}} + + + {{attitudeExplain}} + + + + + 留言(选填) + + {{jiesuan.liuyan.length}}/50 + + + 确认结算 + + + + + + + 上线速度标准 + + + {{item.label}}({{item.value}}分) + {{item.explain}} + + + 关闭 + + + + + + + 服务态度标准 + + + {{item.label}}({{item.value}}分) + {{item.explain}} + + + 关闭 + + + + + + + 确认结算订单? + 结算后订单将变为已完成,确认无误后再点击按钮({{countdown}}s) + 确认结算 + 取消 + + \ No newline at end of file diff --git a/pages/dingdanxiangqing/dingdanxiangqing.wxss b/pages/order-detail/order-detail.wxss similarity index 99% rename from pages/dingdanxiangqing/dingdanxiangqing.wxss rename to pages/order-detail/order-detail.wxss index daeb265..16aaede 100644 --- a/pages/dingdanxiangqing/dingdanxiangqing.wxss +++ b/pages/order-detail/order-detail.wxss @@ -21,7 +21,7 @@ animation: spin 1s linear infinite; margin-bottom: 20rpx; } - @keyframes spin { to { transform: rotate(360deg); } } + .loading-text { font-size: 28rpx; color: #888; } /* 主内容 */ diff --git a/pages/jiedanchi/jiedanchi.js b/pages/order-pool/order-pool.js similarity index 92% rename from pages/jiedanchi/jiedanchi.js rename to pages/order-pool/order-pool.js index 95089c4..2176f96 100644 --- a/pages/jiedanchi/jiedanchi.js +++ b/pages/order-pool/order-pool.js @@ -1,466 +1,458 @@ -// pages/jiedanchi/jiedanchi.js -const app = getApp(); -import request from '../../utils/request.js'; -import PopupService from '../../services/popupService.js'; - -Page({ - data: { - // 1. 商品类型相关 - shangpinleixing: [], // 商品类型列表 {id, jieshao, tupian_url} - xuanzhongLeixingId: null, // 当前选中的类型ID - - // 2. 订单列表与分页相关 - dingdanList: [], // 当前展示的订单列表 - page: 1, - pageSize: 10, - hasMore: true, - isLoading: false, - - // 3. 全局状态字段 - dashoustatus: null, - zhuanghaoStatus: null, // 注意变量名:zhuanghaoStatus - dashouzhuangtai: null, - uid: null, - huiyuanList: [], // clumber 列表 - yajin: 0, - jifen: 0, - - // 4. 刷新控制字段 - scrollViewRefreshing: false, - lastRefreshTime: 0, - refreshCooldown: 2000, - isLoadingMore: false, - - // 5. 切换类型冷却时间控制 - lastSwitchTime: 0, - switchCooldown: 1500, - isSwitching: false, - - // 6. 全局OSS地址 - ossImageUrl: app.globalData.ossImageUrl || '', - - // 7. 授权状态控制 - showUnauthorized: false, - unauthorizedMsg: '您尚未开启此功能', - }, - - async onLoad(options) { - this.loadGlobalStatus(); - this.checkAuthorization(); - }, - // 🆕 页面隐藏时清理弹窗视图 - onHide: function () { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } -}, - - onShow() { - this.registerNotificationComponent(); - this.loadGlobalStatus(); - this.checkAuthorization(); - }, - - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - loadGlobalStatus() { - const globalData = app.globalData; - // 从缓存读取,确保与抢单时使用的数据源一致 - const dashoustatusCache = wx.getStorageSync('dashoustatus'); - const dashoustatus = dashoustatusCache !== '' ? dashoustatusCache : null; - - // 从 globalData 或缓存获取 zhuanghaoStatus(注意字段名可能有差异) - let zhuanghaoStatus = globalData.zhanghaoStatus; - if (zhuanghaoStatus === undefined || zhuanghaoStatus === null) { - zhuanghaoStatus = wx.getStorageSync('zhanghaoStatus'); - } - - this.setData({ - dashoustatus: dashoustatus, - zhuanghaoStatus: zhuanghaoStatus, - dashouzhuangtai: globalData.dashouzhuangtai, - uid: wx.getStorageSync('uid'), - huiyuanList: globalData.clumber || [], - yajin: globalData.yajin || 0, - jifen: globalData.jinfen || 0 - }); - - // 打印当前值,方便调试 - //console.log('loadGlobalStatus -> dashoustatus:', dashoustatus, 'zhuanghaoStatus:', zhuanghaoStatus); - }, - - checkAuthorization() { - const { dashoustatus, zhuanghaoStatus } = this.data; - //console.log('checkAuthorization -> dashoustatus:', dashoustatus, 'zhuanghaoStatus:', zhuanghaoStatus); - - // 完全复制抢单时的判断逻辑 - const isDashouValid = (dashoustatus && dashoustatus == 1) || false; // 存在且等于1 - const isZhuanghaoValid = (zhuanghaoStatus == 1); // 宽松比较,null/undefined/0 均视为 false - - const isAuthorized = isDashouValid && isZhuanghaoValid; - - if (!isAuthorized) { - this.setData({ showUnauthorized: true }); - let msg = ''; - if (!isDashouValid) msg = '您尚未开启身份'; - //else if (!isZhuanghaoValid) msg = '您的账号状态异常'; - this.setData({ unauthorizedMsg: msg || '无法使用抢单功能' }); - } else { - this.setData({ showUnauthorized: false }); - if (!this.data.shangpinleixing.length) { - this.loadShangpinLeixing(); - } else if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - } - PopupService.checkAndShow(this, 'jiedanchi'); - } - }, - - async loadShangpinLeixing() { - wx.showLoading({ title: '加载商品类型...' }); - try { - const res = await request({ - url: '/dingdan/dsqdhqddlx', - method: 'POST', - header: { 'content-type': 'application/json' } - }); - - if (res.statusCode === 200 && res.data) { - const data = res.data; - let list = []; - if (data.code === 200 || data.code === 0) { - if (data.data && Array.isArray(data.data.list)) { - list = data.data.list; - } else if (data.data && Array.isArray(data.data)) { - list = data.data; - } else if (Array.isArray(data.list)) { - list = data.list; - } else if (Array.isArray(data)) { - list = data; - } - } - const processedList = this.processTupianUrl(list); - this.setData({ - shangpinleixing: processedList, - xuanzhongLeixingId: processedList[0]?.id || null - }); - if (this.data.xuanzhongLeixingId) { - this.loadDingdanList(true); - } - } else { - wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none', duration: 2000 }); - } - } catch (error) { - console.error('加载商品类型失败:', error); - wx.showToast({ title: '网络错误,加载失败', icon: 'none', duration: 2000 }); - } finally { - wx.hideLoading(); - } - }, - - processTupianUrl(list) { - const ossUrl = app.globalData.ossImageUrl || ''; - return list.map(item => ({ - ...item, - full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http') ? ossUrl + item.tupian_url : (item.tupian_url || '/images/default-type.png') - })); - }, - - async selectLeixing(e) { - const now = Date.now(); - if (now - this.data.lastSwitchTime < this.data.switchCooldown) { - wx.showToast({ - title: `操作太快,请${Math.ceil((this.data.switchCooldown - (now - this.data.lastSwitchTime)) / 1000)}秒后再试`, - icon: 'none', - duration: 1500 - }); - return; - } - if (this.data.isSwitching) return; - const leixingId = e.currentTarget.dataset.id; - if (leixingId === this.data.xuanzhongLeixingId) return; - this.setData({ isSwitching: true, lastSwitchTime: now }); - wx.showLoading({ title: '切换中...' }); - try { - this.setData({ - xuanzhongLeixingId: leixingId, - dingdanList: [], - page: 1, - hasMore: true - }); - await this.loadDingdanList(true); - } catch (error) { - console.error('切换类型失败:', error); - } finally { - this.setData({ isSwitching: false }); - wx.hideLoading(); - } - }, - - 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; - - this.setData({ - isLoading: true, - isLoadingMore: !isRefresh - }); - - try { - const res = await request({ - url: '/dingdan/ddhq', - method: 'POST', - data: { - leixing_id: this.data.xuanzhongLeixingId, - page: loadPage, - page_size: this.data.pageSize - } - }); - - this.setData({ - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false - }); - - if (res.data.code === 200 || res.data.code === 0) { - const newList = res.data.data.list || []; - const hasMore = res.data.data.has_more || false; - - const processedList = newList.map(item => this.processDingdanItem(item)); - - const updatedList = isRefresh ? processedList : [...this.data.dingdanList, ...processedList]; - - updatedList.sort((a, b) => (b.creat_time || '').localeCompare(a.creat_time || '')); - - this.setData({ - dingdanList: updatedList, - page: loadPage, - hasMore: hasMore - }); - - if (isRefresh) { - this.setData({ lastRefreshTime: Date.now() }); - } - } else { - wx.showToast({ title: res.data.msg || '加载失败', icon: 'none' }); - } - } catch (error) { - console.error('加载订单失败:', error); - this.setData({ - isLoading: false, - isLoadingMore: false, - scrollViewRefreshing: false - }); - wx.showToast({ title: '网络请求失败', icon: 'none' }); - } - }, - - processDingdanItem(item) { - const ossUrl = app.globalData.ossImageUrl || ''; - let fullTupianUrl = ''; - if (item.tupian) { - fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; - } else { - 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; - } - const zhidingNicheng = item.zhiding_nicheng || ''; - - return { - ...item, - full_tupian_url: fullTupianUrl, - isZhiding: isZhiding, - isPingtai: item.pingtai == 1, - isShangjia: item.pingtai == 2, - zhiding_avatar_full: zhidingAvatar, - zhiding_nicheng: zhidingNicheng - }; - }, - - goToChongzhiPage(failureType, huiyuanId = null, requiredYajin = 0) { - let url = '/pages/dashouchongzhi/dashouchongzhi'; - let params = {}; - switch (failureType) { - case 'huiyuan': - params = { needScroll: '0', scrollTo: 'member' }; - break; - case 'yajin': - params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin }; - break; - case 'jifen': - params = { needScroll: '1', scrollTo: 'bottom' }; - break; - } - if (huiyuanId) params.huiyuanId = huiyuanId; - const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&'); - const fullUrl = `${url}?${queryString}`; - wx.navigateTo({ - url: fullUrl, - fail: (err) => { - console.error('跳转失败:', err); - wx.showToast({ title: '跳转失败,请稍后重试', icon: 'none' }); - } - }); - }, - - async onQiangdanTap(e) { - const dingdanItem = e.currentTarget.dataset.item; - if (!dingdanItem) return; - - if (!this.data.dashoustatus || this.data.dashoustatus != 1) { - wx.showToast({ title: '请先开启打手身份', icon: 'none' }); - return; - } - if (this.data.zhuanghaoStatus != 1) { - wx.showToast({ title: '账号异常,无法接单', icon: 'none' }); - return; - } - if (this.data.dashouzhuangtai != 1) { - wx.showToast({ title: '您有订单正在接待中', icon: 'none' }); - return; - } - if (dingdanItem.isZhiding) { - if (!this.data.uid || this.data.uid != dingdanItem.zhiding_uid) { - wx.showToast({ title: '此订单为指定单', icon: 'none' }); - return; - } - } - if (dingdanItem.yaoqiuleixing == 1) { - const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); - if (!hasHuiyuan) { - wx.showToast({ title: '未开通对应会员,无法抢单', icon: 'none', duration: 2000 }); - setTimeout(() => this.goToChongzhiPage('huiyuan', dingdanItem.huiyuan_id), 500); - return; - } - } - if (dingdanItem.yaoqiuleixing == 2) { - if (this.data.yajin < dingdanItem.yajin) { - wx.showToast({ title: `押金不足,需${dingdanItem.yajin}`, icon: 'none', duration: 2000 }); - setTimeout(() => this.goToChongzhiPage('yajin', null, dingdanItem.yajin), 500); - return; - } - } - if (this.data.jifen < 5) { - wx.showToast({ title: '积分不足,至少需要5积分', icon: 'none', duration: 2000 }); - setTimeout(() => this.goToChongzhiPage('jifen'), 500); - return; - } - - const that = this; - wx.showModal({ - title: '确认抢单', - content: `确定要抢此订单吗?${dingdanItem.isZhiding ? '(指定订单)' : ''}`, - success: async function (res) { - if (res.confirm) { - wx.showLoading({ title: '抢单中...', mask: true }); - try { - const qiangdanRes = await request({ - url: '/dingdan/qiangdan', - method: 'POST', - data: { dingdan_id: dingdanItem.dingdan_id } - }); - wx.hideLoading(); - if (qiangdanRes.data.code === 200 || qiangdanRes.data.code === 0) { - that.showQiangdanSuccessEffect(); - if (app.globalData) { - app.globalData.dashouzhuangtai = 0; - that.setData({ dashouzhuangtai: 0 }); - } - const newList = that.data.dingdanList.filter(item => item.dingdan_id !== dingdanItem.dingdan_id); - that.setData({ dingdanList: newList }); - } else { - wx.showToast({ title: qiangdanRes.data.msg || '抢单失败', icon: 'none' }); - } - } catch (error) { - wx.hideLoading(); - console.error('抢单请求失败:', error); - wx.showToast({ title: '网络错误,抢单失败', icon: 'none' }); - } - } - } - }); - }, - - showQiangdanSuccessEffect() { - wx.showToast({ title: '抢单成功!', icon: 'success', duration: 2000 }); - }, - - onViewDetail(e) { - const { type, content } = e.currentTarget.dataset; - wx.showModal({ - title: type === 'jieshao' ? '订单介绍' : '订单备注', - content: content, - showCancel: false, - confirmText: '知道了' - }); - }, - - 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 }); - this.loadDingdanList(false); - } - }, - - 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) { - this.setData({ scrollViewRefreshing: false }); - return; - } - this.setData({ - scrollViewRefreshing: true, - lastRefreshTime: now - }); - if (this.data.xuanzhongLeixingId) { - this.setData({ page: 1, hasMore: true }); - this.loadDingdanList(true); - } else { - this.setData({ scrollViewRefreshing: false }); - } - }, - - goToDashouRegister() { - wx.navigateTo({ - url: '/pages/dashouduan/dashouduan' - }); - } +// pages/order-pool/order-pool.js +const app = getApp(); +import request from '../../utils/request.js'; +import PopupService from '../../services/popupService.js'; + +Page({ + data: { + // 1. 商品类型相关 + shangpinleixing: [], + xuanzhongLeixingId: null, + + // 2. 订单列表与分页相关 + dingdanList: [], + page: 1, + pageSize: 10, + hasMore: true, + isLoading: false, + + // 3. 全局状态字段 + dashoustatus: null, + zhuanghaoStatus: null, + dashouzhuangtai: null, + uid: null, + huiyuanList: [], + yajin: 0, + jifen: 0, + + // 4. 刷新控制字段 + scrollViewRefreshing: false, + lastRefreshTime: 0, + refreshCooldown: 2000, + isLoadingMore: false, + + // 5. 切换类型冷却时间控制 + lastSwitchTime: 0, + switchCooldown: 1500, + isSwitching: false, + + // 6. 全局OSS地址 + ossImageUrl: app.globalData.ossImageUrl || '', + + // 7. 授权状态控制 + showUnauthorized: false, + unauthorizedMsg: '您尚未开启此功能', + }, + + async onLoad(options) { + this.loadGlobalStatus(); + this.checkAuthorization(); + }, + // 页面隐藏时清理弹窗视图 + onHide: function () { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } +}, + + onShow() { + this.registerNotificationComponent(); + this.loadGlobalStatus(); + this.checkAuthorization(); + }, + + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + loadGlobalStatus() { + const globalData = app.globalData; + const dashoustatusCache = wx.getStorageSync('dashoustatus'); + const dashoustatus = dashoustatusCache !== '' ? dashoustatusCache : null; + + let zhuanghaoStatus = globalData.zhanghaoStatus; + if (zhuanghaoStatus === undefined || zhuanghaoStatus === null) { + zhuanghaoStatus = wx.getStorageSync('zhanghaoStatus'); + } + + this.setData({ + dashoustatus: dashoustatus, + zhuanghaoStatus: zhuanghaoStatus, + dashouzhuangtai: globalData.dashouzhuangtai, + uid: wx.getStorageSync('uid'), + huiyuanList: globalData.clumber || [], + yajin: globalData.yajin || 0, + jifen: globalData.jinfen || 0 + }); + }, + + checkAuthorization() { + const { dashoustatus, zhuanghaoStatus } = this.data; + + const isDashouValid = (dashoustatus && dashoustatus == 1) || false; + const isZhuanghaoValid = (zhuanghaoStatus == 1); + + const isAuthorized = isDashouValid && isZhuanghaoValid; + + if (!isAuthorized) { + this.setData({ showUnauthorized: true }); + let msg = ''; + if (!isDashouValid) msg = '您尚未开启身份'; + this.setData({ unauthorizedMsg: msg || '无法使用抢单功能' }); + } else { + this.setData({ showUnauthorized: false }); + if (!this.data.shangpinleixing.length) { + this.loadShangpinLeixing(); + } else if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + } + PopupService.checkAndShow(this, 'jiedanchi'); + } + }, + + async loadShangpinLeixing() { + wx.showLoading({ title: '加载商品类型...' }); + try { + const res = await request({ + url: '/dingdan/dsqdhqddlx', + method: 'POST', + header: { 'content-type': 'application/json' } + }); + + if (res.statusCode === 200 && res.data) { + const data = res.data; + let list = []; + if (data.code === 200 || data.code === 0) { + if (data.data && Array.isArray(data.data.list)) { + list = data.data.list; + } else if (data.data && Array.isArray(data.data)) { + list = data.data; + } else if (Array.isArray(data.list)) { + list = data.list; + } else if (Array.isArray(data)) { + list = data; + } + } + const processedList = this.processTupianUrl(list); + this.setData({ + shangpinleixing: processedList, + xuanzhongLeixingId: processedList[0]?.id || null + }); + if (this.data.xuanzhongLeixingId) { + this.loadDingdanList(true); + } + } else { + wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none', duration: 2000 }); + } + } catch (error) { + console.error('加载商品类型失败:', error); + wx.showToast({ title: '网络错误,加载失败', icon: 'none', duration: 2000 }); + } finally { + wx.hideLoading(); + } + }, + + processTupianUrl(list) { + const ossUrl = app.globalData.ossImageUrl || ''; + return list.map(item => ({ + ...item, + full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http') ? ossUrl + item.tupian_url : (item.tupian_url || '/images/default-type.png') + })); + }, + + async selectLeixing(e) { + const now = Date.now(); + if (now - this.data.lastSwitchTime < this.data.switchCooldown) { + wx.showToast({ + title: `操作太快,请${Math.ceil((this.data.switchCooldown - (now - this.data.lastSwitchTime)) / 1000)}秒后再试`, + icon: 'none', + duration: 1500 + }); + return; + } + if (this.data.isSwitching) return; + const leixingId = e.currentTarget.dataset.id; + if (leixingId === this.data.xuanzhongLeixingId) return; + this.setData({ isSwitching: true, lastSwitchTime: now }); + wx.showLoading({ title: '切换中...' }); + try { + this.setData({ + xuanzhongLeixingId: leixingId, + dingdanList: [], + page: 1, + hasMore: true + }); + await this.loadDingdanList(true); + } catch (error) { + console.error('切换类型失败:', error); + } finally { + this.setData({ isSwitching: false }); + wx.hideLoading(); + } + }, + + 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; + + this.setData({ + isLoading: true, + isLoadingMore: !isRefresh + }); + + try { + const res = await request({ + url: '/dingdan/ddhq', + method: 'POST', + data: { + leixing_id: this.data.xuanzhongLeixingId, + page: loadPage, + page_size: this.data.pageSize + } + }); + + this.setData({ + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + + if (res.data.code === 200 || res.data.code === 0) { + const newList = res.data.data.list || []; + const hasMore = res.data.data.has_more || false; + + const processedList = newList.map(item => this.processDingdanItem(item)); + + const updatedList = isRefresh ? processedList : [...this.data.dingdanList, ...processedList]; + + updatedList.sort((a, b) => (b.creat_time || '').localeCompare(a.creat_time || '')); + + this.setData({ + dingdanList: updatedList, + page: loadPage, + hasMore: hasMore + }); + + if (isRefresh) { + this.setData({ lastRefreshTime: Date.now() }); + } + } else { + wx.showToast({ title: res.data.msg || '加载失败', icon: 'none' }); + } + } catch (error) { + console.error('加载订单失败:', error); + this.setData({ + isLoading: false, + isLoadingMore: false, + scrollViewRefreshing: false + }); + wx.showToast({ title: '网络请求失败', icon: 'none' }); + } + }, + + processDingdanItem(item) { + const ossUrl = app.globalData.ossImageUrl || ''; + let fullTupianUrl = ''; + if (item.tupian) { + fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian; + } else { + 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; + } + const zhidingNicheng = item.zhiding_nicheng || ''; + + return { + ...item, + full_tupian_url: fullTupianUrl, + isZhiding: isZhiding, + isPingtai: item.pingtai == 1, + isShangjia: item.pingtai == 2, + zhiding_avatar_full: zhidingAvatar, + zhiding_nicheng: zhidingNicheng + }; + }, + + goToChongzhiPage(failureType, huiyuanId = null, requiredYajin = 0) { + let url = '/pages/fighter-recharge/fighter-recharge'; + let params = {}; + switch (failureType) { + case 'huiyuan': + params = { needScroll: '0', scrollTo: 'member' }; + break; + case 'yajin': + params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin }; + break; + case 'jifen': + params = { needScroll: '1', scrollTo: 'bottom' }; + break; + } + if (huiyuanId) params.huiyuanId = huiyuanId; + const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&'); + const fullUrl = `${url}?${queryString}`; + wx.navigateTo({ + url: fullUrl, + fail: (err) => { + console.error('跳转失败:', err); + wx.showToast({ title: '跳转失败,请稍后重试', icon: 'none' }); + } + }); + }, + + async onQiangdanTap(e) { + const dingdanItem = e.currentTarget.dataset.item; + if (!dingdanItem) return; + + if (!this.data.dashoustatus || this.data.dashoustatus != 1) { + wx.showToast({ title: '请先开启打手身份', icon: 'none' }); + return; + } + if (this.data.zhuanghaoStatus != 1) { + wx.showToast({ title: '账号异常,无法接单', icon: 'none' }); + return; + } + if (this.data.dashouzhuangtai != 1) { + wx.showToast({ title: '您有订单正在接待中', icon: 'none' }); + return; + } + if (dingdanItem.isZhiding) { + if (!this.data.uid || this.data.uid != dingdanItem.zhiding_uid) { + wx.showToast({ title: '此订单为指定单', icon: 'none' }); + return; + } + } + if (dingdanItem.yaoqiuleixing == 1) { + const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id); + if (!hasHuiyuan) { + wx.showToast({ title: '未开通对应会员,无法抢单', icon: 'none', duration: 2000 }); + setTimeout(() => this.goToChongzhiPage('huiyuan', dingdanItem.huiyuan_id), 500); + return; + } + } + if (dingdanItem.yaoqiuleixing == 2) { + if (this.data.yajin < dingdanItem.yajin) { + wx.showToast({ title: `押金不足,需${dingdanItem.yajin}`, icon: 'none', duration: 2000 }); + setTimeout(() => this.goToChongzhiPage('yajin', null, dingdanItem.yajin), 500); + return; + } + } + if (this.data.jifen < 5) { + wx.showToast({ title: '积分不足,至少需要5积分', icon: 'none', duration: 2000 }); + setTimeout(() => this.goToChongzhiPage('jifen'), 500); + return; + } + + const that = this; + wx.showModal({ + title: '确认抢单', + content: `确定要抢此订单吗?${dingdanItem.isZhiding ? '(指定订单)' : ''}`, + success: async function (res) { + if (res.confirm) { + wx.showLoading({ title: '抢单中...', mask: true }); + try { + const qiangdanRes = await request({ + url: '/dingdan/qiangdan', + method: 'POST', + data: { dingdan_id: dingdanItem.dingdan_id } + }); + wx.hideLoading(); + if (qiangdanRes.data.code === 200 || qiangdanRes.data.code === 0) { + that.showQiangdanSuccessEffect(); + if (app.globalData) { + app.globalData.dashouzhuangtai = 0; + that.setData({ dashouzhuangtai: 0 }); + } + const newList = that.data.dingdanList.filter(item => item.dingdan_id !== dingdanItem.dingdan_id); + that.setData({ dingdanList: newList }); + } else { + wx.showToast({ title: qiangdanRes.data.msg || '抢单失败', icon: 'none' }); + } + } catch (error) { + wx.hideLoading(); + console.error('抢单请求失败:', error); + wx.showToast({ title: '网络错误,抢单失败', icon: 'none' }); + } + } + } + }); + }, + + showQiangdanSuccessEffect() { + wx.showToast({ title: '抢单成功!', icon: 'success', duration: 2000 }); + }, + + onViewDetail(e) { + const { type, content } = e.currentTarget.dataset; + wx.showModal({ + title: type === 'jieshao' ? '订单介绍' : '订单备注', + content: content, + showCancel: false, + confirmText: '知道了' + }); + }, + + 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 }); + this.loadDingdanList(false); + } + }, + + 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) { + this.setData({ scrollViewRefreshing: false }); + return; + } + this.setData({ + scrollViewRefreshing: true, + lastRefreshTime: now + }); + if (this.data.xuanzhongLeixingId) { + this.setData({ page: 1, hasMore: true }); + this.loadDingdanList(true); + } else { + this.setData({ scrollViewRefreshing: false }); + } + }, + + goToDashouRegister() { + wx.navigateTo({ + url: '/pages/fighter/fighter' + }); + } }); \ No newline at end of file diff --git a/pages/jiedanchi/jiedanchi.json b/pages/order-pool/order-pool.json similarity index 100% rename from pages/jiedanchi/jiedanchi.json rename to pages/order-pool/order-pool.json diff --git a/pages/jiedanchi/jiedanchi.wxml b/pages/order-pool/order-pool.wxml similarity index 100% rename from pages/jiedanchi/jiedanchi.wxml rename to pages/order-pool/order-pool.wxml diff --git a/pages/jiedanchi/jiedanchi.wxss b/pages/order-pool/order-pool.wxss similarity index 98% rename from pages/jiedanchi/jiedanchi.wxss rename to pages/order-pool/order-pool.wxss index 5784b03..863351b 100644 --- a/pages/jiedanchi/jiedanchi.wxss +++ b/pages/order-pool/order-pool.wxss @@ -8,7 +8,7 @@ position: relative; } - /* ====== 授权提示页(机甲风格)====== */ + /* 授权提示页 */ .unauthorized-container { position: absolute; top: 0; @@ -146,7 +146,7 @@ 100% { transform: translateX(100%) rotate(30deg); } } - /* ====== 原有样式(保持不变,仅略作调整以兼容提示页)====== */ + /* 原有样式 */ .leixing-quyu { padding: 30rpx 0 20rpx; background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); diff --git a/pages/order-pool2/order-pool2.js b/pages/order-pool2/order-pool2.js new file mode 100644 index 0000000..5db9a92 --- /dev/null +++ b/pages/order-pool2/order-pool2.js @@ -0,0 +1,39 @@ +// pages/order-pool2/order-pool2.js +Page({ + + data: { + + }, + + onLoad(options) { + + }, + + onReady() { + + }, + + onShow() { + + }, + + onHide() { + + }, + + onUnload() { + + }, + + onPullDownRefresh() { + + }, + + onReachBottom() { + + }, + + onShareAppMessage() { + + } +}) diff --git a/pages/peihuDingdan/peihuDingdan.json b/pages/order-pool2/order-pool2.json similarity index 100% rename from pages/peihuDingdan/peihuDingdan.json rename to pages/order-pool2/order-pool2.json diff --git a/pages/order-pool2/order-pool2.wxml b/pages/order-pool2/order-pool2.wxml new file mode 100644 index 0000000..c6b4014 --- /dev/null +++ b/pages/order-pool2/order-pool2.wxml @@ -0,0 +1,2 @@ + +pages/order-pool2/order-pool2.wxml \ No newline at end of file diff --git a/pages/order-pool2/order-pool2.wxss b/pages/order-pool2/order-pool2.wxss new file mode 100644 index 0000000..1c9293f --- /dev/null +++ b/pages/order-pool2/order-pool2.wxss @@ -0,0 +1 @@ +/* pages/order-pool2/order-pool2.wxss */ \ No newline at end of file diff --git a/pages/dingdan/dingdan.js b/pages/orders/orders.js similarity index 90% rename from pages/dingdan/dingdan.js rename to pages/orders/orders.js index 9e31b53..ebee8ba 100644 --- a/pages/dingdan/dingdan.js +++ b/pages/orders/orders.js @@ -1,287 +1,273 @@ -// pages/dingdan/dingdan.js -const app = getApp() -import request from '../../utils/request.js' - -Page({ - data: { - // 订单状态tab配置 - dingdanZhuangtaiTabs: [ - { name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8] }, - { name: '已下单', key: 'yixiadan', zhuangtaiList: [1, 7] }, - { name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2] }, - { name: '争议订单', key: 'zhengyi', zhuangtaiList: [4, 5, 6] }, - { name: '已完成', key: 'yiwancheng', zhuangtaiList: [3] }, - { name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8] } - ], - - // 当前选中的tab索引 - xuanzhongTabIndex: 0, - // 当前选中的tab的key - currentTabKey: 'all', - - // 每个tab对应的订单数据 - dingdanShuju: { - all: { list: [], page: 1, hasMore: true, isLoading: false }, - yixiadan: { list: [], page: 1, hasMore: true, isLoading: false }, - jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false }, - zhengyi: { list: [], page: 1, hasMore: true, isLoading: false }, - yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false }, - jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false } - }, - - // 个人中心传递过来的type参数 - gerenzhongxinType: '', - - // 是否显示加载更多 - xianshiJiazaigengduo: false, - - // 页面加载状态 - isLoading: true - }, - - onLoad(options) { - const type = options.type || '' - - wx.setNavigationBarTitle({ - title: '我的订单' - }) - - this.qingkongGerenzhongxinJishu(type) - - const tabIndex = this.yingsheTypeToTabIndex(type) - const tabKey = this.data.dingdanZhuangtaiTabs[tabIndex].key - - this.setData({ - gerenzhongxinType: type, - xuanzhongTabIndex: tabIndex, - currentTabKey: tabKey, - isLoading: false - }) - - this.jiazaiDingdanShuju(tabIndex) - }, - onShow() { - // 原有代码... - - // 🆕 注册通知组件 - this.registerNotificationComponent(); -}, - -// 🆕 新增:注册通知组件 -registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - - if (notificationComp && notificationComp.showNotification) { - console.log('🏪 商城页面注册通知组件'); - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } -}, - - - qingkongGerenzhongxinJishu(type) { - const jishuMap = { - 'daifuwu': 'daifuwu', - 'fuwuzhong': 'fuwuzhong', - 'yiwancheng': 'yiwancheng', - 'yituikuan': 'yituikuan' - } - - const jishuKey = jishuMap[type] - if (jishuKey && app.globalData.dingdanTiaoshu) { - app.globalData.dingdanTiaoshu[jishuKey] = 0 - } - }, - - yingsheTypeToTabIndex(type) { - const yingsheMap = { - 'daifuwu': 1, - 'fuwuzhong': 2, - 'yiwancheng': 4, - 'yituikuan': 3 - } - - return yingsheMap[type] || 0 - }, - - switchDingdanTab(e) { - const tabIndex = e.currentTarget.dataset.index - if (tabIndex === this.data.xuanzhongTabIndex) return - - const tabKey = this.data.dingdanZhuangtaiTabs[tabIndex].key - - this.setData({ - xuanzhongTabIndex: tabIndex, - currentTabKey: tabKey - }) - - this.jiazaiDingdanShuju(tabIndex) - }, - - async jiazaiDingdanShuju(tabIndex, isLoadMore = false) { - const tab = this.data.dingdanZhuangtaiTabs[tabIndex] - const tabKey = tab.key - - const tabData = this.data.dingdanShuju[tabKey] - - const page = isLoadMore ? tabData.page + 1 : 1 - - if (tabData.isLoading) return - - // 重置逻辑:如果不是加载更多,清空已有数据 - if (!isLoadMore) { - this.setData({ - [`dingdanShuju.${tabKey}.list`]: [], - [`dingdanShuju.${tabKey}.page`]: 1 - }) - } - - this.setData({ - [`dingdanShuju.${tabKey}.isLoading`]: true - }) - - wx.showLoading({ - title: isLoadMore ? '加载更多...' : '加载订单...', - mask: true - }) - - try { - const requestData = { - zhuangtai_list: tab.zhuangtaiList, - page: page, - page_size: 10 - } - - - - const res = await request({ - url: '/dingdan/dingdanhuoqu', - method: 'POST', - data: requestData, - header: { - 'content-type': 'application/json' - } - }) - - - - wx.hideLoading() - - // ✅ 关键修正:res是直接返回的数据对象,不是res.data - if (res && res.data.code === 0) { - // ✅ 关键修正:直接使用res.data.list - const newDingdanList = res.data.data.list || [] - const hasMore = res.data.data.has_more || false - - - - // 处理图片URL,拼接完整路径 - const processedList = newDingdanList.map(item => { - let tupianUrl = item.tupian || '' - - // 如果图片URL不是完整路径,拼接ossImageUrl - if (tupianUrl && !tupianUrl.startsWith('http')) { - const ossImageUrl = app.globalData.ossImageUrl || '' - tupianUrl = ossImageUrl + tupianUrl - } - - const zhuangtaiZh = this.getZhuangtaiZhongwen(item.zhuangtai) - - - return { - ...item, - tupian: tupianUrl, - zhuangtaiZh: zhuangtaiZh - } - }) - - const currentList = this.data.dingdanShuju[tabKey].list - const updatedList = isLoadMore - ? [...currentList, ...processedList] - : processedList - - this.setData({ - [`dingdanShuju.${tabKey}.list`]: updatedList, - [`dingdanShuju.${tabKey}.page`]: page, - [`dingdanShuju.${tabKey}.hasMore`]: hasMore, - [`dingdanShuju.${tabKey}.isLoading`]: false, - xianshiJiazaigengduo: hasMore - }) - - } else { - wx.showToast({ - title: res ? (res.msg || '加载失败') : '请求失败', - icon: 'none', - duration: 2000 - }) - - this.setData({ - [`dingdanShuju.${tabKey}.isLoading`]: false - }) - } - - } catch (error) { - console.error('加载订单数据失败:', error) - wx.hideLoading() - wx.showToast({ - title: '网络请求失败,请重试', - icon: 'none', - duration: 2000 - }) - - this.setData({ - [`dingdanShuju.${tabKey}.isLoading`]: false - }) - } - }, - - getZhuangtaiZhongwen(zhuangtai) { - const zhuangtaiMap = { - 1: '已下单', - 2: '进行中', - 3: '已完成', - 4: '退款中', - 5: '已退款', - 6: '退款失败', - 7: '指定中', - 8: '结算中' - } - - return zhuangtaiMap[zhuangtai] || '未知状态' - }, - - onReachBottom() { - const tabKey = this.data.currentTabKey - const tabData = this.data.dingdanShuju[tabKey] - - if (tabData.hasMore && !tabData.isLoading) { - const tabIndex = this.data.xuanzhongTabIndex - this.jiazaiDingdanShuju(tabIndex, true) - } - }, - - goToDingdanXiangqing(e) { - const dingdanItem = e.currentTarget.dataset.item - if (!dingdanItem) return - - const dingdanDataStr = encodeURIComponent(JSON.stringify(dingdanItem)) - - wx.navigateTo({ - url: `/pages/dingdanxiangqing/dingdanxiangqing?dingdanData=${dingdanDataStr}` - }) - }, - - onImageError(e) { - const index = e.currentTarget.dataset.index - const tabKey = this.data.currentTabKey - - const defaultImage = app.globalData.lunbozhanwei || '/images/default.jpg' - - this.setData({ - [`dingdanShuju.${tabKey}.list[${index}].tupian`]: defaultImage - }) - } +// pages/orders/orders.js +const app = getApp() +import request from '../../utils/request.js' + +Page({ + data: { + // 订单状态tab配置 + dingdanZhuangtaiTabs: [ + { name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8] }, + { name: '已下单', key: 'yixiadan', zhuangtaiList: [1, 7] }, + { name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2] }, + { name: '争议订单', key: 'zhengyi', zhuangtaiList: [4, 5, 6] }, + { name: '已完成', key: 'yiwancheng', zhuangtaiList: [3] }, + { name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8] } + ], + + // 当前选中的tab索引 + xuanzhongTabIndex: 0, + // 当前选中的tab的key + currentTabKey: 'all', + + // 每个tab对应的订单数据 + dingdanShuju: { + all: { list: [], page: 1, hasMore: true, isLoading: false }, + yixiadan: { list: [], page: 1, hasMore: true, isLoading: false }, + jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false }, + zhengyi: { list: [], page: 1, hasMore: true, isLoading: false }, + yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false }, + jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false } + }, + + // 个人中心传递过来的type参数 + gerenzhongxinType: '', + + // 是否显示加载更多 + xianshiJiazaigengduo: false, + + // 页面加载状态 + isLoading: true + }, + + onLoad(options) { + const type = options.type || '' + + wx.setNavigationBarTitle({ + title: '我的订单' + }) + + this.qingkongGerenzhongxinJishu(type) + + const tabIndex = this.yingsheTypeToTabIndex(type) + const tabKey = this.data.dingdanZhuangtaiTabs[tabIndex].key + + this.setData({ + gerenzhongxinType: type, + xuanzhongTabIndex: tabIndex, + currentTabKey: tabKey, + isLoading: false + }) + + this.jiazaiDingdanShuju(tabIndex) + }, + 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() + }; + } + }, + + qingkongGerenzhongxinJishu(type) { + const jishuMap = { + 'daifuwu': 'daifuwu', + 'fuwuzhong': 'fuwuzhong', + 'yiwancheng': 'yiwancheng', + 'yituikuan': 'yituikuan' + } + + const jishuKey = jishuMap[type] + if (jishuKey && app.globalData.dingdanTiaoshu) { + app.globalData.dingdanTiaoshu[jishuKey] = 0 + } + }, + + yingsheTypeToTabIndex(type) { + const yingsheMap = { + 'daifuwu': 1, + 'fuwuzhong': 2, + 'yiwancheng': 4, + 'yituikuan': 3 + } + + return yingsheMap[type] || 0 + }, + + switchDingdanTab(e) { + const tabIndex = e.currentTarget.dataset.index + if (tabIndex === this.data.xuanzhongTabIndex) return + + const tabKey = this.data.dingdanZhuangtaiTabs[tabIndex].key + + this.setData({ + xuanzhongTabIndex: tabIndex, + currentTabKey: tabKey + }) + + this.jiazaiDingdanShuju(tabIndex) + }, + + async jiazaiDingdanShuju(tabIndex, isLoadMore = false) { + const tab = this.data.dingdanZhuangtaiTabs[tabIndex] + const tabKey = tab.key + + const tabData = this.data.dingdanShuju[tabKey] + + const page = isLoadMore ? tabData.page + 1 : 1 + + if (tabData.isLoading) return + + // 重置逻辑:如果不是加载更多,清空已有数据 + if (!isLoadMore) { + this.setData({ + [`dingdanShuju.${tabKey}.list`]: [], + [`dingdanShuju.${tabKey}.page`]: 1 + }) + } + + this.setData({ + [`dingdanShuju.${tabKey}.isLoading`]: true + }) + + wx.showLoading({ + title: isLoadMore ? '加载更多...' : '加载订单...', + mask: true + }) + + try { + const requestData = { + zhuangtai_list: tab.zhuangtaiList, + page: page, + page_size: 10 + } + + const res = await request({ + url: '/dingdan/dingdanhuoqu', + method: 'POST', + data: requestData, + header: { + 'content-type': 'application/json' + } + }) + + wx.hideLoading() + + // 关键修正:res是直接返回的数据对象 + if (res && res.data.code === 0) { + const newDingdanList = res.data.data.list || [] + const hasMore = res.data.data.has_more || false + + // 处理图片URL,拼接完整路径 + const processedList = newDingdanList.map(item => { + let tupianUrl = item.tupian || '' + + // 如果图片URL不是完整路径,拼接ossImageUrl + if (tupianUrl && !tupianUrl.startsWith('http')) { + const ossImageUrl = app.globalData.ossImageUrl || '' + tupianUrl = ossImageUrl + tupianUrl + } + + const zhuangtaiZh = this.getZhuangtaiZhongwen(item.zhuangtai) + + return { + ...item, + tupian: tupianUrl, + zhuangtaiZh: zhuangtaiZh + } + }) + + const currentList = this.data.dingdanShuju[tabKey].list + const updatedList = isLoadMore + ? [...currentList, ...processedList] + : processedList + + this.setData({ + [`dingdanShuju.${tabKey}.list`]: updatedList, + [`dingdanShuju.${tabKey}.page`]: page, + [`dingdanShuju.${tabKey}.hasMore`]: hasMore, + [`dingdanShuju.${tabKey}.isLoading`]: false, + xianshiJiazaigengduo: hasMore + }) + + } else { + wx.showToast({ + title: res ? (res.msg || '加载失败') : '请求失败', + icon: 'none', + duration: 2000 + }) + + this.setData({ + [`dingdanShuju.${tabKey}.isLoading`]: false + }) + } + + } catch (error) { + console.error('加载订单数据失败:', error) + wx.hideLoading() + wx.showToast({ + title: '网络请求失败,请重试', + icon: 'none', + duration: 2000 + }) + + this.setData({ + [`dingdanShuju.${tabKey}.isLoading`]: false + }) + } + }, + + getZhuangtaiZhongwen(zhuangtai) { + const zhuangtaiMap = { + 1: '已下单', + 2: '进行中', + 3: '已完成', + 4: '退款中', + 5: '已退款', + 6: '退款失败', + 7: '指定中', + 8: '结算中' + } + + return zhuangtaiMap[zhuangtai] || '未知状态' + }, + + onReachBottom() { + const tabKey = this.data.currentTabKey + const tabData = this.data.dingdanShuju[tabKey] + + if (tabData.hasMore && !tabData.isLoading) { + const tabIndex = this.data.xuanzhongTabIndex + this.jiazaiDingdanShuju(tabIndex, true) + } + }, + + goToDingdanXiangqing(e) { + const dingdanItem = e.currentTarget.dataset.item + if (!dingdanItem) return + + const dingdanDataStr = encodeURIComponent(JSON.stringify(dingdanItem)) + + wx.navigateTo({ + url: `/pages/order-detail/order-detail?dingdanData=${dingdanDataStr}` + }) + }, + + onImageError(e) { + const index = e.currentTarget.dataset.index + const tabKey = this.data.currentTabKey + + const defaultImage = app.globalData.lunbozhanwei || '/images/default.jpg' + + this.setData({ + [`dingdanShuju.${tabKey}.list[${index}].tupian`]: defaultImage + }) + } }) \ No newline at end of file diff --git a/pages/sjddxq/sjddxq.json b/pages/orders/orders.json similarity index 100% rename from pages/sjddxq/sjddxq.json rename to pages/orders/orders.json diff --git a/pages/dingdan/dingdan.wxml b/pages/orders/orders.wxml similarity index 95% rename from pages/dingdan/dingdan.wxml rename to pages/orders/orders.wxml index 9d64425..a296496 100644 --- a/pages/dingdan/dingdan.wxml +++ b/pages/orders/orders.wxml @@ -1,111 +1,111 @@ - - - - - - - - - {{item.name}} - - - - - - - - - - - - - 加载中... - - - - - - 暂无订单 - 快去下单体验服务吧 - - - - - - - - - - - - - - - {{item.jieshao || '暂无描述'}} - - - - - - - - {{item.zhuangtaiZh || '未知状态'}} - - - - - ¥ - {{item.jine || '0.00'}} - - - - - - - - - - 上拉加载更多 - - - - - - 没有更多订单了 - - - - - - + + + + + + + + + {{item.name}} + + + + + + + + + + + + + 加载中... + + + + + + 暂无订单 + 快去下单体验服务吧 + + + + + + + + + + + + + + + {{item.jieshao || '暂无描述'}} + + + + + + + + {{item.zhuangtaiZh || '未知状态'}} + + + + + ¥ + {{item.jine || '0.00'}} + + + + + + + + + + 上拉加载更多 + + + + + + 没有更多订单了 + + + + + + diff --git a/pages/dingdan/dingdan.wxss b/pages/orders/orders.wxss similarity index 66% rename from pages/dingdan/dingdan.wxss rename to pages/orders/orders.wxss index afb2316..32f9505 100644 --- a/pages/dingdan/dingdan.wxss +++ b/pages/orders/orders.wxss @@ -1,262 +1,190 @@ -/* pages/dingdan/dingdan.wxss */ - -.dingdan-page { - min-height: 100vh; - background-color: #f8f9fa; - padding-bottom: 20rpx; - } - - .dingdan-tabs-scroll { - width: 100%; - height: 90rpx; - white-space: nowrap; - background-color: #ffffff; - border-bottom: 1rpx solid #f0f0f0; - box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03); - } - - .dingdan-tabs-container { - display: flex; - align-items: center; - height: 100%; - padding: 0 20rpx; - } - - .dingdan-tab-item { - display: inline-flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 60rpx; - padding: 0 30rpx; - margin-right: 20rpx; - border-radius: 30rpx; - background-color: #f5f5f5; - color: #666666; - font-size: 28rpx; - transition: all 0.3s ease; - position: relative; - flex-shrink: 0; - } - - .dingdan-tab-item:last-child { - margin-right: 0; - } - - .dingdan-tab-item.tab-active { - background-color: #e8f5e9; - color: #2e7d32; - font-weight: 500; - box-shadow: 0 4rpx 12rpx rgba(46, 125, 50, 0.1); - } - - .tab-active-line { - width: 40rpx; - height: 4rpx; - background-color: #4caf50; - border-radius: 2rpx; - margin-top: 6rpx; - animation: fadeIn 0.3s ease; - } - - @keyframes fadeIn { - from { opacity: 0; transform: scale(0.8); } - to { opacity: 1; transform: scale(1); } - } - - .tab-text { - font-weight: 400; - } - - .dingdan-list-container { - padding: 20rpx; - } - - .loading-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 400rpx; - } - - .loading-spinner { - width: 60rpx; - height: 60rpx; - border: 6rpx solid #e0e0e0; - border-top-color: #4caf50; - border-radius: 50%; - animation: spin 1s linear infinite; - margin-bottom: 20rpx; - } - - @keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } - } - - .loading-text { - font-size: 28rpx; - color: #999999; - } - - .empty-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 500rpx; - padding-top: 80rpx; - } - - .empty-image { - width: 200rpx; - height: 200rpx; - margin-bottom: 30rpx; - opacity: 0.6; - } - - .empty-text { - font-size: 32rpx; - color: #999999; - margin-bottom: 10rpx; - } - - .empty-subtext { - font-size: 26rpx; - color: #cccccc; - } - - .dingdan-card { - display: flex; - align-items: center; - background-color: #ffffff; - border-radius: 16rpx; - padding: 24rpx; - margin-bottom: 20rpx; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); - transition: transform 0.2s ease, box-shadow 0.2s ease; - } - - .dingdan-card:active { - transform: translateY(-2rpx); - box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.08); - } - - .dingdan-card-left { - flex-shrink: 0; - margin-right: 24rpx; - } - - .dingdan-image { - width: 160rpx; - height: 160rpx; - border-radius: 12rpx; - background-color: #f5f5f5; - } - - .dingdan-card-center { - flex: 1; - height: 160rpx; - display: flex; - align-items: flex-start; - } - - .dingdan-jieshao { - font-size: 28rpx; - line-height: 40rpx; - color: #333333; - font-weight: 400; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; - overflow: hidden; - text-overflow: ellipsis; - } - - .dingdan-card-right { - display: flex; - flex-direction: column; - align-items: flex-end; - justify-content: space-between; - height: 160rpx; - margin-left: 20rpx; - } - - .dingdan-zhuangtai { - font-size: 24rpx; - color: #ff6b6b; - font-weight: 500; - padding: 6rpx 16rpx; - border-radius: 20rpx; - background-color: #fff5f5; - white-space: nowrap; - } - - /* ✅ 修正后的价格样式 - 简单明了 */ - .dingdan-jine { - display: flex; - align-items: center; /* 垂直居中 */ - } - - .jine-symbol { - font-size: 28rpx; - color: #333333; - font-weight: 500; - margin-right: 4rpx; /* 添加右边距,让符号和数字有间隔 */ - } - - .jine-number { - font-size: 32rpx; /* 整数和小数一样大 */ - color: #333333; - font-weight: 600; - } - - .load-more-container { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx 0; - } - - .load-more-line { - width: 80rpx; - height: 1rpx; - background-color: #e0e0e0; - margin: 0 20rpx; - } - - .load-more-text { - font-size: 26rpx; - color: #999999; - white-space: nowrap; - } - - .no-more-container { - text-align: center; - padding: 40rpx 0; - } - - .no-more-text { - font-size: 26rpx; - color: #cccccc; - } - - @media (max-width: 375px) { - .dingdan-image { - width: 140rpx; - height: 140rpx; - } - - .dingdan-card-center { - height: 140rpx; - } - - .dingdan-card-right { - height: 140rpx; - } - - .jine-number { - font-size: 30rpx; - } +/* pages/orders/orders.wxss */ + +.dingdan-page { + background-color: #f8f9fa; + padding-bottom: 20rpx; + } + + .dingdan-tabs-scroll { + width: 100%; + height: 90rpx; + white-space: nowrap; + box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03); + } + + .dingdan-tabs-container { + display: flex; + align-items: center; + height: 100%; + padding: 0 20rpx; + } + + .dingdan-tab-item { + position: relative; + } + + .dingdan-tab-item:last-child { + margin-right: 0; + } + + /* .dingdan-tab-item.tab-active 已由全局 .tab-capsule--active 覆盖 */ + + .tab-active-line { + width: 40rpx; + height: 4rpx; + background-color: #4caf50; + border-radius: 2rpx; + margin-top: 6rpx; + animation: fadeIn 0.3s ease; + } + + @keyframes fadeIn { + from { opacity: 0; transform: scale(0.8); } + to { opacity: 1; transform: scale(1); } + } + + .tab-text { + font-weight: 400; + } + + .dingdan-list-container { + padding: 20rpx; + } + + .loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 400rpx; + } + + .loading-spinner { + border: 6rpx solid #e0e0e0; + border-top-color: #4caf50; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 20rpx; + } + + .loading-text { + font-size: 28rpx; + color: #999999; + } + + .empty-container { + height: 500rpx; + padding-top: 80rpx; + } + + .empty-image { + opacity: 0.6; + } + + .empty-text { + font-size: 32rpx; + color: #999999; + } + + .dingdan-card { + display: flex; + align-items: center; + border-radius: 16rpx; + padding: 24rpx; + margin-bottom: 20rpx; + transition: transform 0.2s ease, box-shadow 0.2s ease; + } + + .dingdan-card:active { + transform: translateY(-2rpx); + box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.08); + } + + .dingdan-card-left { + flex-shrink: 0; + margin-right: 24rpx; + } + + .dingdan-image { + width: 160rpx; + height: 160rpx; + border-radius: 12rpx; + background-color: #f5f5f5; + } + + .dingdan-card-center { + flex: 1; + height: 160rpx; + display: flex; + align-items: flex-start; + } + + .dingdan-jieshao { + font-size: 28rpx; + line-height: 40rpx; + color: #333333; + font-weight: 400; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + overflow: hidden; + text-overflow: ellipsis; + } + + .dingdan-card-right { + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: space-between; + height: 160rpx; + margin-left: 20rpx; + } + + /* 价格样式 */ + .dingdan-jine { + display: flex; + align-items: center; /* 垂直居中 */ + } + + .jine-symbol { + font-size: 28rpx; + color: #333333; + font-weight: 500; + margin-right: 4rpx; /* 添加右边距,让符号和数字有间隔 */ + } + + .jine-number { + font-size: 32rpx; /* 整数和小数一样大 */ + color: #333333; + font-weight: 600; + } + + .load-more-line { + width: 80rpx; + height: 1rpx; + background-color: #e0e0e0; + margin: 0 20rpx; + } + + .load-more-text { + white-space: nowrap; + } + + @media (max-width: 375px) { + .dingdan-image { + width: 140rpx; + height: 140rpx; + } + + .dingdan-card-center { + height: 140rpx; + } + + .dingdan-card-right { + height: 140rpx; + } + + .jine-number { + font-size: 30rpx; + } } \ No newline at end of file diff --git a/pages/peihuDingdan/peihuDingdan.wxml b/pages/peihuDingdan/peihuDingdan.wxml deleted file mode 100644 index 003210f..0000000 --- a/pages/peihuDingdan/peihuDingdan.wxml +++ /dev/null @@ -1,2 +0,0 @@ - -pages/peihuDingdan/peihuDingdan.wxml \ No newline at end of file diff --git a/pages/peihuDingdan/peihuDingdan.wxss b/pages/peihuDingdan/peihuDingdan.wxss deleted file mode 100644 index 17e5091..0000000 --- a/pages/peihuDingdan/peihuDingdan.wxss +++ /dev/null @@ -1 +0,0 @@ -/* pages/peihuDingdan/peihuDingdan.wxss */ \ No newline at end of file diff --git a/pages/cfss/components/fakuan-list/fakuan-list.js b/pages/penalty/components/fakuan-list/fakuan-list.js similarity index 100% rename from pages/cfss/components/fakuan-list/fakuan-list.js rename to pages/penalty/components/fakuan-list/fakuan-list.js diff --git a/pages/penalty/components/fakuan-list/fakuan-list.json b/pages/penalty/components/fakuan-list/fakuan-list.json new file mode 100644 index 0000000..49f6b4d --- /dev/null +++ b/pages/penalty/components/fakuan-list/fakuan-list.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "fakuan-pay": "/pages/penalty/components/fakuan-pay/fakuan-pay" + } +} \ No newline at end of file diff --git a/pages/cfss/components/fakuan-list/fakuan-list.wxml b/pages/penalty/components/fakuan-list/fakuan-list.wxml similarity index 100% rename from pages/cfss/components/fakuan-list/fakuan-list.wxml rename to pages/penalty/components/fakuan-list/fakuan-list.wxml diff --git a/pages/cfss/components/fakuan-list/fakuan-list.wxss b/pages/penalty/components/fakuan-list/fakuan-list.wxss similarity index 100% rename from pages/cfss/components/fakuan-list/fakuan-list.wxss rename to pages/penalty/components/fakuan-list/fakuan-list.wxss diff --git a/pages/cfss/components/fakuan-pay/fakuan-pay.js b/pages/penalty/components/fakuan-pay/fakuan-pay.js similarity index 100% rename from pages/cfss/components/fakuan-pay/fakuan-pay.js rename to pages/penalty/components/fakuan-pay/fakuan-pay.js diff --git a/pages/cfss/components/fakuan-pay/fakuan-pay.json b/pages/penalty/components/fakuan-pay/fakuan-pay.json similarity index 100% rename from pages/cfss/components/fakuan-pay/fakuan-pay.json rename to pages/penalty/components/fakuan-pay/fakuan-pay.json diff --git a/pages/cfss/components/fakuan-pay/fakuan-pay.wxml b/pages/penalty/components/fakuan-pay/fakuan-pay.wxml similarity index 100% rename from pages/cfss/components/fakuan-pay/fakuan-pay.wxml rename to pages/penalty/components/fakuan-pay/fakuan-pay.wxml diff --git a/pages/cfss/components/fakuan-pay/fakuan-pay.wxss b/pages/penalty/components/fakuan-pay/fakuan-pay.wxss similarity index 100% rename from pages/cfss/components/fakuan-pay/fakuan-pay.wxss rename to pages/penalty/components/fakuan-pay/fakuan-pay.wxss diff --git a/pages/cfss/components/jifen-list/jifen-list.js b/pages/penalty/components/jifen-list/jifen-list.js similarity index 100% rename from pages/cfss/components/jifen-list/jifen-list.js rename to pages/penalty/components/jifen-list/jifen-list.js diff --git a/pages/cfss/components/jifen-list/jifen-list.json b/pages/penalty/components/jifen-list/jifen-list.json similarity index 100% rename from pages/cfss/components/jifen-list/jifen-list.json rename to pages/penalty/components/jifen-list/jifen-list.json diff --git a/pages/cfss/components/jifen-list/jifen-list.wxml b/pages/penalty/components/jifen-list/jifen-list.wxml similarity index 100% rename from pages/cfss/components/jifen-list/jifen-list.wxml rename to pages/penalty/components/jifen-list/jifen-list.wxml diff --git a/pages/cfss/components/jifen-list/jifen-list.wxss b/pages/penalty/components/jifen-list/jifen-list.wxss similarity index 100% rename from pages/cfss/components/jifen-list/jifen-list.wxss rename to pages/penalty/components/jifen-list/jifen-list.wxss diff --git a/pages/cfss/cfss/cfss.js b/pages/penalty/penalty/penalty.js similarity index 95% rename from pages/cfss/cfss/cfss.js rename to pages/penalty/penalty/penalty.js index abdec80..467d977 100644 --- a/pages/cfss/cfss/cfss.js +++ b/pages/penalty/penalty/penalty.js @@ -1,100 +1,100 @@ -// pages/cfss/cfss.js -import request from '../../../utils/request.js'; // 向上4级就是根目录 -// 如果有 COS: - -const app = getApp(); - -Page({ - data: { - // 统计数字(由接口 /yonghu/cffktjhq 返回) - stats: { - fakuan: { total: 0, daijiaona: 0, shensuzhong: 0, yijiaona: 0, yibohui: 0 }, - jifen: { total: 0, daichuli: 0, yichuli: 0, daichuli_0: 0, shensuzhong_3: 0, yichufa_1: 0, yibohui_2: 0 } - }, - - // 当前选中的主标签:'fakuan' 或 'jifen' - activeTab: 'fakuan', - - // 子标签状态值 - activeFakuanStatus: 1, // 罚款默认展示“待缴纳” - activeJifenStatus: 0, // 积分默认展示“待处理” - - // 搜索关键词(订单号) - searchDingdan: '', - - // 刷新触发器,传给子组件 - trigger: { - fakuan: 0, - jifen: 0 - } - }, - - onLoad() { - this.fetchTongji(); - }, - - onShow() { - // 每次显示页面都重新拉取统计,确保数字最新 - this.fetchTongji(); - }, - - // 获取综合统计 - async fetchTongji() { - try { - const res = await request({ - url: '/yonghu/cffktjhq', - method: 'POST' - }); - if (res.statusCode === 200 && res.data.code === 0) { - this.setData({ stats: res.data.data }); - } - } catch (error) { - console.error('获取处罚统计失败', error); - } - }, - - // 切换主Tab(罚款 / 积分) - switchMainTab(e) { - const tab = e.currentTarget.dataset.tab; - if (tab === this.data.activeTab) return; - this.setData({ activeTab: tab }); - }, - - // 切换罚款状态子标签 - switchFakuanStatus(e) { - const status = Number(e.currentTarget.dataset.status); - if (status === this.data.activeFakuanStatus) return; - this.setData({ activeFakuanStatus: status }); - this.bumpTrigger('fakuan'); // 通知罚款列表组件刷新 - }, - - // 切换积分状态子标签 - switchJifenStatus(e) { - const status = Number(e.currentTarget.dataset.status); - if (status === this.data.activeJifenStatus) return; - this.setData({ activeJifenStatus: status }); - this.bumpTrigger('jifen'); // 通知积分列表组件刷新 - }, - - // 搜索输入 - onSearchInput(e) { - this.setData({ searchDingdan: e.detail.value }); - }, - - // 执行搜索(按键盘搜索按钮或点击搜索图标) - onSearchConfirm() { - this.bumpTrigger(this.data.activeTab); - }, - - // 清空搜索关键字 - clearSearch() { - this.setData({ searchDingdan: '' }); - this.bumpTrigger(this.data.activeTab); - }, - - // 递增触发器,子组件通过 observer 响应 - bumpTrigger(tab) { - const key = `trigger.${tab}`; - this.setData({ [key]: this.data.trigger[tab] + 1 }); - } +// pages/penalty/penalty.js +import request from '../../../utils/request.js'; // 向上4级就是根目录 +// 如果有 COS: + +const app = getApp(); + +Page({ + data: { + // 统计数字(由接口 /yonghu/cffktjhq 返回) + stats: { + fakuan: { total: 0, daijiaona: 0, shensuzhong: 0, yijiaona: 0, yibohui: 0 }, + jifen: { total: 0, daichuli: 0, yichuli: 0, daichuli_0: 0, shensuzhong_3: 0, yichufa_1: 0, yibohui_2: 0 } + }, + + // 当前选中的主标签:'fakuan' 或 'jifen' + activeTab: 'fakuan', + + // 子标签状态值 + activeFakuanStatus: 1, // 罚款默认展示“待缴纳” + activeJifenStatus: 0, // 积分默认展示“待处理” + + // 搜索关键词(订单号) + searchDingdan: '', + + // 刷新触发器,传给子组件 + trigger: { + fakuan: 0, + jifen: 0 + } + }, + + onLoad() { + this.fetchTongji(); + }, + + onShow() { + // 每次显示页面都重新拉取统计,确保数字最新 + this.fetchTongji(); + }, + + // 获取综合统计 + async fetchTongji() { + try { + const res = await request({ + url: '/yonghu/cffktjhq', + method: 'POST' + }); + if (res.statusCode === 200 && res.data.code === 0) { + this.setData({ stats: res.data.data }); + } + } catch (error) { + console.error('获取处罚统计失败', error); + } + }, + + // 切换主Tab(罚款 / 积分) + switchMainTab(e) { + const tab = e.currentTarget.dataset.tab; + if (tab === this.data.activeTab) return; + this.setData({ activeTab: tab }); + }, + + // 切换罚款状态子标签 + switchFakuanStatus(e) { + const status = Number(e.currentTarget.dataset.status); + if (status === this.data.activeFakuanStatus) return; + this.setData({ activeFakuanStatus: status }); + this.bumpTrigger('fakuan'); // 通知罚款列表组件刷新 + }, + + // 切换积分状态子标签 + switchJifenStatus(e) { + const status = Number(e.currentTarget.dataset.status); + if (status === this.data.activeJifenStatus) return; + this.setData({ activeJifenStatus: status }); + this.bumpTrigger('jifen'); // 通知积分列表组件刷新 + }, + + // 搜索输入 + onSearchInput(e) { + this.setData({ searchDingdan: e.detail.value }); + }, + + // 执行搜索(按键盘搜索按钮或点击搜索图标) + onSearchConfirm() { + this.bumpTrigger(this.data.activeTab); + }, + + // 清空搜索关键字 + clearSearch() { + this.setData({ searchDingdan: '' }); + this.bumpTrigger(this.data.activeTab); + }, + + // 递增触发器,子组件通过 observer 响应 + bumpTrigger(tab) { + const key = `trigger.${tab}`; + this.setData({ [key]: this.data.trigger[tab] + 1 }); + } }); \ No newline at end of file diff --git a/pages/cfss/cfss/cfss.json b/pages/penalty/penalty/penalty.json similarity index 56% rename from pages/cfss/cfss/cfss.json rename to pages/penalty/penalty/penalty.json index 4ca406b..df84999 100644 --- a/pages/cfss/cfss/cfss.json +++ b/pages/penalty/penalty/penalty.json @@ -1,10 +1,10 @@ -{ - "usingComponents": { - "fakuan-list": "/pages/cfss/components/fakuan-list/fakuan-list", - "jifen-list": "/pages/cfss/components/jifen-list/jifen-list" - }, - "navigationBarTitleText": "处罚中心", - "navigationBarBackgroundColor": "#ffffff", - "navigationBarTextStyle": "black", - "backgroundColor": "#f7f8fa" +{ + "usingComponents": { + "fakuan-list": "/pages/penalty/components/fakuan-list/fakuan-list", + "jifen-list": "/pages/penalty/components/jifen-list/jifen-list" + }, + "navigationBarTitleText": "处罚中心", + "navigationBarBackgroundColor": "#ffffff", + "navigationBarTextStyle": "black", + "backgroundColor": "#f7f8fa" } \ No newline at end of file diff --git a/pages/cfss/cfss/cfss.wxml b/pages/penalty/penalty/penalty.wxml similarity index 96% rename from pages/cfss/cfss/cfss.wxml rename to pages/penalty/penalty/penalty.wxml index 03e8517..fcc9811 100644 --- a/pages/cfss/cfss/cfss.wxml +++ b/pages/penalty/penalty/penalty.wxml @@ -1,68 +1,68 @@ - - - - - - - {{ stats.fakuan.daijiaona }} - 待缴罚款 - - - {{ stats.jifen.daichuli }} - 待处理积分 - - - - 罚款:已缴{{ stats.fakuan.yijiaona }} · 申诉中{{ stats.fakuan.shensuzhong }} · 成功{{ stats.fakuan.yibohui }} - 积分:已处理{{ stats.jifen.yichuli }} - - - - - - - 罚款 - - - 积分处罚 - - - - - - - 待缴纳 {{ stats.fakuan.daijiaona }} - 申诉中 {{ stats.fakuan.shensuzhong }} - 已缴纳 {{ stats.fakuan.yijiaona }} - 申诉成功 {{ stats.fakuan.yibohui }} - - - - - 待处理 {{ stats.jifen.daichuli }} - 已处理 {{ stats.jifen.yichuli }} - - - - - - - 搜索 - - - - - - - - - - + + + + + + + {{ stats.fakuan.daijiaona }} + 待缴罚款 + + + {{ stats.jifen.daichuli }} + 待处理积分 + + + + 罚款:已缴{{ stats.fakuan.yijiaona }} · 申诉中{{ stats.fakuan.shensuzhong }} · 成功{{ stats.fakuan.yibohui }} + 积分:已处理{{ stats.jifen.yichuli }} + + + + + + + 罚款 + + + 积分处罚 + + + + + + + 待缴纳 {{ stats.fakuan.daijiaona }} + 申诉中 {{ stats.fakuan.shensuzhong }} + 已缴纳 {{ stats.fakuan.yijiaona }} + 申诉成功 {{ stats.fakuan.yibohui }} + + + + + 待处理 {{ stats.jifen.daichuli }} + 已处理 {{ stats.jifen.yichuli }} + + + + + + + 搜索 + + + + + + + + + + \ No newline at end of file diff --git a/pages/cfss/cfss/cfss.wxss b/pages/penalty/penalty/penalty.wxss similarity index 93% rename from pages/cfss/cfss/cfss.wxss rename to pages/penalty/penalty/penalty.wxss index 4cd5d19..4a57b00 100644 --- a/pages/cfss/cfss/cfss.wxss +++ b/pages/penalty/penalty/penalty.wxss @@ -1,121 +1,121 @@ -/* pages/cfss/cfss.wxss */ -page { background: #f7f8fa; font-family: -apple-system, BlinkMacSystemFont, sans-serif; } - -.page-container { padding-bottom: 30rpx; } - -/* 统计卡片 */ -.stats-card { - margin: 24rpx 28rpx; - padding: 30rpx 24rpx; - background: #fff; - border-radius: 24rpx; - box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); -} -.stats-number-row { - display: flex; - justify-content: space-around; - margin-bottom: 20rpx; -} -.number-block { - display: flex; - flex-direction: column; - align-items: center; -} -.big-num { - font-size: 56rpx; - font-weight: 700; -} -.green { color: #2E7D32; } -.orange { color: #E67E22; } -.num-label { - font-size: 24rpx; - color: #888; - margin-top: 8rpx; -} -.stats-detail-row { - border-top: 1rpx solid #eee; - padding-top: 18rpx; -} -.stats-detail-row text { - display: block; - font-size: 22rpx; - color: #aaa; - margin-bottom: 4rpx; -} - -/* 主Tab */ -.tab-row { - display: flex; - margin: 16rpx 28rpx; - background: #fff; - border-radius: 18rpx; - overflow: hidden; - box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.02); -} -.tab-item { - flex: 1; - text-align: center; - padding: 24rpx 0; - font-size: 28rpx; - color: #666; - transition: 0.2s; -} -.tab-item.active { - color: #2E7D32; - font-weight: 600; - background: #F0F9F0; -} - -/* 子状态标签 */ -.sub-tabs { - white-space: nowrap; - margin: 8rpx 28rpx 16rpx; -} -.sub-tag { - display: inline-block; - padding: 10rpx 26rpx; - margin-right: 14rpx; - background: #fff; - border-radius: 30rpx; - font-size: 24rpx; - color: #888; - box-shadow: 0 1rpx 4rpx rgba(0,0,0,0.02); -} -.sub-tag.sub-active { - background: #E8F5E9; - color: #2E7D32; - font-weight: 600; -} - -/* 搜索栏 */ -.search-bar { - display: flex; - align-items: center; - margin: 16rpx 28rpx; - background: #fff; - border-radius: 20rpx; - padding: 12rpx 22rpx; - box-shadow: 0 1rpx 6rpx rgba(0,0,0,0.02); -} -.search-input { - flex: 1; - font-size: 26rpx; - color: #333; -} -.search-btn { - margin-left: 18rpx; - padding: 12rpx 30rpx; - background: #2E7D32; - color: #fff; - border-radius: 16rpx; - font-size: 24rpx; -} -.clear-btn { - margin-left: 16rpx; - font-size: 30rpx; - color: #aaa; -} - -.list-area { - margin-top: 10rpx; +/* pages/penalty/penalty.wxss */ +page { background: #f7f8fa; font-family: -apple-system, BlinkMacSystemFont, sans-serif; } + +.page-container { padding-bottom: 30rpx; } + +/* 统计卡片 */ +.stats-card { + margin: 24rpx 28rpx; + padding: 30rpx 24rpx; + background: #fff; + border-radius: 24rpx; + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); +} +.stats-number-row { + display: flex; + justify-content: space-around; + margin-bottom: 20rpx; +} +.number-block { + display: flex; + flex-direction: column; + align-items: center; +} +.big-num { + font-size: 56rpx; + font-weight: 700; +} +.green { color: #2E7D32; } +.orange { color: #E67E22; } +.num-label { + font-size: 24rpx; + color: #888; + margin-top: 8rpx; +} +.stats-detail-row { + border-top: 1rpx solid #eee; + padding-top: 18rpx; +} +.stats-detail-row text { + display: block; + font-size: 22rpx; + color: #aaa; + margin-bottom: 4rpx; +} + +/* 主Tab */ +.tab-row { + display: flex; + margin: 16rpx 28rpx; + background: #fff; + border-radius: 18rpx; + overflow: hidden; + box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.02); +} +.tab-item { + flex: 1; + text-align: center; + padding: 24rpx 0; + font-size: 28rpx; + color: #666; + transition: 0.2s; +} +.tab-item.active { + color: #2E7D32; + font-weight: 600; + background: #F0F9F0; +} + +/* 子状态标签 */ +.sub-tabs { + white-space: nowrap; + margin: 8rpx 28rpx 16rpx; +} +.sub-tag { + display: inline-block; + padding: 10rpx 26rpx; + margin-right: 14rpx; + background: #fff; + border-radius: 30rpx; + font-size: 24rpx; + color: #888; + box-shadow: 0 1rpx 4rpx rgba(0,0,0,0.02); +} +.sub-tag.sub-active { + background: #E8F5E9; + color: #2E7D32; + font-weight: 600; +} + +/* 搜索栏 */ +.search-bar { + display: flex; + align-items: center; + margin: 16rpx 28rpx; + background: #fff; + border-radius: 20rpx; + padding: 12rpx 22rpx; + box-shadow: 0 1rpx 6rpx rgba(0,0,0,0.02); +} +.search-input { + flex: 1; + font-size: 26rpx; + color: #333; +} +.search-btn { + margin-left: 18rpx; + padding: 12rpx 30rpx; + background: #2E7D32; + color: #fff; + border-radius: 16rpx; + font-size: 24rpx; +} +.clear-btn { + margin-left: 16rpx; + font-size: 30rpx; + color: #aaa; +} + +.list-area { + margin-top: 10rpx; } \ No newline at end of file diff --git a/pages/jiedanchi2/jiedanchi2.js b/pages/pick-user/pick-user.js similarity index 89% rename from pages/jiedanchi2/jiedanchi2.js rename to pages/pick-user/pick-user.js index 0e33db9..1e3bd36 100644 --- a/pages/jiedanchi2/jiedanchi2.js +++ b/pages/pick-user/pick-user.js @@ -1,66 +1,66 @@ -// pages/jiedanchi2/jiedanchi2.js -Page({ - - /** - * 页面的初始数据 - */ - data: { - - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - - } +// pages/pick-user/pick-user.js +Page({ + + /** + * 页面的初始数据 + */ + data: { + + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad(options) { + + }, + + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady() { + + }, + + /** + * 生命周期函数--监听页面显示 + */ + onShow() { + + }, + + /** + * 生命周期函数--监听页面隐藏 + */ + onHide() { + + }, + + /** + * 生命周期函数--监听页面卸载 + */ + onUnload() { + + }, + + /** + * 页面相关事件处理函数--监听用户下拉动作 + */ + onPullDownRefresh() { + + }, + + /** + * 页面上拉触底事件的处理函数 + */ + onReachBottom() { + + }, + + /** + * 用户点击右上角分享 + */ + onShareAppMessage() { + + } }) \ No newline at end of file diff --git a/pages/xuanren/xuanren.json b/pages/pick-user/pick-user.json similarity index 100% rename from pages/xuanren/xuanren.json rename to pages/pick-user/pick-user.json diff --git a/pages/xuanren/xuanren.wxml b/pages/pick-user/pick-user.wxml similarity index 100% rename from pages/xuanren/xuanren.wxml rename to pages/pick-user/pick-user.wxml diff --git a/pages/pick-user/pick-user.wxss b/pages/pick-user/pick-user.wxss new file mode 100644 index 0000000..1fe63ab --- /dev/null +++ b/pages/pick-user/pick-user.wxss @@ -0,0 +1 @@ +/* pages/pick-user/pick-user.wxss */ \ No newline at end of file diff --git a/pages/haibao/haibao.js b/pages/poster/poster.js similarity index 96% rename from pages/haibao/haibao.js rename to pages/poster/poster.js index 3985d30..cb57a14 100644 --- a/pages/haibao/haibao.js +++ b/pages/poster/poster.js @@ -1,281 +1,281 @@ -// pages/haibao/haibao.js -import request from '../../utils/request.js'; - -const app = getApp(); - -Page({ - data: { - qrcodeUrl: '', - isLoading: false, - showPosterCanvas: false, - posterImageTemp: '', - avatarUrl: '', - uid: '', - nickName: '', - }, - - onLoad() { - this.loadQRCodeFromCache(); - this.loadUserInfo(); - }, - - onShow() { - this.registerNotificationComponent(); - }, - - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - loadQRCodeFromCache() { - try { - const relativeUrl = wx.getStorageSync('haibao_url'); - if (relativeUrl) { - const fullUrl = this.getFullImageUrl(relativeUrl); - this.setData({ qrcodeUrl: fullUrl }); - } else { - this.setData({ qrcodeUrl: '' }); - } - } catch (error) { - console.error('读取缓存失败', error); - } - }, - - loadUserInfo() { - const touxiang = wx.getStorageSync('touxiang'); - const ossUrl = app.globalData.ossImageUrl || ''; - const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); - let avatarUrl = defaultAvatar; - if (touxiang && typeof touxiang === 'string' && touxiang.trim() !== '') { - avatarUrl = this.getFullImageUrl(touxiang); - } - const uid = wx.getStorageSync('uid') || ''; - let nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '管事'; - this.setData({ avatarUrl, uid, nickName }); - }, - - getFullImageUrl(url) { - if (!url) return ''; - const ossUrl = app.globalData.ossImageUrl || ''; - return url.startsWith('http') ? url : ossUrl + url; - }, - - refreshQRCode() { - if (this.data.isLoading) return; - this.setData({ isLoading: true }); - request({ - url: '/peizhi/guanshiewm', - method: 'POST', - }).then(res => { - if (res.data && res.data.code === 0) { - const relativeUrl = res.data.data.url; - if (relativeUrl) { - wx.setStorageSync('haibao_url', relativeUrl); - const fullUrl = this.getFullImageUrl(relativeUrl); - this.setData({ qrcodeUrl: fullUrl }); - wx.showToast({ title: '获取成功', icon: 'success' }); - } else { - wx.showToast({ title: '返回数据异常', icon: 'none' }); - } - } else { - wx.showToast({ title: res.data.msg || '获取失败', icon: 'none' }); - } - }).catch(err => { - console.error('获取海报失败', err); - wx.showToast({ title: '网络错误', icon: 'none' }); - }).finally(() => { - this.setData({ isLoading: false }); - }); - }, - - // 🔥【修改】保存二维码到相册(先下载网络图片) - saveToAlbum() { - if (!this.data.qrcodeUrl) { - wx.showToast({ title: '暂无二维码', icon: 'none' }); - return; - } - - wx.showLoading({ title: '保存中...', mask: true }); - wx.downloadFile({ - url: this.data.qrcodeUrl, - success: (res) => { - wx.hideLoading(); - if (res.statusCode === 200) { - // 调用已有的保存函数(传入临时路径) - this.downloadAndSave(res.tempFilePath); - } else { - wx.showToast({ title: '下载失败', icon: 'none' }); - } - }, - fail: (err) => { - wx.hideLoading(); - console.error('下载二维码失败', err); - wx.showToast({ title: '下载失败', icon: 'none' }); - } - }); - }, - - generateMyPoster() { - if (!this.data.qrcodeUrl) { - wx.showToast({ title: '请先生成二维码', icon: 'none' }); - return; - } - - wx.showLoading({ title: '生成海报中...', mask: true }); - - const ossUrl = app.globalData.ossImageUrl || ''; - const bgUrl = ossUrl + 'beijing/haibaobeijing.jpg'; - const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl]; - - const promises = urls.map(url => this.loadImage(url)); - Promise.all(promises) - .then((images) => { - wx.hideLoading(); - this.setData({ showPosterCanvas: true }, () => { - setTimeout(() => { - this.drawPoster(images[0], images[1], images[2]); - }, 200); - }); - }) - .catch((err) => { - wx.hideLoading(); - wx.showToast({ title: '图片加载失败', icon: 'none' }); - console.error('图片加载失败', err); - }); - }, - - loadImage(url) { - return new Promise((resolve, reject) => { - wx.getImageInfo({ - src: url, - success: (res) => resolve(res.path), - fail: reject - }); - }); - }, - - drawPoster(bgPath, qrPath, avatarPath) { - const ctx = wx.createCanvasContext('posterCanvas', this); - const query = wx.createSelectorQuery().in(this); - query.select('.poster-canvas').boundingClientRect(rect => { - if (!rect) { - wx.showToast({ title: '画布获取失败', icon: 'none' }); - return; - } - const canvasWidth = rect.width; - const canvasHeight = rect.height; - - // 1. 绘制背景 - ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight); - - const qrSize = 100; - const margin = 5; - const qrX = canvasWidth - qrSize - margin; - const qrY = canvasHeight - qrSize - margin; - ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize); - - const avatarSize = 60; - const avatarX = margin + 20; - const avatarY = canvasHeight - avatarSize - margin; - ctx.save(); - ctx.beginPath(); - ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI); - ctx.clip(); - ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize); - ctx.restore(); - - ctx.setFontSize(16); - ctx.setFillStyle('#333333'); - ctx.setTextAlign('left'); - - let nick = this.data.nickName || '管事'; - if (nick.length > 3) { - nick = nick.substring(0, 3) + '...'; - } - const nameText = nick; - - const textX = avatarX + avatarSize + 8; - const textY = avatarY + avatarSize/2 + 6; - ctx.fillText(nameText, textX, textY); - - ctx.setFontSize(18); - ctx.setFillStyle('#ffaa00'); - ctx.setTextAlign('left'); - const slogan = '快来加入我们 ✦'; - const sloganX = avatarX; - const sloganY = avatarY - 12; - ctx.fillText(slogan, sloganX, sloganY); - - ctx.draw(false, () => { - wx.canvasToTempFilePath({ - canvasId: 'posterCanvas', - success: (res) => { - this.setData({ posterImageTemp: res.tempFilePath }); - }, - fail: (err) => { - console.error('生成海报临时文件失败', err); - } - }, this); - }); - }).exec(); - }, - - savePoster() { - if (!this.data.posterImageTemp) { - wx.showToast({ title: '海报尚未生成', icon: 'none' }); - return; - } - this.downloadAndSave(this.data.posterImageTemp); - }, - - hidePoster() { - this.setData({ showPosterCanvas: false, posterImageTemp: '' }); - }, - - downloadAndSave(filePath) { - wx.getSetting({ - success: (res) => { - if (!res.authSetting['scope.writePhotosAlbum']) { - wx.authorize({ - scope: 'scope.writePhotosAlbum', - success: () => { - this._saveImage(filePath); - }, - fail: () => { - wx.showModal({ - title: '提示', - content: '需要您授权保存到相册', - success: (modalRes) => { - if (modalRes.confirm) { - wx.openSetting(); - } - } - }); - } - }); - } else { - this._saveImage(filePath); - } - } - }); - }, - - _saveImage(filePath) { - wx.saveImageToPhotosAlbum({ - filePath: filePath, - success: () => { - wx.showToast({ title: '保存成功', icon: 'success' }); - }, - fail: (err) => { - console.error('保存失败', err); - wx.showToast({ title: '保存失败', icon: 'none' }); - } - }); - }, +// pages/poster/poster.js +import request from '../../utils/request.js'; + +const app = getApp(); + +Page({ + data: { + qrcodeUrl: '', + isLoading: false, + showPosterCanvas: false, + posterImageTemp: '', + avatarUrl: '', + uid: '', + nickName: '', + }, + + onLoad() { + this.loadQRCodeFromCache(); + this.loadUserInfo(); + }, + + onShow() { + this.registerNotificationComponent(); + }, + + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + loadQRCodeFromCache() { + try { + const relativeUrl = wx.getStorageSync('haibao_url'); + if (relativeUrl) { + const fullUrl = this.getFullImageUrl(relativeUrl); + this.setData({ qrcodeUrl: fullUrl }); + } else { + this.setData({ qrcodeUrl: '' }); + } + } catch (error) { + console.error('读取缓存失败', error); + } + }, + + loadUserInfo() { + const touxiang = wx.getStorageSync('touxiang'); + const ossUrl = app.globalData.ossImageUrl || ''; + const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg'); + let avatarUrl = defaultAvatar; + if (touxiang && typeof touxiang === 'string' && touxiang.trim() !== '') { + avatarUrl = this.getFullImageUrl(touxiang); + } + const uid = wx.getStorageSync('uid') || ''; + let nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '管事'; + this.setData({ avatarUrl, uid, nickName }); + }, + + getFullImageUrl(url) { + if (!url) return ''; + const ossUrl = app.globalData.ossImageUrl || ''; + return url.startsWith('http') ? url : ossUrl + url; + }, + + refreshQRCode() { + if (this.data.isLoading) return; + this.setData({ isLoading: true }); + request({ + url: '/peizhi/guanshiewm', + method: 'POST', + }).then(res => { + if (res.data && res.data.code === 0) { + const relativeUrl = res.data.data.url; + if (relativeUrl) { + wx.setStorageSync('haibao_url', relativeUrl); + const fullUrl = this.getFullImageUrl(relativeUrl); + this.setData({ qrcodeUrl: fullUrl }); + wx.showToast({ title: '获取成功', icon: 'success' }); + } else { + wx.showToast({ title: '返回数据异常', icon: 'none' }); + } + } else { + wx.showToast({ title: res.data.msg || '获取失败', icon: 'none' }); + } + }).catch(err => { + console.error('获取海报失败', err); + wx.showToast({ title: '网络错误', icon: 'none' }); + }).finally(() => { + this.setData({ isLoading: false }); + }); + }, + + // 🔥【修改】保存二维码到相册(先下载网络图片) + saveToAlbum() { + if (!this.data.qrcodeUrl) { + wx.showToast({ title: '暂无二维码', icon: 'none' }); + return; + } + + wx.showLoading({ title: '保存中...', mask: true }); + wx.downloadFile({ + url: this.data.qrcodeUrl, + success: (res) => { + wx.hideLoading(); + if (res.statusCode === 200) { + // 调用已有的保存函数(传入临时路径) + this.downloadAndSave(res.tempFilePath); + } else { + wx.showToast({ title: '下载失败', icon: 'none' }); + } + }, + fail: (err) => { + wx.hideLoading(); + console.error('下载二维码失败', err); + wx.showToast({ title: '下载失败', icon: 'none' }); + } + }); + }, + + generateMyPoster() { + if (!this.data.qrcodeUrl) { + wx.showToast({ title: '请先生成二维码', icon: 'none' }); + return; + } + + wx.showLoading({ title: '生成海报中...', mask: true }); + + const ossUrl = app.globalData.ossImageUrl || ''; + const bgUrl = ossUrl + 'beijing/haibaobeijing.jpg'; + const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl]; + + const promises = urls.map(url => this.loadImage(url)); + Promise.all(promises) + .then((images) => { + wx.hideLoading(); + this.setData({ showPosterCanvas: true }, () => { + setTimeout(() => { + this.drawPoster(images[0], images[1], images[2]); + }, 200); + }); + }) + .catch((err) => { + wx.hideLoading(); + wx.showToast({ title: '图片加载失败', icon: 'none' }); + console.error('图片加载失败', err); + }); + }, + + loadImage(url) { + return new Promise((resolve, reject) => { + wx.getImageInfo({ + src: url, + success: (res) => resolve(res.path), + fail: reject + }); + }); + }, + + drawPoster(bgPath, qrPath, avatarPath) { + const ctx = wx.createCanvasContext('posterCanvas', this); + const query = wx.createSelectorQuery().in(this); + query.select('.poster-canvas').boundingClientRect(rect => { + if (!rect) { + wx.showToast({ title: '画布获取失败', icon: 'none' }); + return; + } + const canvasWidth = rect.width; + const canvasHeight = rect.height; + + // 1. 绘制背景 + ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight); + + const qrSize = 100; + const margin = 5; + const qrX = canvasWidth - qrSize - margin; + const qrY = canvasHeight - qrSize - margin; + ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize); + + const avatarSize = 60; + const avatarX = margin + 20; + const avatarY = canvasHeight - avatarSize - margin; + ctx.save(); + ctx.beginPath(); + ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI); + ctx.clip(); + ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize); + ctx.restore(); + + ctx.setFontSize(16); + ctx.setFillStyle('#333333'); + ctx.setTextAlign('left'); + + let nick = this.data.nickName || '管事'; + if (nick.length > 3) { + nick = nick.substring(0, 3) + '...'; + } + const nameText = nick; + + const textX = avatarX + avatarSize + 8; + const textY = avatarY + avatarSize/2 + 6; + ctx.fillText(nameText, textX, textY); + + ctx.setFontSize(18); + ctx.setFillStyle('#ffaa00'); + ctx.setTextAlign('left'); + const slogan = '快来加入我们 ✦'; + const sloganX = avatarX; + const sloganY = avatarY - 12; + ctx.fillText(slogan, sloganX, sloganY); + + ctx.draw(false, () => { + wx.canvasToTempFilePath({ + canvasId: 'posterCanvas', + success: (res) => { + this.setData({ posterImageTemp: res.tempFilePath }); + }, + fail: (err) => { + console.error('生成海报临时文件失败', err); + } + }, this); + }); + }).exec(); + }, + + savePoster() { + if (!this.data.posterImageTemp) { + wx.showToast({ title: '海报尚未生成', icon: 'none' }); + return; + } + this.downloadAndSave(this.data.posterImageTemp); + }, + + hidePoster() { + this.setData({ showPosterCanvas: false, posterImageTemp: '' }); + }, + + downloadAndSave(filePath) { + wx.getSetting({ + success: (res) => { + if (!res.authSetting['scope.writePhotosAlbum']) { + wx.authorize({ + scope: 'scope.writePhotosAlbum', + success: () => { + this._saveImage(filePath); + }, + fail: () => { + wx.showModal({ + title: '提示', + content: '需要您授权保存到相册', + success: (modalRes) => { + if (modalRes.confirm) { + wx.openSetting(); + } + } + }); + } + }); + } else { + this._saveImage(filePath); + } + } + }); + }, + + _saveImage(filePath) { + wx.saveImageToPhotosAlbum({ + filePath: filePath, + success: () => { + wx.showToast({ title: '保存成功', icon: 'success' }); + }, + fail: (err) => { + console.error('保存失败', err); + wx.showToast({ title: '保存失败', icon: 'none' }); + } + }); + }, }); \ No newline at end of file diff --git a/pages/haibao/haibao.json b/pages/poster/poster.json similarity index 100% rename from pages/haibao/haibao.json rename to pages/poster/poster.json diff --git a/pages/haibao/haibao.wxml b/pages/poster/poster.wxml similarity index 100% rename from pages/haibao/haibao.wxml rename to pages/poster/poster.wxml diff --git a/pages/haibao/haibao.wxss b/pages/poster/poster.wxss similarity index 100% rename from pages/haibao/haibao.wxss rename to pages/poster/poster.wxss diff --git a/pages/shangpinxiangqing/shangpinxiangqing.js b/pages/product-detail/product-detail.js similarity index 64% rename from pages/shangpinxiangqing/shangpinxiangqing.js rename to pages/product-detail/product-detail.js index 4ef2c34..f619c1f 100644 --- a/pages/shangpinxiangqing/shangpinxiangqing.js +++ b/pages/product-detail/product-detail.js @@ -1,295 +1,249 @@ -// pages/shangpinxiangqing/shangpinxiangqing.js -const app = getApp() -import { ensureLogin } from '../../utils/login' -import { backfillUserProfileCache } from '../../utils/role-tab-bar' - -Page({ - /** - * 页面的初始数据 - */ - data: { - // 全局变量引用 - ossImageUrl: '', - apiBaseUrl: '', - - // 从上级页面传入的参数 - shangpinId: '', // 商品ID - shangpinTitle: '', // 商品标题(可选,用于SEO) - shangpinPrice: '', // 商品价格(可选) - - // 商品详情数据 - shangpinData: null, // 商品详情数据对象 - isLoading: true, // 加载状态 - loadError: false, // 加载错误 - - // 页面字段映射(后端返回字段名) - fieldMapping: { - tupian: 'tupian', // 商品图片URL - biaoti: 'biaoti', // 商品标题 - jiage: 'jiage', // 商品价格 - xiangqing: 'xiangqing', // 商品详细介绍 - xiadanxuzhi: 'xiadanxuzhi', // 下单须知 - guize: 'guize', // 规则图片URL - xiaoliang: 'xiaoliang', // 商品销量 - kucun: 'kucun', // 商品库存 - fenlei: 'fenlei', // 商品分类(可能有用) - pingfen: 'pingfen' // 商品评分(可能有用) - } - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - - - // 获取全局变量 - this.setData({ - ossImageUrl: app.globalData.ossImageUrl, - apiBaseUrl: app.globalData.apiBaseUrl, - shangpinId: options.id || '', - shangpinTitle: options.title || '', - shangpinPrice: options.price || '' - }) - - // 验证商品ID - if (!this.data.shangpinId) { - wx.showToast({ - title: '商品不存在', - icon: 'none' - }) - setTimeout(() => { - wx.navigateBack() - }, 1500) - return - } - - // 加载商品详情数据 - this.loadShangpinDetail() - }, - onShow() { - backfillUserProfileCache(app); - this.registerNotificationComponent(); - }, - -// 🆕 新增:注册通知组件 -registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - - if (notificationComp && notificationComp.showNotification) { - console.log('🏪 商城页面注册通知组件'); - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } -}, - - /** - * 加载商品详情数据 - */ - loadShangpinDetail() { - const that = this - const { shangpinId, apiBaseUrl } = this.data - - this.setData({ isLoading: true, loadError: false }) - - wx.request({ - url: apiBaseUrl + '/shangpin/xiangqinghuoqu/', - method: 'POST', - header: { - 'content-type': 'application/json' - }, - data: { - shangpin_id: shangpinId - }, - success(res) { - - - if (res.statusCode === 200 && res.data && res.data.code === 0) { - // 获取商品数据 - const shangpinData = res.data.data || {} - - // 处理价格显示 - if (shangpinData.jiage) { - const jiage = parseFloat(shangpinData.jiage) || 0 - const priceInteger = Math.floor(jiage) - let priceDecimal = '00' - - const decimalPart = (jiage - priceInteger).toFixed(2) - if (decimalPart > 0) { - priceDecimal = decimalPart.toString().split('.')[1] - } - - shangpinData.priceInteger = priceInteger - shangpinData.priceDecimal = priceDecimal - } - - // 处理图片URL(确保完整URL) - if (shangpinData.tupian && !shangpinData.tupian.startsWith('http')) { - shangpinData.tupian = that.data.ossImageUrl + shangpinData.tupian - } - - // 处理规则图片URL - if (shangpinData.guize && !shangpinData.guize.startsWith('http')) { - shangpinData.guize = that.data.ossImageUrl + shangpinData.guize - } - - // 处理销量显示 - if (shangpinData.xiaoliang) { - shangpinData.xiaoliangText = that.formatXiaoliang(shangpinData.xiaoliang) - } - - // 处理库存显示 - if (shangpinData.kucun) { - shangpinData.kucunText = shangpinData.kucun + '件' - shangpinData.kucunClass = shangpinData.kucun > 0 ? 'kucun-normal' : 'kucun-none' - } - - // 设置页面标题 - if (shangpinData.biaoti) { - wx.setNavigationBarTitle({ - title: '商品详情' - }) - } - - that.setData({ - shangpinData: shangpinData, - isLoading: false - }) - } else { - that.handleLoadError(res.data?.msg || '加载失败') - } - }, - fail(error) { - console.error('商品详情加载失败:', error) - that.handleLoadError('网络错误,请重试') - } - }) - }, - - /** - * 格式化销量显示 - */ - formatXiaoliang(xiaoliang) { - const num = parseInt(xiaoliang) || 0 - - if (num >= 10000) { - return (num / 10000).toFixed(1) + '万+' - } else if (num >= 1000) { - return (num / 1000).toFixed(1) + '千+' - } else { - return num + '' - } - }, - - /** - * 处理加载错误 - */ - handleLoadError(errorMsg) { - this.setData({ - isLoading: false, - loadError: true - }) - - wx.showToast({ - title: errorMsg || '加载失败', - icon: 'none', - duration: 2000 - }) - - // 3秒后自动返回 - setTimeout(() => { - wx.navigateBack() - }, 3000) - }, - - /** - * 预览商品图片 - */ - previewImage() { - const { shangpinData } = this.data - if (!shangpinData || !shangpinData.tupian) return - - wx.previewImage({ - current: shangpinData.tupian, - urls: [shangpinData.tupian] - }) - }, - - /** - * 点击立即下单按钮 - */ - async onOrderClick() { - const { shangpinData, shangpinId } = this.data - - // 检查库存 - if (shangpinData && shangpinData.kucun <= 0) { - wx.showToast({ - title: '商品已售罄', - icon: 'none' - }) - return - } - - // 验证必要数据 - if (!shangpinData || !shangpinData.biaoti) { - wx.showToast({ - title: '商品信息不完整', - icon: 'none' - }) - return - } - - try { - await ensureLogin() - } catch (e) { - return - } - - // 准备跳转数据 - const orderData = { - id: shangpinId, // 商品ID - title: shangpinData.biaoti, // 商品标题 - price: shangpinData.jiage, // 商品价格(原价) - priceInteger: shangpinData.priceInteger, // 价格整数部分 - priceDecimal: shangpinData.priceDecimal, // 价格小数部分 - image: shangpinData.tupian, // 商品图片 - kucun: shangpinData.kucun || 0, // 商品库存 - xiaoliang: shangpinData.xiaoliang || 0 // 商品销量 - } - - // 跳转到提交订单页面 - wx.navigateTo({ - url: `/pages/tijiao/tijiao?data=${encodeURIComponent(JSON.stringify(orderData))}` - }) - }, - - /** - * 刷新页面数据 - */ - onRefresh() { - this.loadShangpinDetail() - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - const { shangpinData, shangpinId } = this.data - - return { - title: shangpinData?.biaoti || '阿龙电竞 - 商品详情', - path: `/pages/shangpinxiangqing/shangpinxiangqing?id=${shangpinId}`, - imageUrl: shangpinData?.tupian || '' - } - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - // 清理工作 - } +// pages/product-detail/product-detail.js +const app = getApp() +import { ensureLogin } from '../../utils/login' +import { backfillUserProfileCache } from '../../utils/role-tab-bar' + +Page({ + data: { + ossImageUrl: '', + apiBaseUrl: '', + + shangpinId: '', + shangpinTitle: '', + shangpinPrice: '', + + shangpinData: null, + isLoading: true, + loadError: false, + + // 页面字段映射 + fieldMapping: { + tupian: 'tupian', + biaoti: 'biaoti', + jiage: 'jiage', + xiangqing: 'xiangqing', + xiadanxuzhi: 'xiadanxuzhi', + guize: 'guize', + xiaoliang: 'xiaoliang', + kucun: 'kucun', + fenlei: 'fenlei', + pingfen: 'pingfen' + } + }, + + onLoad(options) { + this.setData({ + ossImageUrl: app.globalData.ossImageUrl, + apiBaseUrl: app.globalData.apiBaseUrl, + shangpinId: options.id || '', + shangpinTitle: options.title || '', + shangpinPrice: options.price || '' + }) + + if (!this.data.shangpinId) { + wx.showToast({ + title: '商品不存在', + icon: 'none' + }) + setTimeout(() => { + wx.navigateBack() + }, 1500) + return + } + + this.loadShangpinDetail() + }, + onShow() { + backfillUserProfileCache(app); + 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() + }; + } + }, + + loadShangpinDetail() { + const that = this + const { shangpinId, apiBaseUrl } = this.data + + this.setData({ isLoading: true, loadError: false }) + + wx.request({ + url: apiBaseUrl + '/shangpin/xiangqinghuoqu/', + method: 'POST', + header: { + 'content-type': 'application/json' + }, + data: { + shangpin_id: shangpinId + }, + success(res) { + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const shangpinData = res.data.data || {} + + // 处理价格 + if (shangpinData.jiage) { + const jiage = parseFloat(shangpinData.jiage) || 0 + const priceInteger = Math.floor(jiage) + let priceDecimal = '00' + + const decimalPart = (jiage - priceInteger).toFixed(2) + if (decimalPart > 0) { + priceDecimal = decimalPart.toString().split('.')[1] + } + + shangpinData.priceInteger = priceInteger + shangpinData.priceDecimal = priceDecimal + } + + // 处理图片URL + if (shangpinData.tupian && !shangpinData.tupian.startsWith('http')) { + shangpinData.tupian = that.data.ossImageUrl + shangpinData.tupian + } + + // 处理规则图片URL + if (shangpinData.guize && !shangpinData.guize.startsWith('http')) { + shangpinData.guize = that.data.ossImageUrl + shangpinData.guize + } + + // 处理销量显示 + if (shangpinData.xiaoliang) { + shangpinData.xiaoliangText = that.formatXiaoliang(shangpinData.xiaoliang) + } + + // 处理库存显示 + if (shangpinData.kucun) { + shangpinData.kucunText = shangpinData.kucun + '件' + shangpinData.kucunClass = shangpinData.kucun > 0 ? 'kucun-normal' : 'kucun-none' + } + + // 设置页面标题 + if (shangpinData.biaoti) { + wx.setNavigationBarTitle({ + title: '商品详情' + }) + } + + that.setData({ + shangpinData: shangpinData, + isLoading: false + }) + } else { + that.handleLoadError(res.data?.msg || '加载失败') + } + }, + fail(error) { + console.error('商品详情加载失败:', error) + that.handleLoadError('网络错误,请重试') + } + }) + }, + + formatXiaoliang(xiaoliang) { + const num = parseInt(xiaoliang) || 0 + + if (num >= 10000) { + return (num / 10000).toFixed(1) + '万+' + } else if (num >= 1000) { + return (num / 1000).toFixed(1) + '千+' + } else { + return num + '' + } + }, + + handleLoadError(errorMsg) { + this.setData({ + isLoading: false, + loadError: true + }) + + wx.showToast({ + title: errorMsg || '加载失败', + icon: 'none', + duration: 2000 + }) + + // 3秒后自动返回 + setTimeout(() => { + wx.navigateBack() + }, 3000) + }, + + previewImage() { + const { shangpinData } = this.data + if (!shangpinData || !shangpinData.tupian) return + + wx.previewImage({ + current: shangpinData.tupian, + urls: [shangpinData.tupian] + }) + }, + + async onOrderClick() { + const { shangpinData, shangpinId } = this.data + + // 检查库存 + if (shangpinData && shangpinData.kucun <= 0) { + wx.showToast({ + title: '商品已售罄', + icon: 'none' + }) + return + } + + // 验证必要数据 + if (!shangpinData || !shangpinData.biaoti) { + wx.showToast({ + title: '商品信息不完整', + icon: 'none' + }) + return + } + + try { + await ensureLogin() + } catch (e) { + return + } + + const orderData = { + id: shangpinId, + title: shangpinData.biaoti, + price: shangpinData.jiage, + priceInteger: shangpinData.priceInteger, + priceDecimal: shangpinData.priceDecimal, + image: shangpinData.tupian, + kucun: shangpinData.kucun || 0, + xiaoliang: shangpinData.xiaoliang || 0 + } + + wx.navigateTo({ + url: `/pages/submit/submit?data=${encodeURIComponent(JSON.stringify(orderData))}` + }) + }, + + onRefresh() { + this.loadShangpinDetail() + }, + + onShareAppMessage() { + const { shangpinData, shangpinId } = this.data + + return { + title: shangpinData?.biaoti || '阿龙电竞 - 商品详情', + path: `/pages/product-detail/product-detail?id=${shangpinId}`, + imageUrl: shangpinData?.tupian || '' + } + }, + + onUnload() { + } }) \ No newline at end of file diff --git a/pages/tijiao/tijiao.json b/pages/product-detail/product-detail.json similarity index 100% rename from pages/tijiao/tijiao.json rename to pages/product-detail/product-detail.json diff --git a/pages/shangpinxiangqing/shangpinxiangqing.wxml b/pages/product-detail/product-detail.wxml similarity index 84% rename from pages/shangpinxiangqing/shangpinxiangqing.wxml rename to pages/product-detail/product-detail.wxml index 595ed1f..4ad5e00 100644 --- a/pages/shangpinxiangqing/shangpinxiangqing.wxml +++ b/pages/product-detail/product-detail.wxml @@ -1,112 +1,112 @@ - - - - - - - - - - 加载中... - - - - - - - 加载失败 - - - - - - - - - - - - {{shangpinData.kucunText || '库存充足'}} - - - - - - - - - - {{shangpinData.biaoti || ''}} - - - - - - ¥ - {{shangpinData.priceInteger || '0'}} - .{{shangpinData.priceDecimal || '00'}} - - - - - - {{shangpinData.xiaoliangText || '0'}}次购买 - - - - - - - - - 商品介绍: - - - {{shangpinData.xiangqing}} - - - - - - - - 购买须知: - - - {{shangpinData.xiadanxuzhi}} - - - - - - - - - - - - - - - - - - - - - - 立即预约 - - - - + + + + + + + + + + 加载中... + + + + + + + 加载失败 + + + + + + + + + + + + {{shangpinData.kucunText || '库存充足'}} + + + + + + + + + + {{shangpinData.biaoti || ''}} + + + + + + ¥ + {{shangpinData.priceInteger || '0'}} + .{{shangpinData.priceDecimal || '00'}} + + + + + + {{shangpinData.xiaoliangText || '0'}}次购买 + + + + + + + + + 商品介绍: + + + {{shangpinData.xiangqing}} + + + + + + + + 购买须知: + + + {{shangpinData.xiadanxuzhi}} + + + + + + + + + + + + + + + + + + + + + + 立即预约 + + + + \ No newline at end of file diff --git a/pages/shangpinxiangqing/shangpinxiangqing.wxss b/pages/product-detail/product-detail.wxss similarity index 87% rename from pages/shangpinxiangqing/shangpinxiangqing.wxss rename to pages/product-detail/product-detail.wxss index c94d2b8..8590c7c 100644 --- a/pages/shangpinxiangqing/shangpinxiangqing.wxss +++ b/pages/product-detail/product-detail.wxss @@ -1,386 +1,349 @@ -/* pages/shangpinxiangqing/shangpinxiangqing.wxss */ -.detail-page { - width: 100%; - min-height: 100vh; - background: #f5f5f5; - position: relative; - } - - /* 加载状态 */ - .loading-container { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - background: #f5f5f5; - z-index: 100; - } - - .loading-content { - display: flex; - flex-direction: column; - align-items: center; - } - - .loading-spinner { - width: 80rpx; - height: 80rpx; - position: relative; - margin-bottom: 30rpx; - } - - .spinner-ring { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border: 4rpx solid rgba(82, 196, 26, 0.2); - border-radius: 50%; - } - - .spinner-dot { - position: absolute; - top: 0; - left: 50%; - width: 12rpx; - height: 12rpx; - background: #52c41a; - border-radius: 50%; - transform: translateX(-50%); - animation: spin 1s linear infinite; - } - - .loading-text { - font-size: 28rpx; - color: #666; - font-weight: 500; - } - - /* 错误状态 */ - .error-container { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background: #f5f5f5; - z-index: 100; - } - - .error-icon { - width: 180rpx; - height: 180rpx; - opacity: 0.3; - margin-bottom: 30rpx; - } - - .error-text { - font-size: 30rpx; - color: #999; - margin-bottom: 40rpx; - } - - .error-btn { - background: linear-gradient(135deg, #52c41a, #389e0d); - color: white; - font-size: 26rpx; - font-weight: 500; - padding: 20rpx 50rpx; - border-radius: 50rpx; - box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.3); - } - - /* 商品详情内容 */ - .detail-content { - padding-bottom: 140rpx; /* 给底部按钮留出空间 */ - } - - /* 商品图片区域(占满屏幕) */ - .image-section { - width: 100%; - background: white; - } - - .image-container { - width: 100%; - height: 750rpx; /* 正方形,占满屏幕宽度 */ - position: relative; - overflow: hidden; - background: #f5f5f5; - } - - .product-image { - width: 100%; - height: 100%; - } - - /* 库存标签 */ - .kucun-tag { - position: absolute; - bottom: 30rpx; - right: 30rpx; - padding: 12rpx 24rpx; - border-radius: 30rpx; - backdrop-filter: blur(10rpx); - z-index: 10; - } - - .kucun-normal { - background: rgba(0, 0, 0, 0.6); - color: white; - } - - .kucun-none { - background: rgba(255, 77, 79, 0.8); - color: white; - } - - .kucun-text { - font-size: 24rpx; - font-weight: 500; - } - - /* 下方内容区域(顶部有圆角,与图片重叠一部分) */ - .content-area { - position: relative; - background: white; - border-radius: 40rpx 40rpx 0 0; - margin-top: -40rpx; /* 与图片重叠一部分,实现平滑过渡 */ - padding: 40rpx 30rpx 0; - min-height: 400rpx; - } - - /* 标题和价格区域 */ - .title-price-section { - margin-bottom: 40rpx; - } - - .title-row { - margin-bottom: 30rpx; - } - - .product-title { - font-size: 38rpx; - font-weight: 700; - color: #222; - line-height: 1.5; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - overflow: hidden; - } - - /* 价格和销量行 */ - .price-row { - display: flex; - justify-content: space-between; - align-items: center; - } - - /* 价格部分 */ - .price-section { - display: flex; - align-items: baseline; - } - - .price-icon { - font-size: 34rpx; - color: #ff4d4f; - font-weight: 600; - } - - .price-integer { - font-size: 58rpx; - color: #ff4d4f; - font-weight: 700; - margin-left: 4rpx; - } - - .price-decimal { - font-size: 34rpx; - color: #ff4d4f; - font-weight: 600; - } - - /* 销量部分 */ - .sales-section { - display: flex; - align-items: center; - } - - .sales-icon { - width: 30rpx; - height: 30rpx; - margin-right: 12rpx; - opacity: 0.6; - } - - .sales-text { - font-size: 28rpx; - color: #999; - font-weight: 400; - } - - /* 信息区域(商品介绍、购买须知) */ - .info-section { - margin-bottom: 40rpx; - padding-top: 30rpx; - border-top: 1rpx solid #f0f0f0; - } - - .section-header { - display: flex; - align-items: center; - margin-bottom: 20rpx; - } - - .section-icon { - width: 36rpx; - height: 36rpx; - margin-right: 16rpx; - } - - .section-title { - font-size: 32rpx; - font-weight: 600; - color: #52c41a; /* 绿色 */ - } - - .section-content { - line-height: 1.8; - padding-left: 52rpx; /* 与图标对齐 */ - } - - .content-text { - font-size: 28rpx; - color: #333; - font-weight: 400; - white-space: pre-line; - line-height: 1.8; - } - - /* 规则图片区域 */ - .rule-section { - margin: 40rpx 0; - padding-top: 30rpx; - border-top: 1rpx solid #f0f0f0; - } - - .rule-image { - width: 100%; - border-radius: 16rpx; - display: block; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); - } - - /* 占位区域 */ - .placeholder { - height: 140rpx; - } - - /* 立即下单按钮容器(固定底部) */ - .order-btn-container { - position: fixed; - left: 0; - right: 0; - bottom: 0; - padding: 20rpx 30rpx; - background: linear-gradient(transparent, rgba(255, 255, 255, 0.9) 70%); - z-index: 100; - } - - /* 立即下单按钮 */ - .order-btn { - background: linear-gradient(135deg, #52c41a, #389e0d); - border-radius: 50rpx; - height: 100rpx; - display: flex; - align-items: center; - justify-content: center; - position: relative; - overflow: hidden; - box-shadow: - 0 12rpx 36rpx rgba(82, 196, 26, 0.4), - 0 4rpx 12rpx rgba(82, 196, 26, 0.3); - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - } - - .order-btn:active { - transform: scale(0.98); - box-shadow: - 0 6rpx 24rpx rgba(82, 196, 26, 0.5), - 0 2rpx 8rpx rgba(82, 196, 26, 0.4); - } - - /* 按钮发光特效 */ - .btn-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255, 255, 255, 0.1); - animation: glowPulse 2s infinite; - } - - /* 按钮流光特效 */ - .btn-streamer { - position: absolute; - top: 0; - left: 0; - width: 100rpx; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); - transform: translateX(-100%); - animation: streamerFlow 3s infinite; - } - - /* 按钮文字 */ - .btn-text { - font-size: 36rpx; - color: white; - font-weight: 600; - letter-spacing: 2rpx; - position: relative; - z-index: 2; - } - - /* 动画定义 */ - @keyframes spin { - 0% { - transform: translateX(-50%) rotate(0deg); - } - 100% { - transform: translateX(-50%) rotate(360deg); - } - } - - @keyframes glowPulse { - 0%, 100% { - opacity: 0.5; - } - 50% { - opacity: 0.8; - } - } - - @keyframes streamerFlow { - 0% { - transform: translateX(-100%); - } - 50% { - transform: translateX(100%); - } - 100% { - transform: translateX(100%); - } +/* pages/product-detail/product-detail.wxss */ +.detail-page { + width: 100%; + background: #f5f5f5; + } + + /* 加载状态 */ + .loading-container { + position: absolute; + background: #f5f5f5; + z-index: 100; + } + + .loading-content { + display: flex; + flex-direction: column; + align-items: center; + } + + .loading-spinner { + width: 80rpx; + height: 80rpx; + position: relative; + margin-bottom: 30rpx; + } + + .spinner-ring { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 4rpx solid rgba(82, 196, 26, 0.2); + border-radius: 50%; + } + + .spinner-dot { + position: absolute; + top: 0; + left: 50%; + width: 12rpx; + height: 12rpx; + background: #52c41a; + border-radius: 50%; + transform: translateX(-50%); + animation: spin 1s linear infinite; + } + + .loading-text { + font-size: 28rpx; + color: #666; + font-weight: 500; + } + + /* 错误状态 */ + .error-container { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #f5f5f5; + z-index: 100; + padding: 0; + } + + .error-icon { + width: 180rpx; + height: 180rpx; + opacity: 0.3; + margin-bottom: 30rpx; + } + + .error-text { + font-size: 30rpx; + color: #999; + margin-bottom: 40rpx; + } + + .error-btn { + font-weight: 500; + padding: 20rpx 50rpx; + border-radius: 50rpx; + box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.3); + } + + /* 商品详情内容 */ + .detail-content { + padding-bottom: 140rpx; /* 给底部按钮留出空间 */ + } + + /* 商品图片区域(占满屏幕) */ + .image-section { + width: 100%; + background: white; + } + + .image-container { + width: 100%; + height: 750rpx; /* 正方形,占满屏幕宽度 */ + position: relative; + overflow: hidden; + background: #f5f5f5; + } + + .product-image { + width: 100%; + height: 100%; + } + + /* 库存标签 */ + .kucun-tag { + position: absolute; + bottom: 30rpx; + right: 30rpx; + padding: 12rpx 24rpx; + border-radius: 30rpx; + backdrop-filter: blur(10rpx); + z-index: 10; + } + + .kucun-normal { + background: rgba(0, 0, 0, 0.6); + color: white; + } + + .kucun-none { + background: rgba(255, 77, 79, 0.8); + color: white; + } + + .kucun-text { + font-size: 24rpx; + font-weight: 500; + } + + /* 下方内容区域(顶部有圆角,与图片重叠一部分) */ + .content-area { + position: relative; + background: white; + border-radius: 40rpx 40rpx 0 0; + margin-top: -40rpx; /* 与图片重叠一部分,实现平滑过渡 */ + padding: 40rpx 30rpx 0; + min-height: 400rpx; + } + + /* 标题和价格区域 */ + .title-price-section { + margin-bottom: 40rpx; + } + + .title-row { + margin-bottom: 30rpx; + } + + .product-title { + font-size: 38rpx; + font-weight: 700; + color: #222; + line-height: 1.5; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + } + + /* 价格和销量行 */ + .price-row { + display: flex; + justify-content: space-between; + align-items: center; + } + + /* 价格部分 */ + .price-section { + display: flex; + align-items: baseline; + } + + .price-icon { + font-size: 34rpx; + color: #ff4d4f; + font-weight: 600; + } + + .price-integer { + font-size: 58rpx; + color: #ff4d4f; + font-weight: 700; + margin-left: 4rpx; + } + + .price-decimal { + font-size: 34rpx; + color: #ff4d4f; + font-weight: 600; + } + + /* 销量部分 */ + .sales-section { + display: flex; + align-items: center; + } + + .sales-icon { + width: 30rpx; + height: 30rpx; + margin-right: 12rpx; + opacity: 0.6; + } + + .sales-text { + font-size: 28rpx; + color: #999; + font-weight: 400; + } + + /* 信息区域(商品介绍、购买须知) */ + .info-section { + margin-bottom: 40rpx; + padding-top: 30rpx; + border-top: 1rpx solid #f0f0f0; + } + + .section-header { + display: flex; + align-items: center; + margin-bottom: 20rpx; + } + + .section-icon { + width: 36rpx; + height: 36rpx; + margin-right: 16rpx; + } + + .section-title { + font-size: 32rpx; + font-weight: 600; + color: #52c41a; /* 绿色 */ + } + + .section-content { + line-height: 1.8; + padding-left: 52rpx; /* 与图标对齐 */ + } + + .content-text { + font-size: 28rpx; + color: #333; + font-weight: 400; + white-space: pre-line; + line-height: 1.8; + } + + /* 规则图片区域 */ + .rule-section { + margin: 40rpx 0; + padding-top: 30rpx; + border-top: 1rpx solid #f0f0f0; + } + + .rule-image { + width: 100%; + border-radius: 16rpx; + display: block; + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); + } + + /* 占位区域 */ + .placeholder { + height: 140rpx; + } + + /* 立即下单按钮容器(固定底部) */ + .order-btn-container { + background: linear-gradient(transparent, rgba(255, 255, 255, 0.9) 70%); + } + + /* 立即下单按钮 */ + .order-btn { + border-radius: 50rpx; + height: 100rpx; + box-shadow: + 0 12rpx 36rpx rgba(82, 196, 26, 0.4), + 0 4rpx 12rpx rgba(82, 196, 26, 0.3); + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + } + + .order-btn:active { + box-shadow: + 0 6rpx 24rpx rgba(82, 196, 26, 0.5), + 0 2rpx 8rpx rgba(82, 196, 26, 0.4); + } + + /* 按钮发光特效 */ + .btn-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.1); + animation: glowPulse 2s infinite; + } + + /* 按钮流光特效 */ + .btn-streamer { + position: absolute; + top: 0; + left: 0; + width: 100rpx; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transform: translateX(-100%); + animation: streamerFlow 3s infinite; + } + + /* 按钮文字 */ + .btn-text { + font-size: 36rpx; + color: white; + font-weight: 600; + letter-spacing: 2rpx; + position: relative; + z-index: 2; + } + + /* 动画定义 */ + @keyframes glowPulse { + 0%, 100% { + opacity: 0.5; + } + 50% { + opacity: 0.8; + } + } + + @keyframes streamerFlow { + 0% { + transform: translateX(-100%); + } + 50% { + transform: translateX(100%); + } + 100% { + transform: translateX(100%); + } } \ No newline at end of file diff --git a/pages/czjilu/czjilu.js b/pages/recharge-log/recharge-log.js similarity index 100% rename from pages/czjilu/czjilu.js rename to pages/recharge-log/recharge-log.js diff --git a/pages/czjilu/czjilu.json b/pages/recharge-log/recharge-log.json similarity index 100% rename from pages/czjilu/czjilu.json rename to pages/recharge-log/recharge-log.json diff --git a/pages/czjilu/czjilu.wxml b/pages/recharge-log/recharge-log.wxml similarity index 100% rename from pages/czjilu/czjilu.wxml rename to pages/recharge-log/recharge-log.wxml diff --git a/pages/czjilu/czjilu.wxss b/pages/recharge-log/recharge-log.wxss similarity index 100% rename from pages/czjilu/czjilu.wxss rename to pages/recharge-log/recharge-log.wxss diff --git a/pages/tijiao/tijiao.js b/pages/submit/submit.js similarity index 95% rename from pages/tijiao/tijiao.js rename to pages/submit/submit.js index 7d42ccc..f26b7c2 100644 --- a/pages/tijiao/tijiao.js +++ b/pages/submit/submit.js @@ -1,547 +1,547 @@ -// pages/tijiao/tijiao.js -const app = getApp() -import request from '../../utils/request.js' -// 引入弹窗服务(路径请根据项目实际调整) -import PopupService from '../../services/popupService.js' - -Page({ - data: { - // 全局变量 - ossImageUrl: '', - apiBaseUrl: '', - - // 从商品详情页传入的数据 - shangpinData: null, - shangpinId: '', - - // 表单数据 - nicheng: '', // 游戏昵称/ID - beizhu: '', // 备注信息 - zhiding: '', // 指定打手ID(新增) - jine: 0, // 总金额 - - // 页面状态 - isSubmitting: false, - canSubmit: false, - isPaying: false, - - // 支付相关 - orderId: '', - payParams: null, - checkCount: 0, - maxCheckCount: 3 - }, - - onLoad(options) { - // 获取全局变量 - this.setData({ - ossImageUrl: app.globalData.ossImageUrl || '', - apiBaseUrl: app.globalData.apiBaseUrl || '' - }) - - // 设置页面标题 - wx.setNavigationBarTitle({ - title: '提交订单' - }) - - // 解析传递的商品数据 - try { - if (options.data) { - const shangpinData = JSON.parse(decodeURIComponent(options.data)) - - // 处理图片URL(拼接完整路径) - if (shangpinData.image && !shangpinData.image.startsWith('http')) { - shangpinData.image = this.data.ossImageUrl + shangpinData.image - } - - // 处理价格显示 - if (shangpinData.price) { - const price = parseFloat(shangpinData.price) || 0 - const priceInteger = Math.floor(price) - let priceDecimal = '00' - - const decimalPart = (price - priceInteger).toFixed(2) - if (decimalPart > 0) { - priceDecimal = decimalPart.toString().split('.')[1] - } - - shangpinData.priceInteger = priceInteger - shangpinData.priceDecimal = priceDecimal - } - - // 设置商品数据 - this.setData({ - shangpinData: shangpinData, - shangpinId: shangpinData.id || '', - jine: parseFloat(shangpinData.price) || 0, - }) - } else { - this.handleDataError('商品数据不完整') - } - } catch (error) { - this.handleDataError('解析商品数据失败') - } - }, - - onShow() { - // 原有代码:注册通知组件 - this.registerNotificationComponent(); - - // 🆕 进入页面时触发弹窗检查(PopupService 会自动判断是否展示) - PopupService.checkAndShow(this, 'tijiao'); - }, - - // pages/tijiao/tijiao.js 中添加 onHide 方法(如果已有则合并内容) -onHide() { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } - }, - - // 新增:注册通知组件 - registerNotificationComponent() { - const app = getApp(); - const notificationComp = this.selectComponent('#global-notification'); - - if (notificationComp && notificationComp.showNotification) { - //console.log('🏪 商城页面注册通知组件'); - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - /** - * 处理数据错误 - */ - handleDataError(errorMsg) { - wx.showToast({ - title: errorMsg || '数据错误', - icon: 'none' - }) - - setTimeout(() => { - wx.navigateBack() - }, 1500) - }, - - /** - * 游戏昵称输入事件 - */ - onNicknameInput(e) { - const value = e.detail.value.trim() - this.setData({ - nicheng: value - }, () => { - this.checkFormValid() - }) - }, - - /** - * 备注信息输入事件 - */ - onRemarkInput(e) { - const value = e.detail.value.trim() - this.setData({ - beizhu: value - }) - }, - - /** - * 指定打手ID输入事件 - */ - onZhidingInput(e) { - const value = e.detail.value.trim() - this.setData({ - zhiding: value - }) - }, - - /** - * 检查表单是否有效 - */ - checkFormValid() { - const { nicheng } = this.data - - const isValid = nicheng && nicheng.length > 0 && nicheng.length <= 15 - - this.setData({ - canSubmit: isValid - }) - }, - - /** - * 提交订单 - */ - onSubmitOrder() { - const { nicheng, beizhu, zhiding, jine, shangpinId, canSubmit, isSubmitting } = this.data - - // 验证表单 - if (!canSubmit) { - wx.showToast({ - title: '请填写游戏昵称', - icon: 'none' - }) - return - } - - // 防止重复提交 - if (isSubmitting) { - return - } - - this.setData({ - isSubmitting: true, - isPaying: false - }) - - // 显示loading(超时设为10秒) - wx.showLoading({ - title: '创建订单中...', - mask: true - }) - - const timeoutTimer = setTimeout(() => { - wx.hideLoading() - wx.showToast({ - title: '网络超时,请检查您是否已登录', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - }, 10000) - - // 构建请求数据(添加zhiding字段) - const orderData = { - shangpin_id: shangpinId, // 商品ID - nicheng: nicheng, // 游戏昵称 - beizhu: beizhu || '', // 备注(可为空) - zhiding: zhiding || '', // 指定打手ID(可为空) - jine: jine // 金额 - } - - // 调用后端创建订单接口 - request({ - url: '/dingdan/xiadan', - method: 'POST', - data: orderData - }) - .then(res => { - clearTimeout(timeoutTimer) - wx.hideLoading() - - if (res.statusCode === 200 && res.data) { - const response = res.data - - if (response.code === 0 && response.data) { - // 保存订单ID和支付参数 - const orderId = response.data.dingdanid - const payParams = response.data.payParams || {} - - this.setData({ - orderId: orderId, - payParams: payParams, - isSubmitting: false, - isPaying: true, - checkCount: 0 - }) - - // 调起微信支付 - this.triggerWxPayment(payParams) - } else { - wx.showToast({ - title: response.msg || '创建订单失败', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - } - } else { - wx.showToast({ - title: '网络错误,请重试', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - } - }) - .catch(error => { - clearTimeout(timeoutTimer) - wx.hideLoading() - wx.showToast({ - title: '创建订单失败', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - }) - }, - - /** - * 调起微信支付 - */ - triggerWxPayment(payParams) { - // 验证支付参数是否完整 - if (!payParams || !payParams.timeStamp || !payParams.nonceStr || - !payParams.package || !payParams.signType || !payParams.paySign) { - wx.showToast({ - title: '支付参数不完整', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - return - } - - wx.requestPayment({ - timeStamp: payParams.timeStamp, - nonceStr: payParams.nonceStr, - package: payParams.package, - signType: payParams.signType, - paySign: payParams.paySign, - - success: (res) => { - // 支付成功,开始双重确认 - this.onPaymentSuccess() - }, - - fail: (err) => { - // 根据错误类型处理 - if (err.errMsg === 'requestPayment:fail cancel') { - // 用户取消支付 - this.handleUserCancel() - } else { - // 其他支付错误 - this.handlePaymentFail(err) - } - } - }) - }, - - /** - * 处理用户取消支付 - */ - handleUserCancel() { - const { orderId } = this.data - - wx.showToast({ - title: '已取消支付', - icon: 'none', - duration: 1500 - }) - - // 通知后端用户取消(静默请求,不阻塞用户) - if (orderId) { - request({ - url: '/dingdan/shibai', - method: 'POST', - data: { - dingdanid: orderId, - yuanyin: 'user_cancel' - } - }).catch(() => { - // 静默失败 - }) - } - - this.setData({ - isSubmitting: false, - isPaying: false - }) - }, - - /** - * 处理支付失败 - */ - handlePaymentFail(err) { - const { orderId } = this.data - - wx.showToast({ - title: '支付失败', - icon: 'none', - duration: 1500 - }) - - // 通知后端支付失败(简化流程,直接请求,不显示loading) - if (orderId) { - request({ - url: '/dingdan/shibai', - method: 'POST', - data: { - dingdanid: orderId, - yuanyin: 'payment_fail', - cuowu: err.errMsg || '' - } - }).catch(() => { - // 静默失败 - }).finally(() => { - this.setData({ - isSubmitting: false, - isPaying: false - }) - }) - } else { - this.setData({ - isSubmitting: false, - isPaying: false - }) - } - }, - - /** - * 支付成功处理(双重确认) - */ - onPaymentSuccess() { - const { orderId } = this.data - - if (!orderId) { - wx.showToast({ - title: '订单ID不存在', - icon: 'none' - }) - this.setData({ - isSubmitting: false, - isPaying: false - }) - return - } - - // 显示支付成功提示(时间缩短) - wx.showToast({ - title: '支付成功,确认中...', - icon: 'none', - duration: 1500 - }) - - // 开始双重确认流程 - this.checkOrderStatus() - }, - - /** - * 检查订单状态(双重确认) - */ - checkOrderStatus() { - const { orderId, checkCount, maxCheckCount } = this.data - - // 显示加载(时间缩短) - wx.showLoading({ - title: `确认支付状态${checkCount > 0 ? `(${checkCount + 1})` : ''}`, - mask: true - }) - - // 超时设为5秒 - const timeoutTimer = setTimeout(() => { - wx.hideLoading() - this.handleConfirmError('网络超时') - }, 5000) - - // 向后端发起支付复查请求 - request({ - url: '/dingdan/fucha', - method: 'POST', - data: { - dingdanid: orderId - } - }) - .then(res => { - clearTimeout(timeoutTimer) - wx.hideLoading() - - if (res.statusCode === 200 && res.data) { - const response = res.data - - if (response.code === 0) { - // 确认成功,订单状态已更新 - this.handleConfirmSuccess() - } else { - // 后端返回错误 - this.handleConfirmError(response.msg || '订单状态异常') - } - } else { - // 网络错误 - this.handleConfirmError('网络错误') - } - }) - .catch(error => { - clearTimeout(timeoutTimer) - wx.hideLoading() - this.handleConfirmError('检查失败') - }) - }, - - /** - * 处理确认成功 - */ - handleConfirmSuccess() { - // 显示最终成功提示 - wx.showToast({ - title: '购买成功!', - icon: 'success', - duration: 1500 - }) - - // 1.5秒后跳转到首页 - setTimeout(() => { - wx.switchTab({ - url: '/pages/index/index' - }) - }, 1500) - - this.setData({ - isSubmitting: false, - isPaying: false - }) - }, - - /** - * 处理确认错误 - */ - handleConfirmError(errorMsg) { - const { checkCount, maxCheckCount } = this.data - const newCheckCount = checkCount + 1 - - if (newCheckCount < maxCheckCount) { - // 还可以重试 - this.setData({ - checkCount: newCheckCount - }) - - // 1秒后重试 - setTimeout(() => { - this.checkOrderStatus() - }, 1000) - } else { - // 达到最大重试次数 - wx.showModal({ - title: '支付确认中', - content: '支付已成功,但订单状态确认异常。请稍后在订单列表中查看状态,如有问题请联系客服。', - showCancel: false, - confirmText: '我知道了', - success: (res) => { - if (res.confirm) { - wx.switchTab({ - url: '/pages/index/index' - }) - } - } - }) - - this.setData({ - isSubmitting: false, - isPaying: false - }) - } - } +// pages/submit/submit.js +const app = getApp() +import request from '../../utils/request.js' +// 引入弹窗服务(路径请根据项目实际调整) +import PopupService from '../../services/popupService.js' + +Page({ + data: { + // 全局变量 + ossImageUrl: '', + apiBaseUrl: '', + + // 从商品详情页传入的数据 + shangpinData: null, + shangpinId: '', + + // 表单数据 + nicheng: '', // 游戏昵称/ID + beizhu: '', // 备注信息 + zhiding: '', // 指定打手ID(新增) + jine: 0, // 总金额 + + // 页面状态 + isSubmitting: false, + canSubmit: false, + isPaying: false, + + // 支付相关 + orderId: '', + payParams: null, + checkCount: 0, + maxCheckCount: 3 + }, + + onLoad(options) { + // 获取全局变量 + this.setData({ + ossImageUrl: app.globalData.ossImageUrl || '', + apiBaseUrl: app.globalData.apiBaseUrl || '' + }) + + // 设置页面标题 + wx.setNavigationBarTitle({ + title: '提交订单' + }) + + // 解析传递的商品数据 + try { + if (options.data) { + const shangpinData = JSON.parse(decodeURIComponent(options.data)) + + // 处理图片URL(拼接完整路径) + if (shangpinData.image && !shangpinData.image.startsWith('http')) { + shangpinData.image = this.data.ossImageUrl + shangpinData.image + } + + // 处理价格显示 + if (shangpinData.price) { + const price = parseFloat(shangpinData.price) || 0 + const priceInteger = Math.floor(price) + let priceDecimal = '00' + + const decimalPart = (price - priceInteger).toFixed(2) + if (decimalPart > 0) { + priceDecimal = decimalPart.toString().split('.')[1] + } + + shangpinData.priceInteger = priceInteger + shangpinData.priceDecimal = priceDecimal + } + + // 设置商品数据 + this.setData({ + shangpinData: shangpinData, + shangpinId: shangpinData.id || '', + jine: parseFloat(shangpinData.price) || 0, + }) + } else { + this.handleDataError('商品数据不完整') + } + } catch (error) { + this.handleDataError('解析商品数据失败') + } + }, + + onShow() { + // 原有代码:注册通知组件 + this.registerNotificationComponent(); + + // 🆕 进入页面时触发弹窗检查(PopupService 会自动判断是否展示) + PopupService.checkAndShow(this, 'tijiao'); + }, + + // pages/submit/submit.js 中添加 onHide 方法(如果已有则合并内容) +onHide() { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } + }, + + // 新增:注册通知组件 + registerNotificationComponent() { + const app = getApp(); + const notificationComp = this.selectComponent('#global-notification'); + + if (notificationComp && notificationComp.showNotification) { + //console.log('🏪 商城页面注册通知组件'); + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + /** + * 处理数据错误 + */ + handleDataError(errorMsg) { + wx.showToast({ + title: errorMsg || '数据错误', + icon: 'none' + }) + + setTimeout(() => { + wx.navigateBack() + }, 1500) + }, + + /** + * 游戏昵称输入事件 + */ + onNicknameInput(e) { + const value = e.detail.value.trim() + this.setData({ + nicheng: value + }, () => { + this.checkFormValid() + }) + }, + + /** + * 备注信息输入事件 + */ + onRemarkInput(e) { + const value = e.detail.value.trim() + this.setData({ + beizhu: value + }) + }, + + /** + * 指定打手ID输入事件 + */ + onZhidingInput(e) { + const value = e.detail.value.trim() + this.setData({ + zhiding: value + }) + }, + + /** + * 检查表单是否有效 + */ + checkFormValid() { + const { nicheng } = this.data + + const isValid = nicheng && nicheng.length > 0 && nicheng.length <= 15 + + this.setData({ + canSubmit: isValid + }) + }, + + /** + * 提交订单 + */ + onSubmitOrder() { + const { nicheng, beizhu, zhiding, jine, shangpinId, canSubmit, isSubmitting } = this.data + + // 验证表单 + if (!canSubmit) { + wx.showToast({ + title: '请填写游戏昵称', + icon: 'none' + }) + return + } + + // 防止重复提交 + if (isSubmitting) { + return + } + + this.setData({ + isSubmitting: true, + isPaying: false + }) + + // 显示loading(超时设为10秒) + wx.showLoading({ + title: '创建订单中...', + mask: true + }) + + const timeoutTimer = setTimeout(() => { + wx.hideLoading() + wx.showToast({ + title: '网络超时,请检查您是否已登录', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + }, 10000) + + // 构建请求数据(添加zhiding字段) + const orderData = { + shangpin_id: shangpinId, // 商品ID + nicheng: nicheng, // 游戏昵称 + beizhu: beizhu || '', // 备注(可为空) + zhiding: zhiding || '', // 指定打手ID(可为空) + jine: jine // 金额 + } + + // 调用后端创建订单接口 + request({ + url: '/dingdan/xiadan', + method: 'POST', + data: orderData + }) + .then(res => { + clearTimeout(timeoutTimer) + wx.hideLoading() + + if (res.statusCode === 200 && res.data) { + const response = res.data + + if (response.code === 0 && response.data) { + // 保存订单ID和支付参数 + const orderId = response.data.dingdanid + const payParams = response.data.payParams || {} + + this.setData({ + orderId: orderId, + payParams: payParams, + isSubmitting: false, + isPaying: true, + checkCount: 0 + }) + + // 调起微信支付 + this.triggerWxPayment(payParams) + } else { + wx.showToast({ + title: response.msg || '创建订单失败', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + } + } else { + wx.showToast({ + title: '网络错误,请重试', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + } + }) + .catch(error => { + clearTimeout(timeoutTimer) + wx.hideLoading() + wx.showToast({ + title: '创建订单失败', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + }) + }, + + /** + * 调起微信支付 + */ + triggerWxPayment(payParams) { + // 验证支付参数是否完整 + if (!payParams || !payParams.timeStamp || !payParams.nonceStr || + !payParams.package || !payParams.signType || !payParams.paySign) { + wx.showToast({ + title: '支付参数不完整', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + return + } + + wx.requestPayment({ + timeStamp: payParams.timeStamp, + nonceStr: payParams.nonceStr, + package: payParams.package, + signType: payParams.signType, + paySign: payParams.paySign, + + success: (res) => { + // 支付成功,开始双重确认 + this.onPaymentSuccess() + }, + + fail: (err) => { + // 根据错误类型处理 + if (err.errMsg === 'requestPayment:fail cancel') { + // 用户取消支付 + this.handleUserCancel() + } else { + // 其他支付错误 + this.handlePaymentFail(err) + } + } + }) + }, + + /** + * 处理用户取消支付 + */ + handleUserCancel() { + const { orderId } = this.data + + wx.showToast({ + title: '已取消支付', + icon: 'none', + duration: 1500 + }) + + // 通知后端用户取消(静默请求,不阻塞用户) + if (orderId) { + request({ + url: '/dingdan/shibai', + method: 'POST', + data: { + dingdanid: orderId, + yuanyin: 'user_cancel' + } + }).catch(() => { + // 静默失败 + }) + } + + this.setData({ + isSubmitting: false, + isPaying: false + }) + }, + + /** + * 处理支付失败 + */ + handlePaymentFail(err) { + const { orderId } = this.data + + wx.showToast({ + title: '支付失败', + icon: 'none', + duration: 1500 + }) + + // 通知后端支付失败(简化流程,直接请求,不显示loading) + if (orderId) { + request({ + url: '/dingdan/shibai', + method: 'POST', + data: { + dingdanid: orderId, + yuanyin: 'payment_fail', + cuowu: err.errMsg || '' + } + }).catch(() => { + // 静默失败 + }).finally(() => { + this.setData({ + isSubmitting: false, + isPaying: false + }) + }) + } else { + this.setData({ + isSubmitting: false, + isPaying: false + }) + } + }, + + /** + * 支付成功处理(双重确认) + */ + onPaymentSuccess() { + const { orderId } = this.data + + if (!orderId) { + wx.showToast({ + title: '订单ID不存在', + icon: 'none' + }) + this.setData({ + isSubmitting: false, + isPaying: false + }) + return + } + + // 显示支付成功提示(时间缩短) + wx.showToast({ + title: '支付成功,确认中...', + icon: 'none', + duration: 1500 + }) + + // 开始双重确认流程 + this.checkOrderStatus() + }, + + /** + * 检查订单状态(双重确认) + */ + checkOrderStatus() { + const { orderId, checkCount, maxCheckCount } = this.data + + // 显示加载(时间缩短) + wx.showLoading({ + title: `确认支付状态${checkCount > 0 ? `(${checkCount + 1})` : ''}`, + mask: true + }) + + // 超时设为5秒 + const timeoutTimer = setTimeout(() => { + wx.hideLoading() + this.handleConfirmError('网络超时') + }, 5000) + + // 向后端发起支付复查请求 + request({ + url: '/dingdan/fucha', + method: 'POST', + data: { + dingdanid: orderId + } + }) + .then(res => { + clearTimeout(timeoutTimer) + wx.hideLoading() + + if (res.statusCode === 200 && res.data) { + const response = res.data + + if (response.code === 0) { + // 确认成功,订单状态已更新 + this.handleConfirmSuccess() + } else { + // 后端返回错误 + this.handleConfirmError(response.msg || '订单状态异常') + } + } else { + // 网络错误 + this.handleConfirmError('网络错误') + } + }) + .catch(error => { + clearTimeout(timeoutTimer) + wx.hideLoading() + this.handleConfirmError('检查失败') + }) + }, + + /** + * 处理确认成功 + */ + handleConfirmSuccess() { + // 显示最终成功提示 + wx.showToast({ + title: '购买成功!', + icon: 'success', + duration: 1500 + }) + + // 1.5秒后跳转到首页 + setTimeout(() => { + wx.switchTab({ + url: '/pages/index/index' + }) + }, 1500) + + this.setData({ + isSubmitting: false, + isPaying: false + }) + }, + + /** + * 处理确认错误 + */ + handleConfirmError(errorMsg) { + const { checkCount, maxCheckCount } = this.data + const newCheckCount = checkCount + 1 + + if (newCheckCount < maxCheckCount) { + // 还可以重试 + this.setData({ + checkCount: newCheckCount + }) + + // 1秒后重试 + setTimeout(() => { + this.checkOrderStatus() + }, 1000) + } else { + // 达到最大重试次数 + wx.showModal({ + title: '支付确认中', + content: '支付已成功,但订单状态确认异常。请稍后在订单列表中查看状态,如有问题请联系客服。', + showCancel: false, + confirmText: '我知道了', + success: (res) => { + if (res.confirm) { + wx.switchTab({ + url: '/pages/index/index' + }) + } + } + }) + + this.setData({ + isSubmitting: false, + isPaying: false + }) + } + } }) \ No newline at end of file diff --git a/pages/wodedashou/wodedashou.json b/pages/submit/submit.json similarity index 100% rename from pages/wodedashou/wodedashou.json rename to pages/submit/submit.json diff --git a/pages/tijiao/tijiao.wxml b/pages/submit/submit.wxml similarity index 96% rename from pages/tijiao/tijiao.wxml rename to pages/submit/submit.wxml index 3a6b85e..7d65224 100644 --- a/pages/tijiao/tijiao.wxml +++ b/pages/submit/submit.wxml @@ -1,124 +1,124 @@ - - - - - - - - - - - - - - {{shangpinData && shangpinData.title ? shangpinData.title : '商品标题'}} - - - - - 价格: - - ¥ - {{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}} - .{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}} - - - - - - - - - - - - - 昵称 - * - - - - - - - - 备注 - - - - - - - - 指定服务者ID(选填) - - - - - - - - - 微信支付 - - - - - - - - - - - - 总价: - - ¥ - {{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}} - .{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}} - - - - - {{isSubmitting ? '提交中...' : '提交订单'}} - - - - - - - - - + + + + + + + + + + + + + + {{shangpinData && shangpinData.title ? shangpinData.title : '商品标题'}} + + + + + 价格: + + ¥ + {{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}} + .{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}} + + + + + + + + + + + + + 昵称 + * + + + + + + + + 备注 + + + + + + + + 指定服务者ID(选填) + + + + + + + + + 微信支付 + + + + + + + + + + + + 总价: + + ¥ + {{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}} + .{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}} + + + + + {{isSubmitting ? '提交中...' : '提交订单'}} + + + + + + + + + \ No newline at end of file diff --git a/pages/tijiao/tijiao.wxss b/pages/submit/submit.wxss similarity index 94% rename from pages/tijiao/tijiao.wxss rename to pages/submit/submit.wxss index c622155..484080e 100644 --- a/pages/tijiao/tijiao.wxss +++ b/pages/submit/submit.wxss @@ -1,280 +1,280 @@ -/* pages/tijiao/tijiao.wxss */ - -.submit-page { - display: flex; - flex-direction: column; - min-height: 100vh; - background: linear-gradient(135deg, #f8f9ff 0%, #f0f3ff 100%); - box-sizing: border-box; - } - - /* 商品信息区域 */ - .product-section { - padding: 30rpx 30rpx 20rpx 30rpx; - flex-shrink: 0; - } - - .product-card { - background: white; - border-radius: 20rpx; - padding: 30rpx; - display: flex; - align-items: center; - box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06); - } - - .product-image-box { - width: 160rpx; - height: 160rpx; - border-radius: 16rpx; - overflow: hidden; - background: #f5f5f5; - flex-shrink: 0; - margin-right: 24rpx; - } - - .product-image { - width: 100%; - height: 100%; - } - - .product-info { - flex: 1; - display: flex; - flex-direction: column; - justify-content: space-between; - height: 160rpx; - } - - .product-title { - margin-bottom: 20rpx; - } - - .title-text { - font-size: 30rpx; - font-weight: 600; - color: #222; - line-height: 1.4; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - overflow: hidden; - } - - .price-info { - display: flex; - align-items: baseline; - } - - .price-label { - font-size: 26rpx; - color: #666; - font-weight: 500; - } - - .price-value { - display: flex; - align-items: baseline; - } - - .price-icon { - font-size: 28rpx; - color: #ff4d4f; - font-weight: 600; - } - - .price-integer { - font-size: 38rpx; - color: #ff4d4f; - font-weight: 700; - margin-left: 4rpx; - } - - .price-decimal { - font-size: 28rpx; - color: #ff4d4f; - font-weight: 600; - } - - /* 表单区域 */ - .form-section { - padding: 0 30rpx 20rpx 30rpx; - flex-shrink: 0; - } - - .form-card { - background: white; - border-radius: 20rpx; - padding: 30rpx; - box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.05); - } - - .form-item-row { - display: flex; - align-items: center; - padding: 25rpx 0; - border-bottom: 1rpx solid #f5f5f5; - } - - .form-item-row:last-child { - border-bottom: none; - } - - .item-label-row { - width: 220rpx; - flex-shrink: 0; - display: flex; - align-items: center; - } - - .label-text-bold { - font-size: 30rpx; - font-weight: 600; - color: #333; - } - - .label-required { - font-size: 30rpx; - color: #ff4d4f; - margin-left: 8rpx; - } - - .item-input-row { - flex: 1; - font-size: 28rpx; - color: #222; - height: 60rpx; - line-height: 60rpx; - padding: 0 20rpx; - text-align: right; - background: #fafafa; - border-radius: 10rpx; - } - - .input-placeholder-gray { - color: #999; - font-size: 28rpx; - } - - /* 支付方式 */ - .payment-item { - margin-top: 30rpx; - padding-top: 30rpx; - border-top: 1rpx solid #f0f0f0; - } - - .payment-method { - display: flex; - align-items: center; - padding: 20rpx 0; - } - - .payment-icon { - width: 48rpx; - height: 48rpx; - margin-right: 20rpx; - } - - .payment-text { - font-size: 28rpx; - color: #333; - font-weight: 500; - flex: 1; - } - - .payment-checkbox { - width: 40rpx; - height: 40rpx; - border-radius: 50%; - background: #52c41a; - display: flex; - align-items: center; - justify-content: center; - } - - .checkbox-text { - color: white; - font-size: 28rpx; - font-weight: 600; - } - - /* 底部操作栏 */ - .footer-section { - display: flex; - align-items: center; - justify-content: space-between; - padding: 20rpx 30rpx; - background: white; - box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08); - margin-top: auto; - flex-shrink: 0; - } - - .total-price { - display: flex; - align-items: baseline; - flex: 1; - } - - .total-label { - font-size: 30rpx; - color: #333; - font-weight: 600; - } - - .total-value { - display: flex; - align-items: baseline; - } - - .submit-btn { - width: 240rpx; - height: 88rpx; - border-radius: 44rpx; - display: flex; - align-items: center; - justify-content: center; - position: relative; - overflow: hidden; - transition: all 0.3s; - } - - .submit-btn-active { - background: linear-gradient(135deg, #52c41a, #389e0d); - box-shadow: 0 8rpx 32rpx rgba(255, 77, 79, 0.4); - } - - .submit-btn-disabled { - background: #ccc; - box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1); - } - - .submit-btn-active:active { - transform: scale(0.98); - box-shadow: 0 4rpx 20rpx rgba(255, 77, 79, 0.5); - } - - .btn-text { - font-size: 32rpx; - color: white; - font-weight: 600; - position: relative; - z-index: 2; - } - - .btn-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); - transform: translateX(-100%); - animation: btnGlow 3s infinite; - } - - @keyframes btnGlow { - 0% { transform: translateX(-100%); } - 50% { transform: translateX(100%); } - 100% { transform: translateX(100%); } +/* pages/submit/submit.wxss */ + +.submit-page { + display: flex; + flex-direction: column; + min-height: 100vh; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f3ff 100%); + box-sizing: border-box; + } + + /* 商品信息区域 */ + .product-section { + padding: 30rpx 30rpx 20rpx 30rpx; + flex-shrink: 0; + } + + .product-card { + background: white; + border-radius: 20rpx; + padding: 30rpx; + display: flex; + align-items: center; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06); + } + + .product-image-box { + width: 160rpx; + height: 160rpx; + border-radius: 16rpx; + overflow: hidden; + background: #f5f5f5; + flex-shrink: 0; + margin-right: 24rpx; + } + + .product-image { + width: 100%; + height: 100%; + } + + .product-info { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + height: 160rpx; + } + + .product-title { + margin-bottom: 20rpx; + } + + .title-text { + font-size: 30rpx; + font-weight: 600; + color: #222; + line-height: 1.4; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + } + + .price-info { + display: flex; + align-items: baseline; + } + + .price-label { + font-size: 26rpx; + color: #666; + font-weight: 500; + } + + .price-value { + display: flex; + align-items: baseline; + } + + .price-icon { + font-size: 28rpx; + color: #ff4d4f; + font-weight: 600; + } + + .price-integer { + font-size: 38rpx; + color: #ff4d4f; + font-weight: 700; + margin-left: 4rpx; + } + + .price-decimal { + font-size: 28rpx; + color: #ff4d4f; + font-weight: 600; + } + + /* 表单区域 */ + .form-section { + padding: 0 30rpx 20rpx 30rpx; + flex-shrink: 0; + } + + .form-card { + background: white; + border-radius: 20rpx; + padding: 30rpx; + box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.05); + } + + .form-item-row { + display: flex; + align-items: center; + padding: 25rpx 0; + border-bottom: 1rpx solid #f5f5f5; + } + + .form-item-row:last-child { + border-bottom: none; + } + + .item-label-row { + width: 220rpx; + flex-shrink: 0; + display: flex; + align-items: center; + } + + .label-text-bold { + font-size: 30rpx; + font-weight: 600; + color: #333; + } + + .label-required { + font-size: 30rpx; + color: #ff4d4f; + margin-left: 8rpx; + } + + .item-input-row { + flex: 1; + font-size: 28rpx; + color: #222; + height: 60rpx; + line-height: 60rpx; + padding: 0 20rpx; + text-align: right; + background: #fafafa; + border-radius: 10rpx; + } + + .input-placeholder-gray { + color: #999; + font-size: 28rpx; + } + + /* 支付方式 */ + .payment-item { + margin-top: 30rpx; + padding-top: 30rpx; + border-top: 1rpx solid #f0f0f0; + } + + .payment-method { + display: flex; + align-items: center; + padding: 20rpx 0; + } + + .payment-icon { + width: 48rpx; + height: 48rpx; + margin-right: 20rpx; + } + + .payment-text { + font-size: 28rpx; + color: #333; + font-weight: 500; + flex: 1; + } + + .payment-checkbox { + width: 40rpx; + height: 40rpx; + border-radius: 50%; + background: #52c41a; + display: flex; + align-items: center; + justify-content: center; + } + + .checkbox-text { + color: white; + font-size: 28rpx; + font-weight: 600; + } + + /* 底部操作栏 */ + .footer-section { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20rpx 30rpx; + background: white; + box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08); + margin-top: auto; + flex-shrink: 0; + } + + .total-price { + display: flex; + align-items: baseline; + flex: 1; + } + + .total-label { + font-size: 30rpx; + color: #333; + font-weight: 600; + } + + .total-value { + display: flex; + align-items: baseline; + } + + .submit-btn { + width: 240rpx; + height: 88rpx; + border-radius: 44rpx; + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; + transition: all 0.3s; + } + + .submit-btn-active { + background: linear-gradient(135deg, #52c41a, #389e0d); + box-shadow: 0 8rpx 32rpx rgba(255, 77, 79, 0.4); + } + + .submit-btn-disabled { + background: #ccc; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1); + } + + .submit-btn-active:active { + transform: scale(0.98); + box-shadow: 0 4rpx 20rpx rgba(255, 77, 79, 0.5); + } + + .btn-text { + font-size: 32rpx; + color: white; + font-weight: 600; + position: relative; + z-index: 2; + } + + .btn-glow { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transform: translateX(-100%); + animation: btnGlow 3s infinite; + } + + @keyframes btnGlow { + 0% { transform: translateX(-100%); } + 50% { transform: translateX(100%); } + 100% { transform: translateX(100%); } } \ No newline at end of file diff --git a/pages/renzheng/renzheng.js b/pages/verify/verify.js similarity index 89% rename from pages/renzheng/renzheng.js rename to pages/verify/verify.js index 99703cc..1bb9cde 100644 --- a/pages/renzheng/renzheng.js +++ b/pages/verify/verify.js @@ -1,169 +1,169 @@ -// pages/renzheng/renzheng.js -import request from '../../utils/request.js' -import { enterLockedRole } from '../../utils/primary-role.js' - -const API_MAP = { - dashou: '/yonghu/dashouzhuce', - shangjia: '/yonghu/shangjiahuce', - guanshi: '/yonghu/guanshizhuce', - zuzhang: '/yonghu/zuzhangzhuce', - kaoheguan: '/dengji/khgzc' // 🆕 考核官注册接口 -} - -const STATUS_KEY_MAP = { - dashou: 'dashoustatus', - shangjia: 'shangjiastatus', - guanshi: 'guanshistatus', - zuzhang: 'zuzhangstatus', - kaoheguan: 'kaoheguanstatus' // 🆕 考核官缓存键 -} - -const NAME_MAP = { - dashou: '接单员', - shangjia: '商家', - guanshi: '管事', - zuzhang: '组长', - kaoheguan: '考核官' // 🆕 考核官中文名 -} - -Page({ - data: { - authType: '', - authName: '', - pageState: 'need_register', - inviteCode: '', - isLoading: false, - }, - - onLoad(options) { - const type = options.type || '' - if (!API_MAP[type]) { - wx.showToast({ title: '认证类型错误', icon: 'none' }) - setTimeout(() => wx.navigateBack(), 1500) - return - } - this.setData({ authType: type, authName: NAME_MAP[type] }) - this.checkStatus() - }, - - onShow() { - if (this.data.authType) this.checkStatus() - }, - - checkStatus() { - const key = STATUS_KEY_MAP[this.data.authType] - const val = wx.getStorageSync(key) - if (val === 1) { - this.setData({ pageState: 'done' }) - } else { - this.setData({ pageState: 'need_register' }) - } - }, - - onInviteCodeInput(e) { - this.setData({ inviteCode: e.detail.value.trim() }) - }, - - async onRegister() { - const { inviteCode, authType } = this.data - if (!inviteCode) { - wx.showToast({ title: '请输入邀请码', icon: 'none' }) - return - } - if (inviteCode.length > 100) { - wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' }) - return - } - - this.setData({ isLoading: true }) - wx.showLoading({ title: '注册中...', mask: true }) - - try { - const res = await request({ - url: API_MAP[authType], - method: 'POST', - data: { inviteCode } - }) - - if (res && res.data.code === 200) { - const data = res.data.data || res.data - const app = getApp() - - // ----- 缓存身份状态(完全由后端决定) ----- - const key = STATUS_KEY_MAP[authType] - if (data[key] !== undefined) { - wx.setStorageSync(key, data[key]) - app.globalData[key] = data[key] - } else { - wx.setStorageSync(key, 1) - app.globalData[key] = 1 - } - - // 更新其他可能返回的身份状态字段 - const allKeys = ['dashoustatus', 'shangjiastatus', 'guanshistatus', 'zuzhangstatus', 'kaoheguanstatus'] // 🆕 新增 - allKeys.forEach(k => { - if (data[k] !== undefined && k !== key) { - wx.setStorageSync(k, data[k]) - app.globalData[k] = data[k] - } - }) - - // 保存各身份详细信息(参照各注册页面的处理) - if (authType === 'dashou') { - const fields = ['dashounicheng','zhanghaostatus','yongjin','zonge','yajin','chenghao','jifen','clumber','chengjiaoliang','zaixianzhuangtai'] - fields.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] }) - } else if (authType === 'shangjia') { - app.globalData.shangjia = app.globalData.shangjia || {} - const sf = ['nicheng','sjyue','fabu','chengjiao','tuikuan','jinridingdan','jinriliushui','jinyuedingdan','jinyueliushui','zhuangtai'] - sf.forEach(f => { if (data[f] !== undefined) app.globalData.shangjia[f] = data[f] }) - } else if (authType === 'guanshi') { - app.globalData.guanshi = app.globalData.guanshi || {} - const gf = ['gszhstatus','yaoqingzongshu','fenyongzonge','fenyongtixian','yichongzhiDashou'] - gf.forEach(f => { if (data[f] !== undefined) app.globalData.guanshi[f] = data[f] }) - } else if (authType === 'zuzhang') { - const zf = ['ketixian','guanshiCount','fenhongZonge'] - zf.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] }) - } else if (authType === 'kaoheguan') { // 🆕 考核官数据更新 - app.globalData.kaoheguan = app.globalData.kaoheguan || {} - const kf = ['shenhe_zongshu','tongguo_zongshu','yue','zonge','shenhe_zhuangtai','bankuai_list'] - kf.forEach(f => { if (data[f] !== undefined) app.globalData.kaoheguan[f] = data[f] }) - } - - wx.hideLoading() - this.setData({ isLoading: false, pageState: 'done' }) - wx.showToast({ title: '认证成功', icon: 'success' }) - - if (authType === 'dashou' || authType === 'shangjia') { - setTimeout(() => enterLockedRole(authType), 1200) - } else if (authType === 'guanshi') { - setTimeout(() => { - const pages = getCurrentPages() - if (pages.length > 1) { - wx.navigateBack() - } else { - wx.redirectTo({ url: '/pages/dashouduan/dashouduan' }) - } - }, 800) - } - } else { - wx.hideLoading() - this.setData({ isLoading: false }) - wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none' }) - } - } catch (err) { - wx.hideLoading() - this.setData({ isLoading: false }) - wx.showToast({ title: err.message || '注册失败', icon: 'none' }) - } - }, - - goToKefu() { - const app = getApp() - const { link, enterpriseId } = app.globalData.kefuConfig || {} - if (!link || !enterpriseId) { - wx.showToast({ title: '客服配置未加载', icon: 'none' }) - return - } - wx.openCustomerServiceChat({ extInfo: { url: link }, corpId: enterpriseId }) - } +// pages/verify/verify.js +import request from '../../utils/request.js' +import { enterLockedRole } from '../../utils/primary-role.js' + +const API_MAP = { + dashou: '/yonghu/dashouzhuce', + shangjia: '/yonghu/shangjiahuce', + guanshi: '/yonghu/guanshizhuce', + zuzhang: '/yonghu/zuzhangzhuce', + kaoheguan: '/dengji/khgzc' +} + +const STATUS_KEY_MAP = { + dashou: 'dashoustatus', + shangjia: 'shangjiastatus', + guanshi: 'guanshistatus', + zuzhang: 'zuzhangstatus', + kaoheguan: 'kaoheguanstatus' +} + +const NAME_MAP = { + dashou: '接单员', + shangjia: '商家', + guanshi: '管事', + zuzhang: '组长', + kaoheguan: '考核官' +} + +Page({ + data: { + authType: '', + authName: '', + pageState: 'need_register', + inviteCode: '', + isLoading: false, + }, + + onLoad(options) { + const type = options.type || '' + if (!API_MAP[type]) { + wx.showToast({ title: '认证类型错误', icon: 'none' }) + setTimeout(() => wx.navigateBack(), 1500) + return + } + this.setData({ authType: type, authName: NAME_MAP[type] }) + this.checkStatus() + }, + + onShow() { + if (this.data.authType) this.checkStatus() + }, + + checkStatus() { + const key = STATUS_KEY_MAP[this.data.authType] + const val = wx.getStorageSync(key) + if (val === 1) { + this.setData({ pageState: 'done' }) + } else { + this.setData({ pageState: 'need_register' }) + } + }, + + onInviteCodeInput(e) { + this.setData({ inviteCode: e.detail.value.trim() }) + }, + + async onRegister() { + const { inviteCode, authType } = this.data + if (!inviteCode) { + wx.showToast({ title: '请输入邀请码', icon: 'none' }) + return + } + if (inviteCode.length > 100) { + wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' }) + return + } + + this.setData({ isLoading: true }) + wx.showLoading({ title: '注册中...', mask: true }) + + try { + const res = await request({ + url: API_MAP[authType], + method: 'POST', + data: { inviteCode } + }) + + if (res && res.data.code === 200) { + const data = res.data.data || res.data + const app = getApp() + + // 缓存身份状态 + const key = STATUS_KEY_MAP[authType] + if (data[key] !== undefined) { + wx.setStorageSync(key, data[key]) + app.globalData[key] = data[key] + } else { + wx.setStorageSync(key, 1) + app.globalData[key] = 1 + } + + // 更新其他可能返回的身份状态字段 + const allKeys = ['dashoustatus', 'shangjiastatus', 'guanshistatus', 'zuzhangstatus', 'kaoheguanstatus'] + allKeys.forEach(k => { + if (data[k] !== undefined && k !== key) { + wx.setStorageSync(k, data[k]) + app.globalData[k] = data[k] + } + }) + + // 保存各身份详细信息 + if (authType === 'dashou') { + const fields = ['dashounicheng','zhanghaostatus','yongjin','zonge','yajin','chenghao','jifen','clumber','chengjiaoliang','zaixianzhuangtai'] + fields.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] }) + } else if (authType === 'shangjia') { + app.globalData.shangjia = app.globalData.shangjia || {} + const sf = ['nicheng','sjyue','fabu','chengjiao','tuikuan','jinridingdan','jinriliushui','jinyuedingdan','jinyueliushui','zhuangtai'] + sf.forEach(f => { if (data[f] !== undefined) app.globalData.shangjia[f] = data[f] }) + } else if (authType === 'guanshi') { + app.globalData.guanshi = app.globalData.guanshi || {} + const gf = ['gszhstatus','yaoqingzongshu','fenyongzonge','fenyongtixian','yichongzhiDashou'] + gf.forEach(f => { if (data[f] !== undefined) app.globalData.guanshi[f] = data[f] }) + } else if (authType === 'zuzhang') { + const zf = ['ketixian','guanshiCount','fenhongZonge'] + zf.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] }) + } else if (authType === 'kaoheguan') { + app.globalData.kaoheguan = app.globalData.kaoheguan || {} + const kf = ['shenhe_zongshu','tongguo_zongshu','yue','zonge','shenhe_zhuangtai','bankuai_list'] + kf.forEach(f => { if (data[f] !== undefined) app.globalData.kaoheguan[f] = data[f] }) + } + + wx.hideLoading() + this.setData({ isLoading: false, pageState: 'done' }) + wx.showToast({ title: '认证成功', icon: 'success' }) + + if (authType === 'dashou' || authType === 'shangjia') { + setTimeout(() => enterLockedRole(authType), 1200) + } else if (authType === 'guanshi') { + setTimeout(() => { + const pages = getCurrentPages() + if (pages.length > 1) { + wx.navigateBack() + } else { + wx.redirectTo({ url: '/pages/fighter/fighter' }) + } + }, 800) + } + } else { + wx.hideLoading() + this.setData({ isLoading: false }) + wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none' }) + } + } catch (err) { + wx.hideLoading() + this.setData({ isLoading: false }) + wx.showToast({ title: err.message || '注册失败', icon: 'none' }) + } + }, + + goToKefu() { + const app = getApp() + const { link, enterpriseId } = app.globalData.kefuConfig || {} + if (!link || !enterpriseId) { + wx.showToast({ title: '客服配置未加载', icon: 'none' }) + return + } + wx.openCustomerServiceChat({ extInfo: { url: link }, corpId: enterpriseId }) + } }) \ No newline at end of file diff --git a/pages/renzheng/renzheng.json b/pages/verify/verify.json similarity index 100% rename from pages/renzheng/renzheng.json rename to pages/verify/verify.json diff --git a/pages/renzheng/renzheng.wxml b/pages/verify/verify.wxml similarity index 95% rename from pages/renzheng/renzheng.wxml rename to pages/verify/verify.wxml index 5b4b678..5c78d76 100644 --- a/pages/renzheng/renzheng.wxml +++ b/pages/verify/verify.wxml @@ -1,29 +1,29 @@ - - - - - {{authName}}认证 - 您尚未注册此角色或账号已被封禁,请输入邀请码注册或联系客服 - - - - - {{isLoading ? '注册中…' : '立即注册'}} - - 联系客服 - - - - - - 认证成功 - - 您已是{{authName}}身份, - 请退出此页面点击底部导航栏左侧的 - 「切换」 - 按钮,选择 - 「{{authName}}」 - 即可开始使用。 - - + + + + + {{authName}}认证 + 您尚未注册此角色或账号已被封禁,请输入邀请码注册或联系客服 + + + + + {{isLoading ? '注册中…' : '立即注册'}} + + 联系客服 + + + + + + 认证成功 + + 您已是{{authName}}身份, + 请退出此页面点击底部导航栏左侧的 + 「切换」 + 按钮,选择 + 「{{authName}}」 + 即可开始使用。 + + \ No newline at end of file diff --git a/pages/renzheng/renzheng.wxss b/pages/verify/verify.wxss similarity index 95% rename from pages/renzheng/renzheng.wxss rename to pages/verify/verify.wxss index 1dbbb97..277408d 100644 --- a/pages/renzheng/renzheng.wxss +++ b/pages/verify/verify.wxss @@ -34,9 +34,6 @@ page { } .input-box { - background: #F7F3ED; - border-radius: 24rpx; - padding: 0 24rpx; margin-bottom: 40rpx; } diff --git a/pages/tixian/components/mode1/mode1.js b/pages/withdraw/components/mode1/mode1.js similarity index 97% rename from pages/tixian/components/mode1/mode1.js rename to pages/withdraw/components/mode1/mode1.js index 097c9aa..13cd3eb 100644 --- a/pages/tixian/components/mode1/mode1.js +++ b/pages/withdraw/components/mode1/mode1.js @@ -1,484 +1,484 @@ -// pages/tixian/tixian.js -// 子组件版本 - 完整代码,仅适配生命周期,业务逻辑不动 - -import request from '../../../../utils/request.js'; -import upload from '../../../../utils/upload.js'; -import PopupService from '../../../../services/popupService.js'; - -const app = getApp(); -const PAGE_SIZE = 10; -let lastPullDownTime = 0; -const PULL_DOWN_INTERVAL = 2000; - -Component({ - data: { - imgUrls: { - pageBg: '', - cardBg: '', - iconWechat: '', - iconAlipay: '', - iconRecord: '', - iconRefresh: '', - }, - assetList: [], - totalAmount: '0.00', - selectedAsset: null, - txfangshi: null, - txdianhua: '', - txzh: '', - txtupian: '', - ossImageUrl: '', - showTixianModal: false, - tixianAmount: '', - shouxufei: '0.00', - shijidaozhang: '0.00', - currentRate: '0.00', - recordList: [], - page: 1, - nomore: false, - loading: false, - isRefreshing: false, - canloadmore: true, - showSkfsModal: false, - tempTxfangshi: null, - tempTxPhone: '', - tempTxAccount: '', - tempTxImage: '', - choosingImage: false, - showModifyModal: false, - modifyingRecord: null, - modifyTxfangshi: null, - modifyTxPhone: '', - modifyTxAccount: '', - modifyTxImage: '', - modifyImageUrl: '', - showFailModal: false, - currentFailReason: '', - isLoading: false, - }, - - attached() { - this.initImageUrls(); - this.loadAllAssets(); - this.loadWithdrawMethod(); - this.loadWithdrawRecords(true); - }, - - pageLifetimes: { - show() { - this.registerNotification(); - PopupService.checkAndShow(this, 'tixian'); - }, - hide() { - const popup = this.selectComponent('#popupNotice'); - popup?.cleanup?.(); - } - }, - - methods: { - // 下拉刷新 - onPullDownRefresh() { - if (this.data.isRefreshing) { - wx.stopPullDownRefresh(); - return; - } - this.setData({ isRefreshing: true }); - this.loadWithdrawRecords(true).then(() => { - wx.stopPullDownRefresh(); - this.setData({ isRefreshing: false }); - }).catch(() => { - wx.stopPullDownRefresh(); - this.setData({ isRefreshing: false }); - }); - }, - - // 底部按钮加载更多 - loadMoreRecords() { - if (this.data.nomore) { - wx.showToast({ title: '没有更多记录了', icon: 'none' }); - return; - } - if (this.data.loading) return; - this.loadWithdrawRecords(); - }, - - initImageUrls() { - const ossBase = app.globalData.ossImageUrl || ''; - const imgDir = `${ossBase}beijing/tixian/`; - this.setData({ - imgUrls: { - pageBg: `${imgDir}page_bg.png`, - cardBg: `${imgDir}card_bg.png`, - iconWechat: `${imgDir}icon_wechat.png`, - iconAlipay: `${imgDir}icon_alipay.png`, - iconRecord: `${imgDir}icon_record.png`, - iconRefresh: `${imgDir}icon_refresh.png`, - assetTileBg: `${imgDir}asset_tile_bg.png`, - } - }); - }, - - async loadAllAssets() { - this.setData({ isLoading: true }); - try { - const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' }); - if (res?.data?.code === 200) { - const data = res.data.data; - const assets = []; - if (data.dashou_yue && parseFloat(data.dashou_yue) > 0) { - assets.push({ type: 'dashou_yue', label: '打手佣金', amount: data.dashou_yue, rate: data.dashou_rate || 0 }); - } - if (data.dashou_yajin && parseFloat(data.dashou_yajin) > 0) { - assets.push({ type: 'dashou_yajin', label: '打手保证金', amount: data.dashou_yajin, rate: data.dashou_yajin_rate || 0 }); - } - if (data.shangjia_yue && parseFloat(data.shangjia_yue) > 0) { - assets.push({ type: 'shangjia_yue', label: '商家余额', amount: data.shangjia_yue, rate: data.shangjia_rate || 0 }); - } - if (data.guanshi_fenyong && parseFloat(data.guanshi_fenyong) > 0) { - assets.push({ type: 'guanshi_fenyong', label: '管事分红', amount: data.guanshi_fenyong, rate: data.guanshi_rate || 0 }); - } - if (data.zuzhang_fenyong && parseFloat(data.zuzhang_fenyong) > 0) { - assets.push({ type: 'zuzhang_fenyong', label: '组长分红', amount: data.zuzhang_fenyong, rate: data.zuzhang_rate || 0 }); - } - if (data.kaoheguan_fenyong && parseFloat(data.kaoheguan_fenyong) > 0) { - assets.push({ type: 'kaoheguan_fenyong', label: '考核官分佣', amount: data.kaoheguan_fenyong, rate: data.kaoheguan_rate || 0 }); - } - let total = 0; - assets.forEach(item => { total += parseFloat(item.amount); }); - this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoading: false }); - // 缓存费率 - wx.setStorageSync('dashouRate', data.dashou_rate || 0); - wx.setStorageSync('dashou_yajin_rate', data.dashou_yajin_rate || 0); - wx.setStorageSync('shangjia_rate', data.shangjia_rate || 0); - wx.setStorageSync('guanshi_rate', data.guanshi_rate || 0); - wx.setStorageSync('zuzhang_rate', data.zuzhang_rate || 0); - wx.setStorageSync('kaoheguan_rate', data.kaoheguan_rate || 0); - } else { - throw new Error(res?.data?.msg || '获取资产失败'); - } - } catch (err) { - console.error(err); - wx.showToast({ title: '加载失败', icon: 'none' }); - this.setData({ isLoading: false }); - } - }, - - async loadWithdrawMethod() { - const txzh = wx.getStorageSync('txzh') || ''; - const txtupian = wx.getStorageSync('txtupian') || ''; - const txfangshi = wx.getStorageSync('txfangshi') || null; - const txdianhua = wx.getStorageSync('txdianhua') || ''; - if (txzh || txtupian) { - this.setData({ txzh, txtupian, txfangshi, txdianhua, ossImageUrl: app.globalData.ossImageUrl || '' }); - } else { - try { - const res = await request({ url: '/yonghu/tixianhq', method: 'POST' }); - if (res?.data?.code === 0) { - const data = res.data.data; - this.setData({ - txzh: data.txzh || '', - txtupian: data.txtupian || '', - txfangshi: data.txfangshi || null, - txdianhua: data.txdianhua || '', - }); - wx.setStorageSync('txzh', data.txzh || ''); - wx.setStorageSync('txtupian', data.txtupian || ''); - wx.setStorageSync('txfangshi', data.txfangshi || null); - wx.setStorageSync('txdianhua', data.txdianhua || ''); - } - } catch (err) {} - } - }, - - onSelectAsset(e) { - const index = e.currentTarget.dataset.index; - const asset = this.data.assetList[index]; - if (!asset || parseFloat(asset.amount) <= 0) { - wx.showToast({ title: '无可提现金额', icon: 'none' }); - return; - } - this.setData({ - selectedAsset: asset, - showTixianModal: true, - tixianAmount: '', - shouxufei: '0.00', - shijidaozhang: '0.00', - currentRate: asset.rate - }); - }, - - onAmountInput(e) { - let val = e.detail.value; - if (val && !/^\d*\.?\d{0,2}$/.test(val)) return; - this.setData({ tixianAmount: val }); - if (val && parseFloat(val) > 0) { - const amount = parseFloat(val); - const rate = parseFloat(this.data.selectedAsset.rate) || 0; - const fee = amount * rate; - const actual = amount - fee; - this.setData({ shouxufei: fee.toFixed(2), shijidaozhang: actual.toFixed(2) }); - } else { - this.setData({ shouxufei: '0.00', shijidaozhang: '0.00' }); - } - }, - - onQuickAmount(e) { - const val = e.currentTarget.dataset.value; - this.setData({ tixianAmount: val.toString() }); - this.onAmountInput({ detail: { value: val.toString() } }); - }, - - async onConfirmWithdraw() { - const { selectedAsset, tixianAmount, txfangshi, txzh, txtupian, txdianhua } = this.data; - if (!selectedAsset) { wx.showToast({ title: '请选择提现项目', icon: 'none' }); return; } - const amount = parseFloat(tixianAmount); - if (isNaN(amount) || amount <= 0) { wx.showToast({ title: '请输入有效金额', icon: 'none' }); return; } - if (amount > parseFloat(selectedAsset.amount)) { wx.showToast({ title: '超过可提现金额', icon: 'none' }); return; } - if (!txfangshi || (!txzh && !txtupian)) { - wx.showToast({ title: '请先设置收款方式', icon: 'none' }); - this.setData({ showTixianModal: false }); - this.onSetSkfs(); - return; - } - let leixing = 1; - switch (selectedAsset.type) { - case 'dashou_yue': leixing = 1; break; - case 'dashou_yajin': leixing = 5; break; - case 'shangjia_yue': leixing = 6; break; - case 'guanshi_fenyong': leixing = 2; break; - case 'zuzhang_fenyong': leixing = 3; break; - case 'kaoheguan_fenyong': leixing = 4; break; - } - let txskfs = 0; - if (txzh && txtupian) txskfs = 3; - else if (txzh) txskfs = 1; - else if (txtupian) txskfs = 2; - try { - const res = await request({ - url: '/yonghu/tixian', - method: 'POST', - data: { leixing, jine: amount.toFixed(2), fangshi: txfangshi, txskfs } - }); - if (res?.data?.code === 0) { - const newAssetList = this.data.assetList.map(item => { - if (item.type === selectedAsset.type) { - const newAmount = (parseFloat(item.amount) - amount).toFixed(2); - return { ...item, amount: newAmount }; - } - return item; - }); - let newTotal = 0; - newAssetList.forEach(item => { newTotal += parseFloat(item.amount); }); - this.setData({ assetList: newAssetList, totalAmount: newTotal.toFixed(2), showTixianModal: false, selectedAsset: null }); - this.loadWithdrawRecords(true); - wx.showToast({ title: '提现申请已提交', icon: 'success' }); - } else { - wx.showToast({ title: res?.data?.msg || '提现失败', icon: 'none' }); - } - } catch (err) { - wx.showToast({ title: '网络错误', icon: 'none' }); - } - }, - - onCloseTixianModal() { - this.setData({ showTixianModal: false, selectedAsset: null, tixianAmount: '' }); - }, - - onSetSkfs() { - this.setData({ - showSkfsModal: true, - tempTxfangshi: this.data.txfangshi, - tempTxPhone: this.data.txdianhua, - tempTxAccount: this.data.txzh, - tempTxImage: '' - }); - }, - - onSelectFangshi(e) { - this.setData({ tempTxfangshi: e.currentTarget.dataset.fangshi }); - }, - - onPhoneInput(e) { this.setData({ tempTxPhone: e.detail.value }); }, - onAccountInput(e) { this.setData({ tempTxAccount: e.detail.value }); }, - - onChooseImage() { - if (this.data.choosingImage) return; - this.setData({ choosingImage: true }); - wx.chooseMedia({ - count: 1, mediaType: ['image'], - success: (res) => { this.setData({ tempTxImage: res.tempFiles[0].tempFilePath }); }, - complete: () => { this.setData({ choosingImage: false }); } - }); - }, - - onPreviewImage() { - if (this.data.tempTxImage) wx.previewImage({ urls: [this.data.tempTxImage] }); - }, - - onDeleteImage() { this.setData({ tempTxImage: '' }); }, - - async onConfirmSkfs() { - const { tempTxfangshi, tempTxPhone, tempTxAccount, tempTxImage } = this.data; - if (!tempTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; } - if (!tempTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; } - if (tempTxfangshi == 1 && !tempTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; } - if (tempTxfangshi == 2 && !tempTxAccount && !tempTxImage) { - wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return; - } - const formData = { txdianhua: tempTxPhone, txzh: tempTxAccount || '' }; - try { - const res = await upload({ url: '/yonghu/sksc', formData, filePath: tempTxImage || null, fileName: 'file' }); - if (res?.data?.code === 0) { - const data = res.data.data; - this.setData({ - txfangshi: tempTxfangshi, txdianhua: tempTxPhone, txzh: data.txzh || '', txtupian: data.txtupian || '', showSkfsModal: false - }); - wx.setStorageSync('txfangshi', tempTxfangshi); - wx.setStorageSync('txdianhua', tempTxPhone); - wx.setStorageSync('txzh', data.txzh || ''); - wx.setStorageSync('txtupian', data.txtupian || ''); - wx.showToast({ title: '设置成功', icon: 'success' }); - } else { - wx.showToast({ title: res?.data?.msg || '保存失败', icon: 'none' }); - } - } catch (err) { - wx.showToast({ title: '网络错误', icon: 'none' }); - } - }, - - onCloseSkfsModal() { this.setData({ showSkfsModal: false }); }, - - async loadWithdrawRecords(refresh = false) { - const now = Date.now(); - if (now - lastPullDownTime < PULL_DOWN_INTERVAL && !refresh) return; - if (this.data.loading || this.data.isRefreshing) return; - const page = refresh ? 1 : this.data.page; - if (this.data.nomore && !refresh) return; - this.setData({ loading: true, isRefreshing: refresh }); - lastPullDownTime = now; - try { - const res = await request({ url: '/yonghu/tixianjiluhq', method: 'POST', data: { page, limit: PAGE_SIZE } }); - if (res?.data?.code === 0) { - const list = (res.data.data.list || []).map(item => ({ - ...item, - statusText: this.getStatusText(item.zhuangtai), - statusColor: this.getStatusColor(item.zhuangtai) - })); - const newList = refresh ? list : [...this.data.recordList, ...list]; - const hasMore = res.data.data.has_more === true; - this.setData({ - recordList: newList, page: page + 1, nomore: !hasMore, canloadmore: hasMore, - loading: false, isRefreshing: false - }); - } else { - this.setData({ loading: false, isRefreshing: false }); - } - } catch (err) { - this.setData({ loading: false, isRefreshing: false }); - } - }, - - onModifyRecord(e) { - const record = e.currentTarget.dataset.record; - if (parseInt(record.zhuangtai) !== 1) { - wx.showToast({ title: '只有审核中的记录可修改', icon: 'none' }); - return; - } - this.setData({ - modifyingRecord: record, - modifyTxfangshi: record.fangshi, - modifyTxPhone: record.txdianhua || '', - modifyTxAccount: record.txzh || '', - modifyTxImage: '', - modifyImageUrl: record.txtupian ? (app.globalData.ossImageUrl + record.txtupian) : '', - showModifyModal: true - }); - }, - - onSelectModifyFangshi(e) { this.setData({ modifyTxfangshi: e.currentTarget.dataset.fangshi }); }, - onModifyPhoneInput(e) { this.setData({ modifyTxPhone: e.detail.value }); }, - onModifyAccountInput(e) { this.setData({ modifyTxAccount: e.detail.value }); }, - - onChooseModifyImage() { - if (this.data.choosingImage) return; - this.setData({ choosingImage: true }); - wx.chooseMedia({ - count: 1, mediaType: ['image'], - success: (res) => { this.setData({ modifyTxImage: res.tempFiles[0].tempFilePath }); }, - complete: () => { this.setData({ choosingImage: false }); } - }); - }, - - onPreviewModifyImage() { - if (this.data.modifyTxImage) wx.previewImage({ urls: [this.data.modifyTxImage] }); - else if (this.data.modifyImageUrl) wx.previewImage({ urls: [this.data.modifyImageUrl] }); - }, - - onDeleteModifyImage() { this.setData({ modifyTxImage: '' }); }, - - async onConfirmModify() { - const { modifyTxfangshi, modifyTxPhone, modifyTxAccount, modifyTxImage, modifyingRecord } = this.data; - if (!modifyTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; } - if (!modifyTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; } - if (modifyTxfangshi == 1 && !modifyTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; } - if (modifyTxfangshi == 2 && !modifyTxAccount && !modifyTxImage) { - wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return; - } - const formData = { tixian_id: modifyingRecord.id, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '' }; - try { - const res = await upload({ url: '/yonghu/yonghutxshxg', formData, filePath: modifyTxImage || null, fileName: 'file' }); - if (res?.data?.code === 0) { - const data = res.data.data; - const newList = this.data.recordList.map(item => { - if (item.id === modifyingRecord.id) { - return { ...item, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '', txtupian: data.txtupian || modifyingRecord.txtupian }; - } - return item; - }); - this.setData({ recordList: newList, showModifyModal: false, modifyingRecord: null }); - wx.showToast({ title: '修改成功', icon: 'success' }); - } else { - wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' }); - } - } catch (err) { - wx.showToast({ title: '网络错误', icon: 'none' }); - } - }, - - onCloseModifyModal() { this.setData({ showModifyModal: false, modifyingRecord: null }); }, - - onViewFailReason(e) { - const record = e.currentTarget.dataset.record; - const reason = record.fail_reason || record.shibaiyuanyin || '暂无详细信息'; - this.setData({ currentFailReason: reason, showFailModal: true }); - }, - - onCloseFailModal() { this.setData({ showFailModal: false }); }, - - getStatusText(zhuangtai) { - const s = parseInt(zhuangtai); - if (s === 1) return '审核中'; - if (s === 2) return '成功'; - if (s === 3) return '失败'; - return '未知'; - }, - getStatusColor(zhuangtai) { - const s = parseInt(zhuangtai); - if (s === 1) return '#F5A623'; - if (s === 2) return '#2ED158'; - if (s === 3) return '#FF4D4F'; - return '#999'; - }, - - registerNotification() { - const comp = this.selectComponent('#global-notification'); - if (comp?.showNotification) { - app.globalData.globalNotification = { - show: (data) => comp.showNotification(data), - hide: () => comp.hideNotification() - }; - } - }, - stopPropagation() {} - } +// pages/withdraw/withdraw.js +// 子组件版本 - 完整代码,仅适配生命周期,业务逻辑不动 + +import request from '../../../../utils/request.js'; +import upload from '../../../../utils/upload.js'; +import PopupService from '../../../../services/popupService.js'; + +const app = getApp(); +const PAGE_SIZE = 10; +let lastPullDownTime = 0; +const PULL_DOWN_INTERVAL = 2000; + +Component({ + data: { + imgUrls: { + pageBg: '', + cardBg: '', + iconWechat: '', + iconAlipay: '', + iconRecord: '', + iconRefresh: '', + }, + assetList: [], + totalAmount: '0.00', + selectedAsset: null, + txfangshi: null, + txdianhua: '', + txzh: '', + txtupian: '', + ossImageUrl: '', + showTixianModal: false, + tixianAmount: '', + shouxufei: '0.00', + shijidaozhang: '0.00', + currentRate: '0.00', + recordList: [], + page: 1, + nomore: false, + loading: false, + isRefreshing: false, + canloadmore: true, + showSkfsModal: false, + tempTxfangshi: null, + tempTxPhone: '', + tempTxAccount: '', + tempTxImage: '', + choosingImage: false, + showModifyModal: false, + modifyingRecord: null, + modifyTxfangshi: null, + modifyTxPhone: '', + modifyTxAccount: '', + modifyTxImage: '', + modifyImageUrl: '', + showFailModal: false, + currentFailReason: '', + isLoading: false, + }, + + attached() { + this.initImageUrls(); + this.loadAllAssets(); + this.loadWithdrawMethod(); + this.loadWithdrawRecords(true); + }, + + pageLifetimes: { + show() { + this.registerNotification(); + PopupService.checkAndShow(this, 'tixian'); + }, + hide() { + const popup = this.selectComponent('#popupNotice'); + popup?.cleanup?.(); + } + }, + + methods: { + // 下拉刷新 + onPullDownRefresh() { + if (this.data.isRefreshing) { + wx.stopPullDownRefresh(); + return; + } + this.setData({ isRefreshing: true }); + this.loadWithdrawRecords(true).then(() => { + wx.stopPullDownRefresh(); + this.setData({ isRefreshing: false }); + }).catch(() => { + wx.stopPullDownRefresh(); + this.setData({ isRefreshing: false }); + }); + }, + + // 底部按钮加载更多 + loadMoreRecords() { + if (this.data.nomore) { + wx.showToast({ title: '没有更多记录了', icon: 'none' }); + return; + } + if (this.data.loading) return; + this.loadWithdrawRecords(); + }, + + initImageUrls() { + const ossBase = app.globalData.ossImageUrl || ''; + const imgDir = `${ossBase}beijing/tixian/`; + this.setData({ + imgUrls: { + pageBg: `${imgDir}page_bg.png`, + cardBg: `${imgDir}card_bg.png`, + iconWechat: `${imgDir}icon_wechat.png`, + iconAlipay: `${imgDir}icon_alipay.png`, + iconRecord: `${imgDir}icon_record.png`, + iconRefresh: `${imgDir}icon_refresh.png`, + assetTileBg: `${imgDir}asset_tile_bg.png`, + } + }); + }, + + async loadAllAssets() { + this.setData({ isLoading: true }); + try { + const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' }); + if (res?.data?.code === 200) { + const data = res.data.data; + const assets = []; + if (data.dashou_yue && parseFloat(data.dashou_yue) > 0) { + assets.push({ type: 'dashou_yue', label: '打手佣金', amount: data.dashou_yue, rate: data.dashou_rate || 0 }); + } + if (data.dashou_yajin && parseFloat(data.dashou_yajin) > 0) { + assets.push({ type: 'dashou_yajin', label: '打手保证金', amount: data.dashou_yajin, rate: data.dashou_yajin_rate || 0 }); + } + if (data.shangjia_yue && parseFloat(data.shangjia_yue) > 0) { + assets.push({ type: 'shangjia_yue', label: '商家余额', amount: data.shangjia_yue, rate: data.shangjia_rate || 0 }); + } + if (data.guanshi_fenyong && parseFloat(data.guanshi_fenyong) > 0) { + assets.push({ type: 'guanshi_fenyong', label: '管事分红', amount: data.guanshi_fenyong, rate: data.guanshi_rate || 0 }); + } + if (data.zuzhang_fenyong && parseFloat(data.zuzhang_fenyong) > 0) { + assets.push({ type: 'zuzhang_fenyong', label: '组长分红', amount: data.zuzhang_fenyong, rate: data.zuzhang_rate || 0 }); + } + if (data.kaoheguan_fenyong && parseFloat(data.kaoheguan_fenyong) > 0) { + assets.push({ type: 'kaoheguan_fenyong', label: '考核官分佣', amount: data.kaoheguan_fenyong, rate: data.kaoheguan_rate || 0 }); + } + let total = 0; + assets.forEach(item => { total += parseFloat(item.amount); }); + this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoading: false }); + // 缓存费率 + wx.setStorageSync('dashouRate', data.dashou_rate || 0); + wx.setStorageSync('dashou_yajin_rate', data.dashou_yajin_rate || 0); + wx.setStorageSync('shangjia_rate', data.shangjia_rate || 0); + wx.setStorageSync('guanshi_rate', data.guanshi_rate || 0); + wx.setStorageSync('zuzhang_rate', data.zuzhang_rate || 0); + wx.setStorageSync('kaoheguan_rate', data.kaoheguan_rate || 0); + } else { + throw new Error(res?.data?.msg || '获取资产失败'); + } + } catch (err) { + console.error(err); + wx.showToast({ title: '加载失败', icon: 'none' }); + this.setData({ isLoading: false }); + } + }, + + async loadWithdrawMethod() { + const txzh = wx.getStorageSync('txzh') || ''; + const txtupian = wx.getStorageSync('txtupian') || ''; + const txfangshi = wx.getStorageSync('txfangshi') || null; + const txdianhua = wx.getStorageSync('txdianhua') || ''; + if (txzh || txtupian) { + this.setData({ txzh, txtupian, txfangshi, txdianhua, ossImageUrl: app.globalData.ossImageUrl || '' }); + } else { + try { + const res = await request({ url: '/yonghu/tixianhq', method: 'POST' }); + if (res?.data?.code === 0) { + const data = res.data.data; + this.setData({ + txzh: data.txzh || '', + txtupian: data.txtupian || '', + txfangshi: data.txfangshi || null, + txdianhua: data.txdianhua || '', + }); + wx.setStorageSync('txzh', data.txzh || ''); + wx.setStorageSync('txtupian', data.txtupian || ''); + wx.setStorageSync('txfangshi', data.txfangshi || null); + wx.setStorageSync('txdianhua', data.txdianhua || ''); + } + } catch (err) {} + } + }, + + onSelectAsset(e) { + const index = e.currentTarget.dataset.index; + const asset = this.data.assetList[index]; + if (!asset || parseFloat(asset.amount) <= 0) { + wx.showToast({ title: '无可提现金额', icon: 'none' }); + return; + } + this.setData({ + selectedAsset: asset, + showTixianModal: true, + tixianAmount: '', + shouxufei: '0.00', + shijidaozhang: '0.00', + currentRate: asset.rate + }); + }, + + onAmountInput(e) { + let val = e.detail.value; + if (val && !/^\d*\.?\d{0,2}$/.test(val)) return; + this.setData({ tixianAmount: val }); + if (val && parseFloat(val) > 0) { + const amount = parseFloat(val); + const rate = parseFloat(this.data.selectedAsset.rate) || 0; + const fee = amount * rate; + const actual = amount - fee; + this.setData({ shouxufei: fee.toFixed(2), shijidaozhang: actual.toFixed(2) }); + } else { + this.setData({ shouxufei: '0.00', shijidaozhang: '0.00' }); + } + }, + + onQuickAmount(e) { + const val = e.currentTarget.dataset.value; + this.setData({ tixianAmount: val.toString() }); + this.onAmountInput({ detail: { value: val.toString() } }); + }, + + async onConfirmWithdraw() { + const { selectedAsset, tixianAmount, txfangshi, txzh, txtupian, txdianhua } = this.data; + if (!selectedAsset) { wx.showToast({ title: '请选择提现项目', icon: 'none' }); return; } + const amount = parseFloat(tixianAmount); + if (isNaN(amount) || amount <= 0) { wx.showToast({ title: '请输入有效金额', icon: 'none' }); return; } + if (amount > parseFloat(selectedAsset.amount)) { wx.showToast({ title: '超过可提现金额', icon: 'none' }); return; } + if (!txfangshi || (!txzh && !txtupian)) { + wx.showToast({ title: '请先设置收款方式', icon: 'none' }); + this.setData({ showTixianModal: false }); + this.onSetSkfs(); + return; + } + let leixing = 1; + switch (selectedAsset.type) { + case 'dashou_yue': leixing = 1; break; + case 'dashou_yajin': leixing = 5; break; + case 'shangjia_yue': leixing = 6; break; + case 'guanshi_fenyong': leixing = 2; break; + case 'zuzhang_fenyong': leixing = 3; break; + case 'kaoheguan_fenyong': leixing = 4; break; + } + let txskfs = 0; + if (txzh && txtupian) txskfs = 3; + else if (txzh) txskfs = 1; + else if (txtupian) txskfs = 2; + try { + const res = await request({ + url: '/yonghu/tixian', + method: 'POST', + data: { leixing, jine: amount.toFixed(2), fangshi: txfangshi, txskfs } + }); + if (res?.data?.code === 0) { + const newAssetList = this.data.assetList.map(item => { + if (item.type === selectedAsset.type) { + const newAmount = (parseFloat(item.amount) - amount).toFixed(2); + return { ...item, amount: newAmount }; + } + return item; + }); + let newTotal = 0; + newAssetList.forEach(item => { newTotal += parseFloat(item.amount); }); + this.setData({ assetList: newAssetList, totalAmount: newTotal.toFixed(2), showTixianModal: false, selectedAsset: null }); + this.loadWithdrawRecords(true); + wx.showToast({ title: '提现申请已提交', icon: 'success' }); + } else { + wx.showToast({ title: res?.data?.msg || '提现失败', icon: 'none' }); + } + } catch (err) { + wx.showToast({ title: '网络错误', icon: 'none' }); + } + }, + + onCloseTixianModal() { + this.setData({ showTixianModal: false, selectedAsset: null, tixianAmount: '' }); + }, + + onSetSkfs() { + this.setData({ + showSkfsModal: true, + tempTxfangshi: this.data.txfangshi, + tempTxPhone: this.data.txdianhua, + tempTxAccount: this.data.txzh, + tempTxImage: '' + }); + }, + + onSelectFangshi(e) { + this.setData({ tempTxfangshi: e.currentTarget.dataset.fangshi }); + }, + + onPhoneInput(e) { this.setData({ tempTxPhone: e.detail.value }); }, + onAccountInput(e) { this.setData({ tempTxAccount: e.detail.value }); }, + + onChooseImage() { + if (this.data.choosingImage) return; + this.setData({ choosingImage: true }); + wx.chooseMedia({ + count: 1, mediaType: ['image'], + success: (res) => { this.setData({ tempTxImage: res.tempFiles[0].tempFilePath }); }, + complete: () => { this.setData({ choosingImage: false }); } + }); + }, + + onPreviewImage() { + if (this.data.tempTxImage) wx.previewImage({ urls: [this.data.tempTxImage] }); + }, + + onDeleteImage() { this.setData({ tempTxImage: '' }); }, + + async onConfirmSkfs() { + const { tempTxfangshi, tempTxPhone, tempTxAccount, tempTxImage } = this.data; + if (!tempTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; } + if (!tempTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; } + if (tempTxfangshi == 1 && !tempTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; } + if (tempTxfangshi == 2 && !tempTxAccount && !tempTxImage) { + wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return; + } + const formData = { txdianhua: tempTxPhone, txzh: tempTxAccount || '' }; + try { + const res = await upload({ url: '/yonghu/sksc', formData, filePath: tempTxImage || null, fileName: 'file' }); + if (res?.data?.code === 0) { + const data = res.data.data; + this.setData({ + txfangshi: tempTxfangshi, txdianhua: tempTxPhone, txzh: data.txzh || '', txtupian: data.txtupian || '', showSkfsModal: false + }); + wx.setStorageSync('txfangshi', tempTxfangshi); + wx.setStorageSync('txdianhua', tempTxPhone); + wx.setStorageSync('txzh', data.txzh || ''); + wx.setStorageSync('txtupian', data.txtupian || ''); + wx.showToast({ title: '设置成功', icon: 'success' }); + } else { + wx.showToast({ title: res?.data?.msg || '保存失败', icon: 'none' }); + } + } catch (err) { + wx.showToast({ title: '网络错误', icon: 'none' }); + } + }, + + onCloseSkfsModal() { this.setData({ showSkfsModal: false }); }, + + async loadWithdrawRecords(refresh = false) { + const now = Date.now(); + if (now - lastPullDownTime < PULL_DOWN_INTERVAL && !refresh) return; + if (this.data.loading || this.data.isRefreshing) return; + const page = refresh ? 1 : this.data.page; + if (this.data.nomore && !refresh) return; + this.setData({ loading: true, isRefreshing: refresh }); + lastPullDownTime = now; + try { + const res = await request({ url: '/yonghu/tixianjiluhq', method: 'POST', data: { page, limit: PAGE_SIZE } }); + if (res?.data?.code === 0) { + const list = (res.data.data.list || []).map(item => ({ + ...item, + statusText: this.getStatusText(item.zhuangtai), + statusColor: this.getStatusColor(item.zhuangtai) + })); + const newList = refresh ? list : [...this.data.recordList, ...list]; + const hasMore = res.data.data.has_more === true; + this.setData({ + recordList: newList, page: page + 1, nomore: !hasMore, canloadmore: hasMore, + loading: false, isRefreshing: false + }); + } else { + this.setData({ loading: false, isRefreshing: false }); + } + } catch (err) { + this.setData({ loading: false, isRefreshing: false }); + } + }, + + onModifyRecord(e) { + const record = e.currentTarget.dataset.record; + if (parseInt(record.zhuangtai) !== 1) { + wx.showToast({ title: '只有审核中的记录可修改', icon: 'none' }); + return; + } + this.setData({ + modifyingRecord: record, + modifyTxfangshi: record.fangshi, + modifyTxPhone: record.txdianhua || '', + modifyTxAccount: record.txzh || '', + modifyTxImage: '', + modifyImageUrl: record.txtupian ? (app.globalData.ossImageUrl + record.txtupian) : '', + showModifyModal: true + }); + }, + + onSelectModifyFangshi(e) { this.setData({ modifyTxfangshi: e.currentTarget.dataset.fangshi }); }, + onModifyPhoneInput(e) { this.setData({ modifyTxPhone: e.detail.value }); }, + onModifyAccountInput(e) { this.setData({ modifyTxAccount: e.detail.value }); }, + + onChooseModifyImage() { + if (this.data.choosingImage) return; + this.setData({ choosingImage: true }); + wx.chooseMedia({ + count: 1, mediaType: ['image'], + success: (res) => { this.setData({ modifyTxImage: res.tempFiles[0].tempFilePath }); }, + complete: () => { this.setData({ choosingImage: false }); } + }); + }, + + onPreviewModifyImage() { + if (this.data.modifyTxImage) wx.previewImage({ urls: [this.data.modifyTxImage] }); + else if (this.data.modifyImageUrl) wx.previewImage({ urls: [this.data.modifyImageUrl] }); + }, + + onDeleteModifyImage() { this.setData({ modifyTxImage: '' }); }, + + async onConfirmModify() { + const { modifyTxfangshi, modifyTxPhone, modifyTxAccount, modifyTxImage, modifyingRecord } = this.data; + if (!modifyTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; } + if (!modifyTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; } + if (modifyTxfangshi == 1 && !modifyTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; } + if (modifyTxfangshi == 2 && !modifyTxAccount && !modifyTxImage) { + wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return; + } + const formData = { tixian_id: modifyingRecord.id, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '' }; + try { + const res = await upload({ url: '/yonghu/yonghutxshxg', formData, filePath: modifyTxImage || null, fileName: 'file' }); + if (res?.data?.code === 0) { + const data = res.data.data; + const newList = this.data.recordList.map(item => { + if (item.id === modifyingRecord.id) { + return { ...item, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '', txtupian: data.txtupian || modifyingRecord.txtupian }; + } + return item; + }); + this.setData({ recordList: newList, showModifyModal: false, modifyingRecord: null }); + wx.showToast({ title: '修改成功', icon: 'success' }); + } else { + wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' }); + } + } catch (err) { + wx.showToast({ title: '网络错误', icon: 'none' }); + } + }, + + onCloseModifyModal() { this.setData({ showModifyModal: false, modifyingRecord: null }); }, + + onViewFailReason(e) { + const record = e.currentTarget.dataset.record; + const reason = record.fail_reason || record.shibaiyuanyin || '暂无详细信息'; + this.setData({ currentFailReason: reason, showFailModal: true }); + }, + + onCloseFailModal() { this.setData({ showFailModal: false }); }, + + getStatusText(zhuangtai) { + const s = parseInt(zhuangtai); + if (s === 1) return '审核中'; + if (s === 2) return '成功'; + if (s === 3) return '失败'; + return '未知'; + }, + getStatusColor(zhuangtai) { + const s = parseInt(zhuangtai); + if (s === 1) return '#F5A623'; + if (s === 2) return '#2ED158'; + if (s === 3) return '#FF4D4F'; + return '#999'; + }, + + registerNotification() { + const comp = this.selectComponent('#global-notification'); + if (comp?.showNotification) { + app.globalData.globalNotification = { + show: (data) => comp.showNotification(data), + hide: () => comp.hideNotification() + }; + } + }, + stopPropagation() {} + } }); \ No newline at end of file diff --git a/pages/tixian/components/mode1/mode1.json b/pages/withdraw/components/mode1/mode1.json similarity index 100% rename from pages/tixian/components/mode1/mode1.json rename to pages/withdraw/components/mode1/mode1.json diff --git a/pages/tixian/components/mode1/mode1.wxml b/pages/withdraw/components/mode1/mode1.wxml similarity index 98% rename from pages/tixian/components/mode1/mode1.wxml rename to pages/withdraw/components/mode1/mode1.wxml index 7fb3bab..c4f5f71 100644 --- a/pages/tixian/components/mode1/mode1.wxml +++ b/pages/withdraw/components/mode1/mode1.wxml @@ -1,133 +1,133 @@ - - - - - - - - - - - - - 可提总余额 - ¥{{totalAmount}} - - - - - - - ← 左右滑动查看更多资产 → - - - - - - - - {{item.label}} - ¥{{item.amount}} - 费率 {{item.rate}}% - - - 暂无可用资金 - - - - - - - - - - - - 提现记录 - 收款方式 - - - - - ¥{{item.jine}} - {{item.create}} - - - {{item.fangshi == 1 ? '微信' : '支付宝'}} - {{item.leixing == 1 ? '佣金' : (item.leixing == 2 ? '分红' : (item.leixing == 3 ? '组长' : (item.leixing == 4 ? '考核官' : '保证金')))}} - - - {{item.statusText}} ✏修改 - - {{item.statusText}} - 详情 - - {{item.statusText}} - - - 加载中... - —— 没有更多了 —— - 加载更多记录 - - - - - - - - - - - 提现 - - 项目{{selectedAsset.label}} - 可提¥{{selectedAsset.amount}} - 费率{{currentRate}}% - 金额 - ¥{{item}} - 手续费 ¥{{shouxufei}}到账 ¥{{shijidaozhang}} - 收款方式 {{txfangshi == 1 ? '微信' : (txfangshi == 2 ? '支付宝' : '未设置')}}更换 - - 取消确认 - - - - - - - 收款方式 - - 微信支付宝 - - - + 上传收款码预览删除 - - 取消保存 - - - - - - - 修改信息 - - 微信支付宝 - - - + 上传新图片预览删除 - - 取消确认 - - - - - - - 失败原因 - {{currentFailReason}} - 知道了 - - - - + + + + + + + + + + + + + 可提总余额 + ¥{{totalAmount}} + + + + + + + ← 左右滑动查看更多资产 → + + + + + + + + {{item.label}} + ¥{{item.amount}} + 费率 {{item.rate}}% + + + 暂无可用资金 + + + + + + + + + + + + 提现记录 + 收款方式 + + + + + ¥{{item.jine}} + {{item.create}} + + + {{item.fangshi == 1 ? '微信' : '支付宝'}} + {{item.leixing == 1 ? '佣金' : (item.leixing == 2 ? '分红' : (item.leixing == 3 ? '组长' : (item.leixing == 4 ? '考核官' : '保证金')))}} + + + {{item.statusText}} ✏修改 + + {{item.statusText}} + 详情 + + {{item.statusText}} + + + 加载中... + —— 没有更多了 —— + 加载更多记录 + + + + + + + + + + + 提现 + + 项目{{selectedAsset.label}} + 可提¥{{selectedAsset.amount}} + 费率{{currentRate}}% + 金额 + ¥{{item}} + 手续费 ¥{{shouxufei}}到账 ¥{{shijidaozhang}} + 收款方式 {{txfangshi == 1 ? '微信' : (txfangshi == 2 ? '支付宝' : '未设置')}}更换 + + 取消确认 + + + + + + + 收款方式 + + 微信支付宝 + + + + 上传收款码预览删除 + + 取消保存 + + + + + + + 修改信息 + + 微信支付宝 + + + + 上传新图片预览删除 + + 取消确认 + + + + + + + 失败原因 + {{currentFailReason}} + 知道了 + + + + \ No newline at end of file diff --git a/pages/tixian/components/mode1/mode1.wxss b/pages/withdraw/components/mode1/mode1.wxss similarity index 95% rename from pages/tixian/components/mode1/mode1.wxss rename to pages/withdraw/components/mode1/mode1.wxss index a4c4b31..6ce2249 100644 --- a/pages/tixian/components/mode1/mode1.wxss +++ b/pages/withdraw/components/mode1/mode1.wxss @@ -1,424 +1,424 @@ -/* pages/tixian/tixian.wxss - 终极优化版 */ - -page { - background-color: #f5f7fb; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - height: 100%; - } - - .app { - display: flex; - flex-direction: column; - min-height: 100vh; - padding: 0 24rpx 0; - position: relative; - z-index: 1; - box-sizing: border-box; - } - - /* 页面背景模糊极低,不影响阅读 */ - .global-bg { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: -1; - opacity: 0.1; - object-fit: cover; - filter: blur(1rpx); - } - - /* 资产区域整体与顶部保持间距 */ - .assets-section { - margin-top: 24rpx; - flex-shrink: 0; - } - - /* 主卡片玻璃质感 - 模糊加重避免抢眼,同时文字对比加强 */ - .main-card { - background: rgba(248, 250, 252, 0.88); /* 稍微降低透明度,让背景更柔和 */ - backdrop-filter: blur(28rpx); /* 增强模糊,不抢眼 */ - -webkit-backdrop-filter: blur(28rpx); - border-radius: 48rpx; - padding: 30rpx 28rpx 24rpx; /* 稍微缩小高度 */ - margin-bottom: 20rpx; - box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); - border: 1rpx solid rgba(255, 255, 255, 0.4); - background-size: cover; - } - - /* 总余额 - 字体加深加粗,增加阴影提高可读性 */ - .balance-wrap { - text-align: center; - margin-bottom: 20rpx; /* 减小间距,让卡片更紧凑 */ - } - .balance-label { - font-size: 28rpx; - color: #0f172a; /* 更深色 */ - letter-spacing: 1px; - display: block; - margin-bottom: 10rpx; - font-weight: 700; /* 加粗 */ - text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.8); - } - .balance-value { - font-size: 68rpx; - font-weight: 800; - color: #0f172a; - font-family: 'DIN', monospace; - letter-spacing: -1rpx; - text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.6); - } - - /* 内部分隔线(横杠)- 明显且保持层次 */ - .inner-divider { - width: 60%; - height: 2rpx; - background: linear-gradient(90deg, transparent, #64748b, #64748b, transparent); /* 加深颜色 */ - margin: 0 auto 20rpx auto; - border-radius: 2rpx; - opacity: 0.9; - } - - /* 左右滑动提示 - 字体明显 */ - .assets-hint { - display: block; - text-align: center; - font-size: 24rpx; - color: #334155; /* 深灰 */ - margin-bottom: 14rpx; - font-weight: 600; - } - - .assets-scroll { - width: 100%; - white-space: nowrap; - } - .assets-track { - display: inline-flex; - gap: 16rpx; - } - - /* 资产小卡片 - 背景半透模糊,字体深色加粗 */ - .asset-tile { - width: 170rpx; - background: rgba(255, 255, 255, 0.75); /* 稍微提高透明度,让模糊背景透出 */ - backdrop-filter: blur(8rpx); /* 自身轻微模糊,不抢眼 */ - border-radius: 28rpx; - padding: 18rpx 12rpx; - display: inline-flex; - flex-direction: column; - align-items: center; - text-align: center; - border: 1rpx solid rgba(255,255,255,0.5); - box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02); - transition: all 0.2s; - white-space: normal; - background-size: cover; - background-position: center; - } - .asset-tile:active { - background: rgba(255, 255, 255, 0.9); - transform: scale(0.98); - } - .asset-name { - font-size: 24rpx; - font-weight: 700; /* 加粗 */ - color: #1e293b; /* 深色 */ - margin-bottom: 10rpx; - text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.5); - } - .asset-balance { - font-size: 28rpx; - font-weight: 800; /* 加粗 */ - color: #2d6a4f; - font-family: monospace; - margin-bottom: 6rpx; - text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3); - } - .asset-fee { - font-size: 20rpx; - font-weight: 600; /* 加粗并加深 */ - color: #475569; - text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3); - } - .assets-empty { - width: 400rpx; - text-align: center; - color: #a0abb9; - padding: 40rpx 0; - } - - /* 外部层次分隔线 - 保持不变,保留分层 */ - .divider-line { - height: 2rpx; - background: linear-gradient(90deg, transparent, #cbd5e1, #cbd5e1, transparent); - margin: 16rpx 0 20rpx; - width: 80%; - margin-left: auto; - margin-right: auto; - } - - /* 提现记录区 - 无改动,自然贴底 */ - .history-section { - flex: 1; - display: flex; - flex-direction: column; - min-height: 0; - margin-top: 0; - } - .history-header { - display: flex; - justify-content: space-between; - align-items: baseline; - padding: 0 8rpx 20rpx; - flex-shrink: 0; - } - .history-title { - font-size: 34rpx; - font-weight: 600; - color: #1e293b; - } - .history-settings { - font-size: 28rpx; - color: #3b82f6; - } - .history-scroll { - flex: 1; - width: 100%; - padding: 0 20rpx; - box-sizing: border-box; - } - .history-item { - display: flex; - align-items: center; - padding: 28rpx 0; - border-bottom: 1rpx solid rgba(0,0,0,0.05); - } - .history-info { - width: 160rpx; - } - .history-amount { - font-size: 36rpx; - font-weight: 700; - color: #1e293b; - display: block; - } - .history-time { - font-size: 22rpx; - color: #94a3b8; - } - .history-detail { - flex: 1; - padding: 0 20rpx; - } - .history-method { - font-size: 30rpx; - color: #334155; - display: block; - margin-bottom: 6rpx; - } - .history-type { - font-size: 24rpx; - color: #94a3b8; - } - .history-status { - text-align: right; - } - .status-badge { - font-size: 26rpx; - font-weight: 500; - padding: 6rpx 14rpx; - border-radius: 30rpx; - display: inline-block; - } - .status-wait { - color: #f59e0b; - background: rgba(245,158,11,0.1); - } - .status-done { - color: #10b981; - background: rgba(16,185,129,0.1); - } - .status-fail { - color: #ef4444; - background: rgba(239,68,68,0.1); - } - .fail-link { - margin-left: 8rpx; - text-decoration: underline; - } - .load-tip, .more-tip { - text-align: center; - padding: 30rpx; - font-size: 24rpx; - color: #94a3b8; - } - .load-more-btn { - margin: 16rpx 0 20rpx; - padding: 20rpx; - text-align: center; - background: rgba(255,255,255,0.7); - backdrop-filter: blur(8rpx); - border-radius: 40rpx; - font-size: 28rpx; - color: #3b82f6; - border: 1rpx solid rgba(255,255,255,0.5); - } - .load-more-btn:active { - background: rgba(255,255,255,0.9); - } - .safe-bottom { - height: 12rpx; - flex-shrink: 0; - } - - /* ========== 弹窗样式(完整保留) ========== */ - .modal-mask { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0,0,0,0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - } - .modal-dialog { - width: 600rpx; - background: rgba(255,255,255,0.96); - backdrop-filter: blur(20rpx); - border-radius: 48rpx; - overflow: hidden; - box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.1); - border: 1rpx solid rgba(255,255,255,0.6); - } - .modal-header { - padding: 36rpx 32rpx 20rpx; - font-size: 36rpx; - font-weight: 700; - border-bottom: 1rpx solid rgba(0,0,0,0.05); - } - .modal-body { - padding: 32rpx; - } - .info-row, .amount-row, .method-row { - display: flex; - justify-content: space-between; - margin-bottom: 24rpx; - font-size: 28rpx; - } - .amount-row input { - border: 1rpx solid rgba(0,0,0,0.1); - border-radius: 28rpx; - padding: 16rpx 20rpx; - width: 260rpx; - background: rgba(255,255,255,0.9); - } - .quick-row { - display: flex; - gap: 16rpx; - margin: 24rpx 0; - } - .quick-chip { - flex: 1; - background: rgba(241,245,249,0.8); - text-align: center; - padding: 12rpx; - border-radius: 40rpx; - font-size: 28rpx; - } - .fee-row { - display: flex; - justify-content: space-between; - background: rgba(248,250,252,0.8); - padding: 20rpx; - border-radius: 28rpx; - margin: 20rpx 0; - } - .link-text { - color: #3b82f6; - } - .toggle-row { - display: flex; - gap: 20rpx; - margin-bottom: 28rpx; - } - .toggle-item { - flex: 1; - text-align: center; - padding: 20rpx; - border: 1rpx solid rgba(0,0,0,0.08); - border-radius: 30rpx; - background: rgba(255,255,255,0.8); - } - .toggle-item.active { - border-color: #3b82f6; - background: #eff6ff; - } - .field-input { - width: 100%; - border: 1rpx solid rgba(0,0,0,0.08); - border-radius: 28rpx; - padding: 20rpx; - margin-bottom: 20rpx; - box-sizing: border-box; - background: rgba(255,255,255,0.9); - } - .upload-trigger { - background: rgba(241,245,249,0.8); - border: 1rpx dashed #cbd5e1; - border-radius: 28rpx; - padding: 28rpx; - text-align: center; - } - .image-preview { - margin-top: 16rpx; - position: relative; - } - .image-preview image { - width: 100%; - height: 200rpx; - border-radius: 28rpx; - } - .image-actions { - display: flex; - justify-content: space-around; - background: rgba(0,0,0,0.6); - padding: 12rpx; - position: absolute; - bottom: 0; - left: 0; - right: 0; - color: white; - border-bottom-left-radius: 28rpx; - border-bottom-right-radius: 28rpx; - } - .current-img { - margin: 20rpx 0; - } - .current-img image { - width: 100%; - height: 140rpx; - border-radius: 24rpx; - } - .modal-footer { - display: flex; - border-top: 1rpx solid rgba(0,0,0,0.05); - } - .modal-btn { - flex: 1; - text-align: center; - padding: 28rpx; - font-size: 30rpx; - } - .modal-btn.cancel { - color: #8f9bb3; - border-right: 1rpx solid rgba(0,0,0,0.05); - } - .modal-btn.confirm { - color: #3b82f6; +/* pages/withdraw/withdraw.wxss - 终极优化版 */ + +page { + background-color: #f5f7fb; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + height: 100%; + } + + .app { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0 24rpx 0; + position: relative; + z-index: 1; + box-sizing: border-box; + } + + /* 页面背景模糊极低,不影响阅读 */ + .global-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + opacity: 0.1; + object-fit: cover; + filter: blur(1rpx); + } + + /* 资产区域整体与顶部保持间距 */ + .assets-section { + margin-top: 24rpx; + flex-shrink: 0; + } + + /* 主卡片玻璃质感 - 模糊加重避免抢眼,同时文字对比加强 */ + .main-card { + background: rgba(248, 250, 252, 0.88); /* 稍微降低透明度,让背景更柔和 */ + backdrop-filter: blur(28rpx); /* 增强模糊,不抢眼 */ + -webkit-backdrop-filter: blur(28rpx); + border-radius: 48rpx; + padding: 30rpx 28rpx 24rpx; /* 稍微缩小高度 */ + margin-bottom: 20rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); + border: 1rpx solid rgba(255, 255, 255, 0.4); + background-size: cover; + } + + /* 总余额 - 字体加深加粗,增加阴影提高可读性 */ + .balance-wrap { + text-align: center; + margin-bottom: 20rpx; /* 减小间距,让卡片更紧凑 */ + } + .balance-label { + font-size: 28rpx; + color: #0f172a; /* 更深色 */ + letter-spacing: 1px; + display: block; + margin-bottom: 10rpx; + font-weight: 700; /* 加粗 */ + text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.8); + } + .balance-value { + font-size: 68rpx; + font-weight: 800; + color: #0f172a; + font-family: 'DIN', monospace; + letter-spacing: -1rpx; + text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.6); + } + + /* 内部分隔线(横杠)- 明显且保持层次 */ + .inner-divider { + width: 60%; + height: 2rpx; + background: linear-gradient(90deg, transparent, #64748b, #64748b, transparent); /* 加深颜色 */ + margin: 0 auto 20rpx auto; + border-radius: 2rpx; + opacity: 0.9; + } + + /* 左右滑动提示 - 字体明显 */ + .assets-hint { + display: block; + text-align: center; + font-size: 24rpx; + color: #334155; /* 深灰 */ + margin-bottom: 14rpx; + font-weight: 600; + } + + .assets-scroll { + width: 100%; + white-space: nowrap; + } + .assets-track { + display: inline-flex; + gap: 16rpx; + } + + /* 资产小卡片 - 背景半透模糊,字体深色加粗 */ + .asset-tile { + width: 170rpx; + background: rgba(255, 255, 255, 0.75); /* 稍微提高透明度,让模糊背景透出 */ + backdrop-filter: blur(8rpx); /* 自身轻微模糊,不抢眼 */ + border-radius: 28rpx; + padding: 18rpx 12rpx; + display: inline-flex; + flex-direction: column; + align-items: center; + text-align: center; + border: 1rpx solid rgba(255,255,255,0.5); + box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02); + transition: all 0.2s; + white-space: normal; + background-size: cover; + background-position: center; + } + .asset-tile:active { + background: rgba(255, 255, 255, 0.9); + transform: scale(0.98); + } + .asset-name { + font-size: 24rpx; + font-weight: 700; /* 加粗 */ + color: #1e293b; /* 深色 */ + margin-bottom: 10rpx; + text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.5); + } + .asset-balance { + font-size: 28rpx; + font-weight: 800; /* 加粗 */ + color: #2d6a4f; + font-family: monospace; + margin-bottom: 6rpx; + text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3); + } + .asset-fee { + font-size: 20rpx; + font-weight: 600; /* 加粗并加深 */ + color: #475569; + text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3); + } + .assets-empty { + width: 400rpx; + text-align: center; + color: #a0abb9; + padding: 40rpx 0; + } + + /* 外部层次分隔线 - 保持不变,保留分层 */ + .divider-line { + height: 2rpx; + background: linear-gradient(90deg, transparent, #cbd5e1, #cbd5e1, transparent); + margin: 16rpx 0 20rpx; + width: 80%; + margin-left: auto; + margin-right: auto; + } + + /* 提现记录区 - 无改动,自然贴底 */ + .history-section { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + margin-top: 0; + } + .history-header { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: 0 8rpx 20rpx; + flex-shrink: 0; + } + .history-title { + font-size: 34rpx; + font-weight: 600; + color: #1e293b; + } + .history-settings { + font-size: 28rpx; + color: #3b82f6; + } + .history-scroll { + flex: 1; + width: 100%; + padding: 0 20rpx; + box-sizing: border-box; + } + .history-item { + display: flex; + align-items: center; + padding: 28rpx 0; + border-bottom: 1rpx solid rgba(0,0,0,0.05); + } + .history-info { + width: 160rpx; + } + .history-amount { + font-size: 36rpx; + font-weight: 700; + color: #1e293b; + display: block; + } + .history-time { + font-size: 22rpx; + color: #94a3b8; + } + .history-detail { + flex: 1; + padding: 0 20rpx; + } + .history-method { + font-size: 30rpx; + color: #334155; + display: block; + margin-bottom: 6rpx; + } + .history-type { + font-size: 24rpx; + color: #94a3b8; + } + .history-status { + text-align: right; + } + .status-badge { + font-size: 26rpx; + font-weight: 500; + padding: 6rpx 14rpx; + border-radius: 30rpx; + display: inline-block; + } + .status-wait { + color: #f59e0b; + background: rgba(245,158,11,0.1); + } + .status-done { + color: #10b981; + background: rgba(16,185,129,0.1); + } + .status-fail { + color: #ef4444; + background: rgba(239,68,68,0.1); + } + .fail-link { + margin-left: 8rpx; + text-decoration: underline; + } + .load-tip, .more-tip { + text-align: center; + padding: 30rpx; + font-size: 24rpx; + color: #94a3b8; + } + .load-more-btn { + margin: 16rpx 0 20rpx; + padding: 20rpx; + text-align: center; + background: rgba(255,255,255,0.7); + backdrop-filter: blur(8rpx); + border-radius: 40rpx; + font-size: 28rpx; + color: #3b82f6; + border: 1rpx solid rgba(255,255,255,0.5); + } + .load-more-btn:active { + background: rgba(255,255,255,0.9); + } + .safe-bottom { + height: 12rpx; + flex-shrink: 0; + } + + /* ========== 弹窗样式(完整保留) ========== */ + .modal-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + } + .modal-dialog { + width: 600rpx; + background: rgba(255,255,255,0.96); + backdrop-filter: blur(20rpx); + border-radius: 48rpx; + overflow: hidden; + box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.1); + border: 1rpx solid rgba(255,255,255,0.6); + } + .modal-header { + padding: 36rpx 32rpx 20rpx; + font-size: 36rpx; + font-weight: 700; + border-bottom: 1rpx solid rgba(0,0,0,0.05); + } + .modal-body { + padding: 32rpx; + } + .info-row, .amount-row, .method-row { + display: flex; + justify-content: space-between; + margin-bottom: 24rpx; + font-size: 28rpx; + } + .amount-row input { + border: 1rpx solid rgba(0,0,0,0.1); + border-radius: 28rpx; + padding: 16rpx 20rpx; + width: 260rpx; + background: rgba(255,255,255,0.9); + } + .quick-row { + display: flex; + gap: 16rpx; + margin: 24rpx 0; + } + .quick-chip { + flex: 1; + background: rgba(241,245,249,0.8); + text-align: center; + padding: 12rpx; + border-radius: 40rpx; + font-size: 28rpx; + } + .fee-row { + display: flex; + justify-content: space-between; + background: rgba(248,250,252,0.8); + padding: 20rpx; + border-radius: 28rpx; + margin: 20rpx 0; + } + .link-text { + color: #3b82f6; + } + .toggle-row { + display: flex; + gap: 20rpx; + margin-bottom: 28rpx; + } + .toggle-item { + flex: 1; + text-align: center; + padding: 20rpx; + border: 1rpx solid rgba(0,0,0,0.08); + border-radius: 30rpx; + background: rgba(255,255,255,0.8); + } + .toggle-item.active { + border-color: #3b82f6; + background: #eff6ff; + } + .field-input { + width: 100%; + border: 1rpx solid rgba(0,0,0,0.08); + border-radius: 28rpx; + padding: 20rpx; + margin-bottom: 20rpx; + box-sizing: border-box; + background: rgba(255,255,255,0.9); + } + .upload-trigger { + background: rgba(241,245,249,0.8); + border: 1rpx dashed #cbd5e1; + border-radius: 28rpx; + padding: 28rpx; + text-align: center; + } + .image-preview { + margin-top: 16rpx; + position: relative; + } + .image-preview image { + width: 100%; + height: 200rpx; + border-radius: 28rpx; + } + .image-actions { + display: flex; + justify-content: space-around; + background: rgba(0,0,0,0.6); + padding: 12rpx; + position: absolute; + bottom: 0; + left: 0; + right: 0; + color: white; + border-bottom-left-radius: 28rpx; + border-bottom-right-radius: 28rpx; + } + .current-img { + margin: 20rpx 0; + } + .current-img image { + width: 100%; + height: 140rpx; + border-radius: 24rpx; + } + .modal-footer { + display: flex; + border-top: 1rpx solid rgba(0,0,0,0.05); + } + .modal-btn { + flex: 1; + text-align: center; + padding: 28rpx; + font-size: 30rpx; + } + .modal-btn.cancel { + color: #8f9bb3; + border-right: 1rpx solid rgba(0,0,0,0.05); + } + .modal-btn.confirm { + color: #3b82f6; } \ No newline at end of file diff --git a/pages/tixian/components/mode2/mode2.js b/pages/withdraw/components/mode2/mode2.js similarity index 97% rename from pages/tixian/components/mode2/mode2.js rename to pages/withdraw/components/mode2/mode2.js index 426d996..3c1f617 100644 --- a/pages/tixian/components/mode2/mode2.js +++ b/pages/withdraw/components/mode2/mode2.js @@ -1,642 +1,642 @@ -// pages/tixian/components/mode2/mode2.js -// UI 与 mode1 完全一致,业务逻辑为自动打款审核收款 -import request from '../../../../utils/request.js'; -import PopupService from '../../../../services/popupService.js'; - -const app = getApp(); -const yemianshuju = 5; -let lastPullDownTime = 0; -const PULL_DOWN_INTERVAL = 2000; - -const TX_STATUS = { - SHENHEZHONG: 1, - TIXIAN_CHENGGONG: 2, - TIXIAN_SHIBAI: 3, - SHENHE_CHENGGONG: 4, - SHENHE_SHIBAI: 5, - DAI_SHOUKUAN: 6, -}; - -const ASSET_CONFIG = { - dashou_yue: { leixing: 1, label: '打手佣金' }, - guanshi_fenyong: { leixing: 2, label: '管事分红' }, - zuzhang_fenyong: { leixing: 3, label: '组长分红' }, - kaoheguan_fenyong: { leixing: 4, label: '考核官分佣' }, - dashou_yajin: { leixing: 5, label: '打手保证金' }, - shangjia_yue: { leixing: 6, label: '商家余额' }, -}; - -const LEIXING_LABEL = { - 1: '打手佣金', 2: '管事分红', 3: '组长分红', - 4: '考核官分佣', 5: '打手保证金', 6: '商家余额', -}; - -Component({ - properties: { options: { type: Object, value: {} } }, - data: { - imgUrls: { - pageBg: '', cardBg: '', assetTileBg: '', - }, - assetList: [], - totalAmount: '0.00', - selectedAsset: null, - isLoadingAssets: false, - tixianleixing: null, - tixianjine: '', - currentRate: '0.00', - showTixian: false, - recordList: [], - page: 1, - loading: false, - nomore: false, - canloadmore: true, - isRefreshing: false, - shouxufei: '0.00', - shijidaozhang: '0.00', - currentTixianId: null, - submitting: false, - mchId: '', - currentStatusFilter: 0, - statusTabs: [ - { value: 0, label: '全部' }, - { value: 1, label: '审核中' }, - { value: 6, label: '待收款' }, - { value: 4, label: '审核成功' }, - { value: 5, label: '审核失败' }, - { value: 2, label: '提现成功' }, - { value: 3, label: '提现失败' }, - ], - hasPendingCollect: false, - showCollectConfirm: false, - collectConfirmRecord: null, - showDetailModal: false, - detailTitle: '', - detailContent: '', - }, - lifetimes: { - attached() { - this.initImageUrls(); - this.chushihuashuju(); - } - }, - pageLifetimes: { - show() { - this.registerNotificationComponent(); - this.loadAllAssets(); - PopupService.checkAndShow(this, 'tixian'); - }, - hide() { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) popupComp.cleanup(); - } - }, - methods: { - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - initImageUrls() { - const ossBase = app.globalData.ossImageUrl || ''; - const imgDir = `${ossBase}beijing/tixian/`; - this.setData({ - imgUrls: { - pageBg: `${imgDir}page_bg.png`, - cardBg: `${imgDir}card_bg.png`, - assetTileBg: `${imgDir}asset_tile_bg.png`, - } - }); - }, - - parseZhuangtai(item) { - const raw = item.zhuangtai ?? item.status ?? item.state; - const n = parseInt(raw, 10); - return Number.isNaN(n) ? -1 : n; - }, - - /** 规范化列表字段(兼容后端多种命名 / 嵌套 audit) */ - normalizeRecordFields(item) { - const audit = item.audit || item.shenhe || item.shenhe_info || {}; - const shenheJiluId = item.shenhe_jilu_id ?? item.shenheJiluId - ?? item.audit_id ?? item.shenheid ?? audit.id ?? audit.shenhe_jilu_id ?? null; - const shenheDanhao = String( - item.shenhe_danhao || item.shenheDanhao || item.audit_shenhe_danhao - || audit.shenhe_danhao || audit.danhao || '' - ).trim(); - const tixianjiluId = item.tixianjilu_id ?? item.tixianjiluId ?? item.id ?? null; - const zhuangtai = this.parseZhuangtai(item); - return { - ...item, - zhuangtai: zhuangtai >= 0 ? zhuangtai : item.zhuangtai, - shenhe_jilu_id: shenheJiluId, - shenhe_danhao: shenheDanhao, - tixianjilu_id: tixianjiluId, - }; - }, - - hasAuditJiluId(item) { - const id = item.shenhe_jilu_id; - return id !== null && id !== undefined && id !== '' && id !== 0 && id !== '0'; - }, - - hasShenheDanhao(item) { - return !!(item.shenhe_danhao && String(item.shenhe_danhao).trim()); - }, - - isNewAuditRecord(item) { - return this.hasAuditJiluId(item) && this.hasShenheDanhao(item); - }, - - /** 待收款是否可点击:状态6 + 审核记录ID + 审核单号 缺一不可 */ - canCollectRecord(item) { - return this.parseZhuangtai(item) === TX_STATUS.DAI_SHOUKUAN - && this.hasAuditJiluId(item) - && this.hasShenheDanhao(item); - }, - - getLeixingLabel(leixing) { - return LEIXING_LABEL[parseInt(leixing)] || '提现'; - }, - - getStatusBadgeClass(status) { - switch (parseInt(status)) { - case TX_STATUS.SHENHEZHONG: return 'status-wait'; - case TX_STATUS.TIXIAN_CHENGGONG: - case TX_STATUS.SHENHE_CHENGGONG: return 'status-done'; - case TX_STATUS.DAI_SHOUKUAN: return 'status-pending'; - case TX_STATUS.TIXIAN_SHIBAI: - case TX_STATUS.SHENHE_SHIBAI: return 'status-fail'; - default: return 'status-wait'; - } - }, - - processRecordItem(item) { - item = this.normalizeRecordFields(item); - const isNew = this.isNewAuditRecord(item); - const status = this.parseZhuangtai(item); - let statusText = '未知'; - let canCollect = false; - let canShowDetail = false; - let detailReason = ''; - - switch (status) { - case TX_STATUS.SHENHEZHONG: statusText = '审核中'; break; - case TX_STATUS.TIXIAN_CHENGGONG: statusText = '提现成功'; break; - case TX_STATUS.TIXIAN_SHIBAI: - statusText = '提现失败'; - if (item.fail_reason || item.bhliyou) { - canShowDetail = true; - detailReason = item.fail_reason || item.bhliyou; - } - break; - case TX_STATUS.SHENHE_CHENGGONG: statusText = '审核成功'; break; - case TX_STATUS.SHENHE_SHIBAI: - statusText = '审核失败'; - if (item.bhliyou) { canShowDetail = true; detailReason = item.bhliyou; } - break; - case TX_STATUS.DAI_SHOUKUAN: - statusText = '待收款'; - canCollect = this.canCollectRecord(item); - break; - } - - return { - ...item, - isNewAudit: isNew, - leixingLabel: this.getLeixingLabel(item.leixing), - statusText, - statusBadgeClass: this.getStatusBadgeClass(status), - canCollect, - canShowDetail, - detailReason, - }; - }, - - gengxinYue(data, leixing) { - if (!data) return; - if (data.new_yongjin !== undefined && data.new_yongjin !== null) { - app.globalData.yongjin = data.new_yongjin; - } - if (data.new_fenyong !== undefined && data.new_fenyong !== null) { - app.globalData.guanshi.fenyongtixian = data.new_fenyong; - } - if (data.new_yajin !== undefined && data.new_yajin !== null) { - app.globalData.yajin = data.new_yajin; - } - if (data.new_shangjia_yue !== undefined && data.new_shangjia_yue !== null) { - if (app.globalData.shangjia) app.globalData.shangjia.sjyue = data.new_shangjia_yue; - } - if (data.current_rate !== undefined && leixing) { - const rate = parseFloat(data.current_rate); - const rateKeyMap = { 1: 'dashouRate', 5: 'dashou_yajin_rate', 6: 'shangjia_rate', 2: 'guanshi_rate', 3: 'zuzhang_rate', 4: 'kaoheguan_rate' }; - const key = rateKeyMap[leixing]; - if (key) wx.setStorageSync(key, rate); - } - }, - - updatePendingCollectFlag(list) { - const hasPending = (list || []).some(item => item.canCollect); - if (hasPending !== this.data.hasPendingCollect) { - this.setData({ hasPendingCollect: hasPending }); - } - }, - - /** 微信确认收款成功后,本地先把对应记录标为「提现成功」 */ - markLocalRecordWithdrawSuccess(record) { - if (!record) return; - const matchId = String(record.tixianjilu_id || record.id || ''); - const matchDanhao = String(record.shenhe_danhao || '').trim(); - if (!matchId && !matchDanhao) return; - - const newList = (this.data.recordList || []).map((item) => { - const itemId = String(item.tixianjilu_id || item.id || ''); - const itemDanhao = String(item.shenhe_danhao || '').trim(); - const isMatch = (matchId && itemId === matchId) - || (matchDanhao && itemDanhao === matchDanhao); - if (!isMatch) return item; - return this.processRecordItem({ - ...item, - zhuangtai: TX_STATUS.TIXIAN_CHENGGONG, - }); - }); - this.setData({ recordList: newList }); - this.updatePendingCollectFlag(newList); - }, - - async finishWxCollectSuccess(record) { - this.markLocalRecordWithdrawSuccess(record); - await this.loadAllAssets(); - await this.huoquJilu(true, true); - // 后端若尚未落库,刷新后仍可能显示待收款,再覆盖一次本地成功态 - this.markLocalRecordWithdrawSuccess(record); - PopupService.checkAndShow(this, 'tixianchenggong'); - wx.showToast({ - title: '提现成功', - icon: 'success', - duration: 3000, - }); - }, - - async loadAllAssets() { - this.setData({ isLoadingAssets: true }); - try { - const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' }); - if (res?.data?.code === 200 || res?.data?.code === 0) { - const data = res.data.data || {}; - const assets = []; - const pushAsset = (type, amount, rate) => { - const cfg = ASSET_CONFIG[type]; - if (!cfg || !amount || parseFloat(amount) <= 0) return; - assets.push({ - type, - leixing: cfg.leixing, - label: cfg.label, - amount: parseFloat(amount).toFixed(2), - rate: rate || 0, - }); - }; - pushAsset('dashou_yue', data.dashou_yue, data.dashou_rate); - pushAsset('dashou_yajin', data.dashou_yajin, data.dashou_yajin_rate); - pushAsset('shangjia_yue', data.shangjia_yue, data.shangjia_rate); - pushAsset('guanshi_fenyong', data.guanshi_fenyong, data.guanshi_rate); - pushAsset('zuzhang_fenyong', data.zuzhang_fenyong, data.zuzhang_rate); - pushAsset('kaoheguan_fenyong', data.kaoheguan_fenyong, data.kaoheguan_rate); - - let total = 0; - assets.forEach(item => { total += parseFloat(item.amount); }); - this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoadingAssets: false }); - } else { - throw new Error(res?.data?.msg || '获取资产失败'); - } - } catch (err) { - console.error('loadAllAssets', err); - this.setData({ isLoadingAssets: false }); - } - }, - - chushihuashuju() { - this.loadAllAssets(); - this.huoquJilu(true); - }, - - /** 点击资产卡片(与 mode1 一致) */ - onSelectAsset(e) { - const index = e.currentTarget.dataset.index; - const asset = this.data.assetList[index]; - if (!asset || parseFloat(asset.amount) <= 0) { - wx.showToast({ title: '无可提现金额', icon: 'none' }); - return; - } - this.setData({ - selectedAsset: asset, - tixianleixing: asset.leixing, - currentRate: asset.rate, - tixianjine: '', - shouxufei: '0.00', - shijidaozhang: '0.00', - showTixian: true, - }); - }, - - onJineInput(e) { - this.setData({ tixianjine: e.detail.value, shouxufei: '0.00', shijidaozhang: '0.00' }); - }, - - onQuickAmountTap(e) { - const value = e.currentTarget.dataset.value; - this.setData({ tixianjine: value.toString(), shouxufei: '0.00', shijidaozhang: '0.00' }); - }, - - onStatusFilterTap(e) { - const value = parseInt(e.currentTarget.dataset.value); - if (value === this.data.currentStatusFilter) return; - this.setData({ currentStatusFilter: value }); - this.huoquJilu(true); - }, - - async onConfirmTixian() { - if (this.data.submitting) return; - const { tixianleixing, tixianjine, selectedAsset } = this.data; - if (!tixianleixing || !selectedAsset) { - wx.showToast({ title: '请选择提现类型', icon: 'none' }); - return; - } - const jineValue = parseFloat(tixianjine); - if (!tixianjine || isNaN(jineValue) || jineValue <= 0) { - wx.showToast({ title: '请输入有效金额', icon: 'none' }); - return; - } - if (jineValue > parseFloat(selectedAsset.amount)) { - wx.showToast({ title: `超过可提${selectedAsset.label}`, icon: 'none' }); - return; - } - - this.setData({ submitting: true }); - try { - const res = await request({ - url: '/yonghu/zddksh', - method: 'POST', - data: { leixing: tixianleixing, jine: jineValue.toFixed(2) } - }); - if (res.statusCode === 200 && res.data && res.data.code === 0) { - const data = res.data.data || {}; - this.gengxinYue(data, tixianleixing); - if (data.shouxufei !== undefined) { - this.setData({ - shouxufei: parseFloat(data.shouxufei || 0).toFixed(2), - shijidaozhang: parseFloat(data.shijidaozhang || 0).toFixed(2), - }); - } - this.setData({ showTixian: false, submitting: false, selectedAsset: null }); - await this.loadAllAssets(); - this.huoquJilu(true); - wx.showModal({ - title: '申请已提交', - content: '您的提现申请已提交,请等待后台审核。审核通过后,请在本页「提现记录」中点击「收款」按钮,主动确认后才能到账微信零钱。', - showCancel: false, - }); - } else { - wx.showModal({ title: '提现申请失败', content: res.data?.msg || '未知错误', showCancel: false }); - this.setData({ submitting: false }); - } - } catch (err) { - wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false }); - this.setData({ submitting: false }); - } - }, - - onCollectTap(e) { - const index = e.currentTarget.dataset.index; - const record = this.data.recordList[index]; - if (!record) return; - if (this.parseZhuangtai(record) !== TX_STATUS.DAI_SHOUKUAN) { - wx.showToast({ title: '当前状态不可收款', icon: 'none' }); - return; - } - if (!this.hasShenheDanhao(record) || !this.hasAuditJiluId(record)) { - wx.showToast({ title: '审核信息不完整,请刷新后重试', icon: 'none' }); - return; - } - if (this.data.submitting) { - wx.showToast({ title: '正在处理中,请稍后', icon: 'none' }); - return; - } - this.setData({ showCollectConfirm: true, collectConfirmRecord: record }); - }, - - onCloseCollectConfirm() { - if (this.data.submitting) return; - this.setData({ showCollectConfirm: false, collectConfirmRecord: null }); - }, - - async onConfirmCollect() { - if (this.data.submitting) return; - let record = this.data.collectConfirmRecord; - if (!record) return; - - if (!this.canCollectRecord(record)) { - await this.huoquJilu(true, true); - const refreshed = (this.data.recordList || []).find( - r => String(r.id) === String(record.id) - || String(r.tixianjilu_id) === String(record.tixianjilu_id) - ); - if (refreshed) record = refreshed; - } - if (!this.canCollectRecord(record)) { - wx.showModal({ - title: '暂时无法收款', - content: '缺少审核单号或审核记录ID,请下拉刷新后重试。仍不行请联系客服。', - showCancel: false, - }); - return; - } - - this.setData({ showCollectConfirm: false, submitting: true, collectConfirmRecord: record }); - try { - const res = await request({ - url: '/yonghu/tixiansq', - method: 'POST', - data: { - shenhe_danhao: record.shenhe_danhao, - shenhe_jilu_id: record.shenhe_jilu_id || '', - tixianjilu_id: record.tixianjilu_id || record.id || '', - leixing: record.leixing, - } - }); - if (res.statusCode === 200 && res.data && res.data.code === 0) { - const data = res.data.data; - this.setData({ - currentTixianId: data.tixian_id, - mchId: data.mch_id || '', - collectConfirmRecord: record, - }); - this.tiaoqiWeixinQueRen(data.package_info); - } else { - wx.showModal({ title: '收款失败', content: res.data?.msg || '无法发起收款,请稍后重试', showCancel: false }); - this.setData({ submitting: false, collectConfirmRecord: null }); - } - } catch (err) { - wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false }); - this.setData({ submitting: false, collectConfirmRecord: null }); - } - }, - - tiaoqiWeixinQueRen(packageInfo) { - const appId = app.globalData.appId; - const mchId = this.data.mchId; - if (!appId || !mchId) { - wx.showModal({ title: '配置错误', content: '无法调起收款,请联系客服', showCancel: false }); - this.setData({ submitting: false, collectConfirmRecord: null }); - return; - } - wx.requestMerchantTransfer({ - appId, mchId, package: packageInfo, - success: () => { this.tongzhiHouduanQueRen(1); }, - fail: () => { - this.tongzhiHouduanQueRen(0); - wx.showModal({ - title: '确认收款失败', - content: '微信收款确认失败,您可在记录中再次点击「收款」重试。', - showCancel: false, - }); - } - }); - }, - - async tongzhiHouduanQueRen(result) { - if (!this.data.currentTixianId) { - this.setData({ submitting: false, collectConfirmRecord: null }); - return; - } - const record = this.data.collectConfirmRecord; - const wxConfirmed = result === 1; - - try { - const res = await request({ - url: '/yonghu/tixianqr', - method: 'POST', - data: { - tixian_id: this.data.currentTixianId, - result: result, - shenhe_danhao: record ? record.shenhe_danhao : '', - shenhe_jilu_id: record ? (record.shenhe_jilu_id || '') : '', - tixianjilu_id: record ? (record.tixianjilu_id || record.id || '') : '', - leixing: record ? record.leixing : '', - } - }); - if (res.statusCode === 200 && res.data && res.data.code === 0) { - const data = res.data.data || {}; - this.gengxinYue(data, record ? record.leixing : null); - } - - // 微信已确认收款:不论 tixianqr 返回什么,都刷新列表,不弹系统异常 - if (wxConfirmed) { - await this.finishWxCollectSuccess(record); - } else if (res.statusCode === 200 && res.data && res.data.code === 0) { - await this.loadAllAssets(); - this.huoquJilu(true); - wx.showToast({ - title: '收款已取消', - icon: 'none', - duration: 3000, - }); - } else { - wx.showModal({ - title: '确认状态失败', - content: res.data?.msg || '操作失败', - showCancel: false, - }); - } - } catch (err) { - if (wxConfirmed) { - await this.finishWxCollectSuccess(record); - } else { - wx.showModal({ - title: '网络错误', - content: '网络连接失败', - showCancel: false, - }); - } - } finally { - this.setData({ submitting: false, currentTixianId: null, collectConfirmRecord: null }); - } - }, - - onViewDetail(e) { - const index = e.currentTarget.dataset.index; - const record = this.data.recordList[index]; - if (!record || !record.canShowDetail) return; - const status = parseInt(record.zhuangtai); - let detailTitle = '失败原因'; - if (status === TX_STATUS.SHENHE_SHIBAI) detailTitle = '审核失败原因'; - else if (status === TX_STATUS.TIXIAN_SHIBAI) detailTitle = '提现失败原因'; - this.setData({ - showDetailModal: true, - detailTitle, - detailContent: record.detailReason || '暂无详细信息', - }); - }, - - onCloseDetailModal() { - this.setData({ showDetailModal: false, detailTitle: '', detailContent: '' }); - }, - - onCloseTixian() { - if (this.data.submitting) { wx.showToast({ title: '正在处理中,请稍后', icon: 'none' }); return; } - this.setData({ - showTixian: false, selectedAsset: null, tixianleixing: null, - tixianjine: '', shouxufei: '0.00', shijidaozhang: '0.00', submitting: false, - }); - }, - - async huoquJilu(fresh = false, force = false) { - const now = Date.now(); - if (!force && now - lastPullDownTime < 2000 && !fresh) return; - if (!force && (this.data.loading || this.data.isRefreshing)) return; - const page = fresh ? 1 : this.data.page; - if (fresh) this.setData({ nomore: false, canloadmore: true, isRefreshing: true }); - if (this.data.nomore && !fresh) return; - this.setData({ loading: true }); - lastPullDownTime = now; - try { - const res = await request({ - url: '/yonghu/tixianjiluhq', - method: 'POST', - data: { page, limit: yemianshuju, mode: 2, zhuangtai: this.data.currentStatusFilter } - }); - if (res.statusCode === 200 && res.data && res.data.code === 0) { - const data = res.data.data; - const processedList = (data.list || []).map(item => this.processRecordItem(item)); - const newList = fresh ? processedList : [...this.data.recordList, ...processedList]; - this.setData({ - recordList: newList, - page: page + 1, - nomore: !(data.has_more === true), - canloadmore: data.has_more === true, - loading: false, - isRefreshing: false, - }); - this.updatePendingCollectFlag(newList); - } else { - this.setData({ loading: false, isRefreshing: false }); - } - } catch (err) { - this.setData({ loading: false, isRefreshing: false }); - } - }, - - onReachBottom() { - if (this.data.canloadmore && !this.data.nomore && !this.data.loading && !this.data.isRefreshing) { - const now = Date.now(); - if (now - lastPullDownTime >= PULL_DOWN_INTERVAL) this.huoquJilu(); - } - }, - - stopPropagation() {} - } -}); +// pages/withdraw/components/mode2/mode2.js +// UI 与 mode1 完全一致,业务逻辑为自动打款审核收款 +import request from '../../../../utils/request.js'; +import PopupService from '../../../../services/popupService.js'; + +const app = getApp(); +const yemianshuju = 5; +let lastPullDownTime = 0; +const PULL_DOWN_INTERVAL = 2000; + +const TX_STATUS = { + SHENHEZHONG: 1, + TIXIAN_CHENGGONG: 2, + TIXIAN_SHIBAI: 3, + SHENHE_CHENGGONG: 4, + SHENHE_SHIBAI: 5, + DAI_SHOUKUAN: 6, +}; + +const ASSET_CONFIG = { + dashou_yue: { leixing: 1, label: '打手佣金' }, + guanshi_fenyong: { leixing: 2, label: '管事分红' }, + zuzhang_fenyong: { leixing: 3, label: '组长分红' }, + kaoheguan_fenyong: { leixing: 4, label: '考核官分佣' }, + dashou_yajin: { leixing: 5, label: '打手保证金' }, + shangjia_yue: { leixing: 6, label: '商家余额' }, +}; + +const LEIXING_LABEL = { + 1: '打手佣金', 2: '管事分红', 3: '组长分红', + 4: '考核官分佣', 5: '打手保证金', 6: '商家余额', +}; + +Component({ + properties: { options: { type: Object, value: {} } }, + data: { + imgUrls: { + pageBg: '', cardBg: '', assetTileBg: '', + }, + assetList: [], + totalAmount: '0.00', + selectedAsset: null, + isLoadingAssets: false, + tixianleixing: null, + tixianjine: '', + currentRate: '0.00', + showTixian: false, + recordList: [], + page: 1, + loading: false, + nomore: false, + canloadmore: true, + isRefreshing: false, + shouxufei: '0.00', + shijidaozhang: '0.00', + currentTixianId: null, + submitting: false, + mchId: '', + currentStatusFilter: 0, + statusTabs: [ + { value: 0, label: '全部' }, + { value: 1, label: '审核中' }, + { value: 6, label: '待收款' }, + { value: 4, label: '审核成功' }, + { value: 5, label: '审核失败' }, + { value: 2, label: '提现成功' }, + { value: 3, label: '提现失败' }, + ], + hasPendingCollect: false, + showCollectConfirm: false, + collectConfirmRecord: null, + showDetailModal: false, + detailTitle: '', + detailContent: '', + }, + lifetimes: { + attached() { + this.initImageUrls(); + this.chushihuashuju(); + } + }, + pageLifetimes: { + show() { + this.registerNotificationComponent(); + this.loadAllAssets(); + PopupService.checkAndShow(this, 'tixian'); + }, + hide() { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) popupComp.cleanup(); + } + }, + methods: { + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + initImageUrls() { + const ossBase = app.globalData.ossImageUrl || ''; + const imgDir = `${ossBase}beijing/tixian/`; + this.setData({ + imgUrls: { + pageBg: `${imgDir}page_bg.png`, + cardBg: `${imgDir}card_bg.png`, + assetTileBg: `${imgDir}asset_tile_bg.png`, + } + }); + }, + + parseZhuangtai(item) { + const raw = item.zhuangtai ?? item.status ?? item.state; + const n = parseInt(raw, 10); + return Number.isNaN(n) ? -1 : n; + }, + + /** 规范化列表字段(兼容后端多种命名 / 嵌套 audit) */ + normalizeRecordFields(item) { + const audit = item.audit || item.shenhe || item.shenhe_info || {}; + const shenheJiluId = item.shenhe_jilu_id ?? item.shenheJiluId + ?? item.audit_id ?? item.shenheid ?? audit.id ?? audit.shenhe_jilu_id ?? null; + const shenheDanhao = String( + item.shenhe_danhao || item.shenheDanhao || item.audit_shenhe_danhao + || audit.shenhe_danhao || audit.danhao || '' + ).trim(); + const tixianjiluId = item.tixianjilu_id ?? item.tixianjiluId ?? item.id ?? null; + const zhuangtai = this.parseZhuangtai(item); + return { + ...item, + zhuangtai: zhuangtai >= 0 ? zhuangtai : item.zhuangtai, + shenhe_jilu_id: shenheJiluId, + shenhe_danhao: shenheDanhao, + tixianjilu_id: tixianjiluId, + }; + }, + + hasAuditJiluId(item) { + const id = item.shenhe_jilu_id; + return id !== null && id !== undefined && id !== '' && id !== 0 && id !== '0'; + }, + + hasShenheDanhao(item) { + return !!(item.shenhe_danhao && String(item.shenhe_danhao).trim()); + }, + + isNewAuditRecord(item) { + return this.hasAuditJiluId(item) && this.hasShenheDanhao(item); + }, + + /** 待收款是否可点击:状态6 + 审核记录ID + 审核单号 缺一不可 */ + canCollectRecord(item) { + return this.parseZhuangtai(item) === TX_STATUS.DAI_SHOUKUAN + && this.hasAuditJiluId(item) + && this.hasShenheDanhao(item); + }, + + getLeixingLabel(leixing) { + return LEIXING_LABEL[parseInt(leixing)] || '提现'; + }, + + getStatusBadgeClass(status) { + switch (parseInt(status)) { + case TX_STATUS.SHENHEZHONG: return 'status-wait'; + case TX_STATUS.TIXIAN_CHENGGONG: + case TX_STATUS.SHENHE_CHENGGONG: return 'status-done'; + case TX_STATUS.DAI_SHOUKUAN: return 'status-pending'; + case TX_STATUS.TIXIAN_SHIBAI: + case TX_STATUS.SHENHE_SHIBAI: return 'status-fail'; + default: return 'status-wait'; + } + }, + + processRecordItem(item) { + item = this.normalizeRecordFields(item); + const isNew = this.isNewAuditRecord(item); + const status = this.parseZhuangtai(item); + let statusText = '未知'; + let canCollect = false; + let canShowDetail = false; + let detailReason = ''; + + switch (status) { + case TX_STATUS.SHENHEZHONG: statusText = '审核中'; break; + case TX_STATUS.TIXIAN_CHENGGONG: statusText = '提现成功'; break; + case TX_STATUS.TIXIAN_SHIBAI: + statusText = '提现失败'; + if (item.fail_reason || item.bhliyou) { + canShowDetail = true; + detailReason = item.fail_reason || item.bhliyou; + } + break; + case TX_STATUS.SHENHE_CHENGGONG: statusText = '审核成功'; break; + case TX_STATUS.SHENHE_SHIBAI: + statusText = '审核失败'; + if (item.bhliyou) { canShowDetail = true; detailReason = item.bhliyou; } + break; + case TX_STATUS.DAI_SHOUKUAN: + statusText = '待收款'; + canCollect = this.canCollectRecord(item); + break; + } + + return { + ...item, + isNewAudit: isNew, + leixingLabel: this.getLeixingLabel(item.leixing), + statusText, + statusBadgeClass: this.getStatusBadgeClass(status), + canCollect, + canShowDetail, + detailReason, + }; + }, + + gengxinYue(data, leixing) { + if (!data) return; + if (data.new_yongjin !== undefined && data.new_yongjin !== null) { + app.globalData.yongjin = data.new_yongjin; + } + if (data.new_fenyong !== undefined && data.new_fenyong !== null) { + app.globalData.guanshi.fenyongtixian = data.new_fenyong; + } + if (data.new_yajin !== undefined && data.new_yajin !== null) { + app.globalData.yajin = data.new_yajin; + } + if (data.new_shangjia_yue !== undefined && data.new_shangjia_yue !== null) { + if (app.globalData.shangjia) app.globalData.shangjia.sjyue = data.new_shangjia_yue; + } + if (data.current_rate !== undefined && leixing) { + const rate = parseFloat(data.current_rate); + const rateKeyMap = { 1: 'dashouRate', 5: 'dashou_yajin_rate', 6: 'shangjia_rate', 2: 'guanshi_rate', 3: 'zuzhang_rate', 4: 'kaoheguan_rate' }; + const key = rateKeyMap[leixing]; + if (key) wx.setStorageSync(key, rate); + } + }, + + updatePendingCollectFlag(list) { + const hasPending = (list || []).some(item => item.canCollect); + if (hasPending !== this.data.hasPendingCollect) { + this.setData({ hasPendingCollect: hasPending }); + } + }, + + /** 微信确认收款成功后,本地先把对应记录标为「提现成功」 */ + markLocalRecordWithdrawSuccess(record) { + if (!record) return; + const matchId = String(record.tixianjilu_id || record.id || ''); + const matchDanhao = String(record.shenhe_danhao || '').trim(); + if (!matchId && !matchDanhao) return; + + const newList = (this.data.recordList || []).map((item) => { + const itemId = String(item.tixianjilu_id || item.id || ''); + const itemDanhao = String(item.shenhe_danhao || '').trim(); + const isMatch = (matchId && itemId === matchId) + || (matchDanhao && itemDanhao === matchDanhao); + if (!isMatch) return item; + return this.processRecordItem({ + ...item, + zhuangtai: TX_STATUS.TIXIAN_CHENGGONG, + }); + }); + this.setData({ recordList: newList }); + this.updatePendingCollectFlag(newList); + }, + + async finishWxCollectSuccess(record) { + this.markLocalRecordWithdrawSuccess(record); + await this.loadAllAssets(); + await this.huoquJilu(true, true); + // 后端若尚未落库,刷新后仍可能显示待收款,再覆盖一次本地成功态 + this.markLocalRecordWithdrawSuccess(record); + PopupService.checkAndShow(this, 'tixianchenggong'); + wx.showToast({ + title: '提现成功', + icon: 'success', + duration: 3000, + }); + }, + + async loadAllAssets() { + this.setData({ isLoadingAssets: true }); + try { + const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' }); + if (res?.data?.code === 200 || res?.data?.code === 0) { + const data = res.data.data || {}; + const assets = []; + const pushAsset = (type, amount, rate) => { + const cfg = ASSET_CONFIG[type]; + if (!cfg || !amount || parseFloat(amount) <= 0) return; + assets.push({ + type, + leixing: cfg.leixing, + label: cfg.label, + amount: parseFloat(amount).toFixed(2), + rate: rate || 0, + }); + }; + pushAsset('dashou_yue', data.dashou_yue, data.dashou_rate); + pushAsset('dashou_yajin', data.dashou_yajin, data.dashou_yajin_rate); + pushAsset('shangjia_yue', data.shangjia_yue, data.shangjia_rate); + pushAsset('guanshi_fenyong', data.guanshi_fenyong, data.guanshi_rate); + pushAsset('zuzhang_fenyong', data.zuzhang_fenyong, data.zuzhang_rate); + pushAsset('kaoheguan_fenyong', data.kaoheguan_fenyong, data.kaoheguan_rate); + + let total = 0; + assets.forEach(item => { total += parseFloat(item.amount); }); + this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoadingAssets: false }); + } else { + throw new Error(res?.data?.msg || '获取资产失败'); + } + } catch (err) { + console.error('loadAllAssets', err); + this.setData({ isLoadingAssets: false }); + } + }, + + chushihuashuju() { + this.loadAllAssets(); + this.huoquJilu(true); + }, + + /** 点击资产卡片(与 mode1 一致) */ + onSelectAsset(e) { + const index = e.currentTarget.dataset.index; + const asset = this.data.assetList[index]; + if (!asset || parseFloat(asset.amount) <= 0) { + wx.showToast({ title: '无可提现金额', icon: 'none' }); + return; + } + this.setData({ + selectedAsset: asset, + tixianleixing: asset.leixing, + currentRate: asset.rate, + tixianjine: '', + shouxufei: '0.00', + shijidaozhang: '0.00', + showTixian: true, + }); + }, + + onJineInput(e) { + this.setData({ tixianjine: e.detail.value, shouxufei: '0.00', shijidaozhang: '0.00' }); + }, + + onQuickAmountTap(e) { + const value = e.currentTarget.dataset.value; + this.setData({ tixianjine: value.toString(), shouxufei: '0.00', shijidaozhang: '0.00' }); + }, + + onStatusFilterTap(e) { + const value = parseInt(e.currentTarget.dataset.value); + if (value === this.data.currentStatusFilter) return; + this.setData({ currentStatusFilter: value }); + this.huoquJilu(true); + }, + + async onConfirmTixian() { + if (this.data.submitting) return; + const { tixianleixing, tixianjine, selectedAsset } = this.data; + if (!tixianleixing || !selectedAsset) { + wx.showToast({ title: '请选择提现类型', icon: 'none' }); + return; + } + const jineValue = parseFloat(tixianjine); + if (!tixianjine || isNaN(jineValue) || jineValue <= 0) { + wx.showToast({ title: '请输入有效金额', icon: 'none' }); + return; + } + if (jineValue > parseFloat(selectedAsset.amount)) { + wx.showToast({ title: `超过可提${selectedAsset.label}`, icon: 'none' }); + return; + } + + this.setData({ submitting: true }); + try { + const res = await request({ + url: '/yonghu/zddksh', + method: 'POST', + data: { leixing: tixianleixing, jine: jineValue.toFixed(2) } + }); + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const data = res.data.data || {}; + this.gengxinYue(data, tixianleixing); + if (data.shouxufei !== undefined) { + this.setData({ + shouxufei: parseFloat(data.shouxufei || 0).toFixed(2), + shijidaozhang: parseFloat(data.shijidaozhang || 0).toFixed(2), + }); + } + this.setData({ showTixian: false, submitting: false, selectedAsset: null }); + await this.loadAllAssets(); + this.huoquJilu(true); + wx.showModal({ + title: '申请已提交', + content: '您的提现申请已提交,请等待后台审核。审核通过后,请在本页「提现记录」中点击「收款」按钮,主动确认后才能到账微信零钱。', + showCancel: false, + }); + } else { + wx.showModal({ title: '提现申请失败', content: res.data?.msg || '未知错误', showCancel: false }); + this.setData({ submitting: false }); + } + } catch (err) { + wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false }); + this.setData({ submitting: false }); + } + }, + + onCollectTap(e) { + const index = e.currentTarget.dataset.index; + const record = this.data.recordList[index]; + if (!record) return; + if (this.parseZhuangtai(record) !== TX_STATUS.DAI_SHOUKUAN) { + wx.showToast({ title: '当前状态不可收款', icon: 'none' }); + return; + } + if (!this.hasShenheDanhao(record) || !this.hasAuditJiluId(record)) { + wx.showToast({ title: '审核信息不完整,请刷新后重试', icon: 'none' }); + return; + } + if (this.data.submitting) { + wx.showToast({ title: '正在处理中,请稍后', icon: 'none' }); + return; + } + this.setData({ showCollectConfirm: true, collectConfirmRecord: record }); + }, + + onCloseCollectConfirm() { + if (this.data.submitting) return; + this.setData({ showCollectConfirm: false, collectConfirmRecord: null }); + }, + + async onConfirmCollect() { + if (this.data.submitting) return; + let record = this.data.collectConfirmRecord; + if (!record) return; + + if (!this.canCollectRecord(record)) { + await this.huoquJilu(true, true); + const refreshed = (this.data.recordList || []).find( + r => String(r.id) === String(record.id) + || String(r.tixianjilu_id) === String(record.tixianjilu_id) + ); + if (refreshed) record = refreshed; + } + if (!this.canCollectRecord(record)) { + wx.showModal({ + title: '暂时无法收款', + content: '缺少审核单号或审核记录ID,请下拉刷新后重试。仍不行请联系客服。', + showCancel: false, + }); + return; + } + + this.setData({ showCollectConfirm: false, submitting: true, collectConfirmRecord: record }); + try { + const res = await request({ + url: '/yonghu/tixiansq', + method: 'POST', + data: { + shenhe_danhao: record.shenhe_danhao, + shenhe_jilu_id: record.shenhe_jilu_id || '', + tixianjilu_id: record.tixianjilu_id || record.id || '', + leixing: record.leixing, + } + }); + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const data = res.data.data; + this.setData({ + currentTixianId: data.tixian_id, + mchId: data.mch_id || '', + collectConfirmRecord: record, + }); + this.tiaoqiWeixinQueRen(data.package_info); + } else { + wx.showModal({ title: '收款失败', content: res.data?.msg || '无法发起收款,请稍后重试', showCancel: false }); + this.setData({ submitting: false, collectConfirmRecord: null }); + } + } catch (err) { + wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false }); + this.setData({ submitting: false, collectConfirmRecord: null }); + } + }, + + tiaoqiWeixinQueRen(packageInfo) { + const appId = app.globalData.appId; + const mchId = this.data.mchId; + if (!appId || !mchId) { + wx.showModal({ title: '配置错误', content: '无法调起收款,请联系客服', showCancel: false }); + this.setData({ submitting: false, collectConfirmRecord: null }); + return; + } + wx.requestMerchantTransfer({ + appId, mchId, package: packageInfo, + success: () => { this.tongzhiHouduanQueRen(1); }, + fail: () => { + this.tongzhiHouduanQueRen(0); + wx.showModal({ + title: '确认收款失败', + content: '微信收款确认失败,您可在记录中再次点击「收款」重试。', + showCancel: false, + }); + } + }); + }, + + async tongzhiHouduanQueRen(result) { + if (!this.data.currentTixianId) { + this.setData({ submitting: false, collectConfirmRecord: null }); + return; + } + const record = this.data.collectConfirmRecord; + const wxConfirmed = result === 1; + + try { + const res = await request({ + url: '/yonghu/tixianqr', + method: 'POST', + data: { + tixian_id: this.data.currentTixianId, + result: result, + shenhe_danhao: record ? record.shenhe_danhao : '', + shenhe_jilu_id: record ? (record.shenhe_jilu_id || '') : '', + tixianjilu_id: record ? (record.tixianjilu_id || record.id || '') : '', + leixing: record ? record.leixing : '', + } + }); + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const data = res.data.data || {}; + this.gengxinYue(data, record ? record.leixing : null); + } + + // 微信已确认收款:不论 tixianqr 返回什么,都刷新列表,不弹系统异常 + if (wxConfirmed) { + await this.finishWxCollectSuccess(record); + } else if (res.statusCode === 200 && res.data && res.data.code === 0) { + await this.loadAllAssets(); + this.huoquJilu(true); + wx.showToast({ + title: '收款已取消', + icon: 'none', + duration: 3000, + }); + } else { + wx.showModal({ + title: '确认状态失败', + content: res.data?.msg || '操作失败', + showCancel: false, + }); + } + } catch (err) { + if (wxConfirmed) { + await this.finishWxCollectSuccess(record); + } else { + wx.showModal({ + title: '网络错误', + content: '网络连接失败', + showCancel: false, + }); + } + } finally { + this.setData({ submitting: false, currentTixianId: null, collectConfirmRecord: null }); + } + }, + + onViewDetail(e) { + const index = e.currentTarget.dataset.index; + const record = this.data.recordList[index]; + if (!record || !record.canShowDetail) return; + const status = parseInt(record.zhuangtai); + let detailTitle = '失败原因'; + if (status === TX_STATUS.SHENHE_SHIBAI) detailTitle = '审核失败原因'; + else if (status === TX_STATUS.TIXIAN_SHIBAI) detailTitle = '提现失败原因'; + this.setData({ + showDetailModal: true, + detailTitle, + detailContent: record.detailReason || '暂无详细信息', + }); + }, + + onCloseDetailModal() { + this.setData({ showDetailModal: false, detailTitle: '', detailContent: '' }); + }, + + onCloseTixian() { + if (this.data.submitting) { wx.showToast({ title: '正在处理中,请稍后', icon: 'none' }); return; } + this.setData({ + showTixian: false, selectedAsset: null, tixianleixing: null, + tixianjine: '', shouxufei: '0.00', shijidaozhang: '0.00', submitting: false, + }); + }, + + async huoquJilu(fresh = false, force = false) { + const now = Date.now(); + if (!force && now - lastPullDownTime < 2000 && !fresh) return; + if (!force && (this.data.loading || this.data.isRefreshing)) return; + const page = fresh ? 1 : this.data.page; + if (fresh) this.setData({ nomore: false, canloadmore: true, isRefreshing: true }); + if (this.data.nomore && !fresh) return; + this.setData({ loading: true }); + lastPullDownTime = now; + try { + const res = await request({ + url: '/yonghu/tixianjiluhq', + method: 'POST', + data: { page, limit: yemianshuju, mode: 2, zhuangtai: this.data.currentStatusFilter } + }); + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const data = res.data.data; + const processedList = (data.list || []).map(item => this.processRecordItem(item)); + const newList = fresh ? processedList : [...this.data.recordList, ...processedList]; + this.setData({ + recordList: newList, + page: page + 1, + nomore: !(data.has_more === true), + canloadmore: data.has_more === true, + loading: false, + isRefreshing: false, + }); + this.updatePendingCollectFlag(newList); + } else { + this.setData({ loading: false, isRefreshing: false }); + } + } catch (err) { + this.setData({ loading: false, isRefreshing: false }); + } + }, + + onReachBottom() { + if (this.data.canloadmore && !this.data.nomore && !this.data.loading && !this.data.isRefreshing) { + const now = Date.now(); + if (now - lastPullDownTime >= PULL_DOWN_INTERVAL) this.huoquJilu(); + } + }, + + stopPropagation() {} + } +}); diff --git a/pages/tixian/components/mode2/mode2.json b/pages/withdraw/components/mode2/mode2.json similarity index 100% rename from pages/tixian/components/mode2/mode2.json rename to pages/withdraw/components/mode2/mode2.json diff --git a/pages/tixian/components/mode2/mode2.wxml b/pages/withdraw/components/mode2/mode2.wxml similarity index 100% rename from pages/tixian/components/mode2/mode2.wxml rename to pages/withdraw/components/mode2/mode2.wxml diff --git a/pages/tixian/components/mode2/mode2.wxss b/pages/withdraw/components/mode2/mode2.wxss similarity index 100% rename from pages/tixian/components/mode2/mode2.wxss rename to pages/withdraw/components/mode2/mode2.wxss diff --git a/pages/tixian/tixian.js b/pages/withdraw/withdraw.js similarity index 80% rename from pages/tixian/tixian.js rename to pages/withdraw/withdraw.js index 7764518..1246f6c 100644 --- a/pages/tixian/tixian.js +++ b/pages/withdraw/withdraw.js @@ -1,75 +1,72 @@ -// pages/tixian/tixian.js -import request from '../../utils/request.js'; -import PopupService from '../../services/popupService.js'; - -const app = getApp(); - -Page({ - data: { - pageMode: 0, // 0:加载中 1:收款码模式 2:微信零钱模式 - pageOptions: {}, // 保存启动参数,传给子组件 - loadError: false, // 获取模式失败时展示错误状态 - }, - - onLoad(options) { - this.setData({ - pageOptions: options || {} - }); - this.fetchPageMode(); - }, - - // ✅ 用 onShow,别用 pageLifetimes - onShow() { - this.registerNotificationComponent(); - // 如果已经在某个模式下,可以刷新一下子组件数据(可选) - // 弹窗检查 - PopupService.checkAndShow(this, 'tixian'); - }, - - onHide() { - const popupComp = this.selectComponent('#popupNotice'); - if (popupComp && popupComp.cleanup) { - popupComp.cleanup(); - } - }, - - // ✅ 注册通知组件(弹窗依赖它) - registerNotificationComponent() { - const notificationComp = this.selectComponent('#global-notification'); - if (notificationComp && notificationComp.showNotification) { - app.globalData.globalNotification = { - show: (data) => notificationComp.showNotification(data), - hide: () => notificationComp.hideNotification() - }; - } - }, - - async fetchPageMode() { - try { - const res = await request({ - url: '/peizhi/hqtxzsym', - method: 'POST' - }); - - if (res.statusCode === 200 && res.data && res.data.code === 0) { - const mode = parseInt(res.data.data.mode); - this.setData({ - pageMode: (mode === 1 || mode === 2) ? mode : 1, - loadError: false - }); - } else { - this.setData({ pageMode: 1, loadError: false }); - } - } catch (err) { - console.error('获取展示模式失败:', err); - this.setData({ loadError: true }); - } - }, - - retryFetch() { - this.setData({ loadError: false, pageMode: 0 }); - this.fetchPageMode(); - }, - - stopPropagation() {} +// pages/withdraw/withdraw.js +import request from '../../utils/request.js'; +import PopupService from '../../services/popupService.js'; + +const app = getApp(); + +Page({ + data: { + pageMode: 0, + pageOptions: {}, + loadError: false, + }, + + onLoad(options) { + this.setData({ + pageOptions: options || {} + }); + this.fetchPageMode(); + }, + + onShow() { + this.registerNotificationComponent(); + PopupService.checkAndShow(this, 'tixian'); + }, + + onHide() { + const popupComp = this.selectComponent('#popupNotice'); + if (popupComp && popupComp.cleanup) { + popupComp.cleanup(); + } + }, + + // 注册通知组件 + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp && notificationComp.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + async fetchPageMode() { + try { + const res = await request({ + url: '/peizhi/hqtxzsym', + method: 'POST' + }); + + if (res.statusCode === 200 && res.data && res.data.code === 0) { + const mode = parseInt(res.data.data.mode); + this.setData({ + pageMode: (mode === 1 || mode === 2) ? mode : 1, + loadError: false + }); + } else { + this.setData({ pageMode: 1, loadError: false }); + } + } catch (err) { + console.error('获取展示模式失败:', err); + this.setData({ loadError: true }); + } + }, + + retryFetch() { + this.setData({ loadError: false, pageMode: 0 }); + this.fetchPageMode(); + }, + + stopPropagation() {} }); \ No newline at end of file diff --git a/pages/tixian/tixian.json b/pages/withdraw/withdraw.json similarity index 100% rename from pages/tixian/tixian.json rename to pages/withdraw/withdraw.json diff --git a/pages/tixian/tixian.wxml b/pages/withdraw/withdraw.wxml similarity index 92% rename from pages/tixian/tixian.wxml rename to pages/withdraw/withdraw.wxml index 88e6cdd..e059375 100644 --- a/pages/tixian/tixian.wxml +++ b/pages/withdraw/withdraw.wxml @@ -1,33 +1,33 @@ - - - - - - - 加载中... - - - - - 加载失败,请检查网络 - 点击重试 - - - - - - - - - - - + + + + + + + 加载中... + + + + + 加载失败,请检查网络 + 点击重试 + + + + + + + + + + + \ No newline at end of file diff --git a/pages/tixian/tixian.wxss b/pages/withdraw/withdraw.wxss similarity index 53% rename from pages/tixian/tixian.wxss rename to pages/withdraw/withdraw.wxss index 6aa6530..fe81d0a 100644 --- a/pages/tixian/tixian.wxss +++ b/pages/withdraw/withdraw.wxss @@ -1,50 +1,34 @@ -/* pages/tixian/tixian.wxss */ -.tixian-container { - width: 100%; - min-height: 100vh; - position: relative; -} - -/* 加载状态 */ -.loading-center, .error-center { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; - color: #ffffff; - background: #1a0b2e; /* 与赛博朋克背景统一 */ -} - -.loading-spinner { - width: 60rpx; - height: 60rpx; - border: 4rpx solid rgba(157, 78, 221, 0.3); - border-top-color: #9d4edd; - border-radius: 50%; - animation: spin 0.8s linear infinite; - margin-bottom: 30rpx; -} - -.loading-text { - font-size: 28rpx; - color: rgba(255, 255, 255, 0.7); -} - -.error-text { - font-size: 28rpx; - margin-bottom: 30rpx; -} - -.retry-btn { - padding: 20rpx 60rpx; - background: linear-gradient(90deg, #6a11cb, #2575fc); - color: white; - border-radius: 40rpx; - font-size: 28rpx; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} \ No newline at end of file +/* pages/withdraw/withdraw.wxss */ +.tixian-container { + width: 100%; +} + +/* 加载状态 */ +.loading-center, .error-center { + height: 100vh; + color: #ffffff; + background: #1a0b2e; +} + +.loading-spinner { + border: 4rpx solid rgba(157, 78, 221, 0.3); + border-top-color: #9d4edd; + margin-bottom: 30rpx; +} + +.loading-text { + font-size: 28rpx; + color: rgba(255, 255, 255, 0.7); +} + +.error-text { + font-size: 28rpx; + margin-bottom: 30rpx; +} + +.retry-btn { + padding: 20rpx 60rpx; + background: linear-gradient(90deg, #6a11cb, #2575fc); + color: white; + font-size: 28rpx; +} diff --git a/pages/xuanren/xuanren.js b/pages/xuanren/xuanren.js deleted file mode 100644 index 5ac9bb3..0000000 --- a/pages/xuanren/xuanren.js +++ /dev/null @@ -1,66 +0,0 @@ -// pages/xuanren/xuanren.js -Page({ - - /** - * 页面的初始数据 - */ - data: { - - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - - } -}) \ No newline at end of file diff --git a/pages/xuanren/xuanren.wxss b/pages/xuanren/xuanren.wxss deleted file mode 100644 index 9103bc8..0000000 --- a/pages/xuanren/xuanren.wxss +++ /dev/null @@ -1 +0,0 @@ -/* pages/xuanren/xuanren.wxss */ \ No newline at end of file diff --git a/utils/chat-core.js b/utils/chat-core.js index 192f558..02488a4 100644 --- a/utils/chat-core.js +++ b/utils/chat-core.js @@ -1,400 +1,400 @@ -// utils/chat-core.js — 全局 IM 连接、监听、角标(稳定版) -import GoEasy from '../static/lib/goeasy-2.13.24.esm.min'; -import { resolveAvatarUrl } from './avatar.js'; -import { getLocalImUserId, getLocalImIdentity } from './im-user.js'; - -let _convListener = null; -let _privateListener = null; -let _groupListener = null; -let _notificationHandler = null; -let _heartbeatTimer = null; -let _listenersBoundForUser = null; -let _lastGroupSubscribeAt = 0; -const _notifiedMessageIds = new Map(); -const NOTIFY_MAX_AGE_MS = 15000; - -function shouldShowNotification(message) { - if (!message) return false; - const id = message.messageId || `${message.senderId}_${message.timestamp}`; - if (_notifiedMessageIds.has(id)) return false; - if (message.timestamp && Date.now() - message.timestamp > NOTIFY_MAX_AGE_MS) return false; - _notifiedMessageIds.set(id, Date.now()); - if (_notifiedMessageIds.size > 400) { - const cutoff = Date.now() - 60000; - _notifiedMessageIds.forEach((t, k) => { - if (t < cutoff) _notifiedMessageIds.delete(k); - }); - } - return true; -} - -function bindGlobalListenersIfNeeded(app, userId) { - if (_listenersBoundForUser === userId && _convListener) return; - registerGlobalListeners(app); - registerNotification(app); - _listenersBoundForUser = userId; -} - -function initGlobalMessageSystem(app) { - app.ensureConnection = () => ensureConnection(app); - app.connectForCurrentRole = () => ensureConnection(app); - app.loadConversations = () => loadConversations(app); - app.disconnectGoEasy = () => disconnectGoEasy(app); - app.switchRoleAndReconnect = (newRole) => switchRoleAndReconnect(app, newRole); - app.updateUnreadCount = (count) => updateTabBarBadge(app, count || 0); - app.reregisterNotification = () => registerNotification(app); - app.startImWhenReady = () => startImWhenReady(app); - - if (!app.globalData.messageManager) { - app.globalData.messageManager = {}; - } - try { - const muted = wx.getStorageSync('notificationMuted'); - if (muted !== undefined) app.globalData.messageManager.notificationMuted = muted; - } catch (e) {} - - initAppStateListener(app); - initNetworkListener(app); - startHeartbeat(app); - startImWhenReady(app); -} - -/** GoEasy 未就绪时轮询,登录后尽早建立监听 */ -function startImWhenReady(app, maxAttempts = 40) { - let attempts = 0; - const tick = () => { - if (!wx.getStorageSync('uid')) return; - attempts += 1; - if (!wx.goEasy) { - if (attempts < maxAttempts) setTimeout(tick, 250); - return; - } - ensureConnection(app); - }; - tick(); -} - -function getCurrentUserId() { - return (wx.goEasy && wx.goEasy.im && wx.goEasy.im.userId) || null; -} - -function getConnectionStatus() { - if (!wx.goEasy || !wx.goEasy.getConnectionStatus) return 'disconnected'; - return wx.goEasy.getConnectionStatus(); -} - -function isConnected() { - const s = getConnectionStatus(); - return s === 'connected' || s === 'reconnected'; -} - -/** 统一会话数据结构,避免不同回调格式导致列表空白 */ -function normalizeConversationsPayload(result) { - if (!result) return { conversations: [], unreadTotal: 0 }; - const content = result.content || result; - const conversations = content.conversations || result.conversations || []; - const unreadTotal = content.unreadTotal ?? result.unreadTotal ?? 0; - return { conversations, unreadTotal }; -} - -function emitConversationsUpdated(app, result) { - const payload = normalizeConversationsPayload(result); - updateTabBarBadge(app, payload.unreadTotal); - app.emitEvent('conversationsUpdated', { - content: payload, - unreadTotal: payload.unreadTotal, - raw: result, - }); -} - -async function ensureConnection(app) { - const uid = wx.getStorageSync('uid'); - if (!uid || !wx.goEasy) return; - - const targetUserId = getLocalImUserId(app); - const identityType = getLocalImIdentity(app); - if (!targetUserId) return; - - if (isConnected()) { - const currentUserId = getCurrentUserId(); - if (currentUserId === targetUserId) { - bindGlobalListenersIfNeeded(app, targetUserId); - loadConversations(app); - const now = Date.now(); - if (now - _lastGroupSubscribeAt > 60000) { - _lastGroupSubscribeAt = now; - await subscribeAllGroups(app); - } - return; - } - try { - wx.goEasy.disconnect(); - } catch (e) {} - } - - connectGoEasy(app, targetUserId, identityType); -} - -function connectGoEasy(app, userId, identityType) { - const defAvatar = resolveAvatarUrl('', app); - const tx = wx.getStorageSync('touxiang') || ''; - const uid = wx.getStorageSync('uid') || ''; - const nick = wx.getStorageSync('nicheng') || app.globalData.nicheng || app.globalData.dashouNicheng || ''; - const name = nick || ('用户' + (uid || '').substring(0, 6)); - const avatar = resolveAvatarUrl(tx, app) || defAvatar; - - wx.goEasy.connect({ - id: userId, - data: { - name, - avatar, - identityType: identityType === 'normal' ? 'boss' : identityType, - }, - onSuccess: async () => { - try { - wx.setStorageSync('savedGoEasyConnection', JSON.stringify({ - userId, - identityType, - lastConnectTime: Date.now(), - status: 'connected', - })); - } catch (e) {} - bindGlobalListenersIfNeeded(app, userId); - _lastGroupSubscribeAt = Date.now(); - await subscribeAllGroups(app); - loadConversations(app); - }, - onFailed: (error) => { - console.error('GoEasy连接失败', error); - if (error.code === 408) { - bindGlobalListenersIfNeeded(app, userId); - loadConversations(app); - } else { - wx.showToast({ title: '连接失败,请重试', icon: 'none' }); - } - }, - }); -} - -function subscribeAllGroups(app) { - return new Promise((resolve) => { - if (!wx.goEasy || !wx.goEasy.im) return resolve(); - wx.goEasy.im.latestConversations({ - onSuccess: (result) => { - const payload = normalizeConversationsPayload(result); - const groupIds = payload.conversations - .filter((c) => c.type === 'group' && c.groupId) - .map((c) => c.groupId); - if (groupIds.length && wx.goEasy.im.subscribeGroup) { - wx.goEasy.im.subscribeGroup({ - groupIds, - onSuccess: () => resolve(), - onFailed: () => resolve(), - }); - } else { - resolve(); - } - }, - onFailed: () => resolve(), - }); - }); -} - -function registerGlobalListeners(app) { - if (!wx.goEasy || !wx.goEasy.im) return; - - if (_convListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); - } - if (_privateListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); - } - if (_groupListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); - } - - _convListener = (result) => { - emitConversationsUpdated(app, result); - }; - wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); - - _privateListener = () => { - loadConversations(app); - }; - wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); - - _groupListener = () => { - loadConversations(app); - }; - wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); -} - -function loadConversations(app) { - if (!wx.goEasy || !wx.goEasy.im) return; - if (!getCurrentUserId()) return; - - wx.goEasy.im.latestConversations({ - onSuccess: (result) => { - emitConversationsUpdated(app, result); - subscribeAllGroups(app); - }, - onFailed: (err) => { - console.error('加载会话失败', err); - }, - }); -} - -function updateTabBarBadge(app, unreadCount) { - const badgeText = unreadCount > 0 ? (unreadCount > 99 ? '99+' : String(unreadCount)) : ''; - if (!app.globalData.messageManager) app.globalData.messageManager = {}; - app.globalData.messageManager.unreadTotal = unreadCount; - app.globalData.messageManager.tabBarBadgeText = badgeText; - app.emitEvent('tabBarBadgeChanged', { badgeText, showRedDot: unreadCount > 0 }); - - try { - const pages = getCurrentPages(); - if (pages.length) { - const page = pages[pages.length - 1]; - const tabBar = page.selectComponent('#custom-tab-bar'); - if (tabBar && tabBar.setData) tabBar.setData({ badgeText }); - if (page.getTabBar) { - const tb = page.getTabBar(); - if (tb && tb.setData) tb.setData({ badgeText }); - } - } - } catch (e) {} - wx.setStorageSync('messageUnreadTotal', unreadCount); -} - -function registerNotification(app) { - if (!wx.goEasy || !wx.goEasy.im) return; - - if (_notificationHandler) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); - } - - _notificationHandler = (message) => { - if (app.globalData.messageManager && app.globalData.messageManager.notificationMuted) return; - if (!shouldShowNotification(message)) return; - const pages = getCurrentPages(); - if (pages.length) { - const curPage = pages[pages.length - 1]; - const route = curPage.route || ''; - if (route === 'pages/liaotian/liaotian' || route === 'pages/qunliaotian/qunliaotian') return; - } - const senderName = message.senderData?.name || (message.senderId || '用户'); - let content = ''; - if (message.type === 'text') content = message.payload?.text || '[文本]'; - else if (message.type === 'image') content = '[图片]'; - else if (message.type === 'audio') content = '[语音]'; - else content = '[新消息]'; - const avatar = resolveAvatarUrl(message.senderData?.avatar, app); - - if (app.globalData.globalNotification && app.globalData.globalNotification.show) { - app.globalData.globalNotification.show({ - senderName, - content, - avatar, - message, - notificationType: message.groupId ? 'group' : 'private', - groupId: message.groupId, - orderId: message.orderId, - }); - } else { - wx.showToast({ title: `${senderName}: ${content}`, icon: 'none', duration: 2000 }); - } - }; - wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); - wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); -} - -function detachGlobalListeners() { - if (!wx.goEasy || !wx.goEasy.im) return; - if (_convListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); - _convListener = null; - } - if (_privateListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); - _privateListener = null; - } - if (_groupListener) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); - _groupListener = null; - } - if (_notificationHandler) { - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); - wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); - _notificationHandler = null; - } - _listenersBoundForUser = null; -} - -function disconnectGoEasy(app) { - stopHeartbeat(app); - detachGlobalListeners(); - if (wx.goEasy && wx.goEasy.disconnect) { - wx.goEasy.disconnect({ onSuccess: () => {}, onFailed: () => {} }); - } - wx.removeStorageSync('savedGoEasyConnection'); -} - -async function switchRoleAndReconnect(app, newRole) { - disconnectGoEasy(app); - app.globalData.currentRole = newRole; - wx.setStorageSync('currentRole', newRole); - if (app.globalData.primaryRole !== newRole && ['normal', 'dashou', 'shangjia'].includes(newRole)) { - app.globalData.primaryRole = newRole; - wx.setStorageSync('primaryRole', newRole); - } - startHeartbeat(app); - await ensureConnection(app); - return true; -} - -function startHeartbeat(app) { - stopHeartbeat(app); - _heartbeatTimer = setInterval(() => { - if (!wx.getStorageSync('uid')) return; - if (isConnected()) { - loadConversations(app); - } else { - ensureConnection(app); - } - }, 45000); -} - -function stopHeartbeat(app) { - if (_heartbeatTimer) { - clearInterval(_heartbeatTimer); - _heartbeatTimer = null; - } -} - -function initAppStateListener(app) { - wx.onAppShow(() => { - setTimeout(() => { - if (!wx.getStorageSync('uid')) return; - if (!isConnected()) { - ensureConnection(app); - } else { - loadConversations(app); - setTimeout(() => { - const unread = (app.globalData.messageManager && app.globalData.messageManager.unreadTotal) || 0; - updateTabBarBadge(app, unread); - }, 300); - } - }, 200); - }); -} - -function initNetworkListener(app) { - wx.onNetworkStatusChange((res) => { - if (res.isConnected) { - setTimeout(() => ensureConnection(app), 1000); - } - }); -} - -module.exports = { initGlobalMessageSystem }; +// utils/chat-core.js — 全局 IM 连接、监听、角标(稳定版) +import GoEasy from '../static/lib/goeasy-2.13.24.esm.min'; +import { resolveAvatarUrl } from './avatar.js'; +import { getLocalImUserId, getLocalImIdentity } from './im-user.js'; + +let _convListener = null; +let _privateListener = null; +let _groupListener = null; +let _notificationHandler = null; +let _heartbeatTimer = null; +let _listenersBoundForUser = null; +let _lastGroupSubscribeAt = 0; +const _notifiedMessageIds = new Map(); +const NOTIFY_MAX_AGE_MS = 15000; + +function shouldShowNotification(message) { + if (!message) return false; + const id = message.messageId || `${message.senderId}_${message.timestamp}`; + if (_notifiedMessageIds.has(id)) return false; + if (message.timestamp && Date.now() - message.timestamp > NOTIFY_MAX_AGE_MS) return false; + _notifiedMessageIds.set(id, Date.now()); + if (_notifiedMessageIds.size > 400) { + const cutoff = Date.now() - 60000; + _notifiedMessageIds.forEach((t, k) => { + if (t < cutoff) _notifiedMessageIds.delete(k); + }); + } + return true; +} + +function bindGlobalListenersIfNeeded(app, userId) { + if (_listenersBoundForUser === userId && _convListener) return; + registerGlobalListeners(app); + registerNotification(app); + _listenersBoundForUser = userId; +} + +function initGlobalMessageSystem(app) { + app.ensureConnection = () => ensureConnection(app); + app.connectForCurrentRole = () => ensureConnection(app); + app.loadConversations = () => loadConversations(app); + app.disconnectGoEasy = () => disconnectGoEasy(app); + app.switchRoleAndReconnect = (newRole) => switchRoleAndReconnect(app, newRole); + app.updateUnreadCount = (count) => updateTabBarBadge(app, count || 0); + app.reregisterNotification = () => registerNotification(app); + app.startImWhenReady = () => startImWhenReady(app); + + if (!app.globalData.messageManager) { + app.globalData.messageManager = {}; + } + try { + const muted = wx.getStorageSync('notificationMuted'); + if (muted !== undefined) app.globalData.messageManager.notificationMuted = muted; + } catch (e) {} + + initAppStateListener(app); + initNetworkListener(app); + startHeartbeat(app); + startImWhenReady(app); +} + +/** GoEasy 未就绪时轮询,登录后尽早建立监听 */ +function startImWhenReady(app, maxAttempts = 40) { + let attempts = 0; + const tick = () => { + if (!wx.getStorageSync('uid')) return; + attempts += 1; + if (!wx.goEasy) { + if (attempts < maxAttempts) setTimeout(tick, 250); + return; + } + ensureConnection(app); + }; + tick(); +} + +function getCurrentUserId() { + return (wx.goEasy && wx.goEasy.im && wx.goEasy.im.userId) || null; +} + +function getConnectionStatus() { + if (!wx.goEasy || !wx.goEasy.getConnectionStatus) return 'disconnected'; + return wx.goEasy.getConnectionStatus(); +} + +function isConnected() { + const s = getConnectionStatus(); + return s === 'connected' || s === 'reconnected'; +} + +/** 统一会话数据结构,避免不同回调格式导致列表空白 */ +function normalizeConversationsPayload(result) { + if (!result) return { conversations: [], unreadTotal: 0 }; + const content = result.content || result; + const conversations = content.conversations || result.conversations || []; + const unreadTotal = content.unreadTotal ?? result.unreadTotal ?? 0; + return { conversations, unreadTotal }; +} + +function emitConversationsUpdated(app, result) { + const payload = normalizeConversationsPayload(result); + updateTabBarBadge(app, payload.unreadTotal); + app.emitEvent('conversationsUpdated', { + content: payload, + unreadTotal: payload.unreadTotal, + raw: result, + }); +} + +async function ensureConnection(app) { + const uid = wx.getStorageSync('uid'); + if (!uid || !wx.goEasy) return; + + const targetUserId = getLocalImUserId(app); + const identityType = getLocalImIdentity(app); + if (!targetUserId) return; + + if (isConnected()) { + const currentUserId = getCurrentUserId(); + if (currentUserId === targetUserId) { + bindGlobalListenersIfNeeded(app, targetUserId); + loadConversations(app); + const now = Date.now(); + if (now - _lastGroupSubscribeAt > 60000) { + _lastGroupSubscribeAt = now; + await subscribeAllGroups(app); + } + return; + } + try { + wx.goEasy.disconnect(); + } catch (e) {} + } + + connectGoEasy(app, targetUserId, identityType); +} + +function connectGoEasy(app, userId, identityType) { + const defAvatar = resolveAvatarUrl('', app); + const tx = wx.getStorageSync('touxiang') || ''; + const uid = wx.getStorageSync('uid') || ''; + const nick = wx.getStorageSync('nicheng') || app.globalData.nicheng || app.globalData.dashouNicheng || ''; + const name = nick || ('用户' + (uid || '').substring(0, 6)); + const avatar = resolveAvatarUrl(tx, app) || defAvatar; + + wx.goEasy.connect({ + id: userId, + data: { + name, + avatar, + identityType: identityType === 'normal' ? 'boss' : identityType, + }, + onSuccess: async () => { + try { + wx.setStorageSync('savedGoEasyConnection', JSON.stringify({ + userId, + identityType, + lastConnectTime: Date.now(), + status: 'connected', + })); + } catch (e) {} + bindGlobalListenersIfNeeded(app, userId); + _lastGroupSubscribeAt = Date.now(); + await subscribeAllGroups(app); + loadConversations(app); + }, + onFailed: (error) => { + console.error('GoEasy连接失败', error); + if (error.code === 408) { + bindGlobalListenersIfNeeded(app, userId); + loadConversations(app); + } else { + wx.showToast({ title: '连接失败,请重试', icon: 'none' }); + } + }, + }); +} + +function subscribeAllGroups(app) { + return new Promise((resolve) => { + if (!wx.goEasy || !wx.goEasy.im) return resolve(); + wx.goEasy.im.latestConversations({ + onSuccess: (result) => { + const payload = normalizeConversationsPayload(result); + const groupIds = payload.conversations + .filter((c) => c.type === 'group' && c.groupId) + .map((c) => c.groupId); + if (groupIds.length && wx.goEasy.im.subscribeGroup) { + wx.goEasy.im.subscribeGroup({ + groupIds, + onSuccess: () => resolve(), + onFailed: () => resolve(), + }); + } else { + resolve(); + } + }, + onFailed: () => resolve(), + }); + }); +} + +function registerGlobalListeners(app) { + if (!wx.goEasy || !wx.goEasy.im) return; + + if (_convListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); + } + if (_privateListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); + } + if (_groupListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); + } + + _convListener = (result) => { + emitConversationsUpdated(app, result); + }; + wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); + + _privateListener = () => { + loadConversations(app); + }; + wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); + + _groupListener = () => { + loadConversations(app); + }; + wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); +} + +function loadConversations(app) { + if (!wx.goEasy || !wx.goEasy.im) return; + if (!getCurrentUserId()) return; + + wx.goEasy.im.latestConversations({ + onSuccess: (result) => { + emitConversationsUpdated(app, result); + subscribeAllGroups(app); + }, + onFailed: (err) => { + console.error('加载会话失败', err); + }, + }); +} + +function updateTabBarBadge(app, unreadCount) { + const badgeText = unreadCount > 0 ? (unreadCount > 99 ? '99+' : String(unreadCount)) : ''; + if (!app.globalData.messageManager) app.globalData.messageManager = {}; + app.globalData.messageManager.unreadTotal = unreadCount; + app.globalData.messageManager.tabBarBadgeText = badgeText; + app.emitEvent('tabBarBadgeChanged', { badgeText, showRedDot: unreadCount > 0 }); + + try { + const pages = getCurrentPages(); + if (pages.length) { + const page = pages[pages.length - 1]; + const tabBar = page.selectComponent('#custom-tab-bar'); + if (tabBar && tabBar.setData) tabBar.setData({ badgeText }); + if (page.getTabBar) { + const tb = page.getTabBar(); + if (tb && tb.setData) tb.setData({ badgeText }); + } + } + } catch (e) {} + wx.setStorageSync('messageUnreadTotal', unreadCount); +} + +function registerNotification(app) { + if (!wx.goEasy || !wx.goEasy.im) return; + + if (_notificationHandler) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); + } + + _notificationHandler = (message) => { + if (app.globalData.messageManager && app.globalData.messageManager.notificationMuted) return; + if (!shouldShowNotification(message)) return; + const pages = getCurrentPages(); + if (pages.length) { + const curPage = pages[pages.length - 1]; + const route = curPage.route || ''; + if (route === 'pages/chat/chat' || route === 'pages/group-chat/group-chat') return; + } + const senderName = message.senderData?.name || (message.senderId || '用户'); + let content = ''; + if (message.type === 'text') content = message.payload?.text || '[文本]'; + else if (message.type === 'image') content = '[图片]'; + else if (message.type === 'audio') content = '[语音]'; + else content = '[新消息]'; + const avatar = resolveAvatarUrl(message.senderData?.avatar, app); + + if (app.globalData.globalNotification && app.globalData.globalNotification.show) { + app.globalData.globalNotification.show({ + senderName, + content, + avatar, + message, + notificationType: message.groupId ? 'group' : 'private', + groupId: message.groupId, + orderId: message.orderId, + }); + } else { + wx.showToast({ title: `${senderName}: ${content}`, icon: 'none', duration: 2000 }); + } + }; + wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); + wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); +} + +function detachGlobalListeners() { + if (!wx.goEasy || !wx.goEasy.im) return; + if (_convListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener); + _convListener = null; + } + if (_privateListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener); + _privateListener = null; + } + if (_groupListener) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener); + _groupListener = null; + } + if (_notificationHandler) { + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler); + wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler); + _notificationHandler = null; + } + _listenersBoundForUser = null; +} + +function disconnectGoEasy(app) { + stopHeartbeat(app); + detachGlobalListeners(); + if (wx.goEasy && wx.goEasy.disconnect) { + wx.goEasy.disconnect({ onSuccess: () => {}, onFailed: () => {} }); + } + wx.removeStorageSync('savedGoEasyConnection'); +} + +async function switchRoleAndReconnect(app, newRole) { + disconnectGoEasy(app); + app.globalData.currentRole = newRole; + wx.setStorageSync('currentRole', newRole); + if (app.globalData.primaryRole !== newRole && ['normal', 'dashou', 'shangjia'].includes(newRole)) { + app.globalData.primaryRole = newRole; + wx.setStorageSync('primaryRole', newRole); + } + startHeartbeat(app); + await ensureConnection(app); + return true; +} + +function startHeartbeat(app) { + stopHeartbeat(app); + _heartbeatTimer = setInterval(() => { + if (!wx.getStorageSync('uid')) return; + if (isConnected()) { + loadConversations(app); + } else { + ensureConnection(app); + } + }, 45000); +} + +function stopHeartbeat(app) { + if (_heartbeatTimer) { + clearInterval(_heartbeatTimer); + _heartbeatTimer = null; + } +} + +function initAppStateListener(app) { + wx.onAppShow(() => { + setTimeout(() => { + if (!wx.getStorageSync('uid')) return; + if (!isConnected()) { + ensureConnection(app); + } else { + loadConversations(app); + setTimeout(() => { + const unread = (app.globalData.messageManager && app.globalData.messageManager.unreadTotal) || 0; + updateTabBarBadge(app, unread); + }, 300); + } + }, 200); + }); +} + +function initNetworkListener(app) { + wx.onNetworkStatusChange((res) => { + if (res.isConnected) { + setTimeout(() => ensureConnection(app), 1000); + } + }); +} + +module.exports = { initGlobalMessageSystem }; diff --git a/utils/im-user.js b/utils/im-user.js index e1630c8..49f2b39 100644 --- a/utils/im-user.js +++ b/utils/im-user.js @@ -1,78 +1,78 @@ -/** IM 用户 ID:三端连接 + 管事/组长/考核官统一走打手 Ds 前缀 */ -import { getPrimaryRole } from './primary-role.js'; -import { resolveAvatarUrl } from './avatar.js'; -import { ensureRoleOnCenterPage } from './role-tab-bar.js'; - -/** 联系对象前缀:管事/组长/考核官已废弃独立前缀,统一 Ds */ -const PEER_PREFIX = { - boss: 'Boss', - normal: 'Boss', - dashou: 'Ds', - shangjia: 'Sj', - guanshi: 'Ds', - zuzhang: 'Ds', - kaoheguan: 'Ds', -}; - -export function getImPrefixForRole(role) { - return PEER_PREFIX[role] || 'Ds'; -} - -/** 当前端连接 GoEasy 用的 userId */ -export function getLocalImUserId(app) { - app = app || getApp(); - const uid = wx.getStorageSync('uid') || ''; - if (!uid) return ''; - const primary = getPrimaryRole(app); - if (primary === 'dashou') return 'Ds' + uid; - if (primary === 'shangjia') return 'Sj' + uid; - return 'Boss' + uid; -} - -export function getLocalImIdentity(app) { - app = app || getApp(); - return getPrimaryRole(app) || 'normal'; -} - -export function buildPeerImUserId(uid, role = 'dashou') { - if (!uid) return ''; - return getImPrefixForRole(role) + uid; -} - -/** 联系邀请人/管事/组长:统一 Ds 前缀 */ -export function buildGuanshiPeerId(uid) { - return buildDashouPeerId(uid); -} - -export function buildDashouPeerId(uid) { - return buildPeerImUserId(uid, 'dashou'); -} - -export function buildInviterPeerId(uid) { - return buildDashouPeerId(uid); -} - -export function ensureDashouImReady(page) { - const app = getApp(); - ensureRoleOnCenterPage(page, 'dashou'); - if (app.ensureConnection) app.ensureConnection(); -} - -export function openPrivateChat(page, { toUserId, toName, toAvatar, delay = 350 }) { - ensureDashouImReady(page); - const avatar = resolveAvatarUrl(toAvatar); - const param = { - toUserId, - toName: toName || '用户', - toAvatar: avatar, - }; - return new Promise((resolve) => { - setTimeout(() => { - wx.navigateTo({ - url: '/pages/liaotian/liaotian?data=' + encodeURIComponent(JSON.stringify(param)), - fail: () => wx.showToast({ title: '打开聊天失败', icon: 'none' }), - complete: resolve, - }); - }, delay); - }); -} +/** IM 用户 ID:三端连接 + 管事/组长/考核官统一走打手 Ds 前缀 */ +import { getPrimaryRole } from './primary-role.js'; +import { resolveAvatarUrl } from './avatar.js'; +import { ensureRoleOnCenterPage } from './role-tab-bar.js'; + +/** 联系对象前缀:管事/组长/考核官已废弃独立前缀,统一 Ds */ +const PEER_PREFIX = { + boss: 'Boss', + normal: 'Boss', + dashou: 'Ds', + shangjia: 'Sj', + guanshi: 'Ds', + zuzhang: 'Ds', + kaoheguan: 'Ds', +}; + +export function getImPrefixForRole(role) { + return PEER_PREFIX[role] || 'Ds'; +} + +/** 当前端连接 GoEasy 用的 userId */ +export function getLocalImUserId(app) { + app = app || getApp(); + const uid = wx.getStorageSync('uid') || ''; + if (!uid) return ''; + const primary = getPrimaryRole(app); + if (primary === 'dashou') return 'Ds' + uid; + if (primary === 'shangjia') return 'Sj' + uid; + return 'Boss' + uid; +} + +export function getLocalImIdentity(app) { + app = app || getApp(); + return getPrimaryRole(app) || 'normal'; +} + +export function buildPeerImUserId(uid, role = 'dashou') { + if (!uid) return ''; + return getImPrefixForRole(role) + uid; +} + +/** 联系邀请人/管事/组长:统一 Ds 前缀 */ +export function buildGuanshiPeerId(uid) { + return buildDashouPeerId(uid); +} + +export function buildDashouPeerId(uid) { + return buildPeerImUserId(uid, 'dashou'); +} + +export function buildInviterPeerId(uid) { + return buildDashouPeerId(uid); +} + +export function ensureDashouImReady(page) { + const app = getApp(); + ensureRoleOnCenterPage(page, 'dashou'); + if (app.ensureConnection) app.ensureConnection(); +} + +export function openPrivateChat(page, { toUserId, toName, toAvatar, delay = 350 }) { + ensureDashouImReady(page); + const avatar = resolveAvatarUrl(toAvatar); + const param = { + toUserId, + toName: toName || '用户', + toAvatar: avatar, + }; + return new Promise((resolve) => { + setTimeout(() => { + wx.navigateTo({ + url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)), + fail: () => wx.showToast({ title: '打开聊天失败', icon: 'none' }), + complete: resolve, + }); + }, delay); + }); +} diff --git a/utils/primary-role.js b/utils/primary-role.js index 1221323..29005ba 100644 --- a/utils/primary-role.js +++ b/utils/primary-role.js @@ -1,105 +1,105 @@ -/** 三端固定:normal | dashou | shangjia,认证后不可回退 */ - -const VALID = ['normal', 'dashou', 'shangjia']; -const LEGACY_CENTER_ROLES = ['guanshi', 'zuzhang', 'kaoheguan']; - -/** 旧版管事/组长/考核官主端标识 → 统一回落打手 Tab */ -export function migrateLegacyCenterRole(app) { - app = app || getApp(); - const cur = wx.getStorageSync('currentRole') || app.globalData.currentRole || ''; - const pri = wx.getStorageSync('primaryRole') || ''; - const isLegacy = LEGACY_CENTER_ROLES.includes(cur) || LEGACY_CENTER_ROLES.includes(pri); - if (!isLegacy) return false; - - const hasDashouSide = - isRoleStatusActive(wx.getStorageSync('dashoustatus')) - || isRoleStatusActive(wx.getStorageSync('guanshistatus')) - || isRoleStatusActive(wx.getStorageSync('zuzhangstatus')) - || isRoleStatusActive(wx.getStorageSync('kaoheguanstatus')); - - if (hasDashouSide) { - lockPrimaryRole('dashou', app); - return true; - } - return false; -} - -export function isRoleStatusActive(status) { - return Number(status) === 1; -} - -/** 读取主端(兼容旧 currentRole / 管事组长落地页) */ -export function getPrimaryRole(app) { - app = app || getApp(); - const stored = wx.getStorageSync('primaryRole'); - if (VALID.includes(stored)) { - return stored; - } - const legacy = wx.getStorageSync('currentRole') || app.globalData.currentRole || 'normal'; - if (legacy === 'dashou' || legacy === 'shangjia') { - return legacy; - } - if (legacy === 'guanshi' || legacy === 'zuzhang' || legacy === 'kaoheguan') { - if (isRoleStatusActive(wx.getStorageSync('dashoustatus'))) { - return 'dashou'; - } - if (isRoleStatusActive(wx.getStorageSync('shangjiastatus'))) { - return 'shangjia'; - } - } - if (isRoleStatusActive(wx.getStorageSync('dashoustatus'))) { - return 'dashou'; - } - if (isRoleStatusActive(wx.getStorageSync('shangjiastatus'))) { - return 'shangjia'; - } - return 'normal'; -} - -/** 锁定主端并同步 TabBar 角色 */ -export function lockPrimaryRole(role, app) { - if (!VALID.includes(role)) return; - app = app || getApp(); - wx.setStorageSync('primaryRole', role); - wx.setStorageSync('currentRole', role); - app.globalData.primaryRole = role; - app.globalData.currentRole = role; - if (app.emitEvent) { - app.emitEvent('currentRoleChanged', { role }); - } -} - -/** TabBar / IM 使用的有效角色(仅三端) */ -export function getTabRole(app) { - return getPrimaryRole(app); -} - -export function clearPrimaryRole(app) { - app = app || getApp(); - wx.removeStorageSync('primaryRole'); - lockPrimaryRole('normal', app); -} - -export const PRIMARY_DEFAULT_PAGES = { - normal: '/pages/wode/wode', - dashou: '/pages/jiedan/jiedan', - shangjia: '/pages/sjdingdan/sjdingdan', -}; - -/** 锁定主端并跳转到该端默认首页,同时建立 IM 长连接 */ -export function enterLockedRole(role, app) { - if (!VALID.includes(role) || role === 'normal') return false; - app = app || getApp(); - lockPrimaryRole(role, app); - wx.reLaunch({ url: PRIMARY_DEFAULT_PAGES[role] }); - setTimeout(() => { - if (app.switchRoleAndReconnect) { - app.switchRoleAndReconnect(role).catch(() => { - if (app.connectForCurrentRole) app.connectForCurrentRole(); - }); - } else if (app.connectForCurrentRole) { - app.connectForCurrentRole(); - } - }, 600); - return true; -} +/** 三端固定:normal | dashou | shangjia,认证后不可回退 */ + +const VALID = ['normal', 'dashou', 'shangjia']; +const LEGACY_CENTER_ROLES = ['guanshi', 'zuzhang', 'kaoheguan']; + +/** 旧版管事/组长/考核官主端标识 → 统一回落打手 Tab */ +export function migrateLegacyCenterRole(app) { + app = app || getApp(); + const cur = wx.getStorageSync('currentRole') || app.globalData.currentRole || ''; + const pri = wx.getStorageSync('primaryRole') || ''; + const isLegacy = LEGACY_CENTER_ROLES.includes(cur) || LEGACY_CENTER_ROLES.includes(pri); + if (!isLegacy) return false; + + const hasDashouSide = + isRoleStatusActive(wx.getStorageSync('dashoustatus')) + || isRoleStatusActive(wx.getStorageSync('guanshistatus')) + || isRoleStatusActive(wx.getStorageSync('zuzhangstatus')) + || isRoleStatusActive(wx.getStorageSync('kaoheguanstatus')); + + if (hasDashouSide) { + lockPrimaryRole('dashou', app); + return true; + } + return false; +} + +export function isRoleStatusActive(status) { + return Number(status) === 1; +} + +/** 读取主端(兼容旧 currentRole / 管事组长落地页) */ +export function getPrimaryRole(app) { + app = app || getApp(); + const stored = wx.getStorageSync('primaryRole'); + if (VALID.includes(stored)) { + return stored; + } + const legacy = wx.getStorageSync('currentRole') || app.globalData.currentRole || 'normal'; + if (legacy === 'dashou' || legacy === 'shangjia') { + return legacy; + } + if (legacy === 'guanshi' || legacy === 'zuzhang' || legacy === 'kaoheguan') { + if (isRoleStatusActive(wx.getStorageSync('dashoustatus'))) { + return 'dashou'; + } + if (isRoleStatusActive(wx.getStorageSync('shangjiastatus'))) { + return 'shangjia'; + } + } + if (isRoleStatusActive(wx.getStorageSync('dashoustatus'))) { + return 'dashou'; + } + if (isRoleStatusActive(wx.getStorageSync('shangjiastatus'))) { + return 'shangjia'; + } + return 'normal'; +} + +/** 锁定主端并同步 TabBar 角色 */ +export function lockPrimaryRole(role, app) { + if (!VALID.includes(role)) return; + app = app || getApp(); + wx.setStorageSync('primaryRole', role); + wx.setStorageSync('currentRole', role); + app.globalData.primaryRole = role; + app.globalData.currentRole = role; + if (app.emitEvent) { + app.emitEvent('currentRoleChanged', { role }); + } +} + +/** TabBar / IM 使用的有效角色(仅三端) */ +export function getTabRole(app) { + return getPrimaryRole(app); +} + +export function clearPrimaryRole(app) { + app = app || getApp(); + wx.removeStorageSync('primaryRole'); + lockPrimaryRole('normal', app); +} + +export const PRIMARY_DEFAULT_PAGES = { + normal: '/pages/mine/mine', + dashou: '/pages/accept-order/accept-order', + shangjia: '/pages/merchant-orders/merchant-orders', +}; + +/** 锁定主端并跳转到该端默认首页,同时建立 IM 长连接 */ +export function enterLockedRole(role, app) { + if (!VALID.includes(role) || role === 'normal') return false; + app = app || getApp(); + lockPrimaryRole(role, app); + wx.reLaunch({ url: PRIMARY_DEFAULT_PAGES[role] }); + setTimeout(() => { + if (app.switchRoleAndReconnect) { + app.switchRoleAndReconnect(role).catch(() => { + if (app.connectForCurrentRole) app.connectForCurrentRole(); + }); + } else if (app.connectForCurrentRole) { + app.connectForCurrentRole(); + } + }, 600); + return true; +} diff --git a/utils/request.js b/utils/request.js index 4ea5e72..1c87956 100644 --- a/utils/request.js +++ b/utils/request.js @@ -1,74 +1,74 @@ -// utils/request.js -const app = getApp(); - -function request(options) { - const token = wx.getStorageSync('token'); - - // 🔥 没有 token 时不发送请求,直接返回一个“空响应”对象,不影响后续代码 - if (!token) { - // 返回一个模拟的响应,状态码为 401,但不会触发任何弹窗或跳转 - return Promise.resolve({ - statusCode: 401, - data: { code: 401, msg: '未登录' }, - errMsg: 'request:ok' - }); - } - - const header = { - 'Content-Type': 'application/json', - ...options.header, - }; - if (token) { - header['Authorization'] = 'Bearer ' + token; - } - - return new Promise((resolve, reject) => { - wx.request({ - url: app.globalData.apiBaseUrl + options.url, - method: options.method, - data: options.data || {}, - header, - success: async (res) => { - if (res.statusCode === 401 || res.statusCode === 403) { - // 注意:这里的弹窗逻辑只会在有 token 且 token 失效时触发 - // 无 token 的情况已经在上面直接返回,不会走到这里 - if (app.globalData.loginPromise) { - try { - await app.globalData.loginPromise; - const retryRes = await request(options); - resolve(retryRes); - } catch (err) { - wx.showModal({ - content: '操作失败,请先登录', - success: (modalRes) => { - if (modalRes.confirm) { - wx.removeStorageSync('token'); - wx.switchTab({ url: '/pages/wode/wode' }); - } - }, - }); - resolve(res); - } - return; - } - - wx.showModal({ - content: '操作失败,请先登录', - success: (modalRes) => { - if (modalRes.confirm) { - wx.removeStorageSync('token'); - wx.reLaunch({ url: '/pages/wode/wode' }); - } - }, - }); - resolve(res); - return; - } - resolve(res); - }, - fail: reject, - }); - }); -} - +// utils/request.js +const app = getApp(); + +function request(options) { + const token = wx.getStorageSync('token'); + + // 🔥 没有 token 时不发送请求,直接返回一个“空响应”对象,不影响后续代码 + if (!token) { + // 返回一个模拟的响应,状态码为 401,但不会触发任何弹窗或跳转 + return Promise.resolve({ + statusCode: 401, + data: { code: 401, msg: '未登录' }, + errMsg: 'request:ok' + }); + } + + const header = { + 'Content-Type': 'application/json', + ...options.header, + }; + if (token) { + header['Authorization'] = 'Bearer ' + token; + } + + return new Promise((resolve, reject) => { + wx.request({ + url: app.globalData.apiBaseUrl + options.url, + method: options.method, + data: options.data || {}, + header, + success: async (res) => { + if (res.statusCode === 401 || res.statusCode === 403) { + // 注意:这里的弹窗逻辑只会在有 token 且 token 失效时触发 + // 无 token 的情况已经在上面直接返回,不会走到这里 + if (app.globalData.loginPromise) { + try { + await app.globalData.loginPromise; + const retryRes = await request(options); + resolve(retryRes); + } catch (err) { + wx.showModal({ + content: '操作失败,请先登录', + success: (modalRes) => { + if (modalRes.confirm) { + wx.removeStorageSync('token'); + wx.switchTab({ url: '/pages/mine/mine' }); + } + }, + }); + resolve(res); + } + return; + } + + wx.showModal({ + content: '操作失败,请先登录', + success: (modalRes) => { + if (modalRes.confirm) { + wx.removeStorageSync('token'); + wx.reLaunch({ url: '/pages/mine/mine' }); + } + }, + }); + resolve(res); + return; + } + resolve(res); + }, + fail: reject, + }); + }); +} + export default request; \ No newline at end of file diff --git a/utils/role-tab-bar.js b/utils/role-tab-bar.js index d12c9d4..4a19aa0 100644 --- a/utils/role-tab-bar.js +++ b/utils/role-tab-bar.js @@ -1,255 +1,255 @@ -import { clearPrimaryRole } from './primary-role'; -import { getLocalImUserId } from './im-user.js'; -export function isWechatLoginSuccess(body) { - if (!body) return false; - const code = Number(body.code); - return code === 0 || code === 200; -} - -const SESSION_STATUS_KEYS = ['dashoustatus', 'guanshistatus', 'shangjiastatus', 'zuzhangstatus', 'kaoheguanstatus']; - -/** 读取 token(Storage 优先,globalData 兜底并回写 Storage) */ -export function getSessionToken(app) { - app = app || getApp(); - let token = wx.getStorageSync('token') || app.globalData.token || ''; - if (token && !wx.getStorageSync('token')) { - wx.setStorageSync('token', token); - } - return token; -} - -export function isUserLoggedIn(app) { - return !!getSessionToken(app); -} - -/** 从 Storage / globalData 汇总展示用用户信息(兼容其他端注册后 nick 未落盘) */ -export function getUserProfileForDisplay(app) { - app = app || getApp(); - const token = getSessionToken(app); - const uid = wx.getStorageSync('uid') || app.globalData.uid || ''; - let nick = wx.getStorageSync('nicheng') || app.globalData.nicheng || ''; - if (!nick && app.globalData.dashouNicheng) { - nick = app.globalData.dashouNicheng; - } - const tx = wx.getStorageSync('touxiang') || ''; - const def = app.globalData.morentouxiang || ''; - const oss = app.globalData.ossImageUrl || ''; - let avatarUrl = ''; - if (tx) { - avatarUrl = tx.startsWith('http') ? tx : oss + tx; - } else if (def) { - avatarUrl = def.startsWith('http') ? def : oss + def; - } - return { - nick, - uid, - avatarUrl, - isLoggedIn: !!token, - }; -} - -/** 其他端登录/注册成功后,把 globalData 里已有字段补写回 Storage */ -export function backfillUserProfileCache(app) { - app = app || getApp(); - if (!isUserLoggedIn()) return; - const profile = getUserProfileForDisplay(app); - if (profile.nick && !wx.getStorageSync('nicheng')) { - wx.setStorageSync('nicheng', profile.nick); - app.globalData.nicheng = profile.nick; - } - if (profile.uid && !wx.getStorageSync('uid')) { - wx.setStorageSync('uid', profile.uid); - } -} - -export function applyWechatLoginData(data, page) { - if (!data || typeof data !== 'object') return; - const app = getApp(); - syncProfileFields(data); - if (data.token) { - wx.setStorageSync('token', data.token); - } - syncRoleStatuses(data); - syncGroupFields(data); - if (data.zuzhangstatus !== undefined) { - wx.setStorageSync('zuzhangstatus', data.zuzhangstatus); - app.globalData.zuzhangstatus = data.zuzhangstatus; - } - if (data.kaoheguanstatus !== undefined) { - wx.setStorageSync('kaoheguanstatus', data.kaoheguanstatus); - app.globalData.kaoheguanstatus = data.kaoheguanstatus; - } - if (data.dingdantiaoshu) { - app.globalData.dingdanTiaoshu = { - daifuwu: data.dingdantiaoshu.daifuwu || 0, - fuwuzhong: data.dingdantiaoshu.fuwuzhong || 0, - yiwancheng: data.dingdantiaoshu.yiwancheng || 0, - yituikuan: data.dingdantiaoshu.yituikuan || 0, - }; - } - if (data.isJinpai !== undefined) { - wx.setStorageSync('isJinpai', Number(data.isJinpai)); - } - - const targetPage = page || _getCurrentPage(); - refreshTabBar(targetPage); -} - -function _getCurrentPage() { - const pages = getCurrentPages(); - return pages.length ? pages[pages.length - 1] : null; -} - -export function isRoleStatusActive(status) { - return Number(status) === 1; -} - -export function isCenterPageActive(page, dataFlag, statusKey) { - return page.data[dataFlag] || isRoleStatusActive(wx.getStorageSync(statusKey)); -} - -export function syncRoleStatuses(data) { - if (!data || typeof data !== 'object') return; - const app = getApp(); - const roleFields = ['dashoustatus', 'guanshistatus', 'shangjiastatus', 'zuzhangstatus', 'kaoheguanstatus']; - roleFields.forEach((field) => { - if (Object.prototype.hasOwnProperty.call(data, field)) { - const val = Number(data[field]); - const normalized = Number.isNaN(val) ? 0 : val; - wx.setStorageSync(field, normalized); - app.globalData[field] = normalized; - } - }); -} - -export function syncProfileFields(data) { - if (!data || typeof data !== 'object') return; - const app = getApp(); - ['nicheng', 'uid', 'touxiang', 'token'].forEach((field) => { - if (data[field] !== undefined && data[field] !== null) { - wx.setStorageSync(field, data[field]); - app.globalData[field] = data[field]; - } - }); -} - -/** 清除缓存:清空登录与身份,回到点单端「我的」 */ -export function clearCacheAndEnterNormal(page) { - resetGuestSession(page, { skipPageReset: true }); - wx.reLaunch({ url: '/pages/wode/wode' }); -} - -/** 清除缓存并重置为点单端(不跳转,供当前已在点单端时使用) */ -export function resetGuestSession(page, options = {}) { - const app = getApp(); - const configKey = app.CONFIG_CACHE_KEY || 'app_dynamic_config'; - let configCache = null; - try { - configCache = wx.getStorageSync(configKey); - } catch (e) {} - - wx.clearStorageSync(); - - if (configCache && typeof configCache === 'object') { - wx.setStorageSync(configKey, configCache); - } - - clearPrimaryRole(app); - app.globalData.token = ''; - app.globalData.nicheng = ''; - app.globalData.uid = ''; - app.globalData.loginPromise = null; - app.globalData.currentUser = null; - app.globalData.dashouNicheng = ''; - app.globalData.dingdanTiaoshu = { daifuwu: 0, fuwuzhong: 0, yiwancheng: 0, yituikuan: 0 }; - app.globalData.dashouqun = ''; - app.globalData.dashouqunid = ''; - app.globalData.guanshiqun = ''; - app.globalData.guanshiqunid = ''; - SESSION_STATUS_KEYS.forEach((key) => { - app.globalData[key] = 0; - }); - app.globalData.shangpinleixing = []; - app.globalData.shangpinzhuanqu = []; - app.globalData.shangpinliebiao = []; - - app.emitEvent('currentRoleChanged', { role: 'normal' }); - refreshTabBar(page); - - if (!options.skipPageReset && page && page.setData) { - page.setData({ - avatarUrl: '', - userNicheng: '', - userUid: '', - showLoginBtn: true, - orderCounts: { daifuwu: 0, fuwuzhong: 0, yiwancheng: 0, yituikuan: 0 }, - dashouCertified: false, - shangjiaCertified: false, - }); - } -} - -export function syncGroupFields(data) { - if (!data || typeof data !== 'object') return; - const app = getApp(); - ['dashouqun', 'dashouqunid', 'guanshiqun', 'guanshiqunid'].forEach((field) => { - if (data[field] !== undefined) { - wx.setStorageSync(field, data[field]); - app.globalData[field] = data[field]; - } - }); -} - -export function refreshTabBar(page) { - const tryRefresh = () => { - const tabBar = page.getTabBar && page.getTabBar(); - if (tabBar && tabBar.refresh) tabBar.refresh(); - }; - tryRefresh(); - [50, 150, 300, 500, 800].forEach((delay) => setTimeout(tryRefresh, delay)); -} - -export function setRoleAndRefreshTabBar(page, role) { - const app = getApp(); - if (app.setCurrentRole) { - app.setCurrentRole(role); - } else { - app.globalData.currentRole = role; - wx.setStorageSync('currentRole', role); - app.emitEvent('currentRoleChanged', { role }); - } - refreshTabBar(page); -} - -export function reconnectForRole(role) { - const app = getApp(); - if (!wx.getStorageSync('uid')) return; - - const targetUserId = getLocalImUserId(app); - if (!targetUserId) return; - - const status = wx.goEasy?.getConnectionStatus?.() || 'disconnected'; - const currentUserId = wx.goEasy?.im?.userId || ''; - const connected = status === 'connected' || status === 'reconnected'; - - if (connected && currentUserId === targetUserId) { - if (app.loadConversations) app.loadConversations(); - if (app.ensureConnection) app.ensureConnection(); - return; - } - - if (app.switchRoleAndReconnect) { - app.switchRoleAndReconnect(role).catch(() => { - if (app.ensureConnection) app.ensureConnection(); - }); - } else if (app.connectForCurrentRole) { - app.connectForCurrentRole(); - } else if (app.ensureConnection) { - app.ensureConnection(); - } -} - -export function ensureRoleOnCenterPage(page, role) { - setRoleAndRefreshTabBar(page, role); - reconnectForRole(role); -} +import { clearPrimaryRole } from './primary-role'; +import { getLocalImUserId } from './im-user.js'; +export function isWechatLoginSuccess(body) { + if (!body) return false; + const code = Number(body.code); + return code === 0 || code === 200; +} + +const SESSION_STATUS_KEYS = ['dashoustatus', 'guanshistatus', 'shangjiastatus', 'zuzhangstatus', 'kaoheguanstatus']; + +/** 读取 token(Storage 优先,globalData 兜底并回写 Storage) */ +export function getSessionToken(app) { + app = app || getApp(); + let token = wx.getStorageSync('token') || app.globalData.token || ''; + if (token && !wx.getStorageSync('token')) { + wx.setStorageSync('token', token); + } + return token; +} + +export function isUserLoggedIn(app) { + return !!getSessionToken(app); +} + +/** 从 Storage / globalData 汇总展示用用户信息(兼容其他端注册后 nick 未落盘) */ +export function getUserProfileForDisplay(app) { + app = app || getApp(); + const token = getSessionToken(app); + const uid = wx.getStorageSync('uid') || app.globalData.uid || ''; + let nick = wx.getStorageSync('nicheng') || app.globalData.nicheng || ''; + if (!nick && app.globalData.dashouNicheng) { + nick = app.globalData.dashouNicheng; + } + const tx = wx.getStorageSync('touxiang') || ''; + const def = app.globalData.morentouxiang || ''; + const oss = app.globalData.ossImageUrl || ''; + let avatarUrl = ''; + if (tx) { + avatarUrl = tx.startsWith('http') ? tx : oss + tx; + } else if (def) { + avatarUrl = def.startsWith('http') ? def : oss + def; + } + return { + nick, + uid, + avatarUrl, + isLoggedIn: !!token, + }; +} + +/** 其他端登录/注册成功后,把 globalData 里已有字段补写回 Storage */ +export function backfillUserProfileCache(app) { + app = app || getApp(); + if (!isUserLoggedIn()) return; + const profile = getUserProfileForDisplay(app); + if (profile.nick && !wx.getStorageSync('nicheng')) { + wx.setStorageSync('nicheng', profile.nick); + app.globalData.nicheng = profile.nick; + } + if (profile.uid && !wx.getStorageSync('uid')) { + wx.setStorageSync('uid', profile.uid); + } +} + +export function applyWechatLoginData(data, page) { + if (!data || typeof data !== 'object') return; + const app = getApp(); + syncProfileFields(data); + if (data.token) { + wx.setStorageSync('token', data.token); + } + syncRoleStatuses(data); + syncGroupFields(data); + if (data.zuzhangstatus !== undefined) { + wx.setStorageSync('zuzhangstatus', data.zuzhangstatus); + app.globalData.zuzhangstatus = data.zuzhangstatus; + } + if (data.kaoheguanstatus !== undefined) { + wx.setStorageSync('kaoheguanstatus', data.kaoheguanstatus); + app.globalData.kaoheguanstatus = data.kaoheguanstatus; + } + if (data.dingdantiaoshu) { + app.globalData.dingdanTiaoshu = { + daifuwu: data.dingdantiaoshu.daifuwu || 0, + fuwuzhong: data.dingdantiaoshu.fuwuzhong || 0, + yiwancheng: data.dingdantiaoshu.yiwancheng || 0, + yituikuan: data.dingdantiaoshu.yituikuan || 0, + }; + } + if (data.isJinpai !== undefined) { + wx.setStorageSync('isJinpai', Number(data.isJinpai)); + } + + const targetPage = page || _getCurrentPage(); + refreshTabBar(targetPage); +} + +function _getCurrentPage() { + const pages = getCurrentPages(); + return pages.length ? pages[pages.length - 1] : null; +} + +export function isRoleStatusActive(status) { + return Number(status) === 1; +} + +export function isCenterPageActive(page, dataFlag, statusKey) { + return page.data[dataFlag] || isRoleStatusActive(wx.getStorageSync(statusKey)); +} + +export function syncRoleStatuses(data) { + if (!data || typeof data !== 'object') return; + const app = getApp(); + const roleFields = ['dashoustatus', 'guanshistatus', 'shangjiastatus', 'zuzhangstatus', 'kaoheguanstatus']; + roleFields.forEach((field) => { + if (Object.prototype.hasOwnProperty.call(data, field)) { + const val = Number(data[field]); + const normalized = Number.isNaN(val) ? 0 : val; + wx.setStorageSync(field, normalized); + app.globalData[field] = normalized; + } + }); +} + +export function syncProfileFields(data) { + if (!data || typeof data !== 'object') return; + const app = getApp(); + ['nicheng', 'uid', 'touxiang', 'token'].forEach((field) => { + if (data[field] !== undefined && data[field] !== null) { + wx.setStorageSync(field, data[field]); + app.globalData[field] = data[field]; + } + }); +} + +/** 清除缓存:清空登录与身份,回到点单端「我的」 */ +export function clearCacheAndEnterNormal(page) { + resetGuestSession(page, { skipPageReset: true }); + wx.reLaunch({ url: '/pages/mine/mine' }); +} + +/** 清除缓存并重置为点单端(不跳转,供当前已在点单端时使用) */ +export function resetGuestSession(page, options = {}) { + const app = getApp(); + const configKey = app.CONFIG_CACHE_KEY || 'app_dynamic_config'; + let configCache = null; + try { + configCache = wx.getStorageSync(configKey); + } catch (e) {} + + wx.clearStorageSync(); + + if (configCache && typeof configCache === 'object') { + wx.setStorageSync(configKey, configCache); + } + + clearPrimaryRole(app); + app.globalData.token = ''; + app.globalData.nicheng = ''; + app.globalData.uid = ''; + app.globalData.loginPromise = null; + app.globalData.currentUser = null; + app.globalData.dashouNicheng = ''; + app.globalData.dingdanTiaoshu = { daifuwu: 0, fuwuzhong: 0, yiwancheng: 0, yituikuan: 0 }; + app.globalData.dashouqun = ''; + app.globalData.dashouqunid = ''; + app.globalData.guanshiqun = ''; + app.globalData.guanshiqunid = ''; + SESSION_STATUS_KEYS.forEach((key) => { + app.globalData[key] = 0; + }); + app.globalData.shangpinleixing = []; + app.globalData.shangpinzhuanqu = []; + app.globalData.shangpinliebiao = []; + + app.emitEvent('currentRoleChanged', { role: 'normal' }); + refreshTabBar(page); + + if (!options.skipPageReset && page && page.setData) { + page.setData({ + avatarUrl: '', + userNicheng: '', + userUid: '', + showLoginBtn: true, + orderCounts: { daifuwu: 0, fuwuzhong: 0, yiwancheng: 0, yituikuan: 0 }, + dashouCertified: false, + shangjiaCertified: false, + }); + } +} + +export function syncGroupFields(data) { + if (!data || typeof data !== 'object') return; + const app = getApp(); + ['dashouqun', 'dashouqunid', 'guanshiqun', 'guanshiqunid'].forEach((field) => { + if (data[field] !== undefined) { + wx.setStorageSync(field, data[field]); + app.globalData[field] = data[field]; + } + }); +} + +export function refreshTabBar(page) { + const tryRefresh = () => { + const tabBar = page.getTabBar && page.getTabBar(); + if (tabBar && tabBar.refresh) tabBar.refresh(); + }; + tryRefresh(); + [50, 150, 300, 500, 800].forEach((delay) => setTimeout(tryRefresh, delay)); +} + +export function setRoleAndRefreshTabBar(page, role) { + const app = getApp(); + if (app.setCurrentRole) { + app.setCurrentRole(role); + } else { + app.globalData.currentRole = role; + wx.setStorageSync('currentRole', role); + app.emitEvent('currentRoleChanged', { role }); + } + refreshTabBar(page); +} + +export function reconnectForRole(role) { + const app = getApp(); + if (!wx.getStorageSync('uid')) return; + + const targetUserId = getLocalImUserId(app); + if (!targetUserId) return; + + const status = wx.goEasy?.getConnectionStatus?.() || 'disconnected'; + const currentUserId = wx.goEasy?.im?.userId || ''; + const connected = status === 'connected' || status === 'reconnected'; + + if (connected && currentUserId === targetUserId) { + if (app.loadConversations) app.loadConversations(); + if (app.ensureConnection) app.ensureConnection(); + return; + } + + if (app.switchRoleAndReconnect) { + app.switchRoleAndReconnect(role).catch(() => { + if (app.ensureConnection) app.ensureConnection(); + }); + } else if (app.connectForCurrentRole) { + app.connectForCurrentRole(); + } else if (app.ensureConnection) { + app.ensureConnection(); + } +} + +export function ensureRoleOnCenterPage(page, role) { + setRoleAndRefreshTabBar(page, role); + reconnectForRole(role); +} diff --git a/utils/xiaoxilj.js b/utils/xiaoxilj.js index dcf8b60..9e3282e 100644 --- a/utils/xiaoxilj.js +++ b/utils/xiaoxilj.js @@ -1,215 +1,215 @@ -/** - * 连接管理模块 - xiaoxilj.js (根治发送失败:跳转前确保群组已订阅) - * 从详情页跳转订单群聊时,提前订阅群组,避免发送消息时订阅未完成而失败 - */ -const app = getApp(); - -function waitForConnection(expectedUserId, timeout = 10000) { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - app.off('connectionChanged', handler); - reject(new Error('连接超时')); - }, timeout); - - const handler = (event) => { - if (event.status === 'connected') { - if (event.userId === expectedUserId) { - clearTimeout(timer); - app.off('connectionChanged', handler); - resolve(); - } else { - console.error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`); - wx.removeStorageSync('savedGoEasyConnection'); - wx.removeStorageSync('goEasyUserId'); - wx.removeStorageSync('currentGoEasyIdentity'); - if (app.clearSavedConnection) app.clearSavedConnection(); - clearTimeout(timer); - app.off('connectionChanged', handler); - reject(new Error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`)); - } - } else if (event.status === 'disconnected' && !event.manual) { - wx.removeStorageSync('savedGoEasyConnection'); - wx.removeStorageSync('goEasyUserId'); - wx.removeStorageSync('currentGoEasyIdentity'); - if (app.clearSavedConnection) app.clearSavedConnection(); - clearTimeout(timer); - app.off('connectionChanged', handler); - reject(new Error('连接失败')); - } - }; - app.on('connectionChanged', handler); - }); -} - -class ConnectionManager { - // 原有的私聊方法保持不变 - async connectAndChat(params) { - const { identityType, userId, targetUser } = params; - if (!identityType || !userId || !targetUser || !targetUser.id) { - throw new Error('参数不完整'); - } - - if (identityType === 'dashou' && !userId.startsWith('Ds')) { - throw new Error(`打手身份的用户ID必须以Ds开头,实际为 ${userId}`); - } - if (identityType === 'shangjia' && !userId.startsWith('Sj')) { - throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`); - } - if (identityType === 'boss' && !userId.startsWith('Boss')) { - throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`); - } - - wx.removeStorageSync('savedGoEasyConnection'); - wx.removeStorageSync('goEasyUserId'); - wx.removeStorageSync('currentGoEasyIdentity'); - if (app.clearSavedConnection) app.clearSavedConnection(); - - if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') { - wx.goEasy.disconnect(); - } - - const waitPromise = waitForConnection(userId); - app.connectWithIdentity(identityType, userId, false); - - try { - await waitPromise; - - const currentUser = { - id: userId, - name: app.globalData.currentUser?.name || '用户', - avatar: app.globalData.currentUser?.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang) - }; - - const to = { - id: targetUser.id, - name: targetUser.name || '用户', - avatar: targetUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang) - }; - - const param = { to, currentUser }; - const path = '/pages/liaotian/liaotian?data=' + encodeURIComponent(JSON.stringify(param)); - wx.navigateTo({ url: path }); - } catch (err) { - console.error('连接失败:', err); - wx.showToast({ title: err.message || '连接失败', icon: 'none' }); - throw err; - } - } - - async connectToGroupChat(params) { - const { identityType, userId, orderId, groupName, groupAvatar, isCross } = params; - if (!identityType || !userId || !orderId) { - throw new Error('参数不完整:identityType, userId, orderId 必填'); - } - - // 校验 userId 前缀 - if (identityType === 'dashou' && !userId.startsWith('Ds')) { - throw new Error(`打手身份的用户ID必须以Ds开头,实际为 ${userId}`); - } - if (identityType === 'shangjia' && !userId.startsWith('Sj')) { - throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`); - } - if (identityType === 'boss' && !userId.startsWith('Boss')) { - throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`); - } - - - // 1. 同步全局角色,确保群聊页初始化正确 - app.globalData.currentRole = identityType; - wx.setStorageSync('currentRole', identityType); - - const uid = userId.replace(/^(Ds|Sj|Boss|Gs|Zz)/, ''); - const avatar = wx.getStorageSync('touxiang') || - (app.globalData.ossImageUrl + app.globalData.morentouxiang); - app.globalData.currentUser = { - id: userId, - name: app.globalData.currentUser?.name || `用户${uid}`, - avatar: avatar - }; - - // 2. 确保 GoEasy 已使用目标身份连接 - let needConnect = false; - if (!wx.goEasy || !wx.goEasy.getConnectionStatus || wx.goEasy.getConnectionStatus() !== 'connected') { - needConnect = true; - } else { - const currentUserId = wx.goEasy.im?.userId; - if (currentUserId !== userId) { - needConnect = true; - } - } - - if (needConnect) { - wx.removeStorageSync('savedGoEasyConnection'); - wx.removeStorageSync('goEasyUserId'); - if (app.clearSavedConnection) app.clearSavedConnection(); - if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') { - wx.goEasy.disconnect(); - } - const waitPromise = waitForConnection(userId); - app.connectWithIdentity(identityType, userId, false); - try { - await waitPromise; - } catch (err) { - wx.showToast({ title: '连接失败', icon: 'none' }); - throw err; - } - } - - // 3. 从会话列表查找真实群组ID - let realGroupId = null; - try { - const result = await new Promise((resolve, reject) => { - wx.goEasy.im.latestConversations({ - onSuccess: (res) => { - const conversations = res.content?.conversations || []; - const found = conversations.find(c => c.type === 'group' && c.data && c.data.orderId === orderId); - resolve(found ? found.groupId : null); - }, - onFailed: reject - }); - }); - realGroupId = result; - } catch (err) { - console.error('获取会话列表失败:', err); - wx.showToast({ title: '获取群聊信息失败', icon: 'none' }); - throw err; - } - - if (!realGroupId) { - wx.showToast({ title: '暂未创建群聊', icon: 'none' }); - return; - } - - // 4. 🔥 关键:主动订阅群组并等待成功,确保发送消息时订阅已完成 - try { - await new Promise((resolve, reject) => { - wx.goEasy.im.subscribeGroup({ - groupIds: [realGroupId], - onSuccess: () => { - resolve(); - }, - onFailed: (error) => { - console.error('订阅群组失败:', error); - reject(error); - } - }); - }); - } catch (err) { - wx.showToast({ title: '订阅群组失败', icon: 'none' }); - throw err; - } - - // 5. 跳转群聊页(参数与消息列表完全一致) - const param = { - groupId: realGroupId, - orderId: orderId, - groupName: groupName || '订单群聊', - groupAvatar: groupAvatar || '', - isCross: isCross || 0 - }; - const path = '/pages/qunliaotian/qunliaotian?data=' + encodeURIComponent(JSON.stringify(param)); - wx.navigateTo({ url: path }); - } -} - +/** + * 连接管理模块 - xiaoxilj.js (根治发送失败:跳转前确保群组已订阅) + * 从详情页跳转订单群聊时,提前订阅群组,避免发送消息时订阅未完成而失败 + */ +const app = getApp(); + +function waitForConnection(expectedUserId, timeout = 10000) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + app.off('connectionChanged', handler); + reject(new Error('连接超时')); + }, timeout); + + const handler = (event) => { + if (event.status === 'connected') { + if (event.userId === expectedUserId) { + clearTimeout(timer); + app.off('connectionChanged', handler); + resolve(); + } else { + console.error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`); + wx.removeStorageSync('savedGoEasyConnection'); + wx.removeStorageSync('goEasyUserId'); + wx.removeStorageSync('currentGoEasyIdentity'); + if (app.clearSavedConnection) app.clearSavedConnection(); + clearTimeout(timer); + app.off('connectionChanged', handler); + reject(new Error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`)); + } + } else if (event.status === 'disconnected' && !event.manual) { + wx.removeStorageSync('savedGoEasyConnection'); + wx.removeStorageSync('goEasyUserId'); + wx.removeStorageSync('currentGoEasyIdentity'); + if (app.clearSavedConnection) app.clearSavedConnection(); + clearTimeout(timer); + app.off('connectionChanged', handler); + reject(new Error('连接失败')); + } + }; + app.on('connectionChanged', handler); + }); +} + +class ConnectionManager { + // 原有的私聊方法保持不变 + async connectAndChat(params) { + const { identityType, userId, targetUser } = params; + if (!identityType || !userId || !targetUser || !targetUser.id) { + throw new Error('参数不完整'); + } + + if (identityType === 'dashou' && !userId.startsWith('Ds')) { + throw new Error(`打手身份的用户ID必须以Ds开头,实际为 ${userId}`); + } + if (identityType === 'shangjia' && !userId.startsWith('Sj')) { + throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`); + } + if (identityType === 'boss' && !userId.startsWith('Boss')) { + throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`); + } + + wx.removeStorageSync('savedGoEasyConnection'); + wx.removeStorageSync('goEasyUserId'); + wx.removeStorageSync('currentGoEasyIdentity'); + if (app.clearSavedConnection) app.clearSavedConnection(); + + if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') { + wx.goEasy.disconnect(); + } + + const waitPromise = waitForConnection(userId); + app.connectWithIdentity(identityType, userId, false); + + try { + await waitPromise; + + const currentUser = { + id: userId, + name: app.globalData.currentUser?.name || '用户', + avatar: app.globalData.currentUser?.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang) + }; + + const to = { + id: targetUser.id, + name: targetUser.name || '用户', + avatar: targetUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang) + }; + + const param = { to, currentUser }; + const path = '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)); + wx.navigateTo({ url: path }); + } catch (err) { + console.error('连接失败:', err); + wx.showToast({ title: err.message || '连接失败', icon: 'none' }); + throw err; + } + } + + async connectToGroupChat(params) { + const { identityType, userId, orderId, groupName, groupAvatar, isCross } = params; + if (!identityType || !userId || !orderId) { + throw new Error('参数不完整:identityType, userId, orderId 必填'); + } + + // 校验 userId 前缀 + if (identityType === 'dashou' && !userId.startsWith('Ds')) { + throw new Error(`打手身份的用户ID必须以Ds开头,实际为 ${userId}`); + } + if (identityType === 'shangjia' && !userId.startsWith('Sj')) { + throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`); + } + if (identityType === 'boss' && !userId.startsWith('Boss')) { + throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`); + } + + + // 1. 同步全局角色,确保群聊页初始化正确 + app.globalData.currentRole = identityType; + wx.setStorageSync('currentRole', identityType); + + const uid = userId.replace(/^(Ds|Sj|Boss|Gs|Zz)/, ''); + const avatar = wx.getStorageSync('touxiang') || + (app.globalData.ossImageUrl + app.globalData.morentouxiang); + app.globalData.currentUser = { + id: userId, + name: app.globalData.currentUser?.name || `用户${uid}`, + avatar: avatar + }; + + // 2. 确保 GoEasy 已使用目标身份连接 + let needConnect = false; + if (!wx.goEasy || !wx.goEasy.getConnectionStatus || wx.goEasy.getConnectionStatus() !== 'connected') { + needConnect = true; + } else { + const currentUserId = wx.goEasy.im?.userId; + if (currentUserId !== userId) { + needConnect = true; + } + } + + if (needConnect) { + wx.removeStorageSync('savedGoEasyConnection'); + wx.removeStorageSync('goEasyUserId'); + if (app.clearSavedConnection) app.clearSavedConnection(); + if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') { + wx.goEasy.disconnect(); + } + const waitPromise = waitForConnection(userId); + app.connectWithIdentity(identityType, userId, false); + try { + await waitPromise; + } catch (err) { + wx.showToast({ title: '连接失败', icon: 'none' }); + throw err; + } + } + + // 3. 从会话列表查找真实群组ID + let realGroupId = null; + try { + const result = await new Promise((resolve, reject) => { + wx.goEasy.im.latestConversations({ + onSuccess: (res) => { + const conversations = res.content?.conversations || []; + const found = conversations.find(c => c.type === 'group' && c.data && c.data.orderId === orderId); + resolve(found ? found.groupId : null); + }, + onFailed: reject + }); + }); + realGroupId = result; + } catch (err) { + console.error('获取会话列表失败:', err); + wx.showToast({ title: '获取群聊信息失败', icon: 'none' }); + throw err; + } + + if (!realGroupId) { + wx.showToast({ title: '暂未创建群聊', icon: 'none' }); + return; + } + + // 4. 🔥 关键:主动订阅群组并等待成功,确保发送消息时订阅已完成 + try { + await new Promise((resolve, reject) => { + wx.goEasy.im.subscribeGroup({ + groupIds: [realGroupId], + onSuccess: () => { + resolve(); + }, + onFailed: (error) => { + console.error('订阅群组失败:', error); + reject(error); + } + }); + }); + } catch (err) { + wx.showToast({ title: '订阅群组失败', icon: 'none' }); + throw err; + } + + // 5. 跳转群聊页(参数与消息列表完全一致) + const param = { + groupId: realGroupId, + orderId: orderId, + groupName: groupName || '订单群聊', + groupAvatar: groupAvatar || '', + isCross: isCross || 0 + }; + const path = '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)); + wx.navigateTo({ url: path }); + } +} + export default new ConnectionManager(); \ No newline at end of file