Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc650762f8 | ||
|
|
684f392cb6 | ||
|
|
77fefbe8aa | ||
|
|
b9de9ea34e | ||
|
|
1c6c9a7ac0 | ||
|
|
eef2e95bd3 | ||
|
|
0067a63093 | ||
|
|
7eca128bb5 | ||
|
|
83a5a0aaf0 | ||
|
|
42b585274c | ||
|
|
cec1b477b4 | ||
|
|
e203223922 | ||
|
|
fdfd3a9524 | ||
|
|
ada903de07 | ||
|
|
a44be49ac6 | ||
|
|
283133473a | ||
|
|
4b064c6303 | ||
|
|
2a8f7c427c | ||
|
|
16eecd1278 | ||
|
|
09df206fd8 | ||
|
|
6f6dac422f | ||
|
|
782a18006e | ||
|
|
4b60ebbc10 | ||
|
|
566aeaa3b7 |
No files matched your search
@@ -3,6 +3,12 @@ import GoEasy from './static/lib/goeasy-2.13.24.esm.min';
|
|||||||
const ChatCore = require('./utils/chat-core');
|
const ChatCore = require('./utils/chat-core');
|
||||||
import { ensurePhoneAuth } from './utils/phone-auth';
|
import { ensurePhoneAuth } from './utils/phone-auth';
|
||||||
import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role';
|
import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role';
|
||||||
|
import { isFighterOnly, resolveFighterOnlyLaunchUrl } from './utils/fighter-only';
|
||||||
|
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;
|
const roleDefaultPage = PRIMARY_DEFAULT_PAGES;
|
||||||
@@ -36,7 +42,8 @@ App({
|
|||||||
guanshiqun: '',
|
guanshiqun: '',
|
||||||
guanshiqunid: '',
|
guanshiqunid: '',
|
||||||
|
|
||||||
appId:'wx0e4be86faac4a8d1',
|
appId: WX_APP_ID,
|
||||||
|
clubId: CLUB_ID,
|
||||||
|
|
||||||
shangjiastatus: 0,
|
shangjiastatus: 0,
|
||||||
dashoustatus: 0,
|
dashoustatus: 0,
|
||||||
@@ -49,11 +56,7 @@ App({
|
|||||||
yajin: null,
|
yajin: null,
|
||||||
chenghao: '',
|
chenghao: '',
|
||||||
jinfen: null,
|
jinfen: null,
|
||||||
clumber: [{
|
clumber: [],
|
||||||
huiyuanid: '',
|
|
||||||
huiyuanming: '',
|
|
||||||
daoqi: ''
|
|
||||||
}],
|
|
||||||
chengjiaoliang: null,
|
chengjiaoliang: null,
|
||||||
zaixianZhuangtai: null,
|
zaixianZhuangtai: null,
|
||||||
|
|
||||||
@@ -80,6 +83,8 @@ App({
|
|||||||
xshenfen: 1,
|
xshenfen: 1,
|
||||||
|
|
||||||
goEasyConfig: null,
|
goEasyConfig: null,
|
||||||
|
chatEnabled: false,
|
||||||
|
groupInfoMap: {},
|
||||||
kefuConfig: {
|
kefuConfig: {
|
||||||
link: '',
|
link: '',
|
||||||
enterpriseId: ''
|
enterpriseId: ''
|
||||||
@@ -151,6 +156,7 @@ App({
|
|||||||
pageState: {
|
pageState: {
|
||||||
currentPage: '',
|
currentPage: '',
|
||||||
isInChatPage: false,
|
isInChatPage: false,
|
||||||
|
isInGroupChat: false,
|
||||||
currentChatId: '',
|
currentChatId: '',
|
||||||
lastPageUpdate: 0
|
lastPageUpdate: 0
|
||||||
},
|
},
|
||||||
@@ -159,11 +165,23 @@ App({
|
|||||||
debugMode: false,
|
debugMode: false,
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
currentRole: 'normal',
|
currentRole: 'normal',
|
||||||
primaryRole: 'normal'
|
primaryRole: 'normal',
|
||||||
},
|
/** 客服浮钮:full | mini,onLaunch 重置为 full */
|
||||||
|
kefuFloatMode: 'full',
|
||||||
|
/** 本次启动内隐藏客服浮钮(不持久化,杀进程后恢复) */
|
||||||
|
kefuFloatSessionHidden: false,
|
||||||
|
kefuFloatY: null,
|
||||||
|
/** 从「我的」跳抢单页时高亮指定单 */
|
||||||
|
_acceptOrderHighlight: '',
|
||||||
|
},
|
||||||
|
|
||||||
// 核心启动流程
|
// 核心启动流程
|
||||||
async onLaunch() {
|
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.hideHomeButton();
|
||||||
wx.onAppRoute((res) => {
|
wx.onAppRoute((res) => {
|
||||||
@@ -184,7 +202,7 @@ App({
|
|||||||
}
|
}
|
||||||
|
|
||||||
migrateLegacyCenterRole(this);
|
migrateLegacyCenterRole(this);
|
||||||
const savedRole = getPrimaryRole(this);
|
const savedRole = isFighterOnly() ? 'dashou' : getPrimaryRole(this);
|
||||||
lockPrimaryRole(savedRole, this);
|
lockPrimaryRole(savedRole, this);
|
||||||
|
|
||||||
// ②b 冷启动:有 token 时先问后端是否需要手机号认证
|
// ②b 冷启动:有 token 时先问后端是否需要手机号认证
|
||||||
@@ -193,19 +211,27 @@ App({
|
|||||||
if (!phoneOk) return;
|
if (!phoneOk) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetPage = roleDefaultPage[savedRole] || '/pages/index/index';
|
// ②c 打手端冷启动:同步会员/押金等到 globalData(抢单页依赖 clumber)
|
||||||
if (savedRole !== 'normal') {
|
if (wx.getStorageSync('token') && savedRole === 'dashou') {
|
||||||
setTimeout(() => {
|
refreshDashouMembership(this).catch(() => {});
|
||||||
wx.reLaunch({ url: targetPage });
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ③ 应用本地缓存配置
|
// ③ 先应用本地缓存配置(必须在 reLaunch 抢单池之前,否则弹窗图片拼不出 OSS)
|
||||||
const cachedConfig = this.readConfigFromStorage();
|
const cachedConfig = this.readConfigFromStorage();
|
||||||
if (cachedConfig) {
|
if (cachedConfig) {
|
||||||
this.applyDynamicConfig(cachedConfig);
|
this.applyDynamicConfig(cachedConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 纯打手端:未登录必进登录页;已认证进抢单池
|
||||||
|
const targetPage = isFighterOnly()
|
||||||
|
? resolveFighterOnlyLaunchUrl()
|
||||||
|
: (roleDefaultPage[savedRole] || '/pages/index/index');
|
||||||
|
if (isFighterOnly() || savedRole !== 'normal') {
|
||||||
|
setTimeout(() => {
|
||||||
|
wx.reLaunch({ url: targetPage });
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// ④ 初始化
|
// ④ 初始化
|
||||||
this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化
|
this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化
|
||||||
ChatCore.initGlobalMessageSystem(this);
|
ChatCore.initGlobalMessageSystem(this);
|
||||||
@@ -214,13 +240,11 @@ App({
|
|||||||
this.emitEvent('staffContextChanged', {});
|
this.emitEvent('staffContextChanged', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⑤ 建立连接
|
// ⑤ 建立连接(文赫式:全局监听,不反复 disconnect)
|
||||||
const saved = this.getSavedConnection();
|
|
||||||
console.log('【启动】缓存身份:', saved ? saved.identityType : '无',
|
|
||||||
'userId:', saved ? saved.userId : '无');
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.startImWhenReady) this.startImWhenReady();
|
if (this.globalData.chatEnabled && this.ensureConnection) {
|
||||||
else if (this.ensureConnection) this.ensureConnection();
|
this.ensureConnection();
|
||||||
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
// ⑥ 获取远程配置
|
// ⑥ 获取远程配置
|
||||||
@@ -228,10 +252,16 @@ App({
|
|||||||
.then(latestConfig => {
|
.then(latestConfig => {
|
||||||
this.saveConfigToStorage(latestConfig);
|
this.saveConfigToStorage(latestConfig);
|
||||||
this.applyDynamicConfig(latestConfig);
|
this.applyDynamicConfig(latestConfig);
|
||||||
|
warmupPindaoConfig(this);
|
||||||
|
try {
|
||||||
|
const { fetchGonggaoLunbo } = require('./utils/display-config');
|
||||||
|
fetchGonggaoLunbo(this, 'accept_order').catch(() => {});
|
||||||
|
} catch (e) {}
|
||||||
this.initGoEasyWithConfig();
|
this.initGoEasyWithConfig();
|
||||||
this.initCurrentUser();
|
this.initCurrentUser();
|
||||||
if (this.startImWhenReady) this.startImWhenReady();
|
if (this.globalData.chatEnabled && this.ensureConnection) {
|
||||||
else if (this.connectForCurrentRole) this.connectForCurrentRole();
|
this.ensureConnection();
|
||||||
|
}
|
||||||
console.log('远程配置更新完成');
|
console.log('远程配置更新完成');
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -239,10 +269,25 @@ App({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 从后台切回前台时再次向后端校验 */
|
/** 从后台切回前台时再次向后端校验,并维持 IM 连接 */
|
||||||
async onShow() {
|
async onShow() {
|
||||||
if (!wx.getStorageSync('token')) return;
|
if (!wx.getStorageSync('token')) return;
|
||||||
await ensurePhoneAuth({ redirect: true });
|
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 +303,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() {
|
readConfigFromStorage() {
|
||||||
try {
|
try {
|
||||||
const data = wx.getStorageSync(this.CONFIG_CACHE_KEY);
|
const data = wx.getStorageSync(this.getConfigCacheKey());
|
||||||
if (data && typeof data === 'object') {
|
if (data && typeof data === 'object') {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -273,7 +323,7 @@ App({
|
|||||||
saveConfigToStorage(config) {
|
saveConfigToStorage(config) {
|
||||||
try {
|
try {
|
||||||
if (config && typeof config === 'object') {
|
if (config && typeof config === 'object') {
|
||||||
wx.setStorageSync(this.CONFIG_CACHE_KEY, config);
|
wx.setStorageSync(this.getConfigCacheKey(), config);
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
},
|
},
|
||||||
@@ -284,7 +334,7 @@ App({
|
|||||||
wx.request({
|
wx.request({
|
||||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
header: { 'content-type': 'application/json' },
|
header: buildClubHeaders({ 'content-type': 'application/json' }),
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) {
|
if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) {
|
||||||
resolve(res.data.data);
|
resolve(res.data.data);
|
||||||
@@ -307,7 +357,7 @@ App({
|
|||||||
wx.request({
|
wx.request({
|
||||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
header: { 'content-type': 'application/json' },
|
header: buildClubHeaders({ 'content-type': 'application/json' }),
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||||
resolve(res.data.data);
|
resolve(res.data.data);
|
||||||
@@ -350,6 +400,19 @@ App({
|
|||||||
enterpriseId: config.kefu.enterpriseId || ''
|
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 时初始化
|
// 仅在有效 appkey 时初始化
|
||||||
@@ -373,9 +436,10 @@ App({
|
|||||||
modules: ['im', 'pubsub']
|
modules: ['im', 'pubsub']
|
||||||
});
|
});
|
||||||
wx.GoEasy = GoEasy;
|
wx.GoEasy = GoEasy;
|
||||||
|
this.globalData.chatEnabled = true;
|
||||||
console.log('GoEasy 初始化成功');
|
console.log('GoEasy 初始化成功');
|
||||||
if (this.startImWhenReady && wx.getStorageSync('uid')) {
|
if (this.ensureConnection && wx.getStorageSync('uid')) {
|
||||||
setTimeout(() => this.startImWhenReady(), 100);
|
setTimeout(() => this.ensureConnection(), 100);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('GoEasy 初始化失败:', error);
|
console.error('GoEasy 初始化失败:', error);
|
||||||
@@ -385,10 +449,12 @@ App({
|
|||||||
initCurrentUser() {
|
initCurrentUser() {
|
||||||
const uid = wx.getStorageSync('uid');
|
const uid = wx.getStorageSync('uid');
|
||||||
if (uid) {
|
if (uid) {
|
||||||
|
const def = getDefaultAvatarUrl(this);
|
||||||
|
const avatar = resolveAvatarFromStorage(this) || def;
|
||||||
this.globalData.currentUser = {
|
this.globalData.currentUser = {
|
||||||
id: uid,
|
id: uid,
|
||||||
name: '用户' + uid.substring(0, 6),
|
name: wx.getStorageSync('nicheng') || ('用户' + uid.substring(0, 6)),
|
||||||
avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang
|
avatar: avatar || def,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,113 +1,318 @@
|
|||||||
{
|
{
|
||||||
"pages": [
|
"pages": [
|
||||||
|
"pages/fighter/fighter",
|
||||||
|
"pages/accept-order/accept-order",
|
||||||
|
"pages/team-hall/team-hall",
|
||||||
|
"pages/fighter-orders/fighter-orders",
|
||||||
|
"pages/messages/messages",
|
||||||
"pages/index/index",
|
"pages/index/index",
|
||||||
"pages/category/category",
|
"pages/category/category",
|
||||||
"pages/pick-user/pick-user",
|
|
||||||
"pages/messages/messages",
|
|
||||||
"pages/mine/mine",
|
"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-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/merchant-orders/merchant-orders",
|
"pages/merchant-orders/merchant-orders",
|
||||||
"pages/merchant-msg/merchant-msg",
|
"pages/merchant/merchant",
|
||||||
"pages/merchant-rank/merchant-rank",
|
|
||||||
"pages/merchant-recharge/merchant-recharge",
|
|
||||||
"pages/merchant-order-detail/merchant-order-detail",
|
|
||||||
"pages/fighter-order-detail/fighter-order-detail",
|
|
||||||
"pages/chat/chat",
|
|
||||||
"pages/express-order/express-order",
|
|
||||||
"pages/order-pool/order-pool",
|
|
||||||
"pages/poster/poster",
|
|
||||||
"pages/gold-fighter/gold-fighter",
|
|
||||||
"pages/leader/leader",
|
|
||||||
"pages/manager-assign/manager-assign",
|
|
||||||
"pages/leader-bonus-log/leader-bonus-log",
|
|
||||||
"pages/invite-manager/invite-manager",
|
|
||||||
"pages/order-pool2/order-pool2",
|
|
||||||
"pages/group-chat/group-chat",
|
|
||||||
"pages/cs-chat/cs-chat",
|
|
||||||
"pages/verify/verify",
|
|
||||||
"components/global-notification/global-notification",
|
"components/global-notification/global-notification",
|
||||||
"components/popup-notice/popup-notice",
|
"components/popup-notice/popup-notice",
|
||||||
"components/order-card/order-card",
|
"components/order-card/order-card",
|
||||||
"components/order-sender/order-sender",
|
"components/order-sender/order-sender",
|
||||||
"pages/penalty/penalty/penalty",
|
"components/chenghao-tag/chenghao-tag"
|
||||||
"pages/penalty/components/fakuan-list/fakuan-list",
|
],
|
||||||
"pages/penalty/components/jifen-list/jifen-list",
|
"subPackages": [
|
||||||
"pages/penalty/components/fakuan-pay/fakuan-pay",
|
{
|
||||||
"pages/phone-auth/phone-auth",
|
"root": "pages/dashouduan",
|
||||||
"components/chenghao-tag/chenghao-tag",
|
"pages": ["dashouduan"]
|
||||||
"pages/assessor/assessor",
|
},
|
||||||
"pages/assess-score/assess-score",
|
{
|
||||||
"pages/assess-log/assess-log",
|
"root": "pages/guanshiduan",
|
||||||
"pages/assess-center/assess-center",
|
"pages": ["guanshiduan"]
|
||||||
"pages/assess-gold/assess-gold",
|
},
|
||||||
"pages/escort-orders/escort-orders",
|
{
|
||||||
"pages/withdraw/components/mode1/mode1",
|
"root": "pages/pick-user",
|
||||||
"pages/withdraw/components/mode2/mode2"
|
"pages": ["pick-user"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/product-detail",
|
||||||
|
"pages": ["product-detail"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/submit",
|
||||||
|
"pages": ["submit"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/alipay-webview",
|
||||||
|
"pages": ["alipay-webview"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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/fund-freeze",
|
||||||
|
"pages": ["fund-freeze"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/role-agreement",
|
||||||
|
"pages": ["role-agreement"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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/gongdan",
|
||||||
|
"pages": [
|
||||||
|
"create/create",
|
||||||
|
"list/list",
|
||||||
|
"detail/detail",
|
||||||
|
"chongzhi-list/chongzhi-list"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": {
|
"usingComponents": {
|
||||||
"popup-notice": "/components/popup-notice/popup-notice",
|
"popup-notice": "/components/popup-notice/popup-notice",
|
||||||
"tab-bar": "/tab-bar/index"
|
"tab-bar": "/tab-bar/index"
|
||||||
},
|
},
|
||||||
|
|
||||||
"window": {
|
"window": {
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"navigationStyle": "default",
|
"navigationStyle": "default",
|
||||||
"backgroundTextStyle": "light",
|
"backgroundTextStyle": "light",
|
||||||
"navigationBarBackgroundColor": "#fff",
|
"navigationBarBackgroundColor": "#fff",
|
||||||
"navigationBarTitleText": "星阙网络"
|
"navigationBarTitleText": "龙先生电竞"
|
||||||
},
|
},
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"custom": true,
|
"custom": true,
|
||||||
"list": [
|
"list": [
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"pagePath": "pages/order-pool/order-pool",
|
"pagePath": "pages/accept-order/accept-order",
|
||||||
"text": "接单池",
|
"text": "接单池",
|
||||||
"iconPath": "/images/order-pool.png",
|
"iconPath": "/images/order-pool.png",
|
||||||
"selectedIconPath": "/images/order-pool.png"
|
"selectedIconPath": "/images/order-pool.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/order-pool2/order-pool2",
|
"pagePath": "pages/team-hall/team-hall",
|
||||||
"text": "接单池",
|
"text": "组队",
|
||||||
"iconPath": "/images/order-pool.png",
|
"iconPath": "/images/team-hall.png",
|
||||||
"selectedIconPath": "/images/order-pool.png"
|
"selectedIconPath": "/images/team-hall.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",
|
"style": "v2",
|
||||||
"sitemapLocation": "sitemap.json",
|
"sitemapLocation": "sitemap.json",
|
||||||
"lazyCodeLoading": "requiredComponents"
|
"lazyCodeLoading": "requiredComponents"
|
||||||
}
|
}
|
||||||
@@ -2,15 +2,6 @@
|
|||||||
|
|
||||||
/* ========== CSS 变量 ========== */
|
/* ========== CSS 变量 ========== */
|
||||||
page {
|
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-price: #ff4444;
|
||||||
--color-text-main: #333;
|
--color-text-main: #333;
|
||||||
--color-text-gray: #999;
|
--color-text-gray: #999;
|
||||||
@@ -467,7 +458,7 @@ page {
|
|||||||
|
|
||||||
.tag-warning {
|
.tag-warning {
|
||||||
background: rgba(250, 173, 20, 0.1);
|
background: rgba(250, 173, 20, 0.1);
|
||||||
color: #a855f7;
|
color: #faad14;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-danger {
|
.tag-danger {
|
||||||
@@ -477,7 +468,7 @@ page {
|
|||||||
|
|
||||||
.tag-gold {
|
.tag-gold {
|
||||||
background: rgba(201, 169, 98, 0.1);
|
background: rgba(201, 169, 98, 0.1);
|
||||||
color: #9333ea;
|
color: #C9A962;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== 页面容器 ========== */
|
/* ========== 页面容器 ========== */
|
||||||
@@ -524,8 +515,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary--gold {
|
.btn-primary--gold {
|
||||||
background: linear-gradient(135deg, #9333ea, #a855f7);
|
background: linear-gradient(135deg, #C9A962, #D4B56A);
|
||||||
box-shadow: 0 8rpx 20rpx rgba(147, 51, 234, 0.3);
|
box-shadow: 0 8rpx 20rpx rgba(201, 169, 98, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary--green {
|
.btn-primary--green {
|
||||||
@@ -539,8 +530,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary--orange {
|
.btn-primary--orange {
|
||||||
background: linear-gradient(135deg, #a855f7, #7c3aed);
|
background: linear-gradient(135deg, #ffb347, #ff8c1a);
|
||||||
box-shadow: 0 8rpx 20rpx rgba(124, 58, 237, 0.3);
|
box-shadow: 0 8rpx 20rpx rgba(255, 140, 26, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary--purple {
|
.btn-primary--purple {
|
||||||
@@ -574,8 +565,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm--gold {
|
.btn-sm--gold {
|
||||||
background: linear-gradient(135deg, #c4b5fd, #9333ea);
|
background: linear-gradient(135deg, #ffcc00, #ffaa00);
|
||||||
box-shadow: 0 6rpx 16rpx rgba(147, 51, 234, 0.3);
|
box-shadow: 0 6rpx 16rpx rgba(255, 170, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm--green {
|
.btn-sm--green {
|
||||||
@@ -613,8 +604,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-ghost--gold {
|
.btn-ghost--gold {
|
||||||
color: #9333ea;
|
color: #C9A962;
|
||||||
border-color: #9333ea;
|
border-color: #C9A962;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 禁用状态 */
|
/* 禁用状态 */
|
||||||
@@ -863,8 +854,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-tag--warning {
|
.status-tag--warning {
|
||||||
background: #faf5ff;
|
background: #fffbe6;
|
||||||
color: #a855f7;
|
color: #faad14;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-tag--info {
|
.status-tag--info {
|
||||||
@@ -971,8 +962,8 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes crownFloat {
|
@keyframes crownFloat {
|
||||||
0%, 100% { transform: translateY(0) rotate(5deg) scale(1); filter: drop-shadow(0 0 10rpx rgba(196, 181, 253, 0.8)); }
|
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(196, 181, 253, 1)); }
|
50% { transform: translateY(-15rpx) rotate(10deg) scale(1.1); filter: drop-shadow(0 0 25rpx rgba(255, 215, 0, 1)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes haloRotate {
|
@keyframes haloRotate {
|
||||||
@@ -1112,14 +1103,14 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chat-order-bubble {
|
.chat-order-bubble {
|
||||||
background: #f5f3ff;
|
background: #fff7e0;
|
||||||
padding: 12rpx;
|
padding: 12rpx;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-order-label {
|
.chat-order-label {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #a855f7;
|
color: #e6a23c;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1614,7 +1605,7 @@ page {
|
|||||||
|
|
||||||
.rank-card--1 .rank-podium-base { height: 80rpx; }
|
.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-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); }
|
.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;
|
font-size: 85rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
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;
|
animation: crownFloat 3s ease-in-out infinite;
|
||||||
transform: rotate(5deg);
|
transform: rotate(5deg);
|
||||||
}
|
}
|
||||||
@@ -1654,7 +1645,7 @@ page {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 200rpx;
|
width: 200rpx;
|
||||||
height: 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;
|
z-index: 0;
|
||||||
animation: glowPulse 2s ease-in-out infinite;
|
animation: glowPulse 2s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@@ -1686,7 +1677,7 @@ page {
|
|||||||
|
|
||||||
.rank-card--1 .rank-avatar-container { border-width: 6rpx; }
|
.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-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)); }
|
.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;
|
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-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-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%); }
|
.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-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-silver { background: linear-gradient(135deg, #c0c0c0, #808080); }
|
||||||
.rank-badge-bronze { background: linear-gradient(135deg, #cd7f32, #a0522d); }
|
.rank-badge-bronze { background: linear-gradient(135deg, #cd7f32, #a0522d); }
|
||||||
|
|
||||||
@@ -1763,7 +1754,7 @@ page {
|
|||||||
overflow: hidden;
|
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--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); }
|
.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;
|
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--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); }
|
.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;
|
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--2 .rank-currency { color: #c0c0c0; }
|
||||||
.rank-card--3 .rank-currency { color: #cd7f32; }
|
.rank-card--3 .rank-currency { color: #cd7f32; }
|
||||||
|
|
||||||
@@ -1827,7 +1818,7 @@ page {
|
|||||||
text-shadow: 0 0 10rpx rgba(74, 222, 128, 0.5);
|
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--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); }
|
.rank-card--3 .rank-amount { color: #cd7f32; text-shadow: 0 0 10rpx rgba(205, 127, 50, 0.7); }
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +1,119 @@
|
|||||||
// components/chenghao-tag/chenghao-tag.js
|
// components/chenghao-tag/chenghao-tag.js
|
||||||
const app = getApp();
|
const app = getApp();
|
||||||
|
|
||||||
|
const PILL_SHAPES = ['pill', 'rectangle', 'rounded'];
|
||||||
|
|
||||||
Component({
|
Component({
|
||||||
properties: {
|
properties: {
|
||||||
mingcheng: { type: String, value: '' },
|
mingcheng: { type: String, value: '' },
|
||||||
texiaoJson: { type: Object, value: {} }
|
texiaoJson: { type: null, value: null },
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
// 默认值:宽152,高52,六边形,无背景图,无动画,白色字
|
inlineStyle: '',
|
||||||
width: 152,
|
shapeClass: 'tag-pill',
|
||||||
height: 52,
|
|
||||||
shapeClass: 'liubianxing', // 保证至少不是矩形
|
|
||||||
animationClass: '',
|
animationClass: '',
|
||||||
bgStyle: '',
|
|
||||||
textColor: '#FFFFFF',
|
textColor: '#FFFFFF',
|
||||||
textSize: 22,
|
textSize: 22,
|
||||||
imageUrl: ''
|
imageUrl: '',
|
||||||
|
isPill: true,
|
||||||
|
},
|
||||||
|
observers: {
|
||||||
|
'texiaoJson, mingcheng': function () {
|
||||||
|
this._applyConfig(this.properties.texiaoJson);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
lifetimes: {
|
lifetimes: {
|
||||||
attached() {
|
attached() {
|
||||||
const cfg = this.properties.texiaoJson || {};
|
this._applyConfig(this.properties.texiaoJson);
|
||||||
|
},
|
||||||
// 1. 尺寸(稍大一些,一行能放3~4个)
|
},
|
||||||
const width = cfg.width || 152;
|
methods: {
|
||||||
const height = cfg.height || 52;
|
_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 bgStyle = '';
|
||||||
let imageUrl = '';
|
let imageUrl = '';
|
||||||
if (cfg.image_url) {
|
if (cfg.image_url) {
|
||||||
const ossImageUrl = app.globalData.ossImageUrl || '';
|
imageUrl = cfg.image_url.startsWith('http')
|
||||||
imageUrl = cfg.image_url.startsWith('http')
|
? cfg.image_url
|
||||||
? cfg.image_url
|
|
||||||
: ossImageUrl + cfg.image_url;
|
: ossImageUrl + cfg.image_url;
|
||||||
} else if (cfg.bg_gradient) {
|
} else if (cfg.bg_gradient) {
|
||||||
bgStyle = `background: ${cfg.bg_gradient};`;
|
bgStyle = `background: ${cfg.bg_gradient};`;
|
||||||
} else if (cfg.bg_color) {
|
} else if (cfg.bg_color) {
|
||||||
bgStyle = `background: ${cfg.bg_color};`;
|
bgStyle = `background: ${cfg.bg_color};`;
|
||||||
} else {
|
} else {
|
||||||
// 默认紫色渐变
|
bgStyle = 'background: linear-gradient(135deg, #FFD700, #FF8C00);';
|
||||||
bgStyle = `background: linear-gradient(135deg, #c4b5fd, #9333ea);`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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({
|
this.setData({
|
||||||
width, height,
|
isPill: false,
|
||||||
bgStyle, imageUrl,
|
inlineStyle: `width: ${width}rpx; height: ${height}rpx; ${bgStyle}`,
|
||||||
shapeClass, animationClass,
|
shapeClass: cfg.shape || 'liubianxing',
|
||||||
textColor, textSize
|
animationClass: cfg.animation || '',
|
||||||
|
textColor: cfg.text_color || '#FFFFFF',
|
||||||
|
textSize: cfg.text_size || 22,
|
||||||
|
imageUrl,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 背景图加载失败时回退为纯色背景
|
|
||||||
onImageError() {
|
onImageError() {
|
||||||
this.setData({ imageUrl: '' });
|
this.setData({ imageUrl: '' });
|
||||||
// 如果 bgStyle 为空,给个默认背景
|
if (!this.data.inlineStyle.includes('background')) {
|
||||||
if (!this.data.bgStyle) {
|
this.setData({
|
||||||
this.setData({ bgStyle: 'background: linear-gradient(135deg, #c4b5fd, #9333ea);' });
|
inlineStyle: this.data.inlineStyle + ' background: linear-gradient(135deg, #FFD700, #FF8C00);',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
<!-- components/chenghao-tag/chenghao-tag.wxml -->
|
<!-- components/chenghao-tag/chenghao-tag.wxml -->
|
||||||
<view
|
<view
|
||||||
class="tag-root {{shapeClass}} {{animationClass}}"
|
class="tag-root {{shapeClass}} {{animationClass}}"
|
||||||
style="width: {{width}}rpx; height: {{height}}rpx; {{bgStyle}}"
|
style="{{inlineStyle}}"
|
||||||
>
|
>
|
||||||
<!-- 背景图(如果有) -->
|
<image
|
||||||
<image
|
wx:if="{{imageUrl && !isPill}}"
|
||||||
wx:if="{{imageUrl}}"
|
class="tag-bg-image"
|
||||||
class="tag-bg-image"
|
src="{{imageUrl}}"
|
||||||
src="{{imageUrl}}"
|
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
binderror="onImageError"
|
binderror="onImageError"
|
||||||
></image>
|
/>
|
||||||
|
<text
|
||||||
<!-- 文字层 -->
|
class="tag-text"
|
||||||
<text
|
|
||||||
class="tag-text"
|
|
||||||
style="color: {{textColor}}; font-size: {{textSize}}rpx;"
|
style="color: {{textColor}}; font-size: {{textSize}}rpx;"
|
||||||
>{{mingcheng}}</text>
|
>{{mingcheng}}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -12,6 +12,18 @@
|
|||||||
margin: 4rpx;
|
margin: 4rpx;
|
||||||
box-sizing: border-box;
|
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 {
|
.tag-bg-image {
|
||||||
@@ -85,6 +97,21 @@
|
|||||||
animation: glow-anim 2s ease-in-out infinite;
|
animation: glow-anim 2s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@keyframes glow-anim {
|
@keyframes glow-anim {
|
||||||
0%, 100% { box-shadow: 0 0 8rpx 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(196, 181, 253, 0.8), 0 0 40rpx rgba(196, 181, 253, 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;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const { resolveAvatarUrl } = require('../../utils/avatar.js');
|
const { resolveAvatarUrl, getDefaultAvatarUrl } = require('../../utils/avatar.js');
|
||||||
|
|
||||||
Component({
|
Component({
|
||||||
properties: {
|
properties: {
|
||||||
@@ -53,7 +53,8 @@ Component({
|
|||||||
|
|
||||||
// 静音状态
|
// 静音状态
|
||||||
isMuted: false,
|
isMuted: false,
|
||||||
|
formattedTime: '',
|
||||||
|
|
||||||
// 自动隐藏计时器
|
// 自动隐藏计时器
|
||||||
autoHideTimeout: null
|
autoHideTimeout: null
|
||||||
},
|
},
|
||||||
@@ -123,7 +124,7 @@ Component({
|
|||||||
let avatar = resolveAvatarUrl(
|
let avatar = resolveAvatarUrl(
|
||||||
data.avatar || data.message?.senderData?.avatar,
|
data.avatar || data.message?.senderData?.avatar,
|
||||||
app
|
app
|
||||||
);
|
) || getDefaultAvatarUrl(app);
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
show: true,
|
show: true,
|
||||||
@@ -131,6 +132,7 @@ Component({
|
|||||||
message: data.content || '[消息内容]',
|
message: data.content || '[消息内容]',
|
||||||
avatar: avatar,
|
avatar: avatar,
|
||||||
notificationData: data,
|
notificationData: data,
|
||||||
|
formattedTime: this.formatTime(data.timestamp),
|
||||||
progress: 100,
|
progress: 100,
|
||||||
swipingClass: '',
|
swipingClass: '',
|
||||||
swipeStyle: ''
|
swipeStyle: ''
|
||||||
@@ -149,6 +151,7 @@ Component({
|
|||||||
this.clearTimers();
|
this.clearTimers();
|
||||||
this.setData({
|
this.setData({
|
||||||
show: false,
|
show: false,
|
||||||
|
formattedTime: '',
|
||||||
progress: 100,
|
progress: 100,
|
||||||
swipingClass: '',
|
swipingClass: '',
|
||||||
swipeStyle: ''
|
swipeStyle: ''
|
||||||
@@ -265,6 +268,13 @@ Component({
|
|||||||
this.triggerEvent('close');
|
this.triggerEvent('close');
|
||||||
this.hideNotification();
|
this.hideNotification();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onAvatarError() {
|
||||||
|
const def = getDefaultAvatarUrl(getApp());
|
||||||
|
if (def && this.data.avatar !== def) {
|
||||||
|
this.setData({ avatar: def });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onMute(e) {
|
onMute(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -15,14 +15,15 @@
|
|||||||
<!-- 通知内容 -->
|
<!-- 通知内容 -->
|
||||||
<view class="notification-content">
|
<view class="notification-content">
|
||||||
<!-- 左侧头像 -->
|
<!-- 左侧头像 -->
|
||||||
<image class="notification-avatar" src="{{avatar}}" mode="aspectFill"></image>
|
<image class="notification-avatar" src="{{avatar}}" mode="aspectFill" binderror="onAvatarError"></image>
|
||||||
|
|
||||||
<!-- 中间内容区域 -->
|
<!-- 中间内容区域 -->
|
||||||
<view class="notification-body">
|
<view class="notification-body">
|
||||||
|
<view class="notification-tag">新消息</view>
|
||||||
<view class="notification-title">{{title}}</view>
|
<view class="notification-title">{{title}}</view>
|
||||||
<view class="notification-message">{{message}}</view>
|
<view class="notification-message">{{message}}</view>
|
||||||
<view class="notification-time" wx:if="{{showTime}}">
|
<view class="notification-time" wx:if="{{show && showTime && formattedTime}}">
|
||||||
{{formatTime(notificationData ? notificationData.timestamp : '')}}
|
{{formattedTime}}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
.global-notification {
|
.global-notification {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 20rpx;
|
left: 24rpx;
|
||||||
right: 20rpx;
|
right: 24rpx;
|
||||||
top: 0rpx;
|
top: calc(env(safe-area-inset-top) + 108rpx);
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-120%);
|
transform: translateY(-160%);
|
||||||
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
transition: all 0.42s cubic-bezier(0.34, 1.2, 0.64, 1);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 24rpx;
|
border-radius: 28rpx;
|
||||||
background: linear-gradient(135deg,
|
background: linear-gradient(145deg,
|
||||||
rgba(41, 47, 61, 0.98) 0%,
|
rgba(28, 32, 42, 0.97) 0%,
|
||||||
rgba(31, 36, 48, 0.98) 100%);
|
rgba(22, 26, 36, 0.98) 100%);
|
||||||
backdrop-filter: blur(30rpx) saturate(180%);
|
backdrop-filter: blur(40rpx) saturate(180%);
|
||||||
-webkit-backdrop-filter: blur(30rpx) saturate(180%);
|
-webkit-backdrop-filter: blur(40rpx) saturate(180%);
|
||||||
border: 1rpx solid rgba(255, 255, 255, 0.08);
|
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 20rpx 60rpx rgba(0, 0, 0, 0.4),
|
0 24rpx 64rpx rgba(0, 0, 0, 0.45),
|
||||||
0 0 0 1rpx rgba(255, 255, 255, 0.03),
|
0 0 0 1rpx rgba(255, 255, 255, 0.04),
|
||||||
inset 0 1rpx 0 rgba(255, 255, 255, 0.1);
|
inset 0 1rpx 0 rgba(255, 255, 255, 0.12);
|
||||||
min-height: 140rpx;
|
min-height: 148rpx;
|
||||||
touch-action: pan-y;
|
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 {
|
.global-notification.show {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@@ -58,8 +69,8 @@
|
|||||||
.notification-content {
|
.notification-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 32rpx;
|
padding: 28rpx 28rpx 28rpx 36rpx;
|
||||||
min-height: 140rpx;
|
min-height: 148rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +95,18 @@
|
|||||||
justify-content: center;
|
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 {
|
.notification-title {
|
||||||
font-size: 34rpx;
|
font-size: 34rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<movable-area class="kefu-movable-area" wx:if="{{!sessionHidden}}">
|
||||||
|
<movable-view
|
||||||
|
class="kefu-movable-view"
|
||||||
|
direction="vertical"
|
||||||
|
y="{{floatY}}"
|
||||||
|
damping="40"
|
||||||
|
friction="2"
|
||||||
|
bindchange="onFloatMove"
|
||||||
|
>
|
||||||
|
<block wx:if="{{mode === 'full'}}">
|
||||||
|
<view class="kefu-wrap">
|
||||||
|
<view class="kefu-float kefu-float--full">
|
||||||
|
<view class="kefu-unread-badge" wx:if="{{csUnread > 0}}">{{csUnread > 99 ? '99+' : csUnread}}</view>
|
||||||
|
<view class="kefu-float-main" catchtap="onContact">
|
||||||
|
<image class="kefu-float-icon-img" src="{{iconUrl}}" mode="aspectFit" binderror="onIconError"/>
|
||||||
|
<view class="kefu-text-col">
|
||||||
|
<text class="kefu-float-text">联系客服</text>
|
||||||
|
<text class="kefu-float-sub kefu-float-sub--warn" wx:if="{{csUnread > 0}}">有新消息</text>
|
||||||
|
<text class="kefu-float-sub {{csOnline ? 'kefu-float-sub--online' : ''}}" wx:else>{{csStatusText}} {{csHoursText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="kefu-float-close" catchtap="onHideTap">
|
||||||
|
<text>×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="kefu-permanent-row" catchtap="onSessionDismiss">
|
||||||
|
<text class="kefu-permanent-label">本次不再显示</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<block wx:else>
|
||||||
|
<view class="kefu-wrap kefu-wrap--mini">
|
||||||
|
<view class="kefu-float kefu-float--mini" catchtap="onContact" bindlongpress="onExpand">
|
||||||
|
<view class="kefu-unread-badge kefu-unread-badge--mini" wx:if="{{csUnread > 0}}">{{csUnread > 99 ? '99+' : csUnread}}</view>
|
||||||
|
<image class="kefu-float-mini-icon-img" src="{{iconUrl}}" mode="aspectFit" binderror="onIconError"/>
|
||||||
|
</view>
|
||||||
|
<view class="kefu-permanent-row kefu-permanent-row--mini" catchtap="onSessionDismiss">
|
||||||
|
<text class="kefu-permanent-label">隐藏</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</movable-view>
|
||||||
|
</movable-area>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
.card-id { font-size: 24rpx; color: #999; margin-left: 15rpx; }
|
.card-id { font-size: 24rpx; color: #999; margin-left: 15rpx; }
|
||||||
.cross-tag {
|
.cross-tag {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
background: #8b5cf6;
|
background: #ff9900;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 20rpx;
|
font-size: 20rpx;
|
||||||
padding: 2rpx 12rpx;
|
padding: 2rpx 12rpx;
|
||||||
|
|||||||
@@ -1,16 +1,87 @@
|
|||||||
|
import request from '../../utils/request';
|
||||||
|
|
||||||
const app = getApp();
|
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({
|
Component({
|
||||||
properties: {
|
properties: {
|
||||||
visible: Boolean,
|
visible: { type: Boolean, value: false },
|
||||||
showDetail: { 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: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
this.triggerEvent('close');
|
this.triggerEvent('close');
|
||||||
}
|
},
|
||||||
}
|
|
||||||
});
|
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();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,12 +1,28 @@
|
|||||||
<view class="order-sender-mask" wx:if="{{visible}}" catchtap="close"></view>
|
<view class="order-sender-mask" wx:if="{{visible}}" catchtap="close"></view>
|
||||||
<view class="order-sender {{visible ? 'show' : ''}}">
|
<view class="order-sender {{visible ? 'show' : ''}}">
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<text class="title">提示</text>
|
<text class="title">选择订单发送</text>
|
||||||
<text class="close" bindtap="close">✕</text>
|
<text class="close" bindtap="close">✕</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="content">
|
<view class="search-row">
|
||||||
<view class="icon">📋</view>
|
<input class="search-input" placeholder="搜索订单号/内容" value="{{keyword}}" bindinput="onSearchInput" confirm-type="search" />
|
||||||
<text class="notice">此功能暂未开放</text>
|
|
||||||
<text class="sub">敬请期待</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
<scroll-view scroll-y class="order-list" enable-flex>
|
||||||
|
<view class="loading-tip" wx:if="{{loading}}">加载中...</view>
|
||||||
|
<block wx:for="{{filteredOrders}}" wx:key="dingdan_id">
|
||||||
|
<view class="order-item" data-index="{{index}}" bindtap="onSelectOrder">
|
||||||
|
<view class="order-item-top">
|
||||||
|
<text class="order-id">{{item.dingdan_id}}</text>
|
||||||
|
<text class="order-status">{{item.zhuangtaiText}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="order-desc">{{item.jieshao || '暂无介绍'}}</text>
|
||||||
|
<view class="order-item-bottom">
|
||||||
|
<text class="order-price">¥{{item.jine || '0'}}</text>
|
||||||
|
<text class="order-time">{{item.create_time}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="order-send-hint">点击发送订单卡片</text>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<view class="empty-tip" wx:if="{{!loading && !filteredOrders.length}}">暂无相关订单</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
@@ -1,45 +1,140 @@
|
|||||||
.order-sender-mask {
|
.order-sender-mask {
|
||||||
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
position: fixed;
|
||||||
background: rgba(0,0,0,0.5);
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
z-index: 2000;
|
background: rgba(0, 0, 0, 0.5);
|
||||||
}
|
z-index: 2000;
|
||||||
.order-sender {
|
}
|
||||||
position: fixed; bottom: 0; left: 0; right: 0;
|
|
||||||
height: 360rpx;
|
.order-sender {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
border-radius: 24rpx 24rpx 0 0;
|
bottom: 0;
|
||||||
z-index: 2001;
|
left: 0;
|
||||||
transform: translateY(100%);
|
right: 0;
|
||||||
transition: 0.25s;
|
height: 72vh;
|
||||||
display: flex;
|
max-height: 900rpx;
|
||||||
flex-direction: column;
|
background: #fff;
|
||||||
}
|
border-radius: 24rpx 24rpx 0 0;
|
||||||
.order-sender.show { transform: translateY(0); }
|
z-index: 2001;
|
||||||
|
transform: translateY(100%);
|
||||||
.header {
|
transition: transform 0.25s;
|
||||||
display: flex; justify-content: space-between;
|
display: flex;
|
||||||
padding: 24rpx 30rpx;
|
flex-direction: column;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
}
|
||||||
}
|
|
||||||
.title { font-size: 32rpx; font-weight: 600; }
|
.order-sender.show {
|
||||||
.close { font-size: 44rpx; color: #999; padding: 0 12rpx; }
|
transform: translateY(0);
|
||||||
|
}
|
||||||
.content {
|
|
||||||
flex: 1;
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
padding: 24rpx 30rpx;
|
||||||
padding-bottom: 40rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
}
|
flex-shrink: 0;
|
||||||
.icon { font-size: 80rpx; margin-bottom: 20rpx; }
|
}
|
||||||
.notice {
|
|
||||||
font-size: 34rpx;
|
.title {
|
||||||
font-weight: 600;
|
font-size: 32rpx;
|
||||||
color: #333;
|
font-weight: 600;
|
||||||
margin-bottom: 10rpx;
|
}
|
||||||
}
|
|
||||||
.sub {
|
.close {
|
||||||
font-size: 24rpx;
|
font-size: 44rpx;
|
||||||
color: #999;
|
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;
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<view class="pindao-mask" wx:if="{{visible}}" catchtouchmove="preventMove">
|
||||||
|
<view class="pindao-panel" catchtap="preventMove">
|
||||||
|
<view class="pindao-head flexb">
|
||||||
|
<text class="pindao-title">{{title}}</text>
|
||||||
|
<view class="pindao-close" bindtap="onClose">×</view>
|
||||||
|
</view>
|
||||||
|
<view class="pindao-channel" wx:if="{{channelNo}}">
|
||||||
|
<text class="pindao-channel-label">频道号</text>
|
||||||
|
<text class="pindao-channel-no">{{channelNo}}</text>
|
||||||
|
</view>
|
||||||
|
<scroll-view class="pindao-scroll" scroll-y enhanced show-scrollbar="{{false}}">
|
||||||
|
<view wx:if="{{!images || images.length === 0}}" class="pindao-empty">暂无频道内容</view>
|
||||||
|
<image
|
||||||
|
wx:for="{{images}}"
|
||||||
|
wx:key="index"
|
||||||
|
class="pindao-img"
|
||||||
|
src="{{item}}"
|
||||||
|
mode="widthFix"
|
||||||
|
lazy-load="{{false}}"
|
||||||
|
show-menu-by-longpress
|
||||||
|
/>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -41,15 +41,24 @@ Component({
|
|||||||
async show(config, onCloseCallback) {
|
async show(config, onCloseCallback) {
|
||||||
const { title, images, duration, showMuteCheckbox, serverTime } = config;
|
const { title, images, duration, showMuteCheckbox, serverTime } = config;
|
||||||
this.onCloseCallback = onCloseCallback;
|
this.onCloseCallback = onCloseCallback;
|
||||||
|
this._showToken = (this._showToken || 0) + 1;
|
||||||
|
const token = this._showToken;
|
||||||
|
|
||||||
let safeImages = JSON.parse(JSON.stringify(images || []));
|
let safeImages = JSON.parse(JSON.stringify(images || []));
|
||||||
|
// 兼容 url / image_url
|
||||||
|
safeImages = safeImages.map((img) => ({
|
||||||
|
...img,
|
||||||
|
url: img.url || img.image_url || '',
|
||||||
|
text: img.text || '',
|
||||||
|
})).filter((img) => !!img.url);
|
||||||
|
|
||||||
const hasImages = safeImages.length > 0;
|
const hasImages = safeImages.length > 0;
|
||||||
let hasTextOnly = false, textContent = '';
|
let hasTextOnly = false, textContent = '';
|
||||||
if (!hasImages) {
|
if (!hasImages) {
|
||||||
hasTextOnly = true;
|
hasTextOnly = true;
|
||||||
textContent = config.text || '暂无内容';
|
textContent = config.text || '暂无内容';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
visible: true,
|
visible: true,
|
||||||
isMinimized: false,
|
isMinimized: false,
|
||||||
@@ -65,36 +74,91 @@ Component({
|
|||||||
isFullscreen: false,
|
isFullscreen: false,
|
||||||
processedImages: [],
|
processedImages: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
this.startCountdown();
|
this.startCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasImages) {
|
if (!hasImages) return;
|
||||||
const processed = [];
|
|
||||||
const screenWidth = wx.getSystemInfoSync().windowWidth;
|
// 等 OSS 域名就绪再拼接,避免相对路径导致整图空白
|
||||||
const containerWidth = screenWidth * 0.9;
|
await this.ensureOssBase(4000);
|
||||||
const imageWidth = containerWidth - 60;
|
if (token !== this._showToken) return;
|
||||||
for (let i = 0; i < safeImages.length; i++) {
|
|
||||||
const img = safeImages[i];
|
const processed = safeImages.map((img) => ({
|
||||||
const fullUrl = this.getFullImageUrl(img.url);
|
url: this.getFullImageUrl(img.url),
|
||||||
let imageHeight = 200;
|
text: img.text,
|
||||||
try {
|
height: 0,
|
||||||
const res = await this.getImageInfoPromise(fullUrl);
|
}));
|
||||||
const realHeight = (imageWidth * res.height) / res.width;
|
console.log('[popup-notice] 图片URL:', processed.map((p) => p.url));
|
||||||
imageHeight = realHeight;
|
this.setData({ processedImages: processed });
|
||||||
} catch (e) {
|
|
||||||
console.error('获取图片信息失败', fullUrl, e);
|
// 可选:量真实高度(失败也不影响 widthFix 展示)
|
||||||
}
|
const screenWidth = wx.getSystemInfoSync().windowWidth;
|
||||||
processed.push({
|
const containerWidth = Math.min(screenWidth * 0.86, 310);
|
||||||
url: fullUrl,
|
const imageWidth = Math.max(containerWidth - 30, 200);
|
||||||
text: img.text,
|
for (let i = 0; i < processed.length; i++) {
|
||||||
height: imageHeight,
|
if (token !== this._showToken) return;
|
||||||
});
|
const fullUrl = processed[i].url;
|
||||||
|
if (!fullUrl || !/^https?:\/\//.test(fullUrl)) {
|
||||||
|
console.error('[popup-notice] OSS未就绪或URL非法', fullUrl);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await this.getImageInfoPromise(fullUrl);
|
||||||
|
const realHeight = (imageWidth * res.height) / res.width;
|
||||||
|
this.setData({ [`processedImages[${i}].height`]: realHeight });
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取图片信息失败', fullUrl, e);
|
||||||
}
|
}
|
||||||
this.setData({ processedImages: processed });
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 等待 / 回读本地缓存,确保能拼出完整 COS 地址 */
|
||||||
|
ensureOssBase(timeoutMs = 3000) {
|
||||||
|
const app = getApp();
|
||||||
|
const readOss = () => this.resolveOssBase();
|
||||||
|
if (readOss()) return Promise.resolve(readOss());
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let done = false;
|
||||||
|
const finish = () => {
|
||||||
|
if (done) return;
|
||||||
|
done = true;
|
||||||
|
if (app.off) app.off('configApplied', onCfg);
|
||||||
|
clearInterval(timer);
|
||||||
|
clearTimeout(timerOut);
|
||||||
|
resolve(readOss());
|
||||||
|
};
|
||||||
|
const onCfg = () => finish();
|
||||||
|
if (app.on) app.on('configApplied', onCfg);
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
if (readOss()) finish();
|
||||||
|
}, 100);
|
||||||
|
const timerOut = setTimeout(finish, timeoutMs);
|
||||||
|
// 主动再读一次缓存配置
|
||||||
|
try {
|
||||||
|
if (typeof app.readConfigFromStorage === 'function') {
|
||||||
|
const cached = app.readConfigFromStorage();
|
||||||
|
if (cached && app.applyDynamicConfig) app.applyDynamicConfig(cached);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
if (readOss()) finish();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
resolveOssBase() {
|
||||||
|
const app = getApp();
|
||||||
|
let base = (app.globalData && app.globalData.ossImageUrl) || '';
|
||||||
|
if (!base && app && typeof app.readConfigFromStorage === 'function') {
|
||||||
|
try {
|
||||||
|
const cached = app.readConfigFromStorage();
|
||||||
|
base = (cached && cached.cos && cached.cos.ossImageUrl) || '';
|
||||||
|
if (base && app.globalData) app.globalData.ossImageUrl = base;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
return base || '';
|
||||||
|
},
|
||||||
|
|
||||||
getImageInfoPromise(url) {
|
getImageInfoPromise(url) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -204,12 +268,18 @@ Component({
|
|||||||
|
|
||||||
getFullImageUrl(relativeUrl) {
|
getFullImageUrl(relativeUrl) {
|
||||||
if (!relativeUrl) return '';
|
if (!relativeUrl) return '';
|
||||||
if (relativeUrl.startsWith('http')) return relativeUrl;
|
if (relativeUrl.startsWith('http://') || relativeUrl.startsWith('https://')) {
|
||||||
const app = getApp();
|
return relativeUrl;
|
||||||
let base = app.globalData.ossImageUrl || '';
|
}
|
||||||
base = base.replace(/\/+$/, '');
|
// 后端 cos.ossImageUrl 带尾斜杠;相对路径不带前导 /
|
||||||
const clean = relativeUrl.replace(/^\/+/, '');
|
let base = this.resolveOssBase();
|
||||||
return base ? base + '/' + clean : clean;
|
if (!base) {
|
||||||
|
console.warn('[popup-notice] ossImageUrl 为空,无法拼接', relativeUrl);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (!base.endsWith('/')) base += '/';
|
||||||
|
const clean = String(relativeUrl).replace(/^\/+/, '');
|
||||||
|
return base + clean;
|
||||||
},
|
},
|
||||||
|
|
||||||
preventMove() {},
|
preventMove() {},
|
||||||
|
|||||||
@@ -25,15 +25,17 @@
|
|||||||
<view wx:for="{{processedImages}}" wx:key="index" class="image-block">
|
<view wx:for="{{processedImages}}" wx:key="index" class="image-block">
|
||||||
<view wx:if="{{item.text}}" class="block-text">{{item.text}}</view>
|
<view wx:if="{{item.text}}" class="block-text">{{item.text}}</view>
|
||||||
<view class="image-padding">
|
<view class="image-padding">
|
||||||
<image
|
<image
|
||||||
class="block-image"
|
class="block-image"
|
||||||
src="{{item.url}}"
|
src="{{item.url}}"
|
||||||
style="width:100%; height:{{item.height}}px; display:block;"
|
mode="widthFix"
|
||||||
|
style="width:100%; {{item.height > 0 ? 'height:' + item.height + 'px;' : ''}} display:block;"
|
||||||
data-index="{{index}}"
|
data-index="{{index}}"
|
||||||
data-url="{{item.url}}"
|
data-url="{{item.url}}"
|
||||||
bindtap="onCustomPreview"
|
bindtap="onCustomPreview"
|
||||||
binderror="onImageError"
|
binderror="onImageError"
|
||||||
lazy-load="{{false}}"
|
lazy-load="{{false}}"
|
||||||
|
show-menu-by-longpress="{{true}}"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -15,14 +15,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.popup-container {
|
.popup-container {
|
||||||
width: 90%;
|
width: 86%;
|
||||||
height: 85vh;
|
max-width: 620rpx;
|
||||||
|
/* 必须给明确高度:scroll-view 依赖父级高度,height:auto 会导致图片区塌成 0 */
|
||||||
|
height: 68vh;
|
||||||
|
max-height: 68vh;
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 32rpx;
|
border-radius: 28rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-container.fullscreen {
|
.popup-container.fullscreen {
|
||||||
@@ -78,6 +82,7 @@
|
|||||||
|
|
||||||
.scroll-wrapper {
|
.scroll-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -138,7 +143,7 @@
|
|||||||
.countdown-tip {
|
.countdown-tip {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #9333ea;
|
color: #ff6600;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,10 +161,11 @@
|
|||||||
|
|
||||||
/* 🔥 关闭按钮(替换原有 button,增加扫光) */
|
/* 🔥 关闭按钮(替换原有 button,增加扫光) */
|
||||||
.close-btn {
|
.close-btn {
|
||||||
width: 600rpx;
|
width: 86%;
|
||||||
height: 100rpx;
|
max-width: 480rpx;
|
||||||
|
height: 88rpx;
|
||||||
background: #1a1a1a;
|
background: #1a1a1a;
|
||||||
border-radius: 60rpx;
|
border-radius: 44rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -223,7 +229,7 @@
|
|||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
|
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;
|
background: #f0f0f0;
|
||||||
display: block;
|
display: block;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
const STORAGE_KEY = 'tousuFloatHidden';
|
||||||
|
|
||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
lifetimes: {
|
||||||
|
attached() {
|
||||||
|
this._syncHidden();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
pageLifetimes: {
|
||||||
|
show() {
|
||||||
|
this._syncHidden();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
_syncHidden() {
|
||||||
|
let hidden = false;
|
||||||
|
try {
|
||||||
|
hidden = wx.getStorageSync(STORAGE_KEY) === 1 || wx.getStorageSync(STORAGE_KEY) === '1';
|
||||||
|
} catch (e) {}
|
||||||
|
if (hidden !== this.data.hidden) {
|
||||||
|
this.setData({ hidden });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
go() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '/pages/gongdan/create/create',
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('打开投诉页失败', err);
|
||||||
|
wx.showToast({ title: '打开失败,请重试', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onDismiss(e) {
|
||||||
|
if (e && e.stopPropagation) e.stopPropagation();
|
||||||
|
wx.showModal({
|
||||||
|
title: '隐藏投诉入口',
|
||||||
|
content: '隐藏后可在「我的 / 工单」中继续投诉。需要恢复时可清除小程序缓存。',
|
||||||
|
confirmText: '不再显示',
|
||||||
|
cancelText: '取消',
|
||||||
|
success: (res) => {
|
||||||
|
if (!res.confirm) return;
|
||||||
|
try {
|
||||||
|
wx.setStorageSync(STORAGE_KEY, 1);
|
||||||
|
} catch (err) {}
|
||||||
|
this.setData({ hidden: true });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"component":true}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<view class="tousu-wrap" wx:if="{{!hidden}}">
|
||||||
|
<view class="float" catchtap="go">投诉</view>
|
||||||
|
<view class="dismiss-row" catchtap="onDismiss">
|
||||||
|
<text class="dismiss-label">不再显示</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
.tousu-wrap {
|
||||||
|
position: fixed;
|
||||||
|
right: 24rpx;
|
||||||
|
bottom: 280rpx;
|
||||||
|
z-index: 999;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float {
|
||||||
|
min-width: 96rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
padding: 0 22rpx;
|
||||||
|
border-radius: 36rpx;
|
||||||
|
background: rgba(55, 55, 55, 0.72);
|
||||||
|
color: #f5f5f5;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 1rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dismiss-row {
|
||||||
|
padding: 4rpx 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dismiss-label {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: rgba(120, 120, 120, 0.9);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 4rpx;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 小程序所属俱乐部配置 — 每个小程序工程编译前改这里即可。
|
||||||
|
* 星阙 = xq;星之界 = xzj;龙先生 = lxs(与后台 club 表 club_id 一致,勿写成 lsx)。
|
||||||
|
* 不要依赖后端猜测:前端必须明确所属 club。
|
||||||
|
*/
|
||||||
|
export const CLUB_ID = 'lxs';
|
||||||
|
|
||||||
|
/** 与 club 表 wx_appid 一致,登录时可传给后端反查 club */
|
||||||
|
export const WX_APP_ID = 'wx7ff90e9d024fcdb8';
|
||||||
|
|
||||||
|
export const CLUB_NAME = '龙先生电竞';
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
# 总会员抢单/展示修复前备份
|
||||||
|
日期: 2026-07-10
|
||||||
|
原文件见同目录。
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 从服务端刷新打手会员/押金/积分等到 globalData(抢单、考试等页共用)
|
||||||
|
*/
|
||||||
|
import request from './request.js';
|
||||||
|
|
||||||
|
export async function refreshDashouMembership(app) {
|
||||||
|
app = app || getApp();
|
||||||
|
try {
|
||||||
|
const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' });
|
||||||
|
if (res && res.data && res.data.code == 200) {
|
||||||
|
const data = res.data.data || {};
|
||||||
|
const clumber = Array.isArray(data.clumber) ? data.clumber : [];
|
||||||
|
app.globalData.clumber = clumber;
|
||||||
|
if (data.yajin !== undefined) app.globalData.yajin = data.yajin;
|
||||||
|
if (data.jifen !== undefined) app.globalData.jinfen = data.jifen;
|
||||||
|
if (data.zhanghaostatus !== undefined) app.globalData.zhanghaoStatus = data.zhanghaostatus;
|
||||||
|
if (data.dashouzhuangtai !== undefined) app.globalData.dashouzhuangtai = data.dashouzhuangtai;
|
||||||
|
return clumber;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('refreshDashouMembership failed', e);
|
||||||
|
}
|
||||||
|
return app.globalData.clumber || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用户是否持有某会员类型(与抢单卡片判断一致;支持总会员 covers) */
|
||||||
|
export function userHasHuiyuan(huiyuanList, huiyuanId) {
|
||||||
|
if (!huiyuanId) return true;
|
||||||
|
const list = huiyuanList || [];
|
||||||
|
const req = String(huiyuanId);
|
||||||
|
return list.some((h) => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,476 @@
|
|||||||
|
// pages/order-pool/order-pool.js
|
||||||
|
const app = getApp();
|
||||||
|
import request from '../../utils/request.js';
|
||||||
|
import PopupService from '../../services/popupService.js';
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
// 1. 商品类型相关
|
||||||
|
shangpinleixing: [],
|
||||||
|
xuanzhongLeixingId: null,
|
||||||
|
|
||||||
|
// 2. 订单列表与分页相关
|
||||||
|
dingdanList: [],
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
hasMore: true,
|
||||||
|
isLoading: false,
|
||||||
|
|
||||||
|
// 3. 全局状态字段
|
||||||
|
dashoustatus: null,
|
||||||
|
zhuanghaoStatus: null,
|
||||||
|
dashouzhuangtai: null,
|
||||||
|
uid: null,
|
||||||
|
huiyuanList: [],
|
||||||
|
yajin: 0,
|
||||||
|
jifen: 0,
|
||||||
|
|
||||||
|
// 4. 刷新控制字段
|
||||||
|
scrollViewRefreshing: false,
|
||||||
|
lastRefreshTime: 0,
|
||||||
|
refreshCooldown: 2000,
|
||||||
|
isLoadingMore: false,
|
||||||
|
|
||||||
|
// 5. 切换类型冷却时间控制
|
||||||
|
lastSwitchTime: 0,
|
||||||
|
switchCooldown: 1500,
|
||||||
|
isSwitching: false,
|
||||||
|
|
||||||
|
// 6. 全局OSS地址
|
||||||
|
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||||
|
|
||||||
|
// 7. 授权状态控制
|
||||||
|
showUnauthorized: false,
|
||||||
|
unauthorizedMsg: '您尚未开启此功能',
|
||||||
|
|
||||||
|
// 商品轮播展示(只读 globalData,无额外接口)
|
||||||
|
lunboList: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
async onLoad(options) {
|
||||||
|
this.syncShopBannerFromGlobal();
|
||||||
|
this.loadGlobalStatus();
|
||||||
|
this.checkAuthorization();
|
||||||
|
},
|
||||||
|
// 页面隐藏时清理弹窗视图
|
||||||
|
onHide: function () {
|
||||||
|
const popupComp = this.selectComponent('#popupNotice');
|
||||||
|
if (popupComp && popupComp.cleanup) {
|
||||||
|
popupComp.cleanup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
this.syncShopBannerFromGlobal();
|
||||||
|
this.registerNotificationComponent();
|
||||||
|
this.loadGlobalStatus();
|
||||||
|
this.checkAuthorization();
|
||||||
|
},
|
||||||
|
|
||||||
|
registerNotificationComponent() {
|
||||||
|
const notificationComp = this.selectComponent('#global-notification');
|
||||||
|
if (notificationComp && notificationComp.showNotification) {
|
||||||
|
app.globalData.globalNotification = {
|
||||||
|
show: (data) => notificationComp.showNotification(data),
|
||||||
|
hide: () => notificationComp.hideNotification()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 同步点单端已加载的商品轮播图,仅展示用 */
|
||||||
|
syncShopBannerFromGlobal() {
|
||||||
|
const oss = app.globalData.ossImageUrl || '';
|
||||||
|
const lunboList = (app.globalData.shangpinlunbo || []).map((url) => {
|
||||||
|
if (!url) return '';
|
||||||
|
return url.startsWith('http') ? url : oss + url;
|
||||||
|
}).filter(Boolean);
|
||||||
|
this.setData({ lunboList });
|
||||||
|
},
|
||||||
|
|
||||||
|
loadGlobalStatus() {
|
||||||
|
const globalData = app.globalData;
|
||||||
|
const dashoustatusCache = wx.getStorageSync('dashoustatus');
|
||||||
|
const dashoustatus = dashoustatusCache !== '' ? dashoustatusCache : null;
|
||||||
|
|
||||||
|
let zhuanghaoStatus = globalData.zhanghaoStatus;
|
||||||
|
if (zhuanghaoStatus === undefined || zhuanghaoStatus === null) {
|
||||||
|
zhuanghaoStatus = wx.getStorageSync('zhanghaoStatus');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
dashoustatus: dashoustatus,
|
||||||
|
zhuanghaoStatus: zhuanghaoStatus,
|
||||||
|
dashouzhuangtai: globalData.dashouzhuangtai,
|
||||||
|
uid: wx.getStorageSync('uid'),
|
||||||
|
huiyuanList: globalData.clumber || [],
|
||||||
|
yajin: globalData.yajin || 0,
|
||||||
|
jifen: globalData.jinfen || 0
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
checkAuthorization() {
|
||||||
|
const { dashoustatus, zhuanghaoStatus } = this.data;
|
||||||
|
|
||||||
|
const isDashouValid = (dashoustatus && dashoustatus == 1) || false;
|
||||||
|
const isZhuanghaoValid = (zhuanghaoStatus == 1);
|
||||||
|
|
||||||
|
const isAuthorized = isDashouValid && isZhuanghaoValid;
|
||||||
|
|
||||||
|
if (!isAuthorized) {
|
||||||
|
this.setData({ showUnauthorized: true });
|
||||||
|
let msg = '';
|
||||||
|
if (!isDashouValid) msg = '您尚未开启身份';
|
||||||
|
this.setData({ unauthorizedMsg: msg || '无法使用抢单功能' });
|
||||||
|
} else {
|
||||||
|
this.setData({ showUnauthorized: false });
|
||||||
|
if (!this.data.shangpinleixing.length) {
|
||||||
|
this.loadShangpinLeixing();
|
||||||
|
} else if (this.data.xuanzhongLeixingId) {
|
||||||
|
this.loadDingdanList(true);
|
||||||
|
}
|
||||||
|
PopupService.checkAndShow(this, 'jiedanchi');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadShangpinLeixing() {
|
||||||
|
wx.showLoading({ title: '加载商品类型...' });
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/dingdan/dsqdhqddlx',
|
||||||
|
method: 'POST',
|
||||||
|
header: { 'content-type': 'application/json' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.statusCode === 200 && res.data) {
|
||||||
|
const data = res.data;
|
||||||
|
let list = [];
|
||||||
|
if (data.code === 200 || data.code === 0) {
|
||||||
|
if (data.data && Array.isArray(data.data.list)) {
|
||||||
|
list = data.data.list;
|
||||||
|
} else if (data.data && Array.isArray(data.data)) {
|
||||||
|
list = data.data;
|
||||||
|
} else if (Array.isArray(data.list)) {
|
||||||
|
list = data.list;
|
||||||
|
} else if (Array.isArray(data)) {
|
||||||
|
list = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const processedList = this.processTupianUrl(list);
|
||||||
|
this.setData({
|
||||||
|
shangpinleixing: processedList,
|
||||||
|
xuanzhongLeixingId: processedList[0]?.id || null
|
||||||
|
});
|
||||||
|
if (this.data.xuanzhongLeixingId) {
|
||||||
|
this.loadDingdanList(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none', duration: 2000 });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载商品类型失败:', error);
|
||||||
|
wx.showToast({ title: '网络错误,加载失败', icon: 'none', duration: 2000 });
|
||||||
|
} finally {
|
||||||
|
wx.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
processTupianUrl(list) {
|
||||||
|
const ossUrl = app.globalData.ossImageUrl || '';
|
||||||
|
return list.map(item => ({
|
||||||
|
...item,
|
||||||
|
full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http') ? ossUrl + item.tupian_url : (item.tupian_url || '/images/default-type.png')
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
async selectLeixing(e) {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.data.lastSwitchTime < this.data.switchCooldown) {
|
||||||
|
wx.showToast({
|
||||||
|
title: `操作太快,请${Math.ceil((this.data.switchCooldown - (now - this.data.lastSwitchTime)) / 1000)}秒后再试`,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.data.isSwitching) return;
|
||||||
|
const leixingId = e.currentTarget.dataset.id;
|
||||||
|
if (leixingId === this.data.xuanzhongLeixingId) return;
|
||||||
|
this.setData({ isSwitching: true, lastSwitchTime: now });
|
||||||
|
wx.showLoading({ title: '切换中...' });
|
||||||
|
try {
|
||||||
|
this.setData({
|
||||||
|
xuanzhongLeixingId: leixingId,
|
||||||
|
dingdanList: [],
|
||||||
|
page: 1,
|
||||||
|
hasMore: true
|
||||||
|
});
|
||||||
|
await this.loadDingdanList(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('切换类型失败:', error);
|
||||||
|
} finally {
|
||||||
|
this.setData({ isSwitching: false });
|
||||||
|
wx.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadDingdanList(isRefresh = false) {
|
||||||
|
if (this.data.isLoading || !this.data.xuanzhongLeixingId) return;
|
||||||
|
|
||||||
|
const loadPage = isRefresh ? 1 : this.data.page;
|
||||||
|
if (!isRefresh && !this.data.hasMore) return;
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
isLoading: true,
|
||||||
|
isLoadingMore: !isRefresh
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/dingdan/ddhq',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
leixing_id: this.data.xuanzhongLeixingId,
|
||||||
|
page: loadPage,
|
||||||
|
page_size: this.data.pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
isLoading: false,
|
||||||
|
isLoadingMore: false,
|
||||||
|
scrollViewRefreshing: false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.code === 200 || res.data.code === 0) {
|
||||||
|
const newList = res.data.data.list || [];
|
||||||
|
const hasMore = res.data.data.has_more || false;
|
||||||
|
|
||||||
|
const processedList = newList.map(item => this.processDingdanItem(item));
|
||||||
|
|
||||||
|
const updatedList = isRefresh ? processedList : [...this.data.dingdanList, ...processedList];
|
||||||
|
|
||||||
|
updatedList.sort((a, b) => (b.creat_time || '').localeCompare(a.creat_time || ''));
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
dingdanList: updatedList,
|
||||||
|
page: loadPage,
|
||||||
|
hasMore: hasMore
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isRefresh) {
|
||||||
|
this.setData({ lastRefreshTime: Date.now() });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: res.data.msg || '加载失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载订单失败:', error);
|
||||||
|
this.setData({
|
||||||
|
isLoading: false,
|
||||||
|
isLoadingMore: false,
|
||||||
|
scrollViewRefreshing: false
|
||||||
|
});
|
||||||
|
wx.showToast({ title: '网络请求失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
processDingdanItem(item) {
|
||||||
|
const ossUrl = app.globalData.ossImageUrl || '';
|
||||||
|
let fullTupianUrl = '';
|
||||||
|
if (item.tupian) {
|
||||||
|
fullTupianUrl = !item.tupian.startsWith('http') ? ossUrl + item.tupian : item.tupian;
|
||||||
|
} else {
|
||||||
|
const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id);
|
||||||
|
fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
const isZhiding = item.zhuangtai === 7;
|
||||||
|
|
||||||
|
let zhidingAvatar = '';
|
||||||
|
if (item.zhiding_avatar) {
|
||||||
|
zhidingAvatar = !item.zhiding_avatar.startsWith('http') ? ossUrl + item.zhiding_avatar : item.zhiding_avatar;
|
||||||
|
}
|
||||||
|
const zhidingNicheng = item.zhiding_nicheng || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
full_tupian_url: fullTupianUrl,
|
||||||
|
isZhiding: isZhiding,
|
||||||
|
isPingtai: item.pingtai == 1,
|
||||||
|
isShangjia: item.pingtai == 2,
|
||||||
|
zhiding_avatar_full: zhidingAvatar,
|
||||||
|
zhiding_nicheng: zhidingNicheng
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
goToChongzhiPage(failureType, huiyuanId = null, requiredYajin = 0) {
|
||||||
|
let url = '/pages/fighter-recharge/fighter-recharge';
|
||||||
|
let params = {};
|
||||||
|
switch (failureType) {
|
||||||
|
case 'huiyuan':
|
||||||
|
url = '/pages/fighter-recharge/fighter-recharge';
|
||||||
|
params = { scrollTo: 'member' };
|
||||||
|
break;
|
||||||
|
case 'yajin':
|
||||||
|
url = '/pages/fighter-recharge/fighter-deposit';
|
||||||
|
params = { requiredYajin: requiredYajin };
|
||||||
|
break;
|
||||||
|
case 'jifen':
|
||||||
|
url = '/pages/fighter-recharge/fighter-recharge';
|
||||||
|
params = { scrollTo: 'jifen' };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (huiyuanId) params.huiyuanId = huiyuanId;
|
||||||
|
const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
|
||||||
|
const fullUrl = `${url}?${queryString}`;
|
||||||
|
wx.navigateTo({
|
||||||
|
url: fullUrl,
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('跳转失败:', err);
|
||||||
|
wx.showToast({ title: '跳转失败,请稍后重试', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async onQiangdanTap(e) {
|
||||||
|
const dingdanItem = e.currentTarget.dataset.item;
|
||||||
|
if (!dingdanItem) return;
|
||||||
|
|
||||||
|
if (!this.data.dashoustatus || this.data.dashoustatus != 1) {
|
||||||
|
wx.showToast({ title: '请先开启接单员身份', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.data.zhuanghaoStatus != 1) {
|
||||||
|
wx.showToast({ title: '账号异常,无法接单', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.data.dashouzhuangtai != 1) {
|
||||||
|
wx.showToast({ title: '您有订单正在接待中', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dingdanItem.isZhiding) {
|
||||||
|
if (!this.data.uid || this.data.uid != dingdanItem.zhiding_uid) {
|
||||||
|
wx.showToast({ title: '此订单为指定单', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dingdanItem.yaoqiuleixing == 1) {
|
||||||
|
const hasHuiyuan = this.data.huiyuanList.some(h => h.huiyuanid == dingdanItem.huiyuan_id);
|
||||||
|
if (!hasHuiyuan) {
|
||||||
|
wx.showToast({ title: '未开通对应会员,无法抢单', icon: 'none', duration: 2000 });
|
||||||
|
setTimeout(() => this.goToChongzhiPage('huiyuan', dingdanItem.huiyuan_id), 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dingdanItem.yaoqiuleixing == 2) {
|
||||||
|
if (this.data.yajin < dingdanItem.yajin) {
|
||||||
|
wx.showToast({ title: `押金不足,需${dingdanItem.yajin}`, icon: 'none', duration: 2000 });
|
||||||
|
setTimeout(() => this.goToChongzhiPage('yajin', null, dingdanItem.yajin), 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.data.jifen < 5) {
|
||||||
|
wx.showToast({ title: '积分不足,至少需要5积分', icon: 'none', duration: 2000 });
|
||||||
|
setTimeout(() => this.goToChongzhiPage('jifen'), 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const that = this;
|
||||||
|
wx.showModal({
|
||||||
|
title: '确认抢单',
|
||||||
|
content: `确定要抢此订单吗?${dingdanItem.isZhiding ? '(指定订单)' : ''}`,
|
||||||
|
success: async function (res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
wx.showLoading({ title: '抢单中...', mask: true });
|
||||||
|
try {
|
||||||
|
const qiangdanRes = await request({
|
||||||
|
url: '/dingdan/qiangdan',
|
||||||
|
method: 'POST',
|
||||||
|
data: { dingdan_id: dingdanItem.dingdan_id }
|
||||||
|
});
|
||||||
|
wx.hideLoading();
|
||||||
|
if (qiangdanRes.data.code === 200 || qiangdanRes.data.code === 0) {
|
||||||
|
that.showQiangdanSuccessEffect();
|
||||||
|
if (app.globalData) {
|
||||||
|
app.globalData.dashouzhuangtai = 0;
|
||||||
|
that.setData({ dashouzhuangtai: 0 });
|
||||||
|
}
|
||||||
|
const newList = that.data.dingdanList.filter(item => item.dingdan_id !== dingdanItem.dingdan_id);
|
||||||
|
that.setData({ dingdanList: newList });
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: qiangdanRes.data.msg || '抢单失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
wx.hideLoading();
|
||||||
|
console.error('抢单请求失败:', error);
|
||||||
|
wx.showToast({ title: '网络错误,抢单失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showQiangdanSuccessEffect() {
|
||||||
|
wx.showToast({ title: '抢单成功!', icon: 'success', duration: 2000 });
|
||||||
|
},
|
||||||
|
|
||||||
|
onViewDetail(e) {
|
||||||
|
const { type, content } = e.currentTarget.dataset;
|
||||||
|
wx.showModal({
|
||||||
|
title: type === 'jieshao' ? '订单介绍' : '订单备注',
|
||||||
|
content: content,
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '知道了'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onReachBottom() {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.data.lastRefreshTime < this.data.refreshCooldown) {
|
||||||
|
wx.showToast({
|
||||||
|
title: `操作太快,请${Math.ceil((this.data.refreshCooldown - (now - this.data.lastRefreshTime)) / 1000)}秒后再试`,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.data.isLoading || this.data.isLoadingMore) return;
|
||||||
|
if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) {
|
||||||
|
this.setData({ page: this.data.page + 1 });
|
||||||
|
this.loadDingdanList(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onPullDownRefresh() {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.data.lastRefreshTime < this.data.refreshCooldown) {
|
||||||
|
this.setData({ scrollViewRefreshing: false });
|
||||||
|
wx.showToast({
|
||||||
|
title: `操作太快,请${Math.ceil((this.data.refreshCooldown - (now - this.data.lastRefreshTime)) / 1000)}秒后再试`,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.data.isLoading) {
|
||||||
|
this.setData({ scrollViewRefreshing: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
scrollViewRefreshing: true,
|
||||||
|
lastRefreshTime: now
|
||||||
|
});
|
||||||
|
if (this.data.xuanzhongLeixingId) {
|
||||||
|
this.setData({ page: 1, hasMore: true });
|
||||||
|
this.loadDingdanList(true);
|
||||||
|
} else {
|
||||||
|
this.setData({ scrollViewRefreshing: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
goToDashouRegister() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '/pages/fighter/fighter'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
+533
-121
@@ -1,9 +1,25 @@
|
|||||||
// pages/qiangdan/qiangdan.js
|
// pages/qiangdan/qiangdan.js
|
||||||
const app = getApp();
|
const app = getApp();
|
||||||
import request from '../../utils/request.js';
|
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 PopupService from '../../services/popupService.js';
|
||||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||||
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
||||||
|
import { fetchGonggaoLunbo, isGonggaoCacheValid, getCachedGonggaoLunbo } from '../../utils/display-config.js';
|
||||||
|
import { checkPenaltyForGrab } from '../../utils/grab-order-gate.js';
|
||||||
|
import { ensureRoleAgreement } from '../../utils/role-agreement-gate.js';
|
||||||
|
import { fetchMyZhidingOrders, submitZhidingResponse, processZhidingList, filterZhidingBannerList, ZHIDING_HF_MAP } from '../../utils/zhiding-order.js';
|
||||||
|
import { isFighterOnly, FIGHTER_MINE, isDashouCertified, canEnterAcceptOrder, kickToLoginPage } from '../../utils/fighter-only.js';
|
||||||
|
|
||||||
|
/** 成交指标芯片:有真实样本才展示,过滤假 0% */
|
||||||
|
import { buildDealStatChips } from '../../utils/deal-stat-display.js';
|
||||||
|
import { consumeBadgeFields, mergeTypePendingCounts } from '../../utils/dashou-badges.js';
|
||||||
|
|
||||||
|
/** 抢单池轮播 page_key(勿与点单页 order_pool 混用) */
|
||||||
|
const ACCEPT_ORDER_PAGE_KEY = 'accept_order';
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -30,7 +46,7 @@ Page({
|
|||||||
// 4. 刷新控制字段
|
// 4. 刷新控制字段
|
||||||
scrollViewRefreshing: false,
|
scrollViewRefreshing: false,
|
||||||
lastRefreshTime: 0,
|
lastRefreshTime: 0,
|
||||||
refreshCooldown: 2000,
|
refreshCooldown: 0,
|
||||||
isLoadingMore: false,
|
isLoadingMore: false,
|
||||||
|
|
||||||
// 5. 切换类型冷却
|
// 5. 切换类型冷却
|
||||||
@@ -47,16 +63,142 @@ Page({
|
|||||||
|
|
||||||
// 商品轮播展示(只读 globalData,无额外接口)
|
// 商品轮播展示(只读 globalData,无额外接口)
|
||||||
lunboList: [],
|
lunboList: [],
|
||||||
|
gonggao: '',
|
||||||
|
|
||||||
|
examRequired: false,
|
||||||
|
examPassed: false,
|
||||||
|
_examChecked: false,
|
||||||
|
|
||||||
|
myZhidingList: [],
|
||||||
|
highlightOrderId: '',
|
||||||
|
myZhidingCount: 0,
|
||||||
|
defaultAvatarUrl: '',
|
||||||
|
showZhidingDetail: false,
|
||||||
|
zhidingDetailOrder: null,
|
||||||
|
showLaterModal: false,
|
||||||
|
laterOrderId: '',
|
||||||
|
laterNote: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
async onLoad(options) {
|
async onLoad(options) {
|
||||||
this.syncShopBannerFromGlobal();
|
// 未登录 / 未认证:立刻去登录页,禁止在抢单池空转卡死
|
||||||
|
if (isFighterOnly() && !canEnterAcceptOrder()) {
|
||||||
|
wx.reLaunch({ url: FIGHTER_MINE });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ACCEPT_ORDER_PAGE_KEY)) {
|
||||||
|
const gonggaoCached = getCachedGonggaoLunbo(app, ACCEPT_ORDER_PAGE_KEY);
|
||||||
|
const lunboList = this.processLunboUrls((gonggaoCached && gonggaoCached.shangpinlunbo) || []);
|
||||||
|
const gonggao = (gonggaoCached && gonggaoCached.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);
|
||||||
|
this.tryShowAcceptOrderPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loadGlobalStatus();
|
this.loadGlobalStatus();
|
||||||
await this.loadShangpinLeixing();
|
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;
|
||||||
|
|
||||||
|
this.tryShowAcceptOrderPopup();
|
||||||
|
this._skipShowRefresh = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
async tryShowAcceptOrderPopup() {
|
||||||
|
if (app.globalData._acceptOrderPopupDone) return;
|
||||||
|
// 先确保 OSS 配置已加载,再拉弹窗(否则相对 URL 拼不出图)
|
||||||
|
await this.ensureOssReadyForPopup(4000);
|
||||||
|
if (app.globalData._acceptOrderPopupDone) return;
|
||||||
|
app.globalData._acceptOrderPopupDone = true;
|
||||||
PopupService.checkAndShow(this, 'jiedan');
|
PopupService.checkAndShow(this, 'jiedan');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ensureOssReadyForPopup(timeoutMs = 3000) {
|
||||||
|
const hasOss = () => !!(app.globalData && app.globalData.ossImageUrl);
|
||||||
|
if (hasOss()) return Promise.resolve(true);
|
||||||
|
try {
|
||||||
|
const cached = app.readConfigFromStorage && app.readConfigFromStorage();
|
||||||
|
if (cached && app.applyDynamicConfig) {
|
||||||
|
app.applyDynamicConfig(cached);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
if (hasOss()) return Promise.resolve(true);
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let finished = false;
|
||||||
|
const done = () => {
|
||||||
|
if (finished) return;
|
||||||
|
finished = true;
|
||||||
|
if (app.off) app.off('configApplied', onCfg);
|
||||||
|
clearInterval(poll);
|
||||||
|
clearTimeout(to);
|
||||||
|
resolve(hasOss());
|
||||||
|
};
|
||||||
|
const onCfg = () => done();
|
||||||
|
if (app.on) app.on('configApplied', onCfg);
|
||||||
|
const poll = setInterval(() => { if (hasOss()) done(); }, 100);
|
||||||
|
const to = setTimeout(done, timeoutMs);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
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 () {
|
onHide: function () {
|
||||||
|
// 只释放 PopupService 锁,不强制关掉正在展示的弹窗内容(避免刚拼好 URL 就被清掉)
|
||||||
|
PopupService.reset();
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnload: function () {
|
||||||
const popupComp = this.selectComponent('#popupNotice');
|
const popupComp = this.selectComponent('#popupNotice');
|
||||||
if (popupComp && popupComp.cleanup) {
|
if (popupComp && popupComp.cleanup) {
|
||||||
popupComp.cleanup();
|
popupComp.cleanup();
|
||||||
@@ -64,65 +206,101 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async onShow() {
|
async onShow() {
|
||||||
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
|
if (isFighterOnly() && !canEnterAcceptOrder()) {
|
||||||
if (!phoneOk) return;
|
wx.reLaunch({ url: FIGHTER_MINE });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每次进入抢单池都校验手机号认证
|
||||||
|
{
|
||||||
|
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
|
||||||
|
if (!phoneOk) return;
|
||||||
|
}
|
||||||
|
|
||||||
this.syncShopBannerFromGlobal();
|
|
||||||
this.registerNotificationComponent();
|
this.registerNotificationComponent();
|
||||||
this.loadGlobalStatus();
|
await this.syncDashouProfileFromServer();
|
||||||
|
warmupPindaoConfig(app);
|
||||||
|
|
||||||
if (wx.getStorageSync('uid')) {
|
if (wx.getStorageSync('uid')) {
|
||||||
// IM 延后连接,避免切 Tab 时卡顿;订单列表不自动刷新,由用户下拉刷新
|
reconnectForRole('dashou');
|
||||||
setTimeout(() => {
|
if (app.startImWhenReady) app.startImWhenReady();
|
||||||
reconnectForRole('dashou');
|
}
|
||||||
if (app.startImWhenReady) app.startImWhenReady();
|
|
||||||
}, 600);
|
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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 同步点单端已加载的商品轮播图,仅展示用 */
|
/** 进入页面静默刷新(无 loading 遮罩、不清空列表) */
|
||||||
syncShopBannerFromGlobal() {
|
async silentRefreshOnShow() {
|
||||||
const oss = app.globalData.ossImageUrl || '';
|
try {
|
||||||
const lunboList = (app.globalData.shangpinlunbo || []).map((url) => {
|
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 '';
|
if (!url) return '';
|
||||||
return url.startsWith('http') ? url : oss + url;
|
return url.startsWith('http') ? url : oss + url;
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
this.setData({ lunboList });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async refreshDashouProfileSilent() {
|
async loadGonggaoAndLunbo(forceFetch = false) {
|
||||||
try {
|
const cached = getCachedGonggaoLunbo(app, ACCEPT_ORDER_PAGE_KEY);
|
||||||
const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' });
|
let lunboRaw = (cached && cached.shangpinlunbo) || [];
|
||||||
if (!res || res.data.code != 200) return;
|
let gonggaoText = (cached && cached.shangpingonggao) || '';
|
||||||
const data = res.data.data || {};
|
|
||||||
const patch = {
|
if (forceFetch || !isGonggaoCacheValid(app, ACCEPT_ORDER_PAGE_KEY)) {
|
||||||
dashouNicheng: data.dashounicheng || '',
|
try {
|
||||||
zhanghaoStatus: data.zhanghaostatus || '',
|
const data = await fetchGonggaoLunbo(app, ACCEPT_ORDER_PAGE_KEY);
|
||||||
dashouzhuangtai: data.dashouzhuangtai || '',
|
if (data) {
|
||||||
yajin: data.yajin || 0,
|
lunboRaw = data.shangpinlunbo || [];
|
||||||
jifen: data.jifen || 0,
|
gonggaoText = data.shangpingonggao || '';
|
||||||
clumber: data.clumber || [],
|
}
|
||||||
};
|
} catch (e) {
|
||||||
Object.assign(app.globalData, {
|
const fallback = getCachedGonggaoLunbo(app, ACCEPT_ORDER_PAGE_KEY);
|
||||||
dashouNicheng: patch.dashouNicheng,
|
lunboRaw = (fallback && fallback.shangpinlunbo) || [];
|
||||||
zhanghaoStatus: patch.zhanghaoStatus,
|
gonggaoText = (fallback && fallback.shangpingonggao) || '';
|
||||||
dashouzhuangtai: patch.dashouzhuangtai,
|
|
||||||
yajin: patch.yajin,
|
|
||||||
jinfen: patch.jifen,
|
|
||||||
clumber: patch.clumber,
|
|
||||||
});
|
|
||||||
if (data.dashoustatus !== undefined) {
|
|
||||||
wx.setStorageSync('dashoustatus', data.dashoustatus);
|
|
||||||
app.globalData.dashoustatus = data.dashoustatus;
|
|
||||||
}
|
}
|
||||||
this.setData({
|
}
|
||||||
zhuanghaoStatus: patch.zhanghaoStatus,
|
|
||||||
dashouzhuangtai: patch.dashouzhuangtai,
|
const lunboList = this.processLunboUrls(lunboRaw);
|
||||||
huiyuanList: patch.clumber,
|
const gonggao = gonggaoText;
|
||||||
yajin: patch.yajin,
|
this.setData({ lunboList, gonggao });
|
||||||
jifen: patch.jifen,
|
return { lunboList, gonggao };
|
||||||
});
|
|
||||||
} catch (e) {}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
registerNotificationComponent() {
|
registerNotificationComponent() {
|
||||||
@@ -148,9 +326,36 @@ Page({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 拉取最新打手信息(会员/押金/积分),并刷新订单卡片上的会员展示 */
|
||||||
|
async syncDashouProfileFromServer() {
|
||||||
|
if (!wx.getStorageSync('token')) return;
|
||||||
|
try {
|
||||||
|
const res = await request({ url: '/yonghu/dashouxinxi', method: 'POST' });
|
||||||
|
if (res && res.data && res.data.code == 200 && res.data.data) {
|
||||||
|
const data = res.data.data;
|
||||||
|
if (Number(data.zhanghaostatus) !== 1) {
|
||||||
|
kickToLoginPage(
|
||||||
|
data.fengjin_yuanyin
|
||||||
|
? `账号状态异常,您的账号已被封禁。原因:${data.fengjin_yuanyin}`
|
||||||
|
: '账号状态异常,您的账号已被封禁,请联系客服'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
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() {
|
async loadShangpinLeixing(autoLoadOrders = false, preserveSelection = false, showLoading = true) {
|
||||||
wx.showLoading({ title: '加载商品类型...' });
|
if (showLoading) wx.showLoading({ title: '加载商品类型...' });
|
||||||
|
const prevId = this.data.xuanzhongLeixingId;
|
||||||
try {
|
try {
|
||||||
const res = await request({
|
const res = await request({
|
||||||
url: '/dingdan/dsqdhqddlx',
|
url: '/dingdan/dsqdhqddlx',
|
||||||
@@ -166,15 +371,18 @@ Page({
|
|||||||
else if (Array.isArray(data.list)) list = data.list;
|
else if (Array.isArray(data.list)) list = data.list;
|
||||||
else if (Array.isArray(data)) list = data;
|
else if (Array.isArray(data)) list = data;
|
||||||
}
|
}
|
||||||
const processedList = this.processTupianUrl(list);
|
const processedList = mergeTypePendingCounts(this.processTupianUrl(list), data.data?.type_pending_counts);
|
||||||
|
consumeBadgeFields(data.data || {});
|
||||||
|
const firstId = processedList[0]?.id || null;
|
||||||
|
const keepPrev = preserveSelection && prevId && processedList.some((i) => i.id === prevId);
|
||||||
|
const selectedId = keepPrev ? prevId : firstId;
|
||||||
this.setData({
|
this.setData({
|
||||||
shangpinleixing: processedList,
|
shangpinleixing: processedList,
|
||||||
xuanzhongLeixingId: processedList[0]?.id || null
|
xuanzhongLeixingId: selectedId,
|
||||||
});
|
});
|
||||||
if (this.data.xuanzhongLeixingId) {
|
if (autoLoadOrders && selectedId) {
|
||||||
this.loadDingdanList(true);
|
await this.loadDingdanList(true);
|
||||||
// 🆕 加载板块标签
|
await this.loadBankuaiBiaoqian();
|
||||||
this.loadBankuaiBiaoqian();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' });
|
wx.showToast({ title: res.data?.msg || '加载商品类型失败', icon: 'none' });
|
||||||
@@ -182,7 +390,7 @@ Page({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
wx.showToast({ title: '网络错误,加载失败', icon: 'none' });
|
wx.showToast({ title: '网络错误,加载失败', icon: 'none' });
|
||||||
} finally {
|
} finally {
|
||||||
wx.hideLoading();
|
if (showLoading) wx.hideLoading();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -249,8 +457,8 @@ Page({
|
|||||||
xuanzhongBiaoqianId: 0 // 重置标签筛选
|
xuanzhongBiaoqianId: 0 // 重置标签筛选
|
||||||
});
|
});
|
||||||
await this.loadDingdanList(true);
|
await this.loadDingdanList(true);
|
||||||
// 🆕 切换类型后加载新标签
|
|
||||||
await this.loadBankuaiBiaoqian();
|
await this.loadBankuaiBiaoqian();
|
||||||
|
this.persistPageCache();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('切换类型失败:', error);
|
console.error('切换类型失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -270,19 +478,24 @@ Page({
|
|||||||
hasMore: true
|
hasMore: true
|
||||||
});
|
});
|
||||||
await this.loadDingdanList(true);
|
await this.loadDingdanList(true);
|
||||||
|
this.persistPageCache();
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载订单列表
|
// 加载订单列表
|
||||||
async loadDingdanList(isRefresh = false) {
|
async loadDingdanList(isRefresh = false, silent = false) {
|
||||||
if (this.data.isLoading || !this.data.xuanzhongLeixingId) return;
|
if ((!silent && this.data.isLoading) || !this.data.xuanzhongLeixingId) return;
|
||||||
|
if (silent && this._listRequesting) return;
|
||||||
|
|
||||||
const loadPage = isRefresh ? 1 : this.data.page;
|
const loadPage = isRefresh ? 1 : this.data.page;
|
||||||
if (!isRefresh && !this.data.hasMore) return;
|
if (!isRefresh && !this.data.hasMore) return;
|
||||||
|
|
||||||
this.setData({
|
if (!silent) {
|
||||||
isLoading: true,
|
this.setData({
|
||||||
isLoadingMore: !isRefresh
|
isLoading: true,
|
||||||
});
|
isLoadingMore: !isRefresh,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._listRequesting = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await request({
|
const res = await request({
|
||||||
@@ -302,11 +515,18 @@ Page({
|
|||||||
isLoadingMore: false,
|
isLoadingMore: false,
|
||||||
scrollViewRefreshing: false
|
scrollViewRefreshing: false
|
||||||
});
|
});
|
||||||
|
this._listRequesting = false;
|
||||||
|
|
||||||
if (res.data.code === 200 || res.data.code === 0) {
|
if (res.data.code === 200 || res.data.code === 0) {
|
||||||
const newList = res.data.data.list || [];
|
const payload = res.data.data || {};
|
||||||
const hasMore = res.data.data.has_more || false;
|
consumeBadgeFields(payload);
|
||||||
const serverClumber = res.data.data.clumber;
|
if (payload.type_pending_counts) {
|
||||||
|
const merged = mergeTypePendingCounts(this.data.shangpinleixing, payload.type_pending_counts);
|
||||||
|
this.setData({ shangpinleixing: merged });
|
||||||
|
}
|
||||||
|
const newList = payload.list || [];
|
||||||
|
const hasMore = payload.has_more || false;
|
||||||
|
const serverClumber = payload.clumber;
|
||||||
if (Array.isArray(serverClumber) && serverClumber.length) {
|
if (Array.isArray(serverClumber) && serverClumber.length) {
|
||||||
app.globalData.clumber = serverClumber;
|
app.globalData.clumber = serverClumber;
|
||||||
this.setData({ huiyuanList: serverClumber });
|
this.setData({ huiyuanList: serverClumber });
|
||||||
@@ -322,6 +542,7 @@ Page({
|
|||||||
page: loadPage,
|
page: loadPage,
|
||||||
hasMore: hasMore
|
hasMore: hasMore
|
||||||
});
|
});
|
||||||
|
this.persistPageCache();
|
||||||
|
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
this.setData({ lastRefreshTime: Date.now() });
|
this.setData({ lastRefreshTime: Date.now() });
|
||||||
@@ -336,25 +557,36 @@ Page({
|
|||||||
isLoadingMore: false,
|
isLoadingMore: false,
|
||||||
scrollViewRefreshing: false
|
scrollViewRefreshing: false
|
||||||
});
|
});
|
||||||
wx.showToast({ title: '网络请求失败', icon: 'none' });
|
this._listRequesting = false;
|
||||||
|
if (!silent) {
|
||||||
|
wx.showToast({ title: '网络请求失败', icon: 'none' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 处理单条订单数据(包含标签、会员判断)
|
// 处理单条订单数据(包含标签、会员判断)
|
||||||
processDingdanItem(item) {
|
processDingdanItem(item) {
|
||||||
const ossUrl = app.globalData.ossImageUrl || '';
|
const ossUrl = app.globalData.ossImageUrl || '';
|
||||||
|
const leixing = this.data.shangpinleixing.find((l) => l.id == item.leixing_id);
|
||||||
let fullTupianUrl = '';
|
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 {
|
} else {
|
||||||
const leixing = this.data.shangpinleixing.find(l => l.id === item.leixing_id);
|
fullTupianUrl = '/images/default-order.png';
|
||||||
fullTupianUrl = leixing ? leixing.full_tupian_url : '/images/default-order.png';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isZhiding = item.zhuangtai === 7;
|
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) {
|
if (item.zhiding_avatar) {
|
||||||
zhidingAvatar = !item.zhiding_avatar.startsWith('http')
|
zhidingAvatar = !item.zhiding_avatar.startsWith('http')
|
||||||
? ossUrl + item.zhiding_avatar
|
? ossUrl + item.zhiding_avatar
|
||||||
@@ -362,33 +594,49 @@ Page({
|
|||||||
}
|
}
|
||||||
const zhidingNicheng = item.zhiding_nicheng || '';
|
const zhidingNicheng = item.zhiding_nicheng || '';
|
||||||
|
|
||||||
// 🆕 判断用户是否有订单所需的会员(优先后端 hasRequiredMember)
|
// 订单要求指定会员时,核对用户是否持有该会员类型(优先后端字段)
|
||||||
let hasRequiredMember = true;
|
let hasRequiredMember = true;
|
||||||
if (item.hasRequiredMember !== undefined) {
|
if (item.hasRequiredMember !== undefined) {
|
||||||
hasRequiredMember = !!item.hasRequiredMember;
|
hasRequiredMember = !!item.hasRequiredMember;
|
||||||
} else if (item.has_required_member !== undefined) {
|
} else if (item.has_required_member !== undefined) {
|
||||||
hasRequiredMember = !!item.has_required_member;
|
hasRequiredMember = !!item.has_required_member;
|
||||||
} else if (item.yaoqiuleixing == 1 && item.huiyuan_id) {
|
} else if (item.yaoqiuleixing == 1 && item.huiyuan_id) {
|
||||||
const userHasIt = this.data.huiyuanList.some(h =>
|
hasRequiredMember = userHasHuiyuan(this.data.huiyuanList, item.huiyuan_id);
|
||||||
(h.huiyuanid == item.huiyuan_id) || (h.huiyuan_id == item.huiyuan_id)
|
|
||||||
);
|
|
||||||
hasRequiredMember = userHasIt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let shangjiaAvatar = getDefaultAvatarUrl(app);
|
||||||
|
const sjAvatar = (item.sj_avatar || '').trim();
|
||||||
|
if (sjAvatar) {
|
||||||
|
shangjiaAvatar = sjAvatar.startsWith('http') ? sjAvatar : ossUrl + sjAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = normalizeOrderTags(item)
|
||||||
|
|
||||||
|
const dealStatChips = buildDealStatChips(item.shangjia_deal_stat, {
|
||||||
|
dealLabel: '成交率',
|
||||||
|
fineLabel: '罚款率',
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
full_tupian_url: fullTupianUrl,
|
full_tupian_url: fullTupianUrl,
|
||||||
|
leixing_icon_url: fullTupianUrl,
|
||||||
|
shangjia_avatar_full: shangjiaAvatar,
|
||||||
isZhiding: isZhiding,
|
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,
|
isPingtai: item.pingtai == 1,
|
||||||
isShangjia: item.pingtai == 2,
|
isShangjia: item.pingtai == 2,
|
||||||
zhiding_avatar_full: zhidingAvatar,
|
zhiding_avatar_full: zhidingAvatar,
|
||||||
zhiding_nicheng: zhidingNicheng,
|
zhiding_nicheng: zhidingNicheng,
|
||||||
// 🆕 三层标签(后端返回,直接保留)
|
...tags,
|
||||||
xuqiu_biaoqian: item.xuqiu_biaoqian || [],
|
shangjia_youzhi: !!item.shangjia_youzhi,
|
||||||
dashou_biaoqian: item.dashou_biaoqian || [],
|
|
||||||
shangjia_biaoqian: item.shangjia_biaoqian || [],
|
|
||||||
// 🆕 是否有查看价格的权限
|
// 🆕 是否有查看价格的权限
|
||||||
hasRequiredMember: hasRequiredMember,
|
hasRequiredMember: hasRequiredMember,
|
||||||
|
dealStatChips,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -399,13 +647,16 @@ Page({
|
|||||||
|
|
||||||
switch (failureType) {
|
switch (failureType) {
|
||||||
case 'huiyuan':
|
case 'huiyuan':
|
||||||
params = { needScroll: '0', scrollTo: 'member' };
|
url = '/pages/fighter-recharge/fighter-recharge';
|
||||||
|
params = { scrollTo: 'member' };
|
||||||
break;
|
break;
|
||||||
case 'yajin':
|
case 'yajin':
|
||||||
params = { needScroll: '1', scrollTo: 'bottom', requiredYajin: requiredYajin };
|
url = '/pages/fighter-recharge/fighter-deposit';
|
||||||
|
params = { requiredYajin: requiredYajin };
|
||||||
break;
|
break;
|
||||||
case 'jifen':
|
case 'jifen':
|
||||||
params = { needScroll: '1', scrollTo: 'bottom' };
|
url = '/pages/fighter-recharge/fighter-recharge';
|
||||||
|
params = { scrollTo: 'jifen' };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,11 +675,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) {
|
async onQiangdanTap(e) {
|
||||||
const dingdanItem = e.currentTarget.dataset.item;
|
const dingdanItem = e.currentTarget.dataset.item;
|
||||||
if (!dingdanItem) return;
|
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: 打手身份
|
// 校验1: 打手身份
|
||||||
if (!this.data.dashoustatus || this.data.dashoustatus != 1) {
|
if (!this.data.dashoustatus || this.data.dashoustatus != 1) {
|
||||||
wx.showToast({ title: '请先开启接单员身份', icon: 'none' });
|
wx.showToast({ title: '请先开启接单员身份', icon: 'none' });
|
||||||
@@ -453,9 +756,7 @@ Page({
|
|||||||
}
|
}
|
||||||
// 校验5: 会员要求
|
// 校验5: 会员要求
|
||||||
if (dingdanItem.yaoqiuleixing == 1) {
|
if (dingdanItem.yaoqiuleixing == 1) {
|
||||||
const hasHuiyuan = this.data.huiyuanList.some(h =>
|
const hasHuiyuan = userHasHuiyuan(this.data.huiyuanList, dingdanItem.huiyuan_id);
|
||||||
(h.huiyuanid == dingdanItem.huiyuan_id) || (h.huiyuan_id == dingdanItem.huiyuan_id)
|
|
||||||
);
|
|
||||||
if (!hasHuiyuan) {
|
if (!hasHuiyuan) {
|
||||||
wx.showToast({
|
wx.showToast({
|
||||||
title: '未开通对应会员,无法抢单',
|
title: '未开通对应会员,无法抢单',
|
||||||
@@ -495,6 +796,9 @@ Page({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const signed = await ensureRoleAgreement('dashou', 'qiangdan');
|
||||||
|
if (!signed) return;
|
||||||
|
|
||||||
// 确认框
|
// 确认框
|
||||||
const that = this;
|
const that = this;
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
@@ -521,6 +825,8 @@ Page({
|
|||||||
item => item.dingdan_id !== dingdanItem.dingdan_id
|
item => item.dingdan_id !== dingdanItem.dingdan_id
|
||||||
);
|
);
|
||||||
that.setData({ dingdanList: newList });
|
that.setData({ dingdanList: newList });
|
||||||
|
that.persistPageCache();
|
||||||
|
that.loadMyZhidingOrders(true);
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({
|
wx.showToast({
|
||||||
title: qiangdanRes.data.msg || '抢单失败',
|
title: qiangdanRes.data.msg || '抢单失败',
|
||||||
@@ -551,43 +857,138 @@ Page({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onReachBottom() {
|
async loadMyZhidingOrders(silent = false) {
|
||||||
const now = Date.now();
|
if (!this.data.uid && !wx.getStorageSync('uid')) return;
|
||||||
const lastTime = this.data.lastRefreshTime;
|
try {
|
||||||
const cooldown = this.data.refreshCooldown;
|
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) {
|
openZhidingDetail(e) {
|
||||||
wx.showToast({
|
const item = e.currentTarget.dataset.item;
|
||||||
title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`,
|
if (!item) return;
|
||||||
icon: 'none',
|
this.setData({ showZhidingDetail: true, zhidingDetailOrder: item });
|
||||||
duration: 1500
|
},
|
||||||
});
|
|
||||||
|
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;
|
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() {},
|
||||||
|
|
||||||
|
goToComplaintCreate() {
|
||||||
|
wx.navigateTo({ url: '/pages/gongdan/create/create' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onReachBottom() {
|
||||||
if (this.data.isLoading || this.data.isLoadingMore) return;
|
if (this.data.isLoading || this.data.isLoadingMore) return;
|
||||||
|
|
||||||
if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) {
|
if (this.data.hasMore && !this.data.isLoading && this.data.xuanzhongLeixingId) {
|
||||||
this.setData({ page: this.data.page + 1 });
|
this.setData({ page: this.data.page + 1 });
|
||||||
this.loadDingdanList(false);
|
this.loadDingdanList(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onPullDownRefresh() {
|
async onPullDownRefresh() {
|
||||||
const now = Date.now();
|
|
||||||
const lastTime = this.data.lastRefreshTime;
|
|
||||||
const cooldown = this.data.refreshCooldown;
|
|
||||||
|
|
||||||
if (now - lastTime < cooldown) {
|
|
||||||
this.setData({ scrollViewRefreshing: false });
|
|
||||||
wx.showToast({
|
|
||||||
title: `操作太快,请${Math.ceil((cooldown - (now - lastTime)) / 1000)}秒后再试`,
|
|
||||||
icon: 'none',
|
|
||||||
duration: 1500
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.data.isLoading) {
|
if (this.data.isLoading) {
|
||||||
this.setData({ scrollViewRefreshing: false });
|
this.setData({ scrollViewRefreshing: false });
|
||||||
return;
|
return;
|
||||||
@@ -595,15 +996,26 @@ Page({
|
|||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
scrollViewRefreshing: true,
|
scrollViewRefreshing: true,
|
||||||
lastRefreshTime: now,
|
lastRefreshTime: Date.now(),
|
||||||
page: 1,
|
page: 1,
|
||||||
hasMore: true
|
hasMore: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.data.xuanzhongLeixingId) {
|
try {
|
||||||
this.refreshDashouProfileSilent();
|
const banner = await this.loadGonggaoAndLunbo(true);
|
||||||
this.loadDingdanList(true);
|
await this.syncDashouProfileFromServer();
|
||||||
} else {
|
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 });
|
this.setData({ scrollViewRefreshing: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
{
|
{
|
||||||
"navigationBarTitleText": "抢单大厅",
|
"navigationBarTitleText": "抢单列表",
|
||||||
"navigationBarBackgroundColor": "#c4b5fd",
|
"navigationBarBackgroundColor": "#f7dc51",
|
||||||
|
"backgroundColorTop": "#f7dc51",
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"enablePullDownRefresh": false,
|
"enablePullDownRefresh": false,
|
||||||
"backgroundTextStyle": "dark",
|
"backgroundTextStyle": "dark",
|
||||||
"backgroundColor": "#f5f3ff",
|
"backgroundColor": "#fff8e1",
|
||||||
"usingComponents": {
|
"usingComponents": {
|
||||||
"chenghao-tag": "/components/chenghao-tag/chenghao-tag",
|
"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",
|
||||||
|
"popup-notice": "/components/popup-notice/popup-notice"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
refresher-default-style="black"
|
refresher-default-style="black"
|
||||||
|
|
||||||
refresher-background="#f5f3ff"
|
refresher-background="#fff8e1"
|
||||||
|
|
||||||
refresher-triggered="{{scrollViewRefreshing}}"
|
refresher-triggered="{{scrollViewRefreshing}}"
|
||||||
|
|
||||||
@@ -38,6 +38,44 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 公告置顶 -->
|
||||||
|
<view class="tousu-top-bar" catchtap="goToComplaintCreate">
|
||||||
|
<text class="tousu-top-bar-txt">投诉 / 反馈</text>
|
||||||
|
<text class="tousu-top-bar-sub">点这里提交工单</text>
|
||||||
|
<text class="tousu-top-bar-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="xym-gonggao-bar" wx:if="{{gonggao}}">
|
||||||
|
<image class="xym-gonggao-ico" src="https://bintao.xmxym88.com/xcx/bintao/38.png" mode="aspectFit"/>
|
||||||
|
<text class="xym-gonggao-txt">{{gonggao}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 被指定订单提醒 -->
|
||||||
|
<view class="my-zhiding-banner" wx:if="{{myZhidingList.length > 0}}">
|
||||||
|
<view class="my-zhiding-banner-head">
|
||||||
|
<view class="my-zhiding-head-left">
|
||||||
|
<text class="my-zhiding-badge">指定给您</text>
|
||||||
|
<text class="my-zhiding-count-num">{{myZhidingCount || myZhidingList.length}}单</text>
|
||||||
|
</view>
|
||||||
|
<text class="my-zhiding-sub">请确认是否接待</text>
|
||||||
|
</view>
|
||||||
|
<view wx:for="{{myZhidingList}}" wx:key="dingdan_id" class="my-zhiding-card {{item.isHighlighted ? 'my-zhiding-card--highlight' : ''}}">
|
||||||
|
<view class="my-zhiding-card-main" data-item="{{item}}" bindtap="openZhidingDetail">
|
||||||
|
<view class="my-zhiding-card-top">
|
||||||
|
<text class="my-zhiding-order-id">单号 {{item.dingdan_id}}</text>
|
||||||
|
<text class="my-zhiding-reward">¥{{item.dashou_fencheng || 0}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="my-zhiding-desc line2">{{item.jieshao || '暂无介绍'}}</text>
|
||||||
|
<text class="my-zhiding-status" wx:if="{{item.zhiding_hf_text}}">您的回复:{{item.zhiding_hf_text}}{{item.zhiding_dhj_sm ? ' · ' + item.zhiding_dhj_sm : ''}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="my-zhiding-actions">
|
||||||
|
<view class="zhiding-act zhiding-act--ghost" data-item="{{item}}" catchtap="onZhidingReject">不想接</view>
|
||||||
|
<view class="zhiding-act zhiding-act--ghost" data-item="{{item}}" catchtap="onZhidingLater">等会接</view>
|
||||||
|
<view class="zhiding-act zhiding-act--primary" data-item="{{item}}" catchtap="onZhidingAccept">立即接待</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 商品轮播(只读 globalData,与点单端同源) -->
|
<!-- 商品轮播(只读 globalData,与点单端同源) -->
|
||||||
|
|
||||||
<view class="xym-lunbo-container" wx:if="{{lunboList.length > 0}}">
|
<view class="xym-lunbo-container" wx:if="{{lunboList.length > 0}}">
|
||||||
@@ -50,7 +88,7 @@
|
|||||||
|
|
||||||
indicator-color="rgba(255,255,255,0.6)"
|
indicator-color="rgba(255,255,255,0.6)"
|
||||||
|
|
||||||
indicator-active-color="#9333ea"
|
indicator-active-color="#ffd061"
|
||||||
|
|
||||||
autoplay="{{lunboList.length > 1}}"
|
autoplay="{{lunboList.length > 1}}"
|
||||||
|
|
||||||
@@ -74,11 +112,11 @@
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="xym-section-gap" wx:if="{{lunboList.length > 0}}"></view>
|
||||||
|
|
||||||
<!-- 商品类型选择 -->
|
<!-- 商品类型选择 -->
|
||||||
|
|
||||||
<view class="leixing-quyu">
|
<view class="leixing-quyu dingdanxiang1 filter-card mx20">
|
||||||
|
|
||||||
<scroll-view class="leixing-scroll" scroll-x enhanced show-scrollbar="{{false}}">
|
<scroll-view class="leixing-scroll" scroll-x enhanced show-scrollbar="{{false}}">
|
||||||
|
|
||||||
@@ -98,7 +136,10 @@
|
|||||||
|
|
||||||
<view wx:if="{{xuanzhongLeixingId == item.id}}" class="guangyun-effect"></view>
|
<view wx:if="{{xuanzhongLeixingId == item.id}}" class="guangyun-effect"></view>
|
||||||
|
|
||||||
<image class="leixing-tupian" src="{{item.full_tupian_url}}" mode="aspectFill"/>
|
<view class="leixing-pic-wrap">
|
||||||
|
<image class="leixing-tupian" src="{{item.full_tupian_url}}" mode="aspectFill"/>
|
||||||
|
<view class="leixing-badge" wx:if="{{item.pending_badge}}">{{item.pending_badge}}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<text class="leixing-jieshao">{{item.jieshao}}</text>
|
<text class="leixing-jieshao">{{item.jieshao}}</text>
|
||||||
|
|
||||||
@@ -176,7 +217,7 @@
|
|||||||
|
|
||||||
<!-- 平台订单(逍遥梦卡片布局) -->
|
<!-- 平台订单(逍遥梦卡片布局) -->
|
||||||
|
|
||||||
<view wx:if="{{item.isPingtai}}" class="xym-order-item xym-pingtai-order" data-item="{{item}}">
|
<view wx:if="{{item.isPingtai}}" class="xym-order-item xym-pingtai-order {{item.isMyZhiding ? 'order-my-zhiding' : ''}} {{item.isHighlighted ? 'order-zhiding-highlight' : ''}}" data-item="{{item}}">
|
||||||
|
|
||||||
<view class="xym-pingtai-head flexb">
|
<view class="xym-pingtai-head flexb">
|
||||||
|
|
||||||
@@ -190,16 +231,6 @@
|
|||||||
|
|
||||||
<view class="order-con">
|
<view class="order-con">
|
||||||
|
|
||||||
<view wx:if="{{item.isZhiding}}" class="zhiding-strip myflex light">
|
|
||||||
|
|
||||||
<text class="zhiding-label">指定</text>
|
|
||||||
|
|
||||||
<image wx:if="{{item.zhiding_avatar_full}}" class="zhiding-avatar" src="{{item.zhiding_avatar_full}}" mode="aspectFill"/>
|
|
||||||
|
|
||||||
<text class="zhiding-name">{{item.zhiding_nicheng || '指定接单员'}}</text>
|
|
||||||
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="order-row myflex">
|
<view class="order-row myflex">
|
||||||
|
|
||||||
<image class="o-logo" src="{{item.full_tupian_url}}" mode="aspectFill"/>
|
<image class="o-logo" src="{{item.full_tupian_url}}" mode="aspectFill"/>
|
||||||
@@ -212,6 +243,20 @@
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<block wx:if="{{item.isZhiding}}">
|
||||||
|
<view class="zhiding-strip light">
|
||||||
|
<view class="zhiding-strip-top myflex">
|
||||||
|
<text class="zhiding-label">指定</text>
|
||||||
|
<image class="zhiding-avatar" src="{{item.zhiding_avatar_full || defaultAvatarUrl}}" mode="aspectFill"/>
|
||||||
|
<text class="zhiding-name">{{item.zhiding_nicheng || '指定接单员'}}</text>
|
||||||
|
</view>
|
||||||
|
<view wx:if="{{item.dashou_biaoqian.length > 0 || item.zhiding_identity_biaoqian.length > 0}}" class="zhiding-strip-tags">
|
||||||
|
<chenghao-tag wx:for="{{item.dashou_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
<chenghao-tag wx:for="{{item.zhiding_identity_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
<view class="reward-badge platform-reward" wx:if="{{item.hasRequiredMember}}">
|
<view class="reward-badge platform-reward" wx:if="{{item.hasRequiredMember}}">
|
||||||
|
|
||||||
<text class="reward-yen sm">¥</text>
|
<text class="reward-yen sm">¥</text>
|
||||||
@@ -226,9 +271,9 @@
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view wx:if="{{item.beizhu}}" class="remark-block gold" data-type="beizhu" data-content="{{item.beizhu}}" bindtap="onViewDetail">
|
<view class="remark-block gold" data-type="beizhu" data-content="{{item.beizhu}}" bindtap="onViewDetail">
|
||||||
|
|
||||||
<text class="remark-label">备注:</text>{{item.beizhu}}
|
<text class="remark-label">备注:</text>{{item.beizhu || '暂无'}}
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -236,10 +281,10 @@
|
|||||||
|
|
||||||
<text class="xuqiu-label">需求标签</text>
|
<text class="xuqiu-label">需求标签</text>
|
||||||
|
|
||||||
<scroll-view class="biaoqian-inline-scroll" scroll-x>
|
<scroll-view class="biaoqian-inline-scroll" scroll-x enable-flex>
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
<chenghao-tag wx:for="{{item.xuqiu_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
<chenghao-tag wx:for="{{item.xuqiu_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
@@ -248,7 +293,7 @@
|
|||||||
|
|
||||||
<text class="o-amt light">平台派单</text>
|
<text class="o-amt light">平台派单</text>
|
||||||
|
|
||||||
<view class="qiangdan flexa btn-bg btn-qiang btn-qiang-brown" data-item="{{item}}" bindtap="onQiangdanTap">抢单</view>
|
<view class="qiangdan flexa btn-bg btn-qiang btn-qiang-brown" data-item="{{item}}" bindtap="onQiangdanTap">{{item.isMyZhiding ? '立即接待' : '抢单'}}</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -260,9 +305,87 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 优质商家订单(金牌卡片) -->
|
||||||
|
<view wx:elif="{{item.isShangjia && item.shangjia_youzhi}}" class="xym-order-item gold-card {{item.isMyZhiding ? 'order-my-zhiding' : ''}} {{item.isHighlighted ? 'order-zhiding-highlight' : ''}}" data-item="{{item}}">
|
||||||
|
<view class="gold-head flexb">
|
||||||
|
<view class="kehuduan-banner-wrap">
|
||||||
|
<image class="gold-banner" src="https://bintao.xmxym88.com/xcx/bintao/82.png" mode="widthFix"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="gold-body-wrap">
|
||||||
|
<view class="order-con gold-inner">
|
||||||
|
<view class="order-row myflex">
|
||||||
|
<image class="o-logo" src="{{item.leixing_icon_url}}" mode="aspectFill"/>
|
||||||
|
<view class="o-col">
|
||||||
|
<view class="o-goods line2" data-type="jieshao" data-content="{{item.jieshao}}" bindtap="onViewDetail">{{item.jieshao || '暂无介绍'}}</view>
|
||||||
|
<view class="tag-row myflex">
|
||||||
|
<text class="tag-pill tag-youzhi">优质商家</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<block wx:if="{{item.isZhiding}}">
|
||||||
|
<view class="zhiding-strip">
|
||||||
|
<view class="zhiding-strip-top myflex">
|
||||||
|
<text class="zhiding-label">指定</text>
|
||||||
|
<image class="zhiding-avatar" src="{{item.zhiding_avatar_full || defaultAvatarUrl}}" mode="aspectFill"/>
|
||||||
|
<text class="zhiding-name">{{item.zhiding_nicheng || '指定接单员'}}</text>
|
||||||
|
</view>
|
||||||
|
<view wx:if="{{item.dashou_biaoqian.length > 0 || item.zhiding_identity_biaoqian.length > 0}}" class="zhiding-strip-tags">
|
||||||
|
<chenghao-tag wx:for="{{item.dashou_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
<chenghao-tag wx:for="{{item.zhiding_identity_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<view class="reward-badge normal-reward gold-reward" wx:if="{{item.hasRequiredMember}}">
|
||||||
|
<text class="reward-yen sm">¥</text>
|
||||||
|
<text class="reward-num dark">{{item.dashou_fencheng || 0}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="reward-badge member-tip" wx:else>
|
||||||
|
<text class="reward-tip">未开通会员</text>
|
||||||
|
</view>
|
||||||
|
<view class="remark-block dark" data-type="beizhu" data-content="{{item.beizhu}}" bindtap="onViewDetail">
|
||||||
|
<text class="remark-label dark-t">商家备注:</text>{{item.beizhu || '暂无'}}
|
||||||
|
</view>
|
||||||
|
<view wx:if="{{item.shangjia_biaoqian.length > 0 || item.shangjia_identity_biaoqian.length > 0 || item.xuqiu_biaoqian.length > 0}}" class="xuqiu-tags-row">
|
||||||
|
<scroll-view wx:if="{{item.shangjia_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex>
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.shangjia_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view wx:if="{{item.shangjia_identity_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex style="margin-top:8rpx">
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.shangjia_identity_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view wx:if="{{item.xuqiu_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex style="margin-top:8rpx">
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.xuqiu_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
<view class="merchant-plain flexb">
|
||||||
|
<view class="merchant-user myflex">
|
||||||
|
<image class="m-avatar" src="{{item.shangjia_avatar_full}}" mode="aspectFill"/>
|
||||||
|
<view class="m-info">
|
||||||
|
<view class="m-name m-name-light line1">{{item.sjnicheng || '未知商家'}}</view>
|
||||||
|
<view class="m-sn m-sn-light">发布于 {{item.creat_time}}</view>
|
||||||
|
<view class="merchant-stat-row" wx:if="{{item.dealStatChips.length}}">
|
||||||
|
<text class="merchant-stat {{c.hl ? 'highlight' : ''}}" wx:for="{{item.dealStatChips}}" wx:for-item="c" wx:key="k">{{c.t}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="qiangdan flexa btn-bg btn-qiang" data-item="{{item}}" bindtap="onQiangdanTap">{{item.isMyZhiding ? '立即接待' : '抢单'}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="o-foot flexb kehuduan-foot gold-foot-text-only">
|
||||||
|
<text class="o-amt-grey">商家派单</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 商家订单(逍遥梦卡片布局) -->
|
<!-- 商家订单(逍遥梦卡片布局) -->
|
||||||
|
|
||||||
<view wx:elif="{{item.isShangjia}}" class="xym-order-item xym-shangjia-order" data-item="{{item}}">
|
<view wx:elif="{{item.isShangjia}}" class="xym-order-item xym-shangjia-order {{item.isMyZhiding ? 'order-my-zhiding' : ''}} {{item.isHighlighted ? 'order-zhiding-highlight' : ''}}" data-item="{{item}}">
|
||||||
|
|
||||||
<view class="xym-shangjia-head flexb">
|
<view class="xym-shangjia-head flexb">
|
||||||
|
|
||||||
@@ -276,21 +399,30 @@
|
|||||||
|
|
||||||
<view class="order-con">
|
<view class="order-con">
|
||||||
|
|
||||||
<view wx:if="{{item.isZhiding}}" class="zhiding-strip myflex">
|
<block wx:if="{{item.isZhiding}}">
|
||||||
|
<view class="zhiding-strip">
|
||||||
<text class="zhiding-label">指定</text>
|
<view class="zhiding-strip-top myflex">
|
||||||
|
<text class="zhiding-label">指定</text>
|
||||||
<image wx:if="{{item.zhiding_avatar_full}}" class="zhiding-avatar" src="{{item.zhiding_avatar_full}}" mode="aspectFill"/>
|
<image class="zhiding-avatar" src="{{item.zhiding_avatar_full || defaultAvatarUrl}}" mode="aspectFill"/>
|
||||||
|
<text class="zhiding-name">{{item.zhiding_nicheng || '指定接单员'}}</text>
|
||||||
<text class="zhiding-name">{{item.zhiding_nicheng || '指定接单员'}}</text>
|
</view>
|
||||||
|
<view wx:if="{{item.dashou_biaoqian.length > 0 || item.zhiding_identity_biaoqian.length > 0}}" class="zhiding-strip-tags">
|
||||||
</view>
|
<chenghao-tag wx:for="{{item.dashou_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
<chenghao-tag wx:for="{{item.zhiding_identity_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
<view class="merchant-line myflex">
|
<view class="merchant-line myflex">
|
||||||
|
|
||||||
<image class="m-avatar-sm" src="{{item.full_tupian_url}}" mode="aspectFill"/>
|
<image class="m-avatar-sm" src="{{item.shangjia_avatar_full}}" mode="aspectFill"/>
|
||||||
|
|
||||||
<text class="m-name-sm">{{item.sjnicheng || '未知商家'}}</text>
|
<view class="m-meta-col">
|
||||||
|
<text class="m-name-sm">{{item.sjnicheng || '未知商家'}}</text>
|
||||||
|
<view class="merchant-stat-row" wx:if="{{item.dealStatChips.length}}">
|
||||||
|
<text class="merchant-stat {{c.hl ? 'highlight' : ''}}" wx:for="{{item.dealStatChips}}" wx:for-item="c" wx:key="k">{{c.t}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -318,24 +450,33 @@
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view wx:if="{{item.beizhu}}" class="remark-block dark" data-type="beizhu" data-content="{{item.beizhu}}" bindtap="onViewDetail">
|
<view class="remark-block dark" data-type="beizhu" data-content="{{item.beizhu}}" bindtap="onViewDetail">
|
||||||
|
|
||||||
<text class="remark-label">商家备注:</text>{{item.beizhu}}
|
<text class="remark-label">商家备注:</text>{{item.beizhu || '暂无'}}
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view wx:if="{{item.shangjia_biaoqian.length > 0 || item.xuqiu_biaoqian.length > 0}}" class="xuqiu-tags-row">
|
<view wx:if="{{item.shangjia_biaoqian.length > 0 || item.shangjia_identity_biaoqian.length > 0 || item.xuqiu_biaoqian.length > 0}}" class="xuqiu-tags-row">
|
||||||
|
|
||||||
<scroll-view wx:if="{{item.shangjia_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x>
|
<scroll-view wx:if="{{item.shangjia_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex>
|
||||||
|
|
||||||
<chenghao-tag wx:for="{{item.shangjia_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
|
||||||
|
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.shangjia_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view wx:if="{{item.xuqiu_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x style="margin-top:8rpx">
|
<scroll-view wx:if="{{item.shangjia_identity_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex style="margin-top:8rpx">
|
||||||
|
|
||||||
<chenghao-tag wx:for="{{item.xuqiu_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.shangjia_identity_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<scroll-view wx:if="{{item.xuqiu_biaoqian.length > 0}}" class="biaoqian-inline-scroll" scroll-x enable-flex style="margin-top:8rpx">
|
||||||
|
|
||||||
|
<view class="biaoqian-inline-inner">
|
||||||
|
<chenghao-tag wx:for="{{item.xuqiu_biaoqian}}" wx:for-item="tag" wx:key="id" mingcheng="{{tag.mingcheng}}" texiaoJson="{{tag.texiao_json}}" />
|
||||||
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
@@ -344,7 +485,7 @@
|
|||||||
|
|
||||||
<text class="o-amt">商家派单</text>
|
<text class="o-amt">商家派单</text>
|
||||||
|
|
||||||
<view class="qiangdan flexa btn-bg btn-qiang" data-item="{{item}}" bindtap="onQiangdanTap">抢单</view>
|
<view class="qiangdan flexa btn-bg btn-qiang" data-item="{{item}}" bindtap="onQiangdanTap">{{item.isMyZhiding ? '立即接待' : '抢单'}}</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -384,8 +525,58 @@
|
|||||||
|
|
||||||
<global-notification id="global-notification" />
|
<global-notification id="global-notification" />
|
||||||
|
|
||||||
|
<kefu-float bottom="200rpx" />
|
||||||
|
|
||||||
<popup-notice id="popupNotice" />
|
<popup-notice id="popupNotice" />
|
||||||
|
|
||||||
|
<!-- 指定单详情 -->
|
||||||
|
<view class="zhiding-modal-mask" wx:if="{{showZhidingDetail}}" catchtap="closeZhidingDetail">
|
||||||
|
<view class="zhiding-modal" catchtap="noop">
|
||||||
|
<view class="zhiding-modal-head">
|
||||||
|
<text class="zhiding-modal-title">指定订单详情</text>
|
||||||
|
<text class="zhiding-modal-close" catchtap="closeZhidingDetail">×</text>
|
||||||
|
</view>
|
||||||
|
<view class="zhiding-modal-body" wx:if="{{zhidingDetailOrder}}">
|
||||||
|
<view class="zhiding-modal-row"><text class="lbl">单号</text><text>{{zhidingDetailOrder.dingdan_id}}</text></view>
|
||||||
|
<view class="zhiding-modal-row"><text class="lbl">分成</text><text class="reward">¥{{zhidingDetailOrder.dashou_fencheng || 0}}</text></view>
|
||||||
|
<view class="zhiding-modal-row col"><text class="lbl">介绍</text><text>{{zhidingDetailOrder.jieshao || '暂无'}}</text></view>
|
||||||
|
<view class="zhiding-modal-row col" wx:if="{{zhidingDetailOrder.beizhu}}"><text class="lbl">备注</text><text>{{zhidingDetailOrder.beizhu}}</text></view>
|
||||||
|
<view class="zhiding-modal-row" wx:if="{{zhidingDetailOrder.zhiding_hf_text}}"><text class="lbl">您的回复</text><text>{{zhidingDetailOrder.zhiding_hf_text}}</text></view>
|
||||||
|
</view>
|
||||||
|
<view class="my-zhiding-actions zhiding-modal-actions" wx:if="{{zhidingDetailOrder}}">
|
||||||
|
<view class="zhiding-act zhiding-act--ghost" data-item="{{zhidingDetailOrder}}" catchtap="onZhidingReject">不想接</view>
|
||||||
|
<view class="zhiding-act zhiding-act--ghost" data-item="{{zhidingDetailOrder}}" catchtap="onZhidingLater">等会接</view>
|
||||||
|
<view class="zhiding-act zhiding-act--primary" data-item="{{zhidingDetailOrder}}" catchtap="onZhidingAccept">立即接待</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 等会接时间 -->
|
||||||
|
<view class="zhiding-modal-mask zhiding-modal-mask--top" wx:if="{{showLaterModal}}" catchtap="closeLaterModal">
|
||||||
|
<view class="zhiding-modal zhiding-modal--sm" catchtap="noop">
|
||||||
|
<view class="zhiding-modal-head">
|
||||||
|
<text class="zhiding-modal-title">等会接</text>
|
||||||
|
<text class="zhiding-modal-close" catchtap="closeLaterModal">×</text>
|
||||||
|
</view>
|
||||||
|
<view class="zhiding-modal-body">
|
||||||
|
<text class="later-hint">请填写预计接待时间,例如「30分钟后」「今晚8点」</text>
|
||||||
|
<input
|
||||||
|
class="later-input"
|
||||||
|
placeholder="预计接待时间"
|
||||||
|
placeholder-class="later-input-ph"
|
||||||
|
value="{{laterNote}}"
|
||||||
|
bindinput="onLaterNoteInput"
|
||||||
|
maxlength="50"
|
||||||
|
focus="{{showLaterModal}}"
|
||||||
|
adjust-position="{{true}}"
|
||||||
|
confirm-type="done"
|
||||||
|
bindconfirm="confirmZhidingLater"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
<view class="later-confirm" catchtap="confirmZhidingLater">确认</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<tab-bar />
|
<tab-bar />
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
/* pages/qiangdan/qiangdan.wxss - 高级机甲风格重构版(对称优化) */
|
/* pages/qiangdan/qiangdan.wxss - 逍遥梦抢单页 */
|
||||||
@import '../../styles/dashou-xym-theme.wxss';
|
@import '../../styles/dashou-xym-theme.wxss';
|
||||||
|
@import '../../styles/dashou-xym-order-card.wxss';
|
||||||
|
|
||||||
|
page {
|
||||||
|
background-color: #f7dc51;
|
||||||
|
}
|
||||||
|
|
||||||
.qiangdan-page {
|
.qiangdan-page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -8,6 +14,34 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tousu-top-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin: 16rpx 24rpx 8rpx;
|
||||||
|
padding: 18rpx 24rpx;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
background: linear-gradient(90deg, #e85a3a 0%, #f07858 100%);
|
||||||
|
box-shadow: 0 6rpx 18rpx rgba(232, 90, 58, 0.28);
|
||||||
|
z-index: 5;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.tousu-top-bar-txt {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.tousu-top-bar-sub {
|
||||||
|
flex: 1;
|
||||||
|
color: rgba(255,255,255,0.88);
|
||||||
|
font-size: 22rpx;
|
||||||
|
}
|
||||||
|
.tousu-top-bar-arrow {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 36rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* 背景动态纹理,增加层次感 */
|
/* 背景动态纹理,增加层次感 */
|
||||||
.qiangdan-page::before {
|
.qiangdan-page::before {
|
||||||
@@ -88,6 +122,31 @@
|
|||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
border: 2rpx solid rgba(0, 200, 255, 0.4);
|
border: 2rpx solid rgba(0, 200, 255, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leixing-pic-wrap {
|
||||||
|
position: relative;
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leixing-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: -8rpx;
|
||||||
|
right: -12rpx;
|
||||||
|
min-width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #fa3534;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 20rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
.leixing-active .leixing-tupian {
|
.leixing-active .leixing-tupian {
|
||||||
box-shadow: 0 16rpx 40rpx rgba(0, 200, 255, 0.5);
|
box-shadow: 0 16rpx 40rpx rgba(0, 200, 255, 0.5);
|
||||||
@@ -126,6 +185,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
height: 0;
|
height: 0;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-bottom-spacer {
|
.scroll-bottom-spacer {
|
||||||
@@ -486,7 +546,7 @@
|
|||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
padding: 8rpx 20rpx;
|
padding: 8rpx 20rpx;
|
||||||
border-radius: 60rpx;
|
border-radius: 60rpx;
|
||||||
border: 1rpx solid rgba(196, 181, 253, 0.3);
|
border: 1rpx solid rgba(255, 215, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 分佣图标占位符,用户可替换为自己图标 */
|
/* 分佣图标占位符,用户可替换为自己图标 */
|
||||||
@@ -504,10 +564,10 @@
|
|||||||
|
|
||||||
.fenyong-price {
|
.fenyong-price {
|
||||||
font-size: 44rpx;
|
font-size: 44rpx;
|
||||||
color: #c4b5fd;
|
color: #ffd700;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
margin-right: 4rpx;
|
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 {
|
.fenyong-unit {
|
||||||
@@ -764,4 +824,189 @@
|
|||||||
max-width: 50%;
|
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: 86%;
|
||||||
|
max-width: 600rpx;
|
||||||
|
max-height: 72vh;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 24rpx 64rpx rgba(0, 0, 0, 0.35);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.zhiding-modal--sm { max-width: 540rpx; }
|
||||||
|
.zhiding-modal-head {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 22rpx 26rpx;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
background: #fff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.zhiding-modal-title { font-size: 30rpx; font-weight: 700; color: #222; }
|
||||||
|
.zhiding-modal-close { font-size: 44rpx; color: #666; line-height: 1; padding: 0 8rpx; }
|
||||||
|
.zhiding-modal-body {
|
||||||
|
padding: 22rpx 26rpx;
|
||||||
|
background: #fff;
|
||||||
|
max-height: 52vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
// pages/alipay-webview/alipay-webview.js
|
||||||
|
// 支付宝当面付二维码展示页(替代原 web-view 方案,避免 alipay:// scheme 限制)
|
||||||
|
// 通用化:支持通过 pollUrl 参数指定轮询接口,兼容 code===0(订单)和 code===200(Czjilu类)双成功码
|
||||||
|
// 支付成功后通过 EventChannel 通知原页面刷新状态
|
||||||
|
const app = getApp()
|
||||||
|
import request from '../../utils/request.js'
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
qrImage: '',
|
||||||
|
orderId: '',
|
||||||
|
pollUrl: '/dingdan/fucha', // 默认订单轮询接口
|
||||||
|
statusText: '等待支付...',
|
||||||
|
showBack: false,
|
||||||
|
pollCount: 0,
|
||||||
|
maxPollCount: 60,
|
||||||
|
isPaid: false
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(options) {
|
||||||
|
const orderId = options.orderId || ''
|
||||||
|
// base64 图片较大,通过 globalData 传递避免 URL 长度限制
|
||||||
|
const qrImage = app.globalData.alipayQrImage || ''
|
||||||
|
app.globalData.alipayQrImage = ''
|
||||||
|
// 允许调用方指定轮询接口(需 URL 编码),未指定则用默认订单接口
|
||||||
|
const pollUrl = options.pollUrl ? decodeURIComponent(options.pollUrl) : '/dingdan/fucha'
|
||||||
|
this.setData({ qrImage, orderId, pollUrl })
|
||||||
|
// 获取 opener 事件通道,用于支付成功后通知原页面刷新状态
|
||||||
|
this.openerEventChannel = this.getOpenerEventChannel ? this.getOpenerEventChannel() : null
|
||||||
|
this._pollTimer = null
|
||||||
|
this._hidden = false
|
||||||
|
if (orderId) {
|
||||||
|
this.startPolling()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startPolling() {
|
||||||
|
if (this.data.isPaid) return
|
||||||
|
if (this.data.pollCount >= this.data.maxPollCount) {
|
||||||
|
this.setData({ statusText: '支付确认超时,如已支付请点击返回', showBack: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.setData({ pollCount: this.data.pollCount + 1 })
|
||||||
|
this.pollOrderStatus()
|
||||||
|
},
|
||||||
|
|
||||||
|
pollOrderStatus() {
|
||||||
|
if (this.data.isPaid) return
|
||||||
|
request({
|
||||||
|
url: this.data.pollUrl,
|
||||||
|
method: 'POST',
|
||||||
|
data: { dingdanid: this.data.orderId }
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (this.data.isPaid) return
|
||||||
|
// 兼容两种成功码:订单接口 code===0,Czjilu类接口 code===200
|
||||||
|
if (res.statusCode === 200 && res.data && (res.data.code === 0 || res.data.code === 200)) {
|
||||||
|
this.setData({ isPaid: true, statusText: '支付成功!', showBack: true })
|
||||||
|
wx.showToast({ title: '支付成功!', icon: 'success', duration: 1500 })
|
||||||
|
// 通知原页面刷新状态(原页面通过 wx.navigateTo events 注册 onAlipaySuccess)
|
||||||
|
if (this.openerEventChannel && this.openerEventChannel.emit) {
|
||||||
|
try {
|
||||||
|
this.openerEventChannel.emit('onAlipaySuccess', { orderId: this.data.orderId, data: res.data })
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setData({ statusText: '等待支付...' })
|
||||||
|
this._pollTimer = setTimeout(() => this.startPolling(), 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!this.data.isPaid) {
|
||||||
|
this._pollTimer = setTimeout(() => this.startPolling(), 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
wx.navigateBack()
|
||||||
|
},
|
||||||
|
|
||||||
|
onHide() {
|
||||||
|
// 切后台时暂停轮询并清理定时器,但不标记为已支付,以便 onShow 恢复
|
||||||
|
this._hidden = true
|
||||||
|
if (this._pollTimer) {
|
||||||
|
clearTimeout(this._pollTimer)
|
||||||
|
this._pollTimer = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 从后台恢复时,如果未支付且未超时,恢复轮询
|
||||||
|
if (this._hidden && !this.data.isPaid && this.data.orderId &&
|
||||||
|
this.data.pollCount < this.data.maxPollCount) {
|
||||||
|
this._hidden = false
|
||||||
|
this.startPolling()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"navigationBarTitleText": "支付宝支付",
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<view class="qr-container">
|
||||||
|
<view class="qr-title">支付宝扫码支付</view>
|
||||||
|
<image wx:if="{{qrImage}}" class="qr-image" src="{{qrImage}}" mode="aspectFit" />
|
||||||
|
<view class="qr-tip">请使用 <text class="qr-emph">支付宝</text> APP 扫描上方二维码完成支付</view>
|
||||||
|
<view class="qr-status">{{statusText}}</view>
|
||||||
|
<view class="qr-actions" wx:if="{{showBack}}">
|
||||||
|
<view class="qr-btn" bindtap="onBack">返回</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
.qr-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 60rpx 40rpx;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.qr-title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
.qr-image {
|
||||||
|
width: 500rpx;
|
||||||
|
height: 500rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
.qr-tip {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.qr-emph {
|
||||||
|
color: #1677ff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.qr-status {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #1677ff;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
.qr-actions {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
}
|
||||||
|
.qr-btn {
|
||||||
|
background: #1677ff;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 18rpx 80rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
@@ -303,14 +303,28 @@ Page({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (applyFee > 0) {
|
if (applyFee > 0) {
|
||||||
await this.startPayProcess();
|
this.choosePayMethod();
|
||||||
} else {
|
} else {
|
||||||
await this.doFreeApply();
|
await this.doFreeApply();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 选择支付方式
|
||||||
|
choosePayMethod() {
|
||||||
|
wx.showActionSheet({
|
||||||
|
itemList: ['微信支付', '支付宝(扫码)'],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
this.startPayProcess('wechat');
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
this.startPayProcess('alipay');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 支付流程
|
// 支付流程
|
||||||
async startPayProcess() {
|
async startPayProcess(payMethod = 'wechat') {
|
||||||
this.setData({ payLoading: true });
|
this.setData({ payLoading: true });
|
||||||
try {
|
try {
|
||||||
const res = await request({
|
const res = await request({
|
||||||
@@ -323,11 +337,20 @@ Page({
|
|||||||
reapply: this.data.isReapply,
|
reapply: this.data.isReapply,
|
||||||
jilu_id: this.data.applyJiluId,
|
jilu_id: this.data.applyJiluId,
|
||||||
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
||||||
|
pay_method: payMethod === 'alipay' ? 'alipay' : 'wechat'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (res.data.code !== 200) throw new Error(res.data.message || '下单失败');
|
if (res.data.code !== 200) throw new Error(res.data.message || '下单失败');
|
||||||
const payParams = res.data.payParams;
|
const payParams = res.data.payParams;
|
||||||
const dingdanid = res.data.dingdanid;
|
const dingdanid = res.data.dingdanid;
|
||||||
|
|
||||||
|
// 支付宝分支:跳转二维码页
|
||||||
|
if (payMethod === 'alipay' || (payParams && payParams.pay_method === 'alipay')) {
|
||||||
|
this.setData({ payLoading: false });
|
||||||
|
this.triggerAlipayPayment(payParams, dingdanid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wx.requestPayment({
|
wx.requestPayment({
|
||||||
timeStamp: payParams.timeStamp,
|
timeStamp: payParams.timeStamp,
|
||||||
nonceStr: payParams.nonceStr,
|
nonceStr: payParams.nonceStr,
|
||||||
@@ -349,6 +372,32 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========== 支付宝扫码支付封装 ==========
|
||||||
|
triggerAlipayPayment(payParams, orderId) {
|
||||||
|
const qrImage = payParams && payParams.qr_image ? payParams.qr_image : '';
|
||||||
|
if (!qrImage) {
|
||||||
|
wx.showToast({ title: '支付宝二维码生成失败', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const app = getApp();
|
||||||
|
app.globalData.alipayQrImage = qrImage;
|
||||||
|
const pollUrl = encodeURIComponent('/yonghu/khzffc');
|
||||||
|
const self = this;
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/alipay-webview/alipay-webview?orderId=${orderId}&pollUrl=${pollUrl}`,
|
||||||
|
events: {
|
||||||
|
onAlipaySuccess: () => {
|
||||||
|
// 复用微信流成功逻辑:关闭弹窗并刷新考核记录列表
|
||||||
|
wx.showToast({ title: '申请成功', icon: 'success' });
|
||||||
|
self.closeApplyModal();
|
||||||
|
self.fetchAllTags();
|
||||||
|
self.setData({ recordList: [], recordPage: 1 });
|
||||||
|
self.fetchMyRecords(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 轮询支付结果
|
// 轮询支付结果
|
||||||
async pollPayStatus(dingdanid) {
|
async pollPayStatus(dingdanid) {
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ page {
|
|||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
.status-0 { background: #F3E8FF; color: #9333ea; }
|
.status-0 { background: #FFF3E0; color: #EF6C00; }
|
||||||
.status-1 { background: #E8F5E9; color: #2E7D32; }
|
.status-1 { background: #E8F5E9; color: #2E7D32; }
|
||||||
.status-2 { background: #FFEBEE; color: #C62828; }
|
.status-2 { background: #FFEBEE; color: #C62828; }
|
||||||
.status-3 { background: #E3F2FD; color: #1565C0; }
|
.status-3 { background: #E3F2FD; color: #1565C0; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// pages/category/category.js
|
// pages/category/category.js
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
import { createPage } from '../../utils/base-page.js';
|
import { createPage } from '../../utils/base-page.js';
|
||||||
|
import { buildClubHeaders } from '../../utils/club-context.js';
|
||||||
|
import { isFighterOnly, resolveFighterOnlyLaunchUrl } from '../../utils/fighter-only.js';
|
||||||
|
|
||||||
Page(createPage({
|
Page(createPage({
|
||||||
data: {
|
data: {
|
||||||
@@ -24,6 +26,10 @@ Page(createPage({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
|
if (isFighterOnly()) {
|
||||||
|
wx.reLaunch({ url: resolveFighterOnlyLaunchUrl() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setData({
|
this.setData({
|
||||||
ossImageUrl: app.globalData.ossImageUrl
|
ossImageUrl: app.globalData.ossImageUrl
|
||||||
})
|
})
|
||||||
@@ -31,6 +37,10 @@ Page(createPage({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
|
if (isFighterOnly()) {
|
||||||
|
wx.reLaunch({ url: resolveFighterOnlyLaunchUrl() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.registerNotificationComponent();
|
this.registerNotificationComponent();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -114,9 +124,7 @@ Page(createPage({
|
|||||||
wx.request({
|
wx.request({
|
||||||
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
|
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
header: {
|
header: buildClubHeaders({ 'content-type': 'application/json' }),
|
||||||
'content-type': 'application/json'
|
|
||||||
},
|
|
||||||
success(res) {
|
success(res) {
|
||||||
if (res.statusCode === 200 && res.data) {
|
if (res.statusCode === 200 && res.data) {
|
||||||
const data = res.data
|
const data = res.data
|
||||||
|
|||||||
@@ -60,13 +60,13 @@
|
|||||||
|
|
||||||
.search-btn {
|
.search-btn {
|
||||||
margin-left: 20rpx;
|
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);
|
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-btn:active {
|
.search-btn:active {
|
||||||
transform: scale(0.95);
|
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 {
|
.search-btn-text {
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 300rpx;
|
width: 300rpx;
|
||||||
height: 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;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +167,8 @@
|
|||||||
.leixing-active .leixing-image-box {
|
.leixing-active .leixing-image-box {
|
||||||
transform: scale(1.12);
|
transform: scale(1.12);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 18rpx 40rpx rgba(168, 85, 247, 0.3),
|
0 18rpx 40rpx rgba(255, 204, 0, 0.3),
|
||||||
0 8rpx 16rpx rgba(147, 51, 234, 0.2);
|
0 8rpx 16rpx rgba(255, 170, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.leixing-image {
|
.leixing-image {
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
right: -3rpx;
|
right: -3rpx;
|
||||||
bottom: -3rpx;
|
bottom: -3rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: linear-gradient(135deg, #c4b5fd, #9333ea, #7c3aed);
|
background: linear-gradient(135deg, #ffcc00, #ffaa00, #ff8800);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.4s;
|
transition: opacity 0.4s;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
@@ -223,10 +223,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.leixing-active .leixing-text {
|
.leixing-active .leixing-text {
|
||||||
color: #8b5cf6;
|
color: #ff9900;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transform: translateY(-2rpx);
|
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 {
|
.leixing-active-bar {
|
||||||
@@ -234,12 +234,12 @@
|
|||||||
bottom: -4rpx;
|
bottom: -4rpx;
|
||||||
width: 44rpx;
|
width: 44rpx;
|
||||||
height: 4rpx;
|
height: 4rpx;
|
||||||
background: linear-gradient(90deg, #c4b5fd, #9333ea);
|
background: linear-gradient(90deg, #ffcc00, #ffaa00);
|
||||||
border-radius: 2rpx;
|
border-radius: 2rpx;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
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 {
|
.leixing-active-bar-show {
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
|
|
||||||
.border-effect-active {
|
.border-effect-active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
border-color: rgba(168, 85, 247, 0.5);
|
border-color: rgba(255, 204, 0, 0.5);
|
||||||
animation: borderGlow 2s infinite;
|
animation: borderGlow 2s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zhuanqu-item:active {
|
.zhuanqu-item:active {
|
||||||
background: rgba(168, 85, 247, 0.05);
|
background: rgba(255, 204, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.zhuanqu-item-content {
|
.zhuanqu-item-content {
|
||||||
@@ -320,9 +320,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zhuanqu-active .zhuanqu-name {
|
.zhuanqu-active .zhuanqu-name {
|
||||||
color: #8b5cf6;
|
color: #ff9900;
|
||||||
font-weight: 600;
|
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 {
|
.zhuanqu-count {
|
||||||
@@ -332,7 +332,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zhuanqu-active .zhuanqu-count {
|
.zhuanqu-active .zhuanqu-count {
|
||||||
color: #9333ea;
|
color: #ffaa00;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
width: 6rpx;
|
width: 6rpx;
|
||||||
height: 44rpx;
|
height: 44rpx;
|
||||||
background: linear-gradient(180deg, #a855f7, #9333ea);
|
background: linear-gradient(180deg, #ffcc00, #ffaa00);
|
||||||
border-radius: 3rpx 0 0 3rpx;
|
border-radius: 3rpx 0 0 3rpx;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
@@ -353,7 +353,7 @@
|
|||||||
.zhuanqu-indicator-glow {
|
.zhuanqu-indicator-glow {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
animation: indicatorGlow 2s infinite;
|
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 {
|
.indicator-sparkle {
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 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;
|
opacity: 0;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -389,7 +389,7 @@
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(168, 85, 247, 0.1);
|
background: rgba(255, 204, 0, 0.1);
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -463,7 +463,7 @@
|
|||||||
right: -4rpx;
|
right: -4rpx;
|
||||||
bottom: -4rpx;
|
bottom: -4rpx;
|
||||||
border-radius: 18rpx;
|
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;
|
opacity: 0;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -479,7 +479,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 20rpx;
|
width: 20rpx;
|
||||||
height: 20rpx;
|
height: 20rpx;
|
||||||
background: linear-gradient(135deg, #a855f7, transparent 70%);
|
background: linear-gradient(135deg, #ffcc00, transparent 70%);
|
||||||
border-radius: 0 14rpx 0 0;
|
border-radius: 0 14rpx 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +514,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 2rpx;
|
height: 2rpx;
|
||||||
background: linear-gradient(90deg, #c4b5fd, #9333ea);
|
background: linear-gradient(90deg, #ffcc00, #ffaa00);
|
||||||
transition: width 0.3s;
|
transition: width 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,20 +537,20 @@
|
|||||||
|
|
||||||
.price-icon {
|
.price-icon {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #9333ea;
|
color: #ff6600;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-integer {
|
.price-integer {
|
||||||
font-size: 36rpx; /* 适当调整大小 */
|
font-size: 36rpx; /* 适当调整大小 */
|
||||||
color: #9333ea;
|
color: #ff6600;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-left: 2rpx;
|
margin-left: 2rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-decimal {
|
.price-decimal {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #9333ea;
|
color: #ff6600;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,11 +573,11 @@
|
|||||||
.detail-btn {
|
.detail-btn {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 12rpx 28rpx;
|
padding: 12rpx 28rpx;
|
||||||
background: linear-gradient(135deg, #c4b5fd, #9333ea);
|
background: linear-gradient(135deg, #ffcc00, #ffaa00);
|
||||||
border-radius: 40rpx;
|
border-radius: 40rpx;
|
||||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
overflow: hidden;
|
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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -586,7 +586,7 @@
|
|||||||
|
|
||||||
.detail-btn:active {
|
.detail-btn:active {
|
||||||
transform: scale(0.95);
|
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 {
|
.detail-btn-text {
|
||||||
@@ -659,7 +659,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 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;
|
opacity: 0;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -676,7 +676,7 @@
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(168, 85, 247, 0.1);
|
background: rgba(255, 204, 0, 0.1);
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -707,19 +707,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shangpin-empty-btn {
|
.shangpin-empty-btn {
|
||||||
background: linear-gradient(135deg, #c4b5fd, #9333ea);
|
background: linear-gradient(135deg, #ffcc00, #ffaa00);
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 16rpx 44rpx;
|
padding: 16rpx 44rpx;
|
||||||
border-radius: 40rpx;
|
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;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shangpin-empty-btn:active {
|
.shangpin-empty-btn:active {
|
||||||
transform: scale(0.95);
|
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 {
|
.load-more-line {
|
||||||
@@ -859,7 +859,7 @@
|
|||||||
right: -4rpx;
|
right: -4rpx;
|
||||||
bottom: -4rpx;
|
bottom: -4rpx;
|
||||||
border-radius: 20rpx;
|
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;
|
opacity: 0;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -896,7 +896,7 @@
|
|||||||
|
|
||||||
.info-tag {
|
.info-tag {
|
||||||
padding: 6rpx 12rpx;
|
padding: 6rpx 12rpx;
|
||||||
background: rgba(168, 85, 247, 0.1);
|
background: rgba(255, 204, 0, 0.1);
|
||||||
border-radius: 6rpx;
|
border-radius: 6rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,7 +921,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 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;
|
opacity: 0;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -977,7 +977,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 4rpx solid transparent;
|
border: 4rpx solid transparent;
|
||||||
border-top-color: #a855f7;
|
border-top-color: #ffcc00;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
}
|
}
|
||||||
@@ -1028,7 +1028,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
width: 12rpx;
|
width: 12rpx;
|
||||||
height: 12rpx;
|
height: 12rpx;
|
||||||
background: #a855f7;
|
background: #ffcc00;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
@@ -1045,7 +1045,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
width: 200rpx;
|
width: 200rpx;
|
||||||
height: 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%);
|
transform: translate(-50%, -50%);
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
@@ -1076,19 +1076,19 @@
|
|||||||
|
|
||||||
@keyframes borderGlow {
|
@keyframes borderGlow {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
border-color: rgba(168, 85, 247, 0.3);
|
border-color: rgba(255, 204, 0, 0.3);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
border-color: rgba(168, 85, 247, 0.8);
|
border-color: rgba(255, 204, 0, 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes indicatorGlow {
|
@keyframes indicatorGlow {
|
||||||
0%, 100% {
|
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% {
|
50% {
|
||||||
box-shadow: 0 0 30rpx rgba(168, 85, 247, 0.8);
|
box-shadow: 0 0 30rpx rgba(255, 204, 0, 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+165
-69
@@ -1,7 +1,14 @@
|
|||||||
const app = getApp();
|
const app = getApp();
|
||||||
import { formatDate } from '../../static/lib/utils';
|
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 { getLocalImUserId } from '../../utils/im-user.js';
|
||||||
|
import { recordConversationOpen } from '../../utils/group-chat.js';
|
||||||
|
import {
|
||||||
|
fetchHistoryMessages,
|
||||||
|
getOldestHistoryTimestamp,
|
||||||
|
mergeHistoryMessages,
|
||||||
|
waitChatImReady,
|
||||||
|
} from '../../utils/chat-history.js';
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -25,29 +32,58 @@ Page({
|
|||||||
pendingImage: '',
|
pendingImage: '',
|
||||||
pendingImageFile: null,
|
pendingImageFile: null,
|
||||||
keyboardHeight: 0,
|
keyboardHeight: 0,
|
||||||
bottomSafeHeight: 10
|
bottomSafeHeight: 140,
|
||||||
|
defaultAvatarUrl: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
|
const defAvatar = getDefaultAvatarUrl(app);
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
try {
|
try {
|
||||||
const p = JSON.parse(decodeURIComponent(options.data));
|
const p = JSON.parse(decodeURIComponent(options.data));
|
||||||
this.setData({
|
this.setData({
|
||||||
toUserId: p.toUserId || '',
|
toUserId: p.toUserId || '',
|
||||||
toName: p.toName || '聊天',
|
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 });
|
wx.setNavigationBarTitle({ title: this.data.toName });
|
||||||
this.initCurrentUser();
|
this.initCurrentUser();
|
||||||
|
this._unsubConfigAvatar = subscribeConfigAvatarRefresh(this, () => {
|
||||||
|
const def = getDefaultAvatarUrl(app);
|
||||||
|
this.setData({
|
||||||
|
defaultAvatarUrl: def,
|
||||||
|
toAvatar: resolveAvatarUrl(this.data.toAvatar, app) || def,
|
||||||
|
});
|
||||||
|
this.refreshCurrentUserAvatar();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
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();
|
this.ensureChatReady();
|
||||||
},
|
},
|
||||||
|
|
||||||
onHide() {
|
onHide() {
|
||||||
|
if (this.data.toUserId) {
|
||||||
|
recordConversationOpen({ userId: this.data.toUserId });
|
||||||
|
}
|
||||||
this.clearPageListeners();
|
this.clearPageListeners();
|
||||||
this.markPrivateMessageAsRead();
|
this.markPrivateMessageAsRead();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -55,27 +91,34 @@ Page({
|
|||||||
}, 250);
|
}, 250);
|
||||||
},
|
},
|
||||||
|
|
||||||
ensureChatReady() {
|
onUnload() {
|
||||||
|
if (this._unsubConfigAvatar) {
|
||||||
|
this._unsubConfigAvatar();
|
||||||
|
this._unsubConfigAvatar = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async ensureChatReady() {
|
||||||
const targetUserId = getLocalImUserId(app);
|
const targetUserId = getLocalImUserId(app);
|
||||||
if (!targetUserId) return;
|
if (!targetUserId) return;
|
||||||
|
|
||||||
const ready = () => {
|
const ready = async () => {
|
||||||
this.setupAllListeners();
|
this.setupAllListeners();
|
||||||
this.loadHistory(true);
|
await this.loadHistory(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (app.ensureConnection) {
|
try {
|
||||||
const ret = app.ensureConnection();
|
const ok = await waitChatImReady(app, 12000);
|
||||||
if (ret && typeof ret.then === 'function') {
|
if (ok) {
|
||||||
ret.then(ready).catch(ready);
|
await ready();
|
||||||
} else {
|
return;
|
||||||
setTimeout(ready, 300);
|
|
||||||
}
|
}
|
||||||
return;
|
} catch (e) {
|
||||||
|
console.warn('[私聊] IM 连接失败', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isConnected() && wx.goEasy.im?.userId === targetUserId) {
|
if (this.isConnected() && wx.goEasy.im?.userId === targetUserId) {
|
||||||
ready();
|
await ready();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.connectGoEasy(targetUserId);
|
this.connectGoEasy(targetUserId);
|
||||||
@@ -133,14 +176,26 @@ Page({
|
|||||||
const imId = getLocalImUserId(app);
|
const imId = getLocalImUserId(app);
|
||||||
const uid = wx.getStorageSync('uid');
|
const uid = wx.getStorageSync('uid');
|
||||||
const nick = app.globalData.nicheng || app.globalData.dashouNicheng || wx.getStorageSync('nicheng') || '';
|
const nick = app.globalData.nicheng || app.globalData.dashouNicheng || wx.getStorageSync('nicheng') || '';
|
||||||
|
const defAvatar = getDefaultAvatarUrl(app);
|
||||||
|
const avatar = resolveAvatarFromStorage(app) || defAvatar;
|
||||||
this.setData({
|
this.setData({
|
||||||
currentUser: {
|
currentUser: {
|
||||||
id: imId || ('Ds' + uid),
|
id: imId || ('Ds' + uid),
|
||||||
name: nick || `用户${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) {
|
fixAvatar(url) {
|
||||||
return resolveAvatarUrl(url, app);
|
return resolveAvatarUrl(url, app);
|
||||||
},
|
},
|
||||||
@@ -156,6 +211,19 @@ Page({
|
|||||||
normalizeMessage(msg) {
|
normalizeMessage(msg) {
|
||||||
if (!msg) return msg;
|
if (!msg) return msg;
|
||||||
if (!msg.payload) msg.payload = {};
|
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') {
|
if (msg.type === 'image') {
|
||||||
const p = msg.payload;
|
const p = msg.payload;
|
||||||
if (!p.url) p.url = p.thumbnail || p.thumb || p.imageUrl || '';
|
if (!p.url) p.url = p.thumbnail || p.thumb || p.imageUrl || '';
|
||||||
@@ -188,63 +256,91 @@ Page({
|
|||||||
|
|
||||||
onPullDownRefresh() {
|
onPullDownRefresh() {
|
||||||
if (this.data.loadingHistory) return;
|
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.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) {
|
mapHistoryMessage(m, idx, list) {
|
||||||
if (!refresh && !this.data.hasMore) return Promise.resolve();
|
m = this.normalizeMessage(m);
|
||||||
return new Promise((resolve) => {
|
m.formattedTime = formatDate(m.timestamp);
|
||||||
this.setData({ loadingHistory: true });
|
if (idx === 0) m.showTime = true;
|
||||||
const { toUserId, lastTimestamp } = this.data;
|
else m.showTime = (m.timestamp - list[idx - 1].timestamp) / 60000 > 5;
|
||||||
const ts = refresh ? null : lastTimestamp;
|
if (m.senderId === this.data.currentUser?.id) {
|
||||||
wx.goEasy.im.history({
|
m.senderData = {
|
||||||
type: wx.GoEasy.IM_SCENE.PRIVATE, id: toUserId, lastTimestamp: ts, limit: 20,
|
name: this.data.currentUser.name,
|
||||||
onSuccess: (res) => {
|
avatar: resolveAvatarUrl(this.data.currentUser.avatar, app),
|
||||||
let list = res.content || [];
|
};
|
||||||
list.sort((a, b) => a.timestamp - b.timestamp);
|
} else {
|
||||||
list.forEach((m, idx) => {
|
m.senderData = {
|
||||||
m = this.normalizeMessage(m);
|
name: this.data.toName,
|
||||||
list[idx] = m;
|
avatar: resolveAvatarUrl(this.data.toAvatar, app),
|
||||||
m.formattedTime = formatDate(m.timestamp);
|
};
|
||||||
if (idx === 0) m.showTime = true;
|
}
|
||||||
else m.showTime = (m.timestamp - list[idx-1].timestamp) / 60000 > 5;
|
return m;
|
||||||
if (m.senderId === this.data.currentUser.id) {
|
},
|
||||||
m.senderData = {
|
|
||||||
name: this.data.currentUser.name,
|
async loadHistory(refresh) {
|
||||||
avatar: resolveAvatarUrl(this.data.currentUser.avatar, app),
|
if (!refresh && !this.data.hasMore) return;
|
||||||
};
|
if (this.data.loadingHistory) return;
|
||||||
} else {
|
if (!this.data.toUserId) return;
|
||||||
m.senderData = {
|
|
||||||
name: this.data.toName,
|
this.setData({ loadingHistory: true });
|
||||||
avatar: resolveAvatarUrl(this.data.toAvatar, app),
|
try {
|
||||||
};
|
const ready = await waitChatImReady(app, 12000);
|
||||||
}
|
if (!ready) {
|
||||||
});
|
wx.showToast({ title: '消息服务未连接,请稍后重试', icon: 'none' });
|
||||||
let final = refresh ? list : [...list, ...this.data.messages];
|
return;
|
||||||
if (!refresh) {
|
}
|
||||||
for (let i=0; i<final.length; i++) {
|
|
||||||
if (i===0) final[i].showTime = true;
|
const ts = refresh
|
||||||
else final[i].showTime = (final[i].timestamp - final[i-1].timestamp) / 60000 > 5;
|
? null
|
||||||
}
|
: getOldestHistoryTimestamp(this.data.messages, this.data.lastTimestamp);
|
||||||
}
|
if (!refresh && ts == null) {
|
||||||
const ids = new Set();
|
this.setData({ hasMore: false });
|
||||||
const unique = [];
|
wx.showToast({ title: '没有更早的消息了', icon: 'none' });
|
||||||
for (const m of final) { if (!ids.has(m.messageId)) { ids.add(m.messageId); unique.push(m); } }
|
return;
|
||||||
const update = {
|
}
|
||||||
messages: unique,
|
|
||||||
hasMore: list.length >= 20,
|
const raw = await fetchHistoryMessages({
|
||||||
lastTimestamp: unique.length ? unique[0].timestamp : lastTimestamp,
|
scene: wx.GoEasy.IM_SCENE.PRIVATE,
|
||||||
loadingHistory: false
|
id: this.data.toUserId,
|
||||||
};
|
lastTimestamp: ts,
|
||||||
if (refresh) update.scrollToView = 'msg-bottom';
|
limit: 20,
|
||||||
this.setData(update);
|
|
||||||
if (refresh) this.markPrivateMessageAsRead();
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
onFailed: () => { this.setData({ loadingHistory: false }); resolve(); }
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
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() {
|
listenNewMsg() {
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
refresher-enabled="{{true}}"
|
refresher-enabled="{{true}}"
|
||||||
refresher-triggered="{{isRefreshing}}"
|
refresher-triggered="{{isRefreshing}}"
|
||||||
bindrefresherrefresh="onPullDownRefresh"
|
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);">
|
||||||
<view class="chat-loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
<view class="chat-loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||||
<block wx:for="{{messages}}" wx:key="messageId">
|
<block wx:for="{{messages}}" wx:key="messageId">
|
||||||
<view class="chat-msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
<view class="chat-msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||||
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||||
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
||||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{item.senderData.avatar || toAvatar}}" mode="aspectFill" binderror="onPeerAvatarError" />
|
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{toAvatar || defaultAvatarUrl}}" mode="aspectFill" binderror="onPeerAvatarError" />
|
||||||
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
||||||
data-messageid="{{item.messageId}}"
|
data-messageid="{{item.messageId}}"
|
||||||
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
<text class="chat-order-info">ID: {{item.payload.orderId}}</text>
|
<text class="chat-order-info">ID: {{item.payload.orderId}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{item.senderData.avatar || currentUser.avatar}}" mode="aspectFill" binderror="onSelfAvatarError" data-index="{{index}}" />
|
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{currentUser.avatar || defaultAvatarUrl}}" mode="aspectFill" binderror="onSelfAvatarError" data-index="{{index}}" />
|
||||||
</view>
|
</view>
|
||||||
<view wx:if="{{item.senderId === currentUser.id && item.status === 'success'}}" class="chat-read-tag">
|
<view wx:if="{{item.senderId === currentUser.id && item.status === 'success'}}" class="chat-read-tag">
|
||||||
{{item.read ? '已读' : '未读'}}
|
{{item.read ? '已读' : '未读'}}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<view id="msg-bottom" style="height:20rpx;"></view>
|
<view id="msg-bottom" style="height:56rpx;"></view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<view class="chat-input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
<view class="chat-input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||||
|
|||||||
+247
-79
@@ -1,7 +1,14 @@
|
|||||||
const app = getApp();
|
const app = getApp();
|
||||||
import { formatDate } from '../../static/lib/utils';
|
import { formatDate } from '../../static/lib/utils';
|
||||||
import { getLocalImUserId } from '../../utils/im-user.js';
|
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({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -29,11 +36,14 @@ Page({
|
|||||||
pendingImage: '',
|
pendingImage: '',
|
||||||
pendingImageFile: null,
|
pendingImageFile: null,
|
||||||
keyboardHeight: 0,
|
keyboardHeight: 0,
|
||||||
bottomSafeHeight: 10
|
bottomSafeHeight: 140,
|
||||||
|
defaultAvatarUrl: '',
|
||||||
|
welcomeText: '你好,请问有什么可以帮到您的?',
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
let teamId = '', teamName = '客服', teamAvatar = '';
|
let teamId = '', teamName = '客服', teamAvatar = '';
|
||||||
|
const defAvatar = getDefaultAvatarUrl(app);
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
try {
|
try {
|
||||||
const p = JSON.parse(decodeURIComponent(options.data));
|
const p = JSON.parse(decodeURIComponent(options.data));
|
||||||
@@ -43,38 +53,102 @@ Page({
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!teamAvatar) {
|
let teamAvatarResolved = teamAvatar ? ensureAvatarUrl(teamAvatar, app) : defAvatar;
|
||||||
teamAvatar = app.globalData.ossImageUrl + app.globalData.morentouxiang;
|
if (!teamAvatarResolved || !teamAvatarResolved.startsWith('http')) {
|
||||||
|
teamAvatarResolved = defAvatar;
|
||||||
}
|
}
|
||||||
this.setData({ teamId, teamName, teamAvatar });
|
this.setData({ teamId, teamName, teamAvatar: teamAvatarResolved, defaultAvatarUrl: defAvatar });
|
||||||
wx.setNavigationBarTitle({ title: teamName });
|
wx.setNavigationBarTitle({ title: teamName });
|
||||||
this.initCurrentUser();
|
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() {
|
onShow() {
|
||||||
|
const defAvatar = getDefaultAvatarUrl(app);
|
||||||
|
const patch = {
|
||||||
|
defaultAvatarUrl: defAvatar,
|
||||||
|
teamAvatar: defAvatar,
|
||||||
|
};
|
||||||
|
this.setData(patch);
|
||||||
|
this.refreshCurrentUserAvatar();
|
||||||
this.autoConnect();
|
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() {
|
onHide() {
|
||||||
this.clearAllListeners();
|
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);
|
const targetUserId = getLocalImUserId(app);
|
||||||
if (!targetUserId) return;
|
if (!targetUserId) return;
|
||||||
|
|
||||||
const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
|
const ready = async () => {
|
||||||
if (status === 'connected' || status === 'reconnected') {
|
this.setupAllListeners();
|
||||||
const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
|
await this.loadHistory(true);
|
||||||
if (currentUserId === targetUserId) {
|
};
|
||||||
this.setupAllListeners();
|
|
||||||
this.loadHistory(true);
|
try {
|
||||||
|
const ok = await waitChatImReady(app, 12000);
|
||||||
|
if (ok) {
|
||||||
|
await ready();
|
||||||
return;
|
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) {
|
connectGoEasy(userId) {
|
||||||
@@ -84,7 +158,7 @@ Page({
|
|||||||
id: userId,
|
id: userId,
|
||||||
data: {
|
data: {
|
||||||
name: currentUser.name,
|
name: currentUser.name,
|
||||||
avatar: resolveAvatarUrl(currentUser.avatar, app)
|
avatar: resolveAvatarUrl(currentUser.avatar, app) || getDefaultAvatarUrl(app)
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
this.setupAllListeners();
|
this.setupAllListeners();
|
||||||
@@ -119,11 +193,13 @@ Page({
|
|||||||
initCurrentUser() {
|
initCurrentUser() {
|
||||||
const imId = getLocalImUserId(app);
|
const imId = getLocalImUserId(app);
|
||||||
const uid = wx.getStorageSync('uid');
|
const uid = wx.getStorageSync('uid');
|
||||||
|
const defAvatar = getDefaultAvatarUrl(app);
|
||||||
|
const avatar = resolveAvatarFromStorage(app) || defAvatar;
|
||||||
this.setData({
|
this.setData({
|
||||||
currentUser: {
|
currentUser: {
|
||||||
id: imId || ('Boss' + uid),
|
id: imId || ('Boss' + uid),
|
||||||
name: app.globalData.currentUser?.name || `用户${uid}`,
|
name: app.globalData.currentUser?.name || wx.getStorageSync('nicheng') || `用户${uid}`,
|
||||||
avatar: resolveAvatarUrl(wx.getStorageSync('touxiang'), app),
|
avatar,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -169,66 +245,89 @@ Page({
|
|||||||
this.setData({ messages: msgs });
|
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) {
|
async loadHistory(refresh) {
|
||||||
if (!refresh && !this.data.hasMore) return Promise.resolve();
|
if (!refresh && !this.data.hasMore) return;
|
||||||
return new Promise((resolve) => {
|
if (this.data.loadingHistory) return;
|
||||||
this.setData({ loadingHistory: true });
|
if (!this.data.teamId) return;
|
||||||
const { teamId, lastTimestamp } = this.data;
|
|
||||||
const ts = refresh ? null : lastTimestamp;
|
this.setData({ loadingHistory: true });
|
||||||
wx.goEasy.im.history({
|
try {
|
||||||
type: wx.GoEasy.IM_SCENE.CS,
|
const ready = await waitChatImReady(app, 12000);
|
||||||
id: teamId,
|
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,
|
lastTimestamp: ts,
|
||||||
limit: 20,
|
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<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 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() {
|
createWelcomeMessage() {
|
||||||
@@ -238,8 +337,11 @@ Page({
|
|||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
senderId: 'system',
|
senderId: 'system',
|
||||||
receiverId: this.data.currentUser?.id,
|
receiverId: this.data.currentUser?.id,
|
||||||
senderData: { name: '系统消息', avatar: '' },
|
senderData: {
|
||||||
payload: { text: '你好,请问有什么可以帮到您的?' },
|
name: this.data.teamName || '客服',
|
||||||
|
avatar: resolveAvatarUrl(this.data.teamAvatar, app) || this.data.defaultAvatarUrl,
|
||||||
|
},
|
||||||
|
payload: { text: this.data.welcomeText || '你好,请问有什么可以帮到您的?' },
|
||||||
status: 'success',
|
status: 'success',
|
||||||
read: false,
|
read: false,
|
||||||
formattedTime: formatDate(Date.now()),
|
formattedTime: formatDate(Date.now()),
|
||||||
@@ -255,7 +357,10 @@ Page({
|
|||||||
if (msg.senderId === this.data.currentUser.id) return;
|
if (msg.senderId === this.data.currentUser.id) return;
|
||||||
msg = this.normalizeMessage(msg);
|
msg = this.normalizeMessage(msg);
|
||||||
msg.formattedTime = formatDate(msg.timestamp);
|
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 msgs = this.data.messages;
|
||||||
const last = msgs.length ? msgs[msgs.length-1] : null;
|
const last = msgs.length ? msgs[msgs.length-1] : null;
|
||||||
msg.showTime = last ? (msg.timestamp - last.timestamp) / 60000 > 5 : true;
|
msg.showTime = last ? (msg.timestamp - last.timestamp) / 60000 > 5 : true;
|
||||||
@@ -370,11 +475,53 @@ Page({
|
|||||||
});
|
});
|
||||||
wx.goEasy.im.sendMessage({
|
wx.goEasy.im.sendMessage({
|
||||||
message:msg,
|
message:msg,
|
||||||
onSuccess:() => this.updateMsg(id, 'success'),
|
onSuccess:() => {
|
||||||
|
this.updateMsg(id, 'success');
|
||||||
|
this.tryAutoReply(text);
|
||||||
|
},
|
||||||
onFailed:() => this.updateMsg(id, 'failed')
|
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) {
|
sendImageMsg(filePath, fileObj) {
|
||||||
const { currentUser, teamId, teamName, teamAvatar } = this.data;
|
const { currentUser, teamId, teamName, teamAvatar } = this.data;
|
||||||
if (!teamId || !currentUser || !filePath) return;
|
if (!teamId || !currentUser || !filePath) return;
|
||||||
@@ -521,9 +668,30 @@ Page({
|
|||||||
|
|
||||||
onKeyboardHeightChange(e) { this.setData({ keyboardHeight: e.detail.height }); },
|
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() {
|
onPullDownRefresh() {
|
||||||
if (this.data.loadingHistory) return;
|
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.setData({ isRefreshing: true });
|
||||||
this.loadHistory(false).finally(() => { this.setData({ isRefreshing: false }); wx.stopPullDownRefresh(); });
|
this.loadHistory(false).finally(() => {
|
||||||
|
this.setData({ isRefreshing: false });
|
||||||
|
wx.stopPullDownRefresh();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||||
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
||||||
<!-- 对方头像(客服) -->
|
<!-- 对方头像(客服) -->
|
||||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{teamAvatar}}" mode="aspectFill" />
|
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{defaultAvatarUrl}}" mode="aspectFill" binderror="onTeamAvatarError" />
|
||||||
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
||||||
data-messageid="{{item.messageId}}"
|
data-messageid="{{item.messageId}}"
|
||||||
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
||||||
@@ -24,19 +24,19 @@
|
|||||||
<view class="chat-order-info">
|
<view class="chat-order-info">
|
||||||
<text>订单号:{{item.payload.dingdan_id || '无'}}</text>
|
<text>订单号:{{item.payload.dingdan_id || '无'}}</text>
|
||||||
<text>服务:{{item.payload.jieshao || ''}}</text>
|
<text>服务:{{item.payload.jieshao || ''}}</text>
|
||||||
<text style="color:#a855f7;font-weight:bold">¥{{item.payload.jine}}</text>
|
<text style="color:#e6a23c;font-weight:bold">¥{{item.payload.jine}}</text>
|
||||||
</view>
|
</view>
|
||||||
<button class="chat-copy-btn" catchtap="showOrderDetailPopup" data-order="{{item.payload}}" size="mini">查看详情</button>
|
<button class="chat-copy-btn" catchtap="showOrderDetailPopup" data-order="{{item.payload}}" size="mini">查看详情</button>
|
||||||
</view>
|
</view>
|
||||||
<text wx:else class="chat-msg-text">{{item.payload.text || '[未知消息]'}}</text>
|
<text wx:else class="chat-msg-text">{{item.payload.text || '[未知消息]'}}</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- 自己头像 -->
|
<!-- 自己头像 -->
|
||||||
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{currentUser.avatar}}" mode="aspectFill" />
|
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{currentUser.avatar || defaultAvatarUrl}}" mode="aspectFill" binderror="onSelfAvatarError" />
|
||||||
</view>
|
</view>
|
||||||
<!-- 🔥 已读/未读标签已彻底移除 -->
|
<!-- 🔥 已读/未读标签已彻底移除 -->
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<view id="msg-bottom" style="height:20rpx;"></view>
|
<view id="msg-bottom" style="height:56rpx;"></view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 底部输入区域(保持不变) -->
|
<!-- 底部输入区域(保持不变) -->
|
||||||
|
|||||||
@@ -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' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {},
|
||||||
|
"navigationBarTitleText": "接单考试",
|
||||||
|
"navigationBarBackgroundColor": "#c4b5fd",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<view class="exam-page">
|
||||||
|
<view wx:if="{{loading}}" class="center-tip">正在检查考试资格...</view>
|
||||||
|
|
||||||
|
<view wx:elif="{{blocked}}" class="center-box">
|
||||||
|
<text class="tip-title">{{blockTitle}}</text>
|
||||||
|
<text class="tip-desc">{{blockReason}}</text>
|
||||||
|
<view class="btn-row">
|
||||||
|
<view wx:if="{{needRecharge}}" class="btn-primary block" bindtap="goRecharge">去开通会员</view>
|
||||||
|
<view class="btn-outline block" bindtap="retryInit">重试</view>
|
||||||
|
<view class="btn-outline block" bindtap="goBack">返回</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:elif="{{alreadyPassed}}" class="center-box">
|
||||||
|
<text class="tip-title">已通过考试</text>
|
||||||
|
<text class="tip-desc">无需重复考试,可直接抢单</text>
|
||||||
|
<view class="btn-primary block" bindtap="goBack">返回</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:elif="{{finished}}" class="center-box">
|
||||||
|
<text class="tip-title">考试通过</text>
|
||||||
|
<text class="tip-desc">恭喜通过,现在可以去抢单了</text>
|
||||||
|
<view class="btn-primary block" bindtap="goBack">去抢单</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:elif="{{currentQuestion}}" class="exam-body">
|
||||||
|
<view class="exam-card">
|
||||||
|
<view class="progress">第 {{currentIndex + 1}} / {{total}} 题</view>
|
||||||
|
<view class="progress-sub">已错 {{wrongCount}} 题 · 最多可错 {{maxWrong}} 题</view>
|
||||||
|
|
||||||
|
<view class="q-type-tag">{{questionType === 2 ? '多选题' : '单选题'}}</view>
|
||||||
|
<view class="q-stem">{{currentQuestion.stem}}</view>
|
||||||
|
|
||||||
|
<view class="q-images" wx:if="{{currentQuestion.displayImages && currentQuestion.displayImages.length}}">
|
||||||
|
<image wx:for="{{currentQuestion.displayImages}}" wx:key="*this" class="q-img" src="{{item}}" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="options">
|
||||||
|
<view
|
||||||
|
wx:for="{{currentQuestion.displayOptions}}"
|
||||||
|
wx:key="slot"
|
||||||
|
class="opt-item {{item.selected ? 'opt-active' : ''}}"
|
||||||
|
data-slot="{{item.slot}}"
|
||||||
|
bindtap="onSelectOption"
|
||||||
|
>
|
||||||
|
<view class="opt-radio {{item.selected ? 'opt-radio-on' : ''}}">
|
||||||
|
<view wx:if="{{item.selected}}" class="opt-radio-dot"></view>
|
||||||
|
</view>
|
||||||
|
<view class="opt-body">
|
||||||
|
<text class="opt-label">{{item.label}}</text>
|
||||||
|
<text class="opt-text">{{item.text}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:if="{{showExplanation}}" id="explain-box" class="explain-box">
|
||||||
|
<text class="explain-title">解析</text>
|
||||||
|
<text class="explain-text">{{currentQuestion.explanation || '暂无解析'}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="foot-actions" wx:if="{{questionType === 2}}">
|
||||||
|
<view class="btn-primary foot-btn" bindtap="confirmMulti">{{showExplanation ? '重新作答' : '确认本题'}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 });
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{ "navigationBarTitleText": "加载中", "usingComponents": {} }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<view class="tip">正在进入打手端…</view>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.tip { display:flex; align-items:center; justify-content:center; min-height:100vh; color:#999; font-size:28rpx; }
|
||||||
+278
-129
@@ -1,6 +1,9 @@
|
|||||||
// pages/edit/edit.js
|
// pages/edit/edit.js
|
||||||
|
// 点单端设置页;纯打手端时:头像走 /yonghu/xiugai,昵称走 /yonghu/dsgxxx,手机只读(点单端已认证手机号)
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
import upload from '../../utils/upload.js'
|
import upload from '../../utils/upload.js'
|
||||||
|
import request from '../../utils/request.js'
|
||||||
|
import { isFighterOnly } from '../../utils/fighter-only.js'
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -15,54 +18,55 @@ Page({
|
|||||||
newAvatarFile: null,
|
newAvatarFile: null,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
isAvatarActive: false,
|
isAvatarActive: false,
|
||||||
nicknameError: ''
|
nicknameError: '',
|
||||||
|
// 打手扩展字段缓存,更新昵称时原样带回,避免后端把空串覆盖掉
|
||||||
|
_dsDianhua: '',
|
||||||
|
_dsWeixin: '',
|
||||||
|
_dsJieshao: '',
|
||||||
|
fighterMode: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
const fighterMode = isFighterOnly()
|
||||||
|
this.setData({ fighterMode })
|
||||||
wx.setNavigationBarTitle({ title: '编辑资料' })
|
wx.setNavigationBarTitle({ title: '编辑资料' })
|
||||||
this.loadUserData()
|
if (fighterMode) {
|
||||||
},
|
this.loadFighterModeData()
|
||||||
|
} else {
|
||||||
onShow() {
|
this.loadUserData()
|
||||||
this.registerNotificationComponent();
|
|
||||||
},
|
|
||||||
|
|
||||||
registerNotificationComponent() {
|
|
||||||
const notificationComp = this.selectComponent('#global-notification');
|
|
||||||
if (notificationComp && notificationComp.showNotification) {
|
|
||||||
app.globalData.globalNotification = {
|
|
||||||
show: (data) => notificationComp.showNotification(data),
|
|
||||||
hide: () => notificationComp.hideNotification()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载用户数据
|
onShow() {
|
||||||
|
this.registerNotificationComponent()
|
||||||
|
},
|
||||||
|
|
||||||
|
registerNotificationComponent() {
|
||||||
|
const notificationComp = this.selectComponent('#global-notification')
|
||||||
|
if (notificationComp && notificationComp.showNotification) {
|
||||||
|
app.globalData.globalNotification = {
|
||||||
|
show: (data) => notificationComp.showNotification(data),
|
||||||
|
hide: () => notificationComp.hideNotification(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ——— 点单端:原逻辑 ———
|
||||||
loadUserData() {
|
loadUserData() {
|
||||||
try {
|
try {
|
||||||
const uid = wx.getStorageSync('uid') || ''
|
const uid = wx.getStorageSync('uid') || ''
|
||||||
const nicheng = wx.getStorageSync('nicheng') || ''
|
const nicheng = wx.getStorageSync('nicheng') || ''
|
||||||
const phone = wx.getStorageSync('phone') || ''
|
const phone = wx.getStorageSync('phone') || ''
|
||||||
const touxiang = wx.getStorageSync('touxiang') || ''
|
const touxiang = wx.getStorageSync('touxiang') || ''
|
||||||
|
|
||||||
const ossImageUrl = app.globalData.ossImageUrl || ''
|
|
||||||
const defaultAvatar = app.globalData.morentouxiang || ''
|
|
||||||
|
|
||||||
let avatarUrl = ''
|
|
||||||
if (touxiang) {
|
|
||||||
avatarUrl = touxiang.startsWith('http') ? touxiang : `${ossImageUrl}${touxiang}`
|
|
||||||
} else if (defaultAvatar) {
|
|
||||||
avatarUrl = defaultAvatar.startsWith('http') ? defaultAvatar : `${ossImageUrl}${defaultAvatar}`
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
avatarUrl,
|
avatarUrl: this.buildAvatarUrl(touxiang),
|
||||||
uid,
|
uid,
|
||||||
nicheng,
|
nicheng,
|
||||||
phone,
|
phone,
|
||||||
originalAvatar: touxiang,
|
originalAvatar: touxiang,
|
||||||
originalNicheng: nicheng,
|
originalNicheng: nicheng,
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载用户数据失败:', error)
|
console.error('加载用户数据失败:', error)
|
||||||
@@ -71,157 +75,302 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 微信头像选择
|
// ——— 纯打手端:手机/头像用点单端存储;昵称用打手资料 ———
|
||||||
|
async loadFighterModeData() {
|
||||||
|
this.setData({ isLoading: true })
|
||||||
|
try {
|
||||||
|
const uid = wx.getStorageSync('uid') || ''
|
||||||
|
const phone = wx.getStorageSync('phone') || ''
|
||||||
|
const touxiang = wx.getStorageSync('touxiang') || ''
|
||||||
|
|
||||||
|
let nicheng =
|
||||||
|
wx.getStorageSync('dsnc') ||
|
||||||
|
app.globalData.dashouNicheng ||
|
||||||
|
''
|
||||||
|
let dsDianhua = wx.getStorageSync('dsdianhua') || ''
|
||||||
|
let dsWeixin = wx.getStorageSync('dsweixin') || ''
|
||||||
|
let dsJieshao = wx.getStorageSync('dsjieshao') || ''
|
||||||
|
|
||||||
|
// 昵称缺失时拉打手资料(不碰点单端昵称)
|
||||||
|
if (!nicheng || !String(nicheng).trim()) {
|
||||||
|
try {
|
||||||
|
const res = await request({ url: '/yonghu/dszjxxhq', method: 'POST' })
|
||||||
|
if (res && res.data && res.data.code === 200 && res.data.data) {
|
||||||
|
const d = res.data.data
|
||||||
|
nicheng = d.nicheng || ''
|
||||||
|
dsDianhua = d.dianhua || dsDianhua
|
||||||
|
dsWeixin = d.wechat || dsWeixin
|
||||||
|
dsJieshao = d.jieshao || dsJieshao
|
||||||
|
wx.setStorageSync('dsnc', nicheng)
|
||||||
|
wx.setStorageSync('dsdianhua', dsDianhua)
|
||||||
|
wx.setStorageSync('dsweixin', dsWeixin)
|
||||||
|
wx.setStorageSync('dsjieshao', dsJieshao)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('拉取打手昵称失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
avatarUrl: this.buildAvatarUrl(touxiang),
|
||||||
|
uid,
|
||||||
|
phone,
|
||||||
|
nicheng,
|
||||||
|
originalAvatar: touxiang,
|
||||||
|
originalNicheng: nicheng,
|
||||||
|
_dsDianhua: dsDianhua,
|
||||||
|
_dsWeixin: dsWeixin,
|
||||||
|
_dsJieshao: dsJieshao,
|
||||||
|
isLoading: false,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载打手设置数据失败:', error)
|
||||||
|
this.setData({ isLoading: false })
|
||||||
|
wx.showToast({ title: '加载数据失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
buildAvatarUrl(touxiang) {
|
||||||
|
const ossImageUrl = app.globalData.ossImageUrl || ''
|
||||||
|
const defaultAvatar = app.globalData.morentouxiang || ''
|
||||||
|
if (touxiang) {
|
||||||
|
return touxiang.startsWith('http') ? touxiang : `${ossImageUrl}${touxiang}`
|
||||||
|
}
|
||||||
|
if (defaultAvatar) {
|
||||||
|
return defaultAvatar.startsWith('http') ? defaultAvatar : `${ossImageUrl}${defaultAvatar}`
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
|
||||||
onChooseAvatar(e) {
|
onChooseAvatar(e) {
|
||||||
const avatarTempPath = e.detail.avatarUrl
|
const avatarTempPath = e.detail.avatarUrl
|
||||||
this.setData({
|
this.setData(
|
||||||
avatarUrl: avatarTempPath,
|
{
|
||||||
newAvatarFile: avatarTempPath
|
avatarUrl: avatarTempPath,
|
||||||
}, () => {
|
newAvatarFile: avatarTempPath,
|
||||||
this.checkChanges()
|
},
|
||||||
})
|
() => this.checkChanges()
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
chooseAvatar() {
|
chooseAvatar() {
|
||||||
this.setData({ isAvatarActive: true })
|
this.setData({ isAvatarActive: true })
|
||||||
setTimeout(() => {
|
setTimeout(() => this.setData({ isAvatarActive: false }), 500)
|
||||||
this.setData({ isAvatarActive: false })
|
|
||||||
}, 500)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 昵称输入
|
|
||||||
onNicknameInput(e) {
|
onNicknameInput(e) {
|
||||||
const value = e.detail.value.trim()
|
const value = e.detail.value.trim()
|
||||||
this.setData({
|
this.setData(
|
||||||
nicheng: value,
|
{
|
||||||
nicknameError: ''
|
nicheng: value,
|
||||||
}, () => {
|
nicknameError: '',
|
||||||
this.checkChanges()
|
},
|
||||||
})
|
() => this.checkChanges()
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 检查变化
|
|
||||||
checkChanges() {
|
checkChanges() {
|
||||||
const { originalNicheng, nicheng, newAvatarFile } = this.data;
|
const { originalNicheng, nicheng, newAvatarFile } = this.data
|
||||||
const hasChanges = (nicheng !== originalNicheng) || (newAvatarFile !== null);
|
const hasChanges = nicheng !== originalNicheng || newAvatarFile !== null
|
||||||
this.setData({ hasChanges });
|
this.setData({ hasChanges })
|
||||||
|
},
|
||||||
|
|
||||||
|
validateData() {
|
||||||
|
const { nicheng } = this.data
|
||||||
|
let hasError = false
|
||||||
|
this.setData({ nicknameError: '' })
|
||||||
|
|
||||||
|
if (nicheng && nicheng.length > 20) {
|
||||||
|
this.setData({ nicknameError: '昵称不能超过20个字符' })
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
if (nicheng !== this.data.originalNicheng && nicheng.trim() === '') {
|
||||||
|
this.setData({ nicknameError: '昵称不能为空' })
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
if (hasError) {
|
||||||
|
if (this.data.nicknameError) {
|
||||||
|
wx.showToast({ title: this.data.nicknameError, icon: 'none' })
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存
|
|
||||||
async onSave() {
|
async onSave() {
|
||||||
if (!this.data.hasChanges) {
|
if (!this.data.hasChanges) {
|
||||||
wx.showToast({ title: '没有需要保存的更改', icon: 'none' });
|
wx.showToast({ title: '没有需要保存的更改', icon: 'none' })
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (this.data.isSaving) return;
|
if (this.data.isSaving) return
|
||||||
|
if (!this.validateData()) return
|
||||||
// 验证数据
|
|
||||||
if (!this.validateData()) return;
|
this.setData({ isSaving: true })
|
||||||
|
wx.showLoading({ title: '保存中...', mask: true })
|
||||||
this.setData({ isSaving: true });
|
|
||||||
wx.showLoading({ title: '保存中...', mask: true });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const formData = {};
|
if (this.data.fighterMode) {
|
||||||
if (this.data.nicheng !== this.data.originalNicheng) {
|
await this.saveFighterMode()
|
||||||
formData.nicheng = this.data.nicheng;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await upload({
|
|
||||||
url: '/yonghu/xiugai',
|
|
||||||
formData,
|
|
||||||
filePath: this.data.newAvatarFile,
|
|
||||||
fileName: 'avatar'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data) {
|
|
||||||
const response = res.data;
|
|
||||||
if (response.code === 0) {
|
|
||||||
await this.handleUpdateSuccess(response.data);
|
|
||||||
} else {
|
|
||||||
throw new Error(response.msg || '保存失败');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('网络错误');
|
await this.saveOrderMode()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存失败:', error);
|
console.error('保存失败:', error)
|
||||||
if (error.message.includes('认证失败') || error.message.includes('401')) {
|
if (error.message && (error.message.includes('认证失败') || error.message.includes('401'))) {
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '登录已过期,请重新登录',
|
content: '登录已过期,请重新登录',
|
||||||
complete: (res) => {
|
complete: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
wx.removeStorageSync('token');
|
wx.removeStorageSync('token')
|
||||||
wx.removeStorageSync('userInfo');
|
wx.removeStorageSync('userInfo')
|
||||||
wx.switchTab({ url: '/pages/mine/mine' });
|
wx.reLaunch({ url: '/pages/fighter/fighter' })
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: error.message || '保存失败', icon: 'none' });
|
wx.showToast({ title: error.message || '保存失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
wx.hideLoading();
|
wx.hideLoading()
|
||||||
this.setData({ isSaving: false });
|
this.setData({ isSaving: false })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 验证数据
|
/** 点单端原保存:昵称+头像 → /yonghu/xiugai */
|
||||||
validateData() {
|
async saveOrderMode() {
|
||||||
const { nicheng } = this.data;
|
const formData = {}
|
||||||
let hasError = false;
|
if (this.data.nicheng !== this.data.originalNicheng) {
|
||||||
this.setData({ nicknameError: '' });
|
formData.nicheng = this.data.nicheng
|
||||||
|
|
||||||
if (nicheng && nicheng.length > 20) {
|
|
||||||
this.setData({ nicknameError: '昵称不能超过20个字符' });
|
|
||||||
hasError = true;
|
|
||||||
}
|
}
|
||||||
if (nicheng !== this.data.originalNicheng && nicheng.trim() === '') {
|
const res = await upload({
|
||||||
this.setData({ nicknameError: '昵称不能为空' });
|
url: '/yonghu/xiugai',
|
||||||
hasError = true;
|
formData,
|
||||||
|
filePath: this.data.newAvatarFile,
|
||||||
|
fileName: 'avatar',
|
||||||
|
})
|
||||||
|
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||||
|
await this.handleUpdateSuccess(res.data.data || {})
|
||||||
|
} else {
|
||||||
|
throw new Error((res.data && (res.data.msg || res.data.message)) || '保存失败')
|
||||||
}
|
}
|
||||||
if (hasError) {
|
},
|
||||||
if (this.data.nicknameError) {
|
|
||||||
wx.showToast({ title: this.data.nicknameError, icon: 'none' });
|
/**
|
||||||
|
* 纯打手端混调:
|
||||||
|
* - 头像变了 → /yonghu/xiugai(点单端,只传头像,不改点单昵称)
|
||||||
|
* - 昵称变了 → /yonghu/dsgxxx(打手端,带回其它打手字段防覆盖)
|
||||||
|
* 手机号只读,不提交
|
||||||
|
*/
|
||||||
|
async saveFighterMode() {
|
||||||
|
const nickChanged = this.data.nicheng !== this.data.originalNicheng
|
||||||
|
const avatarChanged = !!this.data.newAvatarFile
|
||||||
|
let avatarData = null
|
||||||
|
let nickData = null
|
||||||
|
|
||||||
|
if (avatarChanged) {
|
||||||
|
const res = await upload({
|
||||||
|
url: '/yonghu/xiugai',
|
||||||
|
formData: {},
|
||||||
|
filePath: this.data.newAvatarFile,
|
||||||
|
fileName: 'avatar',
|
||||||
|
})
|
||||||
|
if (!(res.statusCode === 200 && res.data && res.data.code === 0)) {
|
||||||
|
throw new Error((res.data && (res.data.msg || res.data.message)) || '头像保存失败')
|
||||||
}
|
}
|
||||||
return false;
|
avatarData = res.data.data || {}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
if (nickChanged) {
|
||||||
|
const postData = {
|
||||||
|
nicheng: this.data.nicheng,
|
||||||
|
dianhua: this.data._dsDianhua || wx.getStorageSync('dsdianhua') || '',
|
||||||
|
wechat: this.data._dsWeixin || wx.getStorageSync('dsweixin') || '',
|
||||||
|
jieshao: this.data._dsJieshao || wx.getStorageSync('dsjieshao') || '',
|
||||||
|
}
|
||||||
|
const res = await request({
|
||||||
|
url: '/yonghu/dsgxxx',
|
||||||
|
method: 'POST',
|
||||||
|
data: postData,
|
||||||
|
})
|
||||||
|
if (!(res && res.data && res.data.code === 200)) {
|
||||||
|
throw new Error((res && res.data && res.data.msg) || '昵称保存失败')
|
||||||
|
}
|
||||||
|
nickData = res.data.data || postData
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleFighterUpdateSuccess(avatarData, nickData)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleFighterUpdateSuccess(avatarData, nickData) {
|
||||||
|
const ossImageUrl = app.globalData.ossImageUrl || ''
|
||||||
|
let avatarUrl = this.data.avatarUrl
|
||||||
|
let originalAvatar = this.data.originalAvatar
|
||||||
|
let originalNicheng = this.data.originalNicheng
|
||||||
|
let nicheng = this.data.nicheng
|
||||||
|
|
||||||
|
if (avatarData && avatarData.touxiang != null) {
|
||||||
|
wx.setStorageSync('touxiang', avatarData.touxiang)
|
||||||
|
originalAvatar = avatarData.touxiang
|
||||||
|
avatarUrl = avatarData.touxiang.startsWith('http')
|
||||||
|
? avatarData.touxiang
|
||||||
|
: `${ossImageUrl}${avatarData.touxiang}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nickData) {
|
||||||
|
const newNick = nickData.nicheng != null ? nickData.nicheng : nicheng
|
||||||
|
nicheng = newNick
|
||||||
|
originalNicheng = newNick
|
||||||
|
wx.setStorageSync('dsnc', newNick)
|
||||||
|
app.globalData.dashouNicheng = newNick
|
||||||
|
if (nickData.dianhua != null) wx.setStorageSync('dsdianhua', nickData.dianhua || '')
|
||||||
|
if (nickData.wechat != null) wx.setStorageSync('dsweixin', nickData.wechat || '')
|
||||||
|
if (nickData.jieshao != null) wx.setStorageSync('dsjieshao', nickData.jieshao || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
avatarUrl,
|
||||||
|
nicheng,
|
||||||
|
originalAvatar,
|
||||||
|
originalNicheng,
|
||||||
|
newAvatarFile: null,
|
||||||
|
hasChanges: false,
|
||||||
|
_dsDianhua: wx.getStorageSync('dsdianhua') || this.data._dsDianhua,
|
||||||
|
_dsWeixin: wx.getStorageSync('dsweixin') || this.data._dsWeixin,
|
||||||
|
_dsJieshao: wx.getStorageSync('dsjieshao') || this.data._dsJieshao,
|
||||||
|
})
|
||||||
|
|
||||||
|
wx.showToast({ title: '保存成功', icon: 'success', duration: 2000 })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 更新成功处理
|
|
||||||
async handleUpdateSuccess(updateData) {
|
async handleUpdateSuccess(updateData) {
|
||||||
if (updateData.touxiang !== undefined && updateData.touxiang !== null) {
|
if (updateData.touxiang !== undefined && updateData.touxiang !== null) {
|
||||||
wx.setStorageSync('touxiang', updateData.touxiang);
|
wx.setStorageSync('touxiang', updateData.touxiang)
|
||||||
}
|
}
|
||||||
if (updateData.nicheng !== undefined && updateData.nicheng !== null) {
|
if (updateData.nicheng !== undefined && updateData.nicheng !== null) {
|
||||||
wx.setStorageSync('nicheng', updateData.nicheng);
|
wx.setStorageSync('nicheng', updateData.nicheng)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateData.nicheng) {
|
if (updateData.nicheng) {
|
||||||
app.globalData.userNicheng = updateData.nicheng;
|
app.globalData.userNicheng = updateData.nicheng
|
||||||
}
|
}
|
||||||
|
|
||||||
const ossImageUrl = app.globalData.ossImageUrl || '';
|
const ossImageUrl = app.globalData.ossImageUrl || ''
|
||||||
let avatarUrl = this.data.avatarUrl;
|
let avatarUrl = this.data.avatarUrl
|
||||||
if (updateData.touxiang) {
|
if (updateData.touxiang) {
|
||||||
avatarUrl = updateData.touxiang.startsWith('http') ?
|
avatarUrl = updateData.touxiang.startsWith('http')
|
||||||
updateData.touxiang : `${ossImageUrl}${updateData.touxiang}`;
|
? updateData.touxiang
|
||||||
|
: `${ossImageUrl}${updateData.touxiang}`
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
originalAvatar: updateData.touxiang || this.data.originalAvatar,
|
originalAvatar: updateData.touxiang || this.data.originalAvatar,
|
||||||
originalNicheng: updateData.nicheng || this.data.originalNicheng,
|
originalNicheng: updateData.nicheng || this.data.originalNicheng,
|
||||||
newAvatarFile: null,
|
newAvatarFile: null,
|
||||||
hasChanges: false
|
hasChanges: false,
|
||||||
});
|
})
|
||||||
|
|
||||||
wx.showToast({
|
wx.showToast({ title: '保存成功', icon: 'success', duration: 2000 })
|
||||||
title: '保存成功',
|
},
|
||||||
icon: 'success',
|
})
|
||||||
duration: 2000
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -27,14 +27,14 @@
|
|||||||
<view class="item-value readonly">{{uid || '••••••'}}</view>
|
<view class="item-value readonly">{{uid || '••••••'}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 昵称(可编辑) -->
|
<!-- 昵称(可编辑;纯打手端展示/保存的是打手昵称) -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<view class="item-label">昵称</view>
|
<view class="item-label">{{fighterMode ? '服务昵称' : '昵称'}}</view>
|
||||||
<view class="input-container">
|
<view class="input-container">
|
||||||
<input
|
<input
|
||||||
class="item-input {{nicknameError ? 'error' : ''}}"
|
class="item-input {{nicknameError ? 'error' : ''}}"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入昵称"
|
placeholder="{{fighterMode ? '请输入服务昵称' : '请输入昵称'}}"
|
||||||
placeholder-class="placeholder"
|
placeholder-class="placeholder"
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
value="{{nicheng}}"
|
value="{{nicheng}}"
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 手机号(只读展示,不可修改) -->
|
<!-- 手机号(只读:点单端已认证号码,不可手填) -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<view class="item-label">手机号</view>
|
<view class="item-label">手机号</view>
|
||||||
<view class="item-value readonly">{{phone || '未绑定'}}</view>
|
<view class="item-value readonly">{{phone || '未绑定'}}</view>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* pages/edit/edit.wxss */
|
/* pages/edit/edit.wxss */
|
||||||
page {
|
page {
|
||||||
background: linear-gradient(135deg, #faf5ff 0%, #f0f8ff 100%);
|
background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"chenghao-tag": "/components/chenghao-tag/chenghao-tag"
|
"chenghao-tag": "/components/chenghao-tag/chenghao-tag"
|
||||||
},
|
},
|
||||||
"backgroundTextStyle": "dark",
|
"backgroundTextStyle": "dark",
|
||||||
"navigationBarBackgroundColor": "#fff8e1",
|
"navigationBarBackgroundColor": "#f7dc51",
|
||||||
"navigationBarTitleText": "常规发单",
|
"navigationBarTitleText": "常规发单",
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"backgroundColor": "#f5f5f5",
|
"backgroundColor": "#f5f5f5",
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-switch.active {
|
.filter-switch.active {
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ page {
|
|||||||
|
|
||||||
.copy-link-btn {
|
.copy-link-btn {
|
||||||
padding: 8rpx 20rpx;
|
padding: 8rpx 20rpx;
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
border-radius: 15rpx;
|
border-radius: 15rpx;
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
@@ -337,7 +337,7 @@ page {
|
|||||||
.load-more-btn {
|
.load-more-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 15rpx 40rpx;
|
padding: 15rpx 40rpx;
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
border-radius: 30rpx;
|
border-radius: 30rpx;
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
@@ -373,7 +373,7 @@ page {
|
|||||||
.generate-modal-grid-btn,
|
.generate-modal-grid-btn,
|
||||||
.copy-modal-grid-btn,
|
.copy-modal-grid-btn,
|
||||||
.edit-modal-grid-btn {
|
.edit-modal-grid-btn {
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,7 +484,7 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.confirm-add-grid-btn {
|
.confirm-add-grid-btn {
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +538,7 @@ page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.confirm-new-link-grid-btn {
|
.confirm-new-link-grid-btn {
|
||||||
background: linear-gradient(180deg, #c4b5fd, #a78bfa);
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
color: #492f00;
|
color: #492f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +569,7 @@ page {
|
|||||||
width: 90rpx;
|
width: 90rpx;
|
||||||
height: 90rpx;
|
height: 90rpx;
|
||||||
border: 8rpx solid #eee;
|
border: 8rpx solid #eee;
|
||||||
border-top: 8rpx solid #9333ea;
|
border-top: 8rpx solid #ffd061;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 1.2s linear infinite;
|
animation: spin 1.2s linear infinite;
|
||||||
margin-bottom: 35rpx;
|
margin-bottom: 35rpx;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* 页面容器 */
|
/* 页面容器 */
|
||||||
.container {
|
.container {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: linear-gradient(135deg, #f5f3ff 0%, #e6f7ff 100%);
|
background: linear-gradient(135deg, #fffacd 0%, #e6f7ff 100%);
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
height: 180rpx;
|
height: 180rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 6rpx solid #ffffff;
|
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;
|
z-index: 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
width: 220rpx;
|
width: 220rpx;
|
||||||
height: 220rpx;
|
height: 220rpx;
|
||||||
border-radius: 50%;
|
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;
|
z-index: 1;
|
||||||
animation: halo-pulse 2s infinite ease-in-out;
|
animation: halo-pulse 2s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<view class="ledger-page safe-area">
|
||||||
|
<view class="status-bar" style="height:{{statusBar}}px"></view>
|
||||||
|
<view class="nav-bar flexb">
|
||||||
|
<text class="back" bindtap="goBack">‹</text>
|
||||||
|
<text class="nav-title">{{pageTitle}}</text>
|
||||||
|
<text class="back placeholder"></text>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-y class="ledger-scroll" refresher-enabled refresher-triggered="{{refreshing}}" bindrefresherrefresh="onRefresh" bindscrolltolower="onLoadMore">
|
||||||
|
<view wx:if="{{loading && list.length === 0}}" class="empty-box">加载中...</view>
|
||||||
|
<view wx:elif="{{list.length === 0}}" class="empty-box">暂无记录</view>
|
||||||
|
<view wx:for="{{list}}" wx:key="id" class="list-item flexb">
|
||||||
|
<view class="item-main">
|
||||||
|
<view class="row-t">{{item.title}}</view>
|
||||||
|
<view class="row-d">{{item.time}}</view>
|
||||||
|
</view>
|
||||||
|
<text class="row-r {{item.minus ? 'minus' : ''}}">{{item.amount}}</text>
|
||||||
|
</view>
|
||||||
|
<view wx:if="{{list.length > 0 && !hasMore}}" class="load-tip">— 已加载全部 —</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
+683
-683
File diff suppressed because it is too large.
Load diff
@@ -296,9 +296,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zhuangtai-shensuzhong {
|
.zhuangtai-shensuzhong {
|
||||||
background: rgba(147, 51, 234, 0.2);
|
background: rgba(255, 165, 0, 0.2);
|
||||||
border-color: #9333ea;
|
border-color: #FFA500;
|
||||||
box-shadow: 0 0 8rpx rgba(147, 51, 234, 0.2);
|
box-shadow: 0 0 8rpx rgba(255, 165, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.zhuangtai-weizhi {
|
.zhuangtai-weizhi {
|
||||||
@@ -657,9 +657,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cbtn-shensu {
|
.cbtn-shensu {
|
||||||
background: rgba(147, 51, 234, 0.1);
|
background: rgba(255, 165, 0, 0.1);
|
||||||
border-color: #9333ea;
|
border-color: #FFA500;
|
||||||
box-shadow: 0 0 12rpx rgba(147, 51, 234, 0.2);
|
box-shadow: 0 0 12rpx rgba(255, 165, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cbtn-shensu-disabled {
|
.cbtn-shensu-disabled {
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -99,6 +99,15 @@
|
|||||||
<text class="item-label">订单状态:</text>
|
<text class="item-label">订单状态:</text>
|
||||||
<text class="item-value zhuangtai-text">{{zhuangtaiWenziMap[jibenShuju.zhuangtai] || '未知状态'}}</text>
|
<text class="item-value zhuangtai-text">{{zhuangtaiWenziMap[jibenShuju.zhuangtai] || '未知状态'}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="info-item-row auto-settle-row" wx:if="{{autoSettleTip || autoSettleClock}}">
|
||||||
|
<text class="item-label">自动结算:</text>
|
||||||
|
<view class="auto-settle-value">
|
||||||
|
<text class="auto-settle-clock" wx:if="{{autoSettleClock}}">{{autoSettleClock}}</text>
|
||||||
|
<text class="item-value auto-settle-text">{{autoSettleTip}}</text>
|
||||||
|
<text class="auto-settle-expire" wx:if="{{autoSettleExpireAt}}">到期 {{autoSettleExpireAt}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 发单平台信息 -->
|
<!-- 发单平台信息 -->
|
||||||
<view class="info-item-row" wx:if="{{jibenShuju.fadanpingtai !== undefined && jibenShuju.fadanpingtai !== null}}">
|
<view class="info-item-row" wx:if="{{jibenShuju.fadanpingtai !== undefined && jibenShuju.fadanpingtai !== null}}">
|
||||||
@@ -108,6 +117,55 @@
|
|||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 组队面板 -->
|
||||||
|
<view class="team-area" wx:if="{{jibenShuju.zhuangtai == 2 || team}}">
|
||||||
|
<view class="info-title">组队</view>
|
||||||
|
|
||||||
|
<block wx:if="{{!team && jibenShuju.zhuangtai == 2 && isLeader}}">
|
||||||
|
<text class="team-hint">本单进行中,可开启组队招募(最多再招 3 人)</text>
|
||||||
|
<view class="team-open-btn" bindtap="openTeamForm">开启组队</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<block wx:if="{{team}}">
|
||||||
|
<view class="info-item-row">
|
||||||
|
<text class="item-label">状态:</text>
|
||||||
|
<text class="item-value">{{teamStatusText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item-row">
|
||||||
|
<text class="item-label">人数:</text>
|
||||||
|
<text class="item-value">已入队 {{team.joined_count}} / 目标 {{team.need_count}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item-row">
|
||||||
|
<text class="item-label">分红:</text>
|
||||||
|
<text class="item-value jine-green">¥{{teamShareText}}({{team.share_mode == 'fixed' ? '固定' : '平均'}})</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item-row" wx:if="{{team.remark}}">
|
||||||
|
<text class="item-label">备注:</text>
|
||||||
|
<text class="item-value">{{team.remark}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="team-members" wx:if="{{team.members && team.members.length}}">
|
||||||
|
<text class="section-subtitle">组队接待者</text>
|
||||||
|
<block wx:for="{{team.members}}" wx:key="user_uid">
|
||||||
|
<view class="team-member-row">
|
||||||
|
<text class="tm-role">{{item.role_text || (item.role == 'leader' ? '队长' : '队友')}}</text>
|
||||||
|
<text class="tm-name">{{item.nicheng || '打手'}}</text>
|
||||||
|
<text class="tm-uid">{{item.user_uid}}</text>
|
||||||
|
<text class="tm-game" wx:if="{{item.game_id}}">游戏ID {{item.game_id}}</text>
|
||||||
|
<view class="copy-btn" wx:if="{{item.game_id}}" bindtap="fuzhiWenben" data-text="{{item.game_id}}" catchtap="fuzhiWenben">
|
||||||
|
<text class="copy-text">复制</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="team-actions">
|
||||||
|
<view class="team-chat-btn" bindtap="goToTeamGroupChat">进入订单群聊</view>
|
||||||
|
<view class="team-action-btn ghost" wx:if="{{isLeader && team.status == 1 && jibenShuju.zhuangtai == 2}}" bindtap="lockTeam">关停招募</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 商家信息区域 -->
|
<!-- 商家信息区域 -->
|
||||||
<view
|
<view
|
||||||
@@ -151,14 +209,28 @@
|
|||||||
<!-- 退款信息区域 -->
|
<!-- 退款信息区域 -->
|
||||||
<view
|
<view
|
||||||
class="tuikuan-area"
|
class="tuikuan-area"
|
||||||
wx:if="{{showRefundInfo && xiangxiShuju.tuikuan_liyou}}"
|
wx:if="{{showRefundInfo && (xiangxiShuju.tuikuan_liyou || xiangxiShuju.tuikuan_tupian.length)}}"
|
||||||
>
|
>
|
||||||
<view class="info-title">退款信息</view>
|
<view class="info-title">退款信息</view>
|
||||||
|
|
||||||
<view class="info-item-row">
|
<view class="info-item-row" wx:if="{{xiangxiShuju.tuikuan_liyou}}">
|
||||||
<text class="item-label">退款理由:</text>
|
<text class="item-label">退款理由:</text>
|
||||||
<text class="item-value">{{xiangxiShuju.tuikuan_liyou}}</text>
|
<text class="item-value">{{xiangxiShuju.tuikuan_liyou}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="info-item-row" wx:if="{{xiangxiShuju.tuikuan_tupian.length}}" style="flex-direction:column;align-items:flex-start;">
|
||||||
|
<text class="item-label" style="margin-bottom:12rpx;">相关图片:</text>
|
||||||
|
<view style="display:flex;flex-wrap:wrap;">
|
||||||
|
<block wx:for="{{xiangxiShuju.tuikuan_tupian}}" wx:key="*this">
|
||||||
|
<image
|
||||||
|
src="{{item}}"
|
||||||
|
mode="aspectFill"
|
||||||
|
style="width:140rpx;height:140rpx;margin:0 12rpx 12rpx 0;border-radius:8rpx;"
|
||||||
|
bindtap="previewTuikuanTupian"
|
||||||
|
data-url="{{item}}"
|
||||||
|
/>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 处罚申请信息区域 -->
|
<!-- 处罚申请信息区域 -->
|
||||||
@@ -179,7 +251,7 @@
|
|||||||
<text class="item-label">申请状态:</text>
|
<text class="item-label">申请状态:</text>
|
||||||
<text
|
<text
|
||||||
class="item-value"
|
class="item-value"
|
||||||
style="color: {{xiangxiShuju.chufa_zhuangtai == 0 ? '#9333ea' : (xiangxiShuju.chufa_zhuangtai == 1 ? '#4CAF50' : '#FF4444')}}"
|
style="color: {{xiangxiShuju.chufa_zhuangtai == 0 ? '#FF9800' : (xiangxiShuju.chufa_zhuangtai == 1 ? '#4CAF50' : '#FF4444')}}"
|
||||||
>
|
>
|
||||||
{{xiangxiShuju.chufa_zhuangtai == 0 ? '审核中' : (xiangxiShuju.chufa_zhuangtai == 1 ? '处罚成功' : '处罚驳回')}}
|
{{xiangxiShuju.chufa_zhuangtai == 0 ? '审核中' : (xiangxiShuju.chufa_zhuangtai == 1 ? '处罚成功' : '处罚驳回')}}
|
||||||
</text>
|
</text>
|
||||||
@@ -200,7 +272,7 @@
|
|||||||
|
|
||||||
<!-- 接单员交付历史(只读模式) -->
|
<!-- 接单员交付历史(只读模式) -->
|
||||||
<view class="dashou-jiaofu-area" wx:if="{{!isModifying && xiangxiShuju.dashou_jiaofu.length > 0}}">
|
<view class="dashou-jiaofu-area" wx:if="{{!isModifying && xiangxiShuju.dashou_jiaofu.length > 0}}">
|
||||||
<view class="info-title">我的交付</view>
|
<view class="info-title">{{isLeader ? '订单交付' : '订单交付(只读)'}}</view>
|
||||||
|
|
||||||
<!-- 接单员交付图片 -->
|
<!-- 接单员交付图片 -->
|
||||||
<view class="dashou-jiaofu-container">
|
<view class="dashou-jiaofu-container">
|
||||||
@@ -232,8 +304,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 🆕 修改模式下的可编辑区域(当 isModifying 为 true 时显示) -->
|
<!-- 修改模式(仅队长 canModify) -->
|
||||||
<view class="dashou-jiaofu-area" wx:if="{{isModifying}}">
|
<view class="dashou-jiaofu-area" wx:if="{{isModifying && canModify}}">
|
||||||
<view class="info-title">修改交付</view>
|
<view class="info-title">修改交付</view>
|
||||||
|
|
||||||
<!-- 图片编辑区域 -->
|
<!-- 图片编辑区域 -->
|
||||||
@@ -299,8 +371,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 提交订单区域(仅状态=2时显示,保持不变) -->
|
<!-- 提交订单:仅队长(或非组队接单人) -->
|
||||||
<view class="tijiao-area" wx:if="{{jibenShuju.zhuangtai == 2}}">
|
<view class="tijiao-area" wx:if="{{jibenShuju.zhuangtai == 2 && canSubmit}}">
|
||||||
<view class="info-title">提交订单</view>
|
<view class="info-title">提交订单</view>
|
||||||
|
|
||||||
<!-- 选择图片 -->
|
<!-- 选择图片 -->
|
||||||
@@ -367,8 +439,8 @@
|
|||||||
<!-- ========== 底部按钮区域 ========== -->
|
<!-- ========== 底部按钮区域 ========== -->
|
||||||
<view class="bottom-btns-container" wx:if="{{!isLoading}}">
|
<view class="bottom-btns-container" wx:if="{{!isLoading}}">
|
||||||
|
|
||||||
<!-- 🆕 修改模式下的按钮(取消/确认) -->
|
<!-- 修改模式按钮(仅队长 canModify) -->
|
||||||
<block wx:if="{{isModifying}}">
|
<block wx:if="{{isModifying && canModify}}">
|
||||||
<view class="btn-row">
|
<view class="btn-row">
|
||||||
<view
|
<view
|
||||||
class="bottom-btn cancel-modify-btn"
|
class="bottom-btn cancel-modify-btn"
|
||||||
@@ -417,8 +489,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 🆕 新增:修改按钮(仅当状态为4或8时显示) -->
|
<!-- 修改交付:仅队长 -->
|
||||||
<view class="btn-row" wx:if="{{jibenShuju.zhuangtai == 4 || jibenShuju.zhuangtai == 8}}">
|
<view class="btn-row" wx:if="{{canModify && (jibenShuju.zhuangtai == 4 || jibenShuju.zhuangtai == 8)}}">
|
||||||
<view
|
<view
|
||||||
class="bottom-btn modify-btn full-width"
|
class="bottom-btn modify-btn full-width"
|
||||||
bindtap="enterModify"
|
bindtap="enterModify"
|
||||||
@@ -428,15 +500,21 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 提交按钮(仅状态=2时显示) -->
|
<!-- 提交:仅队长 -->
|
||||||
<view
|
<view
|
||||||
class="bottom-btn submit-btn"
|
class="bottom-btn submit-btn"
|
||||||
wx:if="{{jibenShuju.zhuangtai == 2}}"
|
wx:if="{{canSubmit && jibenShuju.zhuangtai == 2}}"
|
||||||
bindtap="tijiaoDingdan"
|
bindtap="tijiaoDingdan"
|
||||||
>
|
>
|
||||||
<text class="btn-text">{{isSubmitting ? '提交中...' : '立即提交'}}</text>
|
<text class="btn-text">{{isSubmitting ? '提交中...' : '立即提交'}}</text>
|
||||||
<view class="btn-shine"></view>
|
<view class="btn-shine"></view>
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
|
class="team-member-tip"
|
||||||
|
wx:if="{{team && !isLeader && jibenShuju.zhuangtai == 2}}"
|
||||||
|
>
|
||||||
|
<text>组队中仅队长可提交交付,请等待队长操作</text>
|
||||||
|
</view>
|
||||||
</block>
|
</block>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
@@ -472,6 +550,49 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 开启组队弹窗 -->
|
||||||
|
<view class="modal-container" wx:if="{{showTeamForm}}">
|
||||||
|
<view class="modal-mask" bindtap="closeTeamForm"></view>
|
||||||
|
<view class="modal-content team-form-modal">
|
||||||
|
<view class="modal-header">
|
||||||
|
<text class="modal-title">开启组队</text>
|
||||||
|
<view class="modal-close" bindtap="closeTeamForm">×</view>
|
||||||
|
</view>
|
||||||
|
<view class="modal-body">
|
||||||
|
<view class="tf-row">
|
||||||
|
<text class="tf-label">招募人数(1~3)</text>
|
||||||
|
<view class="tf-need">
|
||||||
|
<view class="need-btn {{teamForm.need_count == 1 ? 'on' : ''}}" data-n="1" bindtap="setTeamNeed">1</view>
|
||||||
|
<view class="need-btn {{teamForm.need_count == 2 ? 'on' : ''}}" data-n="2" bindtap="setTeamNeed">2</view>
|
||||||
|
<view class="need-btn {{teamForm.need_count == 3 ? 'on' : ''}}" data-n="3" bindtap="setTeamNeed">3</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tf-row">
|
||||||
|
<text class="tf-label">分钱方式</text>
|
||||||
|
<view class="tf-need">
|
||||||
|
<view class="need-btn {{teamForm.share_mode == 'fixed' ? 'on' : ''}}" data-m="fixed" bindtap="setTeamMode">固定值</view>
|
||||||
|
<view class="need-btn {{teamForm.share_mode == 'average' ? 'on' : ''}}" data-m="average" bindtap="setTeamMode">平均值</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tf-row" wx:if="{{teamForm.share_mode == 'fixed'}}">
|
||||||
|
<text class="tf-label">人均金额(元)</text>
|
||||||
|
<input class="tf-input" type="digit" placeholder="队友每人" value="{{teamForm.per_person_amount}}" bindinput="onTeamPerPerson" />
|
||||||
|
</view>
|
||||||
|
<view class="tf-row">
|
||||||
|
<text class="tf-label">队长游戏ID</text>
|
||||||
|
<input class="tf-input" placeholder="必填,队内可见" value="{{teamForm.leader_game_id}}" bindinput="onTeamGameId" maxlength="64" />
|
||||||
|
</view>
|
||||||
|
<view class="tf-row">
|
||||||
|
<text class="tf-label">组队备注(可选)</text>
|
||||||
|
<input class="tf-input" placeholder="大厅可见" value="{{teamForm.remark}}" bindinput="onTeamRemark" maxlength="200" />
|
||||||
|
</view>
|
||||||
|
<view class="tf-actions">
|
||||||
|
<view class="team-open-btn" bindtap="submitOpenTeam">{{teamSubmitting ? '提交中...' : '确认开启'}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<global-notification id="global-notification" />
|
<global-notification id="global-notification" />
|
||||||
<popup-notice id="popupNotice" />
|
<popup-notice id="popupNotice" />
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -2,6 +2,16 @@ const app = getApp();
|
|||||||
import { createPage, request } from '../../utils/base-page.js';
|
import { createPage, request } from '../../utils/base-page.js';
|
||||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||||
import { getOrderStatusText } from '../../utils/api-helper.js';
|
import { getOrderStatusText } from '../../utils/api-helper.js';
|
||||||
|
import {
|
||||||
|
attachAutoSettleFields,
|
||||||
|
buildAutoSettleDisplay,
|
||||||
|
startAutoSettleTicker,
|
||||||
|
stopAutoSettleTicker,
|
||||||
|
} from '../../utils/auto-settle-display.js';
|
||||||
|
import { sanitizeMyDealStat, DEAL_STAT_HELP } from '../../utils/deal-stat-display.js';
|
||||||
|
import { consumeBadgeFields } from '../../utils/dashou-badges.js';
|
||||||
|
import { isFighterOnly, canEnterAcceptOrder, getLoginPageUrl } from '../../utils/fighter-only.js';
|
||||||
|
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
||||||
|
|
||||||
Page(createPage({
|
Page(createPage({
|
||||||
data: {
|
data: {
|
||||||
@@ -9,7 +19,7 @@ Page(createPage({
|
|||||||
shangpinleixing: [],
|
shangpinleixing: [],
|
||||||
xuanzhongLeixingId: null,
|
xuanzhongLeixingId: null,
|
||||||
|
|
||||||
// 订单类型: normal 普通, peihu 陪护
|
// 订单类型固定普通;旧陪护入口已下线(与组队无关)
|
||||||
orderType: 'normal',
|
orderType: 'normal',
|
||||||
|
|
||||||
// 搜索关键字
|
// 搜索关键字
|
||||||
@@ -19,11 +29,12 @@ Page(createPage({
|
|||||||
statusList: [
|
statusList: [
|
||||||
{ name: '全部', key: 'all', zhuangtaiList: [], color: '#333333' },
|
{ name: '全部', key: 'all', zhuangtaiList: [], color: '#333333' },
|
||||||
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
|
{ 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: 'yituikuan', zhuangtaiList: [5], color: '#9E9E9E' },
|
||||||
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
|
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
|
||||||
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
|
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
|
||||||
{ name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' }
|
{ name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' },
|
||||||
|
{ name: '待自动结算', key: 'dai_zidong_jiesuan', zhuangtaiList: [8], color: '#C62828', autoSettlePending: true },
|
||||||
],
|
],
|
||||||
currentStatusKey: 'all',
|
currentStatusKey: 'all',
|
||||||
|
|
||||||
@@ -35,7 +46,8 @@ Page(createPage({
|
|||||||
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||||
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||||
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||||
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
|
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||||
|
dai_zidong_jiesuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
currentList: [],
|
currentList: [],
|
||||||
@@ -45,22 +57,62 @@ Page(createPage({
|
|||||||
scrollViewRefreshing: false,
|
scrollViewRefreshing: false,
|
||||||
defaultImg: '/images/default-order.png',
|
defaultImg: '/images/default-order.png',
|
||||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||||
|
dealStat: null,
|
||||||
|
dealStatChips: [],
|
||||||
|
showDealStatHelp: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
if (isFighterOnly() && !canEnterAcceptOrder()) {
|
||||||
|
wx.reLaunch({ url: getLoginPageUrl() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
wx.setNavigationBarTitle({ title: '我的接单' });
|
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();
|
this.registerNotificationComponent();
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
async onShow() {
|
||||||
|
if (isFighterOnly() && !canEnterAcceptOrder()) {
|
||||||
|
wx.reLaunch({ url: getLoginPageUrl() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
|
||||||
|
if (!phoneOk) return;
|
||||||
|
|
||||||
this.registerNotificationComponent();
|
this.registerNotificationComponent();
|
||||||
|
this.loadDealStat();
|
||||||
|
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')) {
|
if (wx.getStorageSync('uid')) {
|
||||||
reconnectForRole('dashou');
|
reconnectForRole('dashou');
|
||||||
if (app.startImWhenReady) app.startImWhenReady();
|
if (app.startImWhenReady) app.startImWhenReady();
|
||||||
}
|
}
|
||||||
if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
|
if (this._skipShowRefresh) {
|
||||||
this.loadCurrentStatusOrders(true);
|
this._skipShowRefresh = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._ordersSessionReady && this.data.xuanzhongLeixingId && !this._silentRefreshRunning) {
|
||||||
|
this._silentRefreshRunning = true;
|
||||||
|
this.loadCurrentStatusOrders(true, true).finally(() => {
|
||||||
|
this._silentRefreshRunning = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -102,9 +154,11 @@ Page(createPage({
|
|||||||
},
|
},
|
||||||
|
|
||||||
switchOrderType(e) {
|
switchOrderType(e) {
|
||||||
|
// 陪护入口已隐藏;保留方法避免旧事件残留报错
|
||||||
const type = e.currentTarget.dataset.type;
|
const type = e.currentTarget.dataset.type;
|
||||||
|
if (type !== 'normal') return;
|
||||||
if (type === this.data.orderType) return;
|
if (type === this.data.orderType) return;
|
||||||
this.setData({ orderType: type });
|
this.setData({ orderType: 'normal' });
|
||||||
this.resetCurrentStatusData();
|
this.resetCurrentStatusData();
|
||||||
this.loadCurrentStatusOrders(true);
|
this.loadCurrentStatusOrders(true);
|
||||||
},
|
},
|
||||||
@@ -128,6 +182,35 @@ Page(createPage({
|
|||||||
this.loadCurrentStatusOrders(true);
|
this.loadCurrentStatusOrders(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async loadDealStat() {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/dingdan/wo-de-deal-stat',
|
||||||
|
method: 'POST',
|
||||||
|
data: { role: 'dashou' },
|
||||||
|
header: { 'content-type': 'application/json' },
|
||||||
|
});
|
||||||
|
if (res.data && (res.data.code === 0 || res.data.code === 200)) {
|
||||||
|
const cleaned = sanitizeMyDealStat(res.data.data, 'dashou');
|
||||||
|
this.setData({
|
||||||
|
dealStat: cleaned,
|
||||||
|
dealStatChips: (cleaned && cleaned.chips) || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
/* 无样本静默 */
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onDealStatHelpTap() {
|
||||||
|
wx.showModal({
|
||||||
|
title: '指标说明',
|
||||||
|
content: DEAL_STAT_HELP.dashou,
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '知道了',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
switchStatus(e) {
|
switchStatus(e) {
|
||||||
const key = e.currentTarget.dataset.key;
|
const key = e.currentTarget.dataset.key;
|
||||||
if (key === this.data.currentStatusKey) return;
|
if (key === this.data.currentStatusKey) return;
|
||||||
@@ -141,17 +224,21 @@ Page(createPage({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 加载订单(核心)
|
// 加载订单(核心)
|
||||||
async loadCurrentStatusOrders(isRefresh = false) {
|
async loadCurrentStatusOrders(isRefresh = false, silent = false) {
|
||||||
const key = this.data.currentStatusKey;
|
const key = this.data.currentStatusKey;
|
||||||
const tabData = this.data.dsDingdanShuju[key];
|
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;
|
const page = isRefresh ? 1 : tabData.page;
|
||||||
|
|
||||||
this.setData({
|
if (!silent) {
|
||||||
[`dsDingdanShuju.${key}.isLoading`]: true,
|
this.setData({
|
||||||
isLoading: true,
|
[`dsDingdanShuju.${key}.isLoading`]: true,
|
||||||
isLoadingMore: !isRefresh
|
isLoading: true,
|
||||||
});
|
isLoadingMore: !isRefresh,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._listRequesting = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiUrl = this.data.orderType === 'peihu'
|
const apiUrl = this.data.orderType === 'peihu'
|
||||||
@@ -167,6 +254,9 @@ Page(createPage({
|
|||||||
leixing_id: this.data.xuanzhongLeixingId,
|
leixing_id: this.data.xuanzhongLeixingId,
|
||||||
keyword: this.data.searchKeyword || undefined
|
keyword: this.data.searchKeyword || undefined
|
||||||
};
|
};
|
||||||
|
if (statusItem && statusItem.autoSettlePending) {
|
||||||
|
params.auto_settle_pending = 1;
|
||||||
|
}
|
||||||
|
|
||||||
const res = await request({
|
const res = await request({
|
||||||
url: apiUrl,
|
url: apiUrl,
|
||||||
@@ -177,11 +267,13 @@ Page(createPage({
|
|||||||
|
|
||||||
const code = res.data.code;
|
const code = res.data.code;
|
||||||
if (code === 200 || code === 0) {
|
if (code === 200 || code === 0) {
|
||||||
const newList = res.data.data.list || [];
|
const payload = res.data.data || {};
|
||||||
const hasMore = res.data.data.has_more || false;
|
consumeBadgeFields(payload);
|
||||||
|
const newList = payload.list || [];
|
||||||
|
const hasMore = payload.has_more || false;
|
||||||
|
|
||||||
// ✅ 图片URL拼接(核心)
|
// ✅ 图片URL拼接(核心)
|
||||||
const processed = newList.map(item => ({
|
const processed = newList.map(item => attachAutoSettleFields({
|
||||||
...item,
|
...item,
|
||||||
zhuangtaiZh: getOrderStatusText(item.zhuangtai),
|
zhuangtaiZh: getOrderStatusText(item.zhuangtai),
|
||||||
zhuangtaiColor: statusItem.color,
|
zhuangtaiColor: statusItem.color,
|
||||||
@@ -208,14 +300,20 @@ Page(createPage({
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载订单失败', err);
|
console.error('加载订单失败', err);
|
||||||
wx.showToast({ title: err.message || '加载失败', icon: 'none' });
|
if (!silent) {
|
||||||
this.setData({
|
wx.showToast({ title: err.message || '加载失败', icon: 'none' });
|
||||||
[`dsDingdanShuju.${key}.isLoading`]: false,
|
}
|
||||||
isLoading: false,
|
if (!silent) {
|
||||||
isLoadingMore: false,
|
this.setData({
|
||||||
scrollViewRefreshing: false
|
[`dsDingdanShuju.${key}.isLoading`]: false,
|
||||||
});
|
isLoading: false,
|
||||||
this.refreshCurrentListView();
|
isLoadingMore: false,
|
||||||
|
scrollViewRefreshing: false
|
||||||
|
});
|
||||||
|
this.refreshCurrentListView();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this._listRequesting = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -227,6 +325,53 @@ Page(createPage({
|
|||||||
hasMore: tabData.hasMore,
|
hasMore: tabData.hasMore,
|
||||||
isLoading: tabData.isLoading
|
isLoading: tabData.isLoading
|
||||||
});
|
});
|
||||||
|
this.syncAutoSettleListTicker();
|
||||||
|
},
|
||||||
|
|
||||||
|
syncAutoSettleListTicker() {
|
||||||
|
const key = this.data.currentStatusKey;
|
||||||
|
const has = (this.data.currentList || []).some((it) => it && it.auto_settle_eligible);
|
||||||
|
if (!has) {
|
||||||
|
stopAutoSettleTicker(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startAutoSettleTicker(this, {
|
||||||
|
onTick: () => {
|
||||||
|
const k = this.data.currentStatusKey;
|
||||||
|
const list = this.data.currentList || [];
|
||||||
|
const now = Date.now();
|
||||||
|
let changed = false;
|
||||||
|
const next = list.map((it) => {
|
||||||
|
if (!it || !it.auto_settle_eligible) return it;
|
||||||
|
const disp = buildAutoSettleDisplay(it, now);
|
||||||
|
if (!disp) {
|
||||||
|
if (it.autoSettleClock || it.autoSettleTip) {
|
||||||
|
changed = true;
|
||||||
|
return { ...it, autoSettleTip: '', autoSettleClock: '', autoSettleRemainText: '' };
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
if (it.autoSettleClock !== disp.clockText || it.autoSettleTip !== disp.tip) {
|
||||||
|
changed = true;
|
||||||
|
return {
|
||||||
|
...it,
|
||||||
|
autoSettleTip: disp.tip,
|
||||||
|
autoSettleExpireAt: disp.expireAt,
|
||||||
|
autoSettleRemainText: disp.remainText,
|
||||||
|
autoSettleClock: disp.clockText,
|
||||||
|
autoSettleRemainSeconds: disp.remainSeconds,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
this.setData({
|
||||||
|
currentList: next,
|
||||||
|
[`dsDingdanShuju.${k}.list`]: next,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
resetCurrentStatusData() {
|
resetCurrentStatusData() {
|
||||||
@@ -285,5 +430,13 @@ Page(createPage({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onImageError() {}
|
onImageError() {},
|
||||||
|
|
||||||
|
onHide() {
|
||||||
|
stopAutoSettleTicker(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
stopAutoSettleTicker(this);
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"usingComponents": {
|
"usingComponents": {
|
||||||
"global-notification": "/components/global-notification/global-notification"
|
"global-notification": "/components/global-notification/global-notification",
|
||||||
|
"tab-bar": "/tab-bar/index"
|
||||||
},
|
},
|
||||||
"navigationBarTitleText": "我的接单",
|
"navigationBarTitleText": "我的接单",
|
||||||
"enablePullDownRefresh": false,
|
"enablePullDownRefresh": false,
|
||||||
|
|||||||
@@ -17,19 +17,21 @@
|
|||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 筛选行 -->
|
<!-- 筛选行:组队已独立 Tab;旧「陪护订单」半成品入口已隐藏 -->
|
||||||
<view class="filter-row">
|
<view class="filter-row">
|
||||||
<view class="type-switch">
|
<view class="search-box search-box-full">
|
||||||
<view class="type-btn {{orderType == 'normal' ? 'type-active' : ''}}" data-type="normal" bindtap="switchOrderType">普通订单</view>
|
|
||||||
<view class="type-btn {{orderType == 'peihu' ? 'type-active' : ''}}" data-type="peihu" bindtap="switchOrderType">陪护订单</view>
|
|
||||||
</view>
|
|
||||||
<view class="search-box">
|
|
||||||
<image class="search-icon" src="/images/icon_search.svg" mode="aspectFit"/>
|
<image class="search-icon" src="/images/icon_search.svg" mode="aspectFit"/>
|
||||||
<input class="search-input" placeholder="搜索订单ID/介绍" value="{{searchKeyword}}" bindinput="onSearchInput" bindconfirm="onSearchConfirm" confirm-type="search"/>
|
<input class="search-input" placeholder="搜索订单ID/介绍" value="{{searchKeyword}}" bindinput="onSearchInput" bindconfirm="onSearchConfirm" confirm-type="search"/>
|
||||||
<view class="search-clear" wx:if="{{searchKeyword}}" bindtap="clearSearch"><text>✕</text></view>
|
<view class="search-clear" wx:if="{{searchKeyword}}" bindtap="clearSearch"><text>✕</text></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 结算率 / 罚款率(有样本才展示) -->
|
||||||
|
<view class="deal-stat-bar" wx:if="{{dealStat}}">
|
||||||
|
<text class="deal-stat-item" wx:if="{{dealStat.deal_rate_text}}">结算率 {{dealStat.deal_rate_text}}</text>
|
||||||
|
<text class="deal-stat-item" wx:if="{{dealStat.fined_rate_text}}">被罚款率 {{dealStat.fined_rate_text}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 主体:左右布局 -->
|
<!-- 主体:左右布局 -->
|
||||||
<view class="main-container">
|
<view class="main-container">
|
||||||
<!-- 左侧状态栏(固定) -->
|
<!-- 左侧状态栏(固定) -->
|
||||||
@@ -77,8 +79,15 @@
|
|||||||
<view class="order-card" data-item="{{item}}" bindtap="goToDsDingdanXiangqing">
|
<view class="order-card" data-item="{{item}}" bindtap="goToDsDingdanXiangqing">
|
||||||
<image class="card-img" src="{{item.tupian}}" mode="aspectFill" binderror="onImageError"/>
|
<image class="card-img" src="{{item.tupian}}" mode="aspectFill" binderror="onImageError"/>
|
||||||
<view class="card-info">
|
<view class="card-info">
|
||||||
<view class="card-title">{{item.jieshao || '暂无描述'}}</view>
|
<view class="card-title-row">
|
||||||
|
<text class="card-title">{{item.jieshao || '暂无描述'}}</text>
|
||||||
|
<text class="team-badge" wx:if="{{item.has_team}}">组队</text>
|
||||||
|
</view>
|
||||||
<view class="card-id" wx:if="{{item.dingdan_id}}">ID: {{item.dingdan_id}}</view>
|
<view class="card-id" wx:if="{{item.dingdan_id}}">ID: {{item.dingdan_id}}</view>
|
||||||
|
<view class="card-team-meta" wx:if="{{item.has_team}}">
|
||||||
|
{{item.team_role_text || '组队'}} · {{item.team_status_text}} · {{item.team_joined}}/{{item.team_need}}人
|
||||||
|
</view>
|
||||||
|
<view class="card-auto-settle" wx:if="{{item.autoSettleTip}}">{{item.autoSettleTip}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-right">
|
<view class="card-right">
|
||||||
<view class="card-status" style="color: {{item.zhuangtaiColor}};">{{item.zhuangtaiZh}}</view>
|
<view class="card-status" style="color: {{item.zhuangtaiColor}};">{{item.zhuangtaiZh}}</view>
|
||||||
|
|||||||
@@ -9,6 +9,30 @@ page {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: #f5f6fa;
|
background: #f5f6fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.deal-stat-bar {
|
||||||
|
margin: 12rpx 24rpx;
|
||||||
|
padding: 14rpx 20rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.deal-stat-item {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #37474f;
|
||||||
|
background: #eceff1;
|
||||||
|
padding: 4rpx 14rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
.card-auto-settle {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #c62828;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
/* 商品类型区 */
|
/* 商品类型区 */
|
||||||
.leixing-area {
|
.leixing-area {
|
||||||
@@ -92,6 +116,10 @@ page {
|
|||||||
padding: 0 20rpx;
|
padding: 0 20rpx;
|
||||||
height: 68rpx;
|
height: 68rpx;
|
||||||
}
|
}
|
||||||
|
.search-box-full {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
.search-icon {
|
.search-icon {
|
||||||
width: 32rpx;
|
width: 32rpx;
|
||||||
height: 32rpx;
|
height: 32rpx;
|
||||||
@@ -224,6 +252,28 @@ page {
|
|||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.card-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
.team-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #1f8a7c;
|
||||||
|
background: rgba(31, 138, 124, 0.12);
|
||||||
|
padding: 2rpx 10rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.card-team-meta {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #1f8a7c;
|
||||||
|
margin-top: 6rpx;
|
||||||
}
|
}
|
||||||
.card-id {
|
.card-id {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
@@ -346,4 +396,5 @@ page {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import '../../styles/dashou-xym-orders-theme.wxss';
|
@import '../../styles/dashou-xym-orders-theme.wxss';
|
||||||
|
@import '../../styles/dashou-xym-orders-page.wxss';
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# 排行榜页 UI 改造备份
|
||||||
|
|
||||||
|
备份时间:2026-07-06
|
||||||
|
|
||||||
|
## 备份文件
|
||||||
|
|
||||||
|
- `fighter-rank.wxml` / `fighter-rank.wxss` / `fighter-rank.js` / `fighter-rank.json`
|
||||||
|
|
||||||
|
## 改造说明
|
||||||
|
|
||||||
|
- 视觉对齐参考图:黄色顶栏、白底 Tab、领奖台、4 名以后列表
|
||||||
|
- **接口与 JS 业务逻辑不变**(仅 DATE_LIST 展示顺序、Tab 文案微调)
|
||||||
|
|
||||||
|
## 回滚
|
||||||
|
|
||||||
|
将本目录内四个文件覆盖回 `pages/fighter-rank/` 即可。
|
||||||
@@ -0,0 +1,477 @@
|
|||||||
|
/**
|
||||||
|
* 排行榜
|
||||||
|
* 默认 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 ROLE_LIST = [
|
||||||
|
{ 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: '上月' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const ROLE_META = {
|
||||||
|
dashou: {
|
||||||
|
title: '接单员排行榜',
|
||||||
|
sortField: 'chengjiao_zonge',
|
||||||
|
sortLabel: '分红总额',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'jiedan_zongliang', label: '接单量', type: 'int' },
|
||||||
|
{ field: 'jiedan_zonge', label: '接单额', type: 'money' },
|
||||||
|
{ field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
guanshi: {
|
||||||
|
title: '管事排行榜',
|
||||||
|
sortField: 'shouru_zonge',
|
||||||
|
sortLabel: '收入总额',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' },
|
||||||
|
{ field: 'chongzhi_dashou_shu', label: '充值', type: 'int' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
zuzhang: {
|
||||||
|
title: '组长排行榜',
|
||||||
|
sortField: 'shouru_zonge',
|
||||||
|
sortLabel: '收入总额',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' },
|
||||||
|
{ field: 'fenyong_jine', label: '分佣', type: 'money' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
shangjia: {
|
||||||
|
title: '商家排行榜',
|
||||||
|
sortField: 'jiesuan_jine',
|
||||||
|
sortLabel: '成交总额',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' },
|
||||||
|
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
|
||||||
|
{ field: 'paifa_jine', label: '派单额', type: 'money' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 星之界专用展示与排序字段 */
|
||||||
|
const XZJ_ROLE_META = {
|
||||||
|
dashou: {
|
||||||
|
title: '接单员排行榜',
|
||||||
|
sortField: 'chengjiao_zonge',
|
||||||
|
sortLabel: '成交金额',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'jiedan_zongliang', label: '接单量', type: 'int' },
|
||||||
|
{ field: 'jiedan_zonge', label: '接单额', type: 'money' },
|
||||||
|
{ field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
guanshi: {
|
||||||
|
title: '管事排行榜',
|
||||||
|
sortField: 'yaoqing_dashou_shu',
|
||||||
|
sortLabel: '邀请人数',
|
||||||
|
mainType: 'int',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'wuxiao_yaoqing_dashou_shu', label: '无效邀请', type: 'int' },
|
||||||
|
{ field: 'chongzhi_dashou_shu', label: '有效人数', type: 'int' },
|
||||||
|
{ field: 'shouru_zonge', label: '收入金额', type: 'money' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
zuzhang: {
|
||||||
|
title: '组长排行榜',
|
||||||
|
sortField: 'yaoqing_guanshi_shu',
|
||||||
|
sortLabel: '邀请人数',
|
||||||
|
mainType: 'int',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'wuxiao_yaoqing_guanshi_shu', label: '无效邀请', type: 'int' },
|
||||||
|
{ field: 'youxiao_guanshi_shu', label: '有效人数', type: 'int' },
|
||||||
|
{ field: 'shouru_zonge', label: '收入金额', type: 'money' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
shangjia: {
|
||||||
|
title: '商家排行榜',
|
||||||
|
sortField: 'paifa_jine',
|
||||||
|
sortLabel: '派单流水',
|
||||||
|
mainType: 'money',
|
||||||
|
metrics: [
|
||||||
|
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
|
||||||
|
{ field: 'paifa_jine', label: '派单流水', type: 'money' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const ACTIVE_ROLE_META = IS_XZJ ? XZJ_ROLE_META : ROLE_META
|
||||||
|
|
||||||
|
function isInvalidAvatarPath(path) {
|
||||||
|
if (path === null || path === undefined) return true
|
||||||
|
if (typeof path !== 'string') return true
|
||||||
|
const s = path.trim()
|
||||||
|
return !s || s === 'null' || s === 'undefined' || s === 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultAvatar(app) {
|
||||||
|
return getDefaultAvatarUrl(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAvatar(path, app) {
|
||||||
|
app = app || getApp()
|
||||||
|
if (isInvalidAvatarPath(path)) return getDefaultAvatar(app)
|
||||||
|
return resolveAvatarUrl(path, app) || getDefaultAvatar(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
imgUrls: {},
|
||||||
|
roleList: ROLE_LIST,
|
||||||
|
dateList: DATE_LIST,
|
||||||
|
currentRole: 'dashou',
|
||||||
|
currentDate: '今日',
|
||||||
|
fanwei: 'jituan',
|
||||||
|
myClubId: CLUB_ID || 'xq',
|
||||||
|
roleMeta: ROLE_META.dashou,
|
||||||
|
sortLabel: '分红总额',
|
||||||
|
isLoading: true,
|
||||||
|
rankList: [],
|
||||||
|
topThree: [],
|
||||||
|
restList: [],
|
||||||
|
isEmpty: false,
|
||||||
|
defaultAvatar: '',
|
||||||
|
rewardInfo: null,
|
||||||
|
showClaimBar: false,
|
||||||
|
claimLoading: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(options) {
|
||||||
|
const type = options.type || options.rankType || 'dashou'
|
||||||
|
const validRole = ACTIVE_ROLE_META[type] ? type : 'dashou'
|
||||||
|
this.initPage()
|
||||||
|
this.applyRole(validRole, false)
|
||||||
|
this.fetchRankList()
|
||||||
|
},
|
||||||
|
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.fetchRankList().finally(() => wx.stopPullDownRefresh())
|
||||||
|
},
|
||||||
|
|
||||||
|
initPage() {
|
||||||
|
this.syncDefaultAvatar()
|
||||||
|
const g = getApp().globalData
|
||||||
|
const base = (g.ossImageUrl || '') + 'beijing/paihangbang/'
|
||||||
|
this.setData({
|
||||||
|
imgUrls: {
|
||||||
|
pageBg: base + 'page-bg.jpg',
|
||||||
|
cardBg: base + 'list-card-bg.png',
|
||||||
|
emptyIcon: base + 'empty.png',
|
||||||
|
refreshIcon: base + 'icon-refresh.png',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 与 app.js 一致:ossImageUrl + morentouxiang,配置异步加载后 onShow 再同步 */
|
||||||
|
syncDefaultAvatar() {
|
||||||
|
const def = getDefaultAvatar()
|
||||||
|
if (def && def !== this.data.defaultAvatar) {
|
||||||
|
this.setData({ defaultAvatar: def })
|
||||||
|
} else if (!this.data.defaultAvatar && def) {
|
||||||
|
this.setData({ defaultAvatar: def })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 配置晚于页面加载时,补全空头像 */
|
||||||
|
ensureAvatars() {
|
||||||
|
const def = getDefaultAvatar()
|
||||||
|
if (!def) return
|
||||||
|
const g = getApp().globalData
|
||||||
|
const oss = g.ossImageUrl || ''
|
||||||
|
const { rankList, topThree, restList } = this.data
|
||||||
|
if (!rankList.length) {
|
||||||
|
if (def !== this.data.defaultAvatar) this.setData({ defaultAvatar: def })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const isValidUrl = (url) => {
|
||||||
|
if (!url || typeof url !== 'string') return false
|
||||||
|
if (url.startsWith('http://') || url.startsWith('https://')) return true
|
||||||
|
return !!(oss && url.indexOf(oss) === 0)
|
||||||
|
}
|
||||||
|
const fix = (item) => ({
|
||||||
|
...item,
|
||||||
|
avatar: isValidUrl(item.avatar) ? item.avatar : def,
|
||||||
|
})
|
||||||
|
this.setData({
|
||||||
|
defaultAvatar: def,
|
||||||
|
rankList: rankList.map(fix),
|
||||||
|
topThree: topThree.map(fix),
|
||||||
|
restList: restList.map(fix),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
applyRole(role, reload = true) {
|
||||||
|
const meta = ACTIVE_ROLE_META[role]
|
||||||
|
wx.setNavigationBarTitle({ title: meta.title })
|
||||||
|
this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel })
|
||||||
|
if (reload) this.fetchRankList()
|
||||||
|
},
|
||||||
|
|
||||||
|
onRoleTap(e) {
|
||||||
|
const role = e.currentTarget.dataset.role
|
||||||
|
if (!role || role === this.data.currentRole) return
|
||||||
|
this.applyRole(role)
|
||||||
|
},
|
||||||
|
|
||||||
|
onDateTap(e) {
|
||||||
|
const date = e.currentTarget.dataset.date
|
||||||
|
if (!date || date === this.data.currentDate) return
|
||||||
|
this.setData({ currentDate: date })
|
||||||
|
this.fetchRankList()
|
||||||
|
},
|
||||||
|
|
||||||
|
onScopeTap(e) {
|
||||||
|
const fanwei = e.currentTarget.dataset.fanwei
|
||||||
|
if (!fanwei || fanwei === this.data.fanwei) return
|
||||||
|
this.setData({ fanwei })
|
||||||
|
this.fetchRankList()
|
||||||
|
},
|
||||||
|
|
||||||
|
onShowRules() {
|
||||||
|
const r = this.data.rewardInfo
|
||||||
|
if (!r || !r.tiers || !r.tiers.length) {
|
||||||
|
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 tip = r.period_status === 'open' ? '(本期进行中,结束后可领取)' : ''
|
||||||
|
wx.showModal({
|
||||||
|
title: `${r.title || '排行榜奖励'}${tip}`,
|
||||||
|
content: [
|
||||||
|
`俱乐部:${r.club_id || this.data.myClubId}`,
|
||||||
|
`排序:${r.sort_label || ''}`,
|
||||||
|
...lines,
|
||||||
|
r.description || '',
|
||||||
|
].filter(Boolean).join('\n'),
|
||||||
|
showCancel: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async onClaimTap() {
|
||||||
|
const claim = this.data.rewardInfo && this.data.rewardInfo.my_claim
|
||||||
|
if (!claim || !claim.claim_id || this.data.claimLoading) return
|
||||||
|
this.setData({ claimLoading: true })
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/yonghu/phbjllq',
|
||||||
|
method: 'POST',
|
||||||
|
data: { claim_id: claim.claim_id },
|
||||||
|
})
|
||||||
|
const body = res?.data || {}
|
||||||
|
if (body.code === 200) {
|
||||||
|
wx.showToast({ title: `已领取 ¥${claim.amount}`, icon: 'success' })
|
||||||
|
await this.fetchRewardInfo()
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: body.msg || '领取失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
wx.showToast({ title: '领取失败', icon: 'none' })
|
||||||
|
} finally {
|
||||||
|
this.setData({ claimLoading: false })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onRefreshTap() {
|
||||||
|
this.fetchRankList()
|
||||||
|
},
|
||||||
|
|
||||||
|
formatMoney(val) {
|
||||||
|
const n = parseFloat(val)
|
||||||
|
return Number.isNaN(n) ? '0.00' : n.toFixed(2)
|
||||||
|
},
|
||||||
|
|
||||||
|
formatInt(val) {
|
||||||
|
const n = parseInt(val, 10)
|
||||||
|
return Number.isNaN(n) ? '0' : String(n)
|
||||||
|
},
|
||||||
|
|
||||||
|
normalizeItem(raw, index, role) {
|
||||||
|
const meta = ACTIVE_ROLE_META[role]
|
||||||
|
const app = getApp()
|
||||||
|
const uid = raw.yonghuid || raw.uid || ''
|
||||||
|
const nicheng = raw.nicheng || raw.nick || '用户'
|
||||||
|
const def = getDefaultAvatar(app)
|
||||||
|
const avatar = buildAvatar(raw.touxiang || raw.avatar, app) || def
|
||||||
|
const metrics = meta.metrics.map((m) => {
|
||||||
|
const v = raw[m.field]
|
||||||
|
return {
|
||||||
|
label: m.label,
|
||||||
|
value: m.type === 'money' ? this.formatMoney(v) : this.formatInt(v),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const sortRaw = raw[meta.sortField] ?? raw.metric_value
|
||||||
|
const mainType = raw.metric_label ? (Number.isInteger(Number(sortRaw)) && !String(sortRaw).includes('.') ? 'int' : 'money') : (meta.mainType || 'money')
|
||||||
|
const mainValue = mainType === 'money'
|
||||||
|
? this.formatMoney(sortRaw)
|
||||||
|
: this.formatInt(sortRaw)
|
||||||
|
return {
|
||||||
|
mingci: raw.mingci || index + 1,
|
||||||
|
uid,
|
||||||
|
nicheng,
|
||||||
|
avatar,
|
||||||
|
clubName: raw.club_name || raw.club_id || '',
|
||||||
|
rewardAmount: raw.reward_amount || 0,
|
||||||
|
mainType,
|
||||||
|
mainPrefix: mainType === 'money' ? '¥' : '',
|
||||||
|
mainValue,
|
||||||
|
mainLabel: raw.metric_label || meta.sortLabel,
|
||||||
|
metrics,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
applyRewardToList(list, rewardInfo, fanwei) {
|
||||||
|
if (fanwei !== 'club') return list
|
||||||
|
if (!rewardInfo || !rewardInfo.rank_rewards) return list
|
||||||
|
const map = rewardInfo.rank_rewards
|
||||||
|
return list.map((item) => ({
|
||||||
|
...item,
|
||||||
|
rewardAmount: map[item.mingci] || item.rewardAmount || 0,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchRewardInfo() {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/yonghu/phbjlxx',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
shenfen: this.data.currentRole,
|
||||||
|
riqi: this.data.currentDate,
|
||||||
|
club_id: this.data.myClubId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const body = res?.data || {}
|
||||||
|
if (body.code !== 200 || !body.data) return
|
||||||
|
const rewardInfo = body.data
|
||||||
|
const showClaimBar = !!(rewardInfo.my_claim && rewardInfo.my_claim.status === 'pending')
|
||||||
|
const { rankList, fanwei } = this.data
|
||||||
|
const merged = this.applyRewardToList(rankList, rewardInfo, fanwei)
|
||||||
|
this.setData({
|
||||||
|
rewardInfo,
|
||||||
|
showClaimBar,
|
||||||
|
rankList: merged,
|
||||||
|
topThree: merged.slice(0, 3),
|
||||||
|
restList: merged.slice(3),
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('奖励信息加载失败', e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchRankList() {
|
||||||
|
this.setData({ isLoading: true, isEmpty: false, showClaimBar: false })
|
||||||
|
try {
|
||||||
|
const { currentRole, currentDate, fanwei, myClubId } = this.data
|
||||||
|
let list = []
|
||||||
|
let rewardFromRank = null
|
||||||
|
|
||||||
|
if (fanwei === 'club') {
|
||||||
|
const res = await request({
|
||||||
|
url: '/yonghu/phbjlphb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
shenfen: currentRole,
|
||||||
|
riqi: currentDate,
|
||||||
|
fanwei: 'club',
|
||||||
|
club_id: myClubId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const body = res?.data || {}
|
||||||
|
if (body.code === 200 && body.data) {
|
||||||
|
list = body.data.list || []
|
||||||
|
rewardFromRank = body.data.reward || null
|
||||||
|
if (body.data.sort_label) {
|
||||||
|
this.setData({ sortLabel: body.data.sort_label })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const res = await request({
|
||||||
|
url: RANK_API,
|
||||||
|
method: 'POST',
|
||||||
|
data: { shenfen: currentRole, riqi: currentDate },
|
||||||
|
})
|
||||||
|
const body = res?.data || {}
|
||||||
|
const ok = body.code === 200 || body.code === 0
|
||||||
|
list = ok && body.data
|
||||||
|
? (body.data.list || body.data.paihang_list || body.data.rank_list || [])
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(list)) list = []
|
||||||
|
const role = currentRole
|
||||||
|
let normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
||||||
|
if (rewardFromRank) {
|
||||||
|
normalized = this.applyRewardToList(normalized, rewardFromRank, 'club')
|
||||||
|
this.setData({ rewardInfo: rewardFromRank, showClaimBar: !!(rewardFromRank.my_claim && rewardFromRank.my_claim.status === 'pending') })
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
rankList: normalized,
|
||||||
|
topThree: normalized.slice(0, 3),
|
||||||
|
restList: normalized.slice(3),
|
||||||
|
isEmpty: normalized.length === 0,
|
||||||
|
isLoading: false,
|
||||||
|
})
|
||||||
|
this.ensureAvatars()
|
||||||
|
if (!rewardFromRank) {
|
||||||
|
await this.fetchRewardInfo()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('排行榜加载失败', e)
|
||||||
|
wx.showToast({ title: '加载失败', icon: 'none' })
|
||||||
|
this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onAvatarError(e) {
|
||||||
|
const { zone, index } = e.currentTarget.dataset
|
||||||
|
const fallback = getDefaultAvatar()
|
||||||
|
if (!fallback) return
|
||||||
|
const key = zone === 'top' ? `topThree[${index}].avatar` : `restList[${index}].avatar`
|
||||||
|
this.setData({ [key]: fallback })
|
||||||
|
},
|
||||||
|
|
||||||
|
registerNotificationComponent() {
|
||||||
|
const app = getApp()
|
||||||
|
const comp = this.selectComponent('#global-notification')
|
||||||
|
if (comp?.showNotification) {
|
||||||
|
app.globalData.globalNotification = {
|
||||||
|
show: (d) => comp.showNotification(d),
|
||||||
|
hide: () => comp.hideNotification(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
this.syncDefaultAvatar()
|
||||||
|
this.ensureAvatars()
|
||||||
|
this.registerNotificationComponent()
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"global-notification": "/components/global-notification/global-notification"
|
||||||
|
},
|
||||||
|
"navigationBarTitleText": "排行榜",
|
||||||
|
"navigationBarBackgroundColor": "#0d1117",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"enablePullDownRefresh": true,
|
||||||
|
"backgroundColor": "#0d1117",
|
||||||
|
"backgroundTextStyle": "light"
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
<view class="rank-page">
|
||||||
|
<image class="page-bg" src="{{imgUrls.pageBg}}" mode="aspectFill" />
|
||||||
|
|
||||||
|
<view class="top-bar">
|
||||||
|
<view class="top-row">
|
||||||
|
<text class="page-title">{{roleMeta.title}}</text>
|
||||||
|
<view class="refresh-wrap" bindtap="onRefreshTap">
|
||||||
|
<image class="refresh-ico" src="{{imgUrls.refreshIcon}}" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-x class="role-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
<view class="role-line">
|
||||||
|
<view
|
||||||
|
wx:for="{{roleList}}" wx:key="key"
|
||||||
|
class="role-chip {{currentRole === item.key ? 'on' : ''}}"
|
||||||
|
data-role="{{item.key}}" bindtap="onRoleTap"
|
||||||
|
>{{item.label}}</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="date-grid">
|
||||||
|
<view
|
||||||
|
wx:for="{{dateList}}" wx:key="key"
|
||||||
|
class="date-chip {{currentDate === item.key ? 'on' : ''}}"
|
||||||
|
data-date="{{item.key}}" bindtap="onDateTap"
|
||||||
|
>{{item.label}}</view>
|
||||||
|
</view>
|
||||||
|
<text class="sort-tip">{{currentDate}} · 按{{sortLabel}} · TOP50</text>
|
||||||
|
|
||||||
|
<view class="scope-row">
|
||||||
|
<view class="scope-chip {{fanwei === 'jituan' ? 'on' : ''}}" data-fanwei="jituan" bindtap="onScopeTap">集团总榜</view>
|
||||||
|
<view class="scope-chip {{fanwei === 'club' ? 'on' : ''}}" data-fanwei="club" bindtap="onScopeTap">本俱乐部榜</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="reward-banner" wx:if="{{rewardInfo && rewardInfo.scheme_enabled}}" bindtap="onShowRules">
|
||||||
|
<view class="reward-banner-main">
|
||||||
|
<text class="reward-tag">🏆 {{rewardInfo.title || '排行榜奖励'}}</text>
|
||||||
|
<text class="reward-club">俱乐部 {{rewardInfo.club_id || myClubId}}</text>
|
||||||
|
<text class="reward-status" wx:if="{{rewardInfo.period_status === 'open'}}">进行中 · 结束后可领</text>
|
||||||
|
<text class="reward-status pending" wx:elif="{{rewardInfo.my_claim}}">待领取 ¥{{rewardInfo.my_claim.amount}}</text>
|
||||||
|
<text class="reward-status claimed" wx:elif="{{rewardInfo.my_claimed}}">已领取 ¥{{rewardInfo.my_claimed.amount}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="reward-link">规则 ›</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="state-wrap" wx:if="{{isLoading}}">
|
||||||
|
<view class="loader"></view>
|
||||||
|
<text>加载中</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="state-wrap" wx:elif="{{isEmpty}}">
|
||||||
|
<image class="state-img" src="{{imgUrls.emptyIcon}}" mode="aspectFit" />
|
||||||
|
<text>暂无排行数据</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view wx:else scroll-y class="body-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
|
||||||
|
<!-- 前三名 · 纯 CSS 领奖台 -->
|
||||||
|
<view class="podium-panel" wx:if="{{topThree.length > 0}}">
|
||||||
|
<view class="podium-cols">
|
||||||
|
|
||||||
|
<!-- 榜二 -->
|
||||||
|
<view class="p-col p-second" wx:if="{{topThree[1]}}">
|
||||||
|
<view class="p-badge badge-silver"><text>2</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-silver">
|
||||||
|
<image class="p-avatar" src="{{topThree[1].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="1" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name">{{topThree[1].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[1].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money">{{topThree[1].mainPrefix}}{{topThree[1].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[1].mainLabel}}</text>
|
||||||
|
<text class="p-reward" wx:if="{{topThree[1].rewardAmount > 0}}">奖 ¥{{topThree[1].rewardAmount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[1].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-silver"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 榜一 -->
|
||||||
|
<view class="p-col p-first" wx:if="{{topThree[0]}}">
|
||||||
|
<view class="p-badge badge-first"><text>1</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-first">
|
||||||
|
<image class="p-avatar p-avatar-lg" src="{{topThree[0].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="0" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name p-name-first">{{topThree[0].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[0].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money p-money-first">{{topThree[0].mainPrefix}}{{topThree[0].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[0].mainLabel}}</text>
|
||||||
|
<text class="p-reward" wx:if="{{topThree[0].rewardAmount > 0}}">奖 ¥{{topThree[0].rewardAmount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[0].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-first"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 榜三 -->
|
||||||
|
<view class="p-col p-third" wx:if="{{topThree[2]}}">
|
||||||
|
<view class="p-badge badge-bronze"><text>3</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-bronze">
|
||||||
|
<image class="p-avatar" src="{{topThree[2].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="2" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name">{{topThree[2].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[2].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money">{{topThree[2].mainPrefix}}{{topThree[2].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[2].mainLabel}}</text>
|
||||||
|
<text class="p-reward" wx:if="{{topThree[2].rewardAmount > 0}}">奖 ¥{{topThree[2].rewardAmount}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[2].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-bronze"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 4-50 名 -->
|
||||||
|
<view class="list-wrap" wx:if="{{restList.length > 0}}">
|
||||||
|
<view class="list-title-row">
|
||||||
|
<text class="list-title">完整榜单</text>
|
||||||
|
<text class="list-range">第 4 - {{rankList.length}} 名</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="list-card" wx:for="{{restList}}" wx:key="mingci">
|
||||||
|
<image class="list-card-bg" src="{{imgUrls.cardBg}}" mode="aspectFill" />
|
||||||
|
<view class="list-card-body">
|
||||||
|
<view class="lc-rank"><text>{{item.mingci}}</text></view>
|
||||||
|
<image class="lc-avatar" src="{{item.avatar || defaultAvatar}}" mode="aspectFill" data-zone="rest" data-index="{{index}}" binderror="onAvatarError" />
|
||||||
|
<view class="lc-info">
|
||||||
|
<text class="lc-name">{{item.nicheng}}</text>
|
||||||
|
<text class="lc-uid">ID {{item.uid}}<text wx:if="{{item.clubName && fanwei === 'jituan'}}"> · {{item.clubName}}</text></text>
|
||||||
|
<view class="lc-tags">
|
||||||
|
<text class="lc-tag" wx:for="{{item.metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="lc-score">
|
||||||
|
<text class="lc-money">{{item.mainPrefix}}{{item.mainValue}}</text>
|
||||||
|
<text class="lc-label">{{item.mainLabel}}</text>
|
||||||
|
<text class="lc-reward" wx:if="{{item.rewardAmount > 0}}">奖¥{{item.rewardAmount}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-gap"></view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="claim-bar" wx:if="{{showClaimBar && rewardInfo.my_claim}}">
|
||||||
|
<view class="claim-text">
|
||||||
|
<text class="claim-title">🎉 第{{rewardInfo.my_claim.mingci}}名 · 待领取</text>
|
||||||
|
<text class="claim-amount">¥{{rewardInfo.my_claim.amount}}</text>
|
||||||
|
</view>
|
||||||
|
<button class="claim-btn" loading="{{claimLoading}}" bindtap="onClaimTap">立即领取</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification" />
|
||||||
@@ -0,0 +1,559 @@
|
|||||||
|
page {
|
||||||
|
background: #0d1117;
|
||||||
|
color: #fff;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主题色 */
|
||||||
|
/* 选中/金额: #6BA3F7 浅蓝: #8EB8FF 银: #A8B4C4 铜: #C4A882 */
|
||||||
|
|
||||||
|
.rank-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 100%; height: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 顶栏 ========== */
|
||||||
|
.top-bar {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 16rpx 28rpx 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 38rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-wrap {
|
||||||
|
width: 60rpx; height: 60rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255,255,255,0.14);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-ico {
|
||||||
|
width: 32rpx; height: 32rpx;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-scroll {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-line {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12rpx 28rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: rgba(255,255,255,0.65);
|
||||||
|
background: rgba(20, 26, 40, 0.75);
|
||||||
|
border: 1rpx solid rgba(255,255,255,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-chip.on {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
background: rgba(107, 163, 247, 0.45);
|
||||||
|
border-color: rgba(107, 163, 247, 0.65);
|
||||||
|
box-shadow: 0 0 20rpx rgba(107, 163, 247, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 10rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-chip {
|
||||||
|
text-align: center;
|
||||||
|
padding: 14rpx 0;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: rgba(255,255,255,0.65);
|
||||||
|
background: rgba(20, 26, 40, 0.72);
|
||||||
|
border: 1rpx solid rgba(255,255,255,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-chip.on {
|
||||||
|
color: #A8CCFF;
|
||||||
|
font-weight: 600;
|
||||||
|
background: rgba(107, 163, 247, 0.35);
|
||||||
|
border-color: rgba(107, 163, 247, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-tip {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255,255,255,0.45);
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-top: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-chip {
|
||||||
|
padding: 10rpx 24rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: rgba(255,255,255,0.65);
|
||||||
|
background: rgba(20, 26, 40, 0.75);
|
||||||
|
border: 1rpx solid rgba(255,255,255,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-chip.on {
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(255, 193, 7, 0.35);
|
||||||
|
border-color: rgba(255, 193, 7, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reward-banner {
|
||||||
|
margin-top: 16rpx;
|
||||||
|
padding: 20rpx 24rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: linear-gradient(135deg, rgba(255,193,7,0.2), rgba(107,163,247,0.15));
|
||||||
|
border: 1rpx solid rgba(255,193,7,0.35);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reward-banner-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reward-tag { font-size: 28rpx; font-weight: 600; color: #ffd666; }
|
||||||
|
.reward-club { font-size: 22rpx; color: rgba(255,255,255,0.7); }
|
||||||
|
.reward-status { font-size: 22rpx; color: rgba(255,255,255,0.55); }
|
||||||
|
.reward-status.pending { color: #52c41a; font-weight: 600; }
|
||||||
|
.reward-status.claimed { color: #8c8c8c; }
|
||||||
|
.reward-link { font-size: 24rpx; color: #8EB8FF; }
|
||||||
|
|
||||||
|
.p-reward {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #ffd666;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-reward {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #ffd666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-bar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0; right: 0; bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 20rpx 28rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
background: linear-gradient(180deg, rgba(13,17,23,0.2), rgba(13,17,23,0.95));
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top: 1rpx solid rgba(255,193,7,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-text { display: flex; flex-direction: column; }
|
||||||
|
.claim-title { font-size: 26rpx; color: #fff; }
|
||||||
|
.claim-amount { font-size: 36rpx; font-weight: 700; color: #ffd666; }
|
||||||
|
|
||||||
|
.claim-btn {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 40rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
line-height: 72rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background: linear-gradient(135deg, #ffc107, #ff9800);
|
||||||
|
color: #1a1a1a;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-gap {
|
||||||
|
height: 160rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 状态 ========== */
|
||||||
|
.state-wrap {
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 140rpx 0;
|
||||||
|
color: rgba(255,255,255,0.45);
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
width: 48rpx; height: 48rpx;
|
||||||
|
border: 3rpx solid rgba(255,255,255,0.12);
|
||||||
|
border-top-color: #6BA3F7;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.7s linear infinite;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-img {
|
||||||
|
width: 160rpx; height: 160rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 滚动 ========== */
|
||||||
|
.body-scroll {
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
height: calc(100vh - 300rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 领奖台(纯 CSS) ========== */
|
||||||
|
.podium-panel {
|
||||||
|
margin: 8rpx 24rpx 24rpx;
|
||||||
|
padding: 28rpx 12rpx 0;
|
||||||
|
border-radius: 28rpx;
|
||||||
|
background: rgba(14, 18, 30, 0.88);
|
||||||
|
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium-cols {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-col {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 220rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-first {
|
||||||
|
max-width: 250rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-badge {
|
||||||
|
width: 44rpx; height: 44rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 14rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-first .p-badge {
|
||||||
|
width: 52rpx; height: 52rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-first {
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(145deg, #6BA3F7, #4A7FD4);
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(107, 163, 247, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-silver {
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(145deg, #A8B4C4, #7A8899);
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(168, 180, 196, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-bronze {
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(145deg, #C4A882, #9A7858);
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(196, 168, 130, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-avatar-wrap {
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 4rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap-first {
|
||||||
|
padding: 5rpx;
|
||||||
|
background: linear-gradient(145deg, #8EB8FF, #5B8FD8);
|
||||||
|
box-shadow: 0 6rpx 24rpx rgba(107, 163, 247, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap-silver {
|
||||||
|
background: linear-gradient(145deg, #C8D0DA, #909AA8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap-bronze {
|
||||||
|
background: linear-gradient(145deg, #D4B896, #A88860);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-avatar {
|
||||||
|
width: 100rpx; height: 100rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
background: #1a2030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-avatar-lg {
|
||||||
|
width: 120rpx; height: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-name {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255,255,255,0.92);
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-name-first {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-uid {
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-amount {
|
||||||
|
margin: 12rpx 0 10rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-money {
|
||||||
|
display: block;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #8EB8FF;
|
||||||
|
letter-spacing: -0.5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-money-first {
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #A8CCFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 2rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-metrics {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6rpx;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
min-height: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-metric {
|
||||||
|
font-size: 18rpx;
|
||||||
|
color: rgba(255,255,255,0.55);
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
padding: 4rpx 10rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底座 · 圆角柱体,非方块 */
|
||||||
|
.p-pedestal {
|
||||||
|
width: 88%;
|
||||||
|
border-radius: 20rpx 20rpx 0 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-pedestal::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 10%; right: 10%;
|
||||||
|
height: 2rpx;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
border-radius: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-first {
|
||||||
|
height: 100rpx;
|
||||||
|
background: linear-gradient(180deg, rgba(107,163,247,0.55) 0%, rgba(107,163,247,0.22) 100%);
|
||||||
|
border: 1rpx solid rgba(107,163,247,0.35);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-silver {
|
||||||
|
height: 72rpx;
|
||||||
|
background: linear-gradient(180deg, rgba(168,180,196,0.45) 0%, rgba(168,180,196,0.18) 100%);
|
||||||
|
border: 1rpx solid rgba(168,180,196,0.28);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-bronze {
|
||||||
|
height: 56rpx;
|
||||||
|
background: linear-gradient(180deg, rgba(196,168,130,0.45) 0%, rgba(196,168,130,0.18) 100%);
|
||||||
|
border: 1rpx solid rgba(196,168,130,0.28);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 列表 ========== */
|
||||||
|
.list-wrap {
|
||||||
|
padding: 0 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8rpx 8rpx 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(255,255,255,0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-range {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 14rpx;
|
||||||
|
border-radius: 18rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1rpx solid rgba(255,255,255,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 100%; height: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-body {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 22rpx;
|
||||||
|
background: rgba(12, 16, 28, 0.92);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-rank {
|
||||||
|
width: 48rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-rank text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(255,255,255,0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-avatar {
|
||||||
|
width: 80rpx; height: 80rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 16rpx 0 6rpx;
|
||||||
|
border: 2rpx solid rgba(107, 163, 247, 0.2);
|
||||||
|
background: #1a2030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-info { flex: 1; min-width: 0; }
|
||||||
|
|
||||||
|
.lc-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255,255,255,0.92);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-uid {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255,255,255,0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8rpx;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-tag {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: rgba(255,255,255,0.5);
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
padding: 2rpx 10rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-score {
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: right;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-money {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #8EB8FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lc-label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 2rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: rgba(255,255,255,0.32);
|
||||||
|
}
|
||||||
@@ -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 request from '../../utils/request.js'
|
||||||
import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js'
|
import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js'
|
||||||
import { CLUB_ID } from '../../config/club-config.js'
|
import { CLUB_ID } from '../../config/club-config.js'
|
||||||
|
|
||||||
const IS_XZJ = CLUB_ID === 'xzj'
|
const IS_XZJ = CLUB_ID === 'xzj'
|
||||||
const RANK_API = IS_XZJ ? '/yonghu/xzjphbhqsj' : '/yonghu/phbhqsj'
|
const RANK_API = IS_XZJ ? '/yonghu/xzjphbhqsj' : '/yonghu/phbhqsj'
|
||||||
const CLOSED_DATES = ['鏄ㄦ棩', '涓婂懆', '涓婃湀']
|
const CLOSED_DATES = ['昨日', '上周', '上月']
|
||||||
|
|
||||||
const ROLE_LIST = [
|
const ROLE_LIST = [
|
||||||
{ key: 'dashou', label: '鎺ュ崟鍛? },
|
{ key: 'dashou', label: '接单员' },
|
||||||
{ key: 'guanshi', label: '绠′簨' },
|
{ key: 'guanshi', label: '管事' },
|
||||||
{ key: 'zuzhang', label: '缁勯暱' },
|
{ key: 'zuzhang', label: '组长' },
|
||||||
{ key: 'shangjia', label: '鍟嗗' },
|
{ key: 'shangjia', label: '商家' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const DATE_LIST = [
|
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 = {
|
const ROLE_META = {
|
||||||
dashou: {
|
dashou: {
|
||||||
title: '鎺ュ崟鍛樻帓琛屾',
|
title: '接单员排行榜',
|
||||||
sortField: 'chengjiao_zonge',
|
sortField: 'chengjiao_zonge',
|
||||||
sortLabel: '鍒嗙孩鎬婚',
|
sortLabel: '分红总额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'jiedan_zongliang', label: '鎺ュ崟閲?, type: 'int' },
|
{ field: 'jiedan_zongliang', label: '接单量', type: 'int' },
|
||||||
{ field: 'jiedan_zonge', label: '鎺ュ崟棰?, type: 'money' },
|
{ field: 'jiedan_zonge', label: '接单额', type: 'money' },
|
||||||
{ field: 'chengjiao_zongliang', label: '鎴愪氦閲?, type: 'int' },
|
{ field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
guanshi: {
|
guanshi: {
|
||||||
title: '绠′簨鎺掕姒?,
|
title: '管事排行榜',
|
||||||
sortField: 'shouru_zonge',
|
sortField: 'shouru_zonge',
|
||||||
sortLabel: '鏀跺叆鎬婚',
|
sortLabel: '收入总额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'yaoqing_dashou_shu', label: '閭€璇?, type: 'int' },
|
{ field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' },
|
||||||
{ field: 'chongzhi_dashou_shu', label: '鍏呭€?, type: 'int' },
|
{ field: 'chongzhi_dashou_shu', label: '充值', type: 'int' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
zuzhang: {
|
zuzhang: {
|
||||||
title: '缁勯暱鎺掕姒?,
|
title: '组长排行榜',
|
||||||
sortField: 'shouru_zonge',
|
sortField: 'shouru_zonge',
|
||||||
sortLabel: '鏀跺叆鎬婚',
|
sortLabel: '收入总额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'yaoqing_guanshi_shu', label: '閭€璇?, type: 'int' },
|
{ field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' },
|
||||||
{ field: 'fenyong_jine', label: '鍒嗕剑', type: 'money' },
|
{ field: 'fenyong_jine', label: '分佣', type: 'money' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
shangjia: {
|
shangjia: {
|
||||||
title: '鍟嗗鎺掕姒?,
|
title: '商家排行榜',
|
||||||
sortField: 'jiesuan_jine',
|
sortField: 'jiesuan_jine',
|
||||||
sortLabel: '鎴愪氦鎬婚',
|
sortLabel: '成交总额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'jiesuan_dingdan_shu', label: '鎴愪氦閲?, type: 'int' },
|
{ field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' },
|
||||||
{ field: 'paifa_dingdan_shu', label: '娲惧崟閲?, type: 'int' },
|
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
|
||||||
{ field: 'paifa_jine', label: '娲惧崟棰?, type: 'money' },
|
{ field: 'paifa_jine', label: '派单额', type: 'money' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 鏄熶箣鐣屼笓鐢ㄥ睍绀轰笌鎺掑簭瀛楁 */
|
/** 星之界专用展示与排序字段 */
|
||||||
const XZJ_ROLE_META = {
|
const XZJ_ROLE_META = {
|
||||||
dashou: {
|
dashou: {
|
||||||
title: '鎺ュ崟鍛樻帓琛屾',
|
title: '接单员排行榜',
|
||||||
sortField: 'chengjiao_zonge',
|
sortField: 'chengjiao_zonge',
|
||||||
sortLabel: '鎴愪氦閲戦',
|
sortLabel: '成交金额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'jiedan_zongliang', label: '鎺ュ崟閲?, type: 'int' },
|
{ field: 'jiedan_zongliang', label: '接单量', type: 'int' },
|
||||||
{ field: 'jiedan_zonge', label: '鎺ュ崟棰?, type: 'money' },
|
{ field: 'jiedan_zonge', label: '接单额', type: 'money' },
|
||||||
{ field: 'chengjiao_zongliang', label: '鎴愪氦閲?, type: 'int' },
|
{ field: 'chengjiao_zongliang', label: '成交量', type: 'int' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
guanshi: {
|
guanshi: {
|
||||||
title: '绠′簨鎺掕姒?,
|
title: '管事排行榜',
|
||||||
sortField: 'chongzhi_dashou_shu',
|
sortField: 'chongzhi_dashou_shu',
|
||||||
sortLabel: '鏈夋晥浜烘暟',
|
sortLabel: '有效人数',
|
||||||
mainType: 'int',
|
mainType: 'int',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'wuxiao_yaoqing_dashou_shu', label: '鏃犳晥閭€璇?, type: 'int' },
|
{ field: 'wuxiao_yaoqing_dashou_shu', label: '无效邀请', type: 'int' },
|
||||||
{ field: 'yaoqing_dashou_shu', label: '閭€璇蜂汉鏁?, type: 'int' },
|
{ field: 'yaoqing_dashou_shu', label: '邀请人数', type: 'int' },
|
||||||
{ field: 'shouru_zonge', label: '鏀剁泭鎬婚', type: 'money' },
|
{ field: 'shouru_zonge', label: '收益总额', type: 'money' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
zuzhang: {
|
zuzhang: {
|
||||||
title: '缁勯暱鎺掕姒?,
|
title: '组长排行榜',
|
||||||
sortField: 'shouru_zonge',
|
sortField: 'shouru_zonge',
|
||||||
sortLabel: '鏀剁泭鎬婚',
|
sortLabel: '收益总额',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'wuxiao_yaoqing_guanshi_shu', label: '鏃犳晥閭€璇?, type: 'int' },
|
{ field: 'wuxiao_yaoqing_guanshi_shu', label: '无效邀请', type: 'int' },
|
||||||
{ field: 'youxiao_guanshi_shu', label: '鏈夋晥浜烘暟', type: 'int' },
|
{ field: 'youxiao_guanshi_shu', label: '有效人数', type: 'int' },
|
||||||
{ field: 'yaoqing_guanshi_shu', label: '閭€璇蜂汉鏁?, type: 'int' },
|
{ field: 'yaoqing_guanshi_shu', label: '邀请人数', type: 'int' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
shangjia: {
|
shangjia: {
|
||||||
title: '鍟嗗鎺掕姒?,
|
title: '商家排行榜',
|
||||||
sortField: 'paifa_jine',
|
sortField: 'paifa_jine',
|
||||||
sortLabel: '娲惧崟娴佹按',
|
sortLabel: '派单流水',
|
||||||
mainType: 'money',
|
mainType: 'money',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ field: 'paifa_dingdan_shu', label: '娲惧崟閲?, type: 'int' },
|
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
|
||||||
{ field: 'paifa_jine', label: '娲惧崟娴佹按', type: 'money' },
|
{ field: 'paifa_jine', label: '派单流水', type: 'money' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -143,11 +145,12 @@ Page({
|
|||||||
roleList: ROLE_LIST,
|
roleList: ROLE_LIST,
|
||||||
dateList: DATE_LIST,
|
dateList: DATE_LIST,
|
||||||
currentRole: 'dashou',
|
currentRole: 'dashou',
|
||||||
currentDate: '浠婃棩',
|
currentDate: '今日',
|
||||||
fanwei: 'club',
|
fanwei: 'club',
|
||||||
showJituanScope: false, // 涓存椂闅愯棌闆嗗洟鎬绘锛屾仮澶嶆椂鏀?true 骞惰皟鏁?fanwei 榛樿鍊? myClubId: CLUB_ID || 'xq',
|
showJituanScope: false, // 临时隐藏集团总榜,恢复时改 true 并调整 fanwei 默认值
|
||||||
|
myClubId: CLUB_ID || 'xq',
|
||||||
roleMeta: ROLE_META.dashou,
|
roleMeta: ROLE_META.dashou,
|
||||||
sortLabel: '鍒嗙孩鎬婚',
|
sortLabel: '分红总额',
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
rankList: [],
|
rankList: [],
|
||||||
topThree: [],
|
topThree: [],
|
||||||
@@ -183,7 +186,7 @@ Page({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 涓?app.js 涓€鑷达細ossImageUrl + morentouxiang锛岄厤缃紓姝ュ姞杞藉悗 onShow 鍐嶅悓姝?*/
|
/** 与 app.js 一致:ossImageUrl + morentouxiang,配置异步加载后 onShow 再同步 */
|
||||||
syncDefaultAvatar() {
|
syncDefaultAvatar() {
|
||||||
const def = getDefaultAvatar()
|
const def = getDefaultAvatar()
|
||||||
if (def && def !== this.data.defaultAvatar) {
|
if (def && def !== this.data.defaultAvatar) {
|
||||||
@@ -193,7 +196,7 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 閰嶇疆鏅氫簬椤甸潰鍔犺浇鏃讹紝琛ュ叏绌哄ご鍍?*/
|
/** 配置晚于页面加载时,补全空头像 */
|
||||||
ensureAvatars() {
|
ensureAvatars() {
|
||||||
const def = getDefaultAvatar()
|
const def = getDefaultAvatar()
|
||||||
if (!def) return
|
if (!def) return
|
||||||
@@ -223,7 +226,7 @@ Page({
|
|||||||
|
|
||||||
applyRole(role, reload = true) {
|
applyRole(role, reload = true) {
|
||||||
const meta = ACTIVE_ROLE_META[role]
|
const meta = ACTIVE_ROLE_META[role]
|
||||||
wx.setNavigationBarTitle({ title: '鎬绘帓琛屾' })
|
wx.setNavigationBarTitle({ title: '总排行榜' })
|
||||||
this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel })
|
this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel })
|
||||||
if (reload) this.fetchRankList()
|
if (reload) this.fetchRankList()
|
||||||
},
|
},
|
||||||
@@ -252,19 +255,19 @@ Page({
|
|||||||
onShowRules() {
|
onShowRules() {
|
||||||
const r = this.data.rewardInfo
|
const r = this.data.rewardInfo
|
||||||
if (!r || !r.tiers || !r.tiers.length) {
|
if (!r || !r.tiers || !r.tiers.length) {
|
||||||
wx.showToast({ title: '鏆傛棤濂栧姳瑙勫垯', icon: 'none' })
|
wx.showToast({ title: '暂无奖励规则', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const lines = r.tiers.map((t) => {
|
const lines = r.tiers.map((t) => {
|
||||||
const label = t.label || `绗?{t.rank_from}${t.rank_to > t.rank_from ? '-' + t.rank_to : ''}鍚峘
|
const label = t.label || `第${t.rank_from}${t.rank_to > t.rank_from ? '-' + t.rank_to : ''}名`
|
||||||
return `${label}锛毬?{t.amount}`
|
return `${label}:¥${t.amount}`
|
||||||
})
|
})
|
||||||
const tip = r.period_status === 'open' ? '锛堟湰鏈熻繘琛屼腑锛岀粨鏉熷悗鍙鍙栵級' : ''
|
const tip = r.period_status === 'open' ? '(本期进行中,结束后可领取)' : ''
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: `${r.title || '鎺掕姒滃鍔?}${tip}`,
|
title: `${r.title || '排行榜奖励'}${tip}`,
|
||||||
content: [
|
content: [
|
||||||
`淇变箰閮細${r.club_id || this.data.myClubId}`,
|
`俱乐部:${r.club_id || this.data.myClubId}`,
|
||||||
`鎺掑簭锛?{r.sort_label || ''}`,
|
`排序:${r.sort_label || ''}`,
|
||||||
...lines,
|
...lines,
|
||||||
r.description || '',
|
r.description || '',
|
||||||
].filter(Boolean).join('\n'),
|
].filter(Boolean).join('\n'),
|
||||||
@@ -284,13 +287,13 @@ Page({
|
|||||||
})
|
})
|
||||||
const body = res?.data || {}
|
const body = res?.data || {}
|
||||||
if (body.code === 200) {
|
if (body.code === 200) {
|
||||||
wx.showToast({ title: `宸查鍙?楼${claim.amount}`, icon: 'success' })
|
wx.showToast({ title: `已领取 ¥${claim.amount}`, icon: 'success' })
|
||||||
await this.fetchRewardInfo()
|
await this.fetchRewardInfo()
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: body.msg || '棰嗗彇澶辫触', icon: 'none' })
|
wx.showToast({ title: body.msg || '领取失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
wx.showToast({ title: '棰嗗彇澶辫触', icon: 'none' })
|
wx.showToast({ title: '领取失败', icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
this.setData({ claimLoading: false })
|
this.setData({ claimLoading: false })
|
||||||
}
|
}
|
||||||
@@ -314,7 +317,7 @@ Page({
|
|||||||
const meta = ACTIVE_ROLE_META[role]
|
const meta = ACTIVE_ROLE_META[role]
|
||||||
const app = getApp()
|
const app = getApp()
|
||||||
const uid = raw.yonghuid || raw.uid || ''
|
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 def = getDefaultAvatar(app)
|
||||||
const avatar = buildAvatar(raw.touxiang || raw.avatar, app) || def
|
const avatar = buildAvatar(raw.touxiang || raw.avatar, app) || def
|
||||||
const metrics = meta.metrics.map((m) => {
|
const metrics = meta.metrics.map((m) => {
|
||||||
@@ -345,7 +348,7 @@ Page({
|
|||||||
clubName: raw.club_name || raw.club_id || '',
|
clubName: raw.club_name || raw.club_id || '',
|
||||||
rewardAmount: raw.reward_amount || 0,
|
rewardAmount: raw.reward_amount || 0,
|
||||||
mainType,
|
mainType,
|
||||||
mainPrefix: mainType === 'money' ? '楼' : '',
|
mainPrefix: mainType === 'money' ? '¥' : '',
|
||||||
mainValue,
|
mainValue,
|
||||||
mainLabel: (IS_XZJ ? meta.sortLabel : (raw.metric_label || meta.sortLabel)),
|
mainLabel: (IS_XZJ ? meta.sortLabel : (raw.metric_label || meta.sortLabel)),
|
||||||
metrics,
|
metrics,
|
||||||
@@ -387,7 +390,7 @@ Page({
|
|||||||
restList: merged.slice(3),
|
restList: merged.slice(3),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('濂栧姳淇℃伅鍔犺浇澶辫触', e)
|
console.warn('奖励信息加载失败', e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -432,7 +435,7 @@ Page({
|
|||||||
|
|
||||||
if (!Array.isArray(list)) list = []
|
if (!Array.isArray(list)) list = []
|
||||||
const role = currentRole
|
const role = currentRole
|
||||||
// 鍚嶆椤哄簭瀹屽叏娌跨敤鍚庣杩斿洖锛屽墠绔笉鍋?sort / 閲嶆帓
|
// 名次顺序完全沿用后端返回,前端不做 sort / 重排
|
||||||
let normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
let normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role))
|
||||||
if (rewardFromRank) {
|
if (rewardFromRank) {
|
||||||
normalized = this.applyRewardToList(normalized, rewardFromRank, 'club')
|
normalized = this.applyRewardToList(normalized, rewardFromRank, 'club')
|
||||||
@@ -450,8 +453,8 @@ Page({
|
|||||||
await this.fetchRewardInfo()
|
await this.fetchRewardInfo()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('鎺掕姒滃姞杞藉け璐?, e)
|
console.error('排行榜加载失败', e)
|
||||||
wx.showToast({ title: '鍔犺浇澶辫触', icon: 'none' })
|
wx.showToast({ title: '加载失败', icon: 'none' })
|
||||||
this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false })
|
this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
"usingComponents": {
|
"usingComponents": {
|
||||||
"global-notification": "/components/global-notification/global-notification"
|
"global-notification": "/components/global-notification/global-notification"
|
||||||
},
|
},
|
||||||
"navigationBarTitleText": "排行榜",
|
"navigationBarTitleText": "总排行榜",
|
||||||
"navigationBarBackgroundColor": "#0d1117",
|
"navigationBarBackgroundColor": "#FFE566",
|
||||||
"navigationBarTextStyle": "white",
|
"navigationBarTextStyle": "black",
|
||||||
"enablePullDownRefresh": true,
|
"enablePullDownRefresh": true,
|
||||||
"backgroundColor": "#0d1117",
|
"backgroundColor": "#FFE566",
|
||||||
"backgroundTextStyle": "light"
|
"backgroundTextStyle": "dark"
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,47 @@
|
|||||||
<view class="rank-page">
|
<view class="rank-page">
|
||||||
<image class="page-bg" src="{{imgUrls.pageBg}}" mode="aspectFill" />
|
<!-- 顶区:黄底 + 白 Tab + 时间筛选 -->
|
||||||
|
<view class="header-zone">
|
||||||
<view class="top-bar">
|
<view class="role-tabs">
|
||||||
<view class="top-row">
|
<view
|
||||||
<text class="page-title">{{roleMeta.title}}</text>
|
wx:for="{{roleList}}" wx:key="key"
|
||||||
<view class="refresh-wrap" bindtap="onRefreshTap">
|
class="role-tab {{currentRole === item.key ? 'active' : ''}}"
|
||||||
<image class="refresh-ico" src="{{imgUrls.refreshIcon}}" mode="aspectFit" />
|
data-role="{{item.key}}" bindtap="onRoleTap"
|
||||||
|
>
|
||||||
|
<text class="role-tab-text">{{item.label}}</text>
|
||||||
|
<view class="role-tab-line" wx:if="{{currentRole === item.key}}"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<scroll-view scroll-x class="role-scroll" enhanced show-scrollbar="{{false}}">
|
|
||||||
<view class="role-line">
|
<scroll-view scroll-x class="date-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
<view class="date-line">
|
||||||
<view
|
<view
|
||||||
wx:for="{{roleList}}" wx:key="key"
|
wx:for="{{dateList}}" wx:key="key"
|
||||||
class="role-chip {{currentRole === item.key ? 'on' : ''}}"
|
class="date-tab {{currentDate === item.key ? 'active' : ''}}"
|
||||||
data-role="{{item.key}}" bindtap="onRoleTap"
|
data-date="{{item.key}}" bindtap="onDateTap"
|
||||||
>{{item.label}}</view>
|
>{{item.label}}</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<view class="date-grid">
|
|
||||||
<view
|
<view class="scope-row">
|
||||||
wx:for="{{dateList}}" wx:key="key"
|
<!-- 临时隐藏集团总榜,恢复时取消 wx:if 注释 -->
|
||||||
class="date-chip {{currentDate === item.key ? 'on' : ''}}"
|
<view wx:if="{{showJituanScope}}" class="scope-tab {{fanwei === 'jituan' ? 'active' : ''}}" data-fanwei="jituan" bindtap="onScopeTap">集团总榜</view>
|
||||||
data-date="{{item.key}}" bindtap="onDateTap"
|
<view class="scope-tab {{fanwei === 'club' ? 'active' : ''}}" data-fanwei="club" bindtap="onScopeTap">本俱乐部榜</view>
|
||||||
>{{item.label}}</view>
|
<view class="refresh-btn" bindtap="onRefreshTap">
|
||||||
|
<image class="refresh-ico" src="{{imgUrls.refreshIcon}}" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="sort-tip">{{currentDate}} · 按{{sortLabel}} · TOP50</text>
|
<text class="sort-tip">{{currentDate}} · 按{{sortLabel}} · TOP50</text>
|
||||||
|
|
||||||
|
<view class="reward-banner" wx:if="{{rewardInfo && rewardInfo.scheme_enabled}}" bindtap="onShowRules">
|
||||||
|
<view class="reward-banner-main">
|
||||||
|
<text class="reward-tag">🏆 {{rewardInfo.title || '排行榜奖励'}}</text>
|
||||||
|
<text class="reward-club">俱乐部 {{rewardInfo.club_id || myClubId}}</text>
|
||||||
|
<text class="reward-status" wx:if="{{rewardInfo.period_status === 'open'}}">进行中 · 结束后可领</text>
|
||||||
|
<text class="reward-status pending" wx:elif="{{rewardInfo.my_claim}}">待领取 ¥{{rewardInfo.my_claim.amount}}</text>
|
||||||
|
<text class="reward-status claimed" wx:elif="{{rewardInfo.my_claimed}}">已领取 ¥{{rewardInfo.my_claimed.amount}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="reward-link">规则 ›</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="state-wrap" wx:if="{{isLoading}}">
|
<view class="state-wrap" wx:if="{{isLoading}}">
|
||||||
@@ -38,97 +55,85 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view wx:else scroll-y class="body-scroll" enhanced show-scrollbar="{{false}}">
|
<scroll-view wx:else scroll-y class="body-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
<!-- 前三名领奖台 -->
|
||||||
|
<view class="podium-zone" wx:if="{{topThree.length > 0}}">
|
||||||
|
<view class="podium-row">
|
||||||
|
|
||||||
<!-- 前三名 · 纯 CSS 领奖台 -->
|
<view class="podium-col col-2" wx:if="{{topThree[1]}}">
|
||||||
<view class="podium-panel" wx:if="{{topThree.length > 0}}">
|
<view class="crown crown-silver">👑</view>
|
||||||
<view class="podium-cols">
|
<view class="avatar-ring ring-silver">
|
||||||
|
|
||||||
<!-- 榜二 -->
|
|
||||||
<view class="p-col p-second" wx:if="{{topThree[1]}}">
|
|
||||||
<view class="p-badge badge-silver"><text>2</text></view>
|
|
||||||
<view class="p-avatar-wrap wrap-silver">
|
|
||||||
<image class="p-avatar" src="{{topThree[1].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="1" binderror="onAvatarError" />
|
<image class="p-avatar" src="{{topThree[1].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="1" binderror="onAvatarError" />
|
||||||
</view>
|
</view>
|
||||||
<text class="p-name">{{topThree[1].nicheng}}</text>
|
<text class="p-name">{{topThree[1].nicheng}}</text>
|
||||||
<text class="p-uid">ID {{topThree[1].uid}}</text>
|
<text class="p-label">{{topThree[1].mainLabel}}</text>
|
||||||
<view class="p-amount">
|
<text class="p-amount">{{topThree[1].mainPrefix}}{{topThree[1].mainValue}}</text>
|
||||||
<text class="p-money">¥{{topThree[1].mainValue}}</text>
|
|
||||||
<text class="p-label">{{topThree[1].mainLabel}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="p-metrics">
|
<view class="p-metrics">
|
||||||
<text class="p-metric" wx:for="{{topThree[1].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
<text class="p-metric" wx:for="{{topThree[1].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="p-pedestal pedestal-silver"></view>
|
<text class="p-reward" wx:if="{{topThree[1].rewardAmount > 0}}">奖 ¥{{topThree[1].rewardAmount}}</text>
|
||||||
|
<view class="pedestal pedestal-2"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 榜一 -->
|
<view class="podium-col col-1" wx:if="{{topThree[0]}}">
|
||||||
<view class="p-col p-first" wx:if="{{topThree[0]}}">
|
<view class="crown crown-gold">👑</view>
|
||||||
<view class="p-badge badge-first"><text>1</text></view>
|
<view class="avatar-ring ring-gold">
|
||||||
<view class="p-avatar-wrap wrap-first">
|
|
||||||
<image class="p-avatar p-avatar-lg" src="{{topThree[0].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="0" binderror="onAvatarError" />
|
<image class="p-avatar p-avatar-lg" src="{{topThree[0].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="0" binderror="onAvatarError" />
|
||||||
</view>
|
</view>
|
||||||
<text class="p-name p-name-first">{{topThree[0].nicheng}}</text>
|
<text class="p-name p-name-lg">{{topThree[0].nicheng}}</text>
|
||||||
<text class="p-uid">ID {{topThree[0].uid}}</text>
|
<text class="p-label">{{topThree[0].mainLabel}}</text>
|
||||||
<view class="p-amount">
|
<text class="p-amount p-amount-lg">{{topThree[0].mainPrefix}}{{topThree[0].mainValue}}</text>
|
||||||
<text class="p-money p-money-first">¥{{topThree[0].mainValue}}</text>
|
|
||||||
<text class="p-label">{{topThree[0].mainLabel}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="p-metrics">
|
<view class="p-metrics">
|
||||||
<text class="p-metric" wx:for="{{topThree[0].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
<text class="p-metric" wx:for="{{topThree[0].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="p-pedestal pedestal-first"></view>
|
<text class="p-reward" wx:if="{{topThree[0].rewardAmount > 0}}">奖 ¥{{topThree[0].rewardAmount}}</text>
|
||||||
|
<view class="pedestal pedestal-1"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 榜三 -->
|
<view class="podium-col col-3" wx:if="{{topThree[2]}}">
|
||||||
<view class="p-col p-third" wx:if="{{topThree[2]}}">
|
<view class="crown crown-bronze">👑</view>
|
||||||
<view class="p-badge badge-bronze"><text>3</text></view>
|
<view class="avatar-ring ring-bronze">
|
||||||
<view class="p-avatar-wrap wrap-bronze">
|
|
||||||
<image class="p-avatar" src="{{topThree[2].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="2" binderror="onAvatarError" />
|
<image class="p-avatar" src="{{topThree[2].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="2" binderror="onAvatarError" />
|
||||||
</view>
|
</view>
|
||||||
<text class="p-name">{{topThree[2].nicheng}}</text>
|
<text class="p-name">{{topThree[2].nicheng}}</text>
|
||||||
<text class="p-uid">ID {{topThree[2].uid}}</text>
|
<text class="p-label">{{topThree[2].mainLabel}}</text>
|
||||||
<view class="p-amount">
|
<text class="p-amount">{{topThree[2].mainPrefix}}{{topThree[2].mainValue}}</text>
|
||||||
<text class="p-money">¥{{topThree[2].mainValue}}</text>
|
|
||||||
<text class="p-label">{{topThree[2].mainLabel}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="p-metrics">
|
<view class="p-metrics">
|
||||||
<text class="p-metric" wx:for="{{topThree[2].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
<text class="p-metric" wx:for="{{topThree[2].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="p-pedestal pedestal-bronze"></view>
|
<text class="p-reward" wx:if="{{topThree[2].rewardAmount > 0}}">奖 ¥{{topThree[2].rewardAmount}}</text>
|
||||||
|
<view class="pedestal pedestal-3"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 4-50 名 -->
|
<!-- 4 名以后列表 -->
|
||||||
<view class="list-wrap" wx:if="{{restList.length > 0}}">
|
<view class="list-panel" wx:if="{{restList.length > 0}}">
|
||||||
<view class="list-title-row">
|
<view class="list-row" wx:for="{{restList}}" wx:key="mingci">
|
||||||
<text class="list-title">完整榜单</text>
|
<text class="li-rank">{{item.mingci}}</text>
|
||||||
<text class="list-range">第 4 - {{rankList.length}} 名</text>
|
<image class="li-avatar" src="{{item.avatar || defaultAvatar}}" mode="aspectFill" data-zone="rest" data-index="{{index}}" binderror="onAvatarError" />
|
||||||
</view>
|
<text class="li-name">{{item.nicheng}}</text>
|
||||||
|
<view class="li-right">
|
||||||
<view class="list-card" wx:for="{{restList}}" wx:key="mingci">
|
<text class="li-amount">{{item.mainPrefix}}{{item.mainValue}}</text>
|
||||||
<image class="list-card-bg" src="{{imgUrls.cardBg}}" mode="aspectFill" />
|
<text class="li-label">{{item.mainLabel}}</text>
|
||||||
<view class="list-card-body">
|
<view class="li-tags">
|
||||||
<view class="lc-rank"><text>{{item.mingci}}</text></view>
|
<text class="li-tag" wx:for="{{item.metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
<image class="lc-avatar" src="{{item.avatar || defaultAvatar}}" mode="aspectFill" data-zone="rest" data-index="{{index}}" binderror="onAvatarError" />
|
|
||||||
<view class="lc-info">
|
|
||||||
<text class="lc-name">{{item.nicheng}}</text>
|
|
||||||
<text class="lc-uid">ID {{item.uid}}</text>
|
|
||||||
<view class="lc-tags">
|
|
||||||
<text class="lc-tag" wx:for="{{item.metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="lc-score">
|
|
||||||
<text class="lc-money">¥{{item.mainValue}}</text>
|
|
||||||
<text class="lc-label">{{item.mainLabel}}</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
<text class="li-reward" wx:if="{{item.rewardAmount > 0}}">奖¥{{item.rewardAmount}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="bottom-gap"></view>
|
<view class="bottom-gap"></view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="claim-bar" wx:if="{{showClaimBar && rewardInfo.my_claim}}">
|
||||||
|
<view class="claim-text">
|
||||||
|
<text class="claim-title">🎉 第{{rewardInfo.my_claim.mingci}}名 · 待领取</text>
|
||||||
|
<text class="claim-amount">¥{{rewardInfo.my_claim.amount}}</text>
|
||||||
|
</view>
|
||||||
|
<button class="claim-btn" loading="{{claimLoading}}" bindtap="onClaimTap">立即领取</button>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<global-notification id="global-notification" />
|
<global-notification id="global-notification" />
|
||||||
@@ -1,290 +1,434 @@
|
|||||||
page {
|
page {
|
||||||
background: #0d1117;
|
background: #ffe566;
|
||||||
color: #fff;
|
color: #333;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 主题色 */
|
|
||||||
/* 选中/金额: #6BA3F7 浅蓝: #8EB8FF 银: #A8B4C4 铜: #C4A882 */
|
|
||||||
|
|
||||||
.rank-page {
|
.rank-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
position: relative;
|
background: linear-gradient(180deg, #ffe566 0%, #ffe566 420rpx, #fff8dc 520rpx, #ffffff 620rpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-bg {
|
/* ========== 顶区 ========== */
|
||||||
position: fixed;
|
.header-zone {
|
||||||
top: 0; left: 0;
|
|
||||||
width: 100%; height: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== 顶栏 ========== */
|
|
||||||
.top-bar {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
padding: 16rpx 28rpx 20rpx;
|
padding-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-row {
|
.role-tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
background: #ffffff;
|
||||||
|
margin: 0 0 0;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tab {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24rpx 0 18rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tab-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666666;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tab.active .role-tab-text {
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tab-line {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8rpx;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 48rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
background: #3d2914;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-scroll {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 20rpx 0 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-line {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-tab {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10rpx 22rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-tab.active {
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-weight: 700;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-tab.active::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 36rpx;
|
||||||
|
height: 4rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
background: #3d2914;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scope-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 12rpx;
|
||||||
margin-bottom: 20rpx;
|
padding: 8rpx 24rpx 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
.scope-tab {
|
||||||
font-size: 38rpx;
|
padding: 8rpx 20rpx;
|
||||||
font-weight: 700;
|
border-radius: 999rpx;
|
||||||
color: #fff;
|
font-size: 22rpx;
|
||||||
|
color: rgba(0, 0, 0, 0.55);
|
||||||
|
background: rgba(255, 255, 255, 0.55);
|
||||||
|
border: 1rpx solid rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-wrap {
|
.scope-tab.active {
|
||||||
width: 60rpx; height: 60rpx;
|
color: #1a1a1a;
|
||||||
|
font-weight: 600;
|
||||||
|
background: #ffffff;
|
||||||
|
border-color: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-btn {
|
||||||
|
margin-left: auto;
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(255,255,255,0.14);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-ico {
|
.refresh-ico {
|
||||||
width: 32rpx; height: 32rpx;
|
width: 28rpx;
|
||||||
opacity: 0.8;
|
height: 28rpx;
|
||||||
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
|
|
||||||
.role-scroll {
|
.reward-banner {
|
||||||
width: 100%;
|
margin: 0 24rpx 12rpx;
|
||||||
white-space: nowrap;
|
padding: 18rpx 22rpx;
|
||||||
margin-bottom: 16rpx;
|
border-radius: 16rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
border: 1rpx solid rgba(255, 193, 7, 0.35);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.role-line {
|
.reward-banner-main {
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
gap: 12rpx;
|
flex-direction: column;
|
||||||
|
gap: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.role-chip {
|
.reward-tag { font-size: 26rpx; font-weight: 600; color: #d48806; }
|
||||||
display: inline-block;
|
.reward-club { font-size: 22rpx; color: #666; }
|
||||||
padding: 12rpx 28rpx;
|
.reward-status { font-size: 22rpx; color: #999; }
|
||||||
border-radius: 999rpx;
|
.reward-status.pending { color: #52c41a; font-weight: 600; }
|
||||||
font-size: 26rpx;
|
.reward-status.claimed { color: #8c8c8c; }
|
||||||
color: rgba(255,255,255,0.65);
|
.reward-link { font-size: 24rpx; color: #d48806; }
|
||||||
background: rgba(20, 26, 40, 0.75);
|
|
||||||
border: 1rpx solid rgba(255,255,255,0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.role-chip.on {
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
background: rgba(107, 163, 247, 0.45);
|
|
||||||
border-color: rgba(107, 163, 247, 0.65);
|
|
||||||
box-shadow: 0 0 20rpx rgba(107, 163, 247, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
gap: 10rpx;
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-chip {
|
|
||||||
text-align: center;
|
|
||||||
padding: 14rpx 0;
|
|
||||||
border-radius: 14rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: rgba(255,255,255,0.65);
|
|
||||||
background: rgba(20, 26, 40, 0.72);
|
|
||||||
border: 1rpx solid rgba(255,255,255,0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-chip.on {
|
|
||||||
color: #A8CCFF;
|
|
||||||
font-weight: 600;
|
|
||||||
background: rgba(107, 163, 247, 0.35);
|
|
||||||
border-color: rgba(107, 163, 247, 0.55);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sort-tip {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: rgba(255,255,255,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== 状态 ========== */
|
/* ========== 状态 ========== */
|
||||||
.state-wrap {
|
.state-wrap {
|
||||||
position: relative;
|
|
||||||
z-index: 5;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 140rpx 0;
|
padding: 120rpx 0;
|
||||||
color: rgba(255,255,255,0.45);
|
color: rgba(0, 0, 0, 0.45);
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader {
|
.loader {
|
||||||
width: 48rpx; height: 48rpx;
|
width: 48rpx;
|
||||||
border: 3rpx solid rgba(255,255,255,0.12);
|
height: 48rpx;
|
||||||
border-top-color: #6BA3F7;
|
border: 3rpx solid rgba(0, 0, 0, 0.08);
|
||||||
|
border-top-color: #ffb800;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 0.7s linear infinite;
|
animation: spin 0.7s linear infinite;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
.state-img {
|
.state-img {
|
||||||
width: 160rpx; height: 160rpx;
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
opacity: 0.65;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== 滚动 ========== */
|
/* ========== 滚动区 ========== */
|
||||||
.body-scroll {
|
.body-scroll {
|
||||||
position: relative;
|
height: calc(100vh - 280rpx);
|
||||||
z-index: 5;
|
|
||||||
height: calc(100vh - 300rpx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== 领奖台(纯 CSS) ========== */
|
/* ========== 领奖台 ========== */
|
||||||
.podium-panel {
|
.podium-zone {
|
||||||
margin: 8rpx 24rpx 24rpx;
|
padding: 16rpx 16rpx 0;
|
||||||
padding: 28rpx 12rpx 0;
|
|
||||||
border-radius: 28rpx;
|
|
||||||
background: rgba(14, 18, 30, 0.88);
|
|
||||||
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.podium-cols {
|
.podium-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 10rpx;
|
gap: 6rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-col {
|
.podium-col {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
max-width: 220rpx;
|
max-width: 230rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-first {
|
.col-1 {
|
||||||
max-width: 250rpx;
|
max-width: 260rpx;
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-badge {
|
.crown {
|
||||||
width: 44rpx; height: 44rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 14rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-first .p-badge {
|
|
||||||
width: 52rpx; height: 52rpx;
|
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
filter: drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.15));
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-first {
|
.col-1 .crown {
|
||||||
color: #fff;
|
font-size: 34rpx;
|
||||||
background: linear-gradient(145deg, #6BA3F7, #4A7FD4);
|
|
||||||
box-shadow: 0 4rpx 16rpx rgba(107, 163, 247, 0.4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-silver {
|
.avatar-ring {
|
||||||
color: #fff;
|
|
||||||
background: linear-gradient(145deg, #A8B4C4, #7A8899);
|
|
||||||
box-shadow: 0 4rpx 12rpx rgba(168, 180, 196, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
.badge-bronze {
|
|
||||||
color: #fff;
|
|
||||||
background: linear-gradient(145deg, #C4A882, #9A7858);
|
|
||||||
box-shadow: 0 4rpx 12rpx rgba(196, 168, 130, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-avatar-wrap {
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
padding: 4rpx;
|
padding: 6rpx;
|
||||||
margin-bottom: 12rpx;
|
margin-bottom: 10rpx;
|
||||||
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrap-first {
|
.ring-gold {
|
||||||
padding: 5rpx;
|
padding: 8rpx;
|
||||||
background: linear-gradient(145deg, #8EB8FF, #5B8FD8);
|
box-shadow: 0 0 0 4rpx #ffd700, 0 8rpx 20rpx rgba(255, 183, 0, 0.35);
|
||||||
box-shadow: 0 6rpx 24rpx rgba(107, 163, 247, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrap-silver {
|
.ring-silver {
|
||||||
background: linear-gradient(145deg, #C8D0DA, #909AA8);
|
box-shadow: 0 0 0 4rpx #b8c4d4, 0 6rpx 16rpx rgba(120, 140, 180, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrap-bronze {
|
.ring-bronze {
|
||||||
background: linear-gradient(145deg, #D4B896, #A88860);
|
box-shadow: 0 0 0 4rpx #cd9a5a, 0 6rpx 16rpx rgba(205, 127, 50, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-avatar {
|
.p-avatar {
|
||||||
width: 100rpx; height: 100rpx;
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: block;
|
display: block;
|
||||||
background: #1a2030;
|
background: #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-avatar-lg {
|
.p-avatar-lg {
|
||||||
width: 120rpx; height: 120rpx;
|
width: 116rpx;
|
||||||
|
height: 116rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-name {
|
.p-name {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: rgba(255,255,255,0.92);
|
color: #1a1a1a;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-name-first {
|
.p-name-lg {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-uid {
|
|
||||||
margin-top: 4rpx;
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: rgba(255,255,255,0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-amount {
|
|
||||||
margin: 12rpx 0 10rpx;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-money {
|
|
||||||
display: block;
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #8EB8FF;
|
|
||||||
letter-spacing: -0.5rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-money-first {
|
|
||||||
font-size: 34rpx;
|
|
||||||
color: #A8CCFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-label {
|
.p-label {
|
||||||
display: block;
|
font-size: 22rpx;
|
||||||
|
color: #999999;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-amount {
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #ffb800;
|
||||||
|
line-height: 1.3;
|
||||||
margin-top: 2rpx;
|
margin-top: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-amount-lg {
|
||||||
|
font-size: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-sub-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999999;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-sub-value {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ffb800;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-sub-value-lg {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-reward {
|
||||||
|
margin-top: 4rpx;
|
||||||
font-size: 20rpx;
|
font-size: 20rpx;
|
||||||
color: rgba(255,255,255,0.35);
|
color: #d48806;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal {
|
||||||
|
width: 92%;
|
||||||
|
margin-top: 14rpx;
|
||||||
|
border-radius: 16rpx 16rpx 0 0;
|
||||||
|
background: linear-gradient(180deg, #ffe08a 0%, #ffd04d 100%);
|
||||||
|
box-shadow: inset 0 2rpx 0 rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-1 {
|
||||||
|
height: 88rpx;
|
||||||
|
background: linear-gradient(180deg, #ffe08a 0%, #ffc933 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-2 {
|
||||||
|
height: 64rpx;
|
||||||
|
background: linear-gradient(180deg, #ffe08a 0%, #ffd04d 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pedestal-3 {
|
||||||
|
height: 48rpx;
|
||||||
|
background: linear-gradient(180deg, #ffe08a 0%, #ffd04d 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 列表区(白底) ========== */
|
||||||
|
.list-panel {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 32rpx 32rpx 0 0;
|
||||||
|
padding: 24rpx 28rpx 0;
|
||||||
|
min-height: 400rpx;
|
||||||
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24rpx 0;
|
||||||
|
border-bottom: 1rpx solid #f3f3f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-rank {
|
||||||
|
width: 44rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333333;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-avatar {
|
||||||
|
width: 72rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 16rpx 0 8rpx;
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-name {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1a1a1a;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-right {
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: right;
|
||||||
|
margin-left: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-amount {
|
||||||
|
display: block;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-orders {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.li-reward {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #d48806;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-tip {
|
||||||
|
display: block;
|
||||||
|
padding: 0 24rpx 8rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-metrics {
|
.p-metrics {
|
||||||
@@ -292,176 +436,86 @@ page {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 6rpx;
|
gap: 6rpx;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: 16rpx;
|
margin: 8rpx 0 10rpx;
|
||||||
min-height: 36rpx;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-metric {
|
.p-metric {
|
||||||
font-size: 18rpx;
|
font-size: 20rpx;
|
||||||
color: rgba(255,255,255,0.55);
|
color: #888;
|
||||||
background: rgba(255,255,255,0.1);
|
background: rgba(255, 255, 255, 0.65);
|
||||||
padding: 4rpx 10rpx;
|
padding: 4rpx 10rpx;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底座 · 圆角柱体,非方块 */
|
.li-label {
|
||||||
.p-pedestal {
|
|
||||||
width: 88%;
|
|
||||||
border-radius: 20rpx 20rpx 0 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-pedestal::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0; left: 10%; right: 10%;
|
|
||||||
height: 2rpx;
|
|
||||||
background: rgba(255,255,255,0.15);
|
|
||||||
border-radius: 2rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pedestal-first {
|
|
||||||
height: 100rpx;
|
|
||||||
background: linear-gradient(180deg, rgba(107,163,247,0.55) 0%, rgba(107,163,247,0.22) 100%);
|
|
||||||
border: 1rpx solid rgba(107,163,247,0.35);
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pedestal-silver {
|
|
||||||
height: 72rpx;
|
|
||||||
background: linear-gradient(180deg, rgba(168,180,196,0.45) 0%, rgba(168,180,196,0.18) 100%);
|
|
||||||
border: 1rpx solid rgba(168,180,196,0.28);
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pedestal-bronze {
|
|
||||||
height: 56rpx;
|
|
||||||
background: linear-gradient(180deg, rgba(196,168,130,0.45) 0%, rgba(196,168,130,0.18) 100%);
|
|
||||||
border: 1rpx solid rgba(196,168,130,0.28);
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== 列表 ========== */
|
|
||||||
.list-wrap {
|
|
||||||
padding: 0 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-title-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 8rpx 8rpx 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: rgba(255,255,255,0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-range {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: rgba(255,255,255,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-card {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 14rpx;
|
|
||||||
border-radius: 18rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1rpx solid rgba(255,255,255,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-card-bg {
|
|
||||||
position: absolute;
|
|
||||||
top: 0; left: 0;
|
|
||||||
width: 100%; height: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-card-body {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx 22rpx;
|
|
||||||
background: rgba(12, 16, 28, 0.92);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-rank {
|
|
||||||
width: 48rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-rank text {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: rgba(255,255,255,0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-avatar {
|
|
||||||
width: 80rpx; height: 80rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin: 0 16rpx 0 6rpx;
|
|
||||||
border: 2rpx solid rgba(107, 163, 247, 0.2);
|
|
||||||
background: #1a2030;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-info { flex: 1; min-width: 0; }
|
|
||||||
|
|
||||||
.lc-name {
|
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 28rpx;
|
margin-top: 2rpx;
|
||||||
font-weight: 600;
|
|
||||||
color: rgba(255,255,255,0.92);
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-uid {
|
|
||||||
display: block;
|
|
||||||
margin-top: 4rpx;
|
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: rgba(255,255,255,0.32);
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-tags {
|
.li-tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8rpx;
|
gap: 6rpx;
|
||||||
margin-top: 8rpx;
|
justify-content: flex-end;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
max-width: 280rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-tag {
|
.li-tag {
|
||||||
font-size: 20rpx;
|
font-size: 20rpx;
|
||||||
color: rgba(255,255,255,0.5);
|
color: #888;
|
||||||
background: rgba(255,255,255,0.1);
|
background: #f5f5f5;
|
||||||
padding: 2rpx 10rpx;
|
padding: 2rpx 8rpx;
|
||||||
border-radius: 6rpx;
|
border-radius: 6rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-score {
|
.bottom-gap {
|
||||||
flex-shrink: 0;
|
height: 160rpx;
|
||||||
text-align: right;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-money {
|
/* ========== 领取栏 ========== */
|
||||||
display: block;
|
.claim-bar {
|
||||||
font-size: 28rpx;
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 20rpx 28rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top: 1rpx solid #f0f0f0;
|
||||||
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-amount {
|
||||||
|
font-size: 36rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #8EB8FF;
|
color: #ffb800;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-label {
|
.claim-btn {
|
||||||
display: block;
|
margin: 0;
|
||||||
margin-top: 2rpx;
|
padding: 0 40rpx;
|
||||||
font-size: 20rpx;
|
height: 72rpx;
|
||||||
color: rgba(255,255,255,0.32);
|
line-height: 72rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background: linear-gradient(135deg, #ffc107, #ffb300);
|
||||||
|
color: #1a1a1a;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-gap { height: 48rpx; }
|
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
// pages/fighter-recharge/fighter-deposit.js — 平台履约金/保证金独立页
|
||||||
|
import request from '../../utils/request';
|
||||||
|
import PopupService from '../../services/popupService.js';
|
||||||
|
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
||||||
|
import { ICON_KEYS, resolveConfiguredIcon, resolveMiniappIcon, ICON_FOLDER, refreshPindaoConfig } from '../../utils/miniapp-icons.js';
|
||||||
|
import { resolveAvatarFromStorage, onAvatarImageError } from '../../utils/avatar.js';
|
||||||
|
|
||||||
|
const app = getApp();
|
||||||
|
|
||||||
|
const DEFAULT_RULES = [
|
||||||
|
'履约金有效期为永久有效',
|
||||||
|
'超过15天未接单,可联系客服申请退还',
|
||||||
|
'缴纳后可优先接锁单/平台单等待遇',
|
||||||
|
];
|
||||||
|
|
||||||
|
const DEFAULT_BENEFITS = [
|
||||||
|
{ label: '平台订单优先', key: ICON_KEYS.FIGHTER_DEPOSIT_BENEFIT_1 },
|
||||||
|
{ label: '快人一步', key: ICON_KEYS.FIGHTER_DEPOSIT_BENEFIT_2 },
|
||||||
|
{ label: '优质接单', key: ICON_KEYS.FIGHTER_DEPOSIT_BENEFIT_3 },
|
||||||
|
{ label: '解锁平台单', key: ICON_KEYS.FIGHTER_DEPOSIT_BENEFIT_4 },
|
||||||
|
];
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
imgUrls: { pageBg: '', hero: '' },
|
||||||
|
avatarUrl: '',
|
||||||
|
nickname: '',
|
||||||
|
uid: '',
|
||||||
|
yajin: 0,
|
||||||
|
yajinDisplay: '0.00',
|
||||||
|
yajinActive: false,
|
||||||
|
depositRules: DEFAULT_RULES,
|
||||||
|
depositBenefits: DEFAULT_BENEFITS,
|
||||||
|
rulesTitle: '履约金规则',
|
||||||
|
benefitsTitle: '平台履约金权益',
|
||||||
|
pageCopy: null,
|
||||||
|
agreed: false,
|
||||||
|
payAmountLabel: '',
|
||||||
|
yajinAmount: '100',
|
||||||
|
quickAmounts: ['100', '500', '1000', '5000'],
|
||||||
|
showAmountModal: false,
|
||||||
|
showPayMethodModal: false,
|
||||||
|
showBalanceModal: false,
|
||||||
|
showConfirmModal: false,
|
||||||
|
balanceOptions: [],
|
||||||
|
selectedBalanceId: null,
|
||||||
|
selectedBalanceInfo: null,
|
||||||
|
currentYajinAmount: null,
|
||||||
|
currentDingdanid: '',
|
||||||
|
payLoading: false,
|
||||||
|
loadingText: '处理中...',
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(options) {
|
||||||
|
this._jumpParams = options || {};
|
||||||
|
this.initImages();
|
||||||
|
this.loadUserInfo();
|
||||||
|
this.fetchPageCopy();
|
||||||
|
},
|
||||||
|
|
||||||
|
onHide() {
|
||||||
|
this.selectComponent('#popupNotice')?.cleanup?.();
|
||||||
|
},
|
||||||
|
|
||||||
|
async onShow() {
|
||||||
|
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'dashou' });
|
||||||
|
if (!phoneOk) return;
|
||||||
|
this.registerNotification();
|
||||||
|
this.loadYajin();
|
||||||
|
this.refreshConfiguredIcons();
|
||||||
|
if (!this.data.pageCopy) {
|
||||||
|
this.fetchPageCopy();
|
||||||
|
}
|
||||||
|
PopupService.checkAndShow(this, 'dashouchongzhi');
|
||||||
|
const preset = this._jumpParams?.presetAmount || this._jumpParams?.requiredYajin;
|
||||||
|
if (preset && parseFloat(preset) > 0) {
|
||||||
|
this.setData({ yajinAmount: String(parseInt(preset, 10)) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
registerNotification() {
|
||||||
|
const comp = this.selectComponent('#global-notification');
|
||||||
|
if (comp?.showNotification) {
|
||||||
|
app.globalData.globalNotification = {
|
||||||
|
show: (data) => comp.showNotification(data),
|
||||||
|
hide: () => comp.hideNotification(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resolveOssUrl(path) {
|
||||||
|
if (!path) return '';
|
||||||
|
if (path.startsWith('http')) return path;
|
||||||
|
return (app.globalData.ossImageUrl || '') + path;
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchPageCopy() {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/jituan/recharge-page-copy',
|
||||||
|
method: 'POST',
|
||||||
|
data: { page_key: 'yajin' },
|
||||||
|
});
|
||||||
|
if (res.data && res.data.code === 0 && res.data.data) {
|
||||||
|
this.setData({ pageCopy: res.data.data.regions || {} });
|
||||||
|
} else {
|
||||||
|
this.setData({ pageCopy: {} });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('fetchPageCopy failed', e);
|
||||||
|
this.setData({ pageCopy: {} });
|
||||||
|
}
|
||||||
|
this.applyPageCopy();
|
||||||
|
},
|
||||||
|
|
||||||
|
applyPageCopy() {
|
||||||
|
const copy = this.data.pageCopy || {};
|
||||||
|
const patch = {};
|
||||||
|
|
||||||
|
const rulesRegion = copy.rules;
|
||||||
|
if (rulesRegion && Array.isArray(rulesRegion.items) && rulesRegion.items.length > 0) {
|
||||||
|
patch.depositRules = rulesRegion.items
|
||||||
|
.map((it) => (typeof it === 'string' ? it : (it && it.text) || ''))
|
||||||
|
.filter(Boolean);
|
||||||
|
if (rulesRegion.title) patch.rulesTitle = rulesRegion.title;
|
||||||
|
} else {
|
||||||
|
patch.depositRules = DEFAULT_RULES;
|
||||||
|
patch.rulesTitle = '履约金规则';
|
||||||
|
}
|
||||||
|
|
||||||
|
const benefitsRegion = copy.benefits;
|
||||||
|
const fb = (key) => `${ICON_FOLDER}/${key}.png`;
|
||||||
|
if (benefitsRegion && Array.isArray(benefitsRegion.items) && benefitsRegion.items.length > 0) {
|
||||||
|
patch.depositBenefits = benefitsRegion.items.map((item, i) => {
|
||||||
|
const fallback = DEFAULT_BENEFITS[i];
|
||||||
|
const iconUrl = item.icon_url
|
||||||
|
? this.resolveOssUrl(item.icon_url)
|
||||||
|
: (fallback
|
||||||
|
? resolveMiniappIcon(app, fallback.key, fb(fallback.key))
|
||||||
|
: '');
|
||||||
|
return {
|
||||||
|
label: item.label || item.title || '',
|
||||||
|
iconUrl,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (benefitsRegion.title) patch.benefitsTitle = benefitsRegion.title;
|
||||||
|
} else {
|
||||||
|
patch.depositBenefits = DEFAULT_BENEFITS.map((item) => ({
|
||||||
|
label: item.label,
|
||||||
|
iconUrl: resolveMiniappIcon(app, item.key, fb(item.key)),
|
||||||
|
}));
|
||||||
|
patch.benefitsTitle = '平台履约金权益';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData(patch);
|
||||||
|
},
|
||||||
|
|
||||||
|
initImages() {
|
||||||
|
const fb = (key) => `${ICON_FOLDER}/${key}.png`;
|
||||||
|
const depositBenefits = DEFAULT_BENEFITS.map((item) => ({
|
||||||
|
label: item.label,
|
||||||
|
iconUrl: resolveMiniappIcon(app, item.key, fb(item.key)),
|
||||||
|
}));
|
||||||
|
this.setData({
|
||||||
|
imgUrls: {
|
||||||
|
pageBg: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_DEPOSIT_BG),
|
||||||
|
hero: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_DEPOSIT_HERO),
|
||||||
|
},
|
||||||
|
depositBenefits,
|
||||||
|
});
|
||||||
|
if (this.data.pageCopy) {
|
||||||
|
this.applyPageCopy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async refreshConfiguredIcons() {
|
||||||
|
try {
|
||||||
|
await refreshPindaoConfig(app);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('refreshConfiguredIcons failed', e);
|
||||||
|
}
|
||||||
|
this.initImages();
|
||||||
|
this.loadUserInfo();
|
||||||
|
},
|
||||||
|
|
||||||
|
loadUserInfo() {
|
||||||
|
const gd = app.globalData || {};
|
||||||
|
this.setData({
|
||||||
|
avatarUrl: resolveAvatarFromStorage(app),
|
||||||
|
nickname: gd.dashouNicheng || gd.nicheng || '打手',
|
||||||
|
uid: wx.getStorageSync('uid') || gd.uid || '',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onAvatarError() {
|
||||||
|
onAvatarImageError(this, 'avatarUrl', app);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadYajin() {
|
||||||
|
const yajin = parseFloat(app.globalData.yajin || 0) || 0;
|
||||||
|
this.setData({
|
||||||
|
yajin,
|
||||||
|
yajinDisplay: yajin.toFixed(2),
|
||||||
|
yajinActive: yajin > 0,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAgree() {
|
||||||
|
this.setData({ agreed: !this.data.agreed });
|
||||||
|
},
|
||||||
|
|
||||||
|
onTapPay() {
|
||||||
|
if (!this.data.agreed) {
|
||||||
|
wx.showToast({ title: '请先阅读并同意缴纳规则', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setData({ showAmountModal: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
hideAmountModal() {
|
||||||
|
this.setData({ showAmountModal: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
onYajinInput(e) {
|
||||||
|
let v = (e.detail.value || '').replace(/[^\d]/g, '');
|
||||||
|
if (v) {
|
||||||
|
const n = parseInt(v, 10);
|
||||||
|
if (n > 10000) v = '10000';
|
||||||
|
if (n < 1) v = '1';
|
||||||
|
}
|
||||||
|
this.setData({ yajinAmount: v });
|
||||||
|
},
|
||||||
|
|
||||||
|
setQuickAmount(e) {
|
||||||
|
this.setData({ yajinAmount: e.currentTarget.dataset.amount });
|
||||||
|
},
|
||||||
|
|
||||||
|
onConfirmAmount() {
|
||||||
|
const amount = this.data.yajinAmount;
|
||||||
|
if (!amount || amount < 1 || amount > 10000) {
|
||||||
|
wx.showToast({ title: '请输入1-10000元', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.hideAmountModal();
|
||||||
|
this.setData({
|
||||||
|
currentYajinAmount: amount,
|
||||||
|
payAmountLabel: `(¥ ${amount})`,
|
||||||
|
showPayMethodModal: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
hidePayMethodModal() {
|
||||||
|
this.setData({ showPayMethodModal: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
onPayMethodSelect(e) {
|
||||||
|
const method = e.currentTarget.dataset.method;
|
||||||
|
this.hidePayMethodModal();
|
||||||
|
if (method === 'wx' || method === 'alipay') {
|
||||||
|
const payMethod = method === 'alipay' ? 'alipay' : 'wx';
|
||||||
|
this.setData({ yajinAmount: this.data.currentYajinAmount }, () => this.handleYajinPay(payMethod));
|
||||||
|
} else {
|
||||||
|
this.fetchBalanceOptions();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchBalanceOptions() {
|
||||||
|
this.showLoading('获取抵扣信息...');
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/shangpin/czhqdy',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
leixing: 2,
|
||||||
|
yajin_jine: parseInt(this.data.currentYajinAmount, 10),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
this.setData({ balanceOptions: res.data.data || [], showBalanceModal: true });
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: res.data.message || '获取失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
this.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hideBalanceModal() {
|
||||||
|
this.setData({ showBalanceModal: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
onBalanceSelect(e) {
|
||||||
|
const id = e.currentTarget.dataset.id;
|
||||||
|
const selected = this.data.balanceOptions.find((o) => o.id === id);
|
||||||
|
if (!selected) return;
|
||||||
|
this.setData({
|
||||||
|
selectedBalanceId: id,
|
||||||
|
selectedBalanceInfo: selected,
|
||||||
|
showConfirmModal: true,
|
||||||
|
showBalanceModal: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
hideConfirmModal() {
|
||||||
|
this.setData({ showConfirmModal: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
async confirmBalancePay() {
|
||||||
|
const { selectedBalanceId, currentYajinAmount } = this.data;
|
||||||
|
if (!selectedBalanceId) return;
|
||||||
|
this.hideConfirmModal();
|
||||||
|
this.showLoading('抵扣支付中...');
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/shangpin/dsqrgmdh',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
leixing: 2,
|
||||||
|
shenfen_id: selectedBalanceId,
|
||||||
|
yajin_jine: parseInt(currentYajinAmount, 10),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
const data = res.data.data || {};
|
||||||
|
if (data.yajin !== undefined) app.globalData.yajin = data.yajin;
|
||||||
|
this.loadYajin();
|
||||||
|
wx.showToast({ title: '缴纳成功', icon: 'success' });
|
||||||
|
this.showPaySuccessPopup();
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: res.data.message || '购买失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
this.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmWechatPurchase() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
wx.showModal({
|
||||||
|
title: '确认微信支付',
|
||||||
|
content: '您即将通过微信支付缴纳履约金。购买成功后不可随意退款,请确认无误后再继续。',
|
||||||
|
confirmText: '确认购买',
|
||||||
|
cancelText: '再想想',
|
||||||
|
success: (res) => resolve(!!res.confirm),
|
||||||
|
fail: () => resolve(false),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleYajinPay(payMethod = 'wx') {
|
||||||
|
const amount = this.data.yajinAmount;
|
||||||
|
if (!amount || amount < 1 || amount > 10000) {
|
||||||
|
wx.showToast({ title: '请输入1-10000元', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 支付宝无需微信确认弹窗
|
||||||
|
if (payMethod !== 'alipay' && !(await this.confirmWechatPurchase())) return;
|
||||||
|
this.showLoading('发起支付中...');
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/shangpin/yajingoumai',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
jine: parseInt(amount, 10),
|
||||||
|
pay_method: payMethod === 'alipay' ? 'alipay' : 'wechat',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
const payParams = res.data.payParams;
|
||||||
|
const dingdanid = res.data.dingdanid;
|
||||||
|
this.setData({ currentDingdanid: dingdanid });
|
||||||
|
// 支付宝分支:跳转二维码页
|
||||||
|
if (payMethod === 'alipay' || (payParams && payParams.pay_method === 'alipay')) {
|
||||||
|
this.hideLoading();
|
||||||
|
this.triggerAlipayPayment(payParams, dingdanid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.wechatPay(payParams);
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: res.data.message || '支付发起失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
wx.showToast({ title: '支付失败', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
this.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========== 支付宝扫码支付封装 ==========
|
||||||
|
triggerAlipayPayment(payParams, orderId) {
|
||||||
|
const qrImage = payParams && payParams.qr_image ? payParams.qr_image : '';
|
||||||
|
if (!qrImage) {
|
||||||
|
wx.showToast({ title: '支付宝二维码生成失败', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const app = getApp();
|
||||||
|
app.globalData.alipayQrImage = qrImage;
|
||||||
|
const pollUrl = encodeURIComponent('/shangpin/yajinlunxun');
|
||||||
|
const self = this;
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/alipay-webview/alipay-webview?orderId=${orderId}&pollUrl=${pollUrl}`,
|
||||||
|
events: {
|
||||||
|
// 支付宝支付成功后,更新押金全局变量并刷新页面
|
||||||
|
onAlipaySuccess: (res) => {
|
||||||
|
if (res && res.data && res.data.yajin !== undefined) {
|
||||||
|
app.globalData.yajin = res.data.yajin;
|
||||||
|
}
|
||||||
|
self.loadYajin();
|
||||||
|
wx.showToast({ title: '履约金缴纳成功', icon: 'success', duration: 2000 });
|
||||||
|
self.showPaySuccessPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
wechatPay(payParams) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
wx.requestPayment({
|
||||||
|
timeStamp: payParams.timeStamp,
|
||||||
|
nonceStr: payParams.nonceStr,
|
||||||
|
package: payParams.package,
|
||||||
|
signType: payParams.signType || 'MD5',
|
||||||
|
paySign: payParams.paySign,
|
||||||
|
success: async () => {
|
||||||
|
wx.showToast({ title: '支付成功!确认中...', icon: 'none' });
|
||||||
|
try {
|
||||||
|
await this.startPolling();
|
||||||
|
resolve();
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: async (res) => {
|
||||||
|
wx.showToast({ title: res.errMsg?.includes('cancel') ? '已取消支付' : '支付失败', icon: 'none' });
|
||||||
|
try {
|
||||||
|
await request({
|
||||||
|
url: '/shangpin/yajinshibai',
|
||||||
|
method: 'POST',
|
||||||
|
data: { dingdanid: this.data.currentDingdanid },
|
||||||
|
});
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
reject(new Error(res.errMsg));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async startPolling() {
|
||||||
|
const dingdanid = this.data.currentDingdanid;
|
||||||
|
if (!dingdanid) return;
|
||||||
|
this.showLoading('确认支付结果...');
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/shangpin/yajinlunxun',
|
||||||
|
method: 'POST',
|
||||||
|
data: { dingdanid },
|
||||||
|
});
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
if (res.data.yajin !== undefined) app.globalData.yajin = res.data.yajin;
|
||||||
|
this.loadYajin();
|
||||||
|
this.hideLoading();
|
||||||
|
wx.showToast({ title: '履约金缴纳成功', icon: 'success' });
|
||||||
|
this.showPaySuccessPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) { /* retry */ }
|
||||||
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
|
}
|
||||||
|
this.hideLoading();
|
||||||
|
wx.showToast({ title: '确认超时,请稍后查看余额', icon: 'none' });
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoading(text) {
|
||||||
|
this.setData({ payLoading: true, loadingText: text || '处理中...' });
|
||||||
|
},
|
||||||
|
|
||||||
|
hideLoading() {
|
||||||
|
this.setData({ payLoading: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 缴纳成功后弹出后台可配置公告(页面标识 yajinchenggong) */
|
||||||
|
showPaySuccessPopup() {
|
||||||
|
try {
|
||||||
|
PopupService.reset();
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
setTimeout(() => {
|
||||||
|
PopupService.checkAndShow(this, 'yajinchenggong');
|
||||||
|
}, 450);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopPropagation() {},
|
||||||
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"global-notification": "/components/global-notification/global-notification",
|
||||||
|
"popup-notice": "/components/popup-notice/popup-notice"
|
||||||
|
},
|
||||||
|
"navigationBarTitleText": "平台履约金",
|
||||||
|
"navigationBarBackgroundColor": "#FFF9F0",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#FFF9F0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<!-- 平台履约金 / 保证金充值页 -->
|
||||||
|
<view class="deposit-page">
|
||||||
|
<image wx:if="{{imgUrls.pageBg}}" class="page-bg" src="{{imgUrls.pageBg}}" mode="widthFix" />
|
||||||
|
<view class="page-bg-fallback" wx:else></view>
|
||||||
|
|
||||||
|
<view class="page-body">
|
||||||
|
<view class="user-row">
|
||||||
|
<image class="user-avatar" src="{{avatarUrl}}" mode="aspectFill" binderror="onAvatarError" />
|
||||||
|
<view class="user-info">
|
||||||
|
<text class="user-name">{{nickname || '打手'}}</text>
|
||||||
|
<text class="user-id">会员ID: {{uid || '--'}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="deposit-card">
|
||||||
|
<view class="deposit-card-left">
|
||||||
|
<text class="deposit-card-title">平台接单履约金</text>
|
||||||
|
<view class="deposit-price-row">
|
||||||
|
<text class="deposit-currency">¥</text>
|
||||||
|
<text class="deposit-price">{{yajinDisplay}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="deposit-validity">有效期:永久有效</text>
|
||||||
|
</view>
|
||||||
|
<view class="deposit-card-right">
|
||||||
|
<view class="icon-clip icon-clip-deposit" wx:if="{{imgUrls.hero}}">
|
||||||
|
<image class="icon-clip-img" src="{{imgUrls.hero}}" mode="aspectFill" />
|
||||||
|
</view>
|
||||||
|
<view class="deposit-status">{{yajinActive ? '已缴纳' : '未激活'}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="deposit-shimmer"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="section-card">
|
||||||
|
<text class="section-title">{{rulesTitle || '履约金规则'}}</text>
|
||||||
|
<view class="rule-list">
|
||||||
|
<view wx:for="{{depositRules}}" wx:key="index" class="rule-item">
|
||||||
|
<text class="rule-num">{{index + 1}}.</text>
|
||||||
|
<text class="rule-text">{{item}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="section-card">
|
||||||
|
<text class="section-title">{{benefitsTitle || '平台履约金权益'}}</text>
|
||||||
|
<view class="benefit-grid">
|
||||||
|
<view wx:for="{{depositBenefits}}" wx:key="label" class="benefit-item">
|
||||||
|
<view wx:if="{{item.iconUrl}}" class="icon-clip icon-clip-deposit-benefit">
|
||||||
|
<image class="icon-clip-img" src="{{item.iconUrl}}" mode="aspectFill" />
|
||||||
|
</view>
|
||||||
|
<text>{{item.label}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="footer-bar">
|
||||||
|
<view class="agree-row" bindtap="toggleAgree">
|
||||||
|
<view class="agree-check {{agreed ? 'agree-check--on' : ''}}">{{agreed ? '✓' : ''}}</view>
|
||||||
|
<text class="agree-text">已阅读并同意</text>
|
||||||
|
<text class="agree-link">《平台履约金缴纳规则》</text>
|
||||||
|
</view>
|
||||||
|
<view class="pay-btn {{agreed ? '' : 'pay-btn--disabled'}}" bindtap="onTapPay">
|
||||||
|
<text>缴纳履约金{{payAmountLabel}}</text>
|
||||||
|
<view class="pay-btn-shimmer"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 金额输入弹窗 -->
|
||||||
|
<view class="modal-mask" wx:if="{{showAmountModal}}" bindtap="hideAmountModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">缴纳履约金</text>
|
||||||
|
<text class="modal-sub">支持 1-10000 元整数</text>
|
||||||
|
<view class="amount-input-wrap">
|
||||||
|
<text class="amount-prefix">¥</text>
|
||||||
|
<input class="amount-input" type="digit" value="{{yajinAmount}}" bindinput="onYajinInput" focus="{{showAmountModal}}" />
|
||||||
|
</view>
|
||||||
|
<view class="quick-row">
|
||||||
|
<view wx:for="{{quickAmounts}}" wx:key="*this" class="quick-chip {{yajinAmount == item ? 'active' : ''}}" bindtap="setQuickAmount" data-amount="{{item}}">{{item}}元</view>
|
||||||
|
</view>
|
||||||
|
<view class="modal-actions">
|
||||||
|
<view class="modal-btn cancel" bindtap="hideAmountModal">取消</view>
|
||||||
|
<view class="modal-btn confirm" bindtap="onConfirmAmount">下一步</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 支付方式 -->
|
||||||
|
<view class="modal-mask" wx:if="{{showPayMethodModal}}" bindtap="hidePayMethodModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">选择支付方式</text>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="wx">
|
||||||
|
<text class="pay-method-name">微信支付</text>
|
||||||
|
<text class="pay-method-desc">安全快捷</text>
|
||||||
|
</view>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="alipay">
|
||||||
|
<text class="pay-method-name">支付宝</text>
|
||||||
|
<text class="pay-method-desc">扫码支付</text>
|
||||||
|
</view>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="balance">
|
||||||
|
<text class="pay-method-name">余额抵扣</text>
|
||||||
|
<text class="pay-method-desc">使用佣金或分红</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="modal-mask" wx:if="{{showBalanceModal}}" bindtap="hideBalanceModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">选择抵扣身份</text>
|
||||||
|
<view wx:for="{{balanceOptions}}" wx:key="id" class="balance-item" bindtap="onBalanceSelect" data-id="{{item.id}}">
|
||||||
|
<text>{{item.jieshao}}</text>
|
||||||
|
<text class="balance-need">需¥{{item.xuyao}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="modal-mask" wx:if="{{showConfirmModal}}" bindtap="hideConfirmModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">确认抵扣</text>
|
||||||
|
<view class="confirm-row"><text>身份</text><text>{{selectedBalanceInfo.jieshao}}</text></view>
|
||||||
|
<view class="confirm-row"><text>金额</text><text>¥{{selectedBalanceInfo.xuyao}}</text></view>
|
||||||
|
<view class="modal-actions">
|
||||||
|
<view class="modal-btn cancel" bindtap="hideConfirmModal">取消</view>
|
||||||
|
<view class="modal-btn confirm" bindtap="confirmBalancePay">确认支付</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="loading-mask" wx:if="{{payLoading}}">
|
||||||
|
<view class="loading-box">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
<text>{{loadingText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification" />
|
||||||
|
<popup-notice id="popupNotice" />
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
@import '../../styles/xym-recharge-shared.wxss';
|
||||||
|
|
||||||
|
.deposit-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #fff9f0;
|
||||||
|
padding-bottom: calc(220rpx + env(safe-area-inset-bottom));
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-bg-fallback {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 360rpx;
|
||||||
|
background: linear-gradient(180deg, #ffe082 0%, #fff9f0 100%);
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-body {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 24rpx 30rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 88rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-id {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 32rpx 28rpx;
|
||||||
|
background: linear-gradient(135deg, #fff8e1 0%, #ffe0b2 100%);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: stretch;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(255, 183, 77, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-card-left {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-card-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #492f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-price-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
margin: 16rpx 0 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-currency {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
|
margin-right: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-price {
|
||||||
|
font-size: 64rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #222;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-validity {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #947641;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-card-right {
|
||||||
|
position: relative;
|
||||||
|
width: 200rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clip {
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clip-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clip-deposit {
|
||||||
|
width: 180rpx;
|
||||||
|
height: 180rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clip-deposit-benefit {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-status {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-shimmer {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.45) 50%, transparent 60%);
|
||||||
|
animation: card-shimmer 3s infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
padding: 28rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 8rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 20rpx 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 20rpx 30rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
background: rgba(255, 249, 240, 0.96);
|
||||||
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree-check {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2rpx solid #ccc;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree-check--on {
|
||||||
|
background: #f5a623;
|
||||||
|
border-color: #f5a623;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree-link {
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 96rpx;
|
||||||
|
border-radius: 48rpx;
|
||||||
|
background: linear-gradient(90deg, #fae04d, #ffc0a3);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #492f00;
|
||||||
|
box-shadow: 0 8rpx 20rpx rgba(245, 166, 35, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn--disabled {
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn-shimmer {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.5) 50%, transparent 60%);
|
||||||
|
animation: btn-shimmer 2.5s infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes card-shimmer {
|
||||||
|
0% { transform: translateX(-120%); }
|
||||||
|
100% { transform: translateX(120%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes btn-shimmer {
|
||||||
|
0% { transform: translateX(-120%); }
|
||||||
|
100% { transform: translateX(120%); }
|
||||||
|
}
|
||||||
@@ -1,72 +1,62 @@
|
|||||||
// pages/dashou-chongzhi/index.js
|
// pages/fighter-recharge/fighter-recharge.js
|
||||||
import request from '../../utils/request';
|
import request from '../../utils/request';
|
||||||
import PopupService from '../../services/popupService.js';
|
import PopupService from '../../services/popupService.js';
|
||||||
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
||||||
|
import { ICON_KEYS, resolveConfiguredIcon, resolveMiniappIcon, ICON_FOLDER, refreshPindaoConfig } from '../../utils/miniapp-icons.js';
|
||||||
|
import { resolveAvatarFromStorage, onAvatarImageError } from '../../utils/avatar.js';
|
||||||
|
import { refreshDashouMembership } from '../../utils/dashou-profile.js';
|
||||||
|
|
||||||
|
const app = getApp();
|
||||||
|
|
||||||
|
const PLATFORM_ADVANTAGE_META = [
|
||||||
|
{ key: ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_1, title: '订单丰富', desc: '平台单、商家单多种类型' },
|
||||||
|
{ key: ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_2, title: '俱乐部专属', desc: '按俱乐部独立配置权益' },
|
||||||
|
{ key: ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_3, title: '客服支持', desc: '遇到问题随时联系客服' },
|
||||||
|
{ key: ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_4, title: '安全可靠', desc: '资金与订单平台保障' },
|
||||||
|
];
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
// ========== 全局数据 ==========
|
imgUrls: { pageBg: '' },
|
||||||
clubmber: [], // 会员列表(注意:全局变量中是 clumber,这里保持原样)
|
avatarUrl: '',
|
||||||
yajin: 0, // 押金
|
nickname: '',
|
||||||
jifen: 0, // 积分(注意:全局变量中是 jinfen)
|
uid: '',
|
||||||
jifenProgress: 0, // 积分进度条角度
|
memberBadge: '会员',
|
||||||
|
agreed: false,
|
||||||
// ========== 会员商品列表 ==========
|
memberBenefits: [],
|
||||||
huiyuanList: [], // 从后端获取的会员列表
|
platformAdvantages: [],
|
||||||
currentHuiyuanIndex: 0, // 当前选中的会员索引
|
clubmber: [],
|
||||||
currentHuiyuan: {}, // 当前选中的会员详情
|
jifen: 0,
|
||||||
|
huiyuanList: [],
|
||||||
// ========== 押金充值相关 ==========
|
currentHuiyuanIndex: 0,
|
||||||
showYajinModal: false, // 显示押金弹窗
|
currentHuiyuan: {},
|
||||||
yajinAmount: '100', // 押金金额
|
payLoading: false,
|
||||||
|
|
||||||
// ========== 支付相关 ==========
|
|
||||||
payLoading: false, // 支付加载状态
|
|
||||||
loadingText: '支付中...',
|
loadingText: '支付中...',
|
||||||
|
currentDingdanid: '',
|
||||||
// ========== 订单ID记录 ==========
|
|
||||||
currentDingdanid: '', // 当前操作的订单ID
|
|
||||||
|
|
||||||
// ========== 计算高度 ==========
|
|
||||||
huiyuanListHeight: 120,
|
|
||||||
|
|
||||||
// ========== 会员详情规则 ==========
|
|
||||||
detailRules: [],
|
detailRules: [],
|
||||||
|
rulesTitle: '',
|
||||||
// ========== 新增:跳转参数处理 ==========
|
benefitsTitle: '',
|
||||||
// 用于接收从其他页面跳转过来的参数,决定是否自动滚动
|
advantagesTitle: '平台优势',
|
||||||
|
pageCopy: null,
|
||||||
jumpParams: {},
|
jumpParams: {},
|
||||||
|
showPayMethodModal: false,
|
||||||
// ========== 新增:支付方式选择 ==========
|
currentBuyType: null,
|
||||||
showPayMethodModal: false, // 支付方式选择弹窗
|
currentHuiyuanId: null,
|
||||||
currentBuyType: null, // 当前购买类型:1会员 2押金 3积分
|
currentBuyIsTrial: false,
|
||||||
currentHuiyuanId: null, // 当前选中的会员ID(用于会员购买)
|
showBalanceModal: false,
|
||||||
currentBuyIsTrial: false, // 正式/体验:仅体验禁余额抵扣
|
balanceOptions: [],
|
||||||
currentYajinAmount: null, // 当前押金金额(用于押金购买)
|
selectedBalanceId: null,
|
||||||
|
showConfirmModal: false,
|
||||||
// ========== 新增:余额抵扣身份选择 ==========
|
selectedBalanceInfo: null,
|
||||||
showBalanceModal: false, // 余额抵扣身份选择弹窗
|
|
||||||
balanceOptions: [], // 后端返回的身份列表
|
|
||||||
selectedBalanceId: null, // 选中的身份ID
|
|
||||||
|
|
||||||
// ========== 新增:余额抵扣确认弹窗 ==========
|
|
||||||
showConfirmModal: false, // 余额抵扣确认弹窗
|
|
||||||
selectedBalanceInfo: null, // 选中的身份详情(用于确认弹窗)
|
|
||||||
|
|
||||||
// ========== 新增:会员详情弹窗 ==========
|
|
||||||
showMemberModal: false,
|
showMemberModal: false,
|
||||||
currentMemberDetail: null,
|
currentMemberDetail: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 生命周期函数 ==========
|
// ========== 生命周期函数 ==========
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
//console.log('页面加载,跳转参数:', options);
|
this.setData({ jumpParams: options || {} });
|
||||||
|
this.initImages();
|
||||||
// ✅ 新增:保存跳转参数
|
this.loadUserInfo();
|
||||||
this.setData({
|
|
||||||
jumpParams: options || {}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.initPage();
|
this.initPage();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -86,6 +76,7 @@ onHide() {
|
|||||||
this.registerNotificationComponent();
|
this.registerNotificationComponent();
|
||||||
this.loadFromGlobalData();
|
this.loadFromGlobalData();
|
||||||
this.checkAndRefreshData();
|
this.checkAndRefreshData();
|
||||||
|
this.refreshConfiguredIcons();
|
||||||
|
|
||||||
// 调用统一弹窗组件检查并展示公告
|
// 调用统一弹窗组件检查并展示公告
|
||||||
PopupService.checkAndShow(this, 'dashouchongzhi');
|
PopupService.checkAndShow(this, 'dashouchongzhi');
|
||||||
@@ -112,16 +103,210 @@ onHide() {
|
|||||||
|
|
||||||
// ========== 初始化页面 ==========
|
// ========== 初始化页面 ==========
|
||||||
async initPage() {
|
async initPage() {
|
||||||
// 从全局数据加载
|
|
||||||
this.loadFromGlobalData();
|
this.loadFromGlobalData();
|
||||||
|
await this.fetchPageCopy();
|
||||||
// 获取会员商品列表
|
|
||||||
await this.fetchHuiyuanList();
|
await this.fetchHuiyuanList();
|
||||||
|
|
||||||
// 计算会员列表高度
|
|
||||||
this.calculateHuiyuanHeight();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async fetchPageCopy() {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/jituan/recharge-page-copy',
|
||||||
|
method: 'POST',
|
||||||
|
data: { page_key: 'huiyuan' },
|
||||||
|
});
|
||||||
|
if (res.data && res.data.code === 0 && res.data.data) {
|
||||||
|
this.setData({ pageCopy: res.data.data.regions || {} });
|
||||||
|
} else {
|
||||||
|
this.setData({ pageCopy: {} });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('fetchPageCopy failed', e);
|
||||||
|
this.setData({ pageCopy: {} });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initImages() {
|
||||||
|
this.setData({
|
||||||
|
imgUrls: {
|
||||||
|
pageBg: resolveConfiguredIcon(app, ICON_KEYS.FIGHTER_RECHARGE_VIP_BG),
|
||||||
|
},
|
||||||
|
platformAdvantages: this.buildPlatformAdvantages(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async refreshConfiguredIcons() {
|
||||||
|
try {
|
||||||
|
await refreshPindaoConfig(app);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('refreshConfiguredIcons failed', e);
|
||||||
|
}
|
||||||
|
this.initImages();
|
||||||
|
const list = this.data.huiyuanList || [];
|
||||||
|
const idx = this.data.currentHuiyuanIndex || 0;
|
||||||
|
if (list.length) {
|
||||||
|
this.applyCurrentHuiyuan(list[idx] || {}, idx);
|
||||||
|
}
|
||||||
|
this.loadUserInfo();
|
||||||
|
},
|
||||||
|
|
||||||
|
_icon(key, fallbackRel) {
|
||||||
|
return resolveMiniappIcon(app, key, fallbackRel);
|
||||||
|
},
|
||||||
|
|
||||||
|
buildPlatformAdvantages() {
|
||||||
|
const fb = (name) => `${ICON_FOLDER}/${name}.png`;
|
||||||
|
const region = (this.data.pageCopy || {}).advantages;
|
||||||
|
if (region && Array.isArray(region.items) && region.items.length > 0) {
|
||||||
|
return region.items.map((item, i) => {
|
||||||
|
const fallbackKey = [
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_1,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_2,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_3,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_4,
|
||||||
|
][i];
|
||||||
|
const iconUrl = item.icon_url
|
||||||
|
? this.resolveOssUrl(item.icon_url)
|
||||||
|
: (fallbackKey ? this._icon(fallbackKey, fb(fallbackKey)) : '');
|
||||||
|
return {
|
||||||
|
title: item.title || '',
|
||||||
|
desc: item.desc || '',
|
||||||
|
iconUrl,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const keys = [
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_1,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_2,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_3,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_ADVANTAGE_4,
|
||||||
|
];
|
||||||
|
return PLATFORM_ADVANTAGE_META.map((item, i) => ({
|
||||||
|
title: item.title,
|
||||||
|
desc: item.desc,
|
||||||
|
iconUrl: this._icon(keys[i], fb(keys[i])),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
loadUserInfo() {
|
||||||
|
const gd = app.globalData || {};
|
||||||
|
this.setData({
|
||||||
|
avatarUrl: resolveAvatarFromStorage(app),
|
||||||
|
nickname: gd.dashouNicheng || gd.nicheng || '打手',
|
||||||
|
uid: wx.getStorageSync('uid') || gd.uid || '',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onAvatarError() {
|
||||||
|
onAvatarImageError(this, 'avatarUrl', app);
|
||||||
|
},
|
||||||
|
|
||||||
|
resolveOssUrl(path) {
|
||||||
|
if (!path) return '';
|
||||||
|
if (path.startsWith('http')) return path;
|
||||||
|
return (app.globalData.ossImageUrl || '') + path;
|
||||||
|
},
|
||||||
|
|
||||||
|
buildMemberBenefits(huiyuan = {}) {
|
||||||
|
const region = (this.data.pageCopy || {}).benefits;
|
||||||
|
const fb = (name) => `${ICON_FOLDER}/${name}.png`;
|
||||||
|
if (region && Array.isArray(region.items) && region.items.length > 0) {
|
||||||
|
const fallbackKeys = [
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_1,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_2,
|
||||||
|
ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_3,
|
||||||
|
];
|
||||||
|
return region.items.map((item, i) => {
|
||||||
|
const key = fallbackKeys[i];
|
||||||
|
const iconUrl = item.icon_url
|
||||||
|
? this.resolveOssUrl(item.icon_url)
|
||||||
|
: (key ? this._icon(key, fb(key)) : '');
|
||||||
|
return {
|
||||||
|
title: item.title || '',
|
||||||
|
desc: item.desc || '',
|
||||||
|
iconUrl,
|
||||||
|
accentColor: item.accent_color || '',
|
||||||
|
accentStyle: item.accent_color ? `color:${item.accent_color}` : '',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const name = huiyuan.mingzi || '会员';
|
||||||
|
const formalPrice = huiyuan.jiage || '0';
|
||||||
|
const trialPrice = huiyuan.trial_price || '0';
|
||||||
|
const meta = [
|
||||||
|
{
|
||||||
|
key: ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_1,
|
||||||
|
title: '充值立得',
|
||||||
|
desc: `开通${name}正式版 ¥${formalPrice},享优先接单`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_2,
|
||||||
|
title: '体验尝鲜',
|
||||||
|
desc: huiyuan.can_buy_trial
|
||||||
|
? `体验版 ¥${trialPrice}/${huiyuan.trial_days || 0}天,终身1次`
|
||||||
|
: '正式会员支持余额抵扣',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ICON_KEYS.FIGHTER_RECHARGE_BENEFIT_3,
|
||||||
|
title: '专属特权',
|
||||||
|
desc: '解锁平台单、优质接单等待遇',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return meta.map((item) => ({
|
||||||
|
title: item.title,
|
||||||
|
desc: item.desc,
|
||||||
|
iconUrl: this._icon(item.key, fb(item.key)),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
applyCurrentHuiyuan(huiyuan, index) {
|
||||||
|
const copy = this.data.pageCopy || {};
|
||||||
|
const name = huiyuan.mingzi || '会员';
|
||||||
|
const rulesTitle = (copy.rules && copy.rules.title)
|
||||||
|
|| `${name}规则`;
|
||||||
|
const benefitsTitle = (copy.benefits && copy.benefits.title)
|
||||||
|
|| `${name}专属权益`;
|
||||||
|
const advantagesTitle = (copy.advantages && copy.advantages.title)
|
||||||
|
|| '平台优势';
|
||||||
|
this.setData({
|
||||||
|
currentHuiyuanIndex: index,
|
||||||
|
currentHuiyuan: huiyuan,
|
||||||
|
detailRules: this.buildDetailRules(huiyuan),
|
||||||
|
memberBenefits: this.buildMemberBenefits(huiyuan),
|
||||||
|
platformAdvantages: this.buildPlatformAdvantages(),
|
||||||
|
rulesTitle,
|
||||||
|
benefitsTitle,
|
||||||
|
advantagesTitle,
|
||||||
|
memberBadge: huiyuan.mingzi || '会员',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAgree() {
|
||||||
|
this.setData({ agreed: !this.data.agreed });
|
||||||
|
},
|
||||||
|
|
||||||
|
goToDeposit() {
|
||||||
|
wx.navigateTo({ url: '/pages/fighter-recharge/fighter-deposit' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onTapTrial(e) {
|
||||||
|
if (!this.data.agreed) {
|
||||||
|
wx.showToast({ title: '请先阅读并同意会员协议', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onBuyHuiyuanClick(e);
|
||||||
|
},
|
||||||
|
|
||||||
|
onTapFormal(e) {
|
||||||
|
if (!this.data.agreed) {
|
||||||
|
wx.showToast({ title: '请先阅读并同意会员协议', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onBuyHuiyuanClick(e);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopPropagation() {},
|
||||||
|
|
||||||
// ========== 从全局变量加载数据 ==========
|
// ========== 从全局变量加载数据 ==========
|
||||||
loadFromGlobalData() {
|
loadFromGlobalData() {
|
||||||
const app = getApp();
|
const app = getApp();
|
||||||
@@ -130,37 +315,12 @@ onHide() {
|
|||||||
// ✅ 重要:保持字段对应关系
|
// ✅ 重要:保持字段对应关系
|
||||||
// 全局变量中是 clumber,页面中是 clubmber
|
// 全局变量中是 clumber,页面中是 clubmber
|
||||||
// 全局变量中是 jinfen,页面中是 jifen
|
// 全局变量中是 jinfen,页面中是 jifen
|
||||||
this.setData({
|
const rawClubmber = globalData.clumber || [];
|
||||||
clubmber: globalData.clumber || [],
|
const clubmber = rawClubmber.filter((c) => c && c.huiyuanid);
|
||||||
yajin: globalData.yajin || 0,
|
|
||||||
jifen: globalData.jinfen || 0 // ✅ 注意:这里从 jinfen 读取
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算积分进度条
|
|
||||||
this.calculateJifenProgress();
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========== 计算积分进度条角度 ==========
|
|
||||||
calculateJifenProgress() {
|
|
||||||
const jifen = this.data.jifen || 0;
|
|
||||||
const progress = (jifen / 10) * 360; // 满分10分
|
|
||||||
this.setData({
|
this.setData({
|
||||||
jifenProgress: progress
|
clubmber: clubmber,
|
||||||
});
|
jifen: globalData.jinfen || 0,
|
||||||
},
|
|
||||||
|
|
||||||
// ========== 计算会员列表高度 ==========
|
|
||||||
calculateHuiyuanHeight() {
|
|
||||||
const clubmber = this.data.clubmber || [];
|
|
||||||
|
|
||||||
const itemHeight = 100; // 每个会员标签高度
|
|
||||||
const maxHeight = 300; // 最大高度(3个会员)
|
|
||||||
|
|
||||||
let height = clubmber.length * itemHeight;
|
|
||||||
height = Math.min(height, maxHeight);
|
|
||||||
|
|
||||||
this.setData({
|
|
||||||
huiyuanListHeight: height
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -174,17 +334,15 @@ onHide() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
const huiyuanList = res.data.data || [];
|
const huiyuanList = this.processHuiyuanList(res.data.data || []);
|
||||||
|
let index = 0;
|
||||||
// 处理数据,标记已购买的会员
|
const targetId = this.data.jumpParams.huiyuanId;
|
||||||
const processedList = this.processHuiyuanList(huiyuanList);
|
if (targetId) {
|
||||||
|
const found = huiyuanList.findIndex((h) => String(h.id) === String(targetId));
|
||||||
const currentHuiyuan = processedList[0] || {};
|
if (found >= 0) index = found;
|
||||||
this.setData({
|
}
|
||||||
huiyuanList: processedList,
|
this.applyCurrentHuiyuan(huiyuanList[index] || {}, index);
|
||||||
currentHuiyuan,
|
this.setData({ huiyuanList });
|
||||||
detailRules: this.buildDetailRules(currentHuiyuan)
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({
|
wx.showToast({
|
||||||
title: res.data.message || '获取会员列表失败',
|
title: res.data.message || '获取会员列表失败',
|
||||||
@@ -211,7 +369,9 @@ onHide() {
|
|||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
isBought: !!boughtItem,
|
isBought: !!boughtItem,
|
||||||
buyInfo: boughtItem || null
|
buyInfo: boughtItem || null,
|
||||||
|
cardImageUrl: this.resolveOssUrl(item.card_image),
|
||||||
|
cardBgUrl: this.resolveOssUrl(item.card_bg),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -220,43 +380,34 @@ onHide() {
|
|||||||
onSwiperChange(e) {
|
onSwiperChange(e) {
|
||||||
const current = e.detail.current;
|
const current = e.detail.current;
|
||||||
const huiyuanList = this.data.huiyuanList || [];
|
const huiyuanList = this.data.huiyuanList || [];
|
||||||
const currentHuiyuan = huiyuanList[current] || {};
|
this.applyCurrentHuiyuan(huiyuanList[current] || {}, current);
|
||||||
|
|
||||||
this.setData({
|
|
||||||
currentHuiyuanIndex: current,
|
|
||||||
currentHuiyuan,
|
|
||||||
detailRules: this.buildDetailRules(currentHuiyuan)
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 手动选择会员 ==========
|
|
||||||
selectHuiyuan(e) {
|
selectHuiyuan(e) {
|
||||||
const index = e.currentTarget.dataset.index;
|
const index = e.currentTarget.dataset.index;
|
||||||
const huiyuanList = this.data.huiyuanList || [];
|
const huiyuanList = this.data.huiyuanList || [];
|
||||||
|
this.applyCurrentHuiyuan(huiyuanList[index] || {}, index);
|
||||||
const currentHuiyuan = huiyuanList[index] || {};
|
|
||||||
this.setData({
|
|
||||||
currentHuiyuanIndex: index,
|
|
||||||
currentHuiyuan,
|
|
||||||
detailRules: this.buildDetailRules(currentHuiyuan)
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
buildDetailRules(huiyuan = {}) {
|
buildDetailRules(huiyuan = {}) {
|
||||||
|
const region = (this.data.pageCopy || {}).rules;
|
||||||
|
if (region && Array.isArray(region.items) && region.items.length > 0) {
|
||||||
|
return region.items
|
||||||
|
.map((it) => (typeof it === 'string' ? it : (it && it.text) || ''))
|
||||||
|
.filter(Boolean)
|
||||||
|
.slice(0, 4);
|
||||||
|
}
|
||||||
const formalDays = huiyuan.formal_days || 30;
|
const formalDays = huiyuan.formal_days || 30;
|
||||||
const rules = [
|
const rules = [
|
||||||
`正式会员有效期为${formalDays}天,从购买当天开始计算`,
|
`有效期${formalDays}天`,
|
||||||
'会员期间享受优先接单特权',
|
'可接多种订单类型',
|
||||||
'支持随时续费,未过期续费天数叠加,已过期从今天重新计算'
|
'支持续费,天数叠加',
|
||||||
|
'正式会员支持余额抵扣',
|
||||||
];
|
];
|
||||||
if (huiyuan.can_buy_trial) {
|
if (huiyuan.can_buy_trial) {
|
||||||
rules.push(`体验会员终身仅可购买1次(${huiyuan.trial_days || 0}天),体验期仅限制佣金提现`);
|
rules[3] = `体验版¥${huiyuan.trial_price}/${huiyuan.trial_days}天`;
|
||||||
}
|
}
|
||||||
if (huiyuan.trial_enabled && !huiyuan.can_buy_trial) {
|
return rules.slice(0, 4);
|
||||||
rules.push('您已使用过该会员的体验资格');
|
|
||||||
}
|
|
||||||
rules.push('体验会员仅支持微信支付;正式会员可使用佣金、分红或押金抵扣');
|
|
||||||
return rules;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 格式化到期时间 ==========
|
// ========== 格式化到期时间 ==========
|
||||||
@@ -310,109 +461,10 @@ onHide() {
|
|||||||
// ========== 处理自动滚动 ==========
|
// ========== 处理自动滚动 ==========
|
||||||
handleAutoScroll() {
|
handleAutoScroll() {
|
||||||
const { jumpParams } = this.data;
|
const { jumpParams } = this.data;
|
||||||
|
if (!jumpParams || jumpParams.scrollTo !== 'jifen') return;
|
||||||
if (!jumpParams || !jumpParams.needScroll) return;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let scrollTop = 0;
|
wx.pageScrollTo({ selector: '#jifen-section', duration: 300 });
|
||||||
|
}, 600);
|
||||||
if (jumpParams.scrollTo === 'bottom') {
|
|
||||||
scrollTop = 2000;
|
|
||||||
} else if (jumpParams.scrollTo === 'member') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scrollTop > 0) {
|
|
||||||
wx.pageScrollTo({
|
|
||||||
scrollTop: scrollTop,
|
|
||||||
duration: 300
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 800);
|
|
||||||
},
|
|
||||||
|
|
||||||
// ========== 押金充值相关 ==========
|
|
||||||
showYajinModal() {
|
|
||||||
this.setData({
|
|
||||||
showYajinModal: true,
|
|
||||||
yajinAmount: '100'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
hideYajinModal() {
|
|
||||||
this.setData({
|
|
||||||
showYajinModal: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onYajinInput(e) {
|
|
||||||
let value = e.detail.value;
|
|
||||||
value = value.replace(/[^\d]/g, '');
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
const num = parseInt(value);
|
|
||||||
if (num < 1) value = '1';
|
|
||||||
if (num > 10000) value = '10000';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setData({
|
|
||||||
yajinAmount: value
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setYajinAmount(e) {
|
|
||||||
const amount = e.currentTarget.dataset.amount;
|
|
||||||
this.setData({
|
|
||||||
yajinAmount: amount
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async handleYajinPay() {
|
|
||||||
const amount = this.data.yajinAmount;
|
|
||||||
|
|
||||||
if (!amount || amount < 1 || amount > 10000) {
|
|
||||||
wx.showToast({
|
|
||||||
title: '请输入1-10000元的金额',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showLoading('发起支付中...');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await request({
|
|
||||||
url: '/shangpin/yajingoumai',
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
jine: parseInt(amount)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
|
||||||
const payParams = res.data.payParams;
|
|
||||||
const dingdanid = res.data.dingdanid;
|
|
||||||
|
|
||||||
this.setData({
|
|
||||||
currentDingdanid: dingdanid
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.wechatPay(payParams, 'yajin');
|
|
||||||
} else {
|
|
||||||
wx.showToast({
|
|
||||||
title: res.data.message || '支付发起失败',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('押金支付失败:', error);
|
|
||||||
wx.showToast({
|
|
||||||
title: '支付失败,请重试',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
this.hideLoading();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 积分充值相关 ==========
|
// ========== 积分充值相关 ==========
|
||||||
@@ -443,7 +495,7 @@ onHide() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// ========== 会员购买相关 ==========
|
// ========== 会员购买相关 ==========
|
||||||
async handleHuiyuanBuy(e) {
|
async handleHuiyuanBuy(e, payMethod = 'wx') {
|
||||||
const huiyuanId = e.currentTarget.dataset.id;
|
const huiyuanId = e.currentTarget.dataset.id;
|
||||||
const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true';
|
const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true';
|
||||||
|
|
||||||
@@ -455,18 +507,10 @@ onHide() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTrial) {
|
// 支付宝无需微信确认弹窗
|
||||||
const { currentHuiyuan, huiyuanList } = this.data;
|
if (payMethod !== 'alipay') {
|
||||||
const target = (currentHuiyuan && currentHuiyuan.id === huiyuanId)
|
const confirmed = await this.confirmWechatPurchase('huiyuan');
|
||||||
? currentHuiyuan
|
if (!confirmed) return;
|
||||||
: (huiyuanList || []).find(item => item.id === huiyuanId);
|
|
||||||
if (target && !target.can_buy_trial) {
|
|
||||||
wx.showToast({
|
|
||||||
title: '您已使用过该会员的体验资格',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showLoading('发起会员支付中...');
|
this.showLoading('发起会员支付中...');
|
||||||
@@ -477,18 +521,26 @@ onHide() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
huiyuanid: huiyuanId,
|
huiyuanid: huiyuanId,
|
||||||
is_trial: isTrial
|
is_trial: isTrial,
|
||||||
|
pay_method: payMethod === 'alipay' ? 'alipay' : 'wechat'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
const payParams = res.data.payParams;
|
const payParams = res.data.payParams;
|
||||||
const dingdanid = res.data.dingdanid;
|
const dingdanid = res.data.dingdanid;
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
currentDingdanid: dingdanid
|
currentDingdanid: dingdanid
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 支付宝分支:跳转二维码页
|
||||||
|
if (payMethod === 'alipay' || (payParams && payParams.pay_method === 'alipay')) {
|
||||||
|
this.hideLoading();
|
||||||
|
this.triggerAlipayPayment(payParams, dingdanid, 'huiyuan');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.wechatPay(payParams, 'huiyuan', huiyuanId);
|
await this.wechatPay(payParams, 'huiyuan', huiyuanId);
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({
|
wx.showToast({
|
||||||
@@ -508,9 +560,9 @@ onHide() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// ========== 积分购买(微信支付)—— 已替换为正确的后端接口 ==========
|
// ========== 积分购买(微信支付)—— 已替换为正确的后端接口 ==========
|
||||||
async handleJifenBuy(e) {
|
async handleJifenBuy(e, payMethod = 'wx') {
|
||||||
const disabled = e.currentTarget.dataset.disabled;
|
const disabled = e.currentTarget.dataset.disabled;
|
||||||
|
|
||||||
// 检查积分是否已满
|
// 检查积分是否已满
|
||||||
if (disabled === 'true') {
|
if (disabled === 'true') {
|
||||||
wx.showToast({ title: '积分已满,无需补充', icon: 'none' });
|
wx.showToast({ title: '积分已满,无需补充', icon: 'none' });
|
||||||
@@ -524,20 +576,36 @@ onHide() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 支付宝无需微信确认弹窗
|
||||||
|
if (payMethod !== 'alipay') {
|
||||||
|
const confirmed = await this.confirmWechatPurchase('jifen');
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
this.showLoading('发起积分支付中...');
|
this.showLoading('发起积分支付中...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await request({
|
const res = await request({
|
||||||
url: '/shangpin/jifenbc', // 正确的积分下单接口
|
url: '/shangpin/jifenbc', // 正确的积分下单接口
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {}
|
data: {
|
||||||
|
pay_method: payMethod === 'alipay' ? 'alipay' : 'wechat'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
const payParams = res.data.payParams;
|
const payParams = res.data.payParams;
|
||||||
const dingdanid = res.data.dingdanid;
|
const dingdanid = res.data.dingdanid;
|
||||||
|
|
||||||
this.setData({ currentDingdanid: dingdanid });
|
this.setData({ currentDingdanid: dingdanid });
|
||||||
|
|
||||||
|
// 支付宝分支:跳转二维码页
|
||||||
|
if (payMethod === 'alipay' || (payParams && payParams.pay_method === 'alipay')) {
|
||||||
|
this.hideLoading();
|
||||||
|
this.triggerAlipayPayment(payParams, dingdanid, 'jifen');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.wechatPay(payParams, 'jifen');
|
await this.wechatPay(payParams, 'jifen');
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: res.data.message || '积分支付发起失败', icon: 'none' });
|
wx.showToast({ title: res.data.message || '积分支付发起失败', icon: 'none' });
|
||||||
@@ -549,6 +617,37 @@ onHide() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========== 支付宝扫码支付封装 ==========
|
||||||
|
// 跳转到 alipay-webview 展示二维码,并按 payType 指定轮询接口
|
||||||
|
triggerAlipayPayment(payParams, orderId, payType) {
|
||||||
|
const qrImage = payParams && payParams.qr_image ? payParams.qr_image : '';
|
||||||
|
if (!qrImage) {
|
||||||
|
wx.showToast({ title: '支付宝二维码生成失败', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const app = getApp();
|
||||||
|
app.globalData.alipayQrImage = qrImage;
|
||||||
|
let pollUrl = '/dingdan/fucha';
|
||||||
|
if (payType === 'huiyuan') pollUrl = '/shangpin/huiyuanlx';
|
||||||
|
else if (payType === 'jifen') pollUrl = '/shangpin/jifenlunxun';
|
||||||
|
const encodedPollUrl = encodeURIComponent(pollUrl);
|
||||||
|
const self = this;
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/alipay-webview/alipay-webview?orderId=${orderId}&pollUrl=${encodedPollUrl}`,
|
||||||
|
events: {
|
||||||
|
// 支付宝支付成功后,复用微信支付的更新逻辑刷新全局变量与页面
|
||||||
|
onAlipaySuccess: (res) => {
|
||||||
|
if (self.updateAfterPayment) {
|
||||||
|
self.updateAfterPayment(payType, null, res && res.data).then(() => {
|
||||||
|
wx.showToast({ title: self.getSuccessMessage(payType), icon: 'success', duration: 2000 });
|
||||||
|
self.showPaySuccessPopup(payType);
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// ========== 微信支付封装 ==========
|
// ========== 微信支付封装 ==========
|
||||||
async wechatPay(payParams, payType, extraData = null) {
|
async wechatPay(payParams, payType, extraData = null) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -641,6 +740,7 @@ onHide() {
|
|||||||
icon: 'success',
|
icon: 'success',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
});
|
});
|
||||||
|
this.showPaySuccessPopup(payType);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -749,10 +849,11 @@ onHide() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'huiyuan':
|
case 'huiyuan':
|
||||||
if (responseData && responseData.huiyuan) {
|
if (responseData && responseData.jifen !== undefined) {
|
||||||
app.globalData.jinfen = responseData.jifen;
|
app.globalData.jinfen = responseData.jifen;
|
||||||
await this.updateClubmberData(responseData.huiyuan);
|
|
||||||
}
|
}
|
||||||
|
// 从服务端拉完整 clumber(含总会员子类型展开),避免本地只写总会员 ID
|
||||||
|
await refreshDashouMembership(app);
|
||||||
await this.refreshHuiyuanData(extraData);
|
await this.refreshHuiyuanData(extraData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -772,34 +873,29 @@ onHide() {
|
|||||||
|
|
||||||
// ========== 刷新会员数据 ==========
|
// ========== 刷新会员数据 ==========
|
||||||
async refreshHuiyuanData(huiyuanId) {
|
async refreshHuiyuanData(huiyuanId) {
|
||||||
|
await refreshDashouMembership(app);
|
||||||
this.loadFromGlobalData();
|
this.loadFromGlobalData();
|
||||||
await this.fetchHuiyuanList();
|
await this.fetchHuiyuanList();
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 更新会员数据到全局变量 ==========
|
// ========== 更新会员数据到全局变量(兼容旧回调;优先服务端 clumber) ==========
|
||||||
async updateClubmberData(huiyuanData) {
|
async updateClubmberData(huiyuanData) {
|
||||||
const app = getApp();
|
const clumber = await refreshDashouMembership(app);
|
||||||
|
if (clumber && clumber.length) {
|
||||||
|
this.setData({ clubmber: [...clumber] });
|
||||||
|
return;
|
||||||
|
}
|
||||||
const globalClubmber = app.globalData.clumber || [];
|
const globalClubmber = app.globalData.clumber || [];
|
||||||
|
const { huiyuanid, huiyuanming, daoqi } = huiyuanData || {};
|
||||||
const { huiyuanid, huiyuanming, daoqi } = huiyuanData;
|
if (!huiyuanid) return;
|
||||||
|
const index = globalClubmber.findIndex((item) => item.huiyuanid === huiyuanid);
|
||||||
const index = globalClubmber.findIndex(item => item.huiyuanid === huiyuanid);
|
|
||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
globalClubmber[index].daoqi = daoqi;
|
globalClubmber[index].daoqi = daoqi;
|
||||||
} else {
|
} else {
|
||||||
globalClubmber.push({
|
globalClubmber.push({ huiyuanid, huiyuanming, daoqi });
|
||||||
huiyuanid: huiyuanid,
|
|
||||||
huiyuanming: huiyuanming,
|
|
||||||
daoqi: daoqi
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.globalData.clumber = globalClubmber;
|
app.globalData.clumber = globalClubmber;
|
||||||
|
this.setData({ clubmber: [...globalClubmber] });
|
||||||
this.setData({
|
|
||||||
clubmber: [...globalClubmber]
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========== 检查并刷新数据 ==========
|
// ========== 检查并刷新数据 ==========
|
||||||
@@ -817,6 +913,23 @@ onHide() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 支付成功后弹出后台可配置的图文公告(阅读时长=0 即可直接关闭) */
|
||||||
|
showPaySuccessPopup(payType) {
|
||||||
|
const keyMap = {
|
||||||
|
huiyuan: 'huiyuanchenggong',
|
||||||
|
yajin: 'yajinchenggong',
|
||||||
|
jifen: 'jifenchenggong',
|
||||||
|
};
|
||||||
|
const pageKey = keyMap[payType];
|
||||||
|
if (!pageKey) return;
|
||||||
|
try {
|
||||||
|
PopupService.reset();
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
setTimeout(() => {
|
||||||
|
PopupService.checkAndShow(this, pageKey);
|
||||||
|
}, 450);
|
||||||
|
},
|
||||||
|
|
||||||
showLoading(text = '加载中...') {
|
showLoading(text = '加载中...') {
|
||||||
this.setData({
|
this.setData({
|
||||||
payLoading: true,
|
payLoading: true,
|
||||||
@@ -834,12 +947,33 @@ onHide() {
|
|||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 微信支付下单前确认(仅微信购买会员/押金/积分) */
|
||||||
|
confirmWechatPurchase(kind) {
|
||||||
|
const labelMap = {
|
||||||
|
huiyuan: '会员',
|
||||||
|
yajin: '押金',
|
||||||
|
jifen: '积分',
|
||||||
|
};
|
||||||
|
const label = labelMap[kind] || '服务';
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
wx.showModal({
|
||||||
|
title: '确认微信支付',
|
||||||
|
content: `您即将通过微信支付购买${label}。请点击「确认购买」后才会发起支付;购买成功后不可随意退款,请确认无误后再继续。`,
|
||||||
|
confirmText: '确认购买',
|
||||||
|
cancelText: '再想想',
|
||||||
|
success: (res) => resolve(!!res.confirm),
|
||||||
|
fail: () => resolve(false),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// ========== 新增功能(余额抵扣等) ==========
|
// ========== 新增功能(余额抵扣等) ==========
|
||||||
onBuyHuiyuanClick(e) {
|
onBuyHuiyuanClick(e) {
|
||||||
const huiyuanId = e.currentTarget.dataset.id;
|
const huiyuanId = e.currentTarget.dataset.id;
|
||||||
const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true';
|
const isTrial = e.currentTarget.dataset.trial === true || e.currentTarget.dataset.trial === 'true';
|
||||||
|
|
||||||
if (isTrial) {
|
if (isTrial) {
|
||||||
|
this.setData({ currentBuyIsTrial: true });
|
||||||
this.handleHuiyuanBuy(e);
|
this.handleHuiyuanBuy(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -848,25 +982,7 @@ onHide() {
|
|||||||
currentBuyType: 1,
|
currentBuyType: 1,
|
||||||
currentHuiyuanId: huiyuanId,
|
currentHuiyuanId: huiyuanId,
|
||||||
currentBuyIsTrial: false,
|
currentBuyIsTrial: false,
|
||||||
showPayMethodModal: true
|
showPayMethodModal: true,
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onYajinClick() {
|
|
||||||
this.showYajinModal();
|
|
||||||
},
|
|
||||||
|
|
||||||
onYajinConfirm() {
|
|
||||||
const amount = this.data.yajinAmount;
|
|
||||||
if (!amount || amount < 1 || amount > 10000) {
|
|
||||||
wx.showToast({ title: '请输入1-10000元的金额', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.hideYajinModal();
|
|
||||||
this.setData({
|
|
||||||
currentBuyType: 2,
|
|
||||||
currentYajinAmount: amount,
|
|
||||||
showPayMethodModal: true
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -877,30 +993,22 @@ onHide() {
|
|||||||
// 🔥 修改点2:选择支付方式时再次校验积分状态(防止异步过程中积分变化)
|
// 🔥 修改点2:选择支付方式时再次校验积分状态(防止异步过程中积分变化)
|
||||||
onPayMethodSelect(e) {
|
onPayMethodSelect(e) {
|
||||||
const method = e.currentTarget.dataset.method;
|
const method = e.currentTarget.dataset.method;
|
||||||
const { currentBuyType, currentHuiyuanId, currentYajinAmount, jifen } = this.data;
|
const { currentBuyType, currentHuiyuanId, jifen } = this.data;
|
||||||
this.hidePayMethodModal();
|
this.hidePayMethodModal();
|
||||||
|
|
||||||
// 如果是积分购买,且积分已满,直接拒绝
|
|
||||||
if (currentBuyType === 3 && jifen >= 10) {
|
if (currentBuyType === 3 && jifen >= 10) {
|
||||||
wx.showToast({
|
wx.showToast({ title: '积分已满,无需补充', icon: 'none' });
|
||||||
title: '积分已满,无需补充',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method === 'wx') {
|
if (method === 'wx' || method === 'alipay') {
|
||||||
|
const payMethod = method === 'alipay' ? 'alipay' : 'wx';
|
||||||
if (currentBuyType === 1) {
|
if (currentBuyType === 1) {
|
||||||
this.handleHuiyuanBuy({
|
this.handleHuiyuanBuy({
|
||||||
currentTarget: { dataset: { id: currentHuiyuanId, trial: 'false' } }
|
currentTarget: { dataset: { id: currentHuiyuanId, trial: this.data.currentBuyIsTrial ? 'true' : 'false' } },
|
||||||
});
|
}, payMethod);
|
||||||
} else if (currentBuyType === 2) {
|
|
||||||
this.setData({ yajinAmount: currentYajinAmount }, () => {
|
|
||||||
this.handleYajinPay();
|
|
||||||
});
|
|
||||||
} else if (currentBuyType === 3) {
|
} else if (currentBuyType === 3) {
|
||||||
// ✅ 调用已修正的积分支付函数
|
this.handleJifenBuy({ currentTarget: { dataset: { disabled: 'false' } } }, payMethod);
|
||||||
this.handleJifenBuy({ currentTarget: { dataset: { disabled: 'false' } } });
|
|
||||||
}
|
}
|
||||||
} else if (method === 'balance') {
|
} else if (method === 'balance') {
|
||||||
this.fetchBalanceOptions();
|
this.fetchBalanceOptions();
|
||||||
@@ -909,7 +1017,7 @@ onHide() {
|
|||||||
|
|
||||||
// 🔥 修改点3:请求余额抵扣选项前校验积分状态
|
// 🔥 修改点3:请求余额抵扣选项前校验积分状态
|
||||||
async fetchBalanceOptions() {
|
async fetchBalanceOptions() {
|
||||||
const { currentBuyType, currentHuiyuanId, currentYajinAmount, currentBuyIsTrial, jifen } = this.data;
|
const { currentBuyType, currentHuiyuanId, currentBuyIsTrial, jifen } = this.data;
|
||||||
|
|
||||||
if (currentBuyType === 1 && currentBuyIsTrial) {
|
if (currentBuyType === 1 && currentBuyIsTrial) {
|
||||||
wx.showToast({ title: '体验会员仅支持微信支付', icon: 'none' });
|
wx.showToast({ title: '体验会员仅支持微信支付', icon: 'none' });
|
||||||
@@ -934,9 +1042,8 @@ onHide() {
|
|||||||
data: {
|
data: {
|
||||||
leixing: currentBuyType,
|
leixing: currentBuyType,
|
||||||
huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined,
|
huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined,
|
||||||
is_trial: currentBuyType === 1 ? false : undefined,
|
is_trial: currentBuyType === 1 ? currentBuyIsTrial : undefined,
|
||||||
yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined,
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
const options = res.data.data || [];
|
const options = res.data.data || [];
|
||||||
@@ -977,7 +1084,7 @@ onHide() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async confirmBalancePay() {
|
async confirmBalancePay() {
|
||||||
const { selectedBalanceId, currentBuyType, currentHuiyuanId, currentYajinAmount, currentBuyIsTrial } = this.data;
|
const { selectedBalanceId, currentBuyType, currentHuiyuanId, currentBuyIsTrial } = this.data;
|
||||||
if (!selectedBalanceId) return;
|
if (!selectedBalanceId) return;
|
||||||
|
|
||||||
this.hideConfirmModal();
|
this.hideConfirmModal();
|
||||||
@@ -992,18 +1099,19 @@ onHide() {
|
|||||||
shenfen_id: selectedBalanceId,
|
shenfen_id: selectedBalanceId,
|
||||||
huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined,
|
huiyuan_id: currentBuyType === 1 ? currentHuiyuanId : undefined,
|
||||||
is_trial: currentBuyType === 1 ? currentBuyIsTrial : undefined,
|
is_trial: currentBuyType === 1 ? currentBuyIsTrial : undefined,
|
||||||
yajin_jine: currentBuyType === 2 ? parseInt(currentYajinAmount) : undefined,
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
const responseData = res.data.data || {};
|
const responseData = res.data.data || {};
|
||||||
|
const payType = currentBuyType === 1 ? 'huiyuan' : 'jifen';
|
||||||
await this.updateAfterPayment(
|
await this.updateAfterPayment(
|
||||||
currentBuyType === 1 ? 'huiyuan' : (currentBuyType === 2 ? 'yajin' : 'jifen'),
|
payType,
|
||||||
currentBuyType === 1 ? currentHuiyuanId : null,
|
currentBuyType === 1 ? currentHuiyuanId : null,
|
||||||
responseData
|
responseData
|
||||||
);
|
);
|
||||||
wx.showToast({ title: '购买成功', icon: 'success' });
|
wx.showToast({ title: '购买成功', icon: 'success' });
|
||||||
|
this.showPaySuccessPopup(payType);
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: res.data.message || '购买失败', icon: 'none' });
|
wx.showToast({ title: res.data.message || '购买失败', icon: 'none' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"usingComponents": {
|
"usingComponents": {
|
||||||
"global-notification": "/components/global-notification/global-notification"
|
"global-notification": "/components/global-notification/global-notification",
|
||||||
},
|
"popup-notice": "/components/popup-notice/popup-notice"
|
||||||
"navigationBarTitleText": "充值中心",
|
},
|
||||||
"navigationBarBackgroundColor": "#0a0e2a",
|
"navigationBarTitleText": "VIP",
|
||||||
"navigationBarTextStyle": "white",
|
"navigationBarBackgroundColor": "#FFF9F0",
|
||||||
"backgroundColor": "#0a0e2a",
|
"navigationBarTextStyle": "black",
|
||||||
"backgroundTextStyle": "light",
|
"backgroundColor": "#FFF9F0"
|
||||||
"enablePullDownRefresh": false,
|
}
|
||||||
"onReachBottomDistance": 50
|
|
||||||
}
|
|
||||||
@@ -1,528 +1,214 @@
|
|||||||
<!--pages/dashou-chongzhi/index.wxml-->
|
<!-- VIP 会员 + 积分充值页 -->
|
||||||
<view class="page-container">
|
<view class="vip-page">
|
||||||
<!-- ❌ 删除自定义导航栏区块 -->
|
<image wx:if="{{imgUrls.pageBg}}" class="page-bg" src="{{imgUrls.pageBg}}" mode="widthFix" />
|
||||||
|
<view class="page-bg-fallback" wx:else></view>
|
||||||
|
|
||||||
<!-- ======================= -->
|
<view class="page-body">
|
||||||
<!-- VIP会员区域 - 放在上面 -->
|
<view class="user-row">
|
||||||
<!-- ======================= -->
|
<image class="user-avatar" src="{{avatarUrl}}" mode="aspectFill" binderror="onAvatarError" />
|
||||||
<view class="vip-section">
|
<view class="user-info">
|
||||||
<view class="section-header">
|
<text class="user-name">{{nickname || '打手'}}</text>
|
||||||
<view class="header-decoration">
|
<text class="user-id">会员ID: {{uid || '--'}}</text>
|
||||||
<view class="dec-line"></view>
|
|
||||||
<view class="dec-diamond"></view>
|
|
||||||
<text class="dec-text">VIP会员充值</text>
|
|
||||||
<view class="dec-diamond"></view>
|
|
||||||
<view class="dec-line"></view>
|
|
||||||
</view>
|
</view>
|
||||||
<text class="section-subtitle">选择你的会员</text>
|
<view class="member-badge">{{memberBadge}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 会员卡片滑动区域 -->
|
<swiper
|
||||||
<swiper
|
class="vip-swiper"
|
||||||
class="vip-swiper"
|
current="{{currentHuiyuanIndex}}"
|
||||||
current="{{currentHuiyuanIndex}}"
|
circular="{{huiyuanList.length > 1}}"
|
||||||
circular="{{true}}"
|
previous-margin="40rpx"
|
||||||
previous-margin="120rpx"
|
next-margin="40rpx"
|
||||||
next-margin="120rpx"
|
duration="400"
|
||||||
duration="500"
|
|
||||||
easing-function="easeOutCubic"
|
|
||||||
bindchange="onSwiperChange">
|
bindchange="onSwiperChange">
|
||||||
<swiper-item wx:for="{{huiyuanList}}" wx:key="id">
|
<swiper-item wx:for="{{huiyuanList}}" wx:key="id">
|
||||||
<view class="vip-card {{index === currentHuiyuanIndex ? 'active' : ''}}"
|
<view class="vip-card {{index === currentHuiyuanIndex ? 'vip-card--active' : ''}}" data-index="{{index}}" bindtap="selectHuiyuan">
|
||||||
data-index="{{index}}" bindtap="selectHuiyuan">
|
<image wx:if="{{item.cardBgUrl}}" class="vip-card-bg-img" src="{{item.cardBgUrl}}" mode="aspectFill" />
|
||||||
<!-- 机甲风格边框 -->
|
<view class="vip-card-bg" wx:else></view>
|
||||||
<view class="card-frame">
|
<view class="vip-card-inner">
|
||||||
<view class="frame-corner tl"></view>
|
<view class="vip-card-left">
|
||||||
<view class="frame-corner tr"></view>
|
<view class="vip-title-row">
|
||||||
<view class="frame-corner bl"></view>
|
<text class="vip-name">{{item.mingzi}}</text>
|
||||||
<view class="frame-corner br"></view>
|
<view class="vip-status">{{item.isBought ? '已激活' : '未激活'}}</view>
|
||||||
<view class="frame-line top"></view>
|
</view>
|
||||||
<view class="frame-line right"></view>
|
<view class="vip-price-row">
|
||||||
<view class="frame-line bottom"></view>
|
<text class="vip-currency">¥</text>
|
||||||
<view class="frame-line left"></view>
|
<text class="vip-price">{{item.jiage}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<text class="vip-validity">有效期 {{item.formal_days || 30}} 天</text>
|
||||||
<!-- 卡片内容 -->
|
|
||||||
<view class="card-content">
|
|
||||||
<view class="vip-badge" wx:if="{{item.isBought}}">
|
|
||||||
<text class="badge-text">已拥有</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
<view class="vip-card-right">
|
||||||
<view class="vip-title">
|
<view class="icon-clip icon-clip-vip" wx:if="{{item.cardImageUrl}}">
|
||||||
<text class="title-text">{{item.mingzi}}</text>
|
<image class="icon-clip-img" src="{{item.cardImageUrl}}" mode="aspectFill" />
|
||||||
<view class="title-underline"></view>
|
</view>
|
||||||
</view>
|
<view class="vip-logo-fallback" wx:else>
|
||||||
|
<text class="vip-logo-text">VIP</text>
|
||||||
<view class="vip-price">
|
|
||||||
<text class="price-symbol">¥</text>
|
|
||||||
<text class="price-number">{{item.jiage}}</text>
|
|
||||||
<text class="price-unit">/{{item.formal_days || 30}}天</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="vip-features">
|
|
||||||
<view class="feature-item" wx:for="{{item.features || ['特权功能', '专属标识', '优先接单']}}"
|
|
||||||
wx:key="index">
|
|
||||||
<image class="feature-icon" src="/static/images/check-tech.png"></image>
|
|
||||||
<text class="feature-text">{{item}}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="vip-shimmer"></view>
|
||||||
<!-- 选中状态指示器 -->
|
|
||||||
<view class="card-indicator" wx:if="{{index === currentHuiyuanIndex}}">
|
|
||||||
<view class="indicator-triangle"></view>
|
|
||||||
<view class="indicator-glow"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
|
|
||||||
<!-- 会员详细介绍 -->
|
<view class="section-head">
|
||||||
<view class="vip-detail">
|
<view class="section-bar"></view>
|
||||||
<view class="detail-header">
|
<text class="section-title">{{rulesTitle || ((currentHuiyuan.mingzi || '会员') + '规则')}}</text>
|
||||||
<view class="detail-title">
|
</view>
|
||||||
<image class="detail-icon" src="/static/images/info-tech.png"></image>
|
<scroll-view class="rules-scroll" scroll-x enable-flex>
|
||||||
<text class="title-text">{{currentHuiyuan.mingzi}} - 会员详情</text>
|
<view class="rules-row">
|
||||||
|
<view wx:for="{{detailRules}}" wx:key="index" class="rule-card">
|
||||||
|
<view class="rule-num">{{index + 1}}</view>
|
||||||
|
<text class="rule-text">{{item}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="detail-tech"></view>
|
|
||||||
</view>
|
</view>
|
||||||
|
</scroll-view>
|
||||||
<view class="detail-content">
|
|
||||||
<scroll-view class="detail-scroll" scroll-y>
|
<view class="section-head">
|
||||||
<text class="detail-text">{{currentHuiyuan.jieshao || '加载中...'}}</text>
|
<view class="section-bar"></view>
|
||||||
|
<text class="section-title">{{benefitsTitle || ((currentHuiyuan.mingzi || '会员') + '专属权益')}}</text>
|
||||||
<view class="detail-rules">
|
</view>
|
||||||
<view class="rule-item" wx:for="{{detailRules}}" wx:key="index">
|
<view class="benefits-row">
|
||||||
<view class="rule-number">{{index + 1}}</view>
|
<view wx:for="{{memberBenefits}}" wx:key="title" class="benefit-card">
|
||||||
<text class="rule-text">{{item}}</text>
|
<view wx:if="{{item.iconUrl}}" class="icon-clip icon-clip-benefit">
|
||||||
</view>
|
<image class="icon-clip-img" src="{{item.iconUrl}}" mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
<text class="benefit-title">{{item.title}}</text>
|
||||||
|
<text class="benefit-desc" style="{{item.accentStyle}}">{{item.desc}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!-- 购买区域 - 点击按钮先弹出支付方式选择 -->
|
|
||||||
<view class="buy-section">
|
<view class="section-head">
|
||||||
<view class="buy-info">
|
<view class="section-bar"></view>
|
||||||
<view class="price-display">
|
<text class="section-title">{{advantagesTitle || '平台优势'}}</text>
|
||||||
<!-- 🔥 将“机甲能源”改为“价格” -->
|
</view>
|
||||||
<text class="price-label">价格:</text>
|
<view class="advantage-grid">
|
||||||
<text class="price-value">¥{{currentHuiyuan.jiage}}</text>
|
<view wx:for="{{platformAdvantages}}" wx:key="title" class="advantage-item">
|
||||||
<text class="price-days">/{{currentHuiyuan.formal_days || 30}}天</text>
|
<view wx:if="{{item.iconUrl}}" class="icon-clip icon-clip-advantage">
|
||||||
</view>
|
<image class="icon-clip-img" src="{{item.iconUrl}}" mode="aspectFill" />
|
||||||
<text class="buy-desc" wx:if="{{currentHuiyuan.isBought && currentHuiyuan.buyInfo}}">
|
|
||||||
已激活,<text class="expire-date">{{currentHuiyuan.buyInfo.daoqi}}</text>后到期
|
|
||||||
</text>
|
|
||||||
<text class="buy-desc" wx:else>正式会员支持微信或余额抵扣</text>
|
|
||||||
<text class="buy-desc trial-hint" wx:if="{{currentHuiyuan.can_buy_trial}}">
|
|
||||||
体验版仅微信支付 ¥{{currentHuiyuan.trial_price}}/{{currentHuiyuan.trial_days}}天,终身1次
|
|
||||||
</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
<text class="advantage-title">{{item.title}}</text>
|
||||||
<view class="buy-action">
|
<text class="advantage-desc">{{item.desc}}</text>
|
||||||
<view class="tech-buy-btn {{currentHuiyuan.isBought ? 'renew' : ''}}"
|
</view>
|
||||||
bindtap="onBuyHuiyuanClick" data-id="{{currentHuiyuan.id}}" data-trial="false">
|
</view>
|
||||||
<view class="buy-btn-bg"></view>
|
|
||||||
<view class="buy-btn-glow"></view>
|
<view id="jifen-section" class="jifen-section">
|
||||||
<text class="buy-btn-text">
|
<view class="section-head">
|
||||||
{{currentHuiyuan.isBought ? '正式续费' : '购买正式版'}}
|
<view class="section-bar"></view>
|
||||||
</text>
|
<text class="section-title">积分充值</text>
|
||||||
<view class="buy-btn-energy">
|
</view>
|
||||||
<view class="energy-dot"></view>
|
<view class="jifen-card">
|
||||||
<view class="energy-dot"></view>
|
<view class="jifen-left">
|
||||||
<view class="energy-dot"></view>
|
<text class="jifen-label">当前积分</text>
|
||||||
</view>
|
<text class="jifen-value">{{jifen}}</text>
|
||||||
</view>
|
<text class="jifen-tip" wx:if="{{jifen < 10}}">积分不足将影响接单与提现</text>
|
||||||
<view
|
<text class="jifen-tip jifen-tip--ok" wx:else>积分充足</text>
|
||||||
wx:if="{{currentHuiyuan.can_buy_trial}}"
|
|
||||||
class="tech-buy-btn trial-buy-btn"
|
|
||||||
bindtap="onBuyHuiyuanClick"
|
|
||||||
data-id="{{currentHuiyuan.id}}"
|
|
||||||
data-trial="true"
|
|
||||||
>
|
|
||||||
<view class="buy-btn-bg"></view>
|
|
||||||
<text class="buy-btn-text">购买体验版</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
<view class="jifen-btn {{jifen >= 10 ? 'jifen-btn--disabled' : ''}}" bindtap="onJifenClick" data-disabled="{{jifen >= 10}}">
|
||||||
|
{{jifen >= 10 ? '已满' : '补充积分'}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="owned-section" wx:if="{{clubmber.length > 0}}">
|
||||||
|
<view class="section-head">
|
||||||
|
<view class="section-bar"></view>
|
||||||
|
<text class="section-title">我的会员</text>
|
||||||
|
</view>
|
||||||
|
<view wx:for="{{clubmber}}" wx:key="huiyuanid" class="owned-item" data-item="{{item}}" bindtap="showMemberDetail">
|
||||||
|
<text class="owned-name">{{item.huiyuanming}}</text>
|
||||||
|
<text class="owned-expire">到期 {{formatDaoqiTime(item.daoqi)}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- ======================= -->
|
<view class="footer-bar">
|
||||||
<!-- 三卡片区域 - 放在下面 -->
|
<view class="deposit-banner" bindtap="goToDeposit">
|
||||||
<!-- ======================= -->
|
<text class="deposit-banner-text">缴纳履约金,快人一步</text>
|
||||||
<view class="tech-grid">
|
<text class="deposit-banner-link">去缴纳 ></text>
|
||||||
<!-- 会员区域 - 高度限制最多3个,超出可滚动 -->
|
</view>
|
||||||
<view class="tech-card huiyuan-card">
|
<view class="agree-row" bindtap="toggleAgree">
|
||||||
<view class="card-header">
|
<view class="agree-check {{agreed ? 'agree-check--on' : ''}}">{{agreed ? '✓' : ''}}</view>
|
||||||
<view class="card-title">
|
<text class="agree-text">已阅读并同意</text>
|
||||||
<text class="title-text">我的会员</text>
|
<text class="agree-link">《{{currentHuiyuan.mingzi || '会员'}}协议》</text>
|
||||||
<view class="title-text">👑</view>
|
</view>
|
||||||
</view>
|
<view class="buy-row">
|
||||||
<view class="card-badge">{{clubmber.length}}</view>
|
<view
|
||||||
|
wx:if="{{currentHuiyuan.can_buy_trial}}"
|
||||||
|
class="buy-btn buy-btn--outline"
|
||||||
|
bindtap="onTapTrial"
|
||||||
|
data-id="{{currentHuiyuan.id}}"
|
||||||
|
data-trial="true">
|
||||||
|
体验会员 (¥{{currentHuiyuan.trial_price}})
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
<scroll-view
|
class="buy-btn buy-btn--primary {{currentHuiyuan.can_buy_trial ? '' : 'buy-btn--full'}}"
|
||||||
class="huiyuan-scroll"
|
bindtap="onTapFormal"
|
||||||
scroll-y
|
data-id="{{currentHuiyuan.id}}"
|
||||||
enable-flex
|
data-trial="false">
|
||||||
style="height: {{huiyuanListHeight}}rpx">
|
{{currentHuiyuan.isBought ? '续费正式会员' : '升级正式会员'}} (¥{{currentHuiyuan.jiage}})
|
||||||
<view wx:for="{{clubmber}}" wx:key="huiyuanid" class="huiyuan-item" data-item="{{item}}" bindtap="showMemberDetail">
|
<view class="buy-btn-shimmer"></view>
|
||||||
<view class="huiyuan-tag tech-tag">
|
|
||||||
<view class="tag-triangle"></view>
|
|
||||||
<text class="tag-name">{{item.huiyuanming}}</text>
|
|
||||||
<text class="tag-time">到期: {{formatDaoqiTime(item.daoqi)}}</text>
|
|
||||||
<view class="tag-glow"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view wx:if="{{clubmber.length === 0}}" class="empty-huiyuan">
|
|
||||||
<image class="empty-icon" src="/static/images/empty-member.png"></image>
|
|
||||||
<text class="empty-text">暂无会员</text>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
<view class="card-footer">
|
|
||||||
<text class="footer-text">共{{clubmber.length}}个会员</text>
|
|
||||||
<view class="footer-line"></view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 押金区域 - 点击充值按钮弹出押金输入弹窗 -->
|
|
||||||
<view class="tech-card yajin-card">
|
|
||||||
<view class="card-header">
|
|
||||||
<view class="card-title">
|
|
||||||
<text class="title-text">我的押金</text>
|
|
||||||
<view class="title-text">💰</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-corner"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="yajin-display">
|
|
||||||
<view class="amount-container">
|
|
||||||
<text class="amount-symbol">¥</text>
|
|
||||||
<text class="amount-number">{{yajin}}</text>
|
|
||||||
</view>
|
|
||||||
<text class="amount-unit">可用余额</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="tech-line"></view>
|
|
||||||
|
|
||||||
<view class="action-container">
|
|
||||||
<view class="tech-btn yajin-btn" bindtap="onYajinClick">
|
|
||||||
<view class="btn-bg"></view>
|
|
||||||
<text class="btn-text">立即充值</text>
|
|
||||||
<view class="btn-arrow" style="display:none;">➤</view>
|
|
||||||
<view class="btn-glow"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="card-corner corner-bottom"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 积分区域 - 点击补充按钮弹出支付方式选择 -->
|
|
||||||
<view class="tech-card jifen-card">
|
|
||||||
<view class="card-header">
|
|
||||||
<view class="card-title">
|
|
||||||
<text class="title-text">我的积分</text>
|
|
||||||
<view class="title-text">⭐</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="jifen-display">
|
|
||||||
<view class="circle-progress">
|
|
||||||
<view class="circle-bg"></view>
|
|
||||||
<view class="circle-mask" style="transform: rotate({{jifenProgress}}deg);"></view>
|
|
||||||
<view class="circle-fill" style="transform: rotate({{jifenProgress}}deg);"></view>
|
|
||||||
<view class="circle-center">
|
|
||||||
<text class="jifen-value">{{jifen}}</text>
|
|
||||||
<text class="jifen-label">积分</text>
|
|
||||||
</view>
|
|
||||||
<view class="circle-dots">
|
|
||||||
<view class="circle-dot" wx:for="{{10}}" wx:key="index"
|
|
||||||
style="transform: rotate({{index * 36}}deg);"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="jifen-status">
|
|
||||||
<text class="status-text" wx:if="{{jifen < 10}}">积分不足,影响接单,提现权限</text>
|
|
||||||
<text class="status-text full" wx:else>积分充足,无需补充</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="action-container">
|
|
||||||
<view class="tech-btn jifen-btn" bindtap="onJifenClick" data-disabled="{{jifen >= 10}}">
|
|
||||||
<view class="btn-bg"></view>
|
|
||||||
<text class="btn-text">{{jifen >= 10 ? '积分已满' : '立即补充'}}</text>
|
|
||||||
<view class="btn-energy" wx:if="{{jifen < 10}}"></view>
|
|
||||||
<view class="btn-glow" wx:if="{{jifen < 10}}"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ======================= -->
|
|
||||||
<!-- 押金充值弹窗(原有,确认事件改为 onYajinConfirm) -->
|
|
||||||
<!-- ======================= -->
|
|
||||||
<view class="tech-modal" wx:if="{{showYajinModal}}">
|
|
||||||
<view class="modal-backdrop" bindtap="hideYajinModal"></view>
|
|
||||||
<view class="modal-container">
|
|
||||||
<view class="modal-corner tl"></view>
|
|
||||||
<view class="modal-corner tr"></view>
|
|
||||||
<view class="modal-corner bl"></view>
|
|
||||||
<view class="modal-corner br"></view>
|
|
||||||
|
|
||||||
<view class="modal-header">
|
|
||||||
<text class="modal-title">押金充值</text>
|
|
||||||
<text class="modal-subtitle">充值保证金</text>
|
|
||||||
<view class="modal-close" bindtap="hideYajinModal">
|
|
||||||
<text class="close-text">✕</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-body">
|
|
||||||
<view class="input-section">
|
|
||||||
<view class="input-label">
|
|
||||||
<image class="label-icon" src="/static/images/money-tech.png"></image>
|
|
||||||
<text class="label-text">充值金额 (1-10000元)</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="input-container">
|
|
||||||
<view class="input-prefix">¥</view>
|
|
||||||
<input
|
|
||||||
class="yajin-input"
|
|
||||||
type="digit"
|
|
||||||
placeholder="输入充值金额"
|
|
||||||
placeholder-class="input-placeholder"
|
|
||||||
value="{{yajinAmount}}"
|
|
||||||
bindinput="onYajinInput"
|
|
||||||
maxlength="5"
|
|
||||||
focus="{{showYajinModal}}"/>
|
|
||||||
<view class="input-underline"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<text class="input-tip">支持1-10000元整数充值</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="quick-section">
|
|
||||||
<text class="quick-title">快速选择</text>
|
|
||||||
<view class="quick-buttons">
|
|
||||||
<view
|
|
||||||
class="quick-btn {{yajinAmount == '100' ? 'active' : ''}}"
|
|
||||||
bindtap="setYajinAmount"
|
|
||||||
data-amount="100">
|
|
||||||
<text class="quick-text">100元</text>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="quick-btn {{yajinAmount == '500' ? 'active' : ''}}"
|
|
||||||
bindtap="setYajinAmount"
|
|
||||||
data-amount="500">
|
|
||||||
<text class="quick-text">500元</text>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="quick-btn {{yajinAmount == '1000' ? 'active' : ''}}"
|
|
||||||
bindtap="setYajinAmount"
|
|
||||||
data-amount="1000">
|
|
||||||
<text class="quick-text">1000元</text>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="quick-btn {{yajinAmount == '5000' ? 'active' : ''}}"
|
|
||||||
bindtap="setYajinAmount"
|
|
||||||
data-amount="5000">
|
|
||||||
<text class="quick-text">5000元</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-footer">
|
|
||||||
<view class="modal-btn cancel-btn" bindtap="hideYajinModal">
|
|
||||||
<text class="btn-text">取消</text>
|
|
||||||
</view>
|
|
||||||
<view class="modal-divider"></view>
|
|
||||||
<view class="modal-btn confirm-btn" bindtap="onYajinConfirm">
|
|
||||||
<text class="btn-text">确认支付</text>
|
|
||||||
<view class="btn-sparkle"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ====== 支付方式选择弹窗 ====== -->
|
|
||||||
<view class="tech-modal" wx:if="{{showPayMethodModal}}">
|
|
||||||
<view class="modal-backdrop" bindtap="hidePayMethodModal"></view>
|
|
||||||
<view class="modal-container small">
|
|
||||||
<view class="modal-corner tl"></view>
|
|
||||||
<view class="modal-corner tr"></view>
|
|
||||||
<view class="modal-corner bl"></view>
|
|
||||||
<view class="modal-corner br"></view>
|
|
||||||
|
|
||||||
<view class="modal-header">
|
|
||||||
<text class="modal-title">选择支付方式</text>
|
|
||||||
<view class="modal-close" bindtap="hidePayMethodModal">
|
|
||||||
<text class="close-text">✕</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-body">
|
|
||||||
<view class="pay-method-list">
|
|
||||||
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="wx">
|
|
||||||
<image class="method-icon" src="/static/images/wechat-pay.png"></image>
|
|
||||||
<text class="method-name">微信支付</text>
|
|
||||||
<text class="method-desc">安全快捷</text>
|
|
||||||
</view>
|
|
||||||
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="balance">
|
|
||||||
<image class="method-icon" src="/static/images/balance-pay.png"></image>
|
|
||||||
<text class="method-name">余额抵扣</text>
|
|
||||||
<text class="method-desc">使用佣金或分红</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ====== 余额抵扣身份选择弹窗 ====== -->
|
|
||||||
<view class="tech-modal" wx:if="{{showBalanceModal}}">
|
|
||||||
<view class="modal-backdrop" bindtap="hideBalanceModal"></view>
|
|
||||||
<view class="modal-container">
|
|
||||||
<view class="modal-corner tl"></view>
|
|
||||||
<view class="modal-corner tr"></view>
|
|
||||||
<view class="modal-corner bl"></view>
|
|
||||||
<view class="modal-corner br"></view>
|
|
||||||
|
|
||||||
<view class="modal-header">
|
|
||||||
<text class="modal-title">选择抵扣身份</text>
|
|
||||||
<view class="modal-close" bindtap="hideBalanceModal">
|
|
||||||
<text class="close-text">✕</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-body">
|
|
||||||
<view class="balance-list">
|
|
||||||
<view wx:for="{{balanceOptions}}" wx:key="id" class="balance-item"
|
|
||||||
data-id="{{item.id}}" bindtap="onBalanceSelect">
|
|
||||||
<view class="balance-info">
|
|
||||||
<text class="balance-name">{{item.jieshao}}</text>
|
|
||||||
<text class="balance-amount">需¥{{item.xuyao}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="balance-arrow">➤</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ====== 余额抵扣确认弹窗 ====== -->
|
|
||||||
<view class="tech-modal" wx:if="{{showConfirmModal}}">
|
|
||||||
<view class="modal-backdrop" bindtap="hideConfirmModal"></view>
|
|
||||||
<view class="modal-container">
|
|
||||||
<view class="modal-corner tl"></view>
|
|
||||||
<view class="modal-corner tr"></view>
|
|
||||||
<view class="modal-corner bl"></view>
|
|
||||||
<view class="modal-corner br"></view>
|
|
||||||
|
|
||||||
<view class="modal-header">
|
|
||||||
<text class="modal-title">确认抵扣</text>
|
|
||||||
<view class="modal-close" bindtap="hideConfirmModal">
|
|
||||||
<text class="close-text">✕</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-body">
|
|
||||||
<view class="confirm-detail">
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">抵扣身份:</text>
|
|
||||||
<text class="detail-value">{{selectedBalanceInfo && selectedBalanceInfo.jieshao}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">所需金额:</text>
|
|
||||||
<text class="detail-value">¥{{selectedBalanceInfo && selectedBalanceInfo.xuyao}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">实际扣除:</text>
|
|
||||||
<text class="detail-value">¥{{selectedBalanceInfo && selectedBalanceInfo.xuyao}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-tip">确认后将从您的余额中扣除</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-footer">
|
|
||||||
<view class="modal-btn cancel-btn" bindtap="hideConfirmModal">
|
|
||||||
<text class="btn-text">取消</text>
|
|
||||||
</view>
|
|
||||||
<view class="modal-divider"></view>
|
|
||||||
<view class="modal-btn confirm-btn" bindtap="confirmBalancePay">
|
|
||||||
<text class="btn-text">确认支付</text>
|
|
||||||
<view class="btn-sparkle"></view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ====== 会员详情弹窗 ====== -->
|
|
||||||
<view class="tech-modal" wx:if="{{showMemberModal}}">
|
|
||||||
<view class="modal-backdrop" bindtap="hideMemberModal"></view>
|
|
||||||
<view class="modal-container">
|
|
||||||
<view class="modal-corner tl"></view>
|
|
||||||
<view class="modal-corner tr"></view>
|
|
||||||
<view class="modal-corner bl"></view>
|
|
||||||
<view class="modal-corner br"></view>
|
|
||||||
|
|
||||||
<view class="modal-header">
|
|
||||||
<text class="modal-title">会员详情</text>
|
|
||||||
<view class="modal-close" bindtap="hideMemberModal">
|
|
||||||
<text class="close-text">✕</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="modal-body">
|
|
||||||
<view class="member-detail">
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">会员名称:</text>
|
|
||||||
<text class="detail-value">{{currentMemberDetail && currentMemberDetail.huiyuanming}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">到期时间:</text>
|
|
||||||
<text class="detail-value">{{currentMemberDetail && currentMemberDetail.daoqi}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">剩余天数:</text>
|
|
||||||
<text class="detail-value">{{formatRemainTime(currentMemberDetail && currentMemberDetail.daoqi)}}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ❌ 删除“进入提示弹窗”整个区块 -->
|
|
||||||
|
|
||||||
<!-- ======================= -->
|
|
||||||
<!-- 支付加载动画(原有) -->
|
|
||||||
<!-- ======================= -->
|
|
||||||
<view class="tech-loading" wx:if="{{payLoading}}">
|
|
||||||
<view class="loading-backdrop"></view>
|
|
||||||
<view class="loading-content">
|
|
||||||
<view class="loading-spinner">
|
|
||||||
<view class="spinner-ring ring-1"></view>
|
|
||||||
<view class="spinner-ring ring-2"></view>
|
|
||||||
<view class="spinner-ring ring-3"></view>
|
|
||||||
<view class="spinner-core"></view>
|
|
||||||
<view class="spinner-energy"></view>
|
|
||||||
</view>
|
|
||||||
<text class="loading-text">{{loadingText}}</text>
|
|
||||||
<text class="loading-subtext">正在连接支付系统...</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- ======================= -->
|
|
||||||
<!-- 底部机甲装饰 -->
|
|
||||||
<!-- ======================= -->
|
|
||||||
<view class="tech-footer">
|
|
||||||
<view class="footer-line"></view>
|
|
||||||
<view class="footer-text">星阙网络 © 科技</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 通知组件 -->
|
<!-- 支付方式 -->
|
||||||
<global-notification id="global-notification" />
|
<view class="modal-mask" wx:if="{{showPayMethodModal}}" bindtap="hidePayMethodModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">选择支付方式</text>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="wx">
|
||||||
|
<text class="pay-method-name">微信支付</text>
|
||||||
|
<text class="pay-method-desc">安全快捷</text>
|
||||||
|
</view>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="alipay">
|
||||||
|
<text class="pay-method-name">支付宝</text>
|
||||||
|
<text class="pay-method-desc">扫码支付</text>
|
||||||
|
</view>
|
||||||
|
<view class="pay-method-item" bindtap="onPayMethodSelect" data-method="balance">
|
||||||
|
<text class="pay-method-name">余额抵扣</text>
|
||||||
|
<text class="pay-method-desc">使用佣金或分红</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 🆕 统一弹窗组件 -->
|
<view class="modal-mask" wx:if="{{showBalanceModal}}" bindtap="hideBalanceModal">
|
||||||
<popup-notice id="popupNotice" />
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">选择抵扣身份</text>
|
||||||
|
<view wx:for="{{balanceOptions}}" wx:key="id" class="balance-item" bindtap="onBalanceSelect" data-id="{{item.id}}">
|
||||||
|
<text>{{item.jieshao}}</text>
|
||||||
|
<text class="balance-need">需¥{{item.xuyao}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="modal-mask" wx:if="{{showConfirmModal}}" bindtap="hideConfirmModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">确认抵扣</text>
|
||||||
|
<view class="confirm-row"><text>身份</text><text>{{selectedBalanceInfo.jieshao}}</text></view>
|
||||||
|
<view class="confirm-row"><text>金额</text><text>¥{{selectedBalanceInfo.xuyao}}</text></view>
|
||||||
|
<view class="modal-actions">
|
||||||
|
<view class="modal-btn cancel" bindtap="hideConfirmModal">取消</view>
|
||||||
|
<view class="modal-btn confirm" bindtap="confirmBalancePay">确认支付</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="modal-mask" wx:if="{{showMemberModal}}" bindtap="hideMemberModal">
|
||||||
|
<view class="modal-panel" catchtap="stopPropagation">
|
||||||
|
<text class="modal-title">会员详情</text>
|
||||||
|
<view class="confirm-row"><text>名称</text><text>{{currentMemberDetail.huiyuanming}}</text></view>
|
||||||
|
<view class="confirm-row"><text>到期</text><text>{{currentMemberDetail.daoqi}}</text></view>
|
||||||
|
<view class="confirm-row"><text>剩余</text><text>{{formatRemainTime(currentMemberDetail.daoqi)}}</text></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="loading-mask" wx:if="{{payLoading}}">
|
||||||
|
<view class="loading-box">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
<text>{{loadingText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification" />
|
||||||
|
<popup-notice id="popupNotice" />
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"global-notification": "/components/global-notification/global-notification",
|
||||||
|
"chenghao-tag": "/components/chenghao-tag/chenghao-tag",
|
||||||
|
"tab-bar": "/tab-bar/index",
|
||||||
|
"pindao-modal": "/components/pindao-modal/pindao-modal"
|
||||||
|
},
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"backgroundColor": "#fff8e1",
|
||||||
|
"backgroundTextStyle": "dark",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"onReachBottomDistance": 50
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"global-notification": "/components/global-notification/global-notification",
|
||||||
|
"chenghao-tag": "/components/chenghao-tag/chenghao-tag",
|
||||||
|
"tab-bar": "/tab-bar/index",
|
||||||
|
"pindao-modal": "/components/pindao-modal/pindao-modal",
|
||||||
|
"kefu-float": "/components/kefu-float/kefu-float",
|
||||||
|
"popup-notice": "/components/popup-notice/popup-notice"
|
||||||
|
},
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"backgroundColor": "#fff8e1",
|
||||||
|
"backgroundTextStyle": "dark",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"onReachBottomDistance": 50
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
<!-- 打手端个人中心 - 逍遥梦布局,逻辑/事件不变 -->
|
||||||
|
|
||||||
|
<!-- 未注册 -->
|
||||||
|
<block wx:if="{{!isDashou && !isGuanshi && !isZuzhang && !isKaoheguan}}">
|
||||||
|
<view class="user-page unreg-page">
|
||||||
|
<view class="page-header">
|
||||||
|
<view class="status-bar" style="height:{{statusBar}}px"></view>
|
||||||
|
<view class="nav-bar" style="height:{{navBar - statusBar}}px"><text class="nav-title">我的</text></view>
|
||||||
|
</view>
|
||||||
|
<view class="unreg-area">
|
||||||
|
<view class="panel shadow unreg-card">
|
||||||
|
<text class="unreg-title">接单员认证</text>
|
||||||
|
<input class="unreg-input" type="text" placeholder="输入邀请码" maxlength="100" value="{{inviteCode}}" bindinput="onInviteCodeInput" placeholder-class="ph" />
|
||||||
|
<view class="btn-bg unreg-btn" bindtap="onRegister"><text class="unreg-btn-text">立即注册</text></view>
|
||||||
|
<view class="unreg-btn-secondary" bindtap="quickRegisterAsPlatform"><text>平台直签注册</text></view>
|
||||||
|
<view class="unreg-link" bindtap="switchToNormal"><text>返回点单端</text></view>
|
||||||
|
<view class="unreg-link" bindtap="clearCache"><text>退出登录</text></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<tab-bar/>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<!-- 已注册 -->
|
||||||
|
<block wx:else>
|
||||||
|
<view class="user-page xym-user">
|
||||||
|
<view class="page-header">
|
||||||
|
<view class="status-bar" style="height:{{statusBar}}px"></view>
|
||||||
|
<view class="nav-bar" style="height:{{navBar - statusBar}}px">
|
||||||
|
<text class="nav-title">我的</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view
|
||||||
|
class="content"
|
||||||
|
scroll-y
|
||||||
|
enhanced
|
||||||
|
show-scrollbar="{{false}}"
|
||||||
|
refresher-enabled="{{true}}"
|
||||||
|
refresher-threshold="80"
|
||||||
|
refresher-default-style="black"
|
||||||
|
refresher-background="#fff8e1"
|
||||||
|
refresher-triggered="{{scrollViewRefreshing}}"
|
||||||
|
bindrefresherrefresh="onPullDownRefresh"
|
||||||
|
>
|
||||||
|
<view class="user-info flexb">
|
||||||
|
<view class="flex">
|
||||||
|
<image class="avatar" src="{{avatarUrl || imgUrls.avatarDefault}}" mode="aspectFill" bindtap="previewAvatar"/>
|
||||||
|
<view class="user-text-col">
|
||||||
|
<view class="nickname-row">
|
||||||
|
<text class="nickname">{{dashouNicheng || '接单员'}}</text>
|
||||||
|
<view class="deposit-tag" wx:if="{{yajin && yajin != '0' && yajin != '0.00'}}">保证金</view>
|
||||||
|
<view class="role-tags">
|
||||||
|
<text class="role-tag">接单员</text>
|
||||||
|
<text class="role-tag" wx:if="{{isGuanshi}}">管事</text>
|
||||||
|
<text class="role-tag" wx:if="{{isZuzhang}}">组长</text>
|
||||||
|
<text class="role-tag" wx:if="{{isKaoheguan}}">考核</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="sn-row flex" bindtap="copyUid">
|
||||||
|
<text class="sn">ID: {{uid || '--'}}</text>
|
||||||
|
<image class="copy-ico" src="{{imgUrls.iconCopy}}" mode="aspectFit"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="user-header-actions">
|
||||||
|
<image class="header-action-ico" src="{{imgUrls.iconRefresh}}" mode="aspectFit" bindtap="onTapRefresh"/>
|
||||||
|
<image class="setting-ico" src="{{imgUrls.iconEdit}}" mode="aspectFit" bindtap="goToModifyInfo"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="badge-zone" wx:if="{{chenghaoList.length > 0 || (isGuanshi && guanshiChenghaoList.length > 0) || identityTagList.length > 0}}">
|
||||||
|
<scroll-view scroll-x class="badge-scroll" wx:if="{{chenghaoList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{chenghaoList}}" wx:key="index">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view scroll-x class="badge-scroll" wx:if="{{isGuanshi && guanshiChenghaoList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{guanshiChenghaoList}}" wx:key="index">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view scroll-x class="badge-scroll identity-tag-scroll" wx:if="{{identityTagList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{identityTagList}}" wx:key="id">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="wallet-card flexb">
|
||||||
|
<view bindtap="goToWalletDetail">
|
||||||
|
<view class="w-label">我的佣金(元)</view>
|
||||||
|
<view class="w-num">¥{{totalAssets}}</view>
|
||||||
|
<view class="w-sub">可提现 ¥{{yongjin || '0.00'}} · 查看</view>
|
||||||
|
</view>
|
||||||
|
<view class="wallet-btns flex">
|
||||||
|
<view class="btn-outline" catchtap="goToRecharge">充值</view>
|
||||||
|
<view class="btn-outline" catchtap="goToTotalWithdraw">去提现</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="banner-row flex" wx:if="{{showRechargeBanners}}">
|
||||||
|
<image wx:if="{{imgUrls.bannerVip}}" class="banner-img" src="{{imgUrls.bannerVip}}" mode="widthFix" bindtap="goToRechargeMember"/>
|
||||||
|
<image wx:if="{{imgUrls.bannerDeposit}}" class="banner-img" src="{{imgUrls.bannerDeposit}}" mode="widthFix" bindtap="goToRechargeDeposit"/>
|
||||||
|
</view>
|
||||||
|
<view class="recharge-text-row flex" wx:else>
|
||||||
|
<view class="recharge-text-btn" catchtap="goToRechargeMember">充值会员</view>
|
||||||
|
<view class="recharge-text-btn" catchtap="goToRechargeDeposit">充值保证金</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="qiepian-wrap" bindtap="onQiepianTap">
|
||||||
|
<image class="qiepian-banner" src="{{qiepianBanner}}" mode="widthFix"/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="freeze-row flexa">
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{jinfen || '0'}}</text>
|
||||||
|
<text class="freeze-lbl">积分</text>
|
||||||
|
</view>
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{yajin || '0.00'}}</text>
|
||||||
|
<text class="freeze-lbl">保证金</text>
|
||||||
|
</view>
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{yongjin || '0.00'}}</text>
|
||||||
|
<text class="freeze-lbl">佣金</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:if="{{pendingPenaltyCount > 0}}" class="tip-bar flexb" bindtap="goToMyPunishment">
|
||||||
|
<view class="flex">
|
||||||
|
<image class="tip-ico" src="{{penaltyTipIcon}}" mode="aspectFit"/>
|
||||||
|
<text>你有{{pendingPenaltyCount}}条罚单待处理, 前往处理</text>
|
||||||
|
</view>
|
||||||
|
<text class="tip-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow order-nav-box">
|
||||||
|
<view class="panel-title flexb" bindtap="goToAllOrders">
|
||||||
|
<text class="lg">我的订单</text>
|
||||||
|
<text class="muted">全部订单 ›</text>
|
||||||
|
</view>
|
||||||
|
<view class="order-nav">
|
||||||
|
<view wx:for="{{orderNavXym}}" wx:key="name" class="nav-item" data-status="{{item.statusKey}}" bindtap="goToOrdersWithStatus">
|
||||||
|
<view class="icon-wrap">
|
||||||
|
<view wx:if="{{item.showBadge && item.badge > 0}}" class="nav-badge">{{item.badge}}</view>
|
||||||
|
<image class="nav-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
</view>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow trade-box">
|
||||||
|
<view class="section-hd">交易明细</view>
|
||||||
|
<view class="trade-list">
|
||||||
|
<view wx:for="{{tradeNavXym}}" wx:key="name" class="trade-item" data-type="{{item.type}}" bindtap="goToTradeNav">
|
||||||
|
<image class="trade-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow invite-box">
|
||||||
|
<view class="section-hd">好友邀请</view>
|
||||||
|
<view class="invite-row">
|
||||||
|
<view wx:for="{{inviteNavXym}}" wx:key="name" class="invite-item" data-action="{{item.action}}" bindtap="onInviteNavTap">
|
||||||
|
<image class="invite-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow more-box">
|
||||||
|
<view class="section-hd">更多功能</view>
|
||||||
|
<view class="func-list">
|
||||||
|
<view
|
||||||
|
wx:for="{{moreFuncList}}"
|
||||||
|
wx:key="action"
|
||||||
|
class="func-item-xym"
|
||||||
|
bindtap="onMoreFuncTap"
|
||||||
|
data-action="{{item.action}}"
|
||||||
|
data-auth-type="{{item.authType}}"
|
||||||
|
data-rank-type="{{item.rankType}}"
|
||||||
|
>
|
||||||
|
<view class="func-icon-wrap"><image class="func-icon-xym" src="{{item.icon}}" mode="aspectFit"/></view>
|
||||||
|
<text class="func-txt-xym">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="load-tip">— 已加载全部 —</view>
|
||||||
|
<view class="content-bottom"></view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="follow-kuaishou {{followClass}}" bindtap="toggleFollowKuaishou">
|
||||||
|
<image class="ks-icon" src="{{ksIcon}}" mode="aspectFit"/>
|
||||||
|
<text wx:if="{{followExpanded}}" class="ks-text" catchtap="goToGuanzhuKs">关注快手</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<tab-bar/>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<view class="loading-mask" wx:if="{{isLoading}}">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification"/>
|
||||||
|
<popup-notice id="popupNotice"/>
|
||||||
|
<pindao-modal
|
||||||
|
visible="{{pindaoVisible}}"
|
||||||
|
title="{{pindaoTitle}}"
|
||||||
|
channelNo="{{pindaoChannelNo}}"
|
||||||
|
images="{{pindaoImages}}"
|
||||||
|
bind:close="closePindaoModal"
|
||||||
|
/>
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
<!-- 打手端个人中心 - 逍遥梦布局,逻辑/事件不变 -->
|
||||||
|
|
||||||
|
<!-- 未注册 -->
|
||||||
|
<block wx:if="{{!isDashou && !isGuanshi && !isZuzhang && !isKaoheguan}}">
|
||||||
|
<view class="user-page unreg-page">
|
||||||
|
<view class="page-header">
|
||||||
|
<view class="status-bar" style="height:{{statusBar}}px"></view>
|
||||||
|
<view class="nav-bar" style="height:{{navBar - statusBar}}px"><text class="nav-title">我的</text></view>
|
||||||
|
</view>
|
||||||
|
<view class="unreg-area">
|
||||||
|
<view class="panel shadow unreg-card">
|
||||||
|
<text class="unreg-title">接单员认证</text>
|
||||||
|
<input class="unreg-input" type="text" placeholder="输入邀请码" maxlength="100" value="{{inviteCode}}" bindinput="onInviteCodeInput" placeholder-class="ph" />
|
||||||
|
<view class="btn-bg unreg-btn" bindtap="onRegister"><text class="unreg-btn-text">立即注册</text></view>
|
||||||
|
<view class="unreg-btn-secondary" bindtap="quickRegisterAsPlatform"><text>平台直签注册</text></view>
|
||||||
|
<view class="unreg-link" bindtap="switchToNormal"><text>返回点单端</text></view>
|
||||||
|
<view class="unreg-link" bindtap="clearCache"><text>清除缓存,重新登录</text></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<tab-bar/>
|
||||||
|
<kefu-float bottom="200rpx" />
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<!-- 已注册 -->
|
||||||
|
<block wx:else>
|
||||||
|
<view class="user-page xym-user">
|
||||||
|
<view class="page-header">
|
||||||
|
<view class="status-bar" style="height:{{statusBar}}px"></view>
|
||||||
|
<view class="nav-bar" style="height:{{navBar - statusBar}}px">
|
||||||
|
<text class="nav-title">我的</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view
|
||||||
|
class="content"
|
||||||
|
scroll-y
|
||||||
|
enhanced
|
||||||
|
show-scrollbar="{{false}}"
|
||||||
|
refresher-enabled="{{true}}"
|
||||||
|
refresher-threshold="80"
|
||||||
|
refresher-default-style="black"
|
||||||
|
refresher-background="#fff8e1"
|
||||||
|
refresher-triggered="{{scrollViewRefreshing}}"
|
||||||
|
bindrefresherrefresh="onPullDownRefresh"
|
||||||
|
>
|
||||||
|
<view class="user-info flexb">
|
||||||
|
<view class="flex">
|
||||||
|
<image class="avatar" src="{{avatarUrl || imgUrls.avatarDefault}}" mode="aspectFill" bindtap="previewAvatar"/>
|
||||||
|
<view class="user-text-col">
|
||||||
|
<view class="nickname-row">
|
||||||
|
<text class="nickname">{{dashouNicheng || '接单员'}}</text>
|
||||||
|
<view class="deposit-tag" wx:if="{{yajin && yajin != '0' && yajin != '0.00'}}">保证金</view>
|
||||||
|
<view class="role-tags">
|
||||||
|
<text class="role-tag">接单员</text>
|
||||||
|
<text class="role-tag" wx:if="{{isGuanshi}}">管事</text>
|
||||||
|
<text class="role-tag" wx:if="{{isZuzhang}}">组长</text>
|
||||||
|
<text class="role-tag" wx:if="{{isKaoheguan}}">考核</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="sn-row flex" bindtap="copyUid">
|
||||||
|
<text class="sn">ID: {{uid || '--'}}</text>
|
||||||
|
<image class="copy-ico" src="{{imgUrls.iconCopy}}" mode="aspectFit"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="user-header-actions">
|
||||||
|
<image class="header-action-ico" src="{{imgUrls.iconRefresh}}" mode="aspectFit" bindtap="onTapRefresh"/>
|
||||||
|
<image class="setting-ico" src="{{imgUrls.iconEdit}}" mode="aspectFit" bindtap="goToModifyInfo"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 被指定订单(星阙功能保留) -->
|
||||||
|
<view class="my-zhiding-mine-strip" wx:if="{{myZhidingCount > 0 && isDashou}}" bindtap="goToZhidingFromMine">
|
||||||
|
<view class="my-zhiding-mine-strip-left">
|
||||||
|
<text class="my-zhiding-mine-badge">指定</text>
|
||||||
|
<text class="my-zhiding-mine-count">{{myZhidingCount}}单待接待</text>
|
||||||
|
</view>
|
||||||
|
<text class="my-zhiding-mine-arrow">去处理 ›</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="badge-zone" wx:if="{{chenghaoList.length > 0 || (isGuanshi && guanshiChenghaoList.length > 0) || identityTagList.length > 0}}">
|
||||||
|
<scroll-view scroll-x class="badge-scroll" wx:if="{{chenghaoList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{chenghaoList}}" wx:key="index">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view scroll-x class="badge-scroll" wx:if="{{isGuanshi && guanshiChenghaoList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{guanshiChenghaoList}}" wx:key="index">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<scroll-view scroll-x class="badge-scroll identity-tag-scroll" wx:if="{{identityTagList.length > 0}}">
|
||||||
|
<view class="badge-tag-wrap" wx:for="{{identityTagList}}" wx:key="id">
|
||||||
|
<chenghao-tag mingcheng="{{item.mingcheng}}" texiaoJson="{{item.texiao_json}}"/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="wallet-card flexb">
|
||||||
|
<view bindtap="goToWalletDetail">
|
||||||
|
<view class="w-label">我的佣金(元)</view>
|
||||||
|
<view class="w-num">¥{{totalAssets}}</view>
|
||||||
|
<view class="w-sub">可提现 ¥{{yongjin || '0.00'}} · 查看</view>
|
||||||
|
</view>
|
||||||
|
<view class="wallet-btns flex">
|
||||||
|
<view class="btn-outline" catchtap="goToRecharge">充值</view>
|
||||||
|
<view class="btn-outline" catchtap="goToTotalWithdraw">去提现</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="banner-row flex" wx:if="{{showRechargeBanners}}">
|
||||||
|
<image wx:if="{{imgUrls.bannerVip}}" class="banner-img" src="{{imgUrls.bannerVip}}" mode="widthFix" bindtap="goToRecharge"/>
|
||||||
|
<image wx:if="{{imgUrls.bannerDeposit}}" class="banner-img" src="{{imgUrls.bannerDeposit}}" mode="widthFix" bindtap="goToRecharge"/>
|
||||||
|
</view>
|
||||||
|
<view class="recharge-text-row flex" wx:else>
|
||||||
|
<view class="recharge-text-btn" catchtap="goToRecharge">充值会员</view>
|
||||||
|
<view class="recharge-text-btn" catchtap="goToRecharge">充值保证金</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="qiepian-wrap" bindtap="onQiepianTap">
|
||||||
|
<image class="qiepian-banner" src="{{qiepianBanner}}" mode="widthFix"/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="freeze-row flexa">
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{jinfen || '0'}}</text>
|
||||||
|
<text class="freeze-lbl">积分</text>
|
||||||
|
</view>
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{yajin || '0.00'}}</text>
|
||||||
|
<text class="freeze-lbl">保证金</text>
|
||||||
|
</view>
|
||||||
|
<view class="freeze-col flexmc">
|
||||||
|
<text class="freeze-num">{{yongjin || '0.00'}}</text>
|
||||||
|
<text class="freeze-lbl">佣金</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="stats-bar" wx:if="{{isGuanshi || isZuzhang || isKaoheguan}}">
|
||||||
|
<view class="stat-cell" wx:if="{{isGuanshi}}"><text class="stat-val">{{yaoqingzongshu || 0}}</text><text class="stat-lbl">邀请总数</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isGuanshi}}"><text class="stat-val">{{yichongzhiDashou || 0}}</text><text class="stat-lbl">已充值</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isGuanshi}}"><text class="stat-val">{{fenyongzonge || '0.00'}}</text><text class="stat-lbl">分成总额</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isGuanshi}}"><text class="stat-val">{{zhuanhualv || 0}}%</text><text class="stat-lbl">有效率</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isZuzhang}}"><text class="stat-val">{{guanshiCount || 0}}</text><text class="stat-lbl">邀请管事</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isZuzhang}}"><text class="stat-val">{{fenhongZonge || '0.00'}}</text><text class="stat-lbl">分红总额</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isKaoheguan}}"><text class="stat-val">{{shenheZongshu || 0}}</text><text class="stat-lbl">审核总数</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isKaoheguan}}"><text class="stat-val">{{tongguoZongshu || 0}}</text><text class="stat-lbl">通过总数</text></view>
|
||||||
|
<view class="stat-cell" wx:if="{{isKaoheguan}}"><text class="stat-val">{{pendingShenheCount || 0}}</text><text class="stat-lbl">待审核</text></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:if="{{pendingPenaltyCount > 0}}" class="tip-bar flexb" bindtap="goToMyPunishment">
|
||||||
|
<view class="flex">
|
||||||
|
<image class="tip-ico" src="https://bintao.xmxym88.com/xcx/bintao/51.png" mode="aspectFit"/>
|
||||||
|
<text>你有{{pendingPenaltyCount}}条罚单待处理, 前往处理</text>
|
||||||
|
</view>
|
||||||
|
<text class="tip-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow order-nav-box">
|
||||||
|
<view class="panel-title flexb" bindtap="goToAllOrders">
|
||||||
|
<text class="lg">我的订单</text>
|
||||||
|
<text class="muted">全部订单 ›</text>
|
||||||
|
</view>
|
||||||
|
<view class="order-nav">
|
||||||
|
<view wx:for="{{orderNavXym}}" wx:key="name" class="nav-item" data-status="{{item.statusKey}}" bindtap="goToOrdersWithStatus">
|
||||||
|
<view class="icon-wrap">
|
||||||
|
<view wx:if="{{item.showBadge && item.badge > 0}}" class="nav-badge">{{item.badge}}</view>
|
||||||
|
<image class="nav-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
</view>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow trade-box">
|
||||||
|
<view class="section-hd">交易明细</view>
|
||||||
|
<view class="trade-list">
|
||||||
|
<view wx:for="{{tradeNavXym}}" wx:key="name" class="trade-item" data-type="{{item.type}}" bindtap="goToTradeNav">
|
||||||
|
<image class="trade-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow invite-box">
|
||||||
|
<view class="section-hd">好友邀请</view>
|
||||||
|
<view class="invite-row">
|
||||||
|
<view wx:for="{{inviteNavXym}}" wx:key="name" class="invite-item" data-action="{{item.action}}" bindtap="onInviteNavTap">
|
||||||
|
<image class="invite-icon" src="{{item.icon}}" mode="aspectFit"/>
|
||||||
|
<text class="sm">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="my-box shadow more-box">
|
||||||
|
<view class="section-hd">更多功能</view>
|
||||||
|
<view class="func-list">
|
||||||
|
<view
|
||||||
|
wx:for="{{moreFuncList}}"
|
||||||
|
wx:key="action"
|
||||||
|
class="func-item-xym"
|
||||||
|
bindtap="onMoreFuncTap"
|
||||||
|
data-action="{{item.action}}"
|
||||||
|
data-auth-type="{{item.authType}}"
|
||||||
|
data-rank-type="{{item.rankType}}"
|
||||||
|
>
|
||||||
|
<view class="func-icon-wrap"><image class="func-icon-xym" src="{{item.icon}}" mode="aspectFit"/></view>
|
||||||
|
<text class="func-txt-xym">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="load-tip">— 已加载全部 —</view>
|
||||||
|
<view class="content-bottom"></view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="follow-kuaishou {{followClass}}" bindtap="toggleFollowKuaishou">
|
||||||
|
<image class="ks-icon" src="{{ksIcon}}" mode="aspectFit"/>
|
||||||
|
<text wx:if="{{followExpanded}}" class="ks-text" catchtap="goToGuanzhuKs">关注快手</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<tab-bar/>
|
||||||
|
<kefu-float bottom="200rpx" />
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<view class="loading-mask" wx:if="{{isLoading}}">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification"/>
|
||||||
|
<popup-notice id="popupNotice"/>
|
||||||
|
<pindao-modal
|
||||||
|
visible="{{pindaoVisible}}"
|
||||||
|
title="{{pindaoTitle}}"
|
||||||
|
channelNo="{{pindaoChannelNo}}"
|
||||||
|
images="{{pindaoImages}}"
|
||||||
|
bind:close="closePindaoModal"
|
||||||
|
/>
|
||||||
@@ -0,0 +1,618 @@
|
|||||||
|
/* 打手端个人中心 - 逍遥梦 UI(逻辑不变) */
|
||||||
|
@import '../../styles/dashou-xym-user.wxss';
|
||||||
|
|
||||||
|
page {
|
||||||
|
background: #fff8e1;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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; }
|
||||||
|
|
||||||
|
.user-page {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: linear-gradient(180deg, #f7dc51 0%, #fff 28%, #fff8e1 100%);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar,
|
||||||
|
.nav-bar,
|
||||||
|
.content,
|
||||||
|
.unreg-area {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
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;
|
||||||
|
color: #343434;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
height: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-float {
|
||||||
|
position: fixed;
|
||||||
|
right: 24rpx;
|
||||||
|
top: calc(env(safe-area-inset-top) + 100rpx);
|
||||||
|
z-index: 10;
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-float-ico {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
padding: 10rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 110rpx;
|
||||||
|
height: 110rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4rpx solid #f1f7ff;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
font-size: 38rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-tag {
|
||||||
|
font-size: 20rpx;
|
||||||
|
padding: 2rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
|
color: #492f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sn-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sn {
|
||||||
|
color: #999;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-ico {
|
||||||
|
width: 24rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
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;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-zone {
|
||||||
|
padding: 0 24rpx 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-scroll {
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-tag-wrap {
|
||||||
|
display: inline-block;
|
||||||
|
transform: scale(0.72);
|
||||||
|
transform-origin: left center;
|
||||||
|
margin-right: -8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deposit-tag {
|
||||||
|
margin-left: 8rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: linear-gradient(90deg, #e8c547, #8b6914);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-card {
|
||||||
|
margin: 15rpx 30rpx 0;
|
||||||
|
padding: 24rpx 20rpx;
|
||||||
|
border-radius: 26rpx;
|
||||||
|
background: #fef6d4;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-left {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-label {
|
||||||
|
color: #666;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-num {
|
||||||
|
font-size: 44rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-sub {
|
||||||
|
color: #666;
|
||||||
|
font-size: 26rpx;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-btns {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-btns .btn-outline {
|
||||||
|
margin-left: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-row {
|
||||||
|
margin: 20rpx 24rpx 0;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-row .banner-img {
|
||||||
|
width: 48%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-row .banner-img:first-child {
|
||||||
|
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: #fef6d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeze-col {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeze-num {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #7e893c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.freeze-lbl {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #7e893c;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-bg {
|
||||||
|
background: linear-gradient(180deg, #fae04d, #ffc0a3);
|
||||||
|
border-radius: 30px;
|
||||||
|
color: #492f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.withdraw {
|
||||||
|
padding: 14rpx 28rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
border: 2rpx solid #fff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-strip {
|
||||||
|
margin: 16rpx 30rpx 0;
|
||||||
|
padding: 20rpx 24rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: linear-gradient(135deg, #3d3428, #1a1a2e);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-strip-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fcd270;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-strip-sub {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(252, 210, 112, 0.65);
|
||||||
|
margin-top: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-strip-btn {
|
||||||
|
padding: 10rpx 24rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
margin: 20rpx 20rpx 12rpx;
|
||||||
|
background: #fdfcfa;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
padding: 20rpx 10rpx 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow {
|
||||||
|
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
padding: 8rpx 25rpx 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #343434;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 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 {
|
||||||
|
width: 62rpx;
|
||||||
|
height: 62rpx;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 10rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-item {
|
||||||
|
width: 25%;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-icon {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-txt {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-tag {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #bbb;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-tag-done {
|
||||||
|
color: #c9a962;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-hub-tip {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-hub-scroll {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-hub-track {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 8rpx 16rpx 20rpx;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile {
|
||||||
|
display: inline-block;
|
||||||
|
width: 280rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24rpx 20rpx;
|
||||||
|
min-height: 120rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-icon {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-sub {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.82);
|
||||||
|
margin-top: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tile-go {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-weight: 600;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 6rpx 14rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-theme-blue {
|
||||||
|
background: linear-gradient(135deg, #3d6eb5 0%, #6ba3f7 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-theme-gold {
|
||||||
|
background: linear-gradient(135deg, #a8842a 0%, #f5d563 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-theme-gold .rank-tile-name,
|
||||||
|
.rank-theme-gold .rank-tile-sub,
|
||||||
|
.rank-theme-gold .rank-tile-go {
|
||||||
|
color: #3d2a00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-theme-purple {
|
||||||
|
background: linear-gradient(135deg, #6b4fbf 0%, #9b7fe8 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-theme-orange {
|
||||||
|
background: linear-gradient(135deg, #d4652a 0%, #f5a962 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 未注册 */
|
||||||
|
.unreg-page .unreg-area {
|
||||||
|
flex: 1;
|
||||||
|
padding: 40rpx 30rpx 16rpx;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unreg-card {
|
||||||
|
padding: 40rpx 30rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unreg-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unreg-input {
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
background: #f7f7f7;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ph { color: #bbb; }
|
||||||
|
|
||||||
|
.unreg-btn {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unreg-btn-text { color: #492f00; }
|
||||||
|
|
||||||
|
.unreg-btn-secondary {
|
||||||
|
text-align: center;
|
||||||
|
padding: 18rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unreg-link {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.6);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
border: 4rpx solid rgba(0, 0, 0, 0.08);
|
||||||
|
border-top-color: #ffd061;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: fighterSpin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fighterSpin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
Loaded 100 of 327 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user