修正了 pages 名为拼音的问题
This commit is contained in:
827
app.js
827
app.js
@@ -1,415 +1,414 @@
|
||||
// app.js - 稳健生产版本(修复 GoEasy 初始化错误 + 配置100%加载)
|
||||
import GoEasy from './static/lib/goeasy-2.13.24.esm.min';
|
||||
const ChatCore = require('./utils/chat-core');
|
||||
import { check } from './utils/phone-auth';
|
||||
import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role';
|
||||
|
||||
|
||||
// ===== 三端固定首页(与 custom-tab-bar 一致) =====
|
||||
const roleDefaultPage = PRIMARY_DEFAULT_PAGES;
|
||||
|
||||
App({
|
||||
globalData: {
|
||||
|
||||
hasShownPopupOnColdStart: false,
|
||||
|
||||
apiBaseUrl: 'https://www.abas.asia/hqhd',
|
||||
ossImageUrl: '',
|
||||
morentouxiang: '',
|
||||
dashouguize: '',
|
||||
|
||||
shangpinliebiao: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinleixing: [],
|
||||
shangpinlunbo: [],
|
||||
shangpingonggao: '',
|
||||
lunbozhanwei: '/images/lunbozhanwei.jpg',
|
||||
|
||||
dingdanTiaoshu: {
|
||||
daifuwu: 0,
|
||||
fuwuzhong: 0,
|
||||
yiwancheng: 0,
|
||||
yituikuan: 0
|
||||
},
|
||||
|
||||
dashouqun: '',
|
||||
dashouqunid: '',
|
||||
guanshiqun: '',
|
||||
guanshiqunid: '',
|
||||
|
||||
appId:'wx0e4be86faac4a8d1',
|
||||
|
||||
shangjiastatus: 0,
|
||||
dashoustatus: 0,
|
||||
guanshistatus: 0,
|
||||
dashouNicheng: '',
|
||||
zhanghaoStatus: null,
|
||||
dashouzhuangtai: null,
|
||||
yongjin: null,
|
||||
zonge: null,
|
||||
yajin: null,
|
||||
chenghao: '',
|
||||
jinfen: null,
|
||||
clumber: [{
|
||||
huiyuanid: '',
|
||||
huiyuanming: '',
|
||||
daoqi: ''
|
||||
}],
|
||||
chengjiaoliang: null,
|
||||
zaixianZhuangtai: null,
|
||||
|
||||
guanshi: {
|
||||
nicheng: '',
|
||||
uid: '',
|
||||
touxiang: '',
|
||||
gszhstatus: '',
|
||||
yaoqingzongshu: 0,
|
||||
fenyongzonge: '0.00',
|
||||
fenyongtixian: '0.00'
|
||||
},
|
||||
|
||||
shangjia: {
|
||||
sjzhzhuangtai: '',
|
||||
sjyue: '',
|
||||
fadanzong: null,
|
||||
tuikuanzong: null,
|
||||
riliushui: '',
|
||||
yueliushui: ''
|
||||
},
|
||||
|
||||
liaotian_liebiao: [],
|
||||
xshenfen: 1,
|
||||
|
||||
goEasyConfig: null,
|
||||
kefuConfig: {
|
||||
link: '',
|
||||
enterpriseId: ''
|
||||
},
|
||||
|
||||
cosConfig: {
|
||||
bucket: '',
|
||||
region: 'ap-shanghai',
|
||||
uploadPathPrefix: 'order/'
|
||||
},
|
||||
|
||||
goEasyConnection: {
|
||||
status: 'disconnected',
|
||||
userId: '',
|
||||
identityType: '',
|
||||
lastConnectTime: 0,
|
||||
autoReconnect: true,
|
||||
reconnectAttempts: 0,
|
||||
maxReconnectAttempts: 5,
|
||||
heartbeatInterval: null,
|
||||
cacheKeys: {
|
||||
savedConnection: 'savedGoEasyConnection',
|
||||
userId: 'goEasyUserId',
|
||||
identityType: 'currentGoEasyIdentity',
|
||||
connectTime: 'goEasyConnectTime'
|
||||
},
|
||||
config: {
|
||||
heartbeatInterval: 20000,
|
||||
reconnectDelay: 3000,
|
||||
offlineTimeout: 30000,
|
||||
cacheValidityHours: 12
|
||||
}
|
||||
},
|
||||
|
||||
messageManager: {
|
||||
unreadTotal: 0,
|
||||
unreadMap: {},
|
||||
latestMessages: [],
|
||||
notificationQueue: [],
|
||||
notificationVisible: false,
|
||||
lastNotificationTime: 0,
|
||||
notificationCooldown: 3000,
|
||||
tabBarIndex: 2,
|
||||
showTabBarBadge: true,
|
||||
customTabBar: true,
|
||||
tabBarBadgeText: 0,
|
||||
soundEnabled: true,
|
||||
vibrationEnabled: true,
|
||||
doNotDisturb: false,
|
||||
doNotDisturbStart: '22:00',
|
||||
doNotDisturbEnd: '08:00',
|
||||
notificationStyle: {
|
||||
position: 'top',
|
||||
duration: 3000,
|
||||
backgroundColor: '#00f7ff',
|
||||
textColor: '#ffffff',
|
||||
borderRadius: '16rpx',
|
||||
boxShadow: '0 10rpx 30rpx rgba(0, 247, 255, 0.3)'
|
||||
},
|
||||
currentNotification: null,
|
||||
cacheKeys: {
|
||||
messageSettings: 'messageSettings',
|
||||
unreadTotal: 'messageUnreadTotal',
|
||||
latestMessages: 'latestMessages',
|
||||
notificationMuted: 'notificationMuted'
|
||||
}
|
||||
},
|
||||
|
||||
pageState: {
|
||||
currentPage: '',
|
||||
isInChatPage: false,
|
||||
currentChatId: '',
|
||||
lastPageUpdate: 0
|
||||
},
|
||||
|
||||
eventListeners: {},
|
||||
debugMode: false,
|
||||
currentUser: null,
|
||||
currentRole: 'normal',
|
||||
primaryRole: 'normal'
|
||||
},
|
||||
|
||||
// ========== 核心启动流程 ==========
|
||||
async onLaunch() {
|
||||
// ---------- ① 立即隐藏“返回首页”按钮 ----------
|
||||
wx.hideHomeButton();
|
||||
wx.onAppRoute((res) => {
|
||||
wx.hideHomeButton();
|
||||
const path = (res && res.path) || '';
|
||||
if (path === 'pages/guanshiduan/guanshiduan' || path === 'pages/zuzhangduan/zuzhangduan') {
|
||||
migrateLegacyCenterRole(this);
|
||||
lockPrimaryRole('dashou', this);
|
||||
}
|
||||
});
|
||||
|
||||
// ---------- ② 恢复主端并跳转(旧管事/组长标识自动归打手端) ----------
|
||||
migrateLegacyCenterRole(this);
|
||||
const savedRole = getPrimaryRole(this);
|
||||
lockPrimaryRole(savedRole, this);
|
||||
|
||||
const targetPage = roleDefaultPage[savedRole] || '/pages/index/index';
|
||||
if (savedRole !== 'normal') {
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({ url: targetPage });
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// ---------- ③ 立刻应用本地缓存配置 ----------
|
||||
const cachedConfig = this.readConfigFromStorage();
|
||||
if (cachedConfig) {
|
||||
this.applyDynamicConfig(cachedConfig);
|
||||
}
|
||||
|
||||
// ---------- ④ 初始化基础设施 ----------
|
||||
this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化
|
||||
ChatCore.initGlobalMessageSystem(this);
|
||||
this.initCurrentUser();
|
||||
|
||||
// ---------- ⑤ 建立连接 ----------
|
||||
const saved = this.getSavedConnection();
|
||||
console.log('【启动】缓存身份:', saved ? saved.identityType : '无',
|
||||
'userId:', saved ? saved.userId : '无');
|
||||
setTimeout(() => {
|
||||
if (this.startImWhenReady) this.startImWhenReady();
|
||||
else if (this.ensureConnection) this.ensureConnection();
|
||||
}, 300);
|
||||
|
||||
// ---------- ⑥ 后台静默获取最新配置 ----------
|
||||
this.fetchConfigSafely()
|
||||
.then(latestConfig => {
|
||||
this.saveConfigToStorage(latestConfig);
|
||||
this.applyDynamicConfig(latestConfig);
|
||||
this.initGoEasyWithConfig();
|
||||
this.initCurrentUser();
|
||||
if (this.startImWhenReady) this.startImWhenReady();
|
||||
else if (this.connectForCurrentRole) this.connectForCurrentRole();
|
||||
console.log('远程配置更新完成');
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn('远程配置获取失败,继续使用本地缓存', err);
|
||||
});
|
||||
|
||||
// ---------- ⑦ 手机号认证检查 ----------
|
||||
try {
|
||||
const needAuth = await check();
|
||||
if (needAuth) {
|
||||
wx.reLaunch({ url: '/pages/phone-auth/phone-auth' });
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// ========== 连接管理方法 ==========
|
||||
getSavedConnection() {
|
||||
try {
|
||||
const saved = wx.getStorageSync(
|
||||
this.globalData.goEasyConnection.cacheKeys.savedConnection
|
||||
);
|
||||
return saved || null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// ========== 配置缓存读写 ==========
|
||||
CONFIG_CACHE_KEY: 'app_dynamic_config',
|
||||
|
||||
readConfigFromStorage() {
|
||||
try {
|
||||
const data = wx.getStorageSync(this.CONFIG_CACHE_KEY);
|
||||
if (data && typeof data === 'object') {
|
||||
return data;
|
||||
}
|
||||
} catch (e) {}
|
||||
return null;
|
||||
},
|
||||
|
||||
saveConfigToStorage(config) {
|
||||
try {
|
||||
if (config && typeof config === 'object') {
|
||||
wx.setStorageSync(this.CONFIG_CACHE_KEY, config);
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// ========== 安全获取远程配置(永不报错) ==========
|
||||
fetchConfigSafely() {
|
||||
return new Promise((resolve) => {
|
||||
wx.request({
|
||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
console.warn('远程配置接口返回异常,使用已有配置');
|
||||
resolve(this.readConfigFromStorage() || {});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('远程配置网络请求失败,使用已有配置', err);
|
||||
resolve(this.readConfigFromStorage() || {});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// ========== 原有方法(保留,仅增强) ==========
|
||||
fetchDynamicConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data?.msg || '接口返回错误'));
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
applyDynamicConfig(config) {
|
||||
if (!config || typeof config !== 'object') return;
|
||||
|
||||
if (config.cos) {
|
||||
this.globalData.ossImageUrl = config.cos.ossImageUrl || '';
|
||||
this.globalData.cosConfig = {
|
||||
bucket: config.cos.bucket || '',
|
||||
region: config.cos.region || 'ap-shanghai',
|
||||
uploadPathPrefix: config.cos.uploadPathPrefix || 'order/'
|
||||
};
|
||||
}
|
||||
|
||||
if (config.goEasy) {
|
||||
this.globalData.goEasyConfig = {
|
||||
host: config.goEasy.host || 'hangzhou.goeasy.io',
|
||||
appkey: config.goEasy.appkey || ''
|
||||
};
|
||||
}
|
||||
|
||||
if (config.otherConfig) {
|
||||
this.globalData.morentouxiang = config.otherConfig.morentouxiang || '';
|
||||
this.globalData.dashouguize = config.otherConfig.dashouguize || '';
|
||||
}
|
||||
|
||||
if (config.kefu) {
|
||||
this.globalData.kefuConfig = {
|
||||
link: config.kefu.link || '',
|
||||
enterpriseId: config.kefu.enterpriseId || ''
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 🔥 关键修复:只在有效 appkey 时初始化,且避免重复初始化
|
||||
initGoEasyWithConfig() {
|
||||
const cfg = this.globalData.goEasyConfig;
|
||||
if (!cfg || !cfg.appkey) {
|
||||
console.warn('GoEasy appkey 未配置,聊天功能将在配置就绪后自动恢复');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经初始化过,就不再重复创建实例
|
||||
if (wx.goEasy && wx.GoEasy) {
|
||||
console.log('GoEasy 已初始化,跳过');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wx.goEasy = GoEasy.getInstance({
|
||||
host: cfg.host || 'hangzhou.goeasy.io',
|
||||
appkey: cfg.appkey,
|
||||
modules: ['im', 'pubsub']
|
||||
});
|
||||
wx.GoEasy = GoEasy;
|
||||
console.log('GoEasy 初始化成功');
|
||||
if (this.startImWhenReady && wx.getStorageSync('uid')) {
|
||||
setTimeout(() => this.startImWhenReady(), 100);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('GoEasy 初始化失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
initCurrentUser() {
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (uid) {
|
||||
this.globalData.currentUser = {
|
||||
id: uid,
|
||||
name: '用户' + uid.substring(0, 6),
|
||||
avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
emitEvent(eventName, data) {
|
||||
if (this.globalData.eventListeners[eventName]) {
|
||||
this.globalData.eventListeners[eventName].forEach(callback => {
|
||||
try { callback(data); } catch (error) { console.error(error); }
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/** 切换当前角色并通知 custom-tab-bar 立即刷新(Storage + globalData + 事件) */
|
||||
setCurrentRole(role) {
|
||||
if (!role) return;
|
||||
this.globalData.currentRole = role;
|
||||
wx.setStorageSync('currentRole', role);
|
||||
this.emitEvent('currentRoleChanged', { role });
|
||||
},
|
||||
|
||||
on(eventName, callback) {
|
||||
if (!this.globalData.eventListeners[eventName]) {
|
||||
this.globalData.eventListeners[eventName] = [];
|
||||
}
|
||||
this.globalData.eventListeners[eventName].push(callback);
|
||||
},
|
||||
|
||||
off(eventName, callback) {
|
||||
if (this.globalData.eventListeners[eventName]) {
|
||||
const index = this.globalData.eventListeners[eventName].indexOf(callback);
|
||||
if (index > -1) {
|
||||
this.globalData.eventListeners[eventName].splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// app.js
|
||||
import GoEasy from './static/lib/goeasy-2.13.24.esm.min';
|
||||
const ChatCore = require('./utils/chat-core');
|
||||
import { check } from './utils/phone-auth';
|
||||
import { getPrimaryRole, lockPrimaryRole, migrateLegacyCenterRole, PRIMARY_DEFAULT_PAGES } from './utils/primary-role';
|
||||
|
||||
// 三端固定首页
|
||||
const roleDefaultPage = PRIMARY_DEFAULT_PAGES;
|
||||
|
||||
App({
|
||||
globalData: {
|
||||
|
||||
hasShownPopupOnColdStart: false,
|
||||
|
||||
apiBaseUrl: 'https://www.abas.asia/hqhd',
|
||||
ossImageUrl: '',
|
||||
morentouxiang: '',
|
||||
dashouguize: '',
|
||||
|
||||
shangpinliebiao: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinleixing: [],
|
||||
shangpinlunbo: [],
|
||||
shangpingonggao: '',
|
||||
lunbozhanwei: '/images/lunbozhanwei.jpg',
|
||||
|
||||
dingdanTiaoshu: {
|
||||
daifuwu: 0,
|
||||
fuwuzhong: 0,
|
||||
yiwancheng: 0,
|
||||
yituikuan: 0
|
||||
},
|
||||
|
||||
dashouqun: '',
|
||||
dashouqunid: '',
|
||||
guanshiqun: '',
|
||||
guanshiqunid: '',
|
||||
|
||||
appId:'wx0e4be86faac4a8d1',
|
||||
|
||||
shangjiastatus: 0,
|
||||
dashoustatus: 0,
|
||||
guanshistatus: 0,
|
||||
dashouNicheng: '',
|
||||
zhanghaoStatus: null,
|
||||
dashouzhuangtai: null,
|
||||
yongjin: null,
|
||||
zonge: null,
|
||||
yajin: null,
|
||||
chenghao: '',
|
||||
jinfen: null,
|
||||
clumber: [{
|
||||
huiyuanid: '',
|
||||
huiyuanming: '',
|
||||
daoqi: ''
|
||||
}],
|
||||
chengjiaoliang: null,
|
||||
zaixianZhuangtai: null,
|
||||
|
||||
guanshi: {
|
||||
nicheng: '',
|
||||
uid: '',
|
||||
touxiang: '',
|
||||
gszhstatus: '',
|
||||
yaoqingzongshu: 0,
|
||||
fenyongzonge: '0.00',
|
||||
fenyongtixian: '0.00'
|
||||
},
|
||||
|
||||
shangjia: {
|
||||
sjzhzhuangtai: '',
|
||||
sjyue: '',
|
||||
fadanzong: null,
|
||||
tuikuanzong: null,
|
||||
riliushui: '',
|
||||
yueliushui: ''
|
||||
},
|
||||
|
||||
liaotian_liebiao: [],
|
||||
xshenfen: 1,
|
||||
|
||||
goEasyConfig: null,
|
||||
kefuConfig: {
|
||||
link: '',
|
||||
enterpriseId: ''
|
||||
},
|
||||
|
||||
cosConfig: {
|
||||
bucket: '',
|
||||
region: 'ap-shanghai',
|
||||
uploadPathPrefix: 'order/'
|
||||
},
|
||||
|
||||
goEasyConnection: {
|
||||
status: 'disconnected',
|
||||
userId: '',
|
||||
identityType: '',
|
||||
lastConnectTime: 0,
|
||||
autoReconnect: true,
|
||||
reconnectAttempts: 0,
|
||||
maxReconnectAttempts: 5,
|
||||
heartbeatInterval: null,
|
||||
cacheKeys: {
|
||||
savedConnection: 'savedGoEasyConnection',
|
||||
userId: 'goEasyUserId',
|
||||
identityType: 'currentGoEasyIdentity',
|
||||
connectTime: 'goEasyConnectTime'
|
||||
},
|
||||
config: {
|
||||
heartbeatInterval: 20000,
|
||||
reconnectDelay: 3000,
|
||||
offlineTimeout: 30000,
|
||||
cacheValidityHours: 12
|
||||
}
|
||||
},
|
||||
|
||||
messageManager: {
|
||||
unreadTotal: 0,
|
||||
unreadMap: {},
|
||||
latestMessages: [],
|
||||
notificationQueue: [],
|
||||
notificationVisible: false,
|
||||
lastNotificationTime: 0,
|
||||
notificationCooldown: 3000,
|
||||
tabBarIndex: 2,
|
||||
showTabBarBadge: true,
|
||||
customTabBar: true,
|
||||
tabBarBadgeText: 0,
|
||||
soundEnabled: true,
|
||||
vibrationEnabled: true,
|
||||
doNotDisturb: false,
|
||||
doNotDisturbStart: '22:00',
|
||||
doNotDisturbEnd: '08:00',
|
||||
notificationStyle: {
|
||||
position: 'top',
|
||||
duration: 3000,
|
||||
backgroundColor: '#00f7ff',
|
||||
textColor: '#ffffff',
|
||||
borderRadius: '16rpx',
|
||||
boxShadow: '0 10rpx 30rpx rgba(0, 247, 255, 0.3)'
|
||||
},
|
||||
currentNotification: null,
|
||||
cacheKeys: {
|
||||
messageSettings: 'messageSettings',
|
||||
unreadTotal: 'messageUnreadTotal',
|
||||
latestMessages: 'latestMessages',
|
||||
notificationMuted: 'notificationMuted'
|
||||
}
|
||||
},
|
||||
|
||||
pageState: {
|
||||
currentPage: '',
|
||||
isInChatPage: false,
|
||||
currentChatId: '',
|
||||
lastPageUpdate: 0
|
||||
},
|
||||
|
||||
eventListeners: {},
|
||||
debugMode: false,
|
||||
currentUser: null,
|
||||
currentRole: 'normal',
|
||||
primaryRole: 'normal'
|
||||
},
|
||||
|
||||
// 核心启动流程
|
||||
async onLaunch() {
|
||||
// ① 隐藏返回首页按钮
|
||||
wx.hideHomeButton();
|
||||
wx.onAppRoute((res) => {
|
||||
wx.hideHomeButton();
|
||||
const path = (res && res.path) || '';
|
||||
if (path === 'pages/manager/manager' || path === 'pages/leader/leader') {
|
||||
migrateLegacyCenterRole(this);
|
||||
lockPrimaryRole('dashou', this);
|
||||
}
|
||||
});
|
||||
|
||||
// ② 恢复主端并跳转
|
||||
migrateLegacyCenterRole(this);
|
||||
const savedRole = getPrimaryRole(this);
|
||||
lockPrimaryRole(savedRole, this);
|
||||
|
||||
const targetPage = roleDefaultPage[savedRole] || '/pages/index/index';
|
||||
if (savedRole !== 'normal') {
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({ url: targetPage });
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// ③ 应用本地缓存配置
|
||||
const cachedConfig = this.readConfigFromStorage();
|
||||
if (cachedConfig) {
|
||||
this.applyDynamicConfig(cachedConfig);
|
||||
}
|
||||
|
||||
// ④ 初始化
|
||||
this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化
|
||||
ChatCore.initGlobalMessageSystem(this);
|
||||
this.initCurrentUser();
|
||||
|
||||
// ⑤ 建立连接
|
||||
const saved = this.getSavedConnection();
|
||||
console.log('【启动】缓存身份:', saved ? saved.identityType : '无',
|
||||
'userId:', saved ? saved.userId : '无');
|
||||
setTimeout(() => {
|
||||
if (this.startImWhenReady) this.startImWhenReady();
|
||||
else if (this.ensureConnection) this.ensureConnection();
|
||||
}, 300);
|
||||
|
||||
// ⑥ 获取远程配置
|
||||
this.fetchConfigSafely()
|
||||
.then(latestConfig => {
|
||||
this.saveConfigToStorage(latestConfig);
|
||||
this.applyDynamicConfig(latestConfig);
|
||||
this.initGoEasyWithConfig();
|
||||
this.initCurrentUser();
|
||||
if (this.startImWhenReady) this.startImWhenReady();
|
||||
else if (this.connectForCurrentRole) this.connectForCurrentRole();
|
||||
console.log('远程配置更新完成');
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn('远程配置获取失败,继续使用本地缓存', err);
|
||||
});
|
||||
|
||||
// ⑦ 手机号认证检查
|
||||
try {
|
||||
const needAuth = await check();
|
||||
if (needAuth) {
|
||||
wx.reLaunch({ url: '/pages/phone-auth/phone-auth' });
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// 连接管理方法
|
||||
getSavedConnection() {
|
||||
try {
|
||||
const saved = wx.getStorageSync(
|
||||
this.globalData.goEasyConnection.cacheKeys.savedConnection
|
||||
);
|
||||
return saved || null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// 配置缓存读写
|
||||
CONFIG_CACHE_KEY: 'app_dynamic_config',
|
||||
|
||||
readConfigFromStorage() {
|
||||
try {
|
||||
const data = wx.getStorageSync(this.CONFIG_CACHE_KEY);
|
||||
if (data && typeof data === 'object') {
|
||||
return data;
|
||||
}
|
||||
} catch (e) {}
|
||||
return null;
|
||||
},
|
||||
|
||||
saveConfigToStorage(config) {
|
||||
try {
|
||||
if (config && typeof config === 'object') {
|
||||
wx.setStorageSync(this.CONFIG_CACHE_KEY, config);
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// 获取远程配置
|
||||
fetchConfigSafely() {
|
||||
return new Promise((resolve) => {
|
||||
wx.request({
|
||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0 && res.data.data) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
console.warn('远程配置接口返回异常,使用已有配置');
|
||||
resolve(this.readConfigFromStorage() || {});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('远程配置网络请求失败,使用已有配置', err);
|
||||
resolve(this.readConfigFromStorage() || {});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// 获取远程配置
|
||||
fetchDynamicConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data?.msg || '接口返回错误'));
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
applyDynamicConfig(config) {
|
||||
if (!config || typeof config !== 'object') return;
|
||||
|
||||
if (config.cos) {
|
||||
this.globalData.ossImageUrl = config.cos.ossImageUrl || '';
|
||||
this.globalData.cosConfig = {
|
||||
bucket: config.cos.bucket || '',
|
||||
region: config.cos.region || 'ap-shanghai',
|
||||
uploadPathPrefix: config.cos.uploadPathPrefix || 'order/'
|
||||
};
|
||||
}
|
||||
|
||||
if (config.goEasy) {
|
||||
this.globalData.goEasyConfig = {
|
||||
host: config.goEasy.host || 'hangzhou.goeasy.io',
|
||||
appkey: config.goEasy.appkey || ''
|
||||
};
|
||||
}
|
||||
|
||||
if (config.otherConfig) {
|
||||
this.globalData.morentouxiang = config.otherConfig.morentouxiang || '';
|
||||
this.globalData.dashouguize = config.otherConfig.dashouguize || '';
|
||||
}
|
||||
|
||||
if (config.kefu) {
|
||||
this.globalData.kefuConfig = {
|
||||
link: config.kefu.link || '',
|
||||
enterpriseId: config.kefu.enterpriseId || ''
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 仅在有效 appkey 时初始化
|
||||
initGoEasyWithConfig() {
|
||||
const cfg = this.globalData.goEasyConfig;
|
||||
if (!cfg || !cfg.appkey) {
|
||||
console.warn('GoEasy appkey 未配置,聊天功能将在配置就绪后自动恢复');
|
||||
return;
|
||||
}
|
||||
|
||||
// 避免重复初始化
|
||||
if (wx.goEasy && wx.GoEasy) {
|
||||
console.log('GoEasy 已初始化,跳过');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wx.goEasy = GoEasy.getInstance({
|
||||
host: cfg.host || 'hangzhou.goeasy.io',
|
||||
appkey: cfg.appkey,
|
||||
modules: ['im', 'pubsub']
|
||||
});
|
||||
wx.GoEasy = GoEasy;
|
||||
console.log('GoEasy 初始化成功');
|
||||
if (this.startImWhenReady && wx.getStorageSync('uid')) {
|
||||
setTimeout(() => this.startImWhenReady(), 100);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('GoEasy 初始化失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
initCurrentUser() {
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (uid) {
|
||||
this.globalData.currentUser = {
|
||||
id: uid,
|
||||
name: '用户' + uid.substring(0, 6),
|
||||
avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
emitEvent(eventName, data) {
|
||||
if (this.globalData.eventListeners[eventName]) {
|
||||
this.globalData.eventListeners[eventName].forEach(callback => {
|
||||
try { callback(data); } catch (error) { console.error(error); }
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/** 切换角色并通知刷新 */
|
||||
setCurrentRole(role) {
|
||||
if (!role) return;
|
||||
this.globalData.currentRole = role;
|
||||
wx.setStorageSync('currentRole', role);
|
||||
this.emitEvent('currentRoleChanged', { role });
|
||||
},
|
||||
|
||||
on(eventName, callback) {
|
||||
if (!this.globalData.eventListeners[eventName]) {
|
||||
this.globalData.eventListeners[eventName] = [];
|
||||
}
|
||||
this.globalData.eventListeners[eventName].push(callback);
|
||||
},
|
||||
|
||||
off(eventName, callback) {
|
||||
if (this.globalData.eventListeners[eventName]) {
|
||||
const index = this.globalData.eventListeners[eventName].indexOf(callback);
|
||||
if (index > -1) {
|
||||
this.globalData.eventListeners[eventName].splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
212
app.json
212
app.json
@@ -1,107 +1,107 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/fenlei/fenlei",
|
||||
"pages/xuanren/xuanren",
|
||||
"pages/xiaoxi/xiaoxi",
|
||||
"pages/wode/wode",
|
||||
"pages/shangpinxiangqing/shangpinxiangqing",
|
||||
"pages/tijiao/tijiao",
|
||||
"pages/xiugai/xiugai",
|
||||
"pages/dashouduan/dashouduan",
|
||||
"pages/shangjiaduan/shangjiaduan",
|
||||
"pages/guanshiduan/guanshiduan",
|
||||
"pages/dingdan/dingdan",
|
||||
"pages/dingdanxiangqing/dingdanxiangqing",
|
||||
"pages/dashouguize/dashouguize",
|
||||
"pages/dashouxiugai/dashouxiugai",
|
||||
"pages/dashoupaihang/dashoupaihang",
|
||||
"pages/dashouchongzhi/dashouchongzhi",
|
||||
"pages/dashouxiaoxi/dashouxiaoxi",
|
||||
"pages/dashoudingdan/dashoudingdan",
|
||||
"pages/jiedan/jiedan",
|
||||
"pages/tixian/tixian",
|
||||
"pages/yaoqingdashou/yaoqingdashou",
|
||||
"pages/wodedashou/wodedashou",
|
||||
"pages/czjilu/czjilu",
|
||||
"pages/guanshipaihang/guanshipaihang",
|
||||
"pages/sjpaidan/sjpaidan",
|
||||
"pages/sjdingdan/sjdingdan",
|
||||
"pages/sjxiaoxi/sjxiaoxi",
|
||||
"pages/sjpaihang/sjpaihang",
|
||||
"pages/sjchongzhi/sjchongzhi",
|
||||
"pages/sjddxq/sjddxq",
|
||||
"pages/dsddxq/dsddxq",
|
||||
"pages/liaotian/liaotian",
|
||||
"pages/jisufd/jisufd",
|
||||
"pages/jiedanchi/jiedanchi",
|
||||
"pages/haibao/haibao",
|
||||
"pages/jinpaids/jinpaids",
|
||||
"pages/zuzhangduan/zuzhangduan",
|
||||
"pages/guanzhual/guanzhual",
|
||||
"pages/zzfhjilu/zzfhjilu",
|
||||
"pages/yqguanshi/yqguanshi",
|
||||
"pages/jiedanchi2/jiedanchi2",
|
||||
"pages/qunliaotian/qunliaotian",
|
||||
"pages/kefuliaotian/kefuliaotian",
|
||||
"pages/renzheng/renzheng",
|
||||
"components/global-notification/global-notification",
|
||||
"components/popup-notice/popup-notice",
|
||||
"components/order-card/order-card",
|
||||
"components/order-sender/order-sender",
|
||||
"pages/cfss/cfss/cfss",
|
||||
"pages/cfss/components/fakuan-list/fakuan-list",
|
||||
"pages/cfss/components/jifen-list/jifen-list",
|
||||
"pages/cfss/components/fakuan-pay/fakuan-pay",
|
||||
"pages/phone-auth/phone-auth",
|
||||
"components/chenghao-tag/chenghao-tag",
|
||||
"pages/kaoheguan/kaoheguan",
|
||||
"pages/kaohe_dafen/kaohe_dafen",
|
||||
"pages/kaohe_jilu/kaohe_jilu",
|
||||
"pages/kaohe_zhongxin/kaohe_zhongxin",
|
||||
"pages/kaohe_jinpai/kaohe_jinpai",
|
||||
"pages/peihuDingdan/peihuDingdan",
|
||||
"pages/tixian/components/mode1/mode1",
|
||||
"pages/tixian/components/mode2/mode2"
|
||||
|
||||
|
||||
],
|
||||
|
||||
"usingComponents": {
|
||||
"popup-notice": "/components/popup-notice/popup-notice",
|
||||
"custom-tab-bar": "/custom-tab-bar/index"
|
||||
},
|
||||
|
||||
"window": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationStyle": "default",
|
||||
"backgroundTextStyle": "light",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTitleText": "星阙网络"
|
||||
},
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
"list": [
|
||||
|
||||
|
||||
{
|
||||
"pagePath": "pages/jiedanchi/jiedanchi",
|
||||
"text": "接单池",
|
||||
"iconPath": "/images/jiedanchi.png",
|
||||
"selectedIconPath": "/images/jiedanchi.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/jiedanchi2/jiedanchi2",
|
||||
"text": "接单池",
|
||||
"iconPath": "/images/jiedanchi.png",
|
||||
"selectedIconPath": "/images/jiedanchi.png"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
"style": "v2",
|
||||
"sitemapLocation": "sitemap.json",
|
||||
"lazyCodeLoading": "requiredComponents"
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/category/category",
|
||||
"pages/pick-user/pick-user",
|
||||
"pages/messages/messages",
|
||||
"pages/mine/mine",
|
||||
"pages/product-detail/product-detail",
|
||||
"pages/submit/submit",
|
||||
"pages/edit/edit",
|
||||
"pages/fighter/fighter",
|
||||
"pages/merchant/merchant",
|
||||
"pages/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-msg/merchant-msg",
|
||||
"pages/merchant-rank/merchant-rank",
|
||||
"pages/merchant-recharge/merchant-recharge",
|
||||
"pages/merchant-order-detail/merchant-order-detail",
|
||||
"pages/fighter-order-detail/fighter-order-detail",
|
||||
"pages/chat/chat",
|
||||
"pages/express-order/express-order",
|
||||
"pages/order-pool/order-pool",
|
||||
"pages/poster/poster",
|
||||
"pages/gold-fighter/gold-fighter",
|
||||
"pages/leader/leader",
|
||||
"pages/manager-assign/manager-assign",
|
||||
"pages/leader-bonus-log/leader-bonus-log",
|
||||
"pages/invite-manager/invite-manager",
|
||||
"pages/order-pool2/order-pool2",
|
||||
"pages/group-chat/group-chat",
|
||||
"pages/cs-chat/cs-chat",
|
||||
"pages/verify/verify",
|
||||
"components/global-notification/global-notification",
|
||||
"components/popup-notice/popup-notice",
|
||||
"components/order-card/order-card",
|
||||
"components/order-sender/order-sender",
|
||||
"pages/penalty/penalty/penalty",
|
||||
"pages/penalty/components/fakuan-list/fakuan-list",
|
||||
"pages/penalty/components/jifen-list/jifen-list",
|
||||
"pages/penalty/components/fakuan-pay/fakuan-pay",
|
||||
"pages/phone-auth/phone-auth",
|
||||
"components/chenghao-tag/chenghao-tag",
|
||||
"pages/assessor/assessor",
|
||||
"pages/assess-score/assess-score",
|
||||
"pages/assess-log/assess-log",
|
||||
"pages/assess-center/assess-center",
|
||||
"pages/assess-gold/assess-gold",
|
||||
"pages/escort-orders/escort-orders",
|
||||
"pages/withdraw/components/mode1/mode1",
|
||||
"pages/withdraw/components/mode2/mode2"
|
||||
|
||||
|
||||
],
|
||||
|
||||
"usingComponents": {
|
||||
"popup-notice": "/components/popup-notice/popup-notice",
|
||||
"custom-tab-bar": "/custom-tab-bar/index"
|
||||
},
|
||||
|
||||
"window": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationStyle": "default",
|
||||
"backgroundTextStyle": "light",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTitleText": "星阙网络"
|
||||
},
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
"list": [
|
||||
|
||||
|
||||
{
|
||||
"pagePath": "pages/order-pool/order-pool",
|
||||
"text": "接单池",
|
||||
"iconPath": "/images/jiedanchi.png",
|
||||
"selectedIconPath": "/images/jiedanchi.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/order-pool2/order-pool2",
|
||||
"text": "接单池",
|
||||
"iconPath": "/images/jiedanchi.png",
|
||||
"selectedIconPath": "/images/jiedanchi.png"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
"style": "v2",
|
||||
"sitemapLocation": "sitemap.json",
|
||||
"lazyCodeLoading": "requiredComponents"
|
||||
}
|
||||
889
app.wxss
889
app.wxss
@@ -1,10 +1,889 @@
|
||||
/**app.wxss**/
|
||||
.container {
|
||||
height: 100%;
|
||||
/* app.wxss — 全局共享样式 */
|
||||
|
||||
/* ========== CSS 变量 ========== */
|
||||
page {
|
||||
--color-price: #ff4444;
|
||||
--color-text-main: #333;
|
||||
--color-text-gray: #999;
|
||||
--color-border-light: #f0f0f0;
|
||||
--bg-white: #ffffff;
|
||||
--bg-gray-hover: #f5f5f5;
|
||||
|
||||
--radius-lg: 30rpx;
|
||||
--radius-normal: 25rpx;
|
||||
--radius-full: 50%;
|
||||
|
||||
--padding-base: 40rpx;
|
||||
--shadow-modal: 0 20rpx 60rpx rgba(0, 0, 0, 0.2);
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ========== 动画 ========== */
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 0.8; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.2); }
|
||||
}
|
||||
|
||||
@keyframes modalShow {
|
||||
from { opacity: 0; transform: scale(0.9); }
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
0% { transform: translateX(100%); }
|
||||
100% { transform: translateX(-100%); }
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(100%); }
|
||||
to { transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from { transform: translateY(0); }
|
||||
to { transform: translateY(100%); }
|
||||
}
|
||||
|
||||
/* ========== 加载提示 ========== */
|
||||
.loading-toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 30rpx 50rpx;
|
||||
border-radius: var(--radius-normal);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 6rpx solid rgba(255, 255, 255, 0.3);
|
||||
border-top-color: #fff;
|
||||
border-radius: var(--radius-full);
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ========== 价格组件 ========== */
|
||||
.price-wrap {
|
||||
color: var(--color-price);
|
||||
font-weight: bold;
|
||||
}
|
||||
.price-icon {
|
||||
font-size: 24rpx;
|
||||
margin-right: 2rpx;
|
||||
}
|
||||
.price-integer {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.price-decimal {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* ========== 弹窗基础 ========== */
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(5px);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 600rpx;
|
||||
background: var(--bg-white);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-modal);
|
||||
z-index: 1001;
|
||||
animation: modalShow 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: var(--padding-base);
|
||||
border-bottom: 2rpx solid var(--color-border-light);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 200rpx 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
font-size: 40rpx;
|
||||
color: var(--color-text-gray);
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-full);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.modal-close:active {
|
||||
background: var(--bg-gray-hover);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
max-height: 600rpx;
|
||||
padding: var(--padding-base);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--color-text-main);
|
||||
line-height: 1.6;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* ========== Flex 工具类 ========== */
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-column-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ========== 文本工具类 ========== */
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.text-ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.text-ellipsis-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-gray {
|
||||
color: var(--color-text-gray);
|
||||
}
|
||||
|
||||
.text-main {
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
/* ========== 安全区域 ========== */
|
||||
.safe-bottom {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.safe-bottom-fixed {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
/* ========== 通用卡片 ========== */
|
||||
.card {
|
||||
background: var(--bg-white);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-padding {
|
||||
padding: var(--padding-base);
|
||||
}
|
||||
|
||||
/* ========== 毛玻璃 ========== */
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.glass-dark {
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
/* ========== 圆形头像 ========== */
|
||||
.avatar-circle {
|
||||
border-radius: var(--radius-full);
|
||||
border: 2rpx solid #fff;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-sm {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
|
||||
.avatar-md {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
}
|
||||
|
||||
.avatar-lg {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
}
|
||||
|
||||
/* ========== 红点/角标 ========== */
|
||||
.badge-dot {
|
||||
position: absolute;
|
||||
top: -6rpx;
|
||||
right: -6rpx;
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
background: #fa5151;
|
||||
border-radius: var(--radius-full);
|
||||
border: 2rpx solid #fff;
|
||||
}
|
||||
|
||||
.badge-num {
|
||||
position: absolute;
|
||||
top: -10rpx;
|
||||
right: -10rpx;
|
||||
min-width: 32rpx;
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
padding: 0 8rpx;
|
||||
background: #fa5151;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
border: 2rpx solid #fff;
|
||||
}
|
||||
|
||||
/* ========== 空状态 ========== */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 40rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 30rpx;
|
||||
color: var(--color-text-gray);
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.empty-subtext {
|
||||
font-size: 26rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* ========== 分割线 ========== */
|
||||
.divider {
|
||||
height: 2rpx;
|
||||
background: var(--color-border-light);
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.divider-light {
|
||||
height: 1rpx;
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
margin: 16rpx 0;
|
||||
}
|
||||
|
||||
.divider-gradient {
|
||||
height: 2rpx;
|
||||
background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1), transparent);
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
/* ========== 固定底部按钮区 ========== */
|
||||
.fixed-bottom {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
background: linear-gradient(transparent, rgba(255, 255, 255, 0.95) 30%);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* ========== 列表项 ========== */
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 28rpx;
|
||||
border-bottom: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.list-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.list-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.list-arrow {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
opacity: 0.4;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ========== 标签 ========== */
|
||||
.tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.tag-primary {
|
||||
background: rgba(64, 156, 255, 0.1);
|
||||
color: #409cff;
|
||||
}
|
||||
|
||||
.tag-success {
|
||||
background: rgba(82, 196, 26, 0.1);
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.tag-warning {
|
||||
background: rgba(250, 173, 20, 0.1);
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.tag-danger {
|
||||
background: rgba(255, 77, 79, 0.1);
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.tag-gold {
|
||||
background: rgba(201, 169, 98, 0.1);
|
||||
color: #C9A962;
|
||||
}
|
||||
|
||||
/* ========== 页面容器 ========== */
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.page-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ========== 按钮 ========== */
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 48rpx;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
border: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 主按钮(全宽) */
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
line-height: 96rpx;
|
||||
font-size: 34rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary--gold {
|
||||
background: linear-gradient(135deg, #C9A962, #D4B56A);
|
||||
box-shadow: 0 8rpx 20rpx rgba(201, 169, 98, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary--green {
|
||||
background: linear-gradient(135deg, #52c41a, #389e0d);
|
||||
box-shadow: 0 8rpx 20rpx rgba(82, 196, 26, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary--blue {
|
||||
background: linear-gradient(135deg, #409cff, #3080e0);
|
||||
box-shadow: 0 8rpx 20rpx rgba(64, 156, 255, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary--orange {
|
||||
background: linear-gradient(135deg, #ffb347, #ff8c1a);
|
||||
box-shadow: 0 8rpx 20rpx rgba(255, 140, 26, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary--purple {
|
||||
background: linear-gradient(135deg, #6a11cb, #2575fc);
|
||||
box-shadow: 0 8rpx 20rpx rgba(106, 17, 203, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary--red {
|
||||
background: linear-gradient(135deg, #ff4d4f, #cf1322);
|
||||
box-shadow: 0 8rpx 20rpx rgba(255, 77, 79, 0.3);
|
||||
}
|
||||
|
||||
/* 次要按钮 */
|
||||
.btn-secondary {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
color: var(--color-text-main);
|
||||
font-size: 28rpx;
|
||||
padding: 16rpx 32rpx;
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 小型按钮 */
|
||||
.btn-sm {
|
||||
padding: 14rpx 32rpx;
|
||||
font-size: 26rpx;
|
||||
color: #fff;
|
||||
border-radius: 40rpx;
|
||||
}
|
||||
|
||||
.btn-sm--gold {
|
||||
background: linear-gradient(135deg, #ffcc00, #ffaa00);
|
||||
box-shadow: 0 6rpx 16rpx rgba(255, 170, 0, 0.3);
|
||||
}
|
||||
|
||||
.btn-sm--green {
|
||||
background: linear-gradient(135deg, #52c41a, #389e0d);
|
||||
box-shadow: 0 6rpx 16rpx rgba(82, 196, 26, 0.3);
|
||||
}
|
||||
|
||||
.btn-sm--blue {
|
||||
background: linear-gradient(135deg, #409cff, #3080e0);
|
||||
box-shadow: 0 6rpx 16rpx rgba(64, 156, 255, 0.3);
|
||||
}
|
||||
|
||||
.btn-sm--red {
|
||||
background: linear-gradient(135deg, #ff4d4f, #cf1322);
|
||||
box-shadow: 0 6rpx 16rpx rgba(255, 77, 79, 0.3);
|
||||
}
|
||||
|
||||
.btn-sm--dark {
|
||||
background: linear-gradient(135deg, #3d4f66, #2c3e50);
|
||||
box-shadow: 0 6rpx 16rpx rgba(44, 62, 80, 0.3);
|
||||
}
|
||||
|
||||
/* 幽灵按钮(描边) */
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
border: 2rpx solid currentColor;
|
||||
padding: 14rpx 32rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-ghost--primary {
|
||||
color: #409cff;
|
||||
border-color: #409cff;
|
||||
}
|
||||
|
||||
.btn-ghost--gold {
|
||||
color: #C9A962;
|
||||
border-color: #C9A962;
|
||||
}
|
||||
|
||||
/* 禁用状态 */
|
||||
.btn[disabled],
|
||||
.btn-disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ========== 输入框 ========== */
|
||||
.input-rounded {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
border-radius: 44rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--color-text-main);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
|
||||
.input-rounded--dark {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
color: #fff;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.input-rounded--dark::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.input-inline {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: var(--color-text-main);
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
background: #F7F3ED;
|
||||
border-radius: 24rpx;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
/* ========== 搜索框 ========== */
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f0f0f0;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 68rpx;
|
||||
}
|
||||
|
||||
.search-box--glass {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
height: 84rpx;
|
||||
border-radius: 50rpx;
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 28rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
opacity: 0.5;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ========== Tab 标签栏 ========== */
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 24rpx 0;
|
||||
position: relative;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.tab-item--active {
|
||||
color: var(--color-price);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background: var(--color-price);
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
|
||||
/* 胶囊式 Tab */
|
||||
.tab-capsule {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60rpx;
|
||||
padding: 0 30rpx;
|
||||
margin-right: 20rpx;
|
||||
border-radius: 30rpx;
|
||||
background: #f5f5f5;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-capsule--active {
|
||||
background: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4rpx 12rpx rgba(46, 125, 50, 0.1);
|
||||
}
|
||||
|
||||
/* ========== 加载遮罩 ========== */
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.loading-mask--dark {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.loading-mask--light {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
/* 旋转器尺寸变体 */
|
||||
.spinner {
|
||||
border-radius: var(--radius-full);
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.spinner--sm {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 3rpx solid rgba(0, 0, 0, 0.08);
|
||||
border-top-color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.spinner--md {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 5rpx solid rgba(0, 0, 0, 0.08);
|
||||
border-top-color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.spinner--lg {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border: 6rpx solid rgba(0, 0, 0, 0.08);
|
||||
border-top-color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.spinner--white {
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
border-top-color: #fff;
|
||||
}
|
||||
|
||||
/* ========== 刷新按钮 ========== */
|
||||
.refresh-btn {
|
||||
position: fixed;
|
||||
top: 36rpx;
|
||||
right: 32rpx;
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: var(--radius-full);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.refresh-btn--light {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(12rpx);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.6);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.refresh-btn--dark {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
|
||||
.refresh-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
|
||||
/* ========== 状态标签 ========== */
|
||||
.status-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status-tag--danger {
|
||||
background: #fff5f5;
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
.status-tag--success {
|
||||
background: #f0fff0;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.status-tag--warning {
|
||||
background: #fffbe6;
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.status-tag--info {
|
||||
background: #e6f7ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.status-tag--default {
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* ========== 加载更多 ========== */
|
||||
.load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 26rpx;
|
||||
color: var(--color-text-gray);
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
@@ -1,368 +1,363 @@
|
||||
const { resolveAvatarUrl } = require('../../utils/avatar.js');
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
position: {
|
||||
type: String,
|
||||
value: 'top'
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
value: 3000
|
||||
},
|
||||
showProgress: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
showMuteButton: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
showTime: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
swipeToClose: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
swipeThreshold: {
|
||||
type: Number,
|
||||
value: 50
|
||||
}
|
||||
},
|
||||
|
||||
data: {
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
avatar: '',
|
||||
notificationData: null,
|
||||
progress: 100,
|
||||
progressInterval: null,
|
||||
positionClass: 'top',
|
||||
|
||||
// 滑动相关
|
||||
touchStartY: 0,
|
||||
touchStartX: 0,
|
||||
currentY: 0,
|
||||
currentX: 0,
|
||||
isSwiping: false,
|
||||
swipingClass: '',
|
||||
swipeStyle: '',
|
||||
swipeDistance: 0,
|
||||
|
||||
// 静音状态
|
||||
isMuted: false,
|
||||
|
||||
// 自动隐藏计时器
|
||||
autoHideTimeout: null
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.loadMuteSetting();
|
||||
this.setData({
|
||||
positionClass: this.properties.position
|
||||
});
|
||||
this.setupDirectEventListeners();
|
||||
},
|
||||
|
||||
detached() {
|
||||
this.clearTimers();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setupDirectEventListeners() {
|
||||
const app = getApp();
|
||||
if (app) {
|
||||
const self = this;
|
||||
const globalNotification = {
|
||||
show: (data) => {
|
||||
if (self && self.showNotification) {
|
||||
self.showNotification(data);
|
||||
}
|
||||
},
|
||||
hide: () => {
|
||||
if (self && self.hideNotification) {
|
||||
self.hideNotification();
|
||||
}
|
||||
},
|
||||
isMuted: () => {
|
||||
return self.data.isMuted;
|
||||
}
|
||||
};
|
||||
app.globalData.globalNotification = globalNotification;
|
||||
}
|
||||
},
|
||||
|
||||
loadMuteSetting() {
|
||||
try {
|
||||
const isMuted = wx.getStorageSync('notificationMuted') || false;
|
||||
this.setData({ isMuted });
|
||||
} catch (error) {
|
||||
console.warn('加载静音设置失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
saveMuteSetting(isMuted) {
|
||||
try {
|
||||
wx.setStorageSync('notificationMuted', isMuted);
|
||||
} catch (error) {
|
||||
console.warn('保存静音设置失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
showNotification(data) {
|
||||
if (!data) return;
|
||||
if (this.data.isMuted) return;
|
||||
|
||||
this.clearTimers();
|
||||
|
||||
const app = getApp();
|
||||
let avatar = resolveAvatarUrl(
|
||||
data.avatar || data.message?.senderData?.avatar,
|
||||
app
|
||||
);
|
||||
|
||||
this.setData({
|
||||
show: true,
|
||||
title: data.senderName || '新消息',
|
||||
message: data.content || '[消息内容]',
|
||||
avatar: avatar,
|
||||
notificationData: data,
|
||||
progress: 100,
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
|
||||
if (this.properties.showProgress) {
|
||||
this.startProgressBar(this.properties.duration);
|
||||
}
|
||||
|
||||
this.data.autoHideTimeout = setTimeout(() => {
|
||||
this.hideNotification();
|
||||
}, this.properties.duration);
|
||||
},
|
||||
|
||||
hideNotification() {
|
||||
this.clearTimers();
|
||||
this.setData({
|
||||
show: false,
|
||||
progress: 100,
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
this.triggerEvent('hide');
|
||||
},
|
||||
|
||||
startProgressBar(duration) {
|
||||
const interval = 100;
|
||||
const steps = duration / interval;
|
||||
const stepValue = 100 / steps;
|
||||
|
||||
let currentProgress = 100;
|
||||
this.data.progressInterval = setInterval(() => {
|
||||
currentProgress -= stepValue;
|
||||
if (currentProgress <= 0) {
|
||||
currentProgress = 0;
|
||||
this.setData({ progress: currentProgress });
|
||||
clearInterval(this.data.progressInterval);
|
||||
} else {
|
||||
this.setData({ progress: currentProgress });
|
||||
}
|
||||
}, interval);
|
||||
},
|
||||
|
||||
clearTimers() {
|
||||
if (this.data.autoHideTimeout) {
|
||||
clearTimeout(this.data.autoHideTimeout);
|
||||
this.data.autoHideTimeout = null;
|
||||
}
|
||||
if (this.data.progressInterval) {
|
||||
clearInterval(this.data.progressInterval);
|
||||
this.data.progressInterval = null;
|
||||
}
|
||||
},
|
||||
|
||||
onTouchStart(e) {
|
||||
if (!this.properties.swipeToClose) return;
|
||||
const touch = e.touches[0];
|
||||
this.setData({
|
||||
touchStartY: touch.clientY,
|
||||
touchStartX: touch.clientX,
|
||||
currentY: touch.clientY,
|
||||
currentX: touch.clientX,
|
||||
isSwiping: false
|
||||
});
|
||||
this.clearTimers();
|
||||
},
|
||||
|
||||
onTouchMove(e) {
|
||||
if (!this.properties.swipeToClose) return;
|
||||
const touch = e.touches[0];
|
||||
const deltaY = touch.clientY - this.data.touchStartY;
|
||||
const deltaX = touch.clientX - this.data.touchStartX;
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
const absDeltaX = Math.abs(deltaX);
|
||||
|
||||
if (absDeltaY > 10 && absDeltaY > absDeltaX) {
|
||||
this.setData({
|
||||
isSwiping: true,
|
||||
currentY: touch.clientY,
|
||||
swipingClass: deltaY < 0 ? 'swiping-up' : 'swiping',
|
||||
swipeDistance: Math.abs(deltaY),
|
||||
swipeStyle: `--swipe-distance: ${Math.abs(deltaY)}rpx;`
|
||||
});
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd(e) {
|
||||
if (!this.properties.swipeToClose || !this.data.isSwiping) {
|
||||
this.restartAutoHide();
|
||||
return;
|
||||
}
|
||||
const deltaY = this.data.currentY - this.data.touchStartY;
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
if (absDeltaY > this.properties.swipeThreshold) {
|
||||
this.hideNotification();
|
||||
} else {
|
||||
this.setData({
|
||||
swipingClass: '',
|
||||
swipeStyle: 'transition: transform 0.3s ease; transform: translateY(0);'
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
}, 300);
|
||||
this.restartAutoHide();
|
||||
}
|
||||
this.setData({ isSwiping: false });
|
||||
},
|
||||
|
||||
restartAutoHide() {
|
||||
const remainingTime = (this.data.progress / 100) * this.properties.duration;
|
||||
if (remainingTime > 0) {
|
||||
this.data.autoHideTimeout = setTimeout(() => {
|
||||
this.hideNotification();
|
||||
}, remainingTime);
|
||||
}
|
||||
},
|
||||
|
||||
onTap() {
|
||||
const { notificationData } = this.data;
|
||||
if (!notificationData) return;
|
||||
this.triggerEvent('tap', notificationData);
|
||||
this.hideNotification();
|
||||
this.navigateToChatPage(notificationData);
|
||||
},
|
||||
|
||||
onClose(e) {
|
||||
e.stopPropagation();
|
||||
this.triggerEvent('close');
|
||||
this.hideNotification();
|
||||
},
|
||||
|
||||
onMute(e) {
|
||||
e.stopPropagation();
|
||||
const newMutedState = !this.data.isMuted;
|
||||
this.setData({ isMuted: newMutedState });
|
||||
this.saveMuteSetting(newMutedState);
|
||||
|
||||
const app = getApp();
|
||||
if (app && app.toggleDoNotDisturb) {
|
||||
app.toggleDoNotDisturb(newMutedState);
|
||||
}
|
||||
this.triggerEvent('mute', { muted: newMutedState });
|
||||
wx.showToast({
|
||||
title: newMutedState ? '已开启免打扰' : '已关闭免打扰',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
if (newMutedState) {
|
||||
this.hideNotification();
|
||||
}
|
||||
},
|
||||
|
||||
formatTime(timestamp) {
|
||||
if (!timestamp) return '';
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
if (diff < 60 * 1000) return '刚刚';
|
||||
if (diff < 60 * 60 * 1000) return Math.floor(diff / (60 * 1000)) + '分钟前';
|
||||
if (date.toDateString() === now.toDateString()) {
|
||||
return date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0');
|
||||
}
|
||||
const yesterday = new Date(now);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
if (date.toDateString() === yesterday.toDateString()) {
|
||||
return '昨天 ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0');
|
||||
}
|
||||
return (date.getMonth() + 1) + '月' + date.getDate() + '日';
|
||||
},
|
||||
|
||||
navigateToChatPage(data) {
|
||||
if (!data || !data.message) {
|
||||
console.warn('通知数据无效,无法跳转');
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = data.message;
|
||||
let path = '';
|
||||
let queryParam = null;
|
||||
|
||||
// 根据 notificationType 或消息字段判断
|
||||
if (data.notificationType === 'cs' || msg.teamId) {
|
||||
// 客服消息
|
||||
const teamId = data.teamId || msg.teamId;
|
||||
path = '/pages/kefuliaotian/kefuliaotian';
|
||||
queryParam = { teamId: teamId };
|
||||
} else if (data.notificationType === 'group' || msg.groupId) {
|
||||
// 群聊消息
|
||||
const groupId = data.groupId || msg.groupId;
|
||||
const orderId = data.orderId || msg.orderId || '';
|
||||
const groupName = data.groupName || '订单群聊';
|
||||
const groupAvatar = data.groupAvatar || '';
|
||||
const isCross = data.isCross || msg.isCross || 0;
|
||||
path = '/pages/qunliaotian/qunliaotian';
|
||||
queryParam = {
|
||||
groupId,
|
||||
orderId,
|
||||
groupName,
|
||||
groupAvatar,
|
||||
isCross
|
||||
};
|
||||
} else {
|
||||
// 默认私聊
|
||||
const toUserId = data.senderId || msg.senderId;
|
||||
const toName = data.senderName || '用户';
|
||||
const toAvatar = data.avatar || '';
|
||||
path = '/pages/liaotian/liaotian';
|
||||
queryParam = {
|
||||
toUserId,
|
||||
toName,
|
||||
toAvatar
|
||||
};
|
||||
}
|
||||
|
||||
if (path && queryParam) {
|
||||
const encoded = encodeURIComponent(JSON.stringify(queryParam));
|
||||
wx.navigateTo({
|
||||
url: `${path}?data=${encoded}`,
|
||||
fail: (err) => {
|
||||
console.error('通知跳转失败:', err);
|
||||
wx.switchTab({ url: '/pages/xiaoxi/xiaoxi' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.switchTab({ url: '/pages/xiaoxi/xiaoxi' });
|
||||
}
|
||||
}
|
||||
}
|
||||
const { resolveAvatarUrl } = require('../../utils/avatar.js');
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
position: {
|
||||
type: String,
|
||||
value: 'top'
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
value: 3000
|
||||
},
|
||||
showProgress: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
showMuteButton: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
showTime: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
swipeToClose: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
swipeThreshold: {
|
||||
type: Number,
|
||||
value: 50
|
||||
}
|
||||
},
|
||||
|
||||
data: {
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
avatar: '',
|
||||
notificationData: null,
|
||||
progress: 100,
|
||||
progressInterval: null,
|
||||
positionClass: 'top',
|
||||
|
||||
touchStartY: 0,
|
||||
touchStartX: 0,
|
||||
currentY: 0,
|
||||
currentX: 0,
|
||||
isSwiping: false,
|
||||
swipingClass: '',
|
||||
swipeStyle: '',
|
||||
swipeDistance: 0,
|
||||
|
||||
// 静音状态
|
||||
isMuted: false,
|
||||
|
||||
// 自动隐藏计时器
|
||||
autoHideTimeout: null
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.loadMuteSetting();
|
||||
this.setData({
|
||||
positionClass: this.properties.position
|
||||
});
|
||||
this.setupDirectEventListeners();
|
||||
},
|
||||
|
||||
detached() {
|
||||
this.clearTimers();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setupDirectEventListeners() {
|
||||
const app = getApp();
|
||||
if (app) {
|
||||
const self = this;
|
||||
const globalNotification = {
|
||||
show: (data) => {
|
||||
if (self && self.showNotification) {
|
||||
self.showNotification(data);
|
||||
}
|
||||
},
|
||||
hide: () => {
|
||||
if (self && self.hideNotification) {
|
||||
self.hideNotification();
|
||||
}
|
||||
},
|
||||
isMuted: () => {
|
||||
return self.data.isMuted;
|
||||
}
|
||||
};
|
||||
app.globalData.globalNotification = globalNotification;
|
||||
}
|
||||
},
|
||||
|
||||
loadMuteSetting() {
|
||||
try {
|
||||
const isMuted = wx.getStorageSync('notificationMuted') || false;
|
||||
this.setData({ isMuted });
|
||||
} catch (error) {
|
||||
console.warn('加载静音设置失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
saveMuteSetting(isMuted) {
|
||||
try {
|
||||
wx.setStorageSync('notificationMuted', isMuted);
|
||||
} catch (error) {
|
||||
console.warn('保存静音设置失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
showNotification(data) {
|
||||
if (!data) return;
|
||||
if (this.data.isMuted) return;
|
||||
|
||||
this.clearTimers();
|
||||
|
||||
const app = getApp();
|
||||
let avatar = resolveAvatarUrl(
|
||||
data.avatar || data.message?.senderData?.avatar,
|
||||
app
|
||||
);
|
||||
|
||||
this.setData({
|
||||
show: true,
|
||||
title: data.senderName || '新消息',
|
||||
message: data.content || '[消息内容]',
|
||||
avatar: avatar,
|
||||
notificationData: data,
|
||||
progress: 100,
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
|
||||
if (this.properties.showProgress) {
|
||||
this.startProgressBar(this.properties.duration);
|
||||
}
|
||||
|
||||
this.data.autoHideTimeout = setTimeout(() => {
|
||||
this.hideNotification();
|
||||
}, this.properties.duration);
|
||||
},
|
||||
|
||||
hideNotification() {
|
||||
this.clearTimers();
|
||||
this.setData({
|
||||
show: false,
|
||||
progress: 100,
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
this.triggerEvent('hide');
|
||||
},
|
||||
|
||||
startProgressBar(duration) {
|
||||
const interval = 100;
|
||||
const steps = duration / interval;
|
||||
const stepValue = 100 / steps;
|
||||
|
||||
let currentProgress = 100;
|
||||
this.data.progressInterval = setInterval(() => {
|
||||
currentProgress -= stepValue;
|
||||
if (currentProgress <= 0) {
|
||||
currentProgress = 0;
|
||||
this.setData({ progress: currentProgress });
|
||||
clearInterval(this.data.progressInterval);
|
||||
} else {
|
||||
this.setData({ progress: currentProgress });
|
||||
}
|
||||
}, interval);
|
||||
},
|
||||
|
||||
clearTimers() {
|
||||
if (this.data.autoHideTimeout) {
|
||||
clearTimeout(this.data.autoHideTimeout);
|
||||
this.data.autoHideTimeout = null;
|
||||
}
|
||||
if (this.data.progressInterval) {
|
||||
clearInterval(this.data.progressInterval);
|
||||
this.data.progressInterval = null;
|
||||
}
|
||||
},
|
||||
|
||||
onTouchStart(e) {
|
||||
if (!this.properties.swipeToClose) return;
|
||||
const touch = e.touches[0];
|
||||
this.setData({
|
||||
touchStartY: touch.clientY,
|
||||
touchStartX: touch.clientX,
|
||||
currentY: touch.clientY,
|
||||
currentX: touch.clientX,
|
||||
isSwiping: false
|
||||
});
|
||||
this.clearTimers();
|
||||
},
|
||||
|
||||
onTouchMove(e) {
|
||||
if (!this.properties.swipeToClose) return;
|
||||
const touch = e.touches[0];
|
||||
const deltaY = touch.clientY - this.data.touchStartY;
|
||||
const deltaX = touch.clientX - this.data.touchStartX;
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
const absDeltaX = Math.abs(deltaX);
|
||||
|
||||
if (absDeltaY > 10 && absDeltaY > absDeltaX) {
|
||||
this.setData({
|
||||
isSwiping: true,
|
||||
currentY: touch.clientY,
|
||||
swipingClass: deltaY < 0 ? 'swiping-up' : 'swiping',
|
||||
swipeDistance: Math.abs(deltaY),
|
||||
swipeStyle: `--swipe-distance: ${Math.abs(deltaY)}rpx;`
|
||||
});
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd(e) {
|
||||
if (!this.properties.swipeToClose || !this.data.isSwiping) {
|
||||
this.restartAutoHide();
|
||||
return;
|
||||
}
|
||||
const deltaY = this.data.currentY - this.data.touchStartY;
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
if (absDeltaY > this.properties.swipeThreshold) {
|
||||
this.hideNotification();
|
||||
} else {
|
||||
this.setData({
|
||||
swipingClass: '',
|
||||
swipeStyle: 'transition: transform 0.3s ease; transform: translateY(0);'
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
swipingClass: '',
|
||||
swipeStyle: ''
|
||||
});
|
||||
}, 300);
|
||||
this.restartAutoHide();
|
||||
}
|
||||
this.setData({ isSwiping: false });
|
||||
},
|
||||
|
||||
restartAutoHide() {
|
||||
const remainingTime = (this.data.progress / 100) * this.properties.duration;
|
||||
if (remainingTime > 0) {
|
||||
this.data.autoHideTimeout = setTimeout(() => {
|
||||
this.hideNotification();
|
||||
}, remainingTime);
|
||||
}
|
||||
},
|
||||
|
||||
onTap() {
|
||||
const { notificationData } = this.data;
|
||||
if (!notificationData) return;
|
||||
this.triggerEvent('tap', notificationData);
|
||||
this.hideNotification();
|
||||
this.navigateToChatPage(notificationData);
|
||||
},
|
||||
|
||||
onClose(e) {
|
||||
e.stopPropagation();
|
||||
this.triggerEvent('close');
|
||||
this.hideNotification();
|
||||
},
|
||||
|
||||
onMute(e) {
|
||||
e.stopPropagation();
|
||||
const newMutedState = !this.data.isMuted;
|
||||
this.setData({ isMuted: newMutedState });
|
||||
this.saveMuteSetting(newMutedState);
|
||||
|
||||
const app = getApp();
|
||||
if (app && app.toggleDoNotDisturb) {
|
||||
app.toggleDoNotDisturb(newMutedState);
|
||||
}
|
||||
this.triggerEvent('mute', { muted: newMutedState });
|
||||
wx.showToast({
|
||||
title: newMutedState ? '已开启免打扰' : '已关闭免打扰',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
if (newMutedState) {
|
||||
this.hideNotification();
|
||||
}
|
||||
},
|
||||
|
||||
formatTime(timestamp) {
|
||||
if (!timestamp) return '';
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
if (diff < 60 * 1000) return '刚刚';
|
||||
if (diff < 60 * 60 * 1000) return Math.floor(diff / (60 * 1000)) + '分钟前';
|
||||
if (date.toDateString() === now.toDateString()) {
|
||||
return date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0');
|
||||
}
|
||||
const yesterday = new Date(now);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
if (date.toDateString() === yesterday.toDateString()) {
|
||||
return '昨天 ' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0');
|
||||
}
|
||||
return (date.getMonth() + 1) + '月' + date.getDate() + '日';
|
||||
},
|
||||
|
||||
navigateToChatPage(data) {
|
||||
if (!data || !data.message) {
|
||||
console.warn('通知数据无效,无法跳转');
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = data.message;
|
||||
let path = '';
|
||||
let queryParam = null;
|
||||
|
||||
if (data.notificationType === 'cs' || msg.teamId) {
|
||||
const teamId = data.teamId || msg.teamId;
|
||||
path = '/pages/cs-chat/cs-chat';
|
||||
queryParam = { teamId: teamId };
|
||||
} else if (data.notificationType === 'group' || msg.groupId) {
|
||||
const groupId = data.groupId || msg.groupId;
|
||||
const orderId = data.orderId || msg.orderId || '';
|
||||
const groupName = data.groupName || '订单群聊';
|
||||
const groupAvatar = data.groupAvatar || '';
|
||||
const isCross = data.isCross || msg.isCross || 0;
|
||||
path = '/pages/group-chat/group-chat';
|
||||
queryParam = {
|
||||
groupId,
|
||||
orderId,
|
||||
groupName,
|
||||
groupAvatar,
|
||||
isCross
|
||||
};
|
||||
} else {
|
||||
const toUserId = data.senderId || msg.senderId;
|
||||
const toName = data.senderName || '用户';
|
||||
const toAvatar = data.avatar || '';
|
||||
path = '/pages/chat/chat';
|
||||
queryParam = {
|
||||
toUserId,
|
||||
toName,
|
||||
toAvatar
|
||||
};
|
||||
}
|
||||
|
||||
if (path && queryParam) {
|
||||
const encoded = encodeURIComponent(JSON.stringify(queryParam));
|
||||
wx.navigateTo({
|
||||
url: `${path}?data=${encoded}`,
|
||||
fail: (err) => {
|
||||
console.error('通知跳转失败:', err);
|
||||
wx.switchTab({ url: '/pages/messages/messages' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.switchTab({ url: '/pages/messages/messages' });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -18,7 +18,6 @@ Component({
|
||||
isFullscreen: false,
|
||||
timer: null,
|
||||
|
||||
// 悬浮窗相关数据
|
||||
isMinimized: false,
|
||||
floatX: 20,
|
||||
floatY: 200,
|
||||
@@ -163,7 +162,7 @@ Component({
|
||||
this.setData({ muteChecked: e.detail.value.length > 0 });
|
||||
},
|
||||
|
||||
// 🆕 替换原有的 onPreviewImage,改用自定义预览(不触发 onShow)
|
||||
// 自定义图片预览
|
||||
onCustomPreview(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const urls = this.data.processedImages.map(img => img.url);
|
||||
@@ -174,7 +173,6 @@ Component({
|
||||
});
|
||||
},
|
||||
|
||||
// 🆕 关闭自定义预览
|
||||
onCloseCustomPreview() {
|
||||
this.setData({
|
||||
showCustomPreview: false,
|
||||
@@ -225,7 +223,7 @@ Component({
|
||||
if (app.globalData.morentouxiang) {
|
||||
avatarUrl = app.globalData.morentouxiang;
|
||||
} else {
|
||||
// 使用内嵌的默认头像 base64(灰色圆形),确保绝对显示,不依赖外部图片
|
||||
// 默认头像
|
||||
avatarUrl = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI1MCIgZmlsbD0iI2NjY2NjYyIvPjxwYXRoIGQ9Ik01MCAyNWMtMTMuOCAwLTI1IDExLjItMjUgMjUgMCAzLjIgMS4yIDYuMSAzLjIgOC4zQzM0LjQgNzAuNyA0Mi4xIDc1IDUwIDc1czE1LjYtNC4zIDIxLjgtMTEuN0M3My44IDU2LjEgNzUgNTMuMiA3NSA1MGMwLTEzLjgtMTEuMi0yNS0yNS0yNXoiIGZpbGw9IiNmZmZmZmYiLz48L3N2Zz4=';
|
||||
}
|
||||
|
||||
@@ -319,7 +317,7 @@ Component({
|
||||
return false;
|
||||
},
|
||||
|
||||
// 🆕 阻止事件冒泡(用于预览遮罩内部点击不关闭)
|
||||
// 阻止事件冒泡
|
||||
stopPropagation() {}
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
<!-- components/popup-notice/popup-notice.wxml -->
|
||||
|
||||
<!-- 全屏弹窗遮罩层(完全不变) -->
|
||||
<view class="popup-mask" wx:if="{{visible}}" catchtouchmove="preventMove">
|
||||
<view class="popup-container {{isFullscreen ? 'fullscreen' : ''}}">
|
||||
<!-- 右上角操作按钮组 -->
|
||||
@@ -83,7 +82,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 🆕 自定义图片预览遮罩(全屏,不触发页面生命周期) -->
|
||||
<view
|
||||
<view
|
||||
class="custom-preview-mask"
|
||||
wx:if="{{showCustomPreview}}"
|
||||
catchtouchmove="preventMove"
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
/* 以下原有 movable-view 相关样式已弃用,但保留以维持代码完整(用户要求不删代码) */
|
||||
/* 弃用样式 */
|
||||
.floating-area {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,109 +1,109 @@
|
||||
// custom-tab-bar/index.js — 三端固定,无身份切换
|
||||
const app = getApp();
|
||||
import { getTabRole } from '../utils/primary-role.js';
|
||||
|
||||
const roleCfg = {
|
||||
normal: {
|
||||
name: '点单老板',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/index/index', text: '商城', iconPath: '/images/zhuye.png', selectedIconPath: '/images/zhuye.png' },
|
||||
{ pagePath: 'pages/fenlei/fenlei', text: '分类', iconPath: '/images/fenlei.png', selectedIconPath: '/images/fenlei.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/wode/wode', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
dashou: {
|
||||
name: '打手',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/jiedan/jiedan', text: '接单池', iconPath: '/images/jiedanchi.png', selectedIconPath: '/images/jiedanchi.png' },
|
||||
{ pagePath: 'pages/dashoudingdan/dashoudingdan', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/dashouduan/dashouduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
shangjia: {
|
||||
name: '商家',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/sjdingdan/sjdingdan', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/shangjiaduan/shangjiaduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
Component({
|
||||
data: {
|
||||
selectedIndex: 0,
|
||||
tabList: [],
|
||||
currentRole: 'normal',
|
||||
badgeText: '',
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.refresh();
|
||||
this._badgeListener = (data) => {
|
||||
if (data.badgeText !== undefined) {
|
||||
this.setData({ badgeText: data.badgeText });
|
||||
}
|
||||
};
|
||||
this._roleListener = () => this.refresh();
|
||||
app.on('tabBarBadgeChanged', this._badgeListener);
|
||||
app.on('currentRoleChanged', this._roleListener);
|
||||
},
|
||||
detached() {
|
||||
if (this._badgeListener) app.off('tabBarBadgeChanged', this._badgeListener);
|
||||
if (this._roleListener) app.off('currentRoleChanged', this._roleListener);
|
||||
},
|
||||
},
|
||||
|
||||
pageLifetimes: {
|
||||
show() {
|
||||
this.refresh();
|
||||
const globalBadge = app.globalData.messageManager?.tabBarBadgeText || '';
|
||||
if (this.data.badgeText !== globalBadge) {
|
||||
this.setData({ badgeText: globalBadge });
|
||||
}
|
||||
this._syncUnreadWithDebounce();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
_syncUnreadWithDebounce() {
|
||||
if (this._syncTimer) clearTimeout(this._syncTimer);
|
||||
this._syncTimer = setTimeout(() => {
|
||||
if (app && app.loadConversations) app.loadConversations();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
refresh() {
|
||||
const token = wx.getStorageSync('token');
|
||||
let role = getTabRole(app);
|
||||
if (!token) {
|
||||
role = 'normal';
|
||||
}
|
||||
app.globalData.currentRole = role;
|
||||
wx.setStorageSync('currentRole', role);
|
||||
|
||||
let cfg = roleCfg[role];
|
||||
if (!cfg) {
|
||||
cfg = roleCfg.normal;
|
||||
role = 'normal';
|
||||
}
|
||||
|
||||
const list = cfg.tabList.map((v, i) => ({ ...v, index: i }));
|
||||
const pages = getCurrentPages();
|
||||
const curRoute = pages.length ? pages[pages.length - 1].route : '';
|
||||
let idx = list.findIndex((t) => t.pagePath === curRoute);
|
||||
if (idx === -1) idx = 0;
|
||||
this.setData({ currentRole: role, tabList: list, selectedIndex: idx });
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const path = e.currentTarget.dataset.path;
|
||||
const idx = e.currentTarget.dataset.index;
|
||||
if (idx === this.data.selectedIndex) return;
|
||||
wx.redirectTo({ url: '/' + path });
|
||||
},
|
||||
},
|
||||
});
|
||||
// custom-tab-bar/index.js — 三端固定,无身份切换
|
||||
const app = getApp();
|
||||
import { getTabRole } from '../utils/primary-role.js';
|
||||
|
||||
const roleCfg = {
|
||||
normal: {
|
||||
name: '点单老板',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/index/index', text: '商城', iconPath: '/images/zhuye.png', selectedIconPath: '/images/zhuye.png' },
|
||||
{ pagePath: 'pages/category/category', text: '分类', iconPath: '/images/fenlei.png', selectedIconPath: '/images/fenlei.png' },
|
||||
{ pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/mine/mine', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
dashou: {
|
||||
name: '打手',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/accept-order/accept-order', text: '接单池', iconPath: '/images/jiedanchi.png', selectedIconPath: '/images/jiedanchi.png' },
|
||||
{ pagePath: 'pages/fighter-orders/fighter-orders', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/fighter/fighter', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
shangjia: {
|
||||
name: '商家',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/merchant-orders/merchant-orders', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/messages/messages', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/merchant/merchant', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
Component({
|
||||
data: {
|
||||
selectedIndex: 0,
|
||||
tabList: [],
|
||||
currentRole: 'normal',
|
||||
badgeText: '',
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.refresh();
|
||||
this._badgeListener = (data) => {
|
||||
if (data.badgeText !== undefined) {
|
||||
this.setData({ badgeText: data.badgeText });
|
||||
}
|
||||
};
|
||||
this._roleListener = () => this.refresh();
|
||||
app.on('tabBarBadgeChanged', this._badgeListener);
|
||||
app.on('currentRoleChanged', this._roleListener);
|
||||
},
|
||||
detached() {
|
||||
if (this._badgeListener) app.off('tabBarBadgeChanged', this._badgeListener);
|
||||
if (this._roleListener) app.off('currentRoleChanged', this._roleListener);
|
||||
},
|
||||
},
|
||||
|
||||
pageLifetimes: {
|
||||
show() {
|
||||
this.refresh();
|
||||
const globalBadge = app.globalData.messageManager?.tabBarBadgeText || '';
|
||||
if (this.data.badgeText !== globalBadge) {
|
||||
this.setData({ badgeText: globalBadge });
|
||||
}
|
||||
this._syncUnreadWithDebounce();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
_syncUnreadWithDebounce() {
|
||||
if (this._syncTimer) clearTimeout(this._syncTimer);
|
||||
this._syncTimer = setTimeout(() => {
|
||||
if (app && app.loadConversations) app.loadConversations();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
refresh() {
|
||||
const token = wx.getStorageSync('token');
|
||||
let role = getTabRole(app);
|
||||
if (!token) {
|
||||
role = 'normal';
|
||||
}
|
||||
app.globalData.currentRole = role;
|
||||
wx.setStorageSync('currentRole', role);
|
||||
|
||||
let cfg = roleCfg[role];
|
||||
if (!cfg) {
|
||||
cfg = roleCfg.normal;
|
||||
role = 'normal';
|
||||
}
|
||||
|
||||
const list = cfg.tabList.map((v, i) => ({ ...v, index: i }));
|
||||
const pages = getCurrentPages();
|
||||
const curRoute = pages.length ? pages[pages.length - 1].route : '';
|
||||
let idx = list.findIndex((t) => t.pagePath === curRoute);
|
||||
if (idx === -1) idx = 0;
|
||||
this.setData({ currentRole: role, tabList: list, selectedIndex: idx });
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const path = e.currentTarget.dataset.path;
|
||||
const idx = e.currentTarget.dataset.index;
|
||||
if (idx === this.data.selectedIndex) return;
|
||||
wx.redirectTo({ url: '/' + path });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<view class="custom-tab-bar">
|
||||
<view class="bar-row">
|
||||
<view class="tab-capsule">
|
||||
<block wx:for="{{tabList}}" wx:key="index">
|
||||
<view
|
||||
class="tab-item {{selectedIndex === index ? 'active' : ''}}"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
catchtap="switchTab"
|
||||
>
|
||||
<view class="badge-container" wx:if="{{item.pagePath === 'pages/xiaoxi/xiaoxi' && badgeText}}">
|
||||
<view class="tab-badge">{{badgeText}}</view>
|
||||
</view>
|
||||
<image
|
||||
class="tab-icon"
|
||||
src="{{selectedIndex === index ? item.selectedIconPath : item.iconPath}}"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="tab-text">{{item.text}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="custom-tab-bar">
|
||||
<view class="bar-row">
|
||||
<view class="tab-capsule">
|
||||
<block wx:for="{{tabList}}" wx:key="index">
|
||||
<view
|
||||
class="tab-item {{selectedIndex === index ? 'active' : ''}}"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
catchtap="switchTab"
|
||||
>
|
||||
<view class="badge-container" wx:if="{{item.pagePath === 'pages/messages/messages' && badgeText}}">
|
||||
<view class="tab-badge">{{badgeText}}</view>
|
||||
</view>
|
||||
<image
|
||||
class="tab-icon"
|
||||
src="{{selectedIndex === index ? item.selectedIconPath : item.iconPath}}"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="tab-text">{{item.text}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,240 +1,240 @@
|
||||
// pages/shenhedating/shenhedating.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 模块列表 [{bankuai_id, mingcheng, count, is_related}]
|
||||
moduleList: [],
|
||||
xuanzhongBankuaiId: 0, // 0代表全部
|
||||
// 审核记录列表
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 5,
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
lastRefreshTime: 0,
|
||||
refreshCooldown: 2000,
|
||||
// 弹窗控制
|
||||
showRuleModal: false,
|
||||
currentRuleContent: '',
|
||||
showBeizhuModal: false,
|
||||
currentBeizhuContent: '',
|
||||
// 加载状态
|
||||
loadingModules: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadModules();
|
||||
},
|
||||
|
||||
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()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 加载板块模块
|
||||
async loadModules() {
|
||||
this.setData({ loadingModules: true });
|
||||
try {
|
||||
const res = await request({ url: '/dengji/shdthqmk', method: 'POST' });
|
||||
if (res && res.data.code === 0) {
|
||||
const modules = res.data.data.modules || [];
|
||||
this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 });
|
||||
this.loadRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: '加载模块失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ loadingModules: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 选择模块(含全部)
|
||||
selectModule(e) {
|
||||
const bankuaiId = e.currentTarget.dataset.id;
|
||||
if (bankuaiId === this.data.xuanzhongBankuaiId) return;
|
||||
this.setData({
|
||||
xuanzhongBankuaiId: bankuaiId,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载审核记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
if (!isRefresh && !this.data.hasMore) return;
|
||||
|
||||
this.setData({ isLoading: true, isLoadingMore: !isRefresh });
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/hqshsj',
|
||||
method: 'POST',
|
||||
data: {
|
||||
bankuai_id: this.data.xuanzhongBankuaiId || undefined,
|
||||
page: page,
|
||||
page_size: this.data.pageSize
|
||||
}
|
||||
});
|
||||
|
||||
this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false });
|
||||
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const processedList = list.map(item => {
|
||||
let avatar = item.shenqingren_avatar || '';
|
||||
if (avatar && !avatar.startsWith('http')) {
|
||||
avatar = ossUrl + avatar;
|
||||
}
|
||||
return { ...item, shenqingren_avatar: avatar };
|
||||
});
|
||||
const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore: hasMore });
|
||||
if (isRefresh) this.setData({ lastRefreshTime: Date.now() });
|
||||
} else {
|
||||
wx.showToast({ title: '加载记录失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false });
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom() {
|
||||
const now = Date.now();
|
||||
if (now - this.data.lastRefreshTime < this.data.refreshCooldown ||
|
||||
this.data.isLoading || this.data.isLoadingMore) return;
|
||||
if (this.data.hasMore) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
const now = Date.now();
|
||||
if (now - this.data.lastRefreshTime < this.data.refreshCooldown || this.data.isLoading) {
|
||||
this.setData({ scrollViewRefreshing: false });
|
||||
return;
|
||||
}
|
||||
this.setData({ scrollViewRefreshing: true, lastRefreshTime: now, page: 1, hasMore: true });
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 查看规则详情
|
||||
showRuleDetail(e) {
|
||||
const content = e.currentTarget.dataset.content;
|
||||
this.setData({ showRuleModal: true, currentRuleContent: content });
|
||||
},
|
||||
hideRuleDetail() {
|
||||
this.setData({ showRuleModal: false, currentRuleContent: '' });
|
||||
},
|
||||
|
||||
// 查看备注详情
|
||||
showBeizhuDetail(e) {
|
||||
const content = e.currentTarget.dataset.content;
|
||||
this.setData({ showBeizhuModal: true, currentBeizhuContent: content || '无' });
|
||||
},
|
||||
hideBeizhuDetail() {
|
||||
this.setData({ showBeizhuModal: false, currentBeizhuContent: '' });
|
||||
},
|
||||
|
||||
// 抢单
|
||||
async onShouShen(e) {
|
||||
const jiluId = e.currentTarget.dataset.jiluid;
|
||||
const bankuaiId = e.currentTarget.dataset.bankuaiid;
|
||||
if (!jiluId) {
|
||||
wx.showToast({ title: '记录ID异常,无法接单', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const that = this;
|
||||
wx.showModal({
|
||||
title: '确认审核',
|
||||
content: '确定要审核此用户吗?审核后请前往游戏进行审核,并严格评分。',
|
||||
confirmColor: '#c9a558',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '接单中...', mask: true });
|
||||
try {
|
||||
const qdRes = await request({
|
||||
url: '/dengji/shqd',
|
||||
method: 'POST',
|
||||
data: { jilu_id: jiluId }
|
||||
});
|
||||
if (qdRes && qdRes.data.code === 0) {
|
||||
// 抢单成功,弹出联系打手弹窗
|
||||
wx.showModal({
|
||||
title: '接待成功',
|
||||
content: '请认真考核,点击联系他查看打手信息并打分。',
|
||||
showCancel: false,
|
||||
confirmText: '联系他',
|
||||
confirmColor: '#c9a558',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/kaohe_dafen/kaohe_dafen?jilu_id=' + jiluId
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
const newList = that.data.recordList.filter(r => r.jilu_id !== jiluId);
|
||||
that.setData({ recordList: newList });
|
||||
// 对应板块待审核数减1
|
||||
const bkId = qdRes.data.data ? qdRes.data.data.bankuai_id : bankuaiId;
|
||||
if (bkId) {
|
||||
const newModules = that.data.moduleList.map(m => {
|
||||
if (m.bankuai_id === bkId && m.count > 0) {
|
||||
return { ...m, count: m.count - 1 };
|
||||
}
|
||||
return m;
|
||||
});
|
||||
that.setData({ moduleList: newModules });
|
||||
}
|
||||
} else {
|
||||
const errMsg = qdRes?.data?.msg || '接单失败,请重试';
|
||||
wx.showModal({
|
||||
title: '接单失败',
|
||||
content: errMsg,
|
||||
showCancel: false,
|
||||
confirmText: '知道了',
|
||||
confirmColor: '#c9a558'
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '网络错误,请重试',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
} finally {
|
||||
wx.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
noop() {}
|
||||
// pages/shenhedating/shenhedating.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 模块列表 [{bankuai_id, mingcheng, count, is_related}]
|
||||
moduleList: [],
|
||||
xuanzhongBankuaiId: 0, // 0代表全部
|
||||
// 审核记录列表
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 5,
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
lastRefreshTime: 0,
|
||||
refreshCooldown: 2000,
|
||||
// 弹窗控制
|
||||
showRuleModal: false,
|
||||
currentRuleContent: '',
|
||||
showBeizhuModal: false,
|
||||
currentBeizhuContent: '',
|
||||
// 加载状态
|
||||
loadingModules: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadModules();
|
||||
},
|
||||
|
||||
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()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 加载板块模块
|
||||
async loadModules() {
|
||||
this.setData({ loadingModules: true });
|
||||
try {
|
||||
const res = await request({ url: '/dengji/shdthqmk', method: 'POST' });
|
||||
if (res && res.data.code === 0) {
|
||||
const modules = res.data.data.modules || [];
|
||||
this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 });
|
||||
this.loadRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: '加载模块失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ loadingModules: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 选择模块(含全部)
|
||||
selectModule(e) {
|
||||
const bankuaiId = e.currentTarget.dataset.id;
|
||||
if (bankuaiId === this.data.xuanzhongBankuaiId) return;
|
||||
this.setData({
|
||||
xuanzhongBankuaiId: bankuaiId,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载审核记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
if (!isRefresh && !this.data.hasMore) return;
|
||||
|
||||
this.setData({ isLoading: true, isLoadingMore: !isRefresh });
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/hqshsj',
|
||||
method: 'POST',
|
||||
data: {
|
||||
bankuai_id: this.data.xuanzhongBankuaiId || undefined,
|
||||
page: page,
|
||||
page_size: this.data.pageSize
|
||||
}
|
||||
});
|
||||
|
||||
this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false });
|
||||
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const processedList = list.map(item => {
|
||||
let avatar = item.shenqingren_avatar || '';
|
||||
if (avatar && !avatar.startsWith('http')) {
|
||||
avatar = ossUrl + avatar;
|
||||
}
|
||||
return { ...item, shenqingren_avatar: avatar };
|
||||
});
|
||||
const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore: hasMore });
|
||||
if (isRefresh) this.setData({ lastRefreshTime: Date.now() });
|
||||
} else {
|
||||
wx.showToast({ title: '加载记录失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ isLoading: false, isLoadingMore: false, scrollViewRefreshing: false });
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom() {
|
||||
const now = Date.now();
|
||||
if (now - this.data.lastRefreshTime < this.data.refreshCooldown ||
|
||||
this.data.isLoading || this.data.isLoadingMore) return;
|
||||
if (this.data.hasMore) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
const now = Date.now();
|
||||
if (now - this.data.lastRefreshTime < this.data.refreshCooldown || this.data.isLoading) {
|
||||
this.setData({ scrollViewRefreshing: false });
|
||||
return;
|
||||
}
|
||||
this.setData({ scrollViewRefreshing: true, lastRefreshTime: now, page: 1, hasMore: true });
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 查看规则详情
|
||||
showRuleDetail(e) {
|
||||
const content = e.currentTarget.dataset.content;
|
||||
this.setData({ showRuleModal: true, currentRuleContent: content });
|
||||
},
|
||||
hideRuleDetail() {
|
||||
this.setData({ showRuleModal: false, currentRuleContent: '' });
|
||||
},
|
||||
|
||||
// 查看备注详情
|
||||
showBeizhuDetail(e) {
|
||||
const content = e.currentTarget.dataset.content;
|
||||
this.setData({ showBeizhuModal: true, currentBeizhuContent: content || '无' });
|
||||
},
|
||||
hideBeizhuDetail() {
|
||||
this.setData({ showBeizhuModal: false, currentBeizhuContent: '' });
|
||||
},
|
||||
|
||||
// 抢单
|
||||
async onShouShen(e) {
|
||||
const jiluId = e.currentTarget.dataset.jiluid;
|
||||
const bankuaiId = e.currentTarget.dataset.bankuaiid;
|
||||
if (!jiluId) {
|
||||
wx.showToast({ title: '记录ID异常,无法接单', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const that = this;
|
||||
wx.showModal({
|
||||
title: '确认审核',
|
||||
content: '确定要审核此用户吗?审核后请前往游戏进行审核,并严格评分。',
|
||||
confirmColor: '#c9a558',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '接单中...', mask: true });
|
||||
try {
|
||||
const qdRes = await request({
|
||||
url: '/dengji/shqd',
|
||||
method: 'POST',
|
||||
data: { jilu_id: jiluId }
|
||||
});
|
||||
if (qdRes && qdRes.data.code === 0) {
|
||||
// 抢单成功,弹出联系打手弹窗
|
||||
wx.showModal({
|
||||
title: '接待成功',
|
||||
content: '请认真考核,点击联系他查看打手信息并打分。',
|
||||
showCancel: false,
|
||||
confirmText: '联系他',
|
||||
confirmColor: '#c9a558',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/assess-score/assess-score?jilu_id=' + jiluId
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
const newList = that.data.recordList.filter(r => r.jilu_id !== jiluId);
|
||||
that.setData({ recordList: newList });
|
||||
// 对应板块待审核数减1
|
||||
const bkId = qdRes.data.data ? qdRes.data.data.bankuai_id : bankuaiId;
|
||||
if (bkId) {
|
||||
const newModules = that.data.moduleList.map(m => {
|
||||
if (m.bankuai_id === bkId && m.count > 0) {
|
||||
return { ...m, count: m.count - 1 };
|
||||
}
|
||||
return m;
|
||||
});
|
||||
that.setData({ moduleList: newModules });
|
||||
}
|
||||
} else {
|
||||
const errMsg = qdRes?.data?.msg || '接单失败,请重试';
|
||||
wx.showModal({
|
||||
title: '接单失败',
|
||||
content: errMsg,
|
||||
showCancel: false,
|
||||
confirmText: '知道了',
|
||||
confirmColor: '#c9a558'
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '网络错误,请重试',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
} finally {
|
||||
wx.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
noop() {}
|
||||
});
|
||||
@@ -245,8 +245,7 @@
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
|
||||
/* 弹窗 */
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
@@ -1,461 +1,461 @@
|
||||
// pages/kaohe_jinpai/kaohe_jinpai.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
activeTab: 'all_tags',
|
||||
plateList: [], // 第一个接口返回的所有板块及标签(含 fee_list)
|
||||
myTags: [],
|
||||
recordList: [],
|
||||
recordPage: 1,
|
||||
recordHasMore: true,
|
||||
recordLoading: false,
|
||||
recordFilter: 'pending',
|
||||
showApplyModal: false,
|
||||
selectedTag: null,
|
||||
applyGameNick: '',
|
||||
applyRemark: '',
|
||||
applyFee: 0,
|
||||
applyJiluId: '',
|
||||
isReapply: false,
|
||||
payLoading: false,
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 新增:考核官相关
|
||||
kaoheguanList: [], // 所有可选的考核官
|
||||
showKaoheguanModal: false, // 考核官选择弹窗
|
||||
selectedKaoheguanId: '', // 已选择的考核官ID
|
||||
selectedKaoheguanInfo: null, // 已选择的考核官信息(用于展示)
|
||||
searchKeyword: '', // 搜索关键词
|
||||
filteredKaoheguanList: [], // 搜索过滤后的列表
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.fetchAllTags();
|
||||
this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const tab = e.currentTarget.dataset.tab;
|
||||
if (tab === this.data.activeTab) return;
|
||||
this.setData({ activeTab: tab });
|
||||
if (tab === 'my_records') this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
// 获取所有板块及标签(含费用列表),缓存到 plateList,同时获取考核官列表
|
||||
async fetchAllTags() {
|
||||
try {
|
||||
const res = await request({ url: '/dengji/dskhhq', method: 'POST' });
|
||||
if (res.data.code === 0) {
|
||||
const { plate_list, my_tags, kaoheguan_list } = res.data.data;
|
||||
// 拼接考核官头像为完整URL
|
||||
const ossUrl = this.data.ossImageUrl;
|
||||
const processedKgList = (kaoheguan_list || []).map(kg => ({
|
||||
...kg,
|
||||
avatar: kg.avatar && !kg.avatar.startsWith('http') ? ossUrl + kg.avatar : kg.avatar,
|
||||
}));
|
||||
this.setData({
|
||||
plateList: plate_list || [],
|
||||
myTags: my_tags || [],
|
||||
kaoheguanList: processedKgList // 使用拼接后的列表
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// 获取我的考核记录,并根据 plateList 计算本次/预计下次费用
|
||||
async fetchMyRecords(isRefresh = false) {
|
||||
if (this.data.recordLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.recordPage;
|
||||
this.setData({ recordLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dskhjl',
|
||||
method: 'POST',
|
||||
data: { status: this.data.recordFilter, page, page_size: 5 }
|
||||
});
|
||||
if (res.data.code === 0) {
|
||||
const { list, has_more } = res.data.data;
|
||||
|
||||
// 从 plateList 构建标签ID -> 完整标签对象的映射(用于精确匹配费用)
|
||||
const tagMap = {};
|
||||
this.data.plateList.forEach(plate => {
|
||||
(plate.tags || []).forEach(tag => {
|
||||
tagMap[tag.id] = tag; // tag 包含 fee_list
|
||||
});
|
||||
});
|
||||
|
||||
// 处理每条记录:优先使用 tag_obj.id 匹配,其次 chenghao_id
|
||||
const processed = list.map(item => {
|
||||
// 尝试多种方式获取标签ID
|
||||
const tagId = (item.tag_obj && item.tag_obj.id) || item.chenghao_id;
|
||||
const tag = tagMap[tagId] || item.tag_obj || {};
|
||||
const feeList = tag.fee_list || [];
|
||||
let currentFee = 0;
|
||||
let nextFee = 0;
|
||||
if (feeList.length > 0) {
|
||||
const cishu = item.cishu;
|
||||
const cur = feeList.find(f => f.cishu === cishu);
|
||||
currentFee = cur ? cur.feiyong : feeList[feeList.length - 1].feiyong;
|
||||
const nextCishu = cishu + 1;
|
||||
const nxt = feeList.find(f => f.cishu === nextCishu);
|
||||
nextFee = nxt ? nxt.feiyong : feeList[feeList.length - 1].feiyong;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
current_fee: currentFee,
|
||||
next_fee: nextFee,
|
||||
tag_obj: tag // 使用匹配到的完整标签对象,保证后续“再次考核”能拿到费用
|
||||
};
|
||||
});
|
||||
|
||||
const newList = isRefresh ? processed : [...this.data.recordList, ...processed];
|
||||
this.setData({
|
||||
recordList: newList,
|
||||
recordPage: page + 1,
|
||||
recordHasMore: has_more,
|
||||
recordLoading: false
|
||||
});
|
||||
} else {
|
||||
this.setData({ recordLoading: false });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ recordLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
filterRecord(e) {
|
||||
const filter = e.currentTarget.dataset.filter;
|
||||
if (filter === this.data.recordFilter) return;
|
||||
this.setData({ recordFilter: filter, recordList: [], recordPage: 1, recordHasMore: true });
|
||||
this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (this.data.activeTab === 'my_records' && this.data.recordHasMore) {
|
||||
this.fetchMyRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 打开申请考核弹窗,费用完全基于 plateList 中的标签数据
|
||||
openApplyModal(e) {
|
||||
const { tag, jiluid, reapply } = e.currentTarget.dataset;
|
||||
// 查找完整标签对象,保证 fee_list 存在
|
||||
let fullTag = tag;
|
||||
if (fullTag && fullTag.fee_list === undefined) {
|
||||
const found = this.findTagInPlateList(fullTag.id);
|
||||
if (found) fullTag = found;
|
||||
}
|
||||
if (!fullTag) {
|
||||
const found = this.findTagInPlateList(tag);
|
||||
if (found) fullTag = found;
|
||||
}
|
||||
|
||||
let fee = 0;
|
||||
if (fullTag) {
|
||||
let nextCishu = 0;
|
||||
// 再次申请时,基于原记录次数计算下一次考核次数
|
||||
if (reapply && jiluid) {
|
||||
const record = this.data.recordList.find(r => r.jilu_id === jiluid);
|
||||
if (record) {
|
||||
nextCishu = record.cishu + 1;
|
||||
} else {
|
||||
nextCishu = (fullTag.my_cishu || 0) + 1;
|
||||
}
|
||||
} else {
|
||||
nextCishu = (fullTag.my_cishu || 0) + 1;
|
||||
}
|
||||
const feeList = fullTag.fee_list || [];
|
||||
const exact = feeList.find(f => f.cishu === nextCishu);
|
||||
if (exact) {
|
||||
fee = exact.feiyong;
|
||||
} else if (feeList.length > 0) {
|
||||
fee = feeList[feeList.length - 1].feiyong;
|
||||
}
|
||||
}
|
||||
// 检查再次申请时原记录是否有考核官,若有则不允许指定
|
||||
let canSpecify = true;
|
||||
let originalShenheguanId = '';
|
||||
if (reapply && jiluid) {
|
||||
const record = this.data.recordList.find(r => r.jilu_id === jiluid);
|
||||
if (record && record.shenheguan_id) {
|
||||
canSpecify = false; // 已有考核官,不能指定新的
|
||||
originalShenheguanId = record.shenheguan_id;
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
showApplyModal: true,
|
||||
selectedTag: fullTag || null,
|
||||
applyGameNick: '',
|
||||
applyRemark: '',
|
||||
applyFee: fee,
|
||||
applyJiluId: jiluid || '',
|
||||
isReapply: reapply || false,
|
||||
selectedKaoheguanId: '', // 重置
|
||||
selectedKaoheguanInfo: null,
|
||||
canSpecify: canSpecify, // 新增
|
||||
originalShenheguanId: originalShenheguanId, // 新增
|
||||
});
|
||||
},
|
||||
|
||||
// 辅助方法:从 plateList 查找指定 id 的标签
|
||||
findTagInPlateList(tagId) {
|
||||
if (!tagId) return null;
|
||||
for (const plate of this.data.plateList) {
|
||||
for (const t of (plate.tags || [])) {
|
||||
if (t.id === tagId) return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
closeApplyModal() {
|
||||
this.setData({ showApplyModal: false });
|
||||
},
|
||||
|
||||
// 实时更新游戏昵称
|
||||
onNickInput(e) {
|
||||
this.setData({ applyGameNick: e.detail.value });
|
||||
},
|
||||
|
||||
// 实时更新备注
|
||||
onRemarkInput(e) {
|
||||
this.setData({ applyRemark: e.detail.value });
|
||||
},
|
||||
|
||||
// 新增:打开考核官选择弹窗
|
||||
openKaoheguanModal() {
|
||||
if (!this.data.canSpecify) {
|
||||
wx.showToast({ title: '已有考核官,无法重新指定', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
// 根据费用筛选可选考核官
|
||||
let all = [...this.data.kaoheguanList];
|
||||
if (this.data.applyFee > 0) {
|
||||
all = all.filter(kg => kg.is_renzheng);
|
||||
}
|
||||
this.setData({
|
||||
showKaoheguanModal: true,
|
||||
filteredKaoheguanList: all,
|
||||
searchKeyword: '',
|
||||
});
|
||||
},
|
||||
|
||||
// 关闭考核官选择弹窗
|
||||
closeKaoheguanModal() {
|
||||
this.setData({ showKaoheguanModal: false });
|
||||
},
|
||||
|
||||
// 搜索输入
|
||||
onSearchInput(e) {
|
||||
const value = e.detail.value.trim();
|
||||
this.setData({ searchKeyword: value });
|
||||
this.filterKaoheguanList(value);
|
||||
},
|
||||
|
||||
// 过滤考核官列表
|
||||
filterKaoheguanList(keyword) {
|
||||
let all = [...this.data.kaoheguanList];
|
||||
if (this.data.applyFee > 0) {
|
||||
all = all.filter(kg => kg.is_renzheng);
|
||||
}
|
||||
if (keyword) {
|
||||
all = all.filter(kg =>
|
||||
kg.yonghuid.includes(keyword) ||
|
||||
(kg.dashou_nick && kg.dashou_nick.includes(keyword))
|
||||
);
|
||||
}
|
||||
this.setData({ filteredKaoheguanList: all });
|
||||
},
|
||||
|
||||
// 选择一个考核官
|
||||
selectKaoheguan(e) {
|
||||
const kg = e.currentTarget.dataset.kg;
|
||||
if (kg.shenhe_zhuangtai !== 0) {
|
||||
wx.showToast({ title: '该考核官正忙,无法指定', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
selectedKaoheguanId: kg.yonghuid,
|
||||
selectedKaoheguanInfo: kg,
|
||||
showKaoheguanModal: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 取消已选择的考核官
|
||||
clearSelectedKaoheguan() {
|
||||
this.setData({
|
||||
selectedKaoheguanId: '',
|
||||
selectedKaoheguanInfo: null,
|
||||
});
|
||||
},
|
||||
|
||||
// 提交申请
|
||||
async submitApply() {
|
||||
const { applyGameNick, applyRemark, applyFee, selectedTag, isReapply, applyJiluId, selectedKaoheguanId } = this.data;
|
||||
if (!applyGameNick || !applyGameNick.trim()) {
|
||||
wx.showToast({ title: '请输入游戏昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!applyRemark || !applyRemark.trim()) {
|
||||
wx.showToast({ title: '请填写备注', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (applyFee > 0) {
|
||||
await this.startPayProcess();
|
||||
} else {
|
||||
await this.doFreeApply();
|
||||
}
|
||||
},
|
||||
|
||||
// 支付流程
|
||||
async startPayProcess() {
|
||||
this.setData({ payLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/khzf',
|
||||
method: 'POST',
|
||||
data: {
|
||||
tag_id: this.data.selectedTag.id,
|
||||
game_nick: this.data.applyGameNick,
|
||||
remark: this.data.applyRemark,
|
||||
reapply: this.data.isReapply,
|
||||
jilu_id: this.data.applyJiluId,
|
||||
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
||||
}
|
||||
});
|
||||
if (res.data.code !== 200) throw new Error(res.data.message || '下单失败');
|
||||
const payParams = res.data.payParams;
|
||||
const dingdanid = res.data.dingdanid;
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType || 'MD5',
|
||||
paySign: payParams.paySign,
|
||||
success: async () => {
|
||||
await this.pollPayStatus(dingdanid);
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '支付取消或失败', icon: 'none' });
|
||||
request({ url: '/yonghu/khzfsb', method: 'POST', data: { dingdanid } }).catch(()=>{});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
wx.showToast({ title: e.message || '支付异常', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ payLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 轮询支付结果
|
||||
async pollPayStatus(dingdanid) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
try {
|
||||
const res = await request({ url: '/yonghu/khzffc', method: 'POST', data: { dingdanid } });
|
||||
if (res.data.code === 200) {
|
||||
wx.showToast({ title: '申请成功', icon: 'success' });
|
||||
this.closeApplyModal();
|
||||
this.fetchAllTags();
|
||||
this.setData({ recordList: [], recordPage: 1 });
|
||||
this.fetchMyRecords(true);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
}
|
||||
wx.showToast({ title: '支付确认超时', icon: 'none' });
|
||||
},
|
||||
|
||||
// 免费申请
|
||||
async doFreeApply() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dssqkh',
|
||||
method: 'POST',
|
||||
data: {
|
||||
tag_id: this.data.selectedTag.id,
|
||||
game_nick: this.data.applyGameNick,
|
||||
remark: this.data.applyRemark,
|
||||
reapply: this.data.isReapply,
|
||||
jilu_id: this.data.applyJiluId,
|
||||
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
||||
}
|
||||
});
|
||||
if (res.data.code === 0) {
|
||||
wx.showToast({ title: '申请成功', icon: 'success' });
|
||||
this.closeApplyModal();
|
||||
this.fetchAllTags();
|
||||
this.setData({ recordList: [], recordPage: 1 });
|
||||
this.fetchMyRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: res.data.msg || '申请失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 联系考核官(私聊)
|
||||
contactKaoheguan(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
if (!item.shenheguan_id) {
|
||||
wx.showToast({ title: '暂无考核官信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (!uid) {
|
||||
wx.showToast({ title: '用户信息缺失', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (app.globalData.currentRole !== 'dashou') {
|
||||
app.globalData.currentRole = 'dashou';
|
||||
wx.setStorageSync('currentRole', 'dashou');
|
||||
}
|
||||
if (app.connectForCurrentRole) {
|
||||
app.connectForCurrentRole();
|
||||
} else if (app.ensureConnection) {
|
||||
app.ensureConnection();
|
||||
}
|
||||
const ossImageUrl = this.data.ossImageUrl || app.globalData.ossImageUrl || '';
|
||||
let fullAvatar = item.shenheguan_avatar || '';
|
||||
if (fullAvatar && !fullAvatar.startsWith('http')) {
|
||||
fullAvatar = ossImageUrl + fullAvatar;
|
||||
}
|
||||
if (!fullAvatar) {
|
||||
fullAvatar = ossImageUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
|
||||
}
|
||||
const param = {
|
||||
toUserId: 'Kh' + item.shenheguan_id,
|
||||
toName: '考核官' + item.shenheguan_id,
|
||||
toAvatar: fullAvatar
|
||||
};
|
||||
wx.navigateTo({
|
||||
url: '/pages/liaotian/liaotian?data=' + encodeURIComponent(JSON.stringify(param)),
|
||||
fail: (err) => {
|
||||
wx.showToast({ title: '打开聊天失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
showTagDetail(e) {
|
||||
const tag = e.currentTarget.dataset.tag;
|
||||
const feeStr = this.formatFeeList(tag.fee_list);
|
||||
wx.showModal({
|
||||
title: tag.name,
|
||||
content: `规则:${tag.rule || '暂无'}\n${tag.jinpai ? '【可同时开启金牌】' : ''}\n费用:${feeStr}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
},
|
||||
|
||||
formatFeeList(feeList) {
|
||||
if (!feeList || feeList.length === 0) return '暂无';
|
||||
let str = feeList.map(f => `第${f.cishu}次:¥${f.feiyong}`).join(';');
|
||||
const last = feeList[feeList.length - 1];
|
||||
str += `;第${last.cishu}次及以上:¥${last.feiyong}`;
|
||||
return str;
|
||||
},
|
||||
// pages/assess-gold/assess-gold.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
activeTab: 'all_tags',
|
||||
plateList: [], // 第一个接口返回的所有板块及标签(含 fee_list)
|
||||
myTags: [],
|
||||
recordList: [],
|
||||
recordPage: 1,
|
||||
recordHasMore: true,
|
||||
recordLoading: false,
|
||||
recordFilter: 'pending',
|
||||
showApplyModal: false,
|
||||
selectedTag: null,
|
||||
applyGameNick: '',
|
||||
applyRemark: '',
|
||||
applyFee: 0,
|
||||
applyJiluId: '',
|
||||
isReapply: false,
|
||||
payLoading: false,
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 新增:考核官相关
|
||||
kaoheguanList: [], // 所有可选的考核官
|
||||
showKaoheguanModal: false, // 考核官选择弹窗
|
||||
selectedKaoheguanId: '', // 已选择的考核官ID
|
||||
selectedKaoheguanInfo: null, // 已选择的考核官信息(用于展示)
|
||||
searchKeyword: '', // 搜索关键词
|
||||
filteredKaoheguanList: [], // 搜索过滤后的列表
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.fetchAllTags();
|
||||
this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const tab = e.currentTarget.dataset.tab;
|
||||
if (tab === this.data.activeTab) return;
|
||||
this.setData({ activeTab: tab });
|
||||
if (tab === 'my_records') this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
// 获取所有板块及标签(含费用列表),缓存到 plateList,同时获取考核官列表
|
||||
async fetchAllTags() {
|
||||
try {
|
||||
const res = await request({ url: '/dengji/dskhhq', method: 'POST' });
|
||||
if (res.data.code === 0) {
|
||||
const { plate_list, my_tags, kaoheguan_list } = res.data.data;
|
||||
// 拼接考核官头像为完整URL
|
||||
const ossUrl = this.data.ossImageUrl;
|
||||
const processedKgList = (kaoheguan_list || []).map(kg => ({
|
||||
...kg,
|
||||
avatar: kg.avatar && !kg.avatar.startsWith('http') ? ossUrl + kg.avatar : kg.avatar,
|
||||
}));
|
||||
this.setData({
|
||||
plateList: plate_list || [],
|
||||
myTags: my_tags || [],
|
||||
kaoheguanList: processedKgList // 使用拼接后的列表
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// 获取我的考核记录,并根据 plateList 计算本次/预计下次费用
|
||||
async fetchMyRecords(isRefresh = false) {
|
||||
if (this.data.recordLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.recordPage;
|
||||
this.setData({ recordLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dskhjl',
|
||||
method: 'POST',
|
||||
data: { status: this.data.recordFilter, page, page_size: 5 }
|
||||
});
|
||||
if (res.data.code === 0) {
|
||||
const { list, has_more } = res.data.data;
|
||||
|
||||
// 从 plateList 构建标签ID -> 完整标签对象的映射(用于精确匹配费用)
|
||||
const tagMap = {};
|
||||
this.data.plateList.forEach(plate => {
|
||||
(plate.tags || []).forEach(tag => {
|
||||
tagMap[tag.id] = tag; // tag 包含 fee_list
|
||||
});
|
||||
});
|
||||
|
||||
// 处理每条记录:优先使用 tag_obj.id 匹配,其次 chenghao_id
|
||||
const processed = list.map(item => {
|
||||
// 尝试多种方式获取标签ID
|
||||
const tagId = (item.tag_obj && item.tag_obj.id) || item.chenghao_id;
|
||||
const tag = tagMap[tagId] || item.tag_obj || {};
|
||||
const feeList = tag.fee_list || [];
|
||||
let currentFee = 0;
|
||||
let nextFee = 0;
|
||||
if (feeList.length > 0) {
|
||||
const cishu = item.cishu;
|
||||
const cur = feeList.find(f => f.cishu === cishu);
|
||||
currentFee = cur ? cur.feiyong : feeList[feeList.length - 1].feiyong;
|
||||
const nextCishu = cishu + 1;
|
||||
const nxt = feeList.find(f => f.cishu === nextCishu);
|
||||
nextFee = nxt ? nxt.feiyong : feeList[feeList.length - 1].feiyong;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
current_fee: currentFee,
|
||||
next_fee: nextFee,
|
||||
tag_obj: tag // 使用匹配到的完整标签对象,保证后续“再次考核”能拿到费用
|
||||
};
|
||||
});
|
||||
|
||||
const newList = isRefresh ? processed : [...this.data.recordList, ...processed];
|
||||
this.setData({
|
||||
recordList: newList,
|
||||
recordPage: page + 1,
|
||||
recordHasMore: has_more,
|
||||
recordLoading: false
|
||||
});
|
||||
} else {
|
||||
this.setData({ recordLoading: false });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ recordLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
filterRecord(e) {
|
||||
const filter = e.currentTarget.dataset.filter;
|
||||
if (filter === this.data.recordFilter) return;
|
||||
this.setData({ recordFilter: filter, recordList: [], recordPage: 1, recordHasMore: true });
|
||||
this.fetchMyRecords(true);
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (this.data.activeTab === 'my_records' && this.data.recordHasMore) {
|
||||
this.fetchMyRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 打开申请考核弹窗,费用完全基于 plateList 中的标签数据
|
||||
openApplyModal(e) {
|
||||
const { tag, jiluid, reapply } = e.currentTarget.dataset;
|
||||
// 查找完整标签对象,保证 fee_list 存在
|
||||
let fullTag = tag;
|
||||
if (fullTag && fullTag.fee_list === undefined) {
|
||||
const found = this.findTagInPlateList(fullTag.id);
|
||||
if (found) fullTag = found;
|
||||
}
|
||||
if (!fullTag) {
|
||||
const found = this.findTagInPlateList(tag);
|
||||
if (found) fullTag = found;
|
||||
}
|
||||
|
||||
let fee = 0;
|
||||
if (fullTag) {
|
||||
let nextCishu = 0;
|
||||
// 再次申请时,基于原记录次数计算下一次考核次数
|
||||
if (reapply && jiluid) {
|
||||
const record = this.data.recordList.find(r => r.jilu_id === jiluid);
|
||||
if (record) {
|
||||
nextCishu = record.cishu + 1;
|
||||
} else {
|
||||
nextCishu = (fullTag.my_cishu || 0) + 1;
|
||||
}
|
||||
} else {
|
||||
nextCishu = (fullTag.my_cishu || 0) + 1;
|
||||
}
|
||||
const feeList = fullTag.fee_list || [];
|
||||
const exact = feeList.find(f => f.cishu === nextCishu);
|
||||
if (exact) {
|
||||
fee = exact.feiyong;
|
||||
} else if (feeList.length > 0) {
|
||||
fee = feeList[feeList.length - 1].feiyong;
|
||||
}
|
||||
}
|
||||
// 检查再次申请时原记录是否有考核官,若有则不允许指定
|
||||
let canSpecify = true;
|
||||
let originalShenheguanId = '';
|
||||
if (reapply && jiluid) {
|
||||
const record = this.data.recordList.find(r => r.jilu_id === jiluid);
|
||||
if (record && record.shenheguan_id) {
|
||||
canSpecify = false; // 已有考核官,不能指定新的
|
||||
originalShenheguanId = record.shenheguan_id;
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
showApplyModal: true,
|
||||
selectedTag: fullTag || null,
|
||||
applyGameNick: '',
|
||||
applyRemark: '',
|
||||
applyFee: fee,
|
||||
applyJiluId: jiluid || '',
|
||||
isReapply: reapply || false,
|
||||
selectedKaoheguanId: '', // 重置
|
||||
selectedKaoheguanInfo: null,
|
||||
canSpecify: canSpecify, // 新增
|
||||
originalShenheguanId: originalShenheguanId, // 新增
|
||||
});
|
||||
},
|
||||
|
||||
// 辅助方法:从 plateList 查找指定 id 的标签
|
||||
findTagInPlateList(tagId) {
|
||||
if (!tagId) return null;
|
||||
for (const plate of this.data.plateList) {
|
||||
for (const t of (plate.tags || [])) {
|
||||
if (t.id === tagId) return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
closeApplyModal() {
|
||||
this.setData({ showApplyModal: false });
|
||||
},
|
||||
|
||||
// 实时更新游戏昵称
|
||||
onNickInput(e) {
|
||||
this.setData({ applyGameNick: e.detail.value });
|
||||
},
|
||||
|
||||
// 实时更新备注
|
||||
onRemarkInput(e) {
|
||||
this.setData({ applyRemark: e.detail.value });
|
||||
},
|
||||
|
||||
// 新增:打开考核官选择弹窗
|
||||
openKaoheguanModal() {
|
||||
if (!this.data.canSpecify) {
|
||||
wx.showToast({ title: '已有考核官,无法重新指定', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
// 根据费用筛选可选考核官
|
||||
let all = [...this.data.kaoheguanList];
|
||||
if (this.data.applyFee > 0) {
|
||||
all = all.filter(kg => kg.is_renzheng);
|
||||
}
|
||||
this.setData({
|
||||
showKaoheguanModal: true,
|
||||
filteredKaoheguanList: all,
|
||||
searchKeyword: '',
|
||||
});
|
||||
},
|
||||
|
||||
// 关闭考核官选择弹窗
|
||||
closeKaoheguanModal() {
|
||||
this.setData({ showKaoheguanModal: false });
|
||||
},
|
||||
|
||||
// 搜索输入
|
||||
onSearchInput(e) {
|
||||
const value = e.detail.value.trim();
|
||||
this.setData({ searchKeyword: value });
|
||||
this.filterKaoheguanList(value);
|
||||
},
|
||||
|
||||
// 过滤考核官列表
|
||||
filterKaoheguanList(keyword) {
|
||||
let all = [...this.data.kaoheguanList];
|
||||
if (this.data.applyFee > 0) {
|
||||
all = all.filter(kg => kg.is_renzheng);
|
||||
}
|
||||
if (keyword) {
|
||||
all = all.filter(kg =>
|
||||
kg.yonghuid.includes(keyword) ||
|
||||
(kg.dashou_nick && kg.dashou_nick.includes(keyword))
|
||||
);
|
||||
}
|
||||
this.setData({ filteredKaoheguanList: all });
|
||||
},
|
||||
|
||||
// 选择一个考核官
|
||||
selectKaoheguan(e) {
|
||||
const kg = e.currentTarget.dataset.kg;
|
||||
if (kg.shenhe_zhuangtai !== 0) {
|
||||
wx.showToast({ title: '该考核官正忙,无法指定', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
selectedKaoheguanId: kg.yonghuid,
|
||||
selectedKaoheguanInfo: kg,
|
||||
showKaoheguanModal: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 取消已选择的考核官
|
||||
clearSelectedKaoheguan() {
|
||||
this.setData({
|
||||
selectedKaoheguanId: '',
|
||||
selectedKaoheguanInfo: null,
|
||||
});
|
||||
},
|
||||
|
||||
// 提交申请
|
||||
async submitApply() {
|
||||
const { applyGameNick, applyRemark, applyFee, selectedTag, isReapply, applyJiluId, selectedKaoheguanId } = this.data;
|
||||
if (!applyGameNick || !applyGameNick.trim()) {
|
||||
wx.showToast({ title: '请输入游戏昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!applyRemark || !applyRemark.trim()) {
|
||||
wx.showToast({ title: '请填写备注', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (applyFee > 0) {
|
||||
await this.startPayProcess();
|
||||
} else {
|
||||
await this.doFreeApply();
|
||||
}
|
||||
},
|
||||
|
||||
// 支付流程
|
||||
async startPayProcess() {
|
||||
this.setData({ payLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/khzf',
|
||||
method: 'POST',
|
||||
data: {
|
||||
tag_id: this.data.selectedTag.id,
|
||||
game_nick: this.data.applyGameNick,
|
||||
remark: this.data.applyRemark,
|
||||
reapply: this.data.isReapply,
|
||||
jilu_id: this.data.applyJiluId,
|
||||
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
||||
}
|
||||
});
|
||||
if (res.data.code !== 200) throw new Error(res.data.message || '下单失败');
|
||||
const payParams = res.data.payParams;
|
||||
const dingdanid = res.data.dingdanid;
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType || 'MD5',
|
||||
paySign: payParams.paySign,
|
||||
success: async () => {
|
||||
await this.pollPayStatus(dingdanid);
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '支付取消或失败', icon: 'none' });
|
||||
request({ url: '/yonghu/khzfsb', method: 'POST', data: { dingdanid } }).catch(()=>{});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
wx.showToast({ title: e.message || '支付异常', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ payLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 轮询支付结果
|
||||
async pollPayStatus(dingdanid) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
try {
|
||||
const res = await request({ url: '/yonghu/khzffc', method: 'POST', data: { dingdanid } });
|
||||
if (res.data.code === 200) {
|
||||
wx.showToast({ title: '申请成功', icon: 'success' });
|
||||
this.closeApplyModal();
|
||||
this.fetchAllTags();
|
||||
this.setData({ recordList: [], recordPage: 1 });
|
||||
this.fetchMyRecords(true);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
}
|
||||
wx.showToast({ title: '支付确认超时', icon: 'none' });
|
||||
},
|
||||
|
||||
// 免费申请
|
||||
async doFreeApply() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dssqkh',
|
||||
method: 'POST',
|
||||
data: {
|
||||
tag_id: this.data.selectedTag.id,
|
||||
game_nick: this.data.applyGameNick,
|
||||
remark: this.data.applyRemark,
|
||||
reapply: this.data.isReapply,
|
||||
jilu_id: this.data.applyJiluId,
|
||||
shenheguan_id: this.data.selectedKaoheguanId, // 新增
|
||||
}
|
||||
});
|
||||
if (res.data.code === 0) {
|
||||
wx.showToast({ title: '申请成功', icon: 'success' });
|
||||
this.closeApplyModal();
|
||||
this.fetchAllTags();
|
||||
this.setData({ recordList: [], recordPage: 1 });
|
||||
this.fetchMyRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: res.data.msg || '申请失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 联系考核官(私聊)
|
||||
contactKaoheguan(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
if (!item.shenheguan_id) {
|
||||
wx.showToast({ title: '暂无考核官信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (!uid) {
|
||||
wx.showToast({ title: '用户信息缺失', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (app.globalData.currentRole !== 'dashou') {
|
||||
app.globalData.currentRole = 'dashou';
|
||||
wx.setStorageSync('currentRole', 'dashou');
|
||||
}
|
||||
if (app.connectForCurrentRole) {
|
||||
app.connectForCurrentRole();
|
||||
} else if (app.ensureConnection) {
|
||||
app.ensureConnection();
|
||||
}
|
||||
const ossImageUrl = this.data.ossImageUrl || app.globalData.ossImageUrl || '';
|
||||
let fullAvatar = item.shenheguan_avatar || '';
|
||||
if (fullAvatar && !fullAvatar.startsWith('http')) {
|
||||
fullAvatar = ossImageUrl + fullAvatar;
|
||||
}
|
||||
if (!fullAvatar) {
|
||||
fullAvatar = ossImageUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
|
||||
}
|
||||
const param = {
|
||||
toUserId: 'Kh' + item.shenheguan_id,
|
||||
toName: '考核官' + item.shenheguan_id,
|
||||
toAvatar: fullAvatar
|
||||
};
|
||||
wx.navigateTo({
|
||||
url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)),
|
||||
fail: (err) => {
|
||||
wx.showToast({ title: '打开聊天失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
showTagDetail(e) {
|
||||
const tag = e.currentTarget.dataset.tag;
|
||||
const feeStr = this.formatFeeList(tag.fee_list);
|
||||
wx.showModal({
|
||||
title: tag.name,
|
||||
content: `规则:${tag.rule || '暂无'}\n${tag.jinpai ? '【可同时开启金牌】' : ''}\n费用:${feeStr}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
},
|
||||
|
||||
formatFeeList(feeList) {
|
||||
if (!feeList || feeList.length === 0) return '暂无';
|
||||
let str = feeList.map(f => `第${f.cishu}次:¥${f.feiyong}`).join(';');
|
||||
const last = feeList[feeList.length - 1];
|
||||
str += `;第${last.cishu}次及以上:¥${last.feiyong}`;
|
||||
return str;
|
||||
},
|
||||
});
|
||||
@@ -1,135 +1,135 @@
|
||||
<!-- pages/kaohe_jinpai/kaohe_jinpai.wxml -->
|
||||
<view class="page-root">
|
||||
<!-- 顶部Tab切换 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item {{activeTab === 'all_tags' ? 'active' : ''}}" data-tab="all_tags" bindtap="switchTab">考核标签</view>
|
||||
<view class="tab-item {{activeTab === 'my_records' ? 'active' : ''}}" data-tab="my_records" bindtap="switchTab">我的考核</view>
|
||||
</view>
|
||||
|
||||
<!-- 考核标签面板 -->
|
||||
<view class="content-area" wx:if="{{activeTab === 'all_tags'}}">
|
||||
<scroll-view scroll-y="true" class="scroll-view">
|
||||
<view wx:for="{{plateList}}" wx:key="bankuai_id" class="plate-group">
|
||||
<view class="plate-title">{{item.mingcheng}}</view>
|
||||
<view wx:for="{{item.tags}}" wx:key="id" class="tag-card" bindtap="showTagDetail" data-tag="{{item}}">
|
||||
<view class="tag-header">
|
||||
<chenghao-tag mingcheng="{{item.name}}" texiaoJson="{{item.texiao_json}}" />
|
||||
<text wx:if="{{item.jinpai}}" class="jinpai-badge">金牌</text>
|
||||
</view>
|
||||
<view class="fee-line">
|
||||
<text wx:for="{{item.fee_list}}" wx:key="cishu" class="fee-item">{{item.cishu}}次 ¥{{item.feiyong}}</text>
|
||||
<text wx:if="{{item.fee_list.length > 0}}" class="fee-item">≥{{item.fee_list.length}}次 ¥{{item.fee_list[item.fee_list.length-1].feiyong}}</text>
|
||||
</view>
|
||||
<view wx:if="{{!myTags.includes(item.name)}}" class="apply-btn" data-tag="{{item}}" bindtap="openApplyModal">申请考核</view>
|
||||
<view wx:else class="owned-tip">已拥有</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 我的考核面板 -->
|
||||
<view class="content-area" wx:if="{{activeTab === 'my_records'}}">
|
||||
<view class="filter-row">
|
||||
<view class="filter-tag {{recordFilter === 'pending' ? 'active' : ''}}" data-filter="pending" bindtap="filterRecord">进行中/未通过</view>
|
||||
<view class="filter-tag {{recordFilter === 'passed' ? 'active' : ''}}" data-filter="passed" bindtap="filterRecord">已通过</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="scroll-view" bindscrolltolower="onReachBottom">
|
||||
<view wx:for="{{recordList}}" wx:key="jilu_id" class="record-card">
|
||||
<view class="card-top">
|
||||
<text class="tag-name">{{item.chenghao_name}}</text>
|
||||
<text class="status-text" style="color: {{item.statusColor}}">{{item.statusText}}</text>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<text>板块:{{item.bankuai_name}}</text>
|
||||
<text>考核官:{{item.shenheguan_id || '待分配'}}</text>
|
||||
<!-- 联系考核官:纯文字蓝色下划线 -->
|
||||
<view wx:if="{{item.shenheguan_id}}" class="contact-text-link" data-item="{{item}}" bindtap="contactKaoheguan">联系考核官</view>
|
||||
|
||||
<text>游戏ID:{{item.dashou_youxi_id}}</text>
|
||||
<text>备注:{{item.dashou_beizhu}}</text>
|
||||
<text>第{{item.cishu}}次考核 · 共缴 ¥{{item.total_fee}}</text>
|
||||
|
||||
<!-- 进行中/未通过时显示本次及预计下次费用 -->
|
||||
<view wx:if="{{item.zhuangtai !== 1}}" class="fee-predict">
|
||||
<text>本次考核费用:¥{{item.current_fee}}</text>
|
||||
<text>预计下次费用:¥{{item.next_fee}}</text>
|
||||
</view>
|
||||
|
||||
<text wx:if="{{item.last_fail_reason}}">上次拒绝原因:{{item.last_fail_reason}}</text>
|
||||
</view>
|
||||
<!-- 未通过时显示“再次考核”按钮,传递 tag_obj 以便计算费用 -->
|
||||
<view wx:if="{{item.zhuangtai === 2}}" class="reapply-btn" data-tag="{{item.tag_obj}}" data-jiluid="{{item.jilu_id}}" data-reapply="{{true}}" bindtap="openApplyModal">再次考核</view>
|
||||
</view>
|
||||
<view wx:if="{{recordLoading}}" class="loading-more">加载中...</view>
|
||||
<view wx:if="{{!recordHasMore && recordList.length > 0}}" class="no-more">—— 没有更多了 ——</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 申请考核弹窗 -->
|
||||
<view wx:if="{{showApplyModal}}" class="modal-mask" bindtap="closeApplyModal">
|
||||
<view class="modal-dialog" catchtap="noop">
|
||||
<view class="modal-header">申请考核 - {{selectedTag.name}}</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">游戏昵称</text>
|
||||
<input class="form-input" value="{{applyGameNick}}" bindinput="onNickInput" placeholder="请输入游戏昵称" />
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">备注</text>
|
||||
<textarea class="form-textarea" value="{{applyRemark}}" bindinput="onRemarkInput" placeholder="区服、时间段等(请勿填写无关内容,违者封号)" maxlength="100" />
|
||||
</view>
|
||||
|
||||
<!-- 指定考核官区域 -->
|
||||
<view class="form-group">
|
||||
<text class="form-label">指定考核官(可选)</text>
|
||||
<view wx:if="{{!canSpecify}}" class="kg-disabled-tip">
|
||||
<text>已有考核官:{{originalShenheguanId}},不可重新指定</text>
|
||||
</view>
|
||||
<view wx:else>
|
||||
<view wx:if="{{!selectedKaoheguanInfo}}" class="select-kg-btn" bindtap="openKaoheguanModal">选择考核官</view>
|
||||
<view wx:else class="selected-kg-card">
|
||||
<image class="kg-avatar" src="{{selectedKaoheguanInfo.avatar}}" mode="aspectFill" />
|
||||
<view class="kg-info">
|
||||
<text class="kg-uid">UID {{selectedKaoheguanInfo.yonghuid}}</text>
|
||||
<text class="kg-nick" wx:if="{{selectedKaoheguanInfo.dashou_nick}}">{{selectedKaoheguanInfo.dashou_nick}}</text>
|
||||
<text class="kg-status {{selectedKaoheguanInfo.is_renzheng ? 'renzheng' : 'not-renzheng'}}">{{selectedKaoheguanInfo.is_renzheng ? '已认证' : '未认证'}}</text>
|
||||
</view>
|
||||
<view class="clear-kg-btn" bindtap="clearSelectedKaoheguan">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{applyFee > 0}}" class="fee-info">本次需缴纳:<text class="fee-amount">¥{{applyFee}}</text></view>
|
||||
<view class="modal-actions">
|
||||
<view class="btn-cancel" bindtap="closeApplyModal">取消</view>
|
||||
<view class="btn-confirm" bindtap="submitApply">确认申请{{applyFee > 0 ? '并支付' : ''}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 考核官选择弹窗 -->
|
||||
<view wx:if="{{showKaoheguanModal}}" class="modal-mask" bindtap="closeKaoheguanModal">
|
||||
<view class="modal-dialog" catchtap="noop">
|
||||
<view class="modal-header">选择考核官</view>
|
||||
<view class="search-box">
|
||||
<input class="search-input" value="{{searchKeyword}}" bindinput="onSearchInput" placeholder="搜索用户ID或昵称" />
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="kg-scroll">
|
||||
<view wx:for="{{filteredKaoheguanList}}" wx:key="yonghuid" class="kg-item" data-kg="{{item}}" bindtap="selectKaoheguan">
|
||||
<image class="kg-avatar" src="{{item.avatar}}" mode="aspectFill" />
|
||||
<view class="kg-info">
|
||||
<text class="kg-uid">UID {{item.yonghuid}}</text>
|
||||
<text wx:if="{{item.dashou_nick}}" class="kg-nick">{{item.dashou_nick}}</text>
|
||||
<text class="kg-status {{item.is_renzheng ? 'renzheng' : 'not-renzheng'}}">{{item.is_renzheng ? '已认证' : '未认证'}}</text>
|
||||
<text class="kg-state {{item.shenhe_zhuangtai === 0 ? 'free' : 'busy'}}">{{item.shenhe_zhuangtai === 0 ? '空闲' : '忙碌'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if="{{filteredKaoheguanList.length === 0}}" class="empty-tip">暂无符合条件的考核官</view>
|
||||
</scroll-view>
|
||||
<view class="modal-actions">
|
||||
<view class="btn-cancel" bindtap="closeKaoheguanModal">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
<!-- pages/assess-gold/assess-gold.wxml -->
|
||||
<view class="page-root">
|
||||
<!-- 顶部Tab切换 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item {{activeTab === 'all_tags' ? 'active' : ''}}" data-tab="all_tags" bindtap="switchTab">考核标签</view>
|
||||
<view class="tab-item {{activeTab === 'my_records' ? 'active' : ''}}" data-tab="my_records" bindtap="switchTab">我的考核</view>
|
||||
</view>
|
||||
|
||||
<!-- 考核标签面板 -->
|
||||
<view class="content-area" wx:if="{{activeTab === 'all_tags'}}">
|
||||
<scroll-view scroll-y="true" class="scroll-view">
|
||||
<view wx:for="{{plateList}}" wx:key="bankuai_id" class="plate-group">
|
||||
<view class="plate-title">{{item.mingcheng}}</view>
|
||||
<view wx:for="{{item.tags}}" wx:key="id" class="tag-card" bindtap="showTagDetail" data-tag="{{item}}">
|
||||
<view class="tag-header">
|
||||
<chenghao-tag mingcheng="{{item.name}}" texiaoJson="{{item.texiao_json}}" />
|
||||
<text wx:if="{{item.jinpai}}" class="jinpai-badge">金牌</text>
|
||||
</view>
|
||||
<view class="fee-line">
|
||||
<text wx:for="{{item.fee_list}}" wx:key="cishu" class="fee-item">{{item.cishu}}次 ¥{{item.feiyong}}</text>
|
||||
<text wx:if="{{item.fee_list.length > 0}}" class="fee-item">≥{{item.fee_list.length}}次 ¥{{item.fee_list[item.fee_list.length-1].feiyong}}</text>
|
||||
</view>
|
||||
<view wx:if="{{!myTags.includes(item.name)}}" class="apply-btn" data-tag="{{item}}" bindtap="openApplyModal">申请考核</view>
|
||||
<view wx:else class="owned-tip">已拥有</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 我的考核面板 -->
|
||||
<view class="content-area" wx:if="{{activeTab === 'my_records'}}">
|
||||
<view class="filter-row">
|
||||
<view class="filter-tag {{recordFilter === 'pending' ? 'active' : ''}}" data-filter="pending" bindtap="filterRecord">进行中/未通过</view>
|
||||
<view class="filter-tag {{recordFilter === 'passed' ? 'active' : ''}}" data-filter="passed" bindtap="filterRecord">已通过</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="scroll-view" bindscrolltolower="onReachBottom">
|
||||
<view wx:for="{{recordList}}" wx:key="jilu_id" class="record-card">
|
||||
<view class="card-top">
|
||||
<text class="tag-name">{{item.chenghao_name}}</text>
|
||||
<text class="status-text" style="color: {{item.statusColor}}">{{item.statusText}}</text>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<text>板块:{{item.bankuai_name}}</text>
|
||||
<text>考核官:{{item.shenheguan_id || '待分配'}}</text>
|
||||
<!-- 联系考核官:纯文字蓝色下划线 -->
|
||||
<view wx:if="{{item.shenheguan_id}}" class="contact-text-link" data-item="{{item}}" bindtap="contactKaoheguan">联系考核官</view>
|
||||
|
||||
<text>游戏ID:{{item.dashou_youxi_id}}</text>
|
||||
<text>备注:{{item.dashou_beizhu}}</text>
|
||||
<text>第{{item.cishu}}次考核 · 共缴 ¥{{item.total_fee}}</text>
|
||||
|
||||
<!-- 进行中/未通过时显示本次及预计下次费用 -->
|
||||
<view wx:if="{{item.zhuangtai !== 1}}" class="fee-predict">
|
||||
<text>本次考核费用:¥{{item.current_fee}}</text>
|
||||
<text>预计下次费用:¥{{item.next_fee}}</text>
|
||||
</view>
|
||||
|
||||
<text wx:if="{{item.last_fail_reason}}">上次拒绝原因:{{item.last_fail_reason}}</text>
|
||||
</view>
|
||||
<!-- 未通过时显示“再次考核”按钮,传递 tag_obj 以便计算费用 -->
|
||||
<view wx:if="{{item.zhuangtai === 2}}" class="reapply-btn" data-tag="{{item.tag_obj}}" data-jiluid="{{item.jilu_id}}" data-reapply="{{true}}" bindtap="openApplyModal">再次考核</view>
|
||||
</view>
|
||||
<view wx:if="{{recordLoading}}" class="loading-more">加载中...</view>
|
||||
<view wx:if="{{!recordHasMore && recordList.length > 0}}" class="no-more">—— 没有更多了 ——</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 申请考核弹窗 -->
|
||||
<view wx:if="{{showApplyModal}}" class="modal-mask" bindtap="closeApplyModal">
|
||||
<view class="modal-dialog" catchtap="noop">
|
||||
<view class="modal-header">申请考核 - {{selectedTag.name}}</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">游戏昵称</text>
|
||||
<input class="form-input" value="{{applyGameNick}}" bindinput="onNickInput" placeholder="请输入游戏昵称" />
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">备注</text>
|
||||
<textarea class="form-textarea" value="{{applyRemark}}" bindinput="onRemarkInput" placeholder="区服、时间段等(请勿填写无关内容,违者封号)" maxlength="100" />
|
||||
</view>
|
||||
|
||||
<!-- 指定考核官区域 -->
|
||||
<view class="form-group">
|
||||
<text class="form-label">指定考核官(可选)</text>
|
||||
<view wx:if="{{!canSpecify}}" class="kg-disabled-tip">
|
||||
<text>已有考核官:{{originalShenheguanId}},不可重新指定</text>
|
||||
</view>
|
||||
<view wx:else>
|
||||
<view wx:if="{{!selectedKaoheguanInfo}}" class="select-kg-btn" bindtap="openKaoheguanModal">选择考核官</view>
|
||||
<view wx:else class="selected-kg-card">
|
||||
<image class="kg-avatar" src="{{selectedKaoheguanInfo.avatar}}" mode="aspectFill" />
|
||||
<view class="kg-info">
|
||||
<text class="kg-uid">UID {{selectedKaoheguanInfo.yonghuid}}</text>
|
||||
<text class="kg-nick" wx:if="{{selectedKaoheguanInfo.dashou_nick}}">{{selectedKaoheguanInfo.dashou_nick}}</text>
|
||||
<text class="kg-status {{selectedKaoheguanInfo.is_renzheng ? 'renzheng' : 'not-renzheng'}}">{{selectedKaoheguanInfo.is_renzheng ? '已认证' : '未认证'}}</text>
|
||||
</view>
|
||||
<view class="clear-kg-btn" bindtap="clearSelectedKaoheguan">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{applyFee > 0}}" class="fee-info">本次需缴纳:<text class="fee-amount">¥{{applyFee}}</text></view>
|
||||
<view class="modal-actions">
|
||||
<view class="btn-cancel" bindtap="closeApplyModal">取消</view>
|
||||
<view class="btn-confirm" bindtap="submitApply">确认申请{{applyFee > 0 ? '并支付' : ''}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 考核官选择弹窗 -->
|
||||
<view wx:if="{{showKaoheguanModal}}" class="modal-mask" bindtap="closeKaoheguanModal">
|
||||
<view class="modal-dialog" catchtap="noop">
|
||||
<view class="modal-header">选择考核官</view>
|
||||
<view class="search-box">
|
||||
<input class="search-input" value="{{searchKeyword}}" bindinput="onSearchInput" placeholder="搜索用户ID或昵称" />
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="kg-scroll">
|
||||
<view wx:for="{{filteredKaoheguanList}}" wx:key="yonghuid" class="kg-item" data-kg="{{item}}" bindtap="selectKaoheguan">
|
||||
<image class="kg-avatar" src="{{item.avatar}}" mode="aspectFill" />
|
||||
<view class="kg-info">
|
||||
<text class="kg-uid">UID {{item.yonghuid}}</text>
|
||||
<text wx:if="{{item.dashou_nick}}" class="kg-nick">{{item.dashou_nick}}</text>
|
||||
<text class="kg-status {{item.is_renzheng ? 'renzheng' : 'not-renzheng'}}">{{item.is_renzheng ? '已认证' : '未认证'}}</text>
|
||||
<text class="kg-state {{item.shenhe_zhuangtai === 0 ? 'free' : 'busy'}}">{{item.shenhe_zhuangtai === 0 ? '空闲' : '忙碌'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if="{{filteredKaoheguanList.length === 0}}" class="empty-tip">暂无符合条件的考核官</view>
|
||||
</scroll-view>
|
||||
<view class="modal-actions">
|
||||
<view class="btn-cancel" bindtap="closeKaoheguanModal">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
</view>
|
||||
@@ -1,385 +1,385 @@
|
||||
/* pages/kaohe_jinpai/kaohe_jinpai.wxss - 晨雾微光风格 */
|
||||
.page-root {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #F5F7FA 0%, #E4E8F0 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
padding: 30rpx 50rpx;
|
||||
gap: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.65);
|
||||
backdrop-filter: blur(15px);
|
||||
border-bottom: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.tab-item {
|
||||
font-size: 32rpx;
|
||||
color: #6B7280;
|
||||
padding-bottom: 10rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.tab-item.active {
|
||||
color: #4C5BF0;
|
||||
border-bottom-color: #4C5BF0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.scroll-view {
|
||||
height: 100%;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.plate-group {
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
.plate-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
margin-bottom: 20rpx;
|
||||
padding-left: 30rpx;
|
||||
border-left: 6rpx solid #4C5BF0;
|
||||
margin-left: 30rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.tag-card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 20rpx 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.tag-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
.jinpai-badge {
|
||||
font-size: 22rpx;
|
||||
color: #F59E0B;
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fee-line {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.fee-item {
|
||||
font-size: 24rpx;
|
||||
color: #4B5563;
|
||||
background: #F3F4F6;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.apply-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(135deg, #4C5BF0, #6D7AF5);
|
||||
color: #FFFFFF;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2rpx;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.apply-btn:active {
|
||||
opacity: 0.85;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.owned-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
color: #10B981;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 记录卡片 */
|
||||
.record-card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 20rpx 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.card-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.tag-name { font-size: 32rpx; font-weight: 600; color: #1F2937; }
|
||||
.status-text { font-size: 26rpx; }
|
||||
.card-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
font-size: 26rpx;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
/* 联系考核官:蓝色下划线 */
|
||||
.contact-text-link {
|
||||
color: #4C5BF0;
|
||||
text-decoration: underline;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.fee-predict {
|
||||
background: #F3F4F6;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
font-size: 24rpx;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
.reapply-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
margin-top: 20rpx;
|
||||
background: #F59E0B;
|
||||
color: #FFFFFF;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.reapply-btn:active {
|
||||
opacity: 0.85;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
padding: 20rpx 30rpx;
|
||||
gap: 40rpx;
|
||||
}
|
||||
.filter-tag {
|
||||
font-size: 28rpx;
|
||||
color: #6B7280;
|
||||
padding-bottom: 8rpx;
|
||||
border-bottom: 3rpx solid transparent;
|
||||
}
|
||||
.filter-tag.active {
|
||||
color: #4C5BF0;
|
||||
border-bottom-color: #4C5BF0;
|
||||
}
|
||||
|
||||
/* 弹窗 */
|
||||
.modal-mask {
|
||||
position: fixed; top:0; left:0; width:100%; height:100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.modal-dialog {
|
||||
width: 85%;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
padding: 40rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.modal-header { font-size: 34rpx; font-weight: 700; color: #1F2937; margin-bottom: 30rpx; }
|
||||
.form-group { margin-bottom: 25rpx; }
|
||||
.form-label { font-size: 28rpx; color: #4B5563; margin-bottom: 10rpx; display: block; }
|
||||
.form-input, .form-textarea {
|
||||
width: 100%;
|
||||
background: #F9FAFB;
|
||||
border-radius: 14rpx;
|
||||
padding: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1F2937;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
.form-textarea { height: 150rpx; }
|
||||
.fee-info { text-align: center; font-size: 30rpx; margin: 20rpx 0; color: #F59E0B; }
|
||||
.fee-amount { font-weight: 700; }
|
||||
.modal-actions { display: flex; gap: 20rpx; margin-top: 30rpx; }
|
||||
.btn-cancel, .btn-confirm {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn-cancel { background: #F3F4F6; color: #4B5563; }
|
||||
.btn-cancel:active { background: #E5E7EB; }
|
||||
.btn-confirm { background: linear-gradient(135deg, #4C5BF0, #6D7AF5); color: #FFFFFF; }
|
||||
.btn-confirm:active { opacity: 0.85; transform: scale(0.98); }
|
||||
|
||||
.loading-more, .no-more { text-align: center; padding: 30rpx; color: #9CA3AF; font-size: 26rpx; }
|
||||
|
||||
.kg-avatar {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 8rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* 原有样式保留,以下是新增样式 */
|
||||
|
||||
/* 指定考核官选择按钮 */
|
||||
.select-kg-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
background: #F3F4F6;
|
||||
color: #4B5563;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.select-kg-btn:active {
|
||||
background: #E5E7EB;
|
||||
}
|
||||
|
||||
/* 已选择的考核官卡片 */
|
||||
.selected-kg-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #F9FAFB;
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
margin-top: 10rpx;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
.kg-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.kg-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rpx;
|
||||
}
|
||||
.kg-uid {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
}
|
||||
.kg-nick {
|
||||
font-size: 24rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
.kg-status {
|
||||
font-size: 22rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
}
|
||||
.kg-status.renzheng {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: #10B981;
|
||||
}
|
||||
.kg-status.not-renzheng {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
color: #F59E0B;
|
||||
}
|
||||
.clear-kg-btn {
|
||||
color: #EF4444;
|
||||
font-size: 26rpx;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
.clear-kg-btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 禁用指定提示 */
|
||||
.kg-disabled-tip {
|
||||
background: #FEF3C7;
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: #92400E;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 考核官选择弹窗内搜索 */
|
||||
.search-box {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.search-input {
|
||||
width: 100%;
|
||||
background: #F9FAFB;
|
||||
border-radius: 14rpx;
|
||||
padding: 16rpx;
|
||||
font-size: 28rpx;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
/* 考核官滚动列表 */
|
||||
.kg-scroll {
|
||||
max-height: 500rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 单个考核官项 */
|
||||
.kg-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 12rpx;
|
||||
border: 1rpx solid #F3F4F6;
|
||||
}
|
||||
.kg-item:active {
|
||||
background: #F9FAFB;
|
||||
}
|
||||
.kg-item .kg-state {
|
||||
font-size: 22rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
.kg-state.free {
|
||||
color: #10B981;
|
||||
}
|
||||
.kg-state.busy {
|
||||
color: #EF4444;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
color: #9CA3AF;
|
||||
font-size: 26rpx;
|
||||
/* pages/assess-gold/assess-gold.wxss - 晨雾微光风格 */
|
||||
.page-root {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #F5F7FA 0%, #E4E8F0 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
padding: 30rpx 50rpx;
|
||||
gap: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.65);
|
||||
backdrop-filter: blur(15px);
|
||||
border-bottom: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.tab-item {
|
||||
font-size: 32rpx;
|
||||
color: #6B7280;
|
||||
padding-bottom: 10rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.tab-item.active {
|
||||
color: #4C5BF0;
|
||||
border-bottom-color: #4C5BF0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.scroll-view {
|
||||
height: 100%;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.plate-group {
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
.plate-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
margin-bottom: 20rpx;
|
||||
padding-left: 30rpx;
|
||||
border-left: 6rpx solid #4C5BF0;
|
||||
margin-left: 30rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.tag-card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 20rpx 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.tag-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
.jinpai-badge {
|
||||
font-size: 22rpx;
|
||||
color: #F59E0B;
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fee-line {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.fee-item {
|
||||
font-size: 24rpx;
|
||||
color: #4B5563;
|
||||
background: #F3F4F6;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.apply-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(135deg, #4C5BF0, #6D7AF5);
|
||||
color: #FFFFFF;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2rpx;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.apply-btn:active {
|
||||
opacity: 0.85;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.owned-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
color: #10B981;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 记录卡片 */
|
||||
.record-card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 20rpx 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.card-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.tag-name { font-size: 32rpx; font-weight: 600; color: #1F2937; }
|
||||
.status-text { font-size: 26rpx; }
|
||||
.card-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
font-size: 26rpx;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
/* 联系考核官:蓝色下划线 */
|
||||
.contact-text-link {
|
||||
color: #4C5BF0;
|
||||
text-decoration: underline;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.fee-predict {
|
||||
background: #F3F4F6;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
font-size: 24rpx;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
.reapply-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
margin-top: 20rpx;
|
||||
background: #F59E0B;
|
||||
color: #FFFFFF;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.reapply-btn:active {
|
||||
opacity: 0.85;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
padding: 20rpx 30rpx;
|
||||
gap: 40rpx;
|
||||
}
|
||||
.filter-tag {
|
||||
font-size: 28rpx;
|
||||
color: #6B7280;
|
||||
padding-bottom: 8rpx;
|
||||
border-bottom: 3rpx solid transparent;
|
||||
}
|
||||
.filter-tag.active {
|
||||
color: #4C5BF0;
|
||||
border-bottom-color: #4C5BF0;
|
||||
}
|
||||
|
||||
/* 弹窗 */
|
||||
.modal-mask {
|
||||
position: fixed; top:0; left:0; width:100%; height:100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.modal-dialog {
|
||||
width: 85%;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
padding: 40rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.modal-header { font-size: 34rpx; font-weight: 700; color: #1F2937; margin-bottom: 30rpx; }
|
||||
.form-group { margin-bottom: 25rpx; }
|
||||
.form-label { font-size: 28rpx; color: #4B5563; margin-bottom: 10rpx; display: block; }
|
||||
.form-input, .form-textarea {
|
||||
width: 100%;
|
||||
background: #F9FAFB;
|
||||
border-radius: 14rpx;
|
||||
padding: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1F2937;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
.form-textarea { height: 150rpx; }
|
||||
.fee-info { text-align: center; font-size: 30rpx; margin: 20rpx 0; color: #F59E0B; }
|
||||
.fee-amount { font-weight: 700; }
|
||||
.modal-actions { display: flex; gap: 20rpx; margin-top: 30rpx; }
|
||||
.btn-cancel, .btn-confirm {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn-cancel { background: #F3F4F6; color: #4B5563; }
|
||||
.btn-cancel:active { background: #E5E7EB; }
|
||||
.btn-confirm { background: linear-gradient(135deg, #4C5BF0, #6D7AF5); color: #FFFFFF; }
|
||||
.btn-confirm:active { opacity: 0.85; transform: scale(0.98); }
|
||||
|
||||
.loading-more, .no-more { text-align: center; padding: 30rpx; color: #9CA3AF; font-size: 26rpx; }
|
||||
|
||||
.kg-avatar {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 8rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* 原有样式保留,以下是新增样式 */
|
||||
|
||||
/* 指定考核官选择按钮 */
|
||||
.select-kg-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
background: #F3F4F6;
|
||||
color: #4B5563;
|
||||
border-radius: 34rpx;
|
||||
font-size: 28rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.select-kg-btn:active {
|
||||
background: #E5E7EB;
|
||||
}
|
||||
|
||||
/* 已选择的考核官卡片 */
|
||||
.selected-kg-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #F9FAFB;
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
margin-top: 10rpx;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
.kg-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.kg-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rpx;
|
||||
}
|
||||
.kg-uid {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
}
|
||||
.kg-nick {
|
||||
font-size: 24rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
.kg-status {
|
||||
font-size: 22rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
}
|
||||
.kg-status.renzheng {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: #10B981;
|
||||
}
|
||||
.kg-status.not-renzheng {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
color: #F59E0B;
|
||||
}
|
||||
.clear-kg-btn {
|
||||
color: #EF4444;
|
||||
font-size: 26rpx;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
.clear-kg-btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 禁用指定提示 */
|
||||
.kg-disabled-tip {
|
||||
background: #FEF3C7;
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: #92400E;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 考核官选择弹窗内搜索 */
|
||||
.search-box {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.search-input {
|
||||
width: 100%;
|
||||
background: #F9FAFB;
|
||||
border-radius: 14rpx;
|
||||
padding: 16rpx;
|
||||
font-size: 28rpx;
|
||||
border: 1rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
/* 考核官滚动列表 */
|
||||
.kg-scroll {
|
||||
max-height: 500rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 单个考核官项 */
|
||||
.kg-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 12rpx;
|
||||
border: 1rpx solid #F3F4F6;
|
||||
}
|
||||
.kg-item:active {
|
||||
background: #F9FAFB;
|
||||
}
|
||||
.kg-item .kg-state {
|
||||
font-size: 22rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
.kg-state.free {
|
||||
color: #10B981;
|
||||
}
|
||||
.kg-state.busy {
|
||||
color: #EF4444;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
color: #9CA3AF;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
@@ -1,149 +1,149 @@
|
||||
// pages/kaohe_jilu/kaohe_jilu.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 板块筛选
|
||||
moduleList: [],
|
||||
xuanzhongBankuaiId: 0, // 0代表全部
|
||||
// 状态筛选:0-全部 1-审核中 2-已通过 3-未通过
|
||||
statusFilter: 0,
|
||||
// 记录列表
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 5,
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
// 展开的记录ID集合(字符串数组)
|
||||
expandedIds: [],
|
||||
// OSS地址
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadModules();
|
||||
},
|
||||
|
||||
// 加载板块(复用审核大厅接口)
|
||||
async loadModules() {
|
||||
try {
|
||||
const res = await request({ url: '/dengji/shdthqmk', method: 'POST' });
|
||||
if (res && res.data.code === 0) {
|
||||
const modules = res.data.data.modules || [];
|
||||
this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 });
|
||||
this.loadRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: '加载模块失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 选择板块
|
||||
selectModule(e) {
|
||||
const bankuaiId = e.currentTarget.dataset.id;
|
||||
if (bankuaiId === this.data.xuanzhongBankuaiId) return;
|
||||
this.setData({
|
||||
xuanzhongBankuaiId: bankuaiId,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
expandedIds: []
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 选择状态
|
||||
selectStatus(e) {
|
||||
const status = e.currentTarget.dataset.status;
|
||||
if (status === this.data.statusFilter) return;
|
||||
this.setData({
|
||||
statusFilter: status,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
expandedIds: []
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载历史记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
if (!isRefresh && !this.data.hasMore) return;
|
||||
|
||||
this.setData({ isLoading: true, isLoadingMore: !isRefresh });
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khghqkhjl',
|
||||
method: 'POST',
|
||||
data: {
|
||||
bankuai_id: this.data.xuanzhongBankuaiId || undefined,
|
||||
status: this.data.statusFilter || undefined,
|
||||
page: page,
|
||||
page_size: this.data.pageSize
|
||||
}
|
||||
});
|
||||
|
||||
this.setData({ isLoading: false, isLoadingMore: false });
|
||||
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
// 拼接头像
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processedList = list.map(item => {
|
||||
let avatar = item.shenqingren_avatar || '';
|
||||
if (avatar && !avatar.startsWith('http')) {
|
||||
avatar = oss + avatar;
|
||||
}
|
||||
return { ...item, shenqingren_avatar: avatar };
|
||||
});
|
||||
const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore: hasMore });
|
||||
} else {
|
||||
wx.showToast({ title: '加载记录失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ isLoading: false, isLoadingMore: false });
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom() {
|
||||
if (this.data.hasMore && !this.data.isLoading && !this.data.isLoadingMore) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 展开/收起详情
|
||||
toggleExpand(e) {
|
||||
const jiluId = e.currentTarget.dataset.id;
|
||||
// 确保 jiluId 是字符串
|
||||
const id = String(jiluId);
|
||||
const expandedIds = this.data.expandedIds.slice(); // 拷贝
|
||||
const index = expandedIds.indexOf(id);
|
||||
if (index > -1) {
|
||||
expandedIds.splice(index, 1);
|
||||
} else {
|
||||
expandedIds.push(id);
|
||||
}
|
||||
this.setData({ expandedIds });
|
||||
},
|
||||
|
||||
// 去评判(跳转考核打分页)
|
||||
goJudge(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
wx.navigateTo({ url: '/pages/kaohe_dafen/kaohe_dafen?jilu_id=' + item.jilu_id });
|
||||
},
|
||||
|
||||
// 阻止冒泡
|
||||
noop() {}
|
||||
// pages/assess-log/assess-log.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 板块筛选
|
||||
moduleList: [],
|
||||
xuanzhongBankuaiId: 0, // 0代表全部
|
||||
// 状态筛选:0-全部 1-审核中 2-已通过 3-未通过
|
||||
statusFilter: 0,
|
||||
// 记录列表
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 5,
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
// 展开的记录ID集合(字符串数组)
|
||||
expandedIds: [],
|
||||
// OSS地址
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadModules();
|
||||
},
|
||||
|
||||
// 加载板块(复用审核大厅接口)
|
||||
async loadModules() {
|
||||
try {
|
||||
const res = await request({ url: '/dengji/shdthqmk', method: 'POST' });
|
||||
if (res && res.data.code === 0) {
|
||||
const modules = res.data.data.modules || [];
|
||||
this.setData({ moduleList: modules, xuanzhongBankuaiId: 0 });
|
||||
this.loadRecords(true);
|
||||
} else {
|
||||
wx.showToast({ title: '加载模块失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 选择板块
|
||||
selectModule(e) {
|
||||
const bankuaiId = e.currentTarget.dataset.id;
|
||||
if (bankuaiId === this.data.xuanzhongBankuaiId) return;
|
||||
this.setData({
|
||||
xuanzhongBankuaiId: bankuaiId,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
expandedIds: []
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 选择状态
|
||||
selectStatus(e) {
|
||||
const status = e.currentTarget.dataset.status;
|
||||
if (status === this.data.statusFilter) return;
|
||||
this.setData({
|
||||
statusFilter: status,
|
||||
recordList: [],
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
expandedIds: []
|
||||
});
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载历史记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
if (!isRefresh && !this.data.hasMore) return;
|
||||
|
||||
this.setData({ isLoading: true, isLoadingMore: !isRefresh });
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khghqkhjl',
|
||||
method: 'POST',
|
||||
data: {
|
||||
bankuai_id: this.data.xuanzhongBankuaiId || undefined,
|
||||
status: this.data.statusFilter || undefined,
|
||||
page: page,
|
||||
page_size: this.data.pageSize
|
||||
}
|
||||
});
|
||||
|
||||
this.setData({ isLoading: false, isLoadingMore: false });
|
||||
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
// 拼接头像
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processedList = list.map(item => {
|
||||
let avatar = item.shenqingren_avatar || '';
|
||||
if (avatar && !avatar.startsWith('http')) {
|
||||
avatar = oss + avatar;
|
||||
}
|
||||
return { ...item, shenqingren_avatar: avatar };
|
||||
});
|
||||
const newList = isRefresh ? processedList : [...this.data.recordList, ...processedList];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore: hasMore });
|
||||
} else {
|
||||
wx.showToast({ title: '加载记录失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ isLoading: false, isLoadingMore: false });
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom() {
|
||||
if (this.data.hasMore && !this.data.isLoading && !this.data.isLoadingMore) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 展开/收起详情
|
||||
toggleExpand(e) {
|
||||
const jiluId = e.currentTarget.dataset.id;
|
||||
// 确保 jiluId 是字符串
|
||||
const id = String(jiluId);
|
||||
const expandedIds = this.data.expandedIds.slice(); // 拷贝
|
||||
const index = expandedIds.indexOf(id);
|
||||
if (index > -1) {
|
||||
expandedIds.splice(index, 1);
|
||||
} else {
|
||||
expandedIds.push(id);
|
||||
}
|
||||
this.setData({ expandedIds });
|
||||
},
|
||||
|
||||
// 去评判(跳转考核打分页)
|
||||
goJudge(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
wx.navigateTo({ url: '/pages/assess-score/assess-score?jilu_id=' + item.jilu_id });
|
||||
},
|
||||
|
||||
// 阻止冒泡
|
||||
noop() {}
|
||||
});
|
||||
@@ -1,130 +1,130 @@
|
||||
<!-- pages/kaohe_jilu/kaohe_jilu.wxml -->
|
||||
<view class="page-root">
|
||||
<!-- 顶部筛选区 -->
|
||||
<view class="filter-bar">
|
||||
<!-- 板块筛选 -->
|
||||
<scroll-view class="module-scroll" scroll-x enhanced show-scrollbar="{{false}}">
|
||||
<view class="module-container">
|
||||
<view class="filter-item {{xuanzhongBankuaiId === 0 ? 'active' : ''}}"
|
||||
data-id="{{0}}" bindtap="selectModule">
|
||||
<text>全部板块</text>
|
||||
</view>
|
||||
<block wx:for="{{moduleList}}" wx:key="bankuai_id">
|
||||
<view class="filter-item {{xuanzhongBankuaiId === item.bankuai_id ? 'active' : ''}}"
|
||||
data-id="{{item.bankuai_id}}" bindtap="selectModule">
|
||||
<text>{{item.mingcheng}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- 状态筛选 -->
|
||||
<view class="status-row">
|
||||
<view class="status-item {{statusFilter === 0 ? 'active' : ''}}" data-status="{{0}}" bindtap="selectStatus">全部</view>
|
||||
<view class="status-item {{statusFilter === 1 ? 'active' : ''}}" data-status="{{1}}" bindtap="selectStatus">审核中</view>
|
||||
<view class="status-item {{statusFilter === 2 ? 'active' : ''}}" data-status="{{2}}" bindtap="selectStatus">已通过</view>
|
||||
<view class="status-item {{statusFilter === 3 ? 'active' : ''}}" data-status="{{3}}" bindtap="selectStatus">未通过</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表区域 -->
|
||||
<view class="list-container">
|
||||
<scroll-view class="list-scroll" scroll-y enhanced show-scrollbar="{{false}}"
|
||||
bindscrolltolower="onReachBottom">
|
||||
<view class="record-list">
|
||||
<view wx:if="{{!isLoading && recordList.length === 0}}" class="empty-tip">暂无考核记录</view>
|
||||
|
||||
<block wx:for="{{recordList}}" wx:key="jilu_id">
|
||||
<view class="card">
|
||||
<!-- 头部信息 -->
|
||||
<view class="card-header">
|
||||
<image class="avatar" src="{{item.shenqingren_avatar}}" mode="aspectFill" />
|
||||
<view class="user-info">
|
||||
<text class="nickname">{{item.shenqingren_nicheng || '用户'}}</text>
|
||||
<text class="uid">UID {{item.shenqingren_id}}</text>
|
||||
</view>
|
||||
<view class="status-tag status-{{item.zhuangtai}}">
|
||||
{{item.zhuangtai == 0 ? '审核中' : (item.zhuangtai == 1 ? '已通过' : (item.zhuangtai == 2 ? '未通过' : '待审核'))}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 摘要信息 -->
|
||||
<view class="card-summary">
|
||||
<view class="summary-item">
|
||||
<text class="label">板块</text>
|
||||
<text class="value">{{item.bankuai_mingcheng}}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">标签</text>
|
||||
<chenghao-tag mingcheng="{{item.chenghao_mingcheng}}" texiaoJson="{{item.chenghao_texiao_json}}" />
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">次数</text>
|
||||
<text class="value">{{item.cishu}}次</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">总费用</text>
|
||||
<text class="value">¥{{item.total_fee}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作行 -->
|
||||
<view class="card-actions">
|
||||
<view class="expand-btn" data-id="{{item.jilu_id}}" bindtap="toggleExpand">
|
||||
{{expandedIds.indexOf(item.jilu_id) > -1 ? '收起详情' : '展开详情'}}
|
||||
</view>
|
||||
<view wx:if="{{item.zhuangtai == 0}}" class="judge-btn" data-item="{{item}}" bindtap="goJudge">
|
||||
去评判
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 展开的详细内容 -->
|
||||
<view class="card-detail" wx:if="{{expandedIds.indexOf(item.jilu_id) > -1}}">
|
||||
<view class="detail-section" wx:if="{{item.guize_neirong}}">
|
||||
<text class="detail-title">考核规则</text>
|
||||
<text class="detail-text">{{item.guize_neirong}}</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">缴纳记录</text>
|
||||
<view wx:for="{{item.fee_list}}" wx:key="cishu" class="fee-row">
|
||||
<text>第{{item.cishu}}次:¥{{item.jine}}</text>
|
||||
</view>
|
||||
<text wx:if="{{!item.fee_list || item.fee_list.length === 0}}" class="detail-empty">暂无缴纳记录</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">拒绝记录</text>
|
||||
<view wx:for="{{item.reject_list}}" wx:key="cishu" class="reject-row">
|
||||
<view class="reject-item">
|
||||
<text class="reject-time">{{item.create_time}}</text>
|
||||
<text class="reject-reason">第{{item.cishu}}次拒绝:{{item.yuanyin}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text wx:if="{{!item.reject_list || item.reject_list.length === 0}}" class="detail-empty">暂无拒绝记录</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">其他信息</text>
|
||||
<view class="info-grid">
|
||||
<text>打手游戏ID:{{item.dashou_youxi_id || '无'}}</text>
|
||||
<text>打手备注:{{item.dashou_beizhu || '无'}}</text>
|
||||
<text>审核官游戏ID:{{item.shenheguan_youxi_id || '无'}}</text>
|
||||
<text>创建时间:{{item.create_time}}</text>
|
||||
<text>更新时间:{{item.update_time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{isLoadingMore}}" class="loading-more">加载更多...</view>
|
||||
<view wx:if="{{!hasMore && recordList.length > 0}}" class="no-more">—— 没有更多了 ——</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 加载遮罩 -->
|
||||
<view wx:if="{{isLoading && recordList.length === 0}}" class="loading-mask">
|
||||
<view class="loading-spinner"></view>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- pages/assess-log/assess-log.wxml -->
|
||||
<view class="page-root">
|
||||
<!-- 顶部筛选区 -->
|
||||
<view class="filter-bar">
|
||||
<!-- 板块筛选 -->
|
||||
<scroll-view class="module-scroll" scroll-x enhanced show-scrollbar="{{false}}">
|
||||
<view class="module-container">
|
||||
<view class="filter-item {{xuanzhongBankuaiId === 0 ? 'active' : ''}}"
|
||||
data-id="{{0}}" bindtap="selectModule">
|
||||
<text>全部板块</text>
|
||||
</view>
|
||||
<block wx:for="{{moduleList}}" wx:key="bankuai_id">
|
||||
<view class="filter-item {{xuanzhongBankuaiId === item.bankuai_id ? 'active' : ''}}"
|
||||
data-id="{{item.bankuai_id}}" bindtap="selectModule">
|
||||
<text>{{item.mingcheng}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- 状态筛选 -->
|
||||
<view class="status-row">
|
||||
<view class="status-item {{statusFilter === 0 ? 'active' : ''}}" data-status="{{0}}" bindtap="selectStatus">全部</view>
|
||||
<view class="status-item {{statusFilter === 1 ? 'active' : ''}}" data-status="{{1}}" bindtap="selectStatus">审核中</view>
|
||||
<view class="status-item {{statusFilter === 2 ? 'active' : ''}}" data-status="{{2}}" bindtap="selectStatus">已通过</view>
|
||||
<view class="status-item {{statusFilter === 3 ? 'active' : ''}}" data-status="{{3}}" bindtap="selectStatus">未通过</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表区域 -->
|
||||
<view class="list-container">
|
||||
<scroll-view class="list-scroll" scroll-y enhanced show-scrollbar="{{false}}"
|
||||
bindscrolltolower="onReachBottom">
|
||||
<view class="record-list">
|
||||
<view wx:if="{{!isLoading && recordList.length === 0}}" class="empty-tip">暂无考核记录</view>
|
||||
|
||||
<block wx:for="{{recordList}}" wx:key="jilu_id">
|
||||
<view class="card">
|
||||
<!-- 头部信息 -->
|
||||
<view class="card-header">
|
||||
<image class="avatar" src="{{item.shenqingren_avatar}}" mode="aspectFill" />
|
||||
<view class="user-info">
|
||||
<text class="nickname">{{item.shenqingren_nicheng || '用户'}}</text>
|
||||
<text class="uid">UID {{item.shenqingren_id}}</text>
|
||||
</view>
|
||||
<view class="status-tag status-{{item.zhuangtai}}">
|
||||
{{item.zhuangtai == 0 ? '审核中' : (item.zhuangtai == 1 ? '已通过' : (item.zhuangtai == 2 ? '未通过' : '待审核'))}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 摘要信息 -->
|
||||
<view class="card-summary">
|
||||
<view class="summary-item">
|
||||
<text class="label">板块</text>
|
||||
<text class="value">{{item.bankuai_mingcheng}}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">标签</text>
|
||||
<chenghao-tag mingcheng="{{item.chenghao_mingcheng}}" texiaoJson="{{item.chenghao_texiao_json}}" />
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">次数</text>
|
||||
<text class="value">{{item.cishu}}次</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">总费用</text>
|
||||
<text class="value">¥{{item.total_fee}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作行 -->
|
||||
<view class="card-actions">
|
||||
<view class="expand-btn" data-id="{{item.jilu_id}}" bindtap="toggleExpand">
|
||||
{{expandedIds.indexOf(item.jilu_id) > -1 ? '收起详情' : '展开详情'}}
|
||||
</view>
|
||||
<view wx:if="{{item.zhuangtai == 0}}" class="judge-btn" data-item="{{item}}" bindtap="goJudge">
|
||||
去评判
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 展开的详细内容 -->
|
||||
<view class="card-detail" wx:if="{{expandedIds.indexOf(item.jilu_id) > -1}}">
|
||||
<view class="detail-section" wx:if="{{item.guize_neirong}}">
|
||||
<text class="detail-title">考核规则</text>
|
||||
<text class="detail-text">{{item.guize_neirong}}</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">缴纳记录</text>
|
||||
<view wx:for="{{item.fee_list}}" wx:key="cishu" class="fee-row">
|
||||
<text>第{{item.cishu}}次:¥{{item.jine}}</text>
|
||||
</view>
|
||||
<text wx:if="{{!item.fee_list || item.fee_list.length === 0}}" class="detail-empty">暂无缴纳记录</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">拒绝记录</text>
|
||||
<view wx:for="{{item.reject_list}}" wx:key="cishu" class="reject-row">
|
||||
<view class="reject-item">
|
||||
<text class="reject-time">{{item.create_time}}</text>
|
||||
<text class="reject-reason">第{{item.cishu}}次拒绝:{{item.yuanyin}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text wx:if="{{!item.reject_list || item.reject_list.length === 0}}" class="detail-empty">暂无拒绝记录</text>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="detail-title">其他信息</text>
|
||||
<view class="info-grid">
|
||||
<text>打手游戏ID:{{item.dashou_youxi_id || '无'}}</text>
|
||||
<text>打手备注:{{item.dashou_beizhu || '无'}}</text>
|
||||
<text>审核官游戏ID:{{item.shenheguan_youxi_id || '无'}}</text>
|
||||
<text>创建时间:{{item.create_time}}</text>
|
||||
<text>更新时间:{{item.update_time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{isLoadingMore}}" class="loading-more">加载更多...</view>
|
||||
<view wx:if="{{!hasMore && recordList.length > 0}}" class="no-more">—— 没有更多了 ——</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 加载遮罩 -->
|
||||
<view wx:if="{{isLoading && recordList.length === 0}}" class="loading-mask">
|
||||
<view class="loading-spinner"></view>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
@@ -1,263 +1,262 @@
|
||||
/* pages/kaohe_jilu/kaohe_jilu.wxss - 晨露微光风格(左右均等边距) */
|
||||
page {
|
||||
background: linear-gradient(135deg, #FDFBF7 0%, #F2EFE9 100%);
|
||||
color: #4A4A4A;
|
||||
font-family: 'SF Pro Display', 'PingFang SC', system-ui;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-root {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 筛选栏 */
|
||||
.filter-bar {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(20px);
|
||||
border-bottom: 1rpx solid rgba(0,0,0,0.04);
|
||||
flex-shrink: 0;
|
||||
padding: 20rpx 0 0;
|
||||
}
|
||||
|
||||
.module-scroll {
|
||||
white-space: nowrap;
|
||||
height: 70rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
.module-container {
|
||||
display: inline-flex;
|
||||
gap: 20rpx;
|
||||
align-items: center;
|
||||
height: 70rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 30rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 28rpx;
|
||||
background: #F0EFEC;
|
||||
font-size: 26rpx;
|
||||
color: #6B6B6B;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.filter-item.active {
|
||||
background: #C8A27A;
|
||||
color: #FFFFFF;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4rpx 12rpx rgba(200, 162, 122, 0.3);
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
padding: 15rpx 30rpx 20rpx;
|
||||
gap: 30rpx;
|
||||
}
|
||||
.status-item {
|
||||
font-size: 26rpx;
|
||||
color: #8B8B8B;
|
||||
padding-bottom: 8rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.status-item.active {
|
||||
color: #C8A27A;
|
||||
border-bottom-color: #C8A27A;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 列表容器 */
|
||||
.list-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.list-scroll {
|
||||
height: 100%;
|
||||
padding: 20rpx 0; /* 上下内边距 */
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #A0A0A0;
|
||||
font-size: 28rpx;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
/* 卡片:统一左右边距 30rpx */
|
||||
.card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 24rpx 30rpx; /* 左右严格相等 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.avatar {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 18rpx;
|
||||
border: 2rpx solid #F0EDE8;
|
||||
background: #F7F5F2;
|
||||
}
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
.nickname {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #3A3A3A;
|
||||
display: block;
|
||||
}
|
||||
.uid {
|
||||
font-size: 24rpx;
|
||||
color: #9A9A9A;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
.status-tag {
|
||||
font-size: 24rpx;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-0 { background: #FFF3E0; color: #EF6C00; }
|
||||
.status-1 { background: #E8F5E9; color: #2E7D32; }
|
||||
.status-2 { background: #FFEBEE; color: #C62828; }
|
||||
.status-3 { background: #E3F2FD; color: #1565C0; }
|
||||
|
||||
.card-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.summary-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.summary-item .label {
|
||||
color: #8B8B8B;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
.summary-item .value {
|
||||
color: #3A3A3A;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #F5F2ED;
|
||||
}
|
||||
.expand-btn {
|
||||
font-size: 26rpx;
|
||||
color: #C8A27A;
|
||||
font-weight: 500;
|
||||
}
|
||||
.judge-btn {
|
||||
font-size: 26rpx;
|
||||
background: #C8A27A;
|
||||
color: #FFFFFF;
|
||||
padding: 8rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 展开详情(左右边距继承卡片,无需额外设置) */
|
||||
.card-detail {
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #F5F2ED;
|
||||
}
|
||||
.detail-section {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.detail-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #5A5A5A;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
.detail-text {
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.fee-row, .reject-row {
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
.reject-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #FFF9F5;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.reject-time {
|
||||
font-size: 22rpx;
|
||||
color: #B0A090;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.reject-reason {
|
||||
font-size: 24rpx;
|
||||
color: #7A5A4A;
|
||||
}
|
||||
.detail-empty {
|
||||
font-size: 24rpx;
|
||||
color: #A0A0A0;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
.info-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
}
|
||||
|
||||
/* 加载 */
|
||||
.loading-more, .no-more {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(253, 251, 247, 0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #E0DDD5;
|
||||
border-top-color: #C8A27A;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
/* pages/assess-log/assess-log.wxss - 晨露微光风格(左右均等边距) */
|
||||
page {
|
||||
background: linear-gradient(135deg, #FDFBF7 0%, #F2EFE9 100%);
|
||||
color: #4A4A4A;
|
||||
font-family: 'SF Pro Display', 'PingFang SC', system-ui;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-root {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 筛选栏 */
|
||||
.filter-bar {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(20px);
|
||||
border-bottom: 1rpx solid rgba(0,0,0,0.04);
|
||||
flex-shrink: 0;
|
||||
padding: 20rpx 0 0;
|
||||
}
|
||||
|
||||
.module-scroll {
|
||||
white-space: nowrap;
|
||||
height: 70rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
.module-container {
|
||||
display: inline-flex;
|
||||
gap: 20rpx;
|
||||
align-items: center;
|
||||
height: 70rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 30rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 28rpx;
|
||||
background: #F0EFEC;
|
||||
font-size: 26rpx;
|
||||
color: #6B6B6B;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.filter-item.active {
|
||||
background: #C8A27A;
|
||||
color: #FFFFFF;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4rpx 12rpx rgba(200, 162, 122, 0.3);
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
padding: 15rpx 30rpx 20rpx;
|
||||
gap: 30rpx;
|
||||
}
|
||||
.status-item {
|
||||
font-size: 26rpx;
|
||||
color: #8B8B8B;
|
||||
padding-bottom: 8rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.status-item.active {
|
||||
color: #C8A27A;
|
||||
border-bottom-color: #C8A27A;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 列表容器 */
|
||||
.list-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.list-scroll {
|
||||
height: 100%;
|
||||
padding: 20rpx 0; /* 上下内边距 */
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #A0A0A0;
|
||||
font-size: 28rpx;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
/* 卡片:统一左右边距 30rpx */
|
||||
.card {
|
||||
background: #FFFFFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx;
|
||||
margin: 0 30rpx 24rpx 30rpx; /* 左右严格相等 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.avatar {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 18rpx;
|
||||
border: 2rpx solid #F0EDE8;
|
||||
background: #F7F5F2;
|
||||
}
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
.nickname {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #3A3A3A;
|
||||
display: block;
|
||||
}
|
||||
.uid {
|
||||
font-size: 24rpx;
|
||||
color: #9A9A9A;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
.status-tag {
|
||||
font-size: 24rpx;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-0 { background: #FFF3E0; color: #EF6C00; }
|
||||
.status-1 { background: #E8F5E9; color: #2E7D32; }
|
||||
.status-2 { background: #FFEBEE; color: #C62828; }
|
||||
.status-3 { background: #E3F2FD; color: #1565C0; }
|
||||
|
||||
.card-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.summary-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.summary-item .label {
|
||||
color: #8B8B8B;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
.summary-item .value {
|
||||
color: #3A3A3A;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #F5F2ED;
|
||||
}
|
||||
.expand-btn {
|
||||
font-size: 26rpx;
|
||||
color: #C8A27A;
|
||||
font-weight: 500;
|
||||
}
|
||||
.judge-btn {
|
||||
font-size: 26rpx;
|
||||
background: #C8A27A;
|
||||
color: #FFFFFF;
|
||||
padding: 8rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 展开详情(左右边距继承卡片,无需额外设置) */
|
||||
.card-detail {
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #F5F2ED;
|
||||
}
|
||||
.detail-section {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.detail-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #5A5A5A;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
.detail-text {
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.fee-row, .reject-row {
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
.reject-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #FFF9F5;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.reject-time {
|
||||
font-size: 22rpx;
|
||||
color: #B0A090;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.reject-reason {
|
||||
font-size: 24rpx;
|
||||
color: #7A5A4A;
|
||||
}
|
||||
.detail-empty {
|
||||
font-size: 24rpx;
|
||||
color: #A0A0A0;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
.info-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #6B6B6B;
|
||||
}
|
||||
|
||||
/* 加载 */
|
||||
.loading-more, .no-more {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(253, 251, 247, 0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #E0DDD5;
|
||||
border-top-color: #C8A27A;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
@@ -1,208 +1,208 @@
|
||||
// pages/kaohe_dafen/kaohe_dafen.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
import { openPrivateChat, buildDashouPeerId } from '../../utils/im-user.js';
|
||||
import { resolveAvatarUrl } from '../../utils/avatar.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
hasMore: false,
|
||||
isLoading: false,
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 操作弹窗
|
||||
showAgreeModal: false,
|
||||
showRejectModal: false,
|
||||
showTransferModal: false,
|
||||
currentItem: null,
|
||||
rejectReason: '',
|
||||
|
||||
// 倒计时
|
||||
countdown: 2,
|
||||
counting: false,
|
||||
countdownTimer: null,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载考核记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/hqkhxq',
|
||||
method: 'POST',
|
||||
data: { page, page_size: this.data.pageSize }
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processed = list.map(item => ({
|
||||
...item,
|
||||
shenqingren_avatar: item.shenqingren_avatar && !item.shenqingren_avatar.startsWith('http')
|
||||
? oss + item.shenqingren_avatar
|
||||
: item.shenqingren_avatar || '/images/default-avatar.png'
|
||||
}));
|
||||
const newList = isRefresh ? processed : [...this.data.recordList, ...processed];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore, isLoading: false });
|
||||
} else {
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (this.data.hasMore && !this.data.isLoading) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 联系打手(私聊)—— 照搬金牌页面逻辑
|
||||
contactDashou(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item || !item.shenqingren_id) {
|
||||
wx.showToast({ title: '无法获取打手ID', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
openPrivateChat(this, {
|
||||
toUserId: buildDashouPeerId(item.shenqingren_id),
|
||||
toName: '打手' + item.shenqingren_id,
|
||||
toAvatar: resolveAvatarUrl(item.shenqingren_avatar),
|
||||
});
|
||||
},
|
||||
|
||||
// 修改游戏昵称
|
||||
async modifyNick(e) {
|
||||
const { id } = e.currentTarget.dataset;
|
||||
const item = this.data.recordList.find(r => r.jilu_id === id);
|
||||
if (!item) return;
|
||||
const newNick = item.shenheguan_youxi_id || '';
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khgxgkh',
|
||||
method: 'POST',
|
||||
data: { jilu_id: id, caozuo: 'modify_nick', youxi_id: newNick }
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
wx.showToast({ title: '修改成功', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: res.data?.msg || '修改失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
onNickInput(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
const value = e.detail.value;
|
||||
const list = this.data.recordList.map(item => {
|
||||
if (item.jilu_id === id) {
|
||||
return { ...item, shenheguan_youxi_id: value };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
this.setData({ recordList: list });
|
||||
},
|
||||
|
||||
// 🆕 实时更新拒绝原因
|
||||
onRejectInput(e) {
|
||||
this.setData({ rejectReason: e.detail.value });
|
||||
},
|
||||
|
||||
openAgreeModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showAgreeModal: true, currentItem: item });
|
||||
this.startCountdown();
|
||||
},
|
||||
openRejectModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showRejectModal: true, currentItem: item, rejectReason: '' });
|
||||
this.startCountdown();
|
||||
},
|
||||
openTransferModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showTransferModal: true, currentItem: item });
|
||||
this.startCountdown();
|
||||
},
|
||||
|
||||
closeAllModals() {
|
||||
this.stopCountdown();
|
||||
this.setData({
|
||||
showAgreeModal: false,
|
||||
showRejectModal: false,
|
||||
showTransferModal: false,
|
||||
currentItem: null,
|
||||
rejectReason: ''
|
||||
});
|
||||
},
|
||||
|
||||
startCountdown() {
|
||||
this.stopCountdown();
|
||||
this.setData({ counting: true, countdown: 2 });
|
||||
this.data.countdownTimer = setInterval(() => {
|
||||
if (this.data.countdown > 1) {
|
||||
this.setData({ countdown: this.data.countdown - 1 });
|
||||
} else {
|
||||
this.stopCountdown();
|
||||
this.setData({ counting: false, countdown: 0 });
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
stopCountdown() {
|
||||
if (this.data.countdownTimer) {
|
||||
clearInterval(this.data.countdownTimer);
|
||||
this.data.countdownTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 执行操作(从事件对象中获取操作类型)
|
||||
async executeAction(e) {
|
||||
const actionType = e.currentTarget.dataset.action;
|
||||
if (!actionType) {
|
||||
wx.showToast({ title: '操作类型异常', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.data.currentItem;
|
||||
if (!item) return;
|
||||
|
||||
const params = { jilu_id: item.jilu_id, caozuo: actionType };
|
||||
|
||||
if (actionType === 'reject') {
|
||||
if (!this.data.rejectReason.trim()) {
|
||||
wx.showToast({ title: '请填写拒绝原因', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
params.yuanyin = this.data.rejectReason;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await request({ url: '/dengji/khgxgkh', method: 'POST', data: params });
|
||||
if (res && res.data.code === 0) {
|
||||
wx.showToast({ title: '操作成功', icon: 'success' });
|
||||
this.closeAllModals();
|
||||
const newList = this.data.recordList.filter(r => r.jilu_id !== item.jilu_id);
|
||||
this.setData({ recordList: newList });
|
||||
} else {
|
||||
wx.showToast({ title: res.data?.msg || '操作失败', icon: 'none' });
|
||||
this.closeAllModals();
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.closeAllModals();
|
||||
}
|
||||
},
|
||||
// pages/assess-score/assess-score.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
import { openPrivateChat, buildDashouPeerId } from '../../utils/im-user.js';
|
||||
import { resolveAvatarUrl } from '../../utils/avatar.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
recordList: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
hasMore: false,
|
||||
isLoading: false,
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 操作弹窗
|
||||
showAgreeModal: false,
|
||||
showRejectModal: false,
|
||||
showTransferModal: false,
|
||||
currentItem: null,
|
||||
rejectReason: '',
|
||||
|
||||
// 倒计时
|
||||
countdown: 2,
|
||||
counting: false,
|
||||
countdownTimer: null,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadRecords(true);
|
||||
},
|
||||
|
||||
// 加载考核记录
|
||||
async loadRecords(isRefresh = false) {
|
||||
if (this.data.isLoading) return;
|
||||
const page = isRefresh ? 1 : this.data.page;
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/hqkhxq',
|
||||
method: 'POST',
|
||||
data: { page, page_size: this.data.pageSize }
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
const list = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more;
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processed = list.map(item => ({
|
||||
...item,
|
||||
shenqingren_avatar: item.shenqingren_avatar && !item.shenqingren_avatar.startsWith('http')
|
||||
? oss + item.shenqingren_avatar
|
||||
: item.shenqingren_avatar || '/images/default-avatar.png'
|
||||
}));
|
||||
const newList = isRefresh ? processed : [...this.data.recordList, ...processed];
|
||||
this.setData({ recordList: newList, page: page + 1, hasMore, isLoading: false });
|
||||
} else {
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (this.data.hasMore && !this.data.isLoading) {
|
||||
this.loadRecords(false);
|
||||
}
|
||||
},
|
||||
|
||||
// 联系打手(私聊)—— 照搬金牌页面逻辑
|
||||
contactDashou(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item || !item.shenqingren_id) {
|
||||
wx.showToast({ title: '无法获取打手ID', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
openPrivateChat(this, {
|
||||
toUserId: buildDashouPeerId(item.shenqingren_id),
|
||||
toName: '打手' + item.shenqingren_id,
|
||||
toAvatar: resolveAvatarUrl(item.shenqingren_avatar),
|
||||
});
|
||||
},
|
||||
|
||||
// 修改游戏昵称
|
||||
async modifyNick(e) {
|
||||
const { id } = e.currentTarget.dataset;
|
||||
const item = this.data.recordList.find(r => r.jilu_id === id);
|
||||
if (!item) return;
|
||||
const newNick = item.shenheguan_youxi_id || '';
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khgxgkh',
|
||||
method: 'POST',
|
||||
data: { jilu_id: id, caozuo: 'modify_nick', youxi_id: newNick }
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
wx.showToast({ title: '修改成功', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: res.data?.msg || '修改失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
onNickInput(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
const value = e.detail.value;
|
||||
const list = this.data.recordList.map(item => {
|
||||
if (item.jilu_id === id) {
|
||||
return { ...item, shenheguan_youxi_id: value };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
this.setData({ recordList: list });
|
||||
},
|
||||
|
||||
// 🆕 实时更新拒绝原因
|
||||
onRejectInput(e) {
|
||||
this.setData({ rejectReason: e.detail.value });
|
||||
},
|
||||
|
||||
openAgreeModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showAgreeModal: true, currentItem: item });
|
||||
this.startCountdown();
|
||||
},
|
||||
openRejectModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showRejectModal: true, currentItem: item, rejectReason: '' });
|
||||
this.startCountdown();
|
||||
},
|
||||
openTransferModal(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
this.setData({ showTransferModal: true, currentItem: item });
|
||||
this.startCountdown();
|
||||
},
|
||||
|
||||
closeAllModals() {
|
||||
this.stopCountdown();
|
||||
this.setData({
|
||||
showAgreeModal: false,
|
||||
showRejectModal: false,
|
||||
showTransferModal: false,
|
||||
currentItem: null,
|
||||
rejectReason: ''
|
||||
});
|
||||
},
|
||||
|
||||
startCountdown() {
|
||||
this.stopCountdown();
|
||||
this.setData({ counting: true, countdown: 2 });
|
||||
this.data.countdownTimer = setInterval(() => {
|
||||
if (this.data.countdown > 1) {
|
||||
this.setData({ countdown: this.data.countdown - 1 });
|
||||
} else {
|
||||
this.stopCountdown();
|
||||
this.setData({ counting: false, countdown: 0 });
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
stopCountdown() {
|
||||
if (this.data.countdownTimer) {
|
||||
clearInterval(this.data.countdownTimer);
|
||||
this.data.countdownTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 执行操作(从事件对象中获取操作类型)
|
||||
async executeAction(e) {
|
||||
const actionType = e.currentTarget.dataset.action;
|
||||
if (!actionType) {
|
||||
wx.showToast({ title: '操作类型异常', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.data.currentItem;
|
||||
if (!item) return;
|
||||
|
||||
const params = { jilu_id: item.jilu_id, caozuo: actionType };
|
||||
|
||||
if (actionType === 'reject') {
|
||||
if (!this.data.rejectReason.trim()) {
|
||||
wx.showToast({ title: '请填写拒绝原因', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
params.yuanyin = this.data.rejectReason;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await request({ url: '/dengji/khgxgkh', method: 'POST', data: params });
|
||||
if (res && res.data.code === 0) {
|
||||
wx.showToast({ title: '操作成功', icon: 'success' });
|
||||
this.closeAllModals();
|
||||
const newList = this.data.recordList.filter(r => r.jilu_id !== item.jilu_id);
|
||||
this.setData({ recordList: newList });
|
||||
} else {
|
||||
wx.showToast({ title: res.data?.msg || '操作失败', icon: 'none' });
|
||||
this.closeAllModals();
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.closeAllModals();
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,118 +1,118 @@
|
||||
<!-- pages/kaohe_dafen/kaohe_dafen.wxml -->
|
||||
<view class="root-page">
|
||||
<view class="scroll-container" scroll-y="true" bindscrolltolower="onReachBottom">
|
||||
<view class="list">
|
||||
<block wx:for="{{recordList}}" wx:key="jilu_id">
|
||||
<view class="card">
|
||||
<!-- 用户信息行 -->
|
||||
<view class="user-row">
|
||||
<image class="avatar" src="{{item.shenqingren_avatar}}" mode="aspectFill" />
|
||||
<view class="info">
|
||||
<text class="uid">UID {{item.shenqingren_id}}</text>
|
||||
<text class="time">{{item.create_time}}</text>
|
||||
</view>
|
||||
<view class="contact-btn" bindtap="contactDashou" data-item="{{item}}">联系</view>
|
||||
</view>
|
||||
|
||||
<!-- 详情区 -->
|
||||
<view class="detail-grid">
|
||||
<view class="detail-item">
|
||||
<text class="label">板块</text>
|
||||
<text class="value">{{item.bankuai_mingcheng}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">标签</text>
|
||||
<chenghao-tag mingcheng="{{item.chenghao_mingcheng}}" texiaoJson="{{item.chenghao_texiao_json}}" />
|
||||
<text wx:if="{{item.is_jinpai}}" class="jinpai-note">(开启金牌)</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">规则</text>
|
||||
<text class="value rule-content">{{item.guize_neirong}}</text>
|
||||
</view>
|
||||
<!-- 🆕 添加被考核人游戏昵称 -->
|
||||
<view class="detail-item" wx:if="{{item.dashou_youxi_id}}">
|
||||
<text class="label">打手游戏昵称</text>
|
||||
<text class="value">{{item.dashou_youxi_id}}</text>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{item.dashou_beizhu}}">
|
||||
<text class="label">备注</text>
|
||||
<text class="value">{{item.dashou_beizhu}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">次数</text>
|
||||
<text class="value">{{item.cishu}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">待收考核费</text>
|
||||
<text class="value amount">¥{{item.daishou_fei}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上次失败原因 -->
|
||||
<view wx:if="{{item.last_fail_reason}}" class="fail-box">
|
||||
<text class="fail-label">上次拒绝原因:</text>
|
||||
<text class="fail-text">{{item.last_fail_reason}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 游戏昵称修改 -->
|
||||
<view class="nick-row">
|
||||
<text class="label">我的游戏昵称</text>
|
||||
<input class="nick-input" data-id="{{item.jilu_id}}" value="{{item.shenheguan_youxi_id}}" bindinput="onNickInput" placeholder="输入昵称" />
|
||||
<view class="save-nick-btn" data-id="{{item.jilu_id}}" bindtap="modifyNick">保存</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-row">
|
||||
<view class="action-btn agree" data-item="{{item}}" bindtap="openAgreeModal">合格</view>
|
||||
<view class="action-btn reject" data-item="{{item}}" bindtap="openRejectModal">不合格</view>
|
||||
<view class="action-btn transfer" data-item="{{item}}" bindtap="openTransferModal">转移</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:if="{{isLoading}}" class="loading">加载中...</view>
|
||||
<view wx:if="{{!hasMore && recordList.length > 0}}" class="no-more">—— 已加载全部 ——</view>
|
||||
<view wx:if="{{!isLoading && recordList.length === 0}}" class="empty">暂无待考核记录</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通过确认弹窗 -->
|
||||
<view wx:if="{{showAgreeModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">确认通过考核</view>
|
||||
<view class="modal-body">通过后,该用户将获得对应标签,请认真审核后操作。</view>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="agree">确认通过</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拒绝弹窗 -->
|
||||
<view wx:if="{{showRejectModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">拒绝通过</view>
|
||||
<textarea class="reason-input" value="{{rejectReason}}" bindinput="onRejectInput" placeholder="请填写拒绝原因" maxlength="200"></textarea>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="reject">确认拒绝</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 转移弹窗 -->
|
||||
<view wx:if="{{showTransferModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">确认转移考核</view>
|
||||
<view class="modal-body">转移后,您将无法继续考核此订单,可在考核中心重新接待。</view>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="transfer">确认转移</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- pages/assess-score/assess-score.wxml -->
|
||||
<view class="root-page">
|
||||
<view class="scroll-container" scroll-y="true" bindscrolltolower="onReachBottom">
|
||||
<view class="list">
|
||||
<block wx:for="{{recordList}}" wx:key="jilu_id">
|
||||
<view class="card">
|
||||
<!-- 用户信息行 -->
|
||||
<view class="user-row">
|
||||
<image class="avatar" src="{{item.shenqingren_avatar}}" mode="aspectFill" />
|
||||
<view class="info">
|
||||
<text class="uid">UID {{item.shenqingren_id}}</text>
|
||||
<text class="time">{{item.create_time}}</text>
|
||||
</view>
|
||||
<view class="contact-btn" bindtap="contactDashou" data-item="{{item}}">联系</view>
|
||||
</view>
|
||||
|
||||
<!-- 详情区 -->
|
||||
<view class="detail-grid">
|
||||
<view class="detail-item">
|
||||
<text class="label">板块</text>
|
||||
<text class="value">{{item.bankuai_mingcheng}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">标签</text>
|
||||
<chenghao-tag mingcheng="{{item.chenghao_mingcheng}}" texiaoJson="{{item.chenghao_texiao_json}}" />
|
||||
<text wx:if="{{item.is_jinpai}}" class="jinpai-note">(开启金牌)</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">规则</text>
|
||||
<text class="value rule-content">{{item.guize_neirong}}</text>
|
||||
</view>
|
||||
<!-- 🆕 添加被考核人游戏昵称 -->
|
||||
<view class="detail-item" wx:if="{{item.dashou_youxi_id}}">
|
||||
<text class="label">打手游戏昵称</text>
|
||||
<text class="value">{{item.dashou_youxi_id}}</text>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{item.dashou_beizhu}}">
|
||||
<text class="label">备注</text>
|
||||
<text class="value">{{item.dashou_beizhu}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">次数</text>
|
||||
<text class="value">{{item.cishu}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="label">待收考核费</text>
|
||||
<text class="value amount">¥{{item.daishou_fei}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上次失败原因 -->
|
||||
<view wx:if="{{item.last_fail_reason}}" class="fail-box">
|
||||
<text class="fail-label">上次拒绝原因:</text>
|
||||
<text class="fail-text">{{item.last_fail_reason}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 游戏昵称修改 -->
|
||||
<view class="nick-row">
|
||||
<text class="label">我的游戏昵称</text>
|
||||
<input class="nick-input" data-id="{{item.jilu_id}}" value="{{item.shenheguan_youxi_id}}" bindinput="onNickInput" placeholder="输入昵称" />
|
||||
<view class="save-nick-btn" data-id="{{item.jilu_id}}" bindtap="modifyNick">保存</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-row">
|
||||
<view class="action-btn agree" data-item="{{item}}" bindtap="openAgreeModal">合格</view>
|
||||
<view class="action-btn reject" data-item="{{item}}" bindtap="openRejectModal">不合格</view>
|
||||
<view class="action-btn transfer" data-item="{{item}}" bindtap="openTransferModal">转移</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:if="{{isLoading}}" class="loading">加载中...</view>
|
||||
<view wx:if="{{!hasMore && recordList.length > 0}}" class="no-more">—— 已加载全部 ——</view>
|
||||
<view wx:if="{{!isLoading && recordList.length === 0}}" class="empty">暂无待考核记录</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通过确认弹窗 -->
|
||||
<view wx:if="{{showAgreeModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">确认通过考核</view>
|
||||
<view class="modal-body">通过后,该用户将获得对应标签,请认真审核后操作。</view>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="agree">确认通过</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拒绝弹窗 -->
|
||||
<view wx:if="{{showRejectModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">拒绝通过</view>
|
||||
<textarea class="reason-input" value="{{rejectReason}}" bindinput="onRejectInput" placeholder="请填写拒绝原因" maxlength="200"></textarea>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="reject">确认拒绝</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 转移弹窗 -->
|
||||
<view wx:if="{{showTransferModal}}" class="modal-mask" bindtap="closeAllModals">
|
||||
<view class="modal-box" catchtap="noop">
|
||||
<view class="modal-header">确认转移考核</view>
|
||||
<view class="modal-body">转移后,您将无法继续考核此订单,可在考核中心重新接待。</view>
|
||||
<view class="countdown-text" wx:if="{{counting}}">{{countdown}}秒后可确认</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn cancel" bindtap="closeAllModals">取消</view>
|
||||
<view class="btn confirm {{counting ? 'disabled' : ''}}" bindtap="{{counting ? '' : 'executeAction'}}" data-action="transfer">确认转移</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
@@ -1,218 +1,218 @@
|
||||
// pages/kaoheguan/kaoheguan.js
|
||||
// 只新增了两个字段的接收,其余所有代码未变
|
||||
import request from '../../utils/request.js';
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
syncRoleStatuses,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar.js';
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
isKaoheguan: false,
|
||||
isLoading: false,
|
||||
inviteCode: '',
|
||||
statusText: '用户尚未注册或账号已被封禁',
|
||||
uid: '',
|
||||
avatarUrl: '',
|
||||
icons: {
|
||||
refresh: '',
|
||||
tixian: '',
|
||||
daofen: '',
|
||||
jilu: '',
|
||||
zhongxin: '',
|
||||
bgImage: ''
|
||||
},
|
||||
kaoheData: {
|
||||
shenheZongshu: 0,
|
||||
tongguoZongshu: 0,
|
||||
yue: '0.00',
|
||||
zonge: '0.00',
|
||||
shenheZhuangtai: 0,
|
||||
bankuaiList: [],
|
||||
isRenzheng: false, // 🆕 是否认证
|
||||
pendingShenheCount: 0 // 🆕 审核中数量
|
||||
},
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
planetPaused: {
|
||||
top: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false
|
||||
}
|
||||
},
|
||||
|
||||
_planetTimers: {},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/dashouduan/dashouduan' });
|
||||
return;
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const iconBase = 'beijing/kaohe/';
|
||||
this.setData({
|
||||
'icons.refresh': ossUrl + iconBase + 'shuaxin.png',
|
||||
'icons.tixian': ossUrl + iconBase + 'tixian.png',
|
||||
'icons.daofen': ossUrl + iconBase + 'daofen.png',
|
||||
'icons.jilu': ossUrl + iconBase + 'jilu.png',
|
||||
'icons.zhongxin': ossUrl + iconBase + 'zhongxin.png',
|
||||
'icons.bgImage': ossUrl + iconBase + 'top_bg.jpg'
|
||||
});
|
||||
|
||||
const kaoheguanstatus = wx.getStorageSync('kaoheguanstatus');
|
||||
if (isRoleStatusActive(kaoheguanstatus)) {
|
||||
this.loadUserInfo();
|
||||
this.setData({ isKaoheguan: true });
|
||||
this.getKaoheguanInfo();
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
this.setData({ isKaoheguan: false });
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) {
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) {
|
||||
if (!this.data.isKaoheguan) this.setData({ isKaoheguan: true });
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
this.refreshKaoheInfo();
|
||||
}
|
||||
},
|
||||
|
||||
loadUserInfo() {
|
||||
const uid = wx.getStorageSync('uid') || '';
|
||||
const touxiang = wx.getStorageSync('touxiang') || '';
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
|
||||
let avatarUrl = defaultAvatar;
|
||||
if (touxiang) {
|
||||
avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang);
|
||||
}
|
||||
this.setData({ uid, avatarUrl });
|
||||
},
|
||||
|
||||
async getKaoheguanInfo() {
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({ url: '/dengji/khgsx', method: 'POST' });
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data;
|
||||
if (data.zhuangtai === 0 || data.zhuangtai === 2) {
|
||||
wx.setStorageSync('kaoheguanstatus', 0);
|
||||
this.setData({ isKaoheguan: false, isLoading: false, statusText: '用户尚未注册或账号已被封禁' });
|
||||
return;
|
||||
}
|
||||
wx.setStorageSync('kaoheguanstatus', 1);
|
||||
this.setData({
|
||||
isKaoheguan: true,
|
||||
isLoading: false,
|
||||
kaoheData: {
|
||||
shenheZongshu: data.shenhe_zongshu || 0,
|
||||
tongguoZongshu: data.tongguo_zongshu || 0,
|
||||
yue: data.yue || '0.00',
|
||||
zonge: data.zonge || '0.00',
|
||||
shenheZhuangtai: data.shenhe_zhuangtai || 0,
|
||||
bankuaiList: data.bankuai_list || [],
|
||||
isRenzheng: data.is_renzheng || false, // 🆕
|
||||
pendingShenheCount: data.pending_shenhe_count || 0 // 🆕
|
||||
}
|
||||
});
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取考核官信息失败:', error);
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
onInviteCodeInput(e) {
|
||||
this.setData({ inviteCode: e.detail.value.trim() });
|
||||
},
|
||||
|
||||
async onRegister() {
|
||||
const { inviteCode } = this.data;
|
||||
if (!inviteCode) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none', duration: 2000 });
|
||||
return;
|
||||
}
|
||||
if (inviteCode.length > 100) {
|
||||
wx.showToast({ title: '邀请码不能超过100位', icon: 'none', duration: 2000 });
|
||||
return;
|
||||
}
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khgzc',
|
||||
method: 'POST',
|
||||
data: { inviteCode: inviteCode }
|
||||
});
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data || {};
|
||||
syncRoleStatuses(data);
|
||||
if (!Object.prototype.hasOwnProperty.call(data, 'kaoheguanstatus')) {
|
||||
wx.setStorageSync('kaoheguanstatus', 1);
|
||||
}
|
||||
wx.showToast({ title: '注册成功', icon: 'success', duration: 2000 });
|
||||
this.loadUserInfo();
|
||||
await this.getKaoheguanInfo();
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none', duration: 2000 });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('注册失败:', error);
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
refreshKaoheInfo() {
|
||||
const now = Date.now();
|
||||
const lastTime = this.data.lastRefreshTime;
|
||||
const canRefresh = this.data.canRefresh;
|
||||
if (!canRefresh || (now - lastTime < 3000)) return;
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false });
|
||||
this.getKaoheguanInfo();
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000);
|
||||
},
|
||||
|
||||
goToWithdraw() {
|
||||
const yue = this.data.kaoheData.yue || 0;
|
||||
wx.navigateTo({
|
||||
url: `/pages/tixian/tixian?amount=${yue}&from=kaoheguan`
|
||||
});
|
||||
},
|
||||
goToDafen() { wx.navigateTo({ url: '/pages/kaohe_dafen/kaohe_dafen' }); },
|
||||
goToJilu() { wx.navigateTo({ url: '/pages/kaohe_jilu/kaohe_jilu' }); },
|
||||
goToZhongxin() { wx.navigateTo({ url: '/pages/kaohe_zhongxin/kaohe_zhongxin' }); },
|
||||
|
||||
onPlanetTouch(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
if (this._planetTimers[id]) {
|
||||
clearTimeout(this._planetTimers[id]);
|
||||
this._planetTimers[id] = null;
|
||||
}
|
||||
const paused = `planetPaused.${id}`;
|
||||
this.setData({ [paused]: true });
|
||||
},
|
||||
|
||||
onPlanetLeave(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
this._planetTimers[id] = setTimeout(() => {
|
||||
const paused = `planetPaused.${id}`;
|
||||
this.setData({ [paused]: false });
|
||||
}, 5000);
|
||||
}
|
||||
// pages/assessor/assessor.js
|
||||
// 只新增了两个字段的接收,其余所有代码未变
|
||||
import request from '../../utils/request.js';
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
syncRoleStatuses,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar.js';
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
isKaoheguan: false,
|
||||
isLoading: false,
|
||||
inviteCode: '',
|
||||
statusText: '用户尚未注册或账号已被封禁',
|
||||
uid: '',
|
||||
avatarUrl: '',
|
||||
icons: {
|
||||
refresh: '',
|
||||
tixian: '',
|
||||
daofen: '',
|
||||
jilu: '',
|
||||
zhongxin: '',
|
||||
bgImage: ''
|
||||
},
|
||||
kaoheData: {
|
||||
shenheZongshu: 0,
|
||||
tongguoZongshu: 0,
|
||||
yue: '0.00',
|
||||
zonge: '0.00',
|
||||
shenheZhuangtai: 0,
|
||||
bankuaiList: [],
|
||||
isRenzheng: false, // 🆕 是否认证
|
||||
pendingShenheCount: 0 // 🆕 审核中数量
|
||||
},
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
planetPaused: {
|
||||
top: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false
|
||||
}
|
||||
},
|
||||
|
||||
_planetTimers: {},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' });
|
||||
return;
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const iconBase = 'beijing/kaohe/';
|
||||
this.setData({
|
||||
'icons.refresh': ossUrl + iconBase + 'shuaxin.png',
|
||||
'icons.tixian': ossUrl + iconBase + 'tixian.png',
|
||||
'icons.daofen': ossUrl + iconBase + 'daofen.png',
|
||||
'icons.jilu': ossUrl + iconBase + 'jilu.png',
|
||||
'icons.zhongxin': ossUrl + iconBase + 'zhongxin.png',
|
||||
'icons.bgImage': ossUrl + iconBase + 'top_bg.jpg'
|
||||
});
|
||||
|
||||
const kaoheguanstatus = wx.getStorageSync('kaoheguanstatus');
|
||||
if (isRoleStatusActive(kaoheguanstatus)) {
|
||||
this.loadUserInfo();
|
||||
this.setData({ isKaoheguan: true });
|
||||
this.getKaoheguanInfo();
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
this.setData({ isKaoheguan: false });
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) {
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) {
|
||||
if (!this.data.isKaoheguan) this.setData({ isKaoheguan: true });
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
this.refreshKaoheInfo();
|
||||
}
|
||||
},
|
||||
|
||||
loadUserInfo() {
|
||||
const uid = wx.getStorageSync('uid') || '';
|
||||
const touxiang = wx.getStorageSync('touxiang') || '';
|
||||
const ossUrl = app.globalData.ossImageUrl || '';
|
||||
const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
|
||||
let avatarUrl = defaultAvatar;
|
||||
if (touxiang) {
|
||||
avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang);
|
||||
}
|
||||
this.setData({ uid, avatarUrl });
|
||||
},
|
||||
|
||||
async getKaoheguanInfo() {
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({ url: '/dengji/khgsx', method: 'POST' });
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data;
|
||||
if (data.zhuangtai === 0 || data.zhuangtai === 2) {
|
||||
wx.setStorageSync('kaoheguanstatus', 0);
|
||||
this.setData({ isKaoheguan: false, isLoading: false, statusText: '用户尚未注册或账号已被封禁' });
|
||||
return;
|
||||
}
|
||||
wx.setStorageSync('kaoheguanstatus', 1);
|
||||
this.setData({
|
||||
isKaoheguan: true,
|
||||
isLoading: false,
|
||||
kaoheData: {
|
||||
shenheZongshu: data.shenhe_zongshu || 0,
|
||||
tongguoZongshu: data.tongguo_zongshu || 0,
|
||||
yue: data.yue || '0.00',
|
||||
zonge: data.zonge || '0.00',
|
||||
shenheZhuangtai: data.shenhe_zhuangtai || 0,
|
||||
bankuaiList: data.bankuai_list || [],
|
||||
isRenzheng: data.is_renzheng || false, // 🆕
|
||||
pendingShenheCount: data.pending_shenhe_count || 0 // 🆕
|
||||
}
|
||||
});
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取考核官信息失败:', error);
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
onInviteCodeInput(e) {
|
||||
this.setData({ inviteCode: e.detail.value.trim() });
|
||||
},
|
||||
|
||||
async onRegister() {
|
||||
const { inviteCode } = this.data;
|
||||
if (!inviteCode) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none', duration: 2000 });
|
||||
return;
|
||||
}
|
||||
if (inviteCode.length > 100) {
|
||||
wx.showToast({ title: '邀请码不能超过100位', icon: 'none', duration: 2000 });
|
||||
return;
|
||||
}
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/khgzc',
|
||||
method: 'POST',
|
||||
data: { inviteCode: inviteCode }
|
||||
});
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data || {};
|
||||
syncRoleStatuses(data);
|
||||
if (!Object.prototype.hasOwnProperty.call(data, 'kaoheguanstatus')) {
|
||||
wx.setStorageSync('kaoheguanstatus', 1);
|
||||
}
|
||||
wx.showToast({ title: '注册成功', icon: 'success', duration: 2000 });
|
||||
this.loadUserInfo();
|
||||
await this.getKaoheguanInfo();
|
||||
ensureRoleOnCenterPage(this, 'kaoheguan');
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none', duration: 2000 });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('注册失败:', error);
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
refreshKaoheInfo() {
|
||||
const now = Date.now();
|
||||
const lastTime = this.data.lastRefreshTime;
|
||||
const canRefresh = this.data.canRefresh;
|
||||
if (!canRefresh || (now - lastTime < 3000)) return;
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false });
|
||||
this.getKaoheguanInfo();
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000);
|
||||
},
|
||||
|
||||
goToWithdraw() {
|
||||
const yue = this.data.kaoheData.yue || 0;
|
||||
wx.navigateTo({
|
||||
url: `/pages/withdraw/withdraw?amount=${yue}&from=kaoheguan`
|
||||
});
|
||||
},
|
||||
goToDafen() { wx.navigateTo({ url: '/pages/assess-score/assess-score' }); },
|
||||
goToJilu() { wx.navigateTo({ url: '/pages/assess-log/assess-log' }); },
|
||||
goToZhongxin() { wx.navigateTo({ url: '/pages/assess-center/assess-center' }); },
|
||||
|
||||
onPlanetTouch(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
if (this._planetTimers[id]) {
|
||||
clearTimeout(this._planetTimers[id]);
|
||||
this._planetTimers[id] = null;
|
||||
}
|
||||
const paused = `planetPaused.${id}`;
|
||||
this.setData({ [paused]: true });
|
||||
},
|
||||
|
||||
onPlanetLeave(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
this._planetTimers[id] = setTimeout(() => {
|
||||
const paused = `planetPaused.${id}`;
|
||||
this.setData({ [paused]: false });
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
@@ -1,128 +1,128 @@
|
||||
<!-- pages/kaoheguan/kaoheguan.wxml -->
|
||||
<view class="universe-root">
|
||||
<!-- 全屏弱化背景图 -->
|
||||
<image class="full-bg" src="{{icons.bgImage}}" mode="aspectFill" />
|
||||
|
||||
<!-- 动态星空与极光 -->
|
||||
<canvas type="2d" id="starfield" class="starfield-canvas"></canvas>
|
||||
<view class="aurora-ribbon"></view>
|
||||
|
||||
<!-- 未注册状态 -->
|
||||
<view class="unreg-floating" wx:if="{{!isKaoheguan}}">
|
||||
<view class="unreg-core">
|
||||
<image class="unreg-icon" src="/images/kaoheguan.png" mode="aspectFit" />
|
||||
<text class="unreg-title">考核官</text>
|
||||
<text class="unreg-desc">{{statusText}}</text>
|
||||
<input class="unreg-input" type="text" placeholder="输入邀请码" value="{{inviteCode}}" bindinput="onInviteCodeInput" placeholder-class="unreg-placeholder" maxlength="100" />
|
||||
<view class="unreg-btn" bindtap="onRegister">
|
||||
<text class="unreg-btn-text">即刻入驻</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已注册状态 · 行星系统 -->
|
||||
<view class="orbit-zone" wx:else>
|
||||
<!-- 身份条 -->
|
||||
<view class="top-identity">
|
||||
<image class="identity-avatar" src="{{avatarUrl}}" mode="aspectFill" />
|
||||
<view class="identity-info">
|
||||
<text class="identity-name">考核官</text>
|
||||
<view class="identity-uid">
|
||||
<text class="uid-txt">{{uid}}</text>
|
||||
<view class="status-indicator {{kaoheData.shenheZhuangtai == 1 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
<!-- 🆕 添加认证状态,这是唯一新增的行 -->
|
||||
<text class="renzheng-tag {{kaoheData.isRenzheng ? 'authed' : 'unauth'}}">
|
||||
{{kaoheData.isRenzheng ? '已认证' : '未认证'}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="refresh-touch" bindtap="refreshKaoheInfo">
|
||||
<image class="refresh-icon" src="{{icons.refresh}}" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 板块标签云 -->
|
||||
<view class="plate-cloud" wx:if="{{kaoheData.bankuaiList.length > 0}}">
|
||||
<scroll-view class="plate-cloud-scroll" scroll-x="true" enhanced show-scrollbar="{{false}}">
|
||||
<view class="plate-chip" wx:for="{{kaoheData.bankuaiList}}" wx:key="bankuai_id">{{item.mingcheng}}</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 中央余额星球 -->
|
||||
<view class="balance-planet">
|
||||
<view class="planet-ring"></view>
|
||||
<view class="planet-body">
|
||||
<text class="planet-num">{{kaoheData.yue}}元</text>
|
||||
<text class="planet-label">可提现余额</text>
|
||||
</view>
|
||||
<view class="planet-glow"></view>
|
||||
</view>
|
||||
|
||||
<!-- 流星数据条 -->
|
||||
<view class="meteor-stats">
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.shenheZongshu}}</text>
|
||||
<text class="meteor-label">审核总数</text>
|
||||
</view>
|
||||
<view class="meteor-divider"></view>
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.tongguoZongshu}}</text>
|
||||
<text class="meteor-label">通过总数</text>
|
||||
</view>
|
||||
<view class="meteor-divider"></view>
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.zonge}}元</text>
|
||||
<text class="meteor-label">累计赚取</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 十字星阵功能区 -->
|
||||
<view class="star-cross">
|
||||
<!-- 上方:考核中心 -->
|
||||
<view class="cross-item cross-top {{planetPaused.top ? 'pause-spin' : ''}}"
|
||||
bindtap="goToZhongxin"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="top">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.zhongxin}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核中心</text>
|
||||
</view>
|
||||
<!-- 下方:考核打分 -->
|
||||
<view class="cross-item cross-bottom {{planetPaused.bottom ? 'pause-spin' : ''}}"
|
||||
bindtap="goToDafen"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="bottom">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.daofen}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核打分</text>
|
||||
<!-- 🆕 添加红色角标,这是唯一新增的行 -->
|
||||
<view class="badge" wx:if="{{kaoheData.pendingShenheCount > 0}}">{{kaoheData.pendingShenheCount}}</view>
|
||||
</view>
|
||||
<!-- 左侧:考核记录 -->
|
||||
<view class="cross-item cross-left {{planetPaused.left ? 'pause-spin' : ''}}"
|
||||
bindtap="goToJilu"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="left">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.jilu}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核记录</text>
|
||||
</view>
|
||||
<!-- 右侧:立即提现 -->
|
||||
<view class="cross-item cross-right {{planetPaused.right ? 'pause-spin' : ''}}"
|
||||
bindtap="goToWithdraw"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="right">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.tixian}}" mode="aspectFit" />
|
||||
<text class="cross-text">立即提现</text>
|
||||
</view>
|
||||
<!-- 中央五角星 -->
|
||||
<view class="pentagram"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载星门 -->
|
||||
<view class="loading-portal" wx:if="{{isLoading}}">
|
||||
<view class="portal-ring"></view>
|
||||
<text class="portal-text">加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
<!-- pages/assessor/assessor.wxml -->
|
||||
<view class="universe-root">
|
||||
<!-- 全屏弱化背景图 -->
|
||||
<image class="full-bg" src="{{icons.bgImage}}" mode="aspectFill" />
|
||||
|
||||
<!-- 动态星空与极光 -->
|
||||
<canvas type="2d" id="starfield" class="starfield-canvas"></canvas>
|
||||
<view class="aurora-ribbon"></view>
|
||||
|
||||
<!-- 未注册状态 -->
|
||||
<view class="unreg-floating" wx:if="{{!isKaoheguan}}">
|
||||
<view class="unreg-core">
|
||||
<image class="unreg-icon" src="/images/kaoheguan.png" mode="aspectFit" />
|
||||
<text class="unreg-title">考核官</text>
|
||||
<text class="unreg-desc">{{statusText}}</text>
|
||||
<input class="unreg-input" type="text" placeholder="输入邀请码" value="{{inviteCode}}" bindinput="onInviteCodeInput" placeholder-class="unreg-placeholder" maxlength="100" />
|
||||
<view class="unreg-btn" bindtap="onRegister">
|
||||
<text class="unreg-btn-text">即刻入驻</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已注册状态 · 行星系统 -->
|
||||
<view class="orbit-zone" wx:else>
|
||||
<!-- 身份条 -->
|
||||
<view class="top-identity">
|
||||
<image class="identity-avatar" src="{{avatarUrl}}" mode="aspectFill" />
|
||||
<view class="identity-info">
|
||||
<text class="identity-name">考核官</text>
|
||||
<view class="identity-uid">
|
||||
<text class="uid-txt">{{uid}}</text>
|
||||
<view class="status-indicator {{kaoheData.shenheZhuangtai == 1 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
<!-- 🆕 添加认证状态,这是唯一新增的行 -->
|
||||
<text class="renzheng-tag {{kaoheData.isRenzheng ? 'authed' : 'unauth'}}">
|
||||
{{kaoheData.isRenzheng ? '已认证' : '未认证'}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="refresh-touch" bindtap="refreshKaoheInfo">
|
||||
<image class="refresh-icon" src="{{icons.refresh}}" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 板块标签云 -->
|
||||
<view class="plate-cloud" wx:if="{{kaoheData.bankuaiList.length > 0}}">
|
||||
<scroll-view class="plate-cloud-scroll" scroll-x="true" enhanced show-scrollbar="{{false}}">
|
||||
<view class="plate-chip" wx:for="{{kaoheData.bankuaiList}}" wx:key="bankuai_id">{{item.mingcheng}}</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 中央余额星球 -->
|
||||
<view class="balance-planet">
|
||||
<view class="planet-ring"></view>
|
||||
<view class="planet-body">
|
||||
<text class="planet-num">{{kaoheData.yue}}元</text>
|
||||
<text class="planet-label">可提现余额</text>
|
||||
</view>
|
||||
<view class="planet-glow"></view>
|
||||
</view>
|
||||
|
||||
<!-- 流星数据条 -->
|
||||
<view class="meteor-stats">
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.shenheZongshu}}</text>
|
||||
<text class="meteor-label">审核总数</text>
|
||||
</view>
|
||||
<view class="meteor-divider"></view>
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.tongguoZongshu}}</text>
|
||||
<text class="meteor-label">通过总数</text>
|
||||
</view>
|
||||
<view class="meteor-divider"></view>
|
||||
<view class="meteor-item">
|
||||
<text class="meteor-num">{{kaoheData.zonge}}元</text>
|
||||
<text class="meteor-label">累计赚取</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 十字星阵功能区 -->
|
||||
<view class="star-cross">
|
||||
<!-- 上方:考核中心 -->
|
||||
<view class="cross-item cross-top {{planetPaused.top ? 'pause-spin' : ''}}"
|
||||
bindtap="goToZhongxin"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="top">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.zhongxin}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核中心</text>
|
||||
</view>
|
||||
<!-- 下方:考核打分 -->
|
||||
<view class="cross-item cross-bottom {{planetPaused.bottom ? 'pause-spin' : ''}}"
|
||||
bindtap="goToDafen"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="bottom">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.daofen}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核打分</text>
|
||||
<!-- 🆕 添加红色角标,这是唯一新增的行 -->
|
||||
<view class="badge" wx:if="{{kaoheData.pendingShenheCount > 0}}">{{kaoheData.pendingShenheCount}}</view>
|
||||
</view>
|
||||
<!-- 左侧:考核记录 -->
|
||||
<view class="cross-item cross-left {{planetPaused.left ? 'pause-spin' : ''}}"
|
||||
bindtap="goToJilu"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="left">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.jilu}}" mode="aspectFit" />
|
||||
<text class="cross-text">考核记录</text>
|
||||
</view>
|
||||
<!-- 右侧:立即提现 -->
|
||||
<view class="cross-item cross-right {{planetPaused.right ? 'pause-spin' : ''}}"
|
||||
bindtap="goToWithdraw"
|
||||
bindtouchstart="onPlanetTouch" bindtouchend="onPlanetLeave" data-id="right">
|
||||
<view class="orbit-ring"></view>
|
||||
<image class="cross-icon" src="{{icons.tixian}}" mode="aspectFit" />
|
||||
<text class="cross-text">立即提现</text>
|
||||
</view>
|
||||
<!-- 中央五角星 -->
|
||||
<view class="pentagram"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载星门 -->
|
||||
<view class="loading-portal" wx:if="{{isLoading}}">
|
||||
<view class="portal-ring"></view>
|
||||
<text class="portal-text">加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
<custom-tab-bar />
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,452 +1,331 @@
|
||||
// pages/fenlei/fenlei.js
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
// 全局变量引用
|
||||
ossImageUrl: '',
|
||||
|
||||
// 搜索相关
|
||||
searchText: '',
|
||||
showSearchResult: false,
|
||||
searchResults: [],
|
||||
isSearching: false,
|
||||
|
||||
// 页面数据
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
|
||||
// 状态控制
|
||||
selectedLeixingId: null,
|
||||
selectedZhuanquId: null,
|
||||
filteredZhuanquList: [], // 当前类型下的专区列表
|
||||
filteredShangpinList: [], // 当前专区下的商品列表
|
||||
zhuanquByLeixing: {}, // 类型->专区映射对象
|
||||
shangpinByZhuanqu: {}, // 专区->商品映射对象
|
||||
zhuanquGoodsCount: {}, // 专区商品数量统计
|
||||
|
||||
// UI状态
|
||||
isLoading: false,
|
||||
hasInitialized: false
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 获取全局变量
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl
|
||||
})
|
||||
|
||||
// 初始化数据
|
||||
this.initPageData()
|
||||
},
|
||||
onShow() {
|
||||
// 原有代码...
|
||||
|
||||
// 🆕 注册通知组件
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
// 🆕 新增:注册通知组件
|
||||
registerNotificationComponent() {
|
||||
const app = getApp();
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
console.log('🏪 商城页面注册通知组件');
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化页面数据
|
||||
*/
|
||||
initPageData() {
|
||||
const that = this
|
||||
this.setData({ isLoading: true })
|
||||
|
||||
// 检查全局变量是否已有数据
|
||||
if (app.globalData.shangpinleixing && app.globalData.shangpinleixing.length > 0) {
|
||||
this.initFromGlobalData()
|
||||
} else {
|
||||
this.loadAllShangpinData()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 从全局变量初始化数据
|
||||
*/
|
||||
initFromGlobalData() {
|
||||
const leixingList = app.globalData.shangpinleixing || []
|
||||
const zhuanquList = app.globalData.shangpinzhuanqu || []
|
||||
const shangpinList = app.globalData.shangpinliebiao || []
|
||||
|
||||
// 构建映射关系对象
|
||||
const zhuanquByLeixing = {}
|
||||
const shangpinByZhuanqu = {}
|
||||
const zhuanquGoodsCount = {}
|
||||
|
||||
// 1. 构建专区映射 (按类型分组)
|
||||
zhuanquList.forEach(zhuanqu => {
|
||||
const leixingId = zhuanqu.leixing_id
|
||||
if (!zhuanquByLeixing[leixingId]) {
|
||||
zhuanquByLeixing[leixingId] = []
|
||||
}
|
||||
zhuanquByLeixing[leixingId].push(zhuanqu)
|
||||
})
|
||||
|
||||
// 2. 构建商品映射 (按专区分组)并统计数量
|
||||
shangpinList.forEach(shangpin => {
|
||||
const zhuanquId = shangpin.zhuanqu_id
|
||||
if (zhuanquId) {
|
||||
if (!shangpinByZhuanqu[zhuanquId]) {
|
||||
shangpinByZhuanqu[zhuanquId] = []
|
||||
zhuanquGoodsCount[zhuanquId] = 0
|
||||
}
|
||||
|
||||
// 处理价格显示
|
||||
const jiage = parseFloat(shangpin.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
|
||||
shangpinByZhuanqu[zhuanquId].push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: shangpin.tupian_url,
|
||||
duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0
|
||||
})
|
||||
|
||||
zhuanquGoodsCount[zhuanquId] += 1
|
||||
}
|
||||
})
|
||||
|
||||
// 设置初始选中状态(第一个类型和第一个专区)
|
||||
const firstLeixing = leixingList[0]
|
||||
let firstZhuanquId = null
|
||||
|
||||
if (firstLeixing && zhuanquByLeixing[firstLeixing.id]) {
|
||||
firstZhuanquId = zhuanquByLeixing[firstLeixing.id][0]?.id || null
|
||||
}
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: leixingList,
|
||||
shangpinzhuanqu: zhuanquList,
|
||||
shangpinliebiao: shangpinList,
|
||||
zhuanquByLeixing: zhuanquByLeixing,
|
||||
shangpinByZhuanqu: shangpinByZhuanqu,
|
||||
zhuanquGoodsCount: zhuanquGoodsCount,
|
||||
selectedLeixingId: firstLeixing?.id || null,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
// 筛选数据
|
||||
this.filterData()
|
||||
this.setData({ isLoading: false, hasInitialized: true })
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载所有商品数据
|
||||
*/
|
||||
loadAllShangpinData() {
|
||||
const that = this
|
||||
wx.request({
|
||||
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
success(res) {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const data = res.data
|
||||
|
||||
// 存储到全局变量
|
||||
app.globalData.shangpinleixing = data.shangpinleixing || []
|
||||
app.globalData.shangpinzhuanqu = data.shangpinzhuanqu || []
|
||||
app.globalData.shangpinliebiao = data.shangpinliebiao || []
|
||||
|
||||
// 从全局变量初始化
|
||||
that.initFromGlobalData()
|
||||
} else {
|
||||
that.handleLoadError()
|
||||
}
|
||||
},
|
||||
fail(error) {
|
||||
console.error('加载商品数据失败:', error)
|
||||
that.handleLoadError()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理加载错误
|
||||
*/
|
||||
handleLoadError() {
|
||||
wx.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({ isLoading: false })
|
||||
},
|
||||
|
||||
/**
|
||||
* 筛选数据
|
||||
*/
|
||||
filterData() {
|
||||
const { selectedLeixingId, selectedZhuanquId, zhuanquByLeixing, shangpinByZhuanqu } = this.data
|
||||
|
||||
// 1. 筛选专区列表
|
||||
const filteredZhuanquList = zhuanquByLeixing[selectedLeixingId] || []
|
||||
|
||||
// 2. 筛选商品列表
|
||||
let filteredShangpinList = []
|
||||
if (selectedZhuanquId) {
|
||||
filteredShangpinList = shangpinByZhuanqu[selectedZhuanquId] || []
|
||||
} else if (filteredZhuanquList.length > 0) {
|
||||
// 如果没有选中的专区,默认显示第一个专区的商品
|
||||
const firstZhuanquId = filteredZhuanquList[0].id
|
||||
filteredShangpinList = shangpinByZhuanqu[firstZhuanquId] || []
|
||||
this.setData({ selectedZhuanquId: firstZhuanquId })
|
||||
}
|
||||
|
||||
this.setData({
|
||||
filteredZhuanquList: filteredZhuanquList,
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择商品类型
|
||||
*/
|
||||
selectLeixing(e) {
|
||||
const leixingId = e.currentTarget.dataset.id
|
||||
|
||||
if (this.data.selectedLeixingId === leixingId) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取该类型下的第一个专区
|
||||
const zhuanquList = this.data.zhuanquByLeixing[leixingId] || []
|
||||
const firstZhuanquId = zhuanquList.length > 0 ? zhuanquList[0].id : null
|
||||
|
||||
this.setData({
|
||||
selectedLeixingId: leixingId,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
this.filterData()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择商品专区
|
||||
*/
|
||||
selectZhuanqu(e) {
|
||||
const zhuanquId = e.currentTarget.dataset.id
|
||||
|
||||
if (this.data.selectedZhuanquId === zhuanquId) {
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
selectedZhuanquId: zhuanquId
|
||||
}, () => {
|
||||
// 筛选商品列表
|
||||
const filteredShangpinList = this.data.shangpinByZhuanqu[zhuanquId] || []
|
||||
this.setData({
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 搜索框输入事件
|
||||
*/
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchText: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击搜索按钮
|
||||
*/
|
||||
onSearchTap() {
|
||||
const searchText = this.data.searchText.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 开始搜索
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
/**
|
||||
* 键盘搜索事件(回车键)
|
||||
*/
|
||||
onSearchConfirm(e) {
|
||||
const searchText = e.detail.value.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
searchText: searchText
|
||||
})
|
||||
|
||||
// 开始搜索
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行搜索
|
||||
*/
|
||||
startSearch(searchText) {
|
||||
this.setData({
|
||||
isSearching: true,
|
||||
showSearchResult: true
|
||||
})
|
||||
|
||||
// 本地搜索
|
||||
const allShangpin = this.data.shangpinliebiao
|
||||
const results = []
|
||||
|
||||
for (const item of allShangpin) {
|
||||
if (item.biaoqian && item.biaoqian.toLowerCase().includes(searchText.toLowerCase())) {
|
||||
// 处理价格显示
|
||||
const jiage = parseFloat(item.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
|
||||
results.push({
|
||||
id: item.id,
|
||||
biaoqian: item.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: item.tupian_url,
|
||||
leixing_name: this.getLeixingName(item.leixing_id),
|
||||
zhuanqu_name: this.getZhuanquName(item.zhuanqu_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
searchResults: results,
|
||||
isSearching: false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 清空搜索
|
||||
*/
|
||||
onClearSearch() {
|
||||
this.setData({
|
||||
searchText: '',
|
||||
showSearchResult: false,
|
||||
searchResults: []
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据类型ID获取类型名称
|
||||
*/
|
||||
getLeixingName(leixingId) {
|
||||
const leixingList = this.data.shangpinleixing
|
||||
for (const item of leixingList) {
|
||||
if (item.id === leixingId) {
|
||||
return item.jieshao
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据专区ID获取专区名称
|
||||
*/
|
||||
getZhuanquName(zhuanquId) {
|
||||
const zhuanquList = this.data.shangpinzhuanqu
|
||||
for (const item of zhuanquList) {
|
||||
if (item.id === zhuanquId) {
|
||||
return item.mingzi
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
/**
|
||||
* 跳转到商品详情页
|
||||
*/
|
||||
goToDetail(e) {
|
||||
const shangpinId = e.currentTarget.dataset.id
|
||||
if (!shangpinId) return
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/shangpinxiangqing/shangpinxiangqing?id=${shangpinId}`
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新所有数据
|
||||
*/
|
||||
onRefresh() {
|
||||
wx.showLoading({
|
||||
title: '刷新中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 清空全局变量
|
||||
app.globalData.shangpinleixing = []
|
||||
app.globalData.shangpinzhuanqu = []
|
||||
app.globalData.shangpinliebiao = []
|
||||
|
||||
this.loadAllShangpinData()
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '阿龙电竞 - 商品分类',
|
||||
path: '/pages/fenlei/fenlei'
|
||||
}
|
||||
}
|
||||
})
|
||||
// pages/category/category.js
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
ossImageUrl: '',
|
||||
searchText: '',
|
||||
showSearchResult: false,
|
||||
searchResults: [],
|
||||
isSearching: false,
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
selectedLeixingId: null,
|
||||
selectedZhuanquId: null,
|
||||
filteredZhuanquList: [],
|
||||
filteredShangpinList: [],
|
||||
zhuanquByLeixing: {},
|
||||
shangpinByZhuanqu: {},
|
||||
zhuanquGoodsCount: {},
|
||||
isLoading: false,
|
||||
hasInitialized: false
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl
|
||||
})
|
||||
this.initPageData()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const app = getApp();
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
initPageData() {
|
||||
const that = this
|
||||
this.setData({ isLoading: true })
|
||||
if (app.globalData.shangpinleixing && app.globalData.shangpinleixing.length > 0) {
|
||||
this.initFromGlobalData()
|
||||
} else {
|
||||
this.loadAllShangpinData()
|
||||
}
|
||||
},
|
||||
|
||||
initFromGlobalData() {
|
||||
const leixingList = app.globalData.shangpinleixing || []
|
||||
const zhuanquList = app.globalData.shangpinzhuanqu || []
|
||||
const shangpinList = app.globalData.shangpinliebiao || []
|
||||
|
||||
const zhuanquByLeixing = {}
|
||||
const shangpinByZhuanqu = {}
|
||||
const zhuanquGoodsCount = {}
|
||||
|
||||
zhuanquList.forEach(zhuanqu => {
|
||||
const leixingId = zhuanqu.leixing_id
|
||||
if (!zhuanquByLeixing[leixingId]) {
|
||||
zhuanquByLeixing[leixingId] = []
|
||||
}
|
||||
zhuanquByLeixing[leixingId].push(zhuanqu)
|
||||
})
|
||||
|
||||
shangpinList.forEach(shangpin => {
|
||||
const zhuanquId = shangpin.zhuanqu_id
|
||||
if (zhuanquId) {
|
||||
if (!shangpinByZhuanqu[zhuanquId]) {
|
||||
shangpinByZhuanqu[zhuanquId] = []
|
||||
zhuanquGoodsCount[zhuanquId] = 0
|
||||
}
|
||||
const jiage = parseFloat(shangpin.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
shangpinByZhuanqu[zhuanquId].push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: shangpin.tupian_url,
|
||||
duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0
|
||||
})
|
||||
zhuanquGoodsCount[zhuanquId] += 1
|
||||
}
|
||||
})
|
||||
|
||||
const firstLeixing = leixingList[0]
|
||||
let firstZhuanquId = null
|
||||
if (firstLeixing && zhuanquByLeixing[firstLeixing.id]) {
|
||||
firstZhuanquId = zhuanquByLeixing[firstLeixing.id][0]?.id || null
|
||||
}
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: leixingList,
|
||||
shangpinzhuanqu: zhuanquList,
|
||||
shangpinliebiao: shangpinList,
|
||||
zhuanquByLeixing: zhuanquByLeixing,
|
||||
shangpinByZhuanqu: shangpinByZhuanqu,
|
||||
zhuanquGoodsCount: zhuanquGoodsCount,
|
||||
selectedLeixingId: firstLeixing?.id || null,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
this.filterData()
|
||||
this.setData({ isLoading: false, hasInitialized: true })
|
||||
})
|
||||
},
|
||||
|
||||
loadAllShangpinData() {
|
||||
const that = this
|
||||
wx.request({
|
||||
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
success(res) {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const data = res.data
|
||||
app.globalData.shangpinleixing = data.shangpinleixing || []
|
||||
app.globalData.shangpinzhuanqu = data.shangpinzhuanqu || []
|
||||
app.globalData.shangpinliebiao = data.shangpinliebiao || []
|
||||
that.initFromGlobalData()
|
||||
} else {
|
||||
that.handleLoadError()
|
||||
}
|
||||
},
|
||||
fail(error) {
|
||||
console.error('加载商品数据失败:', error)
|
||||
that.handleLoadError()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleLoadError() {
|
||||
wx.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({ isLoading: false })
|
||||
},
|
||||
|
||||
filterData() {
|
||||
const { selectedLeixingId, selectedZhuanquId, zhuanquByLeixing, shangpinByZhuanqu } = this.data
|
||||
const filteredZhuanquList = zhuanquByLeixing[selectedLeixingId] || []
|
||||
let filteredShangpinList = []
|
||||
if (selectedZhuanquId) {
|
||||
filteredShangpinList = shangpinByZhuanqu[selectedZhuanquId] || []
|
||||
} else if (filteredZhuanquList.length > 0) {
|
||||
const firstZhuanquId = filteredZhuanquList[0].id
|
||||
filteredShangpinList = shangpinByZhuanqu[firstZhuanquId] || []
|
||||
this.setData({ selectedZhuanquId: firstZhuanquId })
|
||||
}
|
||||
this.setData({
|
||||
filteredZhuanquList: filteredZhuanquList,
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const leixingId = e.currentTarget.dataset.id
|
||||
if (this.data.selectedLeixingId === leixingId) {
|
||||
return
|
||||
}
|
||||
const zhuanquList = this.data.zhuanquByLeixing[leixingId] || []
|
||||
const firstZhuanquId = zhuanquList.length > 0 ? zhuanquList[0].id : null
|
||||
this.setData({
|
||||
selectedLeixingId: leixingId,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
this.filterData()
|
||||
})
|
||||
},
|
||||
|
||||
selectZhuanqu(e) {
|
||||
const zhuanquId = e.currentTarget.dataset.id
|
||||
if (this.data.selectedZhuanquId === zhuanquId) {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
selectedZhuanquId: zhuanquId
|
||||
}, () => {
|
||||
const filteredShangpinList = this.data.shangpinByZhuanqu[zhuanquId] || []
|
||||
this.setData({
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchText: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
onSearchTap() {
|
||||
const searchText = this.data.searchText.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
onSearchConfirm(e) {
|
||||
const searchText = e.detail.value.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
searchText: searchText
|
||||
})
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
startSearch(searchText) {
|
||||
this.setData({
|
||||
isSearching: true,
|
||||
showSearchResult: true
|
||||
})
|
||||
const allShangpin = this.data.shangpinliebiao
|
||||
const results = []
|
||||
for (const item of allShangpin) {
|
||||
if (item.biaoqian && item.biaoqian.toLowerCase().includes(searchText.toLowerCase())) {
|
||||
const jiage = parseFloat(item.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
results.push({
|
||||
id: item.id,
|
||||
biaoqian: item.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: item.tupian_url,
|
||||
leixing_name: this.getLeixingName(item.leixing_id),
|
||||
zhuanqu_name: this.getZhuanquName(item.zhuanqu_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
searchResults: results,
|
||||
isSearching: false
|
||||
})
|
||||
},
|
||||
|
||||
onClearSearch() {
|
||||
this.setData({
|
||||
searchText: '',
|
||||
showSearchResult: false,
|
||||
searchResults: []
|
||||
})
|
||||
},
|
||||
|
||||
getLeixingName(leixingId) {
|
||||
const leixingList = this.data.shangpinleixing
|
||||
for (const item of leixingList) {
|
||||
if (item.id === leixingId) {
|
||||
return item.jieshao
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
getZhuanquName(zhuanquId) {
|
||||
const zhuanquList = this.data.shangpinzhuanqu
|
||||
for (const item of zhuanquList) {
|
||||
if (item.id === zhuanquId) {
|
||||
return item.mingzi
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
goToDetail(e) {
|
||||
const shangpinId = e.currentTarget.dataset.id
|
||||
if (!shangpinId) return
|
||||
wx.navigateTo({
|
||||
url: `/pages/product-detail/product-detail?id=${shangpinId}`
|
||||
})
|
||||
},
|
||||
|
||||
onRefresh() {
|
||||
wx.showLoading({
|
||||
title: '刷新中...',
|
||||
mask: true
|
||||
})
|
||||
app.globalData.shangpinleixing = []
|
||||
app.globalData.shangpinzhuanqu = []
|
||||
app.globalData.shangpinliebiao = []
|
||||
this.loadAllShangpinData()
|
||||
setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '阿龙电竞 - 商品分类',
|
||||
path: '/pages/category/category'
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,217 +1,217 @@
|
||||
<!-- pages/fenlei/fenlei.wxml -->
|
||||
<view class="fenlei-page">
|
||||
<!-- 1. 毛玻璃搜索框区域(固定) -->
|
||||
<view class="search-container">
|
||||
<view class="search-box">
|
||||
<image src="/images/sousuo.png" class="search-icon" />
|
||||
<input
|
||||
type="text"
|
||||
class="search-input"
|
||||
placeholder="输入商品名称搜索"
|
||||
placeholder-class="search-placeholder"
|
||||
value="{{searchText}}"
|
||||
bindinput="onSearchInput"
|
||||
bindconfirm="onSearchConfirm"
|
||||
confirm-type="search"
|
||||
/>
|
||||
<!-- 清空按钮 -->
|
||||
<view wx:if="{{searchText}}" class="search-clear" bindtap="onClearSearch">
|
||||
<image src="/images/clear.png" class="clear-icon" />
|
||||
</view>
|
||||
<!-- 搜索按钮 -->
|
||||
<view class="search-btn" bindtap="onSearchTap">
|
||||
<text class="search-btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 2. 商品类型选择区域 -->
|
||||
<view class="leixing-container" wx:if="{{!showSearchResult}}">
|
||||
<scroll-view
|
||||
class="leixing-scroll"
|
||||
scroll-x
|
||||
scroll-with-animation
|
||||
show-scrollbar="{{false}}"
|
||||
>
|
||||
<view class="leixing-list">
|
||||
<block wx:for="{{shangpinleixing}}" wx:key="id" wx:for-index="idx">
|
||||
<view
|
||||
class="leixing-item {{selectedLeixingId === item.id ? 'leixing-active' : ''}}"
|
||||
bindtap="selectLeixing"
|
||||
data-id="{{item.id}}"
|
||||
data-index="{{idx}}"
|
||||
>
|
||||
<view class="leixing-image-box">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="leixing-image"
|
||||
/>
|
||||
<view class="leixing-glow {{selectedLeixingId === item.id ? 'leixing-glow-active' : ''}}"></view>
|
||||
</view>
|
||||
<text class="leixing-text">{{item.jieshao}}</text>
|
||||
<view class="leixing-active-bar {{selectedLeixingId === item.id ? 'leixing-active-bar-show' : ''}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 3. 左右分栏布局 -->
|
||||
<view class="main-container" wx:if="{{!showSearchResult}}">
|
||||
<!-- 左边:商品专区列表 -->
|
||||
<scroll-view
|
||||
class="zhuanqu-left"
|
||||
scroll-y
|
||||
enhanced="{{true}}"
|
||||
show-scrollbar="{{false}}"
|
||||
scroll-into-view="{{'zhuanqu-' + selectedZhuanquId}}"
|
||||
>
|
||||
<view class="zhuanqu-list">
|
||||
<block wx:for="{{filteredZhuanquList}}" wx:key="id">
|
||||
<view
|
||||
id="zhuanqu-{{item.id}}"
|
||||
class="zhuanqu-item {{selectedZhuanquId === item.id ? 'zhuanqu-active' : ''}}"
|
||||
bindtap="selectZhuanqu"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="zhuanqu-item-content">
|
||||
<text class="zhuanqu-name">{{item.mingzi}}</text>
|
||||
<text class="zhuanqu-count">({{zhuanquGoodsCount[item.id] || 0}})</text>
|
||||
</view>
|
||||
<view class="zhuanqu-active-indicator {{selectedZhuanquId === item.id ? 'zhuanqu-indicator-glow' : ''}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{filteredZhuanquList.length === 0}}" class="zhuanqu-empty">
|
||||
<image src="/images/empty-box.png" class="zhuanqu-empty-icon" />
|
||||
<text class="zhuanqu-empty-text">暂无专区</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 右边:商品列表 -->
|
||||
<scroll-view
|
||||
class="shangpin-right"
|
||||
scroll-y
|
||||
enhanced="{{true}}"
|
||||
show-scrollbar="{{false}}"
|
||||
>
|
||||
<view class="shangpin-list">
|
||||
<block wx:for="{{filteredShangpinList}}" wx:key="id">
|
||||
<view
|
||||
class="shangpin-item"
|
||||
bindtap="goToDetail"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="shangpin-image-box">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="shangpin-image"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="shangpin-info">
|
||||
<view class="shangpin-title">
|
||||
<text class="shangpin-title-text">{{item.biaoqian}}</text>
|
||||
</view>
|
||||
|
||||
<view class="shangpin-footer">
|
||||
<view class="shangpin-price">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{item.priceInteger}}</text>
|
||||
<text class="price-decimal">.{{item.priceDecimal}}</text>
|
||||
</view>
|
||||
<view class="detail-btn">
|
||||
<text class="detail-btn-text">了解详情</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="item-divider" wx:if="{{index !== filteredShangpinList.length - 1}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{filteredShangpinList.length === 0 && !isLoading}}" class="shangpin-empty">
|
||||
<image src="/images/empty-goods.png" class="shangpin-empty-icon" />
|
||||
<text class="shangpin-empty-text">该专区暂无商品</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="load-more" wx:if="{{filteredShangpinList.length > 0}}">
|
||||
<text class="load-more-text">— 已加载全部商品 —</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果弹窗 -->
|
||||
<view class="search-results-container" wx:if="{{showSearchResult}}">
|
||||
<view class="search-mask" bindtap="onClearSearch"></view>
|
||||
<view class="search-results-content">
|
||||
<view class="search-results-header">
|
||||
<view class="search-header-left">
|
||||
<text class="search-results-title">搜索结果</text>
|
||||
<text class="search-results-count">({{searchResults.length}}个)</text>
|
||||
</view>
|
||||
<view class="search-close" bindtap="onClearSearch">
|
||||
<image src="/images/close.png" class="close-icon" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="search-results-list" scroll-y>
|
||||
<block wx:for="{{searchResults}}" wx:key="id">
|
||||
<view class="search-result-item" bindtap="goToDetail" data-id="{{item.id}}">
|
||||
<view class="search-result-left">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="search-result-image"
|
||||
/>
|
||||
</view>
|
||||
<view class="search-result-right">
|
||||
<view class="search-result-title">{{item.biaoqian}}</view>
|
||||
<view class="search-result-info">
|
||||
<text class="search-result-category">{{item.leixing_name}}</text>
|
||||
<text class="search-result-separator">·</text>
|
||||
<text class="search-result-zhuanqu">{{item.zhuanqu_name}}</text>
|
||||
</view>
|
||||
<view class="search-result-price">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{item.priceInteger}}</text>
|
||||
<text class="price-decimal">.{{item.priceDecimal}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{searchResults.length === 0 && !isSearching}}" class="search-empty">
|
||||
<image src="/images/search-empty.png" class="search-empty-icon" />
|
||||
<text class="search-empty-text">未找到相关商品</text>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{isSearching}}" class="search-loading">
|
||||
<view class="search-spinner">
|
||||
<view class="spinner-circle"></view>
|
||||
</view>
|
||||
<text class="search-loading-text">搜索中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 全局加载状态 -->
|
||||
<view class="loading-toast" wx:if="{{isLoading}}">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner">
|
||||
<view class="spinner-ring"></view>
|
||||
<view class="spinner-dot"></view>
|
||||
</view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部自定义TabBar -->
|
||||
<custom-tab-bar />
|
||||
<!-- pages/category/category.wxml -->
|
||||
<view class="fenlei-page">
|
||||
<!-- 1. 毛玻璃搜索框区域(固定) -->
|
||||
<view class="search-container">
|
||||
<view class="search-box search-box--glass">
|
||||
<image src="/images/sousuo.png" class="search-icon" />
|
||||
<input
|
||||
type="text"
|
||||
class="search-input"
|
||||
placeholder="输入商品名称搜索"
|
||||
placeholder-class="search-placeholder"
|
||||
value="{{searchText}}"
|
||||
bindinput="onSearchInput"
|
||||
bindconfirm="onSearchConfirm"
|
||||
confirm-type="search"
|
||||
/>
|
||||
<!-- 清空按钮 -->
|
||||
<view wx:if="{{searchText}}" class="search-clear" bindtap="onClearSearch">
|
||||
<image src="/images/clear.png" class="clear-icon" />
|
||||
</view>
|
||||
<!-- 搜索按钮 -->
|
||||
<view class="search-btn btn btn-sm btn-sm--gold" bindtap="onSearchTap">
|
||||
<text class="search-btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 2. 商品类型选择区域 -->
|
||||
<view class="leixing-container" wx:if="{{!showSearchResult}}">
|
||||
<scroll-view
|
||||
class="leixing-scroll"
|
||||
scroll-x
|
||||
scroll-with-animation
|
||||
show-scrollbar="{{false}}"
|
||||
>
|
||||
<view class="leixing-list">
|
||||
<block wx:for="{{shangpinleixing}}" wx:key="id" wx:for-index="idx">
|
||||
<view
|
||||
class="leixing-item {{selectedLeixingId === item.id ? 'leixing-active' : ''}}"
|
||||
bindtap="selectLeixing"
|
||||
data-id="{{item.id}}"
|
||||
data-index="{{idx}}"
|
||||
>
|
||||
<view class="leixing-image-box">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="leixing-image"
|
||||
/>
|
||||
<view class="leixing-glow {{selectedLeixingId === item.id ? 'leixing-glow-active' : ''}}"></view>
|
||||
</view>
|
||||
<text class="leixing-text">{{item.jieshao}}</text>
|
||||
<view class="leixing-active-bar {{selectedLeixingId === item.id ? 'leixing-active-bar-show' : ''}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 3. 左右分栏布局 -->
|
||||
<view class="main-container" wx:if="{{!showSearchResult}}">
|
||||
<!-- 左边:商品专区列表 -->
|
||||
<scroll-view
|
||||
class="zhuanqu-left"
|
||||
scroll-y
|
||||
enhanced="{{true}}"
|
||||
show-scrollbar="{{false}}"
|
||||
scroll-into-view="{{'zhuanqu-' + selectedZhuanquId}}"
|
||||
>
|
||||
<view class="zhuanqu-list">
|
||||
<block wx:for="{{filteredZhuanquList}}" wx:key="id">
|
||||
<view
|
||||
id="zhuanqu-{{item.id}}"
|
||||
class="zhuanqu-item {{selectedZhuanquId === item.id ? 'zhuanqu-active' : ''}}"
|
||||
bindtap="selectZhuanqu"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="zhuanqu-item-content">
|
||||
<text class="zhuanqu-name">{{item.mingzi}}</text>
|
||||
<text class="zhuanqu-count">({{zhuanquGoodsCount[item.id] || 0}})</text>
|
||||
</view>
|
||||
<view class="zhuanqu-active-indicator {{selectedZhuanquId === item.id ? 'zhuanqu-indicator-glow' : ''}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{filteredZhuanquList.length === 0}}" class="zhuanqu-empty">
|
||||
<image src="/images/empty-box.png" class="zhuanqu-empty-icon" />
|
||||
<text class="zhuanqu-empty-text">暂无专区</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 右边:商品列表 -->
|
||||
<scroll-view
|
||||
class="shangpin-right"
|
||||
scroll-y
|
||||
enhanced="{{true}}"
|
||||
show-scrollbar="{{false}}"
|
||||
>
|
||||
<view class="shangpin-list">
|
||||
<block wx:for="{{filteredShangpinList}}" wx:key="id">
|
||||
<view
|
||||
class="shangpin-item"
|
||||
bindtap="goToDetail"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="shangpin-image-box">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="shangpin-image"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="shangpin-info">
|
||||
<view class="shangpin-title">
|
||||
<text class="shangpin-title-text">{{item.biaoqian}}</text>
|
||||
</view>
|
||||
|
||||
<view class="shangpin-footer">
|
||||
<view class="shangpin-price">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{item.priceInteger}}</text>
|
||||
<text class="price-decimal">.{{item.priceDecimal}}</text>
|
||||
</view>
|
||||
<view class="detail-btn">
|
||||
<text class="detail-btn-text">了解详情</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="item-divider" wx:if="{{index !== filteredShangpinList.length - 1}}"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{filteredShangpinList.length === 0 && !isLoading}}" class="shangpin-empty">
|
||||
<image src="/images/empty-goods.png" class="shangpin-empty-icon" />
|
||||
<text class="shangpin-empty-text">该专区暂无商品</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="load-more" wx:if="{{filteredShangpinList.length > 0}}">
|
||||
<text class="load-more-text">— 已加载全部商品 —</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果弹窗 -->
|
||||
<view class="search-results-container" wx:if="{{showSearchResult}}">
|
||||
<view class="search-mask" bindtap="onClearSearch"></view>
|
||||
<view class="search-results-content">
|
||||
<view class="search-results-header">
|
||||
<view class="search-header-left">
|
||||
<text class="search-results-title">搜索结果</text>
|
||||
<text class="search-results-count">({{searchResults.length}}个)</text>
|
||||
</view>
|
||||
<view class="search-close" bindtap="onClearSearch">
|
||||
<image src="/images/close.png" class="close-icon" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="search-results-list" scroll-y>
|
||||
<block wx:for="{{searchResults}}" wx:key="id">
|
||||
<view class="search-result-item" bindtap="goToDetail" data-id="{{item.id}}">
|
||||
<view class="search-result-left">
|
||||
<image
|
||||
src="{{ossImageUrl}}{{item.tupian_url}}"
|
||||
mode="aspectFill"
|
||||
class="search-result-image"
|
||||
/>
|
||||
</view>
|
||||
<view class="search-result-right">
|
||||
<view class="search-result-title">{{item.biaoqian}}</view>
|
||||
<view class="search-result-info">
|
||||
<text class="search-result-category">{{item.leixing_name}}</text>
|
||||
<text class="search-result-separator">·</text>
|
||||
<text class="search-result-zhuanqu">{{item.zhuanqu_name}}</text>
|
||||
</view>
|
||||
<view class="search-result-price">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{item.priceInteger}}</text>
|
||||
<text class="price-decimal">.{{item.priceDecimal}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view wx:if="{{searchResults.length === 0 && !isSearching}}" class="search-empty">
|
||||
<image src="/images/search-empty.png" class="search-empty-icon" />
|
||||
<text class="search-empty-text">未找到相关商品</text>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{isSearching}}" class="search-loading">
|
||||
<view class="search-spinner">
|
||||
<view class="spinner-circle"></view>
|
||||
</view>
|
||||
<text class="search-loading-text">搜索中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 全局加载状态 -->
|
||||
<view class="loading-toast loading-mask loading-mask--dark" wx:if="{{isLoading}}">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner">
|
||||
<view class="spinner-ring"></view>
|
||||
<view class="spinner-dot"></view>
|
||||
</view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部自定义TabBar -->
|
||||
<custom-tab-bar />
|
||||
<global-notification id="global-notification" />
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"fakuan-pay": "/pages/cfss/components/fakuan-pay/fakuan-pay"
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,8 @@ Page({
|
||||
teamName = p.teamName || '客服';
|
||||
teamAvatar = p.teamAvatar || '';
|
||||
} catch (e) {
|
||||
console.error('解析客服页面参数失败', e);
|
||||
}
|
||||
}
|
||||
// 默认头像使用全局配置
|
||||
if (!teamAvatar) {
|
||||
teamAvatar = app.globalData.ossImageUrl + app.globalData.morentouxiang;
|
||||
}
|
||||
@@ -171,7 +169,7 @@ Page({
|
||||
this.setData({ messages: msgs });
|
||||
},
|
||||
|
||||
// ---------- 历史消息 + 永久欢迎语 ----------
|
||||
// 历史消息
|
||||
loadHistory(refresh) {
|
||||
if (!refresh && !this.data.hasMore) return Promise.resolve();
|
||||
return new Promise((resolve) => {
|
||||
@@ -209,7 +207,7 @@ Page({
|
||||
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();
|
||||
@@ -249,7 +247,7 @@ Page({
|
||||
};
|
||||
},
|
||||
|
||||
// ---------- 接收新客服消息 ----------
|
||||
// 接收新客服消息
|
||||
listenNewMsg() {
|
||||
if (this._msgHandler) wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CS_MESSAGE_RECEIVED, this._msgHandler);
|
||||
this._msgHandler = (msg) => {
|
||||
@@ -310,7 +308,7 @@ Page({
|
||||
wx.goEasy.im.on(wx.GoEasy.IM_EVENT.MESSAGE_DELETED, this._deleteHandler);
|
||||
},
|
||||
|
||||
// ---------- 面板控制 ----------
|
||||
// 面板控制
|
||||
togglePlusPanel() { this.setData({ showPlusPanel: !this.data.showPlusPanel, showEmojiPanel: false }); },
|
||||
closePlusPanel() { this.setData({ showPlusPanel: false }); },
|
||||
openEmojiFromPlus() { this.setData({ showPlusPanel: false, showEmojiPanel: true }); },
|
||||
@@ -318,7 +316,7 @@ Page({
|
||||
insertEmoji(e) { this.setData({ inputText: this.data.inputText + e.currentTarget.dataset.emoji }); },
|
||||
closeEmojiPanel() { this.setData({ showEmojiPanel: false }); },
|
||||
|
||||
// ---------- 发送消息 ----------
|
||||
// 发送消息
|
||||
onInput(e) { this.setData({ inputText: e.detail.value }); },
|
||||
chooseImage() {
|
||||
const that = this;
|
||||
@@ -409,7 +407,7 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
// ---------- 订单发送 ----------
|
||||
// 订单发送
|
||||
openOrderSender() { this.setData({ showOrderSender: true, showPlusPanel: false }); },
|
||||
closeOrderSender() { this.setData({ showOrderSender: false }); },
|
||||
onSendOrder(e) {
|
||||
@@ -445,7 +443,7 @@ Page({
|
||||
updateMsg(id, status) { this.setData({ messages: this.data.messages.map(m => m.messageId === id ? { ...m, status } : m) }); },
|
||||
needShow(ts) { const ms = this.data.messages; if (!ms.length) return true; const last = ms[ms.length-1]; return (ts - last.timestamp) / 60000 > 5; },
|
||||
|
||||
// ---------- 消息操作 ----------
|
||||
// 消息操作
|
||||
onBubbleTap(e) {
|
||||
const msgId = e.currentTarget.dataset.messageid;
|
||||
const text = e.currentTarget.dataset.text;
|
||||
@@ -1,228 +1,227 @@
|
||||
// pages/xiugai/xiugai.js
|
||||
const app = getApp()
|
||||
import upload from '../../utils/upload.js'
|
||||
|
||||
Page({
|
||||
data: {
|
||||
avatarUrl: '',
|
||||
uid: '',
|
||||
nicheng: '',
|
||||
phone: '',
|
||||
originalAvatar: '',
|
||||
originalNicheng: '',
|
||||
isSaving: false,
|
||||
hasChanges: false,
|
||||
newAvatarFile: null,
|
||||
isLoading: true,
|
||||
isAvatarActive: false,
|
||||
nicknameError: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '编辑资料' })
|
||||
this.loadUserData()
|
||||
},
|
||||
|
||||
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() {
|
||||
try {
|
||||
const uid = wx.getStorageSync('uid') || ''
|
||||
const nicheng = wx.getStorageSync('nicheng') || ''
|
||||
const phone = wx.getStorageSync('phone') || ''
|
||||
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({
|
||||
avatarUrl,
|
||||
uid,
|
||||
nicheng,
|
||||
phone, // 仅展示
|
||||
originalAvatar: touxiang,
|
||||
originalNicheng: nicheng,
|
||||
isLoading: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('加载用户数据失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: '加载数据失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 微信头像选择(未改动)
|
||||
onChooseAvatar(e) {
|
||||
const avatarTempPath = e.detail.avatarUrl
|
||||
this.setData({
|
||||
avatarUrl: avatarTempPath,
|
||||
newAvatarFile: avatarTempPath
|
||||
}, () => {
|
||||
this.checkChanges()
|
||||
})
|
||||
},
|
||||
|
||||
chooseAvatar() {
|
||||
// 仅保留动画效果(透明按钮已触发 onChooseAvatar)
|
||||
this.setData({ isAvatarActive: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ isAvatarActive: false })
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 昵称输入(未改动)
|
||||
onNicknameInput(e) {
|
||||
const value = e.detail.value.trim()
|
||||
this.setData({
|
||||
nicheng: value,
|
||||
nicknameError: ''
|
||||
}, () => {
|
||||
this.checkChanges()
|
||||
})
|
||||
},
|
||||
|
||||
// 检查变化(只比较昵称和头像)
|
||||
checkChanges() {
|
||||
const { originalNicheng, nicheng, newAvatarFile } = this.data;
|
||||
const hasChanges = (nicheng !== originalNicheng) || (newAvatarFile !== null);
|
||||
this.setData({ hasChanges });
|
||||
},
|
||||
|
||||
// 保存(不包含手机号逻辑)
|
||||
async onSave() {
|
||||
if (!this.data.hasChanges) {
|
||||
wx.showToast({ title: '没有需要保存的更改', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (this.data.isSaving) return;
|
||||
|
||||
// 验证数据(昵称)
|
||||
if (!this.validateData()) return;
|
||||
|
||||
this.setData({ isSaving: true });
|
||||
wx.showLoading({ title: '保存中...', mask: true });
|
||||
|
||||
try {
|
||||
const formData = {};
|
||||
if (this.data.nicheng !== this.data.originalNicheng) {
|
||||
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 {
|
||||
throw new Error('网络错误');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
if (error.message.includes('认证失败') || error.message.includes('401')) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '登录已过期,请重新登录',
|
||||
complete: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.removeStorageSync('token');
|
||||
wx.removeStorageSync('userInfo');
|
||||
wx.switchTab({ url: '/pages/wode/wode' });
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.showToast({ title: error.message || '保存失败', icon: 'none' });
|
||||
}
|
||||
} finally {
|
||||
wx.hideLoading();
|
||||
this.setData({ isSaving: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 验证数据(只验证昵称)
|
||||
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 handleUpdateSuccess(updateData) {
|
||||
if (updateData.touxiang !== undefined && updateData.touxiang !== null) {
|
||||
wx.setStorageSync('touxiang', updateData.touxiang);
|
||||
}
|
||||
if (updateData.nicheng !== undefined && updateData.nicheng !== null) {
|
||||
wx.setStorageSync('nicheng', updateData.nicheng);
|
||||
}
|
||||
|
||||
if (updateData.nicheng) {
|
||||
app.globalData.userNicheng = updateData.nicheng;
|
||||
}
|
||||
|
||||
const ossImageUrl = app.globalData.ossImageUrl || '';
|
||||
let avatarUrl = this.data.avatarUrl;
|
||||
if (updateData.touxiang) {
|
||||
avatarUrl = updateData.touxiang.startsWith('http') ?
|
||||
updateData.touxiang : `${ossImageUrl}${updateData.touxiang}`;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
avatarUrl,
|
||||
originalAvatar: updateData.touxiang || this.data.originalAvatar,
|
||||
originalNicheng: updateData.nicheng || this.data.originalNicheng,
|
||||
newAvatarFile: null,
|
||||
hasChanges: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
// pages/edit/edit.js
|
||||
const app = getApp()
|
||||
import upload from '../../utils/upload.js'
|
||||
|
||||
Page({
|
||||
data: {
|
||||
avatarUrl: '',
|
||||
uid: '',
|
||||
nicheng: '',
|
||||
phone: '',
|
||||
originalAvatar: '',
|
||||
originalNicheng: '',
|
||||
isSaving: false,
|
||||
hasChanges: false,
|
||||
newAvatarFile: null,
|
||||
isLoading: true,
|
||||
isAvatarActive: false,
|
||||
nicknameError: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '编辑资料' })
|
||||
this.loadUserData()
|
||||
},
|
||||
|
||||
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() {
|
||||
try {
|
||||
const uid = wx.getStorageSync('uid') || ''
|
||||
const nicheng = wx.getStorageSync('nicheng') || ''
|
||||
const phone = wx.getStorageSync('phone') || ''
|
||||
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({
|
||||
avatarUrl,
|
||||
uid,
|
||||
nicheng,
|
||||
phone,
|
||||
originalAvatar: touxiang,
|
||||
originalNicheng: nicheng,
|
||||
isLoading: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('加载用户数据失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: '加载数据失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 微信头像选择
|
||||
onChooseAvatar(e) {
|
||||
const avatarTempPath = e.detail.avatarUrl
|
||||
this.setData({
|
||||
avatarUrl: avatarTempPath,
|
||||
newAvatarFile: avatarTempPath
|
||||
}, () => {
|
||||
this.checkChanges()
|
||||
})
|
||||
},
|
||||
|
||||
chooseAvatar() {
|
||||
this.setData({ isAvatarActive: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ isAvatarActive: false })
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 昵称输入
|
||||
onNicknameInput(e) {
|
||||
const value = e.detail.value.trim()
|
||||
this.setData({
|
||||
nicheng: value,
|
||||
nicknameError: ''
|
||||
}, () => {
|
||||
this.checkChanges()
|
||||
})
|
||||
},
|
||||
|
||||
// 检查变化
|
||||
checkChanges() {
|
||||
const { originalNicheng, nicheng, newAvatarFile } = this.data;
|
||||
const hasChanges = (nicheng !== originalNicheng) || (newAvatarFile !== null);
|
||||
this.setData({ hasChanges });
|
||||
},
|
||||
|
||||
// 保存
|
||||
async onSave() {
|
||||
if (!this.data.hasChanges) {
|
||||
wx.showToast({ title: '没有需要保存的更改', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (this.data.isSaving) return;
|
||||
|
||||
// 验证数据
|
||||
if (!this.validateData()) return;
|
||||
|
||||
this.setData({ isSaving: true });
|
||||
wx.showLoading({ title: '保存中...', mask: true });
|
||||
|
||||
try {
|
||||
const formData = {};
|
||||
if (this.data.nicheng !== this.data.originalNicheng) {
|
||||
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 {
|
||||
throw new Error('网络错误');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
if (error.message.includes('认证失败') || error.message.includes('401')) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '登录已过期,请重新登录',
|
||||
complete: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.removeStorageSync('token');
|
||||
wx.removeStorageSync('userInfo');
|
||||
wx.switchTab({ url: '/pages/mine/mine' });
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.showToast({ title: error.message || '保存失败', icon: 'none' });
|
||||
}
|
||||
} finally {
|
||||
wx.hideLoading();
|
||||
this.setData({ isSaving: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 验证数据
|
||||
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 handleUpdateSuccess(updateData) {
|
||||
if (updateData.touxiang !== undefined && updateData.touxiang !== null) {
|
||||
wx.setStorageSync('touxiang', updateData.touxiang);
|
||||
}
|
||||
if (updateData.nicheng !== undefined && updateData.nicheng !== null) {
|
||||
wx.setStorageSync('nicheng', updateData.nicheng);
|
||||
}
|
||||
|
||||
if (updateData.nicheng) {
|
||||
app.globalData.userNicheng = updateData.nicheng;
|
||||
}
|
||||
|
||||
const ossImageUrl = app.globalData.ossImageUrl || '';
|
||||
let avatarUrl = this.data.avatarUrl;
|
||||
if (updateData.touxiang) {
|
||||
avatarUrl = updateData.touxiang.startsWith('http') ?
|
||||
updateData.touxiang : `${ossImageUrl}${updateData.touxiang}`;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
avatarUrl,
|
||||
originalAvatar: updateData.touxiang || this.data.originalAvatar,
|
||||
originalNicheng: updateData.nicheng || this.data.originalNicheng,
|
||||
newAvatarFile: null,
|
||||
hasChanges: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,69 +1,69 @@
|
||||
<!-- pages/xiugai/xiugai.wxml -->
|
||||
<view class="xiugai-page">
|
||||
|
||||
<!-- 头像区域(未改动) -->
|
||||
<view class="avatar-section">
|
||||
<view class="avatar-container {{isAvatarActive ? 'active' : ''}}">
|
||||
<!-- 新增:头像包装器,把头像+光晕包在一起,和提示文字隔离 -->
|
||||
<view class="avatar-image-wrapper">
|
||||
<image class="avatar-image" src="{{avatarUrl}}" mode="aspectFill"></image>
|
||||
<view class="avatar-halo"></view>
|
||||
</view>
|
||||
<view class="avatar-hint">点击更换头像</view>
|
||||
</view>
|
||||
<button
|
||||
class="avatar-trigger-button"
|
||||
open-type="chooseAvatar"
|
||||
bindchooseavatar="onChooseAvatar"
|
||||
hover-class="none"
|
||||
></button>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section">
|
||||
<!-- UID(只读) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">UID</view>
|
||||
<view class="item-value readonly">{{uid || '••••••'}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 昵称(可编辑) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">昵称</view>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="item-input {{nicknameError ? 'error' : ''}}"
|
||||
type="text"
|
||||
placeholder="请输入昵称"
|
||||
placeholder-class="placeholder"
|
||||
maxlength="20"
|
||||
value="{{nicheng}}"
|
||||
bindinput="onNicknameInput"
|
||||
/>
|
||||
<view class="error-hint" wx:if="{{nicknameError}}">{{nicknameError}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号(只读展示,不可修改) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">手机号</view>
|
||||
<view class="item-value readonly">{{phone || '未绑定'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮(未改动) -->
|
||||
<button
|
||||
class="save-btn"
|
||||
bindtap="onSave"
|
||||
hover-class="btn-hover"
|
||||
disabled="{{isSaving || !hasChanges}}"
|
||||
>
|
||||
<view class="btn-content">
|
||||
{{isSaving ? '保存中...' : '确认保存'}}
|
||||
<view class="btn-sparkle" wx:if="{{!isSaving}}"></view>
|
||||
</view>
|
||||
</button>
|
||||
|
||||
<view class="safe-area"></view>
|
||||
<global-notification id="global-notification" />
|
||||
<!-- pages/edit/edit.wxml -->
|
||||
<view class="xiugai-page">
|
||||
|
||||
<!-- 头像区域(未改动) -->
|
||||
<view class="avatar-section">
|
||||
<view class="avatar-container {{isAvatarActive ? 'active' : ''}}">
|
||||
<!-- 新增:头像包装器,把头像+光晕包在一起,和提示文字隔离 -->
|
||||
<view class="avatar-image-wrapper">
|
||||
<image class="avatar-image" src="{{avatarUrl}}" mode="aspectFill"></image>
|
||||
<view class="avatar-halo"></view>
|
||||
</view>
|
||||
<view class="avatar-hint">点击更换头像</view>
|
||||
</view>
|
||||
<button
|
||||
class="avatar-trigger-button"
|
||||
open-type="chooseAvatar"
|
||||
bindchooseavatar="onChooseAvatar"
|
||||
hover-class="none"
|
||||
></button>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section">
|
||||
<!-- UID(只读) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">UID</view>
|
||||
<view class="item-value readonly">{{uid || '••••••'}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 昵称(可编辑) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">昵称</view>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="item-input {{nicknameError ? 'error' : ''}}"
|
||||
type="text"
|
||||
placeholder="请输入昵称"
|
||||
placeholder-class="placeholder"
|
||||
maxlength="20"
|
||||
value="{{nicheng}}"
|
||||
bindinput="onNicknameInput"
|
||||
/>
|
||||
<view class="error-hint" wx:if="{{nicknameError}}">{{nicknameError}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号(只读展示,不可修改) -->
|
||||
<view class="form-item">
|
||||
<view class="item-label">手机号</view>
|
||||
<view class="item-value readonly">{{phone || '未绑定'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮(未改动) -->
|
||||
<button
|
||||
class="save-btn"
|
||||
bindtap="onSave"
|
||||
hover-class="btn-hover"
|
||||
disabled="{{isSaving || !hasChanges}}"
|
||||
>
|
||||
<view class="btn-content">
|
||||
{{isSaving ? '保存中...' : '确认保存'}}
|
||||
<view class="btn-sparkle" wx:if="{{!isSaving}}"></view>
|
||||
</view>
|
||||
</button>
|
||||
|
||||
<view class="safe-area"></view>
|
||||
<global-notification id="global-notification" />
|
||||
</view>
|
||||
@@ -1,401 +1,380 @@
|
||||
/* pages/xiugai/xiugai.wxss */
|
||||
page {
|
||||
background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.xiugai-page {
|
||||
padding: 30rpx 40rpx 100rpx;
|
||||
}
|
||||
|
||||
/* ============ 头像区域样式 ============ */
|
||||
.avatar-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 60rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 头像包装器:精确居中,包含头像+光晕 */
|
||||
.avatar-image-wrapper {
|
||||
position: relative;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 头像图片 */
|
||||
.avatar-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid #fff;
|
||||
background-color: #f8f9fa;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
animation: gentleBreath 4s ease-in-out infinite;
|
||||
box-shadow:
|
||||
0 0 0 1rpx rgba(0, 200, 83, 0.3),
|
||||
0 15rpx 40rpx rgba(0, 200, 83, 0.15);
|
||||
box-sizing: border-box; /* 关键:边框向内计算,不占宽度 */
|
||||
}
|
||||
|
||||
/* ✅ 光晕精确居中:已计算头像 6rpx 边框的偏移量 */
|
||||
.avatar-halo {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%); /* 强制居中,无视任何偏差 */
|
||||
width: 228rpx; /* 精确计算:200 + 6*2(边框) + 8*2(外延) = 228 */
|
||||
height: 228rpx;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
border: 3rpx solid transparent;
|
||||
animation: gentleGlow 2s ease-in-out infinite, colorShift 3s ease-in-out infinite;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ✅ 像素点环绕也强制居中 */
|
||||
.avatar-image-wrapper::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 230rpx;
|
||||
height: 230rpx;
|
||||
border-radius: 50%;
|
||||
background:
|
||||
radial-gradient(circle at 30% 30%, rgba(0, 200, 83, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 70% 70%, rgba(100, 221, 23, 0.1) 0%, transparent 50%);
|
||||
animation: pixelOrbit 4s linear infinite;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 温和的呼吸动画 */
|
||||
@keyframes gentleBreath {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
box-shadow:
|
||||
0 0 0 2rpx rgba(0, 200, 83, 0.4),
|
||||
0 15rpx 40rpx rgba(0, 200, 83, 0.2);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.03);
|
||||
box-shadow:
|
||||
0 0 0 5rpx rgba(0, 200, 83, 0.6),
|
||||
0 20rpx 50rpx rgba(0, 200, 83, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 光晕动画 */
|
||||
@keyframes gentleGlow {
|
||||
0%, 100% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.98);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colorShift {
|
||||
0% {
|
||||
border-color: rgba(0, 200, 83, 0.5);
|
||||
}
|
||||
33% {
|
||||
border-color: rgba(100, 221, 23, 0.5);
|
||||
}
|
||||
66% {
|
||||
border-color: rgba(0, 255, 153, 0.5);
|
||||
}
|
||||
100% {
|
||||
border-color: rgba(0, 200, 83, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pixelOrbit {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 更换提示 */
|
||||
.avatar-hint {
|
||||
margin-top: 25rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 12rpx 30rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 25rpx;
|
||||
border: 1rpx solid #eee;
|
||||
box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar-hint::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2rpx;
|
||||
background: linear-gradient(90deg, transparent, #00C853, transparent);
|
||||
animation: hintGlow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes hintGlow {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 点击特效 */
|
||||
.avatar-container.active .avatar-image {
|
||||
animation: clickScale 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes clickScale {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
/* 下载状态 */
|
||||
.avatar-container.downloading .avatar-image {
|
||||
opacity: 0.7;
|
||||
filter: grayscale(30%);
|
||||
}
|
||||
|
||||
/* 透明功能按钮 */
|
||||
.avatar-trigger-button {
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
z-index: 100;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
line-height: 1;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.avatar-trigger-button::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* ============ 表单区域 ============ */
|
||||
.form-section {
|
||||
background: white;
|
||||
border-radius: 25rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 50rpx;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.08);
|
||||
border: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 40rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
min-height: 110rpx;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
width: 150rpx;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-value.readonly {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.item-input {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #ccc;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-input.error {
|
||||
border-bottom: 2rpx solid #ff4d4f;
|
||||
animation: shake 0.5s;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
10%, 30%, 50%, 70%, 90% { transform: translateX(-2rpx); }
|
||||
20%, 40%, 60%, 80% { transform: translateX(2rpx); }
|
||||
}
|
||||
|
||||
.error-hint {
|
||||
font-size: 24rpx;
|
||||
color: #ff4d4f;
|
||||
margin-top: 8rpx;
|
||||
padding-left: 10rpx;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
.phone-hint {
|
||||
font-size: 24rpx;
|
||||
color: #00C853;
|
||||
margin-top: 8rpx;
|
||||
padding-left: 10rpx;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10rpx); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* ============ 保存按钮 ============ */
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
background: linear-gradient(135deg, #00C853 0%, #64DD17 100%);
|
||||
color: white;
|
||||
font-size: 34rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 15rpx 40rpx rgba(0, 200, 83, 0.25);
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.save-btn[disabled] {
|
||||
background: linear-gradient(135deg, #cccccc 0%, #aaaaaa 100%);
|
||||
color: #999;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn-sparkle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.2) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
animation: sparkleMove 2.5s ease-in-out infinite;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes sparkleMove {
|
||||
0% { left: -100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
.btn-hover {
|
||||
opacity: 0.9;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* ============ 手机号获取按钮 ============ */
|
||||
.phone-row {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.phone-value {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.get-phone-btn {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
background: #4a6cf7;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
border-radius: 40rpx;
|
||||
border: none;
|
||||
line-height: 1.4;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.phone-btn-hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.safe-area {
|
||||
height: 100rpx;
|
||||
width: 100%;
|
||||
/* pages/edit/edit.wxss */
|
||||
page {
|
||||
background: linear-gradient(135deg, #fffaf0 0%, #f0f8ff 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.xiugai-page {
|
||||
padding: 30rpx 40rpx 100rpx;
|
||||
}
|
||||
|
||||
/* 头像区域样式 */
|
||||
.avatar-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 60rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 头像包装器 */
|
||||
.avatar-image-wrapper {
|
||||
position: relative;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 头像图片 */
|
||||
.avatar-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid #fff;
|
||||
background-color: #f8f9fa;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
animation: gentleBreath 4s ease-in-out infinite;
|
||||
box-shadow:
|
||||
0 0 0 1rpx rgba(0, 200, 83, 0.3),
|
||||
0 15rpx 40rpx rgba(0, 200, 83, 0.15);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 光晕 */
|
||||
.avatar-halo {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 228rpx;
|
||||
height: 228rpx;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
border: 3rpx solid transparent;
|
||||
animation: gentleGlow 2s ease-in-out infinite, colorShift 3s ease-in-out infinite;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 像素点环绕 */
|
||||
.avatar-image-wrapper::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 230rpx;
|
||||
height: 230rpx;
|
||||
border-radius: 50%;
|
||||
background:
|
||||
radial-gradient(circle at 30% 30%, rgba(0, 200, 83, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 70% 70%, rgba(100, 221, 23, 0.1) 0%, transparent 50%);
|
||||
animation: pixelOrbit 4s linear infinite;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 温和的呼吸动画 */
|
||||
@keyframes gentleBreath {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
box-shadow:
|
||||
0 0 0 2rpx rgba(0, 200, 83, 0.4),
|
||||
0 15rpx 40rpx rgba(0, 200, 83, 0.2);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.03);
|
||||
box-shadow:
|
||||
0 0 0 5rpx rgba(0, 200, 83, 0.6),
|
||||
0 20rpx 50rpx rgba(0, 200, 83, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 光晕动画 */
|
||||
@keyframes gentleGlow {
|
||||
0%, 100% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.98);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colorShift {
|
||||
0% {
|
||||
border-color: rgba(0, 200, 83, 0.5);
|
||||
}
|
||||
33% {
|
||||
border-color: rgba(100, 221, 23, 0.5);
|
||||
}
|
||||
66% {
|
||||
border-color: rgba(0, 255, 153, 0.5);
|
||||
}
|
||||
100% {
|
||||
border-color: rgba(0, 200, 83, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pixelOrbit {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 更换提示 */
|
||||
.avatar-hint {
|
||||
margin-top: 25rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 12rpx 30rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 25rpx;
|
||||
border: 1rpx solid #eee;
|
||||
box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar-hint::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2rpx;
|
||||
background: linear-gradient(90deg, transparent, #00C853, transparent);
|
||||
animation: hintGlow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes hintGlow {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 点击特效 */
|
||||
.avatar-container.active .avatar-image {
|
||||
animation: clickScale 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes clickScale {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
/* 下载状态 */
|
||||
.avatar-container.downloading .avatar-image {
|
||||
opacity: 0.7;
|
||||
filter: grayscale(30%);
|
||||
}
|
||||
|
||||
/* 透明功能按钮 */
|
||||
.avatar-trigger-button {
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
z-index: 100;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
line-height: 1;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.avatar-trigger-button::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.form-section {
|
||||
border-radius: 25rpx;
|
||||
margin-bottom: 50rpx;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.08);
|
||||
border: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 40rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
min-height: 110rpx;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
width: 150rpx;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-value.readonly {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* .item-input — 与全局 .input-inline 完全相同,已移除 */
|
||||
|
||||
.placeholder {
|
||||
color: #ccc;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-input.error {
|
||||
border-bottom: 2rpx solid #ff4d4f;
|
||||
animation: shake 0.5s;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
10%, 30%, 50%, 70%, 90% { transform: translateX(-2rpx); }
|
||||
20%, 40%, 60%, 80% { transform: translateX(2rpx); }
|
||||
}
|
||||
|
||||
.error-hint {
|
||||
font-size: 24rpx;
|
||||
color: #ff4d4f;
|
||||
margin-top: 8rpx;
|
||||
padding-left: 10rpx;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
.phone-hint {
|
||||
font-size: 24rpx;
|
||||
color: #00C853;
|
||||
margin-top: 8rpx;
|
||||
padding-left: 10rpx;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10rpx); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* 保存按钮 */
|
||||
.save-btn {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
background: linear-gradient(135deg, #00C853 0%, #64DD17 100%);
|
||||
font-weight: 500;
|
||||
box-shadow: 0 15rpx 40rpx rgba(0, 200, 83, 0.25);
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.save-btn[disabled] {
|
||||
background: linear-gradient(135deg, #cccccc 0%, #aaaaaa 100%);
|
||||
color: #999;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn-sparkle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.2) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
animation: sparkleMove 2.5s ease-in-out infinite;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes sparkleMove {
|
||||
0% { left: -100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
.btn-hover {
|
||||
opacity: 0.9;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 手机号获取按钮 */
|
||||
.phone-row {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.phone-value {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.get-phone-btn {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
background: #4a6cf7;
|
||||
line-height: 1.4;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.phone-btn-hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.safe-area {
|
||||
height: 100rpx;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,66 +1,66 @@
|
||||
// pages/peihuDingdan/peihuDingdan.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
// pages/escort-orders/escort-orders.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
||||
2
pages/escort-orders/escort-orders.wxml
Normal file
2
pages/escort-orders/escort-orders.wxml
Normal file
@@ -0,0 +1,2 @@
|
||||
<!--pages/escort-orders/escort-orders.wxml-->
|
||||
<text>pages/escort-orders/escort-orders.wxml</text>
|
||||
1
pages/escort-orders/escort-orders.wxss
Normal file
1
pages/escort-orders/escort-orders.wxss
Normal file
@@ -0,0 +1 @@
|
||||
/* pages/escort-orders/escort-orders.wxss */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,230 +1,230 @@
|
||||
<!-- pages/jisufd/jisufd.wxml -->
|
||||
<view class="page-container">
|
||||
<!-- 余额卡片 -->
|
||||
<view class="balance-card">
|
||||
<text class="balance-label">可用余额</text>
|
||||
<view class="balance-amount">
|
||||
<text class="amount-value">{{sjyue}}</text>
|
||||
<text class="amount-unit">元</text>
|
||||
</view>
|
||||
<text class="balance-tip">生成链接将从此余额扣除</text>
|
||||
</view>
|
||||
|
||||
<!-- 商品类型选择 -->
|
||||
<view class="section">
|
||||
<text class="section-title">选择订单类型</text>
|
||||
<scroll-view class="type-scroll" scroll-x="true" enable-flex>
|
||||
<block wx:for="{{shangpinList}}" wx:key="id">
|
||||
<view class="type-item {{selectedTypeId === item.id ? 'type-active' : ''}}"
|
||||
data-id="{{item.id}}" data-item="{{item}}" bindtap="onSelectType">
|
||||
<text class="type-text">{{item.jieshao}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<view class="search-section">
|
||||
<view class="search-box">
|
||||
<text class="search-icon">🔍</text>
|
||||
<input class="search-input" placeholder="输入模板ID/介绍..." value="{{searchParams.keyword}}"
|
||||
bindinput="onSearchKeywordInput" bindconfirm="onSearchConfirm"/>
|
||||
<view class="search-btn" bindtap="onSearchConfirm">
|
||||
<text class="search-btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-row">
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">金额≥</text>
|
||||
<input class="filter-input" type="digit" placeholder="元" value="{{searchParams.minPrice}}" bindinput="onSearchMinPriceInput"/>
|
||||
</view>
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onSearchLabelChange">
|
||||
<view class="picker-view">
|
||||
<text>{{searchLabelName || '全部'}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="clear-search" bindtap="onClearSearch"><text>清空</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 模板卡片网格 -->
|
||||
<view class="template-section">
|
||||
<scroll-view class="template-scroll" scroll-y="true" scroll-with-animation="true" bindscrolltolower="onScrollToLower">
|
||||
<view class="template-grid">
|
||||
<block wx:for="{{templateList}}" wx:key="mobanId">
|
||||
<view class="template-card" bindtap="onCardTap" data-item="{{item}}">
|
||||
<view class="template-intro">
|
||||
<text class="intro-text">{{item.jieshao || '无介绍'}}</text>
|
||||
</view>
|
||||
<view class="template-label" wx:if="{{item.labelName}}">
|
||||
<chenghao-tag mingcheng="{{item.labelName}}" texiaoJson="{{''}}"/>
|
||||
</view>
|
||||
<view class="template-price-row">
|
||||
<text class="template-price-label">价格:</text>
|
||||
<text class="template-price-value">{{item.jiage || '0.00'}}元</text>
|
||||
</view>
|
||||
<view class="template-actions-grid">
|
||||
<view class="action-grid-btn generate-grid-btn {{item.hasGenerated ? 'generated' : ''}}"
|
||||
data-id="{{item.mobanId}}" catchtap="onGenerateLink">
|
||||
{{item.hasGenerated ? '获取新链接' : '生成链接'}}
|
||||
</view>
|
||||
<view class="action-grid-btn copy-grid-btn {{item.isCopied ? 'copied' : ''}}"
|
||||
data-id="{{item.mobanId}}" catchtap="onCopyLink">
|
||||
{{item.isCopied ? '已复制' : '一键复制'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="template-card add-card" bindtap="showAddModal">
|
||||
<view class="add-icon">➕</view>
|
||||
<text class="add-text">添加模板</text>
|
||||
<text class="add-subtext">点击创建新模板</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="load-more" wx:if="{{isLoadingMore}}">...</view>
|
||||
<view class="no-more" wx:if="{{!hasMoreData && templateList.length > 0}}">没有更多模板了</view>
|
||||
<view class="empty-state" wx:if="{{templateList.length === 0 && !isLoading}}">暂无模板</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showDetailModal}}" bindtap="hideDetailModal">
|
||||
<view class="modal-content detail-modal" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="hideDetailModal">×</view>
|
||||
<view class="modal-header"><text class="modal-title">模板详情</text></view>
|
||||
<view class="detail-info" wx:if="{{currentTemplate}}">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">订单介绍</text>
|
||||
<view class="detail-value intro-value"><text>{{currentTemplate.jieshao || '无介绍'}}</text></view>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{currentTemplate.labelName}}">
|
||||
<text class="detail-label">关联标签</text>
|
||||
<chenghao-tag mingcheng="{{currentTemplate.labelName}}" texiaoJson="{{currentTemplate.texiaoJson}}"/>
|
||||
</view>
|
||||
<view class="detail-meta-row">
|
||||
<view class="meta-item"><text class="meta-label">价格</text><text class="meta-value price-meta">{{currentTemplate.jiage || '0.00'}}元</text></view>
|
||||
<view class="meta-divider">|</view>
|
||||
<view class="meta-item"><text class="meta-label">发布数量</text><text class="meta-value count-meta">{{currentTemplate.fabushuliang || 0}}次</text></view>
|
||||
<view class="meta-divider">|</view>
|
||||
<view class="meta-item"><text class="meta-label">模板ID</text><text class="meta-value id-meta">{{currentTemplate.mobanId || 'N/A'}}</text></view>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{currentTemplate.commissionEnabled}}">
|
||||
<text class="detail-label">佣金要求</text>
|
||||
<text class="detail-value">{{currentTemplate.commissionValue}}元(建议≤50)</text>
|
||||
</view>
|
||||
<!-- 链接筛选 -->
|
||||
<view class="link-filter-bar">
|
||||
<text class="filter-label">链接状态:</text>
|
||||
<view class="filter-switch {{detailLinkFilter === 0 ? 'active' : ''}}" bindtap="onToggleLinkFilter">未使用</view>
|
||||
<view class="filter-switch {{detailLinkFilter === 1 ? 'active' : ''}}" bindtap="onToggleLinkFilter">已使用</view>
|
||||
</view>
|
||||
<scroll-view class="link-list" scroll-y="true" style="max-height: 300rpx;">
|
||||
<block wx:for="{{detailLinkList}}" wx:key="id">
|
||||
<view class="link-item">
|
||||
<text class="link-url" selectable="true">{{item.lianjie}}</text>
|
||||
<text class="link-status">{{item.is_used ? '已使用' : '未使用'}}</text>
|
||||
<view wx:if="{{!item.is_used}}" class="copy-link-btn" bindtap="onCopyLinkItem" data-url="{{item.lianjie}}">复制</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="load-more-links" wx:if="{{detailLinkHasMore}}">
|
||||
<view class="load-more-btn" bindtap="onLoadMoreLinks">获取更多链接</view>
|
||||
</view>
|
||||
<view wx:if="{{isLoadingLinks}}" class="link-loading">加载中...</view>
|
||||
<view wx:if="{{detailLinkList.length === 0 && !isLoadingLinks}}" class="link-empty">暂无链接</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="modal-actions-grid">
|
||||
<view class="modal-grid-btn generate-modal-grid-btn" bindtap="onGenerateLinkModal">{{currentTemplate.hasGenerated ? '获取新链接' : '生成链接'}}</view>
|
||||
<view class="modal-grid-btn copy-modal-grid-btn {{currentTemplate.isCopied ? 'copied' : ''}}" bindtap="onCopyLinkModal">{{currentTemplate.isCopied ? '已复制' : '复制链接'}}</view>
|
||||
<view class="modal-grid-btn edit-modal-grid-btn" bindtap="onEditTemplate">{{isEditing ? '保存修改' : '立即修改'}}</view>
|
||||
<view class="modal-grid-btn delete-modal-grid-btn" bindtap="onDeleteTemplate">删除模板</view>
|
||||
</view>
|
||||
<!-- 编辑区 -->
|
||||
<view class="edit-section" wx:if="{{isEditing}}">
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">订单介绍</text>
|
||||
<textarea class="edit-input intro-edit" value="{{editJieshao}}" maxlength="100" placeholder="请输入订单介绍(100字以内)" bindinput="onEditJieshaoInput" auto-height/>
|
||||
<text class="word-count">{{editJieshao.length}}/100</text>
|
||||
</view>
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">价格(元)</text>
|
||||
<input class="edit-input price-edit" type="digit" value="{{editJiage}}" placeholder="0.1 - 10000" bindinput="onEditJiageInput"/>
|
||||
</view>
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onEditLabelChange">
|
||||
<view class="picker-view"><text>{{editLabelName || '无'}}</text></view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="edit-item commission-item">
|
||||
<text class="edit-label">佣金要求(建议≤50)</text>
|
||||
<switch checked="{{editCommissionEnabled}}" bindchange="onEditCommissionToggle"/>
|
||||
<input wx:if="{{editCommissionEnabled}}" class="commission-input" type="digit" placeholder="佣金金额" value="{{editCommissionValue}}" bindinput="onEditCommissionValueInput"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 添加模板弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showAddModal}}" bindtap="hideAddModal">
|
||||
<view class="modal-content add-modal" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="hideAddModal">×</view>
|
||||
<view class="modal-header"><text class="modal-title">添加模板</text></view>
|
||||
<view class="add-form">
|
||||
<view class="form-item">
|
||||
<text class="form-label">订单介绍</text>
|
||||
<textarea class="form-input intro-input" value="{{addJieshao}}" maxlength="100" placeholder="请输入订单介绍(必填)" bindinput="onAddJieshaoInput" auto-height/>
|
||||
<text class="word-count">{{addJieshao.length}}/100</text>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">价格(元)</text>
|
||||
<input class="form-input price-input" type="digit" value="{{addJiage}}" placeholder="0.1 - 10000" bindinput="onAddJiageInput"/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onAddLabelChange">
|
||||
<view class="picker-view"><text>{{addLabelName || '可选'}}</text></view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item commission-item">
|
||||
<text class="form-label">佣金要求(建议≤50)</text>
|
||||
<switch checked="{{addCommissionEnabled}}" bindchange="onAddCommissionToggle"/>
|
||||
<input wx:if="{{addCommissionEnabled}}" class="commission-input" type="digit" placeholder="佣金金额" value="{{addCommissionValue}}" bindinput="onAddCommissionValueInput"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-actions-grid add-actions-grid">
|
||||
<view class="modal-grid-btn cancel-grid-btn" bindtap="hideAddModal">取消</view>
|
||||
<view class="modal-grid-btn confirm-add-grid-btn" bindtap="onAddTemplate">确认添加</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 删除确认弹窗 -->
|
||||
<view class="modal-overlay confirm-overlay" wx:if="{{showDeleteConfirm}}" bindtap="hideDeleteConfirm">
|
||||
<view class="confirm-content" catchtap="stopPropagation">
|
||||
<text class="confirm-title">确认删除</text>
|
||||
<text class="confirm-text">确定要删除这个模板吗?此操作不可恢复。</text>
|
||||
<view class="confirm-actions-grid">
|
||||
<view class="confirm-grid-btn cancel-confirm-grid-btn" bindtap="hideDeleteConfirm">取消</view>
|
||||
<view class="confirm-grid-btn delete-confirm-grid-btn" bindtap="confirmDeleteTemplate">确定删除</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 获取新链接确认弹窗 -->
|
||||
<view class="modal-overlay confirm-overlay" wx:if="{{showNewLinkConfirm}}" bindtap="hideNewLinkConfirm">
|
||||
<view class="confirm-content" catchtap="stopPropagation">
|
||||
<text class="confirm-title">获取新链接</text>
|
||||
<text class="confirm-text">{{currentTemplate.isCopied ? '确定要获取新链接吗?旧链接将失效。' : '您还没有复制当前链接,确定要获取新链接吗?'}}</text>
|
||||
<view class="confirm-actions-grid">
|
||||
<view class="confirm-grid-btn cancel-confirm-grid-btn" bindtap="hideNewLinkConfirm">取消</view>
|
||||
<view class="confirm-grid-btn confirm-new-link-grid-btn" bindtap="confirmNewLink">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- pages/express-order/express-order.wxml -->
|
||||
<view class="page-container">
|
||||
<!-- 余额卡片 -->
|
||||
<view class="balance-card">
|
||||
<text class="balance-label">可用余额</text>
|
||||
<view class="balance-amount">
|
||||
<text class="amount-value">{{sjyue}}</text>
|
||||
<text class="amount-unit">元</text>
|
||||
</view>
|
||||
<text class="balance-tip">生成链接将从此余额扣除</text>
|
||||
</view>
|
||||
|
||||
<!-- 商品类型选择 -->
|
||||
<view class="section">
|
||||
<text class="section-title">选择订单类型</text>
|
||||
<scroll-view class="type-scroll" scroll-x="true" enable-flex>
|
||||
<block wx:for="{{shangpinList}}" wx:key="id">
|
||||
<view class="type-item {{selectedTypeId === item.id ? 'type-active' : ''}}"
|
||||
data-id="{{item.id}}" data-item="{{item}}" bindtap="onSelectType">
|
||||
<text class="type-text">{{item.jieshao}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<view class="search-section">
|
||||
<view class="search-box">
|
||||
<text class="search-icon">🔍</text>
|
||||
<input class="search-input" placeholder="输入模板ID/介绍..." value="{{searchParams.keyword}}"
|
||||
bindinput="onSearchKeywordInput" bindconfirm="onSearchConfirm"/>
|
||||
<view class="search-btn" bindtap="onSearchConfirm">
|
||||
<text class="search-btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-row">
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">金额≥</text>
|
||||
<input class="filter-input" type="digit" placeholder="元" value="{{searchParams.minPrice}}" bindinput="onSearchMinPriceInput"/>
|
||||
</view>
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onSearchLabelChange">
|
||||
<view class="picker-view">
|
||||
<text>{{searchLabelName || '全部'}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="clear-search" bindtap="onClearSearch"><text>清空</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 模板卡片网格 -->
|
||||
<view class="template-section">
|
||||
<scroll-view class="template-scroll" scroll-y="true" scroll-with-animation="true" bindscrolltolower="onScrollToLower">
|
||||
<view class="template-grid">
|
||||
<block wx:for="{{templateList}}" wx:key="mobanId">
|
||||
<view class="template-card" bindtap="onCardTap" data-item="{{item}}">
|
||||
<view class="template-intro">
|
||||
<text class="intro-text">{{item.jieshao || '无介绍'}}</text>
|
||||
</view>
|
||||
<view class="template-label" wx:if="{{item.labelName}}">
|
||||
<chenghao-tag mingcheng="{{item.labelName}}" texiaoJson="{{''}}"/>
|
||||
</view>
|
||||
<view class="template-price-row">
|
||||
<text class="template-price-label">价格:</text>
|
||||
<text class="template-price-value">{{item.jiage || '0.00'}}元</text>
|
||||
</view>
|
||||
<view class="template-actions-grid">
|
||||
<view class="action-grid-btn generate-grid-btn {{item.hasGenerated ? 'generated' : ''}}"
|
||||
data-id="{{item.mobanId}}" catchtap="onGenerateLink">
|
||||
{{item.hasGenerated ? '获取新链接' : '生成链接'}}
|
||||
</view>
|
||||
<view class="action-grid-btn copy-grid-btn {{item.isCopied ? 'copied' : ''}}"
|
||||
data-id="{{item.mobanId}}" catchtap="onCopyLink">
|
||||
{{item.isCopied ? '已复制' : '一键复制'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="template-card add-card" bindtap="showAddModal">
|
||||
<view class="add-icon">➕</view>
|
||||
<text class="add-text">添加模板</text>
|
||||
<text class="add-subtext">点击创建新模板</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="load-more" wx:if="{{isLoadingMore}}">...</view>
|
||||
<view class="no-more" wx:if="{{!hasMoreData && templateList.length > 0}}">没有更多模板了</view>
|
||||
<view class="empty-state" wx:if="{{templateList.length === 0 && !isLoading}}">暂无模板</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showDetailModal}}" bindtap="hideDetailModal">
|
||||
<view class="modal-content detail-modal" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="hideDetailModal">×</view>
|
||||
<view class="modal-header"><text class="modal-title">模板详情</text></view>
|
||||
<view class="detail-info" wx:if="{{currentTemplate}}">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">订单介绍</text>
|
||||
<view class="detail-value intro-value"><text>{{currentTemplate.jieshao || '无介绍'}}</text></view>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{currentTemplate.labelName}}">
|
||||
<text class="detail-label">关联标签</text>
|
||||
<chenghao-tag mingcheng="{{currentTemplate.labelName}}" texiaoJson="{{currentTemplate.texiaoJson}}"/>
|
||||
</view>
|
||||
<view class="detail-meta-row">
|
||||
<view class="meta-item"><text class="meta-label">价格</text><text class="meta-value price-meta">{{currentTemplate.jiage || '0.00'}}元</text></view>
|
||||
<view class="meta-divider">|</view>
|
||||
<view class="meta-item"><text class="meta-label">发布数量</text><text class="meta-value count-meta">{{currentTemplate.fabushuliang || 0}}次</text></view>
|
||||
<view class="meta-divider">|</view>
|
||||
<view class="meta-item"><text class="meta-label">模板ID</text><text class="meta-value id-meta">{{currentTemplate.mobanId || 'N/A'}}</text></view>
|
||||
</view>
|
||||
<view class="detail-item" wx:if="{{currentTemplate.commissionEnabled}}">
|
||||
<text class="detail-label">佣金要求</text>
|
||||
<text class="detail-value">{{currentTemplate.commissionValue}}元(建议≤50)</text>
|
||||
</view>
|
||||
<!-- 链接筛选 -->
|
||||
<view class="link-filter-bar">
|
||||
<text class="filter-label">链接状态:</text>
|
||||
<view class="filter-switch {{detailLinkFilter === 0 ? 'active' : ''}}" bindtap="onToggleLinkFilter">未使用</view>
|
||||
<view class="filter-switch {{detailLinkFilter === 1 ? 'active' : ''}}" bindtap="onToggleLinkFilter">已使用</view>
|
||||
</view>
|
||||
<scroll-view class="link-list" scroll-y="true" style="max-height: 300rpx;">
|
||||
<block wx:for="{{detailLinkList}}" wx:key="id">
|
||||
<view class="link-item">
|
||||
<text class="link-url" selectable="true">{{item.lianjie}}</text>
|
||||
<text class="link-status">{{item.is_used ? '已使用' : '未使用'}}</text>
|
||||
<view wx:if="{{!item.is_used}}" class="copy-link-btn" bindtap="onCopyLinkItem" data-url="{{item.lianjie}}">复制</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="load-more-links" wx:if="{{detailLinkHasMore}}">
|
||||
<view class="load-more-btn" bindtap="onLoadMoreLinks">获取更多链接</view>
|
||||
</view>
|
||||
<view wx:if="{{isLoadingLinks}}" class="link-loading">加载中...</view>
|
||||
<view wx:if="{{detailLinkList.length === 0 && !isLoadingLinks}}" class="link-empty">暂无链接</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="modal-actions-grid">
|
||||
<view class="modal-grid-btn generate-modal-grid-btn" bindtap="onGenerateLinkModal">{{currentTemplate.hasGenerated ? '获取新链接' : '生成链接'}}</view>
|
||||
<view class="modal-grid-btn copy-modal-grid-btn {{currentTemplate.isCopied ? 'copied' : ''}}" bindtap="onCopyLinkModal">{{currentTemplate.isCopied ? '已复制' : '复制链接'}}</view>
|
||||
<view class="modal-grid-btn edit-modal-grid-btn" bindtap="onEditTemplate">{{isEditing ? '保存修改' : '立即修改'}}</view>
|
||||
<view class="modal-grid-btn delete-modal-grid-btn" bindtap="onDeleteTemplate">删除模板</view>
|
||||
</view>
|
||||
<!-- 编辑区 -->
|
||||
<view class="edit-section" wx:if="{{isEditing}}">
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">订单介绍</text>
|
||||
<textarea class="edit-input intro-edit" value="{{editJieshao}}" maxlength="100" placeholder="请输入订单介绍(100字以内)" bindinput="onEditJieshaoInput" auto-height/>
|
||||
<text class="word-count">{{editJieshao.length}}/100</text>
|
||||
</view>
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">价格(元)</text>
|
||||
<input class="edit-input price-edit" type="digit" value="{{editJiage}}" placeholder="0.1 - 10000" bindinput="onEditJiageInput"/>
|
||||
</view>
|
||||
<view class="edit-item">
|
||||
<text class="edit-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onEditLabelChange">
|
||||
<view class="picker-view"><text>{{editLabelName || '无'}}</text></view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="edit-item commission-item">
|
||||
<text class="edit-label">佣金要求(建议≤50)</text>
|
||||
<switch checked="{{editCommissionEnabled}}" bindchange="onEditCommissionToggle"/>
|
||||
<input wx:if="{{editCommissionEnabled}}" class="commission-input" type="digit" placeholder="佣金金额" value="{{editCommissionValue}}" bindinput="onEditCommissionValueInput"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 添加模板弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showAddModal}}" bindtap="hideAddModal">
|
||||
<view class="modal-content add-modal" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="hideAddModal">×</view>
|
||||
<view class="modal-header"><text class="modal-title">添加模板</text></view>
|
||||
<view class="add-form">
|
||||
<view class="form-item">
|
||||
<text class="form-label">订单介绍</text>
|
||||
<textarea class="form-input intro-input" value="{{addJieshao}}" maxlength="100" placeholder="请输入订单介绍(必填)" bindinput="onAddJieshaoInput" auto-height/>
|
||||
<text class="word-count">{{addJieshao.length}}/100</text>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">价格(元)</text>
|
||||
<input class="form-input price-input" type="digit" value="{{addJiage}}" placeholder="0.1 - 10000" bindinput="onAddJiageInput"/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">标签</text>
|
||||
<picker mode="selector" range="{{currentTypeChenghaoList}}" range-key="mingcheng" bindchange="onAddLabelChange">
|
||||
<view class="picker-view"><text>{{addLabelName || '可选'}}</text></view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item commission-item">
|
||||
<text class="form-label">佣金要求(建议≤50)</text>
|
||||
<switch checked="{{addCommissionEnabled}}" bindchange="onAddCommissionToggle"/>
|
||||
<input wx:if="{{addCommissionEnabled}}" class="commission-input" type="digit" placeholder="佣金金额" value="{{addCommissionValue}}" bindinput="onAddCommissionValueInput"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-actions-grid add-actions-grid">
|
||||
<view class="modal-grid-btn cancel-grid-btn" bindtap="hideAddModal">取消</view>
|
||||
<view class="modal-grid-btn confirm-add-grid-btn" bindtap="onAddTemplate">确认添加</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 删除确认弹窗 -->
|
||||
<view class="modal-overlay confirm-overlay" wx:if="{{showDeleteConfirm}}" bindtap="hideDeleteConfirm">
|
||||
<view class="confirm-content" catchtap="stopPropagation">
|
||||
<text class="confirm-title">确认删除</text>
|
||||
<text class="confirm-text">确定要删除这个模板吗?此操作不可恢复。</text>
|
||||
<view class="confirm-actions-grid">
|
||||
<view class="confirm-grid-btn cancel-confirm-grid-btn" bindtap="hideDeleteConfirm">取消</view>
|
||||
<view class="confirm-grid-btn delete-confirm-grid-btn" bindtap="confirmDeleteTemplate">确定删除</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 获取新链接确认弹窗 -->
|
||||
<view class="modal-overlay confirm-overlay" wx:if="{{showNewLinkConfirm}}" bindtap="hideNewLinkConfirm">
|
||||
<view class="confirm-content" catchtap="stopPropagation">
|
||||
<text class="confirm-title">获取新链接</text>
|
||||
<text class="confirm-text">{{currentTemplate.isCopied ? '确定要获取新链接吗?旧链接将失效。' : '您还没有复制当前链接,确定要获取新链接吗?'}}</text>
|
||||
<view class="confirm-actions-grid">
|
||||
<view class="confirm-grid-btn cancel-confirm-grid-btn" bindtap="hideNewLinkConfirm">取消</view>
|
||||
<view class="confirm-grid-btn confirm-new-link-grid-btn" bindtap="confirmNewLink">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
@@ -1,222 +1,222 @@
|
||||
/* pages/jisufd/jisufd.wxss - 增强版,包含标签展示 */
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 50%, #16213e 100%);
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 40rpx;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
.balance-card {
|
||||
background: linear-gradient(135deg, rgba(20,20,30,0.9), rgba(30,30,50,0.9));
|
||||
border-radius: 24rpx;
|
||||
padding: 36rpx;
|
||||
margin-bottom: 40rpx;
|
||||
color: #fff;
|
||||
box-shadow: 0 15rpx 35rpx rgba(0,0,0,0.4), 0 0 40rpx rgba(0,150,255,0.15);
|
||||
text-align: center;
|
||||
border: 1.5rpx solid rgba(0,180,255,0.2);
|
||||
backdrop-filter: blur(10rpx);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.balance-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%; left: -50%;
|
||||
width: 200%; height: 200%;
|
||||
background: linear-gradient(45deg, transparent 30%, rgba(0,180,255,0.1) 50%, transparent 70%);
|
||||
animation: cardShine 6s infinite linear;
|
||||
z-index: 1;
|
||||
}
|
||||
@keyframes cardShine {
|
||||
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
|
||||
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
|
||||
}
|
||||
.balance-label { font-size: 28rpx; color: rgba(255,255,255,0.8); margin-bottom: 18rpx; font-weight: 500; position: relative; z-index: 2; }
|
||||
.balance-amount { display: flex; align-items: baseline; justify-content: center; margin-bottom: 15rpx; position: relative; z-index: 2; }
|
||||
.amount-value { font-size: 64rpx; font-weight: bold; color: #00B4FF; text-shadow: 0 0 20rpx rgba(0,180,255,0.7), 0 0 40rpx rgba(0,180,255,0.4); animation: amountGlow 3s infinite alternate; }
|
||||
@keyframes amountGlow {
|
||||
0% { color: #00B4FF; text-shadow: 0 0 15rpx rgba(0,180,255,0.6); }
|
||||
100% { color: #00E0FF; text-shadow: 0 0 25rpx rgba(0,180,255,0.8), 0 0 50rpx rgba(0,180,255,0.5); }
|
||||
}
|
||||
.amount-unit { font-size: 36rpx; color: #00B4FF; margin-left: 12rpx; font-weight: 500; z-index: 2; }
|
||||
.balance-tip { font-size: 24rpx; color: rgba(255,255,255,0.6); z-index: 2; }
|
||||
|
||||
.section { margin-bottom: 35rpx; }
|
||||
.section-title { font-size: 32rpx; font-weight: 700; color: #FFFFFF; margin-bottom: 25rpx; padding-left: 12rpx; border-left: 6rpx solid #9C27B0; text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.3); }
|
||||
|
||||
.type-scroll { white-space: nowrap; display: flex; height: 90rpx; }
|
||||
.type-item {
|
||||
display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center;
|
||||
height: 85rpx; padding: 0 40rpx; margin-right: 20rpx;
|
||||
background: rgba(255,255,255,0.08); border-radius: 45rpx; border: 2rpx solid rgba(255,255,255,0.15);
|
||||
font-size: 28rpx; color: rgba(255,255,255,0.8);
|
||||
transition: all 0.3s cubic-bezier(0.175,0.885,0.32,1.275);
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
.type-active {
|
||||
background: linear-gradient(135deg, #9C27B0 0%, #673AB7 100%);
|
||||
border-color: #9C27B0; color: white; transform: scale(1.05);
|
||||
box-shadow: 0 10rpx 25rpx rgba(156,39,176,0.4), 0 0 30rpx rgba(156,39,176,0.3);
|
||||
}
|
||||
.type-text { max-width: 220rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
|
||||
|
||||
/* 搜索区域 */
|
||||
.search-section { margin-bottom: 35rpx; }
|
||||
.search-box {
|
||||
display: flex; align-items: center;
|
||||
background: rgba(255,255,255,0.1); border-radius: 50rpx;
|
||||
padding: 20rpx 30rpx; border: 2rpx solid rgba(255,255,255,0.2);
|
||||
backdrop-filter: blur(10rpx); transition: all 0.3s ease;
|
||||
}
|
||||
.search-box:focus-within { border-color: #9C27B0; background: rgba(255,255,255,0.15); box-shadow: 0 0 25rpx rgba(156,39,176,0.3); }
|
||||
.search-icon { font-size: 32rpx; color: rgba(255,255,255,0.7); margin-right: 20rpx; flex-shrink: 0; }
|
||||
.search-input { flex: 1; font-size: 28rpx; color: #FFFFFF; background: transparent; border: none; outline: none; min-height: 40rpx; }
|
||||
.search-input::placeholder { color: rgba(255,255,255,0.4); }
|
||||
.search-btn { background: linear-gradient(135deg, #9C27B0 0%, #673AB7 100%); border-radius: 40rpx; padding: 15rpx 30rpx; margin-left: 20rpx; flex-shrink: 0; box-shadow: 0 8rpx 20rpx rgba(156,39,176,0.3); }
|
||||
.search-btn:active { transform: scale(0.95); }
|
||||
.search-btn-text { font-size: 26rpx; color: white; font-weight: 600; }
|
||||
|
||||
.filter-row { display: flex; align-items: center; margin-top: 20rpx; gap: 15rpx; }
|
||||
.filter-item { display: flex; align-items: center; background: rgba(255,255,255,0.08); border-radius: 30rpx; padding: 10rpx 20rpx; border: 1rpx solid rgba(255,255,255,0.15); }
|
||||
.filter-label { font-size: 24rpx; color: rgba(255,255,255,0.7); margin-right: 10rpx; }
|
||||
.filter-input { width: 120rpx; height: 50rpx; background: transparent; color: #fff; font-size: 26rpx; }
|
||||
.picker-view { padding: 10rpx 0; color: rgba(255,255,255,0.9); font-size: 26rpx; max-width: 160rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.clear-search { margin-left: auto; padding: 10rpx 20rpx; background: rgba(255,255,255,0.1); border-radius: 20rpx; color: rgba(255,255,255,0.7); font-size: 24rpx; }
|
||||
|
||||
/* 模板区域 */
|
||||
.template-section { height: calc(100vh - 600rpx); position: relative; }
|
||||
.template-scroll { height: 100%; }
|
||||
.template-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 25rpx; padding-bottom: 30rpx; }
|
||||
.template-card {
|
||||
background: linear-gradient(145deg, rgba(30,30,45,0.9), rgba(40,40,60,0.9));
|
||||
border-radius: 20rpx; padding: 25rpx;
|
||||
border: 1.5rpx solid rgba(255,255,255,0.1);
|
||||
box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.3), 0 0 25rpx rgba(0,180,255,0.1);
|
||||
transition: all 0.3s ease; backdrop-filter: blur(10rpx);
|
||||
display: flex; flex-direction: column; min-height: 280rpx; position: relative; overflow: hidden;
|
||||
}
|
||||
.template-card::before { content: ''; position: absolute; top:0; left:0; right:0; height:4rpx; background: linear-gradient(90deg, #9C27B0, #00B4FF, #9C27B0); opacity:0.6; }
|
||||
.template-intro { flex:1; margin-bottom:10rpx; min-height:70rpx; overflow:hidden; }
|
||||
.intro-text { font-size:24rpx; line-height:1.4; color:rgba(255,255,255,0.9); display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden; font-weight:500; }
|
||||
.template-label { margin-bottom: 10rpx; }
|
||||
.template-price-row { display:flex; align-items:center; margin-bottom:20rpx; padding:10rpx 0; border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.template-price-label { font-size:22rpx; color:rgba(255,255,255,0.7); margin-right:10rpx; }
|
||||
.template-price-value { font-size:26rpx; font-weight:bold; color:#FFD700; text-shadow:0 0 10rpx rgba(255,215,0,0.3); flex:1; }
|
||||
.template-actions-grid { display:flex; flex-direction:column; gap:12rpx; margin-top:10rpx; }
|
||||
.action-grid-btn {
|
||||
height:65rpx; border-radius:32rpx; font-size:24rpx; font-weight:600; transition:all 0.3s ease;
|
||||
border:none; padding:0 20rpx; box-shadow:0 4rpx 12rpx rgba(0,0,0,0.2), inset 0 1rpx 0 rgba(255,255,255,0.1);
|
||||
display:flex !important; align-items:center !important; justify-content:center !important; text-align:center !important;
|
||||
}
|
||||
.generate-grid-btn { background:linear-gradient(135deg, #00B4FF, #0091EA); color:white; }
|
||||
.generate-grid-btn.generated { background:linear-gradient(135deg, #4CAF50, #2E7D32); }
|
||||
.copy-grid-btn { background:linear-gradient(135deg, #9C27B0, #673AB7); color:white; }
|
||||
.copy-grid-btn.copied { background:linear-gradient(135deg, #FF9800, #F57C00); }
|
||||
.add-card { background: linear-gradient(145deg, rgba(40,40,60,0.7), rgba(60,60,80,0.7)); border:2rpx dashed rgba(255,255,255,0.3); display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:280rpx; }
|
||||
.add-icon { font-size:60rpx; color:rgba(255,255,255,0.6); margin-bottom:20rpx; }
|
||||
.add-text { font-size:30rpx; color:rgba(255,255,255,0.8); font-weight:600; margin-bottom:8rpx; }
|
||||
.add-subtext { font-size:24rpx; color:rgba(255,255,255,0.5); }
|
||||
|
||||
/* 弹窗通用 */
|
||||
.modal-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.75); display:flex; align-items:center; justify-content:center; z-index:9999; padding:30rpx; backdrop-filter:blur(10rpx); animation:fadeIn 0.3s ease; }
|
||||
@keyframes fadeIn { from{opacity:0;} to{opacity:1;} }
|
||||
.modal-content {
|
||||
background:linear-gradient(145deg, rgba(30,30,45,0.95), rgba(40,40,60,0.95));
|
||||
border-radius:30rpx; width:100%; max-width:700rpx; max-height:85vh; overflow-y:auto;
|
||||
border:1.5rpx solid rgba(255,255,255,0.15);
|
||||
box-shadow:0 25rpx 80rpx rgba(0,0,0,0.6), 0 0 60rpx rgba(0,180,255,0.2);
|
||||
animation:slideUp 0.4s cubic-bezier(0.175,0.885,0.32,1.275);
|
||||
position:relative;
|
||||
}
|
||||
@keyframes slideUp { from{transform:translateY(100rpx) scale(0.9); opacity:0;} to{transform:translateY(0) scale(1); opacity:1;} }
|
||||
.modal-close { position:absolute; top:25rpx; right:25rpx; width:60rpx; height:60rpx; border-radius:50%; background:rgba(255,255,255,0.1); display:flex; align-items:center; justify-content:center; font-size:40rpx; color:rgba(255,255,255,0.7); z-index:10; }
|
||||
.modal-header { padding:40rpx 40rpx 20rpx; text-align:center; }
|
||||
.modal-title { font-size:36rpx; font-weight:bold; color:#FFFFFF; }
|
||||
|
||||
.detail-info { padding:30rpx 40rpx; }
|
||||
.detail-item { margin-bottom:30rpx; }
|
||||
.detail-label { font-size:26rpx; color:rgba(255,255,255,0.7); margin-bottom:10rpx; font-weight:500; }
|
||||
.detail-value { font-size:28rpx; color:#FFFFFF; word-break:break-word; }
|
||||
.intro-value { background:rgba(255,255,255,0.05); border-radius:15rpx; padding:20rpx; border:1rpx solid rgba(255,255,255,0.1); max-height:200rpx; overflow-y:auto; }
|
||||
.detail-meta-row { display:flex; align-items:center; justify-content:space-between; padding:25rpx 0; margin:20rpx 0; border-top:1rpx solid rgba(255,255,255,0.1); border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.meta-item { display:flex; flex-direction:column; align-items:center; flex:1; }
|
||||
.meta-label { font-size:22rpx; color:rgba(255,255,255,0.6); margin-bottom:8rpx; }
|
||||
.meta-value { font-size:26rpx; font-weight:600; }
|
||||
.price-meta { color:#FFD700; text-shadow:0 0 10rpx rgba(255,215,0,0.3); }
|
||||
.count-meta { color:#00B4FF; }
|
||||
.id-meta { color:#4CAF50; font-family:'Courier New',monospace; font-size:24rpx; }
|
||||
.meta-divider { color:rgba(255,255,255,0.2); font-size:24rpx; margin:0 15rpx; }
|
||||
|
||||
.link-filter-bar { display:flex; align-items:center; margin-top:30rpx; margin-bottom:20rpx; }
|
||||
.filter-switch {
|
||||
padding:10rpx 25rpx; margin-left:10rpx; border-radius:20rpx; background:rgba(255,255,255,0.1);
|
||||
font-size:24rpx; color:rgba(255,255,255,0.7); transition:all 0.3s;
|
||||
}
|
||||
.filter-switch.active { background:linear-gradient(135deg, #00B4FF, #0091EA); color:white; }
|
||||
.link-list { background:rgba(0,0,0,0.2); border-radius:15rpx; padding:15rpx; }
|
||||
.link-item { display:flex; align-items:center; justify-content:space-between; padding:15rpx 0; border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.link-url { flex:1; font-size:22rpx; color:rgba(255,255,255,0.8); word-break:break-all; margin-right:15rpx; }
|
||||
.link-status { font-size:20rpx; color:rgba(255,255,255,0.5); margin-right:15rpx; }
|
||||
.copy-link-btn { padding:8rpx 20rpx; background:#00B4FF; color:white; border-radius:15rpx; font-size:22rpx; }
|
||||
.load-more-links { text-align:center; padding:20rpx 0; }
|
||||
.load-more-btn { display:inline-block; padding:15rpx 40rpx; background:linear-gradient(135deg, #9C27B0, #673AB7); border-radius:30rpx; color:white; font-size:26rpx; }
|
||||
.link-loading, .link-empty { text-align:center; padding:30rpx; color:rgba(255,255,255,0.5); font-size:24rpx; }
|
||||
|
||||
/* 弹窗按钮 */
|
||||
.modal-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:18rpx; padding:30rpx 40rpx 40rpx; border-top:1rpx solid rgba(255,255,255,0.1); }
|
||||
.modal-grid-btn {
|
||||
height:85rpx; border-radius:42rpx; font-size:28rpx; font-weight:600; transition:all 0.3s;
|
||||
border:none; padding:0 20rpx; box-shadow:0 8rpx 25rpx rgba(0,0,0,0.3), inset 0 1rpx 0 rgba(255,255,255,0.2);
|
||||
display:flex !important; align-items:center !important; justify-content:center !important;
|
||||
}
|
||||
.generate-modal-grid-btn { background:linear-gradient(145deg, #00B4FF, #0091EA); color:white; }
|
||||
.copy-modal-grid-btn { background:linear-gradient(145deg, #9C27B0, #673AB7); color:white; }
|
||||
.copy-modal-grid-btn.copied { background:linear-gradient(145deg, #FF9800, #F57C00); }
|
||||
.edit-modal-grid-btn { background:linear-gradient(145deg, #4CAF50, #2E7D32); color:white; }
|
||||
.delete-modal-grid-btn { background:linear-gradient(145deg, #FF4444, #CC0000); color:white; }
|
||||
|
||||
/* 编辑区 */
|
||||
.edit-section { padding:30rpx 40rpx 20rpx; border-top:1rpx solid rgba(255,255,255,0.1); margin-top:20rpx; }
|
||||
.edit-item { margin-bottom:30rpx; }
|
||||
.edit-label { font-size:26rpx; color:rgba(255,255,255,0.8); margin-bottom:15rpx; font-weight:600; }
|
||||
.edit-input { width:100%; background:rgba(255,255,255,0.08); border:1.5rpx solid rgba(255,255,255,0.2); border-radius:15rpx; padding:25rpx; font-size:28rpx; color:#FFFFFF; }
|
||||
.intro-edit { min-height:150rpx; }
|
||||
.price-edit { text-align:center; font-size:32rpx; font-weight:600; height:90rpx; line-height:90rpx; }
|
||||
.picker-view { padding:25rpx; background:rgba(255,255,255,0.08); border-radius:15rpx; border:1.5rpx solid rgba(255,255,255,0.2); color:#fff; }
|
||||
.commission-item { display:flex; align-items:center; gap:20rpx; }
|
||||
.commission-input { flex:1; background:rgba(255,255,255,0.08); border-radius:15rpx; padding:20rpx; color:#fff; }
|
||||
|
||||
/* 添加表单 */
|
||||
.add-form { padding:30rpx 40rpx 20rpx; }
|
||||
.form-item { margin-bottom:35rpx; }
|
||||
.form-label { font-size:28rpx; color:rgba(255,255,255,0.8); margin-bottom:18rpx; font-weight:600; }
|
||||
.intro-input, .price-input { width:100%; background:rgba(255,255,255,0.08); border:1.5rpx solid rgba(255,255,255,0.2); border-radius:15rpx; padding:25rpx; font-size:28rpx; color:#FFFFFF; }
|
||||
.intro-input { min-height:180rpx; }
|
||||
.price-input { height:90rpx; line-height:90rpx; text-align:center; font-weight:600; }
|
||||
.add-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:25rpx; padding:30rpx 40rpx 40rpx; border-top:1rpx solid rgba(255,255,255,0.1); }
|
||||
.cancel-grid-btn { background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.8); border:1.5rpx solid rgba(255,255,255,0.2); }
|
||||
.confirm-add-grid-btn { background:linear-gradient(145deg, #9C27B0, #673AB7); color:white; }
|
||||
|
||||
/* 确认弹窗 */
|
||||
.confirm-content {
|
||||
background:linear-gradient(145deg, rgba(40,40,60,0.95), rgba(50,50,70,0.95));
|
||||
border-radius:25rpx; padding:50rpx 40rpx 40rpx; width:85%; max-width:550rpx;
|
||||
border:1.5rpx solid rgba(255,255,255,0.15); box-shadow:0 30rpx 90rpx rgba(0,0,0,0.7); text-align:center;
|
||||
animation:scaleIn 0.3s ease;
|
||||
}
|
||||
@keyframes scaleIn { from{transform:scale(0.8); opacity:0;} to{transform:scale(1); opacity:1;} }
|
||||
.confirm-title { font-size:34rpx; font-weight:bold; color:#FFFFFF; margin-bottom:25rpx; }
|
||||
.confirm-text { font-size:28rpx; color:rgba(255,255,255,0.8); margin-bottom:40rpx; }
|
||||
.confirm-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:25rpx; }
|
||||
.confirm-grid-btn { height:85rpx; border-radius:42rpx; font-size:28rpx; font-weight:600; display:flex; align-items:center; justify-content:center; }
|
||||
.cancel-confirm-grid-btn { background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.8); border:1.5rpx solid rgba(255,255,255,0.2); }
|
||||
.delete-confirm-grid-btn { background:linear-gradient(145deg, #FF4444, #CC0000); color:white; }
|
||||
.confirm-new-link-grid-btn { background:linear-gradient(145deg, #00B4FF, #0091EA); color:white; }
|
||||
|
||||
.loading-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(18,18,24,0.95); display:flex; align-items:center; justify-content:center; z-index:10000; }
|
||||
.loading-content { background:rgba(40,40,60,0.95); padding:60rpx 80rpx; border-radius:30rpx; display:flex; flex-direction:column; align-items:center; box-shadow:0 25rpx 70rpx rgba(0,0,0,0.6); }
|
||||
.loading-spinner { width:90rpx; height:90rpx; border:8rpx solid rgba(0,180,255,0.2); border-top:8rpx solid #00B4FF; border-radius:50%; animation:spin 1.2s linear infinite; margin-bottom:35rpx; }
|
||||
.loading-text { font-size:30rpx; color:#00B4FF; font-weight:600; }
|
||||
/* pages/express-order/express-order.wxss - 增强版,包含标签展示 */
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #0a0a0f 0%, #1a1a2e 50%, #16213e 100%);
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 40rpx;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
.balance-card {
|
||||
background: linear-gradient(135deg, rgba(20,20,30,0.9), rgba(30,30,50,0.9));
|
||||
border-radius: 24rpx;
|
||||
padding: 36rpx;
|
||||
margin-bottom: 40rpx;
|
||||
color: #fff;
|
||||
box-shadow: 0 15rpx 35rpx rgba(0,0,0,0.4), 0 0 40rpx rgba(0,150,255,0.15);
|
||||
text-align: center;
|
||||
border: 1.5rpx solid rgba(0,180,255,0.2);
|
||||
backdrop-filter: blur(10rpx);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.balance-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%; left: -50%;
|
||||
width: 200%; height: 200%;
|
||||
background: linear-gradient(45deg, transparent 30%, rgba(0,180,255,0.1) 50%, transparent 70%);
|
||||
animation: cardShine 6s infinite linear;
|
||||
z-index: 1;
|
||||
}
|
||||
@keyframes cardShine {
|
||||
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
|
||||
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
|
||||
}
|
||||
.balance-label { font-size: 28rpx; color: rgba(255,255,255,0.8); margin-bottom: 18rpx; font-weight: 500; position: relative; z-index: 2; }
|
||||
.balance-amount { display: flex; align-items: baseline; justify-content: center; margin-bottom: 15rpx; position: relative; z-index: 2; }
|
||||
.amount-value { font-size: 64rpx; font-weight: bold; color: #00B4FF; text-shadow: 0 0 20rpx rgba(0,180,255,0.7), 0 0 40rpx rgba(0,180,255,0.4); animation: amountGlow 3s infinite alternate; }
|
||||
@keyframes amountGlow {
|
||||
0% { color: #00B4FF; text-shadow: 0 0 15rpx rgba(0,180,255,0.6); }
|
||||
100% { color: #00E0FF; text-shadow: 0 0 25rpx rgba(0,180,255,0.8), 0 0 50rpx rgba(0,180,255,0.5); }
|
||||
}
|
||||
.amount-unit { font-size: 36rpx; color: #00B4FF; margin-left: 12rpx; font-weight: 500; z-index: 2; }
|
||||
.balance-tip { font-size: 24rpx; color: rgba(255,255,255,0.6); z-index: 2; }
|
||||
|
||||
.section { margin-bottom: 35rpx; }
|
||||
.section-title { font-size: 32rpx; font-weight: 700; color: #FFFFFF; margin-bottom: 25rpx; padding-left: 12rpx; border-left: 6rpx solid #9C27B0; text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.3); }
|
||||
|
||||
.type-scroll { white-space: nowrap; display: flex; height: 90rpx; }
|
||||
.type-item {
|
||||
display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center;
|
||||
height: 85rpx; padding: 0 40rpx; margin-right: 20rpx;
|
||||
background: rgba(255,255,255,0.08); border-radius: 45rpx; border: 2rpx solid rgba(255,255,255,0.15);
|
||||
font-size: 28rpx; color: rgba(255,255,255,0.8);
|
||||
transition: all 0.3s cubic-bezier(0.175,0.885,0.32,1.275);
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
.type-active {
|
||||
background: linear-gradient(135deg, #9C27B0 0%, #673AB7 100%);
|
||||
border-color: #9C27B0; color: white; transform: scale(1.05);
|
||||
box-shadow: 0 10rpx 25rpx rgba(156,39,176,0.4), 0 0 30rpx rgba(156,39,176,0.3);
|
||||
}
|
||||
.type-text { max-width: 220rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
|
||||
|
||||
/* 搜索区域 */
|
||||
.search-section { margin-bottom: 35rpx; }
|
||||
.search-box {
|
||||
display: flex; align-items: center;
|
||||
background: rgba(255,255,255,0.1); border-radius: 50rpx;
|
||||
padding: 20rpx 30rpx; border: 2rpx solid rgba(255,255,255,0.2);
|
||||
backdrop-filter: blur(10rpx); transition: all 0.3s ease;
|
||||
}
|
||||
.search-box:focus-within { border-color: #9C27B0; background: rgba(255,255,255,0.15); box-shadow: 0 0 25rpx rgba(156,39,176,0.3); }
|
||||
.search-icon { font-size: 32rpx; color: rgba(255,255,255,0.7); margin-right: 20rpx; flex-shrink: 0; }
|
||||
.search-input { flex: 1; font-size: 28rpx; color: #FFFFFF; background: transparent; border: none; outline: none; min-height: 40rpx; }
|
||||
.search-input::placeholder { color: rgba(255,255,255,0.4); }
|
||||
.search-btn { background: linear-gradient(135deg, #9C27B0 0%, #673AB7 100%); border-radius: 40rpx; padding: 15rpx 30rpx; margin-left: 20rpx; flex-shrink: 0; box-shadow: 0 8rpx 20rpx rgba(156,39,176,0.3); }
|
||||
.search-btn:active { transform: scale(0.95); }
|
||||
.search-btn-text { font-size: 26rpx; color: white; font-weight: 600; }
|
||||
|
||||
.filter-row { display: flex; align-items: center; margin-top: 20rpx; gap: 15rpx; }
|
||||
.filter-item { display: flex; align-items: center; background: rgba(255,255,255,0.08); border-radius: 30rpx; padding: 10rpx 20rpx; border: 1rpx solid rgba(255,255,255,0.15); }
|
||||
.filter-label { font-size: 24rpx; color: rgba(255,255,255,0.7); margin-right: 10rpx; }
|
||||
.filter-input { width: 120rpx; height: 50rpx; background: transparent; color: #fff; font-size: 26rpx; }
|
||||
.picker-view { padding: 10rpx 0; color: rgba(255,255,255,0.9); font-size: 26rpx; max-width: 160rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.clear-search { margin-left: auto; padding: 10rpx 20rpx; background: rgba(255,255,255,0.1); border-radius: 20rpx; color: rgba(255,255,255,0.7); font-size: 24rpx; }
|
||||
|
||||
/* 模板区域 */
|
||||
.template-section { height: calc(100vh - 600rpx); position: relative; }
|
||||
.template-scroll { height: 100%; }
|
||||
.template-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 25rpx; padding-bottom: 30rpx; }
|
||||
.template-card {
|
||||
background: linear-gradient(145deg, rgba(30,30,45,0.9), rgba(40,40,60,0.9));
|
||||
border-radius: 20rpx; padding: 25rpx;
|
||||
border: 1.5rpx solid rgba(255,255,255,0.1);
|
||||
box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.3), 0 0 25rpx rgba(0,180,255,0.1);
|
||||
transition: all 0.3s ease; backdrop-filter: blur(10rpx);
|
||||
display: flex; flex-direction: column; min-height: 280rpx; position: relative; overflow: hidden;
|
||||
}
|
||||
.template-card::before { content: ''; position: absolute; top:0; left:0; right:0; height:4rpx; background: linear-gradient(90deg, #9C27B0, #00B4FF, #9C27B0); opacity:0.6; }
|
||||
.template-intro { flex:1; margin-bottom:10rpx; min-height:70rpx; overflow:hidden; }
|
||||
.intro-text { font-size:24rpx; line-height:1.4; color:rgba(255,255,255,0.9); display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden; font-weight:500; }
|
||||
.template-label { margin-bottom: 10rpx; }
|
||||
.template-price-row { display:flex; align-items:center; margin-bottom:20rpx; padding:10rpx 0; border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.template-price-label { font-size:22rpx; color:rgba(255,255,255,0.7); margin-right:10rpx; }
|
||||
.template-price-value { font-size:26rpx; font-weight:bold; color:#FFD700; text-shadow:0 0 10rpx rgba(255,215,0,0.3); flex:1; }
|
||||
.template-actions-grid { display:flex; flex-direction:column; gap:12rpx; margin-top:10rpx; }
|
||||
.action-grid-btn {
|
||||
height:65rpx; border-radius:32rpx; font-size:24rpx; font-weight:600; transition:all 0.3s ease;
|
||||
border:none; padding:0 20rpx; box-shadow:0 4rpx 12rpx rgba(0,0,0,0.2), inset 0 1rpx 0 rgba(255,255,255,0.1);
|
||||
display:flex !important; align-items:center !important; justify-content:center !important; text-align:center !important;
|
||||
}
|
||||
.generate-grid-btn { background:linear-gradient(135deg, #00B4FF, #0091EA); color:white; }
|
||||
.generate-grid-btn.generated { background:linear-gradient(135deg, #4CAF50, #2E7D32); }
|
||||
.copy-grid-btn { background:linear-gradient(135deg, #9C27B0, #673AB7); color:white; }
|
||||
.copy-grid-btn.copied { background:linear-gradient(135deg, #FF9800, #F57C00); }
|
||||
.add-card { background: linear-gradient(145deg, rgba(40,40,60,0.7), rgba(60,60,80,0.7)); border:2rpx dashed rgba(255,255,255,0.3); display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:280rpx; }
|
||||
.add-icon { font-size:60rpx; color:rgba(255,255,255,0.6); margin-bottom:20rpx; }
|
||||
.add-text { font-size:30rpx; color:rgba(255,255,255,0.8); font-weight:600; margin-bottom:8rpx; }
|
||||
.add-subtext { font-size:24rpx; color:rgba(255,255,255,0.5); }
|
||||
|
||||
/* 弹窗通用 */
|
||||
.modal-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.75); display:flex; align-items:center; justify-content:center; z-index:9999; padding:30rpx; backdrop-filter:blur(10rpx); animation:fadeIn 0.3s ease; }
|
||||
@keyframes fadeIn { from{opacity:0;} to{opacity:1;} }
|
||||
.modal-content {
|
||||
background:linear-gradient(145deg, rgba(30,30,45,0.95), rgba(40,40,60,0.95));
|
||||
border-radius:30rpx; width:100%; max-width:700rpx; max-height:85vh; overflow-y:auto;
|
||||
border:1.5rpx solid rgba(255,255,255,0.15);
|
||||
box-shadow:0 25rpx 80rpx rgba(0,0,0,0.6), 0 0 60rpx rgba(0,180,255,0.2);
|
||||
animation:slideUp 0.4s cubic-bezier(0.175,0.885,0.32,1.275);
|
||||
position:relative;
|
||||
}
|
||||
@keyframes slideUp { from{transform:translateY(100rpx) scale(0.9); opacity:0;} to{transform:translateY(0) scale(1); opacity:1;} }
|
||||
.modal-close { position:absolute; top:25rpx; right:25rpx; width:60rpx; height:60rpx; border-radius:50%; background:rgba(255,255,255,0.1); display:flex; align-items:center; justify-content:center; font-size:40rpx; color:rgba(255,255,255,0.7); z-index:10; }
|
||||
.modal-header { padding:40rpx 40rpx 20rpx; text-align:center; }
|
||||
.modal-title { font-size:36rpx; font-weight:bold; color:#FFFFFF; }
|
||||
|
||||
.detail-info { padding:30rpx 40rpx; }
|
||||
.detail-item { margin-bottom:30rpx; }
|
||||
.detail-label { font-size:26rpx; color:rgba(255,255,255,0.7); margin-bottom:10rpx; font-weight:500; }
|
||||
.detail-value { font-size:28rpx; color:#FFFFFF; word-break:break-word; }
|
||||
.intro-value { background:rgba(255,255,255,0.05); border-radius:15rpx; padding:20rpx; border:1rpx solid rgba(255,255,255,0.1); max-height:200rpx; overflow-y:auto; }
|
||||
.detail-meta-row { display:flex; align-items:center; justify-content:space-between; padding:25rpx 0; margin:20rpx 0; border-top:1rpx solid rgba(255,255,255,0.1); border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.meta-item { display:flex; flex-direction:column; align-items:center; flex:1; }
|
||||
.meta-label { font-size:22rpx; color:rgba(255,255,255,0.6); margin-bottom:8rpx; }
|
||||
.meta-value { font-size:26rpx; font-weight:600; }
|
||||
.price-meta { color:#FFD700; text-shadow:0 0 10rpx rgba(255,215,0,0.3); }
|
||||
.count-meta { color:#00B4FF; }
|
||||
.id-meta { color:#4CAF50; font-family:'Courier New',monospace; font-size:24rpx; }
|
||||
.meta-divider { color:rgba(255,255,255,0.2); font-size:24rpx; margin:0 15rpx; }
|
||||
|
||||
.link-filter-bar { display:flex; align-items:center; margin-top:30rpx; margin-bottom:20rpx; }
|
||||
.filter-switch {
|
||||
padding:10rpx 25rpx; margin-left:10rpx; border-radius:20rpx; background:rgba(255,255,255,0.1);
|
||||
font-size:24rpx; color:rgba(255,255,255,0.7); transition:all 0.3s;
|
||||
}
|
||||
.filter-switch.active { background:linear-gradient(135deg, #00B4FF, #0091EA); color:white; }
|
||||
.link-list { background:rgba(0,0,0,0.2); border-radius:15rpx; padding:15rpx; }
|
||||
.link-item { display:flex; align-items:center; justify-content:space-between; padding:15rpx 0; border-bottom:1rpx solid rgba(255,255,255,0.1); }
|
||||
.link-url { flex:1; font-size:22rpx; color:rgba(255,255,255,0.8); word-break:break-all; margin-right:15rpx; }
|
||||
.link-status { font-size:20rpx; color:rgba(255,255,255,0.5); margin-right:15rpx; }
|
||||
.copy-link-btn { padding:8rpx 20rpx; background:#00B4FF; color:white; border-radius:15rpx; font-size:22rpx; }
|
||||
.load-more-links { text-align:center; padding:20rpx 0; }
|
||||
.load-more-btn { display:inline-block; padding:15rpx 40rpx; background:linear-gradient(135deg, #9C27B0, #673AB7); border-radius:30rpx; color:white; font-size:26rpx; }
|
||||
.link-loading, .link-empty { text-align:center; padding:30rpx; color:rgba(255,255,255,0.5); font-size:24rpx; }
|
||||
|
||||
/* 弹窗按钮 */
|
||||
.modal-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:18rpx; padding:30rpx 40rpx 40rpx; border-top:1rpx solid rgba(255,255,255,0.1); }
|
||||
.modal-grid-btn {
|
||||
height:85rpx; border-radius:42rpx; font-size:28rpx; font-weight:600; transition:all 0.3s;
|
||||
border:none; padding:0 20rpx; box-shadow:0 8rpx 25rpx rgba(0,0,0,0.3), inset 0 1rpx 0 rgba(255,255,255,0.2);
|
||||
display:flex !important; align-items:center !important; justify-content:center !important;
|
||||
}
|
||||
.generate-modal-grid-btn { background:linear-gradient(145deg, #00B4FF, #0091EA); color:white; }
|
||||
.copy-modal-grid-btn { background:linear-gradient(145deg, #9C27B0, #673AB7); color:white; }
|
||||
.copy-modal-grid-btn.copied { background:linear-gradient(145deg, #FF9800, #F57C00); }
|
||||
.edit-modal-grid-btn { background:linear-gradient(145deg, #4CAF50, #2E7D32); color:white; }
|
||||
.delete-modal-grid-btn { background:linear-gradient(145deg, #FF4444, #CC0000); color:white; }
|
||||
|
||||
/* 编辑区 */
|
||||
.edit-section { padding:30rpx 40rpx 20rpx; border-top:1rpx solid rgba(255,255,255,0.1); margin-top:20rpx; }
|
||||
.edit-item { margin-bottom:30rpx; }
|
||||
.edit-label { font-size:26rpx; color:rgba(255,255,255,0.8); margin-bottom:15rpx; font-weight:600; }
|
||||
.edit-input { width:100%; background:rgba(255,255,255,0.08); border:1.5rpx solid rgba(255,255,255,0.2); border-radius:15rpx; padding:25rpx; font-size:28rpx; color:#FFFFFF; }
|
||||
.intro-edit { min-height:150rpx; }
|
||||
.price-edit { text-align:center; font-size:32rpx; font-weight:600; height:90rpx; line-height:90rpx; }
|
||||
.picker-view { padding:25rpx; background:rgba(255,255,255,0.08); border-radius:15rpx; border:1.5rpx solid rgba(255,255,255,0.2); color:#fff; }
|
||||
.commission-item { display:flex; align-items:center; gap:20rpx; }
|
||||
.commission-input { flex:1; background:rgba(255,255,255,0.08); border-radius:15rpx; padding:20rpx; color:#fff; }
|
||||
|
||||
/* 添加表单 */
|
||||
.add-form { padding:30rpx 40rpx 20rpx; }
|
||||
.form-item { margin-bottom:35rpx; }
|
||||
.form-label { font-size:28rpx; color:rgba(255,255,255,0.8); margin-bottom:18rpx; font-weight:600; }
|
||||
.intro-input, .price-input { width:100%; background:rgba(255,255,255,0.08); border:1.5rpx solid rgba(255,255,255,0.2); border-radius:15rpx; padding:25rpx; font-size:28rpx; color:#FFFFFF; }
|
||||
.intro-input { min-height:180rpx; }
|
||||
.price-input { height:90rpx; line-height:90rpx; text-align:center; font-weight:600; }
|
||||
.add-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:25rpx; padding:30rpx 40rpx 40rpx; border-top:1rpx solid rgba(255,255,255,0.1); }
|
||||
.cancel-grid-btn { background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.8); border:1.5rpx solid rgba(255,255,255,0.2); }
|
||||
.confirm-add-grid-btn { background:linear-gradient(145deg, #9C27B0, #673AB7); color:white; }
|
||||
|
||||
/* 确认弹窗 */
|
||||
.confirm-content {
|
||||
background:linear-gradient(145deg, rgba(40,40,60,0.95), rgba(50,50,70,0.95));
|
||||
border-radius:25rpx; padding:50rpx 40rpx 40rpx; width:85%; max-width:550rpx;
|
||||
border:1.5rpx solid rgba(255,255,255,0.15); box-shadow:0 30rpx 90rpx rgba(0,0,0,0.7); text-align:center;
|
||||
animation:scaleIn 0.3s ease;
|
||||
}
|
||||
@keyframes scaleIn { from{transform:scale(0.8); opacity:0;} to{transform:scale(1); opacity:1;} }
|
||||
.confirm-title { font-size:34rpx; font-weight:bold; color:#FFFFFF; margin-bottom:25rpx; }
|
||||
.confirm-text { font-size:28rpx; color:rgba(255,255,255,0.8); margin-bottom:40rpx; }
|
||||
.confirm-actions-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:25rpx; }
|
||||
.confirm-grid-btn { height:85rpx; border-radius:42rpx; font-size:28rpx; font-weight:600; display:flex; align-items:center; justify-content:center; }
|
||||
.cancel-confirm-grid-btn { background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.8); border:1.5rpx solid rgba(255,255,255,0.2); }
|
||||
.delete-confirm-grid-btn { background:linear-gradient(145deg, #FF4444, #CC0000); color:white; }
|
||||
.confirm-new-link-grid-btn { background:linear-gradient(145deg, #00B4FF, #0091EA); color:white; }
|
||||
|
||||
.loading-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(18,18,24,0.95); display:flex; align-items:center; justify-content:center; z-index:10000; }
|
||||
.loading-content { background:rgba(40,40,60,0.95); padding:60rpx 80rpx; border-radius:30rpx; display:flex; flex-direction:column; align-items:center; box-shadow:0 25rpx 70rpx rgba(0,0,0,0.6); }
|
||||
.loading-spinner { width:90rpx; height:90rpx; border:8rpx solid rgba(0,180,255,0.2); border-top:8rpx solid #00B4FF; border-radius:50%; animation:spin 1.2s linear infinite; margin-bottom:35rpx; }
|
||||
.loading-text { font-size:30rpx; color:#00B4FF; font-weight:600; }
|
||||
@keyframes spin { 0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);} }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,316 +1,316 @@
|
||||
<!-- pages/cfss/cfss.wxml -->
|
||||
<view class="cfss-container">
|
||||
<!-- 顶部统计卡片 -->
|
||||
<view class="tongji-card">
|
||||
<view class="tongji-title">处罚统计</view>
|
||||
<view class="tongji-content">
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">总记录</text>
|
||||
<text class="tongji-value">{{ zongshu }}</text>
|
||||
</view>
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">待处理</text>
|
||||
<text class="tongji-value daichuli-value">{{ daichuli }}</text>
|
||||
</view>
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">已处理</text>
|
||||
<text class="tongji-value yichuli-value">{{ yichuli }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 类型切换 -->
|
||||
<view class="leixing-qiehuan">
|
||||
<view
|
||||
class="leixing-item {{ shenfen === 0 ? 'leixing-active' : '' }}"
|
||||
bindtap="qiehuanShenfen"
|
||||
data-type="0"
|
||||
>
|
||||
<text class="leixing-text">待处理</text>
|
||||
<text class="leixing-count">{{ daichuli }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="leixing-item {{ shenfen === 1 ? 'leixing-active' : '' }}"
|
||||
bindtap="qiehuanShenfen"
|
||||
data-type="1"
|
||||
>
|
||||
<text class="leixing-text">已处理</text>
|
||||
<text class="leixing-count">{{ yichuli }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处罚记录列表 -->
|
||||
<scroll-view
|
||||
class="chufa-list"
|
||||
scroll-y
|
||||
enable-back-to-top
|
||||
scroll-with-animation
|
||||
style="height: {{ scrollHeight }}px"
|
||||
bindscrolltolower="shanglaShuaxin"
|
||||
>
|
||||
<!-- 加载中 -->
|
||||
<view wx:if="{{ jiazhaozhong && chufaList.length === 0 }}" class="jiazai-zhong">
|
||||
<view class="loading-animation">
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
</view>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 🔴【关键修改】处罚记录卡片列表 - 直接使用处理好的字段 -->
|
||||
<block wx:for="{{ chufaList }}" wx:key="index">
|
||||
<view
|
||||
class="chufa-card"
|
||||
bindtap="chakanXiangqing"
|
||||
data-item="{{ item }}"
|
||||
>
|
||||
<!-- 卡片顶部:时间和状态 -->
|
||||
<view class="card-top">
|
||||
<!-- 🔴 直接使用display_time -->
|
||||
<text class="shijian">{{ item.display_time }}</text>
|
||||
<!-- 🔴 直接使用display_status和status_class -->
|
||||
<view class="zhuangtai-badge {{ item.status_class }}">
|
||||
{{ item.display_status }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请人信息 -->
|
||||
<view class="qingqiu-row">
|
||||
<text class="qingqiu-label">申请人:</text>
|
||||
<text class="qingqiu-value">{{ item.qingqiuid || '--' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 处罚理由 -->
|
||||
<view class="liyou-row">
|
||||
<text class="liyou-label">处罚理由:</text>
|
||||
<text class="liyou-value">{{ item.cfliyou || '无' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 订单编号 -->
|
||||
<view class="dingdan-row">
|
||||
<text class="dingdan-label">订单编号:</text>
|
||||
<text class="dingdan-value">{{ item.dingdan_id || '--' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 卡片边框效果 -->
|
||||
<view class="card-border"></view>
|
||||
<view class="card-glow"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view wx:if="{{ jiazhaigengduo }}" class="jiazai-gengduo">
|
||||
<view class="scan-line"></view>
|
||||
<text>加载更多...</text>
|
||||
</view>
|
||||
|
||||
<!-- 没有更多数据 -->
|
||||
<view wx:if="{{ !haiyougengduo && chufaList.length > 0 }}" class="meiyou-gengduo">
|
||||
<text>—— 没有更多记录了 ——</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{ !jiazhaozhong && chufaList.length === 0 }}" class="kong-zhuangtai">
|
||||
<view class="empty-icon">⚡</view>
|
||||
<text class="empty-text">暂无处罚记录</text>
|
||||
<text class="empty-subtext">所有事务已处理完毕</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 处罚详情弹窗 -->
|
||||
<view wx:if="{{ showXiangqing }}" class="xiangqing-modal">
|
||||
<view class="modal-mask" bindtap="guanbiXiangqing"></view>
|
||||
<view class="modal-content">
|
||||
<!-- 弹窗头部 -->
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">处罚详情</text>
|
||||
<view class="modal-close" bindtap="guanbiXiangqing">
|
||||
<text class="close-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 🔴【弹窗主体 - 确保可以滚动】 -->
|
||||
<scroll-view class="modal-body" scroll-y style="max-height: 1000rpx;">
|
||||
<!-- 基本信息 -->
|
||||
<view class="detail-section">
|
||||
<view class="section-title">基本信息</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">订单编号:</text>
|
||||
<view class="detail-value-container">
|
||||
<text class="detail-value">{{ xuanzhongChufa.dingdan_id || '--' }}</text>
|
||||
<text class="fuzhi-btn" bindtap="fuzhiWenben" data-text="{{ xuanzhongChufa.dingdan_id }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">申请人ID:</text>
|
||||
<view class="detail-value-container">
|
||||
<text class="detail-value">{{ xuanzhongChufa.qingqiuid || '--' }}</text>
|
||||
<text class="fuzhi-btn" bindtap="fuzhiWenben" data-text="{{ xuanzhongChufa.qingqiuid }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<!-- 🔴 直接使用display_time -->
|
||||
<text class="detail-label">创建时间:</text>
|
||||
<text class="detail-value">{{ xuanzhongChufa.display_time || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处罚信息 -->
|
||||
<view class="detail-section">
|
||||
<view class="section-title">处罚信息</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">处罚状态:</text>
|
||||
<!-- 🔴 直接使用display_status和status_class -->
|
||||
<view class="zhuangtai-badge-inline {{ xuanzhongChufa.status_class }}">
|
||||
{{ xuanzhongChufa.display_status }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row full-row">
|
||||
<text class="detail-label">处罚理由:</text>
|
||||
<text class="detail-value liyou-full">{{ xuanzhongChufa.cfliyou || '无' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 🔴 证据图片展示 - 直接使用full_zhengju_tupian -->
|
||||
<view wx:if="{{ xuanzhongChufa.full_zhengju_tupian && xuanzhongChufa.full_zhengju_tupian.length > 0 }}" class="detail-row full-row">
|
||||
<text class="detail-label">证据图片:</text>
|
||||
<view class="tupian-grid">
|
||||
<block wx:for="{{ xuanzhongChufa.full_zhengju_tupian }}" wx:key="index">
|
||||
<view class="tupian-item" bindtap="yulanTupian" data-url="{{ item }}" data-urls="{{ xuanzhongChufa.full_zhengju_tupian }}">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉信息 -->
|
||||
<view wx:if="{{ xuanzhongChufa.ssliyou || (xuanzhongChufa.full_shensu_tupian && xuanzhongChufa.full_shensu_tupian.length > 0) }}" class="detail-section">
|
||||
<view class="section-title">申诉信息</view>
|
||||
<view wx:if="{{ xuanzhongChufa.ssliyou }}" class="detail-row full-row">
|
||||
<text class="detail-label">申诉理由:</text>
|
||||
<text class="detail-value liyou-full">{{ xuanzhongChufa.ssliyou }}</text>
|
||||
</view>
|
||||
<!-- 🔴 申诉图片展示 - 直接使用full_shensu_tupian -->
|
||||
<view wx:if="{{ xuanzhongChufa.full_shensu_tupian && xuanzhongChufa.full_shensu_tupian.length > 0 }}" class="detail-row full-row">
|
||||
<text class="detail-label">申诉图片:</text>
|
||||
<view class="tupian-grid">
|
||||
<block wx:for="{{ xuanzhongChufa.full_shensu_tupian }}" wx:key="index">
|
||||
<view class="tupian-item" bindtap="yulanTupian" data-url="{{ item }}" data-urls="{{ xuanzhongChufa.full_shensu_tupian }}">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 弹窗底部按钮 -->
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<!-- 联系客服按钮(始终显示) -->
|
||||
<view class="btn btn-kefu" bindtap="lianxiKefu">
|
||||
<text>联系客服</text>
|
||||
</view>
|
||||
<!-- 申诉按钮(只有待处罚状态可点击) -->
|
||||
<view
|
||||
class="btn {{ xuanzhongChufa.sqzhuangtai === 0 ? 'btn-shensu' : 'btn-shensu-disabled' }}"
|
||||
bindtap="{{ xuanzhongChufa.sqzhuangtai === 0 ? 'openShensuModal' : '' }}"
|
||||
>
|
||||
<text>申诉</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉弹窗 -->
|
||||
<view wx:if="{{ showShensuModal }}" class="shensu-modal">
|
||||
<view class="modal-mask" bindtap="closeShensuModal"></view>
|
||||
<view class="modal-content small-modal">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">提交申诉</text>
|
||||
</view>
|
||||
<view class="modal-body">
|
||||
<!-- 申诉理由输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">申诉理由</view>
|
||||
<textarea
|
||||
class="shensu-textarea"
|
||||
value="{{ shensuLiyou }}"
|
||||
bindinput="onShensuLiyouInput"
|
||||
placeholder="请输入申诉理由(最多500字)..."
|
||||
maxlength="500"
|
||||
auto-height
|
||||
/>
|
||||
<view class="word-count">{{ shensuLiyou.length }}/500</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉图片上传 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">申诉图片</view>
|
||||
<view class="upload-tip">最多可上传9张图片</view>
|
||||
|
||||
<!-- 图片网格 -->
|
||||
<view class="tupian-grid-upload">
|
||||
<!-- 已上传图片 -->
|
||||
<block wx:for="{{ shensuTupian }}" wx:key="index">
|
||||
<view class="tupian-item-upload">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image-upload"
|
||||
mode="aspectFill"
|
||||
bindtap="yulanShensuTupian"
|
||||
data-index="{{ index }}"
|
||||
/>
|
||||
<view class="tupian-delete" bindtap="deleteShensuTupian" data-index="{{ index }}">
|
||||
<text>×</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 添加按钮 -->
|
||||
<view
|
||||
wx:if="{{ shensuTupian.length < 9 }}"
|
||||
class="tupian-add-btn"
|
||||
bindtap="chooseShensuTupian"
|
||||
>
|
||||
<view class="add-icon">+</view>
|
||||
<text class="add-text">添加图片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上传进度 -->
|
||||
<view wx:if="{{ shangchuanZongshu > 0 }}" class="upload-progress">
|
||||
<view class="progress-title">上传进度</view>
|
||||
<view class="progress-bar">
|
||||
<view class="progress-inner" style="width: {{ jinduWidth }}"></view>
|
||||
</view>
|
||||
<view class="progress-text">{{ shangchuanJindu }}/{{ shangchuanZongshu }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<view class="btn btn-quxiao" bindtap="closeShensuModal">
|
||||
<text>取消</text>
|
||||
</view>
|
||||
<view class="btn btn-queren" bindtap="submitShensu">
|
||||
<text>提交申诉</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 全局通知组件 -->
|
||||
<global-notification id="global-notification" />
|
||||
<!-- pages/penalty/penalty.wxml -->
|
||||
<view class="cfss-container">
|
||||
<!-- 顶部统计卡片 -->
|
||||
<view class="tongji-card">
|
||||
<view class="tongji-title">处罚统计</view>
|
||||
<view class="tongji-content">
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">总记录</text>
|
||||
<text class="tongji-value">{{ zongshu }}</text>
|
||||
</view>
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">待处理</text>
|
||||
<text class="tongji-value daichuli-value">{{ daichuli }}</text>
|
||||
</view>
|
||||
<view class="tongji-item">
|
||||
<text class="tongji-label">已处理</text>
|
||||
<text class="tongji-value yichuli-value">{{ yichuli }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 类型切换 -->
|
||||
<view class="leixing-qiehuan">
|
||||
<view
|
||||
class="leixing-item {{ shenfen === 0 ? 'leixing-active' : '' }}"
|
||||
bindtap="qiehuanShenfen"
|
||||
data-type="0"
|
||||
>
|
||||
<text class="leixing-text">待处理</text>
|
||||
<text class="leixing-count">{{ daichuli }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="leixing-item {{ shenfen === 1 ? 'leixing-active' : '' }}"
|
||||
bindtap="qiehuanShenfen"
|
||||
data-type="1"
|
||||
>
|
||||
<text class="leixing-text">已处理</text>
|
||||
<text class="leixing-count">{{ yichuli }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处罚记录列表 -->
|
||||
<scroll-view
|
||||
class="chufa-list"
|
||||
scroll-y
|
||||
enable-back-to-top
|
||||
scroll-with-animation
|
||||
style="height: {{ scrollHeight }}px"
|
||||
bindscrolltolower="shanglaShuaxin"
|
||||
>
|
||||
<!-- 加载中 -->
|
||||
<view wx:if="{{ jiazhaozhong && chufaList.length === 0 }}" class="jiazai-zhong">
|
||||
<view class="loading-animation">
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
</view>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 🔴【关键修改】处罚记录卡片列表 - 直接使用处理好的字段 -->
|
||||
<block wx:for="{{ chufaList }}" wx:key="index">
|
||||
<view
|
||||
class="chufa-card"
|
||||
bindtap="chakanXiangqing"
|
||||
data-item="{{ item }}"
|
||||
>
|
||||
<!-- 卡片顶部:时间和状态 -->
|
||||
<view class="card-top">
|
||||
<!-- 🔴 直接使用display_time -->
|
||||
<text class="shijian">{{ item.display_time }}</text>
|
||||
<!-- 🔴 直接使用display_status和status_class -->
|
||||
<view class="zhuangtai-badge {{ item.status_class }}">
|
||||
{{ item.display_status }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请人信息 -->
|
||||
<view class="qingqiu-row">
|
||||
<text class="qingqiu-label">申请人:</text>
|
||||
<text class="qingqiu-value">{{ item.qingqiuid || '--' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 处罚理由 -->
|
||||
<view class="liyou-row">
|
||||
<text class="liyou-label">处罚理由:</text>
|
||||
<text class="liyou-value">{{ item.cfliyou || '无' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 订单编号 -->
|
||||
<view class="dingdan-row">
|
||||
<text class="dingdan-label">订单编号:</text>
|
||||
<text class="dingdan-value">{{ item.dingdan_id || '--' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 卡片边框效果 -->
|
||||
<view class="card-border"></view>
|
||||
<view class="card-glow"></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view wx:if="{{ jiazhaigengduo }}" class="jiazai-gengduo">
|
||||
<view class="scan-line"></view>
|
||||
<text>加载更多...</text>
|
||||
</view>
|
||||
|
||||
<!-- 没有更多数据 -->
|
||||
<view wx:if="{{ !haiyougengduo && chufaList.length > 0 }}" class="meiyou-gengduo">
|
||||
<text>—— 没有更多记录了 ——</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{ !jiazhaozhong && chufaList.length === 0 }}" class="kong-zhuangtai">
|
||||
<view class="empty-icon">⚡</view>
|
||||
<text class="empty-text">暂无处罚记录</text>
|
||||
<text class="empty-subtext">所有事务已处理完毕</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 处罚详情弹窗 -->
|
||||
<view wx:if="{{ showXiangqing }}" class="xiangqing-modal">
|
||||
<view class="modal-mask" bindtap="guanbiXiangqing"></view>
|
||||
<view class="modal-content">
|
||||
<!-- 弹窗头部 -->
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">处罚详情</text>
|
||||
<view class="modal-close" bindtap="guanbiXiangqing">
|
||||
<text class="close-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 🔴【弹窗主体 - 确保可以滚动】 -->
|
||||
<scroll-view class="modal-body" scroll-y style="max-height: 1000rpx;">
|
||||
<!-- 基本信息 -->
|
||||
<view class="detail-section">
|
||||
<view class="section-title">基本信息</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">订单编号:</text>
|
||||
<view class="detail-value-container">
|
||||
<text class="detail-value">{{ xuanzhongChufa.dingdan_id || '--' }}</text>
|
||||
<text class="fuzhi-btn" bindtap="fuzhiWenben" data-text="{{ xuanzhongChufa.dingdan_id }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">申请人ID:</text>
|
||||
<view class="detail-value-container">
|
||||
<text class="detail-value">{{ xuanzhongChufa.qingqiuid || '--' }}</text>
|
||||
<text class="fuzhi-btn" bindtap="fuzhiWenben" data-text="{{ xuanzhongChufa.qingqiuid }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<!-- 🔴 直接使用display_time -->
|
||||
<text class="detail-label">创建时间:</text>
|
||||
<text class="detail-value">{{ xuanzhongChufa.display_time || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处罚信息 -->
|
||||
<view class="detail-section">
|
||||
<view class="section-title">处罚信息</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">处罚状态:</text>
|
||||
<!-- 🔴 直接使用display_status和status_class -->
|
||||
<view class="zhuangtai-badge-inline {{ xuanzhongChufa.status_class }}">
|
||||
{{ xuanzhongChufa.display_status }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-row full-row">
|
||||
<text class="detail-label">处罚理由:</text>
|
||||
<text class="detail-value liyou-full">{{ xuanzhongChufa.cfliyou || '无' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 🔴 证据图片展示 - 直接使用full_zhengju_tupian -->
|
||||
<view wx:if="{{ xuanzhongChufa.full_zhengju_tupian && xuanzhongChufa.full_zhengju_tupian.length > 0 }}" class="detail-row full-row">
|
||||
<text class="detail-label">证据图片:</text>
|
||||
<view class="tupian-grid">
|
||||
<block wx:for="{{ xuanzhongChufa.full_zhengju_tupian }}" wx:key="index">
|
||||
<view class="tupian-item" bindtap="yulanTupian" data-url="{{ item }}" data-urls="{{ xuanzhongChufa.full_zhengju_tupian }}">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉信息 -->
|
||||
<view wx:if="{{ xuanzhongChufa.ssliyou || (xuanzhongChufa.full_shensu_tupian && xuanzhongChufa.full_shensu_tupian.length > 0) }}" class="detail-section">
|
||||
<view class="section-title">申诉信息</view>
|
||||
<view wx:if="{{ xuanzhongChufa.ssliyou }}" class="detail-row full-row">
|
||||
<text class="detail-label">申诉理由:</text>
|
||||
<text class="detail-value liyou-full">{{ xuanzhongChufa.ssliyou }}</text>
|
||||
</view>
|
||||
<!-- 🔴 申诉图片展示 - 直接使用full_shensu_tupian -->
|
||||
<view wx:if="{{ xuanzhongChufa.full_shensu_tupian && xuanzhongChufa.full_shensu_tupian.length > 0 }}" class="detail-row full-row">
|
||||
<text class="detail-label">申诉图片:</text>
|
||||
<view class="tupian-grid">
|
||||
<block wx:for="{{ xuanzhongChufa.full_shensu_tupian }}" wx:key="index">
|
||||
<view class="tupian-item" bindtap="yulanTupian" data-url="{{ item }}" data-urls="{{ xuanzhongChufa.full_shensu_tupian }}">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 弹窗底部按钮 -->
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<!-- 联系客服按钮(始终显示) -->
|
||||
<view class="btn btn-kefu" bindtap="lianxiKefu">
|
||||
<text>联系客服</text>
|
||||
</view>
|
||||
<!-- 申诉按钮(只有待处罚状态可点击) -->
|
||||
<view
|
||||
class="btn {{ xuanzhongChufa.sqzhuangtai === 0 ? 'btn-shensu' : 'btn-shensu-disabled' }}"
|
||||
bindtap="{{ xuanzhongChufa.sqzhuangtai === 0 ? 'openShensuModal' : '' }}"
|
||||
>
|
||||
<text>申诉</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉弹窗 -->
|
||||
<view wx:if="{{ showShensuModal }}" class="shensu-modal">
|
||||
<view class="modal-mask" bindtap="closeShensuModal"></view>
|
||||
<view class="modal-content small-modal">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">提交申诉</text>
|
||||
</view>
|
||||
<view class="modal-body">
|
||||
<!-- 申诉理由输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">申诉理由</view>
|
||||
<textarea
|
||||
class="shensu-textarea"
|
||||
value="{{ shensuLiyou }}"
|
||||
bindinput="onShensuLiyouInput"
|
||||
placeholder="请输入申诉理由(最多500字)..."
|
||||
maxlength="500"
|
||||
auto-height
|
||||
/>
|
||||
<view class="word-count">{{ shensuLiyou.length }}/500</view>
|
||||
</view>
|
||||
|
||||
<!-- 申诉图片上传 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">申诉图片</view>
|
||||
<view class="upload-tip">最多可上传9张图片</view>
|
||||
|
||||
<!-- 图片网格 -->
|
||||
<view class="tupian-grid-upload">
|
||||
<!-- 已上传图片 -->
|
||||
<block wx:for="{{ shensuTupian }}" wx:key="index">
|
||||
<view class="tupian-item-upload">
|
||||
<image
|
||||
src="{{ item }}"
|
||||
class="tupian-image-upload"
|
||||
mode="aspectFill"
|
||||
bindtap="yulanShensuTupian"
|
||||
data-index="{{ index }}"
|
||||
/>
|
||||
<view class="tupian-delete" bindtap="deleteShensuTupian" data-index="{{ index }}">
|
||||
<text>×</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 添加按钮 -->
|
||||
<view
|
||||
wx:if="{{ shensuTupian.length < 9 }}"
|
||||
class="tupian-add-btn"
|
||||
bindtap="chooseShensuTupian"
|
||||
>
|
||||
<view class="add-icon">+</view>
|
||||
<text class="add-text">添加图片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上传进度 -->
|
||||
<view wx:if="{{ shangchuanZongshu > 0 }}" class="upload-progress">
|
||||
<view class="progress-title">上传进度</view>
|
||||
<view class="progress-bar">
|
||||
<view class="progress-inner" style="width: {{ jinduWidth }}"></view>
|
||||
</view>
|
||||
<view class="progress-text">{{ shangchuanJindu }}/{{ shangchuanZongshu }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<view class="btn btn-quxiao" bindtap="closeShensuModal">
|
||||
<text>取消</text>
|
||||
</view>
|
||||
<view class="btn btn-queren" bindtap="submitShensu">
|
||||
<text>提交申诉</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 全局通知组件 -->
|
||||
<global-notification id="global-notification" />
|
||||
</view>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,307 +1,307 @@
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 商品类型
|
||||
shangpinleixing: [],
|
||||
xuanzhongLeixingId: null,
|
||||
|
||||
// 订单类型: normal 普通, peihu 陪护
|
||||
orderType: 'normal',
|
||||
|
||||
// 搜索关键字
|
||||
searchKeyword: '',
|
||||
|
||||
// 状态列表(增加全部)
|
||||
statusList: [
|
||||
{ name: '全部', key: 'all', zhuangtaiList: [], color: '#333333' },
|
||||
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
|
||||
{ name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#FF9800' },
|
||||
{ name: '已退款', key: 'yituikuan', zhuangtaiList: [5], color: '#9E9E9E' },
|
||||
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
|
||||
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
|
||||
{ name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' }
|
||||
],
|
||||
currentStatusKey: 'all',
|
||||
|
||||
// 每个状态独立的数据集
|
||||
dsDingdanShuju: {
|
||||
all: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
|
||||
},
|
||||
|
||||
currentList: [],
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
defaultImg: '/images/default-order.png',
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '我的接单' });
|
||||
this.loadShangpinLeixing();
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
if (wx.getStorageSync('uid')) {
|
||||
reconnectForRole('dashou');
|
||||
if (app.startImWhenReady) app.startImWhenReady();
|
||||
}
|
||||
if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
}
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 加载商品类型(图片拼接)
|
||||
async loadShangpinLeixing() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/dsqdhqddlx',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' }
|
||||
});
|
||||
if (res.data && (res.data.code === 200 || res.data.code === 0)) {
|
||||
let list = res.data.data.list || res.data.data || [];
|
||||
if (!Array.isArray(list)) list = [];
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processed = list.map(item => ({
|
||||
...item,
|
||||
full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http')
|
||||
? oss + item.tupian_url
|
||||
: (item.tupian_url || '/images/default-type.png')
|
||||
}));
|
||||
this.setData({
|
||||
shangpinleixing: processed,
|
||||
xuanzhongLeixingId: processed[0]?.id || null
|
||||
});
|
||||
this.loadCurrentStatusOrders(true);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载商品类型失败', e);
|
||||
}
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
if (id === this.data.xuanzhongLeixingId) return;
|
||||
this.setData({ xuanzhongLeixingId: id });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
switchOrderType(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
if (type === this.data.orderType) return;
|
||||
this.setData({ orderType: type });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({ searchKeyword: e.detail.value });
|
||||
if (this._searchTimer) clearTimeout(this._searchTimer);
|
||||
this._searchTimer = setTimeout(() => {
|
||||
this.onSearchConfirm();
|
||||
}, 500);
|
||||
},
|
||||
|
||||
onSearchConfirm() {
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.setData({ searchKeyword: '' });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
switchStatus(e) {
|
||||
const key = e.currentTarget.dataset.key;
|
||||
if (key === this.data.currentStatusKey) return;
|
||||
this.setData({ currentStatusKey: key });
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
} else {
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载订单(核心)
|
||||
async loadCurrentStatusOrders(isRefresh = false) {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading) return;
|
||||
const page = isRefresh ? 1 : tabData.page;
|
||||
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.isLoading`]: true,
|
||||
isLoading: true,
|
||||
isLoadingMore: !isRefresh
|
||||
});
|
||||
|
||||
try {
|
||||
const apiUrl = this.data.orderType === 'peihu'
|
||||
? '/dingdan/phddlbhq'
|
||||
: '/dingdan/dshqdingdan';
|
||||
|
||||
const statusItem = this.data.statusList.find(s => s.key === key);
|
||||
const zhuangtaiList = statusItem.zhuangtaiList.length > 0 ? statusItem.zhuangtaiList : undefined;
|
||||
const params = {
|
||||
zhuangtai_list: zhuangtaiList,
|
||||
page: page,
|
||||
page_size: 5,
|
||||
leixing_id: this.data.xuanzhongLeixingId,
|
||||
keyword: this.data.searchKeyword || undefined
|
||||
};
|
||||
|
||||
const res = await request({
|
||||
url: apiUrl,
|
||||
method: 'POST',
|
||||
data: params,
|
||||
header: { 'content-type': 'application/json' }
|
||||
});
|
||||
|
||||
const code = res.data.code;
|
||||
if (code === 200 || code === 0) {
|
||||
const newList = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more || false;
|
||||
|
||||
// ✅ 图片URL拼接(核心)
|
||||
const processed = newList.map(item => ({
|
||||
...item,
|
||||
zhuangtaiZh: this.getZhuangtaiZh(item.zhuangtai),
|
||||
zhuangtaiColor: statusItem.color,
|
||||
tupian: item.tupian
|
||||
? (item.tupian.startsWith('http') ? item.tupian : this.data.ossImageUrl + item.tupian)
|
||||
: this.data.defaultImg
|
||||
}));
|
||||
|
||||
const currentList = this.data.dsDingdanShuju[key].list;
|
||||
const updatedList = isRefresh ? processed : [...currentList, ...processed];
|
||||
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.list`]: updatedList,
|
||||
[`dsDingdanShuju.${key}.page`]: page,
|
||||
[`dsDingdanShuju.${key}.hasMore`]: hasMore,
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
} else {
|
||||
throw new Error(res.data.msg || '加载失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载订单失败', err);
|
||||
wx.showToast({ title: err.message || '加载失败', icon: 'none' });
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
refreshCurrentListView() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
this.setData({
|
||||
currentList: tabData.list,
|
||||
hasMore: tabData.hasMore,
|
||||
isLoading: tabData.isLoading
|
||||
});
|
||||
},
|
||||
|
||||
resetCurrentStatusData() {
|
||||
const key = this.data.currentStatusKey;
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.list`]: [],
|
||||
[`dsDingdanShuju.${key}.page`]: 1,
|
||||
[`dsDingdanShuju.${key}.hasMore`]: true,
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
},
|
||||
|
||||
// 下拉刷新(由 scroll-view 触发)
|
||||
onPullDownRefresh() {
|
||||
if (this.data.isLoading) {
|
||||
this.setData({ scrollViewRefreshing: false });
|
||||
return;
|
||||
}
|
||||
this.setData({ scrollViewRefreshing: true });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
// 上拉加载更多(由 scroll-view 触发)
|
||||
onReachBottom() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`dsDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// ✅ 手动点击“加载更多”按钮
|
||||
onLoadMoreTap() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`dsDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
getZhuangtaiZh(zhuangtai) {
|
||||
const map = {
|
||||
1: '已下单', 2: '进行中', 3: '已完成',
|
||||
4: '退款中', 5: '已退款', 6: '退款失败',
|
||||
7: '指定中', 8: '结算中'
|
||||
};
|
||||
return map[zhuangtai] || '未知状态';
|
||||
},
|
||||
|
||||
goToDsDingdanXiangqing(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
const dataStr = encodeURIComponent(JSON.stringify(item));
|
||||
|
||||
if (this.data.orderType === 'peihu') {
|
||||
wx.navigateTo({
|
||||
url: `/pages/peihuDingdan/peihuDingdan?dingdanData=${dataStr}`
|
||||
});
|
||||
} else {
|
||||
wx.navigateTo({
|
||||
url: `/pages/dsddxq/dsddxq?dingdanData=${dataStr}`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onImageError() {}
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 商品类型
|
||||
shangpinleixing: [],
|
||||
xuanzhongLeixingId: null,
|
||||
|
||||
// 订单类型: normal 普通, peihu 陪护
|
||||
orderType: 'normal',
|
||||
|
||||
// 搜索关键字
|
||||
searchKeyword: '',
|
||||
|
||||
// 状态列表(增加全部)
|
||||
statusList: [
|
||||
{ name: '全部', key: 'all', zhuangtaiList: [], color: '#333333' },
|
||||
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
|
||||
{ name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#FF9800' },
|
||||
{ name: '已退款', key: 'yituikuan', zhuangtaiList: [5], color: '#9E9E9E' },
|
||||
{ name: '退款失败', key: 'tuikuanshibai', zhuangtaiList: [6], color: '#F44336' },
|
||||
{ name: '已完成', key: 'yiwancheng', zhuangtaiList: [3], color: '#4CAF50' },
|
||||
{ name: '结算中', key: 'jiesuanzhong', zhuangtaiList: [8], color: '#FF5722' }
|
||||
],
|
||||
currentStatusKey: 'all',
|
||||
|
||||
// 每个状态独立的数据集
|
||||
dsDingdanShuju: {
|
||||
all: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
|
||||
},
|
||||
|
||||
currentList: [],
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
defaultImg: '/images/default-order.png',
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '我的接单' });
|
||||
this.loadShangpinLeixing();
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
if (wx.getStorageSync('uid')) {
|
||||
reconnectForRole('dashou');
|
||||
if (app.startImWhenReady) app.startImWhenReady();
|
||||
}
|
||||
if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
}
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 加载商品类型(图片拼接)
|
||||
async loadShangpinLeixing() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/dsqdhqddlx',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' }
|
||||
});
|
||||
if (res.data && (res.data.code === 200 || res.data.code === 0)) {
|
||||
let list = res.data.data.list || res.data.data || [];
|
||||
if (!Array.isArray(list)) list = [];
|
||||
const oss = this.data.ossImageUrl;
|
||||
const processed = list.map(item => ({
|
||||
...item,
|
||||
full_tupian_url: item.tupian_url && !item.tupian_url.startsWith('http')
|
||||
? oss + item.tupian_url
|
||||
: (item.tupian_url || '/images/default-type.png')
|
||||
}));
|
||||
this.setData({
|
||||
shangpinleixing: processed,
|
||||
xuanzhongLeixingId: processed[0]?.id || null
|
||||
});
|
||||
this.loadCurrentStatusOrders(true);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载商品类型失败', e);
|
||||
}
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
if (id === this.data.xuanzhongLeixingId) return;
|
||||
this.setData({ xuanzhongLeixingId: id });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
switchOrderType(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
if (type === this.data.orderType) return;
|
||||
this.setData({ orderType: type });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({ searchKeyword: e.detail.value });
|
||||
if (this._searchTimer) clearTimeout(this._searchTimer);
|
||||
this._searchTimer = setTimeout(() => {
|
||||
this.onSearchConfirm();
|
||||
}, 500);
|
||||
},
|
||||
|
||||
onSearchConfirm() {
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.setData({ searchKeyword: '' });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
switchStatus(e) {
|
||||
const key = e.currentTarget.dataset.key;
|
||||
if (key === this.data.currentStatusKey) return;
|
||||
this.setData({ currentStatusKey: key });
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
} else {
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载订单(核心)
|
||||
async loadCurrentStatusOrders(isRefresh = false) {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading) return;
|
||||
const page = isRefresh ? 1 : tabData.page;
|
||||
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.isLoading`]: true,
|
||||
isLoading: true,
|
||||
isLoadingMore: !isRefresh
|
||||
});
|
||||
|
||||
try {
|
||||
const apiUrl = this.data.orderType === 'peihu'
|
||||
? '/dingdan/phddlbhq'
|
||||
: '/dingdan/dshqdingdan';
|
||||
|
||||
const statusItem = this.data.statusList.find(s => s.key === key);
|
||||
const zhuangtaiList = statusItem.zhuangtaiList.length > 0 ? statusItem.zhuangtaiList : undefined;
|
||||
const params = {
|
||||
zhuangtai_list: zhuangtaiList,
|
||||
page: page,
|
||||
page_size: 5,
|
||||
leixing_id: this.data.xuanzhongLeixingId,
|
||||
keyword: this.data.searchKeyword || undefined
|
||||
};
|
||||
|
||||
const res = await request({
|
||||
url: apiUrl,
|
||||
method: 'POST',
|
||||
data: params,
|
||||
header: { 'content-type': 'application/json' }
|
||||
});
|
||||
|
||||
const code = res.data.code;
|
||||
if (code === 200 || code === 0) {
|
||||
const newList = res.data.data.list || [];
|
||||
const hasMore = res.data.data.has_more || false;
|
||||
|
||||
// ✅ 图片URL拼接(核心)
|
||||
const processed = newList.map(item => ({
|
||||
...item,
|
||||
zhuangtaiZh: this.getZhuangtaiZh(item.zhuangtai),
|
||||
zhuangtaiColor: statusItem.color,
|
||||
tupian: item.tupian
|
||||
? (item.tupian.startsWith('http') ? item.tupian : this.data.ossImageUrl + item.tupian)
|
||||
: this.data.defaultImg
|
||||
}));
|
||||
|
||||
const currentList = this.data.dsDingdanShuju[key].list;
|
||||
const updatedList = isRefresh ? processed : [...currentList, ...processed];
|
||||
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.list`]: updatedList,
|
||||
[`dsDingdanShuju.${key}.page`]: page,
|
||||
[`dsDingdanShuju.${key}.hasMore`]: hasMore,
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
} else {
|
||||
throw new Error(res.data.msg || '加载失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载订单失败', err);
|
||||
wx.showToast({ title: err.message || '加载失败', icon: 'none' });
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
refreshCurrentListView() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
this.setData({
|
||||
currentList: tabData.list,
|
||||
hasMore: tabData.hasMore,
|
||||
isLoading: tabData.isLoading
|
||||
});
|
||||
},
|
||||
|
||||
resetCurrentStatusData() {
|
||||
const key = this.data.currentStatusKey;
|
||||
this.setData({
|
||||
[`dsDingdanShuju.${key}.list`]: [],
|
||||
[`dsDingdanShuju.${key}.page`]: 1,
|
||||
[`dsDingdanShuju.${key}.hasMore`]: true,
|
||||
[`dsDingdanShuju.${key}.isLoading`]: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
},
|
||||
|
||||
// 下拉刷新(由 scroll-view 触发)
|
||||
onPullDownRefresh() {
|
||||
if (this.data.isLoading) {
|
||||
this.setData({ scrollViewRefreshing: false });
|
||||
return;
|
||||
}
|
||||
this.setData({ scrollViewRefreshing: true });
|
||||
this.resetCurrentStatusData();
|
||||
this.loadCurrentStatusOrders(true);
|
||||
},
|
||||
|
||||
// 上拉加载更多(由 scroll-view 触发)
|
||||
onReachBottom() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`dsDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// ✅ 手动点击“加载更多”按钮
|
||||
onLoadMoreTap() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.dsDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`dsDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
getZhuangtaiZh(zhuangtai) {
|
||||
const map = {
|
||||
1: '已下单', 2: '进行中', 3: '已完成',
|
||||
4: '退款中', 5: '已退款', 6: '退款失败',
|
||||
7: '指定中', 8: '结算中'
|
||||
};
|
||||
return map[zhuangtai] || '未知状态';
|
||||
},
|
||||
|
||||
goToDsDingdanXiangqing(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
const dataStr = encodeURIComponent(JSON.stringify(item));
|
||||
|
||||
if (this.data.orderType === 'peihu') {
|
||||
wx.navigateTo({
|
||||
url: `/pages/escort-orders/escort-orders?dingdanData=${dataStr}`
|
||||
});
|
||||
} else {
|
||||
wx.navigateTo({
|
||||
url: `/pages/fighter-order-detail/fighter-order-detail?dingdanData=${dataStr}`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onImageError() {}
|
||||
});
|
||||
@@ -281,9 +281,7 @@ page {
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.empty-img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
@@ -132,8 +132,6 @@ page {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
.state-img {
|
||||
width: 160rpx; height: 160rpx;
|
||||
margin-bottom: 20rpx;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,15 +4,9 @@ page {
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
/* .page-bg 与全局相同,仅保留差异 */
|
||||
.page-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.42;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.unreg-area {
|
||||
@@ -50,31 +44,26 @@ page {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* .unreg-input 与 .input-rounded 类似,仅保留差异 */
|
||||
.unreg-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.ph { color: #999; }
|
||||
|
||||
/* .unreg-btn 与 .btn .btn-secondary 类似,仅保留差异 */
|
||||
.unreg-btn {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: rgba(255, 255, 255, 0.65);
|
||||
border-radius: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.06);
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
/* .unreg-btn-secondary 与 .btn-secondary 类似,仅保留差异 */
|
||||
.unreg-btn-secondary {
|
||||
margin-bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
@@ -112,27 +101,9 @@ page {
|
||||
padding: 0 24rpx 150rpx;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
position: fixed;
|
||||
top: 36rpx;
|
||||
right: 32rpx;
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(12rpx);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 20;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.6);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
/* .refresh-btn 与全局 .refresh-btn .refresh-btn--light 完全相同,删除 */
|
||||
|
||||
.refresh-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
/* .refresh-icon 与全局 .refresh-icon 完全相同,删除 */
|
||||
|
||||
.user-card {
|
||||
position: relative;
|
||||
@@ -163,13 +134,9 @@ page {
|
||||
backdrop-filter: blur(12rpx);
|
||||
}
|
||||
|
||||
/* .user-avatar 与 .avatar-circle .avatar-md 类似,仅保留差异 */
|
||||
.user-avatar {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #FFFFFF;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-info { flex: 1; min-width: 0; }
|
||||
@@ -254,7 +221,7 @@ page {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ===== 黑卡 VIP ===== */
|
||||
/* 黑卡 VIP */
|
||||
.vip-black-card {
|
||||
position: relative;
|
||||
height: 152rpx;
|
||||
@@ -329,7 +296,7 @@ page {
|
||||
color: #f3ead8;
|
||||
}
|
||||
|
||||
/* ===== 资产面板 ===== */
|
||||
/* 资产面板 */
|
||||
.asset-panel {
|
||||
position: relative;
|
||||
border-radius: 28rpx;
|
||||
@@ -447,7 +414,7 @@ page {
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
/* ===== 排行榜(无大框,梯形格) ===== */
|
||||
/* 排行榜 */
|
||||
.rank-section {
|
||||
margin-bottom: 22rpx;
|
||||
padding: 0 2rpx;
|
||||
@@ -613,7 +580,7 @@ page {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* ===== 功能面板 ===== */
|
||||
/* 功能面板 */
|
||||
.func-panel {
|
||||
position: relative;
|
||||
border-radius: 28rpx;
|
||||
@@ -720,10 +687,10 @@ page {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* .list-card 与 .card 类似,仅保留差异 */
|
||||
.list-card {
|
||||
position: relative;
|
||||
border-radius: 28rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
@@ -743,23 +710,22 @@ page {
|
||||
backdrop-filter: blur(12rpx);
|
||||
}
|
||||
|
||||
/* .list-item 与全局 .list-item 类似,仅保留差异 */
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 22rpx 20rpx;
|
||||
border-bottom: 1rpx solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.list-item:last-child { border-bottom: none; }
|
||||
|
||||
/* .list-icon 与全局 .list-icon 类似,仅保留差异(缺少 flex-shrink:0) */
|
||||
.list-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
/* .list-text 与全局 .list-text 类似,仅保留差异 */
|
||||
.list-text {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
@@ -769,13 +735,12 @@ page {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
/* .list-arrow 与全局 .list-arrow 类似,仅保留差异 */
|
||||
.list-arrow {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
/* ===== 客服入口 ===== */
|
||||
/* 客服入口 */
|
||||
.kefu-banner {
|
||||
position: relative;
|
||||
margin-bottom: 18rpx;
|
||||
@@ -851,7 +816,7 @@ page {
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
/* ===== 总资产 ===== */
|
||||
/* 总资产 */
|
||||
.total-asset-row {
|
||||
position: relative;
|
||||
border-radius: 24rpx;
|
||||
@@ -937,6 +902,7 @@ page {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* .withdraw-btn 与 .btn-sm--dark 类似,仅保留差异 */
|
||||
.withdraw-btn {
|
||||
flex-shrink: 0;
|
||||
min-width: 120rpx;
|
||||
@@ -944,10 +910,7 @@ page {
|
||||
line-height: 72rpx;
|
||||
text-align: center;
|
||||
padding: 0 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #3d4f66 0%, #2c3e50 100%);
|
||||
border-radius: 999rpx;
|
||||
box-shadow: 0 6rpx 20rpx rgba(44, 62, 80, 0.22);
|
||||
}
|
||||
@@ -965,7 +928,7 @@ page {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ===== 身份认证 ===== */
|
||||
/* 身份认证 */
|
||||
.auth-grid {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -1008,28 +971,12 @@ page {
|
||||
background: rgba(90, 107, 87, 0.1);
|
||||
}
|
||||
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
/* .loading-mask 与全局 .loading-mask .loading-mask--light 完全相同,删除 */
|
||||
|
||||
/* .loading-spinner 与 .spinner--md 类似,仅保留差异 */
|
||||
.loading-spinner {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border: 3rpx solid rgba(0, 0, 0, 0.08);
|
||||
border-top-color: #1A1A1A;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
@@ -1,313 +1,313 @@
|
||||
// pages/jinpaids/jinpaids.js
|
||||
import request from '../../utils/request.js'
|
||||
import popupService from '../../services/popupService.js'
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar.js'
|
||||
import { buildInviterPeerId } from '../../utils/im-user.js'
|
||||
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// OSS地址
|
||||
ossImageUrl: '',
|
||||
|
||||
// 图标路径
|
||||
icons: {
|
||||
jinpai: '',
|
||||
refresh: '',
|
||||
copy: '',
|
||||
qiangdan: '',
|
||||
chongzhi: '',
|
||||
dingdan: '',
|
||||
chufa: '',
|
||||
paihang: '',
|
||||
xiugai: '',
|
||||
tixian: '',
|
||||
rightArrow: ''
|
||||
},
|
||||
|
||||
// 用户基本信息
|
||||
uid: '',
|
||||
touxiang: '',
|
||||
avatarUrl: '',
|
||||
dashouNicheng: '',
|
||||
|
||||
// 打手核心数据
|
||||
chenghao: '',
|
||||
yongjin: '0.00',
|
||||
zonge: '0.00',
|
||||
yajin: '0.00',
|
||||
jinfen: '0',
|
||||
chengjiaoliang: '0',
|
||||
zaixianZhuangtai: 0,
|
||||
dashouzhuangtai: '',
|
||||
clumber: [],
|
||||
|
||||
// 金牌专属数据
|
||||
jiedanZongliang: '0',
|
||||
jinriJiedan: '0.00',
|
||||
zuijinTixian: '0.00',
|
||||
|
||||
// 页面状态
|
||||
isLoading: false,
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
|
||||
// 计算数据
|
||||
chengjiaoRate: '0%',
|
||||
chengjiaoAngle: 0,
|
||||
tixianProgress: 0,
|
||||
|
||||
// 邀请人缓存(管事)
|
||||
inviterCache: null,
|
||||
chenghaoList: [] // 新增
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/dashouduan/dashouduan' });
|
||||
},
|
||||
|
||||
onShow() {
|
||||
wx.redirectTo({ url: '/pages/dashouduan/dashouduan' });
|
||||
},
|
||||
|
||||
_deprecatedOnLoad() {
|
||||
const notificationComp = this.selectComponent('#global-notification')
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
loadUserInfo() {
|
||||
const uid = wx.getStorageSync('uid') || ''
|
||||
const touxiang = wx.getStorageSync('touxiang') || ''
|
||||
const ossUrl = app.globalData.ossImageUrl || ''
|
||||
const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg')
|
||||
|
||||
let avatarUrl = defaultAvatar
|
||||
if (touxiang) {
|
||||
avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang)
|
||||
}
|
||||
|
||||
const dashouNicheng = app.globalData.dashouNicheng || wx.getStorageSync('nicheng') || '金牌选手'
|
||||
|
||||
this.setData({ uid, touxiang, avatarUrl, dashouNicheng })
|
||||
},
|
||||
|
||||
async getJinpaiInfo() {
|
||||
this.setData({ isLoading: true })
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/dashouxinxi',
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data
|
||||
|
||||
const updateData = {
|
||||
dashouNicheng: data.dashounicheng || '',
|
||||
zhanghaoStatus: data.zhanghaostatus || '',
|
||||
yongjin: data.yongjin || '0.00',
|
||||
zonge: data.zonge || '0.00',
|
||||
yajin: data.yajin || '0.00',
|
||||
chenghao: data.chenghao || '',
|
||||
jinfen: data.jifen || '0',
|
||||
chengjiaoliang: data.chengjiaoliang || '0',
|
||||
zaixianZhuangtai: data.zaixianzhuangtai || 0,
|
||||
dashouzhuangtai: data.dashouzhuangtai || '',
|
||||
clumber: data.clumber || [],
|
||||
jiedanZongliang: data.jiedanZongliang || '0',
|
||||
jinriJiedan: data.jinriJiedan || '0.00',
|
||||
zuijinTixian: data.zuijinTixian || '0.00',
|
||||
}
|
||||
|
||||
const jiedanTotal = parseFloat(updateData.jiedanZongliang) || 0
|
||||
const chengjiaoTotal = parseFloat(updateData.chengjiaoliang) || 0
|
||||
const rateNumber = jiedanTotal > 0 ? (chengjiaoTotal / jiedanTotal) * 100 : 0
|
||||
const chengjiaoRate = rateNumber.toFixed(1) + '%'
|
||||
const chengjiaoAngle = rateNumber * 3.6
|
||||
|
||||
const zuijin = parseFloat(updateData.zuijinTixian) || 0
|
||||
const zong = parseFloat(updateData.jinriJiedan) || 0
|
||||
const tixianProgress = zong > 0 ? Math.min((zuijin / zong) * 100, 100) : 0
|
||||
|
||||
const globalUpdate = {
|
||||
dashouNicheng: updateData.dashouNicheng,
|
||||
zhanghaoStatus: updateData.zhanghaoStatus,
|
||||
yongjin: updateData.yongjin,
|
||||
zonge: updateData.zonge,
|
||||
yajin: updateData.yajin,
|
||||
chenghao: updateData.chenghao,
|
||||
jinfen: updateData.jinfen,
|
||||
chengjiaoliang: updateData.chengjiaoliang,
|
||||
zaixianZhuangtai: updateData.zaixianZhuangtai,
|
||||
dashouzhuangtai: updateData.dashouzhuangtai,
|
||||
clumber: updateData.clumber,
|
||||
}
|
||||
Object.assign(app.globalData, globalUpdate)
|
||||
|
||||
wx.setStorageSync('nicheng', updateData.dashouNicheng)
|
||||
if (data.touxiang) {
|
||||
wx.setStorageSync('touxiang', data.touxiang)
|
||||
}
|
||||
|
||||
this.setData({
|
||||
...updateData,
|
||||
chengjiaoRate,
|
||||
chengjiaoAngle,
|
||||
tixianProgress: Math.round(tixianProgress),
|
||||
isLoading: false
|
||||
})
|
||||
|
||||
this.checkJinpaiAndRedirect(updateData.chenghao)
|
||||
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' })
|
||||
this.setData({ isLoading: false })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取金牌信息失败:', error)
|
||||
wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
this.setData({ isLoading: false })
|
||||
}
|
||||
},
|
||||
|
||||
refreshJinpaiInfo() {
|
||||
const now = Date.now()
|
||||
const lastTime = this.data.lastRefreshTime
|
||||
const canRefresh = this.data.canRefresh
|
||||
if (!canRefresh || (now - lastTime < 3000)) return
|
||||
|
||||
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false })
|
||||
this.getJinpaiInfo()
|
||||
this.fetchChenghaoList() // 新增
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000)
|
||||
},
|
||||
|
||||
checkJinpaiAndRedirect(chenghao) {
|
||||
if (chenghao !== '金牌选手') {
|
||||
wx.setStorageSync('isJinpai', 0)
|
||||
wx.redirectTo({ url: '/pages/dashouduan/dashouduan' })
|
||||
} else {
|
||||
wx.setStorageSync('isJinpai', 1)
|
||||
}
|
||||
},
|
||||
|
||||
// 联系管事(与打手端完全一致,增加容错)
|
||||
async contactInviter() {
|
||||
wx.showLoading({ title: '获取管事信息...', mask: true })
|
||||
try {
|
||||
const res = await request({ url: '/yonghu/hqwdyqr', method: 'POST' })
|
||||
if (res && res.data.code === 200) {
|
||||
const inviter = res.data.data
|
||||
const ossImageUrl = getApp().globalData.ossImageUrl || ''
|
||||
const fullAvatar = inviter.touxiang
|
||||
? (inviter.touxiang.startsWith('http') ? inviter.touxiang : ossImageUrl + inviter.touxiang)
|
||||
: ''
|
||||
|
||||
// 缓存邀请人信息
|
||||
const cacheData = {
|
||||
uid: inviter.uid,
|
||||
nicheng: inviter.nicheng || '',
|
||||
avatar: fullAvatar
|
||||
}
|
||||
wx.setStorageSync('inviterCache', cacheData)
|
||||
this.setData({ inviterCache: cacheData })
|
||||
|
||||
// 确保打手身份并连接
|
||||
const app = getApp()
|
||||
const myUid = wx.getStorageSync('uid')
|
||||
|
||||
// 如果当前不是打手身份,则切换并重连
|
||||
if (app.globalData.currentRole !== 'dashou') {
|
||||
app.globalData.currentRole = 'dashou'
|
||||
wx.setStorageSync('currentRole', 'dashou')
|
||||
if (app.switchRoleAndReconnect) {
|
||||
await app.switchRoleAndReconnect('dashou')
|
||||
} else if (app.connectWithIdentity) {
|
||||
// 降级方案:直接用打手身份连接
|
||||
await app.connectWithIdentity('dashou', 'Ds' + myUid, false)
|
||||
}
|
||||
} else {
|
||||
// 已为打手,确保连接存活
|
||||
if (app.connectForCurrentRole) {
|
||||
app.connectForCurrentRole()
|
||||
} else if (app.ensureConnection) {
|
||||
app.ensureConnection()
|
||||
}
|
||||
}
|
||||
|
||||
// 构造私聊参数
|
||||
const param = {
|
||||
toUserId: buildInviterPeerId(inviter.uid),
|
||||
toName: inviter.nicheng || '管事',
|
||||
toAvatar: fullAvatar
|
||||
}
|
||||
wx.navigateTo({
|
||||
url: '/pages/liaotian/liaotian?data=' + encodeURIComponent(JSON.stringify(param)),
|
||||
fail: (err) => {
|
||||
console.error('跳转私聊失败', err)
|
||||
wx.showToast({ title: '打开聊天失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('联系管事出错:', e)
|
||||
wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
} finally {
|
||||
wx.hideLoading()
|
||||
}
|
||||
},
|
||||
|
||||
copyUid() {
|
||||
const { uid } = this.data
|
||||
if (!uid) return wx.showToast({ title: 'UID不存在', icon: 'none' })
|
||||
wx.setClipboardData({
|
||||
data: uid,
|
||||
success: () => wx.showToast({ title: '已复制UID', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
previewAvatar() {
|
||||
if (this.data.avatarUrl) wx.previewImage({ urls: [this.data.avatarUrl] })
|
||||
},
|
||||
|
||||
goToWithdraw() { wx.navigateTo({ url: '/pages/tixian/tixian' }) },
|
||||
goToReceiveOrder() { wx.navigateTo({ url: '/pages/jiedan/jiedan' }) },
|
||||
goToRecharge() { wx.navigateTo({ url: '/pages/dashouchongzhi/dashouchongzhi' }) },
|
||||
goToMyOrders() { wx.navigateTo({ url: '/pages/dashoudingdan/dashoudingdan' }) },
|
||||
goToMyPunishment() { wx.navigateTo({ url: '/pages/cfss/cfss/cfss' }) },
|
||||
goToRanking() { wx.navigateTo({ url: '/pages/dashoupaihang/dashoupaihang?type=dashou' }) },
|
||||
goToModifyInfo() { wx.navigateTo({ url: '/pages/dashouxiugai/dashouxiugai' }) },
|
||||
goToRules() { wx.navigateTo({ url: '/pages/dashouguize/dashouguize' }) },
|
||||
// 跳转到考核金牌
|
||||
goToKaohe() {
|
||||
wx.navigateTo({ url: '/pages/kaohe_jinpai/kaohe_jinpai' });
|
||||
},
|
||||
|
||||
async fetchChenghaoList() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dsbqhq',
|
||||
method: 'POST'
|
||||
});
|
||||
if (res && res.data.code === 0 && res.data.data) {
|
||||
this.setData({ chenghaoList: res.data.data.chenghao_list || [] });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取称号标签失败', e);
|
||||
}
|
||||
},
|
||||
// pages/gold-fighter/gold-fighter.js
|
||||
import request from '../../utils/request.js'
|
||||
import popupService from '../../services/popupService.js'
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar.js'
|
||||
import { buildInviterPeerId } from '../../utils/im-user.js'
|
||||
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// OSS地址
|
||||
ossImageUrl: '',
|
||||
|
||||
// 图标路径
|
||||
icons: {
|
||||
jinpai: '',
|
||||
refresh: '',
|
||||
copy: '',
|
||||
qiangdan: '',
|
||||
chongzhi: '',
|
||||
dingdan: '',
|
||||
chufa: '',
|
||||
paihang: '',
|
||||
xiugai: '',
|
||||
tixian: '',
|
||||
rightArrow: ''
|
||||
},
|
||||
|
||||
// 用户基本信息
|
||||
uid: '',
|
||||
touxiang: '',
|
||||
avatarUrl: '',
|
||||
dashouNicheng: '',
|
||||
|
||||
// 打手核心数据
|
||||
chenghao: '',
|
||||
yongjin: '0.00',
|
||||
zonge: '0.00',
|
||||
yajin: '0.00',
|
||||
jinfen: '0',
|
||||
chengjiaoliang: '0',
|
||||
zaixianZhuangtai: 0,
|
||||
dashouzhuangtai: '',
|
||||
clumber: [],
|
||||
|
||||
// 金牌专属数据
|
||||
jiedanZongliang: '0',
|
||||
jinriJiedan: '0.00',
|
||||
zuijinTixian: '0.00',
|
||||
|
||||
// 页面状态
|
||||
isLoading: false,
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
|
||||
// 计算数据
|
||||
chengjiaoRate: '0%',
|
||||
chengjiaoAngle: 0,
|
||||
tixianProgress: 0,
|
||||
|
||||
// 邀请人缓存(管事)
|
||||
inviterCache: null,
|
||||
chenghaoList: [] // 新增
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' });
|
||||
},
|
||||
|
||||
onShow() {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' });
|
||||
},
|
||||
|
||||
_deprecatedOnLoad() {
|
||||
const notificationComp = this.selectComponent('#global-notification')
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
loadUserInfo() {
|
||||
const uid = wx.getStorageSync('uid') || ''
|
||||
const touxiang = wx.getStorageSync('touxiang') || ''
|
||||
const ossUrl = app.globalData.ossImageUrl || ''
|
||||
const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg')
|
||||
|
||||
let avatarUrl = defaultAvatar
|
||||
if (touxiang) {
|
||||
avatarUrl = ossUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang)
|
||||
}
|
||||
|
||||
const dashouNicheng = app.globalData.dashouNicheng || wx.getStorageSync('nicheng') || '金牌选手'
|
||||
|
||||
this.setData({ uid, touxiang, avatarUrl, dashouNicheng })
|
||||
},
|
||||
|
||||
async getJinpaiInfo() {
|
||||
this.setData({ isLoading: true })
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/dashouxinxi',
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data
|
||||
|
||||
const updateData = {
|
||||
dashouNicheng: data.dashounicheng || '',
|
||||
zhanghaoStatus: data.zhanghaostatus || '',
|
||||
yongjin: data.yongjin || '0.00',
|
||||
zonge: data.zonge || '0.00',
|
||||
yajin: data.yajin || '0.00',
|
||||
chenghao: data.chenghao || '',
|
||||
jinfen: data.jifen || '0',
|
||||
chengjiaoliang: data.chengjiaoliang || '0',
|
||||
zaixianZhuangtai: data.zaixianzhuangtai || 0,
|
||||
dashouzhuangtai: data.dashouzhuangtai || '',
|
||||
clumber: data.clumber || [],
|
||||
jiedanZongliang: data.jiedanZongliang || '0',
|
||||
jinriJiedan: data.jinriJiedan || '0.00',
|
||||
zuijinTixian: data.zuijinTixian || '0.00',
|
||||
}
|
||||
|
||||
const jiedanTotal = parseFloat(updateData.jiedanZongliang) || 0
|
||||
const chengjiaoTotal = parseFloat(updateData.chengjiaoliang) || 0
|
||||
const rateNumber = jiedanTotal > 0 ? (chengjiaoTotal / jiedanTotal) * 100 : 0
|
||||
const chengjiaoRate = rateNumber.toFixed(1) + '%'
|
||||
const chengjiaoAngle = rateNumber * 3.6
|
||||
|
||||
const zuijin = parseFloat(updateData.zuijinTixian) || 0
|
||||
const zong = parseFloat(updateData.jinriJiedan) || 0
|
||||
const tixianProgress = zong > 0 ? Math.min((zuijin / zong) * 100, 100) : 0
|
||||
|
||||
const globalUpdate = {
|
||||
dashouNicheng: updateData.dashouNicheng,
|
||||
zhanghaoStatus: updateData.zhanghaoStatus,
|
||||
yongjin: updateData.yongjin,
|
||||
zonge: updateData.zonge,
|
||||
yajin: updateData.yajin,
|
||||
chenghao: updateData.chenghao,
|
||||
jinfen: updateData.jinfen,
|
||||
chengjiaoliang: updateData.chengjiaoliang,
|
||||
zaixianZhuangtai: updateData.zaixianZhuangtai,
|
||||
dashouzhuangtai: updateData.dashouzhuangtai,
|
||||
clumber: updateData.clumber,
|
||||
}
|
||||
Object.assign(app.globalData, globalUpdate)
|
||||
|
||||
wx.setStorageSync('nicheng', updateData.dashouNicheng)
|
||||
if (data.touxiang) {
|
||||
wx.setStorageSync('touxiang', data.touxiang)
|
||||
}
|
||||
|
||||
this.setData({
|
||||
...updateData,
|
||||
chengjiaoRate,
|
||||
chengjiaoAngle,
|
||||
tixianProgress: Math.round(tixianProgress),
|
||||
isLoading: false
|
||||
})
|
||||
|
||||
this.checkJinpaiAndRedirect(updateData.chenghao)
|
||||
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取信息失败', icon: 'none' })
|
||||
this.setData({ isLoading: false })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取金牌信息失败:', error)
|
||||
wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
this.setData({ isLoading: false })
|
||||
}
|
||||
},
|
||||
|
||||
refreshJinpaiInfo() {
|
||||
const now = Date.now()
|
||||
const lastTime = this.data.lastRefreshTime
|
||||
const canRefresh = this.data.canRefresh
|
||||
if (!canRefresh || (now - lastTime < 3000)) return
|
||||
|
||||
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false })
|
||||
this.getJinpaiInfo()
|
||||
this.fetchChenghaoList() // 新增
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000)
|
||||
},
|
||||
|
||||
checkJinpaiAndRedirect(chenghao) {
|
||||
if (chenghao !== '金牌选手') {
|
||||
wx.setStorageSync('isJinpai', 0)
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' })
|
||||
} else {
|
||||
wx.setStorageSync('isJinpai', 1)
|
||||
}
|
||||
},
|
||||
|
||||
// 联系管事(与打手端完全一致,增加容错)
|
||||
async contactInviter() {
|
||||
wx.showLoading({ title: '获取管事信息...', mask: true })
|
||||
try {
|
||||
const res = await request({ url: '/yonghu/hqwdyqr', method: 'POST' })
|
||||
if (res && res.data.code === 200) {
|
||||
const inviter = res.data.data
|
||||
const ossImageUrl = getApp().globalData.ossImageUrl || ''
|
||||
const fullAvatar = inviter.touxiang
|
||||
? (inviter.touxiang.startsWith('http') ? inviter.touxiang : ossImageUrl + inviter.touxiang)
|
||||
: ''
|
||||
|
||||
// 缓存邀请人信息
|
||||
const cacheData = {
|
||||
uid: inviter.uid,
|
||||
nicheng: inviter.nicheng || '',
|
||||
avatar: fullAvatar
|
||||
}
|
||||
wx.setStorageSync('inviterCache', cacheData)
|
||||
this.setData({ inviterCache: cacheData })
|
||||
|
||||
// 确保打手身份并连接
|
||||
const app = getApp()
|
||||
const myUid = wx.getStorageSync('uid')
|
||||
|
||||
// 如果当前不是打手身份,则切换并重连
|
||||
if (app.globalData.currentRole !== 'dashou') {
|
||||
app.globalData.currentRole = 'dashou'
|
||||
wx.setStorageSync('currentRole', 'dashou')
|
||||
if (app.switchRoleAndReconnect) {
|
||||
await app.switchRoleAndReconnect('dashou')
|
||||
} else if (app.connectWithIdentity) {
|
||||
// 降级方案:直接用打手身份连接
|
||||
await app.connectWithIdentity('dashou', 'Ds' + myUid, false)
|
||||
}
|
||||
} else {
|
||||
// 已为打手,确保连接存活
|
||||
if (app.connectForCurrentRole) {
|
||||
app.connectForCurrentRole()
|
||||
} else if (app.ensureConnection) {
|
||||
app.ensureConnection()
|
||||
}
|
||||
}
|
||||
|
||||
// 构造私聊参数
|
||||
const param = {
|
||||
toUserId: buildInviterPeerId(inviter.uid),
|
||||
toName: inviter.nicheng || '管事',
|
||||
toAvatar: fullAvatar
|
||||
}
|
||||
wx.navigateTo({
|
||||
url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)),
|
||||
fail: (err) => {
|
||||
console.error('跳转私聊失败', err)
|
||||
wx.showToast({ title: '打开聊天失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: res?.data?.msg || '获取失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('联系管事出错:', e)
|
||||
wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
} finally {
|
||||
wx.hideLoading()
|
||||
}
|
||||
},
|
||||
|
||||
copyUid() {
|
||||
const { uid } = this.data
|
||||
if (!uid) return wx.showToast({ title: 'UID不存在', icon: 'none' })
|
||||
wx.setClipboardData({
|
||||
data: uid,
|
||||
success: () => wx.showToast({ title: '已复制UID', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
previewAvatar() {
|
||||
if (this.data.avatarUrl) wx.previewImage({ urls: [this.data.avatarUrl] })
|
||||
},
|
||||
|
||||
goToWithdraw() { wx.navigateTo({ url: '/pages/withdraw/withdraw' }) },
|
||||
goToReceiveOrder() { wx.navigateTo({ url: '/pages/accept-order/accept-order' }) },
|
||||
goToRecharge() { wx.navigateTo({ url: '/pages/fighter-recharge/fighter-recharge' }) },
|
||||
goToMyOrders() { wx.navigateTo({ url: '/pages/fighter-orders/fighter-orders' }) },
|
||||
goToMyPunishment() { wx.navigateTo({ url: '/pages/penalty/penalty/penalty' }) },
|
||||
goToRanking() { wx.navigateTo({ url: '/pages/fighter-rank/fighter-rank?type=dashou' }) },
|
||||
goToModifyInfo() { wx.navigateTo({ url: '/pages/fighter-edit/fighter-edit' }) },
|
||||
goToRules() { wx.navigateTo({ url: '/pages/fighter-rules/fighter-rules' }) },
|
||||
// 跳转到考核金牌
|
||||
goToKaohe() {
|
||||
wx.navigateTo({ url: '/pages/assess-gold/assess-gold' });
|
||||
},
|
||||
|
||||
async fetchChenghaoList() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dengji/dsbqhq',
|
||||
method: 'POST'
|
||||
});
|
||||
if (res && res.data.code === 0 && res.data.data) {
|
||||
this.setData({ chenghaoList: res.data.data.chenghao_list || [] });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取称号标签失败', e);
|
||||
}
|
||||
},
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,7 +49,6 @@ Page({
|
||||
isCross: p.isCross
|
||||
});
|
||||
wx.setNavigationBarTitle({ title: this.data.groupName });
|
||||
// 如果有外部传入的 currentUser 信息,直接用,不再依赖全局状态
|
||||
if (p.currentUserId) {
|
||||
this.setData({
|
||||
currentUser: {
|
||||
@@ -111,22 +110,6 @@ Page({
|
||||
});
|
||||
this.setData({ messages: msgs });
|
||||
},
|
||||
/*onLoad(options) {
|
||||
if (options.data) {
|
||||
try {
|
||||
const p = JSON.parse(decodeURIComponent(options.data));
|
||||
this.setData({
|
||||
groupId: p.groupId || '',
|
||||
groupName: p.groupName || '订单群聊',
|
||||
groupAvatar: p.groupAvatar || '',
|
||||
orderId: p.orderId || '',
|
||||
isCross: p.isCross || 0
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
wx.setNavigationBarTitle({ title: this.data.groupName });
|
||||
this.initCurrentUser();
|
||||
},*/
|
||||
|
||||
onShow() {
|
||||
this.autoConnect();
|
||||
@@ -189,8 +172,8 @@ Page({
|
||||
if (!groupId) return;
|
||||
wx.goEasy.im.subscribeGroup({
|
||||
groupIds: [groupId],
|
||||
onSuccess: () => console.log(`[群聊页] 订阅成功: ${groupId}`),
|
||||
onFailed: (err) => console.error(`[群聊页] 订阅失败: ${groupId}`, err)
|
||||
onSuccess: () => {},
|
||||
onFailed: () => {}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -279,7 +262,7 @@ Page({
|
||||
this.markGroupMessageAsRead();
|
||||
};
|
||||
wx.goEasy.im.on(wx.GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, this._msgHandler);
|
||||
this.markGroupMessageAsRead(); // ← 收到新消息就标记已读
|
||||
this.markGroupMessageAsRead();
|
||||
},
|
||||
|
||||
markGroupMessageAsRead() {
|
||||
@@ -1,400 +1,391 @@
|
||||
// pages/shangpin/shangpin.js
|
||||
const app = getApp();
|
||||
import { ensureLogin } from '../../utils/login';
|
||||
import { fetchShopGoods, bindShop } from '../../utils/shop';
|
||||
import { backfillUserProfileCache, getSessionToken } from '../../utils/role-tab-bar';
|
||||
import PopupService from '../../services/popupService.js';
|
||||
|
||||
// 🔥 固定参数:扫码时从 scene 中获取店铺ID的字段名(可在此处集中修改)
|
||||
const SCENE_PARAM = 'scene'; // 二维码参数统一使用 scene,解码后即为店铺ID
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 全局变量引用
|
||||
ossImageUrl: '',
|
||||
lunbozhanwei: '',
|
||||
|
||||
// 页面数据
|
||||
shangpingonggao: '',
|
||||
lunboList: [],
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
|
||||
// 状态控制
|
||||
selectedLeixingId: null,
|
||||
filteredData: [],
|
||||
showGonggaoModal: false,
|
||||
gonggaoAnim: true,
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
hasInitialized: false,
|
||||
|
||||
currentTime: ''
|
||||
},
|
||||
|
||||
// 从二维码解析出的店铺ID(仅在扫码时存在)
|
||||
shopId: null,
|
||||
|
||||
onLoad(options) {
|
||||
// 🔥 解析二维码参数(scene)
|
||||
if (options[SCENE_PARAM]) {
|
||||
try {
|
||||
// 微信会对 scene 进行编码,需要解码
|
||||
const scene = decodeURIComponent(options[SCENE_PARAM]);
|
||||
this.shopId = scene; // 例如:dianpu_123
|
||||
} catch (e) {
|
||||
console.error('scene解码失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 等待全局配置加载完成
|
||||
this.waitForConfigAndInit();
|
||||
// 🆕 修改:仅在已登录时检查弹窗,避免未登录时发起请求导致 401 弹窗
|
||||
const token = getSessionToken(app);
|
||||
if (token) {
|
||||
PopupService.checkAndShow(this, 'index');
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
// 🆕 页面隐藏时清理弹窗视图
|
||||
onHide: function () {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
if (popupComp && popupComp.cleanup) {
|
||||
popupComp.cleanup();
|
||||
}
|
||||
},
|
||||
|
||||
waitForConfigAndInit() {
|
||||
if (app.globalData.ossImageUrl) {
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl,
|
||||
lunbozhanwei: app.globalData.lunbozhanwei,
|
||||
currentTime: this.getCurrentTime()
|
||||
});
|
||||
this.initPageData();
|
||||
} else {
|
||||
setTimeout(() => this.waitForConfigAndInit(), 100);
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
backfillUserProfileCache(app);
|
||||
if (this.data.ossImageUrl) {
|
||||
this.setData({
|
||||
gonggaoAnim: true,
|
||||
currentTime: this.getCurrentTime(),
|
||||
});
|
||||
}
|
||||
this.registerNotificationComponent();
|
||||
|
||||
if (!getSessionToken(app)) {
|
||||
this.setData({
|
||||
hasInitialized: false,
|
||||
filteredData: [],
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 已登录时加载/刷新商品;未登录不自动登录、不跳转
|
||||
if (!this.data.isLoading) {
|
||||
const needLoad = !this.data.hasInitialized
|
||||
|| !this.data.filteredData
|
||||
|| this.data.filteredData.length === 0;
|
||||
if (needLoad) {
|
||||
this.initPageData();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
getCurrentTime() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = now.getDate().toString().padStart(2, '0');
|
||||
const hour = now.getHours().toString().padStart(2, '0');
|
||||
const minute = now.getMinutes().toString().padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hour}:${minute}`;
|
||||
},
|
||||
|
||||
sortByPaixu(list) {
|
||||
if (!list || !Array.isArray(list)) return [];
|
||||
return [...list].sort((a, b) => {
|
||||
const paixuA = a.paixu || 0;
|
||||
const paixuB = b.paixu || 0;
|
||||
if (paixuB !== paixuA) return paixuB - paixuA;
|
||||
return a.id - b.id;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化页面数据(重构后)
|
||||
* 流程:确保登录 → 如有扫码ID则绑定店铺 → 并行加载公告轮播图和商品数据
|
||||
*/
|
||||
async initPageData() {
|
||||
this.setData({ isLoading: true });
|
||||
|
||||
try {
|
||||
// 1. 确保登录(静默,不跳转)
|
||||
await ensureLogin({ page: this });
|
||||
|
||||
// 2. 🔥 关键:仅当通过扫码进入且携带了有效的店铺ID时,才执行绑定
|
||||
if (this.shopId) {
|
||||
await bindShop(this.shopId);
|
||||
}
|
||||
|
||||
// 3. 并行加载公告轮播图(复用原接口,独立请求)和店铺商品(新接口)
|
||||
const [gonggaoResult, shopData] = await Promise.all([
|
||||
this.loadGonggaoAndLunbo(), // 公告轮播图使用原有的 wx.request 方式,不受影响
|
||||
fetchShopGoods() // 商品数据通过封装的 request 获取
|
||||
]);
|
||||
|
||||
// 4. 处理商品数据
|
||||
const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
|
||||
const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
|
||||
const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
|
||||
|
||||
|
||||
// 更新全局缓存(可选,用于其他页面复用)
|
||||
app.globalData.shangpinleixing = sortedLeixing;
|
||||
app.globalData.shangpinzhuanqu = sortedZhuanqu;
|
||||
app.globalData.shangpinliebiao = sortedShangpin;
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: sortedLeixing,
|
||||
shangpinzhuanqu: sortedZhuanqu,
|
||||
shangpinliebiao: sortedShangpin,
|
||||
selectedLeixingId: sortedLeixing[0]?.id || null,
|
||||
isLoading: false,
|
||||
hasInitialized: true,
|
||||
}, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error);
|
||||
this.setData({ isLoading: false });
|
||||
// 错误提示已在各函数内部处理,此处仅做兜底
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载公告和轮播图(完全复用原逻辑,使用 wx.request,不使用封装 request)
|
||||
*/
|
||||
loadGonggaoAndLunbo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果全局已有数据,直接使用
|
||||
if (app.globalData.shangpingonggao && app.globalData.shangpinlunbo.length > 0) {
|
||||
this.setData({
|
||||
shangpingonggao: app.globalData.shangpingonggao,
|
||||
lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
|
||||
});
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: app.globalData.apiBaseUrl + '/peizhi/shangpingonggao/',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const data = res.data;
|
||||
app.globalData.shangpingonggao = data.shangpingonggao || '';
|
||||
app.globalData.shangpinlunbo = data.shangpinlunbo || [];
|
||||
this.setData({
|
||||
shangpingonggao: app.globalData.shangpingonggao,
|
||||
lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
|
||||
});
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('请求失败'));
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
processImageUrls(urlList) {
|
||||
if (!urlList || !Array.isArray(urlList)) return [];
|
||||
return urlList.map(url => url.startsWith('http') ? url : this.data.ossImageUrl + url);
|
||||
},
|
||||
|
||||
/**
|
||||
* 筛选商品数据(完全复用原有逻辑,不做任何改动)
|
||||
*/
|
||||
filterShangpinData() {
|
||||
const { selectedLeixingId, shangpinzhuanqu, shangpinliebiao } = this.data;
|
||||
|
||||
if (!selectedLeixingId || !shangpinzhuanqu || !shangpinliebiao) {
|
||||
this.setData({ filteredData: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
const zhuanquByLeixing = new Map();
|
||||
shangpinzhuanqu.forEach(zhuanqu => {
|
||||
if (zhuanqu.leixing_id === selectedLeixingId) {
|
||||
if (!zhuanquByLeixing.has(selectedLeixingId)) {
|
||||
zhuanquByLeixing.set(selectedLeixingId, []);
|
||||
}
|
||||
zhuanquByLeixing.get(selectedLeixingId).push(zhuanqu);
|
||||
}
|
||||
});
|
||||
|
||||
const shangpinByZhuanqu = new Map();
|
||||
shangpinliebiao.forEach(shangpin => {
|
||||
if (shangpin.leixing_id === selectedLeixingId && shangpin.zhuanqu_id) {
|
||||
const zhuanquId = shangpin.zhuanqu_id;
|
||||
if (!shangpinByZhuanqu.has(zhuanquId)) {
|
||||
shangpinByZhuanqu.set(zhuanquId, []);
|
||||
}
|
||||
|
||||
const jiage = parseFloat(shangpin.jiage) || 0;
|
||||
const priceInteger = Math.floor(jiage);
|
||||
let priceDecimal = '00';
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2);
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1];
|
||||
}
|
||||
|
||||
shangpinByZhuanqu.get(zhuanquId).push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: shangpin.tupian_url,
|
||||
duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0,
|
||||
paixu: shangpin.paixu || 0
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const filteredData = [];
|
||||
const currentZhuanquList = zhuanquByLeixing.get(selectedLeixingId) || [];
|
||||
|
||||
currentZhuanquList.forEach(zhuanqu => {
|
||||
const shangpinList = shangpinByZhuanqu.get(zhuanqu.id) || [];
|
||||
if (shangpinList.length > 0) {
|
||||
filteredData.push({
|
||||
zhuanqu: {
|
||||
id: zhuanqu.id,
|
||||
mingzi: zhuanqu.mingzi,
|
||||
paixu: zhuanqu.paixu || 0
|
||||
},
|
||||
shangpinList: shangpinList
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const sortedFilteredData = filteredData.sort((a, b) => {
|
||||
const paixuA = a.zhuanqu.paixu || 0;
|
||||
const paixuB = b.zhuanqu.paixu || 0;
|
||||
if (paixuB !== paixuA) return paixuB - paixuA;
|
||||
return a.zhuanqu.id - b.zhuanqu.id;
|
||||
});
|
||||
|
||||
this.setData({ filteredData: sortedFilteredData });
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const leixingId = e.currentTarget.dataset.id;
|
||||
if (this.data.selectedLeixingId === leixingId) return;
|
||||
this.setData({ selectedLeixingId: leixingId }, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
},
|
||||
|
||||
showGonggaoDetail() {
|
||||
this.setData({
|
||||
showGonggaoModal: true,
|
||||
gonggaoAnim: false,
|
||||
currentTime: this.getCurrentTime()
|
||||
});
|
||||
},
|
||||
|
||||
hideGonggaoDetail() {
|
||||
this.setData({
|
||||
showGonggaoModal: false,
|
||||
gonggaoAnim: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新所有数据(点击刷新按钮)
|
||||
* 只刷新商品数据,公告轮播图保持不变(若需刷新可清空全局缓存后调用 loadGonggaoAndLunbo)
|
||||
*/
|
||||
async refreshAllData() {
|
||||
if (this.data.isRefreshing) return;
|
||||
this.setData({ isRefreshing: true });
|
||||
wx.showLoading({ title: '刷新中...', mask: true });
|
||||
|
||||
try {
|
||||
// 重新获取商品数据(登录状态由 fetchShopGoods 内部确保)
|
||||
const shopData = await fetchShopGoods();
|
||||
|
||||
// 公告轮播图通常不需要随刷新按钮更新,保持原样
|
||||
|
||||
const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
|
||||
const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
|
||||
const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
|
||||
|
||||
app.globalData.shangpinleixing = sortedLeixing;
|
||||
app.globalData.shangpinzhuanqu = sortedZhuanqu;
|
||||
app.globalData.shangpinliebiao = sortedShangpin;
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: sortedLeixing,
|
||||
shangpinzhuanqu: sortedZhuanqu,
|
||||
shangpinliebiao: sortedShangpin,
|
||||
selectedLeixingId: sortedLeixing[0]?.id || null,
|
||||
isRefreshing: false
|
||||
}, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 });
|
||||
} catch (error) {
|
||||
wx.hideLoading();
|
||||
this.setData({ isRefreshing: false });
|
||||
}
|
||||
},
|
||||
|
||||
goToDetail(e) {
|
||||
const shangpinId = e.currentTarget.dataset.id;
|
||||
if (!shangpinId) return;
|
||||
wx.navigateTo({
|
||||
url: `/pages/shangpinxiangqing/shangpinxiangqing?id=${shangpinId}`
|
||||
});
|
||||
},
|
||||
|
||||
onReachBottom() {},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '阿龙电竞',
|
||||
path: '/pages/shangpin/shangpin'
|
||||
};
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
this.setData({ gonggaoAnim: false });
|
||||
}
|
||||
// pages/shangpin/shangpin.js
|
||||
const app = getApp();
|
||||
import { ensureLogin } from '../../utils/login';
|
||||
import { fetchShopGoods, bindShop } from '../../utils/shop';
|
||||
import { backfillUserProfileCache, getSessionToken } from '../../utils/role-tab-bar';
|
||||
import PopupService from '../../services/popupService.js';
|
||||
|
||||
// 扫码场景参数名
|
||||
const SCENE_PARAM = 'scene';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
ossImageUrl: '',
|
||||
lunbozhanwei: '',
|
||||
|
||||
shangpingonggao: '',
|
||||
lunboList: [],
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
|
||||
selectedLeixingId: null,
|
||||
filteredData: [],
|
||||
showGonggaoModal: false,
|
||||
gonggaoAnim: true,
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
hasInitialized: false,
|
||||
|
||||
currentTime: ''
|
||||
},
|
||||
|
||||
// 扫码解析的店铺ID
|
||||
shopId: null,
|
||||
|
||||
onLoad(options) {
|
||||
// 解析二维码参数
|
||||
if (options[SCENE_PARAM]) {
|
||||
try {
|
||||
const scene = decodeURIComponent(options[SCENE_PARAM]);
|
||||
this.shopId = scene;
|
||||
} catch (e) {
|
||||
console.error('scene解码失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 等待全局配置加载完成
|
||||
this.waitForConfigAndInit();
|
||||
// 已登录时才检查弹窗
|
||||
const token = getSessionToken(app);
|
||||
if (token) {
|
||||
PopupService.checkAndShow(this, 'index');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// 页面隐藏时清理弹窗视图
|
||||
onHide: function () {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
if (popupComp && popupComp.cleanup) {
|
||||
popupComp.cleanup();
|
||||
}
|
||||
},
|
||||
|
||||
waitForConfigAndInit() {
|
||||
if (app.globalData.ossImageUrl) {
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl,
|
||||
lunbozhanwei: app.globalData.lunbozhanwei,
|
||||
currentTime: this.getCurrentTime()
|
||||
});
|
||||
this.initPageData();
|
||||
} else {
|
||||
setTimeout(() => this.waitForConfigAndInit(), 100);
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
backfillUserProfileCache(app);
|
||||
if (this.data.ossImageUrl) {
|
||||
this.setData({
|
||||
gonggaoAnim: true,
|
||||
currentTime: this.getCurrentTime(),
|
||||
});
|
||||
}
|
||||
this.registerNotificationComponent();
|
||||
|
||||
if (!getSessionToken(app)) {
|
||||
this.setData({
|
||||
hasInitialized: false,
|
||||
filteredData: [],
|
||||
shangpinleixing: [],
|
||||
shangpinzhuanqu: [],
|
||||
shangpinliebiao: [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 已登录时加载/刷新商品;未登录不自动登录、不跳转
|
||||
if (!this.data.isLoading) {
|
||||
const needLoad = !this.data.hasInitialized
|
||||
|| !this.data.filteredData
|
||||
|| this.data.filteredData.length === 0;
|
||||
if (needLoad) {
|
||||
this.initPageData();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
getCurrentTime() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = now.getDate().toString().padStart(2, '0');
|
||||
const hour = now.getHours().toString().padStart(2, '0');
|
||||
const minute = now.getMinutes().toString().padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hour}:${minute}`;
|
||||
},
|
||||
|
||||
sortByPaixu(list) {
|
||||
if (!list || !Array.isArray(list)) return [];
|
||||
return [...list].sort((a, b) => {
|
||||
const paixuA = a.paixu || 0;
|
||||
const paixuB = b.paixu || 0;
|
||||
if (paixuB !== paixuA) return paixuB - paixuA;
|
||||
return a.id - b.id;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化页面数据(重构后)
|
||||
* 流程:确保登录 → 如有扫码ID则绑定店铺 → 并行加载公告轮播图和商品数据
|
||||
*/
|
||||
async initPageData() {
|
||||
this.setData({ isLoading: true });
|
||||
|
||||
try {
|
||||
// 1. 确保登录(静默,不跳转)
|
||||
await ensureLogin({ page: this });
|
||||
|
||||
// 2. 扫码进入时绑定店铺
|
||||
if (this.shopId) {
|
||||
await bindShop(this.shopId);
|
||||
}
|
||||
|
||||
// 3. 并行加载公告轮播图和商品数据
|
||||
const [gonggaoResult, shopData] = await Promise.all([
|
||||
this.loadGonggaoAndLunbo(),
|
||||
fetchShopGoods()
|
||||
]);
|
||||
|
||||
// 4. 处理商品数据
|
||||
const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
|
||||
const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
|
||||
const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
|
||||
|
||||
// 更新全局缓存
|
||||
app.globalData.shangpinleixing = sortedLeixing;
|
||||
app.globalData.shangpinzhuanqu = sortedZhuanqu;
|
||||
app.globalData.shangpinliebiao = sortedShangpin;
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: sortedLeixing,
|
||||
shangpinzhuanqu: sortedZhuanqu,
|
||||
shangpinliebiao: sortedShangpin,
|
||||
selectedLeixingId: sortedLeixing[0]?.id || null,
|
||||
isLoading: false,
|
||||
hasInitialized: true,
|
||||
}, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error);
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载公告和轮播图
|
||||
*/
|
||||
loadGonggaoAndLunbo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果全局已有数据,直接使用
|
||||
if (app.globalData.shangpingonggao && app.globalData.shangpinlunbo.length > 0) {
|
||||
this.setData({
|
||||
shangpingonggao: app.globalData.shangpingonggao,
|
||||
lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
|
||||
});
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: app.globalData.apiBaseUrl + '/peizhi/shangpingonggao/',
|
||||
method: 'POST',
|
||||
header: { 'content-type': 'application/json' },
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const data = res.data;
|
||||
app.globalData.shangpingonggao = data.shangpingonggao || '';
|
||||
app.globalData.shangpinlunbo = data.shangpinlunbo || [];
|
||||
this.setData({
|
||||
shangpingonggao: app.globalData.shangpingonggao,
|
||||
lunboList: this.processImageUrls(app.globalData.shangpinlunbo)
|
||||
});
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('请求失败'));
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
processImageUrls(urlList) {
|
||||
if (!urlList || !Array.isArray(urlList)) return [];
|
||||
return urlList.map(url => url.startsWith('http') ? url : this.data.ossImageUrl + url);
|
||||
},
|
||||
|
||||
/**
|
||||
* 筛选商品数据
|
||||
*/
|
||||
filterShangpinData() {
|
||||
const { selectedLeixingId, shangpinzhuanqu, shangpinliebiao } = this.data;
|
||||
|
||||
if (!selectedLeixingId || !shangpinzhuanqu || !shangpinliebiao) {
|
||||
this.setData({ filteredData: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
const zhuanquByLeixing = new Map();
|
||||
shangpinzhuanqu.forEach(zhuanqu => {
|
||||
if (zhuanqu.leixing_id === selectedLeixingId) {
|
||||
if (!zhuanquByLeixing.has(selectedLeixingId)) {
|
||||
zhuanquByLeixing.set(selectedLeixingId, []);
|
||||
}
|
||||
zhuanquByLeixing.get(selectedLeixingId).push(zhuanqu);
|
||||
}
|
||||
});
|
||||
|
||||
const shangpinByZhuanqu = new Map();
|
||||
shangpinliebiao.forEach(shangpin => {
|
||||
if (shangpin.leixing_id === selectedLeixingId && shangpin.zhuanqu_id) {
|
||||
const zhuanquId = shangpin.zhuanqu_id;
|
||||
if (!shangpinByZhuanqu.has(zhuanquId)) {
|
||||
shangpinByZhuanqu.set(zhuanquId, []);
|
||||
}
|
||||
|
||||
const jiage = parseFloat(shangpin.jiage) || 0;
|
||||
const priceInteger = Math.floor(jiage);
|
||||
let priceDecimal = '00';
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2);
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1];
|
||||
}
|
||||
|
||||
shangpinByZhuanqu.get(zhuanquId).push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: shangpin.tupian_url,
|
||||
duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0,
|
||||
paixu: shangpin.paixu || 0
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const filteredData = [];
|
||||
const currentZhuanquList = zhuanquByLeixing.get(selectedLeixingId) || [];
|
||||
|
||||
currentZhuanquList.forEach(zhuanqu => {
|
||||
const shangpinList = shangpinByZhuanqu.get(zhuanqu.id) || [];
|
||||
if (shangpinList.length > 0) {
|
||||
filteredData.push({
|
||||
zhuanqu: {
|
||||
id: zhuanqu.id,
|
||||
mingzi: zhuanqu.mingzi,
|
||||
paixu: zhuanqu.paixu || 0
|
||||
},
|
||||
shangpinList: shangpinList
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const sortedFilteredData = filteredData.sort((a, b) => {
|
||||
const paixuA = a.zhuanqu.paixu || 0;
|
||||
const paixuB = b.zhuanqu.paixu || 0;
|
||||
if (paixuB !== paixuA) return paixuB - paixuA;
|
||||
return a.zhuanqu.id - b.zhuanqu.id;
|
||||
});
|
||||
|
||||
this.setData({ filteredData: sortedFilteredData });
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const leixingId = e.currentTarget.dataset.id;
|
||||
if (this.data.selectedLeixingId === leixingId) return;
|
||||
this.setData({ selectedLeixingId: leixingId }, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
},
|
||||
|
||||
showGonggaoDetail() {
|
||||
this.setData({
|
||||
showGonggaoModal: true,
|
||||
gonggaoAnim: false,
|
||||
currentTime: this.getCurrentTime()
|
||||
});
|
||||
},
|
||||
|
||||
hideGonggaoDetail() {
|
||||
this.setData({
|
||||
showGonggaoModal: false,
|
||||
gonggaoAnim: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新所有数据
|
||||
* 只刷新商品数据
|
||||
*/
|
||||
async refreshAllData() {
|
||||
if (this.data.isRefreshing) return;
|
||||
this.setData({ isRefreshing: true });
|
||||
wx.showLoading({ title: '刷新中...', mask: true });
|
||||
|
||||
try {
|
||||
// 重新获取商品数据
|
||||
const shopData = await fetchShopGoods();
|
||||
|
||||
const sortedLeixing = this.sortByPaixu(shopData.shangpinleixing || []);
|
||||
const sortedZhuanqu = this.sortByPaixu(shopData.shangpinzhuanqu || []);
|
||||
const sortedShangpin = this.sortByPaixu(shopData.shangpinliebiao || []);
|
||||
|
||||
app.globalData.shangpinleixing = sortedLeixing;
|
||||
app.globalData.shangpinzhuanqu = sortedZhuanqu;
|
||||
app.globalData.shangpinliebiao = sortedShangpin;
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: sortedLeixing,
|
||||
shangpinzhuanqu: sortedZhuanqu,
|
||||
shangpinliebiao: sortedShangpin,
|
||||
selectedLeixingId: sortedLeixing[0]?.id || null,
|
||||
isRefreshing: false
|
||||
}, () => {
|
||||
this.filterShangpinData();
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 });
|
||||
} catch (error) {
|
||||
wx.hideLoading();
|
||||
this.setData({ isRefreshing: false });
|
||||
}
|
||||
},
|
||||
|
||||
goToDetail(e) {
|
||||
const shangpinId = e.currentTarget.dataset.id;
|
||||
if (!shangpinId) return;
|
||||
wx.navigateTo({
|
||||
url: `/pages/product-detail/product-detail?id=${shangpinId}`
|
||||
});
|
||||
},
|
||||
|
||||
onReachBottom() {},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '阿龙电竞',
|
||||
path: '/pages/shangpin/shangpin'
|
||||
};
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
this.setData({ gonggaoAnim: false });
|
||||
}
|
||||
});
|
||||
@@ -113,7 +113,6 @@
|
||||
class="shangpin-image"
|
||||
lazy-load="{{true}}"
|
||||
/>
|
||||
<!-- 移除已售标签 -->
|
||||
</view>
|
||||
|
||||
<!-- 商品标题 -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user