修正了 pages 名为拼音的问题
This commit is contained in:
1 parent
76cc4ac55e
commit
296e41a8a7
249 files changed
+29660
-29505
No files matched your search
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+109
-109
@@ -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 });
|
||||
},
|
||||
},
|
||||
});
|
||||
+24
-24
@@ -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
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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() {}
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
@@ -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;
|
||||
},
|
||||
});
|
||||
File renamed without changes.
@@ -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() {}
|
||||
});
|
||||
File renamed without changes.
@@ -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();
|
||||
}
|
||||
},
|
||||
});
|
||||
File renamed without changes.
@@ -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" />
|
||||
File renamed without changes.
@@ -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);
|
||||
}
|
||||
});
|
||||
File renamed without changes.
@@ -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'
|
||||
}
|
||||
}
|
||||
})
|
||||
File renamed without changes.
@@ -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"
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
File renamed without changes.
@@ -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() {
|
||||
|
||||
}
|
||||
})
|
||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
<!--pages/escort-orders/escort-orders.wxml-->
|
||||
<text>pages/escort-orders/escort-orders.wxml</text>
|
||||
@@ -0,0 +1 @@
|
||||
/* pages/escort-orders/escort-orders.wxss */
|
||||
File diff suppressed because it is too large.
Load diff
File renamed without changes.
@@ -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 renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File diff suppressed because it is too large.
Load diff
File renamed without changes.
@@ -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 renamed without changes.
File renamed without changes.
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() {}
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
@@ -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;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -132,8 +132,6 @@ page {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
.state-img {
|
||||
width: 160rpx; height: 160rpx;
|
||||
margin-bottom: 20rpx;
|
||||
+974
-974
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File renamed without changes.
@@ -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 renamed without changes.
File renamed without changes.
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() {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+390
-399
@@ -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>
|
||||
|
||||
<!-- 商品标题 -->
|
||||
|
||||
Loaded 100 of 249 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user