db-site-summary.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import type { InventoryRecord } from '@/api/db/inventory'
  2. import type { PlanDelivery, PlanLoad, PlanStopProduct } from '@/api/pl'
  3. import { formatDate } from '@/utils/format'
  4. import { isPlInternalCustomerName } from '@/utils/pl-internal-customer'
  5. const SITE_INSTRUCTION = '说明:请打开链接上传现场附件并填写备注。'
  6. export type SiteSummaryStopBlock = {
  7. label: string
  8. customerName?: string
  9. businessType?: string
  10. address?: string
  11. productLines: string[]
  12. }
  13. export type SiteSummaryRecord = {
  14. productName?: string
  15. productText?: string
  16. batchNo?: string
  17. planNo?: string
  18. siteUrl?: string
  19. businessType?: string
  20. siteFeedbackRemark?: string
  21. siteFeedbackTime?: string
  22. }
  23. function formatSiteSummaryProductLine(record: SiteSummaryRecord) {
  24. return record.productText || record.productName || '—'
  25. }
  26. function isSegmentSiteRecord(record: SiteSummaryRecord) {
  27. return (record.businessType || '').includes('按段')
  28. }
  29. function formatStopProductLine(product: PlanStopProduct) {
  30. const name = (product.productName || '').trim() || '—'
  31. const qty = product.planQty
  32. const unit = (product.unit || '吨').trim()
  33. if (qty == null) return name
  34. return `${name} ${qty}${unit}`
  35. }
  36. function isSiteVisibleStop(customerName?: string | null, generateDibang?: number | null) {
  37. return isPlInternalCustomerName(customerName) && Number(generateDibang || 0) === 1
  38. }
  39. export function buildSiteStopBlocksFromPlan(
  40. plan?: {
  41. load?: PlanLoad | null
  42. deliveries?: PlanDelivery[] | null
  43. } | null
  44. ): SiteSummaryStopBlock[] {
  45. if (!plan) return []
  46. const blocks: SiteSummaryStopBlock[] = []
  47. const load = plan.load
  48. if (load && isSiteVisibleStop(load.customerName, load.generateDibang)) {
  49. blocks.push({
  50. label: '装货',
  51. customerName: load.customerName || undefined,
  52. businessType: load.dibangDirection || undefined,
  53. address: load.address || undefined,
  54. productLines: (load.products || []).map(formatStopProductLine).filter(Boolean)
  55. })
  56. }
  57. for (const delivery of plan.deliveries || []) {
  58. if (!isSiteVisibleStop(delivery.customerName, delivery.generateDibang)) continue
  59. const seq = delivery.seq != null ? Number(delivery.seq) : 0
  60. blocks.push({
  61. label: seq > 0 ? `送货 #${seq}` : '送货',
  62. customerName: delivery.customerName || undefined,
  63. businessType: delivery.dibangDirection || undefined,
  64. address: delivery.address || undefined,
  65. productLines: (delivery.products || []).map(formatStopProductLine).filter(Boolean)
  66. })
  67. }
  68. return blocks
  69. }
  70. function appendSiteRecordCardLines(
  71. lines: string[],
  72. record: SiteSummaryRecord,
  73. options: { showHeadline?: boolean }
  74. ) {
  75. const headline = (record.productName || '').trim()
  76. const productText = formatSiteSummaryProductLine(record)
  77. if (options.showHeadline && headline) {
  78. lines.push(headline)
  79. }
  80. if (record.businessType && record.businessType !== '—') {
  81. lines.push(`业务类型:${record.businessType}`)
  82. }
  83. if (record.siteFeedbackTime && record.siteFeedbackTime !== '—') {
  84. lines.push(`保存时间:${record.siteFeedbackTime}`)
  85. }
  86. if (record.batchNo) {
  87. lines.push(`出入库单号:${record.batchNo}`)
  88. }
  89. if (productText && productText !== '—' && productText !== headline) {
  90. lines.push(`产品:${productText}`)
  91. }
  92. if (record.siteFeedbackRemark && record.siteFeedbackRemark !== '—') {
  93. lines.push(`现场备注:${record.siteFeedbackRemark}`)
  94. }
  95. lines.push(`现场链接:${record.siteUrl}`)
  96. }
  97. function formatSiteDibangDirectionLabel(direction?: string | null) {
  98. const value = (direction || '').trim()
  99. if (!value || value === 'none') return ''
  100. if (value === 'outbound') return '出库'
  101. if (value === 'inbound') return '入库'
  102. return value
  103. }
  104. function appendStopBlockLines(lines: string[], stop: SiteSummaryStopBlock) {
  105. const bizLabel = formatSiteDibangDirectionLabel(stop.businessType)
  106. const biz = bizLabel ? `(${bizLabel})` : ''
  107. lines.push(`【${stop.label} · ${stop.customerName || '—'}】${biz}`)
  108. if (stop.address) {
  109. lines.push(`地址:${stop.address}`)
  110. }
  111. if (stop.productLines.length) {
  112. stop.productLines.forEach((line) => lines.push(`产品:${line}`))
  113. } else {
  114. lines.push('产品:—')
  115. }
  116. }
  117. export function buildSiteSummaryFromInventoryLinks(options: {
  118. planNo?: string
  119. licensePlate?: string
  120. pickupTime?: string
  121. planDate?: string
  122. records: SiteSummaryRecord[]
  123. stopBlocks?: SiteSummaryStopBlock[]
  124. }) {
  125. const lines = ['【运输现场】']
  126. const planNo = options.planNo || options.records[0]?.planNo
  127. if (planNo) lines.push(`计划号:${planNo}`)
  128. if (options.licensePlate) lines.push(`车牌:${options.licensePlate}`)
  129. const time = formatDate(options.pickupTime) || options.planDate
  130. if (time) lines.push(`时间:${time}`)
  131. const validRecords = options.records.filter((item) => item.siteUrl)
  132. if (!validRecords.length) {
  133. lines.push('现场链接:—')
  134. return lines.join('\n')
  135. }
  136. const stopBlocks = options.stopBlocks || []
  137. const useSegmentLayout =
  138. stopBlocks.length > 0 && validRecords.some((record) => isSegmentSiteRecord(record))
  139. if (useSegmentLayout) {
  140. lines.push('')
  141. stopBlocks.forEach((stop, index) => {
  142. if (index > 0) lines.push('')
  143. appendStopBlockLines(lines, stop)
  144. })
  145. lines.push('')
  146. const record = validRecords[0]
  147. lines.push(`现场链接:${record.siteUrl}`)
  148. } else if (validRecords.length === 1) {
  149. lines.push('')
  150. appendSiteRecordCardLines(lines, validRecords[0], { showHeadline: true })
  151. } else {
  152. lines.push('')
  153. validRecords.forEach((record, index) => {
  154. lines.push(`【${index + 1}】${formatSiteSummaryProductLine(record)}`)
  155. appendSiteRecordCardLines(lines, record, { showHeadline: false })
  156. if (index < validRecords.length - 1) lines.push('')
  157. })
  158. }
  159. lines.push('')
  160. lines.push(SITE_INSTRUCTION)
  161. return lines.join('\n')
  162. }
  163. export function buildSiteSummaryFromInventory(record: InventoryRecord, siteUrl: string) {
  164. const spec = record.specification?.trim()
  165. const product = spec ? `${record.product}(${spec})` : record.product
  166. const lines = [
  167. '【出入库现场】',
  168. `出入库单号:${record.batchNo || '—'}`,
  169. `业务类型:${record.businessType}`,
  170. `日期:${record.date || '—'}`,
  171. `往来单位:${record.partnerCompany || '—'}`,
  172. `产品:${product}`,
  173. `数量(吨):${record.quantity ?? '—'}`,
  174. `车牌:${record.vehicleNo || '—'}`
  175. ]
  176. if (record.planNo) lines.push(`计划号:${record.planNo}`)
  177. lines.push(`现场链接:${siteUrl}`)
  178. lines.push('')
  179. lines.push(SITE_INSTRUCTION)
  180. return lines.join('\n')
  181. }