diff --git a/app.js b/app.js
index 811ef86..e8e1994 100644
--- a/app.js
+++ b/app.js
@@ -1,414 +1,451 @@
-// 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);
- }
- }
- }
+// app.js
+import GoEasy from './static/lib/goeasy-2.13.24.esm.min';
+const ChatCore = require('./utils/chat-core');
+import { ensurePhoneAuth } from './utils/phone-auth';
+import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role';
+import { setClubId, getConfiguredClubId, buildClubHeaders, getClubId } from './utils/club-context';
+import { CLUB_ID, WX_APP_ID } from './config/club-config';
+import { applyMiniappAssetsFromConfig, warmupPindaoConfig } from './utils/miniapp-icons.js';
+import { refreshDashouMembership } from './utils/dashou-profile.js';
+
+// 三端固定首页
+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: WX_APP_ID,
+ clubId: CLUB_ID,
+
+ shangjiastatus: 0,
+ dashoustatus: 0,
+ guanshistatus: 0,
+ dashouNicheng: '',
+ zhanghaoStatus: null,
+ dashouzhuangtai: null,
+ yongjin: null,
+ zonge: null,
+ yajin: null,
+ chenghao: '',
+ jinfen: null,
+ clumber: [],
+ 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() {
+ setClubId(getConfiguredClubId(), this);
+ this.globalData.clubId = CLUB_ID;
+ // ① 隐藏返回首页按钮
+ 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);
+ }
+ });
+
+ // ② 已登录时先恢复子客服身份,再决定主端 Tab(避免客服被当成未入驻)
+ if (wx.getStorageSync('token')) {
+ try {
+ const { restoreStaffContextAfterAuth } = require('./utils/staff-api.js');
+ await restoreStaffContextAfterAuth();
+ } catch (e) {}
+ }
+
+ migrateLegacyCenterRole(this);
+ const savedRole = getPrimaryRole(this);
+ lockPrimaryRole(savedRole, this);
+
+ // ②b 冷启动:有 token 时先问后端是否需要手机号认证
+ if (wx.getStorageSync('token')) {
+ const phoneOk = await ensurePhoneAuth({ redirect: true });
+ if (!phoneOk) return;
+ }
+
+ // ②c 打手端冷启动:同步会员/押金等到 globalData(抢单页依赖 clumber)
+ if (wx.getStorageSync('token') && savedRole === 'dashou') {
+ refreshDashouMembership(this).catch(() => {});
+ }
+
+ 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();
+ if (wx.getStorageSync('token') && this.emitEvent) {
+ this.emitEvent('staffContextChanged', {});
+ }
+
+ // ⑤ 建立连接
+ 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);
+ warmupPindaoConfig(this);
+ try {
+ const { fetchGonggaoLunbo } = require('./utils/display-config');
+ fetchGonggaoLunbo(this, 'accept_order').catch(() => {});
+ } catch (e) {}
+ this.initGoEasyWithConfig();
+ this.initCurrentUser();
+ if (this.startImWhenReady) this.startImWhenReady();
+ else if (this.connectForCurrentRole) this.connectForCurrentRole();
+ console.log('远程配置更新完成');
+ })
+ .catch(err => {
+ console.warn('远程配置获取失败,继续使用本地缓存', err);
+ });
+ },
+
+ /** 从后台切回前台时再次向后端校验 */
+ async onShow() {
+ if (!wx.getStorageSync('token')) return;
+ await ensurePhoneAuth({ redirect: true });
+ },
+
+ // 连接管理方法
+ getSavedConnection() {
+ try {
+ const saved = wx.getStorageSync(
+ this.globalData.goEasyConnection.cacheKeys.savedConnection
+ );
+ return saved || null;
+ } catch (e) {
+ return null;
+ }
+ },
+
+ // 配置缓存读写
+ CONFIG_CACHE_KEY_PREFIX: 'app_dynamic_config_',
+
+ getConfigCacheKey() {
+ const cid = getClubId(this) || CLUB_ID;
+ return this.CONFIG_CACHE_KEY_PREFIX + cid;
+ },
+
+ readConfigFromStorage() {
+ try {
+ const data = wx.getStorageSync(this.getConfigCacheKey());
+ if (data && typeof data === 'object') {
+ return data;
+ }
+ } catch (e) {}
+ return null;
+ },
+
+ saveConfigToStorage(config) {
+ try {
+ if (config && typeof config === 'object') {
+ wx.setStorageSync(this.getConfigCacheKey(), config);
+ }
+ } catch (e) {}
+ },
+
+ // 获取远程配置
+ fetchConfigSafely() {
+ return new Promise((resolve) => {
+ wx.request({
+ url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
+ method: 'POST',
+ header: buildClubHeaders({ '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: buildClubHeaders({ '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 || ''
+ };
+ }
+
+ try {
+ applyMiniappAssetsFromConfig(this, config);
+ } catch (e) {
+ console.warn('miniapp assets apply failed', e);
+ }
+ },
+
+ // 仅在有效 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 1ed971e..bd83c9b 100644
--- a/app.json
+++ b/app.json
@@ -13,6 +13,9 @@
"pages/merchant-home/merchant-home",
"pages/merchant-kefu-key/merchant-kefu-key",
"pages/merchant-kefu-list/merchant-kefu-list",
+ "pages/staff-join/staff-join",
+ "pages/merchant-staff-audit/merchant-staff-audit",
+ "pages/merchant-staff-role/merchant-staff-role",
"pages/manager/manager",
"pages/orders/orders",
"pages/order-detail/order-detail",
@@ -23,14 +26,17 @@
"pages/fighter-msg/fighter-msg",
"pages/fighter-orders/fighter-orders",
"pages/accept-order/accept-order",
+ "pages/dashou-exam/dashou-exam",
"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-regular-dispatch/merchant-regular-dispatch",
"pages/merchant-orders/merchant-orders",
"pages/merchant-msg/merchant-msg",
+ "pages/merchant-penalty/merchant-penalty",
"pages/merchant-rank/merchant-rank",
"pages/merchant-recharge/merchant-recharge",
"pages/merchant-order-detail/merchant-order-detail",
@@ -44,7 +50,6 @@
"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",
@@ -59,22 +64,33 @@
"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"
-
-
],
-
+ "subPackages": [
+ {
+ "root": "pages/assess-center",
+ "name": "assess",
+ "pages": ["assess-center"]
+ },
+ {
+ "root": "pages/assess-score",
+ "pages": ["assess-score"]
+ },
+ {
+ "root": "pages/assess-log",
+ "pages": ["assess-log"]
+ },
+ {
+ "root": "pages/assess-gold",
+ "pages": ["assess-gold"]
+ }
+ ],
"usingComponents": {
"popup-notice": "/components/popup-notice/popup-notice",
"tab-bar": "/tab-bar/index"
},
-
"window": {
"navigationBarTextStyle": "black",
"navigationStyle": "default",
@@ -85,26 +101,33 @@
"tabBar": {
"custom": true,
"list": [
-
-
{
- "pagePath": "pages/order-pool/order-pool",
+ "pagePath": "pages/accept-order/accept-order",
"text": "接单池",
"iconPath": "/images/order-pool.png",
"selectedIconPath": "/images/order-pool.png"
},
{
- "pagePath": "pages/order-pool2/order-pool2",
- "text": "接单池",
- "iconPath": "/images/order-pool.png",
- "selectedIconPath": "/images/order-pool.png"
+ "pagePath": "pages/fighter-orders/fighter-orders",
+ "text": "订单",
+ "iconPath": "/images/orders.png",
+ "selectedIconPath": "/images/orders.png"
+ },
+ {
+ "pagePath": "pages/messages/messages",
+ "text": "消息",
+ "iconPath": "/images/messages.png",
+ "selectedIconPath": "/images/messages.png"
+ },
+ {
+ "pagePath": "pages/fighter/fighter",
+ "text": "我的",
+ "iconPath": "/images/mine.png",
+ "selectedIconPath": "/images/mine.png"
}
-
]
},
-
-
"style": "v2",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
-}
\ No newline at end of file
+}
diff --git a/components/chenghao-tag/chenghao-tag.js b/components/chenghao-tag/chenghao-tag.js
index ae79133..2edff62 100644
--- a/components/chenghao-tag/chenghao-tag.js
+++ b/components/chenghao-tag/chenghao-tag.js
@@ -1,73 +1,106 @@
// components/chenghao-tag/chenghao-tag.js
const app = getApp();
+const PILL_SHAPES = ['pill', 'rectangle', 'rounded'];
+
Component({
properties: {
mingcheng: { type: String, value: '' },
- texiaoJson: { type: Object, value: {} }
+ texiaoJson: { type: Object, value: {} },
},
data: {
- // 默认值:宽152,高52,六边形,无背景图,无动画,白色字
- width: 152,
- height: 52,
- shapeClass: 'liubianxing', // 保证至少不是矩形
+ inlineStyle: '',
+ shapeClass: 'tag-pill',
animationClass: '',
- bgStyle: '',
textColor: '#FFFFFF',
textSize: 22,
- imageUrl: ''
+ imageUrl: '',
+ isPill: true,
+ },
+ observers: {
+ 'texiaoJson, mingcheng': function () {
+ this._applyConfig(this.properties.texiaoJson);
+ },
},
lifetimes: {
attached() {
- const cfg = this.properties.texiaoJson || {};
-
- // 1. 尺寸(稍大一些,一行能放3~4个)
- const width = cfg.width || 152;
- const height = cfg.height || 52;
+ this._applyConfig(this.properties.texiaoJson);
+ },
+ },
+ methods: {
+ _applyConfig(raw) {
+ const cfg = raw || {};
+ const ossImageUrl = app.globalData.ossImageUrl || '';
- // 2. 背景处理:优先背景图,否则用渐变/纯色
+ // 无 shape:身份装饰标签 / 自定义色圆角标;有 shape:考核称号等特殊形状
+ const isPill = !cfg.shape || PILL_SHAPES.includes(cfg.shape);
+
+ if (isPill) {
+ const height = Number(cfg.height) || 44;
+ const minWidth = Number(cfg.width) || 72;
+ const solidColor = cfg.bg_color || cfg.background || cfg.color;
+ let bgStyle = '';
+ if (cfg.bg_gradient) {
+ bgStyle = `background: ${cfg.bg_gradient};`;
+ } else if (solidColor) {
+ bgStyle = `background: ${solidColor};`;
+ } else {
+ bgStyle = 'background: linear-gradient(135deg, #FFD700, #FF8C00);';
+ }
+ const flash = cfg.flash || cfg.animation === 'shine' || cfg.animation === 'glow';
+ let animationClass = cfg.animation || '';
+ if (flash && !animationClass) {
+ animationClass = 'pill-flash';
+ }
+ const borderColor = cfg.borderColor || cfg.border_color;
+ const borderStyle = borderColor ? `border: 2rpx solid ${borderColor};` : '';
+ const textColor = cfg.text_color || cfg.textColor || '#FFFFFF';
+ this.setData({
+ isPill: true,
+ shapeClass: 'tag-pill',
+ animationClass,
+ inlineStyle: `min-width: ${minWidth}rpx; height: ${height}rpx; padding: 0 18rpx; ${bgStyle} ${borderStyle}`,
+ textColor,
+ textSize: cfg.text_size || 22,
+ imageUrl: '',
+ });
+ return;
+ }
+
+ const width = Number(cfg.width) || 152;
+ const height = Number(cfg.height) || 52;
let bgStyle = '';
let imageUrl = '';
if (cfg.image_url) {
- const ossImageUrl = app.globalData.ossImageUrl || '';
- imageUrl = cfg.image_url.startsWith('http')
- ? cfg.image_url
+ imageUrl = cfg.image_url.startsWith('http')
+ ? cfg.image_url
: ossImageUrl + cfg.image_url;
} else if (cfg.bg_gradient) {
bgStyle = `background: ${cfg.bg_gradient};`;
} else if (cfg.bg_color) {
bgStyle = `background: ${cfg.bg_color};`;
} else {
- // 默认金橙渐变
- bgStyle = `background: linear-gradient(135deg, #FFD700, #FF8C00);`;
+ bgStyle = 'background: linear-gradient(135deg, #FFD700, #FF8C00);';
}
- // 3. 形状(后端传入 shape 字段,默认 liubianxing)
- const shapeClass = cfg.shape || 'liubianxing';
-
- // 4. 动画
- const animationClass = cfg.animation || '';
-
- // 5. 文字
- const textColor = cfg.text_color || '#FFFFFF';
- const textSize = cfg.text_size || 22;
-
this.setData({
- width, height,
- bgStyle, imageUrl,
- shapeClass, animationClass,
- textColor, textSize
+ isPill: false,
+ inlineStyle: `width: ${width}rpx; height: ${height}rpx; ${bgStyle}`,
+ shapeClass: cfg.shape || 'liubianxing',
+ animationClass: cfg.animation || '',
+ textColor: cfg.text_color || '#FFFFFF',
+ textSize: cfg.text_size || 22,
+ imageUrl,
});
- }
- },
- methods: {
- // 背景图加载失败时回退为纯色背景
+ },
+
onImageError() {
this.setData({ imageUrl: '' });
- // 如果 bgStyle 为空,给个默认背景
- if (!this.data.bgStyle) {
- this.setData({ bgStyle: 'background: linear-gradient(135deg, #FFD700, #FF8C00);' });
+ if (!this.data.inlineStyle.includes('background')) {
+ this.setData({
+ inlineStyle: this.data.inlineStyle + ' background: linear-gradient(135deg, #FFD700, #FF8C00);',
+ });
}
- }
- }
-});
\ No newline at end of file
+ },
+ },
+});
diff --git a/components/chenghao-tag/chenghao-tag.wxml b/components/chenghao-tag/chenghao-tag.wxml
index e9c44f3..ada7d77 100644
--- a/components/chenghao-tag/chenghao-tag.wxml
+++ b/components/chenghao-tag/chenghao-tag.wxml
@@ -1,20 +1,17 @@
-
-
-
-
-
-
+ {{mingcheng}}
-
\ No newline at end of file
+
diff --git a/components/chenghao-tag/chenghao-tag.wxss b/components/chenghao-tag/chenghao-tag.wxss
index d142188..6fae7d6 100644
--- a/components/chenghao-tag/chenghao-tag.wxss
+++ b/components/chenghao-tag/chenghao-tag.wxss
@@ -12,6 +12,18 @@
margin: 4rpx;
box-sizing: border-box;
}
+
+ /* 身份装饰 / 自定义色:圆角标 */
+ .tag-root.tag-pill {
+ border-radius: 20rpx;
+ clip-path: none;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
+ }
+
+ .tag-pill .tag-text {
+ padding: 0;
+ text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.25);
+ }
/* ========== 背景图 ========== */
.tag-bg-image {
@@ -87,4 +99,19 @@
@keyframes glow-anim {
0%, 100% { box-shadow: 0 0 8rpx rgba(255, 215, 0, 0.4); }
50% { box-shadow: 0 0 20rpx rgba(255, 215, 0, 0.8), 0 0 40rpx rgba(255, 215, 0, 0.4); }
+ }
+
+ /* 身份标签闪光 */
+ .tag-root.pill-flash::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 60%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
+ transform: skewX(-20deg);
+ animation: shine-anim 2.2s infinite;
+ z-index: 1;
+ pointer-events: none;
}
\ No newline at end of file
diff --git a/components/pindao-modal/pindao-modal.js b/components/pindao-modal/pindao-modal.js
new file mode 100644
index 0000000..c1bbf7a
--- /dev/null
+++ b/components/pindao-modal/pindao-modal.js
@@ -0,0 +1,15 @@
+Component({
+ properties: {
+ visible: { type: Boolean, value: false },
+ title: { type: String, value: '频道' },
+ channelNo: { type: String, value: '' },
+ images: { type: Array, value: [] },
+ },
+
+ methods: {
+ preventMove() {},
+ onClose() {
+ this.triggerEvent('close');
+ },
+ },
+});
diff --git a/components/pindao-modal/pindao-modal.json b/components/pindao-modal/pindao-modal.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/components/pindao-modal/pindao-modal.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/components/pindao-modal/pindao-modal.wxml b/components/pindao-modal/pindao-modal.wxml
new file mode 100644
index 0000000..628c411
--- /dev/null
+++ b/components/pindao-modal/pindao-modal.wxml
@@ -0,0 +1,24 @@
+
+
+
+ {{title}}
+ ×
+
+
+ 频道号
+ {{channelNo}}
+
+
+ 暂无频道内容
+
+
+
+
diff --git a/components/pindao-modal/pindao-modal.wxss b/components/pindao-modal/pindao-modal.wxss
new file mode 100644
index 0000000..275d9be
--- /dev/null
+++ b/components/pindao-modal/pindao-modal.wxss
@@ -0,0 +1,88 @@
+.pindao-mask {
+ position: fixed;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.55);
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40rpx;
+ box-sizing: border-box;
+}
+
+.pindao-panel {
+ width: 100%;
+ max-height: 80vh;
+ background: #fff;
+ border-radius: 24rpx;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.pindao-head {
+ padding: 28rpx 32rpx 16rpx;
+ align-items: center;
+}
+
+.pindao-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #222;
+}
+
+.pindao-close {
+ width: 56rpx;
+ height: 56rpx;
+ line-height: 52rpx;
+ text-align: center;
+ font-size: 40rpx;
+ color: #999;
+}
+
+.pindao-channel {
+ padding: 0 32rpx 20rpx;
+ text-align: center;
+}
+
+.pindao-channel-label {
+ display: block;
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 8rpx;
+}
+
+.pindao-channel-no {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #c9a962;
+}
+
+.pindao-scroll {
+ flex: 1;
+ max-height: 60vh;
+ padding: 0 24rpx 24rpx;
+ box-sizing: border-box;
+}
+
+.pindao-img {
+ width: 100%;
+ display: block;
+ margin-bottom: 16rpx;
+ border-radius: 12rpx;
+}
+
+.pindao-empty {
+ text-align: center;
+ color: #999;
+ padding: 48rpx 0;
+ font-size: 28rpx;
+}
+
+.flexb {
+ display: flex;
+ justify-content: space-between;
+}
diff --git a/config/club-config.js b/config/club-config.js
new file mode 100644
index 0000000..7f52960
--- /dev/null
+++ b/config/club-config.js
@@ -0,0 +1,11 @@
+/**
+ * 小程序所属俱乐部配置 — 每个小程序工程编译前改这里即可。
+ * 星阙 = xq;星之界 = xzj;与 club 表 club_id 一致。
+ * 不要依赖后端猜测:前端必须明确所属 club。
+ */
+export const CLUB_ID = 'xq';
+
+/** 与 club 表 wx_appid 一致,登录时可传给后端反查 club */
+export const WX_APP_ID = 'wx0e4be86faac4a8d1';
+
+export const CLUB_NAME = '星阙电竞';
diff --git a/pages/accept-order/accept-order.js b/pages/accept-order/accept-order.js
index 749dfe7..c23fe70 100644
--- a/pages/accept-order/accept-order.js
+++ b/pages/accept-order/accept-order.js
@@ -1,8 +1,14 @@
// pages/qiangdan/qiangdan.js
const app = getApp();
import request from '../../utils/request.js';
+import { normalizeOrderTags } from '../../utils/order-tags.js';
+import { refreshDashouMembership, userHasHuiyuan } from '../../utils/dashou-profile.js';
+import { getDefaultAvatarUrl } from '../../utils/avatar.js';
+import { warmupPindaoConfig } from '../../utils/miniapp-icons.js';
import PopupService from '../../services/popupService.js';
import { reconnectForRole } from '../../utils/role-tab-bar.js';
+import { ensurePhoneAuth } from '../../utils/phone-auth.js';
+import { fetchGonggaoLunbo, isGonggaoCacheValid } from '../../utils/display-config.js';
Page({
data: {
@@ -29,7 +35,7 @@ Page({
// 4. 刷新控制字段
scrollViewRefreshing: false,
lastRefreshTime: 0,
- refreshCooldown: 2000,
+ refreshCooldown: 0,
isLoadingMore: false,
// 5. 切换类型冷却
@@ -46,13 +52,59 @@ Page({
// 商品轮播展示(只读 globalData,无额外接口)
lunboList: [],
+ gonggao: '',
+
+ examRequired: false,
+ examPassed: false,
+ _examChecked: false,
},
- async onLoad(options) {
- this.syncShopBannerFromGlobal();
+ async onLoad() {
+ if (app.globalData._acceptOrderSessionReady && app.globalData._acceptOrderPageCache) {
+ const cache = app.globalData._acceptOrderPageCache;
+ this.setData({ ...cache });
+ if ((!cache.lunboList || cache.lunboList.length === 0) && !cache.gonggao && isGonggaoCacheValid(app)) {
+ const lunboList = this.processLunboUrls(app.globalData.shangpinlunbo);
+ const gonggao = app.globalData.shangpingonggao || '';
+ this.setData({ lunboList, gonggao });
+ this.persistPageCache({ lunboList, gonggao });
+ }
+ this.loadGlobalStatus();
+ this.registerNotificationComponent();
+ await this.syncDashouProfileFromServer();
+ this._skipShowRefresh = true;
+ return;
+ }
+
this.loadGlobalStatus();
- await this.loadShangpinLeixing();
- PopupService.checkAndShow(this, 'jiedan');
+ const banner = await this.loadGonggaoAndLunbo(false);
+ await this.syncDashouProfileFromServer();
+ await this.loadShangpinLeixing(true, false, false);
+ this.persistPageCache(banner);
+ app.globalData._acceptOrderSessionReady = true;
+
+ if (!app.globalData._acceptOrderPopupDone) {
+ PopupService.checkAndShow(this, 'jiedan');
+ app.globalData._acceptOrderPopupDone = true;
+ }
+ this._skipShowRefresh = true;
+ },
+
+ persistPageCache(extra = {}) {
+ const d = this.data;
+ app.globalData._acceptOrderPageCache = {
+ shangpinleixing: d.shangpinleixing,
+ xuanzhongLeixingId: d.xuanzhongLeixingId,
+ dingdanList: d.dingdanList,
+ page: d.page,
+ hasMore: d.hasMore,
+ bankuaiBiaoqian: d.bankuaiBiaoqian,
+ xuanzhongBiaoqianId: d.xuanzhongBiaoqianId,
+ lunboList: extra.lunboList ?? d.lunboList,
+ gonggao: extra.gonggao ?? d.gonggao,
+ lastRefreshTime: d.lastRefreshTime,
+ ossImageUrl: d.ossImageUrl,
+ };
},
onHide: function () {
@@ -62,63 +114,84 @@ Page({
}
},
- onShow() {
- this.syncShopBannerFromGlobal();
+ async onShow() {
+ if (!app.globalData._dashouPhoneChecked) {
+ const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
+ if (!phoneOk) return;
+ app.globalData._dashouPhoneChecked = true;
+ }
+
this.registerNotificationComponent();
- this.loadGlobalStatus();
+ await this.syncDashouProfileFromServer();
+ warmupPindaoConfig(app);
+
if (wx.getStorageSync('uid')) {
reconnectForRole('dashou');
if (app.startImWhenReady) app.startImWhenReady();
- this.refreshDashouProfileSilent();
}
- if (this.data.xuanzhongLeixingId) {
- this.loadDingdanList(true);
+
+ await this.checkExamStatus(false);
+
+ if (this._skipShowRefresh) {
+ this._skipShowRefresh = false;
+ return;
+ }
+
+ if (app.globalData._acceptOrderSessionReady && !this._silentRefreshRunning) {
+ this._silentRefreshRunning = true;
+ this.silentRefreshOnShow().finally(() => {
+ this._silentRefreshRunning = false;
+ });
}
},
- /** 同步点单端已加载的商品轮播图,仅展示用 */
- syncShopBannerFromGlobal() {
- const oss = app.globalData.ossImageUrl || '';
- const lunboList = (app.globalData.shangpinlunbo || []).map((url) => {
+ /** 进入页面静默刷新(无 loading 遮罩、不清空列表) */
+ async silentRefreshOnShow() {
+ try {
+ const banner = await this.loadGonggaoAndLunbo(true);
+ await this.syncDashouProfileFromServer();
+ const leixingId = this.data.xuanzhongLeixingId;
+ if (leixingId) {
+ await this.loadDingdanList(true, true);
+ await this.loadBankuaiBiaoqian();
+ }
+ this.loadGlobalStatus();
+ this.persistPageCache(banner);
+ } catch (e) {
+ console.error('静默刷新失败:', e);
+ }
+ },
+
+ /** 公告 + 轮播(首次/下拉强制拉接口,其余读 globalData 或页面缓存) */
+ processLunboUrls(urlList) {
+ const oss = app.globalData.ossImageUrl || this.data.ossImageUrl || '';
+ return (urlList || []).map((url) => {
if (!url) return '';
return url.startsWith('http') ? url : oss + url;
}).filter(Boolean);
- this.setData({ lunboList });
},
- async refreshDashouProfileSilent() {
- try {
- const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' });
- if (!res || res.data.code != 200) return;
- const data = res.data.data || {};
- const patch = {
- dashouNicheng: data.dashounicheng || '',
- zhanghaoStatus: data.zhanghaostatus || '',
- dashouzhuangtai: data.dashouzhuangtai || '',
- yajin: data.yajin || 0,
- jifen: data.jifen || 0,
- clumber: data.clumber || [],
- };
- Object.assign(app.globalData, {
- dashouNicheng: patch.dashouNicheng,
- zhanghaoStatus: patch.zhanghaoStatus,
- dashouzhuangtai: patch.dashouzhuangtai,
- yajin: patch.yajin,
- jinfen: patch.jifen,
- clumber: patch.clumber,
- });
- if (data.dashoustatus !== undefined) {
- wx.setStorageSync('dashoustatus', data.dashoustatus);
- app.globalData.dashoustatus = data.dashoustatus;
+ async loadGonggaoAndLunbo(forceFetch = false) {
+ let lunboRaw = app.globalData.shangpinlunbo || [];
+ let gonggaoText = app.globalData.shangpingonggao || '';
+
+ if (forceFetch || !isGonggaoCacheValid(app)) {
+ try {
+ const data = await fetchGonggaoLunbo(app, 'accept_order');
+ if (data) {
+ lunboRaw = data.shangpinlunbo || app.globalData.shangpinlunbo || [];
+ gonggaoText = data.shangpingonggao || app.globalData.shangpingonggao || '';
+ }
+ } catch (e) {
+ lunboRaw = app.globalData.shangpinlunbo || [];
+ gonggaoText = app.globalData.shangpingonggao || '';
}
- this.setData({
- zhuanghaoStatus: patch.zhanghaoStatus,
- dashouzhuangtai: patch.dashouzhuangtai,
- huiyuanList: patch.clumber,
- yajin: patch.yajin,
- jifen: patch.jifen,
- });
- } catch (e) {}
+ }
+
+ const lunboList = this.processLunboUrls(lunboRaw);
+ const gonggao = gonggaoText;
+ this.setData({ lunboList, gonggao });
+ return { lunboList, gonggao };
},
registerNotificationComponent() {
@@ -144,9 +217,22 @@ Page({
});
},
+ /** 拉取最新打手信息(会员/押金/积分),并刷新订单卡片上的会员展示 */
+ async syncDashouProfileFromServer() {
+ if (!wx.getStorageSync('token')) return;
+ await refreshDashouMembership(app);
+ this.loadGlobalStatus();
+ if (this.data.dingdanList && this.data.dingdanList.length) {
+ this.setData({
+ dingdanList: this.data.dingdanList.map((item) => this.processDingdanItem(item)),
+ });
+ }
+ },
+
// 加载商品类型
- async loadShangpinLeixing() {
- wx.showLoading({ title: '加载商品类型...' });
+ async loadShangpinLeixing(autoLoadOrders = false, preserveSelection = false, showLoading = true) {
+ if (showLoading) wx.showLoading({ title: '加载商品类型...' });
+ const prevId = this.data.xuanzhongLeixingId;
try {
const res = await request({
url: '/dingdan/dsqdhqddlx',
@@ -163,14 +249,16 @@ Page({
else if (Array.isArray(data)) list = data;
}
const processedList = this.processTupianUrl(list);
+ const firstId = processedList[0]?.id || null;
+ const keepPrev = preserveSelection && prevId && processedList.some((i) => i.id === prevId);
+ const selectedId = keepPrev ? prevId : firstId;
this.setData({
shangpinleixing: processedList,
- xuanzhongLeixingId: processedList[0]?.id || null
+ xuanzhongLeixingId: selectedId,
});
- if (this.data.xuanzhongLeixingId) {
- this.loadDingdanList(true);
- // 🆕 加载板块标签
- this.loadBankuaiBiaoqian();
+ if (autoLoadOrders && selectedId) {
+ await this.loadDingdanList(true);
+ await this.loadBankuaiBiaoqian();
}
} else {
wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' });
@@ -178,7 +266,7 @@ Page({
} catch (error) {
wx.showToast({ title: '网络错误,加载失败', icon: 'none' });
} finally {
- wx.hideLoading();
+ if (showLoading) wx.hideLoading();
}
},
@@ -245,8 +333,8 @@ Page({
xuanzhongBiaoqianId: 0 // 重置标签筛选
});
await this.loadDingdanList(true);
- // 🆕 切换类型后加载新标签
await this.loadBankuaiBiaoqian();
+ this.persistPageCache();
} catch (error) {
console.error('切换类型失败:', error);
} finally {
@@ -266,19 +354,24 @@ Page({
hasMore: true
});
await this.loadDingdanList(true);
+ this.persistPageCache();
},
// 加载订单列表
- async loadDingdanList(isRefresh = false) {
- if (this.data.isLoading || !this.data.xuanzhongLeixingId) return;
+ async loadDingdanList(isRefresh = false, silent = false) {
+ if ((!silent && this.data.isLoading) || !this.data.xuanzhongLeixingId) return;
+ if (silent && this._listRequesting) return;
const loadPage = isRefresh ? 1 : this.data.page;
if (!isRefresh && !this.data.hasMore) return;
- this.setData({
- isLoading: true,
- isLoadingMore: !isRefresh
- });
+ if (!silent) {
+ this.setData({
+ isLoading: true,
+ isLoadingMore: !isRefresh,
+ });
+ }
+ this._listRequesting = true;
try {
const res = await request({
@@ -298,6 +391,7 @@ Page({
isLoadingMore: false,
scrollViewRefreshing: false
});
+ this._listRequesting = false;
if (res.data.code === 200 || res.data.code === 0) {
const newList = res.data.data.list || [];
@@ -313,6 +407,7 @@ Page({
page: loadPage,
hasMore: hasMore
});
+ this.persistPageCache();
if (isRefresh) {
this.setData({ lastRefreshTime: Date.now() });
@@ -327,20 +422,28 @@ Page({
isLoadingMore: false,
scrollViewRefreshing: false
});
- wx.showToast({ title: '网络请求失败', icon: 'none' });
+ this._listRequesting = false;
+ if (!silent) {
+ wx.showToast({ title: '网络请求失败', icon: 'none' });
+ }
}
},
// 处理单条订单数据(包含标签、会员判断)
processDingdanItem(item) {
const ossUrl = app.globalData.ossImageUrl || '';
+ const leixing = this.data.shangpinleixing.find((l) => l.id == item.leixing_id);
let fullTupianUrl = '';
- if (item.tupian) {
- fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian;
+ // 卡片左上角优先用订单类型图,没有再退回默认图(不用商品图/头像顶替类型)
+ if (leixing && leixing.full_tupian_url) {
+ fullTupianUrl = leixing.full_tupian_url;
+ } else if (leixing && leixing.tupian_url) {
+ fullTupianUrl = leixing.tupian_url.startsWith('http')
+ ? leixing.tupian_url
+ : ossUrl + leixing.tupian_url;
} else {
- const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id);
- fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png';
+ fullTupianUrl = '/images/default-order.png';
}
const isZhiding = item.zhuangtai === 7;
@@ -353,25 +456,32 @@ Page({
}
const zhidingNicheng = item.zhiding_nicheng || '';
- // 🆕 判断用户是否有订单所需的会员(仅当订单要求会员类型且存在huiyuan_id)
+ // 订单要求指定会员时,核对用户是否持有该会员类型
let hasRequiredMember = true;
if (item.yaoqiuleixing == 1 && item.huiyuan_id) {
- const userHasIt = this.data.huiyuanList.some(h => h.huiyuanid == item.huiyuan_id);
- hasRequiredMember = userHasIt;
+ hasRequiredMember = userHasHuiyuan(this.data.huiyuanList, item.huiyuan_id);
}
+ let shangjiaAvatar = getDefaultAvatarUrl(app);
+ const sjAvatar = (item.sj_avatar || '').trim();
+ if (sjAvatar) {
+ shangjiaAvatar = sjAvatar.startsWith('http') ? sjAvatar : ossUrl + sjAvatar;
+ }
+
+ const tags = normalizeOrderTags(item)
+
return {
...item,
full_tupian_url: fullTupianUrl,
+ leixing_icon_url: fullTupianUrl,
+ shangjia_avatar_full: shangjiaAvatar,
isZhiding: isZhiding,
isPingtai: item.pingtai == 1,
isShangjia: item.pingtai == 2,
zhiding_avatar_full: zhidingAvatar,
zhiding_nicheng: zhidingNicheng,
- // 🆕 三层标签(后端返回,直接保留)
- xuqiu_biaoqian: item.xuqiu_biaoqian || [],
- dashou_biaoqian: item.dashou_biaoqian || [],
- shangjia_biaoqian: item.shangjia_biaoqian || [],
+ ...tags,
+ shangjia_youzhi: !!item.shangjia_youzhi,
// 🆕 是否有查看价格的权限
hasRequiredMember: hasRequiredMember,
};
@@ -409,11 +519,50 @@ Page({
});
},
+ /** 抢单前考试状态(仅更新状态,不自动跳转考试页) */
+ async checkExamStatus() {
+ try {
+ const res = await request({
+ url: '/jituan/dashou-exam/status',
+ method: 'POST',
+ header: { 'content-type': 'application/json' },
+ });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0) && body.data) {
+ const d = body.data;
+ this.setData({
+ examRequired: !!d.exam_required,
+ examPassed: !!d.exam_passed,
+ });
+ }
+ } catch (e) {
+ console.error('考试状态检查失败', e);
+ }
+ return true;
+ },
+
// 抢单按钮(原封不动)
async onQiangdanTap(e) {
const dingdanItem = e.currentTarget.dataset.item;
if (!dingdanItem) return;
+ await this.checkExamStatus();
+
+ if (this.data.examRequired && !this.data.examPassed) {
+ wx.showModal({
+ title: '须通过接单考试',
+ content: '抢单前需先通过接单考试,是否现在去考试?',
+ confirmText: '去考试',
+ cancelText: '暂不',
+ success: (r) => {
+ if (r.confirm) {
+ wx.navigateTo({ url: '/pages/dashou-exam/dashou-exam' });
+ }
+ },
+ });
+ return;
+ }
+
// 校验1: 打手身份
if (!this.data.dashoustatus || this.data.dashoustatus != 1) {
wx.showToast({ title: '请先开启接单员身份', icon: 'none' });
@@ -438,7 +587,7 @@ Page({
}
// 校验5: 会员要求
if (dingdanItem.yaoqiuleixing == 1) {
- const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id);
+ const hasHuiyuan = userHasHuiyuan(this.data.huiyuanList, dingdanItem.huiyuan_id);
if (!hasHuiyuan) {
wx.showToast({
title: '未开通对应会员,无法抢单',
@@ -504,6 +653,7 @@ Page({
item => item.dingdan_id !== dingdanItem.dingdan_id
);
that.setData({ dingdanList: newList });
+ that.persistPageCache();
} else {
wx.showToast({
title: qiangdanRes.data.msg || '抢单失败',
@@ -535,42 +685,14 @@ Page({
},
onReachBottom() {
- const now = Date.now();
- const lastTime = this.data.lastRefreshTime;
- const cooldown = this.data.refreshCooldown;
-
- if (now - lastTime < cooldown) {
- wx.showToast({
- title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`,
- icon: 'none',
- duration: 1500
- });
- return;
- }
-
if (this.data.isLoading || this.data.isLoadingMore) return;
-
if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) {
this.setData({ page: this.data.page + 1 });
this.loadDingdanList(false);
}
},
- onPullDownRefresh() {
- const now = Date.now();
- const lastTime = this.data.lastRefreshTime;
- const cooldown = this.data.refreshCooldown;
-
- if (now - lastTime < cooldown) {
- this.setData({ scrollViewRefreshing: false });
- wx.showToast({
- title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`,
- icon: 'none',
- duration: 1500
- });
- return;
- }
-
+ async onPullDownRefresh() {
if (this.data.isLoading) {
this.setData({ scrollViewRefreshing: false });
return;
@@ -578,14 +700,25 @@ Page({
this.setData({
scrollViewRefreshing: true,
- lastRefreshTime: now,
+ lastRefreshTime: Date.now(),
page: 1,
- hasMore: true
+ hasMore: true,
});
- if (this.data.xuanzhongLeixingId) {
- this.loadDingdanList(true);
- } else {
+ try {
+ const banner = await this.loadGonggaoAndLunbo(true);
+ await this.syncDashouProfileFromServer();
+ await this.loadShangpinLeixing(false, true, false);
+ const leixingId = this.data.xuanzhongLeixingId;
+ if (leixingId) {
+ await this.loadBankuaiBiaoqian();
+ await this.loadDingdanList(true);
+ }
+ this.loadGlobalStatus();
+ this.persistPageCache(banner);
+ } catch (e) {
+ console.error('下拉刷新失败:', e);
+ } finally {
this.setData({ scrollViewRefreshing: false });
}
}
diff --git a/pages/accept-order/accept-order.json b/pages/accept-order/accept-order.json
index e7e7be0..d496762 100644
--- a/pages/accept-order/accept-order.json
+++ b/pages/accept-order/accept-order.json
@@ -1,6 +1,8 @@
{
"navigationBarTitleText": "抢单大厅",
"navigationBarBackgroundColor": "#f7dc51",
+ "backgroundColor": "#f7dc51",
+ "backgroundColorTop": "#f7dc51",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false,
"backgroundTextStyle": "dark",
diff --git a/pages/accept-order/accept-order.wxml b/pages/accept-order/accept-order.wxml
index 389b531..4088337 100644
--- a/pages/accept-order/accept-order.wxml
+++ b/pages/accept-order/accept-order.wxml
@@ -1,4 +1,4 @@
-
+
@@ -38,6 +38,12 @@
+
+
+
+ {{gonggao}}
+
+
@@ -74,7 +80,7 @@
-
+
@@ -190,16 +196,6 @@
-
-
- 指定
-
-
-
- {{item.zhiding_nicheng || '指定接单员'}}
-
-
-
@@ -212,6 +208,20 @@
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
¥
@@ -226,9 +236,9 @@
-
@@ -260,6 +270,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.jieshao || '暂无介绍'}}
+
+ 优质商家
+
+
+
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
+ ¥
+ {{item.dashou_fencheng || 0}}
+
+
+ 未开通会员
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.sjnicheng || '未知商家'}}
+ 发布于 {{item.creat_time}}
+
+
+ 抢单
+
+
+
+
+
+
@@ -276,19 +361,23 @@
-
-
- 指定
-
-
-
- {{item.zhiding_nicheng || '指定接单员'}}
-
-
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
-
+
{{item.sjnicheng || '未知商家'}}
@@ -318,24 +407,33 @@
-
-
+
@@ -70,6 +82,11 @@
+
+
+
+
+
@@ -85,10 +102,14 @@
-
-
-
-
+
+
+
+
+
+
+ 充值会员
+ 充值保证金
@@ -123,7 +144,7 @@
接单服务
-
+
抢单大厅
@@ -136,6 +157,11 @@
考核金牌
+
+
+ 接单考试
+ {{examPassed ? '已通过' : '待考试'}}
+
@@ -195,7 +221,6 @@
考核打分
考核记录
考核中心
- 考核提现
@@ -217,6 +242,7 @@
在线客服
关注快手
+ 频道
联系邀请人
用户规则
返回点单端
@@ -236,3 +262,10 @@
+
diff --git a/pages/fighter/fighter.wxss b/pages/fighter/fighter.wxss
index d10bfb2..120d290 100644
--- a/pages/fighter/fighter.wxss
+++ b/pages/fighter/fighter.wxss
@@ -40,6 +40,19 @@ page {
justify-content: center;
}
+.nav-bar-actions {
+ position: relative;
+ justify-content: center;
+}
+
+.nav-refresh-ico {
+ position: absolute;
+ right: 24rpx;
+ width: 44rpx;
+ height: 44rpx;
+ padding: 8rpx;
+}
+
.nav-title {
font-size: 34rpx;
font-weight: 700;
@@ -134,6 +147,20 @@ page {
opacity: 0.6;
}
+.user-header-actions {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ flex-shrink: 0;
+}
+
+.header-action-ico {
+ width: 48rpx;
+ height: 48rpx;
+ padding: 6rpx;
+ flex-shrink: 0;
+}
+
.setting-ico {
width: 53rpx;
height: 53rpx;
@@ -233,6 +260,23 @@ page {
margin-right: 2%;
}
+.recharge-text-row {
+ margin: 20rpx 24rpx 0;
+ gap: 16rpx;
+}
+
+.recharge-text-btn {
+ flex: 1;
+ text-align: center;
+ padding: 22rpx 12rpx;
+ border-radius: 16rpx;
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #492f00;
+ background: linear-gradient(180deg, #fff8e1, #ffe8b8);
+ border: 1rpx solid rgba(201, 169, 98, 0.45);
+}
+
.freeze-row {
margin: 16rpx 30rpx 0;
padding: 20rpx 10rpx;
@@ -356,11 +400,35 @@ page {
.order-nav {
padding: 10rpx 0 20rpx;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ align-items: flex-start;
}
.nav-item {
- width: 25%;
+ width: 20%;
+ box-sizing: border-box;
padding: 10rpx 0;
+ position: relative;
+}
+
+.exam-tag {
+ font-size: 20rpx;
+ margin-top: 4rpx;
+ padding: 2rpx 10rpx;
+ border-radius: 8rpx;
+}
+
+.exam-tag-pass {
+ color: #52c41a;
+ background: rgba(82, 196, 26, 0.12);
+}
+
+.exam-tag-pending {
+ color: #fa8c16;
+ background: rgba(250, 140, 16, 0.12);
}
.nav-icon {
diff --git a/pages/index/index.js b/pages/index/index.js
index 09651b3..79f575d 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -1,385 +1,374 @@
-// pages/shangpin/shangpin.js
-const app = getApp();
-import { ensureLogin } from '../../utils/login';
-import { fetchShopGoods, bindShop } from '../../utils/shop';
-import { backfillUserProfileCache, getSessionToken } from '../../utils/role-tab-bar';
-import PopupService from '../../services/popupService.js';
-import { createPage } from '../../utils/base-page.js';
-
-// 扫码场景参数名
-const SCENE_PARAM = 'scene';
-
-Page(createPage({
- data: {
- ossImageUrl: '',
- lunbozhanwei: '',
-
- shangpingonggao: '',
- lunboList: [],
- shangpinleixing: [],
- shangpinzhuanqu: [],
- shangpinliebiao: [],
-
- selectedLeixingId: null,
- filteredData: [],
- showGonggaoModal: false,
- gonggaoAnim: true,
- isLoading: false,
- isRefreshing: false,
- hasInitialized: false,
-
- currentTime: ''
- },
-
- // 扫码解析的店铺ID
- shopId: null,
-
- onLoad(options) {
- // 解析二维码参数
- if (options[SCENE_PARAM]) {
- try {
- const scene = decodeURIComponent(options[SCENE_PARAM]);
- this.shopId = scene;
- } catch (e) {
- console.error('scene解码失败', e);
- }
- }
-
- // 等待全局配置加载完成
- this.waitForConfigAndInit();
- // 已登录时才检查弹窗
- const token = getSessionToken(app);
- if (token) {
- PopupService.checkAndShow(this, 'index');
- }
-
- },
-
- // 页面隐藏时清理弹窗视图
- onHide: function () {
- const popupComp = this.selectComponent('#popupNotice');
- if (popupComp && popupComp.cleanup) {
- popupComp.cleanup();
- }
-},
-
- waitForConfigAndInit() {
- if (app.globalData.ossImageUrl) {
- this.setData({
- ossImageUrl: app.globalData.ossImageUrl,
- lunbozhanwei: app.globalData.lunbozhanwei,
- currentTime: this.getCurrentTime()
- });
- this.initPageData();
- } else {
- setTimeout(() => this.waitForConfigAndInit(), 100);
- }
- },
-
- onShow() {
- backfillUserProfileCache(app);
- if (this.data.ossImageUrl) {
- this.setData({
- gonggaoAnim: true,
- currentTime: this.getCurrentTime(),
- });
- }
- this.registerNotificationComponent();
-
- if (!getSessionToken(app)) {
- this.setData({
- hasInitialized: false,
- filteredData: [],
- shangpinleixing: [],
- shangpinzhuanqu: [],
- shangpinliebiao: [],
- });
- return;
- }
-
- // 已登录时加载/刷新商品;未登录不自动登录、不跳转
- if (!this.data.isLoading) {
- const needLoad = !this.data.hasInitialized
- || !this.data.filteredData
- || this.data.filteredData.length === 0;
- if (needLoad) {
- this.initPageData();
- }
- }
- },
-
- getCurrentTime() {
- const now = new Date();
- const year = now.getFullYear();
- const month = (now.getMonth() + 1).toString().padStart(2, '0');
- const day = now.getDate().toString().padStart(2, '0');
- const hour = now.getHours().toString().padStart(2, '0');
- const minute = now.getMinutes().toString().padStart(2, '0');
- return `${year}-${month}-${day} ${hour}:${minute}`;
- },
-
- sortByPaixu(list) {
- if (!list || !Array.isArray(list)) return [];
- return [...list].sort((a, b) => {
- const paixuA = a.paixu || 0;
- const paixuB = b.paixu || 0;
- if (paixuB !== paixuA) return paixuB - paixuA;
- return a.id - b.id;
- });
- },
-
- /**
- * 初始化页面数据(重构后)
- * 流程:确保登录 → 如有扫码ID则绑定店铺 → 并行加载公告轮播图和商品数据
- */
- async initPageData() {
- this.setData({ isLoading: true });
-
- try {
- // 1. 确保登录(静默,不跳转)
- await ensureLogin({ page: this });
-
- // 2. 扫码进入时绑定店铺
- if (this.shopId) {
- await bindShop(this.shopId);
- }
-
- // 3. 并行加载公告轮播图和商品数据
- const [gonggaoResult, shopData] = await Promise.all([
- this.loadGonggaoAndLunbo(),
- fetchShopGoods()
- ]);
-
- // 4. 处理商品数据
- const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
- const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
- const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
-
- // 更新全局缓存
- app.globalData.shangpinleixing = sortedLeixing;
- app.globalData.shangpinzhuanqu = sortedZhuanqu;
- app.globalData.shangpinliebiao = sortedShangpin;
-
- this.setData({
- shangpinleixing: sortedLeixing,
- shangpinzhuanqu: sortedZhuanqu,
- shangpinliebiao: sortedShangpin,
- selectedLeixingId: sortedLeixing[0]?.id || null,
- isLoading: false,
- hasInitialized: true,
- }, () => {
- this.filterShangpinData();
- });
-
- } catch (error) {
- console.error('初始化失败:', error);
- this.setData({ isLoading: false });
- }
- },
-
- /**
- * 加载公告和轮播图
- */
- loadGonggaoAndLunbo() {
- return new Promise((resolve, reject) => {
- // 如果全局已有数据,直接使用
- if (app.globalData.shangpingonggao && app.globalData.shangpinlunbo.length > 0) {
- this.setData({
- shangpingonggao: app.globalData.shangpingonggao,
- lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
- });
- resolve();
- return;
- }
-
- wx.request({
- url: app.globalData.apiBaseUrl + '/peizhi/shangpingonggao/',
- method: 'POST',
- header: { 'content-type': 'application/json' },
- success: (res) => {
- if (res.statusCode === 200 && res.data) {
- const data = res.data;
- app.globalData.shangpingonggao = data.shangpingonggao || '';
- app.globalData.shangpinlunbo = data.shangpinlunbo || [];
- this.setData({
- shangpingonggao: app.globalData.shangpingonggao,
- lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
- });
- resolve();
- } else {
- reject(new Error('请求失败'));
- }
- },
- fail: reject
- });
- });
- },
-
- processImageUrls(urlList) {
- if (!urlList || !Array.isArray(urlList)) return [];
- return urlList.map(url => url.startsWith('http') ? url : this.data.ossImageUrl + url);
- },
-
- /**
- * 筛选商品数据
- */
- filterShangpinData() {
- const { selectedLeixingId, shangpinzhuanqu, shangpinliebiao } = this.data;
-
- if (!selectedLeixingId || !shangpinzhuanqu || !shangpinliebiao) {
- this.setData({ filteredData: [] });
- return;
- }
-
- const zhuanquByLeixing = new Map();
- shangpinzhuanqu.forEach(zhuanqu => {
- if (zhuanqu.leixing_id === selectedLeixingId) {
- if (!zhuanquByLeixing.has(selectedLeixingId)) {
- zhuanquByLeixing.set(selectedLeixingId, []);
- }
- zhuanquByLeixing.get(selectedLeixingId).push(zhuanqu);
- }
- });
-
- const shangpinByZhuanqu = new Map();
- shangpinliebiao.forEach(shangpin => {
- if (shangpin.leixing_id === selectedLeixingId && shangpin.zhuanqu_id) {
- const zhuanquId = shangpin.zhuanqu_id;
- if (!shangpinByZhuanqu.has(zhuanquId)) {
- shangpinByZhuanqu.set(zhuanquId, []);
- }
-
- 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.get(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,
- paixu: shangpin.paixu || 0
- });
- }
- });
-
- const filteredData = [];
- const currentZhuanquList = zhuanquByLeixing.get(selectedLeixingId) || [];
-
- currentZhuanquList.forEach(zhuanqu => {
- const shangpinList = shangpinByZhuanqu.get(zhuanqu.id) || [];
- if (shangpinList.length > 0) {
- filteredData.push({
- zhuanqu: {
- id: zhuanqu.id,
- mingzi: zhuanqu.mingzi,
- paixu: zhuanqu.paixu || 0
- },
- shangpinList: shangpinList
- });
- }
- });
-
- const sortedFilteredData = filteredData.sort((a, b) => {
- const paixuA = a.zhuanqu.paixu || 0;
- const paixuB = b.zhuanqu.paixu || 0;
- if (paixuB !== paixuA) return paixuB - paixuA;
- return a.zhuanqu.id - b.zhuanqu.id;
- });
-
- this.setData({ filteredData: sortedFilteredData });
- },
-
- selectLeixing(e) {
- const leixingId = e.currentTarget.dataset.id;
- if (this.data.selectedLeixingId === leixingId) return;
- this.setData({ selectedLeixingId: leixingId }, () => {
- this.filterShangpinData();
- });
- },
-
- showGonggaoDetail() {
- this.setData({
- showGonggaoModal: true,
- _modalLeaving: false,
- gonggaoAnim: false,
- currentTime: this.getCurrentTime()
- });
- },
-
- hideGonggaoDetail() {
- this.setData({
- showGonggaoModal: false,
- _modalLeaving: true,
- gonggaoAnim: true
- });
- setTimeout(() => this.setData({ _modalLeaving: false }), 300);
- },
-
- /**
- * 刷新所有数据
- * 只刷新商品数据
- */
- async refreshAllData() {
- if (this.data.isRefreshing) return;
- this.setData({ isRefreshing: true });
- wx.showLoading({ title: '刷新中...', mask: true });
-
- try {
- // 重新获取商品数据
- const shopData = await fetchShopGoods();
-
- const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
- const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
- const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
-
- app.globalData.shangpinleixing = sortedLeixing;
- app.globalData.shangpinzhuanqu = sortedZhuanqu;
- app.globalData.shangpinliebiao = sortedShangpin;
-
- this.setData({
- shangpinleixing: sortedLeixing,
- shangpinzhuanqu: sortedZhuanqu,
- shangpinliebiao: sortedShangpin,
- selectedLeixingId: sortedLeixing[0]?.id || null,
- isRefreshing: false
- }, () => {
- this.filterShangpinData();
- });
-
- wx.hideLoading();
- wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 });
- } catch (error) {
- wx.hideLoading();
- this.setData({ isRefreshing: false });
- }
- },
-
- goToDetail(e) {
- const shangpinId = e.currentTarget.dataset.id;
- if (!shangpinId) return;
- wx.navigateTo({
- url: `/pages/product-detail/product-detail?id=${shangpinId}`
- });
- },
-
- onReachBottom() {},
-
- onShareAppMessage() {
- return {
- title: '阿龙电竞',
- path: '/pages/shangpin/shangpin'
- };
- },
-
- onUnload() {
- this.setData({ gonggaoAnim: false });
- }
-}))
+// pages/shangpin/shangpin.js
+const app = getApp();
+import { ensureLogin } from '../../utils/login';
+import { fetchShopGoods, bindShop } from '../../utils/shop';
+import { backfillUserProfileCache, getSessionToken } from '../../utils/role-tab-bar';
+import PopupService from '../../services/popupService.js';
+import { createPage } from '../../utils/base-page.js';
+import { fetchGonggaoLunbo, isGonggaoCacheValid } from '../../utils/display-config';
+
+// 扫码场景参数名
+const SCENE_PARAM = 'scene';
+
+Page(createPage({
+ data: {
+ ossImageUrl: '',
+ lunbozhanwei: '',
+
+ shangpingonggao: '',
+ lunboList: [],
+ shangpinleixing: [],
+ shangpinzhuanqu: [],
+ shangpinliebiao: [],
+
+ selectedLeixingId: null,
+ filteredData: [],
+ showGonggaoModal: false,
+ gonggaoAnim: true,
+ isLoading: false,
+ isRefreshing: false,
+ hasInitialized: false,
+
+ currentTime: ''
+ },
+
+ // 扫码解析的店铺ID
+ shopId: null,
+
+ onLoad(options) {
+ // 解析二维码参数
+ if (options[SCENE_PARAM]) {
+ try {
+ const scene = decodeURIComponent(options[SCENE_PARAM]);
+ this.shopId = scene;
+ } catch (e) {
+ console.error('scene解码失败', e);
+ }
+ }
+
+ // 等待全局配置加载完成
+ this.waitForConfigAndInit();
+ // 已登录时才检查弹窗
+ const token = getSessionToken(app);
+ if (token) {
+ PopupService.checkAndShow(this, 'index');
+ }
+
+ },
+
+ // 页面隐藏时清理弹窗视图
+ onHide: function () {
+ const popupComp = this.selectComponent('#popupNotice');
+ if (popupComp && popupComp.cleanup) {
+ popupComp.cleanup();
+ }
+},
+
+ waitForConfigAndInit() {
+ if (app.globalData.ossImageUrl) {
+ this.setData({
+ ossImageUrl: app.globalData.ossImageUrl,
+ lunbozhanwei: app.globalData.lunbozhanwei,
+ currentTime: this.getCurrentTime()
+ });
+ this.initPageData();
+ } else {
+ setTimeout(() => this.waitForConfigAndInit(), 100);
+ }
+ },
+
+ onShow() {
+ backfillUserProfileCache(app);
+ if (this.data.ossImageUrl) {
+ this.setData({
+ gonggaoAnim: true,
+ currentTime: this.getCurrentTime(),
+ });
+ }
+ this.registerNotificationComponent();
+
+ if (!getSessionToken(app)) {
+ this.setData({
+ hasInitialized: false,
+ filteredData: [],
+ shangpinleixing: [],
+ shangpinzhuanqu: [],
+ shangpinliebiao: [],
+ });
+ return;
+ }
+
+ // 已登录时加载/刷新商品;未登录不自动登录、不跳转
+ if (!this.data.isLoading) {
+ const needLoad = !this.data.hasInitialized
+ || !this.data.filteredData
+ || this.data.filteredData.length === 0;
+ if (needLoad) {
+ this.initPageData();
+ }
+ }
+ },
+
+ getCurrentTime() {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = (now.getMonth() + 1).toString().padStart(2, '0');
+ const day = now.getDate().toString().padStart(2, '0');
+ const hour = now.getHours().toString().padStart(2, '0');
+ const minute = now.getMinutes().toString().padStart(2, '0');
+ return `${year}-${month}-${day} ${hour}:${minute}`;
+ },
+
+ sortByPaixu(list) {
+ if (!list || !Array.isArray(list)) return [];
+ return [...list].sort((a, b) => {
+ const paixuA = a.paixu || 0;
+ const paixuB = b.paixu || 0;
+ if (paixuB !== paixuA) return paixuB - paixuA;
+ return a.id - b.id;
+ });
+ },
+
+ /**
+ * 初始化页面数据(重构后)
+ * 流程:确保登录 → 如有扫码ID则绑定店铺 → 并行加载公告轮播图和商品数据
+ */
+ async initPageData() {
+ this.setData({ isLoading: true });
+
+ try {
+ // 1. 确保登录(静默,不跳转)
+ await ensureLogin({ page: this });
+
+ // 2. 扫码进入时绑定店铺
+ if (this.shopId) {
+ await bindShop(this.shopId);
+ }
+
+ // 3. 并行加载公告轮播图和商品数据
+ const [gonggaoResult, shopData] = await Promise.all([
+ this.loadGonggaoAndLunbo(),
+ fetchShopGoods()
+ ]);
+
+ // 4. 处理商品数据
+ const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
+ const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
+ const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
+
+ // 更新全局缓存
+ app.globalData.shangpinleixing = sortedLeixing;
+ app.globalData.shangpinzhuanqu = sortedZhuanqu;
+ app.globalData.shangpinliebiao = sortedShangpin;
+
+ this.setData({
+ shangpinleixing: sortedLeixing,
+ shangpinzhuanqu: sortedZhuanqu,
+ shangpinliebiao: sortedShangpin,
+ selectedLeixingId: sortedLeixing[0]?.id || null,
+ isLoading: false,
+ hasInitialized: true,
+ }, () => {
+ this.filterShangpinData();
+ });
+
+ } catch (error) {
+ console.error('初始化失败:', error);
+ this.setData({ isLoading: false });
+ }
+ },
+
+ /**
+ * 加载公告和轮播图
+ */
+ loadGonggaoAndLunbo() {
+ return new Promise((resolve, reject) => {
+ if (isGonggaoCacheValid(app)) {
+ this.setData({
+ shangpingonggao: app.globalData.shangpingonggao,
+ lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
+ });
+ resolve();
+ return;
+ }
+
+ fetchGonggaoLunbo(app, 'order_pool')
+ .then((data) => {
+ this.setData({
+ shangpingonggao: data.shangpingonggao || '',
+ lunboList: this.processImageUrls(data.shangpinlunbo || [])
+ });
+ resolve();
+ })
+ .catch(reject);
+ });
+ },
+
+ processImageUrls(urlList) {
+ if (!urlList || !Array.isArray(urlList)) return [];
+ return urlList.map(url => url.startsWith('http') ? url : this.data.ossImageUrl + url);
+ },
+
+ /**
+ * 筛选商品数据
+ */
+ filterShangpinData() {
+ const { selectedLeixingId, shangpinzhuanqu, shangpinliebiao } = this.data;
+
+ if (!selectedLeixingId || !shangpinzhuanqu || !shangpinliebiao) {
+ this.setData({ filteredData: [] });
+ return;
+ }
+
+ const zhuanquByLeixing = new Map();
+ shangpinzhuanqu.forEach(zhuanqu => {
+ if (zhuanqu.leixing_id === selectedLeixingId) {
+ if (!zhuanquByLeixing.has(selectedLeixingId)) {
+ zhuanquByLeixing.set(selectedLeixingId, []);
+ }
+ zhuanquByLeixing.get(selectedLeixingId).push(zhuanqu);
+ }
+ });
+
+ const shangpinByZhuanqu = new Map();
+ shangpinliebiao.forEach(shangpin => {
+ if (shangpin.leixing_id === selectedLeixingId && shangpin.zhuanqu_id) {
+ const zhuanquId = shangpin.zhuanqu_id;
+ if (!shangpinByZhuanqu.has(zhuanquId)) {
+ shangpinByZhuanqu.set(zhuanquId, []);
+ }
+
+ 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.get(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,
+ paixu: shangpin.paixu || 0
+ });
+ }
+ });
+
+ const filteredData = [];
+ const currentZhuanquList = zhuanquByLeixing.get(selectedLeixingId) || [];
+
+ currentZhuanquList.forEach(zhuanqu => {
+ const shangpinList = shangpinByZhuanqu.get(zhuanqu.id) || [];
+ if (shangpinList.length > 0) {
+ filteredData.push({
+ zhuanqu: {
+ id: zhuanqu.id,
+ mingzi: zhuanqu.mingzi,
+ paixu: zhuanqu.paixu || 0
+ },
+ shangpinList: shangpinList
+ });
+ }
+ });
+
+ const sortedFilteredData = filteredData.sort((a, b) => {
+ const paixuA = a.zhuanqu.paixu || 0;
+ const paixuB = b.zhuanqu.paixu || 0;
+ if (paixuB !== paixuA) return paixuB - paixuA;
+ return a.zhuanqu.id - b.zhuanqu.id;
+ });
+
+ this.setData({ filteredData: sortedFilteredData });
+ },
+
+ selectLeixing(e) {
+ const leixingId = e.currentTarget.dataset.id;
+ if (this.data.selectedLeixingId === leixingId) return;
+ this.setData({ selectedLeixingId: leixingId }, () => {
+ this.filterShangpinData();
+ });
+ },
+
+ showGonggaoDetail() {
+ this.setData({
+ showGonggaoModal: true,
+ _modalLeaving: false,
+ gonggaoAnim: false,
+ currentTime: this.getCurrentTime()
+ });
+ },
+
+ hideGonggaoDetail() {
+ this.setData({
+ showGonggaoModal: false,
+ _modalLeaving: true,
+ gonggaoAnim: true
+ });
+ setTimeout(() => this.setData({ _modalLeaving: false }), 300);
+ },
+
+ /**
+ * 刷新所有数据
+ * 只刷新商品数据
+ */
+ async refreshAllData() {
+ if (this.data.isRefreshing) return;
+ this.setData({ isRefreshing: true });
+ wx.showLoading({ title: '刷新中...', mask: true });
+
+ try {
+ // 重新获取商品数据
+ const shopData = await fetchShopGoods();
+
+ const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
+ const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
+ const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
+
+ app.globalData.shangpinleixing = sortedLeixing;
+ app.globalData.shangpinzhuanqu = sortedZhuanqu;
+ app.globalData.shangpinliebiao = sortedShangpin;
+
+ this.setData({
+ shangpinleixing: sortedLeixing,
+ shangpinzhuanqu: sortedZhuanqu,
+ shangpinliebiao: sortedShangpin,
+ selectedLeixingId: sortedLeixing[0]?.id || null,
+ isRefreshing: false
+ }, () => {
+ this.filterShangpinData();
+ });
+
+ wx.hideLoading();
+ wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 });
+ } catch (error) {
+ wx.hideLoading();
+ this.setData({ isRefreshing: false });
+ }
+ },
+
+ goToDetail(e) {
+ const shangpinId = e.currentTarget.dataset.id;
+ if (!shangpinId) return;
+ wx.navigateTo({
+ url: `/pages/product-detail/product-detail?id=${shangpinId}`
+ });
+ },
+
+ onReachBottom() {},
+
+ onShareAppMessage() {
+ return {
+ title: '阿龙电竞',
+ path: '/pages/shangpin/shangpin'
+ };
+ },
+
+ onUnload() {
+ this.setData({ gonggaoAnim: false });
+ }
+}))
diff --git a/pages/invite-manager/invite-manager.js b/pages/invite-manager/invite-manager.js
index 7a0fff4..b9ecaaf 100644
--- a/pages/invite-manager/invite-manager.js
+++ b/pages/invite-manager/invite-manager.js
@@ -1,21 +1,32 @@
-// pages/zuzhanghaibao/zuzhanghaibao.js
+// pages/invite-manager/invite-manager.js — 组长推广海报
import request from '../../utils/request.js';
+import {
+ getFullImageUrl,
+ loadPosterPageConfig,
+ posterInviteCacheKey,
+ posterQrCacheKey,
+} from '../../utils/poster-page.js';
const app = getApp();
Page({
data: {
- qrcodeUrl: '', // 二维码完整URL
- yaoqingma: '', // 组长邀请码字符串
+ qrcodeUrl: '',
+ yaoqingma: '',
isLoading: false,
showPosterCanvas: false,
- posterImageTemp: '', // 生成的海报临时路径
- avatarUrl: '', // 用户头像完整URL
+ posterImageTemp: '',
+ avatarUrl: '',
uid: '',
nickName: '',
+ posterBgUrl: '',
},
- onLoad() {
+ async onLoad() {
+ const { bgUrl, qrCacheKey } = await loadPosterPageConfig('zuzhang', app);
+ this._qrCacheKey = qrCacheKey;
+ this._inviteCacheKey = posterInviteCacheKey();
+ this.setData({ posterBgUrl: bgUrl });
this.loadFromCache();
this.loadUserInfo();
},
@@ -29,126 +40,88 @@ Page({
if (notificationComp && notificationComp.showNotification) {
app.globalData.globalNotification = {
show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
+ hide: () => notificationComp.hideNotification(),
};
}
},
- /**
- * 从缓存加载二维码URL和邀请码
- * 缓存键名使用独特拼音,避免与管事页面冲突
- */
loadFromCache() {
try {
- const relativeUrl = wx.getStorageSync('zuzhang_haibao_url');
+ const key = this._qrCacheKey || posterQrCacheKey('zuzhang');
+ const relativeUrl = wx.getStorageSync(key);
if (relativeUrl) {
- const fullUrl = this.getFullImageUrl(relativeUrl);
- this.setData({ qrcodeUrl: fullUrl });
- }
- const yaoqingma = wx.getStorageSync('zuzhang_yaoqingma');
- if (yaoqingma) {
- this.setData({ yaoqingma });
+ this.setData({ qrcodeUrl: getFullImageUrl(relativeUrl, app) });
}
+ const inviteKey = this._inviteCacheKey || posterInviteCacheKey();
+ const yaoqingma = wx.getStorageSync(inviteKey);
+ if (yaoqingma) this.setData({ yaoqingma });
} catch (error) {
console.error('读取缓存失败', error);
}
},
- /**
- * 加载用户头像、昵称、UID
- */
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);
+ avatarUrl = getFullImageUrl(touxiang, app);
}
const uid = wx.getStorageSync('uid') || '';
- // 组长昵称可能从全局变量或缓存获取
- let nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '组长';
+ const nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '组长';
this.setData({ avatarUrl, uid, nickName });
},
- /**
- * 拼接完整图片URL
- */
- getFullImageUrl(url) {
- if (!url) return '';
- const ossUrl = app.globalData.ossImageUrl || '';
- return url.startsWith('http') ? url : ossUrl + url;
- },
-
- /**
- * 刷新/获取二维码和邀请码
- * 调用 /peizhi/zuzhanghb 接口
- */
refreshQRCode() {
if (this.data.isLoading) return;
this.setData({ isLoading: true });
-
- request({
- url: '/peizhi/zuzhanghb',
- method: 'POST',
- })
- .then(res => {
+ request({ url: '/peizhi/zuzhanghb', method: 'POST' })
+ .then((res) => {
if (res.data && res.data.code === 0) {
- const { url: relativeUrl, yaoqingma } = res.data.data; // 假设返回字段为 url 和 yaoqingma
+ const { url: relativeUrl, yaoqingma } = res.data.data || {};
if (relativeUrl) {
- wx.setStorageSync('zuzhang_haibao_url', relativeUrl);
- const fullUrl = this.getFullImageUrl(relativeUrl);
- this.setData({ qrcodeUrl: fullUrl });
+ const key = this._qrCacheKey || posterQrCacheKey('zuzhang');
+ wx.setStorageSync(key, relativeUrl);
+ this.setData({ qrcodeUrl: getFullImageUrl(relativeUrl, app) });
}
if (yaoqingma) {
- wx.setStorageSync('zuzhang_yaoqingma', yaoqingma);
+ const inviteKey = this._inviteCacheKey || posterInviteCacheKey();
+ wx.setStorageSync(inviteKey, yaoqingma);
this.setData({ yaoqingma });
}
wx.showToast({ title: '获取成功', icon: 'success' });
} else {
- wx.showToast({ title: res.data.msg || '获取失败', icon: 'none' });
+ wx.showToast({ title: res.data.msg || res.data.message || '获取失败', icon: 'none' });
}
})
- .catch(err => {
+ .catch((err) => {
console.error('获取组长海报失败', err);
wx.showToast({ title: '网络错误', icon: 'none' });
})
- .finally(() => {
- this.setData({ isLoading: false });
- });
+ .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' });
- }
+ if (res.statusCode === 200) this.downloadAndSave(res.tempFilePath);
+ else wx.showToast({ title: '下载失败', icon: 'none' });
},
- fail: (err) => {
+ fail: () => {
wx.hideLoading();
- console.error('下载二维码失败', err);
wx.showToast({ title: '下载失败', icon: 'none' });
- }
+ },
});
},
- /**
- * 复制邀请码到剪贴板
- */
copyInviteCode() {
if (!this.data.yaoqingma) {
wx.showToast({ title: '暂无邀请码', icon: 'none' });
@@ -156,145 +129,78 @@ Page({
}
wx.setClipboardData({
data: this.data.yaoqingma,
- success: () => {
- wx.showToast({ title: '复制成功', icon: 'success' });
- },
- fail: () => {
- wx.showToast({ title: '复制失败', icon: 'none' });
- }
+ success: () => wx.showToast({ title: '复制成功', icon: 'success' }),
});
},
- /**
- * 生成专属海报(包含头像、二维码、昵称、标语)
- */
generateMyPoster() {
if (!this.data.qrcodeUrl) {
wx.showToast({ title: '请先生成二维码', icon: 'none' });
return;
}
-
wx.showLoading({ title: '生成海报中...', mask: true });
-
- const ossUrl = app.globalData.ossImageUrl || '';
- // 🔥 组长海报背景图路径:beijing/zuzhangbeijing.jpg
- const bgUrl = ossUrl + 'beijing/zuzhangbeijing.jpg';
- const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl];
-
- // 并行加载所有图片
- const promises = urls.map(url => this.loadImage(url));
- Promise.all(promises)
+ const bgUrl = this.data.posterBgUrl;
+ Promise.all([bgUrl, this.data.qrcodeUrl, this.data.avatarUrl].map((u) => this.loadImage(u)))
.then((images) => {
wx.hideLoading();
this.setData({ showPosterCanvas: true }, () => {
- // 确保 canvas 已渲染
- setTimeout(() => {
- this.drawPoster(images[0], images[1], images[2]);
- }, 200);
+ setTimeout(() => this.drawPoster(images[0], images[1], images[2]), 200);
});
})
- .catch((err) => {
+ .catch(() => {
wx.hideLoading();
wx.showToast({ title: '图片加载失败', icon: 'none' });
- console.error('图片加载失败', err);
});
},
- /**
- * 加载图片为本地路径(用于 canvas 绘制)
- */
loadImage(url) {
return new Promise((resolve, reject) => {
- wx.getImageInfo({
- src: url,
- success: (res) => resolve(res.path),
- fail: reject
- });
+ wx.getImageInfo({ src: url, success: (res) => resolve(res.path), fail: reject });
});
},
- /**
- * 绘制海报
- * @param {string} bgPath 背景图本地路径
- * @param {string} qrPath 二维码本地路径
- * @param {string} avatarPath 头像本地路径
- */
drawPoster(bgPath, qrPath, avatarPath) {
const ctx = wx.createCanvasContext('posterCanvas', this);
- const query = wx.createSelectorQuery().in(this);
- query.select('.poster-canvas').boundingClientRect(rect => {
+ wx.createSelectorQuery().in(this).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);
-
- // 🔥【位置调整】二维码向右上角移动一丢丢 (增加 margin 从 5 到 15)
const qrSize = 100;
- const margin = 15; // 原来 5,现在 15,向右下各移一点,但看起来更协调
+ const margin = 15;
const qrX = canvasWidth - qrSize - margin;
const qrY = canvasHeight - qrSize - margin;
ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
-
- // 🔥【位置调整】头像也向右上移动一丢丢 (原来 margin 5,现在 margin 15)
const avatarSize = 60;
- const avatarMargin = 15;
- const avatarX = avatarMargin + 10; // 原来 margin 5+20,现在 15+20,相当于右移10
- const avatarY = canvasHeight - avatarSize - avatarMargin;
-
- // 圆形头像裁剪
+ const avatarX = margin + 10;
+ const avatarY = canvasHeight - avatarSize - margin;
ctx.save();
ctx.beginPath();
- ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI);
+ 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.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);
-
- // 绘制邀请语
+ if (nick.length > 3) nick = nick.substring(0, 3) + '...';
+ ctx.fillText(nick, avatarX + avatarSize + 8, avatarY + avatarSize / 2 + 6);
ctx.setFontSize(18);
- ctx.setFillStyle('#ffaa00'); // 金黄色,呼应组长主题
- ctx.setTextAlign('left');
- const slogan = '加入我的团队 ✦';
- const sloganX = avatarX;
- const sloganY = avatarY - 12;
- ctx.fillText(slogan, sloganX, sloganY);
-
- // 异步绘制
+ ctx.setFillStyle('#ffaa00');
+ ctx.fillText('加入我的团队 ✦', avatarX, avatarY - 12);
ctx.draw(false, () => {
wx.canvasToTempFilePath({
canvasId: 'posterCanvas',
- success: (res) => {
- this.setData({ posterImageTemp: res.tempFilePath });
- },
- fail: (err) => {
- console.error('生成海报临时文件失败', err);
- }
+ success: (res) => this.setData({ posterImageTemp: res.tempFilePath }),
}, this);
});
}).exec();
},
- /**
- * 保存生成的海报
- */
savePoster() {
if (!this.data.posterImageTemp) {
wx.showToast({ title: '海报尚未生成', icon: 'none' });
@@ -303,54 +209,37 @@ Page({
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);
- },
+ success: () => this._saveImage(filePath),
fail: () => {
wx.showModal({
title: '提示',
content: '需要您授权保存到相册',
- success: (modalRes) => {
- if (modalRes.confirm) {
- wx.openSetting();
- }
- }
+ success: (m) => { if (m.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' });
- }
+ filePath,
+ success: () => wx.showToast({ title: '保存成功', icon: 'success' }),
+ fail: () => wx.showToast({ title: '保存失败', icon: 'none' }),
});
},
-});
\ No newline at end of file
+});
diff --git a/pages/merchant-dispatch/merchant-dispatch.js b/pages/merchant-dispatch/merchant-dispatch.js
index e28da8e..28e1381 100644
--- a/pages/merchant-dispatch/merchant-dispatch.js
+++ b/pages/merchant-dispatch/merchant-dispatch.js
@@ -1,11 +1,15 @@
// pages/merchant-dispatch/merchant-dispatch.js
import { createPage, request } from '../../utils/base-page.js'
import PopupService from '../../services/popupService.js' // 引入弹窗服务
+import { STAFF_API, isStaffMode, refreshStaffContext, getStaffContext, restoreStaffContextAfterAuth, isMerchantPortalUser } from '../../utils/staff-api.js'
Page(createPage({
data: {
- // 商家余额 (从全局变量获取)
+ // 可用余额 / 客服额度
sjyue: '0.00',
+ isStaffMode: false,
+ balanceLabel: '可用余额',
+ balanceTip: '派单将从此余额扣除',
// 商品类型列表
shangpinList: [],
@@ -20,6 +24,7 @@ Page(createPage({
dingdanJieshao: '', // 订单介绍
dingdanBeizhu: '', // 订单备注
laobanName: '', // 老板游戏昵称/UID
+ waibuDingdanId: '', // 外部平台订单号
zhidingUid: '', // 指定打手UID
jiage: '', // 订单价格
@@ -42,7 +47,15 @@ Page(createPage({
bgImageUrl: ''
},
- onLoad() {
+ async onLoad() {
+ if (wx.getStorageSync('token')) {
+ await restoreStaffContextAfterAuth()
+ }
+ if (!isMerchantPortalUser()) {
+ wx.showToast({ title: '请先成为商家或绑定客服', icon: 'none' })
+ setTimeout(() => wx.navigateBack(), 1500)
+ return
+ }
this.loadBgImage() // 拼接背景图
this.loadShangjiaYue() // 从全局变量获取商家余额
this.loadShangpinTypes() // 加载商品类型
@@ -50,15 +63,9 @@ Page(createPage({
},
onShow() {
- // 每次显示页面时刷新余额(可能从其他页面充值后返回)
this.loadShangjiaYue()
- // 重新拼接背景图(确保最新)
this.loadBgImage()
-
- // 注册通知组件(用于全局消息提示)
this.registerNotificationComponent()
-
- // 重置按钮缩进定时器(重新开始5秒倒计时)
this.startTutorialBtnTimer()
},
@@ -87,6 +94,22 @@ Page(createPage({
// ==================== 基础数据加载 ====================
loadShangjiaYue() {
+ const staff = isStaffMode()
+ this.setData({
+ isStaffMode: staff,
+ balanceLabel: staff ? '可用额度' : '可用余额',
+ balanceTip: staff ? '派单将从您的客服额度扣除(需老板先划额度)' : '派单将从此余额扣除',
+ })
+ if (staff) {
+ const ctx = getStaffContext() || {}
+ const wallet = ctx.wallet || {}
+ this.setData({ sjyue: wallet.quota_available || '0.00' })
+ refreshStaffContext(request).then((fresh) => {
+ const w = (fresh && fresh.wallet) || wallet
+ this.setData({ sjyue: w.quota_available || '0.00' })
+ }).catch(() => {})
+ return
+ }
const app = getApp()
const shangjiaData = app.globalData.shangjia || {}
this.setData({
@@ -97,13 +120,16 @@ Page(createPage({
// 加载商品类型(与极速派单完全一致)
async loadShangpinTypes() {
this.setData({ isLoading: true })
+ const staff = isStaffMode()
try {
const res = await request({
- url: '/dingdan/sjspleixing',
+ url: staff ? STAFF_API.productTypes : '/dingdan/sjspleixing',
method: 'POST'
})
- if (res && res.data.code === 200) {
- let list = res.data.data || []
+ const code = res && res.data && res.data.code
+ if (code === 200 || code === 0) {
+ let list = (res.data.data || [])
+ if (!Array.isArray(list) && list.list) list = list.list
// 强制倒序排列(与极速派单保持一致)
list.reverse()
this.setData({
@@ -115,14 +141,14 @@ Page(createPage({
this.setSelectedType(list[0])
}
} else {
- throw new Error(res.data.msg || '加载失败')
+ throw new Error((res.data && res.data.msg) || '加载失败')
}
} catch (error) {
console.error('加载商品类型失败:', error)
this.setData({ isLoading: false })
wx.showToast({
- title: '加载类型失败',
- icon: 'error',
+ title: error.message || '加载类型失败',
+ icon: 'none',
duration: 2000
})
}
@@ -189,6 +215,9 @@ Page(createPage({
onLaobanNameInput(e) {
this.setData({ laobanName: e.detail.value })
},
+ onWaibuDingdanIdInput(e) {
+ this.setData({ waibuDingdanId: e.detail.value })
+ },
onZhidingUidInput(e) {
this.setData({ zhidingUid: e.detail.value })
},
@@ -282,21 +311,29 @@ Page(createPage({
}
}
- // 4. 验证余额是否足够
+ // 4. 验证余额/额度是否足够
const balance = parseFloat(sjyue)
if (price > balance) {
- wx.showModal({
- title: '余额不足',
- content: `当前余额${sjyue}元,需要${jiage}元。请先充值。`,
- confirmText: '去充值',
- success: (res) => {
- if (res.confirm) {
- wx.navigateTo({
- url: '/pages/merchant-recharge/merchant-recharge'
- })
+ if (this.data.isStaffMode) {
+ wx.showModal({
+ title: '额度不足',
+ content: `当前可用额度${sjyue}元,需要${jiage}元。请联系商家老板划额度。`,
+ showCancel: false,
+ })
+ } else {
+ wx.showModal({
+ title: '余额不足',
+ content: `当前余额${sjyue}元,需要${jiage}元。请先充值。`,
+ confirmText: '去充值',
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({
+ url: '/pages/merchant-recharge/merchant-recharge'
+ })
+ }
}
- }
- })
+ })
+ }
return false
}
@@ -309,6 +346,7 @@ Page(createPage({
dingdanJieshao: '',
dingdanBeizhu: '',
laobanName: '',
+ waibuDingdanId: '',
zhidingUid: '',
jiage: '',
selectedLabelId: '',
@@ -338,6 +376,7 @@ Page(createPage({
dingdanJieshao: this.data.dingdanJieshao.trim(),
dingdanBeizhu: this.data.dingdanBeizhu.trim() || '',
laobanName: this.data.laobanName.trim(),
+ waibuDingdanId: this.data.waibuDingdanId.trim() || '',
zhidingUid: this.data.zhidingUid.trim() || '',
jiage: this.data.jiage,
// 新增字段
@@ -349,29 +388,31 @@ Page(createPage({
try {
const res = await request({
- url: '/dingdan/sjpaifa',
+ url: isStaffMode() ? STAFF_API.orderDispatch : '/dingdan/sjpaifa',
method: 'POST',
data: postData
})
if (res && res.data.code === 200) {
- // 派单成功
wx.showToast({
title: '派单成功',
icon: 'success',
duration: 2000
})
- // 更新全局变量中的商家信息(余额、发单量、流水)
const orderAmount = parseFloat(this.data.jiage)
- const app = getApp()
- if (app.globalData.shangjia) {
- const newBalance = parseFloat(app.globalData.shangjia.sjyue || '0') - orderAmount
- app.globalData.shangjia.sjyue = newBalance.toFixed(2)
- app.globalData.shangjia.fadanzong = (parseInt(app.globalData.shangjia.fadanzong || '0') + 1).toString()
- app.globalData.shangjia.riliushui = (parseFloat(app.globalData.shangjia.riliushui || '0') + orderAmount).toFixed(2)
- app.globalData.shangjia.yueliushui = (parseFloat(app.globalData.shangjia.yueliushui || '0') + orderAmount).toFixed(2)
- this.setData({ sjyue: app.globalData.shangjia.sjyue })
+ if (this.data.isStaffMode) {
+ this.loadShangjiaYue()
+ } else {
+ const app = getApp()
+ if (app.globalData.shangjia) {
+ const newBalance = parseFloat(app.globalData.shangjia.sjyue || '0') - orderAmount
+ app.globalData.shangjia.sjyue = newBalance.toFixed(2)
+ app.globalData.shangjia.fadanzong = (parseInt(app.globalData.shangjia.fadanzong || '0') + 1).toString()
+ app.globalData.shangjia.riliushui = (parseFloat(app.globalData.shangjia.riliushui || '0') + orderAmount).toFixed(2)
+ app.globalData.shangjia.yueliushui = (parseFloat(app.globalData.shangjia.yueliushui || '0') + orderAmount).toFixed(2)
+ this.setData({ sjyue: app.globalData.shangjia.sjyue })
+ }
}
// 延迟重置表单,避免用户连续提交
diff --git a/pages/merchant-dispatch/merchant-dispatch.wxml b/pages/merchant-dispatch/merchant-dispatch.wxml
index 947aba1..b535bc2 100644
--- a/pages/merchant-dispatch/merchant-dispatch.wxml
+++ b/pages/merchant-dispatch/merchant-dispatch.wxml
@@ -2,12 +2,12 @@
- 可用余额
+ {{balanceLabel}}
{{sjyue}}
元
- 派单将从此余额扣除
+ {{balanceTip}}
@@ -84,6 +84,21 @@
/>
+
+
+
+ 拼多多订单号
+ 选填
+
+
+
+
diff --git a/pages/merchant-home/merchant-home.js b/pages/merchant-home/merchant-home.js
index f82958d..ec6ca8c 100644
--- a/pages/merchant-home/merchant-home.js
+++ b/pages/merchant-home/merchant-home.js
@@ -1,5 +1,13 @@
import { createPage, request, ensureRoleOnCenterPage } from '../../utils/base-page.js';
import { getOrderStatusText } from '../../utils/api-helper.js';
+import {
+ STAFF_API, isStaffMode, isMerchantPortalUser, refreshStaffContext, syncStaffUi,
+ restoreStaffContextAfterAuth, applyStaffStatsToPage, getStaffContext,
+} from '../../utils/staff-api.js';
+import { ensurePhoneAuth } from '../../utils/phone-auth.js';
+import { fetchGonggaoLunbo, isGonggaoCacheValid } from '../../utils/display-config';
+import { ICON_KEYS, resolveMiniappIcon } from '../../utils/miniapp-icons.js';
+import { fetchMerchantOrderStats, applyOrderStatsToHome } from '../../utils/merchant-order-stats.js';
const app = getApp();
@@ -12,46 +20,106 @@ Page(createPage({
statusBar: 20,
navBar: 44,
isShangjia: false,
+ isStaffMode: false,
+ staffRoleName: '',
+ quotaAvailable: '0.00',
+ canDispatch: true,
+ canStaffManage: true,
lunboList: [],
lunbozhanwei: '/images/lunbozhanwei.jpg',
gonggao: '',
swiperCurrent: 0,
imgUrls: {
- noticeIco: 'https://bintao.xmxym88.com/xcx/bintao/38.png',
- statCardBg: 'https://bintao.xmxym88.com/xcx/bintao/3.png',
- kefuKeyBtn: 'https://bintao.xmxym88.com/xcx/bintao/13.png',
- kefuListBtn: 'https://bintao.xmxym88.com/xcx/bintao/21.png',
+ noticeIco: '',
+ statCardBg: '',
+ kefuKeyBtn: '',
+ kefuListBtn: '',
+ iconRegular: '',
+ iconCustom: '',
},
stats: {
pendingCount: 0,
pendingAmount: '0.00',
todayDispatch: 0,
todayRefund: 0,
+ completedCount: 0,
+ completedAmount: '0.00',
+ refundCount: 0,
+ refundAmount: '0.00',
+ dispatchCount: 0,
+ dispatchAmount: '0.00',
},
recentOrders: [],
recentLoading: false,
},
- onLoad() {
+ async onLoad() {
const sys = wx.getSystemInfoSync();
this.setData({
statusBar: sys.statusBarHeight || 20,
navBar: (sys.statusBarHeight || 20) + 44,
lunbozhanwei: app.globalData.lunbozhanwei || '/images/lunbozhanwei.jpg',
});
+ if (wx.getStorageSync('token')) {
+ await restoreStaffContextAfterAuth();
+ }
this.checkRole();
- this.waitForConfigAndLoadBanner();
+ syncStaffUi(this);
+ this.setupImageUrls();
+ await this.waitForConfigAndLoadBanner();
+ if (this.data.isShangjia) {
+ await this.loadDashboard(false);
+ }
+ this._merchantHomeSessionReady = true;
+ this._skipShowRefresh = true;
this.checkColdStartPopup('shangjiaduan');
},
- onShow() {
+ async onShow() {
+ if (!app.globalData._shangjiaPhoneChecked) {
+ const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'shangjia' });
+ if (!phoneOk) return;
+ app.globalData._shangjiaPhoneChecked = true;
+ }
+
this.registerNotificationComponent();
+ // 先用本地缓存渲染,再向服务端同步子客服身份
this.checkRole();
+ syncStaffUi(this);
+ if (app.globalData.ossImageUrl || app.globalData.miniappIcons) {
+ this.setupImageUrls();
+ }
+ const token = wx.getStorageSync('token');
+ const isOwner = Number(wx.getStorageSync('shangjiastatus')) === 1;
+ if (token && !isOwner) {
+ await restoreStaffContextAfterAuth();
+ this.checkRole();
+ syncStaffUi(this);
+ } else if (isStaffMode()) {
+ await refreshStaffContext(request);
+ this.checkRole();
+ syncStaffUi(this);
+ applyStaffStatsToPage(this, getStaffContext());
+ }
+
if (this.data.isShangjia) {
ensureRoleOnCenterPage(this, 'shangjia');
- this.loadDashboard();
}
- this.loadBannerData();
+
+ if (this._skipShowRefresh) {
+ this._skipShowRefresh = false;
+ return;
+ }
+
+ const silent = this._merchantHomeSessionReady;
+ if (this.data.isShangjia) {
+ this.loadDashboard(silent);
+ }
+ if (silent) {
+ this.loadBannerData(true, true);
+ } else {
+ this.loadBannerData(false);
+ }
},
onPullDownRefresh() {
@@ -65,10 +133,36 @@ Page(createPage({
waitForConfigAndLoadBanner() {
if (app.globalData.ossImageUrl || app.globalData.apiBaseUrl) {
- this.loadBannerData(true);
- return;
+ this.setupImageUrls();
+ return this.loadBannerData(true);
}
- setTimeout(() => this.waitForConfigAndLoadBanner(), 100);
+ return new Promise((resolve) => {
+ const tick = () => {
+ if (app.globalData.ossImageUrl || app.globalData.apiBaseUrl) {
+ this.setupImageUrls();
+ this.loadBannerData(true).finally(resolve);
+ } else {
+ setTimeout(tick, 100);
+ }
+ };
+ tick();
+ });
+ },
+
+ setupImageUrls() {
+ const ossBase = app.globalData.ossImageUrl || '';
+ const homeDir = `${ossBase}beijing/shangjiaduan/home/`;
+ const icon = (key, fallback) => resolveMiniappIcon(app, key, fallback);
+ this.setData({
+ imgUrls: {
+ noticeIco: icon(ICON_KEYS.MERCHANT_HOME_NOTICE, `${homeDir}notice.png`),
+ statCardBg: icon(ICON_KEYS.MERCHANT_HOME_STAT_BG, `${ossBase}beijing/shangjiaduan/stat_card_bg.png`),
+ kefuKeyBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_KEY, `${homeDir}kefu_key.png`),
+ kefuListBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_LIST, `${homeDir}kefu_list.png`),
+ iconRegular: icon(ICON_KEYS.MERCHANT_HOME_REGULAR, `${homeDir}regular_dispatch.png`),
+ iconCustom: icon(ICON_KEYS.MERCHANT_HOME_CUSTOM, `${homeDir}custom_dispatch.png`),
+ },
+ });
},
processImageUrls(urlList) {
@@ -78,14 +172,13 @@ Page(createPage({
},
checkRole() {
- const ok = Number(wx.getStorageSync('shangjiastatus')) === 1;
- this.setData({ isShangjia: ok });
+ syncStaffUi(this);
},
- loadBannerData(forceFetch) {
+ loadBannerData(forceFetch, silent) {
const g = app.globalData || {};
const cachedList = g.shangpinlunbo || [];
- if (!forceFetch && cachedList.length) {
+ if (!forceFetch && isGonggaoCacheValid(app) && cachedList.length) {
this.setData({
lunboList: this.processImageUrls(cachedList),
gonggao: g.shangpingonggao || '',
@@ -93,45 +186,30 @@ Page(createPage({
});
return Promise.resolve();
}
- if (!forceFetch && g.shangpingonggao) {
+ return fetchGonggaoLunbo(app, 'merchant_home').then((data) => {
+ if (!data) return;
this.setData({
- lunboList: this.processImageUrls(cachedList),
- gonggao: g.shangpingonggao,
+ lunboList: this.processImageUrls(app.globalData.shangpinlunbo),
+ gonggao: app.globalData.shangpingonggao || '',
});
- return Promise.resolve();
- }
- const apiBase = g.apiBaseUrl || '';
- if (!apiBase) return Promise.resolve();
- return new Promise((resolve) => {
- wx.request({
- url: `${apiBase}/peizhi/shangpingonggao/`,
- method: 'POST',
- header: { 'content-type': 'application/json' },
- success: (res) => {
- if (res.statusCode === 200 && res.data) {
- const data = res.data;
- app.globalData.shangpingonggao = data.shangpingonggao || '';
- app.globalData.shangpinlunbo = data.shangpinlunbo || [];
- this.setData({
- lunboList: this.processImageUrls(app.globalData.shangpinlunbo),
- gonggao: app.globalData.shangpingonggao,
- });
- }
- },
- complete: resolve,
- });
- });
+ }).catch(() => {});
},
- async loadDashboard() {
+ async loadDashboard(silent = false) {
await Promise.all([
this.loadShangjiaBrief(),
this.loadPendingStats(),
- this.loadRecentOrders(),
+ this.loadRecentOrders(silent),
]);
},
async loadShangjiaBrief() {
+ if (isStaffMode()) {
+ const ctx = await refreshStaffContext(request);
+ syncStaffUi(this);
+ applyStaffStatsToPage(this, ctx);
+ return;
+ }
try {
const res = await request({
url: '/yonghu/shangjiaxinxi',
@@ -155,39 +233,24 @@ Page(createPage({
async loadPendingStats() {
try {
- const res = await request({
- url: '/dingdan/sjdingdanhq',
- method: 'POST',
- data: { zhuangtai_list: [8], page: 1, page_size: 20 },
- });
- if (res.data && (res.data.code === 0 || res.data.code === 200)) {
- const data = res.data.data || {};
- const list = data.list || [];
- let amount = 0;
- list.forEach((item) => {
- const v = parseFloat(item.jine || item.dingdan_jine || 0);
- if (!Number.isNaN(v)) amount += v;
- });
- this.setData({
- stats: {
- ...this.data.stats,
- pendingCount: data.pending_count != null ? data.pending_count : list.length,
- pendingAmount: amount.toFixed(2),
- },
- });
- }
+ const data = await fetchMerchantOrderStats(request, {});
+ applyOrderStatsToHome(this, data);
} catch (e) {
- console.error('待结算统计失败', e);
+ console.warn('待结算统计失败', e);
}
},
/** 最近订单:同订单页「全部」筛选,取最新若干条 */
- async loadRecentOrders() {
- if (this.data.recentLoading) return;
- this.setData({ recentLoading: true });
+ async loadRecentOrders(silent = false) {
+ if (this.data.recentLoading && !silent) return;
+ if (silent && this._recentOrdersRequesting) return;
+ if (!silent) {
+ this.setData({ recentLoading: true });
+ }
+ this._recentOrdersRequesting = true;
try {
const res = await request({
- url: '/dingdan/sjdingdanhq',
+ url: isStaffMode() ? STAFF_API.orderList : '/dingdan/sjdingdanhq',
method: 'POST',
data: {
zhuangtai_list: ALL_ORDER_ZHUANGTAI,
@@ -206,7 +269,7 @@ Page(createPage({
return {
dingdan_id: item.dingdan_id,
title: item.jieshao || '暂无描述',
- time: item.create_time || '',
+ time: item.create_time || item.CreateTime || '',
status: getOrderStatusText(item.zhuangtai),
money: item.jine || '0.00',
raw,
@@ -217,7 +280,10 @@ Page(createPage({
} catch (e) {
console.error('最近订单加载失败', e);
} finally {
- this.setData({ recentLoading: false });
+ this._recentOrdersRequesting = false;
+ if (!silent) {
+ this.setData({ recentLoading: false });
+ }
}
},
@@ -225,12 +291,24 @@ Page(createPage({
this.setData({ swiperCurrent: e.detail.current });
},
- goDispatch() {
+ goRegularDispatch() {
+ wx.navigateTo({ url: '/pages/merchant-regular-dispatch/merchant-regular-dispatch' });
+ },
+
+ goLinkDispatch() {
+ wx.navigateTo({ url: '/pages/express-order/express-order' });
+ },
+
+ goCustomDispatch() {
wx.navigateTo({ url: '/pages/merchant-dispatch/merchant-dispatch' });
},
+ goDispatch() {
+ this.goCustomDispatch();
+ },
+
goExpress() {
- wx.navigateTo({ url: '/pages/express-order/express-order' });
+ this.goLinkDispatch();
},
goOrdersTab() {
diff --git a/pages/merchant-home/merchant-home.wxml b/pages/merchant-home/merchant-home.wxml
index 354e576..49adef1 100644
--- a/pages/merchant-home/merchant-home.wxml
+++ b/pages/merchant-home/merchant-home.wxml
@@ -7,7 +7,7 @@
-
+
商家入驻
完成入驻后可发单、管理订单
@@ -18,6 +18,11 @@
+
+
+ {{gonggao}}
+
+
@@ -34,14 +39,21 @@
-
-
- {{gonggao}}
+
+ 商家客服 · {{staffRoleName}} · 可用额度 ¥{{quotaAvailable}}
-
-
-
+
+
+
+
+
+
+
+ 链接派单
+ 模板管理 · 生成链接
+
+
@@ -62,6 +74,28 @@
{{stats.pendingAmount}}
+
+
+ 成交总量
+ {{stats.completedCount}}
+
+
+
+ 成交总额(元)
+ {{stats.completedAmount}}
+
+
+
+
+ 退款总量
+ {{stats.refundCount}}
+
+
+
+ 退款总额(元)
+ {{stats.refundAmount}}
+
+
今日派单(数)
@@ -73,7 +107,7 @@
{{stats.todayRefund}}
-
+
diff --git a/pages/merchant-home/merchant-home.wxss b/pages/merchant-home/merchant-home.wxss
index 1945741..4a6d535 100644
--- a/pages/merchant-home/merchant-home.wxss
+++ b/pages/merchant-home/merchant-home.wxss
@@ -92,7 +92,7 @@ page {
display: flex;
align-items: center;
background: #fdf9db;
- margin: 0 24rpx;
+ margin: 12rpx 24rpx 0;
border-radius: 10rpx;
padding: 10rpx 16rpx;
}
@@ -111,11 +111,22 @@ page {
flex: 1;
}
+.sj-fadan-block {
+ margin: 16rpx 24rpx 0;
+ display: flex;
+ flex-direction: column;
+ gap: 10rpx;
+}
+
.sj-fadan-row {
display: flex;
- margin: 24rpx 20rpx 0;
- padding: 10rpx;
- gap: 8rpx;
+ margin: 0;
+ padding: 0;
+ gap: 16rpx;
+}
+
+.sj-fadan-row--link {
+ margin-top: 0;
}
.sj-fadan-img-btn {
@@ -125,18 +136,35 @@ page {
background-repeat: no-repeat;
}
-.sj-fadan-img-btn--left {
- background-image: url('https://bintao.xmxym88.com/xcx/bintao/74.png');
- margin-right: 8rpx;
+.sj-fadan-big-btn {
+ flex: 1;
+ height: 128rpx;
+ border-radius: 16rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.08);
}
-.sj-fadan-img-btn--right {
- background-image: url('https://bintao.xmxym88.com/xcx/bintao/76.png');
- margin-left: 8rpx;
+.sj-fadan-big-btn--link {
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+}
+
+.sj-fadan-big-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #492f00;
+}
+
+.sj-fadan-big-sub {
+ font-size: 22rpx;
+ color: #886633;
+ margin-top: 8rpx;
}
.merchant-stats {
- margin: 32rpx 25rpx 0;
+ margin: 12rpx 25rpx 0;
border-radius: 26rpx;
padding-bottom: 24rpx;
position: relative;
@@ -307,3 +335,16 @@ page {
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
+
+.staff-banner {
+ margin-top: 16rpx;
+ padding: 16rpx 24rpx;
+ background: #fff8e8;
+ border-radius: 12rpx;
+ border: 1rpx solid #f0d89a;
+}
+
+.staff-banner-txt {
+ font-size: 24rpx;
+ color: #8a6d2b;
+}
diff --git a/pages/merchant-kefu-key/merchant-kefu-key.js b/pages/merchant-kefu-key/merchant-kefu-key.js
index 07716c2..778c87e 100644
--- a/pages/merchant-kefu-key/merchant-kefu-key.js
+++ b/pages/merchant-kefu-key/merchant-kefu-key.js
@@ -1,60 +1,128 @@
-/** 客服邀请码/秘钥 - UI 预览,后端接入前使用 mock 数据 */
+/** 客服邀请码管理 — 对接 merchant-staff API */
+import request from '../../utils/request.js';
+import { STAFF_API } from '../../utils/staff-api.js';
+
Page({
data: {
statusBar: 20,
gudingCode: 'XQKF2026',
- kefuTips: '客服秘钥用于绑定子客服账号,后端接口就绪后将自动替换为真实数据。',
- sublist: [{ name: '全部' }, { name: '未使用' }, { name: '已使用' }],
+ kefuTips: '一次性邀请码绑定子客服,固定码仅展示不可绑定。',
+ sublist: [{ name: '全部', status: null }, { name: '未使用', status: 0 }, { name: '已使用', status: 1 }],
subCurrent: 0,
- list: [
- { id: 1, typeName: '财务', code: 'CW-8X2K9P', status: 0, adddate: '2026-06-10' },
- { id: 2, typeName: '总管', code: 'ZG-3M7N1Q', status: 1, adddate: '2026-06-08', usedate: '2026-06-12', user: { nickname: '客服小张', avatar: '/images/default-avatar.png' } },
- ],
+ list: [],
+ roles: [],
showQrcodeTips: false,
+ loading: false,
},
onLoad() {
const sys = wx.getSystemInfoSync();
this.setData({ statusBar: sys.statusBarHeight || 20 });
+ this.loadRoles();
+ this.loadList();
},
- goBack() {
- wx.navigateBack();
+ onShow() {
+ this.loadList();
},
+ async loadRoles() {
+ try {
+ const res = await request({ url: STAFF_API.roleList, method: 'POST' });
+ if (res.data && res.data.code === 0) {
+ this.setData({ roles: res.data.data.roles || [] });
+ }
+ } catch (e) {}
+ },
+
+ async loadList() {
+ const tab = this.data.sublist[this.data.subCurrent];
+ try {
+ const res = await request({
+ url: STAFF_API.inviteList,
+ method: 'POST',
+ data: tab.status === null ? {} : { status: tab.status },
+ });
+ if (res.data && res.data.code === 0) {
+ const d = res.data.data || {};
+ this.setData({
+ list: d.list || [],
+ gudingCode: d.gudingCode || 'XQKF2026',
+ });
+ }
+ } catch (e) {
+ wx.showToast({ title: '加载失败', icon: 'none' });
+ }
+ },
+
+ goBack() { wx.navigateBack(); },
+
copyFixed() {
wx.setClipboardData({ data: this.data.gudingCode });
},
switchSub(e) {
- this.setData({ subCurrent: Number(e.currentTarget.dataset.idx) });
+ this.setData({ subCurrent: Number(e.currentTarget.dataset.idx) }, () => this.loadList());
},
- addKey() {
- wx.showToast({ title: '后端接入后可添加', icon: 'none' });
+ async addKey() {
+ const roles = this.data.roles;
+ if (!roles.length) {
+ wx.showToast({ title: '暂无角色,请稍后重试', icon: 'none' });
+ return;
+ }
+ const names = roles.map(r => r.role_name);
+ wx.showActionSheet({
+ itemList: names,
+ success: async (r) => {
+ const role = roles[r.tapIndex];
+ wx.showLoading({ title: '生成中' });
+ try {
+ const res = await request({
+ url: STAFF_API.inviteCreate,
+ method: 'POST',
+ data: { role_id: role.id },
+ });
+ if (res.data && res.data.code === 0) {
+ wx.showToast({ title: '已生成', icon: 'success' });
+ this.loadList();
+ } else {
+ wx.showToast({ title: res.data.msg || '失败', icon: 'none' });
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+ });
},
copyCode(e) {
wx.setClipboardData({ data: e.currentTarget.dataset.code || '' });
},
- delKey() {
- wx.showToast({ title: '预览数据不可删除', icon: 'none' });
- },
-
- showTips() {
- this.setData({ showQrcodeTips: true });
- },
-
- closeTips() {
- this.setData({ showQrcodeTips: false });
- },
-
- previewQr() {
- wx.previewImage({
- urls: ['https://xy-1314784552.cos.ap-guangzhou.myqcloud.com/uploads/images/ewm.png'],
+ async delKey(e) {
+ const id = e.currentTarget.dataset.id;
+ if (!id) return;
+ const res = await request({
+ url: STAFF_API.inviteRevoke,
+ method: 'POST',
+ data: { id },
});
+ if (res.data && res.data.code === 0) {
+ wx.showToast({ title: '已作废' });
+ this.loadList();
+ } else {
+ wx.showToast({ title: res.data.msg || '失败', icon: 'none' });
+ }
},
+ showTips() { this.setData({ showQrcodeTips: true }); },
+ closeTips() { this.setData({ showQrcodeTips: false }); },
+ goAudit() {
+ wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit' });
+ },
+ goToRoleManage() {
+ wx.navigateTo({ url: '/pages/merchant-staff-role/merchant-staff-role' });
+ },
noop() {},
});
diff --git a/pages/merchant-kefu-key/merchant-kefu-key.wxml b/pages/merchant-kefu-key/merchant-kefu-key.wxml
index 76ea3a5..1696a56 100644
--- a/pages/merchant-kefu-key/merchant-kefu-key.wxml
+++ b/pages/merchant-kefu-key/merchant-kefu-key.wxml
@@ -26,6 +26,16 @@
添加
+
+ 角色与权限管理(资金池/划额度在此配置角色)
+ ›
+
+
+
+ 操作日志与客服排行
+ ›
+
+
秘钥使用方法
›
@@ -50,7 +60,6 @@
暂无卡密
- 预览 · 接口就绪后对接真实数据
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.js b/pages/merchant-kefu-list/merchant-kefu-list.js
index 20e28fe..8364979 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.js
+++ b/pages/merchant-kefu-list/merchant-kefu-list.js
@@ -1,47 +1,433 @@
-/** 客服列表 - UI 预览,mock 数据 */
+/** 客服列表 — 派单量 / 剩余额度 / 封禁解封 */
+
+import request from '../../utils/request.js';
+
+import { STAFF_API, isStaffMode } from '../../utils/staff-api.js';
+
+
+
+const app = getApp();
+
+
+
+function avatarUrl(path) {
+
+ if (!path) return '/images/default-avatar.png';
+
+ if (path.startsWith('http')) return path;
+
+ const oss = app.globalData.ossImageUrl || '';
+
+ const p = path.startsWith('/') ? path.slice(1) : path;
+
+ return oss ? oss + p : '/images/default-avatar.png';
+
+}
+
+
+
Page({
+
data: {
+
statusBar: 20,
- list: [
- {
- id: 1,
- nickname: '客服总管-阿星',
- avatar: '/images/default-avatar.png',
- uid: '1008601',
- isChief: true,
- isFinance: false,
- orderCount: 128,
- settleCount: 96,
- settleAmount: '12800.00',
- },
- {
- id: 2,
- nickname: '财务-小李',
- avatar: '/images/default-avatar.png',
- uid: '1008602',
- isChief: false,
- isFinance: true,
- orderCount: 56,
- settleCount: 52,
- settleAmount: '6800.00',
- },
- ],
+
+ list: [],
+
+ isOwner: false,
+
},
+
+
onLoad() {
+
const sys = wx.getSystemInfoSync();
- this.setData({ statusBar: sys.statusBarHeight || 20 });
+
+ this.setData({ statusBar: sys.statusBarHeight || 20, isOwner: !isStaffMode() });
+
+ this.loadList();
+
},
- goBack() {
- wx.navigateBack();
+
+
+ onShow() {
+
+ this.loadList();
+
+ },
+
+
+
+ formatList(raw) {
+
+ return (raw || []).map((item) => ({
+
+ ...item,
+
+ avatar: avatarUrl(item.avatar),
+
+ todayDispatchCount: item.todayDispatchCount != null ? item.todayDispatchCount : 0,
+
+ todayDispatchAmount: item.todayDispatchAmount || '0.00',
+
+ dispatchCount: item.dispatchCount != null ? item.dispatchCount : (item.orderCount || 0),
+
+ dispatchAmount: item.dispatchAmount || '0.00',
+
+ settleCount: item.settleCount != null ? item.settleCount : 0,
+
+ settleAmount: item.settleAmount || '0.00',
+
+ refundCount: item.refundCount != null ? item.refundCount : 0,
+
+ refundAmount: item.refundAmount || '0.00',
+
+ quotaAvailable: item.quota_available || '0.00',
+
+ quotaRevokable: item.quota_available || '0.00',
+
+ isSelf: !!item.isSelf,
+
+ }));
+
+ },
+
+
+
+ rejectSelf(id) {
+
+ const row = (this.data.list || []).find((x) => String(x.id) === String(id));
+
+ if (row && row.isSelf) {
+
+ wx.showToast({ title: '不能对本人操作', icon: 'none' });
+
+ return true;
+
+ }
+
+ return false;
+
+ },
+
+
+
+ async loadList() {
+
+ try {
+
+ const res = await request({ url: STAFF_API.memberList, method: 'POST' });
+
+ if (res.data && res.data.code === 0) {
+
+ const raw = (res.data.data && res.data.data.list) || [];
+
+ this.setData({ list: this.formatList(raw) });
+
+ }
+
+ } catch (e) {
+
+ wx.showToast({ title: '加载失败', icon: 'none' });
+
+ }
+
+ },
+
+
+
+ goBack() { wx.navigateBack(); },
+
+
+
+ goBack() { wx.navigateBack(); },
+
+ goStaffOrders(e) {
+ const id = e.currentTarget.dataset.id;
+ const label = e.currentTarget.dataset.label || '';
+ wx.redirectTo({
+ url: `/pages/merchant-orders/merchant-orders?staff_member_id=${id}&staff_label=${encodeURIComponent(label)}`,
+ });
+ },
+
+ onEditRemark(e) {
+ const id = e.currentTarget.dataset.id;
+ const oldRemark = e.currentTarget.dataset.remark || '';
+ wx.showModal({
+ title: '客服备注',
+ editable: true,
+ placeholderText: '如:晚班小李、财务小王',
+ content: oldRemark,
+ success: async (r) => {
+ if (!r.confirm) return;
+ const remark = (r.content || '').trim();
+ const res = await request({
+ url: STAFF_API.memberUpdateRemark,
+ method: 'POST',
+ data: { member_id: id, merchant_remark: remark },
+ });
+ wx.showToast({
+ title: (res.data && res.data.code === 0) ? '已保存' : (res.data.msg || '失败'),
+ icon: 'none',
+ });
+ this.loadList();
+ },
+ });
},
copyUid(e) {
+
wx.setClipboardData({ data: e.currentTarget.dataset.uid || '' });
+
},
- onAction(e) {
- wx.showToast({ title: '后端接入后生效', icon: 'none' });
+
+
+ async onAllocate(e) {
+
+ const id = e.currentTarget.dataset.id;
+
+ if (this.rejectSelf(id)) return;
+
+ wx.showModal({
+
+ title: '划额度',
+
+ editable: true,
+
+ placeholderText: '输入金额',
+
+ success: async (r) => {
+
+ if (!r.confirm || !r.content) return;
+
+ const res = await request({
+
+ url: STAFF_API.walletAllocate,
+
+ method: 'POST',
+
+ data: { member_id: id, amount: r.content },
+
+ });
+
+ wx.showToast({
+
+ title: (res.data && res.data.code === 0) ? '成功' : (res.data.msg || '失败'),
+
+ icon: 'none',
+
+ });
+
+ this.loadList();
+
+ },
+
+ });
+
},
+
+
+
+ async onRevoke(e) {
+
+ const id = e.currentTarget.dataset.id;
+
+ if (this.rejectSelf(id)) return;
+
+ const available = e.currentTarget.dataset.available || '0';
+
+ wx.showModal({
+
+ title: '收回额度',
+
+ editable: true,
+
+ placeholderText: `最多可收回 ${available} 元`,
+
+ success: async (r) => {
+
+ if (!r.confirm || !r.content) return;
+
+ const res = await request({
+
+ url: STAFF_API.walletRevoke,
+
+ method: 'POST',
+
+ data: { member_id: id, amount: r.content },
+
+ });
+
+ wx.showToast({
+
+ title: (res.data && res.data.code === 0) ? '已收回' : (res.data.msg || '失败'),
+
+ icon: 'none',
+
+ });
+
+ if (res.data && res.data.code === 0) this.loadList();
+
+ },
+
+ });
+
+ },
+
+
+
+ async onToggleDisable(e) {
+
+ const id = e.currentTarget.dataset.id;
+
+ if (this.rejectSelf(id)) return;
+
+ const disabled = e.currentTarget.dataset.disabled;
+
+ const action = disabled ? '解封' : '封禁';
+
+ wx.showModal({
+
+ title: `${action}客服`,
+
+ content: disabled ? '解封后该客服可继续登录操作' : '封禁后该客服无法使用商家端功能',
+
+ success: async (r) => {
+
+ if (!r.confirm) return;
+
+ const res = await request({
+
+ url: STAFF_API.memberDisable,
+
+ method: 'POST',
+
+ data: { member_id: id, disable: !disabled },
+
+ });
+
+ wx.showToast({ title: (res.data && res.data.msg) || action, icon: 'none' });
+
+ this.loadList();
+
+ },
+
+ });
+
+ },
+
+
+
+ async onRemove(e) {
+
+ const id = e.currentTarget.dataset.id;
+
+ wx.showModal({
+
+ title: '移除客服',
+
+ content: '移除后该用户可认证商家或绑定其他商家',
+
+ success: async (r) => {
+
+ if (!r.confirm) return;
+
+ const res = await request({
+
+ url: STAFF_API.memberRemove,
+
+ method: 'POST',
+
+ data: { member_id: id },
+
+ });
+
+ wx.showToast({ title: res.data.msg || '完成', icon: 'none' });
+
+ this.loadList();
+
+ },
+
+ });
+
+ },
+
+
+
+ async onAssignRole(e) {
+
+ const memberId = e.currentTarget.dataset.id;
+
+ if (this.rejectSelf(memberId)) return;
+
+ const rolesRes = await request({ url: STAFF_API.roleList, method: 'POST' });
+
+ const roles = (rolesRes.data && rolesRes.data.data && rolesRes.data.data.roles) || [];
+
+ if (!roles.length) {
+
+ wx.showToast({ title: '请先创建角色', icon: 'none' });
+
+ return;
+
+ }
+
+ wx.showActionSheet({
+
+ itemList: roles.map((r) => r.role_name),
+
+ success: async (r) => {
+
+ const role = roles[r.tapIndex];
+
+ const res = await request({
+
+ url: STAFF_API.memberUpdateRole,
+
+ method: 'POST',
+
+ data: { member_id: memberId, role_id: role.id },
+
+ });
+
+ const ok = res.data && res.data.code === 0;
+
+ const roleName = (res.data && res.data.data && res.data.data.role_name) || role.role_name;
+
+ wx.showToast({
+
+ title: ok ? `已设为${roleName}` : (res.data.msg || '失败'),
+
+ icon: 'none',
+
+ });
+
+ if (ok) this.loadList();
+
+ },
+
+ });
+
+ },
+
+
+
+ goRank() {
+
+ wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit?tab=rank' });
+
+ },
+
+
+
+ goAudit() {
+
+ wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit' });
+
+ },
+
});
+
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxml b/pages/merchant-kefu-list/merchant-kefu-list.wxml
index db7b934..a4684eb 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.wxml
+++ b/pages/merchant-kefu-list/merchant-kefu-list.wxml
@@ -1,47 +1,165 @@
+
+
+
‹
+
客服列表
+
+
+
+
-
+
+
+
+
+
+
+
{{item.nickname}}
+
+ {{item.role_name || '客服'}}
+
总管
+
+ 本人
+
财务
+
+ 已封禁
+
+
ID: {{item.uid}}
复制
+
+
+
+
+
+
+ 剩余额度
+
+ ¥{{item.quotaAvailable}}
+
+
+
+
- {{item.orderCount}}
- 接单数
+
+ {{item.todayDispatchCount}}
+
+ 今日派单
+
+
+
+ {{item.dispatchCount}}
+
+ 累计派单
+
+
+
+
+
{{item.settleCount}}
- 结算数
+
+ 结单数
+
+
- ¥{{item.settleAmount}}
- 结算金额
+
+ {{item.refundCount}}
+
+ 退款数
+
+
+
+
+
+
+
+ ¥{{item.todayDispatchAmount}}
+
+ 今日派单额
+
+
+
+
+
+ ¥{{item.dispatchAmount}}
+
+ 派单金额
+
+
+
+
+
+ ¥{{item.settleAmount}}
+
+ 结算金额
+
+
+
+
+
+ ¥{{item.refundAmount}}
+
+ 退款金额
+
+
+
+
+
- 查看订单
- 权限管理
- 删除
+ 备注
+ 查看订单
+
+
+
+ 划额度
+
+ 收回额度
+
+ 换角色
+
+ {{item.isDisabled ? '解封' : '封禁'}}
+
+ 移除
+
+
+
+ 本人账号不可在此操作,如需调整请联系商家老板
+
- 预览 · 接口就绪后对接真实数据
+
+ 暂无客服成员
+
+ 操作日志 ›
+
+ 客服排行 ›
+
+
+
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxss b/pages/merchant-kefu-list/merchant-kefu-list.wxss
index effefea..12a8fce 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.wxss
+++ b/pages/merchant-kefu-list/merchant-kefu-list.wxss
@@ -31,6 +31,34 @@
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
}
+.kefu-card.disabled-card { opacity: 0.72; }
+
+.badge-role {
+ font-size: 20rpx;
+ padding: 2rpx 10rpx;
+ background: #f0f0f0;
+ color: #666;
+ border-radius: 6rpx;
+ margin-left: 8rpx;
+}
+
+.badge-off {
+ background: #ffebee;
+ color: #c62828;
+}
+
+.quota-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12rpx 0 8rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ margin-bottom: 12rpx;
+}
+
+.quota-label { font-size: 24rpx; color: #888; }
+.quota-val { font-size: 30rpx; color: #C9A962; font-weight: 600; }
+
.kefu-av {
width: 88rpx;
height: 88rpx;
@@ -55,6 +83,15 @@
.badge-chief { background: #ffb508; }
.badge-finance { background: #1b6ef3; }
+.badge-self { background: #9e9e9e; }
+
+.self-tip {
+ margin-top: 16rpx;
+ padding: 16rpx 0 4rpx;
+ font-size: 24rpx;
+ color: #999;
+ text-align: center;
+}
.kefu-uid {
font-size: 24rpx;
@@ -75,12 +112,23 @@
border-bottom: 1rpx solid #f5f5f5;
}
+.amount-stats {
+ margin-top: 0;
+ border-top: none;
+ padding-top: 0;
+}
+
.stat-n {
font-size: 28rpx;
font-weight: 700;
color: #e67e22;
}
+.stat-amt {
+ font-size: 24rpx;
+ color: #c0392b;
+}
+
.stat-l {
font-size: 22rpx;
color: #999;
diff --git a/pages/merchant-order-detail/merchant-order-detail.js b/pages/merchant-order-detail/merchant-order-detail.js
index 25b5660..8c0afe0 100644
--- a/pages/merchant-order-detail/merchant-order-detail.js
+++ b/pages/merchant-order-detail/merchant-order-detail.js
@@ -1,835 +1,901 @@
-// pages/merchant-order-detail/merchant-order-detail.js - 商家订单详情(完整版,已添加罚款/退款操作及教程按钮)
-const app = getApp()
-import request from '../../utils/request.js'
-import PopupService from '../../services/popupService.js' // 新增:导入弹窗服务
-
-Page({
- data: {
- jibenShuju: {
- dingdan_id: '', tupian: '', jieshao: '', create_time: '',
- jine: '', nicheng: '', beizhu: '', zhuangtai: 0, fadanpingtai: 0
- },
- dashouInfo: { yonghuid: '', nicheng: '', avatar: '' },
- xiangxiShuju: {
- dashou_jiaofu: [], dashou_liuyan: '', tuikuan_liyou: '', shangjia_liuyan: ''
- },
- fadanData: null,
- fenhongLilv: 0,
- xinDingdanId: '',
- zhuangtaiYanseMap: {
- 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0',
- 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1'
- },
- zhuangtaiWenziMap: {
- 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中',
- 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中'
- },
- isLoading: true,
- showChexiaoModal: false, chexiaoLiyou: '', isChexiaoLoading: false,
- showTuikuanModal: false, tuikuanLiyou: '', isTuikuanLoading: false,
- showFakuanModal: false, fakuanLiyou: '', fakuanJine: '', yingxiangQiangdan: true, isFakuanLoading: false,
- showGhDashouModal: false, isGhDashouLoading: false,
- showJiesuanConfirm: false, isJiesuanLoading: false,
- jiesuanPingfen: 0, jiesuanLiuyan: '',
- xingxingData: [
- { id: 1, active: false }, { id: 2, active: false }, { id: 3, active: false },
- { id: 4, active: false }, { id: 5, active: false }
- ],
- currentIMUserId: '',
-
- // ========== 新增:罚单/订单操作弹窗控制 ==========
- showModifyFakuanModal: false, // 修改罚款弹窗
- modifyFakuanLiyou: '', // 修改后的罚款理由
- modifyFakuanJine: '', // 修改后的罚款金额
- showCancelFakuanModal: false, // 撤销罚款弹窗
- cancelFakuanLiyou: '', // 撤销驳回理由
- showResubmitFakuanModal: false, // 再次申请罚款弹窗
- resubmitFakuanLiyou: '', // 再次申请的理由
- resubmitFakuanJine: '', // 再次申请的金额
- showCancelTuikuanModal: false, // 撤销退款申请弹窗
- cancelTuikuanLiyou: '', // 撤销退款理由
- showModifyTuikuanModal: false, // 修改退款理由弹窗
- modifyTuikuanLiyou: '', // 修改后的退款理由
- // 教程按钮状态
- tutorialBtnHidden: false
- },
-
- onLoad(options) {
- wx.setNavigationBarTitle({ title: '订单详情' })
- this.ensureIMConnection()
- this.jiexiTiaozhuanCanshu(options)
- // 新增:启动教程按钮定时器
- this.startTutorialBtnTimer()
- },
-
- onShow() {
- this.registerNotificationComponent()
- this.ensureIMConnection()
- },
-
- onHide() {
- // 页面隐藏时重置弹窗服务状态,避免影响其他页面
- PopupService.reset()
- },
-
- onUnload() {
- // 清除缩进定时器,避免内存泄漏
- if (this.tutorialTimer) {
- clearTimeout(this.tutorialTimer)
- }
- // 页面卸载时重置弹窗服务
- PopupService.reset()
- },
-
- registerNotificationComponent() {
- const notificationComp = this.selectComponent('#global-notification')
- if (notificationComp && notificationComp.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- }
- }
- },
-
- ensureIMConnection() {
- const uid = wx.getStorageSync('uid')
- if (!uid) return
- const targetUserId = 'Sj' + uid
- if (wx.goEasy && wx.goEasy.getConnectionStatus) {
- const status = wx.goEasy.getConnectionStatus()
- if (status === 'connected' || status === 'reconnected') {
- const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null
- if (currentUserId === targetUserId) {
- this.setData({ currentIMUserId: targetUserId })
- return
- } else {
- wx.goEasy.disconnect()
- }
- }
- }
- this.connectGoEasy(targetUserId)
- },
-
- connectGoEasy(userId) {
- let currentUser = app.globalData.currentUser
- if (!currentUser) {
- const uid = wx.getStorageSync('uid')
- currentUser = {
- id: uid,
- name: '用户' + (uid ? uid.substring(0, 6) : ''),
- avatar: app.globalData.ossImageUrl + app.globalData.morentouxiang
- }
- }
- wx.goEasy.connect({
- id: userId,
- data: {
- name: currentUser.name,
- avatar: currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang)
- },
- onSuccess: () => {
- this.setData({ currentIMUserId: userId })
- try {
- wx.setStorageSync('savedGoEasyConnection', JSON.stringify({
- userId, identityType: 'shangjia', lastConnectTime: Date.now()
- }))
- wx.setStorageSync('goEasyUserId', userId)
- } catch (e) {}
- },
- onFailed: (error) => {
- if (error.code === 408) {
- this.setData({ currentIMUserId: userId })
- } else {
- console.error('IM连接失败', error)
- }
- }
- })
- },
-
- jiexiTiaozhuanCanshu(options) {
- try {
- const dingdanDataStr = options.dingdanData || ''
- if (!dingdanDataStr) {
- wx.showToast({ title: '订单数据错误', icon: 'none' })
- setTimeout(() => wx.navigateBack(), 1500)
- return
- }
- const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr))
- let tupianUrl = dingdanData.tupian || ''
- if (!tupianUrl) tupianUrl = this.getTupianUrl()
- let jine = parseFloat(dingdanData.jine || 0)
- if (isNaN(jine)) jine = 0
- this.setData({
- 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '',
- 'jibenShuju.tupian': tupianUrl,
- 'jibenShuju.jieshao': dingdanData.jieshao || '',
- 'jibenShuju.create_time': dingdanData.create_time || '',
- 'jibenShuju.jine': jine.toFixed(2),
- 'jibenShuju.nicheng': dingdanData.nicheng || '',
- 'jibenShuju.beizhu': dingdanData.beizhu || '',
- 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0,
- 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0,
- isLoading: false
- })
- this.jiazaiXiangxiShuju(dingdanData.dingdan_id)
- } catch (error) {
- console.error('解析订单数据失败', error)
- wx.showToast({ title: '数据解析失败', icon: 'none' })
- setTimeout(() => wx.navigateBack(), 1500)
- }
- },
-
- getTupianUrl() {
- const cacheTouxiang = wx.getStorageSync('touxiang') || ''
- let tupianPath = cacheTouxiang || app.globalData.morentouxiang || ''
- const ossImageUrl = app.globalData.ossImageUrl || ''
- if (tupianPath && ossImageUrl) {
- if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1)
- return ossImageUrl + tupianPath
- }
- return ''
- },
-
- async jiazaiXiangxiShuju(dingdanId) {
- if (!dingdanId) return
- try {
- const res = await request({
- url: '/dingdan/sjddxq',
- method: 'POST',
- data: { dingdan_id: dingdanId },
- header: { 'content-type': 'application/json' }
- })
- if (res && res.data.code === 0 && res.data.data) {
- const d = res.data.data
- let jiaofuList = d.dashou_jiaofu || []
- jiaofuList = jiaofuList.map(url => {
- if (url && !url.startsWith('http')) {
- const oss = app.globalData.ossImageUrl || ''
- return oss + url
- }
- return url
- })
- let dashouAvatar = d.dashou_avatar || ''
- if (dashouAvatar && !dashouAvatar.startsWith('http')) {
- dashouAvatar = (app.globalData.ossImageUrl || '') + dashouAvatar
- }
- this.setData({
- 'dashouInfo.yonghuid': d.dashou_yonghuid || '',
- 'dashouInfo.nicheng': d.dashou_nicheng || '',
- 'dashouInfo.avatar': dashouAvatar,
- 'xiangxiShuju.dashou_jiaofu': jiaofuList,
- 'xiangxiShuju.dashou_liuyan': d.dashou_liuyan || '',
- 'xiangxiShuju.tuikuan_liyou': d.tuikuan_liyou || '',
- 'xiangxiShuju.shangjia_liuyan': d.shangjia_liuyan || '',
- fadanData: d.fadan || null,
- fenhongLilv: parseFloat(d.fenhong_lilv) || 0,
- xinDingdanId: d.xin_dingdan_id || '',
- 'jibenShuju.zhuangtai': d.zhuangtai || this.data.jibenShuju.zhuangtai
- })
- } else {
- wx.showToast({ title: res?.data?.msg || '获取详情失败', icon: 'none' })
- }
- } catch (err) {
- console.error('加载详情失败', err)
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- fuzhiWenben(e) {
- const text = e.currentTarget.dataset.text
- if (!text) return
- wx.setClipboardData({ data: text })
- wx.showToast({ title: '已复制', icon: 'success' })
- },
-
- yulanTupian(e) {
- const current = e.currentTarget.dataset.url
- const urls = e.currentTarget.dataset.urls || [current]
- wx.previewImage({ current, urls })
- },
-
- goToKefu() {
- const kefuLink = app.globalData.kefuConfig?.link || ''
- const corpId = app.globalData.kefuConfig?.enterpriseId || ''
- if (!kefuLink || !corpId) {
- wx.showToast({ title: '客服配置未加载', icon: 'none' })
- return
- }
- wx.openCustomerServiceChat({
- extInfo: { url: kefuLink },
- corpId: corpId,
- success: (res) => console.log('跳转客服成功', res),
- fail: (err) => {
- console.error('跳转客服失败', err)
- wx.showToast({ title: '暂时无法连接客服', icon: 'none' })
- }
- })
- },
-
- // ===== 联系打手(替打手订阅 + 发机器人消息 + 跳转) =====
- goToChatWithDashou() {
- const uid = wx.getStorageSync('uid')
- if (!uid) return
-
- const orderId = this.data.jibenShuju.dingdan_id
- if (!orderId) {
- wx.showToast({ title: '订单ID缺失', icon: 'none' })
- return
- }
-
- const targetUserId = 'Sj' + uid
- if (this.data.currentIMUserId !== targetUserId) {
- this.ensureIMConnection()
- wx.showToast({ title: '连接中,请稍后再试', icon: 'none' })
- return
- }
-
- const that = this
- const groupName = this.data.jibenShuju.nicheng + '的订单群'
- const isCross = this.data.jibenShuju.fadanpingtai || 0
- const dashouUid = this.data.dashouInfo.yonghuid
-
- // 第一步:商家自己订阅群组
- wx.goEasy.im.subscribeGroup({
- groupIds: [orderId],
- onSuccess: () => {
- // 如果有打手,则需要帮打手订阅并发送消息
- if (dashouUid) {
- that.bangDashouDingyue(orderId, dashouUid)
- .then(() => {
- that.tiaozhuanQunLiao(orderId, groupName, isCross)
- })
- .catch((err) => {
- console.error('替打手订阅失败,仍可跳转群聊', err)
- wx.showToast({ title: '通知接单员可能失败', icon: 'none' })
- that.tiaozhuanQunLiao(orderId, groupName, isCross)
- })
- } else {
- // 无打手,直接跳转
- that.tiaozhuanQunLiao(orderId, groupName, isCross)
- }
- },
- onFailed: (error) => {
- console.error('订阅群组失败', error)
- wx.showToast({ title: '连接群聊失败', icon: 'none' })
- }
- })
- },
-
- // 帮打手订阅群组 + 发送机器人消息
- bangDashouDingyue(orderId, dashouUid) {
- return new Promise((resolve, reject) => {
- const dashouImId = 'Ds' + dashouUid
- const appkey = 'BC-32e2991c69bc47e1b538e73aaed37fc1' // 你的GoEasy AppKey
- const restHost = 'https://rest-hz.goeasy.io'
-
- // 1. 通过 REST API 为打手订阅群组
- wx.request({
- url: restHost + '/v2/im/subscribe-groups',
- method: 'POST',
- header: { 'content-type': 'application/json' },
- data: {
- appkey: appkey,
- userIds: [dashouImId],
- groupIds: [orderId]
- },
- success: (res) => {
- if (res.data.code === 200) {
- // 2. 订阅成功后,以打手身份发送一条系统消息
- wx.request({
- url: restHost + '/v2/im/message',
- method: 'POST',
- header: { 'content-type': 'application/json' },
- data: {
- appkey: appkey,
- senderId: dashouImId,
- senderData: { name: '系统通知', avatar: '' },
- to: {
- type: 'group',
- id: orderId,
- data: { name: '订单群', avatar: '' }
- },
- type: 'text',
- payload: '此消息为系统自动发送,接单员看到后会尽快回复您。'
- },
- success: (msgRes) => {
- if (msgRes.data.code === 200) {
- resolve()
- } else {
- reject(new Error('发送消息失败'))
- }
- },
- fail: reject
- })
- } else {
- reject(new Error('订阅打手失败'))
- }
- },
- fail: reject
- })
- })
- },
-
- // 跳转群聊页面
- tiaozhuanQunLiao(orderId, groupName, isCross) {
- const param = {
- groupId: orderId,
- orderId: orderId,
- groupName: groupName,
- groupAvatar: '',
- isCross: isCross
- }
- wx.navigateTo({
- url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param))
- })
- },
-
- // ========== 以下所有业务功能完全保持不变 ==========
- showGhDashouConfirm() { this.setData({ showGhDashouModal: true }) },
- closeGhDashouModal() { this.setData({ showGhDashouModal: false }) },
- async tijiaoGhDashou() {
- if (this.data.isGhDashouLoading) return
- this.setData({ isGhDashouLoading: true })
- wx.showLoading({ title: '更换中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/zxsjghds',
- method: 'POST',
- data: { dingdan_id: this.data.jibenShuju.dingdan_id },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isGhDashouLoading: false, showGhDashouModal: false })
- if (res && res.data.code === 0) {
- this.setData({ xinDingdanId: res.data.data?.xin_dingdan_id || '' })
- wx.showToast({ title: '更换成功', icon: 'success' })
- this.jiazaiXiangxiShuju(this.data.jibenShuju.dingdan_id)
- } else {
- wx.showToast({ title: res?.data?.msg || '更换失败', icon: 'none' })
- }
- } catch (err) {
- wx.hideLoading()
- this.setData({ isGhDashouLoading: false, showGhDashouModal: false })
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- showFakuanModal() { this.setData({ showFakuanModal: true, fakuanLiyou: '', fakuanJine: '', yingxiangQiangdan: true }) },
- closeFakuanModal() { this.setData({ showFakuanModal: false }) },
- inputFakuanLiyou(e) { this.setData({ fakuanLiyou: e.detail.value.slice(0, 50) }) },
- inputFakuanJine(e) { this.setData({ fakuanJine: e.detail.value }) },
- toggleQiangdan() { this.setData({ yingxiangQiangdan: !this.data.yingxiangQiangdan }) },
- jisuanFenhong() {
- const jine = parseFloat(this.data.fakuanJine)
- if (isNaN(jine) || jine <= 0) return '0.00'
- return (jine * this.data.fenhongLilv).toFixed(2)
- },
- async tijiaoFakuan() {
- const { fakuanLiyou, fakuanJine, jibenShuju, dashouInfo } = this.data
- if (!fakuanLiyou.trim()) { wx.showToast({ title: '请输入罚款原因', icon: 'none' }); return }
- const jineNum = parseFloat(fakuanJine)
- if (isNaN(jineNum) || jineNum <= 0) { wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return }
- if (this.data.isFakuanLoading) return
- this.setData({ isFakuanLoading: true })
- wx.showLoading({ title: '提交中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/sjfksq',
- method: 'POST',
- data: {
- dingdan_id: jibenShuju.dingdan_id,
- chufa_liyou: fakuanLiyou,
- fakuanjine: jineNum.toFixed(2),
- yingxiang_qiangdan: this.data.yingxiangQiangdan ? 1 : 0,
- dashou_id: dashouInfo.yonghuid
- },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isFakuanLoading: false })
- if (res && res.data.code === 0) {
- wx.showToast({ title: '罚款申请已提交', icon: 'success' })
- this.setData({ showFakuanModal: false })
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id)
- } else {
- wx.showToast({ title: res?.data?.msg || '提交失败', icon: 'none' })
- }
- } catch (err) {
- wx.hideLoading()
- this.setData({ isFakuanLoading: false })
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- showChexiaoBtn() { this.setData({ showChexiaoModal: true, chexiaoLiyou: '' }) },
- closeChexiaoModal() { this.setData({ showChexiaoModal: false }) },
- shuruChexiaoLiyou(e) { this.setData({ chexiaoLiyou: e.detail.value.slice(0, 50) }) },
- async tijiaoChexiao() {
- if (this.data.isChexiaoLoading) return
- const { chexiaoLiyou, jibenShuju } = this.data
- if (!chexiaoLiyou.trim()) { wx.showToast({ title: '请输入撤销原因', icon: 'none' }); return }
- this.setData({ isChexiaoLoading: true })
- wx.showLoading({ title: '撤销中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/sjchexiao',
- method: 'POST',
- data: { dingdan_id: jibenShuju.dingdan_id, chexiao_liyou: chexiaoLiyou },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isChexiaoLoading: false })
- if (res && res.data.code === 0) {
- this.setData({ 'jibenShuju.zhuangtai': 5, showChexiaoModal: false })
- wx.showToast({ title: '撤销成功', icon: 'success' })
- } else {
- wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' })
- }
- } catch (err) {
- wx.hideLoading()
- this.setData({ isChexiaoLoading: false })
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- showTuikuanBtn() { this.setData({ showTuikuanModal: true, tuikuanLiyou: '' }) },
- closeTuikuanModal() { this.setData({ showTuikuanModal: false }) },
- shuruTuikuanLiyou(e) { this.setData({ tuikuanLiyou: e.detail.value.slice(0, 50) }) },
- async tijiaoTuikuan() {
- if (this.data.isTuikuanLoading) return
- const { tuikuanLiyou, jibenShuju } = this.data
- if (!tuikuanLiyou.trim()) { wx.showToast({ title: '请输入退款原因', icon: 'none' }); return }
- this.setData({ isTuikuanLoading: true })
- wx.showLoading({ title: '提交中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/sjtkshenqing',
- method: 'POST',
- data: { dingdan_id: jibenShuju.dingdan_id, tuikuan_liyou: tuikuanLiyou },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isTuikuanLoading: false })
- if (res && res.data.code === 0) {
- this.setData({ 'jibenShuju.zhuangtai': 4, showTuikuanModal: false })
- wx.showToast({ title: '退款申请已提交', icon: 'success' })
- } else {
- wx.showToast({ title: res?.data?.msg || '失败', icon: 'none' })
- }
- } catch (err) {
- wx.hideLoading()
- this.setData({ isTuikuanLoading: false })
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- dianjiXingxing(e) {
- const pf = e.currentTarget.dataset.index
- const newStars = this.data.xingxingData.map((item, idx) => ({ ...item, active: idx < pf }))
- this.setData({ xingxingData: newStars, jiesuanPingfen: pf })
- },
- shuruLiuyan(e) { this.setData({ jiesuanLiuyan: e.detail.value.slice(0, 50) }) },
- showJiesuanConfirm() { this.setData({ showJiesuanConfirm: true }) },
- closeJiesuanConfirm() { this.setData({ showJiesuanConfirm: false }) },
- async tijiaoJiesuan() {
- if (this.data.isJiesuanLoading) return
- this.setData({ isJiesuanLoading: true })
- wx.showLoading({ title: '结算中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/sjjiesuan',
- method: 'POST',
- data: {
- dingdan_id: this.data.jibenShuju.dingdan_id,
- pingfen: this.data.jiesuanPingfen,
- liuyan: this.data.jiesuanLiuyan
- },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isJiesuanLoading: false, showJiesuanConfirm: false })
- if (res && res.data.code === 0) {
- this.setData({ 'jibenShuju.zhuangtai': 3 })
- wx.showToast({ title: '结算成功', icon: 'success' })
- } else {
- wx.showToast({ title: res?.data?.msg || '结算失败', icon: 'none' })
- }
- } catch (err) {
- wx.hideLoading()
- this.setData({ isJiesuanLoading: false })
- wx.showToast({ title: '网络错误', icon: 'none' })
- }
- },
-
- // ========== 新增:罚款操作(修改/撤销/再次申请) ==========
- // 显示修改罚款弹窗(仅当状态为待缴纳 或 申诉中 时可用)
- showModifyFakuan() {
- const status = this.data.fadanData?.zhuangtai;
- if (status !== 1 && status !== 3) {
- wx.showToast({ title: '当前状态不可修改罚款', icon: 'none' });
- return;
- }
- this.setData({
- showModifyFakuanModal: true,
- modifyFakuanLiyou: this.data.fadanData?.chufaliyou || '',
- modifyFakuanJine: this.data.fadanData?.fakuanjine || ''
- });
- },
- closeModifyFakuanModal() {
- this.setData({ showModifyFakuanModal: false });
- },
- inputModifyFakuanLiyou(e) {
- this.setData({ modifyFakuanLiyou: e.detail.value.slice(0, 100) });
- },
- inputModifyFakuanJine(e) {
- this.setData({ modifyFakuanJine: e.detail.value });
- },
- async submitModifyFakuan() {
- const { modifyFakuanLiyou, modifyFakuanJine, fadanData, jibenShuju } = this.data;
- if (!modifyFakuanLiyou.trim()) {
- wx.showToast({ title: '请输入罚款理由', icon: 'none' }); return;
- }
- const jine = parseFloat(modifyFakuanJine);
- if (isNaN(jine) || jine <= 0) {
- wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return;
- }
- wx.showLoading({ title: '提交中...', mask: true });
- try {
- const res = await request({
- url: '/dingdan/sjfkxgycx',
- method: 'POST',
- data: {
- operation: 'modify_penalty',
- fadan_id: fadanData.id,
- dingdan_id: jibenShuju.dingdan_id,
- liyou: modifyFakuanLiyou,
- jine: jine.toFixed(2)
- }
- });
- wx.hideLoading();
- if (res && res.data.code === 0) {
- wx.showToast({ title: '修改成功', icon: 'success' });
- this.setData({ showModifyFakuanModal: false });
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id); // 刷新数据
- } else {
- wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
- }
- } catch (err) {
- wx.hideLoading();
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- // 显示撤销罚款弹窗(待缴纳/申诉中 可撤销,变为已驳回)
- showCancelFakuan() {
- const status = this.data.fadanData?.zhuangtai;
- if (status !== 1 && status !== 3) {
- wx.showToast({ title: '当前状态不可撤销罚款', icon: 'none' });
- return;
- }
- this.setData({ showCancelFakuanModal: true, cancelFakuanLiyou: '' });
- },
- closeCancelFakuanModal() {
- this.setData({ showCancelFakuanModal: false });
- },
- inputCancelFakuanLiyou(e) {
- this.setData({ cancelFakuanLiyou: e.detail.value.slice(0, 100) });
- },
- async submitCancelFakuan() {
- const { cancelFakuanLiyou, fadanData, jibenShuju } = this.data;
- if (!cancelFakuanLiyou.trim()) {
- wx.showToast({ title: '请输入驳回理由', icon: 'none' }); return;
- }
- wx.showLoading({ title: '提交中...', mask: true });
- try {
- const res = await request({
- url: '/dingdan/sjfkxgycx',
- method: 'POST',
- data: {
- operation: 'cancel_penalty',
- fadan_id: fadanData.id,
- dingdan_id: jibenShuju.dingdan_id,
- liyou: cancelFakuanLiyou
- }
- });
- wx.hideLoading();
- if (res && res.data.code === 0) {
- wx.showToast({ title: '已撤销', icon: 'success' });
- this.setData({ showCancelFakuanModal: false });
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
- } else {
- wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' });
- }
- } catch (err) {
- wx.hideLoading();
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- // 显示再次申请罚款弹窗(仅当状态为已驳回时可用)
- showResubmitFakuan() {
- if (this.data.fadanData?.zhuangtai !== 4) {
- wx.showToast({ title: '当前状态不可再次申请', icon: 'none' });
- return;
- }
- this.setData({
- showResubmitFakuanModal: true,
- resubmitFakuanLiyou: '',
- resubmitFakuanJine: ''
- });
- },
- closeResubmitFakuanModal() {
- this.setData({ showResubmitFakuanModal: false });
- },
- inputResubmitFakuanLiyou(e) {
- this.setData({ resubmitFakuanLiyou: e.detail.value.slice(0, 100) });
- },
- inputResubmitFakuanJine(e) {
- this.setData({ resubmitFakuanJine: e.detail.value });
- },
- async submitResubmitFakuan() {
- const { resubmitFakuanLiyou, resubmitFakuanJine, fadanData, jibenShuju } = this.data;
- if (!resubmitFakuanLiyou.trim()) {
- wx.showToast({ title: '请输入罚款理由', icon: 'none' }); return;
- }
- const jine = parseFloat(resubmitFakuanJine);
- if (isNaN(jine) || jine <= 0) {
- wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return;
- }
- wx.showLoading({ title: '提交中...', mask: true });
- try {
- const res = await request({
- url: '/dingdan/sjfkxgycx',
- method: 'POST',
- data: {
- operation: 'resubmit_penalty',
- fadan_id: fadanData.id,
- dingdan_id: jibenShuju.dingdan_id,
- liyou: resubmitFakuanLiyou,
- jine: jine.toFixed(2)
- }
- });
- wx.hideLoading();
- if (res && res.data.code === 0) {
- wx.showToast({ title: '申请成功', icon: 'success' });
- this.setData({ showResubmitFakuanModal: false });
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
- } else {
- wx.showToast({ title: res?.data?.msg || '申请失败', icon: 'none' });
- }
- } catch (err) {
- wx.hideLoading();
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- // ========== 新增:订单退款操作(撤销/修改理由) ==========
- showCancelTuikuan() {
- if (this.data.jibenShuju.zhuangtai !== 4) {
- wx.showToast({ title: '只有退款中的订单可撤销', icon: 'none' });
- return;
- }
- this.setData({ showCancelTuikuanModal: true, cancelTuikuanLiyou: '' });
- },
- closeCancelTuikuanModal() {
- this.setData({ showCancelTuikuanModal: false });
- },
- inputCancelTuikuanLiyou(e) {
- this.setData({ cancelTuikuanLiyou: e.detail.value.slice(0, 100) });
- },
- async submitCancelTuikuan() {
- const { cancelTuikuanLiyou, jibenShuju } = this.data;
- if (!cancelTuikuanLiyou.trim()) {
- wx.showToast({ title: '请输入撤销理由', icon: 'none' }); return;
- }
- wx.showLoading({ title: '撤销中...', mask: true });
- try {
- const res = await request({
- url: '/dingdan/sjfkxgycx',
- method: 'POST',
- data: {
- operation: 'cancel_refund',
- dingdan_id: jibenShuju.dingdan_id,
- liyou: cancelTuikuanLiyou
- }
- });
- wx.hideLoading();
- if (res && res.data.code === 0) {
- wx.showToast({ title: '已撤销退款申请', icon: 'success' });
- this.setData({ showCancelTuikuanModal: false });
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
- } else {
- wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' });
- }
- } catch (err) {
- wx.hideLoading();
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- showModifyTuikuan() {
- if (this.data.jibenShuju.zhuangtai !== 4) {
- wx.showToast({ title: '只有退款中的订单可修改理由', icon: 'none' });
- return;
- }
- this.setData({
- showModifyTuikuanModal: true,
- modifyTuikuanLiyou: this.data.xiangxiShuju.tuikuan_liyou || ''
- });
- },
- closeModifyTuikuanModal() {
- this.setData({ showModifyTuikuanModal: false });
- },
- inputModifyTuikuanLiyou(e) {
- this.setData({ modifyTuikuanLiyou: e.detail.value.slice(0, 100) });
- },
- async submitModifyTuikuan() {
- const { modifyTuikuanLiyou, jibenShuju } = this.data;
- if (!modifyTuikuanLiyou.trim()) {
- wx.showToast({ title: '请输入退款理由', icon: 'none' }); return;
- }
- wx.showLoading({ title: '修改中...', mask: true });
- try {
- const res = await request({
- url: '/dingdan/sjfkxgycx',
- method: 'POST',
- data: {
- operation: 'modify_refund_reason',
- dingdan_id: jibenShuju.dingdan_id,
- liyou: modifyTuikuanLiyou
- }
- });
- wx.hideLoading();
- if (res && res.data.code === 0) {
- wx.showToast({ title: '修改成功', icon: 'success' });
- this.setData({ showModifyTuikuanModal: false });
- this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
- } else {
- wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
- }
- } catch (err) {
- wx.hideLoading();
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- // ========== 新增:教程按钮 ==========
- startTutorialBtnTimer() {
- if (this.tutorialTimer) clearTimeout(this.tutorialTimer);
- this.tutorialTimer = setTimeout(() => {
- this.setData({ tutorialBtnHidden: true });
- }, 5000);
- },
- resetTutorialBtn() {
- if (this.data.tutorialBtnHidden) {
- this.setData({ tutorialBtnHidden: false });
- }
- if (this.tutorialTimer) clearTimeout(this.tutorialTimer);
- this.tutorialTimer = setTimeout(() => {
- this.setData({ tutorialBtnHidden: true });
- }, 5000);
- },
- onTutorialBtnTap() {
- this.resetTutorialBtn();
- PopupService.checkAndShow(this, 'sjddxq1');
- }
+// pages/merchant-order-detail/merchant-order-detail.js - 商家订单详情(完整版,已添加罚款/退款操作及教程按钮)
+const app = getApp()
+import request from '../../utils/request.js'
+import PopupService from '../../services/popupService.js' // 新增:导入弹窗服务
+import { STAFF_API, isStaffMode, syncStaffUi, getStaffContext, staffCan } from '../../utils/staff-api.js'
+
+/** 可申请罚款的订单状态:进行中/已完成/退款中/已退款/退款失败/结算中 */
+const PENALTY_APPLY_ORDER_STATUSES = [2, 3, 4, 5, 6, 8]
+
+function canApplyOrderPenalty({ zhuangtai, dashouYonghuid, fadanData, canPenalty }) {
+ return canPenalty
+ && !fadanData
+ && dashouYonghuid
+ && PENALTY_APPLY_ORDER_STATUSES.includes(Number(zhuangtai))
+}
+
+Page({
+ data: {
+ jibenShuju: {
+ dingdan_id: '', tupian: '', jieshao: '', create_time: '',
+ jine: '', nicheng: '', beizhu: '', waibu_dingdan_id: '', zhuangtai: 0, fadanpingtai: 0
+ },
+ dashouInfo: { yonghuid: '', nicheng: '', avatar: '' },
+ dispatchStaff: null,
+ dispatchStaffAvatar: '',
+ xiangxiShuju: {
+ dashou_jiaofu: [], dashou_liuyan: '', tuikuan_liyou: '', shangjia_liuyan: ''
+ },
+ fadanData: null,
+ fenhongLilv: 0,
+ xinDingdanId: '',
+ zhuangtaiYanseMap: {
+ 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0',
+ 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1'
+ },
+ zhuangtaiWenziMap: {
+ 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中',
+ 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中'
+ },
+ isLoading: true,
+ showChexiaoModal: false, chexiaoLiyou: '', isChexiaoLoading: false,
+ showTuikuanModal: false, tuikuanLiyou: '', isTuikuanLoading: false,
+ showFakuanModal: false, fakuanLiyou: '', fakuanJine: '', yingxiangQiangdan: true, isFakuanLoading: false,
+ showGhDashouModal: false, isGhDashouLoading: false,
+ showJiesuanConfirm: false, isJiesuanLoading: false,
+ jiesuanPingfen: 0, jiesuanLiuyan: '',
+ xingxingData: [
+ { id: 1, active: false }, { id: 2, active: false }, { id: 3, active: false },
+ { id: 4, active: false }, { id: 5, active: false }
+ ],
+ currentIMUserId: '',
+
+ // ========== 新增:罚单/订单操作弹窗控制 ==========
+ showModifyFakuanModal: false, // 修改罚款弹窗
+ modifyFakuanLiyou: '', // 修改后的罚款理由
+ modifyFakuanJine: '', // 修改后的罚款金额
+ showCancelFakuanModal: false, // 撤销罚款弹窗
+ cancelFakuanLiyou: '', // 撤销驳回理由
+ showResubmitFakuanModal: false, // 再次申请罚款弹窗
+ resubmitFakuanLiyou: '', // 再次申请的理由
+ resubmitFakuanJine: '', // 再次申请的金额
+ showCancelTuikuanModal: false, // 撤销退款申请弹窗
+ cancelTuikuanLiyou: '', // 撤销退款理由
+ showModifyTuikuanModal: false, // 修改退款理由弹窗
+ modifyTuikuanLiyou: '', // 修改后的退款理由
+ // 教程按钮状态
+ tutorialBtnHidden: false,
+ canCancel: true,
+ canRefund: true,
+ canSettle: true,
+ canPenalty: true,
+ canPenaltyManage: true,
+ canShowPenaltyApply: false,
+ },
+
+ refreshPenaltyApplyBtn() {
+ const { jibenShuju, dashouInfo, fadanData, canPenalty } = this.data
+ this.setData({
+ canShowPenaltyApply: canApplyOrderPenalty({
+ zhuangtai: jibenShuju.zhuangtai,
+ dashouYonghuid: dashouInfo.yonghuid,
+ fadanData,
+ canPenalty,
+ }),
+ })
+ },
+
+ onLoad(options) {
+ wx.setNavigationBarTitle({ title: '订单详情' })
+ syncStaffUi(this)
+ this.ensureIMConnection()
+ this.jiexiTiaozhuanCanshu(options)
+ // 新增:启动教程按钮定时器
+ this.startTutorialBtnTimer()
+ },
+
+ onShow() {
+ this.registerNotificationComponent()
+ syncStaffUi(this)
+ this.refreshPenaltyApplyBtn()
+ this.ensureIMConnection()
+ },
+
+ onHide() {
+ // 页面隐藏时重置弹窗服务状态,避免影响其他页面
+ PopupService.reset()
+ },
+
+ onUnload() {
+ // 清除缩进定时器,避免内存泄漏
+ if (this.tutorialTimer) {
+ clearTimeout(this.tutorialTimer)
+ }
+ // 页面卸载时重置弹窗服务
+ PopupService.reset()
+ },
+
+ registerNotificationComponent() {
+ const notificationComp = this.selectComponent('#global-notification')
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification()
+ }
+ }
+ },
+
+ ensureIMConnection() {
+ const uid = wx.getStorageSync('uid')
+ if (!uid) return
+ const targetUserId = 'Sj' + uid
+ if (wx.goEasy && wx.goEasy.getConnectionStatus) {
+ const status = wx.goEasy.getConnectionStatus()
+ if (status === 'connected' || status === 'reconnected') {
+ const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null
+ if (currentUserId === targetUserId) {
+ this.setData({ currentIMUserId: targetUserId })
+ return
+ } else {
+ wx.goEasy.disconnect()
+ }
+ }
+ }
+ this.connectGoEasy(targetUserId)
+ },
+
+ connectGoEasy(userId) {
+ let currentUser = app.globalData.currentUser
+ if (!currentUser) {
+ const uid = wx.getStorageSync('uid')
+ currentUser = {
+ id: uid,
+ name: '用户' + (uid ? uid.substring(0, 6) : ''),
+ avatar: app.globalData.ossImageUrl + app.globalData.morentouxiang
+ }
+ }
+ const staffCtx = isStaffMode() ? getStaffContext() : null
+ let imName = currentUser.name || wx.getStorageSync('nicheng') || '商家'
+ if (staffCtx) {
+ const roleLabel = staffCtx.role_name || '客服'
+ const nick = staffCtx.display_name || wx.getStorageSync('nicheng') || ''
+ imName = nick ? `${nick}(${roleLabel})` : roleLabel
+ }
+ wx.goEasy.connect({
+ id: userId,
+ data: {
+ name: imName,
+ avatar: currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang)
+ },
+ onSuccess: () => {
+ this.setData({ currentIMUserId: userId })
+ try {
+ wx.setStorageSync('savedGoEasyConnection', JSON.stringify({
+ userId, identityType: 'shangjia', lastConnectTime: Date.now()
+ }))
+ wx.setStorageSync('goEasyUserId', userId)
+ } catch (e) {}
+ },
+ onFailed: (error) => {
+ if (error.code === 408) {
+ this.setData({ currentIMUserId: userId })
+ } else {
+ console.error('IM连接失败', error)
+ }
+ }
+ })
+ },
+
+ jiexiTiaozhuanCanshu(options) {
+ const directId = options.dingdan_id || options.dingdanId || ''
+ if (directId) {
+ this.setData({
+ 'jibenShuju.dingdan_id': directId,
+ isLoading: false,
+ })
+ this.jiazaiXiangxiShuju(directId)
+ return
+ }
+ try {
+ const dingdanDataStr = options.dingdanData || ''
+ if (!dingdanDataStr) {
+ wx.showToast({ title: '订单数据错误', icon: 'none' })
+ setTimeout(() => wx.navigateBack(), 1500)
+ return
+ }
+ const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr))
+ let tupianUrl = dingdanData.tupian || ''
+ if (!tupianUrl) tupianUrl = this.getTupianUrl()
+ let jine = parseFloat(dingdanData.jine || 0)
+ if (isNaN(jine)) jine = 0
+ this.setData({
+ 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '',
+ 'jibenShuju.tupian': tupianUrl,
+ 'jibenShuju.jieshao': dingdanData.jieshao || '',
+ 'jibenShuju.create_time': dingdanData.create_time || '',
+ 'jibenShuju.jine': jine.toFixed(2),
+ 'jibenShuju.nicheng': dingdanData.nicheng || '',
+ 'jibenShuju.beizhu': dingdanData.beizhu || '',
+ 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0,
+ 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0,
+ isLoading: false
+ })
+ this.jiazaiXiangxiShuju(dingdanData.dingdan_id)
+ } catch (error) {
+ console.error('解析订单数据失败', error)
+ wx.showToast({ title: '数据解析失败', icon: 'none' })
+ setTimeout(() => wx.navigateBack(), 1500)
+ }
+ },
+
+ getTupianUrl() {
+ const cacheTouxiang = wx.getStorageSync('touxiang') || ''
+ let tupianPath = cacheTouxiang || app.globalData.morentouxiang || ''
+ const ossImageUrl = app.globalData.ossImageUrl || ''
+ if (tupianPath && ossImageUrl) {
+ if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1)
+ return ossImageUrl + tupianPath
+ }
+ return ''
+ },
+
+ async jiazaiXiangxiShuju(dingdanId) {
+ if (!dingdanId) return
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.orderDetail : '/dingdan/sjddxq',
+ method: 'POST',
+ data: { dingdan_id: dingdanId },
+ header: { 'content-type': 'application/json' }
+ })
+ if (res && res.data.code === 0 && res.data.data) {
+ const d = res.data.data
+ let jiaofuList = d.dashou_jiaofu || []
+ jiaofuList = jiaofuList.map(url => {
+ if (url && !url.startsWith('http')) {
+ const oss = app.globalData.ossImageUrl || ''
+ return oss + url
+ }
+ return url
+ })
+ let dashouAvatar = d.dashou_avatar || ''
+ if (dashouAvatar && !dashouAvatar.startsWith('http')) {
+ dashouAvatar = (app.globalData.ossImageUrl || '') + dashouAvatar
+ }
+ let dispatchStaffAvatar = (d.dispatch_staff && d.dispatch_staff.dispatch_staff_avatar) || ''
+ if (dispatchStaffAvatar && !dispatchStaffAvatar.startsWith('http')) {
+ const oss = app.globalData.ossImageUrl || ''
+ dispatchStaffAvatar = oss + (dispatchStaffAvatar.startsWith('/') ? dispatchStaffAvatar.slice(1) : dispatchStaffAvatar)
+ }
+ this.setData({
+ 'dashouInfo.yonghuid': d.dashou_yonghuid || '',
+ 'dashouInfo.nicheng': d.dashou_nicheng || '',
+ 'dashouInfo.avatar': dashouAvatar,
+ dispatchStaff: d.dispatch_staff || null,
+ dispatchStaffAvatar: dispatchStaffAvatar || '/images/default-avatar.png',
+ 'xiangxiShuju.dashou_jiaofu': jiaofuList,
+ 'xiangxiShuju.dashou_liuyan': d.dashou_liuyan || '',
+ 'xiangxiShuju.tuikuan_liyou': d.tuikuan_liyou || '',
+ 'xiangxiShuju.shangjia_liuyan': d.shangjia_liuyan || '',
+ fadanData: d.fadan || null,
+ fenhongLilv: parseFloat(d.fenhong_lilv) || 0,
+ xinDingdanId: d.xin_dingdan_id || '',
+ 'jibenShuju.zhuangtai': d.zhuangtai || this.data.jibenShuju.zhuangtai,
+ 'jibenShuju.waibu_dingdan_id': d.waibu_dingdan_id || '',
+ })
+ this.refreshPenaltyApplyBtn()
+ } else {
+ wx.showToast({ title: res?.data?.msg || '获取详情失败', icon: 'none' })
+ }
+ } catch (err) {
+ console.error('加载详情失败', err)
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ fuzhiWenben(e) {
+ const text = e.currentTarget.dataset.text
+ if (!text) return
+ wx.setClipboardData({ data: text })
+ wx.showToast({ title: '已复制', icon: 'success' })
+ },
+
+ yulanTupian(e) {
+ const current = e.currentTarget.dataset.url
+ const urls = e.currentTarget.dataset.urls || [current]
+ wx.previewImage({ current, urls })
+ },
+
+ goToKefu() {
+ const kefuLink = app.globalData.kefuConfig?.link || ''
+ const corpId = app.globalData.kefuConfig?.enterpriseId || ''
+ if (!kefuLink || !corpId) {
+ wx.showToast({ title: '客服配置未加载', icon: 'none' })
+ return
+ }
+ wx.openCustomerServiceChat({
+ extInfo: { url: kefuLink },
+ corpId: corpId,
+ success: (res) => console.log('跳转客服成功', res),
+ fail: (err) => {
+ console.error('跳转客服失败', err)
+ wx.showToast({ title: '暂时无法连接客服', icon: 'none' })
+ }
+ })
+ },
+
+ // ===== 联系打手(替打手订阅 + 发机器人消息 + 跳转) =====
+ goToChatWithDashou() {
+ if (isStaffMode() && !staffCan('imChat')) {
+ wx.showToast({ title: '当前角色无订单聊天权限', icon: 'none' })
+ return
+ }
+ const uid = wx.getStorageSync('uid')
+ if (!uid) return
+
+ const orderId = this.data.jibenShuju.dingdan_id
+ if (!orderId) {
+ wx.showToast({ title: '订单ID缺失', icon: 'none' })
+ return
+ }
+
+ const targetUserId = 'Sj' + uid
+ if (this.data.currentIMUserId !== targetUserId) {
+ this.ensureIMConnection()
+ wx.showToast({ title: '连接中,请稍后再试', icon: 'none' })
+ return
+ }
+
+ const that = this
+ const groupName = this.data.jibenShuju.nicheng + '的订单群'
+ const isCross = this.data.jibenShuju.fadanpingtai || 0
+ const dashouUid = this.data.dashouInfo.yonghuid
+
+ // 第一步:商家自己订阅群组
+ wx.goEasy.im.subscribeGroup({
+ groupIds: [orderId],
+ onSuccess: () => {
+ // 如果有打手,则需要帮打手订阅并发送消息
+ if (dashouUid) {
+ that.bangDashouDingyue(orderId, dashouUid)
+ .then(() => {
+ that.tiaozhuanQunLiao(orderId, groupName, isCross)
+ })
+ .catch((err) => {
+ console.error('替打手订阅失败,仍可跳转群聊', err)
+ wx.showToast({ title: '通知接单员可能失败', icon: 'none' })
+ that.tiaozhuanQunLiao(orderId, groupName, isCross)
+ })
+ } else {
+ // 无打手,直接跳转
+ that.tiaozhuanQunLiao(orderId, groupName, isCross)
+ }
+ },
+ onFailed: (error) => {
+ console.error('订阅群组失败', error)
+ wx.showToast({ title: '连接群聊失败', icon: 'none' })
+ }
+ })
+ },
+
+ // 帮打手订阅群组 + 发送机器人消息
+ bangDashouDingyue(orderId, dashouUid) {
+ return new Promise((resolve, reject) => {
+ const dashouImId = 'Ds' + dashouUid
+ const appkey = 'BC-32e2991c69bc47e1b538e73aaed37fc1' // 你的GoEasy AppKey
+ const restHost = 'https://rest-hz.goeasy.io'
+
+ // 1. 通过 REST API 为打手订阅群组
+ wx.request({
+ url: restHost + '/v2/im/subscribe-groups',
+ method: 'POST',
+ header: { 'content-type': 'application/json' },
+ data: {
+ appkey: appkey,
+ userIds: [dashouImId],
+ groupIds: [orderId]
+ },
+ success: (res) => {
+ if (res.data.code === 200) {
+ // 2. 订阅成功后,以打手身份发送一条系统消息
+ wx.request({
+ url: restHost + '/v2/im/message',
+ method: 'POST',
+ header: { 'content-type': 'application/json' },
+ data: {
+ appkey: appkey,
+ senderId: dashouImId,
+ senderData: { name: '系统通知', avatar: '' },
+ to: {
+ type: 'group',
+ id: orderId,
+ data: { name: '订单群', avatar: '' }
+ },
+ type: 'text',
+ payload: '此消息为系统自动发送,接单员看到后会尽快回复您。'
+ },
+ success: (msgRes) => {
+ if (msgRes.data.code === 200) {
+ resolve()
+ } else {
+ reject(new Error('发送消息失败'))
+ }
+ },
+ fail: reject
+ })
+ } else {
+ reject(new Error('订阅打手失败'))
+ }
+ },
+ fail: reject
+ })
+ })
+ },
+
+ // 跳转群聊页面
+ tiaozhuanQunLiao(orderId, groupName, isCross) {
+ const param = {
+ groupId: orderId,
+ orderId: orderId,
+ groupName: groupName,
+ groupAvatar: '',
+ isCross: isCross
+ }
+ wx.navigateTo({
+ url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param))
+ })
+ },
+
+ // ========== 以下所有业务功能完全保持不变 ==========
+ showGhDashouConfirm() { this.setData({ showGhDashouModal: true }) },
+ closeGhDashouModal() { this.setData({ showGhDashouModal: false }) },
+ async tijiaoGhDashou() {
+ if (this.data.isGhDashouLoading) return
+ this.setData({ isGhDashouLoading: true })
+ wx.showLoading({ title: '更换中...', mask: true })
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.changePlayer : '/dingdan/zxsjghds',
+ method: 'POST',
+ data: { dingdan_id: this.data.jibenShuju.dingdan_id },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isGhDashouLoading: false, showGhDashouModal: false })
+ if (res && res.data.code === 0) {
+ this.setData({ xinDingdanId: res.data.data?.xin_dingdan_id || '' })
+ wx.showToast({ title: '更换成功', icon: 'success' })
+ this.jiazaiXiangxiShuju(this.data.jibenShuju.dingdan_id)
+ } else {
+ wx.showToast({ title: res?.data?.msg || '更换失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ this.setData({ isGhDashouLoading: false, showGhDashouModal: false })
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ showFakuanModal() { this.setData({ showFakuanModal: true, fakuanLiyou: '', fakuanJine: '', yingxiangQiangdan: true }) },
+ closeFakuanModal() { this.setData({ showFakuanModal: false }) },
+ inputFakuanLiyou(e) { this.setData({ fakuanLiyou: e.detail.value.slice(0, 50) }) },
+ inputFakuanJine(e) { this.setData({ fakuanJine: e.detail.value }) },
+ toggleQiangdan() { this.setData({ yingxiangQiangdan: !this.data.yingxiangQiangdan }) },
+ jisuanFenhong() {
+ const jine = parseFloat(this.data.fakuanJine)
+ if (isNaN(jine) || jine <= 0) return '0.00'
+ return (jine * this.data.fenhongLilv).toFixed(2)
+ },
+ async tijiaoFakuan() {
+ const { fakuanLiyou, fakuanJine, jibenShuju, dashouInfo } = this.data
+ if (!fakuanLiyou.trim()) { wx.showToast({ title: '请输入罚款原因', icon: 'none' }); return }
+ const jineNum = parseFloat(fakuanJine)
+ if (isNaN(jineNum) || jineNum <= 0) { wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return }
+ if (this.data.isFakuanLoading) return
+ this.setData({ isFakuanLoading: true })
+ wx.showLoading({ title: '提交中...', mask: true })
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyApply : '/dingdan/sjfksq',
+ method: 'POST',
+ data: {
+ dingdan_id: jibenShuju.dingdan_id,
+ chufa_liyou: fakuanLiyou,
+ fakuanjine: jineNum.toFixed(2),
+ yingxiang_qiangdan: this.data.yingxiangQiangdan ? 1 : 0,
+ dashou_id: dashouInfo.yonghuid
+ },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isFakuanLoading: false })
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '罚款申请已提交', icon: 'success' })
+ this.setData({ showFakuanModal: false })
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id)
+ } else {
+ wx.showToast({ title: res?.data?.msg || '提交失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ this.setData({ isFakuanLoading: false })
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ showChexiaoBtn() { this.setData({ showChexiaoModal: true, chexiaoLiyou: '' }) },
+ closeChexiaoModal() { this.setData({ showChexiaoModal: false }) },
+ shuruChexiaoLiyou(e) { this.setData({ chexiaoLiyou: e.detail.value.slice(0, 50) }) },
+ async tijiaoChexiao() {
+ if (this.data.isChexiaoLoading) return
+ const { chexiaoLiyou, jibenShuju } = this.data
+ if (!chexiaoLiyou.trim()) { wx.showToast({ title: '请输入撤销原因', icon: 'none' }); return }
+ this.setData({ isChexiaoLoading: true })
+ wx.showLoading({ title: '撤销中...', mask: true })
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.orderCancel : '/dingdan/sjchexiao',
+ method: 'POST',
+ data: { dingdan_id: jibenShuju.dingdan_id, chexiao_liyou: chexiaoLiyou },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isChexiaoLoading: false })
+ if (res && res.data.code === 0) {
+ this.setData({ 'jibenShuju.zhuangtai': 5, showChexiaoModal: false })
+ this.refreshPenaltyApplyBtn()
+ wx.showToast({ title: '撤销成功', icon: 'success' })
+ } else {
+ wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ this.setData({ isChexiaoLoading: false })
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ showTuikuanBtn() { this.setData({ showTuikuanModal: true, tuikuanLiyou: '' }) },
+ closeTuikuanModal() { this.setData({ showTuikuanModal: false }) },
+ shuruTuikuanLiyou(e) { this.setData({ tuikuanLiyou: e.detail.value.slice(0, 50) }) },
+ async tijiaoTuikuan() {
+ if (this.data.isTuikuanLoading) return
+ const { tuikuanLiyou, jibenShuju } = this.data
+ if (!tuikuanLiyou.trim()) { wx.showToast({ title: '请输入退款原因', icon: 'none' }); return }
+ this.setData({ isTuikuanLoading: true })
+ wx.showLoading({ title: '提交中...', mask: true })
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.orderRefund : '/dingdan/sjtkshenqing',
+ method: 'POST',
+ data: { dingdan_id: jibenShuju.dingdan_id, tuikuan_liyou: tuikuanLiyou },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isTuikuanLoading: false })
+ if (res && res.data.code === 0) {
+ this.setData({ 'jibenShuju.zhuangtai': 4, showTuikuanModal: false })
+ this.refreshPenaltyApplyBtn()
+ wx.showToast({ title: '退款申请已提交', icon: 'success' })
+ } else {
+ wx.showToast({ title: res?.data?.msg || '失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ this.setData({ isTuikuanLoading: false })
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ dianjiXingxing(e) {
+ const pf = e.currentTarget.dataset.index
+ const newStars = this.data.xingxingData.map((item, idx) => ({ ...item, active: idx < pf }))
+ this.setData({ xingxingData: newStars, jiesuanPingfen: pf })
+ },
+ shuruLiuyan(e) { this.setData({ jiesuanLiuyan: e.detail.value.slice(0, 50) }) },
+ showJiesuanConfirm() { this.setData({ showJiesuanConfirm: true }) },
+ closeJiesuanConfirm() { this.setData({ showJiesuanConfirm: false }) },
+ async tijiaoJiesuan() {
+ if (this.data.isJiesuanLoading) return
+ this.setData({ isJiesuanLoading: true })
+ wx.showLoading({ title: '结算中...', mask: true })
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.orderSettle : '/dingdan/sjjiesuan',
+ method: 'POST',
+ data: {
+ dingdan_id: this.data.jibenShuju.dingdan_id,
+ pingfen: this.data.jiesuanPingfen,
+ liuyan: this.data.jiesuanLiuyan
+ },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isJiesuanLoading: false, showJiesuanConfirm: false })
+ if (res && res.data.code === 0) {
+ this.setData({ 'jibenShuju.zhuangtai': 3 })
+ this.refreshPenaltyApplyBtn()
+ wx.showToast({ title: '结算成功', icon: 'success' })
+ } else {
+ wx.showToast({ title: res?.data?.msg || '结算失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ this.setData({ isJiesuanLoading: false })
+ wx.showToast({ title: '网络错误', icon: 'none' })
+ }
+ },
+
+ // ========== 新增:罚款操作(修改/撤销/再次申请) ==========
+ // 显示修改罚款弹窗(仅当状态为待缴纳 或 申诉中 时可用)
+ showModifyFakuan() {
+ const status = this.data.fadanData?.zhuangtai;
+ if (status !== 1 && status !== 3) {
+ wx.showToast({ title: '当前状态不可修改罚款', icon: 'none' });
+ return;
+ }
+ this.setData({
+ showModifyFakuanModal: true,
+ modifyFakuanLiyou: this.data.fadanData?.chufaliyou || '',
+ modifyFakuanJine: this.data.fadanData?.fakuanjine || ''
+ });
+ },
+ closeModifyFakuanModal() {
+ this.setData({ showModifyFakuanModal: false });
+ },
+ inputModifyFakuanLiyou(e) {
+ this.setData({ modifyFakuanLiyou: e.detail.value.slice(0, 100) });
+ },
+ inputModifyFakuanJine(e) {
+ this.setData({ modifyFakuanJine: e.detail.value });
+ },
+ async submitModifyFakuan() {
+ const { modifyFakuanLiyou, modifyFakuanJine, fadanData, jibenShuju } = this.data;
+ if (!modifyFakuanLiyou.trim()) {
+ wx.showToast({ title: '请输入罚款理由', icon: 'none' }); return;
+ }
+ const jine = parseFloat(modifyFakuanJine);
+ if (isNaN(jine) || jine <= 0) {
+ wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return;
+ }
+ wx.showLoading({ title: '提交中...', mask: true });
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyManage : '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'modify_penalty',
+ fadan_id: fadanData.id,
+ dingdan_id: jibenShuju.dingdan_id,
+ liyou: modifyFakuanLiyou,
+ jine: jine.toFixed(2)
+ }
+ });
+ wx.hideLoading();
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '修改成功', icon: 'success' });
+ this.setData({ showModifyFakuanModal: false });
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id); // 刷新数据
+ } else {
+ wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ // 显示撤销罚款弹窗(待缴纳/申诉中 可撤销,变为已驳回)
+ showCancelFakuan() {
+ const status = this.data.fadanData?.zhuangtai;
+ if (status !== 1 && status !== 3) {
+ wx.showToast({ title: '当前状态不可撤销罚款', icon: 'none' });
+ return;
+ }
+ this.setData({ showCancelFakuanModal: true, cancelFakuanLiyou: '' });
+ },
+ closeCancelFakuanModal() {
+ this.setData({ showCancelFakuanModal: false });
+ },
+ inputCancelFakuanLiyou(e) {
+ this.setData({ cancelFakuanLiyou: e.detail.value.slice(0, 100) });
+ },
+ async submitCancelFakuan() {
+ const { cancelFakuanLiyou, fadanData, jibenShuju } = this.data;
+ if (!cancelFakuanLiyou.trim()) {
+ wx.showToast({ title: '请输入驳回理由', icon: 'none' }); return;
+ }
+ wx.showLoading({ title: '提交中...', mask: true });
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyManage : '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'cancel_penalty',
+ fadan_id: fadanData.id,
+ dingdan_id: jibenShuju.dingdan_id,
+ liyou: cancelFakuanLiyou
+ }
+ });
+ wx.hideLoading();
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '已撤销', icon: 'success' });
+ this.setData({ showCancelFakuanModal: false });
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
+ } else {
+ wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ // 显示再次申请罚款弹窗(仅当状态为已驳回时可用)
+ showResubmitFakuan() {
+ if (this.data.fadanData?.zhuangtai !== 4) {
+ wx.showToast({ title: '当前状态不可再次申请', icon: 'none' });
+ return;
+ }
+ this.setData({
+ showResubmitFakuanModal: true,
+ resubmitFakuanLiyou: '',
+ resubmitFakuanJine: ''
+ });
+ },
+ closeResubmitFakuanModal() {
+ this.setData({ showResubmitFakuanModal: false });
+ },
+ inputResubmitFakuanLiyou(e) {
+ this.setData({ resubmitFakuanLiyou: e.detail.value.slice(0, 100) });
+ },
+ inputResubmitFakuanJine(e) {
+ this.setData({ resubmitFakuanJine: e.detail.value });
+ },
+ async submitResubmitFakuan() {
+ const { resubmitFakuanLiyou, resubmitFakuanJine, fadanData, jibenShuju } = this.data;
+ if (!resubmitFakuanLiyou.trim()) {
+ wx.showToast({ title: '请输入罚款理由', icon: 'none' }); return;
+ }
+ const jine = parseFloat(resubmitFakuanJine);
+ if (isNaN(jine) || jine <= 0) {
+ wx.showToast({ title: '请输入正确的罚款金额', icon: 'none' }); return;
+ }
+ wx.showLoading({ title: '提交中...', mask: true });
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyManage : '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'resubmit_penalty',
+ fadan_id: fadanData.id,
+ dingdan_id: jibenShuju.dingdan_id,
+ liyou: resubmitFakuanLiyou,
+ jine: jine.toFixed(2)
+ }
+ });
+ wx.hideLoading();
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '申请成功', icon: 'success' });
+ this.setData({ showResubmitFakuanModal: false });
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
+ } else {
+ wx.showToast({ title: res?.data?.msg || '申请失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ // ========== 新增:订单退款操作(撤销/修改理由) ==========
+ showCancelTuikuan() {
+ if (this.data.jibenShuju.zhuangtai !== 4) {
+ wx.showToast({ title: '只有退款中的订单可撤销', icon: 'none' });
+ return;
+ }
+ this.setData({ showCancelTuikuanModal: true, cancelTuikuanLiyou: '' });
+ },
+ closeCancelTuikuanModal() {
+ this.setData({ showCancelTuikuanModal: false });
+ },
+ inputCancelTuikuanLiyou(e) {
+ this.setData({ cancelTuikuanLiyou: e.detail.value.slice(0, 100) });
+ },
+ async submitCancelTuikuan() {
+ const { cancelTuikuanLiyou, jibenShuju } = this.data;
+ if (!cancelTuikuanLiyou.trim()) {
+ wx.showToast({ title: '请输入撤销理由', icon: 'none' }); return;
+ }
+ wx.showLoading({ title: '撤销中...', mask: true });
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyManage : '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'cancel_refund',
+ dingdan_id: jibenShuju.dingdan_id,
+ liyou: cancelTuikuanLiyou
+ }
+ });
+ wx.hideLoading();
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '已撤销退款申请', icon: 'success' });
+ this.setData({ showCancelTuikuanModal: false });
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
+ } else {
+ wx.showToast({ title: res?.data?.msg || '撤销失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ showModifyTuikuan() {
+ if (this.data.jibenShuju.zhuangtai !== 4) {
+ wx.showToast({ title: '只有退款中的订单可修改理由', icon: 'none' });
+ return;
+ }
+ this.setData({
+ showModifyTuikuanModal: true,
+ modifyTuikuanLiyou: this.data.xiangxiShuju.tuikuan_liyou || ''
+ });
+ },
+ closeModifyTuikuanModal() {
+ this.setData({ showModifyTuikuanModal: false });
+ },
+ inputModifyTuikuanLiyou(e) {
+ this.setData({ modifyTuikuanLiyou: e.detail.value.slice(0, 100) });
+ },
+ async submitModifyTuikuan() {
+ const { modifyTuikuanLiyou, jibenShuju } = this.data;
+ if (!modifyTuikuanLiyou.trim()) {
+ wx.showToast({ title: '请输入退款理由', icon: 'none' }); return;
+ }
+ wx.showLoading({ title: '修改中...', mask: true });
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.penaltyManage : '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'modify_refund_reason',
+ dingdan_id: jibenShuju.dingdan_id,
+ liyou: modifyTuikuanLiyou
+ }
+ });
+ wx.hideLoading();
+ if (res && res.data.code === 0) {
+ wx.showToast({ title: '修改成功', icon: 'success' });
+ this.setData({ showModifyTuikuanModal: false });
+ this.jiazaiXiangxiShuju(jibenShuju.dingdan_id);
+ } else {
+ wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ // ========== 新增:教程按钮 ==========
+ startTutorialBtnTimer() {
+ if (this.tutorialTimer) clearTimeout(this.tutorialTimer);
+ this.tutorialTimer = setTimeout(() => {
+ this.setData({ tutorialBtnHidden: true });
+ }, 5000);
+ },
+ resetTutorialBtn() {
+ if (this.data.tutorialBtnHidden) {
+ this.setData({ tutorialBtnHidden: false });
+ }
+ if (this.tutorialTimer) clearTimeout(this.tutorialTimer);
+ this.tutorialTimer = setTimeout(() => {
+ this.setData({ tutorialBtnHidden: true });
+ }, 5000);
+ },
+ onTutorialBtnTap() {
+ this.resetTutorialBtn();
+ PopupService.checkAndShow(this, 'sjddxq1');
+ }
})
\ No newline at end of file
diff --git a/pages/merchant-order-detail/merchant-order-detail.wxml b/pages/merchant-order-detail/merchant-order-detail.wxml
index 5301cd6..0f6441b 100644
--- a/pages/merchant-order-detail/merchant-order-detail.wxml
+++ b/pages/merchant-order-detail/merchant-order-detail.wxml
@@ -1,354 +1,369 @@
-
-
-
-
-
-
-
-
- 加载中...
-
-
-
-
-
-
-
-
-
-
-
- {{jibenShuju.jieshao || '无描述'}}
-
-
-
-
-
- 订单信息
-
- 游戏昵称{{jibenShuju.nicheng}}
-
- 备注{{jibenShuju.beizhu}}
-
- 订单ID{{jibenShuju.dingdan_id}}📋
-
- 创建时间{{jibenShuju.create_time}}
-
- 订单金额¥{{jibenShuju.jine}}
-
- 状态{{zhuangtaiWenziMap[jibenShuju.zhuangtai]}}
-
-
- 撤销退款申请
- 修改退款理由
-
-
-
-
-
- 服务接单员
-
-
-
-
-
- 服务详情
-
-
- 交付图片
-
-
-
-
-
-
-
-
-
-
-
-
-
- 接单员留言
- {{xiangxiShuju.dashou_liuyan}}
-
-
-
- 退款理由
- {{xiangxiShuju.tuikuan_liyou}}
-
-
-
- 商家留言
- {{xiangxiShuju.shangjia_liuyan}}
-
-
-
-
-
- 罚款信息
-
- 罚款金额¥{{fadanData.fakuanjine || '0.00'}}
-
- 罚款理由{{fadanData.chufaliyou || '-'}}
-
- 是否影响抢单{{fadanData.yingxiang_qiangdan == 1 ? '是' : '否'}}
-
- 罚单状态{{fadanData.zhuangtai == 1 ? '待缴纳' : fadanData.zhuangtai == 2 ? '已缴纳' : fadanData.zhuangtai == 3 ? '申诉中' : '已驳回'}}
-
- 申诉理由{{fadanData.shensuliyou}}
-
- 同意处罚理由{{fadanData.tongyi_chufaliyou}}
-
- 驳回理由{{fadanData.bohuiliyou}}
-
- 创建时间{{fadanData.create_time}}
-
- 更新时间{{fadanData.update_time}}
-
-
-
-
- 修改罚款
- 撤销罚款
-
-
-
- 再次申请罚款
-
-
-
-
-
-
- 更换接单员成功
- 新订单ID{{xinDingdanId}}📋
-
-
-
-
- 订单结算
-
- 打星评分
-
-
-
-
- {{item.active ? '★' : '☆'}}
-
-
-
-
-
-
- 立即结算
-
-
-
-
-
-
-
- 联系客服
- 联系接单员
-
-
-
-
- 撤销订单
-
-
-
- 申请退款
-
-
-
-
-
-
-
- 撤销订单×
-
-
- 取消
- {{isChexiaoLoading ? '处理中' : '确认撤销'}}
-
-
-
-
-
-
-
-
- 申请退款×
-
-
- 取消
- {{isTuikuanLoading ? '处理中' : '确认申请'}}
-
-
-
-
-
-
-
-
- 更换接单员×
-
- 确认更换接单员吗?当前订单将被撤销,并生成一条相同内容的新订单(接单员清空)。
-
-
- 取消
- {{isGhDashouLoading ? '处理中' : '确认更换'}}
-
-
-
-
-
-
-
-
- 申请罚款×
-
- 罚款原因
-
- 罚款金额
-
-
- 是否影响抢单
-
-
-
-
- 此次罚款应得分红:¥{{jisuanFenhong()}}(利率 {{fenhongLilv*100}}%)
-
-
- 取消
- {{isFakuanLoading ? '处理中' : '确认申请'}}
-
-
-
-
-
-
-
-
- 确认结算×
-
- 确认结算该订单吗?结算后状态变为“已完成”。
-
-
- 取消
- {{isJiesuanLoading ? '处理中' : '确认结算'}}
-
-
-
-
-
-
-
-
- 修改罚款×
-
- 罚款理由
-
- 罚款金额
-
-
-
- 取消
- 确认修改
-
-
-
-
-
-
-
-
- 撤销罚款×
-
- 驳回理由
-
-
-
- 取消
- 确认撤销
-
-
-
-
-
-
-
-
- 再次申请罚款×
-
- 罚款理由
-
- 罚款金额
-
-
-
- 取消
- 确认申请
-
-
-
-
-
-
-
-
- 撤销退款申请×
-
- 撤销理由
-
-
-
- 取消
- 确认撤销
-
-
-
-
-
-
-
-
- 修改退款理由×
-
- 退款理由
-
-
-
- 取消
- 确认修改
-
-
-
-
-
-
-
-
-
- 教程
-
-
-
-
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+
+ {{jibenShuju.jieshao || '无描述'}}
+
+
+
+
+
+ 订单信息
+
+ 游戏昵称{{jibenShuju.nicheng}}
+
+ 备注{{jibenShuju.beizhu}}
+
+ 拼多多订单号{{jibenShuju.waibu_dingdan_id}}📋
+
+ 订单ID{{jibenShuju.dingdan_id}}📋
+
+ 创建时间{{jibenShuju.create_time}}
+
+ 订单金额¥{{jibenShuju.jine}}
+
+ 状态{{zhuangtaiWenziMap[jibenShuju.zhuangtai]}}
+
+
+ 派单客服
+
+
+
+
+ 撤销退款申请
+ 修改退款理由
+
+
+
+
+
+ 服务接单员
+
+
+
+
+
+ 服务详情
+
+
+ 交付图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 接单员留言
+ {{xiangxiShuju.dashou_liuyan}}
+
+
+
+ 退款理由
+ {{xiangxiShuju.tuikuan_liyou}}
+
+
+
+ 商家留言
+ {{xiangxiShuju.shangjia_liuyan}}
+
+
+
+
+
+ 罚款信息
+
+ 罚款金额¥{{fadanData.fakuanjine || '0.00'}}
+
+ 罚款理由{{fadanData.chufaliyou || '-'}}
+
+ 是否影响抢单{{fadanData.yingxiang_qiangdan == 1 ? '是' : '否'}}
+
+ 罚单状态{{fadanData.zhuangtai == 1 ? '待缴纳' : fadanData.zhuangtai == 2 ? '已缴纳' : fadanData.zhuangtai == 3 ? '申诉中' : '已驳回'}}
+
+ 申诉理由{{fadanData.shensuliyou}}
+
+ 同意处罚理由{{fadanData.tongyi_chufaliyou}}
+
+ 驳回理由{{fadanData.bohuiliyou}}
+
+ 创建时间{{fadanData.create_time}}
+
+ 更新时间{{fadanData.update_time}}
+
+
+
+ 修改罚款
+ 撤销罚款
+
+
+ 再次申请罚款
+
+
+
+
+
+
+ 更换接单员成功
+ 新订单ID{{xinDingdanId}}📋
+
+
+
+
+ 订单结算
+
+ 打星评分
+
+
+
+
+ {{item.active ? '★' : '☆'}}
+
+
+
+
+
+
+ 立即结算
+
+
+
+
+
+
+ 联系客服
+ 联系接单员
+
+
+ 撤销订单
+ 更换接单员
+ 申请退款
+ 申请罚款
+
+
+
+
+
+
+
+ 撤销订单×
+
+
+ 取消
+ {{isChexiaoLoading ? '处理中' : '确认撤销'}}
+
+
+
+
+
+
+
+
+ 申请退款×
+
+
+ 取消
+ {{isTuikuanLoading ? '处理中' : '确认申请'}}
+
+
+
+
+
+
+
+
+ 更换接单员×
+
+ 确认更换接单员吗?当前订单将被撤销,并生成一条相同内容的新订单(接单员清空,拼多多订单号将保留)。
+
+
+ 取消
+ {{isGhDashouLoading ? '处理中' : '确认更换'}}
+
+
+
+
+
+
+
+
+ 申请罚款×
+
+ 罚款原因
+
+ 罚款金额
+
+
+ 是否影响抢单
+
+
+
+
+ 此次罚款应得分红:¥{{jisuanFenhong()}}(利率 {{fenhongLilv*100}}%)
+
+
+ 取消
+ {{isFakuanLoading ? '处理中' : '确认申请'}}
+
+
+
+
+
+
+
+
+ 确认结算×
+
+ 确认结算该订单吗?结算后状态变为“已完成”。
+
+
+ 取消
+ {{isJiesuanLoading ? '处理中' : '确认结算'}}
+
+
+
+
+
+
+
+
+ 修改罚款×
+
+ 罚款理由
+
+ 罚款金额
+
+
+
+ 取消
+ 确认修改
+
+
+
+
+
+
+
+
+ 撤销罚款×
+
+ 驳回理由
+
+
+
+ 取消
+ 确认撤销
+
+
+
+
+
+
+
+
+ 再次申请罚款×
+
+ 罚款理由
+
+ 罚款金额
+
+
+
+ 取消
+ 确认申请
+
+
+
+
+
+
+
+
+ 撤销退款申请×
+
+ 撤销理由
+
+
+
+ 取消
+ 确认撤销
+
+
+
+
+
+
+
+
+ 修改退款理由×
+
+ 退款理由
+
+
+
+ 取消
+ 确认修改
+
+
+
+
+
+
+
+
+
+ 教程
+
+
+
+
\ No newline at end of file
diff --git a/pages/merchant-order-detail/merchant-order-detail.wxss b/pages/merchant-order-detail/merchant-order-detail.wxss
index 245d3d7..1f535be 100644
--- a/pages/merchant-order-detail/merchant-order-detail.wxss
+++ b/pages/merchant-order-detail/merchant-order-detail.wxss
@@ -1,185 +1,214 @@
-/* pages/merchant-order-detail/merchant-order-detail.wxss - 商家订单详情页样式(正方形九宫格,圆形头像) */
-/* 页面全局背景 */
-page { background: #f5f7fa; }
-/* 页面底部留出固定栏的空间 */
-.sjddxq-page { padding-bottom: 160rpx; }
-
-/* 加载状态居中布局 */
-.loading-container { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 60vh; }
-/* 加载旋转动画图标 */
-.loading-spinner { width: 64rpx; height: 64rpx; border: 6rpx solid #e0e0e0; border-top-color: #4caf50; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 20rpx; }
-
-/* 加载文字 */
-.loading-text { color: #666; font-size: 28rpx; }
-
-/* 内容区域的内边距 */
-.content-container { padding: 24rpx; }
-
-/* 通用卡片样式 */
-.card { background: #fff; border-radius: 24rpx; padding: 28rpx; margin-bottom: 24rpx; box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.04); }
-/* 卡片标题样式 */
-.card-title { font-size: 32rpx; font-weight: 600; color: #1a1a1a; margin-bottom: 20rpx; padding-bottom: 12rpx; border-bottom: 1rpx solid #f0f0f0; }
-
-/* 商品卡片:左右布局 */
-.shangpin-card { display: flex; align-items: center; }
-/* 商品图片:固定宽高为正方形 */
-.shangpin-img { width: 180rpx; height: 180rpx; border-radius: 16rpx; background: #f5f5f5; margin-right: 24rpx; flex-shrink: 0; }
-.shangpin-text { flex: 1; }
-.jieshao-text { font-size: 28rpx; color: #333; line-height: 1.6; }
-
-/* 信息行:左右分布,底部虚线 */
-.info-row { display: flex; justify-content: space-between; align-items: center; padding: 14rpx 0; border-bottom: 1rpx dashed #f5f5f5; }
-.info-row:last-child { border-bottom: none; }
-.label { font-size: 28rpx; color: #888; min-width: 140rpx; }
-.value { font-size: 28rpx; color: #333; text-align: right; word-break: break-all; }
-.value-with-copy { display: flex; align-items: center; }
-/* 复制按钮 */
-.copy-btn { margin-left: 12rpx; color: #4caf50; font-size: 26rpx; padding: 4rpx 12rpx; background: #e8f5e9; border-radius: 16rpx; }
-/* 红色价格 */
-.price-red { color: #ff4444; font-weight: 600; }
-.zhuangtai-text { font-weight: 600; }
-
-/* 打手卡片头部 */
-.dashou-header { display: flex; align-items: center; }
-/* 打手头像:固定宽高,圆形 */
-.dashou-avatar { width: 88rpx; height: 88rpx; border-radius: 50%; margin-right: 20rpx; }
-.dashou-detail { flex: 1; }
-.dashou-nicheng { font-size: 30rpx; font-weight: 500; margin-bottom: 6rpx; }
-.dashou-id-row { display: flex; align-items: center; font-size: 26rpx; }
-
-/* 服务详情子标题 */
-.sub-title { font-size: 28rpx; color: #555; margin: 16rpx 0 8rpx; }
-/* 内容框(留言、理由等) */
-.content-box { background: #f9f9f9; border-radius: 12rpx; padding: 16rpx; font-size: 26rpx; color: #444; line-height: 1.5; margin-bottom: 16rpx; }
-
-/* ========= 核心:交付图片九宫格,强制正方形 ========= */
-.image-grid { display: flex; flex-wrap: wrap; margin-bottom: 16rpx; }
-/* 每个图片的外层容器 */
-.grid-img-wrapper {
- width: calc(33.33% - 8rpx); /* 每行三个,减去间距 */
- margin: 4rpx;
- position: relative; /* 为绝对定位的图片提供锚点 */
- overflow: hidden;
- border-radius: 12rpx;
-}
-/* 使用伪元素撑出 1:1 的正方形高度 */
-.grid-img-wrapper::after {
- content: '';
- display: block;
- padding-bottom: 100%; /* 100% 相对于自身宽度,实现正方形 */
-}
-/* 图片绝对定位填满整个容器 */
-.grid-img {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- object-fit: cover; /* 保持比例裁剪,不变形 */
-}
-
-/* 结算区域:星星评分 */
-.star-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20rpx; }
-.stars { display: flex; }
-.star { font-size: 48rpx; color: #ccc; margin-left: 8rpx; transition: all 0.2s; }
-.star-active { color: #ffc107; transform: scale(1.1); }
-/* 留言输入框 */
-.liuyan-input { width: 100%; height: 120rpx; background: #f9f9f9; border-radius: 12rpx; padding: 16rpx; font-size: 28rpx; margin-bottom: 20rpx; }
-/* 结算按钮 */
-.jiesuan-btn { background: #4caf50; color: #fff; text-align: center; padding: 20rpx; border-radius: 48rpx; font-size: 30rpx; font-weight: 600; margin-top: 10rpx; }
-
-/* 底部固定操作栏 */
-.bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; padding: 16rpx 24rpx; box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.06); display: flex; flex-direction: column; gap: 12rpx; z-index: 100; }
-.bottom-btn-group { display: flex; gap: 16rpx; }
-.btn-outline { flex: 1; text-align: center; padding: 18rpx 0; border-radius: 44rpx; font-size: 28rpx; font-weight: 500; border: 2rpx solid #1976D2; color: #1976D2; background: #fff; }
-.btn-primary { background: #2196F3; color: #fff; flex: 1; text-align: center; padding: 18rpx 0; border-radius: 44rpx; font-weight: 600; font-size: 28rpx; }
-.btn-warn { background: #ff9800; color: #fff; flex: 1; text-align: center; padding: 18rpx 0; border-radius: 44rpx; font-weight: 600; font-size: 28rpx; }
-.btn-danger { background: #f44336; color: #fff; flex: 1; text-align: center; padding: 18rpx 0; border-radius: 44rpx; font-weight: 600; font-size: 28rpx; }
-
-/* 弹窗通用样式 */
-.modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; }
-.modal-mask { position: absolute; width: 100%; height: 100%; background: rgba(0,0,0,0.45); }
-.modal-content { position: relative; width: 620rpx; background: #fff; border-radius: 32rpx; overflow: hidden; }
-.modal-hd { padding: 32rpx; font-size: 34rpx; font-weight: 600; display: flex; justify-content: space-between; border-bottom: 1rpx solid #f0f0f0; }
-.modal-close { color: #999; font-size: 40rpx; }
-.modal-body { padding: 32rpx; }
-.modal-tip { font-size: 28rpx; color: #555; margin-bottom: 12rpx; }
-.modal-input { width: 100%; height: 140rpx; background: #f5f5f5; border-radius: 12rpx; padding: 16rpx; font-size: 28rpx; margin-bottom: 20rpx; }
-.modal-input-num { width: 100%; height: 80rpx; background: #f5f5f5; border-radius: 12rpx; padding: 0 20rpx; font-size: 32rpx; margin-bottom: 20rpx; }
-.toggle-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
-.toggle { width: 100rpx; height: 50rpx; border-radius: 50rpx; background: #e0e0e0; display: flex; align-items: center; padding: 0 4rpx; transition: background 0.2s; }
-.toggle-on { background: #4caf50; }
-.toggle-knob { width: 42rpx; height: 42rpx; border-radius: 50%; background: #fff; transition: transform 0.2s; }
-.toggle-on .toggle-knob { transform: translateX(50rpx); }
-.fenhong-tip { text-align: center; font-size: 28rpx; color: #ff9800; margin: 16rpx 0 0; }
-.modal-btns { display: flex; border-top: 1rpx solid #f0f0f0; }
-.modal-btn { flex: 1; text-align: center; padding: 28rpx; font-size: 30rpx; font-weight: 500; }
-.modal-btn.cancel { color: #888; background: #f5f5f5; }
-.modal-btn.confirm { color: #4caf50; background: #e8f5e9; }
-
-
-
-
-/* ========== 新增:罚单/订单操作按钮样式 ========== */
-.fakuan-actions, .refund-actions {
- display: flex;
- gap: 20rpx;
- margin-top: 24rpx;
- padding-top: 16rpx;
- border-top: 1rpx solid #f0f0f0;
-}
-.action-btn {
- flex: 1;
- text-align: center;
- padding: 16rpx 0;
- border-radius: 44rpx;
- font-size: 28rpx;
- font-weight: 500;
-}
-.action-modify {
- background: #2196F3;
- color: #fff;
-}
-.action-cancel {
- background: #ff9800;
- color: #fff;
-}
-.action-resubmit {
- background: #4caf50;
- color: #fff;
-}
-
-/* ========== 新增:教程按钮样式 ========== */
-.tutorial-btn {
- position: fixed;
- right: 0;
- top: 20%;
- transform: translateY(-50%);
- width: 120rpx;
- height: 120rpx;
- background: rgba(0, 0, 0, 0.75);
- backdrop-filter: blur(15rpx);
- border-radius: 60rpx 0 0 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10001;
- box-shadow: -8rpx 0 20rpx rgba(0,0,0,0.3);
- transition: right 0.3s ease-out;
- border: 2rpx solid rgba(255,215,0,0.5);
- border-right: none;
-}
-.tutorial-btn-text {
- color: #FFD700;
- font-size: 36rpx;
- font-weight: bold;
- writing-mode: vertical-rl;
- letter-spacing: 6rpx;
-}
-.tutorial-btn-hidden {
- right: -80rpx;
-}
-.tutorial-btn-hover {
- background: rgba(0, 0, 0, 0.9);
- transform: translateY(-50%) scale(1.05);
+/* pages/merchant-order-detail/merchant-order-detail.wxss - 商家订单详情(逍遥梦金色主题) */
+@import '../../styles/shangjia-xym-common.wxss';
+
+page { background: #fff8e1; }
+.sjddxq-page { padding-bottom: calc(200rpx + env(safe-area-inset-bottom)); }
+
+/* 加载状态居中布局 */
+.loading-container { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 60vh; }
+/* 加载旋转动画图标 */
+.loading-spinner { width: 64rpx; height: 64rpx; border: 6rpx solid #e0e0e0; border-top-color: #4caf50; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 20rpx; }
+
+/* 加载文字 */
+.loading-text { color: #666; font-size: 28rpx; }
+
+/* 内容区域的内边距 */
+.content-container { padding: 24rpx; }
+
+/* 通用卡片样式 */
+.card { background: #fdfcfa; border-radius: 24rpx; padding: 28rpx; margin-bottom: 24rpx; box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.06); border: 1rpx solid rgba(245, 213, 99, 0.25); }
+/* 卡片标题样式 */
+.card-title { font-size: 32rpx; font-weight: 600; color: #1a1a1a; margin-bottom: 20rpx; padding-bottom: 12rpx; border-bottom: 1rpx solid #f0f0f0; }
+
+/* 商品卡片:左右布局 */
+.shangpin-card { display: flex; align-items: center; }
+/* 商品图片:固定宽高为正方形 */
+.shangpin-img { width: 180rpx; height: 180rpx; border-radius: 16rpx; background: #f5f5f5; margin-right: 24rpx; flex-shrink: 0; }
+.shangpin-text { flex: 1; }
+.jieshao-text { font-size: 28rpx; color: #333; line-height: 1.6; }
+
+/* 信息行:左右分布,底部虚线 */
+.info-row { display: flex; justify-content: space-between; align-items: center; padding: 14rpx 0; border-bottom: 1rpx dashed #f5f5f5; }
+.info-row:last-child { border-bottom: none; }
+.label { font-size: 28rpx; color: #888; min-width: 140rpx; }
+.value { font-size: 28rpx; color: #333; text-align: right; word-break: break-all; }
+.value-with-copy { display: flex; align-items: center; }
+/* 复制按钮 */
+.copy-btn { margin-left: 12rpx; color: #4caf50; font-size: 26rpx; padding: 4rpx 12rpx; background: #e8f5e9; border-radius: 16rpx; }
+/* 红色价格 */
+.price-red { color: #ff4444; font-weight: 600; }
+.zhuangtai-text { font-weight: 600; }
+
+/* 打手卡片头部 */
+.dashou-header { display: flex; align-items: center; }
+/* 打手头像:固定宽高,圆形 */
+.dashou-avatar { width: 88rpx; height: 88rpx; border-radius: 50%; margin-right: 20rpx; }
+.dashou-detail { flex: 1; }
+.dashou-nicheng { font-size: 30rpx; font-weight: 500; margin-bottom: 6rpx; }
+.dashou-id-row { display: flex; align-items: center; font-size: 26rpx; }
+
+/* 服务详情子标题 */
+.sub-title { font-size: 28rpx; color: #555; margin: 16rpx 0 8rpx; }
+/* 内容框(留言、理由等) */
+.content-box { background: #f9f9f9; border-radius: 12rpx; padding: 16rpx; font-size: 26rpx; color: #444; line-height: 1.5; margin-bottom: 16rpx; }
+
+/* ========= 核心:交付图片九宫格,强制正方形 ========= */
+.image-grid { display: flex; flex-wrap: wrap; margin-bottom: 16rpx; }
+/* 每个图片的外层容器 */
+.grid-img-wrapper {
+ width: calc(33.33% - 8rpx); /* 每行三个,减去间距 */
+ margin: 4rpx;
+ position: relative; /* 为绝对定位的图片提供锚点 */
+ overflow: hidden;
+ border-radius: 12rpx;
+}
+/* 使用伪元素撑出 1:1 的正方形高度 */
+.grid-img-wrapper::after {
+ content: '';
+ display: block;
+ padding-bottom: 100%; /* 100% 相对于自身宽度,实现正方形 */
+}
+/* 图片绝对定位填满整个容器 */
+.grid-img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover; /* 保持比例裁剪,不变形 */
+}
+
+/* 结算区域:星星评分 */
+.star-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20rpx; }
+.stars { display: flex; }
+.star { font-size: 48rpx; color: #ccc; margin-left: 8rpx; transition: all 0.2s; }
+.star-active { color: #ffc107; transform: scale(1.1); }
+/* 留言输入框 */
+.liuyan-input { width: 100%; height: 120rpx; background: #f9f9f9; border-radius: 12rpx; padding: 16rpx; font-size: 28rpx; margin-bottom: 20rpx; }
+/* 结算按钮(卡片内) */
+.jiesuan-btn { margin-top: 10rpx; }
+
+/* 底部固定操作栏 */
+.bottom-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(180deg, rgba(255, 248, 225, 0.96), #fff8e1 30%);
+ padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
+ box-shadow: 0 -8rpx 28rpx rgba(0, 0, 0, 0.08);
+ display: flex;
+ flex-direction: column;
+ gap: 12rpx;
+ z-index: 100;
+ border-top: 1rpx solid rgba(245, 213, 99, 0.45);
+}
+
+.bottom-btn-group {
+ display: flex;
+ gap: 16rpx;
+ flex-wrap: wrap;
+}
+
+.sj-action-btn {
+ flex: 1;
+ min-width: 0;
+ text-align: center;
+ padding: 22rpx 12rpx;
+ border-radius: 60rpx;
+ font-size: 28rpx;
+ font-weight: 700;
+ box-sizing: border-box;
+}
+
+.sj-action-btn--gold {
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ border: 2rpx solid #fff;
+ box-shadow: 0 6rpx 18rpx rgba(245, 213, 99, 0.35);
+}
+
+.sj-action-btn--outline {
+ background: rgba(255, 255, 255, 0.95);
+ color: #492f00;
+ border: 2rpx solid #f5d563;
+}
+
+.sj-action-btn--warn {
+ background: linear-gradient(180deg, #ffb74d, #ff8a65);
+ color: #492f00;
+ border: 2rpx solid #fff;
+ box-shadow: 0 6rpx 16rpx rgba(255, 138, 101, 0.28);
+}
+
+.sj-action-btn--full {
+ flex: 1 1 100%;
+}
+
+/* 弹窗通用样式 */
+.modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; }
+.modal-mask { position: absolute; width: 100%; height: 100%; background: rgba(0,0,0,0.45); }
+.modal-content { position: relative; width: 620rpx; background: #fdfcfa; border-radius: 32rpx; overflow: hidden; border: 2rpx solid rgba(245, 213, 99, 0.4); }
+.modal-hd { padding: 32rpx; font-size: 34rpx; font-weight: 700; color: #492f00; display: flex; justify-content: space-between; border-bottom: 1rpx solid rgba(245, 213, 99, 0.35); }
+.modal-close { color: #999; font-size: 40rpx; }
+.modal-body { padding: 32rpx; }
+.modal-tip { font-size: 28rpx; color: #555; margin-bottom: 12rpx; }
+.modal-input { width: 100%; height: 140rpx; background: #f5f5f5; border-radius: 12rpx; padding: 16rpx; font-size: 28rpx; margin-bottom: 20rpx; }
+.modal-input-num { width: 100%; height: 80rpx; background: #f5f5f5; border-radius: 12rpx; padding: 0 20rpx; font-size: 32rpx; margin-bottom: 20rpx; }
+.toggle-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
+.toggle { width: 100rpx; height: 50rpx; border-radius: 50rpx; background: #e0e0e0; display: flex; align-items: center; padding: 0 4rpx; transition: background 0.2s; }
+.toggle-on { background: #4caf50; }
+.toggle-knob { width: 42rpx; height: 42rpx; border-radius: 50%; background: #fff; transition: transform 0.2s; }
+.toggle-on .toggle-knob { transform: translateX(50rpx); }
+.fenhong-tip { text-align: center; font-size: 28rpx; color: #ff9800; margin: 16rpx 0 0; }
+.modal-btns { display: flex; border-top: 1rpx solid #f0f0f0; }
+.modal-btn { flex: 1; text-align: center; padding: 28rpx; font-size: 30rpx; font-weight: 500; }
+.modal-btn.cancel { color: #886633; background: #fff8e1; }
+.modal-btn.confirm { color: #492f00; background: linear-gradient(180deg, #fae04d, #ffc0a3); font-weight: 700; }
+
+
+
+
+/* 罚单/退款操作按钮 */
+.fakuan-actions, .refund-actions {
+ display: flex;
+ gap: 20rpx;
+ margin-top: 24rpx;
+ padding-top: 16rpx;
+ border-top: 1rpx dashed rgba(245, 213, 99, 0.5);
+}
+
+/* ========== 新增:教程按钮样式 ========== */
+.tutorial-btn {
+ position: fixed;
+ right: 0;
+ top: 20%;
+ transform: translateY(-50%);
+ width: 120rpx;
+ height: 120rpx;
+ background: rgba(0, 0, 0, 0.75);
+ backdrop-filter: blur(15rpx);
+ border-radius: 60rpx 0 0 60rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10001;
+ box-shadow: -8rpx 0 20rpx rgba(0,0,0,0.3);
+ transition: right 0.3s ease-out;
+ border: 2rpx solid rgba(255,215,0,0.5);
+ border-right: none;
+}
+.tutorial-btn-text {
+ color: #FFD700;
+ font-size: 36rpx;
+ font-weight: bold;
+ writing-mode: vertical-rl;
+ letter-spacing: 6rpx;
+}
+.tutorial-btn-hidden {
+ right: -80rpx;
+}
+.tutorial-btn-hover {
+ background: rgba(0, 0, 0, 0.9);
+ transform: translateY(-50%) scale(1.05);
}
\ No newline at end of file
diff --git a/pages/merchant-orders/merchant-orders.js b/pages/merchant-orders/merchant-orders.js
index 8ae4cc6..65e3e32 100644
--- a/pages/merchant-orders/merchant-orders.js
+++ b/pages/merchant-orders/merchant-orders.js
@@ -3,17 +3,36 @@ const app = getApp();
import { createPage, request } from '../../utils/base-page.js';
import { reconnectForRole } from '../../utils/role-tab-bar.js';
import { getOrderStatusText } from '../../utils/api-helper.js';
+import { STAFF_API, isStaffMode, refreshStaffContext, syncStaffUi } from '../../utils/staff-api.js';
+import { ensurePhoneAuth } from '../../utils/phone-auth.js';
+import { normalizeOrderTags } from '../../utils/order-tags.js';
+import { ICON_KEYS, resolveMiniappIcon, MERCHANT_GOLD_BANNER_FALLBACK } from '../../utils/miniapp-icons.js';
+import { fetchMerchantOrderStats } from '../../utils/merchant-order-stats.js';
+
+const EMPTY_TAB = { list: [], page: 1, hasMore: true, isLoading: false };
+
+function buildEmptyStatusData() {
+ return {
+ all: { ...EMPTY_TAB },
+ jinxingzhong: { ...EMPTY_TAB },
+ tuikuanzhong: { ...EMPTY_TAB },
+ yituikuan: { ...EMPTY_TAB },
+ tuikuanshibai: { ...EMPTY_TAB },
+ yiwancheng: { ...EMPTY_TAB },
+ jiesuanzhong: { ...EMPTY_TAB },
+ };
+}
Page(createPage({
data: {
- // 商品类型(和打手端用同一个接口)
shangpinleixing: [],
xuanzhongLeixingId: null,
- // 搜索关键字(模糊搜索)
searchKeyword: '',
- // 状态列表(含全部)
+ timeStart: '',
+ timeEnd: '',
+
statusList: [
{ name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8], color: '#333333' },
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
@@ -21,75 +40,210 @@ Page(createPage({
{ name: '已退款', key: 'yituikuan', zhuangtaiList: [5], color: '#9E9E9E' },
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
- { name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' }
+ { name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' },
],
currentStatusKey: 'all',
- // 每个状态独立的数据集
- sjDingdanShuju: {
- all: { list: [], page: 1, hasMore: true, isLoading: false },
- jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false },
- tuikuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
- yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
- tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
- yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
- jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
- },
+ sjDingdanShuju: buildEmptyStatusData(),
currentList: [],
hasMore: true,
isLoading: false,
isLoadingMore: false,
scrollViewRefreshing: false,
+ listScrollTop: 0,
defaultImg: '/images/default-order.png',
ossImageUrl: app.globalData.ossImageUrl || '',
- // 待结算数量
pendingCount: 0,
+ goldBannerUrl: '',
+ staffList: [],
+ selectedStaffMemberId: '',
+ selectedStaffLabel: '全部客服',
+ canViewFinance: true,
+ orderStats: {
+ pending_count: 0,
+ pending_amount: '0.00',
+ completed_count: 0,
+ completed_amount: '0.00',
+ refund_count: 0,
+ refund_amount: '0.00',
+ dispatch_count: 0,
+ dispatch_amount: '0.00',
+ },
},
- onLoad() {
- wx.setNavigationBarTitle({ title: '我的派单' });
+ onLoad(options) {
+ this._listInitialized = false;
+ this._savedScrollTop = 0;
+ this._skipShowRefresh = false;
+ this.setData({
+ goldBannerUrl: resolveMiniappIcon(app, ICON_KEYS.MERCHANT_GOLD_BANNER, MERCHANT_GOLD_BANNER_FALLBACK),
+ });
+ wx.setNavigationBarTitle({ title: isStaffMode() ? '客服派单' : '我的派单' });
+ syncStaffUi(this);
+ if (isStaffMode()) {
+ refreshStaffContext(request).then(() => syncStaffUi(this));
+ }
this.loadShangpinLeixing();
this.registerNotificationComponent();
+ if (options && options.staff_member_id) {
+ this.setData({
+ selectedStaffMemberId: String(options.staff_member_id),
+ selectedStaffLabel: options.staff_label || '指定客服',
+ });
+ }
+ if (!isStaffMode()) {
+ this.loadStaffList();
+ }
},
- onShow() {
+ async onShow() {
+ const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'shangjia' });
+ if (!phoneOk) return;
+
this.registerNotificationComponent();
- this.loadPendingCount();
+ this.loadOrderStats();
if (wx.getStorageSync('uid')) {
reconnectForRole('shangjia');
if (app.startImWhenReady) app.startImWhenReady();
}
- if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
- this.loadCurrentStatusOrders(true);
+
+ if (this._skipShowRefresh) {
+ this._skipShowRefresh = false;
+ this.restoreListScroll();
+ return;
+ }
+
+ // 从详情返回:保持列表与滚动位置,不整页重载
+ if (this._listInitialized) {
+ this.restoreListScroll();
+ return;
+ }
+ },
+
+ restoreListScroll() {
+ const top = this._savedScrollTop || 0;
+ if (top <= 0) return;
+ this.setData({ listScrollTop: 0 });
+ wx.nextTick(() => {
+ this.setData({ listScrollTop: top });
+ });
+ },
+
+ onListScroll(e) {
+ this._savedScrollTop = e.detail.scrollTop || 0;
+ },
+
+ buildListParams(key, page) {
+ const statusItem = this.data.statusList.find((s) => s.key === key);
+ const params = {
+ zhuangtai_list: statusItem.zhuangtaiList,
+ page,
+ page_size: 5,
+ leixing_id: this.data.xuanzhongLeixingId,
+ keyword: this.data.searchKeyword || undefined,
+ };
+ const { timeStart, timeEnd } = this.data;
+ if (timeStart) params.start_time = `${timeStart} 00:00:00`;
+ if (timeEnd) params.end_time = `${timeEnd} 23:59:59`;
+ if (this.data.selectedStaffMemberId) {
+ params.staff_member_id = this.data.selectedStaffMemberId;
+ }
+ return params;
+ },
+
+ async loadStaffList() {
+ try {
+ const res = await request({ url: STAFF_API.memberList, method: 'POST' });
+ if (res.data && res.data.code === 0) {
+ const list = (res.data.data && res.data.data.list) || [];
+ this.setData({ staffList: list });
+ }
+ } catch (e) {
+ /* 非老板无权限时静默 */
+ }
+ },
+
+ onStaffFilterChange(e) {
+ const idx = Number(e.detail.value);
+ const list = this.data.staffList || [];
+ const row = list[idx];
+ if (!row) return;
+ this._savedScrollTop = 0;
+ this.setData({
+ selectedStaffMemberId: String(row.id),
+ selectedStaffLabel: row.nickname || row.uid,
+ listScrollTop: 0,
+ });
+ this.resetAllStatusData();
+ this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
+ },
+
+ clearStaffFilter() {
+ this._savedScrollTop = 0;
+ this.setData({
+ selectedStaffMemberId: '',
+ selectedStaffLabel: '全部客服',
+ listScrollTop: 0,
+ });
+ this.resetAllStatusData();
+ this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
+ },
+
+ async loadOrderStats() {
+ try {
+ const params = {};
+ const { timeStart, timeEnd, selectedStaffMemberId, xuanzhongLeixingId } = this.data;
+ if (timeStart) params.start_time = `${timeStart} 00:00:00`;
+ if (timeEnd) params.end_time = `${timeEnd} 23:59:59`;
+ if (selectedStaffMemberId) params.staff_member_id = selectedStaffMemberId;
+ if (xuanzhongLeixingId) params.leixing_id = xuanzhongLeixingId;
+
+ const data = await fetchMerchantOrderStats(request, params);
+ const order = data.order || {};
+ this.setData({
+ orderStats: {
+ pending_count: order.pending_count || 0,
+ pending_amount: order.pending_amount || '0.00',
+ completed_count: order.completed_count || 0,
+ completed_amount: order.completed_amount || '0.00',
+ refund_count: order.refund_count || 0,
+ refund_amount: order.refund_amount || '0.00',
+ dispatch_count: order.dispatch_count || 0,
+ dispatch_amount: order.dispatch_amount || '0.00',
+ },
+ pendingCount: order.pending_count || 0,
+ canViewFinance: data.can_view_finance !== false,
+ });
+ } catch (e) {
+ console.warn('订单统计失败', e);
}
},
- // 🆕 加载商品类型(和打手端用同一个接口 /dingdan/dsqdhqddlx)
async loadShangpinLeixing() {
try {
const res = await request({
url: '/dingdan/dsqdhqddlx',
method: 'POST',
- header: { 'content-type': 'application/json' }
+ header: { 'content-type': 'application/json' },
});
if (res.data && (res.data.code === 200 || res.data.code === 0)) {
let list = res.data.data.list || res.data.data || [];
if (!Array.isArray(list)) list = [];
const oss = this.data.ossImageUrl;
- // 拼接图片完整URL
- const processed = list.map(item => ({
+ const processed = list.map((item) => ({
...item,
full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http')
? oss + item.tupian_url
- : (item.tupian_url || '/images/default-type.png')
+ : (item.tupian_url || '/images/default-type.png'),
}));
this.setData({
shangpinleixing: processed,
- xuanzhongLeixingId: processed[0]?.id || null
+ xuanzhongLeixingId: processed[0]?.id || null,
});
- // 初始加载全部状态订单
this.loadCurrentStatusOrders(true);
}
} catch (e) {
@@ -97,16 +251,16 @@ Page(createPage({
}
},
- // 选择商品类型
selectLeixing(e) {
const id = e.currentTarget.dataset.id;
if (id === this.data.xuanzhongLeixingId) return;
- this.setData({ xuanzhongLeixingId: id });
- this.resetCurrentStatusData();
+ this._savedScrollTop = 0;
+ this.setData({ xuanzhongLeixingId: id, listScrollTop: 0 });
+ this.resetAllStatusData();
this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
},
- // 搜索输入(防抖)
onSearchInput(e) {
this.setData({ searchKeyword: e.detail.value });
if (this._searchTimer) clearTimeout(this._searchTimer);
@@ -115,26 +269,76 @@ Page(createPage({
}, 500);
},
- // 搜索确认
onSearchConfirm() {
- this.resetCurrentStatusData();
+ this._savedScrollTop = 0;
+ this.setData({ listScrollTop: 0 });
+ this.resetAllStatusData();
this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
},
- // 清除搜索
clearSearch() {
- this.setData({ searchKeyword: '' });
- this.resetCurrentStatusData();
+ this._savedScrollTop = 0;
+ this.setData({ searchKeyword: '', listScrollTop: 0 });
+ this.resetAllStatusData();
this.loadCurrentStatusOrders(true);
},
- // 切换状态Tab
+ onTimeStartChange(e) {
+ this.setData({ timeStart: e.detail.value }, () => this.triggerTimeFilterReload());
+ },
+
+ onTimeEndChange(e) {
+ this.setData({ timeEnd: e.detail.value }, () => this.triggerTimeFilterReload());
+ },
+
+ triggerTimeFilterReload() {
+ this._savedScrollTop = 0;
+ this.setData({ listScrollTop: 0 });
+ this.resetAllStatusData();
+ this.loadCurrentStatusOrders(true);
+ },
+
+ clearTimeFilter() {
+ this._savedScrollTop = 0;
+ this.setData({ timeStart: '', timeEnd: '', listScrollTop: 0 });
+ this.resetAllStatusData();
+ this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
+ },
+
+ pickQuickRange(e) {
+ const days = Number(e.currentTarget.dataset.days);
+ if (!days) {
+ this.clearTimeFilter();
+ return;
+ }
+ const end = new Date();
+ const start = new Date();
+ start.setDate(end.getDate() - (days - 1));
+ const fmt = (d) => {
+ const y = d.getFullYear();
+ const m = String(d.getMonth() + 1).padStart(2, '0');
+ const day = String(d.getDate()).padStart(2, '0');
+ return `${y}-${m}-${day}`;
+ };
+ this._savedScrollTop = 0;
+ this.setData({
+ timeStart: fmt(start),
+ timeEnd: fmt(end),
+ listScrollTop: 0,
+ });
+ this.resetAllStatusData();
+ this.loadCurrentStatusOrders(true);
+ this.loadOrderStats();
+ },
+
switchStatus(e) {
const key = e.currentTarget.dataset.key;
if (key === this.data.currentStatusKey) return;
- this.setData({ currentStatusKey: key });
+ this._savedScrollTop = 0;
+ this.setData({ currentStatusKey: key, listScrollTop: 0 });
const tabData = this.data.sjDingdanShuju[key];
- // 如果该状态没有数据,则加载;否则只刷新视图
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
this.loadCurrentStatusOrders(true);
} else {
@@ -142,67 +346,62 @@ Page(createPage({
}
},
- // 🆕 加载订单(核心方法,接口固定用商家订单接口 /dingdan/sjdingdanhq)
- async loadCurrentStatusOrders(isRefresh = false) {
+ async loadCurrentStatusOrders(isRefresh = false, pageOverride = null) {
const key = this.data.currentStatusKey;
const tabData = this.data.sjDingdanShuju[key];
if (tabData.isLoading) return;
- const page = isRefresh ? 1 : tabData.page;
+
+ const page = isRefresh ? 1 : (pageOverride || tabData.page + 1);
+ if (!isRefresh && !tabData.hasMore) return;
this.setData({
[`sjDingdanShuju.${key}.isLoading`]: true,
- isLoading: true,
- isLoadingMore: !isRefresh
+ isLoading: isRefresh && tabData.list.length === 0,
+ isLoadingMore: !isRefresh,
});
try {
- const statusItem = this.data.statusList.find(s => s.key === key);
- const zhuangtaiList = statusItem.zhuangtaiList;
-
- // 构建请求参数
- const params = {
- zhuangtai_list: zhuangtaiList,
- page: page,
- page_size: 5,
- leixing_id: this.data.xuanzhongLeixingId, // 🆕 商品类型筛选
- keyword: this.data.searchKeyword || undefined // 🆕 模糊搜索
- };
+ const statusItem = this.data.statusList.find((s) => s.key === key);
+ const params = this.buildListParams(key, page);
const res = await request({
- url: '/dingdan/sjdingdanhq', // 商家订单接口(和原来一样)
+ url: isStaffMode() ? STAFF_API.orderList : '/dingdan/sjdingdanhq',
method: 'POST',
data: params,
- header: { 'content-type': 'application/json' }
+ header: { 'content-type': 'application/json' },
});
const code = res.data.code;
if (code === 200 || code === 0) {
const newList = res.data.data.list || [];
- const hasMore = res.data.data.has_more || false;
+ const total = Number(res.data.data.total);
+ const hasMore = typeof res.data.data.has_more === 'boolean'
+ ? res.data.data.has_more
+ : (Number.isFinite(total) ? page * params.page_size < total : newList.length >= params.page_size);
- // 处理数据:拼接图片、转换状态中文
- const processed = newList.map(item => ({
- ...item,
- zhuangtaiZh: getOrderStatusText(item.zhuangtai),
- zhuangtaiColor: statusItem.color,
- // 如果有商品图片则用商品图片,否则用默认图
- tupian: item.tupian
- ? (item.tupian.startsWith('http') ? item.tupian : this.data.ossImageUrl + item.tupian)
- : this.data.defaultImg
- }));
+ const processed = newList.map((item) => this.processOrderItem(item, statusItem.color));
+ const prevList = isRefresh ? [] : tabData.list;
+ const updatedList = [...prevList, ...processed];
- const currentList = this.data.sjDingdanShuju[key].list;
- const updatedList = isRefresh ? processed : [...currentList, ...processed];
+ // 按订单 ID 去重,避免分页边界重复
+ const seen = new Set();
+ const deduped = updatedList.filter((row) => {
+ const id = row.dingdan_id;
+ if (!id || seen.has(id)) return false;
+ seen.add(id);
+ return true;
+ });
this.setData({
- [`sjDingdanShuju.${key}.list`]: updatedList,
+ [`sjDingdanShuju.${key}.list`]: deduped,
[`sjDingdanShuju.${key}.page`]: page,
[`sjDingdanShuju.${key}.hasMore`]: hasMore,
[`sjDingdanShuju.${key}.isLoading`]: false,
isLoading: false,
isLoadingMore: false,
- scrollViewRefreshing: false
+ scrollViewRefreshing: false,
});
+ this._listInitialized = true;
this.refreshCurrentListView();
} else {
throw new Error(res.data.msg || '加载失败');
@@ -214,94 +413,109 @@ Page(createPage({
[`sjDingdanShuju.${key}.isLoading`]: false,
isLoading: false,
isLoadingMore: false,
- scrollViewRefreshing: false
+ scrollViewRefreshing: false,
});
this.refreshCurrentListView();
}
},
- // 刷新当前视图
refreshCurrentListView() {
const key = this.data.currentStatusKey;
const tabData = this.data.sjDingdanShuju[key];
this.setData({
currentList: tabData.list,
hasMore: tabData.hasMore,
- isLoading: tabData.isLoading
+ isLoading: tabData.isLoading,
});
},
- // 重置当前状态数据
+ resetAllStatusData() {
+ const patch = {};
+ Object.keys(this.data.sjDingdanShuju).forEach((k) => {
+ patch[`sjDingdanShuju.${k}`] = { ...EMPTY_TAB };
+ });
+ this.setData(patch);
+ this.refreshCurrentListView();
+ },
+
resetCurrentStatusData() {
const key = this.data.currentStatusKey;
this.setData({
- [`sjDingdanShuju.${key}.list`]: [],
- [`sjDingdanShuju.${key}.page`]: 1,
- [`sjDingdanShuju.${key}.hasMore`]: true,
- [`sjDingdanShuju.${key}.isLoading`]: false
+ [`sjDingdanShuju.${key}`]: { ...EMPTY_TAB },
});
this.refreshCurrentListView();
},
- // 🆕 加载待结算数量
async loadPendingCount() {
- try {
- const res = await request({
- url: '/dingdan/sjdingdanhq',
- method: 'POST',
- data: {
- zhuangtai_list: [8],
- page: 1,
- page_size: 1
- }
- });
- if (res && res.data.code === 0) {
- this.setData({ pendingCount: res.data.data.pending_count || 0 });
- }
- } catch (error) {
- console.error('加载待结算数量失败:', error);
- }
+ return this.loadOrderStats();
},
- // 下拉刷新(由 scroll-view 触发)
onPullDownRefresh() {
- if (this.data.isLoading) {
+ if (this.data.isLoading || this.data.isLoadingMore) {
this.setData({ scrollViewRefreshing: false });
return;
}
- this.setData({ scrollViewRefreshing: true });
+ this._savedScrollTop = 0;
+ this.setData({ scrollViewRefreshing: true, listScrollTop: 0 });
this.resetCurrentStatusData();
this.loadCurrentStatusOrders(true);
},
- // 上拉加载更多(由 scroll-view 触发)
onReachBottom() {
const key = this.data.currentStatusKey;
const tabData = this.data.sjDingdanShuju[key];
if (tabData.isLoading || !tabData.hasMore) return;
- this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
this.loadCurrentStatusOrders(false);
},
- // 🆕 手动点击"加载更多"按钮
onLoadMoreTap() {
const key = this.data.currentStatusKey;
const tabData = this.data.sjDingdanShuju[key];
if (tabData.isLoading || !tabData.hasMore) return;
- this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
this.loadCurrentStatusOrders(false);
},
- // 跳转订单详情
+ processOrderItem(item, zhuangtaiColor) {
+ const oss = this.data.ossImageUrl || '';
+ const leixing = this.data.shangpinleixing.find((l) => l.id === item.leixing_id);
+ const leixingIconUrl = leixing ? leixing.full_tupian_url : '/images/default-type.png';
+
+ let sjAvatarFull = '/images/default-avatar.png';
+ if (item.sj_avatar) {
+ sjAvatarFull = item.sj_avatar.startsWith('http') ? item.sj_avatar : oss + item.sj_avatar;
+ }
+
+ let zhidingAvatarFull = '';
+ if (item.zhiding_avatar) {
+ zhidingAvatarFull = item.zhiding_avatar.startsWith('http') ? item.zhiding_avatar : oss + item.zhiding_avatar;
+ }
+
+ const tags = normalizeOrderTags(item);
+
+ return {
+ ...item,
+ zhuangtaiZh: getOrderStatusText(item.zhuangtai),
+ zhuangtaiColor: zhuangtaiColor || '#333333',
+ leixing_icon_url: leixingIconUrl,
+ sj_avatar_full: sjAvatarFull,
+ zhiding_avatar_full: zhidingAvatarFull,
+ isZhiding: item.zhuangtai === 7,
+ creat_time: item.creat_time || item.create_time || '',
+ ...tags,
+ shangjia_youzhi: !!item.shangjia_youzhi,
+ };
+ },
+
goToSjDingdanXiangqing(e) {
const item = e.currentTarget.dataset.item;
if (!item) return;
+ this._skipShowRefresh = true;
const dataStr = encodeURIComponent(JSON.stringify(item));
wx.navigateTo({
- url: `/pages/merchant-order-detail/merchant-order-detail?dingdanData=${dataStr}`
+ url: `/pages/merchant-order-detail/merchant-order-detail?dingdanData=${dataStr}`,
});
},
- // 图片加载失败
- onImageError() {}
-}))
+ onImageError() {},
+}));
+
diff --git a/pages/merchant-orders/merchant-orders.json b/pages/merchant-orders/merchant-orders.json
index d7516ff..ed34544 100644
--- a/pages/merchant-orders/merchant-orders.json
+++ b/pages/merchant-orders/merchant-orders.json
@@ -2,8 +2,9 @@
"navigationBarTitleText": "我的派单",
"enablePullDownRefresh": false,
"backgroundTextStyle": "dark",
- "backgroundColor": "#f8f9fa",
+ "backgroundColor": "#fff8e1",
"usingComponents": {
- "global-notification": "/components/global-notification/global-notification"
+ "global-notification": "/components/global-notification/global-notification",
+ "chenghao-tag": "/components/chenghao-tag/chenghao-tag"
}
}
\ No newline at end of file
diff --git a/pages/merchant-orders/merchant-orders.wxml b/pages/merchant-orders/merchant-orders.wxml
index 35ed354..dd9ec81 100644
--- a/pages/merchant-orders/merchant-orders.wxml
+++ b/pages/merchant-orders/merchant-orders.wxml
@@ -1,135 +1,265 @@
-
-
-
-
-
-
-
-
-
- {{item.jieshao || '类型'}}
-
-
-
-
-
-
-
-
-
-
-
- ✕
-
-
-
-
-
-
- 待结算订单
- {{pendingCount}}
-
-
-
-
-
-
-
-
- {{item.name}}
-
-
- {{pendingCount}}
-
-
-
-
-
-
-
-
- ⚡ 正在刷新...
- ▼ 下拉刷新
-
-
-
-
-
-
-
- 加载订单中...
-
-
-
-
-
- 暂无订单
- 快去派发订单吧
-
-
-
-
-
-
- {{item.create_time}}
-
-
-
-
- {{item.jieshao || '暂无描述'}}
- ID: {{item.dingdan_id}}
- 昵称: {{item.nicheng}}
-
-
- {{item.zhuangtaiZh}}
-
- ¥
- {{item.jine || '0.00'}}
-
-
-
-
-
-
-
-
- 上拉加载更多
-
-
-
-
-
- 加载中...
-
-
-
-
-
-
-
-
-
- —— 没有更多了 ——
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ {{item.jieshao || '类型'}}
+
+
+
+
+
+
+
+
+
+
+
+ ✕
+
+
+
+
+
+
+ {{timeStart || '开始日期'}}
+
+ 至
+
+ {{timeEnd || '结束日期'}}
+
+ 清除
+
+
+ 全部
+ 今天
+ 近7天
+ 近30天
+
+
+
+
+ {{selectedStaffLabel}}
+
+ 清除
+
+
+
+
+
+ 待结算订单
+ {{pendingCount}}
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+ {{pendingCount}}
+
+
+
+
+
+
+
+
+ ⚡ 正在刷新...
+ ▼ 下拉刷新
+
+
+
+
+
+
+
+ 加载订单中...
+
+
+
+
+
+ 暂无订单
+ 快去派发订单吧
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
+
+ {{item.jieshao || '暂无介绍'}}
+
+ 优质商家
+
+
+
+
+ ¥
+ {{item.jine || '0.00'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.sjnicheng || '未知商家'}}
+ ID:{{item.shangjia_id}} 发布于 {{item.creat_time}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
+
+ {{item.jieshao || '暂无介绍'}}
+
+
+
+ ¥
+ {{item.jine || '0.00'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.sjnicheng || '未知商家'}}
+ ID:{{item.shangjia_id}} 发布于 {{item.creat_time}}
+
+
+
+
+
+
+
+
+
+
+
+ 上拉加载更多
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+ —— 没有更多了 ——
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/merchant-orders/merchant-orders.wxss b/pages/merchant-orders/merchant-orders.wxss
index 5d01da2..8b6334a 100644
--- a/pages/merchant-orders/merchant-orders.wxss
+++ b/pages/merchant-orders/merchant-orders.wxss
@@ -1,428 +1,529 @@
-/* pages/merchant-orders/merchant-orders.wxss */
-
-/* 页面容器:禁止整体滚动 */
-page {
- height: 100%;
- overflow: hidden;
- }
- .sj-page {
- height: 100vh;
- display: flex;
- flex-direction: column;
- background: #f5f6fa;
- }
-
- /* ========== 商品类型区 ========== */
- .leixing-area {
- background: #fff;
- padding: 24rpx 0;
- border-bottom: 1rpx solid #f0f0f0;
- flex-shrink: 0;
- }
- .leixing-scroll {
- white-space: nowrap;
- }
- .leixing-container {
- display: inline-flex;
- padding: 0 24rpx;
- }
- .leixing-item {
- display: inline-flex;
- flex-direction: column;
- align-items: center;
- margin-right: 32rpx;
- padding: 12rpx 20rpx;
- border-radius: 28rpx;
- transition: all 0.2s;
- }
- .leixing-item.leixing-active {
- background: linear-gradient(135deg, #e8f0fe, #d4e4ff);
- box-shadow: 0 4rpx 12rpx rgba(33,150,243,0.15);
- }
- .leixing-img {
- width: 72rpx;
- height: 72rpx;
- border-radius: 50%;
- background: #f0f0f0;
- margin-bottom: 8rpx;
- }
- .leixing-name {
- font-size: 24rpx;
- color: #333;
- max-width: 100rpx;
- text-align: center;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- /* ========== 搜索行 ========== */
- .filter-row {
- display: flex;
- align-items: center;
- padding: 20rpx 24rpx;
- background: #fff;
- border-bottom: 1rpx solid #f0f0f0;
- flex-shrink: 0;
- }
- .search-box {
- flex: 1;
- display: flex;
- align-items: center;
- background: #f0f2f5;
- border-radius: 36rpx;
- padding: 0 20rpx;
- height: 68rpx;
- }
- .search-icon {
- width: 32rpx;
- height: 32rpx;
- margin-right: 12rpx;
- opacity: 0.5;
- }
- .search-input {
- flex: 1;
- font-size: 26rpx;
- color: #333;
- }
- .search-clear {
- width: 40rpx;
- height: 40rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #ccc;
- border-radius: 50%;
- margin-left: 8rpx;
- }
- .search-clear text {
- font-size: 24rpx;
- color: #fff;
- font-weight: bold;
- }
-
- /* ========== 待结算提示条(保留原样式) ========== */
- .sj-pending-tip {
- margin: 20rpx 24rpx;
- padding: 16rpx 24rpx;
- background: linear-gradient(145deg, #ffe8cc, #ffdbb5);
- border-left: 8rpx solid #ffaa00;
- border-radius: 16rpx;
- display: flex;
- align-items: center;
- gap: 16rpx;
- box-shadow: 0 8rpx 20rpx rgba(255,170,0,0.3);
- flex-shrink: 0;
- }
- .sj-pending-icon {
- font-size: 36rpx;
- color: #ffaa00;
- }
- .sj-pending-text {
- font-size: 28rpx;
- color: #b25700;
- font-weight: 600;
- }
- .sj-pending-badge {
- min-width: 44rpx;
- height: 44rpx;
- padding: 0 12rpx;
- background: linear-gradient(145deg, #ff3b3b, #d10000);
- color: #fff;
- font-size: 26rpx;
- font-weight: 700;
- line-height: 44rpx;
- text-align: center;
- border-radius: 22rpx;
- margin-left: auto;
- box-shadow: 0 4rpx 12rpx rgba(255,0,0,0.5);
- }
-
- /* ========== 主体布局 ========== */
- .main-container {
- flex: 1;
- display: flex;
- overflow: hidden;
- }
-
- /* 左侧状态栏 */
- .left-status {
- width: 180rpx;
- background: #fff;
- border-right: 1rpx solid #f0f0f0;
- padding: 28rpx 0;
- flex-shrink: 0;
- }
- .status-item {
- padding: 28rpx 20rpx;
- display: flex;
- align-items: center;
- justify-content: space-between;
- position: relative;
- }
- .status-item.status-active {
- background: linear-gradient(to right, #e3f2fd, #fff);
- }
- .status-name {
- font-size: 28rpx;
- color: #555;
- }
- .status-active .status-name {
- color: #1976D2;
- font-weight: 600;
- }
- .status-dot {
- width: 14rpx;
- height: 14rpx;
- border-radius: 50%;
- background: #1976D2;
- }
- /* 结算中状态的小红点数字 */
- .sj-status-badge {
- min-width: 36rpx;
- height: 36rpx;
- padding: 0 8rpx;
- background: linear-gradient(145deg, #ff4d4f, #d10000);
- color: #fff;
- font-size: 22rpx;
- font-weight: 700;
- line-height: 36rpx;
- text-align: center;
- border-radius: 18rpx;
- margin-left: 8rpx;
- box-shadow: 0 4rpx 8rpx rgba(255,0,0,0.4);
- }
-
- /* 右侧包裹 */
- .right-wrapper {
- flex: 1;
- padding-right: 30rpx;
- box-sizing: border-box;
- overflow: hidden;
- }
- .right-list {
- width: 100%;
- height: 100%;
- background: #f5f6fa;
- }
- .refresher-slot {
- text-align: center;
- padding: 14rpx 0;
- font-size: 24rpx;
- color: #999;
- }
-
- /* 内容容器 */
- .list-inner {
- padding: 24rpx 0 200rpx 20rpx;
- box-sizing: border-box;
- }
-
- /* ========== 订单卡片 ========== */
- .order-card {
- background: #fff;
- border-radius: 24rpx;
- padding: 24rpx;
- margin-bottom: 24rpx;
- box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.04);
- box-sizing: border-box;
- width: 100%;
- display: flex;
- flex-direction: column;
- }
- /* 结算中卡片特殊边框 */
- .sj-card-jiesuan {
- border: 2rpx solid #ff5722;
- box-shadow: 0 6rpx 20rpx rgba(255,87,34,0.15);
- }
- .order-card:active {
- transform: scale(0.98);
- }
-
- /* 创建时间 */
- .card-time {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 12rpx;
- padding-bottom: 8rpx;
- border-bottom: 1rpx dashed rgba(0,120,255,0.15);
- }
-
- /* 内容行 */
- .card-content-row {
- display: flex;
- align-items: flex-start;
- }
-
- /* 商品图片 */
- .card-img {
- width: 130rpx;
- height: 130rpx;
- border-radius: 18rpx;
- background: #f0f0f0;
- margin-right: 24rpx;
- flex-shrink: 0;
- }
-
- /* 中间信息区 */
- .card-info {
- flex: 1;
- min-height: 130rpx;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- min-width: 0;
- }
- .card-title {
- font-size: 28rpx;
- color: #222;
- line-height: 1.5;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- overflow: hidden;
- }
- .card-id {
- font-size: 22rpx;
- color: #999;
- margin-top: 6rpx;
- }
- .card-nicheng {
- font-size: 22rpx;
- color: #666;
- margin-top: 4rpx;
- }
-
- /* 右侧状态和价格 */
- .card-right {
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- justify-content: center;
- min-height: 130rpx;
- margin-left: 20rpx;
- flex-shrink: 0;
- max-width: 160rpx;
- }
- .card-status {
- font-size: 24rpx;
- font-weight: 500;
- padding: 4rpx 12rpx;
- background: #f5f5f5;
- border-radius: 20rpx;
- margin-bottom: 8rpx;
- white-space: nowrap;
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- /* 结算中状态红色高亮(保留原样式) */
- .sj-status-jiesuan {
- background: linear-gradient(145deg, #ff4d4f, #d10000) !important;
- color: #fff !important;
- border-color: #ffaa00;
- box-shadow: 0 0 15rpx #ff4d4f;
- }
- .card-price {
- display: flex;
- align-items: baseline;
- white-space: nowrap;
- }
- .price-symbol {
- font-size: 28rpx;
- color: #ffaa00;
- font-weight: 700;
- margin-right: 4rpx;
- }
- .price-number {
- font-size: 36rpx;
- font-weight: 700;
- color: #333;
- }
-
- /* ========== 加载与空状态 ========== */
- .loading-state, .empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 120rpx 0;
- }
- .loading-spinner {
- width: 52rpx;
- height: 52rpx;
- border: 4rpx solid #e0e0e0;
- border-top-color: #1976D2;
- border-radius: 50%;
- animation: spin 0.8s linear infinite;
- margin-bottom: 24rpx;
- }
-
- .empty-img {
- width: 200rpx;
- height: 200rpx;
- opacity: 0.4;
- margin-bottom: 24rpx;
- }
- .empty-text, .loading-tip {
- font-size: 28rpx;
- color: #999;
- }
- .empty-subtext {
- font-size: 26rpx;
- color: #b0b0b0;
- margin-top: 10rpx;
- }
-
- .load-more {
- text-align: center;
- padding: 36rpx 0 20rpx 0;
- font-size: 26rpx;
- color: #999;
- }
- .loading-more-state {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 20rpx 0;
- font-size: 26rpx;
- color: #999;
- }
- .mini-spinner {
- display: inline-block;
- width: 26rpx;
- height: 26rpx;
- border: 3rpx solid #ccc;
- border-top-color: #1976D2;
- border-radius: 50%;
- animation: spin 0.6s linear infinite;
- vertical-align: middle;
- margin-right: 10rpx;
- }
-
- .manual-load-more {
- display: flex;
- justify-content: center;
- padding: 30rpx 0 10rpx 0;
- }
- .load-more-btn {
- background: #ffffff;
- color: #1976D2;
- font-size: 28rpx;
- font-weight: 500;
- border: 2rpx solid #1976D2;
- border-radius: 40rpx;
- padding: 16rpx 60rpx;
- text-align: center;
- box-shadow: 0 4rpx 12rpx rgba(33,150,243,0.1);
- }
- .load-more-btn::after {
- border: none;
- }
-
- .no-more {
- text-align: center;
- padding: 40rpx 0;
- font-size: 26rpx;
- color: #999;
+/* pages/merchant-orders/merchant-orders.wxss */
+@import '../../styles/dashou-xym-order-card.wxss';
+@import '../../styles/shangjia-merchant-order-card.wxss';
+
+/* 页面容器:禁止整体滚动 */
+page {
+ height: 100%;
+ overflow: hidden;
+ background: #fff8e1;
+ }
+ .sj-page {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: #fff8e1;
+ }
+
+ /* ========== 商品类型区 ========== */
+ .leixing-area {
+ background: #fff;
+ padding: 24rpx 0;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ .leixing-scroll {
+ white-space: nowrap;
+ }
+ .leixing-container {
+ display: inline-flex;
+ padding: 0 24rpx;
+ }
+ .leixing-item {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ margin-right: 32rpx;
+ padding: 12rpx 20rpx;
+ border-radius: 28rpx;
+ transition: all 0.2s;
+ }
+ .leixing-item.leixing-active {
+ background: linear-gradient(135deg, #e8f0fe, #d4e4ff);
+ box-shadow: 0 4rpx 12rpx rgba(33,150,243,0.15);
+ }
+ .leixing-img {
+ width: 72rpx;
+ height: 72rpx;
+ border-radius: 50%;
+ background: #f0f0f0;
+ margin-bottom: 8rpx;
+ }
+ .leixing-name {
+ font-size: 24rpx;
+ color: #333;
+ max-width: 100rpx;
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ /* ========== 搜索行 ========== */
+ .filter-row {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 24rpx;
+ background: #fff;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ .search-box {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background: #f0f2f5;
+ border-radius: 36rpx;
+ padding: 0 20rpx;
+ height: 68rpx;
+ }
+ .search-icon {
+ width: 32rpx;
+ height: 32rpx;
+ margin-right: 12rpx;
+ opacity: 0.5;
+ }
+ .search-input {
+ flex: 1;
+ font-size: 26rpx;
+ color: #333;
+ }
+ .search-clear {
+ width: 40rpx;
+ height: 40rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #ccc;
+ border-radius: 50%;
+ margin-left: 8rpx;
+ }
+ .search-clear text {
+ font-size: 24rpx;
+ color: #fff;
+ font-weight: bold;
+ }
+
+ /* ========== 时间段筛选 ========== */
+ .time-filter-row {
+ display: flex;
+ align-items: center;
+ padding: 12rpx 24rpx 8rpx;
+ background: #fff;
+ gap: 12rpx;
+ flex-shrink: 0;
+ }
+ .time-pill {
+ min-width: 180rpx;
+ padding: 10rpx 20rpx;
+ font-size: 24rpx;
+ color: #666;
+ background: #f0f2f5;
+ border-radius: 28rpx;
+ text-align: center;
+ }
+ .time-pill--active {
+ color: #492f00;
+ background: linear-gradient(180deg, #fff8e1, #ffe9b8);
+ border: 1rpx solid #e8c547;
+ }
+ .time-sep {
+ font-size: 24rpx;
+ color: #999;
+ }
+ .time-clear {
+ font-size: 24rpx;
+ color: #c9a227;
+ padding: 8rpx 12rpx;
+ flex-shrink: 0;
+ }
+ .time-quick-row {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ padding: 0 24rpx 16rpx;
+ background: #fff;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ .time-quick-chip {
+ padding: 8rpx 20rpx;
+ font-size: 22rpx;
+ color: #666;
+ background: #f5f5f5;
+ border-radius: 24rpx;
+ }
+
+ .staff-filter-row {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ padding: 12rpx 24rpx;
+ background: #fff;
+ border-bottom: 1rpx solid #f0f0f0;
+ }
+ .staff-filter-pill {
+ padding: 10rpx 24rpx;
+ background: #f0f7ff;
+ color: #1565C0;
+ border-radius: 24rpx;
+ font-size: 24rpx;
+ }
+ .staff-filter-clear {
+ font-size: 24rpx;
+ color: #999;
+ }
+ .sidebar-stats {
+ padding: 12rpx 8rpx 16rpx;
+ margin-bottom: 8rpx;
+ border-bottom: 1rpx solid #eee;
+ }
+ .sb-line {
+ display: block;
+ font-size: 20rpx;
+ color: #888;
+ line-height: 1.6;
+ word-break: break-all;
+ }
+ .sb-line.accent { color: #E65100; font-weight: 600; }
+
+ /* ========== 待结算提示条(保留原样式) ========== */
+ .sj-pending-tip {
+ margin: 20rpx 24rpx;
+ padding: 16rpx 24rpx;
+ background: linear-gradient(145deg, #ffe8cc, #ffdbb5);
+ border-left: 8rpx solid #ffaa00;
+ border-radius: 16rpx;
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ box-shadow: 0 8rpx 20rpx rgba(255,170,0,0.3);
+ flex-shrink: 0;
+ }
+ .sj-pending-icon {
+ font-size: 36rpx;
+ color: #ffaa00;
+ }
+ .sj-pending-text {
+ font-size: 28rpx;
+ color: #b25700;
+ font-weight: 600;
+ }
+ .sj-pending-badge {
+ min-width: 44rpx;
+ height: 44rpx;
+ padding: 0 12rpx;
+ background: linear-gradient(145deg, #ff3b3b, #d10000);
+ color: #fff;
+ font-size: 26rpx;
+ font-weight: 700;
+ line-height: 44rpx;
+ text-align: center;
+ border-radius: 22rpx;
+ margin-left: auto;
+ box-shadow: 0 4rpx 12rpx rgba(255,0,0,0.5);
+ }
+
+ /* ========== 主体布局 ========== */
+ .main-container {
+ flex: 1;
+ display: flex;
+ overflow: hidden;
+ }
+
+ /* 左侧状态栏 */
+ .left-status {
+ width: 180rpx;
+ background: #fff;
+ border-right: 1rpx solid #f0f0f0;
+ padding: 28rpx 0;
+ flex-shrink: 0;
+ }
+ .status-item {
+ padding: 28rpx 20rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ position: relative;
+ }
+ .status-item.status-active {
+ background: linear-gradient(to right, #e3f2fd, #fff);
+ }
+ .status-name {
+ font-size: 28rpx;
+ color: #555;
+ }
+ .status-active .status-name {
+ color: #1976D2;
+ font-weight: 600;
+ }
+ .status-dot {
+ width: 14rpx;
+ height: 14rpx;
+ border-radius: 50%;
+ background: #1976D2;
+ }
+ /* 结算中状态的小红点数字 */
+ .sj-status-badge {
+ min-width: 36rpx;
+ height: 36rpx;
+ padding: 0 8rpx;
+ background: linear-gradient(145deg, #ff4d4f, #d10000);
+ color: #fff;
+ font-size: 22rpx;
+ font-weight: 700;
+ line-height: 36rpx;
+ text-align: center;
+ border-radius: 18rpx;
+ margin-left: 8rpx;
+ box-shadow: 0 4rpx 8rpx rgba(255,0,0,0.4);
+ }
+
+ /* 右侧包裹 */
+ .right-wrapper {
+ flex: 1;
+ padding-right: 30rpx;
+ box-sizing: border-box;
+ overflow: hidden;
+ }
+ .right-list {
+ width: 100%;
+ height: 100%;
+ background: #f5f6fa;
+ }
+ .refresher-slot {
+ text-align: center;
+ padding: 14rpx 0;
+ font-size: 24rpx;
+ color: #999;
+ }
+
+ /* 内容容器 */
+ .list-inner {
+ padding: 24rpx 0 200rpx 20rpx;
+ box-sizing: border-box;
+ }
+
+ /* ========== 订单卡片 ========== */
+ .order-card {
+ background: #fff;
+ border-radius: 24rpx;
+ padding: 24rpx;
+ margin-bottom: 24rpx;
+ box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.04);
+ box-sizing: border-box;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ }
+ /* 结算中卡片特殊边框 */
+ .sj-card-jiesuan {
+ border: 2rpx solid #ff5722;
+ box-shadow: 0 6rpx 20rpx rgba(255,87,34,0.15);
+ }
+ .order-card:active {
+ transform: scale(0.98);
+ }
+
+ /* 创建时间 */
+ .card-time {
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 12rpx;
+ padding-bottom: 8rpx;
+ border-bottom: 1rpx dashed rgba(0,120,255,0.15);
+ }
+
+ /* 内容行 */
+ .card-content-row {
+ display: flex;
+ align-items: flex-start;
+ }
+
+ /* 商品图片 */
+ .card-img {
+ width: 130rpx;
+ height: 130rpx;
+ border-radius: 18rpx;
+ background: #f0f0f0;
+ margin-right: 24rpx;
+ flex-shrink: 0;
+ }
+
+ /* 中间信息区 */
+ .card-info {
+ flex: 1;
+ min-height: 130rpx;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ min-width: 0;
+ }
+ .card-title {
+ font-size: 28rpx;
+ color: #222;
+ line-height: 1.5;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ }
+ .card-id {
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 6rpx;
+ }
+ .card-nicheng {
+ font-size: 22rpx;
+ color: #666;
+ margin-top: 4rpx;
+ }
+
+ /* 右侧状态和价格 */
+ .card-right {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ justify-content: center;
+ min-height: 130rpx;
+ margin-left: 20rpx;
+ flex-shrink: 0;
+ max-width: 160rpx;
+ }
+ .card-status {
+ font-size: 24rpx;
+ font-weight: 500;
+ padding: 4rpx 12rpx;
+ background: #f5f5f5;
+ border-radius: 20rpx;
+ margin-bottom: 8rpx;
+ white-space: nowrap;
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ /* 结算中状态红色高亮(保留原样式) */
+ .sj-status-jiesuan {
+ background: linear-gradient(145deg, #ff4d4f, #d10000) !important;
+ color: #fff !important;
+ border-color: #ffaa00;
+ box-shadow: 0 0 15rpx #ff4d4f;
+ }
+ .card-price {
+ display: flex;
+ align-items: baseline;
+ white-space: nowrap;
+ }
+ .price-symbol {
+ font-size: 28rpx;
+ color: #ffaa00;
+ font-weight: 700;
+ margin-right: 4rpx;
+ }
+ .price-number {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #333;
+ }
+
+ /* ========== 加载与空状态 ========== */
+ .loading-state, .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 120rpx 0;
+ }
+ .loading-spinner {
+ width: 52rpx;
+ height: 52rpx;
+ border: 4rpx solid #e0e0e0;
+ border-top-color: #1976D2;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ margin-bottom: 24rpx;
+ }
+
+ .empty-img {
+ width: 200rpx;
+ height: 200rpx;
+ opacity: 0.4;
+ margin-bottom: 24rpx;
+ }
+ .empty-text, .loading-tip {
+ font-size: 28rpx;
+ color: #999;
+ }
+ .empty-subtext {
+ font-size: 26rpx;
+ color: #b0b0b0;
+ margin-top: 10rpx;
+ }
+
+ .load-more {
+ text-align: center;
+ padding: 36rpx 0 20rpx 0;
+ font-size: 26rpx;
+ color: #999;
+ }
+ .loading-more-state {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20rpx 0;
+ font-size: 26rpx;
+ color: #999;
+ }
+ .mini-spinner {
+ display: inline-block;
+ width: 26rpx;
+ height: 26rpx;
+ border: 3rpx solid #ccc;
+ border-top-color: #1976D2;
+ border-radius: 50%;
+ animation: spin 0.6s linear infinite;
+ vertical-align: middle;
+ margin-right: 10rpx;
+ }
+
+ .manual-load-more {
+ display: flex;
+ justify-content: center;
+ padding: 30rpx 0 10rpx 0;
+ }
+ .load-more-btn {
+ background: #ffffff;
+ color: #1976D2;
+ font-size: 28rpx;
+ font-weight: 500;
+ border: 2rpx solid #1976D2;
+ border-radius: 40rpx;
+ padding: 16rpx 60rpx;
+ text-align: center;
+ box-shadow: 0 4rpx 12rpx rgba(33,150,243,0.1);
+ }
+ .load-more-btn::after {
+ border: none;
+ }
+
+ .no-more {
+ text-align: center;
+ padding: 40rpx 0;
+ font-size: 26rpx;
+ color: #999;
+ }
+
+ .sj-order-list {
+ padding: 0 4rpx 8rpx;
+ }
+
+ .list-inner {
+ padding: 12rpx 8rpx 24rpx;
+ }
+
+ .load-more-btn {
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ border: 2rpx solid #fff;
+ box-shadow: 0 6rpx 16rpx rgba(245, 213, 99, 0.3);
}
\ No newline at end of file
diff --git a/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.js b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.js
new file mode 100644
index 0000000..935a918
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.js
@@ -0,0 +1,406 @@
+import request from '../../../../utils/request.js';
+
+const app = getApp();
+const MEIYE = 5;
+
+Component({
+ properties: {
+ status: { type: Number, value: 1, observer: 'reload' },
+ searchDingdan: { type: String, value: '', observer: 'reload' },
+ trigger: { type: Number, value: 0, observer: 'reload' }
+ },
+
+ data: {
+ list: [],
+ page: 1,
+ hasMore: true,
+ loading: false,
+ loadingMore: false,
+ ossImageUrl: app.globalData.ossImageUrl || '',
+
+ showDetail: false,
+ detailItem: null,
+
+ showModify: false,
+ modifyLiyou: '',
+ modifyJine: '',
+
+ showCancel: false,
+ cancelLiyou: '',
+
+ showResubmit: false,
+ resubmitLiyou: '',
+ resubmitJine: '',
+
+ uploading: false,
+ uploadProgressWidth: '0%'
+ },
+
+ lifetimes: {
+ attached() { this.reload(); }
+ },
+
+ methods: {
+ reload() {
+ this.setData({ page: 1, list: [], hasMore: true });
+ this.loadData();
+ },
+
+ mapItem(item) {
+ const z = Number(item.zhuangtai);
+ let display_status = '未知', status_class = 'zhuangtai-weizhi';
+ if (z === 1) { display_status = '待缴纳'; status_class = 'zhuangtai-daijiaona'; }
+ else if (z === 2) { display_status = '已缴纳'; status_class = 'zhuangtai-yijiaona'; }
+ else if (z === 3) { display_status = '申诉中'; status_class = 'zhuangtai-shensuzhong'; }
+ else if (z === 4) { display_status = '已驳回'; status_class = 'zhuangtai-yibohui'; }
+
+ const zhengju = (item.zhengju_tupian || []).map(img => ({
+ id: img.id,
+ url: img.url,
+ fullUrl: this.getFullUrl(img.url)
+ }));
+ const shensu = (item.shensu_tupian || []).map(img => ({
+ id: img.id,
+ url: img.url,
+ fullUrl: this.getFullUrl(img.url)
+ }));
+
+ return {
+ ...item,
+ display_status,
+ status_class,
+ create_time: item.CreateTime || '',
+ zhengju_list: zhengju,
+ shensu_list: shensu,
+ staff_label: item.staff_display_name ? `客服:${item.staff_display_name}` : ''
+ };
+ },
+
+ async loadData(isLoadMore = false) {
+ if (this.data.loading || this.data.loadingMore) return;
+ if (isLoadMore && !this.data.hasMore) return;
+
+ if (isLoadMore) this.setData({ loadingMore: true });
+ else this.setData({ loading: true });
+
+ try {
+ const res = await request({
+ url: '/yonghu/sjfklbhq',
+ method: 'POST',
+ data: {
+ page: this.data.page,
+ page_size: MEIYE,
+ zhuangtai: this.data.status,
+ sousuo_dingdan_id: this.data.searchDingdan
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ const data = res.data.data;
+ const rows = (data.list || []).map(item => this.mapItem(item));
+ const newList = isLoadMore ? this.data.list.concat(rows) : rows;
+ this.setData({
+ list: newList,
+ hasMore: data.has_more || false,
+ page: isLoadMore ? this.data.page + 1 : 2,
+ loading: false,
+ loadingMore: false
+ });
+ } else {
+ wx.showToast({ title: res.data?.msg || '加载失败', icon: 'none' });
+ this.setData({ loading: false, loadingMore: false });
+ }
+ } catch (e) {
+ wx.showToast({ title: '网络请求失败', icon: 'none' });
+ this.setData({ loading: false, loadingMore: false });
+ }
+ },
+
+ loadMore() {
+ if (this.data.list.length === 0 || !this.data.hasMore) return;
+ this.loadData(true);
+ },
+
+ openDetail(e) {
+ const item = e.currentTarget.dataset.item;
+ this.setData({ showDetail: true, detailItem: item });
+ },
+
+ closeDetail() {
+ this.setData({ showDetail: false, detailItem: null });
+ },
+
+ goOrder(e) {
+ const id = e.currentTarget.dataset.id || this.data.detailItem?.guanliandingdan_id;
+ if (!id) return;
+ wx.navigateTo({ url: `/pages/merchant-order-detail/merchant-order-detail?dingdan_id=${id}` });
+ },
+
+ openModify() {
+ const item = this.data.detailItem;
+ this.setData({
+ showModify: true,
+ modifyLiyou: item.chufaliyou || '',
+ modifyJine: item.fakuanjine || ''
+ });
+ },
+
+ closeModify() { this.setData({ showModify: false }); },
+
+ onModifyLiyou(e) { this.setData({ modifyLiyou: e.detail.value.slice(0, 500) }); },
+ onModifyJine(e) { this.setData({ modifyJine: e.detail.value }); },
+
+ async submitModify() {
+ const item = this.data.detailItem;
+ const liyou = this.data.modifyLiyou.trim();
+ const jine = parseFloat(this.data.modifyJine);
+ if (!liyou) { wx.showToast({ title: '请输入罚款原因', icon: 'none' }); return; }
+ if (!jine || jine <= 0) { wx.showToast({ title: '金额无效', icon: 'none' }); return; }
+
+ wx.showLoading({ title: '提交中' });
+ try {
+ const res = await request({
+ url: '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'modify_penalty',
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ liyou: liyou,
+ jine: jine.toFixed(2)
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ wx.showToast({ title: '修改成功', icon: 'success' });
+ this.setData({ showModify: false });
+ this.closeDetail();
+ this.reload();
+ this.triggerEvent('changed');
+ } else {
+ wx.showToast({ title: res.data?.msg || '修改失败', icon: 'none' });
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ openCancel() { this.setData({ showCancel: true, cancelLiyou: '' }); },
+ closeCancel() { this.setData({ showCancel: false }); },
+ onCancelLiyou(e) { this.setData({ cancelLiyou: e.detail.value.slice(0, 500) }); },
+
+ async submitCancel() {
+ const item = this.data.detailItem;
+ const liyou = this.data.cancelLiyou.trim();
+ if (!liyou) { wx.showToast({ title: '请输入驳回理由', icon: 'none' }); return; }
+ wx.showLoading({ title: '提交中' });
+ try {
+ const res = await request({
+ url: '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'cancel_penalty',
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ liyou: liyou
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ wx.showToast({ title: '已撤销', icon: 'success' });
+ this.setData({ showCancel: false });
+ this.closeDetail();
+ this.reload();
+ this.triggerEvent('changed');
+ } else {
+ wx.showToast({ title: res.data?.msg || '操作失败', icon: 'none' });
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ openResubmit() {
+ const item = this.data.detailItem;
+ this.setData({
+ showResubmit: true,
+ resubmitLiyou: item.chufaliyou || '',
+ resubmitJine: item.fakuanjine || ''
+ });
+ },
+
+ closeResubmit() { this.setData({ showResubmit: false }); },
+ onResubmitLiyou(e) { this.setData({ resubmitLiyou: e.detail.value.slice(0, 500) }); },
+ onResubmitJine(e) { this.setData({ resubmitJine: e.detail.value }); },
+
+ async submitResubmit() {
+ const item = this.data.detailItem;
+ const liyou = this.data.resubmitLiyou.trim();
+ const jine = parseFloat(this.data.resubmitJine);
+ if (!liyou || !jine || jine <= 0) {
+ wx.showToast({ title: '请填写完整信息', icon: 'none' });
+ return;
+ }
+ wx.showLoading({ title: '提交中' });
+ try {
+ const res = await request({
+ url: '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'resubmit_penalty',
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ liyou: liyou,
+ jine: jine.toFixed(2)
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ wx.showToast({ title: '已重新申请', icon: 'success' });
+ this.setData({ showResubmit: false });
+ this.closeDetail();
+ this.reload();
+ this.triggerEvent('changed');
+ } else {
+ wx.showToast({ title: res.data?.msg || '操作失败', icon: 'none' });
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ chooseEvidence() {
+ const item = this.data.detailItem;
+ const remain = 9 - (item.zhengju_list || []).length;
+ if (remain <= 0) return;
+ wx.chooseMedia({
+ count: remain,
+ mediaType: ['image'],
+ sourceType: ['album', 'camera'],
+ success: async (res) => {
+ const paths = res.tempFiles.map(f => f.tempFilePath);
+ await this.uploadAndAddEvidence(paths);
+ }
+ });
+ },
+
+ async uploadAndAddEvidence(localPaths) {
+ const item = this.data.detailItem;
+ if (!localPaths.length) return;
+ this.setData({ uploading: true, uploadProgressWidth: '0%' });
+
+ try {
+ const keys = await this.uploadToCos(localPaths, item);
+ if (!keys) return;
+ const res = await request({
+ url: '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'manage_penalty_evidence',
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ add_urls: keys,
+ remove_ids: []
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ wx.showToast({ title: '图片已更新', icon: 'success' });
+ this.reload();
+ this.triggerEvent('changed');
+ this.setData({ showDetail: false, detailItem: null });
+ } else {
+ wx.showToast({ title: res.data?.msg || '保存失败', icon: 'none' });
+ }
+ } finally {
+ this.setData({ uploading: false });
+ }
+ },
+
+ async deleteEvidence(e) {
+ const imgId = e.currentTarget.dataset.id;
+ const item = this.data.detailItem;
+ wx.showLoading({ title: '删除中' });
+ try {
+ const res = await request({
+ url: '/dingdan/sjfkxgycx',
+ method: 'POST',
+ data: {
+ operation: 'manage_penalty_evidence',
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ add_urls: [],
+ remove_ids: [imgId]
+ }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ const zhengju = item.zhengju_list.filter(img => img.id !== imgId);
+ this.setData({ detailItem: { ...item, zhengju_list: zhengju } });
+ this.reload();
+ this.triggerEvent('changed');
+ } else {
+ wx.showToast({ title: res.data?.msg || '删除失败', icon: 'none' });
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ async uploadToCos(localPaths, item) {
+ const credRes = await request({
+ url: '/dingdan/dsscpz',
+ method: 'POST',
+ data: {
+ dingdan_id: item.guanliandingdan_id,
+ fadan_id: item.id,
+ yongtu: 'fakuan_evidence'
+ }
+ });
+ if (credRes.data.code !== 0) {
+ wx.showToast({ title: credRes.data.msg || '凭证失败', icon: 'none' });
+ return null;
+ }
+ const tokenData = credRes.data.data;
+ const credentials = tokenData.credentials || tokenData;
+ const COS = require('../../../../utils/cos-wx-sdk-v5.min.js');
+ const cos = new COS({
+ SimpleUploadMethod: 'putObject',
+ getAuthorization: (_, callback) => {
+ callback({
+ TmpSecretId: credentials.tmpSecretId,
+ TmpSecretKey: credentials.tmpSecretKey,
+ SecurityToken: credentials.sessionToken || '',
+ StartTime: tokenData.startTime,
+ ExpiredTime: tokenData.expiredTime
+ });
+ }
+ });
+ const bucket = tokenData.bucket || 'julebu-1361527063';
+ const region = tokenData.region || 'ap-shanghai';
+ const uid = app.globalData.userInfo?.yonghuid || wx.getStorageSync('uid') || '0000000';
+ const keys = [];
+ const total = localPaths.length;
+
+ for (let i = 0; i < total; i++) {
+ const key = `fakuan/shangjiafakuan/zhengju/${uid}_${item.id}_${Date.now() + i}.jpg`;
+ await new Promise((resolve, reject) => {
+ cos.uploadFile({
+ Bucket: bucket,
+ Region: region,
+ Key: key,
+ FilePath: localPaths[i]
+ }, (err) => err ? reject(err) : resolve());
+ });
+ keys.push(key);
+ this.setData({ uploadProgressWidth: `${((i + 1) / total * 100).toFixed(0)}%` });
+ }
+ return keys;
+ },
+
+ previewImage(e) {
+ const url = e.currentTarget.dataset.url;
+ wx.previewImage({ current: url, urls: [url] });
+ },
+
+ getFullUrl(url) {
+ if (!url) return '';
+ if (url.startsWith('http')) return url;
+ return this.data.ossImageUrl + url;
+ }
+ }
+});
diff --git a/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.json b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxml b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxml
new file mode 100644
index 0000000..3fd9734
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxml
@@ -0,0 +1,115 @@
+
+
+ 加载中...
+
+
+
+ {{ item.create_time }}
+ {{ item.display_status }}
+
+ 金额:¥{{ item.fakuanjine }}
+ 理由:{{ item.chufaliyou }}
+ {{ item.staff_label }}
+ 订单:{{ item.guanliandingdan_id }}
+
+
+ 点击获取更多
+ 加载中...
+ —— 没有更多了 ——
+ 暂无罚单记录
+
+
+
+
+
+ 罚单详情
+ ✕
+
+
+ 罚款金额¥{{ detailItem.fakuanjine }}
+ 状态{{ detailItem.display_status }}
+ 分红到账¥{{ detailItem.applicant_bonus_amount || '0.00' }}
+ 申请客服{{ detailItem.staff_label }}
+ 处罚理由{{ detailItem.chufaliyou }}
+
+ 关联订单
+ {{ detailItem.guanliandingdan_id }} ›
+
+ 驳回理由{{ detailItem.bohuiliyou }}
+ 申诉理由{{ detailItem.shensuliyou }}
+
+
+ 处罚证据图(可管理)
+
+
+
+
+ ✕
+
+
+ +
+
+ 上传中 {{ uploadProgressWidth }}
+
+
+
+ 打手申诉图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改罚单✕
+
+
+
+
+
+
+
+
+
+
+ 撤销罚单✕
+
+
+
+
+
+
+
+
+
+ 再次申请✕
+
+
+
+
+
+
+
+
diff --git a/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxss b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxss
new file mode 100644
index 0000000..506ba33
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-fakuan-list/merchant-fakuan-list.wxss
@@ -0,0 +1,17 @@
+@import '../../../../pages/penalty/components/fakuan-list/fakuan-list.wxss';
+
+.staff { color: #1565C0; }
+.link { color: #1565C0; }
+.warn { background: #E53935; color: #fff; }
+.sub-modal { z-index: 1000; }
+.modal-panel.small { max-height: 60vh; }
+.input-num {
+ width: 100%;
+ box-sizing: border-box;
+ margin-top: 16rpx;
+ padding: 16rpx;
+ background: #f9f9f9;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+}
+.progress-text { font-size: 22rpx; color: #1565C0; margin-top: 8rpx; }
diff --git a/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.js b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.js
new file mode 100644
index 0000000..6e30691
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.js
@@ -0,0 +1,112 @@
+import request from '../../../../utils/request.js';
+
+const app = getApp();
+const MEIYE = 10;
+
+Component({
+ properties: {
+ status: { type: Number, value: 0, observer: 'reload' },
+ trigger: { type: Number, value: 0, observer: 'reload' }
+ },
+
+ data: {
+ list: [],
+ page: 1,
+ hasMore: true,
+ loading: false,
+ loadingMore: false,
+ ossImageUrl: app.globalData.ossImageUrl || '',
+ showDetail: false,
+ detailItem: {}
+ },
+
+ lifetimes: {
+ attached() { this.reload(); }
+ },
+
+ methods: {
+ reload() {
+ this.setData({ page: 1, list: [], hasMore: true });
+ this.loadData();
+ },
+
+ mapItem(item) {
+ const n = Number(item.sqzhuangtai);
+ let display_status = '未知', status_class = 'zhuangtai-weizhi';
+ if (n === 0) { display_status = '待处理'; status_class = 'zhuangtai-daijiaona'; }
+ else if (n === 1) { display_status = '已处罚'; status_class = 'zhuangtai-yijiaona'; }
+ else if (n === 2) { display_status = '已撤销'; status_class = 'zhuangtai-yibohui'; }
+ else if (n === 3) { display_status = '申诉中'; status_class = 'zhuangtai-shensuzhong'; }
+
+ return {
+ ...item,
+ display_status,
+ status_class,
+ display_time: item.CreateTime || item.create_time || '--',
+ full_zhengju: (item.zhengju_tupian || []).map(u => this.fullUrl(u)),
+ full_shensu: (item.shensu_tupian || []).map(u => this.fullUrl(u))
+ };
+ },
+
+ fullUrl(url) {
+ if (!url) return '';
+ if (url.startsWith('http')) return url;
+ return this.data.ossImageUrl + url;
+ },
+
+ async loadData(isLoadMore = false) {
+ if (this.data.loading || this.data.loadingMore) return;
+ if (isLoadMore && !this.data.hasMore) return;
+ if (isLoadMore) this.setData({ loadingMore: true });
+ else this.setData({ loading: true });
+
+ try {
+ const res = await request({
+ url: '/yonghu/sjcfjlhq',
+ method: 'POST',
+ data: { page: this.data.page, page_size: MEIYE, zhuangtai: this.data.status }
+ });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ const data = res.data.data;
+ const rows = (data.list || []).map(item => this.mapItem(item));
+ const newList = isLoadMore ? this.data.list.concat(rows) : rows;
+ this.setData({
+ list: newList,
+ hasMore: data.has_more === true,
+ page: this.data.page + 1,
+ loading: false,
+ loadingMore: false
+ });
+ } else {
+ this.setData({ loading: false, loadingMore: false, hasMore: false });
+ }
+ } catch (e) {
+ this.setData({ loading: false, loadingMore: false });
+ }
+ },
+
+ loadMore() {
+ if (!this.data.hasMore || this.data.loadingMore) return;
+ this.loadData(true);
+ },
+
+ openDetail(e) {
+ this.setData({ showDetail: true, detailItem: e.currentTarget.dataset.item });
+ },
+
+ closeDetail() {
+ this.setData({ showDetail: false, detailItem: {} });
+ },
+
+ goOrder(e) {
+ const id = e.currentTarget.dataset.id;
+ if (!id) return;
+ wx.navigateTo({ url: `/pages/merchant-order-detail/merchant-order-detail?dingdan_id=${id}` });
+ },
+
+ previewImage(e) {
+ const url = e.currentTarget.dataset.url;
+ wx.previewImage({ current: url, urls: [url] });
+ }
+ }
+});
diff --git a/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.json b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxml b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxml
new file mode 100644
index 0000000..e16d1f2
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxml
@@ -0,0 +1,60 @@
+
+
+ 加载中...
+
+
+
+ {{ item.display_time }}
+ {{ item.display_status }}
+
+ 扣分:{{ item.jifen }} 积分
+ 理由:{{ item.cfliyou }}
+ 订单:{{ item.dingdan_id }}
+
+
+ —— 没有更多了 ——
+ 暂无积分处罚记录
+
+
+
+
+
+ 积分处罚详情
+ ✕
+
+
+ 扣分{{ detailItem.jifen }} 积分
+ 状态{{ detailItem.display_status }}
+ 处罚理由{{ detailItem.cfliyou }}
+
+ 关联订单
+ {{ detailItem.dingdan_id }} ›
+
+ 申诉理由{{ detailItem.ssliyou }}
+
+ 商家证据图
+
+
+
+
+
+
+
+
+
+ 打手申诉图
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxss b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxss
new file mode 100644
index 0000000..c336397
--- /dev/null
+++ b/pages/merchant-penalty/components/merchant-jifen-list/merchant-jifen-list.wxss
@@ -0,0 +1,3 @@
+@import '../../../../pages/penalty/components/fakuan-list/fakuan-list.wxss';
+
+.link { color: #1565C0; }
diff --git a/pages/merchant-penalty/merchant-penalty.js b/pages/merchant-penalty/merchant-penalty.js
new file mode 100644
index 0000000..61606c1
--- /dev/null
+++ b/pages/merchant-penalty/merchant-penalty.js
@@ -0,0 +1,88 @@
+import request from '../../utils/request.js';
+
+Page({
+ data: {
+ stats: {
+ fakuan: {
+ total: 0, total_jine: '0.00',
+ daijiaona: 0, daijiaona_jine: '0.00',
+ yijiaona: 0, yijiaona_jine: '0.00',
+ shensuzhong: 0, shensuzhong_jine: '0.00',
+ yibohui: 0, yibohui_jine: '0.00',
+ shijidaozhang_jine: '0.00'
+ },
+ jifen: {
+ total: 0, total_jifen: 0,
+ daichuli: 0, daichuli_jifen: 0,
+ yichuli: 0, yichuli_jifen: 0
+ }
+ },
+ 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/sjcftjhq', method: 'POST' });
+ if (res.statusCode === 200 && res.data.code === 0) {
+ this.setData({ stats: res.data.data });
+ }
+ } catch (e) {
+ console.error('获取商家处罚统计失败', e);
+ }
+ },
+
+ 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);
+ },
+
+ bumpTrigger(tab) {
+ const key = `trigger.${tab}`;
+ this.setData({ [key]: this.data.trigger[tab] + 1 });
+ },
+
+ onPenaltyChanged() {
+ this.fetchTongji();
+ this.bumpTrigger('fakuan');
+ }
+});
diff --git a/pages/merchant-penalty/merchant-penalty.json b/pages/merchant-penalty/merchant-penalty.json
new file mode 100644
index 0000000..2fe1f4a
--- /dev/null
+++ b/pages/merchant-penalty/merchant-penalty.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "处罚管理",
+ "usingComponents": {
+ "merchant-fakuan-list": "./components/merchant-fakuan-list/merchant-fakuan-list",
+ "merchant-jifen-list": "./components/merchant-jifen-list/merchant-jifen-list"
+ }
+}
diff --git a/pages/merchant-penalty/merchant-penalty.wxml b/pages/merchant-penalty/merchant-penalty.wxml
new file mode 100644
index 0000000..bf53118
--- /dev/null
+++ b/pages/merchant-penalty/merchant-penalty.wxml
@@ -0,0 +1,76 @@
+
+
+ 金额罚单汇总
+
+
+ ¥{{ stats.fakuan.total_jine }}
+ 总金额
+
+
+ ¥{{ stats.fakuan.daijiaona_jine }}
+ 待缴纳
+
+
+ ¥{{ stats.fakuan.yijiaona_jine }}
+ 已缴纳
+
+
+
+ 申诉中 ¥{{ stats.fakuan.shensuzhong_jine }}
+ 已驳回 ¥{{ stats.fakuan.yibohui_jine }}
+ 实际到账 ¥{{ stats.fakuan.shijidaozhang_jine }}
+
+ 积分处罚汇总
+
+
+ {{ stats.jifen.total_jifen }}
+ 总积分
+
+
+ {{ stats.jifen.daichuli_jifen }}
+ 待处理
+
+
+ {{ stats.jifen.yichuli_jifen }}
+ 已处理
+
+
+
+
+
+ 金额罚单
+ 积分处罚
+
+
+
+
+ 待缴纳 {{ stats.fakuan.daijiaona }}
+ 申诉中 {{ stats.fakuan.shensuzhong }}
+ 已缴纳 {{ stats.fakuan.yijiaona }}
+ 已驳回 {{ stats.fakuan.yibohui }}
+
+
+
+ 搜索
+ ✕
+
+
+
+
+ 待处理 {{ stats.jifen.daichuli }}
+ 已处理 {{ stats.jifen.yichuli }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/merchant-penalty/merchant-penalty.wxss b/pages/merchant-penalty/merchant-penalty.wxss
new file mode 100644
index 0000000..ed3f383
--- /dev/null
+++ b/pages/merchant-penalty/merchant-penalty.wxss
@@ -0,0 +1,76 @@
+page { background: #f7f8fa; }
+.page-container { padding-bottom: 30rpx; }
+
+.stats-card {
+ margin: 24rpx 28rpx;
+ padding: 28rpx 24rpx;
+ background: #fff;
+ border-radius: 24rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
+}
+.stats-title { font-size: 28rpx; font-weight: 600; color: #333; margin-bottom: 16rpx; }
+.jifen-title { margin-top: 20rpx; padding-top: 16rpx; border-top: 1rpx solid #eee; }
+.money-row { display: flex; justify-content: space-around; margin-bottom: 12rpx; }
+.money-row.sub { justify-content: space-between; font-size: 22rpx; color: #888; padding: 8rpx 0; }
+.money-item { display: flex; flex-direction: column; align-items: center; }
+.money-num { font-size: 32rpx; font-weight: 700; color: #333; }
+.money-num.orange { color: #E67E22; }
+.money-num.green { color: #2E7D32; }
+.money-label { font-size: 22rpx; color: #999; margin-top: 6rpx; }
+
+.tab-row {
+ display: flex;
+ margin: 16rpx 28rpx;
+ background: #fff;
+ border-radius: 18rpx;
+ overflow: hidden;
+}
+.tab-item {
+ flex: 1;
+ text-align: center;
+ padding: 24rpx 0;
+ font-size: 28rpx;
+ color: #666;
+}
+.tab-item.active {
+ color: #1565C0;
+ font-weight: 600;
+ background: #E3F2FD;
+}
+
+.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;
+}
+.sub-tag.sub-active {
+ background: #E3F2FD;
+ color: #1565C0;
+ font-weight: 600;
+}
+
+.search-bar {
+ display: flex;
+ align-items: center;
+ margin: 16rpx 28rpx;
+ background: #fff;
+ border-radius: 20rpx;
+ padding: 12rpx 22rpx;
+}
+.search-input { flex: 1; font-size: 26rpx; }
+.search-btn {
+ margin-left: 18rpx;
+ padding: 12rpx 30rpx;
+ background: #1565C0;
+ color: #fff;
+ border-radius: 16rpx;
+ font-size: 24rpx;
+}
+.clear-btn { margin-left: 16rpx; color: #aaa; }
+
+.list-area { margin-top: 10rpx; }
diff --git a/pages/merchant-recharge/merchant-recharge.js b/pages/merchant-recharge/merchant-recharge.js
index 889cfee..518da2f 100644
--- a/pages/merchant-recharge/merchant-recharge.js
+++ b/pages/merchant-recharge/merchant-recharge.js
@@ -1,5 +1,6 @@
// pages/shangjia-chongzhi/index.js
import request from '../../utils/request';
+import { guardMerchantOwnerAction } from '../../utils/staff-api.js';
Page({
data: {
@@ -37,6 +38,10 @@ Page({
},
onLoad() {
+ if (!guardMerchantOwnerAction('仅商家老板可充值')) {
+ setTimeout(() => wx.navigateBack(), 1200);
+ return;
+ }
this.initPage();
},
diff --git a/pages/merchant-regular-dispatch/merchant-regular-dispatch.js b/pages/merchant-regular-dispatch/merchant-regular-dispatch.js
new file mode 100644
index 0000000..d1c3a09
--- /dev/null
+++ b/pages/merchant-regular-dispatch/merchant-regular-dispatch.js
@@ -0,0 +1,374 @@
+// pages/merchant-regular-dispatch/merchant-regular-dispatch.js
+import { createPage, request } from '../../utils/base-page.js';
+import {
+ STAFF_API, isStaffMode, refreshStaffContext, getStaffContext,
+ restoreStaffContextAfterAuth, isMerchantPortalUser, staffOrOwner,
+} from '../../utils/staff-api.js';
+
+const PAGE_SIZE = 50;
+
+function apiOk(res) {
+ const code = res && res.data && res.data.code;
+ return code === 200 || code === 0;
+}
+
+Page(createPage({
+ data: {
+ sjyue: '0.00',
+ isStaffMode: false,
+ balanceLabel: '可用余额',
+ balanceTip: '派单将从此余额扣除',
+
+ shangpinList: [],
+ selectedTypeId: null,
+ selectedHuiyuanId: null,
+ selectedYaoqiuleixing: null,
+ currentTypeChenghaoList: [],
+
+ dingdanJieshao: '',
+ dingdanBeizhu: '',
+ laobanName: '',
+ waibuDingdanId: '',
+ zhidingUid: '',
+ jiage: '',
+ selectedLabelId: '',
+ selectedLabelName: '',
+ commissionEnabled: false,
+ commissionValue: '',
+
+ showTemplateSheet: false,
+ templateKeyword: '',
+ templateList: [],
+ templatePage: 1,
+ templateHasMore: true,
+ templateLoading: false,
+
+ isLoading: false,
+ isSubmitting: false,
+ },
+
+ async onLoad() {
+ if (wx.getStorageSync('token')) {
+ await restoreStaffContextAfterAuth();
+ }
+ if (!isMerchantPortalUser()) {
+ wx.showToast({ title: '请先成为商家或绑定客服', icon: 'none' });
+ setTimeout(() => wx.navigateBack(), 1500);
+ return;
+ }
+ this.loadShangjiaYue();
+ this.loadShangpinTypes();
+ },
+
+ onShow() {
+ this.loadShangjiaYue();
+ this.registerNotificationComponent();
+ },
+
+ loadShangjiaYue() {
+ const staff = isStaffMode();
+ this.setData({
+ isStaffMode: staff,
+ balanceLabel: staff ? '可用额度' : '可用余额',
+ balanceTip: staff ? '派单将从您的客服额度扣除(需老板先划额度)' : '派单将从此余额扣除',
+ });
+ if (staff) {
+ const ctx = getStaffContext() || {};
+ const wallet = ctx.wallet || {};
+ this.setData({ sjyue: wallet.quota_available || '0.00' });
+ refreshStaffContext(request).then((fresh) => {
+ const w = (fresh && fresh.wallet) || wallet;
+ this.setData({ sjyue: w.quota_available || '0.00' });
+ }).catch(() => {});
+ return;
+ }
+ const app = getApp();
+ const shangjiaData = app.globalData.shangjia || {};
+ this.setData({ sjyue: shangjiaData.sjyue || '0.00' });
+ },
+
+ async loadShangpinTypes() {
+ this.setData({ isLoading: true });
+ const staff = isStaffMode();
+ try {
+ const res = await request({
+ url: staff ? STAFF_API.productTypes : '/dingdan/sjspleixing',
+ method: 'POST',
+ });
+ if (apiOk(res)) {
+ let list = res.data.data || [];
+ if (!Array.isArray(list) && list.list) list = list.list;
+ list.reverse();
+ this.setData({ shangpinList: list, isLoading: false });
+ if (list.length > 0) {
+ this.setSelectedType(list[0]);
+ }
+ } else {
+ throw new Error((res.data && res.data.msg) || '加载失败');
+ }
+ } catch (error) {
+ console.error('加载商品类型失败:', error);
+ this.setData({ isLoading: false });
+ wx.showToast({ title: error.message || '加载类型失败', icon: 'none' });
+ }
+ },
+
+ setSelectedType(item) {
+ this.setData({
+ selectedTypeId: item.id,
+ selectedHuiyuanId: item.huiyuan_id,
+ selectedYaoqiuleixing: item.yaoqiuleixing,
+ currentTypeChenghaoList: item.chenghaoList || [],
+ dingdanJieshao: '',
+ jiage: '',
+ selectedLabelId: '',
+ selectedLabelName: '',
+ commissionEnabled: false,
+ commissionValue: '',
+ });
+ },
+
+ onSelectType(e) {
+ const { item } = e.currentTarget.dataset;
+ this.setSelectedType(item);
+ },
+
+ openTemplateSheet() {
+ if (!this.data.selectedTypeId) {
+ wx.showToast({ title: '请先选择订单类型', icon: 'none' });
+ return;
+ }
+ this.setData({
+ showTemplateSheet: true,
+ templateKeyword: '',
+ templateList: [],
+ templatePage: 1,
+ templateHasMore: true,
+ }, () => this.loadTemplates(true));
+ },
+
+ closeTemplateSheet() {
+ this.setData({ showTemplateSheet: false });
+ },
+
+ onTemplateKeywordInput(e) {
+ this.setData({ templateKeyword: e.detail.value });
+ },
+
+ onTemplateSearch() {
+ this.setData({ templateList: [], templatePage: 1, templateHasMore: true }, () => {
+ this.loadTemplates(true);
+ });
+ },
+
+ onTemplateScrollLower() {
+ const { templateHasMore, templateLoading } = this.data;
+ if (!templateHasMore || templateLoading) return;
+ this.setData({ templatePage: this.data.templatePage + 1 }, () => this.loadTemplates(false));
+ },
+
+ async loadTemplates(reset) {
+ const { selectedTypeId, templatePage, templateKeyword } = this.data;
+ if (!selectedTypeId) return;
+ this.setData({ templateLoading: true });
+ try {
+ const postData = {
+ shangpinTypeId: selectedTypeId,
+ page: templatePage,
+ pageSize: PAGE_SIZE,
+ getType: 1,
+ };
+ if (templateKeyword.trim()) {
+ postData.keyword = templateKeyword.trim();
+ }
+ const res = await request({
+ url: staffOrOwner(STAFF_API.templateList, '/peizhi/sjddmblb'),
+ method: 'POST',
+ data: postData,
+ });
+ if (apiOk(res)) {
+ const data = res.data.data || {};
+ const newTemplates = (data.list || []).map((item) => ({
+ mobanId: item.mobanId || item.id,
+ jieshao: item.jieshao || item.moban_jieshao || '',
+ jiage: item.jiage || item.price || '',
+ labelId: item.labelId || '',
+ labelName: item.labelName || '',
+ commissionEnabled: !!item.commissionEnabled,
+ commissionValue: item.commissionValue || '',
+ }));
+ const merged = reset || templatePage === 1
+ ? newTemplates
+ : [...this.data.templateList, ...newTemplates];
+ this.setData({
+ templateList: merged,
+ templateHasMore: data.hasMore !== false && newTemplates.length === PAGE_SIZE,
+ templateLoading: false,
+ });
+ } else {
+ this.setData({ templateLoading: false, templateHasMore: false });
+ }
+ } catch (e) {
+ console.error(e);
+ this.setData({ templateLoading: false });
+ wx.showToast({ title: '加载模板失败', icon: 'none' });
+ }
+ },
+
+ onSelectTemplate(e) {
+ const { item } = e.currentTarget.dataset;
+ if (!item) return;
+ this.setData({
+ dingdanJieshao: item.jieshao || '',
+ jiage: String(item.jiage || ''),
+ selectedLabelId: item.labelId || '',
+ selectedLabelName: item.labelName || this.getLabelNameById(item.labelId),
+ commissionEnabled: !!item.commissionEnabled,
+ commissionValue: item.commissionValue || '',
+ showTemplateSheet: false,
+ });
+ },
+
+ getLabelNameById(labelId) {
+ if (!labelId) return '';
+ const found = this.data.currentTypeChenghaoList.find((x) => x.id == labelId);
+ return found ? found.mingcheng : '';
+ },
+
+ onDingdanBeizhuInput(e) { this.setData({ dingdanBeizhu: e.detail.value }); },
+ onLaobanNameInput(e) { this.setData({ laobanName: e.detail.value }); },
+ onWaibuDingdanIdInput(e) { this.setData({ waibuDingdanId: e.detail.value }); },
+ onZhidingUidInput(e) { this.setData({ zhidingUid: e.detail.value }); },
+
+ validateForm() {
+ const { selectedTypeId, dingdanJieshao, laobanName, jiage, sjyue } = this.data;
+ if (!selectedTypeId) {
+ wx.showToast({ title: '请选择订单类型', icon: 'none' });
+ return false;
+ }
+ if (!dingdanJieshao.trim()) {
+ wx.showToast({ title: '请选择订单模板', icon: 'none' });
+ return false;
+ }
+ if (!laobanName.trim()) {
+ wx.showToast({ title: '请输入老板游戏昵称', icon: 'none' });
+ return false;
+ }
+ if (!jiage) {
+ wx.showToast({ title: '模板价格无效', icon: 'none' });
+ return false;
+ }
+ const price = parseFloat(jiage);
+ if (isNaN(price) || price < 0.1 || price > 10000) {
+ wx.showToast({ title: '价格需在0.1-10000元之间', icon: 'none' });
+ return false;
+ }
+ const balance = parseFloat(sjyue);
+ if (price > balance) {
+ if (this.data.isStaffMode) {
+ wx.showModal({
+ title: '额度不足',
+ content: `当前可用额度${sjyue}元,需要${jiage}元。请联系商家老板划额度。`,
+ showCancel: false,
+ });
+ } else {
+ wx.showModal({
+ title: '余额不足',
+ content: `当前余额${sjyue}元,需要${jiage}元。请先充值。`,
+ confirmText: '去充值',
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({ url: '/pages/merchant-recharge/merchant-recharge' });
+ }
+ },
+ });
+ }
+ return false;
+ }
+ return true;
+ },
+
+ resetForm() {
+ this.setData({
+ dingdanJieshao: '',
+ dingdanBeizhu: '',
+ laobanName: '',
+ waibuDingdanId: '',
+ zhidingUid: '',
+ jiage: '',
+ selectedLabelId: '',
+ selectedLabelName: '',
+ commissionEnabled: false,
+ commissionValue: '',
+ });
+ if (this.data.shangpinList.length > 0) {
+ this.setSelectedType(this.data.shangpinList[0]);
+ }
+ },
+
+ async onSubmit() {
+ if (this.data.isSubmitting) return;
+ if (!this.validateForm()) return;
+ this.setData({ isSubmitting: true });
+
+ const postData = {
+ shangpinTypeId: this.data.selectedTypeId,
+ huiyuanId: this.data.selectedHuiyuanId,
+ yaoqiuleixing: this.data.selectedYaoqiuleixing,
+ dingdanJieshao: this.data.dingdanJieshao.trim(),
+ dingdanBeizhu: this.data.dingdanBeizhu.trim() || '',
+ laobanName: this.data.laobanName.trim(),
+ zhidingUid: this.data.zhidingUid.trim() || '',
+ waibuDingdanId: this.data.waibuDingdanId.trim() || '',
+ jiage: this.data.jiage,
+ labelId: this.data.selectedLabelId || '',
+ labelName: this.data.selectedLabelName || '',
+ commissionEnabled: this.data.commissionEnabled,
+ commissionValue: this.data.commissionEnabled ? this.data.commissionValue : '',
+ };
+
+ try {
+ const res = await request({
+ url: isStaffMode() ? STAFF_API.orderDispatch : '/dingdan/sjpaifa',
+ method: 'POST',
+ data: postData,
+ });
+ if (res && res.data.code === 200) {
+ wx.showToast({ title: '派单成功', icon: 'success', duration: 2000 });
+ const orderAmount = parseFloat(this.data.jiage);
+ if (this.data.isStaffMode) {
+ this.loadShangjiaYue();
+ } else {
+ const app = getApp();
+ if (app.globalData.shangjia) {
+ const newBalance = parseFloat(app.globalData.shangjia.sjyue || '0') - orderAmount;
+ app.globalData.shangjia.sjyue = newBalance.toFixed(2);
+ app.globalData.shangjia.fadanzong = (parseInt(app.globalData.shangjia.fadanzong || '0') + 1).toString();
+ app.globalData.shangjia.riliushui = (parseFloat(app.globalData.shangjia.riliushui || '0') + orderAmount).toFixed(2);
+ app.globalData.shangjia.yueliushui = (parseFloat(app.globalData.shangjia.yueliushui || '0') + orderAmount).toFixed(2);
+ this.setData({ sjyue: app.globalData.shangjia.sjyue });
+ }
+ }
+ setTimeout(() => {
+ this.resetForm();
+ this.setData({ isSubmitting: false });
+ }, 1500);
+ } else {
+ wx.showModal({
+ title: '派单失败',
+ content: res.data.msg || '请稍后重试',
+ showCancel: false,
+ });
+ this.setData({ isSubmitting: false });
+ }
+ } catch (error) {
+ console.error('派单请求失败:', error);
+ wx.showModal({
+ title: '请求失败',
+ content: error.message || '网络错误,请检查连接',
+ showCancel: false,
+ });
+ this.setData({ isSubmitting: false });
+ }
+ },
+}));
diff --git a/pages/merchant-regular-dispatch/merchant-regular-dispatch.json b/pages/merchant-regular-dispatch/merchant-regular-dispatch.json
new file mode 100644
index 0000000..5311e9b
--- /dev/null
+++ b/pages/merchant-regular-dispatch/merchant-regular-dispatch.json
@@ -0,0 +1,13 @@
+{
+ "usingComponents": {
+ "global-notification": "/components/global-notification/global-notification",
+ "popup-notice": "/components/popup-notice/popup-notice",
+ "chenghao-tag": "/components/chenghao-tag/chenghao-tag"
+ },
+ "backgroundTextStyle": "dark",
+ "navigationBarBackgroundColor": "#fff8e1",
+ "navigationBarTitleText": "常规发单",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#f5f5f5",
+ "enablePullDownRefresh": false
+}
diff --git a/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxml b/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxml
new file mode 100644
index 0000000..f919af5
--- /dev/null
+++ b/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxml
@@ -0,0 +1,184 @@
+
+
+
+ {{balanceLabel}}
+
+ {{sjyue}}
+ 元
+
+ {{balanceTip}}
+
+
+
+
+
+
+ {{item.jieshao}}
+
+
+
+
+
+
+
+
+
+ 订单介绍
+ *
+
+
+ {{dingdanJieshao || '点击选择模板'}}
+ ▸
+
+
+
+
+
+ 订单价格
+ *
+
+
+ ¥
+ {{jiage || '0.00'}}
+
+
+ 标签:{{selectedLabelName}}
+ 押金:¥{{commissionValue}}
+
+
+
+
+
+
+
+
+
+ 订单备注
+ 选填
+ {{dingdanBeizhu.length}}/50
+
+
+
+
+
+
+ 老板昵称/ID
+ *
+ {{laobanName.length}}/15
+
+
+
+
+
+
+ 拼多多订单号
+ 选填
+
+
+
+
+
+
+ 指定UID
+ 选填
+
+
+
+
+
+
+
+
+
+ {{isSubmitting ? '派发中...' : '立即派发'}}
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+ 选择订单模板
+ ×
+
+
+
+ 搜索
+
+
+
+
+ {{item.jieshao || '无介绍'}}
+
+
+ ¥{{item.jiage || '0.00'}}
+
+
+
+ 暂无模板
+ 加载中...
+
+
+
+
+
+
+
diff --git a/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxss b/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxss
new file mode 100644
index 0000000..2ea80fa
--- /dev/null
+++ b/pages/merchant-regular-dispatch/merchant-regular-dispatch.wxss
@@ -0,0 +1,343 @@
+@import '../../styles/shangjia-xym-form.wxss';
+
+page {
+ background: #f5f5f5;
+}
+
+.balance-row {
+ display: flex;
+ align-items: baseline;
+ justify-content: center;
+ margin: 12rpx 0 8rpx;
+}
+
+.balance-value {
+ font-size: 52rpx;
+ font-weight: 700;
+ line-height: 1;
+}
+
+.balance-unit {
+ font-size: 26rpx;
+ margin-left: 6rpx;
+ font-weight: 500;
+}
+
+.balance-tip {
+ font-size: 20rpx;
+ display: block;
+}
+
+.card-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20rpx;
+}
+
+.card-dot {
+ width: 8rpx;
+ height: 8rpx;
+ border-radius: 4rpx;
+ margin-right: 12rpx;
+ flex-shrink: 0;
+}
+
+.type-scroll {
+ white-space: nowrap;
+ display: flex;
+ padding: 8rpx 0;
+}
+
+.field {
+ margin-bottom: 24rpx;
+}
+
+.field:last-child {
+ margin-bottom: 0;
+}
+
+.field-head {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10rpx;
+}
+
+.field-label {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.field-required {
+ font-size: 26rpx;
+ color: #e04040;
+ margin-left: 4rpx;
+}
+
+.field-optional {
+ font-size: 20rpx;
+ color: #bbb;
+ margin-left: 8rpx;
+}
+
+.field-count {
+ font-size: 20rpx;
+ color: #ccc;
+ margin-left: auto;
+}
+
+.field-input {
+ width: 100%;
+ height: 76rpx;
+ background: #f7f7f7;
+ border-radius: 12rpx;
+ padding: 0 20rpx;
+ font-size: 26rpx;
+ color: #333;
+ border: 1rpx solid #eee;
+ box-sizing: border-box;
+}
+
+.field-readonly {
+ background: #fafafa;
+ color: #666;
+}
+
+.field-picker {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 76rpx;
+ background: #f7f7f7;
+ border-radius: 12rpx;
+ padding: 16rpx 20rpx;
+ border: 1rpx solid #eee;
+ font-size: 26rpx;
+ color: #333;
+}
+
+.field-picker-ph {
+ color: #bbb;
+}
+
+.field-picker-arrow {
+ font-size: 24rpx;
+ color: #ccc;
+ flex-shrink: 0;
+ margin-left: 12rpx;
+}
+
+.price-display {
+ display: flex;
+ align-items: baseline;
+ height: 76rpx;
+ background: #fafafa;
+ border-radius: 12rpx;
+ padding: 0 20rpx;
+ border: 1rpx solid #eee;
+}
+
+.price-prefix {
+ font-size: 28rpx;
+ font-weight: 700;
+ color: #e04040;
+ margin-right: 8rpx;
+}
+
+.price-value {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #e04040;
+}
+
+.template-meta {
+ margin-top: 12rpx;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12rpx;
+ align-items: center;
+}
+
+.template-meta-label {
+ font-size: 22rpx;
+ color: #999;
+}
+
+.bottom-space {
+ height: 20rpx;
+}
+
+.submit-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: #fff;
+ padding: 16rpx 24rpx;
+ padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
+ border-top: 1rpx solid #f0f0f0;
+ z-index: 9999;
+}
+
+.submit-btn {
+ height: 88rpx;
+ background: #e04040;
+ border-radius: 12rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #fff;
+ letter-spacing: 2rpx;
+}
+
+.submit-btn--hover {
+ opacity: 0.85;
+}
+
+.submit-btn--disabled {
+ opacity: 0.5;
+ pointer-events: none;
+}
+
+.loading-mask {
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(255,255,255,0.8);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10000;
+}
+
+.loading-box {
+ background: #fff;
+ padding: 48rpx 64rpx;
+ border-radius: 16rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.08);
+}
+
+.loading-spinner {
+ width: 44rpx;
+ height: 44rpx;
+ border: 4rpx solid #eee;
+ border-top-color: #333;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ margin-bottom: 16rpx;
+}
+
+.loading-text {
+ font-size: 24rpx;
+ color: #666;
+}
+
+/* 模板选择底部弹层 */
+.sheet-mask {
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0,0,0,0.45);
+ z-index: 10001;
+}
+
+.sheet-panel {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ max-height: 75vh;
+ background: #fff;
+ border-radius: 24rpx 24rpx 0 0;
+ z-index: 10002;
+ display: flex;
+ flex-direction: column;
+}
+
+.sheet-hd {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 28rpx 24rpx 16rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+}
+
+.sheet-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #333;
+}
+
+.sheet-close {
+ font-size: 40rpx;
+ color: #999;
+ line-height: 1;
+ padding: 0 8rpx;
+}
+
+.sheet-search {
+ display: flex;
+ align-items: center;
+ margin: 16rpx 24rpx;
+ background: #f5f5f5;
+ border-radius: 12rpx;
+ padding: 0 16rpx;
+ height: 72rpx;
+}
+
+.sheet-search-input {
+ flex: 1;
+ font-size: 26rpx;
+ height: 72rpx;
+}
+
+.sheet-search-btn {
+ font-size: 26rpx;
+ color: #e04040;
+ font-weight: 600;
+ padding-left: 16rpx;
+}
+
+.sheet-list {
+ flex: 1;
+ min-height: 200rpx;
+ max-height: 50vh;
+}
+
+.sheet-item {
+ padding: 24rpx;
+ border-bottom: 1rpx solid #f5f5f5;
+}
+
+.sheet-item:active {
+ background: #fafafa;
+}
+
+.sheet-item-intro {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8rpx;
+}
+
+.sheet-item-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.sheet-item-price {
+ font-size: 26rpx;
+ color: #e04040;
+ font-weight: 700;
+}
+
+.sheet-empty {
+ text-align: center;
+ padding: 60rpx 24rpx;
+ font-size: 26rpx;
+ color: #999;
+}
diff --git a/pages/merchant-staff-audit/merchant-staff-audit.js b/pages/merchant-staff-audit/merchant-staff-audit.js
new file mode 100644
index 0000000..9b665d3
--- /dev/null
+++ b/pages/merchant-staff-audit/merchant-staff-audit.js
@@ -0,0 +1,99 @@
+import request from '../../utils/request.js';
+import { STAFF_API } from '../../utils/staff-api.js';
+
+const ORDER_AUDIT_ACTIONS = [
+ 'DISPATCH', 'LINK_GENERATE', 'SETTLE', 'CANCEL', 'REFUND_APPLY',
+ 'CHANGE_PLAYER', 'PENALTY_APPLY', 'PENALTY_MANAGE',
+];
+
+Page({
+ data: {
+ tab: 'audit',
+ auditList: [],
+ rankList: [],
+ page: 1,
+ hasMore: true,
+ loading: false,
+ total: 0,
+ },
+
+ onLoad(options) {
+ if (options.tab === 'rank') this.setData({ tab: 'rank' });
+ wx.setNavigationBarTitle({
+ title: options.tab === 'rank' ? '客服排行' : '操作日志',
+ });
+ this.loadData(true);
+ },
+
+ onPullDownRefresh() {
+ this.loadData(true).finally(() => wx.stopPullDownRefresh());
+ },
+
+ onReachBottom() {
+ if (this.data.tab === 'audit' && this.data.hasMore && !this.data.loading) {
+ this.loadAudit(false);
+ }
+ },
+
+ switchTab(e) {
+ const tab = e.currentTarget.dataset.tab;
+ wx.setNavigationBarTitle({ title: tab === 'rank' ? '客服排行' : '操作日志' });
+ this.setData({ tab, page: 1, hasMore: true }, () => this.loadData(true));
+ },
+
+ loadData(reset) {
+ if (this.data.tab === 'audit') return this.loadAudit(reset);
+ return this.loadRank();
+ },
+
+ async loadAudit(reset) {
+ if (this.data.loading) return;
+ const page = reset ? 1 : this.data.page;
+ this.setData({ loading: true });
+ try {
+ const res = await request({
+ url: STAFF_API.auditList,
+ method: 'POST',
+ data: { page, page_size: 20 },
+ });
+ if (res.data && res.data.code === 0) {
+ const d = res.data.data || {};
+ const list = (d.list || []).map((item) => ({
+ ...item,
+ canJumpOrder: ORDER_AUDIT_ACTIONS.indexOf(item.action) >= 0 && !!item.resource_id,
+ }));
+ this.setData({
+ auditList: reset ? list : [...this.data.auditList, ...list],
+ page: page + 1,
+ hasMore: !!d.has_more,
+ total: d.total || 0,
+ loading: false,
+ });
+ } else {
+ this.setData({ loading: false });
+ wx.showToast({ title: res.data?.msg || '加载失败', icon: 'none' });
+ }
+ } catch (e) {
+ this.setData({ loading: false });
+ }
+ },
+
+ async loadRank() {
+ const res = await request({
+ url: STAFF_API.rank,
+ method: 'POST',
+ data: { period: 'month', sort_by: 'dispatch_count' },
+ });
+ if (res.data && res.data.code === 0) {
+ this.setData({ rankList: (res.data.data && res.data.data.list) || [] });
+ }
+ },
+
+ goOrderDetail(e) {
+ const item = e.currentTarget.dataset.item;
+ if (!item || !item.canJumpOrder || !item.resource_id) return;
+ wx.navigateTo({
+ url: `/pages/merchant-order-detail/merchant-order-detail?dingdan_id=${encodeURIComponent(item.resource_id)}`,
+ });
+ },
+});
diff --git a/pages/merchant-staff-audit/merchant-staff-audit.json b/pages/merchant-staff-audit/merchant-staff-audit.json
new file mode 100644
index 0000000..97f600a
--- /dev/null
+++ b/pages/merchant-staff-audit/merchant-staff-audit.json
@@ -0,0 +1,5 @@
+{
+ "navigationBarTitleText": "操作日志",
+ "enablePullDownRefresh": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/pages/merchant-staff-audit/merchant-staff-audit.wxml b/pages/merchant-staff-audit/merchant-staff-audit.wxml
new file mode 100644
index 0000000..ecc1393
--- /dev/null
+++ b/pages/merchant-staff-audit/merchant-staff-audit.wxml
@@ -0,0 +1,39 @@
+
+ 仅记录派单、退款、模板等重要操作,不含普通查看
+
+ 操作日志
+ 客服排行
+
+
+ 共 {{total}} 条重要操作
+
+
+ {{item.action_label || item.action}}
+ ¥{{item.amount}}
+
+
+
+ {{item.role_name || (item.operator_type === 'STAFF' ? '客服' : '老板')}}
+
+ {{item.operator_name}}
+ ID:{{item.operator_user_id}}
+
+ {{item.time}}
+ 订单:{{item.resource_id}}
+ 点击查看订单详情 ›
+
+
+ 加载中...
+ 上拉加载更多
+ 暂无操作日志
+
+
+
+ #{{item.rank}} {{item.display_name}}
+ 派单 {{item.dispatch_count}} 单 · ¥{{item.dispatch_amount}}
+ 结单 {{item.settle_count}} 单 · ¥{{item.settle_amount}}
+
+ 暂无排行数据
+
+
diff --git a/pages/merchant-staff-audit/merchant-staff-audit.wxss b/pages/merchant-staff-audit/merchant-staff-audit.wxss
new file mode 100644
index 0000000..3edb7b4
--- /dev/null
+++ b/pages/merchant-staff-audit/merchant-staff-audit.wxss
@@ -0,0 +1,25 @@
+.page { padding: 24rpx; background: #f5f5f5; min-height: 100vh; box-sizing: border-box; }
+.head-tip { font-size: 24rpx; color: #888; margin-bottom: 16rpx; line-height: 1.5; }
+.tabs { display: flex; margin-bottom: 24rpx; }
+.tab { flex: 1; text-align: center; padding: 20rpx; background: #fff; margin-right: 8rpx; border-radius: 8rpx; font-size: 28rpx; }
+.tab.on { background: #C9A962; color: #fff; }
+.summary { font-size: 24rpx; color: #666; margin-bottom: 16rpx; }
+.item { background: #fff; padding: 24rpx; margin-bottom: 16rpx; border-radius: 12rpx; }
+.item-hd { margin-bottom: 12rpx; }
+.act { font-size: 30rpx; color: #333; font-weight: 600; }
+.amount { font-size: 28rpx; color: #C9A962; }
+.operator { display: flex; align-items: center; flex-wrap: wrap; gap: 12rpx; margin-bottom: 8rpx; }
+.tag { font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 6rpx; }
+.tag-staff { background: #e8f4ff; color: #1976d2; }
+.tag-owner { background: #fff3e0; color: #e65100; }
+.name { font-size: 26rpx; color: #333; }
+.uid { font-size: 22rpx; color: #999; }
+.meta { display: block; font-size: 24rpx; color: #999; margin-top: 6rpx; }
+.res { display: block; font-size: 24rpx; color: #666; margin-top: 8rpx; word-break: break-all; }
+.remark { display: block; font-size: 24rpx; color: #888; margin-top: 6rpx; }
+.rank { font-weight: 600; font-size: 28rpx; display: block; }
+.load-tip { text-align: center; color: #999; padding: 24rpx; font-size: 24rpx; }
+.empty { text-align: center; color: #999; padding: 80rpx; }
+.item-link { border-left: 6rpx solid #C9A962; }
+.jump-tip { display: block; font-size: 24rpx; color: #C9A962; margin-top: 8rpx; }
+.flexb { display: flex; justify-content: space-between; align-items: center; }
diff --git a/pages/merchant-staff-role/merchant-staff-role.js b/pages/merchant-staff-role/merchant-staff-role.js
new file mode 100644
index 0000000..9ba3950
--- /dev/null
+++ b/pages/merchant-staff-role/merchant-staff-role.js
@@ -0,0 +1,236 @@
+/** 商家老板:角色与权限管理 */
+import request from '../../utils/request.js';
+import { STAFF_API, isStaffMode, isMerchantOwnerOnly } from '../../utils/staff-api.js';
+
+/** 与后端 constants.PERMISSION_DEFINITIONS 一致,接口为空时前端兜底 */
+const FALLBACK_PERMISSIONS = [
+ { perm_code: 'staff_manage', perm_name: '子客服管理' },
+ { perm_code: 'role_manage', perm_name: '角色管理' },
+ { perm_code: 'wallet_allocate', perm_name: '划额度' },
+ { perm_code: 'wallet_revoke', perm_name: '收回额度' },
+ { perm_code: 'wallet_view', perm_name: '查看额度' },
+ { perm_code: 'finance_view', perm_name: '查看商家余额' },
+ { perm_code: 'order_dispatch', perm_name: '派单发单' },
+ { perm_code: 'order_view_all', perm_name: '查看全部订单' },
+ { perm_code: 'order_view_self', perm_name: '只看自己派的单' },
+ { perm_code: 'order_detail', perm_name: '订单详情' },
+ { perm_code: 'order_settle', perm_name: '结单' },
+ { perm_code: 'order_refund_apply', perm_name: '申请退款' },
+ { perm_code: 'order_cancel', perm_name: '撤销订单' },
+ { perm_code: 'order_change_player', perm_name: '换打手' },
+ { perm_code: 'penalty_apply', perm_name: '申请罚单' },
+ { perm_code: 'penalty_manage', perm_name: '改撤罚单' },
+ { perm_code: 'penalty_view', perm_name: '查看罚单' },
+ { perm_code: 'staff_disable', perm_name: '封禁解封客服' },
+ { perm_code: 'template_manage', perm_name: '派单模板' },
+ { perm_code: 'audit_view', perm_name: '操作日志' },
+ { perm_code: 'rank_view', perm_name: '客服排行榜' },
+ { perm_code: 'im_chat', perm_name: '订单IM' },
+ { perm_code: 'stats_view', perm_name: '统计数据' },
+];
+
+Page({
+ data: {
+ statusBar: 20,
+ permScrollHeight: 360,
+ loading: false,
+ roles: [],
+ rawPermissions: [],
+ permissionOptions: [],
+ selectedPerms: [],
+ showEditPanel: false,
+ showCreatePanel: false,
+ editingRoleId: null,
+ editingRoleName: '',
+ newRoleName: '',
+ },
+
+ onLoad() {
+ const sys = wx.getSystemInfoSync();
+ const h = sys.windowHeight || 667;
+ this.setData({
+ statusBar: sys.statusBarHeight || 20,
+ permScrollHeight: Math.floor(h * 0.45),
+ });
+ if (!this.ensureOwnerAccess()) return;
+ this.loadRoles();
+ },
+
+ onShow() {
+ if (!isMerchantOwnerOnly()) return;
+ if (!this.data.showEditPanel && !this.data.showCreatePanel) {
+ this.loadRoles();
+ }
+ },
+
+ ensureOwnerAccess() {
+ if (isStaffMode() || Number(wx.getStorageSync('shangjiastatus')) !== 1) {
+ wx.showToast({ title: '仅商家老板可管理角色权限', icon: 'none' });
+ setTimeout(() => wx.navigateBack(), 1200);
+ return false;
+ }
+ return true;
+ },
+
+ /** allPerms: [{perm_code, perm_name}] selectedCodes: ['order_dispatch', ...] */
+ buildPermOptions(allPerms, selectedCodes) {
+ const list = (allPerms && allPerms.length) ? allPerms : FALLBACK_PERMISSIONS;
+ const set = new Set(selectedCodes || []);
+ return list.map((p) => {
+ const code = p.perm_code || p;
+ const name = p.perm_name || code;
+ return {
+ perm_code: code,
+ perm_name: name,
+ checked: set.has(code),
+ };
+ });
+ },
+
+ normalizeRoles(list) {
+ return (list || []).map((r) => ({
+ ...r,
+ permCount: (r.permissions && r.permissions.length) || 0,
+ }));
+ },
+
+ resolveAllPermissions(apiList) {
+ if (apiList && apiList.length) return apiList;
+ return FALLBACK_PERMISSIONS;
+ },
+
+ async loadRoles() {
+ this.setData({ loading: true });
+ try {
+ const res = await request({ url: STAFF_API.roleList, method: 'POST' });
+ if (res.data && res.data.code === 0) {
+ const d = res.data.data || {};
+ const rawPermissions = this.resolveAllPermissions(d.all_permissions);
+ this.setData({
+ roles: this.normalizeRoles(d.roles),
+ rawPermissions,
+ });
+ return rawPermissions;
+ }
+ wx.showToast({ title: (res.data && res.data.msg) || '加载失败', icon: 'none' });
+ } catch (e) {
+ wx.showToast({ title: '加载失败', icon: 'none' });
+ } finally {
+ this.setData({ loading: false });
+ }
+ const fallback = FALLBACK_PERMISSIONS;
+ this.setData({ rawPermissions: fallback });
+ return fallback;
+ },
+
+ goBack() { wx.navigateBack(); },
+
+ openCreate() {
+ const raw = this.data.rawPermissions.length
+ ? this.data.rawPermissions
+ : FALLBACK_PERMISSIONS;
+ this.setData({
+ showCreatePanel: true,
+ showEditPanel: false,
+ newRoleName: '',
+ selectedPerms: [],
+ permissionOptions: this.buildPermOptions(raw, []),
+ });
+ },
+
+ closeCreate() {
+ this.setData({ showCreatePanel: false, permissionOptions: [], selectedPerms: [] });
+ },
+
+ onNameInput(e) {
+ this.setData({ newRoleName: e.detail.value });
+ },
+
+ togglePermItem(e) {
+ const code = e.currentTarget.dataset.code;
+ if (!code) return;
+ const opts = (this.data.permissionOptions || []).map((p) => (
+ p.perm_code === code ? { ...p, checked: !p.checked } : p
+ ));
+ this.setData({
+ permissionOptions: opts,
+ selectedPerms: opts.filter((x) => x.checked).map((x) => x.perm_code),
+ });
+ },
+
+ async editRole(e) {
+ const id = e.currentTarget.dataset.id;
+ let role = this.data.roles.find((r) => String(r.id) === String(id));
+ if (!role) return;
+
+ let rawPermissions = this.data.rawPermissions;
+ if (!rawPermissions.length) {
+ rawPermissions = await this.loadRoles();
+ role = this.data.roles.find((r) => String(r.id) === String(id));
+ if (!role) return;
+ }
+
+ const perms = role.permissions || [];
+ this.setData({
+ showEditPanel: true,
+ showCreatePanel: false,
+ editingRoleId: role.id,
+ editingRoleName: role.role_name || '',
+ selectedPerms: [...perms],
+ permissionOptions: this.buildPermOptions(rawPermissions, perms),
+ });
+ },
+
+ closeEdit() {
+ this.setData({
+ showEditPanel: false,
+ editingRoleId: null,
+ editingRoleName: '',
+ selectedPerms: [],
+ permissionOptions: [],
+ });
+ },
+
+ async saveRolePerms() {
+ const { editingRoleId, selectedPerms } = this.data;
+ if (!editingRoleId) return;
+ wx.showLoading({ title: '保存中' });
+ try {
+ const res = await request({
+ url: STAFF_API.roleSetPerms,
+ method: 'POST',
+ data: { role_id: editingRoleId, permissions: selectedPerms },
+ });
+ wx.showToast({ title: (res.data && res.data.msg) || '已保存', icon: 'none' });
+ if (res.data && res.data.code === 0) {
+ this.closeEdit();
+ this.loadRoles();
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ async createRole() {
+ const name = (this.data.newRoleName || '').trim();
+ if (!name) {
+ wx.showToast({ title: '请输入角色名', icon: 'none' });
+ return;
+ }
+ wx.showLoading({ title: '创建中' });
+ try {
+ const res = await request({
+ url: STAFF_API.roleCreate,
+ method: 'POST',
+ data: { role_name: name, permissions: this.data.selectedPerms },
+ });
+ wx.showToast({ title: (res.data && res.data.msg) || '完成', icon: 'none' });
+ if (res.data && res.data.code === 0) {
+ this.closeCreate();
+ this.loadRoles();
+ }
+ } finally {
+ wx.hideLoading();
+ }
+ },
+});
diff --git a/pages/merchant-staff-role/merchant-staff-role.json b/pages/merchant-staff-role/merchant-staff-role.json
new file mode 100644
index 0000000..5089993
--- /dev/null
+++ b/pages/merchant-staff-role/merchant-staff-role.json
@@ -0,0 +1,4 @@
+{
+ "navigationBarTitleText": "角色与权限",
+ "navigationStyle": "custom"
+}
diff --git a/pages/merchant-staff-role/merchant-staff-role.wxml b/pages/merchant-staff-role/merchant-staff-role.wxml
new file mode 100644
index 0000000..e79c771
--- /dev/null
+++ b/pages/merchant-staff-role/merchant-staff-role.wxml
@@ -0,0 +1,75 @@
+
+
+
+ ‹
+ 角色与权限
+ 新建
+
+
+
+ 可自由创建角色并勾选权限;预置角色也可改权限。
+ 暂无角色,请先新建或联系管理员同步权限
+
+
+ {{item.role_name}}
+ {{item.is_system ? '系统' : '自定义'}}
+
+ {{item.role_hint || ''}}
+ 已授权 {{item.permCount}} 项 · 点击编辑
+
+
+
+
+
+
+
+ 编辑角色权限
+ {{editingRoleName}}
+
+
+
+ {{item.perm_name}}
+ {{item.perm_code}}
+
+ {{item.checked ? '✓' : ''}}
+
+
+
+
+
+
+
+
+
+
+
+
+ 新建角色
+
+
+
+
+ {{item.perm_name}}
+ {{item.perm_code}}
+
+ {{item.checked ? '✓' : ''}}
+
+
+
+
+
+
+
+
diff --git a/pages/merchant-staff-role/merchant-staff-role.wxss b/pages/merchant-staff-role/merchant-staff-role.wxss
new file mode 100644
index 0000000..b606080
--- /dev/null
+++ b/pages/merchant-staff-role/merchant-staff-role.wxss
@@ -0,0 +1,221 @@
+@import '../../styles/shangjia-xym-common.wxss';
+
+.role-page {
+ min-height: 100vh;
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
+ box-sizing: border-box;
+}
+
+.role-nav {
+ padding: 0 24rpx 16rpx;
+}
+
+.nav-back {
+ width: 60rpx;
+ font-size: 48rpx;
+ color: #333;
+}
+
+.nav-title {
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #343434;
+}
+
+.nav-link {
+ width: 60rpx;
+ text-align: right;
+ font-size: 28rpx;
+ color: #c9a962;
+}
+
+.role-scroll {
+ height: calc(100vh - 120rpx);
+}
+
+.role-tip {
+ font-size: 24rpx;
+ color: #888;
+ margin: 20rpx 24rpx;
+}
+
+.role-empty {
+ text-align: center;
+ padding: 80rpx 24rpx;
+ font-size: 26rpx;
+ color: #999;
+}
+
+.role-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin: 0 24rpx 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+}
+
+.role-name {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.role-tag {
+ font-size: 22rpx;
+ color: #999;
+}
+
+.role-sub {
+ display: block;
+ margin-top: 8rpx;
+ font-size: 24rpx;
+ color: #666;
+}
+
+/* 弹层:独立根节点,全屏 fixed */
+.role-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 1000;
+}
+
+.role-mask-bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+}
+
+.role-panel {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: #fff;
+ border-radius: 24rpx 24rpx 0 0;
+ padding: 32rpx 24rpx calc(24rpx + env(safe-area-inset-bottom));
+ z-index: 1001;
+ max-height: 85vh;
+ box-sizing: border-box;
+}
+
+.panel-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.panel-role-name {
+ display: block;
+ margin-top: 8rpx;
+ margin-bottom: 16rpx;
+ font-size: 26rpx;
+ color: #888;
+}
+
+.perm-scroll {
+ width: 100%;
+}
+
+.perm-row {
+ padding: 20rpx 8rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ min-height: 88rpx;
+ box-sizing: border-box;
+}
+
+.perm-row.perm-on {
+ background: #fffbf0;
+}
+
+.perm-text {
+ flex: 1;
+ padding-right: 16rpx;
+}
+
+.perm-name {
+ display: block;
+ font-size: 28rpx;
+ color: #333;
+ line-height: 1.4;
+}
+
+.perm-code {
+ display: block;
+ margin-top: 4rpx;
+ font-size: 22rpx;
+ color: #999;
+}
+
+.perm-check {
+ width: 48rpx;
+ height: 48rpx;
+ line-height: 48rpx;
+ text-align: center;
+ font-size: 32rpx;
+ color: #c9a962;
+ font-weight: 700;
+ border: 2rpx solid #ddd;
+ border-radius: 8rpx;
+ flex-shrink: 0;
+}
+
+.perm-on .perm-check {
+ border-color: #c9a962;
+ background: #c9a962;
+ color: #fff;
+}
+
+.perm-empty {
+ padding: 40rpx 0;
+ text-align: center;
+ font-size: 26rpx;
+ color: #999;
+}
+
+.name-input {
+ border: 1rpx solid #eee;
+ padding: 20rpx;
+ margin: 16rpx 0;
+ border-radius: 8rpx;
+ font-size: 28rpx;
+}
+
+.panel-btns {
+ margin-top: 24rpx;
+ gap: 16rpx;
+}
+
+.panel-btn {
+ flex: 1;
+ margin: 0;
+ padding: 0;
+ height: 88rpx;
+ line-height: 88rpx;
+ font-size: 30rpx;
+ border-radius: 12rpx;
+ border: none;
+}
+
+.panel-btn::after {
+ border: none;
+}
+
+.panel-btn.cancel {
+ background: #f5f5f5;
+ color: #666;
+}
+
+.panel-btn.ok {
+ background: #c9a962;
+ color: #fff;
+}
+
+.btn-hover {
+ opacity: 0.85;
+}
diff --git a/pages/merchant/merchant.js b/pages/merchant/merchant.js
index 2d5a1bb..fcb530e 100644
--- a/pages/merchant/merchant.js
+++ b/pages/merchant/merchant.js
@@ -2,6 +2,14 @@
import { createPage, ensureRoleOnCenterPage, lockPrimaryRole, parseSceneOptions, request } from '../../utils/base-page.js';
import { ensureLogin } from '../../utils/login.js';
+import {
+ STAFF_API, isStaffMode, isMerchantPortalUser, refreshStaffContext, syncStaffUi, getStaffContext,
+ restoreStaffContextAfterAuth, applyStaffStatsToPage, guardMerchantOwnerAction, clearStaffSession,
+} from '../../utils/staff-api.js';
+import { fetchMerchantOrderStats, applyOrderStatsToPage } from '../../utils/merchant-order-stats.js';
+import { clearCacheAndEnterNormal } from '../../utils/base-page.js';
+import { ICON_KEYS, resolveMiniappIcon } from '../../utils/miniapp-icons.js';
+import { getDefaultAvatarUrl } from '../../utils/avatar.js';
const app = getApp();
@@ -32,11 +40,20 @@ Page(createPage({
// 商家状态
isShangjia: false,
+ isStaffMode: false,
+ staffRoleName: '',
+ quotaAvailable: '0.00',
+ canDispatch: true,
+ canStaffManage: true,
+ canAudit: true,
+ showRechargeWithdraw: true,
isAutoRegistering: false,
+ staffBooting: false,
// 用户基础信息
uid: '',
avatarUrl: '',
+ defaultAvatarUrl: '',
nicheng: '',
// 商家核心数据
@@ -48,16 +65,33 @@ Page(createPage({
jinridingdan: 0,
jinrituikuan: 0,
chenghaoList: [],
+ identityTagList: [],
// 交互控制
inviteCode: '',
pendingCount: 0,
punishPending: 0,
+ canViewFinance: true,
+ orderStats: {
+ pending_count: 0,
+ pending_amount: '0.00',
+ completed_count: 0,
+ completed_amount: '0.00',
+ refund_count: 0,
+ refund_amount: '0.00',
+ dispatch_count: 0,
+ dispatch_amount: '0.00',
+ },
+ penaltyStats: {
+ fakuan_pending: 0,
+ fakuan_pending_amount: '0.00',
+ jifen_pending: 0,
+ },
statusBar: 20,
navBar: 44,
},
- onLoad(options) {
+ async onLoad(options) {
const sys = wx.getSystemInfoSync();
this.setData({
statusBar: sys.statusBarHeight || 20,
@@ -65,7 +99,12 @@ Page(createPage({
});
const parsed = parseSceneOptions(options);
this.setupImageUrls();
+ this.setData({ defaultAvatarUrl: getDefaultAvatarUrl(app) });
+ if (wx.getStorageSync('token')) {
+ await restoreStaffContextAfterAuth();
+ }
this.checkRoleStatus();
+ syncStaffUi(this);
const inviteCode = parsed.inviteCode;
if (inviteCode) {
@@ -95,69 +134,185 @@ Page(createPage({
}
this.checkColdStartPopup('shangjiaduan');
+ this.loadMerchantDataIfNeeded(true);
},
- onShow() {
+ async onShow() {
this.registerNotificationComponent();
- if (this.data.isShangjia) {
- ensureRoleOnCenterPage(this, 'shangjia');
- this.refreshShangjiaInfo();
- this.loadPendingCount();
- this.loadPunishPending();
+ this.syncRoleStatusFromStorage();
+ syncStaffUi(this);
+ if (app.globalData.ossImageUrl) {
+ this.setupImageUrls();
+ }
+ this.loadMerchantDataIfNeeded();
+ },
+
+ syncRoleStatusFromStorage() {
+ try {
+ const uid = wx.getStorageSync('uid');
+ const portal = isMerchantPortalUser();
+ const staffFlag = Number(wx.getStorageSync('staffstatus')) === 1;
+ if (portal || staffFlag) {
+ this.setData({ isShangjia: portal || staffFlag, uid: uid || '', staffBooting: false, isLoading: false });
+ } else {
+ this.setData({ isShangjia: false, staffBooting: false, isLoading: false });
+ }
+ } catch (error) {
+ this.setData({ isShangjia: false, staffBooting: false, isLoading: false });
}
},
- // 图片路径初始化
+ async loadMerchantDataIfNeeded(force = false) {
+ if (!this.data.isShangjia && !isMerchantPortalUser()) return;
+ if (!force && this._merchantDataLoaded) return;
+ try {
+ const token = wx.getStorageSync('token');
+ if (token && Number(wx.getStorageSync('shangjiastatus')) !== 1 && !isStaffMode()) {
+ await restoreStaffContextAfterAuth();
+ } else if (isStaffMode()) {
+ await refreshStaffContext(request);
+ }
+ this.syncRoleStatusFromStorage();
+ syncStaffUi(this);
+ if (this.data.isShangjia || isMerchantPortalUser()) {
+ ensureRoleOnCenterPage(this, 'shangjia');
+ if (isStaffMode()) {
+ await this.loadStaffProfile();
+ } else {
+ await this.getShangjiaInfo();
+ }
+ this.loadPendingCount();
+ if (!isStaffMode()) {
+ this.loadPunishPending();
+ }
+ this.loadIdentityTags();
+ this._merchantDataLoaded = true;
+ }
+ } catch (err) {
+ console.error('商家个人中心加载', err);
+ this.setData({ isLoading: false, staffBooting: false });
+ }
+ },
+
+ // 图片路径:样式不变,仅图标地址走存储桶 + 后台可配置
setupImageUrls() {
const ossBase = app.globalData.ossImageUrl || '';
const imgDir = `${ossBase}beijing/shangjiaduan/`;
+ const icon = (key, ossName) => resolveMiniappIcon(app, key, imgDir + ossName);
this.setData({
imgUrls: this.initImageUrls({
- pageBg: `${imgDir}page_bg.png`,
- avatarCardBg: `${imgDir}avatar_card_bg.png`,
- assetCardBg: `${imgDir}asset_card_bg.png`,
- statCardBg: `${imgDir}stat_card_bg.png`,
- funcItemBg: `${imgDir}func_item_bg.png`,
- primaryFuncBg: `${imgDir}primary_func_bg.png`,
- highlightFuncBg: `${imgDir}highlight_func_bg.png`,
- iconRelease: `${imgDir}icon_release.png`,
- iconFast: `${imgDir}icon_fast.png`,
- iconOrders: `${imgDir}icon_orders.png`,
- iconService: `${imgDir}icon_service.png`,
- iconPunish: `${imgDir}icon_punish.png`,
- iconRank: `${imgDir}icon_rank.png`,
- iconRecharge: `${imgDir}icon_recharge.png`,
- iconWithdraw: `${imgDir}icon_withdraw.png`,
- iconRefresh: `${imgDir}icon_refresh.png`,
- iconCopy: `${imgDir}icon_copy.png`,
- avatarFrame: `${imgDir}avatar_frame.png`,
- iconClear: `${ossBase}beijing/tubiao/grzx_qingchu.jpg`,
+ pageBg: imgDir + 'page_bg.png',
+ avatarCardBg: imgDir + 'avatar_card_bg.png',
+ assetCardBg: imgDir + 'asset_card_bg.png',
+ statCardBg: imgDir + 'stat_card_bg.png',
+ funcItemBg: imgDir + 'func_item_bg.png',
+ primaryFuncBg: imgDir + 'primary_func_bg.png',
+ highlightFuncBg: imgDir + 'highlight_func_bg.png',
+ iconRelease: icon(ICON_KEYS.MERCHANT_CUSTOM, 'icon_release.png'),
+ iconFast: icon(ICON_KEYS.MERCHANT_REGULAR, 'icon_fast.png'),
+ iconOrders: icon(ICON_KEYS.MERCHANT_LINK, 'icon_orders.png'),
+ iconService: icon(ICON_KEYS.MERCHANT_KEFU_KEY, 'icon_service.png'),
+ iconKefuList: icon(ICON_KEYS.MERCHANT_KEFU_LIST, 'icon_kefu_list.png'),
+ iconPunish: icon(ICON_KEYS.MERCHANT_PUNISH, 'icon_punish.png'),
+ iconRank: icon(ICON_KEYS.MERCHANT_RANK, 'icon_rank.png'),
+ iconWithdraw: imgDir + 'icon_withdraw.png',
+ iconRefresh: icon(ICON_KEYS.MERCHANT_REFRESH, 'icon_refresh.png'),
+ iconCopy: imgDir + 'icon_copy.png',
+ avatarFrame: imgDir + 'avatar_frame.png',
+ iconClear: ossBase ? `${ossBase}beijing/tubiao/grzx_qingchu.jpg` : '',
iconSwitch: '/images/_exit.png',
- })
+ }),
});
},
- // 商家状态检查(覆盖基类 checkRoleStatus,增加 getShangjiaInfo 调用)
+ // 商家状态检查(首次进入拉数据;onShow 不重复请求)
checkRoleStatus() {
try {
- const shangjiastatus = wx.getStorageSync('shangjiastatus');
const uid = wx.getStorageSync('uid');
- if (shangjiastatus) {
- this.setData({ isShangjia: true, uid: uid || '' });
- this.loadAvatar();
- this.getShangjiaInfo();
+ const portal = isMerchantPortalUser();
+ const staffFlag = Number(wx.getStorageSync('staffstatus')) === 1;
+
+ if (portal) {
+ this.setData({ isShangjia: true, uid: uid || '', staffBooting: false, isLoading: false });
+ syncStaffUi(this);
ensureRoleOnCenterPage(this, 'shangjia');
- } else {
- this.setData({ isShangjia: false });
+ return;
}
+
+ if (staffFlag) {
+ this.bootStaffPortal(uid);
+ return;
+ }
+
+ this.setData({ isShangjia: false, staffBooting: false, isLoading: false });
+ syncStaffUi(this);
} catch (error) {
console.error('读取商家状态失败', error);
- this.setData({ isShangjia: false });
+ this.setData({ isShangjia: false, staffBooting: false, isLoading: false });
+ syncStaffUi(this);
}
},
- // 获取商家信息
+ /** 已绑定客服、尚未拉到 context 时恢复身份(不展示商家邀请码) */
+ async bootStaffPortal(uid) {
+ this.setData({ staffBooting: true, isLoading: true, uid: uid || '' });
+ syncStaffUi(this);
+ await restoreStaffContextAfterAuth();
+ if (isMerchantPortalUser()) {
+ this.setData({ isShangjia: true, staffBooting: false, isLoading: false });
+ syncStaffUi(this);
+ if (isStaffMode()) {
+ await this.loadStaffProfile();
+ }
+ ensureRoleOnCenterPage(this, 'shangjia');
+ return;
+ }
+ this.setData({ staffBooting: false, isLoading: false, isShangjia: false });
+ syncStaffUi(this);
+ wx.showToast({ title: '客服身份已失效,请联系商家老板', icon: 'none' });
+ },
+
+ onInviteCodeInput(e) {
+ this.setData({ inviteCode: (e.detail.value || '').trim() });
+ },
+
+ goToStaffJoin() {
+ wx.navigateTo({ url: '/pages/staff-join/staff-join' });
+ },
+
+ clearCache() {
+ wx.showModal({
+ title: '清除缓存',
+ content: '将清除所有登录与身份数据,并回到点单端,确定继续?',
+ confirmText: '确定',
+ cancelText: '取消',
+ success: (r) => {
+ if (!r.confirm) return;
+ clearStaffSession();
+ clearCacheAndEnterNormal(this);
+ },
+ });
+ },
+
+ async loadStaffProfile() {
+ const ctx = await refreshStaffContext(request);
+ const profile = wx.getStorageSync('nicheng') || (ctx && ctx.display_name) || '商家客服';
+ this.loadAvatar();
+ this.setData({
+ nicheng: (ctx && ctx.display_name) || profile,
+ sjyue: (ctx && ctx.wallet && ctx.wallet.quota_available) || '0.00',
+ chenghaoList: [],
+ isLoading: false,
+ });
+ syncStaffUi(this);
+ applyStaffStatsToPage(this, ctx);
+ },
+
+ // 获取商家信息(仅商家老板;子客服禁止调用)
async getShangjiaInfo() {
+ if (isStaffMode() || Number(wx.getStorageSync('staffstatus')) === 1) {
+ return this.loadStaffProfile();
+ }
await this.loadData({
url: '/yonghu/shangjiaxinxi',
method: 'POST',
@@ -173,8 +328,8 @@ Page(createPage({
this.setData({
nicheng: data.nicheng || '',
sjyue: data.sjyue || '0.00',
- fabu: data.fadanzong || 0,
- tuikuan: data.tuikuanzong || 0,
+ fabu: data.fabu || data.fadanzong || 0,
+ tuikuan: data.tuikuan || data.tuikuanzong || 0,
jinriliushui: data.riliushui || '0.00',
jinyueliushui: data.yueliushui || '0.00',
jinridingdan: data.jinripaidan || 0,
@@ -182,6 +337,7 @@ Page(createPage({
chenghaoList: chenghaoList,
isLoading: false,
});
+ this.loadAvatar();
if (this.data.isAutoRegistering) {
this.setData({ isAutoRegistering: false });
@@ -192,37 +348,60 @@ Page(createPage({
},
refreshShangjiaInfo() {
- this.throttledRefresh(() => this.getShangjiaInfo());
+ if (isStaffMode()) {
+ this.throttledRefresh(() => this.loadStaffProfile());
+ return;
+ }
+ this.throttledRefresh(() => {
+ this.getShangjiaInfo();
+ this.loadPendingCount();
+ this.loadPunishPending();
+ this.loadIdentityTags();
+ });
},
- async loadPendingCount() {
+ async onPullDownRefresh() {
try {
- const res = await request({
- url: '/dingdan/sjdingdanhq',
- method: 'POST',
- data: { zhuangtai_list: [8], page: 1, page_size: 1 },
- });
- if (res && res.data && (res.data.code === 0 || res.data.code === 200)) {
- this.setData({ pendingCount: res.data.data.pending_count || 0 });
+ if (isStaffMode()) {
+ await this.loadStaffProfile();
+ } else {
+ await Promise.all([
+ this.getShangjiaInfo(),
+ this.loadDashboardStats(),
+ this.loadIdentityTags(),
+ ]);
}
- } catch (e) {
- console.error('待结算数量失败', e);
+ } finally {
+ wx.stopPullDownRefresh();
}
},
- async loadPunishPending() {
+ async loadDashboardStats() {
try {
- const res = await request({
- url: '/yonghu/sjcfjlhq',
- method: 'POST',
- data: { page: 1, page_size: 1, zhuangtai: 0 },
- });
+ const data = await fetchMerchantOrderStats(request, {});
+ applyOrderStatsToPage(this, data);
+ } catch (e) {
+ console.warn('经营统计失败', e);
+ }
+ },
+
+ async loadPendingCount() {
+ return this.loadDashboardStats();
+ },
+
+ async loadPunishPending() {
+ return this.loadDashboardStats();
+ },
+
+ async loadIdentityTags() {
+ try {
+ const res = await request({ url: '/jituan/identity-tag/my-tags', method: 'POST' });
if (res && res.data && (res.data.code === 0 || res.data.code === 200)) {
const d = res.data.data || {};
- this.setData({ punishPending: d.daichuli_count || d.pending_count || 0 });
+ this.setData({ identityTagList: d.shangjia || [] });
}
} catch (e) {
- /* 接口字段未定时静默 */
+ /* 静默 */
}
},
@@ -262,9 +441,44 @@ Page(createPage({
}
},
+ editNicheng() {
+ if (!guardMerchantOwnerAction('子客服无法修改商家昵称')) return;
+ wx.showModal({
+ title: '修改昵称',
+ editable: true,
+ placeholderText: '请输入商家昵称',
+ content: this.data.nicheng || '',
+ success: async (res) => {
+ if (!res.confirm) return;
+ const nicheng = (res.content || '').trim();
+ if (!nicheng) {
+ wx.showToast({ title: '昵称不能为空', icon: 'none' });
+ return;
+ }
+ try {
+ const r = await request({
+ url: '/yonghu/shangjiagxnc',
+ method: 'POST',
+ data: { nicheng },
+ });
+ if (r.data && r.data.code === 200) {
+ wx.setStorageSync('nicheng', nicheng);
+ this.setData({ nicheng });
+ wx.showToast({ title: '昵称已更新', icon: 'success' });
+ } else {
+ wx.showToast({ title: (r.data && r.data.msg) || '更新失败', icon: 'none' });
+ }
+ } catch (e) {
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+ });
+ },
+
// 页面跳转
+ goToRegularPaiDan() { wx.navigateTo({ url: '/pages/merchant-regular-dispatch/merchant-regular-dispatch' }); },
goToPaiDan() { wx.navigateTo({ url: '/pages/merchant-dispatch/merchant-dispatch' }); },
- goToJiSuPaiDan() {
+ goToLinkPaiDan() {
wx.vibrateShort({ type: 'medium' });
wx.navigateTo({ url: '/pages/express-order/express-order' });
},
@@ -273,10 +487,18 @@ Page(createPage({
goToHome() { wx.redirectTo({ url: '/pages/merchant-home/merchant-home' }); },
goToKefuKey() { wx.navigateTo({ url: '/pages/merchant-kefu-key/merchant-kefu-key' }); },
goToKefuList() { wx.navigateTo({ url: '/pages/merchant-kefu-list/merchant-kefu-list' }); },
- goToRecharge() { wx.navigateTo({ url: '/pages/merchant-recharge/merchant-recharge' }); },
- goToWithdraw() { wx.navigateTo({ url: '/pages/withdraw/withdraw' }); },
+ goToAuditLog() { wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit' }); },
+ goToStaffRank() { wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit?tab=rank' }); },
+ goToRecharge() {
+ if (!guardMerchantOwnerAction('子客服无法充值,请联系商家老板')) return;
+ wx.navigateTo({ url: '/pages/merchant-recharge/merchant-recharge' });
+ },
+ goToWithdraw() {
+ if (!guardMerchantOwnerAction('子客服无法提现,请联系商家老板')) return;
+ wx.navigateTo({ url: '/pages/withdraw/withdraw' });
+ },
goToRanking() { wx.navigateTo({ url: '/pages/fighter-rank/fighter-rank?type=shangjia' }); },
- goToMessages() { wx.navigateTo({ url: '/pages/merchant-msg/merchant-msg' }); },
+ goToMessages() { wx.navigateTo({ url: '/pages/merchant-penalty/merchant-penalty' }); },
}, {
roleConfig: {
role: 'shangjia',
diff --git a/pages/merchant/merchant.json b/pages/merchant/merchant.json
index efe08a9..b207753 100644
--- a/pages/merchant/merchant.json
+++ b/pages/merchant/merchant.json
@@ -8,5 +8,5 @@
"navigationStyle": "custom",
"backgroundColor": "#fff8e1",
"backgroundTextStyle": "dark",
- "enablePullDownRefresh": false
+ "enablePullDownRefresh": true
}
\ No newline at end of file
diff --git a/pages/merchant/merchant.wxml b/pages/merchant/merchant.wxml
index 308544e..a62bc70 100644
--- a/pages/merchant/merchant.wxml
+++ b/pages/merchant/merchant.wxml
@@ -1,5 +1,21 @@
-
+
+
+
+
+
+ 客服身份加载中
+ 请稍候,正在同步您的派单员权限…
+
+
+
+
+
+
+