优化了样式,抽象出了 WXSS/JS 库
This commit is contained in:
@@ -1,218 +1,163 @@
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
// pages/assessor/assessor.js
|
||||
import { createPage, request, isCenterPageActive, ensureRoleOnCenterPage } from '../../utils/base-page.js';
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
isKaoheguan: 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
|
||||
},
|
||||
planetPaused: {
|
||||
top: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false
|
||||
}
|
||||
},
|
||||
|
||||
_planetTimers: {},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' });
|
||||
return;
|
||||
const icons = this.initImageUrls({
|
||||
'icons.refresh': 'beijing/kaohe/shuaxin.png',
|
||||
'icons.tixian': 'beijing/kaohe/tixian.png',
|
||||
'icons.daofen': 'beijing/kaohe/daofen.png',
|
||||
'icons.jilu': 'beijing/kaohe/jilu.png',
|
||||
'icons.zhongxin': 'beijing/kaohe/zhongxin.png',
|
||||
'icons.bgImage': 'beijing/kaohe/top_bg.jpg'
|
||||
});
|
||||
this.setData(icons);
|
||||
|
||||
this.checkRoleStatus();
|
||||
if (this.data.isKaoheguan) {
|
||||
this.getKaoheguanInfo();
|
||||
}
|
||||
this.checkColdStartPopup('kaoheguanduan');
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (isCenterPageActive(this, 'isKaoheguan', 'kaoheguanstatus')) {
|
||||
if (!this.data.isKaoheguan) this.setData({ isKaoheguan: true });
|
||||
ensureRoleOnCenterPage(this, 'dashou');
|
||||
this.refreshKaoheInfo();
|
||||
}
|
||||
},
|
||||
|
||||
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, 'dashou');
|
||||
} 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() {
|
||||
this.registerWithInviteCode({
|
||||
inviteCode: this.data.inviteCode,
|
||||
apiUrl: '/dengji/khgzc',
|
||||
role: 'dashou',
|
||||
statusKey: 'kaoheguanstatus',
|
||||
successMsg: '注册成功',
|
||||
onSuccess: async () => {
|
||||
this.loadUserInfo();
|
||||
await this.getKaoheguanInfo();
|
||||
ensureRoleOnCenterPage(this, 'dashou');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refreshKaoheInfo() {
|
||||
this.throttledRefresh(this.getKaoheguanInfo);
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
}, {
|
||||
roleConfig: {
|
||||
role: 'dashou',
|
||||
statusKey: 'kaoheguanstatus',
|
||||
dataFlag: 'isKaoheguan',
|
||||
pageId: 'kaoheguanduan',
|
||||
apiUrl: '/dengji/khgsx'
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -1,331 +1,321 @@
|
||||
// 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'
|
||||
}
|
||||
}
|
||||
})
|
||||
// pages/category/category.js
|
||||
const app = getApp()
|
||||
import { createPage } from '../../utils/base-page.js';
|
||||
|
||||
Page(createPage({
|
||||
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();
|
||||
},
|
||||
|
||||
initPageData() {
|
||||
const that = this
|
||||
this.setData({ isLoading: true })
|
||||
if (app.globalData.shangpinleixing && app.globalData.shangpinleixing.length > 0) {
|
||||
this.initFromGlobalData()
|
||||
} else {
|
||||
this.loadAllShangpinData()
|
||||
}
|
||||
},
|
||||
|
||||
initFromGlobalData() {
|
||||
const leixingList = app.globalData.shangpinleixing || []
|
||||
const zhuanquList = app.globalData.shangpinzhuanqu || []
|
||||
const shangpinList = app.globalData.shangpinliebiao || []
|
||||
|
||||
const zhuanquByLeixing = {}
|
||||
const shangpinByZhuanqu = {}
|
||||
const zhuanquGoodsCount = {}
|
||||
|
||||
zhuanquList.forEach(zhuanqu => {
|
||||
const leixingId = zhuanqu.leixing_id
|
||||
if (!zhuanquByLeixing[leixingId]) {
|
||||
zhuanquByLeixing[leixingId] = []
|
||||
}
|
||||
zhuanquByLeixing[leixingId].push(zhuanqu)
|
||||
})
|
||||
|
||||
shangpinList.forEach(shangpin => {
|
||||
const zhuanquId = shangpin.zhuanqu_id
|
||||
if (zhuanquId) {
|
||||
if (!shangpinByZhuanqu[zhuanquId]) {
|
||||
shangpinByZhuanqu[zhuanquId] = []
|
||||
zhuanquGoodsCount[zhuanquId] = 0
|
||||
}
|
||||
const jiage = parseFloat(shangpin.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
shangpinByZhuanqu[zhuanquId].push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: shangpin.tupian_url,
|
||||
duiwai_xiaoliang: shangpin.duiwai_xiaoliang || 0
|
||||
})
|
||||
zhuanquGoodsCount[zhuanquId] += 1
|
||||
}
|
||||
})
|
||||
|
||||
const firstLeixing = leixingList[0]
|
||||
let firstZhuanquId = null
|
||||
if (firstLeixing && zhuanquByLeixing[firstLeixing.id]) {
|
||||
firstZhuanquId = zhuanquByLeixing[firstLeixing.id][0]?.id || null
|
||||
}
|
||||
|
||||
this.setData({
|
||||
shangpinleixing: leixingList,
|
||||
shangpinzhuanqu: zhuanquList,
|
||||
shangpinliebiao: shangpinList,
|
||||
zhuanquByLeixing: zhuanquByLeixing,
|
||||
shangpinByZhuanqu: shangpinByZhuanqu,
|
||||
zhuanquGoodsCount: zhuanquGoodsCount,
|
||||
selectedLeixingId: firstLeixing?.id || null,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
this.filterData()
|
||||
this.setData({ isLoading: false, hasInitialized: true })
|
||||
})
|
||||
},
|
||||
|
||||
loadAllShangpinData() {
|
||||
const that = this
|
||||
wx.request({
|
||||
url: app.globalData.apiBaseUrl + '/shangpin/shangpinhuoqu/',
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
success(res) {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const data = res.data
|
||||
app.globalData.shangpinleixing = data.shangpinleixing || []
|
||||
app.globalData.shangpinzhuanqu = data.shangpinzhuanqu || []
|
||||
app.globalData.shangpinliebiao = data.shangpinliebiao || []
|
||||
that.initFromGlobalData()
|
||||
} else {
|
||||
that.handleLoadError()
|
||||
}
|
||||
},
|
||||
fail(error) {
|
||||
console.error('加载商品数据失败:', error)
|
||||
that.handleLoadError()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleLoadError() {
|
||||
wx.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({ isLoading: false })
|
||||
},
|
||||
|
||||
filterData() {
|
||||
const { selectedLeixingId, selectedZhuanquId, zhuanquByLeixing, shangpinByZhuanqu } = this.data
|
||||
const filteredZhuanquList = zhuanquByLeixing[selectedLeixingId] || []
|
||||
let filteredShangpinList = []
|
||||
if (selectedZhuanquId) {
|
||||
filteredShangpinList = shangpinByZhuanqu[selectedZhuanquId] || []
|
||||
} else if (filteredZhuanquList.length > 0) {
|
||||
const firstZhuanquId = filteredZhuanquList[0].id
|
||||
filteredShangpinList = shangpinByZhuanqu[firstZhuanquId] || []
|
||||
this.setData({ selectedZhuanquId: firstZhuanquId })
|
||||
}
|
||||
this.setData({
|
||||
filteredZhuanquList: filteredZhuanquList,
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
},
|
||||
|
||||
selectLeixing(e) {
|
||||
const leixingId = e.currentTarget.dataset.id
|
||||
if (this.data.selectedLeixingId === leixingId) {
|
||||
return
|
||||
}
|
||||
const zhuanquList = this.data.zhuanquByLeixing[leixingId] || []
|
||||
const firstZhuanquId = zhuanquList.length > 0 ? zhuanquList[0].id : null
|
||||
this.setData({
|
||||
selectedLeixingId: leixingId,
|
||||
selectedZhuanquId: firstZhuanquId
|
||||
}, () => {
|
||||
this.filterData()
|
||||
})
|
||||
},
|
||||
|
||||
selectZhuanqu(e) {
|
||||
const zhuanquId = e.currentTarget.dataset.id
|
||||
if (this.data.selectedZhuanquId === zhuanquId) {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
selectedZhuanquId: zhuanquId
|
||||
}, () => {
|
||||
const filteredShangpinList = this.data.shangpinByZhuanqu[zhuanquId] || []
|
||||
this.setData({
|
||||
filteredShangpinList: filteredShangpinList
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchText: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
onSearchTap() {
|
||||
const searchText = this.data.searchText.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
onSearchConfirm(e) {
|
||||
const searchText = e.detail.value.trim()
|
||||
if (!searchText) {
|
||||
wx.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
searchText: searchText
|
||||
})
|
||||
this.startSearch(searchText)
|
||||
},
|
||||
|
||||
startSearch(searchText) {
|
||||
this.setData({
|
||||
isSearching: true,
|
||||
showSearchResult: true
|
||||
})
|
||||
const allShangpin = this.data.shangpinliebiao
|
||||
const results = []
|
||||
for (const item of allShangpin) {
|
||||
if (item.biaoqian && item.biaoqian.toLowerCase().includes(searchText.toLowerCase())) {
|
||||
const jiage = parseFloat(item.jiage) || 0
|
||||
const priceInteger = Math.floor(jiage)
|
||||
let priceDecimal = '00'
|
||||
const decimalPart = (jiage - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
results.push({
|
||||
id: item.id,
|
||||
biaoqian: item.biaoqian,
|
||||
jiage: jiage,
|
||||
priceInteger: priceInteger,
|
||||
priceDecimal: priceDecimal,
|
||||
tupian_url: item.tupian_url,
|
||||
leixing_name: this.getLeixingName(item.leixing_id),
|
||||
zhuanqu_name: this.getZhuanquName(item.zhuanqu_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
searchResults: results,
|
||||
isSearching: false
|
||||
})
|
||||
},
|
||||
|
||||
onClearSearch() {
|
||||
this.setData({
|
||||
searchText: '',
|
||||
showSearchResult: false,
|
||||
searchResults: []
|
||||
})
|
||||
},
|
||||
|
||||
getLeixingName(leixingId) {
|
||||
const leixingList = this.data.shangpinleixing
|
||||
for (const item of leixingList) {
|
||||
if (item.id === leixingId) {
|
||||
return item.jieshao
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
getZhuanquName(zhuanquId) {
|
||||
const zhuanquList = this.data.shangpinzhuanqu
|
||||
for (const item of zhuanquList) {
|
||||
if (item.id === zhuanquId) {
|
||||
return item.mingzi
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
goToDetail(e) {
|
||||
const shangpinId = e.currentTarget.dataset.id
|
||||
if (!shangpinId) return
|
||||
wx.navigateTo({
|
||||
url: `/pages/product-detail/product-detail?id=${shangpinId}`
|
||||
})
|
||||
},
|
||||
|
||||
onRefresh() {
|
||||
wx.showLoading({
|
||||
title: '刷新中...',
|
||||
mask: true
|
||||
})
|
||||
app.globalData.shangpinleixing = []
|
||||
app.globalData.shangpinzhuanqu = []
|
||||
app.globalData.shangpinliebiao = []
|
||||
this.loadAllShangpinData()
|
||||
setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '阿龙电竞 - 商品分类',
|
||||
path: '/pages/category/category'
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
<view class="chat-page">
|
||||
<scroll-view class="msg-list" scroll-y="true"
|
||||
<scroll-view class="chat-msg-list" scroll-y="true"
|
||||
scroll-into-view="{{scrollToView}}"
|
||||
refresher-enabled="{{true}}"
|
||||
refresher-triggered="{{isRefreshing}}"
|
||||
bindrefresherrefresh="onPullDownRefresh"
|
||||
style="top: 20rpx; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 20rpx);">
|
||||
<view class="loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<view class="chat-loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<block wx:for="{{messages}}" wx:key="messageId">
|
||||
<view class="msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="msg-row {{item.senderId === currentUser.id ? 'right' : 'left'}}">
|
||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="avatar" src="{{item.senderData.avatar || toAvatar}}" mode="aspectFill" binderror="onPeerAvatarError" />
|
||||
<view class="bubble {{item.senderId === currentUser.id ? 'bubble-right' : 'bubble-left'}}"
|
||||
<view class="chat-msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{item.senderData.avatar || toAvatar}}" mode="aspectFill" binderror="onPeerAvatarError" />
|
||||
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
||||
data-messageid="{{item.messageId}}"
|
||||
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
||||
bindtap="{{item.type==='text' ? 'onBubbleTap' : (item.type==='image' ? 'previewImage' : '')}}"
|
||||
data-url="{{item.type==='image' ? item.payload.url : ''}}">
|
||||
<text wx:if="{{item.type === 'text'}}" class="msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="msg-image" src="{{item.payload.url}}" mode="widthFix" />
|
||||
<view wx:elif="{{item.type === 'order'}}" class="order-bubble">
|
||||
<text class="order-label">[订单]</text>
|
||||
<text class="order-info">ID: {{item.payload.orderId}}</text>
|
||||
<text wx:if="{{item.type === 'text'}}" class="chat-msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="chat-msg-image" src="{{item.payload.url}}" mode="widthFix" />
|
||||
<view wx:elif="{{item.type === 'order'}}" class="chat-order-bubble">
|
||||
<text class="chat-order-label">[订单]</text>
|
||||
<text class="chat-order-info">ID: {{item.payload.orderId}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="avatar" src="{{item.senderData.avatar || currentUser.avatar}}" mode="aspectFill" binderror="onSelfAvatarError" data-index="{{index}}" />
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{item.senderData.avatar || currentUser.avatar}}" mode="aspectFill" binderror="onSelfAvatarError" data-index="{{index}}" />
|
||||
</view>
|
||||
<view wx:if="{{item.senderId === currentUser.id && item.status === 'success'}}" class="read-tag">
|
||||
<view wx:if="{{item.senderId === currentUser.id && item.status === 'success'}}" class="chat-read-tag">
|
||||
{{item.read ? '已读' : '未读'}}
|
||||
</view>
|
||||
</view>
|
||||
@@ -33,53 +33,53 @@
|
||||
<view id="msg-bottom" style="height:20rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="plus-grid">
|
||||
<view class="plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="plus-icon">😀</text>
|
||||
<text class="plus-label">表情</text>
|
||||
<view class="chat-input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="chat-plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="chat-plus-grid">
|
||||
<view class="chat-plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="chat-plus-icon">😀</text>
|
||||
<text class="chat-plus-label">表情</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="chooseImage">
|
||||
<text class="plus-icon">📷</text>
|
||||
<text class="plus-label">图片</text>
|
||||
<view class="chat-plus-item" catchtap="chooseImage">
|
||||
<text class="chat-plus-icon">📷</text>
|
||||
<text class="chat-plus-label">图片</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="openOrderSender">
|
||||
<text class="plus-icon">📋</text>
|
||||
<text class="plus-label">订单</text>
|
||||
<view class="chat-plus-item" catchtap="openOrderSender">
|
||||
<text class="chat-plus-icon">📋</text>
|
||||
<text class="chat-plus-label">订单</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="emoji-scroll">
|
||||
<view class="emoji-grid">
|
||||
<view class="chat-emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="chat-emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="chat-emoji-scroll">
|
||||
<view class="chat-emoji-grid">
|
||||
<block wx:for="{{emojiList}}" wx:key="*this">
|
||||
<view class="emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
<view class="chat-emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
<view class="chat-pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="chat-pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="chat-pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
</view>
|
||||
|
||||
<view class="write-row">
|
||||
<input class="text-input" placeholder="消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="plus-icon-single">➕</text>
|
||||
<view class="chat-write-row">
|
||||
<input class="chat-text-input" placeholder="消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="chat-send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="chat-plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="chat-plus-icon-single">➕</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="detail-content" catchtap="noop">
|
||||
<text class="detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="copy-btn" bindtap="copyDetail">复制</button>
|
||||
<view class="chat-detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="chat-detail-content" catchtap="noop">
|
||||
<text class="chat-detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="chat-copy-btn" bindtap="copyDetail">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -1,98 +1 @@
|
||||
.chat-page { width:100%; height:100vh; background:#f5f5f5; }
|
||||
|
||||
.msg-list {
|
||||
position: absolute;
|
||||
left:0; right:0;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.loading-more { text-align:center; font-size:24rpx; color:#999; padding:20rpx 0; }
|
||||
.time-tag { text-align:center; margin:28rpx 0; font-size:24rpx; color:#b0b0b0; }
|
||||
.msg-wrapper { margin-bottom:12rpx; }
|
||||
.msg-row { display:flex; align-items:flex-start; margin-bottom:4rpx; }
|
||||
.right { justify-content:flex-end; }
|
||||
.left { justify-content:flex-start; }
|
||||
.avatar { width:76rpx; height:76rpx; border-radius:50%; background:#e0e0e0; margin:0 12rpx; flex-shrink:0; }
|
||||
.bubble { max-width:70%; padding:16rpx 20rpx; border-radius:16rpx; position:relative; word-break:break-all; font-size:30rpx; line-height:1.5; }
|
||||
.bubble-left { background:#fff; border-top-left-radius:4rpx; }
|
||||
.bubble-right { background:#00aaff; color:#fff; border-top-right-radius:4rpx; }
|
||||
.msg-text { color:inherit; }
|
||||
.msg-image { max-width:240rpx; border-radius:10rpx; }
|
||||
.order-bubble { background:#fff7e0; padding:12rpx; border-radius:8rpx; }
|
||||
.order-label { font-size:24rpx; color:#e6a23c; font-weight:600; }
|
||||
.order-info { font-size:24rpx; color:#333; margin:6rpx 0; }
|
||||
|
||||
.read-tag {
|
||||
font-size:20rpx;
|
||||
color:#888;
|
||||
text-align:right;
|
||||
padding:4rpx 12rpx 0 0;
|
||||
margin-top: -4rpx;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
position: fixed;
|
||||
left:0; right:0;
|
||||
background:#f7f7f7;
|
||||
border-top:1rpx solid #ddd;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.plus-panel {
|
||||
position: absolute;
|
||||
bottom:100%; left:0; right:0;
|
||||
background:#fff;
|
||||
border-top:1rpx solid #e0e0e0;
|
||||
padding: 20rpx;
|
||||
transform: translateY(100%);
|
||||
opacity:0;
|
||||
transition: transform 0.3s, opacity 0.3s;
|
||||
pointer-events:none;
|
||||
z-index:9;
|
||||
}
|
||||
.plus-panel.show { transform: translateY(0); opacity:1; pointer-events:auto; }
|
||||
.plus-grid { display: flex; justify-content: space-around; }
|
||||
.plus-item { display: flex; flex-direction: column; align-items: center; width: 120rpx; }
|
||||
.plus-icon { font-size: 60rpx; }
|
||||
.plus-label { font-size: 24rpx; color: #666; margin-top: 8rpx; }
|
||||
|
||||
.emoji-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:transparent; z-index:8; }
|
||||
.emoji-panel {
|
||||
position: absolute; bottom:100%; left:0; right:0;
|
||||
background:#fff; border-top:1rpx solid #e0e0e0;
|
||||
height:380rpx;
|
||||
transform: translateY(100%); opacity:0; transition:0.3s;
|
||||
pointer-events:none; z-index:9;
|
||||
}
|
||||
.emoji-panel.show { transform:translateY(0); opacity:1; pointer-events:auto; }
|
||||
.emoji-scroll { height:100%; }
|
||||
.emoji-grid { display:flex; flex-wrap:wrap; padding:20rpx 10rpx; }
|
||||
.emoji-item { width:14.28%; text-align:center; padding:16rpx 0; font-size:44rpx; }
|
||||
|
||||
.pending-image { display:flex; align-items:center; padding:10rpx 20rpx; background:#fff; }
|
||||
.pending-thumb { width:80rpx; height:80rpx; border-radius:8rpx; }
|
||||
.pending-remove { font-size:30rpx; color:#999; margin-left:10rpx; }
|
||||
|
||||
.write-row { display:flex; padding:0 20rpx 10rpx; align-items:center; }
|
||||
.text-input {
|
||||
flex:1; height:76rpx; background:#fff; border-radius:12rpx;
|
||||
padding:0 20rpx; font-size:30rpx; margin-right:12rpx;
|
||||
}
|
||||
.send-btn {
|
||||
width:120rpx; height:76rpx; background:#00aaff; color:#fff;
|
||||
font-size:28rpx; font-weight:500; border-radius:12rpx;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.plus-btn {
|
||||
width:56rpx; height:56rpx;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.plus-icon-single { font-size:46rpx; color:#00aaff; }
|
||||
|
||||
.detail-modal { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.7); z-index:999; display:flex; align-items:center; justify-content:center; }
|
||||
.detail-content { width:80%; max-height:80%; background:#fff; border-radius:16rpx; padding:40rpx; }
|
||||
.detail-text { font-size:32rpx; line-height:1.6; word-break:break-all; overflow-y:auto; }
|
||||
.copy-btn { width:100%; height:80rpx; background:#00aaff; color:#fff; border-radius:12rpx; margin-top:20rpx; font-size:30rpx; }
|
||||
/* 使用全局 chat-* 样式 */
|
||||
@@ -1,37 +1,37 @@
|
||||
<view class="chat-page">
|
||||
<scroll-view class="msg-list" scroll-y="true"
|
||||
<scroll-view class="chat-msg-list" scroll-y="true"
|
||||
scroll-into-view="{{scrollToView}}"
|
||||
refresher-enabled="{{true}}"
|
||||
refresher-triggered="{{isRefreshing}}"
|
||||
bindrefresherrefresh="onPullDownRefresh"
|
||||
style="top: 20rpx; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 20rpx);">
|
||||
<view class="loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<view class="chat-loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<block wx:for="{{messages}}" wx:key="messageId">
|
||||
<view class="msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="msg-row {{item.senderId === currentUser.id ? 'right' : 'left'}}">
|
||||
<view class="chat-msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
||||
<!-- 对方头像(客服) -->
|
||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="avatar" src="{{teamAvatar}}" mode="aspectFill" />
|
||||
<view class="bubble {{item.senderId === currentUser.id ? 'bubble-right' : 'bubble-left'}}"
|
||||
<image wx:if="{{item.senderId !== currentUser.id}}" class="chat-avatar" src="{{teamAvatar}}" mode="aspectFill" />
|
||||
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
||||
data-messageid="{{item.messageId}}"
|
||||
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
||||
bindtap="{{item.type==='text' ? 'onBubbleTap' : (item.type==='image' ? 'previewImage' : '')}}"
|
||||
data-url="{{item.type==='image' ? item.payload.url : ''}}">
|
||||
<text wx:if="{{item.type === 'text'}}" class="msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="msg-image" src="{{item.payload.url}}" mode="widthFix" data-url="{{item.payload.url}}" bindtap="previewImage"/>
|
||||
<view wx:elif="{{item.type === 'order'}}" class="order-bubble">
|
||||
<text class="order-label">📋 订单消息</text>
|
||||
<view class="order-brief">
|
||||
<text wx:if="{{item.type === 'text'}}" class="chat-msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="chat-msg-image" src="{{item.payload.url}}" mode="widthFix" data-url="{{item.payload.url}}" bindtap="previewImage"/>
|
||||
<view wx:elif="{{item.type === 'order'}}" class="chat-order-bubble">
|
||||
<text class="chat-order-label">📋 订单消息</text>
|
||||
<view class="chat-order-info">
|
||||
<text>订单号:{{item.payload.dingdan_id || '无'}}</text>
|
||||
<text>服务:{{item.payload.jieshao || ''}}</text>
|
||||
<text class="order-price">¥{{item.payload.jine}}</text>
|
||||
<text style="color:#e6a23c;font-weight:bold">¥{{item.payload.jine}}</text>
|
||||
</view>
|
||||
<button class="order-detail-btn" catchtap="showOrderDetailPopup" data-order="{{item.payload}}" size="mini">查看详情</button>
|
||||
<button class="chat-copy-btn" catchtap="showOrderDetailPopup" data-order="{{item.payload}}" size="mini">查看详情</button>
|
||||
</view>
|
||||
<text wx:else class="msg-text">{{item.payload.text || '[未知消息]'}}</text>
|
||||
<text wx:else class="chat-msg-text">{{item.payload.text || '[未知消息]'}}</text>
|
||||
</view>
|
||||
<!-- 自己头像 -->
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="avatar" src="{{currentUser.avatar}}" mode="aspectFill" />
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{currentUser.avatar}}" mode="aspectFill" />
|
||||
</view>
|
||||
<!-- 🔥 已读/未读标签已彻底移除 -->
|
||||
</view>
|
||||
@@ -40,70 +40,70 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部输入区域(保持不变) -->
|
||||
<view class="input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="plus-grid">
|
||||
<view class="plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="plus-icon">😀</text>
|
||||
<text class="plus-label">表情</text>
|
||||
<view class="chat-input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="chat-plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="chat-plus-grid">
|
||||
<view class="chat-plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="chat-plus-icon">😀</text>
|
||||
<text class="chat-plus-label">表情</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="chooseImage">
|
||||
<text class="plus-icon">📷</text>
|
||||
<text class="plus-label">图片</text>
|
||||
<view class="chat-plus-item" catchtap="chooseImage">
|
||||
<text class="chat-plus-icon">📷</text>
|
||||
<text class="chat-plus-label">图片</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="openOrderSender">
|
||||
<text class="plus-icon">📋</text>
|
||||
<text class="plus-label">订单</text>
|
||||
<view class="chat-plus-item" catchtap="openOrderSender">
|
||||
<text class="chat-plus-icon">📋</text>
|
||||
<text class="chat-plus-label">订单</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="emoji-scroll">
|
||||
<view class="emoji-grid">
|
||||
<view class="chat-emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="chat-emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="chat-emoji-scroll">
|
||||
<view class="chat-emoji-grid">
|
||||
<block wx:for="{{emojiList}}" wx:key="*this">
|
||||
<view class="emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
<view class="chat-emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
<view class="chat-pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="chat-pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="chat-pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
</view>
|
||||
|
||||
<view class="write-row">
|
||||
<input class="text-input" placeholder="消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="plus-icon-single">➕</text>
|
||||
<view class="chat-write-row">
|
||||
<input class="chat-text-input" placeholder="消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="chat-send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="chat-plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="chat-plus-icon-single">➕</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 文本双击放大弹窗 -->
|
||||
<view class="detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="detail-content" catchtap="noop">
|
||||
<text class="detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="copy-btn" bindtap="copyDetail">复制</button>
|
||||
<view class="chat-detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="chat-detail-content" catchtap="noop">
|
||||
<text class="chat-detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="chat-copy-btn" bindtap="copyDetail">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单详情弹窗 -->
|
||||
<view class="order-detail-mask" wx:if="{{showOrderDetail}}" catchtap="hideOrderDetail">
|
||||
<view class="order-detail-panel" catchtap="noop">
|
||||
<view class="order-detail-title">订单详情</view>
|
||||
<view class="order-detail-item">订单号:{{detailOrder.dingdan_id}}</view>
|
||||
<view class="order-detail-item">服务描述:{{detailOrder.jieshao}}</view>
|
||||
<view class="order-detail-item">金额:¥{{detailOrder.jine}}</view>
|
||||
<view class="order-detail-item">类型:{{detailOrder.leixing || '无'}}</view>
|
||||
<view class="order-detail-item">时间:{{detailOrder.shijian || '无'}}</view>
|
||||
<button class="order-detail-close-btn" catchtap="hideOrderDetail">关闭</button>
|
||||
<view class="chat-detail-modal" wx:if="{{showOrderDetail}}" catchtap="hideOrderDetail">
|
||||
<view class="chat-detail-content" catchtap="noop">
|
||||
<view class="chat-detail-text">订单详情</view>
|
||||
<view class="chat-detail-text">订单号:{{detailOrder.dingdan_id}}</view>
|
||||
<view class="chat-detail-text">服务描述:{{detailOrder.jieshao}}</view>
|
||||
<view class="chat-detail-text">金额:¥{{detailOrder.jine}}</view>
|
||||
<view class="chat-detail-text">类型:{{detailOrder.leixing || '无'}}</view>
|
||||
<view class="chat-detail-text">时间:{{detailOrder.shijian || '无'}}</view>
|
||||
<button class="chat-copy-btn" catchtap="hideOrderDetail">关闭</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单发送组件 -->
|
||||
<order-sender visible="{{showOrderSender}}" bind:send="onSendOrder" bind:close="closeOrderSender" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,67 +1 @@
|
||||
.chat-page { width:100%; height:100vh; background:#f5f5f5; }
|
||||
.msg-list { position:absolute; left:0; right:0; padding:0 20rpx; box-sizing:border-box; overflow-y:auto; }
|
||||
.loading-more { text-align:center; font-size:24rpx; color:#999; padding:20rpx 0; }
|
||||
.time-tag { text-align:center; margin:28rpx 0; font-size:24rpx; color:#b0b0b0; }
|
||||
.msg-wrapper { margin-bottom:12rpx; }
|
||||
.msg-row { display:flex; align-items:flex-start; margin-bottom:4rpx; }
|
||||
.right { justify-content:flex-end; }
|
||||
.left { justify-content:flex-start; }
|
||||
.avatar { width:76rpx; height:76rpx; border-radius:50%; background:#e0e0e0; margin:0 12rpx; flex-shrink:0; }
|
||||
.bubble { max-width:70%; padding:16rpx 20rpx; border-radius:16rpx; position:relative; word-break:break-all; font-size:30rpx; line-height:1.5; }
|
||||
.bubble-left { background:#fff; border-top-left-radius:4rpx; }
|
||||
.bubble-right { background:#00aaff; color:#fff; border-top-right-radius:4rpx; }
|
||||
.msg-text { color:inherit; }
|
||||
.msg-image { max-width:240rpx; border-radius:10rpx; }
|
||||
|
||||
/* 已读/未读标签:靠右显示 */
|
||||
.read-tag {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
font-size: 20rpx;
|
||||
color: #888;
|
||||
padding: 4rpx 12rpx 0 0;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
|
||||
/* 订单气泡 */
|
||||
.order-bubble { background:#fff7e0; padding:12rpx; border-radius:8rpx; }
|
||||
.order-label { font-size:24rpx; color:#e6a23c; font-weight:600; margin-bottom:8rpx; }
|
||||
.order-brief { font-size:24rpx; color:#333; line-height:1.6; }
|
||||
.order-price { color:#e6a23c; font-weight:bold; }
|
||||
.order-detail-btn { margin-top:10rpx; background:#e6a23c; color:#fff; border-radius:8rpx; }
|
||||
|
||||
/* 订单详情弹窗 */
|
||||
.order-detail-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.6); z-index:999; display:flex; justify-content:center; align-items:center; }
|
||||
.order-detail-panel { width:80%; background:#fff; border-radius:20rpx; padding:30rpx; }
|
||||
.order-detail-title { font-size:34rpx; font-weight:bold; margin-bottom:20rpx; color:#333; }
|
||||
.order-detail-item { font-size:28rpx; margin:16rpx 0; color:#555; }
|
||||
.order-detail-close-btn { width:100%; height:80rpx; background:#00aaff; color:#fff; border-radius:12rpx; margin-top:30rpx; font-size:30rpx; }
|
||||
|
||||
/* 底部输入区域 */
|
||||
.input-area { position:fixed; left:0; right:0; background:#f7f7f7; border-top:1rpx solid #ddd; z-index:10; }
|
||||
.plus-panel { position:absolute; bottom:100%; left:0; right:0; background:#fff; border-top:1rpx solid #e0e0e0; padding:20rpx; transform:translateY(100%); opacity:0; transition:0.3s; pointer-events:none; z-index:9; }
|
||||
.plus-panel.show { transform:translateY(0); opacity:1; pointer-events:auto; }
|
||||
.plus-grid { display:flex; justify-content:space-around; }
|
||||
.plus-item { display:flex; flex-direction:column; align-items:center; width:120rpx; }
|
||||
.plus-icon { font-size:60rpx; }
|
||||
.plus-label { font-size:24rpx; color:#666; margin-top:8rpx; }
|
||||
.emoji-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:transparent; z-index:8; }
|
||||
.emoji-panel { position:absolute; bottom:100%; left:0; right:0; background:#fff; border-top:1rpx solid #e0e0e0; height:380rpx; transform:translateY(100%); opacity:0; transition:0.3s; pointer-events:none; z-index:9; }
|
||||
.emoji-panel.show { transform:translateY(0); opacity:1; pointer-events:auto; }
|
||||
.emoji-scroll { height:100%; }
|
||||
.emoji-grid { display:flex; flex-wrap:wrap; padding:20rpx 10rpx; }
|
||||
.emoji-item { width:14.28%; text-align:center; padding:16rpx 0; font-size:44rpx; }
|
||||
.pending-image { display:flex; align-items:center; padding:10rpx 20rpx; background:#fff; }
|
||||
.pending-thumb { width:80rpx; height:80rpx; border-radius:8rpx; }
|
||||
.pending-remove { font-size:30rpx; color:#999; margin-left:10rpx; }
|
||||
.write-row { display:flex; padding:0 20rpx 10rpx; align-items:center; }
|
||||
.text-input { flex:1; height:76rpx; background:#fff; border-radius:12rpx; padding:0 20rpx; font-size:30rpx; margin-right:12rpx; }
|
||||
.send-btn { width:120rpx; height:76rpx; background:#00aaff; color:#fff; font-size:28rpx; font-weight:500; border-radius:12rpx; display:flex; align-items:center; justify-content:center; }
|
||||
.plus-btn { width:56rpx; height:56rpx; display:flex; align-items:center; justify-content:center; margin-left:10rpx; }
|
||||
.plus-icon-single { font-size:46rpx; color:#00aaff; }
|
||||
|
||||
/* 双击放大文本弹窗 */
|
||||
.detail-modal { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.7); z-index:999; display:flex; align-items:center; justify-content:center; }
|
||||
.detail-content { width:80%; max-height:80%; background:#fff; border-radius:16rpx; padding:40rpx; }
|
||||
.detail-text { font-size:32rpx; line-height:1.6; word-break:break-all; overflow-y:auto; }
|
||||
.copy-btn { width:100%; height:80rpx; background:#00aaff; color:#fff; border-radius:12rpx; margin-top:20rpx; font-size:30rpx; }
|
||||
/* 使用全局 chat-* 样式 */
|
||||
|
||||
@@ -215,14 +215,14 @@
|
||||
|
||||
<!-- 弹窗底部按钮 -->
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<view class="cbtn-group">
|
||||
<!-- 联系客服按钮(始终显示) -->
|
||||
<view class="btn btn-kefu" bindtap="lianxiKefu">
|
||||
<view class="cbtn cbtn-kefu" bindtap="lianxiKefu">
|
||||
<text>联系客服</text>
|
||||
</view>
|
||||
<!-- 申诉按钮(只有待处罚状态可点击) -->
|
||||
<view
|
||||
class="btn {{ xuanzhongChufa.sqzhuangtai === 0 ? 'btn-shensu' : 'btn-shensu-disabled' }}"
|
||||
<view
|
||||
class="cbtn {{ xuanzhongChufa.sqzhuangtai === 0 ? 'cbtn-shensu' : 'cbtn-shensu-disabled' }}"
|
||||
bindtap="{{ xuanzhongChufa.sqzhuangtai === 0 ? 'openShensuModal' : '' }}"
|
||||
>
|
||||
<text>申诉</text>
|
||||
@@ -299,11 +299,11 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
<view class="btn-group">
|
||||
<view class="btn btn-quxiao" bindtap="closeShensuModal">
|
||||
<view class="cbtn-group">
|
||||
<view class="cbtn cbtn-quxiao" bindtap="closeShensuModal">
|
||||
<text>取消</text>
|
||||
</view>
|
||||
<view class="btn btn-queren" bindtap="submitShensu">
|
||||
<view class="cbtn cbtn-queren" bindtap="submitShensu">
|
||||
<text>提交申诉</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -625,12 +625,12 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
.cbtn-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
.cbtn {
|
||||
flex: 1;
|
||||
height: 90rpx;
|
||||
display: flex;
|
||||
@@ -645,37 +645,37 @@
|
||||
color: var(--cyber-text) !important;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
.cbtn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn-kefu {
|
||||
.cbtn-kefu {
|
||||
background: rgba(0, 243, 255, 0.1);
|
||||
border-color: var(--cyber-blue);
|
||||
box-shadow: 0 0 12rpx rgba(0, 243, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-shensu {
|
||||
.cbtn-shensu {
|
||||
background: rgba(255, 165, 0, 0.1);
|
||||
border-color: #FFA500;
|
||||
box-shadow: 0 0 12rpx rgba(255, 165, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-shensu-disabled {
|
||||
.cbtn-shensu-disabled {
|
||||
background: rgba(102, 102, 102, 0.1);
|
||||
border-color: #666;
|
||||
box-shadow: 0 0 12rpx rgba(102, 102, 102, 0.2);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.btn-quxiao {
|
||||
.cbtn-quxiao {
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 12rpx rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.btn-queren {
|
||||
.cbtn-queren {
|
||||
background: rgba(0, 255, 157, 0.1);
|
||||
border-color: var(--cyber-green);
|
||||
box-shadow: 0 0 12rpx rgba(0, 255, 157, 0.2);
|
||||
|
||||
@@ -1,307 +1,289 @@
|
||||
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() {}
|
||||
});
|
||||
const app = getApp();
|
||||
import { createPage, request } from '../../utils/base-page.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
import { getOrderStatusText } from '../../utils/api-helper.js';
|
||||
|
||||
Page(createPage({
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
// 加载商品类型(图片拼接)
|
||||
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: getOrderStatusText(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);
|
||||
},
|
||||
|
||||
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() {}
|
||||
}))
|
||||
|
||||
@@ -503,7 +503,7 @@
|
||||
<!-- ======================= -->
|
||||
<view class="tech-footer">
|
||||
<view class="footer-line"></view>
|
||||
<view class="footer-text">星阙网络 © 7891 科技</view>
|
||||
<view class="footer-text">星阙网络 © 科技</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
// pages/dashouzhongxin/dashouzhongxin.js
|
||||
import request from '../../utils/request.js'
|
||||
import popupService from '../../services/popupService.js'
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
syncRoleStatuses,
|
||||
syncProfileFields,
|
||||
syncGroupFields,
|
||||
ensureRoleOnCenterPage,
|
||||
clearCacheAndEnterNormal,
|
||||
} from '../../utils/role-tab-bar.js'
|
||||
import { lockPrimaryRole, migrateLegacyCenterRole, enterLockedRole } from '../../utils/primary-role.js'
|
||||
import { resolveAvatarUrl, resolveAvatarFromStorage } from '../../utils/avatar.js'
|
||||
import { createPage, request, isRoleStatusActive, isCenterPageActive, syncRoleStatuses, syncProfileFields, syncGroupFields, ensureRoleOnCenterPage, clearCacheAndEnterNormal, lockPrimaryRole, migrateLegacyCenterRole, enterLockedRole, parseSceneOptions } from '../../utils/base-page.js'
|
||||
import { resolveAvatarUrl } from '../../utils/avatar.js'
|
||||
import { openPrivateChat, buildInviterPeerId } from '../../utils/im-user.js'
|
||||
|
||||
const PLATFORM_INVITE_CODE = '0000008RffVgKHMj7kQC'
|
||||
|
||||
Page({
|
||||
Page(createPage({
|
||||
data: {
|
||||
// 图片路径对象
|
||||
imgUrls: {},
|
||||
|
||||
|
||||
isDashou: false,
|
||||
isGuanshi: false,
|
||||
isZuzhang: false,
|
||||
@@ -31,7 +20,6 @@ Page({
|
||||
assetBreakdown: [],
|
||||
pendingAuthList: [],
|
||||
showAuthSection: false,
|
||||
isLoading: false,
|
||||
inviteCode: '',
|
||||
guanshiInviteCode: '',
|
||||
zuzhangInviteCode: '',
|
||||
@@ -48,8 +36,6 @@ Page({
|
||||
clumber: [],
|
||||
chengjiaoliang: '',
|
||||
zaixianZhuangtai: 0,
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
isAutoRegistering: false,
|
||||
inviterCache: null,
|
||||
zuzhangInviterCache: null,
|
||||
@@ -165,17 +151,10 @@ Page({
|
||||
});
|
||||
this.checkRoleStatuses();
|
||||
|
||||
const registerType = options.registerType || 'dashou';
|
||||
if (options.scene) {
|
||||
try {
|
||||
const scene = decodeURIComponent(options.scene);
|
||||
options.inviteCode = scene;
|
||||
} catch (e) {
|
||||
console.error('scene解码失败', e);
|
||||
}
|
||||
}
|
||||
const parsed = parseSceneOptions(options);
|
||||
const registerType = parsed.registerType || 'dashou';
|
||||
const { inviteCode } = parsed;
|
||||
this.checkDashouStatus();
|
||||
const { inviteCode } = options || {};
|
||||
if (inviteCode) {
|
||||
if (registerType === 'guanshi') {
|
||||
this.setData({ guanshiInviteCode: inviteCode });
|
||||
@@ -189,26 +168,7 @@ Page({
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
// 注意:不再重复声明 app
|
||||
if (!app.globalData.hasShownPopupOnColdStart) {
|
||||
app.globalData.hasShownPopupOnColdStart = true;
|
||||
setTimeout(() => {
|
||||
popupService.checkAndShow(this, 'dashouduan');
|
||||
}, 300);
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
if (isCenterPageActive(this, 'isDashou', 'dashoustatus')) {
|
||||
ensureRoleOnCenterPage(this, 'dashou');
|
||||
}
|
||||
},
|
||||
|
||||
onHide() {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
if (popupComp && popupComp.cleanup) {
|
||||
popupComp.cleanup();
|
||||
}
|
||||
this.checkColdStartPopup('dashouduan');
|
||||
},
|
||||
|
||||
onShow() {
|
||||
@@ -324,60 +284,36 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
_isApiSuccess(body) {
|
||||
if (!body) return false;
|
||||
const code = Number(body.code);
|
||||
return code === 200 || code === 0;
|
||||
},
|
||||
|
||||
_getApiMsg(body) {
|
||||
if (!body) return '';
|
||||
return body.msg || body.message || '';
|
||||
},
|
||||
|
||||
_extractUserData(body) {
|
||||
if (!body) return {};
|
||||
if (body.data && typeof body.data === 'object' && !Array.isArray(body.data)) {
|
||||
return body.data;
|
||||
}
|
||||
const userData = { ...body };
|
||||
delete userData.code;
|
||||
delete userData.msg;
|
||||
delete userData.message;
|
||||
return userData;
|
||||
},
|
||||
|
||||
async refreshAllInfo(showToast = true) {
|
||||
const now = Date.now();
|
||||
if (!this.data.canRefresh || (now - this.data.lastRefreshTime < 3000)) return;
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false, isLoading: true });
|
||||
try {
|
||||
this.checkRoleStatuses();
|
||||
const results = await Promise.allSettled([
|
||||
this._fetchDashouInfoSilent(),
|
||||
this.fetchChenghaoList(),
|
||||
this._fetchGuanshiInfoSilent(),
|
||||
this.fetchGuanshiChenghaoList(),
|
||||
this._fetchZuzhangInfoSilent(),
|
||||
this._fetchKaoheguanInfoSilent(),
|
||||
]);
|
||||
this.checkRoleStatuses();
|
||||
const dashouOk = results[0].status === 'fulfilled';
|
||||
if (showToast) {
|
||||
wx.showToast({
|
||||
title: dashouOk ? '刷新成功' : '刷新失败',
|
||||
icon: dashouOk ? 'success' : 'none',
|
||||
duration: 1500,
|
||||
});
|
||||
this.throttledRefresh(async () => {
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
this.checkRoleStatuses();
|
||||
const results = await Promise.allSettled([
|
||||
this._fetchDashouInfoSilent(),
|
||||
this.fetchChenghaoList(),
|
||||
this._fetchGuanshiInfoSilent(),
|
||||
this.fetchGuanshiChenghaoList(),
|
||||
this._fetchZuzhangInfoSilent(),
|
||||
this._fetchKaoheguanInfoSilent(),
|
||||
]);
|
||||
this.checkRoleStatuses();
|
||||
const dashouOk = results[0].status === 'fulfilled';
|
||||
if (showToast) {
|
||||
wx.showToast({
|
||||
title: dashouOk ? '刷新成功' : '刷新失败',
|
||||
icon: dashouOk ? 'success' : 'none',
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (showToast) {
|
||||
wx.showToast({ title: '刷新失败', icon: 'none' });
|
||||
}
|
||||
} finally {
|
||||
this.setData({ isLoading: false });
|
||||
}
|
||||
} catch (e) {
|
||||
if (showToast) {
|
||||
wx.showToast({ title: '刷新失败', icon: 'none' });
|
||||
}
|
||||
} finally {
|
||||
this.setData({ isLoading: false });
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000);
|
||||
}
|
||||
}, 3000);
|
||||
},
|
||||
|
||||
refreshDashouInfo() {
|
||||
@@ -875,17 +811,6 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
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()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
checkDashouStatus() {
|
||||
try {
|
||||
const dashoustatus = wx.getStorageSync('dashoustatus');
|
||||
@@ -905,11 +830,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
loadAvatar() {
|
||||
const avatarUrl = resolveAvatarFromStorage(getApp());
|
||||
this.setData({ avatarUrl });
|
||||
},
|
||||
|
||||
checkGlobalData() {
|
||||
const app = getApp();
|
||||
const globalData = app.globalData || {};
|
||||
@@ -1058,19 +978,6 @@ Page({
|
||||
ensureRoleOnCenterPage(this, 'dashou');
|
||||
},
|
||||
|
||||
copyUid() {
|
||||
const { uid } = this.data;
|
||||
if (!uid) {
|
||||
wx.showToast({ title: 'UID不存在', icon: 'none', duration: 1500 });
|
||||
return;
|
||||
}
|
||||
wx.setClipboardData({
|
||||
data: uid,
|
||||
success: () => wx.showToast({ title: '已复制UID', icon: 'success', duration: 1500 }),
|
||||
fail: () => wx.showToast({ title: '复制失败', icon: 'error', duration: 1500 })
|
||||
});
|
||||
},
|
||||
|
||||
previewAvatar() {
|
||||
const { avatarUrl } = this.data;
|
||||
if (avatarUrl) wx.previewImage({ urls: [avatarUrl] });
|
||||
@@ -1079,19 +986,6 @@ Page({
|
||||
goToWithdraw() { wx.navigateTo({ url: '/pages/withdraw/withdraw' }) },
|
||||
goToTotalWithdraw() { this.goToWithdraw(); },
|
||||
|
||||
goToKefu() {
|
||||
const app = getApp();
|
||||
const { link, enterpriseId } = app.globalData.kefuConfig || {};
|
||||
if (!link || !enterpriseId) {
|
||||
wx.showToast({ title: '客服配置未加载', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: { url: link },
|
||||
corpId: enterpriseId,
|
||||
});
|
||||
},
|
||||
|
||||
goToAuth(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
if (!type || !['dashou', 'shangjia', 'guanshi', 'zuzhang'].includes(type)) return;
|
||||
@@ -1171,20 +1065,4 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
clearCache() {
|
||||
wx.showModal({
|
||||
title: '清除缓存',
|
||||
content: '将清除所有登录与身份数据,并回到点单端,确定继续?',
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
success: (r) => {
|
||||
if (r.confirm) clearCacheAndEnterNormal(this);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
switchToNormal() {
|
||||
lockPrimaryRole('normal');
|
||||
wx.reLaunch({ url: '/pages/mine/mine' });
|
||||
},
|
||||
})
|
||||
}, { roleConfig: { role: 'dashou', statusKey: 'dashoustatus', dataFlag: 'isDashou', pageId: 'dashouduan', apiUrl: '/yonghu/dashouxinxi' } }))
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
>
|
||||
<view class="rank-cell-inner">
|
||||
<image class="rank-bg-icon" src="{{item.icon}}" mode="aspectFit" />
|
||||
<view class="rank-content">
|
||||
<view class="rank-cell-content">
|
||||
<image class="rank-main-icon" src="{{item.icon}}" mode="aspectFit" />
|
||||
<text class="rank-cell-name">{{item.name}}</text>
|
||||
<text class="rank-cell-sub">{{item.sub}}</text>
|
||||
|
||||
@@ -469,7 +469,7 @@ page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
@@ -477,25 +477,27 @@ page {
|
||||
|
||||
.rank-bg-icon {
|
||||
position: absolute;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
right: -12rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
right: 8rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) rotate(-10deg);
|
||||
opacity: 0.15;
|
||||
opacity: 0.12;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.rank-content {
|
||||
.rank-cell-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.rank-main-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
margin-bottom: 6rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.rank-shape-right .rank-cell-inner {
|
||||
@@ -509,7 +511,7 @@ page {
|
||||
transform: translateY(-50%) rotate(10deg);
|
||||
}
|
||||
|
||||
.rank-shape-right .rank-content {
|
||||
.rank-shape-right .rank-cell-content {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +1,92 @@
|
||||
<view class="chat-page">
|
||||
<scroll-view class="msg-list" scroll-y="true"
|
||||
<scroll-view class="chat-msg-list" scroll-y="true"
|
||||
scroll-into-view="{{scrollToView}}"
|
||||
refresher-enabled="{{true}}"
|
||||
refresher-triggered="{{isRefreshing}}"
|
||||
bindrefresherrefresh="onPullDownRefresh"
|
||||
style="top: 20rpx; bottom: calc({{bottomSafeHeight}}rpx + {{keyboardHeight}}px + env(safe-area-inset-bottom) + 20rpx);">
|
||||
<view class="loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<view class="chat-loading-more" wx:if="{{loadingHistory}}">加载更早消息...</view>
|
||||
<block wx:for="{{messages}}" wx:key="messageId">
|
||||
<view class="msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="msg-row {{item.senderId === currentUser.id ? 'right' : 'left'}}">
|
||||
<view class="chat-msg-wrapper" data-messageid="{{item.messageId}}" bindlongpress="showAction">
|
||||
<view class="chat-time-tag" wx:if="{{item.showTime}}">{{item.formattedTime}}</view>
|
||||
<view class="chat-msg-row {{item.senderId === currentUser.id ? 'chat-msg-row--right' : 'chat-msg-row--left'}}">
|
||||
<!-- 对方头像及昵称 -->
|
||||
<view wx:if="{{item.senderId !== currentUser.id}}" class="sender-info">
|
||||
<image class="avatar" src="{{item.senderData.avatar || '/images/default-avatar.png'}}" mode="aspectFill" />
|
||||
<image class="chat-avatar" src="{{item.senderData.avatar || '/images/default-avatar.png'}}" mode="aspectFill" />
|
||||
<text class="sender-name">{{item.senderData.name || item.senderId}}</text>
|
||||
</view>
|
||||
<view class="bubble {{item.senderId === currentUser.id ? 'bubble-right' : 'bubble-left'}}"
|
||||
<view class="chat-bubble {{item.senderId === currentUser.id ? 'chat-bubble--right' : 'chat-bubble--left'}}"
|
||||
data-messageid="{{item.messageId}}"
|
||||
data-text="{{item.type==='text' ? item.payload.text : ''}}"
|
||||
bindtap="{{item.type==='text' ? 'onBubbleTap' : (item.type==='image' ? 'previewImage' : '')}}"
|
||||
data-url="{{item.type==='image' ? item.payload.url : ''}}">
|
||||
<text wx:if="{{item.type === 'text'}}" class="msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="msg-image" src="{{item.payload.url}}" mode="widthFix" />
|
||||
<view wx:elif="{{item.type === 'order'}}" class="order-bubble" data-payload="{{item.payload}}" bindtap="viewOrderDetail">
|
||||
<text class="order-label">[订单]</text>
|
||||
<text class="order-info">ID: {{item.payload.orderId}}</text>
|
||||
<text class="order-info">内容: {{item.payload.jieshao}}</text>
|
||||
<text class="order-info">金额: ¥{{item.payload.jine}}</text>
|
||||
<view class="order-detail-link">点击查看详情</view>
|
||||
<text wx:if="{{item.type === 'text'}}" class="chat-msg-text">{{item.payload.text}}</text>
|
||||
<image wx:elif="{{item.type === 'image'}}" class="chat-msg-image" src="{{item.payload.url}}" mode="widthFix" />
|
||||
<view wx:elif="{{item.type === 'order'}}" class="chat-order-bubble" data-payload="{{item.payload}}" bindtap="viewOrderDetail">
|
||||
<text class="chat-order-label">[订单]</text>
|
||||
<text class="chat-order-info">ID: {{item.payload.orderId}}</text>
|
||||
<text class="chat-order-info">内容: {{item.payload.jieshao}}</text>
|
||||
<text class="chat-order-info">金额: ¥{{item.payload.jine}}</text>
|
||||
<view class="chat-order-info" style="color:#007aff;margin-top:8rpx">点击查看详情</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 自己的头像 -->
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="avatar" src="{{currentUser.avatar}}" mode="aspectFill" />
|
||||
<image wx:if="{{item.senderId === currentUser.id}}" class="chat-avatar" src="{{currentUser.avatar}}" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view id="msg-bottom" style="height:20rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="plus-grid">
|
||||
<view class="plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="plus-icon">😀</text>
|
||||
<text class="plus-label">表情</text>
|
||||
<view class="chat-input-area" style="bottom: {{keyboardHeight}}px; padding-bottom: calc(10rpx + env(safe-area-inset-bottom));">
|
||||
<view class="chat-plus-panel {{showPlusPanel ? 'show' : ''}}" catchtap="closePlusPanel">
|
||||
<view class="chat-plus-grid">
|
||||
<view class="chat-plus-item" catchtap="openEmojiFromPlus">
|
||||
<text class="chat-plus-icon">😀</text>
|
||||
<text class="chat-plus-label">表情</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="chooseImage">
|
||||
<text class="plus-icon">📷</text>
|
||||
<text class="plus-label">图片</text>
|
||||
<view class="chat-plus-item" catchtap="chooseImage">
|
||||
<text class="chat-plus-icon">📷</text>
|
||||
<text class="chat-plus-label">图片</text>
|
||||
</view>
|
||||
<view class="plus-item" catchtap="openOrderSender">
|
||||
<text class="plus-icon">📋</text>
|
||||
<text class="plus-label">订单</text>
|
||||
<view class="chat-plus-item" catchtap="openOrderSender">
|
||||
<text class="chat-plus-icon">📋</text>
|
||||
<text class="chat-plus-label">订单</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="emoji-scroll">
|
||||
<view class="emoji-grid">
|
||||
<view class="chat-emoji-mask" wx:if="{{showEmojiPanel}}" catchtap="closeEmojiPanel"></view>
|
||||
<view class="chat-emoji-panel {{showEmojiPanel ? 'show' : ''}}">
|
||||
<scroll-view scroll-y="true" class="chat-emoji-scroll">
|
||||
<view class="chat-emoji-grid">
|
||||
<block wx:for="{{emojiList}}" wx:key="*this">
|
||||
<view class="emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
<view class="chat-emoji-item" data-emoji="{{item}}" catchtap="insertEmoji">{{item}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
<view class="chat-pending-image" wx:if="{{pendingImage}}">
|
||||
<image class="chat-pending-thumb" src="{{pendingImage}}" mode="aspectFill" />
|
||||
<view class="chat-pending-remove" catchtap="clearPendingImage">✕</view>
|
||||
</view>
|
||||
|
||||
<view class="write-row">
|
||||
<input class="text-input" placeholder="发送消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="plus-icon-single">➕</text>
|
||||
<view class="chat-write-row">
|
||||
<input class="chat-text-input" placeholder="发送消息" value="{{inputText}}" bindinput="onInput" adjust-position="{{false}}" bindkeyboardheightchange="onKeyboardHeightChange" cursor-spacing="10"/>
|
||||
<view class="chat-send-btn" bindtap="sendMessage">发送</view>
|
||||
<view class="chat-plus-btn" bindtap="togglePlusPanel">
|
||||
<text class="chat-plus-icon-single">➕</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="detail-content" catchtap="noop">
|
||||
<text class="detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="copy-btn" bindtap="copyDetail">复制</button>
|
||||
<view class="chat-detail-modal" wx:if="{{showDetailModal}}" catchtap="hideDetail">
|
||||
<view class="chat-detail-content" catchtap="noop">
|
||||
<text class="chat-detail-text" user-select="true">{{detailText}}</text>
|
||||
<button class="chat-copy-btn" bindtap="copyDetail">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<order-sender visible="{{showOrderSender}}" bind:send="onSendOrder" bind:close="closeOrderSender" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,97 +1,6 @@
|
||||
.chat-page { width:100%; height:100vh; background:#f5f5f5; }
|
||||
/* 使用全局 chat-* 样式 */
|
||||
|
||||
.msg-list {
|
||||
position: absolute;
|
||||
left:0; right:0;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.loading-more { text-align:center; font-size:24rpx; color:#999; padding:20rpx 0; }
|
||||
.time-tag { text-align:center; margin:28rpx 0; font-size:24rpx; color:#b0b0b0; }
|
||||
.msg-wrapper { margin-bottom:12rpx; }
|
||||
.msg-row { display:flex; align-items:flex-start; margin-bottom:4rpx; }
|
||||
.right { justify-content:flex-end; }
|
||||
.left { justify-content:flex-start; }
|
||||
.avatar { width:76rpx; height:76rpx; border-radius:50%; background:#e0e0e0; margin:0 12rpx; flex-shrink:0; }
|
||||
.bubble { max-width:70%; padding:16rpx 20rpx; border-radius:16rpx; position:relative; word-break:break-all; font-size:30rpx; line-height:1.5; }
|
||||
.bubble-left { background:#fff; border-top-left-radius:4rpx; }
|
||||
.bubble-right { background:#00aaff; color:#fff; border-top-right-radius:4rpx; }
|
||||
.msg-text { color:inherit; }
|
||||
.msg-image { max-width:240rpx; border-radius:10rpx; }
|
||||
|
||||
.order-bubble { background:#fff7e0; padding:12rpx; border-radius:8rpx; }
|
||||
.order-label { font-size:24rpx; color:#e6a23c; font-weight:600; }
|
||||
.order-info { font-size:24rpx; color:#333; margin:6rpx 0; }
|
||||
.order-detail-link { color:#007aff; font-size:24rpx; margin-top:8rpx; }
|
||||
|
||||
.input-area {
|
||||
position: fixed;
|
||||
left:0; right:0;
|
||||
background:#f7f7f7;
|
||||
border-top:1rpx solid #ddd;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.plus-panel {
|
||||
position: absolute;
|
||||
bottom:100%; left:0; right:0;
|
||||
background:#fff;
|
||||
border-top:1rpx solid #e0e0e0;
|
||||
padding: 20rpx;
|
||||
transform: translateY(100%);
|
||||
opacity:0;
|
||||
transition: transform 0.3s, opacity 0.3s;
|
||||
pointer-events:none;
|
||||
z-index:9;
|
||||
}
|
||||
.plus-panel.show { transform: translateY(0); opacity:1; pointer-events:auto; }
|
||||
.plus-grid { display: flex; justify-content: space-around; }
|
||||
.plus-item { display: flex; flex-direction: column; align-items: center; width: 120rpx; }
|
||||
.plus-icon { font-size: 60rpx; }
|
||||
.plus-label { font-size: 24rpx; color: #666; margin-top: 8rpx; }
|
||||
|
||||
.emoji-mask { position:fixed; top:0; left:0; right:0; bottom:0; background:transparent; z-index:8; }
|
||||
.emoji-panel {
|
||||
position: absolute; bottom:100%; left:0; right:0;
|
||||
background:#fff; border-top:1rpx solid #e0e0e0;
|
||||
height:380rpx;
|
||||
transform: translateY(100%); opacity:0; transition:0.3s;
|
||||
pointer-events:none; z-index:9;
|
||||
}
|
||||
.emoji-panel.show { transform:translateY(0); opacity:1; pointer-events:auto; }
|
||||
.emoji-scroll { height:100%; }
|
||||
.emoji-grid { display:flex; flex-wrap:wrap; padding:20rpx 10rpx; }
|
||||
.emoji-item { width:14.28%; text-align:center; padding:16rpx 0; font-size:44rpx; }
|
||||
|
||||
.pending-image { display:flex; align-items:center; padding:10rpx 20rpx; background:#fff; }
|
||||
.pending-thumb { width:80rpx; height:80rpx; border-radius:8rpx; }
|
||||
.pending-remove { font-size:30rpx; color:#999; margin-left:10rpx; }
|
||||
|
||||
.write-row { display:flex; padding:0 20rpx 10rpx; align-items:center; }
|
||||
.text-input {
|
||||
flex:1; height:76rpx; background:#fff; border-radius:12rpx;
|
||||
padding:0 20rpx; font-size:30rpx; margin-right:12rpx;
|
||||
}
|
||||
.send-btn {
|
||||
width:120rpx; height:76rpx; background:#00aaff; color:#fff;
|
||||
font-size:28rpx; font-weight:500; border-radius:12rpx;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.plus-btn {
|
||||
width:56rpx; height:56rpx;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.plus-icon-single { font-size:46rpx; color:#00aaff; }
|
||||
|
||||
.detail-modal { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.7); z-index:999; display:flex; align-items:center; justify-content:center; }
|
||||
.detail-content { width:80%; max-height:80%; background:#fff; border-radius:16rpx; padding:40rpx; }
|
||||
.detail-text { font-size:32rpx; line-height:1.6; word-break:break-all; overflow-y:auto; }
|
||||
.copy-btn { width:100%; height:80rpx; background:#00aaff; color:#fff; border-radius:12rpx; margin-top:20rpx; font-size:30rpx; }
|
||||
|
||||
/* 发送者昵称样式 */
|
||||
/* 发送者昵称样式(群聊特有) */
|
||||
.sender-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -106,4 +15,4 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ import { ensureLogin } from '../../utils/login';
|
||||
import { fetchShopGoods, bindShop } from '../../utils/shop';
|
||||
import { backfillUserProfileCache, getSessionToken } from '../../utils/role-tab-bar';
|
||||
import PopupService from '../../services/popupService.js';
|
||||
import { createPage } from '../../utils/base-page.js';
|
||||
|
||||
// 扫码场景参数名
|
||||
const SCENE_PARAM = 'scene';
|
||||
|
||||
Page({
|
||||
Page(createPage({
|
||||
data: {
|
||||
ossImageUrl: '',
|
||||
lunbozhanwei: '',
|
||||
@@ -26,7 +27,7 @@ Page({
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
hasInitialized: false,
|
||||
|
||||
|
||||
currentTime: ''
|
||||
},
|
||||
|
||||
@@ -43,7 +44,7 @@ Page({
|
||||
console.error('scene解码失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 等待全局配置加载完成
|
||||
this.waitForConfigAndInit();
|
||||
// 已登录时才检查弹窗
|
||||
@@ -107,16 +108,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
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();
|
||||
@@ -234,12 +225,12 @@ Page({
|
||||
*/
|
||||
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) {
|
||||
@@ -249,7 +240,7 @@ Page({
|
||||
zhuanquByLeixing.get(selectedLeixingId).push(zhuanqu);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const shangpinByZhuanqu = new Map();
|
||||
shangpinliebiao.forEach(shangpin => {
|
||||
if (shangpin.leixing_id === selectedLeixingId && shangpin.zhuanqu_id) {
|
||||
@@ -257,7 +248,7 @@ Page({
|
||||
if (!shangpinByZhuanqu.has(zhuanquId)) {
|
||||
shangpinByZhuanqu.set(zhuanquId, []);
|
||||
}
|
||||
|
||||
|
||||
const jiage = parseFloat(shangpin.jiage) || 0;
|
||||
const priceInteger = Math.floor(jiage);
|
||||
let priceDecimal = '00';
|
||||
@@ -265,7 +256,7 @@ Page({
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1];
|
||||
}
|
||||
|
||||
|
||||
shangpinByZhuanqu.get(zhuanquId).push({
|
||||
id: shangpin.id,
|
||||
biaoqian: shangpin.biaoqian,
|
||||
@@ -278,10 +269,10 @@ Page({
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const filteredData = [];
|
||||
const currentZhuanquList = zhuanquByLeixing.get(selectedLeixingId) || [];
|
||||
|
||||
|
||||
currentZhuanquList.forEach(zhuanqu => {
|
||||
const shangpinList = shangpinByZhuanqu.get(zhuanqu.id) || [];
|
||||
if (shangpinList.length > 0) {
|
||||
@@ -295,14 +286,14 @@ Page({
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
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 });
|
||||
},
|
||||
|
||||
@@ -315,18 +306,21 @@ Page({
|
||||
},
|
||||
|
||||
showGonggaoDetail() {
|
||||
this.setData({
|
||||
this.setData({
|
||||
showGonggaoModal: true,
|
||||
_modalLeaving: false,
|
||||
gonggaoAnim: false,
|
||||
currentTime: this.getCurrentTime()
|
||||
});
|
||||
},
|
||||
|
||||
hideGonggaoDetail() {
|
||||
this.setData({
|
||||
this.setData({
|
||||
showGonggaoModal: false,
|
||||
gonggaoAnim: true
|
||||
_modalLeaving: true,
|
||||
gonggaoAnim: true
|
||||
});
|
||||
setTimeout(() => this.setData({ _modalLeaving: false }), 300);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -388,4 +382,4 @@ Page({
|
||||
onUnload() {
|
||||
this.setData({ gonggaoAnim: false });
|
||||
}
|
||||
});
|
||||
}))
|
||||
|
||||
@@ -146,9 +146,9 @@
|
||||
</view>
|
||||
|
||||
<!-- 公告详情弹窗 -->
|
||||
<view class="gonggao-modal" wx:if="{{showGonggaoModal}}">
|
||||
<view class="modal-mask" bindtap="hideGonggaoDetail"></view>
|
||||
<view class="modal-content">
|
||||
<view class="gonggao-modal {{showGonggaoModal ? 'gonggao-modal--show' : 'gonggao-modal--hide'}}" wx:if="{{showGonggaoModal || _modalLeaving}}">
|
||||
<view class="modal-mask {{showGonggaoModal ? 'modal-mask--in' : 'modal-mask--out'}}" bindtap="hideGonggaoDetail"></view>
|
||||
<view class="modal-content {{showGonggaoModal ? 'modal-content--in' : 'modal-content--out'}}">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">公告详情</text>
|
||||
<view class="modal-close" bindtap="hideGonggaoDetail">×</view>
|
||||
|
||||
@@ -411,3 +411,82 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-mask {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 0;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-mask--in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-mask--out {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 620rpx;
|
||||
max-height: 70vh;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-content--in {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-content--out {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 32rpx 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-close {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
border-radius: 50%;
|
||||
background: #f5f5f5;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-body {
|
||||
flex: 1;
|
||||
padding: 28rpx 32rpx 36rpx;
|
||||
max-height: 55vh;
|
||||
}
|
||||
|
||||
.gonggao-modal .modal-text {
|
||||
font-size: 28rpx;
|
||||
color: #444;
|
||||
line-height: 1.8;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,225 +1,135 @@
|
||||
// pages/leader/leader.js
|
||||
import request from '../../utils/request.js'
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
syncRoleStatuses,
|
||||
syncProfileFields,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar.js'
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 页面状态
|
||||
isZuzhang: false,
|
||||
isLoading: false,
|
||||
|
||||
// 邀请码
|
||||
inviteCode: '',
|
||||
|
||||
// 用户信息
|
||||
uid: '',
|
||||
nicheng: '',
|
||||
avatarUrl: '',
|
||||
|
||||
// 组长信息
|
||||
ketixian: '0.00',
|
||||
guanshiCount: 0,
|
||||
fenhongZonge: '0.00',
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' });
|
||||
return;
|
||||
// 以下保留供恢复参考
|
||||
this.checkLoginStatus()
|
||||
},
|
||||
|
||||
onReady() {
|
||||
if (isCenterPageActive(this, 'isZuzhang', 'zuzhangstatus')) {
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent()
|
||||
if (isCenterPageActive(this, 'isZuzhang', 'zuzhangstatus')) {
|
||||
if (!this.data.isZuzhang) this.setData({ isZuzhang: true })
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
this.getZuzhangInfo()
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '您尚未登录,请先登录',
|
||||
confirmText: '去登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.reLaunch({ url: '/pages/gerenzhongxin/gerenzhongxin' })
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
this.checkZuzhangStatus()
|
||||
return true
|
||||
},
|
||||
|
||||
// 检查组长状态
|
||||
checkZuzhangStatus() {
|
||||
try {
|
||||
const zuzhangstatus = wx.getStorageSync('zuzhangstatus')
|
||||
if (isRoleStatusActive(zuzhangstatus)) {
|
||||
this.setData({ isZuzhang: true })
|
||||
this.loadUserInfo()
|
||||
this.getZuzhangInfo()
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
} else {
|
||||
this.setData({ isZuzhang: false })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('读取缓存失败:', error)
|
||||
this.setData({ isZuzhang: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 加载用户信息
|
||||
loadUserInfo() {
|
||||
const app = getApp()
|
||||
const globalData = app.globalData || {}
|
||||
|
||||
const touxiang = wx.getStorageSync('touxiang')
|
||||
const ossImageUrl = globalData.ossImageUrl || ''
|
||||
const morentouxiang = globalData.morentouxiang || 'avatar/default.jpg'
|
||||
|
||||
let avatarUrl = ''
|
||||
if (touxiang) {
|
||||
avatarUrl = ossImageUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang)
|
||||
} else {
|
||||
avatarUrl = ossImageUrl + (morentouxiang.startsWith('/') ? morentouxiang : '/' + morentouxiang)
|
||||
}
|
||||
|
||||
const uid = wx.getStorageSync('uid') || ''
|
||||
const nicheng = wx.getStorageSync('nicheng') || globalData.nicheng || ''
|
||||
|
||||
this.setData({ avatarUrl, uid, nicheng })
|
||||
},
|
||||
|
||||
// 注册通知组件
|
||||
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()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 获取组长信息(刷新)
|
||||
async getZuzhangInfo() {
|
||||
this.setData({ isLoading: true })
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/zuzhangxinxi',
|
||||
method: 'POST'
|
||||
})
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data
|
||||
this.setData({
|
||||
ketixian: data.ketixian || '0.00',
|
||||
guanshiCount: data.guanshiCount || 0,
|
||||
fenhongZonge: data.fenhongZonge || '0.00',
|
||||
isLoading: false
|
||||
})
|
||||
wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 })
|
||||
} else {
|
||||
throw new Error(res?.data?.msg || '获取信息失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取组长信息失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: error.message || '刷新失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新按钮点击
|
||||
refreshZuzhangInfo() {
|
||||
this.getZuzhangInfo()
|
||||
},
|
||||
|
||||
// 邀请码输入
|
||||
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: '/yonghu/zuzhangzhuce',
|
||||
method: 'POST',
|
||||
data: { inviteCode }
|
||||
})
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data || {}
|
||||
syncRoleStatuses(data)
|
||||
syncProfileFields(data)
|
||||
if (!Object.prototype.hasOwnProperty.call(data, 'zuzhangstatus')) {
|
||||
wx.setStorageSync('zuzhangstatus', 1)
|
||||
}
|
||||
this.setData({
|
||||
isZuzhang: true,
|
||||
ketixian: data.ketixian || '0.00',
|
||||
guanshiCount: data.guanshiCount || 0,
|
||||
fenhongZonge: data.fenhongZonge || '0.00',
|
||||
isLoading: false
|
||||
})
|
||||
this.loadUserInfo()
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
wx.showToast({ title: '注册成功!', icon: 'success', duration: 2000 })
|
||||
} else {
|
||||
throw new Error(res?.data?.msg || '注册失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('注册失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: error.message || '注册失败', icon: 'error' })
|
||||
}
|
||||
},
|
||||
|
||||
// 跳转到提现页面
|
||||
goToWithdraw() {
|
||||
const { ketixian } = this.data
|
||||
wx.navigateTo({
|
||||
url: `/pages/withdraw/withdraw?from=zuzhang&amount=${ketixian}`
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到分红记录
|
||||
goToFenhongJilu() {
|
||||
wx.navigateTo({ url: '/pages/leader-bonus-log/leader-bonus-log' })
|
||||
},
|
||||
|
||||
// 跳转到邀请管事
|
||||
goToYaoqingGuanshi() {
|
||||
wx.navigateTo({ url: '/pages/invite-manager/invite-manager' })
|
||||
}
|
||||
})
|
||||
// pages/leader/leader.js
|
||||
import { createPage, request, syncRoleStatuses, syncProfileFields, ensureRoleOnCenterPage, isCenterPageActive, parseSceneOptions } from '../../utils/base-page.js'
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
isZuzhang: false,
|
||||
|
||||
// 邀请码
|
||||
inviteCode: '',
|
||||
|
||||
// 用户信息
|
||||
uid: '',
|
||||
nicheng: '',
|
||||
avatarUrl: '',
|
||||
|
||||
// 组长信息
|
||||
ketixian: '0.00',
|
||||
guanshiCount: 0,
|
||||
fenhongZonge: '0.00',
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const parsed = parseSceneOptions(options)
|
||||
if (parsed.inviteCode) {
|
||||
this.setData({ inviteCode: parsed.inviteCode })
|
||||
}
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' })
|
||||
return
|
||||
// 以下保留供恢复参考
|
||||
this.checkLoginStatus()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent()
|
||||
this.checkColdStartPopup('zuzhangduan')
|
||||
if (isCenterPageActive(this, 'isZuzhang', 'zuzhangstatus')) {
|
||||
if (!this.data.isZuzhang) this.setData({ isZuzhang: true })
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
this.getZuzhangInfo()
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '您尚未登录,请先登录',
|
||||
confirmText: '去登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.reLaunch({ url: '/pages/gerenzhongxin/gerenzhongxin' })
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
this.checkRoleStatus()
|
||||
return true
|
||||
},
|
||||
|
||||
// 角色状态检查后的额外数据加载(由 mixin 的 checkRoleStatus 调用)
|
||||
checkGlobalData() {
|
||||
this.loadUserInfo()
|
||||
this.getZuzhangInfo()
|
||||
},
|
||||
|
||||
// 获取组长信息(刷新)
|
||||
async getZuzhangInfo() {
|
||||
this.loadData({
|
||||
url: '/yonghu/zuzhangxinxi',
|
||||
method: 'POST',
|
||||
errorMsg: '获取信息失败',
|
||||
onSuccess: (data) => {
|
||||
this.setData({
|
||||
ketixian: data.ketixian || '0.00',
|
||||
guanshiCount: data.guanshiCount || 0,
|
||||
fenhongZonge: data.fenhongZonge || '0.00',
|
||||
})
|
||||
wx.showToast({ title: '刷新成功', icon: 'success', duration: 1500 })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新按钮点击
|
||||
refreshZuzhangInfo() {
|
||||
this.throttledRefresh(this.getZuzhangInfo)
|
||||
},
|
||||
|
||||
// 邀请码输入
|
||||
onInviteCodeInput(e) {
|
||||
this.setData({ inviteCode: e.detail.value.trim() })
|
||||
},
|
||||
|
||||
// 注册组长
|
||||
onRegister() {
|
||||
const { inviteCode } = this.data
|
||||
this.registerWithInviteCode({
|
||||
inviteCode,
|
||||
apiUrl: '/yonghu/zuzhangzhuce',
|
||||
role: 'zuzhang',
|
||||
statusKey: 'zuzhangstatus',
|
||||
successMsg: '注册成功!',
|
||||
onSuccess: (userData) => {
|
||||
this.setData({
|
||||
isZuzhang: true,
|
||||
ketixian: userData.ketixian || '0.00',
|
||||
guanshiCount: userData.guanshiCount || 0,
|
||||
fenhongZonge: userData.fenhongZonge || '0.00',
|
||||
})
|
||||
this.loadUserInfo()
|
||||
ensureRoleOnCenterPage(this, 'zuzhang')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到提现页面
|
||||
goToWithdraw() {
|
||||
const { ketixian } = this.data
|
||||
wx.navigateTo({
|
||||
url: `/pages/withdraw/withdraw?from=zuzhang&amount=${ketixian}`
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到分红记录
|
||||
goToFenhongJilu() {
|
||||
wx.navigateTo({ url: '/pages/leader-bonus-log/leader-bonus-log' })
|
||||
},
|
||||
|
||||
// 跳转到邀请管事
|
||||
goToYaoqingGuanshi() {
|
||||
wx.navigateTo({ url: '/pages/invite-manager/invite-manager' })
|
||||
}
|
||||
}, { roleConfig: { role: 'dashou', statusKey: 'zuzhangstatus', dataFlag: 'isZuzhang', pageId: 'zuzhangduan', apiUrl: '/yonghu/zuzhangxinxi' } }))
|
||||
|
||||
@@ -1,235 +1,205 @@
|
||||
<!-- pages/guanshi-paihang/guanshi-paihang.wxml -->
|
||||
<view class="guanshi-paihang-page">
|
||||
|
||||
<!-- pages/manager-rank/manager-rank.wxml -->
|
||||
<view class="rank-page">
|
||||
|
||||
<!-- 赛博朋克背景元素 -->
|
||||
<view class="cyber-bg">
|
||||
<view class="rank-cyber-bg">
|
||||
<!-- 网格线 -->
|
||||
<view class="cyber-grid"></view>
|
||||
<view class="rank-cyber-grid"></view>
|
||||
<!-- 扫描线 -->
|
||||
<view class="cyber-scanline"></view>
|
||||
<view class="rank-cyber-scanline"></view>
|
||||
<!-- 流动数据流 -->
|
||||
<view class="data-streams">
|
||||
<view class="stream stream-1"></view>
|
||||
<view class="stream stream-2"></view>
|
||||
<view class="stream stream-3"></view>
|
||||
<view class="rank-data-streams">
|
||||
<view class="rank-stream rank-stream--1"></view>
|
||||
<view class="rank-stream rank-stream--2"></view>
|
||||
<view class="rank-stream rank-stream--3"></view>
|
||||
</view>
|
||||
<!-- 浮动粒子 -->
|
||||
<view class="floating-particles">
|
||||
<view class="particle" wx:for="{{12}}" wx:key="index"></view>
|
||||
</view>
|
||||
<view class="rank-particle" wx:for="{{12}}" wx:key="index"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 页面头部 -->
|
||||
<view class="page-header">
|
||||
<view class="rank-page-header">
|
||||
<!-- 标题 -->
|
||||
<view class="title-container">
|
||||
<text class="main-title">管事排行榜</text>
|
||||
<view class="title-line"></view>
|
||||
<text class="sub-title">GUANSHI RANKING</text>
|
||||
<view class="rank-title-container">
|
||||
<text class="rank-main-title">管事排行榜</text>
|
||||
<view class="rank-title-line"></view>
|
||||
<text class="rank-sub-title">GUANSHI RANKING</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 切换按钮 -->
|
||||
<view class="toggle-container">
|
||||
<view class="toggle-bg" style="transform: translateX({{paihangLeixing == 1 ? '0' : '100%'}});"></view>
|
||||
<view
|
||||
class="toggle-btn {{paihangLeixing == 1 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
<view class="rank-toggle-container">
|
||||
<view class="rank-toggle-bg" style="transform: translateX({{paihangLeixing == 1 ? '0' : '100%'}});"></view>
|
||||
<view
|
||||
class="rank-toggle-btn {{paihangLeixing == 1 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
data-leixing="1"
|
||||
bindtap="qiehuangPaihangLeixing"
|
||||
>
|
||||
<text class="toggle-text">今日充值人数</text>
|
||||
<view class="toggle-line {{paihangLeixing == 1 ? 'active' : ''}}"></view>
|
||||
<text class="rank-toggle-text">今日充值人数</text>
|
||||
<view class="rank-toggle-line {{paihangLeixing == 1 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
<view
|
||||
class="toggle-btn {{paihangLeixing == 2 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
<view
|
||||
class="rank-toggle-btn {{paihangLeixing == 2 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
data-leixing="2"
|
||||
bindtap="qiehuangPaihangLeixing"
|
||||
>
|
||||
<text class="toggle-text">今月充值人数</text>
|
||||
<view class="toggle-line {{paihangLeixing == 2 ? 'active' : ''}}"></view>
|
||||
<text class="rank-toggle-text">今月充值人数</text>
|
||||
<view class="rank-toggle-line {{paihangLeixing == 2 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view wx:if="{{jiazaiZhuangtai}}" class="loading-state">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner">
|
||||
<view class="spinner-outer"></view>
|
||||
<view class="spinner-inner"></view>
|
||||
<view class="spinner-core"></view>
|
||||
</view>
|
||||
<text class="loading-text">数据加载中</text>
|
||||
<text class="loading-sub">Connecting to server...</text>
|
||||
<view wx:if="{{jiazaiZhuangtai}}" class="rank-loading-state">
|
||||
<view class="rank-loading-spinner">
|
||||
<view class="rank-spinner-outer"></view>
|
||||
<view class="rank-spinner-inner"></view>
|
||||
<view class="rank-spinner-core"></view>
|
||||
</view>
|
||||
<text class="rank-loading-text">数据加载中</text>
|
||||
<text class="rank-loading-sub">Connecting to server...</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 排行榜内容 -->
|
||||
<view wx:else class="ranking-content">
|
||||
|
||||
<view wx:else class="rank-content">
|
||||
|
||||
<!-- 虚拟数据提示 -->
|
||||
<view wx:if="{{!xianshiZhenshiShuju}}" class="demo-notice">
|
||||
<view class="notice-icon">📡</view>
|
||||
<view class="notice-content">
|
||||
<text class="notice-title">排行榜数据准备中</text>
|
||||
<text class="notice-desc">当前显示为模拟数据,实时排名即将开放</text>
|
||||
<view wx:if="{{!xianshiZhenshiShuju}}" class="rank-demo-notice">
|
||||
<view class="rank-notice-icon">📡</view>
|
||||
<view class="rank-notice-content">
|
||||
<text class="rank-notice-title">排行榜数据准备中</text>
|
||||
<text class="rank-notice-desc">当前显示为模拟数据,实时排名即将开放</text>
|
||||
</view>
|
||||
<view class="notice-glow"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- ========== 前三名区域 ========== -->
|
||||
<view class="top-three-section" wx:if="{{qiansanMing.length > 0}}">
|
||||
|
||||
<view class="rank-top-three" wx:if="{{qiansanMing.length > 0}}">
|
||||
|
||||
<!-- 第二名 -->
|
||||
<view class="rank-card rank-2 {{flashCardIndex == 1 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--2 {{flashCardIndex == 1 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 1 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="1" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
<view class="podium-base podium-silver">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">2</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-silver">
|
||||
<text class="rank-podium-number">2</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-silver">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[1] ? qiansanMing[1].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-silver"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-silver">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[1] ? qiansanMing[1].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-silver"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-silver">2</view>
|
||||
<view class="rank-badge rank-badge-silver">2</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[1] ? qiansanMing[1].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[1] ? qiansanMing[1].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[1] ? qiansanMing[1].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[1] ? qiansanMing[1].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">充值大手:</text>
|
||||
<view class="income-value">
|
||||
<text class="amount {{qiansanMing[1] ? qiansanMing[1].jineClass : ''}}">{{qiansanMing[1] ? qiansanMing[1].jine : '0'}}</text>
|
||||
<text class="unit">人</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">充值大手:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-amount {{qiansanMing[1] ? qiansanMing[1].jineClass : ''}}">{{qiansanMing[1] ? qiansanMing[1].jine : '0'}}</text>
|
||||
<text class="rank-unit">人</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第一名 -->
|
||||
<view class="rank-card rank-1 {{flashCardIndex == 0 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--1 {{flashCardIndex == 0 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 0 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="0" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
|
||||
<!-- 皇冠 -->
|
||||
<view class="crown-container" animation="{{crownAnimation}}">
|
||||
<view class="crown">
|
||||
<text class="crown-icon">👑</text>
|
||||
<view class="crown-rays">
|
||||
<view class="ray ray-1"></view>
|
||||
<view class="ray ray-2"></view>
|
||||
<view class="ray ray-3"></view>
|
||||
<view class="ray ray-4"></view>
|
||||
<view class="ray ray-5"></view>
|
||||
<view class="ray ray-6"></view>
|
||||
</view>
|
||||
<view class="crown-glow"></view>
|
||||
</view>
|
||||
<view class="rank-crown-container" animation="{{crownAnimation}}">
|
||||
<text class="rank-crown-icon">👑</text>
|
||||
<view class="rank-crown-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="podium-base podium-gold">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">1</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-gold">
|
||||
<text class="rank-podium-number">1</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-gold">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[0] ? qiansanMing[0].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-gold"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
<view class="sparkle s4"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-gold">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[0] ? qiansanMing[0].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-gold"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
<view class="rank-sparkle" style="bottom:15%;right:15%;animation-delay:1.5s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-gold">1</view>
|
||||
<view class="rank-badge rank-badge-gold">1</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[0] ? qiansanMing[0].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[0] ? qiansanMing[0].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[0] ? qiansanMing[0].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[0] ? qiansanMing[0].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">充值大手:</text>
|
||||
<view class="income-value">
|
||||
<text class="amount {{qiansanMing[0] ? qiansanMing[0].jineClass : ''}}">{{qiansanMing[0] ? qiansanMing[0].jine : '0'}}</text>
|
||||
<text class="unit">人</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">充值大手:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-amount {{qiansanMing[0] ? qiansanMing[0].jineClass : ''}}">{{qiansanMing[0] ? qiansanMing[0].jine : '0'}}</text>
|
||||
<text class="rank-unit">人</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第三名 -->
|
||||
<view class="rank-card rank-3 {{flashCardIndex == 2 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--3 {{flashCardIndex == 2 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 2 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="2" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
<view class="podium-base podium-bronze">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">3</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-bronze">
|
||||
<text class="rank-podium-number">3</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-bronze">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[2] ? qiansanMing[2].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-bronze"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-bronze">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[2] ? qiansanMing[2].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-bronze"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-bronze">3</view>
|
||||
<view class="rank-badge rank-badge-bronze">3</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[2] ? qiansanMing[2].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[2] ? qiansanMing[2].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[2] ? qiansanMing[2].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[2] ? qiansanMing[2].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">充值大手:</text>
|
||||
<view class="income-value">
|
||||
<text class="amount {{qiansanMing[2] ? qiansanMing[2].jineClass : ''}}">{{qiansanMing[2] ? qiansanMing[2].jine : '0'}}</text>
|
||||
<text class="unit">人</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">充值大手:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-amount {{qiansanMing[2] ? qiansanMing[2].jineClass : ''}}">{{qiansanMing[2] ? qiansanMing[2].jine : '0'}}</text>
|
||||
<text class="rank-unit">人</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -237,52 +207,48 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- ========== 其他排名列表 ========== -->
|
||||
<view class="other-ranks-section" wx:if="{{paihangShuju.length > 0}}">
|
||||
<view class="section-title">
|
||||
<view class="title-line"></view>
|
||||
<text class="title-text">其他排名</text>
|
||||
<view class="title-line"></view>
|
||||
<view wx:if="{{paihangShuju.length > 0}}">
|
||||
<view class="rank-section-title">
|
||||
<view class="rank-section-line"></view>
|
||||
<text class="rank-section-text">其他排名</text>
|
||||
<view class="rank-section-line"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list">
|
||||
<view class="rank-item {{flashCardIndex == index && flashCardType == 'normal' ? 'flash' : ''}}"
|
||||
wx:for="{{paihangShuju}}" wx:key="index"
|
||||
animation="{{flashCardIndex == index && flashCardType == 'normal' ? flashAnimation : ''}}"
|
||||
data-index="{{index}}" data-type="normal" bindtap="handleCardTap">
|
||||
|
||||
<view class="rank-number">
|
||||
<text class="number-text">{{xianshiZhenshiShuju ? index + 4 : index + 1}}</text>
|
||||
<view class="number-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-avatar">
|
||||
<image class="rank-avatar-img" src="{{item.full_touxiang}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-info">
|
||||
<text class="rank-name">{{item.nicheng}}</text>
|
||||
<text class="rank-uid">UID: {{item.uid}}</text>
|
||||
</view>
|
||||
|
||||
<view class="rank-income">
|
||||
<text class="income-amount {{item.jineClass}}">{{item.jine}}</text>
|
||||
<text class="income-unit">人</text>
|
||||
<view class="income-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-hover"></view>
|
||||
|
||||
<view class="rank-list-item {{flashCardIndex == index && flashCardType == 'normal' ? 'flash' : ''}}"
|
||||
wx:for="{{paihangShuju}}" wx:key="index"
|
||||
animation="{{flashCardIndex == index && flashCardType == 'normal' ? flashAnimation : ''}}"
|
||||
data-index="{{index}}" data-type="normal" bindtap="handleCardTap">
|
||||
|
||||
<view class="rank-number">
|
||||
<text class="rank-number-text">{{xianshiZhenshiShuju ? index + 4 : index + 1}}</text>
|
||||
<view class="rank-number-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-avatar">
|
||||
<image class="rank-list-avatar-img" src="{{item.full_touxiang}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-list-avatar-halo"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-info">
|
||||
<text class="rank-list-name">{{item.nicheng}}</text>
|
||||
<text class="rank-list-uid">UID: {{item.uid}}</text>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-income">
|
||||
<text class="rank-income-amount {{item.jineClass}}">{{item.jine}}</text>
|
||||
<text class="rank-income-unit">人</text>
|
||||
<view class="rank-income-glow"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{xianshiZhenshiShuju && paihangShuju.length === 0 && qiansanMing.length === 0}}" class="empty-state">
|
||||
<view class="empty-icon">🏆</view>
|
||||
<text class="empty-title">暂无排名数据</text>
|
||||
<text class="empty-desc">成为第一个登榜的管事吧</text>
|
||||
<view wx:if="{{xianshiZhenshiShuju && paihangShuju.length === 0 && qiansanMing.length === 0}}" class="rank-empty-state">
|
||||
<view class="rank-empty-icon">🏆</view>
|
||||
<text class="rank-empty-title">暂无排名数据</text>
|
||||
<text class="rank-empty-desc">成为第一个登榜的管事吧</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,418 +1,406 @@
|
||||
// pages/merchant-dispatch/merchant-dispatch.js
|
||||
import request from '../../utils/request.js'
|
||||
import PopupService from '../../services/popupService.js' // 引入弹窗服务
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 商家余额 (从全局变量获取)
|
||||
sjyue: '0.00',
|
||||
|
||||
// 商品类型列表
|
||||
shangpinList: [],
|
||||
// 当前选中的商品类型信息
|
||||
selectedTypeId: null,
|
||||
selectedHuiyuanId: null,
|
||||
selectedYaoqiuleixing: null,
|
||||
// 当前商品类型下的称号列表(用于标签选择器)
|
||||
currentTypeChenghaoList: [],
|
||||
|
||||
// 表单字段
|
||||
dingdanJieshao: '', // 订单介绍
|
||||
dingdanBeizhu: '', // 订单备注
|
||||
laobanName: '', // 老板游戏昵称/UID
|
||||
zhidingUid: '', // 指定打手UID
|
||||
jiage: '', // 订单价格
|
||||
|
||||
// 新增字段:抢单标签(称号)
|
||||
selectedLabelId: '', // 选中的标签ID
|
||||
selectedLabelName: '', // 选中的标签名称
|
||||
|
||||
// 新增字段:佣金要求(压金)
|
||||
commissionEnabled: false, // 是否开启佣金要求
|
||||
commissionValue: '', // 佣金金额(元)
|
||||
|
||||
// 页面状态
|
||||
isLoading: false, // 加载商品类型中
|
||||
isSubmitting: false, // 提交派单中
|
||||
|
||||
// 教程按钮状态
|
||||
tutorialBtnHidden: false, // false=完全显示,true=缩进隐藏(只露边)
|
||||
|
||||
// 背景图URL(动态拼接)
|
||||
bgImageUrl: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadBgImage() // 拼接背景图
|
||||
this.loadShangjiaYue() // 从全局变量获取商家余额
|
||||
this.loadShangpinTypes() // 加载商品类型
|
||||
this.startTutorialBtnTimer() // 启动按钮缩进定时器
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 每次显示页面时刷新余额(可能从其他页面充值后返回)
|
||||
this.loadShangjiaYue()
|
||||
// 重新拼接背景图(确保最新)
|
||||
this.loadBgImage()
|
||||
|
||||
// 注册通知组件(用于全局消息提示)
|
||||
this.registerNotificationComponent()
|
||||
|
||||
// 重置按钮缩进定时器(重新开始5秒倒计时)
|
||||
this.startTutorialBtnTimer()
|
||||
},
|
||||
|
||||
onHide() {
|
||||
// 页面隐藏时重置弹窗服务状态,避免影响其他页面
|
||||
PopupService.reset()
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// 清除缩进定时器,避免内存泄漏
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
// 页面卸载时重置弹窗服务
|
||||
PopupService.reset()
|
||||
},
|
||||
|
||||
// ==================== 背景图动态拼接 ====================
|
||||
loadBgImage() {
|
||||
const app = getApp()
|
||||
const ossBase = app.globalData.ossImageUrl || 'https://your-oss-bucket.oss-cn-region.aliyuncs.com'
|
||||
// 拼接完整路径:beijing/shangjiapaidan/bg.jpg
|
||||
const bgUrl = ossBase.replace(/\/$/, '') + '/beijing/shangjiapaidan/bg.jpg'
|
||||
this.setData({ bgImageUrl: bgUrl })
|
||||
},
|
||||
|
||||
// ==================== 基础数据加载 ====================
|
||||
loadShangjiaYue() {
|
||||
const app = getApp()
|
||||
const shangjiaData = app.globalData.shangjia || {}
|
||||
this.setData({
|
||||
sjyue: shangjiaData.sjyue || '0.00'
|
||||
})
|
||||
},
|
||||
|
||||
// 加载商品类型(与极速派单完全一致)
|
||||
async loadShangpinTypes() {
|
||||
this.setData({ isLoading: true })
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjspleixing',
|
||||
method: 'POST'
|
||||
})
|
||||
if (res && res.data.code === 200) {
|
||||
let list = res.data.data || []
|
||||
// 强制倒序排列(与极速派单保持一致)
|
||||
list.reverse()
|
||||
this.setData({
|
||||
shangpinList: list,
|
||||
isLoading: false
|
||||
})
|
||||
// 默认选中第一个
|
||||
if (list.length > 0) {
|
||||
this.setSelectedType(list[0])
|
||||
}
|
||||
} else {
|
||||
throw new Error(res.data.msg || '加载失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载商品类型失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({
|
||||
title: '加载类型失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 设置选中的商品类型,并提取该类型下的称号列表
|
||||
setSelectedType(item) {
|
||||
this.setData({
|
||||
selectedTypeId: item.id,
|
||||
selectedHuiyuanId: item.huiyuan_id,
|
||||
selectedYaoqiuleixing: item.yaoqiuleixing,
|
||||
currentTypeChenghaoList: item.chenghaoList || [],
|
||||
// 切换商品类型时,清空之前选择的标签和佣金
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: '',
|
||||
commissionEnabled: false,
|
||||
commissionValue: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 注册全局通知组件(用于顶部提示)
|
||||
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()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 教程按钮控制 ====================
|
||||
// 启动定时器:5秒后让按钮缩进
|
||||
startTutorialBtnTimer() {
|
||||
// 清除旧的定时器
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
// 5秒后将按钮缩进隐藏
|
||||
this.tutorialTimer = setTimeout(() => {
|
||||
this.setData({ tutorialBtnHidden: true })
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 重置按钮状态(完全显示)并重新开始5秒倒计时
|
||||
resetTutorialBtn() {
|
||||
// 如果按钮当前是缩进状态,先恢复完全显示
|
||||
if (this.data.tutorialBtnHidden) {
|
||||
this.setData({ tutorialBtnHidden: false })
|
||||
}
|
||||
// 重新开始计时(清除旧定时器,新定时器5秒后缩进)
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
this.tutorialTimer = setTimeout(() => {
|
||||
this.setData({ tutorialBtnHidden: true })
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 点击教程按钮:重置按钮状态,并调用 PopupService 弹出教程
|
||||
async onTutorialBtnTap() {
|
||||
// 首先重置按钮状态(完全显示并重新计时)
|
||||
this.resetTutorialBtn()
|
||||
// 调用弹窗服务,页面标识为 'sjpd1'
|
||||
PopupService.checkAndShow(this, 'sjpd1')
|
||||
},
|
||||
|
||||
// ==================== 表单输入事件 ====================
|
||||
onDingdanJieshaoInput(e) {
|
||||
this.setData({ dingdanJieshao: e.detail.value })
|
||||
},
|
||||
onDingdanBeizhuInput(e) {
|
||||
this.setData({ dingdanBeizhu: e.detail.value })
|
||||
},
|
||||
onLaobanNameInput(e) {
|
||||
this.setData({ laobanName: e.detail.value })
|
||||
},
|
||||
onZhidingUidInput(e) {
|
||||
this.setData({ zhidingUid: e.detail.value })
|
||||
},
|
||||
onJiageInput(e) {
|
||||
let value = e.detail.value
|
||||
// 前端验证:确保是数字且最多两位小数
|
||||
if (value === '' || /^\d+(\.\d{0,2})?$/.test(value)) {
|
||||
this.setData({ jiage: value })
|
||||
}
|
||||
},
|
||||
|
||||
// 标签选择器(picker事件)
|
||||
onLabelChange(e) {
|
||||
const idx = e.detail.value
|
||||
const label = this.data.currentTypeChenghaoList[idx]
|
||||
if (label) {
|
||||
this.setData({
|
||||
selectedLabelId: label.id,
|
||||
selectedLabelName: label.mingcheng
|
||||
})
|
||||
} else {
|
||||
this.setData({
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: ''
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 佣金开关
|
||||
onCommissionToggle() {
|
||||
this.setData({ commissionEnabled: !this.data.commissionEnabled })
|
||||
},
|
||||
onCommissionValueInput(e) {
|
||||
let value = e.detail.value
|
||||
if (value === '' || /^\d+(\.\d{0,2})?$/.test(value)) {
|
||||
this.setData({ commissionValue: value })
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 表单验证与提交 ====================
|
||||
validateForm() {
|
||||
const {
|
||||
selectedTypeId,
|
||||
dingdanJieshao,
|
||||
laobanName,
|
||||
jiage,
|
||||
sjyue,
|
||||
commissionEnabled,
|
||||
commissionValue
|
||||
} = this.data
|
||||
|
||||
// 1. 验证必填项
|
||||
if (!selectedTypeId) {
|
||||
wx.showToast({ title: '请选择订单类型', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!dingdanJieshao.trim()) {
|
||||
wx.showToast({ title: '请输入订单介绍', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!laobanName.trim()) {
|
||||
wx.showToast({ title: '请输入老板游戏昵称', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!jiage) {
|
||||
wx.showToast({ title: '请输入订单价格', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
|
||||
// 2. 验证价格格式和范围
|
||||
const price = parseFloat(jiage)
|
||||
if (isNaN(price) || price < 0.1 || price > 10000) {
|
||||
wx.showToast({ title: '价格需在0.1-10000元之间', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (jiage.includes('.') && jiage.split('.')[1].length > 2) {
|
||||
wx.showToast({ title: '最多支持两位小数', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. 验证佣金要求(若开启)
|
||||
if (commissionEnabled) {
|
||||
const commission = parseFloat(commissionValue)
|
||||
if (isNaN(commission) || commission <= 0) {
|
||||
wx.showToast({ title: '请输入有效的佣金金额', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (commission > 50000) {
|
||||
wx.showToast({ title: '佣金建议不超过50000元', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 验证余额是否足够
|
||||
const balance = parseFloat(sjyue)
|
||||
if (price > balance) {
|
||||
wx.showModal({
|
||||
title: '余额不足',
|
||||
content: `当前余额${sjyue}元,需要${jiage}元。请先充值。`,
|
||||
confirmText: '去充值',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/merchant-recharge/merchant-recharge'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
// 重置表单(保留商品类型选中状态)
|
||||
resetForm() {
|
||||
this.setData({
|
||||
dingdanJieshao: '',
|
||||
dingdanBeizhu: '',
|
||||
laobanName: '',
|
||||
zhidingUid: '',
|
||||
jiage: '',
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: '',
|
||||
commissionEnabled: false,
|
||||
commissionValue: ''
|
||||
})
|
||||
// 重置选中第一个商品类型(可选)
|
||||
if (this.data.shangpinList.length > 0) {
|
||||
this.setSelectedType(this.data.shangpinList[0])
|
||||
}
|
||||
},
|
||||
|
||||
// 提交派单
|
||||
async onSubmit() {
|
||||
if (this.data.isSubmitting) return
|
||||
if (!this.validateForm()) return
|
||||
|
||||
this.setData({ isSubmitting: true })
|
||||
|
||||
// 准备提交数据(原有字段 + 新增字段)
|
||||
const postData = {
|
||||
// 原有必传字段
|
||||
shangpinTypeId: this.data.selectedTypeId,
|
||||
huiyuanId: this.data.selectedHuiyuanId,
|
||||
yaoqiuleixing: this.data.selectedYaoqiuleixing,
|
||||
dingdanJieshao: this.data.dingdanJieshao.trim(),
|
||||
dingdanBeizhu: this.data.dingdanBeizhu.trim() || '',
|
||||
laobanName: this.data.laobanName.trim(),
|
||||
zhidingUid: this.data.zhidingUid.trim() || '',
|
||||
jiage: this.data.jiage,
|
||||
// 新增字段
|
||||
labelId: this.data.selectedLabelId || '',
|
||||
labelName: this.data.selectedLabelName || '',
|
||||
commissionEnabled: this.data.commissionEnabled,
|
||||
commissionValue: this.data.commissionEnabled ? this.data.commissionValue : ''
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjpaifa',
|
||||
method: 'POST',
|
||||
data: postData
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
// 派单成功
|
||||
wx.showToast({
|
||||
title: '派单成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// 更新全局变量中的商家信息(余额、发单量、流水)
|
||||
const orderAmount = parseFloat(this.data.jiage)
|
||||
const app = getApp()
|
||||
if (app.globalData.shangjia) {
|
||||
const newBalance = parseFloat(app.globalData.shangjia.sjyue || '0') - orderAmount
|
||||
app.globalData.shangjia.sjyue = newBalance.toFixed(2)
|
||||
app.globalData.shangjia.fadanzong = (parseInt(app.globalData.shangjia.fadanzong || '0') + 1).toString()
|
||||
app.globalData.shangjia.riliushui = (parseFloat(app.globalData.shangjia.riliushui || '0') + orderAmount).toFixed(2)
|
||||
app.globalData.shangjia.yueliushui = (parseFloat(app.globalData.shangjia.yueliushui || '0') + orderAmount).toFixed(2)
|
||||
this.setData({ sjyue: app.globalData.shangjia.sjyue })
|
||||
}
|
||||
|
||||
// 延迟重置表单,避免用户连续提交
|
||||
setTimeout(() => {
|
||||
this.resetForm()
|
||||
this.setData({ isSubmitting: false })
|
||||
}, 1500)
|
||||
} else {
|
||||
wx.showModal({
|
||||
title: '派单失败',
|
||||
content: res.data.msg || '请稍后重试',
|
||||
showCancel: false
|
||||
})
|
||||
this.setData({ isSubmitting: false })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('派单请求失败:', error)
|
||||
wx.showModal({
|
||||
title: '请求失败',
|
||||
content: error.message || '网络错误,请检查连接',
|
||||
showCancel: false
|
||||
})
|
||||
this.setData({ isSubmitting: false })
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 商品类型选择 ====================
|
||||
onSelectType(e) {
|
||||
const { id, item } = e.currentTarget.dataset
|
||||
this.setSelectedType(item)
|
||||
}
|
||||
})
|
||||
// pages/merchant-dispatch/merchant-dispatch.js
|
||||
import { createPage, request } from '../../utils/base-page.js'
|
||||
import PopupService from '../../services/popupService.js' // 引入弹窗服务
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
// 商家余额 (从全局变量获取)
|
||||
sjyue: '0.00',
|
||||
|
||||
// 商品类型列表
|
||||
shangpinList: [],
|
||||
// 当前选中的商品类型信息
|
||||
selectedTypeId: null,
|
||||
selectedHuiyuanId: null,
|
||||
selectedYaoqiuleixing: null,
|
||||
// 当前商品类型下的称号列表(用于标签选择器)
|
||||
currentTypeChenghaoList: [],
|
||||
|
||||
// 表单字段
|
||||
dingdanJieshao: '', // 订单介绍
|
||||
dingdanBeizhu: '', // 订单备注
|
||||
laobanName: '', // 老板游戏昵称/UID
|
||||
zhidingUid: '', // 指定打手UID
|
||||
jiage: '', // 订单价格
|
||||
|
||||
// 新增字段:抢单标签(称号)
|
||||
selectedLabelId: '', // 选中的标签ID
|
||||
selectedLabelName: '', // 选中的标签名称
|
||||
|
||||
// 新增字段:佣金要求(压金)
|
||||
commissionEnabled: false, // 是否开启佣金要求
|
||||
commissionValue: '', // 佣金金额(元)
|
||||
|
||||
// 页面状态
|
||||
isLoading: false, // 加载商品类型中
|
||||
isSubmitting: false, // 提交派单中
|
||||
|
||||
// 教程按钮状态
|
||||
tutorialBtnHidden: false, // false=完全显示,true=缩进隐藏(只露边)
|
||||
|
||||
// 背景图URL(动态拼接)
|
||||
bgImageUrl: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadBgImage() // 拼接背景图
|
||||
this.loadShangjiaYue() // 从全局变量获取商家余额
|
||||
this.loadShangpinTypes() // 加载商品类型
|
||||
this.startTutorialBtnTimer() // 启动按钮缩进定时器
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 每次显示页面时刷新余额(可能从其他页面充值后返回)
|
||||
this.loadShangjiaYue()
|
||||
// 重新拼接背景图(确保最新)
|
||||
this.loadBgImage()
|
||||
|
||||
// 注册通知组件(用于全局消息提示)
|
||||
this.registerNotificationComponent()
|
||||
|
||||
// 重置按钮缩进定时器(重新开始5秒倒计时)
|
||||
this.startTutorialBtnTimer()
|
||||
},
|
||||
|
||||
onHide() {
|
||||
// 页面隐藏时重置弹窗服务状态,避免影响其他页面
|
||||
PopupService.reset()
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// 清除缩进定时器,避免内存泄漏
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
// 页面卸载时重置弹窗服务
|
||||
PopupService.reset()
|
||||
},
|
||||
|
||||
// ==================== 背景图动态拼接 ====================
|
||||
loadBgImage() {
|
||||
const app = getApp()
|
||||
const ossBase = app.globalData.ossImageUrl || 'https://your-oss-bucket.oss-cn-region.aliyuncs.com'
|
||||
// 拼接完整路径:beijing/shangjiapaidan/bg.jpg
|
||||
const bgUrl = ossBase.replace(/\/$/, '') + '/beijing/shangjiapaidan/bg.jpg'
|
||||
this.setData({ bgImageUrl: bgUrl })
|
||||
},
|
||||
|
||||
// ==================== 基础数据加载 ====================
|
||||
loadShangjiaYue() {
|
||||
const app = getApp()
|
||||
const shangjiaData = app.globalData.shangjia || {}
|
||||
this.setData({
|
||||
sjyue: shangjiaData.sjyue || '0.00'
|
||||
})
|
||||
},
|
||||
|
||||
// 加载商品类型(与极速派单完全一致)
|
||||
async loadShangpinTypes() {
|
||||
this.setData({ isLoading: true })
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjspleixing',
|
||||
method: 'POST'
|
||||
})
|
||||
if (res && res.data.code === 200) {
|
||||
let list = res.data.data || []
|
||||
// 强制倒序排列(与极速派单保持一致)
|
||||
list.reverse()
|
||||
this.setData({
|
||||
shangpinList: list,
|
||||
isLoading: false
|
||||
})
|
||||
// 默认选中第一个
|
||||
if (list.length > 0) {
|
||||
this.setSelectedType(list[0])
|
||||
}
|
||||
} else {
|
||||
throw new Error(res.data.msg || '加载失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载商品类型失败:', error)
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({
|
||||
title: '加载类型失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 设置选中的商品类型,并提取该类型下的称号列表
|
||||
setSelectedType(item) {
|
||||
this.setData({
|
||||
selectedTypeId: item.id,
|
||||
selectedHuiyuanId: item.huiyuan_id,
|
||||
selectedYaoqiuleixing: item.yaoqiuleixing,
|
||||
currentTypeChenghaoList: item.chenghaoList || [],
|
||||
// 切换商品类型时,清空之前选择的标签和佣金
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: '',
|
||||
commissionEnabled: false,
|
||||
commissionValue: ''
|
||||
})
|
||||
},
|
||||
|
||||
// ==================== 教程按钮控制 ====================
|
||||
// 启动定时器:5秒后让按钮缩进
|
||||
startTutorialBtnTimer() {
|
||||
// 清除旧的定时器
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
// 5秒后将按钮缩进隐藏
|
||||
this.tutorialTimer = setTimeout(() => {
|
||||
this.setData({ tutorialBtnHidden: true })
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 重置按钮状态(完全显示)并重新开始5秒倒计时
|
||||
resetTutorialBtn() {
|
||||
// 如果按钮当前是缩进状态,先恢复完全显示
|
||||
if (this.data.tutorialBtnHidden) {
|
||||
this.setData({ tutorialBtnHidden: false })
|
||||
}
|
||||
// 重新开始计时(清除旧定时器,新定时器5秒后缩进)
|
||||
if (this.tutorialTimer) {
|
||||
clearTimeout(this.tutorialTimer)
|
||||
}
|
||||
this.tutorialTimer = setTimeout(() => {
|
||||
this.setData({ tutorialBtnHidden: true })
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 点击教程按钮:重置按钮状态,并调用 PopupService 弹出教程
|
||||
async onTutorialBtnTap() {
|
||||
// 首先重置按钮状态(完全显示并重新计时)
|
||||
this.resetTutorialBtn()
|
||||
// 调用弹窗服务,页面标识为 'sjpd1'
|
||||
PopupService.checkAndShow(this, 'sjpd1')
|
||||
},
|
||||
|
||||
// ==================== 表单输入事件 ====================
|
||||
onDingdanJieshaoInput(e) {
|
||||
this.setData({ dingdanJieshao: e.detail.value })
|
||||
},
|
||||
onDingdanBeizhuInput(e) {
|
||||
this.setData({ dingdanBeizhu: e.detail.value })
|
||||
},
|
||||
onLaobanNameInput(e) {
|
||||
this.setData({ laobanName: e.detail.value })
|
||||
},
|
||||
onZhidingUidInput(e) {
|
||||
this.setData({ zhidingUid: e.detail.value })
|
||||
},
|
||||
onJiageInput(e) {
|
||||
let value = e.detail.value
|
||||
// 前端验证:确保是数字且最多两位小数
|
||||
if (value === '' || /^\d+(\.\d{0,2})?$/.test(value)) {
|
||||
this.setData({ jiage: value })
|
||||
}
|
||||
},
|
||||
|
||||
// 标签选择器(picker事件)
|
||||
onLabelChange(e) {
|
||||
const idx = e.detail.value
|
||||
const label = this.data.currentTypeChenghaoList[idx]
|
||||
if (label) {
|
||||
this.setData({
|
||||
selectedLabelId: label.id,
|
||||
selectedLabelName: label.mingcheng
|
||||
})
|
||||
} else {
|
||||
this.setData({
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: ''
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 佣金开关
|
||||
onCommissionToggle() {
|
||||
this.setData({ commissionEnabled: !this.data.commissionEnabled })
|
||||
},
|
||||
onCommissionValueInput(e) {
|
||||
let value = e.detail.value
|
||||
if (value === '' || /^\d+(\.\d{0,2})?$/.test(value)) {
|
||||
this.setData({ commissionValue: value })
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 表单验证与提交 ====================
|
||||
validateForm() {
|
||||
const {
|
||||
selectedTypeId,
|
||||
dingdanJieshao,
|
||||
laobanName,
|
||||
jiage,
|
||||
sjyue,
|
||||
commissionEnabled,
|
||||
commissionValue
|
||||
} = this.data
|
||||
|
||||
// 1. 验证必填项
|
||||
if (!selectedTypeId) {
|
||||
wx.showToast({ title: '请选择订单类型', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!dingdanJieshao.trim()) {
|
||||
wx.showToast({ title: '请输入订单介绍', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!laobanName.trim()) {
|
||||
wx.showToast({ title: '请输入老板游戏昵称', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!jiage) {
|
||||
wx.showToast({ title: '请输入订单价格', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
|
||||
// 2. 验证价格格式和范围
|
||||
const price = parseFloat(jiage)
|
||||
if (isNaN(price) || price < 0.1 || price > 10000) {
|
||||
wx.showToast({ title: '价格需在0.1-10000元之间', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (jiage.includes('.') && jiage.split('.')[1].length > 2) {
|
||||
wx.showToast({ title: '最多支持两位小数', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. 验证佣金要求(若开启)
|
||||
if (commissionEnabled) {
|
||||
const commission = parseFloat(commissionValue)
|
||||
if (isNaN(commission) || commission <= 0) {
|
||||
wx.showToast({ title: '请输入有效的佣金金额', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (commission > 50000) {
|
||||
wx.showToast({ title: '佣金建议不超过50000元', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 验证余额是否足够
|
||||
const balance = parseFloat(sjyue)
|
||||
if (price > balance) {
|
||||
wx.showModal({
|
||||
title: '余额不足',
|
||||
content: `当前余额${sjyue}元,需要${jiage}元。请先充值。`,
|
||||
confirmText: '去充值',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/merchant-recharge/merchant-recharge'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
// 重置表单(保留商品类型选中状态)
|
||||
resetForm() {
|
||||
this.setData({
|
||||
dingdanJieshao: '',
|
||||
dingdanBeizhu: '',
|
||||
laobanName: '',
|
||||
zhidingUid: '',
|
||||
jiage: '',
|
||||
selectedLabelId: '',
|
||||
selectedLabelName: '',
|
||||
commissionEnabled: false,
|
||||
commissionValue: ''
|
||||
})
|
||||
// 重置选中第一个商品类型(可选)
|
||||
if (this.data.shangpinList.length > 0) {
|
||||
this.setSelectedType(this.data.shangpinList[0])
|
||||
}
|
||||
},
|
||||
|
||||
// 提交派单
|
||||
async onSubmit() {
|
||||
if (this.data.isSubmitting) return
|
||||
if (!this.validateForm()) return
|
||||
|
||||
this.setData({ isSubmitting: true })
|
||||
|
||||
// 准备提交数据(原有字段 + 新增字段)
|
||||
const postData = {
|
||||
// 原有必传字段
|
||||
shangpinTypeId: this.data.selectedTypeId,
|
||||
huiyuanId: this.data.selectedHuiyuanId,
|
||||
yaoqiuleixing: this.data.selectedYaoqiuleixing,
|
||||
dingdanJieshao: this.data.dingdanJieshao.trim(),
|
||||
dingdanBeizhu: this.data.dingdanBeizhu.trim() || '',
|
||||
laobanName: this.data.laobanName.trim(),
|
||||
zhidingUid: this.data.zhidingUid.trim() || '',
|
||||
jiage: this.data.jiage,
|
||||
// 新增字段
|
||||
labelId: this.data.selectedLabelId || '',
|
||||
labelName: this.data.selectedLabelName || '',
|
||||
commissionEnabled: this.data.commissionEnabled,
|
||||
commissionValue: this.data.commissionEnabled ? this.data.commissionValue : ''
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjpaifa',
|
||||
method: 'POST',
|
||||
data: postData
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
// 派单成功
|
||||
wx.showToast({
|
||||
title: '派单成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// 更新全局变量中的商家信息(余额、发单量、流水)
|
||||
const orderAmount = parseFloat(this.data.jiage)
|
||||
const app = getApp()
|
||||
if (app.globalData.shangjia) {
|
||||
const newBalance = parseFloat(app.globalData.shangjia.sjyue || '0') - orderAmount
|
||||
app.globalData.shangjia.sjyue = newBalance.toFixed(2)
|
||||
app.globalData.shangjia.fadanzong = (parseInt(app.globalData.shangjia.fadanzong || '0') + 1).toString()
|
||||
app.globalData.shangjia.riliushui = (parseFloat(app.globalData.shangjia.riliushui || '0') + orderAmount).toFixed(2)
|
||||
app.globalData.shangjia.yueliushui = (parseFloat(app.globalData.shangjia.yueliushui || '0') + orderAmount).toFixed(2)
|
||||
this.setData({ sjyue: app.globalData.shangjia.sjyue })
|
||||
}
|
||||
|
||||
// 延迟重置表单,避免用户连续提交
|
||||
setTimeout(() => {
|
||||
this.resetForm()
|
||||
this.setData({ isSubmitting: false })
|
||||
}, 1500)
|
||||
} else {
|
||||
wx.showModal({
|
||||
title: '派单失败',
|
||||
content: res.data.msg || '请稍后重试',
|
||||
showCancel: false
|
||||
})
|
||||
this.setData({ isSubmitting: false })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('派单请求失败:', error)
|
||||
wx.showModal({
|
||||
title: '请求失败',
|
||||
content: error.message || '网络错误,请检查连接',
|
||||
showCancel: false
|
||||
})
|
||||
this.setData({ isSubmitting: false })
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 商品类型选择 ====================
|
||||
onSelectType(e) {
|
||||
const { id, item } = e.currentTarget.dataset
|
||||
this.setSelectedType(item)
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -1,327 +1,307 @@
|
||||
// pages/merchant-orders/merchant-orders.js
|
||||
const app = getApp();
|
||||
import request from '../../utils/request.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 商品类型(和打手端用同一个接口)
|
||||
shangpinleixing: [],
|
||||
xuanzhongLeixingId: null,
|
||||
|
||||
// 搜索关键字(模糊搜索)
|
||||
searchKeyword: '',
|
||||
|
||||
// 状态列表(含全部)
|
||||
statusList: [
|
||||
{ name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8], 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',
|
||||
|
||||
// 每个状态独立的数据集
|
||||
sjDingdanShuju: {
|
||||
all: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
|
||||
},
|
||||
|
||||
currentList: [],
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
defaultImg: '/images/default-order.png',
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 待结算数量
|
||||
pendingCount: 0,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '我的派单' });
|
||||
this.loadShangpinLeixing();
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
this.loadPendingCount();
|
||||
if (wx.getStorageSync('uid')) {
|
||||
reconnectForRole('shangjia');
|
||||
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()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 🆕 加载商品类型(和打手端用同一个接口 /dingdan/dsqdhqddlx)
|
||||
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;
|
||||
// 拼接图片完整URL
|
||||
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);
|
||||
},
|
||||
|
||||
// 搜索输入(防抖)
|
||||
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);
|
||||
},
|
||||
|
||||
// 切换状态Tab
|
||||
switchStatus(e) {
|
||||
const key = e.currentTarget.dataset.key;
|
||||
if (key === this.data.currentStatusKey) return;
|
||||
this.setData({ currentStatusKey: key });
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
// 如果该状态没有数据,则加载;否则只刷新视图
|
||||
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
} else {
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 🆕 加载订单(核心方法,接口固定用商家订单接口 /dingdan/sjdingdanhq)
|
||||
async loadCurrentStatusOrders(isRefresh = false) {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
if (tabData.isLoading) return;
|
||||
const page = isRefresh ? 1 : tabData.page;
|
||||
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.isLoading`]: true,
|
||||
isLoading: true,
|
||||
isLoadingMore: !isRefresh
|
||||
});
|
||||
|
||||
try {
|
||||
const statusItem = this.data.statusList.find(s => s.key === key);
|
||||
const zhuangtaiList = statusItem.zhuangtaiList;
|
||||
|
||||
// 构建请求参数
|
||||
const params = {
|
||||
zhuangtai_list: zhuangtaiList,
|
||||
page: page,
|
||||
page_size: 5,
|
||||
leixing_id: this.data.xuanzhongLeixingId, // 🆕 商品类型筛选
|
||||
keyword: this.data.searchKeyword || undefined // 🆕 模糊搜索
|
||||
};
|
||||
|
||||
const res = await request({
|
||||
url: '/dingdan/sjdingdanhq', // 商家订单接口(和原来一样)
|
||||
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;
|
||||
|
||||
// 处理数据:拼接图片、转换状态中文
|
||||
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.sjDingdanShuju[key].list;
|
||||
const updatedList = isRefresh ? processed : [...currentList, ...processed];
|
||||
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.list`]: updatedList,
|
||||
[`sjDingdanShuju.${key}.page`]: page,
|
||||
[`sjDingdanShuju.${key}.hasMore`]: hasMore,
|
||||
[`sjDingdanShuju.${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({
|
||||
[`sjDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新当前视图
|
||||
refreshCurrentListView() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
this.setData({
|
||||
currentList: tabData.list,
|
||||
hasMore: tabData.hasMore,
|
||||
isLoading: tabData.isLoading
|
||||
});
|
||||
},
|
||||
|
||||
// 重置当前状态数据
|
||||
resetCurrentStatusData() {
|
||||
const key = this.data.currentStatusKey;
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.list`]: [],
|
||||
[`sjDingdanShuju.${key}.page`]: 1,
|
||||
[`sjDingdanShuju.${key}.hasMore`]: true,
|
||||
[`sjDingdanShuju.${key}.isLoading`]: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
},
|
||||
|
||||
// 🆕 加载待结算数量
|
||||
async loadPendingCount() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjdingdanhq',
|
||||
method: 'POST',
|
||||
data: {
|
||||
zhuangtai_list: [8],
|
||||
page: 1,
|
||||
page_size: 1
|
||||
}
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
this.setData({ pendingCount: res.data.data.pending_count || 0 });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载待结算数量失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新(由 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.sjDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// 🆕 手动点击"加载更多"按钮
|
||||
onLoadMoreTap() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// 状态码转中文
|
||||
getZhuangtaiZh(zhuangtai) {
|
||||
const map = {
|
||||
1: '已下单', 2: '进行中', 3: '已完成',
|
||||
4: '退款中', 5: '已退款', 6: '退款失败',
|
||||
7: '指定中', 8: '结算中'
|
||||
};
|
||||
return map[zhuangtai] || '未知状态';
|
||||
},
|
||||
|
||||
// 跳转订单详情
|
||||
goToSjDingdanXiangqing(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
const dataStr = encodeURIComponent(JSON.stringify(item));
|
||||
wx.navigateTo({
|
||||
url: `/pages/merchant-order-detail/merchant-order-detail?dingdanData=${dataStr}`
|
||||
});
|
||||
},
|
||||
|
||||
// 图片加载失败
|
||||
onImageError() {}
|
||||
});
|
||||
// pages/merchant-orders/merchant-orders.js
|
||||
const app = getApp();
|
||||
import { createPage, request } from '../../utils/base-page.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
import { getOrderStatusText } from '../../utils/api-helper.js';
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
// 商品类型(和打手端用同一个接口)
|
||||
shangpinleixing: [],
|
||||
xuanzhongLeixingId: null,
|
||||
|
||||
// 搜索关键字(模糊搜索)
|
||||
searchKeyword: '',
|
||||
|
||||
// 状态列表(含全部)
|
||||
statusList: [
|
||||
{ name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8], 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',
|
||||
|
||||
// 每个状态独立的数据集
|
||||
sjDingdanShuju: {
|
||||
all: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jinxingzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanzhong: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yituikuan: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
tuikuanshibai: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
yiwancheng: { list: [], page: 1, hasMore: true, isLoading: false },
|
||||
jiesuanzhong: { list: [], page: 1, hasMore: true, isLoading: false }
|
||||
},
|
||||
|
||||
currentList: [],
|
||||
hasMore: true,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false,
|
||||
defaultImg: '/images/default-order.png',
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
|
||||
// 待结算数量
|
||||
pendingCount: 0,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.setNavigationBarTitle({ title: '我的派单' });
|
||||
this.loadShangpinLeixing();
|
||||
this.registerNotificationComponent();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
this.loadPendingCount();
|
||||
if (wx.getStorageSync('uid')) {
|
||||
reconnectForRole('shangjia');
|
||||
if (app.startImWhenReady) app.startImWhenReady();
|
||||
}
|
||||
if (this.data.currentStatusKey && this.data.xuanzhongLeixingId) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
}
|
||||
},
|
||||
|
||||
// 🆕 加载商品类型(和打手端用同一个接口 /dingdan/dsqdhqddlx)
|
||||
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;
|
||||
// 拼接图片完整URL
|
||||
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);
|
||||
},
|
||||
|
||||
// 搜索输入(防抖)
|
||||
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);
|
||||
},
|
||||
|
||||
// 切换状态Tab
|
||||
switchStatus(e) {
|
||||
const key = e.currentTarget.dataset.key;
|
||||
if (key === this.data.currentStatusKey) return;
|
||||
this.setData({ currentStatusKey: key });
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
// 如果该状态没有数据,则加载;否则只刷新视图
|
||||
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
|
||||
this.loadCurrentStatusOrders(true);
|
||||
} else {
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 🆕 加载订单(核心方法,接口固定用商家订单接口 /dingdan/sjdingdanhq)
|
||||
async loadCurrentStatusOrders(isRefresh = false) {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
if (tabData.isLoading) return;
|
||||
const page = isRefresh ? 1 : tabData.page;
|
||||
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.isLoading`]: true,
|
||||
isLoading: true,
|
||||
isLoadingMore: !isRefresh
|
||||
});
|
||||
|
||||
try {
|
||||
const statusItem = this.data.statusList.find(s => s.key === key);
|
||||
const zhuangtaiList = statusItem.zhuangtaiList;
|
||||
|
||||
// 构建请求参数
|
||||
const params = {
|
||||
zhuangtai_list: zhuangtaiList,
|
||||
page: page,
|
||||
page_size: 5,
|
||||
leixing_id: this.data.xuanzhongLeixingId, // 🆕 商品类型筛选
|
||||
keyword: this.data.searchKeyword || undefined // 🆕 模糊搜索
|
||||
};
|
||||
|
||||
const res = await request({
|
||||
url: '/dingdan/sjdingdanhq', // 商家订单接口(和原来一样)
|
||||
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;
|
||||
|
||||
// 处理数据:拼接图片、转换状态中文
|
||||
const processed = newList.map(item => ({
|
||||
...item,
|
||||
zhuangtaiZh: getOrderStatusText(item.zhuangtai),
|
||||
zhuangtaiColor: statusItem.color,
|
||||
// 如果有商品图片则用商品图片,否则用默认图
|
||||
tupian: item.tupian
|
||||
? (item.tupian.startsWith('http') ? item.tupian : this.data.ossImageUrl + item.tupian)
|
||||
: this.data.defaultImg
|
||||
}));
|
||||
|
||||
const currentList = this.data.sjDingdanShuju[key].list;
|
||||
const updatedList = isRefresh ? processed : [...currentList, ...processed];
|
||||
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.list`]: updatedList,
|
||||
[`sjDingdanShuju.${key}.page`]: page,
|
||||
[`sjDingdanShuju.${key}.hasMore`]: hasMore,
|
||||
[`sjDingdanShuju.${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({
|
||||
[`sjDingdanShuju.${key}.isLoading`]: false,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
scrollViewRefreshing: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新当前视图
|
||||
refreshCurrentListView() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
this.setData({
|
||||
currentList: tabData.list,
|
||||
hasMore: tabData.hasMore,
|
||||
isLoading: tabData.isLoading
|
||||
});
|
||||
},
|
||||
|
||||
// 重置当前状态数据
|
||||
resetCurrentStatusData() {
|
||||
const key = this.data.currentStatusKey;
|
||||
this.setData({
|
||||
[`sjDingdanShuju.${key}.list`]: [],
|
||||
[`sjDingdanShuju.${key}.page`]: 1,
|
||||
[`sjDingdanShuju.${key}.hasMore`]: true,
|
||||
[`sjDingdanShuju.${key}.isLoading`]: false
|
||||
});
|
||||
this.refreshCurrentListView();
|
||||
},
|
||||
|
||||
// 🆕 加载待结算数量
|
||||
async loadPendingCount() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/dingdan/sjdingdanhq',
|
||||
method: 'POST',
|
||||
data: {
|
||||
zhuangtai_list: [8],
|
||||
page: 1,
|
||||
page_size: 1
|
||||
}
|
||||
});
|
||||
if (res && res.data.code === 0) {
|
||||
this.setData({ pendingCount: res.data.data.pending_count || 0 });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载待结算数量失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新(由 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.sjDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// 🆕 手动点击"加载更多"按钮
|
||||
onLoadMoreTap() {
|
||||
const key = this.data.currentStatusKey;
|
||||
const tabData = this.data.sjDingdanShuju[key];
|
||||
if (tabData.isLoading || !tabData.hasMore) return;
|
||||
this.setData({ [`sjDingdanShuju.${key}.page`]: tabData.page + 1 });
|
||||
this.loadCurrentStatusOrders(false);
|
||||
},
|
||||
|
||||
// 跳转订单详情
|
||||
goToSjDingdanXiangqing(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
if (!item) return;
|
||||
const dataStr = encodeURIComponent(JSON.stringify(item));
|
||||
wx.navigateTo({
|
||||
url: `/pages/merchant-order-detail/merchant-order-detail?dingdanData=${dataStr}`
|
||||
});
|
||||
},
|
||||
|
||||
// 图片加载失败
|
||||
onImageError() {}
|
||||
}))
|
||||
|
||||
@@ -1,235 +1,205 @@
|
||||
<!-- pages/shangjia-paihang/shangjia-paihang.wxml -->
|
||||
<view class="shangjia-paihang-page">
|
||||
|
||||
<!-- pages/merchant-rank/merchant-rank.wxml -->
|
||||
<view class="rank-page">
|
||||
|
||||
<!-- 赛博朋克背景元素 -->
|
||||
<view class="cyber-bg">
|
||||
<view class="rank-cyber-bg">
|
||||
<!-- 网格线 -->
|
||||
<view class="cyber-grid"></view>
|
||||
<view class="rank-cyber-grid"></view>
|
||||
<!-- 扫描线 -->
|
||||
<view class="cyber-scanline"></view>
|
||||
<view class="rank-cyber-scanline"></view>
|
||||
<!-- 流动数据流 -->
|
||||
<view class="data-streams">
|
||||
<view class="stream stream-1"></view>
|
||||
<view class="stream stream-2"></view>
|
||||
<view class="stream stream-3"></view>
|
||||
<view class="rank-data-streams">
|
||||
<view class="rank-stream rank-stream--1"></view>
|
||||
<view class="rank-stream rank-stream--2"></view>
|
||||
<view class="rank-stream rank-stream--3"></view>
|
||||
</view>
|
||||
<!-- 浮动粒子 -->
|
||||
<view class="floating-particles">
|
||||
<view class="particle" wx:for="{{12}}" wx:key="index"></view>
|
||||
</view>
|
||||
<view class="rank-particle" wx:for="{{12}}" wx:key="index"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 页面头部 -->
|
||||
<view class="page-header">
|
||||
<view class="rank-page-header">
|
||||
<!-- 标题 -->
|
||||
<view class="title-container">
|
||||
<text class="main-title">商家排行榜</text>
|
||||
<view class="title-line"></view>
|
||||
<text class="sub-title">SHANGJIA RANKING</text>
|
||||
<view class="rank-title-container">
|
||||
<text class="rank-main-title">商家排行榜</text>
|
||||
<view class="rank-title-line"></view>
|
||||
<text class="rank-sub-title">SHANGJIA RANKING</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 切换按钮 -->
|
||||
<view class="toggle-container">
|
||||
<view class="toggle-bg" style="transform: translateX({{paihangLeixing == 1 ? '0' : '100%'}});"></view>
|
||||
<view
|
||||
class="toggle-btn {{paihangLeixing == 1 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
<view class="rank-toggle-container">
|
||||
<view class="rank-toggle-bg" style="transform: translateX({{paihangLeixing == 1 ? '0' : '100%'}});"></view>
|
||||
<view
|
||||
class="rank-toggle-btn {{paihangLeixing == 1 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
data-leixing="1"
|
||||
bindtap="qiehuangPaihangLeixing"
|
||||
>
|
||||
<text class="toggle-text">今日流水</text>
|
||||
<view class="toggle-line {{paihangLeixing == 1 ? 'active' : ''}}"></view>
|
||||
<text class="rank-toggle-text">今日流水</text>
|
||||
<view class="rank-toggle-line {{paihangLeixing == 1 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
<view
|
||||
class="toggle-btn {{paihangLeixing == 2 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
<view
|
||||
class="rank-toggle-btn {{paihangLeixing == 2 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
|
||||
data-leixing="2"
|
||||
bindtap="qiehuangPaihangLeixing"
|
||||
>
|
||||
<text class="toggle-text">今月流水</text>
|
||||
<view class="toggle-line {{paihangLeixing == 2 ? 'active' : ''}}"></view>
|
||||
<text class="rank-toggle-text">今月流水</text>
|
||||
<view class="rank-toggle-line {{paihangLeixing == 2 ? 'active' : ''}}"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view wx:if="{{jiazaiZhuangtai}}" class="loading-state">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner">
|
||||
<view class="spinner-outer"></view>
|
||||
<view class="spinner-inner"></view>
|
||||
<view class="spinner-core"></view>
|
||||
</view>
|
||||
<text class="loading-text">数据加载中</text>
|
||||
<text class="loading-sub">Connecting to server...</text>
|
||||
<view wx:if="{{jiazaiZhuangtai}}" class="rank-loading-state">
|
||||
<view class="rank-loading-spinner">
|
||||
<view class="rank-spinner-outer"></view>
|
||||
<view class="rank-spinner-inner"></view>
|
||||
<view class="rank-spinner-core"></view>
|
||||
</view>
|
||||
<text class="rank-loading-text">数据加载中</text>
|
||||
<text class="rank-loading-sub">Connecting to server...</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 排行榜内容 -->
|
||||
<view wx:else class="ranking-content">
|
||||
|
||||
<view wx:else class="rank-content">
|
||||
|
||||
<!-- 虚拟数据提示 -->
|
||||
<view wx:if="{{!xianshiZhenshiShuju}}" class="demo-notice">
|
||||
<view class="notice-icon">📡</view>
|
||||
<view class="notice-content">
|
||||
<text class="notice-title">排行榜数据准备中</text>
|
||||
<text class="notice-desc">当前显示为模拟数据,实时排名即将开放</text>
|
||||
<view wx:if="{{!xianshiZhenshiShuju}}" class="rank-demo-notice">
|
||||
<view class="rank-notice-icon">📡</view>
|
||||
<view class="rank-notice-content">
|
||||
<text class="rank-notice-title">排行榜数据准备中</text>
|
||||
<text class="rank-notice-desc">当前显示为模拟数据,实时排名即将开放</text>
|
||||
</view>
|
||||
<view class="notice-glow"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- ========== 前三名区域 ========== -->
|
||||
<view class="top-three-section" wx:if="{{qiansanMing.length > 0}}">
|
||||
|
||||
<view class="rank-top-three" wx:if="{{qiansanMing.length > 0}}">
|
||||
|
||||
<!-- 第二名 -->
|
||||
<view class="rank-card rank-2 {{flashCardIndex == 1 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--2 {{flashCardIndex == 1 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 1 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="1" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
<view class="podium-base podium-silver">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">2</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-silver">
|
||||
<text class="rank-podium-number">2</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-silver">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[1] ? qiansanMing[1].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-silver"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-silver">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[1] ? qiansanMing[1].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-silver"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-silver">2</view>
|
||||
<view class="rank-badge rank-badge-silver">2</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[1] ? qiansanMing[1].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[1] ? qiansanMing[1].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[1] ? qiansanMing[1].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[1] ? qiansanMing[1].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">流水:</text>
|
||||
<view class="income-value">
|
||||
<text class="currency">¥</text>
|
||||
<text class="amount {{qiansanMing[1] ? qiansanMing[1].jineClass : ''}}">{{qiansanMing[1] ? qiansanMing[1].jine : '0.00'}}</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">流水:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-currency">¥</text>
|
||||
<text class="rank-amount {{qiansanMing[1] ? qiansanMing[1].jineClass : ''}}">{{qiansanMing[1] ? qiansanMing[1].jine : '0.00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第一名 -->
|
||||
<view class="rank-card rank-1 {{flashCardIndex == 0 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--1 {{flashCardIndex == 0 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 0 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="0" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
|
||||
<!-- 皇冠 -->
|
||||
<view class="crown-container" animation="{{crownAnimation}}">
|
||||
<view class="crown">
|
||||
<text class="crown-icon">👑</text>
|
||||
<view class="crown-rays">
|
||||
<view class="ray ray-1"></view>
|
||||
<view class="ray ray-2"></view>
|
||||
<view class="ray ray-3"></view>
|
||||
<view class="ray ray-4"></view>
|
||||
<view class="ray ray-5"></view>
|
||||
<view class="ray ray-6"></view>
|
||||
</view>
|
||||
<view class="crown-glow"></view>
|
||||
</view>
|
||||
<view class="rank-crown-container" animation="{{crownAnimation}}">
|
||||
<text class="rank-crown-icon">👑</text>
|
||||
<view class="rank-crown-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="podium-base podium-gold">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">1</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-gold">
|
||||
<text class="rank-podium-number">1</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-gold">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[0] ? qiansanMing[0].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-gold"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
<view class="sparkle s4"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-gold">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[0] ? qiansanMing[0].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-gold"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
<view class="rank-sparkle" style="bottom:15%;right:15%;animation-delay:1.5s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-gold">1</view>
|
||||
<view class="rank-badge rank-badge-gold">1</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[0] ? qiansanMing[0].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[0] ? qiansanMing[0].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[0] ? qiansanMing[0].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[0] ? qiansanMing[0].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">流水:</text>
|
||||
<view class="income-value">
|
||||
<text class="currency">¥</text>
|
||||
<text class="amount {{qiansanMing[0] ? qiansanMing[0].jineClass : ''}}">{{qiansanMing[0] ? qiansanMing[0].jine : '0.00'}}</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">流水:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-currency">¥</text>
|
||||
<text class="rank-amount {{qiansanMing[0] ? qiansanMing[0].jineClass : ''}}">{{qiansanMing[0] ? qiansanMing[0].jine : '0.00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第三名 -->
|
||||
<view class="rank-card rank-3 {{flashCardIndex == 2 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
<view class="rank-card rank-card--3 {{flashCardIndex == 2 && flashCardType == 'top3' ? 'flash' : ''}}"
|
||||
animation="{{flashCardIndex == 2 && flashCardType == 'top3' ? flashAnimation : ''}}"
|
||||
data-index="2" data-type="top3" bindtap="handleCardTap">
|
||||
|
||||
<view class="podium-base podium-bronze">
|
||||
<view class="podium-glow"></view>
|
||||
<text class="podium-number">3</text>
|
||||
|
||||
<view class="rank-podium-base rank-podium-bronze">
|
||||
<text class="rank-podium-number">3</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="rank-content">
|
||||
<!-- 头像容器 -->
|
||||
<view class="avatar-frame frame-bronze">
|
||||
<view class="avatar-container">
|
||||
<image class="avatar-image" src="{{qiansanMing[2] ? qiansanMing[2].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="avatar-halo halo-bronze"></view>
|
||||
<view class="avatar-sparkles">
|
||||
<view class="sparkle s1"></view>
|
||||
<view class="sparkle s2"></view>
|
||||
<view class="sparkle s3"></view>
|
||||
</view>
|
||||
<view class="rank-avatar-frame rank-frame-bronze">
|
||||
<view class="rank-avatar-container">
|
||||
<image class="rank-avatar-image" src="{{qiansanMing[2] ? qiansanMing[2].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo rank-halo-bronze"></view>
|
||||
<view class="rank-sparkle" style="top:15%;left:15%;animation-delay:0s"></view>
|
||||
<view class="rank-sparkle" style="top:25%;right:25%;animation-delay:0.5s"></view>
|
||||
<view class="rank-sparkle" style="bottom:35%;left:35%;animation-delay:1s"></view>
|
||||
</view>
|
||||
<view class="rank-badge badge-bronze">3</view>
|
||||
<view class="rank-badge rank-badge-bronze">3</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info-card">
|
||||
<view class="info-header">
|
||||
<text class="user-name">{{qiansanMing[2] ? qiansanMing[2].nicheng : '等待上榜'}}</text>
|
||||
</view>
|
||||
<view class="info-body">
|
||||
<view class="uid-row">
|
||||
<text class="uid-label">ID:</text>
|
||||
<text class="uid-value">{{qiansanMing[2] ? qiansanMing[2].uid : '----'}}</text>
|
||||
<view class="rank-user-info-card">
|
||||
<text class="rank-user-name">{{qiansanMing[2] ? qiansanMing[2].nicheng : '等待上榜'}}</text>
|
||||
<view class="rank-info-body">
|
||||
<view class="rank-uid-row">
|
||||
<text class="rank-uid-label">ID:</text>
|
||||
<text class="rank-uid-value">{{qiansanMing[2] ? qiansanMing[2].uid : '----'}}</text>
|
||||
</view>
|
||||
<view class="income-row">
|
||||
<text class="income-label">流水:</text>
|
||||
<view class="income-value">
|
||||
<text class="currency">¥</text>
|
||||
<text class="amount {{qiansanMing[2] ? qiansanMing[2].jineClass : ''}}">{{qiansanMing[2] ? qiansanMing[2].jine : '0.00'}}</text>
|
||||
<view class="rank-income-row">
|
||||
<text class="rank-income-label">流水:</text>
|
||||
<view class="rank-income-value">
|
||||
<text class="rank-currency">¥</text>
|
||||
<text class="rank-amount {{qiansanMing[2] ? qiansanMing[2].jineClass : ''}}">{{qiansanMing[2] ? qiansanMing[2].jine : '0.00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -237,54 +207,50 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- ========== 其他排名列表 ========== -->
|
||||
<view class="other-ranks-section" wx:if="{{paihangShuju.length > 0}}">
|
||||
<view class="section-title">
|
||||
<view class="title-line"></view>
|
||||
<text class="title-text">其他排名</text>
|
||||
<view class="title-line"></view>
|
||||
<view wx:if="{{paihangShuju.length > 0}}">
|
||||
<view class="rank-section-title">
|
||||
<view class="rank-section-line"></view>
|
||||
<text class="rank-section-text">其他排名</text>
|
||||
<view class="rank-section-line"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list">
|
||||
<view class="rank-item {{flashCardIndex == index && flashCardType == 'normal' ? 'flash' : ''}}"
|
||||
wx:for="{{paihangShuju}}" wx:key="index"
|
||||
animation="{{flashCardIndex == index && flashCardType == 'normal' ? flashAnimation : ''}}"
|
||||
data-index="{{index}}" data-type="normal" bindtap="handleCardTap">
|
||||
|
||||
<view class="rank-number">
|
||||
<text class="number-text">{{xianshiZhenshiShuju ? index + 4 : index + 1}}</text>
|
||||
<view class="number-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-avatar">
|
||||
<image class="rank-avatar-img" src="{{item.full_touxiang}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-avatar-halo"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-info">
|
||||
<text class="rank-name">{{item.nicheng}}</text>
|
||||
<text class="rank-uid">UID: {{item.uid}}</text>
|
||||
</view>
|
||||
|
||||
<view class="rank-income">
|
||||
<text class="income-currency">¥</text>
|
||||
<text class="income-amount {{item.jineClass}}">{{item.jine}}</text>
|
||||
<view class="income-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-hover"></view>
|
||||
|
||||
<view class="rank-list-item {{flashCardIndex == index && flashCardType == 'normal' ? 'flash' : ''}}"
|
||||
wx:for="{{paihangShuju}}" wx:key="index"
|
||||
animation="{{flashCardIndex == index && flashCardType == 'normal' ? flashAnimation : ''}}"
|
||||
data-index="{{index}}" data-type="normal" bindtap="handleCardTap">
|
||||
|
||||
<view class="rank-number">
|
||||
<text class="rank-number-text">{{xianshiZhenshiShuju ? index + 4 : index + 1}}</text>
|
||||
<view class="rank-number-glow"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-avatar">
|
||||
<image class="rank-list-avatar-img" src="{{item.full_touxiang}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
|
||||
<view class="rank-list-avatar-halo"></view>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-info">
|
||||
<text class="rank-list-name">{{item.nicheng}}</text>
|
||||
<text class="rank-list-uid">UID: {{item.uid}}</text>
|
||||
</view>
|
||||
|
||||
<view class="rank-list-income">
|
||||
<text class="rank-income-currency">¥</text>
|
||||
<text class="rank-income-amount {{item.jineClass}}">{{item.jine}}</text>
|
||||
<view class="rank-income-glow"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{xianshiZhenshiShuju && paihangShuju.length === 0 && qiansanMing.length === 0}}" class="empty-state">
|
||||
<view class="empty-icon">🏆</view>
|
||||
<text class="empty-title">暂无排名数据</text>
|
||||
<text class="empty-desc">成为第一个登榜的商家吧</text>
|
||||
<view wx:if="{{xianshiZhenshiShuju && paihangShuju.length === 0 && qiansanMing.length === 0}}" class="rank-empty-state">
|
||||
<view class="rank-empty-icon">🏆</view>
|
||||
<text class="rank-empty-title">暂无排名数据</text>
|
||||
<text class="rank-empty-desc">成为第一个登榜的商家吧</text>
|
||||
</view>
|
||||
</view>
|
||||
<global-notification id="global-notification" />
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,11 @@
|
||||
// pages/shangjiazhongxin/shangjiazhongxin.js
|
||||
// pages/shangjiazhongxin/shangjiiazhongxin.js
|
||||
|
||||
import request from '../../utils/request.js';
|
||||
import popupService from '../../services/popupService.js';
|
||||
import {
|
||||
isRoleStatusActive,
|
||||
isCenterPageActive,
|
||||
syncRoleStatuses,
|
||||
syncProfileFields,
|
||||
ensureRoleOnCenterPage,
|
||||
clearCacheAndEnterNormal,
|
||||
} from '../../utils/role-tab-bar.js';
|
||||
import { lockPrimaryRole } from '../../utils/primary-role.js';
|
||||
import { createPage, ensureRoleOnCenterPage, lockPrimaryRole, parseSceneOptions } from '../../utils/base-page.js';
|
||||
import { ensureLogin } from '../../utils/login.js';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
Page(createPage({
|
||||
data: {
|
||||
// 图片资源
|
||||
imgUrls: {
|
||||
@@ -35,14 +25,13 @@ Page({
|
||||
iconRecharge: '',
|
||||
iconWithdraw: '',
|
||||
iconRefresh: '',
|
||||
iconCopy: '',
|
||||
avatarFrame: '',
|
||||
iconClear: '',
|
||||
},
|
||||
iconCopy: '',
|
||||
avatarFrame: '',
|
||||
iconClear: '',
|
||||
},
|
||||
|
||||
// 商家状态
|
||||
isShangjia: false,
|
||||
isLoading: false,
|
||||
isAutoRegistering: false,
|
||||
|
||||
// 用户基础信息
|
||||
@@ -62,52 +51,57 @@ Page({
|
||||
|
||||
// 交互控制
|
||||
inviteCode: '',
|
||||
lastRefreshTime: 0,
|
||||
canRefresh: true,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.initImageUrls();
|
||||
this.checkShangjiaStatus();
|
||||
const parsed = parseSceneOptions(options);
|
||||
this.setupImageUrls();
|
||||
this.checkRoleStatus();
|
||||
|
||||
const { inviteCode } = options || {};
|
||||
const inviteCode = parsed.inviteCode;
|
||||
if (inviteCode) {
|
||||
this.setData({ inviteCode });
|
||||
setTimeout(() => this.handleInviteCodeWithLoginCheck(inviteCode), 500);
|
||||
setTimeout(() => this.handleInviteCodeWithLoginCheck({
|
||||
inviteCode,
|
||||
role: 'shangjia',
|
||||
statusKey: 'shangjiastatus',
|
||||
alreadyMsg: '您已是商家',
|
||||
onNeedLogin: (code) => {
|
||||
this.setData({ inviteCode: code });
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
if (!this.data.isShangjia) {
|
||||
wx.showLoading({ title: '商家注册中...', mask: true });
|
||||
this.setData({ isAutoRegistering: true });
|
||||
this.onRegister();
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
onAlreadyRegistered: () => {
|
||||
wx.showToast({ title: '您已是商家', icon: 'success' });
|
||||
ensureRoleOnCenterPage(this, 'shangjia');
|
||||
},
|
||||
}), 500);
|
||||
}
|
||||
|
||||
if (!app.globalData.hasShownPopupOnColdStart) {
|
||||
app.globalData.hasShownPopupOnColdStart = true;
|
||||
setTimeout(() => popupService.checkAndShow(this, 'shangjiaduan'), 300);
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
if (isCenterPageActive(this, 'isShangjia', 'shangjiastatus')) {
|
||||
ensureRoleOnCenterPage(this, 'shangjia');
|
||||
}
|
||||
this.checkColdStartPopup('shangjiaduan');
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
if (isCenterPageActive(this, 'isShangjia', 'shangjiastatus')) {
|
||||
if (!this.data.isShangjia) this.setData({ isShangjia: true });
|
||||
if (this.data.isShangjia) {
|
||||
ensureRoleOnCenterPage(this, 'shangjia');
|
||||
this.refreshShangjiaInfo();
|
||||
}
|
||||
},
|
||||
|
||||
onHide() {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
popupComp?.cleanup?.();
|
||||
},
|
||||
|
||||
// 图片路径初始化
|
||||
initImageUrls() {
|
||||
setupImageUrls() {
|
||||
const ossBase = app.globalData.ossImageUrl || '';
|
||||
const imgDir = `${ossBase}beijing/shangjiaduan/`;
|
||||
this.setData({
|
||||
imgUrls: {
|
||||
imgUrls: this.initImageUrls({
|
||||
pageBg: `${imgDir}page_bg.png`,
|
||||
avatarCardBg: `${imgDir}avatar_card_bg.png`,
|
||||
assetCardBg: `${imgDir}asset_card_bg.png`,
|
||||
@@ -128,16 +122,16 @@ Page({
|
||||
avatarFrame: `${imgDir}avatar_frame.png`,
|
||||
iconClear: `${ossBase}beijing/tubiao/grzx_qingchu.jpg`,
|
||||
iconSwitch: '/images/_exit.png',
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// 商家状态检查
|
||||
checkShangjiaStatus() {
|
||||
// 商家状态检查(覆盖基类 checkRoleStatus,增加 getShangjiaInfo 调用)
|
||||
checkRoleStatus() {
|
||||
try {
|
||||
const shangjiastatus = wx.getStorageSync('shangjiastatus');
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (isRoleStatusActive(shangjiastatus)) {
|
||||
if (shangjiastatus) {
|
||||
this.setData({ isShangjia: true, uid: uid || '' });
|
||||
this.loadAvatar();
|
||||
this.getShangjiaInfo();
|
||||
@@ -151,32 +145,20 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
loadAvatar() {
|
||||
const { ossImageUrl = '', morentouxiang = 'avatar/default.jpg' } = app.globalData || {};
|
||||
const touxiang = wx.getStorageSync('touxiang') || '';
|
||||
let avatarUrl = '';
|
||||
if (touxiang) {
|
||||
avatarUrl = ossImageUrl + (touxiang.startsWith('/') ? touxiang : '/' + touxiang);
|
||||
} else {
|
||||
avatarUrl = ossImageUrl + (morentouxiang.startsWith('/') ? morentouxiang : '/' + morentouxiang);
|
||||
}
|
||||
this.setData({ avatarUrl });
|
||||
},
|
||||
|
||||
// 获取商家信息
|
||||
async getShangjiaInfo() {
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({ url: '/yonghu/shangjiaxinxi', method: 'POST' });
|
||||
if (res?.data?.code === 200) {
|
||||
const data = res.data.data;
|
||||
await this.loadData({
|
||||
url: '/yonghu/shangjiaxinxi',
|
||||
method: 'POST',
|
||||
successCode: 200,
|
||||
errorMsg: '获取商家信息失败',
|
||||
onSuccess: (data) => {
|
||||
// 更新全局缓存
|
||||
app.globalData.shangjia = data;
|
||||
wx.setStorageSync('shangjiastatus', 1);
|
||||
|
||||
const chenghaoList = data.chenghao_list || [];
|
||||
|
||||
// 字段映射
|
||||
this.setData({
|
||||
nicheng: data.nicheng || '',
|
||||
sjyue: data.sjyue || '0.00',
|
||||
@@ -189,133 +171,46 @@ Page({
|
||||
chenghaoList: chenghaoList,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
|
||||
if (this.data.isAutoRegistering) {
|
||||
this.setData({ isAutoRegistering: false });
|
||||
wx.showToast({ title: '商家注册成功', icon: 'success' });
|
||||
}
|
||||
} else {
|
||||
throw new Error(res?.data?.msg || '获取商家信息失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取商家信息失败', error);
|
||||
this.setData({ isLoading: false });
|
||||
wx.showToast({ title: error.message || '加载失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
refreshShangjiaInfo() {
|
||||
const now = Date.now();
|
||||
if (!this.data.canRefresh || now - this.data.lastRefreshTime < 3000) {
|
||||
wx.showToast({ title: '操作过快', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({ lastRefreshTime: now, canRefresh: false });
|
||||
this.getShangjiaInfo();
|
||||
setTimeout(() => this.setData({ canRefresh: true }), 3000);
|
||||
},
|
||||
|
||||
// 邀请码注册
|
||||
handleInviteCodeWithLoginCheck(inviteCode) {
|
||||
const token = wx.getStorageSync('token');
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (!token || !uid) {
|
||||
this.setData({ inviteCode });
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
if (!this.data.isShangjia) {
|
||||
wx.showLoading({ title: '商家注册中...', mask: true });
|
||||
this.setData({ isAutoRegistering: true });
|
||||
this.onRegister();
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
} else {
|
||||
if (!this.data.isShangjia) {
|
||||
wx.showLoading({ title: '商家注册中...', mask: true });
|
||||
this.setData({ isAutoRegistering: true });
|
||||
this.onRegister();
|
||||
} else {
|
||||
wx.showToast({ title: '您已是商家', icon: 'success' });
|
||||
ensureRoleOnCenterPage(this, 'shangjia');
|
||||
}
|
||||
}
|
||||
this.throttledRefresh(() => this.getShangjiaInfo());
|
||||
},
|
||||
|
||||
async onRegister() {
|
||||
const { inviteCode } = this.data;
|
||||
if (!inviteCode) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (inviteCode.length > 100) {
|
||||
wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({ isLoading: true });
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/yonghu/shangjiahuce',
|
||||
method: 'POST',
|
||||
data: { inviteCode }
|
||||
});
|
||||
if (res?.data?.code === 200) {
|
||||
const data = res.data.data || {};
|
||||
syncRoleStatuses(data);
|
||||
syncProfileFields(data);
|
||||
if (!Object.prototype.hasOwnProperty.call(data, 'shangjiastatus')) {
|
||||
wx.setStorageSync('shangjiastatus', 1);
|
||||
app.globalData.shangjiastatus = 1;
|
||||
}
|
||||
app.globalData.shangjia = data;
|
||||
const chenghaoList = data.chenghao_list || [];
|
||||
await this.registerWithInviteCode({
|
||||
inviteCode,
|
||||
apiUrl: '/yonghu/shangjiahuce',
|
||||
role: 'shangjia',
|
||||
statusKey: 'shangjiastatus',
|
||||
successMsg: '商家注册成功',
|
||||
onSuccess: (userData) => {
|
||||
app.globalData.shangjia = userData;
|
||||
const chenghaoList = userData.chenghao_list || [];
|
||||
this.setData({
|
||||
isShangjia: true,
|
||||
nicheng: data.nicheng || '',
|
||||
sjyue: data.sjyue || '0.00',
|
||||
fabu: data.fabu || 0,
|
||||
tuikuan: data.tuikuan || 0,
|
||||
jinriliushui: data.jinriliushui || '0.00',
|
||||
jinyueliushui: data.jinyueliushui || '0.00',
|
||||
jinridingdan: data.jinridingdan || 0,
|
||||
nicheng: userData.nicheng || '',
|
||||
sjyue: userData.sjyue || '0.00',
|
||||
fabu: userData.fabu || 0,
|
||||
tuikuan: userData.tuikuan || 0,
|
||||
jinriliushui: userData.jinriliushui || '0.00',
|
||||
jinyueliushui: userData.jinyueliushui || '0.00',
|
||||
jinridingdan: userData.jinridingdan || 0,
|
||||
chenghaoList: chenghaoList,
|
||||
isLoading: false,
|
||||
isAutoRegistering: false,
|
||||
});
|
||||
this.loadAvatar();
|
||||
ensureRoleOnCenterPage(this, 'shangjia');
|
||||
lockPrimaryRole('shangjia');
|
||||
wx.showToast({ title: '商家注册成功', icon: 'success' });
|
||||
} else {
|
||||
throw new Error(res?.data?.msg || '注册失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('商家注册失败', error);
|
||||
this.setData({ isLoading: false, isAutoRegistering: false });
|
||||
wx.showToast({ title: error.message, icon: 'error' });
|
||||
}
|
||||
},
|
||||
|
||||
// 辅助功能
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp?.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
copyUid() {
|
||||
if (!this.data.uid) {
|
||||
wx.showToast({ title: 'UID不存在', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
wx.setClipboardData({
|
||||
data: this.data.uid,
|
||||
success: () => wx.showToast({ title: 'UID已复制', icon: 'success' }),
|
||||
fail: () => wx.showToast({ title: '复制失败', icon: 'error' })
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -327,7 +222,7 @@ Page({
|
||||
|
||||
// 页面跳转
|
||||
goToPaiDan() { wx.navigateTo({ url: '/pages/merchant-dispatch/merchant-dispatch' }); },
|
||||
goToJiSuPaiDan() {
|
||||
goToJiSuPaiDan() {
|
||||
wx.vibrateShort({ type: 'medium' });
|
||||
wx.navigateTo({ url: '/pages/express-order/express-order' });
|
||||
},
|
||||
@@ -336,33 +231,12 @@ Page({
|
||||
goToWithdraw() { wx.navigateTo({ url: '/pages/withdraw/withdraw' }); },
|
||||
goToRanking() { wx.navigateTo({ url: '/pages/fighter-rank/fighter-rank?type=shangjia' }); },
|
||||
goToMessages() { wx.navigateTo({ url: '/pages/merchant-msg/merchant-msg' }); },
|
||||
goToKefu() {
|
||||
const { kefuConfig } = app.globalData;
|
||||
if (kefuConfig?.link && kefuConfig?.enterpriseId) {
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: { url: kefuConfig.link },
|
||||
corpId: kefuConfig.enterpriseId,
|
||||
fail: () => wx.showToast({ title: '客服暂不可用', icon: 'none' })
|
||||
});
|
||||
} else {
|
||||
wx.showToast({ title: '客服配置未加载', icon: 'none' });
|
||||
}
|
||||
}, {
|
||||
roleConfig: {
|
||||
role: 'shangjia',
|
||||
statusKey: 'shangjiastatus',
|
||||
dataFlag: 'isShangjia',
|
||||
pageId: 'shangjiaduan',
|
||||
apiUrl: '/yonghu/shangjiaxinxi',
|
||||
},
|
||||
|
||||
clearCache() {
|
||||
wx.showModal({
|
||||
title: '清除缓存',
|
||||
content: '将清除所有登录与身份数据,并回到点单端,确定继续?',
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
success: (r) => {
|
||||
if (r.confirm) clearCacheAndEnterNormal(this);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
switchToNormal() {
|
||||
lockPrimaryRole('normal');
|
||||
wx.reLaunch({ url: '/pages/mine/mine' });
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -1,403 +1,394 @@
|
||||
// pages/messages/messages.js
|
||||
const app = getApp();
|
||||
import { formatDate } from '../../static/lib/utils';
|
||||
import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage } from '../../utils/avatar.js';
|
||||
import { getLocalImUserId } from '../../utils/im-user.js';
|
||||
import { normalizeConversationsList } from '../../utils/conversation-display.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
import { getPrimaryRole } from '../../utils/primary-role.js';
|
||||
const { jianquanxian } = require('../../utils/imAuth/jianquanxian');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
allConversations: [],
|
||||
filteredConversations: [],
|
||||
activeTab: 0,
|
||||
tabUnread: [0, 0, 0],
|
||||
displayCount: 10,
|
||||
searchKeyword: '',
|
||||
actionPopup: { visible: false, conversation: null },
|
||||
currentUser: null,
|
||||
notificationMuted: false,
|
||||
scrollHeight: 0
|
||||
},
|
||||
|
||||
_permissionSeq: 0,
|
||||
_peerProfileCache: {},
|
||||
|
||||
onLoad() {
|
||||
this.calculateScrollHeight();
|
||||
const muted = wx.getStorageSync('notificationMuted') || false;
|
||||
this.setData({ notificationMuted: muted });
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (!this.checkLoginStatus()) return;
|
||||
this.registerNotificationComponent();
|
||||
this.checkPermissionAndAutoConnect();
|
||||
},
|
||||
|
||||
onHide() {},
|
||||
|
||||
onUnload() {},
|
||||
|
||||
// ========== ==== ================ ==== ================ 鉴权检查 ==========
|
||||
async checkPermissionAndAutoConnect() {
|
||||
const seq = ++this._permissionSeq;
|
||||
let quanxian;
|
||||
try {
|
||||
quanxian = await jianquanxian(app);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
if (seq !== this._permissionSeq) return;
|
||||
|
||||
if (!quanxian.allowed) {
|
||||
const currentRole = app.globalData.currentRole || 'normal';
|
||||
let content = '您没有权限使用消息功能';
|
||||
if (currentRole === 'dashou') content = '您需要先充值会员才能使用消息功能';
|
||||
wx.showModal({
|
||||
title: '权限不足',
|
||||
content,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.autoConnect();
|
||||
},
|
||||
|
||||
// 登录状态检查
|
||||
checkLoginStatus() {
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (!uid) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' });
|
||||
setTimeout(() => { wx.redirectTo({ url: '/pages/mine/mine' }); }, 1500);
|
||||
return false;
|
||||
}
|
||||
let currentUser = app.globalData.currentUser;
|
||||
if (!currentUser) {
|
||||
currentUser = {
|
||||
id: getLocalImUserId(app) || uid,
|
||||
name: wx.getStorageSync('nicheng') || app.globalData.dashouNicheng || app.globalData.nicheng || ('用户' + uid.substring(0, 6)),
|
||||
avatar: resolveAvatarFromStorage(app),
|
||||
};
|
||||
app.globalData.currentUser = currentUser;
|
||||
}
|
||||
this.setData({ currentUser });
|
||||
return true;
|
||||
},
|
||||
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
autoConnect() {
|
||||
const targetUserId = getLocalImUserId(app);
|
||||
if (!targetUserId) return;
|
||||
|
||||
if (app.ensureConnection) app.ensureConnection();
|
||||
reconnectForRole(getPrimaryRole(app));
|
||||
|
||||
const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
|
||||
if (status === 'connected' || status === 'reconnected') {
|
||||
const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
|
||||
if (currentUserId === targetUserId) {
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
wx.goEasy.disconnect();
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
this.connectGoEasy(targetUserId);
|
||||
},
|
||||
|
||||
connectGoEasy(userId) {
|
||||
const { currentUser } = this.data;
|
||||
if (!currentUser) return;
|
||||
wx.goEasy.connect({
|
||||
id: userId,
|
||||
data: {
|
||||
name: currentUser.name,
|
||||
avatar: resolveAvatarUrl(currentUser.avatar, app),
|
||||
},
|
||||
onSuccess: () => {
|
||||
try {
|
||||
wx.setStorageSync('savedGoEasyConnection', JSON.stringify({
|
||||
userId,
|
||||
identityType: app.globalData.currentRole,
|
||||
lastConnectTime: Date.now(),
|
||||
status: 'connected',
|
||||
}));
|
||||
} catch (e) {}
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
if (app.registerNotification) {
|
||||
}
|
||||
},
|
||||
onFailed: (error) => {
|
||||
if (error.code === 408) {
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
} else {
|
||||
wx.showToast({ title: '连接失败,请重试', icon: 'none' });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
setupConversationListener() {
|
||||
if (!wx.goEasy || !wx.goEasy.im) return;
|
||||
if (this.conversationsUpdatedListener) {
|
||||
wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.conversationsUpdatedListener);
|
||||
}
|
||||
this.conversationsUpdatedListener = (result) => {
|
||||
const content = result?.content || result;
|
||||
this.renderConversations(content);
|
||||
};
|
||||
wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.conversationsUpdatedListener);
|
||||
},
|
||||
|
||||
loadConversations() {
|
||||
if (!wx.goEasy || !wx.goEasy.im) return;
|
||||
wx.goEasy.im.latestConversations({
|
||||
onSuccess: (result) => {
|
||||
const content = result?.content || result;
|
||||
this.renderConversations(content);
|
||||
},
|
||||
onFailed: () => {
|
||||
wx.showToast({ title: '获取会话失败', icon: 'none' });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 会话渲染与排序
|
||||
renderConversations(content) {
|
||||
const conversations = (content && content.conversations) ? content.conversations : [];
|
||||
if (!conversations.length) {
|
||||
this.setData({ allConversations: [] }, () => this.applyFilter());
|
||||
return;
|
||||
}
|
||||
let list = normalizeConversationsList(conversations, app, this._peerProfileCache);
|
||||
list.forEach(item => {
|
||||
if (!item.lastMessage) {
|
||||
item.lastMessage = { type: 'text', payload: { text: '' }, timestamp: 0 };
|
||||
}
|
||||
if (item.lastMessage.timestamp) {
|
||||
item.lastMessage.date = formatDate(item.lastMessage.timestamp);
|
||||
}
|
||||
});
|
||||
|
||||
list.sort((a, b) => {
|
||||
if (a.top && !b.top) return -1;
|
||||
if (!a.top && b.top) return 1;
|
||||
if (a.unread > 0 && b.unread <= 0) return -1;
|
||||
if (a.unread <= 0 && b.unread > 0) return 1;
|
||||
const ta = (a.lastMessage && a.lastMessage.timestamp) || 0;
|
||||
const tb = (b.lastMessage && b.lastMessage.timestamp) || 0;
|
||||
return tb - ta;
|
||||
});
|
||||
|
||||
this.setData({ allConversations: list, displayCount: 10 }, () => {
|
||||
this.applyFilter();
|
||||
});
|
||||
|
||||
const unreadTotal = content.unreadTotal !== undefined
|
||||
? content.unreadTotal
|
||||
: list.reduce((sum, c) => sum + (c.unread || 0), 0);
|
||||
if (app.updateUnreadCount) {
|
||||
app.updateUnreadCount(unreadTotal);
|
||||
} else if (app.emitEvent) {
|
||||
app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
|
||||
}
|
||||
|
||||
// 重新订阅群组
|
||||
this.subscribeGroupsIfNeeded(list);
|
||||
},
|
||||
|
||||
/**
|
||||
* 群组订阅,每次获取群组列表时直接订阅保证消息不丢失
|
||||
*/
|
||||
subscribeGroupsIfNeeded(conversations) {
|
||||
if (!wx.goEasy?.im || typeof wx.goEasy.im.subscribeGroup !== 'function') return;
|
||||
|
||||
const groupIds = conversations
|
||||
.filter(c => c.type === 'group' && c.groupId)
|
||||
.map(c => c.groupId);
|
||||
|
||||
if (groupIds.length === 0) return;
|
||||
|
||||
// 不再判断缓存,直接订阅当前所有群组
|
||||
wx.goEasy.im.subscribeGroup({
|
||||
groupIds: groupIds,
|
||||
onSuccess: () => {
|
||||
// 可选的日志输出,不影响功能
|
||||
// console.log('群组订阅成功', groupIds);
|
||||
},
|
||||
onFailed: (error) => {
|
||||
console.error('群组订阅失败:', error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
applyFilter() {
|
||||
const { allConversations, activeTab, searchKeyword } = this.data;
|
||||
let filtered = [];
|
||||
if (activeTab === 0) {
|
||||
filtered = allConversations.filter(c => c.type === 'group' && c.data && c.data.orderId);
|
||||
} else if (activeTab === 1) {
|
||||
filtered = allConversations.filter(c => c.type === 'private');
|
||||
} else if (activeTab === 2) {
|
||||
filtered = allConversations.filter(c => c.type === 'cs');
|
||||
}
|
||||
|
||||
if (searchKeyword.trim()) {
|
||||
const kw = searchKeyword.trim().toLowerCase();
|
||||
filtered = filtered.filter(c => {
|
||||
const name = (c.data && c.data.name || '').toLowerCase();
|
||||
const orderId = (c.data && c.data.orderId || '').toLowerCase();
|
||||
const id = (c.userId || c.groupId || '').toLowerCase();
|
||||
return name.includes(kw) || id.includes(kw) || orderId.includes(kw);
|
||||
});
|
||||
}
|
||||
|
||||
const tabUnread = [0, 0, 0];
|
||||
allConversations.forEach(c => {
|
||||
if (c.type === 'group' && c.data && c.data.orderId) tabUnread[0] += c.unread || 0;
|
||||
else if (c.type === 'private') tabUnread[1] += c.unread || 0;
|
||||
else if (c.type === 'cs') tabUnread[2] += c.unread || 0;
|
||||
});
|
||||
|
||||
this.setData({ filteredConversations: filtered, tabUnread });
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const index = parseInt(e.currentTarget.dataset.index);
|
||||
this.setData({ activeTab: index, displayCount: 10, searchKeyword: '' }, () => this.applyFilter());
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({ searchKeyword: e.detail.value, displayCount: 10 }, () => this.applyFilter());
|
||||
},
|
||||
|
||||
onScrollToLower() {
|
||||
const { displayCount, filteredConversations } = this.data;
|
||||
if (displayCount < filteredConversations.length) {
|
||||
this.setData({ displayCount: Math.min(displayCount + 10, filteredConversations.length) });
|
||||
}
|
||||
},
|
||||
|
||||
onRefresh() {
|
||||
this.loadConversations();
|
||||
},
|
||||
|
||||
chat(e) {
|
||||
const conversation = e.currentTarget.dataset.conversation;
|
||||
if (!conversation) return;
|
||||
|
||||
if (conversation.type === 'private') {
|
||||
const param = {
|
||||
toUserId: conversation.userId,
|
||||
toName: conversation.data.name || '用户',
|
||||
toAvatar: resolveAvatarUrl(conversation.data.avatar, app),
|
||||
};
|
||||
wx.navigateTo({ url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
} else if (conversation.type === 'group') {
|
||||
const param = {
|
||||
groupId: conversation.groupId,
|
||||
orderId: conversation.data.orderId || '',
|
||||
groupName: conversation.data.name,
|
||||
groupAvatar: conversation.data.avatar,
|
||||
isCross: conversation.data.isCross || 0
|
||||
};
|
||||
wx.navigateTo({ url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
} else if (conversation.type === 'cs') {
|
||||
const param = { teamId: conversation.teamId || conversation.id };
|
||||
wx.navigateTo({ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
}
|
||||
},
|
||||
|
||||
chatKefu() {
|
||||
const param = { teamId: 'support_team' };
|
||||
wx.navigateTo({ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
},
|
||||
|
||||
showAction(e) {
|
||||
const conversation = e.currentTarget.dataset.conversation;
|
||||
this.setData({ ['actionPopup.conversation']: conversation, ['actionPopup.visible']: true });
|
||||
},
|
||||
closeMask() {
|
||||
this.setData({ ['actionPopup.visible']: false });
|
||||
},
|
||||
topConversation() {
|
||||
let conversation = this.data.actionPopup.conversation;
|
||||
if (!conversation) return;
|
||||
const top = !conversation.top;
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
if (conversation.type === 'private') {
|
||||
wx.goEasy.im.topPrivateConversation({
|
||||
userId: conversation.userId, top,
|
||||
onSuccess: () => {
|
||||
wx.hideLoading(); this.loadConversations();
|
||||
wx.showToast({ title: top ? '已置顶' : '已取消置顶' });
|
||||
},
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); }
|
||||
});
|
||||
} else {
|
||||
wx.goEasy.im.topGroupConversation({
|
||||
groupId: conversation.groupId, top,
|
||||
onSuccess: () => {
|
||||
wx.hideLoading(); this.loadConversations();
|
||||
wx.showToast({ title: top ? '已置顶' : '已取消置顶' });
|
||||
},
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); }
|
||||
});
|
||||
}
|
||||
this.closeMask();
|
||||
},
|
||||
removeConversation() {
|
||||
let conversation = this.data.actionPopup.conversation;
|
||||
if (!conversation) return;
|
||||
wx.showLoading({ title: '删除中...' });
|
||||
wx.goEasy.im.removeConversation({
|
||||
conversation: conversation,
|
||||
onSuccess: () => { wx.hideLoading(); this.loadConversations(); wx.showToast({ title: '已删除' }); },
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '删除失败', icon: 'none' }); }
|
||||
});
|
||||
this.closeMask();
|
||||
},
|
||||
|
||||
toggleNotification() {
|
||||
const newMuted = !this.data.notificationMuted;
|
||||
this.setData({ notificationMuted: newMuted });
|
||||
wx.setStorageSync('notificationMuted', newMuted);
|
||||
wx.showToast({ title: newMuted ? '已静音' : '已开启通知', icon: 'none' });
|
||||
},
|
||||
|
||||
calculateScrollHeight() {
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
const windowHeight = systemInfo.windowHeight;
|
||||
const windowWidth = systemInfo.windowWidth;
|
||||
const rpxRatio = 750 / windowWidth;
|
||||
const headerHeight = 150 / rpxRatio;
|
||||
const tabBarHeight = 130 / rpxRatio;
|
||||
const safeAreaBottom = systemInfo.safeArea ? (windowHeight - systemInfo.safeArea.bottom) : 0;
|
||||
this.setData({ scrollHeight: windowHeight - headerHeight - tabBarHeight - safeAreaBottom });
|
||||
},
|
||||
|
||||
onAvatarError(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const def = getDefaultAvatarUrl(app);
|
||||
const key = `filteredConversations[${index}].data.avatar`;
|
||||
this.setData({ [key]: def });
|
||||
}
|
||||
});
|
||||
// pages/messages/messages.js
|
||||
const app = getApp();
|
||||
import { formatDate } from '../../static/lib/utils';
|
||||
import { resolveAvatarUrl, getDefaultAvatarUrl, resolveAvatarFromStorage } from '../../utils/avatar.js';
|
||||
import { getLocalImUserId } from '../../utils/im-user.js';
|
||||
import { normalizeConversationsList } from '../../utils/conversation-display.js';
|
||||
import { reconnectForRole } from '../../utils/role-tab-bar.js';
|
||||
import { getPrimaryRole } from '../../utils/primary-role.js';
|
||||
import { createPage } from '../../utils/base-page.js';
|
||||
const { jianquanxian } = require('../../utils/imAuth/jianquanxian');
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
allConversations: [],
|
||||
filteredConversations: [],
|
||||
activeTab: 0,
|
||||
tabUnread: [0, 0, 0],
|
||||
displayCount: 10,
|
||||
searchKeyword: '',
|
||||
actionPopup: { visible: false, conversation: null },
|
||||
currentUser: null,
|
||||
notificationMuted: false,
|
||||
scrollHeight: 0
|
||||
},
|
||||
|
||||
_permissionSeq: 0,
|
||||
_peerProfileCache: {},
|
||||
|
||||
onLoad() {
|
||||
this.calculateScrollHeight();
|
||||
const muted = wx.getStorageSync('notificationMuted') || false;
|
||||
this.setData({ notificationMuted: muted });
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (!this.checkLoginStatus()) return;
|
||||
this.registerNotificationComponent();
|
||||
this.checkPermissionAndAutoConnect();
|
||||
},
|
||||
|
||||
onHide() {},
|
||||
|
||||
onUnload() {},
|
||||
|
||||
// ========== ==== ================ ==== ================ 鉴权检查 ==========
|
||||
async checkPermissionAndAutoConnect() {
|
||||
const seq = ++this._permissionSeq;
|
||||
let quanxian;
|
||||
try {
|
||||
quanxian = await jianquanxian(app);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
if (seq !== this._permissionSeq) return;
|
||||
|
||||
if (!quanxian.allowed) {
|
||||
const currentRole = app.globalData.currentRole || 'normal';
|
||||
let content = '您没有权限使用消息功能';
|
||||
if (currentRole === 'dashou') content = '您需要先充值会员才能使用消息功能';
|
||||
wx.showModal({
|
||||
title: '权限不足',
|
||||
content,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.autoConnect();
|
||||
},
|
||||
|
||||
// 登录状态检查
|
||||
checkLoginStatus() {
|
||||
const uid = wx.getStorageSync('uid');
|
||||
if (!uid) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' });
|
||||
setTimeout(() => { wx.redirectTo({ url: '/pages/mine/mine' }); }, 1500);
|
||||
return false;
|
||||
}
|
||||
let currentUser = app.globalData.currentUser;
|
||||
if (!currentUser) {
|
||||
currentUser = {
|
||||
id: getLocalImUserId(app) || uid,
|
||||
name: wx.getStorageSync('nicheng') || app.globalData.dashouNicheng || app.globalData.nicheng || ('用户' + uid.substring(0, 6)),
|
||||
avatar: resolveAvatarFromStorage(app),
|
||||
};
|
||||
app.globalData.currentUser = currentUser;
|
||||
}
|
||||
this.setData({ currentUser });
|
||||
return true;
|
||||
},
|
||||
|
||||
autoConnect() {
|
||||
const targetUserId = getLocalImUserId(app);
|
||||
if (!targetUserId) return;
|
||||
|
||||
if (app.ensureConnection) app.ensureConnection();
|
||||
reconnectForRole(getPrimaryRole(app));
|
||||
|
||||
const status = wx.goEasy.getConnectionStatus ? wx.goEasy.getConnectionStatus() : 'disconnected';
|
||||
if (status === 'connected' || status === 'reconnected') {
|
||||
const currentUserId = wx.goEasy.im ? wx.goEasy.im.userId : null;
|
||||
if (currentUserId === targetUserId) {
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
wx.goEasy.disconnect();
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
this.connectGoEasy(targetUserId);
|
||||
},
|
||||
|
||||
connectGoEasy(userId) {
|
||||
const { currentUser } = this.data;
|
||||
if (!currentUser) return;
|
||||
wx.goEasy.connect({
|
||||
id: userId,
|
||||
data: {
|
||||
name: currentUser.name,
|
||||
avatar: resolveAvatarUrl(currentUser.avatar, app),
|
||||
},
|
||||
onSuccess: () => {
|
||||
try {
|
||||
wx.setStorageSync('savedGoEasyConnection', JSON.stringify({
|
||||
userId,
|
||||
identityType: app.globalData.currentRole,
|
||||
lastConnectTime: Date.now(),
|
||||
status: 'connected',
|
||||
}));
|
||||
} catch (e) {}
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
if (app.registerNotification) {
|
||||
}
|
||||
},
|
||||
onFailed: (error) => {
|
||||
if (error.code === 408) {
|
||||
this.setupConversationListener();
|
||||
this.loadConversations();
|
||||
} else {
|
||||
wx.showToast({ title: '连接失败,请重试', icon: 'none' });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
setupConversationListener() {
|
||||
if (!wx.goEasy || !wx.goEasy.im) return;
|
||||
if (this.conversationsUpdatedListener) {
|
||||
wx.goEasy.im.off(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.conversationsUpdatedListener);
|
||||
}
|
||||
this.conversationsUpdatedListener = (result) => {
|
||||
const content = result?.content || result;
|
||||
this.renderConversations(content);
|
||||
};
|
||||
wx.goEasy.im.on(wx.GoEasy.IM_EVENT.CONVERSATIONS_UPDATED, this.conversationsUpdatedListener);
|
||||
},
|
||||
|
||||
loadConversations() {
|
||||
if (!wx.goEasy || !wx.goEasy.im) return;
|
||||
wx.goEasy.im.latestConversations({
|
||||
onSuccess: (result) => {
|
||||
const content = result?.content || result;
|
||||
this.renderConversations(content);
|
||||
},
|
||||
onFailed: () => {
|
||||
wx.showToast({ title: '获取会话失败', icon: 'none' });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 会话渲染与排序
|
||||
renderConversations(content) {
|
||||
const conversations = (content && content.conversations) ? content.conversations : [];
|
||||
if (!conversations.length) {
|
||||
this.setData({ allConversations: [] }, () => this.applyFilter());
|
||||
return;
|
||||
}
|
||||
let list = normalizeConversationsList(conversations, app, this._peerProfileCache);
|
||||
list.forEach(item => {
|
||||
if (!item.lastMessage) {
|
||||
item.lastMessage = { type: 'text', payload: { text: '' }, timestamp: 0 };
|
||||
}
|
||||
if (item.lastMessage.timestamp) {
|
||||
item.lastMessage.date = formatDate(item.lastMessage.timestamp);
|
||||
}
|
||||
});
|
||||
|
||||
list.sort((a, b) => {
|
||||
if (a.top && !b.top) return -1;
|
||||
if (!a.top && b.top) return 1;
|
||||
if (a.unread > 0 && b.unread <= 0) return -1;
|
||||
if (a.unread <= 0 && b.unread > 0) return 1;
|
||||
const ta = (a.lastMessage && a.lastMessage.timestamp) || 0;
|
||||
const tb = (b.lastMessage && b.lastMessage.timestamp) || 0;
|
||||
return tb - ta;
|
||||
});
|
||||
|
||||
this.setData({ allConversations: list, displayCount: 10 }, () => {
|
||||
this.applyFilter();
|
||||
});
|
||||
|
||||
const unreadTotal = content.unreadTotal !== undefined
|
||||
? content.unreadTotal
|
||||
: list.reduce((sum, c) => sum + (c.unread || 0), 0);
|
||||
if (app.updateUnreadCount) {
|
||||
app.updateUnreadCount(unreadTotal);
|
||||
} else if (app.emitEvent) {
|
||||
app.emitEvent('tabBarBadgeChanged', { badgeText: unreadTotal > 0 ? String(unreadTotal) : '' });
|
||||
}
|
||||
|
||||
// 重新订阅群组
|
||||
this.subscribeGroupsIfNeeded(list);
|
||||
},
|
||||
|
||||
/**
|
||||
* 群组订阅,每次获取群组列表时直接订阅保证消息不丢失
|
||||
*/
|
||||
subscribeGroupsIfNeeded(conversations) {
|
||||
if (!wx.goEasy?.im || typeof wx.goEasy.im.subscribeGroup !== 'function') return;
|
||||
|
||||
const groupIds = conversations
|
||||
.filter(c => c.type === 'group' && c.groupId)
|
||||
.map(c => c.groupId);
|
||||
|
||||
if (groupIds.length === 0) return;
|
||||
|
||||
// 不再判断缓存,直接订阅当前所有群组
|
||||
wx.goEasy.im.subscribeGroup({
|
||||
groupIds: groupIds,
|
||||
onSuccess: () => {
|
||||
// 可选的日志输出,不影响功能
|
||||
// console.log('群组订阅成功', groupIds);
|
||||
},
|
||||
onFailed: (error) => {
|
||||
console.error('群组订阅失败:', error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
applyFilter() {
|
||||
const { allConversations, activeTab, searchKeyword } = this.data;
|
||||
let filtered = [];
|
||||
if (activeTab === 0) {
|
||||
filtered = allConversations.filter(c => c.type === 'group' && c.data && c.data.orderId);
|
||||
} else if (activeTab === 1) {
|
||||
filtered = allConversations.filter(c => c.type === 'private');
|
||||
} else if (activeTab === 2) {
|
||||
filtered = allConversations.filter(c => c.type === 'cs');
|
||||
}
|
||||
|
||||
if (searchKeyword.trim()) {
|
||||
const kw = searchKeyword.trim().toLowerCase();
|
||||
filtered = filtered.filter(c => {
|
||||
const name = (c.data && c.data.name || '').toLowerCase();
|
||||
const orderId = (c.data && c.data.orderId || '').toLowerCase();
|
||||
const id = (c.userId || c.groupId || '').toLowerCase();
|
||||
return name.includes(kw) || id.includes(kw) || orderId.includes(kw);
|
||||
});
|
||||
}
|
||||
|
||||
const tabUnread = [0, 0, 0];
|
||||
allConversations.forEach(c => {
|
||||
if (c.type === 'group' && c.data && c.data.orderId) tabUnread[0] += c.unread || 0;
|
||||
else if (c.type === 'private') tabUnread[1] += c.unread || 0;
|
||||
else if (c.type === 'cs') tabUnread[2] += c.unread || 0;
|
||||
});
|
||||
|
||||
this.setData({ filteredConversations: filtered, tabUnread });
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const index = parseInt(e.currentTarget.dataset.index);
|
||||
this.setData({ activeTab: index, displayCount: 10, searchKeyword: '' }, () => this.applyFilter());
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({ searchKeyword: e.detail.value, displayCount: 10 }, () => this.applyFilter());
|
||||
},
|
||||
|
||||
onScrollToLower() {
|
||||
const { displayCount, filteredConversations } = this.data;
|
||||
if (displayCount < filteredConversations.length) {
|
||||
this.setData({ displayCount: Math.min(displayCount + 10, filteredConversations.length) });
|
||||
}
|
||||
},
|
||||
|
||||
onRefresh() {
|
||||
this.loadConversations();
|
||||
},
|
||||
|
||||
chat(e) {
|
||||
const conversation = e.currentTarget.dataset.conversation;
|
||||
if (!conversation) return;
|
||||
|
||||
if (conversation.type === 'private') {
|
||||
const param = {
|
||||
toUserId: conversation.userId,
|
||||
toName: conversation.data.name || '用户',
|
||||
toAvatar: resolveAvatarUrl(conversation.data.avatar, app),
|
||||
};
|
||||
wx.navigateTo({ url: '/pages/chat/chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
} else if (conversation.type === 'group') {
|
||||
const param = {
|
||||
groupId: conversation.groupId,
|
||||
orderId: conversation.data.orderId || '',
|
||||
groupName: conversation.data.name,
|
||||
groupAvatar: conversation.data.avatar,
|
||||
isCross: conversation.data.isCross || 0
|
||||
};
|
||||
wx.navigateTo({ url: '/pages/group-chat/group-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
} else if (conversation.type === 'cs') {
|
||||
const param = { teamId: conversation.teamId || conversation.id };
|
||||
wx.navigateTo({ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
}
|
||||
},
|
||||
|
||||
chatKefu() {
|
||||
const param = { teamId: 'support_team' };
|
||||
wx.navigateTo({ url: '/pages/cs-chat/cs-chat?data=' + encodeURIComponent(JSON.stringify(param)) });
|
||||
},
|
||||
|
||||
showAction(e) {
|
||||
const conversation = e.currentTarget.dataset.conversation;
|
||||
this.setData({ ['actionPopup.conversation']: conversation, ['actionPopup.visible']: true });
|
||||
},
|
||||
closeMask() {
|
||||
this.setData({ ['actionPopup.visible']: false });
|
||||
},
|
||||
topConversation() {
|
||||
let conversation = this.data.actionPopup.conversation;
|
||||
if (!conversation) return;
|
||||
const top = !conversation.top;
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
if (conversation.type === 'private') {
|
||||
wx.goEasy.im.topPrivateConversation({
|
||||
userId: conversation.userId, top,
|
||||
onSuccess: () => {
|
||||
wx.hideLoading(); this.loadConversations();
|
||||
wx.showToast({ title: top ? '已置顶' : '已取消置顶' });
|
||||
},
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); }
|
||||
});
|
||||
} else {
|
||||
wx.goEasy.im.topGroupConversation({
|
||||
groupId: conversation.groupId, top,
|
||||
onSuccess: () => {
|
||||
wx.hideLoading(); this.loadConversations();
|
||||
wx.showToast({ title: top ? '已置顶' : '已取消置顶' });
|
||||
},
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); }
|
||||
});
|
||||
}
|
||||
this.closeMask();
|
||||
},
|
||||
removeConversation() {
|
||||
let conversation = this.data.actionPopup.conversation;
|
||||
if (!conversation) return;
|
||||
wx.showLoading({ title: '删除中...' });
|
||||
wx.goEasy.im.removeConversation({
|
||||
conversation: conversation,
|
||||
onSuccess: () => { wx.hideLoading(); this.loadConversations(); wx.showToast({ title: '已删除' }); },
|
||||
onFailed: () => { wx.hideLoading(); wx.showToast({ title: '删除失败', icon: 'none' }); }
|
||||
});
|
||||
this.closeMask();
|
||||
},
|
||||
|
||||
toggleNotification() {
|
||||
const newMuted = !this.data.notificationMuted;
|
||||
this.setData({ notificationMuted: newMuted });
|
||||
wx.setStorageSync('notificationMuted', newMuted);
|
||||
wx.showToast({ title: newMuted ? '已静音' : '已开启通知', icon: 'none' });
|
||||
},
|
||||
|
||||
calculateScrollHeight() {
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
const windowHeight = systemInfo.windowHeight;
|
||||
const windowWidth = systemInfo.windowWidth;
|
||||
const rpxRatio = 750 / windowWidth;
|
||||
const headerHeight = 150 / rpxRatio;
|
||||
const tabBarHeight = 130 / rpxRatio;
|
||||
const safeAreaBottom = systemInfo.safeArea ? (windowHeight - systemInfo.safeArea.bottom) : 0;
|
||||
this.setData({ scrollHeight: windowHeight - headerHeight - tabBarHeight - safeAreaBottom });
|
||||
},
|
||||
|
||||
onAvatarError(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const def = getDefaultAvatarUrl(app);
|
||||
const key = `filteredConversations[${index}].data.avatar`;
|
||||
this.setData({ [key]: def });
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -1,38 +1,254 @@
|
||||
.msg-page { background: #f5f5f5; }
|
||||
/* pages/messages/messages.wxss */
|
||||
|
||||
.header { display: flex; align-items: center; padding: 20rpx 24rpx; background: #fff; border-bottom: 1rpx solid #e8e8e8; }
|
||||
.search-bar { flex: 1; }
|
||||
.search-input { height: 68rpx; }
|
||||
.search-icon { font-size: 32rpx; margin-left: 10rpx; color: #999; }
|
||||
.notify-switch { margin-left: 20rpx; }
|
||||
.notify-text { font-size: 26rpx; color: #666; padding: 10rpx 16rpx; background: #f0f0f0; border-radius: 30rpx; }
|
||||
.msg-page {
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.tab-row { border-bottom: 1rpx solid #e8e8e8; }
|
||||
/* .tab-item 已由全局 .tab-item 覆盖 */
|
||||
.tab-item.active { color: #07c160; font-weight: 600; }
|
||||
.tab-item.active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 60rpx; height: 6rpx; background: #07c160; border-radius: 3rpx; }
|
||||
.tab-badge { border-radius: 20rpx; padding: 2rpx 12rpx; margin-left: 8rpx; }
|
||||
/* 顶部搜索 + 通知 */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 24rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.conversation-list { background: #fff; }
|
||||
.conversation-item { display: flex; align-items: center; padding: 20rpx 24rpx; border-bottom: 1rpx solid #f0f0f0; }
|
||||
.has-unread { background: #fafafa; }
|
||||
.avatar { width: 96rpx; height: 96rpx; border-radius: 12rpx; margin-right: 20rpx; background: #eee; }
|
||||
.info { flex: 1; }
|
||||
.top-line { display: flex; justify-content: space-between; margin-bottom: 8rpx; }
|
||||
.name { font-size: 30rpx; color: #1a1a1a; font-weight: 500; }
|
||||
.time { font-size: 22rpx; color: #999; }
|
||||
.bottom-line { display: flex; justify-content: space-between; align-items: center; }
|
||||
.last-msg { font-size: 26rpx; color: #888; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.unread-dot { background: #fa5151; color: #fff; font-size: 20rpx; border-radius: 50%; min-width: 36rpx; height: 36rpx; line-height: 36rpx; text-align: center; margin-left: 12rpx; }
|
||||
.load-tip { text-align: center; padding: 24rpx; color: #999; font-size: 24rpx; }
|
||||
.empty { text-align: center; padding: 200rpx 0; color: #bbb; font-size: 28rpx; }
|
||||
.search-bar {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 24rpx;
|
||||
height: 68rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 68rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 28rpx;
|
||||
margin-left: 10rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.notify-switch {
|
||||
margin-left: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notify-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
padding: 10rpx 20rpx;
|
||||
background: #f0f0f0;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
|
||||
/* TAB 栏 */
|
||||
.tab-row {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #e8e8e8;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 88rpx;
|
||||
position: relative;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: #07c160;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-item.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background: #07c160;
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tab-badge {
|
||||
background: #fa5151;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 2rpx 10rpx;
|
||||
margin-left: 8rpx;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 会话列表 */
|
||||
.conversation-list {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.conversation-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.conversation-item:active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.has-unread {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
background: #eee;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.top-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 30rpx;
|
||||
color: #1a1a1a;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
flex-shrink: 0;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.bottom-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.last-msg {
|
||||
font-size: 26rpx;
|
||||
color: #888;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.unread-dot {
|
||||
background: #fa5151;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
border-radius: 50%;
|
||||
min-width: 36rpx;
|
||||
height: 36rpx;
|
||||
line-height: 36rpx;
|
||||
text-align: center;
|
||||
margin-left: 12rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.load-tip {
|
||||
text-align: center;
|
||||
padding: 24rpx;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 200rpx 0;
|
||||
color: #bbb;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 客服入口 */
|
||||
.kefu-entry { text-align: center; padding: 100rpx 0; }
|
||||
.kefu-btn { width: 300rpx; background: #07c160; color: #fff; border-radius: 40rpx; font-size: 28rpx; }
|
||||
.kefu-entry {
|
||||
text-align: center;
|
||||
padding: 100rpx 0;
|
||||
}
|
||||
|
||||
.kefu-btn {
|
||||
width: 300rpx;
|
||||
background: #07c160;
|
||||
color: #fff;
|
||||
border-radius: 40rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 操作弹窗 */
|
||||
.action-mask { background: rgba(0,0,0,0.4); z-index: 10000; }
|
||||
.action-sheet { position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-radius: 24rpx 24rpx 0 0; padding: 20rpx 20rpx 150rpx 20rpx; }
|
||||
.action-btn { text-align: center; padding: 28rpx 0; font-size: 32rpx; border-bottom: 1rpx solid #eee; }
|
||||
.cancel { color: #999; margin-top: 12rpx; border-bottom: none; }
|
||||
.action-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
animation: fadeIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
.action-sheet {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
padding: 20rpx 20rpx 60rpx;
|
||||
animation: slideInUp 0.25s ease-out;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
text-align: center;
|
||||
padding: 28rpx 0;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
color: #999;
|
||||
margin-top: 12rpx;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@@ -1,169 +1,140 @@
|
||||
// pages/mine/mine.js
|
||||
const app = getApp();
|
||||
import { ensureLogin } from '../../utils/login';
|
||||
import {
|
||||
backfillUserProfileCache,
|
||||
getUserProfileForDisplay,
|
||||
clearCacheAndEnterNormal,
|
||||
isRoleStatusActive,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar';
|
||||
import { enterLockedRole } from '../../utils/primary-role.js';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
avatarUrl: '',
|
||||
userNicheng: '',
|
||||
userUid: '',
|
||||
showLoginBtn: false,
|
||||
orderCounts: { daifuwu:0, fuwuzhong:0, yiwancheng:0, yituikuan:0 },
|
||||
// 图标
|
||||
settingIcon: '', daifuwuIcon: '', fuwuzhongIcon: '', yiwanchengIcon: '', yituikuanIcon: '',
|
||||
dashouIcon: '', shangjiaIcon: '', guanshiIcon: '', kefuIcon: '',
|
||||
zuzhangIcon: '', guanzhualongIcon: '', arrowRightIcon: '', qingchuIcon: '',
|
||||
dashouCertified: false,
|
||||
shangjiaCertified: false,
|
||||
bottomSafePadding: 0
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.initIconUrls()
|
||||
this.loadUserData()
|
||||
this.setBottomSafe()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.initIconUrls();
|
||||
this.registerNotification();
|
||||
this.checkAvatarPrompt();
|
||||
backfillUserProfileCache(app);
|
||||
this.loadUserData();
|
||||
this.updateOrderCounts();
|
||||
},
|
||||
|
||||
setBottomSafe() {
|
||||
const sys = wx.getSystemInfoSync()
|
||||
const safeBottom = sys.screenHeight - sys.safeArea.bottom // 底部安全区高度(px)
|
||||
const tabBarHeight = (sys.windowWidth / 750) * 100 // 100rpx 转为 px
|
||||
this.setData({
|
||||
bottomSafePadding: safeBottom + tabBarHeight + 4 // 4px 微调,确保不留缝隙
|
||||
})
|
||||
},
|
||||
|
||||
registerNotification() {
|
||||
const comp = this.selectComponent('#global-notification')
|
||||
if (comp?.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: d => comp.showNotification(d),
|
||||
hide: () => comp.hideNotification()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
checkAvatarPrompt() {
|
||||
const ds = wx.getStorageSync('dashoustatus')
|
||||
const tx = wx.getStorageSync('touxiang') || ''
|
||||
if (ds === 1 && (!tx || tx === 'a_long/morentouxiang.jpg')) {
|
||||
wx.showModal({
|
||||
title: '提示', content: '请先设置头像',
|
||||
confirmText: '去设置', confirmColor: '#C9A962',
|
||||
success: r => r.confirm && wx.navigateTo({ url: '/pages/edit/edit' })
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
initIconUrls() {
|
||||
const base = (app.globalData.ossImageUrl || '') + '/beijing/tubiao/'
|
||||
this.setData({
|
||||
settingIcon: base + 'grzx_shezhi.jpg',
|
||||
daifuwuIcon: base + 'grzx_daifuwu.jpg',
|
||||
fuwuzhongIcon: base + 'grzx_fuwuzhong.jpg',
|
||||
yiwanchengIcon: base + 'grzx_yiwancheng.jpg',
|
||||
yituikuanIcon: base + 'grzx_yituikuan.jpg',
|
||||
dashouIcon: base + 'grzx_dashou.jpg',
|
||||
shangjiaIcon: base + 'grzx_shangjia.jpg',
|
||||
guanshiIcon: base + 'grzx_guanshi.jpg',
|
||||
kefuIcon: base + 'grzx_kefu.jpg',
|
||||
zuzhangIcon: base + 'grzx_zuzhang.jpg',
|
||||
guanzhualongIcon: base + 'grzx_guanzhualong.jpg',
|
||||
arrowRightIcon: base + 'grzx_arrow_right.jpg',
|
||||
qingchuIcon: base + 'grzx_qingchu.jpg',
|
||||
kaoheguanIcon: base + 'kaoheguan.png',
|
||||
})
|
||||
},
|
||||
|
||||
loadUserData() {
|
||||
const profile = getUserProfileForDisplay(app);
|
||||
this.setData({
|
||||
avatarUrl: profile.avatarUrl,
|
||||
userNicheng: profile.nick,
|
||||
userUid: profile.uid,
|
||||
showLoginBtn: !profile.isLoggedIn,
|
||||
dashouCertified: isRoleStatusActive(wx.getStorageSync('dashoustatus')),
|
||||
shangjiaCertified: isRoleStatusActive(wx.getStorageSync('shangjiastatus')),
|
||||
});
|
||||
},
|
||||
|
||||
updateOrderCounts() {
|
||||
const c = app.globalData.dingdanTiaoshu || {}
|
||||
this.setData({ orderCounts: {
|
||||
daifuwu: c.daifuwu||0, fuwuzhong: c.fuwuzhong||0,
|
||||
yiwancheng: c.yiwancheng||0, yituikuan: c.yituikuan||0
|
||||
}})
|
||||
},
|
||||
|
||||
goToSetting() { wx.navigateTo({ url: '/pages/edit/edit' }) },
|
||||
|
||||
handleWechatLogin() {
|
||||
wx.showLoading({ title: '登录中...', mask: true });
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
this.loadUserData();
|
||||
this.updateOrderCounts();
|
||||
wx.showToast({ title: '登录成功', icon: 'success' });
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => wx.hideLoading());
|
||||
},
|
||||
|
||||
goToOrder(e) { wx.navigateTo({ url: `/pages/orders/orders?type=${e.currentTarget.dataset.type}` }) },
|
||||
|
||||
goToAuth(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
if (!type || !['dashou', 'shangjia'].includes(type)) return;
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
this.loadUserData();
|
||||
const statusKey = type === 'dashou' ? 'dashoustatus' : 'shangjiastatus';
|
||||
if (isRoleStatusActive(wx.getStorageSync(statusKey))) {
|
||||
ensureRoleOnCenterPage(this, type);
|
||||
enterLockedRole(type, app);
|
||||
return;
|
||||
}
|
||||
wx.navigateTo({ url: `/pages/verify/verify?type=${type}` });
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
goToKefu() {
|
||||
const { link, enterpriseId } = app.globalData.kefuConfig || {}
|
||||
if (!link || !enterpriseId) { wx.showToast({ title: '客服配置未加载', icon: 'none' }); return }
|
||||
wx.openCustomerServiceChat({ extInfo: { url: link }, corpId: enterpriseId })
|
||||
},
|
||||
goToCustomService() { this.goToKefu() },
|
||||
goToGuanzhuA() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) },
|
||||
|
||||
clearCache() {
|
||||
wx.showModal({
|
||||
title: '清除缓存',
|
||||
content: '将清除所有登录与身份数据,并回到点单端,确定继续?',
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
success: r => {
|
||||
if (r.confirm) {
|
||||
clearCacheAndEnterNormal(this);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
// pages/mine/mine.js
|
||||
const app = getApp();
|
||||
import { ensureLogin } from '../../utils/login';
|
||||
import {
|
||||
backfillUserProfileCache,
|
||||
getUserProfileForDisplay,
|
||||
isRoleStatusActive,
|
||||
ensureRoleOnCenterPage,
|
||||
} from '../../utils/role-tab-bar';
|
||||
import { enterLockedRole } from '../../utils/primary-role.js';
|
||||
import { createPage } from '../../utils/base-page.js';
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
avatarUrl: '',
|
||||
userNicheng: '',
|
||||
userUid: '',
|
||||
showLoginBtn: false,
|
||||
orderCounts: { daifuwu:0, fuwuzhong:0, yiwancheng:0, yituikuan:0 },
|
||||
// 图标
|
||||
settingIcon: '', daifuwuIcon: '', fuwuzhongIcon: '', yiwanchengIcon: '', yituikuanIcon: '',
|
||||
dashouIcon: '', shangjiaIcon: '', guanshiIcon: '', kefuIcon: '',
|
||||
zuzhangIcon: '', guanzhualongIcon: '', arrowRightIcon: '', qingchuIcon: '',
|
||||
dashouCertified: false,
|
||||
shangjiaCertified: false,
|
||||
bottomSafePadding: 0
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.initIconUrls()
|
||||
this.loadUserData()
|
||||
this.setBottomSafe()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.initIconUrls();
|
||||
this.registerNotificationComponent();
|
||||
this.checkAvatarPrompt();
|
||||
backfillUserProfileCache(app);
|
||||
this.loadUserData();
|
||||
this.updateOrderCounts();
|
||||
},
|
||||
|
||||
setBottomSafe() {
|
||||
const sys = wx.getSystemInfoSync()
|
||||
const safeBottom = sys.screenHeight - sys.safeArea.bottom // 底部安全区高度(px)
|
||||
const tabBarHeight = (sys.windowWidth / 750) * 100 // 100rpx 转为 px
|
||||
this.setData({
|
||||
bottomSafePadding: safeBottom + tabBarHeight + 4 // 4px 微调,确保不留缝隙
|
||||
})
|
||||
},
|
||||
|
||||
checkAvatarPrompt() {
|
||||
const ds = wx.getStorageSync('dashoustatus')
|
||||
const tx = wx.getStorageSync('touxiang') || ''
|
||||
if (ds === 1 && (!tx || tx === 'a_long/morentouxiang.jpg')) {
|
||||
wx.showModal({
|
||||
title: '提示', content: '请先设置头像',
|
||||
confirmText: '去设置', confirmColor: '#C9A962',
|
||||
success: r => r.confirm && wx.navigateTo({ url: '/pages/edit/edit' })
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
initIconUrls() {
|
||||
const base = (app.globalData.ossImageUrl || '') + '/beijing/tubiao/'
|
||||
this.setData({
|
||||
settingIcon: base + 'grzx_shezhi.jpg',
|
||||
daifuwuIcon: base + 'grzx_daifuwu.jpg',
|
||||
fuwuzhongIcon: base + 'grzx_fuwuzhong.jpg',
|
||||
yiwanchengIcon: base + 'grzx_yiwancheng.jpg',
|
||||
yituikuanIcon: base + 'grzx_yituikuan.jpg',
|
||||
dashouIcon: base + 'grzx_dashou.jpg',
|
||||
shangjiaIcon: base + 'grzx_shangjia.jpg',
|
||||
guanshiIcon: base + 'grzx_guanshi.jpg',
|
||||
kefuIcon: base + 'grzx_kefu.jpg',
|
||||
zuzhangIcon: base + 'grzx_zuzhang.jpg',
|
||||
guanzhualongIcon: base + 'grzx_guanzhualong.jpg',
|
||||
arrowRightIcon: base + 'grzx_arrow_right.jpg',
|
||||
qingchuIcon: base + 'grzx_qingchu.jpg',
|
||||
kaoheguanIcon: base + 'kaoheguan.png',
|
||||
})
|
||||
},
|
||||
|
||||
loadUserData() {
|
||||
const profile = getUserProfileForDisplay(app);
|
||||
this.setData({
|
||||
avatarUrl: profile.avatarUrl,
|
||||
userNicheng: profile.nick,
|
||||
userUid: profile.uid,
|
||||
showLoginBtn: !profile.isLoggedIn,
|
||||
dashouCertified: isRoleStatusActive(wx.getStorageSync('dashoustatus')),
|
||||
shangjiaCertified: isRoleStatusActive(wx.getStorageSync('shangjiastatus')),
|
||||
});
|
||||
},
|
||||
|
||||
updateOrderCounts() {
|
||||
const c = app.globalData.dingdanTiaoshu || {}
|
||||
this.setData({ orderCounts: {
|
||||
daifuwu: c.daifuwu||0, fuwuzhong: c.fuwuzhong||0,
|
||||
yiwancheng: c.yiwancheng||0, yituikuan: c.yituikuan||0
|
||||
}})
|
||||
},
|
||||
|
||||
goToSetting() { wx.navigateTo({ url: '/pages/edit/edit' }) },
|
||||
|
||||
handleWechatLogin() {
|
||||
wx.showLoading({ title: '登录中...', mask: true });
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
this.loadUserData();
|
||||
this.updateOrderCounts();
|
||||
wx.showToast({ title: '登录成功', icon: 'success' });
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => wx.hideLoading());
|
||||
},
|
||||
|
||||
goToOrder(e) { wx.navigateTo({ url: `/pages/orders/orders?type=${e.currentTarget.dataset.type}` }) },
|
||||
|
||||
goToAuth(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
if (!type || !['dashou', 'shangjia'].includes(type)) return;
|
||||
ensureLogin({ silent: false, page: this })
|
||||
.then(() => {
|
||||
this.loadUserData();
|
||||
const statusKey = type === 'dashou' ? 'dashoustatus' : 'shangjiastatus';
|
||||
if (isRoleStatusActive(wx.getStorageSync(statusKey))) {
|
||||
ensureRoleOnCenterPage(this, type);
|
||||
enterLockedRole(type, app);
|
||||
return;
|
||||
}
|
||||
wx.navigateTo({ url: `/pages/verify/verify?type=${type}` });
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
goToCustomService() { this.goToKefu() },
|
||||
goToGuanzhuA() { wx.navigateTo({ url: '/pages/manager-assign/manager-assign' }) },
|
||||
}))
|
||||
|
||||
@@ -1,190 +1,213 @@
|
||||
/* pages/orders/orders.wxss */
|
||||
|
||||
.dingdan-page {
|
||||
background-color: #f8f9fa;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.dingdan-tabs-scroll {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.dingdan-tabs-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.dingdan-tab-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dingdan-tab-item:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* .dingdan-tab-item.tab-active 已由全局 .tab-capsule--active 覆盖 */
|
||||
|
||||
.tab-active-line {
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #4caf50;
|
||||
border-radius: 2rpx;
|
||||
margin-top: 6rpx;
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: scale(0.8); }
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.dingdan-list-container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
border: 6rpx solid #e0e0e0;
|
||||
border-top-color: #4caf50;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.empty-container {
|
||||
height: 500rpx;
|
||||
padding-top: 80rpx;
|
||||
}
|
||||
|
||||
.empty-image {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.dingdan-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.dingdan-card:active {
|
||||
transform: translateY(-2rpx);
|
||||
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.dingdan-card-left {
|
||||
flex-shrink: 0;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.dingdan-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.dingdan-card-center {
|
||||
flex: 1;
|
||||
height: 160rpx;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.dingdan-jieshao {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.dingdan-card-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
height: 160rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
/* 价格样式 */
|
||||
.dingdan-jine {
|
||||
display: flex;
|
||||
align-items: center; /* 垂直居中 */
|
||||
}
|
||||
|
||||
.jine-symbol {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
margin-right: 4rpx; /* 添加右边距,让符号和数字有间隔 */
|
||||
}
|
||||
|
||||
.jine-number {
|
||||
font-size: 32rpx; /* 整数和小数一样大 */
|
||||
color: #333333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.load-more-line {
|
||||
width: 80rpx;
|
||||
height: 1rpx;
|
||||
background-color: #e0e0e0;
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 375px) {
|
||||
.dingdan-image {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.dingdan-card-center {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.dingdan-card-right {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.jine-number {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
/* pages/orders/orders.wxss */
|
||||
|
||||
.dingdan-page {
|
||||
background: #f2f2f2;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* TAB栏 */
|
||||
.dingdan-tabs-scroll {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
white-space: nowrap;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.dingdan-tabs-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.dingdan-tab-item {
|
||||
position: relative;
|
||||
padding: 0 28rpx;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.dingdan-tab-item.tab-active .tab-text {
|
||||
color: #e02e24;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.tab-active-line {
|
||||
width: 40rpx;
|
||||
height: 6rpx;
|
||||
background: #e02e24;
|
||||
border-radius: 3rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 列表区 */
|
||||
.dingdan-list-container {
|
||||
padding: 20rpx 24rpx;
|
||||
}
|
||||
|
||||
/* 加载 */
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border: 4rpx solid #f0f0f0;
|
||||
border-top-color: #e02e24;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 500rpx;
|
||||
}
|
||||
|
||||
.empty-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
opacity: 0.5;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.empty-subtext {
|
||||
font-size: 24rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
/* 订单卡片 */
|
||||
.dingdan-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.dingdan-card-left {
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.dingdan-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.dingdan-card-center {
|
||||
flex: 1;
|
||||
height: 160rpx;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.dingdan-jieshao {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #333;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dingdan-card-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
height: 160rpx;
|
||||
margin-left: 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dingdan-zhuangtai {
|
||||
font-size: 24rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dingdan-jine {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.jine-symbol {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.jine-number {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 加载更多 */
|
||||
.load-more-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx 0;
|
||||
}
|
||||
|
||||
.load-more-line {
|
||||
width: 80rpx;
|
||||
height: 1rpx;
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
|
||||
.no-more-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx 0;
|
||||
}
|
||||
|
||||
.no-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
@@ -62,9 +62,9 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="modal-foot">
|
||||
<view wx:if="{{ detailItem.zhuangtai === 1 && !detailItem.bohuiliyou }}" class="btn primary" bindtap="openShensu">申诉</view>
|
||||
<view wx:if="{{ detailItem.zhuangtai === 1 || detailItem.zhuangtai === 3 }}" class="btn primary" bindtap="startPay">立即缴纳</view>
|
||||
<view class="btn default" bindtap="closeDetail">关闭</view>
|
||||
<view wx:if="{{ detailItem.zhuangtai === 1 && !detailItem.bohuiliyou }}" class="pbtn primary" bindtap="openShensu">申诉</view>
|
||||
<view wx:if="{{ detailItem.zhuangtai === 1 || detailItem.zhuangtai === 3 }}" class="pbtn primary" bindtap="startPay">立即缴纳</view>
|
||||
<view class="pbtn default" bindtap="closeDetail">关闭</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -100,8 +100,8 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="modal-foot">
|
||||
<view class="btn default" bindtap="closeShensu">取消</view>
|
||||
<view class="btn primary" bindtap="submitShensu">提交申诉</view>
|
||||
<view class="pbtn default" bindtap="closeShensu">取消</view>
|
||||
<view class="pbtn primary" bindtap="submitShensu">提交申诉</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -50,10 +50,10 @@ page { background: #f5f5f5; }
|
||||
.progress-text { font-size: 22rpx; color: #2e7d32; text-align: right; margin-top: 4rpx; }
|
||||
|
||||
.modal-foot { width: 100%; box-sizing: border-box; display: flex; padding: 16rpx 30rpx 30rpx; gap: 20rpx; border-top: 1px solid #eee; }
|
||||
.btn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.pbtn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.primary { background: #2e7d32; color: #fff; }
|
||||
.default { background: #f0f0f0; color: #555; }
|
||||
.btn:active { opacity: 0.8; }
|
||||
.pbtn:active { opacity: 0.8; }
|
||||
|
||||
|
||||
/* ===== 获取更多按钮 ===== */
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
<text class="confirm-tip">确认后将从您的佣金/分红中扣除</text>
|
||||
</view>
|
||||
<view class="pay-foot">
|
||||
<view class="btn default" bindtap="backToMethod">取消</view>
|
||||
<view class="btn primary" bindtap="confirmBalance">确认</view>
|
||||
<view class="pbtn default" bindtap="backToMethod">取消</view>
|
||||
<view class="pbtn primary" bindtap="confirmBalance">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
.loading-text { color: #fff; font-size: 26rpx; }
|
||||
|
||||
.btn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.pbtn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.primary { background: #2e7d32; color: #fff; }
|
||||
.default { background: #f0f0f0; color: #555; }
|
||||
.btn:active { opacity: 0.8; }
|
||||
.pbtn:active { opacity: 0.8; }
|
||||
@@ -60,8 +60,8 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="modal-foot">
|
||||
<view wx:if="{{ xuanzhongChufa.sqzhuangtai === 0 }}" class="btn primary" bindtap="openShensuModal">申诉</view>
|
||||
<view class="btn default" bindtap="guanbiXiangqing">关闭</view>
|
||||
<view wx:if="{{ xuanzhongChufa.sqzhuangtai === 0 }}" class="pbtn primary" bindtap="openShensuModal">申诉</view>
|
||||
<view class="pbtn default" bindtap="guanbiXiangqing">关闭</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -97,8 +97,8 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="modal-foot">
|
||||
<view class="btn default" bindtap="closeShensuModal">取消</view>
|
||||
<view class="btn primary" bindtap="submitShensu">提交申诉</view>
|
||||
<view class="pbtn default" bindtap="closeShensuModal">取消</view>
|
||||
<view class="pbtn primary" bindtap="submitShensu">提交申诉</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -59,10 +59,10 @@ page { background: #f5f5f5; }
|
||||
|
||||
/* 🔥 底部按钮区左右 padding 严格均等 */
|
||||
.modal-foot { width: 100%; box-sizing: border-box; display: flex; padding: 16rpx 30rpx 30rpx; gap: 20rpx; border-top: 1px solid #eee; }
|
||||
.btn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.pbtn { flex: 1; text-align: center; padding: 22rpx 0; border-radius: 16rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.primary { background: #2e7d32; color: #fff; }
|
||||
.default { background: #f0f0f0; color: #555; }
|
||||
.btn:active { opacity: 0.8; }
|
||||
.pbtn:active { opacity: 0.8; }
|
||||
|
||||
|
||||
/* ===== 获取更多按钮 ===== */
|
||||
|
||||
@@ -25,38 +25,38 @@
|
||||
|
||||
<!-- 按钮区域(第一行:保存/刷新/生成海报) -->
|
||||
<view class="button-section">
|
||||
<view class="btn-group">
|
||||
<view class="btn save-btn" bindtap="saveToAlbum" wx:if="{{qrcodeUrl}}">
|
||||
<text class="btn-icon">📥</text>
|
||||
<text class="btn-text">保存二维码</text>
|
||||
<view class="pbtn-group">
|
||||
<view class="pbtn pbtn-save" bindtap="saveToAlbum" wx:if="{{qrcodeUrl}}">
|
||||
<text class="pbtn-icon">📥</text>
|
||||
<text class="pbtn-text">保存二维码</text>
|
||||
</view>
|
||||
<view class="btn refresh-btn" bindtap="refreshQRCode" wx:if="{{!isLoading}}">
|
||||
<text class="btn-icon">⟳</text>
|
||||
<text class="btn-text">{{qrcodeUrl ? '重新获取' : '获取二维码'}}</text>
|
||||
<view class="pbtn pbtn-refresh" bindtap="refreshQRCode" wx:if="{{!isLoading}}">
|
||||
<text class="pbtn-icon">⟳</text>
|
||||
<text class="pbtn-text">{{qrcodeUrl ? '重新获取' : '获取二维码'}}</text>
|
||||
</view>
|
||||
<view class="btn loading-btn" wx:else>
|
||||
<view class="pbtn pbtn-loading" wx:else>
|
||||
<view class="loading-spinner-small"></view>
|
||||
<text class="btn-text">生成中...</text>
|
||||
<text class="pbtn-text">生成中...</text>
|
||||
</view>
|
||||
<!-- 🔥【新增】生成我的专属海报按钮 -->
|
||||
<view class="btn poster-btn" bindtap="generateMyPoster" wx:if="{{qrcodeUrl && !showPosterCanvas}}">
|
||||
<text class="btn-icon">🎨</text>
|
||||
<text class="btn-text">生成我的专属海报</text>
|
||||
<!-- 生成我的专属海报按钮 -->
|
||||
<view class="pbtn pbtn-poster" bindtap="generateMyPoster" wx:if="{{qrcodeUrl && !showPosterCanvas}}">
|
||||
<text class="pbtn-icon">🎨</text>
|
||||
<text class="pbtn-text">生成我的专属海报</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 🔥【新增】专属海报展示区(当 showPosterCanvas 为 true 时显示) -->
|
||||
<!-- 专属海报展示区(当 showPosterCanvas 为 true 时显示) -->
|
||||
<view class="poster-section" wx:if="{{showPosterCanvas}}">
|
||||
<canvas canvas-id="posterCanvas" class="poster-canvas"></canvas>
|
||||
<view class="poster-actions">
|
||||
<view class="btn save-poster-btn" bindtap="savePoster">
|
||||
<text class="btn-icon">📥</text>
|
||||
<text class="btn-text">保存海报</text>
|
||||
<view class="pbtn pbtn-save-poster" bindtap="savePoster">
|
||||
<text class="pbtn-icon">📥</text>
|
||||
<text class="pbtn-text">保存海报</text>
|
||||
</view>
|
||||
<view class="btn back-btn" bindtap="hidePoster">
|
||||
<text class="btn-icon">↩️</text>
|
||||
<text class="btn-text">返回</text>
|
||||
<view class="pbtn pbtn-back" bindtap="hidePoster">
|
||||
<text class="pbtn-icon">↩️</text>
|
||||
<text class="pbtn-text">返回</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -68,4 +68,4 @@
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,269 +1,237 @@
|
||||
/* 机甲风格推广海报页面(含新增专属海报样式) */
|
||||
/* 推广海报页面 */
|
||||
|
||||
page {
|
||||
background: #0a0e17;
|
||||
min-height: 100vh;
|
||||
font-family: 'Avenir', 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 背景网格 */
|
||||
.grid-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
linear-gradient(rgba(0, 160, 255, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0, 160, 255, 0.05) 1px, transparent 1px);
|
||||
background-size: 50rpx 50rpx;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
min-height: 100vh;
|
||||
padding: 30rpx 25rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 机械装饰线条 */
|
||||
.mech-line {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
.line-h {
|
||||
top: 200rpx;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2rpx;
|
||||
background: linear-gradient(90deg, transparent, #00a6ff, transparent);
|
||||
}
|
||||
.line-v {
|
||||
right: 50rpx;
|
||||
top: 100rpx;
|
||||
width: 2rpx;
|
||||
height: 300rpx;
|
||||
background: linear-gradient(180deg, transparent, #00a6ff, transparent);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
/* 标题区域 */
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.title {
|
||||
font-size: 44rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 30rpx #00a6ff;
|
||||
letter-spacing: 2rpx;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 28rpx;
|
||||
color: #9cf;
|
||||
opacity: 0.9;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 二维码区域(方形,无斜切) */
|
||||
.qrcode-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.qrcode-wrapper {
|
||||
position: relative;
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
background: rgba(0, 20, 40, 0.8);
|
||||
border: 4rpx solid #00a6ff;
|
||||
/* 移除 clip-path,保持方形 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 80rpx rgba(0, 166, 255, 0.4);
|
||||
animation: qrcodePulse 2s infinite alternate;
|
||||
}
|
||||
.qrcode-img {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.qrcode-glow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: radial-gradient(circle at 30% 30%, rgba(0, 166, 255, 0.2), transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.empty-qrcode {
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
background: rgba(0, 20, 40, 0.8);
|
||||
border: 4rpx dashed #00a6ff;
|
||||
/* 方形 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
color: #00a6ff;
|
||||
margin-bottom: 20rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.empty-text {
|
||||
font-size: 26rpx;
|
||||
color: #9cf;
|
||||
text-align: center;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
/* 按钮区域(机甲斜切风格) */
|
||||
.button-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.btn {
|
||||
width: 220rpx;
|
||||
height: 80rpx;
|
||||
background: rgba(0, 30, 60, 0.8);
|
||||
border: 2rpx solid #00a6ff;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
transition: 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn:active {
|
||||
transform: scale(0.96);
|
||||
box-shadow: 0 0 40rpx #00a6ff;
|
||||
}
|
||||
.save-btn {
|
||||
border-color: #00a6ff;
|
||||
}
|
||||
.refresh-btn {
|
||||
border-color: #ffaa00;
|
||||
}
|
||||
.refresh-btn .btn-icon {
|
||||
color: #ffaa00;
|
||||
}
|
||||
/* 🔥【新增】生成海报按钮样式 */
|
||||
.poster-btn {
|
||||
border-color: #ffaa00;
|
||||
}
|
||||
.poster-btn .btn-icon {
|
||||
color: #ffaa00;
|
||||
}
|
||||
.loading-btn {
|
||||
opacity: 0.7;
|
||||
pointer-events: none;
|
||||
}
|
||||
.btn-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
}
|
||||
.loading-spinner-small {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
border: 4rpx solid rgba(255,255,255,0.2);
|
||||
border-top: 4rpx solid #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
/* 🔥【新增】专属海报展示区 */
|
||||
.poster-section {
|
||||
margin-top: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.poster-canvas {
|
||||
width: 600rpx;
|
||||
height: 900rpx;
|
||||
background: #1a1f2e; /* 占位色 */
|
||||
border: 4rpx solid #00a6ff;
|
||||
box-shadow: 0 0 60rpx #00a6ff;
|
||||
/* 保持方形,无斜切 */
|
||||
}
|
||||
.poster-actions {
|
||||
display: flex;
|
||||
gap: 30rpx;
|
||||
margin-top: 30rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
.save-poster-btn {
|
||||
background: linear-gradient(45deg, #0066cc, #00a6ff);
|
||||
border-color: #00a6ff;
|
||||
}
|
||||
.back-btn {
|
||||
background: rgba(0, 30, 60, 0.8);
|
||||
border-color: #00a6ff;
|
||||
}
|
||||
|
||||
/* 使用说明(保留) */
|
||||
.instruction {
|
||||
margin-top: 30rpx;
|
||||
padding: 20rpx 40rpx;
|
||||
background: rgba(0, 30, 50, 0.5);
|
||||
border-left: 4rpx solid #00a6ff;
|
||||
clip-path: polygon(0 0, 100% 0, 98% 100%, 0 100%);
|
||||
}
|
||||
.instruction-text {
|
||||
font-size: 24rpx;
|
||||
color: #9cf;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
@keyframes qrcodePulse {
|
||||
0% { box-shadow: 0 0 40rpx rgba(0, 166, 255, 0.3); }
|
||||
100% { box-shadow: 0 0 100rpx rgba(0, 166, 255, 0.6); }
|
||||
}
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
background: #0a0e17;
|
||||
min-height: 100vh;
|
||||
font-family: 'Avenir', 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 背景网格 */
|
||||
.grid-bg {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background-image:
|
||||
linear-gradient(rgba(0, 160, 255, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0, 160, 255, 0.05) 1px, transparent 1px);
|
||||
background-size: 50rpx 50rpx;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
min-height: 100vh;
|
||||
padding: 30rpx 25rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 机械装饰线条 */
|
||||
.mech-line {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
.line-h {
|
||||
top: 200rpx; left: 0;
|
||||
width: 100%; height: 2rpx;
|
||||
background: linear-gradient(90deg, transparent, #00a6ff, transparent);
|
||||
}
|
||||
.line-v {
|
||||
right: 50rpx; top: 100rpx;
|
||||
width: 2rpx; height: 300rpx;
|
||||
background: linear-gradient(180deg, transparent, #00a6ff, transparent);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
/* 标题区域 */
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.title {
|
||||
font-size: 44rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 30rpx #00a6ff;
|
||||
letter-spacing: 2rpx;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 28rpx;
|
||||
color: #9cf;
|
||||
opacity: 0.9;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 二维码区域 */
|
||||
.qrcode-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.qrcode-wrapper {
|
||||
position: relative;
|
||||
width: 400rpx; height: 400rpx;
|
||||
background: rgba(0, 20, 40, 0.8);
|
||||
border: 4rpx solid #00a6ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 80rpx rgba(0, 166, 255, 0.4);
|
||||
animation: qrcodePulse 2s infinite alternate;
|
||||
}
|
||||
.qrcode-img {
|
||||
width: 90%; height: 90%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.qrcode-glow {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background: radial-gradient(circle at 30% 30%, rgba(0, 166, 255, 0.2), transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.empty-qrcode {
|
||||
width: 400rpx; height: 400rpx;
|
||||
background: rgba(0, 20, 40, 0.8);
|
||||
border: 4rpx dashed #00a6ff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
color: #00a6ff;
|
||||
margin-bottom: 20rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.empty-text {
|
||||
font-size: 26rpx;
|
||||
color: #9cf;
|
||||
text-align: center;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
/* 按钮区域 */
|
||||
.button-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.pbtn-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.pbtn {
|
||||
width: 220rpx;
|
||||
height: 80rpx;
|
||||
background: rgba(0, 30, 60, 0.8);
|
||||
border: 2rpx solid #00a6ff;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.pbtn:active {
|
||||
transform: scale(0.96);
|
||||
box-shadow: 0 0 40rpx #00a6ff;
|
||||
}
|
||||
.pbtn-save { border-color: #00a6ff; }
|
||||
.pbtn-refresh { border-color: #ffaa00; }
|
||||
.pbtn-refresh .pbtn-icon { color: #ffaa00; }
|
||||
.pbtn-poster { border-color: #ffaa00; }
|
||||
.pbtn-poster .pbtn-icon { color: #ffaa00; }
|
||||
.pbtn-loading {
|
||||
opacity: 0.7;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pbtn-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.pbtn-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
}
|
||||
.loading-spinner-small {
|
||||
width: 30rpx; height: 30rpx;
|
||||
border: 4rpx solid rgba(255,255,255,0.2);
|
||||
border-top: 4rpx solid #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
/* 专属海报展示区 */
|
||||
.poster-section {
|
||||
margin-top: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.poster-canvas {
|
||||
width: 600rpx; height: 900rpx;
|
||||
background: #1a1f2e;
|
||||
border: 4rpx solid #00a6ff;
|
||||
box-shadow: 0 0 60rpx #00a6ff;
|
||||
}
|
||||
.poster-actions {
|
||||
display: flex;
|
||||
gap: 30rpx;
|
||||
margin-top: 30rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
.pbtn-save-poster {
|
||||
background: linear-gradient(45deg, #0066cc, #00a6ff);
|
||||
border-color: #00a6ff;
|
||||
}
|
||||
.pbtn-back {
|
||||
background: rgba(0, 30, 60, 0.8);
|
||||
border-color: #00a6ff;
|
||||
}
|
||||
|
||||
/* 使用说明 */
|
||||
.instruction {
|
||||
margin-top: 30rpx;
|
||||
padding: 20rpx 40rpx;
|
||||
background: rgba(0, 30, 50, 0.5);
|
||||
border-left: 4rpx solid #00a6ff;
|
||||
clip-path: polygon(0 0, 100% 0, 98% 100%, 0 100%);
|
||||
}
|
||||
.instruction-text {
|
||||
font-size: 24rpx;
|
||||
color: #9cf;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
@keyframes qrcodePulse {
|
||||
0% { box-shadow: 0 0 40rpx rgba(0, 166, 255, 0.3); }
|
||||
100% { box-shadow: 0 0 100rpx rgba(0, 166, 255, 0.6); }
|
||||
}
|
||||
|
||||
@@ -140,8 +140,7 @@ Page({
|
||||
that.handleLoadError(res.data?.msg || '加载失败')
|
||||
}
|
||||
},
|
||||
fail(error) {
|
||||
console.error('商品详情加载失败:', error)
|
||||
fail() {
|
||||
that.handleLoadError('网络错误,请重试')
|
||||
}
|
||||
})
|
||||
@@ -234,6 +233,10 @@ Page({
|
||||
this.loadShangpinDetail()
|
||||
},
|
||||
|
||||
goToKefu() {
|
||||
wx.navigateTo({ url: '/pages/cs-chat/cs-chat' })
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
const { shangpinData, shangpinId } = this.data
|
||||
|
||||
|
||||
@@ -1,112 +1,123 @@
|
||||
<!--pages/product-detail/product-detail.wxml-->
|
||||
<view class="detail-page page-container">
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading-container loading-mask loading-mask--light" 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 class="error-container empty-state" wx:if="{{!isLoading && loadError}}">
|
||||
<image src="/images/error.png" class="error-icon" />
|
||||
<text class="error-text">加载失败</text>
|
||||
<button class="error-btn btn btn-sm btn-sm--green" bindtap="onRefresh">重新加载</button>
|
||||
</view>
|
||||
|
||||
<!-- 商品详情内容 -->
|
||||
<view class="detail-content" wx:if="{{!isLoading && !loadError && shangpinData}}">
|
||||
<!-- 商品图片区域(占满屏幕) -->
|
||||
<view class="image-section">
|
||||
<view class="image-container" bindtap="previewImage">
|
||||
<image
|
||||
src="{{shangpinData.tupian}}"
|
||||
mode="aspectFill"
|
||||
class="product-image"
|
||||
/>
|
||||
<!-- 库存标签 -->
|
||||
<view class="kucun-tag {{shangpinData.kucunClass || 'kucun-normal'}}">
|
||||
<text class="kucun-text">{{shangpinData.kucunText || '库存充足'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 下方内容区域(顶部有圆角) -->
|
||||
<view class="content-area">
|
||||
<!-- 商品标题和价格区域 -->
|
||||
<view class="title-price-section">
|
||||
<view class="title-row">
|
||||
<text class="product-title">{{shangpinData.biaoti || ''}}</text>
|
||||
</view>
|
||||
|
||||
<view class="price-row">
|
||||
<!-- 价格 -->
|
||||
<view class="price-section">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{shangpinData.priceInteger || '0'}}</text>
|
||||
<text class="price-decimal">.{{shangpinData.priceDecimal || '00'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 销量 -->
|
||||
<view class="sales-section">
|
||||
<image src="/images/xiaoliang.png" class="sales-icon" />
|
||||
<text class="sales-text">{{shangpinData.xiaoliangText || '0'}}次购买</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品介绍区域 -->
|
||||
<view class="info-section" wx:if="{{shangpinData.xiangqing}}">
|
||||
<view class="section-header">
|
||||
<image src="/images/jieshao.png" class="section-icon" />
|
||||
<text class="section-title">商品介绍:</text>
|
||||
</view>
|
||||
<view class="section-content">
|
||||
<text class="content-text">{{shangpinData.xiangqing}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买须知区域 -->
|
||||
<view class="info-section" wx:if="{{shangpinData.xiadanxuzhi}}">
|
||||
<view class="section-header">
|
||||
<image src="/images/jieshao.png" class="section-icon" />
|
||||
<text class="section-title">购买须知:</text>
|
||||
</view>
|
||||
<view class="section-content">
|
||||
<text class="content-text">{{shangpinData.xiadanxuzhi}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 规则图片区域(只有有图片时才显示) -->
|
||||
<view class="rule-section" wx:if="{{shangpinData.guize}}">
|
||||
<image
|
||||
src="{{shangpinData.guize}}"
|
||||
mode="widthFix"
|
||||
class="rule-image"
|
||||
binderror="onImageError"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 占位区域(给底部按钮留空间) -->
|
||||
<view class="placeholder"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 立即下单按钮(固定在底部,无价格标签) -->
|
||||
<view class="order-btn-container fixed-bottom" wx:if="{{!isLoading && !loadError && shangpinData}}">
|
||||
<view class="order-btn btn btn-primary btn-primary--green" bindtap="onOrderClick">
|
||||
<!-- 按钮发光特效 -->
|
||||
<view class="btn-glow"></view>
|
||||
<!-- 按钮流光特效 -->
|
||||
<view class="btn-streamer"></view>
|
||||
<!-- 按钮文字 -->
|
||||
<text class="btn-text">立即预约</text>
|
||||
</view>
|
||||
</view>
|
||||
<global-notification id="global-notification" />
|
||||
|
||||
</view>
|
||||
<!--pages/product-detail/product-detail.wxml-->
|
||||
<view class="page">
|
||||
<!-- 加载 -->
|
||||
<view class="loading-box" wx:if="{{isLoading}}">
|
||||
<view class="spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 错误 -->
|
||||
<view class="error-box" wx:if="{{!isLoading && loadError}}">
|
||||
<text class="error-text">加载失败</text>
|
||||
<view class="error-btn" bindtap="onRefresh">重新加载</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品详情 -->
|
||||
<block wx:if="{{!isLoading && !loadError && shangpinData}}">
|
||||
<!-- 商品大图 -->
|
||||
<view class="hero" bindtap="previewImage">
|
||||
<image src="{{shangpinData.tupian}}" mode="aspectFill" class="hero-img" />
|
||||
<!-- 图片角标 -->
|
||||
<view class="hero-badge">
|
||||
<text class="hero-badge-text">{{shangpinData.kucun <= 0 ? '已售罄' : '现货'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 价格区 - 红底渐变 -->
|
||||
<view class="price-block">
|
||||
<view class="price-left">
|
||||
<text class="price-sym">¥</text>
|
||||
<text class="price-int">{{shangpinData.priceInteger || '0'}}</text>
|
||||
<text class="price-dec">.{{shangpinData.priceDecimal || '00'}}</text>
|
||||
</view>
|
||||
<view class="price-right">
|
||||
<text class="sold-text">已拼{{shangpinData.xiaoliangText || '0'}}件</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题区 -->
|
||||
<view class="title-block">
|
||||
<view class="title-tags">
|
||||
<text class="tag-hot">热卖</text>
|
||||
</view>
|
||||
<text class="title-text">{{shangpinData.biaoti || ''}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 服务保障条 -->
|
||||
<view class="service-strip">
|
||||
<view class="service-item">
|
||||
<text class="service-check">✓</text>
|
||||
<text class="service-label">极速接单</text>
|
||||
</view>
|
||||
<view class="service-item">
|
||||
<text class="service-check">✓</text>
|
||||
<text class="service-label">资金担保</text>
|
||||
</view>
|
||||
<view class="service-item">
|
||||
<text class="service-check">✓</text>
|
||||
<text class="service-label">售后保障</text>
|
||||
</view>
|
||||
<view class="service-item">
|
||||
<text class="service-check">✓</text>
|
||||
<text class="service-label">隐私保护</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 选择SKU入口 -->
|
||||
<view class="sku-trigger" bindtap="onOrderClick">
|
||||
<view class="sku-trigger-left">
|
||||
<text class="sku-label">选择</text>
|
||||
<text class="sku-value">服务规格、购买数量</text>
|
||||
</view>
|
||||
<text class="sku-arrow">></text>
|
||||
</view>
|
||||
|
||||
<!-- 商品介绍 -->
|
||||
<view class="detail-card" wx:if="{{shangpinData.xiangqing}}">
|
||||
<view class="detail-card-head">
|
||||
<text class="detail-card-title">商品介绍</text>
|
||||
</view>
|
||||
<text class="detail-card-body">{{shangpinData.xiangqing}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 购买须知 -->
|
||||
<view class="detail-card" wx:if="{{shangpinData.xiadanxuzhi}}">
|
||||
<view class="detail-card-head">
|
||||
<text class="detail-card-title">购买须知</text>
|
||||
</view>
|
||||
<text class="detail-card-body">{{shangpinData.xiadanxuzhi}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 规则图片 -->
|
||||
<view class="detail-card" wx:if="{{shangpinData.guize}}">
|
||||
<view class="detail-card-head">
|
||||
<text class="detail-card-title">服务规则</text>
|
||||
</view>
|
||||
<image src="{{shangpinData.guize}}" mode="widthFix" class="rule-img" binderror="onImageError" />
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
</block>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar" wx:if="{{!isLoading && !loadError && shangpinData}}">
|
||||
<view class="bottom-bar-inner">
|
||||
<!-- 客服 -->
|
||||
<view class="bar-icon-btn" bindtap="goToKefu">
|
||||
<text class="bar-icon-text">客服</text>
|
||||
</view>
|
||||
<!-- 单独购买 -->
|
||||
<view
|
||||
class="bar-buy-btn {{shangpinData.kucun <= 0 ? 'bar-buy-btn--disabled' : ''}}"
|
||||
bindtap="onOrderClick"
|
||||
hover-class="bar-buy-btn--hover"
|
||||
>
|
||||
<text class="bar-buy-text">{{shangpinData.kucun <= 0 ? '已售罄' : '立即下单'}}</text>
|
||||
<text class="bar-buy-price">¥{{shangpinData.priceInteger || '0'}}.{{shangpinData.priceDecimal || '00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
</view>
|
||||
|
||||
@@ -1,349 +1,347 @@
|
||||
/* pages/product-detail/product-detail.wxss */
|
||||
.detail-page {
|
||||
width: 100%;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-container {
|
||||
position: absolute;
|
||||
background: #f5f5f5;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
position: relative;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.spinner-ring {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 4rpx solid rgba(82, 196, 26, 0.2);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.spinner-dot {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background: #52c41a;
|
||||
border-radius: 50%;
|
||||
transform: translateX(-50%);
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 错误状态 */
|
||||
.error-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #f5f5f5;
|
||||
z-index: 100;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
opacity: 0.3;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.error-btn {
|
||||
font-weight: 500;
|
||||
padding: 20rpx 50rpx;
|
||||
border-radius: 50rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.3);
|
||||
}
|
||||
|
||||
/* 商品详情内容 */
|
||||
.detail-content {
|
||||
padding-bottom: 140rpx; /* 给底部按钮留出空间 */
|
||||
}
|
||||
|
||||
/* 商品图片区域(占满屏幕) */
|
||||
.image-section {
|
||||
width: 100%;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
width: 100%;
|
||||
height: 750rpx; /* 正方形,占满屏幕宽度 */
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 库存标签 */
|
||||
.kucun-tag {
|
||||
position: absolute;
|
||||
bottom: 30rpx;
|
||||
right: 30rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 30rpx;
|
||||
backdrop-filter: blur(10rpx);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.kucun-normal {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.kucun-none {
|
||||
background: rgba(255, 77, 79, 0.8);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.kucun-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 下方内容区域(顶部有圆角,与图片重叠一部分) */
|
||||
.content-area {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
margin-top: -40rpx; /* 与图片重叠一部分,实现平滑过渡 */
|
||||
padding: 40rpx 30rpx 0;
|
||||
min-height: 400rpx;
|
||||
}
|
||||
|
||||
/* 标题和价格区域 */
|
||||
.title-price-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.title-row {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 38rpx;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
line-height: 1.5;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 价格和销量行 */
|
||||
.price-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 价格部分 */
|
||||
.price-section {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.price-icon {
|
||||
font-size: 34rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.price-integer {
|
||||
font-size: 58rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 700;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.price-decimal {
|
||||
font-size: 34rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 销量部分 */
|
||||
.sales-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sales-icon {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 12rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.sales-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 信息区域(商品介绍、购买须知) */
|
||||
.info-section {
|
||||
margin-bottom: 40rpx;
|
||||
padding-top: 30rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #52c41a; /* 绿色 */
|
||||
}
|
||||
|
||||
.section-content {
|
||||
line-height: 1.8;
|
||||
padding-left: 52rpx; /* 与图标对齐 */
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
white-space: pre-line;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
/* 规则图片区域 */
|
||||
.rule-section {
|
||||
margin: 40rpx 0;
|
||||
padding-top: 30rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.rule-image {
|
||||
width: 100%;
|
||||
border-radius: 16rpx;
|
||||
display: block;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 占位区域 */
|
||||
.placeholder {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
/* 立即下单按钮容器(固定底部) */
|
||||
.order-btn-container {
|
||||
background: linear-gradient(transparent, rgba(255, 255, 255, 0.9) 70%);
|
||||
}
|
||||
|
||||
/* 立即下单按钮 */
|
||||
.order-btn {
|
||||
border-radius: 50rpx;
|
||||
height: 100rpx;
|
||||
box-shadow:
|
||||
0 12rpx 36rpx rgba(82, 196, 26, 0.4),
|
||||
0 4rpx 12rpx rgba(82, 196, 26, 0.3);
|
||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.order-btn:active {
|
||||
box-shadow:
|
||||
0 6rpx 24rpx rgba(82, 196, 26, 0.5),
|
||||
0 2rpx 8rpx rgba(82, 196, 26, 0.4);
|
||||
}
|
||||
|
||||
/* 按钮发光特效 */
|
||||
.btn-glow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
animation: glowPulse 2s infinite;
|
||||
}
|
||||
|
||||
/* 按钮流光特效 */
|
||||
.btn-streamer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100rpx;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
|
||||
transform: translateX(-100%);
|
||||
animation: streamerFlow 3s infinite;
|
||||
}
|
||||
|
||||
/* 按钮文字 */
|
||||
.btn-text {
|
||||
font-size: 36rpx;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2rpx;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 动画定义 */
|
||||
@keyframes glowPulse {
|
||||
0%, 100% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes streamerFlow {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
/* pages/product-detail/product-detail.wxss */
|
||||
|
||||
page {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 140rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 加载 */
|
||||
.loading-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border: 4rpx solid #f0f0f0;
|
||||
border-top-color: #e02e24;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 错误 */
|
||||
.error-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.error-btn {
|
||||
padding: 16rpx 48rpx;
|
||||
background: #e02e24;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 40rpx;
|
||||
}
|
||||
|
||||
/* 商品大图 */
|
||||
.hero {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 750rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.hero-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
left: 24rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 6rpx;
|
||||
background: rgba(224, 46, 36, 0.85);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.hero-badge-text {
|
||||
font-size: 20rpx;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* 价格区 - 拼多多红底 */
|
||||
.price-block {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 28rpx;
|
||||
background: linear-gradient(135deg, #e02e24, #f05545);
|
||||
}
|
||||
|
||||
.price-left {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.price-sym {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.price-int {
|
||||
font-size: 60rpx;
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
margin-left: 2rpx;
|
||||
}
|
||||
|
||||
.price-dec {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.price-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sold-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
/* 标题区 */
|
||||
.title-block {
|
||||
background: #fff;
|
||||
padding: 24rpx 28rpx 20rpx;
|
||||
}
|
||||
|
||||
.title-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.tag-hot {
|
||||
font-size: 20rpx;
|
||||
color: #fff;
|
||||
background: #e02e24;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 4rpx;
|
||||
font-weight: 600;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
line-height: 1.6;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 服务保障条 */
|
||||
.service-strip {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
padding: 16rpx 28rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 24rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.service-check {
|
||||
font-size: 20rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 700;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.service-label {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 选择SKU入口 */
|
||||
.sku-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
padding: 24rpx 28rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.sku-trigger-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sku-label {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.sku-value {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sku-arrow {
|
||||
font-size: 28rpx;
|
||||
color: #ccc;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
/* 详情卡片 */
|
||||
.detail-card {
|
||||
background: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 28rpx;
|
||||
}
|
||||
|
||||
.detail-card-head {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.detail-card-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
position: relative;
|
||||
padding-left: 16rpx;
|
||||
}
|
||||
|
||||
.detail-card-title::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 4rpx;
|
||||
width: 6rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 3rpx;
|
||||
background: #e02e24;
|
||||
}
|
||||
|
||||
.detail-card-body {
|
||||
font-size: 26rpx;
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.rule-img {
|
||||
width: 100%;
|
||||
border-radius: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 底部留白 */
|
||||
.bottom-space {
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
background: #fff;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.bottom-bar-inner {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.bar-icon-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 28rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
|
||||
.bar-icon-text {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.bar-buy-btn {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #e02e24;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.bar-buy-btn--disabled {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.bar-buy-btn--hover {
|
||||
opacity: 0.9;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.bar-buy-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.bar-buy-price {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
@@ -1,547 +1,332 @@
|
||||
// pages/submit/submit.js
|
||||
const app = getApp()
|
||||
import request from '../../utils/request.js'
|
||||
// 引入弹窗服务(路径请根据项目实际调整)
|
||||
import PopupService from '../../services/popupService.js'
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 全局变量
|
||||
ossImageUrl: '',
|
||||
apiBaseUrl: '',
|
||||
|
||||
// 从商品详情页传入的数据
|
||||
shangpinData: null,
|
||||
shangpinId: '',
|
||||
|
||||
// 表单数据
|
||||
nicheng: '', // 游戏昵称/ID
|
||||
beizhu: '', // 备注信息
|
||||
zhiding: '', // 指定打手ID(新增)
|
||||
jine: 0, // 总金额
|
||||
|
||||
// 页面状态
|
||||
isSubmitting: false,
|
||||
canSubmit: false,
|
||||
isPaying: false,
|
||||
|
||||
// 支付相关
|
||||
orderId: '',
|
||||
payParams: null,
|
||||
checkCount: 0,
|
||||
maxCheckCount: 3
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 获取全局变量
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
apiBaseUrl: app.globalData.apiBaseUrl || ''
|
||||
})
|
||||
|
||||
// 设置页面标题
|
||||
wx.setNavigationBarTitle({
|
||||
title: '提交订单'
|
||||
})
|
||||
|
||||
// 解析传递的商品数据
|
||||
try {
|
||||
if (options.data) {
|
||||
const shangpinData = JSON.parse(decodeURIComponent(options.data))
|
||||
|
||||
// 处理图片URL(拼接完整路径)
|
||||
if (shangpinData.image && !shangpinData.image.startsWith('http')) {
|
||||
shangpinData.image = this.data.ossImageUrl + shangpinData.image
|
||||
}
|
||||
|
||||
// 处理价格显示
|
||||
if (shangpinData.price) {
|
||||
const price = parseFloat(shangpinData.price) || 0
|
||||
const priceInteger = Math.floor(price)
|
||||
let priceDecimal = '00'
|
||||
|
||||
const decimalPart = (price - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
|
||||
shangpinData.priceInteger = priceInteger
|
||||
shangpinData.priceDecimal = priceDecimal
|
||||
}
|
||||
|
||||
// 设置商品数据
|
||||
this.setData({
|
||||
shangpinData: shangpinData,
|
||||
shangpinId: shangpinData.id || '',
|
||||
jine: parseFloat(shangpinData.price) || 0,
|
||||
})
|
||||
} else {
|
||||
this.handleDataError('商品数据不完整')
|
||||
}
|
||||
} catch (error) {
|
||||
this.handleDataError('解析商品数据失败')
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 原有代码:注册通知组件
|
||||
this.registerNotificationComponent();
|
||||
|
||||
// 🆕 进入页面时触发弹窗检查(PopupService 会自动判断是否展示)
|
||||
PopupService.checkAndShow(this, 'tijiao');
|
||||
},
|
||||
|
||||
// pages/submit/submit.js 中添加 onHide 方法(如果已有则合并内容)
|
||||
onHide() {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
if (popupComp && popupComp.cleanup) {
|
||||
popupComp.cleanup();
|
||||
}
|
||||
},
|
||||
|
||||
// 新增:注册通知组件
|
||||
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()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理数据错误
|
||||
*/
|
||||
handleDataError(errorMsg) {
|
||||
wx.showToast({
|
||||
title: errorMsg || '数据错误',
|
||||
icon: 'none'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
wx.navigateBack()
|
||||
}, 1500)
|
||||
},
|
||||
|
||||
/**
|
||||
* 游戏昵称输入事件
|
||||
*/
|
||||
onNicknameInput(e) {
|
||||
const value = e.detail.value.trim()
|
||||
this.setData({
|
||||
nicheng: value
|
||||
}, () => {
|
||||
this.checkFormValid()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 备注信息输入事件
|
||||
*/
|
||||
onRemarkInput(e) {
|
||||
const value = e.detail.value.trim()
|
||||
this.setData({
|
||||
beizhu: value
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定打手ID输入事件
|
||||
*/
|
||||
onZhidingInput(e) {
|
||||
const value = e.detail.value.trim()
|
||||
this.setData({
|
||||
zhiding: value
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查表单是否有效
|
||||
*/
|
||||
checkFormValid() {
|
||||
const { nicheng } = this.data
|
||||
|
||||
const isValid = nicheng && nicheng.length > 0 && nicheng.length <= 15
|
||||
|
||||
this.setData({
|
||||
canSubmit: isValid
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交订单
|
||||
*/
|
||||
onSubmitOrder() {
|
||||
const { nicheng, beizhu, zhiding, jine, shangpinId, canSubmit, isSubmitting } = this.data
|
||||
|
||||
// 验证表单
|
||||
if (!canSubmit) {
|
||||
wx.showToast({
|
||||
title: '请填写游戏昵称',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 防止重复提交
|
||||
if (isSubmitting) {
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
isSubmitting: true,
|
||||
isPaying: false
|
||||
})
|
||||
|
||||
// 显示loading(超时设为10秒)
|
||||
wx.showLoading({
|
||||
title: '创建订单中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
const timeoutTimer = setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '网络超时,请检查您是否已登录',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
}, 10000)
|
||||
|
||||
// 构建请求数据(添加zhiding字段)
|
||||
const orderData = {
|
||||
shangpin_id: shangpinId, // 商品ID
|
||||
nicheng: nicheng, // 游戏昵称
|
||||
beizhu: beizhu || '', // 备注(可为空)
|
||||
zhiding: zhiding || '', // 指定打手ID(可为空)
|
||||
jine: jine // 金额
|
||||
}
|
||||
|
||||
// 调用后端创建订单接口
|
||||
request({
|
||||
url: '/dingdan/xiadan',
|
||||
method: 'POST',
|
||||
data: orderData
|
||||
})
|
||||
.then(res => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const response = res.data
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
// 保存订单ID和支付参数
|
||||
const orderId = response.data.dingdanid
|
||||
const payParams = response.data.payParams || {}
|
||||
|
||||
this.setData({
|
||||
orderId: orderId,
|
||||
payParams: payParams,
|
||||
isSubmitting: false,
|
||||
isPaying: true,
|
||||
checkCount: 0
|
||||
})
|
||||
|
||||
// 调起微信支付
|
||||
this.triggerWxPayment(payParams)
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: response.msg || '创建订单失败',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '创建订单失败',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 调起微信支付
|
||||
*/
|
||||
triggerWxPayment(payParams) {
|
||||
// 验证支付参数是否完整
|
||||
if (!payParams || !payParams.timeStamp || !payParams.nonceStr ||
|
||||
!payParams.package || !payParams.signType || !payParams.paySign) {
|
||||
wx.showToast({
|
||||
title: '支付参数不完整',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType,
|
||||
paySign: payParams.paySign,
|
||||
|
||||
success: (res) => {
|
||||
// 支付成功,开始双重确认
|
||||
this.onPaymentSuccess()
|
||||
},
|
||||
|
||||
fail: (err) => {
|
||||
// 根据错误类型处理
|
||||
if (err.errMsg === 'requestPayment:fail cancel') {
|
||||
// 用户取消支付
|
||||
this.handleUserCancel()
|
||||
} else {
|
||||
// 其他支付错误
|
||||
this.handlePaymentFail(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理用户取消支付
|
||||
*/
|
||||
handleUserCancel() {
|
||||
const { orderId } = this.data
|
||||
|
||||
wx.showToast({
|
||||
title: '已取消支付',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 通知后端用户取消(静默请求,不阻塞用户)
|
||||
if (orderId) {
|
||||
request({
|
||||
url: '/dingdan/shibai',
|
||||
method: 'POST',
|
||||
data: {
|
||||
dingdanid: orderId,
|
||||
yuanyin: 'user_cancel'
|
||||
}
|
||||
}).catch(() => {
|
||||
// 静默失败
|
||||
})
|
||||
}
|
||||
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理支付失败
|
||||
*/
|
||||
handlePaymentFail(err) {
|
||||
const { orderId } = this.data
|
||||
|
||||
wx.showToast({
|
||||
title: '支付失败',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 通知后端支付失败(简化流程,直接请求,不显示loading)
|
||||
if (orderId) {
|
||||
request({
|
||||
url: '/dingdan/shibai',
|
||||
method: 'POST',
|
||||
data: {
|
||||
dingdanid: orderId,
|
||||
yuanyin: 'payment_fail',
|
||||
cuowu: err.errMsg || ''
|
||||
}
|
||||
}).catch(() => {
|
||||
// 静默失败
|
||||
}).finally(() => {
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 支付成功处理(双重确认)
|
||||
*/
|
||||
onPaymentSuccess() {
|
||||
const { orderId } = this.data
|
||||
|
||||
if (!orderId) {
|
||||
wx.showToast({
|
||||
title: '订单ID不存在',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 显示支付成功提示(时间缩短)
|
||||
wx.showToast({
|
||||
title: '支付成功,确认中...',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 开始双重确认流程
|
||||
this.checkOrderStatus()
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查订单状态(双重确认)
|
||||
*/
|
||||
checkOrderStatus() {
|
||||
const { orderId, checkCount, maxCheckCount } = this.data
|
||||
|
||||
// 显示加载(时间缩短)
|
||||
wx.showLoading({
|
||||
title: `确认支付状态${checkCount > 0 ? `(${checkCount + 1})` : ''}`,
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 超时设为5秒
|
||||
const timeoutTimer = setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
this.handleConfirmError('网络超时')
|
||||
}, 5000)
|
||||
|
||||
// 向后端发起支付复查请求
|
||||
request({
|
||||
url: '/dingdan/fucha',
|
||||
method: 'POST',
|
||||
data: {
|
||||
dingdanid: orderId
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const response = res.data
|
||||
|
||||
if (response.code === 0) {
|
||||
// 确认成功,订单状态已更新
|
||||
this.handleConfirmSuccess()
|
||||
} else {
|
||||
// 后端返回错误
|
||||
this.handleConfirmError(response.msg || '订单状态异常')
|
||||
}
|
||||
} else {
|
||||
// 网络错误
|
||||
this.handleConfirmError('网络错误')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
this.handleConfirmError('检查失败')
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理确认成功
|
||||
*/
|
||||
handleConfirmSuccess() {
|
||||
// 显示最终成功提示
|
||||
wx.showToast({
|
||||
title: '购买成功!',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 1.5秒后跳转到首页
|
||||
setTimeout(() => {
|
||||
wx.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1500)
|
||||
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理确认错误
|
||||
*/
|
||||
handleConfirmError(errorMsg) {
|
||||
const { checkCount, maxCheckCount } = this.data
|
||||
const newCheckCount = checkCount + 1
|
||||
|
||||
if (newCheckCount < maxCheckCount) {
|
||||
// 还可以重试
|
||||
this.setData({
|
||||
checkCount: newCheckCount
|
||||
})
|
||||
|
||||
// 1秒后重试
|
||||
setTimeout(() => {
|
||||
this.checkOrderStatus()
|
||||
}, 1000)
|
||||
} else {
|
||||
// 达到最大重试次数
|
||||
wx.showModal({
|
||||
title: '支付确认中',
|
||||
content: '支付已成功,但订单状态确认异常。请稍后在订单列表中查看状态,如有问题请联系客服。',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.setData({
|
||||
isSubmitting: false,
|
||||
isPaying: false
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
// pages/submit/submit.js
|
||||
const app = getApp()
|
||||
import request from '../../utils/request.js'
|
||||
import PopupService from '../../services/popupService.js'
|
||||
|
||||
Page({
|
||||
data: {
|
||||
ossImageUrl: '',
|
||||
apiBaseUrl: '',
|
||||
|
||||
shangpinData: null,
|
||||
shangpinId: '',
|
||||
|
||||
nicheng: '',
|
||||
beizhu: '',
|
||||
zhiding: '',
|
||||
quantity: 1,
|
||||
jine: 0,
|
||||
|
||||
totalPriceInteger: '0',
|
||||
totalPriceDecimal: '00',
|
||||
|
||||
isSubmitting: false,
|
||||
canSubmit: false,
|
||||
isPaying: false,
|
||||
|
||||
orderId: '',
|
||||
payParams: null,
|
||||
checkCount: 0,
|
||||
maxCheckCount: 3
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
ossImageUrl: app.globalData.ossImageUrl || '',
|
||||
apiBaseUrl: app.globalData.apiBaseUrl || ''
|
||||
})
|
||||
|
||||
wx.setNavigationBarTitle({ title: '提交订单' })
|
||||
|
||||
try {
|
||||
if (options.data) {
|
||||
const shangpinData = JSON.parse(decodeURIComponent(options.data))
|
||||
|
||||
if (shangpinData.image && !shangpinData.image.startsWith('http')) {
|
||||
shangpinData.image = this.data.ossImageUrl + shangpinData.image
|
||||
}
|
||||
|
||||
if (shangpinData.price) {
|
||||
const price = parseFloat(shangpinData.price) || 0
|
||||
const priceInteger = Math.floor(price)
|
||||
let priceDecimal = '00'
|
||||
const decimalPart = (price - priceInteger).toFixed(2)
|
||||
if (decimalPart > 0) {
|
||||
priceDecimal = decimalPart.toString().split('.')[1]
|
||||
}
|
||||
shangpinData.priceInteger = priceInteger
|
||||
shangpinData.priceDecimal = priceDecimal
|
||||
}
|
||||
|
||||
this.setData({
|
||||
shangpinData: shangpinData,
|
||||
shangpinId: shangpinData.id || '',
|
||||
jine: parseFloat(shangpinData.price) || 0,
|
||||
}, () => this.updateTotalPrice())
|
||||
} else {
|
||||
this.handleDataError('商品数据不完整')
|
||||
}
|
||||
} catch (error) {
|
||||
this.handleDataError('解析商品数据失败')
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent()
|
||||
PopupService.checkAndShow(this, 'tijiao')
|
||||
},
|
||||
|
||||
onHide() {
|
||||
const popupComp = this.selectComponent('#popupNotice')
|
||||
if (popupComp && popupComp.cleanup) popupComp.cleanup()
|
||||
},
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateTotalPrice() {
|
||||
const total = this.data.jine * this.data.quantity
|
||||
const intPart = Math.floor(total)
|
||||
const decPart = (total - intPart).toFixed(2).split('.')[1]
|
||||
this.setData({
|
||||
totalPriceInteger: intPart,
|
||||
totalPriceDecimal: decPart
|
||||
})
|
||||
},
|
||||
|
||||
onQtyMinus() {
|
||||
if (this.data.quantity <= 1) return
|
||||
this.setData({ quantity: this.data.quantity - 1 }, () => this.updateTotalPrice())
|
||||
},
|
||||
|
||||
onQtyPlus() {
|
||||
if (this.data.quantity >= 99) return
|
||||
this.setData({ quantity: this.data.quantity + 1 }, () => this.updateTotalPrice())
|
||||
},
|
||||
|
||||
handleDataError(errorMsg) {
|
||||
wx.showToast({ title: errorMsg || '数据错误', icon: 'none' })
|
||||
setTimeout(() => wx.navigateBack(), 1500)
|
||||
},
|
||||
|
||||
goBack() {
|
||||
wx.navigateBack()
|
||||
},
|
||||
|
||||
onNicknameInput(e) {
|
||||
this.setData({ nicheng: e.detail.value.trim() }, () => this.checkFormValid())
|
||||
},
|
||||
|
||||
onRemarkInput(e) {
|
||||
this.setData({ beizhu: e.detail.value.trim() })
|
||||
},
|
||||
|
||||
onZhidingInput(e) {
|
||||
this.setData({ zhiding: e.detail.value.trim() })
|
||||
},
|
||||
|
||||
checkFormValid() {
|
||||
const { nicheng } = this.data
|
||||
this.setData({ canSubmit: nicheng && nicheng.length > 0 && nicheng.length <= 15 })
|
||||
},
|
||||
|
||||
onSubmitOrder() {
|
||||
const { nicheng, beizhu, zhiding, jine, quantity, shangpinId, canSubmit, isSubmitting } = this.data
|
||||
|
||||
if (!canSubmit) {
|
||||
wx.showToast({ title: '请填写游戏昵称', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (isSubmitting) return
|
||||
|
||||
this.setData({ isSubmitting: true, isPaying: false })
|
||||
|
||||
wx.showLoading({ title: '创建订单中...', mask: true })
|
||||
|
||||
const timeoutTimer = setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: '网络超时,请检查您是否已登录', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
}, 10000)
|
||||
|
||||
const orderData = {
|
||||
shangpin_id: shangpinId,
|
||||
nicheng: nicheng,
|
||||
beizhu: beizhu || '',
|
||||
zhiding: zhiding || '',
|
||||
jine: jine * quantity,
|
||||
shuliang: quantity
|
||||
}
|
||||
|
||||
request({
|
||||
url: '/dingdan/xiadan',
|
||||
method: 'POST',
|
||||
data: orderData
|
||||
})
|
||||
.then(res => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
const response = res.data
|
||||
if (response.code === 0 && response.data) {
|
||||
const orderId = response.data.dingdanid
|
||||
const payParams = response.data.payParams || {}
|
||||
this.setData({
|
||||
orderId: orderId,
|
||||
payParams: payParams,
|
||||
isSubmitting: false,
|
||||
isPaying: true,
|
||||
checkCount: 0
|
||||
})
|
||||
this.triggerWxPayment(payParams)
|
||||
} else {
|
||||
wx.showToast({ title: response.msg || '创建订单失败', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
}
|
||||
} else {
|
||||
wx.showToast({ title: '网络错误,请重试', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: '创建订单失败', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
})
|
||||
},
|
||||
|
||||
triggerWxPayment(payParams) {
|
||||
if (!payParams || !payParams.timeStamp || !payParams.nonceStr ||
|
||||
!payParams.package || !payParams.signType || !payParams.paySign) {
|
||||
wx.showToast({ title: '支付参数不完整', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
return
|
||||
}
|
||||
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType,
|
||||
paySign: payParams.paySign,
|
||||
success: () => this.onPaymentSuccess(),
|
||||
fail: (err) => {
|
||||
if (err.errMsg === 'requestPayment:fail cancel') {
|
||||
this.handleUserCancel()
|
||||
} else {
|
||||
this.handlePaymentFail(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleUserCancel() {
|
||||
const { orderId } = this.data
|
||||
wx.showToast({ title: '已取消支付', icon: 'none', duration: 1500 })
|
||||
if (orderId) {
|
||||
request({
|
||||
url: '/dingdan/shibai',
|
||||
method: 'POST',
|
||||
data: { dingdanid: orderId, yuanyin: 'user_cancel' }
|
||||
}).catch(() => {})
|
||||
}
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
},
|
||||
|
||||
handlePaymentFail(err) {
|
||||
const { orderId } = this.data
|
||||
wx.showToast({ title: '支付失败', icon: 'none', duration: 1500 })
|
||||
if (orderId) {
|
||||
request({
|
||||
url: '/dingdan/shibai',
|
||||
method: 'POST',
|
||||
data: { dingdanid: orderId, yuanyin: 'payment_fail', cuowu: err.errMsg || '' }
|
||||
}).catch(() => {}).finally(() => {
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
})
|
||||
} else {
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
}
|
||||
},
|
||||
|
||||
onPaymentSuccess() {
|
||||
const { orderId } = this.data
|
||||
if (!orderId) {
|
||||
wx.showToast({ title: '订单ID不存在', icon: 'none' })
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: '支付成功,确认中...', icon: 'none', duration: 1500 })
|
||||
this.checkOrderStatus()
|
||||
},
|
||||
|
||||
checkOrderStatus() {
|
||||
const { orderId, checkCount, maxCheckCount } = this.data
|
||||
wx.showLoading({ title: `确认支付状态${checkCount > 0 ? `(${checkCount + 1})` : ''}`, mask: true })
|
||||
|
||||
const timeoutTimer = setTimeout(() => {
|
||||
wx.hideLoading()
|
||||
this.handleConfirmError('网络超时')
|
||||
}, 5000)
|
||||
|
||||
request({
|
||||
url: '/dingdan/fucha',
|
||||
method: 'POST',
|
||||
data: { dingdanid: orderId }
|
||||
})
|
||||
.then(res => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
if (res.data.code === 0) {
|
||||
this.handleConfirmSuccess()
|
||||
} else {
|
||||
this.handleConfirmError(res.data.msg || '订单状态异常')
|
||||
}
|
||||
} else {
|
||||
this.handleConfirmError('网络错误')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
clearTimeout(timeoutTimer)
|
||||
wx.hideLoading()
|
||||
this.handleConfirmError('检查失败')
|
||||
})
|
||||
},
|
||||
|
||||
handleConfirmSuccess() {
|
||||
wx.showToast({ title: '购买成功!', icon: 'success', duration: 1500 })
|
||||
setTimeout(() => wx.switchTab({ url: '/pages/index/index' }), 1500)
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
},
|
||||
|
||||
handleConfirmError(errorMsg) {
|
||||
const newCheckCount = this.data.checkCount + 1
|
||||
if (newCheckCount < this.data.maxCheckCount) {
|
||||
this.setData({ checkCount: newCheckCount })
|
||||
setTimeout(() => this.checkOrderStatus(), 1000)
|
||||
} else {
|
||||
wx.showModal({
|
||||
title: '支付确认中',
|
||||
content: '支付已成功,但订单状态确认异常。请稍后在订单列表中查看状态,如有问题请联系客服。',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
})
|
||||
this.setData({ isSubmitting: false, isPaying: false })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,124 +1,132 @@
|
||||
<!--pages/submit/submit.wxml-->
|
||||
<view class="submit-page">
|
||||
<!-- 商品信息区域 -->
|
||||
<view class="product-section">
|
||||
<view class="product-card">
|
||||
<!-- 商品图片 -->
|
||||
<view class="product-image-box">
|
||||
<image
|
||||
src="{{shangpinData && shangpinData.image ? shangpinData.image : ''}}"
|
||||
mode="aspectFill"
|
||||
class="product-image"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<view class="product-info">
|
||||
<view class="product-title">
|
||||
<text class="title-text">{{shangpinData && shangpinData.title ? shangpinData.title : '商品标题'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 价格信息 -->
|
||||
<view class="price-info">
|
||||
<text class="price-label">价格:</text>
|
||||
<view class="price-value">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}}</text>
|
||||
<text class="price-decimal">.{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域(左右布局) -->
|
||||
<view class="form-section">
|
||||
<view class="form-card">
|
||||
<!-- 游戏昵称 - 左右布局 -->
|
||||
<view class="form-item-row">
|
||||
<view class="item-label-row">
|
||||
<text class="label-text-bold">昵称</text>
|
||||
<text class="label-required">*</text>
|
||||
</view>
|
||||
<input
|
||||
class="item-input-row"
|
||||
type="text"
|
||||
placeholder="请输入您的昵称"
|
||||
placeholder-class="input-placeholder-gray"
|
||||
maxlength="15"
|
||||
value="{{nicheng}}"
|
||||
bindinput="onNicknameInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 - 左右布局 -->
|
||||
<view class="form-item-row">
|
||||
<view class="item-label-row">
|
||||
<text class="label-text-bold">备注</text>
|
||||
</view>
|
||||
<input
|
||||
class="item-input-row"
|
||||
type="text"
|
||||
placeholder="请补充您要补充的其他联系信息"
|
||||
placeholder-class="input-placeholder-gray"
|
||||
maxlength="30"
|
||||
value="{{beizhu}}"
|
||||
bindinput="onRemarkInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 指定打手ID - 左右布局 -->
|
||||
<view class="form-item-row">
|
||||
<view class="item-label-row">
|
||||
<text class="label-text-bold">指定服务者ID(选填)</text>
|
||||
</view>
|
||||
<input
|
||||
class="item-input-row"
|
||||
type="text"
|
||||
placeholder="填写您需要指定的服务者"
|
||||
placeholder-class="input-placeholder-gray"
|
||||
maxlength="20"
|
||||
value="{{zhiding}}"
|
||||
bindinput="onZhidingInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="payment-item">
|
||||
<view class="payment-method">
|
||||
<image src="/images/wechat-pay.png" class="payment-icon" />
|
||||
<text class="payment-text">微信支付</text>
|
||||
<view class="payment-checkbox">
|
||||
<text class="checkbox-text">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="footer-section">
|
||||
<view class="total-price">
|
||||
<text class="total-label">总价:</text>
|
||||
<view class="total-value">
|
||||
<text class="price-icon">¥</text>
|
||||
<text class="price-integer">{{shangpinData && shangpinData.priceInteger ? shangpinData.priceInteger : '0'}}</text>
|
||||
<text class="price-decimal">.{{shangpinData && shangpinData.priceDecimal ? shangpinData.priceDecimal : '00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="submit-btn {{canSubmit && !isSubmitting ? 'submit-btn-active' : 'submit-btn-disabled'}}"
|
||||
bindtap="onSubmitOrder"
|
||||
>
|
||||
<text class="btn-text">{{isSubmitting ? '提交中...' : '提交订单'}}</text>
|
||||
<view class="btn-glow"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 全局通知组件 -->
|
||||
<global-notification id="global-notification" />
|
||||
|
||||
<!-- 弹窗公告组件(供 PopupService 调用) -->
|
||||
<popup-notice id="popupNotice" />
|
||||
</view>
|
||||
<!--pages/submit/submit.wxml-->
|
||||
<view class="page">
|
||||
<!-- 商品摘要 - 拼多多SKU弹窗顶部风格 -->
|
||||
<view class="sku-header">
|
||||
<image class="sku-thumb" src="{{shangpinData.image || ''}}" mode="aspectFill" />
|
||||
<view class="sku-header-info">
|
||||
<view class="sku-price-row">
|
||||
<text class="sku-price-sym">¥</text>
|
||||
<text class="sku-price-int">{{totalPriceInteger}}</text>
|
||||
<text class="sku-price-dec">.{{totalPriceDecimal}}</text>
|
||||
</view>
|
||||
<text class="sku-stock">库存{{shangpinData.kucun || 0}}件</text>
|
||||
<text class="sku-selected">已选:{{quantity}}份</text>
|
||||
</view>
|
||||
<view class="sku-close" bindtap="goBack">×</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买数量 -->
|
||||
<view class="sku-section">
|
||||
<text class="sku-section-title">购买数量</text>
|
||||
<view class="qty-row">
|
||||
<view class="qty-btn {{quantity <= 1 ? 'qty-btn--disabled' : ''}}" bindtap="onQtyMinus">-</view>
|
||||
<text class="qty-val">{{quantity}}</text>
|
||||
<view class="qty-btn {{quantity >= 99 ? 'qty-btn--disabled' : ''}}" bindtap="onQtyPlus">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 服务信息 -->
|
||||
<view class="sku-section">
|
||||
<text class="sku-section-title">服务信息</text>
|
||||
|
||||
<view class="form-field">
|
||||
<view class="field-top">
|
||||
<text class="field-name">游戏昵称</text>
|
||||
<text class="field-required">必填</text>
|
||||
</view>
|
||||
<input
|
||||
class="field-input"
|
||||
type="text"
|
||||
placeholder="请输入您的游戏昵称"
|
||||
placeholder-class="ph"
|
||||
maxlength="15"
|
||||
value="{{nicheng}}"
|
||||
bindinput="onNicknameInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-field">
|
||||
<view class="field-top">
|
||||
<text class="field-name">备注</text>
|
||||
<text class="field-optional">选填</text>
|
||||
</view>
|
||||
<input
|
||||
class="field-input"
|
||||
type="text"
|
||||
placeholder="补充其他联系信息"
|
||||
placeholder-class="ph"
|
||||
maxlength="30"
|
||||
value="{{beizhu}}"
|
||||
bindinput="onRemarkInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-field">
|
||||
<view class="field-top">
|
||||
<text class="field-name">指定服务者</text>
|
||||
<text class="field-optional">选填</text>
|
||||
</view>
|
||||
<input
|
||||
class="field-input"
|
||||
type="text"
|
||||
placeholder="填写指定服务者ID"
|
||||
placeholder-class="ph"
|
||||
maxlength="20"
|
||||
value="{{zhiding}}"
|
||||
bindinput="onZhidingInput"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 服务保障 -->
|
||||
<view class="sku-section">
|
||||
<text class="sku-section-title">服务保障</text>
|
||||
<view class="guarantee-row">
|
||||
<view class="guarantee-item">
|
||||
<text class="g-check">✓</text>
|
||||
<text class="g-text">极速接单</text>
|
||||
</view>
|
||||
<view class="guarantee-item">
|
||||
<text class="g-check">✓</text>
|
||||
<text class="g-text">资金担保</text>
|
||||
</view>
|
||||
<view class="guarantee-item">
|
||||
<text class="g-check">✓</text>
|
||||
<text class="g-text">售后保障</text>
|
||||
</view>
|
||||
<view class="guarantee-item">
|
||||
<text class="g-check">✓</text>
|
||||
<text class="g-text">隐私保护</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="sku-section">
|
||||
<text class="sku-section-title">支付方式</text>
|
||||
<view class="pay-row">
|
||||
<image src="/images/wechat-pay.png" class="pay-icon" />
|
||||
<text class="pay-label">微信支付</text>
|
||||
<view class="pay-check">
|
||||
<text class="pay-check-icon">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
|
||||
<!-- 底部确认按钮 -->
|
||||
<view class="confirm-bar">
|
||||
<view
|
||||
class="confirm-btn {{canSubmit && !isSubmitting ? 'confirm-btn--active' : 'confirm-btn--disabled'}}"
|
||||
bindtap="onSubmitOrder"
|
||||
hover-class="confirm-btn--hover"
|
||||
>
|
||||
{{isSubmitting ? '提交中...' : '确定'}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<global-notification id="global-notification" />
|
||||
<popup-notice id="popupNotice" />
|
||||
</view>
|
||||
|
||||
@@ -1,280 +1,296 @@
|
||||
/* pages/submit/submit.wxss */
|
||||
|
||||
.submit-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #f8f9ff 0%, #f0f3ff 100%);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 商品信息区域 */
|
||||
.product-section {
|
||||
padding: 30rpx 30rpx 20rpx 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.product-image-box {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
background: #f5f5f5;
|
||||
flex-shrink: 0;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.price-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.price-icon {
|
||||
font-size: 28rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.price-integer {
|
||||
font-size: 38rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 700;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.price-decimal {
|
||||
font-size: 28rpx;
|
||||
color: #ff4d4f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.form-section {
|
||||
padding: 0 30rpx 20rpx 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.form-item-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 25rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.form-item-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-label-row {
|
||||
width: 220rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label-text-bold {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.label-required {
|
||||
font-size: 30rpx;
|
||||
color: #ff4d4f;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
.item-input-row {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
padding: 0 20rpx;
|
||||
text-align: right;
|
||||
background: #fafafa;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.input-placeholder-gray {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 支付方式 */
|
||||
.payment-item {
|
||||
margin-top: 30rpx;
|
||||
padding-top: 30rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.payment-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.payment-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.payment-checkbox {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: #52c41a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.checkbox-text {
|
||||
color: white;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.footer-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 30rpx;
|
||||
background: white;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
margin-top: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.total-price {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.total-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 240rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.submit-btn-active {
|
||||
background: linear-gradient(135deg, #52c41a, #389e0d);
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
.submit-btn-disabled {
|
||||
background: #ccc;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.submit-btn-active:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 20rpx rgba(255, 77, 79, 0.5);
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 32rpx;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.btn-glow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transform: translateX(-100%);
|
||||
animation: btnGlow 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes btnGlow {
|
||||
0% { transform: translateX(-100%); }
|
||||
50% { transform: translateX(100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
/* pages/submit/submit.wxss */
|
||||
|
||||
page {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 140rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* SKU头部 - 拼多多弹窗风格 */
|
||||
.sku-header {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
padding: 24rpx;
|
||||
position: relative;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.sku-thumb {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 12rpx;
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.sku-header-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
.sku-price-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.sku-price-sym {
|
||||
font-size: 28rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sku-price-int {
|
||||
font-size: 48rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
margin-left: 2rpx;
|
||||
}
|
||||
|
||||
.sku-price-dec {
|
||||
font-size: 28rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sku-stock {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.sku-selected {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.sku-close {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
right: 16rpx;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
border-radius: 50%;
|
||||
background: #f5f5f5;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* SKU区块 */
|
||||
.sku-section {
|
||||
background: #fff;
|
||||
padding: 24rpx 28rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.sku-section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 数量选择器 */
|
||||
.qty-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.qty-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
border: 1rpx solid #e8e8e8;
|
||||
}
|
||||
|
||||
.qty-btn--disabled {
|
||||
color: #ccc;
|
||||
border-color: #f0f0f0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.qty-val {
|
||||
min-width: 80rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
|
||||
/* 表单字段 */
|
||||
.form-field {
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.form-field:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.field-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.field-required {
|
||||
font-size: 20rpx;
|
||||
color: #e02e24;
|
||||
background: #fff1f0;
|
||||
padding: 2rpx 10rpx;
|
||||
border-radius: 4rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.field-optional {
|
||||
font-size: 20rpx;
|
||||
color: #bbb;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.field-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f7f7f7;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
border: 1rpx solid #eee;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ph {
|
||||
color: #bbb;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
/* 服务保障 */
|
||||
.guarantee-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx 20rpx;
|
||||
}
|
||||
|
||||
.guarantee-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.g-check {
|
||||
font-size: 20rpx;
|
||||
color: #e02e24;
|
||||
font-weight: 700;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.g-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 支付方式 */
|
||||
.pay-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.pay-label {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pay-check {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
background: #52c41a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pay-check-icon {
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 底部留白 */
|
||||
.bottom-space {
|
||||
height: 20rpx;
|
||||
}
|
||||
|
||||
/* 底部确认按钮 */
|
||||
.confirm-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 100rpx;
|
||||
background: #fff;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
letter-spacing: 4rpx;
|
||||
}
|
||||
|
||||
.confirm-btn--active {
|
||||
background: #e02e24;
|
||||
}
|
||||
|
||||
.confirm-btn--disabled {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.confirm-btn--hover {
|
||||
opacity: 0.9;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
@@ -1,169 +1,159 @@
|
||||
// pages/verify/verify.js
|
||||
import request from '../../utils/request.js'
|
||||
import { enterLockedRole } from '../../utils/primary-role.js'
|
||||
|
||||
const API_MAP = {
|
||||
dashou: '/yonghu/dashouzhuce',
|
||||
shangjia: '/yonghu/shangjiahuce',
|
||||
guanshi: '/yonghu/guanshizhuce',
|
||||
zuzhang: '/yonghu/zuzhangzhuce',
|
||||
kaoheguan: '/dengji/khgzc'
|
||||
}
|
||||
|
||||
const STATUS_KEY_MAP = {
|
||||
dashou: 'dashoustatus',
|
||||
shangjia: 'shangjiastatus',
|
||||
guanshi: 'guanshistatus',
|
||||
zuzhang: 'zuzhangstatus',
|
||||
kaoheguan: 'kaoheguanstatus'
|
||||
}
|
||||
|
||||
const NAME_MAP = {
|
||||
dashou: '接单员',
|
||||
shangjia: '商家',
|
||||
guanshi: '管事',
|
||||
zuzhang: '组长',
|
||||
kaoheguan: '考核官'
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
authType: '',
|
||||
authName: '',
|
||||
pageState: 'need_register',
|
||||
inviteCode: '',
|
||||
isLoading: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const type = options.type || ''
|
||||
if (!API_MAP[type]) {
|
||||
wx.showToast({ title: '认证类型错误', icon: 'none' })
|
||||
setTimeout(() => wx.navigateBack(), 1500)
|
||||
return
|
||||
}
|
||||
this.setData({ authType: type, authName: NAME_MAP[type] })
|
||||
this.checkStatus()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.data.authType) this.checkStatus()
|
||||
},
|
||||
|
||||
checkStatus() {
|
||||
const key = STATUS_KEY_MAP[this.data.authType]
|
||||
const val = wx.getStorageSync(key)
|
||||
if (val === 1) {
|
||||
this.setData({ pageState: 'done' })
|
||||
} else {
|
||||
this.setData({ pageState: 'need_register' })
|
||||
}
|
||||
},
|
||||
|
||||
onInviteCodeInput(e) {
|
||||
this.setData({ inviteCode: e.detail.value.trim() })
|
||||
},
|
||||
|
||||
async onRegister() {
|
||||
const { inviteCode, authType } = this.data
|
||||
if (!inviteCode) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (inviteCode.length > 100) {
|
||||
wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({ isLoading: true })
|
||||
wx.showLoading({ title: '注册中...', mask: true })
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: API_MAP[authType],
|
||||
method: 'POST',
|
||||
data: { inviteCode }
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data || res.data
|
||||
const app = getApp()
|
||||
|
||||
// 缓存身份状态
|
||||
const key = STATUS_KEY_MAP[authType]
|
||||
if (data[key] !== undefined) {
|
||||
wx.setStorageSync(key, data[key])
|
||||
app.globalData[key] = data[key]
|
||||
} else {
|
||||
wx.setStorageSync(key, 1)
|
||||
app.globalData[key] = 1
|
||||
}
|
||||
|
||||
// 更新其他可能返回的身份状态字段
|
||||
const allKeys = ['dashoustatus', 'shangjiastatus', 'guanshistatus', 'zuzhangstatus', 'kaoheguanstatus']
|
||||
allKeys.forEach(k => {
|
||||
if (data[k] !== undefined && k !== key) {
|
||||
wx.setStorageSync(k, data[k])
|
||||
app.globalData[k] = data[k]
|
||||
}
|
||||
})
|
||||
|
||||
// 保存各身份详细信息
|
||||
if (authType === 'dashou') {
|
||||
const fields = ['dashounicheng','zhanghaostatus','yongjin','zonge','yajin','chenghao','jifen','clumber','chengjiaoliang','zaixianzhuangtai']
|
||||
fields.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] })
|
||||
} else if (authType === 'shangjia') {
|
||||
app.globalData.shangjia = app.globalData.shangjia || {}
|
||||
const sf = ['nicheng','sjyue','fabu','chengjiao','tuikuan','jinridingdan','jinriliushui','jinyuedingdan','jinyueliushui','zhuangtai']
|
||||
sf.forEach(f => { if (data[f] !== undefined) app.globalData.shangjia[f] = data[f] })
|
||||
} else if (authType === 'guanshi') {
|
||||
app.globalData.guanshi = app.globalData.guanshi || {}
|
||||
const gf = ['gszhstatus','yaoqingzongshu','fenyongzonge','fenyongtixian','yichongzhiDashou']
|
||||
gf.forEach(f => { if (data[f] !== undefined) app.globalData.guanshi[f] = data[f] })
|
||||
} else if (authType === 'zuzhang') {
|
||||
const zf = ['ketixian','guanshiCount','fenhongZonge']
|
||||
zf.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] })
|
||||
} else if (authType === 'kaoheguan') {
|
||||
app.globalData.kaoheguan = app.globalData.kaoheguan || {}
|
||||
const kf = ['shenhe_zongshu','tongguo_zongshu','yue','zonge','shenhe_zhuangtai','bankuai_list']
|
||||
kf.forEach(f => { if (data[f] !== undefined) app.globalData.kaoheguan[f] = data[f] })
|
||||
}
|
||||
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false, pageState: 'done' })
|
||||
wx.showToast({ title: '认证成功', icon: 'success' })
|
||||
|
||||
if (authType === 'dashou' || authType === 'shangjia') {
|
||||
setTimeout(() => enterLockedRole(authType), 1200)
|
||||
} else if (authType === 'guanshi') {
|
||||
setTimeout(() => {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
wx.navigateBack()
|
||||
} else {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' })
|
||||
}
|
||||
}, 800)
|
||||
}
|
||||
} else {
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none' })
|
||||
}
|
||||
} catch (err) {
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: err.message || '注册失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
goToKefu() {
|
||||
const app = getApp()
|
||||
const { link, enterpriseId } = app.globalData.kefuConfig || {}
|
||||
if (!link || !enterpriseId) {
|
||||
wx.showToast({ title: '客服配置未加载', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.openCustomerServiceChat({ extInfo: { url: link }, corpId: enterpriseId })
|
||||
}
|
||||
})
|
||||
// pages/verify/verify.js
|
||||
import { createPage, request } from '../../utils/base-page.js'
|
||||
import { enterLockedRole } from '../../utils/primary-role.js'
|
||||
|
||||
const API_MAP = {
|
||||
dashou: '/yonghu/dashouzhuce',
|
||||
shangjia: '/yonghu/shangjiahuce',
|
||||
guanshi: '/yonghu/guanshizhuce',
|
||||
zuzhang: '/yonghu/zuzhangzhuce',
|
||||
kaoheguan: '/dengji/khgzc'
|
||||
}
|
||||
|
||||
const STATUS_KEY_MAP = {
|
||||
dashou: 'dashoustatus',
|
||||
shangjia: 'shangjiastatus',
|
||||
guanshi: 'guanshistatus',
|
||||
zuzhang: 'zuzhangstatus',
|
||||
kaoheguan: 'kaoheguanstatus'
|
||||
}
|
||||
|
||||
const NAME_MAP = {
|
||||
dashou: '接单员',
|
||||
shangjia: '商家',
|
||||
guanshi: '管事',
|
||||
zuzhang: '组长',
|
||||
kaoheguan: '考核官'
|
||||
}
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
authType: '',
|
||||
authName: '',
|
||||
pageState: 'need_register',
|
||||
inviteCode: '',
|
||||
isLoading: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const type = options.type || ''
|
||||
if (!API_MAP[type]) {
|
||||
wx.showToast({ title: '认证类型错误', icon: 'none' })
|
||||
setTimeout(() => wx.navigateBack(), 1500)
|
||||
return
|
||||
}
|
||||
this.setData({ authType: type, authName: NAME_MAP[type] })
|
||||
this.checkStatus()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.data.authType) this.checkStatus()
|
||||
},
|
||||
|
||||
checkStatus() {
|
||||
const key = STATUS_KEY_MAP[this.data.authType]
|
||||
const val = wx.getStorageSync(key)
|
||||
if (val === 1) {
|
||||
this.setData({ pageState: 'done' })
|
||||
} else {
|
||||
this.setData({ pageState: 'need_register' })
|
||||
}
|
||||
},
|
||||
|
||||
onInviteCodeInput(e) {
|
||||
this.setData({ inviteCode: e.detail.value.trim() })
|
||||
},
|
||||
|
||||
async onRegister() {
|
||||
const { inviteCode, authType } = this.data
|
||||
if (!inviteCode) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (inviteCode.length > 100) {
|
||||
wx.showToast({ title: '邀请码不能超过100字符', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({ isLoading: true })
|
||||
wx.showLoading({ title: '注册中...', mask: true })
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: API_MAP[authType],
|
||||
method: 'POST',
|
||||
data: { inviteCode }
|
||||
})
|
||||
|
||||
if (res && res.data.code === 200) {
|
||||
const data = res.data.data || res.data
|
||||
const app = getApp()
|
||||
|
||||
// 缓存身份状态
|
||||
const key = STATUS_KEY_MAP[authType]
|
||||
if (data[key] !== undefined) {
|
||||
wx.setStorageSync(key, data[key])
|
||||
app.globalData[key] = data[key]
|
||||
} else {
|
||||
wx.setStorageSync(key, 1)
|
||||
app.globalData[key] = 1
|
||||
}
|
||||
|
||||
// 更新其他可能返回的身份状态字段
|
||||
const allKeys = ['dashoustatus', 'shangjiastatus', 'guanshistatus', 'zuzhangstatus', 'kaoheguanstatus']
|
||||
allKeys.forEach(k => {
|
||||
if (data[k] !== undefined && k !== key) {
|
||||
wx.setStorageSync(k, data[k])
|
||||
app.globalData[k] = data[k]
|
||||
}
|
||||
})
|
||||
|
||||
// 保存各身份详细信息
|
||||
if (authType === 'dashou') {
|
||||
const fields = ['dashounicheng','zhanghaostatus','yongjin','zonge','yajin','chenghao','jifen','clumber','chengjiaoliang','zaixianzhuangtai']
|
||||
fields.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] })
|
||||
} else if (authType === 'shangjia') {
|
||||
app.globalData.shangjia = app.globalData.shangjia || {}
|
||||
const sf = ['nicheng','sjyue','fabu','chengjiao','tuikuan','jinridingdan','jinriliushui','jinyuedingdan','jinyueliushui','zhuangtai']
|
||||
sf.forEach(f => { if (data[f] !== undefined) app.globalData.shangjia[f] = data[f] })
|
||||
} else if (authType === 'guanshi') {
|
||||
app.globalData.guanshi = app.globalData.guanshi || {}
|
||||
const gf = ['gszhstatus','yaoqingzongshu','fenyongzonge','fenyongtixian','yichongzhiDashou']
|
||||
gf.forEach(f => { if (data[f] !== undefined) app.globalData.guanshi[f] = data[f] })
|
||||
} else if (authType === 'zuzhang') {
|
||||
const zf = ['ketixian','guanshiCount','fenhongZonge']
|
||||
zf.forEach(f => { if (data[f] !== undefined) app.globalData[f] = data[f] })
|
||||
} else if (authType === 'kaoheguan') {
|
||||
app.globalData.kaoheguan = app.globalData.kaoheguan || {}
|
||||
const kf = ['shenhe_zongshu','tongguo_zongshu','yue','zonge','shenhe_zhuangtai','bankuai_list']
|
||||
kf.forEach(f => { if (data[f] !== undefined) app.globalData.kaoheguan[f] = data[f] })
|
||||
}
|
||||
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false, pageState: 'done' })
|
||||
wx.showToast({ title: '认证成功', icon: 'success' })
|
||||
|
||||
if (authType === 'dashou' || authType === 'shangjia') {
|
||||
setTimeout(() => enterLockedRole(authType), 1200)
|
||||
} else if (authType === 'guanshi') {
|
||||
setTimeout(() => {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
wx.navigateBack()
|
||||
} else {
|
||||
wx.redirectTo({ url: '/pages/fighter/fighter' })
|
||||
}
|
||||
}, 800)
|
||||
}
|
||||
} else {
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: res?.data?.msg || '注册失败', icon: 'none' })
|
||||
}
|
||||
} catch (err) {
|
||||
wx.hideLoading()
|
||||
this.setData({ isLoading: false })
|
||||
wx.showToast({ title: err.message || '注册失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -1,72 +1,54 @@
|
||||
// pages/withdraw/withdraw.js
|
||||
import request from '../../utils/request.js';
|
||||
import PopupService from '../../services/popupService.js';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
pageMode: 0,
|
||||
pageOptions: {},
|
||||
loadError: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
pageOptions: options || {}
|
||||
});
|
||||
this.fetchPageMode();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
PopupService.checkAndShow(this, 'tixian');
|
||||
},
|
||||
|
||||
onHide() {
|
||||
const popupComp = this.selectComponent('#popupNotice');
|
||||
if (popupComp && popupComp.cleanup) {
|
||||
popupComp.cleanup();
|
||||
}
|
||||
},
|
||||
|
||||
// 注册通知组件
|
||||
registerNotificationComponent() {
|
||||
const notificationComp = this.selectComponent('#global-notification');
|
||||
if (notificationComp && notificationComp.showNotification) {
|
||||
app.globalData.globalNotification = {
|
||||
show: (data) => notificationComp.showNotification(data),
|
||||
hide: () => notificationComp.hideNotification()
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
async fetchPageMode() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/peizhi/hqtxzsym',
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||
const mode = parseInt(res.data.data.mode);
|
||||
this.setData({
|
||||
pageMode: (mode === 1 || mode === 2) ? mode : 1,
|
||||
loadError: false
|
||||
});
|
||||
} else {
|
||||
this.setData({ pageMode: 1, loadError: false });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取展示模式失败:', err);
|
||||
this.setData({ loadError: true });
|
||||
}
|
||||
},
|
||||
|
||||
retryFetch() {
|
||||
this.setData({ loadError: false, pageMode: 0 });
|
||||
this.fetchPageMode();
|
||||
},
|
||||
|
||||
stopPropagation() {}
|
||||
});
|
||||
// pages/withdraw/withdraw.js
|
||||
import { createPage, request } from '../../utils/base-page.js';
|
||||
import PopupService from '../../services/popupService.js';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
Page(createPage({
|
||||
data: {
|
||||
pageMode: 0,
|
||||
pageOptions: {},
|
||||
loadError: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
pageOptions: options || {}
|
||||
});
|
||||
this.fetchPageMode();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.registerNotificationComponent();
|
||||
PopupService.checkAndShow(this, 'tixian');
|
||||
},
|
||||
|
||||
async fetchPageMode() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/peizhi/hqtxzsym',
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||
const mode = parseInt(res.data.data.mode);
|
||||
this.setData({
|
||||
pageMode: (mode === 1 || mode === 2) ? mode : 1,
|
||||
loadError: false
|
||||
});
|
||||
} else {
|
||||
this.setData({ pageMode: 1, loadError: false });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取展示模式失败:', err);
|
||||
this.setData({ loadError: true });
|
||||
}
|
||||
},
|
||||
|
||||
retryFetch() {
|
||||
this.setData({ loadError: false, pageMode: 0 });
|
||||
this.fetchPageMode();
|
||||
},
|
||||
|
||||
stopPropagation() {}
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user