pl-batch-print.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // web-admin/src/utils/pl-batch-print.ts
  2. import type { Plan, PlanProduct } from '@/api/pl'
  3. import type { PlPrintSlipCommand } from '@/utils/pl-display'
  4. import { canPrintSlipCommand } from '@/utils/pl-display'
  5. export type SlipPlanProduct = PlanProduct & { slipPlanNo?: string }
  6. export function normalizeCustomerName(name?: string | null) {
  7. return String(name || '').trim()
  8. }
  9. export function canBatchPrintSlip(
  10. plans: Array<Pick<Plan, 'planType' | 'customerName' | 'planDate'>>,
  11. command: PlPrintSlipCommand
  12. ): { ok: boolean; reason?: string } {
  13. if (!plans?.length) return { ok: false, reason: '请先勾选运输计划' }
  14. if (plans.length === 1) {
  15. if (!canPrintSlipCommand(plans[0].planType, command)) {
  16. return { ok: false, reason: '当前单据类型不支持打印该单据' }
  17. }
  18. return { ok: true }
  19. }
  20. if (command === 'inbound') {
  21. if (!plans.every((p) => p.planType === 'inbound')) {
  22. return { ok: false, reason: '合打入库单要求:均为入库类计划' }
  23. }
  24. const c = normalizeCustomerName(plans[0].customerName)
  25. const d = plans[0].planDate
  26. if (!c || !d || !plans.every((p) => normalizeCustomerName(p.customerName) === c && p.planDate === d)) {
  27. return {
  28. ok: false,
  29. reason: '合打入库单要求:客户名称一致且计划日期一致,且均为入库类计划'
  30. }
  31. }
  32. return { ok: true }
  33. }
  34. if (command === 'delivery') {
  35. if (!plans.every((p) => p.planType === 'outbound')) {
  36. return { ok: false, reason: '合打送(提)货单要求:均为出库类计划' }
  37. }
  38. const c = normalizeCustomerName(plans[0].customerName)
  39. const d = plans[0].planDate
  40. if (!c || !d || !plans.every((p) => normalizeCustomerName(p.customerName) === c && p.planDate === d)) {
  41. return {
  42. ok: false,
  43. reason: '合打送(提)货单要求:客户名称一致且计划日期一致,且均为出库类计划'
  44. }
  45. }
  46. return { ok: true }
  47. }
  48. if (command === 'subpack') {
  49. if (!plans.every((p) => canPrintSlipCommand(p.planType, 'subpack'))) {
  50. return { ok: false, reason: '分装单仅支持出库类计划' }
  51. }
  52. return { ok: true }
  53. }
  54. return { ok: false, reason: '未知单据类型' }
  55. }
  56. export function mergeBatchPrintRemarks(plans: Array<Pick<Plan, 'planNo' | 'remark'>>) {
  57. return plans
  58. .map((p) => {
  59. const text = String(p.remark || '').trim()
  60. if (!text) return ''
  61. return `${p.planNo}:${text}`
  62. })
  63. .filter(Boolean)
  64. .join('\n')
  65. }
  66. /** 备注写入 HTML 模版时换行 */
  67. export function formatRemarkForSlipHtml(remark?: string | null) {
  68. return String(remark || '')
  69. .replace(/&/g, '&amp;')
  70. .replace(/</g, '&lt;')
  71. .replace(/>/g, '&gt;')
  72. .replace(/\n/g, '<br />')
  73. }
  74. /** 合打视图:首条为抬头基准;产品展开并打 slipPlanNo;清空车辆;备注合并 */
  75. export function buildBatchPrintPlanView(plans: Plan[]): Plan {
  76. if (!plans.length) throw new Error('plans empty')
  77. const base = { ...plans[0] }
  78. const products: SlipPlanProduct[] = []
  79. for (const p of plans) {
  80. for (const prod of p.products || []) {
  81. products.push({ ...prod, slipPlanNo: p.planNo })
  82. }
  83. }
  84. base.products = products
  85. base.remark = mergeBatchPrintRemarks(plans)
  86. base.licensePlate = undefined
  87. base.vehicleId = undefined
  88. base.driverId = undefined
  89. base.driverName = undefined
  90. base.trailerNo = undefined
  91. base.personnelSummary = undefined
  92. return base
  93. }
  94. export function normalizePlanIds(planIdOrIds: string | string[]): string[] {
  95. const ids = Array.isArray(planIdOrIds) ? planIdOrIds : [planIdOrIds]
  96. return ids.map((id) => String(id || '').trim()).filter(Boolean)
  97. }