plDriverPlanCopy.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /**
  2. * 司机运输计划单「复制发群」纯文本(不含附件)
  3. * 规格:docs/superpowers/specs/2026-10-13-mini-pl-driver-plan-copy-product-lines-design.md
  4. * (头信息/区块/边界继承 2026-10-12 enrich 设计)
  5. */
  6. const DASH = '—'
  7. const FIELD_GAP = ' '
  8. function stopTypeOf(stop) {
  9. return String(stop?.stopType || stop?.stop_type || '').trim()
  10. }
  11. function customerNameOf(stop) {
  12. const name = String(stop?.customerName || stop?.customer_name || '').trim()
  13. return name || DASH
  14. }
  15. function textOrDash(value) {
  16. const s = String(value ?? '').trim()
  17. return s || DASH
  18. }
  19. function formatQtyWithUnit(raw, unit) {
  20. if (raw == null || raw === '') return DASH
  21. const qty = String(raw).trim()
  22. if (!qty) return DASH
  23. const u = String(unit || '').trim()
  24. return u ? `${qty} ${u}` : qty
  25. }
  26. function planQtyOf(product) {
  27. if (product?.planQty != null && product.planQty !== '') return product.planQty
  28. if (product?.plan_qty != null && product.plan_qty !== '') return product.plan_qty
  29. if (product?.quantity != null && product.quantity !== '') return product.quantity
  30. return null
  31. }
  32. function actualQtyOf(product) {
  33. if (product?.actualQty != null && product.actualQty !== '') return product.actualQty
  34. if (product?.actual_qty != null && product.actual_qty !== '') return product.actual_qty
  35. return null
  36. }
  37. /** 产品三行:产品信息 / 计划数量 / 实际数量(组间不空行) */
  38. function formatProductLines(product) {
  39. const name = textOrDash(product?.productName ?? product?.product_name)
  40. const model = textOrDash(product?.model)
  41. const pack = textOrDash(product?.packageSpec ?? product?.package_spec)
  42. const unit = product?.unit
  43. const planPart = formatQtyWithUnit(planQtyOf(product), unit)
  44. const actualPart = formatQtyWithUnit(actualQtyOf(product), unit)
  45. return [
  46. `- 产品信息:${name}${FIELD_GAP}${model}${FIELD_GAP}${pack}`,
  47. `- 计划数量:${planPart}`,
  48. `- 实际数量:${actualPart}`
  49. ]
  50. }
  51. /**
  52. * 追加「送货信息:」或「装货信息:」区块。
  53. * 无站点 → 标题下单独一行 —
  54. * 有站点无产品 → 客户名:下一行 - —
  55. */
  56. function appendInfoSection(lines, title, stops) {
  57. lines.push(title)
  58. if (!stops.length) {
  59. lines.push(DASH)
  60. return
  61. }
  62. stops.forEach((stop) => {
  63. lines.push(`${customerNameOf(stop)}:`)
  64. const products = Array.isArray(stop?.products) ? stop.products : []
  65. if (!products.length) {
  66. lines.push(`- ${DASH}`)
  67. return
  68. }
  69. products.forEach((product) => {
  70. formatProductLines(product).forEach((line) => lines.push(line))
  71. })
  72. })
  73. }
  74. /**
  75. * @param {object} page driverPlanApi.get 详情(可含 copySeqNo)
  76. * @returns {string}
  77. */
  78. export function buildDriverPlanCopyText(page = {}) {
  79. const stops = Array.isArray(page?.stops) ? page.stops : []
  80. const loadStops = stops.filter((s) => stopTypeOf(s) === 'load')
  81. const deliveryStops = stops.filter((s) => stopTypeOf(s) === 'delivery')
  82. const rawSeq = page?.copySeqNo ?? page?.copy_seq_no
  83. const seqText = rawSeq != null && rawSeq !== '' ? String(rawSeq) : DASH
  84. const lines = [
  85. `序号:${seqText}`,
  86. `计划编号:${textOrDash(page?.planNo ?? page?.plan_no)}`,
  87. `车辆:${textOrDash(page?.licensePlate ?? page?.license_plate)}`
  88. ]
  89. appendInfoSection(lines, '送货信息:', deliveryStops)
  90. appendInfoSection(lines, '装货信息:', loadStops)
  91. return lines.join('\n')
  92. }
  93. /** 复制到剪贴板;成功返回 true */
  94. export function copyDriverPlanToClipboard(page) {
  95. const text = buildDriverPlanCopyText(page)
  96. if (!text) {
  97. uni.showToast({ title: '暂无可复制内容', icon: 'none' })
  98. return Promise.resolve(false)
  99. }
  100. return new Promise((resolve) => {
  101. uni.setClipboardData({
  102. data: text,
  103. success: () => {
  104. uni.showToast({ title: '已复制', icon: 'success' })
  105. resolve(true)
  106. },
  107. fail: () => {
  108. uni.showToast({ title: '复制失败', icon: 'none' })
  109. resolve(false)
  110. }
  111. })
  112. })
  113. }