Просмотр исходного кода

feat(web-admin): add batch print merge helpers for transport plans

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 3 месяцев назад
Родитель
Сommit
bbcb2b8936
1 измененных файлов с 109 добавлено и 0 удалено
  1. 109 0
      web-admin/src/utils/pl-batch-print.ts

+ 109 - 0
web-admin/src/utils/pl-batch-print.ts

@@ -0,0 +1,109 @@
+// web-admin/src/utils/pl-batch-print.ts
+import type { Plan, PlanProduct } from '@/api/pl'
+import type { PlPrintSlipCommand } from '@/utils/pl-display'
+import { canPrintSlipCommand } from '@/utils/pl-display'
+
+export type SlipPlanProduct = PlanProduct & { slipPlanNo?: string }
+
+export function normalizeCustomerName(name?: string | null) {
+  return String(name || '').trim()
+}
+
+export function canBatchPrintSlip(
+  plans: Array<Pick<Plan, 'planType' | 'customerName' | 'planDate'>>,
+  command: PlPrintSlipCommand
+): { ok: boolean; reason?: string } {
+  if (!plans?.length) return { ok: false, reason: '请先勾选运输计划' }
+
+  if (plans.length === 1) {
+    if (!canPrintSlipCommand(plans[0].planType, command)) {
+      return { ok: false, reason: '当前单据类型不支持打印该单据' }
+    }
+    return { ok: true }
+  }
+
+  if (command === 'inbound') {
+    if (!plans.every((p) => p.planType === 'inbound')) {
+      return { ok: false, reason: '合打入库单要求:均为入库类计划' }
+    }
+    const c = normalizeCustomerName(plans[0].customerName)
+    const d = plans[0].planDate
+    if (!c || !d || !plans.every((p) => normalizeCustomerName(p.customerName) === c && p.planDate === d)) {
+      return {
+        ok: false,
+        reason: '合打入库单要求:客户名称一致且计划日期一致,且均为入库类计划'
+      }
+    }
+    return { ok: true }
+  }
+
+  if (command === 'delivery') {
+    if (!plans.every((p) => p.planType === 'outbound')) {
+      return { ok: false, reason: '合打送(提)货单要求:均为出库类计划' }
+    }
+    const c = normalizeCustomerName(plans[0].customerName)
+    const d = plans[0].planDate
+    if (!c || !d || !plans.every((p) => normalizeCustomerName(p.customerName) === c && p.planDate === d)) {
+      return {
+        ok: false,
+        reason: '合打送(提)货单要求:客户名称一致且计划日期一致,且均为出库类计划'
+      }
+    }
+    return { ok: true }
+  }
+
+  if (command === 'subpack') {
+    if (!plans.every((p) => canPrintSlipCommand(p.planType, 'subpack'))) {
+      return { ok: false, reason: '分装单仅支持出库类计划' }
+    }
+    return { ok: true }
+  }
+
+  return { ok: false, reason: '未知单据类型' }
+}
+
+export function mergeBatchPrintRemarks(plans: Array<Pick<Plan, 'planNo' | 'remark'>>) {
+  return plans
+    .map((p) => {
+      const text = String(p.remark || '').trim()
+      if (!text) return ''
+      return `${p.planNo}:${text}`
+    })
+    .filter(Boolean)
+    .join('\n')
+}
+
+/** 备注写入 HTML 模版时换行 */
+export function formatRemarkForSlipHtml(remark?: string | null) {
+  return String(remark || '')
+    .replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/\n/g, '<br />')
+}
+
+/** 合打视图:首条为抬头基准;产品展开并打 slipPlanNo;清空车辆;备注合并 */
+export function buildBatchPrintPlanView(plans: Plan[]): Plan {
+  if (!plans.length) throw new Error('plans empty')
+  const base = { ...plans[0] }
+  const products: SlipPlanProduct[] = []
+  for (const p of plans) {
+    for (const prod of p.products || []) {
+      products.push({ ...prod, slipPlanNo: p.planNo })
+    }
+  }
+  base.products = products
+  base.remark = mergeBatchPrintRemarks(plans)
+  base.licensePlate = undefined
+  base.vehicleId = undefined
+  base.driverId = undefined
+  base.driverName = undefined
+  base.trailerNo = undefined
+  base.personnelSummary = undefined
+  return base
+}
+
+export function normalizePlanIds(planIdOrIds: string | string[]): string[] {
+  const ids = Array.isArray(planIdOrIds) ? planIdOrIds : [planIdOrIds]
+  return ids.map((id) => String(id || '').trim()).filter(Boolean)
+}