import type { Plan, PlanProduct, TransportArrangeResult, TransportInventoryLink, TransportSiteLink } from '@/api/pl' import { planApi } from '@/api/pl' import DbPoundSlipQrcodeDialog from '@/components/business/db/DbPoundSlipQrcodeDialog.vue' import { useDictStore } from '@/store/modules/dict' import { formatDate } from '@/utils/format' import { appendAmapNavLine, buildAmapNavigationUrl } from '@/utils/amap/navigation' import { pickBxData } from '@/utils/http/bx' import { formatPlanProductListText } from '@/utils/pl-display' import { buildSiteSummaryFromInventoryLinks } from '@/utils/db-site-summary' export function usePlPlanArrangeActions() { const dictStore = useDictStore() const plan = ref | null>(null) const products = ref([]) const driverUrl = ref('') const licensePlate = ref('') const siteRecords = ref([]) const inventoryRecords = ref([]) const qrcodeVisible = ref(false) const selectedInventoryId = ref('') const selectedInventoryUnit = ref('') const qrcodeDialogRef = ref | null>(null) const showArrangeActions = computed( () => Boolean( plan.value?.transportStatus === 'arranged' && plan.value?.followStatus !== 'cancelled' && (driverUrl.value || siteRecords.value.length || inventoryRecords.value.length) ) ) const hasSiteInventoryRecords = computed(() => siteRecords.value.length > 0) const hasSiteLinks = computed(() => siteRecords.value.some(item => Boolean(item.siteUrl?.trim()))) /** 勾选「生成地磅单」后才会关联 db_purchase_plan,磅单二维码仅针对这类记录 */ const dibangInventoryRecords = computed(() => inventoryRecords.value.filter(item => Boolean(item.dbPurchasePlanId?.trim())) ) const hasDibangInventoryRecords = computed(() => dibangInventoryRecords.value.length > 0) function getUnitLabel(unit: string) { return dictStore.getLabel('crm_product_unit', unit) || unit } function resetArrangeActions() { plan.value = null products.value = [] driverUrl.value = '' licensePlate.value = '' siteRecords.value = [] inventoryRecords.value = [] qrcodeVisible.value = false selectedInventoryId.value = '' selectedInventoryUnit.value = '' } function applyArrangeResult( result: TransportArrangeResult, contextPlan?: Partial, contextProducts?: PlanProduct[] ) { if (contextPlan) plan.value = contextPlan if (contextProducts) products.value = contextProducts driverUrl.value = result.driverUrl || '' licensePlate.value = result.licensePlate || '' siteRecords.value = result.siteRecords || [] inventoryRecords.value = result.inventoryRecords || [] } async function loadArrangeActions(planId: string) { resetArrangeActions() const planRes = await planApi.get(planId) const data = pickBxData(planRes) if (!data) return plan.value = data products.value = Array.isArray(data.products) ? data.products : [] if (data.transportStatus !== 'arranged' || data.followStatus === 'cancelled') { return } const infoRes = await planApi.getArrangeInfo(planId) const info = pickBxData<{ driverUrl?: string driver_url?: string licensePlate?: string license_plate?: string siteRecords?: TransportSiteLink[] site_records?: TransportSiteLink[] inventoryRecords?: TransportInventoryLink[] inventory_records?: TransportInventoryLink[] }>(infoRes) driverUrl.value = info?.driverUrl || info?.driver_url || '' licensePlate.value = info?.licensePlate || info?.license_plate || data.licensePlate || '' siteRecords.value = info?.siteRecords || info?.site_records || [] inventoryRecords.value = info?.inventoryRecords || info?.inventory_records || [] } function buildPlanSummaryText(options?: { startPoint?: string endPoint?: string pickupAddress?: string pickupLng?: number | null pickupLat?: number | null destinationAddress?: string destinationLng?: number | null destinationLat?: number | null pickupContact?: string pickupNotes?: string deliveryContact?: string destinationNotes?: string licensePlate?: string driverUrl?: string }) { const plate = options?.licensePlate || licensePlate.value || plan.value?.licensePlate || '—' const lines = [`【${plate} - 运输安排】`, `计划号:${plan.value?.planNo || '—'}`] lines.push(`车牌:${plate}`) lines.push( `时间:${formatDate(plan.value?.pickupTime) || plan.value?.planDate || '—'}` ) const productText = products.value .map(p => formatPlanProductListText(p, getUnitLabel, { usePlannedQuantity: true })) .join(';') lines.push(`产品:${productText || '—'}`) const pickupAddress = options?.pickupAddress || plan.value?.pickupAddress || options?.startPoint || '—' const destinationAddress = options?.destinationAddress || plan.value?.destinationAddress || plan.value?.destinationName || options?.endPoint || '—' lines.push(`取货地址:${pickupAddress}`) lines.push(`送货地址:${destinationAddress}`) const pickupLng = options?.pickupLng ?? plan.value?.pickupLng const pickupLat = options?.pickupLat ?? plan.value?.pickupLat const destinationLng = options?.destinationLng ?? plan.value?.destinationLng const destinationLat = options?.destinationLat ?? plan.value?.destinationLat appendAmapNavLine( lines, '取货导航', buildAmapNavigationUrl(pickupLng, pickupLat, pickupAddress !== '—' ? pickupAddress : '取货点') ) appendAmapNavLine( lines, '送货导航', buildAmapNavigationUrl( destinationLng, destinationLat, destinationAddress !== '—' ? destinationAddress : '送货点' ) ) lines.push( `取货联系方式:${options?.pickupContact || plan.value?.pickupContact || '—'}` ) lines.push(`取货注意事项:${options?.pickupNotes || plan.value?.pickupNotes || '—'}`) lines.push( `送货联系方式:${options?.deliveryContact || plan.value?.deliveryContact || '—'}` ) lines.push(`送货注意事项:${options?.destinationNotes || plan.value?.destinationNotes || '—'}`) lines.push(`司机链接:${options?.driverUrl || driverUrl.value || '—'}`) return lines.join('\n') } async function copyDriverUrl(url?: string) { const target = url || driverUrl.value if (!target) return await navigator.clipboard.writeText(target) ElMessage.success('已复制司机链接') } function resolveSiteRecordProductText(record: TransportSiteLink) { const product = products.value.find(item => item.id === record.planProductId) if (product) { return formatPlanProductListText(product, getUnitLabel, { usePlannedQuantity: true }) } return record.productName || '—' } function buildSiteSummaryText(options?: { licensePlate?: string }) { return buildSiteSummaryFromInventoryLinks({ planNo: plan.value?.planNo, licensePlate: options?.licensePlate || licensePlate.value || plan.value?.licensePlate, pickupTime: plan.value?.pickupTime, planDate: plan.value?.planDate, records: siteRecords.value.map(record => ({ ...record, productText: resolveSiteRecordProductText(record) })) }) } async function copySiteSummary(options?: { licensePlate?: string }) { if (!hasSiteLinks.value) { ElMessage.warning('暂无现场链接') return } await navigator.clipboard.writeText(buildSiteSummaryText(options)) ElMessage.success('已复制给现场') } async function copyPlanSummary(options?: { startPoint?: string endPoint?: string pickupAddress?: string pickupLng?: number | null pickupLat?: number | null destinationAddress?: string destinationLng?: number | null destinationLat?: number | null pickupContact?: string pickupNotes?: string deliveryContact?: string destinationNotes?: string licensePlate?: string driverUrl?: string }) { await navigator.clipboard.writeText(buildPlanSummaryText(options)) ElMessage.success('已复制给司机') } function resolveInventoryUnitLabel(record: TransportInventoryLink) { const product = products.value.find(item => item.id === record.planProductId) const unitRaw = product?.unit || '' return unitRaw ? getUnitLabel(unitRaw) : '吨' } async function copyPoundSlipQrcode() { const records = dibangInventoryRecords.value if (!records.length) { ElMessage.warning('未勾选生成地磅单,暂无磅单二维码') return } if (records.length === 1) { selectedInventoryId.value = records[0].dbInventoryId selectedInventoryUnit.value = resolveInventoryUnitLabel(records[0]) qrcodeVisible.value = true await nextTick() await qrcodeDialogRef.value?.copyQrcodeImage() return } try { const { value } = await ElMessageBox.prompt('请选择要复制二维码的产品行', '复制磅单二维码', { inputPlaceholder: records.map((item, idx) => `${idx + 1}. ${item.productName}`).join('\n'), confirmButtonText: '确定', inputValidator: val => { const index = Number(val) - 1 if (!Number.isInteger(index) || index < 0 || index >= records.length) { return '请输入有效序号' } return true } }) const index = Number(value) - 1 const record = records[index] selectedInventoryId.value = record.dbInventoryId selectedInventoryUnit.value = resolveInventoryUnitLabel(record) qrcodeVisible.value = true await nextTick() await qrcodeDialogRef.value?.copyQrcodeImage() } catch { // 用户取消 } } return { plan, products, driverUrl, licensePlate, siteRecords, inventoryRecords, qrcodeVisible, selectedInventoryId, selectedInventoryUnit, qrcodeDialogRef, showArrangeActions, hasSiteInventoryRecords, hasSiteLinks, dibangInventoryRecords, hasDibangInventoryRecords, resetArrangeActions, applyArrangeResult, loadArrangeActions, buildPlanSummaryText, buildSiteSummaryText, copyDriverUrl, copySiteSummary, copyPlanSummary, copyPoundSlipQrcode } }