dingdanquanliucheng/frontend/mini-app/pages/manager/approve-detail/approve-detail.js
wsb1224 a0e5120c7d 修复小程序审批通过后剪切板仍无内容:内联构建采购文本避免时序问题
将采购信息构建逻辑从独立方法移入 _submitApproval 回调内,
直接从 orderInfo.items 原始数据构建,绕过 this.data.products
可能未就绪的时序问题;移除未使用的 _buildProcurementText 方法。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-23 01:08:51 +08:00

635 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 订单详情页面(审批 + 完整信息展示)
* 职责:展示订单完整信息(基础信息、费用明细、产品列表、收货信息、审批记录),
* 支持审批通过/退回,待审批状态下可选择下发工厂。
*/
var subscribe = require("../../../utils/subscribe");
function mapOrderStatus(status) {
var app = getApp();
return app.mapOrderStatus(status);
}
function getStatusBadge(status) {
var map = {
pending_approve: "badge-orange", cancel_pending: "badge-orange",
cancel_fulfillment_pending: "badge-orange",
approved: "badge-green", rejected: "badge-red",
pending_factory: "badge-blue", pending_driver: "badge-purple",
accepted: "badge-blue", picked_up: "badge-teal",
delivered: "badge-green", completed: "badge-green",
pending_settle: "badge-orange", settled: "badge-purple",
canceled: "badge-red",
};
return map[status] || "badge-gray";
}
function fmt(v) { return Number(v || 0).toFixed(2); }
Page({
data: {
statusBarHeight: 20,
taskId: null,
loading: true,
actionLoading: false,
message: "",
orderInfo: null,
products: [],
approveLogs: [],
logistics: null,
traceList: [],
factoryList: [],
selectedFactoryIndex: -1,
selectedFactoryId: null,
driverList: [],
selectedDriverIndex: -1,
selectedDriverId: null,
taskForm: {
pickup_address: "",
delivery_address: "",
pickup_content: "",
quantity: "1",
},
},
async onLoad(options) {
var app = getApp();
this.setData({
statusBarHeight: app.globalData.statusBarHeight,
taskId: Number(options.id || 0),
});
await this.loadDetail();
this.loadFactoryList();
this.loadDriverList();
},
async loadDetail() {
var app = getApp();
this.setData({ loading: true, message: "" });
try {
var data = await app.request({ url: "/api/orders/" + this.data.taskId, method: "GET" });
var sale = Number(data.sale_price_total || 0);
var cost = Number(data.cost_price_total || 0);
var rebate = Number(data.rebate_total || 0);
var freight = Number(data.freight_total || 0);
var tax = Number(data.tax_total || 0);
var commission = Number(data.commission_amount || 0);
var profit = Number(data.profit_total || 0);
var profitRate = sale > 0 ? (profit / sale * 100).toFixed(1) + "%" : "-";
// 费用明细:有值才显示
var feeItems = [
{ label: "合同金额", value: fmt(data.contract_amount), isIncome: true },
{ label: "成本", value: fmt(cost) },
];
if (rebate > 0) feeItems.push({ label: "回扣", value: fmt(rebate) });
if (freight > 0) feeItems.push({ label: "运费", value: fmt(freight) });
if (tax > 0) feeItems.push({ label: "税费", value: fmt(tax) });
if (commission > 0) feeItems.push({ label: "佣金", value: fmt(commission) });
feeItems.push({ label: "利润", value: fmt(profit), isProfit: true });
// 产品明细(从 data.items 构建,包含规格/需求规格/单位等完整字段)
var rawItems = data.items || [];
var products = [];
for (var i = 0; i < rawItems.length; i++) {
var ci = rawItems[i];
if (ci.product_name) {
products.push({
name: ci.product_name,
spec: ci.specification || "",
demandSpec: ci.demand_specification || "",
qty: ci.quantity || 0,
unit: ci.unit || "",
salePrice: fmt(ci.sale_price),
costAmount: fmt(Number(ci.quantity || 0) * Number(ci.cost_price || 0)),
});
}
}
// 审批记录
var approveLogs = data.approve_logs || [];
// 物流信息
var logistics = (data.logistics_info && data.logistics_info.task) || null;
this.setData({
orderInfo: Object.assign({}, data, {
statusText: mapOrderStatus(data.order_status),
badgeClass: getStatusBadge(data.order_status),
profitTotalText: fmt(profit),
profitRate: profitRate,
profitClass: profit >= 0 ? "profit-positive" : "profit-negative",
profitArrow: profit >= 0 ? "↑" : "↓",
feeItems: feeItems,
}),
products: products,
approveLogs: approveLogs,
logistics: logistics,
traceList: [],
});
// 加载物流轨迹
if (logistics && logistics.tracking_number) {
this.loadTrace();
}
// 待工厂状态:自动填充任务表单
if (data.order_status === "pending_factory") {
this.setData({
taskForm: {
pickup_address: data.factory_name || "",
delivery_address: data.customer_address || "",
pickup_content: data.customer_name ? data.customer_name + " 订单货物" : "",
quantity: "1",
},
});
}
} catch (error) {
this.setData({ message: error.message || "加载失败" });
} finally {
this.setData({ loading: false });
}
},
async loadTrace() {
var app = getApp();
try {
var result = await app.request({
url: "/api/logistics/" + this.data.taskId + "/trace",
method: "GET",
});
var traceList = (result && result.trace_list) || [];
this.setData({ traceList: traceList });
} catch (e) {
console.error("加载物流轨迹失败:", e);
}
},
async loadFactoryList() {
var app = getApp();
try {
var data = await app.request({
url: "/api/suppliers?supplier_type=factory&status=1&page_size=100",
method: "GET",
});
var list = data.list || data || [];
this.setData({ factoryList: list });
} catch (e) {
console.error("加载工厂列表失败:", e);
}
},
onFactoryChange: function (e) {
var idx = Number(e.detail.value);
var factory = this.data.factoryList[idx];
if (factory) {
this.setData({
selectedFactoryIndex: idx,
selectedFactoryId: factory.supplier_id || factory.supplierId || null,
});
}
},
async loadDriverList() {
var app = getApp();
try {
var data = await app.request({ url: "/api/system/users/drivers", method: "GET" });
var list = data.list || data || [];
this.setData({ driverList: list });
} catch (e) {
console.error("加载司机列表失败:", e);
}
},
onDriverChange: function (e) {
var idx = Number(e.detail.value);
var driver = this.data.driverList[idx];
if (driver) {
this.setData({
selectedDriverIndex: idx,
selectedDriverId: driver.user_id || driver.id || null,
});
}
},
handleApprove: function (event) {
var that = this;
var result = event.currentTarget.dataset.result;
var orderInfo = this.data.orderInfo;
if (!orderInfo) return;
var isCancelFlow = ["cancel_pending", "cancel_fulfillment_pending"].indexOf(orderInfo.order_status) >= 0;
var targetUrl = isCancelFlow
? "/api/orders/" + orderInfo.order_id + "/cancel-approve"
: "/api/orders/" + orderInfo.order_id + "/approve";
if (result === "pass") {
// 通过:直接确认
var confirmMsg = isCancelFlow ? "确认同意取消此订单?" : "确认审批通过?";
wx.showModal({
title: "确认通过",
content: confirmMsg,
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
var payload = { approve_result: result, approve_opinion: "同意" };
// 如果是待审批状态且未自发附加工厂ID和司机ID
if (!isCancelFlow && orderInfo.order_status === "pending_approve" && !orderInfo.tracking_number) {
if (that.data.selectedFactoryId) {
payload.factory_id = that.data.selectedFactoryId;
}
if (that.data.selectedDriverId) {
payload.driver_id = that.data.selectedDriverId;
}
}
that._submitApproval(targetUrl, payload);
},
});
} else {
// 退回:弹出输入框填写原因
wx.showModal({
title: "退回原因",
editable: true,
placeholderText: "请输入退回原因(可选)",
confirmColor: "#be123c",
success: function (res) {
if (!res.confirm) return;
var opinion = res.content || "退回";
that._submitApproval(targetUrl, { approve_result: result, approve_opinion: opinion });
},
});
}
},
_submitApproval: async function (targetUrl, payload) {
var that = this;
var app = getApp();
that.setData({ actionLoading: true, message: "" });
// 请求订阅消息授权
await subscribe.ensureSubscribePermission("approve");
app.request({
url: targetUrl, method: "POST",
data: payload,
}).then(function (res) {
if (payload.approve_result === "pass") {
// 从原始数据直接构建采购信息,避免 this.data 时序问题
var orderData = that.data.orderInfo;
var text = "";
if (orderData) {
var items = orderData.items || [];
var lines = [];
for (var i = 0; i < items.length; i++) {
var ci = items[i];
if (!ci.product_name) continue;
lines.push((lines.length + 1) + ". " + ci.product_name);
if (ci.specification) lines.push(" 规格: " + ci.specification);
if (ci.demand_specification) lines.push(" 需求规格: " + ci.demand_specification);
if (ci.quantity) lines.push(" 数量: " + ci.quantity + (ci.unit || ""));
}
if (orderData.remark) lines.push("备注: " + orderData.remark);
if (orderData.customer_demand) lines.push("客户需求: " + orderData.customer_demand);
text = lines.join("\n");
}
if (text) {
wx.setClipboardData({ data: text });
} else {
wx.showToast({ title: "审批通过", icon: "success" });
}
} else {
wx.showToast({ title: "已退回", icon: "success" });
}
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "操作失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
// 任务表单输入
onTaskFormInput: function (e) {
var field = e.currentTarget.dataset.field;
var obj = {};
obj["taskForm." + field] = e.detail.value;
this.setData(obj);
},
// 提交审核(草稿/已驳回 → 待审批)
handleSubmitReview: function () {
var that = this;
var app = getApp();
wx.showModal({
title: "确认提交",
content: "确认提交此订单进入审核?",
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/orders/" + that.data.orderInfo.order_id + "/submit",
method: "POST",
}).then(function () {
wx.showToast({ title: "已提交审核", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "提交失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
});
},
// 推进待工厂(已审批 → 待工厂处理)
handlePushToFactory: function () {
var that = this;
var app = getApp();
var orderInfo = this.data.orderInfo;
if (!orderInfo) return;
// 自发订单:直接完成
if (orderInfo.tracking_number) {
wx.showModal({
title: "确认",
content: "马甸工厂自发,审批通过后将直接完成订单",
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
that._changeStatus("completed", "订单已直接完成");
},
});
return;
}
if (!that.data.selectedFactoryId) {
wx.showToast({ title: "请选择工厂", icon: "none" });
return;
}
if (!that.data.selectedDriverId) {
wx.showToast({ title: "请选择司机", icon: "none" });
return;
}
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/orders/" + orderInfo.order_id + "/status",
method: "POST",
data: { target_status: "pending_factory", factory_id: that.data.selectedFactoryId },
}).then(function () {
return app.request({
url: "/api/logistics/tasks",
method: "POST",
data: {
order_id: orderInfo.order_id,
driver_id: Number(that.data.selectedDriverId),
pickup_address: orderInfo.factory_name || "",
delivery_address: orderInfo.customer_address || "",
pickup_content: orderInfo.customer_name ? orderInfo.customer_name + " 订单货物" : "",
quantity: 1,
factory_id: that.data.selectedFactoryId,
},
});
}).then(function () {
wx.showToast({ title: "已推进待工厂并分配司机", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "操作失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
// 分配任务(待工厂处理 → 待司机接单)
handleAssignTask: function () {
var that = this;
var app = getApp();
var orderInfo = this.data.orderInfo;
if (!orderInfo) return;
if (!that.data.selectedDriverId) {
wx.showToast({ title: "请选择司机", icon: "none" });
return;
}
var form = that.data.taskForm;
if (!form.pickup_address.trim()) {
wx.showToast({ title: "请填写取货地址", icon: "none" });
return;
}
if (!form.delivery_address.trim()) {
wx.showToast({ title: "请填写送货地址", icon: "none" });
return;
}
if (!form.pickup_content.trim()) {
wx.showToast({ title: "请填写取货内容", icon: "none" });
return;
}
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/logistics/tasks",
method: "POST",
data: {
order_id: orderInfo.order_id,
driver_id: Number(that.data.selectedDriverId),
pickup_address: form.pickup_address.trim(),
delivery_address: form.delivery_address.trim(),
pickup_content: form.pickup_content.trim(),
quantity: Number(form.quantity) || 1,
factory_id: orderInfo.factory_id || undefined,
},
}).then(function () {
wx.showToast({ title: "任务分配成功", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "分配失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
// 分配/重新分配司机(待司机接单)
handleAssignDriver: function () {
var that = this;
var app = getApp();
var orderInfo = this.data.orderInfo;
if (!orderInfo) return;
if (!that.data.selectedDriverId) {
wx.showToast({ title: "请选择司机", icon: "none" });
return;
}
var doAssign = function () {
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/logistics/tasks",
method: "POST",
data: {
order_id: orderInfo.order_id,
driver_id: Number(that.data.selectedDriverId),
pickup_address: orderInfo.factory_name || "",
delivery_address: orderInfo.customer_address || "",
pickup_content: orderInfo.customer_name ? orderInfo.customer_name + " 订单货物" : "",
quantity: 1,
factory_id: orderInfo.factory_id || undefined,
},
}).then(function () {
wx.showToast({ title: "司机分配成功", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "分配失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
};
// 如果已有物流任务,先取消
if (that.data.logistics && that.data.logistics.task_id) {
wx.showModal({
title: "重新分配",
content: "确定要重新分配司机吗?当前物流任务将被取消。",
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
that.setData({ actionLoading: true });
app.request({
url: "/api/logistics/tasks/" + that.data.logistics.task_id + "/cancel",
method: "POST",
data: { cancel_reason: "管理员重新分配司机" },
}).then(function () {
return doAssign();
}).catch(function (error) {
that.setData({ message: error.message || "取消物流任务失败", actionLoading: false });
});
},
});
} else {
doAssign();
}
},
// 简单状态变更
handleSimpleTransition: function (e) {
var that = this;
var target = e.currentTarget.dataset.target;
var labelMap = {
picked_up: "确认揽货",
delivered: "确认送达",
production: "标记生产",
shipped: "标记发货",
completed: "标记完成",
pending_settle: "待结算",
};
wx.showModal({
title: "确认操作",
content: "确认" + (labelMap[target] || "变更状态") + "",
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
that._changeStatus(target, labelMap[target] || "操作成功");
},
});
},
_changeStatus: function (targetStatus, successMsg) {
var that = this;
var app = getApp();
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/orders/" + that.data.orderInfo.order_id + "/status",
method: "POST",
data: { target_status: targetStatus },
}).then(function () {
wx.showToast({ title: successMsg || "操作成功", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "操作失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
// 申请取消
handleApplyCancel: function () {
var that = this;
wx.showModal({
title: "申请取消",
editable: true,
placeholderText: "请输入取消原因(必填)",
confirmColor: "#be123c",
success: function (res) {
if (!res.confirm) return;
var reason = (res.content || "").trim();
if (!reason) {
wx.showToast({ title: "请输入取消原因", icon: "none" });
return;
}
var app = getApp();
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/orders/" + that.data.orderInfo.order_id + "/cancel",
method: "POST",
data: { cancel_reason: reason },
}).then(function () {
wx.showToast({ title: "已发起取消", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "取消失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
});
},
// 结算提成
handleSettle: function () {
var that = this;
var app = getApp();
wx.showModal({
title: "确认结算",
content: "确认结算此订单提成?",
confirmColor: "#2563eb",
success: function (res) {
if (!res.confirm) return;
that.setData({ actionLoading: true, message: "" });
app.request({
url: "/api/orders/" + that.data.orderInfo.order_id + "/settle",
method: "POST",
}).then(function () {
wx.showToast({ title: "提成已结算", icon: "success" });
return that.loadDetail();
}).catch(function (error) {
that.setData({ message: error.message || "结算失败" });
}).finally(function () {
that.setData({ actionLoading: false });
});
},
});
},
handleBack: function () { wx.navigateBack({ delta: 1 }); },
// 分享给好友
onShareAppMessage: function () {
var orderInfo = this.data.orderInfo;
var title = orderInfo ? "订单详情 " + (orderInfo.order_no || "") : "订单详情";
return {
title: title,
path: "/pages/manager/approve-detail/approve-detail?id=" + this.data.taskId,
};
},
// 分享到朋友圈
onShareTimeline: function () {
var orderInfo = this.data.orderInfo;
var title = orderInfo ? "订单详情 " + (orderInfo.order_no || "") : "订单详情";
return {
title: title,
query: "id=" + this.data.taskId,
};
},
});