usePlPlanViewDetail.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import { getContract } from '@/api/crm/contract'
  2. import type { ContractVO } from '@/api/crm/contract/types'
  3. import {
  4. inventoryApi,
  5. type InventoryRecord,
  6. type InventoryWeighingRecord
  7. } from '@/api/db/inventory'
  8. import {
  9. planApi,
  10. transportApi,
  11. type Plan,
  12. type PlanProduct,
  13. type Transport,
  14. type TransportInventoryLink
  15. } from '@/api/pl'
  16. import type { PlanFormProductRow } from '@/composables/usePlContractToPlan'
  17. import { loadVehicleViewBundle, type VehicleViewBundle } from '@/composables/usePlVehicleViewDetail'
  18. import { enrichPlanProductsHazardFromCrm } from '@/composables/usePlToxicProductCertCheck'
  19. import { pickBxData } from '@/utils/http/bx'
  20. export interface PlPlanTransportDibangRow {
  21. link: TransportInventoryLink
  22. inventory: InventoryRecord | null
  23. weighing: InventoryWeighingRecord | null
  24. }
  25. export function mapPlanProductToFormRow(item: PlanProduct, index: number): PlanFormProductRow {
  26. return {
  27. productId: String(item.productId || index),
  28. productNo: item.productNo || String(item.productId || index),
  29. productName: item.productName || '',
  30. model: item.model,
  31. categoryName: item.categoryName,
  32. unit: item.unit || '吨',
  33. quantity: Number(item.quantity || item.inboundEstimateQty || item.outboundEstimateQty || 0),
  34. actualQty: Number(
  35. item.actualQty ?? item.quantity ?? item.inboundEstimateQty ?? item.outboundEstimateQty ?? 0
  36. ),
  37. packageSpec: item.packageSpec,
  38. deliveryMethod: item.deliveryMethod,
  39. taxRate: item.taxRate != null ? Number(item.taxRate) : undefined,
  40. taxPrice: item.taxPrice ?? item.inboundPrice ?? item.outboundPrice,
  41. taxSubtotal: item.taxSubtotal ?? item.inboundAmount ?? item.outboundAmount,
  42. taxAmount: item.taxAmount,
  43. remark: item.remark,
  44. isExplosive: Number(item.isExplosive ?? 0),
  45. isToxic: Number(item.isToxic ?? 0)
  46. }
  47. }
  48. export function buildContractSnapshotFromPlan(data: Plan, rows: PlanFormProductRow[]): ContractVO {
  49. return {
  50. id: data.contractId || '',
  51. contractNo: data.contractNo || '',
  52. contractName: data.contractNo || '',
  53. customerId: data.customerId || '',
  54. customerName: data.customerName || '',
  55. contactName: data.contactName || '',
  56. contactMobile: data.contactPhone || '',
  57. contractType: '',
  58. amount: data.totalAmount || 0,
  59. signDate: '',
  60. startDate: data.contractStartDate || '',
  61. endDate: data.contractEndDate || '',
  62. contractPeriod: 0,
  63. status: '',
  64. approvalStatus: '',
  65. contractFile: '',
  66. attachmentFiles: '',
  67. ownerUserId: '',
  68. ownerUserName: '',
  69. receivedAmount: 0,
  70. unreceivedAmount: 0,
  71. invoiceAmount: 0,
  72. uninvoiceAmount: 0,
  73. partyA: data.partyA || data.supplierName || '',
  74. partyAAddress: '',
  75. partyAContact: '',
  76. partyAMobile: '',
  77. partyALegalPerson: '',
  78. partyAAgent: '',
  79. partyAPhoneFax: '',
  80. partyABank: '',
  81. partyAAccount: '',
  82. supplierName: data.supplierName,
  83. settlementMethod: data.settlementMethod,
  84. partyB: data.partyB || data.customerName || '',
  85. partyBAddress: '',
  86. partyBContact: data.contactName || '',
  87. partyBMobile: data.contactPhone || '',
  88. partyBLegalPerson: '',
  89. partyBAgent: '',
  90. partyBPhoneFax: '',
  91. partyBBank: '',
  92. partyBAccount: '',
  93. paymentTerms: '',
  94. deliveryTerms: '',
  95. contractTerms: '',
  96. invalidReason: '',
  97. invalidTime: '',
  98. createTime: '',
  99. remark: data.remark || '',
  100. products: rows as unknown as ContractVO['products']
  101. }
  102. }
  103. function normalizeContractSnapshot(raw: unknown): ContractVO | null {
  104. if (!raw || typeof raw !== 'object') return null
  105. const payload = raw as Record<string, unknown>
  106. const nested = payload.data
  107. if (nested && typeof nested === 'object') {
  108. return nested as ContractVO
  109. }
  110. return raw as ContractVO
  111. }
  112. export function usePlPlanViewDetail() {
  113. const loading = ref(false)
  114. const plan = ref<Plan | null>(null)
  115. const products = ref<PlanProduct[]>([])
  116. const transport = ref<Transport | null>(null)
  117. const vehicleBundle = ref<VehicleViewBundle | null>(null)
  118. const contractSnapshot = ref<ContractVO | null>(null)
  119. const dibangRows = ref<PlPlanTransportDibangRow[]>([])
  120. async function loadDibangRows(planId: string, data: Plan) {
  121. dibangRows.value = []
  122. if (data.followStatus === 'cancelled' || data.transportStatus !== 'arranged') {
  123. return
  124. }
  125. try {
  126. const infoRes = await planApi.getArrangeInfo(planId)
  127. const info = pickBxData<{ inventoryRecords?: TransportInventoryLink[] }>(infoRes)
  128. const links = info?.inventoryRecords || []
  129. if (!links.length) return
  130. dibangRows.value = await Promise.all(
  131. links.map(async (link) => {
  132. let inventory: InventoryRecord | null = null
  133. let weighing: InventoryWeighingRecord | null = null
  134. try {
  135. inventory = await inventoryApi.get(link.dbInventoryId)
  136. } catch {
  137. inventory = null
  138. }
  139. try {
  140. const related = await inventoryApi.getRelated(link.dbInventoryId)
  141. weighing = related?.weighing ?? null
  142. } catch {
  143. weighing = null
  144. }
  145. return { link, inventory, weighing }
  146. })
  147. )
  148. } catch {
  149. dibangRows.value = []
  150. }
  151. }
  152. async function loadDetail(planId: string) {
  153. loading.value = true
  154. plan.value = null
  155. products.value = []
  156. transport.value = null
  157. vehicleBundle.value = null
  158. contractSnapshot.value = null
  159. dibangRows.value = []
  160. try {
  161. const res = await planApi.get(planId)
  162. const data = pickBxData<Plan>(res)
  163. plan.value = data || null
  164. const rows = (data?.products || []).map(mapPlanProductToFormRow)
  165. products.value = await enrichPlanProductsHazardFromCrm(data?.products || [])
  166. if (data?.contractId) {
  167. try {
  168. const contractRes = await getContract(data.contractId)
  169. contractSnapshot.value = normalizeContractSnapshot(contractRes.data ?? contractRes)
  170. } catch {
  171. contractSnapshot.value = buildContractSnapshotFromPlan(data, rows)
  172. }
  173. } else if (data) {
  174. contractSnapshot.value = buildContractSnapshotFromPlan(data, rows)
  175. }
  176. const detailTasks: Promise<void>[] = []
  177. if (data?.transportId) {
  178. detailTasks.push(
  179. transportApi
  180. .get(data.transportId)
  181. .then((transportRes) => {
  182. transport.value = pickBxData<Transport>(transportRes)
  183. })
  184. .catch(() => {
  185. transport.value = null
  186. })
  187. )
  188. }
  189. if (data?.vehicleId) {
  190. detailTasks.push(
  191. loadVehicleViewBundle(data.vehicleId)
  192. .then((bundle) => {
  193. vehicleBundle.value = bundle
  194. })
  195. .catch(() => {
  196. vehicleBundle.value = null
  197. })
  198. )
  199. }
  200. if (detailTasks.length) {
  201. await Promise.all(detailTasks)
  202. }
  203. if (data) {
  204. await loadDibangRows(planId, data)
  205. }
  206. } finally {
  207. loading.value = false
  208. }
  209. }
  210. function resetDetail() {
  211. plan.value = null
  212. products.value = []
  213. transport.value = null
  214. vehicleBundle.value = null
  215. contractSnapshot.value = null
  216. dibangRows.value = []
  217. }
  218. return {
  219. loading,
  220. plan,
  221. products,
  222. transport,
  223. vehicleBundle,
  224. contractSnapshot,
  225. dibangRows,
  226. loadDetail,
  227. resetDetail
  228. }
  229. }