513 lines
16 KiB
JavaScript
513 lines
16 KiB
JavaScript
// 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';
|
|
import { STAFF_API, isStaffMode, refreshStaffContext, syncStaffUi } from '../../utils/staff-api.js';
|
|
import { ensurePhoneAuth } from '../../utils/phone-auth.js';
|
|
import { fetchMerchantOrderStats } from '../../utils/merchant-order-stats.js';
|
|
|
|
const EMPTY_TAB = { list: [], page: 1, hasMore: true, isLoading: false };
|
|
|
|
function buildEmptyStatusData() {
|
|
return {
|
|
all: { ...EMPTY_TAB },
|
|
daifuwu: { ...EMPTY_TAB },
|
|
zhidingzhong: { ...EMPTY_TAB },
|
|
jinxingzhong: { ...EMPTY_TAB },
|
|
tuikuanzhong: { ...EMPTY_TAB },
|
|
yituikuan: { ...EMPTY_TAB },
|
|
tuikuanshibai: { ...EMPTY_TAB },
|
|
yiwancheng: { ...EMPTY_TAB },
|
|
jiesuanzhong: { ...EMPTY_TAB },
|
|
};
|
|
}
|
|
|
|
const STATUS_TAG_STYLE = {
|
|
1: { color: '#E65100', bg: '#FFF3E0' },
|
|
2: { color: '#1565C0', bg: '#E3F2FD' },
|
|
3: { color: '#2E7D32', bg: '#E8F5E9' },
|
|
4: { color: '#EF6C00', bg: '#FFF8E1' },
|
|
5: { color: '#616161', bg: '#F5F5F5' },
|
|
6: { color: '#C62828', bg: '#FFEBEE' },
|
|
7: { color: '#BF360C', bg: '#FFE0B2' },
|
|
8: { color: '#D84315', bg: '#FBE9E7' },
|
|
};
|
|
|
|
Page(createPage({
|
|
data: {
|
|
shangpinleixing: [],
|
|
xuanzhongLeixingId: null,
|
|
|
|
searchKeyword: '',
|
|
|
|
timeStart: '',
|
|
timeEnd: '',
|
|
|
|
statusList: [
|
|
{ name: '全部', key: 'all', zhuangtaiList: [1, 2, 3, 4, 5, 6, 7, 8], color: '#333333' },
|
|
{ name: '待服务', key: 'daifuwu', zhuangtaiList: [1], color: '#E65100' },
|
|
{ name: '指定中', key: 'zhidingzhong', zhuangtaiList: [7], color: '#BF360C' },
|
|
{ name: '进行中', key: 'jinxingzhong', zhuangtaiList: [2], color: '#2196F3' },
|
|
{ name: '退款中', key: 'tuikuanzhong', zhuangtaiList: [4], color: '#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: buildEmptyStatusData(),
|
|
|
|
currentList: [],
|
|
hasMore: true,
|
|
isLoading: false,
|
|
isLoadingMore: false,
|
|
scrollViewRefreshing: false,
|
|
listScrollTop: 0,
|
|
defaultImg: '/images/default-order.png',
|
|
ossImageUrl: app.globalData.ossImageUrl || '',
|
|
|
|
pendingCount: 0,
|
|
staffList: [],
|
|
selectedStaffMemberId: '',
|
|
selectedStaffLabel: '全部客服',
|
|
canViewFinance: true,
|
|
orderStats: {
|
|
pending_count: 0,
|
|
pending_amount: '0.00',
|
|
completed_count: 0,
|
|
completed_amount: '0.00',
|
|
refund_count: 0,
|
|
refund_amount: '0.00',
|
|
dispatch_count: 0,
|
|
dispatch_amount: '0.00',
|
|
},
|
|
},
|
|
|
|
onLoad(options) {
|
|
this._listInitialized = false;
|
|
this._savedScrollTop = 0;
|
|
this._skipShowRefresh = false;
|
|
wx.setNavigationBarTitle({ title: isStaffMode() ? '客服派单' : '我的派单' });
|
|
syncStaffUi(this);
|
|
if (isStaffMode()) {
|
|
refreshStaffContext(request).then(() => syncStaffUi(this));
|
|
}
|
|
this.loadShangpinLeixing();
|
|
this.registerNotificationComponent();
|
|
if (options && options.staff_member_id) {
|
|
this.setData({
|
|
selectedStaffMemberId: String(options.staff_member_id),
|
|
selectedStaffLabel: options.staff_label || '指定客服',
|
|
});
|
|
}
|
|
if (!isStaffMode()) {
|
|
this.loadStaffList();
|
|
}
|
|
},
|
|
|
|
async onShow() {
|
|
const phoneOk = await ensurePhoneAuth({ redirect: true, role: 'shangjia' });
|
|
if (!phoneOk) return;
|
|
|
|
this.registerNotificationComponent();
|
|
this.loadOrderStats();
|
|
if (wx.getStorageSync('uid')) {
|
|
reconnectForRole('shangjia');
|
|
if (app.startImWhenReady) app.startImWhenReady();
|
|
}
|
|
|
|
if (this._skipShowRefresh) {
|
|
this._skipShowRefresh = false;
|
|
this.restoreListScroll();
|
|
return;
|
|
}
|
|
|
|
// 从详情返回:保持列表与滚动位置,不整页重载
|
|
if (this._listInitialized) {
|
|
this.restoreListScroll();
|
|
return;
|
|
}
|
|
},
|
|
|
|
restoreListScroll() {
|
|
const top = this._savedScrollTop || 0;
|
|
if (top <= 0) return;
|
|
this.setData({ listScrollTop: 0 });
|
|
wx.nextTick(() => {
|
|
this.setData({ listScrollTop: top });
|
|
});
|
|
},
|
|
|
|
onListScroll(e) {
|
|
this._savedScrollTop = e.detail.scrollTop || 0;
|
|
},
|
|
|
|
buildListParams(key, page) {
|
|
const statusItem = this.data.statusList.find((s) => s.key === key);
|
|
const params = {
|
|
zhuangtai_list: statusItem.zhuangtaiList,
|
|
page,
|
|
page_size: 5,
|
|
leixing_id: this.data.xuanzhongLeixingId,
|
|
keyword: this.data.searchKeyword || undefined,
|
|
};
|
|
const { timeStart, timeEnd } = this.data;
|
|
if (timeStart) params.start_time = `${timeStart} 00:00:00`;
|
|
if (timeEnd) params.end_time = `${timeEnd} 23:59:59`;
|
|
if (this.data.selectedStaffMemberId) {
|
|
params.staff_member_id = this.data.selectedStaffMemberId;
|
|
}
|
|
return params;
|
|
},
|
|
|
|
async loadStaffList() {
|
|
try {
|
|
const res = await request({ url: STAFF_API.memberList, method: 'POST' });
|
|
if (res.data && res.data.code === 0) {
|
|
const list = (res.data.data && res.data.data.list) || [];
|
|
this.setData({ staffList: list });
|
|
}
|
|
} catch (e) {
|
|
/* 非老板无权限时静默 */
|
|
}
|
|
},
|
|
|
|
onStaffFilterChange(e) {
|
|
const idx = Number(e.detail.value);
|
|
const list = this.data.staffList || [];
|
|
const row = list[idx];
|
|
if (!row) return;
|
|
this._savedScrollTop = 0;
|
|
this.setData({
|
|
selectedStaffMemberId: String(row.id),
|
|
selectedStaffLabel: row.nickname || row.uid,
|
|
listScrollTop: 0,
|
|
});
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
clearStaffFilter() {
|
|
this._savedScrollTop = 0;
|
|
this.setData({
|
|
selectedStaffMemberId: '',
|
|
selectedStaffLabel: '全部客服',
|
|
listScrollTop: 0,
|
|
});
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
async loadOrderStats() {
|
|
try {
|
|
const params = {};
|
|
const { timeStart, timeEnd, selectedStaffMemberId, xuanzhongLeixingId } = this.data;
|
|
if (timeStart) params.start_time = `${timeStart} 00:00:00`;
|
|
if (timeEnd) params.end_time = `${timeEnd} 23:59:59`;
|
|
if (selectedStaffMemberId) params.staff_member_id = selectedStaffMemberId;
|
|
if (xuanzhongLeixingId) params.leixing_id = xuanzhongLeixingId;
|
|
|
|
const data = await fetchMerchantOrderStats(request, params);
|
|
const order = data.order || {};
|
|
this.setData({
|
|
orderStats: {
|
|
pending_count: order.pending_count || 0,
|
|
pending_amount: order.pending_amount || '0.00',
|
|
completed_count: order.completed_count || 0,
|
|
completed_amount: order.completed_amount || '0.00',
|
|
refund_count: order.refund_count || 0,
|
|
refund_amount: order.refund_amount || '0.00',
|
|
dispatch_count: order.dispatch_count || 0,
|
|
dispatch_amount: order.dispatch_amount || '0.00',
|
|
},
|
|
pendingCount: order.pending_count || 0,
|
|
canViewFinance: data.can_view_finance !== false,
|
|
});
|
|
} catch (e) {
|
|
console.warn('订单统计失败', e);
|
|
}
|
|
},
|
|
|
|
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._savedScrollTop = 0;
|
|
this.setData({ xuanzhongLeixingId: id, listScrollTop: 0 });
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
onSearchInput(e) {
|
|
this.setData({ searchKeyword: e.detail.value });
|
|
if (this._searchTimer) clearTimeout(this._searchTimer);
|
|
this._searchTimer = setTimeout(() => {
|
|
this.onSearchConfirm();
|
|
}, 500);
|
|
},
|
|
|
|
onSearchConfirm() {
|
|
this._savedScrollTop = 0;
|
|
this.setData({ listScrollTop: 0 });
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
clearSearch() {
|
|
this._savedScrollTop = 0;
|
|
this.setData({ searchKeyword: '', listScrollTop: 0 });
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
},
|
|
|
|
onTimeStartChange(e) {
|
|
this.setData({ timeStart: e.detail.value }, () => this.triggerTimeFilterReload());
|
|
},
|
|
|
|
onTimeEndChange(e) {
|
|
this.setData({ timeEnd: e.detail.value }, () => this.triggerTimeFilterReload());
|
|
},
|
|
|
|
triggerTimeFilterReload() {
|
|
this._savedScrollTop = 0;
|
|
this.setData({ listScrollTop: 0 });
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
},
|
|
|
|
clearTimeFilter() {
|
|
this._savedScrollTop = 0;
|
|
this.setData({ timeStart: '', timeEnd: '', listScrollTop: 0 });
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
pickQuickRange(e) {
|
|
const days = Number(e.currentTarget.dataset.days);
|
|
if (!days) {
|
|
this.clearTimeFilter();
|
|
return;
|
|
}
|
|
const end = new Date();
|
|
const start = new Date();
|
|
start.setDate(end.getDate() - (days - 1));
|
|
const fmt = (d) => {
|
|
const y = d.getFullYear();
|
|
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
const day = String(d.getDate()).padStart(2, '0');
|
|
return `${y}-${m}-${day}`;
|
|
};
|
|
this._savedScrollTop = 0;
|
|
this.setData({
|
|
timeStart: fmt(start),
|
|
timeEnd: fmt(end),
|
|
listScrollTop: 0,
|
|
});
|
|
this.resetAllStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
this.loadOrderStats();
|
|
},
|
|
|
|
switchStatus(e) {
|
|
const key = e.currentTarget.dataset.key;
|
|
if (key === this.data.currentStatusKey) return;
|
|
this._savedScrollTop = 0;
|
|
this.setData({ currentStatusKey: key, listScrollTop: 0 });
|
|
const tabData = this.data.sjDingdanShuju[key];
|
|
if (tabData.list.length === 0 && tabData.hasMore && !tabData.isLoading) {
|
|
this.loadCurrentStatusOrders(true);
|
|
} else {
|
|
this.refreshCurrentListView();
|
|
}
|
|
},
|
|
|
|
async loadCurrentStatusOrders(isRefresh = false, pageOverride = null) {
|
|
const key = this.data.currentStatusKey;
|
|
const tabData = this.data.sjDingdanShuju[key];
|
|
if (tabData.isLoading) return;
|
|
|
|
const page = isRefresh ? 1 : (pageOverride || tabData.page + 1);
|
|
if (!isRefresh && !tabData.hasMore) return;
|
|
|
|
this.setData({
|
|
[`sjDingdanShuju.${key}.isLoading`]: true,
|
|
isLoading: isRefresh && tabData.list.length === 0,
|
|
isLoadingMore: !isRefresh,
|
|
});
|
|
|
|
try {
|
|
const statusItem = this.data.statusList.find((s) => s.key === key);
|
|
const params = this.buildListParams(key, page);
|
|
|
|
const res = await request({
|
|
url: isStaffMode() ? STAFF_API.orderList : '/dingdan/sjdingdanhq',
|
|
method: 'POST',
|
|
data: params,
|
|
header: { 'content-type': 'application/json' },
|
|
});
|
|
|
|
const code = res.data.code;
|
|
if (code === 200 || code === 0) {
|
|
const newList = res.data.data.list || [];
|
|
const total = Number(res.data.data.total);
|
|
const hasMore = typeof res.data.data.has_more === 'boolean'
|
|
? res.data.data.has_more
|
|
: (Number.isFinite(total) ? page * params.page_size < total : newList.length >= params.page_size);
|
|
|
|
const processed = newList.map((item) => this.processOrderItem(item, statusItem.color));
|
|
const prevList = isRefresh ? [] : tabData.list;
|
|
const updatedList = [...prevList, ...processed];
|
|
|
|
// 按订单 ID 去重,避免分页边界重复
|
|
const seen = new Set();
|
|
const deduped = updatedList.filter((row) => {
|
|
const id = row.dingdan_id;
|
|
if (!id || seen.has(id)) return false;
|
|
seen.add(id);
|
|
return true;
|
|
});
|
|
|
|
this.setData({
|
|
[`sjDingdanShuju.${key}.list`]: deduped,
|
|
[`sjDingdanShuju.${key}.page`]: page,
|
|
[`sjDingdanShuju.${key}.hasMore`]: hasMore,
|
|
[`sjDingdanShuju.${key}.isLoading`]: false,
|
|
isLoading: false,
|
|
isLoadingMore: false,
|
|
scrollViewRefreshing: false,
|
|
});
|
|
this._listInitialized = true;
|
|
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,
|
|
});
|
|
},
|
|
|
|
resetAllStatusData() {
|
|
const patch = {};
|
|
Object.keys(this.data.sjDingdanShuju).forEach((k) => {
|
|
patch[`sjDingdanShuju.${k}`] = { ...EMPTY_TAB };
|
|
});
|
|
this.setData(patch);
|
|
this.refreshCurrentListView();
|
|
},
|
|
|
|
resetCurrentStatusData() {
|
|
const key = this.data.currentStatusKey;
|
|
this.setData({
|
|
[`sjDingdanShuju.${key}`]: { ...EMPTY_TAB },
|
|
});
|
|
this.refreshCurrentListView();
|
|
},
|
|
|
|
async loadPendingCount() {
|
|
return this.loadOrderStats();
|
|
},
|
|
|
|
onPullDownRefresh() {
|
|
if (this.data.isLoading || this.data.isLoadingMore) {
|
|
this.setData({ scrollViewRefreshing: false });
|
|
return;
|
|
}
|
|
this._savedScrollTop = 0;
|
|
this.setData({ scrollViewRefreshing: true, listScrollTop: 0 });
|
|
this.resetCurrentStatusData();
|
|
this.loadCurrentStatusOrders(true);
|
|
},
|
|
|
|
onReachBottom() {
|
|
const key = this.data.currentStatusKey;
|
|
const tabData = this.data.sjDingdanShuju[key];
|
|
if (tabData.isLoading || !tabData.hasMore) return;
|
|
this.loadCurrentStatusOrders(false);
|
|
},
|
|
|
|
onLoadMoreTap() {
|
|
const key = this.data.currentStatusKey;
|
|
const tabData = this.data.sjDingdanShuju[key];
|
|
if (tabData.isLoading || !tabData.hasMore) return;
|
|
this.loadCurrentStatusOrders(false);
|
|
},
|
|
|
|
processOrderItem(item, zhuangtaiColor) {
|
|
const st = Number(item.zhuangtai);
|
|
const tagStyle = STATUS_TAG_STYLE[st] || { color: zhuangtaiColor || '#333', bg: '#F5F5F5' };
|
|
|
|
return {
|
|
...item,
|
|
zhuangtaiZh: getOrderStatusText(st),
|
|
zhuangtaiColor: tagStyle.color,
|
|
zhuangtaiBg: tagStyle.bg,
|
|
creat_time: item.creat_time || item.create_time || '',
|
|
};
|
|
},
|
|
|
|
goToSjDingdanXiangqing(e) {
|
|
const item = e.currentTarget.dataset.item;
|
|
if (!item) return;
|
|
this._skipShowRefresh = true;
|
|
const dataStr = encodeURIComponent(JSON.stringify(item));
|
|
wx.navigateTo({
|
|
url: `/pages/merchant-order-detail/merchant-order-detail?dingdanData=${dataStr}`,
|
|
});
|
|
},
|
|
|
|
onImageError() {},
|
|
}));
|
|
|