Преглед на файлове

feat(miniprogram): enrich driver plan copy-to-group text

Show vehicle plate and compact product lines under delivery/load
sections segmented by customer, per the 2026-10-12 design.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong преди 2 седмици
родител
ревизия
fc840d1cbb
променени са 1 файла, в които са добавени 65 реда и са изтрити 42 реда
  1. 65 42
      miniprogram/utils/plDriverPlanCopy.js

+ 65 - 42
miniprogram/utils/plDriverPlanCopy.js

@@ -1,8 +1,10 @@
 /**
  * 司机运输计划单「复制发群」纯文本(不含附件)
+ * 规格:docs/superpowers/specs/2026-10-12-mini-pl-driver-plan-copy-text-enrich-design.md
  */
 
 const DASH = '—'
+const FIELD_GAP = '  '
 
 function stopTypeOf(stop) {
   return String(stop?.stopType || stop?.stop_type || '').trim()
@@ -13,33 +15,77 @@ function customerNameOf(stop) {
   return name || DASH
 }
 
-function formatActualQtyLine(partyLabel, product) {
-  const unit = String(product?.unit || '').trim()
-  const raw = product?.actualQty ?? product?.actual_qty
-  let qtyPart = DASH
-  if (raw != null && raw !== '') {
-    qtyPart = String(raw)
-    if (unit) qtyPart = `${qtyPart} ${unit}`
-  }
-  return `${partyLabel}:${qtyPart}`
+function textOrDash(value) {
+  const s = String(value ?? '').trim()
+  return s || DASH
+}
+
+function formatQtyWithUnit(raw, unit) {
+  if (raw == null || raw === '') return DASH
+  const qty = String(raw).trim()
+  if (!qty) return DASH
+  const u = String(unit || '').trim()
+  return u ? `${qty} ${u}` : qty
+}
+
+function planQtyOf(product) {
+  if (product?.planQty != null && product.planQty !== '') return product.planQty
+  if (product?.plan_qty != null && product.plan_qty !== '') return product.plan_qty
+  if (product?.quantity != null && product.quantity !== '') return product.quantity
+  return null
+}
+
+function actualQtyOf(product) {
+  if (product?.actualQty != null && product.actualQty !== '') return product.actualQty
+  if (product?.actual_qty != null && product.actual_qty !== '') return product.actual_qty
+  return null
 }
 
-function appendQtySection(lines, title, qtyLines) {
+/** 产品紧凑行:- 名称  型号  包装  计划数量:…  实际数量:… */
+function formatProductLine(product) {
+  const name = textOrDash(product?.productName ?? product?.product_name)
+  const model = textOrDash(product?.model)
+  const pack = textOrDash(product?.packageSpec ?? product?.package_spec)
+  const unit = product?.unit
+  const planPart = formatQtyWithUnit(planQtyOf(product), unit)
+  const actualPart = formatQtyWithUnit(actualQtyOf(product), unit)
+  return (
+    `- ${name}${FIELD_GAP}${model}${FIELD_GAP}${pack}` +
+    `${FIELD_GAP}计划数量:${planPart}${FIELD_GAP}实际数量:${actualPart}`
+  )
+}
+
+/**
+ * 追加「送货信息:」或「装货信息:」区块。
+ * 无站点 → 标题下单独一行 —
+ * 有站点无产品 → 客户名:下一行 - —
+ */
+function appendInfoSection(lines, title, stops) {
   lines.push(title)
-  if (!qtyLines.length) {
+  if (!stops.length) {
     lines.push(DASH)
-  } else {
-    lines.push(...qtyLines)
+    return
   }
+  stops.forEach((stop) => {
+    lines.push(`${customerNameOf(stop)}:`)
+    const products = Array.isArray(stop?.products) ? stop.products : []
+    if (!products.length) {
+      lines.push(`- ${DASH}`)
+      return
+    }
+    products.forEach((product) => {
+      lines.push(formatProductLine(product))
+    })
+  })
 }
 
 /**
- * @param {object} page driverPlanApi.get 详情
+ * @param {object} page driverPlanApi.get 详情(可含 copySeqNo)
  * @returns {string}
  */
 export function buildDriverPlanCopyText(page = {}) {
   const stops = Array.isArray(page?.stops) ? page.stops : []
-  const loadStop = stops.find((s) => stopTypeOf(s) === 'load')
+  const loadStops = stops.filter((s) => stopTypeOf(s) === 'load')
   const deliveryStops = stops.filter((s) => stopTypeOf(s) === 'delivery')
 
   const rawSeq = page?.copySeqNo ?? page?.copy_seq_no
@@ -47,35 +93,12 @@ export function buildDriverPlanCopyText(page = {}) {
 
   const lines = [
     `序号:${seqText}`,
-    `计划编号:${String(page?.planNo || page?.plan_no || '').trim() || DASH}`,
-    `装货方:${loadStop ? customerNameOf(loadStop) : DASH}`
+    `计划编号:${textOrDash(page?.planNo ?? page?.plan_no)}`,
+    `车辆:${textOrDash(page?.licensePlate ?? page?.license_plate)}`
   ]
 
-  if (!deliveryStops.length) {
-    lines.push(`送货方#1:${DASH}`)
-  } else {
-    deliveryStops.forEach((stop, index) => {
-      lines.push(`送货方#${index + 1}:${customerNameOf(stop)}`)
-    })
-  }
-
-  const loadQtyLines = []
-  if (loadStop) {
-    const products = Array.isArray(loadStop.products) ? loadStop.products : []
-    products.forEach((product) => {
-      loadQtyLines.push(formatActualQtyLine('装货方', product))
-    })
-  }
-  appendQtySection(lines, '实际装货量:', loadQtyLines)
-
-  const deliveryQtyLines = []
-  deliveryStops.forEach((stop, index) => {
-    const products = Array.isArray(stop?.products) ? stop.products : []
-    products.forEach((product) => {
-      deliveryQtyLines.push(formatActualQtyLine(`送货方#${index + 1}`, product))
-    })
-  })
-  appendQtySection(lines, '实际送货量:', deliveryQtyLines)
+  appendInfoSection(lines, '送货信息:', deliveryStops)
+  appendInfoSection(lines, '装货信息:', loadStops)
 
   return lines.join('\n')
 }