pl-driver-summary.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import type { PlanDelivery, PlanLoad, PlanProduct, PlanStopProduct } from '@/api/pl'
  2. import {
  3. appendAmapNavLine,
  4. buildAmapNavigationUrlWithFallback
  5. } from '@/utils/amap/navigation'
  6. import { formatDate } from '@/utils/format'
  7. import { formatPlanProductListText } from '@/utils/pl-display'
  8. export type DriverSummaryStopBlock = {
  9. label: string
  10. customerName?: string
  11. stopTime?: string
  12. address?: string
  13. lng?: number | null
  14. lat?: number | null
  15. contact?: string
  16. notes?: string
  17. productLines: string[]
  18. }
  19. type DriverSummaryPlan = {
  20. planNo?: string
  21. licensePlate?: string
  22. pickupTime?: string
  23. planDate?: string
  24. personnelSummary?: string
  25. pickupAddress?: string
  26. pickupLng?: number | null
  27. pickupLat?: number | null
  28. pickupContact?: string
  29. pickupNotes?: string
  30. destinationAddress?: string
  31. destinationName?: string
  32. destinationLng?: number | null
  33. destinationLat?: number | null
  34. deliveryContact?: string
  35. destinationNotes?: string
  36. startPoint?: string
  37. endPoint?: string
  38. load?: PlanLoad | null
  39. deliveries?: PlanDelivery[] | null
  40. }
  41. function formatDriverStopProductLine(
  42. product: PlanStopProduct,
  43. getUnitLabel?: (unit: string) => string
  44. ) {
  45. return formatPlanProductListText(
  46. {
  47. productName: product.productName,
  48. model: product.model,
  49. packageSpec: product.packageSpec,
  50. unit: product.unit,
  51. quantity: product.planQty
  52. },
  53. getUnitLabel,
  54. { usePlannedQuantity: true }
  55. )
  56. }
  57. function formatPlanLevelProductLines(
  58. products: PlanProduct[],
  59. getUnitLabel?: (unit: string) => string
  60. ) {
  61. return products
  62. .map((product) => formatPlanProductListText(product, getUnitLabel, { usePlannedQuantity: true }))
  63. .filter(Boolean)
  64. }
  65. function appendDriverStopBlockLines(lines: string[], stop: DriverSummaryStopBlock) {
  66. lines.push(`【${stop.label} · ${stop.customerName || '—'}】`)
  67. if (stop.stopTime) {
  68. lines.push(`时间:${stop.stopTime}`)
  69. }
  70. if (stop.address) {
  71. lines.push(`地址:${stop.address}`)
  72. }
  73. appendAmapNavLine(
  74. lines,
  75. '导航',
  76. buildAmapNavigationUrlWithFallback({
  77. lng: stop.lng,
  78. lat: stop.lat,
  79. address: stop.address,
  80. name: stop.label
  81. })
  82. )
  83. if (stop.contact) {
  84. lines.push(`联系方式:${stop.contact}`)
  85. }
  86. if (stop.notes) {
  87. lines.push(`注意事项:${stop.notes}`)
  88. }
  89. if (stop.productLines.length) {
  90. stop.productLines.forEach((line) => lines.push(`产品:${line}`))
  91. } else {
  92. lines.push('产品:—')
  93. }
  94. }
  95. export function buildDriverStopBlocksFromPlan(
  96. plan?: DriverSummaryPlan | null,
  97. getUnitLabel?: (unit: string) => string
  98. ): DriverSummaryStopBlock[] {
  99. if (!plan) return []
  100. const blocks: DriverSummaryStopBlock[] = []
  101. const load = plan.load
  102. if (load) {
  103. blocks.push({
  104. label: '装货',
  105. customerName: load.customerName || undefined,
  106. stopTime: formatDate(load.loadTime) || undefined,
  107. address: load.address || undefined,
  108. lng: load.lng,
  109. lat: load.lat,
  110. contact: load.contact || undefined,
  111. notes: load.notes || undefined,
  112. productLines: (load.products || []).map((product) =>
  113. formatDriverStopProductLine(product, getUnitLabel)
  114. )
  115. })
  116. }
  117. for (const delivery of plan.deliveries || []) {
  118. const seq = delivery.seq != null ? Number(delivery.seq) : 0
  119. blocks.push({
  120. label: seq > 0 ? `送货 #${seq}` : '送货',
  121. customerName: delivery.customerName || undefined,
  122. stopTime: formatDate(delivery.deliveryTime) || undefined,
  123. address: delivery.address || undefined,
  124. lng: delivery.lng,
  125. lat: delivery.lat,
  126. contact: delivery.contact || undefined,
  127. notes: delivery.notes || undefined,
  128. productLines: (delivery.products || []).map((product) =>
  129. formatDriverStopProductLine(product, getUnitLabel)
  130. )
  131. })
  132. }
  133. return blocks
  134. }
  135. function buildLegacyDriverStopBlocks(
  136. plan: DriverSummaryPlan,
  137. overrides: {
  138. pickupAddress?: string
  139. pickupLng?: number | null
  140. pickupLat?: number | null
  141. pickupContact?: string
  142. pickupNotes?: string
  143. destinationAddress?: string
  144. destinationLng?: number | null
  145. destinationLat?: number | null
  146. deliveryContact?: string
  147. destinationNotes?: string
  148. startPoint?: string
  149. endPoint?: string
  150. },
  151. productLines: string[]
  152. ): DriverSummaryStopBlock[] {
  153. const pickupAddress =
  154. overrides.pickupAddress || plan.pickupAddress || overrides.startPoint || plan.startPoint
  155. const destinationAddress =
  156. overrides.destinationAddress ||
  157. plan.destinationAddress ||
  158. plan.destinationName ||
  159. overrides.endPoint ||
  160. plan.endPoint
  161. const blocks: DriverSummaryStopBlock[] = []
  162. if (pickupAddress) {
  163. blocks.push({
  164. label: '取货',
  165. customerName: plan.load?.customerName || undefined,
  166. stopTime: formatDate(plan.pickupTime) || undefined,
  167. address: pickupAddress,
  168. lng: overrides.pickupLng ?? plan.pickupLng,
  169. lat: overrides.pickupLat ?? plan.pickupLat,
  170. contact: overrides.pickupContact || plan.pickupContact || undefined,
  171. notes: overrides.pickupNotes || plan.pickupNotes || undefined,
  172. productLines: productLines.length ? productLines : []
  173. })
  174. }
  175. if (destinationAddress) {
  176. blocks.push({
  177. label: '送货',
  178. customerName: undefined,
  179. stopTime: undefined,
  180. address: destinationAddress,
  181. lng: overrides.destinationLng ?? plan.destinationLng,
  182. lat: overrides.destinationLat ?? plan.destinationLat,
  183. contact: overrides.deliveryContact || plan.deliveryContact || undefined,
  184. notes: overrides.destinationNotes || plan.destinationNotes || undefined,
  185. productLines: []
  186. })
  187. }
  188. return blocks
  189. }
  190. export function buildDriverSummaryFromPlan(options: {
  191. plan?: DriverSummaryPlan | null
  192. planNo?: string
  193. licensePlate?: string
  194. pickupTime?: string
  195. planDate?: string
  196. personnelSummary?: string
  197. driverUrl?: string
  198. products?: PlanProduct[]
  199. stopBlocks?: DriverSummaryStopBlock[]
  200. getUnitLabel?: (unit: string) => string
  201. pickupAddress?: string
  202. pickupLng?: number | null
  203. pickupLat?: number | null
  204. destinationAddress?: string
  205. destinationLng?: number | null
  206. destinationLat?: number | null
  207. pickupContact?: string
  208. pickupNotes?: string
  209. deliveryContact?: string
  210. destinationNotes?: string
  211. startPoint?: string
  212. endPoint?: string
  213. }) {
  214. const plan = options.plan || {}
  215. const plate = options.licensePlate || plan.licensePlate || '—'
  216. const lines = [`【${plate} - 运输计划】`]
  217. lines.push(`计划号:${options.planNo || plan.planNo || '—'}`)
  218. lines.push(`车牌:${plate}`)
  219. const time = formatDate(options.pickupTime || plan.pickupTime) || options.planDate || plan.planDate
  220. if (time) lines.push(`时间:${time}`)
  221. const productLines = formatPlanLevelProductLines(options.products || [], options.getUnitLabel)
  222. let stopBlocks =
  223. options.stopBlocks ||
  224. buildDriverStopBlocksFromPlan(plan, options.getUnitLabel)
  225. if (!stopBlocks.length) {
  226. stopBlocks = buildLegacyDriverStopBlocks(plan, options, productLines)
  227. }
  228. if (stopBlocks.length) {
  229. lines.push('')
  230. stopBlocks.forEach((stop, index) => {
  231. if (index > 0) lines.push('')
  232. appendDriverStopBlockLines(lines, stop)
  233. })
  234. } else if (productLines.length) {
  235. lines.push('')
  236. lines.push(`产品:${productLines.join(';')}`)
  237. }
  238. lines.push('')
  239. lines.push(`司机链接:${options.driverUrl || '—'}`)
  240. return lines.join('\n')
  241. }