diff --git a/app.js b/app.js
index f9d7d0a..be37b63 100644
--- a/app.js
+++ b/app.js
@@ -3,6 +3,11 @@ 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 { getDefaultAvatarUrl, resolveAvatarFromStorage } = require('./utils/avatar.js');
// 三端固定首页
const roleDefaultPage = PRIMARY_DEFAULT_PAGES;
@@ -36,7 +41,8 @@ App({
guanshiqun: '',
guanshiqunid: '',
- appId:'wx0e4be86faac4a8d1',
+ appId: WX_APP_ID,
+ clubId: CLUB_ID,
shangjiastatus: 0,
dashoustatus: 0,
@@ -49,11 +55,7 @@ App({
yajin: null,
chenghao: '',
jinfen: null,
- clumber: [{
- huiyuanid: '',
- huiyuanming: '',
- daoqi: ''
- }],
+ clumber: [],
chengjiaoliang: null,
zaixianZhuangtai: null,
@@ -80,6 +82,8 @@ App({
xshenfen: 1,
goEasyConfig: null,
+ chatEnabled: false,
+ groupInfoMap: {},
kefuConfig: {
link: '',
enterpriseId: ''
@@ -151,6 +155,7 @@ App({
pageState: {
currentPage: '',
isInChatPage: false,
+ isInGroupChat: false,
currentChatId: '',
lastPageUpdate: 0
},
@@ -159,11 +164,23 @@ App({
debugMode: false,
currentUser: null,
currentRole: 'normal',
- primaryRole: 'normal'
- },
+ primaryRole: 'normal',
+ /** 客服浮钮:full | mini,onLaunch 重置为 full */
+ kefuFloatMode: 'full',
+ /** 本次启动内隐藏客服浮钮(不持久化,杀进程后恢复) */
+ kefuFloatSessionHidden: false,
+ kefuFloatY: null,
+ /** 从「我的」跳抢单页时高亮指定单 */
+ _acceptOrderHighlight: '',
+ },
// 核心启动流程
async onLaunch() {
+ this.globalData.kefuFloatMode = 'full';
+ this.globalData.kefuFloatSessionHidden = false;
+ try { wx.removeStorageSync('kefuFloatPermanentHidden'); } catch (e) {}
+ setClubId(getConfiguredClubId(), this);
+ this.globalData.clubId = CLUB_ID;
// ① 隐藏返回首页按钮
wx.hideHomeButton();
wx.onAppRoute((res) => {
@@ -193,6 +210,11 @@ App({
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(() => {
@@ -214,13 +236,11 @@ App({
this.emitEvent('staffContextChanged', {});
}
- // ⑤ 建立连接
- const saved = this.getSavedConnection();
- console.log('【启动】缓存身份:', saved ? saved.identityType : '无',
- 'userId:', saved ? saved.userId : '无');
+ // ⑤ 建立连接(文赫式:全局监听,不反复 disconnect)
setTimeout(() => {
- if (this.startImWhenReady) this.startImWhenReady();
- else if (this.ensureConnection) this.ensureConnection();
+ if (this.globalData.chatEnabled && this.ensureConnection) {
+ this.ensureConnection();
+ }
}, 300);
// ⑥ 获取远程配置
@@ -228,10 +248,16 @@ App({
.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();
+ if (this.globalData.chatEnabled && this.ensureConnection) {
+ this.ensureConnection();
+ }
console.log('远程配置更新完成');
})
.catch(err => {
@@ -239,10 +265,25 @@ App({
});
},
- /** 从后台切回前台时再次向后端校验 */
+ /** 从后台切回前台时再次向后端校验,并维持 IM 连接 */
async onShow() {
if (!wx.getStorageSync('token')) return;
await ensurePhoneAuth({ redirect: true });
+ if (this.globalData.chatEnabled && typeof this.startImWhenReady === 'function') {
+ this.startImWhenReady();
+ } else if (this.globalData.chatEnabled && typeof this.ensureConnection === 'function') {
+ this.globalData.goEasyConnection.autoReconnect = true;
+ if (typeof this.restoreTabBarBadge === 'function') {
+ this.restoreTabBarBadge();
+ }
+ this.ensureConnection();
+ if (typeof this.syncConnectionStatus === 'function') {
+ setTimeout(() => this.syncConnectionStatus(), 800);
+ }
+ if (typeof this.loadConversations === 'function') {
+ setTimeout(() => this.loadConversations(), 300);
+ }
+ }
},
// 连接管理方法
@@ -258,11 +299,16 @@ App({
},
// 配置缓存读写
- CONFIG_CACHE_KEY: 'app_dynamic_config',
+ 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.CONFIG_CACHE_KEY);
+ const data = wx.getStorageSync(this.getConfigCacheKey());
if (data && typeof data === 'object') {
return data;
}
@@ -273,7 +319,7 @@ App({
saveConfigToStorage(config) {
try {
if (config && typeof config === 'object') {
- wx.setStorageSync(this.CONFIG_CACHE_KEY, config);
+ wx.setStorageSync(this.getConfigCacheKey(), config);
}
} catch (e) {}
},
@@ -284,7 +330,7 @@ App({
wx.request({
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
method: 'POST',
- header: { 'content-type': 'application/json' },
+ 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);
@@ -307,7 +353,7 @@ App({
wx.request({
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
method: 'POST',
- header: { 'content-type': 'application/json' },
+ header: buildClubHeaders({ 'content-type': 'application/json' }),
success: (res) => {
if (res.statusCode === 200 && res.data && res.data.code === 0) {
resolve(res.data.data);
@@ -350,6 +396,19 @@ App({
enterpriseId: config.kefu.enterpriseId || ''
};
}
+
+ try {
+ applyMiniappAssetsFromConfig(this, config);
+ } catch (e) {
+ console.warn('miniapp assets apply failed', e);
+ }
+
+ if (this.emitEvent) {
+ this.emitEvent('configApplied', {
+ ossImageUrl: this.globalData.ossImageUrl,
+ morentouxiang: this.globalData.morentouxiang,
+ });
+ }
},
// 仅在有效 appkey 时初始化
@@ -373,9 +432,10 @@ App({
modules: ['im', 'pubsub']
});
wx.GoEasy = GoEasy;
+ this.globalData.chatEnabled = true;
console.log('GoEasy 初始化成功');
- if (this.startImWhenReady && wx.getStorageSync('uid')) {
- setTimeout(() => this.startImWhenReady(), 100);
+ if (this.ensureConnection && wx.getStorageSync('uid')) {
+ setTimeout(() => this.ensureConnection(), 100);
}
} catch (error) {
console.error('GoEasy 初始化失败:', error);
@@ -385,10 +445,12 @@ App({
initCurrentUser() {
const uid = wx.getStorageSync('uid');
if (uid) {
+ const def = getDefaultAvatarUrl(this);
+ const avatar = resolveAvatarFromStorage(this) || def;
this.globalData.currentUser = {
id: uid,
- name: '用户' + uid.substring(0, 6),
- avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang
+ name: wx.getStorageSync('nicheng') || ('用户' + uid.substring(0, 6)),
+ avatar: avatar || def,
};
}
},
diff --git a/app.json b/app.json
index 7dba254..6f42352 100644
--- a/app.json
+++ b/app.json
@@ -2,82 +2,252 @@
"pages": [
"pages/index/index",
"pages/category/category",
- "pages/pick-user/pick-user",
"pages/messages/messages",
"pages/mine/mine",
- "pages/product-detail/product-detail",
- "pages/submit/submit",
- "pages/edit/edit",
- "pages/fighter/fighter",
- "pages/merchant/merchant",
- "pages/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",
- "pages/fighter-rules/fighter-rules",
- "pages/fighter-edit/fighter-edit",
- "pages/fighter-rank/fighter-rank",
- "pages/fighter-recharge/fighter-recharge",
- "pages/fighter-msg/fighter-msg",
- "pages/fighter-orders/fighter-orders",
"pages/accept-order/accept-order",
- "pages/withdraw/withdraw",
- "pages/invite-fighter/invite-fighter",
- "pages/my-fighter/my-fighter",
- "pages/recharge-log/recharge-log",
- "pages/manager-rank/manager-rank",
- "pages/merchant-dispatch/merchant-dispatch",
+ "pages/fighter-orders/fighter-orders",
+ "pages/fighter/fighter",
+ "pages/merchant-home/merchant-home",
"pages/merchant-orders/merchant-orders",
- "pages/merchant-msg/merchant-msg",
- "pages/merchant-rank/merchant-rank",
- "pages/merchant-recharge/merchant-recharge",
- "pages/merchant-order-detail/merchant-order-detail",
- "pages/fighter-order-detail/fighter-order-detail",
- "pages/chat/chat",
- "pages/express-order/express-order",
- "pages/order-pool/order-pool",
- "pages/poster/poster",
- "pages/gold-fighter/gold-fighter",
- "pages/leader/leader",
- "pages/manager-assign/manager-assign",
- "pages/leader-bonus-log/leader-bonus-log",
- "pages/invite-manager/invite-manager",
- "pages/order-pool2/order-pool2",
- "pages/group-chat/group-chat",
- "pages/cs-chat/cs-chat",
- "pages/verify/verify",
+ "pages/merchant/merchant",
"components/global-notification/global-notification",
"components/popup-notice/popup-notice",
"components/order-card/order-card",
"components/order-sender/order-sender",
- "pages/penalty/penalty/penalty",
- "pages/penalty/components/fakuan-list/fakuan-list",
- "pages/penalty/components/jifen-list/jifen-list",
- "pages/penalty/components/fakuan-pay/fakuan-pay",
- "pages/phone-auth/phone-auth",
- "components/chenghao-tag/chenghao-tag",
- "pages/assessor/assessor",
- "pages/assess-score/assess-score",
- "pages/assess-log/assess-log",
- "pages/assess-center/assess-center",
- "pages/assess-gold/assess-gold",
- "pages/escort-orders/escort-orders",
- "pages/withdraw/components/mode1/mode1",
- "pages/withdraw/components/mode2/mode2"
-
-
+ "components/chenghao-tag/chenghao-tag"
+ ],
+ "subPackages": [
+ {
+ "root": "pages/dashouduan",
+ "pages": ["dashouduan"]
+ },
+ {
+ "root": "pages/guanshiduan",
+ "pages": ["guanshiduan"]
+ },
+ {
+ "root": "pages/pick-user",
+ "pages": ["pick-user"]
+ },
+ {
+ "root": "pages/product-detail",
+ "pages": ["product-detail"]
+ },
+ {
+ "root": "pages/submit",
+ "pages": ["submit"]
+ },
+ {
+ "root": "pages/edit",
+ "pages": ["edit"]
+ },
+ {
+ "root": "pages/merchant-kefu-key",
+ "pages": ["merchant-kefu-key"]
+ },
+ {
+ "root": "pages/merchant-kefu-list",
+ "pages": ["merchant-kefu-list"]
+ },
+ {
+ "root": "pages/staff-join",
+ "pages": ["staff-join"]
+ },
+ {
+ "root": "pages/merchant-staff-audit",
+ "pages": ["merchant-staff-audit"]
+ },
+ {
+ "root": "pages/merchant-staff-role",
+ "pages": ["merchant-staff-role"]
+ },
+ {
+ "root": "pages/manager",
+ "pages": ["manager"]
+ },
+ {
+ "root": "pages/orders",
+ "pages": ["orders"]
+ },
+ {
+ "root": "pages/order-detail",
+ "pages": ["order-detail"]
+ },
+ {
+ "root": "pages/fighter-rules",
+ "pages": ["fighter-rules"]
+ },
+ {
+ "root": "pages/fighter-edit",
+ "pages": ["fighter-edit"]
+ },
+ {
+ "root": "pages/fighter-rank",
+ "pages": ["fighter-rank"]
+ },
+ {
+ "root": "pages/fighter-recharge",
+ "pages": ["fighter-recharge", "fighter-deposit"]
+ },
+ {
+ "root": "pages/fighter-ledger",
+ "pages": ["fighter-ledger"]
+ },
+ {
+ "root": "pages/fighter-msg",
+ "pages": ["fighter-msg"]
+ },
+ {
+ "root": "pages/dashou-exam",
+ "pages": ["dashou-exam"]
+ },
+ {
+ "root": "pages/withdraw",
+ "pages": ["withdraw", "withdraw-records", "components/mode1/mode1", "components/mode2/mode2"]
+ },
+ {
+ "root": "pages/invite-fighter",
+ "pages": ["invite-fighter"]
+ },
+ {
+ "root": "pages/my-fighter",
+ "pages": ["my-fighter"]
+ },
+ {
+ "root": "pages/recharge-log",
+ "pages": ["recharge-log"]
+ },
+ {
+ "root": "pages/manager-rank",
+ "pages": ["manager-rank"]
+ },
+ {
+ "root": "pages/merchant-data-stats",
+ "pages": ["merchant-data-stats"]
+ },
+ {
+ "root": "pages/merchant-dispatch",
+ "pages": ["merchant-dispatch"]
+ },
+ {
+ "root": "pages/merchant-regular-dispatch",
+ "pages": ["merchant-regular-dispatch"]
+ },
+ {
+ "root": "pages/merchant-msg",
+ "pages": ["merchant-msg"]
+ },
+ {
+ "root": "pages/merchant-penalty",
+ "pages": ["merchant-penalty"]
+ },
+ {
+ "root": "pages/merchant-rank",
+ "pages": ["merchant-rank"]
+ },
+ {
+ "root": "pages/merchant-recharge",
+ "pages": ["merchant-recharge"]
+ },
+ {
+ "root": "pages/merchant-order-detail",
+ "pages": ["merchant-order-detail"]
+ },
+ {
+ "root": "pages/fighter-order-detail",
+ "pages": ["fighter-order-detail"]
+ },
+ {
+ "root": "pages/chat",
+ "pages": ["chat"]
+ },
+ {
+ "root": "pages/express-order",
+ "pages": ["express-order"]
+ },
+ {
+ "root": "pages/order-pool",
+ "pages": ["order-pool"]
+ },
+ {
+ "root": "pages/poster",
+ "pages": ["poster"]
+ },
+ {
+ "root": "pages/gold-fighter",
+ "pages": ["gold-fighter"]
+ },
+ {
+ "root": "pages/leader",
+ "pages": ["leader"]
+ },
+ {
+ "root": "pages/manager-assign",
+ "pages": ["manager-assign"]
+ },
+ {
+ "root": "pages/leader-bonus-log",
+ "pages": ["leader-bonus-log"]
+ },
+ {
+ "root": "pages/invite-manager",
+ "pages": ["invite-manager"]
+ },
+ {
+ "root": "pages/group-chat",
+ "pages": ["group-chat"]
+ },
+ {
+ "root": "pages/cs-chat",
+ "pages": ["cs-chat"]
+ },
+ {
+ "root": "pages/verify",
+ "pages": ["verify"]
+ },
+ {
+ "root": "pages/penalty",
+ "pages": [
+ "penalty/penalty",
+ "components/fakuan-list/fakuan-list",
+ "components/jifen-list/jifen-list",
+ "components/fakuan-pay/fakuan-pay"
+ ]
+ },
+ {
+ "root": "pages/phone-auth",
+ "pages": ["phone-auth"]
+ },
+ {
+ "root": "pages/assessor",
+ "pages": ["assessor"]
+ },
+ {
+ "root": "pages/escort-orders",
+ "pages": ["escort-orders"]
+ },
+ {
+ "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",
@@ -88,26 +258,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/app.wxss b/app.wxss
index b58b0e0..58b2d37 100644
--- a/app.wxss
+++ b/app.wxss
@@ -2,15 +2,6 @@
/* ========== CSS 变量 ========== */
page {
- /* 星阙紫色主题 */
- --theme-primary: #9333ea;
- --theme-primary-light: #a855f7;
- --theme-primary-lighter: #c4b5fd;
- --theme-primary-lightest: #ede9fe;
- --theme-bg-tint: #f5f3ff;
- --theme-gradient: linear-gradient(180deg, #c4b5fd, #a78bfa);
- --theme-gradient-bg: linear-gradient(180deg, #c4b5fd 0%, #fff 28%, #f5f3ff 100%);
-
--color-price: #ff4444;
--color-text-main: #333;
--color-text-gray: #999;
@@ -467,7 +458,7 @@ page {
.tag-warning {
background: rgba(250, 173, 20, 0.1);
- color: #a855f7;
+ color: #faad14;
}
.tag-danger {
@@ -477,7 +468,7 @@ page {
.tag-gold {
background: rgba(201, 169, 98, 0.1);
- color: #9333ea;
+ color: #C9A962;
}
/* ========== 页面容器 ========== */
@@ -524,8 +515,8 @@ page {
}
.btn-primary--gold {
- background: linear-gradient(135deg, #9333ea, #a855f7);
- box-shadow: 0 8rpx 20rpx rgba(147, 51, 234, 0.3);
+ background: linear-gradient(135deg, #C9A962, #D4B56A);
+ box-shadow: 0 8rpx 20rpx rgba(201, 169, 98, 0.3);
}
.btn-primary--green {
@@ -539,8 +530,8 @@ page {
}
.btn-primary--orange {
- background: linear-gradient(135deg, #a855f7, #7c3aed);
- box-shadow: 0 8rpx 20rpx rgba(124, 58, 237, 0.3);
+ background: linear-gradient(135deg, #ffb347, #ff8c1a);
+ box-shadow: 0 8rpx 20rpx rgba(255, 140, 26, 0.3);
}
.btn-primary--purple {
@@ -574,8 +565,8 @@ page {
}
.btn-sm--gold {
- background: linear-gradient(135deg, #c4b5fd, #9333ea);
- box-shadow: 0 6rpx 16rpx rgba(147, 51, 234, 0.3);
+ background: linear-gradient(135deg, #ffcc00, #ffaa00);
+ box-shadow: 0 6rpx 16rpx rgba(255, 170, 0, 0.3);
}
.btn-sm--green {
@@ -613,8 +604,8 @@ page {
}
.btn-ghost--gold {
- color: #9333ea;
- border-color: #9333ea;
+ color: #C9A962;
+ border-color: #C9A962;
}
/* 禁用状态 */
@@ -863,8 +854,8 @@ page {
}
.status-tag--warning {
- background: #faf5ff;
- color: #a855f7;
+ background: #fffbe6;
+ color: #faad14;
}
.status-tag--info {
@@ -971,8 +962,8 @@ page {
}
@keyframes crownFloat {
- 0%, 100% { transform: translateY(0) rotate(5deg) scale(1); filter: drop-shadow(0 0 10rpx rgba(196, 181, 253, 0.8)); }
- 50% { transform: translateY(-15rpx) rotate(10deg) scale(1.1); filter: drop-shadow(0 0 25rpx rgba(196, 181, 253, 1)); }
+ 0%, 100% { transform: translateY(0) rotate(5deg) scale(1); filter: drop-shadow(0 0 10rpx rgba(255, 215, 0, 0.8)); }
+ 50% { transform: translateY(-15rpx) rotate(10deg) scale(1.1); filter: drop-shadow(0 0 25rpx rgba(255, 215, 0, 1)); }
}
@keyframes haloRotate {
@@ -1112,14 +1103,14 @@ page {
}
.chat-order-bubble {
- background: #f5f3ff;
+ background: #fff7e0;
padding: 12rpx;
border-radius: 8rpx;
}
.chat-order-label {
font-size: 24rpx;
- color: #a855f7;
+ color: #e6a23c;
font-weight: 600;
}
@@ -1614,7 +1605,7 @@ page {
.rank-card--1 .rank-podium-base { height: 80rpx; }
-.rank-podium-gold { background: linear-gradient(180deg, rgba(196, 181, 253, 0.3) 0%, rgba(196, 181, 253, 0.1) 100%); border: 1rpx solid rgba(196, 181, 253, 0.4); }
+.rank-podium-gold { background: linear-gradient(180deg, rgba(255, 215, 0, 0.3) 0%, rgba(255, 215, 0, 0.1) 100%); border: 1rpx solid rgba(255, 215, 0, 0.4); }
.rank-podium-silver { background: linear-gradient(180deg, rgba(192, 192, 192, 0.3) 0%, rgba(192, 192, 192, 0.1) 100%); border: 1rpx solid rgba(192, 192, 192, 0.4); }
.rank-podium-bronze { background: linear-gradient(180deg, rgba(205, 127, 50, 0.3) 0%, rgba(205, 127, 50, 0.1) 100%); border: 1rpx solid rgba(205, 127, 50, 0.4); }
@@ -1642,7 +1633,7 @@ page {
font-size: 85rpx;
position: relative;
z-index: 2;
- filter: drop-shadow(0 0 10rpx rgba(196, 181, 253, 0.8));
+ filter: drop-shadow(0 0 10rpx rgba(255, 215, 0, 0.8));
animation: crownFloat 3s ease-in-out infinite;
transform: rotate(5deg);
}
@@ -1654,7 +1645,7 @@ page {
transform: translate(-50%, -50%);
width: 200rpx;
height: 200rpx;
- background: radial-gradient(circle, rgba(196, 181, 253, 0.3) 0%, rgba(196, 181, 253, 0.1) 40%, transparent 70%);
+ background: radial-gradient(circle, rgba(255, 215, 0, 0.3) 0%, rgba(255, 215, 0, 0.1) 40%, transparent 70%);
z-index: 0;
animation: glowPulse 2s ease-in-out infinite;
}
@@ -1686,7 +1677,7 @@ page {
.rank-card--1 .rank-avatar-container { border-width: 6rpx; }
-.rank-frame-gold .rank-avatar-container { border-color: rgba(196, 181, 253, 0.3); filter: drop-shadow(0 0 30rpx rgba(196, 181, 253, 0.5)); }
+.rank-frame-gold .rank-avatar-container { border-color: rgba(255, 215, 0, 0.3); filter: drop-shadow(0 0 30rpx rgba(255, 215, 0, 0.5)); }
.rank-frame-silver .rank-avatar-container { border-color: rgba(192, 192, 192, 0.3); filter: drop-shadow(0 0 25rpx rgba(192, 192, 192, 0.5)); }
.rank-frame-bronze .rank-avatar-container { border-color: rgba(205, 127, 50, 0.3); filter: drop-shadow(0 0 25rpx rgba(205, 127, 50, 0.5)); }
@@ -1710,7 +1701,7 @@ page {
animation: haloRotate 10s linear infinite;
}
-.rank-halo-gold { width: 220rpx; height: 220rpx; background: radial-gradient(circle, rgba(196, 181, 253, 0.4) 0%, rgba(196, 181, 253, 0.2) 30%, transparent 70%); }
+.rank-halo-gold { width: 220rpx; height: 220rpx; background: radial-gradient(circle, rgba(255, 215, 0, 0.4) 0%, rgba(255, 215, 0, 0.2) 30%, transparent 70%); }
.rank-card--1 .rank-halo-gold { width: 260rpx; height: 260rpx; }
.rank-halo-silver { width: 200rpx; height: 200rpx; background: radial-gradient(circle, rgba(192, 192, 192, 0.4) 0%, rgba(192, 192, 192, 0.2) 30%, transparent 70%); }
.rank-halo-bronze { width: 200rpx; height: 200rpx; background: radial-gradient(circle, rgba(205, 127, 50, 0.4) 0%, rgba(205, 127, 50, 0.2) 30%, transparent 70%); }
@@ -1748,7 +1739,7 @@ page {
.rank-card--1 .rank-badge { width: 70rpx; height: 70rpx; font-size: 32rpx; bottom: -15rpx; right: -15rpx; }
-.rank-badge-gold { background: linear-gradient(135deg, #c4b5fd, #9333ea); }
+.rank-badge-gold { background: linear-gradient(135deg, #ffd700, #ff9800); }
.rank-badge-silver { background: linear-gradient(135deg, #c0c0c0, #808080); }
.rank-badge-bronze { background: linear-gradient(135deg, #cd7f32, #a0522d); }
@@ -1763,7 +1754,7 @@ page {
overflow: hidden;
}
-.rank-card--1 .rank-user-info-card { border-color: rgba(196, 181, 253, 0.3); background: rgba(20, 15, 5, 0.95); }
+.rank-card--1 .rank-user-info-card { border-color: rgba(255, 215, 0, 0.3); background: rgba(20, 15, 5, 0.95); }
.rank-card--2 .rank-user-info-card { border-color: rgba(192, 192, 192, 0.3); background: rgba(25, 25, 35, 0.95); }
.rank-card--3 .rank-user-info-card { border-color: rgba(205, 127, 50, 0.3); background: rgba(30, 20, 10, 0.95); }
@@ -1778,7 +1769,7 @@ page {
text-align: center;
}
-.rank-card--1 .rank-user-name { color: #c4b5fd; text-shadow: 0 0 15rpx rgba(196, 181, 253, 0.7); font-size: 34rpx; }
+.rank-card--1 .rank-user-name { color: #ffd700; text-shadow: 0 0 15rpx rgba(255, 215, 0, 0.7); font-size: 34rpx; }
.rank-card--2 .rank-user-name { color: #c0c0c0; text-shadow: 0 0 10rpx rgba(192, 192, 192, 0.7); }
.rank-card--3 .rank-user-name { color: #cd7f32; text-shadow: 0 0 10rpx rgba(205, 127, 50, 0.7); }
@@ -1816,7 +1807,7 @@ page {
margin-right: 4rpx;
}
-.rank-card--1 .rank-currency { color: #c4b5fd; }
+.rank-card--1 .rank-currency { color: #ffd700; }
.rank-card--2 .rank-currency { color: #c0c0c0; }
.rank-card--3 .rank-currency { color: #cd7f32; }
@@ -1827,7 +1818,7 @@ page {
text-shadow: 0 0 10rpx rgba(74, 222, 128, 0.5);
}
-.rank-card--1 .rank-amount { color: #c4b5fd; text-shadow: 0 0 15rpx rgba(196, 181, 253, 0.7); }
+.rank-card--1 .rank-amount { color: #ffd700; text-shadow: 0 0 15rpx rgba(255, 215, 0, 0.7); }
.rank-card--2 .rank-amount { color: #c0c0c0; text-shadow: 0 0 10rpx rgba(192, 192, 192, 0.7); }
.rank-card--3 .rank-amount { color: #cd7f32; text-shadow: 0 0 10rpx rgba(205, 127, 50, 0.7); }
diff --git a/components/chenghao-tag/chenghao-tag.js b/components/chenghao-tag/chenghao-tag.js
index b52ed96..37fcf1d 100644
--- a/components/chenghao-tag/chenghao-tag.js
+++ b/components/chenghao-tag/chenghao-tag.js
@@ -1,73 +1,119 @@
// 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: null, value: null },
},
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) {
+ let cfg = raw || {};
+ if (typeof cfg === 'string') {
+ try {
+ cfg = JSON.parse(cfg);
+ } catch (e) {
+ cfg = {};
+ }
+ }
+ if (Array.isArray(cfg)) {
+ cfg = cfg[0] || {};
+ }
+ if (!cfg || typeof cfg !== 'object') {
+ cfg = {};
+ }
+ 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, #c4b5fd, #9333ea);`;
+ 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, #c4b5fd, #9333ea);' });
+ 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 27bdd1d..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 {
@@ -85,6 +97,21 @@
animation: glow-anim 2s ease-in-out infinite;
}
@keyframes glow-anim {
- 0%, 100% { box-shadow: 0 0 8rpx rgba(196, 181, 253, 0.4); }
- 50% { box-shadow: 0 0 20rpx rgba(196, 181, 253, 0.8), 0 0 40rpx rgba(196, 181, 253, 0.4); }
+ 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/global-notification/global-notification.js b/components/global-notification/global-notification.js
index 29820d6..139fce1 100644
--- a/components/global-notification/global-notification.js
+++ b/components/global-notification/global-notification.js
@@ -1,4 +1,4 @@
-const { resolveAvatarUrl } = require('../../utils/avatar.js');
+const { resolveAvatarUrl, getDefaultAvatarUrl } = require('../../utils/avatar.js');
Component({
properties: {
@@ -53,7 +53,8 @@ Component({
// 静音状态
isMuted: false,
-
+ formattedTime: '',
+
// 自动隐藏计时器
autoHideTimeout: null
},
@@ -123,7 +124,7 @@ Component({
let avatar = resolveAvatarUrl(
data.avatar || data.message?.senderData?.avatar,
app
- );
+ ) || getDefaultAvatarUrl(app);
this.setData({
show: true,
@@ -131,6 +132,7 @@ Component({
message: data.content || '[消息内容]',
avatar: avatar,
notificationData: data,
+ formattedTime: this.formatTime(data.timestamp),
progress: 100,
swipingClass: '',
swipeStyle: ''
@@ -149,6 +151,7 @@ Component({
this.clearTimers();
this.setData({
show: false,
+ formattedTime: '',
progress: 100,
swipingClass: '',
swipeStyle: ''
@@ -265,6 +268,13 @@ Component({
this.triggerEvent('close');
this.hideNotification();
},
+
+ onAvatarError() {
+ const def = getDefaultAvatarUrl(getApp());
+ if (def && this.data.avatar !== def) {
+ this.setData({ avatar: def });
+ }
+ },
onMute(e) {
e.stopPropagation();
diff --git a/components/global-notification/global-notification.wxml b/components/global-notification/global-notification.wxml
index d76b58c..3f7cea1 100644
--- a/components/global-notification/global-notification.wxml
+++ b/components/global-notification/global-notification.wxml
@@ -15,14 +15,15 @@
-
+
+ 新消息
{{title}}
{{message}}
-
- {{formatTime(notificationData ? notificationData.timestamp : '')}}
+
+ {{formattedTime}}
diff --git a/components/global-notification/global-notification.wxss b/components/global-notification/global-notification.wxss
index fc67be6..80e8f3a 100644
--- a/components/global-notification/global-notification.wxss
+++ b/components/global-notification/global-notification.wxss
@@ -1,29 +1,40 @@
.global-notification {
position: fixed;
- left: 20rpx;
- right: 20rpx;
- top: 0rpx;
+ left: 24rpx;
+ right: 24rpx;
+ top: calc(env(safe-area-inset-top) + 108rpx);
z-index: 99999;
opacity: 0;
- transform: translateY(-120%);
- transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+ transform: translateY(-160%);
+ transition: all 0.42s cubic-bezier(0.34, 1.2, 0.64, 1);
pointer-events: none;
overflow: hidden;
- border-radius: 24rpx;
- background: linear-gradient(135deg,
- rgba(41, 47, 61, 0.98) 0%,
- rgba(31, 36, 48, 0.98) 100%);
- backdrop-filter: blur(30rpx) saturate(180%);
- -webkit-backdrop-filter: blur(30rpx) saturate(180%);
- border: 1rpx solid rgba(255, 255, 255, 0.08);
- box-shadow:
- 0 20rpx 60rpx rgba(0, 0, 0, 0.4),
- 0 0 0 1rpx rgba(255, 255, 255, 0.03),
- inset 0 1rpx 0 rgba(255, 255, 255, 0.1);
- min-height: 140rpx;
+ border-radius: 28rpx;
+ background: linear-gradient(145deg,
+ rgba(28, 32, 42, 0.97) 0%,
+ rgba(22, 26, 36, 0.98) 100%);
+ backdrop-filter: blur(40rpx) saturate(180%);
+ -webkit-backdrop-filter: blur(40rpx) saturate(180%);
+ border: 1rpx solid rgba(255, 255, 255, 0.1);
+ box-shadow:
+ 0 24rpx 64rpx rgba(0, 0, 0, 0.45),
+ 0 0 0 1rpx rgba(255, 255, 255, 0.04),
+ inset 0 1rpx 0 rgba(255, 255, 255, 0.12);
+ min-height: 148rpx;
touch-action: pan-y;
}
+.global-notification::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 24rpx;
+ bottom: 24rpx;
+ width: 6rpx;
+ border-radius: 0 6rpx 6rpx 0;
+ background: linear-gradient(180deg, #07c160 0%, #D4AF37 100%);
+}
+
.global-notification.show {
opacity: 1;
transform: translateY(0);
@@ -58,8 +69,8 @@
.notification-content {
display: flex;
align-items: center;
- padding: 32rpx;
- min-height: 140rpx;
+ padding: 28rpx 28rpx 28rpx 36rpx;
+ min-height: 148rpx;
position: relative;
}
@@ -84,6 +95,18 @@
justify-content: center;
}
+.notification-tag {
+ display: inline-block;
+ align-self: flex-start;
+ font-size: 20rpx;
+ color: #07c160;
+ background: rgba(7, 193, 96, 0.15);
+ padding: 4rpx 14rpx;
+ border-radius: 20rpx;
+ margin-bottom: 8rpx;
+ font-weight: 500;
+}
+
.notification-title {
font-size: 34rpx;
font-weight: 600;
diff --git a/components/kefu-float/kefu-float.js b/components/kefu-float/kefu-float.js
new file mode 100644
index 0000000..3fda074
--- /dev/null
+++ b/components/kefu-float/kefu-float.js
@@ -0,0 +1,170 @@
+import { openCustomerServiceChat, resolveKefuIconUrl } from '../../utils/kefu-nav.js';
+
+const CS_HOUR_START = 8;
+const CS_HOUR_END = 23;
+
+function getCsOnlineStatus() {
+ const hour = new Date().getHours();
+ const online = hour >= CS_HOUR_START && hour < CS_HOUR_END;
+ return {
+ csOnline: online,
+ csHoursText: '8:00-23:00',
+ csStatusText: online ? '在线' : '在线时间',
+ };
+}
+
+Component({
+ properties: {
+ bottom: { type: String, value: '200rpx' },
+ },
+
+ data: {
+ mode: 'full',
+ sessionHidden: false,
+ csUnread: 0,
+ floatY: 520,
+ iconUrl: '',
+ csOnline: false,
+ csHoursText: '8:00-23:00',
+ csStatusText: '在线时间',
+ },
+
+ lifetimes: {
+ attached() {
+ const app = getApp();
+ this._syncIcon();
+ this._syncFromGlobal();
+ this._initFloatY();
+ this._convHandler = () => this.syncCsUnread();
+ this._configHandler = () => this._syncIcon();
+ if (app.on) {
+ app.on('conversationsUpdated', this._convHandler);
+ app.on('unreadCountChanged', this._convHandler);
+ app.on('configApplied', this._configHandler);
+ }
+ this.syncCsUnread();
+ this._syncOnlineStatus();
+ },
+ detached() {
+ const app = getApp();
+ if (app.off) {
+ if (this._convHandler) {
+ app.off('conversationsUpdated', this._convHandler);
+ app.off('unreadCountChanged', this._convHandler);
+ }
+ if (this._configHandler) {
+ app.off('configApplied', this._configHandler);
+ }
+ }
+ },
+ },
+
+ pageLifetimes: {
+ show() {
+ this._syncIcon();
+ this._syncFromGlobal();
+ this.syncCsUnread();
+ this._syncOnlineStatus();
+ },
+ },
+
+ methods: {
+ _syncOnlineStatus() {
+ this.setData(getCsOnlineStatus());
+ },
+ _syncIcon() {
+ const url = resolveKefuIconUrl(getApp());
+ if (url && url !== this.data.iconUrl) {
+ this.setData({ iconUrl: url });
+ }
+ },
+
+ _initFloatY() {
+ const app = getApp();
+ if (app.globalData.kefuFloatY != null) {
+ this.setData({ floatY: app.globalData.kefuFloatY });
+ return;
+ }
+ try {
+ const sys = wx.getSystemInfoSync();
+ const defaultY = Math.floor((sys.windowHeight || 600) * 0.55);
+ this.setData({ floatY: defaultY });
+ } catch (e) {
+ this.setData({ floatY: 520 });
+ }
+ },
+
+ _syncFromGlobal() {
+ const app = getApp();
+ const sessionHidden = !!app.globalData.kefuFloatSessionHidden;
+ const mode = app.globalData.kefuFloatMode || 'full';
+ this.setData({ sessionHidden, mode });
+ },
+
+ onFloatMove(e) {
+ const y = e.detail && e.detail.y;
+ if (y == null) return;
+ const app = getApp();
+ app.globalData.kefuFloatY = y;
+ },
+
+ syncCsUnread() {
+ if (this.data.sessionHidden) return;
+ if (!wx.goEasy?.im?.latestConversations) return;
+ wx.goEasy.im.latestConversations({
+ onSuccess: (res) => {
+ const list = res.content?.conversations || res.conversations || [];
+ let unread = 0;
+ list.forEach((c) => {
+ if (c.type === 'cs' || c.teamId === 'support_team') {
+ unread += c.unread || 0;
+ }
+ });
+ if (unread !== this.data.csUnread) {
+ this.setData({ csUnread: unread });
+ }
+ },
+ onFailed: () => {},
+ });
+ },
+
+ onIconError() {
+ this._syncIcon();
+ },
+
+ onContact() {
+ openCustomerServiceChat();
+ },
+
+ onHideTap(e) {
+ if (e && e.stopPropagation) e.stopPropagation();
+ const app = getApp();
+ app.globalData.kefuFloatMode = 'mini';
+ this.setData({ mode: 'mini' });
+ },
+
+ onExpand(e) {
+ if (e && e.stopPropagation) e.stopPropagation();
+ const app = getApp();
+ app.globalData.kefuFloatMode = 'full';
+ this.setData({ mode: 'full' });
+ },
+
+ onSessionDismiss(e) {
+ if (e && e.stopPropagation) e.stopPropagation();
+ wx.showModal({
+ title: '隐藏联系客服',
+ content: '本次使用期间不再显示此按钮。清空后台重新进入小程序后会再次出现。',
+ confirmText: '确定隐藏',
+ cancelText: '取消',
+ success: (res) => {
+ if (res.confirm) {
+ const app = getApp();
+ app.globalData.kefuFloatSessionHidden = true;
+ this.setData({ sessionHidden: true });
+ }
+ },
+ });
+ },
+ },
+});
diff --git a/components/kefu-float/kefu-float.json b/components/kefu-float/kefu-float.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/components/kefu-float/kefu-float.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/components/kefu-float/kefu-float.wxml b/components/kefu-float/kefu-float.wxml
new file mode 100644
index 0000000..bdc6b2d
--- /dev/null
+++ b/components/kefu-float/kefu-float.wxml
@@ -0,0 +1,44 @@
+
+
+
+
+
+ {{csUnread > 99 ? '99+' : csUnread}}
+
+
+
+ 联系客服
+ 有新消息
+ {{csStatusText}} {{csHoursText}}
+
+
+
+ ×
+
+
+
+ 本次不再显示
+
+
+
+
+
+
+
+ {{csUnread > 99 ? '99+' : csUnread}}
+
+
+
+ 隐藏
+
+
+
+
+
diff --git a/components/kefu-float/kefu-float.wxss b/components/kefu-float/kefu-float.wxss
new file mode 100644
index 0000000..6cd2c59
--- /dev/null
+++ b/components/kefu-float/kefu-float.wxss
@@ -0,0 +1,186 @@
+.kefu-movable-area {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 900;
+}
+
+.kefu-movable-view {
+ width: auto;
+ height: auto;
+ pointer-events: auto;
+ position: absolute;
+ right: 20rpx;
+ top: 0;
+}
+
+.kefu-wrap {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ pointer-events: auto;
+}
+
+.kefu-float {
+ position: relative;
+}
+
+.kefu-float--full {
+ display: flex;
+ align-items: stretch;
+ background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
+ border-radius: 999rpx;
+ box-shadow: 0 8rpx 28rpx rgba(7, 193, 96, 0.45);
+ border: 2rpx solid rgba(255, 255, 255, 0.85);
+ overflow: visible;
+ animation: kefu-pulse 2.4s ease-in-out infinite;
+}
+
+@keyframes kefu-pulse {
+ 0%, 100% { box-shadow: 0 8rpx 28rpx rgba(7, 193, 96, 0.45); }
+ 50% { box-shadow: 0 8rpx 36rpx rgba(7, 193, 96, 0.65), 0 0 0 8rpx rgba(7, 193, 96, 0.12); }
+}
+
+.kefu-unread-badge {
+ position: absolute;
+ top: -10rpx;
+ right: -6rpx;
+ min-width: 36rpx;
+ height: 36rpx;
+ line-height: 36rpx;
+ padding: 0 8rpx;
+ background: #fa5151;
+ color: #fff;
+ font-size: 20rpx;
+ font-weight: 700;
+ text-align: center;
+ border-radius: 18rpx;
+ border: 3rpx solid #fff;
+ z-index: 2;
+}
+
+.kefu-unread-badge--mini {
+ top: -6rpx;
+ right: -4rpx;
+}
+
+.kefu-float-main {
+ display: flex;
+ align-items: center;
+ padding: 18rpx 24rpx;
+ flex: 1;
+}
+
+.kefu-float-main:active {
+ opacity: 0.88;
+}
+
+.kefu-float-icon-img {
+ width: 44rpx;
+ height: 44rpx;
+ margin-right: 12rpx;
+ flex-shrink: 0;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.95);
+ padding: 4rpx;
+}
+
+.kefu-text-col {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+}
+
+.kefu-float-text {
+ font-size: 28rpx;
+ color: #fff;
+ font-weight: 700;
+ white-space: nowrap;
+}
+
+.kefu-float-sub {
+ font-size: 20rpx;
+ color: rgba(255, 255, 255, 0.92);
+ margin-top: 2rpx;
+ font-weight: 600;
+}
+
+.kefu-float-sub--online {
+ color: #e8ffe8;
+}
+
+.kefu-float-sub--warn {
+ color: #fff3e0;
+}
+
+.kefu-float-close {
+ width: 52rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.12);
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 34rpx;
+ line-height: 1;
+ border-left: 1rpx solid rgba(255, 255, 255, 0.25);
+ border-radius: 0 999rpx 999rpx 0;
+}
+
+.kefu-float-close:active {
+ background: rgba(0, 0, 0, 0.2);
+}
+
+.kefu-permanent-row {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ margin-top: 6rpx;
+ padding: 4rpx 10rpx;
+}
+
+.kefu-permanent-row:active {
+ opacity: 0.75;
+}
+
+.kefu-permanent-row--mini {
+ margin-top: 4rpx;
+ padding: 2rpx 8rpx;
+}
+
+.kefu-permanent-label {
+ font-size: 20rpx;
+ color: #888;
+}
+
+.kefu-wrap--mini {
+ align-items: flex-end;
+}
+
+.kefu-float--mini {
+ width: 96rpx;
+ height: 96rpx;
+ padding: 0;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
+ box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.45);
+ border: 3rpx solid #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: kefu-pulse 2.4s ease-in-out infinite;
+}
+
+.kefu-float--mini:active {
+ transform: scale(0.96);
+}
+
+.kefu-float-mini-icon-img {
+ width: 48rpx;
+ height: 48rpx;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.95);
+ padding: 4rpx;
+}
diff --git a/components/order-card/order-card.wxss b/components/order-card/order-card.wxss
index 51c76d2..62c2737 100644
--- a/components/order-card/order-card.wxss
+++ b/components/order-card/order-card.wxss
@@ -15,7 +15,7 @@
.card-id { font-size: 24rpx; color: #999; margin-left: 15rpx; }
.cross-tag {
margin-left: auto;
- background: #8b5cf6;
+ background: #ff9900;
color: #fff;
font-size: 20rpx;
padding: 2rpx 12rpx;
diff --git a/components/order-sender/order-sender.js b/components/order-sender/order-sender.js
index f4c9444..5e0ce70 100644
--- a/components/order-sender/order-sender.js
+++ b/components/order-sender/order-sender.js
@@ -1,16 +1,87 @@
+import request from '../../utils/request';
+
const app = getApp();
+function mapIdentityForApi() {
+ const role = app.globalData.currentRole || wx.getStorageSync('currentRole') || 'normal';
+ if (role === 'dashou') return 'dashou';
+ if (role === 'shangjia') return 'shangjia';
+ return 'normal';
+}
+
Component({
properties: {
- visible: Boolean,
- showDetail: { type: Boolean, value: false }
+ visible: { type: Boolean, value: false },
+ groupId: { type: String, value: '' },
+ orderId: { type: String, value: '' },
},
- data: {},
+ data: {
+ keyword: '',
+ loading: false,
+ orders: [],
+ filteredOrders: [],
+ },
+
+ observers: {
+ visible(v) {
+ if (v) {
+ this.setData({ keyword: '' });
+ this.loadOrders('');
+ }
+ },
+ },
methods: {
close() {
this.triggerEvent('close');
- }
- }
-});
\ No newline at end of file
+ },
+
+ onSearchInput(e) {
+ const keyword = (e.detail.value || '').trim();
+ this.setData({ keyword });
+ if (this._searchTimer) clearTimeout(this._searchTimer);
+ this._searchTimer = setTimeout(() => {
+ this.loadOrders(keyword);
+ }, 350);
+ },
+
+ async loadOrders(keyword) {
+ const { groupId, orderId } = this.properties;
+ if (!groupId && !orderId) return;
+
+ this.setData({ loading: true });
+ try {
+ const res = await request({
+ url: '/dingdan/ltpddd',
+ method: 'POST',
+ data: {
+ groupId,
+ dingdan_id: orderId,
+ keyword: keyword || '',
+ identityType: mapIdentityForApi(),
+ },
+ });
+ const body = res?.data || {};
+ const list = body.data?.list || [];
+ this.setData({
+ orders: list,
+ filteredOrders: list,
+ loading: false,
+ });
+ } catch (e) {
+ console.warn('加载历史订单失败', e);
+ this.setData({ loading: false, orders: [], filteredOrders: [] });
+ wx.showToast({ title: '加载订单失败', icon: 'none' });
+ }
+ },
+
+ onSelectOrder(e) {
+ const index = e.currentTarget.dataset.index;
+ const order = this.data.filteredOrders[index];
+ if (!order) return;
+ this.triggerEvent('send', { order });
+ this.close();
+ },
+ },
+});
diff --git a/components/order-sender/order-sender.wxml b/components/order-sender/order-sender.wxml
index ae53ed5..3e5dd08 100644
--- a/components/order-sender/order-sender.wxml
+++ b/components/order-sender/order-sender.wxml
@@ -1,12 +1,28 @@
-
- 📋
- 此功能暂未开放
- 敬请期待
+
+
-
\ No newline at end of file
+
+ 加载中...
+
+
+
+ {{item.dingdan_id}}
+ {{item.zhuangtaiText}}
+
+ {{item.jieshao || '暂无介绍'}}
+
+ ¥{{item.jine || '0'}}
+ {{item.create_time}}
+
+ 点击发送订单卡片
+
+
+ 暂无相关订单
+
+
diff --git a/components/order-sender/order-sender.wxss b/components/order-sender/order-sender.wxss
index c0ffc48..304f2cd 100644
--- a/components/order-sender/order-sender.wxss
+++ b/components/order-sender/order-sender.wxss
@@ -1,45 +1,140 @@
.order-sender-mask {
- position: fixed; top: 0; left: 0; right: 0; bottom: 0;
- background: rgba(0,0,0,0.5);
- z-index: 2000;
- }
- .order-sender {
- position: fixed; bottom: 0; left: 0; right: 0;
- height: 360rpx;
- background: #fff;
- border-radius: 24rpx 24rpx 0 0;
- z-index: 2001;
- transform: translateY(100%);
- transition: 0.25s;
- display: flex;
- flex-direction: column;
- }
- .order-sender.show { transform: translateY(0); }
-
- .header {
- display: flex; justify-content: space-between;
- padding: 24rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
- }
- .title { font-size: 32rpx; font-weight: 600; }
- .close { font-size: 44rpx; color: #999; padding: 0 12rpx; }
-
- .content {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding-bottom: 40rpx;
- }
- .icon { font-size: 80rpx; margin-bottom: 20rpx; }
- .notice {
- font-size: 34rpx;
- font-weight: 600;
- color: #333;
- margin-bottom: 10rpx;
- }
- .sub {
- font-size: 24rpx;
- color: #999;
- }
\ No newline at end of file
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 2000;
+}
+
+.order-sender {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 72vh;
+ max-height: 900rpx;
+ background: #fff;
+ border-radius: 24rpx 24rpx 0 0;
+ z-index: 2001;
+ transform: translateY(100%);
+ transition: transform 0.25s;
+ display: flex;
+ flex-direction: column;
+}
+
+.order-sender.show {
+ transform: translateY(0);
+}
+
+.header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+}
+
+.title {
+ font-size: 32rpx;
+ font-weight: 600;
+}
+
+.close {
+ font-size: 44rpx;
+ color: #999;
+ padding: 0 12rpx;
+}
+
+.search-row {
+ padding: 16rpx 24rpx;
+ flex-shrink: 0;
+}
+
+.search-input {
+ background: #f5f5f5;
+ border-radius: 32rpx;
+ padding: 16rpx 28rpx;
+ font-size: 28rpx;
+}
+
+.order-list {
+ flex: 1;
+ height: 0;
+ padding: 0 24rpx 24rpx;
+ box-sizing: border-box;
+}
+
+.loading-tip,
+.empty-tip {
+ text-align: center;
+ color: #999;
+ font-size: 28rpx;
+ padding: 60rpx 0;
+}
+
+.order-item {
+ background: #fafafa;
+ border-radius: 16rpx;
+ padding: 20rpx 24rpx;
+ margin-bottom: 16rpx;
+ border: 1rpx solid #eee;
+}
+
+.order-item:active {
+ background: #f0f7ff;
+}
+
+.order-item-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 8rpx;
+}
+
+.order-id {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.order-status {
+ font-size: 22rpx;
+ color: #07c160;
+ background: #e8f8ee;
+ padding: 4rpx 14rpx;
+ border-radius: 20rpx;
+}
+
+.order-desc {
+ font-size: 26rpx;
+ color: #666;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 8rpx;
+}
+
+.order-item-bottom {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.order-price {
+ font-size: 28rpx;
+ color: #ff6b00;
+ font-weight: 600;
+}
+
+.order-time {
+ font-size: 22rpx;
+ color: #aaa;
+}
+
+.order-send-hint {
+ display: block;
+ font-size: 22rpx;
+ color: #007aff;
+ margin-top: 10rpx;
+}
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..9e7d8a3
--- /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/components/popup-notice/popup-notice.wxss b/components/popup-notice/popup-notice.wxss
index 76ac9c5..e19960f 100644
--- a/components/popup-notice/popup-notice.wxss
+++ b/components/popup-notice/popup-notice.wxss
@@ -138,7 +138,7 @@
.countdown-tip {
text-align: center;
font-size: 28rpx;
- color: #9333ea;
+ color: #ff6600;
margin-bottom: 20rpx;
}
@@ -223,7 +223,7 @@
height: 120rpx;
border-radius: 50%;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
- border: 2rpx solid rgba(196, 181, 253, 0.6);
+ border: 2rpx solid rgba(255, 215, 0, 0.6);
background: #f0f0f0;
display: block;
transform: translateZ(0);
diff --git a/config/club-config.js b/config/club-config.js
new file mode 100644
index 0000000..3343581
--- /dev/null
+++ b/config/club-config.js
@@ -0,0 +1,11 @@
+/**
+ * 小程序所属俱乐部配置 — 每个小程序工程编译前改这里即可。
+ * 星阙 = xq;星之界 = xzj;与 club 表 club_id 一致。
+ * 不要依赖后端猜测:前端必须明确所属 club。
+ */
+export const CLUB_ID = 'xzj';
+
+/** 与 club 表 wx_appid 一致,登录时可传给后端反查 club */
+export const WX_APP_ID = 'wxdefa454152e78a03';
+
+export const CLUB_NAME = '星之界电竞';
diff --git a/pages/accept-order/accept-order.js b/pages/accept-order/accept-order.js
index 7dea5c6..ca6d6fd 100644
--- a/pages/accept-order/accept-order.js
+++ b/pages/accept-order/accept-order.js
@@ -1,9 +1,16 @@
// 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';
+import { checkPenaltyForGrab } from '../../utils/grab-order-gate.js';
+import { fetchMyZhidingOrders, submitZhidingResponse, processZhidingList, filterZhidingBannerList, ZHIDING_HF_MAP } from '../../utils/zhiding-order.js';
Page({
data: {
@@ -30,7 +37,7 @@ Page({
// 4. 刷新控制字段
scrollViewRefreshing: false,
lastRefreshTime: 0,
- refreshCooldown: 2000,
+ refreshCooldown: 0,
isLoadingMore: false,
// 5. 切换类型冷却
@@ -47,13 +54,93 @@ Page({
// 商品轮播展示(只读 globalData,无额外接口)
lunboList: [],
+ gonggao: '',
+
+ examRequired: false,
+ examPassed: false,
+ _examChecked: false,
+
+ myZhidingList: [],
+ highlightOrderId: '',
+ myZhidingCount: 0,
+ defaultAvatarUrl: '',
+ showZhidingDetail: false,
+ zhidingDetailOrder: null,
+ showLaterModal: false,
+ laterOrderId: '',
+ laterNote: '',
},
async onLoad(options) {
- this.syncShopBannerFromGlobal();
+ const defAvatar = getDefaultAvatarUrl(app);
+ const highlight = (options && options.highlight) ? String(options.highlight) : '';
+ this.setData({ defaultAvatarUrl: defAvatar, highlightOrderId: highlight });
+ if (options && options.highlight) {
+ this._pendingHighlight = String(options.highlight);
+ }
+ if (app.globalData._acceptOrderSessionReady && app.globalData._acceptOrderPageCache) {
+ const cache = { ...app.globalData._acceptOrderPageCache };
+ this.data.shangpinleixing = cache.shangpinleixing || [];
+ const dingdanList = Array.isArray(cache.dingdanList)
+ ? cache.dingdanList.map((item) => this.processDingdanItem(item))
+ : [];
+ this.setData({
+ ...cache,
+ shangpinleixing: cache.shangpinleixing || [],
+ dingdanList,
+ bankuaiBiaoqian: cache.bankuaiBiaoqian || [],
+ lunboList: cache.lunboList || [],
+ });
+ 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();
+ if (!this.data.shangpinleixing || this.data.shangpinleixing.length === 0) {
+ await this.loadShangpinLeixing(true, false, false);
+ } else if (this.data.xuanzhongLeixingId) {
+ await this.loadDingdanList(true, true);
+ }
+ this.persistPageCache();
+ this._skipShowRefresh = true;
+ await this.loadMyZhidingOrders(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);
+ await this.loadMyZhidingOrders(true);
+ 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 () {
@@ -64,65 +151,94 @@ Page({
},
async onShow() {
- const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
- if (!phoneOk) return;
+ if (!app.globalData._dashouPhoneChecked) {
+ const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
+ if (!phoneOk) return;
+ app.globalData._dashouPhoneChecked = true;
+ }
- this.syncShopBannerFromGlobal();
this.registerNotificationComponent();
- this.loadGlobalStatus();
+ await this.syncDashouProfileFromServer();
+ warmupPindaoConfig(app);
if (wx.getStorageSync('uid')) {
- // IM 延后连接,避免切 Tab 时卡顿;订单列表不自动刷新,由用户下拉刷新
- setTimeout(() => {
- reconnectForRole('dashou');
- if (app.startImWhenReady) app.startImWhenReady();
- }, 600);
+ reconnectForRole('dashou');
+ if (app.startImWhenReady) app.startImWhenReady();
+ }
+
+ await this.checkExamStatus(false);
+
+ this.setData({ defaultAvatarUrl: getDefaultAvatarUrl(app) });
+ await this.loadMyZhidingOrders(true);
+
+ const hl = app.globalData._acceptOrderHighlight;
+ if (hl) {
+ app.globalData._acceptOrderHighlight = '';
+ this.setData({ highlightOrderId: hl });
+ await this.loadMyZhidingOrders(true);
+ }
+
+ 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();
+ }
+ await this.loadMyZhidingOrders(true);
+ 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() {
@@ -148,9 +264,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',
@@ -167,14 +296,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' });
@@ -182,7 +313,7 @@ Page({
} catch (error) {
wx.showToast({ title: '网络错误,加载失败', icon: 'none' });
} finally {
- wx.hideLoading();
+ if (showLoading) wx.hideLoading();
}
},
@@ -249,8 +380,8 @@ Page({
xuanzhongBiaoqianId: 0 // 重置标签筛选
});
await this.loadDingdanList(true);
- // 🆕 切换类型后加载新标签
await this.loadBankuaiBiaoqian();
+ this.persistPageCache();
} catch (error) {
console.error('切换类型失败:', error);
} finally {
@@ -270,19 +401,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({
@@ -302,6 +438,7 @@ Page({
isLoadingMore: false,
scrollViewRefreshing: false
});
+ this._listRequesting = false;
if (res.data.code === 200 || res.data.code === 0) {
const newList = res.data.data.list || [];
@@ -322,6 +459,7 @@ Page({
page: loadPage,
hasMore: hasMore
});
+ this.persistPageCache();
if (isRefresh) {
this.setData({ lastRefreshTime: Date.now() });
@@ -336,25 +474,36 @@ 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;
+ const uid = this.data.uid;
+ const isMyZhiding = isZhiding && uid && String(item.zhiding_uid) === String(uid);
- let zhidingAvatar = '';
+ const defAvatar = getDefaultAvatarUrl(app);
+ let zhidingAvatar = defAvatar;
if (item.zhiding_avatar) {
zhidingAvatar = !item.zhiding_avatar.startsWith('http')
? ossUrl + item.zhiding_avatar
@@ -362,31 +511,41 @@ Page({
}
const zhidingNicheng = item.zhiding_nicheng || '';
- // 🆕 判断用户是否有订单所需的会员(优先后端 hasRequiredMember)
+ // 订单要求指定会员时,核对用户是否持有该会员类型(优先后端字段)
let hasRequiredMember = true;
if (item.hasRequiredMember !== undefined) {
hasRequiredMember = !!item.hasRequiredMember;
} else if (item.has_required_member !== undefined) {
hasRequiredMember = !!item.has_required_member;
} else if (item.yaoqiuleixing == 1 && item.huiyuan_id) {
- const userHasIt = this.data.huiyuanList.some(h =>
- (h.huiyuanid == item.huiyuan_id) || (h.huiyuan_id == 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,
+ isMyZhiding,
+ isHighlighted: this.data.highlightOrderId && item.dingdan_id === this.data.highlightOrderId,
+ zhiding_hf: item.zhiding_hf,
+ zhiding_hf_text: item.zhiding_hf_text || ZHIDING_HF_MAP[item.zhiding_hf] || '',
+ zhiding_dhj_sm: item.zhiding_dhj_sm || '',
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,
};
@@ -399,13 +558,16 @@ Page({
switch (failureType) {
case 'huiyuan':
- params = { needScroll: '0', scrollTo: 'member' };
+ url = '/pages/fighter-recharge/fighter-recharge';
+ params = { scrollTo: 'member' };
break;
case 'yajin':
- params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin };
+ url = '/pages/fighter-recharge/fighter-deposit';
+ params = { requiredYajin: requiredYajin };
break;
case 'jifen':
- params = { needScroll: '1', scrollTo: 'bottom' };
+ url = '/pages/fighter-recharge/fighter-recharge';
+ params = { scrollTo: 'jifen' };
break;
}
@@ -424,11 +586,63 @@ 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;
+ const penalty = await checkPenaltyForGrab();
+ if (penalty.blocked) {
+ wx.showToast({
+ title: penalty.msg,
+ icon: 'none',
+ duration: 2000,
+ });
+ setTimeout(() => {
+ wx.navigateTo({ url: penalty.url });
+ }, 500);
+ 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' });
@@ -453,9 +667,7 @@ Page({
}
// 校验5: 会员要求
if (dingdanItem.yaoqiuleixing == 1) {
- const hasHuiyuan = this.data.huiyuanList.some(h =>
- (h.huiyuanid == dingdanItem.huiyuan_id) || (h.huiyuan_id == dingdanItem.huiyuan_id)
- );
+ const hasHuiyuan = userHasHuiyuan(this.data.huiyuanList, dingdanItem.huiyuan_id);
if (!hasHuiyuan) {
wx.showToast({
title: '未开通对应会员,无法抢单',
@@ -521,6 +733,8 @@ Page({
item => item.dingdan_id !== dingdanItem.dingdan_id
);
that.setData({ dingdanList: newList });
+ that.persistPageCache();
+ that.loadMyZhidingOrders(true);
} else {
wx.showToast({
title: qiangdanRes.data.msg || '抢单失败',
@@ -551,43 +765,134 @@ Page({
});
},
- onReachBottom() {
- const now = Date.now();
- const lastTime = this.data.lastRefreshTime;
- const cooldown = this.data.refreshCooldown;
+ async loadMyZhidingOrders(silent = false) {
+ if (!this.data.uid && !wx.getStorageSync('uid')) return;
+ try {
+ const raw = await fetchMyZhidingOrders();
+ const uid = this.data.uid || wx.getStorageSync('uid');
+ const highlight = this.data.highlightOrderId || this._pendingHighlight || '';
+ const list = filterZhidingBannerList(processZhidingList(raw, app, uid, highlight));
+ this.setData({ myZhidingList: list, myZhidingCount: list.length });
+ if (highlight && list.some((o) => o.dingdan_id === highlight)) {
+ this.setData({ highlightOrderId: highlight });
+ this._pendingHighlight = '';
+ }
+ } catch (e) {
+ if (!silent) console.warn('loadMyZhidingOrders', e);
+ }
+ },
- if (now - lastTime < cooldown) {
- wx.showToast({
- title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`,
- icon: 'none',
- duration: 1500
- });
+ openZhidingDetail(e) {
+ const item = e.currentTarget.dataset.item;
+ if (!item) return;
+ this.setData({ showZhidingDetail: true, zhidingDetailOrder: item });
+ },
+
+ closeZhidingDetail() {
+ this.setData({ showZhidingDetail: false, zhidingDetailOrder: null });
+ },
+
+ async onZhidingReject(e) {
+ const item = e.currentTarget.dataset.item;
+ if (!item) return;
+ wx.showModal({
+ title: '确认婉拒',
+ content: '婉拒后订单将退回抢单大厅,确定不想接此单吗?',
+ confirmText: '不想接',
+ confirmColor: '#e64340',
+ success: async (res) => {
+ if (!res.confirm) return;
+ wx.showLoading({ title: '提交中...', mask: true });
+ try {
+ const body = await submitZhidingResponse(item.dingdan_id, 2);
+ wx.hideLoading();
+ if (body && (body.code === 200 || body.code === 0)) {
+ wx.showToast({ title: body.msg || '已婉拒', icon: 'none' });
+ this.closeZhidingDetail();
+ await this.loadMyZhidingOrders(true);
+ await this.loadDingdanList(true, true);
+ } else {
+ wx.showToast({ title: body?.msg || '操作失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+ });
+ },
+
+ onZhidingLater(e) {
+ const item = e.currentTarget.dataset.item;
+ if (!item) return;
+ this.setData({
+ showZhidingDetail: false,
+ zhidingDetailOrder: null,
+ showLaterModal: true,
+ laterOrderId: item.dingdan_id,
+ laterNote: item.zhiding_dhj_sm || '',
+ });
+ },
+
+ closeLaterModal() {
+ this.setData({ showLaterModal: false, laterOrderId: '', laterNote: '' });
+ },
+
+ onLaterNoteInput(e) {
+ this.setData({ laterNote: e.detail.value });
+ },
+
+ async confirmZhidingLater() {
+ const { laterOrderId, laterNote } = this.data;
+ if (!laterNote.trim()) {
+ wx.showToast({ title: '请填写预计接待时间', icon: 'none' });
return;
}
+ wx.showLoading({ title: '提交中...', mask: true });
+ try {
+ const body = await submitZhidingResponse(laterOrderId, 3, laterNote.trim());
+ wx.hideLoading();
+ if (body && (body.code === 200 || body.code === 0)) {
+ const note = laterNote.trim();
+ wx.showToast({ title: `已记录:${note}`, icon: 'none', duration: 3500 });
+ this.closeLaterModal();
+ this.closeZhidingDetail();
+ await this.loadMyZhidingOrders(true);
+ await this.loadDingdanList(true, true);
+ } else {
+ wx.showToast({ title: body?.msg || '操作失败', icon: 'none' });
+ }
+ } catch (e) {
+ wx.hideLoading();
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+ async onZhidingAccept(e) {
+ const item = e.currentTarget.dataset.item;
+ if (!item) return;
+ wx.showLoading({ title: '处理中...', mask: true });
+ try {
+ await submitZhidingResponse(item.dingdan_id, 1);
+ wx.hideLoading();
+ } catch (e) {
+ wx.hideLoading();
+ }
+ const processed = this.processDingdanItem(item);
+ this.onQiangdanTap({ currentTarget: { dataset: { item: processed } } });
+ },
+
+ noop() {},
+
+ onReachBottom() {
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;
@@ -595,15 +900,26 @@ Page({
this.setData({
scrollViewRefreshing: true,
- lastRefreshTime: now,
+ lastRefreshTime: Date.now(),
page: 1,
- hasMore: true
+ hasMore: true,
});
- if (this.data.xuanzhongLeixingId) {
- this.refreshDashouProfileSilent();
- 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);
+ }
+ await this.loadMyZhidingOrders(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 d8aa64a..8be2c01 100644
--- a/pages/accept-order/accept-order.json
+++ b/pages/accept-order/accept-order.json
@@ -1,12 +1,14 @@
{
- "navigationBarTitleText": "抢单大厅",
- "navigationBarBackgroundColor": "#c4b5fd",
+ "navigationBarTitleText": "抢单列表",
+ "navigationBarBackgroundColor": "#f7dc51",
+ "backgroundColorTop": "#f7dc51",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false,
"backgroundTextStyle": "dark",
- "backgroundColor": "#f5f3ff",
+ "backgroundColor": "#fff8e1",
"usingComponents": {
"chenghao-tag": "/components/chenghao-tag/chenghao-tag",
- "global-notification": "/components/global-notification/global-notification"
+ "global-notification": "/components/global-notification/global-notification",
+ "kefu-float": "/components/kefu-float/kefu-float"
}
}
diff --git a/pages/accept-order/accept-order.wxml b/pages/accept-order/accept-order.wxml
index cbad5f6..5dfa720 100644
--- a/pages/accept-order/accept-order.wxml
+++ b/pages/accept-order/accept-order.wxml
@@ -18,7 +18,7 @@
refresher-default-style="black"
- refresher-background="#f5f3ff"
+ refresher-background="#fff8e1"
refresher-triggered="{{scrollViewRefreshing}}"
@@ -38,6 +38,38 @@
+
+
+
+ {{gonggao}}
+
+
+
+
+
+
+ 指定给您
+ {{myZhidingCount || myZhidingList.length}}单
+
+ 请确认是否接待
+
+
+
+
+ 单号 {{item.dingdan_id}}
+ ¥{{item.dashou_fencheng || 0}}
+
+ {{item.jieshao || '暂无介绍'}}
+ 您的回复:{{item.zhiding_hf_text}}{{item.zhiding_dhj_sm ? ' · ' + item.zhiding_dhj_sm : ''}}
+
+
+ 不想接
+ 等会接
+ 立即接待
+
+
+
+
@@ -50,7 +82,7 @@
indicator-color="rgba(255,255,255,0.6)"
- indicator-active-color="#9333ea"
+ indicator-active-color="#ffd061"
autoplay="{{lunboList.length > 1}}"
@@ -74,11 +106,11 @@
-
+
-
+
@@ -176,7 +208,7 @@
-
+
@@ -190,16 +222,6 @@
-
-
- 指定
-
-
-
- {{item.zhiding_nicheng || '指定接单员'}}
-
-
-
@@ -212,6 +234,20 @@
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
¥
@@ -226,9 +262,9 @@
-
@@ -248,7 +284,7 @@
平台派单
- 抢单
+ {{item.isMyZhiding ? '立即接待' : '抢单'}}
@@ -260,9 +296,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.jieshao || '暂无介绍'}}
+
+ 优质商家
+
+
+
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
+
+ ¥
+ {{item.dashou_fencheng || 0}}
+
+
+ 未开通会员
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.sjnicheng || '未知商家'}}
+ 发布于 {{item.creat_time}}
+
+
+ {{item.isMyZhiding ? '立即接待' : '抢单'}}
+
+
+
+
+
+
-
+
@@ -276,19 +387,23 @@
-
-
- 指定
-
-
-
- {{item.zhiding_nicheng || '指定接单员'}}
-
-
+
+
+
+ 指定
+
+ {{item.zhiding_nicheng || '指定接单员'}}
+
+
+
+
+
+
+
-
+
{{item.sjnicheng || '未知商家'}}
@@ -318,24 +433,33 @@
-
diff --git a/pages/accept-order/accept-order.wxss b/pages/accept-order/accept-order.wxss
index 45c1dbe..8ebdb0a 100644
--- a/pages/accept-order/accept-order.wxss
+++ b/pages/accept-order/accept-order.wxss
@@ -1,5 +1,11 @@
-/* pages/qiangdan/qiangdan.wxss - 高级机甲风格重构版(对称优化) */
+/* pages/qiangdan/qiangdan.wxss - 逍遥梦抢单页 */
@import '../../styles/dashou-xym-theme.wxss';
+@import '../../styles/dashou-xym-order-card.wxss';
+
+page {
+ background-color: #f7dc51;
+}
+
.qiangdan-page {
height: 100vh;
display: flex;
@@ -126,6 +132,7 @@
flex: 1;
height: 0;
-webkit-overflow-scrolling: touch;
+ background: transparent;
}
.scroll-bottom-spacer {
@@ -486,7 +493,7 @@
background: rgba(0, 0, 0, 0.3);
padding: 8rpx 20rpx;
border-radius: 60rpx;
- border: 1rpx solid rgba(196, 181, 253, 0.3);
+ border: 1rpx solid rgba(255, 215, 0, 0.3);
}
/* 分佣图标占位符,用户可替换为自己图标 */
@@ -504,10 +511,10 @@
.fenyong-price {
font-size: 44rpx;
- color: #c4b5fd;
+ color: #ffd700;
font-weight: 800;
margin-right: 4rpx;
- text-shadow: 0 0 20px rgba(196, 181, 253, 0.8);
+ text-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
}
.fenyong-unit {
@@ -764,4 +771,179 @@
max-width: 50%;
}
-@import '../../styles/dashou-xym-order-card.wxss';
+ /* 被指定订单(星阙功能保留,不影响星之界卡片 UI) */
+ .my-zhiding-banner {
+ margin: 16rpx 24rpx 0;
+ padding: 22rpx;
+ border-radius: 20rpx;
+ background: linear-gradient(135deg, #ff9500 0%, #ff6b00 100%);
+ border: 3rpx solid #ff4500;
+ box-shadow: 0 12rpx 32rpx rgba(255, 69, 0, 0.45);
+ position: relative;
+ z-index: 20;
+ }
+ .my-zhiding-banner-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 16rpx;
+ }
+ .my-zhiding-head-left {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ }
+ .my-zhiding-badge {
+ font-size: 26rpx;
+ font-weight: 800;
+ color: #ff4500;
+ background: #fff;
+ padding: 8rpx 18rpx;
+ border-radius: 999rpx;
+ }
+ .my-zhiding-count-num {
+ font-size: 32rpx;
+ font-weight: 800;
+ color: #fff;
+ }
+ .my-zhiding-sub {
+ font-size: 26rpx;
+ color: #fff;
+ font-weight: 700;
+ }
+ .my-zhiding-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 18rpx;
+ margin-bottom: 12rpx;
+ border: 2rpx solid #ffe0b2;
+ }
+ .my-zhiding-card--highlight {
+ border-color: #ff8c00;
+ box-shadow: 0 0 0 4rpx rgba(255, 140, 0, 0.15);
+ }
+ .my-zhiding-card-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 8rpx;
+ }
+ .my-zhiding-order-id {
+ font-size: 24rpx;
+ color: #666;
+ }
+ .my-zhiding-reward {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #e64340;
+ }
+ .my-zhiding-desc {
+ font-size: 28rpx;
+ color: #333;
+ line-height: 1.5;
+ }
+ .my-zhiding-status {
+ display: block;
+ margin-top: 8rpx;
+ font-size: 24rpx;
+ color: #059669;
+ }
+ .my-zhiding-actions {
+ display: flex;
+ gap: 12rpx;
+ margin-top: 16rpx;
+ }
+ .zhiding-act {
+ flex: 1;
+ text-align: center;
+ padding: 14rpx 0;
+ border-radius: 999rpx;
+ font-size: 26rpx;
+ font-weight: 600;
+ }
+ .zhiding-act--ghost {
+ background: #f3f4f6;
+ color: #666;
+ }
+ .zhiding-act--primary {
+ background: linear-gradient(90deg, #ff8c00, #ff6b00);
+ color: #fff;
+ }
+ .order-my-zhiding {
+ border: 3rpx solid #ff4500 !important;
+ box-shadow: 0 0 0 6rpx rgba(255, 69, 0, 0.25), 0 12rpx 36rpx rgba(255, 69, 0, 0.35) !important;
+ }
+ .order-zhiding-highlight {
+ animation: zhidingPulse 1.5s ease-in-out 2;
+ }
+ @keyframes zhidingPulse {
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 140, 0, 0.3); }
+ 50% { box-shadow: 0 0 0 12rpx rgba(255, 140, 0, 0); }
+ }
+ .zhiding-modal-mask {
+ position: fixed;
+ left: 0; right: 0; top: 0; bottom: 0;
+ background: rgba(0, 0, 0, 0.62);
+ z-index: 10050;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40rpx;
+ }
+ .zhiding-modal-mask--top {
+ z-index: 10060;
+ }
+ .zhiding-modal {
+ width: 100%;
+ max-width: 640rpx;
+ background: #ffffff;
+ border-radius: 24rpx;
+ overflow: hidden;
+ box-shadow: 0 24rpx 64rpx rgba(0, 0, 0, 0.35);
+ }
+ .zhiding-modal--sm { max-width: 580rpx; }
+ .zhiding-modal-head {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 28rpx;
+ border-bottom: 1rpx solid #eee;
+ background: #fff;
+ }
+ .zhiding-modal-title { font-size: 32rpx; font-weight: 700; color: #222; }
+ .zhiding-modal-close { font-size: 44rpx; color: #666; line-height: 1; padding: 0 8rpx; }
+ .zhiding-modal-body { padding: 24rpx 28rpx; background: #fff; }
+ .zhiding-modal-row {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+ color: #333;
+ }
+ .zhiding-modal-row.col { flex-direction: column; gap: 8rpx; }
+ .zhiding-modal-row .lbl { color: #999; font-size: 24rpx; }
+ .zhiding-modal-row .reward { color: #e64340; font-weight: 700; }
+ .zhiding-modal-actions { padding: 0 28rpx 28rpx; margin-top: 0; background: #fff; }
+ .later-hint { font-size: 26rpx; color: #444; display: block; margin-bottom: 16rpx; }
+ .later-input {
+ width: 100%;
+ box-sizing: border-box;
+ border: 2rpx solid #ddd;
+ border-radius: 12rpx;
+ padding: 22rpx 20rpx;
+ font-size: 28rpx;
+ color: #222;
+ background: #f9fafb;
+ min-height: 88rpx;
+ }
+ .later-input-ph { color: #aaa; }
+ .later-confirm {
+ margin: 0 28rpx 28rpx;
+ text-align: center;
+ padding: 24rpx;
+ background: linear-gradient(90deg, #ff8c00, #ff4500);
+ color: #fff;
+ border-radius: 999rpx;
+ font-size: 30rpx;
+ font-weight: 700;
+ }
diff --git a/pages/assess-log/assess-log.wxss b/pages/assess-log/assess-log.wxss
index 679e76a..1b986f6 100644
--- a/pages/assess-log/assess-log.wxss
+++ b/pages/assess-log/assess-log.wxss
@@ -132,7 +132,7 @@ page {
border-radius: 20rpx;
font-weight: 500;
}
- .status-0 { background: #F3E8FF; color: #9333ea; }
+ .status-0 { background: #FFF3E0; color: #EF6C00; }
.status-1 { background: #E8F5E9; color: #2E7D32; }
.status-2 { background: #FFEBEE; color: #C62828; }
.status-3 { background: #E3F2FD; color: #1565C0; }
diff --git a/pages/category/category.js b/pages/category/category.js
index abd8f65..5dffc1a 100644
--- a/pages/category/category.js
+++ b/pages/category/category.js
@@ -1,6 +1,7 @@
// pages/category/category.js
const app = getApp()
import { createPage } from '../../utils/base-page.js';
+import { buildClubHeaders } from '../../utils/club-context.js';
Page(createPage({
data: {
@@ -114,9 +115,7 @@ Page(createPage({
wx.request({
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
method: 'POST',
- header: {
- 'content-type': 'application/json'
- },
+ header: buildClubHeaders({ 'content-type': 'application/json' }),
success(res) {
if (res.statusCode === 200 && res.data) {
const data = res.data
diff --git a/pages/category/category.wxss b/pages/category/category.wxss
index d5791ab..9ce1023 100644
--- a/pages/category/category.wxss
+++ b/pages/category/category.wxss
@@ -60,13 +60,13 @@
.search-btn {
margin-left: 20rpx;
- box-shadow: 0 6rpx 20rpx rgba(147, 51, 234, 0.3);
+ box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.3);
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.search-btn:active {
transform: scale(0.95);
- box-shadow: 0 4rpx 15rpx rgba(147, 51, 234, 0.4);
+ box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4);
}
.search-btn-text {
@@ -127,7 +127,7 @@
transform: translate(-50%, -50%);
width: 300rpx;
height: 300rpx;
- background: radial-gradient(circle, rgba(168, 85, 247, 0.1) 0%, transparent 70%);
+ background: radial-gradient(circle, rgba(255, 204, 0, 0.1) 0%, transparent 70%);
z-index: -1;
}
@@ -167,8 +167,8 @@
.leixing-active .leixing-image-box {
transform: scale(1.12);
box-shadow:
- 0 18rpx 40rpx rgba(168, 85, 247, 0.3),
- 0 8rpx 16rpx rgba(147, 51, 234, 0.2);
+ 0 18rpx 40rpx rgba(255, 204, 0, 0.3),
+ 0 8rpx 16rpx rgba(255, 170, 0, 0.2);
}
.leixing-image {
@@ -185,7 +185,7 @@
right: -3rpx;
bottom: -3rpx;
border-radius: 50%;
- background: linear-gradient(135deg, #c4b5fd, #9333ea, #7c3aed);
+ background: linear-gradient(135deg, #ffcc00, #ffaa00, #ff8800);
opacity: 0;
transition: opacity 0.4s;
z-index: -1;
@@ -223,10 +223,10 @@
}
.leixing-active .leixing-text {
- color: #8b5cf6;
+ color: #ff9900;
font-weight: 600;
transform: translateY(-2rpx);
- text-shadow: 0 2rpx 4rpx rgba(168, 85, 247, 0.2);
+ text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2);
}
.leixing-active-bar {
@@ -234,12 +234,12 @@
bottom: -4rpx;
width: 44rpx;
height: 4rpx;
- background: linear-gradient(90deg, #c4b5fd, #9333ea);
+ background: linear-gradient(90deg, #ffcc00, #ffaa00);
border-radius: 2rpx;
opacity: 0;
transform: scaleX(0);
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
- box-shadow: 0 2rpx 8rpx rgba(147, 51, 234, 0.4);
+ box-shadow: 0 2rpx 8rpx rgba(255, 170, 0, 0.4);
}
.leixing-active-bar-show {
@@ -261,7 +261,7 @@
.border-effect-active {
opacity: 1;
- border-color: rgba(168, 85, 247, 0.5);
+ border-color: rgba(255, 204, 0, 0.5);
animation: borderGlow 2s infinite;
}
@@ -295,7 +295,7 @@
}
.zhuanqu-item:active {
- background: rgba(168, 85, 247, 0.05);
+ background: rgba(255, 204, 0, 0.05);
}
.zhuanqu-item-content {
@@ -320,9 +320,9 @@
}
.zhuanqu-active .zhuanqu-name {
- color: #8b5cf6;
+ color: #ff9900;
font-weight: 600;
- text-shadow: 0 2rpx 4rpx rgba(168, 85, 247, 0.2);
+ text-shadow: 0 2rpx 4rpx rgba(255, 153, 0, 0.2);
}
.zhuanqu-count {
@@ -332,7 +332,7 @@
}
.zhuanqu-active .zhuanqu-count {
- color: #9333ea;
+ color: #ffaa00;
font-weight: 500;
}
@@ -343,7 +343,7 @@
transform: translateY(-50%);
width: 6rpx;
height: 44rpx;
- background: linear-gradient(180deg, #a855f7, #9333ea);
+ background: linear-gradient(180deg, #ffcc00, #ffaa00);
border-radius: 3rpx 0 0 3rpx;
opacity: 0;
transition: all 0.3s;
@@ -353,7 +353,7 @@
.zhuanqu-indicator-glow {
opacity: 1;
animation: indicatorGlow 2s infinite;
- box-shadow: 0 0 20rpx rgba(168, 85, 247, 0.5);
+ box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.5);
}
.indicator-sparkle {
@@ -372,7 +372,7 @@
left: 0;
right: 0;
bottom: 0;
- background: linear-gradient(90deg, transparent, rgba(168, 85, 247, 0.05), transparent);
+ background: linear-gradient(90deg, transparent, rgba(255, 204, 0, 0.05), transparent);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
@@ -389,7 +389,7 @@
width: 0;
height: 0;
border-radius: 50%;
- background: rgba(168, 85, 247, 0.1);
+ background: rgba(255, 204, 0, 0.1);
transform: translate(-50%, -50%);
opacity: 0;
pointer-events: none;
@@ -463,7 +463,7 @@
right: -4rpx;
bottom: -4rpx;
border-radius: 18rpx;
- background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), transparent);
+ background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
@@ -479,7 +479,7 @@
right: 0;
width: 20rpx;
height: 20rpx;
- background: linear-gradient(135deg, #a855f7, transparent 70%);
+ background: linear-gradient(135deg, #ffcc00, transparent 70%);
border-radius: 0 14rpx 0 0;
}
@@ -514,7 +514,7 @@
left: 0;
width: 0;
height: 2rpx;
- background: linear-gradient(90deg, #c4b5fd, #9333ea);
+ background: linear-gradient(90deg, #ffcc00, #ffaa00);
transition: width 0.3s;
}
@@ -537,20 +537,20 @@
.price-icon {
font-size: 24rpx;
- color: #9333ea;
+ color: #ff6600;
font-weight: 500;
}
.price-integer {
font-size: 36rpx; /* 适当调整大小 */
- color: #9333ea;
+ color: #ff6600;
font-weight: 600;
margin-left: 2rpx;
}
.price-decimal {
font-size: 24rpx;
- color: #9333ea;
+ color: #ff6600;
font-weight: 500;
}
@@ -573,11 +573,11 @@
.detail-btn {
position: relative;
padding: 12rpx 28rpx;
- background: linear-gradient(135deg, #c4b5fd, #9333ea);
+ background: linear-gradient(135deg, #ffcc00, #ffaa00);
border-radius: 40rpx;
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
overflow: hidden;
- box-shadow: 0 6rpx 20rpx rgba(147, 51, 234, 0.2);
+ box-shadow: 0 6rpx 20rpx rgba(255, 170, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
@@ -586,7 +586,7 @@
.detail-btn:active {
transform: scale(0.95);
- box-shadow: 0 4rpx 15rpx rgba(147, 51, 234, 0.4);
+ box-shadow: 0 4rpx 15rpx rgba(255, 170, 0, 0.4);
}
.detail-btn-text {
@@ -659,7 +659,7 @@
left: 0;
right: 0;
bottom: 0;
- background: linear-gradient(135deg, transparent, rgba(168, 85, 247, 0.03), transparent);
+ background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.03), transparent);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
@@ -676,7 +676,7 @@
width: 0;
height: 0;
border-radius: 50%;
- background: rgba(168, 85, 247, 0.1);
+ background: rgba(255, 204, 0, 0.1);
transform: translate(-50%, -50%);
opacity: 0;
pointer-events: none;
@@ -707,19 +707,19 @@
}
.shangpin-empty-btn {
- background: linear-gradient(135deg, #c4b5fd, #9333ea);
+ background: linear-gradient(135deg, #ffcc00, #ffaa00);
color: white;
font-size: 26rpx;
font-weight: 500;
padding: 16rpx 44rpx;
border-radius: 40rpx;
- box-shadow: 0 8rpx 24rpx rgba(147, 51, 234, 0.3);
+ box-shadow: 0 8rpx 24rpx rgba(255, 170, 0, 0.3);
transition: all 0.3s;
}
.shangpin-empty-btn:active {
transform: scale(0.95);
- box-shadow: 0 4rpx 16rpx rgba(147, 51, 234, 0.4);
+ box-shadow: 0 4rpx 16rpx rgba(255, 170, 0, 0.4);
}
.load-more-line {
@@ -859,7 +859,7 @@
right: -4rpx;
bottom: -4rpx;
border-radius: 20rpx;
- background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), transparent);
+ background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), transparent);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
@@ -896,7 +896,7 @@
.info-tag {
padding: 6rpx 12rpx;
- background: rgba(168, 85, 247, 0.1);
+ background: rgba(255, 204, 0, 0.1);
border-radius: 6rpx;
}
@@ -921,7 +921,7 @@
left: 0;
right: 0;
bottom: 0;
- background: linear-gradient(135deg, transparent, rgba(168, 85, 247, 0.05), transparent);
+ background: linear-gradient(135deg, transparent, rgba(255, 204, 0, 0.05), transparent);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
@@ -977,7 +977,7 @@
width: 100%;
height: 100%;
border: 4rpx solid transparent;
- border-top-color: #a855f7;
+ border-top-color: #ffcc00;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@@ -1028,7 +1028,7 @@
left: 50%;
width: 12rpx;
height: 12rpx;
- background: #a855f7;
+ background: #ffcc00;
border-radius: 50%;
transform: translateX(-50%);
animation: spin 1s linear infinite;
@@ -1045,7 +1045,7 @@
left: 50%;
width: 200rpx;
height: 200rpx;
- background: radial-gradient(circle, rgba(168, 85, 247, 0.2) 0%, transparent 70%);
+ background: radial-gradient(circle, rgba(255, 204, 0, 0.2) 0%, transparent 70%);
transform: translate(-50%, -50%);
z-index: -1;
}
@@ -1076,19 +1076,19 @@
@keyframes borderGlow {
0%, 100% {
- border-color: rgba(168, 85, 247, 0.3);
+ border-color: rgba(255, 204, 0, 0.3);
}
50% {
- border-color: rgba(168, 85, 247, 0.8);
+ border-color: rgba(255, 204, 0, 0.8);
}
}
@keyframes indicatorGlow {
0%, 100% {
- box-shadow: 0 0 20rpx rgba(168, 85, 247, 0.3);
+ box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.3);
}
50% {
- box-shadow: 0 0 30rpx rgba(168, 85, 247, 0.8);
+ box-shadow: 0 0 30rpx rgba(255, 204, 0, 0.8);
}
}
diff --git a/pages/chat/chat.js b/pages/chat/chat.js
index 9178c6c..3f3ec92 100644
--- a/pages/chat/chat.js
+++ b/pages/chat/chat.js
@@ -1,7 +1,14 @@
const app = getApp();
import { formatDate } from '../../static/lib/utils';
-import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js';
+import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage, subscribeConfigAvatarRefresh } from '../../utils/avatar.js';
import { getLocalImUserId } from '../../utils/im-user.js';
+import { recordConversationOpen } from '../../utils/group-chat.js';
+import {
+ fetchHistoryMessages,
+ getOldestHistoryTimestamp,
+ mergeHistoryMessages,
+ waitChatImReady,
+} from '../../utils/chat-history.js';
Page({
data: {
@@ -25,29 +32,58 @@ Page({
pendingImage: '',
pendingImageFile: null,
keyboardHeight: 0,
- bottomSafeHeight: 10
+ bottomSafeHeight: 140,
+ defaultAvatarUrl: '',
},
onLoad(options) {
+ const defAvatar = getDefaultAvatarUrl(app);
if (options.data) {
try {
const p = JSON.parse(decodeURIComponent(options.data));
this.setData({
toUserId: p.toUserId || '',
toName: p.toName || '聊天',
- toAvatar: resolveAvatarUrl(p.toAvatar, app),
+ toAvatar: resolveAvatarUrl(p.toAvatar, app) || defAvatar,
+ defaultAvatarUrl: defAvatar,
});
- } catch (e) {}
+ } catch (e) {
+ this.setData({ defaultAvatarUrl: defAvatar });
+ }
+ } else {
+ this.setData({ defaultAvatarUrl: defAvatar });
}
wx.setNavigationBarTitle({ title: this.data.toName });
this.initCurrentUser();
+ this._unsubConfigAvatar = subscribeConfigAvatarRefresh(this, () => {
+ const def = getDefaultAvatarUrl(app);
+ this.setData({
+ defaultAvatarUrl: def,
+ toAvatar: resolveAvatarUrl(this.data.toAvatar, app) || def,
+ });
+ this.refreshCurrentUserAvatar();
+ });
},
onShow() {
+ const defAvatar = getDefaultAvatarUrl(app);
+ this.setData({
+ defaultAvatarUrl: defAvatar,
+ toAvatar: resolveAvatarUrl(this.data.toAvatar, app) || defAvatar,
+ });
+ this.refreshCurrentUserAvatar();
+ if (this.data.toUserId) {
+ if (!app.globalData.pageState) app.globalData.pageState = {};
+ app.globalData.pageState.lastOpenedConvId = this.data.toUserId;
+ recordConversationOpen({ userId: this.data.toUserId });
+ }
this.ensureChatReady();
},
onHide() {
+ if (this.data.toUserId) {
+ recordConversationOpen({ userId: this.data.toUserId });
+ }
this.clearPageListeners();
this.markPrivateMessageAsRead();
setTimeout(() => {
@@ -55,27 +91,34 @@ Page({
}, 250);
},
- ensureChatReady() {
+ onUnload() {
+ if (this._unsubConfigAvatar) {
+ this._unsubConfigAvatar();
+ this._unsubConfigAvatar = null;
+ }
+ },
+
+ async ensureChatReady() {
const targetUserId = getLocalImUserId(app);
if (!targetUserId) return;
- const ready = () => {
+ const ready = async () => {
this.setupAllListeners();
- this.loadHistory(true);
+ await this.loadHistory(true);
};
- if (app.ensureConnection) {
- const ret = app.ensureConnection();
- if (ret && typeof ret.then === 'function') {
- ret.then(ready).catch(ready);
- } else {
- setTimeout(ready, 300);
+ try {
+ const ok = await waitChatImReady(app, 12000);
+ if (ok) {
+ await ready();
+ return;
}
- return;
+ } catch (e) {
+ console.warn('[私聊] IM 连接失败', e);
}
if (this.isConnected() && wx.goEasy.im?.userId === targetUserId) {
- ready();
+ await ready();
return;
}
this.connectGoEasy(targetUserId);
@@ -133,14 +176,26 @@ Page({
const imId = getLocalImUserId(app);
const uid = wx.getStorageSync('uid');
const nick = app.globalData.nicheng || app.globalData.dashouNicheng || wx.getStorageSync('nicheng') || '';
+ const defAvatar = getDefaultAvatarUrl(app);
+ const avatar = resolveAvatarFromStorage(app) || defAvatar;
this.setData({
currentUser: {
id: imId || ('Ds' + uid),
name: nick || `用户${uid}`,
- avatar: resolveAvatarUrl(wx.getStorageSync('touxiang'), app),
+ avatar,
},
});
},
+
+ refreshCurrentUserAvatar() {
+ const defAvatar = getDefaultAvatarUrl(app);
+ const cu = this.data.currentUser;
+ if (!cu) return;
+ const avatar = resolveAvatarUrl(cu.avatar || wx.getStorageSync('touxiang'), app) || defAvatar;
+ if (avatar !== cu.avatar) {
+ this.setData({ currentUser: { ...cu, avatar } });
+ }
+ },
fixAvatar(url) {
return resolveAvatarUrl(url, app);
},
@@ -156,6 +211,19 @@ Page({
normalizeMessage(msg) {
if (!msg) return msg;
if (!msg.payload) msg.payload = {};
+ const defAvatar = this.data.defaultAvatarUrl || getDefaultAvatarUrl(app);
+ const myId = this.data.currentUser?.id;
+ if (myId && msg.senderId === myId) {
+ msg.senderData = {
+ name: this.data.currentUser.name,
+ avatar: resolveAvatarUrl(this.data.currentUser.avatar, app) || defAvatar,
+ };
+ } else {
+ msg.senderData = {
+ name: this.data.toName,
+ avatar: resolveAvatarUrl(this.data.toAvatar, app) || defAvatar,
+ };
+ }
if (msg.type === 'image') {
const p = msg.payload;
if (!p.url) p.url = p.thumbnail || p.thumb || p.imageUrl || '';
@@ -188,63 +256,91 @@ Page({
onPullDownRefresh() {
if (this.data.loadingHistory) return;
+ if (!this.data.hasMore) {
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ return;
+ }
this.setData({ isRefreshing: true });
- this.loadHistory(false).finally(() => { this.setData({ isRefreshing: false }); wx.stopPullDownRefresh(); });
+ this.loadHistory(false).finally(() => {
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ });
},
- loadHistory(refresh) {
- if (!refresh && !this.data.hasMore) return Promise.resolve();
- return new Promise((resolve) => {
- this.setData({ loadingHistory: true });
- const { toUserId, lastTimestamp } = this.data;
- const ts = refresh ? null : lastTimestamp;
- wx.goEasy.im.history({
- type: wx.GoEasy.IM_SCENE.PRIVATE, id: toUserId, lastTimestamp: ts, limit: 20,
- onSuccess: (res) => {
- let list = res.content || [];
- list.sort((a, b) => a.timestamp - b.timestamp);
- list.forEach((m, idx) => {
- m = this.normalizeMessage(m);
- list[idx] = m;
- m.formattedTime = formatDate(m.timestamp);
- if (idx === 0) m.showTime = true;
- else m.showTime = (m.timestamp - list[idx-1].timestamp) / 60000 > 5;
- if (m.senderId === this.data.currentUser.id) {
- m.senderData = {
- name: this.data.currentUser.name,
- avatar: resolveAvatarUrl(this.data.currentUser.avatar, app),
- };
- } else {
- m.senderData = {
- name: this.data.toName,
- avatar: resolveAvatarUrl(this.data.toAvatar, app),
- };
- }
- });
- let final = refresh ? list : [...list, ...this.data.messages];
- if (!refresh) {
- for (let i=0; i 5;
- }
- }
- const ids = new Set();
- const unique = [];
- for (const m of final) { if (!ids.has(m.messageId)) { ids.add(m.messageId); unique.push(m); } }
- const update = {
- messages: unique,
- hasMore: list.length >= 20,
- lastTimestamp: unique.length ? unique[0].timestamp : lastTimestamp,
- loadingHistory: false
- };
- if (refresh) update.scrollToView = 'msg-bottom';
- this.setData(update);
- if (refresh) this.markPrivateMessageAsRead();
- resolve();
- },
- onFailed: () => { this.setData({ loadingHistory: false }); resolve(); }
+ mapHistoryMessage(m, idx, list) {
+ m = this.normalizeMessage(m);
+ m.formattedTime = formatDate(m.timestamp);
+ if (idx === 0) m.showTime = true;
+ else m.showTime = (m.timestamp - list[idx - 1].timestamp) / 60000 > 5;
+ if (m.senderId === this.data.currentUser?.id) {
+ m.senderData = {
+ name: this.data.currentUser.name,
+ avatar: resolveAvatarUrl(this.data.currentUser.avatar, app),
+ };
+ } else {
+ m.senderData = {
+ name: this.data.toName,
+ avatar: resolveAvatarUrl(this.data.toAvatar, app),
+ };
+ }
+ return m;
+ },
+
+ async loadHistory(refresh) {
+ if (!refresh && !this.data.hasMore) return;
+ if (this.data.loadingHistory) return;
+ if (!this.data.toUserId) return;
+
+ this.setData({ loadingHistory: true });
+ try {
+ const ready = await waitChatImReady(app, 12000);
+ if (!ready) {
+ wx.showToast({ title: '消息服务未连接,请稍后重试', icon: 'none' });
+ return;
+ }
+
+ const ts = refresh
+ ? null
+ : getOldestHistoryTimestamp(this.data.messages, this.data.lastTimestamp);
+ if (!refresh && ts == null) {
+ this.setData({ hasMore: false });
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ return;
+ }
+
+ const raw = await fetchHistoryMessages({
+ scene: wx.GoEasy.IM_SCENE.PRIVATE,
+ id: this.data.toUserId,
+ lastTimestamp: ts,
+ limit: 20,
});
- });
+
+ const merged = mergeHistoryMessages({
+ incoming: raw,
+ existing: this.data.messages,
+ refresh,
+ limit: 20,
+ mapMessage: (m, idx, list) => this.mapHistoryMessage(m, idx, list),
+ });
+
+ const update = {
+ messages: merged.messages,
+ hasMore: merged.hasMore,
+ lastTimestamp: merged.lastTimestamp,
+ };
+ if (refresh) update.scrollToView = 'msg-bottom';
+ this.setData(update);
+ if (refresh) this.markPrivateMessageAsRead();
+ } catch (e) {
+ console.warn('[私聊] 历史消息加载失败', e);
+ if (!refresh) {
+ wx.showToast({ title: '加载历史消息失败', icon: 'none' });
+ }
+ } finally {
+ this.setData({ loadingHistory: false });
+ }
},
listenNewMsg() {
diff --git a/pages/chat/chat.wxml b/pages/chat/chat.wxml
index 5dd1fb6..c64b50a 100644
--- a/pages/chat/chat.wxml
+++ b/pages/chat/chat.wxml
@@ -4,13 +4,13 @@
refresher-enabled="{{true}}"
refresher-triggered="{{isRefreshing}}"
bindrefresherrefresh="onPullDownRefresh"
- style="top: 20rpx; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 20rpx);">
+ style="top: 20rpx; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 24rpx);">
加载更早消息...
{{item.formattedTime}}
-
+
ID: {{item.payload.orderId}}
-
+
{{item.read ? '已读' : '未读'}}
-
+
diff --git a/pages/cs-chat/cs-chat.js b/pages/cs-chat/cs-chat.js
index 645fcd6..1e1a4c8 100644
--- a/pages/cs-chat/cs-chat.js
+++ b/pages/cs-chat/cs-chat.js
@@ -1,7 +1,14 @@
const app = getApp();
import { formatDate } from '../../static/lib/utils';
import { getLocalImUserId } from '../../utils/im-user.js';
-import { resolveAvatarUrl } from '../../utils/avatar.js';
+import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage, subscribeConfigAvatarRefresh, ensureAvatarUrl } from '../../utils/avatar.js';
+import {
+ fetchHistoryMessages,
+ getOldestHistoryTimestamp,
+ mergeHistoryMessages,
+ waitChatImReady,
+} from '../../utils/chat-history.js';
+import { matchAutoReply, getWelcomeText } from '../../utils/scriptService.js';
Page({
data: {
@@ -29,11 +36,14 @@ Page({
pendingImage: '',
pendingImageFile: null,
keyboardHeight: 0,
- bottomSafeHeight: 10
+ bottomSafeHeight: 140,
+ defaultAvatarUrl: '',
+ welcomeText: '你好,请问有什么可以帮到您的?',
},
onLoad(options) {
let teamId = '', teamName = '客服', teamAvatar = '';
+ const defAvatar = getDefaultAvatarUrl(app);
if (options.data) {
try {
const p = JSON.parse(decodeURIComponent(options.data));
@@ -43,38 +53,102 @@ Page({
} catch (e) {
}
}
- if (!teamAvatar) {
- teamAvatar = app.globalData.ossImageUrl + app.globalData.morentouxiang;
+ let teamAvatarResolved = teamAvatar ? ensureAvatarUrl(teamAvatar, app) : defAvatar;
+ if (!teamAvatarResolved || !teamAvatarResolved.startsWith('http')) {
+ teamAvatarResolved = defAvatar;
}
- this.setData({ teamId, teamName, teamAvatar });
+ this.setData({ teamId, teamName, teamAvatar: teamAvatarResolved, defaultAvatarUrl: defAvatar });
wx.setNavigationBarTitle({ title: teamName });
this.initCurrentUser();
+ this.loadWelcomeScript();
+ this._unsubConfigAvatar = subscribeConfigAvatarRefresh(this, () => {
+ const def = getDefaultAvatarUrl(app);
+ this.setData({
+ defaultAvatarUrl: def,
+ teamAvatar: def,
+ });
+ this.refreshCurrentUserAvatar();
+ });
+ },
+
+ onUnload() {
+ if (this._unsubConfigAvatar) {
+ this._unsubConfigAvatar();
+ this._unsubConfigAvatar = null;
+ }
},
onShow() {
+ const defAvatar = getDefaultAvatarUrl(app);
+ const patch = {
+ defaultAvatarUrl: defAvatar,
+ teamAvatar: defAvatar,
+ };
+ this.setData(patch);
+ this.refreshCurrentUserAvatar();
this.autoConnect();
},
+ refreshCurrentUserAvatar() {
+ const defAvatar = getDefaultAvatarUrl(app);
+ const cu = this.data.currentUser;
+ if (!cu) return;
+ const avatar = resolveAvatarUrl(cu.avatar || wx.getStorageSync('touxiang'), app) || defAvatar;
+ if (avatar !== cu.avatar) {
+ this.setData({ currentUser: { ...cu, avatar } });
+ }
+ },
+
onHide() {
this.clearAllListeners();
},
- autoConnect() {
+ async loadWelcomeScript() {
+ try {
+ const text = await getWelcomeText();
+ if (!text) return;
+ this.setData({ welcomeText: text });
+ const msgs = this.data.messages;
+ const idx = msgs.findIndex((m) => m.messageId === 'welcome-cs');
+ if (idx >= 0) {
+ const updated = [...msgs];
+ updated[idx] = { ...updated[idx], payload: { ...updated[idx].payload, text } };
+ this.setData({ messages: updated });
+ }
+ } catch (e) {
+ console.warn('loadWelcomeScript failed', e);
+ }
+ },
+
+ async autoConnect() {
const targetUserId = getLocalImUserId(app);
if (!targetUserId) return;
- const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
- if (status === 'connected' || status === 'reconnected') {
- const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
- if (currentUserId === targetUserId) {
- this.setupAllListeners();
- this.loadHistory(true);
+ const ready = async () => {
+ this.setupAllListeners();
+ await this.loadHistory(true);
+ };
+
+ try {
+ const ok = await waitChatImReady(app, 12000);
+ if (ok) {
+ await ready();
return;
- } else {
- wx.goEasy.disconnect();
}
+ } catch (e) {
+ console.warn('[客服] IM 连接失败', e);
}
- this.connectGoEasy(targetUserId);
+
+ if (this.isConnected()) {
+ await ready();
+ } else {
+ this.connectGoEasy(targetUserId);
+ }
+ },
+
+ isConnected() {
+ const s = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
+ return s === 'connected' || s === 'reconnected';
},
connectGoEasy(userId) {
@@ -84,7 +158,7 @@ Page({
id: userId,
data: {
name: currentUser.name,
- avatar: resolveAvatarUrl(currentUser.avatar, app)
+ avatar: resolveAvatarUrl(currentUser.avatar, app) || getDefaultAvatarUrl(app)
},
onSuccess: () => {
this.setupAllListeners();
@@ -119,11 +193,13 @@ Page({
initCurrentUser() {
const imId = getLocalImUserId(app);
const uid = wx.getStorageSync('uid');
+ const defAvatar = getDefaultAvatarUrl(app);
+ const avatar = resolveAvatarFromStorage(app) || defAvatar;
this.setData({
currentUser: {
id: imId || ('Boss' + uid),
- name: app.globalData.currentUser?.name || `用户${uid}`,
- avatar: resolveAvatarUrl(wx.getStorageSync('touxiang'), app),
+ name: app.globalData.currentUser?.name || wx.getStorageSync('nicheng') || `用户${uid}`,
+ avatar,
},
});
},
@@ -169,66 +245,89 @@ Page({
this.setData({ messages: msgs });
},
+ mapHistoryMessage(m, idx, list) {
+ m = this.normalizeMessage(m);
+ m.formattedTime = formatDate(m.timestamp);
+ if (idx === 0) m.showTime = true;
+ else m.showTime = (m.timestamp - list[idx - 1].timestamp) / 60000 > 5;
+ if (m.senderId === this.data.currentUser?.id) {
+ const av = resolveAvatarUrl(this.data.currentUser.avatar, app) || this.data.defaultAvatarUrl;
+ m.senderData = { name: this.data.currentUser.name, avatar: av };
+ } else {
+ const av = resolveAvatarUrl(this.data.teamAvatar, app) || this.data.defaultAvatarUrl;
+ m.senderData = { name: this.data.teamName, avatar: av };
+ }
+ return m;
+ },
+
+ injectWelcomeMessage(messages) {
+ const list = Array.isArray(messages) ? [...messages] : [];
+ const welcomeId = 'welcome-cs';
+ if (!list.some((m) => m.messageId === welcomeId)) {
+ const welcome = this.createWelcomeMessage();
+ welcome.messageId = welcomeId;
+ welcome.showTime = true;
+ list.unshift(welcome);
+ }
+ return list;
+ },
+
// 历史消息
- loadHistory(refresh) {
- if (!refresh && !this.data.hasMore) return Promise.resolve();
- return new Promise((resolve) => {
- this.setData({ loadingHistory: true });
- const { teamId, lastTimestamp } = this.data;
- const ts = refresh ? null : lastTimestamp;
- wx.goEasy.im.history({
- type: wx.GoEasy.IM_SCENE.CS,
- id: teamId,
+ async loadHistory(refresh) {
+ if (!refresh && !this.data.hasMore) return;
+ if (this.data.loadingHistory) return;
+ if (!this.data.teamId) return;
+
+ this.setData({ loadingHistory: true });
+ try {
+ const ready = await waitChatImReady(app, 12000);
+ if (!ready) {
+ wx.showToast({ title: '消息服务未连接,请稍后重试', icon: 'none' });
+ return;
+ }
+
+ const ts = refresh
+ ? null
+ : getOldestHistoryTimestamp(this.data.messages, this.data.lastTimestamp);
+ if (!refresh && ts == null) {
+ this.setData({ hasMore: false });
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ return;
+ }
+
+ const raw = await fetchHistoryMessages({
+ scene: wx.GoEasy.IM_SCENE.CS,
+ id: this.data.teamId,
lastTimestamp: ts,
limit: 20,
- onSuccess: (res) => {
- let list = res.content || [];
- list.sort((a, b) => a.timestamp - b.timestamp);
- list.forEach((m, idx) => {
- m = this.normalizeMessage(m);
- list[idx] = m;
- m.formattedTime = formatDate(m.timestamp);
- if (idx === 0) m.showTime = true;
- else m.showTime = (m.timestamp - list[idx-1].timestamp) / 60000 > 5;
- if (m.senderId === this.data.currentUser.id) {
- m.senderData = { name: this.data.currentUser.name, avatar: this.data.currentUser.avatar };
- } else {
- m.senderData = { name: this.data.teamName, avatar: this.data.teamAvatar };
- }
- });
- let final = refresh ? list : [...list, ...this.data.messages];
- if (!refresh) {
- for (let i=0; i 5;
- }
- }
- const ids = new Set();
- const unique = [];
- for (const m of final) { if (!ids.has(m.messageId)) { ids.add(m.messageId); unique.push(m); } }
-
- // 插入欢迎语
- const welcomeId = 'welcome-cs';
- if (!unique.some(m => m.messageId === welcomeId)) {
- const welcome = this.createWelcomeMessage();
- welcome.messageId = welcomeId;
- welcome.showTime = true;
- unique.unshift(welcome);
- }
-
- const update = {
- messages: unique,
- hasMore: list.length >= 20,
- lastTimestamp: unique.length ? unique[0].timestamp : lastTimestamp,
- loadingHistory: false
- };
- if (refresh) update.scrollToView = 'msg-bottom';
- this.setData(update);
- resolve();
- },
- onFailed: () => { this.setData({ loadingHistory: false }); resolve(); }
});
- });
+
+ let merged = mergeHistoryMessages({
+ incoming: raw,
+ existing: this.data.messages,
+ refresh,
+ limit: 20,
+ mapMessage: (m, idx, list) => this.mapHistoryMessage(m, idx, list),
+ });
+
+ merged.messages = this.injectWelcomeMessage(merged.messages);
+ merged.lastTimestamp = getOldestHistoryTimestamp(merged.messages, merged.lastTimestamp);
+
+ const update = {
+ messages: merged.messages,
+ hasMore: merged.hasMore,
+ lastTimestamp: merged.lastTimestamp,
+ };
+ if (refresh) update.scrollToView = 'msg-bottom';
+ this.setData(update);
+ } catch (e) {
+ console.warn('[客服] 历史消息加载失败', e);
+ if (!refresh) {
+ wx.showToast({ title: '加载历史消息失败', icon: 'none' });
+ }
+ } finally {
+ this.setData({ loadingHistory: false });
+ }
},
createWelcomeMessage() {
@@ -238,8 +337,11 @@ Page({
timestamp: Date.now(),
senderId: 'system',
receiverId: this.data.currentUser?.id,
- senderData: { name: '系统消息', avatar: '' },
- payload: { text: '你好,请问有什么可以帮到您的?' },
+ senderData: {
+ name: this.data.teamName || '客服',
+ avatar: resolveAvatarUrl(this.data.teamAvatar, app) || this.data.defaultAvatarUrl,
+ },
+ payload: { text: this.data.welcomeText || '你好,请问有什么可以帮到您的?' },
status: 'success',
read: false,
formattedTime: formatDate(Date.now()),
@@ -255,7 +357,10 @@ Page({
if (msg.senderId === this.data.currentUser.id) return;
msg = this.normalizeMessage(msg);
msg.formattedTime = formatDate(msg.timestamp);
- msg.senderData = { name: this.data.teamName, avatar: this.data.teamAvatar };
+ msg.senderData = {
+ name: this.data.teamName,
+ avatar: resolveAvatarUrl(this.data.teamAvatar, app) || this.data.defaultAvatarUrl,
+ };
const msgs = this.data.messages;
const last = msgs.length ? msgs[msgs.length-1] : null;
msg.showTime = last ? (msg.timestamp - last.timestamp) / 60000 > 5 : true;
@@ -370,11 +475,53 @@ Page({
});
wx.goEasy.im.sendMessage({
message:msg,
- onSuccess:() => this.updateMsg(id, 'success'),
+ onSuccess:() => {
+ this.updateMsg(id, 'success');
+ this.tryAutoReply(text);
+ },
onFailed:() => this.updateMsg(id, 'failed')
});
},
+ async tryAutoReply(userText) {
+ try {
+ const result = await matchAutoReply(userText);
+ if (result && result.matched && result.content) {
+ this.insertCsAutoReply(result);
+ }
+ } catch (e) {
+ console.warn('tryAutoReply failed', e);
+ }
+ },
+
+ insertCsAutoReply(result) {
+ const replyType = (result && result.reply_type) || 'text';
+ const content = (result && result.content) || '';
+ if (!content) return;
+ const isImage = replyType === 'image';
+ const msg = {
+ messageId: 'auto-reply-' + Date.now(),
+ type: isImage ? 'image' : 'text',
+ timestamp: Date.now(),
+ senderId: this.data.teamId,
+ receiverId: this.data.currentUser?.id,
+ senderData: {
+ name: this.data.teamName,
+ avatar: resolveAvatarUrl(this.data.teamAvatar, app) || this.data.defaultAvatarUrl,
+ },
+ payload: isImage ? { url: content } : { text: content },
+ status: 'success',
+ read: false,
+ formattedTime: formatDate(Date.now()),
+ showTime: this.needShow(Date.now()),
+ };
+ if (isImage) msg.imageUrl = content;
+ this.setData({
+ messages: [...this.data.messages, msg],
+ scrollToView: 'msg-bottom',
+ });
+ },
+
sendImageMsg(filePath, fileObj) {
const { currentUser, teamId, teamName, teamAvatar } = this.data;
if (!teamId || !currentUser || !filePath) return;
@@ -521,9 +668,30 @@ Page({
onKeyboardHeightChange(e) { this.setData({ keyboardHeight: e.detail.height }); },
+ onTeamAvatarError() {
+ this.setData({ teamAvatar: getDefaultAvatarUrl(app) });
+ },
+
+ onSelfAvatarError() {
+ const def = getDefaultAvatarUrl(app);
+ const cu = this.data.currentUser;
+ if (cu) {
+ this.setData({ currentUser: { ...cu, avatar: def } });
+ }
+ },
+
onPullDownRefresh() {
if (this.data.loadingHistory) return;
+ if (!this.data.hasMore) {
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ return;
+ }
this.setData({ isRefreshing: true });
- this.loadHistory(false).finally(() => { this.setData({ isRefreshing: false }); wx.stopPullDownRefresh(); });
+ this.loadHistory(false).finally(() => {
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ });
}
});
\ No newline at end of file
diff --git a/pages/cs-chat/cs-chat.wxml b/pages/cs-chat/cs-chat.wxml
index 723917b..bc8bc09 100644
--- a/pages/cs-chat/cs-chat.wxml
+++ b/pages/cs-chat/cs-chat.wxml
@@ -11,7 +11,7 @@
{{item.formattedTime}}
-
+
订单号:{{item.payload.dingdan_id || '无'}}
服务:{{item.payload.jieshao || ''}}
- ¥{{item.payload.jine}}
+ ¥{{item.payload.jine}}
{{item.payload.text || '[未知消息]'}}
-
+
-
+
diff --git a/pages/dashou-exam/dashou-exam.js b/pages/dashou-exam/dashou-exam.js
new file mode 100644
index 0000000..4332310
--- /dev/null
+++ b/pages/dashou-exam/dashou-exam.js
@@ -0,0 +1,283 @@
+import { createPage, request } from '../../utils/base-page.js';
+import { refreshDashouMembership } from '../../utils/dashou-profile.js';
+import { isApiSuccess, getApiMsg } from '../../utils/api-helper.js';
+
+const LABELS = ['A', 'B', 'C', 'D', 'E', 'F'];
+
+function toSlotNum(slot) {
+ const n = Number(slot);
+ return Number.isFinite(n) ? n : slot;
+}
+
+function normalizeSlots(slots) {
+ return (slots || []).map(toSlotNum);
+}
+
+function slotsEqual(a, b) {
+ const sa = normalizeSlots(a).sort((x, y) => x - y);
+ const sb = normalizeSlots(b).sort((x, y) => x - y);
+ return sa.length === sb.length && sa.every((v, i) => v == sb[i]);
+}
+
+function shuffle(arr) {
+ const a = [...arr];
+ for (let i = a.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [a[i], a[j]] = [a[j], a[i]];
+ }
+ return a;
+}
+
+Page(createPage({
+ data: {
+ loading: true,
+ alreadyPassed: false,
+ finished: false,
+ blocked: false,
+ blockTitle: '',
+ blockReason: '',
+ needRecharge: false,
+ questions: [],
+ currentIndex: 0,
+ currentQuestion: null,
+ questionType: 1,
+ total: 0,
+ wrongCount: 0,
+ maxWrong: 0,
+ correctCount: 0,
+ selectedSlots: [],
+ showExplanation: false,
+ },
+
+ onLoad() {
+ this.initExam();
+ },
+
+ showBlocked(title, reason, needRecharge = false) {
+ this.setData({
+ loading: false,
+ blocked: true,
+ blockTitle: title,
+ blockReason: reason,
+ needRecharge: !!needRecharge,
+ });
+ },
+
+ /** 进入页先查 status:不满足条件留在本页提示,不自动退出 */
+ async initExam() {
+ this.setData({ loading: true, blocked: false, needRecharge: false });
+ try {
+ await refreshDashouMembership(getApp());
+ const res = await request({ url: '/jituan/dashou-exam/status', method: 'POST' });
+ const body = res?.data;
+ if (!isApiSuccess(body)) {
+ this.showBlocked('无法开始考试', getApiMsg(body) || '无法获取考试状态,请稍后重试');
+ return;
+ }
+ const d = body.data || {};
+ if (!d.exam_enabled) {
+ this.showBlocked(
+ '未开启考试',
+ '本俱乐部尚未开启接单考试。若后台已开启,请确认配置的是当前小程序对应俱乐部。'
+ );
+ return;
+ }
+ if (d.exam_passed) {
+ this.setData({ loading: false, alreadyPassed: true });
+ return;
+ }
+ const cfg = d.config || {};
+ if (cfg.require_member && !d.has_member) {
+ this.showBlocked('须先开通会员', '本俱乐部要求开通会员后才能参加考试', true);
+ return;
+ }
+ if ((d.pool_count || 0) < 1) {
+ this.showBlocked(
+ '暂无可用考题',
+ '考试已开启,但题库没有「已上架」的题目。请在后台确认题目已上架,且每题至少两个选项并标记正确答案。'
+ );
+ return;
+ }
+ await this.loadBundle();
+ } catch (e) {
+ this.showBlocked('网络错误', '请检查网络后下拉重新进入本页');
+ }
+ },
+
+ async loadBundle() {
+ this.setData({ loading: true, finished: false, showExplanation: false, blocked: false });
+ try {
+ const res = await request({ url: '/jituan/dashou-exam/bundle', method: 'POST' });
+ const body = res?.data;
+ if (!isApiSuccess(body)) {
+ this.showBlocked('加载考题失败', getApiMsg(body) || '请稍后重试或联系管理员');
+ return;
+ }
+ const d = body.data || {};
+ if (d.already_passed) {
+ this.setData({ alreadyPassed: true, loading: false });
+ return;
+ }
+ const cfg = d.config || {};
+ const prepared = (d.questions || []).map((q) => this.prepareQuestion(q)).filter((q) => (q.displayOptions || []).length > 0);
+ if (!prepared.length) {
+ this.showBlocked(
+ '题目配置不完整',
+ '已抽到的题目缺少有效选项,请在后台检查题目是否至少两个选项并标记正确答案。'
+ );
+ return;
+ }
+ this.setData({
+ loading: false,
+ questions: prepared,
+ total: prepared.length,
+ currentIndex: 0,
+ wrongCount: 0,
+ correctCount: 0,
+ maxWrong: cfg.max_wrong || 0,
+ currentQuestion: prepared[0],
+ questionType: prepared[0].question_type || 1,
+ selectedSlots: [],
+ });
+ } catch (e) {
+ this.showBlocked('网络错误', '拉取考题失败,请稍后重试');
+ }
+ },
+
+ prepareQuestion(q) {
+ const oss = getApp().globalData.ossImageUrl || '';
+ const displayImages = (q.images || []).map((u) => (u.startsWith('http') ? u : oss + u));
+ const shuffled = shuffle(q.options || []).map((opt, idx) => ({
+ slot: toSlotNum(opt.slot),
+ text: opt.text,
+ label: LABELS[idx] || String(idx + 1),
+ selected: false,
+ }));
+ return {
+ ...q,
+ question_type: Number(q.question_type) || 1,
+ displayImages,
+ displayOptions: shuffled,
+ correctSlots: normalizeSlots(q.correct_slots || []),
+ };
+ },
+
+ applySelectedToOptions(selectedSlots) {
+ const q = this.data.currentQuestion;
+ if (!q) return;
+ const set = normalizeSlots(selectedSlots);
+ const displayOptions = (q.displayOptions || []).map((opt) => ({
+ ...opt,
+ selected: set.some((s) => s == opt.slot),
+ }));
+ this.setData({
+ selectedSlots: set,
+ currentQuestion: { ...q, displayOptions },
+ });
+ },
+
+ onSelectOption(e) {
+ const slot = toSlotNum(e.currentTarget.dataset.slot);
+ const q = this.data.currentQuestion;
+ if (!q || slot === undefined || slot === null || slot === '') return;
+ if (q.question_type === 2) {
+ const set = [...this.data.selectedSlots];
+ const i = set.findIndex((s) => s == slot);
+ if (i >= 0) set.splice(i, 1);
+ else set.push(slot);
+ if (this.data.showExplanation) {
+ this.setData({ showExplanation: false });
+ }
+ this.applySelectedToOptions(set);
+ return;
+ }
+ this.applySelectedToOptions([slot]);
+ if (this.data.showExplanation) {
+ this.setData({ showExplanation: false });
+ }
+ setTimeout(() => this.gradeAnswer([slot]), 120);
+ },
+
+ confirmMulti() {
+ if (this.data.showExplanation) {
+ this.setData({ showExplanation: false });
+ this.applySelectedToOptions([]);
+ return;
+ }
+ if (!this.data.selectedSlots.length) {
+ wx.showToast({ title: '请选择答案', icon: 'none' });
+ return;
+ }
+ this.gradeAnswer([...this.data.selectedSlots]);
+ },
+
+ /** 前端本地判分(bundle 已含正确答案与解析) */
+ gradeAnswer(selected) {
+ const q = this.data.currentQuestion;
+ const correct = q.correctSlots || [];
+ const isRight = slotsEqual(selected, correct);
+
+ if (!isRight) {
+ const wrongCount = this.data.wrongCount + 1;
+ this.setData({ wrongCount, showExplanation: true });
+ if (wrongCount > this.data.maxWrong) {
+ wx.showModal({
+ title: '答题失败',
+ content: `${q.explanation || '本题答错了'}。错题过多,将重新开始本轮考试。`,
+ showCancel: false,
+ success: () => this.loadBundle(),
+ });
+ } else {
+ wx.showToast({ title: '答错了,请查看解析', icon: 'none' });
+ }
+ return;
+ }
+
+ const correctCount = this.data.correctCount + 1;
+ const next = this.data.currentIndex + 1;
+ if (next >= this.data.total) {
+ this.submitPassed(correctCount);
+ return;
+ }
+ const nextQ = this.data.questions[next];
+ this.setData({
+ correctCount,
+ currentIndex: next,
+ currentQuestion: nextQ,
+ questionType: nextQ.question_type,
+ selectedSlots: [],
+ showExplanation: false,
+ });
+ },
+
+ async submitPassed(correctCount) {
+ try {
+ const res = await request({ url: '/jituan/dashou-exam/mark-passed', method: 'POST' });
+ const body = res?.data;
+ if (isApiSuccess(body)) {
+ this.setData({ finished: true, correctCount });
+ } else {
+ wx.showToast({ title: getApiMsg(body) || '提交失败', icon: 'none' });
+ }
+ } catch (e) {
+ wx.showToast({ title: '提交失败', icon: 'none' });
+ }
+ },
+
+ goRecharge() {
+ wx.navigateTo({ url: '/pages/fighter-recharge/fighter-recharge' });
+ },
+
+ retryInit() {
+ this.initExam();
+ },
+
+ goBack() {
+ const pages = getCurrentPages();
+ if (pages.length > 1) {
+ wx.navigateBack();
+ } else {
+ wx.switchTab({ url: '/pages/accept-order/accept-order' });
+ }
+ },
+}));
diff --git a/pages/dashou-exam/dashou-exam.json b/pages/dashou-exam/dashou-exam.json
new file mode 100644
index 0000000..26876a8
--- /dev/null
+++ b/pages/dashou-exam/dashou-exam.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "接单考试",
+ "navigationBarBackgroundColor": "#c4b5fd",
+ "navigationBarTextStyle": "black"
+}
diff --git a/pages/dashou-exam/dashou-exam.wxml b/pages/dashou-exam/dashou-exam.wxml
new file mode 100644
index 0000000..6a36f55
--- /dev/null
+++ b/pages/dashou-exam/dashou-exam.wxml
@@ -0,0 +1,66 @@
+
+ 正在检查考试资格...
+
+
+ {{blockTitle}}
+ {{blockReason}}
+
+ 去开通会员
+ 重试
+ 返回
+
+
+
+
+ 已通过考试
+ 无需重复考试,可直接抢单
+ 返回
+
+
+
+ 考试通过
+ 恭喜通过,现在可以去抢单了
+ 去抢单
+
+
+
+
+ 第 {{currentIndex + 1}} / {{total}} 题
+ 已错 {{wrongCount}} 题 · 最多可错 {{maxWrong}} 题
+
+ {{questionType === 2 ? '多选题' : '单选题'}}
+ {{currentQuestion.stem}}
+
+
+
+
+
+
+
+
+
+
+
+ {{item.label}}
+ {{item.text}}
+
+
+
+
+
+ 解析
+ {{currentQuestion.explanation || '暂无解析'}}
+
+
+
+
+
+
diff --git a/pages/dashou-exam/dashou-exam.wxss b/pages/dashou-exam/dashou-exam.wxss
new file mode 100644
index 0000000..8227bc8
--- /dev/null
+++ b/pages/dashou-exam/dashou-exam.wxss
@@ -0,0 +1,228 @@
+.exam-page {
+ min-height: 100vh;
+ background: linear-gradient(180deg, #f5f3ff 0%, #fff3d6 100%);
+ padding: 24rpx;
+ padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
+ box-sizing: border-box;
+}
+
+.center-tip,
+.center-box {
+ padding: 80rpx 40rpx;
+ text-align: center;
+}
+
+.tip-title {
+ font-size: 36rpx;
+ font-weight: 600;
+ display: block;
+ margin-bottom: 16rpx;
+ color: #333;
+}
+
+.tip-desc {
+ font-size: 28rpx;
+ color: #666;
+ display: block;
+ margin-bottom: 32rpx;
+ line-height: 1.6;
+}
+
+.btn-primary {
+ background: linear-gradient(90deg, #c4b5fd, #a78bfa);
+ padding: 22rpx 48rpx;
+ border-radius: 48rpx;
+ font-weight: 600;
+ font-size: 30rpx;
+ color: #6d28d9;
+ text-align: center;
+}
+
+.btn-primary.block {
+ display: block;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.btn-row {
+ display: flex;
+ flex-direction: column;
+ gap: 20rpx;
+ margin-top: 24rpx;
+}
+
+.btn-outline {
+ padding: 20rpx 48rpx;
+ border-radius: 48rpx;
+ border: 2rpx solid #ddd;
+ color: #666;
+ font-size: 28rpx;
+ text-align: center;
+ background: #fff;
+}
+
+.btn-outline.block {
+ display: block;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.exam-body {
+ display: flex;
+ flex-direction: column;
+ min-height: calc(100vh - 48rpx);
+}
+
+.exam-card {
+ flex: 1;
+ background: #fff;
+ border-radius: 24rpx;
+ padding: 28rpx;
+ box-shadow: 0 8rpx 32rpx rgba(73, 47, 0, 0.06);
+}
+
+.progress {
+ font-size: 28rpx;
+ color: #6d28d9;
+ font-weight: 600;
+}
+
+.progress-sub {
+ font-size: 24rpx;
+ color: #999;
+ margin-top: 8rpx;
+ margin-bottom: 24rpx;
+}
+
+.q-type-tag {
+ display: inline-block;
+ font-size: 22rpx;
+ color: #b8860b;
+ background: #f5f3ff;
+ border: 1rpx solid #c4b5fd;
+ border-radius: 8rpx;
+ padding: 4rpx 16rpx;
+ margin-bottom: 16rpx;
+}
+
+.q-stem {
+ font-size: 32rpx;
+ font-weight: 600;
+ line-height: 1.6;
+ margin-bottom: 24rpx;
+ color: #222;
+}
+
+.q-images {
+ margin-bottom: 24rpx;
+}
+
+.q-img {
+ width: 100%;
+ border-radius: 12rpx;
+ margin-bottom: 12rpx;
+}
+
+.options {
+ margin-top: 8rpx;
+}
+
+.opt-item {
+ background: #fafafa;
+ border: 2rpx solid #eee;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 16rpx;
+ display: flex;
+ align-items: flex-start;
+ gap: 20rpx;
+}
+
+.opt-active {
+ border-color: #c4b5fd;
+ background: #fffdf0;
+}
+
+.opt-radio {
+ width: 36rpx;
+ height: 36rpx;
+ border-radius: 50%;
+ border: 2rpx solid #ccc;
+ flex-shrink: 0;
+ margin-top: 4rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+}
+
+.opt-radio-on {
+ border-color: #c4b5fd;
+ background: #f5f3ff;
+}
+
+.opt-radio-dot {
+ width: 18rpx;
+ height: 18rpx;
+ border-radius: 50%;
+ background: #c4b5fd;
+}
+
+.opt-body {
+ flex: 1;
+ display: flex;
+ gap: 12rpx;
+ align-items: flex-start;
+}
+
+.opt-label {
+ font-weight: 700;
+ color: #6d28d9;
+ min-width: 40rpx;
+ font-size: 28rpx;
+}
+
+.opt-text {
+ flex: 1;
+ font-size: 28rpx;
+ line-height: 1.5;
+ color: #333;
+}
+
+.explain-box {
+ background: #fffbf0;
+ border-left: 6rpx solid #e6a23c;
+ padding: 20rpx 24rpx;
+ margin-top: 24rpx;
+ border-radius: 0 12rpx 12rpx 0;
+}
+
+.explain-title {
+ font-weight: 600;
+ color: #333;
+ display: block;
+ margin-bottom: 8rpx;
+ font-size: 28rpx;
+}
+
+.explain-text {
+ font-size: 26rpx;
+ color: #666;
+ line-height: 1.6;
+}
+
+.foot-actions {
+ margin-top: 24rpx;
+ padding: 0 8rpx;
+}
+
+.foot-btn {
+ width: 100%;
+ box-sizing: border-box;
+ min-height: 88rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1.2;
+ padding: 0 32rpx;
+}
diff --git a/pages/dashouduan/dashouduan.js b/pages/dashouduan/dashouduan.js
new file mode 100644
index 0000000..395bbe5
--- /dev/null
+++ b/pages/dashouduan/dashouduan.js
@@ -0,0 +1,14 @@
+/** 旧二维码兼容:dashouduan → 打手中心,inviteCode 自动注册逻辑不变 */
+import { parseSceneOptions } from '../../utils/base-page.js';
+
+Page({
+ onLoad(options) {
+ const parsed = parseSceneOptions(options || {});
+ const inviteCode = parsed.inviteCode || options.inviteCode || '';
+ let url = '/pages/fighter/fighter';
+ if (inviteCode) {
+ url += `?inviteCode=${encodeURIComponent(inviteCode)}`;
+ }
+ wx.reLaunch({ url });
+ },
+});
diff --git a/pages/dashouduan/dashouduan.json b/pages/dashouduan/dashouduan.json
new file mode 100644
index 0000000..52bc9cd
--- /dev/null
+++ b/pages/dashouduan/dashouduan.json
@@ -0,0 +1 @@
+{ "navigationBarTitleText": "加载中", "usingComponents": {} }
diff --git a/pages/dashouduan/dashouduan.wxml b/pages/dashouduan/dashouduan.wxml
new file mode 100644
index 0000000..3dee721
--- /dev/null
+++ b/pages/dashouduan/dashouduan.wxml
@@ -0,0 +1 @@
+正在进入打手端…
diff --git a/pages/dashouduan/dashouduan.wxss b/pages/dashouduan/dashouduan.wxss
new file mode 100644
index 0000000..8082289
--- /dev/null
+++ b/pages/dashouduan/dashouduan.wxss
@@ -0,0 +1 @@
+.tip { display:flex; align-items:center; justify-content:center; min-height:100vh; color:#999; font-size:28rpx; }
diff --git a/pages/edit/edit.wxss b/pages/edit/edit.wxss
index 8ce2df8..f98b51a 100644
--- a/pages/edit/edit.wxss
+++ b/pages/edit/edit.wxss
@@ -1,6 +1,6 @@
/* pages/edit/edit.wxss */
page {
- background: linear-gradient(135deg, #faf5ff 0%, #f0f8ff 100%);
+ background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%);
min-height: 100vh;
}
diff --git a/pages/express-order/express-order.json b/pages/express-order/express-order.json
index 7682a2b..87bc997 100644
--- a/pages/express-order/express-order.json
+++ b/pages/express-order/express-order.json
@@ -4,7 +4,7 @@
"chenghao-tag": "/components/chenghao-tag/chenghao-tag"
},
"backgroundTextStyle": "dark",
- "navigationBarBackgroundColor": "#fff8e1",
+ "navigationBarBackgroundColor": "#f7dc51",
"navigationBarTitleText": "常规发单",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
diff --git a/pages/express-order/express-order.wxss b/pages/express-order/express-order.wxss
index 8081935..4584d49 100644
--- a/pages/express-order/express-order.wxss
+++ b/pages/express-order/express-order.wxss
@@ -289,7 +289,7 @@ page {
}
.filter-switch.active {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
}
@@ -323,7 +323,7 @@ page {
.copy-link-btn {
padding: 8rpx 20rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
border-radius: 15rpx;
font-size: 22rpx;
@@ -337,7 +337,7 @@ page {
.load-more-btn {
display: inline-block;
padding: 15rpx 40rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
border-radius: 30rpx;
color: #492f00;
font-size: 26rpx;
@@ -373,7 +373,7 @@ page {
.generate-modal-grid-btn,
.copy-modal-grid-btn,
.edit-modal-grid-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
}
@@ -484,7 +484,7 @@ page {
}
.confirm-add-grid-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
}
@@ -538,7 +538,7 @@ page {
}
.confirm-new-link-grid-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
}
@@ -569,7 +569,7 @@ page {
width: 90rpx;
height: 90rpx;
border: 8rpx solid #eee;
- border-top: 8rpx solid #9333ea;
+ border-top: 8rpx solid #ffd061;
border-radius: 50%;
animation: spin 1.2s linear infinite;
margin-bottom: 35rpx;
diff --git a/pages/fighter-edit/fighter-edit.wxss b/pages/fighter-edit/fighter-edit.wxss
index cccfd60..653e8db 100644
--- a/pages/fighter-edit/fighter-edit.wxss
+++ b/pages/fighter-edit/fighter-edit.wxss
@@ -1,7 +1,7 @@
/* 页面容器 */
.container {
min-height: 100vh;
- background: linear-gradient(135deg, #f5f3ff 0%, #e6f7ff 100%);
+ background: linear-gradient(135deg, #fffacd 0%, #e6f7ff 100%);
padding: 20rpx;
box-sizing: border-box;
}
@@ -27,7 +27,7 @@
height: 180rpx;
border-radius: 50%;
border: 6rpx solid #ffffff;
- box-shadow: 0 0 30rpx rgba(196, 181, 253, 0.4);
+ box-shadow: 0 0 30rpx rgba(255, 215, 0, 0.4);
z-index: 2;
position: relative;
background-color: #f5f5f5;
@@ -38,7 +38,7 @@
width: 220rpx;
height: 220rpx;
border-radius: 50%;
- background: radial-gradient(circle, rgba(196, 181, 253, 0.2) 0%, transparent 70%);
+ background: radial-gradient(circle, rgba(255, 215, 0, 0.2) 0%, transparent 70%);
z-index: 1;
animation: halo-pulse 2s infinite ease-in-out;
}
diff --git a/pages/fighter-ledger/fighter-ledger.js b/pages/fighter-ledger/fighter-ledger.js
new file mode 100644
index 0000000..a714e82
--- /dev/null
+++ b/pages/fighter-ledger/fighter-ledger.js
@@ -0,0 +1,139 @@
+import request from '../../utils/request.js';
+import { getOrderStatusText } from '../../utils/api-helper.js';
+
+const PAGE_SIZE = 15;
+
+const TYPE_CONFIG = {
+ commission: { title: '佣金记录', statuses: [3, 8] },
+ settle: { title: '结算记录', statuses: [3] },
+ withdraw: { title: '提现记录', api: 'withdraw' },
+ deduct: { title: '扣款记录', api: 'deduct' },
+};
+
+Page({
+ data: {
+ pageTitle: '交易明细',
+ type: 'commission',
+ statusBar: 20,
+ list: [],
+ page: 1,
+ hasMore: true,
+ loading: false,
+ refreshing: false,
+ },
+
+ onLoad(options) {
+ const sys = wx.getSystemInfoSync();
+ const type = (options.type || 'commission').trim();
+ const cfg = TYPE_CONFIG[type] || TYPE_CONFIG.commission;
+ this.setData({
+ type,
+ pageTitle: cfg.title,
+ statusBar: sys.statusBarHeight || 20,
+ });
+ this.loadList(true);
+ },
+
+ goBack() {
+ wx.navigateBack({ fail: () => wx.switchTab({ url: '/pages/fighter/fighter' }) });
+ },
+
+ onRefresh() {
+ this.setData({ refreshing: true });
+ this.loadList(true).finally(() => this.setData({ refreshing: false }));
+ },
+
+ onLoadMore() {
+ if (this.data.hasMore && !this.data.loading) {
+ this.loadList(false);
+ }
+ },
+
+ async loadList(refresh) {
+ const { type, loading } = this.data;
+ if (loading) return;
+ const page = refresh ? 1 : this.data.page;
+ this.setData({ loading: true });
+ try {
+ let rows = [];
+ let hasMore = false;
+ if (type === 'withdraw') {
+ const res = await request({
+ url: '/yonghu/tixianjiluhq',
+ method: 'POST',
+ data: { page, limit: PAGE_SIZE },
+ });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0)) {
+ const raw = body.data?.list || [];
+ rows = raw.map((item, idx) => ({
+ id: item.id || item.jilu_id || `${page}-${idx}`,
+ title: item.beizhu || item.status_text || item.zhuangtai_text || '提现',
+ time: item.creat_time || item.create_time || item.tijiao_shijian || '',
+ amount: `-¥${item.jine || item.amount || item.tixian_jine || '0.00'}`,
+ minus: true,
+ }));
+ hasMore = raw.length >= PAGE_SIZE;
+ }
+ } else if (type === 'deduct') {
+ const res = await request({
+ url: '/yonghu/dsfklbhq',
+ method: 'POST',
+ data: { page, page_size: PAGE_SIZE, zhuangtai: 0 },
+ });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0)) {
+ const raw = body.data?.list || [];
+ rows = raw.map((item, idx) => ({
+ id: item.fadan_id || item.id || `${page}-${idx}`,
+ title: item.yuanyin || item.beizhu || item.fakuan_yuanyin || '扣款',
+ time: item.creat_time || item.create_time || '',
+ amount: `-¥${item.jine || item.fakuan_jine || item.fakuanjine || '0.00'}`,
+ minus: true,
+ }));
+ hasMore = raw.length >= PAGE_SIZE;
+ }
+ } else {
+ const cfg = TYPE_CONFIG[type] || TYPE_CONFIG.commission;
+ const res = await request({
+ url: '/dingdan/dshqdingdan',
+ method: 'POST',
+ data: {
+ zhuangtai_list: cfg.statuses,
+ page,
+ page_size: PAGE_SIZE,
+ },
+ });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0)) {
+ const raw = body.data?.list || [];
+ rows = raw.map((item) => {
+ const amt = item.jine || item.dashou_fencheng || '0.00';
+ const brief = (item.jieshao || '').trim();
+ const title = brief
+ ? (brief.length > 18 ? `${brief.slice(0, 18)}…` : brief)
+ : `订单 ${item.dingdan_id || ''}`;
+ return {
+ id: item.dingdan_id,
+ title,
+ time: item.wancheng_shijian || item.jiesuan_shijian || item.creat_time || getOrderStatusText(item.zhuangtai),
+ amount: `+¥${amt}`,
+ minus: false,
+ };
+ });
+ hasMore = body.data?.has_more ?? raw.length >= PAGE_SIZE;
+ }
+ }
+ const list = refresh ? rows : [...this.data.list, ...rows];
+ this.setData({
+ list,
+ page: refresh ? 2 : page + 1,
+ hasMore,
+ });
+ } catch (e) {
+ console.error('ledger load fail', e);
+ } finally {
+ this.setData({ loading: false });
+ }
+ },
+});
diff --git a/pages/fighter-ledger/fighter-ledger.json b/pages/fighter-ledger/fighter-ledger.json
new file mode 100644
index 0000000..b16ef3e
--- /dev/null
+++ b/pages/fighter-ledger/fighter-ledger.json
@@ -0,0 +1,4 @@
+{
+ "navigationStyle": "custom",
+ "usingComponents": {}
+}
diff --git a/pages/fighter-ledger/fighter-ledger.wxml b/pages/fighter-ledger/fighter-ledger.wxml
new file mode 100644
index 0000000..b7513d1
--- /dev/null
+++ b/pages/fighter-ledger/fighter-ledger.wxml
@@ -0,0 +1,20 @@
+
+
+
+ ‹
+ {{pageTitle}}
+
+
+
+ 加载中...
+ 暂无记录
+
+
+ {{item.title}}
+ {{item.time}}
+
+ {{item.amount}}
+
+ — 已加载全部 —
+
+
diff --git a/pages/fighter-ledger/fighter-ledger.wxss b/pages/fighter-ledger/fighter-ledger.wxss
new file mode 100644
index 0000000..ece738c
--- /dev/null
+++ b/pages/fighter-ledger/fighter-ledger.wxss
@@ -0,0 +1,75 @@
+@import '../../styles/xym-layout.wxss';
+
+.ledger-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ display: flex;
+ flex-direction: column;
+}
+
+.nav-bar {
+ padding: 0 24rpx 16rpx;
+}
+
+.back {
+ width: 60rpx;
+ font-size: 48rpx;
+ color: #333;
+ line-height: 1;
+}
+
+.back.placeholder {
+ visibility: hidden;
+}
+
+.nav-title {
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #222;
+}
+
+.ledger-scroll {
+ flex: 1;
+ height: 0;
+ padding: 0 24rpx;
+ box-sizing: border-box;
+}
+
+.list-item {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 16rpx;
+}
+
+.row-t {
+ font-size: 28rpx;
+ color: #222;
+ font-weight: 600;
+}
+
+.row-d {
+ font-size: 24rpx;
+ color: #999;
+ margin-top: 8rpx;
+}
+
+.row-r {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #492f00;
+ flex-shrink: 0;
+ margin-left: 16rpx;
+}
+
+.row-r.minus {
+ color: #ff4c45;
+}
+
+.empty-box,
+.load-tip {
+ text-align: center;
+ color: #999;
+ font-size: 26rpx;
+ padding: 80rpx 0;
+}
diff --git a/pages/fighter-msg/fighter-msg.js b/pages/fighter-msg/fighter-msg.js
index 8088f2f..22ab72f 100644
--- a/pages/fighter-msg/fighter-msg.js
+++ b/pages/fighter-msg/fighter-msg.js
@@ -1,684 +1,684 @@
-// pages/penalty/penalty.js
-import request from '../../utils/request.js'
-const app = getApp()
-const MEIYE_TIAOSHU = 5
-
-Page({
- data: {
- zongshu: 0,
- daichuli: 0,
- yichuli: 0,
- shenfen: 0,
- chufaList: [],
- dangqianye: 1,
- haiyougengduo: true,
- jiazhaozhong: false,
- jiazhaigengduo: false,
- scrollHeight: 0,
- showXiangqing: false,
- xuanzhongChufa: {},
- showShensuModal: false,
- shensuLiyou: '',
- shensuTupian: [],
- shensuTupianUrls: [],
- shangchuanJindu: 0,
- shangchuanZongshu: 0,
- jinduWidth: '0%',
- isShangchuanzhong: false,
- ossImageUrl: '',
- fangdouTimer: null
- },
-
- onLoad(options) {
- this.registerNotificationComponent()
- this.initOSSUrl()
- this.jisuanGaodu()
- this.chushihuaShuju()
- },
-
-
-
-
-
-
-
- onShow() {
- this.registerNotificationComponent()
- },
-
- onUnload() {
- if (this.data.fangdouTimer) clearTimeout(this.data.fangdouTimer)
- },
-
- onReachBottom() {
- this.shanglaShuaxin()
- },
-
- registerNotificationComponent() {
- const notificationComp = this.selectComponent('#global-notification')
- if (notificationComp && notificationComp.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- }
- }
- },
-
- initOSSUrl() {
- const ossImageUrl = app.globalData.ossImageUrl || ''
- this.setData({ ossImageUrl })
- },
-
- jisuanGaodu() {
- const systemInfo = wx.getSystemInfoSync()
- const windowHeight = systemInfo.windowHeight
- const height = windowHeight - 200 - 100 - 40
- this.setData({
- scrollHeight: height > 0 ? height : 400
- })
- },
-
- chushihuaShuju() {
- this.setData({
- dangqianye: 1,
- chufaList: [],
- haiyougengduo: true
- })
- this.jiazhuoquTongji()
- this.jiazhuoquChufaList()
- },
-
- async jiazhuoquTongji() {
- try {
- const res = await request({
- url: '/yonghu/dshqcfjl',
- method: 'POST',
- data: { qingqiu_tongji: true }
- })
- if (res.statusCode === 200 && res.data.code === 0) {
- const data = res.data.data
- this.setData({
- zongshu: data.zongshu || 0,
- daichuli: data.daichuli || 0,
- yichuli: data.yichuli || 0
- })
- }
- } catch (error) {
- console.error('获取统计信息失败:', error)
- }
- },
-
- async jiazhuoquChufaList(isLoadMore = false) {
- if (this.data.jiazhaozhong || this.data.jiazhaigengduo) return
- if (isLoadMore) {
- if (!this.data.haiyougengduo) return
- this.setData({ jiazhaigengduo: true })
- } else {
- this.setData({ jiazhaozhong: true })
- }
-
- try {
- const params = {
- page: this.data.dangqianye,
- page_size: MEIYE_TIAOSHU
- }
- if (this.data.shenfen === 0) {
- params.zhuangtai = 0
- } else {
- params.zhuangtai = 1
- }
-
- const res = await request({
- url: '/yonghu/dshqcfjl',
- method: 'POST',
- data: params
- })
-
- //console.log('🔴【后端返回的数据】:', res.data)
-
- if (res.statusCode === 200 && res.data.code === 0) {
- const data = res.data.data
-
- if (data.list && Array.isArray(data.list)) {
- // 🔴【关键修复】在数据加载时就处理好显示字段
- const processedList = data.list.map(item => {
- // 处理显示时间
- let displayTime = '--'
- if (item.create_time) {
- if (typeof item.create_time === 'number') {
- displayTime = String(item.create_time)
- } else if (typeof item.create_time === 'string') {
- displayTime = item.create_time
- } else {
- displayTime = String(item.create_time)
- }
- }
-
- // 处理显示状态
- let displayStatus = '未知状态'
- let statusClass = 'zhuangtai-weizhi'
- const statusNum = Number(item.sqzhuangtai)
-
- if (!isNaN(statusNum)) {
- if (statusNum === 0) {
- displayStatus = '待处罚'
- statusClass = 'zhuangtai-daichuli'
- } else if (statusNum === 1) {
- displayStatus = '已处罚'
- statusClass = 'zhuangtai-yichufa'
- } else if (statusNum === 2) {
- displayStatus = '已驳回'
- statusClass = 'zhuangtai-yibohui'
- } else if (statusNum === 3) {
- displayStatus = '申诉中'
- statusClass = 'zhuangtai-shensuzhong'
- }
- }
-
- // 处理图片URL(在数据加载时就拼接完整URL)
- const fullZhengjuTupian = (item.zhengju_tupian || []).map(url => this.getFullImageUrl(url))
- const fullShensuTupian = (item.shensu_tupian || []).map(url => this.getFullImageUrl(url))
-
- return {
- ...item,
- display_time: displayTime, // 🔴 处理好的显示时间
- display_status: displayStatus, // 🔴 处理好的显示状态
- status_class: statusClass, // 🔴 处理好的状态样式类
- zhengju_tupian: item.zhengju_tupian || [],
- shensu_tupian: item.shensu_tupian || [],
- full_zhengju_tupian: fullZhengjuTupian, // 🔴 完整图片URL
- full_shensu_tupian: fullShensuTupian // 🔴 完整图片URL
- }
- })
-
- //console.log('🔴【处理后的数据】:', processedList)
-
- let newList
- if (isLoadMore) {
- newList = [...this.data.chufaList, ...processedList]
- } else {
- newList = processedList
- }
-
- const hasMore = data.has_more === true
- this.setData({
- chufaList: newList,
- haiyougengduo: hasMore,
- dangqianye: this.data.dangqianye + 1
- })
- } else {
- this.setData({ haiyougengduo: false })
- }
- } else {
- throw new Error(res.data?.msg || '加载处罚记录失败')
- }
- } catch (error) {
- console.error('加载处罚记录失败:', error)
- wx.showToast({
- title: error.message || '加载失败',
- icon: 'none'
- })
- this.setData({ haiyougengduo: false })
- } finally {
- if (isLoadMore) {
- this.setData({ jiazhaigengduo: false })
- } else {
- this.setData({ jiazhaozhong: false })
- }
- }
- },
-
- qiehuanShenfen(e) {
- const type = parseInt(e.currentTarget.dataset.type)
- if (this.data.shenfen === type) return
- this.setData({
- shenfen: type,
- dangqianye: 1,
- chufaList: [],
- haiyougengduo: true
- })
- this.jiazhuoquChufaList()
- },
-
- shanglaShuaxin() {
- if (this.data.fangdouTimer) clearTimeout(this.data.fangdouTimer)
- const timer = setTimeout(() => {
- if (this.data.jiazhaozhong || this.data.jiazhaigengduo) return
- if (!this.data.haiyougengduo) return
- this.jiazhuoquChufaList(true)
- }, 300)
- this.setData({ fangdouTimer: timer })
- },
-
- chakanXiangqing(e) {
- const item = e.currentTarget.dataset.item
- this.setData({
- xuanzhongChufa: item,
- showXiangqing: true
- })
- },
-
- guanbiXiangqing() {
- this.setData({
- showXiangqing: false,
- xuanzhongChufa: {}
- })
- },
-
- openShensuModal() {
- if (this.data.xuanzhongChufa.ssliyou ||
- (this.data.xuanzhongChufa.shensu_tupian && this.data.xuanzhongChufa.shensu_tupian.length > 0)) {
- wx.showToast({
- title: '您已经提交过申诉,请等待处理结果',
- icon: 'none'
- })
- return
- }
- this.setData({
- showShensuModal: true,
- shensuLiyou: '',
- shensuTupian: [],
- shensuTupianUrls: [],
- shangchuanJindu: 0,
- shangchuanZongshu: 0,
- jinduWidth: '0%'
- })
- },
-
- closeShensuModal() {
- this.setData({
- showShensuModal: false,
- shensuLiyou: '',
- shensuTupian: [],
- shensuTupianUrls: []
- })
- },
-
- onShensuLiyouInput(e) {
- const value = e.detail.value.slice(0, 500)
- this.setData({ shensuLiyou: value })
- },
-
- chooseShensuTupian() {
- if (this.data.isShangchuanzhong) return
- const shengyu = 9 - this.data.shensuTupian.length
- if (shengyu <= 0) {
- wx.showToast({
- title: '最多只能上传9张图片',
- icon: 'none'
- })
- return
- }
- wx.chooseMedia({
- count: shengyu,
- mediaType: ['image'],
- sourceType: ['album', 'camera'],
- success: (res) => {
- const newTupian = [...this.data.shensuTupian, ...res.tempFiles.map(file => file.tempFilePath)]
- this.setData({ shensuTupian: newTupian.slice(0, 9) })
- }
- })
- },
-
- deleteShensuTupian(e) {
- const index = e.currentTarget.dataset.index
- const newTupian = [...this.data.shensuTupian]
- newTupian.splice(index, 1)
- this.setData({ shensuTupian: newTupian })
- },
-
- yulanShensuTupian(e) {
- const index = e.currentTarget.dataset.index
- const urls = this.data.shensuTupian
- if (!urls[index]) return
- wx.previewImage({
- current: urls[index],
- urls: urls
- })
- },
-
- lianxiKefu() {
- 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'
- });
- }
- });
- },
-
- async getCOSZhengshu() {
- try {
- const res = await request({
- url: '/dingdan/dsscpz',
- method: 'POST',
- data: {
- dingdan_id: this.data.xuanzhongChufa.dingdan_id,
- yongtu: 'chufa'
- }
- })
- if (res.statusCode === 200 && res.data.code === 0 && res.data.data) {
- return res.data.data
- } else {
- throw new Error(res?.data?.msg || '获取上传凭证失败')
- }
- } catch (error) {
- console.error('获取COS凭证失败:', error)
- throw error
- }
- },
-
- initCOSClient(tokenData) {
- const COS = require('../../utils/cos-wx-sdk-v5.js')
- const credentials = tokenData.credentials || tokenData
- const bucket = tokenData.bucket || 'julebu-1361527063'
- const region = tokenData.region || 'ap-shanghai'
- const cos = new COS({
- SimpleUploadMethod: 'putObject',
- getAuthorization: async (options, callback) => {
- const authParams = {
- TmpSecretId: credentials.tmpSecretId,
- TmpSecretKey: credentials.tmpSecretKey,
- SecurityToken: credentials.sessionToken || '',
- StartTime: tokenData.startTime || Math.floor(Date.now() / 1000),
- ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200)
- }
- callback(authParams)
- }
- })
- return { cos, bucket, region }
- },
-
- async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) {
- return new Promise((resolve) => {
- const timeoutId = setTimeout(() => {
- resolve({ status: 'optimistic_success', key: cosKey })
- }, 2000)
- cosInstance.uploadFile({
- Bucket: bucket,
- Region: region,
- Key: cosKey,
- FilePath: filePath,
- onProgress: (progressInfo) => {
- const percent = Math.round(progressInfo.percent * 100)
- if (percent === 100) {
- clearTimeout(timeoutId)
- resolve({ status: 'optimistic_success', key: cosKey })
- }
- }
- })
- })
- },
-
- async piliangShangchuanShensuTupian() {
- const total = this.data.shensuTupian.length
- if (total === 0) return []
- this.setData({
- shangchuanZongshu: total,
- shangchuanJindu: 0,
- jinduWidth: '0%',
- isShangchuanzhong: true
- })
- let yonghuid = ''
-
- // 方案1:直接从全局缓存获取
- const uid = wx.getStorageSync('uid')
- if (uid) {
- yonghuid = String(uid).padStart(7, '0')
- //console.log('🔴【从uid获取yonghuid】', yonghuid)
- }
-
- // 方案2:如果还没有,从用户信息获取
- if (!yonghuid && app.globalData.userInfo && app.globalData.userInfo.yonghuid) {
- yonghuid = String(app.globalData.userInfo.yonghuid).padStart(7, '0')
- //console.log('🔴【从userInfo获取yonghuid】', yonghuid)
- }
-
- // 方案3:如果还没有,直接提示并返回
- if (!yonghuid) {
- wx.showToast({
- title: '请先登录',
- icon: 'none'
- })
- this.setData({ isShangchuanzhong: false })
- return []
- }
-
-
-
- const preGeneratedUrls = []
- for (let i = 0; i < total; i++) {
- const timestamp = Date.now() + i
- const random = Math.floor(Math.random() * 10000)
- const fileExt = this.getFileExtension(this.data.shensuTupian[i])
- const fileName = `${yonghuid}_${timestamp}_${random}${fileExt}`
- const cosKey = `a_long/chfajltp/dssstp/${fileName}`
- preGeneratedUrls.push(cosKey)
- }
-
- let cosClient, bucket, region
- try {
- const tokenData = await this.getCOSZhengshu()
- const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData)
- cosClient = cos
- bucket = cosBucket
- region = cosRegion
- } catch (error) {
- wx.showToast({ title: '上传初始化失败', icon: 'none' })
- this.setData({ isShangchuanzhong: false })
- return []
- }
-
- const uploadTasks = []
- for (let i = 0; i < total; i++) {
- const task = this.shangchuanDanZhangTupian(
- this.data.shensuTupian[i],
- preGeneratedUrls[i],
- i,
- cosClient,
- bucket,
- region
- ).then((result) => {
- const currentDone = i + 1
- const jinduPercent = ((currentDone / total) * 100).toFixed(0)
- this.setData({
- shangchuanJindu: currentDone,
- jinduWidth: `${jinduPercent}%`
- })
- return result
- })
- uploadTasks.push(task)
- }
- await Promise.all(uploadTasks)
- this.setData({ isShangchuanzhong: false })
- return preGeneratedUrls
- },
-
- getFileExtension(filePath) {
- const lastDotIndex = filePath.lastIndexOf('.')
- if (lastDotIndex === -1) return '.jpg'
- const ext = filePath.substring(lastDotIndex).toLowerCase()
- const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
- return allowedExts.includes(ext) ? ext : '.jpg'
- },
-
- async submitShensu() {
- if (!this.data.shensuLiyou.trim()) {
- wx.showToast({ title: '请输入申诉理由', icon: 'none' }); return
- }
- if (this.data.shensuTupian.length === 0) {
- wx.showModal({
- title: '提示',
- content: '未上传任何图片,确定要提交申诉吗?',
- success: async (res) => {
- if (res.confirm) await this.tijiaoShensuData([])
- }
- })
- return
- }
- wx.showToast({ title: '开始上传图片...', icon: 'none' })
- try {
- const tupianUrls = await this.piliangShangchuanShensuTupian()
- if (!tupianUrls || tupianUrls.length === 0) throw new Error('图片上传失败')
- await this.tijiaoShensuData(tupianUrls)
- } catch (error) {
- console.error('提交申诉失败:', error)
- wx.showToast({ title: error.message || '提交失败', icon: 'none' })
- }
- },
-
- async tijiaoShensuData(tupianUrls) {
- wx.showToast({ title: '提交申诉中...', icon: 'none' })
- try {
- const res = await request({
- url: '/yonghu/dscfss',
- method: 'POST',
- data: {
- chufa_id: this.data.xuanzhongChufa.id,
- shensu_liyou: this.data.shensuLiyou,
- shensu_tupian_urls: tupianUrls
- }
- })
- if (res.statusCode === 200 && res.data.code === 0) {
- this.updateChufaRecord({
- sqzhuangtai: 3,
- ssliyou: this.data.shensuLiyou,
- shensu_tupian: tupianUrls
- })
- this.setData({
- showShensuModal: false,
- showXiangqing: false,
- shensuLiyou: '',
- shensuTupian: [],
- xuanzhongChufa: {}
- })
- wx.showToast({ title: '申诉提交成功,请等待处理', icon: 'success' })
- setTimeout(() => { this.chushihuaShuju() }, 500)
- } else {
- throw new Error(res.data?.msg || '提交申诉失败')
- }
- } catch (error) {
- console.error('提交申诉数据失败:', error)
- wx.showToast({ title: error.message || '提交失败', icon: 'none' })
- }
- },
-
- updateChufaRecord(newData) {
- const newList = this.data.chufaList.map(item => {
- if (item.id === this.data.xuanzhongChufa.id) {
- const updatedItem = { ...item, ...newData }
- // 🔴 更新显示字段
- if (newData.sqzhuangtai === 3) {
- updatedItem.display_status = '申诉中'
- updatedItem.status_class = 'zhuangtai-shensuzhong'
- }
- if (newData.shensu_tupian) {
- updatedItem.full_shensu_tupian = newData.shensu_tupian.map(url => this.getFullImageUrl(url))
- }
- return updatedItem
- }
- return item
- })
- this.setData({ chufaList: newList })
- },
-
- // 🔴【图片URL拼接 - 确保返回完整URL】
- getFullImageUrl(relativeUrl) {
- //console.log('🔴【图片拼接】输入:', relativeUrl)
-
- if (!relativeUrl) return ''
- if (relativeUrl.startsWith('http')) {
- //console.log('🔴【已经是完整URL】返回:', relativeUrl)
- return relativeUrl
- }
-
- const ossUrl = this.data.ossImageUrl
- if (!ossUrl) {
- //console.log('🔴【OSS地址为空】返回原始URL:', relativeUrl)
- return relativeUrl
- }
-
- let fullUrl
- if (ossUrl.endsWith('/') && relativeUrl.startsWith('/')) {
- fullUrl = ossUrl + relativeUrl.substring(1)
- } else if (!ossUrl.endsWith('/') && !relativeUrl.startsWith('/')) {
- fullUrl = ossUrl + '/' + relativeUrl
- } else {
- fullUrl = ossUrl + relativeUrl
- }
-
- // console.log('🔴【拼接后URL】:', fullUrl)
- return fullUrl
- },
-
- yulanTupian(e) {
- const currentUrl = e.currentTarget.dataset.url
- const urls = e.currentTarget.dataset.urls || []
- if (!currentUrl) return
-
- const fullCurrentUrl = currentUrl.startsWith('http') ? currentUrl : this.getFullImageUrl(currentUrl)
- const fullUrls = urls.map(url => url.startsWith('http') ? url : this.getFullImageUrl(url))
-
- wx.previewImage({
- current: fullCurrentUrl,
- urls: fullUrls.length > 0 ? fullUrls : [fullCurrentUrl]
- })
- },
-
- fuzhiWenben(e) {
- const text = e.currentTarget.dataset.text
- if (!text) return
-
- wx.setClipboardData({
- data: text,
- success: () => {
- wx.showToast({ title: '复制成功', icon: 'success' })
- },
- fail: () => {
- wx.showToast({ title: '复制失败', icon: 'none' })
- }
- })
- },
-
- // 🔴【保留原函数但已不再使用(用于向后兼容)】
- formatShijian(shijian) {
- if (!shijian) return '--'
- return String(shijian)
- },
-
- getZhuangtaiText(zhuangtai) {
- const statusNum = Number(zhuangtai)
- if (statusNum === 0) return '待处罚'
- if (statusNum === 1) return '已处罚'
- if (statusNum === 2) return '已驳回'
- if (statusNum === 3) return '申诉中'
- return '未知状态'
- },
-
- getZhuangtaiClass(zhuangtai) {
- const statusNum = Number(zhuangtai)
- if (statusNum === 0) return 'zhuangtai-daichuli'
- if (statusNum === 1) return 'zhuangtai-yichufa'
- if (statusNum === 2) return 'zhuangtai-yibohui'
- if (statusNum === 3) return 'zhuangtai-shensuzhong'
- return 'zhuangtai-weizhi'
- }
+// pages/penalty/penalty.js
+import request from '../../utils/request.js'
+const app = getApp()
+const MEIYE_TIAOSHU = 5
+
+Page({
+ data: {
+ zongshu: 0,
+ daichuli: 0,
+ yichuli: 0,
+ shenfen: 0,
+ chufaList: [],
+ dangqianye: 1,
+ haiyougengduo: true,
+ jiazhaozhong: false,
+ jiazhaigengduo: false,
+ scrollHeight: 0,
+ showXiangqing: false,
+ xuanzhongChufa: {},
+ showShensuModal: false,
+ shensuLiyou: '',
+ shensuTupian: [],
+ shensuTupianUrls: [],
+ shangchuanJindu: 0,
+ shangchuanZongshu: 0,
+ jinduWidth: '0%',
+ isShangchuanzhong: false,
+ ossImageUrl: '',
+ fangdouTimer: null
+ },
+
+ onLoad(options) {
+ this.registerNotificationComponent()
+ this.initOSSUrl()
+ this.jisuanGaodu()
+ this.chushihuaShuju()
+ },
+
+
+
+
+
+
+
+ onShow() {
+ this.registerNotificationComponent()
+ },
+
+ onUnload() {
+ if (this.data.fangdouTimer) clearTimeout(this.data.fangdouTimer)
+ },
+
+ onReachBottom() {
+ this.shanglaShuaxin()
+ },
+
+ registerNotificationComponent() {
+ const notificationComp = this.selectComponent('#global-notification')
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification()
+ }
+ }
+ },
+
+ initOSSUrl() {
+ const ossImageUrl = app.globalData.ossImageUrl || ''
+ this.setData({ ossImageUrl })
+ },
+
+ jisuanGaodu() {
+ const systemInfo = wx.getSystemInfoSync()
+ const windowHeight = systemInfo.windowHeight
+ const height = windowHeight - 200 - 100 - 40
+ this.setData({
+ scrollHeight: height > 0 ? height : 400
+ })
+ },
+
+ chushihuaShuju() {
+ this.setData({
+ dangqianye: 1,
+ chufaList: [],
+ haiyougengduo: true
+ })
+ this.jiazhuoquTongji()
+ this.jiazhuoquChufaList()
+ },
+
+ async jiazhuoquTongji() {
+ try {
+ const res = await request({
+ url: '/yonghu/dshqcfjl',
+ method: 'POST',
+ data: { qingqiu_tongji: true }
+ })
+ if (res.statusCode === 200 && res.data.code === 0) {
+ const data = res.data.data
+ this.setData({
+ zongshu: data.zongshu || 0,
+ daichuli: data.daichuli || 0,
+ yichuli: data.yichuli || 0
+ })
+ }
+ } catch (error) {
+ console.error('获取统计信息失败:', error)
+ }
+ },
+
+ async jiazhuoquChufaList(isLoadMore = false) {
+ if (this.data.jiazhaozhong || this.data.jiazhaigengduo) return
+ if (isLoadMore) {
+ if (!this.data.haiyougengduo) return
+ this.setData({ jiazhaigengduo: true })
+ } else {
+ this.setData({ jiazhaozhong: true })
+ }
+
+ try {
+ const params = {
+ page: this.data.dangqianye,
+ page_size: MEIYE_TIAOSHU
+ }
+ if (this.data.shenfen === 0) {
+ params.zhuangtai = 0
+ } else {
+ params.zhuangtai = 1
+ }
+
+ const res = await request({
+ url: '/yonghu/dshqcfjl',
+ method: 'POST',
+ data: params
+ })
+
+ //console.log('🔴【后端返回的数据】:', res.data)
+
+ if (res.statusCode === 200 && res.data.code === 0) {
+ const data = res.data.data
+
+ if (data.list && Array.isArray(data.list)) {
+ // 🔴【关键修复】在数据加载时就处理好显示字段
+ const processedList = data.list.map(item => {
+ // 处理显示时间
+ let displayTime = '--'
+ if (item.create_time) {
+ if (typeof item.create_time === 'number') {
+ displayTime = String(item.create_time)
+ } else if (typeof item.create_time === 'string') {
+ displayTime = item.create_time
+ } else {
+ displayTime = String(item.create_time)
+ }
+ }
+
+ // 处理显示状态
+ let displayStatus = '未知状态'
+ let statusClass = 'zhuangtai-weizhi'
+ const statusNum = Number(item.sqzhuangtai)
+
+ if (!isNaN(statusNum)) {
+ if (statusNum === 0) {
+ displayStatus = '待处罚'
+ statusClass = 'zhuangtai-daichuli'
+ } else if (statusNum === 1) {
+ displayStatus = '已处罚'
+ statusClass = 'zhuangtai-yichufa'
+ } else if (statusNum === 2) {
+ displayStatus = '已驳回'
+ statusClass = 'zhuangtai-yibohui'
+ } else if (statusNum === 3) {
+ displayStatus = '申诉中'
+ statusClass = 'zhuangtai-shensuzhong'
+ }
+ }
+
+ // 处理图片URL(在数据加载时就拼接完整URL)
+ const fullZhengjuTupian = (item.zhengju_tupian || []).map(url => this.getFullImageUrl(url))
+ const fullShensuTupian = (item.shensu_tupian || []).map(url => this.getFullImageUrl(url))
+
+ return {
+ ...item,
+ display_time: displayTime, // 🔴 处理好的显示时间
+ display_status: displayStatus, // 🔴 处理好的显示状态
+ status_class: statusClass, // 🔴 处理好的状态样式类
+ zhengju_tupian: item.zhengju_tupian || [],
+ shensu_tupian: item.shensu_tupian || [],
+ full_zhengju_tupian: fullZhengjuTupian, // 🔴 完整图片URL
+ full_shensu_tupian: fullShensuTupian // 🔴 完整图片URL
+ }
+ })
+
+ //console.log('🔴【处理后的数据】:', processedList)
+
+ let newList
+ if (isLoadMore) {
+ newList = [...this.data.chufaList, ...processedList]
+ } else {
+ newList = processedList
+ }
+
+ const hasMore = data.has_more === true
+ this.setData({
+ chufaList: newList,
+ haiyougengduo: hasMore,
+ dangqianye: this.data.dangqianye + 1
+ })
+ } else {
+ this.setData({ haiyougengduo: false })
+ }
+ } else {
+ throw new Error(res.data?.msg || '加载处罚记录失败')
+ }
+ } catch (error) {
+ console.error('加载处罚记录失败:', error)
+ wx.showToast({
+ title: error.message || '加载失败',
+ icon: 'none'
+ })
+ this.setData({ haiyougengduo: false })
+ } finally {
+ if (isLoadMore) {
+ this.setData({ jiazhaigengduo: false })
+ } else {
+ this.setData({ jiazhaozhong: false })
+ }
+ }
+ },
+
+ qiehuanShenfen(e) {
+ const type = parseInt(e.currentTarget.dataset.type)
+ if (this.data.shenfen === type) return
+ this.setData({
+ shenfen: type,
+ dangqianye: 1,
+ chufaList: [],
+ haiyougengduo: true
+ })
+ this.jiazhuoquChufaList()
+ },
+
+ shanglaShuaxin() {
+ if (this.data.fangdouTimer) clearTimeout(this.data.fangdouTimer)
+ const timer = setTimeout(() => {
+ if (this.data.jiazhaozhong || this.data.jiazhaigengduo) return
+ if (!this.data.haiyougengduo) return
+ this.jiazhuoquChufaList(true)
+ }, 300)
+ this.setData({ fangdouTimer: timer })
+ },
+
+ chakanXiangqing(e) {
+ const item = e.currentTarget.dataset.item
+ this.setData({
+ xuanzhongChufa: item,
+ showXiangqing: true
+ })
+ },
+
+ guanbiXiangqing() {
+ this.setData({
+ showXiangqing: false,
+ xuanzhongChufa: {}
+ })
+ },
+
+ openShensuModal() {
+ if (this.data.xuanzhongChufa.ssliyou ||
+ (this.data.xuanzhongChufa.shensu_tupian && this.data.xuanzhongChufa.shensu_tupian.length > 0)) {
+ wx.showToast({
+ title: '您已经提交过申诉,请等待处理结果',
+ icon: 'none'
+ })
+ return
+ }
+ this.setData({
+ showShensuModal: true,
+ shensuLiyou: '',
+ shensuTupian: [],
+ shensuTupianUrls: [],
+ shangchuanJindu: 0,
+ shangchuanZongshu: 0,
+ jinduWidth: '0%'
+ })
+ },
+
+ closeShensuModal() {
+ this.setData({
+ showShensuModal: false,
+ shensuLiyou: '',
+ shensuTupian: [],
+ shensuTupianUrls: []
+ })
+ },
+
+ onShensuLiyouInput(e) {
+ const value = e.detail.value.slice(0, 500)
+ this.setData({ shensuLiyou: value })
+ },
+
+ chooseShensuTupian() {
+ if (this.data.isShangchuanzhong) return
+ const shengyu = 9 - this.data.shensuTupian.length
+ if (shengyu <= 0) {
+ wx.showToast({
+ title: '最多只能上传9张图片',
+ icon: 'none'
+ })
+ return
+ }
+ wx.chooseMedia({
+ count: shengyu,
+ mediaType: ['image'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const newTupian = [...this.data.shensuTupian, ...res.tempFiles.map(file => file.tempFilePath)]
+ this.setData({ shensuTupian: newTupian.slice(0, 9) })
+ }
+ })
+ },
+
+ deleteShensuTupian(e) {
+ const index = e.currentTarget.dataset.index
+ const newTupian = [...this.data.shensuTupian]
+ newTupian.splice(index, 1)
+ this.setData({ shensuTupian: newTupian })
+ },
+
+ yulanShensuTupian(e) {
+ const index = e.currentTarget.dataset.index
+ const urls = this.data.shensuTupian
+ if (!urls[index]) return
+ wx.previewImage({
+ current: urls[index],
+ urls: urls
+ })
+ },
+
+ lianxiKefu() {
+ 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'
+ });
+ }
+ });
+ },
+
+ async getCOSZhengshu() {
+ try {
+ const res = await request({
+ url: '/dingdan/dsscpz',
+ method: 'POST',
+ data: {
+ dingdan_id: this.data.xuanzhongChufa.dingdan_id,
+ yongtu: 'chufa'
+ }
+ })
+ if (res.statusCode === 200 && res.data.code === 0 && res.data.data) {
+ return res.data.data
+ } else {
+ throw new Error(res?.data?.msg || '获取上传凭证失败')
+ }
+ } catch (error) {
+ console.error('获取COS凭证失败:', error)
+ throw error
+ }
+ },
+
+ initCOSClient(tokenData) {
+ const COS = require('../../utils/cos-wx-sdk-v5.min.js')
+ const credentials = tokenData.credentials || tokenData
+ const bucket = tokenData.bucket || 'julebu-1361527063'
+ const region = tokenData.region || 'ap-shanghai'
+ const cos = new COS({
+ SimpleUploadMethod: 'putObject',
+ getAuthorization: async (options, callback) => {
+ const authParams = {
+ TmpSecretId: credentials.tmpSecretId,
+ TmpSecretKey: credentials.tmpSecretKey,
+ SecurityToken: credentials.sessionToken || '',
+ StartTime: tokenData.startTime || Math.floor(Date.now() / 1000),
+ ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200)
+ }
+ callback(authParams)
+ }
+ })
+ return { cos, bucket, region }
+ },
+
+ async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) {
+ return new Promise((resolve) => {
+ const timeoutId = setTimeout(() => {
+ resolve({ status: 'optimistic_success', key: cosKey })
+ }, 2000)
+ cosInstance.uploadFile({
+ Bucket: bucket,
+ Region: region,
+ Key: cosKey,
+ FilePath: filePath,
+ onProgress: (progressInfo) => {
+ const percent = Math.round(progressInfo.percent * 100)
+ if (percent === 100) {
+ clearTimeout(timeoutId)
+ resolve({ status: 'optimistic_success', key: cosKey })
+ }
+ }
+ })
+ })
+ },
+
+ async piliangShangchuanShensuTupian() {
+ const total = this.data.shensuTupian.length
+ if (total === 0) return []
+ this.setData({
+ shangchuanZongshu: total,
+ shangchuanJindu: 0,
+ jinduWidth: '0%',
+ isShangchuanzhong: true
+ })
+ let yonghuid = ''
+
+ // 方案1:直接从全局缓存获取
+ const uid = wx.getStorageSync('uid')
+ if (uid) {
+ yonghuid = String(uid).padStart(7, '0')
+ //console.log('🔴【从uid获取yonghuid】', yonghuid)
+ }
+
+ // 方案2:如果还没有,从用户信息获取
+ if (!yonghuid && app.globalData.userInfo && app.globalData.userInfo.yonghuid) {
+ yonghuid = String(app.globalData.userInfo.yonghuid).padStart(7, '0')
+ //console.log('🔴【从userInfo获取yonghuid】', yonghuid)
+ }
+
+ // 方案3:如果还没有,直接提示并返回
+ if (!yonghuid) {
+ wx.showToast({
+ title: '请先登录',
+ icon: 'none'
+ })
+ this.setData({ isShangchuanzhong: false })
+ return []
+ }
+
+
+
+ const preGeneratedUrls = []
+ for (let i = 0; i < total; i++) {
+ const timestamp = Date.now() + i
+ const random = Math.floor(Math.random() * 10000)
+ const fileExt = this.getFileExtension(this.data.shensuTupian[i])
+ const fileName = `${yonghuid}_${timestamp}_${random}${fileExt}`
+ const cosKey = `a_long/chfajltp/dssstp/${fileName}`
+ preGeneratedUrls.push(cosKey)
+ }
+
+ let cosClient, bucket, region
+ try {
+ const tokenData = await this.getCOSZhengshu()
+ const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData)
+ cosClient = cos
+ bucket = cosBucket
+ region = cosRegion
+ } catch (error) {
+ wx.showToast({ title: '上传初始化失败', icon: 'none' })
+ this.setData({ isShangchuanzhong: false })
+ return []
+ }
+
+ const uploadTasks = []
+ for (let i = 0; i < total; i++) {
+ const task = this.shangchuanDanZhangTupian(
+ this.data.shensuTupian[i],
+ preGeneratedUrls[i],
+ i,
+ cosClient,
+ bucket,
+ region
+ ).then((result) => {
+ const currentDone = i + 1
+ const jinduPercent = ((currentDone / total) * 100).toFixed(0)
+ this.setData({
+ shangchuanJindu: currentDone,
+ jinduWidth: `${jinduPercent}%`
+ })
+ return result
+ })
+ uploadTasks.push(task)
+ }
+ await Promise.all(uploadTasks)
+ this.setData({ isShangchuanzhong: false })
+ return preGeneratedUrls
+ },
+
+ getFileExtension(filePath) {
+ const lastDotIndex = filePath.lastIndexOf('.')
+ if (lastDotIndex === -1) return '.jpg'
+ const ext = filePath.substring(lastDotIndex).toLowerCase()
+ const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
+ return allowedExts.includes(ext) ? ext : '.jpg'
+ },
+
+ async submitShensu() {
+ if (!this.data.shensuLiyou.trim()) {
+ wx.showToast({ title: '请输入申诉理由', icon: 'none' }); return
+ }
+ if (this.data.shensuTupian.length === 0) {
+ wx.showModal({
+ title: '提示',
+ content: '未上传任何图片,确定要提交申诉吗?',
+ success: async (res) => {
+ if (res.confirm) await this.tijiaoShensuData([])
+ }
+ })
+ return
+ }
+ wx.showToast({ title: '开始上传图片...', icon: 'none' })
+ try {
+ const tupianUrls = await this.piliangShangchuanShensuTupian()
+ if (!tupianUrls || tupianUrls.length === 0) throw new Error('图片上传失败')
+ await this.tijiaoShensuData(tupianUrls)
+ } catch (error) {
+ console.error('提交申诉失败:', error)
+ wx.showToast({ title: error.message || '提交失败', icon: 'none' })
+ }
+ },
+
+ async tijiaoShensuData(tupianUrls) {
+ wx.showToast({ title: '提交申诉中...', icon: 'none' })
+ try {
+ const res = await request({
+ url: '/yonghu/dscfss',
+ method: 'POST',
+ data: {
+ chufa_id: this.data.xuanzhongChufa.id,
+ shensu_liyou: this.data.shensuLiyou,
+ shensu_tupian_urls: tupianUrls
+ }
+ })
+ if (res.statusCode === 200 && res.data.code === 0) {
+ this.updateChufaRecord({
+ sqzhuangtai: 3,
+ ssliyou: this.data.shensuLiyou,
+ shensu_tupian: tupianUrls
+ })
+ this.setData({
+ showShensuModal: false,
+ showXiangqing: false,
+ shensuLiyou: '',
+ shensuTupian: [],
+ xuanzhongChufa: {}
+ })
+ wx.showToast({ title: '申诉提交成功,请等待处理', icon: 'success' })
+ setTimeout(() => { this.chushihuaShuju() }, 500)
+ } else {
+ throw new Error(res.data?.msg || '提交申诉失败')
+ }
+ } catch (error) {
+ console.error('提交申诉数据失败:', error)
+ wx.showToast({ title: error.message || '提交失败', icon: 'none' })
+ }
+ },
+
+ updateChufaRecord(newData) {
+ const newList = this.data.chufaList.map(item => {
+ if (item.id === this.data.xuanzhongChufa.id) {
+ const updatedItem = { ...item, ...newData }
+ // 🔴 更新显示字段
+ if (newData.sqzhuangtai === 3) {
+ updatedItem.display_status = '申诉中'
+ updatedItem.status_class = 'zhuangtai-shensuzhong'
+ }
+ if (newData.shensu_tupian) {
+ updatedItem.full_shensu_tupian = newData.shensu_tupian.map(url => this.getFullImageUrl(url))
+ }
+ return updatedItem
+ }
+ return item
+ })
+ this.setData({ chufaList: newList })
+ },
+
+ // 🔴【图片URL拼接 - 确保返回完整URL】
+ getFullImageUrl(relativeUrl) {
+ //console.log('🔴【图片拼接】输入:', relativeUrl)
+
+ if (!relativeUrl) return ''
+ if (relativeUrl.startsWith('http')) {
+ //console.log('🔴【已经是完整URL】返回:', relativeUrl)
+ return relativeUrl
+ }
+
+ const ossUrl = this.data.ossImageUrl
+ if (!ossUrl) {
+ //console.log('🔴【OSS地址为空】返回原始URL:', relativeUrl)
+ return relativeUrl
+ }
+
+ let fullUrl
+ if (ossUrl.endsWith('/') && relativeUrl.startsWith('/')) {
+ fullUrl = ossUrl + relativeUrl.substring(1)
+ } else if (!ossUrl.endsWith('/') && !relativeUrl.startsWith('/')) {
+ fullUrl = ossUrl + '/' + relativeUrl
+ } else {
+ fullUrl = ossUrl + relativeUrl
+ }
+
+ // console.log('🔴【拼接后URL】:', fullUrl)
+ return fullUrl
+ },
+
+ yulanTupian(e) {
+ const currentUrl = e.currentTarget.dataset.url
+ const urls = e.currentTarget.dataset.urls || []
+ if (!currentUrl) return
+
+ const fullCurrentUrl = currentUrl.startsWith('http') ? currentUrl : this.getFullImageUrl(currentUrl)
+ const fullUrls = urls.map(url => url.startsWith('http') ? url : this.getFullImageUrl(url))
+
+ wx.previewImage({
+ current: fullCurrentUrl,
+ urls: fullUrls.length > 0 ? fullUrls : [fullCurrentUrl]
+ })
+ },
+
+ fuzhiWenben(e) {
+ const text = e.currentTarget.dataset.text
+ if (!text) return
+
+ wx.setClipboardData({
+ data: text,
+ success: () => {
+ wx.showToast({ title: '复制成功', icon: 'success' })
+ },
+ fail: () => {
+ wx.showToast({ title: '复制失败', icon: 'none' })
+ }
+ })
+ },
+
+ // 🔴【保留原函数但已不再使用(用于向后兼容)】
+ formatShijian(shijian) {
+ if (!shijian) return '--'
+ return String(shijian)
+ },
+
+ getZhuangtaiText(zhuangtai) {
+ const statusNum = Number(zhuangtai)
+ if (statusNum === 0) return '待处罚'
+ if (statusNum === 1) return '已处罚'
+ if (statusNum === 2) return '已驳回'
+ if (statusNum === 3) return '申诉中'
+ return '未知状态'
+ },
+
+ getZhuangtaiClass(zhuangtai) {
+ const statusNum = Number(zhuangtai)
+ if (statusNum === 0) return 'zhuangtai-daichuli'
+ if (statusNum === 1) return 'zhuangtai-yichufa'
+ if (statusNum === 2) return 'zhuangtai-yibohui'
+ if (statusNum === 3) return 'zhuangtai-shensuzhong'
+ return 'zhuangtai-weizhi'
+ }
})
\ No newline at end of file
diff --git a/pages/fighter-msg/fighter-msg.wxss b/pages/fighter-msg/fighter-msg.wxss
index 21bbf83..2c19a0c 100644
--- a/pages/fighter-msg/fighter-msg.wxss
+++ b/pages/fighter-msg/fighter-msg.wxss
@@ -296,9 +296,9 @@
}
.zhuangtai-shensuzhong {
- background: rgba(147, 51, 234, 0.2);
- border-color: #9333ea;
- box-shadow: 0 0 8rpx rgba(147, 51, 234, 0.2);
+ background: rgba(255, 165, 0, 0.2);
+ border-color: #FFA500;
+ box-shadow: 0 0 8rpx rgba(255, 165, 0, 0.2);
}
.zhuangtai-weizhi {
@@ -657,9 +657,9 @@
}
.cbtn-shensu {
- background: rgba(147, 51, 234, 0.1);
- border-color: #9333ea;
- box-shadow: 0 0 12rpx rgba(147, 51, 234, 0.2);
+ background: rgba(255, 165, 0, 0.1);
+ border-color: #FFA500;
+ box-shadow: 0 0 12rpx rgba(255, 165, 0, 0.2);
}
.cbtn-shensu-disabled {
diff --git a/pages/fighter-order-detail/fighter-order-detail.js b/pages/fighter-order-detail/fighter-order-detail.js
index 582e5f1..7e8951a 100644
--- a/pages/fighter-order-detail/fighter-order-detail.js
+++ b/pages/fighter-order-detail/fighter-order-detail.js
@@ -1,741 +1,727 @@
-// pages/fighter-order-detail/fighter-order-detail.js - 【最终版:提交前公告弹窗 + 修改图片至少保留一张】
-const app = getApp()
-import request from '../../utils/request.js'
-const COS = require('../../utils/cos-wx-sdk-v5.js')
-
-Page({
- data: {
- jibenShuju: {
- dingdan_id: '',
- tupian: '',
- jieshao: '',
- create_time: '',
- jine: '',
- nicheng: '',
- beizhu: '',
- zhuangtai: 0,
- fadanpingtai: 0
- },
- xiangxiShuju: {
- shangjia_id: '',
- shangjia_nicheng: '',
- shangjia_liuyan: '',
- tuikuan_liyou: '',
- chufa_liyou: '',
- chufa_zhuangtai: 0,
- chufa_jieguo: '',
- bohui_liyou: '',
- dashou_jiaofu: [],
- dashou_liuyan: '',
- laoban_id: ''
- },
- zhuangtaiYanseMap: {
- 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#F3E8FF',
- 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#F5F3FF'
- },
- zhuangtaiWenziMap: {
- 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中',
- 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中'
- },
- isLoading: true,
- isSubmitting: false,
- liuyan: '',
- xuanzhongTupian: [],
- shangchuanJindu: 0,
- shangchuanZongshu: 0,
- jinduWidth: '0%',
- showWanzhengJieshao: false,
- wanzhengJieshao: '',
- showWanzhengBeizhu: false,
- wanzhengBeizhu: '',
- ossImageUrl: '',
- morentouxiang: '',
- showRefundInfo: false,
-
- // 修改功能所需字段
- isModifying: false,
- originalDashouJiaofu: [],
- originalDashouLiuyan: '',
- remainingOriginals: [],
- modifiedLiuyan: '',
- deletedImages: [],
- newImages: [],
- isConfirming: false,
- modifyUploadProgress: { total: 0, current: 0, width: '0%' }
- },
-
- onLoad(options) {
- wx.setNavigationBarTitle({ title: '订单详情' })
- this.initGlobalData()
- this.jiexiTiaozhuanCanshu(options)
- },
- onHide() {
- const popupComp = this.selectComponent('#popupNotice');
- if (popupComp && popupComp.cleanup) {
- popupComp.cleanup();
- }
- },
-
- onShow() {
- this.registerNotificationComponent();
- },
-
- registerNotificationComponent() {
- const app = getApp();
- const notificationComp = this.selectComponent('#global-notification');
- if (notificationComp && notificationComp.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- };
- }
- },
-
- initGlobalData() {
- const app = getApp()
- const ossImageUrl = app.globalData.ossImageUrl || 'https://your-oss-domain.com/'
- const morentouxiang = app.globalData.morentouxiang || '/images/default-avatar.png'
- this.setData({ ossImageUrl, morentouxiang })
- },
-
- jiexiTiaozhuanCanshu(options) {
- try {
- const dingdanDataStr = options.dingdanData || ''
- if (!dingdanDataStr) {
- wx.showToast({ title: '订单数据错误', icon: 'none' })
- setTimeout(() => wx.navigateBack(), 1500)
- return
- }
- const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr))
- let tupianUrl = dingdanData.tupian || ''
- if (!tupianUrl) tupianUrl = this.getTupianUrl()
- let jine = parseFloat(dingdanData.jine || 0)
- if (isNaN(jine)) jine = 0
- const formattedJine = jine.toFixed(2)
- this.setData({
- 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '',
- 'jibenShuju.tupian': tupianUrl,
- 'jibenShuju.jieshao': dingdanData.jieshao || '',
- 'jibenShuju.create_time': dingdanData.create_time || '',
- 'jibenShuju.jine': formattedJine,
- 'jibenShuju.nicheng': dingdanData.nicheng || '',
- 'jibenShuju.beizhu': dingdanData.beizhu || '',
- 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0,
- 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0,
- isLoading: false
- })
- this.jiazaiXiangxiShuju(dingdanData.dingdan_id)
- } catch (error) {
- console.error('解析订单数据失败:', error)
- wx.showToast({ title: '数据解析失败', icon: 'none' })
- setTimeout(() => wx.navigateBack(), 1500)
- }
- },
-
- getTupianUrl() {
- const cacheTouxiang = wx.getStorageSync('touxiang') || ''
- let tupianPath = cacheTouxiang || app.globalData.morentouxiang || ''
- const ossImageUrl = app.globalData.ossImageUrl || ''
- if (tupianPath && ossImageUrl) {
- if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1)
- return ossImageUrl + tupianPath
- }
- return ''
- },
-
- async jiazaiXiangxiShuju(dingdanId) {
- if (!dingdanId) return
- wx.showLoading({ title: '加载中...', mask: true })
- try {
- const res = await request({
- url: '/dingdan/dsddxq',
- method: 'POST',
- data: { dingdan_id: dingdanId },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- if (res && res.data.code === 0 && res.data.data) {
- const data = res.data.data
- let dashouJiaofuList = data.dashou_jiaofu || []
- dashouJiaofuList = dashouJiaofuList.map(imgUrl => {
- if (imgUrl && !imgUrl.startsWith('http')) {
- const ossImageUrl = app.globalData.ossImageUrl || ''
- if (imgUrl.startsWith('/')) imgUrl = imgUrl.substring(1)
- return ossImageUrl + imgUrl
- }
- return imgUrl
- })
- this.setData({
- 'xiangxiShuju.shangjia_id': data.shangjia_id || '',
- 'xiangxiShuju.shangjia_nicheng': data.shangjia_nicheng || '',
- 'xiangxiShuju.shangjia_liuyan': data.shangjia_liuyan || '',
- 'xiangxiShuju.tuikuan_liyou': data.tuikuan_liyou || '',
- 'xiangxiShuju.chufa_liyou': data.chufa_liyou || '',
- 'xiangxiShuju.chufa_zhuangtai': data.chufa_zhuangtai || 0,
- 'xiangxiShuju.chufa_jieguo': data.chufa_jieguo || '',
- 'xiangxiShuju.bohui_liyou': data.bohui_liyou || '',
- 'xiangxiShuju.dashou_jiaofu': dashouJiaofuList,
- 'xiangxiShuju.dashou_liuyan': data.dashou_liuyan || '',
- 'xiangxiShuju.laoban_id': data.laoban_id || '',
- 'jibenShuju.zhuangtai': data.zhuangtai || 0,
- 'jibenShuju.beizhu': data.beizhu || '',
- 'liuyan': data.dashou_liuyan || '',
- 'jibenShuju.fadanpingtai': data.fadanpingtai || 0
- })
- const currentStatus = data.zhuangtai || 0
- const showRefund = [4,5,6].includes(currentStatus)
- this.setData({ showRefundInfo: showRefund })
- } else {
- const errorMsg = res?.data?.msg || '获取订单详情失败'
- wx.showToast({ title: errorMsg, icon: 'none', duration: 2000 })
- }
- } catch (error) {
- console.error('加载详细数据失败:', error)
- wx.hideLoading()
- wx.showToast({ title: '加载数据失败,请重试', icon: 'none', duration: 2000 })
- }
- },
-
- // ========== 原有提交功能(部分修改) ==========
- xuanzeTupian() {
- if (this.data.isSubmitting) return
- const shengyu = 9 - this.data.xuanzhongTupian.length
- if (shengyu <= 0) {
- wx.showToast({ title: '最多只能选择9张图片', icon: 'none' })
- return
- }
- wx.chooseImage({
- count: shengyu,
- sizeType: ['compressed'],
- sourceType: ['album', 'camera'],
- success: (res) => {
- const newTupian = [...this.data.xuanzhongTupian, ...res.tempFilePaths]
- this.setData({ xuanzhongTupian: newTupian.slice(0, 9) })
- }
- })
- },
- shanchuTupian(e) {
- const index = e.currentTarget.dataset.index
- const newTupian = [...this.data.xuanzhongTupian]
- newTupian.splice(index, 1)
- this.setData({ xuanzhongTupian: newTupian })
- },
- yulanTupian(e) {
- const currentUrl = e.currentTarget.dataset.url
- const urls = e.currentTarget.dataset.urls || []
- if (!currentUrl) return
- wx.previewImage({ current: currentUrl, urls: urls.length > 0 ? urls : [currentUrl] })
- },
- getFileExtension(filePath) {
- const lastDotIndex = filePath.lastIndexOf('.')
- if (lastDotIndex === -1) return '.jpg'
- const ext = filePath.substring(lastDotIndex).toLowerCase()
- const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
- return allowedExts.includes(ext) ? ext : '.jpg'
- },
- shuruLiuyan(e) {
- const liuyan = e.detail.value.slice(0, 50)
- this.setData({ liuyan })
- },
- chakanWanzhengJieshao() {
- this.setData({ showWanzhengJieshao: true, wanzhengJieshao: this.data.jibenShuju.jieshao || '无' })
- },
- guanbiWanzhengJieshao() { this.setData({ showWanzhengJieshao: false }) },
- chakanWanzhengBeizhu() {
- this.setData({ showWanzhengBeizhu: true, wanzhengBeizhu: this.data.jibenShuju.beizhu || '无' })
- },
- guanbiWanzhengBeizhu() { this.setData({ showWanzhengBeizhu: false }) },
- async fuzhiWenben(e) {
- const text = e.currentTarget.dataset.text
- if (!text) return
- try {
- await wx.setClipboardData({ data: text })
- wx.showToast({ title: '复制成功', icon: 'success', duration: 1500 })
- } catch (error) {
- console.error('复制失败:', error)
- wx.showToast({ title: '复制失败', icon: 'none' })
- }
- },
- goToKefu() {
- const kefuLink = app.globalData.kefuConfig?.link || '';
- const corpId = app.globalData.kefuConfig?.enterpriseId || '';
-
- if (!kefuLink || !corpId) {
- wx.showToast({
- title: '客服配置未加载',
- icon: 'none'
- });
- return;
- }
-
- wx.openCustomerServiceChat({
- extInfo: { url: kefuLink },
- corpId: corpId,
- success: (res) => {
- console.log('跳转客服成功', res);
- },
- fail: (err) => {
- console.error('跳转客服失败', err);
- wx.showToast({
- title: '暂时无法连接客服',
- icon: 'none'
- });
- }
- });
- },
-
- // ===== 联系老板(订单群 groupId 即订单号,与商家端 sjddxq 一致) =====
- goToChatWithBoss() {
- const uid = wx.getStorageSync('uid')
- if (!uid) {
- wx.showToast({ title: '用户信息缺失', icon: 'none' })
- return
- }
-
- const orderId = this.data.jibenShuju.dingdan_id
- if (!orderId) {
- wx.showToast({ title: '订单ID缺失', icon: 'none' })
- return
- }
-
- const targetUserId = 'Ds' + uid
- const connected = wx.goEasy && wx.goEasy.getConnectionStatus && wx.goEasy.getConnectionStatus() === 'connected'
- const currentUserId = wx.goEasy?.im?.userId
- if (!connected || currentUserId !== targetUserId) {
- if (app.ensureConnection) app.ensureConnection()
- wx.showToast({ title: '连接中,请稍后再试', icon: 'none' })
- return
- }
-
- const orderIdStr = String(orderId)
- const groupName = (this.data.jibenShuju.nicheng || '订单') + '的订单群'
- const isCross = this.data.jibenShuju.fadanpingtai || 0
-
- wx.goEasy.im.subscribeGroup({
- groupIds: [orderIdStr],
- onSuccess: () => {
- const param = {
- groupId: orderIdStr,
- orderId: orderIdStr,
- groupName,
- groupAvatar: '',
- isCross,
- }
- wx.navigateTo({
- url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)),
- })
- },
- onFailed: (err) => {
- console.error('订阅群组失败', err)
- wx.showToast({ title: '连接群聊失败', icon: 'none' })
- },
- })
- },
-
- async getCOSZhengshu() {
- try {
- const res = await request({
- url: '/dingdan/dsscpz',
- method: 'POST',
- data: { dingdan_id: this.data.jibenShuju.dingdan_id }
- })
- if (res && res.data.code === 0 && res.data.data) return res.data.data
- else throw new Error(res?.data?.msg || '获取上传凭证失败')
- } catch (error) {
- console.error('获取COS凭证失败:', error)
- throw error
- }
- },
-
- initCOSClient(tokenData) {
- const credentials = tokenData.credentials || tokenData
- const bucket = tokenData.bucket || 'julebu-1361527063'
- const region = tokenData.region || 'ap-shanghai'
- const cos = new COS({
- SimpleUploadMethod: 'putObject',
- getAuthorization: async (options, callback) => {
- const authParams = {
- TmpSecretId: credentials.tmpSecretId,
- TmpSecretKey: credentials.tmpSecretKey,
- SecurityToken: credentials.sessionToken || '',
- StartTime: tokenData.startTime || Math.floor(Date.now() / 1000),
- ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200)
- }
- callback(authParams)
- }
- })
- return { cos, bucket, region }
- },
-
- async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) {
- return new Promise((resolve) => {
- const timeoutId = setTimeout(() => resolve({ status: 'optimistic_success', key: cosKey }), 2000)
- cosInstance.uploadFile({
- Bucket: bucket,
- Region: region,
- Key: cosKey,
- FilePath: filePath,
- onProgress: (progressInfo) => {
- const percent = Math.round(progressInfo.percent * 100)
- if (percent === 100) {
- clearTimeout(timeoutId)
- resolve({ status: 'optimistic_success', key: cosKey })
- }
- }
- })
- })
- },
-
- async piliangShangchuanTupian() {
- const total = this.data.xuanzhongTupian.length
- this.setData({ shangchuanZongshu: total, shangchuanJindu: 0, jinduWidth: '0%' })
- wx.showLoading({ title: '正在准备...', mask: true })
- const preGeneratedUrls = []
- for (let i = 0; i < total; i++) {
- const timestamp = Date.now() + i
- const random = Math.floor(Math.random() * 10000)
- const fileExt = this.getFileExtension(this.data.xuanzhongTupian[i])
- const fileName = `${timestamp}_${random}${fileExt}`
- const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}`
- preGeneratedUrls.push(cosKey)
- }
- let cosClient, bucket, region
- try {
- const tokenData = await this.getCOSZhengshu()
- const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData)
- cosClient = cos
- bucket = cosBucket
- region = cosRegion
- } catch (error) {
- wx.hideLoading()
- wx.showToast({ title: '上传初始化失败', icon: 'none' })
- return []
- }
- const uploadTasks = []
- for (let i = 0; i < total; i++) {
- const task = this.shangchuanDanZhangTupian(
- this.data.xuanzhongTupian[i],
- preGeneratedUrls[i],
- i,
- cosClient,
- bucket,
- region
- ).then((result) => {
- const currentDone = i + 1
- const jinduPercent = ((currentDone / total) * 100).toFixed(0)
- this.setData({ shangchuanJindu: currentDone, jinduWidth: `${jinduPercent}%` })
- return result
- })
- uploadTasks.push(task)
- }
- wx.showLoading({ title: `上传中...`, mask: true })
- await Promise.all(uploadTasks)
- wx.hideLoading()
- return preGeneratedUrls
- },
-
- tijiaoDingdan() {
- this.showAnnouncementAndConfirm()
- },
-
- async showAnnouncementAndConfirm() {
- try {
- const res = await request({
- url: '/peizhi/tanchuang',
- method: 'POST',
- data: { pageKey: 'dsddxq' }
- })
- if (res.statusCode !== 200 || res.data.code !== 0) {
- this.showOriginalConfirmAndSubmit()
- return
- }
- const { popups = [], serverTime } = res.data.data
- if (!popups.length) {
- this.showOriginalConfirmAndSubmit()
- return
- }
- const popup = popups[0]
- const popupComp = this.selectComponent('#popupNotice')
- if (!popupComp) {
- console.error('未找到弹窗组件 #popupNotice')
- this.showOriginalConfirmAndSubmit()
- return
- }
- const showData = {
- popupId: popup.popup_id,
- title: popup.title || '',
- duration: popup.duration || 0,
- images: popup.images || [],
- showMuteCheckbox: false,
- serverTime: serverTime
- }
- popupComp.show(showData, (result) => {
- this.showOriginalConfirmAndSubmit()
- })
- } catch (error) {
- console.error('获取公告配置失败', error)
- this.showOriginalConfirmAndSubmit()
- }
- },
-
- showOriginalConfirmAndSubmit() {
- if (this.data.isSubmitting) {
- wx.showToast({ title: '正在提交中', icon: 'none' })
- return
- }
- if (this.data.jibenShuju.zhuangtai !== 2) {
- wx.showToast({ title: '订单状态不可提交', icon: 'none' })
- return
- }
- if (this.data.xuanzhongTupian.length === 0) {
- wx.showToast({ title: '请至少上传一张图片', icon: 'none' })
- return
- }
- wx.showModal({
- title: '⚠️ 提交确认',
- content: '在提交订单之前,请确保您已在接单员端页面认真阅读接单员规则。如有漏交图片,订单被退款,概不申诉。',
- confirmText: '我已阅读',
- cancelText: '我再想想',
- success: (res) => {
- if (res.confirm) this._doSubmit()
- },
- fail: (err) => {
- console.error('弹窗失败', err)
- wx.showToast({ title: '系统异常,请重试', icon: 'none' })
- }
- })
- },
-
- async _doSubmit() {
- this.setData({ isSubmitting: true })
- wx.showLoading({ title: '开始提交...', mask: true })
- try {
- const tupianUrls = await this.piliangShangchuanTupian()
- if (!tupianUrls || tupianUrls.length === 0) throw new Error('无法生成上传路径')
- wx.showLoading({ title: '提交订单数据...', mask: true })
- const res = await request({
- url: '/dingdan/dstijiao',
- method: 'POST',
- data: {
- dingdan_id: this.data.jibenShuju.dingdan_id,
- liuyan: this.data.liuyan || '',
- jiaofu_tupian_urls: tupianUrls
- },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isSubmitting: false })
- if (res && res.data.code === 0) {
- const ossImageUrl = app.globalData.ossImageUrl || ''
- const fullUrls = tupianUrls.map(url => {
- if (url && !url.startsWith('http')) {
- if (url.startsWith('/')) url = url.substring(1)
- return ossImageUrl + url
- }
- return url
- })
- this.setData({
- 'jibenShuju.zhuangtai': 8,
- 'xiangxiShuju.dashou_liuyan': this.data.liuyan || '',
- 'xiangxiShuju.dashou_jiaofu': fullUrls,
- xuanzhongTupian: [],
- liuyan: '',
- shangchuanJindu: 0,
- shangchuanZongshu: 0,
- jinduWidth: '0%',
- })
- if (app.globalData.dashouzhuangtai != 1) app.globalData.dashouzhuangtai = 1
- wx.showToast({ title: '提交成功!', icon: 'success', duration: 2000 })
- setTimeout(() => wx.navigateBack(), 1500)
- } else {
- const errorMsg = res?.data?.msg || '提交失败'
- wx.showToast({ title: errorMsg, icon: 'none' })
- }
- } catch (error) {
- console.error('提交失败:', error)
- wx.hideLoading()
- this.setData({ isSubmitting: false })
- wx.showToast({ title: error.message || '提交失败', icon: 'none' })
- }
- },
-
- // ========== 修改功能(增加最少一张图片校验) ==========
- extractRelativePath(fullUrl) {
- const ossImageUrl = this.data.ossImageUrl
- if (fullUrl.startsWith(ossImageUrl)) return fullUrl.substring(ossImageUrl.length)
- return fullUrl
- },
- enterModify() {
- const { dashou_jiaofu, dashou_liuyan } = this.data.xiangxiShuju
- this.setData({
- isModifying: true,
- originalDashouJiaofu: dashou_jiaofu.slice(),
- remainingOriginals: dashou_jiaofu.slice(),
- originalDashouLiuyan: dashou_liuyan || '',
- modifiedLiuyan: dashou_liuyan || '',
- deletedImages: [],
- newImages: []
- })
- },
- cancelModify() {
- this.setData({
- isModifying: false,
- originalDashouJiaofu: [],
- remainingOriginals: [],
- originalDashouLiuyan: '',
- modifiedLiuyan: '',
- deletedImages: [],
- newImages: []
- })
- },
- handleDeleteImage(e) {
- const fullUrl = e.currentTarget.dataset.url
- const { originalDashouJiaofu, remainingOriginals, deletedImages, newImages } = this.data
- if (originalDashouJiaofu.includes(fullUrl)) {
- const newRemaining = remainingOriginals.filter(url => url !== fullUrl)
- this.setData({
- remainingOriginals: newRemaining,
- deletedImages: [...deletedImages, fullUrl]
- })
- } else {
- const index = newImages.indexOf(fullUrl)
- if (index > -1) {
- const newImagesCopy = [...newImages]
- newImagesCopy.splice(index, 1)
- this.setData({ newImages: newImagesCopy })
- }
- }
- },
- handleAddImage() {
- if (this.data.isConfirming) return
- const currentCount = this.getCurrentImageCount()
- const maxCount = 9 - currentCount
- if (maxCount <= 0) {
- wx.showToast({ title: '最多9张图片', icon: 'none' })
- return
- }
- wx.chooseImage({
- count: maxCount,
- sizeType: ['compressed'],
- sourceType: ['album', 'camera'],
- success: (res) => {
- const newImages = [...this.data.newImages, ...res.tempFilePaths]
- this.setData({ newImages: newImages.slice(0, 9) })
- }
- })
- },
- getCurrentImageCount() {
- const { remainingOriginals, newImages } = this.data
- return remainingOriginals.length + newImages.length
- },
- onModifyLiuyanInput(e) {
- this.setData({ modifiedLiuyan: e.detail.value.slice(0, 50) })
- },
-
- async confirmModify() {
- if (this.data.isConfirming) return
- const { dingdan_id } = this.data.jibenShuju
- const { remainingOriginals, deletedImages, newImages, modifiedLiuyan, originalDashouLiuyan } = this.data
- const hasLiuyanChange = modifiedLiuyan !== originalDashouLiuyan
- const hasDelete = deletedImages.length > 0
- const hasAdd = newImages.length > 0
-
- if (!hasLiuyanChange && !hasDelete && !hasAdd) {
- wx.showToast({ title: '没有修改内容', icon: 'none' })
- return
- }
-
- const finalImageCount = remainingOriginals.length + newImages.length
- if (finalImageCount === 0) {
- wx.showToast({ title: '至少保留一张图片', icon: 'none' })
- return
- }
-
- this.setData({ isConfirming: true })
- wx.showLoading({ title: '提交修改...', mask: true })
- try {
- const tokenData = await this.getCOSZhengshu()
- const { cos, bucket, region } = this.initCOSClient(tokenData)
-
- let newImageRelativePaths = []
- if (hasAdd) {
- const total = newImages.length
- this.setData({ 'modifyUploadProgress.total': total, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' })
- const preGeneratedKeys = []
- for (let i = 0; i < total; i++) {
- const timestamp = Date.now() + i
- const random = Math.floor(Math.random() * 10000)
- const fileExt = this.getFileExtension(newImages[i])
- const fileName = `${timestamp}_${random}${fileExt}`
- const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}`
- preGeneratedKeys.push(cosKey)
- }
- const uploadTasks = []
- for (let i = 0; i < total; i++) {
- const task = this.shangchuanDanZhangTupian(
- newImages[i],
- preGeneratedKeys[i],
- i,
- cos,
- bucket,
- region
- ).then((result) => {
- const currentDone = i + 1
- const jinduPercent = ((currentDone / total) * 100).toFixed(0)
- this.setData({
- 'modifyUploadProgress.current': currentDone,
- 'modifyUploadProgress.width': `${jinduPercent}%`
- })
- return result.key
- })
- uploadTasks.push(task)
- }
- wx.showLoading({ title: `上传中...`, mask: true })
- newImageRelativePaths = await Promise.all(uploadTasks)
- wx.hideLoading()
- this.setData({ 'modifyUploadProgress.total': 0, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' })
- }
-
- const deletedRelativePaths = deletedImages.map(fullUrl => this.extractRelativePath(fullUrl))
-
- const res = await request({
- url: '/dingdan/dsxiugaidd',
- method: 'POST',
- data: {
- dingdan_id,
- liuyan: modifiedLiuyan,
- deleted_images: deletedRelativePaths,
- new_images: newImageRelativePaths
- },
- header: { 'content-type': 'application/json' }
- })
- wx.hideLoading()
- this.setData({ isConfirming: false })
- if (res && res.data.code === 0) {
- const ossImageUrl = this.data.ossImageUrl
- const newFullUrls = newImageRelativePaths.map(rel => ossImageUrl + rel)
- const newDashouJiaofu = [...remainingOriginals, ...newFullUrls]
- this.setData({
- 'xiangxiShuju.dashou_jiaofu': newDashouJiaofu,
- 'xiangxiShuju.dashou_liuyan': modifiedLiuyan,
- isModifying: false,
- originalDashouJiaofu: [],
- remainingOriginals: [],
- originalDashouLiuyan: '',
- deletedImages: [],
- newImages: [],
- modifiedLiuyan: ''
- })
- wx.showToast({ title: '修改成功', icon: 'success' })
- } else {
- const errorMsg = res?.data?.msg || '修改失败'
- wx.showToast({ title: errorMsg, icon: 'none' })
- }
- } catch (error) {
- console.error('修改失败:', error)
- wx.hideLoading()
- this.setData({ isConfirming: false })
- wx.showToast({ title: error.message || '修改失败', icon: 'none' })
- }
- }
+// pages/fighter-order-detail/fighter-order-detail.js - 【最终版:提交前公告弹窗 + 修改图片至少保留一张】
+const app = getApp()
+import request from '../../utils/request.js'
+import connectionManager from '../../utils/xiaoxilj.js'
+const COS = require('../../utils/cos-wx-sdk-v5.min.js')
+
+Page({
+ data: {
+ jibenShuju: {
+ dingdan_id: '',
+ tupian: '',
+ jieshao: '',
+ create_time: '',
+ jine: '',
+ nicheng: '',
+ beizhu: '',
+ zhuangtai: 0,
+ fadanpingtai: 0
+ },
+ xiangxiShuju: {
+ shangjia_id: '',
+ shangjia_nicheng: '',
+ shangjia_liuyan: '',
+ tuikuan_liyou: '',
+ chufa_liyou: '',
+ chufa_zhuangtai: 0,
+ chufa_jieguo: '',
+ bohui_liyou: '',
+ dashou_jiaofu: [],
+ dashou_liuyan: '',
+ laoban_id: ''
+ },
+ zhuangtaiYanseMap: {
+ 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0',
+ 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1'
+ },
+ zhuangtaiWenziMap: {
+ 1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中',
+ 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中'
+ },
+ isLoading: true,
+ isSubmitting: false,
+ liuyan: '',
+ xuanzhongTupian: [],
+ shangchuanJindu: 0,
+ shangchuanZongshu: 0,
+ jinduWidth: '0%',
+ showWanzhengJieshao: false,
+ wanzhengJieshao: '',
+ showWanzhengBeizhu: false,
+ wanzhengBeizhu: '',
+ ossImageUrl: '',
+ morentouxiang: '',
+ showRefundInfo: false,
+
+ // 修改功能所需字段
+ isModifying: false,
+ originalDashouJiaofu: [],
+ originalDashouLiuyan: '',
+ remainingOriginals: [],
+ modifiedLiuyan: '',
+ deletedImages: [],
+ newImages: [],
+ isConfirming: false,
+ modifyUploadProgress: { total: 0, current: 0, width: '0%' }
+ },
+
+ onLoad(options) {
+ wx.setNavigationBarTitle({ title: '订单详情' })
+ this.initGlobalData()
+ this.jiexiTiaozhuanCanshu(options)
+ },
+ onHide() {
+ const popupComp = this.selectComponent('#popupNotice');
+ if (popupComp && popupComp.cleanup) {
+ popupComp.cleanup();
+ }
+ },
+
+ onShow() {
+ this.registerNotificationComponent();
+ },
+
+ registerNotificationComponent() {
+ const app = getApp();
+ const notificationComp = this.selectComponent('#global-notification');
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification()
+ };
+ }
+ },
+
+ initGlobalData() {
+ const app = getApp()
+ const ossImageUrl = app.globalData.ossImageUrl || 'https://your-oss-domain.com/'
+ const morentouxiang = app.globalData.morentouxiang || '/images/default-avatar.png'
+ this.setData({ ossImageUrl, morentouxiang })
+ },
+
+ jiexiTiaozhuanCanshu(options) {
+ try {
+ const dingdanDataStr = options.dingdanData || ''
+ if (!dingdanDataStr) {
+ wx.showToast({ title: '订单数据错误', icon: 'none' })
+ setTimeout(() => wx.navigateBack(), 1500)
+ return
+ }
+ const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr))
+ let tupianUrl = dingdanData.tupian || ''
+ if (!tupianUrl) tupianUrl = this.getTupianUrl()
+ let jine = parseFloat(dingdanData.jine || 0)
+ if (isNaN(jine)) jine = 0
+ const formattedJine = jine.toFixed(2)
+ this.setData({
+ 'jibenShuju.dingdan_id': dingdanData.dingdan_id || '',
+ 'jibenShuju.tupian': tupianUrl,
+ 'jibenShuju.jieshao': dingdanData.jieshao || '',
+ 'jibenShuju.create_time': dingdanData.create_time || '',
+ 'jibenShuju.jine': formattedJine,
+ 'jibenShuju.nicheng': dingdanData.nicheng || '',
+ 'jibenShuju.beizhu': dingdanData.beizhu || '',
+ 'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0,
+ 'jibenShuju.fadanpingtai': dingdanData.fadanpingtai || 0,
+ isLoading: false
+ })
+ this.jiazaiXiangxiShuju(dingdanData.dingdan_id)
+ } catch (error) {
+ console.error('解析订单数据失败:', error)
+ wx.showToast({ title: '数据解析失败', icon: 'none' })
+ setTimeout(() => wx.navigateBack(), 1500)
+ }
+ },
+
+ getTupianUrl() {
+ const cacheTouxiang = wx.getStorageSync('touxiang') || ''
+ let tupianPath = cacheTouxiang || app.globalData.morentouxiang || ''
+ const ossImageUrl = app.globalData.ossImageUrl || ''
+ if (tupianPath && ossImageUrl) {
+ if (tupianPath.startsWith('/')) tupianPath = tupianPath.substring(1)
+ return ossImageUrl + tupianPath
+ }
+ return ''
+ },
+
+ async jiazaiXiangxiShuju(dingdanId) {
+ if (!dingdanId) return
+ wx.showLoading({ title: '加载中...', mask: true })
+ try {
+ const res = await request({
+ url: '/dingdan/dsddxq',
+ method: 'POST',
+ data: { dingdan_id: dingdanId },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ if (res && res.data.code === 0 && res.data.data) {
+ const data = res.data.data
+ let dashouJiaofuList = data.dashou_jiaofu || []
+ dashouJiaofuList = dashouJiaofuList.map(imgUrl => {
+ if (imgUrl && !imgUrl.startsWith('http')) {
+ const ossImageUrl = app.globalData.ossImageUrl || ''
+ if (imgUrl.startsWith('/')) imgUrl = imgUrl.substring(1)
+ return ossImageUrl + imgUrl
+ }
+ return imgUrl
+ })
+ this.setData({
+ 'xiangxiShuju.shangjia_id': data.shangjia_id || '',
+ 'xiangxiShuju.shangjia_nicheng': data.shangjia_nicheng || '',
+ 'xiangxiShuju.shangjia_liuyan': data.shangjia_liuyan || '',
+ 'xiangxiShuju.tuikuan_liyou': data.tuikuan_liyou || '',
+ 'xiangxiShuju.chufa_liyou': data.chufa_liyou || '',
+ 'xiangxiShuju.chufa_zhuangtai': data.chufa_zhuangtai || 0,
+ 'xiangxiShuju.chufa_jieguo': data.chufa_jieguo || '',
+ 'xiangxiShuju.bohui_liyou': data.bohui_liyou || '',
+ 'xiangxiShuju.dashou_jiaofu': dashouJiaofuList,
+ 'xiangxiShuju.dashou_liuyan': data.dashou_liuyan || '',
+ 'xiangxiShuju.laoban_id': data.laoban_id || '',
+ 'jibenShuju.zhuangtai': data.zhuangtai || 0,
+ 'jibenShuju.beizhu': data.beizhu || '',
+ 'liuyan': data.dashou_liuyan || '',
+ 'jibenShuju.fadanpingtai': data.fadanpingtai || 0
+ })
+ const currentStatus = data.zhuangtai || 0
+ const showRefund = [4,5,6].includes(currentStatus)
+ this.setData({ showRefundInfo: showRefund })
+ } else {
+ const errorMsg = res?.data?.msg || '获取订单详情失败'
+ wx.showToast({ title: errorMsg, icon: 'none', duration: 2000 })
+ }
+ } catch (error) {
+ console.error('加载详细数据失败:', error)
+ wx.hideLoading()
+ wx.showToast({ title: '加载数据失败,请重试', icon: 'none', duration: 2000 })
+ }
+ },
+
+ // ========== 原有提交功能(部分修改) ==========
+ xuanzeTupian() {
+ if (this.data.isSubmitting) return
+ const shengyu = 9 - this.data.xuanzhongTupian.length
+ if (shengyu <= 0) {
+ wx.showToast({ title: '最多只能选择9张图片', icon: 'none' })
+ return
+ }
+ wx.chooseImage({
+ count: shengyu,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const newTupian = [...this.data.xuanzhongTupian, ...res.tempFilePaths]
+ this.setData({ xuanzhongTupian: newTupian.slice(0, 9) })
+ }
+ })
+ },
+ shanchuTupian(e) {
+ const index = e.currentTarget.dataset.index
+ const newTupian = [...this.data.xuanzhongTupian]
+ newTupian.splice(index, 1)
+ this.setData({ xuanzhongTupian: newTupian })
+ },
+ yulanTupian(e) {
+ const currentUrl = e.currentTarget.dataset.url
+ const urls = e.currentTarget.dataset.urls || []
+ if (!currentUrl) return
+ wx.previewImage({ current: currentUrl, urls: urls.length > 0 ? urls : [currentUrl] })
+ },
+ getFileExtension(filePath) {
+ const lastDotIndex = filePath.lastIndexOf('.')
+ if (lastDotIndex === -1) return '.jpg'
+ const ext = filePath.substring(lastDotIndex).toLowerCase()
+ const allowedExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
+ return allowedExts.includes(ext) ? ext : '.jpg'
+ },
+ shuruLiuyan(e) {
+ const liuyan = e.detail.value.slice(0, 50)
+ this.setData({ liuyan })
+ },
+ chakanWanzhengJieshao() {
+ this.setData({ showWanzhengJieshao: true, wanzhengJieshao: this.data.jibenShuju.jieshao || '无' })
+ },
+ guanbiWanzhengJieshao() { this.setData({ showWanzhengJieshao: false }) },
+ chakanWanzhengBeizhu() {
+ this.setData({ showWanzhengBeizhu: true, wanzhengBeizhu: this.data.jibenShuju.beizhu || '无' })
+ },
+ guanbiWanzhengBeizhu() { this.setData({ showWanzhengBeizhu: false }) },
+ async fuzhiWenben(e) {
+ const text = e.currentTarget.dataset.text
+ if (!text) return
+ try {
+ await wx.setClipboardData({ data: text })
+ wx.showToast({ title: '复制成功', icon: 'success', duration: 1500 })
+ } catch (error) {
+ console.error('复制失败:', error)
+ wx.showToast({ title: '复制失败', icon: 'none' })
+ }
+ },
+ goToKefu() {
+ const kefuLink = app.globalData.kefuConfig?.link || '';
+ const corpId = app.globalData.kefuConfig?.enterpriseId || '';
+
+ if (!kefuLink || !corpId) {
+ wx.showToast({
+ title: '客服配置未加载',
+ icon: 'none'
+ });
+ return;
+ }
+
+ wx.openCustomerServiceChat({
+ extInfo: { url: kefuLink },
+ corpId: corpId,
+ success: (res) => {
+ console.log('跳转客服成功', res);
+ },
+ fail: (err) => {
+ console.error('跳转客服失败', err);
+ wx.showToast({
+ title: '暂时无法连接客服',
+ icon: 'none'
+ });
+ }
+ });
+ },
+
+ // ===== 联系老板/商家(配对群 group_Ds{打手}_Sj/Boss{对方}) =====
+ goToChatWithBoss() {
+ const uid = wx.getStorageSync('uid')
+ if (!uid) {
+ wx.showToast({ title: '用户信息缺失', icon: 'none' })
+ return
+ }
+
+ const orderId = this.data.jibenShuju.dingdan_id
+ if (!orderId) {
+ wx.showToast({ title: '订单ID缺失', icon: 'none' })
+ return
+ }
+
+ const fadanPingtai = this.data.jibenShuju.fadanpingtai || 0
+ const partnerUid = fadanPingtai === 2
+ ? (this.data.xiangxiShuju.shangjia_id || '')
+ : (this.data.xiangxiShuju.laoban_id || '')
+
+ connectionManager.connectToGroupChat({
+ identityType: 'dashou',
+ userId: 'Ds' + uid,
+ orderId: orderId,
+ partnerUid,
+ fadanPingtai,
+ groupName: (this.data.jibenShuju.nicheng || '订单') + '的订单群',
+ isCross: this.data.jibenShuju.fadanpingtai || 0,
+ }).catch((err) => {
+ console.error('跳转群聊失败', err)
+ wx.showToast({ title: '跳转聊天失败', icon: 'none' })
+ })
+ },
+
+ async getCOSZhengshu() {
+ try {
+ const res = await request({
+ url: '/dingdan/dsscpz',
+ method: 'POST',
+ data: { dingdan_id: this.data.jibenShuju.dingdan_id }
+ })
+ if (res && res.data.code === 0 && res.data.data) return res.data.data
+ else throw new Error(res?.data?.msg || '获取上传凭证失败')
+ } catch (error) {
+ console.error('获取COS凭证失败:', error)
+ throw error
+ }
+ },
+
+ initCOSClient(tokenData) {
+ const credentials = tokenData.credentials || tokenData
+ const bucket = tokenData.bucket || 'julebu-1361527063'
+ const region = tokenData.region || 'ap-shanghai'
+ const cos = new COS({
+ SimpleUploadMethod: 'putObject',
+ getAuthorization: async (options, callback) => {
+ const authParams = {
+ TmpSecretId: credentials.tmpSecretId,
+ TmpSecretKey: credentials.tmpSecretKey,
+ SecurityToken: credentials.sessionToken || '',
+ StartTime: tokenData.startTime || Math.floor(Date.now() / 1000),
+ ExpiredTime: tokenData.expiredTime || (Math.floor(Date.now() / 1000) + 7200)
+ }
+ callback(authParams)
+ }
+ })
+ return { cos, bucket, region }
+ },
+
+ async shangchuanDanZhangTupian(filePath, cosKey, index, cosInstance, bucket, region) {
+ return new Promise((resolve) => {
+ const timeoutId = setTimeout(() => resolve({ status: 'optimistic_success', key: cosKey }), 2000)
+ cosInstance.uploadFile({
+ Bucket: bucket,
+ Region: region,
+ Key: cosKey,
+ FilePath: filePath,
+ onProgress: (progressInfo) => {
+ const percent = Math.round(progressInfo.percent * 100)
+ if (percent === 100) {
+ clearTimeout(timeoutId)
+ resolve({ status: 'optimistic_success', key: cosKey })
+ }
+ }
+ })
+ })
+ },
+
+ async piliangShangchuanTupian() {
+ const total = this.data.xuanzhongTupian.length
+ this.setData({ shangchuanZongshu: total, shangchuanJindu: 0, jinduWidth: '0%' })
+ wx.showLoading({ title: '正在准备...', mask: true })
+ const preGeneratedUrls = []
+ for (let i = 0; i < total; i++) {
+ const timestamp = Date.now() + i
+ const random = Math.floor(Math.random() * 10000)
+ const fileExt = this.getFileExtension(this.data.xuanzhongTupian[i])
+ const fileName = `${timestamp}_${random}${fileExt}`
+ const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}`
+ preGeneratedUrls.push(cosKey)
+ }
+ let cosClient, bucket, region
+ try {
+ const tokenData = await this.getCOSZhengshu()
+ const { cos, bucket: cosBucket, region: cosRegion } = this.initCOSClient(tokenData)
+ cosClient = cos
+ bucket = cosBucket
+ region = cosRegion
+ } catch (error) {
+ wx.hideLoading()
+ wx.showToast({ title: '上传初始化失败', icon: 'none' })
+ return []
+ }
+ const uploadTasks = []
+ for (let i = 0; i < total; i++) {
+ const task = this.shangchuanDanZhangTupian(
+ this.data.xuanzhongTupian[i],
+ preGeneratedUrls[i],
+ i,
+ cosClient,
+ bucket,
+ region
+ ).then((result) => {
+ const currentDone = i + 1
+ const jinduPercent = ((currentDone / total) * 100).toFixed(0)
+ this.setData({ shangchuanJindu: currentDone, jinduWidth: `${jinduPercent}%` })
+ return result
+ })
+ uploadTasks.push(task)
+ }
+ wx.showLoading({ title: `上传中...`, mask: true })
+ await Promise.all(uploadTasks)
+ wx.hideLoading()
+ return preGeneratedUrls
+ },
+
+ tijiaoDingdan() {
+ this.showAnnouncementAndConfirm()
+ },
+
+ async showAnnouncementAndConfirm() {
+ try {
+ const res = await request({
+ url: '/peizhi/tanchuang',
+ method: 'POST',
+ data: { pageKey: 'dsddxq' }
+ })
+ if (res.statusCode !== 200 || res.data.code !== 0) {
+ this.showOriginalConfirmAndSubmit()
+ return
+ }
+ const { popups = [], serverTime } = res.data.data
+ if (!popups.length) {
+ this.showOriginalConfirmAndSubmit()
+ return
+ }
+ const popup = popups[0]
+ const popupComp = this.selectComponent('#popupNotice')
+ if (!popupComp) {
+ console.error('未找到弹窗组件 #popupNotice')
+ this.showOriginalConfirmAndSubmit()
+ return
+ }
+ const showData = {
+ popupId: popup.popup_id,
+ title: popup.title || '',
+ duration: popup.duration || 0,
+ images: popup.images || [],
+ showMuteCheckbox: false,
+ serverTime: serverTime
+ }
+ popupComp.show(showData, (result) => {
+ this.showOriginalConfirmAndSubmit()
+ })
+ } catch (error) {
+ console.error('获取公告配置失败', error)
+ this.showOriginalConfirmAndSubmit()
+ }
+ },
+
+ showOriginalConfirmAndSubmit() {
+ if (this.data.isSubmitting) {
+ wx.showToast({ title: '正在提交中', icon: 'none' })
+ return
+ }
+ if (this.data.jibenShuju.zhuangtai !== 2) {
+ wx.showToast({ title: '订单状态不可提交', icon: 'none' })
+ return
+ }
+ if (this.data.xuanzhongTupian.length === 0) {
+ wx.showToast({ title: '请至少上传一张图片', icon: 'none' })
+ return
+ }
+ wx.showModal({
+ title: '⚠️ 提交确认',
+ content: '在提交订单之前,请确保您已在接单员端页面认真阅读接单员规则。如有漏交图片,订单被退款,概不申诉。',
+ confirmText: '我已阅读',
+ cancelText: '我再想想',
+ success: (res) => {
+ if (res.confirm) this._doSubmit()
+ },
+ fail: (err) => {
+ console.error('弹窗失败', err)
+ wx.showToast({ title: '系统异常,请重试', icon: 'none' })
+ }
+ })
+ },
+
+ async _doSubmit() {
+ this.setData({ isSubmitting: true })
+ wx.showLoading({ title: '开始提交...', mask: true })
+ try {
+ const tupianUrls = await this.piliangShangchuanTupian()
+ if (!tupianUrls || tupianUrls.length === 0) throw new Error('无法生成上传路径')
+ wx.showLoading({ title: '提交订单数据...', mask: true })
+ const res = await request({
+ url: '/dingdan/dstijiao',
+ method: 'POST',
+ data: {
+ dingdan_id: this.data.jibenShuju.dingdan_id,
+ liuyan: this.data.liuyan || '',
+ jiaofu_tupian_urls: tupianUrls
+ },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isSubmitting: false })
+ if (res && res.data.code === 0) {
+ const ossImageUrl = app.globalData.ossImageUrl || ''
+ const fullUrls = tupianUrls.map(url => {
+ if (url && !url.startsWith('http')) {
+ if (url.startsWith('/')) url = url.substring(1)
+ return ossImageUrl + url
+ }
+ return url
+ })
+ this.setData({
+ 'jibenShuju.zhuangtai': 8,
+ 'xiangxiShuju.dashou_liuyan': this.data.liuyan || '',
+ 'xiangxiShuju.dashou_jiaofu': fullUrls,
+ xuanzhongTupian: [],
+ liuyan: '',
+ shangchuanJindu: 0,
+ shangchuanZongshu: 0,
+ jinduWidth: '0%',
+ })
+ if (app.globalData.dashouzhuangtai != 1) app.globalData.dashouzhuangtai = 1
+ wx.showToast({ title: '提交成功!', icon: 'success', duration: 2000 })
+ setTimeout(() => wx.navigateBack(), 1500)
+ } else {
+ const errorMsg = res?.data?.msg || '提交失败'
+ wx.showToast({ title: errorMsg, icon: 'none' })
+ }
+ } catch (error) {
+ console.error('提交失败:', error)
+ wx.hideLoading()
+ this.setData({ isSubmitting: false })
+ wx.showToast({ title: error.message || '提交失败', icon: 'none' })
+ }
+ },
+
+ // ========== 修改功能(增加最少一张图片校验) ==========
+ extractRelativePath(fullUrl) {
+ const ossImageUrl = this.data.ossImageUrl
+ if (fullUrl.startsWith(ossImageUrl)) return fullUrl.substring(ossImageUrl.length)
+ return fullUrl
+ },
+ enterModify() {
+ const { dashou_jiaofu, dashou_liuyan } = this.data.xiangxiShuju
+ this.setData({
+ isModifying: true,
+ originalDashouJiaofu: dashou_jiaofu.slice(),
+ remainingOriginals: dashou_jiaofu.slice(),
+ originalDashouLiuyan: dashou_liuyan || '',
+ modifiedLiuyan: dashou_liuyan || '',
+ deletedImages: [],
+ newImages: []
+ })
+ },
+ cancelModify() {
+ this.setData({
+ isModifying: false,
+ originalDashouJiaofu: [],
+ remainingOriginals: [],
+ originalDashouLiuyan: '',
+ modifiedLiuyan: '',
+ deletedImages: [],
+ newImages: []
+ })
+ },
+ handleDeleteImage(e) {
+ const fullUrl = e.currentTarget.dataset.url
+ const { originalDashouJiaofu, remainingOriginals, deletedImages, newImages } = this.data
+ if (originalDashouJiaofu.includes(fullUrl)) {
+ const newRemaining = remainingOriginals.filter(url => url !== fullUrl)
+ this.setData({
+ remainingOriginals: newRemaining,
+ deletedImages: [...deletedImages, fullUrl]
+ })
+ } else {
+ const index = newImages.indexOf(fullUrl)
+ if (index > -1) {
+ const newImagesCopy = [...newImages]
+ newImagesCopy.splice(index, 1)
+ this.setData({ newImages: newImagesCopy })
+ }
+ }
+ },
+ handleAddImage() {
+ if (this.data.isConfirming) return
+ const currentCount = this.getCurrentImageCount()
+ const maxCount = 9 - currentCount
+ if (maxCount <= 0) {
+ wx.showToast({ title: '最多9张图片', icon: 'none' })
+ return
+ }
+ wx.chooseImage({
+ count: maxCount,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const newImages = [...this.data.newImages, ...res.tempFilePaths]
+ this.setData({ newImages: newImages.slice(0, 9) })
+ }
+ })
+ },
+ getCurrentImageCount() {
+ const { remainingOriginals, newImages } = this.data
+ return remainingOriginals.length + newImages.length
+ },
+ onModifyLiuyanInput(e) {
+ this.setData({ modifiedLiuyan: e.detail.value.slice(0, 50) })
+ },
+
+ async confirmModify() {
+ if (this.data.isConfirming) return
+ const { dingdan_id } = this.data.jibenShuju
+ const { remainingOriginals, deletedImages, newImages, modifiedLiuyan, originalDashouLiuyan } = this.data
+ const hasLiuyanChange = modifiedLiuyan !== originalDashouLiuyan
+ const hasDelete = deletedImages.length > 0
+ const hasAdd = newImages.length > 0
+
+ if (!hasLiuyanChange && !hasDelete && !hasAdd) {
+ wx.showToast({ title: '没有修改内容', icon: 'none' })
+ return
+ }
+
+ const finalImageCount = remainingOriginals.length + newImages.length
+ if (finalImageCount === 0) {
+ wx.showToast({ title: '至少保留一张图片', icon: 'none' })
+ return
+ }
+
+ this.setData({ isConfirming: true })
+ wx.showLoading({ title: '提交修改...', mask: true })
+ try {
+ const tokenData = await this.getCOSZhengshu()
+ const { cos, bucket, region } = this.initCOSClient(tokenData)
+
+ let newImageRelativePaths = []
+ if (hasAdd) {
+ const total = newImages.length
+ this.setData({ 'modifyUploadProgress.total': total, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' })
+ const preGeneratedKeys = []
+ for (let i = 0; i < total; i++) {
+ const timestamp = Date.now() + i
+ const random = Math.floor(Math.random() * 10000)
+ const fileExt = this.getFileExtension(newImages[i])
+ const fileName = `${timestamp}_${random}${fileExt}`
+ const cosKey = `order/${this.data.jibenShuju.dingdan_id}/${fileName}`
+ preGeneratedKeys.push(cosKey)
+ }
+ const uploadTasks = []
+ for (let i = 0; i < total; i++) {
+ const task = this.shangchuanDanZhangTupian(
+ newImages[i],
+ preGeneratedKeys[i],
+ i,
+ cos,
+ bucket,
+ region
+ ).then((result) => {
+ const currentDone = i + 1
+ const jinduPercent = ((currentDone / total) * 100).toFixed(0)
+ this.setData({
+ 'modifyUploadProgress.current': currentDone,
+ 'modifyUploadProgress.width': `${jinduPercent}%`
+ })
+ return result.key
+ })
+ uploadTasks.push(task)
+ }
+ wx.showLoading({ title: `上传中...`, mask: true })
+ newImageRelativePaths = await Promise.all(uploadTasks)
+ wx.hideLoading()
+ this.setData({ 'modifyUploadProgress.total': 0, 'modifyUploadProgress.current': 0, 'modifyUploadProgress.width': '0%' })
+ }
+
+ const deletedRelativePaths = deletedImages.map(fullUrl => this.extractRelativePath(fullUrl))
+
+ const res = await request({
+ url: '/dingdan/dsxiugaidd',
+ method: 'POST',
+ data: {
+ dingdan_id,
+ liuyan: modifiedLiuyan,
+ deleted_images: deletedRelativePaths,
+ new_images: newImageRelativePaths
+ },
+ header: { 'content-type': 'application/json' }
+ })
+ wx.hideLoading()
+ this.setData({ isConfirming: false })
+ if (res && res.data.code === 0) {
+ const ossImageUrl = this.data.ossImageUrl
+ const newFullUrls = newImageRelativePaths.map(rel => ossImageUrl + rel)
+ const newDashouJiaofu = [...remainingOriginals, ...newFullUrls]
+ this.setData({
+ 'xiangxiShuju.dashou_jiaofu': newDashouJiaofu,
+ 'xiangxiShuju.dashou_liuyan': modifiedLiuyan,
+ isModifying: false,
+ originalDashouJiaofu: [],
+ remainingOriginals: [],
+ originalDashouLiuyan: '',
+ deletedImages: [],
+ newImages: [],
+ modifiedLiuyan: ''
+ })
+ wx.showToast({ title: '修改成功', icon: 'success' })
+ } else {
+ const errorMsg = res?.data?.msg || '修改失败'
+ wx.showToast({ title: errorMsg, icon: 'none' })
+ }
+ } catch (error) {
+ console.error('修改失败:', error)
+ wx.hideLoading()
+ this.setData({ isConfirming: false })
+ wx.showToast({ title: error.message || '修改失败', icon: 'none' })
+ }
+ }
})
\ No newline at end of file
diff --git a/pages/fighter-order-detail/fighter-order-detail.wxml b/pages/fighter-order-detail/fighter-order-detail.wxml
index 40790b3..47ff950 100644
--- a/pages/fighter-order-detail/fighter-order-detail.wxml
+++ b/pages/fighter-order-detail/fighter-order-detail.wxml
@@ -179,7 +179,7 @@
申请状态:
{{xiangxiShuju.chufa_zhuangtai == 0 ? '审核中' : (xiangxiShuju.chufa_zhuangtai == 1 ? '处罚成功' : '处罚驳回')}}
diff --git a/pages/fighter-order-detail/fighter-order-detail.wxss b/pages/fighter-order-detail/fighter-order-detail.wxss
index 2d7a8a8..a990b50 100644
--- a/pages/fighter-order-detail/fighter-order-detail.wxss
+++ b/pages/fighter-order-detail/fighter-order-detail.wxss
@@ -432,9 +432,9 @@
/* 🆕 新增:联系老板按钮 */
.boss-btn {
- background-color: #9333ea;
+ background-color: #ff9800;
color: #ffffff;
- box-shadow: 0 4rpx 15rpx rgba(147, 51, 234, 0.3);
+ box-shadow: 0 4rpx 15rpx rgba(255, 152, 0, 0.3);
}
/* 🆕 新增:修改按钮(黑色) */
diff --git a/pages/fighter-orders/fighter-orders.js b/pages/fighter-orders/fighter-orders.js
index 189638b..9a6ca25 100644
--- a/pages/fighter-orders/fighter-orders.js
+++ b/pages/fighter-orders/fighter-orders.js
@@ -19,7 +19,7 @@ Page(createPage({
statusList: [
{ name: '全部', key: 'all', zhuangtaiList: [], color: '#333333' },
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
- { name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#9333ea' },
+ { name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#FF9800' },
{ name: '已退款', key: 'yituikuan', zhuangtaiList: [5], color: '#9E9E9E' },
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
@@ -49,18 +49,43 @@ Page(createPage({
onLoad() {
wx.setNavigationBarTitle({ title: '我的接单' });
- this.loadShangpinLeixing();
+ this.loadShangpinLeixing().then(() => {
+ if (this.data.xuanzhongLeixingId) {
+ return this.loadCurrentStatusOrders(true);
+ }
+ }).finally(() => {
+ this._ordersSessionReady = true;
+ this._skipShowRefresh = true;
+ });
this.registerNotificationComponent();
},
onShow() {
this.registerNotificationComponent();
+ const app = getApp();
+ const filterKey = app.globalData._fighterOrdersStatusKey;
+ if (filterKey) {
+ app.globalData._fighterOrdersStatusKey = null;
+ if (this.data.statusList.some((s) => s.key === filterKey)) {
+ this.setData({ currentStatusKey: filterKey });
+ }
+ if (this.data.xuanzhongLeixingId) {
+ this.loadCurrentStatusOrders(true);
+ }
+ }
if (wx.getStorageSync('uid')) {
reconnectForRole('dashou');
if (app.startImWhenReady) app.startImWhenReady();
}
- if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
- this.loadCurrentStatusOrders(true);
+ if (this._skipShowRefresh) {
+ this._skipShowRefresh = false;
+ return;
+ }
+ if (this._ordersSessionReady && this.data.xuanzhongLeixingId && !this._silentRefreshRunning) {
+ this._silentRefreshRunning = true;
+ this.loadCurrentStatusOrders(true, true).finally(() => {
+ this._silentRefreshRunning = false;
+ });
}
},
@@ -141,17 +166,21 @@ Page(createPage({
},
// 加载订单(核心)
- async loadCurrentStatusOrders(isRefresh = false) {
+ async loadCurrentStatusOrders(isRefresh = false, silent = false) {
const key = this.data.currentStatusKey;
const tabData = this.data.dsDingdanShuju[key];
- if (tabData.isLoading) return;
+ if (tabData.isLoading && !silent) return;
+ if (silent && this._listRequesting) return;
const page = isRefresh ? 1 : tabData.page;
- this.setData({
- [`dsDingdanShuju.${key}.isLoading`]: true,
- isLoading: true,
- isLoadingMore: !isRefresh
- });
+ if (!silent) {
+ this.setData({
+ [`dsDingdanShuju.${key}.isLoading`]: true,
+ isLoading: true,
+ isLoadingMore: !isRefresh,
+ });
+ }
+ this._listRequesting = true;
try {
const apiUrl = this.data.orderType === 'peihu'
@@ -208,14 +237,20 @@ Page(createPage({
}
} catch (err) {
console.error('加载订单失败', err);
- wx.showToast({ title: err.message || '加载失败', icon: 'none' });
- this.setData({
- [`dsDingdanShuju.${key}.isLoading`]: false,
- isLoading: false,
- isLoadingMore: false,
- scrollViewRefreshing: false
- });
- this.refreshCurrentListView();
+ if (!silent) {
+ wx.showToast({ title: err.message || '加载失败', icon: 'none' });
+ }
+ if (!silent) {
+ this.setData({
+ [`dsDingdanShuju.${key}.isLoading`]: false,
+ isLoading: false,
+ isLoadingMore: false,
+ scrollViewRefreshing: false
+ });
+ this.refreshCurrentListView();
+ }
+ } finally {
+ this._listRequesting = false;
}
},
diff --git a/pages/fighter-orders/fighter-orders.json b/pages/fighter-orders/fighter-orders.json
index 60b86d2..44bcb57 100644
--- a/pages/fighter-orders/fighter-orders.json
+++ b/pages/fighter-orders/fighter-orders.json
@@ -1,6 +1,7 @@
{
"usingComponents": {
- "global-notification": "/components/global-notification/global-notification"
+ "global-notification": "/components/global-notification/global-notification",
+ "tab-bar": "/tab-bar/index"
},
"navigationBarTitleText": "我的接单",
"enablePullDownRefresh": false,
diff --git a/pages/fighter-orders/fighter-orders.wxss b/pages/fighter-orders/fighter-orders.wxss
index a523181..c8bb5ed 100644
--- a/pages/fighter-orders/fighter-orders.wxss
+++ b/pages/fighter-orders/fighter-orders.wxss
@@ -346,4 +346,5 @@ page {
color: #999;
}
-@import '../../styles/dashou-xym-orders-theme.wxss';
\ No newline at end of file
+@import '../../styles/dashou-xym-orders-theme.wxss';
+@import '../../styles/dashou-xym-orders-page.wxss';
\ No newline at end of file
diff --git a/pages/fighter-rank/fighter-rank.js b/pages/fighter-rank/fighter-rank.js
index baac5bf..111cd33 100644
--- a/pages/fighter-rank/fighter-rank.js
+++ b/pages/fighter-rank/fighter-rank.js
@@ -1,119 +1,121 @@
-/**
- * 鎺掕姒? * 榛樿 POST /yonghu/phbhqsj
- * 鏄熶箣鐣?xzj) POST /yonghu/xzjphbhqsj锛堥個璇蜂汉鏁版帓搴忕瓑涓撶敤瑙勫垯锛? */
+/**
+ * 排行榜
+ * 默认 POST /yonghu/phbhqsj
+ * 星之界(xzj) POST /yonghu/xzjphbhqsj(邀请人数排序等专用规则)
+ */
import request from '../../utils/request.js'
import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js'
import { CLUB_ID } from '../../config/club-config.js'
const IS_XZJ = CLUB_ID === 'xzj'
const RANK_API = IS_XZJ ? '/yonghu/xzjphbhqsj' : '/yonghu/phbhqsj'
-const CLOSED_DATES = ['鏄ㄦ棩', '涓婂懆', '涓婃湀']
+const CLOSED_DATES = ['昨日', '上周', '上月']
const ROLE_LIST = [
- { key: 'dashou', label: '鎺ュ崟鍛? },
- { key: 'guanshi', label: '绠′簨' },
- { key: 'zuzhang', label: '缁勯暱' },
- { key: 'shangjia', label: '鍟嗗' },
+ { key: 'dashou', label: '接单员' },
+ { key: 'guanshi', label: '管事' },
+ { key: 'zuzhang', label: '组长' },
+ { key: 'shangjia', label: '商家' },
]
const DATE_LIST = [
- { key: '浠婃棩', label: '浠婃棩' },
- { key: '鏄ㄦ棩', label: '鏄ㄦ棩' },
- { key: '鏈懆', label: '鏈懆' },
- { key: '涓婂懆', label: '涓婂懆' },
- { key: '鏈湀', label: '鏈湀' },
- { key: '涓婃湀', label: '涓婃湀' },
- { key: '鎬绘', label: '鎬绘' },
+ { key: '今日', label: '今日' },
+ { key: '昨日', label: '昨日' },
+ { key: '本周', label: '本周' },
+ { key: '上周', label: '上周' },
+ { key: '本月', label: '本月' },
+ { key: '上月', label: '上月' },
+ { key: '总榜', label: '总榜' },
]
const ROLE_META = {
dashou: {
- title: '鎺ュ崟鍛樻帓琛屾',
+ title: '接单员排行榜',
sortField: 'chengjiao_zonge',
- sortLabel: '鍒嗙孩鎬婚',
+ sortLabel: '分红总额',
mainType: 'money',
metrics: [
- { field: 'jiedan_zongliang', label: '鎺ュ崟閲?, type: 'int' },
- { field: 'jiedan_zonge', label: '鎺ュ崟棰?, type: 'money' },
- { field: 'chengjiao_zongliang', label: '鎴愪氦閲?, type: 'int' },
+ { field: 'jiedan_zongliang', label: '接单量', type: 'int' },
+ { field: 'jiedan_zonge', label: '接单额', type: 'money' },
+ { field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
],
},
guanshi: {
- title: '绠′簨鎺掕姒?,
+ title: '管事排行榜',
sortField: 'shouru_zonge',
- sortLabel: '鏀跺叆鎬婚',
+ sortLabel: '收入总额',
mainType: 'money',
metrics: [
- { field: 'yaoqing_dashou_shu', label: '閭€璇?, type: 'int' },
- { field: 'chongzhi_dashou_shu', label: '鍏呭€?, type: 'int' },
+ { field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' },
+ { field: 'chongzhi_dashou_shu', label: '充值', type: 'int' },
],
},
zuzhang: {
- title: '缁勯暱鎺掕姒?,
+ title: '组长排行榜',
sortField: 'shouru_zonge',
- sortLabel: '鏀跺叆鎬婚',
+ sortLabel: '收入总额',
mainType: 'money',
metrics: [
- { field: 'yaoqing_guanshi_shu', label: '閭€璇?, type: 'int' },
- { field: 'fenyong_jine', label: '鍒嗕剑', type: 'money' },
+ { field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' },
+ { field: 'fenyong_jine', label: '分佣', type: 'money' },
],
},
shangjia: {
- title: '鍟嗗鎺掕姒?,
+ title: '商家排行榜',
sortField: 'jiesuan_jine',
- sortLabel: '鎴愪氦鎬婚',
+ sortLabel: '成交总额',
mainType: 'money',
metrics: [
- { field: 'jiesuan_dingdan_shu', label: '鎴愪氦閲?, type: 'int' },
- { field: 'paifa_dingdan_shu', label: '娲惧崟閲?, type: 'int' },
- { field: 'paifa_jine', label: '娲惧崟棰?, type: 'money' },
+ { field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' },
+ { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
+ { field: 'paifa_jine', label: '派单额', type: 'money' },
],
},
}
-/** 鏄熶箣鐣屼笓鐢ㄥ睍绀轰笌鎺掑簭瀛楁 */
+/** 星之界专用展示与排序字段 */
const XZJ_ROLE_META = {
dashou: {
- title: '鎺ュ崟鍛樻帓琛屾',
+ title: '接单员排行榜',
sortField: 'chengjiao_zonge',
- sortLabel: '鎴愪氦閲戦',
+ sortLabel: '成交金额',
mainType: 'money',
metrics: [
- { field: 'jiedan_zongliang', label: '鎺ュ崟閲?, type: 'int' },
- { field: 'jiedan_zonge', label: '鎺ュ崟棰?, type: 'money' },
- { field: 'chengjiao_zongliang', label: '鎴愪氦閲?, type: 'int' },
+ { field: 'jiedan_zongliang', label: '接单量', type: 'int' },
+ { field: 'jiedan_zonge', label: '接单额', type: 'money' },
+ { field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
],
},
guanshi: {
- title: '绠′簨鎺掕姒?,
+ title: '管事排行榜',
sortField: 'chongzhi_dashou_shu',
- sortLabel: '鏈夋晥浜烘暟',
+ sortLabel: '有效人数',
mainType: 'int',
metrics: [
- { field: 'wuxiao_yaoqing_dashou_shu', label: '鏃犳晥閭€璇?, type: 'int' },
- { field: 'yaoqing_dashou_shu', label: '閭€璇蜂汉鏁?, type: 'int' },
- { field: 'shouru_zonge', label: '鏀剁泭鎬婚', type: 'money' },
+ { field: 'wuxiao_yaoqing_dashou_shu', label: '无效邀请', type: 'int' },
+ { field: 'yaoqing_dashou_shu', label: '邀请人数', type: 'int' },
+ { field: 'shouru_zonge', label: '收益总额', type: 'money' },
],
},
zuzhang: {
- title: '缁勯暱鎺掕姒?,
+ title: '组长排行榜',
sortField: 'shouru_zonge',
- sortLabel: '鏀剁泭鎬婚',
+ sortLabel: '收益总额',
mainType: 'money',
metrics: [
- { field: 'wuxiao_yaoqing_guanshi_shu', label: '鏃犳晥閭€璇?, type: 'int' },
- { field: 'youxiao_guanshi_shu', label: '鏈夋晥浜烘暟', type: 'int' },
- { field: 'yaoqing_guanshi_shu', label: '閭€璇蜂汉鏁?, type: 'int' },
+ { field: 'wuxiao_yaoqing_guanshi_shu', label: '无效邀请', type: 'int' },
+ { field: 'youxiao_guanshi_shu', label: '有效人数', type: 'int' },
+ { field: 'yaoqing_guanshi_shu', label: '邀请人数', type: 'int' },
],
},
shangjia: {
- title: '鍟嗗鎺掕姒?,
+ title: '商家排行榜',
sortField: 'paifa_jine',
- sortLabel: '娲惧崟娴佹按',
+ sortLabel: '派单流水',
mainType: 'money',
metrics: [
- { field: 'paifa_dingdan_shu', label: '娲惧崟閲?, type: 'int' },
- { field: 'paifa_jine', label: '娲惧崟娴佹按', type: 'money' },
+ { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
+ { field: 'paifa_jine', label: '派单流水', type: 'money' },
],
},
}
@@ -143,11 +145,12 @@ Page({
roleList: ROLE_LIST,
dateList: DATE_LIST,
currentRole: 'dashou',
- currentDate: '浠婃棩',
+ currentDate: '今日',
fanwei: 'club',
- showJituanScope: false, // 涓存椂闅愯棌闆嗗洟鎬绘锛屾仮澶嶆椂鏀?true 骞惰皟鏁?fanwei 榛樿鍊? myClubId: CLUB_ID || 'xq',
+ showJituanScope: false, // 临时隐藏集团总榜,恢复时改 true 并调整 fanwei 默认值
+ myClubId: CLUB_ID || 'xq',
roleMeta: ROLE_META.dashou,
- sortLabel: '鍒嗙孩鎬婚',
+ sortLabel: '分红总额',
isLoading: true,
rankList: [],
topThree: [],
@@ -183,7 +186,7 @@ Page({
})
},
- /** 涓?app.js 涓€鑷达細ossImageUrl + morentouxiang锛岄厤缃紓姝ュ姞杞藉悗 onShow 鍐嶅悓姝?*/
+ /** 与 app.js 一致:ossImageUrl + morentouxiang,配置异步加载后 onShow 再同步 */
syncDefaultAvatar() {
const def = getDefaultAvatar()
if (def && def !== this.data.defaultAvatar) {
@@ -193,7 +196,7 @@ Page({
}
},
- /** 閰嶇疆鏅氫簬椤甸潰鍔犺浇鏃讹紝琛ュ叏绌哄ご鍍?*/
+ /** 配置晚于页面加载时,补全空头像 */
ensureAvatars() {
const def = getDefaultAvatar()
if (!def) return
@@ -223,7 +226,7 @@ Page({
applyRole(role, reload = true) {
const meta = ACTIVE_ROLE_META[role]
- wx.setNavigationBarTitle({ title: '鎬绘帓琛屾' })
+ wx.setNavigationBarTitle({ title: '总排行榜' })
this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel })
if (reload) this.fetchRankList()
},
@@ -252,19 +255,19 @@ Page({
onShowRules() {
const r = this.data.rewardInfo
if (!r || !r.tiers || !r.tiers.length) {
- wx.showToast({ title: '鏆傛棤濂栧姳瑙勫垯', icon: 'none' })
+ wx.showToast({ title: '暂无奖励规则', icon: 'none' })
return
}
const lines = r.tiers.map((t) => {
- const label = t.label || `绗?{t.rank_from}${t.rank_to > t.rank_from ? '-' + t.rank_to : ''}鍚峘
- return `${label}锛毬?{t.amount}`
+ const label = t.label || `第${t.rank_from}${t.rank_to > t.rank_from ? '-' + t.rank_to : ''}名`
+ return `${label}:¥${t.amount}`
})
- const tip = r.period_status === 'open' ? '锛堟湰鏈熻繘琛屼腑锛岀粨鏉熷悗鍙鍙栵級' : ''
+ const tip = r.period_status === 'open' ? '(本期进行中,结束后可领取)' : ''
wx.showModal({
- title: `${r.title || '鎺掕姒滃鍔?}${tip}`,
+ title: `${r.title || '排行榜奖励'}${tip}`,
content: [
- `淇变箰閮細${r.club_id || this.data.myClubId}`,
- `鎺掑簭锛?{r.sort_label || ''}`,
+ `俱乐部:${r.club_id || this.data.myClubId}`,
+ `排序:${r.sort_label || ''}`,
...lines,
r.description || '',
].filter(Boolean).join('\n'),
@@ -284,13 +287,13 @@ Page({
})
const body = res?.data || {}
if (body.code === 200) {
- wx.showToast({ title: `宸查鍙?楼${claim.amount}`, icon: 'success' })
+ wx.showToast({ title: `已领取 ¥${claim.amount}`, icon: 'success' })
await this.fetchRewardInfo()
} else {
- wx.showToast({ title: body.msg || '棰嗗彇澶辫触', icon: 'none' })
+ wx.showToast({ title: body.msg || '领取失败', icon: 'none' })
}
} catch (e) {
- wx.showToast({ title: '棰嗗彇澶辫触', icon: 'none' })
+ wx.showToast({ title: '领取失败', icon: 'none' })
} finally {
this.setData({ claimLoading: false })
}
@@ -314,7 +317,7 @@ Page({
const meta = ACTIVE_ROLE_META[role]
const app = getApp()
const uid = raw.yonghuid || raw.uid || ''
- const nicheng = raw.nicheng || raw.nick || (role === 'dashou' ? '鎵撴墜' : role === 'guanshi' ? '绠′簨' : role === 'zuzhang' ? '缁勯暱' : role === 'shangjia' ? '鍟嗗' : '鐢ㄦ埛')
+ const nicheng = raw.nicheng || raw.nick || (role === 'dashou' ? '打手' : role === 'guanshi' ? '管事' : role === 'zuzhang' ? '组长' : role === 'shangjia' ? '商家' : '用户')
const def = getDefaultAvatar(app)
const avatar = buildAvatar(raw.touxiang || raw.avatar, app) || def
const metrics = meta.metrics.map((m) => {
@@ -345,7 +348,7 @@ Page({
clubName: raw.club_name || raw.club_id || '',
rewardAmount: raw.reward_amount || 0,
mainType,
- mainPrefix: mainType === 'money' ? '楼' : '',
+ mainPrefix: mainType === 'money' ? '¥' : '',
mainValue,
mainLabel: (IS_XZJ ? meta.sortLabel : (raw.metric_label || meta.sortLabel)),
metrics,
@@ -387,7 +390,7 @@ Page({
restList: merged.slice(3),
})
} catch (e) {
- console.warn('濂栧姳淇℃伅鍔犺浇澶辫触', e)
+ console.warn('奖励信息加载失败', e)
}
},
@@ -432,7 +435,7 @@ Page({
if (!Array.isArray(list)) list = []
const role = currentRole
- // 鍚嶆椤哄簭瀹屽叏娌跨敤鍚庣杩斿洖锛屽墠绔笉鍋?sort / 閲嶆帓
+ // 名次顺序完全沿用后端返回,前端不做 sort / 重排
let normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
if (rewardFromRank) {
normalized = this.applyRewardToList(normalized, rewardFromRank, 'club')
@@ -450,8 +453,8 @@ Page({
await this.fetchRewardInfo()
}
} catch (e) {
- console.error('鎺掕姒滃姞杞藉け璐?, e)
- wx.showToast({ title: '鍔犺浇澶辫触', icon: 'none' })
+ console.error('排行榜加载失败', e)
+ wx.showToast({ title: '加载失败', icon: 'none' })
this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false })
}
},
diff --git a/pages/fighter-rank/fighter-rank.json b/pages/fighter-rank/fighter-rank.json
index 2d19320..a432e9d 100644
--- a/pages/fighter-rank/fighter-rank.json
+++ b/pages/fighter-rank/fighter-rank.json
@@ -2,10 +2,10 @@
"usingComponents": {
"global-notification": "/components/global-notification/global-notification"
},
- "navigationBarTitleText": "排行榜",
- "navigationBarBackgroundColor": "#0d1117",
- "navigationBarTextStyle": "white",
+ "navigationBarTitleText": "总排行榜",
+ "navigationBarBackgroundColor": "#FFE566",
+ "navigationBarTextStyle": "black",
"enablePullDownRefresh": true,
- "backgroundColor": "#0d1117",
- "backgroundTextStyle": "light"
+ "backgroundColor": "#FFE566",
+ "backgroundTextStyle": "dark"
}
diff --git a/pages/fighter-rank/fighter-rank.wxml b/pages/fighter-rank/fighter-rank.wxml
index 8c4db95..ea58de9 100644
--- a/pages/fighter-rank/fighter-rank.wxml
+++ b/pages/fighter-rank/fighter-rank.wxml
@@ -1,30 +1,47 @@
-
-
-
-
- {{roleMeta.title}}
-
-
+
+
@@ -247,3 +209,10 @@
+
diff --git a/pages/fighter/fighter.wxss b/pages/fighter/fighter.wxss
index 77158ab..94bd2ed 100644
--- a/pages/fighter/fighter.wxss
+++ b/pages/fighter/fighter.wxss
@@ -1,7 +1,8 @@
/* 打手端个人中心 - 逍遥梦 UI(逻辑不变) */
+@import '../../styles/dashou-xym-user.wxss';
page {
- background: #f5f3ff;
+ background: #fff8e1;
color: #333;
}
@@ -16,7 +17,7 @@ page {
flex-direction: column;
overflow: hidden;
box-sizing: border-box;
- background: linear-gradient(180deg, #c4b5fd 0%, #fff 28%, #f5f3ff 100%);
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
position: relative;
}
@@ -24,6 +25,7 @@ page {
position: relative;
z-index: 2;
flex-shrink: 0;
+ background: linear-gradient(180deg, #f7dc51 0%, #ffd061 100%);
}
.status-bar,
@@ -40,6 +42,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;
@@ -52,10 +67,6 @@ page {
padding-bottom: 0;
}
-.content-bottom {
- height: 12rpx;
-}
-
.refresh-float {
position: fixed;
right: 24rpx;
@@ -112,7 +123,7 @@ page {
font-size: 20rpx;
padding: 2rpx 12rpx;
border-radius: 8rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
}
@@ -134,6 +145,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;
@@ -169,7 +194,7 @@ page {
margin: 15rpx 30rpx 0;
padding: 24rpx 20rpx;
border-radius: 26rpx;
- background: #ede9fe;
+ background: #fef6d4;
align-items: center;
}
@@ -210,7 +235,7 @@ page {
font-weight: 700;
border: 2rpx solid #fff;
border-radius: 60rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
white-space: nowrap;
}
@@ -233,11 +258,28 @@ 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;
border-radius: 15rpx;
- background: #ede9fe;
+ background: #fef6d4;
}
.freeze-col {
@@ -259,7 +301,7 @@ page {
}
.btn-bg {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
border-radius: 30px;
color: #492f00;
}
@@ -300,39 +342,6 @@ page {
font-weight: 700;
}
-.stats-bar {
- margin: 12rpx 30rpx 0;
- padding: 16rpx 16rpx 8rpx;
- background: #fdfcfa;
- border-radius: 16rpx;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
- align-content: flex-start;
- box-shadow: 0 3px 10px rgba(0, 0, 0, 0.04);
-}
-
-.stat-cell {
- width: 25%;
- padding: 8rpx 0 12rpx;
- box-sizing: border-box;
- text-align: center;
-}
-
-.stat-val {
- display: block;
- font-size: 28rpx;
- font-weight: 700;
- color: #222;
-}
-
-.stat-lbl {
- display: block;
- font-size: 22rpx;
- color: #999;
- margin-top: 4rpx;
-}
-
.panel {
margin: 20rpx 20rpx 12rpx;
background: #fdfcfa;
@@ -356,11 +365,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 {
@@ -405,7 +438,7 @@ page {
}
.func-tag-done {
- color: #9333ea;
+ color: #c9a962;
}
.rank-hub-tip {
@@ -484,7 +517,7 @@ page {
}
.rank-theme-gold {
- background: linear-gradient(135deg, #a8842a 0%, #c4b5fd 100%);
+ background: linear-gradient(135deg, #a8842a 0%, #f5d563 100%);
}
.rank-theme-gold .rank-tile-name,
@@ -498,7 +531,7 @@ page {
}
.rank-theme-orange {
- background: linear-gradient(135deg, #7c3aed 0%, #c4b5fd 100%);
+ background: linear-gradient(135deg, #d4652a 0%, #f5a962 100%);
}
/* 未注册 */
@@ -576,7 +609,7 @@ page {
width: 60rpx;
height: 60rpx;
border: 4rpx solid rgba(0, 0, 0, 0.08);
- border-top-color: #9333ea;
+ border-top-color: #ffd061;
border-radius: 50%;
animation: fighterSpin 0.8s linear infinite;
}
diff --git a/pages/gold-fighter/gold-fighter.wxss b/pages/gold-fighter/gold-fighter.wxss
index c8a3f34..c8abc80 100644
--- a/pages/gold-fighter/gold-fighter.wxss
+++ b/pages/gold-fighter/gold-fighter.wxss
@@ -69,20 +69,20 @@ page {
/* 火苗图标燃烧动画 */
.fire-icon {
animation: fireBurn 0.8s infinite alternate ease-in-out;
- filter: drop-shadow(0 0 10rpx #9333ea);
+ filter: drop-shadow(0 0 10rpx #ffaa00);
}
@keyframes fireBurn {
- 0% { transform: scale(1) rotate(-3deg); filter: drop-shadow(0 0 10rpx #9333ea); }
- 25% { transform: scale(1.1) rotate(2deg); filter: drop-shadow(0 0 20rpx #9333ea); }
- 50% { transform: scale(1.05) rotate(-2deg); filter: drop-shadow(0 0 30rpx #9333ea); }
- 75% { transform: scale(1.15) rotate(3deg); filter: drop-shadow(0 0 40rpx #9333ea); }
- 100% { transform: scale(1) rotate(-3deg); filter: drop-shadow(0 0 10rpx #9333ea); }
+ 0% { transform: scale(1) rotate(-3deg); filter: drop-shadow(0 0 10rpx #ffaa00); }
+ 25% { transform: scale(1.1) rotate(2deg); filter: drop-shadow(0 0 20rpx #ff5500); }
+ 50% { transform: scale(1.05) rotate(-2deg); filter: drop-shadow(0 0 30rpx #ffaa00); }
+ 75% { transform: scale(1.15) rotate(3deg); filter: drop-shadow(0 0 40rpx #ffaa00); }
+ 100% { transform: scale(1) rotate(-3deg); filter: drop-shadow(0 0 10rpx #ffaa00); }
}
.jinpai-title {
font-size: 40rpx;
font-weight: bold;
- color: #9333ea;
- text-shadow: 0 0 30rpx #9333ea, 0 0 60rpx #9333ea;
+ color: #ffaa00;
+ text-shadow: 0 0 30rpx #ffaa00, 0 0 60rpx #ffaa00;
letter-spacing: 2rpx;
}
.refresh-btn {
@@ -255,7 +255,7 @@ page {
display: flex;
align-items: center;
background: rgba(255,255,255,0.1);
- border: 2rpx solid #9333ea;
+ border: 2rpx solid #ffaa00;
clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
padding: 15rpx 30rpx;
position: relative;
@@ -269,7 +269,7 @@ page {
.withdraw-text {
font-size: 32rpx;
font-weight: bold;
- color: #9333ea;
+ color: #ffaa00;
}
.withdraw-glow {
position: absolute;
@@ -491,7 +491,7 @@ page {
content: '';
width: 100rpx;
height: 100rpx;
- border: 4rpx solid #9333ea;
+ border: 4rpx solid #ffaa00;
border-radius: 50%;
border-bottom-color: transparent;
animation: spin 1.5s reverse infinite;
diff --git a/pages/group-chat/group-chat.js b/pages/group-chat/group-chat.js
index dbbe03e..2a73f76 100644
--- a/pages/group-chat/group-chat.js
+++ b/pages/group-chat/group-chat.js
@@ -2,7 +2,15 @@ const app = getApp();
import { formatDate } from '../../static/lib/utils';
import { sendGroupMessage } from '../../utils/message-sender';
import { getLocalImUserId } from '../../utils/im-user.js';
-import { resolveAvatarUrl } from '../../utils/avatar.js';
+import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage } from '../../utils/avatar.js';
+import { getZhuangtaiText, isPairGroupId, normalizeGroupMessage, recordConversationOpen } from '../../utils/group-chat.js';
+import request from '../../utils/request';
+import {
+ fetchHistoryMessages,
+ getOldestHistoryTimestamp,
+ mergeHistoryMessages,
+ waitChatImReady,
+} from '../../utils/chat-history.js';
Page({
data: {
@@ -11,6 +19,10 @@ Page({
groupAvatar: '',
orderId: '',
isCross: 0,
+ orderZhuangtai: null,
+ orderZhuangtaiText: '',
+ orderJieshao: '',
+ orderJine: '',
currentUser: null,
messages: [],
inputText: '',
@@ -30,7 +42,8 @@ Page({
pendingImage: '',
pendingImageFile: null,
keyboardHeight: 0,
- bottomSafeHeight: 10
+ bottomSafeHeight: 140,
+ defaultAvatarUrl: '',
},
onLoad(options) {
let p = { groupId: '', groupName: '订单群聊', groupAvatar: '', orderId: '', isCross: 0,
@@ -41,37 +54,79 @@ Page({
p = { ...p, ...d };
} catch (e) {}
}
+ const orderIdStr = String(p.orderId || '').replace(/^group_/, '') ||
+ (p.groupId && !isPairGroupId(p.groupId) ? String(p.groupId).replace(/^group_/, '') : '');
+ const groupId = p.groupId
+ ? String(p.groupId)
+ : (orderIdStr ? `group_${orderIdStr}` : '');
+ const zt = p.orderZhuangtai;
+ const defAvatar = getDefaultAvatarUrl(app);
this.setData({
- groupId: p.groupId,
+ groupId,
groupName: p.groupName,
- groupAvatar: p.groupAvatar,
- orderId: p.orderId,
- isCross: p.isCross
+ groupAvatar: resolveAvatarUrl(p.groupAvatar, app) || defAvatar,
+ orderId: orderIdStr,
+ isCross: p.isCross,
+ orderJieshao: p.orderDesc || p.orderJieshao || '',
+ orderJine: p.orderJine || '',
+ orderZhuangtai: zt,
+ orderZhuangtaiText: zt != null ? getZhuangtaiText(zt) : '',
+ defaultAvatarUrl: defAvatar,
});
wx.setNavigationBarTitle({ title: this.data.groupName });
- if (p.currentUserId) {
- this.setData({
- currentUser: {
- id: p.currentUserId,
- name: p.currentUserName || `用户${p.currentUserId.replace(/^[A-Za-z]+/,'')}`,
- avatar: resolveAvatarUrl(p.currentUserAvatar, app)
- }
- });
- } else {
+ this.ensureCurrentUser(p);
+ },
+
+ ensureCurrentUser(p) {
+ p = p || {};
+ const localImId = getLocalImUserId(app);
+ const uid = wx.getStorageSync('uid') || '';
+ const userId = localImId || p.currentUserId || '';
+ if (!userId) {
this.initCurrentUser();
+ return;
}
+ const defAvatar = getDefaultAvatarUrl(app);
+ const rawAvatar = p.currentUserAvatar
+ || wx.getStorageSync('touxiang')
+ || app.globalData.currentUser?.avatar
+ || '';
+ const name = p.currentUserName
+ || app.globalData.currentUser?.name
+ || wx.getStorageSync('nicheng')
+ || app.globalData.dashouNicheng
+ || app.globalData.nicheng
+ || `用户${uid}`;
+ const avatar = resolveAvatarUrl(rawAvatar, app) || defAvatar;
+ const currentUser = { id: userId, name, avatar: avatar || defAvatar };
+ app.globalData.currentUser = { ...app.globalData.currentUser, ...currentUser };
+ this.setData({ currentUser });
+ },
+
+ getMyChatProfile() {
+ const cu = this.data.currentUser;
+ const defAvatar = getDefaultAvatarUrl(app);
+ if (cu && cu.id) {
+ return {
+ id: cu.id,
+ name: cu.name || `用户${wx.getStorageSync('uid') || ''}`,
+ avatar: resolveAvatarUrl(cu.avatar, app) || defAvatar,
+ };
+ }
+ const imId = getLocalImUserId(app);
+ const uid = wx.getStorageSync('uid') || '';
+ return {
+ id: imId || '',
+ name: wx.getStorageSync('nicheng') || app.globalData.nicheng || `用户${uid}`,
+ avatar: resolveAvatarFromStorage(app) || defAvatar,
+ };
},
initCurrentUser() {
- const imId = getLocalImUserId(app);
- const uid = wx.getStorageSync('uid');
- this.setData({
- currentUser: {
- id: imId || ('Boss' + uid),
- name: app.globalData.currentUser?.name || `用户${uid}`,
- avatar: resolveAvatarUrl(wx.getStorageSync('touxiang'), app),
- },
- });
+ const profile = this.getMyChatProfile();
+ if (!profile.id) return;
+ this.setData({ currentUser: profile });
+ app.globalData.currentUser = { ...app.globalData.currentUser, ...profile };
},
buildImageFile(tempPath, size) {
@@ -84,14 +139,99 @@ Page({
normalizeMessage(msg) {
if (!msg) return msg;
+ msg = normalizeGroupMessage(msg);
if (!msg.payload) msg.payload = {};
- if (msg.type === 'image') {
- const p = msg.payload;
- if (!p.url) p.url = p.thumbnail || p.thumb || p.imageUrl || '';
+ const defAvatar = getDefaultAvatarUrl(app);
+ const me = this.getMyChatProfile();
+ if (me.id && msg.senderId === me.id) {
+ msg.senderData = {
+ name: me.name,
+ avatar: me.avatar || defAvatar,
+ };
+ } else if (msg.senderData?.avatar) {
+ msg.senderData.avatar = resolveAvatarUrl(msg.senderData.avatar, app) || defAvatar;
+ } else if (msg.senderData) {
+ msg.senderData.avatar = defAvatar;
+ }
+ if (msg.type === 'image' && msg.payload?.url && !String(msg.payload.url).startsWith('http')) {
+ msg.payload.url = resolveAvatarUrl(msg.payload.url, app) || msg.payload.url;
}
return msg;
},
+ mapIdentityForApi() {
+ const role = app.globalData.currentRole || wx.getStorageSync('currentRole') || 'normal';
+ if (role === 'dashou') return 'dashou';
+ if (role === 'shangjia') return 'shangjia';
+ return 'normal';
+ },
+
+ async refreshLatestOrderBar() {
+ const { groupId, orderId } = this.data;
+ if (!groupId && !orderId) return;
+ try {
+ const res = await request({
+ url: '/dingdan/ltpddd',
+ method: 'POST',
+ data: {
+ groupId,
+ dingdan_id: orderId,
+ identityType: this.mapIdentityForApi(),
+ },
+ });
+ const body = res?.data || {};
+ const latest = body.data?.latest;
+ if (!latest) return;
+ this.setData({
+ orderId: latest.dingdan_id,
+ orderJieshao: latest.jieshao || '',
+ orderJine: latest.jine || '',
+ orderZhuangtai: latest.zhuangtai,
+ orderZhuangtaiText: getZhuangtaiText(latest.zhuangtai),
+ });
+ } catch (e) {
+ console.warn('刷新最新订单条失败', e);
+ }
+ },
+
+ async refreshOrderStatus() {
+ const { orderId } = this.data;
+ if (!orderId) return;
+ try {
+ const res = await request({
+ url: '/dingdan/ltddzt',
+ method: 'POST',
+ data: {
+ dingdan_id: orderId,
+ identityType: this.mapIdentityForApi(),
+ },
+ });
+ const body = res?.data || {};
+ const st = body.data;
+ if (!st) return;
+ this.setData({
+ orderJieshao: st.jieshao || this.data.orderJieshao,
+ orderJine: st.jine || this.data.orderJine,
+ orderZhuangtai: st.zhuangtai,
+ orderZhuangtaiText: getZhuangtaiText(st.zhuangtai),
+ });
+ } catch (e) {
+ console.warn('刷新订单状态失败', e);
+ }
+ },
+
+ startOrderStatusPoll() {
+ this.stopOrderStatusPoll();
+ this._orderPollTimer = setInterval(() => this.refreshOrderStatus(), 15000);
+ },
+
+ stopOrderStatusPoll() {
+ if (this._orderPollTimer) {
+ clearInterval(this._orderPollTimer);
+ this._orderPollTimer = null;
+ }
+ },
+
mergeSentMessage(localId, sent) {
if (!sent) {
this.updateMsg(localId, 'success');
@@ -112,54 +252,90 @@ Page({
},
onShow() {
+ const defAvatar = getDefaultAvatarUrl(app);
+ this.setData({
+ defaultAvatarUrl: defAvatar,
+ groupAvatar: resolveAvatarUrl(this.data.groupAvatar, app) || defAvatar,
+ });
+ this.ensureCurrentUser({});
+ if (this.data.groupId) {
+ if (!app.globalData.pageState) app.globalData.pageState = {};
+ app.globalData.pageState.lastOpenedConvId = this.data.groupId;
+ recordConversationOpen({ groupId: this.data.groupId });
+ }
+ this.refreshLatestOrderBar();
+ this.startOrderStatusPoll();
this.autoConnect();
},
onHide() {
+ if (this.data.groupId) {
+ recordConversationOpen({ groupId: this.data.groupId });
+ }
+ this.stopOrderStatusPoll();
this.clearAllListeners();
},
- autoConnect() {
- const targetUserId = getLocalImUserId(app);
+ onUnload() {
+ this.stopOrderStatusPoll();
+ },
+
+ async autoConnect() {
+ const targetUserId = this.data.currentUser?.id || getLocalImUserId(app);
if (!targetUserId) return;
+ const afterReady = async () => {
+ await this.subscribeGroupIfNeeded();
+ this.setupAllListeners();
+ await this.loadHistory(true);
+ this.markGroupMessageAsRead();
+ };
+
+ try {
+ const ok = await waitChatImReady(app, 12000);
+ if (ok) {
+ await afterReady();
+ return;
+ }
+ } catch (e) {
+ console.warn('[群聊] IM 连接失败', e);
+ }
+
const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
if (status === 'connected' || status === 'reconnected') {
const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
if (currentUserId === targetUserId) {
- this.subscribeGroupIfNeeded();
- this.setupAllListeners();
- this.loadHistory(true);
+ await afterReady();
return;
- } else {
- wx.goEasy.disconnect();
}
+ wx.goEasy.disconnect();
}
this.connectGoEasy(targetUserId);
},
connectGoEasy(userId) {
- const { currentUser } = this.data;
- if (!currentUser) return;
+ const me = this.getMyChatProfile();
+ if (!me.id) return;
+ const defAvatar = getDefaultAvatarUrl(app);
wx.goEasy.connect({
id: userId,
data: {
- name: currentUser.name,
- avatar: resolveAvatarUrl(currentUser.avatar, app),
+ name: me.name,
+ avatar: me.avatar || defAvatar,
},
onSuccess: () => {
- this.subscribeGroupIfNeeded();
- this.setupAllListeners();
- this.loadHistory(true).then(()=>{
- this.markGroupMessageAsRead
-
+ this.subscribeGroupIfNeeded().then(() => {
+ this.setupAllListeners();
+ this.loadHistory(true);
+ this.markGroupMessageAsRead();
});
},
onFailed: (error) => {
if (error.code === 408) {
- this.subscribeGroupIfNeeded();
- this.setupAllListeners();
- this.loadHistory(true);
+ this.subscribeGroupIfNeeded().then(() => {
+ this.setupAllListeners();
+ this.loadHistory(true);
+ });
} else {
wx.showToast({ title: '连接失败,请重试', icon: 'none' });
}
@@ -169,11 +345,16 @@ Page({
subscribeGroupIfNeeded() {
const { groupId } = this.data;
- if (!groupId) return;
- wx.goEasy.im.subscribeGroup({
- groupIds: [groupId],
- onSuccess: () => {},
- onFailed: () => {}
+ if (!groupId || !wx.goEasy?.im?.subscribeGroup) return Promise.resolve();
+ return new Promise((resolve) => {
+ wx.goEasy.im.subscribeGroup({
+ groupIds: [String(groupId)],
+ onSuccess: () => resolve(true),
+ onFailed: (error) => {
+ console.warn('subscribeGroup failed', error);
+ resolve(false);
+ },
+ });
});
},
@@ -197,57 +378,95 @@ Page({
onPullDownRefresh() {
if (this.data.loadingHistory) return;
+ if (!this.data.hasMore) {
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ return;
+ }
this.setData({ isRefreshing: true });
- this.loadHistory(false).finally(() => { this.setData({ isRefreshing: false }); wx.stopPullDownRefresh(); });
+ this.loadHistory(false).finally(() => {
+ this.setData({ isRefreshing: false });
+ wx.stopPullDownRefresh();
+ });
},
- loadHistory(refresh) {
- if (!refresh && !this.data.hasMore) return Promise.resolve();
- return new Promise((resolve) => {
- this.setData({ loadingHistory: true });
- const { groupId, lastTimestamp } = this.data;
- const ts = refresh ? null : lastTimestamp;
- wx.goEasy.im.history({
- type: wx.GoEasy.IM_SCENE.GROUP,
- id: groupId,
- lastTimestamp: ts,
- limit: 20,
- onSuccess: (res) => {
- let list = res.content || [];
- list.sort((a, b) => a.timestamp - b.timestamp);
- list.forEach((m, idx) => {
- m = this.normalizeMessage(m);
- list[idx] = m;
- m.formattedTime = formatDate(m.timestamp);
- if (idx === 0) m.showTime = true;
- else m.showTime = (m.timestamp - list[idx-1].timestamp) / 60000 > 5;
- if (!m.senderData) m.senderData = { name: '未知用户', avatar: '' };
- });
- let final = refresh ? list : [...list, ...this.data.messages];
- if (!refresh) {
- for (let i = 0; i < final.length; i++) {
- if (i === 0) final[i].showTime = true;
- else final[i].showTime = (final[i].timestamp - final[i-1].timestamp) / 60000 > 5;
- }
- }
- const ids = new Set();
- const unique = [];
- for (const m of final) { if (!ids.has(m.messageId)) { ids.add(m.messageId); unique.push(m); } }
- const update = {
- messages: unique,
- hasMore: list.length >= 20,
- lastTimestamp: unique.length ? unique[0].timestamp : lastTimestamp,
- loadingHistory: false
- };
- if (refresh) update.scrollToView = 'msg-bottom';
- this.setData(update);
- resolve();
- },
- onFailed: () => { this.setData({ loadingHistory: false }); resolve(); }
- });
+ mapHistoryMessage(m, idx, list) {
+ m = this.normalizeMessage(m);
+ m.formattedTime = formatDate(m.timestamp);
+ if (idx === 0) m.showTime = true;
+ else m.showTime = (m.timestamp - list[idx - 1].timestamp) / 60000 > 5;
+ if (!m.senderData) m.senderData = { name: '未知用户', avatar: '' };
+ return m;
+ },
+
+ async fetchGroupHistoryPage(gid, lastTimestamp) {
+ return fetchHistoryMessages({
+ scene: wx.GoEasy.IM_SCENE.GROUP,
+ id: gid,
+ lastTimestamp,
+ limit: 20,
});
},
+ async loadHistory(refresh) {
+ if (!refresh && !this.data.hasMore) return;
+ if (this.data.loadingHistory) return;
+ if (!this.data.groupId) return;
+
+ this.setData({ loadingHistory: true });
+ try {
+ const ready = await waitChatImReady(app, 12000);
+ if (!ready) {
+ wx.showToast({ title: '消息服务未连接,请稍后重试', icon: 'none' });
+ return;
+ }
+
+ await this.subscribeGroupIfNeeded();
+
+ const ts = refresh
+ ? null
+ : getOldestHistoryTimestamp(this.data.messages, this.data.lastTimestamp);
+ if (!refresh && ts == null) {
+ this.setData({ hasMore: false });
+ wx.showToast({ title: '没有更早的消息了', icon: 'none' });
+ return;
+ }
+
+ let raw = await this.fetchGroupHistoryPage(this.data.groupId, ts);
+
+ if (refresh && raw.length === 0 && isPairGroupId(this.data.groupId) && this.data.orderId) {
+ const legacyId = `group_${this.data.orderId}`;
+ if (legacyId !== this.data.groupId) {
+ raw = await this.fetchGroupHistoryPage(legacyId, ts);
+ }
+ }
+
+ const merged = mergeHistoryMessages({
+ incoming: raw,
+ existing: this.data.messages,
+ refresh,
+ limit: 20,
+ mapMessage: (m, idx, list) => this.mapHistoryMessage(m, idx, list),
+ });
+
+ const update = {
+ messages: merged.messages,
+ hasMore: merged.hasMore,
+ lastTimestamp: merged.lastTimestamp,
+ };
+ if (refresh) update.scrollToView = 'msg-bottom';
+ this.setData(update);
+ } catch (e) {
+ console.warn('[群聊] 历史消息加载失败', e);
+ if (!refresh) {
+ wx.showToast({ title: '加载历史消息失败', icon: 'none' });
+ }
+ } finally {
+ this.setData({ loadingHistory: false });
+ }
+ },
+
listenNewMsg() {
if (this._msgHandler) wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, this._msgHandler);
this._msgHandler = (msg) => {
@@ -531,7 +750,9 @@ Page({
orderId: order.dingdan_id,
jieshao: order.jieshao,
jine: order.jine,
- beizhu: order.beizhu
+ beizhu: order.beizhu,
+ zhuangtai: order.zhuangtai,
+ nicheng: order.nicheng,
};
sendGroupMessage({
msgData: {
@@ -555,6 +776,10 @@ Page({
},
onSuccess: (messageId, status) => {
that.updateMsg(messageId, status);
+ that.closeOrderSender();
+ if (status === 'success') {
+ wx.showToast({ title: '订单已发送', icon: 'success' });
+ }
}
});
},
@@ -566,5 +791,24 @@ Page({
this.setData({ detailText: text, showDetailModal: true });
},
- onKeyboardHeightChange(e) { this.setData({ keyboardHeight: e.detail.height }); }
+ onKeyboardHeightChange(e) { this.setData({ keyboardHeight: e.detail.height }); },
+
+ onAvatarError(e) {
+ const def = getDefaultAvatarUrl(app);
+ const idx = e.currentTarget.dataset.index;
+ if (idx != null && idx !== '') {
+ this.setData({ [`messages[${idx}].senderData.avatar`]: def });
+ }
+ },
+
+ onSelfAvatarError() {
+ const def = getDefaultAvatarUrl(app);
+ if (this.data.currentUser) {
+ this.setData({ 'currentUser.avatar': def });
+ }
+ },
+
+ tapOrderBar() {
+ this.openOrderSender();
+ },
});
\ No newline at end of file
diff --git a/pages/group-chat/group-chat.json b/pages/group-chat/group-chat.json
index d5bfa0e..3e7741a 100644
--- a/pages/group-chat/group-chat.json
+++ b/pages/group-chat/group-chat.json
@@ -1,6 +1,7 @@
{
"navigationBarTitleText": "群聊",
"usingComponents": {
- "order-card": "/components/order-card/order-card"
+ "order-card": "/components/order-card/order-card",
+ "order-sender": "/components/order-sender/order-sender"
}
}
\ No newline at end of file
diff --git a/pages/group-chat/group-chat.wxml b/pages/group-chat/group-chat.wxml
index 2abee15..4e6555a 100644
--- a/pages/group-chat/group-chat.wxml
+++ b/pages/group-chat/group-chat.wxml
@@ -1,18 +1,28 @@
+
+
+
+ 订单 {{orderId}}
+ ¥{{orderJine}}
+
+ {{orderZhuangtaiText}}
+
+ {{orderJieshao}}
+ 点击查看历史订单并发送
+
+ style="top: {{orderId ? '120rpx' : '20rpx'}}; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 24rpx);">
加载更早消息...
-
+
{{item.formattedTime}}
-
-
+
{{item.senderData.name || item.senderId}}
ID: {{item.payload.orderId}}
内容: {{item.payload.jieshao}}
金额: ¥{{item.payload.jine}}
+ 备注: {{item.payload.beizhu}}
点击查看详情
-
-
+
-
+
@@ -88,5 +98,5 @@
-
+
diff --git a/pages/group-chat/group-chat.wxss b/pages/group-chat/group-chat.wxss
index dab11fa..81654bb 100644
--- a/pages/group-chat/group-chat.wxss
+++ b/pages/group-chat/group-chat.wxss
@@ -1,5 +1,67 @@
/* 使用全局 chat-* 样式 */
+.order-status-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 11;
+ background: #fff;
+ padding: 16rpx 24rpx;
+ border-bottom: 1rpx solid #e8e8e8;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
+}
+
+.order-status-main {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.order-status-id {
+ font-size: 26rpx;
+ color: #333;
+ font-weight: 600;
+}
+
+.order-status-tag {
+ font-size: 22rpx;
+ color: #07c160;
+ background: #e8f8ee;
+ padding: 4rpx 16rpx;
+ border-radius: 20rpx;
+}
+
+.order-status-left {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-width: 0;
+}
+
+.order-status-price {
+ font-size: 24rpx;
+ color: #ff6b00;
+ margin-top: 4rpx;
+}
+
+.order-status-hint {
+ font-size: 22rpx;
+ color: #007aff;
+ margin-top: 6rpx;
+ display: block;
+}
+
+.order-status-desc {
+ font-size: 24rpx;
+ color: #888;
+ margin-top: 8rpx;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
/* 发送者昵称样式(群聊特有) */
.sender-info {
display: flex;
diff --git a/pages/guanshiduan/guanshiduan.js b/pages/guanshiduan/guanshiduan.js
new file mode 100644
index 0000000..9674848
--- /dev/null
+++ b/pages/guanshiduan/guanshiduan.js
@@ -0,0 +1,14 @@
+/** 旧二维码兼容:guanshiduan → 打手中心管事注册,逻辑不变 */
+import { parseSceneOptions } from '../../utils/base-page.js';
+
+Page({
+ onLoad(options) {
+ const parsed = parseSceneOptions(options || {});
+ const inviteCode = parsed.inviteCode || options.inviteCode || '';
+ let url = '/pages/fighter/fighter?registerType=guanshi';
+ if (inviteCode) {
+ url += `&inviteCode=${encodeURIComponent(inviteCode)}`;
+ }
+ wx.reLaunch({ url });
+ },
+});
diff --git a/pages/guanshiduan/guanshiduan.json b/pages/guanshiduan/guanshiduan.json
new file mode 100644
index 0000000..52bc9cd
--- /dev/null
+++ b/pages/guanshiduan/guanshiduan.json
@@ -0,0 +1 @@
+{ "navigationBarTitleText": "加载中", "usingComponents": {} }
diff --git a/pages/guanshiduan/guanshiduan.wxml b/pages/guanshiduan/guanshiduan.wxml
new file mode 100644
index 0000000..4a671a9
--- /dev/null
+++ b/pages/guanshiduan/guanshiduan.wxml
@@ -0,0 +1 @@
+正在进入管事注册…
diff --git a/pages/guanshiduan/guanshiduan.wxss b/pages/guanshiduan/guanshiduan.wxss
new file mode 100644
index 0000000..8082289
--- /dev/null
+++ b/pages/guanshiduan/guanshiduan.wxss
@@ -0,0 +1 @@
+.tip { display:flex; align-items:center; justify-content:center; min-height:100vh; color:#999; font-size:28rpx; }
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/index/index.wxml b/pages/index/index.wxml
index f96faf4..9251efd 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -18,7 +18,7 @@
class="lunbo-swiper"
indicator-dots="{{lunboList.length > 1}}"
indicator-color="rgba(255,255,255,0.6)"
- indicator-active-color="#a855f7"
+ indicator-active-color="#ffcc00"
autoplay="{{lunboList.length > 1}}"
interval="3000"
circular
diff --git a/pages/index/index.wxss b/pages/index/index.wxss
index 2121cf9..fbcc9aa 100644
--- a/pages/index/index.wxss
+++ b/pages/index/index.wxss
@@ -12,7 +12,7 @@
border-radius: 40rpx;
background: linear-gradient(135deg,
rgba(220, 255, 220, 0.85) 0%,
- rgba(237, 233, 254, 0.85) 100%);
+ rgba(255, 255, 200, 0.85) 100%);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
@@ -120,7 +120,7 @@
position: absolute;
width: 12rpx;
height: 12rpx;
- background: #a855f7;
+ background: #ffcc00;
border-radius: 50%;
top: 15rpx;
right: 15rpx;
@@ -195,8 +195,8 @@
}
.leixing-active .leixing-glow {
- border-color: #a855f7;
- box-shadow: 0 0 20rpx rgba(168, 85, 247, 0.5);
+ border-color: #ffcc00;
+ box-shadow: 0 0 20rpx rgba(255, 204, 0, 0.5);
}
.leixing-active .leixing-image-box {
@@ -239,7 +239,7 @@
.zhuanqu-icon-image {
width: 100%;
height: 100%;
- filter: drop-shadow(0 2rpx 4rpx rgba(168, 85, 247, 0.3));
+ filter: drop-shadow(0 2rpx 4rpx rgba(255, 204, 0, 0.3));
}
.zhuanqu-sparkle {
@@ -249,11 +249,11 @@
@keyframes sparkle {
0%, 100% {
transform: scale(1) rotate(0deg);
- filter: drop-shadow(0 2rpx 4rpx rgba(168, 85, 247, 0.3));
+ filter: drop-shadow(0 2rpx 4rpx rgba(255, 204, 0, 0.3));
}
50% {
transform: scale(1.1) rotate(10deg);
- filter: drop-shadow(0 4rpx 8rpx rgba(168, 85, 247, 0.6));
+ filter: drop-shadow(0 4rpx 8rpx rgba(255, 204, 0, 0.6));
}
}
@@ -271,7 +271,7 @@
bottom: -8rpx;
width: 60rpx;
height: 4rpx;
- background: linear-gradient(90deg, #a855f7, transparent);
+ background: linear-gradient(90deg, #ffcc00, transparent);
border-radius: 2rpx;
}
diff --git a/pages/invite-manager/invite-manager.js b/pages/invite-manager/invite-manager.js
index 8fad7f7..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('#9333ea'); // 金黄色,呼应组长主题
- 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/invite-manager/invite-manager.wxss b/pages/invite-manager/invite-manager.wxss
index 28b59f7..b271fb5 100644
--- a/pages/invite-manager/invite-manager.wxss
+++ b/pages/invite-manager/invite-manager.wxss
@@ -15,8 +15,8 @@ page {
width: 100%;
height: 100%;
background-image:
- linear-gradient(rgba(168, 85, 247, 0.05) 1px, transparent 1px),
- linear-gradient(90deg, rgba(168, 85, 247, 0.05) 1px, transparent 1px);
+ linear-gradient(rgba(255, 200, 0, 0.05) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(255, 200, 0, 0.05) 1px, transparent 1px);
background-size: 50rpx 50rpx;
pointer-events: none;
z-index: 0;
@@ -41,14 +41,14 @@ page {
left: 0;
width: 100%;
height: 2rpx;
- background: linear-gradient(90deg, transparent, #9333ea, transparent);
+ background: linear-gradient(90deg, transparent, #ffaa00, transparent);
}
.line-v {
right: 50rpx;
top: 100rpx;
width: 2rpx;
height: 300rpx;
- background: linear-gradient(180deg, transparent, #9333ea, transparent);
+ background: linear-gradient(180deg, transparent, #ffaa00, transparent);
}
.content {
@@ -71,14 +71,14 @@ page {
font-size: 44rpx;
font-weight: bold;
color: #fff;
- text-shadow: 0 0 30rpx #9333ea;
+ text-shadow: 0 0 30rpx #ffaa00;
letter-spacing: 2rpx;
display: block;
margin-bottom: 20rpx;
}
.subtitle {
font-size: 28rpx;
- color: #c4b5fd;
+ color: #ffd966;
opacity: 0.9;
letter-spacing: 1rpx;
}
@@ -96,11 +96,11 @@ page {
width: 400rpx;
height: 400rpx;
background: rgba(20, 20, 20, 0.8);
- border: 4rpx solid #9333ea;
+ border: 4rpx solid #ffaa00;
display: flex;
align-items: center;
justify-content: center;
- box-shadow: 0 0 80rpx rgba(147, 51, 234, 0.4);
+ box-shadow: 0 0 80rpx rgba(255, 170, 0, 0.4);
animation: qrcodePulse 2s infinite alternate;
}
.qrcode-img {
@@ -114,14 +114,14 @@ page {
left: 0;
width: 100%;
height: 100%;
- background: radial-gradient(circle at 30% 30%, rgba(147, 51, 234, 0.2), transparent 70%);
+ background: radial-gradient(circle at 30% 30%, rgba(255, 170, 0, 0.2), transparent 70%);
pointer-events: none;
}
.empty-qrcode {
width: 400rpx;
height: 400rpx;
background: rgba(20, 20, 20, 0.8);
- border: 4rpx dashed #9333ea;
+ border: 4rpx dashed #ffaa00;
display: flex;
flex-direction: column;
align-items: center;
@@ -129,13 +129,13 @@ page {
}
.empty-icon {
font-size: 80rpx;
- color: #9333ea;
+ color: #ffaa00;
margin-bottom: 20rpx;
opacity: 0.5;
}
.empty-text {
font-size: 26rpx;
- color: #c4b5fd;
+ color: #ffd966;
text-align: center;
padding: 0 40rpx;
}
@@ -148,14 +148,14 @@ page {
background: rgba(0, 0, 0, 0.5);
padding: 20rpx 30rpx;
border-radius: 60rpx;
- border: 2rpx solid #9333ea;
+ border: 2rpx solid #ffaa00;
margin-bottom: 30rpx;
width: 90%;
box-sizing: border-box;
}
.code-label {
font-size: 28rpx;
- color: #c4b5fd;
+ color: #ffd966;
margin-right: 10rpx;
}
.code-value {
@@ -169,23 +169,23 @@ page {
.copy-btn {
display: flex;
align-items: center;
- background: rgba(147, 51, 234, 0.2);
+ background: rgba(255, 170, 0, 0.2);
padding: 10rpx 20rpx;
border-radius: 40rpx;
margin-left: 20rpx;
- border: 2rpx solid #9333ea;
+ border: 2rpx solid #ffaa00;
}
.copy-icon {
font-size: 28rpx;
- color: #9333ea;
+ color: #ffaa00;
margin-right: 6rpx;
}
.copy-text {
font-size: 24rpx;
- color: #9333ea;
+ color: #ffaa00;
}
.copy-btn:active {
- background: rgba(147, 51, 234, 0.4);
+ background: rgba(255, 170, 0, 0.4);
transform: scale(0.96);
}
@@ -206,7 +206,7 @@ page {
width: 220rpx;
height: 80rpx;
background: rgba(20, 20, 20, 0.8);
- border: 2rpx solid #9333ea;
+ border: 2rpx solid #ffaa00;
border-right: none;
border-bottom: none;
clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
@@ -219,22 +219,22 @@ page {
}
.btn:active {
transform: scale(0.96);
- box-shadow: 0 0 40rpx #9333ea;
+ box-shadow: 0 0 40rpx #ffaa00;
}
.save-btn {
- border-color: #9333ea;
+ border-color: #ffaa00;
}
.refresh-btn {
- border-color: #9333ea;
+ border-color: #ffaa00;
}
.refresh-btn .btn-icon {
- color: #9333ea;
+ color: #ffaa00;
}
.poster-btn {
- border-color: #9333ea;
+ border-color: #ffaa00;
}
.poster-btn .btn-icon {
- color: #9333ea;
+ color: #ffaa00;
}
.loading-btn {
opacity: 0.7;
@@ -254,7 +254,7 @@ page {
width: 30rpx;
height: 30rpx;
border: 4rpx solid rgba(255,255,255,0.2);
- border-top: 4rpx solid #9333ea;
+ border-top: 4rpx solid #ffaa00;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 10rpx;
@@ -272,8 +272,8 @@ page {
width: 600rpx;
height: 900rpx;
background: #1a1f2e;
- border: 4rpx solid #9333ea;
- box-shadow: 0 0 60rpx #9333ea;
+ border: 4rpx solid #ffaa00;
+ box-shadow: 0 0 60rpx #ffaa00;
}
.poster-actions {
display: flex;
@@ -282,12 +282,12 @@ page {
justify-content: center;
}
.save-poster-btn {
- background: linear-gradient(45deg, #6d28d9, #9333ea);
- border-color: #9333ea;
+ background: linear-gradient(45deg, #cc8400, #ffaa00);
+ border-color: #ffaa00;
}
.back-btn {
background: rgba(20, 20, 20, 0.8);
- border-color: #9333ea;
+ border-color: #ffaa00;
}
/* 使用说明 */
@@ -295,19 +295,19 @@ page {
margin-top: 30rpx;
padding: 20rpx 40rpx;
background: rgba(20, 20, 20, 0.5);
- border-left: 4rpx solid #9333ea;
+ border-left: 4rpx solid #ffaa00;
clip-path: polygon(0 0, 100% 0, 98% 100%, 0 100%);
}
.instruction-text {
font-size: 24rpx;
- color: #c4b5fd;
+ color: #ffd966;
line-height: 1.6;
}
/* 动画 */
@keyframes qrcodePulse {
- 0% { box-shadow: 0 0 40rpx rgba(147, 51, 234, 0.3); }
- 100% { box-shadow: 0 0 100rpx rgba(147, 51, 234, 0.6); }
+ 0% { box-shadow: 0 0 40rpx rgba(255, 170, 0, 0.3); }
+ 100% { box-shadow: 0 0 100rpx rgba(255, 170, 0, 0.6); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
diff --git a/pages/manager-assign/manager-assign.json b/pages/manager-assign/manager-assign.json
index 03bf4df..4a234f5 100644
--- a/pages/manager-assign/manager-assign.json
+++ b/pages/manager-assign/manager-assign.json
@@ -1,5 +1,5 @@
{
- "navigationBarTitleText": "关注星阙",
+ "navigationBarTitleText": "星之界",
"usingComponents": {
"global-notification": "/components/global-notification/global-notification"
},
diff --git a/pages/merchant-data-stats/merchant-data-stats.js b/pages/merchant-data-stats/merchant-data-stats.js
new file mode 100644
index 0000000..2721567
--- /dev/null
+++ b/pages/merchant-data-stats/merchant-data-stats.js
@@ -0,0 +1,67 @@
+import { createPage, request } from '../../utils/base-page.js';
+import { fetchMerchantOrderStats, applyOrderStatsToPage } from '../../utils/merchant-order-stats.js';
+
+Page(createPage({
+ data: {
+ statusBar: 20,
+ loading: true,
+ canViewFinance: true,
+ orderStats: {
+ pending_count: 0,
+ pending_amount: '0.00',
+ completed_count: 0,
+ completed_amount: '0.00',
+ refund_count: 0,
+ refund_amount: '0.00',
+ dispatch_count: 0,
+ dispatch_amount: '0.00',
+ },
+ penaltyStats: {
+ fakuan_pending: 0,
+ fakuan_pending_amount: '0.00',
+ jifen_pending: 0,
+ },
+ jinriliushui: '0.00',
+ jinyueliushui: '0.00',
+ jinridingdan: 0,
+ jinrituikuan: 0,
+ },
+
+ onLoad() {
+ const sys = wx.getSystemInfoSync();
+ this.setData({ statusBar: sys.statusBarHeight || 20 });
+ this.loadData();
+ },
+
+ onPullDownRefresh() {
+ this.loadData().finally(() => wx.stopPullDownRefresh());
+ },
+
+ async loadData() {
+ this.setData({ loading: true });
+ try {
+ const statsData = await fetchMerchantOrderStats(request, {});
+ applyOrderStatsToPage(this, statsData);
+ try {
+ const res = await request({ url: '/yonghu/shangjiaxinxi', method: 'POST' });
+ if (res.data && res.data.code === 200) {
+ const d = res.data.data || {};
+ this.setData({
+ jinriliushui: d.jinriliushui || '0.00',
+ jinyueliushui: d.jinyueliushui || '0.00',
+ jinridingdan: d.jinripaidan || 0,
+ jinrituikuan: d.jinrituikuan || 0,
+ });
+ }
+ } catch (e) {
+ console.warn('商家流水加载失败', e);
+ }
+ } finally {
+ this.setData({ loading: false });
+ }
+ },
+
+ goBack() {
+ wx.navigateBack();
+ },
+}));
diff --git a/pages/merchant-data-stats/merchant-data-stats.json b/pages/merchant-data-stats/merchant-data-stats.json
new file mode 100644
index 0000000..2cfa46f
--- /dev/null
+++ b/pages/merchant-data-stats/merchant-data-stats.json
@@ -0,0 +1,5 @@
+{
+ "navigationStyle": "custom",
+ "enablePullDownRefresh": true,
+ "usingComponents": {}
+}
diff --git a/pages/merchant-data-stats/merchant-data-stats.wxml b/pages/merchant-data-stats/merchant-data-stats.wxml
new file mode 100644
index 0000000..b815939
--- /dev/null
+++ b/pages/merchant-data-stats/merchant-data-stats.wxml
@@ -0,0 +1,56 @@
+
+
+
+ ‹
+ 经营数据
+
+
+
+
+
+
+
+ {{orderStats.pending_count}}
+ 待结算(单)
+ ¥{{orderStats.pending_amount}}
+
+
+ {{orderStats.completed_count}}
+ 成交总量
+ ¥{{orderStats.completed_amount}}
+
+
+
+
+ {{orderStats.refund_count}}
+ 退款总量
+ ¥{{orderStats.refund_amount}}
+
+
+ {{orderStats.dispatch_count}}
+ 发单总量
+ ¥{{orderStats.dispatch_amount}}
+
+
+ {{jinriliushui}}
+ 今日流水
+
+
+ {{jinyueliushui}}
+ 今月流水
+
+
+ {{jinridingdan}}
+ 今日派单
+
+
+ {{jinrituikuan}}
+ 今日退款
+
+
+
+ 处罚待处理:罚单 {{penaltyStats.fakuan_pending}}(¥{{penaltyStats.fakuan_pending_amount}})· 积分 {{penaltyStats.jifen_pending}}
+
+
+
+
diff --git a/pages/merchant-data-stats/merchant-data-stats.wxss b/pages/merchant-data-stats/merchant-data-stats.wxss
new file mode 100644
index 0000000..f9d7bdd
--- /dev/null
+++ b/pages/merchant-data-stats/merchant-data-stats.wxss
@@ -0,0 +1,84 @@
+@import '../../styles/shangjia-xym-common.wxss';
+
+page { background: #fff8e1; }
+
+.sub-scroll { height: calc(100vh - 120rpx); }
+
+.data-panel { padding: 24rpx; margin-top: 16rpx; }
+
+.data-highlight {
+ margin-bottom: 24rpx;
+ gap: 16rpx;
+}
+
+.data-hl-item {
+ flex: 1;
+ text-align: center;
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 20rpx 12rpx;
+}
+
+.data-hl-num {
+ display: block;
+ font-size: 40rpx;
+ font-weight: 700;
+ color: #333;
+}
+
+.data-hl-num.accent { color: #e65100; }
+
+.data-hl-lbl {
+ display: block;
+ font-size: 24rpx;
+ color: #888;
+ margin-top: 8rpx;
+}
+
+.data-hl-sub {
+ display: block;
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 4rpx;
+}
+
+.data-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 16rpx;
+}
+
+.data-cell {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 20rpx 16rpx;
+ text-align: center;
+}
+
+.data-cell-num {
+ display: block;
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.data-cell-lbl {
+ display: block;
+ font-size: 22rpx;
+ color: #888;
+ margin-top: 6rpx;
+}
+
+.data-cell-sub {
+ display: block;
+ font-size: 20rpx;
+ color: #aaa;
+ margin-top: 4rpx;
+}
+
+.penalty-mini {
+ margin-top: 20rpx;
+ font-size: 24rpx;
+ color: #666;
+ line-height: 1.5;
+}
diff --git a/pages/merchant-dispatch/merchant-dispatch.js b/pages/merchant-dispatch/merchant-dispatch.js
index d2f15d6..28e1381 100644
--- a/pages/merchant-dispatch/merchant-dispatch.js
+++ b/pages/merchant-dispatch/merchant-dispatch.js
@@ -24,6 +24,7 @@ Page(createPage({
dingdanJieshao: '', // 订单介绍
dingdanBeizhu: '', // 订单备注
laobanName: '', // 老板游戏昵称/UID
+ waibuDingdanId: '', // 外部平台订单号
zhidingUid: '', // 指定打手UID
jiage: '', // 订单价格
@@ -214,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 })
},
@@ -342,6 +346,7 @@ Page(createPage({
dingdanJieshao: '',
dingdanBeizhu: '',
laobanName: '',
+ waibuDingdanId: '',
zhidingUid: '',
jiage: '',
selectedLabelId: '',
@@ -371,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,
// 新增字段
diff --git a/pages/merchant-dispatch/merchant-dispatch.json b/pages/merchant-dispatch/merchant-dispatch.json
index c01f2ef..a2b524c 100644
--- a/pages/merchant-dispatch/merchant-dispatch.json
+++ b/pages/merchant-dispatch/merchant-dispatch.json
@@ -4,9 +4,9 @@
"popup-notice": "/components/popup-notice/popup-notice"
},
"backgroundTextStyle": "dark",
- "navigationBarBackgroundColor": "#fff8e1",
+ "navigationBarBackgroundColor": "#f7dc51",
"navigationBarTitleText": "自定义发单",
"navigationBarTextStyle": "black",
- "backgroundColor": "#f5f5f5",
+ "backgroundColor": "#fff8e1",
"enablePullDownRefresh": false
}
\ No newline at end of file
diff --git a/pages/merchant-dispatch/merchant-dispatch.wxml b/pages/merchant-dispatch/merchant-dispatch.wxml
index d070ce7..b535bc2 100644
--- a/pages/merchant-dispatch/merchant-dispatch.wxml
+++ b/pages/merchant-dispatch/merchant-dispatch.wxml
@@ -84,6 +84,21 @@
/>
+
+
+
+ 拼多多订单号
+ 选填
+
+
+
+
@@ -144,7 +159,7 @@
选填
-
+
{{commissionEnabled ? '已开启' : '未开启'}}
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, XYM_HOME_FALLBACK.noticeIco),
+ statCardBg: icon(ICON_KEYS.MERCHANT_HOME_STAT_BG, `${ossBase}beijing/shangjiaduan/stat_card_bg.png`) || XYM_HOME_FALLBACK.statCardBg,
+ kefuKeyBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_KEY, XYM_HOME_FALLBACK.kefuKeyBtn),
+ kefuListBtn: icon(ICON_KEYS.MERCHANT_HOME_KEFU_LIST, XYM_HOME_FALLBACK.kefuListBtn),
+ iconRegular: icon(ICON_KEYS.MERCHANT_HOME_REGULAR, XYM_HOME_FALLBACK.iconRegular),
+ iconCustom: icon(ICON_KEYS.MERCHANT_HOME_CUSTOM, XYM_HOME_FALLBACK.iconCustom),
+ },
+ });
},
processImageUrls(urlList) {
@@ -109,13 +182,13 @@ Page(createPage({
},
checkRole() {
- this.setData({ isShangjia: isMerchantPortalUser() });
+ 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 || '',
@@ -123,41 +196,20 @@ 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),
]);
},
@@ -191,36 +243,21 @@ Page(createPage({
async loadPendingStats() {
try {
- const res = await request({
- url: isStaffMode() ? STAFF_API.orderList : '/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: isStaffMode() ? STAFF_API.orderList : '/dingdan/sjdingdanhq',
@@ -253,7 +290,10 @@ Page(createPage({
} catch (e) {
console.error('最近订单加载失败', e);
} finally {
- this.setData({ recentLoading: false });
+ this._recentOrdersRequesting = false;
+ if (!silent) {
+ this.setData({ recentLoading: false });
+ }
}
},
@@ -261,12 +301,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 86debc7..d8f66be 100644
--- a/pages/merchant-home/merchant-home.wxml
+++ b/pages/merchant-home/merchant-home.wxml
@@ -18,6 +18,11 @@
+
+
+ {{gonggao}}
+
+
@@ -34,18 +39,21 @@
-
-
- {{gonggao}}
-
-
商家客服 · {{staffRoleName}} · 可用额度 ¥{{quotaAvailable}}
-
-
-
+
+
+
+
+
+
+
+ 链接派单
+ 模板管理 · 生成链接
+
+
diff --git a/pages/merchant-home/merchant-home.wxss b/pages/merchant-home/merchant-home.wxss
index eb664c3..bfe38b0 100644
--- a/pages/merchant-home/merchant-home.wxss
+++ b/pages/merchant-home/merchant-home.wxss
@@ -1,7 +1,7 @@
@import '../../styles/shangjia-xym-common.wxss';
page {
- background: #f5f3ff;
+ background: #fff8e1;
}
.sj-page--home {
@@ -85,14 +85,14 @@ page {
.dot.active {
width: 16rpx;
border-radius: 8rpx;
- background: #9333ea;
+ background: #ffd061;
}
.sj-notice-bar {
display: flex;
align-items: center;
background: #fdf9db;
- margin: 0 24rpx;
+ margin: 12rpx 24rpx 0;
border-radius: 10rpx;
padding: 10rpx 16rpx;
}
@@ -102,6 +102,10 @@ page {
height: 56rpx;
flex-shrink: 0;
margin-right: 12rpx;
+ background-image: url('https://bintao.xmxym88.com/xcx/bintao/38.png');
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
}
.sj-notice-txt {
@@ -111,11 +115,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 {
@@ -127,16 +142,41 @@ page {
.sj-fadan-img-btn--left {
background-image: url('https://bintao.xmxym88.com/xcx/bintao/74.png');
- margin-right: 8rpx;
}
.sj-fadan-img-btn--right {
background-image: url('https://bintao.xmxym88.com/xcx/bintao/76.png');
- margin-left: 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-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;
@@ -151,8 +191,10 @@ page {
left: 0;
right: 0;
bottom: 0;
+ background-image: url('https://bintao.xmxym88.com/xcx/bintao/3.png');
background-size: 100% auto;
background-repeat: no-repeat;
+ background-position: center top;
pointer-events: none;
z-index: 0;
}
@@ -311,7 +353,7 @@ page {
.staff-banner {
margin-top: 16rpx;
padding: 16rpx 24rpx;
- background: #f5f3ff;
+ background: #fff8e8;
border-radius: 12rpx;
border: 1rpx solid #f0d89a;
}
diff --git a/pages/merchant-kefu-key/merchant-kefu-key.wxss b/pages/merchant-kefu-key/merchant-kefu-key.wxss
index df03957..b51a295 100644
--- a/pages/merchant-kefu-key/merchant-kefu-key.wxss
+++ b/pages/merchant-kefu-key/merchant-kefu-key.wxss
@@ -95,7 +95,7 @@
padding: 16rpx 32rpx;
min-height: 64rpx;
border-radius: 10rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
font-size: 28rpx;
font-weight: 700;
@@ -108,8 +108,8 @@
}
.tips-bar {
- background: #f5f3ff;
- border: 1rpx solid #c4b5fd;
+ background: #fff7e6;
+ border: 1rpx solid #ffd591;
border-radius: 12rpx;
padding: 18rpx 20rpx;
font-size: 26rpx;
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.js b/pages/merchant-kefu-list/merchant-kefu-list.js
index 5ca8c31..8507c85 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.js
+++ b/pages/merchant-kefu-list/merchant-kefu-list.js
@@ -34,6 +34,10 @@ Page({
list: [],
+ displayList: [],
+
+ searchKeyword: '',
+
isOwner: false,
},
@@ -124,7 +128,9 @@ Page({
const raw = (res.data.data && res.data.data.list) || [];
- this.setData({ list: this.formatList(raw) });
+ this._allList = this.formatList(raw);
+
+ this.applySearchFilter();
}
@@ -140,7 +146,64 @@ Page({
goBack() { wx.navigateBack(); },
+ applySearchFilter() {
+ const kw = (this.data.searchKeyword || '').trim().toLowerCase();
+ const all = this._allList || [];
+ if (!kw) {
+ this.setData({ list: all, displayList: all });
+ return;
+ }
+ const filtered = all.filter((item) => {
+ const uid = String(item.uid || '').toLowerCase();
+ const remark = String(item.merchant_remark || '').toLowerCase();
+ const nick = String(item.nickname || '').toLowerCase();
+ return uid.includes(kw) || remark.includes(kw) || nick.includes(kw);
+ });
+ this.setData({ list: all, displayList: filtered });
+ },
+ onSearchInput(e) {
+ this.setData({ searchKeyword: e.detail.value || '' });
+ this.applySearchFilter();
+ },
+
+ clearSearch() {
+ this.setData({ searchKeyword: '' });
+ this.applySearchFilter();
+ },
+
+ 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) {
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxml b/pages/merchant-kefu-list/merchant-kefu-list.wxml
index 78166a7..ab260ae 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.wxml
+++ b/pages/merchant-kefu-list/merchant-kefu-list.wxml
@@ -12,11 +12,17 @@
-
+
+
+
+
+ ✕
+
+
-
+
@@ -41,12 +47,10 @@
-
ID: {{item.uid}}
-
复制
-
+
@@ -132,7 +136,12 @@
-
+
+ 备注
+ 查看订单
+
+
+
划额度
@@ -150,7 +159,7 @@
- 暂无客服成员
+ 暂无客服成员
操作日志 ›
diff --git a/pages/merchant-kefu-list/merchant-kefu-list.wxss b/pages/merchant-kefu-list/merchant-kefu-list.wxss
index 5ab7f2a..9d21e0f 100644
--- a/pages/merchant-kefu-list/merchant-kefu-list.wxss
+++ b/pages/merchant-kefu-list/merchant-kefu-list.wxss
@@ -57,7 +57,7 @@
}
.quota-label { font-size: 24rpx; color: #888; }
-.quota-val { font-size: 30rpx; color: #9333ea; font-weight: 600; }
+.quota-val { font-size: 30rpx; color: #C9A962; font-weight: 600; }
.kefu-av {
width: 88rpx;
@@ -81,7 +81,7 @@
color: #fff;
}
-.badge-chief { background: #9333ea; }
+.badge-chief { background: #ffb508; }
.badge-finance { background: #1b6ef3; }
.badge-self { background: #9e9e9e; }
@@ -155,3 +155,16 @@
font-size: 22rpx;
color: #bbb;
}
+
+.filter-row { margin-bottom: 8rpx; }
+.search-box {
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 32rpx;
+ padding: 12rpx 20rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
+}
+.search-icon { width: 32rpx; height: 32rpx; margin-right: 12rpx; }
+.search-input { flex: 1; font-size: 26rpx; }
+.search-clear { padding: 8rpx; color: #999; font-size: 24rpx; }
diff --git a/pages/merchant-msg/merchant-msg.json b/pages/merchant-msg/merchant-msg.json
index e3c4071..93de58c 100644
--- a/pages/merchant-msg/merchant-msg.json
+++ b/pages/merchant-msg/merchant-msg.json
@@ -3,8 +3,8 @@
"global-notification": "/components/global-notification/global-notification"
},
"navigationBarTitleText": "处罚记录",
- "navigationBarBackgroundColor": "#0a0a12",
- "navigationBarTextStyle": "white",
- "backgroundColor": "#0a0a12",
+ "navigationBarBackgroundColor": "#f7dc51",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#fff8e1",
"enablePullDownRefresh": false
}
\ No newline at end of file
diff --git a/pages/merchant-msg/merchant-msg.wxss b/pages/merchant-msg/merchant-msg.wxss
index 96c1fa0..7c1666a 100644
--- a/pages/merchant-msg/merchant-msg.wxss
+++ b/pages/merchant-msg/merchant-msg.wxss
@@ -2,20 +2,20 @@
/* 🔴【样式与cfss页面基本相同,只添加了独占按钮样式】 */
:root {
- --cyber-blue: rgba(0, 243, 255, 0.7);
- --cyber-pink: rgba(255, 0, 255, 0.7);
- --cyber-purple: rgba(157, 0, 255, 0.7);
- --cyber-green: rgba(0, 255, 157, 0.7);
- --cyber-red: rgba(255, 0, 102, 0.7);
+ --cyber-blue: rgba(255, 208, 97, 0.85);
+ --cyber-pink: rgba(255, 192, 163, 0.85);
+ --cyber-purple: rgba(230, 126, 34, 0.85);
+ --cyber-green: rgba(76, 175, 80, 0.85);
+ --cyber-red: rgba(230, 74, 25, 0.85);
- --cyber-bg: #2a2a3a;
- --cyber-card: #333344;
- --cyber-border: rgba(255, 255, 255, 0.15);
- --cyber-glow: rgba(0, 243, 255, 0.2);
+ --cyber-bg: #fff8e1;
+ --cyber-card: #fef6d4;
+ --cyber-border: rgba(255, 208, 97, 0.35);
+ --cyber-glow: rgba(255, 208, 97, 0.2);
- --cyber-text: #ffffff;
- --cyber-text-light: #e6e6e6;
- --cyber-text-lighter: #cccccc;
+ --cyber-text: #333333;
+ --cyber-text-light: #666666;
+ --cyber-text-lighter: #888888;
}
.cfss-container {
@@ -38,8 +38,8 @@
bottom: 0;
background-image:
- linear-gradient(rgba(0, 243, 255, 0.05) 1px, transparent 1px),
- linear-gradient(90deg, rgba(0, 243, 255, 0.05) 1px, transparent 1px);
+ linear-gradient(rgba(255, 208, 97, 0.08) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(255, 208, 97, 0.08) 1px, transparent 1px);
background-size: 40rpx 40rpx;
pointer-events: none;
opacity: 0.15;
@@ -48,14 +48,14 @@
/* ====== 统计卡片 ====== */
.tongji-card {
- background: rgba(255, 0, 102, 0.3);
+ background: #fef6d4;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
border: 1rpx solid var(--cyber-border);
box-shadow:
0 0 20rpx rgba(255, 0, 102, 0.2),
- inset 0 0 10rpx rgba(0, 243, 255, 0.05);
+ inset 0 0 10rpx rgba(255, 208, 97, 0.05);
position: relative;
overflow: hidden;
z-index: 1;
@@ -109,7 +109,7 @@
/* ====== 类型切换 ====== */
.leixing-qiehuan {
display: flex;
- background: rgba(255, 0, 102, 0.3);
+ background: #fef6d4;
border-radius: 16rpx;
padding: 10rpx;
margin-bottom: 30rpx;
@@ -133,8 +133,8 @@
}
.leixing-active {
- background: linear-gradient(135deg, rgba(0, 243, 255, 0.15), rgba(157, 0, 255, 0.15));
- box-shadow: 0 0 15rpx rgba(0, 243, 255, 0.2);
+ background: linear-gradient(135deg, rgba(250, 224, 77, 0.25), rgba(255, 192, 163, 0.25));
+ box-shadow: 0 0 15rpx rgba(255, 208, 97, 0.2);
}
.leixing-text {
@@ -211,7 +211,7 @@
/* 处罚卡片 */
.chufa-card {
- background: rgba(560, 50, 65, 0.8);
+ background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
@@ -236,7 +236,7 @@
right: -1px;
bottom: -1px;
border-radius: 21rpx;
- background: linear-gradient(45deg, rgba(138, 60, 138, 0.3), rgba(131, 208, 212, 0.3), rgba(255, 0, 255, 0.3), rgba(0, 243, 255, 0.3));
+ background: linear-gradient(45deg, rgba(250, 224, 77, 0.3), rgba(255, 192, 163, 0.3), rgba(255, 208, 97, 0.3), rgba(255, 224, 130, 0.3));
z-index: -1;
opacity: 0;
transition: opacity 0.3s ease;
@@ -292,15 +292,15 @@
}
.zhuangtai-shensuzhong {
- background: rgba(147, 51, 234, 0.2);
- border-color: #9333ea;
- box-shadow: 0 0 8rpx rgba(147, 51, 234, 0.2);
+ background: rgba(255, 165, 0, 0.2);
+ border-color: #FFA500;
+ box-shadow: 0 0 8rpx rgba(255, 165, 0, 0.2);
}
.zhuangtai-weizhi {
- background: rgba(128, 0, 255, 0.2);
- border-color: rgba(128, 0, 255, 0.5);
- box-shadow: 0 0 8rpx rgba(128, 0, 255, 0.2);
+ background: rgba(255, 152, 0, 0.15);
+ border-color: rgba(255, 152, 0, 0.5);
+ box-shadow: 0 0 8rpx rgba(255, 152, 0, 0.2);
}
/* 其他文字内容 */
@@ -423,7 +423,7 @@
.modal-content {
position: relative;
- background: #3a3a4a;
+ background: #fff;
border-radius: 30rpx;
width: 90%;
max-height: 80vh;
@@ -458,11 +458,11 @@
justify-content: center;
border-radius: 50%;
background: rgba(137, 210, 214, 0.1);
- border: 1rpx solid rgba(0, 243, 255, 0.3);
+ border: 1rpx solid rgba(255, 208, 97, 0.3);
}
.modal-close:active {
- background: rgba(0, 243, 255, 0.2);
+ background: rgba(255, 208, 97, 0.2);
transform: scale(0.95);
}
@@ -492,7 +492,7 @@
color: var(--cyber-blue);
margin-bottom: 25rpx;
padding-bottom: 15rpx;
- border-bottom: 1rpx solid rgba(0, 243, 255, 0.2);
+ border-bottom: 1rpx solid rgba(255, 208, 97, 0.2);
text-shadow: 0 0 8rpx var(--cyber-blue);
}
@@ -534,13 +534,13 @@
font-size: 24rpx;
padding: 8rpx 20rpx;
border-radius: 8rpx;
- background: rgba(0, 243, 255, 0.1);
- border: 1rpx solid rgba(0, 243, 255, 0.3);
+ background: rgba(255, 208, 97, 0.1);
+ border: 1rpx solid rgba(255, 208, 97, 0.3);
flex-shrink: 0;
}
.fuzhi-btn:active {
- background: rgba(0, 243, 255, 0.2);
+ background: rgba(255, 208, 97, 0.2);
}
.full-row {
@@ -598,7 +598,7 @@
border-radius: 10rpx;
overflow: hidden;
position: relative;
- border: 1rpx solid rgba(0, 243, 255, 0.2);
+ border: 1rpx solid rgba(255, 208, 97, 0.2);
}
.tupian-image {
@@ -628,7 +628,7 @@
.preview-text {
color: white;
font-size: 24rpx;
- background: rgba(0, 243, 255, 0.7);
+ background: rgba(255, 208, 97, 0.7);
padding: 8rpx 16rpx;
border-radius: 8rpx;
}
@@ -636,7 +636,7 @@
/* 🔴【新增】弹窗底部按钮独占一行样式 */
.modal-footer {
padding: 30rpx;
- border-top: 1rpx solid rgba(0, 243, 255, 0.2);
+ border-top: 1rpx solid rgba(255, 208, 97, 0.2);
flex-shrink: 0;
}
@@ -666,9 +666,9 @@
/* 按钮样式 */
.btn-kefu {
- background: rgba(0, 243, 255, 0.1);
+ background: rgba(255, 208, 97, 0.1);
border-color: var(--cyber-blue);
- box-shadow: 0 0 12rpx rgba(0, 243, 255, 0.2);
+ box-shadow: 0 0 12rpx rgba(255, 208, 97, 0.2);
}
/* 响应式调整 */
@@ -712,7 +712,7 @@
aspect-ratio: 1;
border-radius: 12rpx;
overflow: hidden;
- border: 1rpx solid rgba(0, 243, 255, 0.3);
+ border: 1rpx solid rgba(255, 208, 97, 0.3);
background-color: rgba(0, 0, 0, 0.2);
}
@@ -745,7 +745,7 @@
.preview-text {
color: white;
font-size: 24rpx;
- background: rgba(0, 243, 255, 0.7);
+ background: rgba(255, 208, 97, 0.7);
padding: 8rpx 16rpx;
border-radius: 8rpx;
}
\ No newline at end of file
diff --git a/pages/merchant-order-detail/merchant-order-detail.js b/pages/merchant-order-detail/merchant-order-detail.js
index d245e7b..f9b2d64 100644
--- a/pages/merchant-order-detail/merchant-order-detail.js
+++ b/pages/merchant-order-detail/merchant-order-detail.js
@@ -2,13 +2,24 @@
const app = getApp()
import request from '../../utils/request.js'
import PopupService from '../../services/popupService.js' // 新增:导入弹窗服务
+import connectionManager from '../../utils/xiaoxilj.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: '', zhuangtai: 0, fadanpingtai: 0
+ jine: '', nicheng: '', beizhu: '', waibu_dingdan_id: '', zhuangtai: 0, fadanpingtai: 0
},
dashouInfo: { yonghuid: '', nicheng: '', avatar: '' },
dispatchStaff: null,
@@ -20,8 +31,8 @@ Page({
fenhongLilv: 0,
xinDingdanId: '',
zhuangtaiYanseMap: {
- 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#F3E8FF',
- 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#F5F3FF'
+ 1: '#E8F5E9', 2: '#E3F2FD', 3: '#F3E5F5', 4: '#FFF3E0',
+ 5: '#FFEBEE', 6: '#EFEBE9', 7: '#E0F7FA', 8: '#FFF8E1'
},
zhuangtaiWenziMap: {
1: '已下单', 2: '进行中', 3: '已完成', 4: '退款中',
@@ -60,6 +71,19 @@ Page({
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) {
@@ -74,6 +98,7 @@ Page({
onShow() {
this.registerNotificationComponent()
syncStaffUi(this)
+ this.refreshPenaltyApplyBtn()
this.ensureIMConnection()
},
@@ -256,8 +281,10 @@ Page({
fadanData: d.fadan || null,
fenhongLilv: parseFloat(d.fenhong_lilv) || 0,
xinDingdanId: d.xin_dingdan_id || '',
- 'jibenShuju.zhuangtai': d.zhuangtai || this.data.jibenShuju.zhuangtai
+ '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' })
}
@@ -298,7 +325,7 @@ Page({
})
},
- // ===== 联系打手(替打手订阅 + 发机器人消息 + 跳转) =====
+ // ===== 联系打手(订单群 groupId = 订单号) =====
goToChatWithDashou() {
if (isStaffMode() && !staffCan('imChat')) {
wx.showToast({ title: '当前角色无订单聊天权限', icon: 'none' })
@@ -313,43 +340,37 @@ Page({
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
+ const that = this
- // 第一步:商家自己订阅群组
- 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' })
- }
- })
+ const openGroupChat = () => {
+ connectionManager.connectToGroupChat({
+ identityType: 'shangjia',
+ userId: 'Sj' + uid,
+ orderId: orderId,
+ partnerUid: dashouUid,
+ fadanPingtai: this.data.jibenShuju.fadanpingtai || 0,
+ groupName,
+ isCross,
+ }).catch((err) => {
+ console.error('跳转群聊失败', err)
+ wx.showToast({ title: '跳转聊天失败', icon: 'none' })
+ })
+ }
+
+ if (dashouUid) {
+ that.bangDashouDingyue(orderId, dashouUid)
+ .then(openGroupChat)
+ .catch((err) => {
+ console.error('替打手订阅失败,仍可进入群聊', err)
+ wx.showToast({ title: '通知接单员可能失败', icon: 'none' })
+ openGroupChat()
+ })
+ } else {
+ openGroupChat()
+ }
},
// 帮打手订阅群组 + 发送机器人消息
@@ -406,20 +427,6 @@ Page({
})
},
- // 跳转群聊页面
- 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 }) },
@@ -450,7 +457,13 @@ Page({
}
},
- showFakuanModal() { this.setData({ showFakuanModal: true, fakuanLiyou: '', fakuanJine: '', yingxiangQiangdan: true }) },
+ showFakuanModal() {
+ const dingdanId = this.data.jibenShuju.dingdan_id
+ if (dingdanId) {
+ this.jiazaiXiangxiShuju(dingdanId)
+ }
+ 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 }) },
@@ -517,6 +530,7 @@ Page({
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' })
@@ -548,6 +562,7 @@ Page({
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' })
@@ -586,6 +601,7 @@ Page({
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' })
diff --git a/pages/merchant-order-detail/merchant-order-detail.wxml b/pages/merchant-order-detail/merchant-order-detail.wxml
index c9b5e5e..0f6441b 100644
--- a/pages/merchant-order-detail/merchant-order-detail.wxml
+++ b/pages/merchant-order-detail/merchant-order-detail.wxml
@@ -29,6 +29,8 @@
游戏昵称{{jibenShuju.nicheng}}
备注{{jibenShuju.beizhu}}
+
+ 拼多多订单号{{jibenShuju.waibu_dingdan_id}}📋
订单ID{{jibenShuju.dingdan_id}}📋
@@ -58,8 +60,8 @@
- 撤销退款申请
- 修改退款理由
+ 撤销退款申请
+ 修改退款理由
@@ -135,14 +137,12 @@
更新时间{{fadanData.update_time}}
-
- 修改罚款
- 撤销罚款
+ 修改罚款
+ 撤销罚款
-
- 再次申请罚款
+ 再次申请罚款
@@ -169,25 +169,21 @@
- 立即结算
+ 立即结算
-
-
+
- 联系客服
- 联系接单员
+ 联系客服
+ 联系接单员
-
-
- 撤销订单
-
-
-
- 申请退款
+ 撤销订单
+ 更换接单员
+ 申请退款
+ 申请罚款
@@ -223,7 +219,7 @@
更换接单员×
- 确认更换接单员吗?当前订单将被撤销,并生成一条相同内容的新订单(接单员清空)。
+ 确认更换接单员吗?当前订单将被撤销,并生成一条相同内容的新订单(接单员清空,拼多多订单号将保留)。
取消
diff --git a/pages/merchant-order-detail/merchant-order-detail.wxss b/pages/merchant-order-detail/merchant-order-detail.wxss
index aa54dd5..7aed2dd 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: #a855f7; 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: #9333ea; 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: #9333ea; 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: #9333ea;
- 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(196, 181, 253,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 #ffd061;
+}
+
+.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 7ba5bb8..a1a899a 100644
--- a/pages/merchant-orders/merchant-orders.js
+++ b/pages/merchant-orders/merchant-orders.js
@@ -5,52 +5,90 @@ 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 { fetchMerchantOrderStats } from '../../utils/merchant-order-stats.js';
+
+const EMPTY_TAB = { list: [], page: 1, hasMore: true, isLoading: false };
+
+function buildEmptyStatusData() {
+ return {
+ all: { ...EMPTY_TAB },
+ daifuwu: { ...EMPTY_TAB },
+ zhidingzhong: { ...EMPTY_TAB },
+ jinxingzhong: { ...EMPTY_TAB },
+ tuikuanzhong: { ...EMPTY_TAB },
+ yituikuan: { ...EMPTY_TAB },
+ tuikuanshibai: { ...EMPTY_TAB },
+ yiwancheng: { ...EMPTY_TAB },
+ jiesuanzhong: { ...EMPTY_TAB },
+ };
+}
+
+const STATUS_TAG_STYLE = {
+ 1: { color: '#E65100', bg: '#FFF3E0' },
+ 2: { color: '#1565C0', bg: '#E3F2FD' },
+ 3: { color: '#2E7D32', bg: '#E8F5E9' },
+ 4: { color: '#EF6C00', bg: '#FFF8E1' },
+ 5: { color: '#616161', bg: '#F5F5F5' },
+ 6: { color: '#C62828', bg: '#FFEBEE' },
+ 7: { color: '#BF360C', bg: '#FFE0B2' },
+ 8: { color: '#D84315', bg: '#FBE9E7' },
+};
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: 'daifuwu', zhuangtaiList: [1], color: '#E65100' },
+ { name: '指定中', key: 'zhidingzhong', zhuangtaiList: [7], color: '#BF360C' },
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
- { name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#9333ea' },
+ { name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#FF9800' },
{ 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,
+ 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() {
+ onLoad(options) {
+ this._listInitialized = false;
+ this._savedScrollTop = 0;
+ this._skipShowRefresh = false;
wx.setNavigationBarTitle({ title: isStaffMode() ? '客服派单' : '我的派单' });
syncStaffUi(this);
if (isStaffMode()) {
@@ -58,6 +96,15 @@ Page(createPage({
}
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();
+ }
},
async onShow() {
@@ -65,40 +112,147 @@ Page(createPage({
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) {
@@ -106,16 +260,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);
@@ -124,26 +278,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 {
@@ -151,67 +355,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: 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 || '加载失败');
@@ -223,94 +422,91 @@ 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: isStaffMode() ? STAFF_API.orderList : '/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 st = Number(item.zhuangtai);
+ const tagStyle = STATUS_TAG_STYLE[st] || { color: zhuangtaiColor || '#333', bg: '#F5F5F5' };
+
+ return {
+ ...item,
+ zhuangtaiZh: getOrderStatusText(st),
+ zhuangtaiColor: tagStyle.color,
+ zhuangtaiBg: tagStyle.bg,
+ creat_time: item.creat_time || item.create_time || '',
+ };
+ },
+
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..640e2c2 100644
--- a/pages/merchant-orders/merchant-orders.wxml
+++ b/pages/merchant-orders/merchant-orders.wxml
@@ -1,135 +1,162 @@
-
-
-
-
-
-
-
-
-
- {{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.dingdan_id}}
+ {{item.zhuangtaiZh}}
+
+ {{item.jieshao || '暂无介绍'}}
+
+ ¥{{item.jine || '0.00'}}
+ {{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 7c14df1..014a4bf 100644
--- a/pages/merchant-orders/merchant-orders.wxss
+++ b/pages/merchant-orders/merchant-orders.wxss
@@ -1,428 +1,646 @@
-/* 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, #ede9fe, #ddd6fe);
- border-left: 8rpx solid #9333ea;
- border-radius: 16rpx;
- display: flex;
- align-items: center;
- gap: 16rpx;
- box-shadow: 0 8rpx 20rpx rgba(147, 51, 234,0.3);
- flex-shrink: 0;
- }
- .sj-pending-icon {
- font-size: 36rpx;
- color: #9333ea;
- }
- .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: #9333ea;
- box-shadow: 0 0 15rpx #ff4d4f;
- }
- .card-price {
- display: flex;
- align-items: baseline;
- white-space: nowrap;
- }
- .price-symbol {
- font-size: 28rpx;
- color: #9333ea;
- 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;
+ overflow: hidden;
+ box-sizing: border-box;
+ }
+
+ /* ========== 商品类型区 ========== */
+ .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;
+ padding: 0 24rpx 16rpx;
+ background: #fff;
+ border-bottom: 1rpx solid #f0f0f0;
+ gap: 16rpx;
+ flex-shrink: 0;
+ }
+ .staff-filter-pill {
+ display: inline-flex;
+ align-items: center;
+ max-width: 100%;
+ padding: 12rpx 24rpx;
+ border-radius: 32rpx;
+ background: #f7f7f7;
+ border: 1rpx solid #eee;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+ }
+ .staff-filter-pill--active {
+ background: linear-gradient(180deg, #fff8e1, #ffe9b8);
+ border-color: #e8c547;
+ box-shadow: 0 4rpx 12rpx rgba(232, 197, 71, 0.25);
+ }
+ .staff-filter-tag {
+ flex-shrink: 0;
+ font-size: 22rpx;
+ font-weight: 700;
+ color: #8a6d2b;
+ padding: 4rpx 12rpx;
+ margin-right: 12rpx;
+ border-radius: 16rpx;
+ background: rgba(255, 255, 255, 0.65);
+ }
+ .staff-filter-pill--active .staff-filter-tag {
+ background: rgba(255, 255, 255, 0.85);
+ color: #492f00;
+ }
+ .staff-filter-value {
+ flex: 1;
+ min-width: 0;
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #333;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .staff-filter-pill--active .staff-filter-value {
+ color: #492f00;
+ }
+ .staff-filter-arrow {
+ flex-shrink: 0;
+ margin-left: 8rpx;
+ font-size: 22rpx;
+ color: #999;
+ }
+ .staff-filter-pill--active .staff-filter-arrow {
+ color: #8a6d2b;
+ }
+ .staff-filter-clear {
+ flex-shrink: 0;
+ font-size: 24rpx;
+ color: #c9a227;
+ padding: 10rpx 16rpx;
+ border-radius: 24rpx;
+ background: #fff8e8;
+ border: 1rpx solid #f0d89a;
+ }
+
+ /* ========== 待结算提示条(保留原样式) ========== */
+ .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;
+ min-height: 0;
+ }
+
+ /* 左侧状态栏 */
+ .left-status {
+ width: 180rpx;
+ height: 100%;
+ background: #fff;
+ border-right: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ }
+ .left-status-inner {
+ padding: 12rpx 0 48rpx;
+ }
+ .status-item {
+ padding: 22rpx 16rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ position: relative;
+ flex-wrap: wrap;
+ gap: 6rpx;
+ }
+ .status-item.status-active {
+ background: linear-gradient(to right, #e3f2fd, #fff);
+ }
+ .status-name {
+ font-size: 26rpx;
+ color: #555;
+ flex: 1;
+ min-width: 0;
+ }
+ .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);
+ }
+
+ /* 简洁订单卡片 */
+ .sj-order-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 16rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+ border: 1rpx solid #eee;
+ }
+ .sj-order-card:active {
+ opacity: 0.92;
+ }
+ .sj-order-card-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12rpx;
+ gap: 16rpx;
+ }
+ .sj-order-id {
+ font-size: 24rpx;
+ color: #888;
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .sj-status-tag {
+ flex-shrink: 0;
+ font-size: 24rpx;
+ font-weight: 700;
+ padding: 8rpx 20rpx;
+ border-radius: 999rpx;
+ }
+ .sj-order-desc {
+ font-size: 30rpx;
+ color: #222;
+ line-height: 1.5;
+ font-weight: 500;
+ margin-bottom: 12rpx;
+ }
+ .sj-order-meta {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+ .sj-order-amount {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #e53935;
+ }
+ .sj-order-time {
+ font-size: 22rpx;
+ color: #aaa;
+ }
+ .sj-order-remark {
+ margin-top: 10rpx;
+ font-size: 24rpx;
+ color: #666;
+ line-height: 1.4;
+ }
+ .line2 {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
}
\ 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..75f36c7
--- /dev/null
+++ b/pages/merchant-penalty/merchant-penalty.wxss
@@ -0,0 +1,76 @@
+page { background: #fff8e1; }
+.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-rank/merchant-rank.json b/pages/merchant-rank/merchant-rank.json
index 1a33122..2e98ac2 100644
--- a/pages/merchant-rank/merchant-rank.json
+++ b/pages/merchant-rank/merchant-rank.json
@@ -3,10 +3,10 @@
"global-notification": "/components/global-notification/global-notification"
},
"navigationBarTitleText": "商家排行榜",
- "navigationBarBackgroundColor": "#000000",
- "navigationBarTextStyle": "white",
+ "navigationBarBackgroundColor": "#f7dc51",
+ "navigationBarTextStyle": "black",
"enablePullDownRefresh": false,
- "backgroundColor": "#000000",
+ "backgroundColor": "#fff8e1",
"backgroundTextStyle": "dark",
"onReachBottomDistance": 50
}
\ No newline at end of file
diff --git a/pages/merchant-recharge/merchant-recharge.json b/pages/merchant-recharge/merchant-recharge.json
index 85fce31..48942a7 100644
--- a/pages/merchant-recharge/merchant-recharge.json
+++ b/pages/merchant-recharge/merchant-recharge.json
@@ -1,8 +1,8 @@
{
"navigationBarTitleText": "商家充值",
- "navigationBarBackgroundColor": "#0a0e17",
- "navigationBarTextStyle": "white",
- "backgroundColor": "#0a0e17",
+ "navigationBarBackgroundColor": "#f7dc51",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#fff8e1",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false,
"usingComponents": {
diff --git a/pages/merchant-recharge/merchant-recharge.wxss b/pages/merchant-recharge/merchant-recharge.wxss
index 3b1fed0..ab2fa7a 100644
--- a/pages/merchant-recharge/merchant-recharge.wxss
+++ b/pages/merchant-recharge/merchant-recharge.wxss
@@ -6,23 +6,23 @@
/* 科技主题色 - 增强对比度 */
:root {
- --primary-color: #00f3ff; /* 主科技蓝 */
- --primary-light: #4dfbff; /* 亮科技蓝 */
- --primary-dark: #00a0b0; /* 暗科技蓝 */
- --secondary-color: #ff2a6d; /* 科技粉红 */
- --accent-color: #c4b5fd; /* 科技金 */
- --accent-purple: #9d4edd; /* 科技紫 */
- --dark-bg: #0a0e17; /* 深色背景 */
- --medium-bg: #13182b; /* 中色背景 */
- --light-bg: #1c2238; /* 浅色背景 */
- --card-bg: rgba(20, 25, 40, 0.85); /* 卡片背景 - 提高透明度 */
- --border-glow: rgba(0, 243, 255, 0.4);
- --text-primary: #ffffff; /* 主要文字 */
- --text-secondary: #a0aec0; /* 次要文字 */
- --text-highlight: #ffffff; /* 高亮文字 */
- --text-glow: #00f3ff; /* 发光文字 */
- --shadow-tech: 0 8rpx 24rpx rgba(0, 0, 0, 0.5);
- --shadow-glow: 0 0 20rpx rgba(0, 243, 255, 0.25);
+ --primary-color: #ffd061;
+ --primary-light: #ffe082;
+ --primary-dark: #e6a020;
+ --secondary-color: #ffc0a3;
+ --accent-color: #e67e22;
+ --accent-purple: #ffb74d;
+ --dark-bg: #fff8e1;
+ --medium-bg: #fff9f0;
+ --light-bg: #fff8e1;
+ --card-bg: #fef6d4;
+ --border-glow: rgba(255, 208, 97, 0.4);
+ --text-primary: #222222;
+ --text-secondary: #666666;
+ --text-highlight: #492f00;
+ --text-glow: #e67e22;
+ --shadow-tech: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
+ --shadow-glow: 0 0 20rpx rgba(255, 208, 97, 0.25);
}
/* 全局页面样式 - 修复背景 */
@@ -31,9 +31,9 @@
color: var(--text-primary);
min-height: 100vh;
background: linear-gradient(145deg,
- var(--dark-bg) 0%,
- var(--medium-bg) 50%,
- var(--light-bg) 100%
+ #f7dc51 0%,
+ #fff8e1 50%,
+ #fff9f0 100%
) !important;
position: relative;
overflow-x: hidden;
@@ -46,17 +46,17 @@
/* ========== 余额卡片样式 - 完全重写 ========== */
.balance-card {
- background: rgba(20, 25, 40, 0.9); /* 降低透明度,提高文字可见性 */
+ background: #fef6d4; /* 降低透明度,提高文字可见性 */
border-radius: 25rpx;
padding: 35rpx 25rpx;
margin: 0 0 35rpx;
position: relative;
overflow: hidden;
- border: 1.5rpx solid rgba(0, 243, 255, 0.3);
+ border: 1.5rpx solid rgba(255, 208, 97, 0.3);
box-shadow:
var(--shadow-tech),
var(--shadow-glow),
- inset 0 0 15rpx rgba(0, 243, 255, 0.08);
+ inset 0 0 15rpx rgba(255, 208, 97, 0.08);
z-index: 1;
/* 移除或大幅降低毛玻璃效果 */
backdrop-filter: blur(2px);
@@ -82,9 +82,9 @@
letter-spacing: 1.5rpx;
color: var(--text-primary) !important; /* 强制使用白色,确保可见 */
text-shadow:
- 0 0 15rpx rgba(0, 243, 255, 0.8),
- 0 0 30rpx rgba(0, 243, 255, 0.4),
- 0 0 45rpx rgba(0, 243, 255, 0.2);
+ 0 0 15rpx rgba(255, 208, 97, 0.8),
+ 0 0 30rpx rgba(255, 208, 97, 0.4),
+ 0 0 45rpx rgba(255, 208, 97, 0.2);
position: relative;
display: inline-block;
/* 移除背景渐变,直接用纯色加阴影 */
@@ -142,10 +142,10 @@
/* VIP商家标签 */
.balance-chip {
background: linear-gradient(90deg,
- rgba(0, 243, 255, 0.15),
+ rgba(255, 208, 97, 0.15),
rgba(255, 42, 109, 0.15)
);
- border: 1rpx solid rgba(0, 243, 255, 0.3);
+ border: 1rpx solid rgba(255, 208, 97, 0.3);
border-radius: 20rpx;
padding: 10rpx 20rpx;
display: flex;
@@ -154,8 +154,8 @@
height: 44rpx;
min-width: 180rpx;
box-shadow:
- 0 4rpx 12rpx rgba(0, 243, 255, 0.2),
- inset 0 0 8rpx rgba(0, 243, 255, 0.1);
+ 0 4rpx 12rpx rgba(255, 208, 97, 0.2),
+ inset 0 0 8rpx rgba(255, 208, 97, 0.1);
position: relative;
z-index: 10; /* 确保在最上层 */
}
@@ -184,8 +184,8 @@
color: var(--accent-color) !important; /* 使用金色,确保可见 */
margin-right: 8rpx;
text-shadow:
- 0 0 20rpx rgba(196, 181, 253, 0.7),
- 0 0 40rpx rgba(196, 181, 253, 0.4);
+ 0 0 20rpx rgba(255, 215, 0, 0.7),
+ 0 0 40rpx rgba(255, 215, 0, 0.4);
display: inline-block;
vertical-align: middle;
line-height: 1;
@@ -201,9 +201,9 @@
color: var(--text-primary) !important; /* 强制使用白色 */
line-height: 1;
text-shadow:
- 0 0 20rpx rgba(0, 243, 255, 0.8),
- 0 0 40rpx rgba(0, 243, 255, 0.5),
- 0 0 60rpx rgba(0, 243, 255, 0.3);
+ 0 0 20rpx rgba(255, 208, 97, 0.8),
+ 0 0 40rpx rgba(255, 208, 97, 0.5),
+ 0 0 60rpx rgba(255, 208, 97, 0.3);
letter-spacing: -1.5rpx;
display: inline-block;
position: relative;
@@ -242,10 +242,10 @@
display: flex;
align-items: center;
justify-content: center;
- background: rgba(0, 243, 255, 0.08);
+ background: rgba(255, 208, 97, 0.08);
padding: 10rpx 22rpx;
border-radius: 18rpx;
- border: 1rpx solid rgba(0, 243, 255, 0.2);
+ border: 1rpx solid rgba(255, 208, 97, 0.2);
min-width: 150rpx;
}
@@ -337,7 +337,7 @@
/* ========== 充值金额区域 ========== */
.amount-section {
- background: rgba(25, 30, 48, 0.9);
+ background: #fef6d4;
border-radius: 25rpx;
padding: 35rpx 25rpx;
margin-bottom: 35rpx;
@@ -345,7 +345,7 @@
backdrop-filter: blur(4px);
box-shadow:
var(--shadow-tech),
- inset 0 0 15rpx rgba(0, 243, 255, 0.05);
+ inset 0 0 15rpx rgba(255, 208, 97, 0.05);
position: relative;
z-index: 1;
}
@@ -387,8 +387,8 @@
}
.amount-item {
- background: rgba(255, 255, 255, 0.05);
- border: 2rpx solid rgba(255, 255, 255, 0.12);
+ background: rgba(255, 255, 255, 0.85);
+ border: 2rpx solid rgba(255, 208, 97, 0.35);
border-radius: 18rpx;
padding: 26rpx 10rpx;
text-align: center;
@@ -408,15 +408,15 @@
.amount-item.active {
background: linear-gradient(135deg,
- rgba(0, 243, 255, 0.15),
- rgba(157, 78, 221, 0.15)
+ rgba(250, 224, 77, 0.35),
+ rgba(255, 192, 163, 0.35)
);
border-color: var(--primary-color);
transform: translateY(-3rpx);
box-shadow:
- 0 10rpx 25rpx rgba(0, 243, 255, 0.2),
- 0 0 30rpx rgba(0, 243, 255, 0.1),
- inset 0 0 12rpx rgba(0, 243, 255, 0.1);
+ 0 10rpx 25rpx rgba(255, 208, 97, 0.2),
+ 0 0 30rpx rgba(255, 208, 97, 0.1),
+ inset 0 0 12rpx rgba(255, 208, 97, 0.1);
}
.amount-text {
@@ -442,7 +442,7 @@
height: 90%;
background: radial-gradient(
circle at center,
- rgba(0, 243, 255, 0.2) 0%,
+ rgba(255, 208, 97, 0.2) 0%,
transparent 70%
);
border-radius: 50%;
@@ -491,7 +491,7 @@
font-size: 42rpx;
font-weight: 800;
color: var(--accent-color) !important;
- text-shadow: 0 0 10rpx rgba(196, 181, 253, 0.5);
+ text-shadow: 0 0 10rpx rgba(255, 215, 0, 0.5);
z-index: 10;
padding-left: 10rpx;
}
@@ -515,7 +515,7 @@
.custom-input:focus {
border-bottom-color: var(--primary-color);
- box-shadow: 0 0 15rpx rgba(0, 243, 255, 0.3);
+ box-shadow: 0 0 15rpx rgba(255, 208, 97, 0.3);
}
.placeholder {
@@ -589,23 +589,23 @@
/* 激活状态 - 修复为科技蓝渐变 */
.pay-button.active {
background: linear-gradient(135deg,
- #008ca3, /* 深蓝 */
- #00b8d4, /* 中蓝 */
- #00f3ff /* 亮蓝 */
+ #fae04d,
+ #ffc0a3,
+ #ffd061
);
- border: 1.5rpx solid rgba(0, 243, 255, 0.6);
+ border: 1.5rpx solid rgba(255, 208, 97, 0.6);
box-shadow:
- 0 12rpx 35rpx rgba(0, 243, 255, 0.4),
- 0 0 50rpx rgba(0, 243, 255, 0.3),
- inset 0 0 20rpx rgba(0, 243, 255, 0.15);
+ 0 12rpx 35rpx rgba(255, 208, 97, 0.4),
+ 0 0 50rpx rgba(255, 208, 97, 0.3),
+ inset 0 0 20rpx rgba(255, 208, 97, 0.15);
}
.pay-button.active:active {
transform: scale(0.98);
box-shadow:
- 0 8rpx 25rpx rgba(0, 243, 255, 0.4),
- 0 0 35rpx rgba(0, 243, 255, 0.3),
- inset 0 0 15rpx rgba(0, 243, 255, 0.15);
+ 0 8rpx 25rpx rgba(255, 208, 97, 0.4),
+ 0 0 35rpx rgba(255, 208, 97, 0.3),
+ inset 0 0 15rpx rgba(255, 208, 97, 0.15);
}
/* 按钮闪光特效 */
@@ -658,7 +658,7 @@
color: white !important;
text-shadow:
0 0 12rpx rgba(255, 255, 255, 0.8),
- 0 0 25rpx rgba(0, 243, 255, 0.6);
+ 0 0 25rpx rgba(255, 208, 97, 0.6);
}
/* ========== 支付状态提示 ========== */
@@ -668,7 +668,7 @@
left: 0;
right: 0;
bottom: 0;
- background: rgba(10, 14, 23, 0.95);
+ background: rgba(255, 248, 225, 0.95);
display: flex;
justify-content: center;
align-items: center;
@@ -678,8 +678,8 @@
.status-content {
background: linear-gradient(135deg,
- rgba(25, 30, 48, 0.95),
- rgba(40, 47, 75, 0.95)
+ #fff,
+ #fef6d4
);
border-radius: 28rpx;
padding: 60rpx 40rpx;
@@ -689,7 +689,7 @@
border: 2rpx solid var(--primary-color);
box-shadow:
0 20rpx 50rpx rgba(0, 0, 0, 0.6),
- 0 0 50rpx rgba(0, 243, 255, 0.4);
+ 0 0 50rpx rgba(255, 208, 97, 0.4);
position: relative;
overflow: hidden;
animation: statusAppear 0.3s ease-out;
@@ -706,7 +706,7 @@
color: var(--text-primary) !important;
display: block;
margin-bottom: 15rpx;
- text-shadow: 0 0 10rpx rgba(0, 243, 255, 0.6);
+ text-shadow: 0 0 10rpx rgba(255, 208, 97, 0.6);
position: relative;
z-index: 10;
}
@@ -729,13 +729,13 @@
}
.action-button {
- background: linear-gradient(135deg, #008ca3, #00f3ff);
+ background: linear-gradient(135deg, #fae04d, #ffd061);
border-radius: 20rpx;
padding: 20rpx 40rpx;
min-width: 200rpx;
box-shadow:
- 0 8rpx 24rpx rgba(0, 243, 255, 0.4),
- 0 0 16rpx rgba(0, 243, 255, 0.3);
+ 0 8rpx 24rpx rgba(255, 208, 97, 0.4),
+ 0 0 16rpx rgba(255, 208, 97, 0.3);
display: flex;
align-items: center;
justify-content: center;
@@ -745,8 +745,8 @@
.action-button:active {
transform: scale(0.95);
box-shadow:
- 0 4rpx 12rpx rgba(0, 243, 255, 0.4),
- 0 0 8rpx rgba(0, 243, 255, 0.3);
+ 0 4rpx 12rpx rgba(255, 208, 97, 0.4),
+ 0 0 8rpx rgba(255, 208, 97, 0.3);
}
.action-text {
@@ -764,7 +764,7 @@
left: 0;
right: 0;
bottom: 0;
- background: rgba(10, 14, 23, 0.92);
+ background: rgba(255, 248, 225, 0.92);
display: flex;
justify-content: center;
align-items: center;
@@ -793,7 +793,7 @@
margin: 0 auto 30rpx;
box-shadow:
0 0 20rpx var(--primary-color),
- inset 0 0 12rpx rgba(0, 243, 255, 0.2);
+ inset 0 0 12rpx rgba(255, 208, 97, 0.2);
position: relative;
}
@@ -805,7 +805,7 @@
.loading-text {
font-size: 28rpx;
color: var(--text-primary);
- text-shadow: 0 0 10rpx rgba(0, 243, 255, 0.6);
+ text-shadow: 0 0 10rpx rgba(255, 208, 97, 0.6);
letter-spacing: 1rpx;
}
@@ -814,12 +814,12 @@
/* ========== 修复背景颜色和间距 ========== */
-/* 1. 调整背景颜色为更亮的科技风 */
+/* 1. 橙黄主题背景 */
page {
- background: linear-gradient(135deg,
- #0e1424 0%, /* 调亮深色部分 */
- #1a2238 50%,
- #242d45 100%
+ background: linear-gradient(180deg,
+ #f7dc51 0%,
+ #fff8e1 50%,
+ #fff9f0 100%
) !important;
height: 100%;
}
@@ -836,8 +836,8 @@ page {
margin: 0 0 30rpx !important; /* 增加下方间距 */
padding: 35rpx 25rpx !important; /* 增加内边距 */
border-radius: 25rpx !important;
- background: rgba(25, 30, 48, 0.9) !important; /* 调亮背景 */
- border: 1.5rpx solid rgba(0, 243, 255, 0.4) !important; /* 加强边框 */
+ background: #fef6d4 !important; /* 调亮背景 */
+ border: 1.5rpx solid rgba(255, 208, 97, 0.4) !important; /* 加强边框 */
}
/* 4. 调整余额字体和颜色 - 确保可见 */
@@ -847,21 +847,19 @@ page {
.currency {
font-size: 42rpx !important;
- color: #c4b5fd !important; /* 使用更亮的金色 */
- text-shadow: 0 0 20rpx rgba(196, 181, 253, 0.8) !important;
+ color: #e67e22 !important;
+ text-shadow: none !important;
}
.amount {
- font-size: 72rpx !important; /* 稍微调大 */
- color: #ffffff !important;
- text-shadow:
- 0 0 25rpx rgba(0, 243, 255, 0.8),
- 0 0 50rpx rgba(0, 243, 255, 0.5) !important;
+ font-size: 72rpx !important;
+ color: #222 !important;
+ text-shadow: none !important;
}
.unit {
font-size: 30rpx !important;
- color: #a0aec0 !important; /* 调亮灰色 */
+ color: #666 !important;
}
/* 5. 调整充值金额区域 */
@@ -869,7 +867,7 @@ page {
margin-bottom: 30rpx !important;
padding: 30rpx 25rpx !important;
border-radius: 25rpx !important;
- background: rgba(30, 35, 55, 0.9) !important; /* 调亮背景 */
+ background: #fff !important; /* 调亮背景 */
}
/* 6. 调整快捷金额网格 */
@@ -885,7 +883,7 @@ page {
.amount-text {
font-size: 32rpx !important;
- color: #ffffff !important;
+ color: #333 !important;
}
/* 7. 调整输入区域 - 修复占位符溢出问题 */
@@ -900,27 +898,27 @@ page {
.custom-input {
padding: 28rpx 20rpx 28rpx 60rpx !important;
- height: 145rpx !important; /* 增加高度,让内容有足够空间 */
+ height: 145rpx !important;
font-size: 40rpx !important;
- color: #ffffff !important;
- border-bottom: 2rpx solid rgba(255, 255, 255, 0.2) !important;
+ color: #222 !important;
+ border-bottom: 2rpx solid rgba(0, 0, 0, 0.12) !important;
}
.custom-input:focus {
- border-bottom-color: #00f3ff !important;
- box-shadow: 0 0 20rpx rgba(0, 243, 255, 0.4) !important;
+ border-bottom-color: #ffd061 !important;
+ box-shadow: 0 0 20rpx rgba(255, 208, 97, 0.4) !important;
}
.input-label {
font-size: 40rpx !important;
- color: #c4b5fd !important; /* 使用金色 */
- text-shadow: 0 0 15rpx rgba(196, 181, 253, 0.6) !important;
+ color: #e67e22 !important;
+ text-shadow: none !important;
top: 50% !important;
transform: translateY(-50%) !important;
}
.placeholder {
- color: rgba(160, 174, 192, 0.8) !important; /* 调亮占位符 */
+ color: rgba(102, 102, 102, 0.7) !important;
font-size: 34rpx !important;
font-weight: 500 !important;
}
@@ -937,49 +935,45 @@ page {
.pay-button.active {
background: linear-gradient(135deg,
- #0099b0, /* 更亮的蓝 */
- #00ccff, /* 亮蓝 */
- #00f3ff /* 最亮蓝 */
+ #fae04d,
+ #ffc0a3,
+ #ffd061
) !important;
- border: 1.5rpx solid rgba(0, 243, 255, 0.8) !important;
+ border: 1.5rpx solid rgba(255, 208, 97, 0.8) !important;
}
.button-text {
font-size: 36rpx !important;
- color: #ffffff !important;
- text-shadow: 0 0 10rpx rgba(0, 243, 255, 0.8) !important;
+ color: #492f00 !important;
+ text-shadow: none !important;
}
- /* 9. 调整标题文字颜色 - 确保清晰可见 */
.title-text {
font-size: 36rpx !important;
- color: #ffffff !important;
- text-shadow:
- 0 0 20rpx rgba(0, 243, 255, 0.8),
- 0 0 40rpx rgba(0, 243, 255, 0.4) !important;
+ color: #222 !important;
+ text-shadow: none !important;
}
.section-title {
font-size: 34rpx !important;
- color: #ffffff !important;
- text-shadow: 0 0 15rpx rgba(255, 255, 255, 0.3) !important;
+ color: #222 !important;
+ text-shadow: none !important;
}
.subtitle-text,
.amount-hint {
- color: #b8c2cc !important; /* 调亮灰色文字 */
+ color: #666 !important;
font-size: 26rpx !important;
}
- /* 10. 调整卡片文字颜色 */
.chip-text {
- color: #ffffff !important;
- text-shadow: 0 0 8rpx rgba(0, 243, 255, 0.6) !important;
+ color: #492f00 !important;
+ text-shadow: none !important;
}
.tag-text {
- color: #4dfbff !important; /* 使用亮科技蓝 */
- text-shadow: 0 0 8rpx rgba(0, 243, 255, 0.4) !important;
+ color: #e67e22 !important;
+ text-shadow: none !important;
}
/* 11. 增强装饰元素可见性(但不干扰文字) */
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..2baf92f
--- /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": "#f7dc51",
+ "navigationBarTitleText": "常规发单",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#fff8e1",
+ "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.wxss b/pages/merchant-staff-audit/merchant-staff-audit.wxss
index e0282da..8f7e0ee 100644
--- a/pages/merchant-staff-audit/merchant-staff-audit.wxss
+++ b/pages/merchant-staff-audit/merchant-staff-audit.wxss
@@ -1,17 +1,17 @@
-.page { padding: 24rpx; background: #f5f5f5; min-height: 100vh; box-sizing: border-box; }
+.page { padding: 24rpx; background: #fff8e1; 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: #9333ea; color: #fff; }
+.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: #9333ea; }
+.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: #f3e8ff; color: #7c3aed; }
+.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; }
@@ -20,6 +20,6 @@
.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 #9333ea; }
-.jump-tip { display: block; font-size: 24rpx; color: #9333ea; margin-top: 8rpx; }
+.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.wxss b/pages/merchant-staff-role/merchant-staff-role.wxss
index 12ac9ac..b606080 100644
--- a/pages/merchant-staff-role/merchant-staff-role.wxss
+++ b/pages/merchant-staff-role/merchant-staff-role.wxss
@@ -2,7 +2,7 @@
.role-page {
min-height: 100vh;
- background: linear-gradient(180deg, #c4b5fd 0%, #fff 28%, #f5f3ff 100%);
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
box-sizing: border-box;
}
@@ -26,7 +26,7 @@
width: 60rpx;
text-align: right;
font-size: 28rpx;
- color: #9333ea;
+ color: #c9a962;
}
.role-scroll {
@@ -130,7 +130,7 @@
}
.perm-row.perm-on {
- background: #faf5ff;
+ background: #fffbf0;
}
.perm-text {
@@ -158,7 +158,7 @@
line-height: 48rpx;
text-align: center;
font-size: 32rpx;
- color: #9333ea;
+ color: #c9a962;
font-weight: 700;
border: 2rpx solid #ddd;
border-radius: 8rpx;
@@ -166,8 +166,8 @@
}
.perm-on .perm-check {
- border-color: #9333ea;
- background: #9333ea;
+ border-color: #c9a962;
+ background: #c9a962;
color: #fff;
}
@@ -212,7 +212,7 @@
}
.panel-btn.ok {
- background: #9333ea;
+ background: #c9a962;
color: #fff;
}
diff --git a/pages/merchant/merchant.js b/pages/merchant/merchant.js
index 322541a..54ff719 100644
--- a/pages/merchant/merchant.js
+++ b/pages/merchant/merchant.js
@@ -6,7 +6,10 @@ 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();
@@ -33,6 +36,7 @@ Page(createPage({
iconCopy: '',
avatarFrame: '',
iconClear: '',
+ iconKefuList: '',
},
// 商家状态
@@ -50,6 +54,7 @@ Page(createPage({
// 用户基础信息
uid: '',
avatarUrl: '',
+ defaultAvatarUrl: '',
nicheng: '',
// 商家核心数据
@@ -61,12 +66,28 @@ Page(createPage({
jinridingdan: 0,
jinrituikuan: 0,
chenghaoList: [],
+ identityTagList: [],
// 交互控制
inviteCode: '',
pendingCount: 0,
punishPending: 0,
- scrollRefreshing: false,
+ 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,
},
@@ -79,10 +100,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) {
@@ -112,102 +135,108 @@ Page(createPage({
}
this.checkColdStartPopup('shangjiaduan');
+ this.loadMerchantDataIfNeeded(true);
},
async onShow() {
this.registerNotificationComponent();
+ if (!this._ossImagesReady && app.globalData.ossImageUrl) {
+ this.setupImageUrls();
+ this._ossImagesReady = true;
+ }
+ this.syncRoleStatusFromStorage();
+ syncStaffUi(this);
+
+ if (this._showRefreshTimer) clearTimeout(this._showRefreshTimer);
+ this._showRefreshTimer = setTimeout(() => {
+ if (this.data.isShangjia || isMerchantPortalUser()) {
+ if (!isStaffMode()) {
+ this.loadDashboardStats();
+ }
+ }
+ this.loadMerchantDataIfNeeded();
+ }, 200);
+ },
+
+ syncRoleStatusFromStorage() {
+ try {
+ const uid = wx.getStorageSync('uid');
+ const portal = isMerchantPortalUser();
+ const staffFlag = Number(wx.getStorageSync('staffstatus')) === 1;
+ if (portal || staffFlag) {
+ this.setData({ isShangjia: true, uid: uid || '', staffBooting: false, isLoading: false });
+ } else if (!this.data.isShangjia) {
+ 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');
- const isOwner = Number(wx.getStorageSync('shangjiastatus')) === 1;
- if (token && !isOwner) {
+ if (token && Number(wx.getStorageSync('shangjiastatus')) !== 1 && !isStaffMode()) {
await restoreStaffContextAfterAuth();
+ } else if (isStaffMode()) {
+ await refreshStaffContext(request);
}
- this.checkRoleStatus();
+ this.syncRoleStatusFromStorage();
syncStaffUi(this);
- if (this.data.isShangjia) {
+ if (this.data.isShangjia || isMerchantPortalUser()) {
ensureRoleOnCenterPage(this, 'shangjia');
- this.applyCachedShangjiaFromGlobal();
+ if (isStaffMode()) {
+ await this.loadStaffProfile();
+ } else {
+ await this.getShangjiaInfo();
+ }
+ this.loadPendingCount();
+ if (!isStaffMode()) {
+ this.loadPunishPending();
+ }
+ this.loadIdentityTags();
+ this._merchantDataLoaded = true;
}
} catch (err) {
- console.error('商家个人中心 onShow', err);
+ console.error('商家个人中心加载', err);
this.setData({ isLoading: false, staffBooting: false });
}
},
- applyCachedShangjiaFromGlobal() {
- const cached = app.globalData.shangjia || {};
- const ctx = getStaffContext();
- if (isStaffMode() && ctx) {
- syncStaffUi(this);
- return;
- }
- if (!cached.nicheng && !cached.sjyue) return;
- this.setData({
- nicheng: cached.nicheng || this.data.nicheng || '',
- sjyue: cached.sjyue || this.data.sjyue || '0.00',
- fabu: cached.fadanzong ?? this.data.fabu ?? 0,
- tuikuan: cached.tuikuanzong ?? this.data.tuikuan ?? 0,
- jinriliushui: cached.riliushui || this.data.jinriliushui || '0.00',
- jinyueliushui: cached.yueliushui || this.data.jinyueliushui || '0.00',
- jinridingdan: cached.jinripaidan ?? this.data.jinridingdan ?? 0,
- jinrituikuan: cached.jinrituikuan ?? this.data.jinrituikuan ?? 0,
- chenghaoList: cached.chenghao_list || this.data.chenghaoList || [],
- });
- },
-
- async onPullDownRefresh() {
- if (this._pullRefreshing) return;
- this._pullRefreshing = true;
- this.setData({ scrollRefreshing: true });
- try {
- if (isStaffMode()) {
- await refreshStaffContext(request);
- await this.loadStaffProfile();
- } else {
- await this.getShangjiaInfo();
- await Promise.allSettled([this.loadPendingCount(), this.loadPunishPending()]);
- }
- syncStaffUi(this);
- wx.showToast({ title: '已更新', icon: 'success', duration: 1200 });
- } catch (e) {
- wx.showToast({ title: '刷新失败', icon: 'none' });
- } finally {
- this._pullRefreshing = false;
- this.setData({ scrollRefreshing: 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',
- })
+ }),
});
},
- // 商家状态检查(子客服与老板均可进入;子客服绝不走商家注册接口)
+ // 商家状态检查(首次进入拉数据;onShow 不重复请求)
checkRoleStatus() {
try {
const uid = wx.getStorageSync('uid');
@@ -217,14 +246,6 @@ Page(createPage({
if (portal) {
this.setData({ isShangjia: true, uid: uid || '', staffBooting: false, isLoading: false });
syncStaffUi(this);
- if (isStaffMode()) {
- this.loadStaffProfile();
- } else if (Number(wx.getStorageSync('shangjiastatus')) === 1) {
- this.loadAvatar();
- this.getShangjiaInfo();
- } else if (staffFlag) {
- this.bootStaffPortal(uid);
- }
ensureRoleOnCenterPage(this, 'shangjia');
return;
}
@@ -303,7 +324,7 @@ Page(createPage({
if (isStaffMode() || Number(wx.getStorageSync('staffstatus')) === 1) {
return this.loadStaffProfile();
}
- return this.loadData({
+ await this.loadData({
url: '/yonghu/shangjiaxinxi',
method: 'POST',
successCode: 200,
@@ -318,8 +339,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,
@@ -327,6 +348,7 @@ Page(createPage({
chenghaoList: chenghaoList,
isLoading: false,
});
+ this.loadAvatar();
if (this.data.isAutoRegistering) {
this.setData({ isAutoRegistering: false });
@@ -341,37 +363,56 @@ Page(createPage({
this.throttledRefresh(() => this.loadStaffProfile());
return;
}
- this.throttledRefresh(() => this.getShangjiaInfo());
+ this.throttledRefresh(() => {
+ this.getShangjiaInfo();
+ this.loadPendingCount();
+ this.loadPunishPending();
+ this.loadIdentityTags();
+ });
},
- async loadPendingCount() {
+ async onPullDownRefresh() {
try {
- const res = await request({
- url: isStaffMode() ? STAFF_API.orderList : '/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) {
- /* 接口字段未定时静默 */
+ /* 静默 */
}
},
@@ -411,9 +452,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' });
},
@@ -433,7 +509,8 @@ Page(createPage({
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' }); },
+ goToDataStats() { wx.navigateTo({ url: '/pages/merchant-data-stats/merchant-data-stats' }); },
}, {
roleConfig: {
role: 'shangjia',
diff --git a/pages/merchant/merchant.json b/pages/merchant/merchant.json
index ab56ffb..b207753 100644
--- a/pages/merchant/merchant.json
+++ b/pages/merchant/merchant.json
@@ -6,7 +6,7 @@
"chenghao-tag": "/components/chenghao-tag/chenghao-tag"
},
"navigationStyle": "custom",
- "backgroundColor": "#f5f3ff",
+ "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 80823a6..0d35507 100644
--- a/pages/merchant/merchant.wxml
+++ b/pages/merchant/merchant.wxml
@@ -40,32 +40,30 @@
-
+
-
+
-
+
{{nicheng || '商家'}}
- {{isStaffMode ? (staffRoleName || '商家客服') : '商家'}}
+ {{staffRoleName || '商家客服'}}
+ 商家
+
+ 修改昵称
+
+
+
+
ID: {{uid || '--'}}
@@ -73,9 +71,12 @@
+
-
+
@@ -136,20 +137,28 @@
交易与发单
+
+
+ 常规派单
+
- 自定义单
+ 自定义派单
-
-
- 常规单
+
+
+ 链接派单
+
+
+
+ 经营数据
客服邀请码
-
+
客服列表
diff --git a/pages/merchant/merchant.wxss b/pages/merchant/merchant.wxss
index 3a0c632..dd5b294 100644
--- a/pages/merchant/merchant.wxss
+++ b/pages/merchant/merchant.wxss
@@ -1,7 +1,7 @@
@import '../../styles/shangjia-xym-common.wxss';
page {
- background: #f5f3ff;
+ background: #fff8e1;
}
.user-page {
@@ -15,6 +15,18 @@ page {
display: flex;
align-items: center;
justify-content: center;
+ position: relative;
+}
+
+.sj-nav-bar {
+ justify-content: center;
+}
+
+.nav-refresh-ico {
+ position: absolute;
+ right: 24rpx;
+ width: 44rpx;
+ height: 44rpx;
}
.content {
@@ -42,10 +54,39 @@ page {
height: 32rpx;
}
+.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;
+}
+
.user-info {
padding: 10rpx 30rpx;
}
+.user-info > .flex {
+ align-items: flex-start;
+ width: 100%;
+}
+
+.user-info > .flex > .avatar {
+ flex-shrink: 0;
+}
+
+.user-info > .flex > view:not(.avatar) {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+}
+
.avatar {
width: 110rpx;
height: 110rpx;
@@ -64,7 +105,25 @@ page {
.nickname-row {
flex-wrap: wrap;
align-items: center;
- gap: 8rpx;
+ gap: 6rpx;
+ max-width: 100%;
+}
+
+.sj-identity-tag {
+ flex-shrink: 0;
+}
+
+.nickname-edit-btn {
+ display: inline-flex;
+ margin-top: 10rpx;
+ padding: 8rpx 22rpx;
+ font-size: 24rpx;
+ font-weight: 600;
+ color: #7a5a12;
+ background: linear-gradient(180deg, #fff8e1, #ffe9b8);
+ border: 1rpx solid #e8c547;
+ border-radius: 28rpx;
+ box-shadow: 0 2rpx 8rpx rgba(200, 160, 40, 0.15);
}
.sn-row {
@@ -85,7 +144,7 @@ page {
}
.badge-zone {
- padding: 0 24rpx 8rpx;
+ padding: 0 24rpx 4rpx;
}
.badge-scroll {
@@ -95,9 +154,21 @@ page {
.badge-tag-wrap {
display: inline-block;
- transform: scale(0.72);
+ transform: scale(0.65);
transform-origin: left center;
- margin-right: -8rpx;
+ margin-right: -12rpx;
+}
+
+.identity-tags-row {
+ flex-wrap: wrap;
+ gap: 2rpx;
+ margin-top: 6rpx;
+ max-width: 100%;
+}
+
+.identity-tags-row .badge-tag-wrap {
+ transform: scale(0.62);
+ margin-right: -14rpx;
}
.wallet-btns .sj-btn-outline {
@@ -108,7 +179,7 @@ page {
margin: 16rpx 30rpx 0;
padding: 20rpx 10rpx;
border-radius: 15rpx;
- background: #ede9fe;
+ background: #fef6d4;
}
.freeze-col {
@@ -230,7 +301,7 @@ page {
width: 60rpx;
height: 60rpx;
border: 4rpx solid rgba(0, 0, 0, 0.08);
- border-top-color: #9333ea;
+ border-top-color: #ffd061;
border-radius: 50%;
animation: sjSpin 0.8s linear infinite;
}
diff --git a/pages/messages/messages.js b/pages/messages/messages.js
index 0bac1cb..5adef98 100644
--- a/pages/messages/messages.js
+++ b/pages/messages/messages.js
@@ -2,10 +2,12 @@
const app = getApp();
import { formatDate } from '../../static/lib/utils';
import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage } from '../../utils/avatar.js';
-import { getLocalImUserId } from '../../utils/im-user.js';
-import { normalizeConversationsList } from '../../utils/conversation-display.js';
-import { reconnectForRole } from '../../utils/role-tab-bar.js';
+import { getLocalImUserId, getLocalImIdentity, getImUserIdForRole, loadGroupMetaCache, getDefaultAvatar } from '../../utils/im-user.js';
+import { enrichGroupConversation, isOrderGroupConversation, sortConversations, recordConversationOpen, getZhuangtaiText } from '../../utils/group-chat.js';
+import request from '../../utils/request';
+import { openCustomerServiceChat } from '../../utils/kefu-nav.js';
import { getPrimaryRole } from '../../utils/primary-role.js';
+import { isStaffMode } from '../../utils/staff-api.js';
import { createPage } from '../../utils/base-page.js';
const { jianquanxian } = require('../../utils/imAuth/jianquanxian');
@@ -20,51 +22,186 @@ Page(createPage({
actionPopup: { visible: false, conversation: null },
currentUser: null,
notificationMuted: false,
- scrollHeight: 0
+ scrollHeight: 0,
+ imStatus: 'connecting',
+ imStatusText: '',
+ defaultAvatarUrl: '',
},
_permissionSeq: 0,
_peerProfileCache: {},
+ _lastConvSignature: '',
+ _lastRefreshTs: 0,
+ _showRefreshTimer: null,
+ _statusRefreshTimer: null,
+ _chatAllowed: true,
onLoad() {
this.calculateScrollHeight();
+ this.setData({ defaultAvatarUrl: getDefaultAvatarUrl(app) });
const muted = wx.getStorageSync('notificationMuted') || false;
this.setData({ notificationMuted: muted });
+ if (app.globalData.messageManager) {
+ app.globalData.messageManager.notificationMuted = muted;
+ }
+ loadGroupMetaCache(app);
+ this._onGlobalConvUpdated = (content) => {
+ if (content && content.conversations) {
+ this.renderConversations(content);
+ } else if (app.loadConversations) {
+ app.loadConversations();
+ }
+ };
+ this._onUnreadChanged = (data) => {
+ const unreadTotal = data?.unreadTotal ?? app.globalData.messageManager?.unreadTotal ?? 0;
+ if (app.globalData.messageManager) {
+ app.globalData.messageManager.unreadTotal = unreadTotal;
+ }
+ if (app.emitEvent) {
+ app.emitEvent('tabBarBadgeChanged', {
+ badgeText: unreadTotal > 0 ? String(unreadTotal) : '',
+ });
+ }
+ };
+ this._onConnectionChanged = (data) => {
+ const status = data?.status || 'disconnected';
+ const textMap = {
+ connected: '',
+ connecting: '正在连接消息服务…',
+ reconnecting: '正在重新连接…',
+ disconnected: '消息未连接,点击重试',
+ disabled: '消息服务未配置',
+ };
+ this.setData({
+ imStatus: status,
+ imStatusText: textMap[status] || (status === 'connected' ? '' : '消息未连接,点击重试'),
+ });
+ if (status === 'connected') {
+ this.setupConversationListener();
+ this.loadConversations();
+ }
+ };
+ app.on('conversationsUpdated', this._onGlobalConvUpdated);
+ app.on('unreadCountChanged', this._onUnreadChanged);
+ app.on('connectionChanged', this._onConnectionChanged);
},
- onShow() {
+ onUnload() {
+ if (this._onGlobalConvUpdated) {
+ app.off('conversationsUpdated', this._onGlobalConvUpdated);
+ }
+ if (this._onUnreadChanged) {
+ app.off('unreadCountChanged', this._onUnreadChanged);
+ }
+ if (this._onConnectionChanged) {
+ app.off('connectionChanged', this._onConnectionChanged);
+ }
+ if (this.conversationsUpdatedListener && wx.goEasy?.im) {
+ wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.conversationsUpdatedListener);
+ this.conversationsUpdatedListener = null;
+ }
+ },
+
+ async onShow() {
if (!this.checkLoginStatus()) return;
+ this.setData({ defaultAvatarUrl: getDefaultAvatarUrl(app) });
+ loadGroupMetaCache(app);
+ if (app.restoreTabBarBadge) app.restoreTabBarBadge();
this.registerNotificationComponent();
- this.checkPermissionAndAutoConnect();
+ if (app.globalData.messageManager?.unreadTotal != null && app.emitEvent) {
+ app.emitEvent('tabBarBadgeChanged', {
+ badgeText: app.globalData.messageManager.unreadTotal > 0
+ ? String(app.globalData.messageManager.unreadTotal) : '',
+ });
+ }
+ this.patchLocalReadState();
+ await this.checkPermissionAndAutoConnect();
+ if (this._chatAllowed) {
+ if (app.ensureConnection) app.ensureConnection();
+ this.setupConversationListener();
+ if (app.syncConnectionStatus) app.syncConnectionStatus();
+ this.scheduleSoftRefresh();
+ }
+ },
+
+ scheduleSoftRefresh() {
+ if (this._showRefreshTimer) clearTimeout(this._showRefreshTimer);
+ if (this._statusRefreshTimer) clearTimeout(this._statusRefreshTimer);
+ this._showRefreshTimer = setTimeout(() => {
+ this._showRefreshTimer = null;
+ const now = Date.now();
+ if (now - this._lastRefreshTs < 1800 && this.data.allConversations.length) {
+ return;
+ }
+ this._lastRefreshTs = now;
+ if (app.loadConversations) app.loadConversations();
+ else if (wx.goEasy?.im) this.loadConversations();
+ }, 350);
+ },
+
+ patchLocalReadState() {
+ const openId = app.globalData.pageState?.lastOpenedConvId;
+ if (!openId || !this.data.allConversations.length) return;
+
+ const list = this.data.allConversations.map((c) => {
+ const id = c.groupId || c.userId;
+ if (id === openId && (c.unread || 0) > 0) {
+ return { ...c, unread: 0 };
+ }
+ return c;
+ });
+
+ const openTimes = wx.getStorageSync('conversationOpenTimes') || {};
+ sortConversations(list, openTimes);
+ this.setData({ allConversations: list }, () => this.applyFilter());
+ },
+
+ retryImConnection() {
+ if (!app.globalData.chatEnabled) {
+ wx.showToast({ title: '消息服务未就绪', icon: 'none' });
+ return;
+ }
+ this.setData({ imStatus: 'connecting', imStatusText: '正在连接消息服务…' });
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.globalData.goEasyConnection.reconnectAttempts = 0;
+ if (app.ensureConnection) app.ensureConnection();
+ setTimeout(() => {
+ if (app.syncConnectionStatus) app.syncConnectionStatus();
+ if (app.loadConversations) app.loadConversations();
+ }, 2000);
},
onHide() {},
- onUnload() {},
-
// ========== ==== ================ ==== ================ 鉴权检查 ==========
async checkPermissionAndAutoConnect() {
const seq = ++this._permissionSeq;
let quanxian;
try {
- quanxian = await jianquanxian(app);
+ quanxian = await jianquanxian(app, { silent: true });
} catch (e) {
+ this._chatAllowed = true;
return;
}
if (seq !== this._permissionSeq) return;
if (!quanxian.allowed) {
+ this._chatAllowed = false;
const currentRole = app.globalData.currentRole || 'normal';
- let content = '您没有权限使用消息功能';
- if (currentRole === 'dashou') content = '您需要先充值会员才能使用消息功能';
- wx.showModal({
- title: '权限不足',
- content,
- showCancel: false,
- confirmText: '我知道了'
- });
+ let hint = '消息连接暂不可用,列表可正常浏览';
+ if (currentRole === 'dashou') {
+ hint = '开通会员后可收发消息(列表可正常浏览)';
+ }
+ const prev = this.data.imStatusText;
+ if (prev !== hint) {
+ this.setData({ imStatusText: hint });
+ }
return;
}
+ this._chatAllowed = true;
+ if (this.data.imStatusText && this.data.imStatusText.includes('会员')) {
+ this.setData({ imStatusText: '' });
+ }
this.autoConnect();
},
@@ -90,26 +227,40 @@ Page(createPage({
},
autoConnect() {
- const targetUserId = getLocalImUserId(app);
+ const role = isStaffMode() ? 'shangjia' : (getLocalImIdentity(app) || app.globalData.currentRole || 'normal');
+ const uid = wx.getStorageSync('uid');
+ const targetUserId = getImUserIdForRole(role, uid);
if (!targetUserId) return;
- if (app.ensureConnection) app.ensureConnection();
- reconnectForRole(getPrimaryRole(app));
+ const onReady = () => {
+ this.setupConversationListener();
+ if (app.loadConversations) app.loadConversations();
+ else this.loadConversations();
+ };
- const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
- if (status === 'connected' || status === 'reconnected') {
- const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
- if (currentUserId === targetUserId) {
- this.setupConversationListener();
- this.loadConversations();
- return;
- }
- try {
- wx.goEasy.disconnect();
- } catch (e) {}
+ const status = wx.goEasy?.getConnectionStatus?.() || 'disconnected';
+ const currentUserId = wx.goEasy?.im?.userId;
+ if ((status === 'connected' || status === 'reconnected') && currentUserId === targetUserId) {
+ onReady();
+ return;
}
- this.connectGoEasy(targetUserId);
+ const tryConnect = async () => {
+ try {
+ if (app.ensureImForRole) {
+ await app.ensureImForRole(role);
+ } else if (app.connectWithIdentity) {
+ await app.connectWithIdentity(role, targetUserId, true);
+ } else if (app.ensureConnection) {
+ app.ensureConnection();
+ }
+ onReady();
+ } catch (e) {
+ const s = wx.goEasy?.getConnectionStatus?.();
+ if (s === 'connected' || s === 'reconnected') onReady();
+ }
+ };
+ tryConnect();
},
connectGoEasy(userId) {
@@ -173,13 +324,44 @@ Page(createPage({
// 会话渲染与排序
renderConversations(content) {
- const conversations = (content && content.conversations) ? content.conversations : [];
- if (!conversations.length) {
+ if (!content || !content.conversations) {
this.setData({ allConversations: [] }, () => this.applyFilter());
return;
}
- let list = normalizeConversationsList(conversations, app, this._peerProfileCache);
- list.forEach(item => {
+ let list = content.conversations;
+ const defaultAvatar = getDefaultAvatar(app);
+ const myGoEasyId = wx.goEasy?.im?.userId || getLocalImUserId(app);
+ const ossBase = app.globalData.ossImageUrl || '';
+ const groupMeta = app.globalData.groupInfoMap || {};
+
+ list.forEach((item, idx) => {
+ item.key = item.groupId || item.userId || item.teamId || `${item.type || 'c'}_${idx}`;
+ if (item.type === 'group') {
+ if (!item.data) item.data = {};
+ if (!item.data.orderId && item.groupId) {
+ const m = /^group_(.+)$/.exec(String(item.groupId));
+ if (m) item.data.orderId = m[1];
+ }
+ const meta = groupMeta[item.groupId];
+ if (meta) {
+ if (!item.data) item.data = {};
+ Object.assign(item.data, meta);
+ }
+ if (item.data.orderJieshao && !item.data.orderDesc) {
+ item.data.orderDesc = item.data.orderJieshao;
+ }
+ if (item.data && item.data.dashouGoEasyId) {
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ app.globalData.groupInfoMap[item.groupId] = {
+ ...app.globalData.groupInfoMap[item.groupId],
+ ...item.data,
+ };
+ }
+ enrichGroupConversation(item, myGoEasyId, defaultAvatar, ossBase);
+ } else {
+ if (!item.data) item.data = {};
+ item.data.avatar = resolveAvatarUrl(item.data.avatar, app) || defaultAvatar;
+ }
if (!item.lastMessage) {
item.lastMessage = { type: 'text', payload: { text: '' }, timestamp: 0 };
}
@@ -188,31 +370,111 @@ Page(createPage({
}
});
- list.sort((a, b) => {
- if (a.top && !b.top) return -1;
- if (!a.top && b.top) return 1;
- if (a.unread > 0 && b.unread <= 0) return -1;
- if (a.unread <= 0 && b.unread > 0) return 1;
- const ta = (a.lastMessage && a.lastMessage.timestamp) || 0;
- const tb = (b.lastMessage && b.lastMessage.timestamp) || 0;
- return tb - ta;
- });
-
- this.setData({ allConversations: list, displayCount: 10 }, () => {
- this.applyFilter();
- });
+ const openTimes = wx.getStorageSync('conversationOpenTimes') || {};
+ sortConversations(list, openTimes);
const unreadTotal = content.unreadTotal !== undefined
? content.unreadTotal
: list.reduce((sum, c) => sum + (c.unread || 0), 0);
+
+ const signature = list.map((c) => {
+ const id = c.groupId || c.userId || c.teamId || '';
+ const unread = c.unread || 0;
+ const ts = c.lastMessage?.timestamp || 0;
+ const preview = c.displayLastMsg || c.lastMessage?.payload?.text || '';
+ return `${id}:${unread}:${ts}:${preview.slice(0, 20)}`;
+ }).join('|');
+
+ if (signature === this._lastConvSignature && this.data.allConversations.length) {
+ if (app.globalData.messageManager) {
+ app.globalData.messageManager.unreadTotal = unreadTotal;
+ }
+ if (app.updateUnreadCount) {
+ app.updateUnreadCount(unreadTotal);
+ } else if (app.emitEvent) {
+ app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
+ }
+ this.applyFilter();
+ return;
+ }
+ this._lastConvSignature = signature;
+
+ if (app.globalData.messageManager) {
+ app.globalData.messageManager.unreadTotal = unreadTotal;
+ }
if (app.updateUnreadCount) {
app.updateUnreadCount(unreadTotal);
} else if (app.emitEvent) {
app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
}
- // 重新订阅群组
+ const prevDisplay = this.data.displayCount;
+ this.setData({
+ allConversations: list,
+ displayCount: prevDisplay > 10 ? prevDisplay : 10,
+ }, () => {
+ this.applyFilter();
+ });
+
this.subscribeGroupsIfNeeded(list);
+ this.scheduleOrderStatusRefresh(list);
+ },
+
+ scheduleOrderStatusRefresh(conversations) {
+ if (this._statusRefreshTimer) clearTimeout(this._statusRefreshTimer);
+ this._statusRefreshTimer = setTimeout(() => {
+ this._statusRefreshTimer = null;
+ this.refreshOrderStatuses(conversations);
+ }, 400);
+ },
+
+ async refreshOrderStatuses(conversations) {
+ const orderIds = [];
+ (conversations || this.data.allConversations).forEach((c) => {
+ if (!isOrderGroupConversation(c)) return;
+ const oid = c.data?.orderId;
+ if (oid && !orderIds.includes(oid)) orderIds.push(oid);
+ });
+ if (!orderIds.length) return;
+
+ try {
+ const res = await request({
+ url: '/dingdan/ltddztpl',
+ method: 'POST',
+ data: { order_ids: orderIds.slice(0, 20) },
+ });
+ const body = res?.data || {};
+ const map = body.data || {};
+ if (!Object.keys(map).length) return;
+
+ let changed = false;
+ const list = this.data.allConversations.map((c) => {
+ const oid = c.data?.orderId;
+ if (!oid || !map[oid]) return c;
+ const st = map[oid];
+ changed = true;
+ const data = {
+ ...c.data,
+ orderId: oid,
+ orderDesc: st.jieshao || c.data.orderDesc,
+ orderJine: st.jine != null ? st.jine : c.data.orderJine,
+ orderZhuangtai: st.zhuangtai,
+ orderZhuangtaiText: getZhuangtaiText(st.zhuangtai),
+ };
+ if (c.groupId && app.globalData.groupInfoMap) {
+ app.globalData.groupInfoMap[c.groupId] = {
+ ...(app.globalData.groupInfoMap[c.groupId] || {}),
+ ...data,
+ };
+ }
+ return { ...c, data };
+ });
+ if (changed) {
+ this.setData({ allConversations: list }, () => this.applyFilter());
+ }
+ } catch (e) {
+ console.warn('刷新订单状态失败', e);
+ }
},
/**
@@ -244,7 +506,7 @@ Page(createPage({
const { allConversations, activeTab, searchKeyword } = this.data;
let filtered = [];
if (activeTab === 0) {
- filtered = allConversations.filter(c => c.type === 'group' && c.data && c.data.orderId);
+ filtered = allConversations.filter(c => isOrderGroupConversation(c));
} else if (activeTab === 1) {
filtered = allConversations.filter(c => c.type === 'private');
} else if (activeTab === 2) {
@@ -263,7 +525,7 @@ Page(createPage({
const tabUnread = [0, 0, 0];
allConversations.forEach(c => {
- if (c.type === 'group' && c.data && c.data.orderId) tabUnread[0] += c.unread || 0;
+ if (isOrderGroupConversation(c)) tabUnread[0] += c.unread || 0;
else if (c.type === 'private') tabUnread[1] += c.unread || 0;
else if (c.type === 'cs') tabUnread[2] += c.unread || 0;
});
@@ -273,7 +535,10 @@ Page(createPage({
switchTab(e) {
const index = parseInt(e.currentTarget.dataset.index);
- this.setData({ activeTab: index, displayCount: 10, searchKeyword: '' }, () => this.applyFilter());
+ this.setData({ activeTab: index, displayCount: 10, searchKeyword: '' }, () => {
+ this.applyFilter();
+ this.calculateScrollHeight();
+ });
},
onSearchInput(e) {
@@ -294,6 +559,16 @@ Page(createPage({
chat(e) {
const conversation = e.currentTarget.dataset.conversation;
if (!conversation) return;
+ if (this._chatAllowed === false) {
+ wx.showToast({ title: '请先开通会员后再聊天', icon: 'none' });
+ return;
+ }
+ recordConversationOpen(conversation);
+ const convId = conversation.groupId || conversation.userId;
+ if (convId) {
+ if (!app.globalData.pageState) app.globalData.pageState = {};
+ app.globalData.pageState.lastOpenedConvId = convId;
+ }
if (conversation.type === 'private') {
const param = {
@@ -302,13 +577,23 @@ Page(createPage({
toAvatar: resolveAvatarUrl(conversation.data.avatar, app),
};
wx.navigateTo({ url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)) });
- } else if (conversation.type === 'group') {
+ } else if (conversation.type === 'group' || (conversation.groupId && isOrderGroupConversation(conversation))) {
+ const d = conversation.data || {};
+ const rawGid = conversation.groupId || '';
+ const oid = String(d.orderId || rawGid).replace(/^group_/, '');
+ const groupId = rawGid.startsWith('group_') ? rawGid : (oid ? `group_${oid}` : rawGid);
const param = {
- groupId: conversation.groupId,
- orderId: conversation.data.orderId || '',
- groupName: conversation.data.name,
- groupAvatar: conversation.data.avatar,
- isCross: conversation.data.isCross || 0
+ groupId,
+ orderId: oid,
+ groupName: d.name || '订单群聊',
+ groupAvatar: d.avatar,
+ isCross: d.isCross || 0,
+ orderZhuangtai: d.orderZhuangtai,
+ orderJine: d.orderJine,
+ orderDesc: d.orderDesc || d.orderJieshao || '',
+ currentUserId: wx.goEasy?.im?.userId || getLocalImUserId(app),
+ currentUserName: this.data.currentUser?.name || '',
+ currentUserAvatar: this.data.currentUser?.avatar || '',
};
wx.navigateTo({ url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
} else if (conversation.type === 'cs') {
@@ -318,8 +603,7 @@ Page(createPage({
},
chatKefu() {
- const param = { teamId: 'support_team' };
- wx.navigateTo({ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
+ openCustomerServiceChat();
},
showAction(e) {
@@ -381,8 +665,9 @@ Page(createPage({
const rpxRatio = 750 / windowWidth;
const headerHeight = 150 / rpxRatio;
const tabBarHeight = 130 / rpxRatio;
+ const kefuBarHeight = this.data.activeTab === 2 ? (112 / rpxRatio) : 0;
const safeAreaBottom = systemInfo.safeArea ? (windowHeight - systemInfo.safeArea.bottom) : 0;
- this.setData({ scrollHeight: windowHeight - headerHeight - tabBarHeight - safeAreaBottom });
+ this.setData({ scrollHeight: windowHeight - headerHeight - tabBarHeight - kefuBarHeight - safeAreaBottom });
},
onAvatarError(e) {
diff --git a/pages/messages/messages.json b/pages/messages/messages.json
index 0dbdec6..ba43917 100644
--- a/pages/messages/messages.json
+++ b/pages/messages/messages.json
@@ -1,4 +1,5 @@
{
+ "navigationBarTitleText": "星之界",
"usingComponents": {
"global-notification": "/components/global-notification/global-notification",
"tab-bar": "/tab-bar/index"
diff --git a/pages/messages/messages.wxml b/pages/messages/messages.wxml
index 1b0373b..470aad3 100644
--- a/pages/messages/messages.wxml
+++ b/pages/messages/messages.wxml
@@ -10,51 +10,72 @@
+
+ ⚠
+ {{imStatusText}},点击重连
+
+
订单消息
- {{tabUnread[0]}}
+ {{tabUnread[0]}}
用户消息
- {{tabUnread[1]}}
+ {{tabUnread[1]}}
客服消息
- {{tabUnread[2]}}
+ {{tabUnread[2]}}
+
+
+
+
-
-
+
+
- {{item.data.name}}
+
+ {{item.data.name || '用户'}}
+ ID {{item.data.counterpartYonghuid}}
+
{{item.lastMessage.date}}
-
+
+
+ {{item.displayLastMsg || item.lastMessage.payload.text}}
+ {{item.unread > 99 ? '99+' : item.unread}}
+
+
+
+ 单号
+ {{item.data.orderId}}
+ {{item.data.orderZhuangtaiText}}
+
+ {{item.data.orderDesc}}
+
+
+
{{item.lastMessage.type === 'text' ? item.lastMessage.payload.text : (item.lastMessage.type === 'image' ? '[图片]' : '[其他消息]')}}
{{item.unread > 99 ? '99+' : item.unread}}
-
-
-
-
-
+
上拉加载更多
暂无相关消息
-
{{actionPopup.conversation.top ? '取消置顶' : '置顶聊天'}}
@@ -63,7 +84,6 @@
-
-
\ No newline at end of file
+
diff --git a/pages/messages/messages.wxss b/pages/messages/messages.wxss
index 99eb09f..e74ba33 100644
--- a/pages/messages/messages.wxss
+++ b/pages/messages/messages.wxss
@@ -11,6 +11,31 @@
align-items: center;
padding: 20rpx 24rpx;
background: #fff;
+ border-bottom: 1rpx solid #e8e8e8;
+}
+
+.im-status-bar {
+ display: flex;
+ align-items: center;
+ padding: 16rpx 24rpx;
+ background: #fff1f0;
+ border-bottom: 1rpx solid #ffccc7;
+}
+
+.im-status-bar--warn {
+ background: linear-gradient(90deg, #fff7e6 0%, #fff1f0 100%);
+}
+
+.im-status-icon {
+ font-size: 28rpx;
+ margin-right: 12rpx;
+ color: #fa541c;
+}
+
+.im-status-text {
+ font-size: 26rpx;
+ color: #cf1322;
+ font-weight: 500;
}
.search-bar {
@@ -105,12 +130,61 @@
.conversation-item {
display: flex;
- align-items: center;
+ align-items: flex-start;
padding: 24rpx;
border-bottom: 1rpx solid #f0f0f0;
transition: background 0.15s;
}
+.order-group-item {
+ padding: 22rpx 24rpx;
+}
+
+.order-compact {
+ margin-top: 8rpx;
+ padding-top: 8rpx;
+ border-top: 1rpx solid #f3f3f3;
+}
+
+.order-compact-row {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 8rpx;
+ margin-bottom: 4rpx;
+}
+
+.order-id-tag {
+ font-size: 20rpx;
+ color: #999;
+ background: #f0f0f0;
+ padding: 2rpx 10rpx;
+ border-radius: 6rpx;
+}
+
+.order-id-text {
+ font-size: 22rpx;
+ color: #576b95;
+}
+
+.order-status-inline {
+ font-size: 20rpx;
+ color: #07c160;
+ background: #e8f8ef;
+ padding: 2rpx 10rpx;
+ border-radius: 6rpx;
+}
+
+.order-desc-compact {
+ display: block;
+ font-size: 24rpx;
+ color: #888;
+ line-height: 1.4;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
.conversation-item:active {
background: #f5f5f5;
}
@@ -128,6 +202,56 @@
flex-shrink: 0;
}
+.avatar-round {
+ border-radius: 50%;
+}
+
+.user-meta-row {
+ margin-bottom: 4rpx;
+}
+
+.user-meta {
+ font-size: 24rpx;
+ color: #333;
+}
+
+.user-meta.sub {
+ color: #666;
+ font-size: 22rpx;
+}
+
+.order-block {
+ background: #f7f8fa;
+ border-radius: 12rpx;
+ padding: 16rpx 18rpx;
+ margin-bottom: 10rpx;
+}
+
+.order-id {
+ display: block;
+ font-size: 24rpx;
+ color: #576b95;
+ margin-bottom: 6rpx;
+}
+
+.order-desc {
+ display: block;
+ font-size: 26rpx;
+ color: #333;
+ line-height: 1.5;
+ word-break: break-all;
+}
+
+.order-status {
+ display: inline-block;
+ font-size: 22rpx;
+ color: #07c160;
+ margin-top: 8rpx;
+ padding: 2rpx 12rpx;
+ background: #e8f8ef;
+ border-radius: 8rpx;
+}
+
.info {
flex: 1;
min-width: 0;
@@ -140,11 +264,23 @@
margin-bottom: 8rpx;
}
+.name-col {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.uid-tag {
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 2rpx;
+}
+
.name {
font-size: 30rpx;
color: #1a1a1a;
font-weight: 500;
- flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -201,16 +337,25 @@
/* 客服入口 */
.kefu-entry {
- text-align: center;
- padding: 100rpx 0;
+ padding: 16rpx 24rpx 8rpx;
+ background: #fff;
}
.kefu-btn {
- width: 300rpx;
- background: #07c160;
+ width: 100%;
+ height: 88rpx;
+ line-height: 88rpx;
+ background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
color: #fff;
- border-radius: 40rpx;
- font-size: 28rpx;
+ border-radius: 44rpx;
+ font-size: 32rpx;
+ font-weight: 700;
+ box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.35);
+ border: none;
+}
+
+.kefu-btn::after {
+ border: none;
}
/* 操作弹窗 */
diff --git a/pages/mine/mine.js b/pages/mine/mine.js
index 9c4da41..8365416 100644
--- a/pages/mine/mine.js
+++ b/pages/mine/mine.js
@@ -12,6 +12,15 @@ import { enterLockedRole } from '../../utils/primary-role.js';
import { isStaffMode, getStaffContext, restoreStaffContextAfterAuth } from '../../utils/staff-api.js';
import { createPage } from '../../utils/base-page.js';
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
+import {
+ ICON_KEYS,
+ resolveMiniappIcon,
+ getPindaoConfig,
+ resolvePindaoImages,
+ refreshPindaoConfig,
+ warmupPindaoConfig,
+ PINDAO_ICON_FALLBACK,
+} from '../../utils/miniapp-icons.js';
Page(createPage({
data: {
@@ -20,70 +29,62 @@ Page(createPage({
userUid: '',
showLoginBtn: false,
orderCounts: { daifuwu:0, fuwuzhong:0, yiwancheng:0, yituikuan:0 },
- // 图标
- settingIcon: '', daifuwuIcon: '', fuwuzhongIcon: '', yiwanchengIcon: '', yituikuanIcon: '',
+ settingIcon: '', refreshIcon: '',
+ daifuwuIcon: '', fuwuzhongIcon: '', yiwanchengIcon: '', yituikuanIcon: '',
dashouIcon: '', shangjiaIcon: '', guanshiIcon: '', kefuIcon: '',
- zuzhangIcon: '', guanzhualongIcon: '', arrowRightIcon: '', qingchuIcon: '',
+ zuzhangIcon: '', guanzhualongIcon: '', pindaoIcon: '', arrowRightIcon: '', qingchuIcon: '',
dashouCertified: false,
shangjiaCertified: false,
staffCertified: false,
staffTag: '入驻',
- bottomSafePadding: 0
+ bottomSafePadding: 0,
+ pindaoVisible: false,
+ pindaoTitle: '频道',
+ pindaoChannelNo: '',
+ pindaoImages: [],
+ showPindaoEntry: false,
+ _profileRefreshing: false,
},
onLoad() {
- this.initIconUrls()
- this.loadUserData()
- this.setBottomSafe()
+ this.initIconUrls();
+ this.loadUserData();
+ this.setBottomSafe();
+ this.updatePindaoEntry();
},
- async onShow() {
- const phoneOk = await ensurePhoneAuth({
+ onShow() {
+ ensurePhoneAuth({
redirect: true,
returnPage: '/pages/mine/mine',
- });
- if (!phoneOk) return;
-
- this.initIconUrls();
- this.registerNotificationComponent();
- this.checkAvatarPrompt();
- backfillUserProfileCache(app);
- if (getSessionToken(app)) {
- restoreStaffContextAfterAuth().finally(() => {
- this.loadUserData();
- this.updateOrderCounts();
- });
- } else {
+ }).then((phoneOk) => {
+ if (!phoneOk) return;
+ this.registerNotificationComponent();
this.loadUserData();
this.updateOrderCounts();
- }
+ this.updatePindaoEntry();
+ });
+ },
+
+ updatePindaoEntry() {
+ const dashou = isRoleStatusActive(wx.getStorageSync('dashoustatus'));
+ this.setData({ showPindaoEntry: dashou });
},
setBottomSafe() {
- const sys = wx.getSystemInfoSync()
- const safeBottom = sys.screenHeight - sys.safeArea.bottom // 底部安全区高度(px)
- const tabBarHeight = (sys.windowWidth / 750) * 100 // 100rpx 转为 px
+ const sys = wx.getSystemInfoSync();
+ const safeBottom = sys.screenHeight - sys.safeArea.bottom;
+ const tabBarHeight = (sys.windowWidth / 750) * 100;
this.setData({
- bottomSafePadding: safeBottom + tabBarHeight + 4 // 4px 微调,确保不留缝隙
- })
- },
-
- checkAvatarPrompt() {
- const ds = wx.getStorageSync('dashoustatus')
- const tx = wx.getStorageSync('touxiang') || ''
- if (ds === 1 && (!tx || tx === 'a_long/morentouxiang.jpg')) {
- wx.showModal({
- title: '提示', content: '请先设置头像',
- confirmText: '去设置', confirmColor: '#9333ea',
- success: r => r.confirm && wx.navigateTo({ url: '/pages/edit/edit' })
- })
- }
+ bottomSafePadding: safeBottom + tabBarHeight + 4,
+ });
},
initIconUrls() {
- const base = (app.globalData.ossImageUrl || '') + '/beijing/tubiao/'
+ const base = (app.globalData.ossImageUrl || '') + 'beijing/tubiao/';
this.setData({
settingIcon: base + 'grzx_shezhi.jpg',
+ refreshIcon: resolveMiniappIcon(app, ICON_KEYS.ICON_REFRESH, base + 'grzx_shezhi.jpg'),
daifuwuIcon: base + 'grzx_daifuwu.jpg',
fuwuzhongIcon: base + 'grzx_fuwuzhong.jpg',
yiwanchengIcon: base + 'grzx_yiwancheng.jpg',
@@ -94,10 +95,11 @@ Page(createPage({
kefuIcon: base + 'grzx_kefu.jpg',
zuzhangIcon: base + 'grzx_zuzhang.jpg',
guanzhualongIcon: base + 'grzx_guanzhualong.jpg',
+ pindaoIcon: resolveMiniappIcon(app, ICON_KEYS.MINE_PINDAO, base + 'grzx_pindao.jpg'),
arrowRightIcon: base + 'grzx_arrow_right.jpg',
qingchuIcon: base + 'grzx_qingchu.jpg',
kaoheguanIcon: base + 'kaoheguan.png',
- })
+ });
},
loadUserData() {
@@ -117,14 +119,61 @@ Page(createPage({
},
updateOrderCounts() {
- const c = app.globalData.dingdanTiaoshu || {}
+ const c = app.globalData.dingdanTiaoshu || {};
this.setData({ orderCounts: {
daifuwu: c.daifuwu||0, fuwuzhong: c.fuwuzhong||0,
- yiwancheng: c.yiwancheng||0, yituikuan: c.yituikuan||0
- }})
+ yiwancheng: c.yiwancheng||0, yituikuan: c.yituikuan||0,
+ }});
},
- goToSetting() { wx.navigateTo({ url: '/pages/edit/edit' }) },
+ async onTapRefresh() {
+ if (this._profileRefreshing) return;
+ this._profileRefreshing = true;
+ wx.showLoading({ title: '刷新中', mask: true });
+ try {
+ if (getSessionToken(app)) {
+ await restoreStaffContextAfterAuth();
+ }
+ backfillUserProfileCache(app);
+ this.loadUserData();
+ this.updateOrderCounts();
+ wx.showToast({ title: '已刷新', icon: 'success' });
+ } catch (e) {
+ wx.showToast({ title: '刷新失败', icon: 'none' });
+ } finally {
+ wx.hideLoading();
+ this._profileRefreshing = false;
+ }
+ },
+
+ openPindaoModal() {
+ 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 });
+ },
+
+ goToGuanzhuA() {
+ wx.navigateTo({ url: '/pages/manager-assign/manager-assign' });
+ },
+
+ goToSetting() { wx.navigateTo({ url: '/pages/edit/edit' }); },
handleWechatLogin() {
wx.showLoading({ title: '登录中...', mask: true });
@@ -139,7 +188,7 @@ Page(createPage({
.finally(() => wx.hideLoading());
},
- goToOrder(e) { wx.navigateTo({ url: `/pages/orders/orders?type=${e.currentTarget.dataset.type}` }) },
+ goToOrder(e) { wx.navigateTo({ url: `/pages/orders/orders?type=${e.currentTarget.dataset.type}` }); },
goToAuth(e) {
const type = e.currentTarget.dataset.type;
@@ -178,6 +227,4 @@ Page(createPage({
})
.catch(() => {});
},
-
- goToGuanzhuA() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) },
-}))
+}));
diff --git a/pages/mine/mine.json b/pages/mine/mine.json
index a1b6de3..1106d48 100644
--- a/pages/mine/mine.json
+++ b/pages/mine/mine.json
@@ -1,7 +1,8 @@
{
"usingComponents": {
"global-notification": "/components/global-notification/global-notification",
- "tab-bar": "/tab-bar/index"
+ "tab-bar": "/tab-bar/index",
+ "pindao-modal": "/components/pindao-modal/pindao-modal"
},
"navigationBarTitleText": "个人中心",
"navigationBarBackgroundColor": "#F7F3ED",
diff --git a/pages/mine/mine.wxml b/pages/mine/mine.wxml
index 6777621..5b0bb6a 100644
--- a/pages/mine/mine.wxml
+++ b/pages/mine/mine.wxml
@@ -5,8 +5,13 @@
-
-
+
+
+
+
+
+
+
@@ -63,7 +68,11 @@
- 关注星阙
+ 关注快手
+
+
+
+ 频道
@@ -121,4 +130,11 @@
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/pages/mine/mine.wxss b/pages/mine/mine.wxss
index 453e7f6..b036091 100644
--- a/pages/mine/mine.wxss
+++ b/pages/mine/mine.wxss
@@ -18,7 +18,7 @@ page {
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
- background: linear-gradient(180deg, #ede9fe 0%, #f5f5f5 40%, #f5f5f5 100%);
+ background: linear-gradient(180deg, #fef6d4 0%, #f5f5f5 40%, #f5f5f5 100%);
z-index: 0;
pointer-events: none;
}
@@ -48,7 +48,7 @@ page {
height: 48rpx;
}
.icon-bg {
- background: #ede9fe;
+ background: #fef6d4;
border-radius: 22rpx;
display: flex;
align-items: center;
@@ -67,8 +67,25 @@ page {
width: 56rpx; height: 56rpx;
display: flex; align-items: center; justify-content: center;
}
-.settings-icon .icon-dark {
- width: 44rpx; height: 44rpx;
+.hero-actions {
+ position: absolute;
+ top: 24rpx;
+ right: 24rpx;
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ z-index: 10;
+}
+.hero-action-btn {
+ width: 56rpx;
+ height: 56rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.hero-action-btn .icon-dark {
+ width: 44rpx;
+ height: 44rpx;
}
.user-block {
display: flex;
@@ -124,7 +141,7 @@ page {
line-height: 1.2;
}
.gradient-bg {
- background: linear-gradient(to right, rgba(147, 51, 234, 0.05), rgba(147, 51, 234, 0.15));
+ background: linear-gradient(to right, rgba(255, 208, 97, 0.05), rgba(255, 208, 97, 0.15));
}
.title-text {
font-size: 34rpx;
@@ -216,7 +233,7 @@ page {
margin-top: 4rpx;
}
.auth-tag-done {
- color: #9333ea;
+ color: #C9A962;
font-weight: 500;
}
@@ -257,6 +274,6 @@ page {
background: none;
}
.coop {
- color: #9333ea;
+ color: #C9A962;
font-weight: 500;
}
diff --git a/pages/order-detail/order-detail.js b/pages/order-detail/order-detail.js
index d04a153..3e985fb 100644
--- a/pages/order-detail/order-detail.js
+++ b/pages/order-detail/order-detail.js
@@ -211,6 +211,8 @@ Page({
identityType: 'normal',
userId: 'Boss' + uid,
orderId: dingdanId,
+ partnerUid: this.data.xiangxiShuju.dashou || '',
+ fadanPingtai: this.data.jibenShuju.fadanpingtai || 0,
groupName: this.data.jibenShuju.nicheng + '的订单群',
isCross: 0
}).catch(err => {
diff --git a/pages/order-pool/order-pool.js b/pages/order-pool/order-pool.js
index 8c6206a..f6429ed 100644
--- a/pages/order-pool/order-pool.js
+++ b/pages/order-pool/order-pool.js
@@ -308,13 +308,16 @@ Page({
let params = {};
switch (failureType) {
case 'huiyuan':
- params = { needScroll: '0', scrollTo: 'member' };
+ url = '/pages/fighter-recharge/fighter-recharge';
+ params = { scrollTo: 'member' };
break;
case 'yajin':
- params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin };
+ url = '/pages/fighter-recharge/fighter-deposit';
+ params = { requiredYajin: requiredYajin };
break;
case 'jifen':
- params = { needScroll: '1', scrollTo: 'bottom' };
+ url = '/pages/fighter-recharge/fighter-recharge';
+ params = { scrollTo: 'jifen' };
break;
}
if (huiyuanId) params.huiyuanId = huiyuanId;
diff --git a/pages/order-pool/order-pool.wxml b/pages/order-pool/order-pool.wxml
index cffad16..69d5832 100644
--- a/pages/order-pool/order-pool.wxml
+++ b/pages/order-pool/order-pool.wxml
@@ -25,7 +25,7 @@
class="xym-lunbo-swiper"
indicator-dots="{{lunboList.length > 1}}"
indicator-color="rgba(255,255,255,0.6)"
- indicator-active-color="#9333ea"
+ indicator-active-color="#ffd061"
autoplay="{{lunboList.length > 1}}"
interval="4000"
circular
@@ -75,7 +75,7 @@
refresher-enabled="{{xuanzhongLeixingId != null}}"
refresher-threshold="80"
refresher-default-style="black"
- refresher-background="#f5f3ff"
+ refresher-background="#f5f5f5"
refresher-triggered="{{scrollViewRefreshing}}"
bindrefresherrefresh="onPullDownRefresh"
bindscrolltolower="onReachBottom"
diff --git a/pages/order-pool/order-pool.wxss b/pages/order-pool/order-pool.wxss
index ca2ce20..1419c14 100644
--- a/pages/order-pool/order-pool.wxss
+++ b/pages/order-pool/order-pool.wxss
@@ -64,9 +64,9 @@
width: 72rpx;
height: 52rpx;
margin-bottom: 30rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
border-radius: 10rpx;
- box-shadow: 0 8rpx 24rpx rgba(180, 130, 20, 0.25);
+ box-shadow: 0 8rpx 24rpx rgba(124, 58, 237, 0.25);
}
.icon-lock::before {
@@ -96,10 +96,10 @@
.message {
font-size: 32rpx;
- color: #9333ea;
+ color: #ffaa00;
margin-bottom: 16rpx;
font-weight: 600;
- text-shadow: 0 0 10rpx #9333ea;
+ text-shadow: 0 0 10rpx #ffaa00;
}
.description {
diff --git a/pages/penalty/components/fakuan-list/fakuan-list.js b/pages/penalty/components/fakuan-list/fakuan-list.js
index cf45977..4570034 100644
--- a/pages/penalty/components/fakuan-list/fakuan-list.js
+++ b/pages/penalty/components/fakuan-list/fakuan-list.js
@@ -75,7 +75,27 @@ Component({
});
if (res.statusCode === 200 && res.data.code === 0) {
const data = res.data.data;
- const newList = isLoadMore ? this.data.list.concat(data.list || []) : (data.list || []);
+ const rows = (data.list || []).map(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(url => this.getFullUrl(url));
+ const shensu = (item.shensu_tupian || []).map(url => this.getFullUrl(url));
+ return {
+ ...item,
+ create_time: item.CreateTime || '',
+ display_status,
+ status_class,
+ zhengju_tupian: item.zhengju_tupian || [],
+ shensu_tupian: item.shensu_tupian || [],
+ zhengju_full: zhengju,
+ shensu_full: shensu
+ };
+ });
+ const newList = isLoadMore ? this.data.list.concat(rows) : rows;
this.setData({
list: newList,
hasMore: data.has_more || false, // 以后端返回为准
@@ -231,7 +251,7 @@ Component({
return null;
}
- const COS = require('../../../../utils/cos-wx-sdk-v5.js');
+ const COS = require('../../../../utils/cos-wx-sdk-v5.min.js');
const credentials = tokenData.credentials || tokenData;
const cos = new COS({
SimpleUploadMethod: 'putObject',
diff --git a/pages/penalty/components/fakuan-list/fakuan-list.wxml b/pages/penalty/components/fakuan-list/fakuan-list.wxml
index d530f75..fb4f8b8 100644
--- a/pages/penalty/components/fakuan-list/fakuan-list.wxml
+++ b/pages/penalty/components/fakuan-list/fakuan-list.wxml
@@ -39,23 +39,23 @@
申诉理由{{ detailItem.shensuliyou }}
-
+
证据图片
-
-
-
+
+
+
-
+
申诉图片
-
-
-
+
+
+
diff --git a/pages/penalty/components/fakuan-list/fakuan-list.wxss b/pages/penalty/components/fakuan-list/fakuan-list.wxss
index 1cb84c3..8b27be6 100644
--- a/pages/penalty/components/fakuan-list/fakuan-list.wxss
+++ b/pages/penalty/components/fakuan-list/fakuan-list.wxss
@@ -14,7 +14,7 @@ page { background: #f5f5f5; }
.tag { font-size: 20rpx; padding: 2rpx 14rpx; border-radius: 16rpx; display: inline-block; }
/* 状态标签颜色(与积分组件完全相同) */
-.zhuangtai-daijiaona { background: #F3E8FF; color: #7c3aed; } /* 待缴纳 */
+.zhuangtai-daijiaona { background: #FFF3E0; color: #E65100; } /* 待缴纳 */
.zhuangtai-yijiaona { background: #E8F5E9; color: #2E7D32; } /* 已缴纳 */
.zhuangtai-shensuzhong { background: #E3F2FD; color: #1565C0; } /* 申诉中 */
.zhuangtai-yibohui { background: #F3E5F5; color: #7B1FA2; } /* 申诉成功 */
diff --git a/pages/penalty/components/jifen-list/jifen-list.js b/pages/penalty/components/jifen-list/jifen-list.js
index 487c7d9..d0102ef 100644
--- a/pages/penalty/components/jifen-list/jifen-list.js
+++ b/pages/penalty/components/jifen-list/jifen-list.js
@@ -150,7 +150,7 @@ getFullImageUrl(relativeUrl) {
throw new Error(res?.data?.msg || '获取上传凭证失败');
},
initCOSClient(tokenData) {
- const COS = require('../../../../utils/cos-wx-sdk-v5.js');
+ const COS = require('../../../../utils/cos-wx-sdk-v5.min.js');
const credentials = tokenData.credentials || tokenData;
const bucket = tokenData.bucket || 'julebu-1361527063';
const region = tokenData.region || 'ap-shanghai';
diff --git a/pages/penalty/components/jifen-list/jifen-list.wxss b/pages/penalty/components/jifen-list/jifen-list.wxss
index e3509f6..bc802da 100644
--- a/pages/penalty/components/jifen-list/jifen-list.wxss
+++ b/pages/penalty/components/jifen-list/jifen-list.wxss
@@ -16,7 +16,7 @@ page { background: #f5f5f5; }
.card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
.time { font-size: 24rpx; color: #999; }
.tag { font-size: 20rpx; padding: 2rpx 14rpx; border-radius: 16rpx; display: inline-block; }
-.zhuangtai-daichuli { background: #f3e8ff; color: #7c3aed; }
+.zhuangtai-daichuli { background: #fff3e0; color: #e65100; }
.zhuangtai-yichufa { background: #e8f5e9; color: #2e7d32; }
.zhuangtai-yibohui { background: #f3e5f5; color: #7b1fa2; }
.zhuangtai-shensuzhong { background: #e3f2fd; color: #1565c0; }
diff --git a/pages/penalty/penalty/penalty.wxss b/pages/penalty/penalty/penalty.wxss
index 4bc33c7..4a57b00 100644
--- a/pages/penalty/penalty/penalty.wxss
+++ b/pages/penalty/penalty/penalty.wxss
@@ -26,7 +26,7 @@ page { background: #f7f8fa; font-family: -apple-system, BlinkMacSystemFont, sans
font-weight: 700;
}
.green { color: #2E7D32; }
-.orange { color: #9333ea; }
+.orange { color: #E67E22; }
.num-label {
font-size: 24rpx;
color: #888;
diff --git a/pages/poster/poster.js b/pages/poster/poster.js
index e47101b..0e02d9f 100644
--- a/pages/poster/poster.js
+++ b/pages/poster/poster.js
@@ -1,281 +1,236 @@
-// pages/poster/poster.js
-import request from '../../utils/request.js';
-
-const app = getApp();
-
-Page({
- data: {
- qrcodeUrl: '',
- isLoading: false,
- showPosterCanvas: false,
- posterImageTemp: '',
- avatarUrl: '',
- uid: '',
- nickName: '',
- },
-
- onLoad() {
- this.loadQRCodeFromCache();
- this.loadUserInfo();
- },
-
- onShow() {
- this.registerNotificationComponent();
- },
-
- registerNotificationComponent() {
- const notificationComp = this.selectComponent('#global-notification');
- if (notificationComp && notificationComp.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- };
- }
- },
-
- loadQRCodeFromCache() {
- try {
- const relativeUrl = wx.getStorageSync('haibao_url');
- if (relativeUrl) {
- const fullUrl = this.getFullImageUrl(relativeUrl);
- this.setData({ qrcodeUrl: fullUrl });
- } else {
- this.setData({ qrcodeUrl: '' });
- }
- } catch (error) {
- console.error('读取缓存失败', error);
- }
- },
-
- loadUserInfo() {
- const touxiang = wx.getStorageSync('touxiang');
- const ossUrl = app.globalData.ossImageUrl || '';
- const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
- let avatarUrl = defaultAvatar;
- if (touxiang && typeof touxiang === 'string' && touxiang.trim() !== '') {
- avatarUrl = this.getFullImageUrl(touxiang);
- }
- const uid = wx.getStorageSync('uid') || '';
- let nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '管事';
- this.setData({ avatarUrl, uid, nickName });
- },
-
- getFullImageUrl(url) {
- if (!url) return '';
- const ossUrl = app.globalData.ossImageUrl || '';
- return url.startsWith('http') ? url : ossUrl + url;
- },
-
- refreshQRCode() {
- if (this.data.isLoading) return;
- this.setData({ isLoading: true });
- request({
- url: '/peizhi/guanshiewm',
- method: 'POST',
- }).then(res => {
- if (res.data && res.data.code === 0) {
- const relativeUrl = res.data.data.url;
- if (relativeUrl) {
- wx.setStorageSync('haibao_url', relativeUrl);
- const fullUrl = this.getFullImageUrl(relativeUrl);
- this.setData({ qrcodeUrl: fullUrl });
- wx.showToast({ title: '获取成功', icon: 'success' });
- } else {
- wx.showToast({ title: '返回数据异常', icon: 'none' });
- }
- } else {
- wx.showToast({ title: res.data.msg || '获取失败', icon: 'none' });
- }
- }).catch(err => {
- console.error('获取海报失败', err);
- wx.showToast({ title: '网络错误', icon: 'none' });
- }).finally(() => {
- this.setData({ isLoading: false });
- });
- },
-
- // 🔥【修改】保存二维码到相册(先下载网络图片)
- saveToAlbum() {
- if (!this.data.qrcodeUrl) {
- wx.showToast({ title: '暂无二维码', icon: 'none' });
- return;
- }
-
- wx.showLoading({ title: '保存中...', mask: true });
- wx.downloadFile({
- url: this.data.qrcodeUrl,
- success: (res) => {
- wx.hideLoading();
- if (res.statusCode === 200) {
- // 调用已有的保存函数(传入临时路径)
- this.downloadAndSave(res.tempFilePath);
- } else {
- wx.showToast({ title: '下载失败', icon: 'none' });
- }
- },
- fail: (err) => {
- wx.hideLoading();
- console.error('下载二维码失败', err);
- wx.showToast({ title: '下载失败', icon: 'none' });
- }
- });
- },
-
- generateMyPoster() {
- if (!this.data.qrcodeUrl) {
- wx.showToast({ title: '请先生成二维码', icon: 'none' });
- return;
- }
-
- wx.showLoading({ title: '生成海报中...', mask: true });
-
- const ossUrl = app.globalData.ossImageUrl || '';
- const bgUrl = ossUrl + 'beijing/haibaobeijing.jpg';
- const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl];
-
- const promises = urls.map(url => this.loadImage(url));
- Promise.all(promises)
- .then((images) => {
- wx.hideLoading();
- this.setData({ showPosterCanvas: true }, () => {
- setTimeout(() => {
- this.drawPoster(images[0], images[1], images[2]);
- }, 200);
- });
- })
- .catch((err) => {
- wx.hideLoading();
- wx.showToast({ title: '图片加载失败', icon: 'none' });
- console.error('图片加载失败', err);
- });
- },
-
- loadImage(url) {
- return new Promise((resolve, reject) => {
- wx.getImageInfo({
- src: url,
- success: (res) => resolve(res.path),
- fail: reject
- });
- });
- },
-
- drawPoster(bgPath, qrPath, avatarPath) {
- const ctx = wx.createCanvasContext('posterCanvas', this);
- const query = wx.createSelectorQuery().in(this);
- query.select('.poster-canvas').boundingClientRect(rect => {
- if (!rect) {
- wx.showToast({ title: '画布获取失败', icon: 'none' });
- return;
- }
- const canvasWidth = rect.width;
- const canvasHeight = rect.height;
-
- // 1. 绘制背景
- ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight);
-
- const qrSize = 100;
- const margin = 5;
- const qrX = canvasWidth - qrSize - margin;
- const qrY = canvasHeight - qrSize - margin;
- ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
-
- const avatarSize = 60;
- const avatarX = margin + 20;
- const avatarY = canvasHeight - avatarSize - margin;
- ctx.save();
- ctx.beginPath();
- ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI);
- ctx.clip();
- ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
- ctx.restore();
-
- ctx.setFontSize(16);
- ctx.setFillStyle('#333333');
- ctx.setTextAlign('left');
-
- let nick = this.data.nickName || '管事';
- if (nick.length > 3) {
- nick = nick.substring(0, 3) + '...';
- }
- const nameText = nick;
-
- const textX = avatarX + avatarSize + 8;
- const textY = avatarY + avatarSize/2 + 6;
- ctx.fillText(nameText, textX, textY);
-
- ctx.setFontSize(18);
- ctx.setFillStyle('#9333ea');
- ctx.setTextAlign('left');
- const slogan = '快来加入我们 ✦';
- const sloganX = avatarX;
- const sloganY = avatarY - 12;
- ctx.fillText(slogan, sloganX, sloganY);
-
- ctx.draw(false, () => {
- wx.canvasToTempFilePath({
- canvasId: 'posterCanvas',
- success: (res) => {
- this.setData({ posterImageTemp: res.tempFilePath });
- },
- fail: (err) => {
- console.error('生成海报临时文件失败', err);
- }
- }, this);
- });
- }).exec();
- },
-
- savePoster() {
- if (!this.data.posterImageTemp) {
- wx.showToast({ title: '海报尚未生成', icon: 'none' });
- return;
- }
- this.downloadAndSave(this.data.posterImageTemp);
- },
-
- hidePoster() {
- this.setData({ showPosterCanvas: false, posterImageTemp: '' });
- },
-
- downloadAndSave(filePath) {
- wx.getSetting({
- success: (res) => {
- if (!res.authSetting['scope.writePhotosAlbum']) {
- wx.authorize({
- scope: 'scope.writePhotosAlbum',
- success: () => {
- this._saveImage(filePath);
- },
- fail: () => {
- wx.showModal({
- title: '提示',
- content: '需要您授权保存到相册',
- success: (modalRes) => {
- if (modalRes.confirm) {
- wx.openSetting();
- }
- }
- });
- }
- });
- } else {
- this._saveImage(filePath);
- }
- }
- });
- },
-
- _saveImage(filePath) {
- wx.saveImageToPhotosAlbum({
- filePath: filePath,
- success: () => {
- wx.showToast({ title: '保存成功', icon: 'success' });
- },
- fail: (err) => {
- console.error('保存失败', err);
- wx.showToast({ title: '保存失败', icon: 'none' });
- }
- });
- },
-});
\ No newline at end of file
+// pages/poster/poster.js — 管事推广海报
+import request from '../../utils/request.js';
+import {
+ getFullImageUrl,
+ loadPosterPageConfig,
+ posterQrCacheKey,
+} from '../../utils/poster-page.js';
+
+const app = getApp();
+
+Page({
+ data: {
+ qrcodeUrl: '',
+ isLoading: false,
+ showPosterCanvas: false,
+ posterImageTemp: '',
+ avatarUrl: '',
+ uid: '',
+ nickName: '',
+ posterBgUrl: '',
+ },
+
+ async onLoad() {
+ const { bgUrl, qrCacheKey } = await loadPosterPageConfig('guanshi', app);
+ this._qrCacheKey = qrCacheKey;
+ this.setData({ posterBgUrl: bgUrl });
+ this.loadQRCodeFromCache();
+ this.loadUserInfo();
+ },
+
+ onShow() {
+ this.registerNotificationComponent();
+ },
+
+ registerNotificationComponent() {
+ const notificationComp = this.selectComponent('#global-notification');
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification(),
+ };
+ }
+ },
+
+ loadQRCodeFromCache() {
+ try {
+ const key = this._qrCacheKey || posterQrCacheKey('guanshi');
+ const relativeUrl = wx.getStorageSync(key);
+ if (relativeUrl) {
+ this.setData({ qrcodeUrl: getFullImageUrl(relativeUrl, app) });
+ } else {
+ this.setData({ qrcodeUrl: '' });
+ }
+ } catch (error) {
+ console.error('读取缓存失败', error);
+ }
+ },
+
+ loadUserInfo() {
+ const touxiang = wx.getStorageSync('touxiang');
+ const ossUrl = app.globalData.ossImageUrl || '';
+ const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
+ let avatarUrl = defaultAvatar;
+ if (touxiang && typeof touxiang === 'string' && touxiang.trim() !== '') {
+ avatarUrl = getFullImageUrl(touxiang, app);
+ }
+ const uid = wx.getStorageSync('uid') || '';
+ const nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '管事';
+ this.setData({ avatarUrl, uid, nickName });
+ },
+
+ refreshQRCode() {
+ if (this.data.isLoading) return;
+ this.setData({ isLoading: true });
+ request({
+ url: '/peizhi/guanshiewm',
+ method: 'POST',
+ }).then((res) => {
+ if (res.data && res.data.code === 0) {
+ const relativeUrl = res.data.data.url;
+ if (relativeUrl) {
+ const key = this._qrCacheKey || posterQrCacheKey('guanshi');
+ wx.setStorageSync(key, relativeUrl);
+ this.setData({ qrcodeUrl: getFullImageUrl(relativeUrl, app) });
+ wx.showToast({ title: '获取成功', icon: 'success' });
+ } else {
+ wx.showToast({ title: '返回数据异常', icon: 'none' });
+ }
+ } else {
+ wx.showToast({ title: res.data.msg || res.data.message || '获取失败', icon: 'none' });
+ }
+ }).catch((err) => {
+ console.error('获取海报失败', err);
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }).finally(() => {
+ this.setData({ isLoading: false });
+ });
+ },
+
+ saveToAlbum() {
+ if (!this.data.qrcodeUrl) {
+ wx.showToast({ title: '暂无二维码', icon: 'none' });
+ return;
+ }
+ wx.showLoading({ title: '保存中...', mask: true });
+ wx.downloadFile({
+ url: this.data.qrcodeUrl,
+ success: (res) => {
+ wx.hideLoading();
+ if (res.statusCode === 200) {
+ this.downloadAndSave(res.tempFilePath);
+ } else {
+ wx.showToast({ title: '下载失败', icon: 'none' });
+ }
+ },
+ fail: () => {
+ wx.hideLoading();
+ wx.showToast({ title: '下载失败', icon: 'none' });
+ },
+ });
+ },
+
+ generateMyPoster() {
+ if (!this.data.qrcodeUrl) {
+ wx.showToast({ title: '请先生成二维码', icon: 'none' });
+ return;
+ }
+ wx.showLoading({ title: '生成海报中...', mask: true });
+ const bgUrl = this.data.posterBgUrl;
+ const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl];
+ Promise.all(urls.map((url) => this.loadImage(url)))
+ .then((images) => {
+ wx.hideLoading();
+ this.setData({ showPosterCanvas: true }, () => {
+ setTimeout(() => this.drawPoster(images[0], images[1], images[2]), 200);
+ });
+ })
+ .catch((err) => {
+ wx.hideLoading();
+ wx.showToast({ title: '图片加载失败', icon: 'none' });
+ console.error('图片加载失败', err);
+ });
+ },
+
+ loadImage(url) {
+ return new Promise((resolve, reject) => {
+ wx.getImageInfo({ src: url, success: (res) => resolve(res.path), fail: reject });
+ });
+ },
+
+ drawPoster(bgPath, qrPath, avatarPath) {
+ const ctx = wx.createCanvasContext('posterCanvas', this);
+ const query = wx.createSelectorQuery().in(this);
+ query.select('.poster-canvas').boundingClientRect((rect) => {
+ if (!rect) {
+ wx.showToast({ title: '画布获取失败', icon: 'none' });
+ return;
+ }
+ const canvasWidth = rect.width;
+ const canvasHeight = rect.height;
+ ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight);
+ const qrSize = 100;
+ const margin = 5;
+ const qrX = canvasWidth - qrSize - margin;
+ const qrY = canvasHeight - qrSize - margin;
+ ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
+ const avatarSize = 60;
+ const avatarX = margin + 20;
+ const avatarY = canvasHeight - avatarSize - margin;
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, 2 * Math.PI);
+ ctx.clip();
+ ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
+ ctx.restore();
+ ctx.setFontSize(16);
+ ctx.setFillStyle('#333333');
+ ctx.setTextAlign('left');
+ let nick = this.data.nickName || '管事';
+ if (nick.length > 3) nick = nick.substring(0, 3) + '...';
+ ctx.fillText(nick, avatarX + avatarSize + 8, avatarY + avatarSize / 2 + 6);
+ ctx.setFontSize(18);
+ 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),
+ }, this);
+ });
+ }).exec();
+ },
+
+ savePoster() {
+ if (!this.data.posterImageTemp) {
+ wx.showToast({ title: '海报尚未生成', icon: 'none' });
+ return;
+ }
+ this.downloadAndSave(this.data.posterImageTemp);
+ },
+
+ hidePoster() {
+ this.setData({ showPosterCanvas: false, posterImageTemp: '' });
+ },
+
+ downloadAndSave(filePath) {
+ wx.getSetting({
+ success: (res) => {
+ if (!res.authSetting['scope.writePhotosAlbum']) {
+ wx.authorize({
+ scope: 'scope.writePhotosAlbum',
+ success: () => this._saveImage(filePath),
+ fail: () => {
+ wx.showModal({
+ title: '提示',
+ content: '需要您授权保存到相册',
+ success: (modalRes) => { if (modalRes.confirm) wx.openSetting(); },
+ });
+ },
+ });
+ } else {
+ this._saveImage(filePath);
+ }
+ },
+ });
+ },
+
+ _saveImage(filePath) {
+ wx.saveImageToPhotosAlbum({
+ filePath,
+ success: () => wx.showToast({ title: '保存成功', icon: 'success' }),
+ fail: () => wx.showToast({ title: '保存失败', icon: 'none' }),
+ });
+ },
+});
diff --git a/pages/poster/poster.wxss b/pages/poster/poster.wxss
index 484a40b..0157a40 100644
--- a/pages/poster/poster.wxss
+++ b/pages/poster/poster.wxss
@@ -161,10 +161,10 @@ page {
box-shadow: 0 0 40rpx #00a6ff;
}
.pbtn-save { border-color: #00a6ff; }
-.pbtn-refresh { border-color: #9333ea; }
-.pbtn-refresh .pbtn-icon { color: #9333ea; }
-.pbtn-poster { border-color: #9333ea; }
-.pbtn-poster .pbtn-icon { color: #9333ea; }
+.pbtn-refresh { border-color: #ffaa00; }
+.pbtn-refresh .pbtn-icon { color: #ffaa00; }
+.pbtn-poster { border-color: #ffaa00; }
+.pbtn-poster .pbtn-icon { color: #ffaa00; }
.pbtn-loading {
opacity: 0.7;
pointer-events: none;
diff --git a/pages/product-detail/product-detail.js b/pages/product-detail/product-detail.js
index 1f698b8..430dfc2 100644
--- a/pages/product-detail/product-detail.js
+++ b/pages/product-detail/product-detail.js
@@ -1,252 +1,251 @@
-// pages/product-detail/product-detail.js
-const app = getApp()
-import { ensureLogin } from '../../utils/login'
-import { backfillUserProfileCache } from '../../utils/role-tab-bar'
-
-Page({
- data: {
- ossImageUrl: '',
- apiBaseUrl: '',
-
- shangpinId: '',
- shangpinTitle: '',
- shangpinPrice: '',
-
- shangpinData: null,
- isLoading: true,
- loadError: false,
-
- // 页面字段映射
- fieldMapping: {
- tupian: 'tupian',
- biaoti: 'biaoti',
- jiage: 'jiage',
- xiangqing: 'xiangqing',
- xiadanxuzhi: 'xiadanxuzhi',
- guize: 'guize',
- xiaoliang: 'xiaoliang',
- kucun: 'kucun',
- fenlei: 'fenlei',
- pingfen: 'pingfen'
- }
- },
-
- onLoad(options) {
- this.setData({
- ossImageUrl: app.globalData.ossImageUrl,
- apiBaseUrl: app.globalData.apiBaseUrl,
- shangpinId: options.id || '',
- shangpinTitle: options.title || '',
- shangpinPrice: options.price || ''
- })
-
- if (!this.data.shangpinId) {
- wx.showToast({
- title: '商品不存在',
- icon: 'none'
- })
- setTimeout(() => {
- wx.navigateBack()
- }, 1500)
- return
- }
-
- this.loadShangpinDetail()
- },
- onShow() {
- backfillUserProfileCache(app);
- this.registerNotificationComponent();
- },
-
- registerNotificationComponent() {
- const app = getApp();
- const notificationComp = this.selectComponent('#global-notification');
-
- if (notificationComp && notificationComp.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- };
- }
- },
-
- loadShangpinDetail() {
- const that = this
- const { shangpinId, apiBaseUrl } = this.data
-
- this.setData({ isLoading: true, loadError: false })
-
- wx.request({
- url: apiBaseUrl + '/shangpin/xiangqinghuoqu/',
- method: 'POST',
- header: {
- 'content-type': 'application/json'
- },
- data: {
- shangpin_id: shangpinId
- },
- success(res) {
- if (res.statusCode === 200 && res.data && res.data.code === 0) {
- const shangpinData = res.data.data || {}
-
- // 处理价格
- if (shangpinData.jiage) {
- const jiage = parseFloat(shangpinData.jiage) || 0
- const priceInteger = Math.floor(jiage)
- let priceDecimal = '00'
-
- const decimalPart = (jiage - priceInteger).toFixed(2)
- if (decimalPart > 0) {
- priceDecimal = decimalPart.toString().split('.')[1]
- }
-
- shangpinData.priceInteger = priceInteger
- shangpinData.priceDecimal = priceDecimal
- }
-
- // 处理图片URL
- if (shangpinData.tupian && !shangpinData.tupian.startsWith('http')) {
- shangpinData.tupian = that.data.ossImageUrl + shangpinData.tupian
- }
-
- // 处理规则图片URL
- if (shangpinData.guize && !shangpinData.guize.startsWith('http')) {
- shangpinData.guize = that.data.ossImageUrl + shangpinData.guize
- }
-
- // 处理销量显示
- if (shangpinData.xiaoliang) {
- shangpinData.xiaoliangText = that.formatXiaoliang(shangpinData.xiaoliang)
- }
-
- // 处理库存显示
- if (shangpinData.kucun) {
- shangpinData.kucunText = shangpinData.kucun + '件'
- shangpinData.kucunClass = shangpinData.kucun > 0 ? 'kucun-normal' : 'kucun-none'
- }
-
- // 设置页面标题
- if (shangpinData.biaoti) {
- wx.setNavigationBarTitle({
- title: '商品详情'
- })
- }
-
- that.setData({
- shangpinData: shangpinData,
- isLoading: false
- })
- } else {
- that.handleLoadError(res.data?.msg || '加载失败')
- }
- },
- fail() {
- that.handleLoadError('网络错误,请重试')
- }
- })
- },
-
- formatXiaoliang(xiaoliang) {
- const num = parseInt(xiaoliang) || 0
-
- if (num >= 10000) {
- return (num / 10000).toFixed(1) + '万+'
- } else if (num >= 1000) {
- return (num / 1000).toFixed(1) + '千+'
- } else {
- return num + ''
- }
- },
-
- handleLoadError(errorMsg) {
- this.setData({
- isLoading: false,
- loadError: true
- })
-
- wx.showToast({
- title: errorMsg || '加载失败',
- icon: 'none',
- duration: 2000
- })
-
- // 3秒后自动返回
- setTimeout(() => {
- wx.navigateBack()
- }, 3000)
- },
-
- previewImage() {
- const { shangpinData } = this.data
- if (!shangpinData || !shangpinData.tupian) return
-
- wx.previewImage({
- current: shangpinData.tupian,
- urls: [shangpinData.tupian]
- })
- },
-
- async onOrderClick() {
- const { shangpinData, shangpinId } = this.data
-
- // 检查库存
- if (shangpinData && shangpinData.kucun <= 0) {
- wx.showToast({
- title: '商品已售罄',
- icon: 'none'
- })
- return
- }
-
- // 验证必要数据
- if (!shangpinData || !shangpinData.biaoti) {
- wx.showToast({
- title: '商品信息不完整',
- icon: 'none'
- })
- return
- }
-
- try {
- await ensureLogin()
- } catch (e) {
- return
- }
-
- const orderData = {
- id: shangpinId,
- title: shangpinData.biaoti,
- price: shangpinData.jiage,
- priceInteger: shangpinData.priceInteger,
- priceDecimal: shangpinData.priceDecimal,
- image: shangpinData.tupian,
- kucun: shangpinData.kucun || 0,
- xiaoliang: shangpinData.xiaoliang || 0
- }
-
- wx.navigateTo({
- url: `/pages/submit/submit?data=${encodeURIComponent(JSON.stringify(orderData))}`
- })
- },
-
- onRefresh() {
- this.loadShangpinDetail()
- },
-
- goToKefu() {
- wx.navigateTo({ url: '/pages/cs-chat/cs-chat' })
- },
-
- onShareAppMessage() {
- const { shangpinData, shangpinId } = this.data
-
- return {
- title: shangpinData?.biaoti || '阿龙电竞 - 商品详情',
- path: `/pages/product-detail/product-detail?id=${shangpinId}`,
- imageUrl: shangpinData?.tupian || ''
- }
- },
-
- onUnload() {
- }
+// pages/product-detail/product-detail.js
+const app = getApp()
+import { ensureLogin } from '../../utils/login'
+import { backfillUserProfileCache } from '../../utils/role-tab-bar'
+import { buildClubHeaders } from '../../utils/club-context.js'
+
+Page({
+ data: {
+ ossImageUrl: '',
+ apiBaseUrl: '',
+
+ shangpinId: '',
+ shangpinTitle: '',
+ shangpinPrice: '',
+
+ shangpinData: null,
+ isLoading: true,
+ loadError: false,
+
+ // 页面字段映射
+ fieldMapping: {
+ tupian: 'tupian',
+ biaoti: 'biaoti',
+ jiage: 'jiage',
+ xiangqing: 'xiangqing',
+ xiadanxuzhi: 'xiadanxuzhi',
+ guize: 'guize',
+ xiaoliang: 'xiaoliang',
+ kucun: 'kucun',
+ fenlei: 'fenlei',
+ pingfen: 'pingfen'
+ }
+ },
+
+ onLoad(options) {
+ this.setData({
+ ossImageUrl: app.globalData.ossImageUrl,
+ apiBaseUrl: app.globalData.apiBaseUrl,
+ shangpinId: options.id || '',
+ shangpinTitle: options.title || '',
+ shangpinPrice: options.price || ''
+ })
+
+ if (!this.data.shangpinId) {
+ wx.showToast({
+ title: '商品不存在',
+ icon: 'none'
+ })
+ setTimeout(() => {
+ wx.navigateBack()
+ }, 1500)
+ return
+ }
+
+ this.loadShangpinDetail()
+ },
+ onShow() {
+ backfillUserProfileCache(app);
+ this.registerNotificationComponent();
+ },
+
+ registerNotificationComponent() {
+ const app = getApp();
+ const notificationComp = this.selectComponent('#global-notification');
+
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification()
+ };
+ }
+ },
+
+ loadShangpinDetail() {
+ const that = this
+ const { shangpinId, apiBaseUrl } = this.data
+
+ this.setData({ isLoading: true, loadError: false })
+
+ wx.request({
+ url: apiBaseUrl + '/shangpin/xiangqinghuoqu/',
+ method: 'POST',
+ header: buildClubHeaders({ 'content-type': 'application/json' }),
+ data: {
+ shangpin_id: shangpinId
+ },
+ success(res) {
+ if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ const shangpinData = res.data.data || {}
+
+ // 处理价格
+ if (shangpinData.jiage) {
+ const jiage = parseFloat(shangpinData.jiage) || 0
+ const priceInteger = Math.floor(jiage)
+ let priceDecimal = '00'
+
+ const decimalPart = (jiage - priceInteger).toFixed(2)
+ if (decimalPart > 0) {
+ priceDecimal = decimalPart.toString().split('.')[1]
+ }
+
+ shangpinData.priceInteger = priceInteger
+ shangpinData.priceDecimal = priceDecimal
+ }
+
+ // 处理图片URL
+ if (shangpinData.tupian && !shangpinData.tupian.startsWith('http')) {
+ shangpinData.tupian = that.data.ossImageUrl + shangpinData.tupian
+ }
+
+ // 处理规则图片URL
+ if (shangpinData.guize && !shangpinData.guize.startsWith('http')) {
+ shangpinData.guize = that.data.ossImageUrl + shangpinData.guize
+ }
+
+ // 处理销量显示
+ if (shangpinData.xiaoliang) {
+ shangpinData.xiaoliangText = that.formatXiaoliang(shangpinData.xiaoliang)
+ }
+
+ // 处理库存显示
+ if (shangpinData.kucun) {
+ shangpinData.kucunText = shangpinData.kucun + '件'
+ shangpinData.kucunClass = shangpinData.kucun > 0 ? 'kucun-normal' : 'kucun-none'
+ }
+
+ // 设置页面标题
+ if (shangpinData.biaoti) {
+ wx.setNavigationBarTitle({
+ title: '商品详情'
+ })
+ }
+
+ that.setData({
+ shangpinData: shangpinData,
+ isLoading: false
+ })
+ } else {
+ that.handleLoadError(res.data?.msg || '加载失败')
+ }
+ },
+ fail() {
+ that.handleLoadError('网络错误,请重试')
+ }
+ })
+ },
+
+ formatXiaoliang(xiaoliang) {
+ const num = parseInt(xiaoliang) || 0
+
+ if (num >= 10000) {
+ return (num / 10000).toFixed(1) + '万+'
+ } else if (num >= 1000) {
+ return (num / 1000).toFixed(1) + '千+'
+ } else {
+ return num + ''
+ }
+ },
+
+ handleLoadError(errorMsg) {
+ this.setData({
+ isLoading: false,
+ loadError: true
+ })
+
+ wx.showToast({
+ title: errorMsg || '加载失败',
+ icon: 'none',
+ duration: 2000
+ })
+
+ // 3秒后自动返回
+ setTimeout(() => {
+ wx.navigateBack()
+ }, 3000)
+ },
+
+ previewImage() {
+ const { shangpinData } = this.data
+ if (!shangpinData || !shangpinData.tupian) return
+
+ wx.previewImage({
+ current: shangpinData.tupian,
+ urls: [shangpinData.tupian]
+ })
+ },
+
+ async onOrderClick() {
+ const { shangpinData, shangpinId } = this.data
+
+ // 检查库存
+ if (shangpinData && shangpinData.kucun <= 0) {
+ wx.showToast({
+ title: '商品已售罄',
+ icon: 'none'
+ })
+ return
+ }
+
+ // 验证必要数据
+ if (!shangpinData || !shangpinData.biaoti) {
+ wx.showToast({
+ title: '商品信息不完整',
+ icon: 'none'
+ })
+ return
+ }
+
+ try {
+ await ensureLogin()
+ } catch (e) {
+ return
+ }
+
+ const orderData = {
+ id: shangpinId,
+ title: shangpinData.biaoti,
+ price: shangpinData.jiage,
+ priceInteger: shangpinData.priceInteger,
+ priceDecimal: shangpinData.priceDecimal,
+ image: shangpinData.tupian,
+ kucun: shangpinData.kucun || 0,
+ xiaoliang: shangpinData.xiaoliang || 0
+ }
+
+ wx.navigateTo({
+ url: `/pages/submit/submit?data=${encodeURIComponent(JSON.stringify(orderData))}`
+ })
+ },
+
+ onRefresh() {
+ this.loadShangpinDetail()
+ },
+
+ goToKefu() {
+ wx.navigateTo({ url: '/pages/cs-chat/cs-chat' })
+ },
+
+ onShareAppMessage() {
+ const { shangpinData, shangpinId } = this.data
+
+ return {
+ title: shangpinData?.biaoti || '阿龙电竞 - 商品详情',
+ path: `/pages/product-detail/product-detail?id=${shangpinId}`,
+ imageUrl: shangpinData?.tupian || ''
+ }
+ },
+
+ onUnload() {
+ }
})
\ No newline at end of file
diff --git a/pages/recharge-log/recharge-log.js b/pages/recharge-log/recharge-log.js
index a2a592d..2ad324c 100644
--- a/pages/recharge-log/recharge-log.js
+++ b/pages/recharge-log/recharge-log.js
@@ -1,288 +1,401 @@
-// 管事会员记录页面逻辑
+// 佣金记录(三合一:接单佣金 / 管事分佣 / 组长分红)
import request from '../../utils/request.js';
+import { getOrderStatusText } from '../../utils/api-helper.js';
+import { isRoleStatusActive } from '../../utils/base-page.js';
-// 每页数据条数常量 - 统一管理,方便修改
-const MEIYE_TIAOSHU = 50;
+const MEIYE_TIAOSHU_GUANSHI = 50;
+const PAGE_SIZE_DASHOU = 15;
+const PAGE_SIZE_ZUZHANG = 5;
+const REFRESH_CD = 2000;
+
+const TAB_MAP = {
+ dashou: 'dashou',
+ commission: 'dashou',
+ guanshi: 'guanshi',
+ recharge: 'guanshi',
+ zuzhang: 'zuzhang',
+ fenhong: 'zuzhang',
+};
Page({
data: {
- // 从全局变量获取的数据
- yaoqingzongshu: 0, // 邀请打手总数
- fenyongzonge: '0.00', // 分成总额
-
- // 从接口获取的数据
- chongzhiDashouShuliang: 0, // 充值打手数量
- dashouList: [], // 打手列表数据
- zongTiaoshu: 0, // 总条数
-
- // 分页相关
- dangqianYe: 1, // 当前页
- meiyouGengduo: false, // 没有更多数据
- jiazaiZhong: false, // 加载中状态
- jiazaiGengduo: false, // 加载更多状态
-
- // UI状态
- cuowuTishi: '', // 错误提示
- shuaxinKezhi: false, // 刷新按钮是否可点击
- shuaxinCd: 2000, // 刷新冷却时间(毫秒)
-
- // 常量(用于模板)
- meiyeTiaoshu: MEIYE_TIAOSHU // 每页条数
+ activeTab: 'dashou',
+ tabs: [],
+
+ isDashou: false,
+ isGuanshi: false,
+ isZuzhang: false,
+
+ // 管事分佣统计
+ yaoqingzongshu: 0,
+ fenyongzonge: '0.00',
+ chongzhiDashouShuliang: 0,
+
+ // 组长分红统计
+ fenhongZonge: '0.00',
+ yaoqingGuanshi: 0,
+ fenhongCishu: 0,
+
+ // 接单佣金列表
+ dashouCommissionList: [],
+ dashouPage: 1,
+ dashouHasMore: true,
+ dashouTotal: 0,
+
+ // 管事分佣列表
+ guanshiList: [],
+ guanshiPage: 1,
+ guanshiHasMore: false,
+ guanshiTotal: 0,
+
+ // 组长分红列表
+ zuzhangList: [],
+ zuzhangPage: 1,
+ zuzhangHasMore: true,
+ zuzhangTotal: 0,
+
+ jiazaiZhong: false,
+ jiazaiGengduo: false,
+ shuaxinKezhi: false,
+ cuowuTishi: '',
+
+ loadedTabs: {},
+ scrollTop: 0,
},
onLoad(options) {
- // 从全局变量获取管事数据
- this.huoquQuanjubianliang();
-
- // 加载第一页数据
- this.jiazaiShuju(true);
+ this._initRoles();
+ const requested = TAB_MAP[(options.tab || options.type || '').trim()] || 'dashou';
+ const tabs = this._buildTabs();
+ const activeTab = tabs.find((t) => t.key === requested)?.key || tabs[0]?.key || 'dashou';
+
+ this.setData({ tabs, activeTab }, () => {
+ if (this.data.isGuanshi) this.huoquQuanjubianliang();
+ this._loadTab(activeTab, true);
+ });
},
onShow() {
- // 页面显示时检查全局变量是否有更新
this.registerNotificationComponent();
- this.huoquQuanjubianliang();
+ if (this.data.isGuanshi) this.huoquQuanjubianliang();
},
- // 🆕 新增:注册通知组件
- registerNotificationComponent() {
- const app = getApp();
- const notificationComp = this.selectComponent('#global-notification');
-
- if (notificationComp && notificationComp.showNotification) {
- console.log('🏪 商城页面注册通知组件');
- app.globalData.globalNotification = {
- show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
- };
- }
- },
- // 获取全局变量数据
- huoquQuanjubianliang() {
+ registerNotificationComponent() {
const app = getApp();
- const guanshiData = app.globalData.guanshi;
-
+ const notificationComp = this.selectComponent('#global-notification');
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification(),
+ };
+ }
+ },
+
+ _initRoles() {
+ const isDashou = isRoleStatusActive(wx.getStorageSync('dashoustatus'));
+ const isGuanshi = isRoleStatusActive(wx.getStorageSync('guanshistatus'));
+ const isZuzhang = isRoleStatusActive(wx.getStorageSync('zuzhangstatus'));
+ this.setData({
+ isDashou: isDashou || (!isGuanshi && !isZuzhang),
+ isGuanshi,
+ isZuzhang,
+ });
+ },
+
+ _buildTabs() {
+ const { isDashou, isGuanshi, isZuzhang } = this.data;
+ const tabs = [];
+ if (isDashou) tabs.push({ key: 'dashou', label: '接单佣金' });
+ if (isGuanshi) tabs.push({ key: 'guanshi', label: '管事分佣' });
+ if (isZuzhang) tabs.push({ key: 'zuzhang', label: '组长分红' });
+ if (!tabs.length) tabs.push({ key: 'dashou', label: '接单佣金' });
+ return tabs;
+ },
+
+ onTabTap(e) {
+ const key = e.currentTarget.dataset.key;
+ if (key === this.data.activeTab) return;
+ this.setData({ activeTab: key, cuowuTishi: '', scrollTop: 0 });
+ if (!this.data.loadedTabs[key]) {
+ this._loadTab(key, true);
+ }
+ },
+
+ huoquQuanjubianliang() {
+ const guanshiData = getApp().globalData.guanshi;
if (guanshiData) {
this.setData({
yaoqingzongshu: guanshiData.yaoqingzongshu || 0,
- fenyongzonge: guanshiData.fenyongzonge || '0.00'
+ fenyongzonge: guanshiData.fenyongzonge || '0.00',
});
}
},
- // 加载数据核心方法
- async jiazaiShuju(chushihua = false) {
- // 防止重复请求
- if (this.data.jiazaiZhong) return;
-
- // 如果是初始化加载,重置分页
- if (chushihua) {
+ _loadTab(tab, reset) {
+ if (tab === 'dashou') return this._loadDashouCommission(reset);
+ if (tab === 'guanshi') return this._loadGuanshi(reset);
+ if (tab === 'zuzhang') return this._loadZuzhang(reset);
+ return Promise.resolve();
+ },
+
+ shuaxinShuju() {
+ if (this.data.shuaxinKezhi) {
+ wx.showToast({ title: `请等待${REFRESH_CD / 1000}秒`, icon: 'none' });
+ return;
+ }
+ this.setData({ shuaxinKezhi: true, cuowuTishi: '' });
+ this._loadTab(this.data.activeTab, true).finally(() => {
+ setTimeout(() => this.setData({ shuaxinKezhi: false }), REFRESH_CD);
+ });
+ },
+
+ shanglaJiazai() {
+ const { activeTab, jiazaiGengduo, jiazaiZhong, loadedTabs } = this.data;
+ if (!loadedTabs[activeTab] || jiazaiGengduo || jiazaiZhong) return;
+
+ if (activeTab === 'dashou' && !this.data.dashouHasMore) return;
+ if (activeTab === 'guanshi' && this.data.guanshiHasMore === false) return;
+ if (activeTab === 'zuzhang' && !this.data.zuzhangHasMore) return;
+
+ this._loadTab(activeTab, false);
+ },
+
+ chongshiJiazai() {
+ this.setData({ cuowuTishi: '' });
+ this._loadTab(this.data.activeTab, true);
+ },
+
+ async _loadDashouCommission(reset) {
+ if (this.data.jiazaiZhong || this.data.jiazaiGengduo) return;
+ const page = reset ? 1 : this.data.dashouPage;
+ if (!reset && !this.data.dashouHasMore) return;
+
+ this.setData({
+ jiazaiZhong: reset,
+ jiazaiGengduo: !reset,
+ cuowuTishi: '',
+ });
+
+ try {
+ const res = await request({
+ url: '/dingdan/dshqdingdan',
+ method: 'POST',
+ data: {
+ zhuangtai_list: [3, 8],
+ page,
+ page_size: PAGE_SIZE_DASHOU,
+ },
+ });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0)) {
+ const raw = body.data?.list || [];
+ const rows = raw.map((item) => {
+ const amt = item.jine || item.dashou_fencheng || '0.00';
+ const brief = (item.jieshao || '').trim();
+ const title = brief
+ ? (brief.length > 18 ? `${brief.slice(0, 18)}…` : brief)
+ : `订单 ${item.dingdan_id || ''}`;
+ return {
+ id: item.dingdan_id,
+ title,
+ time: item.wancheng_shijian || item.jiesuan_shijian || item.creat_time || getOrderStatusText(item.zhuangtai),
+ amount: parseFloat(amt || 0).toFixed(2),
+ };
+ });
+ const list = reset ? rows : [...this.data.dashouCommissionList, ...rows];
+ const hasMore = body.data?.has_more ?? raw.length >= PAGE_SIZE_DASHOU;
+ const loadedTabs = { ...this.data.loadedTabs, dashou: true };
+ this.setData({
+ dashouCommissionList: list,
+ dashouPage: reset ? 2 : page + 1,
+ dashouHasMore: hasMore,
+ dashouTotal: body.data?.total || list.length,
+ loadedTabs,
+ });
+ } else {
+ this.setData({ cuowuTishi: body?.msg || '数据加载失败' });
+ }
+ } catch (e) {
+ console.error('接单佣金加载失败', e);
+ this.setData({ cuowuTishi: '网络错误,请检查网络连接' });
+ } finally {
+ this.setData({ jiazaiZhong: false, jiazaiGengduo: false });
+ }
+ },
+
+ async _loadGuanshi(reset) {
+ if (this.data.jiazaiZhong || this.data.jiazaiGengduo) return;
+
+ if (reset) {
this.setData({
- dangqianYe: 1,
- meiyouGengduo: false,
- dashouList: [],
- zongTiaoshu: 0,
- chongzhiDashouShuliang: 0
+ guanshiPage: 1,
+ guanshiHasMore: false,
+ guanshiList: [],
+ guanshiTotal: 0,
+ chongzhiDashouShuliang: 0,
});
} else {
- // 上拉加载更多时,检查是否还有更多数据
- if (this.data.meiyouGengduo) return;
-
- // 如果有数据但不足一页,说明后端已经没数据了
- if (this.data.dashouList.length > 0 && this.data.dashouList.length < MEIYE_TIAOSHU) {
- this.setData({ meiyouGengduo: true });
+ if (this.data.guanshiList.length > 0 && this.data.guanshiList.length < MEIYE_TIAOSHU_GUANSHI) {
+ this.setData({ guanshiHasMore: false });
return;
}
-
- // 如果数据量已经达到总条数,则不请求
- if (this.data.dashouList.length >= this.data.zongTiaoshu && this.data.zongTiaoshu > 0) {
- this.setData({ meiyouGengduo: true });
+ if (this.data.guanshiList.length >= this.data.guanshiTotal && this.data.guanshiTotal > 0) {
+ this.setData({ guanshiHasMore: false });
return;
}
}
-
- // 设置加载状态
+
+ const dangqianYe = reset ? 1 : this.data.guanshiPage;
this.setData({
- jiazaiZhong: chushihua ? true : false,
- jiazaiGengduo: !chushihua ? true : false,
- cuowuTishi: ''
+ jiazaiZhong: reset,
+ jiazaiGengduo: !reset,
+ cuowuTishi: '',
});
-
+
try {
- const { dangqianYe } = this.data;
-
- // 严格按照您的request规范调用
const res = await request({
url: '/shangpin/fenhonghq',
method: 'POST',
- data: {
- page: dangqianYe,
- page_size: MEIYE_TIAOSHU // 使用统一常量
- }
+ data: { page: dangqianYe, page_size: MEIYE_TIAOSHU_GUANSHI },
});
-
- // 处理返回数据
+
if (res.data.code === 200) {
const data = res.data.data || {};
- const newList = data.list || [];
- const total = data.total || 0;
-
- // 处理头像URL拼接
- const processedList = this.chuliTouxiangURL(newList);
-
- // 计算是否有更多数据
- const hasMoreData = processedList.length === MEIYE_TIAOSHU;
-
- // 更新数据
+ const newList = this.chuliTouxiangURL(data.list || []);
+ const hasMore = newList.length === MEIYE_TIAOSHU_GUANSHI;
+ const loadedTabs = { ...this.data.loadedTabs, guanshi: true };
this.setData({
- dashouList: chushihua ? processedList : [...this.data.dashouList, ...processedList],
- zongTiaoshu: total,
+ guanshiList: reset ? newList : [...this.data.guanshiList, ...newList],
+ guanshiTotal: data.total || 0,
chongzhiDashouShuliang: data.chongzhi_dashou_shuliang || 0,
- meiyouGengduo: !hasMoreData,
- dangqianYe: chushihua ? 2 : this.data.dangqianYe + 1
+ guanshiHasMore: hasMore,
+ guanshiPage: reset ? 2 : dangqianYe + 1,
+ loadedTabs,
});
-
- // 如果数据为空,显示空状态
- if (chushihua && processedList.length === 0) {
- wx.showToast({
- title: '暂无数据',
- icon: 'none',
- duration: 1500
- });
- }
-
- // 如果加载了数据,给个提示
- if (processedList.length > 0) {
- if (chushihua) {
- wx.showToast({
- title: `已加载${processedList.length}条记录`,
- icon: 'success',
- duration: 1000
- });
- }
- }
} else {
- this.setData({
- cuowuTishi: res.data.msg || '数据加载失败'
- });
- wx.showToast({
- title: res.data.msg || '加载失败',
- icon: 'none',
- duration: 2000
- });
+ this.setData({ cuowuTishi: res.data.msg || '数据加载失败' });
}
- } catch (error) {
- console.error('加载数据失败:', error);
- this.setData({
- cuowuTishi: '网络错误,请检查网络连接'
- });
- wx.showToast({
- title: '网络错误',
- icon: 'none',
- duration: 2000
- });
+ } catch (e) {
+ console.error('管事分佣加载失败', e);
+ this.setData({ cuowuTishi: '网络错误,请检查网络连接' });
} finally {
- this.setData({
- jiazaiZhong: false,
- jiazaiGengduo: false
- });
+ this.setData({ jiazaiZhong: false, jiazaiGengduo: false });
+ }
+ },
+
+ async _loadZuzhang(reset) {
+ if (this.data.jiazaiZhong || this.data.jiazaiGengduo) return;
+ const page = reset ? 1 : this.data.zuzhangPage;
+ if (!reset && !this.data.zuzhangHasMore) return;
+
+ this.setData({
+ jiazaiZhong: reset,
+ jiazaiGengduo: !reset,
+ cuowuTishi: '',
+ });
+
+ try {
+ const res = await request({
+ url: '/shangpin/zuzhangfenhong',
+ method: 'POST',
+ data: { page, page_size: PAGE_SIZE_ZUZHANG },
+ });
+
+ if (res.data.code === 200) {
+ const data = res.data.data || {};
+ const processedList = this.processZuzhangList(data.list || []);
+ const loadedTabs = { ...this.data.loadedTabs, zuzhang: true };
+ if (reset) {
+ this.setData({
+ fenhongZonge: data.fenhong_zonge || '0.00',
+ yaoqingGuanshi: data.yaoqing_guanshi || 0,
+ fenhongCishu: data.fenhong_cishu || 0,
+ zuzhangList: processedList,
+ zuzhangTotal: data.total || 0,
+ zuzhangPage: 2,
+ zuzhangHasMore: processedList.length === PAGE_SIZE_ZUZHANG,
+ loadedTabs,
+ });
+ } else {
+ const newList = [...this.data.zuzhangList, ...processedList];
+ this.setData({
+ zuzhangList: newList,
+ zuzhangPage: page + 1,
+ zuzhangHasMore: processedList.length === PAGE_SIZE_ZUZHANG,
+ loadedTabs,
+ });
+ }
+ } else {
+ this.setData({ cuowuTishi: res.data.msg || '数据加载失败' });
+ }
+ } catch (e) {
+ console.error('组长分红加载失败', e);
+ this.setData({ cuowuTishi: '网络错误,请检查网络连接' });
+ } finally {
+ this.setData({ jiazaiZhong: false, jiazaiGengduo: false });
}
},
- // 处理头像URL拼接
chuliTouxiangURL(list) {
const app = getApp();
const ossUrl = app.globalData.ossImageUrl || '';
-
- return list.map(item => {
- // 确保有头像URL,如果没有则使用默认头像
+ return list.map((item) => {
let touxiangUrl = item.avatar || '';
if (touxiangUrl && !touxiangUrl.startsWith('http')) {
touxiangUrl = ossUrl + touxiangUrl;
}
-
- // 格式化时间
let shijian = item.create_time || '';
if (shijian) {
- // 如果是时间戳,转换为日期格式
if (/^\d+$/.test(shijian)) {
- const date = new Date(parseInt(shijian));
- shijian = `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
+ const date = new Date(parseInt(shijian, 10));
+ shijian = `${date.getMonth() + 1}月${date.getDate()}日 ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
} else {
- // 如果是字符串,提取日期和时间
try {
const dateObj = new Date(shijian);
- shijian = `${dateObj.getMonth() + 1}月${dateObj.getDate()}日 ${dateObj.getHours().toString().padStart(2, '0')}:${dateObj.getMinutes().toString().padStart(2, '0')}`;
- } catch (e) {
+ shijian = `${dateObj.getMonth() + 1}月${dateObj.getDate()}日 ${String(dateObj.getHours()).padStart(2, '0')}:${String(dateObj.getMinutes()).padStart(2, '0')}`;
+ } catch (err) {
shijian = shijian.substring(0, 10);
}
}
}
-
return {
...item,
touxiangUrl: touxiangUrl || '/images/default-avatar.png',
- shijian: shijian,
- fenhong: parseFloat(item.fenhong || 0).toFixed(2)
+ shijian,
+ fenhong: parseFloat(item.fenhong || 0).toFixed(2),
};
});
},
- // 刷新数据(带防重复点击)
- shuaxinShuju() {
- // 检查是否在冷却中
- if (this.data.shuaxinKezhi) {
- wx.showToast({
- title: `请等待${this.data.shuaxinCd/1000}秒`,
- icon: 'none',
- duration: 1000
- });
- return;
- }
-
- // 设置冷却状态
- this.setData({ shuaxinKezhi: true });
-
- // 显示刷新动画
- this.setData({
- jiazaiZhong: true
- });
-
- // 刷新数据
- this.jiazaiShuju(true).finally(() => {
- // 2秒后恢复按钮可点击
- setTimeout(() => {
- this.setData({ shuaxinKezhi: false });
- }, this.data.shuaxinCd);
- });
+ processZuzhangList(list) {
+ const app = getApp();
+ const ossUrl = app.globalData.ossImageUrl || '';
+ const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
+ return list.map((item) => ({
+ dashouAvatar: this.getFullUrl(item.dashou_avatar, ossUrl, defaultAvatar),
+ dashouNicheng: item.dashou_nicheng || '接单员',
+ dashouYonghuid: item.dashou_yonghuid || '',
+ guanshiAvatar: this.getFullUrl(item.guanshi_avatar, ossUrl, defaultAvatar),
+ guanshiNicheng: item.guanshi_nicheng || '管事',
+ guanshiYonghuid: item.guanshi_yonghuid || '',
+ fenhong: parseFloat(item.fenhong || 0).toFixed(2),
+ shijian: this.formatTime(item.create_time),
+ }));
},
- // 上拉加载更多
- shanglaJiazai() {
- // 没有更多数据时不再请求
- if (this.data.meiyouGengduo) {
- wx.showToast({
- title: '已经到底了',
- icon: 'none',
- duration: 1000
- });
- return;
- }
-
- // 如果正在加载,不再请求
- if (this.data.jiazaiGengduo || this.data.jiazaiZhong) {
- return;
- }
-
- this.jiazaiShuju(false);
+ getFullUrl(relativePath, ossUrl, defaultUrl) {
+ if (!relativePath) return defaultUrl;
+ if (relativePath.startsWith('http')) return relativePath;
+ return ossUrl + (relativePath.startsWith('/') ? relativePath : `/${relativePath}`) || defaultUrl;
},
- // 重试加载
- chongshiJiazai() {
- this.setData({
- cuowuTishi: '',
- meiyouGengduo: false
- });
- this.jiazaiShuju(true);
- }
-});
\ No newline at end of file
+ formatTime(timestamp) {
+ if (!timestamp) return '';
+ try {
+ const date = new Date(timestamp);
+ return `${date.getMonth() + 1}月${date.getDate()}日 ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
+ } catch (e) {
+ return String(timestamp).substring(0, 10) || '';
+ }
+ },
+});
diff --git a/pages/recharge-log/recharge-log.json b/pages/recharge-log/recharge-log.json
index ea59dc7..15af151 100644
--- a/pages/recharge-log/recharge-log.json
+++ b/pages/recharge-log/recharge-log.json
@@ -1,11 +1,11 @@
{
- "usingComponents": {
- "global-notification": "/components/global-notification/global-notification"
- },
- "navigationBarTitleText": "会员记录",
- "navigationBarBackgroundColor": "#0a0a0f",
- "navigationBarTextStyle": "white",
- "backgroundColor": "#0a0a0f",
- "backgroundTextStyle": "light",
- "enablePullDownRefresh": false
- }
\ No newline at end of file
+ "usingComponents": {
+ "global-notification": "/components/global-notification/global-notification"
+ },
+ "navigationBarTitleText": "佣金记录",
+ "navigationBarBackgroundColor": "#f7dc51",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#fff8e1",
+ "backgroundTextStyle": "dark",
+ "enablePullDownRefresh": false
+}
diff --git a/pages/recharge-log/recharge-log.wxml b/pages/recharge-log/recharge-log.wxml
index 9131036..fddc37d 100644
--- a/pages/recharge-log/recharge-log.wxml
+++ b/pages/recharge-log/recharge-log.wxml
@@ -1,119 +1,191 @@
-
+
-
-
-
-
-
- 分红总额
- ¥{{fenyongzonge}}
- 累计收益
-
+
+
+ {{item.label}}
+
-
-
-
- {{yaoqingzongshu}}
- 邀请接单员
+
+
+
+ 分红总额
+ ¥{{fenyongzonge}}
+ 累计管事分佣收益
+
+
+
+ {{yaoqingzongshu}}
+ 邀请接单员
-
-
-
-
- {{chongzhiDashouShuliang}}
- 充值接单员
+
+
+ {{chongzhiDashouShuliang}}
+ 充值接单员
-
-
- ↻
+
+
+
+
+ 分红总额
+ ¥{{fenhongZonge}}
+
+
+
+ 邀请管事
+ {{yaoqingGuanshi}}
+
+
+
+ 分红次数
+ {{fenhongCishu}}
+
+
+
+
+
+
+ 接单佣金明细
+ 已完成 / 已结算订单的分佣记录
+
+
+
+ ↻
-
-
-
-
-
-
- 加载中...
+ scroll-top="{{scrollTop}}"
+ bindscrolltolower="shanglaJiazai"
+ >
+
+
+
+ 加载中...
-
-
-
- 🚀
- 暂无会员记录
- 快去邀请接单员吧
- 点击刷新
+
+
+ 加载中...
+
+
+
+ 加载中...
-
-
-
-
- 充值记录
- ({{dashouList.length}}/{{zongTiaoshu}})
+
+
+
+ 📋
+ 暂无佣金记录
+ 完成订单后将在此展示
+ 刷新
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 佣金明细
+ {{dashouCommissionList.length}}条
+
+
+
+
+ {{item.title}}
+ {{item.time}}
+ +¥{{item.amount}}
+
+
+
+
+
+
-
-
- {{item.nicheng}}
- ID: {{item.yonghuid}}
+
+
+
+ 🚀
+ 暂无分佣记录
+ 邀请接单员充值后将获得分佣
+ 刷新
+
+
+
+ 分佣明细
+ {{guanshiList.length}}/{{guanshiTotal}}
+
+
+
+
+
+ {{item.nicheng}}
+ ID: {{item.yonghuid}} · {{item.shijian}}
-
-
-
-
- +
- ¥{{item.fenhong}}
-
- {{item.shijian}}
+
+ +¥{{item.fenhong}}
-
-
-
-
-
-
- 加载更多中...
-
-
-
-
- ✓
- 已经到底了,共{{dashouList.length}}条记录
+
+
+
+
+
+
+
+
+
+ 📭
+ 暂无分红记录
+ 邀请管事并让接单员充值即可获得分红
+ 刷新
+
+
+ 分红明细
+ {{zuzhangList.length}}/{{zuzhangTotal}}
+
+
+
+
+
+
+ {{item.dashouNicheng}}
+ ID: {{item.dashouYonghuid}}
+
+
+
+ 所属管事
+ →
+
+
+
+
+ {{item.guanshiNicheng}}
+ +¥{{item.fenhong}}
+ {{item.shijian}}
+
+
+
+
+
+
+
-
-
- ⚠️
- {{cuowuTishi}}
- 重试加载
+
+ {{cuowuTishi}}
+ 重试
diff --git a/pages/recharge-log/recharge-log.wxss b/pages/recharge-log/recharge-log.wxss
index 4ad0790..e3b8a5f 100644
--- a/pages/recharge-log/recharge-log.wxss
+++ b/pages/recharge-log/recharge-log.wxss
@@ -1,506 +1,420 @@
-/* 管事会员记录页面样式 - 赛博风格 */
-
-/* 页面容器 */
+/* 佣金记录 - 逍遥梦黄色风格 */
page {
- height: 100%;
- background: #0a0a0f;
- }
-
- .page-container {
- height: 100%;
- background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 50%, #16213e 100%);
- position: relative;
- }
-
- /* 固定顶部区域 */
- .fixed-top {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- z-index: 100;
- background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 100%);
- padding-bottom: 20rpx;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.3);
- }
-
- /* 顶部统计区域 - 赛博卡片设计 */
- .tongji-quyu {
- position: relative;
- margin: 20rpx 30rpx 0;
- padding: 40rpx 30rpx;
- background: rgba(20, 20, 35, 0.9);
- border-radius: 24rpx;
- border: 1px solid rgba(100, 255, 255, 0.1);
- box-shadow:
- 0 10rpx 30rpx rgba(0, 0, 0, 0.4),
- 0 0 20rpx rgba(100, 255, 255, 0.05) inset,
- 0 0 0 1px rgba(100, 255, 255, 0.1);
- backdrop-filter: blur(10px);
- overflow: hidden;
- }
-
- .tongji-bg {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background:
- linear-gradient(45deg,
- rgba(100, 255, 255, 0.03) 0%,
- rgba(255, 100, 255, 0.03) 100%);
- z-index: 0;
- }
-
- /* 分红总额样式 - 赛博霓虹效果 */
- .fenyong-zonge {
- position: relative;
- text-align: center;
- padding: 20rpx 0 30rpx;
- margin-bottom: 25rpx;
- border-bottom: 1px solid rgba(100, 255, 255, 0.1);
- z-index: 1;
- }
-
- .zonge-label {
- font-size: 26rpx;
- color: rgba(255, 255, 255, 0.7);
- margin-bottom: 15rpx;
- text-transform: uppercase;
- letter-spacing: 2rpx;
- }
-
- .zonge-value {
- font-size: 60rpx;
- font-weight: 800;
- color: #00ffea;
- margin-bottom: 8rpx;
- text-shadow:
- 0 0 10rpx rgba(0, 255, 234, 0.5),
- 0 0 20rpx rgba(0, 255, 234, 0.3);
- font-family: 'Arial', sans-serif;
- }
-
- .zonge-tip {
- font-size: 22rpx;
- color: rgba(255, 255, 255, 0.5);
- }
-
- /* 底部统计信息 */
- .tongji-bottom {
- display: flex;
- justify-content: space-around;
- align-items: center;
- z-index: 1;
- position: relative;
- }
-
- .tongji-item {
- text-align: center;
- flex: 1;
- }
-
- .tongji-number {
- font-size: 40rpx;
- font-weight: 700;
- color: #ffffff;
- margin-bottom: 6rpx;
- text-shadow: 0 0 10rpx rgba(255, 255, 255, 0.3);
- }
-
- .tongji-label {
- font-size: 24rpx;
- color: rgba(255, 255, 255, 0.6);
- }
-
- .tongji-divider {
- width: 1px;
- height: 45rpx;
- background: linear-gradient(to bottom,
- transparent 0%,
- rgba(100, 255, 255, 0.3) 50%,
- transparent 100%);
- }
-
- /* 刷新按钮 - 固定在右上角 */
- .shuaxin-anniu {
- position: absolute;
- top: 60rpx;
- right: 60rpx;
- z-index: 200;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 70rpx;
- height: 70rpx;
- background: rgba(20, 20, 35, 0.95);
- border-radius: 50%;
- border: 1px solid rgba(100, 255, 255, 0.2);
- box-shadow:
- 0 8rpx 20rpx rgba(0, 0, 0, 0.4),
- 0 0 20rpx rgba(100, 255, 255, 0.1);
- backdrop-filter: blur(10px);
- transition: all 0.3s ease;
- }
-
- .shuaxin-anniu:active {
- transform: scale(0.95);
- background: rgba(100, 255, 255, 0.1);
- box-shadow:
- 0 4rpx 10rpx rgba(0, 0, 0, 0.3),
- 0 0 30rpx rgba(100, 255, 255, 0.2);
- }
-
- .shuaxin-icon {
- font-size: 32rpx;
- color: #00ffea;
- transition: all 0.3s ease;
- }
-
- .shuaxin-disabled {
- color: rgba(255, 255, 255, 0.3);
- animation: rotate 1s linear infinite;
- }
-
- @keyframes rotate {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
-
- /* 滚动区域 - 只包裹列表部分 */
- .scroll-area {
- position: fixed;
- top: 340rpx; /* 根据固定区域高度调整 */
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 50;
- }
-
- /* 全局加载状态 */
- .jiazai-quanju {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 120rpx 0;
- }
-
- .jiazai-spinner {
- width: 80rpx;
- height: 80rpx;
- border: 4rpx solid rgba(100, 255, 255, 0.1);
- border-top: 4rpx solid #00ffea;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin-bottom: 30rpx;
- box-shadow: 0 0 20rpx rgba(0, 255, 234, 0.3);
- }
-
- @keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
-
- .jiazai-text {
- font-size: 28rpx;
- color: rgba(255, 255, 255, 0.7);
- }
-
- /* 空数据提示 */
- .kong-shuju {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 120rpx 30rpx;
- background: rgba(20, 20, 35, 0.5);
- border-radius: 24rpx;
- border: 1px solid rgba(100, 255, 255, 0.1);
- margin: 40rpx 30rpx 0;
- }
-
- .kong-icon {
- font-size: 100rpx;
- margin-bottom: 30rpx;
- color: rgba(255, 255, 255, 0.2);
- }
-
- .kong-text {
- font-size: 32rpx;
- color: rgba(255, 255, 255, 0.8);
- margin-bottom: 10rpx;
- font-weight: 500;
- }
-
- .kong-tip {
- font-size: 26rpx;
- color: rgba(255, 255, 255, 0.5);
- margin-bottom: 50rpx;
- }
-
- .kong-btn {
- padding: 20rpx 50rpx;
- background: linear-gradient(90deg, #00ffea 0%, #0088ff 100%);
- color: #000;
- border-radius: 50rpx;
- font-size: 28rpx;
- font-weight: 600;
- box-shadow: 0 8rpx 20rpx rgba(0, 255, 234, 0.3);
- }
-
- .kong-btn:active {
- transform: scale(0.95);
- box-shadow: 0 4rpx 10rpx rgba(0, 255, 234, 0.2);
- }
-
- /* 列表标题 */
- .list-title {
- margin: 0 30rpx 20rpx;
- display: flex;
- align-items: baseline;
- }
-
- .title-text {
- font-size: 32rpx;
- color: #ffffff;
- font-weight: 600;
- margin-right: 10rpx;
- text-shadow: 0 0 10rpx rgba(255, 255, 255, 0.2);
- }
-
- .title-count {
- font-size: 24rpx;
- color: rgba(255, 255, 255, 0.5);
- }
-
- /* 卡片列表 */
- .card-list {
- margin: 0 30rpx;
- }
-
- /* 打手卡片 - 赛博风格设计 */
- .dashou-card {
- position: relative;
- display: flex;
- align-items: center;
- padding: 30rpx;
- margin-bottom: 20rpx;
- background: rgba(20, 20, 35, 0.7);
- border-radius: 20rpx;
- border: 1px solid rgba(100, 255, 255, 0.1);
- box-shadow:
- 0 8rpx 24rpx rgba(0, 0, 0, 0.3),
- 0 0 0 1px rgba(100, 255, 255, 0.05);
- transition: all 0.3s ease;
- }
-
- .dashou-card:active {
- transform: translateY(-2rpx);
- background: rgba(30, 30, 50, 0.8);
- box-shadow:
- 0 12rpx 30rpx rgba(0, 0, 0, 0.4),
- 0 0 20rpx rgba(100, 255, 255, 0.1);
- }
-
- /* 头像区域 - 纯圆形 */
- .touxiang-quyu {
- position: relative;
- margin-right: 30rpx;
- flex-shrink: 0;
- }
-
- .dashou-touxiang {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50%; /* 确保是纯圆形 */
- z-index: 2;
- position: relative;
- }
-
- .touxiang-border {
- position: absolute;
- top: -4rpx;
- left: -4rpx;
- width: 108rpx;
- height: 108rpx;
- border-radius: 50%;
- background: linear-gradient(45deg, #00ffea, #ff00ff);
- z-index: 1;
- opacity: 0.3;
- animation: borderGlow 2s linear infinite;
- }
-
- @keyframes borderGlow {
- 0%, 100% { opacity: 0.3; }
- 50% { opacity: 0.6; }
- }
-
- /* 信息区域 */
- .xinxi-quyu {
- flex: 1;
- min-width: 0; /* 防止内容撑开 */
- }
-
- .nicheng {
- font-size: 32rpx;
- font-weight: 600;
- color: #ffffff;
- margin-bottom: 10rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-shadow: 0 0 10rpx rgba(255, 255, 255, 0.2);
- }
-
- .dashou-id {
- font-size: 24rpx;
- color: rgba(255, 255, 255, 0.5);
- letter-spacing: 1rpx;
- }
-
- /* 分红金额区域 */
- .fenhong-quyu {
- text-align: right;
- flex-shrink: 0;
- min-width: 180rpx;
- }
-
- .fenhong-value {
- margin-bottom: 8rpx;
- }
-
- .fenhong-jiahao {
- font-size: 26rpx;
- color: #00ff00;
- margin-right: 4rpx;
- }
-
- .fenhong-shuzi {
- font-size: 32rpx;
- font-weight: 700;
- color: #00ff00;
- text-shadow: 0 0 10rpx rgba(0, 255, 0, 0.5);
- }
-
- .shijian {
- font-size: 22rpx;
- color: rgba(255, 255, 255, 0.4);
- }
-
- /* 加载更多提示 */
- .jiazai-gengduo {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 40rpx 0 60rpx;
- margin: 0 30rpx;
- }
-
- .gengduo-spinner {
- width: 40rpx;
- height: 40rpx;
- border: 3rpx solid rgba(100, 255, 255, 0.1);
- border-top: 3rpx solid #00ffea;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin-bottom: 20rpx;
- }
-
- .gengduo-text {
- font-size: 26rpx;
- color: rgba(255, 255, 255, 0.6);
- }
-
- /* 没有更多数据 */
- .meiyou-gengduo {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 50rpx 0 80rpx;
- margin: 0 30rpx;
- color: rgba(255, 255, 255, 0.4);
- }
-
- .meiyou-icon {
- width: 60rpx;
- height: 60rpx;
- border-radius: 50%;
- background: rgba(0, 255, 234, 0.1);
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 32rpx;
- color: #00ffea;
- margin-bottom: 20rpx;
- border: 1px solid rgba(0, 255, 234, 0.2);
- }
-
- .meiyou-text {
- font-size: 26rpx;
- text-align: center;
- }
-
- /* 错误提示 */
- .cuowu-quyu {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 100rpx 30rpx;
- background: rgba(40, 20, 20, 0.8);
- border-radius: 24rpx;
- border: 1px solid rgba(255, 100, 100, 0.2);
- margin: 40rpx 30rpx 0;
- }
-
- .cuowu-icon {
- font-size: 80rpx;
- color: #ff5555;
- margin-bottom: 30rpx;
- text-shadow: 0 0 20rpx rgba(255, 85, 85, 0.5);
- }
-
- .cuowu-text {
- font-size: 30rpx;
- color: rgba(255, 255, 255, 0.9);
- margin-bottom: 40rpx;
- text-align: center;
- line-height: 1.5;
- }
-
- .cuowu-btn {
- padding: 20rpx 50rpx;
- background: linear-gradient(90deg, #a855f7 0%, #7c3aed 100%);
- color: #fff;
- border-radius: 50rpx;
- font-size: 28rpx;
- font-weight: 600;
- box-shadow: 0 8rpx 20rpx rgba(255, 85, 85, 0.3);
- }
-
- .cuowu-btn:active {
- transform: scale(0.95);
- box-shadow: 0 4rpx 10rpx rgba(255, 85, 85, 0.2);
- }
+ height: 100%;
+ background: #fff8e1;
+}
+.page-container {
+ height: 100%;
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 18%, #fff8e1 100%);
+ position: relative;
+}
+.fixed-top {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ padding: 16rpx 24rpx 20rpx;
+ background: linear-gradient(180deg, #f7dc51 0%, #ffd061 85%, #fff8e1 100%);
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.06);
+}
+.tab-bar {
+ display: flex;
+ background: rgba(255, 255, 255, 0.75);
+ border-radius: 999rpx;
+ padding: 6rpx;
+ margin-bottom: 20rpx;
+}
+
+.tab-item {
+ flex: 1;
+ text-align: center;
+ padding: 16rpx 8rpx;
+ font-size: 26rpx;
+ color: #666;
+ border-radius: 999rpx;
+ transition: all 0.2s;
+}
+
+.tab-item.active {
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ font-weight: 700;
+ box-shadow: 0 4rpx 12rpx rgba(250, 180, 80, 0.35);
+}
+
+.stats-card {
+ background: #fef6d4;
+ border-radius: 24rpx;
+ padding: 28rpx 24rpx;
+ border: 2rpx solid rgba(255, 255, 255, 0.8);
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+}
+
+.stats-main {
+ text-align: center;
+ padding-bottom: 20rpx;
+ margin-bottom: 20rpx;
+ border-bottom: 1rpx solid rgba(0, 0, 0, 0.06);
+}
+
+.stats-label,
+.stats-label-sm {
+ display: block;
+ font-size: 24rpx;
+ color: #888;
+ margin-bottom: 8rpx;
+}
+
+.stats-amount {
+ display: block;
+ font-size: 52rpx;
+ font-weight: 800;
+ color: #e65100;
+ line-height: 1.2;
+}
+
+.stats-amount-sm {
+ display: block;
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #e65100;
+}
+
+.stats-tip {
+ display: block;
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 6rpx;
+}
+
+.stats-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.stats-row.three .stats-cell {
+ flex: 1;
+ text-align: center;
+}
+
+.stats-cell {
+ text-align: center;
+ flex: 1;
+}
+
+.stats-num {
+ display: block;
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #333;
+}
+
+.stats-sub {
+ display: block;
+ font-size: 22rpx;
+ color: #888;
+ margin-top: 4rpx;
+}
+
+.stats-divider {
+ width: 1rpx;
+ height: 48rpx;
+ background: rgba(0, 0, 0, 0.08);
+}
+
+.dashou-hd {
+ text-align: center;
+ padding: 32rpx 24rpx;
+}
+
+.dashou-title {
+ display: block;
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #333;
+}
+
+.dashou-sub {
+ display: block;
+ font-size: 24rpx;
+ color: #888;
+ margin-top: 8rpx;
+}
+
+.refresh-btn {
+ position: absolute;
+ top: 20rpx;
+ right: 36rpx;
+ width: 64rpx;
+ height: 64rpx;
+ background: rgba(255, 255, 255, 0.9);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+}
+
+.refresh-icon {
+ font-size: 32rpx;
+ color: #e65100;
+}
+
+.refresh-icon.spin {
+ animation: spin 1s linear infinite;
+ opacity: 0.5;
+}
+
+@keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
-/* 调整滚动区域的顶部距离,增加间隔 */
.scroll-area {
- position: fixed;
- top: 400rpx; /* 从 340rpx 增加到 360rpx,增加20rpx的间隔 */
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 50;
- }
-
- /* 如果觉得还不够,可以再增加列表标题的上边距 */
- .list-title {
- margin: 10rpx 30rpx 20rpx; /* 从 0 30rpx 20rpx 改为 10rpx 30rpx 20rpx */
- display: flex;
- align-items: baseline;
- }
\ No newline at end of file
+ position: fixed;
+ top: 280rpx;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 50;
+}
+
+.scroll-area.has-tabs.dashou { top: 300rpx; }
+.scroll-area.has-tabs.guanshi { top: 420rpx; }
+.scroll-area.has-tabs.zuzhang { top: 320rpx; }
+.scroll-area.guanshi:not(.has-tabs) { top: 400rpx; }
+.scroll-area.zuzhang:not(.has-tabs) { top: 300rpx; }
+
+.state-box,
+.empty-box {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 80rpx 40rpx;
+ margin: 24rpx;
+ background: #fff;
+ border-radius: 24rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+}
+
+.spinner {
+ width: 64rpx;
+ height: 64rpx;
+ border: 4rpx solid #ffe082;
+ border-top-color: #e65100;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ margin-bottom: 20rpx;
+}
+
+.spinner.sm {
+ width: 36rpx;
+ height: 36rpx;
+ margin-bottom: 0;
+ margin-right: 12rpx;
+}
+
+.empty-icon {
+ font-size: 72rpx;
+ margin-bottom: 16rpx;
+}
+
+.empty-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8rpx;
+}
+
+.empty-tip {
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 32rpx;
+ text-align: center;
+}
+
+.empty-btn {
+ padding: 16rpx 48rpx;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ font-size: 28rpx;
+ font-weight: 600;
+ border-radius: 999rpx;
+}
+
+.list-hd {
+ display: flex;
+ align-items: baseline;
+ margin: 8rpx 24rpx 16rpx;
+}
+
+.list-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #333;
+ margin-right: 12rpx;
+}
+
+.list-count {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.record-list {
+ padding: 0 24rpx 40rpx;
+}
+
+.record-card {
+ display: flex;
+ align-items: center;
+ padding: 24rpx;
+ margin-bottom: 16rpx;
+ background: #fff;
+ border-radius: 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+}
+
+.record-card.avatar-card .avatar {
+ width: 88rpx;
+ height: 88rpx;
+ border-radius: 50%;
+ margin-right: 20rpx;
+ flex-shrink: 0;
+ background: #eee;
+}
+
+.record-main {
+ flex: 1;
+ min-width: 0;
+}
+
+.record-title {
+ display: block;
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.record-time {
+ display: block;
+ font-size: 22rpx;
+ color: #999;
+ margin-top: 6rpx;
+}
+
+.record-amt {
+ font-size: 30rpx;
+ font-weight: 700;
+ flex-shrink: 0;
+}
+
+.record-amt.plus {
+ color: #2e7d32;
+}
+
+.amt-col {
+ text-align: right;
+}
+
+.bonus-card {
+ display: flex;
+ align-items: center;
+ padding: 20rpx;
+ margin-bottom: 16rpx;
+ background: #fff;
+ border-radius: 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+}
+
+.bonus-left,
+.bonus-right {
+ display: flex;
+ align-items: center;
+ flex: 1;
+ min-width: 0;
+}
+
+.bonus-right {
+ flex-direction: row;
+ justify-content: flex-end;
+}
+
+.avatar.sm {
+ width: 64rpx;
+ height: 64rpx;
+ border-radius: 50%;
+ margin-right: 12rpx;
+ flex-shrink: 0;
+ background: #eee;
+}
+
+.bonus-info {
+ min-width: 0;
+ flex: 1;
+}
+
+.bonus-mid {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 0 8rpx;
+ flex-shrink: 0;
+}
+
+.bonus-tag {
+ font-size: 20rpx;
+ color: #999;
+}
+
+.bonus-arrow {
+ font-size: 24rpx;
+ color: #e65100;
+}
+
+.footer-tip {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 24rpx;
+ font-size: 24rpx;
+ color: #999;
+}
+
+.footer-tip.muted {
+ padding-bottom: 60rpx;
+}
+
+.error-bar {
+ position: fixed;
+ bottom: 40rpx;
+ left: 24rpx;
+ right: 24rpx;
+ z-index: 200;
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 20rpx 24rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
+ font-size: 26rpx;
+ color: #666;
+}
+
+.error-btn {
+ padding: 10rpx 28rpx;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ font-size: 24rpx;
+ font-weight: 600;
+ border-radius: 999rpx;
+}
diff --git a/pages/staff-join/staff-join.wxss b/pages/staff-join/staff-join.wxss
index dfe251e..63a6da0 100644
--- a/pages/staff-join/staff-join.wxss
+++ b/pages/staff-join/staff-join.wxss
@@ -3,6 +3,6 @@
.title { display: block; font-size: 36rpx; font-weight: 600; color: #333; margin-bottom: 16rpx; }
.desc { display: block; font-size: 26rpx; color: #666; line-height: 1.6; margin-bottom: 32rpx; }
.input { border: 1px solid #ddd; border-radius: 12rpx; padding: 24rpx; font-size: 30rpx; margin-bottom: 32rpx; }
-.btn { background: #9333ea; color: #fff; border-radius: 12rpx; }
+.btn { background: #C9A962; color: #fff; border-radius: 12rpx; }
.tips { margin-top: 32rpx; font-size: 24rpx; color: #999; line-height: 2; }
.tips text { display: block; }
diff --git a/pages/verify/verify.wxss b/pages/verify/verify.wxss
index 7f25bac..277408d 100644
--- a/pages/verify/verify.wxss
+++ b/pages/verify/verify.wxss
@@ -47,7 +47,7 @@ page {
width: 100%;
height: 96rpx;
line-height: 96rpx;
- background: linear-gradient(135deg, #9333ea, #a855f7);
+ background: linear-gradient(135deg, #C9A962, #D4B56A);
color: #fff;
font-size: 34rpx;
font-weight: 600;
@@ -58,7 +58,7 @@ page {
.kefu-link {
margin-top: 30rpx;
font-size: 28rpx;
- color: #9333ea;
+ color: #C9A962;
text-decoration: underline;
}
@@ -69,7 +69,7 @@ page {
.done-icon {
font-size: 80rpx;
- color: #9333ea;
+ color: #C9A962;
margin-bottom: 30rpx;
font-weight: bold;
}
@@ -86,7 +86,7 @@ page {
}
.highlight {
- color: #9333ea;
+ color: #C9A962;
font-weight: 700;
font-size: 36rpx;
}
\ No newline at end of file
diff --git a/pages/withdraw/components/mode1/mode1.js b/pages/withdraw/components/mode1/mode1.js
index 8f702a7..4bc9d01 100644
--- a/pages/withdraw/components/mode1/mode1.js
+++ b/pages/withdraw/components/mode1/mode1.js
@@ -1,484 +1,440 @@
-// pages/withdraw/withdraw.js
-// 子组件版本 - 完整代码,仅适配生命周期,业务逻辑不动
-
+// pages/withdraw/components/mode1/mode1.js — 收款码手动审核纯提现
import request from '../../../../utils/request.js';
import upload from '../../../../utils/upload.js';
import PopupService from '../../../../services/popupService.js';
const app = getApp();
-const PAGE_SIZE = 10;
-let lastPullDownTime = 0;
-const PULL_DOWN_INTERVAL = 2000;
+
+const ASSET_TYPES = {
+ dashou_yue: { leixing: 1, label: '接单员佣金' },
+ dashou_yajin: { leixing: 5, label: '接单员保证金' },
+ shangjia_yue: { leixing: 6, label: '商家余额' },
+ guanshi_fenyong: { leixing: 2, label: '管事分红' },
+ zuzhang_fenyong: { leixing: 3, label: '组长分红' },
+ kaoheguan_fenyong: { leixing: 4, label: '考核官分佣' },
+};
+
+const FROM_ASSET_MAP = {
+ dashou: 'dashou_yue',
+ guanshi: 'guanshi_fenyong',
+ zuzhang: 'zuzhang_fenyong',
+ kaoheguan: 'kaoheguan_fenyong',
+ kaohe: 'kaoheguan_fenyong',
+ shangjia: 'shangjia_yue',
+ yajin: 'dashou_yajin',
+};
Component({
- data: {
- imgUrls: {
- pageBg: '',
- cardBg: '',
- iconWechat: '',
- iconAlipay: '',
- iconRecord: '',
- iconRefresh: '',
- },
- assetList: [],
- totalAmount: '0.00',
- selectedAsset: null,
- txfangshi: null,
- txdianhua: '',
- txzh: '',
- txtupian: '',
- ossImageUrl: '',
- showTixianModal: false,
- tixianAmount: '',
- shouxufei: '0.00',
- shijidaozhang: '0.00',
- currentRate: '0.00',
- recordList: [],
- page: 1,
- nomore: false,
- loading: false,
- isRefreshing: false,
- canloadmore: true,
- showSkfsModal: false,
- tempTxfangshi: null,
- tempTxPhone: '',
- tempTxAccount: '',
- tempTxImage: '',
- choosingImage: false,
- showModifyModal: false,
- modifyingRecord: null,
- modifyTxfangshi: null,
- modifyTxPhone: '',
- modifyTxAccount: '',
- modifyTxImage: '',
- modifyImageUrl: '',
- showFailModal: false,
- currentFailReason: '',
- isLoading: false,
- },
-
- attached() {
- this.initImageUrls();
- this.loadAllAssets();
- this.loadWithdrawMethod();
- this.loadWithdrawRecords(true);
- },
-
- pageLifetimes: {
- show() {
- this.registerNotification();
- PopupService.checkAndShow(this, 'tixian');
- },
- hide() {
- const popup = this.selectComponent('#popupNotice');
- popup?.cleanup?.();
- }
- },
-
- methods: {
- // 下拉刷新
- onPullDownRefresh() {
- if (this.data.isRefreshing) {
- wx.stopPullDownRefresh();
- return;
- }
- this.setData({ isRefreshing: true });
- this.loadWithdrawRecords(true).then(() => {
- wx.stopPullDownRefresh();
- this.setData({ isRefreshing: false });
- }).catch(() => {
- wx.stopPullDownRefresh();
- this.setData({ isRefreshing: false });
- });
- },
-
- // 底部按钮加载更多
- loadMoreRecords() {
- if (this.data.nomore) {
- wx.showToast({ title: '没有更多记录了', icon: 'none' });
- return;
- }
- if (this.data.loading) return;
- this.loadWithdrawRecords();
- },
-
- initImageUrls() {
- const ossBase = app.globalData.ossImageUrl || '';
- const imgDir = `${ossBase}beijing/tixian/`;
- this.setData({
- imgUrls: {
- pageBg: `${imgDir}page_bg.png`,
- cardBg: `${imgDir}card_bg.png`,
- iconWechat: `${imgDir}icon_wechat.png`,
- iconAlipay: `${imgDir}icon_alipay.png`,
- iconRecord: `${imgDir}icon_record.png`,
- iconRefresh: `${imgDir}icon_refresh.png`,
- assetTileBg: `${imgDir}asset_tile_bg.png`,
- }
- });
- },
-
- async loadAllAssets() {
- this.setData({ isLoading: true });
- try {
- const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' });
- if (res?.data?.code === 200) {
- const data = res.data.data;
- const assets = [];
- if (data.dashou_yue && parseFloat(data.dashou_yue) > 0) {
- assets.push({ type: 'dashou_yue', label: '接单员佣金', amount: data.dashou_yue, rate: data.dashou_rate || 0 });
- }
- if (data.dashou_yajin && parseFloat(data.dashou_yajin) > 0) {
- assets.push({ type: 'dashou_yajin', label: '接单员保证金', amount: data.dashou_yajin, rate: data.dashou_yajin_rate || 0 });
- }
- if (data.shangjia_yue && parseFloat(data.shangjia_yue) > 0) {
- assets.push({ type: 'shangjia_yue', label: '商家余额', amount: data.shangjia_yue, rate: data.shangjia_rate || 0 });
- }
- if (data.guanshi_fenyong && parseFloat(data.guanshi_fenyong) > 0) {
- assets.push({ type: 'guanshi_fenyong', label: '管事分红', amount: data.guanshi_fenyong, rate: data.guanshi_rate || 0 });
- }
- if (data.zuzhang_fenyong && parseFloat(data.zuzhang_fenyong) > 0) {
- assets.push({ type: 'zuzhang_fenyong', label: '组长分红', amount: data.zuzhang_fenyong, rate: data.zuzhang_rate || 0 });
- }
- if (data.kaoheguan_fenyong && parseFloat(data.kaoheguan_fenyong) > 0) {
- assets.push({ type: 'kaoheguan_fenyong', label: '考核官分佣', amount: data.kaoheguan_fenyong, rate: data.kaoheguan_rate || 0 });
- }
- let total = 0;
- assets.forEach(item => { total += parseFloat(item.amount); });
- this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoading: false });
- // 缓存费率
- wx.setStorageSync('dashouRate', data.dashou_rate || 0);
- wx.setStorageSync('dashou_yajin_rate', data.dashou_yajin_rate || 0);
- wx.setStorageSync('shangjia_rate', data.shangjia_rate || 0);
- wx.setStorageSync('guanshi_rate', data.guanshi_rate || 0);
- wx.setStorageSync('zuzhang_rate', data.zuzhang_rate || 0);
- wx.setStorageSync('kaoheguan_rate', data.kaoheguan_rate || 0);
- } else {
- throw new Error(res?.data?.msg || '获取资产失败');
- }
- } catch (err) {
- console.error(err);
- wx.showToast({ title: '加载失败', icon: 'none' });
- this.setData({ isLoading: false });
- }
- },
-
- async loadWithdrawMethod() {
- const txzh = wx.getStorageSync('txzh') || '';
- const txtupian = wx.getStorageSync('txtupian') || '';
- const txfangshi = wx.getStorageSync('txfangshi') || null;
- const txdianhua = wx.getStorageSync('txdianhua') || '';
- if (txzh || txtupian) {
- this.setData({ txzh, txtupian, txfangshi, txdianhua, ossImageUrl: app.globalData.ossImageUrl || '' });
- } else {
- try {
- const res = await request({ url: '/yonghu/tixianhq', method: 'POST' });
- if (res?.data?.code === 0) {
- const data = res.data.data;
- this.setData({
- txzh: data.txzh || '',
- txtupian: data.txtupian || '',
- txfangshi: data.txfangshi || null,
- txdianhua: data.txdianhua || '',
- });
- wx.setStorageSync('txzh', data.txzh || '');
- wx.setStorageSync('txtupian', data.txtupian || '');
- wx.setStorageSync('txfangshi', data.txfangshi || null);
- wx.setStorageSync('txdianhua', data.txdianhua || '');
- }
- } catch (err) {}
- }
- },
-
- onSelectAsset(e) {
- const index = e.currentTarget.dataset.index;
- const asset = this.data.assetList[index];
- if (!asset || parseFloat(asset.amount) <= 0) {
- wx.showToast({ title: '无可提现金额', icon: 'none' });
- return;
- }
- this.setData({
- selectedAsset: asset,
- showTixianModal: true,
+ properties: { options: { type: Object, value: {} } },
+ data: {
+ imgUrls: { iconWechat: '', iconAlipay: '' },
+ assetList: [],
+ displayAssetList: [],
+ totalAmount: '0.00',
+ canWithdraw: false,
+ isLoadingAssets: false,
+ selectedAsset: null,
tixianAmount: '',
+ feeRateText: '--',
+ currentRate: '0%',
shouxufei: '0.00',
shijidaozhang: '0.00',
- currentRate: asset.rate
- });
+ showTixianModal: false,
+ submitting: false,
+ txfangshi: null,
+ txdianhua: '',
+ txzh: '',
+ txtupian: '',
+ showSkfsModal: false,
+ tempTxfangshi: null,
+ tempTxPhone: '',
+ tempTxAccount: '',
+ tempTxImage: '',
+ choosingImage: false,
},
- onAmountInput(e) {
- let val = e.detail.value;
- if (val && !/^\d*\.?\d{0,2}$/.test(val)) return;
- this.setData({ tixianAmount: val });
- if (val && parseFloat(val) > 0) {
- const amount = parseFloat(val);
- const rate = parseFloat(this.data.selectedAsset.rate) || 0;
- const fee = amount * rate;
- const actual = amount - fee;
- this.setData({ shouxufei: fee.toFixed(2), shijidaozhang: actual.toFixed(2) });
- } else {
- this.setData({ shouxufei: '0.00', shijidaozhang: '0.00' });
- }
+ attached() {
+ this.initImageUrls();
+ this.loadAllAssets();
+ this.loadWithdrawMethod();
},
- onQuickAmount(e) {
- const val = e.currentTarget.dataset.value;
- this.setData({ tixianAmount: val.toString() });
- this.onAmountInput({ detail: { value: val.toString() } });
+ pageLifetimes: {
+ show() {
+ this.registerNotification();
+ this.loadAllAssets();
+ PopupService.checkAndShow(this, 'tixian');
+ },
+ hide() {
+ const popup = this.selectComponent('#popupNotice');
+ popup?.cleanup?.();
+ },
},
- async onConfirmWithdraw() {
- const { selectedAsset, tixianAmount, txfangshi, txzh, txtupian, txdianhua } = this.data;
- if (!selectedAsset) { wx.showToast({ title: '请选择提现项目', icon: 'none' }); return; }
- const amount = parseFloat(tixianAmount);
- if (isNaN(amount) || amount <= 0) { wx.showToast({ title: '请输入有效金额', icon: 'none' }); return; }
- if (amount > parseFloat(selectedAsset.amount)) { wx.showToast({ title: '超过可提现金额', icon: 'none' }); return; }
- if (!txfangshi || (!txzh && !txtupian)) {
- wx.showToast({ title: '请先设置收款方式', icon: 'none' });
- this.setData({ showTixianModal: false });
- this.onSetSkfs();
- return;
- }
- let leixing = 1;
- switch (selectedAsset.type) {
- case 'dashou_yue': leixing = 1; break;
- case 'dashou_yajin': leixing = 5; break;
- case 'shangjia_yue': leixing = 6; break;
- case 'guanshi_fenyong': leixing = 2; break;
- case 'zuzhang_fenyong': leixing = 3; break;
- case 'kaoheguan_fenyong': leixing = 4; break;
- }
- let txskfs = 0;
- if (txzh && txtupian) txskfs = 3;
- else if (txzh) txskfs = 1;
- else if (txtupian) txskfs = 2;
- try {
- const res = await request({
- url: '/yonghu/tixian',
- method: 'POST',
- data: { leixing, jine: amount.toFixed(2), fangshi: txfangshi, txskfs }
- });
- if (res?.data?.code === 0) {
- const newAssetList = this.data.assetList.map(item => {
- if (item.type === selectedAsset.type) {
- const newAmount = (parseFloat(item.amount) - amount).toFixed(2);
- return { ...item, amount: newAmount };
+ methods: {
+ formatRatePercent(rate) {
+ const r = parseFloat(rate) || 0;
+ if (r <= 1 && r > 0) return `${(r * 100).toFixed(0)}%`;
+ return `${r}%`;
+ },
+
+ registerNotification() {
+ const comp = this.selectComponent('#global-notification');
+ if (comp?.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => comp.showNotification(data),
+ hide: () => comp.hideNotification(),
+ };
}
- return item;
- });
- let newTotal = 0;
- newAssetList.forEach(item => { newTotal += parseFloat(item.amount); });
- this.setData({ assetList: newAssetList, totalAmount: newTotal.toFixed(2), showTixianModal: false, selectedAsset: null });
- this.loadWithdrawRecords(true);
- wx.showToast({ title: '提现申请已提交', icon: 'success' });
- } else {
- wx.showToast({ title: res?.data?.msg || '提现失败', icon: 'none' });
- }
- } catch (err) {
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
+ },
- onCloseTixianModal() {
- this.setData({ showTixianModal: false, selectedAsset: null, tixianAmount: '' });
- },
+ initImageUrls() {
+ const ossBase = app.globalData.ossImageUrl || '';
+ const imgDir = `${ossBase}beijing/tixian/`;
+ this.setData({
+ imgUrls: {
+ iconWechat: `${imgDir}icon_wechat.png`,
+ iconAlipay: `${imgDir}icon_alipay.png`,
+ },
+ });
+ },
- onSetSkfs() {
- this.setData({
- showSkfsModal: true,
- tempTxfangshi: this.data.txfangshi,
- tempTxPhone: this.data.txdianhua,
- tempTxAccount: this.data.txzh,
- tempTxImage: ''
- });
- },
+ /** 顶部展示:不含保证金的可提现合计 */
+ calcDisplayTotal(assets) {
+ let total = 0;
+ (assets || []).forEach((item) => {
+ if (item.type === 'dashou_yajin') return;
+ total += parseFloat(item.amount) || 0;
+ });
+ return total;
+ },
- onSelectFangshi(e) {
- this.setData({ tempTxfangshi: e.currentTarget.dataset.fangshi });
- },
+ hasAnyWithdrawable(assets) {
+ return (assets || []).some((item) => parseFloat(item.amount) > 0);
+ },
- onPhoneInput(e) { this.setData({ tempTxPhone: e.detail.value }); },
- onAccountInput(e) { this.setData({ tempTxAccount: e.detail.value }); },
-
- onChooseImage() {
- if (this.data.choosingImage) return;
- this.setData({ choosingImage: true });
- wx.chooseMedia({
- count: 1, mediaType: ['image'],
- success: (res) => { this.setData({ tempTxImage: res.tempFiles[0].tempFilePath }); },
- complete: () => { this.setData({ choosingImage: false }); }
- });
- },
-
- onPreviewImage() {
- if (this.data.tempTxImage) wx.previewImage({ urls: [this.data.tempTxImage] });
- },
-
- onDeleteImage() { this.setData({ tempTxImage: '' }); },
-
- async onConfirmSkfs() {
- const { tempTxfangshi, tempTxPhone, tempTxAccount, tempTxImage } = this.data;
- if (!tempTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; }
- if (!tempTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; }
- if (tempTxfangshi == 1 && !tempTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; }
- if (tempTxfangshi == 2 && !tempTxAccount && !tempTxImage) {
- wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return;
- }
- const formData = { txdianhua: tempTxPhone, txzh: tempTxAccount || '' };
- try {
- const res = await upload({ url: '/yonghu/sksc', formData, filePath: tempTxImage || null, fileName: 'file' });
- if (res?.data?.code === 0) {
- const data = res.data.data;
- this.setData({
- txfangshi: tempTxfangshi, txdianhua: tempTxPhone, txzh: data.txzh || '', txtupian: data.txtupian || '', showSkfsModal: false
- });
- wx.setStorageSync('txfangshi', tempTxfangshi);
- wx.setStorageSync('txdianhua', tempTxPhone);
- wx.setStorageSync('txzh', data.txzh || '');
- wx.setStorageSync('txtupian', data.txtupian || '');
- wx.showToast({ title: '设置成功', icon: 'success' });
- } else {
- wx.showToast({ title: res?.data?.msg || '保存失败', icon: 'none' });
- }
- } catch (err) {
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
-
- onCloseSkfsModal() { this.setData({ showSkfsModal: false }); },
-
- async loadWithdrawRecords(refresh = false) {
- const now = Date.now();
- if (now - lastPullDownTime < PULL_DOWN_INTERVAL && !refresh) return;
- if (this.data.loading || this.data.isRefreshing) return;
- const page = refresh ? 1 : this.data.page;
- if (this.data.nomore && !refresh) return;
- this.setData({ loading: true, isRefreshing: refresh });
- lastPullDownTime = now;
- try {
- const res = await request({ url: '/yonghu/tixianjiluhq', method: 'POST', data: { page, limit: PAGE_SIZE } });
- if (res?.data?.code === 0) {
- const list = (res.data.data.list || []).map(item => ({
- ...item,
- statusText: this.getStatusText(item.zhuangtai),
- statusColor: this.getStatusColor(item.zhuangtai)
- }));
- const newList = refresh ? list : [...this.data.recordList, ...list];
- const hasMore = res.data.data.has_more === true;
- this.setData({
- recordList: newList, page: page + 1, nomore: !hasMore, canloadmore: hasMore,
- loading: false, isRefreshing: false
- });
- } else {
- this.setData({ loading: false, isRefreshing: false });
- }
- } catch (err) {
- this.setData({ loading: false, isRefreshing: false });
- }
- },
-
- onModifyRecord(e) {
- const record = e.currentTarget.dataset.record;
- if (parseInt(record.zhuangtai) !== 1) {
- wx.showToast({ title: '只有审核中的记录可修改', icon: 'none' });
- return;
- }
- this.setData({
- modifyingRecord: record,
- modifyTxfangshi: record.fangshi,
- modifyTxPhone: record.txdianhua || '',
- modifyTxAccount: record.txzh || '',
- modifyTxImage: '',
- modifyImageUrl: record.txtupian ? (app.globalData.ossImageUrl + record.txtupian) : '',
- showModifyModal: true
- });
- },
-
- onSelectModifyFangshi(e) { this.setData({ modifyTxfangshi: e.currentTarget.dataset.fangshi }); },
- onModifyPhoneInput(e) { this.setData({ modifyTxPhone: e.detail.value }); },
- onModifyAccountInput(e) { this.setData({ modifyTxAccount: e.detail.value }); },
-
- onChooseModifyImage() {
- if (this.data.choosingImage) return;
- this.setData({ choosingImage: true });
- wx.chooseMedia({
- count: 1, mediaType: ['image'],
- success: (res) => { this.setData({ modifyTxImage: res.tempFiles[0].tempFilePath }); },
- complete: () => { this.setData({ choosingImage: false }); }
- });
- },
-
- onPreviewModifyImage() {
- if (this.data.modifyTxImage) wx.previewImage({ urls: [this.data.modifyTxImage] });
- else if (this.data.modifyImageUrl) wx.previewImage({ urls: [this.data.modifyImageUrl] });
- },
-
- onDeleteModifyImage() { this.setData({ modifyTxImage: '' }); },
-
- async onConfirmModify() {
- const { modifyTxfangshi, modifyTxPhone, modifyTxAccount, modifyTxImage, modifyingRecord } = this.data;
- if (!modifyTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; }
- if (!modifyTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; }
- if (modifyTxfangshi == 1 && !modifyTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; }
- if (modifyTxfangshi == 2 && !modifyTxAccount && !modifyTxImage) {
- wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return;
- }
- const formData = { tixian_id: modifyingRecord.id, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '' };
- try {
- const res = await upload({ url: '/yonghu/yonghutxshxg', formData, filePath: modifyTxImage || null, fileName: 'file' });
- if (res?.data?.code === 0) {
- const data = res.data.data;
- const newList = this.data.recordList.map(item => {
- if (item.id === modifyingRecord.id) {
- return { ...item, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '', txtupian: data.txtupian || modifyingRecord.txtupian };
+ applyRouteOptions(assets) {
+ const opts = this.properties.options || {};
+ const fromKey = FROM_ASSET_MAP[opts.from];
+ let selected = null;
+ if (fromKey) {
+ selected = assets.find((a) => a.type === fromKey) || null;
+ } else if (assets.length === 1) {
+ selected = assets[0];
}
- return item;
- });
- this.setData({ recordList: newList, showModifyModal: false, modifyingRecord: null });
- wx.showToast({ title: '修改成功', icon: 'success' });
- } else {
- wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
- }
- } catch (err) {
- wx.showToast({ title: '网络错误', icon: 'none' });
- }
- },
+ const patch = {};
+ if (selected) {
+ patch.selectedAsset = selected;
+ patch.feeRateText = selected.rateText;
+ }
+ if (opts.amount && parseFloat(opts.amount) > 0) {
+ const amt = parseFloat(opts.amount);
+ const max = selected ? parseFloat(selected.amount) : amt;
+ patch.tixianAmount = Math.min(amt, max).toFixed(2);
+ }
+ if (Object.keys(patch).length) {
+ this.setData(patch, () => {
+ this.recalcFee(this.data.tixianAmount, this.data.selectedAsset);
+ });
+ }
+ },
- onCloseModifyModal() { this.setData({ showModifyModal: false, modifyingRecord: null }); },
+ onSelectAsset(e) {
+ const index = e.currentTarget.dataset.index;
+ const asset = this.data.displayAssetList[index];
+ if (!asset || parseFloat(asset.amount) <= 0) {
+ wx.showToast({ title: '该账户无可提余额', icon: 'none' });
+ return;
+ }
+ let amount = this.data.tixianAmount;
+ const max = parseFloat(asset.amount);
+ if (amount && parseFloat(amount) > max) {
+ amount = asset.amount;
+ }
+ this.setData({ selectedAsset: asset, tixianAmount: amount });
+ this.recalcFee(amount, asset);
+ },
- onViewFailReason(e) {
- const record = e.currentTarget.dataset.record;
- const reason = record.fail_reason || record.shibaiyuanyin || '暂无详细信息';
- this.setData({ currentFailReason: reason, showFailModal: true });
- },
+ async loadAllAssets() {
+ this.setData({ isLoadingAssets: true, totalAmount: '0.00', canWithdraw: false, assetList: [] });
+ try {
+ const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' });
+ if (res?.data?.code === 200 || res?.data?.code === 0) {
+ const data = res.data.data || {};
+ const assets = [];
+ const push = (type, amount, rate) => {
+ const cfg = ASSET_TYPES[type];
+ if (!cfg || !amount || parseFloat(amount) <= 0) return;
+ assets.push({
+ type,
+ leixing: cfg.leixing,
+ label: cfg.label,
+ amount: parseFloat(amount).toFixed(2),
+ rate: rate || 0,
+ rateText: this.formatRatePercent(rate || 0),
+ });
+ };
+ push('dashou_yue', data.dashou_yue, data.dashou_rate);
+ push('dashou_yajin', data.dashou_yajin, data.dashou_yajin_rate);
+ push('shangjia_yue', data.shangjia_yue, data.shangjia_rate);
+ push('guanshi_fenyong', data.guanshi_fenyong, data.guanshi_rate);
+ push('zuzhang_fenyong', data.zuzhang_fenyong, data.zuzhang_rate);
+ push('kaoheguan_fenyong', data.kaoheguan_fenyong, data.kaoheguan_rate);
- onCloseFailModal() { this.setData({ showFailModal: false }); },
+ const displayTotal = this.calcDisplayTotal(assets);
+ const firstRate = assets.find((a) => a.type !== 'dashou_yajin')?.rate || 0;
+ this.setData({
+ assetList: assets,
+ displayAssetList: assets,
+ totalAmount: displayTotal.toFixed(2),
+ canWithdraw: this.hasAnyWithdrawable(assets),
+ isLoadingAssets: false,
+ feeRateText: displayTotal > 0 ? this.formatRatePercent(firstRate) : '--',
+ }, () => this.applyRouteOptions(assets));
+ if (!this.data.selectedAsset) {
+ this.recalcFee(this.data.tixianAmount, null);
+ }
+ } else {
+ throw new Error(res?.data?.msg || '获取资产失败');
+ }
+ } catch (err) {
+ console.error('loadAllAssets', err);
+ this.setData({ isLoadingAssets: false, totalAmount: '0.00', canWithdraw: false, assetList: [] });
+ }
+ },
- getStatusText(zhuangtai) {
- const s = parseInt(zhuangtai);
- if (s === 1) return '审核中';
- if (s === 2) return '成功';
- if (s === 3) return '失败';
- return '未知';
- },
- getStatusColor(zhuangtai) {
- const s = parseInt(zhuangtai);
- if (s === 1) return '#F5A623';
- if (s === 2) return '#2ED158';
- if (s === 3) return '#FF4D4F';
- return '#999';
- },
+ async loadWithdrawMethod() {
+ const txzh = wx.getStorageSync('txzh') || '';
+ const txtupian = wx.getStorageSync('txtupian') || '';
+ const txfangshi = wx.getStorageSync('txfangshi') || null;
+ const txdianhua = wx.getStorageSync('txdianhua') || '';
+ if (txzh || txtupian || txfangshi) {
+ this.setData({ txzh, txtupian, txfangshi, txdianhua });
+ return;
+ }
+ try {
+ const res = await request({ url: '/yonghu/tixianhq', method: 'POST' });
+ if (res?.data?.code === 0) {
+ const data = res.data.data;
+ this.setData({
+ txzh: data.txzh || '',
+ txtupian: data.txtupian || '',
+ txfangshi: data.txfangshi || null,
+ txdianhua: data.txdianhua || '',
+ });
+ wx.setStorageSync('txzh', data.txzh || '');
+ wx.setStorageSync('txtupian', data.txtupian || '');
+ wx.setStorageSync('txfangshi', data.txfangshi || null);
+ wx.setStorageSync('txdianhua', data.txdianhua || '');
+ }
+ } catch (err) { /* ignore */ }
+ },
- registerNotification() {
- const comp = this.selectComponent('#global-notification');
- if (comp?.showNotification) {
- app.globalData.globalNotification = {
- show: (data) => comp.showNotification(data),
- hide: () => comp.hideNotification()
- };
- }
+ recalcFee(amountStr, asset) {
+ const amount = parseFloat(amountStr);
+ if (!amountStr || isNaN(amount) || amount <= 0 || !asset) {
+ this.setData({
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
+ feeRateText: asset ? asset.rateText : this.data.feeRateText,
+ });
+ return;
+ }
+ const rate = parseFloat(asset.rate) || 0;
+ const fee = amount * rate;
+ this.setData({
+ shouxufei: fee.toFixed(2),
+ shijidaozhang: (amount - fee).toFixed(2),
+ feeRateText: asset.rateText,
+ currentRate: asset.rateText,
+ });
+ },
+
+ onAmountInput(e) {
+ let val = e.detail.value;
+ if (val && !/^\d*\.?\d{0,2}$/.test(val)) return;
+ this.setData({ tixianAmount: val });
+ this.recalcFee(val, this.data.selectedAsset);
+ },
+
+ onWithdrawAll() {
+ const { selectedAsset } = this.data;
+ if (!selectedAsset) {
+ wx.showToast({ title: '请先选择提现账户', icon: 'none' });
+ return;
+ }
+ const max = selectedAsset.amount;
+ this.setData({ tixianAmount: max });
+ this.recalcFee(max, selectedAsset);
+ },
+
+ onTapWithdraw() {
+ if (this.data.submitting) return;
+ if (!this.hasAnyWithdrawable(this.data.assetList)) {
+ wx.showToast({ title: '暂无可提现余额', icon: 'none' });
+ return;
+ }
+ const { selectedAsset, tixianAmount } = this.data;
+ if (!selectedAsset) {
+ wx.showToast({ title: '请先选择要提现的账户', icon: 'none' });
+ return;
+ }
+ const amount = parseFloat(tixianAmount);
+ if (isNaN(amount) || amount <= 0) {
+ wx.showToast({ title: '请输入有效金额', icon: 'none' });
+ return;
+ }
+ if (amount > parseFloat(selectedAsset.amount)) {
+ wx.showToast({ title: `超过${selectedAsset.label}可提余额`, icon: 'none' });
+ return;
+ }
+ const { txfangshi, txzh, txtupian } = this.data;
+ if (!txfangshi || (!txzh && !txtupian)) {
+ wx.showToast({ title: '请先设置收款方式', icon: 'none' });
+ this.onSetSkfs();
+ return;
+ }
+ this.applyIdentityAndConfirm(selectedAsset);
+ },
+
+ applyIdentityAndConfirm(asset) {
+ this.recalcFee(this.data.tixianAmount, asset);
+ this.setData({ selectedAsset: asset, showTixianModal: true });
+ },
+
+ async onConfirmWithdraw() {
+ const { selectedAsset, tixianAmount, txfangshi, txzh, txtupian } = this.data;
+ if (!selectedAsset) {
+ wx.showToast({ title: '请选择提现身份', icon: 'none' });
+ return;
+ }
+ const amount = parseFloat(tixianAmount);
+ if (isNaN(amount) || amount <= 0) {
+ wx.showToast({ title: '请输入有效金额', icon: 'none' });
+ return;
+ }
+ if (amount > parseFloat(selectedAsset.amount)) {
+ wx.showToast({ title: '超过可提余额', icon: 'none' });
+ return;
+ }
+ const leixing = selectedAsset.leixing;
+ let txskfs = 0;
+ if (txzh && txtupian) txskfs = 3;
+ else if (txzh) txskfs = 1;
+ else if (txtupian) txskfs = 2;
+
+ this.setData({ submitting: true });
+ try {
+ const res = await request({
+ url: '/yonghu/tixian',
+ method: 'POST',
+ data: { leixing, jine: amount.toFixed(2), fangshi: txfangshi, txskfs },
+ });
+ if (res?.data?.code === 0) {
+ this.setData({
+ showTixianModal: false,
+ selectedAsset: null,
+ tixianAmount: '',
+ submitting: false,
+ });
+ await this.loadAllAssets();
+ wx.showModal({
+ title: '申请成功',
+ content: '提现申请已提交,请前往「提现记录」查看审核进度。',
+ confirmText: '查看提现记录',
+ cancelText: '知道了',
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({ url: '/pages/withdraw/withdraw-records' });
+ }
+ },
+ });
+ } else {
+ wx.showToast({ title: res?.data?.msg || '提现失败', icon: 'none' });
+ this.setData({ submitting: false });
+ }
+ } catch (err) {
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ this.setData({ submitting: false });
+ }
+ },
+
+ onCloseTixianModal() {
+ if (this.data.submitting) return;
+ this.setData({ showTixianModal: false, selectedAsset: null });
+ },
+
+ onSetSkfs() {
+ this.setData({
+ showSkfsModal: true,
+ tempTxfangshi: this.data.txfangshi,
+ tempTxPhone: this.data.txdianhua,
+ tempTxAccount: this.data.txzh,
+ tempTxImage: '',
+ });
+ },
+
+ onSelectFangshi(e) { this.setData({ tempTxfangshi: e.currentTarget.dataset.fangshi }); },
+ onPhoneInput(e) { this.setData({ tempTxPhone: e.detail.value }); },
+ onAccountInput(e) { this.setData({ tempTxAccount: e.detail.value }); },
+
+ onChooseImage() {
+ if (this.data.choosingImage) return;
+ this.setData({ choosingImage: true });
+ wx.chooseMedia({
+ count: 1,
+ mediaType: ['image'],
+ success: (res) => { this.setData({ tempTxImage: res.tempFiles[0].tempFilePath }); },
+ complete: () => { this.setData({ choosingImage: false }); },
+ });
+ },
+
+ onPreviewImage() {
+ if (this.data.tempTxImage) wx.previewImage({ urls: [this.data.tempTxImage] });
+ },
+
+ onDeleteImage() { this.setData({ tempTxImage: '' }); },
+
+ async onConfirmSkfs() {
+ const { tempTxfangshi, tempTxPhone, tempTxAccount, tempTxImage } = this.data;
+ if (!tempTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; }
+ if (!tempTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; }
+ if (tempTxfangshi == 1 && !tempTxImage && !this.data.txtupian) {
+ wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return;
+ }
+ if (tempTxfangshi == 2 && !tempTxAccount && !tempTxImage && !this.data.txzh) {
+ wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return;
+ }
+ try {
+ const res = await upload({
+ url: '/yonghu/sksc',
+ formData: { txdianhua: tempTxPhone, txzh: tempTxAccount || '' },
+ filePath: tempTxImage || null,
+ fileName: 'file',
+ });
+ if (res?.data?.code === 0) {
+ const data = res.data.data;
+ this.setData({
+ txfangshi: tempTxfangshi,
+ txdianhua: tempTxPhone,
+ txzh: data.txzh || '',
+ txtupian: data.txtupian || this.data.txtupian,
+ showSkfsModal: false,
+ });
+ wx.setStorageSync('txfangshi', tempTxfangshi);
+ wx.setStorageSync('txdianhua', tempTxPhone);
+ wx.setStorageSync('txzh', data.txzh || '');
+ wx.setStorageSync('txtupian', data.txtupian || this.data.txtupian);
+ wx.showToast({ title: '设置成功', icon: 'success' });
+ } else {
+ wx.showToast({ title: res?.data?.msg || '保存失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ onCloseSkfsModal() { this.setData({ showSkfsModal: false }); },
+ stopPropagation() {},
},
- stopPropagation() {}
- }
-});
\ No newline at end of file
+});
diff --git a/pages/withdraw/components/mode1/mode1.wxml b/pages/withdraw/components/mode1/mode1.wxml
index c4f5f71..ce59995 100644
--- a/pages/withdraw/components/mode1/mode1.wxml
+++ b/pages/withdraw/components/mode1/mode1.wxml
@@ -1,133 +1,115 @@
-
-
-
-
-
-
-
-
-
-
-
-
- 可提总余额
- ¥{{totalAmount}}
-
-
-
-
-
-
- ← 左右滑动查看更多资产 →
-
-
-
-
-
-
-
- {{item.label}}
- ¥{{item.amount}}
- 费率 {{item.rate}}%
-
-
- 暂无可用资金
-
-
+
+
+
+
+
+
+
+ {{txfangshi == 1 ? '微信零钱' : (txfangshi == 2 ? '收款码' : '请先设置收款')}}
+
-
-
-
+ 设置收款方式
-
-
-
-
-
-
- ¥{{item.jine}}
- {{item.create}}
-
-
- {{item.fangshi == 1 ? '微信' : '支付宝'}}
- {{item.leixing == 1 ? '佣金' : (item.leixing == 2 ? '分红' : (item.leixing == 3 ? '组长' : (item.leixing == 4 ? '考核官' : '保证金')))}}
-
-
- {{item.statusText}} ✏修改
-
- {{item.statusText}}
- 详情
-
- {{item.statusText}}
-
+
+
+
+ {{item.label}}
+ ¥{{item.amount}}
- 加载中...
- —— 没有更多了 ——
- 加载更多记录
+ 请先选择上方提现账户
+ 当前:{{selectedAsset.label}}
-
+
+
+ 当前可提现:
+ ¥
+ {{selectedAsset ? selectedAsset.amount : totalAmount}}
+
+
+ ¥
+
+ 全部提现
+
+
+
+ 提示:提现手续费
+ {{feeRateText}}
+ 。
+
+
+
+
+
+ 处理中...
+ 确认提现
+
+
+
+
+ 📢 提现须知
+ 🕒 提交后将进入人工审核,请耐心等待
+ 📌 审核结果可在「提现记录」中查看
+ 💰 每笔只能从单个账户提现,请先选择对应账户
+ ✅ 请确保收款方式与收款码正确后再提交
+ 🎧 如有疑问请联系客服核实处理
+
-
-
-
+
- 项目{{selectedAsset.label}}
+ 身份{{selectedAsset.label}}
可提¥{{selectedAsset.amount}}
- 费率{{currentRate}}%
- 金额
- ¥{{item}}
+ 费率{{currentRate}}
+ 提现金额¥{{tixianAmount}}
手续费 ¥{{shouxufei}}到账 ¥{{shijidaozhang}}
- 收款方式 {{txfangshi == 1 ? '微信' : (txfangshi == 2 ? '支付宝' : '未设置')}}更换
+ 收款{{txfangshi == 1 ? '微信' : (txfangshi == 2 ? '支付宝' : '未设置')}}
+
+
-
-
-
- 微信支付宝
+
+
+ 微信
+ 支付宝
+
- + 上传收款码预览删除
+
+ + 上传收款码
+ 预览删除
+
-
-
-
-
-
-
-
-
-
- 微信支付宝
-
-
- + 上传新图片预览删除
+
-
-
-
-
-
-
-
-
- {{currentFailReason}}
-
-
\ No newline at end of file
+
diff --git a/pages/withdraw/components/mode1/mode1.wxss b/pages/withdraw/components/mode1/mode1.wxss
index 6ce2249..2d5e693 100644
--- a/pages/withdraw/components/mode1/mode1.wxss
+++ b/pages/withdraw/components/mode1/mode1.wxss
@@ -1,424 +1,85 @@
-/* pages/withdraw/withdraw.wxss - 终极优化版 */
+@import '../mode2/mode2.wxss';
-page {
- background-color: #f5f7fb;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- height: 100%;
- }
-
- .app {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- padding: 0 24rpx 0;
- position: relative;
- z-index: 1;
- box-sizing: border-box;
- }
-
- /* 页面背景模糊极低,不影响阅读 */
- .global-bg {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: -1;
- opacity: 0.1;
- object-fit: cover;
- filter: blur(1rpx);
- }
-
- /* 资产区域整体与顶部保持间距 */
- .assets-section {
- margin-top: 24rpx;
- flex-shrink: 0;
- }
-
- /* 主卡片玻璃质感 - 模糊加重避免抢眼,同时文字对比加强 */
- .main-card {
- background: rgba(248, 250, 252, 0.88); /* 稍微降低透明度,让背景更柔和 */
- backdrop-filter: blur(28rpx); /* 增强模糊,不抢眼 */
- -webkit-backdrop-filter: blur(28rpx);
- border-radius: 48rpx;
- padding: 30rpx 28rpx 24rpx; /* 稍微缩小高度 */
- margin-bottom: 20rpx;
- box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
- border: 1rpx solid rgba(255, 255, 255, 0.4);
- background-size: cover;
- }
-
- /* 总余额 - 字体加深加粗,增加阴影提高可读性 */
- .balance-wrap {
- text-align: center;
- margin-bottom: 20rpx; /* 减小间距,让卡片更紧凑 */
- }
- .balance-label {
- font-size: 28rpx;
- color: #0f172a; /* 更深色 */
- letter-spacing: 1px;
- display: block;
- margin-bottom: 10rpx;
- font-weight: 700; /* 加粗 */
- text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.8);
- }
- .balance-value {
- font-size: 68rpx;
- font-weight: 800;
- color: #0f172a;
- font-family: 'DIN', monospace;
- letter-spacing: -1rpx;
- text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.6);
- }
-
- /* 内部分隔线(横杠)- 明显且保持层次 */
- .inner-divider {
- width: 60%;
- height: 2rpx;
- background: linear-gradient(90deg, transparent, #64748b, #64748b, transparent); /* 加深颜色 */
- margin: 0 auto 20rpx auto;
- border-radius: 2rpx;
- opacity: 0.9;
- }
-
- /* 左右滑动提示 - 字体明显 */
- .assets-hint {
- display: block;
- text-align: center;
- font-size: 24rpx;
- color: #334155; /* 深灰 */
- margin-bottom: 14rpx;
- font-weight: 600;
- }
-
- .assets-scroll {
- width: 100%;
- white-space: nowrap;
- }
- .assets-track {
- display: inline-flex;
- gap: 16rpx;
- }
-
- /* 资产小卡片 - 背景半透模糊,字体深色加粗 */
- .asset-tile {
- width: 170rpx;
- background: rgba(255, 255, 255, 0.75); /* 稍微提高透明度,让模糊背景透出 */
- backdrop-filter: blur(8rpx); /* 自身轻微模糊,不抢眼 */
- border-radius: 28rpx;
- padding: 18rpx 12rpx;
- display: inline-flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- border: 1rpx solid rgba(255,255,255,0.5);
- box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02);
- transition: all 0.2s;
- white-space: normal;
- background-size: cover;
- background-position: center;
- }
- .asset-tile:active {
- background: rgba(255, 255, 255, 0.9);
- transform: scale(0.98);
- }
- .asset-name {
- font-size: 24rpx;
- font-weight: 700; /* 加粗 */
- color: #1e293b; /* 深色 */
- margin-bottom: 10rpx;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.5);
- }
- .asset-balance {
- font-size: 28rpx;
- font-weight: 800; /* 加粗 */
- color: #2d6a4f;
- font-family: monospace;
- margin-bottom: 6rpx;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
- }
- .asset-fee {
- font-size: 20rpx;
- font-weight: 600; /* 加粗并加深 */
- color: #475569;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
- }
- .assets-empty {
- width: 400rpx;
- text-align: center;
- color: #a0abb9;
- padding: 40rpx 0;
- }
-
- /* 外部层次分隔线 - 保持不变,保留分层 */
- .divider-line {
- height: 2rpx;
- background: linear-gradient(90deg, transparent, #cbd5e1, #cbd5e1, transparent);
- margin: 16rpx 0 20rpx;
- width: 80%;
- margin-left: auto;
- margin-right: auto;
- }
-
- /* 提现记录区 - 无改动,自然贴底 */
- .history-section {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
- margin-top: 0;
- }
- .history-header {
- display: flex;
- justify-content: space-between;
- align-items: baseline;
- padding: 0 8rpx 20rpx;
- flex-shrink: 0;
- }
- .history-title {
- font-size: 34rpx;
- font-weight: 600;
- color: #1e293b;
- }
- .history-settings {
- font-size: 28rpx;
- color: #3b82f6;
- }
- .history-scroll {
- flex: 1;
- width: 100%;
- padding: 0 20rpx;
- box-sizing: border-box;
- }
- .history-item {
- display: flex;
- align-items: center;
- padding: 28rpx 0;
- border-bottom: 1rpx solid rgba(0,0,0,0.05);
- }
- .history-info {
- width: 160rpx;
- }
- .history-amount {
- font-size: 36rpx;
- font-weight: 700;
- color: #1e293b;
- display: block;
- }
- .history-time {
- font-size: 22rpx;
- color: #94a3b8;
- }
- .history-detail {
- flex: 1;
- padding: 0 20rpx;
- }
- .history-method {
- font-size: 30rpx;
- color: #334155;
- display: block;
- margin-bottom: 6rpx;
- }
- .history-type {
- font-size: 24rpx;
- color: #94a3b8;
- }
- .history-status {
- text-align: right;
- }
- .status-badge {
- font-size: 26rpx;
- font-weight: 500;
- padding: 6rpx 14rpx;
- border-radius: 30rpx;
- display: inline-block;
- }
- .status-wait {
- color: #f59e0b;
- background: rgba(245,158,11,0.1);
- }
- .status-done {
- color: #10b981;
- background: rgba(16,185,129,0.1);
- }
- .status-fail {
- color: #ef4444;
- background: rgba(239,68,68,0.1);
- }
- .fail-link {
- margin-left: 8rpx;
- text-decoration: underline;
- }
- .load-tip, .more-tip {
- text-align: center;
- padding: 30rpx;
- font-size: 24rpx;
- color: #94a3b8;
- }
- .load-more-btn {
- margin: 16rpx 0 20rpx;
- padding: 20rpx;
- text-align: center;
- background: rgba(255,255,255,0.7);
- backdrop-filter: blur(8rpx);
- border-radius: 40rpx;
- font-size: 28rpx;
- color: #3b82f6;
- border: 1rpx solid rgba(255,255,255,0.5);
- }
- .load-more-btn:active {
- background: rgba(255,255,255,0.9);
- }
- .safe-bottom {
- height: 12rpx;
- flex-shrink: 0;
- }
-
- /* ========== 弹窗样式(完整保留) ========== */
- .modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0,0,0,0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
- }
- .modal-dialog {
- width: 600rpx;
- background: rgba(255,255,255,0.96);
- backdrop-filter: blur(20rpx);
- border-radius: 48rpx;
- overflow: hidden;
- box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.1);
- border: 1rpx solid rgba(255,255,255,0.6);
- }
- .modal-header {
- padding: 36rpx 32rpx 20rpx;
- font-size: 36rpx;
- font-weight: 700;
- border-bottom: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-body {
- padding: 32rpx;
- }
- .info-row, .amount-row, .method-row {
- display: flex;
- justify-content: space-between;
- margin-bottom: 24rpx;
- font-size: 28rpx;
- }
- .amount-row input {
- border: 1rpx solid rgba(0,0,0,0.1);
- border-radius: 28rpx;
- padding: 16rpx 20rpx;
- width: 260rpx;
- background: rgba(255,255,255,0.9);
- }
- .quick-row {
- display: flex;
- gap: 16rpx;
- margin: 24rpx 0;
- }
- .quick-chip {
- flex: 1;
- background: rgba(241,245,249,0.8);
- text-align: center;
- padding: 12rpx;
- border-radius: 40rpx;
- font-size: 28rpx;
- }
- .fee-row {
- display: flex;
- justify-content: space-between;
- background: rgba(248,250,252,0.8);
- padding: 20rpx;
- border-radius: 28rpx;
- margin: 20rpx 0;
- }
- .link-text {
- color: #3b82f6;
- }
- .toggle-row {
- display: flex;
- gap: 20rpx;
- margin-bottom: 28rpx;
- }
- .toggle-item {
- flex: 1;
- text-align: center;
- padding: 20rpx;
- border: 1rpx solid rgba(0,0,0,0.08);
- border-radius: 30rpx;
- background: rgba(255,255,255,0.8);
- }
- .toggle-item.active {
- border-color: #3b82f6;
- background: #eff6ff;
- }
- .field-input {
- width: 100%;
- border: 1rpx solid rgba(0,0,0,0.08);
- border-radius: 28rpx;
- padding: 20rpx;
- margin-bottom: 20rpx;
- box-sizing: border-box;
- background: rgba(255,255,255,0.9);
- }
- .upload-trigger {
- background: rgba(241,245,249,0.8);
- border: 1rpx dashed #cbd5e1;
- border-radius: 28rpx;
- padding: 28rpx;
- text-align: center;
- }
- .image-preview {
- margin-top: 16rpx;
- position: relative;
- }
- .image-preview image {
- width: 100%;
- height: 200rpx;
- border-radius: 28rpx;
- }
- .image-actions {
- display: flex;
- justify-content: space-around;
- background: rgba(0,0,0,0.6);
- padding: 12rpx;
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- color: white;
- border-bottom-left-radius: 28rpx;
- border-bottom-right-radius: 28rpx;
- }
- .current-img {
- margin: 20rpx 0;
- }
- .current-img image {
- width: 100%;
- height: 140rpx;
- border-radius: 24rpx;
- }
- .modal-footer {
- display: flex;
- border-top: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-btn {
- flex: 1;
- text-align: center;
- padding: 28rpx;
- font-size: 30rpx;
- }
- .modal-btn.cancel {
- color: #8f9bb3;
- border-right: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-btn.confirm {
- color: #3b82f6;
- }
\ No newline at end of file
+.method-card--row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-right: 24rpx;
+}
+
+.method-setting {
+ font-size: 26rpx;
+ color: #ff8c00;
+ flex-shrink: 0;
+ padding: 16rpx 8rpx;
+}
+
+.method-tab-icon--placeholder {
+ background: #e0e0e0;
+ border-radius: 8rpx;
+}
+
+.skfs-body .toggle-row {
+ display: flex;
+ gap: 16rpx;
+ margin-bottom: 24rpx;
+}
+
+.toggle-item {
+ flex: 1;
+ text-align: center;
+ padding: 20rpx;
+ border-radius: 12rpx;
+ background: #f5f5f5;
+ font-size: 28rpx;
+ color: #666;
+}
+
+.toggle-item.active {
+ background: #fff8e1;
+ color: #ff8c00;
+ font-weight: 600;
+ border: 2rpx solid #FFD54F;
+}
+
+.field-input {
+ width: 100%;
+ box-sizing: border-box;
+ padding: 24rpx;
+ margin-bottom: 16rpx;
+ background: #f8f8f8;
+ border-radius: 12rpx;
+ font-size: 28rpx;
+}
+
+.upload-wrap {
+ margin-top: 16rpx;
+}
+
+.upload-trigger {
+ padding: 48rpx;
+ text-align: center;
+ border: 2rpx dashed #ddd;
+ border-radius: 12rpx;
+ color: #999;
+ font-size: 28rpx;
+}
+
+.image-preview {
+ position: relative;
+}
+
+.image-preview image {
+ width: 100%;
+ height: 320rpx;
+ border-radius: 12rpx;
+}
+
+.image-actions {
+ display: flex;
+ justify-content: center;
+ gap: 32rpx;
+ margin-top: 16rpx;
+ font-size: 28rpx;
+ color: #ff8c00;
+}
diff --git a/pages/withdraw/components/mode2/mode2.js b/pages/withdraw/components/mode2/mode2.js
index ee9b6d5..b393f71 100644
--- a/pages/withdraw/components/mode2/mode2.js
+++ b/pages/withdraw/components/mode2/mode2.js
@@ -1,21 +1,8 @@
-// pages/withdraw/components/mode2/mode2.js
-// UI 与 mode1 完全一致,业务逻辑为自动打款审核收款
+// pages/withdraw/components/mode2/mode2.js — 自动打款纯提现
import request from '../../../../utils/request.js';
import PopupService from '../../../../services/popupService.js';
const app = getApp();
-const yemianshuju = 5;
-let lastPullDownTime = 0;
-const PULL_DOWN_INTERVAL = 2000;
-
-const TX_STATUS = {
- SHENHEZHONG: 1,
- TIXIAN_CHENGGONG: 2,
- TIXIAN_SHIBAI: 3,
- SHENHE_CHENGGONG: 4,
- SHENHE_SHIBAI: 5,
- DAI_SHOUKUAN: 6,
-};
const ASSET_CONFIG = {
dashou_yue: { leixing: 1, label: '接单员佣金' },
@@ -26,58 +13,41 @@ const ASSET_CONFIG = {
shangjia_yue: { leixing: 6, label: '商家余额' },
};
-const LEIXING_LABEL = {
- 1: '接单员佣金', 2: '管事分红', 3: '组长分红',
- 4: '考核官分佣', 5: '接单员保证金', 6: '商家余额',
+/** 页面入参 from 与资产 type 映射 */
+const FROM_ASSET_MAP = {
+ dashou: 'dashou_yue',
+ guanshi: 'guanshi_fenyong',
+ zuzhang: 'zuzhang_fenyong',
+ kaoheguan: 'kaoheguan_fenyong',
+ kaohe: 'kaoheguan_fenyong',
+ shangjia: 'shangjia_yue',
+ yajin: 'dashou_yajin',
};
Component({
properties: { options: { type: Object, value: {} } },
data: {
- imgUrls: {
- pageBg: '', cardBg: '', assetTileBg: '',
- },
+ imgUrls: { iconWechat: '' },
assetList: [],
+ displayAssetList: [],
totalAmount: '0.00',
+ canWithdraw: false,
selectedAsset: null,
isLoadingAssets: false,
tixianleixing: null,
tixianjine: '',
currentRate: '0.00',
+ feeRateText: '--',
showTixian: false,
- recordList: [],
- page: 1,
- loading: false,
- nomore: false,
- canloadmore: true,
- isRefreshing: false,
shouxufei: '0.00',
shijidaozhang: '0.00',
- currentTixianId: null,
submitting: false,
- mchId: '',
- currentStatusFilter: 0,
- statusTabs: [
- { value: 0, label: '全部' },
- { value: 1, label: '审核中' },
- { value: 6, label: '待收款' },
- { value: 4, label: '审核成功' },
- { value: 5, label: '审核失败' },
- { value: 2, label: '提现成功' },
- { value: 3, label: '提现失败' },
- ],
- hasPendingCollect: false,
- showCollectConfirm: false,
- collectConfirmRecord: null,
- showDetailModal: false,
- detailTitle: '',
- detailContent: '',
},
lifetimes: {
attached() {
this.initImageUrls();
- this.chushihuashuju();
- }
+ this.loadAllAssets();
+ },
},
pageLifetimes: {
show() {
@@ -88,7 +58,7 @@ Component({
hide() {
const popupComp = this.selectComponent('#popupNotice');
if (popupComp && popupComp.cleanup) popupComp.cleanup();
- }
+ },
},
methods: {
registerNotificationComponent() {
@@ -96,127 +66,11 @@ Component({
if (notificationComp && notificationComp.showNotification) {
app.globalData.globalNotification = {
show: (data) => notificationComp.showNotification(data),
- hide: () => notificationComp.hideNotification()
+ hide: () => notificationComp.hideNotification(),
};
}
},
- initImageUrls() {
- const ossBase = app.globalData.ossImageUrl || '';
- const imgDir = `${ossBase}beijing/tixian/`;
- this.setData({
- imgUrls: {
- pageBg: `${imgDir}page_bg.png`,
- cardBg: `${imgDir}card_bg.png`,
- assetTileBg: `${imgDir}asset_tile_bg.png`,
- }
- });
- },
-
- parseZhuangtai(item) {
- const raw = item.zhuangtai ?? item.status ?? item.state;
- const n = parseInt(raw, 10);
- return Number.isNaN(n) ? -1 : n;
- },
-
- /** 规范化列表字段(兼容后端多种命名 / 嵌套 audit) */
- normalizeRecordFields(item) {
- const audit = item.audit || item.shenhe || item.shenhe_info || {};
- const shenheJiluId = item.shenhe_jilu_id ?? item.shenheJiluId
- ?? item.audit_id ?? item.shenheid ?? audit.id ?? audit.shenhe_jilu_id ?? null;
- const shenheDanhao = String(
- item.shenhe_danhao || item.shenheDanhao || item.audit_shenhe_danhao
- || audit.shenhe_danhao || audit.danhao || ''
- ).trim();
- const tixianjiluId = item.tixianjilu_id ?? item.tixianjiluId ?? item.id ?? null;
- const zhuangtai = this.parseZhuangtai(item);
- return {
- ...item,
- zhuangtai: zhuangtai >= 0 ? zhuangtai : item.zhuangtai,
- shenhe_jilu_id: shenheJiluId,
- shenhe_danhao: shenheDanhao,
- tixianjilu_id: tixianjiluId,
- };
- },
-
- hasAuditJiluId(item) {
- const id = item.shenhe_jilu_id;
- return id !== null && id !== undefined && id !== '' && id !== 0 && id !== '0';
- },
-
- hasShenheDanhao(item) {
- return !!(item.shenhe_danhao && String(item.shenhe_danhao).trim());
- },
-
- isNewAuditRecord(item) {
- return this.hasAuditJiluId(item) && this.hasShenheDanhao(item);
- },
-
- /** 待收款是否可点击:状态6 + 审核记录ID + 审核单号 缺一不可 */
- canCollectRecord(item) {
- return this.parseZhuangtai(item) === TX_STATUS.DAI_SHOUKUAN
- && this.hasAuditJiluId(item)
- && this.hasShenheDanhao(item);
- },
-
- getLeixingLabel(leixing) {
- return LEIXING_LABEL[parseInt(leixing)] || '提现';
- },
-
- getStatusBadgeClass(status) {
- switch (parseInt(status)) {
- case TX_STATUS.SHENHEZHONG: return 'status-wait';
- case TX_STATUS.TIXIAN_CHENGGONG:
- case TX_STATUS.SHENHE_CHENGGONG: return 'status-done';
- case TX_STATUS.DAI_SHOUKUAN: return 'status-pending';
- case TX_STATUS.TIXIAN_SHIBAI:
- case TX_STATUS.SHENHE_SHIBAI: return 'status-fail';
- default: return 'status-wait';
- }
- },
-
- processRecordItem(item) {
- item = this.normalizeRecordFields(item);
- const isNew = this.isNewAuditRecord(item);
- const status = this.parseZhuangtai(item);
- let statusText = '未知';
- let canCollect = false;
- let canShowDetail = false;
- let detailReason = '';
-
- switch (status) {
- case TX_STATUS.SHENHEZHONG: statusText = '审核中'; break;
- case TX_STATUS.TIXIAN_CHENGGONG: statusText = '提现成功'; break;
- case TX_STATUS.TIXIAN_SHIBAI:
- statusText = '提现失败';
- if (item.fail_reason || item.bhliyou) {
- canShowDetail = true;
- detailReason = item.fail_reason || item.bhliyou;
- }
- break;
- case TX_STATUS.SHENHE_CHENGGONG: statusText = '审核成功'; break;
- case TX_STATUS.SHENHE_SHIBAI:
- statusText = '审核失败';
- if (item.bhliyou) { canShowDetail = true; detailReason = item.bhliyou; }
- break;
- case TX_STATUS.DAI_SHOUKUAN:
- statusText = '待收款';
- canCollect = this.canCollectRecord(item);
- break;
- }
-
- return {
- ...item,
- isNewAudit: isNew,
- leixingLabel: this.getLeixingLabel(item.leixing),
- statusText,
- statusBadgeClass: this.getStatusBadgeClass(status),
- canCollect,
- canShowDetail,
- detailReason,
- };
- },
-
gengxinYue(data, leixing) {
if (!data) return;
if (data.new_yongjin !== undefined && data.new_yongjin !== null) {
@@ -239,51 +93,79 @@ Component({
}
},
- updatePendingCollectFlag(list) {
- const hasPending = (list || []).some(item => item.canCollect);
- if (hasPending !== this.data.hasPendingCollect) {
- this.setData({ hasPendingCollect: hasPending });
+ initImageUrls() {
+ const ossBase = app.globalData.ossImageUrl || '';
+ const imgDir = `${ossBase}beijing/tixian/`;
+ this.setData({
+ imgUrls: {
+ iconWechat: `${imgDir}icon_wechat.png`,
+ },
+ });
+ },
+
+ /** 顶部展示:不含保证金的可提现合计 */
+ calcDisplayTotal(assets) {
+ let total = 0;
+ (assets || []).forEach((item) => {
+ if (item.type === 'dashou_yajin') return;
+ total += parseFloat(item.amount) || 0;
+ });
+ return total;
+ },
+
+ hasAnyWithdrawable(assets) {
+ return (assets || []).some((item) => parseFloat(item.amount) > 0);
+ },
+
+ applyRouteOptions(assets) {
+ const opts = this.properties.options || {};
+ const fromKey = FROM_ASSET_MAP[opts.from];
+ let selected = null;
+ if (fromKey) {
+ selected = assets.find((a) => a.type === fromKey) || null;
+ } else if (assets.length === 1) {
+ selected = assets[0];
+ }
+ const patch = {};
+ if (selected) {
+ patch.selectedAsset = selected;
+ patch.tixianleixing = selected.leixing;
+ patch.feeRateText = selected.rateText;
+ }
+ if (opts.amount && parseFloat(opts.amount) > 0) {
+ const amt = parseFloat(opts.amount);
+ const max = selected ? parseFloat(selected.amount) : amt;
+ patch.tixianjine = Math.min(amt, max).toFixed(2);
+ }
+ if (Object.keys(patch).length) {
+ this.setData(patch, () => {
+ this.recalcFee(this.data.tixianjine, this.data.selectedAsset);
+ });
}
},
- /** 微信确认收款成功后,本地先把对应记录标为「提现成功」 */
- markLocalRecordWithdrawSuccess(record) {
- if (!record) return;
- const matchId = String(record.tixianjilu_id || record.id || '');
- const matchDanhao = String(record.shenhe_danhao || '').trim();
- if (!matchId && !matchDanhao) return;
-
- const newList = (this.data.recordList || []).map((item) => {
- const itemId = String(item.tixianjilu_id || item.id || '');
- const itemDanhao = String(item.shenhe_danhao || '').trim();
- const isMatch = (matchId && itemId === matchId)
- || (matchDanhao && itemDanhao === matchDanhao);
- if (!isMatch) return item;
- return this.processRecordItem({
- ...item,
- zhuangtai: TX_STATUS.TIXIAN_CHENGGONG,
- });
- });
- this.setData({ recordList: newList });
- this.updatePendingCollectFlag(newList);
- },
-
- async finishWxCollectSuccess(record) {
- this.markLocalRecordWithdrawSuccess(record);
- await this.loadAllAssets();
- await this.huoquJilu(true, true);
- // 后端若尚未落库,刷新后仍可能显示待收款,再覆盖一次本地成功态
- this.markLocalRecordWithdrawSuccess(record);
- PopupService.checkAndShow(this, 'tixianchenggong');
- wx.showToast({
- title: '提现成功',
- icon: 'success',
- duration: 3000,
+ onSelectAsset(e) {
+ const index = e.currentTarget.dataset.index;
+ const asset = this.data.displayAssetList[index];
+ if (!asset || parseFloat(asset.amount) <= 0) {
+ wx.showToast({ title: '该账户无可提余额', icon: 'none' });
+ return;
+ }
+ let jine = this.data.tixianjine;
+ const max = parseFloat(asset.amount);
+ if (jine && parseFloat(jine) > max) {
+ jine = asset.amount;
+ }
+ this.setData({
+ selectedAsset: asset,
+ tixianleixing: asset.leixing,
+ tixianjine: jine,
});
+ this.recalcFee(jine, asset);
},
async loadAllAssets() {
- this.setData({ isLoadingAssets: true });
+ this.setData({ isLoadingAssets: true, totalAmount: '0.00', canWithdraw: false, assetList: [] });
try {
const res = await request({ url: '/yonghu/tixianzichan', method: 'POST' });
if (res?.data?.code === 200 || res?.data?.code === 0) {
@@ -298,6 +180,7 @@ Component({
label: cfg.label,
amount: parseFloat(amount).toFixed(2),
rate: rate || 0,
+ rateText: this.formatRatePercent(rate || 0),
});
};
pushAsset('dashou_yue', data.dashou_yue, data.dashou_rate);
@@ -307,63 +190,114 @@ Component({
pushAsset('zuzhang_fenyong', data.zuzhang_fenyong, data.zuzhang_rate);
pushAsset('kaoheguan_fenyong', data.kaoheguan_fenyong, data.kaoheguan_rate);
- let total = 0;
- assets.forEach(item => { total += parseFloat(item.amount); });
- this.setData({ assetList: assets, totalAmount: total.toFixed(2), isLoadingAssets: false });
+ const displayTotal = this.calcDisplayTotal(assets);
+ const firstRate = assets.find((a) => a.type !== 'dashou_yajin')?.rate || 0;
+ this.setData({
+ assetList: assets,
+ displayAssetList: assets,
+ totalAmount: displayTotal.toFixed(2),
+ canWithdraw: this.hasAnyWithdrawable(assets),
+ isLoadingAssets: false,
+ feeRateText: displayTotal > 0 ? this.formatRatePercent(firstRate) : '--',
+ }, () => this.applyRouteOptions(assets));
+ if (!this.data.selectedAsset) {
+ this.recalcFee(this.data.tixianjine, null);
+ }
} else {
throw new Error(res?.data?.msg || '获取资产失败');
}
} catch (err) {
console.error('loadAllAssets', err);
- this.setData({ isLoadingAssets: false });
+ this.setData({ isLoadingAssets: false, totalAmount: '0.00', canWithdraw: false, assetList: [] });
}
},
- chushihuashuju() {
- this.loadAllAssets();
- this.huoquJilu(true);
+ formatRatePercent(rate) {
+ const r = parseFloat(rate) || 0;
+ if (r <= 1 && r > 0) return `${(r * 100).toFixed(0)}%`;
+ return `${r}%`;
},
- /** 点击资产卡片(与 mode1 一致) */
- onSelectAsset(e) {
- const index = e.currentTarget.dataset.index;
- const asset = this.data.assetList[index];
- if (!asset || parseFloat(asset.amount) <= 0) {
- wx.showToast({ title: '无可提现金额', icon: 'none' });
+ recalcFee(amountStr, asset) {
+ const amount = parseFloat(amountStr);
+ if (!amountStr || isNaN(amount) || amount <= 0 || !asset) {
+ this.setData({
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
+ feeRateText: asset ? this.formatRatePercent(asset.rate) : this.data.feeRateText,
+ });
return;
}
+ const rate = parseFloat(asset.rate) || 0;
+ const fee = amount * rate;
+ const actual = amount - fee;
this.setData({
- selectedAsset: asset,
- tixianleixing: asset.leixing,
- currentRate: asset.rate,
- tixianjine: '',
- shouxufei: '0.00',
- shijidaozhang: '0.00',
- showTixian: true,
+ shouxufei: fee.toFixed(2),
+ shijidaozhang: actual.toFixed(2),
+ feeRateText: this.formatRatePercent(rate),
+ currentRate: this.formatRatePercent(rate),
});
},
onJineInput(e) {
- this.setData({ tixianjine: e.detail.value, shouxufei: '0.00', shijidaozhang: '0.00' });
+ const val = e.detail.value;
+ this.setData({ tixianjine: val });
+ this.recalcFee(val, this.data.selectedAsset);
},
- onQuickAmountTap(e) {
- const value = e.currentTarget.dataset.value;
- this.setData({ tixianjine: value.toString(), shouxufei: '0.00', shijidaozhang: '0.00' });
+ onWithdrawAll() {
+ const { selectedAsset } = this.data;
+ if (!selectedAsset) {
+ wx.showToast({ title: '请先选择提现账户', icon: 'none' });
+ return;
+ }
+ const max = selectedAsset.amount;
+ this.setData({ tixianjine: max });
+ this.recalcFee(max, selectedAsset);
},
- onStatusFilterTap(e) {
- const value = parseInt(e.currentTarget.dataset.value);
- if (value === this.data.currentStatusFilter) return;
- this.setData({ currentStatusFilter: value });
- this.huoquJilu(true);
+ onTapWithdraw() {
+ if (this.data.submitting) return;
+ if (!this.hasAnyWithdrawable(this.data.assetList)) {
+ wx.showToast({ title: '暂无可提现余额', icon: 'none' });
+ return;
+ }
+ const { selectedAsset, tixianjine } = this.data;
+ if (!selectedAsset) {
+ wx.showToast({ title: '请先选择要提现的账户', icon: 'none' });
+ return;
+ }
+ const jineValue = parseFloat(tixianjine);
+ if (!tixianjine || isNaN(jineValue) || jineValue <= 0) {
+ wx.showToast({ title: '请输入有效金额', icon: 'none' });
+ return;
+ }
+ if (jineValue <= 0.1) {
+ wx.showToast({ title: '提现金额须大于0.1元', icon: 'none' });
+ return;
+ }
+ if (jineValue > parseFloat(selectedAsset.amount)) {
+ wx.showToast({ title: `超过${selectedAsset.label}可提余额`, icon: 'none' });
+ return;
+ }
+ this.applyIdentityAndConfirm(selectedAsset);
+ },
+
+ applyIdentityAndConfirm(asset) {
+ this.recalcFee(this.data.tixianjine, asset);
+ this.setData({
+ selectedAsset: asset,
+ tixianleixing: asset.leixing,
+ currentRate: this.formatRatePercent(asset.rate),
+ showTixian: true,
+ });
},
async onConfirmTixian() {
if (this.data.submitting) return;
const { tixianleixing, tixianjine, selectedAsset } = this.data;
if (!tixianleixing || !selectedAsset) {
- wx.showToast({ title: '请选择提现类型', icon: 'none' });
+ wx.showToast({ title: '请选择提现身份', icon: 'none' });
return;
}
const jineValue = parseFloat(tixianjine);
@@ -372,7 +306,7 @@ Component({
return;
}
if (jineValue > parseFloat(selectedAsset.amount)) {
- wx.showToast({ title: `超过可提${selectedAsset.label}`, icon: 'none' });
+ wx.showToast({ title: `超过${selectedAsset.label}可提余额`, icon: 'none' });
return;
}
@@ -381,24 +315,30 @@ Component({
const res = await request({
url: '/yonghu/zddksh',
method: 'POST',
- data: { leixing: tixianleixing, jine: jineValue.toFixed(2) }
+ data: { leixing: tixianleixing, jine: jineValue.toFixed(2) },
});
if (res.statusCode === 200 && res.data && res.data.code === 0) {
const data = res.data.data || {};
this.gengxinYue(data, tixianleixing);
- if (data.shouxufei !== undefined) {
- this.setData({
- shouxufei: parseFloat(data.shouxufei || 0).toFixed(2),
- shijidaozhang: parseFloat(data.shijidaozhang || 0).toFixed(2),
- });
- }
- this.setData({ showTixian: false, submitting: false, selectedAsset: null });
+ this.setData({
+ showTixian: false,
+ submitting: false,
+ selectedAsset: null,
+ tixianjine: '',
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
+ });
await this.loadAllAssets();
- this.huoquJilu(true);
wx.showModal({
- title: '申请已提交',
- content: '您的提现申请已提交,请等待后台审核。审核通过后,请在本页「提现记录」中点击「收款」按钮,主动确认后才能到账微信零钱。',
- showCancel: false,
+ title: '申请成功',
+ content: '提现申请已提交,请前往「提现记录」查看进度;审核通过后可在该页点击「收款」确认到账。',
+ confirmText: '查看提现记录',
+ cancelText: '知道了',
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({ url: '/pages/withdraw/withdraw-records' });
+ }
+ },
});
} else {
wx.showModal({ title: '提现申请失败', content: res.data?.msg || '未知错误', showCancel: false });
@@ -410,233 +350,20 @@ Component({
}
},
- onCollectTap(e) {
- const index = e.currentTarget.dataset.index;
- const record = this.data.recordList[index];
- if (!record) return;
- if (this.parseZhuangtai(record) !== TX_STATUS.DAI_SHOUKUAN) {
- wx.showToast({ title: '当前状态不可收款', icon: 'none' });
- return;
- }
- if (!this.hasShenheDanhao(record) || !this.hasAuditJiluId(record)) {
- wx.showToast({ title: '审核信息不完整,请刷新后重试', icon: 'none' });
- return;
- }
+ onCloseTixian() {
if (this.data.submitting) {
wx.showToast({ title: '正在处理中,请稍后', icon: 'none' });
return;
}
- this.setData({ showCollectConfirm: true, collectConfirmRecord: record });
- },
-
- onCloseCollectConfirm() {
- if (this.data.submitting) return;
- this.setData({ showCollectConfirm: false, collectConfirmRecord: null });
- },
-
- async onConfirmCollect() {
- if (this.data.submitting) return;
- let record = this.data.collectConfirmRecord;
- if (!record) return;
-
- if (!this.canCollectRecord(record)) {
- await this.huoquJilu(true, true);
- const refreshed = (this.data.recordList || []).find(
- r => String(r.id) === String(record.id)
- || String(r.tixianjilu_id) === String(record.tixianjilu_id)
- );
- if (refreshed) record = refreshed;
- }
- if (!this.canCollectRecord(record)) {
- wx.showModal({
- title: '暂时无法收款',
- content: '缺少审核单号或审核记录ID,请下拉刷新后重试。仍不行请联系客服。',
- showCancel: false,
- });
- return;
- }
-
- this.setData({ showCollectConfirm: false, submitting: true, collectConfirmRecord: record });
- try {
- const res = await request({
- url: '/yonghu/tixiansq',
- method: 'POST',
- data: {
- shenhe_danhao: record.shenhe_danhao,
- shenhe_jilu_id: record.shenhe_jilu_id || '',
- tixianjilu_id: record.tixianjilu_id || record.id || '',
- leixing: record.leixing,
- }
- });
- if (res.statusCode === 200 && res.data && res.data.code === 0) {
- const data = res.data.data;
- this.setData({
- currentTixianId: data.tixian_id,
- mchId: data.mch_id || '',
- collectConfirmRecord: record,
- });
- this.tiaoqiWeixinQueRen(data.package_info);
- } else {
- wx.showModal({ title: '收款失败', content: res.data?.msg || '无法发起收款,请稍后重试', showCancel: false });
- this.setData({ submitting: false, collectConfirmRecord: null });
- }
- } catch (err) {
- wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false });
- this.setData({ submitting: false, collectConfirmRecord: null });
- }
- },
-
- tiaoqiWeixinQueRen(packageInfo) {
- const appId = app.globalData.appId;
- const mchId = this.data.mchId;
- if (!appId || !mchId) {
- wx.showModal({ title: '配置错误', content: '无法调起收款,请联系客服', showCancel: false });
- this.setData({ submitting: false, collectConfirmRecord: null });
- return;
- }
- wx.requestMerchantTransfer({
- appId, mchId, package: packageInfo,
- success: () => { this.tongzhiHouduanQueRen(1); },
- fail: () => {
- this.tongzhiHouduanQueRen(0);
- wx.showModal({
- title: '确认收款失败',
- content: '微信收款确认失败,您可在记录中再次点击「收款」重试。',
- showCancel: false,
- });
- }
- });
- },
-
- async tongzhiHouduanQueRen(result) {
- if (!this.data.currentTixianId) {
- this.setData({ submitting: false, collectConfirmRecord: null });
- return;
- }
- const record = this.data.collectConfirmRecord;
- const wxConfirmed = result === 1;
-
- try {
- const res = await request({
- url: '/yonghu/tixianqr',
- method: 'POST',
- data: {
- tixian_id: this.data.currentTixianId,
- result: result,
- shenhe_danhao: record ? record.shenhe_danhao : '',
- shenhe_jilu_id: record ? (record.shenhe_jilu_id || '') : '',
- tixianjilu_id: record ? (record.tixianjilu_id || record.id || '') : '',
- leixing: record ? record.leixing : '',
- }
- });
- if (res.statusCode === 200 && res.data && res.data.code === 0) {
- const data = res.data.data || {};
- this.gengxinYue(data, record ? record.leixing : null);
- }
-
- // 微信已确认收款:不论 tixianqr 返回什么,都刷新列表,不弹系统异常
- if (wxConfirmed) {
- await this.finishWxCollectSuccess(record);
- } else if (res.statusCode === 200 && res.data && res.data.code === 0) {
- await this.loadAllAssets();
- this.huoquJilu(true);
- wx.showToast({
- title: '收款已取消',
- icon: 'none',
- duration: 3000,
- });
- } else {
- wx.showModal({
- title: '确认状态失败',
- content: res.data?.msg || '操作失败',
- showCancel: false,
- });
- }
- } catch (err) {
- if (wxConfirmed) {
- await this.finishWxCollectSuccess(record);
- } else {
- wx.showModal({
- title: '网络错误',
- content: '网络连接失败',
- showCancel: false,
- });
- }
- } finally {
- this.setData({ submitting: false, currentTixianId: null, collectConfirmRecord: null });
- }
- },
-
- onViewDetail(e) {
- const index = e.currentTarget.dataset.index;
- const record = this.data.recordList[index];
- if (!record || !record.canShowDetail) return;
- const status = parseInt(record.zhuangtai);
- let detailTitle = '失败原因';
- if (status === TX_STATUS.SHENHE_SHIBAI) detailTitle = '审核失败原因';
- else if (status === TX_STATUS.TIXIAN_SHIBAI) detailTitle = '提现失败原因';
this.setData({
- showDetailModal: true,
- detailTitle,
- detailContent: record.detailReason || '暂无详细信息',
+ showTixian: false,
+ selectedAsset: null,
+ tixianleixing: null,
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
});
},
- onCloseDetailModal() {
- this.setData({ showDetailModal: false, detailTitle: '', detailContent: '' });
- },
-
- onCloseTixian() {
- if (this.data.submitting) { wx.showToast({ title: '正在处理中,请稍后', icon: 'none' }); return; }
- this.setData({
- showTixian: false, selectedAsset: null, tixianleixing: null,
- tixianjine: '', shouxufei: '0.00', shijidaozhang: '0.00', submitting: false,
- });
- },
-
- async huoquJilu(fresh = false, force = false) {
- const now = Date.now();
- if (!force && now - lastPullDownTime < 2000 && !fresh) return;
- if (!force && (this.data.loading || this.data.isRefreshing)) return;
- const page = fresh ? 1 : this.data.page;
- if (fresh) this.setData({ nomore: false, canloadmore: true, isRefreshing: true });
- if (this.data.nomore && !fresh) return;
- this.setData({ loading: true });
- lastPullDownTime = now;
- try {
- const res = await request({
- url: '/yonghu/tixianjiluhq',
- method: 'POST',
- data: { page, limit: yemianshuju, mode: 2, zhuangtai: this.data.currentStatusFilter }
- });
- if (res.statusCode === 200 && res.data && res.data.code === 0) {
- const data = res.data.data;
- const processedList = (data.list || []).map(item => this.processRecordItem(item));
- const newList = fresh ? processedList : [...this.data.recordList, ...processedList];
- this.setData({
- recordList: newList,
- page: page + 1,
- nomore: !(data.has_more === true),
- canloadmore: data.has_more === true,
- loading: false,
- isRefreshing: false,
- });
- this.updatePendingCollectFlag(newList);
- } else {
- this.setData({ loading: false, isRefreshing: false });
- }
- } catch (err) {
- this.setData({ loading: false, isRefreshing: false });
- }
- },
-
- onReachBottom() {
- if (this.data.canloadmore && !this.data.nomore && !this.data.loading && !this.data.isRefreshing) {
- const now = Date.now();
- if (now - lastPullDownTime >= PULL_DOWN_INTERVAL) this.huoquJilu();
- }
- },
-
- stopPropagation() {}
- }
+ stopPropagation() {},
+ },
});
diff --git a/pages/withdraw/components/mode2/mode2.wxml b/pages/withdraw/components/mode2/mode2.wxml
index 9f1a5cb..a2081d6 100644
--- a/pages/withdraw/components/mode2/mode2.wxml
+++ b/pages/withdraw/components/mode2/mode2.wxml
@@ -1,113 +1,91 @@
-
-
-
-
-
-
-
-
- 可提总余额
- ¥{{totalAmount}}
-
-
- ← 左右滑动查看更多资产 →
-
-
-
-
- {{item.label}}
- ¥{{item.amount}}
- 费率 {{item.rate}}%
-
-
- 暂无可用资金
-
-
+
+
+
+
+
+
+ 微信零钱
+
-
-
-
-
-
-
- 您有审核通过的提现待收款,请点击「收款」按钮,在微信中主动确认后才能到账。
-
-
-
-
- {{item.label}}
+
+
+
+
+ {{item.label}}
+ ¥{{item.amount}}
-
-
-
-
- ¥{{item.jine}}
- {{item.create}}
-
-
- 微信零钱
- {{item.leixingLabel}}
-
-
-
-
- {{item.statusText}}
- 点击收款
-
-
- {{item.statusText}}
- 详情
-
- {{item.statusText}}
-
-
- 加载中...
- —— 没有更多了 ——
- 加载更多记录
- 暂无提现记录
-
+ 请先选择上方提现账户
+ 当前:{{selectedAsset.label}}
-
+
+
+
+ 当前可提现:
+ ¥
+ {{selectedAsset ? selectedAsset.amount : totalAmount}}
+
+
+ ¥
+
+ 全部提现
+
+
+
+ 提示:提现手续费
+ {{feeRateText}}
+ 。
+
+
+
+
+
+
+ 处理中...
+ 确认提现
+
+
+
+
+
+ 📢 提现须知
+ 🕒 提交后需等待后台审核,请耐心等待
+ 📌 审核通过后,请前往「提现记录」点击「收款」确认到账
+ 💰 每笔只能从单个账户提现,请先选择对应账户再填写金额
+ ✅ 提现方式仅支持微信零钱,暂不支持支付宝
+ 🎧 运营账户不足时暂时无法提现,请稍后再试或联系客服
+
-
+
-
+
- 提交后需等待审核,审核通过后请在本页点击「收款」确认到账
- 项目{{selectedAsset.label}}
+ 提交后需等待审核,审核通过后请在「提现记录」中点击「收款」确认到账
+ 身份{{selectedAsset.label}}
可提¥{{selectedAsset.amount}}
- 费率{{currentRate}}%
-
- 金额
-
-
-
- ¥{{item}}
-
+ 费率{{currentRate}}
+ 提现金额¥{{tixianjine}}
手续费 ¥{{shouxufei}}
到账 ¥{{shijidaozhang}}
@@ -120,33 +98,5 @@
-
-
-
-
-
- 审核已通过,{{collectConfirmRecord.leixingLabel}} ¥{{collectConfirmRecord.jine}}
- 请点击「去收款」,然后在微信弹窗中主动确认,资金才会打入您的微信零钱。
- 审核单号:{{collectConfirmRecord.shenhe_danhao}}
- 注意:审核通过≠已到账,必须您本人点击确认才能完成收款!
-
-
-
-
-
-
-
-
-
- {{detailContent}}
-
-
-
-
diff --git a/pages/withdraw/components/mode2/mode2.wxss b/pages/withdraw/components/mode2/mode2.wxss
index bbbe546..7fbbc66 100644
--- a/pages/withdraw/components/mode2/mode2.wxss
+++ b/pages/withdraw/components/mode2/mode2.wxss
@@ -1,408 +1,325 @@
-/* mode2 自动打款 - UI 完全复用 mode1 样式 */
-
page {
- background-color: #f5f7fb;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- height: 100%;
- }
-
- .app {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- padding: 0 24rpx 0;
- position: relative;
- z-index: 1;
- box-sizing: border-box;
- }
-
- .global-bg {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: -1;
- opacity: 0.1;
- object-fit: cover;
- filter: blur(1rpx);
- }
-
- .assets-section {
- margin-top: 24rpx;
- flex-shrink: 0;
- }
-
- .main-card {
- background: rgba(248, 250, 252, 0.88);
- backdrop-filter: blur(28rpx);
- -webkit-backdrop-filter: blur(28rpx);
- border-radius: 48rpx;
- padding: 30rpx 28rpx 24rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
- border: 1rpx solid rgba(255, 255, 255, 0.4);
- background-size: cover;
- }
-
- .balance-wrap {
- text-align: center;
- margin-bottom: 20rpx;
- }
- .balance-label {
- font-size: 28rpx;
- color: #0f172a;
- letter-spacing: 1px;
- display: block;
- margin-bottom: 10rpx;
- font-weight: 700;
- text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.8);
- }
- .balance-value {
- font-size: 68rpx;
- font-weight: 800;
- color: #0f172a;
- font-family: 'DIN', monospace;
- letter-spacing: -1rpx;
- text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.6);
- }
-
- .inner-divider {
- width: 60%;
- height: 2rpx;
- background: linear-gradient(90deg, transparent, #64748b, #64748b, transparent);
- margin: 0 auto 20rpx auto;
- border-radius: 2rpx;
- opacity: 0.9;
- }
-
- .assets-hint {
- display: block;
- text-align: center;
- font-size: 24rpx;
- color: #334155;
- margin-bottom: 14rpx;
- font-weight: 600;
- }
-
- .assets-scroll {
- width: 100%;
- white-space: nowrap;
- }
- .assets-track {
- display: inline-flex;
- gap: 16rpx;
- }
-
- .asset-tile {
- width: 170rpx;
- background: rgba(255, 255, 255, 0.75);
- backdrop-filter: blur(8rpx);
- border-radius: 28rpx;
- padding: 18rpx 12rpx;
- display: inline-flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- border: 1rpx solid rgba(255,255,255,0.5);
- box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02);
- transition: all 0.2s;
- white-space: normal;
- background-size: cover;
- background-position: center;
- }
- .asset-tile:active {
- background: rgba(255, 255, 255, 0.9);
- transform: scale(0.98);
- }
- .asset-name {
- font-size: 24rpx;
- font-weight: 700;
- color: #1e293b;
- margin-bottom: 10rpx;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.5);
- }
- .asset-balance {
- font-size: 28rpx;
- font-weight: 800;
- color: #2d6a4f;
- font-family: monospace;
- margin-bottom: 6rpx;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
- }
- .asset-fee {
- font-size: 20rpx;
- font-weight: 600;
- color: #475569;
- text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
- }
- .assets-empty {
- width: 400rpx;
- text-align: center;
- color: #a0abb9;
- padding: 40rpx 0;
- }
-
- .divider-line {
- height: 2rpx;
- background: linear-gradient(90deg, transparent, #cbd5e1, #cbd5e1, transparent);
- margin: 16rpx 0 20rpx;
- width: 80%;
- margin-left: auto;
- margin-right: auto;
- }
-
- .history-section {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
- margin-top: 0;
- }
- .history-header {
- display: flex;
- justify-content: space-between;
- align-items: baseline;
- padding: 0 8rpx 20rpx;
- flex-shrink: 0;
- }
- .history-title {
- font-size: 34rpx;
- font-weight: 600;
- color: #1e293b;
- }
- .history-scroll {
- flex: 1;
- width: 100%;
- padding: 0 20rpx;
- box-sizing: border-box;
- }
- .history-item {
- display: flex;
- align-items: center;
- padding: 28rpx 0;
- border-bottom: 1rpx solid rgba(0,0,0,0.05);
- }
- .history-info { width: 160rpx; }
- .history-amount {
- font-size: 36rpx;
- font-weight: 700;
- color: #1e293b;
- display: block;
- }
- .history-time {
- font-size: 22rpx;
- color: #94a3b8;
- }
- .history-detail {
- flex: 1;
- padding: 0 20rpx;
- }
- .history-method {
- font-size: 30rpx;
- color: #334155;
- display: block;
- margin-bottom: 6rpx;
- }
- .history-type {
- font-size: 24rpx;
- color: #94a3b8;
- }
- .history-status { text-align: right; }
-
- .status-badge {
- font-size: 26rpx;
- font-weight: 500;
- padding: 6rpx 14rpx;
- border-radius: 30rpx;
- display: inline-block;
- }
- .status-wait {
- color: #f59e0b;
- background: rgba(245,158,11,0.1);
- }
- .status-done {
- color: #10b981;
- background: rgba(16,185,129,0.1);
- }
- .status-fail {
- color: #ef4444;
- background: rgba(239,68,68,0.1);
- }
- .status-pending {
- color: #3b82f6;
- background: rgba(59,130,246,0.1);
- }
- .fail-link {
- margin-left: 8rpx;
- text-decoration: underline;
- }
- .collect-tappable {
- display: inline-flex;
- flex-direction: column;
- align-items: center;
- gap: 4rpx;
- padding: 10rpx 18rpx;
- cursor: pointer;
- border: 2rpx solid rgba(59,130,246,0.35);
- box-shadow: 0 4rpx 12rpx rgba(59,130,246,0.15);
- }
- .collect-tappable:active {
- transform: scale(0.97);
- opacity: 0.9;
- }
- .collect-sub {
- font-size: 22rpx;
- font-weight: 700;
- color: #1d4ed8;
- text-decoration: underline;
- }
-
- .load-tip, .more-tip {
- text-align: center;
- padding: 30rpx;
- font-size: 24rpx;
- color: #94a3b8;
- }
- .load-more-btn {
- margin: 16rpx 0 20rpx;
- padding: 20rpx;
- text-align: center;
- background: rgba(255,255,255,0.7);
- backdrop-filter: blur(8rpx);
- border-radius: 40rpx;
- font-size: 28rpx;
- color: #3b82f6;
- border: 1rpx solid rgba(255,255,255,0.5);
- }
- .load-more-btn:active { background: rgba(255,255,255,0.9); }
- .safe-bottom { height: 12rpx; flex-shrink: 0; }
-
- /* 自动打款专属(少量追加) */
- .pending-tip {
- margin: 0 8rpx 16rpx;
- padding: 16rpx 20rpx;
- font-size: 24rpx;
- color: #1d4ed8;
- background: rgba(59,130,246,0.08);
- border-radius: 20rpx;
- line-height: 1.5;
- }
- .filter-scroll {
- width: 100%;
- white-space: nowrap;
- margin-bottom: 12rpx;
- }
- .filter-track {
- display: inline-flex;
- gap: 12rpx;
- padding: 0 8rpx;
- }
- .filter-chip {
- flex-shrink: 0;
- padding: 10rpx 22rpx;
- font-size: 24rpx;
- color: #64748b;
- background: rgba(255,255,255,0.8);
- border-radius: 30rpx;
- border: 1rpx solid rgba(0,0,0,0.06);
- }
- .filter-chip.active {
- color: #3b82f6;
- background: #eff6ff;
- border-color: #3b82f6;
- }
- .auto-tip {
- font-size: 24rpx;
- color: #3b82f6;
- margin-bottom: 20rpx;
- line-height: 1.5;
- }
- .warn-tip {
- font-size: 24rpx;
- color: #f59e0b;
- margin-top: 16rpx;
- font-weight: 600;
- }
-
- /* 弹窗(与 mode1 一致) */
- .modal-mask {
- position: fixed;
- top: 0; left: 0; right: 0; bottom: 0;
- background: rgba(0,0,0,0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
- }
- .modal-dialog {
- width: 600rpx;
- background: rgba(255,255,255,0.96);
- backdrop-filter: blur(20rpx);
- border-radius: 48rpx;
- overflow: hidden;
- box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.1);
- border: 1rpx solid rgba(255,255,255,0.6);
- }
- .modal-header {
- padding: 36rpx 32rpx 20rpx;
- font-size: 36rpx;
- font-weight: 700;
- border-bottom: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-body {
- padding: 32rpx;
- font-size: 28rpx;
- color: #334155;
- line-height: 1.6;
- }
- .info-row, .amount-row {
- display: flex;
- justify-content: space-between;
- margin-bottom: 24rpx;
- font-size: 28rpx;
- }
- .amount-row input {
- border: 1rpx solid rgba(0,0,0,0.1);
- border-radius: 28rpx;
- padding: 16rpx 20rpx;
- width: 260rpx;
- background: rgba(255,255,255,0.9);
- }
- .quick-row {
- display: flex;
- gap: 16rpx;
- margin: 24rpx 0;
- }
- .quick-chip {
- flex: 1;
- background: rgba(241,245,249,0.8);
- text-align: center;
- padding: 12rpx;
- border-radius: 40rpx;
- font-size: 28rpx;
- }
- .fee-row {
- display: flex;
- justify-content: space-between;
- background: rgba(248,250,252,0.8);
- padding: 20rpx;
- border-radius: 28rpx;
- margin: 20rpx 0;
- }
- .modal-footer {
- display: flex;
- border-top: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-btn {
- flex: 1;
- text-align: center;
- padding: 28rpx;
- font-size: 30rpx;
- }
- .modal-btn.cancel {
- color: #8f9bb3;
- border-right: 1rpx solid rgba(0,0,0,0.05);
- }
- .modal-btn.confirm { color: #3b82f6; }
-
\ No newline at end of file
+ background: #f5f5f5;
+ min-height: 100vh;
+}
+
+.ref-page {
+ min-height: 100vh;
+ padding: 24rpx 24rpx 48rpx;
+ box-sizing: border-box;
+}
+
+/* 提现方式 Tab */
+.method-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 0 32rpx;
+ margin-bottom: 20rpx;
+}
+
+.method-tab {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 28rpx 16rpx 20rpx;
+ position: relative;
+}
+
+.method-tab-icon {
+ width: 48rpx;
+ height: 48rpx;
+ margin-bottom: 8rpx;
+}
+
+.method-tab-text {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 500;
+}
+
+.method-tab-line {
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80rpx;
+ height: 6rpx;
+ background: #FFD54F;
+ border-radius: 3rpx;
+}
+
+/* 账户选择 */
+.account-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 20rpx 16rpx 16rpx;
+ margin-bottom: 20rpx;
+}
+
+.account-scroll {
+ white-space: nowrap;
+ display: flex;
+ flex-direction: row;
+}
+
+.account-chip {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16rpx 24rpx;
+ margin-right: 16rpx;
+ border-radius: 12rpx;
+ background: #f8f8f8;
+ border: 2rpx solid transparent;
+ min-width: 160rpx;
+}
+
+.account-chip--active {
+ background: #fffbeb;
+ border-color: #FFD54F;
+}
+
+.account-chip--disabled {
+ opacity: 0.45;
+}
+
+.chip-label {
+ font-size: 24rpx;
+ color: #666;
+ margin-bottom: 4rpx;
+}
+
+.chip-amount {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 600;
+}
+
+.account-warn {
+ display: block;
+ margin-top: 12rpx;
+ font-size: 24rpx;
+ color: #ff8c00;
+ padding: 0 8rpx;
+}
+
+.account-ok {
+ display: block;
+ margin-top: 12rpx;
+ font-size: 24rpx;
+ color: #888;
+ padding: 0 8rpx;
+}
+
+/* 金额卡片 */
+.amount-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 32rpx 32rpx 28rpx;
+ margin-bottom: 32rpx;
+}
+
+.avail-row {
+ display: flex;
+ align-items: baseline;
+ margin-bottom: 32rpx;
+}
+
+.avail-label {
+ font-size: 28rpx;
+ color: #333;
+}
+
+.avail-symbol {
+ font-size: 28rpx;
+ color: #ff8c00;
+ margin-left: 4rpx;
+}
+
+.avail-amount {
+ font-size: 32rpx;
+ color: #ff8c00;
+ font-weight: 700;
+}
+
+.input-row {
+ display: flex;
+ align-items: center;
+ padding-bottom: 8rpx;
+}
+
+.input-symbol {
+ font-size: 64rpx;
+ font-weight: 700;
+ color: #333;
+ line-height: 1;
+ margin-right: 8rpx;
+}
+
+.amount-input {
+ flex: 1;
+ font-size: 56rpx;
+ font-weight: 600;
+ color: #333;
+ height: 80rpx;
+ min-height: 80rpx;
+}
+
+.amount-placeholder {
+ color: #ccc;
+ font-size: 40rpx;
+ font-weight: 400;
+}
+
+.withdraw-all {
+ font-size: 28rpx;
+ color: #ff8c00;
+ padding: 8rpx 0 8rpx 16rpx;
+ flex-shrink: 0;
+}
+
+.input-divider {
+ height: 1rpx;
+ background: #eee;
+ margin: 16rpx 0 20rpx;
+}
+
+.fee-tip {
+ font-size: 26rpx;
+ color: #666;
+}
+
+.fee-highlight {
+ color: #ff8c00;
+ font-weight: 600;
+}
+
+/* 确认按钮 */
+.submit-wrap {
+ padding: 0 8rpx;
+ margin-bottom: 32rpx;
+}
+
+.confirm-btn {
+ width: 100%;
+ height: 96rpx;
+ background: linear-gradient(90deg, #FFD54F 0%, #FFB300 100%);
+ border-radius: 48rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #333;
+ box-shadow: 0 8rpx 20rpx rgba(255, 179, 0, 0.35);
+}
+
+.confirm-btn:active {
+ opacity: 0.92;
+ transform: scale(0.99);
+}
+
+.confirm-btn--disabled {
+ background: linear-gradient(90deg, #e0e0e0, #bdbdbd);
+ box-shadow: none;
+ color: #999;
+}
+
+/* 须知 */
+.notice-box {
+ background: #ebebeb;
+ border-radius: 16rpx;
+ padding: 28rpx 28rpx 32rpx;
+}
+
+.notice-title {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 600;
+ margin-bottom: 20rpx;
+}
+
+.notice-item {
+ font-size: 26rpx;
+ color: #555;
+ line-height: 1.7;
+ margin-bottom: 8rpx;
+}
+
+/* 确认弹窗 */
+.modal-mask {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1001;
+}
+
+.modal-dialog {
+ width: 620rpx;
+ background: #fff;
+ border-radius: 20rpx;
+ overflow: hidden;
+}
+
+.modal-header {
+ padding: 32rpx;
+ font-size: 34rpx;
+ font-weight: 700;
+ text-align: center;
+ border-bottom: 1rpx solid #f0f0f0;
+}
+
+.modal-body {
+ padding: 32rpx;
+ font-size: 28rpx;
+ color: #333;
+}
+
+.auto-tip {
+ font-size: 24rpx;
+ color: #ff8c00;
+ margin-bottom: 20rpx;
+ line-height: 1.5;
+}
+
+.info-row {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+}
+
+.fee-row {
+ display: flex;
+ justify-content: space-between;
+ background: #fff8e1;
+ padding: 20rpx;
+ border-radius: 12rpx;
+ margin-top: 16rpx;
+ color: #333;
+}
+
+.modal-footer {
+ display: flex;
+ border-top: 1rpx solid #f0f0f0;
+}
+
+.modal-btn {
+ flex: 1;
+ text-align: center;
+ padding: 28rpx;
+ font-size: 30rpx;
+}
+
+.modal-btn.cancel {
+ color: #999;
+ border-right: 1rpx solid #f0f0f0;
+}
+
+.modal-btn.confirm {
+ color: #ff8c00;
+ font-weight: 600;
+}
diff --git a/pages/withdraw/components/record-mode1/record-mode1.js b/pages/withdraw/components/record-mode1/record-mode1.js
new file mode 100644
index 0000000..08598ab
--- /dev/null
+++ b/pages/withdraw/components/record-mode1/record-mode1.js
@@ -0,0 +1,243 @@
+// pages/withdraw/components/record-mode1/record-mode1.js
+// 子组件版本 - 完整代码,仅适配生命周期,业务逻辑不动
+
+import request from '../../../../utils/request.js';
+import upload from '../../../../utils/upload.js';
+import PopupService from '../../../../services/popupService.js';
+
+const app = getApp();
+const PAGE_SIZE = 10;
+let lastPullDownTime = 0;
+const PULL_DOWN_INTERVAL = 2000;
+
+Component({
+ data: {
+ imgUrls: {
+ pageBg: '',
+ cardBg: '',
+ iconWechat: '',
+ iconAlipay: '',
+ iconRecord: '',
+ iconRefresh: '',
+ },
+ assetList: [],
+ totalAmount: '0.00',
+ selectedAsset: null,
+ txfangshi: null,
+ txdianhua: '',
+ txzh: '',
+ txtupian: '',
+ ossImageUrl: '',
+ showTixianModal: false,
+ tixianAmount: '',
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
+ currentRate: '0.00',
+ recordList: [],
+ page: 1,
+ nomore: false,
+ loading: false,
+ isRefreshing: false,
+ canloadmore: true,
+ showSkfsModal: false,
+ tempTxfangshi: null,
+ tempTxPhone: '',
+ tempTxAccount: '',
+ tempTxImage: '',
+ choosingImage: false,
+ showModifyModal: false,
+ modifyingRecord: null,
+ modifyTxfangshi: null,
+ modifyTxPhone: '',
+ modifyTxAccount: '',
+ modifyTxImage: '',
+ modifyImageUrl: '',
+ showFailModal: false,
+ currentFailReason: '',
+ isLoading: false,
+ },
+
+ attached() {
+ this.initImageUrls();
+ this.loadWithdrawRecords(true);
+ },
+
+ pageLifetimes: {
+ show() {
+ this.registerNotification();
+ PopupService.checkAndShow(this, 'tixian');
+ },
+ hide() {
+ const popup = this.selectComponent('#popupNotice');
+ popup?.cleanup?.();
+ }
+ },
+
+ methods: {
+ onPullDownRefresh() {
+ return this.loadWithdrawRecords(true);
+ },
+
+ onLoadMoreFromScroll() {
+ this.loadMoreRecords();
+ },
+
+ loadMoreRecords() {
+ if (this.data.nomore) {
+ wx.showToast({ title: '没有更多记录了', icon: 'none' });
+ return;
+ }
+ if (this.data.loading) return;
+ this.loadWithdrawRecords();
+ },
+
+ initImageUrls() {
+ const ossBase = app.globalData.ossImageUrl || '';
+ const imgDir = `${ossBase}beijing/tixian/`;
+ this.setData({
+ imgUrls: {
+ pageBg: `${imgDir}page_bg.png`,
+ cardBg: `${imgDir}card_bg.png`,
+ iconWechat: `${imgDir}icon_wechat.png`,
+ iconAlipay: `${imgDir}icon_alipay.png`,
+ iconRecord: `${imgDir}icon_record.png`,
+ iconRefresh: `${imgDir}icon_refresh.png`,
+ assetTileBg: `${imgDir}asset_tile_bg.png`,
+ }
+ });
+ },
+
+ async loadWithdrawRecords(refresh = false) {
+ const now = Date.now();
+ if (now - lastPullDownTime < PULL_DOWN_INTERVAL && !refresh) return;
+ if (this.data.loading || this.data.isRefreshing) return;
+ const page = refresh ? 1 : this.data.page;
+ if (this.data.nomore && !refresh) return;
+ this.setData({ loading: true, isRefreshing: refresh });
+ lastPullDownTime = now;
+ try {
+ const res = await request({ url: '/yonghu/tixianjiluhq', method: 'POST', data: { page, limit: PAGE_SIZE } });
+ if (res?.data?.code === 0) {
+ const list = (res.data.data.list || []).map(item => ({
+ ...item,
+ statusText: this.getStatusText(item.zhuangtai),
+ statusColor: this.getStatusColor(item.zhuangtai)
+ }));
+ const newList = refresh ? list : [...this.data.recordList, ...list];
+ const hasMore = res.data.data.has_more === true;
+ this.setData({
+ recordList: newList, page: page + 1, nomore: !hasMore, canloadmore: hasMore,
+ loading: false, isRefreshing: false
+ });
+ } else {
+ this.setData({ loading: false, isRefreshing: false });
+ }
+ } catch (err) {
+ this.setData({ loading: false, isRefreshing: false });
+ }
+ },
+
+ onModifyRecord(e) {
+ const record = e.currentTarget.dataset.record;
+ if (parseInt(record.zhuangtai) !== 1) {
+ wx.showToast({ title: '只有审核中的记录可修改', icon: 'none' });
+ return;
+ }
+ this.setData({
+ modifyingRecord: record,
+ modifyTxfangshi: record.fangshi,
+ modifyTxPhone: record.txdianhua || '',
+ modifyTxAccount: record.txzh || '',
+ modifyTxImage: '',
+ modifyImageUrl: record.txtupian ? (app.globalData.ossImageUrl + record.txtupian) : '',
+ showModifyModal: true
+ });
+ },
+
+ onSelectModifyFangshi(e) { this.setData({ modifyTxfangshi: e.currentTarget.dataset.fangshi }); },
+ onModifyPhoneInput(e) { this.setData({ modifyTxPhone: e.detail.value }); },
+ onModifyAccountInput(e) { this.setData({ modifyTxAccount: e.detail.value }); },
+
+ onChooseModifyImage() {
+ if (this.data.choosingImage) return;
+ this.setData({ choosingImage: true });
+ wx.chooseMedia({
+ count: 1, mediaType: ['image'],
+ success: (res) => { this.setData({ modifyTxImage: res.tempFiles[0].tempFilePath }); },
+ complete: () => { this.setData({ choosingImage: false }); }
+ });
+ },
+
+ onPreviewModifyImage() {
+ if (this.data.modifyTxImage) wx.previewImage({ urls: [this.data.modifyTxImage] });
+ else if (this.data.modifyImageUrl) wx.previewImage({ urls: [this.data.modifyImageUrl] });
+ },
+
+ onDeleteModifyImage() { this.setData({ modifyTxImage: '' }); },
+
+ async onConfirmModify() {
+ const { modifyTxfangshi, modifyTxPhone, modifyTxAccount, modifyTxImage, modifyingRecord } = this.data;
+ if (!modifyTxfangshi) { wx.showToast({ title: '请选择提现方式', icon: 'none' }); return; }
+ if (!modifyTxPhone) { wx.showToast({ title: '请输入收款人电话', icon: 'none' }); return; }
+ if (modifyTxfangshi == 1 && !modifyTxImage) { wx.showToast({ title: '请上传微信收款码', icon: 'none' }); return; }
+ if (modifyTxfangshi == 2 && !modifyTxAccount && !modifyTxImage) {
+ wx.showToast({ title: '请填写支付宝账号或上传收款码', icon: 'none' }); return;
+ }
+ const formData = { tixian_id: modifyingRecord.id, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '' };
+ try {
+ const res = await upload({ url: '/yonghu/yonghutxshxg', formData, filePath: modifyTxImage || null, fileName: 'file' });
+ if (res?.data?.code === 0) {
+ const data = res.data.data;
+ const newList = this.data.recordList.map(item => {
+ if (item.id === modifyingRecord.id) {
+ return { ...item, fangshi: modifyTxfangshi, txdianhua: modifyTxPhone, txzh: modifyTxAccount || '', txtupian: data.txtupian || modifyingRecord.txtupian };
+ }
+ return item;
+ });
+ this.setData({ recordList: newList, showModifyModal: false, modifyingRecord: null });
+ wx.showToast({ title: '修改成功', icon: 'success' });
+ } else {
+ wx.showToast({ title: res?.data?.msg || '修改失败', icon: 'none' });
+ }
+ } catch (err) {
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ },
+
+ onCloseModifyModal() { this.setData({ showModifyModal: false, modifyingRecord: null }); },
+
+ onViewFailReason(e) {
+ const record = e.currentTarget.dataset.record;
+ const reason = record.fail_reason || record.shibaiyuanyin || '暂无详细信息';
+ this.setData({ currentFailReason: reason, showFailModal: true });
+ },
+
+ onCloseFailModal() { this.setData({ showFailModal: false }); },
+
+ getStatusText(zhuangtai) {
+ const s = parseInt(zhuangtai);
+ if (s === 1) return '审核中';
+ if (s === 2) return '成功';
+ if (s === 3) return '失败';
+ return '未知';
+ },
+ getStatusColor(zhuangtai) {
+ const s = parseInt(zhuangtai);
+ if (s === 1) return '#F5A623';
+ if (s === 2) return '#2ED158';
+ if (s === 3) return '#FF4D4F';
+ return '#999';
+ },
+
+ registerNotification() {
+ const comp = this.selectComponent('#global-notification');
+ if (comp?.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => comp.showNotification(data),
+ hide: () => comp.hideNotification()
+ };
+ }
+ },
+ stopPropagation() {}
+ }
+});
\ No newline at end of file
diff --git a/pages/withdraw/components/record-mode1/record-mode1.json b/pages/withdraw/components/record-mode1/record-mode1.json
new file mode 100644
index 0000000..60741f8
--- /dev/null
+++ b/pages/withdraw/components/record-mode1/record-mode1.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "global-notification": "/components/global-notification/global-notification",
+ "popup-notice": "/components/popup-notice/popup-notice"
+ }
+}
diff --git a/pages/withdraw/components/record-mode1/record-mode1.wxml b/pages/withdraw/components/record-mode1/record-mode1.wxml
new file mode 100644
index 0000000..b8df4c1
--- /dev/null
+++ b/pages/withdraw/components/record-mode1/record-mode1.wxml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+ ¥{{item.jine}}
+ {{item.create}}
+
+
+ {{item.fangshi == 1 ? '微信' : '支付宝'}}
+ {{item.leixing == 1 ? '佣金' : (item.leixing == 2 ? '分红' : (item.leixing == 3 ? '组长' : (item.leixing == 4 ? '考核官' : '保证金')))}}
+
+
+ {{item.statusText}} ✏修改
+
+ {{item.statusText}}
+ 详情
+
+ {{item.statusText}}
+
+
+ 加载中...
+ —— 没有更多了 ——
+ 加载更多记录
+ 暂无提现记录
+
+
+
+
+
+
+
+
+
+
+ 微信支付宝
+
+
+ + 上传新图片预览删除
+
+
+
+
+
+
+
+
+ {{currentFailReason}}
+
+
+
+
+
+
diff --git a/pages/withdraw/components/record-mode1/record-mode1.wxss b/pages/withdraw/components/record-mode1/record-mode1.wxss
new file mode 100644
index 0000000..7341d35
--- /dev/null
+++ b/pages/withdraw/components/record-mode1/record-mode1.wxss
@@ -0,0 +1,67 @@
+@import "../record-mode2/record-mode2.wxss";
+
+.history-section--full {
+ flex: 1;
+ min-height: calc(100vh - 48rpx);
+ margin-top: 24rpx;
+}
+
+.history-section--full .history-scroll {
+ height: calc(100vh - 200rpx);
+}
+
+.toggle-row {
+ display: flex;
+ gap: 16rpx;
+ margin-bottom: 20rpx;
+}
+
+.toggle-item {
+ flex: 1;
+ text-align: center;
+ padding: 16rpx;
+ border-radius: 12rpx;
+ background: #f1f5f9;
+ font-size: 28rpx;
+ color: #64748b;
+}
+
+.toggle-item.active {
+ background: #eff6ff;
+ color: #3b82f6;
+ font-weight: 600;
+}
+
+.field-input {
+ width: 100%;
+ box-sizing: border-box;
+ padding: 20rpx;
+ border: 1rpx solid #e2e8f0;
+ border-radius: 12rpx;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+}
+
+.upload-trigger {
+ padding: 40rpx;
+ text-align: center;
+ border: 2rpx dashed #cbd5e1;
+ border-radius: 12rpx;
+ color: #64748b;
+ font-size: 28rpx;
+}
+
+.image-preview image {
+ width: 100%;
+ height: 240rpx;
+ border-radius: 12rpx;
+}
+
+.image-actions {
+ display: flex;
+ gap: 24rpx;
+ justify-content: center;
+ margin-top: 12rpx;
+ font-size: 26rpx;
+ color: #3b82f6;
+}
diff --git a/pages/withdraw/components/record-mode2/record-mode2.js b/pages/withdraw/components/record-mode2/record-mode2.js
new file mode 100644
index 0000000..6d441ae
--- /dev/null
+++ b/pages/withdraw/components/record-mode2/record-mode2.js
@@ -0,0 +1,513 @@
+// pages/withdraw/components/record-mode2/record-mode2.js
+// UI 与 mode1 完全一致,业务逻辑为自动打款审核收款
+import request from '../../../../utils/request.js';
+import PopupService from '../../../../services/popupService.js';
+
+const app = getApp();
+const yemianshuju = 5;
+let lastPullDownTime = 0;
+const PULL_DOWN_INTERVAL = 2000;
+
+const TX_STATUS = {
+ SHENHEZHONG: 1,
+ TIXIAN_CHENGGONG: 2,
+ TIXIAN_SHIBAI: 3,
+ SHENHE_CHENGGONG: 4,
+ SHENHE_SHIBAI: 5,
+ DAI_SHOUKUAN: 6,
+};
+
+const ASSET_CONFIG = {
+ dashou_yue: { leixing: 1, label: '接单员佣金' },
+ guanshi_fenyong: { leixing: 2, label: '管事分红' },
+ zuzhang_fenyong: { leixing: 3, label: '组长分红' },
+ kaoheguan_fenyong: { leixing: 4, label: '考核官分佣' },
+ dashou_yajin: { leixing: 5, label: '接单员保证金' },
+ shangjia_yue: { leixing: 6, label: '商家余额' },
+};
+
+const LEIXING_LABEL = {
+ 1: '接单员佣金', 2: '管事分红', 3: '组长分红',
+ 4: '考核官分佣', 5: '接单员保证金', 6: '商家余额',
+};
+
+Component({
+ properties: { options: { type: Object, value: {} } },
+ data: {
+ imgUrls: {
+ pageBg: '', cardBg: '', assetTileBg: '',
+ },
+ assetList: [],
+ totalAmount: '0.00',
+ selectedAsset: null,
+ isLoadingAssets: false,
+ tixianleixing: null,
+ tixianjine: '',
+ currentRate: '0.00',
+ showTixian: false,
+ recordList: [],
+ page: 1,
+ loading: false,
+ nomore: false,
+ canloadmore: true,
+ isRefreshing: false,
+ shouxufei: '0.00',
+ shijidaozhang: '0.00',
+ currentTixianId: null,
+ submitting: false,
+ mchId: '',
+ currentStatusFilter: 0,
+ statusTabs: [
+ { value: 0, label: '全部' },
+ { value: 1, label: '审核中' },
+ { value: 6, label: '待收款' },
+ { value: 4, label: '审核成功' },
+ { value: 5, label: '审核失败' },
+ { value: 2, label: '提现成功' },
+ { value: 3, label: '提现失败' },
+ ],
+ hasPendingCollect: false,
+ showCollectConfirm: false,
+ collectConfirmRecord: null,
+ showDetailModal: false,
+ detailTitle: '',
+ detailContent: '',
+ },
+ lifetimes: {
+ attached() {
+ this.initImageUrls();
+ this.huoquJilu(true);
+ }
+ },
+ pageLifetimes: {
+ show() {
+ this.registerNotificationComponent();
+ PopupService.checkAndShow(this, 'tixian');
+ },
+ hide() {
+ const popupComp = this.selectComponent('#popupNotice');
+ if (popupComp && popupComp.cleanup) popupComp.cleanup();
+ }
+ },
+ methods: {
+ registerNotificationComponent() {
+ const notificationComp = this.selectComponent('#global-notification');
+ if (notificationComp && notificationComp.showNotification) {
+ app.globalData.globalNotification = {
+ show: (data) => notificationComp.showNotification(data),
+ hide: () => notificationComp.hideNotification()
+ };
+ }
+ },
+
+ initImageUrls() {
+ const ossBase = app.globalData.ossImageUrl || '';
+ const imgDir = `${ossBase}beijing/tixian/`;
+ this.setData({
+ imgUrls: {
+ pageBg: `${imgDir}page_bg.png`,
+ cardBg: `${imgDir}card_bg.png`,
+ assetTileBg: `${imgDir}asset_tile_bg.png`,
+ }
+ });
+ },
+
+ parseZhuangtai(item) {
+ const raw = item.zhuangtai ?? item.status ?? item.state;
+ const n = parseInt(raw, 10);
+ return Number.isNaN(n) ? -1 : n;
+ },
+
+ /** 规范化列表字段(兼容后端多种命名 / 嵌套 audit) */
+ normalizeRecordFields(item) {
+ const audit = item.audit || item.shenhe || item.shenhe_info || {};
+ const shenheJiluId = item.shenhe_jilu_id ?? item.shenheJiluId
+ ?? item.audit_id ?? item.shenheid ?? audit.id ?? audit.shenhe_jilu_id ?? null;
+ const shenheDanhao = String(
+ item.shenhe_danhao || item.shenheDanhao || item.audit_shenhe_danhao
+ || audit.shenhe_danhao || audit.danhao || ''
+ ).trim();
+ const tixianjiluId = item.tixianjilu_id ?? item.tixianjiluId ?? item.id ?? null;
+ const zhuangtai = this.parseZhuangtai(item);
+ return {
+ ...item,
+ zhuangtai: zhuangtai >= 0 ? zhuangtai : item.zhuangtai,
+ shenhe_jilu_id: shenheJiluId,
+ shenhe_danhao: shenheDanhao,
+ tixianjilu_id: tixianjiluId,
+ };
+ },
+
+ hasAuditJiluId(item) {
+ const id = item.shenhe_jilu_id;
+ return id !== null && id !== undefined && id !== '' && id !== 0 && id !== '0';
+ },
+
+ hasShenheDanhao(item) {
+ return !!(item.shenhe_danhao && String(item.shenhe_danhao).trim());
+ },
+
+ isNewAuditRecord(item) {
+ return this.hasAuditJiluId(item) && this.hasShenheDanhao(item);
+ },
+
+ /** 待收款是否可点击:状态6 + 审核记录ID + 审核单号 缺一不可 */
+ canCollectRecord(item) {
+ return this.parseZhuangtai(item) === TX_STATUS.DAI_SHOUKUAN
+ && this.hasAuditJiluId(item)
+ && this.hasShenheDanhao(item);
+ },
+
+ getLeixingLabel(leixing) {
+ return LEIXING_LABEL[parseInt(leixing)] || '提现';
+ },
+
+ getStatusBadgeClass(status) {
+ switch (parseInt(status)) {
+ case TX_STATUS.SHENHEZHONG: return 'status-wait';
+ case TX_STATUS.TIXIAN_CHENGGONG:
+ case TX_STATUS.SHENHE_CHENGGONG: return 'status-done';
+ case TX_STATUS.DAI_SHOUKUAN: return 'status-pending';
+ case TX_STATUS.TIXIAN_SHIBAI:
+ case TX_STATUS.SHENHE_SHIBAI: return 'status-fail';
+ default: return 'status-wait';
+ }
+ },
+
+ processRecordItem(item) {
+ item = this.normalizeRecordFields(item);
+ const isNew = this.isNewAuditRecord(item);
+ const status = this.parseZhuangtai(item);
+ let statusText = '未知';
+ let canCollect = false;
+ let canShowDetail = false;
+ let detailReason = '';
+
+ switch (status) {
+ case TX_STATUS.SHENHEZHONG: statusText = '审核中'; break;
+ case TX_STATUS.TIXIAN_CHENGGONG: statusText = '提现成功'; break;
+ case TX_STATUS.TIXIAN_SHIBAI:
+ statusText = '提现失败';
+ if (item.fail_reason || item.bhliyou) {
+ canShowDetail = true;
+ detailReason = item.fail_reason || item.bhliyou;
+ }
+ break;
+ case TX_STATUS.SHENHE_CHENGGONG: statusText = '审核成功'; break;
+ case TX_STATUS.SHENHE_SHIBAI:
+ statusText = '审核失败';
+ if (item.bhliyou) { canShowDetail = true; detailReason = item.bhliyou; }
+ break;
+ case TX_STATUS.DAI_SHOUKUAN:
+ statusText = '待收款';
+ canCollect = this.canCollectRecord(item);
+ break;
+ }
+
+ return {
+ ...item,
+ isNewAudit: isNew,
+ leixingLabel: this.getLeixingLabel(item.leixing),
+ statusText,
+ statusBadgeClass: this.getStatusBadgeClass(status),
+ canCollect,
+ canShowDetail,
+ detailReason,
+ };
+ },
+
+ gengxinYue(data, leixing) {
+ if (!data) return;
+ if (data.new_yongjin !== undefined && data.new_yongjin !== null) {
+ app.globalData.yongjin = data.new_yongjin;
+ }
+ if (data.new_fenyong !== undefined && data.new_fenyong !== null) {
+ app.globalData.guanshi.fenyongtixian = data.new_fenyong;
+ }
+ if (data.new_yajin !== undefined && data.new_yajin !== null) {
+ app.globalData.yajin = data.new_yajin;
+ }
+ if (data.new_shangjia_yue !== undefined && data.new_shangjia_yue !== null) {
+ if (app.globalData.shangjia) app.globalData.shangjia.sjyue = data.new_shangjia_yue;
+ }
+ if (data.current_rate !== undefined && leixing) {
+ const rate = parseFloat(data.current_rate);
+ const rateKeyMap = { 1: 'dashouRate', 5: 'dashou_yajin_rate', 6: 'shangjia_rate', 2: 'guanshi_rate', 3: 'zuzhang_rate', 4: 'kaoheguan_rate' };
+ const key = rateKeyMap[leixing];
+ if (key) wx.setStorageSync(key, rate);
+ }
+ },
+
+ updatePendingCollectFlag(list) {
+ const hasPending = (list || []).some(item => item.canCollect);
+ if (hasPending !== this.data.hasPendingCollect) {
+ this.setData({ hasPendingCollect: hasPending });
+ }
+ },
+
+ /** 微信确认收款成功后,本地先把对应记录标为「提现成功」 */
+ markLocalRecordWithdrawSuccess(record) {
+ if (!record) return;
+ const matchId = String(record.tixianjilu_id || record.id || '');
+ const matchDanhao = String(record.shenhe_danhao || '').trim();
+ if (!matchId && !matchDanhao) return;
+
+ const newList = (this.data.recordList || []).map((item) => {
+ const itemId = String(item.tixianjilu_id || item.id || '');
+ const itemDanhao = String(item.shenhe_danhao || '').trim();
+ const isMatch = (matchId && itemId === matchId)
+ || (matchDanhao && itemDanhao === matchDanhao);
+ if (!isMatch) return item;
+ return this.processRecordItem({
+ ...item,
+ zhuangtai: TX_STATUS.TIXIAN_CHENGGONG,
+ });
+ });
+ this.setData({ recordList: newList });
+ this.updatePendingCollectFlag(newList);
+ },
+
+ async finishWxCollectSuccess(record) {
+ this.markLocalRecordWithdrawSuccess(record);
+ await this.huoquJilu(true, true);
+ this.markLocalRecordWithdrawSuccess(record);
+ PopupService.checkAndShow(this, 'tixianchenggong');
+ wx.showToast({
+ title: '提现成功',
+ icon: 'success',
+ duration: 3000,
+ });
+ },
+
+ onPullDownRefresh() {
+ return this.huoquJilu(true, true);
+ },
+
+ onStatusFilterTap(e) {
+ const value = parseInt(e.currentTarget.dataset.value, 10);
+ if (value === this.data.currentStatusFilter) return;
+ this.setData({ currentStatusFilter: value });
+ this.huoquJilu(true);
+ },
+
+ onCollectTap(e) {
+ const index = e.currentTarget.dataset.index;
+ const record = this.data.recordList[index];
+ if (!record) return;
+ if (this.parseZhuangtai(record) !== TX_STATUS.DAI_SHOUKUAN) {
+ wx.showToast({ title: '当前状态不可收款', icon: 'none' });
+ return;
+ }
+ if (!this.hasShenheDanhao(record) || !this.hasAuditJiluId(record)) {
+ wx.showToast({ title: '审核信息不完整,请刷新后重试', icon: 'none' });
+ return;
+ }
+ if (this.data.submitting) {
+ wx.showToast({ title: '正在处理中,请稍后', icon: 'none' });
+ return;
+ }
+ this.setData({ showCollectConfirm: true, collectConfirmRecord: record });
+ },
+
+ onCloseCollectConfirm() {
+ if (this.data.submitting) return;
+ this.setData({ showCollectConfirm: false, collectConfirmRecord: null });
+ },
+
+ async onConfirmCollect() {
+ if (this.data.submitting) return;
+ let record = this.data.collectConfirmRecord;
+ if (!record) return;
+
+ if (!this.canCollectRecord(record)) {
+ await this.huoquJilu(true, true);
+ const refreshed = (this.data.recordList || []).find(
+ r => String(r.id) === String(record.id)
+ || String(r.tixianjilu_id) === String(record.tixianjilu_id)
+ );
+ if (refreshed) record = refreshed;
+ }
+ if (!this.canCollectRecord(record)) {
+ wx.showModal({
+ title: '暂时无法收款',
+ content: '缺少审核单号或审核记录ID,请下拉刷新后重试。仍不行请联系客服。',
+ showCancel: false,
+ });
+ return;
+ }
+
+ this.setData({ showCollectConfirm: false, submitting: true, collectConfirmRecord: record });
+ try {
+ const res = await request({
+ url: '/yonghu/tixiansq',
+ method: 'POST',
+ data: {
+ shenhe_danhao: record.shenhe_danhao,
+ shenhe_jilu_id: record.shenhe_jilu_id || '',
+ tixianjilu_id: record.tixianjilu_id || record.id || '',
+ leixing: record.leixing,
+ }
+ });
+ if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ const data = res.data.data;
+ this.setData({
+ currentTixianId: data.tixian_id,
+ mchId: data.mch_id || '',
+ collectConfirmRecord: record,
+ });
+ this.tiaoqiWeixinQueRen(data.package_info);
+ } else {
+ wx.showModal({ title: '收款失败', content: res.data?.msg || '无法发起收款,请稍后重试', showCancel: false });
+ this.setData({ submitting: false, collectConfirmRecord: null });
+ }
+ } catch (err) {
+ wx.showModal({ title: '网络错误', content: '网络连接失败,请稍后重试', showCancel: false });
+ this.setData({ submitting: false, collectConfirmRecord: null });
+ }
+ },
+
+ tiaoqiWeixinQueRen(packageInfo) {
+ const appId = app.globalData.appId;
+ const mchId = this.data.mchId;
+ if (!appId || !mchId) {
+ wx.showModal({ title: '配置错误', content: '无法调起收款,请联系客服', showCancel: false });
+ this.setData({ submitting: false, collectConfirmRecord: null });
+ return;
+ }
+ wx.requestMerchantTransfer({
+ appId, mchId, package: packageInfo,
+ success: () => { this.tongzhiHouduanQueRen(1); },
+ fail: () => {
+ this.tongzhiHouduanQueRen(0);
+ wx.showModal({
+ title: '确认收款失败',
+ content: '微信收款确认失败,您可在记录中再次点击「收款」重试。',
+ showCancel: false,
+ });
+ }
+ });
+ },
+
+ async tongzhiHouduanQueRen(result) {
+ if (!this.data.currentTixianId) {
+ this.setData({ submitting: false, collectConfirmRecord: null });
+ return;
+ }
+ const record = this.data.collectConfirmRecord;
+ const wxConfirmed = result === 1;
+
+ try {
+ const res = await request({
+ url: '/yonghu/tixianqr',
+ method: 'POST',
+ data: {
+ tixian_id: this.data.currentTixianId,
+ result: result,
+ shenhe_danhao: record ? record.shenhe_danhao : '',
+ shenhe_jilu_id: record ? (record.shenhe_jilu_id || '') : '',
+ tixianjilu_id: record ? (record.tixianjilu_id || record.id || '') : '',
+ leixing: record ? record.leixing : '',
+ }
+ });
+ if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ const data = res.data.data || {};
+ this.gengxinYue(data, record ? record.leixing : null);
+ }
+
+ // 微信已确认收款:不论 tixianqr 返回什么,都刷新列表,不弹系统异常
+ if (wxConfirmed) {
+ await this.finishWxCollectSuccess(record);
+ } else if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ this.huoquJilu(true);
+ wx.showToast({
+ title: '收款已取消',
+ icon: 'none',
+ duration: 3000,
+ });
+ } else {
+ wx.showModal({
+ title: '确认状态失败',
+ content: res.data?.msg || '操作失败',
+ showCancel: false,
+ });
+ }
+ } catch (err) {
+ if (wxConfirmed) {
+ await this.finishWxCollectSuccess(record);
+ } else {
+ wx.showModal({
+ title: '网络错误',
+ content: '网络连接失败',
+ showCancel: false,
+ });
+ }
+ } finally {
+ this.setData({ submitting: false, currentTixianId: null, collectConfirmRecord: null });
+ }
+ },
+
+ onViewDetail(e) {
+ const index = e.currentTarget.dataset.index;
+ const record = this.data.recordList[index];
+ if (!record || !record.canShowDetail) return;
+ const status = parseInt(record.zhuangtai);
+ let detailTitle = '失败原因';
+ if (status === TX_STATUS.SHENHE_SHIBAI) detailTitle = '审核失败原因';
+ else if (status === TX_STATUS.TIXIAN_SHIBAI) detailTitle = '提现失败原因';
+ this.setData({
+ showDetailModal: true,
+ detailTitle,
+ detailContent: record.detailReason || '暂无详细信息',
+ });
+ },
+
+ onCloseDetailModal() {
+ this.setData({ showDetailModal: false, detailTitle: '', detailContent: '' });
+ },
+
+ async huoquJilu(fresh = false, force = false) {
+ const now = Date.now();
+ if (!force && now - lastPullDownTime < 2000 && !fresh) return;
+ if (!force && (this.data.loading || this.data.isRefreshing)) return;
+ const page = fresh ? 1 : this.data.page;
+ if (fresh) this.setData({ nomore: false, canloadmore: true, isRefreshing: true });
+ if (this.data.nomore && !fresh) return;
+ this.setData({ loading: true });
+ lastPullDownTime = now;
+ try {
+ const res = await request({
+ url: '/yonghu/tixianjiluhq',
+ method: 'POST',
+ data: { page, limit: yemianshuju, mode: 2, zhuangtai: this.data.currentStatusFilter }
+ });
+ if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ const data = res.data.data;
+ const processedList = (data.list || []).map(item => this.processRecordItem(item));
+ const newList = fresh ? processedList : [...this.data.recordList, ...processedList];
+ this.setData({
+ recordList: newList,
+ page: page + 1,
+ nomore: !(data.has_more === true),
+ canloadmore: data.has_more === true,
+ loading: false,
+ isRefreshing: false,
+ });
+ this.updatePendingCollectFlag(newList);
+ } else {
+ this.setData({ loading: false, isRefreshing: false });
+ }
+ } catch (err) {
+ this.setData({ loading: false, isRefreshing: false });
+ }
+ },
+
+ onReachBottom() {
+ if (this.data.canloadmore && !this.data.nomore && !this.data.loading && !this.data.isRefreshing) {
+ const now = Date.now();
+ if (now - lastPullDownTime >= PULL_DOWN_INTERVAL) this.huoquJilu();
+ }
+ },
+
+ stopPropagation() {}
+ }
+});
diff --git a/pages/withdraw/components/record-mode2/record-mode2.json b/pages/withdraw/components/record-mode2/record-mode2.json
new file mode 100644
index 0000000..60741f8
--- /dev/null
+++ b/pages/withdraw/components/record-mode2/record-mode2.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "global-notification": "/components/global-notification/global-notification",
+ "popup-notice": "/components/popup-notice/popup-notice"
+ }
+}
diff --git a/pages/withdraw/components/record-mode2/record-mode2.wxml b/pages/withdraw/components/record-mode2/record-mode2.wxml
new file mode 100644
index 0000000..5f72a13
--- /dev/null
+++ b/pages/withdraw/components/record-mode2/record-mode2.wxml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+ 您有审核通过的提现待收款,请点击「收款」按钮,在微信中主动确认后才能到账。
+
+
+
+
+ {{item.label}}
+
+
+
+
+
+
+ ¥{{item.jine}}
+ {{item.create}}
+
+
+ 微信零钱
+ {{item.leixingLabel}}
+
+
+
+ {{item.statusText}}
+ 点击收款
+
+
+ {{item.statusText}}
+ 详情
+
+ {{item.statusText}}
+
+
+ 加载中...
+ —— 没有更多了 ——
+ 加载更多记录
+ 暂无提现记录
+
+
+
+
+
+
+
+
+
+
+ 审核已通过,{{collectConfirmRecord.leixingLabel}} ¥{{collectConfirmRecord.jine}}
+ 请点击「去收款」,然后在微信弹窗中主动确认,资金才会打入您的微信零钱。
+ 审核单号:{{collectConfirmRecord.shenhe_danhao}}
+ 注意:审核通过≠已到账,必须您本人点击确认才能完成收款!
+
+
+
+
+
+
+
+
+ {{detailContent}}
+
+
+
+
+
+
diff --git a/pages/withdraw/components/record-mode2/record-mode2.wxss b/pages/withdraw/components/record-mode2/record-mode2.wxss
new file mode 100644
index 0000000..982008e
--- /dev/null
+++ b/pages/withdraw/components/record-mode2/record-mode2.wxss
@@ -0,0 +1,416 @@
+/* mode2 自动打款 - UI 完全复用 mode1 样式 */
+
+page {
+ background-color: #f5f7fb;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ height: 100%;
+ }
+
+ .app {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ padding: 0 24rpx 0;
+ position: relative;
+ z-index: 1;
+ box-sizing: border-box;
+ }
+
+ .global-bg {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ opacity: 0.1;
+ object-fit: cover;
+ filter: blur(1rpx);
+ }
+
+ .assets-section {
+ margin-top: 24rpx;
+ flex-shrink: 0;
+ }
+
+ .main-card {
+ background: rgba(248, 250, 252, 0.88);
+ backdrop-filter: blur(28rpx);
+ -webkit-backdrop-filter: blur(28rpx);
+ border-radius: 48rpx;
+ padding: 30rpx 28rpx 24rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+ border: 1rpx solid rgba(255, 255, 255, 0.4);
+ background-size: cover;
+ }
+
+ .balance-wrap {
+ text-align: center;
+ margin-bottom: 20rpx;
+ }
+ .balance-label {
+ font-size: 28rpx;
+ color: #0f172a;
+ letter-spacing: 1px;
+ display: block;
+ margin-bottom: 10rpx;
+ font-weight: 700;
+ text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.8);
+ }
+ .balance-value {
+ font-size: 68rpx;
+ font-weight: 800;
+ color: #0f172a;
+ font-family: 'DIN', monospace;
+ letter-spacing: -1rpx;
+ text-shadow: 0 1rpx 2rpx rgba(255,255,255,0.6);
+ }
+
+ .inner-divider {
+ width: 60%;
+ height: 2rpx;
+ background: linear-gradient(90deg, transparent, #64748b, #64748b, transparent);
+ margin: 0 auto 20rpx auto;
+ border-radius: 2rpx;
+ opacity: 0.9;
+ }
+
+ .assets-hint {
+ display: block;
+ text-align: center;
+ font-size: 24rpx;
+ color: #334155;
+ margin-bottom: 14rpx;
+ font-weight: 600;
+ }
+
+ .assets-scroll {
+ width: 100%;
+ white-space: nowrap;
+ }
+ .assets-track {
+ display: inline-flex;
+ gap: 16rpx;
+ }
+
+ .asset-tile {
+ width: 170rpx;
+ background: rgba(255, 255, 255, 0.75);
+ backdrop-filter: blur(8rpx);
+ border-radius: 28rpx;
+ padding: 18rpx 12rpx;
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ border: 1rpx solid rgba(255,255,255,0.5);
+ box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02);
+ transition: all 0.2s;
+ white-space: normal;
+ background-size: cover;
+ background-position: center;
+ }
+ .asset-tile:active {
+ background: rgba(255, 255, 255, 0.9);
+ transform: scale(0.98);
+ }
+ .asset-name {
+ font-size: 24rpx;
+ font-weight: 700;
+ color: #1e293b;
+ margin-bottom: 10rpx;
+ text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.5);
+ }
+ .asset-balance {
+ font-size: 28rpx;
+ font-weight: 800;
+ color: #2d6a4f;
+ font-family: monospace;
+ margin-bottom: 6rpx;
+ text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
+ }
+ .asset-fee {
+ font-size: 20rpx;
+ font-weight: 600;
+ color: #475569;
+ text-shadow: 0 1rpx 1rpx rgba(255,255,255,0.3);
+ }
+ .assets-empty {
+ width: 400rpx;
+ text-align: center;
+ color: #a0abb9;
+ padding: 40rpx 0;
+ }
+
+ .divider-line {
+ height: 2rpx;
+ background: linear-gradient(90deg, transparent, #cbd5e1, #cbd5e1, transparent);
+ margin: 16rpx 0 20rpx;
+ width: 80%;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ .history-section {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ min-height: 0;
+ margin-top: 0;
+ }
+ .history-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ padding: 0 8rpx 20rpx;
+ flex-shrink: 0;
+ }
+ .history-title {
+ font-size: 34rpx;
+ font-weight: 600;
+ color: #1e293b;
+ }
+ .history-scroll {
+ flex: 1;
+ width: 100%;
+ padding: 0 20rpx;
+ box-sizing: border-box;
+ }
+ .history-item {
+ display: flex;
+ align-items: center;
+ padding: 28rpx 0;
+ border-bottom: 1rpx solid rgba(0,0,0,0.05);
+ }
+ .history-info { width: 160rpx; }
+ .history-amount {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #1e293b;
+ display: block;
+ }
+ .history-time {
+ font-size: 22rpx;
+ color: #94a3b8;
+ }
+ .history-detail {
+ flex: 1;
+ padding: 0 20rpx;
+ }
+ .history-method {
+ font-size: 30rpx;
+ color: #334155;
+ display: block;
+ margin-bottom: 6rpx;
+ }
+ .history-type {
+ font-size: 24rpx;
+ color: #94a3b8;
+ }
+ .history-status { text-align: right; }
+
+ .status-badge {
+ font-size: 26rpx;
+ font-weight: 500;
+ padding: 6rpx 14rpx;
+ border-radius: 30rpx;
+ display: inline-block;
+ }
+ .status-wait {
+ color: #f59e0b;
+ background: rgba(245,158,11,0.1);
+ }
+ .status-done {
+ color: #10b981;
+ background: rgba(16,185,129,0.1);
+ }
+ .status-fail {
+ color: #ef4444;
+ background: rgba(239,68,68,0.1);
+ }
+ .status-pending {
+ color: #3b82f6;
+ background: rgba(59,130,246,0.1);
+ }
+ .fail-link {
+ margin-left: 8rpx;
+ text-decoration: underline;
+ }
+ .collect-tappable {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4rpx;
+ padding: 10rpx 18rpx;
+ cursor: pointer;
+ border: 2rpx solid rgba(59,130,246,0.35);
+ box-shadow: 0 4rpx 12rpx rgba(59,130,246,0.15);
+ }
+ .collect-tappable:active {
+ transform: scale(0.97);
+ opacity: 0.9;
+ }
+ .collect-sub {
+ font-size: 22rpx;
+ font-weight: 700;
+ color: #1d4ed8;
+ text-decoration: underline;
+ }
+
+ .load-tip, .more-tip {
+ text-align: center;
+ padding: 30rpx;
+ font-size: 24rpx;
+ color: #94a3b8;
+ }
+ .load-more-btn {
+ margin: 16rpx 0 20rpx;
+ padding: 20rpx;
+ text-align: center;
+ background: rgba(255,255,255,0.7);
+ backdrop-filter: blur(8rpx);
+ border-radius: 40rpx;
+ font-size: 28rpx;
+ color: #3b82f6;
+ border: 1rpx solid rgba(255,255,255,0.5);
+ }
+ .load-more-btn:active { background: rgba(255,255,255,0.9); }
+.history-section--full {
+ flex: 1;
+ min-height: calc(100vh - 48rpx);
+ margin-top: 24rpx;
+}
+
+.history-section--full .history-scroll {
+ height: calc(100vh - 280rpx);
+}
+
+ /* 自动打款专属(少量追加) */
+ .pending-tip {
+ margin: 0 8rpx 16rpx;
+ padding: 16rpx 20rpx;
+ font-size: 24rpx;
+ color: #1d4ed8;
+ background: rgba(59,130,246,0.08);
+ border-radius: 20rpx;
+ line-height: 1.5;
+ }
+ .filter-scroll {
+ width: 100%;
+ white-space: nowrap;
+ margin-bottom: 12rpx;
+ }
+ .filter-track {
+ display: inline-flex;
+ gap: 12rpx;
+ padding: 0 8rpx;
+ }
+ .filter-chip {
+ flex-shrink: 0;
+ padding: 10rpx 22rpx;
+ font-size: 24rpx;
+ color: #64748b;
+ background: rgba(255,255,255,0.8);
+ border-radius: 30rpx;
+ border: 1rpx solid rgba(0,0,0,0.06);
+ }
+ .filter-chip.active {
+ color: #3b82f6;
+ background: #eff6ff;
+ border-color: #3b82f6;
+ }
+ .auto-tip {
+ font-size: 24rpx;
+ color: #3b82f6;
+ margin-bottom: 20rpx;
+ line-height: 1.5;
+ }
+ .warn-tip {
+ font-size: 24rpx;
+ color: #f59e0b;
+ margin-top: 16rpx;
+ font-weight: 600;
+ }
+
+ /* 弹窗(与 mode1 一致) */
+ .modal-mask {
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0,0,0,0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ }
+ .modal-dialog {
+ width: 600rpx;
+ background: rgba(255,255,255,0.96);
+ backdrop-filter: blur(20rpx);
+ border-radius: 48rpx;
+ overflow: hidden;
+ box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.1);
+ border: 1rpx solid rgba(255,255,255,0.6);
+ }
+ .modal-header {
+ padding: 36rpx 32rpx 20rpx;
+ font-size: 36rpx;
+ font-weight: 700;
+ border-bottom: 1rpx solid rgba(0,0,0,0.05);
+ }
+ .modal-body {
+ padding: 32rpx;
+ font-size: 28rpx;
+ color: #334155;
+ line-height: 1.6;
+ }
+ .info-row, .amount-row {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 24rpx;
+ font-size: 28rpx;
+ }
+ .amount-row input {
+ border: 1rpx solid rgba(0,0,0,0.1);
+ border-radius: 28rpx;
+ padding: 16rpx 20rpx;
+ width: 260rpx;
+ background: rgba(255,255,255,0.9);
+ }
+ .quick-row {
+ display: flex;
+ gap: 16rpx;
+ margin: 24rpx 0;
+ }
+ .quick-chip {
+ flex: 1;
+ background: rgba(241,245,249,0.8);
+ text-align: center;
+ padding: 12rpx;
+ border-radius: 40rpx;
+ font-size: 28rpx;
+ }
+ .fee-row {
+ display: flex;
+ justify-content: space-between;
+ background: rgba(248,250,252,0.8);
+ padding: 20rpx;
+ border-radius: 28rpx;
+ margin: 20rpx 0;
+ }
+ .modal-footer {
+ display: flex;
+ border-top: 1rpx solid rgba(0,0,0,0.05);
+ }
+ .modal-btn {
+ flex: 1;
+ text-align: center;
+ padding: 28rpx;
+ font-size: 30rpx;
+ }
+ .modal-btn.cancel {
+ color: #8f9bb3;
+ border-right: 1rpx solid rgba(0,0,0,0.05);
+ }
+ .modal-btn.confirm { color: #3b82f6; }
+
\ No newline at end of file
diff --git a/pages/withdraw/withdraw-records.js b/pages/withdraw/withdraw-records.js
new file mode 100644
index 0000000..0835813
--- /dev/null
+++ b/pages/withdraw/withdraw-records.js
@@ -0,0 +1,51 @@
+// pages/withdraw/withdraw-records.js — 提现记录独立页
+import { createPage, request } from '../../utils/base-page.js';
+
+Page(createPage({
+ data: {
+ pageMode: 0,
+ loadError: false,
+ },
+
+ onLoad() {
+ this.fetchPageMode();
+ },
+
+ async fetchPageMode() {
+ try {
+ const res = await request({
+ url: '/peizhi/hqtxzsym',
+ method: 'POST',
+ });
+ if (res.statusCode === 200 && res.data && res.data.code === 0) {
+ const mode = parseInt(res.data.data.mode, 10);
+ this.setData({
+ pageMode: (mode === 1 || mode === 2) ? mode : 1,
+ loadError: false,
+ });
+ } else {
+ this.setData({ pageMode: 1, loadError: false });
+ }
+ } catch (err) {
+ console.error('获取展示模式失败:', err);
+ this.setData({ loadError: true });
+ }
+ },
+
+ retryFetch() {
+ this.setData({ loadError: false, pageMode: 0 });
+ this.fetchPageMode();
+ },
+
+ onPullDownRefresh() {
+ const mode = this.data.pageMode;
+ const compId = mode === 1 ? '#record-mode2' : mode === 2 ? '#record-mode1' : null;
+ if (!compId) {
+ wx.stopPullDownRefresh();
+ return;
+ }
+ const comp = this.selectComponent(compId);
+ const p = comp && comp.onPullDownRefresh ? comp.onPullDownRefresh() : Promise.resolve();
+ Promise.resolve(p).finally(() => wx.stopPullDownRefresh());
+ },
+}));
diff --git a/pages/withdraw/withdraw-records.json b/pages/withdraw/withdraw-records.json
new file mode 100644
index 0000000..802472c
--- /dev/null
+++ b/pages/withdraw/withdraw-records.json
@@ -0,0 +1,11 @@
+{
+ "navigationBarTitleText": "提现记录",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#f5f7fb",
+ "enablePullDownRefresh": true,
+ "usingComponents": {
+ "record-mode1": "./components/record-mode1/record-mode1",
+ "record-mode2": "./components/record-mode2/record-mode2"
+ }
+}
diff --git a/pages/withdraw/withdraw-records.wxml b/pages/withdraw/withdraw-records.wxml
new file mode 100644
index 0000000..592ebb8
--- /dev/null
+++ b/pages/withdraw/withdraw-records.wxml
@@ -0,0 +1,14 @@
+
+
+
+ 加载中...
+
+
+
+ 加载失败,请检查网络
+ 点击重试
+
+
+
+
+
diff --git a/pages/withdraw/withdraw-records.wxss b/pages/withdraw/withdraw-records.wxss
new file mode 100644
index 0000000..9e4215a
--- /dev/null
+++ b/pages/withdraw/withdraw-records.wxss
@@ -0,0 +1,41 @@
+.records-container {
+ width: 100%;
+ min-height: 100vh;
+ background: #f5f7fb;
+}
+
+.loading-center, .error-center {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #64748b;
+}
+
+.loading-spinner {
+ width: 60rpx;
+ height: 60rpx;
+ border: 4rpx solid rgba(59, 130, 246, 0.2);
+ border-top-color: #3b82f6;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ margin-bottom: 24rpx;
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
+
+.loading-text, .error-text {
+ font-size: 28rpx;
+}
+
+.retry-btn {
+ margin-top: 24rpx;
+ padding: 16rpx 48rpx;
+ background: #3b82f6;
+ color: #fff;
+ border-radius: 40rpx;
+ font-size: 28rpx;
+}
diff --git a/pages/withdraw/withdraw.json b/pages/withdraw/withdraw.json
index e2d5589..9fb4b06 100644
--- a/pages/withdraw/withdraw.json
+++ b/pages/withdraw/withdraw.json
@@ -1,14 +1,14 @@
{
- "usingComponents": {
- "mode1": "./components/mode1/mode1",
- "mode2": "./components/mode2/mode2"
- },
- "navigationBarTitleText": "提现中心",
- "navigationBarBackgroundColor": "#ffffff",
- "navigationBarTextStyle": "black",
- "backgroundColor": "#f5f7fb",
- "enablePullDownRefresh": false,
- "onReachBottomDistance": 50,
- "navigationStyle": "default",
- "disableScroll": false
- }
\ No newline at end of file
+ "usingComponents": {
+ "mode1": "./components/mode1/mode1",
+ "mode2": "./components/mode2/mode2"
+ },
+ "navigationBarTitleText": "提现",
+ "navigationBarBackgroundColor": "#FFD54F",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#f5f5f5",
+ "enablePullDownRefresh": false,
+ "onReachBottomDistance": 50,
+ "navigationStyle": "default",
+ "disableScroll": false
+}
diff --git a/pages/withdraw/withdraw.wxss b/pages/withdraw/withdraw.wxss
index fe81d0a..2606acf 100644
--- a/pages/withdraw/withdraw.wxss
+++ b/pages/withdraw/withdraw.wxss
@@ -1,13 +1,19 @@
/* pages/withdraw/withdraw.wxss */
.tixian-container {
width: 100%;
+ min-height: 100vh;
+ background: #f5f5f5;
}
/* 加载状态 */
.loading-center, .error-center {
height: 100vh;
- color: #ffffff;
- background: #1a0b2e;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #666;
+ background: #f5f5f5;
}
.loading-spinner {
diff --git a/project.config.json b/project.config.json
index ba985c2..cd3eb56 100644
--- a/project.config.json
+++ b/project.config.json
@@ -34,9 +34,34 @@
},
"libVersion": "3.14.3",
"packOptions": {
- "ignore": [],
+ "ignore": [
+ {
+ "value": "_backup_20260705_pre_split",
+ "type": "folder"
+ },
+ {
+ "value": "_backup_withdraw_20260705",
+ "type": "folder"
+ },
+ {
+ "value": "_backup_pre_redesign",
+ "type": "folder"
+ },
+ {
+ "value": "_backup_20260706",
+ "type": "folder"
+ },
+ {
+ "value": "_backup_ui_20260706",
+ "type": "folder"
+ },
+ {
+ "value": ".bak",
+ "type": "suffix"
+ }
+ ],
"include": []
},
- "appid": "wx0e4be86faac4a8d1",
+ "appid": "wxdefa454152e78a03",
"simulatorPluginLibVersion": {}
}
\ No newline at end of file
diff --git a/styles/dashou-xym-order-card.wxss b/styles/dashou-xym-order-card.wxss
index 6bdf05f..8bd7521 100644
--- a/styles/dashou-xym-order-card.wxss
+++ b/styles/dashou-xym-order-card.wxss
@@ -17,22 +17,22 @@
box-shadow: 0 10rpx 28rpx rgba(0, 0, 0, 0.09);
}
-/* 平台订单 - 紫色主题 */
+/* 平台订单 */
.xym-pingtai-order {
padding-bottom: 5rpx;
- background: #7c3aed;
+ background: #927a46;
}
.xym-pingtai-head {
height: 72rpx;
padding: 0 24rpx;
- background: linear-gradient(50deg, #6d28d9, #9333ea);
+ background: linear-gradient(50deg, #957c48, #5c4a28);
border-radius: 30rpx 30rpx 0 0;
}
.xym-head-time {
font-size: 24rpx;
- color: #e9d5ff;
+ color: #fcd270;
}
.xym-head-tag {
@@ -40,21 +40,21 @@
padding: 4rpx 16rpx;
border-radius: 8rpx;
font-weight: 600;
- background: rgba(196, 181, 253, 0.28);
- color: #f5f3ff;
- border: 1rpx solid rgba(196, 181, 253, 0.55);
+ background: rgba(252, 210, 112, 0.22);
+ color: #fcd270;
+ border: 1rpx solid rgba(252, 210, 112, 0.4);
}
.xym-pingtai-body {
border-radius: 40rpx 10rpx 30rpx 30rpx;
padding: 0 20rpx 24rpx;
- background: linear-gradient(to bottom, #5b21b6, #c4b5fd);
+ background: linear-gradient(to bottom, #3a3220, #cec180);
}
/* 商家订单 */
.xym-shangjia-order {
padding-bottom: 5rpx;
- background: linear-gradient(to bottom, #f5f3ff, #ddd6fe);
+ background: linear-gradient(to bottom, #fff8e1, #ffe0b2);
overflow: hidden;
}
@@ -74,7 +74,7 @@
.xym-shangjia-head .xym-head-tag {
background: rgba(255, 255, 255, 0.65);
color: #492f00;
- border-color: rgba(147, 51, 234, 0.5);
+ border-color: rgba(255, 208, 97, 0.5);
}
.order-con {
@@ -148,10 +148,34 @@
padding: 10rpx 16rpx;
background: rgba(255, 77, 109, 0.12);
border-radius: 12rpx;
- flex-wrap: wrap;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
gap: 8rpx;
}
+.zhiding-strip-top {
+ display: flex;
+ align-items: center;
+ gap: 10rpx;
+ width: 100%;
+}
+
+.zhiding-strip-tags {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ align-items: flex-start;
+ align-content: flex-start;
+ width: 100%;
+ margin-top: 2rpx;
+ gap: 4rpx;
+}
+
+.zhiding-strip-tags .tag-root {
+ margin: 2rpx 4rpx 2rpx 0;
+}
+
.zhiding-strip.light {
background: rgba(255, 255, 255, 0.35);
}
@@ -174,14 +198,105 @@
.zhiding-strip .zhiding-name {
font-size: 24rpx;
color: #666;
- max-width: 200rpx;
+ flex: 1;
+ min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
+.zhiding-tags-row {
+ margin: 8rpx 16rpx 12rpx;
+}
+
+.zhiding-tags-row .biaoqian-inline-scroll + .biaoqian-inline-scroll {
+ margin-top: 8rpx;
+}
+
+/* 金牌卡底部商家条 */
+.gold-card .merchant-strip {
+ margin: 16rpx 6rpx 0;
+ padding: 16rpx 20rpx;
+ align-items: center;
+ border-radius: 16rpx;
+ background: linear-gradient(90deg, #4a3a24 0%, #6b5434 50%, #4a3a24 100%);
+}
+
+.gold-card .merchant-strip .m-avatar-sm {
+ width: 64rpx;
+ height: 64rpx;
+ border: 2rpx solid rgba(255, 215, 0, 0.35);
+}
+
+.gold-card .merchant-strip .m-info {
+ flex: 1;
+ min-width: 0;
+ margin-left: 12rpx;
+}
+
+.gold-card .merchant-strip .m-name-sm {
+ color: #f5e6c8;
+ font-size: 28rpx;
+}
+
+.gold-card .merchant-strip .m-sn-light {
+ color: rgba(245, 230, 200, 0.72);
+ font-size: 22rpx;
+ margin-top: 4rpx;
+}
+
+.merchant-foot {
+ margin-top: 16rpx;
+ padding: 12rpx 10rpx 4rpx;
+ align-items: center;
+ gap: 12rpx;
+}
+
+.merchant-foot .merchant-user {
+ flex: 1;
+ min-width: 0;
+ align-items: center;
+}
+
+.merchant-foot .m-info {
+ flex: 1;
+ min-width: 0;
+ margin-left: 12rpx;
+}
+
+.gold-card .merchant-foot {
+ margin: 16rpx 6rpx 0;
+ padding: 16rpx 12rpx;
+ border-radius: 16rpx;
+ background: linear-gradient(90deg, #4a3a24 0%, #6b5434 50%, #4a3a24 100%);
+}
+
+.gold-card .merchant-foot .m-avatar-sm {
+ border: 2rpx solid rgba(255, 215, 0, 0.35);
+}
+
+.gold-card .merchant-foot .m-name-sm {
+ color: #f5e6c8;
+}
+
+.gold-card .merchant-foot .m-sn-light {
+ color: rgba(245, 230, 200, 0.72);
+}
+
+.xym-shangjia-body .merchant-foot {
+ padding-top: 8rpx;
+}
+
+.gold-card .order-row {
+ padding: 8rpx 10rpx 0;
+}
+
+.gold-card .gold-inner {
+ padding: 16rpx 10rpx 12rpx;
+}
+
.xym-pingtai-body .zhiding-strip .zhiding-name {
- color: #ede9fe;
+ color: #f5e6b8;
}
.reward-badge {
@@ -198,13 +313,13 @@
}
.reward-badge.normal-reward {
- color: #4c1d95;
- background: linear-gradient(to bottom, #c4b5fd, #a78bfa);
+ color: #492f00;
+ background: linear-gradient(to bottom, #fae04d, #ffc0a3);
}
.reward-badge.platform-reward {
color: #fff;
- background: linear-gradient(to right, #9333ea, #c4b5fd);
+ background: linear-gradient(to right, #dabd83, #704029);
}
.xym-shangjia-body .reward-badge:not(.member-tip) {
@@ -253,8 +368,8 @@
.remark-block.gold {
color: #fff;
- border-color: #c4b5fd;
- background: rgba(196, 181, 253, 0.12);
+ border-color: #ffd700;
+ background: rgba(255, 215, 0, 0.12);
}
.remark-block.dark {
@@ -268,7 +383,7 @@
}
.remark-block.gold .remark-label {
- color: #c4b5fd;
+ color: #ffd700;
}
.remark-block.dark .remark-label {
@@ -303,17 +418,17 @@
}
.o-amt.light {
- color: #ede9fe;
+ color: #f5e6b8;
}
.btn-bg {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
border-radius: 60rpx;
color: #492f00;
}
.qiangdan {
- color: #4c1d95;
+ color: #492f00;
width: 180rpx;
min-width: 100rpx;
padding: 15rpx 10rpx;
@@ -325,8 +440,8 @@
}
.qiangdan.btn-qiang-brown {
- background: linear-gradient(to right, #7c3aed 0%, #c4b5fd 100%) !important;
- color: #fff !important;
+ background: linear-gradient(to right, #7a4a2d 0%, #e4ce94 100%) !important;
+ color: #000 !important;
}
.view-more-inline {
@@ -336,6 +451,251 @@
}
.biaoqian-inline-scroll {
- white-space: nowrap;
width: 100%;
+ white-space: nowrap;
+}
+
+.biaoqian-inline-inner {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ flex-wrap: nowrap;
+ padding-right: 12rpx;
+}
+
+/* 优质商家金牌卡片 — 与逍遥梦 ui-preview 一致 */
+.xym-order-item.gold-card {
+ margin-bottom: 20rpx;
+ border-radius: 30rpx;
+ box-shadow: 0 12rpx 32rpx rgba(248, 211, 44, 0.28);
+ overflow: hidden;
+}
+
+.gold-card {
+ padding-bottom: 5rpx;
+ position: relative;
+ background: linear-gradient(to bottom, #ffecc5, #fffbf3);
+}
+
+.gold-head {
+ height: 77rpx;
+ display: flex;
+ align-items: center;
+ background: linear-gradient(127deg, #F8D32C 0%, #FFB26A 35%, #FFEE58 70%, #F8D32C 100%);
+ border-radius: 32rpx 32rpx 0 0;
+}
+
+.kehuduan-banner-wrap,
+.gold-banner-wrap {
+ margin-left: 46rpx;
+}
+
+.gold-banner {
+ width: 222rpx;
+ height: 70rpx;
+ margin-left: -28rpx;
+ margin-top: 8rpx;
+ display: block;
+}
+
+.tag-row {
+ flex-wrap: wrap;
+ gap: 8rpx;
+ margin-top: 10rpx;
+}
+
+.tag-pill {
+ font-size: 22rpx;
+ padding: 4rpx 18rpx;
+ border-radius: 10rpx;
+}
+
+.tag-pill.tag-youzhi,
+.tag-youzhi {
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492c00;
+ font-size: 24rpx;
+ padding: 4rpx 18rpx;
+ border-radius: 10rpx;
+ margin-right: 10rpx;
+ font-weight: 600;
+}
+
+.gold-body-wrap {
+ border-radius: 10rpx 10rpx 30rpx 30rpx;
+ padding: 0 20rpx 20rpx;
+ background: linear-gradient(to bottom, #1f1a14 0%, #342b22 38%, #4a3d30 68%, #6b5638 100%);
+}
+
+.gold-inner {
+ padding: 25rpx 10rpx 10rpx;
+ position: relative;
+ background: transparent;
+ border-radius: 0;
+ box-shadow: none;
+}
+
+.gold-card .o-goods {
+ color: #fff;
+}
+
+.gold-card .m-name-sm {
+ color: #f5e6c8;
+}
+
+.gold-card .merchant-line {
+ padding: 0 10rpx;
+}
+
+.gold-card .remark-block.dark {
+ color: rgba(255, 255, 255, 0.88);
+ border-color: #c9a227;
+ background: rgba(0, 0, 0, 0.12);
+ margin: 12rpx 10rpx 0;
+ padding: 8rpx 20rpx;
+ border-bottom: 1rpx dotted rgba(255, 255, 255, 0.15);
+ padding-bottom: 15rpx;
+}
+
+.gold-card .remark-block.dark .remark-label {
+ color: #e8c547;
+}
+
+.gold-card .merchant-tags-container,
+.gold-card .xuqiu-tags-row {
+ margin: 10rpx 5rpx 0;
+ border-top: 3rpx dotted rgba(255, 255, 255, 0.15);
+ padding-top: 16rpx;
+}
+
+.gold-card .merchant-strip {
+ background: linear-gradient(90deg, #4a3a24 0%, #6b5434 50%, #4a3a24 100%);
+ background-image: none;
+}
+
+.gold-card .m-name.light-t,
+.gold-card .m-name-sm {
+ color: #f5e6c8;
+}
+
+.gold-card .m-sn.light-sub,
+.gold-card .m-sn-light {
+ color: rgba(245, 230, 200, 0.72);
+}
+
+.gold-card .o-amt-grey {
+ color: rgba(255, 255, 255, 0.65);
+}
+
+.gold-card .zhiding-strip {
+ background: rgba(255, 215, 0, 0.12);
+}
+
+.gold-card .zhiding-strip .zhiding-name {
+ color: rgba(255, 255, 255, 0.9);
+}
+
+.gold-card .zhiding-strip .zhiding-label {
+ color: #ffd700;
+ background: rgba(255, 215, 0, 0.2);
+}
+
+.gold-card .o-amt {
+ color: rgba(255, 255, 255, 0.65);
+}
+
+.gold-card .reward-badge.normal-reward.gold-reward {
+ top: 100rpx;
+ box-shadow: 0 4rpx 14rpx rgba(201, 162, 39, 0.35);
+ border: 1rpx solid rgba(255, 215, 0, 0.4);
+}
+
+.gold-card .merchant-plain {
+ margin-top: 20rpx;
+ padding: 0 10rpx;
+ align-items: center;
+}
+
+.gold-card .merchant-plain.flexb .merchant-user {
+ flex: 1;
+ min-width: 0;
+ align-items: center;
+}
+
+.gold-card .merchant-plain.flexb .m-info {
+ flex: 1;
+ min-width: 0;
+ margin-left: 12rpx;
+}
+
+.gold-card .merchant-plain.flexb .qiangdan {
+ flex-shrink: 0;
+}
+
+.gold-card .gold-foot-text-only {
+ justify-content: flex-start;
+}
+
+.gold-card .m-avatar {
+ width: 64rpx;
+ height: 64rpx;
+ border-radius: 50%;
+ flex-shrink: 0;
+ border: 2rpx solid rgba(255, 215, 0, 0.35);
+}
+
+.gold-card .m-name-light {
+ color: #f5e6c8;
+ font-size: 26rpx;
+ font-weight: 700;
+}
+
+.line1 {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.gold-card .m-sn-light {
+ color: rgba(245, 230, 200, 0.72);
+ font-size: 22rpx;
+ margin-top: 4rpx;
+}
+
+.gold-card .o-amt-grey {
+ font-size: 24rpx;
+ color: rgba(255, 255, 255, 0.65);
+}
+
+.gold-card .kehuduan-foot {
+ justify-content: flex-end;
+ margin-top: 16rpx;
+ padding: 0 10rpx 6rpx;
+}
+
+/* 公告条 */
+.xym-gonggao-bar {
+ display: flex;
+ align-items: center;
+ background: #fdf9db;
+ margin: 0 24rpx 0;
+ border-radius: 10rpx;
+ padding: 10rpx 16rpx;
+}
+
+.xym-gonggao-ico {
+ width: 40rpx;
+ height: 40rpx;
+ flex-shrink: 0;
+ margin-right: 12rpx;
+}
+
+.xym-gonggao-txt {
+ font-size: 24rpx;
+ color: #666;
+ line-height: 1.5;
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
diff --git a/styles/dashou-xym-orders-page.wxss b/styles/dashou-xym-orders-page.wxss
new file mode 100644
index 0000000..145ef20
--- /dev/null
+++ b/styles/dashou-xym-orders-page.wxss
@@ -0,0 +1,119 @@
+/* 打手订单 Tab - 逍遥梦 order 页布局增强 */
+@import './xym-layout.wxss';
+
+.ds-page.xym-order-page {
+ background: #f5f5f5;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.xym-order-page .xym-order-header {
+ position: relative;
+ flex-shrink: 0;
+ padding-bottom: 8rpx;
+}
+
+.xym-order-page .xym-order-bg {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 200rpx;
+ z-index: 0;
+}
+
+.xym-order-page .xym-order-title-bar {
+ position: relative;
+ z-index: 2;
+ text-align: center;
+ padding: 16rpx 0 8rpx;
+}
+
+.xym-order-page .xym-order-title {
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #343434;
+}
+
+.xym-order-page .main-container {
+ flex: 1;
+ min-height: 0;
+}
+
+.xym-order-page .order-card-xym {
+ margin: 0 0 16rpx;
+ padding: 20rpx;
+ border-radius: 16rpx;
+ background: #fff;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
+ display: flex;
+ align-items: flex-start;
+}
+
+.xym-order-page .card-hd-xym {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12rpx;
+}
+
+.xym-order-page .card-time-xym {
+ font-size: 22rpx;
+ color: #999;
+}
+
+.xym-order-page .card-status-xym {
+ font-size: 24rpx;
+ font-weight: 600;
+}
+
+.xym-order-page .card-bd-xym {
+ display: flex;
+ width: 100%;
+}
+
+.xym-order-page .goods-img-xym {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 12rpx;
+ flex-shrink: 0;
+ background: #f0f0f0;
+}
+
+.xym-order-page .goods-info-xym {
+ flex: 1;
+ margin-left: 16rpx;
+ min-width: 0;
+}
+
+.xym-order-page .goods-name-xym {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #222;
+ line-height: 1.4;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.xym-order-page .goods-sub-xym {
+ font-size: 24rpx;
+ color: #666;
+ margin-top: 8rpx;
+}
+
+.xym-order-page .goods-price-xym {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #492f00;
+ margin-top: 8rpx;
+}
+
+.xym-order-page .load-tip-xym {
+ text-align: center;
+ color: #999;
+ font-size: 24rpx;
+ padding: 20rpx 0 40rpx;
+}
diff --git a/styles/dashou-xym-orders-theme.wxss b/styles/dashou-xym-orders-theme.wxss
index 9eef9fb..75fe04d 100644
--- a/styles/dashou-xym-orders-theme.wxss
+++ b/styles/dashou-xym-orders-theme.wxss
@@ -13,8 +13,8 @@
}
.leixing-item.leixing-active {
- background: linear-gradient(180deg, #ede9fe, #c4b5fd) !important;
- box-shadow: 0 4rpx 12rpx rgba(147, 51, 234, 0.35) !important;
+ background: linear-gradient(180deg, #fff0c2, #f5d563) !important;
+ box-shadow: 0 4rpx 12rpx rgba(255, 208, 97, 0.35) !important;
}
.leixing-active .leixing-name {
@@ -32,14 +32,14 @@
}
.type-btn.type-active {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
box-shadow: 0 2rpx 8rpx rgba(180, 130, 20, 0.2) !important;
}
.search-box {
background: #fff !important;
- border: 1rpx solid rgba(147, 51, 234, 0.3) !important;
+ border: 1rpx solid rgba(255, 208, 97, 0.3) !important;
}
.left-status {
@@ -48,7 +48,7 @@
}
.status-item.status-active {
- background: #f5f3ff !important;
+ background: #fff8e1 !important;
}
.status-active .status-name {
@@ -56,7 +56,7 @@
}
.status-dot {
- background: #9333ea !important;
+ background: #ffd061 !important;
}
.right-list {
@@ -74,11 +74,11 @@
.loading-spinner,
.mini-spinner {
- border-top-color: #9333ea !important;
+ border-top-color: #ffd061 !important;
}
.load-more-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
border: 2rpx solid #fff !important;
}
diff --git a/styles/dashou-xym-rank-theme.wxss b/styles/dashou-xym-rank-theme.wxss
index ec8b09a..e6eaa43 100644
--- a/styles/dashou-xym-rank-theme.wxss
+++ b/styles/dashou-xym-rank-theme.wxss
@@ -24,13 +24,13 @@ page {
.role-chip {
background: rgba(255, 255, 255, 0.8) !important;
color: #666 !important;
- border: 2rpx solid rgba(147, 51, 234, 0.25) !important;
+ border: 2rpx solid rgba(255, 208, 97, 0.25) !important;
}
.role-chip.on {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
- border-color: #9333ea !important;
+ border-color: #ffd061 !important;
font-weight: 700 !important;
}
@@ -40,7 +40,7 @@ page {
}
.date-chip.on {
- background: #ede9fe !important;
+ background: #fef6d4 !important;
color: #492f00 !important;
font-weight: 700 !important;
}
@@ -76,7 +76,7 @@ page {
}
.my-rank-bar {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
}
.my-rank-bar text {
@@ -88,5 +88,5 @@ page {
}
.loader {
- border-top-color: #9333ea !important;
+ border-top-color: #ffd061 !important;
}
diff --git a/styles/dashou-xym-recharge-theme.wxss b/styles/dashou-xym-recharge-theme.wxss
index 3cdeb11..4b2d43a 100644
--- a/styles/dashou-xym-recharge-theme.wxss
+++ b/styles/dashou-xym-recharge-theme.wxss
@@ -1,7 +1,7 @@
/* 打手充值页 - 逍遥梦风格视觉覆盖(不改 wxml/逻辑) */
.page-container {
- background: linear-gradient(180deg, #c4b5fd 0%, #fff 22%, #f5f3ff 100%) !important;
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 22%, #fff8e1 100%) !important;
}
.page-container::before {
@@ -19,18 +19,18 @@
.dec-line,
.dec-diamond {
- background: #9333ea !important;
+ background: #ffd061 !important;
}
.vip-card {
background: #fdfcfa !important;
- border: 2rpx solid rgba(147, 51, 234, 0.5) !important;
+ border: 2rpx solid rgba(255, 208, 97, 0.5) !important;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08) !important;
}
.vip-card.active {
- border-color: #9333ea !important;
- box-shadow: 0 8rpx 28rpx rgba(147, 51, 234, 0.35) !important;
+ border-color: #ffd061 !important;
+ box-shadow: 0 8rpx 28rpx rgba(255, 208, 97, 0.35) !important;
}
.card-frame,
@@ -69,7 +69,7 @@
.tech-buy-btn,
.tech-btn,
.modal-btn.confirm-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
border: 2rpx solid #fff !important;
border-radius: 44rpx !important;
box-shadow: 0 4rpx 12rpx rgba(180, 130, 20, 0.25) !important;
@@ -122,8 +122,8 @@
.huiyuan-tag,
.tech-tag {
- background: #ede9fe !important;
- border: 1rpx solid rgba(147, 51, 234, 0.4) !important;
+ background: #fef6d4 !important;
+ border: 1rpx solid rgba(255, 208, 97, 0.4) !important;
}
.tag-name {
@@ -135,7 +135,7 @@
}
.tech-line {
- background: linear-gradient(90deg, transparent, #9333ea, transparent) !important;
+ background: linear-gradient(90deg, transparent, #ffd061, transparent) !important;
}
.tech-modal .modal-container {
@@ -168,13 +168,13 @@
}
.quick-btn {
- background: #ede9fe !important;
- border: 2rpx solid rgba(147, 51, 234, 0.4) !important;
+ background: #fef6d4 !important;
+ border: 2rpx solid rgba(255, 208, 97, 0.4) !important;
}
.quick-btn.active {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
- border-color: #9333ea !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
+ border-color: #ffd061 !important;
}
.quick-text {
@@ -182,7 +182,7 @@
}
.pay-method-item {
- background: #ede9fe !important;
+ background: #fef6d4 !important;
border-radius: 16rpx !important;
}
@@ -204,8 +204,8 @@
}
.spinner-ring {
- border-color: rgba(147, 51, 234, 0.3) !important;
- border-top-color: #9333ea !important;
+ border-color: rgba(255, 208, 97, 0.3) !important;
+ border-top-color: #ffd061 !important;
}
.tech-footer .footer-text {
diff --git a/styles/dashou-xym-theme.wxss b/styles/dashou-xym-theme.wxss
index 952714f..84fd7e1 100644
--- a/styles/dashou-xym-theme.wxss
+++ b/styles/dashou-xym-theme.wxss
@@ -1,10 +1,18 @@
/* 打手端抢单页 - 逍遥梦风格视觉覆盖(不改 wxml 结构/class) */
.xym-lunbo-container {
- margin: 16rpx 24rpx 0;
+ margin: 8rpx 24rpx 10rpx;
border-radius: 20rpx;
overflow: hidden;
flex-shrink: 0;
+ box-shadow: 0 6rpx 18rpx rgba(0, 0, 0, 0.08);
+ border: 2rpx solid rgba(255, 255, 255, 0.7);
+ background: #fff;
+}
+
+.xym-section-gap {
+ height: 12rpx;
+ flex-shrink: 0;
}
.xym-lunbo-swiper {
@@ -19,7 +27,7 @@
}
.qiangdan-page {
- background: linear-gradient(180deg, #c4b5fd 0%, #fff 28%, #f5f3ff 100%) !important;
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%) !important;
}
.qiangdan-page::before {
@@ -29,10 +37,11 @@
.leixing-quyu {
background: #fff !important;
border-bottom: none !important;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06) !important;
- margin: 12rpx 20rpx 0 !important;
+ box-shadow: 0 4rpx 14rpx rgba(0, 0, 0, 0.06) !important;
+ margin: 6rpx 20rpx 8rpx !important;
border-radius: 28rpx !important;
padding: 14rpx 0 8rpx !important;
+ border: 2rpx solid rgba(255, 224, 130, 0.5) !important;
}
.leixing-scroll {
@@ -52,8 +61,8 @@
}
.leixing-active .leixing-tupian {
- border: 3rpx solid #9333ea !important;
- box-shadow: 0 6rpx 16rpx rgba(147, 51, 234, 0.45) !important;
+ border: 3rpx solid #ffd061 !important;
+ box-shadow: 0 6rpx 16rpx rgba(255, 208, 97, 0.45) !important;
}
.leixing-jieshao {
@@ -64,12 +73,12 @@
}
.leixing-active .leixing-jieshao {
- color: #6d28d9 !important;
+ color: #492f00 !important;
font-weight: 700 !important;
}
.guangyun-effect {
- background: radial-gradient(circle, rgba(147, 51, 234, 0.35) 0%, transparent 70%) !important;
+ background: radial-gradient(circle, rgba(255, 208, 97, 0.35) 0%, transparent 70%) !important;
}
.biaoqian-quyu {
@@ -79,16 +88,16 @@
.biaoqian-item {
background: rgba(255, 255, 255, 0.65) !important;
- border: 2rpx solid rgba(147, 51, 234, 0.25) !important;
+ border: 2rpx solid rgba(201, 162, 39, 0.25) !important;
}
.biaoqian-active {
- background: linear-gradient(180deg, #ede9fe, #c4b5fd) !important;
- border-color: rgba(124, 58, 237, 0.85) !important;
+ background: linear-gradient(180deg, #fff0c2, #f5d563) !important;
+ border-color: rgba(180, 130, 20, 0.85) !important;
}
.fenge-xian {
- background: linear-gradient(90deg, transparent, #9333ea, transparent) !important;
+ background: linear-gradient(90deg, transparent, #ffd061, transparent) !important;
opacity: 0.6 !important;
margin: 6rpx 30rpx 0 !important;
}
@@ -100,7 +109,7 @@
.refreshing-text,
.pull-down-text {
- color: #7c3aed !important;
+ color: #6b5420 !important;
text-shadow: none !important;
}
@@ -120,7 +129,7 @@
}
.pingtai-card {
- background: linear-gradient(to bottom, #7c3aed, #c4b5fd) !important;
+ background: linear-gradient(to bottom, #927a46, #cec180) !important;
padding: 0 0 16rpx !important;
}
@@ -131,7 +140,7 @@
.pingtai-card .card-top,
.shangjia-card .card-top {
- background: linear-gradient(50deg, #6d28d9, #9333ea) !important;
+ background: linear-gradient(50deg, #957c48, #5c4a28) !important;
border-radius: 28rpx 28rpx 0 0 !important;
margin: -28rpx -24rpx 16rpx !important;
padding: 16rpx 24rpx !important;
@@ -139,11 +148,11 @@
.pingtai-tag,
.creat-time {
- color: #ede9fe !important;
+ color: #fcd270 !important;
}
.shangjia-card {
- background: linear-gradient(to bottom, #f5f3ff, #ddd6fe) !important;
+ background: linear-gradient(to bottom, #fff8e1, #ffe0b2) !important;
}
.card-content,
@@ -167,26 +176,26 @@
}
.fenyong-box {
- background: linear-gradient(to bottom, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(to bottom, #fae04d, #ffc0a3) !important;
border-radius: 30rpx !important;
}
.fenyong-text,
.fenyong-price,
.fenyong-unit {
- color: #4c1d95 !important;
+ color: #492f00 !important;
}
.qiangdan-btn,
.mecha-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
border: 2rpx solid #fff !important;
- box-shadow: 0 4rpx 12rpx rgba(124, 58, 237, 0.25) !important;
+ box-shadow: 0 4rpx 12rpx rgba(180, 130, 20, 0.25) !important;
}
.qiangdan-btn .btn-text,
.mecha-btn .btn-text {
- color: #4c1d95 !important;
+ color: #492f00 !important;
}
.btn-shine,
@@ -196,7 +205,7 @@
}
.loading-mask {
- background: rgba(245, 243, 255, 0.85) !important;
+ background: rgba(255, 248, 225, 0.85) !important;
}
.loading-mask-text,
@@ -206,7 +215,7 @@
}
.unauthorized-container {
- background: linear-gradient(180deg, #c4b5fd, #fff 50%) !important;
+ background: linear-gradient(180deg, #f7dc51, #fff 50%) !important;
}
.unauthorized-card {
@@ -225,12 +234,12 @@
}
.btn-register {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
border-radius: 44rpx !important;
}
.btn-register .btn-text {
- color: #4c1d95 !important;
+ color: #492f00 !important;
}
.card-glow {
@@ -246,15 +255,15 @@
}
.tag-platform {
- background: rgba(196, 181, 253, 0.28);
- color: #ede9fe;
- border: 1rpx solid rgba(196, 181, 253, 0.55);
+ background: rgba(252, 210, 112, 0.22);
+ color: #fcd270;
+ border: 1rpx solid rgba(252, 210, 112, 0.45);
}
.tag-merchant {
background: rgba(255, 255, 255, 0.45);
- color: #6d28d9;
- border: 1rpx solid rgba(147, 51, 234, 0.55);
+ color: #492f00;
+ border: 1rpx solid rgba(255, 208, 97, 0.55);
}
.fenyong-mark {
@@ -264,7 +273,7 @@
text-align: center;
font-size: 22rpx;
font-weight: 700;
- color: #4c1d95;
+ color: #492f00;
background: rgba(255, 255, 255, 0.72);
border-radius: 50%;
margin-right: 8rpx;
@@ -286,3 +295,62 @@
font-weight: 700 !important;
letter-spacing: 1rpx;
}
+
+/* 手动刷新悬浮钮(抢单池 / 接单页) */
+.refresh-float {
+ position: fixed;
+ right: 24rpx;
+ top: calc(env(safe-area-inset-top) + 88rpx);
+ z-index: 20;
+ width: 64rpx;
+ height: 64rpx;
+ background: rgba(255, 255, 255, 0.92);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.12);
+ border: 2rpx solid rgba(255, 208, 97, 0.45);
+}
+
+.refresh-float:active {
+ transform: scale(0.96);
+}
+
+.refresh-float-ico {
+ width: 34rpx;
+ height: 34rpx;
+}
+
+.dingdanxiang1.filter-card {
+ margin: 12rpx 20rpx 8rpx !important;
+ border-radius: 24rpx !important;
+ background: rgba(255, 255, 255, 0.95) !important;
+ box-shadow: 0 6rpx 18rpx rgba(0, 0, 0, 0.06) !important;
+ border: 2rpx solid rgba(255, 224, 130, 0.45) !important;
+}
+
+.xym-gonggao-bar {
+ margin: 8rpx 20rpx 0;
+ padding: 12rpx 16rpx;
+ border-radius: 12rpx;
+ background: rgba(255, 255, 255, 0.9);
+ display: flex;
+ align-items: center;
+}
+
+.xym-gonggao-ico {
+ width: 32rpx;
+ height: 32rpx;
+ margin-right: 12rpx;
+ flex-shrink: 0;
+}
+
+.xym-gonggao-txt {
+ font-size: 24rpx;
+ color: #492f00;
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
diff --git a/styles/dashou-xym-user.wxss b/styles/dashou-xym-user.wxss
new file mode 100644
index 0000000..74ba2bf
--- /dev/null
+++ b/styles/dashou-xym-user.wxss
@@ -0,0 +1,292 @@
+/* 打手「我的」页 - 逍遥梦 user 页视觉(仅样式) */
+@import './xym-layout.wxss';
+
+.shadow {
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+}
+
+.user-page.xym-user {
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
+}
+
+.user-page.xym-user .bg-img {
+ display: none;
+}
+
+.user-page.xym-user .wallet-card {
+ margin: 0 30rpx;
+ padding: 20rpx;
+ border-radius: 26rpx;
+ background: #fef6d4;
+}
+
+.user-page.xym-user .w-label {
+ color: #666;
+ font-size: 26rpx;
+}
+
+.user-page.xym-user .w-num {
+ font-size: 44rpx;
+ font-weight: 700;
+ color: #222;
+ margin-top: 10rpx;
+}
+
+.user-page.xym-user .w-sub {
+ color: #666;
+ font-size: 26rpx;
+ margin-top: 8rpx;
+}
+
+.user-page.xym-user .btn-outline {
+ padding: 10rpx 24rpx;
+ font-size: 26rpx;
+ font-weight: 700;
+ border: 2rpx solid #fff;
+ border-radius: 60rpx;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ white-space: nowrap;
+ margin-left: 12rpx;
+}
+
+.user-page.xym-user .banner-row {
+ margin: 20rpx 24rpx 0;
+ align-items: flex-start;
+}
+
+.user-page.xym-user .banner-img {
+ width: 48%;
+ height: 150rpx;
+ border-radius: 16rpx;
+ overflow: hidden;
+ background: #eee;
+ display: block;
+}
+
+.user-page.xym-user .banner-row .banner-img:first-child {
+ margin-right: 2%;
+}
+
+.user-page.xym-user .qiepian-wrap {
+ margin: 20rpx 24rpx 0;
+ border-radius: 16rpx;
+ overflow: hidden;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.user-page.xym-user .qiepian-banner {
+ width: 100%;
+ display: block;
+ min-height: 120rpx;
+}
+
+.user-page.xym-user .tip-bar {
+ margin: 22rpx 30rpx 0;
+ padding: 20rpx;
+ border-radius: 20rpx;
+ background: #ffedee;
+ color: #ff4c45;
+ font-size: 26rpx;
+}
+
+.user-page.xym-user .tip-ico {
+ width: 28rpx;
+ height: 28rpx;
+ margin-right: 12rpx;
+}
+
+.user-page.xym-user .tip-arrow {
+ color: #ff4c45;
+ font-size: 36rpx;
+}
+
+.user-page.xym-user .my-box {
+ border-radius: 20rpx;
+ margin: 20rpx;
+ padding-bottom: 10rpx;
+ background: #fdfcfa;
+}
+
+.user-page.xym-user .panel-title {
+ padding: 35rpx 35rpx 0;
+ font-weight: 700;
+}
+
+.user-page.xym-user .lg {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #222;
+}
+
+.user-page.xym-user .muted {
+ color: #999;
+ font-size: 28rpx;
+}
+
+.user-page.xym-user .sm {
+ font-size: 24rpx;
+ color: #666;
+}
+
+.user-page.xym-user .order-nav {
+ padding: 26rpx 0 10rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.user-page.xym-user .nav-item {
+ width: 25%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.user-page.xym-user .icon-wrap {
+ position: relative;
+ display: flex;
+ justify-content: center;
+}
+
+.user-page.xym-user .nav-badge {
+ position: absolute;
+ top: -8rpx;
+ right: 8rpx;
+ min-width: 32rpx;
+ height: 32rpx;
+ line-height: 32rpx;
+ text-align: center;
+ font-size: 20rpx;
+ background: #ff4c45;
+ color: #fff;
+ border-radius: 16rpx;
+ z-index: 1;
+ padding: 0 6rpx;
+}
+
+.user-page.xym-user .nav-icon {
+ width: 62rpx;
+ height: 62rpx;
+ margin-bottom: 10rpx;
+}
+
+.user-page.xym-user .section-hd {
+ font-weight: 700;
+ font-size: 32rpx;
+ padding: 30rpx 20rpx 0;
+ color: #222;
+}
+
+.user-page.xym-user .trade-list {
+ flex-wrap: wrap;
+ padding: 20rpx 10rpx;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+}
+
+.user-page.xym-user .trade-item {
+ width: 20%;
+ padding: 12rpx 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.user-page.xym-user .trade-icon {
+ width: 50rpx;
+ height: 50rpx;
+ margin-bottom: 10rpx;
+}
+
+.user-page.xym-user .invite-row {
+ padding: 20rpx 10rpx 30rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.user-page.xym-user .invite-item {
+ width: 33.33%;
+ padding: 10rpx 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.user-page.xym-user .invite-icon {
+ width: 50rpx;
+ height: 50rpx;
+ margin-bottom: 8rpx;
+}
+
+.user-page.xym-user .func-list {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 10rpx 0;
+}
+
+.user-page.xym-user .func-item-xym {
+ width: 25%;
+ padding: 16rpx 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.user-page.xym-user .func-icon-wrap {
+ width: 88rpx;
+ height: 88rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 8rpx;
+}
+
+.user-page.xym-user .func-icon-xym {
+ width: 48rpx;
+ height: 48rpx;
+}
+
+.user-page.xym-user .func-txt-xym {
+ font-size: 24rpx;
+ color: #666;
+ text-align: center;
+}
+
+.user-page.xym-user .follow-kuaishou {
+ position: fixed;
+ right: 0;
+ bottom: calc(280rpx + env(safe-area-inset-bottom));
+ z-index: 99;
+ display: flex;
+ align-items: center;
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 40rpx 0 0 40rpx;
+ padding: 12rpx 16rpx 12rpx 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.user-page.xym-user .follow-kuaishou.expanded {
+ padding-right: 24rpx;
+}
+
+.user-page.xym-user .ks-icon {
+ width: 48rpx;
+ height: 48rpx;
+}
+
+.user-page.xym-user .ks-text {
+ font-size: 24rpx;
+ color: #333;
+ margin-left: 10rpx;
+ white-space: nowrap;
+}
+
+.user-page.xym-user .load-tip {
+ text-align: center;
+ color: #999;
+ font-size: 24rpx;
+ padding: 24rpx 0 40rpx;
+}
diff --git a/styles/shangjia-merchant-order-card.wxss b/styles/shangjia-merchant-order-card.wxss
new file mode 100644
index 0000000..966be62
--- /dev/null
+++ b/styles/shangjia-merchant-order-card.wxss
@@ -0,0 +1,219 @@
+/* 商家订单列表卡片 - 对齐逍遥梦 ui-preview/index */
+
+.normal-card {
+ padding-bottom: 5rpx;
+ margin-bottom: 24rpx;
+ border-radius: 30rpx;
+ position: relative;
+ background: linear-gradient(to bottom, #fff8e1, #ffe0b2);
+ box-sizing: border-box;
+ overflow: hidden;
+ box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.12);
+}
+
+.normal-body-wrap {
+ border-radius: 10rpx 10rpx 30rpx 30rpx;
+ padding: 0 20rpx 20rpx;
+}
+
+.normal-card .order-row {
+ padding: 20rpx 10rpx 10rpx;
+}
+
+.normal-card .remark-block.dark {
+ color: #888;
+ border: none;
+ background: transparent;
+ margin: 0 10rpx 10rpx;
+ padding: 8rpx 20rpx;
+ border-bottom: 1rpx dotted #ddd;
+ padding-bottom: 15rpx;
+ border-radius: 0;
+}
+
+.normal-card .remark-label.dark-t {
+ color: #888;
+ font-weight: 400;
+}
+
+.normal-card .merchant-tags-container {
+ margin-top: 10rpx;
+ border-top: 3rpx dotted rgba(255, 255, 255, 0.85);
+ padding-top: 16rpx;
+}
+
+.normal-card .o-foot {
+ margin-top: 20rpx;
+ padding: 0 10rpx 6rpx;
+}
+
+/* 金牌卡样式见 dashou-xym-order-card.wxss,此处仅保留商家端差异 */
+
+.order-con {
+ position: relative;
+ min-height: 100rpx;
+}
+
+.order-row {
+ align-items: flex-start;
+}
+
+.o-logo {
+ width: 88rpx;
+ height: 88rpx;
+ border-radius: 12rpx;
+ margin-right: 14rpx;
+ flex-shrink: 0;
+ background: #eee;
+}
+
+.o-col {
+ flex: 1;
+ min-width: 0;
+ padding-right: 136rpx;
+ box-sizing: border-box;
+}
+
+.o-goods {
+ font-weight: 700;
+ font-size: 30rpx;
+ line-height: 1.5;
+ color: #333;
+}
+
+.line2 {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+}
+
+.reward-badge {
+ position: absolute;
+ right: 0;
+ top: 18rpx;
+ font-size: 24rpx;
+ padding: 6rpx 20rpx;
+ border-radius: 30rpx 10rpx 0 30rpx;
+ display: flex;
+ align-items: baseline;
+ z-index: 3;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+}
+
+.normal-reward {
+ color: #492f00;
+ background: linear-gradient(to bottom, #fae04d, #ffc0a3);
+}
+
+.reward-yen.sm {
+ font-size: 24rpx;
+}
+
+.reward-num {
+ font-weight: 700;
+ font-size: 34rpx;
+}
+
+.reward-num.dark {
+ color: #c00;
+}
+
+.remark-block.dark {
+ color: #666;
+ border-color: #87ceeb;
+ background: rgba(135, 206, 235, 0.12);
+ font-size: 24rpx;
+ margin: 12rpx 10rpx 0;
+ padding: 12rpx 16rpx;
+ border-left: 4rpx solid #87ceeb;
+ border-radius: 0 8rpx 8rpx 0;
+}
+
+.remark-label.dark-t {
+ color: #87ceeb;
+ font-weight: 600;
+}
+
+.merchant-tags-container {
+ margin: 10rpx 5rpx 0;
+}
+
+.biaoqian-inline-scroll {
+ white-space: nowrap;
+ width: 100%;
+}
+
+.merchant-strip {
+ display: flex;
+ align-items: center;
+ background-image: url('https://bintao-1308403501.cos.ap-guangzhou.myqcloud.com/xcx/static/dilanimg/50.png');
+ background-size: 100% 100%;
+ border-radius: 16rpx 16rpx 0 0;
+ padding: 12rpx 16rpx;
+ margin-top: 16rpx;
+}
+
+.m-avatar {
+ width: 70rpx;
+ height: 70rpx;
+ border-radius: 50%;
+ margin-right: 12rpx;
+ flex-shrink: 0;
+ background: #eee;
+}
+
+.m-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.m-name.light-t {
+ color: #fff;
+ font-size: 26rpx;
+ font-weight: 700;
+}
+
+.m-sn.light-sub {
+ color: #fff;
+ font-size: 22rpx;
+ opacity: 0.9;
+ margin-top: 4rpx;
+}
+
+.o-foot {
+ margin-top: 16rpx;
+ padding: 0 10rpx 6rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.o-amt-grey {
+ font-size: 24rpx;
+ color: #999;
+}
+
+.sj-status-pill {
+ font-size: 24rpx;
+ font-weight: 700;
+ padding: 8rpx 20rpx;
+ border-radius: 30rpx;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ flex-shrink: 0;
+}
+
+/* zhiding / gold-card 见 dashou-xym-order-card.wxss */
+
+.myflex {
+ display: flex;
+ align-items: center;
+}
+
+.flexb {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
diff --git a/styles/shangjia-xym-common.wxss b/styles/shangjia-xym-common.wxss
index 1dfbc0d..e15ccb5 100644
--- a/styles/shangjia-xym-common.wxss
+++ b/styles/shangjia-xym-common.wxss
@@ -10,7 +10,7 @@
min-height: 100vh;
display: flex;
flex-direction: column;
- background: linear-gradient(180deg, #c4b5fd 0%, #fff 28%, #f5f3ff 100%);
+ background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
box-sizing: border-box;
overflow: hidden;
}
@@ -49,13 +49,13 @@
font-weight: 700;
border: 2rpx solid #fff;
border-radius: 60rpx;
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
color: #492f00;
white-space: nowrap;
}
.sj-btn-bg {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa);
+ background: linear-gradient(180deg, #fae04d, #ffc0a3);
border-radius: 60rpx;
color: #492f00;
font-weight: 700;
@@ -66,7 +66,7 @@
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 8rpx;
- background: #8b5cf6;
+ background: #ffb74d;
color: #fff;
}
@@ -74,7 +74,7 @@
margin: 0 30rpx;
padding: 24rpx 20rpx;
border-radius: 26rpx;
- background: #ede9fe;
+ background: #fef6d4;
}
.sj-w-label {
@@ -129,11 +129,11 @@
}
.sj-fadan-btn--regular {
- background: linear-gradient(135deg, #f5f3ff, #ddd6fe);
+ background: linear-gradient(135deg, #fff8e1, #ffe0b2);
}
.sj-fadan-btn--custom {
- background: linear-gradient(135deg, #ede9fe, #c4b5fd);
+ background: linear-gradient(135deg, #fef6d4, #ffd061);
}
.sj-fadan-title {
@@ -219,7 +219,7 @@
text-align: center;
padding: 16rpx 8rpx;
border-radius: 12rpx;
- background: linear-gradient(180deg, #f5f3ff, #ede9fe);
+ background: linear-gradient(180deg, #fff8e1, #fef6d4);
font-size: 24rpx;
color: #492f00;
font-weight: 600;
diff --git a/styles/shangjia-xym-form.wxss b/styles/shangjia-xym-form.wxss
index 6239952..40b153c 100644
--- a/styles/shangjia-xym-form.wxss
+++ b/styles/shangjia-xym-form.wxss
@@ -7,11 +7,11 @@
padding: 24rpx;
padding-bottom: 160rpx;
box-sizing: border-box;
- background: linear-gradient(180deg, #c4b5fd 0%, #f5f5f5 18%, #f5f5f5 100%);
+ background: linear-gradient(180deg, #f7dc51 0%, #fff8e1 18%, #fff8e1 100%);
}
.sj-form-theme .balance-card {
- background: #ede9fe !important;
+ background: #fef6d4 !important;
border-radius: 26rpx !important;
padding: 28rpx 24rpx !important;
margin-bottom: 20rpx !important;
@@ -76,7 +76,7 @@
}
.sj-form-theme .card-dot {
- background: #9333ea !important;
+ background: #ffd061 !important;
}
.sj-form-theme .card-title,
@@ -108,12 +108,12 @@
.sj-form-theme .type-chip--active,
.sj-form-theme .type-active {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
font-weight: 700 !important;
border: none !important;
transform: none !important;
- box-shadow: 0 4rpx 12rpx rgba(147, 51, 234, 0.35) !important;
+ box-shadow: 0 4rpx 12rpx rgba(255, 208, 97, 0.45) !important;
}
.sj-form-theme .type-text {
@@ -161,11 +161,11 @@
}
.sj-form-theme .submit-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
border-radius: 44rpx !important;
font-weight: 700 !important;
- box-shadow: 0 6rpx 16rpx rgba(147, 51, 234, 0.35) !important;
+ box-shadow: 0 6rpx 16rpx rgba(255, 208, 97, 0.45) !important;
}
.sj-form-theme .submit-bar {
@@ -174,7 +174,7 @@
}
.sj-form-theme switch {
- color: #9333ea !important;
+ color: #ffd061 !important;
}
.sj-form-theme .search-section {
@@ -197,7 +197,7 @@
}
.sj-form-theme .search-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
box-shadow: none !important;
}
@@ -233,7 +233,7 @@
.sj-form-theme .generate-grid-btn,
.sj-form-theme .copy-grid-btn,
.sj-form-theme .action-grid-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
border: 2rpx solid #fff !important;
box-shadow: none !important;
@@ -250,7 +250,7 @@
}
.sj-form-theme .tutorial-btn {
- background: linear-gradient(180deg, #c4b5fd, #a78bfa) !important;
+ background: linear-gradient(180deg, #fae04d, #ffc0a3) !important;
color: #492f00 !important;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1) !important;
}
diff --git a/styles/xym-layout.wxss b/styles/xym-layout.wxss
new file mode 100644
index 0000000..491c41e
--- /dev/null
+++ b/styles/xym-layout.wxss
@@ -0,0 +1,5 @@
+/* 逍遥梦布局工具类 */
+.flex { display: flex; align-items: center; }
+.flexb { display: flex; align-items: center; justify-content: space-between; }
+.flexa { display: flex; align-items: center; justify-content: space-around; }
+.flexmc { display: flex; flex-direction: column; align-items: center; justify-content: center; }
diff --git a/styles/xym-recharge-shared.wxss b/styles/xym-recharge-shared.wxss
new file mode 100644
index 0000000..93243d9
--- /dev/null
+++ b/styles/xym-recharge-shared.wxss
@@ -0,0 +1,171 @@
+/* 会员/保证金充值页共用弹窗与 loading */
+.modal-mask {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.45);
+ z-index: 1000;
+ display: flex;
+ align-items: flex-end;
+ justify-content: center;
+}
+
+.modal-panel {
+ width: 100%;
+ background: #fff;
+ border-radius: 32rpx 32rpx 0 0;
+ padding: 32rpx 28rpx calc(24rpx + env(safe-area-inset-bottom));
+}
+
+.modal-title {
+ display: block;
+ font-size: 34rpx;
+ font-weight: 700;
+ text-align: center;
+ margin-bottom: 8rpx;
+}
+
+.modal-sub {
+ display: block;
+ text-align: center;
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 24rpx;
+}
+
+.amount-input-wrap {
+ display: flex;
+ align-items: center;
+ border-bottom: 2rpx solid #f0e6d8;
+ padding-bottom: 12rpx;
+ margin-bottom: 20rpx;
+}
+
+.amount-prefix {
+ font-size: 40rpx;
+ font-weight: 700;
+ color: #492f00;
+ margin-right: 8rpx;
+}
+
+.amount-input {
+ flex: 1;
+ font-size: 36rpx;
+}
+
+.quick-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+ margin-bottom: 24rpx;
+}
+
+.quick-chip {
+ padding: 12rpx 24rpx;
+ border-radius: 999rpx;
+ background: #f5f5f5;
+ font-size: 26rpx;
+ color: #666;
+}
+
+.quick-chip.active {
+ background: #fff3cd;
+ color: #492f00;
+ font-weight: 600;
+}
+
+.modal-actions {
+ display: flex;
+ gap: 20rpx;
+}
+
+.modal-btn {
+ flex: 1;
+ height: 88rpx;
+ border-radius: 44rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 30rpx;
+}
+
+.modal-btn.cancel {
+ background: #f5f5f5;
+ color: #666;
+}
+
+.modal-btn.confirm {
+ background: linear-gradient(90deg, #fae04d, #ffc0a3);
+ color: #492f00;
+ font-weight: 700;
+}
+
+.pay-method-item {
+ padding: 28rpx 20rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+}
+
+.pay-method-name {
+ display: block;
+ font-size: 30rpx;
+ font-weight: 600;
+}
+
+.pay-method-desc {
+ display: block;
+ font-size: 24rpx;
+ color: #999;
+ margin-top: 6rpx;
+}
+
+.balance-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 24rpx 12rpx;
+ border-bottom: 1rpx solid #f5f5f5;
+ font-size: 28rpx;
+}
+
+.balance-need {
+ color: #e6a23c;
+ font-weight: 600;
+}
+
+.confirm-row {
+ display: flex;
+ justify-content: space-between;
+ padding: 16rpx 0;
+ font-size: 28rpx;
+}
+
+.loading-mask {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.35);
+ z-index: 2000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.loading-box {
+ background: #fff;
+ border-radius: 20rpx;
+ padding: 40rpx 48rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 16rpx;
+}
+
+.loading-spinner {
+ width: 56rpx;
+ height: 56rpx;
+ border: 4rpx solid #f0e6d8;
+ border-top-color: #f5a623;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
diff --git a/tab-bar/index.js b/tab-bar/index.js
index d3e09a0..f16bc59 100644
--- a/tab-bar/index.js
+++ b/tab-bar/index.js
@@ -32,6 +32,13 @@ const roleCfg = {
},
};
+const TAB_BAR_NATIVE_PAGES = new Set([
+ 'pages/accept-order/accept-order',
+ 'pages/fighter-orders/fighter-orders',
+ 'pages/messages/messages',
+ 'pages/fighter/fighter',
+]);
+
Component({
data: {
selectedIndex: 0,
@@ -43,6 +50,7 @@ Component({
lifetimes: {
attached() {
this.refresh();
+ this._restoreBadgeFromCache();
this._badgeListener = (data) => {
if (data.badgeText !== undefined) {
this.setData({ badgeText: data.badgeText });
@@ -61,20 +69,48 @@ Component({
pageLifetimes: {
show() {
this.refresh();
- const globalBadge = app.globalData.messageManager?.tabBarBadgeText || '';
- if (this.data.badgeText !== globalBadge) {
- this.setData({ badgeText: globalBadge });
- }
+ this._restoreBadgeFromCache();
this._syncUnreadWithDebounce();
},
},
methods: {
+ _restoreBadgeFromCache() {
+ const mm = app.globalData.messageManager || {};
+ let badgeText = mm.tabBarBadgeText || '';
+ if (!badgeText) {
+ try {
+ badgeText = wx.getStorageSync('tabBarMessageBadge') || '';
+ } catch (e) {}
+ }
+ if (!badgeText && mm.unreadTotal > 0) {
+ badgeText = mm.unreadTotal > 99 ? '99+' : String(mm.unreadTotal);
+ }
+ if (!badgeText) {
+ try {
+ const saved = wx.getStorageSync('messageUnreadTotal');
+ if (saved > 0) badgeText = saved > 99 ? '99+' : String(saved);
+ } catch (e) {}
+ }
+ if (badgeText && badgeText !== this.data.badgeText) {
+ this.setData({ badgeText });
+ }
+ if (app.restoreTabBarBadge) app.restoreTabBarBadge();
+ },
+
_syncUnreadWithDebounce() {
if (this._syncTimer) clearTimeout(this._syncTimer);
this._syncTimer = setTimeout(() => {
- if (app && app.loadConversations) app.loadConversations();
- }, 300);
+ if (app.globalData.goEasyConnection) {
+ app.globalData.goEasyConnection.autoReconnect = true;
+ }
+ if (app.startImWhenReady) {
+ app.startImWhenReady();
+ } else {
+ if (app.ensureConnection) app.ensureConnection();
+ if (app.loadConversations) app.loadConversations();
+ }
+ }, 200);
},
refresh() {
@@ -104,7 +140,13 @@ Component({
const path = e.currentTarget.dataset.path;
const idx = e.currentTarget.dataset.index;
if (idx === this.data.selectedIndex) return;
- wx.redirectTo({ url: '/' + path });
+ const url = '/' + path;
+ // tabBar 注册页用 switchTab;其余页用 reLaunch(redirectTo 对 tab 页会失败)
+ if (TAB_BAR_NATIVE_PAGES.has(path)) {
+ wx.switchTab({ url });
+ } else {
+ wx.reLaunch({ url });
+ }
},
},
});
diff --git a/tab-bar/index.wxss b/tab-bar/index.wxss
index e9a5bd1..b348446 100644
--- a/tab-bar/index.wxss
+++ b/tab-bar/index.wxss
@@ -47,7 +47,7 @@
}
.c-tab-txt-on {
- color: #9333ea;
+ color: #ffd061;
font-weight: 600;
}
diff --git a/utils/avatar.js b/utils/avatar.js
index c5efd6b..0c0c725 100644
--- a/utils/avatar.js
+++ b/utils/avatar.js
@@ -1,4 +1,4 @@
-/** 统一头像 URL:无有效头像时始终返回 ossImageUrl + morentouxiang */
+/** 统一头像 URL:无有效头像时始终返回 ossImageUrl + morentouxiang(后端配置) */
function isBlankPath(p) {
if (p == null) return true;
@@ -7,28 +7,71 @@ function isBlankPath(p) {
return !s || s === 'null' || s === 'undefined' || s === 'none';
}
+function readConfigFallback(app) {
+ if (!app || typeof app.readConfigFromStorage !== 'function') return null;
+ try {
+ return app.readConfigFromStorage();
+ } catch (e) {
+ return null;
+ }
+}
+
+function getOssBase(app) {
+ let oss = app.globalData?.ossImageUrl || '';
+ if (!oss) {
+ const cfg = readConfigFallback(app);
+ oss = cfg?.cos?.ossImageUrl || '';
+ }
+ return oss;
+}
+
+function getDefaultRelative(app) {
+ let def = app.globalData?.morentouxiang || '';
+ if (!def) {
+ const cfg = readConfigFallback(app);
+ def = cfg?.otherConfig?.morentouxiang || '';
+ }
+ return def || 'avatar/default.jpg';
+}
+
export function getDefaultAvatarUrl(app) {
return resolveAvatarUrl('', app);
}
export function resolveAvatarUrl(rawPath, app) {
app = app || getApp();
- const oss = app.globalData.ossImageUrl || '';
- const def = app.globalData.morentouxiang || 'avatar/default.jpg';
+ const oss = getOssBase(app);
+ const def = getDefaultRelative(app);
if (!isBlankPath(rawPath)) {
if (rawPath.startsWith('http://') || rawPath.startsWith('https://')) {
return rawPath;
}
- const path = rawPath.startsWith('/') ? rawPath : '/' + rawPath;
- return oss + path;
+ const path = rawPath.startsWith('/') ? rawPath : `/${rawPath}`;
+ if (oss) return oss + path;
+ return path;
}
if (def.startsWith('http://') || def.startsWith('https://')) {
return def;
}
- const defPath = def.startsWith('/') ? def : '/' + def;
- return oss + defPath;
+ const defPath = def.startsWith('/') ? def : `/${def}`;
+ if (oss) return oss + defPath;
+ // 配置未就绪时仍返回相对路径,由 binderror 回退;有 oss 时必须拼完整 URL
+ return defPath;
+}
+
+/** 是否已是可加载的完整头像 URL */
+export function isUsableAvatarUrl(url) {
+ return url && (url.startsWith('http://') || url.startsWith('https://'));
+}
+
+export function ensureAvatarUrl(rawPath, app) {
+ app = app || getApp();
+ const resolved = resolveAvatarUrl(rawPath, app);
+ if (isUsableAvatarUrl(resolved)) return resolved;
+ const def = getDefaultAvatarUrl(app);
+ return isUsableAvatarUrl(def) ? def : resolved;
}
export function resolveAvatarFromStorage(app) {
@@ -36,3 +79,19 @@ export function resolveAvatarFromStorage(app) {
const tx = wx.getStorageSync('touxiang') || '';
return resolveAvatarUrl(tx, app);
}
+
+/** 配置加载后刷新页面头像(聊天页等订阅 configApplied) */
+export function subscribeConfigAvatarRefresh(page, refreshFn) {
+ const app = getApp();
+ if (!app || typeof refreshFn !== 'function') return null;
+ const handler = () => refreshFn();
+ if (app.on) app.on('configApplied', handler);
+ return () => { if (app.off) app.off('configApplied', handler); };
+}
+
+/** 消息列表/聊天页 image 加载失败时回退默认头像 */
+export function onAvatarImageError(page, dataKey, app) {
+ if (!page || !dataKey) return;
+ const def = getDefaultAvatarUrl(app || getApp());
+ page.setData({ [dataKey]: def });
+}
diff --git a/utils/base-page.js b/utils/base-page.js
index 6531b92..bb13c82 100644
--- a/utils/base-page.js
+++ b/utils/base-page.js
@@ -272,6 +272,10 @@ const BASE_METHODS = {
const result = {};
Object.keys(urlMap).forEach((key) => {
const path = urlMap[key];
+ if (!path || typeof path !== 'string') {
+ result[key] = '';
+ return;
+ }
result[key] = path.startsWith('http') || path.startsWith('/') ? path : ossImageUrl + path;
});
return result;
diff --git a/utils/chat-core.js b/utils/chat-core.js
index 58c4e93..8f2b97c 100644
--- a/utils/chat-core.js
+++ b/utils/chat-core.js
@@ -1,400 +1,991 @@
-// utils/chat-core.js — 全局 IM 连接、监听、角标(稳定版)
-import GoEasy from '../static/lib/goeasy-2.13.24.esm.min';
-import { resolveAvatarUrl } from './avatar.js';
-import { getLocalImUserId, getLocalImIdentity } from './im-user.js';
-
-let _convListener = null;
-let _privateListener = null;
-let _groupListener = null;
-let _notificationHandler = null;
-let _heartbeatTimer = null;
-let _listenersBoundForUser = null;
-let _lastGroupSubscribeAt = 0;
-const _notifiedMessageIds = new Map();
-const NOTIFY_MAX_AGE_MS = 15000;
-
-function shouldShowNotification(message) {
- if (!message) return false;
- const id = message.messageId || `${message.senderId}_${message.timestamp}`;
- if (_notifiedMessageIds.has(id)) return false;
- if (message.timestamp && Date.now() - message.timestamp > NOTIFY_MAX_AGE_MS) return false;
- _notifiedMessageIds.set(id, Date.now());
- if (_notifiedMessageIds.size > 400) {
- const cutoff = Date.now() - 60000;
- _notifiedMessageIds.forEach((t, k) => {
- if (t < cutoff) _notifiedMessageIds.delete(k);
- });
- }
- return true;
-}
-
-function bindGlobalListenersIfNeeded(app, userId) {
- if (_listenersBoundForUser === userId && _convListener) return;
- registerGlobalListeners(app);
- registerNotification(app);
- _listenersBoundForUser = userId;
-}
-
-function initGlobalMessageSystem(app) {
- app.ensureConnection = () => ensureConnection(app);
- app.connectForCurrentRole = () => ensureConnection(app);
- app.loadConversations = () => loadConversations(app);
- app.disconnectGoEasy = () => disconnectGoEasy(app);
- app.switchRoleAndReconnect = (newRole) => switchRoleAndReconnect(app, newRole);
- app.updateUnreadCount = (count) => updateTabBarBadge(app, count || 0);
- app.reregisterNotification = () => registerNotification(app);
- app.startImWhenReady = () => startImWhenReady(app);
-
- if (!app.globalData.messageManager) {
- app.globalData.messageManager = {};
- }
- try {
- const muted = wx.getStorageSync('notificationMuted');
- if (muted !== undefined) app.globalData.messageManager.notificationMuted = muted;
- } catch (e) {}
-
- initAppStateListener(app);
- initNetworkListener(app);
- startHeartbeat(app);
- startImWhenReady(app);
-}
-
-/** GoEasy 未就绪时轮询,登录后尽早建立监听 */
-function startImWhenReady(app, maxAttempts = 40) {
- let attempts = 0;
- const tick = () => {
- if (!wx.getStorageSync('uid')) return;
- attempts += 1;
- if (!wx.goEasy) {
- if (attempts < maxAttempts) setTimeout(tick, 250);
- return;
- }
- ensureConnection(app);
- };
- tick();
-}
-
-function getCurrentUserId() {
- return (wx.goEasy && wx.goEasy.im && wx.goEasy.im.userId) || null;
-}
-
-function getConnectionStatus() {
- if (!wx.goEasy || !wx.goEasy.getConnectionStatus) return 'disconnected';
- return wx.goEasy.getConnectionStatus();
-}
-
-function isConnected() {
- const s = getConnectionStatus();
- return s === 'connected' || s === 'reconnected';
-}
-
-/** 统一会话数据结构,避免不同回调格式导致列表空白 */
-function normalizeConversationsPayload(result) {
- if (!result) return { conversations: [], unreadTotal: 0 };
- const content = result.content || result;
- const conversations = content.conversations || result.conversations || [];
- const unreadTotal = content.unreadTotal ?? result.unreadTotal ?? 0;
- return { conversations, unreadTotal };
-}
-
-function emitConversationsUpdated(app, result) {
- const payload = normalizeConversationsPayload(result);
- updateTabBarBadge(app, payload.unreadTotal);
- app.emitEvent('conversationsUpdated', {
- content: payload,
- unreadTotal: payload.unreadTotal,
- raw: result,
- });
-}
-
-async function ensureConnection(app) {
- const uid = wx.getStorageSync('uid');
- if (!uid || !wx.goEasy) return;
-
- const targetUserId = getLocalImUserId(app);
- const identityType = getLocalImIdentity(app);
- if (!targetUserId) return;
-
- if (isConnected()) {
- const currentUserId = getCurrentUserId();
- if (currentUserId === targetUserId) {
- bindGlobalListenersIfNeeded(app, targetUserId);
- loadConversations(app);
- const now = Date.now();
- if (now - _lastGroupSubscribeAt > 60000) {
- _lastGroupSubscribeAt = now;
- await subscribeAllGroups(app);
- }
- return;
- }
- try {
- wx.goEasy.disconnect();
- } catch (e) {}
- }
-
- connectGoEasy(app, targetUserId, identityType);
-}
-
-function connectGoEasy(app, userId, identityType) {
- const defAvatar = resolveAvatarUrl('', app);
- const tx = wx.getStorageSync('touxiang') || '';
- const uid = wx.getStorageSync('uid') || '';
- const nick = wx.getStorageSync('nicheng') || app.globalData.nicheng || app.globalData.dashouNicheng || '';
- const name = nick || ('用户' + (uid || '').substring(0, 6));
- const avatar = resolveAvatarUrl(tx, app) || defAvatar;
-
- wx.goEasy.connect({
- id: userId,
- data: {
- name,
- avatar,
- identityType: identityType === 'normal' ? 'boss' : identityType,
- },
- onSuccess: async () => {
- try {
- wx.setStorageSync('savedGoEasyConnection', JSON.stringify({
- userId,
- identityType,
- lastConnectTime: Date.now(),
- status: 'connected',
- }));
- } catch (e) {}
- bindGlobalListenersIfNeeded(app, userId);
- _lastGroupSubscribeAt = Date.now();
- await subscribeAllGroups(app);
- loadConversations(app);
- },
- onFailed: (error) => {
- console.error('GoEasy连接失败', error);
- if (error.code === 408) {
- bindGlobalListenersIfNeeded(app, userId);
- loadConversations(app);
- } else {
- wx.showToast({ title: '连接失败,请重试', icon: 'none' });
- }
- },
- });
-}
-
-function subscribeAllGroups(app) {
- return new Promise((resolve) => {
- if (!wx.goEasy || !wx.goEasy.im) return resolve();
- wx.goEasy.im.latestConversations({
- onSuccess: (result) => {
- const payload = normalizeConversationsPayload(result);
- const groupIds = payload.conversations
- .filter((c) => c.type === 'group' && c.groupId)
- .map((c) => c.groupId);
- if (groupIds.length && wx.goEasy.im.subscribeGroup) {
- wx.goEasy.im.subscribeGroup({
- groupIds,
- onSuccess: () => resolve(),
- onFailed: () => resolve(),
- });
- } else {
- resolve();
- }
- },
- onFailed: () => resolve(),
- });
- });
-}
-
-function registerGlobalListeners(app) {
- if (!wx.goEasy || !wx.goEasy.im) return;
-
- if (_convListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener);
- }
- if (_privateListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener);
- }
- if (_groupListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener);
- }
-
- _convListener = (result) => {
- emitConversationsUpdated(app, result);
- };
- wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener);
-
- _privateListener = () => {
- loadConversations(app);
- };
- wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener);
-
- _groupListener = () => {
- loadConversations(app);
- };
- wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener);
-}
-
-function loadConversations(app) {
- if (!wx.goEasy || !wx.goEasy.im) return;
- if (!getCurrentUserId()) return;
-
- wx.goEasy.im.latestConversations({
- onSuccess: (result) => {
- emitConversationsUpdated(app, result);
- subscribeAllGroups(app);
- },
- onFailed: (err) => {
- console.error('加载会话失败', err);
- },
- });
-}
-
-function updateTabBarBadge(app, unreadCount) {
- const badgeText = unreadCount > 0 ? (unreadCount > 99 ? '99+' : String(unreadCount)) : '';
- if (!app.globalData.messageManager) app.globalData.messageManager = {};
- app.globalData.messageManager.unreadTotal = unreadCount;
- app.globalData.messageManager.tabBarBadgeText = badgeText;
- app.emitEvent('tabBarBadgeChanged', { badgeText, showRedDot: unreadCount > 0 });
-
- try {
- const pages = getCurrentPages();
- if (pages.length) {
- const page = pages[pages.length - 1];
- const tabBar = page.selectComponent('#tab-bar');
- if (tabBar && tabBar.setData) tabBar.setData({ badgeText });
- if (page.getTabBar) {
- const tb = page.getTabBar();
- if (tb && tb.setData) tb.setData({ badgeText });
- }
- }
- } catch (e) {}
- wx.setStorageSync('messageUnreadTotal', unreadCount);
-}
-
-function registerNotification(app) {
- if (!wx.goEasy || !wx.goEasy.im) return;
-
- if (_notificationHandler) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler);
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler);
- }
-
- _notificationHandler = (message) => {
- if (app.globalData.messageManager && app.globalData.messageManager.notificationMuted) return;
- if (!shouldShowNotification(message)) return;
- const pages = getCurrentPages();
- if (pages.length) {
- const curPage = pages[pages.length - 1];
- const route = curPage.route || '';
- if (route === 'pages/chat/chat' || route === 'pages/group-chat/group-chat') return;
- }
- const senderName = message.senderData?.name || (message.senderId || '用户');
- let content = '';
- if (message.type === 'text') content = message.payload?.text || '[文本]';
- else if (message.type === 'image') content = '[图片]';
- else if (message.type === 'audio') content = '[语音]';
- else content = '[新消息]';
- const avatar = resolveAvatarUrl(message.senderData?.avatar, app);
-
- if (app.globalData.globalNotification && app.globalData.globalNotification.show) {
- app.globalData.globalNotification.show({
- senderName,
- content,
- avatar,
- message,
- notificationType: message.groupId ? 'group' : 'private',
- groupId: message.groupId,
- orderId: message.orderId,
- });
- } else {
- wx.showToast({ title: `${senderName}: ${content}`, icon: 'none', duration: 2000 });
- }
- };
- wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler);
- wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler);
-}
-
-function detachGlobalListeners() {
- if (!wx.goEasy || !wx.goEasy.im) return;
- if (_convListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _convListener);
- _convListener = null;
- }
- if (_privateListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _privateListener);
- _privateListener = null;
- }
- if (_groupListener) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _groupListener);
- _groupListener = null;
- }
- if (_notificationHandler) {
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _notificationHandler);
- wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _notificationHandler);
- _notificationHandler = null;
- }
- _listenersBoundForUser = null;
-}
-
-function disconnectGoEasy(app) {
- stopHeartbeat(app);
- detachGlobalListeners();
- if (wx.goEasy && wx.goEasy.disconnect) {
- wx.goEasy.disconnect({ onSuccess: () => {}, onFailed: () => {} });
- }
- wx.removeStorageSync('savedGoEasyConnection');
-}
-
-async function switchRoleAndReconnect(app, newRole) {
- disconnectGoEasy(app);
- app.globalData.currentRole = newRole;
- wx.setStorageSync('currentRole', newRole);
- if (app.globalData.primaryRole !== newRole && ['normal', 'dashou', 'shangjia'].includes(newRole)) {
- app.globalData.primaryRole = newRole;
- wx.setStorageSync('primaryRole', newRole);
- }
- startHeartbeat(app);
- await ensureConnection(app);
- return true;
-}
-
-function startHeartbeat(app) {
- stopHeartbeat(app);
- _heartbeatTimer = setInterval(() => {
- if (!wx.getStorageSync('uid')) return;
- if (isConnected()) {
- loadConversations(app);
- } else {
- ensureConnection(app);
- }
- }, 45000);
-}
-
-function stopHeartbeat(app) {
- if (_heartbeatTimer) {
- clearInterval(_heartbeatTimer);
- _heartbeatTimer = null;
- }
-}
-
-function initAppStateListener(app) {
- wx.onAppShow(() => {
- setTimeout(() => {
- if (!wx.getStorageSync('uid')) return;
- if (!isConnected()) {
- ensureConnection(app);
- } else {
- loadConversations(app);
- setTimeout(() => {
- const unread = (app.globalData.messageManager && app.globalData.messageManager.unreadTotal) || 0;
- updateTabBarBadge(app, unread);
- }, 300);
- }
- }, 200);
- });
-}
-
-function initNetworkListener(app) {
- wx.onNetworkStatusChange((res) => {
- if (res.isConnected) {
- setTimeout(() => ensureConnection(app), 1000);
- }
- });
-}
-
-module.exports = { initGlobalMessageSystem };
+// utils/chat-core.js — 全局 IM 连接、监听、重连、角标
+import GoEasy from '../static/lib/goeasy-2.13.24.esm.min';
+import { jianquanxian } from './imAuth/jianquanxian';
+import { parseOrderCardText } from './group-chat.js';
+import { persistGroupMeta, getFreshImUser, getImUserIdForRole, getLocalImUserId, getLocalImIdentity } from './im-user.js';
+
+let _globalPrivateHandler = null;
+let _globalGroupHandler = null;
+let _globalConvHandler = null;
+let _imLockDepth = 0;
+let _loadConvTimer = null;
+let _loadConvInFlight = false;
+
+async function withImLock(fn) {
+ if (_imLockDepth > 0) {
+ return await fn();
+ }
+ _imLockDepth += 1;
+ try {
+ return await fn();
+ } finally {
+ _imLockDepth -= 1;
+ }
+}
+
+function initGlobalMessageSystem(app) {
+ app.updateUnreadCount = (count) => updateUnreadCount(app, count);
+ app.disconnectGoEasy = () => disconnectGoEasy(app);
+ app.ensureConnection = () => ensureConnection(app);
+ app.connectWithIdentity = (identityType, userId, isAutoRestore) =>
+ connectWithIdentity(app, identityType, userId, isAutoRestore);
+ app.connectForCurrentRole = () => connectForCurrentRole(app);
+ app.switchRoleAndReconnect = (newRole) => switchRoleAndReconnect(app, newRole);
+ app.toggleDoNotDisturb = (enabled) => toggleDoNotDisturb(app, enabled);
+ app.toggleNotificationMute = (enabled) => toggleNotificationMute(app, enabled);
+ app.closeNotification = () => closeNotification(app);
+ app.loadConversations = () => loadConversations(app);
+ app.updateCurrentPageState = () => updateCurrentPageState(app);
+ app.getSavedConnection = () => getSavedConnection(app);
+ app.clearSavedConnection = () => clearSavedConnection(app);
+ app.saveConnectionState = () => saveConnectionState(app);
+ app.handleNewMessage = (message) => handleNewMessage(app, message);
+ app.ensureImForRole = (role) => ensureImForRole(app, role);
+ app.syncConnectionStatus = () => syncConnectionStatus(app);
+ app.restoreTabBarBadge = () => restoreCachedBadge(app);
+ app.startImWhenReady = () => startImWhenReady(app);
+
+ loadUserSettings(app);
+ initNetworkListener(app);
+ initAppStateListener(app);
+ bindGoEasyLifecycle(app);
+ setupEventSystem(app);
+ checkAndRestoreConnection(app);
+}
+
+function bindGoEasyLifecycle(app) {
+ if (!wx.goEasy || app._goEasyLifecycleBound) return;
+ app._goEasyLifecycleBound = true;
+ try {
+ wx.goEasy.on('connected', () => {
+ app.globalData.goEasyConnection.status = 'connected';
+ app.globalData.goEasyConnection.autoReconnect = true;
+ setupMessageListeners(app);
+ loadConversations(app);
+ startHeartbeat(app);
+ syncConnectionStatus(app);
+ });
+ wx.goEasy.on('disconnected', () => {
+ app.globalData.goEasyConnection.status = 'disconnected';
+ if (!app._imSuppressDisconnectEvent) {
+ app.emitEvent('connectionChanged', { status: 'disconnected' });
+ }
+ if (app.globalData.goEasyConnection.autoReconnect) {
+ setTimeout(() => ensureConnection(app), app.globalData.goEasyConnection.config.reconnectDelay);
+ }
+ });
+ } catch (e) {
+ console.warn('绑定 GoEasy 生命周期失败:', e);
+ }
+}
+
+function getCurrentGoEasyUserId() {
+ return (wx.goEasy && wx.goEasy.im && wx.goEasy.im.userId) || null;
+}
+
+function getExpectedImUserId(app) {
+ const fromLocal = getLocalImUserId(app);
+ if (fromLocal) return fromLocal;
+ const uid = wx.getStorageSync('uid');
+ if (!uid) return '';
+ const role = app.globalData.currentRole || getLocalImIdentity(app) || 'normal';
+ return getImUserIdForRole(role, uid);
+}
+
+function loadUserSettings(app) {
+ try {
+ const messageSettings = wx.getStorageSync(app.globalData.messageManager.cacheKeys.messageSettings);
+ if (messageSettings) {
+ app.globalData.messageManager = { ...app.globalData.messageManager, ...messageSettings };
+ }
+ const notificationMuted = wx.getStorageSync(app.globalData.messageManager.cacheKeys.notificationMuted);
+ if (notificationMuted !== '') {
+ app.globalData.messageManager.notificationMuted = notificationMuted;
+ }
+ const savedUnread = wx.getStorageSync(app.globalData.messageManager.cacheKeys.unreadTotal);
+ if (savedUnread !== '' && savedUnread !== undefined) {
+ app.globalData.messageManager.unreadTotal = savedUnread;
+ updateTabBarBadge(app, savedUnread);
+ }
+ const savedMessages = wx.getStorageSync(app.globalData.messageManager.cacheKeys.latestMessages);
+ if (savedMessages) {
+ app.globalData.messageManager.latestMessages = savedMessages;
+ }
+ } catch (error) {
+ console.warn('加载用户设置失败:', error);
+ }
+}
+
+function initNetworkListener(app) {
+ wx.onNetworkStatusChange((res) => {
+ if (res.isConnected) {
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.globalData.goEasyConnection.reconnectAttempts = 0;
+ app.emitEvent('connectionChanged', { status: 'reconnecting', reason: 'network' });
+ ensureConnection(app);
+ } else {
+ app.globalData.goEasyConnection.status = 'disconnected';
+ app.emitEvent('connectionChanged', { status: 'disconnected', reason: 'network' });
+ }
+ });
+}
+
+function initAppStateListener(app) {
+ wx.onAppShow(() => {
+ updateCurrentPageState(app);
+ app.globalData.goEasyConnection.autoReconnect = true;
+ restoreCachedBadge(app);
+ ensureConnection(app);
+ setTimeout(() => loadConversations(app), 400);
+ });
+ wx.onAppHide(() => {
+ pauseHeartbeat(app);
+ saveConnectionState(app);
+ });
+}
+
+function checkAndRestoreConnection(app) {
+ try {
+ const savedConnection = wx.getStorageSync(app.globalData.goEasyConnection.cacheKeys.savedConnection);
+ if (savedConnection && savedConnection.userId && savedConnection.identityType) {
+ const now = Date.now();
+ const lastTime = savedConnection.lastConnectTime || 0;
+ const hoursDiff = (now - lastTime) / (1000 * 60 * 60);
+ const validityHours = app.globalData.goEasyConnection.config.cacheValidityHours || 12;
+ if (hoursDiff > validityHours) {
+ clearSavedConnection(app);
+ }
+ }
+ ensureConnection(app);
+ } catch (error) {
+ console.warn('检查保存的连接信息失败:', error);
+ }
+}
+
+function setupEventSystem(app) {
+ if (!app.globalData.eventListeners) {
+ app.globalData.eventListeners = {};
+ }
+}
+
+function isSdkConnected() {
+ if (!wx.goEasy?.getConnectionStatus) return false;
+ const s = wx.goEasy.getConnectionStatus();
+ return s === 'connected' || s === 'reconnected';
+}
+
+function isImConnected() {
+ return isSdkConnected();
+}
+
+/** 已连接且身份正确则直接恢复监听,避免重复 connect 触发 408 */
+function adoptExistingConnection(app, identityType, userId) {
+ app.globalData.goEasyConnection.status = 'connected';
+ app.globalData.goEasyConnection.userId = userId;
+ app.globalData.goEasyConnection.identityType = identityType;
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.globalData.goEasyConnection.reconnectAttempts = 0;
+ saveConnectionState(app);
+ startHeartbeat(app);
+ setupMessageListeners(app);
+ loadConversations(app);
+ syncConnectionStatus(app);
+}
+
+/** 根据 SDK 真实状态同步 UI(避免已连接仍显示未连接) */
+function syncConnectionStatus(app) {
+ if (app.globalData.chatEnabled === false) {
+ app.emitEvent('connectionChanged', { status: 'disabled', reason: 'chat_disabled' });
+ return;
+ }
+ const expectedId = getExpectedImUserId(app);
+ if (!expectedId) {
+ app.emitEvent('connectionChanged', { status: 'disconnected', reason: 'no_uid' });
+ return;
+ }
+ const cur = getCurrentGoEasyUserId();
+ if (isSdkConnected() && (!cur || cur === expectedId)) {
+ app.globalData.goEasyConnection.status = 'connected';
+ app.globalData.goEasyConnection.userId = cur || expectedId;
+ app.globalData.goEasyConnection.autoReconnect = true;
+ setupMessageListeners(app);
+ loadConversations(app);
+ restoreCachedBadge(app);
+ app.emitEvent('connectionChanged', { status: 'connected' });
+ return;
+ }
+ const st = app.globalData.goEasyConnection.status;
+ if (st === 'connecting' || st === 'reconnecting') {
+ app.emitEvent('connectionChanged', { status: st });
+ } else {
+ app.emitEvent('connectionChanged', { status: 'disconnected' });
+ }
+}
+
+function ensureConnection(app) {
+ if (!wx.goEasy?.connect) return;
+ if (app.globalData.chatEnabled === false) {
+ syncConnectionStatus(app);
+ return;
+ }
+
+ const expectedId = getExpectedImUserId(app);
+ if (!expectedId) return;
+
+ const role = app.globalData.currentRole || 'normal';
+
+ if (isImConnected()) {
+ const cur = getCurrentGoEasyUserId();
+ if (cur === expectedId) {
+ setupMessageListeners(app);
+ startHeartbeat(app);
+ loadConversations(app);
+ syncConnectionStatus(app);
+ return;
+ }
+ connectForCurrentRole(app);
+ return;
+ }
+
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.emitEvent('connectionChanged', { status: 'connecting' });
+
+ const saved = getSavedConnection(app);
+ if (saved && saved.userId === expectedId && saved.identityType === role) {
+ connectWithIdentity(app, saved.identityType, saved.userId, true);
+ return;
+ }
+
+ connectForCurrentRole(app);
+}
+
+async function ensureImForRole(app, role) {
+ const uid = wx.getStorageSync('uid');
+ if (!uid) throw new Error('未登录');
+ const targetUserId = getImUserIdForRole(role, uid);
+ if (!targetUserId) throw new Error('无效身份');
+
+ if (isImConnected() && getCurrentGoEasyUserId() === targetUserId) {
+ setupMessageListeners(app);
+ loadConversations(app);
+ syncConnectionStatus(app);
+ return;
+ }
+
+ if (app.globalData.currentRole !== role) {
+ app.globalData.currentRole = role;
+ wx.setStorageSync('currentRole', role);
+ }
+
+ await connectWithIdentity(app, role, targetUserId, true);
+}
+
+function getSavedConnection(app) {
+ try {
+ const saved = wx.getStorageSync(app.globalData.goEasyConnection.cacheKeys.savedConnection);
+ if (!saved) return null;
+ if (typeof saved === 'string') return JSON.parse(saved);
+ return saved;
+ } catch (error) {
+ console.error('获取保存的连接信息失败:', error);
+ return null;
+ }
+}
+
+function saveConnectionState(app) {
+ try {
+ const { goEasyConnection } = app.globalData;
+ const connectionState = {
+ userId: goEasyConnection.userId,
+ identityType: goEasyConnection.identityType,
+ lastConnectTime: Date.now(),
+ autoReconnect: goEasyConnection.autoReconnect,
+ status: goEasyConnection.status,
+ };
+ wx.setStorageSync(goEasyConnection.cacheKeys.savedConnection, JSON.stringify(connectionState));
+ } catch (error) {
+ console.warn('保存连接状态失败:', error);
+ }
+}
+
+function clearSavedConnection(app) {
+ const { cacheKeys } = app.globalData.goEasyConnection;
+ wx.removeStorageSync(cacheKeys.savedConnection);
+ wx.removeStorageSync(cacheKeys.userId);
+ wx.removeStorageSync(cacheKeys.identityType);
+ app.globalData.goEasyConnection.userId = '';
+ app.globalData.goEasyConnection.identityType = '';
+ app.globalData.goEasyConnection.lastConnectTime = 0;
+}
+
+function disconnectGoEasy(app, options = {}) {
+ const silent = options.silent === true;
+ const keepAutoReconnect = options.keepAutoReconnect === true;
+
+ return withImLock(() => new Promise((resolve) => {
+ if (silent) app._imSuppressDisconnectEvent = true;
+ app.globalData.goEasyConnection.status = 'disconnected';
+ if (!keepAutoReconnect) {
+ app.globalData.goEasyConnection.autoReconnect = false;
+ }
+ stopHeartbeat(app);
+ removeGlobalMessageListeners();
+
+ const finish = () => {
+ clearSavedConnection(app);
+ if (!keepAutoReconnect) {
+ app.globalData.messageManager.unreadTotal = 0;
+ updateTabBarBadge(app, 0);
+ }
+ if (!silent) {
+ app.emitEvent('connectionChanged', { status: 'disconnected', manual: true });
+ }
+ app._imSuppressDisconnectEvent = false;
+ resolve();
+ };
+
+ if (wx.goEasy && wx.goEasy.disconnect) {
+ wx.goEasy.disconnect({
+ onSuccess: finish,
+ onFailed: finish,
+ });
+ } else {
+ finish();
+ }
+ }));
+}
+
+async function connectWithIdentity(app, identityType, userId, isAutoRestore = false) {
+ if (!wx.goEasy?.connect) {
+ return Promise.reject(new Error('聊天服务未就绪'));
+ }
+
+ return withImLock(async () => {
+ if (!isAutoRestore) {
+ const quanxian = await jianquanxian(app);
+ if (!quanxian.allowed) {
+ throw new Error(quanxian.reason || '无聊天权限');
+ }
+ } else {
+ const uid = wx.getStorageSync('uid');
+ if (!uid) throw new Error('未登录');
+ }
+
+ const currentId = getCurrentGoEasyUserId();
+ if (isSdkConnected()) {
+ if (!currentId || currentId === userId) {
+ adoptExistingConnection(app, identityType, userId);
+ return;
+ }
+ await disconnectGoEasy(app, { silent: true, keepAutoReconnect: true });
+ app.globalData.goEasyConnection.autoReconnect = true;
+ await new Promise((r) => setTimeout(r, 400));
+ }
+
+ if (currentId && currentId !== userId && !isSdkConnected()) {
+ await disconnectGoEasy(app, { silent: true, keepAutoReconnect: true });
+ app.globalData.goEasyConnection.autoReconnect = true;
+ await new Promise((r) => setTimeout(r, 400));
+ }
+
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.globalData.goEasyConnection.status = 'connecting';
+ app.globalData.goEasyConnection.userId = userId;
+ app.globalData.goEasyConnection.identityType = identityType;
+ if (!isAutoRestore) app.globalData.goEasyConnection.reconnectAttempts = 0;
+ saveConnectionState(app);
+ app.emitEvent('connectionChanged', { status: 'connecting', identityType, userId });
+
+ const uid = wx.getStorageSync('uid');
+ const role = identityType || app.globalData.currentRole || 'normal';
+ const freshUser = getFreshImUser(app, role, uid);
+ const currentUser = app.globalData.currentUser || {
+ id: uid,
+ name: freshUser.name,
+ avatar: freshUser.avatar,
+ };
+
+ return new Promise((resolve, reject) => {
+ wx.goEasy.connect({
+ id: userId,
+ data: {
+ name: freshUser.name || currentUser.name,
+ avatar: freshUser.avatar || currentUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
+ identityType,
+ },
+ onSuccess: () => {
+ app.globalData.goEasyConnection.status = 'connected';
+ app.globalData.goEasyConnection.lastConnectTime = Date.now();
+ app.globalData.goEasyConnection.reconnectAttempts = 0;
+ saveConnectionState(app);
+ startHeartbeat(app);
+ setupMessageListeners(app);
+ loadConversations(app);
+ app.emitEvent('connectionChanged', { status: 'connected', identityType, userId });
+ resolve();
+ },
+ onFailed: (error) => {
+ console.error('GoEasy连接失败:', error);
+ // 408 = 已连接,勿再 connect,直接复用当前连接
+ if (error.code === 408) {
+ adoptExistingConnection(app, identityType, userId);
+ resolve();
+ return;
+ }
+ if (error.code === 900) {
+ app.globalData.goEasyConnection.autoReconnect = false;
+ app.globalData.goEasyConnection.status = 'disconnected';
+ clearSavedConnection(app);
+ stopHeartbeat(app);
+ wx.showModal({
+ title: '消息功能暂不可用',
+ content: '当前使用人数爆满,消息功能暂时无法使用。请联系管理员升级套餐后重试。',
+ showCancel: false,
+ confirmText: '我知道了',
+ });
+ app.emitEvent('connectionChanged', { status: 'disconnected', error, reason: 'overcapacity' });
+ reject(error);
+ return;
+ }
+ app.globalData.goEasyConnection.status = 'reconnecting';
+ app.emitEvent('connectionChanged', { status: 'reconnecting', error, isAutoRestore });
+ const { autoReconnect, reconnectAttempts, maxReconnectAttempts } = app.globalData.goEasyConnection;
+ if (autoReconnect && reconnectAttempts < maxReconnectAttempts && !isSdkConnected()) {
+ app.globalData.goEasyConnection.reconnectAttempts++;
+ const delay = app.globalData.goEasyConnection.config.reconnectDelay * reconnectAttempts;
+ setTimeout(() => {
+ if (app.globalData.goEasyConnection.autoReconnect) {
+ connectWithIdentity(app, identityType, userId, true).then(resolve).catch(reject);
+ }
+ }, delay);
+ } else {
+ reject(error);
+ }
+ },
+ });
+ });
+ });
+}
+
+async function connectForCurrentRole(app) {
+ const uid = wx.getStorageSync('uid');
+ if (!uid) return;
+ const role = app.globalData.currentRole || 'normal';
+ const targetUserId = getImUserIdForRole(role, uid);
+
+ const currentUserId = getCurrentGoEasyUserId();
+ if (currentUserId === targetUserId && isImConnected()) {
+ setupMessageListeners(app);
+ startHeartbeat(app);
+ loadConversations(app);
+ syncConnectionStatus(app);
+ return;
+ }
+ if (currentUserId && currentUserId !== targetUserId) {
+ await disconnectGoEasy(app, { silent: true, keepAutoReconnect: true });
+ app.globalData.goEasyConnection.autoReconnect = true;
+ }
+ await connectWithIdentity(app, role, targetUserId, true);
+}
+
+async function switchRoleAndReconnect(app, newRole) {
+ try {
+ await withImLock(async () => {
+ await disconnectGoEasy(app, { silent: true, keepAutoReconnect: true });
+ app.globalData.currentRole = newRole;
+ wx.setStorageSync('currentRole', newRole);
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.globalData.goEasyConnection.reconnectAttempts = 0;
+ const uid = wx.getStorageSync('uid');
+ const targetUserId = getImUserIdForRole(newRole, uid);
+ // 切换身份用轻量连接,避免鉴权接口失败把 IM 永久断开
+ await connectWithIdentity(app, newRole, targetUserId, true);
+ });
+ return true;
+ } catch (error) {
+ console.warn('切换身份 IM 重连失败', error);
+ syncConnectionStatus(app);
+ throw error;
+ }
+}
+
+function startHeartbeat(app) {
+ const { goEasyConnection } = app.globalData;
+ stopHeartbeat(app);
+ let convTick = 0;
+ goEasyConnection.heartbeatInterval = setInterval(() => {
+ if (goEasyConnection.status === 'connected' && wx.goEasy?.im) {
+ if (isSdkConnected()) {
+ convTick += 1;
+ if (convTick % 3 === 0) {
+ loadConversations(app);
+ }
+ } else {
+ goEasyConnection.status = 'reconnecting';
+ app.emitEvent('connectionChanged', { status: 'reconnecting' });
+ attemptReconnect(app);
+ }
+ } else if (goEasyConnection.autoReconnect && !isSdkConnected()) {
+ ensureConnection(app);
+ }
+ }, goEasyConnection.config.heartbeatInterval);
+}
+
+function stopHeartbeat(app) {
+ if (app.globalData.goEasyConnection.heartbeatInterval) {
+ clearInterval(app.globalData.goEasyConnection.heartbeatInterval);
+ app.globalData.goEasyConnection.heartbeatInterval = null;
+ }
+}
+
+function pauseHeartbeat(app) { stopHeartbeat(app); }
+
+function attemptReconnect(app) {
+ const { goEasyConnection } = app.globalData;
+ if (!goEasyConnection.autoReconnect || isSdkConnected()) return;
+ if (goEasyConnection.reconnectAttempts >= goEasyConnection.maxReconnectAttempts) {
+ goEasyConnection.reconnectAttempts = 0;
+ }
+ if (goEasyConnection.userId && goEasyConnection.identityType) {
+ connectWithIdentity(app, goEasyConnection.identityType, goEasyConnection.userId, true);
+ } else {
+ connectForCurrentRole(app);
+ }
+}
+
+function removeGlobalMessageListeners() {
+ if (!wx.goEasy?.im) return;
+ if (_globalPrivateHandler) {
+ wx.goEasy.im.off(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _globalPrivateHandler);
+ _globalPrivateHandler = null;
+ }
+ if (_globalGroupHandler) {
+ wx.goEasy.im.off(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _globalGroupHandler);
+ _globalGroupHandler = null;
+ }
+ if (_globalConvHandler) {
+ wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _globalConvHandler);
+ _globalConvHandler = null;
+ }
+}
+
+function setupMessageListeners(app) {
+ if (!wx.goEasy?.im || typeof wx.goEasy.im.on !== 'function') {
+ return;
+ }
+ removeGlobalMessageListeners();
+
+ _globalPrivateHandler = (message) => {
+ app.handleNewMessage(message);
+ };
+ _globalGroupHandler = (message) => {
+ app.handleNewMessage(message);
+ };
+ _globalConvHandler = (conversations) => {
+ const normalized = normalizeConversationPayload(conversations);
+ const unreadTotal = normalized?.unreadTotal ?? conversations?.unreadTotal ?? 0;
+ applyUnreadTotal(app, unreadTotal);
+ if (normalized && typeof app.emitEvent === 'function') {
+ app.emitEvent('conversationsUpdated', normalized);
+ }
+ };
+
+ wx.goEasy.im.on(wx.GoEasy.IM_EVENT.PRIVATE_MESSAGE_RECEIVED, _globalPrivateHandler);
+ wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, _globalGroupHandler);
+ wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, _globalConvHandler);
+}
+
+function handleNewMessage(app, message) {
+ const messageId = message.messageId || message.id;
+ const fingerprint = `${message.senderId}_${message.timestamp}_${message.type}`;
+ const msgKey = messageId || fingerprint;
+
+ if (!app._processedMessages) app._processedMessages = new Set();
+ if (app._processedMessages.has(msgKey)) return;
+ app._processedMessages.add(msgKey);
+ if (app._processedMessages.size > 300) {
+ app._processedMessages.delete(app._processedMessages.values().next().value);
+ }
+
+ cacheMessage(app, message);
+ loadConversations(app);
+
+ if (shouldShowNotification(app, message)) {
+ let notificationType = 'private';
+ let extraData = {};
+ if (message.groupId) {
+ notificationType = 'group';
+ extraData = {
+ groupId: message.groupId,
+ orderId: message.orderId || '',
+ groupName: '',
+ groupAvatar: '',
+ isCross: message.isCross || 0,
+ };
+ const groupInfo = app.globalData.groupInfoMap?.[message.groupId];
+ if (groupInfo) {
+ extraData.groupName = groupInfo.name || '';
+ extraData.groupAvatar = groupInfo.avatar || '';
+ }
+ } else if (message.teamId) {
+ notificationType = 'cs';
+ extraData = { teamId: message.teamId };
+ }
+ showNotificationDirect(app, {
+ senderId: message.senderId,
+ senderName: message.senderData?.name || '用户',
+ avatar: message.senderData?.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
+ content: formatMessageForNotification(message),
+ message,
+ notificationType,
+ ...extraData,
+ });
+ }
+}
+
+function shouldShowNotification(app, message) {
+ if (app.globalData.messageManager.notificationMuted) return false;
+ if (isDoNotDisturbTime(app)) return false;
+ if (isMessageFromCurrentChat(app, message)) return false;
+ return true;
+}
+
+function isDoNotDisturbTime(app) {
+ const { doNotDisturb, doNotDisturbStart, doNotDisturbEnd } = app.globalData.messageManager;
+ if (!doNotDisturb) return false;
+ const now = new Date();
+ const currentTime = now.getHours() * 60 + now.getMinutes();
+ const [sH, sM] = doNotDisturbStart.split(':').map(Number);
+ const [eH, eM] = doNotDisturbEnd.split(':').map(Number);
+ const startTime = sH * 60 + sM;
+ const endTime = eH * 60 + eM;
+ if (startTime < endTime) {
+ return currentTime >= startTime && currentTime < endTime;
+ }
+ return currentTime >= startTime || currentTime < endTime;
+}
+
+function isMessageFromCurrentChat(app, message) {
+ const pageState = app.globalData.pageState || {};
+ if (!pageState.isInChatPage || !pageState.currentChatId) return false;
+ if (message.groupId) {
+ return message.groupId === pageState.currentChatId;
+ }
+ const myId = app.globalData.goEasyConnection?.userId || getCurrentGoEasyUserId();
+ if (!myId) return false;
+ const peerId = message.senderId === myId ? message.receiverId : message.senderId;
+ return peerId === pageState.currentChatId || message.senderId === pageState.currentChatId;
+}
+
+function showNotificationDirect(app, data) {
+ if (app.globalData.globalNotification?.show) {
+ try {
+ app.globalData.globalNotification.show(data);
+ return;
+ } catch (error) {
+ console.warn('全局通知显示失败:', error);
+ }
+ }
+ app.emitEvent('showNotification', data);
+}
+
+function startImWhenReady(app) {
+ if (!wx.getStorageSync('uid')) return;
+ app.globalData.goEasyConnection.autoReconnect = true;
+ restoreCachedBadge(app);
+ ensureConnection(app);
+ setTimeout(() => {
+ if (isSdkConnected()) {
+ setupMessageListeners(app);
+ loadConversations(app);
+ }
+ restoreCachedBadge(app);
+ }, 450);
+}
+
+function restoreCachedBadge(app) {
+ const { messageManager } = app.globalData;
+ let unread = messageManager.unreadTotal;
+ if (unread == null || unread === '') {
+ try {
+ const saved = wx.getStorageSync(messageManager.cacheKeys.unreadTotal);
+ if (saved !== '' && saved != null) unread = Number(saved) || 0;
+ } catch (e) {}
+ }
+ if (!unread) {
+ try {
+ const badgeStr = wx.getStorageSync('tabBarMessageBadge');
+ if (badgeStr && badgeStr !== '0') {
+ unread = badgeStr === '99+' ? 100 : (parseInt(badgeStr, 10) || 0);
+ }
+ } catch (e) {}
+ }
+ if (unread > 0) {
+ updateTabBarBadge(app, unread);
+ } else if (messageManager.tabBarBadgeText) {
+ app.emitEvent('tabBarBadgeChanged', {
+ index: messageManager.tabBarIndex,
+ badgeText: messageManager.tabBarBadgeText,
+ showRedDot: true,
+ forceUpdate: true,
+ });
+ updateTabBarDirectly(app, messageManager.tabBarBadgeText);
+ }
+}
+
+function applyUnreadTotal(app, unreadTotal) {
+ const prev = app.globalData.messageManager.unreadTotal;
+ const connected = isSdkConnected();
+ if (unreadTotal === 0 && !connected && prev > 0) {
+ restoreCachedBadge(app);
+ return;
+ }
+ app.globalData.messageManager.unreadTotal = unreadTotal;
+ updateTabBarBadge(app, unreadTotal);
+ wx.setStorageSync(app.globalData.messageManager.cacheKeys.unreadTotal, unreadTotal);
+ if (prev !== unreadTotal) {
+ app.emitEvent('unreadCountChanged', { unreadTotal });
+ }
+}
+
+async function updateUnreadCount(app, customCount) {
+ let unreadTotal = customCount;
+ if (unreadTotal === undefined) {
+ try {
+ const result = await getUnreadCount(app);
+ unreadTotal = result.unreadTotal || 0;
+ } catch (error) {
+ console.error('获取未读数失败:', error);
+ return;
+ }
+ }
+ applyUnreadTotal(app, unreadTotal);
+}
+
+function getUnreadCount(app) {
+ return new Promise((resolve, reject) => {
+ if (!getCurrentGoEasyUserId()) {
+ resolve({ unreadTotal: 0 });
+ return;
+ }
+ wx.goEasy.im.latestConversations({
+ onSuccess: (result) => resolve({
+ unreadTotal: result.unreadTotal || 0,
+ conversations: result.content?.conversations || [],
+ }),
+ onFailed: reject,
+ });
+ });
+}
+
+function formatMessageForNotification(message) {
+ switch (message.type) {
+ case 'text': return message.payload.text || '[文本]';
+ case 'image': return '[图片]';
+ case 'audio': return '[语音]';
+ case 'video': return '[视频]';
+ case 'file': return '[文件]';
+ case 'order': return '[订单]';
+ default: return '[新消息]';
+ }
+}
+
+function cacheMessage(app, message) {
+ if (message.groupId && message.type === 'text' && message.payload?.text) {
+ const card = parseOrderCardText(message.payload.text);
+ if (card && card.zhuangtai != null) {
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ const meta = {
+ ...(app.globalData.groupInfoMap[message.groupId] || {}),
+ orderId: card.orderId,
+ orderZhuangtai: card.zhuangtai,
+ orderDesc: card.jieshao,
+ };
+ app.globalData.groupInfoMap[message.groupId] = meta;
+ persistGroupMeta(app, message.groupId, meta);
+ }
+ }
+ const { latestMessages } = app.globalData.messageManager;
+ latestMessages.unshift({
+ id: message.messageId,
+ type: message.type,
+ senderId: message.senderId,
+ senderName: message.senderData?.name,
+ content: formatMessageForNotification(message),
+ timestamp: message.timestamp || Date.now(),
+ conversationId: message.conversationId,
+ });
+ if (latestMessages.length > 50) latestMessages.length = 50;
+ wx.setStorageSync(app.globalData.messageManager.cacheKeys.latestMessages, latestMessages);
+}
+
+function normalizeConversationPayload(result) {
+ if (!result) return null;
+ const content = result.content || result;
+ const list = content.conversations || result.conversations;
+ if (!list || !Array.isArray(list)) return null;
+ return {
+ conversations: list,
+ unreadTotal: content.unreadTotal ?? result.unreadTotal ?? 0,
+ };
+}
+
+function loadConversations(app) {
+ if (_loadConvTimer) clearTimeout(_loadConvTimer);
+ _loadConvTimer = setTimeout(() => {
+ _loadConvTimer = null;
+ loadConversationsNow(app);
+ }, 280);
+}
+
+function loadConversationsNow(app) {
+ if (_loadConvInFlight) return;
+ if (!isSdkConnected() || !wx.goEasy?.im?.latestConversations) {
+ restoreCachedBadge(app);
+ if (app.globalData.goEasyConnection.autoReconnect) {
+ ensureConnection(app);
+ }
+ return;
+ }
+ _loadConvInFlight = true;
+ wx.goEasy.im.latestConversations({
+ onSuccess: (result) => {
+ _loadConvInFlight = false;
+ const normalized = normalizeConversationPayload(result);
+ if (result.unreadTotal !== undefined) {
+ applyUnreadTotal(app, result.unreadTotal);
+ } else if (normalized) {
+ applyUnreadTotal(app, normalized.unreadTotal);
+ }
+ if (normalized && typeof app.emitEvent === 'function') {
+ app.emitEvent('conversationsUpdated', normalized);
+ }
+ const conversations = normalized?.conversations || [];
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ conversations.forEach((c) => {
+ if (c.type === 'group' && c.groupId) {
+ app.globalData.groupInfoMap[c.groupId] = c.data || {};
+ }
+ });
+ _ensureGroupSubscriptions(app, conversations);
+ },
+ onFailed: (error) => {
+ _loadConvInFlight = false;
+ console.error('加载会话列表失败:', error);
+ restoreCachedBadge(app);
+ if (!isSdkConnected() && app.globalData.goEasyConnection.autoReconnect) {
+ attemptReconnect(app);
+ }
+ },
+ });
+}
+
+function _ensureGroupSubscriptions(app, conversations) {
+ const groupIds = conversations
+ .filter((c) => c.type === 'group' && c.groupId)
+ .map((c) => c.groupId);
+
+ if (groupIds.length === 0) return;
+ if (!wx.goEasy?.im || typeof wx.goEasy.im.subscribeGroup !== 'function') return;
+
+ wx.goEasy.im.subscribeGroup({
+ groupIds,
+ onSuccess: () => {},
+ onFailed: (error) => console.error('全局订阅群组失败:', error),
+ });
+}
+
+function updateCurrentPageState(app) {
+ try {
+ const pages = getCurrentPages();
+ if (pages.length > 0) {
+ const currentPage = pages[pages.length - 1];
+ const chatPages = [
+ 'pages/chat/chat',
+ 'pages/group-chat/group-chat',
+ 'pages/cs-chat/cs-chat',
+ 'pages/liaotian/liaotian',
+ 'pages/qunliaotian/qunliaotian',
+ 'pages/kefuliaotian/kefuliaotian',
+ ];
+ app.globalData.pageState.currentPage = currentPage.route;
+ app.globalData.pageState.isInChatPage = chatPages.indexOf(currentPage.route) >= 0;
+ app.globalData.pageState.lastPageUpdate = Date.now();
+ }
+ } catch (error) {
+ console.warn('更新页面状态失败:', error);
+ }
+}
+
+function saveUserSettings(app) {
+ try {
+ wx.setStorageSync(app.globalData.messageManager.cacheKeys.messageSettings, {
+ soundEnabled: app.globalData.messageManager.soundEnabled,
+ vibrationEnabled: app.globalData.messageManager.vibrationEnabled,
+ doNotDisturb: app.globalData.messageManager.doNotDisturb,
+ doNotDisturbStart: app.globalData.messageManager.doNotDisturbStart,
+ doNotDisturbEnd: app.globalData.messageManager.doNotDisturbEnd,
+ notificationMuted: app.globalData.messageManager.notificationMuted,
+ notificationStyle: app.globalData.messageManager.notificationStyle,
+ });
+ } catch (error) {
+ console.warn('保存用户设置失败:', error);
+ }
+}
+
+function toggleDoNotDisturb(app, enabled) {
+ app.globalData.messageManager.doNotDisturb = enabled;
+ saveUserSettings(app);
+ wx.showToast({ title: `免打扰${enabled ? '开启' : '关闭'}`, icon: 'success', duration: 2000 });
+}
+
+function toggleNotificationMute(app, enabled) {
+ app.globalData.messageManager.notificationMuted = enabled;
+ wx.setStorageSync(app.globalData.messageManager.cacheKeys.notificationMuted, enabled);
+ saveUserSettings(app);
+ wx.showToast({ title: `通知${enabled ? '静音' : '开启'}`, icon: 'success', duration: 2000 });
+}
+
+function closeNotification(app) {
+ app.emitEvent('hideNotification');
+}
+
+function updateTabBarBadge(app, unreadCount) {
+ const { messageManager } = app.globalData;
+ if (!messageManager.showTabBarBadge) return;
+ let badgeText = '';
+ if (unreadCount > 0) {
+ badgeText = unreadCount > 99 ? '99+' : unreadCount.toString();
+ }
+ messageManager.tabBarBadgeText = badgeText;
+ app.emitEvent('tabBarBadgeChanged', {
+ index: messageManager.tabBarIndex,
+ badgeText,
+ showRedDot: unreadCount > 0,
+ forceUpdate: true,
+ });
+ updateTabBarDirectly(app, badgeText);
+ saveTabBarBadgeToStorage(app, badgeText);
+}
+
+function updateTabBarDirectly(app, badgeText) {
+ try {
+ const pages = getCurrentPages();
+ for (let i = pages.length - 1; i >= 0; i--) {
+ const tabBar = pages[i].selectComponent('#custom-tab-bar')
+ || pages[i].selectComponent('tab-bar');
+ if (tabBar && tabBar.setData) {
+ tabBar.setData({ badgeText });
+ break;
+ }
+ }
+ } catch (error) { console.warn('直接更新TabBar失败:', error); }
+}
+
+function saveTabBarBadgeToStorage(app, badgeText) {
+ try {
+ wx.setStorageSync('tabBarMessageBadge', badgeText);
+ } catch (error) { console.warn('保存TabBar徽章失败:', error); }
+}
+
+module.exports = { initGlobalMessageSystem };
diff --git a/utils/chat-history.js b/utils/chat-history.js
new file mode 100644
index 0000000..6147619
--- /dev/null
+++ b/utils/chat-history.js
@@ -0,0 +1,121 @@
+/**
+ * 聊天历史消息加载(私聊 / 群聊 / 客服共用)
+ * - 排除本地/欢迎语等合成消息的 timestamp,避免下拉加载错位
+ * - 统一 IM 连接等待与 history API 封装
+ */
+
+const SYNTHETIC_MSG_ID = /^(local-|img-|order-|welcome-|auto-reply-)/;
+
+export function isHistorySyntheticMessage(msg) {
+ return !!(msg && msg.messageId && SYNTHETIC_MSG_ID.test(String(msg.messageId)));
+}
+
+/** 取当前列表里最早一条「真实」服务端消息的时间戳,供 GoEasy history 分页 */
+export function getOldestHistoryTimestamp(messages, fallback = null) {
+ if (!Array.isArray(messages)) return fallback;
+ let oldest = null;
+ for (const m of messages) {
+ if (!m || m.timestamp == null) continue;
+ if (isHistorySyntheticMessage(m)) continue;
+ if (oldest == null || m.timestamp < oldest) oldest = m.timestamp;
+ }
+ return oldest != null ? oldest : fallback;
+}
+
+/** 等待 IM 连接就绪(优先 ensureImForRole,避免未连上就拉历史) */
+export async function waitChatImReady(app, timeoutMs = 12000) {
+ const role = app?.globalData?.currentRole || 'normal';
+ if (app?.ensureImForRole) {
+ try {
+ await app.ensureImForRole(role);
+ if (isImConnected()) return true;
+ } catch (e) {
+ console.warn('[IM] ensureImForRole failed', e);
+ }
+ }
+ if (app?.ensureConnection) app.ensureConnection();
+ return waitImConnected(app, timeoutMs);
+}
+
+export function isImConnected() {
+ const status = wx.goEasy?.getConnectionStatus?.() || 'disconnected';
+ return (status === 'connected' || status === 'reconnected') && !!wx.goEasy?.im;
+}
+
+/** 等待 IM 连接就绪(下拉加载历史前必须先连上) */
+export function waitImConnected(app, timeoutMs = 8000) {
+ return new Promise((resolve) => {
+ if (isImConnected()) {
+ resolve(true);
+ return;
+ }
+ if (app?.ensureConnection) app.ensureConnection();
+ const start = Date.now();
+ const timer = setInterval(() => {
+ if (isImConnected()) {
+ clearInterval(timer);
+ resolve(true);
+ } else if (Date.now() - start >= timeoutMs) {
+ clearInterval(timer);
+ resolve(false);
+ }
+ }, 200);
+ });
+}
+
+export function fetchHistoryMessages({ scene, id, lastTimestamp, limit = 20 }) {
+ return new Promise((resolve, reject) => {
+ if (!wx.goEasy?.im?.history) {
+ reject(new Error('IM未初始化'));
+ return;
+ }
+ if (!id) {
+ reject(new Error('会话ID为空'));
+ return;
+ }
+ wx.goEasy.im.history({
+ type: scene,
+ id: String(id),
+ lastTimestamp: lastTimestamp ?? null,
+ limit,
+ onSuccess: (res) => resolve(res?.content || []),
+ onFailed: (err) => reject(err || new Error('加载历史消息失败')),
+ });
+ });
+}
+
+/**
+ * 合并一页历史消息
+ * @returns {{ messages, hasMore, lastTimestamp }}
+ */
+export function mergeHistoryMessages({ incoming, existing, refresh, limit = 20, mapMessage }) {
+ let list = Array.isArray(incoming) ? [...incoming] : [];
+ list.sort((a, b) => a.timestamp - b.timestamp);
+ if (typeof mapMessage === 'function') {
+ list = list.map((m, idx) => mapMessage(m, idx, list));
+ }
+
+ const prev = Array.isArray(existing) ? existing : [];
+ let final = refresh ? list : [...list, ...prev];
+
+ if (!refresh) {
+ for (let i = 0; i < final.length; i += 1) {
+ if (i === 0) final[i].showTime = true;
+ else final[i].showTime = (final[i].timestamp - final[i - 1].timestamp) / 60000 > 5;
+ }
+ }
+
+ const ids = new Set();
+ const unique = [];
+ for (const m of final) {
+ if (!m?.messageId || ids.has(m.messageId)) continue;
+ ids.add(m.messageId);
+ unique.push(m);
+ }
+
+ return {
+ messages: unique,
+ hasMore: list.length >= limit,
+ lastTimestamp: getOldestHistoryTimestamp(unique, null),
+ };
+}
diff --git a/utils/club-context.js b/utils/club-context.js
new file mode 100644
index 0000000..4d51548
--- /dev/null
+++ b/utils/club-context.js
@@ -0,0 +1,64 @@
+/**
+ * 多俱乐部上下文(读取 config/club-config.js 中的固定 club_id)
+ */
+import { CLUB_ID as CONFIG_CLUB_ID, WX_APP_ID } from '../config/club-config';
+
+const CLUB_ID_KEY = 'club_id';
+const CLUB_SCOPE_KEY = 'club_scope';
+const DEFAULT_CLUB_ID = CONFIG_CLUB_ID || 'xq';
+
+export const CLUB_API = {
+ wechatLogin: '/jituan/auth/wechat-login',
+ dashouRegister: '/jituan/auth/dashou-register',
+ clubList: '/jituan/club/list',
+};
+
+export function getConfiguredClubId() {
+ return DEFAULT_CLUB_ID;
+}
+
+export function getWxAppId() {
+ return WX_APP_ID || '';
+}
+
+export function getClubId(app) {
+ const configured = getConfiguredClubId();
+ const stored = wx.getStorageSync(CLUB_ID_KEY);
+ if (stored && stored === configured) {
+ return stored;
+ }
+ if (stored && stored !== configured) {
+ wx.removeStorageSync(CLUB_ID_KEY);
+ }
+ app = app || getApp();
+ if (app && app.globalData && app.globalData.clubId === configured) {
+ return app.globalData.clubId;
+ }
+ return configured;
+}
+
+export function setClubId(clubId, app) {
+ const configured = getConfiguredClubId();
+ const id = (clubId || configured).trim() || configured;
+ if (id !== configured) {
+ console.warn('[club] 登录返回 club_id 与工程配置不一致,以工程配置为准', id, configured);
+ }
+ const finalId = configured;
+ app = app || getApp();
+ wx.setStorageSync(CLUB_ID_KEY, finalId);
+ if (app && app.globalData) {
+ app.globalData.clubId = finalId;
+ }
+ return finalId;
+}
+
+export function getClubScope() {
+ return wx.getStorageSync(CLUB_SCOPE_KEY) || 'single';
+}
+
+export function buildClubHeaders(extra = {}) {
+ return {
+ ...extra,
+ 'X-Club-Id': getClubId(),
+ };
+}
diff --git a/utils/cos-wx-sdk-v5.min.js b/utils/cos-wx-sdk-v5.min.js
new file mode 100644
index 0000000..55b0f0f
--- /dev/null
+++ b/utils/cos-wx-sdk-v5.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.COS=t():e.COS=t()}(window,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/Users/chrisftian/Documents/projects/cos-sdk/cos-wx-sdk-v5/dist",n(n.s=8)}([function(e,t,n){"use strict";function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var i=0,a=function(){};return{s:a,n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,s=!0,c=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){c=!0,r=e},f:function(){try{s||null==n.return||n.return()}finally{if(c)throw r}}}}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=new Array(t);n=0;--a){var r=this.tryEntries[a],s=r.completion;if("root"===r.tryLoc)return o("end");if(r.tryLoc<=this.prev){var c=i.call(r,"catchLoc"),l=i.call(r,"finallyLoc");if(c&&l){if(this.prev=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&i.call(o,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),O(n),y}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var i=n.completion;if("throw"===i.type){var o=i.arg;O(n)}return o}}throw Error("illegal catch attempt")},delegateYield:function(t,n,i){return this.delegate={iterator:I(t),resultName:n,nextLoc:i},"next"===this.method&&(this.arg=e),y}},t}function r(e,t,n,i,o,a,r){try{var s=e[a](r),c=s.value}catch(e){return void n(e)}s.done?t(c):Promise.resolve(c).then(i,o)}function s(e){return s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},s(e)}var c=n(10),l=n(13),p=n(14),u=p.btoa,d=wx.getFileSystemManager(),f=n(2),m=n(15),h=m.XMLParser,g=m.XMLBuilder,v=new h({ignoreDeclaration:!0,ignoreAttributes:!0,parseTagValue:!1,trimValues:!1}),y=new g,x=function e(t){if(A(t))for(var n in t){var i=t[n];"string"==typeof i?"#text"===n&&delete t[n]:Array.isArray(i)?i.forEach((function(t){e(t)})):A(i)&&e(i)}};function k(e){return encodeURIComponent(e).replace(/!/g,"%21").replace(/'/g,"%27").replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/\*/g,"%2A")}function b(e,t){var n=[];for(var i in e)e.hasOwnProperty(i)&&n.push(t?k(i).toLowerCase():i);return n.sort((function(e,t){return(e=e.toLowerCase())===(t=t.toLowerCase())?0:e>t?1:-1}))}var C=["cache-control","content-disposition","content-encoding","content-length","content-md5","content-type","expect","expires","host","if-match","if-modified-since","if-none-match","if-unmodified-since","origin","range","transfer-encoding","pic-operations"],S=function(){},w=function(e){var t={};for(var n in e)e.hasOwnProperty(n)&&void 0!==e[n]&&null!==e[n]&&(t[n]=e[n]);return t};function T(e){return E(e,(function(e){return"object"===s(e)&&null!==e?T(e):e}))}function R(e,t){return P(t,(function(n,i){e[i]=t[i]})),e}function B(e){return e instanceof Array}function A(e){return"[object Object]"===Object.prototype.toString.call(e)}function P(e,t){for(var n in e)e.hasOwnProperty(n)&&t(e[n],n)}function E(e,t){var n=B(e)?[]:{};for(var i in e)e.hasOwnProperty(i)&&(n[i]=t(e[i],i));return n}var O=function(e,t){if(t=R({},t),"getAuth"!==e&&"getV4Auth"!==e&&"getObjectUrl"!==e){var n=t.Headers||{};if(t&&"object"===s(t)){!function(){for(var e in t)t.hasOwnProperty(e)&&e.indexOf("x-cos-")>-1&&(n[e]=t[e])}();U.each({"x-cos-mfa":"MFA","Content-MD5":"ContentMD5","Content-Length":"ContentLength","Content-Type":"ContentType",Expect:"Expect",Expires:"Expires","Cache-Control":"CacheControl","Content-Disposition":"ContentDisposition","Content-Encoding":"ContentEncoding",Range:"Range","If-Modified-Since":"IfModifiedSince","If-Unmodified-Since":"IfUnmodifiedSince","If-Match":"IfMatch","If-None-Match":"IfNoneMatch","x-cos-copy-source":"CopySource","x-cos-copy-source-Range":"CopySourceRange","x-cos-metadata-directive":"MetadataDirective","x-cos-copy-source-If-Modified-Since":"CopySourceIfModifiedSince","x-cos-copy-source-If-Unmodified-Since":"CopySourceIfUnmodifiedSince","x-cos-copy-source-If-Match":"CopySourceIfMatch","x-cos-copy-source-If-None-Match":"CopySourceIfNoneMatch","x-cos-acl":"ACL","x-cos-grant-read":"GrantRead","x-cos-grant-write":"GrantWrite","x-cos-grant-full-control":"GrantFullControl","x-cos-grant-read-acp":"GrantReadAcp","x-cos-grant-write-acp":"GrantWriteAcp","x-cos-storage-class":"StorageClass","x-cos-traffic-limit":"TrafficLimit","x-cos-mime-limit":"MimeLimit","x-cos-forbid-overwrite":"ForbidOverwrite","x-cos-server-side-encryption-customer-algorithm":"SSECustomerAlgorithm","x-cos-server-side-encryption-customer-key":"SSECustomerKey","x-cos-server-side-encryption-customer-key-MD5":"SSECustomerKeyMD5","x-cos-server-side-encryption":"ServerSideEncryption","x-cos-server-side-encryption-cos-kms-key-id":"SSEKMSKeyId","x-cos-server-side-encryption-context":"SSEContext","Pic-Operations":"PicOperations"},(function(e,i){void 0!==t[e]&&(n[i]=t[e])})),t.Headers=w(n)}}return t},j=function(e){return new Promise((function(t,n){d.readFile({filePath:e,success:function(e){t(e.data)},fail:function(e){n((null==e?void 0:e.errMsg)||"")}})}))},I=function(){var e,t=(e=a().mark((function e(t,n,i){return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if("postObject"!==t){e.next=4;break}i(),e.next=21;break;case 4:if("putObject"!==t){e.next=20;break}if(void 0!==n.Body||!n.FilePath){e.next=17;break}return e.prev=6,e.next=9,j(n.FilePath);case 9:n.Body=e.sent,e.next=17;break;case 12:return e.prev=12,e.t0=e.catch(6),n.Body=void 0,i({error:"readFile error, ".concat(e.t0)}),e.abrupt("return");case 17:void 0!==n.Body?(n.ContentLength=n.Body.byteLength,i(null,n.ContentLength)):i({error:"missing param Body"}),e.next=21;break;case 20:n.FilePath?d.stat({path:n.FilePath,success:function(e){var t=e.stats;n.FileStat=t,n.FileStat.FilePath=n.FilePath;var o=t.isDirectory()?0:t.size;n.ContentLength=o=o||0,i(null,o)},fail:function(e){i(e)}}):i({error:"missing param FilePath"});case 21:case"end":return e.stop()}}),e,null,[[6,12]])})),function(){var t=this,n=arguments;return new Promise((function(i,o){var a=e.apply(t,n);function s(e){r(a,i,o,s,c,"next",e)}function c(e){r(a,i,o,s,c,"throw",e)}s(void 0)}))});return function(e,n,i){return t.apply(this,arguments)}}(),_=function(e){return Date.now()+(e||0)},N=function(e,t){if(!e||!t)return-1;e=e.split("."),t=t.split(".");for(var n=Math.max(e.length,t.length);e.lengtha)return 1;if(o=0);return function(){return!1,i}}(),U={noop:S,formatParams:O,apiWrapper:function(e,t){return function(n,i){var o,a=this;if("function"==typeof n&&(i=n,n={}),n=O(e,n),a.options.EnableReporter)if("sliceUploadFile"===n.calledBySdk||"sliceCopyFile"===n.calledBySdk)o=n.tracker&&n.tracker.generateSubTracker({apiName:e});else if(["uploadFile","uploadFiles"].includes(e))o=null;else{var r=0;n.Body&&(r="string"==typeof n.Body?n.Body.length:n.Body.size||n.Body.byteLength||0);var s=a.options.UseAccelerate||"string"==typeof a.options.Domain&&a.options.Domain.includes("accelerate.");o=new f({Beacon:a.options.BeaconReporter,clsReporter:a.options.ClsReporter,bucket:n.Bucket,region:n.Region,apiName:e,realApi:e,accelerate:s,fileKey:n.Key,fileSize:r,deepTracker:a.options.DeepTracker,customId:a.options.CustomId,delay:a.options.TrackerDelay})}n.tracker=o;var c=function(e){return e&&e.headers&&(e.headers["x-ci-request-id"]&&(e.RequestId=e.headers["x-ci-request-id"]),e.headers["x-cos-request-id"]&&(e.RequestId=e.headers["x-cos-request-id"]),e.headers["x-cos-version-id"]&&(e.VersionId=e.headers["x-cos-version-id"]),e.headers["x-cos-delete-marker"]&&(e.DeleteMarker=e.headers["x-cos-delete-marker"])),e},l=function(e,t){o&&o.report(e,t),i&&i(c(e),c(t))},p=function(){if("getService"!==e&&"abortUploadTask"!==e){var t=function(e,t){var n=t.Bucket,i=t.Region,o=t.Key;if(e.indexOf("Bucket")>-1||"deleteMultipleObject"===e||"multipartList"===e||"listObjectVersions"===e){if(!n)return"Bucket";if(!i)return"Region"}else if(e.indexOf("Object")>-1||e.indexOf("multipart")>-1||"sliceUploadFile"===e||"abortUploadTask"===e||"uploadFile"===e){if(!n)return"Bucket";if(!i)return"Region";if(!o)return"Key"}return!1}(e,n);if(t)return"missing param "+t;if(n.Region){if(n.Region.indexOf("cos.")>-1)return'param Region should not be start with "cos."';if(!/^([a-z\d-]+)$/.test(n.Region))return"Region format error.";!a.options.CompatibilityMode&&-1===n.Region.indexOf("-")&&"yfb"!==n.Region&&"default"!==n.Region&&n.Region}if(n.Bucket){if(!/^([a-z\d-]+)-(\d+)$/.test(n.Bucket))if(n.AppId)n.Bucket=n.Bucket+"-"+n.AppId;else{if(!a.options.AppId)return'Bucket should format as "test-1250000000".';n.Bucket=n.Bucket+"-"+a.options.AppId}n.AppId&&delete n.AppId}n.Key&&"/"===n.Key.substr(0,1)&&(n.Key=n.Key.substr(1))}}(),u=["getAuth","getObjectUrl"].includes(e);if(!u&&!i)return new Promise((function(e,o){if(i=function(t,n){t?o(t):e(n)},p)return l({error:p});t.call(a,n,l)}));if(p)return l({error:p});var d=t.call(a,n,l);return u?d:void 0}},xml2json:function(e){var t=v.parse(e);return x(t),t},json2xml:function(e){return y.build(e)},md5:c,clearKey:w,fileSlice:function(e,t,n,i){e?d.readFile({filePath:e,position:t,length:n-t,success:function(e){i(e.data)},fail:function(){i(null)}}):i(null)},getBodyMd5:function(e,t,n){n=n||S,e&&t&&t instanceof ArrayBuffer?U.getFileMd5(t,(function(e,t){n(t)})):n()},getFileMd5:function(e,t){var n=c(e);return t&&t(n),n},binaryBase64:function(e){var t,n,i,o="";for(t=0,n=e.length/2;t-1||i.indexOf("x-ci-")>-1||C.indexOf(i)>-1)&&(t[n]=e[n])}return t}(T(e.Headers||e.headers||{})),c=e.Key||"";e.UseRawKey?t=e.Pathname||e.pathname||"/"+c:0!==(t=e.Pathname||e.pathname||c).indexOf("/")&&(t="/"+t);var p=!1!==e.ForceSignHost;if(!s.Host&&!s.host&&e.Bucket&&e.Region&&p&&(s.Host=e.Bucket+".cos."+e.Region+".myqcloud.com"),n&&i){var u=Math.round(_(e.SystemClockOffset)/1e3)-1,d=u,f=e.Expires||e.expires;d+=void 0===f?900:1*f||0;var m=n,h=o||u+";"+d,g=o||u+";"+d,v=b(s,!0).join(";").toLowerCase(),y=b(r,!0).join(";").toLowerCase(),x=l.HmacSHA1(g,i).toString(),k=[a,t,U.obj2str(r,!0),U.obj2str(s,!0),""].join("\n"),S=["sha1",h,l.SHA1(k).toString(),""].join("\n");return["q-sign-algorithm=sha1","q-ak="+m,"q-sign-time="+h,"q-key-time="+g,"q-header-list="+v,"q-url-param-list="+y,"q-signature="+l.HmacSHA1(S,x).toString()].join("&")}},compareVersion:N,canFileSlice:L,isCIHost:function(e){return/^https?:\/\/([^/]+\.)?ci\.[^/]+/.test(e)},error:function(e,t){var n=e;return e.message=e.message||null,"string"==typeof t?(e.error=t,e.message=t):"object"===s(t)&&null!==t&&(R(e,t),(t.code||t.name)&&(e.code=t.code||t.name),t.message&&(e.message=t.message),t.stack&&(e.stack=t.stack)),"function"==typeof Object.defineProperty&&(Object.defineProperty(e,"name",{writable:!0,enumerable:!1}),Object.defineProperty(e,"message",{enumerable:!0})),e.name=t&&t.name||e.name||e.code||"Error",e.code||(e.code=e.name),e.error||(e.error=T(n)),e},getSourceParams:function(e){var t=this.options.CopySourceParser;if(t)return t(e);var n=e.match(/^([^.]+-\d+)\.cos(v6|-cdc|-internal)?\.([^.]+)\.((myqcloud\.com)|(tencentcos\.cn))\/(.+)$/);return n?{Bucket:n[1],Region:n[3],Key:n[7]}:null},encodeBase64:function(e,t){var n=p.encode(e);return t&&(n=n.replaceAll("+","-").replaceAll("/","_").replaceAll("=","")),n},simplifyPath:function(e){var t,n=[],o=i(e.split("/"));try{for(o.s();!(t=o.n()).done;){var a=t.value;".."===a?n.length&&n.pop():a.length&&"."!==a&&n.push(a)}}catch(e){o.e(e)}finally{o.f()}return"/"+n.join("/")},arrayBufferToString:function(e){return new TextDecoder("utf-8").decode(e)},parseResBody:function(e){var t;if(e&&"string"==typeof e){var n=e.trim(),i=0===n.indexOf("<"),o=0===n.indexOf("{");if(i)t=U.xml2json(e)||{};else if(o)try{var a=e.replace(/\n/g," "),r=JSON.parse(a);t="[object Object]"===Object.prototype.toString.call(r)?r:e}catch(n){t=e}else t=e}else t=e||{};return t}};e.exports=U},function(e,t,n){"use strict";const i=":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",o="["+i+"]["+(i+"\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040")+"]*",a=new RegExp("^"+o+"$");t.isExist=function(e){return void 0!==e},t.isEmptyObject=function(e){return 0===Object.keys(e).length},t.merge=function(e,t,n){if(t){const i=Object.keys(t),o=i.length;for(let a=0;a=0;--o){var r=this.tryEntries[o],s=r.completion;if("root"===r.tryLoc)return i("end");if(r.tryLoc<=this.prev){var c=a.call(r,"catchLoc"),l=a.call(r,"finallyLoc");if(c&&l){if(this.prev=0;--n){var i=this.tryEntries[n];if(i.tryLoc<=this.prev&&a.call(i,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),O(n),y}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var i=n.completion;if("throw"===i.type){var o=i.arg;O(n)}return o}}throw Error("illegal catch attempt")},delegateYield:function(t,n,i){return this.delegate={iterator:I(t),resultName:n,nextLoc:i},"next"===this.method&&(this.arg=e),y}},t}function a(e,t,n,i,o,a,r){try{var s=e[a](r),c=s.value}catch(e){return void n(e)}s.done?t(c):Promise.resolve(c).then(i,o)}function r(e){return function(){var t=this,n=arguments;return new Promise((function(i,o){var r=e.apply(t,n);function s(e){a(r,i,o,s,c,"next",e)}function c(e){a(r,i,o,s,c,"throw",e)}s(void 0)}))}}function s(e,t,n){return(t=l(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){for(var n=0;n5&&"xml"===i)return m("InvalidXml","XML declaration allowed only at the start of the document.",g(e,t));if("?"==e[t]&&">"==e[t+1]){t++;break}}return t}function s(e,t){if(e.length>t+5&&"-"===e[t+1]&&"-"===e[t+2]){for(t+=3;t"===e[t+2]){t+=2;break}}else if(e.length>t+8&&"D"===e[t+1]&&"O"===e[t+2]&&"C"===e[t+3]&&"T"===e[t+4]&&"Y"===e[t+5]&&"P"===e[t+6]&&"E"===e[t+7]){let n=1;for(t+=8;t"===e[t]&&(n--,0===n))break}else if(e.length>t+9&&"["===e[t+1]&&"C"===e[t+2]&&"D"===e[t+3]&&"A"===e[t+4]&&"T"===e[t+5]&&"A"===e[t+6]&&"["===e[t+7])for(t+=8;t"===e[t+2]){t+=2;break}return t}t.validate=function(e,t){t=Object.assign({},o,t);const n=[];let c=!1,l=!1;"\ufeff"===e[0]&&(e=e.substr(1));for(let o=0;o"!==e[o]&&" "!==e[o]&&"\t"!==e[o]&&"\n"!==e[o]&&"\r"!==e[o];o++)y+=e[o];if(y=y.trim(),"/"===y[y.length-1]&&(y=y.substring(0,y.length-1),o--),u=y,!i.isName(u)){let t;return t=0===y.trim().length?"Invalid space after '<'.":"Tag '"+y+"' is an invalid name.",m("InvalidTag",t,g(e,o))}const x=p(e,o);if(!1===x)return m("InvalidAttr","Attributes for '"+y+"' have open quote.",g(e,o));let k=x.value;if(o=x.index,"/"===k[k.length-1]){const n=o-k.length;k=k.substring(0,k.length-1);const i=d(k,t);if(!0!==i)return m(i.err.code,i.err.msg,g(e,n+i.err.line));c=!0}else if(v){if(!x.tagClosed)return m("InvalidTag","Closing tag '"+y+"' doesn't have proper closing.",g(e,o));if(k.trim().length>0)return m("InvalidTag","Closing tag '"+y+"' can't have attributes or invalid starting.",g(e,h));if(0===n.length)return m("InvalidTag","Closing tag '"+y+"' has not been opened.",g(e,h));{const t=n.pop();if(y!==t.tagName){let n=g(e,t.tagStartPos);return m("InvalidTag","Expected closing tag '"+t.tagName+"' (opened in line "+n.line+", col "+n.col+") instead of closing tag '"+y+"'.",g(e,h))}0==n.length&&(l=!0)}}else{const i=d(k,t);if(!0!==i)return m(i.err.code,i.err.msg,g(e,o-k.length+i.err.line));if(!0===l)return m("InvalidXml","Multiple possible root nodes found.",g(e,o));-1!==t.unpairedTags.indexOf(y)||n.push({tagName:y,tagStartPos:h}),c=!0}for(o++;o0)||m("InvalidXml","Invalid '"+JSON.stringify(n.map((e=>e.tagName)),null,4).replace(/\r?\n/g,"")+"' found.",{line:1,col:1}):m("InvalidXml","Start tag expected.",1)};const c='"',l="'";function p(e,t){let n="",i="",o=!1;for(;t"===e[t]&&""===i){o=!0;break}n+=e[t]}return""===i&&{value:n,index:t,tagClosed:o}}const u=new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?","g");function d(e,t){const n=i.getAllMatches(e,u),o={};for(let e=0;e{for(const n of e){if("string"==typeof n&&t===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}}:()=>!1}},function(e,t){var n=function(e){var t={},n=function(e){return!t[e]&&(t[e]=[]),t[e]};e.on=function(e,t){n(e).push(t)},e.off=function(e,t){for(var i=n(e),o=i.length-1;o>=0;o--)t===i[o]&&i.splice(o,1)},e.emit=function(e,t){for(var i=n(e).map((function(e){return e})),o=0;o=0;n--){var o=i[n][2];(!o||o+2592e3=0;a--){var r=i[a];(r[0]===e&&r[1]===t||e!==r[0]&&0===r[0].indexOf(o))&&i.splice(a,1)}i.unshift([e,t,Math.round(Date.now()/1e3)]),i.length>n&&i.splice(n),l()}},removeUploadId:function(e){c(),delete p.using[e];for(var t=i.length-1;t>=0;t--)i[t][1]===e&&i.splice(t,1);l()}};e.exports=p},function(e,t,n){var i=n(9);e.exports=i},function(e,t,n){"use strict";var i=n(0),o=n(6),a=n(25),r=n(26),s=n(32),c=n(3),l={SecretId:"",SecretKey:"",SecurityToken:"",StartTime:0,ExpiredTime:0,ChunkRetryTimes:2,FileParallelLimit:3,ChunkParallelLimit:3,ChunkSize:1048576,SliceSize:1048576,CopyChunkParallelLimit:20,CopyChunkSize:10485760,CopySliceSize:10485760,MaxPartNumber:1e4,ProgressInterval:1e3,UploadQueueSize:1e4,Domain:"",ServiceDomain:"",Protocol:"",CompatibilityMode:!1,ForcePathStyle:!1,Timeout:0,CorrectClockSkew:!0,SystemClockOffset:0,UploadCheckContentMd5:!1,UploadAddMetaMd5:!1,UploadIdCacheLimit:50,UseAccelerate:!1,ForceSignHost:!0,HttpDNSServiceId:"",SimpleUploadMethod:"postObject",AutoSwitchHost:!1,CopySourceParser:null,ObjectKeySimplifyCheck:!0,DeepTracker:!1,TrackerDelay:5e3,CustomId:"",BeaconReporter:null,ClsReporter:null},p=function(e){if(this.options=i.extend(i.clone(l),e||{}),this.options.FileParallelLimit=Math.max(1,this.options.FileParallelLimit),this.options.ChunkParallelLimit=Math.max(1,this.options.ChunkParallelLimit),this.options.ChunkRetryTimes=Math.max(0,this.options.ChunkRetryTimes),this.options.ChunkSize=Math.max(1048576,this.options.ChunkSize),this.options.CopyChunkParallelLimit=Math.max(1,this.options.CopyChunkParallelLimit),this.options.CopyChunkSize=Math.max(1048576,this.options.CopyChunkSize),this.options.CopySliceSize=Math.max(0,this.options.CopySliceSize),this.options.MaxPartNumber=Math.max(1024,Math.min(1e4,this.options.MaxPartNumber)),this.options.Timeout=Math.max(0,this.options.Timeout),this.options.EnableReporter=this.options.BeaconReporter||this.options.ClsReporter,this.options.AppId,this.options.SecretId&&this.options.SecretId.indexOf(" "),this.options.SecretKey&&this.options.SecretKey.indexOf(" "),this.options.ForcePathStyle)throw new Error("ForcePathStyle is not supported");o.init(this),a.init(this)};r.init(p,a),s.init(p,a),p.util={md5:i.md5,xml2json:i.xml2json,json2xml:i.json2xml,encodeBase64:i.encodeBase64},p.getAuthorization=i.getAuth,p.version=c.version,e.exports=p},function(e,t,n){(function(e){var t;function i(e){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i(e)}!function(){"use strict";var o="input is invalid type",a="object"===("undefined"==typeof window?"undefined":i(window)),r=a?window:{};r.JS_MD5_NO_WINDOW&&(a=!1),!a&&"object"===("undefined"==typeof self?"undefined":i(self))&&(r=self);var s,c=!r.JS_MD5_NO_COMMON_JS&&"object"===i(e)&&e.exports,l=n(12),p=!r.JS_MD5_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,u="0123456789abcdef".split(""),d=[128,32768,8388608,-2147483648],f=[0,8,16,24],m=["hex","array","digest","buffer","arrayBuffer","base64"],h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),g=[];if(p){var v=new ArrayBuffer(68);s=new Uint8Array(v),g=new Uint32Array(v)}!r.JS_MD5_NO_NODE_JS&&Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),!p||!r.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView||(ArrayBuffer.isView=function(e){return"object"===i(e)&&e.buffer&&e.buffer.constructor===ArrayBuffer});var y=function(e){return function(t){return new x(!0).update(t)[e]()}};function x(e){if(e)g[0]=g[16]=g[1]=g[2]=g[3]=g[4]=g[5]=g[6]=g[7]=g[8]=g[9]=g[10]=g[11]=g[12]=g[13]=g[14]=g[15]=0,this.blocks=g,this.buffer8=s;else if(p){var t=new ArrayBuffer(68);this.buffer8=new Uint8Array(t),this.blocks=new Uint32Array(t)}else this.blocks=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.h0=this.h1=this.h2=this.h3=this.start=this.bytes=this.hBytes=0,this.finalized=this.hashed=!1,this.first=!0}x.prototype.update=function(e){if(!this.finalized){var t,n=i(e);if("string"!==n){if("object"!==n)throw o;if(null===e)throw o;if(!p||e.constructor!==ArrayBuffer&&"ArrayBuffer"!==e.constructor.name){if(!(Array.isArray(e)||p&&ArrayBuffer.isView(e)))throw o}else e=new Uint8Array(e);t=!0}for(var a,r,s=0,c=e.length,l=this.blocks,u=this.buffer8;s>2]|=e[s]<>6,u[r++]=128|63&a):a<55296||a>=57344?(u[r++]=224|a>>12,u[r++]=128|a>>6&63,u[r++]=128|63&a):(a=65536+((1023&a)<<10|1023&e.charCodeAt(++s)),u[r++]=240|a>>18,u[r++]=128|a>>12&63,u[r++]=128|a>>6&63,u[r++]=128|63&a);else for(r=this.start;s>2]|=a<>2]|=(192|a>>6)<>2]|=(128|63&a)<=57344?(l[r>>2]|=(224|a>>12)<>2]|=(128|a>>6&63)<>2]|=(128|63&a)<>2]|=(240|a>>18)<>2]|=(128|a>>12&63)<>2]|=(128|a>>6&63)<>2]|=(128|63&a)<=64?(this.start=r-64,this.hash(),this.hashed=!0):this.start=r}return this.bytes>4294967295&&(this.hBytes+=this.bytes/4294967296<<0,this.bytes=this.bytes%4294967296),this}},x.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var e=this.blocks,t=this.lastByteIndex;e[t>>2]|=d[3&t],t>=56&&(this.hashed||this.hash(),e[0]=e[16],e[16]=e[1]=e[2]=e[3]=e[4]=e[5]=e[6]=e[7]=e[8]=e[9]=e[10]=e[11]=e[12]=e[13]=e[14]=e[15]=0),e[14]=this.bytes<<3,e[15]=this.hBytes<<3|this.bytes>>>29,this.hash()}},x.prototype.hash=function(){var e,t,n,i,o,a,r=this.blocks;this.first?t=((t=((e=((e=r[0]-680876937)<<7|e>>>25)-271733879<<0)^(n=((n=(-271733879^(i=((i=(-1732584194^2004318071&e)+r[1]-117830708)<<12|i>>>20)+e<<0)&(-271733879^e))+r[2]-1126478375)<<17|n>>>15)+i<<0)&(i^e))+r[3]-1316259209)<<22|t>>>10)+n<<0:(e=this.h0,t=this.h1,n=this.h2,t=((t+=((e=((e+=((i=this.h3)^t&(n^i))+r[0]-680876936)<<7|e>>>25)+t<<0)^(n=((n+=(t^(i=((i+=(n^e&(t^n))+r[1]-389564586)<<12|i>>>20)+e<<0)&(e^t))+r[2]+606105819)<<17|n>>>15)+i<<0)&(i^e))+r[3]-1044525330)<<22|t>>>10)+n<<0),t=((t+=((e=((e+=(i^t&(n^i))+r[4]-176418897)<<7|e>>>25)+t<<0)^(n=((n+=(t^(i=((i+=(n^e&(t^n))+r[5]+1200080426)<<12|i>>>20)+e<<0)&(e^t))+r[6]-1473231341)<<17|n>>>15)+i<<0)&(i^e))+r[7]-45705983)<<22|t>>>10)+n<<0,t=((t+=((e=((e+=(i^t&(n^i))+r[8]+1770035416)<<7|e>>>25)+t<<0)^(n=((n+=(t^(i=((i+=(n^e&(t^n))+r[9]-1958414417)<<12|i>>>20)+e<<0)&(e^t))+r[10]-42063)<<17|n>>>15)+i<<0)&(i^e))+r[11]-1990404162)<<22|t>>>10)+n<<0,t=((t+=((e=((e+=(i^t&(n^i))+r[12]+1804603682)<<7|e>>>25)+t<<0)^(n=((n+=(t^(i=((i+=(n^e&(t^n))+r[13]-40341101)<<12|i>>>20)+e<<0)&(e^t))+r[14]-1502002290)<<17|n>>>15)+i<<0)&(i^e))+r[15]+1236535329)<<22|t>>>10)+n<<0,t=((t+=((i=((i+=(t^n&((e=((e+=(n^i&(t^n))+r[1]-165796510)<<5|e>>>27)+t<<0)^t))+r[6]-1069501632)<<9|i>>>23)+e<<0)^e&((n=((n+=(e^t&(i^e))+r[11]+643717713)<<14|n>>>18)+i<<0)^i))+r[0]-373897302)<<20|t>>>12)+n<<0,t=((t+=((i=((i+=(t^n&((e=((e+=(n^i&(t^n))+r[5]-701558691)<<5|e>>>27)+t<<0)^t))+r[10]+38016083)<<9|i>>>23)+e<<0)^e&((n=((n+=(e^t&(i^e))+r[15]-660478335)<<14|n>>>18)+i<<0)^i))+r[4]-405537848)<<20|t>>>12)+n<<0,t=((t+=((i=((i+=(t^n&((e=((e+=(n^i&(t^n))+r[9]+568446438)<<5|e>>>27)+t<<0)^t))+r[14]-1019803690)<<9|i>>>23)+e<<0)^e&((n=((n+=(e^t&(i^e))+r[3]-187363961)<<14|n>>>18)+i<<0)^i))+r[8]+1163531501)<<20|t>>>12)+n<<0,t=((t+=((i=((i+=(t^n&((e=((e+=(n^i&(t^n))+r[13]-1444681467)<<5|e>>>27)+t<<0)^t))+r[2]-51403784)<<9|i>>>23)+e<<0)^e&((n=((n+=(e^t&(i^e))+r[7]+1735328473)<<14|n>>>18)+i<<0)^i))+r[12]-1926607734)<<20|t>>>12)+n<<0,t=((t+=((a=(i=((i+=((o=t^n)^(e=((e+=(o^i)+r[5]-378558)<<4|e>>>28)+t<<0))+r[8]-2022574463)<<11|i>>>21)+e<<0)^e)^(n=((n+=(a^t)+r[11]+1839030562)<<16|n>>>16)+i<<0))+r[14]-35309556)<<23|t>>>9)+n<<0,t=((t+=((a=(i=((i+=((o=t^n)^(e=((e+=(o^i)+r[1]-1530992060)<<4|e>>>28)+t<<0))+r[4]+1272893353)<<11|i>>>21)+e<<0)^e)^(n=((n+=(a^t)+r[7]-155497632)<<16|n>>>16)+i<<0))+r[10]-1094730640)<<23|t>>>9)+n<<0,t=((t+=((a=(i=((i+=((o=t^n)^(e=((e+=(o^i)+r[13]+681279174)<<4|e>>>28)+t<<0))+r[0]-358537222)<<11|i>>>21)+e<<0)^e)^(n=((n+=(a^t)+r[3]-722521979)<<16|n>>>16)+i<<0))+r[6]+76029189)<<23|t>>>9)+n<<0,t=((t+=((a=(i=((i+=((o=t^n)^(e=((e+=(o^i)+r[9]-640364487)<<4|e>>>28)+t<<0))+r[12]-421815835)<<11|i>>>21)+e<<0)^e)^(n=((n+=(a^t)+r[15]+530742520)<<16|n>>>16)+i<<0))+r[2]-995338651)<<23|t>>>9)+n<<0,t=((t+=((i=((i+=(t^((e=((e+=(n^(t|~i))+r[0]-198630844)<<6|e>>>26)+t<<0)|~n))+r[7]+1126891415)<<10|i>>>22)+e<<0)^((n=((n+=(e^(i|~t))+r[14]-1416354905)<<15|n>>>17)+i<<0)|~e))+r[5]-57434055)<<21|t>>>11)+n<<0,t=((t+=((i=((i+=(t^((e=((e+=(n^(t|~i))+r[12]+1700485571)<<6|e>>>26)+t<<0)|~n))+r[3]-1894986606)<<10|i>>>22)+e<<0)^((n=((n+=(e^(i|~t))+r[10]-1051523)<<15|n>>>17)+i<<0)|~e))+r[1]-2054922799)<<21|t>>>11)+n<<0,t=((t+=((i=((i+=(t^((e=((e+=(n^(t|~i))+r[8]+1873313359)<<6|e>>>26)+t<<0)|~n))+r[15]-30611744)<<10|i>>>22)+e<<0)^((n=((n+=(e^(i|~t))+r[6]-1560198380)<<15|n>>>17)+i<<0)|~e))+r[13]+1309151649)<<21|t>>>11)+n<<0,t=((t+=((i=((i+=(t^((e=((e+=(n^(t|~i))+r[4]-145523070)<<6|e>>>26)+t<<0)|~n))+r[11]-1120210379)<<10|i>>>22)+e<<0)^((n=((n+=(e^(i|~t))+r[2]+718787259)<<15|n>>>17)+i<<0)|~e))+r[9]-343485551)<<21|t>>>11)+n<<0,this.first?(this.h0=e+1732584193<<0,this.h1=t-271733879<<0,this.h2=n-1732584194<<0,this.h3=i+271733878<<0,this.first=!1):(this.h0=this.h0+e<<0,this.h1=this.h1+t<<0,this.h2=this.h2+n<<0,this.h3=this.h3+i<<0)},x.prototype.hex=function(){this.finalize();var e=this.h0,t=this.h1,n=this.h2,i=this.h3;return u[e>>4&15]+u[15&e]+u[e>>12&15]+u[e>>8&15]+u[e>>20&15]+u[e>>16&15]+u[e>>28&15]+u[e>>24&15]+u[t>>4&15]+u[15&t]+u[t>>12&15]+u[t>>8&15]+u[t>>20&15]+u[t>>16&15]+u[t>>28&15]+u[t>>24&15]+u[n>>4&15]+u[15&n]+u[n>>12&15]+u[n>>8&15]+u[n>>20&15]+u[n>>16&15]+u[n>>28&15]+u[n>>24&15]+u[i>>4&15]+u[15&i]+u[i>>12&15]+u[i>>8&15]+u[i>>20&15]+u[i>>16&15]+u[i>>28&15]+u[i>>24&15]},x.prototype.toString=x.prototype.hex,x.prototype.digest=function(){this.finalize();var e=this.h0,t=this.h1,n=this.h2,i=this.h3;return[255&e,e>>8&255,e>>16&255,e>>24&255,255&t,t>>8&255,t>>16&255,t>>24&255,255&n,n>>8&255,n>>16&255,n>>24&255,255&i,i>>8&255,i>>16&255,i>>24&255]},x.prototype.array=x.prototype.digest,x.prototype.arrayBuffer=function(){this.finalize();var e=new ArrayBuffer(16),t=new Uint32Array(e);return t[0]=this.h0,t[1]=this.h1,t[2]=this.h2,t[3]=this.h3,e},x.prototype.buffer=x.prototype.arrayBuffer,x.prototype.base64=function(){for(var e,t,n,i="",o=this.array(),a=0;a<15;)e=o[a++],t=o[a++],n=o[a++],i+=h[e>>>2]+h[63&(e<<4|t>>>4)]+h[63&(t<<2|n>>>6)]+h[63&n];return e=o[a],i+=h[e>>>2]+h[e<<4&63]+"=="};var k=function(){var e=y("hex");e.getCtx=e.create=function(){return new x},e.update=function(t){return e.create().update(t)};for(var t=0;t>>2]|=(n[o>>>2]>>>24-o%4*8&255)<<24-(i+o)%4*8;else if(65535>>2]=n[o>>>2];else t.push.apply(t,n);return this.sigBytes+=e,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=a.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],i=0;i>>2]>>>24-i%4*8&255;n.push((o>>>4).toString(16)),n.push((15&o).toString(16))}return n.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>3]|=parseInt(e.substr(i,2),16)<<24-i%8*4;return new r.init(n,t/2)}},l=s.Latin1={stringify:function(e){var t=e.words;e=e.sigBytes;for(var n=[],i=0;i>>2]>>>24-i%4*8&255));return n.join("")},parse:function(e){for(var t=e.length,n=[],i=0;i>>2]|=(255&e.charCodeAt(i))<<24-i%4*8;return new r.init(n,t)}},p=s.Utf8={stringify:function(e){try{return decodeURIComponent(escape(l.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return l.parse(unescape(encodeURIComponent(e)))}},u=i.BufferedBlockAlgorithm=a.extend({reset:function(){this._data=new r.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=p.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,i=n.words,o=n.sigBytes,a=this.blockSize,s=o/(4*a);if(t=(s=t?e.ceil(s):e.max((0|s)-this._minBufferSize,0))*a,o=e.min(4*t,o),t){for(var c=0;cl;l++){if(16>l)a[l]=0|e[t+l];else{var p=a[l-3]^a[l-8]^a[l-14]^a[l-16];a[l]=p<<1|p>>>31}p=(i<<5|i>>>27)+c+a[l],p=20>l?p+(1518500249+(o&r|~o&s)):40>l?p+(1859775393+(o^r^s)):60>l?p+((o&r|o&s|r&s)-1894007588):p+((o^r^s)-899497514),c=s,s=r,r=o<<30|o>>>2,o=i,i=p}n[0]=n[0]+i|0,n[1]=n[1]+o|0,n[2]=n[2]+r|0,n[3]=n[3]+s|0,n[4]=n[4]+c|0},_doFinalize:function(){var e=this._data,t=e.words,n=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[14+(i+64>>>9<<4)]=Math.floor(n/4294967296),t[15+(i+64>>>9<<4)]=n,e.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var e=o.clone.call(this);return e._hash=this._hash.clone(),e}}),n.SHA1=o._createHelper(r),n.HmacSHA1=o._createHmacHelper(r),function(){var e=l,t=e.enc.Utf8;e.algo.HMAC=e.lib.Base.extend({init:function(e,n){e=this._hasher=new e.init,"string"==typeof n&&(n=t.parse(n));var i=e.blockSize,o=4*i;n.sigBytes>o&&(n=e.finalize(n)),n.clamp();for(var a=this._oKey=n.clone(),r=this._iKey=n.clone(),s=a.words,c=r.words,l=0;l>>2]>>>24-a%4*8&255)<<16|(t[a+1>>>2]>>>24-(a+1)%4*8&255)<<8|t[a+2>>>2]>>>24-(a+2)%4*8&255,s=0;s<4&&a+.75*s>>6*(3-s)&63));var c=i.charAt(64);if(c)for(;o.length%4;)o.push(c);return o.join("")},parse:function(e){var t=e.length,n=this._map,i=n.charAt(64);if(i){var o=e.indexOf(i);-1!=o&&(t=o)}for(var a=[],r=0,s=0;s>>6-s%4*2;a[r>>>2]|=(l|p)<<24-r%4*8,r++}return c.create(a,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},e.exports=l},function(e,t){var n=function(e){var t=(e=e||{}).Base64,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",i=function(e){for(var t={},n=0,i=e.length;n>>6)+o(128|63&t):o(224|t>>>12&15)+o(128|t>>>6&63)+o(128|63&t);var t=65536+1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320);return o(240|t>>>18&7)+o(128|t>>>12&63)+o(128|t>>>6&63)+o(128|63&t)},r=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,s=function(e){return e.replace(r,a)},c=function(e){var t=[0,2,1][e.length%3],i=e.charCodeAt(0)<<16|(e.length>1?e.charCodeAt(1):0)<<8|(e.length>2?e.charCodeAt(2):0);return[n.charAt(i>>>18),n.charAt(i>>>12&63),t>=2?"=":n.charAt(i>>>6&63),t>=1?"=":n.charAt(63&i)].join("")},l=e.btoa?function(t){return e.btoa(t)}:function(e){return e.replace(/[\s\S]{1,3}/g,c)},p=function(e){return l(s(e))},u=function(e,t){return t?p(String(e)).replace(/[+\/]/g,(function(e){return"+"==e?"-":"_"})).replace(/=/g,""):p(String(e))},d=new RegExp(["[À-ß][-¿]","[à-ï][-¿]{2}","[ð-÷][-¿]{3}"].join("|"),"g"),f=function(e){switch(e.length){case 4:var t=((7&e.charCodeAt(0))<<18|(63&e.charCodeAt(1))<<12|(63&e.charCodeAt(2))<<6|63&e.charCodeAt(3))-65536;return o(55296+(t>>>10))+o(56320+(1023&t));case 3:return o((15&e.charCodeAt(0))<<12|(63&e.charCodeAt(1))<<6|63&e.charCodeAt(2));default:return o((31&e.charCodeAt(0))<<6|63&e.charCodeAt(1))}},m=function(e){return e.replace(d,f)},h=function(e){var t=e.length,n=t%4,a=(t>0?i[e.charAt(0)]<<18:0)|(t>1?i[e.charAt(1)]<<12:0)|(t>2?i[e.charAt(2)]<<6:0)|(t>3?i[e.charAt(3)]:0),r=[o(a>>>16),o(a>>>8&255),o(255&a)];return r.length-=[0,0,2,1][n],r.join("")},g=e.atob?function(t){return e.atob(t)}:function(e){return e.replace(/[\s\S]{1,4}/g,h)},v=function(e){return m(g(e))},y=function(e){return v(String(e).replace(/[-_]/g,(function(e){return"-"==e?"+":"/"})).replace(/[^A-Za-z0-9\+\/]/g,""))};return{VERSION:"2.1.9",atob:g,btoa:l,fromBase64:y,toBase64:u,utob:s,encode:u,encodeURI:function(e){return u(e,!0)},btou:m,decode:y,noConflict:function(){var n=e.Base64;return e.Base64=t,n}}}();e.exports=n},function(e,t,n){"use strict";const i=n(4),o=n(16),a=n(23);e.exports={XMLParser:o,XMLValidator:i,XMLBuilder:a}},function(e,t,n){const{buildOptions:i}=n(17),o=n(18),{prettify:a}=n(22),r=n(4);e.exports=class{constructor(e){this.externalEntities={},this.options=i(e)}parse(e,t){if("string"==typeof e);else{if(!e.toString)throw new Error("XML data is accepted in String or Bytes[] form.");e=e.toString()}if(t){!0===t&&(t={});const n=r.validate(e,t);if(!0!==n)throw Error(`${n.err.msg}:${n.err.line}:${n.err.col}`)}const n=new o(this.options);n.addExternalEntities(this.externalEntities);const i=n.parseXml(e);return this.options.preserveOrder||void 0===i?i:a(i,this.options)}addEntity(e,t){if(-1!==t.indexOf("&"))throw new Error("Entity value can't have '&'");if(-1!==e.indexOf("&")||-1!==e.indexOf(";"))throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'");if("&"===t)throw new Error("An entity with value '&' is not permitted");this.externalEntities[e]=t}}},function(e,t){const n={preserveOrder:!1,attributeNamePrefix:"@_",attributesGroupName:!1,textNodeName:"#text",ignoreAttributes:!0,removeNSPrefix:!1,allowBooleanAttributes:!1,parseTagValue:!0,parseAttributeValue:!1,trimValues:!0,cdataPropName:!1,numberParseOptions:{hex:!0,leadingZeros:!0,eNotation:!0},tagValueProcessor:function(e,t){return t},attributeValueProcessor:function(e,t){return t},stopNodes:[],alwaysCreateTextNode:!1,isArray:()=>!1,commentPropName:!1,unpairedTags:[],processEntities:!0,htmlEntities:!1,ignoreDeclaration:!1,ignorePiTags:!1,transformTagName:!1,transformAttributeName:!1,updateTag:function(e,t,n){return e}};t.buildOptions=function(e){return Object.assign({},n,e)},t.defaultOptions=n},function(e,t,n){"use strict";const i=n(1),o=n(19),a=n(20),r=n(21),s=n(5);function c(e){const t=Object.keys(e);for(let n=0;n0)){r||(e=this.replaceEntitiesValue(e));const i=this.options.tagValueProcessor(t,e,n,o,a);if(null==i)return e;if(typeof i!=typeof e||i!==e)return i;if(this.options.trimValues)return b(e,this.options.parseTagValue,this.options.numberParseOptions);return e.trim()===e?b(e,this.options.parseTagValue,this.options.numberParseOptions):e}}function p(e){if(this.options.removeNSPrefix){const t=e.split(":"),n="/"===e.charAt(0)?"/":"";if("xmlns"===t[0])return"";2===t.length&&(e=n+t[1])}return e}const u=new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?","gm");function d(e,t,n){if(!0!==this.options.ignoreAttributes&&"string"==typeof e){const n=i.getAllMatches(e,u),o=n.length,a={};for(let e=0;e",s,"Closing Tag is not closed.");let o=e.substring(s+2,t).trim();if(this.options.removeNSPrefix){const e=o.indexOf(":");-1!==e&&(o=o.substr(e+1))}this.options.transformTagName&&(o=this.options.transformTagName(o)),n&&(i=this.saveTextToParentTag(i,n,r));const a=r.substring(r.lastIndexOf(".")+1);if(o&&-1!==this.options.unpairedTags.indexOf(o))throw new Error(`Unpaired tag can not be used as closing tag: ${o}>`);let c=0;a&&-1!==this.options.unpairedTags.indexOf(a)?(c=r.lastIndexOf(".",r.lastIndexOf(".")-1),this.tagsNodeStack.pop()):c=r.lastIndexOf("."),r=r.substring(0,c),n=this.tagsNodeStack.pop(),i="",s=t}else if("?"===e[s+1]){let t=x(e,s,!1,"?>");if(!t)throw new Error("Pi Tag is not closed.");if(i=this.saveTextToParentTag(i,n,r),this.options.ignoreDeclaration&&"?xml"===t.tagName||this.options.ignorePiTags);else{const e=new o(t.tagName);e.add(this.options.textNodeName,""),t.tagName!==t.tagExp&&t.attrExpPresent&&(e[":@"]=this.buildAttributesMap(t.tagExp,r,t.tagName)),this.addChild(n,e,r)}s=t.closeIndex+1}else if("!--"===e.substr(s+1,3)){const t=y(e,"--\x3e",s+4,"Comment is not closed.");if(this.options.commentPropName){const o=e.substring(s+4,t-2);i=this.saveTextToParentTag(i,n,r),n.add(this.options.commentPropName,[{[this.options.textNodeName]:o}])}s=t}else if("!D"===e.substr(s+1,2)){const t=a(e,s);this.docTypeEntities=t.entities,s=t.i}else if("!["===e.substr(s+1,2)){const t=y(e,"]]>",s,"CDATA is not closed.")-2,o=e.substring(s+9,t);i=this.saveTextToParentTag(i,n,r);let a=this.parseTextData(o,n.tagname,r,!0,!1,!0,!0);null==a&&(a=""),this.options.cdataPropName?n.add(this.options.cdataPropName,[{[this.options.textNodeName]:o}]):n.add(this.options.textNodeName,a),s=t+2}else{let a=x(e,s,this.options.removeNSPrefix),c=a.tagName;const l=a.rawTagName;let p=a.tagExp,u=a.attrExpPresent,d=a.closeIndex;this.options.transformTagName&&(c=this.options.transformTagName(c)),n&&i&&"!xml"!==n.tagname&&(i=this.saveTextToParentTag(i,n,r,!1));const f=n;if(f&&-1!==this.options.unpairedTags.indexOf(f.tagname)&&(n=this.tagsNodeStack.pop(),r=r.substring(0,r.lastIndexOf("."))),c!==t.tagname&&(r+=r?"."+c:c),this.isItStopNode(this.options.stopNodes,r,c)){let t="";if(p.length>0&&p.lastIndexOf("/")===p.length-1)"/"===c[c.length-1]?(c=c.substr(0,c.length-1),r=r.substr(0,r.length-1),p=c):p=p.substr(0,p.length-1),s=a.closeIndex;else if(-1!==this.options.unpairedTags.indexOf(c))s=a.closeIndex;else{const n=this.readStopNodeData(e,l,d+1);if(!n)throw new Error(`Unexpected end of ${l}`);s=n.i,t=n.tagContent}const i=new o(c);c!==p&&u&&(i[":@"]=this.buildAttributesMap(p,r,c)),t&&(t=this.parseTextData(t,c,r,!0,u,!0,!0)),r=r.substr(0,r.lastIndexOf(".")),i.add(this.options.textNodeName,t),this.addChild(n,i,r)}else{if(p.length>0&&p.lastIndexOf("/")===p.length-1){"/"===c[c.length-1]?(c=c.substr(0,c.length-1),r=r.substr(0,r.length-1),p=c):p=p.substr(0,p.length-1),this.options.transformTagName&&(c=this.options.transformTagName(c));const e=new o(c);c!==p&&u&&(e[":@"]=this.buildAttributesMap(p,r,c)),this.addChild(n,e,r),r=r.substr(0,r.lastIndexOf("."))}else{const e=new o(c);this.tagsNodeStack.push(n),c!==p&&u&&(e[":@"]=this.buildAttributesMap(p,r,c)),this.addChild(n,e,r),n=e}i="",s=d}}else i+=e[s]}return t.child};function m(e,t,n){const i=this.options.updateTag(t.tagname,n,t[":@"]);!1===i||("string"==typeof i?(t.tagname=i,e.addChild(t)):e.addChild(t))}const h=function(e){if(this.options.processEntities){for(let t in this.docTypeEntities){const n=this.docTypeEntities[t];e=e.replace(n.regx,n.val)}for(let t in this.lastEntities){const n=this.lastEntities[t];e=e.replace(n.regex,n.val)}if(this.options.htmlEntities)for(let t in this.htmlEntities){const n=this.htmlEntities[t];e=e.replace(n.regex,n.val)}e=e.replace(this.ampEntity.regex,this.ampEntity.val)}return e};function g(e,t,n,i){return e&&(void 0===i&&(i=0===Object.keys(t.child).length),void 0!==(e=this.parseTextData(e,t.tagname,n,!1,!!t[":@"]&&0!==Object.keys(t[":@"]).length,i))&&""!==e&&t.add(this.options.textNodeName,e),e=""),e}function v(e,t,n){const i="*."+n;for(const n in e){const o=e[n];if(i===o||t===o)return!0}return!1}function y(e,t,n,i){const o=e.indexOf(t,n);if(-1===o)throw new Error(i);return o+t.length-1}function x(e,t,n,i=">"){const o=function(e,t,n=">"){let i,o="";for(let a=t;a",n,`${t} is not closed`);if(e.substring(n+2,a).trim()===t&&(o--,0===o))return{tagContent:e.substring(i,n),i:a};n=a}else if("?"===e[n+1]){n=y(e,"?>",n+1,"StopNode is not closed.")}else if("!--"===e.substr(n+1,3)){n=y(e,"--\x3e",n+3,"StopNode is not closed.")}else if("!["===e.substr(n+1,2)){n=y(e,"]]>",n,"StopNode is not closed.")-2}else{const i=x(e,n,">");if(i){(i&&i.tagName)===t&&"/"!==i.tagExp[i.tagExp.length-1]&&o++,n=i.closeIndex}}}function b(e,t,n){if(t&&"string"==typeof e){const t=e.trim();return"true"===t||"false"!==t&&r(e,n)}return i.isExist(e)?e:""}e.exports=class{constructor(e){this.options=e,this.currentNode=null,this.tagsNodeStack=[],this.docTypeEntities={},this.lastEntities={apos:{regex:/&(apos|#39|#x27);/g,val:"'"},gt:{regex:/&(gt|#62|#x3E);/g,val:">"},lt:{regex:/&(lt|#60|#x3C);/g,val:"<"},quot:{regex:/&(quot|#34|#x22);/g,val:'"'}},this.ampEntity={regex:/&(amp|#38|#x26);/g,val:"&"},this.htmlEntities={space:{regex:/&(nbsp|#160);/g,val:" "},cent:{regex:/&(cent|#162);/g,val:"¢"},pound:{regex:/&(pound|#163);/g,val:"£"},yen:{regex:/&(yen|#165);/g,val:"¥"},euro:{regex:/&(euro|#8364);/g,val:"€"},copyright:{regex:/&(copy|#169);/g,val:"©"},reg:{regex:/&(reg|#174);/g,val:"®"},inr:{regex:/&(inr|#8377);/g,val:"₹"},num_dec:{regex:/([0-9]{1,7});/g,val:(e,t)=>String.fromCharCode(Number.parseInt(t,10))},num_hex:{regex:/([0-9a-fA-F]{1,6});/g,val:(e,t)=>String.fromCharCode(Number.parseInt(t,16))}},this.addExternalEntities=c,this.parseXml=f,this.parseTextData=l,this.resolveNameSpace=p,this.buildAttributesMap=d,this.isItStopNode=v,this.replaceEntitiesValue=h,this.readStopNodeData=k,this.saveTextToParentTag=g,this.addChild=m,this.ignoreAttributesFn=s(this.options.ignoreAttributes)}}},function(e,t,n){"use strict";e.exports=class{constructor(e){this.tagname=e,this.child=[],this[":@"]={}}add(e,t){"__proto__"===e&&(e="#__proto__"),this.child.push({[e]:t})}addChild(e){"__proto__"===e.tagname&&(e.tagname="#__proto__"),e[":@"]&&Object.keys(e[":@"]).length>0?this.child.push({[e.tagname]:e.child,":@":e[":@"]}):this.child.push({[e.tagname]:e.child})}}},function(e,t,n){const i=n(1);function o(e,t){let n="";for(;t"===e[t]){if(d?"-"===e[t-1]&&"-"===e[t-2]&&(d=!1,i--):i--,0===i)break}else"["===e[t]?u=!0:f+=e[t];else{if(u&&r(e,t))t+=7,[entityName,val,t]=o(e,t+1),-1===val.indexOf("&")&&(n[p(entityName)]={regx:RegExp(`&${entityName};`,"g"),val:val});else if(u&&s(e,t))t+=8;else if(u&&c(e,t))t+=8;else if(u&&l(e,t))t+=9;else{if(!a)throw new Error("Invalid DOCTYPE");d=!0}i++,f=""}if(0!==i)throw new Error("Unclosed DOCTYPE")}return{entities:n,i:t}}},function(e,t){const n=/^[-+]?0x[a-fA-F0-9]+$/,i=/^([\-\+])?(0*)(\.[0-9]+([eE]\-?[0-9]+)?|[0-9]+(\.[0-9]+([eE]\-?[0-9]+)?)?)$/;!Number.parseInt&&window.parseInt&&(Number.parseInt=window.parseInt),!Number.parseFloat&&window.parseFloat&&(Number.parseFloat=window.parseFloat);const o={hex:!0,leadingZeros:!0,decimalPoint:".",eNotation:!0};e.exports=function(e,t={}){if(t=Object.assign({},o,t),!e||"string"!=typeof e)return e;let a=e.trim();if(void 0!==t.skipLike&&t.skipLike.test(a))return e;if(t.hex&&n.test(a))return Number.parseInt(a,16);{const n=i.exec(a);if(n){const i=n[1],o=n[2];let r=function(e){if(e&&-1!==e.indexOf("."))return"."===(e=e.replace(/0+$/,""))?e="0":"."===e[0]?e="0"+e:"."===e[e.length-1]&&(e=e.substr(0,e.length-1)),e;return e}(n[3]);const s=n[4]||n[6];if(!t.leadingZeros&&o.length>0&&i&&"."!==a[2])return e;if(!t.leadingZeros&&o.length>0&&!i&&"."!==a[1])return e;{const n=Number(a),c=""+n;return-1!==c.search(/[eE]/)||s?t.eNotation?n:e:-1!==a.indexOf(".")?"0"===c&&""===r||c===r||i&&c==="-"+r?n:e:o?r===c||i+r===c?n:e:a===c||a===i+c?n:e}}return e}}},function(e,t,n){"use strict";function i(e,t,n){let s;const c={};for(let l=0;l0&&(c[t.textNodeName]=s):void 0!==s&&(c[t.textNodeName]=s),c}function o(e){const t=Object.keys(e);for(let e=0;e","g"),val:">"},{regex:new RegExp("<","g"),val:"<"},{regex:new RegExp("'","g"),val:"'"},{regex:new RegExp('"',"g"),val:"""}],processEntities:!0,stopNodes:[],oneListGroup:!1};function r(e){this.options=Object.assign({},a,e),!0===this.options.ignoreAttributes||this.options.attributesGroupName?this.isAttribute=function(){return!1}:(this.ignoreAttributesFn=o(this.options.ignoreAttributes),this.attrPrefixLen=this.options.attributeNamePrefix.length,this.isAttribute=l),this.processTextOrObjNode=s,this.options.format?(this.indentate=c,this.tagEndChar=">\n",this.newLine="\n"):(this.indentate=function(){return""},this.tagEndChar=">",this.newLine="")}function s(e,t,n,i){const o=this.j2x(e,n+1,i.concat(t));return void 0!==e[this.options.textNodeName]&&1===Object.keys(e).length?this.buildTextValNode(e[this.options.textNodeName],t,o.attrStr,n):this.buildObjectNode(o.val,t,o.attrStr,n)}function c(e){return this.options.indentBy.repeat(e)}function l(e){return!(!e.startsWith(this.options.attributeNamePrefix)||e===this.options.textNodeName)&&e.substr(this.attrPrefixLen)}r.prototype.build=function(e){return this.options.preserveOrder?i(e,this.options):(Array.isArray(e)&&this.options.arrayNodeName&&this.options.arrayNodeName.length>1&&(e={[this.options.arrayNodeName]:e}),this.j2x(e,0,[]).val)},r.prototype.j2x=function(e,t,n){let i="",o="";const a=n.join(".");for(let r in e)if(Object.prototype.hasOwnProperty.call(e,r))if(void 0===e[r])this.isAttribute(r)&&(o+="");else if(null===e[r])this.isAttribute(r)?o+="":"?"===r[0]?o+=this.indentate(t)+"<"+r+"?"+this.tagEndChar:o+=this.indentate(t)+"<"+r+"/"+this.tagEndChar;else if(e[r]instanceof Date)o+=this.buildTextValNode(e[r],r,"",t);else if("object"!=typeof e[r]){const n=this.isAttribute(r);if(n&&!this.ignoreAttributesFn(n,a))i+=this.buildAttrPairStr(n,""+e[r]);else if(!n)if(r===this.options.textNodeName){let t=this.options.tagValueProcessor(r,""+e[r]);o+=this.replaceEntitiesValue(t)}else o+=this.buildTextValNode(e[r],r,"",t)}else if(Array.isArray(e[r])){const i=e[r].length;let a="",s="";for(let c=0;c"+e+o}},r.prototype.closeTag=function(e){let t="";return-1!==this.options.unpairedTags.indexOf(e)?this.options.suppressUnpairedNode||(t="/"):t=this.options.suppressEmptyNode?"/":`>${e}`,t},r.prototype.buildTextValNode=function(e,t,n,i){if(!1!==this.options.cdataPropName&&t===this.options.cdataPropName)return this.indentate(i)+``+this.newLine;if(!1!==this.options.commentPropName&&t===this.options.commentPropName)return this.indentate(i)+`\x3c!--${e}--\x3e`+this.newLine;if("?"===t[0])return this.indentate(i)+"<"+t+n+"?"+this.tagEndChar;{let o=this.options.tagValueProcessor(t,e);return o=this.replaceEntitiesValue(o),""===o?this.indentate(i)+"<"+t+n+this.closeTag(t)+this.tagEndChar:this.indentate(i)+"<"+t+n+">"+o+""+t+this.tagEndChar}},r.prototype.replaceEntitiesValue=function(e){if(e&&e.length>0&&this.options.processEntities)for(let t=0;t`,p=!1;continue}if(f===t.commentPropName){l+=c+`\x3c!--${d[f][0][t.textNodeName]}--\x3e`,p=!0;continue}if("?"===f[0]){const e=o(d[":@"],t),n="?xml"===f?"":c;let i=d[f][0][t.textNodeName];i=0!==i.length?" "+i:"",l+=n+`<${f}${i}${e}?>`,p=!0;continue}let h=c;""!==h&&(h+=t.indentBy);const g=c+`<${f}${o(d[":@"],t)}`,v=n(d[f],t,m,h);-1!==t.unpairedTags.indexOf(f)?t.suppressUnpairedNode?l+=g+">":l+=g+"/>":v&&0!==v.length||!t.suppressEmptyNode?v&&v.endsWith(">")?l+=g+`>${v}${c}${f}>`:(l+=g+">",v&&""!==c&&(v.includes("/>")||v.includes(""))?l+=c+t.indentBy+v+c:l+=v,l+=`${f}>`):l+=g+"/>",p=!0}return l}function i(e){const t=Object.keys(e);for(let n=0;n0&&t.processEntities)for(let n=0;n0&&(i="\n"),n(e,t,"",i)}},function(e,t,n){var i=n(7),o=n(0),a={};e.exports.transferToTaskMethod=function(e,t){a[t]=e[t],e[t]=function(e,n){e.SkipTask?a[t].call(this,e,n):this._addTask(t,e,n)}},e.exports.init=function(e){var t,n,r=[],s={},c=0,l=0,p=function(e){var t={id:e.id,Bucket:e.Bucket,Region:e.Region,Key:e.Key,FilePath:e.FilePath,state:e.state,loaded:e.loaded,size:e.size,speed:e.speed,percent:e.percent,hashPercent:e.hashPercent,error:e.error};return e.FilePath&&(t.FilePath=e.FilePath),t},u=(n=function(){t=0,e.emit("task-list-update",{list:o.map(r,p)}),e.emit("list-update",{list:o.map(r,p)})},function(){t||(t=setTimeout(n))}),d=function(){if(!(r.length<=e.options.UploadQueueSize)){for(var t=0;te.options.UploadQueueSize;){var n="waiting"===r[t].state||"checking"===r[t].state||"uploading"===r[t].state;r[t]&&n?t++:(s[r[t].id]&&delete s[r[t].id],r.splice(t,1),l--)}u()}},f=function t(){if(!(c>=e.options.FileParallelLimit)){for(;r[l]&&"waiting"!==r[l].state;)l++;if(!(l>=r.length)){var n=r[l];l++,c++,n.state="checking",n.params.onTaskStart&&n.params.onTaskStart(p(n)),!n.params.UploadData&&(n.params.UploadData={});var i=o.formatParams(n.api,n.params);a[n.api].call(e,i,(function(i,o){e._isRunningTask(n.id)&&("checking"!==n.state&&"uploading"!==n.state||(n.state=i?"error":"success",i&&(n.error=i),c--,u(),t(),n.callback&&n.callback(i,o),"success"===n.state&&(n.params&&(delete n.params.UploadData,delete n.params.Body,delete n.params),delete n.callback)),d())})),u(),setTimeout(t)}}},m=function(t,n){var o=s[t];if(o){var a=o&&"waiting"===o.state,r=o&&("checking"===o.state||"uploading"===o.state);if("canceled"===n&&"canceled"!==o.state||"paused"===n&&a||"paused"===n&&r){if("paused"===n&&o.params.Body&&"function"==typeof o.params.Body.pipe)return;o.state=n,e.emit("inner-kill-task",{TaskId:t,toState:n});try{var l=o&&o.params&&o.params.UploadData.UploadId}catch(e){}"canceled"===n&&l&&i.removeUsing(l),u(),r&&(c--,f()),"canceled"===n&&(o.params&&(delete o.params.UploadData,delete o.params.Body,delete o.params),delete o.callback)}d()}};e._addTasks=function(t){o.each(t,(function(t){e._addTask(t.api,t.params,t.callback,!0)})),u()},e._addTask=function(t,n,i,a){var c="postObject"===e.options.SimpleUploadMethod?"postObject":"putObject";"sliceUploadFile"!==t||o.canFileSlice()||(t=c),n=o.formatParams(t,n);var l=o.uuid();n.TaskId=l,n.onTaskReady&&n.onTaskReady(l);var p={params:n,callback:i,api:t,index:r.length,id:l,Bucket:n.Bucket,Region:n.Region,Key:n.Key,FilePath:n.FilePath||"",state:"waiting",loaded:0,size:0,speed:0,percent:0,hashPercent:0,error:null},m=n.onHashProgress;n.onHashProgress=function(t){e._isRunningTask(p.id)&&(p.hashPercent=t.percent,m&&m(t),u())};var h=n.onProgress;return n.onProgress=function(t){e._isRunningTask(p.id)&&("checking"===p.state&&(p.state="uploading"),p.loaded=t.loaded,p.size=t.total,p.speed=t.speed,p.percent=t.percent,h&&h(t),u())},o.getFileSize(t,n,(function(e,t){e?i(e):(s[l]=p,r.push(p),p.size=t,!a&&u(),f(),d())})),l},e._isRunningTask=function(e){var t=s[e];return!(!t||"checking"!==t.state&&"uploading"!==t.state)},e.getTaskList=function(){return o.map(r,p)},e.cancelTask=function(e){m(e,"canceled")},e.pauseTask=function(e){m(e,"paused")},e.restartTask=function(e){var t=s[e];!t||"paused"!==t.state&&"error"!==t.state||(t.state="waiting",u(),l=Math.min(l,t.index),f())},e.isUploadRunning=function(){return c||l-1?"{Region}.myqcloud.com":"cos.{Region}.myqcloud.com",e.ForcePathStyle||(a="{Bucket}."+a)),a=(a=a.replace(/\{\{AppId\}\}/gi,i).replace(/\{\{Bucket\}\}/gi,n).replace(/\{\{Region\}\}/gi,r).replace(/\{\{.*?\}\}/gi,"")).replace(/\{AppId\}/gi,i).replace(/\{BucketName\}/gi,n).replace(/\{Bucket\}/gi,t).replace(/\{Region\}/gi,r).replace(/\{.*?\}/gi,""),/^[a-zA-Z]+:\/\//.test(a)||(a="https://"+a),"/"===a.slice(-1)&&(a=a.slice(0,-1));var c=a;return e.ForcePathStyle&&(c+="/"+t),c+="/",s&&(c+=o.camSafeUrlEncode(s).replace(/%2F/g,"/")),e.isLocation&&(c=c.replace(/^https?:\/\//,"")),c}var l=function(e){if(!e.Bucket||!e.Region)return"";var t=void 0===e.UseAccelerate?this.options.UseAccelerate:e.UseAccelerate;return(e.Url||c({ForcePathStyle:this.options.ForcePathStyle,protocol:this.options.Protocol,domain:this.options.Domain,bucket:e.Bucket,region:t?"accelerate":e.Region})).replace(/^https?:\/\/([^/]+)(\/.*)?$/,"$1")};function p(e,t){var n=o.clone(e.Headers),i="";o.each(n,(function(e,t){(""===e||["content-type","cache-control"].indexOf(t.toLowerCase())>-1)&&delete n[t],"host"===t.toLowerCase()&&(i=e)}));var a=!1!==e.ForceSignHost;!i&&e.SignHost&&a&&(n.Host=e.SignHost);var r=!1,s=function(e,n){r||(r=!0,n&&n.XCosSecurityToken&&!n.SecurityToken&&((n=o.clone(n)).SecurityToken=n.XCosSecurityToken,delete n.XCosSecurityToken),t&&t(e,n))},c=this,l=e.Bucket||"",p=e.Region||"",u="name/cos:PostObject"!==e.Action&&e.Key?e.Key:"";c.options.ForcePathStyle&&l&&(u=l+"/"+u);var d="/"+u,f={},m=e.Scope;if(!m){var h=e.Action||"",g=e.ResourceKey||e.Key||"";m=e.Scope||[{action:h,bucket:l,region:p,prefix:g}]}var v=o.md5(JSON.stringify(m));c._StsCache=c._StsCache||[],function(){var e,t;for(e=c._StsCache.length-1;e>=0;e--){t=c._StsCache[e];var n=Math.round(o.getSkewTime(c.options.SystemClockOffset)/1e3)+30;if(t.StartTime&&n=t.ExpiredTime)c._StsCache.splice(e,1);else if(!t.ScopeLimit||t.ScopeLimit&&t.ScopeKey===v){f=t;break}}}();var y=function(){var t="";f.StartTime&&e.Expires?t=f.StartTime+";"+(f.StartTime+1*e.Expires):f.StartTime&&f.ExpiredTime&&(t=f.StartTime+";"+f.ExpiredTime);var i={Authorization:o.getAuth({SecretId:f.TmpSecretId,SecretKey:f.TmpSecretKey,Method:e.Method,Pathname:d,Query:e.Query,Headers:n,Expires:e.Expires,SystemClockOffset:c.options.SystemClockOffset,KeyTime:t,ForceSignHost:a}),SecurityToken:f.SecurityToken||f.XCosSecurityToken||"",Token:f.Token||"",ClientIP:f.ClientIP||"",ClientUA:f.ClientUA||"",SignFrom:"client"};s(null,i)},x=function(e){if(e.Authorization){var t=!1,n=e.Authorization;if(n)if(n.indexOf(" ")>-1)t=!1;else if(n.indexOf("q-sign-algorithm=")>-1&&n.indexOf("q-ak=")>-1&&n.indexOf("q-sign-time=")>-1&&n.indexOf("q-key-time=")>-1&&n.indexOf("q-url-param-list=")>-1)t=!0;else try{(n=atob(n)).indexOf("a=")>-1&&n.indexOf("k=")>-1&&n.indexOf("t=")>-1&&n.indexOf("r=")>-1&&n.indexOf("b=")>-1&&(t=!0)}catch(e){}if(!t)return o.error(new Error("getAuthorization callback params format error"))}else{if(!e.TmpSecretId)return o.error(new Error('getAuthorization callback params missing "TmpSecretId"'));if(!e.TmpSecretKey)return o.error(new Error('getAuthorization callback params missing "TmpSecretKey"'));if(!e.SecurityToken&&!e.XCosSecurityToken)return o.error(new Error('getAuthorization callback params missing "SecurityToken"'));if(!e.ExpiredTime)return o.error(new Error('getAuthorization callback params missing "ExpiredTime"'));if(e.ExpiredTime&&10!==e.ExpiredTime.toString().length)return o.error(new Error('getAuthorization callback params "ExpiredTime" should be 10 digits'));if(e.StartTime&&10!==e.StartTime.toString().length)return o.error(new Error('getAuthorization callback params "StartTime" should be 10 StartTime'))}return!1};if(f.ExpiredTime&&f.ExpiredTime-o.getSkewTime(c.options.SystemClockOffset)/1e3>60)y();else if(c.options.getAuthorization)c.options.getAuthorization.call(c,{Bucket:l,Region:p,Method:e.Method,Key:u,Pathname:d,Query:e.Query,Headers:n,Scope:m,SystemClockOffset:c.options.SystemClockOffset,ForceSignHost:a},(function(e){"string"==typeof e&&(e={Authorization:e});var t=x(e);if(t)return s(t);e.Authorization?s(null,e):((f=e||{}).Scope=m,f.ScopeKey=v,c._StsCache.push(f),y())}));else{if(!c.options.getSTS)return function(){var t="";if(c.options.StartTime&&e.Expires){if(10!==c.options.StartTime.toString().length)return s(o.error(new Error('params "StartTime" should be 10 digits')));t=c.options.StartTime+";"+(c.options.StartTime+1*e.Expires)}else if(c.options.StartTime&&c.options.ExpiredTime){if(10!==c.options.StartTime.toString().length)return s(o.error(new Error('params "StartTime" should be 10 digits')));if(10!==c.options.ExpiredTime.toString().length)return s(o.error(new Error('params "ExpiredTime" should be 10 digits')));t=c.options.StartTime+";"+1*c.options.ExpiredTime}var i={Authorization:o.getAuth({SecretId:e.SecretId||c.options.SecretId,SecretKey:e.SecretKey||c.options.SecretKey,Method:e.Method,Pathname:d,Query:e.Query,Headers:n,Expires:e.Expires,KeyTime:t,SystemClockOffset:c.options.SystemClockOffset,ForceSignHost:a}),SecurityToken:c.options.SecurityToken||c.options.XCosSecurityToken,SignFrom:"client"};return s(null,i),i}();c.options.getSTS.call(c,{Bucket:l,Region:p},(function(e){(f=e||{}).Scope=m,f.ScopeKey=v,f.TmpSecretId||(f.TmpSecretId=f.SecretId),f.TmpSecretKey||(f.TmpSecretKey=f.SecretKey);var t=x(f);if(t)return s(t);c._StsCache.push(f),y()}))}return""}function u(e){var t=this,n=!1,i=!1,a=!1,r=e.headers&&(e.headers.date||e.headers.Date)||e.error&&e.error.ServerTime;try{var s=e.error.Code,c=e.error.Message;("RequestTimeTooSkewed"===s||"AccessDenied"===s&&"Request has expired"===c)&&(a=!0)}catch(e){}if(e){if(a&&r){var l=Date.parse(r);this.options.CorrectClockSkew&&Math.abs(o.getSkewTime(this.options.SystemClockOffset)-l)>=3e4&&(this.options.SystemClockOffset=l-Date.now(),n=!0)}else{if(5===Math.floor(e.statusCode/100))return{canRetry:!0,networkError:!1};if("timeout"===e.message)return{canRetry:!0,networkError:t.options.AutoSwitchHost}}if(e.statusCode){var p=Math.floor(e.statusCode/100),u=(null==e?void 0:e.headers)&&(null==e?void 0:e.headers["x-cos-request-id"]);[3,4,5].includes(p)&&!u&&(n=t.options.AutoSwitchHost,i=!0)}else n=!0,i=t.options.AutoSwitchHost}return{canRetry:n,networkError:i}}function d(e){var t=e.requestUrl,n=e.clientCalcSign,i=e.networkError;if(!this.options.AutoSwitchHost)return!1;if(!t)return!1;if(!n)return!1;if(!i)return!1;return/^https?:\/\/[^\/]*\.cos\.[^\/]*\.myqcloud\.com(\/.*)?$/.test(t)&&!/^https?:\/\/[^\/]*\.cos\.accelerate\.myqcloud\.com(\/.*)?$/.test(t)}function f(e,t){var n=this;!e.headers&&(e.headers={}),!e.qs&&(e.qs={}),e.VersionId&&(e.qs.versionId=e.VersionId),e.qs=o.clearKey(e.qs),e.headers&&(e.headers=o.clearKey(e.headers)),e.qs&&(e.qs=o.clearKey(e.qs));var i=o.clone(e.qs);e.action&&(i[e.action]="");var a=e.url||e.Url,r=e.SignHost||l.call(this,{Bucket:e.Bucket,Region:e.Region,Url:a}),s=e.tracker;!function o(a){var c=n.options.SystemClockOffset;e.SwitchHost&&(r=r.replace(/myqcloud.com/,"tencentcos.cn")),s&&s.setParams({signStartTime:(new Date).getTime(),httpRetryTimes:a-1}),p.call(n,{Bucket:e.Bucket||"",Region:e.Region||"",Method:e.method,Key:e.Key,Query:i,Headers:e.headers,SignHost:r,Action:e.Action,ResourceKey:e.ResourceKey,Scope:e.Scope,ForceSignHost:n.options.ForceSignHost},(function(i,r){i?t(i):(s&&s.setParams({signEndTime:(new Date).getTime(),httpStartTime:(new Date).getTime()}),e.AuthData=r,m.call(n,e,(function(i,l){var p=!1,f=!1;if(i){var m=u.call(n,i);p=m.canRetry||c!==n.options.SystemClockOffset,f=m.networkError}if(s&&s.setParams({httpEndTime:(new Date).getTime()}),i&&a<4&&p){e.headers&&(delete e.headers.Authorization,delete e.headers.token,delete e.headers.clientIP,delete e.headers.clientUA,e.headers["x-cos-security-token"]&&delete e.headers["x-cos-security-token"],e.headers["x-ci-security-token"]&&delete e.headers["x-ci-security-token"]);var h=d.call(n,{requestUrl:(null==i?void 0:i.url)||"",clientCalcSign:"client"===(null==r?void 0:r.SignFrom),networkError:f});e.SwitchHost=h,e.headers["x-cos-sdk-retry"]="true",o(a+1)}else t(i,l)})))}))}(1)}function m(e,t){var n=this,a=e.TaskId;if(!a||n._isRunningTask(a)){var r=e.Bucket,s=e.Region,l=e.Key,p=e.method||"GET",u=e.url||e.Url,d=e.body,f=e.json,m=e.rawBody,h=e.dataType,g=n.options.HttpDNSServiceId;n.options.UseAccelerate&&(s="accelerate"),u=u||c({ForcePathStyle:n.options.ForcePathStyle,protocol:n.options.Protocol,domain:n.options.Domain,bucket:r,region:s,object:l}),e.SwitchHost&&(u=u.replace(/myqcloud.com/,"tencentcos.cn"));var v=l?u:"";e.action&&(u=u+"?"+e.action),e.qsStr&&(u=u.indexOf("?")>-1?u+"&"+e.qsStr:u+"?"+e.qsStr);var y={method:p,url:u,headers:e.headers,qs:e.qs,filePath:e.filePath,body:d,json:f,httpDNSServiceId:g,dataType:h},x="x-cos-security-token";o.isCIHost(u)&&(x="x-ci-security-token"),y.headers.Authorization=e.AuthData.Authorization,e.AuthData.Token&&(y.headers.token=e.AuthData.Token),e.AuthData.ClientIP&&(y.headers.clientIP=e.AuthData.ClientIP),e.AuthData.ClientUA&&(y.headers.clientUA=e.AuthData.ClientUA),e.AuthData.SecurityToken&&(y.headers[x]=e.AuthData.SecurityToken),y.headers&&(y.headers=o.clearKey(y.headers)),y=o.clearKey(y),e.onProgress&&"function"==typeof e.onProgress&&(y.onProgress=function(t){if(!a||n._isRunningTask(a)){var i=t?t.loaded:0;e.onProgress({loaded:i,total:t.total})}}),this.options.Timeout&&(y.timeout=this.options.Timeout),n.options.ForcePathStyle&&(y.pathStyle=n.options.ForcePathStyle),n.emit("before-send",y);var k,b=y.url.includes("accelerate."),C=y.qs?Object.keys(y.qs).map((function(e){return"".concat(e,"=").concat(y.qs[e])})).join("&"):"",S=C?y.url+"?"+C:y.url;if(e.tracker)e.tracker.setParams({url:S,httpMethod:y.method,accelerate:b,httpSize:(null===(k=y.body)||void 0===k?void 0:k.size)||0}),e.tracker.parent&&!e.tracker.parent.params.url&&e.tracker.parent.setParams({url:v,accelerate:b});var w=i(y,(function(e,i,r){if("abort"!==e){var s,c=function(e,r){if(a&&n.off("inner-kill-task",T),!s){s=!0;var c={};i&&i.statusCode&&(c.statusCode=i.statusCode),i&&i.headers&&(c.headers=i.headers),e?(y.url&&(c.url=y.url),y.method&&(c.method=y.method),e=o.extend(e||{},c),t(e,null)):(r=o.extend(r||{},c),t(null,r)),w=null}};if(e)c({error:e});else{var l=i.statusCode,p=2===Math.floor(l/100);if(m){if(p)return c(null,{body:r});if(r instanceof ArrayBuffer){var u=o.arrayBufferToString(r),d=o.parseResBody(u);return c({error:d.Error||d})}}var f=o.parseResBody(r);p?f.Error?c({error:f.Error}):c(null,f):c({error:f.Error||f})}}})),T=function e(t){t.TaskId===a&&(w&&w.abort&&w.abort(),n.off("inner-kill-task",e))};a&&n.on("inner-kill-task",T)}}var h={getService:function(e,t){"function"==typeof e&&(t=e,e={});var n="https:",i=this.options.ServiceDomain,a=e.Region;i?(i=i.replace(/\{\{Region\}\}/gi,a||"").replace(/\{\{.*?\}\}/gi,""),/^[a-zA-Z]+:\/\//.test(i)||(i=n+"//"+i),"/"===i.slice(-1)&&(i=i.slice(0,-1))):i=a?n+"//cos."+a+".myqcloud.com":n+"//service.cos.myqcloud.com";i.replace(/^https?:\/\/([^/]+)(\/.*)?$/,"$1"),f.call(this,{Action:"name/cos:GetService",url:i,method:"GET",headers:e.Headers,tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n&&n.ListAllMyBucketsResult&&n.ListAllMyBucketsResult.Buckets&&n.ListAllMyBucketsResult.Buckets.Bucket||[];i=o.isArray(i)?i:[i];var a=n&&n.ListAllMyBucketsResult&&n.ListAllMyBucketsResult.Owner||{};t(null,{Buckets:i,Owner:a,statusCode:n.statusCode,headers:n.headers})}))},putBucket:function(e,t){var n=this,i="";if(e.BucketAZConfig){var a={BucketAZConfig:e.BucketAZConfig};i=o.json2xml({CreateBucketConfiguration:a})}f.call(this,{Action:"name/cos:PutBucket",method:"PUT",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,body:i,tracker:e.tracker},(function(i,o){if(i)return t(i);var a=c({protocol:n.options.Protocol,domain:n.options.Domain,bucket:e.Bucket,region:e.Region,isLocation:!0});t(null,{Location:a,statusCode:o.statusCode,headers:o.headers})}))},headBucket:function(e,t){f.call(this,{Action:"name/cos:HeadBucket",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,method:"HEAD",tracker:e.tracker},(function(e,n){t(e,n)}))},getBucket:function(e,t){var n={};n.prefix=e.Prefix||"",n.delimiter=e.Delimiter,n.marker=e.Marker,n["max-keys"]=e.MaxKeys,n["encoding-type"]=e.EncodingType,f.call(this,{Action:"name/cos:GetBucket",ResourceKey:n.prefix,method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,qs:n,tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.ListBucketResult||{},a=i.Contents||[],r=i.CommonPrefixes||[];a=o.isArray(a)?a:[a],r=o.isArray(r)?r:[r];var s=o.clone(i);o.extend(s,{Contents:a,CommonPrefixes:r,statusCode:n.statusCode,headers:n.headers}),t(null,s)}))},deleteBucket:function(e,t){f.call(this,{Action:"name/cos:DeleteBucket",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,method:"DELETE",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketAcl:function(e,t){var n=e.Headers,i="";if(e.AccessControlPolicy){var a=o.clone(e.AccessControlPolicy||{}),r=a.Grants||a.Grant;r=o.isArray(r)?r:[r],delete a.Grant,delete a.Grants,a.AccessControlList={Grant:r},i=o.json2xml({AccessControlPolicy:a}),n["Content-Type"]="application/xml",n["Content-MD5"]=o.binaryBase64(o.md5(i))}o.each(n,(function(e,t){0===t.indexOf("x-cos-grant-")&&(n[t]=s(n[t]))})),f.call(this,{Action:"name/cos:PutBucketACL",method:"PUT",Bucket:e.Bucket,Region:e.Region,headers:n,action:"acl",body:i,tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketAcl:function(e,t){f.call(this,{Action:"name/cos:GetBucketACL",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"acl",tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.AccessControlPolicy||{},a=i.Owner||{},s=i.AccessControlList.Grant||[];s=o.isArray(s)?s:[s];var c=r(i);n.headers&&n.headers["x-cos-acl"]&&(c.ACL=n.headers["x-cos-acl"]),c=o.extend(c,{Owner:a,Grants:s,statusCode:n.statusCode,headers:n.headers}),t(null,c)}))},putBucketCors:function(e,t){var n=(e.CORSConfiguration||{}).CORSRules||e.CORSRules||[];n=o.clone(o.isArray(n)?n:[n]),o.each(n,(function(e){o.each(["AllowedOrigin","AllowedHeader","AllowedMethod","ExposeHeader"],(function(t){var n=t+"s",i=e[n]||e[t]||[];delete e[n],e[t]=o.isArray(i)?i:[i]}))}));var i={CORSRule:n};e.ResponseVary&&(i.ResponseVary=e.ResponseVary);var a=o.json2xml({CORSConfiguration:i}),r=e.Headers;r["Content-Type"]="application/xml",r["Content-MD5"]=o.binaryBase64(o.md5(a)),f.call(this,{Action:"name/cos:PutBucketCORS",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:a,action:"cors",headers:r,tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketCors:function(e,t){f.call(this,{Action:"name/cos:GetBucketCORS",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"cors",tracker:e.tracker},(function(e,n){if(e)if(404===e.statusCode&&e.error&&"NoSuchCORSConfiguration"===e.error.Code){var i={CORSRules:[],statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else t(e);else{var a=n.CORSConfiguration||{},r=a.CORSRules||a.CORSRule||[];r=o.clone(o.isArray(r)?r:[r]);var s=a.ResponseVary;o.each(r,(function(e){o.each(["AllowedOrigin","AllowedHeader","AllowedMethod","ExposeHeader"],(function(t){var n=t+"s",i=e[n]||e[t]||[];delete e[t],e[n]=o.isArray(i)?i:[i]}))})),t(null,{CORSRules:r,ResponseVary:s,statusCode:n.statusCode,headers:n.headers})}}))},deleteBucketCors:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketCORS",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"cors",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode||e.statusCode,headers:n.headers})}))},getBucketLocation:function(e,t){f.call(this,{Action:"name/cos:GetBucketLocation",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"location",tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,n)}))},getBucketPolicy:function(e,t){f.call(this,{Action:"name/cos:GetBucketPolicy",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"policy",rawBody:!0,tracker:e.tracker},(function(e,n){if(e)return e.statusCode&&403===e.statusCode?t({ErrorStatus:"Access Denied"}):e.statusCode&&405===e.statusCode?t({ErrorStatus:"Method Not Allowed"}):e.statusCode&&404===e.statusCode?t({ErrorStatus:"Policy Not Found"}):t(e);var i={};try{i=JSON.parse(n.body)}catch(e){}t(null,{Policy:i,statusCode:n.statusCode,headers:n.headers})}))},putBucketPolicy:function(e,t){var n=e.Policy,i=n;try{"string"==typeof n?n=JSON.parse(i):i=JSON.stringify(n)}catch(e){t({error:"Policy format error"})}var a=e.Headers;a["Content-Type"]="application/json",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketPolicy",method:"PUT",Bucket:e.Bucket,Region:e.Region,action:"policy",body:i,headers:a,json:!0,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},deleteBucketPolicy:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketPolicy",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"policy",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode||e.statusCode,headers:n.headers})}))},putBucketTagging:function(e,t){var n=e.Tagging||{},i=n.TagSet||n.Tags||e.Tags||[];i=o.clone(o.isArray(i)?i:[i]);var a=o.json2xml({Tagging:{TagSet:{Tag:i}}}),r=e.Headers;r["Content-Type"]="application/xml",r["Content-MD5"]=o.binaryBase64(o.md5(a)),f.call(this,{Action:"name/cos:PutBucketTagging",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:a,action:"tagging",headers:r,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketTagging:function(e,t){f.call(this,{Action:"name/cos:GetBucketTagging",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"tagging",tracker:e.tracker},(function(e,n){if(e)if(404!==e.statusCode||!e.error||"Not Found"!==e.error&&"NoSuchTagSet"!==e.error.Code)t(e);else{var i={Tags:[],statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else{var a=[];try{a=n.Tagging.TagSet.Tag||[]}catch(e){}a=o.clone(o.isArray(a)?a:[a]),t(null,{Tags:a,statusCode:n.statusCode,headers:n.headers})}}))},deleteBucketTagging:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketTagging",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"tagging",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketLifecycle:function(e,t){var n=(e.LifecycleConfiguration||{}).Rules||e.Rules||[];n=o.clone(n);var i=o.json2xml({LifecycleConfiguration:{Rule:n}}),a=e.Headers;a["Content-Type"]="application/xml",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketLifecycle",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"lifecycle",headers:a,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketLifecycle:function(e,t){f.call(this,{Action:"name/cos:GetBucketLifecycle",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"lifecycle",tracker:e.tracker},(function(e,n){if(e)if(404===e.statusCode&&e.error&&"NoSuchLifecycleConfiguration"===e.error.Code){var i={Rules:[],statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else t(e);else{var a=[];try{a=n.LifecycleConfiguration.Rule||[]}catch(e){}a=o.clone(o.isArray(a)?a:[a]),t(null,{Rules:a,statusCode:n.statusCode,headers:n.headers})}}))},deleteBucketLifecycle:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketLifecycle",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"lifecycle",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketVersioning:function(e,t){if(e.VersioningConfiguration){var n=e.VersioningConfiguration||{},i=o.json2xml({VersioningConfiguration:n}),a=e.Headers;a["Content-Type"]="application/xml",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketVersioning",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"versioning",headers:a,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))}else t({error:"missing param VersioningConfiguration"})},getBucketVersioning:function(e,t){f.call(this,{Action:"name/cos:GetBucketVersioning",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"versioning",tracker:e.tracker},(function(e,n){e||!n.VersioningConfiguration&&(n.VersioningConfiguration={}),t(e,n)}))},putBucketReplication:function(e,t){var n=o.clone(e.ReplicationConfiguration),i=o.json2xml({ReplicationConfiguration:n});i=(i=i.replace(/<(\/?)Rules>/gi,"<$1Rule>")).replace(/<(\/?)Tags>/gi,"<$1Tag>");var a=e.Headers;a["Content-Type"]="application/xml",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketReplication",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"replication",headers:a,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketReplication:function(e,t){f.call(this,{Action:"name/cos:GetBucketReplication",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"replication",tracker:e.tracker},(function(e,n){if(e)if(404!==e.statusCode||!e.error||"Not Found"!==e.error&&"ReplicationConfigurationnotFoundError"!==e.error.Code)t(e);else{var i={ReplicationConfiguration:{Rules:[]},statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else e||!n.ReplicationConfiguration&&(n.ReplicationConfiguration={}),n.ReplicationConfiguration.Rule&&(n.ReplicationConfiguration.Rules=n.ReplicationConfiguration.Rule,delete n.ReplicationConfiguration.Rule),t(e,n)}))},deleteBucketReplication:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketReplication",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"replication",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketWebsite:function(e,t){if(e.WebsiteConfiguration){var n=o.clone(e.WebsiteConfiguration||{}),i=n.RoutingRules||n.RoutingRule||[];i=o.isArray(i)?i:[i],delete n.RoutingRule,delete n.RoutingRules,i.length&&(n.RoutingRules={RoutingRule:i});var a=o.json2xml({WebsiteConfiguration:n}),r=e.Headers;r["Content-Type"]="application/xml",r["Content-MD5"]=o.binaryBase64(o.md5(a)),f.call(this,{Action:"name/cos:PutBucketWebsite",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:a,action:"website",headers:r,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))}else t({error:"missing param WebsiteConfiguration"})},getBucketWebsite:function(e,t){f.call(this,{Action:"name/cos:GetBucketWebsite",method:"GET",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,action:"website",tracker:e.tracker},(function(e,n){if(e)if(404===e.statusCode&&"NoSuchWebsiteConfiguration"===e.error.Code){var i={WebsiteConfiguration:{},statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else t(e);else{var a=n.WebsiteConfiguration||{};if(a.RoutingRules){var r=o.clone(a.RoutingRules.RoutingRule||[]);r=o.makeArray(r),a.RoutingRules=r}t(null,{WebsiteConfiguration:a,statusCode:n.statusCode,headers:n.headers})}}))},deleteBucketWebsite:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketWebsite",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"website",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketReferer:function(e,t){if(e.RefererConfiguration){var n=o.clone(e.RefererConfiguration||{}),i=n.DomainList||{},a=i.Domains||i.Domain||[];(a=o.isArray(a)?a:[a]).length&&(n.DomainList={Domain:a});var r=o.json2xml({RefererConfiguration:n}),s=e.Headers;s["Content-Type"]="application/xml",s["Content-MD5"]=o.binaryBase64(o.md5(r)),f.call(this,{Action:"name/cos:PutBucketReferer",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:r,action:"referer",headers:s,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))}else t({error:"missing param RefererConfiguration"})},getBucketReferer:function(e,t){f.call(this,{Action:"name/cos:GetBucketReferer",method:"GET",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,action:"referer",tracker:e.tracker},(function(e,n){if(e)if(404===e.statusCode&&"NoSuchRefererConfiguration"===e.error.Code){var i={WebsiteConfiguration:{},statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else t(e);else{var a=n.RefererConfiguration||{};if(a.DomainList){var r=o.makeArray(a.DomainList.Domain||[]);a.DomainList={Domains:r}}t(null,{RefererConfiguration:a,statusCode:n.statusCode,headers:n.headers})}}))},putBucketDomain:function(e,t){var n=(e.DomainConfiguration||{}).DomainRule||e.DomainRule||[];n=o.clone(n);var i=o.json2xml({DomainConfiguration:{DomainRule:n}}),a=e.Headers;a["Content-Type"]="application/xml",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketDomain",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"domain",headers:a,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketDomain:function(e,t){f.call(this,{Action:"name/cos:GetBucketDomain",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"domain",tracker:e.tracker},(function(e,n){if(e)return t(e);var i=[];try{i=n.DomainConfiguration.DomainRule||[]}catch(e){}i=o.clone(o.isArray(i)?i:[i]),t(null,{DomainRule:i,statusCode:n.statusCode,headers:n.headers})}))},deleteBucketDomain:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketDomain",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"domain",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketOrigin:function(e,t){var n=(e.OriginConfiguration||{}).OriginRule||e.OriginRule||[];n=o.clone(n);var i=o.json2xml({OriginConfiguration:{OriginRule:n}}),a=e.Headers;a["Content-Type"]="application/xml",a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Action:"name/cos:PutBucketOrigin",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"origin",headers:a,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketOrigin:function(e,t){f.call(this,{Action:"name/cos:GetBucketOrigin",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"origin",tracker:e.tracker},(function(e,n){if(e)return t(e);var i=[];try{i=n.OriginConfiguration.OriginRule||[]}catch(e){}i=o.clone(o.isArray(i)?i:[i]),t(null,{OriginRule:i,statusCode:n.statusCode,headers:n.headers})}))},deleteBucketOrigin:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketOrigin",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"origin",tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketLogging:function(e,t){var n=o.json2xml({BucketLoggingStatus:e.BucketLoggingStatus||""}),i=e.Headers;i["Content-Type"]="application/xml",i["Content-MD5"]=o.binaryBase64(o.md5(n)),f.call(this,{Action:"name/cos:PutBucketLogging",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:n,action:"logging",headers:i,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketLogging:function(e,t){f.call(this,{Action:"name/cos:GetBucketLogging",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"logging",tracker:e.tracker},(function(e,n){if(e)return t(e);delete n.BucketLoggingStatus._xmlns,t(null,{BucketLoggingStatus:n.BucketLoggingStatus,statusCode:n.statusCode,headers:n.headers})}))},putBucketInventory:function(e,t){var n=o.clone(e.InventoryConfiguration);if(n.OptionalFields){var i=n.OptionalFields||[];n.OptionalFields={Field:i}}if(n.Destination&&n.Destination.COSBucketDestination&&n.Destination.COSBucketDestination.Encryption){var a=n.Destination.COSBucketDestination.Encryption;Object.keys(a).indexOf("SSECOS")>-1&&(a["SSE-COS"]=a.SSECOS,delete a.SSECOS)}var r=o.json2xml({InventoryConfiguration:n}),s=e.Headers;s["Content-Type"]="application/xml",s["Content-MD5"]=o.binaryBase64(o.md5(r)),f.call(this,{Action:"name/cos:PutBucketInventory",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:r,action:"inventory",qs:{id:e.Id},headers:s,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getBucketInventory:function(e,t){f.call(this,{Action:"name/cos:GetBucketInventory",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"inventory",qs:{id:e.Id},tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.InventoryConfiguration;if(i&&i.OptionalFields&&i.OptionalFields.Field){var a=i.OptionalFields.Field;o.isArray(a)||(a=[a]),i.OptionalFields=a}if(i.Destination&&i.Destination.COSBucketDestination&&i.Destination.COSBucketDestination.Encryption){var r=i.Destination.COSBucketDestination.Encryption;Object.keys(r).indexOf("SSE-COS")>-1&&(r.SSECOS=r["SSE-COS"],delete r["SSE-COS"])}t(null,{InventoryConfiguration:i,statusCode:n.statusCode,headers:n.headers})}))},listBucketInventory:function(e,t){f.call(this,{Action:"name/cos:ListBucketInventory",method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"inventory",qs:{"continuation-token":e.ContinuationToken},tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.ListInventoryConfigurationResult,a=i.InventoryConfiguration||[];a=o.isArray(a)?a:[a],delete i.InventoryConfiguration,o.each(a,(function(e){if(e&&e.OptionalFields&&e.OptionalFields.Field){var t=e.OptionalFields.Field;o.isArray(t)||(t=[t]),e.OptionalFields=t}if(e.Destination&&e.Destination.COSBucketDestination&&e.Destination.COSBucketDestination.Encryption){var n=e.Destination.COSBucketDestination.Encryption;Object.keys(n).indexOf("SSE-COS")>-1&&(n.SSECOS=n["SSE-COS"],delete n["SSE-COS"])}})),i.InventoryConfigurations=a,o.extend(i,{statusCode:n.statusCode,headers:n.headers}),t(null,i)}))},deleteBucketInventory:function(e,t){f.call(this,{Action:"name/cos:DeleteBucketInventory",method:"DELETE",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"inventory",qs:{id:e.Id},tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},putBucketAccelerate:function(e,t){if(e.AccelerateConfiguration){var n={AccelerateConfiguration:e.AccelerateConfiguration||{}},i=o.json2xml(n),a={"Content-Type":"application/xml"};a["Content-MD5"]=o.binaryBase64(o.md5(i)),f.call(this,{Interface:"putBucketAccelerate",Action:"name/cos:PutBucketAccelerate",method:"PUT",Bucket:e.Bucket,Region:e.Region,body:i,action:"accelerate",headers:a,tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,{statusCode:n.statusCode,headers:n.headers})}))}else t({error:"missing param AccelerateConfiguration"})},getBucketAccelerate:function(e,t){f.call(this,{Interface:"getBucketAccelerate",Action:"name/cos:GetBucketAccelerate",method:"GET",Bucket:e.Bucket,Region:e.Region,action:"accelerate",tracker:e.tracker},(function(e,n){e||!n.AccelerateConfiguration&&(n.AccelerateConfiguration={}),t(e,n)}))},getObject:function(e,t){if(this.options.ObjectKeySimplifyCheck&&"/"===o.simplifyPath(e.Key))return void t(o.error(new Error("The Getobject Key is illegal")));var n=e.Query||{},i=e.QueryString||"",a=e.tracker;a&&a.setParams({signStartTime:(new Date).getTime()}),n["response-content-type"]=e.ResponseContentType,n["response-content-language"]=e.ResponseContentLanguage,n["response-expires"]=e.ResponseExpires,n["response-cache-control"]=e.ResponseCacheControl,n["response-content-disposition"]=e.ResponseContentDisposition,n["response-content-encoding"]=e.ResponseContentEncoding,f.call(this,{Action:"name/cos:GetObject",method:"GET",Bucket:e.Bucket,Region:e.Region,Key:e.Key,VersionId:e.VersionId,headers:e.Headers,qs:n,qsStr:i,rawBody:!0,dataType:e.DataType,tracker:a},(function(n,i){if(n){var a=n.statusCode;return e.Headers["If-Modified-Since"]&&a&&304===a?t(null,{NotModified:!0}):t(n)}t(null,{Body:i.body,ETag:o.attr(i.headers,"etag",""),statusCode:i.statusCode,headers:i.headers})}))},headObject:function(e,t){f.call(this,{Action:"name/cos:HeadObject",method:"HEAD",Bucket:e.Bucket,Region:e.Region,Key:e.Key,VersionId:e.VersionId,headers:e.Headers,tracker:e.tracker},(function(n,i){if(n){var a=n.statusCode;return e.Headers["If-Modified-Since"]&&a&&304===a?t(null,{NotModified:!0,statusCode:a}):t(n)}i.ETag=o.attr(i.headers,"etag",""),t(null,i)}))},listObjectVersions:function(e,t){var n={};n.prefix=e.Prefix||"",n.delimiter=e.Delimiter,n["key-marker"]=e.KeyMarker,n["version-id-marker"]=e.VersionIdMarker,n["max-keys"]=e.MaxKeys,n["encoding-type"]=e.EncodingType,f.call(this,{Action:"name/cos:GetBucketObjectVersions",ResourceKey:n.prefix,method:"GET",Bucket:e.Bucket,Region:e.Region,headers:e.Headers,qs:n,action:"versions",tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.ListVersionsResult||{},a=i.DeleteMarker||[];a=o.isArray(a)?a:[a];var r=i.Version||[];r=o.isArray(r)?r:[r];var s=o.clone(i);delete s.DeleteMarker,delete s.Version,o.extend(s,{DeleteMarkers:a,Versions:r,statusCode:n.statusCode,headers:n.headers}),t(null,s)}))},putObject:function(e,t){var n=this,i=e.ContentLength,r=o.throttleOnProgress.call(n,i,e.onProgress),s=e.Headers;s["Cache-Control"]||s["cache-control"]||(s["Cache-Control"]=""),s["Content-Type"]||s["content-type"]||(s["Content-Type"]=a.getType(e.Key)||"application/octet-stream");var l=e.UploadAddMetaMd5||n.options.UploadAddMetaMd5||n.options.UploadCheckContentMd5,p=e.tracker;l&&p&&p.setParams({md5StartTime:(new Date).getTime()}),o.getBodyMd5(l,e.Body,(function(a){a&&(p&&p.setParams({md5EndTime:(new Date).getTime()}),n.options.UploadCheckContentMd5&&(s["Content-MD5"]=o.binaryBase64(a)),(e.UploadAddMetaMd5||n.options.UploadAddMetaMd5)&&(s["x-cos-meta-md5"]=a)),void 0!==e.ContentLength&&(s["Content-Length"]=e.ContentLength),r(null,!0),f.call(n,{Action:"name/cos:PutObject",TaskId:e.TaskId,method:"PUT",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,qs:e.Query,body:e.Body,onProgress:r,tracker:p},(function(a,s){if(a)return r(null,!0),t(a);r({loaded:i,total:i},!0);var l=c({ForcePathStyle:n.options.ForcePathStyle,protocol:n.options.Protocol,domain:n.options.Domain,bucket:e.Bucket,region:n.options.UseAccelerate?"accelerate":e.Region,object:e.Key});l=l.substr(l.indexOf("://")+3),s.Location=l,s.ETag=o.attr(s.headers,"etag",""),t(null,s)}))}))},postObject:function(e,t){var n=this,i={},a=e.FilePath;if(a){for(var r in i["Cache-Control"]=e.CacheControl,i["Content-Disposition"]=e.ContentDisposition,i["Content-Encoding"]=e.ContentEncoding,i["Content-MD5"]=e.ContentMD5,i["Content-Length"]=e.ContentLength,i["Content-Type"]=e.ContentType,i.Expect=e.Expect,i.Expires=e.Expires,i["x-cos-acl"]=e.ACL,i["x-cos-grant-read"]=e.GrantRead,i["x-cos-grant-write"]=e.GrantWrite,i["x-cos-grant-full-control"]=e.GrantFullControl,i["x-cos-storage-class"]=e.StorageClass,i["x-cos-mime-limit"]=e.MimeLimit,i["x-cos-traffic-limit"]=e.TrafficLimit,i["x-cos-forbid-overwrite"]=e.ForbidOverwrite,i["x-cos-server-side-encryption-customer-algorithm"]=e.SSECustomerAlgorithm,i["x-cos-server-side-encryption-customer-key"]=e.SSECustomerKey,i["x-cos-server-side-encryption-customer-key-MD5"]=e.SSECustomerKeyMD5,i["x-cos-server-side-encryption"]=e.ServerSideEncryption,i["x-cos-server-side-encryption-cos-kms-key-id"]=e.SSEKMSKeyId,i["x-cos-server-side-encryption-context"]=e.SSEContext,delete i["Content-Length"],delete i["content-length"],e)r.indexOf("x-cos-meta-")>-1&&(i[r]=e[r]);var s=o.throttleOnProgress.call(n,i["Content-Length"],e.onProgress);f.call(this,{Action:"name/cos:PostObject",method:"POST",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:i,qs:e.Query,filePath:a,TaskId:e.TaskId,onProgress:s,tracker:e.tracker},(function(i,o){if(s(null,!0),i)return t(i);if(o&&o.headers){var r=o.headers,l=r.etag||r.Etag||r.ETag||"",p=a.substr(a.lastIndexOf("/")+1),u=c({ForcePathStyle:n.options.ForcePathStyle,protocol:n.options.Protocol,domain:n.options.Domain,bucket:e.Bucket,region:e.Region,object:e.Key.replace(/\$\{filename\}/g,p),isLocation:!0});return t(null,{Location:u,statusCode:o.statusCode,headers:r,ETag:l})}t(null,o)}))}else t({error:"missing param FilePath"})},deleteObject:function(e,t){f.call(this,{Action:"name/cos:DeleteObject",method:"DELETE",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,VersionId:e.VersionId,tracker:e.tracker},(function(e,n){if(e){var i=e.statusCode;return i&&204===i?t(null,{statusCode:i}):i&&404===i?t(null,{BucketNotFound:!0,statusCode:i}):t(e)}t(null,{statusCode:n.statusCode,headers:n.headers})}))},getObjectAcl:function(e,t){var n={};e.VersionId&&(n.versionId=e.VersionId),f.call(this,{Action:"name/cos:GetObjectACL",method:"GET",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,qs:n,action:"acl",tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.AccessControlPolicy||{},a=i.Owner||{},s=i.AccessControlList&&i.AccessControlList.Grant||[];s=o.isArray(s)?s:[s];var c=r(i);n.headers&&n.headers["x-cos-acl"]&&(c.ACL=n.headers["x-cos-acl"]),c=o.extend(c,{Owner:a,Grants:s,statusCode:n.statusCode,headers:n.headers}),t(null,c)}))},putObjectAcl:function(e,t){var n=e.Headers,i="";if(e.AccessControlPolicy){var a=o.clone(e.AccessControlPolicy||{}),r=a.Grants||a.Grant;r=o.isArray(r)?r:[r],delete a.Grant,delete a.Grants,a.AccessControlList={Grant:r},i=o.json2xml({AccessControlPolicy:a}),n["Content-Type"]="application/xml",n["Content-MD5"]=o.binaryBase64(o.md5(i))}o.each(n,(function(e,t){0===t.indexOf("x-cos-grant-")&&(n[t]=s(n[t]))})),f.call(this,{Action:"name/cos:PutObjectACL",method:"PUT",Bucket:e.Bucket,Region:e.Region,Key:e.Key,action:"acl",headers:n,body:i,tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,{statusCode:n.statusCode,headers:n.headers})}))},optionsObject:function(e,t){var n=e.Headers;n.Origin=e.Origin,n["Access-Control-Request-Method"]=e.AccessControlRequestMethod,n["Access-Control-Request-Headers"]=e.AccessControlRequestHeaders,f.call(this,{Action:"name/cos:OptionsObject",method:"OPTIONS",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:n,tracker:e.tracker},(function(e,n){if(e)return e.statusCode&&403===e.statusCode?t(null,{OptionsForbidden:!0,statusCode:e.statusCode}):t(e);var i=n.headers||{};t(null,{AccessControlAllowOrigin:i["access-control-allow-origin"],AccessControlAllowMethods:i["access-control-allow-methods"],AccessControlAllowHeaders:i["access-control-allow-headers"],AccessControlExposeHeaders:i["access-control-expose-headers"],AccessControlMaxAge:i["access-control-max-age"],statusCode:n.statusCode,headers:n.headers})}))},putObjectCopy:function(e,t){var n=e.Headers;!n["Cache-Control"]&&n["cache-control"]&&(n["Cache-Control"]="");var i=e.CopySource||"",a=o.getSourceParams.call(this,i);if(a){var r=a.Bucket,s=a.Region,c=decodeURIComponent(a.Key);f.call(this,{Scope:[{action:"name/cos:GetObject",bucket:r,region:s,prefix:c},{action:"name/cos:PutObject",bucket:e.Bucket,region:e.Region,prefix:e.Key}],method:"PUT",Bucket:e.Bucket,Region:e.Region,Key:e.Key,VersionId:e.VersionId,headers:e.Headers,tracker:e.tracker},(function(e,n){if(e)return t(e);var i=o.clone(n.CopyObjectResult||{});o.extend(i,{statusCode:n.statusCode,headers:n.headers}),t(null,i)}))}else t({error:"CopySource format error"})},deleteMultipleObject:function(e,t){var n=e.Objects||[],i=e.Quiet;n=o.isArray(n)?n:[n];var a=o.json2xml({Delete:{Object:n,Quiet:i||!1}}),r=e.Headers;r["Content-Type"]="application/xml",r["Content-MD5"]=o.binaryBase64(o.md5(a));var s=o.map(n,(function(t){return{action:"name/cos:DeleteObject",bucket:e.Bucket,region:e.Region,prefix:t.Key}}));f.call(this,{Scope:s,method:"POST",Bucket:e.Bucket,Region:e.Region,body:a,action:"delete",headers:r,tracker:e.tracker},(function(e,n){if(e)return t(e);var i=n.DeleteResult||{},a=i.Deleted||[],r=i.Error||[];a=o.isArray(a)?a:[a],r=o.isArray(r)?r:[r];var s=o.clone(i);o.extend(s,{Error:r,Deleted:a,statusCode:n.statusCode,headers:n.headers}),t(null,s)}))},restoreObject:function(e,t){var n=e.Headers;if(e.RestoreRequest){var i=e.RestoreRequest||{},a=o.json2xml({RestoreRequest:i});n["Content-Type"]="application/xml",n["Content-MD5"]=o.binaryBase64(o.md5(a)),f.call(this,{Action:"name/cos:RestoreObject",method:"POST",Bucket:e.Bucket,Region:e.Region,Key:e.Key,VersionId:e.VersionId,body:a,action:"restore",headers:n,tracker:e.tracker},(function(e,n){t(e,n)}))}else t({error:"missing param RestoreRequest"})},putObjectTagging:function(e,t){var n=e.Tagging||{},i=n.TagSet||n.Tags||e.Tags||[];i=o.clone(o.isArray(i)?i:[i]);var a=o.json2xml({Tagging:{TagSet:{Tag:i}}}),r=e.Headers;r["Content-Type"]="application/xml",r["Content-MD5"]=o.binaryBase64(o.md5(a)),f.call(this,{Interface:"putObjectTagging",Action:"name/cos:PutObjectTagging",method:"PUT",Bucket:e.Bucket,Key:e.Key,Region:e.Region,body:a,action:"tagging",headers:r,VersionId:e.VersionId,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},getObjectTagging:function(e,t){f.call(this,{Interface:"getObjectTagging",Action:"name/cos:GetObjectTagging",method:"GET",Key:e.Key,Bucket:e.Bucket,Region:e.Region,headers:e.Headers,action:"tagging",VersionId:e.VersionId,tracker:e.tracker},(function(e,n){if(e)if(404!==e.statusCode||!e.error||"Not Found"!==e.error&&"NoSuchTagSet"!==e.error.Code)t(e);else{var i={Tags:[],statusCode:e.statusCode};e.headers&&(i.headers=e.headers),t(null,i)}else{var a=[];try{a=n.Tagging.TagSet.Tag||[]}catch(e){}a=o.clone(o.isArray(a)?a:[a]),t(null,{Tags:a,statusCode:n.statusCode,headers:n.headers})}}))},deleteObjectTagging:function(e,t){f.call(this,{Interface:"deleteObjectTagging",Action:"name/cos:DeleteObjectTagging",method:"DELETE",Bucket:e.Bucket,Region:e.Region,Key:e.Key,headers:e.Headers,action:"tagging",VersionId:e.VersionId,tracker:e.tracker},(function(e,n){return e&&204===e.statusCode?t(null,{statusCode:e.statusCode}):e?t(e):void t(null,{statusCode:n.statusCode,headers:n.headers})}))},appendObject:function(e,t){f.call(this,{Action:"name/cos:AppendObject",method:"POST",Bucket:e.Bucket,Region:e.Region,action:"append",Key:e.Key,body:e.Body,qs:{position:e.Position},headers:e.Headers,tracker:e.tracker},(function(e,n){if(e)return t(e);t(null,n)}))},uploadPartCopy:function(e,t){var n=e.CopySource||"",i=o.getSourceParams.call(this,n);if(i){var a=i.Bucket,r=i.Region,s=decodeURIComponent(i.Key);f.call(this,{Scope:[{action:"name/cos:GetObject",bucket:a,region:r,prefix:s},{action:"name/cos:PutObject",bucket:e.Bucket,region:e.Region,prefix:e.Key}],method:"PUT",Bucket:e.Bucket,Region:e.Region,Key:e.Key,VersionId:e.VersionId,qs:{partNumber:e.PartNumber,uploadId:e.UploadId},headers:e.Headers,tracker:e.tracker},(function(e,n){if(e)return t(e);var i=o.clone(n.CopyPartResult||{});o.extend(i,{statusCode:n.statusCode,headers:n.headers}),t(null,i)}))}else t({error:"CopySource format error"})},multipartInit:function(e,t){var n=e.Headers,i=e.tracker;n["Cache-Control"]||n["cache-control"]||(n["Cache-Control"]=""),n["Content-Type"]||n["content-type"]||(n["Content-Type"]=a.getType(e.Key)||"application/octet-stream"),f.call(this,{Action:"name/cos:InitiateMultipartUpload",method:"POST",Bucket:e.Bucket,Region:e.Region,Key:e.Key,action:"uploads",headers:e.Headers,qs:e.Query,tracker:i},(function(e,n){return e?(i&&i.parent&&i.parent.setParams({errorNode:"multipartInit"}),t(e)):(n=o.clone(n||{}))&&n.InitiateMultipartUploadResult?t(null,o.extend(n.InitiateMultipartUploadResult,{statusCode:n.statusCode,headers:n.headers})):void t(null,n)}))},multipartUpload:function(e,t){var n=this;o.getFileSize("multipartUpload",e,(function(){var i=e.tracker,a=n.options.UploadCheckContentMd5;a&&i&&i.setParams({md5StartTime:(new Date).getTime()}),o.getBodyMd5(a,e.Body,(function(r){r&&(e.Headers["Content-MD5"]=o.binaryBase64(r),a&&i&&i.setParams({md5EndTime:(new Date).getTime()})),i&&i.setParams({partNumber:e.PartNumber}),f.call(n,{Action:"name/cos:UploadPart",TaskId:e.TaskId,method:"PUT",Bucket:e.Bucket,Region:e.Region,Key:e.Key,qs:{partNumber:e.PartNumber,uploadId:e.UploadId},headers:e.Headers,onProgress:e.onProgress,body:e.Body||null,tracker:i},(function(e,n){if(e)return i&&i.parent&&i.parent.setParams({errorNode:"multipartUpload"}),t(e);t(null,{ETag:o.attr(n.headers,"etag",{}),statusCode:n.statusCode,headers:n.headers})}))}))}))},multipartComplete:function(e,t){for(var n=this,i=e.UploadId,a=e.Parts,r=e.tracker,s=0,l=a.length;s-1?function(e){var t=e.match(/q-url-param-list.*?(?=&)/g)[0],n="q-url-param-list="+encodeURIComponent(t.replace(/q-url-param-list=/,"")).toLowerCase(),i=new RegExp(t,"g");return e.replace(i,n)}(n.Authorization):"sign="+encodeURIComponent(n.Authorization)),n.SecurityToken&&(i+="&x-cos-security-token="+n.SecurityToken),n.ClientIP&&(i+="&clientIP="+n.ClientIP),n.ClientUA&&(i+="&clientUA="+n.ClientUA),n.Token&&(i+="&token="+n.Token),r&&(i+="&"+r),setTimeout((function(){t(null,{Url:i})}))}}));return d?(s+="?"+d.Authorization+(d.SecurityToken?"&x-cos-security-token="+d.SecurityToken:""),r&&(s+="&"+r)):r&&(s+="?"+r),s},getAuth:function(e){return o.getAuth({SecretId:e.SecretId||this.options.SecretId||"",SecretKey:e.SecretKey||this.options.SecretKey||"",Bucket:e.Bucket,Region:e.Region,Method:e.Method,Key:e.Key,Query:e.Query,Headers:e.Headers,Expires:e.Expires,SystemClockOffset:this.options.SystemClockOffset})}};e.exports.init=function(e,t){t.transferToTaskMethod(h,"postObject"),t.transferToTaskMethod(h,"putObject"),o.each(h,(function(t,n){e.prototype[n]=o.apiWrapper(n,t)}))}},function(e,t){function n(e){return encodeURIComponent(e).replace(/!/g,"%21").replace(/'/g,"%27").replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/\*/g,"%2A")}var i=function(e,t){var i,o,a,r=[],s=function(e,t){var i=[];for(var o in e)e.hasOwnProperty(o)&&i.push(t?n(o).toLowerCase():o);return i.sort((function(e,t){return(e=e.toLowerCase())===(t=t.toLowerCase())?0:e>t?1:-1}))}(e);for(i=0;i-1||m.indexOf(h)>-1)&&(f[h]=e.headers[h]);a["x-cos-acl"]&&(f.acl=a["x-cos-acl"]),!f["Content-Type"]&&(f["Content-Type"]=""),(n=wx.uploadFile({url:r,method:s,name:"file",header:a,filePath:o,formData:f,timeout:e.timeout,success:function(e){p(null,e)},fail:function(e){p(e.errMsg,e)}})).onProgressUpdate((function(e){c&&c({loaded:e.totalBytesSent,total:e.totalBytesExpectedToSend,progress:e.progress/100})}))}else{var g=e.qs&&i(e.qs)||"";g&&(r+=(r.indexOf("?")>-1?"&":"?")+g),a["Content-Length"]&&delete a["Content-Length"];var v={url:r,method:s,header:a,dataType:"text",data:e.body,responseType:e.dataType||"text",timeout:e.timeout,redirect:"manual",success:function(e){p(null,e)},fail:function(e){p(e.errMsg,e)}};l&&Object.assign(v,{enableHttpDNS:!0,httpDNSServiceId:l}),n=wx.request(v)}return n}},function(e,t,n){"use strict";let i=n(29);e.exports=new i(n(30),n(31))},function(e,t,n){"use strict";function i(){this._types=Object.create(null),this._extensions=Object.create(null);for(let e=0;e=0;--o){var r=this.tryEntries[o],s=r.completion;if("root"===r.tryLoc)return i("end");if(r.tryLoc<=this.prev){var c=a.call(r,"catchLoc"),l=a.call(r,"finallyLoc");if(c&&l){if(this.prev=0;--n){var i=this.tryEntries[n];if(i.tryLoc<=this.prev&&a.call(i,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),O(n),y}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var i=n.completion;if("throw"===i.type){var o=i.arg;O(n)}return o}}throw Error("illegal catch attempt")},delegateYield:function(t,n,i){return this.delegate={iterator:I(t),resultName:n,nextLoc:i},"next"===this.method&&(this.arg=e),y}},t}function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}function a(e,t,n,i,o,a,r){try{var s=e[a](r),c=s.value}catch(e){return void n(e)}s.done?t(c):Promise.resolve(c).then(i,o)}function r(e){return function(){var t=this,n=arguments;return new Promise((function(i,o){var r=e.apply(t,n);function s(e){a(r,i,o,s,c,"next",e)}function c(e){a(r,i,o,s,c,"throw",e)}s(void 0)}))}}var s=n(7),c=n(33),l=n(6).EventProxy,p=n(0),u=n(2);function d(e,t){var n=e.TaskId,i=e.Bucket,o=e.Region,a=e.Key,r=e.StorageClass,u=this,d={},h=e.FileSize,g=e.SliceSize,v=Math.ceil(h/g),y=0,x=p.throttleOnProgress.call(u,h,e.onHashProgress),k=function(t,n){var i=t.length;if(0===i)return n(null,!0);if(i>v)return n(null,!1);if(i>1&&Math.max(t[0].Size,t[1].Size)!==g)return n(null,!1);!function o(a){if(a=c.length)b.emit("has_and_check_upload_id",t);else{var d=c[l];if(!p.isInArray(t,d))return s.removeUploadId(d),void r(l+1);s.using[d]?r(l+1):m.call(u,{Bucket:i,Region:o,Key:a,UploadId:d,tracker:e.tracker},(function(e,t){u._isRunningTask(n)&&(e?(s.removeUploadId(d),r(l+1)):b.emit("upload_id_available",{UploadId:d,PartList:t.PartList}))}))}}(0)}else b.emit("has_and_check_upload_id",t)})),b.on("get_remote_upload_id_list",(function(){f.call(u,{Bucket:i,Region:o,Key:a,tracker:e.tracker},(function(t,o){if(u._isRunningTask(n)){if(t)return b.emit("error",t);var c=p.filter(o.UploadList,(function(e){return e.Key===a&&(!r||e.StorageClass.toUpperCase()===r.toUpperCase())})).reverse().map((function(e){return e.UploadId||e.UploadID}));if(c.length)b.emit("seek_local_avail_upload_id",c);else{var l,d=s.getFileId(e.FileStat,e.ChunkSize,i,a);d&&(l=s.getUploadIdList(d))&&p.each(l,(function(e){s.removeUploadId(e)})),b.emit("no_available_upload_id")}}}))})),b.emit("get_remote_upload_id_list")}function f(e,t){var n=this,i=[],o={Bucket:e.Bucket,Region:e.Region,Prefix:e.Key,calledBySdk:e.calledBySdk||"sliceUploadFile",tracker:e.tracker};!function e(){n.multipartList(o,(function(n,a){if(n)return t(n);i.push.apply(i,a.Upload||[]),"true"===a.IsTruncated?(o.KeyMarker=a.NextKeyMarker,o.UploadIdMarker=a.NextUploadIdMarker,e()):t(null,{UploadList:i})}))}()}function m(e,t){var n=this,i=[],o={Bucket:e.Bucket,Region:e.Region,Key:e.Key,UploadId:e.UploadId,calledBySdk:"sliceUploadFile",tracker:e.tracker};!function e(){n.multipartListPart(o,(function(n,a){if(n)return t(n);i.push.apply(i,a.Part||[]),"true"===a.IsTruncated?(o.PartNumberMarker=a.NextPartNumberMarker,e()):t(null,{PartList:i})}))}()}function h(e,t){var n=this,i=e.TaskId,o=e.Bucket,a=e.Region,r=e.Key,s=e.UploadData,l=e.FileSize,u=e.SliceSize,d=Math.min(e.AsyncLimit||n.options.ChunkParallelLimit||1,256),f=e.FilePath,m=Math.ceil(l/u),h=0,v=e.ServerSideEncryption,y=p.filter(s.PartList,(function(e){return e.Uploaded&&(h+=e.PartNumber>=m&&l%u||u),!e.Uploaded})),x=e.onProgress;c.eachLimit(y,d,(function(t,c){if(n._isRunningTask(i)){var p=t.PartNumber,d=Math.min(l,t.PartNumber*u)-(t.PartNumber-1)*u,m=0;g.call(n,{TaskId:i,Bucket:o,Region:a,Key:r,SliceSize:u,FileSize:l,PartNumber:p,ServerSideEncryption:v,FilePath:f,UploadData:s,onProgress:function(e){h+=e.loaded-m,m=e.loaded,x({loaded:h,total:l})},tracker:e.tracker},(function(e,o){n._isRunningTask(i)&&(e?h-=m:(h+=d-m,t.ETag=o.ETag),x({loaded:h,total:l}),c(e||null,o))}))}}),(function(e){if(n._isRunningTask(i))return e?t(e):void t(null,{UploadId:s.UploadId,SliceList:s.PartList})}))}function g(e,t){var n=this,i=e.TaskId,o=e.Bucket,a=e.Region,r=e.Key,s=e.FileSize,l=e.FilePath,u=1*e.PartNumber,d=e.SliceSize,f=e.ServerSideEncryption,m=e.UploadData,h=n.options.ChunkRetryTimes+1,g=e.Headers||{},v=d*(u-1),y=d,x=v+d;x>s&&(y=(x=s)-v);var k=["x-cos-traffic-limit","x-cos-mime-limit"],b={};p.each(g,(function(e,t){k.indexOf(t)>-1&&(b[t]=e)})),p.fileSlice(l,v,x,(function(s){var l=p.getFileMd5(s),d=l?p.binaryBase64(l):null,g=m.PartList[u-1];c.retry(h,(function(t){n._isRunningTask(i)&&n.multipartUpload({TaskId:i,Bucket:o,Region:a,Key:r,ContentLength:y,PartNumber:u,UploadId:m.UploadId,ServerSideEncryption:f,Body:s,Headers:b,onProgress:e.onProgress,ContentMD5:d,calledBySdk:"sliceUploadFile",tracker:e.tracker},(function(e,o){if(n._isRunningTask(i))return e?t(e):(g.Uploaded=!0,t(null,o))}))}),(function(e,o){if(n._isRunningTask(i))return t(e,o)}))}))}function v(e,t){var n=e.Bucket,i=e.Region,o=e.Key,a=e.UploadId,r=e.SliceList,s=this,l=this.options.ChunkRetryTimes+1,p=r.map((function(e){return{PartNumber:e.PartNumber,ETag:e.ETag}}));c.retry(l,(function(t){s.multipartComplete({Bucket:n,Region:i,Key:o,UploadId:a,Parts:p,calledBySdk:"sliceUploadFile",Headers:e.Headers||{},tracker:e.tracker},t)}),(function(e,n){t(e,n)}))}function y(e,t){var n=e.Bucket,i=e.Region,o=e.Key,a=e.AbortArray,r=e.AsyncLimit||1,s=this,l=0,p=new Array(a.length);c.eachLimit(a,r,(function(t,a){var r=l;if(o&&o!==t.Key)return p[r]={error:{KeyNotMatch:!0}},void a(null);var c=t.UploadId||t.UploadID;s.multipartAbort({Bucket:n,Region:i,Key:t.Key,Headers:e.Headers,UploadId:c},(function(e){var o={Bucket:n,Region:i,Key:t.Key,UploadId:c};p[r]={error:e,task:o},a(null)})),l++}),(function(e){if(e)return t(e);for(var n=[],i=[],o=0,a=p.length;or?"sliceUploadFile":"putObject",t.tracker=new u({Beacon:a.options.BeaconReporter,clsReporter:a.options.ClsReporter,bucket:t.Bucket,region:t.Region,apiName:"uploadFile",realApi:f,fileKey:t.Key,fileSize:c,accelerate:d,deepTracker:a.options.DeepTracker,customId:a.options.CustomId,delay:a.options.TrackerDelay})),p.each(t,(function(e,t){"object"!==o(e)&&"function"!=typeof e&&(l[t]=e)})),m=t.onTaskReady,t.onTaskReady=function(e){l.TaskId=e,m&&m(e)},h=t.onFileFinish,g=function(e,i){t.tracker&&t.tracker.report(e,i),h&&h(e,i,l),n&&n(e,i)},v="postObject"===a.options.SimpleUploadMethod?"postObject":"putObject",y=c>r?"sliceUploadFile":v,s.push({api:y,params:t,callback:g}),a._addTasks(s);case 24:case"end":return e.stop()}}),e,this,[[3,9]])})))).apply(this,arguments)}function k(){return k=r(i().mark((function e(t,n){var a,s,c,l,d,f,m,h,g,v,y;return i().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return a=this,s=void 0===t.SliceSize?a.options.SliceSize:t.SliceSize,c=0,l=0,d=p.throttleOnProgress.call(a,l,t.onProgress),f=t.files.length,m=t.onFileFinish,h=Array(f),g=function(e,t,i){d(null,!0),m&&m(e,t,i),h[i.Index]={options:i,error:e,data:t},--f<=0&&n&&n(null,{files:h})},v=[],y=function(){return t.files.map((function(e,t){return new Promise(function(){var n=r(i().mark((function n(r){var f,m,h,y,x,k,b,C,S,w,T;return i().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return f=0,n.prev=1,n.next=4,p.getFileSizeByPath(e.FilePath);case 4:f=n.sent,n.next=9;break;case 7:n.prev=7,n.t0=n.catch(1);case 9:m={Index:t,TaskId:""},c+=f,a.options.EnableReporter&&(h=a.options.UseAccelerate||"string"==typeof a.options.Domain&&a.options.Domain.includes("accelerate."),y=f>s?"sliceUploadFile":"putObject",e.tracker=new u({Beacon:a.options.BeaconReporter,clsReporter:a.options.ClsReporter,bucket:e.Bucket,region:e.Region,apiName:"uploadFiles",realApi:y,fileKey:e.Key,fileSize:f,accelerate:h,deepTracker:a.options.DeepTracker,customId:a.options.CustomId,delay:a.options.TrackerDelay})),p.each(e,(function(e,t){"object"!==o(e)&&"function"!=typeof e&&(m[t]=e)})),x=e.onTaskReady,e.onTaskReady=function(e){m.TaskId=e,x&&x(e)},k=0,b=e.onProgress,e.onProgress=function(e){l=l-k+e.loaded,k=e.loaded,b&&b(e),d({loaded:l,total:c})},C=e.onFileFinish,S=function(t,n){e.tracker&&e.tracker.report(t,n),C&&C(t,n),g&&g(t,n,m)},w="postObject"===a.options.SimpleUploadMethod?"postObject":"putObject",T=f>s?"sliceUploadFile":w,v.push({api:T,params:e,callback:S}),r(!0);case 24:case"end":return n.stop()}}),n,null,[[1,7]])})));return function(e){return n.apply(this,arguments)}}())}))},e.next=13,Promise.all(y());case 13:a._addTasks(v);case 14:case"end":return e.stop()}}),e,this)}))),k.apply(this,arguments)}function b(e,t){var n=e.TaskId,i=e.Bucket,o=e.Region,a=e.Key,r=e.CopySource,s=e.UploadId,l=1*e.PartNumber,p=e.CopySourceRange,u=this.options.ChunkRetryTimes+1,d=this;c.retry(u,(function(t){d.uploadPartCopy({TaskId:n,Bucket:i,Region:o,Key:a,CopySource:r,UploadId:s,PartNumber:l,CopySourceRange:p,onProgress:e.onProgress,tracker:e.tracker,calledBySdk:e.calledBySdk},(function(e,n){t(e||null,n)}))}),(function(e,n){return t(e,n)}))}var C={sliceUploadFile:function(e,t){var n=this;if(!p.canFileSlice())return e.SkipTask=!0,void("postObject"===n.options.SimpleUploadMethod?n.postObject(e,t):n.putObject(e,t));var i,o,a=new l,r=e.TaskId,c=e.Bucket,u=e.Region,f=e.Key,m=e.FilePath,g=e.ChunkSize||e.SliceSize||n.options.ChunkSize,y=e.AsyncLimit,x=e.StorageClass,k=e.ServerSideEncryption,b=e.onHashProgress,C=e.tracker;C&&C.setParams({chunkSize:g}),a.on("error",(function(i){if(n._isRunningTask(r)){var o={UploadId:e.UploadData.UploadId||"",err:i,error:i};return t(o)}})),a.on("upload_complete",(function(n){var i=p.extend({UploadId:e.UploadData.UploadId||""},n);t(null,i)})),a.on("upload_slice_complete",(function(t){var l={};p.each(e.Headers,(function(e,t){var n=t.toLowerCase();0!==n.indexOf("x-cos-meta-")&&"pic-operations"!==n||(l[t]=e)})),v.call(n,{Bucket:c,Region:u,Key:f,UploadId:t.UploadId,SliceList:t.SliceList,Headers:l,tracker:C},(function(e,c){if(n._isRunningTask(r)){if(s.removeUsing(t.UploadId),e)return o(null,!0),a.emit("error",e);s.removeUploadId(t.UploadId),o({loaded:i,total:i},!0),a.emit("upload_complete",c)}}))})),a.on("get_upload_data_finish",(function(t){var l=s.getFileId(e.FileStat,e.ChunkSize,c,f);l&&s.saveUploadId(l,t.UploadId,n.options.UploadIdCacheLimit),s.setUsing(t.UploadId),o(null,!0),h.call(n,{TaskId:r,Bucket:c,Region:u,Key:f,FilePath:m,FileSize:i,SliceSize:g,AsyncLimit:y,ServerSideEncryption:k,UploadData:t,onProgress:o,tracker:C},(function(e,t){if(n._isRunningTask(r))return e?(o(null,!0),a.emit("error",e)):void a.emit("upload_slice_complete",t)}))})),a.on("get_file_size_finish",(function(){if(o=p.throttleOnProgress.call(n,i,e.onProgress),e.UploadData.UploadId)a.emit("get_upload_data_finish",e.UploadData);else{var t=p.extend({TaskId:r,Bucket:c,Region:u,Key:f,Headers:e.Headers,StorageClass:x,FilePath:m,FileSize:i,SliceSize:g,onHashProgress:b,tracker:C},e);t.FileSize=i,d.call(n,t,(function(t,i){if(n._isRunningTask(r)){if(t)return a.emit("error",t);e.UploadData.UploadId=i.UploadId,e.UploadData.PartList=i.PartList,a.emit("get_upload_data_finish",e.UploadData)}}))}})),i=e.ContentLength,delete e.ContentLength,!e.Headers&&(e.Headers={}),p.each(e.Headers,(function(t,n){"content-length"===n.toLowerCase()&&delete e.Headers[n]})),function(){for(var t=[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,5120],o=1048576,a=0;a=w&&y%k||k),!e.Uploaded}));c.eachLimit(f,C,(function(t,n){var s=t.PartNumber,p=t.CopySourceRange,d=t.end-t.start,f=0;c.retry(S,(function(t){b.call(i,{Bucket:o,Region:a,Key:r,CopySource:u,UploadId:l.UploadId,PartNumber:s,CopySourceRange:p,tracker:e.tracker,calledBySdk:"sliceCopyFile",onProgress:function(e){T+=e.loaded-f,f=e.loaded,x({loaded:T,total:y})}},t)}),(function(e,i){if(e)return n(e);x({loaded:T,total:y}),T+=d-f,t.ETag=i.ETag,n(e||null,i)}))}),(function(e){if(e)return s.removeUsing(l.UploadId),x(null,!0),t(e);n.emit("copy_slice_complete",l)}))})),n.on("get_chunk_size_finish",(function(){var c=function(){i.multipartInit({Bucket:o,Region:a,Key:r,Headers:A,tracker:e.tracker,calledBySdk:"sliceCopyFile"},(function(i,o){if(i)return t(i);e.UploadId=o.UploadId,n.emit("get_copy_data_finish",{UploadId:e.UploadId,PartList:e.PartList})}))},l=s.getCopyFileId(u,R,k,o,r),d=s.getUploadIdList(l);if(!l||!d)return c();!function t(l){if(l>=d.length)return c();var u=d[l];if(s.using[u])return t(l+1);m.call(i,{Bucket:o,Region:a,Key:r,UploadId:u,tracker:e.tracker,calledBySdk:"sliceCopyFile"},(function(i,o){if(i)s.removeUploadId(u),t(l+1);else{if(s.using[u])return t(l+1);var a={},r=0;p.each(o.PartList,(function(e){var t=parseInt(e.Size),n=r+t-1;a[e.PartNumber+"|"+r+"|"+n]=e.ETag,r+=t})),p.each(e.PartList,(function(e){var t=a[e.PartNumber+"|"+e.start+"|"+e.end];t&&(e.ETag=t,e.Uploaded=!0)})),n.emit("get_copy_data_finish",{UploadId:u,PartList:e.PartList})}}))}(0)})),n.on("get_file_size_finish",(function(){var o;if(function(){for(var t=[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,5120],n=1048576,o=0;o11&&(B[t]=e)})),n.emit("get_file_size_finish")}else t({error:'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.'})}))}else t({error:"CopySource format error"})}};e.exports.init=function(e,t){t.transferToTaskMethod(C,"sliceUploadFile"),p.each(C,(function(t,n){e.prototype[n]=p.apiWrapper(n,t)}))}},function(e,t){var n={eachLimit:function(e,t,n,i){if(i=i||function(){},!e.length||t<=0)return i();var o=0,a=0,r=0;!function s(){if(o>=e.length)return i();for(;r=e.length?i():s())}))}()},retry:function(e,t,n){e<1?n():function i(o){t((function(t,a){t&&o {
+ if (String(h.huiyuanid) === req || String(h.huiyuan_id) === req) return true;
+ const covers = h.included_huiyuan_ids || h.covers || [];
+ return Array.isArray(covers) && covers.some((id) => String(id) === req);
+ });
+}
diff --git a/utils/display-config.js b/utils/display-config.js
new file mode 100644
index 0000000..e01f79a
--- /dev/null
+++ b/utils/display-config.js
@@ -0,0 +1,42 @@
+/**
+ * 按俱乐部拉取公告/轮播(必须带 X-Club-Id,否则会落到默认 xq)
+ */
+import { buildClubHeaders, getClubId } from './club-context';
+
+export function isGonggaoCacheValid(app) {
+ const g = app.globalData || {};
+ const cid = getClubId(app);
+ return g._gonggaoClubId === cid && (g.shangpingonggao || (g.shangpinlunbo && g.shangpinlunbo.length));
+}
+
+export function applyGonggaoToGlobal(app, data) {
+ if (!data) return;
+ const g = app.globalData;
+ g.shangpingonggao = data.shangpingonggao || '';
+ g.shangpinlunbo = data.shangpinlunbo || [];
+ g._gonggaoClubId = getClubId(app);
+}
+
+export function fetchGonggaoLunbo(app, pageKey = 'order_pool') {
+ const apiBase = app.globalData && app.globalData.apiBaseUrl;
+ if (!apiBase) {
+ return Promise.resolve(null);
+ }
+ return new Promise((resolve, reject) => {
+ wx.request({
+ url: `${apiBase}/peizhi/shangpingonggao/`,
+ method: 'POST',
+ header: buildClubHeaders({ 'content-type': 'application/json' }),
+ data: { page_key: pageKey },
+ success: (res) => {
+ if (res.statusCode === 200 && res.data) {
+ applyGonggaoToGlobal(app, res.data);
+ resolve(res.data);
+ } else {
+ reject(new Error('shangpingonggao 请求失败'));
+ }
+ },
+ fail: reject,
+ });
+ });
+}
diff --git a/utils/grab-order-gate.js b/utils/grab-order-gate.js
new file mode 100644
index 0000000..5fc5799
--- /dev/null
+++ b/utils/grab-order-gate.js
@@ -0,0 +1,25 @@
+/**
+ * 抢单前检查(仅点击抢单时调用)
+ */
+import request from './request.js';
+
+/** 检查是否有待处理罚款(待缴纳 / 申诉中) */
+export async function checkPenaltyForGrab() {
+ try {
+ const res = await request({ url: '/yonghu/cffktjhq', method: 'POST' });
+ if (res?.data?.code === 0) {
+ const fk = res.data.data?.fakuan || {};
+ const pending = Number(fk.daijiaona || 0) + Number(fk.shensuzhong || 0);
+ if (pending > 0) {
+ return {
+ blocked: true,
+ msg: '您有未缴纳或申诉中的罚单,请先处理后再抢单',
+ url: '/pages/penalty/penalty/penalty',
+ };
+ }
+ }
+ } catch (e) {
+ console.error('checkPenaltyForGrab failed', e);
+ }
+ return { blocked: false };
+}
diff --git a/utils/group-chat.js b/utils/group-chat.js
new file mode 100644
index 0000000..d354a4a
--- /dev/null
+++ b/utils/group-chat.js
@@ -0,0 +1,273 @@
+/**
+ * 打手-商家/老板配对群:group_Ds{打手}_Sj{商家}
+ */
+export const ORDER_CARD_PREFIX = '[ORDER_CARD]';
+
+const ZHUANGTAI_MAP = {
+ 1: '待抢单', 2: '进行中', 3: '已完成', 4: '退款中',
+ 5: '已退款', 6: '退款失败', 7: '指定中', 8: '结算中',
+ 9: '未支付', 14: '支付失败', 25: '已废弃',
+};
+
+export function getZhuangtaiText(zhuangtai) {
+ if (zhuangtai == null || zhuangtai === '') return '';
+ const n = Number(zhuangtai);
+ return ZHUANGTAI_MAP[n] || ZHUANGTAI_MAP[zhuangtai] || '';
+}
+
+export function buildDashouShangjiaGroupId(dashouUid, shangjiaUid) {
+ return `group_Ds${dashouUid}_Sj${shangjiaUid}`;
+}
+
+export function buildDashouBossGroupId(dashouUid, bossUid) {
+ return `group_Ds${dashouUid}_Boss${bossUid}`;
+}
+
+export function resolveLocalGroupId(identityType, myUid, partnerUid, fadanPingtai, orderId, isCross) {
+ const cross = isCross === 1 || isCross === true || String(isCross) === '1';
+ if (cross && orderId) {
+ return `group_${orderId}`;
+ }
+ if (!myUid) return orderId ? `group_${orderId}` : null;
+ if (!partnerUid) return orderId ? `group_${orderId}` : null;
+ if (identityType === 'shangjia') {
+ return buildDashouShangjiaGroupId(partnerUid, myUid);
+ }
+ if (identityType === 'dashou') {
+ if (fadanPingtai === 2 || String(fadanPingtai) === '2') {
+ return buildDashouShangjiaGroupId(myUid, partnerUid);
+ }
+ return buildDashouBossGroupId(myUid, partnerUid);
+ }
+ if (identityType === 'boss' || identityType === 'normal') {
+ if (partnerUid && myUid) {
+ return buildDashouBossGroupId(partnerUid, myUid);
+ }
+ return orderId ? `group_${orderId}` : null;
+ }
+ return orderId ? `group_${orderId}` : null;
+}
+
+export function isPairGroupId(groupId) {
+ return /^group_Ds\w+_(Sj|Boss)\w+$/.test(groupId || '');
+}
+
+export function parsePairGroupId(groupId) {
+ if (!groupId) return null;
+ let m = /^group_Ds(\w+)_Sj(\w+)$/.exec(groupId);
+ if (m) return { dashouId: `Ds${m[1]}`, partnerId: `Sj${m[2]}`, partnerRole: 'shangjia' };
+ m = /^group_Ds(\w+)_Boss(\w+)$/.exec(groupId);
+ if (m) return { dashouId: `Ds${m[1]}`, partnerId: `Boss${m[2]}`, partnerRole: 'boss' };
+ return null;
+}
+
+export function getCounterpartGoEasyId(groupId, myGoEasyId) {
+ const parsed = parsePairGroupId(groupId);
+ if (!parsed || !myGoEasyId) return null;
+ if (myGoEasyId === parsed.dashouId) return parsed.partnerId;
+ if (myGoEasyId === parsed.partnerId) return parsed.dashouId;
+ return null;
+}
+
+function fixAvatarUrl(avatar, defaultAvatar, ossBase) {
+ if (!avatar) return defaultAvatar;
+ if (avatar.startsWith('http')) return avatar;
+ return (ossBase || '') + avatar.replace(/^\//, '');
+}
+
+/** 根据群 to.data 与当前身份,解析对方/双方展示信息 */
+export function applyPairMetaToConversation(item, myGoEasyId, defaultAvatar, ossBase) {
+ if (!item || !item.data) return;
+ const d = item.data;
+
+ if (d.dashouGoEasyId && d.partnerGoEasyId) {
+ const isDashou = myGoEasyId === d.dashouGoEasyId;
+ const isPartner = myGoEasyId === d.partnerGoEasyId;
+ d.dashouNicheng = d.dashouName || d.dashouNicheng || '';
+ d.partnerNicheng = d.partnerName || d.partnerNicheng || '';
+ d.dashouAvatar = fixAvatarUrl(d.dashouAvatar, defaultAvatar, ossBase);
+ d.partnerAvatar = fixAvatarUrl(d.partnerAvatar, defaultAvatar, ossBase);
+
+ if (isDashou) {
+ d.counterpartId = d.partnerGoEasyId;
+ d.counterpartYonghuid = d.partnerYonghuid || d.partnerGoEasyId.replace(/^(Sj|Boss)/, '');
+ d.partnerRoleLabel = d.partnerGoEasyId.startsWith('Boss') ? '老板' : '商家';
+ d.name = d.partnerNicheng || `${d.partnerRoleLabel}${d.counterpartYonghuid}`;
+ d.avatar = d.partnerAvatar || defaultAvatar;
+ } else if (isPartner) {
+ d.counterpartId = d.dashouGoEasyId;
+ d.counterpartYonghuid = d.dashouYonghuid || d.dashouGoEasyId.replace(/^Ds/, '');
+ d.name = d.dashouNicheng || `打手${d.counterpartYonghuid}`;
+ d.avatar = d.dashouAvatar || defaultAvatar;
+ } else {
+ const cpId = getCounterpartGoEasyId(item.groupId, myGoEasyId);
+ if (cpId === d.partnerGoEasyId) {
+ d.name = d.partnerNicheng;
+ d.avatar = d.partnerAvatar || defaultAvatar;
+ } else if (cpId === d.dashouGoEasyId) {
+ d.name = d.dashouNicheng;
+ d.avatar = d.dashouAvatar || defaultAvatar;
+ }
+ }
+ return;
+ }
+
+ const parsed = parsePairGroupId(item.groupId);
+ if (parsed && myGoEasyId) {
+ const isDashou = myGoEasyId === parsed.dashouId;
+ const isPartner = myGoEasyId === parsed.partnerId;
+ if (isDashou) {
+ d.counterpartId = parsed.partnerId;
+ d.counterpartYonghuid = parsed.partnerId.replace(/^(Sj|Boss)/, '');
+ d.partnerRoleLabel = parsed.partnerRole === 'boss' ? '老板' : '商家';
+ if (!d.name || d.name === item.groupId) {
+ d.name = d.partnerNicheng || `${d.partnerRoleLabel}${d.counterpartYonghuid.slice(-6)}`;
+ }
+ if (!d.avatar || d.avatar === defaultAvatar) {
+ d.avatar = d.partnerAvatar || defaultAvatar;
+ }
+ } else if (isPartner) {
+ d.counterpartId = parsed.dashouId;
+ d.counterpartYonghuid = parsed.dashouId.replace(/^Ds/, '');
+ if (!d.name || d.name === item.groupId) {
+ d.name = d.dashouNicheng || `打手${d.counterpartYonghuid.slice(-6)}`;
+ }
+ if (!d.avatar || d.avatar === defaultAvatar) {
+ d.avatar = d.dashouAvatar || defaultAvatar;
+ }
+ }
+ }
+
+ const counterpartId = getCounterpartGoEasyId(item.groupId, myGoEasyId);
+ if (counterpartId) {
+ d.counterpartId = counterpartId;
+ d.counterpartYonghuid = counterpartId.replace(/^(Ds|Sj|Boss)/, '');
+ if (!d.name || d.name === item.groupId) {
+ d.name = `用户${d.counterpartYonghuid.slice(-6)}`;
+ }
+ }
+
+ if (item.lastMessage && item.lastMessage.senderId && item.lastMessage.senderId !== myGoEasyId) {
+ const sd = item.lastMessage.senderData || {};
+ if (sd.avatar) d.avatar = fixAvatarUrl(sd.avatar, defaultAvatar, ossBase);
+ if (sd.name) d.name = sd.name;
+ }
+
+ d.avatar = fixAvatarUrl(d.avatar, defaultAvatar, ossBase);
+}
+
+export function parseOrderCardText(text) {
+ if (!text || !text.startsWith(ORDER_CARD_PREFIX)) return null;
+ try {
+ const data = JSON.parse(text.slice(ORDER_CARD_PREFIX.length));
+ return {
+ orderId: data.dingdan_id,
+ jieshao: data.jieshao || '',
+ jine: data.jine || '',
+ beizhu: data.beizhu || '',
+ zhuangtai: data.zhuangtai,
+ nicheng: data.nicheng || '',
+ create_time: data.create_time || '',
+ };
+ } catch (e) {
+ return null;
+ }
+}
+
+import { getChatImageUrl } from '../static/lib/utils.js';
+
+export function normalizeGroupMessage(msg) {
+ if (!msg) return msg;
+ if (msg.type === 'text' && msg.payload && msg.payload.text) {
+ const card = parseOrderCardText(msg.payload.text);
+ if (card) {
+ msg.type = 'order';
+ msg.payload = card;
+ }
+ }
+ if (msg.type === 'custom' && msg.payload) {
+ const inner = msg.payload.payload || msg.payload;
+ if (inner && (inner.orderId || inner.dingdan_id)) {
+ msg.type = 'order';
+ msg.payload = {
+ orderId: inner.orderId || inner.dingdan_id,
+ jieshao: inner.jieshao || '',
+ jine: inner.jine || '',
+ beizhu: inner.beizhu || '',
+ zhuangtai: inner.zhuangtai,
+ nicheng: inner.nicheng || '',
+ create_time: inner.create_time || '',
+ };
+ }
+ }
+ if (msg.type === 'image') {
+ const url = getChatImageUrl(msg);
+ msg.payload = { ...(msg.payload || {}), url };
+ msg.imageUrl = url;
+ }
+ return msg;
+}
+
+export function formatLastMessagePreview(msg) {
+ if (!msg) return '';
+ if (msg.type === 'text' && msg.payload && msg.payload.text) {
+ const card = parseOrderCardText(msg.payload.text);
+ if (card) return `[订单] ${card.jieshao || card.orderId}`;
+ return msg.payload.text;
+ }
+ if (msg.type === 'order' && msg.payload) {
+ return `[订单] ${msg.payload.jieshao || msg.payload.orderId || ''}`;
+ }
+ if (msg.type === 'image') return '[图片]';
+ return '[消息]';
+}
+
+export function enrichGroupConversation(item, myGoEasyId, defaultAvatar, ossBase) {
+ if (!item || item.type !== 'group') return item;
+ if (!item.data) item.data = {};
+
+ applyPairMetaToConversation(item, myGoEasyId, defaultAvatar, ossBase);
+
+ if (item.data.orderZhuangtai != null) {
+ item.data.orderZhuangtaiText = ZHUANGTAI_MAP[item.data.orderZhuangtai] || '';
+ }
+
+ item.displayLastMsg = formatLastMessagePreview(item.lastMessage);
+ if (!item.data.avatar) item.data.avatar = defaultAvatar;
+ return item;
+}
+
+export function isOrderGroupConversation(c) {
+ if (!c || c.type !== 'group') return false;
+ if (c.data && c.data.orderId) return true;
+ if (c.data && c.data.dashouGoEasyId) return true;
+ return isPairGroupId(c.groupId) || /^group_\w+$/.test(c.groupId || '');
+}
+
+export function getConversationSortTime(conversation, openTimes) {
+ const id = conversation.groupId || conversation.userId || '';
+ const msgTs = conversation.lastMessage?.timestamp || 0;
+ const openTs = (openTimes && id && openTimes[id]) ? openTimes[id] : 0;
+ // QQ/微信:取「最后消息时间」与「最近进入会话时间」较大值;新消息到达会更新 msgTs 并置顶
+ return Math.max(msgTs, openTs);
+}
+
+export function sortConversations(list, openTimes) {
+ return list.sort((a, b) => {
+ if (a.top && !b.top) return -1;
+ if (!a.top && b.top) return 1;
+ const ta = getConversationSortTime(a, openTimes);
+ const tb = getConversationSortTime(b, openTimes);
+ return tb - ta;
+ });
+}
+
+export function recordConversationOpen(conversation) {
+ const id = conversation?.groupId || conversation?.userId;
+ if (!id) return;
+ try {
+ const times = wx.getStorageSync('conversationOpenTimes') || {};
+ times[id] = Date.now();
+ wx.setStorageSync('conversationOpenTimes', times);
+ } catch (e) {}
+}
diff --git a/utils/im-user.js b/utils/im-user.js
index 49f2b39..20bcc83 100644
--- a/utils/im-user.js
+++ b/utils/im-user.js
@@ -2,6 +2,7 @@
import { getPrimaryRole } from './primary-role.js';
import { resolveAvatarUrl } from './avatar.js';
import { ensureRoleOnCenterPage } from './role-tab-bar.js';
+import { isStaffMode } from './staff-api.js';
/** 联系对象前缀:管事/组长/考核官已废弃独立前缀,统一 Ds */
const PEER_PREFIX = {
@@ -14,15 +15,38 @@ const PEER_PREFIX = {
kaoheguan: 'Ds',
};
+export const IM_ROLE_PREFIX = {
+ normal: 'Boss',
+ dashou: 'Ds',
+ shangjia: 'Sj',
+ guanshi: 'Ds',
+ zuzhang: 'Ds',
+ kaoheguan: 'Ds',
+};
+
+import { getDefaultAvatarUrl } from './avatar.js';
+
+export function getDefaultAvatar(app) {
+ return getDefaultAvatarUrl(app || getApp());
+}
+
export function getImPrefixForRole(role) {
+ if (isStaffMode()) return 'Sj';
return PEER_PREFIX[role] || 'Ds';
}
-/** 当前端连接 GoEasy 用的 userId */
+export function getImUserIdForRole(role, uid) {
+ if (!uid) return '';
+ const prefix = getImPrefixForRole(role);
+ return prefix + uid;
+}
+
+/** 当前端连接 GoEasy 用的 userId(子客服仍用 Sj) */
export function getLocalImUserId(app) {
app = app || getApp();
const uid = wx.getStorageSync('uid') || '';
if (!uid) return '';
+ if (isStaffMode()) return 'Sj' + uid;
const primary = getPrimaryRole(app);
if (primary === 'dashou') return 'Ds' + uid;
if (primary === 'shangjia') return 'Sj' + uid;
@@ -31,15 +55,43 @@ export function getLocalImUserId(app) {
export function getLocalImIdentity(app) {
app = app || getApp();
+ if (isStaffMode()) return 'shangjia';
return getPrimaryRole(app) || 'normal';
}
+export function getFreshImUser(app, role, uid) {
+ const effectiveRole = isStaffMode() ? 'shangjia' : role;
+ const id = getImUserIdForRole(effectiveRole, uid);
+ const touxiang = wx.getStorageSync('touxiang') || '';
+ const avatar = resolveAvatarUrl(touxiang, app);
+ const name = app.globalData.currentUser?.name || `用户${(uid || '').slice(-6)}`;
+ return { id, name, avatar };
+}
+
+export function persistGroupMeta(app, groupId, meta) {
+ if (!groupId || !meta) return;
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ app.globalData.groupInfoMap[groupId] = { ...app.globalData.groupInfoMap[groupId], ...meta };
+ try {
+ const cache = wx.getStorageSync('pairGroupMetaCache') || {};
+ cache[groupId] = app.globalData.groupInfoMap[groupId];
+ wx.setStorageSync('pairGroupMetaCache', cache);
+ } catch (e) {}
+}
+
+export function loadGroupMetaCache(app) {
+ try {
+ const cache = wx.getStorageSync('pairGroupMetaCache') || {};
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ Object.assign(app.globalData.groupInfoMap, cache);
+ } catch (e) {}
+}
+
export function buildPeerImUserId(uid, role = 'dashou') {
if (!uid) return '';
return getImPrefixForRole(role) + uid;
}
-/** 联系邀请人/管事/组长:统一 Ds 前缀 */
export function buildGuanshiPeerId(uid) {
return buildDashouPeerId(uid);
}
diff --git a/utils/imAuth/dashoujianquan.js b/utils/imAuth/dashoujianquan.js
index b1fc2be..025cc03 100644
--- a/utils/imAuth/dashoujianquan.js
+++ b/utils/imAuth/dashoujianquan.js
@@ -4,9 +4,9 @@ const imRequest = require('./imRequest.js');
/**
* 打手 IM 权限检测
* POST /yonghu/dshqltqx
- * 后端返回 { code: 0, allow: 1 } 或 { code: 0, allow: 0 }
*/
-async function dashoujianquan(app) {
+async function dashoujianquan(app, options = {}) {
+ const silent = options && options.silent === true;
const uid = wx.getStorageSync('uid');
if (!uid) return { allowed: false, reason: '未登录' };
@@ -21,7 +21,8 @@ async function dashoujianquan(app) {
const allow = res.data.allow;
if (allow === 1) {
return { allowed: true };
- } else {
+ }
+ if (!silent) {
await app.disconnectGoEasy();
wx.showToast({
title: '当前身份已不支持消息聊天功能,请充值会员或联系管理员后尝试',
@@ -30,22 +31,24 @@ async function dashoujianquan(app) {
mask: true
});
await new Promise(r => setTimeout(r, 2100));
- return { allowed: false, reason: '接单员消息权限被限制' };
}
+ return { allowed: false, reason: '接单员消息权限被限制' };
}
throw new Error(res.data?.msg || '鉴权接口异常');
} catch (err) {
console.error('打手鉴权失败:', err);
- await app.disconnectGoEasy();
- wx.showToast({
- title: '消息服务暂不可用,请稍后重试',
- icon: 'none',
- duration: 2000,
- mask: true
- });
- await new Promise(r => setTimeout(r, 2100));
+ if (!silent) {
+ await app.disconnectGoEasy();
+ wx.showToast({
+ title: '消息服务暂不可用,请稍后重试',
+ icon: 'none',
+ duration: 2000,
+ mask: true
+ });
+ await new Promise(r => setTimeout(r, 2100));
+ }
return { allowed: false, reason: '鉴权请求失败' };
}
}
-module.exports = { dashoujianquan };
\ No newline at end of file
+module.exports = { dashoujianquan };
diff --git a/utils/imAuth/jianquanxian.js b/utils/imAuth/jianquanxian.js
index f373451..351b338 100644
--- a/utils/imAuth/jianquanxian.js
+++ b/utils/imAuth/jianquanxian.js
@@ -14,21 +14,21 @@ const { dashoujianquan } = require('./dashoujianquan.js');
* @param {Object} app 全局 App 实例
* @returns {Promise<{ allowed: boolean, reason?: string }>}
*/
-async function jianquanxian(app) {
+async function jianquanxian(app, options = {}) {
+ const silent = options && options.silent === true;
// 1. 检测登录态(用 uid 或 token)
const token = wx.getStorageSync('token') || wx.getStorageSync('uid');
if (!token) {
- // 没登录:先强制断开(如果已连接)
- await app.disconnectGoEasy();
- // 弹窗提示,强制阅读 2 秒
- wx.showToast({
- title: '您当前处于未登录状态,消息功能暂不可用',
- icon: 'none',
- duration: 2000,
- mask: true
- });
- // 等待提示结束,确保用户看到
- await new Promise(resolve => setTimeout(resolve, 2100));
+ if (!silent) {
+ await app.disconnectGoEasy();
+ wx.showToast({
+ title: '您当前处于未登录状态,消息功能暂不可用',
+ icon: 'none',
+ duration: 2000,
+ mask: true
+ });
+ await new Promise(resolve => setTimeout(resolve, 2100));
+ }
return { allowed: false, reason: '未登录' };
}
@@ -37,17 +37,16 @@ async function jianquanxian(app) {
// 3. 根据角色分发到具体鉴权模块
switch (role) {
- case 'normal': // 点单老板
- return laobanjianquan(app);
+ case 'normal':
+ return laobanjianquan(app, { silent });
- case 'dashou': // 打手
- return dashoujianquan(app);
+ case 'dashou':
+ return dashoujianquan(app, { silent });
- // 其他角色暂未细分,统一放行(后续可新增对应文件)
case 'shangjia':
case 'guanshi':
case 'zuzhang':
- case 'kaoheguan':
+ case 'kaoheguan':
return { allowed: true };
default:
diff --git a/utils/imAuth/laobanjianquan.js b/utils/imAuth/laobanjianquan.js
index a29361a..275358f 100644
--- a/utils/imAuth/laobanjianquan.js
+++ b/utils/imAuth/laobanjianquan.js
@@ -4,9 +4,9 @@ const imRequest = require('./imRequest.js');
/**
* 老板(点单用户)IM 权限检测
* POST /yonghu/lbhqltqx
- * 后端返回 { code: 0, allow: 1 } 或 { code: 0, allow: 0 }
*/
-async function laobanjianquan(app) {
+async function laobanjianquan(app, options = {}) {
+ const silent = options && options.silent === true;
const uid = wx.getStorageSync('uid');
if (!uid) return { allowed: false, reason: '未登录' };
@@ -21,7 +21,8 @@ async function laobanjianquan(app) {
const allow = res.data.allow;
if (allow === 1) {
return { allowed: true };
- } else {
+ }
+ if (!silent) {
await app.disconnectGoEasy();
wx.showToast({
title: '当前身份已不支持使用消息功能',
@@ -30,22 +31,24 @@ async function laobanjianquan(app) {
mask: true
});
await new Promise(r => setTimeout(r, 1100));
- return { allowed: false, reason: '当前身份无消息权限' };
}
+ return { allowed: false, reason: '当前身份无消息权限' };
}
throw new Error(res.data?.msg || '鉴权接口异常');
} catch (err) {
console.error('老板鉴权失败:', err);
- await app.disconnectGoEasy();
- wx.showToast({
- title: '消息服务暂不可用,请稍后重试',
- icon: 'none',
- duration: 2000,
- mask: true
- });
- await new Promise(r => setTimeout(r, 2100));
+ if (!silent) {
+ await app.disconnectGoEasy();
+ wx.showToast({
+ title: '消息服务暂不可用,请稍后重试',
+ icon: 'none',
+ duration: 2000,
+ mask: true
+ });
+ await new Promise(r => setTimeout(r, 2100));
+ }
return { allowed: false, reason: '鉴权请求失败' };
}
}
-module.exports = { laobanjianquan };
\ No newline at end of file
+module.exports = { laobanjianquan };
diff --git a/utils/kefu-nav.js b/utils/kefu-nav.js
new file mode 100644
index 0000000..55caa57
--- /dev/null
+++ b/utils/kefu-nav.js
@@ -0,0 +1,27 @@
+/** 与消息页「联系客服」一致:跳转客服会话 */
+export function openCustomerServiceChat() {
+ const app = getApp();
+ if (app.globalData.chatEnabled && app.ensureConnection) {
+ app.globalData.goEasyConnection.autoReconnect = true;
+ app.ensureConnection();
+ }
+ const param = { teamId: 'support_team' };
+ wx.navigateTo({
+ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)),
+ });
+}
+
+/** 与打手「我的」页在线客服同一图标:beijing/tubiao/grzx_kefu.jpg */
+export function resolveKefuIconUrl(app) {
+ app = app || getApp();
+ const rel = 'beijing/tubiao/grzx_kefu.jpg';
+ let base = (app.globalData && app.globalData.ossImageUrl) || '';
+ if (!base && typeof app.readConfigFromStorage === 'function') {
+ try {
+ const cached = app.readConfigFromStorage();
+ base = (cached && cached.cos && cached.cos.ossImageUrl) || '';
+ } catch (e) {}
+ }
+ if (!base) return '';
+ return base.endsWith('/') ? base + rel : base + rel;
+}
diff --git a/utils/login.js b/utils/login.js
index 146cb41..bfafed9 100644
--- a/utils/login.js
+++ b/utils/login.js
@@ -6,6 +6,7 @@ import {
isWechatLoginSuccess,
} from './role-tab-bar';
import { restoreStaffContextAfterAuth } from './staff-api.js';
+import { CLUB_API, getClubId, setClubId, buildClubHeaders } from './club-context';
const app = getApp();
@@ -19,12 +20,10 @@ export function ensureLogin(options = {}) {
return Promise.resolve(true);
}
- // 关键:如果已有登录流程正在执行,直接返回那个 Promise,避免并发登录
if (app.globalData.loginPromise) {
return app.globalData.loginPromise;
}
- // 开始新的登录流程
const loginPromise = new Promise(async (resolve, reject) => {
if (silent) {
wx.showLoading({ title: '自动登录中...', mask: true });
@@ -36,12 +35,15 @@ export function ensureLogin(options = {}) {
const apiBaseUrl = app.globalData.apiBaseUrl;
if (!apiBaseUrl) throw new Error('服务器配置错误');
+ const clubId = getClubId(app);
+ const appId = app.globalData.appId || '';
+
const res = await new Promise((resolve, reject) => {
wx.request({
- url: apiBaseUrl + '/yonghu/wechatlogin',
+ url: apiBaseUrl + CLUB_API.wechatLogin,
method: 'POST',
- data: { code: loginRes.code },
- header: { 'content-type': 'application/json' },
+ data: { code: loginRes.code, club_id: clubId, app_id: appId },
+ header: buildClubHeaders({ 'content-type': 'application/json' }),
success: resolve,
fail: reject,
});
@@ -49,7 +51,11 @@ export function ensureLogin(options = {}) {
const userData = res.data && (res.data.data || res.data);
if (res.statusCode === 200 && isWechatLoginSuccess(res.data) && userData) {
+ if (userData.club_id) {
+ setClubId(userData.club_id, app);
+ }
applyWechatLoginData(userData, page);
+ restoreStaffContextAfterAuth();
resolve(true);
} else {
const msg = res.data?.msg || '登录失败';
@@ -64,12 +70,10 @@ export function ensureLogin(options = {}) {
}
});
- // 存储全局登录 Promise,供 request.js 感知
app.globalData.loginPromise = loginPromise;
- // 无论成功或失败,完成后清空标记
loginPromise.finally(() => {
app.globalData.loginPromise = null;
});
return loginPromise;
-}
\ No newline at end of file
+}
diff --git a/utils/merchant-order-stats.js b/utils/merchant-order-stats.js
new file mode 100644
index 0000000..1fd97f8
--- /dev/null
+++ b/utils/merchant-order-stats.js
@@ -0,0 +1,95 @@
+/**
+ * 商家订单统计:优先新接口,失败时回退订单列表中的 pending 字段
+ */
+import { STAFF_API, isStaffMode } from './staff-api.js';
+
+const EMPTY_ORDER = {
+ 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',
+};
+
+export async function fetchMerchantOrderStats(request, params = {}) {
+ const statsUrl = isStaffMode() ? STAFF_API.orderStats : '/dingdan/sjshujutj';
+ try {
+ const res = await request({ url: statsUrl, method: 'POST', data: params });
+ if (res.statusCode === 200 && res.data && (res.data.code === 0 || res.data.code === 200)) {
+ return res.data.data || {};
+ }
+ } catch (e) {
+ console.warn('统计接口失败,尝试回退', e);
+ }
+
+ try {
+ const listUrl = isStaffMode() ? STAFF_API.orderList : '/dingdan/sjdingdanhq';
+ const fb = await request({
+ url: listUrl,
+ method: 'POST',
+ data: { zhuangtai_list: [8], page: 1, page_size: 1, ...params },
+ });
+ if (fb.statusCode === 200 && fb.data && fb.data.code === 0) {
+ const d = fb.data.data || {};
+ return {
+ order: {
+ ...EMPTY_ORDER,
+ pending_count: d.pending_count || 0,
+ pending_amount: d.pending_amount || '0.00',
+ },
+ can_view_finance: true,
+ };
+ }
+ } catch (e) {
+ console.warn('统计回退失败', e);
+ }
+ return { order: { ...EMPTY_ORDER }, can_view_finance: true };
+}
+
+export function applyOrderStatsToPage(page, data) {
+ const order = data.order || data || {};
+ const penalty = data.penalty || {};
+ const fakuanP = penalty.fakuan_pending || 0;
+ const jifenP = penalty.jifen_pending || 0;
+ page.setData({
+ canViewFinance: data.can_view_finance !== false,
+ 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',
+ },
+ penaltyStats: {
+ fakuan_pending: fakuanP,
+ fakuan_pending_amount: penalty.fakuan_pending_amount || '0.00',
+ jifen_pending: jifenP,
+ },
+ pendingCount: order.pending_count || 0,
+ punishPending: fakuanP + jifenP,
+ });
+}
+
+export function applyOrderStatsToHome(page, data, statsKey = 'stats') {
+ const order = data.order || data || {};
+ const base = page.data[statsKey] || {};
+ page.setData({
+ [statsKey]: {
+ ...base,
+ pendingCount: order.pending_count || 0,
+ pendingAmount: order.pending_amount || '0.00',
+ completedCount: order.completed_count || 0,
+ completedAmount: order.completed_amount || '0.00',
+ refundCount: order.refund_count || 0,
+ refundAmount: order.refund_amount || '0.00',
+ dispatchCount: order.dispatch_count || 0,
+ dispatchAmount: order.dispatch_amount || '0.00',
+ },
+ });
+}
diff --git a/utils/miniapp-icons.js b/utils/miniapp-icons.js
new file mode 100644
index 0000000..6192e08
--- /dev/null
+++ b/utils/miniapp-icons.js
@@ -0,0 +1,238 @@
+/** 小程序可配置图标(启动时从 qdpzhq.miniappAssets 注入 globalData) */
+
+import { buildClubHeaders } from './club-context.js';
+
+export const ICON_KEYS = {
+ MERCHANT_GOLD_BANNER: 'merchant_gold_banner',
+ MERCHANT_HOME_REGULAR: 'merchant_home_regular',
+ MERCHANT_HOME_CUSTOM: 'merchant_home_custom',
+ MERCHANT_HOME_LINK: 'merchant_home_link',
+ MERCHANT_HOME_KEFU_KEY: 'merchant_home_kefu_key',
+ MERCHANT_HOME_KEFU_LIST: 'merchant_home_kefu_list',
+ MERCHANT_HOME_NOTICE: 'merchant_home_notice',
+ MERCHANT_HOME_STAT_BG: 'merchant_home_stat_bg',
+ MERCHANT_REGULAR: 'merchant_regular_dispatch',
+ MERCHANT_CUSTOM: 'merchant_custom_dispatch',
+ MERCHANT_PENDING: 'merchant_pending_settle',
+ MERCHANT_KEFU_KEY: 'merchant_kefu_key',
+ MERCHANT_KEFU_LIST: 'merchant_kefu_list',
+ MERCHANT_LINK: 'merchant_link_dispatch',
+ MERCHANT_PUNISH: 'merchant_punish',
+ MERCHANT_RANK: 'merchant_rank',
+ MERCHANT_REFRESH: 'merchant_refresh',
+ FIGHTER_RECHARGE_MEMBER: 'fighter_recharge_member',
+ FIGHTER_RECHARGE_DEPOSIT: 'fighter_recharge_deposit',
+ FIGHTER_RECHARGE_VIP_BG: 'fighter_recharge_vip_bg',
+ FIGHTER_DEPOSIT_BG: 'fighter_deposit_bg',
+ FIGHTER_DEPOSIT_HERO: 'fighter_deposit_hero',
+ FIGHTER_DEPOSIT_BENEFIT_1: 'fighter_deposit_benefit_1',
+ FIGHTER_DEPOSIT_BENEFIT_2: 'fighter_deposit_benefit_2',
+ FIGHTER_DEPOSIT_BENEFIT_3: 'fighter_deposit_benefit_3',
+ FIGHTER_DEPOSIT_BENEFIT_4: 'fighter_deposit_benefit_4',
+ FIGHTER_RECHARGE_BENEFIT_1: 'fighter_recharge_benefit_1',
+ FIGHTER_RECHARGE_BENEFIT_2: 'fighter_recharge_benefit_2',
+ FIGHTER_RECHARGE_BENEFIT_3: 'fighter_recharge_benefit_3',
+ FIGHTER_RECHARGE_ADVANTAGE_1: 'fighter_recharge_advantage_1',
+ FIGHTER_RECHARGE_ADVANTAGE_2: 'fighter_recharge_advantage_2',
+ FIGHTER_RECHARGE_ADVANTAGE_3: 'fighter_recharge_advantage_3',
+ FIGHTER_RECHARGE_ADVANTAGE_4: 'fighter_recharge_advantage_4',
+ FIGHTER_ORDER_PENDING: 'fighter_order_pending',
+ FIGHTER_ORDER_SETTLING: 'fighter_order_settling',
+ FIGHTER_ORDER_DONE: 'fighter_order_done',
+ FIGHTER_ORDER_CLOSED: 'fighter_order_closed',
+ FIGHTER_TRADE_COMMISSION: 'fighter_trade_commission',
+ FIGHTER_TRADE_WITHDRAW: 'fighter_trade_withdraw',
+ FIGHTER_TRADE_SETTLE: 'fighter_trade_settle',
+ FIGHTER_TRADE_DEDUCT: 'fighter_trade_deduct',
+ FIGHTER_TRADE_RECHARGE: 'fighter_trade_recharge',
+ FIGHTER_INVITE_SUBORDINATE: 'fighter_invite_subordinate',
+ FIGHTER_INVITE_POSTER: 'fighter_invite_poster',
+ FIGHTER_INVITE_CODE: 'fighter_invite_code',
+ FIGHTER_KUAISHOU_CASH: 'fighter_kuaishou_cash',
+ FIGHTER_MINE_COPY: 'fighter_mine_copy',
+ FIGHTER_MINE_EDIT: 'fighter_mine_edit',
+ FIGHTER_MINE_QIEPIAN: 'fighter_mine_qiepian',
+ FIGHTER_MINE_PENALTY_TIP: 'fighter_mine_penalty_tip',
+ FIGHTER_MINE_KEFU: 'fighter_mine_kefu',
+ FIGHTER_MINE_SHANGJIA: 'fighter_mine_shangjia',
+ FIGHTER_MINE_PUNISH: 'fighter_mine_punish',
+ FIGHTER_MINE_MEDAL: 'fighter_mine_medal',
+ FIGHTER_MINE_BOOK: 'fighter_mine_book',
+ FIGHTER_MINE_RANK: 'fighter_mine_rank',
+ FIGHTER_MINE_INVITE: 'fighter_mine_invite',
+ FIGHTER_MINE_CONTACT: 'fighter_mine_contact',
+ FIGHTER_MINE_RECORD: 'fighter_mine_record',
+ FIGHTER_MINE_KAOHE_DAFEN: 'fighter_mine_kaohe_dafen',
+ FIGHTER_MINE_KAOHE_JILU: 'fighter_mine_kaohe_jilu',
+ FIGHTER_MINE_KAOHE_ZHONGXIN: 'fighter_mine_kaohe_zhongxin',
+ FIGHTER_MINE_DASHOU_AUTH: 'fighter_mine_dashou_auth',
+ FIGHTER_MINE_CLEAR: 'fighter_mine_clear',
+ FIGHTER_MINE_SWITCH: 'fighter_mine_switch',
+ MINE_PINDAO: 'mine_pindao',
+ ICON_REFRESH: 'icon_refresh',
+};
+
+/** 仅后台上传后才展示(页面大背景),横幅/功能图标走 resolveMiniappIcon */
+export const CONFIG_ONLY_ICON_KEYS = new Set([
+ ICON_KEYS.FIGHTER_RECHARGE_VIP_BG,
+ ICON_KEYS.FIGHTER_DEPOSIT_BG,
+ ICON_KEYS.FIGHTER_DEPOSIT_HERO,
+]);
+
+export const ICON_FOLDER = 'beijing/tubiao/chengxutubiao';
+
+/** 逍遥梦原版金牌横幅(硬编码时代 82.png) */
+export const MERCHANT_GOLD_BANNER_FALLBACK = 'https://bintao.xmxym88.com/xcx/bintao/82.png';
+
+/** 频道入口图标默认相对路径(拼接 ossImageUrl;后台上传 mine_pindao 后覆盖) */
+export const PINDAO_ICON_FALLBACK = 'beijing/tubiao/grzx_pindao.jpg';
+
+/** 打手中心图标默认相对路径(后台未上传时由后端 default 下发,此处仅离线兜底) */
+export function defaultIconRel(key) {
+ return `${ICON_FOLDER}/${key}.png`;
+}
+
+function ossBase(app) {
+ return (app && app.globalData && app.globalData.ossImageUrl) || '';
+}
+
+export function applyMiniappAssetsFromConfig(app, config) {
+ if (!app || !config) return;
+ const assets = config.miniappAssets || {};
+ app.globalData.miniappIcons = assets.icons || {};
+ app.globalData.pindaoConfig = assets.pindao || { channel_no: '', title: '频道', images: [] };
+ app.globalData.posterConfig = assets.poster || {
+ guanshi_bg: 'beijing/haibaobeijing.jpg',
+ zuzhang_bg: 'beijing/zuzhangbeijing.jpg',
+ };
+}
+
+/** 后台已上传的可配置图标(无则返回空,不显示) */
+export function resolveConfiguredIcon(app, key) {
+ const icons = (app && app.globalData && app.globalData.miniappIcons) || {};
+ const path = icons[key];
+ if (!path) return '';
+ if (path.startsWith('http')) return path;
+ return ossBase(app) + path;
+}
+
+/** 通用图标:有配置用配置,否则用 fallback */
+export function resolveMiniappIcon(app, key, fallback = '') {
+ if (CONFIG_ONLY_ICON_KEYS.has(key)) {
+ return resolveConfiguredIcon(app, key);
+ }
+ const icons = (app && app.globalData && app.globalData.miniappIcons) || {};
+ const path = icons[key];
+ if (!path) {
+ if (!fallback) return '';
+ if (fallback.startsWith('http')) return fallback;
+ const base = ossBase(app);
+ return base ? base + fallback : fallback;
+ }
+ if (path.startsWith('http')) return path;
+ return ossBase(app) + path;
+}
+
+export function getPindaoConfig(app) {
+ return (app && app.globalData && app.globalData.pindaoConfig) || {
+ channel_no: '',
+ title: '频道',
+ images: [],
+ };
+}
+
+export function hasPindaoEntry(app) {
+ const cfg = getPindaoConfig(app);
+ if ((cfg.channel_no || '').trim()) return true;
+ return (cfg.images || []).length > 0;
+}
+
+export function resolvePindaoImages(app) {
+ const cfg = getPindaoConfig(app);
+ const base = ossBase(app);
+ return (cfg.images || []).map((url) => {
+ if (!url) return '';
+ return url.startsWith('http') ? url : base + url;
+ }).filter(Boolean);
+}
+
+export function preloadPindaoImages(urls) {
+ (urls || []).forEach((src) => {
+ if (!src) return;
+ wx.getImageInfo({ src, fail: () => {} });
+ });
+}
+
+export async function refreshPindaoConfig(app) {
+ app = app || getApp();
+ try {
+ if (typeof app.fetchConfigSafely === 'function') {
+ const config = await app.fetchConfigSafely();
+ if (config && typeof config === 'object') {
+ if (typeof app.applyDynamicConfig === 'function') {
+ app.applyDynamicConfig(config);
+ } else {
+ applyMiniappAssetsFromConfig(app, config);
+ }
+ if (typeof app.saveConfigToStorage === 'function') {
+ app.saveConfigToStorage(config);
+ }
+ }
+ }
+ } catch (e) {
+ console.warn('refreshPindaoConfig failed', e);
+ }
+ const cfg = getPindaoConfig(app);
+ const images = resolvePindaoImages(app);
+ preloadPindaoImages(images);
+ return { cfg, images };
+}
+
+export function warmupPindaoConfig(app) {
+ const cached = resolvePindaoImages(app || getApp());
+ if (cached.length) preloadPindaoImages(cached);
+ refreshPindaoConfig(app).catch(() => {});
+}
+
+export function getPosterConfig(app) {
+ return (app && app.globalData && app.globalData.posterConfig) || {
+ guanshi_bg: 'beijing/haibaobeijing.jpg',
+ zuzhang_bg: 'beijing/zuzhangbeijing.jpg',
+ };
+}
+
+export function resolvePosterBg(app, role) {
+ const cfg = getPosterConfig(app);
+ const rel = role === 'zuzhang' ? cfg.zuzhang_bg : cfg.guanshi_bg;
+ const base = ossBase(app);
+ const fallback = role === 'zuzhang' ? 'beijing/zuzhangbeijing.jpg' : 'beijing/haibaobeijing.jpg';
+ const path = rel || fallback;
+ return path.startsWith('http') ? path : base + path;
+}
+
+export async function refreshPosterConfig(app) {
+ app = app || getApp();
+ try {
+ const token = wx.getStorageSync('token');
+ const header = buildClubHeaders({ 'Content-Type': 'application/json' });
+ if (token) header.Authorization = 'Bearer ' + token;
+ const res = await new Promise((resolve, reject) => {
+ wx.request({
+ url: app.globalData.apiBaseUrl + '/peizhi/haibaopz',
+ method: 'POST',
+ header,
+ success: (r) => resolve(r),
+ fail: reject,
+ });
+ });
+ const body = res?.data;
+ if (body && body.code === 0 && body.data && body.data.poster) {
+ app.globalData.posterConfig = body.data.poster;
+ if (body.data.club_id) app.globalData.clubId = body.data.club_id;
+ return body.data.poster;
+ }
+ } catch (e) {
+ console.warn('refreshPosterConfig failed', e);
+ }
+ return getPosterConfig(app);
+}
diff --git a/utils/order-tags.js b/utils/order-tags.js
new file mode 100644
index 0000000..fdc0575
--- /dev/null
+++ b/utils/order-tags.js
@@ -0,0 +1,47 @@
+/** 订单标签 texiao_json 规范化(兼容字符串 / 对象) */
+export function parseTexiaoJson(raw) {
+ if (!raw) return {};
+ if (typeof raw === 'object') return { ...raw };
+ if (typeof raw === 'string') {
+ try {
+ const parsed = JSON.parse(raw);
+ return typeof parsed === 'object' && parsed ? { ...parsed } : {};
+ } catch (e) {
+ return {};
+ }
+ }
+ return {};
+}
+
+/** 合并顶层 color / flash 与 texiao_json */
+export function mergeTagTexiao(tag) {
+ const texiao = parseTexiaoJson(tag.texiao_json);
+ const color = tag.color || texiao.color || texiao.bg_color;
+ if (color) {
+ texiao.color = color;
+ }
+ if (tag.flash_enabled != null && texiao.flash == null) {
+ texiao.flash = !!tag.flash_enabled;
+ }
+ return texiao;
+}
+
+export function normalizeTagList(list) {
+ if (!Array.isArray(list)) return [];
+ return list.map((tag) => ({
+ ...tag,
+ id: tag.id,
+ mingcheng: tag.mingcheng || tag.name || '',
+ texiao_json: mergeTagTexiao(tag),
+ }));
+}
+
+export function normalizeOrderTags(item) {
+ return {
+ xuqiu_biaoqian: normalizeTagList(item.xuqiu_biaoqian),
+ dashou_biaoqian: normalizeTagList(item.dashou_biaoqian),
+ shangjia_biaoqian: normalizeTagList(item.shangjia_biaoqian),
+ shangjia_identity_biaoqian: normalizeTagList(item.shangjia_identity_biaoqian),
+ zhiding_identity_biaoqian: normalizeTagList(item.zhiding_identity_biaoqian),
+ };
+}
diff --git a/utils/phone-auth.js b/utils/phone-auth.js
index f34d990..9302db7 100644
--- a/utils/phone-auth.js
+++ b/utils/phone-auth.js
@@ -1,7 +1,5 @@
/**
- * 手机号强制认证 - 完全自包含逻辑模块
- *
- * check / ensurePhoneAuth 每次均请求后端 /peizhi/yhbdsjh 判断 need_auth
+ * 手机号强制认证:每次调用 check / ensurePhoneAuth 均请求后端 /peizhi/yhbdsjh
*/
const API_BASE = 'https://www.abas.asia/hqhd';
@@ -9,18 +7,29 @@ const AUTH_CHECK_URL = '/peizhi/yhbdsjh';
const AUTH_SUBMIT_URL = '/yonghu/xiugai';
const AUTH_PAGE = '/pages/phone-auth/phone-auth';
const RETURN_ROLE_KEY = 'phone_auth_return_role';
+const RETURN_PAGE_KEY = 'phone_auth_return_page';
+
+function buildHeaders(extra = {}) {
+ const token = wx.getStorageSync('token');
+ const header = { 'Content-Type': 'application/json', ...extra };
+ if (token) header['Authorization'] = 'Bearer ' + token;
+ try {
+ const { buildClubHeaders } = require('./club-context.js');
+ return buildClubHeaders(header);
+ } catch (e) {
+ const clubId = wx.getStorageSync('club_id') || 'xq';
+ header['X-Club-Id'] = clubId;
+ return header;
+ }
+}
function innerRequest(url, data = {}) {
return new Promise((resolve, reject) => {
- const token = wx.getStorageSync('token');
- const header = { 'Content-Type': 'application/json' };
- if (token) header['Authorization'] = 'Bearer ' + token;
-
wx.request({
url: API_BASE + url,
method: 'POST',
data,
- header,
+ header: buildHeaders(),
success: (res) => resolve(res),
fail: (err) => reject(err),
});
@@ -43,7 +52,7 @@ function innerUpload(url, filePath, formData = {}, fileName = 'avatar') {
filePath,
name: fileName,
formData,
- header: { Authorization: 'Bearer ' + token },
+ header: buildHeaders({ Authorization: 'Bearer ' + token }),
success: (res) => {
if (res.statusCode === 200) {
try {
@@ -92,10 +101,29 @@ function parseCheckResponse(res) {
return { ok: true, needAuth: !!needAuth };
}
-/**
- * 询问后端是否需要手机号认证
- * @returns {Promise} true=需要认证
- */
+/** 根据当前主端/身份推断认证完成后回跳角色 */
+function resolveReturnRole() {
+ const primary = wx.getStorageSync('primaryRole') || wx.getStorageSync('currentRole') || '';
+ if (primary === 'dashou' || primary === 'shangjia') return primary;
+ if (Number(wx.getStorageSync('shangjiastatus')) === 1) return 'shangjia';
+ if (Number(wx.getStorageSync('staffstatus')) === 1) return 'shangjia';
+ if (
+ Number(wx.getStorageSync('dashoustatus')) === 1
+ || Number(wx.getStorageSync('guanshistatus')) === 1
+ || Number(wx.getStorageSync('zuzhangstatus')) === 1
+ || Number(wx.getStorageSync('kaoheguanstatus')) === 1
+ ) {
+ return 'dashou';
+ }
+ return 'mine';
+}
+
+function defaultReturnPage(role) {
+ if (role === 'dashou') return '/pages/accept-order/accept-order';
+ if (role === 'shangjia') return '/pages/merchant-home/merchant-home';
+ return '/pages/mine/mine';
+}
+
async function check() {
const token = wx.getStorageSync('token');
if (!token) return false;
@@ -110,9 +138,13 @@ async function check() {
}
}
-function redirectToPhoneAuth(returnRole) {
- if (returnRole) {
- wx.setStorageSync(RETURN_ROLE_KEY, returnRole);
+function redirectToPhoneAuth(returnRole, returnPage) {
+ const role = returnRole || resolveReturnRole();
+ wx.setStorageSync(RETURN_ROLE_KEY, role);
+ if (returnPage) {
+ wx.setStorageSync(RETURN_PAGE_KEY, returnPage);
+ } else {
+ wx.removeStorageSync(RETURN_PAGE_KEY);
}
if (!isOnPhoneAuthPage()) {
wx.reLaunch({ url: AUTH_PAGE });
@@ -120,26 +152,32 @@ function redirectToPhoneAuth(returnRole) {
}
/**
- * 打手端等场景:向后端确认,未认证则跳转认证页
- * @returns {Promise} true=已通过或无需认证;false=已跳转认证页
+ * 向后端确认是否需要手机号认证;需要则跳转认证页
+ * @returns {Promise} true=无需认证或已满足;false=已跳转认证页
*/
async function ensurePhoneAuth(options = {}) {
- const { redirect = true, role = 'dashou' } = options;
+ const { redirect = true, role, returnPage } = options;
const token = wx.getStorageSync('token');
if (!token) return true;
const needAuth = await check();
if (!needAuth) return true;
- if (redirect) redirectToPhoneAuth(role);
+ if (redirect) {
+ redirectToPhoneAuth(role || resolveReturnRole(), returnPage);
+ }
return false;
}
function getPhoneAuthReturnPage() {
- const role = wx.getStorageSync(RETURN_ROLE_KEY) || '';
+ const savedPage = wx.getStorageSync(RETURN_PAGE_KEY);
+ wx.removeStorageSync(RETURN_PAGE_KEY);
+ if (savedPage) {
+ wx.removeStorageSync(RETURN_ROLE_KEY);
+ return savedPage;
+ }
+ const role = wx.getStorageSync(RETURN_ROLE_KEY) || resolveReturnRole();
wx.removeStorageSync(RETURN_ROLE_KEY);
- if (role === 'dashou') return '/pages/accept-order/accept-order';
- if (role === 'shangjia') return '/pages/merchant-orders/merchant-orders';
- return '/pages/mine/mine';
+ return defaultReturnPage(role);
}
async function submit(phoneCode, avatarPath) {
@@ -166,4 +204,5 @@ module.exports = {
ensurePhoneAuth,
redirectToPhoneAuth,
getPhoneAuthReturnPage,
+ resolveReturnRole,
};
diff --git a/utils/poster-page.js b/utils/poster-page.js
new file mode 100644
index 0000000..c85b939
--- /dev/null
+++ b/utils/poster-page.js
@@ -0,0 +1,30 @@
+/** 推广海报页:按俱乐部分缓存二维码与背景 */
+import { getClubId } from './club-context.js';
+import { resolvePosterBg, refreshPosterConfig } from './miniapp-icons.js';
+
+export function posterQrCacheKey(role) {
+ const clubId = getClubId();
+ return role === 'zuzhang'
+ ? `zuzhang_haibao_url_${clubId}`
+ : `guanshi_haibao_url_${clubId}`;
+}
+
+export function posterInviteCacheKey() {
+ return `zuzhang_yaoqingma_${getClubId()}`;
+}
+
+export function getFullImageUrl(url, app) {
+ app = app || getApp();
+ if (!url) return '';
+ const oss = app.globalData.ossImageUrl || '';
+ return url.startsWith('http') ? url : oss + url;
+}
+
+export async function loadPosterPageConfig(role, app) {
+ app = app || getApp();
+ await refreshPosterConfig(app);
+ return {
+ bgUrl: resolvePosterBg(app, role),
+ qrCacheKey: posterQrCacheKey(role),
+ };
+}
diff --git a/utils/primary-role.js b/utils/primary-role.js
index f37a34f..cb949e3 100644
--- a/utils/primary-role.js
+++ b/utils/primary-role.js
@@ -1,5 +1,6 @@
/** 三端固定:normal | dashou | shangjia,认证后不可回退 */
+import { isStaffMode } from './staff-api.js';
import { ensurePhoneAuth } from './phone-auth.js';
const VALID = ['normal', 'dashou', 'shangjia'];
@@ -55,6 +56,9 @@ export function getPrimaryRole(app) {
if (isRoleStatusActive(wx.getStorageSync('shangjiastatus'))) {
return 'shangjia';
}
+ if (isStaffMode()) {
+ return 'shangjia';
+ }
return 'normal';
}
@@ -85,7 +89,7 @@ export function clearPrimaryRole(app) {
export const PRIMARY_DEFAULT_PAGES = {
normal: '/pages/mine/mine',
dashou: '/pages/accept-order/accept-order',
- shangjia: '/pages/merchant-orders/merchant-orders',
+ shangjia: '/pages/merchant-home/merchant-home',
};
/** 锁定主端并跳转到该端默认首页,同时建立 IM 长连接 */
@@ -107,8 +111,8 @@ function finishEnterLockedRole(role, app) {
export function enterLockedRole(role, app) {
if (!VALID.includes(role) || role === 'normal') return false;
- if (role === 'dashou') {
- ensurePhoneAuth({ redirect: true, role: 'dashou' }).then((ok) => {
+ if (role === 'dashou' || role === 'shangjia') {
+ ensurePhoneAuth({ redirect: true, role }).then((ok) => {
if (ok) finishEnterLockedRole(role, app);
});
return true;
diff --git a/utils/request.js b/utils/request.js
index 4204ca1..4aae63a 100644
--- a/utils/request.js
+++ b/utils/request.js
@@ -1,11 +1,11 @@
// utils/request.js
+import { buildClubHeaders } from './club-context';
+
function request(options) {
const app = getApp();
const token = wx.getStorageSync('token');
-
- // 🔥 没有 token 时不发送请求,直接返回一个“空响应”对象,不影响后续代码
+
if (!token) {
- // 返回一个模拟的响应,状态码为 401,但不会触发任何弹窗或跳转
return Promise.resolve({
statusCode: 401,
data: { code: 401, msg: '未登录' },
@@ -13,10 +13,10 @@ function request(options) {
});
}
- const header = {
+ const header = buildClubHeaders({
'Content-Type': 'application/json',
...options.header,
- };
+ });
if (token) {
header['Authorization'] = 'Bearer ' + token;
}
@@ -24,13 +24,12 @@ function request(options) {
return new Promise((resolve, reject) => {
wx.request({
url: app.globalData.apiBaseUrl + options.url,
- method: options.method,
+ method: options.method || 'GET',
data: options.data || {},
header,
+ timeout: options.timeout || 15000,
success: async (res) => {
if (res.statusCode === 401 || res.statusCode === 403) {
- // 注意:这里的弹窗逻辑只会在有 token 且 token 失效时触发
- // 无 token 的情况已经在上面直接返回,不会走到这里
if (app.globalData.loginPromise) {
try {
await app.globalData.loginPromise;
@@ -65,9 +64,20 @@ function request(options) {
}
resolve(res);
},
- fail: reject,
+ fail: (err) => {
+ // 网络层失败(超时/域名不可达等),避免未捕获 Promise 触发 MiniProgramError 红屏
+ console.warn('request fail:', options.url, err && err.errMsg);
+ resolve({
+ statusCode: 0,
+ data: {
+ code: 408,
+ msg: (err && err.errMsg) || '网络请求失败',
+ },
+ errMsg: (err && err.errMsg) || 'request:fail',
+ });
+ },
});
});
}
-export default request;
\ No newline at end of file
+export default request;
diff --git a/utils/role-tab-bar.js b/utils/role-tab-bar.js
index 8d80a97..39f766f 100644
--- a/utils/role-tab-bar.js
+++ b/utils/role-tab-bar.js
@@ -183,6 +183,11 @@ export function resetGuestSession(page, options = {}) {
app.globalData.shangpinleixing = [];
app.globalData.shangpinzhuanqu = [];
app.globalData.shangpinliebiao = [];
+ app.globalData._acceptOrderSessionReady = false;
+ app.globalData._acceptOrderPageCache = null;
+ app.globalData._acceptOrderPopupDone = false;
+ app.globalData._dashouPhoneChecked = false;
+ app.globalData._shangjiaPhoneChecked = false;
app.emitEvent('currentRoleChanged', { role: 'normal' });
refreshTabBar(page);
@@ -244,8 +249,9 @@ export function reconnectForRole(role) {
const connected = status === 'connected' || status === 'reconnected';
if (connected && currentUserId === targetUserId) {
- if (app.loadConversations) app.loadConversations();
+ if (app.restoreTabBarBadge) app.restoreTabBarBadge();
if (app.ensureConnection) app.ensureConnection();
+ if (app.loadConversations) app.loadConversations();
return;
}
diff --git a/utils/scriptService.js b/utils/scriptService.js
new file mode 100644
index 0000000..635e649
--- /dev/null
+++ b/utils/scriptService.js
@@ -0,0 +1,127 @@
+// utils/scriptService.js — 客服话术拉取与自动回复匹配
+import request from './request.js';
+
+const DEFAULT_SCRIPTS = {
+ chat_image_confirm: {
+ title: '温馨提示',
+ content: '平台禁止任何违法违规行为,聊天内容仅限于商家与接单员正常业务对接。严禁赌博、诈骗及其他非法行为,违者后果自负。',
+ confirm_text: '确认',
+ cancel_text: '取消',
+ },
+ cs_welcome: {
+ content: '你好,请问有什么可以帮到您的?',
+ },
+};
+
+const textCache = {};
+const TEXT_CACHE_TTL = 5 * 60 * 1000;
+
+function fitModalBtn(text, fallback) {
+ const t = (text || fallback || '确定').trim();
+ if (t && t.length <= 4) return t;
+ return fallback || '确定';
+}
+
+function openConfirmModal(script, onConfirm, onCancel) {
+ wx.showModal({
+ title: ((script.title || '提示').trim()).slice(0, 32),
+ content: script.content || '',
+ confirmText: fitModalBtn(script.confirm_text, '确认'),
+ cancelText: fitModalBtn(script.cancel_text, '取消'),
+ success: (res) => {
+ if (res.confirm) onConfirm && onConfirm();
+ else onCancel && onCancel();
+ },
+ fail: () => onCancel && onCancel(),
+ });
+}
+
+function mergeScript(sceneKey, remote) {
+ const base = DEFAULT_SCRIPTS[sceneKey] || {};
+ if (!remote) return { ...base };
+ return { ...base, ...remote };
+}
+
+export async function fetchScripts(sceneKeys) {
+ if (!sceneKeys || !sceneKeys.length) return {};
+
+ const now = Date.now();
+ const cached = {};
+ const needFetch = [];
+
+ sceneKeys.forEach((key) => {
+ const entry = textCache[key];
+ if (entry && now - entry.time < TEXT_CACHE_TTL) {
+ cached[key] = entry.data;
+ } else {
+ needFetch.push(key);
+ }
+ });
+
+ if (needFetch.length) {
+ try {
+ const res = await request({
+ url: '/peizhi/huashuhq',
+ method: 'POST',
+ data: { scene_keys: needFetch },
+ });
+ const payload = (res && res.data && res.data.code === 200) ? res.data.data || {} : {};
+ needFetch.forEach((key) => {
+ textCache[key] = { time: now, data: payload[key] };
+ cached[key] = payload[key];
+ });
+ } catch (e) {
+ console.warn('fetchScripts failed', e);
+ }
+ }
+
+ const result = {};
+ sceneKeys.forEach((key) => {
+ result[key] = mergeScript(key, cached[key]);
+ });
+ return result;
+}
+
+export async function showConfirmByScene(sceneKey, onConfirm, onCancel) {
+ try {
+ const data = await fetchScripts([sceneKey]);
+ openConfirmModal(data[sceneKey] || mergeScript(sceneKey, null), onConfirm, onCancel);
+ } catch (e) {
+ openConfirmModal(mergeScript(sceneKey, null), onConfirm, onCancel);
+ }
+}
+
+export async function matchAutoReply(userText) {
+ if (!userText || !userText.trim()) {
+ return { matched: false, content: '', reply_type: 'text' };
+ }
+ try {
+ const res = await request({
+ url: '/peizhi/huashu_match',
+ method: 'POST',
+ data: {
+ scene_key: 'cs_auto_reply',
+ user_text: userText.trim(),
+ },
+ });
+ if (res && res.data && res.data.code === 200 && res.data.data) {
+ return res.data.data;
+ }
+ } catch (e) {
+ console.warn('matchAutoReply failed', e);
+ }
+ return { matched: false, content: '', reply_type: 'text' };
+}
+
+export async function getWelcomeText() {
+ const data = await fetchScripts(['cs_welcome']);
+ const script = data.cs_welcome || DEFAULT_SCRIPTS.cs_welcome;
+ return script.content || DEFAULT_SCRIPTS.cs_welcome.content;
+}
+
+export default {
+ fetchScripts,
+ showConfirmByScene,
+ matchAutoReply,
+ getWelcomeText,
+};
diff --git a/utils/staff-api.js b/utils/staff-api.js
index 3f5943f..b964f86 100644
--- a/utils/staff-api.js
+++ b/utils/staff-api.js
@@ -46,6 +46,8 @@ export const STAFF_API = {
penaltyApply: `${STAFF_PREFIX}/order/penalty-apply`,
penaltyManage: `${STAFF_PREFIX}/order/penalty-manage`,
changePlayer: `${STAFF_PREFIX}/order/change-player`,
+ orderStats: `${STAFF_PREFIX}/order/stats`,
+ memberUpdateRemark: `${STAFF_PREFIX}/member/update-remark`,
};
export function getStaffContext() {
@@ -222,8 +224,9 @@ export function syncStaffUi(page) {
const ctx = staff ? (getStaffContext() || {}) : null;
const wallet = (ctx && ctx.wallet) || {};
const portal = isMerchantPortalUser();
+ const staffFlag = Number(wx.getStorageSync('staffstatus')) === 1;
page.setData({
- isShangjia: portal,
+ isShangjia: portal || staffFlag || !!(page.data && page.data.isShangjia),
isStaffMode: staff,
isMerchantOwner: !staff && Number(wx.getStorageSync('shangjiastatus')) === 1,
staffRoleName: staff ? (ctx.role_name || '客服') : '',
diff --git a/utils/upload.js b/utils/upload.js
index 060e5ee..971507c 100644
--- a/utils/upload.js
+++ b/utils/upload.js
@@ -1,5 +1,6 @@
// utils/upload.js
import request from './request.js'
+import { buildClubHeaders } from './club-context.js'
const app = getApp()
@@ -39,9 +40,9 @@ const upload = async (options) => {
filePath,
name: fileName,
formData,
- header: {
+ header: buildClubHeaders({
'Authorization': `Bearer ${token}`
- },
+ }),
success: (res) => {
if (res.statusCode === 200) {
diff --git a/utils/xiaoxilj.js b/utils/xiaoxilj.js
index d934f09..a8c7c95 100644
--- a/utils/xiaoxilj.js
+++ b/utils/xiaoxilj.js
@@ -1,215 +1,296 @@
/**
- * 连接管理模块 - xiaoxilj.js (根治发送失败:跳转前确保群组已订阅)
- * 从详情页跳转订单群聊时,提前订阅群组,避免发送消息时订阅未完成而失败
+ * 订单群聊跳转:与文赫一致,新群用打手+商家/老板配对 groupId;旧 group_{订单号} 会话保留
*/
+import request from './request';
+import { persistGroupMeta } from './im-user.js';
+import { resolveLocalGroupId } from './group-chat.js';
+
const app = getApp();
-function waitForConnection(expectedUserId, timeout = 10000) {
- return new Promise((resolve, reject) => {
- const timer = setTimeout(() => {
- app.off('connectionChanged', handler);
- reject(new Error('连接超时'));
- }, timeout);
+function formatError(err) {
+ if (!err) return '进入聊天失败';
+ if (typeof err === 'string') return err;
+ if (err.message) return err.message;
+ if (err.msg) return String(err.msg);
+ if (err.content) return String(err.content);
+ if (err.code) return `连接失败(${err.code})`;
+ try {
+ return JSON.stringify(err);
+ } catch (e) {
+ return '进入聊天失败';
+ }
+}
- const handler = (event) => {
- if (event.status === 'connected') {
- if (event.userId === expectedUserId) {
- clearTimeout(timer);
- app.off('connectionChanged', handler);
- resolve();
- } else {
- console.error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`);
- wx.removeStorageSync('savedGoEasyConnection');
- wx.removeStorageSync('goEasyUserId');
- wx.removeStorageSync('currentGoEasyIdentity');
- if (app.clearSavedConnection) app.clearSavedConnection();
- clearTimeout(timer);
- app.off('connectionChanged', handler);
- reject(new Error(`连接身份不匹配: 期望 ${expectedUserId}, 实际 ${event.userId}`));
- }
- } else if (event.status === 'disconnected' && !event.manual) {
- wx.removeStorageSync('savedGoEasyConnection');
- wx.removeStorageSync('goEasyUserId');
- wx.removeStorageSync('currentGoEasyIdentity');
- if (app.clearSavedConnection) app.clearSavedConnection();
- clearTimeout(timer);
- app.off('connectionChanged', handler);
- reject(new Error('连接失败'));
- }
- };
- app.on('connectionChanged', handler);
+function withTimeout(promise, ms, errMsg) {
+ return new Promise((resolve, reject) => {
+ const timer = setTimeout(() => reject(new Error(errMsg || '操作超时')), ms);
+ promise
+ .then((v) => { clearTimeout(timer); resolve(v); })
+ .catch((e) => { clearTimeout(timer); reject(e); });
});
}
+function mapIdentityForApi(identityType) {
+ if (identityType === 'dashou') return 'dashou';
+ if (identityType === 'shangjia') return 'shangjia';
+ return 'normal';
+}
+
+function validateIdentity(identityType, userId) {
+ if (identityType === 'dashou' && !userId.startsWith('Ds')) {
+ throw new Error('接单员 ID 必须以 Ds 开头');
+ }
+ if (identityType === 'shangjia' && !userId.startsWith('Sj')) {
+ throw new Error('商家 ID 必须以 Sj 开头');
+ }
+ if ((identityType === 'boss' || identityType === 'normal') && !userId.startsWith('Boss')) {
+ throw new Error('老板 ID 必须以 Boss 开头');
+ }
+}
+
+function getConnectedUserId() {
+ const fromState = app.globalData?.goEasyConnection?.userId;
+ const fromIm = wx.goEasy?.im?.userId;
+ return fromState || fromIm || '';
+}
+
+function isImConnected() {
+ const status = wx.goEasy?.getConnectionStatus?.() || 'disconnected';
+ return status === 'connected' || status === 'reconnected';
+}
+
+async function ensureIdentityConnection(identityType, userId) {
+ validateIdentity(identityType, userId);
+
+ app.globalData.currentRole = identityType;
+ wx.setStorageSync('currentRole', identityType);
+
+ const uid = userId.replace(/^(Ds|Sj|Boss)/, '');
+ const avatar = wx.getStorageSync('touxiang') ||
+ (app.globalData.ossImageUrl + app.globalData.morentouxiang);
+ app.globalData.currentUser = {
+ id: userId,
+ name: app.globalData.currentUser?.name || `用户${uid}`,
+ avatar,
+ };
+
+ if (!app.globalData.chatEnabled || !wx.goEasy?.im) {
+ throw new Error('聊天服务未就绪,请稍后重试');
+ }
+
+ if (isImConnected() && getConnectedUserId() === userId) {
+ return;
+ }
+
+ const connectedId = getConnectedUserId();
+ if (connectedId && connectedId !== userId && app.disconnectGoEasy) {
+ await app.disconnectGoEasy();
+ }
+
+ if (!app.connectWithIdentity) {
+ throw new Error('聊天功能未初始化');
+ }
+
+ await withTimeout(
+ app.connectWithIdentity(identityType, userId, true),
+ 12000,
+ 'IM连接超时'
+ );
+
+ if (!isImConnected()) {
+ throw new Error('IM连接失败,请检查网络后重试');
+ }
+}
+
+async function prepareGroupChat(identityType, userId, orderId, partnerUid, fadanPingtai, groupName, isCross) {
+ const orderIdStr = String(orderId || '').replace(/^group_/, '');
+ let chatData = null;
+
+ try {
+ const res = await withTimeout(
+ request({
+ url: '/dingdan/ltdhzb',
+ method: 'POST',
+ data: {
+ dingdan_id: orderIdStr,
+ identityType: mapIdentityForApi(identityType),
+ push_order_card: false,
+ },
+ }),
+ 12000,
+ '准备群聊超时'
+ );
+ const body = res?.data || {};
+ if ((body.code === 0 || body.code === 200) && body.data?.groupId) {
+ chatData = body.data;
+ } else if (body.msg) {
+ console.warn('ltdhzb:', body.msg);
+ }
+ } catch (e) {
+ console.warn('ltdhzb 请求失败,尝试本地配对 groupId', e);
+ }
+
+ if (!chatData?.groupId) {
+ const myUid = userId.replace(/^(Ds|Sj|Boss)/, '');
+ let localGroupId = resolveLocalGroupId(
+ identityType, myUid, partnerUid, fadanPingtai, orderIdStr, isCross
+ );
+ if (!localGroupId && orderIdStr) {
+ localGroupId = `group_${orderIdStr}`;
+ }
+ if (!localGroupId) {
+ throw new Error('无法确定群聊,请确认订单已接单且对方信息完整');
+ }
+ chatData = {
+ groupId: localGroupId,
+ orderId: orderIdStr,
+ groupName: groupName || '订单群聊',
+ isCross: isCross || fadanPingtai || 0,
+ };
+ try {
+ await request({
+ url: '/dingdan/ltdhzb',
+ method: 'POST',
+ data: {
+ dingdan_id: orderIdStr,
+ identityType: mapIdentityForApi(identityType),
+ push_order_card: false,
+ },
+ });
+ } catch (e) { /* ignore */ }
+ }
+
+ return chatData;
+}
+
class ConnectionManager {
- // 原有的私聊方法保持不变
async connectAndChat(params) {
const { identityType, userId, targetUser } = params;
if (!identityType || !userId || !targetUser || !targetUser.id) {
throw new Error('参数不完整');
}
- if (identityType === 'dashou' && !userId.startsWith('Ds')) {
- throw new Error(`接单员身份的用户ID必须以Ds开头,实际为 ${userId}`);
- }
- if (identityType === 'shangjia' && !userId.startsWith('Sj')) {
- throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`);
- }
- if (identityType === 'boss' && !userId.startsWith('Boss')) {
- throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`);
- }
+ await ensureIdentityConnection(identityType, userId);
- wx.removeStorageSync('savedGoEasyConnection');
- wx.removeStorageSync('goEasyUserId');
- wx.removeStorageSync('currentGoEasyIdentity');
- if (app.clearSavedConnection) app.clearSavedConnection();
+ const currentUser = {
+ id: userId,
+ name: app.globalData.currentUser?.name || '用户',
+ avatar: app.globalData.currentUser?.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
+ };
- if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') {
- wx.goEasy.disconnect();
- }
+ const to = {
+ id: targetUser.id,
+ name: targetUser.name || '用户',
+ avatar: targetUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang),
+ };
- const waitPromise = waitForConnection(userId);
- app.connectWithIdentity(identityType, userId, false);
-
- try {
- await waitPromise;
-
- const currentUser = {
- id: userId,
- name: app.globalData.currentUser?.name || '用户',
- avatar: app.globalData.currentUser?.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang)
- };
-
- const to = {
- id: targetUser.id,
- name: targetUser.name || '用户',
- avatar: targetUser.avatar || (app.globalData.ossImageUrl + app.globalData.morentouxiang)
- };
-
- const param = { to, currentUser };
- const path = '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param));
- wx.navigateTo({ url: path });
- } catch (err) {
- console.error('连接失败:', err);
- wx.showToast({ title: err.message || '连接失败', icon: 'none' });
- throw err;
- }
+ wx.navigateTo({
+ url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify({ to, currentUser })),
+ });
}
async connectToGroupChat(params) {
- const { identityType, userId, orderId, groupName, groupAvatar, isCross } = params;
+ const {
+ identityType, userId, orderId, groupName, groupAvatar, isCross,
+ partnerUid, fadanPingtai,
+ } = params;
+
if (!identityType || !userId || !orderId) {
- throw new Error('参数不完整:identityType, userId, orderId 必填');
+ throw new Error('参数不完整');
}
- // 校验 userId 前缀
- if (identityType === 'dashou' && !userId.startsWith('Ds')) {
- throw new Error(`接单员身份的用户ID必须以Ds开头,实际为 ${userId}`);
- }
- if (identityType === 'shangjia' && !userId.startsWith('Sj')) {
- throw new Error(`商家身份的用户ID必须以Sj开头,实际为 ${userId}`);
- }
- if (identityType === 'boss' && !userId.startsWith('Boss')) {
- throw new Error(`老板身份的用户ID必须以Boss开头,实际为 ${userId}`);
- }
-
-
- // 1. 同步全局角色,确保群聊页初始化正确
app.globalData.currentRole = identityType;
wx.setStorageSync('currentRole', identityType);
- const uid = userId.replace(/^(Ds|Sj|Boss|Gs|Zz)/, '');
- const avatar = wx.getStorageSync('touxiang') ||
- (app.globalData.ossImageUrl + app.globalData.morentouxiang);
- app.globalData.currentUser = {
- id: userId,
- name: app.globalData.currentUser?.name || `用户${uid}`,
- avatar: avatar
- };
+ wx.showLoading({ title: '建立联系中...', mask: true });
- // 2. 确保 GoEasy 已使用目标身份连接
- let needConnect = false;
- if (!wx.goEasy || !wx.goEasy.getConnectionStatus || wx.goEasy.getConnectionStatus() !== 'connected') {
- needConnect = true;
- } else {
- const currentUserId = wx.goEasy.im?.userId;
- if (currentUserId !== userId) {
- needConnect = true;
- }
- }
+ try {
+ const chatData = await prepareGroupChat(
+ identityType, userId, orderId, partnerUid, fadanPingtai || isCross, groupName, isCross
+ );
- if (needConnect) {
- wx.removeStorageSync('savedGoEasyConnection');
- wx.removeStorageSync('goEasyUserId');
- if (app.clearSavedConnection) app.clearSavedConnection();
- if (wx.goEasy && wx.goEasy.getConnectionStatus() === 'connected') {
- wx.goEasy.disconnect();
+ const realGroupId = chatData.groupId;
+ let avatar = chatData.counterpartAvatar || chatData.groupAvatar || groupAvatar || '';
+ if (avatar && !avatar.startsWith('http')) {
+ avatar = app.globalData.ossImageUrl + avatar.replace(/^\//, '');
}
- const waitPromise = waitForConnection(userId);
- app.connectWithIdentity(identityType, userId, false);
+
+ if (!app.globalData.groupInfoMap) app.globalData.groupInfoMap = {};
+ const meta = {
+ name: chatData.counterpartName || chatData.groupName || groupName,
+ avatar,
+ orderId: chatData.orderId || String(orderId).replace(/^group_/, ''),
+ orderDesc: chatData.orderDesc || '',
+ orderZhuangtai: chatData.orderZhuangtai,
+ orderJine: chatData.orderJine,
+ dashouGoEasyId: chatData.dashouGoEasyId,
+ partnerGoEasyId: chatData.partnerGoEasyId,
+ dashouYonghuid: chatData.dashouYonghuid,
+ partnerYonghuid: chatData.partnerYonghuid,
+ dashouName: chatData.dashouName,
+ partnerName: chatData.partnerName,
+ dashouAvatar: chatData.dashouAvatar,
+ partnerAvatar: chatData.partnerAvatar,
+ counterpartId: chatData.counterpartId,
+ counterpartYonghuid: chatData.counterpartYonghuid,
+ };
+ app.globalData.groupInfoMap[realGroupId] = meta;
+ persistGroupMeta(app, realGroupId, meta);
+
+ let imReady = false;
try {
- await waitPromise;
- } catch (err) {
- wx.showToast({ title: '连接失败', icon: 'none' });
- throw err;
+ await ensureIdentityConnection(identityType, userId);
+ imReady = true;
+ try {
+ await withTimeout(
+ new Promise((resolve, reject) => {
+ wx.goEasy.im.subscribeGroup({
+ groupIds: [realGroupId],
+ onSuccess: () => resolve(),
+ onFailed: (error) => reject(error),
+ });
+ }),
+ 8000,
+ '订阅群聊超时'
+ );
+ } catch (subErr) {
+ console.warn('订阅群聊失败,仍尝试进入页面', subErr);
+ }
+ } catch (imErr) {
+ console.warn('IM连接失败,仍进入聊天页由页面重连', imErr);
}
- }
- // 3. 从会话列表查找真实群组ID
- let realGroupId = null;
- try {
- const result = await new Promise((resolve, reject) => {
- wx.goEasy.im.latestConversations({
- onSuccess: (res) => {
- const conversations = res.content?.conversations || [];
- const found = conversations.find(c => c.type === 'group' && c.data && c.data.orderId === orderId);
- resolve(found ? found.groupId : null);
- },
- onFailed: reject
- });
- });
- realGroupId = result;
- } catch (err) {
- console.error('获取会话列表失败:', err);
- wx.showToast({ title: '获取群聊信息失败', icon: 'none' });
- throw err;
- }
+ const uid = userId.replace(/^(Ds|Sj|Boss)/, '');
+ const param = {
+ groupId: realGroupId,
+ orderId: chatData.orderId || String(orderId).replace(/^group_/, ''),
+ groupName: chatData.counterpartName || chatData.groupName || groupName || '订单群聊',
+ groupAvatar: avatar,
+ isCross: chatData.isCross != null ? chatData.isCross : (isCross || 0),
+ currentUserId: userId,
+ currentUserName: app.globalData.currentUser?.name || `用户${uid}`,
+ currentUserAvatar: app.globalData.currentUser?.avatar ||
+ (wx.getStorageSync('touxiang') || (app.globalData.ossImageUrl + app.globalData.morentouxiang)),
+ orderZhuangtai: chatData.orderZhuangtai,
+ orderJine: chatData.orderJine,
+ orderDesc: chatData.orderDesc || '',
+ imReady,
+ };
- if (!realGroupId) {
- wx.showToast({ title: '暂未创建群聊', icon: 'none' });
- return;
- }
-
- // 4. 🔥 关键:主动订阅群组并等待成功,确保发送消息时订阅已完成
- try {
- await new Promise((resolve, reject) => {
- wx.goEasy.im.subscribeGroup({
- groupIds: [realGroupId],
- onSuccess: () => {
- resolve();
- },
- onFailed: (error) => {
- console.error('订阅群组失败:', error);
- reject(error);
- }
- });
+ wx.hideLoading();
+ wx.navigateTo({
+ url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)),
+ fail: (navErr) => {
+ wx.showToast({ title: formatError(navErr), icon: 'none', duration: 2500 });
+ },
});
} catch (err) {
- wx.showToast({ title: '订阅群组失败', icon: 'none' });
+ wx.hideLoading();
+ console.error('跳转群聊失败:', err);
+ wx.showToast({ title: formatError(err), icon: 'none', duration: 2500 });
throw err;
}
-
- // 5. 跳转群聊页(参数与消息列表完全一致)
- const param = {
- groupId: realGroupId,
- orderId: orderId,
- groupName: groupName || '订单群聊',
- groupAvatar: groupAvatar || '',
- isCross: isCross || 0
- };
- const path = '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param));
- wx.navigateTo({ url: path });
}
}
-export default new ConnectionManager();
\ No newline at end of file
+export default new ConnectionManager();
diff --git a/utils/zhiding-order.js b/utils/zhiding-order.js
new file mode 100644
index 0000000..e3a8981
--- /dev/null
+++ b/utils/zhiding-order.js
@@ -0,0 +1,53 @@
+import request from './request.js';
+import { getDefaultAvatarUrl } from './avatar.js';
+
+export const ZHIDING_HF_MAP = { 1: '想接', 2: '已婉拒', 3: '等会接' };
+
+export async function fetchMyZhidingOrders() {
+ try {
+ const res = await request({ url: '/dingdan/zdcx', method: 'POST', data: {} });
+ const body = res?.data;
+ if (body && (body.code === 200 || body.code === 0) && body.data) {
+ return body.data.list || [];
+ }
+ } catch (e) {
+ console.warn('fetchMyZhidingOrders failed', e);
+ }
+ return [];
+}
+
+export async function submitZhidingResponse(dingdanId, huifu, dengHuiNote = '') {
+ const res = await request({
+ url: '/dingdan/zdhf',
+ method: 'POST',
+ data: {
+ dingdan_id: dingdanId,
+ huifu,
+ deng_hui_note: dengHuiNote,
+ },
+ });
+ return res?.data;
+}
+
+export function processZhidingList(list, app, uid, highlightOrderId = '') {
+ const defAvatar = getDefaultAvatarUrl(app);
+ const oss = app.globalData?.ossImageUrl || '';
+ return (list || []).map((item) => {
+ let avatar = defAvatar;
+ if (item.zhiding_avatar) {
+ avatar = item.zhiding_avatar.startsWith('http') ? item.zhiding_avatar : oss + item.zhiding_avatar;
+ }
+ return {
+ ...item,
+ isMyZhiding: true,
+ zhiding_avatar_full: avatar,
+ zhiding_hf_text: item.zhiding_hf_text || ZHIDING_HF_MAP[item.zhiding_hf] || '',
+ isHighlighted: highlightOrderId && item.dingdan_id === highlightOrderId,
+ };
+ }).filter((item) => String(item.zhiding_uid) === String(uid));
+}
+
+/** 横幅只展示尚未回复的指定单(已等会接/不想接的不占横幅) */
+export function filterZhidingBannerList(list) {
+ return (list || []).filter((item) => !item.zhiding_hf);
+}