From e8cb9e1588acbc46b046a2257350331b2e36ed6d Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 22 Aug 2026 09:50:50 +0800 Subject: [PATCH] 1 --- 悦/货代SAAS平台后台/AGENTS.md | 2 +- 悦/货代SAAS平台后台/PDA(海外)/index.html | 72 +- 悦/货代SAAS平台后台/index.html | 1042 +++++++++++++++-- 悦/货代SAAS平台后台/prototype-src/app.js | 774 ++++++++++-- .../prototype-src/manifest.json | 8 +- .../modules/02-domestic-warehouse.html | 12 +- .../modules/03-overseas-warehouse.html | 28 +- .../modules/04-overseas-delivery.html | 16 +- .../modules/04a-customer-service.html | 22 +- .../prototype-src/modules/06-containers.html | 4 +- .../modules/07-overseas-business.html | 25 + .../prototype-src/modules/10-general.html | 13 +- .../prototype-src/overlays.html | 68 +- 悦/货代SAAS平台后台/prototype-src/shell.html | 64 +- 悦/货代SAAS平台后台/prototype-src/tail.html | 16 +- .../tests/verify-customer-followup.cjs | 55 + ...stomer-service-exception-order-numbers.cjs | 10 +- ...rify-customer-service-exception-orders.cjs | 7 +- ...rify-customer-service-manual-exception.cjs | 27 + .../tests/verify-dispatch-bol-print.cjs | 97 ++ .../verify-dispatch-edit-field-removed.cjs | 39 + ...fy-domestic-inbound-warehouse-transfer.cjs | 147 +++ ...ound-smart-schedule-appointment-search.cjs | 17 + ...rify-fba-inbound-smart-schedule-weight.cjs | 23 + .../tests/verify-finance-ar-detail-report.cjs | 29 +- .../verify-last-mile-detention-fields.cjs | 119 ++ ...y-last-mile-inbound-pallet-outsourcing.cjs | 55 + .../tests/verify-last-mile-inbound-urgent.cjs | 114 ++ .../verify-last-mile-manual-client-nodes.cjs | 127 ++ .../tests/verify-last-mile-settlement.cjs | 79 ++ ...erify-outbound-vehicle-buy-appointment.cjs | 20 + .../verify-outbound-vehicle-edit-delivery.cjs | 2 +- .../tests/verify-overseas-pda.cjs | 10 +- .../tests/verify-overseas-truck-detail.cjs | 45 + ...verify-overseas-truck-edit-attachments.cjs | 20 + 35 files changed, 2937 insertions(+), 271 deletions(-) create mode 100644 悦/货代SAAS平台后台/tests/verify-customer-followup.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-customer-service-manual-exception.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-dispatch-bol-print.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-dispatch-edit-field-removed.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-domestic-inbound-warehouse-transfer.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-fba-inbound-smart-schedule-appointment-search.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-fba-inbound-smart-schedule-weight.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-last-mile-detention-fields.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-last-mile-inbound-pallet-outsourcing.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-last-mile-inbound-urgent.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-last-mile-manual-client-nodes.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-last-mile-settlement.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-outbound-vehicle-buy-appointment.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-overseas-truck-detail.cjs create mode 100644 悦/货代SAAS平台后台/tests/verify-overseas-truck-edit-attachments.cjs diff --git a/悦/货代SAAS平台后台/AGENTS.md b/悦/货代SAAS平台后台/AGENTS.md index a0494de..18735a0 100644 --- a/悦/货代SAAS平台后台/AGENTS.md +++ b/悦/货代SAAS平台后台/AGENTS.md @@ -123,7 +123,7 @@ node tests/verify-prototype-modules.cjs | 客户服务 | `prototype-src/modules/04a-customer-service.html` | `outbound-exception`(异常订单) | | 供应商中心 | `prototype-src/modules/05-suppliers.html` | 供应商列表/编辑、快递公司、往来单位、海运渠道 | | 货柜管理 | `prototype-src/modules/06-containers.html` | 订舱、拖车、货柜、装柜清单、预装清单、装柜看板 | -| 海外业务 | `prototype-src/modules/07-overseas-business.html` | 采购订单、本土卡车、本土散板及新增/编辑/详情 | +| 海外业务 | `prototype-src/modules/07-overseas-business.html` | 采购订单、本土卡车及详情、本土散板及新增/编辑/详情 | | 财务管理 | `prototype-src/modules/08-finance.html` | 客户账户、应收应付、对账单、结算单、费用分析、利润表及历史财务报表页 | | 销售管理 | `prototype-src/modules/09-sales.html` | 拜访记录新增/详情、销售提成 | | 通用资料 | `prototype-src/modules/10-general.html` | 产品、费用项目、汇率管理、仓库(`gen-owned-warehouse`、`gen-fba`、`gen-partner-warehouse`)、下载、船期价格、车辆及详情、派送车队报价表、历史库位/托盘/路线页 | diff --git a/悦/货代SAAS平台后台/PDA(海外)/index.html b/悦/货代SAAS平台后台/PDA(海外)/index.html index c3b9a26..75caff9 100644 --- a/悦/货代SAAS平台后台/PDA(海外)/index.html +++ b/悦/货代SAAS平台后台/PDA(海外)/index.html @@ -234,15 +234,18 @@ button:disabled{opacity:.42} } @@ -296,22 +304,23 @@ const cargo=[ ]; const pickTasks=[{id:'OUT-260819-004',inboundCode:'FBA-ONT8-260819-004',plateNo:'CA 8KX-217',driver:'Michael Chen',outboundTime:'2026-08-20 09:30',destination:'ONT8',customer:'杭州积乐贸易',boxes:6,palletCount:3,totalPallets:3,orderInfo:'SO-260819-004 / AMZ-PO-88401',items:[{sku:'YQ-CASE-01',qty:45,picked:0},{sku:'YQ-CABLE-02',qty:20,picked:0}]},{id:'OUT-260819-006',inboundCode:'FBA-LGB8-260819-006',plateNo:'CA 6MP-908',driver:'David Lee',outboundTime:'2026-08-20 13:00',destination:'LGB8',customer:'宁波远航电商',boxes:3,palletCount:2,totalPallets:2,orderInfo:'SO-260819-006 / AMZ-PO-88412',items:[{sku:'NH-BAG-04',qty:12,picked:0},{sku:'NH-BAG-06',qty:18,picked:0}]}]; const inventory=[...cargo.map((x,i)=>({sku:x.sku,name:x.name,customer:x.customer,boxNo:x.boxNo,palletNo:i<2?'D2222-TC-001':'—',destinationCode:x.destinationCode,qty:x.receivedQty,status:x.receivedQty?'在库':'在途'})),{sku:'JZ-MOUSE-07',name:'Wireless mouse',customer:'深圳璟智供应链',boxNo:'BX-88416-03',palletNo:'—',destinationCode:'ONT8',qty:90,status:'在途'}]; +const demoConsolidatedPallets=[{id:'D2222-TC-019',mode:'consolidate',planId:null,targetPallets:null,container:'D2222',destinationCode:'ONT8',destinationAddress:'24300 Nandina Ave, Moreno Valley, CA',items:[{...cargo[0],isMerged:false,mergeFlag:'否'},{...cargo[1],isMerged:true,mergeFlag:'是'}]}]; const WORK_LABELS={zh:{inboundPallet:'入库打托',inboundPalletDesc:'按入库计划托数完成打托',pallet:'入库打托',palletDesc:'按计划托数装对应货物',palletList:'托盘列表',palletListDesc:'选择托盘进入详情',pendingPallet:'待创建托盘',cartonCount:'箱数',boxMark:'箱唛',productName:'产品名称',palletStatus:'托盘状态',idle:'闲置',occupied:'占用',viewPalletDetails:'选择查看明细',directEnter:'直接进入',selectPalletLabel:'选择托盘标',palletLabel:'托盘标',palletizeAction:'打托',planDesc:'按入库计划选择打托任务',mergeOnly:'合托',mergeDesc:'将不足一托的箱子合成一托',startPallet:'开始打托',palletProgress:'打托进度',palletTargetReached:'已达到计划托数,不能继续提交'},en:{inboundPallet:'Inbound palletizing',inboundPalletDesc:'Palletize against the inbound plan',pallet:'Inbound palletizing',palletDesc:'Load freight by planned pallet count',palletList:'Pallet list',palletListDesc:'Select a pallet to view details',pendingPallet:'Pallet to create',cartonCount:'Cartons',boxMark:'Carton mark',productName:'Product name',palletStatus:'Pallet status',idle:'Idle',occupied:'Occupied',viewPalletDetails:'View pallet details',directEnter:'Enter directly',selectPalletLabel:'Select pallet label',palletLabel:'Pallet label',palletizeAction:'Palletize',planDesc:'Choose an inbound plan to palletize',mergeOnly:'Consolidate',mergeDesc:'Combine cartons that do not fill a pallet',startPallet:'Start palletizing',palletProgress:'Palletizing progress',palletTargetReached:'Planned pallet count reached'},es:{inboundPallet:'Paletizado de entrada',inboundPalletDesc:'Paletiza según el plan de entrada',pallet:'Paletizado de entrada',palletDesc:'Carga según los pallets del plan',palletList:'Lista de pallets',palletListDesc:'Selecciona un pallet para ver detalles',pendingPallet:'Pallet por crear',cartonCount:'Cajas',boxMark:'Marca de caja',productName:'Nombre del producto',palletStatus:'Estado del pallet',idle:'Libre',occupied:'Ocupado',viewPalletDetails:'Ver detalles de pallets',directEnter:'Entrar directamente',selectPalletLabel:'Seleccionar etiqueta de pallet',palletLabel:'Etiqueta de pallet',palletizeAction:'Paletizar',planDesc:'Elige un plan de entrada para paletizar',mergeOnly:'Consolidar',mergeDesc:'Combina cajas que no llenan un pallet',startPallet:'Iniciar paletizado',palletProgress:'Progreso de paletizado',palletTargetReached:'Se alcanzó el total de pallets del plan'}}; -const state={lang:localStorage.getItem('overseas-pda-lang')||'zh',page:'login',user:null,error:'',selectedPlanId:null,receiveScan:[],receiveStatus:{},unloadPhotos:{},pallet:null,palletMode:'palletize',pallets:[],palletMessage:null,pickTaskId:null,pickMessage:null,reviewScanned:[],handoverDone:false,handoverPhotos:{},inventoryQuery:'',relabelMessage:null,relabelDoneOrders:{},exceptionRefValue:'',exceptionMessage:null}; -const EXTRA_LABELS={zh:{planDesc:'按计划核对托数并打托',startPallet:'开始打托',mergeOnly:'合托',receiveDesc:'拍摄 5 张作业照片完成收货',receiveListTitle:'待卸货集装箱',receiveListDesc:'选择集装箱后拍摄 5 张照片完成收货',pendingContainers:'个待卸货集装箱',startUnload:'开始拆柜',stocktake:'库存盘点',transfer:'移库作业',relabel:'换标作业',exception:'异常处理',palletCount:'托数',palletQty:'托盘数量',linkedOrder:'关联订单',licensePlate:'车牌照片',containerSeal:'集装箱封签',doorOpen:'开柜照片',unloading:'卸货照片',unloadComplete:'卸货完成照片',takePhoto:'拍照',retake:'重拍',photoProgress:'拍照进度',confirmUnload:'确认拆柜收货',photosRequired:'请完成全部 5 张照片',handoverPhotosRequired:'请完成全部 7 张交接照片',mergeFlag:'是否合托',yesMerge:'是',noMerge:'否',licensePlatePhoto:'车牌照片',vehicleCabPhoto:'车厢照片',driverLicense:'司机驾照',loadingSealPhoto:'装货封门照片',lockSealPhoto:'锁门 SEAL 照片',bolDriverSigned:'BOL(含司机签字)',amazonAppointment:'亚马逊预约单',handoverPhotos:'交接照片(7张)',relabelTitle:'换标作业',relabelHint:'订单列表中提交换标完成',newLabel:'新标签 / 新 SKU',submitRelabel:'换标完成',relabelDone:'换标已完成',relabelStatus:'换标状态',exceptionTitle:'异常处理',exceptionType:'异常类型',exceptionRef:'关联箱号 / 托盘号',exceptionDesc:'异常描述',submitException:'提交异常',exceptionDone:'异常已记录',selectException:'请选择异常类型',queryHint:'输入托盘号或产品名称',inventoryDesc:'查询产品名称或托盘号'},en:{planDesc:'Verify pallet count and start palletizing',startPallet:'Start palletizing',mergeOnly:'Consolidate',receiveDesc:'Capture 5 operation photos to receive',receiveListTitle:'Containers to unload',receiveListDesc:'Choose a container, then capture 5 photos to receive it',pendingContainers:'containers to unload',startUnload:'Start unload',stocktake:'Stocktake',transfer:'Stock transfer',relabel:'Relabeling',exception:'Exceptions',palletCount:'Pallets',palletQty:'Pallet quantity',linkedOrder:'Linked order',licensePlate:'License plate photo',containerSeal:'Container seal',doorOpen:'Door open',unloading:'Unloading',unloadComplete:'Unload complete',takePhoto:'Take photo',retake:'Retake',photoProgress:'Photo progress',confirmUnload:'Confirm unloading',photosRequired:'Complete all 5 photos',handoverPhotosRequired:'Complete all 7 handover photos',mergeFlag:'Merged pallet',yesMerge:'Yes',noMerge:'No',licensePlatePhoto:'License plate photo',vehicleCabPhoto:'Vehicle cab photo',driverLicense:'Driver license',loadingSealPhoto:'Loading door photo',lockSealPhoto:'Lock SEAL photo',bolDriverSigned:'BOL with driver signature',amazonAppointment:'Amazon appointment',handoverPhotos:'Handover photos (7)',relabelTitle:'Relabeling',relabelHint:'Submit completion from the order list',newLabel:'New label / new SKU',submitRelabel:'Relabel complete',relabelDone:'Relabel completed',relabelStatus:'Relabel status',exceptionTitle:'Exception handling',exceptionType:'Exception type',exceptionRef:'Carton / pallet reference',exceptionDesc:'Exception description',submitException:'Log exception',exceptionDone:'Exception recorded',selectException:'Select an exception type',queryHint:'Enter pallet ID or product name',inventoryDesc:'Search product name or pallet ID'},es:{planDesc:'Verifica pallets e inicia paletizado',startPallet:'Iniciar paletizado',mergeOnly:'Consolidar',receiveDesc:'Captura 5 fotos para recibir',receiveListTitle:'Contenedores por descargar',receiveListDesc:'Elige un contenedor y captura 5 fotos para recibirlo',pendingContainers:'contenedores por descargar',startUnload:'Iniciar descarga',stocktake:'Inventario físico',transfer:'Traslado interno',relabel:'Reetiquetado',exception:'Excepciones',palletCount:'Pallets',palletQty:'Cantidad de pallets',linkedOrder:'Pedido relacionado',licensePlate:'Matrícula',containerSeal:'Sello del contenedor',doorOpen:'Apertura',unloading:'Descarga',unloadComplete:'Descarga terminada',takePhoto:'Tomar foto',retake:'Repetir',photoProgress:'Progreso de fotos',confirmUnload:'Confirmar descarga',photosRequired:'Completa las 5 fotos',handoverPhotosRequired:'Completa las 7 fotos de entrega',mergeFlag:'Pallet consolidado',yesMerge:'Sí',noMerge:'No',licensePlatePhoto:'Foto de matrícula',vehicleCabPhoto:'Foto de cabina',driverLicense:'Licencia del conductor',loadingSealPhoto:'Puerta de carga',lockSealPhoto:'Foto del SEAL',bolDriverSigned:'BOL firmado por conductor',amazonAppointment:'Cita de Amazon',handoverPhotos:'Fotos de entrega (7)',relabelTitle:'Reetiquetado',relabelHint:'Envía la finalización desde la lista de pedidos',newLabel:'Nueva etiqueta / SKU',submitRelabel:'Reetiquetado completo',relabelDone:'Reetiquetado completado',relabelStatus:'Estado del reetiquetado',exceptionTitle:'Gestión de excepciones',exceptionType:'Tipo de excepción',exceptionRef:'Referencia de caja / pallet',exceptionDesc:'Descripción de la excepción',submitException:'Registrar excepción',exceptionDone:'Excepción registrada',selectException:'Selecciona un tipo',queryHint:'Escribe ID de pallet o nombre del producto',inventoryDesc:'Busca nombre del producto o ID de pallet'}}; +const state={lang:localStorage.getItem('overseas-pda-lang')||'zh',page:'login',user:null,error:'',selectedPlanId:null,receiveScan:[],receiveStatus:{},unloadPhotos:{},pallet:null,palletMode:'palletize',pallets:demoConsolidatedPallets.map(pallet=>({...pallet,items:pallet.items.map(item=>({...item}))})),palletMessage:null,palletPhotos:{},photoPalletId:'',pickTaskId:null,pickMessage:null,reviewScanned:[],handoverDone:false,handoverPhotos:{},inventoryQuery:'',relabelMessage:null,relabelDoneOrders:{},exceptionRefValue:'',exceptionMessage:null}; +const EXTRA_LABELS={zh:{planDesc:'按计划核对托数并打托',startPallet:'开始打托',mergeOnly:'合托',receiveDesc:'拍摄 5 张作业照片完成收货',receiveListTitle:'待卸货集装箱',receiveListDesc:'选择集装箱后拍摄 5 张照片完成收货',pendingContainers:'个待卸货集装箱',startUnload:'开始拆柜',stocktake:'库存盘点',transfer:'移库作业',relabel:'换标作业',exception:'异常处理',palletCount:'托数',palletQty:'托盘数量',linkedOrder:'关联订单',licensePlate:'车牌照片',containerSeal:'集装箱封签',doorOpen:'开柜照片',unloading:'卸货照片',unloadComplete:'卸货完成照片',takePhoto:'拍照',retake:'重拍',photoProgress:'拍照进度',confirmUnload:'确认拆柜收货',photosRequired:'请完成全部 5 张照片',handoverPhotosRequired:'请完成全部 7 张交接照片',mergeFlag:'是否合托',yesMerge:'是',noMerge:'否',licensePlatePhoto:'车牌照片',vehicleCabPhoto:'车厢照片',driverLicense:'司机驾照',loadingSealPhoto:'装货封门照片',lockSealPhoto:'锁门 SEAL 照片',bolDriverSigned:'BOL(含司机签字)',amazonAppointment:'亚马逊预约单',handoverPhotos:'交接照片(7张)',relabelTitle:'换标作业',relabelHint:'订单列表中提交换标完成',newLabel:'新标签 / 新 SKU',submitRelabel:'换标完成',relabelDone:'换标已完成',relabelStatus:'换标状态',exceptionTitle:'异常处理',exceptionType:'异常类型',exceptionRef:'关联尾程订单号 / 入仓码 / 托盘号',exceptionDesc:'异常描述',submitException:'提交异常',exceptionDone:'异常已记录',selectException:'请选择异常类型',queryHint:'输入托盘号或产品名称',inventoryDesc:'查询产品名称或托盘号'},en:{planDesc:'Verify pallet count and start palletizing',startPallet:'Start palletizing',mergeOnly:'Consolidate',receiveDesc:'Capture 5 operation photos to receive',receiveListTitle:'Containers to unload',receiveListDesc:'Choose a container, then capture 5 photos to receive it',pendingContainers:'containers to unload',startUnload:'Start unload',stocktake:'Stocktake',transfer:'Stock transfer',relabel:'Relabeling',exception:'Exceptions',palletCount:'Pallets',palletQty:'Pallet quantity',linkedOrder:'Linked order',licensePlate:'License plate photo',containerSeal:'Container seal',doorOpen:'Door open',unloading:'Unloading',unloadComplete:'Unload complete',takePhoto:'Take photo',retake:'Retake',photoProgress:'Photo progress',confirmUnload:'Confirm unloading',photosRequired:'Complete all 5 photos',handoverPhotosRequired:'Complete all 7 handover photos',mergeFlag:'Merged pallet',yesMerge:'Yes',noMerge:'No',licensePlatePhoto:'License plate photo',vehicleCabPhoto:'Vehicle cab photo',driverLicense:'Driver license',loadingSealPhoto:'Loading door photo',lockSealPhoto:'Lock SEAL photo',bolDriverSigned:'BOL with driver signature',amazonAppointment:'Amazon appointment',handoverPhotos:'Handover photos (7)',relabelTitle:'Relabeling',relabelHint:'Submit completion from the order list',newLabel:'New label / new SKU',submitRelabel:'Relabel complete',relabelDone:'Relabel completed',relabelStatus:'Relabel status',exceptionTitle:'Exception handling',exceptionType:'Exception type',exceptionRef:'Outbound order / inbound code / pallet ID',exceptionDesc:'Exception description',submitException:'Log exception',exceptionDone:'Exception recorded',selectException:'Select an exception type',queryHint:'Enter pallet ID or product name',inventoryDesc:'Search product name or pallet ID'},es:{planDesc:'Verifica pallets e inicia paletizado',startPallet:'Iniciar paletizado',mergeOnly:'Consolidar',receiveDesc:'Captura 5 fotos para recibir',receiveListTitle:'Contenedores por descargar',receiveListDesc:'Elige un contenedor y captura 5 fotos para recibirlo',pendingContainers:'contenedores por descargar',startUnload:'Iniciar descarga',stocktake:'Inventario físico',transfer:'Traslado interno',relabel:'Reetiquetado',exception:'Excepciones',palletCount:'Pallets',palletQty:'Cantidad de pallets',linkedOrder:'Pedido relacionado',licensePlate:'Matrícula',containerSeal:'Sello del contenedor',doorOpen:'Apertura',unloading:'Descarga',unloadComplete:'Descarga terminada',takePhoto:'Tomar foto',retake:'Repetir',photoProgress:'Progreso de fotos',confirmUnload:'Confirmar descarga',photosRequired:'Completa las 5 fotos',handoverPhotosRequired:'Completa las 7 fotos de entrega',mergeFlag:'Pallet consolidado',yesMerge:'Sí',noMerge:'No',licensePlatePhoto:'Foto de matrícula',vehicleCabPhoto:'Foto de cabina',driverLicense:'Licencia del conductor',loadingSealPhoto:'Puerta de carga',lockSealPhoto:'Foto del SEAL',bolDriverSigned:'BOL firmado por conductor',amazonAppointment:'Cita de Amazon',handoverPhotos:'Fotos de entrega (7)',relabelTitle:'Reetiquetado',relabelHint:'Envía la finalización desde la lista de pedidos',newLabel:'Nueva etiqueta / SKU',submitRelabel:'Reetiquetado completo',relabelDone:'Reetiquetado completado',relabelStatus:'Estado del reetiquetado',exceptionTitle:'Gestión de excepciones',exceptionType:'Tipo de excepción',exceptionRef:'Orden de salida / código de entrada / ID de pallet',exceptionDesc:'Descripción de la excepción',submitException:'Registrar excepción',exceptionDone:'Excepción registrada',selectException:'Selecciona un tipo',queryHint:'Escribe ID de pallet o nombre del producto',inventoryDesc:'Busca nombre del producto o ID de pallet'}}; const PICK_LABELS={zh:{outboundOrderNo:'出库单号',inboundCode:'入仓码',plateNo:'车牌号',outboundTime:'出库时间',totalPalletBoxes:'总托数 / 总箱数',orderList:'订单列表',tractorDriver:'拖车司机',tractorPlate:'拖车车牌',destinationWarehouse:'目的仓编码'},en:{outboundOrderNo:'Outbound order',inboundCode:'Inbound code',plateNo:'Plate number',outboundTime:'Outbound time',totalPalletBoxes:'Total pallets / cartons',orderList:'Order list',tractorDriver:'Tractor driver',tractorPlate:'Tractor plate',destinationWarehouse:'Destination warehouse'},es:{outboundOrderNo:'Orden de salida',inboundCode:'Código de entrada',plateNo:'Matrícula',outboundTime:'Hora de salida',totalPalletBoxes:'Pallets / cajas totales',orderList:'Lista de pedidos',tractorDriver:'Conductor del tractor',tractorPlate:'Matrícula del tractor',destinationWarehouse:'Almacén de destino'}}; function t(key,vars={}){let value=WORK_LABELS[state.lang]?.[key]||EXTRA_LABELS[state.lang]?.[key]||PICK_LABELS[state.lang]?.[key]||(I18N[state.lang]&&I18N[state.lang][key])||WORK_LABELS.zh[key]||EXTRA_LABELS.zh[key]||PICK_LABELS.zh[key]||I18N.zh[key]||key;return String(value).replace(/\{(\w+)\}/g,(_,k)=>vars[k]??'');} function esc(value){return String(value??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));} const ICON_PATHS={ - pallet:'', - unload:'', - merge:'', - pick:'', + pallet:'', + unload:'', + merge:'', + pick:'', review:'', - handover:'', - inventory:'', - relabel:'', - exception:'', + handover:'', + inventory:'', + relabel:'', + exception:'', more:'', scan:'', arrowLeft:'', @@ -347,9 +356,9 @@ function canMergePallet(pallet,cargo){ return !pallet.destinationCode || ((!cargo.destinationCode || pallet.destinationCode===cargo.destinationCode) && (!pallet.destinationAddress || pallet.destinationAddress===cargo.destinationAddress)); } function startPlanPallet(planId){state.selectedPlanId=planId;state.palletMode='palletize';state.pallet=null;state.palletMessage=null;state.page='pallet-list';render();} -function startConsolidation(){state.palletMode='consolidate';state.pallet={id:'',mode:'consolidate',planId:null,targetPallets:null,destinationCode:'',destinationAddress:'',items:[]};state.palletMessage=null;state.page='pallet';render();} +function startConsolidation(){state.palletMode='consolidate';state.pallet=null;state.palletMessage=null;state.photoPalletId='';state.page='pallet-list';render();} function plannedPalletNo(plan,index){return `${plan.container}-TC-${String(index+1).padStart(3,'0')}`;} -function palletListView(){const consolidating=state.palletMode==='consolidate';const activePlans=consolidating?plans:[selectedPlan()];const slots=activePlans.flatMap(plan=>Array.from({length:plan.expectedPallets},(_,index)=>({plan,no:plannedPalletNo(plan,index)})));const occupied=slots.filter(slot=>state.pallets.some(x=>x.id===slot.no)).length;const title=consolidating?t('mergeOnly'):t('palletList');const description=consolidating?t('mergeDesc'):`${selectedPlan().id} · ${t('palletListDesc')}`;return layout(`
${occupied} / ${slots.length} ${t('occupied')}
${slots.map(({plan,no})=>{const saved=state.pallets.find(x=>x.id===no);const isOccupied=Boolean(saved);return `
${esc(no)}
${esc(plan.id)} · ${esc(plan.container)}
${t(isOccupied?'occupied':'idle')}
${t('destination')}${esc(saved?.destinationCode||plan.destinationCode)}
${t('cartonCount')}${saved?.items.length||0}
`}).join('')}
`,title,description,consolidating?'workbench':'plans');} + function palletListView(){const consolidating=state.palletMode==='consolidate';const activePlans=consolidating?plans:[selectedPlan()];const slots=activePlans.flatMap(plan=>Array.from({length:plan.expectedPallets},(_,index)=>({plan,no:plannedPalletNo(plan,index)})));const occupied=slots.filter(slot=>state.pallets.some(x=>x.id===slot.no)).length;const title=consolidating?t('mergeOnly'):t('palletList');const description=consolidating?t('mergeDesc'):`${selectedPlan().id} · ${t('palletListDesc')}`;return layout(`
${occupied} / ${slots.length} ${t('occupied')}
${slots.map(({plan,no})=>{const saved=state.pallets.find(x=>x.id===no);const isOccupied=Boolean(saved);return `
${esc(no)}
${esc(plan.id)} · ${esc(plan.container)}
${t(isOccupied?'occupied':'idle')}
${t('destination')}${esc(saved?.destinationCode||plan.destinationCode)}
${t('cartonCount')}${saved?.items.length||0}
`}).join('')}
`,title,description,consolidating?'workbench':'plans');} function selectPallet(palletId,planId){const saved=state.pallets.find(x=>x.id===palletId);if(planId)state.selectedPlanId=planId;const consolidating=state.palletMode==='consolidate';state.pallet=saved?{...JSON.parse(JSON.stringify(saved)),persisted:true}:{id:palletId,mode:consolidating?'consolidate':'palletize',planId:consolidating?null:state.selectedPlanId,targetPallets:consolidating?null:selectedPlan().expectedPallets,destinationCode:'',destinationAddress:'',items:[]};state.palletMessage=null;state.page='pallet';render();} function palletView(){const p=selectedPlan();const consolidating=state.palletMode==='consolidate';const done=consolidating?0:state.pallets.filter(x=>x.mode==='palletize'&&x.planId===p.id).length;const targetReached=!consolidating&&done>=p.expectedPallets;const candidates=cargo.filter(c=>c.received&&!c.palletNo&&(consolidating||c.planNo===p.id));const title=consolidating?t('mergeOnly'):t('pallet');const description=consolidating?t('mergeDesc'):t('palletDesc');if(!state.pallet){return layout(`

${title}

${description}

${consolidating?candidates.length:`${done} / ${p.expectedPallets}`}
${candidates.map(c=>`
${esc(c.boxNo)} · ${esc(c.sku)}

${esc(c.customer)} · ${esc(c.planNo)} · ${esc(c.destinationCode)}

`).join('')||`
${targetReached?t('taskDone'):t('empty')}
`}
`,title,description,consolidating?'workbench':'plans');} return layout(`

${t('currentPallet')}

${state.pallet.destinationCode?`${t('lockedDest')}: ${esc(state.pallet.destinationCode)}`:description}

${state.pallet.items.length} ${t('items')}
${t('palletNo')}${esc(state.pallet.id||'DRAFT')}
${t('destination')}${esc(state.pallet.destinationCode||'—')}
${t('destinationAddress')}${esc(state.pallet.destinationAddress||'—')}
${t('pieces')}${state.pallet.items.reduce((s,x)=>s+x.qty,0)}
${state.palletMessage?`
${esc(state.palletMessage.text)}
`:''}

${t('items')}

${t('trace')}

${state.pallet.items.length?`
${state.pallet.items.map((x,i)=>``).join('')}
${t('boxNo')}${t('sku')}${t('customer')}${t('planNo')}${t('qty')}
${esc(x.boxNo)}${esc(x.sku)}${esc(x.customer)}${esc(x.planNo)}${x.qty}
`:`
${t('emptyPallet')}
`}
`,title,consolidating?t('sameDest'):`${p.id} · ${done} / ${p.expectedPallets} ${t('palletCount')}`,consolidating?'workbench':'plans');} @@ -377,7 +386,7 @@ function handleHandoverPhoto(key,input){const file=input.files&&input.files[0];i function completeHandover(){if(HANDOVER_PHOTO_STEPS.some(key=>!state.handoverPhotos[key])){toast(t('handoverPhotosRequired'),'bad');return}state.handoverDone=true;toast(t('taskDone'),'good');render();} function relabelView(){return layout(`
${plans.length} ${t('orderList')}
${plans.map(p=>{const done=Boolean(state.relabelDoneOrders[p.id]);return `
${esc(p.id)}
${t('container')}: ${esc(p.container)} · ${esc(p.customer)}
${done?t('complete'):t('pending')}
${t('inboundCode')}${esc(p.inboundCode||p.tickets)}
${t('palletCount')}${p.expectedPallets} ${t('palletCount')}
${t('relabelStatus')}${done?t('relabelDone'):t('pending')}
`}).join('')}
`,t('relabelTitle'),t('relabelHint'),'workbench');} function submitRelabel(planId){if(!planId)return;state.relabelDoneOrders[planId]=true;state.relabelMessage={type:'good',text:`${t('relabelDone')}: ${planId}`};toast(state.relabelMessage.text,'good');render();} - function exceptionView(){return layout(`

${t('exceptionTitle')}

${t('pending')}
${state.exceptionMessage?`
${esc(state.exceptionMessage.text)}
`:''}
`,t('exceptionTitle'),t('exceptionDesc'),'workbench');} + function exceptionView(){return layout(`

${t('exceptionTitle')}

${t('pending')}
${state.exceptionMessage?`
${esc(state.exceptionMessage.text)}
`:''}
`,t('exceptionTitle'),t('exceptionDesc'),'workbench');} function handleExceptionScan(){const value=(document.getElementById('exception-scan')?.value||'').trim();if(!value){state.exceptionMessage={type:'error',text:t('required')};render();return}state.exceptionRefValue=value;state.exceptionMessage={type:'good',text:`${t('scanSuccess')}: ${value}`};render();} function submitException(){const type=(document.getElementById('exception-type')?.value||'').trim();const ref=(document.getElementById('exception-ref')?.value||'').trim();const desc=(document.getElementById('exception-desc')?.value||'').trim();if(!type||!ref||!desc){state.exceptionMessage={type:'error',text:t('required')};render();return}state.exceptionRefValue=ref;state.exceptionMessage={type:'good',text:`${t('exceptionDone')}: ${ref}`};render();} function inventoryView(){const q=state.inventoryQuery.toLowerCase();const rows=inventory.filter(x=>!q||[x.palletNo,x.name].some(v=>String(v).toLowerCase().includes(q)));return layout(`
${q?`
`:''}
${rows.length ? rows.map(x=>``).join('') : ``}
${t('productName')}${t('customer')}${t('palletNo')}${t('qty')}${t('inventoryStatus')}
${esc(x.name)}${esc(x.customer)}${esc(x.palletNo)}${x.qty}${esc(x.status==='在库'?t('inStock'):t('inTransit'))}
${t('noResult')}
`,t('inventory'),t('inventoryDesc'),'workbench');} @@ -386,6 +395,15 @@ function profileView(){return layout(`
`;document.getElementById('modal-confirm').onclick=onConfirm;} function closeModal(){document.getElementById('modal-root').innerHTML='';} let toastTimer;function toast(message,type='info'){const root=document.getElementById('toast-root');root.innerHTML=`
${esc(message)}
`;clearTimeout(toastTimer);toastTimer=setTimeout(()=>root.innerHTML='',2600);} +function palletPhotoKey(palletId){return palletId||state.pallet?.id||`DRAFT-${state.selectedPlanId||'pallet'}`;} +function palletPhotoItems(palletId){return state.palletPhotos[palletPhotoKey(palletId)]||[];} +function openPalletPhotos(palletId,planId){if(planId)state.selectedPlanId=planId;state.photoPalletId=palletId;state.page='photo-detail';render();} +function handlePalletPhoto(input){const file=input.files&&input.files[0];if(!file)return;const key=palletPhotoKey(state.photoPalletId||state.pallet?.id);const reader=new FileReader();reader.onload=()=>{state.palletPhotos[key]??=[];state.palletPhotos[key].push(reader.result);state.photoPalletId=key;render()};reader.readAsDataURL(file);} +function photoCaptureButton(){return ``;} +function photoListMarkup(palletId){const photos=palletPhotoItems(palletId);return photos.length?`
${photos.map((src,index)=>`
${t('photoItem')} ${index+1}
${t('photoItem')} ${index+1}
`).join('')}
`:`
${t('noPhotos')}
`;} +function photoDetailView(){const key=state.photoPalletId||palletPhotoKey();const saved=state.pallets.find(x=>x.id===key);const plan=plans.find(x=>x.id===saved?.planId)||selectedPlan();return layout(`

${t('photoDetails')}

${esc(key)} · ${esc(saved?.destinationCode||plan?.destinationCode||'—')}

${palletPhotoItems(key).length}
${photoListMarkup(key)}
${photoCaptureButton()}
`,t('photoDetails'),t('palletPhotoHint'),'pallet-list');} +function injectPalletListPhotoButtons(){if(state.page!=='pallet-list')return;const consolidating=state.palletMode==='consolidate';const activePlans=consolidating?plans:[selectedPlan()];const slots=activePlans.flatMap(plan=>Array.from({length:plan.expectedPallets},(_,index)=>({plan,no:plannedPalletNo(plan,index)})));document.querySelectorAll('.list-card').forEach((card,index)=>{const slot=slots[index];const actions=card.querySelector('.card-actions');if(!slot||!actions||actions.querySelector('.photo-details-btn'))return;const button=document.createElement('button');button.className='btn ghost photo-details-btn';button.textContent=t('photoDetails');button.onclick=()=>openPalletPhotos(slot.no,slot.plan.id);actions.prepend(button);});} +function injectPalletPhotoFeatures(){if(state.page!=='pallet'||!state.pallet)return;const root=document.querySelector('.content');if(!root||root.querySelector('.pallet-site-photos'))return;const key=palletPhotoKey();const section=document.createElement('section');section.className='work-card pallet-site-photos';section.innerHTML=`

${t('sitePhotos')}

${t('palletPhotoHint')}

${palletPhotoItems(key).length}
${photoListMarkup(key)}
${photoCaptureButton()}
`;const bottom=root.querySelector('.bottom-bar');if(bottom)root.insertBefore(section,bottom);else root.appendChild(section);} function injectReservedEntries(){if(state.page!=='workbench')return;const grids=document.querySelectorAll('.entry-grid');const grid=grids[grids.length-1];if(!grid)return;const more=grid.querySelectorAll('.entry')[1];if(more)more.style.display='none';grid.insertAdjacentHTML('beforeend',``);} function injectInboundPalletUnits(){if(state.page!=='workbench')return;const inbound=document.querySelectorAll('.entry-grid')[0];const entries=inbound?.querySelectorAll('.entry');if(inbound&&entries?.[1]&&entries?.[0]){inbound.insertBefore(entries[1],entries[0]);entries[1].classList.add('receive-entry');}document.querySelectorAll('.task-strip .task-main p').forEach((el,index)=>{const p=plans.filter(x=>x.status==='待卸货')[index];if(p)el.textContent=`${p.customer} · ${p.destinationCode} · ${p.expectedPallets} ${t('palletCount')}`});} function injectOutboundEntryUnits(){if(state.page!=='workbench')return;document.querySelectorAll('.entry-grid')[1]?.classList.add('outbound-entry-grid');} @@ -411,6 +429,26 @@ Object.assign(EXTRA_LABELS.es,{vehicleType:'Tipo de vehículo',vehicleTypeValue: Object.assign(EXTRA_LABELS.zh,{skipReasonTitle:'跳拣原因',skipReasonNotFound:'未找到其他货物',skipReasonOutOfStock:'缺货',skipReasonOther:'其他'}); Object.assign(EXTRA_LABELS.en,{skipReasonTitle:'Skip reason',skipReasonNotFound:'No other freight found',skipReasonOutOfStock:'Out of stock',skipReasonOther:'Other'}); Object.assign(EXTRA_LABELS.es,{skipReasonTitle:'Motivo de omisión',skipReasonNotFound:'No se encontró otra carga',skipReasonOutOfStock:'Sin stock',skipReasonOther:'Otro'}); +Object.assign(EXTRA_LABELS.zh,{photoDetails:'照片明细',sitePhotos:'现场照片',photoItem:'照片',noPhotos:'暂无照片',palletPhotoHint:'查看或拍摄托盘现场照片'}); +Object.assign(EXTRA_LABELS.en,{photoDetails:'Photo details',sitePhotos:'Site photos',photoItem:'Photo',noPhotos:'No photos yet',palletPhotoHint:'View or capture pallet site photos'}); +Object.assign(EXTRA_LABELS.es,{photoDetails:'Detalles de fotos',sitePhotos:'Fotos en sitio',photoItem:'Foto',noPhotos:'Aún no hay fotos',palletPhotoHint:'Ver o capturar fotos del pallet'}); +Object.assign(EXTRA_LABELS.zh,{newConsolidation:'新增合托',noConsolidationPallets:'暂无合托托盘',reconsolidate:'重新合托',submitConsolidation:'提交合托',consolidationUpdated:'合托已更新'}); +Object.assign(EXTRA_LABELS.en,{newConsolidation:'New consolidation',noConsolidationPallets:'No consolidated pallets',reconsolidate:'Re-consolidate',submitConsolidation:'Submit consolidation',consolidationUpdated:'Consolidation updated'}); +Object.assign(EXTRA_LABELS.es,{newConsolidation:'Nueva consolidación',noConsolidationPallets:'No hay pallets consolidados',reconsolidate:'Reconsolidar',submitConsolidation:'Enviar consolidación',consolidationUpdated:'Consolidación actualizada'}); +const basePalletListView=palletListView; +palletListView=function(){const consolidating=state.palletMode==='consolidate';if(!consolidating)return basePalletListView();const created=consolidating ? state.pallets.filter(pallet=>pallet.mode==='consolidate') : [];return layout(`
${created.length} ${t('palletCount')}
${created.length?`
${created.map(pallet=>{const sourcePlan=plans.find(plan=>plan.id===pallet.items[0]?.planNo);return `
${esc(pallet.id)}
${esc(sourcePlan?.id||'—')} · ${esc(pallet.container||sourcePlan?.container||'—')}
${t('occupied')}
${t('destination')}${esc(pallet.destinationCode||'—')}
${t('cartonCount')}${pallet.items.length}
`}).join('')}
`:`
${t('noConsolidationPallets')}
`}
`,t('mergeOnly'),t('mergeDesc'),'workbench');}; +function startNewConsolidation(){state.palletMode='consolidate';state.pallet=null;state.palletMessage=null;state.photoPalletId='';startPallet();} +function reconsolidatePallet(palletId){const saved=state.pallets.find(pallet=>pallet.id===palletId&&pallet.mode==='consolidate');if(!saved)return;state.palletMode='consolidate';state.pallet={...JSON.parse(JSON.stringify(saved)),originalPalletId:palletId};state.palletMessage=null;state.photoPalletId='';state.page='pallet';render();} +function submitConsolidation(){if(!state.pallet?.items.length){state.palletMessage={type:'error',text:t('emptyPallet')};render();return}const originalPalletId=state.pallet.originalPalletId;const originalIndex=state.pallets.findIndex(pallet=>pallet.id===originalPalletId);if(originalIndex<0){submitPallet();return}const updated=JSON.parse(JSON.stringify(state.pallet));delete updated.originalPalletId;delete updated.persisted;state.pallets[originalIndex]=updated;updated.items.forEach(item=>{const source=cargo.find(c=>c.id===item.id);if(source)source.palletNo=updated.id});state.pallet=null;state.palletMessage=null;toast(t('consolidationUpdated'),'good');state.page='pallet-list';render();} +photoCaptureButton=function(id='pallet-photo-capture-input'){return ``;}; +photoAddButton=function(){const id='pallet-site-photo-input';return ``;}; +photoDetailView=function(){const key=state.photoPalletId||palletPhotoKey();const saved=state.pallets.find(x=>x.id===key);const plan=plans.find(x=>x.id===saved?.planId)||selectedPlan();return layout(`

${t('photoDetails')}

${esc(key)} · ${esc(saved?.destinationCode||plan?.destinationCode||'—')}

${palletPhotoItems(key).length}
${photoListMarkup(key)}
${photoCaptureButton()}
`,t('photoDetails'),t('palletPhotoHint'),'pallet-list');}; +injectPalletPhotoFeatures=function(){if(state.page!=='pallet'||!state.pallet)return;const root=document.querySelector('.content');if(!root||root.querySelector('.pallet-site-photos'))return;const key=palletPhotoKey();const photos=palletPhotoItems(key);const photoTiles=photos.length?`
${photos.map((src,index)=>`
${t('photoItem')} ${index+1}
${t('photoItem')} ${index+1}
`).join('')}
`:'';const section=document.createElement('section');section.className='work-card pallet-site-photos';section.innerHTML=`

${t('sitePhotos')}

${t('palletPhotoHint')}

${photos.length}
${photoTiles}
${photoAddButton()}
`;const bottom=root.querySelector('.bottom-bar');if(bottom)root.insertBefore(section,bottom);else root.appendChild(section);}; +injectPalletListPhotoButtons=function(){if(state.page!=='pallet-list')return;document.querySelectorAll('.list-card .card-actions').forEach(actions=>{actions.querySelector('.btn.ghost')?.style.setProperty('margin-right','auto');});}; +function injectReconsolidationSubmit(){if(state.page!=='pallet'||!state.pallet?.originalPalletId)return;const button=document.querySelector('.bottom-bar .btn.primary');if(!button)return;button.textContent=t('submitConsolidation');button.disabled=!state.pallet.items.length;button.onclick=submitConsolidation;} +function injectCurrentPalletCleanup(){if(state.page!=='pallet'||!state.pallet)return;document.querySelector('.content > .work-card:first-child .work-head > .status')?.remove();} +const baseRender=render; +render=function(){if(state.page==='photo-detail'){document.getElementById('app').innerHTML=photoDetailView();injectIconReplacements();document.documentElement.lang=state.lang==='zh'?'zh-CN':state.lang==='es'?'es':'en';return}baseRender();injectPalletListPhotoButtons();injectPalletPhotoFeatures();injectReconsolidationSubmit();injectCurrentPalletCleanup();}; render(); diff --git a/悦/货代SAAS平台后台/index.html b/悦/货代SAAS平台后台/index.html index 59030e4..7d9c5e1 100644 --- a/悦/货代SAAS平台后台/index.html +++ b/悦/货代SAAS平台后台/index.html @@ -598,6 +598,10 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .dispatch-exception-actions a:hover{text-decoration:underline} .dispatch-exception-actions a.danger{color:#dc2626} .dispatch-exception-process-note{padding:10px 12px;border:1px solid #fde68a;border-radius:6px;background:#fffbeb;color:#92400e;font-size:12px;line-height:1.5;margin-bottom:14px} +.customer-followup-file{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:6px;background:#fff} +.customer-followup-file-name{min-width:0;overflow:hidden;color:#374151;font-size:12px;text-overflow:ellipsis;white-space:nowrap} +.customer-followup-file-meta{display:block;margin-top:2px;color:#9ca3af;font-size:11px} +.customer-followup-file-delete{flex:0 0 auto;padding:3px 7px;border:1px solid #fecaca;border-radius:4px;background:#fff;color:#b91c1c;font-size:11px;cursor:pointer} .dispatch-doc-cell{width:312px;min-width:312px;padding:2px 0} .dispatch-doc-summary{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:7px} .dispatch-doc-count{font-size:11px;font-weight:600;color:#374151;white-space:nowrap} @@ -651,7 +655,7 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .warehouse-page-tab:hover{color:#1677ff;background:#f7faff} .warehouse-page-tab.active{border-bottom-color:#1677ff;color:#1677ff;font-weight:650} .warehouse-page-tab:focus-visible{outline:2px solid #1677ff;outline-offset:2px} -#page-gen-owned-warehouse .warehouse-table-wrap,#page-gen-fba .warehouse-table-wrap,#page-gen-partner-warehouse .warehouse-table-wrap{width:100%;overflow-x:auto} +#page-gen-owned-warehouse .warehouse-table-wrap,#page-gen-fba .warehouse-table-wrap,#page-gen-partner-warehouse .warehouse-table-wrap,#page-gen-private-warehouse .warehouse-table-wrap{width:100%;overflow-x:auto} .warehouse-table-wrap table{min-width:1040px} .vehicle-owner-tabs{display:inline-flex;align-items:center;margin:14px 0 12px;padding:3px;border:1px solid #dfe5ee;border-radius:6px;background:#f4f6f9} .vehicle-owner-tab{min-width:104px;height:32px;padding:0 16px;border:0;border-radius:4px;background:transparent;color:#5f6b7a;font-size:13px;cursor:pointer} @@ -682,7 +686,7 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .vehicle-detail-relation.is-current{color:#1677ff;background:#eaf3ff} .vehicle-detail-relation.is-history{color:#64748b;background:#f1f5f9} @media(max-width:900px){.vehicle-detail-head{align-items:flex-start;flex-direction:column;padding:16px 18px}.vehicle-detail-head .btn{align-self:flex-end}.vehicle-detail-body{padding:16px 18px 20px}.vehicle-detail-grid{grid-template-columns:1fr}.vehicle-region-tabs{overflow-x:auto}.vehicle-region-tab,.warehouse-page-tab{flex:1;min-width:104px;padding:0 14px}} -@media(max-width:700px){.dispatch-doc-modal-meta,.dispatch-reject-meta{grid-template-columns:1fr}.dispatch-reject-meta>div:first-child{grid-column:auto}.dispatch-doc-row{grid-template-columns:1fr}.dispatch-doc-controls{justify-content:flex-start}.vehicle-detail-field{grid-template-columns:96px minmax(0,1fr)}.vehicle-detail-empty{position:sticky;left:0;background:#fff;text-align:left!important}} +@media(max-width:700px){.dispatch-doc-modal-meta,.dispatch-reject-meta,.customer-followup-modal-meta{grid-template-columns:1fr!important}.dispatch-reject-meta>div:first-child{grid-column:auto}.customer-followup-modal-meta>div{grid-column:auto!important}.dispatch-doc-row{grid-template-columns:1fr}.dispatch-doc-controls{justify-content:flex-start}.vehicle-detail-field{grid-template-columns:96px minmax(0,1fr)}.vehicle-detail-empty{position:sticky;left:0;background:#fff;text-align:left!important}} .inbound-action-row{display:flex;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid #e5e7eb} .inbound-action-row .btn{padding:7px 14px;font-size:12px;border-radius:4px;font-weight:600} .inbound-button-group{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap} @@ -981,6 +985,61 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font #booking-print-sheet{display:block!important;position:absolute!important;left:0!important;top:0!important;width:210mm!important;height:297mm!important;margin:0!important} #booking-print-sheet>.booking-print-sheet{display:block!important;width:210mm!important;min-height:297mm!important;margin:0!important;transform:none!important;box-shadow:none!important} } +/* ===== 派送单 BOL 模板打印 ===== */ +.dispatch-bol-print-modal{padding:20px;box-sizing:border-box;background:rgba(15,23,42,.58)} +.dispatch-bol-print-panel{width:min(1120px,96vw);height:min(94vh,980px);max-width:1120px;max-height:94vh;display:flex;flex-direction:column;overflow:hidden;background:#fff;border-radius:10px;box-shadow:0 18px 48px rgba(15,23,42,.24)} +.dispatch-bol-print-toolbar{min-height:64px;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid #e5e7eb;background:#fff;box-sizing:border-box} +.dispatch-bol-print-toolbar>div:first-child{display:grid;gap:3px;min-width:0} +.dispatch-bol-print-toolbar span{font-size:11px;color:#64748b} +#dispatch-bol-print-title{font-size:15px;color:#1f2937;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.dispatch-bol-print-actions{display:flex;align-items:center;gap:8px;flex:0 0 auto} +.dispatch-bol-print-close{width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:6px;background:transparent;color:#64748b;font-size:24px;line-height:1;cursor:pointer} +.dispatch-bol-print-close:hover{background:#f1f5f9;color:#1f2937} +.dispatch-bol-print-close:focus-visible{outline:2px solid #1677ff;outline-offset:2px} +.dispatch-bol-print-scroll{flex:1;min-height:0;overflow:auto;padding:24px;background:#eef1f5;box-sizing:border-box} +#dispatch-bol-print-stage{position:relative;margin:0 auto} +#dispatch-bol-print-sheet>.dispatch-bol-sheet{width:210mm;min-height:297mm;padding:10mm 12mm 18mm;box-sizing:border-box;background:#fff;color:#000;transform-origin:top left;box-shadow:0 4px 20px rgba(15,23,42,.14);font-family:Arial,"Microsoft YaHei",sans-serif;font-size:10.5pt;line-height:1.24;page:dispatchBol} +.dispatch-bol-sheet *{box-sizing:border-box} +.dispatch-bol-document-title{height:15mm;display:flex;align-items:center;justify-content:center;border:1px solid #000;background:#000;color:#fff;font-family:"Times New Roman","SimSun",serif;font-size:24pt;font-weight:700;line-height:1;letter-spacing:.01em} +.dispatch-bol-summary{display:grid;grid-template-columns:52.5% 47.5%;border-left:1px solid #000;border-right:1px solid #000} +.dispatch-bol-summary>section{min-width:0;border-bottom:1px solid #000} +.dispatch-bol-summary>section+section{border-left:1px solid #000} +.dispatch-bol-section-title{height:9mm;margin:0;padding:0 1mm;display:flex;align-items:center;background:#000;color:#fff;font-family:"Times New Roman","SimSun",serif;font-size:16pt;font-weight:400;line-height:1} +.dispatch-bol-section-body{padding:2mm 1.5mm} +.dispatch-bol-top .dispatch-bol-section-body{min-height:36mm;display:flex;flex-direction:column;justify-content:center} +.dispatch-bol-shipper strong{display:block;margin-bottom:1mm;font-size:16pt;line-height:1.15} +.dispatch-bol-address{white-space:pre-line;font-size:12pt;line-height:1.28} +.dispatch-bol-fields{display:grid;grid-template-columns:max-content minmax(0,1fr);align-content:center;gap:.8mm 1.5mm;font-size:11pt} +.dispatch-bol-fields dt{font-weight:400} +.dispatch-bol-fields dd{margin:0;min-width:0;overflow-wrap:anywhere} +.dispatch-bol-fields .is-emphasis{font-weight:700} +.dispatch-bol-middle .dispatch-bol-section-body{min-height:27mm;padding-top:1.5mm} +.dispatch-bol-destination-title{font-size:12pt;margin-bottom:.8mm} +.dispatch-bol-destination-line{font-size:11.5pt;line-height:1.38} +.dispatch-bol-lines{width:100%;border-collapse:collapse;table-layout:fixed;font-family:"Times New Roman","SimSun",serif;font-size:9.5pt} +.dispatch-bol-lines th,.dispatch-bol-lines td{border:1px solid #000;padding:1.8mm 1mm;text-align:center;vertical-align:middle;overflow-wrap:anywhere} +.dispatch-bol-lines th{height:13mm;background:#fff;color:#000;font-family:Arial,"Microsoft YaHei",sans-serif;font-size:9pt;line-height:1.15;white-space:normal} +.dispatch-bol-lines td{height:9mm;font-size:8.5pt;white-space:nowrap;overflow-wrap:normal} +.dispatch-bol-lines th:nth-child(1){width:9%}.dispatch-bol-lines th:nth-child(2){width:14%}.dispatch-bol-lines th:nth-child(3){width:12%}.dispatch-bol-lines th:nth-child(4){width:18%}.dispatch-bol-lines th:nth-child(5){width:22%}.dispatch-bol-lines th:nth-child(6){width:18%}.dispatch-bol-lines th:nth-child(7){width:7%} +.dispatch-bol-lines thead{display:table-header-group} +.dispatch-bol-lines tr{break-inside:avoid;page-break-inside:avoid} +.dispatch-bol-empty{height:24mm!important;color:#4b5563;font-family:Arial,"Microsoft YaHei",sans-serif!important} +.dispatch-bol-total{display:grid;grid-template-columns:1fr auto;align-items:center;gap:12mm;margin:12mm 18mm 0;font-family:"Times New Roman","SimSun",serif;font-size:12pt;break-inside:avoid;page-break-inside:avoid} +.dispatch-bol-total strong{font-family:Arial,"Microsoft YaHei",sans-serif;font-size:18pt;font-weight:400;line-height:1} +@media(max-width:680px){.dispatch-bol-print-modal{padding:8px}.dispatch-bol-print-panel{width:calc(100vw - 16px);height:calc(100vh - 16px);max-height:none}.dispatch-bol-print-toolbar{align-items:flex-start;gap:10px;padding:10px 12px;flex-wrap:wrap}.dispatch-bol-print-actions{width:100%;justify-content:flex-end}.dispatch-bol-print-scroll{padding:12px}} +@page dispatchBol{size:A4 portrait;margin:0} +@media print{ + html:has(body.dispatch-bol-printing),body.dispatch-bol-printing{width:210mm!important;min-width:0!important;height:auto!important;min-height:0!important;margin:0!important;padding:0!important;background:#fff!important;overflow:visible!important} + body.dispatch-bol-printing>*:not(#modal-dispatch-bol-print){display:none!important} + body.dispatch-bol-printing #modal-booking-print-preview,body.dispatch-bol-printing #modal-ct-pallet-label-preview{display:none!important} + body.dispatch-bol-printing #modal-dispatch-bol-print{display:block!important;position:static!important;inset:auto!important;width:210mm!important;height:auto!important;padding:0!important;background:#fff!important} + body.dispatch-bol-printing #modal-dispatch-bol-print,body.dispatch-bol-printing #modal-dispatch-bol-print *{visibility:visible!important} + body.dispatch-bol-printing .dispatch-bol-print-panel{display:block!important;position:static!important;width:210mm!important;height:auto!important;max-width:none!important;max-height:none!important;border:0!important;border-radius:0!important;box-shadow:none!important;overflow:visible!important} + body.dispatch-bol-printing .dispatch-bol-print-toolbar{display:none!important} + body.dispatch-bol-printing .dispatch-bol-print-scroll{display:block!important;position:static!important;width:210mm!important;height:auto!important;padding:0!important;background:#fff!important;overflow:visible!important} + body.dispatch-bol-printing #dispatch-bol-print-stage,body.dispatch-bol-printing #dispatch-bol-print-sheet{display:block!important;position:static!important;width:210mm!important;height:auto!important;margin:0!important} + body.dispatch-bol-printing #dispatch-bol-print-sheet>.dispatch-bol-sheet{display:block!important;width:210mm!important;min-height:297mm!important;margin:0!important;transform:none!important;box-shadow:none!important} +} /* 基本Tab只读展示 */ .basic-readonly input,.basic-readonly select,.basic-readonly textarea{background:#f5f5f5;color:#666;cursor:not-allowed;pointer-events:none} /* MB/L 逐行字段 */ @@ -1261,6 +1320,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou @@ -1537,11 +1598,11 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - + -详情 | +详情 | EXP260814001 -审核通过 +已入库 审核通过 2026-08-14 未录入费用 @@ -1592,6 +1653,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
@@ -1704,6 +1766,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
@@ -1816,6 +1879,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
@@ -1928,6 +1992,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
@@ -2040,6 +2105,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
@@ -3082,7 +3148,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 单号 到达状态(FBA状态编号) 配送 -编辑 输入人 输入时间 FBA配送类型 @@ -3096,7 +3161,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - +
资料加载中…
派送中 海卡 @@ -3121,7 +3186,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou D202606001 已签收 是 -编辑 李输入 2026-06-15 09:00 FBA-标准 @@ -3133,7 +3197,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 7260.00 - +
资料加载中…
已签收 海卡 @@ -3158,7 +3222,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou D202606002 已签收 是 -编辑 王输入 2026-06-14 07:30 FBA-标准 @@ -3170,7 +3233,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 5775.00 - +
资料加载中…
派送中 海卡 @@ -3195,7 +3258,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou D202606003 运输中 否 -编辑 张输入 2026-06-15 10:00 FBA-加急 @@ -3207,7 +3269,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 3520.00 - +
资料加载中…
已签收 海卡 @@ -3232,7 +3294,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou D202606004 已签收 是 -编辑 陈输入 2026-06-13 08:10 FBA-退货 @@ -3244,7 +3305,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 1072.50 - +
资料加载中…
派送中 海卡 @@ -3269,7 +3330,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou D202606005 待处理 否 -编辑 刘输入 2026-06-15 14:00 FBA-标准 @@ -4120,7 +4180,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-
异常订单
+
异常订单
0异常订单
0待处理
0处理中
@@ -4136,6 +4196,26 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
+ +
+
+ +
客户回访
+
i页面展示最近 7 天内已完成派送的订单,完成时间以签收/派送完成时间为准。
+
0可回访订单
0待回访
0已完成回访
+
+
+ + + +
+
+
+ +
操作派送单号客户联系人完成时间目的地回访状态回访时间回访结果资料
+
+
+
产品信息
@@ -4184,25 +4264,32 @@ FORM: 已建立后台列表页的精确扩展;本次需求已明确,因此
仓库管理
-
+
自有仓名称仓库地址城市州/省邮编国家状态操作
仓库管理
-
+
自有仓
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
仓库管理
-
+
自有仓
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+
仓库管理
+
+
自有仓
+
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+ @@ -8741,6 +8829,9 @@ FORM: 通用模块中的管理清单加分区编辑弹窗,作为既有后台 总箱数 计费体积(m³) 总托盘数 +托盘类型 +是否外配 +是否加急 状态 FBA预约 排车状态 @@ -8750,7 +8841,7 @@ FORM: 通用模块中的管理清单加分区编辑弹窗,作为既有后台
- + @@ -8786,7 +8877,7 @@ FORM: 通用模块中的管理清单加分区编辑弹窗,作为既有后台
作业要求
-
+
@@ -9100,9 +9191,11 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 .lmo-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-top:14px}.lmo-section{background:#fff;border:1px solid #e5eaf1;border-radius:8px;overflow:hidden}.lmo-section.wide{grid-column:1/-1}.lmo-section-title{min-height:44px;padding:12px 16px;border-bottom:1px solid #e8edf3;box-sizing:border-box;font-size:14px;font-weight:700;color:#1f2937}.lmo-info-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));padding:4px 16px 12px}.lmo-info-item{display:grid;grid-template-columns:118px minmax(0,1fr);gap:10px;padding:10px 4px;border-bottom:1px solid #f0f2f5;font-size:13px}.lmo-info-item .label{color:#8491a3}.lmo-info-item .value{color:#273548;font-weight:500;word-break:break-word}.lmo-empty{padding:28px;text-align:center;color:#94a3b8;font-size:13px} .lmo-departure-fee-head{display:flex;align-items:center;justify-content:space-between;gap:10px}.lmo-departure-fee-hint{font-size:12px;font-weight:400;color:#8491a3}.lmo-departure-fee-scroll{overflow-x:auto}.lmo-departure-fee-table{width:100%;min-width:620px;border-collapse:collapse;font-size:12px}.lmo-departure-fee-table th{padding:10px 12px;background:#f8fafc;border-bottom:1px solid #e8edf3;color:#526071;font-weight:650;text-align:left;white-space:nowrap}.lmo-departure-fee-table td{padding:10px 12px;border-bottom:1px solid #f0f2f5;color:#334155;white-space:nowrap;vertical-align:middle}.lmo-departure-fee-table tbody tr:last-child td{border-bottom:0}.lmo-departure-fee-table .supplier-cell{color:#475569}.lmo-departure-fee-table .amount-cell{text-align:right;color:#1f5fbf;font-weight:700}.lmo-departure-fee-table tfoot td{border-top:1px solid #dce3ec;border-bottom:0;background:#f8fafc;font-weight:700}.lmo-departure-fee-table .total-label{text-align:right;color:#526071}.lmo-departure-fee-table .total-amount{color:#111827}.lmo-departure-fee-empty{padding:28px!important;text-align:center;color:#94a3b8!important} .lmo-modal-note{margin-bottom:14px;padding:10px 12px;border:1px solid #dbeafe;border-radius:6px;background:#f7faff;color:#526071;font-size:12px}.lmo-modal-note.warning{border-color:#fde2b8;background:#fffaf0;color:#9a5b13} +#modal-lmo-manual-nodes .modal{display:flex;max-height:calc(100vh - 48px);overflow:hidden;flex-direction:column}#modal-lmo-manual-nodes .modal-body{min-height:0;overflow:hidden}#modal-lmo-manual-nodes .modal-header,#modal-lmo-manual-nodes .modal-footer{flex:0 0 auto}.lmo-manual-node-order{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:14px;padding:11px 13px;border:1px solid #e5eaf1;border-radius:6px;background:#f8fafc;color:#64748b;font-size:12px}.lmo-manual-node-order strong{min-width:0;color:#1f2937;font-size:13px;overflow-wrap:anywhere}.lmo-manual-node-wrap{max-height:430px;overflow:auto;border:1px solid #e5eaf1;border-radius:7px}.lmo-manual-node-table{width:100%;min-width:560px;border-collapse:collapse}.lmo-manual-node-table th{position:sticky;top:0;z-index:1;padding:10px 14px;background:#f8fafc;border-bottom:1px solid #e5eaf1;color:#526071;font-size:12px;font-weight:650;text-align:left}.lmo-manual-node-table td{padding:9px 14px;border-bottom:1px solid #edf0f4;color:#334155;font-size:13px}.lmo-manual-node-table tr:last-child td{border-bottom:0}.lmo-manual-node-table input{width:100%;min-width:220px;height:36px;padding:0 10px;border:1px solid #d7dee8;border-radius:6px;background:#fff;color:#273548;font:13px inherit;box-sizing:border-box;outline:none}.lmo-manual-node-table input:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)} .lmo-checkbox-option{display:flex;align-items:center;gap:8px;min-height:36px;color:#334155;font-size:13px;cursor:pointer}.lmo-checkbox-option input{width:16px;height:16px;margin:0;accent-color:#667eea} @media(max-width:900px){.lmo-detail-grid{grid-template-columns:1fr}.lmo-section.wide{grid-column:auto}.lmo-detail-head{align-items:flex-start;flex-wrap:wrap}.lmo-detail-head .lmo-detail-actions{width:100%;margin-left:0}.lmo-info-grid{grid-template-columns:1fr}.lmo-field-selector-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} @media(max-width:600px){#modal-lmo-inbound-plan .modal{width:calc(100% - 24px);max-width:none}.modal-overlay#modal-lmo-inbound-plan .modal-body{padding:20px}.modal-overlay#modal-lmo-inbound-plan .form-row{grid-template-columns:minmax(0,1fr);gap:12px;margin-bottom:12px}.modal-overlay#modal-lmo-inbound-plan .form-group{min-width:0}.modal-overlay#modal-lmo-inbound-plan .modal-footer{padding:12px 16px;flex-wrap:wrap}} +@media(max-width:600px){#modal-lmo-manual-nodes .modal{width:calc(100% - 24px);max-width:none}#modal-lmo-manual-nodes .modal-body{padding:16px}#modal-lmo-manual-nodes .modal-footer{padding:12px 16px;flex-wrap:wrap}.lmo-manual-node-order{align-items:flex-start;flex-direction:column;gap:4px}.lmo-manual-node-table{min-width:0;table-layout:fixed}.lmo-manual-node-table th:first-child{width:42%!important}.lmo-manual-node-table th,.lmo-manual-node-table td{padding-inline:10px}.lmo-manual-node-table input{min-width:0;padding-inline:7px;font-size:12px}} @media(max-width:600px){#modal-fba-relabel-form .modal{width:calc(100% - 24px)!important;max-width:none!important}#modal-fba-relabel-form .modal-body{padding:20px}#modal-fba-relabel-form .form-row{grid-template-columns:minmax(0,1fr);gap:12px;margin-bottom:12px}#modal-fba-relabel-form .form-group{min-width:0}#modal-fba-relabel-form .modal-footer{padding:12px 16px;flex-wrap:wrap}} @@ -9114,6 +9207,8 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度
+ +
+ + + - + @@ -9171,6 +9270,10 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 + + + + @@ -10164,6 +10267,25 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 + +
+
+
+
本土卡车订单详情
-
+
-
+
+
+
+

运输信息

+

联系人信息

+

货物信息

+

时间与费用

+

上传资料

+
+
+
+
+
@@ -10209,6 +10331,12 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度
+ +
+
+
支持多文件上传,保存后可再次编辑删除。
+
+
@@ -10285,6 +10413,26 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度
+ + +