import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' import { normalizeTripDetail } from './trips' import type { TripDetail } from '../tripTypes' export interface PickupSource { customerId: string; transferNo: string } export interface PickupCandidate extends PickupSource { lastlegOrderNo: string; warehouseId: string; warehouseCode?: string | null; warehouseName?: string | null; pickupAddress: string; contactName: string; contactPhone: string; packageCount: number; expectedArrivalAt: string | null } export interface PickupEvidence { fileId: string; fileName: string; contentType: string; sizeBytes: number } export interface PickupTask extends Omit { status: string; tripNo: string | null; vehiclePlate: string | null; driverName: string | null; driverPhone: string | null plannedDepartureAt: string | null; actualPackages: number | null; pickedAt: string | null; arrivedAt: string | null; remark: string | null; evidence: PickupEvidence[] } export interface PickupPlan { sources: PickupSource[]; plannedDepartureAt: string; expectedDriverEndAt: string; remark?: string; idempotencyKey: string } export interface PickupCommand { recordVersion: number; idempotencyKey: string; reason: string } export interface PickupConfirmation { recordVersion: number; idempotencyKey: string; actualPackages: number; evidenceFileIds: string[]; remark?: string } export const pickupStatusLabels: Record = { PENDING_REVIEW: '待审核', WAITING: '待安排取货', ASSIGNED: '已安排取货', PICKED: '已取货', ARRIVED: '已送仓' } const base = '/platform/v1/last-leg/fleet/pickups' const tripPath = (tripNo: string) => `${base}/${encodeURIComponent(tripNo)}` const taskPath = (tripNo: string, row: PickupSource) => `${tripPath(tripNo)}/tasks/${encodeURIComponent(row.customerId)}/${encodeURIComponent(row.transferNo)}` type Page = { records: PickupCandidate[]; total: string | number } type WireDetail = Parameters[0] /** 待取货列表始终以服务端资格和总数为准。 */ export async function listPickupCandidates(page: number, size: number, keyword?: string) { const value = unwrapApiResponse(await http.get, ApiEnvelope>(base, { params: { page, size, keyword } })) return { records: value.records, total: Number(value.total) } } /** 安排成功返回原有车次详情。 */ export async function createPickupTrip(body: PickupPlan): Promise { return normalizeTripDetail(unwrapApiResponse(await http.post, ApiEnvelope>(base, body))) } /** 车次成员一次读取,避免逐行加载。 */ export async function getPickupTasks(tripNo: string): Promise { return unwrapApiResponse(await http.get, ApiEnvelope>(`${tripPath(tripNo)}/tasks`)) } /** 运输发车与结案沿取货专用规则执行。 */ export async function commandPickupTrip(tripNo: string, action: 'depart' | 'complete', body: PickupCommand): Promise { return normalizeTripDetail(unwrapApiResponse(await http.post, ApiEnvelope>(`${tripPath(tripNo)}/${action}`, body))) } /** 取货和送仓逐票确认,保留请求键以支持未知结果重试。 */ export async function commandPickupTask(tripNo: string, row: PickupSource, action: 'picked' | 'arrive', body: PickupCommand | PickupConfirmation): Promise { return unwrapApiResponse(await http.post, ApiEnvelope>(`${taskPath(tripNo, row)}/${action}`, body)) } /** 文件上传绑定本票与当前车次。 */ export async function uploadPickupEvidence(tripNo: string, row: PickupSource, file: File): Promise { const body = new FormData(); body.append('file', file) return unwrapApiResponse(await http.post, ApiEnvelope>(`${taskPath(tripNo, row)}/files`, body)) } /** 本票凭证通过授权入口读取,永不使用公共文件直链。 */ export async function downloadPickupEvidence(row: PickupSource, fileId: string): Promise { return http.get(`/platform/v1/last-leg/warehouse-transfers/${encodeURIComponent(row.transferNo)}/pickup-evidence/${encodeURIComponent(fileId)}`, { params: { customerId: row.customerId }, responseType: 'blob' }) }