本地备份:商家打手端UI恢复稳定版,后续可回退

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-27 07:38:01 +08:00
parent fc0ee9a4d1
commit eaf05663ee
24 changed files with 2759 additions and 2098 deletions

View File

@@ -2,9 +2,25 @@
import { createPage, request, isRoleStatusActive, isCenterPageActive, syncRoleStatuses, syncProfileFields, syncGroupFields, ensureRoleOnCenterPage, clearCacheAndEnterNormal, lockPrimaryRole, migrateLegacyCenterRole, enterLockedRole, parseSceneOptions } from '../../utils/base-page.js'
import { resolveAvatarUrl } from '../../utils/avatar.js'
import { openPrivateChat, buildInviterPeerId } from '../../utils/im-user.js'
import { isStaffMode, getStaffContext } from '../../utils/staff-api.js'
import { ensurePhoneAuth } from '../../utils/phone-auth.js'
import {
ICON_KEYS,
resolveMiniappIcon,
resolveConfiguredIcon,
refreshPindaoConfig,
getPindaoConfig,
resolvePindaoImages,
warmupPindaoConfig,
PINDAO_ICON_FALLBACK,
} from '../../utils/miniapp-icons.js'
const PLATFORM_INVITE_CODE = '0000008RffVgKHMj7kQC'
/** 会员/保证金横幅 COS 兜底(后台未上传时仍显示) */
const FIGHTER_BANNER_VIP_FALLBACK = 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/20260512123427531240452.png'
const FIGHTER_BANNER_DEPOSIT_FALLBACK = 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/202605121234283091d3980.png'
Page(createPage({
data: {
// 图片路径对象
@@ -41,6 +57,7 @@ Page(createPage({
zuzhangInviterCache: null,
chenghaoList: [],
guanshiChenghaoList: [],
identityTagList: [],
gszhstatus: '',
yaoqingzongshu: 0,
fenyongzonge: '0.00',
@@ -65,13 +82,25 @@ Page(createPage({
statusBar: 20,
navBar: 44,
pindaoVisible: false,
pindaoTitle: '频道',
pindaoChannelNo: '',
examEnabled: false,
examPassed: false,
pindaoImages: [],
scrollViewRefreshing: false,
showRechargeBanners: false,
showPindaoEntry: true,
},
_buildImgUrls(ossImageUrl) {
const app = getApp();
const dsBase = ossImageUrl + 'beijing/dashouduan/';
const iconBase = ossImageUrl + 'beijing/dashouduan/dashoutubiaobeijing/';
const gsBase = ossImageUrl + 'beijing/guanshiduan/';
const khBase = ossImageUrl + 'beijing/kaohe/';
const icon = (key, fallback) => resolveMiniappIcon(app, key, fallback);
return {
pageBg: dsBase + 'page-bg.jpg',
userCardBg: dsBase + 'user-card-bg.png',
@@ -83,7 +112,7 @@ Page(createPage({
listBg: dsBase + 'list-card-bg.png',
topBg: iconBase + 'top-bg.jpg',
cardBg: iconBase + 'card-bg.jpg',
iconRefresh: gsBase + 'icon-refresh.png',
iconRefresh: icon(ICON_KEYS.ICON_REFRESH, gsBase + 'icon-refresh.png'),
iconCopy: gsBase + 'icon-copy.png',
iconVip: dsBase + 'icon-vip.png',
iconArrowLight: dsBase + 'icon-arrow-light.png',
@@ -118,6 +147,7 @@ Page(createPage({
iconSwitch: '/images/_exit.png',
iconKefu: ossImageUrl + 'beijing/tubiao/grzx_kefu.jpg',
iconKuaishou: ossImageUrl + 'beijing/tubiao/grzx_guanzhualong.jpg',
iconPindao: icon(ICON_KEYS.MINE_PINDAO, ossImageUrl + PINDAO_ICON_FALLBACK),
iconKaoheDafen: khBase + 'daofen.png',
iconKaoheJilu: khBase + 'jilu.png',
iconKaoheZhongxin: khBase + 'zhongxin.png',
@@ -128,8 +158,8 @@ Page(createPage({
kefuBannerBg: dsBase + 'kefu-banner-bg.png',
totalAssetBg: dsBase + 'total-asset-bg.png',
authPanelBg: dsBase + 'auth-panel-bg.png',
bannerVip: 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/20260512123427531240452.png',
bannerDeposit: 'https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/uploads/images/202605121234283091d3980.png',
bannerVip: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER) || FIGHTER_BANNER_VIP_FALLBACK,
bannerDeposit: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT) || FIGHTER_BANNER_DEPOSIT_FALLBACK,
};
},
@@ -177,9 +207,28 @@ Page(createPage({
}
}
this.checkColdStartPopup('dashouduan');
this.syncConfiguredAssets();
},
onShow() {
syncConfiguredAssets() {
const app = getApp();
const bannerVip = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_MEMBER) || FIGHTER_BANNER_VIP_FALLBACK;
const bannerDeposit = resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_DEPOSIT) || FIGHTER_BANNER_DEPOSIT_FALLBACK;
const imgUrls = { ...this.data.imgUrls, bannerVip, bannerDeposit };
this.setData({
imgUrls,
showRechargeBanners: !!(bannerVip || bannerDeposit),
showPindaoEntry: this.data.isDashou || this.data.isGuanshi || this.data.isZuzhang || this.data.isKaoheguan,
});
},
async onShow() {
if (!app.globalData._dashouPhoneChecked) {
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
if (!phoneOk) return;
app.globalData._dashouPhoneChecked = true;
}
migrateLegacyCenterRole(getApp());
lockPrimaryRole('dashou', getApp());
wx.setStorageSync('isJinpai', 0);
@@ -190,16 +239,17 @@ Page(createPage({
this.setData({ inviterCache, zuzhangInviterCache });
this.registerNotificationComponent();
warmupPindaoConfig(app);
this.checkRoleStatuses();
this.syncConfiguredAssets();
if (isCenterPageActive(this, 'isDashou', 'dashoustatus')) {
if (!this.data.isDashou) this.setData({ isDashou: true });
ensureRoleOnCenterPage(this, 'dashou');
setTimeout(() => this.refreshAllInfo(false), 300);
this.loadExamStatus();
} else if (isRoleStatusActive(wx.getStorageSync('guanshistatus')) ||
isRoleStatusActive(wx.getStorageSync('zuzhangstatus')) ||
isRoleStatusActive(wx.getStorageSync('kaoheguanstatus'))) {
ensureRoleOnCenterPage(this, 'dashou');
setTimeout(() => this.refreshAllInfo(false), 300);
}
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
@@ -277,12 +327,17 @@ Page(createPage({
tag: d.shangjiaCertified ? '进入商家端' : '去认证',
done: d.shangjiaCertified,
});
list.push({
type: 'staff',
name: '商家客服',
icon: img.iconKefu || img.iconShangjia,
tag: isStaffMode() ? '进入工作台' : '去入驻',
done: isStaffMode(),
});
if (!d.isGuanshi) {
list.push({ type: 'guanshi', name: '管事', icon: img.iconGuanshiAuth, tag: '去认证' });
}
if (!d.isZuzhang) {
list.push({ type: 'zuzhang', name: '组长', icon: img.iconZuzhangAuth, tag: '去认证' });
}
// 组长由后台添加,前端不再展示「组长认证」入口
if (!d.isDashou) {
list.push({ type: 'dashou', name: '接单员', icon: img.iconDashouAuth, tag: '去认证' });
}
@@ -293,35 +348,37 @@ Page(createPage({
},
async refreshAllInfo(showToast = true) {
this.throttledRefresh(async () => {
this.setData({ isLoading: true });
try {
this.checkRoleStatuses();
const results = await Promise.allSettled([
this._fetchDashouInfoSilent(),
this.fetchChenghaoList(),
this._fetchGuanshiInfoSilent(),
this.fetchGuanshiChenghaoList(),
this._fetchZuzhangInfoSilent(),
this._fetchKaoheguanInfoSilent(),
]);
this.checkRoleStatuses();
const dashouOk = results[0].status === 'fulfilled';
if (showToast) {
wx.showToast({
title: dashouOk ? '刷新成功' : '刷新失败',
icon: dashouOk ? 'success' : 'none',
duration: 1500,
});
}
} catch (e) {
if (showToast) {
wx.showToast({ title: '刷新失败', icon: 'none' });
}
} finally {
this.setData({ isLoading: false });
if (this._profileRefreshing) return;
this._profileRefreshing = true;
this.setData({ isLoading: true });
try {
this.checkRoleStatuses();
const results = await Promise.allSettled([
this._fetchDashouInfoSilent(),
this.fetchChenghaoList(),
this._fetchGuanshiInfoSilent(),
this.fetchGuanshiChenghaoList(),
this._fetchZuzhangInfoSilent(),
this._fetchKaoheguanInfoSilent(),
this.loadIdentityTags(),
]);
this.checkRoleStatuses();
const dashouOk = results[0].status === 'fulfilled';
if (showToast) {
wx.showToast({
title: dashouOk ? '刷新成功' : '刷新失败',
icon: dashouOk ? 'success' : 'none',
duration: 1500,
});
}
}, 3000);
} catch (e) {
if (showToast) {
wx.showToast({ title: '刷新失败', icon: 'none' });
}
} finally {
this._profileRefreshing = false;
this.setData({ isLoading: false });
}
},
refreshDashouInfo() {
@@ -332,6 +389,34 @@ Page(createPage({
this.refreshAllInfo(true);
},
onPullDownRefresh() {
this.setData({ scrollViewRefreshing: true });
Promise.all([
this.refreshAllInfo(false),
this.loadExamStatus(),
]).finally(() => {
this.setData({ scrollViewRefreshing: false });
wx.stopPullDownRefresh();
});
},
async loadIdentityTags() {
try {
const res = await request({ url: '/jituan/identity-tag/my-tags', method: 'POST' });
if (res && res.data && (res.data.code === 0 || res.data.code === 200)) {
const d = res.data.data || {};
const merged = [
...(d.dashou || []),
...(d.zuzhang || []),
...(d.guanshi || []),
];
this.setData({ identityTagList: merged });
}
} catch (e) {
/* 静默 */
}
},
async _fetchDashouInfoSilent() {
const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' });
if (res && res.data.code == 200) {
@@ -1015,6 +1100,14 @@ Page(createPage({
onTapAuthItem(e) {
const type = e.currentTarget.dataset.type;
if (type === 'staff') {
if (isStaffMode()) {
enterLockedRole('shangjia', getApp());
} else {
wx.navigateTo({ url: '/pages/staff-join/staff-join' });
}
return;
}
if (type === 'shangjia') {
this.onTapShangjiaAuth();
return;
@@ -1038,6 +1131,21 @@ Page(createPage({
wx.navigateTo({ url: '/pages/verify/verify?type=shangjia' });
},
goToReceiveOrder() { wx.navigateTo({ url: '/pages/accept-order/accept-order' }) },
goToDashouExam() { wx.navigateTo({ url: '/pages/dashou-exam/dashou-exam' }) },
async loadExamStatus() {
try {
const res = await request({ url: '/jituan/dashou-exam/status', method: 'POST' });
const body = res?.data;
if (body && (body.code === 200 || body.code === 0) && body.data) {
const d = body.data;
this.setData({
examEnabled: !!d.exam_enabled,
examPassed: !!d.exam_passed,
});
}
} catch (e) { /* 静默 */ }
},
goToMyOrders() { wx.navigateTo({ url: '/pages/fighter-orders/fighter-orders' }) },
goToMyPunishment() { wx.navigateTo({ url: '/pages/penalty/penalty/penalty' }) },
goToRecharge() { wx.navigateTo({ url: '/pages/fighter-recharge/fighter-recharge' }) },
@@ -1045,7 +1153,33 @@ Page(createPage({
const type = e?.currentTarget?.dataset?.type || 'dashou';
wx.navigateTo({ url: `/pages/fighter-rank/fighter-rank?type=${type}` });
},
goToGuanzhuKs() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) },
goToGuanzhuKs() {
wx.navigateTo({ url: '/pages/manager-assign/manager-assign' });
},
openPindaoModal() {
const app = getApp();
const cfg = getPindaoConfig(app);
const images = resolvePindaoImages(app);
this.setData({
pindaoVisible: true,
pindaoTitle: cfg.title || '频道',
pindaoChannelNo: cfg.channel_no || '',
pindaoImages: images,
});
refreshPindaoConfig(app).then(({ cfg: latest, images: latestImages }) => {
if (!this.data.pindaoVisible) return;
this.setData({
pindaoTitle: latest.title || '频道',
pindaoChannelNo: latest.channel_no || '',
pindaoImages: latestImages,
});
}).catch(() => {});
},
closePindaoModal() {
this.setData({ pindaoVisible: false });
},
goToKaoheDafen() { wx.navigateTo({ url: '/pages/assess-score/assess-score' }) },
goToKaoheJilu() { wx.navigateTo({ url: '/pages/assess-log/assess-log' }) },
goToKaoheZhongxin() { wx.navigateTo({ url: '/pages/assess-center/assess-center' }) },

View File

@@ -2,7 +2,8 @@
"usingComponents": {
"global-notification": "/components/global-notification/global-notification",
"chenghao-tag": "/components/chenghao-tag/chenghao-tag",
"tab-bar": "/tab-bar/index"
"tab-bar": "/tab-bar/index",
"pindao-modal": "/components/pindao-modal/pindao-modal"
},
"navigationStyle": "custom",
"backgroundColor": "#fff8e1",

View File

@@ -26,14 +26,23 @@
<view class="user-page">
<view class="page-header">
<view class="status-bar" style="height:{{statusBar}}px"></view>
<view class="nav-bar" style="height:{{navBar - statusBar}}px"><text class="nav-title">我的</text></view>
<view class="nav-bar" style="height:{{navBar - statusBar}}px">
<text class="nav-title">我的</text>
</view>
</view>
<view class="refresh-float" bindtap="onTapRefresh">
<image class="refresh-float-ico" src="{{imgUrls.iconRefresh}}" mode="aspectFit"/>
</view>
<scroll-view class="content" scroll-y enhanced show-scrollbar="{{false}}">
<scroll-view
class="content"
scroll-y
enhanced
show-scrollbar="{{false}}"
refresher-enabled="{{true}}"
refresher-threshold="80"
refresher-default-style="black"
refresher-background="#fff8e1"
refresher-triggered="{{scrollViewRefreshing}}"
bindrefresherrefresh="onPullDownRefresh"
>
<!-- 用户信息 -->
<view class="user-info flexb">
<view class="flex">
@@ -55,11 +64,14 @@
</view>
</view>
</view>
<image class="setting-ico" src="{{imgUrls.iconEdit}}" mode="aspectFit" bindtap="goToModifyInfo"/>
<view class="user-header-actions">
<image class="header-action-ico" src="{{imgUrls.iconRefresh}}" mode="aspectFit" bindtap="onTapRefresh"/>
<image class="setting-ico" src="{{imgUrls.iconEdit}}" mode="aspectFit" bindtap="goToModifyInfo"/>
</view>
</view>
<!-- 称号 -->
<view class="badge-zone" wx:if="{{chenghaoList.length > 0 || (isGuanshi && guanshiChenghaoList.length > 0)}}">
<view class="badge-zone" wx:if="{{chenghaoList.length > 0 || (isGuanshi && guanshiChenghaoList.length > 0) || identityTagList.length > 0}}">
<scroll-view scroll-x class="badge-scroll" wx:if="{{chenghaoList.length > 0}}">
<view class="badge-tag-wrap" wx:for="{{chenghaoList}}" wx:key="index">
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
@@ -70,6 +82,11 @@
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
</view>
</scroll-view>
<scroll-view scroll-x class="badge-scroll identity-tag-scroll" wx:if="{{identityTagList.length > 0}}">
<view class="badge-tag-wrap" wx:for="{{identityTagList}}" wx:key="id">
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
</view>
</scroll-view>
</view>
<!-- 佣金/资产卡(逍遥梦 wallet-card -->
@@ -85,10 +102,14 @@
</view>
</view>
<!-- 会员充值 + 保证金(均跳转同一充值页 -->
<view class="banner-row flex">
<image class="banner-img" src="{{imgUrls.bannerVip}}" mode="widthFix" bindtap="goToRecharge"/>
<image class="banner-img" src="{{imgUrls.bannerDeposit}}" mode="widthFix" bindtap="goToRecharge"/>
<!-- 会员充值 + 保证金(无后台图时显示文字按钮 -->
<view class="banner-row flex" wx:if="{{showRechargeBanners}}">
<image wx:if="{{imgUrls.bannerVip}}" class="banner-img" src="{{imgUrls.bannerVip}}" mode="widthFix" bindtap="goToRecharge"/>
<image wx:if="{{imgUrls.bannerDeposit}}" class="banner-img" src="{{imgUrls.bannerDeposit}}" mode="widthFix" bindtap="goToRecharge"/>
</view>
<view class="recharge-text-row flex" wx:else>
<view class="recharge-text-btn" catchtap="goToRecharge">充值会员</view>
<view class="recharge-text-btn" catchtap="goToRecharge">充值保证金</view>
</view>
<!-- 资产统计(逍遥梦 freeze-row -->
@@ -123,7 +144,7 @@
<!-- 接单服务(对应逍遥梦「我的订单」四宫格) -->
<view class="panel shadow">
<view class="panel-title flexb"><text class="lg">接单服务</text></view>
<view class="order-nav flexa">
<view class="order-nav">
<view class="nav-item flexmc" bindtap="goToReceiveOrder">
<image class="nav-icon" src="{{imgUrls.iconGame}}" mode="aspectFit"/><text class="sm">抢单大厅</text>
</view>
@@ -136,6 +157,11 @@
<view class="nav-item flexmc" bindtap="goToKaohe">
<image class="nav-icon" src="{{imgUrls.iconMedal}}" mode="aspectFit"/><text class="sm">考核金牌</text>
</view>
<view class="nav-item flexmc" bindtap="goToDashouExam">
<image class="nav-icon" src="{{imgUrls.iconBook}}" mode="aspectFit"/>
<text class="sm">接单考试</text>
<text wx:if="{{examEnabled}}" class="exam-tag {{examPassed ? 'exam-tag-pass' : 'exam-tag-pending'}}">{{examPassed ? '已通过' : '待考试'}}</text>
</view>
</view>
</view>
@@ -195,7 +221,6 @@
<view class="func-item flexmc" bindtap="goToKaoheDafen"><image class="func-icon" src="{{imgUrls.iconKaoheDafen}}" mode="aspectFit"/><text class="func-txt">考核打分</text></view>
<view class="func-item flexmc" bindtap="goToKaoheJilu"><image class="func-icon" src="{{imgUrls.iconKaoheJilu}}" mode="aspectFit"/><text class="func-txt">考核记录</text></view>
<view class="func-item flexmc" bindtap="goToKaoheZhongxin"><image class="func-icon" src="{{imgUrls.iconKaoheZhongxin}}" mode="aspectFit"/><text class="func-txt">考核中心</text></view>
<view class="func-item flexmc" bindtap="goToKaoheWithdraw"><image class="func-icon" src="{{imgUrls.iconWithdraw}}" mode="aspectFit"/><text class="func-txt">考核提现</text></view>
</view>
</view>
@@ -217,6 +242,7 @@
<view class="func-grid">
<view class="func-item flexmc" bindtap="goToKefu"><image class="func-icon" src="{{imgUrls.iconKefu}}" mode="aspectFit"/><text class="func-txt">在线客服</text></view>
<view class="func-item flexmc" bindtap="goToGuanzhuKs"><image class="func-icon" src="{{imgUrls.iconKuaishou}}" mode="aspectFit"/><text class="func-txt">关注快手</text></view>
<view class="func-item flexmc" wx:if="{{showPindaoEntry}}" bindtap="openPindaoModal"><image class="func-icon" src="{{imgUrls.iconPindao}}" mode="aspectFit"/><text class="func-txt">频道</text></view>
<view class="func-item flexmc" bindtap="contactInviter"><image class="func-icon" src="{{imgUrls.iconInvite}}" mode="aspectFit"/><text class="func-txt">联系邀请人</text></view>
<view class="func-item flexmc" bindtap="goToRules"><image class="func-icon" src="{{imgUrls.iconBook}}" mode="aspectFit"/><text class="func-txt">用户规则</text></view>
<view class="func-item flexmc" bindtap="switchToNormal"><image class="func-icon" src="{{imgUrls.iconSwitch}}" mode="aspectFit"/><text class="func-txt">返回点单端</text></view>
@@ -236,3 +262,10 @@
<global-notification id="global-notification"/>
<popup-notice id="popupNotice"/>
<pindao-modal
visible="{{pindaoVisible}}"
title="{{pindaoTitle}}"
channelNo="{{pindaoChannelNo}}"
images="{{pindaoImages}}"
bind:close="closePindaoModal"
/>

View File

@@ -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 {