const PRINT_TITLE = "销售订单"; const formatDisplayDate = (value) => { if (!value) return ""; const date = new Date(value); if (Number.isNaN(date.getTime())) return String(value); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}/${month}/${day}`; }; const getCurrentDateTime = () => { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}/${month}/${day}`; }; const escapeHtml = (value) => String(value ?? "") .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); const toNumber = (value) => { const num = Number(value); return Number.isFinite(num) ? num : 0; }; const formatMoney = (value) => { const num = toNumber(value); return num.toFixed(2); }; const formatArea = (value) => { const num = toNumber(value); return num ? num.toFixed(2) : ""; }; const formatQty = (value) => { const num = toNumber(value); return num ? String(num) : ""; }; const getItemAmount = (item) => { const fromPrice = toNumber(item?.taxInclusiveUnitPrice) * toNumber(item?.quantity); const amount = toNumber(item?.taxInclusiveTotalPrice || item?.amount || fromPrice); return amount; }; const getItemArea = (item) => toNumber(item?.area || item?.settleTotalArea || item?.actualTotalArea); const getDeliveryAddress = (data) => data?.companyAddress || data?.deliveryAddress || data?.shippingAddress || data?.address || data?.shipAddress || ""; const normalizeRequirementText = (value) => { const text = String(value ?? "").trim(); if (!text) return ""; return text .replace(/^加工要求和备注[::]\s*/g, "") .replace(/^加工要求[::]\s*/g, "") .replace(/^备注[::]\s*/g, ""); }; const extractOtherFees = (data, items) => { const source = []; if (Array.isArray(data?.otherFees)) source.push(...data.otherFees); if (Array.isArray(data?.otherAmounts)) source.push(...data.otherAmounts); if (Array.isArray(data?.otherAmountList)) source.push(...data.otherAmountList); if (Array.isArray(data?.otherAmountProjects)) source.push(...data.otherAmountProjects); if (Array.isArray(data?.salesProductProcessList)) source.push(...data.salesProductProcessList); (Array.isArray(items) ? items : []).forEach((item) => { if (Array.isArray(item?.salesProductProcessList)) source.push(...item.salesProductProcessList); if (Array.isArray(item?.otherAmounts)) source.push(...item.otherAmounts); }); const map = new Map(); source.forEach((fee) => { const name = String(fee?.feeName || fee?.processName || fee?.name || fee?.itemName || "").trim(); if (!name) return; const quantity = toNumber(fee?.quantity || fee?.num); const unitPrice = toNumber(fee?.unitPrice || fee?.price); const amount = toNumber(fee?.amount || fee?.totalPrice) || (quantity && unitPrice ? quantity * unitPrice : 0); const key = name; if (!map.has(key)) { map.set(key, { name, quantity: 0, unitPrice: 0, amount: 0 }); } const row = map.get(key); row.quantity += quantity; row.unitPrice = unitPrice || row.unitPrice; row.amount += amount; }); return Array.from(map.values()); }; const renderOtherFeeRows = (rows) => { const list = Array.isArray(rows) ? rows : []; if (list.length === 0) { return ``; } return list .map((row) => { const name = escapeHtml(row.name); const unitPrice = row.unitPrice ? formatMoney(row.unitPrice) : ""; const quantity = row.quantity ? String(row.quantity) : ""; const amount = row.amount ? formatMoney(row.amount) : ""; return `${name}${unitPrice}${quantity}${amount}`; }) .join(""); }; const splitItemsByPage = (items, pageSize) => { const list = Array.isArray(items) ? items : []; if (list.length === 0) return [[]]; const pages = []; for (let i = 0; i < list.length; i += pageSize) { pages.push(list.slice(i, i + pageSize)); } return pages; }; const renderRows = (items, startIndex) => { const list = Array.isArray(items) ? items : []; if (list.length === 0) { return ` 暂无明细 `; } return list .map((item, idx) => { const width = escapeHtml(item?.width); const height = escapeHtml(item?.height); const sizeText = width || height ? `${width}*${height}` : ""; const unitPrice = formatMoney(item?.taxInclusiveUnitPrice || item?.unitPrice); const amount = formatMoney(getItemAmount(item)); return ` ${startIndex + idx + 1} ${escapeHtml(item?.floorCode)} ${sizeText} ${formatQty(item?.quantity)} ${formatArea(item?.area || item?.settleTotalArea || item?.actualTotalArea)} ${unitPrice} ${amount} ${escapeHtml(item?.processRequirement)} `; }) .join(""); }; export const printSalesOrder = (orderData) => { const data = orderData ?? {}; const items = Array.isArray(data.items) ? data.items : []; const pageSize = 15; const pages = splitItemsByPage(items, pageSize); const totalPages = pages.length; const subtotalQuantity = toNumber(data.subtotalQuantity); const subtotalArea = toNumber(data.subtotalArea); const subtotalAmount = toNumber(data.subtotalAmount); const totalQuantity = toNumber(data.totalQuantity) || items.reduce((sum, item) => sum + toNumber(item?.quantity), 0); const totalArea = toNumber(data.totalArea) || items.reduce((sum, item) => sum + getItemArea(item), 0); const totalAmount = toNumber(data.totalAmount) || items.reduce((sum, item) => sum + getItemAmount(item), 0); const otherFees = extractOtherFees(data, items); const printWindow = window.open("", "_blank", "width=1200,height=900"); if (!printWindow) { throw new Error("浏览器拦截了弹窗,请允许弹窗后重试"); } const html = ` ${PRINT_TITLE} ${pages .map((pageItems, pageIndex) => { const isLastPage = pageIndex === totalPages - 1; const startIndex = pageIndex * pageSize; return `
${escapeHtml(data.companyName || "鹤壁天沐钢化玻璃厂")}
销售订单
客户名称: ${escapeHtml(data.customerName)} 项目名称: ${escapeHtml(data.projectName)} 业 务 员: ${escapeHtml(data.salesman)}
制单日期: ${escapeHtml(formatDisplayDate(data.executionDate || data.orderMakerDate || data.registerDate || data.entryDate))} 交货日期: ${escapeHtml(formatDisplayDate(data.deliveryDate))}
送货地址: ${escapeHtml(getDeliveryAddress(data))}
${renderRows(pageItems, startIndex)} ${ isLastPage ? ` ` : ` ` }
序号 楼层编号 宽(弧长)*高 数量 结算面积 单价 金额 加工要求
产品名称: ${escapeHtml(data.productName || items[0]?.productDescription)} 订单编号: ${escapeHtml(data.salesContractNo)}
小计: ${subtotalQuantity || totalQuantity || ""} ${subtotalArea ? subtotalArea.toFixed(2) : totalArea ? totalArea.toFixed(2) : ""} ${formatMoney(subtotalAmount || totalAmount)}
合计: ${totalQuantity || ""} ${totalArea ? totalArea.toFixed(2) : ""} ${formatMoney(totalAmount)}
其他费用 单价 数量 金额
加工要求和备注:
${renderOtherFeeRows(otherFees)}
${escapeHtml(normalizeRequirementText(data.remakes || data.remarks || data.orderProcessRequirement))}
总金额: ${escapeHtml(data.totalAmountDisplay || `${formatMoney(totalAmount)}元`)}
下页续...
${ isLastPage ? `
客户签名:
` : "" }
`; }) .join("")} `; printWindow.document.write(html); printWindow.document.close(); printWindow.onload = () => { setTimeout(() => { printWindow.focus(); printWindow.print(); printWindow.close(); }, 300); }; };