diff --git a/miniprogram/app.js b/miniprogram/app.js index fb438a9..cd75c7c 100644 --- a/miniprogram/app.js +++ b/miniprogram/app.js @@ -1,29 +1,32 @@ // app.js - 优化生产版本(修复重连机制和用户ID问题) -import GoEasy from './static/lib/goeasy-2.13.24.esm.min'; -const ChatCore = require('./utils/chat-core'); import { check } from './utils/phone-auth'; +// 【聊天总开关】GoEasy 续费/开通后保持 true;未开通时改为 false 避免 SDK 报错 +const IM_SERVICE_ENABLED = true; + // ===== 角色 → 默认首页(与 custom-tab-bar 完全一致) ===== const roleDefaultPage = { normal: '/pages/index/index', - dashou: '/pages/dashouduan/dashouduan', - shangjia: '/pages/shangjiaduan/shangjiaduan', // 商家首页也是商城 + dashou: '/pages/jiedan/jiedan', + shangjia: '/pages/shangjiaduan/shangjiaduan', guanshi: '/pages/guanshiduan/guanshiduan', zuzhang: '/pages/zuzhangduan/zuzhangduan', kaoheguan: '/pages/kaoheguan/kaoheguan' }; +// 【暂时下线】组长/考核官身份已统一迁移为打手 +const DEPRECATED_ROLES = ['zuzhang', 'kaoheguan']; + App({ globalData: { hasShownPopupOnColdStart: false, - apiBaseUrl: 'https://6ccy.top/hqhd', + apiBaseUrl: 'https://wenhe.nmslb.com/hqhd', ossImageUrl: '', morentouxiang: '', dashouguize: '', - paihangAssets: null, shangpinliebiao: [], shangpinzhuanqu: [], @@ -44,7 +47,7 @@ App({ guanshiqun: '', guanshiqunid: '', - appId:'wx2517043ca3f39677', + appId:'wx568f9b618bfa7578', shangjiastatus: 0, dashoustatus: 0, @@ -84,7 +87,8 @@ App({ yueliushui: '' }, - liaotian_liebiao: [], + paihangAssets: null, + pageAssets: null, xshenfen: 1, goEasyConfig: null, @@ -172,59 +176,58 @@ App({ // ========== 仅修改 onLaunch,其余未动 ========== async onLaunch() { - // ---------- ① 立即隐藏“返回首页”按钮 ---------- wx.hideHomeButton(); wx.onAppRoute(() => { wx.hideHomeButton(); }); - // 🆕 手机号认证检查 - - // ---------- ② 恢复角色并跳转(不依赖网络) ---------- + this.initChatStubs(); + + // 冷启动进入商城首页,但保留身份用于 IM(勿把 currentRole 强行改成 normal) const savedRole = wx.getStorageSync('currentRole') || 'normal'; - this.globalData.currentRole = savedRole; + const normalizedRole = this.normalizeRole(savedRole); + this.globalData.currentRole = normalizedRole; + wx.setStorageSync('currentRole', normalizedRole); - const targetPage = roleDefaultPage[savedRole] || '/pages/index/index'; - if (savedRole !== 'normal' || targetPage !== '/pages/index/index') { - setTimeout(() => { - wx.reLaunch({ url: targetPage }); - }, 0); - } + setTimeout(() => { + wx.reLaunch({ url: '/pages/index/index' }); + }, 0); - // ---------- ③ 后台静默获取配置,成功后再初始化 GoEasy/IM ---------- this.fetchDynamicConfig() .then(config => { this.applyDynamicConfig(config); - this.initGoEasyWithConfig(); - ChatCore.initGlobalMessageSystem(this); + if (IM_SERVICE_ENABLED) { + this.initGoEasyWithConfig(); + const ChatCore = require('./utils/chat-core'); + ChatCore.initGlobalMessageSystem(this); + this.bootstrapImListening(); + } this.initCurrentUser(); - this.bootstrapImListening(); }) .catch(error => { console.error('获取动态配置失败:', error); - this.initGoEasyWithConfig(); - ChatCore.initGlobalMessageSystem(this); this.initCurrentUser(); }); - try { - const needAuth = await check(); - if (needAuth) { - wx.reLaunch({ url: '/pages/phone-auth/phone-auth' }); - return; - } - } catch (e) {} + try { + const needAuth = await check(); + if (needAuth) { + wx.reLaunch({ url: '/pages/phone-auth/phone-auth' }); + return; + } + } catch (e) {} }, onShow() { - if (typeof this.ensureConnection === 'function') { + if (this.globalData.chatEnabled && typeof this.ensureConnection === 'function') { this.ensureConnection(); } }, + /** 配置加载完成后立即启动 IM 监听(有 uid 即连) */ bootstrapImListening() { const uid = wx.getStorageSync('uid'); - if (!uid) return; + if (!uid || !this.globalData.chatEnabled) return; try { this.ensureConnection(); } catch (e) { @@ -232,6 +235,26 @@ App({ } }, + initChatStubs() { + this.globalData.chatEnabled = false; + wx.goEasy = null; + this.disconnectGoEasy = () => Promise.resolve(); + this.ensureConnection = () => {}; + this.connectWithIdentity = () => Promise.reject(new Error('聊天未启用')); + this.connectForCurrentRole = () => {}; + this.switchRoleAndReconnect = () => Promise.resolve(false); + this.loadConversations = () => {}; + this.updateUnreadCount = () => {}; + this.getSavedConnection = () => null; + this.clearSavedConnection = () => {}; + this.saveConnectionState = () => {}; + this.handleNewMessage = () => {}; + this.toggleDoNotDisturb = () => {}; + this.toggleNotificationMute = () => {}; + this.closeNotification = () => {}; + this.updateCurrentPageState = () => {}; + }, + @@ -243,6 +266,10 @@ App({ method: 'POST', header: { 'content-type': 'application/json' }, success: (res) => { + if (res.statusCode >= 500) { + reject(new Error('服务器错误 ' + res.statusCode)); + return; + } if (res.statusCode === 200 && res.data && res.data.code === 0) { resolve(res.data.data); } else { @@ -274,6 +301,9 @@ App({ this.globalData.dashouguize = config.otherConfig.dashouguize || ''; this.globalData.paihangAssets = config.otherConfig.paihangAssets || null; } + if (config.pageAssets) { + this.globalData.pageAssets = config.pageAssets; + } if (config.kefu) { this.globalData.kefuConfig = { link: config.kefu.link || '', @@ -283,9 +313,11 @@ App({ }, initGoEasyWithConfig() { + if (!IM_SERVICE_ENABLED) return; + const GoEasy = require('./static/lib/goeasy-2.13.24.esm.min').default; + wx.GoEasy = GoEasy; const cfg = this.globalData.goEasyConfig; if (!cfg || !cfg.appkey) { - console.error('GoEasy appkey 未配置,无法初始化'); this.globalData.chatEnabled = false; return; } @@ -295,7 +327,6 @@ App({ appkey: cfg.appkey, modules: ['im', 'pubsub'] }); - wx.GoEasy = GoEasy; const imReady = !!(wx.goEasy?.im && typeof wx.goEasy.im.on === 'function'); this.globalData.chatEnabled = imReady; if (!imReady) { @@ -307,7 +338,7 @@ App({ wx.goEasy = null; } }, - + initCurrentUser() { const uid = wx.getStorageSync('uid'); if (uid) { @@ -341,5 +372,14 @@ App({ this.globalData.eventListeners[eventName].splice(index, 1); } } + }, + + normalizeRole(role) { + if (DEPRECATED_ROLES.includes(role)) return 'dashou'; + return role || 'normal'; + }, + + getDashouEntryPage() { + return '/pages/jiedan/jiedan'; } }); \ No newline at end of file diff --git a/miniprogram/pages/dashoupaihang/dashoupaihang.js b/miniprogram/pages/dashoupaihang/dashoupaihang.js index 1bf4b2e..de9b858 100644 --- a/miniprogram/pages/dashoupaihang/dashoupaihang.js +++ b/miniprogram/pages/dashoupaihang/dashoupaihang.js @@ -28,43 +28,43 @@ const ROLE_META = { dashou: { title: '打手排行榜', sortField: 'chengjiao_zonge', - sortLabel: '成交总额', + sortLabel: '收益', mainType: 'money', metrics: [ { field: 'jiedan_zongliang', label: '接单量', type: 'int' }, - { field: 'jiedan_zonge', label: '接单额', type: 'money' }, { field: 'chengjiao_zongliang', label: '成交量', type: 'int' }, + { field: 'jiedan_zonge', label: '接单额', type: 'money' }, ], }, guanshi: { title: '管事排行榜', sortField: 'shouru_zonge', - sortLabel: '收入总额', + sortLabel: '收益总额', mainType: 'money', metrics: [ - { field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' }, - { field: 'chongzhi_dashou_shu', label: '充值', type: 'int' }, + { field: 'yaoqing_dashou_shu', label: '邀请人数', type: 'int' }, + { field: 'chongzhi_dashou_shu', label: '充值人数', type: 'int' }, ], }, zuzhang: { title: '组长排行榜', sortField: 'shouru_zonge', - sortLabel: '收入总额', + sortLabel: '收益总额', mainType: 'money', metrics: [ - { field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' }, + { field: 'yaoqing_guanshi_shu', label: '邀请人数', type: 'int' }, { field: 'fenyong_jine', label: '分佣', type: 'money' }, ], }, shangjia: { title: '商家排行榜', - sortField: 'jiesuan_jine', - sortLabel: '成交总额', + sortField: 'paifa_jine', + sortLabel: '流水', mainType: 'money', metrics: [ - { field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' }, { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' }, - { field: 'paifa_jine', label: '派单额', type: 'money' }, + { field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' }, + { field: 'jiesuan_jine', label: '结算额', type: 'money' }, ], }, } @@ -107,14 +107,15 @@ Page({ initPageAssets() { this.syncDefaultAvatar() const g = getApp().globalData + const oss = (g.ossImageUrl || '').replace(/\/$/, '') const assets = g.paihangAssets || {} - const base = (g.ossImageUrl || '') + (assets.basePath || 'beijing/paihangbang/') + const url = (p) => (p ? `${oss}/${String(p).replace(/^\//, '')}` : '') this.setData({ imgUrls: { - pageBg: base + (assets.pageBg || 'page-bg.jpg'), - cardBg: base + (assets.cardBg || 'list-card-bg.png'), - emptyIcon: base + (assets.emptyIcon || 'empty.png'), - refreshIcon: base + (assets.refreshIcon || 'icon-refresh.png'), + pageBg: url(assets.pageBg) || `${oss}/beijing/paihangbang/page-bg.jpg`, + cardBg: url(assets.cardBg) || `${oss}/beijing/paihangbang/list-card-bg.png`, + emptyIcon: url(assets.emptyIcon) || `${oss}/beijing/paihangbang/empty.png`, + refreshIcon: url(assets.refreshIcon) || `${oss}/beijing/paihangbang/icon-refresh.png`, }, }) }, diff --git a/miniprogram/pages/shangjiaduan/shangjiaduan.js b/miniprogram/pages/shangjiaduan/shangjiaduan.js new file mode 100644 index 0000000..47f539f --- /dev/null +++ b/miniprogram/pages/shangjiaduan/shangjiaduan.js @@ -0,0 +1,337 @@ +// pages/shangjiazhongxin/shangjiazhongxin.js +// 🏪 商家中心 - 完全重构版 | 背景图全覆盖 | 称号从商家接口获取 + +import request from '../../utils/request.js'; +import popupService from '../../services/popupService.js'; +import { getDefaultInviteCode } from '../../utils/default-invite-code.js'; + +const app = getApp(); + +Page({ + data: { + // ========== 图片资源 ========== + imgUrls: { + pageBg: '', + avatarCardBg: '', + assetCardBg: '', + statCardBg: '', + funcItemBg: '', + primaryFuncBg: '', + highlightFuncBg: '', + iconRelease: '', + iconFast: '', + iconOrders: '', + iconService: '', + iconPunish: '', + iconRank: '', + iconRecharge: '', + iconWithdraw: '', + iconRefresh: '', + iconCopy: '', + avatarFrame: '', + }, + + // ========== 商家状态 ========== + isShangjia: false, + isLoading: false, + isAutoRegistering: false, + + // ========== 用户基础信息 ========== + uid: '', + avatarUrl: '', + nicheng: '', + + // ========== 商家核心数据 ========== + sjyue: '0.00', + fabu: 0, + tuikuan: 0, + jinriliushui: '0.00', + jinyueliushui: '0.00', + jinridingdan: 0, + jinrituikuan: 0, + chenghaoList: [], // 称号列表(从商家接口获取) + + // ========== 交互控制 ========== + inviteCode: '', + lastRefreshTime: 0, + canRefresh: true, + }, + + onLoad(options) { + this.initImageUrls(); + this.checkShangjiaStatus(); + + const { inviteCode } = options || {}; + if (inviteCode) { + this.setData({ inviteCode }); + setTimeout(() => this.handleInviteCodeWithLoginCheck(inviteCode), 500); + } + + if (!app.globalData.hasShownPopupOnColdStart) { + app.globalData.hasShownPopupOnColdStart = true; + setTimeout(() => popupService.checkAndShow(this, 'shangjiaduan'), 300); + } + }, + + onShow() { + this.registerNotificationComponent(); + if (this.data.isShangjia) { + this.refreshShangjiaInfo(); + } + }, + + onHide() { + const popupComp = this.selectComponent('#popupNotice'); + popupComp?.cleanup?.(); + }, + + // ========== 图片路径初始化 ========== + initImageUrls() { + const ossBase = (app.globalData.ossImageUrl || '').replace(/\/$/, ''); + const cfg = app.globalData.pageAssets?.shangjiaduan || {}; + const url = (key, fallback) => { + const p = cfg[key]; + if (p) return `${ossBase}/${String(p).replace(/^\//, '')}`; + return `${ossBase}/beijing/shangjiaduan/${fallback}`; + }; + this.setData({ + imgUrls: { + pageBg: url('pageBg', 'page_bg.png'), + avatarCardBg: url('avatarCardBg', 'avatar_card_bg.png'), + assetCardBg: url('assetCardBg', 'asset_card_bg.png'), + statCardBg: url('statCardBg', 'stat_card_bg.png'), + funcItemBg: url('funcItemBg', 'func_item_bg.png'), + primaryFuncBg: url('primaryFuncBg', 'primary_func_bg.png'), + highlightFuncBg: url('highlightFuncBg', 'highlight_func_bg.png'), + iconRelease: url('iconRelease', 'icon_release.png'), + iconFast: url('iconFast', 'icon_fast.png'), + iconOrders: url('iconOrders', 'icon_orders.png'), + iconService: url('iconService', 'icon_service.png'), + iconPunish: url('iconPunish', 'icon_punish.png'), + iconRank: url('iconRank', 'icon_rank.png'), + iconRecharge: url('iconRecharge', 'icon_recharge.png'), + iconWithdraw: url('iconWithdraw', 'icon_withdraw.png'), + iconRefresh: url('iconRefresh', 'icon_refresh.png'), + iconCopy: url('iconCopy', 'icon_copy.png'), + avatarFrame: url('avatarFrame', 'avatar_frame.png'), + } + }); + }, + + // ========== 商家状态检查 ========== + checkShangjiaStatus() { + try { + const shangjiastatus = wx.getStorageSync('shangjiastatus'); + const uid = wx.getStorageSync('uid'); + if (shangjiastatus === 1) { + this.setData({ isShangjia: true, uid: uid || '' }); + this.loadAvatar(); + this.getShangjiaInfo(); // 获取完整商家数据(含称号) + } else { + this.setData({ isShangjia: false }); + } + } catch (error) { + console.error('读取商家状态失败', error); + this.setData({ isShangjia: false }); + } + }, + + loadAvatar() { + const { ossImageUrl = '', morentouxiang = 'avatar/default.jpg' } = app.globalData || {}; + const touxiang = wx.getStorageSync('touxiang') || ''; + let avatarUrl = ''; + if (touxiang) { + avatarUrl = ossImageUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang); + } else { + avatarUrl = ossImageUrl + (morentouxiang.startsWith('/') ? morentouxiang : '/' + morentouxiang); + } + this.setData({ avatarUrl }); + }, + + // ========== 获取商家信息(核心接口,包含称号列表)========== + async getShangjiaInfo() { + this.setData({ isLoading: true }); + try { + const res = await request({ url: '/yonghu/shangjiaxinxi', method: 'POST' }); + if (res?.data?.code === 200) { + const data = res.data.data; + // 更新全局缓存 + app.globalData.shangjia = data; + wx.setStorageSync('shangjiastatus', 1); + + // 称号列表:优先使用接口返回的 chenghao_list,若无则空数组 + const chenghaoList = data.chenghao_list || []; + + // ✅ 字段映射:后端返回字段 → 前端 data 字段(只改这里,其他一律不变) + this.setData({ + nicheng: data.nicheng || '', // 商家昵称(后端如有则显示) + sjyue: data.sjyue || '0.00', // 商家余额 + fabu: data.fadanzong || 0, // 发单总量(后端 fadanzong) + tuikuan: data.tuikuanzong || 0, // 退款总量(后端 tuikuanzong) + jinriliushui: data.riliushui || '0.00', // 今日流水(后端 riliushui) + jinyueliushui: data.yueliushui || '0.00', // 今月流水(后端 yueliushui) + jinridingdan: data.jinripaidan || 0, // 今日派单数(后端 jinripaidan) + jinrituikuan: data.jinrituikuan || 0, // 今日退款数(后端 jinrituikuan) + chenghaoList: chenghaoList, + isLoading: false, + }); + + if (this.data.isAutoRegistering) { + this.setData({ isAutoRegistering: false }); + wx.showToast({ title: '商家注册成功', icon: 'success' }); + } + } else { + throw new Error(res?.data?.msg || '获取商家信息失败'); + } + } catch (error) { + console.error('获取商家信息失败', error); + wx.showToast({ title: error.message || '加载失败', icon: 'none' }); + } finally { + this.setData({ isLoading: false }); + } + }, + + refreshShangjiaInfo() { + const now = Date.now(); + if (!this.data.canRefresh || now - this.data.lastRefreshTime < 3000) { + wx.showToast({ title: '操作过快', icon: 'none' }); + return; + } + this.setData({ lastRefreshTime: now, canRefresh: false }); + this.getShangjiaInfo(); // 刷新时重新获取所有数据 + setTimeout(() => this.setData({ canRefresh: true }), 3000); + }, + + // ========== 邀请码注册 ========== + handleInviteCodeWithLoginCheck(inviteCode) { + const token = wx.getStorageSync('token'); + const uid = wx.getStorageSync('uid'); + if (!token || !uid) { + wx.reLaunch({ + url: `/pages/gerenzhongxin/gerenzhongxin?autoLogin=true&inviteCode=${inviteCode}&redirect=/pages/shangjiazhongxin/shangjiazhongxin&type=shangjia` + }); + } else { + if (!this.data.isShangjia) { + wx.showLoading({ title: '商家注册中...', mask: true }); + this.setData({ isAutoRegistering: true }); + this.onRegister(); + } else { + wx.showToast({ title: '您已是商家', icon: 'success' }); + } + } + }, + + async onRegister() { + const { inviteCode } = this.data; + if (!inviteCode) { + wx.showToast({ title: '请输入邀请码', icon: 'none' }); + return; + } + if (inviteCode.length > 100) { + wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' }); + return; + } + this.doRegisterWithCode(inviteCode); + }, + + onQuickRegister() { + const code = getDefaultInviteCode('shangjia'); + if (!code) { + wx.showToast({ title: '暂不支持无邀请码注册', icon: 'none' }); + return; + } + this.setData({ inviteCode: code }); + this.doRegisterWithCode(code); + }, + + async doRegisterWithCode(inviteCode) { + this.setData({ isLoading: true }); + try { + const res = await request({ + url: '/yonghu/shangjiahuce', + method: 'POST', + data: { inviteCode } + }); + if (res?.data?.code === 200) { + wx.setStorageSync('shangjiastatus', 1); + const data = res.data.data; + app.globalData.shangjia = data; + const chenghaoList = data.chenghao_list || []; + this.setData({ + isShangjia: true, + nicheng: data.nicheng || '', + sjyue: data.sjyue || '0.00', + fabu: data.fabu || 0, + tuikuan: data.tuikuan || 0, + jinriliushui: data.jinriliushui || '0.00', + jinyueliushui: data.jinyueliushui || '0.00', + jinridingdan: data.jinridingdan || 0, + chenghaoList: chenghaoList, + isLoading: false, + isAutoRegistering: false, + }); + this.loadAvatar(); + wx.showToast({ title: '商家注册成功', icon: 'success' }); + } else { + throw new Error(res?.data?.msg || '注册失败'); + } + } catch (error) { + console.error('商家注册失败', error); + this.setData({ isLoading: false, isAutoRegistering: false }); + wx.showToast({ title: error.message, icon: 'error' }); + } + }, + + // ========== 辅助功能 ========== + registerNotificationComponent() { + const notificationComp = this.selectComponent('#global-notification'); + if (notificationComp?.showNotification) { + app.globalData.globalNotification = { + show: (data) => notificationComp.showNotification(data), + hide: () => notificationComp.hideNotification() + }; + } + }, + + copyUid() { + if (!this.data.uid) { + wx.showToast({ title: 'UID不存在', icon: 'none' }); + return; + } + wx.setClipboardData({ + data: this.data.uid, + success: () => wx.showToast({ title: 'UID已复制', icon: 'success' }), + fail: () => wx.showToast({ title: '复制失败', icon: 'error' }) + }); + }, + + previewAvatar() { + if (this.data.avatarUrl) { + wx.previewImage({ urls: [this.data.avatarUrl] }); + } + }, + + // ========== 页面跳转 ========== + goToPaiDan() { wx.navigateTo({ url: '/pages/sjpaidan/sjpaidan' }); }, + goToJiSuPaiDan() { + wx.vibrateShort({ type: 'medium' }); + wx.navigateTo({ url: '/pages/jisufd/jisufd' }); + }, + goToMyOrders() { wx.navigateTo({ url: '/pages/sjdingdan/sjdingdan' }); }, + goToRecharge() { wx.navigateTo({ url: '/pages/sjchongzhi/sjchongzhi' }); }, + goToWithdraw() { wx.navigateTo({ url: '/pages/tixian/tixian' }); }, + goToRanking() { wx.navigateTo({ url: '/pages/sjpaihang/sjpaihang' }); }, + goToMessages() { wx.navigateTo({ url: '/pages/sjxiaoxi/sjxiaoxi' }); }, + goToKefu() { + const { kefuConfig } = app.globalData; + if (kefuConfig?.link && kefuConfig?.enterpriseId) { + wx.openCustomerServiceChat({ + extInfo: { url: kefuConfig.link }, + corpId: kefuConfig.enterpriseId, + fail: () => wx.showToast({ title: '客服暂不可用', icon: 'none' }) + }); + } else { + wx.showToast({ title: '客服配置未加载', icon: 'none' }); + } + }, +}); \ No newline at end of file