diff --git a/.gitignore b/.gitignore index 4f074fd..8721ed8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ .DS_Store **/.DS_Store +.playwright-cli +.superpowers +output +docs \ No newline at end of file diff --git a/悦/货代SAAS平台后台/AGENTS.md b/悦/货代SAAS平台后台/AGENTS.md index 79996ab..a0494de 100644 --- a/悦/货代SAAS平台后台/AGENTS.md +++ b/悦/货代SAAS平台后台/AGENTS.md @@ -4,7 +4,7 @@ - 页面、字段和局部交互先按下方“原型模块快速索引”定位,再只读取命中的 `prototype-src/modules/*.html`。 - 页面涉及弹窗、抽屉或跨模块交互时,再读取 `prototype-src/overlays.html` 和 `prototype-src/app.js` 中对应 ID/函数;视觉样式按需读取 `prototype-src/shell.html`。 -- `index.html` 是由拆分源码生成的完整可运行入口,本地预览直接双击它。`货代SaaS平台原型-完整备份.html` 仅作为迁移前的大文件备份,不作为日常入口。 +- `index.html` 是由拆分源码生成的完整可运行入口,本地预览直接双击它。 - WMS 字段未在原型中明确时,再读取 `wms_full_data.json` 和 `柏悦WMS系统文档.md`。 ## 怎么看 @@ -117,15 +117,16 @@ node tests/verify-prototype-modules.cjs |---|---|---| | 首页数据看板 | `prototype-src/modules/00-dashboard.html` | `dashboard` | | 客户管理 | `prototype-src/modules/01-customers.html` | `tenant-list`、`tenant-detail`、`warehouse-tier-fee` | -| 国内仓 | `prototype-src/modules/02-domestic-warehouse.html` | 入库订单与详情、测量/收货审核、WMS 基础/入库/盘点/出库/库存/加工/移库/上架、库位、托盘、国内整柜 | +| 国内仓 | `prototype-src/modules/02-domestic-warehouse.html` | 入库订单与详情、测量/收货审核、WMS 基础/入库/盘点/出库/库存/加工/移库/上架、库位、托盘及详情、国内整柜 | | 海外仓 | `prototype-src/modules/03-overseas-warehouse.html` | 尾程订单,海外仓入库/出库/换标,产品/托盘/箱号/库存,采购库存及详情 | | 海外派送 | `prototype-src/modules/04-overseas-delivery.html` | `outbound-dispatch`、BOL/自提历史页、排车列表/编辑/详情 | +| 客户服务 | `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/08-finance.html` | 客户账户、应收应付、对账单、结算单、费用分析、利润表及历史财务报表页 | | 销售管理 | `prototype-src/modules/09-sales.html` | 拜访记录新增/详情、销售提成 | -| 通用资料 | `prototype-src/modules/10-general.html` | 产品、费用项目、仓库、下载、船期价格、车辆及历史库位/托盘/路线页 | +| 通用资料 | `prototype-src/modules/10-general.html` | 产品、费用项目、汇率管理、仓库(`gen-owned-warehouse`、`gen-fba`、`gen-partner-warehouse`)、下载、船期价格、车辆及详情、派送车队报价表、历史库位/托盘/路线页 | | 系统与消息 | `prototype-src/modules/11-system-messages.html` | 用户、角色、菜单权限、品牌/客户历史页、消息管理/模板/我的消息、海外用户 | | 历史订单与库存 | `prototype-src/modules/12-legacy-orders.html` | 旧运单、OMS、库存及库龄页面;当前侧栏无直接入口,使用前核对需求 | | 运价、报关与清关 | `prototype-src/modules/13-freight-customs.html` | 旧运价/报价/空运/铁路/对账/报表、报关基础资料、清关页面;当前侧栏无直接入口,使用前核对需求 | diff --git a/悦/货代SAAS平台后台/PDA(海外)/index.html b/悦/货代SAAS平台后台/PDA(海外)/index.html new file mode 100644 index 0000000..c3b9a26 --- /dev/null +++ b/悦/货代SAAS平台后台/PDA(海外)/index.html @@ -0,0 +1,417 @@ + + + + + +Overseas Warehouse PDA + + + + + + +
+ +
+ + + diff --git a/悦/货代SAAS平台后台/PRODUCT.md b/悦/货代SAAS平台后台/PRODUCT.md new file mode 100644 index 0000000..70a832a --- /dev/null +++ b/悦/货代SAAS平台后台/PRODUCT.md @@ -0,0 +1,47 @@ +# Product + + + +## Platform + +web + +## Users + +货代 SaaS 平台的后台管理、运营、仓储、财务及相关业务人员。他们在桌面端为主的管理环境中,重复处理客户、仓库、运输、货柜、海外业务、财务、销售、通用资料和系统配置等操作。 + +## Product Purpose + +平台集中承载货代业务的资料维护、订单执行、仓储作业、派送、结算和管理流程。成功意味着用户能够快速定位业务模块,准确查看和维护字段,并在列表、详情、弹窗和状态流转之间完成可追溯操作。 + +## Operating Context + +- 产品以完整可运行的后台原型交付,`index.html` 是验收入口。 +- 维护源码按一级业务导航拆分到 `prototype-src/modules/*.html`,共用弹窗位于 `prototype-src/overlays.html`,交互位于 `prototype-src/app.js`。 +- 页面通过侧栏进入;没有导航入口的页面按历史或隐藏页面处理。 +- 表格、筛选、弹窗、状态、审计字段和跨模块数据联动是主要交互形式。 + +## Capabilities and Constraints + +- 当前交付是原生 HTML、CSS 和 JavaScript 构成的静态后台原型,不包含后端持久化。 +- 页面 ID、模块归属、导航入口和生成顺序由 `prototype-src/manifest.json` 约束。 +- 新增或修改页面后必须重建 `index.html` 并运行模块一致性校验。 +- 产品文案使用中文;业务代码、币种、仓号等保留约定的英文缩写。 +- 未在原型、阶段需求或已确认契约中定义的业务流程不得猜测补齐。 + +## Evidence on Hand + +- 完整后台原型及拆分源码:`index.html`、`prototype-src/` +- 页面与模块维护规则:`AGENTS.md` +- WMS 字段资料:`wms_full_data.json`、`柏悦WMS系统文档.md` +- 自动验证脚本:`tests/` + +仓库中没有可用于对外宣传的客户证明、商业指标或品牌素材,后续界面不得虚构此类内容。 + +## Product Principles + +- 业务契约优先:页面字段、状态和流程以已确认需求与原型为准。 +- 操作效率优先:后台界面保持紧凑、可扫描,并支持高频重复操作。 +- 数据可追溯:关键维护动作保留时间、人员、状态和历史记录。 +- 模块边界稳定:列表、详情和编辑保持在同一业务域,共用交互放入共享文件。 +- 验证后交付:源码修改、完整入口构建和交互验收必须一致。 diff --git a/悦/货代SAAS平台后台/fee-detail-layout-options.html b/悦/货代SAAS平台后台/fee-detail-layout-options.html new file mode 100644 index 0000000..516da1e --- /dev/null +++ b/悦/货代SAAS平台后台/fee-detail-layout-options.html @@ -0,0 +1,27 @@ + + + + + +尾程订单详情 - 费用明细布局 + + + +
+

尾程订单详情:费用明细布局草图

按你的要求,将“关联单据”移至“计划信息”之后,费用明细紧随其后。

+
+
A推荐:关联单据后使用全宽费用表便于核对多项费用及合计
+
+
订单信息→订单明细→计划信息→关联单据→费用明细→货物信息 / 操作记录
+
+
计划信息
入仓码LA-ONT8-0813
计划出库日期2026-08-15
合托批次CT20260813001
派送方式卡车派送
+
关联单据
入库单 FBI20260813001
出库单 FBO20260815001
派送单 FBD20260815001
+
费用明细 费用项目按订单实际发生展示
费用项目计费说明币种单价数量金额费用状态
仓储费在库 3 天USD2.008 托48.00待结算
贴标费FNSKU 贴标USD0.152,304 件345.60待结算
出库费整托出库USD12.008 托96.00待结算
派送费FBA ONT8USD—1 单180.00待结算
已发生 4 项费用合计 USD 669.60
+
+
+
+
+ + diff --git a/悦/货代SAAS平台后台/index.html b/悦/货代SAAS平台后台/index.html index 8a9f9e3..59030e4 100644 --- a/悦/货代SAAS平台后台/index.html +++ b/悦/货代SAAS平台后台/index.html @@ -37,6 +37,8 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Helv .top-message-dropdown button span{width:20px;text-align:center} .hamburger{color:#fff;font-size:24px;cursor:pointer;transition:all .3s;position:relative;z-index:1;padding:8px;border-radius:8px} .hamburger:hover{background:rgba(255,255,255,.15);transform:scale(1.1)} +@media(max-width:1100px){.top-nav .tenant-switch{display:none}} +@media(max-width:820px){.top-nav{padding:0 12px;gap:8px}.top-nav .logo{min-width:0}.top-nav .nav-right{display:none}} .layout{display:flex;margin-top:64px;height:calc(100vh - 64px);overflow:hidden} .sidebar{width:240px;background:rgba(255,255,255,.9);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-right:1px solid rgba(255,255,255,.3);position:fixed;top:64px;left:0;bottom:0;overflow-y:auto;z-index:90;transition:transform .35s cubic-bezier(.4,0,.2,1);padding:12px 0;box-shadow:4px 0 32px rgba(0,0,0,.08)} .sidebar.collapsed{transform:translateX(-240px)} @@ -81,6 +83,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Helv .stat-card:nth-child(3) .decorator{background:linear-gradient(135deg,#f59e0b,#ea580c)} .stat-card:nth-child(4) .decorator{background:linear-gradient(135deg,#7c3aed,#6d28d9)} .stat-card:nth-child(5) .decorator{background:linear-gradient(135deg,#ec4899,#db2777)} +#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:repeat(4,minmax(0,1fr))} +#page-gen-exchange-rate .exchange-rate-summary .stat-card{min-width:0} +#page-gen-exchange-rate .exchange-rate-summary .value{font-size:20px;line-height:1.35;letter-spacing:0;overflow-wrap:anywhere} +#page-gen-exchange-rate .table-toolbar{gap:12px;flex-wrap:wrap} +@media(max-width:1200px){#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:repeat(2,minmax(0,1fr))}} +@media(max-width:640px){#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:1fr}} /* CHART */ .chart-row{display:grid;grid-template-columns:2fr 1fr;gap:20px;margin-bottom:20px} .chart-row.equal{grid-template-columns:1fr 1fr} @@ -139,7 +147,7 @@ canvas{max-height:280px} #rsq-wrap.rsq-collapsed .rsq-toggle svg{transform:rotate(180deg)} .recon-main-table-wrap{overflow-x:auto} #page-customer-arap .arap-table-wrap{width:100%;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch} -#page-customer-arap .arap-table{width:2005px;min-width:2005px;table-layout:fixed;border-collapse:collapse;font-size:12.5px} +#page-customer-arap .arap-table{width:1800px;min-width:1800px;table-layout:fixed;border-collapse:collapse;font-size:12.5px} #page-customer-arap .arap-table th{height:44px;padding:10px 8px;background:#f5f6fb;color:#333;font-size:12px;font-weight:600;text-align:left;white-space:nowrap} #page-customer-arap .arap-table td{height:55px;padding:10px 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} #page-customer-arap .arap-table th:nth-child(1),#page-customer-arap .arap-table td:nth-child(1){padding-left:5px;padding-right:5px} @@ -147,26 +155,32 @@ canvas{max-height:280px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar{height:8px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar-thumb{background:#cfd6df;border-radius:8px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar-track{background:#f3f4f6} -#page-customer-recon-stmt .recon-main-table{font-size:11px;min-width:1740px;table-layout:fixed} +#page-customer-recon-stmt .recon-main-table{font-size:11px;min-width:1880px;table-layout:fixed} #page-customer-recon-stmt .recon-main-table th{padding:9px 6px;font-size:11px;line-height:1.25;text-align:center;white-space:nowrap} -#page-customer-recon-stmt .recon-main-table td{height:34px;padding:7px 6px;font-size:11px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -#page-customer-recon-stmt .recon-main-table th:nth-child(1){width:190px;min-width:190px!important} +#page-customer-recon-stmt .recon-main-table td{height:38px;padding:7px 6px;font-size:11px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +#page-customer-recon-stmt .recon-main-table th:nth-child(1){width:260px;min-width:260px!important} #page-customer-recon-stmt .recon-main-table th:nth-child(2){width:70px} -#page-customer-recon-stmt .recon-main-table th:nth-child(3){width:80px} -#page-customer-recon-stmt .recon-main-table th:nth-child(4){width:150px} -#page-customer-recon-stmt .recon-main-table th:nth-child(5),#page-customer-recon-stmt .recon-main-table th:nth-child(6){width:86px} -#page-customer-recon-stmt .recon-main-table th:nth-child(7){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(8){width:45px} -#page-customer-recon-stmt .recon-main-table th:nth-child(9){width:88px} -#page-customer-recon-stmt .recon-main-table th:nth-child(10),#page-customer-recon-stmt .recon-main-table th:nth-child(11){width:80px} -#page-customer-recon-stmt .recon-main-table th:nth-child(12){width:115px} -#page-customer-recon-stmt .recon-main-table th:nth-child(13){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(14){width:68px} -#page-customer-recon-stmt .recon-main-table th:nth-child(15){width:60px} -#page-customer-recon-stmt .recon-main-table th:nth-child(16),#page-customer-recon-stmt .recon-main-table th:nth-child(18){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(17),#page-customer-recon-stmt .recon-main-table th:nth-child(19){width:120px} +#page-customer-recon-stmt .recon-main-table th:nth-child(3){width:86px} +#page-customer-recon-stmt .recon-main-table th:nth-child(4){width:80px} +#page-customer-recon-stmt .recon-main-table th:nth-child(5){width:150px} +#page-customer-recon-stmt .recon-main-table th:nth-child(6),#page-customer-recon-stmt .recon-main-table th:nth-child(7){width:86px} +#page-customer-recon-stmt .recon-main-table th:nth-child(8){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(9){width:45px} +#page-customer-recon-stmt .recon-main-table th:nth-child(10){width:88px} +#page-customer-recon-stmt .recon-main-table th:nth-child(11),#page-customer-recon-stmt .recon-main-table th:nth-child(12){width:80px} +#page-customer-recon-stmt .recon-main-table th:nth-child(13){width:115px} +#page-customer-recon-stmt .recon-main-table th:nth-child(14){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(15){width:68px} +#page-customer-recon-stmt .recon-main-table th:nth-child(16){width:60px} +#page-customer-recon-stmt .recon-main-table th:nth-child(17),#page-customer-recon-stmt .recon-main-table th:nth-child(19){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(18),#page-customer-recon-stmt .recon-main-table th:nth-child(20){width:120px} #page-customer-recon-stmt .recon-main-table td:first-child{overflow:visible;text-overflow:clip;text-align:left;font-size:9px} -#page-customer-recon-stmt .recon-main-table td:nth-child(12),#page-customer-recon-stmt .recon-main-table td:nth-child(14),#page-customer-recon-stmt .recon-main-table td:nth-child(17),#page-customer-recon-stmt .recon-main-table td:nth-child(19){font-size:10px} +#page-customer-recon-stmt .recon-main-table td:nth-child(13),#page-customer-recon-stmt .recon-main-table td:nth-child(15),#page-customer-recon-stmt .recon-main-table td:nth-child(18),#page-customer-recon-stmt .recon-main-table td:nth-child(20){font-size:10px} +#page-customer-recon-stmt .recon-action-link{border:0;background:transparent;padding:2px 3px;color:#1677ff;font:10px inherit;cursor:pointer} +#page-customer-recon-stmt .recon-action-link:hover{text-decoration:underline} +#page-customer-recon-stmt .recon-action-link.is-danger{color:#f5222d} +#page-customer-recon-stmt .recon-action-link.is-success{color:#16a34a} +#page-customer-recon-stmt .recon-action-link:disabled{color:#b8b8b8;cursor:not-allowed;text-decoration:none} #page-customer-recon-stmt .recon-detail-empty{padding:16px!important} @media(max-width:1500px){.rsq-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.rsq-span-2{grid-column:span 2}.rsq-actions{grid-column:span 2;justify-content:flex-end}} @media(max-width:900px){.rsq-grid{grid-template-columns:1fr}.rsq-span-2,.rsq-actions{grid-column:span 1}.rsq-field{align-items:flex-start;flex-direction:column}.rsq-field>input,.rsq-field>select,.rsq-date{width:100%}} @@ -545,6 +559,45 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .dispatch-actions{display:flex;flex-direction:column;align-items:flex-start;gap:5px;min-width:86px} .dispatch-actions a{color:#2563eb;font-size:11px;line-height:1.35;text-decoration:none;white-space:nowrap} .dispatch-actions a:hover{text-decoration:underline} +.dispatch-actions .dispatch-action-danger{color:#dc2626} +.dispatch-actions .dispatch-action-danger:hover{color:#b91c1c} +.dispatch-actions .dispatch-cancel-action.is-blocked{color:#9ca3af;text-decoration:none;cursor:not-allowed} +.dispatch-cancel-picking{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;margin-bottom:14px;border:1px solid #e5e7eb;border-radius:6px;background:#f9fafb} +.dispatch-cancel-picking span{color:#6b7280;font-size:12px} +.dispatch-cancel-picking strong{font-size:13px;color:#1f2937} +.dispatch-waybill{color:#2563eb;font-weight:500} +.dispatch-waybill-alert{color:#dc2626!important;text-decoration:underline;text-decoration-style:dotted;text-underline-offset:3px;cursor:help} +.dispatch-waybill-alert:hover,.dispatch-waybill-alert:focus-visible{color:#b91c1c!important;outline:none} +.dispatch-reject-close{font-size:20px;line-height:1;cursor:pointer;color:#6b7280} +.dispatch-reject-close:hover{color:#111827} +.dispatch-reject-meta{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:18px} +.dispatch-reject-meta>div{min-width:0;padding:10px 12px;border:1px solid #e5e7eb;border-radius:6px;background:#f9fafb} +.dispatch-reject-meta>div:first-child{grid-column:1/-1} +.dispatch-reject-meta span{display:block;margin-bottom:4px;color:#6b7280;font-size:12px} +.dispatch-reject-meta strong{display:block;overflow-wrap:anywhere;color:#1f2937;font-size:13px;font-weight:600} +.dispatch-reject-notify-row{display:flex;align-items:flex-start;gap:10px;padding:12px;border:1px solid #dbeafe;border-radius:6px;background:#eff6ff;cursor:pointer} +.dispatch-reject-notify-row input{width:16px;height:16px;margin:2px 0 0;accent-color:#2563eb;flex:0 0 auto} +.dispatch-reject-notify-row span{display:flex;flex-direction:column;gap:3px;min-width:0} +.dispatch-reject-notify-row strong{color:#1e3a8a;font-size:13px} +.dispatch-reject-notify-row small{color:#1e40af;font-size:12px;line-height:1.45} +.dispatch-exception-summary{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px} +.dispatch-exception-kpi{display:flex;align-items:baseline;gap:6px;padding:10px 14px;border:1px solid #e5e7eb;border-radius:6px;background:#fff} +.dispatch-exception-kpi strong{font-size:18px;color:#111827} +.dispatch-exception-kpi span{font-size:12px;color:#6b7280} +.dispatch-exception-no{color:#1f2937;font-weight:600;white-space:nowrap} +.dispatch-exception-relations{display:flex;min-width:190px;flex-direction:column;gap:3px} +.dispatch-exception-relation{display:grid;grid-template-columns:34px minmax(0,1fr);align-items:baseline;gap:6px;line-height:1.4} +.dispatch-exception-relation-label{color:#9ca3af;font-size:11px;white-space:nowrap} +.dispatch-exception-relation-no{min-width:0;color:#374151;font-size:12px;overflow-wrap:anywhere} +.dispatch-exception-related-meta{grid-column:1/-1} +.dispatch-exception-related-meta .dispatch-exception-relations{min-width:0} +.dispatch-exception-type{font-weight:600;white-space:nowrap} +.dispatch-exception-reason{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#4b5563} +.dispatch-exception-actions{display:flex;flex-wrap:wrap;gap:6px;white-space:nowrap} +.dispatch-exception-actions a{color:#2563eb;font-size:12px;text-decoration:none} +.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} .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} @@ -574,7 +627,62 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .dispatch-doc-upload-label:hover,.dispatch-doc-upload-label:focus-within{border-color:#2563eb;background:#eff6ff} .dispatch-doc-delete{padding:4px 7px;border:1px solid #fecaca;border-radius:4px;background:#fff;color:#b91c1c;font-size:11px;cursor:pointer} .dispatch-doc-delete:disabled{border-color:#e5e7eb;color:#9ca3af;cursor:not-allowed} -@media(max-width:700px){.dispatch-doc-modal-meta{grid-template-columns:1fr}.dispatch-doc-row{grid-template-columns:1fr}.dispatch-doc-controls{justify-content:flex-start}} +.edit-fleet-form{display:flex;flex-direction:column;gap:14px} +.edit-fleet-field{display:grid;grid-template-columns:100px minmax(0,1fr);align-items:center;gap:12px} +.edit-fleet-field-top{align-items:start} +.edit-fleet-field>label{color:#374151;font-size:13px;text-align:right;white-space:nowrap} +.edit-fleet-field input,.edit-fleet-field select,.edit-fleet-field textarea{width:100%;padding:8px 10px;border:1px solid #d1d5db;border-radius:6px;background:#fff;color:#374151;font:inherit;outline:none} +.edit-fleet-field input:focus,.edit-fleet-field select:focus,.edit-fleet-field textarea:focus{border-color:#3b82f6;box-shadow:0 0 0 2px rgba(59,130,246,.08)} +.edit-fleet-field input[readonly]{background:#f5f7fa;color:#6b7280} +.edit-fleet-current{padding:9px 11px;border:1px solid #dbeafe;border-radius:6px;background:#eff6ff;color:#1e40af;font-size:13px;font-weight:600;min-height:38px;display:flex;align-items:center} +.edit-fleet-required{color:#ef4444;margin-right:2px} +.edit-fleet-reason-wrap{min-width:0} +.edit-fleet-reason-wrap textarea{resize:vertical;min-height:78px} +.edit-fleet-reason-wrap textarea:disabled{background:#f5f7fa;color:#9ca3af;cursor:not-allowed} +.edit-fleet-reason-hint{margin-top:5px;color:#6b7280;font-size:11px;line-height:1.4} +.edit-fleet-reason-hint.is-required{color:#b45309} +.vehicle-fleet-reason{max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#374151} +.vehicle-region-tabs{display:flex;align-items:center;gap:0;margin:0 0 14px;border-bottom:1px solid #dfe5ee} +.vehicle-region-tab{min-width:116px;height:42px;padding:0 22px;border:0;border-bottom:2px solid transparent;background:#fff;color:#5f6b7a;font-size:14px;font-weight:500;cursor:pointer} +.vehicle-region-tab:hover{color:#1677ff;background:#f7faff} +.vehicle-region-tab.active{border-bottom-color:#1677ff;color:#1677ff;font-weight:650} +.warehouse-page-tabs{display:flex;align-items:center;gap:0;margin:0 0 14px;border-bottom:1px solid #dfe5ee;overflow-x:auto} +.warehouse-page-tab{min-width:116px;height:42px;padding:0 22px;border:0;border-bottom:2px solid transparent;background:#fff;color:#5f6b7a;font-size:14px;font-weight:500;cursor:pointer} +.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} +.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} +.vehicle-owner-tab:hover{color:#1f2937} +.vehicle-owner-tab.active{background:#fff;color:#1f2937;font-weight:650;box-shadow:0 1px 3px rgba(15,23,42,.12)} +.vehicle-region-tab:focus-visible,.vehicle-owner-tab:focus-visible{outline:2px solid #1677ff;outline-offset:2px} +.vehicle-detail-card{width:100%;max-width:1280px;overflow:hidden} +.vehicle-detail-head{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;padding:18px 24px;border-bottom:1px solid #edf0f4;background:#fff} +.vehicle-detail-title{color:#1f2937;font-size:18px;font-weight:700;line-height:1.4} +.vehicle-detail-meta{display:flex;align-items:center;gap:10px;margin-top:6px;color:#64748b;font-size:13px} +.vehicle-detail-meta>span:first-child{color:#334155;font-weight:600} +.vehicle-detail-body{padding:20px 24px 24px} +.vehicle-detail-section{margin:0;padding:0} +.vehicle-detail-section+.vehicle-detail-section{margin-top:26px} +.vehicle-detail-section h3{margin:0 0 12px;color:#273449;font-size:14px;font-weight:650;line-height:1.5} +.vehicle-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 36px;border-top:1px solid #edf0f4} +.vehicle-detail-field{display:grid;grid-template-columns:124px minmax(0,1fr);align-items:start;min-height:44px;padding:11px 0;border-bottom:1px solid #edf0f4;font-size:13px;line-height:1.65} +.vehicle-detail-label{color:#768398} +.vehicle-detail-value{min-width:0;color:#273449;font-weight:500;overflow-wrap:anywhere} +.vehicle-detail-table-scroll{overflow-x:auto;border:1px solid #dfe5ee;border-radius:6px;background:#fff} +.vehicle-detail-table{width:100%;min-width:820px;border-collapse:collapse;font-size:12px} +.vehicle-detail-table th,.vehicle-detail-table td{padding:10px 12px;border-bottom:1px solid #edf0f4;text-align:left;white-space:nowrap} +.vehicle-detail-table th{background:#f5f7fa;color:#5f6b7a;font-weight:600} +.vehicle-detail-table td{color:#374151} +.vehicle-detail-table tbody tr:last-child td{border-bottom:0} +.vehicle-detail-empty{padding:24px!important;text-align:center!important;color:#94a3b8!important} +.vehicle-detail-relation{display:inline-block;padding:2px 9px;border-radius:10px;font-size:12px;line-height:1.5} +.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}} .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} @@ -888,6 +996,20 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font /* ===== 全局列表统一规范(以海外仓库存列表为基准) ===== */ .page .table-card{background:#fff;border:1px solid #e5eaf1;border-radius:12px;box-shadow:0 3px 12px rgba(15,23,42,.05);backdrop-filter:none} +.location-search-row{flex-wrap:wrap;gap:8px} +.location-search-row select,.location-search-row input{width:160px} +.location-search-row select:nth-child(2){width:140px} +.location-search-row select:nth-child(4){width:120px} +.location-table-scroll{overflow-x:auto} +.location-table-scroll table{min-width:1120px;font-size:12px} +.location-table-scroll th,.location-table-scroll td{white-space:nowrap} +.location-table-scroll .location-operation{width:92px} +.location-table-scroll .location-operation a{color:#1890ff;text-decoration:none;margin-right:14px} +.location-table-scroll .location-operation .location-delete{color:#f5222d;margin-right:0} +.location-table-scroll .location-code{font-weight:600;color:#1f2937} +.location-table-scroll .location-weight{text-align:right} +.location-table-scroll .location-remark{color:#94a3b8} +@media(max-width:600px){#modal-domestic-location .modal,#modal-overseas-location .modal{width:calc(100% - 24px);max-height:calc(100vh - 24px);border-radius:16px}#modal-domestic-location .modal-header,#modal-overseas-location .modal-header{padding:16px 18px}#modal-domestic-location .modal-body,#modal-overseas-location .modal-body{padding:18px}#modal-domestic-location .modal-footer,#modal-overseas-location .modal-footer{padding:14px 18px}#modal-domestic-location .form-row,#modal-overseas-location .form-row{grid-template-columns:minmax(0,1fr);gap:14px;margin-bottom:14px}#modal-domestic-location .form-group,#modal-overseas-location .form-group{min-width:0}#modal-domestic-location .form-group input,#modal-domestic-location .form-group select,#modal-domestic-location .form-group textarea,#modal-overseas-location .form-group input,#modal-overseas-location .form-group select,#modal-overseas-location .form-group textarea{width:100%;min-width:0}#modal-domestic-location .form-group[style*="visibility:hidden"],#modal-overseas-location .form-group[style*="visibility:hidden"]{display:none}} .page .table-toolbar{min-height:56px;box-sizing:border-box;padding:13px 18px;border-bottom:1px solid #e8edf3;background:#fff} .page .table-toolbar .title{font-size:15px;font-weight:700;color:#1f2937} .inventory-management-tabs{display:flex;align-items:center;gap:0;min-height:50px;margin-bottom:12px;padding:0 18px;overflow-x:auto;background:#fff;border:1px solid #e5eaf1;border-radius:8px;box-shadow:0 2px 8px rgba(15,23,42,.04)} @@ -979,6 +1101,82 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font body.dashboard-fullscreen #page-dashboard table:has(>thead)>thead>tr>th{background:rgba(38,76,109,.35)!important;color:#8fa8be!important;border-color:rgba(92,141,184,.16)!important} body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{background:transparent!important;color:#c8d8e7!important;border-color:rgba(92,141,184,.12)!important} +.outbound-vehicle-modal{display:flex;flex-direction:column;width:min(1080px,calc(100vw - 32px));max-width:1080px;max-height:calc(100vh - 32px);border-radius:8px;overflow:hidden} +.outbound-vehicle-modal>.modal-header{flex:0 0 auto;padding:18px 20px;background:#fff;border-bottom:1px solid #e5e7eb;font-size:16px} +.outbound-vehicle-modal-body{flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;overflow-x:hidden;padding:18px 20px} +.outbound-vehicle-modal>.modal-footer{flex:0 0 auto;padding:14px 20px;border-top:1px solid #e5e7eb;background:#fff} +.outbound-vehicle-tabs{display:flex;border-bottom:1px solid #e5e7eb;padding:0 20px;background:#fff} +.outbound-vehicle-tabs button{min-height:42px;padding:0 16px;border:0;border-bottom:2px solid transparent;background:transparent;color:#64748b;cursor:pointer} +.outbound-vehicle-tabs button.active{border-bottom-color:#2563eb;color:#2563eb;font-weight:600} +.outbound-vehicle-modal-close{border:0;background:transparent;color:#64748b;cursor:pointer;font-size:22px;line-height:1} +.outbound-vehicle-form-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px 16px} +.outbound-vehicle-form-grid .form-group{min-width:0;margin:0}.outbound-vehicle-form-grid input,.outbound-vehicle-form-grid select{width:100%;box-sizing:border-box} +.outbound-vehicle-modal [hidden]{display:none!important} +.outbound-vehicle-section-title{margin:18px 0 12px;padding-bottom:8px;border-bottom:1px solid #e5e7eb;color:#334155;font-size:14px;font-weight:700}.outbound-vehicle-section-title:first-child{margin-top:0} +.outbound-vehicle-table-wrap{overflow:auto;border:1px solid #e5e7eb;border-radius:6px}.outbound-vehicle-table-wrap table{min-width:780px}.outbound-vehicle-empty{padding:36px 16px;text-align:center;color:#94a3b8} +.dispatch-row-located{animation:dispatch-row-located 1.8s ease-out}@keyframes dispatch-row-located{0%,45%{background:#fef3c7}100%{background:transparent}} +@media(max-width:760px){.outbound-vehicle-modal{width:calc(100vw - 16px);max-height:calc(100vh - 16px)}.outbound-vehicle-modal>.modal-header{padding:14px}.outbound-vehicle-modal-body{padding:14px}.outbound-vehicle-form-grid,.outbound-vehicle-edit-modal .form-row{grid-template-columns:1fr}.outbound-vehicle-section-title{margin-top:16px}.outbound-vehicle-modal>.modal-footer{padding:12px 14px}.outbound-vehicle-modal .modal-footer .btn{min-width:0}} +#modal-fba-carton-form .form-group{min-width:0} +#modal-fba-carton-form input,#modal-fba-carton-form select,#modal-fba-carton-form textarea{box-sizing:border-box;max-width:100%} +@media(max-width:600px){#modal-fba-carton-form .modal{display:flex;flex-direction:column;width:calc(100vw - 24px)!important;max-height:calc(100vh - 24px);overflow:hidden}#modal-fba-carton-form .modal-body{overflow-x:hidden;overflow-y:auto;padding:18px}#modal-fba-carton-form .form-row{grid-template-columns:minmax(0,1fr);gap:14px;margin-bottom:14px}#modal-fba-carton-form .modal-footer{flex:0 0 auto;padding:12px 18px}#modal-fba-carton-form .modal-footer .btn{min-width:0}} + +/* ===== 货柜托盘标全屏预览 ===== */ +.ct-pallet-preview-modal{--ct-pallet-code-size:120px;--ct-pallet-destination-size:180px;inset:0;padding:0;background:#1b1f22;backdrop-filter:none;align-items:stretch;justify-content:stretch} +.ct-pallet-preview-panel{width:100vw;max-width:none;height:100vh;max-height:none;border:0;border-radius:0;box-shadow:none;overflow:hidden;display:flex;flex-direction:column;background:#1b1f22;animation:none} +.ct-pallet-preview-toolbar{min-height:72px;flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:20px;padding:12px 18px;border-bottom:1px solid #343a3f;background:#252a2e;color:#fff;box-sizing:border-box} +.ct-pallet-preview-meta{flex:0 0 176px;display:grid;gap:3px;min-width:176px} +.ct-pallet-preview-meta>span{font-size:12px;color:#b9c0c5} +.ct-pallet-preview-meta strong{font-size:15px;color:#fff;white-space:nowrap} +.ct-pallet-preview-controls{display:flex;align-items:center;justify-content:flex-end;gap:10px;min-width:0;flex-wrap:wrap} +.ct-pallet-font-control{display:flex;align-items:center;gap:8px;white-space:nowrap;font-size:12px;color:#d9dee2} +.ct-pallet-font-stepper{height:34px;display:grid;grid-template-columns:34px 48px 34px;align-items:stretch;border:1px solid #535b61;border-radius:6px;overflow:hidden;background:#1b1f22} +.ct-pallet-font-stepper button{border:0;background:#343a3f;color:#fff;font-size:18px;line-height:1;cursor:pointer} +.ct-pallet-font-stepper button:hover{background:#454d53} +.ct-pallet-font-stepper button:focus-visible,.ct-pallet-preview-close:focus-visible,.ct-pallet-preview-toolbar .btn:focus-visible{outline:2px solid #69b1ff;outline-offset:2px} +.ct-pallet-font-stepper output{display:flex;align-items:center;justify-content:center;border-inline:1px solid #535b61;color:#fff;font-size:12px;font-variant-numeric:tabular-nums} +.ct-pallet-preview-toolbar .btn{height:34px;padding:0 14px;border-radius:6px;font-size:12px;box-shadow:none;transform:none} +.ct-pallet-preview-toolbar .btn-default{background:#fff;color:#374151;border:1px solid #d1d5db} +.ct-pallet-preview-toolbar .btn-primary{background:#1677ff;color:#fff;border:1px solid #1677ff} +.ct-pallet-print-action{background:#0958d9!important;border:1px solid #0958d9!important;color:#fff} +.ct-pallet-print-action:hover,.ct-pallet-print-action:focus{background:#003eb3!important;border-color:#003eb3!important;color:#fff} +.ct-pallet-preview-toolbar .btn:hover{transform:none;box-shadow:none} +.ct-pallet-preview-close{width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:6px;background:transparent;color:#d9dee2;font-size:24px;line-height:1;cursor:pointer} +.ct-pallet-preview-close:hover{background:#343a3f;color:#fff} +.ct-pallet-preview-scroll{flex:1;min-width:0;min-height:0;overflow:auto;padding:28px;background:#1b1f22;box-sizing:border-box} +#ct-pallet-label-list{width:max-content;min-width:100%;display:grid;justify-items:center;gap:28px} +.ct-pallet-label-sheet{page:ctPalletLabel;position:relative;width:297mm;height:210mm;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12mm;padding:14mm;background:#fff;color:#000;box-shadow:0 8px 28px rgba(0,0,0,.34);overflow:hidden;page-break-after:always;break-after:page;font-family:"Microsoft YaHei","SimHei",sans-serif} +.ct-pallet-label-sheet:last-child{page-break-after:auto;break-after:auto} +.ct-pallet-label-code,.ct-pallet-label-destination{width:100%;max-width:100%;margin:0;text-align:center;font-weight:900;line-height:.95;letter-spacing:0;overflow-wrap:anywhere;word-break:break-word} +.ct-pallet-label-code{font-size:var(--ct-pallet-code-size)} +.ct-pallet-label-destination{font-size:var(--ct-pallet-destination-size)} +.ct-pallet-label-empty{width:min(520px,calc(100vw - 48px));padding:28px;text-align:center;color:#c8cdd1;border:1px solid #454b50;border-radius:6px;background:#252a2e;box-sizing:border-box} +@media(max-width:900px){ + .ct-pallet-preview-toolbar{align-items:flex-start;gap:10px;padding:10px 12px;flex-wrap:wrap} + .ct-pallet-preview-meta{flex-basis:100%;min-width:0} + .ct-pallet-preview-controls{width:100%;justify-content:flex-start} + .ct-pallet-preview-scroll{padding:16px 12px} +} +@media(max-width:760px){ + .ct-pallet-preview-controls{gap:8px} + .ct-pallet-preview-controls .btn,.ct-pallet-preview-controls .booking-print-close,.ct-pallet-preview-controls .ct-pallet-preview-close,.ct-pallet-font-control button{min-height:40px} + .ct-pallet-preview-controls .ct-pallet-preview-close{min-width:40px} + .ct-pallet-font-stepper{height:40px;grid-template-columns:40px 48px 40px} + .ct-pallet-font-stepper button{width:40px;height:40px} +} +@page ctPalletLabel{size:A4 landscape;margin:0} +@media print{ + html:has(body.ct-pallet-printing),body.ct-pallet-printing{width:297mm!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.ct-pallet-printing>*:not(#modal-ct-pallet-label-preview){display:none!important} + body.ct-pallet-printing #modal-booking-print-preview{display:none!important} + body.ct-pallet-printing #modal-ct-pallet-label-preview{display:block!important;position:static!important;inset:auto!important;width:297mm!important;height:auto!important;padding:0!important;background:#fff!important} + body.ct-pallet-printing #modal-ct-pallet-label-preview,body.ct-pallet-printing #modal-ct-pallet-label-preview *{visibility:visible!important} + body.ct-pallet-printing .ct-pallet-preview-panel{display:block!important;position:static!important;width:297mm!important;height:auto!important;max-width:none!important;max-height:none!important;margin:0!important;background:#fff!important;overflow:visible!important} + body.ct-pallet-printing .ct-pallet-preview-toolbar{display:none!important} + body.ct-pallet-printing .ct-pallet-preview-scroll{display:block!important;position:static!important;width:297mm!important;height:auto!important;padding:0!important;background:#fff!important;overflow:visible!important} + body.ct-pallet-printing #ct-pallet-label-list{display:block!important;width:297mm!important;min-width:0!important;margin:0!important} + body.ct-pallet-printing .ct-pallet-label-sheet{display:flex!important;width:297mm!important;height:210mm!important;margin:0!important;box-shadow:none!important;page-break-after:always;break-after:page} + body.ct-pallet-printing .ct-pallet-label-sheet:last-child{page-break-after:auto;break-after:auto} +} @@ -1035,8 +1233,8 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - + @@ -1049,7 +1247,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - @@ -1060,6 +1257,12 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + - - -
@@ -1356,6 +1537,16 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + + +详情 | +EXP260814001 +审核通过 +审核通过 +2026-08-14 +未录入费用 +义乌卓越义乌仓上海分拨仓未配载否---义乌卓越物流快递订单快递2026-08-1413800138000义乌市稠州北路322000ops@example.com国内快递-否不涉及--342420.250.250A141.6740国内地址上海分拨仓上海市青浦区201700王师傅139001390002026-08-14 10:202026-08-14 11:05---顺丰速运SF260814001当天寄出优先处理admin2026-08-14 + 详情 | PCKHK2606151047待接收审核未录入测量数据未录入费用杭州积乐义乌仓义乌仓未配载否-CSLU1234567ABC123杭州积乐贸易海运拼箱自提2024-01-1513800138000杭州市江干区XX路XX号310000contact@example.com海运买单否已完成2024-01-202024-02-1055004802.52.42A1520450FBA仓美国仓USA Address90210John123456789--file.pdfmark.pdforder.pdf顺丰SF123456789无内部备注admin2024-01-10 详情 | PCKHK2606151046待接收审核未录入测量数据未录入费用杭州积乐义乌仓义乌仓未配载否-CSLU1234568ABC124杭州积乐贸易海运拼箱送货上门2024-01-1613900139000杭州市西湖区XX路XX号310001contact2@example.com海运退税否已完成2024-01-212024-02-1188007804.03.83A2850720FBA仓美国仓USA Address 290211Mike987654321--file2.pdfmark2.pdforder2.pdf圆通YT123456789加急内部备注2user12024-01-11 详情 | HDHK2606151045待接收审核未录入测量数据未录入费用岩盛义乌仓义乌仓未配载否-CSLU1234569ABC125岩盛进出口空运自提2024-01-1713700137000深圳市南山区XX路XX号518000ys@rocksheng.com空运买单否已完成2024-01-222024-01-2531501450.50.454A3160130FBA仓德国仓Germany Address10178Tom456789012--file3.pdfmark3.pdforder3.pdfEMSEMS123456789无内部备注3user22024-01-12 @@ -1954,7 +2145,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-入库码:PCKK2606151065 +入库码:PCKK2606151065
@@ -2291,7 +2482,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou @@ -2576,6 +2764,12 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
+
+箱子是否计费: + + +
+
扣货理由: @@ -2830,7 +3024,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
拖动查询项左侧手柄可自定义排列
-
+
@@ -2901,7 +3095,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - +
资料加载中…
派送中 @@ -2938,7 +3132,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 52800.00 7260.00 - +
资料加载中…
已签收 @@ -2975,7 +3169,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 42000.00 5775.00 - +
资料加载中…
派送中 @@ -3012,7 +3206,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 25600.00 3520.00 - +
资料加载中…
已签收 @@ -3049,10 +3243,10 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 7800.00 1072.50 - +
资料加载中…
-待派送 +派送中 海卡 YWBHK200615005 标准订单 @@ -3194,7 +3388,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 审核时间 - + 编辑 已审核 @@ -3243,7 +3437,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
@@ -3923,6 +4117,25 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +
+
+ +
异常订单
+
0异常订单
0待处理
0处理中
+
+
+ + + + +
+
+
+ +
操作异常订单号关联订单号异常类型客户仓库异常原因异常时间处理状态处理动作退回物流单号处理人更新时间
+
+
+
产品信息
@@ -3935,7 +4148,28 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
分类国内国际费用类型名称货柜应付货柜应收仓储应付仓储应收平摊费用说明创建人创建日期更新人更新日期操作
- + +
+
+
最新维护汇率
-
+
汇率月份
-
+
最后更新人
-
+
最后更新时间
-
+
+
+
美元兑人民币月平均汇率统一口径:1 USD = X CNY
+
+
汇率月份平均汇率换算说明状态更新人更新时间备注操作
+
+
+ +
排车列表
@@ -3948,50 +4182,183 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
操作排车单号车牌号司机联系电话托车公司名称派送单路线发车时间FBA预约车辆预约预计到达时间车辆状态
- -
-
← 返回列表
-
-
编辑排车
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
+
+
仓库管理
+
+
+
自有仓名称仓库地址城市州/省邮编国家状态操作
+
-
仓库管理
-
-
仓库代码仓库地址城市州/省邮编国家状态操作
+
仓库管理
+
+
自有仓
+
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+
仓库管理
+
+
自有仓
+
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+ + + + +
+ +
+
海外仓报价
+
+ + + + + + + +
+
操作报价名称海外仓服务商币种生效日期失效日期报价版本状态更新时间备注
+ +
+
+ + + + +
下载中心
@@ -4097,15 +4464,15 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-
+
-
+
等待读取上月平均汇率
-
操作亚马逊仓AMS+换单费内陆清关/报关费关税提柜费拆柜费托盘费派送费费用小计海运费成本总成本(USD)汇率折人民币重量(kg)成本单价(元/kg)建议报价
-
计算公式:费用小计 = AMS/换单 + 内陆 + 清关/报关 + 关税 + 提柜 + 拆柜 + 托盘 + 派送;总成本 = 小计 + 海运费;成本单价 = 总成本 × 汇率 ÷ 计费基数。
+
操作亚马逊仓AMS+换单费内陆清关/报关费关税提柜费拆柜费托盘费派送费费用小计海运费成本总成本(USD)汇率折人民币重量(kg)成本单价(元/kg)销售底价建议报价
+
计算公式:费用小计 = AMS/换单 + 内陆 + 清关/报关 + 关税 + 提柜 + 拆柜 + 托盘 + 派送;总成本 = 小计 + 海运费;成本单价 = 总成本 × 汇率 ÷ 计费基数;销售底价 = 建议报价 - 0.6。
@@ -4197,7 +4564,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou -
销售编号销售姓名区域/团队客户数订单数销售额(元)综合提成率提成金额(元)操作
+
销售编号销售姓名区域/团队客户数订单数销售额(元)综合提成率固定提成(元)溢价提成(元)垫款利息(元)提成金额(元)操作
@@ -4768,7 +5135,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - +
报关单列表
报关单号运单号进出口贸易方式口岸申报状态海关放行申报日期操作
@@ -5614,16 +5981,15 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
客户账户数
0个
账户实际余额
¥0
冻结金额
¥0
本月累计扣款
¥0
客户账户
-
操作客户基本信息客户编号联系人联系电话实际余额冻结金额可用余额账户状态最后变动时间
+
操作客户基本信息客户编号联系人联系电话实际余额冻结金额可用余额账户状态最后变动时间
+
充值申请记录
操作申请单号客户名称充值金额充值方式到账日期凭证数量申请时间申请状态审核人审核时间审核备注
-
客户账户详情正常
+
客户账户详情正常
实际余额
¥0.00
冻结金额
¥0.00
可用余额
¥0.00
账户明细(充值/扣款)
至
流水号发生时间扣款类型关联单据收入支出变动后余额操作人备注
- -
@@ -5645,7 +6011,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
@@ -5671,7 +6037,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - +
@@ -5695,7 +6061,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- + @@ -5708,6 +6074,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + @@ -5732,6 +6099,43 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + +
+ + +

应收款统计表

+ +
+
应收总金额CNY 0.00
+
已收合计CNY 0.00
+
零头减免CNY 0.00
+
余额未收CNY 0.00
+
+
应收款明细客户 / 备注随明细行展示
操作订单状态 派送单号 费用类型金额 集装箱号 柜号
+
+
@@ -5740,7 +6144,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 费用单据详情 — — -
+
应收/应付
—
@@ -5788,8 +6192,9 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- + + @@ -5909,7 +6314,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - @@ -5950,7 +6354,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +付款状态: @@ -5969,7 +6373,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- @@ -6536,9 +6939,14 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 拖车列表 +
+
国内
+
海外
+
+
- 拖车列表 + 拖车列表
@@ -6559,8 +6967,8 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- - + + @@ -6645,10 +7053,10 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
费用信息
-
RMB
+
RMB
-
RMB
+
RMB
@@ -6746,10 +7154,10 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
费用信息
-
RMB
+
RMB
-
RMB
+
RMB
@@ -6945,7 +7353,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
船期信息
-
+
港口与类型
@@ -7418,7 +7826,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-
货柜列表
+
货柜列表
@@ -7436,13 +7844,13 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou ⟳ 刷新⚙ 设置
-
操作操作 审核状态客户是否确认 账单编号 客户公司名 结算起始日操作 结算单号 客户公司名费用类型 币种 应收金额 已收 操作 结算单号 供应商费用类型 币种 应付金额 已付 司机 车头号 门店应付拖车费应收拖车费应付拖车费应收拖车费 预计装箱日期 状态 附件
操作集装箱号装柜清单号货柜状态是否异常柜号目的港清关资料DO资料PU资料码头车队仓库提单号船名航次箱型(货柜类型)船公司始发港目的港货柜容量(m³)装柜时间预计开船时间实际开船时间预计到港时间实际到港时间
+
操作报空预警集装箱号装柜清单号货柜状态是否异常柜号目的港清关资料DO资料PU资料码头车队仓库提单号船名航次箱型(货柜类型)船公司始发港目的港货柜容量(m³)装柜时间预计开船时间实际开船时间预计到港时间实际到港时间预计提柜时间约车时间报空时间还柜时间
-
货柜费用
+
货柜费用
@@ -7462,6 +7870,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
+
装柜清单
@@ -7472,8 +7881,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou 展开 ▼
- -
已选择 0 项   清空 @@ -7486,7 +7893,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- + @@ -7557,6 +7964,49 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
+ +
+ +
+
库位管理
+
+ + + + + + +
+
+
操作操作 仓库 装柜清单号 集装箱号
+
操作库位编码仓库库区库位类型最大承重(kg)状态备注
+
+ +
+ + + +
@@ -7581,14 +8031,12 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
- - @@ -7861,13 +8309,28 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
财务利润表
+
+ + +
查询维度 + 时间 @@ -7883,11 +8346,11 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
利润合计
¥0
综合利润率
0.0%
-
-
客户
-
货柜
-
单票
-
单月
+
+
客户
+
货柜
+
单票
+
单月
@@ -7959,28 +8422,26 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
车辆列表
+
+ + +
-
-
自有车辆
-
外派车辆
+
+ +
-
-区域: -全部 -国内 -国外 -
操作 客户 海外仓 SKU编码 中文品名批次数库位数 在库总量 可用库存 暂扣库存
@@ -7988,6 +8449,7 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + @@ -7996,19 +8458,16 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
车牌 车型当前公里码(km) 司机 联系电话 状态 区域 操作
+
+ + + @@ -8037,7 +8496,11 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-
+
+
+
+ +
@@ -8050,13 +8513,65 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- - + +
+ +
+
派送车队报价
+
+ + + + + + + + +
+
车牌 车型 油耗(L/100km) 当前公里码(km) 外派单位 联系电话当前派送单最近更换原因 状态 区域 操作
操作发货地(城市)目的仓(FBA仓点)迈数(预估距离)车队渠道整车自提整车派送散板派送状态更新时间备注
+ +
报价金额按美元记录;迈数为预估距离,实际派送费用以订单确认时的有效报价为准。
+
+
+ + + + + + +
+ +
+
+
车辆详情
——
+ +
+
+
+

车辆信息

+
+
+
+

派送订单明细

+
派送单号BOL / 来源单号客户目的仓预约日期派送状态关联关系
+
+
+

派送更换记录

+
时间派送单号动作关联车辆原因操作人
+
+
+
+
@@ -8191,7 +8706,13 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou #page-fba-inbound-order .fbio-list-actions{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 20px;border-top:1px solid #eef2f7;border-bottom:1px solid #e5e7eb;background:#fafbfc} #page-fba-inbound-order .fbio-list-action-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px} #page-fba-inbound-order .fbio-list-action-buttons .btn{min-width:76px} -@media(max-width:720px){#page-fba-inbound-order .fbio-list-actions{align-items:flex-start;flex-direction:column;padding:10px 14px}#page-fba-inbound-order .fbio-list-action-buttons{width:100%;justify-content:flex-start}} +.fbd-inbound-fee-table th,.fbd-inbound-fee-table td{text-align:center!important} +.fbd-receivable-fee-table th,.fbd-receivable-fee-table td{text-align:center!important} +.fbio-edit-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px} +.fbio-edit-grid .form-group{min-width:0;margin:0} +.fbio-edit-grid .form-group input,.fbio-edit-grid .form-group select{width:100%;box-sizing:border-box} +.fbio-readonly-input{background:#f5f7fa!important;color:#64748b!important;cursor:not-allowed} +@media(max-width:720px){#page-fba-inbound-order .fbio-list-actions{align-items:flex-start;flex-direction:column;padding:10px 14px}#page-fba-inbound-order .fbio-list-action-buttons{width:100%;justify-content:flex-start}.fbio-edit-grid{grid-template-columns:1fr}}
@@ -8228,7 +8749,8 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- + + @@ -8243,11 +8765,12 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
+ @@ -8260,18 +8783,20 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
订单信息
-
+
+
作业要求
+
- + @@ -8282,21 +8807,19 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
- +
-
换标单号 商品SKU 中文品名 箱数预算总价 贴标要求 上传文件 状态
+
- - - - - - - + + + + +
出库单号 出库类型目的仓转仓商品SKU中文品名出库数量箱数总净重(kg)SKU种数总托数总箱数总重量(kg)总体积(m3) 状态 操作
@@ -8314,23 +8837,38 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
+ + +
-
托盘管理
+
托盘管理
+
- +
+ + + @@ -8340,14 +8878,16 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou + +
-
箱号管理
+
箱号管理
- + @@ -8370,13 +8910,13 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou
-
入库单详情
入库单号 —
—
+
入库单详情
入库单号 —
—
应收费用明细
托盘编码 托盘类型仓库 容积(m³)托盘重量(kg)采购价格 所属FBA仓 状态 备注
序号费用项目币种金额备注
暂无应收费用明细
应收费用合计(USD)$0.00
-
出库单详情
出库单号 —
—
+
出库单详情
出库单号 —
—
托盘信息
托盘号入仓码箱数重量体积
暂无托盘信息
应收费用明细
序号费用项目币种金额备注
暂无应收费用明细
应收费用合计(USD)$0.00
@@ -8515,6 +9055,8 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 -->
@@ -10986,7 +11580,7 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度
-
资料上传后会回写当前派送单,并沿用历史 BOL 资料0/5 已上传
+
资料上传后会回写当前派送单,并沿用历史 BOL 资料0/7 已上传
@@ -11102,12 +11696,12 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -11172,8 +12015,85 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 + + + - + + '; showModal('modal-sc-detail'); } function scReset(){ @@ -3417,13 +4196,13 @@ function renderCustomerAccounts(){ var list=customerAccountData.filter(function(d){var balanceOk=!balanceFilter||(balanceFilter==='positive'&&d.balance>0)||(balanceFilter==='zero'&&d.balance===0)||(balanceFilter==='negative'&&d.balance<0);return (!kw||(d.name+d.code).toLowerCase().indexOf(kw)>-1)&&(!status||d.status===status)&&balanceOk;}); var totalBalance=customerAccountData.reduce(function(s,d){return s+d.balance;},0),totalFrozen=customerAccountData.reduce(function(s,d){return s+d.frozen;},0),monthDeduction=Object.keys(customerAccountTransactions).reduce(function(sum,id){return sum+(customerAccountTransactions[id]||[]).filter(function(t){return t.time.slice(0,7)==='2026-08';}).reduce(function(s,t){return s+t.expense;},0);},0); document.getElementById('ca-stat-count').innerHTML=customerAccountData.length+'个';document.getElementById('ca-stat-balance').textContent=caMoney(totalBalance);document.getElementById('ca-stat-frozen').textContent=caMoney(totalFrozen);document.getElementById('ca-stat-deduction').textContent=caMoney(monthDeduction);document.getElementById('ca-total-count').textContent='共 '+list.length+' 条'; - document.getElementById('tbody-customer-account').innerHTML=list.map(function(d){var available=d.balance-d.frozen,statusClass=d.status==='正常'?'tag-green':(d.status==='冻结'?'tag-orange':'tag-gray');return '
'+d.shortName.slice(0,1)+'
'+d.name+'
'+d.email+'
'+d.code+''+d.contact+''+d.phone+''+caMoney(d.balance)+''+caMoney(d.frozen)+''+caMoney(available)+''+d.status+''+d.lastChange+'';}).join('')||'暂无符合条件的客户账户'; + document.getElementById('tbody-customer-account').innerHTML=list.map(function(d){var available=d.balance-d.frozen,statusClass=d.status==='正常'?'tag-green':(d.status==='冻结'?'tag-orange':'tag-gray');return '
'+d.shortName.slice(0,1)+'
'+d.name+'
'+d.email+'
'+d.code+''+d.contact+''+d.phone+''+caMoney(d.balance)+''+caMoney(d.frozen)+''+caMoney(available)+''+d.status+''+d.lastChange+'';}).join('')||'暂无符合条件的客户账户'; } function resetCustomerAccountFilters(){document.getElementById('ca-filter-keyword').value='';document.getElementById('ca-filter-status').value='';document.getElementById('ca-filter-balance').value='';renderCustomerAccounts();} function showCustomerAccountDetail(id){currentCustomerAccountId=id;switchPage('customer-account-detail',null);renderCustomerAccountDetail();} function renderCustomerAccountDetail(){ var d=customerAccountData.find(function(x){return x.id===currentCustomerAccountId;});if(!d)return; - document.getElementById('ca-detail-name').textContent=d.name;var status=document.getElementById('ca-detail-status');status.textContent=d.status;status.className='tag '+(d.status==='正常'?'tag-green':d.status==='冻结'?'tag-orange':'tag-gray');document.getElementById('ca-detail-balance').textContent=caMoney(d.balance);document.getElementById('ca-detail-frozen').textContent=caMoney(d.frozen);document.getElementById('ca-detail-available').textContent=caMoney(d.balance-d.frozen);document.getElementById('ca-detail-recharge-btn').onclick=function(){showCustomerRecharge(d.id);}; + document.getElementById('ca-detail-name').textContent=d.name;var status=document.getElementById('ca-detail-status');status.textContent=d.status;status.className='tag '+(d.status==='正常'?'tag-green':d.status==='冻结'?'tag-orange':'tag-gray');document.getElementById('ca-detail-balance').textContent=caMoney(d.balance);document.getElementById('ca-detail-frozen').textContent=caMoney(d.frozen);document.getElementById('ca-detail-available').textContent=caMoney(d.balance-d.frozen);document.getElementById('ca-detail-recharge-btn').onclick=function(){showCustomerRechargeApplication(d.id);};document.getElementById('ca-detail-deduction-btn').onclick=function(){showCustomerDeduction(d.id);}; var info=[['客户编号',d.code],['联系人',d.contact],['联系电话',d.phone],['联系邮箱',d.email],['客户简称',d.shortName],['信用等级',d.creditLevel],['结算方式',d.settlement],['最后变动时间',d.lastChange]];document.getElementById('ca-detail-info').innerHTML=info.map(function(x){return '
'+x[0]+'
'+x[1]+'
';}).join('');renderCustomerAccountTransactions(); } function renderCustomerAccountTransactions(){ @@ -3431,10 +4210,47 @@ function renderCustomerAccountTransactions(){ } function resetCustomerAccountTransactions(){document.getElementById('ca-detail-type').value='';document.getElementById('ca-detail-start').value='';document.getElementById('ca-detail-end').value='';renderCustomerAccountTransactions();} function caToday(){var d=new Date(),p=function(n){return String(n).padStart(2,'0');};return d.getFullYear()+'-'+p(d.getMonth()+1)+'-'+p(d.getDate());} -function showCustomerRecharge(id){var d=customerAccountData.find(function(x){return x.id===id;});if(!d)return;document.getElementById('ca-recharge-id').value=id;document.getElementById('ca-recharge-customer').value=d.name;document.getElementById('ca-recharge-current').value=caMoney(d.balance);document.getElementById('ca-recharge-amount').value='';document.getElementById('ca-recharge-method').value='银行转账';document.getElementById('ca-recharge-date').value=caToday();document.getElementById('ca-recharge-ref').value='';document.getElementById('ca-recharge-remark').value='';showModal('modal-customer-recharge');} -function saveCustomerRecharge(){ - var id=document.getElementById('ca-recharge-id').value,d=customerAccountData.find(function(x){return x.id===id;}),amount=parseFloat(document.getElementById('ca-recharge-amount').value),date=document.getElementById('ca-recharge-date').value,method=document.getElementById('ca-recharge-method').value,ref=document.getElementById('ca-recharge-ref').value.trim(),remark=document.getElementById('ca-recharge-remark').value.trim();if(!d)return;if(!amount||amount<=0){showToast('请输入大于0的充值金额','error');return;}if(!date){showToast('请选择到账日期','error');return;} - d.balance=Number((d.balance+amount).toFixed(2));d.lastChange=date+' '+new Date().toTimeString().slice(0,5);if(d.status==='冻结'&&d.balance>=0)d.status='正常';var seq=String(Date.now()).slice(-8);if(!customerAccountTransactions[id])customerAccountTransactions[id]=[];customerAccountTransactions[id].unshift({no:'AC'+date.replace(/-/g,'')+seq,time:d.lastChange,type:'充值',order:ref||('RC'+seq),income:amount,expense:0,balance:d.balance,operator:'当前用户',remark:remark||method+'手动充值'});hideModal('modal-customer-recharge');renderCustomerAccounts();if(currentCustomerAccountId===id&&document.getElementById('page-customer-account-detail').classList.contains('active'))renderCustomerAccountDetail();showToast('充值成功,账户余额已更新','success'); +function validateCustomerDeduction(account,amount){ + if(!account||account.status!=='正常')return '当前账户状态不允许扣款'; + if(!Number.isFinite(amount)||amount<=0)return '请输入大于0的扣款金额'; + var available=Number((account.balance-account.frozen).toFixed(2)); + if(amount>available)return '扣款金额不能超过可用余额'; + return ''; +} +function applyCustomerDeduction(account,transactions,values){ + account.balance=Number((account.balance-values.amount).toFixed(2)); + account.lastChange=values.time; + var transaction={no:values.no,time:values.time,type:values.type,order:values.order||'',income:0,expense:values.amount,balance:account.balance,operator:'当前用户',remark:values.remark||'手动扣款'}; + transactions.unshift(transaction); + return transaction; +} +function showCustomerDeduction(id){ + var d=customerAccountData.find(function(x){return x.id===id;}); + if(!d)return; + if(d.status!=='正常'){showToast('当前账户状态不允许扣款','error');return;} + document.getElementById('ca-deduction-id').value=id; + document.getElementById('ca-deduction-customer').value=d.name; + document.getElementById('ca-deduction-current').value=caMoney(d.balance); + document.getElementById('ca-deduction-available').value=caMoney(d.balance-d.frozen); + document.getElementById('ca-deduction-amount').value=''; + document.getElementById('ca-deduction-type').value='贴牌'; + document.getElementById('ca-deduction-date').value=caToday(); + document.getElementById('ca-deduction-order').value=''; + document.getElementById('ca-deduction-remark').value=''; + showModal('modal-customer-deduction'); +} +function saveCustomerDeduction(){ + var id=document.getElementById('ca-deduction-id').value,d=customerAccountData.find(function(x){return x.id===id;}),amount=parseFloat(document.getElementById('ca-deduction-amount').value),type=document.getElementById('ca-deduction-type').value,date=document.getElementById('ca-deduction-date').value,order=document.getElementById('ca-deduction-order').value.trim(),remark=document.getElementById('ca-deduction-remark').value.trim(); + var error=validateCustomerDeduction(d,amount); + if(error){showToast(error,'error');return;} + if(!date){showToast('请选择扣款日期','error');return;} + var time=date+' '+new Date().toTimeString().slice(0,5),seq=String(Date.now()).slice(-8); + if(!customerAccountTransactions[id])customerAccountTransactions[id]=[]; + applyCustomerDeduction(d,customerAccountTransactions[id],{amount:amount,type:type,time:time,no:'AC'+date.replace(/-/g,'')+seq,order:order,remark:remark}); + hideModal('modal-customer-deduction'); + renderCustomerAccounts(); + if(currentCustomerAccountId===id&&document.getElementById('page-customer-account-detail').classList.contains('active'))renderCustomerAccountDetail(); + showToast('扣款成功,账户余额已更新','success'); } function renderCashflow(){renderTable('tbody-cashflow',cashflowData,['no','type','party','amt','cur','balance','date','remark'],(d,c)=>{ @@ -3523,6 +4339,10 @@ function resetCtForm(){ document.getElementById('ct-add-etd').value=''; document.getElementById('ct-add-eta').value=''; document.getElementById('ct-add-etw').value=''; + document.getElementById('ct-add-pickup-expected').value=''; + document.getElementById('ct-add-appointment-at').value=''; + document.getElementById('ct-add-emptied-at').value=''; + document.getElementById('ct-add-returned-at').value=''; document.getElementById('ct-add-declare').value=''; } @@ -3562,6 +4382,10 @@ function openCtEdit(index){ document.getElementById('ct-add-etd').value=d.etd||''; document.getElementById('ct-add-eta').value=d.eta||''; document.getElementById('ct-add-etw').value=d.etw||''; + document.getElementById('ct-add-pickup-expected').value=d.pickupExpectedAt||''; + document.getElementById('ct-add-appointment-at').value=d.appointmentAt||''; + document.getElementById('ct-add-emptied-at').value=d.emptiedAt||''; + document.getElementById('ct-add-returned-at').value=d.returnedAt||''; document.getElementById('ct-add-declare').value=d.declareAmount||''; showModal('modal-ct-add'); } @@ -3582,6 +4406,10 @@ function saveCtAdd(){ const etd=document.getElementById('ct-add-etd').value; const eta=document.getElementById('ct-add-eta').value; const etw=document.getElementById('ct-add-etw').value; + const pickupExpectedAt=document.getElementById('ct-add-pickup-expected').value; + const appointmentAt=document.getElementById('ct-add-appointment-at').value; + const emptiedAt=document.getElementById('ct-add-emptied-at').value; + const returnedAt=document.getElementById('ct-add-returned-at').value; const declareAmount=parseFloat(document.getElementById('ct-add-declare').value)||0; if(!boxno){showToast('请输入集装箱号','warning');return;} if(!ctno){showToast('请输入柜号','warning');return;} @@ -3592,7 +4420,7 @@ function saveCtAdd(){ if(ctListData.some(function(item,index){return item.no===boxno&&index!==ctEditingIndex;})){showToast('集装箱号已存在','warning');return;} if(ctEditingIndex>=0){ const d=ctListData[ctEditingIndex]; - Object.assign(d,{no:boxno,ctNo:ctno,wh:wh,bl:bl,vessel:vessel,type:type,carrier:carrier,pol:pol,pod:pod,destWh:destWh,vol:vol,etd:etd,eta:eta,etw:etw,declareAmount:declareAmount}); + Object.assign(d,{no:boxno,ctNo:ctno,wh:wh,bl:bl,vessel:vessel,type:type,carrier:carrier,pol:pol,pod:pod,destWh:destWh,vol:vol,etd:etd,eta:eta,etw:etw,pickupExpectedAt:pickupExpectedAt,appointmentAt:appointmentAt,emptiedAt:emptiedAt,returnedAt:returnedAt,declareAmount:declareAmount}); hideModal('modal-ct-add'); renderCtList(); showToast('货柜信息修改成功','success'); @@ -3600,7 +4428,7 @@ function saveCtAdd(){ const now=new Date(); const pad=function(value){return String(value).padStart(2,'0');}; const created=now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+pad(now.getHours())+':'+pad(now.getMinutes()); - ctListData.unshift({no:boxno,manifest:'—',status:'待装柜',isAbnormal:false,abnormalReason:'',abnormalLogs:[],ctNo:ctno,clearDoc:null,releaseDoc:null,puDoc:null,fleet:'',wh:wh,bl:bl,vessel:vessel,type:type,carrier:carrier,pol:pol,pod:pod,destWh:destWh,vol:vol,time:created,etd:etd,atd:'',eta:eta,ata:'',etw:etw,declareAmount:declareAmount}); + ctListData.unshift({no:boxno,manifest:'—',status:'待装柜',isAbnormal:false,abnormalReason:'',abnormalLogs:[],ctNo:ctno,clearDoc:null,releaseDoc:null,puDoc:null,fleet:'',wh:wh,bl:bl,vessel:vessel,type:type,carrier:carrier,pol:pol,pod:pod,destWh:destWh,vol:vol,time:created,etd:etd,atd:'',eta:eta,ata:'',etw:etw,pickupExpectedAt:pickupExpectedAt,appointmentAt:appointmentAt,emptyExpectedAt:'',emptiedAt:emptiedAt,returnedAt:returnedAt,declareAmount:declareAmount}); hideModal('modal-ct-add'); renderCtList(); showToast('货柜添加成功','success'); @@ -4861,31 +5689,73 @@ const outboundVehicleData = [ ]; let outboundVehicleListScrollTop=0; const dispatchOrders = [ -{orderNo:'PCKHK2606151034', weight:2000, pallets:20, destFba:'ONT8', vol:18, container:'CSLU1234567', region:'洛杉矶', otype:'合德正班', status:'待派送'}, -{orderNo:'PCKHK2606151030', weight:300, pallets:6, destFba:'FTW1', vol:3, container:'CSLU2345678', region:'纽约', otype:'合德海卡', status:'派送中'}, -{orderNo:'PCKHK2606151028', weight:1400, pallets:14, destFba:'LAX9', vol:12, container:'CSLU3456789', region:'洛杉矶', otype:'洛杉矶普通', status:'待派送'}, -{orderNo:'PCKHK2606151025', weight:3500, pallets:30, destFba:'ONT8', vol:28, container:'CSLU4567890', region:'洛杉矶', otype:'合德正班', status:'已送达'}, -{orderNo:'PCKHK2606151024', weight:1800, pallets:18, destFba:'CLT2', vol:16, container:'CSLU5678901', region:'纽约', otype:'合德海卡', status:'派送中'}, -{orderNo:'PCKHK2606151023', weight:800, pallets:8, destFba:'LAX9', vol:7, container:'CSLU6789012', region:'洛杉矶', otype:'洛杉矶普通', status:'已签收'}, -{orderNo:'PCKHK2606151022', weight:2500, pallets:25, destFba:'FTW1', vol:22, container:'CSLU7890123', region:'纽约', otype:'合德正班', status:'待派送'}, -{orderNo:'PCKHK2606151021', weight:1200, pallets:12, destFba:'ONT8', vol:10, container:'CSLU8901234', region:'洛杉矶', otype:'合德海卡', status:'已送达'} + {orderNo:'PCKHK2606151034', weight:2000, pallets:20, destFba:'ONT8', vol:18, container:'CSLU1234567', region:'洛杉矶', otype:'一件代发', status:'待派送', appointmentDate:'2026-07-28T09:00', estimatedLoadingTime:'2026-07-27T15:00', palletDetails:[{palletNo:'PAL-PCK-1034-01',boxes:12},{palletNo:'PAL-PCK-1034-02',boxes:10},{palletNo:'PAL-PCK-1034-03',boxes:9},{palletNo:'PAL-PCK-1034-04',boxes:11}]}, + {orderNo:'PCKHK2606151030', weight:300, pallets:6, destFba:'FTW1', vol:3, container:'CSLU2345678', region:'纽约', otype:'头程', status:'派送中', appointmentDate:'2026-07-29T10:00', estimatedLoadingTime:'2026-07-28T16:00', palletDetails:[{palletNo:'PAL-PCK-1030-01',boxes:8},{palletNo:'PAL-PCK-1030-02',boxes:7}]}, + {orderNo:'PCKHK2606151028', weight:1400, pallets:14, destFba:'LAX9', vol:12, container:'CSLU3456789', region:'洛杉矶', otype:'仓储转运', status:'待派送', appointmentDate:'2026-07-30T08:30', estimatedLoadingTime:'2026-07-29T14:30', palletDetails:[{palletNo:'PAL-PCK-1028-01',boxes:10},{palletNo:'PAL-PCK-1028-02',boxes:12},{palletNo:'PAL-PCK-1028-03',boxes:9}]}, + {orderNo:'PCKHK2606151025', weight:3500, pallets:30, destFba:'ONT8', vol:28, container:'CSLU4567890', region:'洛杉矶', otype:'一件代发', status:'已送达', appointmentDate:'2026-07-26T11:00', estimatedLoadingTime:'2026-07-25T17:00', palletDetails:[{palletNo:'PAL-PCK-1025-01',boxes:20},{palletNo:'PAL-PCK-1025-02',boxes:18},{palletNo:'PAL-PCK-1025-03',boxes:16},{palletNo:'PAL-PCK-1025-04',boxes:14},{palletNo:'PAL-PCK-1025-05',boxes:12}]}, + {orderNo:'PCKHK2606151024', weight:1800, pallets:18, destFba:'CLT2', vol:16, container:'CSLU5678901', region:'纽约', otype:'头程', status:'派送中', appointmentDate:'2026-07-31T09:30', estimatedLoadingTime:'2026-07-30T15:30', palletDetails:[{palletNo:'PAL-PCK-1024-01',boxes:14},{palletNo:'PAL-PCK-1024-02',boxes:13},{palletNo:'PAL-PCK-1024-03',boxes:12}]}, + {orderNo:'PCKHK2606151023', weight:800, pallets:8, destFba:'LAX9', vol:7, container:'CSLU6789012', region:'洛杉矶', otype:'仓储转运', status:'已签收', appointmentDate:'2026-07-27T08:00', estimatedLoadingTime:'2026-07-26T13:00', palletDetails:[]}, + {orderNo:'PCKHK2606151022', weight:2500, pallets:25, destFba:'FTW1', vol:22, container:'CSLU7890123', region:'纽约', otype:'一件代发', status:'待派送', appointmentDate:'2026-08-01T10:00', estimatedLoadingTime:'2026-07-31T16:00', palletDetails:[{palletNo:'PAL-PCK-1022-01',boxes:18},{palletNo:'PAL-PCK-1022-02',boxes:17},{palletNo:'PAL-PCK-1022-03',boxes:16},{palletNo:'PAL-PCK-1022-04',boxes:15}]}, + {orderNo:'PCKHK2606151021', weight:1200, pallets:12, destFba:'ONT8', vol:10, container:'CSLU8901234', region:'洛杉矶', otype:'头程', status:'已送达', appointmentDate:'2026-07-28T13:00', estimatedLoadingTime:'2026-07-27T18:00', palletDetails:[{palletNo:'PAL-PCK-1021-01',boxes:11},{palletNo:'PAL-PCK-1021-02',boxes:10}]} ]; +let outboundVehicleEditDraft=null; +let outboundVehicleOrderSelection=new Set(); +let outboundVehicleDeliveryContext=''; +const outboundVehicleLoadingFeeDefaults={地板:150,混装:100}; + +function validateOutboundVehicleDeliveryDraft(draft,expressCompanies){ + const required=[['预派送日期',draft.deliveryDate],['派送方式',draft.deliveryMethod],['提货方式',draft.pickupMethod],['装车类型',draft.loadType]]; + const missing=required.find(([,value])=>!value);if(missing)return '请填写'+missing[0]; + const fees=[['派送费用',draft.dispatchFee]]; + if(draft.loadType!=='托盘')fees.push(['装车费',draft.loadingFee]); + const invalid=fees.find(([,value])=>value===''||value===null||value===undefined||!Number.isFinite(Number(value))||Number(value)<0); + if(invalid)return '请填写有效的'+invalid[0]; + if(draft.deliveryMethod==='快递'){ + const companies=Array.isArray(expressCompanies)?expressCompanies:[]; + const company=companies.find(item=>item.id===draft.courierCompanyId&&item.status==='合作中'); + if(!company)return '请选择有效的快递公司'; + } + return ''; +} +function nextOutboundVehicleDeliveryNo(dateValue,records=lastMileDispatchData){ + const day=String(dateValue||'').replace(/\D/g,'').slice(0,8),prefix='PSD'+day; + const max=records.reduce((result,item)=>{const match=String(item.dispatchNo||'').match(new RegExp('^'+prefix+'(\\d{3})$'));return match?Math.max(result,Number(match[1])):result;},0); + return prefix+String(max+1).padStart(3,'0'); +} + +function cloneOutboundVehicleOrder(order){ + return {orderNo:String(order.orderNo||''),weight:Number(order.weight||0),pallets:Number(order.pallets||0),destFba:String(order.destFba||''),vol:Number(order.vol||0),container:String(order.container||''),status:String(order.status||'待派送')}; +} +function getAvailableOutboundVehicleOrders(vehicleNo,draftOrders,orders=dispatchOrders,vehicles=outboundVehicleData){ + const occupied=new Set(); + vehicles.filter(vehicle=>vehicle.vehicleNo!==vehicleNo).forEach(vehicle=>(vehicle.orders||[]).forEach(order=>occupied.add(order.orderNo))); + const draftNos=new Set((draftOrders||[]).map(order=>order.orderNo)); + return orders.filter(order=>order.status==='待派送'&&!occupied.has(order.orderNo)&&!draftNos.has(order.orderNo)); +} +function getOutboundVehicleOrderOptionPool(){ + if(!outboundVehicleEditDraft)return []; + const current=(outboundVehicleData.find(item=>item.vehicleNo===outboundVehicleEditDraft.vehicleNo)||{}).orders||[]; + const source=[];const seen=new Set(); + dispatchOrders.concat(current).forEach(order=>{if(!seen.has(order.orderNo)){seen.add(order.orderNo);source.push({...order,status:order.status||'待派送'});}}); + return getAvailableOutboundVehicleOrders(outboundVehicleEditDraft.vehicleNo,outboundVehicleEditDraft.orders,source,outboundVehicleData); +} let dsTrucks = [ {id:'t30', name:'30托盘', capacity:30}, {id:'t26', name:'26托盘', capacity:26} ]; -let dsTruckOrders = {}; +let dsTruckPallets = {}; let dsCurrentType = '全部'; let dsCurrentChannel='全美'; let dsKeyword=''; let dsDest=''; let dsStatus=''; let dsSeq=0; +let dsSelectedOrderNo=''; function openDispatchSchedule(){ dsTrucks=[{id:'t30',name:'30托盘',capacity:30},{id:'t26',name:'26托盘',capacity:26}]; - dsTruckOrders={};dsTrucks.forEach(t=>dsTruckOrders[t.id]=[]); - dsCurrentChannel='全美';dsCurrentType='全部';dsKeyword='';dsDest='';dsStatus=''; + dsTruckPallets={};dsTrucks.forEach(t=>dsTruckPallets[t.id]=[]); + dsCurrentChannel='全美';dsCurrentType='全部';dsKeyword='';dsDest='';dsStatus='';dsSelectedOrderNo=''; document.querySelectorAll('.ds-channel').forEach(b=>b.classList.toggle('active',b.dataset.ch==='全美')); document.querySelectorAll('.ds-tf').forEach(b=>b.classList.toggle('active',b.dataset.tf==='全部')); const qo=document.getElementById('ds-q-ono');if(qo)qo.value=''; @@ -4932,66 +5802,103 @@ function setDispatchType(tf,el){ } function renderDispatchOrders(){ const list=dispatchOrders.filter(o=>(dsCurrentChannel==='全美'||o.region===dsCurrentChannel)&&(dsCurrentType==='全部'||o.otype===dsCurrentType)&&(!dsDest||o.destFba===dsDest)&&(!dsStatus||o.status===dsStatus)&&(!dsKeyword||o.orderNo.toLowerCase().includes(dsKeyword.toLowerCase()))); + if(dsSelectedOrderNo&&!list.some(order=>order.orderNo===dsSelectedOrderNo))dsSelectedOrderNo=''; const box=document.getElementById('ds-orders-list'); const cnt=document.getElementById('ds-orders-count'); if(cnt)cnt.textContent='('+list.length+'单)'; - if(!list.length){box.innerHTML='
该条件下暂无出库单
';return;} + if(!list.length){box.innerHTML='
该条件下暂无出库单
';renderDispatchPalletDetails();return;} box.innerHTML=` - +${list.map((o,i)=>{ - const placed=Object.values(dsTruckOrders).some(arr=>arr.includes(o.orderNo)); - return ` + return ` + + + `; }).join('')}
订单号重量托盘数量目的地FBA体积货柜号订单号订单类型重量托盘数量目的地FBA体积货柜号预约送仓时间预计装车时间
${o.orderNo}${lmoEsc(o.otype)} ${o.weight} ${o.pallets} ${o.destFba} ${o.vol} ${o.container} ∨${o.appointmentDate||'—'}${o.estimatedLoadingTime||'—'}
`; + renderDispatchPalletDetails(); } -function dsDragStart(e,ono){e.dataTransfer.setData('text/plain',ono);e.dataTransfer.effectAllowed='move';} +function selectDispatchOrder(ono){ + dsSelectedOrderNo=ono; + renderDispatchOrders(); +} +function getDispatchPalletKey(orderNo,palletNo){return encodeURIComponent(orderNo)+'::'+encodeURIComponent(palletNo);} +function getDispatchPalletVolume(order){return (Number(order&&order.vol)||0)/Math.max(1,Number(order&&order.pallets)||0);} +function getDispatchPalletByKey(key){ + for(const order of dispatchOrders){ + const detail=(Array.isArray(order.palletDetails)?order.palletDetails:[]).find(item=>getDispatchPalletKey(order.orderNo,item.palletNo)===key); + if(detail)return {key,orderNo:order.orderNo,palletNo:detail.palletNo,boxes:Number(detail.boxes)||0,volume:getDispatchPalletVolume(order)}; + } + return null; +} +function getDispatchPalletAssignment(key){ + for(const truckId in dsTruckPallets){if((dsTruckPallets[truckId]||[]).some(item=>item.key===key))return truckId;} + return ''; +} +function renderDispatchPalletDetails(){ + const panel=document.getElementById('ds-pallet-detail'); + const orderNo=document.getElementById('ds-pallet-detail-order'); + const body=document.getElementById('ds-pallet-detail-body'); + if(!panel||!orderNo||!body)return; + const order=dispatchOrders.find(item=>item.orderNo===dsSelectedOrderNo); + if(!order){orderNo.textContent='未选择订单';body.innerHTML='请选择订单查看托盘明细';return;} + orderNo.textContent=order.orderNo; + const rows=Array.isArray(order.palletDetails)?order.palletDetails:[]; + body.innerHTML=rows.length?rows.map(item=>{ + const key=getDispatchPalletKey(order.orderNo,item.palletNo),assigned=getDispatchPalletAssignment(key),dragArg=lmoEsc(JSON.stringify(key)); + const dragAttrs=assigned?'draggable="false" aria-disabled="true"':`draggable="true" ondragstart="dsPalletDragStart(event,${dragArg})"`; + const assignedTruck=dsTrucks.find(truck=>truck.id===assigned); + return `
${lmoEsc(item.palletNo)}${assigned?'已分配':''}
${Number(item.boxes)}`; + }).join(''):'该订单暂无托盘明细'; +} +function dsPalletDragStart(e,key){e.dataTransfer.setData('text/plain',key);e.dataTransfer.effectAllowed='move';} function dsAllowDrop(e){e.preventDefault();e.currentTarget.classList.add('ds-over');} function dsDropTruck(e,truckId){ e.preventDefault(); e.currentTarget.classList.remove('ds-over'); - const ono=e.dataTransfer.getData('text/plain'); - if(!ono)return; - for(const tid in dsTruckOrders)dsTruckOrders[tid]=dsTruckOrders[tid].filter(x=>x!==ono); - dsTruckOrders[truckId]=dsTruckOrders[truckId]||[]; - dsTruckOrders[truckId].push(ono); + const key=e.dataTransfer.getData('text/plain'),pallet=getDispatchPalletByKey(key); + if(!pallet)return; + for(const tid in dsTruckPallets)dsTruckPallets[tid]=dsTruckPallets[tid].filter(item=>item.key!==key); + dsTruckPallets[truckId]=dsTruckPallets[truckId]||[]; + dsTruckPallets[truckId].push(pallet); renderDispatchTrucks(); - renderDispatchOrders(); + renderDispatchPalletDetails(); } function renderDispatchTrucks(){ const wrap=document.getElementById('ds-trucks'); if(!wrap)return; if(!dsTrucks.length){wrap.innerHTML='
暂无装托盘,点击右上角「+ 添加装托盘」
';return;} wrap.innerHTML=dsTrucks.map(t=>{ - const arr=dsTruckOrders[t.id]||[]; - const p=arr.reduce((s,ono)=>s+(dispatchOrders.find(x=>x.orderNo===ono)?.pallets||0),0); - const v=arr.reduce((s,ono)=>s+(dispatchOrders.find(x=>x.orderNo===ono)?.vol||0),0); + const arr=dsTruckPallets[t.id]||[]; + const p=arr.length; + const v=arr.reduce((sum,item)=>sum+(Number(item.volume)||0),0); const over=p>t.capacity; - const items=arr.map(ono=>{ - const o=dispatchOrders.find(x=>x.orderNo===ono); - return `
${o.orderNo}${o.pallets}托·${o.vol}m³×
`; + const items=arr.map(item=>{ + const keyArg=lmoEsc(JSON.stringify(item.key)); + return `
${lmoEsc(item.palletNo)}${lmoEsc(item.orderNo)} · ${Number(item.boxes)}箱 · ${Number(item.volume).toFixed(2)}m³×
`; }).join(''); return `
${t.name} 托数 ${p}/${t.capacity} · 立方 ${v.toFixed(1)}
-
${items||'
拖入订单
'}
+
${items||'
拖入托盘
'}
删除此托盘
`; }).join(''); } -function dsRemoveFromTruck(truckId,ono){ - dsTruckOrders[truckId]=(dsTruckOrders[truckId]||[]).filter(x=>x!==ono); +function dsRemoveFromTruck(truckId,key){ + dsTruckPallets[truckId]=(dsTruckPallets[truckId]||[]).filter(item=>item.key!==key); renderDispatchTrucks(); - renderDispatchOrders(); + renderDispatchPalletDetails(); } function dsAddTruck(){ const cap=prompt('请输入装托盘容量(托数):','20'); @@ -5000,44 +5907,60 @@ function dsAddTruck(){ if(isNaN(n)||n<=0){showToast('请输入有效的托数','warning');return;} const id='t'+Date.now(); dsTrucks.push({id,name:n+'托盘',capacity:n}); - dsTruckOrders[id]=[]; + dsTruckPallets[id]=[]; renderDispatchTrucks(); } function dsRemoveTruck(id){ - delete dsTruckOrders[id]; + delete dsTruckPallets[id]; dsTrucks=dsTrucks.filter(t=>t.id!==id); renderDispatchTrucks(); - renderDispatchOrders(); + renderDispatchPalletDetails(); } function preScheduleVehicle(){ - const trucksWith=dsTrucks.filter(t=>(dsTruckOrders[t.id]||[]).length>0); - if(!trucksWith.length){showToast('请先将订单拖入装托盘','warning');return;} + const trucksWith=dsTrucks.filter(t=>(dsTruckPallets[t.id]||[]).length>0); + if(!trucksWith.length){showToast('请先将托盘拖入装托盘类型','warning');return;} const now=new Date(); const d=now.getFullYear()+String(now.getMonth()+1).padStart(2,'0')+String(now.getDate()).padStart(2,'0'); let total=0; + const scheduledKeys=new Set(); trucksWith.forEach(t=>{ - const arr=dsTruckOrders[t.id]; + const arr=dsTruckPallets[t.id]; total+=arr.length; + arr.forEach(item=>scheduledKeys.add(item.key)); dsSeq++; - const bolOrders=arr.map(ono=>dispatchOrders.find(x=>x.orderNo===ono)).filter(Boolean); + const orderNos=[...new Set(arr.map(item=>item.orderNo))]; + const bolOrders=orderNos.map(ono=>{ + const source=dispatchOrders.find(order=>order.orderNo===ono),pallets=arr.filter(item=>item.orderNo===ono); + if(!source)return null; + const volume=pallets.reduce((sum,item)=>sum+(Number(item.volume)||0),0); + return {...source,pallets:pallets.length,vol:Number(volume.toFixed(2)),palletDetails:pallets.map(item=>({palletNo:item.palletNo,boxes:item.boxes}))}; + }).filter(Boolean); outboundVehicleData.unshift({ vehicleNo:'PC'+d+String(dsSeq).padStart(3,'0'), plate:'待分配', driver:'待定', phone:'-', company:'待分配', - dispatch:arr.join('、'), route:t.name, depart:'-', + dispatch:orderNos.join('、'), route:t.name, depart:'-', fbaBooking:'待预约', carBooking:'待预约', eta:'-', status:'待发车', orders:bolOrders }); - arr.forEach(ono=>{ - const idx=dispatchOrders.findIndex(x=>x.orderNo===ono); - if(idx>-1)dispatchOrders.splice(idx,1); - }); }); + for(let index=dispatchOrders.length-1;index>=0;index--){ + const order=dispatchOrders[index],details=Array.isArray(order.palletDetails)?order.palletDetails:[]; + const remaining=details.filter(item=>!scheduledKeys.has(getDispatchPalletKey(order.orderNo,item.palletNo))); + const scheduledCount=details.length-remaining.length; + if(!scheduledCount)continue; + if(!remaining.length){dispatchOrders.splice(index,1);continue;} + const palletVolume=getDispatchPalletVolume(order); + order.palletDetails=remaining; + order.pallets=Math.max(remaining.length,(Number(order.pallets)||0)-scheduledCount); + order.vol=Number(Math.max(0,(Number(order.vol)||0)-palletVolume*scheduledCount).toFixed(2)); + } dsTrucks=[{id:'t30',name:'30托盘',capacity:30},{id:'t26',name:'26托盘',capacity:26}]; - dsTruckOrders={};dsTrucks.forEach(t=>dsTruckOrders[t.id]=[]); + dsTruckPallets={};dsTrucks.forEach(t=>dsTruckPallets[t.id]=[]); + dsSelectedOrderNo=''; renderOutboundVehicle(); renderDispatchTrucks(); hideModal('modal-dispatch-schedule'); - showToast('已预排车 '+trucksWith.length+' 个托盘,共 '+total+' 单同步至排车列表','success'); + showToast('已预排车 '+trucksWith.length+' 个装托盘,共 '+total+' 托同步至排车列表','success'); } function renderOutboundVehicle(){ const tb=document.getElementById('tbody-outbound-vehicle'); @@ -5057,7 +5980,8 @@ function renderOutboundVehicle(){ const row=document.createElement('tr'); const actionCell=document.createElement('td'); actionCell.style.cssText='white-space:nowrap;text-align:center'; - actionCell.append(createAction('编辑',()=>editVehicle(v.vehicleNo),false),document.createTextNode(' '),createAction('详情',()=>openOutboundVehicleDetail(v.vehicleNo),false),document.createTextNode(' '),createAction('转派送',()=>openBolModal(v.vehicleNo),true)); + const deliveryAction=v.deliveryNo?createAction('查看派送单',()=>openOutboundVehicleDelivery(v.deliveryNo),true):createAction('转派送',()=>openBolModal(v.vehicleNo),true); + actionCell.append(createAction('编辑',()=>editVehicle(v.vehicleNo),false),document.createTextNode(' '),createAction('详情',()=>openOutboundVehicleDetail(v.vehicleNo),false),document.createTextNode(' '),deliveryAction); row.append(actionCell,createTextCell(v.vehicleNo),createTextCell(v.plate),createTextCell(v.driver),createTextCell(v.phone),createTextCell(v.company||'待分配'),createTextCell(v.dispatch),createTextCell(v.route),createTextCell(v.depart),createTextCell(v.fbaBooking||'-'),createTextCell(v.carBooking||'-'),createTextCell(v.eta||'-')); const statusCell=document.createElement('td'); const statusTag=document.createElement('span'); @@ -5072,25 +5996,29 @@ function renderOutboundVehicle(){ } function openBolModal(vehicleNo){ const v=outboundVehicleData.find(x=>x.vehicleNo===vehicleNo); - if(!v){showToast('未找到该排车记录','warning');return;} - /* 预填部分字段 */ - document.getElementById('bol-containerNo').value=v.containerNo||''; - document.getElementById('bol-cabinetNo').value=v.plate||''; - /* 订单明细 */ + if(!v){showToast('未找到该排车记录','error');return;} + if(v.deliveryNo){openOutboundVehicleDelivery(v.deliveryNo);return;} + outboundVehicleDeliveryContext=v.vehicleNo; + const set=(id,value)=>{const input=document.getElementById(id);if(input)input.value=value||'';}; + set('bol-vehicle-no',v.vehicleNo);set('bol-containerNo',(v.orders||[])[0]?.container||'');set('bol-cabinetNo',v.plate);set('bol-deliveryDate','');set('bol-deliveryMethod','');set('bol-pickupMethod','');set('bol-loadType','托盘');set('bol-dispatchFee','');set('bol-loadingFee','0');set('bol-courierCompanyId','');set('bol-driverName',v.company&&v.driver?v.company+' / '+v.driver:v.driver||v.company);set('bol-driverPhone',v.phone);set('bol-vehicleType','');set('bol-bookAccount','');set('bol-appointmentNo','');set('bol-vehicleSize',''); const orders=v.orders||[]; const cnt=document.getElementById('bol-detail-count'); if(cnt)cnt.textContent='('+orders.length+'单)'; const body=document.getElementById('bol-detail-body'); - if(body)body.innerHTML=orders.length?orders.map(o=>` - ${o.orderNo} - ${o.weight} - ${o.pallets} - ${o.destFba} - ${o.vol} - ${o.container} - `).join(''):'该排车单暂无关联订单明细'; + if(body){body.replaceChildren();if(!orders.length){const row=document.createElement('tr'),cell=document.createElement('td');cell.colSpan=6;cell.textContent='该排车单暂无关联订单明细';row.appendChild(cell);body.appendChild(row);}orders.forEach(order=>{const row=document.createElement('tr');[order.orderNo,order.weight,order.pallets,order.destFba,order.vol,order.container].forEach(value=>{const cell=document.createElement('td');cell.textContent=String(value??'');row.appendChild(cell);});body.appendChild(row);});} + handleOutboundVehicleLoadTypeChange(); + handleOutboundVehicleDeliveryMethodChange(); showModal('modal-bol'); } +function handleOutboundVehicleLoadTypeChange(){ + const type=document.getElementById('bol-loadType')?.value||'托盘',field=document.getElementById('bol-loading-fee-field'),input=document.getElementById('bol-loadingFee'),visible=type==='地板'||type==='混装'; + if(field)field.hidden=!visible;if(input)input.value=visible?String(outboundVehicleLoadingFeeDefaults[type]):'0'; +} +function handleOutboundVehicleDeliveryMethodChange(){ + const method=document.getElementById('bol-deliveryMethod')?.value||'',companyField=document.getElementById('bol-courier-company-field'),companySelect=document.getElementById('bol-courierCompanyId'),visible=method==='快递'; + if(companyField)companyField.hidden=!visible; + if(companySelect){companySelect.required=visible;companySelect.innerHTML=''+genExpressData.filter(item=>item.status==='合作中').map(item=>'').join('');if(!visible)companySelect.value='';} +} function bolSearch(){ const dd=document.getElementById('bol-deliveryDate').value; const dm=document.getElementById('bol-deliveryMethod').value; @@ -5098,44 +6026,75 @@ function bolSearch(){ showToast('搜索完成','success'); } function saveBol(){ - hideModal('modal-bol'); - showToast('转派送提交成功','success'); + const vehicle=outboundVehicleData.find(item=>item.vehicleNo===outboundVehicleDeliveryContext);if(!vehicle){showToast('未找到排车记录','error');return;} + if(vehicle.deliveryNo){openOutboundVehicleDelivery(vehicle.deliveryNo);return;} + const value=id=>document.getElementById(id)?.value||''; + const draft={deliveryDate:value('bol-deliveryDate'),deliveryMethod:value('bol-deliveryMethod'),pickupMethod:value('bol-pickupMethod'),loadType:value('bol-loadType'),dispatchFee:value('bol-dispatchFee'),loadingFee:value('bol-loadingFee'),courierCompanyId:value('bol-courierCompanyId'),appointmentAccount:value('bol-bookAccount'),appointmentNo:value('bol-appointmentNo'),vehicleSize:value('bol-vehicleSize')}; + const error=validateOutboundVehicleDeliveryDraft(draft,genExpressData);if(error){showToast(error,'error');return;} + const deliveryNo=nextOutboundVehicleDeliveryNo(draft.deliveryDate),orders=vehicle.orders||[]; + const deliveryFee=Number(draft.dispatchFee); + const courierCompany=draft.deliveryMethod==='快递'?genExpressData.find(item=>item.id===draft.courierCompanyId&&item.status==='合作中'):null; + const courierSnapshot={courierCompanyId:courierCompany?.id||'',courierCompanyName:courierCompany?.name||''}; + const record={dispatchNo:deliveryNo,source:'outboundVehicle',vehicleNo:vehicle.vehicleNo,lastMileNo:'',owner:'排车转派送',warehouse:'海外仓',destFba:[...new Set(orders.map(order=>order.destFba).filter(Boolean))].join('、')||'—',inboundNo:orders.map(order=>order.orderNo).join('、'),appointmentAccount:draft.appointmentAccount,appointmentNo:draft.appointmentNo||'—',appointmentDate:draft.deliveryDate,slot:'—',pallets:orders.reduce((sum,order)=>sum+Number(order.pallets||0),0),boxes:0,weight:orders.reduce((sum,order)=>sum+Number(order.weight||0),0),volume:orders.reduce((sum,order)=>sum+Number(order.vol||0),0),createdAt:lmoNow(),status:'待派送',pickingStatus:'已拣货',deliveryMethod:draft.deliveryMethod,pickupMethod:draft.pickupMethod,loadType:draft.loadType,vehicleSize:draft.vehicleSize,dispatchFee:deliveryFee,estimatedDispatchFee:deliveryFee,loadingFee:draft.loadType==='托盘'?0:Number(draft.loadingFee),...courierSnapshot,plate:vehicle.plate,driver:vehicle.driver}; + lastMileDispatchData.unshift(record);vehicle.deliveryNo=deliveryNo;vehicle.delivery={...draft,...courierSnapshot,deliveryNo,driverName:value('bol-driverName'),driverPhone:value('bol-driverPhone'),vehicleType:value('bol-vehicleType')};outboundVehicleDeliveryContext='';hideModal('modal-bol');renderOutboundVehicle();showToast('已生成派送单 '+deliveryNo,'success'); } function editVehicle(vehicleNo){ const v=outboundVehicleData.find(x=>x.vehicleNo===vehicleNo); - if(!v){showToast('未找到该排车记录','warning');return;} - document.getElementById('ve-vehicleNo').value=v.vehicleNo; - document.getElementById('ve-vehicleNoShow').value=v.vehicleNo; - document.getElementById('ve-plate').value=v.plate||''; - document.getElementById('ve-company').value=v.company||''; - document.getElementById('ve-driver').value=v.driver||''; - document.getElementById('ve-phone').value=v.phone||''; - document.getElementById('ve-dispatch').value=v.dispatch||''; - document.getElementById('ve-route').value=v.route||''; - document.getElementById('ve-depart').value=(v.depart&&v.depart!=='-'&&v.depart!=='待定')?v.depart:''; - document.getElementById('ve-eta').value=(v.eta&&v.eta!=='-'&&v.eta!=='待定')?v.eta:''; - document.getElementById('ve-fbaBooking').value=v.fbaBooking||''; - document.getElementById('ve-carBooking').value=v.carBooking||''; - document.getElementById('ve-status').value=v.status||'待发车'; - switchPage('outbound-vehicle-edit'); + if(!v){showToast('未找到该排车记录','error');return;} + outboundVehicleEditDraft={...v,orders:(v.orders||[]).map(cloneOutboundVehicleOrder)}; + const values={'ove-vehicle-no':v.vehicleNo,'ove-plate':v.plate||'','ove-company':v.company||'','ove-driver':v.driver||'','ove-phone':v.phone||'','ove-route':v.route||'','ove-depart':normalizeOutboundVehicleDateTime(v.depart),'ove-eta':normalizeOutboundVehicleDateTime(v.eta),'ove-fba-booking':v.fbaBooking||'','ove-car-booking':v.carBooking||'','ove-status':v.status||'待发车'}; + Object.keys(values).forEach(id=>{const input=document.getElementById(id);if(input)input.value=values[id];}); + switchOutboundVehicleEditTab('info'); + renderOutboundVehicleEditOrders(); + showModal('modal-outbound-vehicle-edit'); +} +function normalizeOutboundVehicleDateTime(value){return value&&value!=='-'&&value!=='待定'?String(value).replace(' ','T'):'';} +function switchOutboundVehicleEditTab(tab,button){ + const info=document.getElementById('ove-panel-info'),orders=document.getElementById('ove-panel-orders'); + if(info)info.hidden=tab!=='info';if(orders)orders.hidden=tab!=='orders'; + document.querySelectorAll('#modal-outbound-vehicle-edit [data-tab]').forEach(item=>item.classList.toggle('active',item.dataset.tab===tab)); + if(button)button.classList.add('active'); +} +function renderOutboundVehicleEditOrders(){ + const body=document.getElementById('ove-orders-body'),orders=outboundVehicleEditDraft&&outboundVehicleEditDraft.orders||[]; + const count=document.getElementById('ove-order-tab-count');if(count)count.textContent=String(orders.length);if(!body)return; + body.replaceChildren(); + if(!orders.length){const row=document.createElement('tr'),cell=document.createElement('td');cell.colSpan=7;cell.className='outbound-vehicle-empty';cell.textContent='暂无关联订单';row.appendChild(cell);body.appendChild(row);return;} + orders.forEach(order=>{const row=document.createElement('tr');[order.orderNo,order.weight,order.pallets,order.destFba,order.vol,order.container].forEach(value=>{const cell=document.createElement('td');cell.textContent=String(value??'');row.appendChild(cell);});const action=document.createElement('td'),button=document.createElement('button');button.type='button';button.className='btn btn-sm btn-default';button.textContent='删除';button.addEventListener('click',()=>removeOutboundVehicleEditOrder(order.orderNo));action.appendChild(button);row.appendChild(action);body.appendChild(row);}); +} +function removeOutboundVehicleEditOrder(orderNo){if(!outboundVehicleEditDraft)return;outboundVehicleEditDraft.orders=outboundVehicleEditDraft.orders.filter(order=>order.orderNo!==orderNo);renderOutboundVehicleEditOrders();} +function cancelOutboundVehicleEdit(){outboundVehicleEditDraft=null;outboundVehicleOrderSelection.clear();hideModal('modal-outbound-vehicle-order-select');hideModal('modal-outbound-vehicle-edit');} +function openOutboundVehicleOrderSelect(){ + if(!outboundVehicleEditDraft){showToast('请先打开排车编辑','error');return;} + outboundVehicleOrderSelection.clear();['ove-order-keyword','ove-order-fba'].forEach(id=>{const input=document.getElementById(id);if(input)input.value='';});renderOutboundVehicleOrderOptions();showModal('modal-outbound-vehicle-order-select'); +} +function renderOutboundVehicleOrderOptions(){ + const body=document.getElementById('ove-order-options-body');if(!body)return; + const keyword=(document.getElementById('ove-order-keyword')?.value||'').trim().toLowerCase(),fba=(document.getElementById('ove-order-fba')?.value||'').trim().toLowerCase(); + const list=getOutboundVehicleOrderOptionPool().filter(order=>(!keyword||(order.orderNo+' '+order.container).toLowerCase().includes(keyword))&&(!fba||order.destFba.toLowerCase().includes(fba))); + body.replaceChildren(); + if(!list.length){const row=document.createElement('tr'),cell=document.createElement('td');cell.colSpan=7;cell.className='outbound-vehicle-empty';cell.textContent='暂无符合条件的待派送订单';row.appendChild(cell);body.appendChild(row);} + list.forEach(order=>{const row=document.createElement('tr'),selectCell=document.createElement('td'),checkbox=document.createElement('input');checkbox.type='checkbox';checkbox.checked=outboundVehicleOrderSelection.has(order.orderNo);checkbox.addEventListener('change',()=>toggleOutboundVehicleOrderSelection(order.orderNo,checkbox.checked));selectCell.appendChild(checkbox);row.appendChild(selectCell);[order.orderNo,order.weight,order.pallets,order.destFba,order.vol,order.container].forEach(value=>{const cell=document.createElement('td');cell.textContent=String(value??'');row.appendChild(cell);});body.appendChild(row);}); + const summary=document.getElementById('ove-order-option-summary');if(summary)summary.textContent='共 '+list.length+' 条待派送订单,已选择 '+outboundVehicleOrderSelection.size+' 条'; +} +function toggleOutboundVehicleOrderSelection(orderNo,checked){if(checked)outboundVehicleOrderSelection.add(orderNo);else outboundVehicleOrderSelection.delete(orderNo);renderOutboundVehicleOrderOptions();} +function confirmOutboundVehicleOrderSelection(){ + if(!outboundVehicleEditDraft)return; + const available=getOutboundVehicleOrderOptionPool(),availableMap=new Map(available.map(order=>[order.orderNo,order]));let added=0,skipped=0; + outboundVehicleOrderSelection.forEach(orderNo=>{const order=availableMap.get(orderNo);if(order){outboundVehicleEditDraft.orders.push(cloneOutboundVehicleOrder(order));added++;}else skipped++;}); + outboundVehicleOrderSelection.clear();renderOutboundVehicleEditOrders();hideModal('modal-outbound-vehicle-order-select'); + if(skipped)showToast('部分订单已被占用,已跳过 '+skipped+' 条','warning');else if(added)showToast('已加入 '+added+' 条订单','success');else showToast('请至少选择 1 条订单','warning'); } function saveVehicleEdit(){ - const vehicleNo=document.getElementById('ve-vehicleNo').value; + if(!outboundVehicleEditDraft){showToast('未找到编辑草稿','error');return;} + const vehicleNo=outboundVehicleEditDraft.vehicleNo; const v=outboundVehicleData.find(x=>x.vehicleNo===vehicleNo); - if(!v){showToast('未找到该排车记录','warning');return;} - v.plate=document.getElementById('ve-plate').value; - v.company=document.getElementById('ve-company').value; - v.driver=document.getElementById('ve-driver').value; - v.phone=document.getElementById('ve-phone').value; - v.dispatch=document.getElementById('ve-dispatch').value; - v.route=document.getElementById('ve-route').value; - v.depart=document.getElementById('ve-depart').value||'-'; - v.eta=document.getElementById('ve-eta').value||'-'; - v.fbaBooking=document.getElementById('ve-fbaBooking').value||'-'; - v.carBooking=document.getElementById('ve-carBooking').value||'-'; - v.status=document.getElementById('ve-status').value; - renderOutboundVehicle(); - switchPage('outbound-vehicle'); + if(!v){showToast('未找到该排车记录','error');return;} + const fields={plate:'ove-plate',company:'ove-company',driver:'ove-driver',phone:'ove-phone',route:'ove-route',depart:'ove-depart',eta:'ove-eta',fbaBooking:'ove-fba-booking',carBooking:'ove-car-booking',status:'ove-status'}; + Object.keys(fields).forEach(key=>{outboundVehicleEditDraft[key]=document.getElementById(fields[key])?.value||'';}); + if(!outboundVehicleEditDraft.orders.length){showToast('请至少保留 1 条关联订单','error');switchOutboundVehicleEditTab('orders');return;} + Object.assign(v,outboundVehicleEditDraft);v.depart=v.depart?String(v.depart).replace('T',' '):'-';v.eta=v.eta?String(v.eta).replace('T',' '):'-';v.orders=outboundVehicleEditDraft.orders.map(cloneOutboundVehicleOrder);v.dispatch=v.orders.map(order=>order.orderNo).join('、');v.updatedAt=lmoNow(); + outboundVehicleEditDraft=null;hideModal('modal-outbound-vehicle-edit');renderOutboundVehicle(); showToast('排车信息已保存','success'); } @@ -5200,12 +6159,210 @@ function saveCtAbnormalState(){ showToast(canceling?'已取消货柜异常标记':'货柜已标记为异常','success'); return true; } -function renderCtList(){renderTable('tbody-ct-list',ctListData,['_cb','_act','no','manifest','status','isAbnormal','ctNo','clearDoc','releaseDoc','puDoc','fleet','wh','bl','vessel','type','carrier','pol','pod','vol','time','etd','atd','eta','ata'],(d,c,i)=>{ -if(c==='_cb')return ``; +function formatCtDateTime(value){return value?String(value).replace('T',' '):'—';} +function getCtEmptyWarningState(item,now){ + if(!item||!item.emptyExpectedAt)return {tone:'none',text:'—'}; + if(item.emptiedAt)return {tone:'done',text:'已报空'}; + var current=now&&typeof now.getTime==='function'?new Date(now.getTime()):new Date(); + var expected=new Date(item.emptyExpectedAt); + if(Number.isNaN(expected.getTime())||current<=expected)return {tone:'normal',text:'未超时'}; + var days=Math.ceil((current.getTime()-expected.getTime())/86400000); + return {tone:'overdue',text:'超时 '+days+' 天'}; +} +function renderCtEmptyWarning(item){ + var state=getCtEmptyWarningState(item,new Date()); + if(state.tone==='done')return ''+state.text+''; + if(state.tone==='overdue')return ''+state.text+''; + if(state.tone==='normal')return ''+state.text+''; + return '—'; +} +// ===== 货柜托盘标纯函数 ===== +const MAX_CT_PALLET_LABELS_PER_GROUP=500; +const CT_PALLET_VOLUME_SCALE=1000000000; +function normalizeCtPalletCabinet(value){ + return String(value||'').split(/[((]/)[0].trim(); +} +function buildCtPalletLabels(containers,manifests,detailMap){ + const labels=[]; + let skippedContainers=0; + let skippedDetails=0; + const manifestList=Array.isArray(manifests)?manifests:[]; + const detailsByManifest=detailMap||{}; + const manifestByNo=new Map(); + const labelCounters=new Map(); + manifestList.forEach(manifest=>{ + if(manifest&&!manifestByNo.has(manifest.no))manifestByNo.set(manifest.no,manifest); + }); + + (Array.isArray(containers)?containers:[]).forEach(container=>{ + const cabinetNo=normalizeCtPalletCabinet(container&&container.ctNo); + const manifest=manifestByNo.get(container&&container.manifest); + const details=manifest&&detailsByManifest[manifest.no]; + if(!cabinetNo||!manifest||!Array.isArray(details)||!details.length){ + skippedContainers++; + return; + } + + const groups=new Map(); + details.forEach(detail=>{ + const destWh=String(detail&&detail.destWh||'').trim(); + const businessTypeCode=String(detail&&detail.businessTypeCode||'').trim().toUpperCase(); + const volume=Number(detail&&detail.vol); + if(!destWh||!businessTypeCode||!Number.isFinite(volume)||volume<=0){ + skippedDetails++; + return; + } + const volumeUnits=Math.round(volume*CT_PALLET_VOLUME_SCALE); + if(!Number.isSafeInteger(volumeUnits)||volumeUnits<=0){ + skippedDetails++; + return; + } + const key=destWh+'\u0000'+businessTypeCode; + if(!groups.has(key))groups.set(key,{destWh:destWh,businessTypeCode:businessTypeCode,volumeUnits:0,detailCount:0,overflow:false}); + const group=groups.get(key); + group.detailCount++; + if(!group.overflow){ + const nextVolumeUnits=group.volumeUnits+volumeUnits; + if(Number.isSafeInteger(nextVolumeUnits))group.volumeUnits=nextVolumeUnits; + else group.overflow=true; + } + }); + + const sortedGroups=Array.from(groups.values()).sort((left,right)=>{ + if(left.businessTypeCode!==right.businessTypeCode)return left.businessTypeCode{ + if(group.overflow){ + skippedDetails+=group.detailCount; + return; + } + const normalizedVolume=group.volumeUnits/CT_PALLET_VOLUME_SCALE; + const palletTotal=Math.ceil(group.volumeUnits/(2*CT_PALLET_VOLUME_SCALE)); + if(!Number.isFinite(normalizedVolume)||!Number.isFinite(palletTotal)||palletTotal<=0||palletTotal>MAX_CT_PALLET_LABELS_PER_GROUP){ + skippedDetails+=group.detailCount; + return; + } + const outputVolume=Number(normalizedVolume.toFixed(9)); + const counterKey=cabinetNo+'\u0000'+group.businessTypeCode; + if(!labelCounters.has(counterKey))labelCounters.set(counterKey,0); + for(let index=0;index
${code}
${destination}
`; + }).join(''); +} +function openCtPalletLabelPreview(){ + const checked=Array.from(document.querySelectorAll('.ct-row-cb:checked')); + if(!checked.length){showToast('请先选择需要生成托盘标的货柜','warning');return;} + const selected=checked.map(function(input){return ctListData[Number(input.dataset.ctIndex)];}).filter(Boolean); + const result=buildCtPalletLabels(selected,ctManifestData,mfDetailData); + if(!result.labels.length){showToast('所选货柜暂无可生成的托盘标数据','warning');return;} + currentCtPalletLabels=result.labels; + renderCtPalletLabelPreview(); + ctPalletLabelReturnFocus=document.activeElement; + if(!ctPalletLabelReturnFocus||typeof ctPalletLabelReturnFocus.focus!=='function')ctPalletLabelReturnFocus=null; + showModal('modal-ct-pallet-label-preview'); + requestAnimationFrame(function(){ + const closeButton=document.getElementById('ct-pallet-preview-close'); + if(closeButton)closeButton.focus(); + }); + if(result.skippedContainers||result.skippedDetails){ + showToast('已跳过 '+result.skippedContainers+' 个货柜、'+result.skippedDetails+' 条无效明细','warning'); + } +} +function adjustCtPalletLabelFont(target,delta){ + if(target!=='code'&&target!=='destination')return; + const limits=target==='code'?{min:60,max:220}:{min:60,max:240}; + const step=Number(delta); + if(!Number.isFinite(step))return; + ctPalletLabelFontSizes[target]=Math.min(limits.max,Math.max(limits.min,ctPalletLabelFontSizes[target]+step)); + const modal=document.getElementById('modal-ct-pallet-label-preview'); + const output=document.getElementById(target==='code'?'ct-pallet-code-size':'ct-pallet-destination-size'); + if(modal)modal.style.setProperty(target==='code'?'--ct-pallet-code-size':'--ct-pallet-destination-size',ctPalletLabelFontSizes[target]+'px'); + if(output)output.textContent=String(ctPalletLabelFontSizes[target]); +} +function closeCtPalletLabelPreview(){ + hideModal('modal-ct-pallet-label-preview'); + document.body.classList.remove('ct-pallet-printing'); + if(ctPalletLabelReturnFocus&&ctPalletLabelReturnFocus.isConnected&&typeof ctPalletLabelReturnFocus.focus==='function')ctPalletLabelReturnFocus.focus(); + ctPalletLabelReturnFocus=null; +} +function printCtPalletLabels(){ + if(!currentCtPalletLabels.length){showToast('暂无可打印的托盘标','warning');return;} + document.body.classList.add('ct-pallet-printing'); + window.print(); +} +window.addEventListener('afterprint',function(){document.body.classList.remove('ct-pallet-printing');}); +document.addEventListener('keydown',function(event){ + const modal=document.getElementById('modal-ct-pallet-label-preview'); + if(!modal||!modal.classList.contains('show'))return; + if(event.key==='Escape'){ + event.preventDefault(); + closeCtPalletLabelPreview(); + return; + } + if(event.key!=='Tab')return; + const focusable=Array.from(modal.querySelectorAll('button:not([disabled]),[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])')); + if(!focusable.length)return; + const first=focusable[0]; + const last=focusable[focusable.length-1]; + if(event.shiftKey&&(document.activeElement===first||!modal.contains(document.activeElement))){ + event.preventDefault(); + last.focus(); + }else if(!event.shiftKey&&(document.activeElement===last||!modal.contains(document.activeElement))){ + event.preventDefault(); + first.focus(); + } +}); +function renderCtList(){renderTable('tbody-ct-list',ctListData,['_cb','_act','_emptyWarning','no','manifest','status','isAbnormal','ctNo','clearDoc','releaseDoc','puDoc','fleet','wh','bl','vessel','type','carrier','pol','pod','vol','time','etd','atd','eta','ata','pickupExpectedAt','appointmentAt','emptiedAt','returnedAt'],(d,c,i)=>{ +if(c==='_cb')return ``; if(c==='_act')return `编辑   清关   ${d.isAbnormal?'取消异常':'标记异常'}   更多 ∨`; if(c==='status')return renderContainerStatusTag(d.status); if(c==='isAbnormal')return renderAbnormalTag(getContainerAbnormalState(d.no)); -if(c==='fleet'){const fleetOpts=['顺通拖车车队','宏达联运车队','飞跃码头车队','中欧陆运车队','环宇港运车队'];return ``;} +if(c==='fleet'){ + const fleetOpts=['顺通拖车车队','宏达联运车队','飞跃码头车队','中欧陆运车队','环宇港运车队']; + return `
`; +} if(c==='clearDoc'||c==='releaseDoc'||c==='puDoc'){ const key=c;const v=d[key]; if(v) return `📎 ${v.length>12?v.substring(0,12)+'...':v}`; @@ -5213,6 +6370,8 @@ if(c==='clearDoc'||c==='releaseDoc'||c==='puDoc'){ } if(c==='vol')return d.vol||'-'; if(c==='time'||c==='etd'||c==='atd'||c==='eta'||c==='ata')return d[c]||'-'; +if(c==='pickupExpectedAt'||c==='appointmentAt'||c==='emptiedAt'||c==='returnedAt')return formatCtDateTime(d[c]); +if(c==='_emptyWarning')return renderCtEmptyWarning(d); return d[c]; });} function ctUploadDoc(no,key,el){ @@ -5267,7 +6426,7 @@ function renderCtManifest(){ const stMap={'国内报关成功':'tag-green','待拣货装柜':'tag-orange','已装柜':'tag-blue','已封箱':'tag-purple'}; tb.innerHTML=ctManifestData.map(d=>` - 🖨打印 备注 删除 + 查看详情 🖨打印 备注 删除 ${d.wh} ${d.no} ${d.ctNo} @@ -5568,8 +6727,8 @@ function renderUnifiedInventory(list){ if(!tb)return; tb.innerHTML=data.length?data.map(function(item){ const statusClass={'正常':'tag-green','库存不足':'tag-orange','无可用库存':'tag-gray','存在暂扣':'tag-red','存在美本土散版':'tag-cyan'}[item.status]||'tag-gray'; - return '查看'+lmoEsc(item.owner)+''+lmoEsc(item.warehouse)+''+lmoEsc(item.sku)+''+lmoEsc(item.cnName)+''+item.batches.length+''+item.locations.length+''+formatWmsUnits(item.onHandStock)+''+formatWmsUnits(item.availableStock)+''+formatWmsUnits(item.holdStock)+''+formatWmsUnits(item.defectiveStock)+''+formatWmsUnits(item.inTransitStock)+''+formatWmsUnits(item.purchaseStock)+''+lmoEsc(item.status)+''+lmoEsc(item.updatedAt)+''; - }).join(''):'暂无符合条件的库存信息'; + return '查看'+lmoEsc(item.owner)+''+lmoEsc(item.warehouse)+''+lmoEsc(item.sku)+''+lmoEsc(item.cnName)+''+formatWmsUnits(item.onHandStock)+''+formatWmsUnits(item.availableStock)+''+formatWmsUnits(item.holdStock)+''+formatWmsUnits(item.defectiveStock)+''+formatWmsUnits(item.inTransitStock)+''+formatWmsUnits(item.purchaseStock)+''+lmoEsc(item.status)+''+lmoEsc(item.updatedAt)+''; + }).join(''):'暂无符合条件的库存信息'; const total=document.getElementById('inventory-overview-total'); if(total)total.textContent='共 '+data.length+' 条'; } @@ -5654,8 +6813,8 @@ function renderInventoryTransactions(list){ const tb=document.getElementById('tbody-inventory-transactions'); if(!tb)return; tb.innerHTML=data.length?data.map(function(row){ - return ''+lmoEsc(row.occurredAt)+''+lmoEsc(row.owner)+''+lmoEsc(row.warehouse)+''+lmoEsc(row.sku)+''+lmoEsc(row.cnName)+''+lmoEsc(row.businessType)+''+wmsDocumentLink('business',row.businessOrderNo)+''+wmsDocumentLink('inbound',row.inboundNo)+''+wmsDocumentLink('outbound',row.outboundNo)+''+lmoEsc(row.batchNo)+''+lmoEsc(row.location)+''+row.inQty+''+row.outQty+''+row.balance+''+lmoEsc(row.operator)+''+lmoEsc(row.remark)+''; - }).join(''):'暂无符合条件的进销存记录'; + return ''+lmoEsc(row.occurredAt)+''+lmoEsc(row.owner)+''+lmoEsc(row.warehouse)+''+lmoEsc(row.sku)+''+lmoEsc(row.cnName)+''+lmoEsc(row.businessType)+''+wmsDocumentLink('business',row.businessOrderNo)+''+wmsDocumentLink('inbound',row.inboundNo)+''+wmsDocumentLink('outbound',row.outboundNo)+''+row.inQty+''+row.outQty+''+row.balance+''+lmoEsc(row.operator)+''+lmoEsc(row.remark)+''; + }).join(''):'暂无符合条件的进销存记录'; const total=document.getElementById('inventory-transaction-total'); if(total)total.textContent='共 '+data.length+' 条'; } @@ -6390,6 +7549,34 @@ const selectedLastMileOrderNos=new Set(); let lastMileImportRows=[]; function lmoNow(){const d=new Date(),p=n=>String(n).padStart(2,'0');return d.getFullYear()+'-'+p(d.getMonth()+1)+'-'+p(d.getDate())+' '+p(d.getHours())+':'+p(d.getMinutes());} function lmoEsc(value){return String(value==null?'':value).replace(/[&<>"']/g,ch=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]));} +function parseLastMileTime(value){ + const normalized=String(value==null?'':value).trim(); + if(!normalized)return NaN; + const match=/^(\d{4})-(\d{2})-(\d{2})(?:T| )(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?(Z|[+-]\d{2}:\d{2})?$/.exec(normalized); + if(!match)return NaN; + const year=Number(match[1]),month=Number(match[2]),day=Number(match[3]),hour=Number(match[4]),minute=Number(match[5]),second=Number(match[6]||0),offset=match[8]||''; + const daysInMonth=new Date(year,month,0).getDate(); + if(month<1||month>12||day<1||day>daysInMonth||hour>23||minute>59||second>59||(offset&&offset!=='Z'&&(Number(offset.slice(1,3))>23||Number(offset.slice(4,6))>59)))return NaN; + const time=Date.parse(normalized.includes('T')?normalized:normalized.replace(' ','T')); + return Number.isNaN(time)?NaN:time; +} +function getLastMileWarnings(order,now){ + const warnings=[]; + const containerState=getContainerAbnormalState(order&&order.containerNo); + if(containerState.isAbnormal)warnings.push({type:'container',label:'货柜异常',className:'tag-red',title:containerState.reason||'未填写异常原因'}); + if(order&&order.serviceType==='拒收订单')warnings.push({type:'rejection',label:'拒收',className:'tag-red',title:order.rejectionTime?'拒收时间:'+order.rejectionTime:'拒收订单'}); + if(order&&order.serviceType==='快递订单'&&!String(order.outboundNo||'').trim()){ + const inboundTime=parseLastMileTime(order.actualInboundTime); + const currentTime=parseLastMileTime(now==null?new Date().toISOString():now); + const elapsedHours=Math.floor((currentTime-inboundTime)*(1/(60*60*1000))); + if(Number.isFinite(inboundTime)&&Number.isFinite(currentTime)&&elapsedHours>=48)warnings.push({type:'warehouse-timeout',label:'在库超时 '+elapsedHours+'h',className:'tag-orange',title:'实际入库时间:'+order.actualInboundTime}); + } + return warnings; +} +function renderLastMileWarningTags(order,now){ + const warnings=getLastMileWarnings(order,now); + return warnings.length?`
${warnings.map(warning=>`${lmoEsc(warning.label)}`).join('')}
`:'—'; +} const orderedLastMileFieldConfig=lastMileFieldConfig.slice().sort((a,b)=>a.order-b.order); function getLastMileFieldDefaults(mode){ const selected=orderedLastMileFieldConfig.filter(field=>field.defaultSelected||((mode||'import')==='import'&&field.importRequired)).map(field=>field.key); @@ -6527,10 +7714,10 @@ function createLastMileOrderFromFirstLeg(firstLegOrder){ const order={ no:'LMO20260810'+seq,firstLegNo:firstLegOrder.firstLegNo,serviceType:firstLegOrder.serviceType||'头程',owner:firstLegOrder.owner,warehouse:firstLegOrder.warehouse, fbaWarehouse:firstLegOrder.fbaWarehouse,transferWarehouse:firstLegOrder.transferWarehouse||'',containerNo:firstLegOrder.containerNo,pallets:firstLegOrder.pallets,boxes:firstLegOrder.boxes, - pieces:firstLegOrder.pieces,weight:firstLegOrder.weight,volume:firstLegOrder.volume,volumeWeight:firstLegOrder.volumeWeight||Number(((firstLegOrder.volume||0)*167).toFixed(2)),portEta:firstLegOrder.portEta||firstLegOrder.eta,eta:firstLegOrder.eta,actualArrivalTime:firstLegOrder.actualArrivalTime||(firstLegOrder.customsStatus==='清关完成'?firstLegOrder.eta:''),transportMode:firstLegOrder.transportMode, + pieces:firstLegOrder.pieces,weight:firstLegOrder.weight,volume:firstLegOrder.volume,volumeWeight:firstLegOrder.volumeWeight||Number(((firstLegOrder.volume||0)*167).toFixed(2)),portEta:firstLegOrder.portEta||firstLegOrder.eta,eta:firstLegOrder.eta,actualArrivalTime:firstLegOrder.actualArrivalTime||(firstLegOrder.customsStatus==='清关完成'?firstLegOrder.eta:''),rejectionTime:firstLegOrder.rejectionTime||'',actualInboundTime:firstLegOrder.actualInboundTime||'',transportMode:firstLegOrder.transportMode, customsStatus:firstLegOrder.customsStatus||'待清关',inboundPlan:firstLegOrder.inboundPlan||null,consolidation:firstLegOrder.consolidation||null,isConsolidated:!!firstLegOrder.isConsolidated, appointment:firstLegOrder.appointment||null,outboundPlan:firstLegOrder.outboundPlan||null,inboundNo:firstLegOrder.inboundNo||'', - outboundNo:firstLegOrder.outboundNo||'',dispatchNo:firstLegOrder.dispatchNo||'',cargo:firstLegOrder.cargo||[], + outboundNo:firstLegOrder.outboundNo||'',dispatchNo:firstLegOrder.dispatchNo||'',cargo:firstLegOrder.cargo||[],feeDetails:Array.isArray(firstLegOrder.feeDetails)?firstLegOrder.feeDetails.slice():[], noteSelf:firstLegOrder.noteSelf||'',noteCustomer:firstLegOrder.noteCustomer||'',noteWarehouse:firstLegOrder.noteWarehouse||'',transferRemark:firstLegOrder.transferRemark||'', logs:[{time:'2026-08-10 09:00',node:'尾程订单生成',operator:'系统',result:'头程订单出库完成,自动生成尾程订单'}] }; @@ -6542,6 +7729,20 @@ function createLastMileOrderFromFirstLeg(firstLegOrder){ lastMileOrderData.push(order); return order; } +lastMileFirstLegSamples[0].feeDetails=[ + {feeType:'清关费',supplier:'宁波中基惠通报关有限公司',currency:'USD',amount:420,status:'已产生'}, + {feeType:'拖车费',supplier:'宁波北仑顺达集装箱运输',currency:'USD',amount:780,status:'已产生'}, + {feeType:'贴箱唛费',supplier:'洛杉矶长滩海外仓',currency:'USD',amount:36,status:'已产生'}, + {feeType:'开箱费',supplier:'洛杉矶长滩海外仓',currency:'USD',amount:12,status:'已产生'}, + {feeType:'挑货费',supplier:'洛杉矶长滩海外仓',currency:'USD',amount:8.5,status:'已产生'}, + {feeType:'仓储费',supplier:'洛杉矶长滩海外仓',currency:'USD',amount:100,status:'待产生'} +]; +lastMileFirstLegSamples[1].feeDetails=[ + {feeType:'入库费',supplier:'纽约海外仓',currency:'USD',amount:120,status:'已产生'}, + {feeType:'仓储费',supplier:'纽约海外仓',currency:'USD',amount:64,status:'已产生'}, + {feeType:'派送费',supplier:'UPS',currency:'USD',amount:180,status:'已产生'}, + {feeType:'出库费',supplier:'纽约海外仓',currency:'USD',amount:0,status:'待产生'} +]; lastMileFirstLegSamples.forEach(createLastMileOrderFromFirstLeg); function renderLastMileOperationItems(order,locked){ @@ -6568,12 +7769,12 @@ function renderLastMileOrders(list){ return ` ${operationContent} - ${lmoEsc(order.no)}${lmoEsc(order.serviceType||'头程')}${lmoEsc(order.inboundPlan&&order.inboundPlan.inboundCode||order.inboundCode||'—')}${lmoEsc(order.owner)}${lmoEsc(order.warehouse)}${lmoEsc(order.transferWarehouse||'—')}${lmoEsc(order.fbaWarehouse)}${lmoEsc(order.containerNo)}${renderContainerStatusTag((findContainerByNo(order.containerNo)||{}).status)}${renderAbnormalTag(getContainerAbnormalState(order.containerNo))}${detained?'是':'否'}${order.pallets}${order.boxes}${order.volume}${order.pieces}${order.volumeWeight}${lmoEsc(order.portEta||'—')}${lmoEsc(order.actualArrivalTime||'—')}${lmoEsc(order.eta)}${order.inboundNo?`${lmoEsc(order.inboundNo)}`:'—'}${order.outboundNo?`${lmoEsc(order.outboundNo)}`:'—'}${order.dispatchNo?`${lmoEsc(order.dispatchNo)}`:'—'}${relabel?`${lmoEsc(relabel.orderNo)}`:'—'}${relabel?`${lmoEsc(relabel.status)}`:'—'}${isLastMileConsolidated(order)?`已合托`:'—'}${lmoEsc(order.status)} + ${lmoEsc(order.no)}${renderLastMileWarningTags(order)}${lmoEsc(order.serviceType||'头程')}${lmoEsc(order.rejectionTime||'—')}${lmoEsc(order.inboundPlan&&order.inboundPlan.inboundCode||order.inboundCode||'—')}${lmoEsc(order.owner)}${lmoEsc(order.warehouse)}${lmoEsc(order.transferWarehouse||'—')}${lmoEsc(order.fbaWarehouse)}${lmoEsc(order.containerNo)}${renderContainerStatusTag((findContainerByNo(order.containerNo)||{}).status)}${renderAbnormalTag(getContainerAbnormalState(order.containerNo))}${detained?'是':'否'}${order.pallets}${order.boxes}${order.volume}${order.pieces}${order.volumeWeight}${lmoEsc(order.portEta||'—')}${lmoEsc(order.actualArrivalTime||'—')}${lmoEsc(order.eta)}${order.inboundNo?`${lmoEsc(order.inboundNo)}`:'—'}${order.outboundNo?`${lmoEsc(order.outboundNo)}`:'—'}${order.dispatchNo?`${lmoEsc(order.dispatchNo)}`:'—'}${relabel?`${lmoEsc(relabel.orderNo)}`:'—'}${relabel?`${lmoEsc(relabel.status)}`:'—'}${isLastMileConsolidated(order)?`已合托`:'—'}${lmoEsc(order.status)} `; - }).join(''):'
未查询到符合条件的尾程订单
'; + }).join(''):'
未查询到符合条件的尾程订单
'; const total=document.getElementById('lmo-total');if(total)total.textContent='共 '+data.length+' 条'; updateLastMileSelectionSummary(data); } @@ -6616,6 +7817,32 @@ function lastMileReset(){ function openLastMileOrderDetail(no){const order=lastMileOrderData.find(item=>item.no===no);if(!order)return;currentLastMileOrderNo=no;switchPage('last-mile-order-detail');renderLastMileOrderDetail(order);} function backToLastMileOrders(){const nav=document.querySelector('.sub-menu-item[onclick="switchPage(\'last-mile-orders\',this)"]');switchPage('last-mile-orders',nav);} function lmoInfo(label,value){return `
${lmoEsc(label)}${value==null||value===''?'—':lmoEsc(value)}
`;} +function getLastMileDepartureFeeRecords(order){ + return Array.isArray(order&&order.feeDetails)?order.feeDetails.filter(function(fee){ + const amount=Number(fee&&fee.amount); + return fee&&fee.status==='已产生'&&Number.isFinite(amount)&&amount>0; + }):[]; +} +function getLastMileDepartureFeeTotalText(rows){ + const currencyBuckets=rows.reduce(function(sum, fee){ + const currency=String(fee.currency||'').trim()||'—'; + sum[currency]=(sum[currency]||0)+Number(fee.amount); + return sum; + },{}); + return Object.keys(currencyBuckets).map(function(currency){ + return currency+' '+currencyBuckets[currency].toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g,','); + }).join(';'); +} +function renderLastMileDepartureFees(order){ + const tbody=document.getElementById('tbody-lmo-departure-fee'),total=document.getElementById('lmo-departure-fee-total'); + if(!tbody||!total)return; + const rows=getLastMileDepartureFeeRecords(order); + tbody.innerHTML=rows.length?rows.map(function(fee,index){ + const amount=Number(fee.amount),currency=fee.currency?lmoEsc(fee.currency)+' ':'',supplier=lmoEsc(fee.supplier||'—'); + return ''+String(index+1)+''+lmoEsc(fee.feeType||'—')+''+supplier+''+currency+amount.toFixed(2)+''; + }).join(''):'暂无已产生费用'; + total.textContent=getLastMileDepartureFeeTotalText(rows)||'—'; +} function renderLastMileOrderDetail(order){ order=order||lastMileOrderData.find(item=>item.no===currentLastMileOrderNo);if(!order)return; currentLastMileOrderNo=order.no;order.status=deriveLastMileStatus(order); @@ -6624,12 +7851,13 @@ function renderLastMileOrderDetail(order){ const status=document.getElementById('lmo-detail-status');status.textContent=order.status;status.className='tag '+lastMileStatusClass(order.status); const containerAbnormal=getContainerAbnormalState(order.containerNo); const relabel=getLastMileRelabelOrder(order); - document.getElementById('lmo-detail-order-info').innerHTML=lmoInfo('订单类型',order.serviceType)+lmoInfo('头程单号',order.firstLegNo)+lmoInfo('货主',order.owner)+lmoInfo('海外仓',order.warehouse)+lmoInfo('转仓目的仓',order.transferWarehouse)+lmoInfo('FBA仓库',order.fbaWarehouse)+lmoInfo('集装箱号',order.containerNo)+lmoInfo('货柜异常',containerAbnormal.isAbnormal?'异常':'正常')+lmoInfo('异常原因',containerAbnormal.isAbnormal?(containerAbnormal.reason||'未填写异常原因'):'—')+lmoInfo('运输方式',order.transportMode)+lmoInfo('预计到仓',order.eta)+lmoInfo('清关状态',order.customsStatus); + document.getElementById('lmo-detail-order-info').innerHTML=lmoInfo('订单类型',order.serviceType)+lmoInfo('拒收时间',order.rejectionTime)+lmoInfo('实际入库时间',order.actualInboundTime)+lmoInfo('头程单号',order.firstLegNo)+lmoInfo('货主',order.owner)+lmoInfo('海外仓',order.warehouse)+lmoInfo('转仓目的仓',order.transferWarehouse)+lmoInfo('FBA仓库',order.fbaWarehouse)+lmoInfo('集装箱号',order.containerNo)+lmoInfo('货柜异常',containerAbnormal.isAbnormal?'异常':'正常')+lmoInfo('异常原因',containerAbnormal.isAbnormal?(containerAbnormal.reason||'未填写异常原因'):'—')+lmoInfo('运输方式',order.transportMode)+lmoInfo('预计到仓',order.eta)+lmoInfo('清关状态',order.customsStatus); document.getElementById('lmo-detail-order-details').innerHTML=lmoInfo('订单类型',order.serviceType)+lmoInfo('入仓码',order.inboundPlan&&order.inboundPlan.inboundCode)+lmoInfo('目的仓',order.transferWarehouse||order.fbaWarehouse)+lmoInfo('托数',order.pallets)+lmoInfo('箱数',order.boxes)+lmoInfo('数量',order.pieces)+lmoInfo('体积重量',order.volumeWeight)+lmoInfo('预计到港时间',order.portEta)+lmoInfo('实际到港时间',order.actualArrivalTime)+lmoInfo('预计到仓',order.eta)+lmoInfo('是否暂扣',isLastMileOrderDetained(order)?'是':'否')+lmoInfo('备注(仅自己)',order.noteSelf)+lmoInfo('备注(客户)',order.noteCustomer)+lmoInfo('备注(仓库)',order.noteWarehouse); document.getElementById('lmo-detail-plan-info').innerHTML=lmoInfo('入仓码',order.inboundPlan&&order.inboundPlan.inboundCode)+lmoInfo('计划入库仓',order.inboundPlan&&order.inboundPlan.warehouse)+lmoInfo('合托批次',order.consolidation&&order.consolidation.batchNo)+lmoInfo('合托后托数',order.consolidation&&order.consolidation.pallets)+lmoInfo('计划出库日期',order.outboundPlan&&order.outboundPlan.date)+lmoInfo('派送方式',order.outboundPlan&&order.outboundPlan.mode)+lmoInfo('FBA预约号',order.appointment&&order.appointment.no)+lmoInfo('预约状态',order.appointment&&order.appointment.status)+lmoInfo('换标状态',relabel&&relabel.status); const cargo=document.getElementById('tbody-lmo-detail-cargo');cargo.innerHTML=(order.cargo||[]).map(item=>`${lmoEsc(item.sku)}${lmoEsc(item.cnName)}${item.pallets}${item.boxes}${item.pieces}${item.weight}${item.volume}`).join('')||'暂无货物信息'; const docs=[['入库单',order.inboundNo,order.inboundPlan&&order.inboundPlan.createdAt,'fba-inbound-order'],['出库单',order.outboundNo,order.outboundPlan&&order.outboundPlan.createdAt,'fba-outbound-order'],['派送单',order.dispatchNo,order.appointment&&order.appointment.createdAt,'outbound-dispatch'],['换标单',relabel&&relabel.orderNo,relabel&&relabel.createdAt,'fba-relabel-order-detail']].filter(item=>item[1]); - document.getElementById('tbody-lmo-detail-documents').innerHTML=docs.map(item=>`${item[0]}${lmoEsc(item[1])}${lmoEsc(item[2]||'—')}`).join('')||'暂无关联单据'; + const documentQuote=order.quote||order.quoteNo||'—'; + document.getElementById('tbody-lmo-detail-documents').innerHTML=docs.map(item=>`${item[0]}${lmoEsc(item[1])}${lmoEsc(item[2]||'—')}${lmoEsc(documentQuote)}`).join('')||'暂无关联单据'; document.getElementById('tbody-lmo-detail-logs').innerHTML=(order.logs||[]).slice().reverse().map(log=>`${lmoEsc(log.time)}${lmoEsc(log.node)}${lmoEsc(log.operator)}${lmoEsc(log.result)}`).join('')||'暂无操作记录'; } function lmoActionOrder(no){const target=no||currentLastMileOrderNo;currentLastMileActionNo=target;return lastMileOrderData.find(order=>order.no===target);} @@ -6714,7 +7942,7 @@ function downloadCsvFile(filename,csv){ link.href=url;link.download=filename;document.body.appendChild(link);link.click();link.remove();URL.revokeObjectURL(url); } function downloadLastMileImportTemplate(selectedKeys=getSelectedImportFieldKeys()){ - const sample={orderType:'一件代发',firstLegNo:'HC20260810006',owner:'示例客户',warehouse:'洛杉矶长滩海外仓',transferWarehouse:'纽约海外仓',fbaWarehouse:'FBA ONT8',containerNo:'TLLU26081006',pallets:'2',boxes:'20',pieces:'480',weight:'360',volume:'3.6',volumeWeight:'601.2',portEta:'2026-08-18',actualArrivalTime:'',eta:'2026-08-19',customsStatus:'待清关',noteSelf:'优先处理',noteCustomer:'',noteWarehouse:'到仓后联系客户'}; + const sample={orderType:'一件代发',rejectionTime:'',actualInboundTime:'',firstLegNo:'HC20260810006',owner:'示例客户',warehouse:'洛杉矶长滩海外仓',transferWarehouse:'纽约海外仓',fbaWarehouse:'FBA ONT8',containerNo:'TLLU26081006',pallets:'2',boxes:'20',pieces:'480',weight:'360',volume:'3.6',volumeWeight:'601.2',portEta:'2026-08-18',actualArrivalTime:'',eta:'2026-08-19',customsStatus:'待清关',noteSelf:'优先处理',noteCustomer:'',noteWarehouse:'到仓后联系客户'}; const csv=buildLastMileCsv([sample],selectedKeys); downloadCsvFile('尾程订单导入模板.csv',csv); } @@ -6730,8 +7958,8 @@ function parseLastMileCsv(text,selectedKeys=getSelectedImportFieldKeys()){ const cells=splitLastMileCsvLine(line),record={};headers.forEach((header,i)=>record[header]=cells[i]||''); const valueFor=(key)=>{const field=getLastMileField(key);if(!field)return '';const aliases={warehouse:['当前仓','海外仓'],transferWarehouse:['目的仓','转仓仓库'],pieces:['数量','件数']};for(const label of [field.label,...(aliases[key]||[])])if(Object.prototype.hasOwnProperty.call(record,label))return record[label];return '';}; const num=key=>{const raw=valueFor(key);if(raw==='')return 0;const value=Number(raw);return Number.isFinite(value)?value:NaN;}; - const orderType=record['订单类型']||valueFor('orderType'),errors=[];if(orderType&&!["一件代发","头程"].includes(orderType))errors.push('订单类型仅支持一件代发或头程'); - const data={firstLegNo:valueFor('firstLegNo'),serviceType:orderType||'头程',status:'出库完成',owner:valueFor('owner'),warehouse:valueFor('warehouse'),transferWarehouse:valueFor('transferWarehouse'),fbaWarehouse:valueFor('fbaWarehouse'),containerNo:valueFor('containerNo'),pallets:num('pallets'),boxes:num('boxes'),pieces:num('pieces'),weight:num('weight'),volume:num('volume'),volumeWeight:num('volumeWeight'),portEta:valueFor('portEta'),actualArrivalTime:valueFor('actualArrivalTime'),eta:valueFor('eta'),transportMode:'导入',customsStatus:valueFor('customsStatus')||'待清关',noteSelf:valueFor('noteSelf'),noteCustomer:valueFor('noteCustomer'),noteWarehouse:valueFor('noteWarehouse'),cargo:[]}; + const orderType=record['订单类型']||valueFor('orderType'),errors=[],supportedOrderTypes=['一件代发','头程','拒收订单','快递订单'];if(orderType&&!supportedOrderTypes.includes(orderType))errors.push('订单类型仅支持一件代发、头程、拒收订单或快递订单'); + const data={firstLegNo:valueFor('firstLegNo'),serviceType:orderType||'头程',status:'出库完成',owner:valueFor('owner'),warehouse:valueFor('warehouse'),transferWarehouse:valueFor('transferWarehouse'),fbaWarehouse:valueFor('fbaWarehouse'),containerNo:valueFor('containerNo'),pallets:num('pallets'),boxes:num('boxes'),pieces:num('pieces'),weight:num('weight'),volume:num('volume'),volumeWeight:num('volumeWeight'),portEta:valueFor('portEta'),actualArrivalTime:valueFor('actualArrivalTime'),rejectionTime:valueFor('rejectionTime'),actualInboundTime:valueFor('actualInboundTime'),eta:valueFor('eta'),transportMode:'导入',customsStatus:valueFor('customsStatus')||'待清关',noteSelf:valueFor('noteSelf'),noteCustomer:valueFor('noteCustomer'),noteWarehouse:valueFor('noteWarehouse'),cargo:[]}; if(!data.firstLegNo)errors.push('缺少头程单号');if(!data.owner)errors.push('缺少货主');if(!data.warehouse)errors.push('缺少当前仓');if(!data.fbaWarehouse)errors.push('缺少FBA仓库'); ['pallets','boxes','pieces','weight','volume','volumeWeight'].forEach(key=>{if(selectedKeys.includes(key)&&Number.isNaN(data[key]))errors.push(getLastMileField(key).label+'格式不正确');}); if(lastMileOrderData.some(order=>order.firstLegNo===data.firstLegNo))errors.push('头程单号重复'); @@ -6804,22 +8032,47 @@ function openLastMileOutboundPlan(no){const order=lmoActionOrder(no);if(!order)r function saveLastMileOutboundPlan(){ const order=lastMileOrderData.find(item=>item.no===currentLastMileActionNo);if(!order)return;if(isLastMileOrderDetained(order)){showToast('头程订单已暂扣,不能创建出库单','warning');return;}const date=document.getElementById('lmo-outbound-date').value,fbaWarehouse=document.getElementById('lmo-outbound-fba').value,mode=document.getElementById('lmo-outbound-mode').value,remark=document.getElementById('lmo-outbound-remark').value.trim();if(!date||!fbaWarehouse||!mode){showToast('请填写完整的出库计划','error');return;} const now=lmoNow();order.outboundPlan={date,fbaWarehouse,mode,remark,createdAt:order.outboundPlan&&order.outboundPlan.createdAt||now};order.fbaWarehouse=fbaWarehouse;let linked=order.outboundNo&&fbaOutboundOrderData.find(item=>item.outboundNo===order.outboundNo);const firstCargo=(order.cargo||[])[0]||{}; - if(!linked){if(!order.outboundNo)order.outboundNo='FBO'+now.slice(0,10).replace(/-/g,'')+String(fbaOutboundOrderData.length+1).padStart(3,'0');fbaOutboundOrderData.unshift({outboundNo:order.outboundNo,outboundType:'派送',destWh:fbaWarehouse,transferWarehouse:order.transferWarehouse||'',sku:firstCargo.sku||'多SKU',cnName:firstCargo.cnName||'尾程订单货物',totalQty:order.pieces,boxes:order.boxes,netWt:order.weight,status:'待发货',lastMileNo:order.no,planDate:date,mode});}else{Object.assign(linked,{outboundType:linked.outboundType||'派送',destWh:fbaWarehouse,transferWarehouse:order.transferWarehouse||'',totalQty:order.pieces,boxes:order.boxes,netWt:order.weight,planDate:date,mode});} + const outboundItems=(order.cargo||[]).map(cargo=>{const skuCode=String(cargo.sku||'SKU').replace(/^SKU-/,'');return {owner:order.owner,sku:cargo.sku,cnName:cargo.cnName,quantity:cargo.pieces,boxes:cargo.boxes,pallets:cargo.pallets,weight:cargo.weight,volume:cargo.volume,palletNo:cargo.palletNo||'PAL-'+skuCode+'-01',inboundCode:cargo.inboundCode||order.inboundPlan&&order.inboundPlan.inboundCode||'—'};}); + const summary=summarizeFbaOutboundItems(outboundItems.length?outboundItems:[{owner:order.owner,sku:firstCargo.sku||'—',cnName:firstCargo.cnName||'尾程订单货物',quantity:order.pieces,boxes:order.boxes,pallets:order.pallets,weight:order.weight,volume:order.volume}]); + const outboundSummary={owner:summary.owner,skuCount:summary.skuCount,palletTotal:summary.palletTotal,totalQty:summary.totalQty,boxes:summary.boxes,netWt:summary.netWt,volume:summary.volume,items:outboundItems}; + if(!linked){if(!order.outboundNo)order.outboundNo='FBO'+now.slice(0,10).replace(/-/g,'')+String(fbaOutboundOrderData.length+1).padStart(3,'0');fbaOutboundOrderData.unshift({outboundNo:order.outboundNo,outboundType:'派送',destWh:fbaWarehouse,transferWarehouse:order.transferWarehouse||'',sku:firstCargo.sku||'多SKU',cnName:firstCargo.cnName||'尾程订单货物',status:'待发货',lastMileNo:order.no,planDate:date,mode,fees:createFbaOutboundReceivableFees(),...outboundSummary});}else{Object.assign(linked,{outboundType:linked.outboundType||'派送',destWh:fbaWarehouse,transferWarehouse:order.transferWarehouse||'',planDate:date,mode,...outboundSummary});} order.logs.push({time:now,node:'出库计划',operator:'张经理',result:'已保存并关联出库单 '+order.outboundNo});hideModal('modal-lmo-outbound-plan');refreshLastMileViews(order);showToast('出库计划已保存,已生成出库单 '+order.outboundNo,'success'); } function openLastMileAppointment(no){const order=lmoActionOrder(no);if(!order)return;const plan=order.appointment||{};document.getElementById('lmo-appointment-no').value=plan.no||'';document.getElementById('lmo-appointment-date').value=plan.date||'';document.getElementById('lmo-appointment-slot').value=plan.slot||'08:00-12:00';document.getElementById('lmo-appointment-status').value=plan.status||'待预约';showModal('modal-lmo-fba-appointment');} function saveLastMileAppointment(){ const order=lastMileOrderData.find(item=>item.no===currentLastMileActionNo);if(!order)return;const no=document.getElementById('lmo-appointment-no').value.trim(),date=document.getElementById('lmo-appointment-date').value,slot=document.getElementById('lmo-appointment-slot').value,status=document.getElementById('lmo-appointment-status').value;if(!no||!date||!slot){showToast('请填写完整的FBA预约信息','error');return;} const now=lmoNow();order.appointment={no,date,slot,status,createdAt:order.appointment&&order.appointment.createdAt||now}; - if(status==='预约成功'&&!order.dispatchNo){order.dispatchNo='DSP'+now.slice(0,10).replace(/-/g,'')+String(lastMileDispatchData.length+1).padStart(3,'0');const dispatch={dispatchNo:order.dispatchNo,lastMileNo:order.no,firstLegNo:order.firstLegNo,owner:order.owner,warehouse:order.warehouse,destFba:order.fbaWarehouse,inboundNo:order.inboundNo,appointmentNo:no,appointmentDate:date,slot,pallets:order.pallets,boxes:order.boxes,weight:order.weight,volume:order.volume,createdAt:now,status:'待派送'};lastMileDispatchData.unshift(dispatch);dispatchOrders.unshift({orderNo:order.dispatchNo,weight:order.weight,pallets:order.pallets,destFba:order.fbaWarehouse.replace('FBA ',''),vol:order.volume,container:order.containerNo,region:order.warehouse.includes('纽约')?'纽约':order.warehouse.includes('汉堡')?'欧洲':'洛杉矶',otype:'尾程派送',status:'待派送'});} + if(status==='预约成功'&&!order.dispatchNo){order.dispatchNo='DSP'+now.slice(0,10).replace(/-/g,'')+String(lastMileDispatchData.length+1).padStart(3,'0');const dispatch={dispatchNo:order.dispatchNo,lastMileNo:order.no,firstLegNo:order.firstLegNo,owner:order.owner,customer:order.owner,contact:order.contact||'未配置联系人',warehouse:order.warehouse,destFba:order.fbaWarehouse,inboundNo:order.inboundNo,appointmentNo:no,appointmentDate:date,slot,pallets:order.pallets,boxes:order.boxes,weight:order.weight,volume:order.volume,createdAt:now,status:'待派送',pickingStatus:'未拣货',expressNo:order.expressNo||'',outboundAt:order.outboundAt||'',courierNodes:Array.isArray(order.courierNodes)?order.courierNodes.slice():[]};lastMileDispatchData.unshift(dispatch);dispatchOrders.unshift({orderNo:order.dispatchNo,weight:order.weight,pallets:order.pallets,destFba:order.fbaWarehouse.replace('FBA ',''),vol:order.volume,container:order.containerNo,region:order.warehouse.includes('纽约')?'纽约':order.warehouse.includes('汉堡')?'欧洲':'洛杉矶',otype:'尾程派送',status:'待派送'});} order.logs.push({time:now,node:'FBA预约',operator:'张经理',result:status+(order.dispatchNo?',关联派送单 '+order.dispatchNo:'')});hideModal('modal-lmo-fba-appointment');refreshLastMileViews(order);showToast(status==='预约成功'?'预约成功,已生成派送单 '+order.dispatchNo:'FBA预约信息已保存','success'); } function renderLastMileDispatchRows(){ const tb=document.getElementById('tbody-outbound-dispatch');if(!tb)return; tb.querySelectorAll('tr[data-last-mile-dispatch]').forEach(row=>row.remove()); - const rows=lastMileDispatchData.map(item=>`详情${lmoEsc(item.status)}海卡${lmoEsc(item.dispatchNo)}尾程订单待配载${lmoEsc(item.warehouse)}——${lmoEsc(item.inboundNo||'—')}——${lmoEsc(item.destFba)}${lmoEsc(item.appointmentNo+' '+item.slot)}${lmoEsc(item.owner)}—${lmoEsc(item.appointmentDate)}系统同步正常卡车派送${lmoEsc(item.appointmentNo)}${lmoEsc(item.lastMileNo)}预约成功否编辑系统${lmoEsc(item.createdAt)}FBA-预约—${item.weight}${item.volume}${item.boxes}——`).join(''); + const rows=lastMileDispatchData.map(item=>{const fromVehicle=item.source==='outboundVehicle',detail=fromVehicle?`openOutboundVehicleDetail('${lmoEsc(item.vehicleNo)}')`:`openLastMileOrderDetail('${lmoEsc(item.lastMileNo)}')`,method=fromVehicle?item.deliveryMethod:'卡车派送',appointment=(item.appointmentNo||'—')+' '+(item.slot||'—');return `详情${getDispatchStatusTag(item.status)}${lmoEsc(fromVehicle?item.loadType||'海卡':'海卡')}${lmoEsc(item.dispatchNo)}${fromVehicle?'排车转派送':'尾程订单'}待配载${lmoEsc(item.warehouse)}${lmoEsc(item.plate||'—')}${lmoEsc(item.driver||'—')}${lmoEsc(item.inboundNo||'—')}——${lmoEsc(item.destFba)}${lmoEsc(appointment)}${lmoEsc(item.owner)}${fromVehicle?'USD '+Number(item.dispatchFee||0).toFixed(2):'—'}${lmoEsc(item.appointmentDate)}系统同步正常${lmoEsc(method)}${lmoEsc(item.appointmentNo||'—')}${lmoEsc(item.lastMileNo||item.vehicleNo||'—')}预约成功否编辑系统${lmoEsc(item.createdAt)}${fromVehicle?lmoEsc(item.pickupMethod||'—'):'FBA-预约'}${fromVehicle?'USD '+Number(item.estimatedDispatchFee||0).toFixed(2):'—'}${Number(item.weight||0)}${Number(item.volume||0)}${Number(item.boxes||0)}${fromVehicle?'USD '+Number(item.loadingFee||0).toFixed(2):'—'}—`;}).join(''); if(rows)tb.insertAdjacentHTML('afterbegin',rows); enhanceDispatchRows(); + renderOutboundVehicleCourierFeeRows(); +} +function getOutboundVehicleCourierFeeDetails(records){ + return (Array.isArray(records)?records:[]).filter(item=>item&&item.source==='outboundVehicle'&&item.deliveryMethod==='快递'&&item.dispatchFee!==''&&item.dispatchFee!==null&&item.dispatchFee!==undefined&&Number.isFinite(Number(item.dispatchFee))&&Number(item.dispatchFee)>=0).map(item=>({dispatchNo:String(item.dispatchNo||''),company:String(item.courierCompanyName||''),businessDate:String(item.appointmentDate||''),currency:'USD',amount:Number(item.dispatchFee)})); +} +function renderOutboundVehicleCourierFeeRows(){ + const tbody=document.getElementById('tbody-dispatch-fee');if(!tbody)return; + tbody.querySelectorAll('[data-generated-courier-fee]').forEach(row=>row.remove()); + getOutboundVehicleCourierFeeDetails(lastMileDispatchData).forEach(detail=>{ + const row=document.createElement('tr');row.setAttribute('data-generated-courier-fee',detail.dispatchNo); + const values=['编辑','待审核','应付',detail.company||'—',detail.dispatchNo,detail.businessDate,'快递费',detail.currency,detail.amount.toFixed(2),'是','排车转派送自动生成','—','—']; + values.forEach((value,index)=>{const cell=document.createElement('td');if(index===0){const link=document.createElement('a');link.href='javascript:void(0)';link.style.cssText='color:#3b82f6;font-size:12px';link.textContent=value;cell.appendChild(link);}else if(index===1){const tag=document.createElement('span');tag.className='tag tag-orange';tag.textContent=value;cell.appendChild(tag);}else{cell.textContent=value;if(index===4)cell.style.cssText='color:#3b82f6;font-weight:500';}row.appendChild(cell);}); + tbody.appendChild(row); + }); + const total=document.getElementById('dispatch-fee-total');if(total)total.textContent='共 '+tbody.querySelectorAll('tr').length+' 条'; +} +function openOutboundVehicleDelivery(deliveryNo){ + const record=lastMileDispatchData.find(item=>item.dispatchNo===deliveryNo);if(!record){showToast('未找到派送单 '+deliveryNo,'error');return;} + switchPage('outbound-dispatch');renderLastMileDispatchRows(); + const row=Array.from(document.querySelectorAll('#tbody-outbound-dispatch tr[data-last-mile-dispatch]')).find(item=>item.getAttribute('data-last-mile-dispatch')===deliveryNo); + if(row){row.classList.remove('dispatch-row-located');void row.offsetWidth;row.classList.add('dispatch-row-located');row.scrollIntoView({block:'center',inline:'nearest'});} + showToast('已定位派送单 '+deliveryNo,'success'); } /* ===== FBA退货 - 入库单 ===== */ @@ -6841,7 +8094,7 @@ function renderFbaInboundOrder(list){ ${d.status} ${lmoEsc(d.appointmentStatus||'未预约')} ${lmoEsc(d.scheduleStatus||'未排车')} - 查看   编辑 + 查看   编辑 `).join(''); const pg=document.getElementById('fbio-total'); if(pg)pg.textContent='共 '+data.length+' 条'; @@ -6874,14 +8127,28 @@ function validateFbioBatchWarehouse(records){ function openFbioBatchAppointment(){ const records=getSelectedFbioInboundOrders(),error=validateFbioBatchWarehouse(records);if(error){showToast(error,'error');return;} document.getElementById('fbio-appointment-summary').textContent='已选择 '+records.length+' 条,FBA仓库:'+getFbioFbaWarehouse(records[0]); - document.getElementById('fbio-appointment-no').value='';document.getElementById('fbio-appointment-date').value='';document.getElementById('fbio-appointment-status').value='预约成功';document.getElementById('fbio-appointment-remark').value='';showModal('modal-fbio-appointment'); + document.getElementById('fbio-appointment-no').value='';document.getElementById('fbio-appointment-date').value='';document.getElementById('fbio-appointment-loading-time').value='';document.getElementById('fbio-appointment-status').value='预约成功';document.getElementById('fbio-appointment-remark').value='';showModal('modal-fbio-appointment'); } function saveFbioBatchAppointment(){ const records=getSelectedFbioInboundOrders(),error=validateFbioBatchWarehouse(records);if(error){hideModal('modal-fbio-appointment');showToast(error,'error');return;} - const no=document.getElementById('fbio-appointment-no').value.trim(),date=document.getElementById('fbio-appointment-date').value,status=document.getElementById('fbio-appointment-status').value,remark=document.getElementById('fbio-appointment-remark').value.trim();if(!no||!date){showToast('请填写预约号和预约日期','error');return;} - const now=lmoNow();records.forEach(record=>{record.fbaWarehouse=getFbioFbaWarehouse(record);record.appointmentNo=no;record.appointmentDate=date;record.appointmentStatus=status;record.appointmentRemark=remark;record.appointmentUpdatedAt=now;const linked=lastMileOrderData.find(order=>order.inboundNo===record.inboundNo);if(linked){linked.appointment={...(linked.appointment||{}),no,date,status,remark,createdAt:now};linked.logs.push({time:now,node:'入库单FBA预约',operator:'张经理',result:status+',关联入库单 '+record.inboundNo});refreshLastMileViews(linked);}}); + const no=document.getElementById('fbio-appointment-no').value.trim(),date=document.getElementById('fbio-appointment-date').value,estimatedLoadingTime=document.getElementById('fbio-appointment-loading-time').value,status=document.getElementById('fbio-appointment-status').value,remark=document.getElementById('fbio-appointment-remark').value.trim();if(!no||!date||!estimatedLoadingTime){showToast('请填写预约号、预约送仓时间和预计装车时间','error');return;} + const now=lmoNow();records.forEach(record=>{record.fbaWarehouse=getFbioFbaWarehouse(record);record.appointmentNo=no;record.appointmentDate=date;record.estimatedLoadingTime=estimatedLoadingTime;record.appointmentStatus=status;record.appointmentRemark=remark;record.appointmentUpdatedAt=now;const linked=lastMileOrderData.find(order=>order.inboundNo===record.inboundNo);if(linked){linked.appointment={...(linked.appointment||{}),no,date,estimatedLoadingTime,status,remark,createdAt:now};linked.logs.push({time:now,node:'入库单FBA预约',operator:'张经理',result:status+',关联入库单 '+record.inboundNo});refreshLastMileViews(linked);}const dispatch=dispatchOrders.find(order=>order.orderNo===record.inboundNo);if(dispatch){dispatch.appointmentDate=date;dispatch.estimatedLoadingTime=estimatedLoadingTime;}}); hideModal('modal-fbio-appointment');renderFbaInboundOrder();showToast('已完成 '+records.length+' 条 FBA 预约','success'); } + +function getFbioEditElement(id){return document.getElementById(id);} +function setFbioEditValue(id,value){const el=getFbioEditElement(id);if(el)el.value=value==null?'':String(value);} +function openFbioEditModal(inboundNo){ + const record=fbaInboundOrderData.find(item=>item.inboundNo===inboundNo);if(!record){showToast('未找到入库单记录','error');return;} + setFbioEditValue('fbio-edit-inbound-no',record.inboundNo);setFbioEditValue('fbio-edit-warehouse-code',record.warehouseCode);setFbioEditValue('fbio-edit-type',record.type);setFbioEditValue('fbio-edit-wh',record.wh);setFbioEditValue('fbio-edit-fba-warehouse',getFbioFbaWarehouse(record));setFbioEditValue('fbio-edit-owner',record.owner);setFbioEditValue('fbio-edit-total-boxes',record.totalBoxes);setFbioEditValue('fbio-edit-charge-vol',record.chargeVol);setFbioEditValue('fbio-edit-pallet-total',record.palletTotal);setFbioEditValue('fbio-edit-status',record.status);setFbioEditValue('fbio-edit-appointment-date',record.appointmentDate);setFbioEditValue('fbio-edit-loading-time',record.estimatedLoadingTime);showModal('modal-fbio-edit'); +} +function saveFbioEdit(){ + const inboundNo=(getFbioEditElement('fbio-edit-inbound-no')||{}).value,record=fbaInboundOrderData.find(item=>item.inboundNo===inboundNo);if(!record){showToast('未找到入库单记录','error');return;} + const warehouseCode=(getFbioEditElement('fbio-edit-warehouse-code')||{}).value.trim(),type=(getFbioEditElement('fbio-edit-type')||{}).value,wh=(getFbioEditElement('fbio-edit-wh')||{}).value,fbaWarehouse=(getFbioEditElement('fbio-edit-fba-warehouse')||{}).value,owner=(getFbioEditElement('fbio-edit-owner')||{}).value.trim(),totalBoxes=Number((getFbioEditElement('fbio-edit-total-boxes')||{}).value),chargeVol=Number((getFbioEditElement('fbio-edit-charge-vol')||{}).value),palletTotal=Number((getFbioEditElement('fbio-edit-pallet-total')||{}).value),status=(getFbioEditElement('fbio-edit-status')||{}).value,appointmentDate=(getFbioEditElement('fbio-edit-appointment-date')||{}).value,estimatedLoadingTime=(getFbioEditElement('fbio-edit-loading-time')||{}).value; + if(!warehouseCode||!type||!wh||!fbaWarehouse||!owner){showToast('请完整填写入库单基础信息','error');return;}if(!Number.isInteger(totalBoxes)||totalBoxes<0||!Number.isInteger(palletTotal)||palletTotal<0||!Number.isFinite(chargeVol)||chargeVol<0){showToast('箱数、托盘数需为非负整数,计费体积需为非负数','error');return;} + Object.assign(record,{warehouseCode,type,wh,fbaWarehouse,owner,totalBoxes,chargeVol,palletTotal,status,appointmentDate,estimatedLoadingTime,updatedAt:lmoNow()});const dispatch=dispatchOrders.find(order=>order.orderNo===record.inboundNo);if(dispatch){dispatch.appointmentDate=appointmentDate;dispatch.estimatedLoadingTime=estimatedLoadingTime;dispatch.pallets=palletTotal;dispatch.vol=chargeVol;dispatch.destFba=fbaWarehouse.replace('FBA ','');} + hideModal('modal-fbio-edit');renderFbaInboundOrder();showToast('入库单 '+inboundNo+' 已更新','success'); +} function openFbioBatchSchedule(){ const records=getSelectedFbioInboundOrders(),error=validateFbioBatchWarehouse(records);if(error){showToast(error,'error');return;} if(records.some(record=>record.appointmentStatus!=='预约成功')){showToast('排车前必须预约成功','error');return;} @@ -6936,57 +8203,78 @@ function nextFbaRelabelOrderNo(dateValue,orders){ function formatFbaRelabelFee(value){ if(value===''||value===null||value===undefined)return '-'; const amount=Number(value); - return Number.isFinite(amount)?'¥'+amount.toFixed(2):'-'; + return Number.isFinite(amount)?'$'+amount.toFixed(2):String(value); +} +function calculateFbaRelabelFeeTotal(fees){ + return ['openBoxFee','pickingFee','relabelFee','cartonMarkFee'].reduce((total,key)=>{ + const amount=Number(fees&&fees[key]); + return total+(Number.isFinite(amount)?amount:0); + },0); } function buildFbaRelabelRecord(form,current,nowValue,orders){ - const allowed={relatedOrderNo:form.relatedOrderNo,sku:form.sku,cnName:form.cnName,boxes:Number(form.boxes),labelReq:form.labelReq,file:form.file||'',status:form.status||'待处理',remark:form.remark||''}; - if(current)return Object.assign({},current,allowed,{updatedAt:nowValue}); + const allowed={relatedOrderNo:form.relatedOrderNo,sku:form.sku,cnName:form.cnName,boxes:Number(form.boxes),budgetTotal:Number(form.budgetTotal),labelReq:form.labelReq,file:form.file||'',status:form.status||'待处理',remark:form.remark||''}; + if(current){ + const fees=Object.assign({},current.fees||{}); + if(form.relabelCost!==''&&form.relabelCost!==null&&form.relabelCost!==undefined)fees.relabelCost=Number(form.relabelCost);else delete fees.relabelCost; + return Object.assign({},current,allowed,{fees,updatedAt:nowValue}); + } const day=String(nowValue||'').slice(0,10); return Object.assign({orderNo:nextFbaRelabelOrderNo(day,orders),createdAt:nowValue,updatedAt:nowValue,fees:{}},allowed,{status:'待处理'}); } function resetFbaRelabelForm(){ - ['fbro-form-related-order','fbro-form-sku','fbro-form-cn-name','fbro-form-boxes','fbro-form-remark'].forEach(id=>{const element=document.getElementById(id);if(element)element.value='';}); + ['fbro-form-related-order','fbro-form-sku','fbro-form-cn-name','fbro-form-boxes','fbro-form-budget-total','fbro-form-remark'].forEach(id=>{const element=document.getElementById(id);if(element)element.value='';}); const file=document.getElementById('fbro-form-file');if(file){file.value='';file.dataset.currentFile='';} document.getElementById('fbro-form-label-req').value=''; document.getElementById('fbro-form-status').value='待处理'; + document.getElementById('fbro-form-relabel-cost').value=''; } function openFbaRelabelCreate(){ fbroEditingOrderNo='';resetFbaRelabelForm(); document.getElementById('fbro-form-title').textContent='新增换标单'; document.getElementById('fbro-form-order-no').value='系统自动生成'; document.getElementById('fbro-form-status').disabled=true; + document.getElementById('fbro-form-cost-row').style.display='none'; + document.getElementById('fbro-form-submit').textContent='保存换标单'; showModal('modal-fba-relabel-form'); } function openFbaRelabelEdit(orderNo){ const record=fbaRelabelOrderData.find(item=>item.orderNo===orderNo); if(!record){showToast('未找到换标单记录','error');return false;} fbroEditingOrderNo=record.orderNo;resetFbaRelabelForm(); - document.getElementById('fbro-form-title').textContent='编辑换标单'; + document.getElementById('fbro-form-title').textContent='审核换标单'; document.getElementById('fbro-form-order-no').value=record.orderNo; document.getElementById('fbro-form-related-order').value=record.relatedOrderNo||''; document.getElementById('fbro-form-sku').value=record.sku||''; document.getElementById('fbro-form-cn-name').value=record.cnName||''; document.getElementById('fbro-form-boxes').value=record.boxes||''; + document.getElementById('fbro-form-budget-total').value=record.budgetTotal==null?'':record.budgetTotal; document.getElementById('fbro-form-label-req').value=record.labelReq||''; document.getElementById('fbro-form-status').disabled=false; document.getElementById('fbro-form-status').value=record.status||'待处理'; + document.getElementById('fbro-form-cost-row').style.display=''; + document.getElementById('fbro-form-relabel-cost').value=record.fees&&record.fees.relabelCost!=null?record.fees.relabelCost:''; + document.getElementById('fbro-form-submit').textContent='提交审核'; document.getElementById('fbro-form-remark').value=record.remark==='—'?'':record.remark||''; document.getElementById('fbro-form-file').dataset.currentFile=record.file||''; showModal('modal-fba-relabel-form');return true; } +function openFbaRelabelAudit(orderNo){return openFbaRelabelEdit(orderNo);} function readFbaRelabelForm(){ const fileInput=document.getElementById('fbro-form-file'); - return {relatedOrderNo:document.getElementById('fbro-form-related-order').value.trim(),sku:document.getElementById('fbro-form-sku').value.trim(),cnName:document.getElementById('fbro-form-cn-name').value.trim(),boxes:Number(document.getElementById('fbro-form-boxes').value),labelReq:document.getElementById('fbro-form-label-req').value,status:document.getElementById('fbro-form-status').value,remark:document.getElementById('fbro-form-remark').value.trim(),file:fileInput.files&&fileInput.files[0]?fileInput.files[0].name:(fileInput.dataset.currentFile||'')}; + const budgetTotalInput=document.getElementById('fbro-form-budget-total').value.trim(),relabelCostInput=document.getElementById('fbro-form-relabel-cost').value.trim(); + return {relatedOrderNo:document.getElementById('fbro-form-related-order').value.trim(),sku:document.getElementById('fbro-form-sku').value.trim(),cnName:document.getElementById('fbro-form-cn-name').value.trim(),boxes:Number(document.getElementById('fbro-form-boxes').value),budgetTotal:Number(budgetTotalInput),budgetTotalInput,labelReq:document.getElementById('fbro-form-label-req').value,status:document.getElementById('fbro-form-status').value,relabelCost:relabelCostInput===''?'':Number(relabelCostInput),remark:document.getElementById('fbro-form-remark').value.trim(),file:fileInput.files&&fileInput.files[0]?fileInput.files[0].name:(fileInput.dataset.currentFile||'')}; } function saveFbaRelabelOrder(){ const form=readFbaRelabelForm(); if(!form.relatedOrderNo||!form.sku||!form.cnName||!form.labelReq){showToast('请完整填写关联订单、商品SKU、中文品名、箱数和贴标要求','warning');return false;} if(!Number.isInteger(form.boxes)||form.boxes<=0){showToast('箱数必须为正整数','warning');return false;} + if(!form.budgetTotalInput||!Number.isFinite(form.budgetTotal)||form.budgetTotal<0){showToast('预算总价必须为非负数字','warning');return false;} + if(form.relabelCost!==''&&(!Number.isFinite(form.relabelCost)||form.relabelCost<0)){showToast('预算报价必须为非负数字','warning');return false;} const current=fbroEditingOrderNo?fbaRelabelOrderData.find(item=>item.orderNo===fbroEditingOrderNo):null; if(fbroEditingOrderNo&&!current){showToast('未找到换标单记录','error');return false;} const now=fbroNowParts(new Date()).time,record=buildFbaRelabelRecord(form,current,now,fbaRelabelOrderData); if(current)fbaRelabelOrderData.splice(fbaRelabelOrderData.indexOf(current),1,record);else fbaRelabelOrderData.unshift(record); - hideModal('modal-fba-relabel-form');fbroApplyCurrentSearch();showToast(current?'换标单编辑成功':'换标单新增成功','success');return true; + hideModal('modal-fba-relabel-form');fbroApplyCurrentSearch();showToast(current?'换标单审核成功':'换标单新增成功','success');return true; } function renderFbaRelabelOrder(list){ const data=list||fbaRelabelOrderData; @@ -6997,10 +8285,11 @@ function renderFbaRelabelOrder(list){ ${lmoEsc(d.sku)} ${lmoEsc(d.cnName)} ${lmoEsc(d.boxes)} + ${formatFbaRelabelFee(d.budgetTotal)} ${lmoEsc(d.labelReq)} ${d.file?lmoEsc(d.file):'—'} ${lmoEsc(d.status)} - 查看   编辑 + 查看   审核 `).join(''); const pg=document.getElementById('fbro-total'); if(pg)pg.textContent='共 '+data.length+' 条'; @@ -7027,12 +8316,86 @@ function fbroReset(){ showToast('已重置','info'); } document.addEventListener('click',event=>{ - const view=event.target.closest('[data-fbro-view-order]'),edit=event.target.closest('[data-fbro-edit-order]'); + const view=event.target.closest('[data-fbro-view-order]'),audit=event.target.closest('[data-fbro-audit-order]'); if(view){event.preventDefault();openFbaRelabelOrderDetail(view.dataset.fbroViewOrder);} - if(edit){event.preventDefault();openFbaRelabelEdit(edit.dataset.fbroEditOrder);} + if(audit){event.preventDefault();openFbaRelabelAudit(audit.dataset.fbroAuditOrder);} }); /* ===== FBA退货 - 出库单 ===== */ +let currentFbaOutboundEditNo=''; +let currentFbaOutboundEditState=null; +let currentFbaOutboundCancelNo=''; + +function getFbaOutboundStockRows(order,stockData){ + if(Array.isArray(order.items)&&order.items.length){ + const rows=order.items.map(item=>{ + let index=Number.isInteger(item.stockIndex)?item.stockIndex:-1; + if(index<0||!stockData[index]||stockData[index].sku!==item.sku){ + const matches=stockData.map((stock,stockIndex)=>({stock,stockIndex})).filter(candidate=>candidate.stock.sku===item.sku&&(!item.warehouse||candidate.stock.wh===item.warehouse)); + index=matches.length===1?matches[0].stockIndex:-1; + } + return {index,quantity:Number(item.quantity)||0}; + }); + return rows.some(item=>item.index<0||!stockData[item.index])?null:rows; + } + const matches=stockData.map((stock,index)=>({stock,index})).filter(candidate=>candidate.stock.sku===order.sku); + return matches.length===1?[{index:matches[0].index,quantity:Number(order.totalQty)||0}]:null; +} +function getFbaOutboundEditableRows(order){ + return getFbaOutboundStockRows(order,warehouseStockData); +} +function prepareFbaOutboundCancellation(order,stockData,reason,nowValue){ + if(!order)return {ok:false,message:'未找到出库单记录'}; + if(order.status!=='待发货')return {ok:false,message:'仅待发货出库单可取消'}; + const normalizedReason=String(reason||'').trim(); + if(!normalizedReason)return {ok:false,message:'请填写取消原因'}; + const rows=getFbaOutboundStockRows(order,stockData); + if(!rows||!rows.length)return {ok:false,message:'库存返还校验失败,请刷新后重试'}; + const returnedByIndex={}; + for(const row of rows){ + if(!Number.isInteger(row.index)||!stockData[row.index]||!Number.isFinite(row.quantity)||row.quantity<=0)return {ok:false,message:'库存返还校验失败,请刷新后重试'}; + returnedByIndex[row.index]=(returnedByIndex[row.index]||0)+row.quantity; + } + const stockUpdates={}; + for(const index of Object.keys(returnedByIndex)){ + const next=Number(stockData[index].availQty)+returnedByIndex[index]; + if(!Number.isFinite(next))return {ok:false,message:'库存返还校验失败,请刷新后重试'}; + stockUpdates[index]=next; + } + return {ok:true,stockUpdates,orderChanges:{status:'已取消',cancelReason:normalizedReason,cancelledAt:nowValue,updatedAt:nowValue}}; +} +function openFbaOutboundCancellation(no){ + const order=fbaOutboundOrderData.find(item=>item.outboundNo===no); + if(!order){showToast('未找到出库单记录','error');return false;} + if(order.status!=='待发货'){showToast('仅待发货出库单可取消','warning');return false;} + currentFbaOutboundCancelNo=no; + document.getElementById('fboo-cancel-no').value=no; + document.getElementById('fboo-cancel-summary').textContent=`出库单 ${order.outboundNo} · ${order.sku||'—'} · 出库数量 ${order.totalQty||0}`; + document.getElementById('fboo-cancel-reason').value=''; + showModal('modal-fboo-cancel'); + return true; +} +function confirmFbaOutboundCancellation(){ + const no=currentFbaOutboundCancelNo||document.getElementById('fboo-cancel-no').value; + const order=fbaOutboundOrderData.find(item=>item.outboundNo===no); + const reason=document.getElementById('fboo-cancel-reason').value; + const plan=prepareFbaOutboundCancellation(order,warehouseStockData,reason,fbroNowParts(new Date()).time); + if(!plan.ok){showToast(plan.message,plan.message==='未找到出库单记录'||plan.message.includes('库存')?'error':'warning');return false;} + Object.keys(plan.stockUpdates).forEach(index=>{warehouseStockData[index].availQty=plan.stockUpdates[index];}); + Object.assign(order,plan.orderChanges); + hideModal('modal-fboo-cancel'); + currentFbaOutboundCancelNo=''; + fbooApplyCurrentSearch(); + showToast('出库单 '+order.outboundNo+' 已取消,库存已返还','success'); + return true; +} +function fbooEditInventoryLimit(index,originalByIndex){ + // 编辑上限为当前可用库存加本单原占用量,保存时再按新旧差额更新。 + return (Number(warehouseStockData[index]&&warehouseStockData[index].availQty)||0)+(Number(originalByIndex[index])||0); +} +function fbooDestinationConfig(type){ + return {一件代发:['收件信息','请输入收件人、电话和地址'],头程:['目的信息','请输入目的仓或入仓码'],派送:['派送信息','请输入FBA仓库或派送地址'],自提单:['自提信息','请输入自提人、联系电话或自提备注']}[type]||['目的信息','请输入目的信息']; +} function openFbaOutboundCreate(){ document.getElementById('fboo-create-type').value='一件代发'; document.getElementById('fboo-create-destination').value=''; @@ -7041,8 +8404,7 @@ function openFbaOutboundCreate(){ } function updateFbaOutboundDestinationHint(){ const type=document.getElementById('fboo-create-type').value,input=document.getElementById('fboo-create-destination'),label=document.getElementById('fboo-destination-label'); - const config={一件代发:['收件信息','请输入收件人、电话和地址'],头程:['目的信息','请输入目的仓或入仓码'],派送:['派送信息','请输入FBA仓库或派送地址'],自提单:['自提信息','请输入自提人、联系电话或自提备注']}; - const item=config[type];label.textContent=(item?item[0]:'目的信息')+' *';input.disabled=!item;input.placeholder=item?item[1]:'请先选择出库类型';if(!item)input.value=''; + const item=fbooDestinationConfig(type);label.textContent=item[0]+' *';input.disabled=false;input.placeholder=item[1]; } function renderFbaOutboundInventory(){ const tb=document.getElementById('tbody-fboo-create-inventory');if(!tb)return; @@ -7057,48 +8419,125 @@ function updateFbaOutboundSummary(){ document.querySelectorAll('#tbody-fboo-create-inventory input[type="checkbox"]:checked').forEach(checkbox=>{count++;const input=document.querySelector(`[data-fboo-qty="${checkbox.dataset.fbooIndex}"]`);total+=Number(input&&input.value)||0;}); document.getElementById('fboo-selected-count').textContent=count;document.getElementById('fboo-selected-qty').textContent=total; } +function getFbaOutboundLineMetrics(stock,quantity){ + const product=fbaProductData.find(item=>item.sku===stock.sku),baseQty=Number(stock.actualStock||stock.availQty)||0; + const perBox=Math.max(1,Math.round(baseQty/(Number(stock.boxes)||1))),perPallet=Math.max(1,Math.round(baseQty/(Number(stock.pallets)||1))); + const unitVolume=product?Number(product.len||0)*Number(product.wid||0)*Number(product.height||0)/1000000:0; + const skuCode=String(stock.sku||'SKU').replace(/^SKU-/,''); + return {boxes:Math.max(1,Math.ceil(quantity/perBox)),pallets:Math.max(1,Math.ceil(quantity/perPallet)),weight:Number((quantity*Number(product&&product.weight||0)).toFixed(2)),volume:Number((quantity*unitVolume).toFixed(3)),palletNo:stock.palletNo||'PAL-'+skuCode+'-01',inboundCode:stock.inboundCode||'IC-'+skuCode}; +} +function summarizeFbaOutboundItems(items){ + const owners=[...new Set(items.map(item=>item.owner||item.stock&&item.stock.owner).filter(Boolean))]; + return {owner:owners.length===1?owners[0]:owners.length?owners.length+'个货主':'—',skuCount:items.length,palletTotal:items.reduce((sum,item)=>sum+Number(item.pallets||0),0),totalQty:items.reduce((sum,item)=>sum+Number(item.quantity||0),0),boxes:items.reduce((sum,item)=>sum+Number(item.boxes||0),0),netWt:Number(items.reduce((sum,item)=>sum+Number(item.weight||0),0).toFixed(2)),volume:Number(items.reduce((sum,item)=>sum+Number(item.volume||0),0).toFixed(3))}; +} function saveFbaOutboundOrder(){ const type=document.getElementById('fboo-create-type').value,destination=document.getElementById('fboo-create-destination').value.trim(),remark=document.getElementById('fboo-create-remark').value.trim(); if(!type){showToast('请选择出库类型','error');return;}if(!destination){showToast('请填写目的信息','error');return;} const items=[];let invalid=''; document.querySelectorAll('#tbody-fboo-create-inventory input[type="checkbox"]:checked').forEach(checkbox=>{const index=Number(checkbox.dataset.fbooIndex),stock=warehouseStockData[index],input=document.querySelector(`[data-fboo-qty="${index}"]`),quantity=Number(input&&input.value),available=Number(stock&&stock.availQty)||0;if(!Number.isInteger(quantity)||quantity<1)invalid='请输入有效的出库数量';else if(quantity > available)invalid=`${stock.sku} 的出库数量不能超过可用库存 ${available}`;else items.push({index,stock,quantity});}); if(invalid){showToast(invalid,'error');return;}if(!items.length){showToast('请至少选择一个出库商品','error');return;} - let totalQty=0,totalBoxes=0,totalWeight=0;items.forEach(item=>{const stock=item.stock,product=fbaProductData.find(productItem=>productItem.sku===stock.sku),perBox=Math.max(1,Math.round((stock.actualStock||stock.availQty)/(stock.boxes||1)));item.boxes=Math.max(1,Math.ceil(item.quantity/perBox));totalQty+=item.quantity;totalBoxes+=item.boxes;totalWeight+=item.quantity*Number(product&&product.weight||0);warehouseStockData[item.index].availQty -= item.quantity;}); + items.forEach(item=>{Object.assign(item,getFbaOutboundLineMetrics(item.stock,item.quantity));warehouseStockData[item.index].availQty -= item.quantity;}); + const summary=summarizeFbaOutboundItems(items); const first=items[0].stock,outboundNo='FBOO'+new Date().toISOString().slice(0,10).replace(/-/g,'')+String(fbaOutboundOrderData.length+1).padStart(3,'0'); - fbaOutboundOrderData.unshift({outboundNo,outboundType:type,destWh:destination,sku:items.length===1?first.sku:`${items.length}个SKU`,cnName:items.length===1?first.cnName:`${first.cnName}等${items.length}项`,totalQty,boxes:totalBoxes,netWt:Number(totalWeight.toFixed(2)),status:'待发货',remark,items:items.map(item=>({sku:item.stock.sku,cnName:item.stock.cnName,warehouse:item.stock.wh,quantity:item.quantity,boxes:item.boxes}))}); + fbaOutboundOrderData.unshift({outboundNo,outboundType:type,destWh:destination,owner:summary.owner,sku:items.length===1?first.sku:`${items.length}个SKU`,cnName:items.length===1?first.cnName:`${first.cnName}等${items.length}项`,skuCount:summary.skuCount,palletTotal:summary.palletTotal,totalQty:summary.totalQty,boxes:summary.boxes,netWt:summary.netWt,volume:summary.volume,status:'待发货',remark,fees:createFbaOutboundReceivableFees(),items:items.map(item=>({stockIndex:item.index,owner:item.stock.owner,sku:item.stock.sku,cnName:item.stock.cnName,warehouse:item.stock.wh,quantity:item.quantity,boxes:item.boxes,pallets:item.pallets,weight:item.weight,volume:item.volume,palletNo:item.palletNo,inboundCode:item.inboundCode}))}); hideModal('modal-fboo-create');renderFbaOutboundOrder();showToast('出库单 '+outboundNo+' 已创建','success'); } +function renderFbaOutboundEditInventory(state){ + const tb=document.getElementById('tbody-fboo-edit-inventory');if(!tb)return; + const originalByIndex=state&&state.originalByIndex||{}; + tb.innerHTML=warehouseStockData.map((item,index)=>{ + const original=Number(originalByIndex[index])||0,limit=fbooEditInventoryLimit(index,originalByIndex),checked=Object.prototype.hasOwnProperty.call(originalByIndex,index); + return `${lmoEsc(item.sku)}${lmoEsc(item.cnName)}LOT-${lmoEsc(item.sku.replace('SKU-',''))}-2608PAL-${lmoEsc(item.sku.replace('SKU-',''))}-01${lmoEsc(item.wh)}${limit}`; + }).join('')||'暂无可出库商品'; + updateFbaOutboundEditSummary(); +} +function toggleFbaOutboundEditItem(index,checkbox){ + const input=document.querySelector(`[data-fboo-edit-qty="${index}"]`);if(!input)return; + input.disabled=!checkbox.checked;input.value=checkbox.checked?'1':'';updateFbaOutboundEditSummary();if(checkbox.checked)input.focus(); +} +function updateFbaOutboundEditSummary(){ + let count=0,total=0; + document.querySelectorAll('#tbody-fboo-edit-inventory input[type="checkbox"]:checked').forEach(checkbox=>{count++;const input=document.querySelector(`[data-fboo-edit-qty="${checkbox.dataset.fbooEditIndex}"]`);total+=Number(input&&input.value)||0;}); + const countEl=document.getElementById('fboo-edit-selected-count'),qtyEl=document.getElementById('fboo-edit-selected-qty');if(countEl)countEl.textContent=count;if(qtyEl)qtyEl.textContent=total; +} +function openFbaOutboundEdit(no){ + const order=fbaOutboundOrderData.find(item=>item.outboundNo===no); + if(!order){showToast('未找到出库单记录','error');return;} + if(order.status!=='待发货'){showToast('仅待发货出库单可编辑','warning');return;} + const rows=getFbaOutboundEditableRows(order),originalByIndex={}; + if(rows)rows.forEach(item=>{originalByIndex[item.index]=(Number(originalByIndex[item.index])||0)+item.quantity;}); + currentFbaOutboundEditNo=no;currentFbaOutboundEditState={valid:!!rows,originalByIndex}; + document.getElementById('fboo-edit-no').value=order.outboundNo; + document.getElementById('fboo-edit-type').value=order.outboundType||'头程'; + document.getElementById('fboo-edit-destination').value=order.destWh||''; + document.getElementById('fboo-edit-remark').value=order.remark==='—'?'':order.remark||''; + const destination=fbooDestinationConfig(order.outboundType),note=document.getElementById('fboo-edit-note'),save=document.getElementById('fboo-edit-save'); + document.getElementById('fboo-edit-destination-label').textContent=destination[0]+' *';document.getElementById('fboo-edit-destination').placeholder=destination[1]; + note.textContent=rows?'原商品数量会先释放,再按本次编辑结果重新占用库存。':'该出库单缺少库存关联,无法保存。';note.classList.toggle('is-error',!rows);save.disabled=!rows; + renderFbaOutboundEditInventory(currentFbaOutboundEditState);showModal('modal-fboo-edit'); + const editModal=document.querySelector('#modal-fboo-edit .modal');if(editModal)editModal.scrollTop=0; +} +function saveFbaOutboundEdit(){ + const order=fbaOutboundOrderData.find(item=>item.outboundNo===currentFbaOutboundEditNo),state=currentFbaOutboundEditState; + if(!order){showToast('未找到出库单记录','error');return;} + if(order.status!=='待发货'){showToast('仅待发货出库单可编辑','warning');return;} + if(!state||!state.valid){showToast('该出库单缺少库存关联,无法保存','error');return;} + const destination=document.getElementById('fboo-edit-destination').value.trim(),remark=document.getElementById('fboo-edit-remark').value.trim(); + if(!destination){showToast('请填写目的信息','error');return;} + const selected=[];let invalid=''; + document.querySelectorAll('#tbody-fboo-edit-inventory input[type="checkbox"]:checked').forEach(checkbox=>{ + const index=Number(checkbox.dataset.fbooEditIndex),stock=warehouseStockData[index],input=document.querySelector(`[data-fboo-edit-qty="${index}"]`),quantity=Number(input&&input.value),limit=fbooEditInventoryLimit(index,state.originalByIndex); + if(!Number.isInteger(quantity)||quantity<1)invalid='请输入有效的出库数量';else if(quantity>limit)invalid=`${stock.sku} 的出库数量不能超过本单可编辑库存 ${limit}`;else selected.push({index,stock,quantity}); + }); + if(invalid){showToast(invalid,'error');return;}if(!selected.length){showToast('请至少选择一个出库商品','error');return;} + const deltas={};Object.keys(state.originalByIndex).forEach(index=>{deltas[index]=Number(state.originalByIndex[index])||0;});selected.forEach(item=>{deltas[item.index]=(deltas[item.index]||0)-item.quantity;}); + const nextInventory={};for(const index of Object.keys(deltas)){const stock=warehouseStockData[index],next=Number(stock&&stock.availQty)+deltas[index];if(!stock||!Number.isFinite(next)||next<0){showToast('库存校验失败,请刷新后重试','error');return;}nextInventory[index]=next;} + selected.forEach(item=>Object.assign(item,getFbaOutboundLineMetrics(item.stock,item.quantity))); + const summary=summarizeFbaOutboundItems(selected); + Object.keys(nextInventory).forEach(index=>{warehouseStockData[index].availQty=nextInventory[index];}); + const first=selected[0].stock;Object.assign(order,{destWh:destination,remark,owner:summary.owner,sku:selected.length===1?first.sku:`${selected.length}个SKU`,cnName:selected.length===1?first.cnName:`${first.cnName}等${selected.length}项`,skuCount:summary.skuCount,palletTotal:summary.palletTotal,totalQty:summary.totalQty,boxes:summary.boxes,netWt:summary.netWt,volume:summary.volume,updatedAt:new Date().toLocaleString('zh-CN',{hour12:false}),items:selected.map(item=>({stockIndex:item.index,owner:item.stock.owner,sku:item.stock.sku,cnName:item.stock.cnName,warehouse:item.stock.wh,quantity:item.quantity,boxes:item.boxes,pallets:item.pallets,weight:item.weight,volume:item.volume,palletNo:item.palletNo,inboundCode:item.inboundCode}))}); + hideModal('modal-fboo-edit');currentFbaOutboundEditNo='';currentFbaOutboundEditState=null;renderFbaOutboundOrder();showToast('出库单 '+order.outboundNo+' 已保存','success'); +} +const fbaOutboundStatusTag={'待发货':'tag-orange','已发货':'tag-blue','已签收':'tag-green','已取消':'tag-gray'}; function renderFbaOutboundOrder(list){ const data=list||fbaOutboundOrderData; const tb=document.getElementById('tbody-fba-outbound-order'); if(!tb)return; - tb.innerHTML=data.map(d=>` + tb.innerHTML=data.map(d=>{const canOperate=d.status === '待发货',editAction=canOperate?`编辑`:'编辑',cancelAction=canOperate?`取消`:'取消';return ` ${d.outboundNo} ${d.outboundType||'头程'} - ${d.destWh} - ${d.transferWarehouse||'—'} - ${d.sku} - ${d.cnName} - ${d.totalQty||'—'} - ${d.boxes} - ${d.netWt} - ${d.status} - 查看   编辑 - `).join(''); + ${d.skuCount||'—'} + ${d.palletTotal||'—'} + ${d.boxes||'—'} + ${d.netWt||'—'} + ${d.volume||'—'} + ${d.status} + 查看   ${editAction}   ${cancelAction} + `;}).join(''); const pg=document.getElementById('fboo-total'); if(pg)pg.textContent='共 '+data.length+' 条'; } -function fbooSearch(){ +document.addEventListener('click',event=>{ + const cancel=event.target.closest('[data-fboo-cancel-order]'); + if(!cancel)return; + event.preventDefault(); + openFbaOutboundCancellation(cancel.dataset.fbooCancelOrder); +}); +function getFilteredFbaOutboundOrders(){ const no=(document.getElementById('fboo-no')||{}).value||''; const dest=(document.getElementById('fboo-dest')||{}).value||''; - const st=(document.getElementById('fboo-status')||{}).value||''; - const kw=s=>(''+(s||'')).toLowerCase(); - const filtered=fbaOutboundOrderData.filter(d=>{ - if(no && !kw(d.outboundNo).includes(kw(no))) return false; - if(dest && d.destWh!==dest) return false; - if(st && d.status!==st) return false; + const status=(document.getElementById('fboo-status')||{}).value||''; + const keyword=value=>String(value||'').toLowerCase(); + return fbaOutboundOrderData.filter(order=>{ + if(no&&!keyword(order.outboundNo).includes(keyword(no)))return false; + if(dest&&order.destWh!==dest)return false; + if(status&&order.status!==status)return false; return true; }); +} +function fbooApplyCurrentSearch(){renderFbaOutboundOrder(getFilteredFbaOutboundOrders());} +function fbooSearch(){ + const filtered=getFilteredFbaOutboundOrders(); renderFbaOutboundOrder(filtered); showToast('查询完成,共 '+filtered.length+' 条','success'); } @@ -7109,6 +8548,11 @@ function fbooReset(){ } /* ===== FBA退货 - 托盘管理 ===== */ +let fbaPalletEditingCode=''; +function formatFbaPalletPurchasePrice(value){ + const price=Number(value); + return Number.isFinite(price)?'$'+price.toFixed(2):'—'; +} function renderFbaPallet(list){ const data=list||fbaPalletData; const tb=document.getElementById('tbody-fba-pallet'); @@ -7116,11 +8560,14 @@ function renderFbaPallet(list){ tb.innerHTML=data.map(d=>` ${d.code} ${d.type} + ${d.warehouse||'-'} ${d.vol} + ${d.weight} + ${formatFbaPalletPurchasePrice(d.purchasePrice)} ${d.fbaWh} ${d.status} ${d.remark||'-'} - 查看   编辑 + 查看   编辑 `).join(''); const pg=document.getElementById('fbp-total'); if(pg)pg.textContent='共 '+data.length+' 条'; @@ -7128,11 +8575,13 @@ function renderFbaPallet(list){ function fbpSearch(){ const code=(document.getElementById('fbp-code')||{}).value||''; const type=(document.getElementById('fbp-type')||{}).value||''; + const wh=(document.getElementById('fbp-wh')||{}).value||''; const st=(document.getElementById('fbp-status')||{}).value||''; const kw=s=>(''+(s||'')).toLowerCase(); const filtered=fbaPalletData.filter(d=>{ if(code && !kw(d.code).includes(kw(code))) return false; if(type && d.type!==type) return false; + if(wh && d.warehouse!==wh) return false; if(st && d.status!==st) return false; return true; }); @@ -7140,48 +8589,186 @@ function fbpSearch(){ showToast('查询完成,共 '+filtered.length+' 条','success'); } function fbpReset(){ - ['fbp-code','fbp-type','fbp-status'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';}); + ['fbp-code','fbp-type','fbp-wh','fbp-status'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';}); renderFbaPallet(); showToast('已重置','info'); } +function openFbaPalletForm(code){ + const d=code?fbaPalletData.find(item=>item.code===code):null; + if(code&&!d){showToast('未找到托盘记录','error');return;} + fbaPalletEditingCode=d?d.code:''; + const set=(id,value)=>{const el=document.getElementById(id);if(el)el.value=value==null?'':value;}; + const title=document.getElementById('fbp-form-title'); + if(title)title.textContent=d?'编辑托盘':'新增托盘'; + set('fbp-form-code',d?d.code:''); + const codeInput=document.getElementById('fbp-form-code'); + if(codeInput)codeInput.readOnly=!!d; + set('fbp-form-type',d?d.type:'木托盘'); + set('fbp-form-volume',d?d.vol:''); + set('fbp-form-weight',d?d.weight:''); + set('fbp-form-price',d?d.purchasePrice:''); + set('fbp-form-overseas-warehouse',d?d.warehouse:'洛杉矶长滩海外仓'); + set('fbp-form-warehouse',d?d.fbaWh:'FBA ONT8'); + set('fbp-form-status',d?d.status:'闲置'); + set('fbp-form-remark',d?d.remark:''); + showModal('modal-fba-pallet-form'); +} +function saveFbaPalletForm(){ + const get=id=>((document.getElementById(id)||{}).value||'').trim(); + const code=get('fbp-form-code'); + const type=get('fbp-form-type'); + const volumeInput=get('fbp-form-volume'); + const weightInput=get('fbp-form-weight'); + const priceInput=get('fbp-form-price'); + const volume=Number(volumeInput); + const weight=Number(weightInput); + const purchasePrice=Number(priceInput); + const warehouse=get('fbp-form-overseas-warehouse'); + const fbaWh=get('fbp-form-warehouse'); + const status=get('fbp-form-status'); + const remark=get('fbp-form-remark'); + if(!code){showToast('请填写托盘编码','warning');return;} + if(!type){showToast('请选择托盘类型','warning');return;} + if(!volumeInput||!Number.isFinite(volume)||volume<=0){showToast('请填写大于 0 的容积(m³)','warning');return;} + if(!weightInput||!Number.isFinite(weight)||weight<=0){showToast('请输入大于0的托盘重量','warning');return;} + if(priceInput===''||!Number.isFinite(purchasePrice)||purchasePrice<0){showToast('请填写有效的采购价格','warning');return;} + if(!warehouse){showToast('请选择仓库','warning');return;} + if(!fbaWh){showToast('请选择所属 FBA 仓','warning');return;} + if(!status){showToast('请选择托盘状态','warning');return;} + const now=new Date().toISOString().slice(0,16).replace('T',' '); + const next={code,type,warehouse,vol:volume,weight,purchasePrice,fbaWh,status,remark}; + const index=fbaPalletData.findIndex(item=>item.code===fbaPalletEditingCode); + if(index>=0){ + fbaPalletData[index]={...fbaPalletData[index],...next,updatedAt:now}; + }else{ + if(fbaPalletData.some(item=>item.code===code)){showToast('托盘编码已存在','warning');return;} + fbaPalletData.unshift({...next,relatedInboundNo:'—',cartonCount:0,createdAt:now,updatedAt:now}); + } + fbaPalletEditingCode=''; + hideModal('modal-fba-pallet-form'); + renderFbaPallet(); + showToast(index>=0?'托盘已保存':'托盘已新增','success'); +} /* ===== FBA退货 - 箱号管理 ===== */ +let fbaCartonEditingNo=''; +function getFbaCartonStatus(item){ + const outbound=(''+((item||{}).relatedOutboundNo||'')).trim(); + return outbound&&outbound!=='—'?'已出库':'在库'; +} +function getFilteredFbaCartons(){ + const carton=((document.getElementById('fbc-carton')||{}).value||'').trim().toLowerCase(); + const wh=((document.getElementById('fbc-wh')||{}).value||'').trim(); + const status=((document.getElementById('fbc-status')||{}).value||'').trim(); + return fbaCartonData.filter(item=>{ + if(carton&&!item.cartonNo.toLowerCase().includes(carton))return false; + if(wh&&item.fbaWh!==wh)return false; + if(status&&getFbaCartonStatus(item)!==status)return false; + return true; + }); +} function renderFbaCarton(list){ - const data=list||fbaCartonData; + const data=list||getFilteredFbaCartons(); const tb=document.getElementById('tbody-fba-carton'); if(!tb)return; - tb.innerHTML=data.map(d=>` - ${d.cartonNo} - ${d.fbaWh} - ${d.sku} - ${d.cnName} - ${d.qty} - ${d.weight} - ${d.status} - 查看   编辑 - `).join(''); + tb.innerHTML=data.map(item=>{ + const status=getFbaCartonStatus(item); + const cartonArg=lmoEsc(JSON.stringify(item.cartonNo)); + const edit=status==='在库'?`   编辑`:''; + return ` + ${lmoEsc(item.cartonNo)} + ${lmoEsc(item.fbaWh)} + ${lmoEsc(item.sku)} + ${lmoEsc(item.cnName)} + ${item.qty} + ${item.weight} + ${status} + 查看${edit} + `; + }).join(''); const pg=document.getElementById('fbc-total'); if(pg)pg.textContent='共 '+data.length+' 条'; } function fbcSearch(){ - const carton=(document.getElementById('fbc-carton')||{}).value||''; - const wh=(document.getElementById('fbc-wh')||{}).value||''; - const st=(document.getElementById('fbc-status')||{}).value||''; - const kw=s=>(''+(s||'')).toLowerCase(); - const filtered=fbaCartonData.filter(d=>{ - if(carton && !kw(d.cartonNo).includes(kw(carton))) return false; - if(wh && d.fbaWh!==wh) return false; - if(st && d.status!==st) return false; - return true; - }); + const filtered=getFilteredFbaCartons(); renderFbaCarton(filtered); showToast('查询完成,共 '+filtered.length+' 条','success'); } function fbcReset(){ ['fbc-carton','fbc-wh','fbc-status'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';}); - renderFbaCarton(); + renderFbaCarton(getFilteredFbaCartons()); showToast('已重置','info'); } +function openFbaCartonForm(cartonNo){ + const item=cartonNo?fbaCartonData.find(entry=>entry.cartonNo===cartonNo):null; + if(cartonNo&&!item){showToast('未找到箱号记录','error');return;} + if(item&&getFbaCartonStatus(item)==='已出库'){showToast('已出库箱号不可编辑','warning');return;} + fbaCartonEditingNo=item?item.cartonNo:''; + const set=(id,value)=>{const el=document.getElementById(id);if(el)el.value=value==null?'':value;}; + const title=document.getElementById('fbc-form-title'); + const cartonInput=document.getElementById('fbc-form-carton'); + if(title)title.textContent=item?'编辑箱号':'新增箱号'; + if(cartonInput)cartonInput.readOnly=!!item; + set('fbc-form-carton',item?item.cartonNo:''); + set('fbc-form-wh',item?item.fbaWh:''); + set('fbc-form-sku',item?item.sku:''); + set('fbc-form-cn-name',item?item.cnName:''); + set('fbc-form-qty',item?item.qty:''); + set('fbc-form-weight',item?item.weight:''); + set('fbc-form-pallet',item&&item.relatedPalletNo!=='—'?item.relatedPalletNo:''); + set('fbc-form-inbound',item&&item.relatedInboundNo!=='—'?item.relatedInboundNo:''); + set('fbc-form-outbound',item?item.relatedOutboundNo||'—':'—'); + set('fbc-form-status',item?getFbaCartonStatus(item):'在库'); + set('fbc-form-remark',item&&item.remark!=='—'?item.remark:''); + showModal('modal-fba-carton-form'); +} +function saveFbaCartonForm(){ + const get=id=>((document.getElementById(id)||{}).value||'').trim(); + const editingItem=fbaCartonEditingNo?fbaCartonData.find(item=>item.cartonNo===fbaCartonEditingNo):null; + const cartonNo=editingItem?editingItem.cartonNo:get('fbc-form-carton'); + const fbaWh=get('fbc-form-wh'); + const sku=get('fbc-form-sku'); + const cnName=get('fbc-form-cn-name'); + const qtyText=get('fbc-form-qty'); + const weightText=get('fbc-form-weight'); + const relatedPalletNo=get('fbc-form-pallet')||'—'; + const relatedInboundNo=get('fbc-form-inbound')||'—'; + const remark=get('fbc-form-remark')||'—'; + if(fbaCartonEditingNo&&!editingItem){showToast('未找到箱号记录','error');return;} + if(editingItem&&getFbaCartonStatus(editingItem)==='已出库'){showToast('已出库箱号不可编辑','warning');return;} + if(!cartonNo){showToast('请输入箱号','warning');return;} + if(!fbaWh){showToast('请选择所属 FBA 仓','warning');return;} + if(!sku){showToast('请输入商品 SKU','warning');return;} + if(!cnName){showToast('请输入中文品名','warning');return;} + if(!/^\d+$/.test(qtyText)||Number(qtyText)<=0){showToast('数量必须为大于 0 的整数','warning');return;} + const weight=Number(weightText); + if(!Number.isFinite(weight)||weight<=0){showToast('重量必须为大于 0 的数字','warning');return;} + if(!editingItem&&fbaCartonData.some(item=>item.cartonNo===cartonNo)){showToast('箱号已存在','warning');return;} + const nowDate=new Date(); + const pad=value=>String(value).padStart(2,'0'); + const now=`${nowDate.getFullYear()}-${pad(nowDate.getMonth()+1)}-${pad(nowDate.getDate())} ${pad(nowDate.getHours())}:${pad(nowDate.getMinutes())}`; + if(editingItem){ + Object.assign(editingItem,{fbaWh,sku,cnName,qty:Number(qtyText),weight,relatedPalletNo,relatedInboundNo,remark,status:getFbaCartonStatus(editingItem),updatedAt:now}); + }else{ + const next={cartonNo,fbaWh,sku,cnName,qty:Number(qtyText),weight,relatedPalletNo,relatedInboundNo,relatedOutboundNo:'—',remark,createdAt:now,updatedAt:now}; + fbaCartonData.unshift({...next,status:getFbaCartonStatus(next)}); + } + fbaCartonEditingNo=''; + hideModal('modal-fba-carton-form'); + renderFbaCarton(getFilteredFbaCartons()); + showToast(editingItem?'箱号已保存':'箱号已新增','success'); +} +function exportFbaCartons(){ + const data=getFilteredFbaCartons(); + if(!data.length){showToast('暂无可导出数据','warning');return;} + const headers=['箱号','所属FBA仓','商品SKU','中文品名','数量','重量(kg)','状态','关联托盘','关联入库单','关联出库单','备注','创建时间','更新时间']; + const rows=data.map(item=>[item.cartonNo,item.fbaWh,item.sku,item.cnName,item.qty,item.weight,getFbaCartonStatus(item),item.relatedPalletNo||'—',item.relatedInboundNo||'—',item.relatedOutboundNo||'—',item.remark||'—',item.createdAt||'—',item.updatedAt||'—']); + const csv='\ufeff'+[headers,...rows].map(row=>row.map(csvEscape).join(',')).join('\r\n'); + const date=new Date(); + const pad=value=>String(value).padStart(2,'0'); + downloadCsvFile(`箱号管理-${date.getFullYear()}${pad(date.getMonth()+1)}${pad(date.getDate())}.csv`,csv); + showToast('已导出 '+data.length+' 条箱号记录','success'); +} /* ===== 海外仓五类只读详情 ===== */ function fbaDetailDisplay(value){ @@ -7206,47 +8793,81 @@ function showFbaReadOnlyDetail(pageId,headId,statusId,recordNo,status,contentId, switchPage(pageId); window.scrollTo(0,0); } +function formatFbaReceivableFee(amount){ + if(amount===null||amount===undefined||String(amount).trim()==='')return '-'; + const value=Number(amount);return Number.isFinite(value)&&value>=0?'$'+value.toFixed(2):'-'; +} +function renderFbaReceivableFees(bodyId,totalId,fees){ + const body=document.getElementById(bodyId),totalNode=document.getElementById(totalId);if(!body||!totalNode)return; + const rows=Array.isArray(fees)?fees.filter(Boolean):[]; + body.innerHTML=rows.length?rows.map((item,index)=>`${index+1}${lmoEsc(item.name||'-')}${lmoEsc(item.currency||'-')}${formatFbaReceivableFee(item.amount)}${lmoEsc(item.remark||'-')}`).join(''):'暂无应收费用明细'; + const total=rows.reduce((sum,item)=>{if(item.amount===null||item.amount===undefined||String(item.amount).trim()==='')return sum;const value=Number(item.amount);return sum+(Number.isFinite(value)&&value>=0?value:0);},0); + totalNode.textContent='$'+total.toFixed(2); +} +function renderFbaInboundFees(fees){renderFbaReceivableFees('fbd-inbound-fees','fbd-inbound-fee-total',fees);} +function renderFbaOutboundFees(fees){renderFbaReceivableFees('fbd-outbound-fees','fbd-outbound-fee-total',fees);} function openFbaInboundOrderDetail(no){ const d=fbaInboundOrderData.find(item=>item.inboundNo===no); if(!d){showToast('未找到入库单记录','error');return;} showFbaReadOnlyDetail('fba-inbound-order-detail','fbd-inbound-no','fbd-inbound-status',d.inboundNo,d.status,'fbd-inbound-content',[ {title:'单据信息',rows:[['入库单号',d.inboundNo],['入仓码',d.warehouseCode],['类型',d.type],['货主',d.owner],['关联订单',d.relatedOrderNo]]}, {title:'仓储信息',rows:[['海外仓',d.wh],['FBA仓库',getFbioFbaWarehouse(d)],['总箱数',d.totalBoxes],['计费体积(m³)',d.chargeVol],['总托盘数',d.palletTotal]]}, - {title:'预约与排车',rows:[['状态',d.status],['预约状态',d.appointmentStatus||'未预约'],['排车状态',d.scheduleStatus||'未排车'],['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]]} + {title:'预约与排车',rows:[['状态',d.status],['预约状态',d.appointmentStatus||'未预约'],['预约送仓时间',d.appointmentDate||'—'],['预计装车时间',d.estimatedLoadingTime||'—'],['排车状态',d.scheduleStatus||'未排车'],['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]]} ]); + renderFbaInboundFees(d.fees); +} +function getFbaOutboundPalletRows(item){ + const details=Array.isArray(item&&item.palletDetails)?item.palletDetails:[]; + if(details.length)return details.map(detail=>Object.assign({},item,detail)); + const count=Math.max(1,Math.floor(Number(item&&item.pallets)||1)),boxes=Number(item&&item.boxes)||0,weight=Number(item&&item.weight)||0,volume=Number(item&&item.volume)||0; + const distribute=(total,precision)=>Array.from({length:count},(_,index)=>{if(index===count-1)return Number(total.toFixed(precision));const value=Number((total/count).toFixed(precision));total-=value;return value;}); + const boxRows=distribute(boxes,0),weightRows=distribute(weight,2),volumeRows=distribute(volume,3),skuCode=String(item&&item.sku||'SKU').replace(/^SKU-/,''); + const palletBase=item&&item.palletNo||'PAL-'+skuCode+'-01',inboundCode=item&&item.inboundCode||'IC-'+skuCode; + return Array.from({length:count},(_,index)=>{const suffix=String(index+1).padStart(2,'0'),palletNo=count===1?palletBase:(/-\d+$/.test(palletBase)?palletBase.replace(/-\d+$/,'-'+suffix):palletBase+'-'+suffix);return {sku:item&&item.sku,cnName:item&&item.cnName,palletNo,inboundCode,boxes:boxRows[index],weight:weightRows[index],volume:volumeRows[index]};}); +} +function renderFbaOutboundSkuInfo(items){ + const body=document.getElementById('fbd-outbound-sku-items');if(!body)return; + const rows=(Array.isArray(items)?items:[]).flatMap(item=>getFbaOutboundPalletRows(item)); + body.innerHTML=rows.length?rows.map(item=>`${lmoEsc(fbaDetailDisplay(item.palletNo))}${lmoEsc(fbaDetailDisplay(item.inboundCode))}${lmoEsc(fbaDetailDisplay(item.boxes))}${lmoEsc(fbaDetailDisplay(item.weight))}${lmoEsc(fbaDetailDisplay(item.volume))}`).join(''):'暂无托盘信息'; } function openFbaOutboundOrderDetail(no){ const d=fbaOutboundOrderData.find(item=>item.outboundNo===no); if(!d){showToast('未找到出库单记录','error');return;} + const outboundRows=[['状态',d.status]]; + if(d.status==='已取消')outboundRows.push(['取消原因',d.cancelReason],['取消时间',d.cancelledAt]); + outboundRows.push(['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]); showFbaReadOnlyDetail('fba-outbound-order-detail','fbd-outbound-no','fbd-outbound-status',d.outboundNo,d.status,'fbd-outbound-content',[ - {title:'单据信息',rows:[['出库单号',d.outboundNo],['出库类型',d.outboundType],['目的仓',d.destWh],['转仓',d.transferWarehouse||'—'],['关联订单',d.relatedOrderNo]]}, - {title:'商品信息',rows:[['商品SKU',d.sku],['中文品名',d.cnName],['出库数量',d.totalQty],['箱数',d.boxes],['总净重(kg)',d.netWt]]}, - {title:'出库信息',rows:[['状态',d.status],['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]]} + {title:'单据信息',rows:[['出库单号',d.outboundNo],['出库类型',d.outboundType],['货主',d.owner],['目的信息',d.destWh],['关联订单',d.relatedOrderNo]]}, + {title:'出库汇总',rows:[['SKU种数',d.skuCount],['总托数',d.palletTotal],['总箱数',d.boxes],['总重量(kg)',d.netWt],['总体积(m3)',d.volume]]}, + {title:'出库信息',rows:outboundRows} ]); + renderFbaOutboundSkuInfo(d.items); + renderFbaOutboundFees(d.fees); } function openFbaRelabelOrderDetail(no){ const d=fbaRelabelOrderData.find(item=>item.orderNo===no); if(!d){showToast('未找到换标单记录','error');return;} showFbaReadOnlyDetail('fba-relabel-order-detail','fbd-relabel-no','fbd-relabel-status',d.orderNo,d.status,'fbd-relabel-content',[ {title:'单据信息',rows:[['换标单号',d.orderNo],['关联订单',d.relatedOrderNo],['状态',d.status],['创建时间',d.createdAt],['更新时间',d.updatedAt]]}, - {title:'商品信息',rows:[['商品SKU',d.sku],['中文品名',d.cnName],['箱数',d.boxes]]}, + {title:'商品信息',rows:[['商品SKU',d.sku],['中文品名',d.cnName],['箱数',d.boxes],['预算总价',formatFbaRelabelFee(d.budgetTotal)]]}, {title:'作业要求',rows:[['贴标要求',d.labelReq],['上传文件',d.file],['备注',d.remark]]}, - {title:'费用明细',rows:[['开箱费',formatFbaRelabelFee(d.fees&&d.fees.openBoxFee)],['挑货费',formatFbaRelabelFee(d.fees&&d.fees.pickingFee)],['换标费',formatFbaRelabelFee(d.fees&&d.fees.relabelFee)],['换箱唛标费',formatFbaRelabelFee(d.fees&&d.fees.cartonMarkFee)]]} + {title:'费用明细',rows:[['开箱费',formatFbaRelabelFee(d.fees&&d.fees.openBoxFee)],['挑货费',formatFbaRelabelFee(d.fees&&d.fees.pickingFee)],['换标费',formatFbaRelabelFee(d.fees&&d.fees.relabelFee)],['换箱唛标费',formatFbaRelabelFee(d.fees&&d.fees.cartonMarkFee)],['换标费总计',formatFbaRelabelFee(calculateFbaRelabelFeeTotal(d.fees))]]} ]); } function openFbaPalletDetail(code){ const d=fbaPalletData.find(item=>item.code===code); if(!d){showToast('未找到托盘记录','error');return;} showFbaReadOnlyDetail('fba-pallet-detail','fbd-pallet-no','fbd-pallet-status',d.code,d.status,'fbd-pallet-content',[ - {title:'基础信息',rows:[['托盘编码',d.code],['托盘类型',d.type],['容积(m³)',d.vol],['所属FBA仓',d.fbaWh],['状态',d.status]]}, + {title:'基础信息',rows:[['托盘编码',d.code],['托盘类型',d.type],['仓库',d.warehouse||'—'],['容积(m³)',d.vol],['采购价格',formatFbaPalletPurchasePrice(d.purchasePrice)],['所属FBA仓',d.fbaWh],['状态',d.status]]}, {title:'使用信息',rows:[['关联入库单',d.relatedInboundNo],['关联箱数',d.cartonCount],['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]]} ]); } function openFbaCartonDetail(no){ const d=fbaCartonData.find(item=>item.cartonNo===no); if(!d){showToast('未找到箱号记录','error');return;} - showFbaReadOnlyDetail('fba-carton-detail','fbd-carton-no','fbd-carton-status',d.cartonNo,d.status,'fbd-carton-content',[ - {title:'基础信息',rows:[['箱号',d.cartonNo],['所属FBA仓',d.fbaWh],['状态',d.status],['关联托盘',d.relatedPalletNo],['关联入库单',d.relatedInboundNo],['关联出库单',d.relatedOutboundNo]]}, + const status=getFbaCartonStatus(d); + showFbaReadOnlyDetail('fba-carton-detail','fbd-carton-no','fbd-carton-status',d.cartonNo,status,'fbd-carton-content',[ + {title:'基础信息',rows:[['箱号',d.cartonNo],['所属FBA仓',d.fbaWh],['状态',status],['关联托盘',d.relatedPalletNo],['关联入库单',d.relatedInboundNo],['关联出库单',d.relatedOutboundNo]]}, {title:'商品信息',rows:[['商品SKU',d.sku],['中文品名',d.cnName],['数量',d.qty],['重量(kg)',d.weight],['创建时间',d.createdAt],['更新时间',d.updatedAt],['备注',d.remark]]} ]); } @@ -7644,121 +9265,109 @@ function switchDomesticStockTab(tab,el){ if(tab==='hold')renderDomesticHoldStock(); if(tab==='purchase')renderDomesticPurchaseStock(); } +const domesticLocationData=[ + {code:'A1',wh:'上海外高桥仓',zone:'常规货',type:'货架位',maxWeight:500,status:'占用',remark:''}, + {code:'A2',wh:'上海外高桥仓',zone:'一件代发',type:'货架位',maxWeight:500,status:'闲置',remark:''}, + {code:'A3',wh:'上海外高桥仓',zone:'海派',type:'托盘位',maxWeight:800,status:'闲置',remark:'重货专区'}, + {code:'B1',wh:'深圳盐田仓',zone:'常规货',type:'货架位',maxWeight:500,status:'占用',remark:''}, + {code:'B2',wh:'深圳盐田仓',zone:'一件代发',type:'流利架位',maxWeight:300,status:'闲置',remark:''}, + {code:'C1',wh:'宁波北仑仓',zone:'常规货',type:'地堆位',maxWeight:1000,status:'闲置',remark:'整柜备货'} +]; const overseasLocationData=(function(){ - const whMap={'A':'洛杉矶长滩海外仓','B':'纽约海外仓'}; + const whMap={A:'洛杉矶长滩海外仓',B:'纽约海外仓',C:'汉堡海外仓'}; const zones=['常规货','一件代发','海派']; const arr=[]; - ['A','B'].forEach(function(pre){ - for(let n=1;n<=12;n++){ - const idx=arr.length; - arr.push({ - code:pre+n, - wh:whMap[pre], - zone:zones[idx%3], - type:'货架位', - maxWeight:500, - status:(idx%4===0?'占用':'闲置'), - remark:'' - }); + Object.keys(whMap).forEach(function(prefix){ + for(let number=1;number<=6;number+=1){ + const index=arr.length; + arr.push({code:prefix+number,wh:whMap[prefix],zone:zones[index%3],type:'货架位',maxWeight:500,status:index%4===0?'占用':'闲置',remark:''}); } }); return arr; })(); -let editingLocIdx=-1; -function renderOverseasLocation(list){ - const data=list||overseasLocationData; - const tb=document.getElementById('tbody-overseas-location'); - if(!tb)return; - tb.innerHTML=data.map((d,i)=>` - ${d.code} - ${d.wh} - ${d.zone} - ${d.type} - ${d.maxWeight} - ${d.status} - ${d.remark||'-'} - 编辑   删除 - `).join(''); - const pg=document.getElementById('loc-total'); - if(pg)pg.textContent='共 '+data.length+' 条'; +const locationManagementConfigs={ + domestic:{data:domesticLocationData,prefix:'dom-loc',tbody:'tbody-domestic-location',modal:'modal-domestic-location',title:'dom-loc-modal-title',defaultWarehouse:'上海外高桥仓'}, + overseas:{data:overseasLocationData,prefix:'ovs-loc',tbody:'tbody-overseas-location',modal:'modal-overseas-location',title:'ovs-loc-modal-title',defaultWarehouse:'洛杉矶长滩海外仓'} +}; +let editingLocation={scope:'',index:-1}; +function getLocationManagementConfig(scope){return locationManagementConfigs[scope]||null;} +function locationControlId(config,suffix){return config.prefix+'-'+suffix;} +function locationText(value){return String(value==null?'':value).replace(/[&<>"']/g,function(char){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[char];});} +function renderLocationManagement(scope,list){ + const config=getLocationManagementConfig(scope);if(!config)return; + const data=Array.isArray(list)?list:config.data; + const tbody=document.getElementById(config.tbody);if(!tbody)return; + tbody.innerHTML=data.map(function(record){ + const index=config.data.indexOf(record); + const statusClass=record.status==='闲置'?'tag-green':'tag-orange'; + return `编辑删除${locationText(record.code)}${locationText(record.wh)}${locationText(record.zone)}${locationText(record.type)}${locationText(record.maxWeight)}${locationText(record.status)}${locationText(record.remark||'-')}`; + }).join(''); + const total=document.getElementById(locationControlId(config,'total'));if(total)total.textContent='共 '+data.length+' 条'; } -function locSearch(){ - const wh=(document.getElementById('loc-wh')||{}).value||''; - const zone=(document.getElementById('loc-zone')||{}).value||''; - const code=(document.getElementById('loc-code')||{}).value||''; - const status=(document.getElementById('loc-status')||{}).value||''; - const kw=s=>(''+(s||'')).toLowerCase(); - const filtered=overseasLocationData.filter(d=>{ - if(wh && d.wh!==wh)return false; - if(zone && d.zone!==zone)return false; - if(code && !kw(d.code).includes(kw(code)))return false; - if(status && d.status!==status)return false; - return true; - }); - renderOverseasLocation(filtered); - showToast('查询完成,共 '+filtered.length+' 条','success'); +function searchLocationManagement(scope){ + const config=getLocationManagementConfig(scope);if(!config)return; + const read=function(suffix){return ((document.getElementById(locationControlId(config,suffix))||{}).value||'').trim();}; + const wh=read('wh');const zone=read('zone');const code=read('code').toLowerCase();const status=read('status'); + const filtered=config.data.filter(function(record){return (!wh||record.wh===wh)&&(!zone||record.zone===zone)&&(!code||String(record.code).toLowerCase().includes(code))&&(!status||record.status===status);}); + renderLocationManagement(scope,filtered);showToast('查询完成,共 '+filtered.length+' 条','success'); } -function locReset(){ - ['loc-wh','loc-zone','loc-code','loc-status'].forEach(function(id){const el=document.getElementById(id);if(el)el.value='';}); - renderOverseasLocation(); - showToast('已重置','info'); +function resetLocationManagement(scope){ + const config=getLocationManagementConfig(scope);if(!config)return; + ['wh','zone','code','status'].forEach(function(suffix){const control=document.getElementById(locationControlId(config,suffix));if(control)control.value='';}); + renderLocationManagement(scope);showToast('已重置','info'); } -function openLocModal(idx){ - editingLocIdx=idx; - const title=document.getElementById('loc-modal-title'); - const set=function(id,v){const el=document.getElementById(id);if(el)el.value=(v==null?'':v);}; - if(idx>=0){ - const d=overseasLocationData[idx]; - title.textContent='编辑库位'; - set('loc-code-in',d.code);set('loc-wh-in',d.wh);set('loc-zone-in',d.zone);set('loc-type-in',d.type); - set('loc-weight-in',d.maxWeight); - set('loc-status-in',d.status);set('loc-remark-in',d.remark); +function openLocationManagementModal(scope,index){ + const config=getLocationManagementConfig(scope);if(!config)return; + editingLocation={scope:scope,index:index}; + const set=function(suffix,value){const control=document.getElementById(locationControlId(config,suffix));if(control)control.value=value==null?'':value;}; + const title=document.getElementById(config.title); + if(index>=0&&config.data[index]){ + const record=config.data[index];if(title)title.textContent='编辑库位'; + set('code-in',record.code);set('wh-in',record.wh);set('zone-in',record.zone);set('type-in',record.type);set('weight-in',record.maxWeight==='-'?'':record.maxWeight);set('status-in',record.status);set('remark-in',record.remark); }else{ - title.textContent='新增库位'; - ['loc-code-in','loc-weight-in','loc-remark-in'].forEach(function(id){set(id,'');}); - set('loc-wh-in','洛杉矶长滩海外仓');set('loc-zone-in','常规货');set('loc-type-in','货架位');set('loc-status-in','闲置'); + editingLocation.index=-1;if(title)title.textContent='新增库位'; + set('code-in','');set('wh-in',config.defaultWarehouse);set('zone-in','常规货');set('type-in','货架位');set('weight-in','');set('status-in','闲置');set('remark-in',''); } - showModal('modal-location'); + showModal(config.modal); } -function saveLocation(){ - const get=function(id){return ((document.getElementById(id)||{}).value||'').trim();}; - const code=get('loc-code-in'); +function saveLocationManagement(scope){ + const config=getLocationManagementConfig(scope);if(!config)return; + const read=function(suffix){return ((document.getElementById(locationControlId(config,suffix))||{}).value||'').trim();}; + const code=read('code-in');const weight=read('weight-in'); if(!code){showToast('请填写库位编码','warning');return;} - const rec={ - code:code, - wh:get('loc-wh-in'), - zone:get('loc-zone-in'), - type:get('loc-type-in'), - maxWeight:get('loc-weight-in')||'-', - status:get('loc-status-in')||'闲置', - remark:get('loc-remark-in') - }; - if(editingLocIdx>=0){overseasLocationData[editingLocIdx]=rec;} - else{overseasLocationData.unshift(rec);} - editingLocIdx=-1; - hideModal('modal-location'); - renderOverseasLocation(); - showToast('库位已保存','success'); + if(config.data.some(function(record,index){return index!==editingLocation.index&&record.code.toLowerCase()===code.toLowerCase();})){showToast('库位编码已存在','warning');return;} + if(weight!==''&&(!Number.isFinite(Number(weight))||Number(weight)<0)){showToast('最大承重不能小于 0','warning');return;} + const record={code:code,wh:read('wh-in'),zone:read('zone-in'),type:read('type-in'),maxWeight:weight===''?'-':Number(weight),status:read('status-in')||'闲置',remark:read('remark-in')}; + if(editingLocation.scope===scope&&editingLocation.index>=0)config.data[editingLocation.index]=record;else config.data.unshift(record); + editingLocation={scope:'',index:-1};hideModal(config.modal);renderLocationManagement(scope);showToast('库位已保存','success'); } -function delLocation(idx){ - if(idx<0||idx>=overseasLocationData.length)return; - const d=overseasLocationData[idx]; - if(!confirm('确认删除库位 '+d.code+' ?'))return; - overseasLocationData.splice(idx,1); - renderOverseasLocation(); - showToast('库位已删除','success'); +function deleteLocationManagement(scope,index){ + const config=getLocationManagementConfig(scope);if(!config||index<0||index>=config.data.length)return; + const record=config.data[index];if(!confirm('确认删除库位 '+record.code+' ?'))return; + config.data.splice(index,1);renderLocationManagement(scope);showToast('库位已删除','success'); } +function exportLocationData(scope){const labels={domestic:'国内仓',overseas:'海外仓'};showToast((labels[scope]||'')+'库位数据已导出','success');} +function renderDomesticLocation(list){renderLocationManagement('domestic',list);} +function renderOverseasLocation(list){renderLocationManagement('overseas',list);} +function searchDomesticLocation(){searchLocationManagement('domestic');} +function searchOverseasLocation(){searchLocationManagement('overseas');} +function resetDomesticLocation(){resetLocationManagement('domestic');} +function resetOverseasLocation(){resetLocationManagement('overseas');} +function openDomesticLocationModal(index){openLocationManagementModal('domestic',index);} +function openOverseasLocationModal(index){openLocationManagementModal('overseas',index);} +function saveDomesticLocation(){saveLocationManagement('domestic');} +function saveOverseasLocation(){saveLocationManagement('overseas');} /* 托盘管理 */ const overseasPalletData=[ - {code:'TP-001',type:'木托盘',vol:1.20,weight:22.50,status:'闲置',remark:'标准川字托盘'}, - {code:'TP-002',type:'木托盘',vol:1.20,weight:23.00,status:'占用',remark:''}, - {code:'TP-003',type:'塑料托盘',vol:1.35,weight:15.20,status:'闲置',remark:'防潮耐腐蚀'}, - {code:'TP-004',type:'金属托盘',vol:1.50,weight:38.50,status:'闲置',remark:'重载钢托盘'}, - {code:'TP-005',type:'免熏蒸托盘',vol:1.10,weight:19.80,status:'占用',remark:'出口免检'}, - {code:'TP-006',type:'纸托盘',vol:0.80,weight:8.50,status:'闲置',remark:'一次性轻货'}, - {code:'TP-007',type:'塑料托盘',vol:1.35,weight:15.00,status:'闲置',remark:''}, - {code:'TP-008',type:'木托盘',vol:1.20,weight:22.80,status:'占用',remark:'仓库周转'} + {code:'TP-001',type:'木托盘',vol:1.20,weight:22.50,purchasePrice:120.00,status:'闲置',remark:'标准川字托盘'}, + {code:'TP-002',type:'木托盘',vol:1.20,weight:23.00,purchasePrice:128.00,status:'占用',remark:''}, + {code:'TP-003',type:'塑料托盘',vol:1.35,weight:15.20,purchasePrice:165.50,status:'闲置',remark:'防潮耐腐蚀'}, + {code:'TP-004',type:'金属托盘',vol:1.50,weight:38.50,purchasePrice:398.00,status:'闲置',remark:'重载钢托盘'}, + {code:'TP-005',type:'免熏蒸托盘',vol:1.10,weight:19.80,purchasePrice:145.00,status:'占用',remark:'出口免检'}, + {code:'TP-006',type:'纸托盘',vol:0.80,weight:8.50,purchasePrice:68.00,status:'闲置',remark:'一次性轻货'}, + {code:'TP-007',type:'塑料托盘',vol:1.35,weight:15.00,purchasePrice:158.00,status:'闲置',remark:''}, + {code:'TP-008',type:'木托盘',vol:1.20,weight:22.80,purchasePrice:125.00,status:'占用',remark:'仓库周转'} ]; let editingPalletIdx=-1; function renderOverseasPallet(list){ @@ -7770,9 +9379,10 @@ function renderOverseasPallet(list){ ${d.type} ${Number(d.vol).toFixed(2)} ${Number(d.weight||0).toFixed(2)} + ¥${Number(d.purchasePrice).toFixed(2)} ${d.status} ${d.remark||'-'} - 编辑   删除 + 详情   编辑   删除 `).join(''); const pg=document.getElementById('pallet-total'); if(pg)pg.textContent='共 '+data.length+' 条'; @@ -7784,10 +9394,10 @@ function openPalletModal(idx){ if(idx>=0){ const d=overseasPalletData[idx]; title.textContent='编辑托盘'; - set('pallet-code-in',d.code);set('pallet-type-in',d.type);set('pallet-vol-in',d.vol);set('pallet-weight-in',d.weight);set('pallet-status-in',d.status);set('pallet-remark-in',d.remark); + set('pallet-code-in',d.code);set('pallet-type-in',d.type);set('pallet-vol-in',d.vol);set('pallet-weight-in',d.weight);set('pallet-purchase-price-in',d.purchasePrice);set('pallet-status-in',d.status);set('pallet-remark-in',d.remark); }else{ title.textContent='新增托盘'; - ['pallet-code-in','pallet-vol-in','pallet-weight-in','pallet-remark-in'].forEach(function(id){set(id,'');}); + ['pallet-code-in','pallet-vol-in','pallet-weight-in','pallet-purchase-price-in','pallet-remark-in'].forEach(function(id){set(id,'');}); set('pallet-type-in','木托盘');set('pallet-status-in','闲置'); } showModal('modal-pallet'); @@ -7800,7 +9410,9 @@ function savePallet(){ if(!vol||isNaN(Number(vol))||Number(vol)<=0){showToast('请填写有效的托盘容积(m³)','warning');return;} const weight=get('pallet-weight-in'); if(!weight||isNaN(Number(weight))||Number(weight)<=0){showToast('请填写有效的托盘重量(kg)','warning');return;} - const rec={code:code,type:get('pallet-type-in'),vol:Number(vol),weight:Number(weight),status:get('pallet-status-in')||'闲置',remark:get('pallet-remark-in')}; + const purchasePrice=get('pallet-purchase-price-in'); + if(purchasePrice===''||isNaN(Number(purchasePrice))||Number(purchasePrice)<0){showToast('请填写有效的采购价格','warning');return;} + const rec={code:code,type:get('pallet-type-in'),vol:Number(vol),weight:Number(weight),purchasePrice:Number(purchasePrice),status:get('pallet-status-in')||'闲置',remark:get('pallet-remark-in')}; if(editingPalletIdx>=0){overseasPalletData[editingPalletIdx]=rec;} else{overseasPalletData.unshift(rec);} editingPalletIdx=-1; @@ -7816,6 +9428,33 @@ function delPallet(idx){ renderOverseasPallet(); showToast('托盘已删除','success'); } +function openPalletDetail(code){ + const d=overseasPalletData.find(function(item){return item.code===code;}); + if(!d){showToast('未找到托盘记录','error');return;} + const no=document.getElementById('pallet-detail-no'); + const status=document.getElementById('pallet-detail-status'); + const content=document.getElementById('pallet-detail-content'); + if(no)no.textContent=d.code; + if(status){ + status.textContent=d.status; + status.className='tag '+(d.status==='闲置'?'tag-green':'tag-orange'); + } + if(content)content.innerHTML= + '
基础信息
'+ + '
托盘编码
'+d.code+'
'+ + '
托盘类型
'+d.type+'
'+ + '
托盘容积
'+Number(d.vol).toFixed(2)+' m³
'+ + '
托盘重量
'+Number(d.weight).toFixed(2)+' kg
'+ + '
采购与使用信息
'+ + '
采购价格
¥'+Number(d.purchasePrice).toFixed(2)+'
'+ + '
状态
'+d.status+'
'+ + '
备注
'+(d.remark||'-')+'
'; + switchPage('pallet-detail'); +} +function backToPalletManage(){ + renderOverseasPallet(); + switchPage('pallet-manage'); +} function palletSearch(){ const code=(document.getElementById('pallet-code')||{}).value||''; const type=(document.getElementById('pallet-type')||{}).value||''; @@ -7890,6 +9529,15 @@ function showPreloadDetail(no){ } // ==================== CONTAINER COST ==================== +function openCtCostAdd(){ + var select=document.getElementById('cost-supplier'); + if(select){ + select.innerHTML=''+(supplierData||[]).map(function(s){return '';}).join(''); + select.value=''; + select.required=true; + } + showModal('modal-ct-cost-add'); +} function renderCtCost(){renderTable('tbody-ct-cost',ctCostData,['id','ctNo','type','amount','currency','date','remark',''],(d,c)=>{ if(c==='amount'){ var sym=d.currency==='CNY'?'¥':'$'; @@ -7909,9 +9557,11 @@ function saveCtCost(){ var currency=document.getElementById('cost-currency').value; var date=document.getElementById('cost-date').value; var remark=document.getElementById('cost-remark').value.trim(); + var supplier=(document.getElementById('cost-supplier')||{}).value||''; if(!ctNo){showToast('请填写集装箱号','error');return;} if(!amount||Number(amount)<=0){showToast('请填写金额','error');return;} - ctCostData.unshift({id:'COST'+String(ctCostData.length+1).padStart(3,'0'),ctNo:ctNo,type:type,amount:Number(amount),currency:currency,date:date,remark:remark}); + if(!supplier){showToast('请选择供应商','error');return;} + ctCostData.unshift({id:'COST'+String(ctCostData.length+1).padStart(3,'0'),ctNo:ctNo,type:type,amount:Number(amount),currency:currency,date:date,remark:remark,supplier:supplier}); hideModal('modal-ct-cost-add'); renderCtCost(); showToast('费用已添加','success'); @@ -7985,16 +9635,29 @@ const profitContainerData=[ {ctNo:'MSKU8812001',cust:'岩盛国际物流',income:452000,cost:378000,profit:74000}, {ctNo:'MSKU8812002',cust:'深圳前海远达国际物流',income:189000,cost:161000,profit:28000} ]; -const profitTicketData=[ -{ticket:'BLP20260701001',cust:'杭州积乐贸易有限公司',channel:'海运FBA',income:128000,cost:106000,profit:22000,ctNo:'CSLU1234567',month:'2026-05'}, -{ticket:'BLP20260701002',cust:'义乌欧业进出口有限公司',channel:'海运FBA',income:96000,cost:81000,profit:15000,ctNo:'CSLU4567890',month:'2026-03'}, -{ticket:'BLP20260701003',cust:'上海粤讯供应链',channel:'空运',income:74000,cost:62000,profit:12000,ctNo:'CSLU8901234',month:'2026-04'}, -{ticket:'BLP20260701004',cust:'岩盛国际物流',channel:'海运FBA',income:156000,cost:130000,profit:26000,ctNo:'MSKU8812001',month:'2026-05'}, -{ticket:'BLP20260701005',cust:'深圳前海远达国际物流',channel:'铁路',income:63000,cost:54000,profit:9000,ctNo:'MSKU8812002',month:'2026-02'}, -{ticket:'BLP20260701006',cust:'杭州积乐贸易有限公司',channel:'海运FBA',income:99000,cost:83000,profit:16000,ctNo:'CSLU1234567',month:'2026-06'}, -{ticket:'BLP20260701007',cust:'义乌欧业进出口有限公司',channel:'空运',income:72000,cost:61000,profit:11000,ctNo:'CSLU4567890',month:'2026-03'}, -{ticket:'BLP20260701008',cust:'上海粤讯供应链',channel:'海运FBA',income:58000,cost:49000,profit:9000,ctNo:'CSLU8901234',month:'2026-04'} -]; +const profitBusinessData={ +firstMile:[ +{ticket:'FM202605001',cust:'杭州积乐贸易有限公司',channel:'海运FBA',income:128000,cost:106000,profit:22000,ctNo:'CSLU1234567',month:'2026-05',orderType:'暂扣'}, +{ticket:'FM202603002',cust:'义乌欧业进出口有限公司',channel:'海运FBA',income:96000,cost:81000,profit:15000,ctNo:'CSLU4567890',month:'2026-03',orderType:'退货'}, +{ticket:'FM202604003',cust:'上海粤讯供应链',channel:'空运',income:74000,cost:62000,profit:12000,ctNo:'CSLU8901234',month:'2026-04',orderType:'仓储转运'}, +{ticket:'FM202605004',cust:'岩盛国际物流',channel:'海运FBA',income:156000,cost:130000,profit:26000,ctNo:'MSKU8812001',month:'2026-05',orderType:'换标'}, +{ticket:'FM202602005',cust:'深圳前海远达国际物流',channel:'铁路',income:63000,cost:54000,profit:9000,ctNo:'MSKU8812002',month:'2026-02',orderType:'暂扣'}, +{ticket:'FM202606006',cust:'杭州积乐贸易有限公司',channel:'海运FBA',income:99000,cost:83000,profit:16000,ctNo:'CSLU1234567',month:'2026-06',orderType:'退货'}, +{ticket:'FM202603007',cust:'义乌欧业进出口有限公司',channel:'空运',income:72000,cost:61000,profit:11000,ctNo:'CSLU4567890',month:'2026-03',orderType:'仓储转运'}, +{ticket:'FM202604008',cust:'上海粤讯供应链',channel:'海运FBA',income:58000,cost:49000,profit:9000,ctNo:'CSLU8901234',month:'2026-04',orderType:'换标'} +], +lastMile:[ +{ticket:'LM202605001',cust:'杭州积乐贸易有限公司',channel:'海外仓配',income:46800,cost:31900,profit:14900,ctNo:'CSLU1234567',month:'2026-05',orderType:'仓储转运'}, +{ticket:'LM202603002',cust:'义乌欧业进出口有限公司',channel:'退货处理',income:38200,cost:26700,profit:11500,ctNo:'CSLU4567890',month:'2026-03',orderType:'退货'}, +{ticket:'LM202604003',cust:'上海粤讯供应链',channel:'海外仓配',income:29500,cost:20800,profit:8700,ctNo:'CSLU8901234',month:'2026-04',orderType:'暂扣'}, +{ticket:'LM202606004',cust:'岩盛国际物流',channel:'海外仓配',income:52100,cost:36900,profit:15200,ctNo:'MSKU8812001',month:'2026-06',orderType:'换标'}, +{ticket:'LM202606005',cust:'杭州积乐贸易有限公司',channel:'海外仓配',income:33600,cost:23800,profit:9800,ctNo:'CSLU1234567',month:'2026-06',orderType:'仓储转运'} +] +}; +const profitBusinessLabels={ +firstMile:'头程', +lastMile:'尾程' +}; const profitMonthData=[ {month:'2026-01',income:2180000,cost:1820000,profit:360000,docs:72}, {month:'2026-02',income:1860000,cost:1560000,profit:300000,docs:61}, @@ -8003,9 +9666,35 @@ const profitMonthData=[ {month:'2026-05',income:2510000,cost:2090000,profit:420000,docs:84}, {month:'2026-06',income:1980000,cost:1660000,profit:320000,docs:59} ]; +let profitBusiness='firstMile'; let profitTab='customer'; let profitVisibleTickets=[]; let profitCurrentData={customer:[],container:[],ticket:[],month:[]}; +function getActiveProfitTickets(){return profitBusinessData[profitBusiness]||[];} +function profitOrderType(){return (document.getElementById('profit-order-type')||{}).value||'';} +function profitMatchesOrderType(ticket){const type=profitOrderType();return !type||ticket.orderType===type;} +function activateProfitBusiness(key){ + document.querySelectorAll('#profit-business-tabs .profit-business-tab').forEach(tab=>{ + tab.classList.toggle('active',tab.dataset.profitBusiness===key); + }); +} +function profitRenderCurrentBusiness(){ + profitRenderAll( + profitAggregate(profitVisibleTickets,'customer'), + profitAggregate(profitVisibleTickets,'container'), + profitVisibleTickets.slice(), + profitAggregate(profitVisibleTickets,'month'), + profitVisibleTickets + ); +} +function switchProfitBusiness(key,el){ + if(!profitBusinessData[key])return; + profitBusiness=key; + activateProfitBusiness(key); + const kw=document.getElementById('profit-kw');if(kw)kw.value=''; + profitVisibleTickets=getActiveProfitTickets().filter(d=>profitInRange(d.month)&&profitMatchesOrderType(d)); + profitRenderCurrentBusiness(); +} function activateProfitTab(key){ profitTab=key; document.querySelectorAll('#page-profit .profit-stab').forEach(t=>{ @@ -8122,7 +9811,7 @@ function profitSearch(){ const end=(document.getElementById('profit-end')||{}).value; if(start&&end&&start>end){showToast('开始月份不能晚于结束月份','error');return;} const kw=((document.getElementById('profit-kw')||{}).value||'').trim().toLowerCase(); - profitVisibleTickets=profitTicketData.filter(d=>profitInRange(d.month)); + profitVisibleTickets=getActiveProfitTickets().filter(d=>profitInRange(d.month)&&profitMatchesOrderType(d)); let data={ customer:profitAggregate(profitVisibleTickets,'customer'), container:profitAggregate(profitVisibleTickets,'container'), @@ -8144,20 +9833,33 @@ function profitSearch(){ showToast('查询完成,共 '+data[scope].length+' 条结果','success'); } function profitReset(){ + profitBusiness='firstMile';activateProfitBusiness(profitBusiness); const scope=document.getElementById('profit-scope');if(scope)scope.value='customer'; + const orderType=document.getElementById('profit-order-type');if(orderType)orderType.value=''; ['profit-kw','profit-start','profit-end'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';}); - profitVisibleTickets=profitTicketData.slice(); + profitVisibleTickets=getActiveProfitTickets().slice(); activateProfitTab('customer');profitSetPlaceholder('customer'); - profitRenderAll(profitAggregate(profitVisibleTickets,'customer'),profitAggregate(profitVisibleTickets,'container'),profitVisibleTickets.slice(),profitAggregate(profitVisibleTickets,'month'),profitVisibleTickets); + profitRenderCurrentBusiness(); } function profitRate(profit,income){return income>0?(profit/income*100):0;} +const profitFeeTemplates={ +firstMile:{ +income:['头程运费收入','操作及服务费','其他收入'], +cost:['头程运输费','订舱及操作费','拖车费','报关/清关费'] +}, +lastMile:{ +income:['尾程服务收入','海外仓服务收入','其他收入'], +cost:['尾程运输成本','仓内操作成本','派送操作费','其他成本'] +} +}; function profitTicketFeeDetail(t){ const I=t.income,C=t.cost; const i1=Math.round(I*0.68),i2=Math.round(I*0.22),i3=I-i1-i2; const c1=Math.round(C*0.38),c2=Math.round(C*0.27),c3=Math.round(C*0.20),c4=C-c1-c2-c3; + const template=profitFeeTemplates[profitBusiness]||profitFeeTemplates.firstMile; return { - inc:[{n:'海运费收入',a:i1},{n:'操作及服务费',a:i2},{n:'其他收入',a:i3}], - cos:[{n:'头程海运费',a:c1},{n:'海外仓操作费',a:c2},{n:'拖车费',a:c3},{n:'报关/清关费',a:c4}] + inc:[{n:template.income[0],a:i1},{n:template.income[1],a:i2},{n:template.income[2],a:i3}], + cos:[{n:template.cost[0],a:c1},{n:template.cost[1],a:c2},{n:template.cost[2],a:c3},{n:template.cost[3],a:c4}] }; } function openProfitDetail(dim,val){ @@ -8187,7 +9889,7 @@ function openProfitDetail(dim,val){ const incRows=f.inc.map(r=>''+r.n+''+fmt(r.a)+'').join(''); const cosRows=f.cos.map(r=>''+r.n+''+fmt(r.a)+'').join(''); const iSum=f.inc.reduce((s,r)=>s+r.a,0),cSum=f.cos.reduce((s,r)=>s+r.a,0); - html+='
关联货柜:'+agg.ctNo+'客户:'+agg.cust+'渠道:'+agg.channel+'业务月份:'+agg.month+'
'+ + html+='
业务类型:'+profitBusinessLabels[profitBusiness]+'关联货柜:'+agg.ctNo+'客户:'+agg.cust+'渠道:'+agg.channel+'业务月份:'+agg.month+'
'+ '
收入明细
'+incRows+'
费用项金额
小计'+fmt(iSum)+'
'+ '
成本明细
'+cosRows+'
费用项金额
小计'+fmt(cSum)+'
'+ '
'; @@ -8219,44 +9921,75 @@ let ownVehiclesData=[ {id:'VO3',plate:'浙A·K5532',model:'解放J6P 9.6米',fuel:22.8,mileage:45600,driver:'王磊',phone:'13700137003',status:'维修中',region:'domestic',note:'变速箱检修中'}, {id:'VO4',plate:'苏E·L7788',model:'东风天锦 6.8米',fuel:17.5,mileage:98230,driver:'赵敏',phone:'13600136004',status:'在役',region:'domestic',note:''}, {id:'VO5',plate:'沪C·M1190',model:'依维柯 厢式',fuel:10.8,mileage:53400,driver:'陈浩',phone:'13500135005',status:'停用',region:'domestic',note:'年检过期待处理'}, -{id:'VO6',plate:'浙B·N3344',model:'重汽豪沃 12.5米',fuel:26.3,mileage:31200,driver:'刘洋',phone:'13300133006',status:'在役',region:'overseas',note:'海外仓自有拖车'}, +{id:'VO6',plate:'浙B·N3344',model:'重汽豪沃 12.5米',fuel:26.3,mileage:31200,driver:'刘洋',phone:'13300133006',email:'liuyang@baiyue-logistics.com',status:'在役',region:'overseas',note:'海外仓自有拖车'}, {id:'VO7',plate:'沪A·P6677',model:'福田奥铃 4.2米',fuel:12.9,mileage:67800,driver:'孙倩',phone:'18800188007',status:'在役',region:'domestic',note:''}, -{id:'VO8',plate:'苏B·Q8821',model:'五十铃 5.2米',fuel:14.6,mileage:78900,driver:'周杰',phone:'18600186008',status:'外派中',region:'overseas',note:'外派至海外合作仓库'} +{id:'VO8',plate:'苏B·Q8821',model:'五十铃 5.2米',fuel:14.6,mileage:78900,driver:'周杰',phone:'18600186008',email:'zhoujie@baiyue-logistics.com',status:'外派中',region:'overseas',note:'外派至海外合作仓库'} ]; let dispatchVehiclesData=[ {id:'VD1',plate:'沪D·R2233',model:'解放 9.6米',fuel:21.0,mileage:56000,driver:'顺通物流',phone:'021-58886661',status:'外派中',region:'domestic',note:''}, {id:'VD2',plate:'浙C·S4455',model:'东风 6.8米',fuel:18.2,mileage:41000,driver:'恒丰运输',phone:'0571-86667772',status:'外派中',region:'domestic',note:''}, {id:'VD3',plate:'沪E·T6677',model:'江铃 4.2米',fuel:12.5,mileage:33000,driver:'速达配送',phone:'021-57778883',status:'已归还',region:'domestic',note:''}, -{id:'VD4',plate:'苏A·U8899',model:'重汽 12.5米',fuel:25.4,mileage:28000,driver:'联运物流',phone:'025-84449994',status:'外派中',region:'overseas',note:'外派海外仓'}, -{id:'VD5',plate:'浙D·V1122',model:'福田 5.2米',fuel:15.1,mileage:47000,driver:'安捷运输',phone:'0579-85556665',status:'已归还',region:'overseas',note:'外派海外仓'} +{id:'VD4',plate:'苏A·U8899',model:'重汽 12.5米',fuel:25.4,mileage:28000,driver:'联运物流',phone:'025-84449994',email:'dispatch@lianyun-logistics.com',status:'外派中',region:'overseas',note:'外派海外仓'}, +{id:'VD5',plate:'浙D·V1122',model:'福田 5.2米',fuel:15.1,mileage:47000,driver:'安捷运输',phone:'0579-85556665',email:'service@anjie-transport.com',status:'已归还',region:'overseas',note:'外派海外仓'} ]; +const seededDispatchFleetRecord=staticDispatchRecords.find(item=>item.dispatchNo==='YWBHK200615001'); +const seededDispatchFleetVehicle=dispatchVehiclesData.find(item=>item.id==='VD4'); +if(seededDispatchFleetRecord&&seededDispatchFleetVehicle){ + applyDispatchFleetChange(seededDispatchFleetRecord,null,seededDispatchFleetVehicle,'','2026-06-15 09:00','李输入'); +} let vehicleTab='own'; -let vehicleRegion={own:'all',dispatch:'all'}; +let vehicleRegion='domestic'; let vehicleEditCtx={key:'own',id:null}; +let vehicleDetailContext={key:'own',id:'',region:'domestic',tab:'own',scrollTop:0}; function vehicleStatusTag(s){ const map={'在役':['#52c41a','#f6ffed','#b7eb8f'],'外派中':['#1677ff','#e6f4ff','#91caff'],'维修中':['#fa8c16','#fff7e6','#ffd591'],'停用':['#8c8c8c','#fafafa','#d9d9d9'],'已归还':['#722ed1','#f9f0ff','#d3adf7']}; const c=map[s]||['#8c8c8c','#fafafa','#d9d9d9']; return ''+s+''; } function vehicleRegionTag(r){ - if(r==='overseas')return '国外'; + if(r==='overseas')return '海外'; return '国内'; } -function setVehicleRegion(key,reg,el){ - vehicleRegion[key]=reg; - document.querySelectorAll('#panel-vehicle-'+key+' .vregion-pill').forEach(p=>{p.style.color='#374151';p.style.background='#fff';p.style.borderColor='#e5e7eb';}); - if(el){el.style.color='#fa8c16';el.style.background='#fff7e6';el.style.borderColor='#ffd591';} +function syncVehicleTabState(){ + document.querySelectorAll('#page-vehicle .vehicle-region-tab').forEach(tab=>{ + const active=tab.dataset.region===vehicleRegion; + tab.classList.toggle('active',active); + tab.setAttribute('aria-selected',active?'true':'false'); + }); + document.querySelectorAll('#page-vehicle .vehicle-owner-tab').forEach(tab=>{ + const active=tab.dataset.owner===vehicleTab; + tab.classList.toggle('active',active); + tab.setAttribute('aria-selected',active?'true':'false'); + }); + document.querySelectorAll('#page-vehicle .vehicle-panel').forEach(panel=>{panel.style.display='none';}); + const panel=document.getElementById('panel-vehicle-'+vehicleTab); + if(panel)panel.style.display='block'; + document.querySelectorAll('#page-vehicle .vehicle-overseas-only').forEach(cell=>{cell.style.display=vehicleRegion==='overseas'?'':'none';}); +} +function syncVehicleEmailFieldVisibility(){ + const region=(document.getElementById('vehicle-m-region')||{}).value||'domestic'; + const group=document.getElementById('vehicle-email-group'); + const email=document.getElementById('vehicle-m-email'); + if(group)group.style.display=region==='overseas'?'':'none'; + if(email&®ion!=='overseas')email.value=''; +} +function switchVehicleRegion(el,region){ + vehicleRegion=region; + syncVehicleTabState(); renderVehicle(); } function vehicleRenderOne(arr,tbodyId,key){ const tb=document.getElementById(tbodyId); if(!tb)return; - if(!arr.length){tb.innerHTML='暂无车辆';return;} + if(!arr.length){tb.innerHTML='暂无车辆';return;} const fmt=n=>n.toLocaleString('zh-CN'); tb.innerHTML=arr.map(d=>{ - const ops='查看'+ + ensureFleetSyncState(d); + const ops='查看'+ '编辑'+ '删除'; + const fleetCells=key==='dispatch'?''+lmoEsc(d.currentDispatchNo||'—')+''+ + ''+lmoEsc(d.lastFleetChangeReason||'—')+'':''; return ''+ ''+d.plate+''+ ''+d.model+''+ @@ -8264,6 +9997,8 @@ function vehicleRenderOne(arr,tbodyId,key){ ''+fmt(d.mileage)+''+ ''+d.driver+''+ ''+d.phone+''+ + (d.region==='overseas'?''+lmoEsc(d.email||'—')+'':'')+ + fleetCells+ ''+vehicleStatusTag(d.status)+''+ ''+vehicleRegionTag(d.region)+''+ ''+ops+''; @@ -8273,7 +10008,7 @@ function vehicleApplyFilter(){ const kw=((document.getElementById('vehicle-kw')||{}).value||'').trim().toLowerCase(); const st=(document.getElementById('vehicle-status')||{}).value||''; const filt=arr=>arr.filter(d=>{ - const okw=!kw||(d.plate+' '+d.driver+' '+d.model+' '+(d.phone||'')).toLowerCase().includes(kw); + const okw=!kw||(d.plate+' '+d.driver+' '+d.model+' '+(d.phone||'')+' '+(d.email||'')).toLowerCase().includes(kw); const os=!st||d.status===st; return okw&&os; }); @@ -8281,19 +10016,18 @@ function vehicleApplyFilter(){ } function renderVehicle(){ const f=vehicleApplyFilter(); - const own=f.own.filter(d=>vehicleRegion.own==='all'||d.region===vehicleRegion.own); - const dispatch=f.dispatch.filter(d=>vehicleRegion.dispatch==='all'||d.region===vehicleRegion.dispatch); + const own=f.own.filter(d=>d.region===vehicleRegion); + const dispatch=f.dispatch.filter(d=>d.region===vehicleRegion); vehicleRenderOne(own,'tbody-vehicle-own','own'); vehicleRenderOne(dispatch,'tbody-vehicle-dispatch','dispatch'); const pg=document.getElementById('vehicle-total'); - if(pg)pg.textContent='共 '+(own.length+dispatch.length)+' 条(自有 '+own.length+' · 外派 '+dispatch.length+')'; + const current=vehicleTab==='own'?own:dispatch; + if(pg)pg.textContent='共 '+current.length+' 条'; } function switchVehicleTab(el,key){ vehicleTab=key; - document.querySelectorAll('#page-vehicle .vehicle-stab').forEach(t=>{t.style.color='#374151';t.style.borderBottomColor='transparent';t.style.fontWeight='';}); - el.style.color='#1677ff';el.style.borderBottomColor='#1677ff';el.style.fontWeight='600'; - document.querySelectorAll('#page-vehicle .vehicle-panel').forEach(p=>p.style.display='none'); - document.getElementById('panel-vehicle-'+key).style.display='block'; + syncVehicleTabState(); + renderVehicle(); } function vehicleSearch(){renderVehicle();showToast('查询完成','success');} function vehicleReset(){ @@ -8319,6 +10053,7 @@ function openVehicleModal(mode,key,id){ setV('vehicle-m-status',d.status); setV('vehicle-m-region',d.region||'domestic'); setV('vehicle-m-phone',d.phone||''); + setV('vehicle-m-email',d.region==='overseas'?(d.email||''):''); setV('vehicle-m-note',d.note||''); }else{ setV('vehicle-m-type',vehicleTab); @@ -8328,10 +10063,12 @@ function openVehicleModal(mode,key,id){ setV('vehicle-m-mileage',''); setV('vehicle-m-driver',''); setV('vehicle-m-status','在役'); - setV('vehicle-m-region','domestic'); + setV('vehicle-m-region',vehicleRegion); setV('vehicle-m-phone',''); + setV('vehicle-m-email',''); setV('vehicle-m-note',''); } + syncVehicleEmailFieldVisibility(); showModal('modal-vehicle-edit'); } function saveVehicle(){ @@ -8344,6 +10081,7 @@ function saveVehicle(){ const status=document.getElementById('vehicle-m-status').value; const region=document.getElementById('vehicle-m-region').value; const phone=(document.getElementById('vehicle-m-phone').value||'').trim(); + const email=region==='overseas'?(document.getElementById('vehicle-m-email').value||'').trim():''; const note=(document.getElementById('vehicle-m-note').value||'').trim(); if(!plate){showToast('请填写车牌号','warning');return;} if(!model){showToast('请填写车型','warning');return;} @@ -8351,37 +10089,96 @@ function saveVehicle(){ if(isNaN(mileage)||mileage<0){showToast('请填写有效公里码','warning');return;} const arr=getVehicleArr(key); if(vehicleEditCtx.id){ - const d=arr.find(x=>x.id===vehicleEditCtx.id); - if(d){Object.assign(d,{plate,model,fuel,mileage,driver,status,region,phone,note});} + const sourceArr=getVehicleArr(vehicleEditCtx.key); + const sourceIndex=sourceArr.findIndex(x=>x.id===vehicleEditCtx.id); + const d=sourceIndex>=0?sourceArr[sourceIndex]:null; + if(d){ + Object.assign(d,{plate,model,fuel,mileage,driver,status,region,phone,email,note}); + if(sourceArr!==arr){sourceArr.splice(sourceIndex,1);arr.unshift(d);} + } showToast('车辆已更新','success'); }else{ const id=(key==='own'?'VO':'VD')+(arr.length+1); - arr.unshift({id,plate,model,fuel,mileage,driver,status,region,phone,note}); + arr.unshift({id,plate,model,fuel,mileage,driver,status,region,phone,email,note}); showToast('车辆已添加','success'); } + vehicleRegion=region; + vehicleTab=key; + syncVehicleTabState(); renderVehicle(); - const tabEl=[...document.querySelectorAll('#page-vehicle .vehicle-stab')].find(t=>(key==='own'?'自有':'外派')===t.textContent.trim()); - if(tabEl)switchVehicleTab(tabEl,key); hideModal('modal-vehicle-edit'); } -function viewVehicle(key,id){ - const d=getVehicleArr(key).find(x=>x.id===id); - if(!d)return; - document.getElementById('vehicle-view-title').textContent='车辆详情 · '+d.plate; +function getVehicleDispatchOrders(vehicle,records){ + const vehicleId=String(vehicle&&vehicle.id||''); + const historyNos=new Set((vehicle&&vehicle.fleetChangeHistory||[]).map(item=>String(item.dispatchNo||item.bolNo||'')).filter(Boolean)); + const matches=new Map(); + (records||[]).forEach(record=>{ + const dispatchNo=String(record.dispatchNo||record.bolNo||record.firstLegNo||''); + const isCurrent=String(record.fleetVehicleId||'')===vehicleId; + const isHistory=historyNos.has(dispatchNo); + if(!dispatchNo||(!isCurrent&&!isHistory))return; + const next={record,relation:isCurrent?'当前关联':'历史关联'}; + const previous=matches.get(dispatchNo); + if(!previous||next.relation==='当前关联')matches.set(dispatchNo,next); + }); + return Array.from(matches.values()); +} +function renderVehicleFleetHistory(vehicle){ + const tbody=document.getElementById('vehicle-detail-history-body'); + if(!tbody)return; + ensureFleetSyncState(vehicle); + const history=vehicle.fleetChangeHistory||[]; + tbody.innerHTML=history.length?history.map(item=>''+lmoEsc(item.time||'—')+''+lmoEsc(item.dispatchNo||item.bolNo||'—')+''+lmoEsc(item.action||'—')+''+lmoEsc(item.otherVehicle||'—')+''+lmoEsc(item.reason||'—')+''+lmoEsc(item.operator||'—')+'').join(''):'暂无派送更换记录'; +} +function renderVehicleDetail(vehicle,key){ + const plate=document.getElementById('vehicle-detail-plate'),status=document.getElementById('vehicle-detail-status'),info=document.getElementById('vehicle-detail-info'),ordersBody=document.getElementById('vehicle-detail-orders-body'); + if(!plate||!status||!info||!ordersBody)return; + ensureFleetSyncState(vehicle); const fmt=n=>n.toLocaleString('zh-CN'); const rows=[ - ['车牌号',d.plate], - ['车型',d.model], - ['油耗',d.fuel+' L/100km'], - ['当前公里码',fmt(d.mileage)+' km'], - ['司机 / 外派单位',d.driver||'—'], - ['联系电话',d.phone||'—'], - ['状态',vehicleStatusTag(d.status)], - ['区域',vehicleRegionTag(d.region)], - ['备注',d.note||'—'] + ['车辆归属',key==='own'?'自有车辆':'外派车辆'], + ['区域',vehicle.region==='overseas'?'海外':'国内'], + ['车牌号',vehicle.plate], + ['车型',vehicle.model], + [key==='own'?'司机':'外派单位',vehicle.driver||'—'], + ['联系电话',vehicle.phone||'—'], + ...(vehicle.region==='overseas'?[['邮箱',vehicle.email||'—']]:[]), + ['油耗',vehicle.fuel+' L/100km'], + ['当前公里码',fmt(vehicle.mileage)+' km'], + ['状态',vehicle.status||'—'], + ['备注',vehicle.note||'—'] ]; - document.getElementById('vehicle-view-body').innerHTML='
'+rows.map(r=>'
'+r[0]+'
'+r[1]+'
').join('')+'
'; - showModal('modal-vehicle-view'); + plate.textContent=vehicle.plate||'—'; + status.className=''; + status.innerHTML=vehicleStatusTag(vehicle.status||'—'); + info.innerHTML=rows.map(row=>'
'+lmoEsc(row[0])+'
'+lmoEsc(row[1])+'
').join(''); + const orders=getVehicleDispatchOrders(vehicle,[...lastMileDispatchData,...staticDispatchRecords]); + ordersBody.innerHTML=orders.length?orders.map(item=>{ + const record=item.record; + const relationClass=item.relation==='当前关联'?'is-current':'is-history'; + return ''+lmoEsc(record.dispatchNo||record.bolNo||'—')+''+lmoEsc(record.bolNo||record.lastMileNo||record.firstLegNo||record.vehicleNo||'—')+''+lmoEsc(record.customer||record.owner||'—')+''+lmoEsc(record.destFba||record.warehouse||'—')+''+lmoEsc(record.appointmentDate||record.depart||'—')+''+lmoEsc(record.status||'—')+''+item.relation+''; + }).join(''):'暂无派送订单明细'; + renderVehicleFleetHistory(vehicle); +} +function openVehicleDetail(key,id){ + const vehicle=getVehicleArr(key).find(item=>item.id===id); + if(!vehicle){showToast('未找到该车辆记录','error');return;} + const mainScroll=document.querySelector('.main-content'); + const vehicleNav=document.querySelector('.sub-menu-item[onclick="switchPage(\'vehicle\',this)"]'); + vehicleDetailContext={key,id,region:vehicleRegion,tab:vehicleTab,scrollTop:mainScroll?mainScroll.scrollTop:0}; + renderVehicleDetail(vehicle,key); + switchPage('vehicle-detail',vehicleNav); + if(mainScroll)mainScroll.scrollTop=0; +} +function backToVehicleList(){ + vehicleRegion=vehicleDetailContext.region||'domestic'; + vehicleTab=vehicleDetailContext.tab||vehicleDetailContext.key||'own'; + const vehicleNav=document.querySelector('.sub-menu-item[onclick="switchPage(\'vehicle\',this)"]'); + switchPage('vehicle',vehicleNav); + syncVehicleTabState(); + renderVehicle(); + const mainScroll=document.querySelector('.main-content'); + if(mainScroll)requestAnimationFrame(()=>{mainScroll.scrollTop=vehicleDetailContext.scrollTop||0;}); } function deleteVehicle(key,id){ if(typeof confirm==='function' && !confirm('确认删除该车辆?此操作不可撤销。'))return; @@ -8462,8 +10259,11 @@ if(el&&el.classList.contains('sub-menu-item'))el.classList.add('active'); // Render data for the page if(page==='tenant-list')renderTenant(); if(page==='supplier-list')renderSupplier(); +if(page==='delivery-fleet-quote')renderDeliveryFleetQuotes(); if(page==='ocean-channel')renderOceanChannels(); if(page==='truck-list')renderTruckList(); +if(page==='truck-add'){truckAddRegion=truckRegion;updateTruckCurrencyLabels();} +if(page==='truck-edit')updateTruckCurrencyLabels(); if(page==='overseas-users')renderOverseasUsers(); if(page==='overseas-purchase')switchPurchaseOrderTab('domestic'); if(page==='overseas-truck')renderTruckOrderList(); @@ -8514,6 +10314,7 @@ if(page==='inbound-detail'){ document.querySelectorAll('.ops-panel').forEach(p=>p.style.display='none'); const skuPanel=document.getElementById('ops-sku-detail'); if(skuPanel)skuPanel.style.display='block'; + renderDomesticInboundFees(); } if(page==='wh-inbound')renderInbound(); if(page==='wh-check')renderWhCheck(); @@ -8553,6 +10354,7 @@ if(page==='overseas-stock')renderOverseasStock(); if(page==='overseas-inbound')renderOverseasInbound(); if(page==='overseas-outbound')renderOverseasOutbound(); if(page==='overseas-relabel')renderOverseasRelabel(); +if(page==='domestic-location')renderDomesticLocation(); if(page==='overseas-location')renderOverseasLocation(); if(page==='fba-return-list')renderFbaReturn(); if(page==='fba-return-inbound')renderFbaReturnInbound(); @@ -8571,6 +10373,7 @@ if(page==='pallet-manage')renderOverseasPallet(); if(page==='ct-preload')renderCtPreload(); if(page==='ct-board')renderCtBoard(); if(page==='outbound-dispatch')renderLastMileDispatchRows(); +if(page==='outbound-exception')renderDispatchExceptions(); if(page==='outbound-vehicle')renderOutboundVehicle(); if(page==='finance-ar')renderAR(); if(page==='finance-ap')renderAP(); @@ -8587,9 +10390,10 @@ if(page==='finance-bill'){ renderBill(); } if(page==='finance-bill-generate')renderSupplierRecon(); -if(page==='customer-account')renderCustomerAccounts(); +if(page==='customer-account'){renderCustomerAccounts();renderCustomerRechargeApplications();} if(page==='customer-account-detail')renderCustomerAccountDetail(); if(page==='customer-arap')renderArap(); +if(page==='finance-ar-detail-report')renderReceivableDetailReport(); if(page==='customer-recon-stmt')renderCustomerReconStmt(); if(page==='settlement-ap')renderSettleAp(); if(page==='settlement-ar')renderSettlementAr(); @@ -8606,7 +10410,11 @@ if(page==='rpt-freight'){renderFreightReport();requestAnimationFrame(()=>{reques if(page==='rpt-business')renderRptBusiness(); if(page==='gen-product')renderGenProduct(); if(page==='gen-fee')renderGenFee(); +if(page==='gen-exchange-rate')renderExchangeRates(); +if(page==='gen-owned-warehouse')renderOwnedWarehouse(); if(page==='gen-fba')renderGenFba(); +if(page==='gen-partner-warehouse')renderPartnerWarehouse(); +if(page==='gen-overseas-quote')renderOverseasWarehouseQuotes(); if(page==='gen-download')renderDownloadCenter(); if(page==='gen-pallet')renderGenPallet(); if(page==='gen-location')renderGenLocation(); @@ -8624,12 +10432,150 @@ if(page==='sys-tenant')renderSysTenant(); if(window.innerWidth<768)document.getElementById('sidebar').classList.remove('mobile-open'); } +const domesticInboundFeeData=[]; +let domesticInboundDetailOrderCode='PCKK2606151065'; +let domesticInboundFeeContext={mode:'pickup',orderCode:domesticInboundDetailOrderCode,trigger:null,voucherName:''}; + +function buildDomesticInboundFeeRecord(form,context,now){ +return { +orderCode:context.orderCode, +type:form.type, +amount:Number(form.amount), +currency:form.currency, +voucherName:form.voucherName||'', +remark:form.remark||'', +auditStatus:'待审核', +businessDate:now.slice(0,10) +}; +} + +function domesticInboundFeeLocalDateTime(){ +const now=new Date(); +const pad=value=>String(value).padStart(2,'0'); +return now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+pad(now.getHours())+':'+pad(now.getMinutes())+':'+pad(now.getSeconds()); +} + +function escapeDomesticInboundFeeHtml(value){ +return String(value==null?'':value).replace(/[&<>"']/g,char=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char])); +} + +function setDomesticInboundDetailOrderCode(orderCode){ +domesticInboundDetailOrderCode=String(orderCode||'PCKK2606151065'); +const code=document.getElementById('domestic-inbound-detail-code'); +if(code)code.textContent='入库码:'+domesticInboundDetailOrderCode; +} + +function openDomesticInboundDetail(orderCode){ +setDomesticInboundDetailOrderCode(orderCode); +switchPage('inbound-detail'); +} + +function syncDomesticInboundDetailOrderFromListClick(event){ +const link=event.target.closest('a'); +if(!link||link.getAttribute('onclick')!=="switchPage('inbound-detail')")return; +const row=link.closest('tr'); +const orderCode=row&&row.cells[2]?row.cells[2].textContent.trim():''; +if(orderCode)setDomesticInboundDetailOrderCode(orderCode); +} + +document.addEventListener('click',syncDomesticInboundDetailOrderFromListClick,true); + +function renderDomesticInboundFees(){ +const body=document.getElementById('domestic-inbound-fee-body'); +if(!body)return; +const rows=domesticInboundFeeData.filter(item=>item.orderCode===domesticInboundDetailOrderCode); +if(!rows.length){ +body.innerHTML='
暂无费用明细
'; +return; +} +body.innerHTML=rows.map((item,index)=>{ +const display=escapeDomesticInboundFeeHtml; +const amount=Number(item.amount).toFixed(2); +const voucher=item.voucherName?''+display(item.voucherName)+'':'—'; +return '查看'+display(item.auditStatus)+'应付——'+display(item.orderCode)+''+display(item.businessDate)+'——————'+display(item.type)+''+display(item.currency)+''+amount+'—————否———'+voucher+''+display(item.remark||'—')+''; +}).join(''); +} + +function openDomesticInboundFeeModal(mode,orderCode,trigger){ +const isCourier=mode==='courier'; +domesticInboundFeeContext={mode:isCourier?'courier':'pickup',orderCode:String(orderCode||domesticInboundDetailOrderCode),trigger:trigger||null,voucherName:''}; +const type=document.getElementById('domestic-fee-type'); +const amount=document.getElementById('domestic-fee-amount'); +const currency=document.getElementById('domestic-fee-currency'); +const remark=document.getElementById('domestic-fee-remark'); +const code=document.getElementById('domestic-fee-order-code'); +if(type){type.disabled=isCourier;type.value=isCourier?'快递费':'取货费';} +if(amount)amount.value=''; +if(currency)currency.value='CNY'; +if(remark)remark.value=''; +if(code)code.textContent=domesticInboundFeeContext.orderCode; +removeDomesticFeeVoucher(); +syncDomesticFeeVoucherRequirement(); +document.querySelectorAll('.more-dropdown').forEach(item=>item.classList.remove('open')); +showModal('modal-domestic-inbound-fee'); +setTimeout(()=>amount&&amount.focus(),0); +} + +function syncDomesticFeeVoucherRequirement(){ +const type=document.getElementById('domestic-fee-type')?.value||'取货费'; +const wrap=document.getElementById('domestic-fee-voucher-wrap'); +const required=document.getElementById('domestic-fee-voucher-required'); +if(wrap)wrap.style.display=type==='取货费'?'block':'none'; +if(required)required.style.display=type==='取货费'?'inline':'none'; +if(type!=='取货费')removeDomesticFeeVoucher(); +} + +function handleDomesticFeeVoucher(input){ +const file=input&&input.files&&input.files[0]; +if(!file){removeDomesticFeeVoucher();return;} +const allowed=/\.(pdf|png|jpe?g|gif|webp)$/i.test(file.name)||String(file.type).startsWith('image/')||file.type==='application/pdf'; +if(!allowed){ +showToast('付款凭证仅支持图片或 PDF 文件','error'); +removeDomesticFeeVoucher(); +return; +} +domesticInboundFeeContext.voucherName=file.name; +const name=document.getElementById('domestic-fee-voucher-name'); +const remove=document.getElementById('domestic-fee-voucher-remove'); +if(name){name.textContent=file.name;name.style.color='#334155';name.title=file.name;} +if(remove)remove.style.display='inline-flex'; +} + +function removeDomesticFeeVoucher(){ +domesticInboundFeeContext.voucherName=''; +const input=document.getElementById('domestic-fee-voucher'); +const name=document.getElementById('domestic-fee-voucher-name'); +const remove=document.getElementById('domestic-fee-voucher-remove'); +if(input)input.value=''; +if(name){name.textContent='未选择文件';name.style.color='#94a3b8';name.title='';} +if(remove)remove.style.display='none'; +} + +function saveDomesticInboundFee(){ +const type=document.getElementById('domestic-fee-type')?.value||''; +const amountValue=document.getElementById('domestic-fee-amount')?.value||''; +const amount=Number(amountValue); +const currency=document.getElementById('domestic-fee-currency')?.value||'CNY'; +const remark=(document.getElementById('domestic-fee-remark')?.value||'').trim(); +if(!amountValue||!Number.isFinite(amount)||amount<=0){showToast('请输入大于 0 的费用金额','error');return;} +if(type==='取货费'&&!domesticInboundFeeContext.voucherName){showToast('取货费必须上传付款凭证','error');return;} +const now=domesticInboundFeeLocalDateTime(); +domesticInboundFeeData.push(buildDomesticInboundFeeRecord({type,amount,currency,voucherName:domesticInboundFeeContext.voucherName,remark},domesticInboundFeeContext,now)); +document.querySelectorAll('[data-inbound-fee-status]').forEach(cell=>{ +if(cell.getAttribute('data-inbound-fee-status')===domesticInboundFeeContext.orderCode)cell.innerHTML='待审核'; +}); +renderDomesticInboundFees(); +hideModal('modal-domestic-inbound-fee'); +showToast('费用已保存,等待审核','success'); +} + function switchDetailTab(el,panelId){ document.querySelectorAll('#detail-tabs .detail-tab').forEach(t=>t.classList.remove('active')); el.classList.add('active'); document.querySelectorAll('.detail-panel').forEach(p=>p.style.display='none'); const panel=document.getElementById(panelId); if(panel)panel.style.display='block'; +if(panelId==='detail-fee')renderDomesticInboundFees(); } function toggleMoreDropdown(btn){ @@ -8676,6 +10622,7 @@ tabs.forEach(t=>t.classList.remove('active')); el.classList.add('active'); document.getElementById('dispatch-sku-panel').style.display=tab==='sku'?'block':'none'; document.getElementById('dispatch-fee-panel').style.display=tab==='fee'?'block':'none'; +if(tab==='fee')renderOutboundVehicleCourierFeeRows(); } function switchBolTab(tab,el){ @@ -8695,12 +10642,14 @@ document.getElementById('selfpickup-detail-panel').style.display=tab==='detail'? function submitOtherInfo(){ const detainFlag=document.querySelector('input[name="detainFlag"]:checked')?.value; +const boxChargeFlag=document.querySelector('input[name="boxChargeFlag"]:checked')?.value||'0'; const detainReason=document.getElementById('detainReason')?.value||''; const expressCo=document.getElementById('expressCompany')?.value||''; const expressNo=document.getElementById('expressNo')?.value||''; const remark=document.getElementById('remark')?.value||''; const internalRemark=document.getElementById('internalRemark')?.value||''; -showToast('其他信息已提交','success'); +const boxChargeLabel=boxChargeFlag==='1'?'是':'否'; +showToast('其他信息已提交,箱子是否计费:'+boxChargeLabel,'success'); } function toggleMenu(label){ @@ -10107,38 +12056,295 @@ var supplierCatNames={booking:'订舱',customs:'报关',trucking:'拖车',cert:' // ============ 客户应收应付 ============ var arapData=[ -{customer:'义乌市赛恩进出口有限公司',billNo:'',joinSettle:'是',auditStatus:'客服提交',arAp:'应收',whCode:'HDHK2606271801',orderStatus:'派送待审',dispatchNo:'',feeType:'运费',containerNo:'ZCSU7140067',cabinetNo:'D2129(以是快揽)'}, -{customer:'义乌市赛恩进出口有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'PCKK2606301559',orderStatus:'派送完成',dispatchNo:'20260623056',feeType:'仓储费',containerNo:'CAUU8853971',cabinetNo:'D2062(上海合禧快揽)'}, -{customer:'义乌市华牧贸易有限公司',billNo:'',joinSettle:'是',auditStatus:'新增',arAp:'应收',whCode:'PCHWK2606161088',orderStatus:'入库完成',dispatchNo:'',feeType:'运费',containerNo:'',cabinetNo:''}, -{customer:'义乌市博隆网络科技有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'HPHK2605160727',orderStatus:'派送完成',dispatchNo:'C1720260625190',feeType:'仓储费',containerNo:'SMCU1009301',cabinetNo:'D2037(SML)'}, -{customer:'上海粤祺网络科技有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'HPHK2605140527',orderStatus:'派送完成',dispatchNo:'C1720260625355',feeType:'仓储费',containerNo:'SMCU1009301',cabinetNo:'D2037(SML)'} +{customer:'义乌市赛恩进出口有限公司',billNo:'',joinSettle:'是',auditStatus:'客服提交',arAp:'应收',whCode:'HDHK2606271801',orderStatus:'派送待审',dispatchNo:'',feeType:'运费',amount:'1280.00',containerNo:'ZCSU7140067',cabinetNo:'D2129(以是快揽)'}, +{customer:'义乌市赛恩进出口有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'PCKK2606301559',orderStatus:'派送完成',dispatchNo:'20260623056',feeType:'仓储费',amount:'560.00',containerNo:'CAUU8853971',cabinetNo:'D2062(上海合禧快揽)'}, +{customer:'义乌市华牧贸易有限公司',billNo:'',joinSettle:'是',auditStatus:'新增',arAp:'应收',whCode:'PCHWK2606161088',orderStatus:'入库完成',dispatchNo:'',feeType:'运费',amount:'980.50',containerNo:'',cabinetNo:''}, +{customer:'义乌市博隆网络科技有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'HPHK2605160727',orderStatus:'派送完成',dispatchNo:'C1720260625190',feeType:'仓储费',amount:'720.00',containerNo:'SMCU1009301',cabinetNo:'D2037(SML)'}, +{customer:'上海粤祺网络科技有限公司',billNo:'',joinSettle:'是',auditStatus:'财务通过',arAp:'应收',whCode:'HPHK2605140527',orderStatus:'派送完成',dispatchNo:'C1720260625355',feeType:'仓储费',amount:'645.80',containerNo:'SMCU1009301',cabinetNo:'D2037(SML)'} ]; + +function getArapActionState(status){ + return {canEdit:status!=='审核通过',canAudit:status==='待审核'}; +} +function getArapStatusAfterSave(){ + return '待审核'; +} +function getArapAuditStatus(action){ + return action==='pass'?'审核通过':'审核驳回'; +} +function normalizeArapAmount(value){ + var text=String(value==null?'':value).trim(); + if(!/^\d+(\.\d{1,2})?$/.test(text))return ''; + var amount=Number(text); + return Number.isFinite(amount)&&amount>=0?amount.toFixed(2):''; +} +function appendArapLog(record,node,result,remark){ + if(!Array.isArray(record.logs))record.logs=[]; + record.logs.push({time:new Date().toLocaleString('zh-CN',{hour12:false}),node:node,operator:'财务专员',result:result,remark:remark||'—'}); +} +arapData.forEach(function(record,index){ + var legacyStatus=record.auditStatus; + record.auditStatus=legacyStatus==='财务通过'?'审核通过':'待审核'; + record.logs=[{time:'2026-08-'+String(10+index).padStart(2,'0')+' 09:20',node:'费用已生成',operator:'系统',result:'成功',remark:'由业务单据自动生成'}]; + if(legacyStatus==='客服提交')record.logs.push({time:'2026-08-'+String(10+index).padStart(2,'0')+' 10:05',node:'提交审核',operator:'客服专员',result:'待审核',remark:'费用信息核对完成'}); + if(legacyStatus==='财务通过')record.logs.push({time:'2026-08-'+String(10+index).padStart(2,'0')+' 14:30',node:'财务审核',operator:'财务专员',result:'审核通过',remark:'允许参与结算'}); +}); + function renderArap(){ var tb=document.getElementById('tbody-arap'); if(!tb)return; -var auditCls={'财务通过':'color:#52c41a;background:#f6ffed;border:1px solid #b7eb8f;padding:2px 10px;border-radius:10px;font-size:12px','客服提交':'color:#1890ff;background:#e6f7ff;border:1px solid #91d5ff;padding:2px 10px;border-radius:10px;font-size:12px','新增':'color:#fa8c16;background:#fff7e6;border:1px solid #ffd591;padding:2px 10px;border-radius:10px;font-size:12px'}; -tb.innerHTML=arapData.map(function(d,i){ -var ops='详情' -+'审核' -+'编辑' -+'禁止结算' -+'删除'; -return '' -+'' -+''+ops+'' -+''+d.customer+'' -+''+(d.billNo||'')+'' -+''+d.joinSettle+'' -+''+d.auditStatus+'' -+''+d.arAp+'' -+''+d.whCode+'' -+''+d.orderStatus+'' -+''+(d.dispatchNo||'')+'' -+''+d.feeType+'' -+''+d.containerNo+'' -+''+d.cabinetNo+'' -+''; +var auditCls={'审核通过':'tag-green','待审核':'tag-orange','审核驳回':'tag-red'}; +var statusFilter=document.getElementById('arap-filter-audit-status'); +var queryStatus=statusFilter?statusFilter.value:''; +var rows=arapData.map(function(d,i){ + if(queryStatus&&d.auditStatus!==queryStatus)return ''; + var state=getArapActionState(d.auditStatus); + var ops='详情'; + if(state.canAudit)ops+='审核'; + if(state.canEdit)ops+='编辑'; + ops+='禁止结算'; + return '' + +'' + +''+ops+'' + +''+d.customer+'' + +''+(d.billNo||'')+'' + +''+d.joinSettle+'' + +''+d.auditStatus+'' + +''+d.arAp+'' + +''+d.whCode+'' + +''+d.orderStatus+'' + +''+(d.dispatchNo||'')+'' + +''+d.feeType+'' + +''+d.amount+'' + +''+d.containerNo+'' + +''+d.cabinetNo+'' + +''; }).join(''); +tb.innerHTML=rows||'暂无匹配数据'; +} + +// ============ 应收款统计表 ============ +var receivableDetailReportData=[ + {year:2026,receivableEntity:'浙江柏悦贸易有限公司',currency:'CNY',customer:'柏悦贸易',monthlyAmounts:{1:{direct:86400,special:22000},2:{direct:92500,special:30800},3:{direct:75300,special:28600},4:{direct:104000,special:35200},5:{direct:128000,special:36500},6:{direct:99800,special:42300},7:{direct:113600,special:52000,received:142000,deduction:200}},remark:'7月专线待核销'}, + {year:2026,receivableEntity:'付银装',currency:'CNY',customer:'付银装',monthlyAmounts:{1:{direct:45800,special:18600},2:{direct:58200,special:21300},3:{direct:72000,special:25000},4:{direct:67800,special:29100},5:{direct:86000,special:28600},6:{direct:74500,special:31200},7:{direct:92400,special:34800,received:118000,deduction:0}},remark:''}, + {year:2026,receivableEntity:'曼博无锡配送仓库',currency:'CNY',customer:'曼博无锡',monthlyAmounts:{1:{direct:36000,special:12800},2:{direct:42500,special:15200},3:{direct:48900,special:16800},4:{direct:55300,special:17600},5:{direct:52800,special:18000},6:{direct:61400,special:21500},7:{direct:68700,special:24300,received:80000,deduction:60}},remark:'待补收款凭证'}, + {year:2026,receivableEntity:'深圳前海跨境电商有限公司',currency:'USD',customer:'前海跨境',monthlyAmounts:{3:{direct:8800,special:2400},4:{direct:9600,special:3100},5:{direct:10600,special:3600},6:{direct:11500,special:4200},7:{direct:12800,special:4600,received:15000,deduction:25}},remark:'按美元原币统计'}, + {year:2026,receivableEntity:'杭州积乐贸易有限公司',currency:'CNY',customer:'积乐贸易',monthlyAmounts:{5:{direct:0,special:16500},6:{direct:48600,special:19200},7:{direct:52700,special:22800,received:70000,deduction:0}},remark:''}, + {year:2025,receivableEntity:'浙江柏悦贸易有限公司',currency:'CNY',customer:'柏悦贸易',monthlyAmounts:{11:{direct:80600,special:26100},12:{direct:94200,special:31500,received:110000,deduction:100}},remark:'2025年历史数据'} +]; +var receivableReportEditingIndex=-1; +function calculateReceivableReportRow(record,monthKey){ + var normalizedMonth=/^\d{4}-\d{2}$/.test(String(monthKey||''))?String(monthKey):'2026-07'; + var parts=normalizedMonth.split('-'); + var selectedYear=Number(parts[0]),selectedMonth=Number(parts[1]); + var source=record.year===selectedYear&&record.monthlyAmounts&&record.monthlyAmounts[selectedMonth]; + var month=source?{direct:Number(source.direct)||0,special:Number(source.special)||0}:{direct:null,special:null}; + var receivableAmount=(month.direct||0)+(month.special||0); + var receivedAmount=source?Number(source.received)||0:0; + var deductionAmount=source?Number(source.deduction)||0:0; + return Object.assign({},record,{monthKey:normalizedMonth,month:month,receivableAmount:receivableAmount,receivedAmount:receivedAmount,deductionAmount:deductionAmount,balanceAmount:receivableAmount-receivedAmount-deductionAmount}); +} +function summarizeReceivableReportByCurrency(rows){ + return rows.reduce(function(summary,row){ + var currency=row.currency||'CNY'; + if(!summary[currency])summary[currency]={receivable:0,received:0,deduction:0,balance:0}; + summary[currency].receivable+=row.receivableAmount; + summary[currency].received+=row.receivedAmount; + summary[currency].deduction+=row.deductionAmount; + summary[currency].balance+=row.balanceAmount; + return summary; + },{}); +} +function formatReceivableReportAmount(amount,currency){ + return (currency||'CNY')+' '+Number(amount||0).toLocaleString('zh-CN',{minimumFractionDigits:2,maximumFractionDigits:2}); +} +function buildReceivableReportHeader(monthKey){ + return '序号应收单位币种FBA直发FBA专线应收总金额已收合计零头减免余额未收客户备注操作'; +} +function updateReceivableReportEditableFields(record,customer,remark){ + var normalizedCustomer=String(customer==null?'':customer).trim(); + var normalizedRemark=String(remark==null?'':remark).trim(); + if(!record||!normalizedCustomer||normalizedCustomer.length>50||normalizedRemark.length>200)return false; + record.customer=normalizedCustomer; + record.remark=normalizedRemark; + return true; +} +function escapeReceivableReportText(value){ + return String(value==null?'':value).replace(/[&<>"']/g,function(char){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[char];}); +} +function receivableReportCellAmount(value){ + return Number(value||0).toLocaleString('zh-CN',{minimumFractionDigits:2,maximumFractionDigits:2}); +} +function populateReceivableReportFilters(){ + var entity=document.getElementById('ardr-entity'),currency=document.getElementById('ardr-currency'); + if(!entity||!currency)return; + var oldEntity=entity.value,oldCurrency=currency.value; + var entities=[...new Set(receivableDetailReportData.map(function(item){return item.receivableEntity;}))].sort(); + var currencies=[...new Set(receivableDetailReportData.map(function(item){return item.currency;}))].sort(); + entity.innerHTML=''+entities.map(function(item){return '';}).join(''); + currency.innerHTML=''+currencies.map(function(item){return '';}).join(''); + if(entities.indexOf(oldEntity)>=0)entity.value=oldEntity; + if(currencies.indexOf(oldCurrency)>=0)currency.value=oldCurrency; +} +function renderReceivableReportSummary(summary){ + var currencies=Object.keys(summary).sort(); + if(!currencies.length)currencies=['CNY']; + var fields=[['ardr-total-receivable','receivable'],['ardr-total-received','received'],['ardr-total-deduction','deduction'],['ardr-total-balance','balance']]; + fields.forEach(function(pair){ + var el=document.getElementById(pair[0]); + if(!el)return; + el.innerHTML=currencies.map(function(currency){return formatReceivableReportAmount(summary[currency]?summary[currency][pair[1]]:0,currency);}).join('
'); + }); +} +function renderReceivableDetailReport(){ + var tbody=document.getElementById('tbody-receivable-detail-report'); + var thead=document.getElementById('thead-receivable-detail-report'); + var monthEl=document.getElementById('ardr-month'); + if(!tbody||!thead||!monthEl)return; + populateReceivableReportFilters(); + var monthKey=/^\d{4}-\d{2}$/.test(monthEl.value)?monthEl.value:'2026-07'; + var year=Number(monthKey.slice(0,4)); + var month=Number(monthKey.slice(5,7)); + var entity=(document.getElementById('ardr-entity')||{}).value||''; + var currency=(document.getElementById('ardr-currency')||{}).value||''; + var rows=receivableDetailReportData.filter(function(item){return item.year===year&&item.monthlyAmounts&&item.monthlyAmounts[month]&&(!entity||item.receivableEntity===entity)&&(!currency||item.currency===currency);}).map(function(item){var row=calculateReceivableReportRow(item,monthKey);row.sourceIndex=receivableDetailReportData.indexOf(item);return row;}); + var summary=summarizeReceivableReportByCurrency(rows); + renderReceivableReportSummary(summary); + thead.innerHTML=buildReceivableReportHeader(monthKey); + var title=document.getElementById('ardr-table-title'); + if(title)title.textContent='应收款明细'; + var count=document.getElementById('ardr-table-count'); + if(count)count.textContent='共 '+rows.length+' 个应收单位 · 金额按原币种统计'; + if(!rows.length){tbody.innerHTML='暂无匹配的应收款明细';return;} + var body=rows.map(function(row,index){ + var cells=''+(index+1)+''+escapeReceivableReportText(row.receivableEntity)+''+escapeReceivableReportText(row.currency)+''; + cells+=''+((row.month.direct===null)?'—':receivableReportCellAmount(row.month.direct))+''+((row.month.special===null)?'—':receivableReportCellAmount(row.month.special))+''; + cells+=''+receivableReportCellAmount(row.receivableAmount)+''+receivableReportCellAmount(row.receivedAmount)+''+receivableReportCellAmount(row.deductionAmount)+''+receivableReportCellAmount(row.balanceAmount)+''+escapeReceivableReportText(row.customer||'—')+''+escapeReceivableReportText(row.remark||'—')+''; + return ''+cells+''; + }).join(''); + Object.keys(summary).sort().forEach(function(currencyKey){ + var matching=rows.filter(function(row){return row.currency===currencyKey;}); + if(!matching.length)return; + var monthTotal=matching.reduce(function(total,row){return {direct:total.direct+(row.month.direct||0),special:total.special+(row.month.special||0)};},{direct:0,special:0}); + var total=summary[currencyKey],cells=''+currencyKey+' 合计'; + cells+=''+receivableReportCellAmount(monthTotal.direct)+''+receivableReportCellAmount(monthTotal.special)+''; + cells+=''+receivableReportCellAmount(total.receivable)+''+receivableReportCellAmount(total.received)+''+receivableReportCellAmount(total.deduction)+''+receivableReportCellAmount(total.balance)+'———'; + body+=''+cells+''; + }); + tbody.innerHTML=body; +} +function openReceivableReportEdit(index){ + var record=receivableDetailReportData[index]; + if(!record)return; + receivableReportEditingIndex=index; + var entity=document.getElementById('ardr-edit-entity'); + var customer=document.getElementById('ardr-edit-customer'); + var remark=document.getElementById('ardr-edit-remark'); + if(entity)entity.value=record.receivableEntity||''; + if(customer)customer.value=record.customer||''; + if(remark)remark.value=record.remark||''; + showModal('modal-receivable-report-edit'); + if(customer)setTimeout(function(){customer.focus();},0); +} +function saveReceivableReportEdit(){ + var record=receivableDetailReportData[receivableReportEditingIndex]; + var customer=document.getElementById('ardr-edit-customer'); + var remark=document.getElementById('ardr-edit-remark'); + var customerValue=customer?customer.value.trim():''; + var remarkValue=remark?remark.value.trim():''; + if(!customerValue){showToast('请输入客户','warning');if(customer)customer.focus();return;} + if(customerValue.length>50){showToast('客户最多输入 50 个字符','warning');if(customer)customer.focus();return;} + if(remarkValue.length>200){showToast('备注最多输入 200 个字符','warning');if(remark)remark.focus();return;} + if(!updateReceivableReportEditableFields(record,customerValue,remarkValue))return; + hideModal('modal-receivable-report-edit'); + receivableReportEditingIndex=-1; + renderReceivableDetailReport(); + showToast('应收款明细已更新','success'); +} +function resetReceivableDetailReportFilters(){ + var month=document.getElementById('ardr-month'),entity=document.getElementById('ardr-entity'),currency=document.getElementById('ardr-currency'); + if(month)month.value='2026-07'; + if(entity)entity.value=''; + if(currency)currency.value=''; + renderReceivableDetailReport(); +} +function printReceivableDetailReport(){showToast('正在打开打印预览','info');} +function exportReceivableDetailReport(){showToast('应收款统计表已导出','success');} + +var currentArapFormIndex=-1; +var currentArapAuditIndex=-1; +function setArapFormValue(id,value){var el=document.getElementById(id);if(el)el.value=value==null?'':value;} +function getArapFormValue(id){var el=document.getElementById(id);return el?el.value.trim():'';} +function openArapForm(index){ + var hasIndex=typeof index==='number'&&index>=0; + if(hasIndex){ + var record=arapData[index]; + if(!record)return; + var state=getArapActionState(record.auditStatus); + if(!state.canEdit){showToast('审核通过的记录不可编辑','warning');return;} + currentArapFormIndex=index; + document.getElementById('arap-form-title').textContent='编辑客户应收应付'; + [['arap-form-customer',record.customer],['arap-form-join-settle',record.joinSettle],['arap-form-type',record.arAp],['arap-form-wh-code',record.whCode],['arap-form-order-status',record.orderStatus],['arap-form-dispatch-no',record.dispatchNo],['arap-form-fee-type',record.feeType],['arap-form-amount',record.amount],['arap-form-container-no',record.containerNo],['arap-form-cabinet-no',record.cabinetNo]].forEach(function(pair){setArapFormValue(pair[0],pair[1]);}); + }else{ + currentArapFormIndex=-1; + document.getElementById('arap-form-title').textContent='新增客户应收应付'; + ['arap-form-customer','arap-form-join-settle','arap-form-type','arap-form-wh-code','arap-form-order-status','arap-form-dispatch-no','arap-form-fee-type','arap-form-amount','arap-form-container-no','arap-form-cabinet-no'].forEach(function(id){setArapFormValue(id,'');}); + } + setArapFormValue('arap-form-index',currentArapFormIndex); + showModal('modal-arap-form'); +} +function saveArapForm(){ + var required=[['arap-form-customer','客户公司名'],['arap-form-join-settle','参与结算'],['arap-form-type','应收/应付'],['arap-form-wh-code','入仓码'],['arap-form-order-status','订单状态'],['arap-form-fee-type','费用类型'],['arap-form-amount','金额']]; + for(var i=0;i=0){ + var existing=arapData[currentArapFormIndex]; + if(!existing||!getArapActionState(existing.auditStatus).canEdit){showToast('审核通过的记录不可编辑','warning');hideModal('modal-arap-form');return;} + Object.keys(values).forEach(function(key){existing[key]=values[key];}); + existing.auditStatus=getArapStatusAfterSave('edit'); + appendArapLog(existing,'编辑记录','待审核','修改后重新提交审核'); + showToast('编辑成功,已提交审核','success'); + }else{ + var record=Object.assign({billNo:'',auditStatus:getArapStatusAfterSave('new'),logs:[]},values); + arapData.unshift(record); + appendArapLog(record,'新增记录','待审核','新增后提交审核'); + currentArapDetailIndex=0; + showToast('新增成功,已提交审核','success'); + } + hideModal('modal-arap-form'); + renderArap(); + if(currentArapDetailIndex>=0&&document.getElementById('page-customer-arap-detail').classList.contains('active'))renderArapDetail(); +} +function openArapAudit(index){ + var record=arapData[index]; + if(!record)return; + var state=getArapActionState(record.auditStatus); + if(!state.canAudit){showToast('当前状态不可审核','warning');return;} + currentArapAuditIndex=index; + setArapFormValue('arap-audit-index',index); + document.getElementById('arap-audit-doc-no').textContent=arapDetailDocumentNo(index,record); + document.getElementById('arap-audit-customer').textContent=record.customer||'—'; + document.getElementById('arap-audit-fee-type').textContent=record.feeType||'—'; + document.getElementById('arap-audit-amount').textContent=record.amount||'—'; + document.getElementById('arap-audit-status').textContent=record.auditStatus; + setArapFormValue('arap-audit-remark',''); + setArapFormValue('arap-audit-reject-reason',''); + showModal('modal-arap-audit'); +} +function submitArapAudit(action){ + var record=arapData[currentArapAuditIndex]; + if(!record||!getArapActionState(record.auditStatus).canAudit){showToast('当前状态不可审核','warning');return;} + var rejectReason=getArapFormValue('arap-audit-reject-reason'); + if(action==='reject'&&!rejectReason){showToast('驳回原因不能为空','error');return;} + var result=getArapAuditStatus(action); + record.auditStatus=result; + appendArapLog(record,action==='pass'?'财务审核':'财务驳回',result,action==='pass'?getArapFormValue('arap-audit-remark'):rejectReason); + hideModal('modal-arap-audit'); + renderArap(); + if(document.getElementById('page-customer-arap-detail').classList.contains('active'))renderArapDetail(); + showToast(action==='pass'?'审核通过,记录已锁定':'审核已驳回,可编辑后重新提交',action==='pass'?'success':'warning'); } var currentArapDetailIndex=-1; @@ -10166,7 +12372,8 @@ function renderArapDetail(){ var d=arapData[currentArapDetailIndex]; if(!d)return; var docNo=arapDetailDocumentNo(currentArapDetailIndex,d); - var auditClass={'财务通过':'tag-green','客服提交':'tag-blue','新增':'tag-orange'}[d.auditStatus]||'tag-gray'; + var actionState=getArapActionState(d.auditStatus); + var auditClass={'审核通过':'tag-green','待审核':'tag-orange','审核驳回':'tag-red'}[d.auditStatus]||'tag-gray'; document.getElementById('arap-detail-nav-no').textContent=docNo; document.getElementById('arap-detail-title').textContent='费用单据详情 · '+docNo; var auditBadge=document.getElementById('arap-detail-audit-badge'); @@ -10181,32 +12388,32 @@ function renderArapDetail(){ document.getElementById('arap-detail-join').textContent=d.joinSettle||'否'; document.getElementById('arap-detail-join').style.color=d.joinSettle==='是'?'#16a34a':'#ef4444'; document.getElementById('arap-detail-audit').textContent=d.auditStatus||'—'; - document.getElementById('arap-detail-audit').style.color=d.auditStatus==='财务通过'?'#16a34a':d.auditStatus==='客服提交'?'#1677ff':'#d97706'; - document.getElementById('arap-detail-audit-btn').style.display=d.auditStatus==='财务通过'?'none':'inline-flex'; + document.getElementById('arap-detail-audit').style.color=d.auditStatus==='审核通过'?'#16a34a':d.auditStatus==='审核驳回'?'#dc2626':'#d97706'; + document.getElementById('arap-detail-edit-btn').style.display=actionState.canEdit?'inline-flex':'none'; + document.getElementById('arap-detail-audit-btn').style.display=actionState.canAudit?'inline-flex':'none'; - var basic=[['费用单号',docNo],['客户公司',d.customer],['应收/应付',d.arAp],['费用类型',d.feeType],['参与结算',d.joinSettle],['审核状态',d.auditStatus],['账单编号',d.billNo||'暂未生成'],['费用来源','业务系统自动生成']]; + var basic=[['费用单号',docNo],['客户公司',d.customer],['应收/应付',d.arAp],['费用类型',d.feeType],['金额',d.amount],['参与结算',d.joinSettle],['审核状态',d.auditStatus],['账单编号',d.billNo||'暂未生成'],['费用来源','业务系统自动生成']]; document.getElementById('arap-detail-basic').innerHTML=basic.map(function(item){return '
'+item[0]+''+item[1]+'
';}).join(''); - var steps=[{name:'费用已生成',done:true,desc:'业务单据触发费用生成'},{name:'客服已提交',done:d.auditStatus!=='新增',desc:d.auditStatus==='新增'?'等待客服确认':'费用信息已提交财务'},{name:'财务已审核',done:d.auditStatus==='财务通过',desc:d.auditStatus==='财务通过'?'审核通过,可参与对账':'等待财务审核'}]; + var steps=[{name:'费用已生成',done:true,desc:'业务单据触发费用生成'},{name:'待财务审核',done:d.auditStatus!=='待审核',desc:d.auditStatus==='待审核'?'等待财务审核':'审核已处理'},{name:'财务审核结果',done:d.auditStatus!=='待审核',desc:d.auditStatus==='审核通过'?'审核通过,记录已锁定':d.auditStatus==='审核驳回'?'审核驳回,可编辑后重新提交':'等待审核结果'}]; document.getElementById('arap-detail-timeline').innerHTML=steps.map(function(step,i){return '
'+(step.done?'✓':'·')+''+(i':'')+'
'+step.name+'
'+step.desc+'
';}).join(''); document.getElementById('tbody-arap-detail-business').innerHTML=''+(d.whCode||'—')+''+(d.orderStatus||'—')+''+(d.dispatchNo||'—')+''+(d.containerNo||'—')+''+(d.cabinetNo||'—')+''+(d.billNo||'暂未生成')+''; - var baseDay=String(10+currentArapDetailIndex).padStart(2,'0'); - var logs=[{time:'2026-07-'+baseDay+' 09:20',node:'生成费用',operator:'系统',result:'成功',remark:'由业务单据自动生成'}]; - if(d.auditStatus!=='新增')logs.push({time:'2026-07-'+baseDay+' 10:05',node:'客服提交',operator:'客服专员',result:'已提交',remark:'费用信息核对完成'}); - if(d.auditStatus==='财务通过')logs.push({time:'2026-07-'+baseDay+' 14:30',node:'财务审核',operator:'财务专员',result:'审核通过',remark:'允许参与结算'}); - document.getElementById('tbody-arap-detail-log').innerHTML=logs.map(function(log){return ''+log.time+''+log.node+''+log.operator+''+log.result+''+log.remark+'';}).join(''); + var logs=Array.isArray(d.logs)?d.logs:[]; + var resultClass={成功:'tag-green','待审核':'tag-orange','审核通过':'tag-green','审核驳回':'tag-red','已提交':'tag-blue'}; + document.getElementById('tbody-arap-detail-log').innerHTML=logs.map(function(log){return ''+log.time+''+log.node+''+log.operator+''+log.result+''+log.remark+'';}).join('')||'暂无操作记录'; } // ============ 客户对账单 ============ var customerReconStmtData=[ -{id:'Y2607095',status:'待审核',customer:'杭州恺予科技有限公司',startDate:'2026-07-21',endDate:'2026-08-20',period:7,currency:'CNY',rate:6.8,totalAr:86809.8,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-21 14:14:22',updater:'叶珊珊',updateDate:'2026-07-21 14:14:22'}, -{id:'Y2607093',status:'待审核',customer:'义乌市恒瑞网络科技有限公司',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:583.43,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:07:59',updater:'叶珊珊',updateDate:'2026-07-13 18:07:59'}, -{id:'Y2607091',status:'待审核',customer:'义乌市恒瑞电子商务商行',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:7049.7,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:07:17',updater:'叶珊珊',updateDate:'2026-07-13 18:07:17'}, -{id:'Y2607089',status:'待审核',customer:'义乌市飞骥电子商务有限公司',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:5743.4,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:06:06',updater:'叶珊珊',updateDate:'2026-07-13 18:06:06'}, -{id:'Y2607087',status:'待审核',customer:'上海驿道电子商务有限公司',startDate:'2026-07-08',endDate:'2026-08-07',period:7,currency:'CNY',rate:6.8,totalAr:488848.6,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-08 10:30:41',updater:'叶珊珊',updateDate:'2026-07-08 10:30:41'}, -{id:'Y2607085',status:'审核通过',customer:'深圳市前海环球物流有限公司',startDate:'2026-07-05',endDate:'2026-08-04',period:7,currency:'CNY',rate:6.8,totalAr:125600,paidAr:80000,lastPayTime:'2026-07-15 10:30:00',settled:'否',invoiceDate:'2026-07-10',remark:'',creator:'李明',createDate:'2026-07-05 09:15:22',updater:'李明',updateDate:'2026-07-15 11:20:33'}, -{id:'Y2607083',status:'审核拒绝',customer:'宁波海联进出口有限公司',startDate:'2026-07-01',endDate:'2026-07-31',period:7,currency:'CNY',rate:6.8,totalAr:45600,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'数据有误',creator:'王芳',createDate:'2026-07-01 16:42:10',updater:'王芳',updateDate:'2026-07-02 09:10:15'} +{id:'Y2607095',status:'待审核',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'杭州恺予科技有限公司',startDate:'2026-07-21',endDate:'2026-08-20',period:7,currency:'CNY',rate:6.8,totalAr:86809.8,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-21 14:14:22',updater:'叶珊珊',updateDate:'2026-07-21 14:14:22'}, +{id:'Y2607093',status:'待审核',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'义乌市恒瑞网络科技有限公司',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:583.43,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:07:59',updater:'叶珊珊',updateDate:'2026-07-13 18:07:59'}, +{id:'Y2607091',status:'待审核',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'义乌市恒瑞电子商务商行',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:7049.7,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:07:17',updater:'叶珊珊',updateDate:'2026-07-13 18:07:17'}, +{id:'Y2607089',status:'待审核',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'义乌市飞骥电子商务有限公司',startDate:'2026-07-13',endDate:'2026-08-12',period:7,currency:'CNY',rate:6.8,totalAr:5743.4,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-13 18:06:06',updater:'叶珊珊',updateDate:'2026-07-13 18:06:06'}, +{id:'Y2607087',status:'待审核',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'上海驿道电子商务有限公司',startDate:'2026-07-08',endDate:'2026-08-07',period:7,currency:'CNY',rate:6.8,totalAr:488848.6,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'',creator:'叶珊珊',createDate:'2026-07-08 10:30:41',updater:'叶珊珊',updateDate:'2026-07-08 10:30:41'}, +{id:'Y2607085',status:'审核通过',customerConfirmStatus:'待确认',pushTime:'2026-08-14 10:20:00',confirmTime:'',settlementId:'',customer:'深圳市前海环球物流有限公司',startDate:'2026-07-05',endDate:'2026-08-04',period:7,currency:'CNY',rate:6.8,totalAr:125600,paidAr:80000,lastPayTime:'2026-07-15 10:30:00',settled:'否',invoiceDate:'2026-07-10',remark:'',creator:'李明',createDate:'2026-07-05 09:15:22',updater:'李明',updateDate:'2026-07-15 11:20:33'}, +{id:'Y2607084',status:'审核通过',customerConfirmStatus:'已确认',pushTime:'2026-08-13 14:10:00',confirmTime:'2026-08-14 09:35:00',settlementId:'',customer:'浙江柏悦贸易有限公司',startDate:'2026-07-01',endDate:'2026-07-31',period:30,currency:'CNY',rate:6.8,totalAr:98000,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'客户已确认',creator:'叶珊珊',createDate:'2026-08-13 13:42:00',updater:'叶珊珊',updateDate:'2026-08-14 09:35:00'}, +{id:'Y2607083',status:'审核拒绝',customerConfirmStatus:'未推送',pushTime:'',confirmTime:'',settlementId:'',customer:'宁波海联进出口有限公司',startDate:'2026-07-01',endDate:'2026-07-31',period:7,currency:'CNY',rate:6.8,totalAr:45600,paidAr:0,lastPayTime:'',settled:'否',invoiceDate:'',remark:'数据有误',creator:'王芳',createDate:'2026-07-01 16:42:10',updater:'王芳',updateDate:'2026-07-02 09:10:15'} ]; var reconStmtDetailData={ @@ -10245,10 +12452,104 @@ var reconStmtPayData={ var reconStmtSelectedId=''; +function getReconStmtActionState(record){ + var hasSettlement=!!(record&&record.settlementId); + return { + canPush:!!record&&record.status==='审核通过'&&record.customerConfirmStatus!=='已确认', + canSettle:!!record&&record.customerConfirmStatus==='已确认'&&!hasSettlement, + hasSettlement:hasSettlement + }; +} + +function markReconStmtPushed(record,time){ + if(!getReconStmtActionState(record).canPush)return false; + record.customerConfirmStatus='待确认'; + record.pushTime=time; + record.updateDate=time; + record.updater='财务专员'; + return true; +} + +function buildSettlementFromReconStmt(record,settlementId,date){ + if(!getReconStmtActionState(record).canSettle)return null; + var received=Number(record.paidAr||0); + var total=Number(record.totalAr||0); + return { + id:settlementId, + customer:record.customer, + feeType:'客户对账', + currency:record.currency, + arAmount:total, + received:received, + balance:Math.max(0,total-received), + billNo:record.id, + period:record.startDate+' ~ '+record.endDate, + genDate:date, + dueDate:record.endDate, + payStatus:received>0?'部分收款':'待收款', + approveStatus:'草稿', + creator:'财务专员', + reviewer:'', + status:'草稿' + }; +} + +function reconStmtNowText(){ + return new Date().toLocaleString('zh-CN',{hour12:false}).replace(/\//g,'-'); +} + +function nextReconSettlementId(){ + var stamp=new Date().toISOString().slice(0,10).replace(/-/g,''); + var sequence=String(settlementArData.length+1).padStart(3,'0'); + return 'SAR-'+stamp+'-'+sequence; +} + +function pushReconStmtToCustomer(id){ + var record=customerReconStmtData.find(function(item){return item.id===id;}); + if(!record){showToast('未找到对账单','error');return;} + if(!markReconStmtPushed(record,reconStmtNowText())){ + showToast(record.status!=='审核通过'?'审核通过后才可推送':'客户已确认,无需再次推送','warning'); + return; + } + renderCustomerReconStmt(); + showToast('对账单已推送给客户,等待客户确认','success'); +} + +function createSettlementFromReconStmt(id){ + var record=customerReconStmtData.find(function(item){return item.id===id;}); + if(!record){showToast('未找到对账单','error');return;} + if(record.settlementId){ + showToast('该对账单已生成结算单 '+record.settlementId,'info'); + switchPage('settlement-ar'); + renderSettlementAr(); + return; + } + if(!getReconStmtActionState(record).canSettle){ + showToast('客户确认后才可结算','warning'); + return; + } + var date=new Date().toISOString().slice(0,10); + var settlement=buildSettlementFromReconStmt(record,nextReconSettlementId(),date); + if(!settlement){showToast('客户确认后才可结算','warning');return;} + settlementArData.unshift(settlement); + record.settlementId=settlement.id; + record.updateDate=reconStmtNowText(); + record.updater='财务专员'; + renderCustomerReconStmt(); + switchPage('settlement-ar'); + renderSettlementAr(); + showToast('结算单已生成:'+settlement.id,'success'); +} + function renderCustomerReconStmt(){ var tb=document.getElementById('tbody-customer-recon-stmt'); if(!tb)return; var statusMap={'待审核':'color:#faad14;background:#fffbe6;border:1px solid #ffe58f;padding:1px 6px;border-radius:4px;font-size:11px','审核通过':'color:#52c41a;background:#f6ffed;border:1px solid #b7eb8f;padding:1px 6px;border-radius:4px;font-size:11px','审核拒绝':'color:#f5222d;background:#fff2f0;border:1px solid #ffccc7;padding:1px 6px;border-radius:4px;font-size:11px','待确认':'color:#1890ff;background:#e6f7ff;border:1px solid #91d5ff;padding:1px 6px;border-radius:4px;font-size:11px'}; +var confirmMap={ +'未推送':'color:#64748b;background:#f1f5f9;border:1px solid #cbd5e1;padding:1px 6px;border-radius:4px;font-size:11px', +'待确认':'color:#d97706;background:#fffbeb;border:1px solid #fde68a;padding:1px 6px;border-radius:4px;font-size:11px', +'已确认':'color:#16a34a;background:#f0fdf4;border:1px solid #bbf7d0;padding:1px 6px;border-radius:4px;font-size:11px' +}; var qStatus=document.getElementById('rsq-status').value; var qBillno=(document.getElementById('rsq-billno').value||'').trim().toLowerCase(); var qCustomer=(document.getElementById('rsq-customer').value||'').trim().toLowerCase(); @@ -10260,15 +12561,28 @@ if(qCustomer && !d.customer.toLowerCase().includes(qCustomer))return; count++; var checked=reconStmtSelectedId===d.id?' checked':''; var unpaid=d.totalAr-d.paidAr; +var actionState=getReconStmtActionState(d); +var actions=''+ +''+ +''; +if(d.status==='待审核'){ +actions+=''+ +''; +} +if(d.status==='审核通过'&&d.customerConfirmStatus!=='已确认'){ +actions+=''; +} +if(actionState.hasSettlement){ +actions+=''; +}else{ +actions+=''; +} rows+=''+ -''+ -''+ -'导出账单明细'+ -'删除'+ -'审核通过'+ -'审核拒绝'+ -''+ +''+actions+''+ ''+d.status+''+ +''+d.customerConfirmStatus+''+ ''+d.id+''+ ''+d.customer+''+ ''+d.startDate+''+ @@ -10288,7 +12602,7 @@ rows+=''+ ''+d.updateDate+''+ ''; }); -tb.innerHTML=rows||'暂无匹配数据'; +tb.innerHTML=rows||'暂无匹配数据'; document.getElementById('recon-stmt-pagination').innerHTML='共 '+count+' 条...5条/页跳至页'; renderReconStmtDetail(); renderReconStmtPay(); @@ -10433,14 +12747,16 @@ function renderSettlementAr(){ if(cur!=='全部币种'&&d.currency!==cur)return null; if(no&&!d.id.toLowerCase().includes(no)&&!d.billNo.toLowerCase().includes(no))return null; totalAr+=d.arAmount;totalRec+=d.received;totalBal+=d.balance; + var voucherCount=Array.isArray(d.paymentVouchers)?d.paymentVouchers.length:0; + var voucherText='上传付款凭证'+(voucherCount?'('+voucherCount+')':''); return ''+ ''+ '详情 '+ + ' '+ (d.balance>0&&d.status==='生效'?'':'')+''+ ''+d.id+''+ ''+d.customer+''+ - ''+d.feeType+''+ - ''+d.currency+''+ + ''+d.currency+''+ ''+(d.currency==='USD'?'$':'¥')+d.arAmount.toLocaleString()+''+ ''+(d.currency==='USD'?'$':'¥')+d.received.toLocaleString()+''+ ''+(d.currency==='USD'?'$':'¥')+d.balance.toLocaleString()+''+ @@ -10455,7 +12771,7 @@ function renderSettlementAr(){ ''+d.status+''+ ''; }).filter(Boolean); - tb.innerHTML=rows.length?rows.join(''):'暂无匹配数据'; + tb.innerHTML=rows.length?rows.join(''):'暂无匹配数据'; document.getElementById('sar-total').textContent='¥'+totalAr.toLocaleString(); document.getElementById('sar-received').textContent='¥'+totalRec.toLocaleString(); document.getElementById('sar-pending').textContent='¥'+totalBal.toLocaleString(); @@ -10479,29 +12795,35 @@ var settlementApData=[ function renderSettleAp(){ var tb=document.getElementById('tbody-settle-ap'); if(!tb)return; - var status=document.getElementById('sap-status')?document.getElementById('sap-status').value:'全部状态'; + var status=document.getElementById('sap-status')?document.getElementById('sap-status').value:'全部付款状态'; var supplier=document.getElementById('sap-supplier')?document.getElementById('sap-supplier').value:'全部供应商'; var currency=document.getElementById('sap-currency')?document.getElementById('sap-currency').value:'全部币种'; var no=(document.getElementById('sap-no')?document.getElementById('sap-no').value:'').trim().toLowerCase(); var payCls={'已结清':'tag-green','部分付款':'tag-orange','待付款':'tag-red'}; - var approveCls={'已审批':'tag-green','审批中':'tag-orange','草稿':'tag-gray'}; + var approveCls={'已审批':'tag-green','审批中':'tag-orange','已驳回':'tag-red','草稿':'tag-gray'}; var statusCls={'生效':'tag-green','待审批':'tag-orange','草稿':'tag-gray'}; var total=0,paid=0,balance=0,profit=0; var rows=settlementApData.map(function(d){ - if(status!=='全部状态'&&d.payStatus!==status)return null; + if(status!=='全部付款状态'&&d.payStatus!==status)return null; if(supplier!=='全部供应商'&&d.supplier!==supplier)return null; if(currency!=='全部币种'&&d.currency!==currency)return null; if(no&&!d.id.toLowerCase().includes(no)&&!d.billNo.toLowerCase().includes(no))return null; total+=d.apAmount;paid+=d.paid;balance+=d.balance;profit+=d.profitAmount||0; var symbol=d.currency==='USD'?'$':'¥'; + var voucherCount=Array.isArray(d.paymentVouchers)?d.paymentVouchers.length:0; + var voucherText='上传付款凭证'+(voucherCount?'('+voucherCount+')':''); + var actionHtml='详情 '+ + ' '+ + ' '+ + (d.balance>0&&d.status==='生效'?'':''); return ''+ - '详情 '+(d.balance>0&&d.status==='生效'?'':'')+''+d.id+''+d.supplier+''+d.feeType+''+d.currency+''+ + ''+actionHtml+''+d.id+''+d.supplier+''+d.currency+''+ ''+symbol+d.apAmount.toLocaleString()+''+symbol+d.paid.toLocaleString()+''+symbol+d.balance.toLocaleString()+''+ ''+d.billNo+''+d.period+''+d.genDate+''+d.dueDate+''+ ''+d.payStatus+''+d.approveStatus+''+ ''+d.hasProfit+''+symbol+(d.profitAmount||0).toLocaleString()+''+d.creator+''+(d.reviewer||'-')+''+d.status+''; }).filter(Boolean); - tb.innerHTML=rows.length?rows.join(''):'暂无匹配数据'; + tb.innerHTML=rows.length?rows.join(''):'暂无匹配数据'; document.getElementById('sap-total').textContent='¥'+total.toLocaleString(); document.getElementById('sap-paid').textContent='¥'+paid.toLocaleString(); document.getElementById('sap-pending').textContent='¥'+balance.toLocaleString(); @@ -10516,6 +12838,187 @@ function resetSettlementAp(){ renderSettleAp(); } +var currentSettlementVoucher=null; +var settlementApVoucherDraft=[]; +var settlementApVoucherOriginalCount=0; +var currentSettlementApApprovalId=''; + +function getSettlementApApprovalActionState(status){ + var readonly=status==='已审批'; + return {canSubmit:!readonly,readonly:readonly}; +} + +function getSettlementApApprovalResult(action){ + return action==='pass'?{approveStatus:'已审批',status:'生效'}:{approveStatus:'已驳回',status:'待审批'}; +} + +function formatSettlementApVoucherSize(size){ + var bytes=Number(size||0); + if(bytes<1024)return bytes+' B'; + if(bytes<1024*1024)return (bytes/1024).toFixed(1)+' KB'; + return (bytes/1024/1024).toFixed(1)+' MB'; +} + +function escapeSettlementApHtml(value){ + return String(value==null?'':value).replace(/[&<>"']/g,function(char){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[char];}); +} + +function validateSettlementApVoucherFile(file,existing){ + var allowedExtensions=['pdf','jpg','jpeg','png']; + var allowedTypes=['application/pdf','image/jpeg','image/png']; + var name=String(file&&file.name||'').trim(); + var extension=(name.split('.').pop()||'').toLowerCase(); + if(allowedExtensions.indexOf(extension)<0||(file.type&&allowedTypes.indexOf(file.type)<0))return name+' 格式不支持,仅支持 PDF、JPG、JPEG、PNG'; + if(Number(file.size||0)>10 * 1024 * 1024)return name+' 超过 10MB,无法添加'; + if((existing||[]).some(function(item){return String(item.name||'').toLowerCase()===name.toLowerCase();}))return name+' 已存在,请勿重复上传'; + return ''; +} + +function createSettlementApVoucherEntry(file,uploadedAt){ + var extension=(String(file.name||'').split('.').pop()||'').toLowerCase(); + return {name:file.name,size:Number(file.size||0),type:file.type||extension.toUpperCase(),uploadedAt:uploadedAt,uploader:'王建国'}; +} + +function getSettlementVoucherPartyLabel(type){ + return type==='ar'?'客户公司':'供应商'; +} + +function settlementVoucherRecord(){ + if(!currentSettlementVoucher)return null; + var list=currentSettlementVoucher.type==='ar'?settlementArData:settlementApData; + return list.find(function(item){return item.id===currentSettlementVoucher.id;})||null; +} + +function openSettlementVoucher(type,id){ + currentSettlementVoucher={type:type,id:id}; + var record=settlementVoucherRecord(); + if(!record)return; + settlementApVoucherDraft=(record.paymentVouchers||[]).map(function(file){return Object.assign({},file);}); + settlementApVoucherOriginalCount=settlementApVoucherDraft.length; + document.getElementById('settlement-ap-voucher-no').textContent=record.id; + document.getElementById('settlement-voucher-party-label').textContent=getSettlementVoucherPartyLabel(type); + document.getElementById('settlement-ap-voucher-supplier').textContent=type==='ar'?record.customer:record.supplier; + document.getElementById('settlement-ap-voucher-files').value=''; + renderSettlementApVoucherList(); + showModal('modal-settlement-ap-voucher'); +} + +function openSettlementArVoucher(id){ + openSettlementVoucher('ar',id); +} + +function openSettlementApVoucher(id){ + openSettlementVoucher('ap',id); +} + +function handleSettlementApVoucherFiles(files){ + Array.prototype.forEach.call(files||[],function(file){ + var error=validateSettlementApVoucherFile(file,settlementApVoucherDraft); + if(error){ + showToast(error,'error'); + return; + } + settlementApVoucherDraft.push(createSettlementApVoucherEntry(file,new Date().toLocaleString('zh-CN',{hour12:false}))); + }); + var input=document.getElementById('settlement-ap-voucher-files'); + if(input)input.value=''; + renderSettlementApVoucherList(); +} + +function renderSettlementApVoucherList(){ + var list=document.getElementById('settlement-ap-voucher-list'); + if(!list)return; + var count=document.getElementById('settlement-voucher-count'); + if(count)count.textContent=settlementApVoucherDraft.length; + if(!settlementApVoucherDraft.length){ + list.innerHTML='
暂未上传付款凭证
'; + return; + } + list.innerHTML=settlementApVoucherDraft.map(function(file,index){ + return '
'+escapeSettlementApHtml(file.name)+'
'+formatSettlementApVoucherSize(file.size)+' · '+escapeSettlementApHtml(file.type||'未知类型')+' · '+escapeSettlementApHtml(file.uploadedAt||'')+' · '+escapeSettlementApHtml(file.uploader||'')+'
'; + }).join(''); +} + +function removeSettlementApVoucher(index){ + settlementApVoucherDraft.splice(index,1); + renderSettlementApVoucherList(); +} + +function saveSettlementApVouchers(){ + var record=settlementVoucherRecord(); + if(!record)return; + if(!settlementApVoucherDraft.length&&!settlementApVoucherOriginalCount){ + showToast('请先选择付款凭证','error'); + return; + } + record.paymentVouchers=settlementApVoucherDraft.map(function(file){return Object.assign({},file);}); + var isAr=currentSettlementVoucher.type==='ar'; + closeSettlementApVoucher(); + if(isAr)renderSettlementAr();else renderSettleAp(); + if(document.getElementById('page-settlement-detail').classList.contains('active'))renderSettlementDetail(); + showToast('付款凭证保存成功','success'); +} + +function closeSettlementApVoucher(){ + hideModal('modal-settlement-ap-voucher'); + currentSettlementVoucher=null; + settlementApVoucherDraft=[]; + settlementApVoucherOriginalCount=0; +} + +function openSettlementApApproval(id){ + currentSettlementApApprovalId=id; + var record=settlementApData.find(function(item){return item.id===id;}); + if(!record)return; + var symbol=record.currency==='USD'?'$':'¥'; + var actionState=getSettlementApApprovalActionState(record.approveStatus); + document.getElementById('settlement-ap-approval-no').textContent=record.id; + document.getElementById('settlement-ap-approval-supplier').textContent=record.supplier; + document.getElementById('settlement-ap-approval-amount').textContent=symbol+record.apAmount.toLocaleString(); + document.getElementById('settlement-ap-approval-pay-status').textContent=record.payStatus; + document.getElementById('settlement-ap-approval-status').textContent=record.approveStatus; + document.getElementById('settlement-ap-approval-remark').value=record.reviewRemark||''; + document.getElementById('settlement-ap-approval-reject-reason').value=record.rejectReason||''; + document.getElementById('settlement-ap-approval-remark').disabled=actionState.readonly; + document.getElementById('settlement-ap-approval-reject-reason').disabled=actionState.readonly; + var readonlyTip=document.getElementById('settlement-ap-approval-readonly'); + readonlyTip.style.display=actionState.readonly?'block':'none'; + readonlyTip.textContent=actionState.readonly?'该结算单已由 '+(record.reviewer||'审核人')+' 于 '+(record.reviewTime||'—')+' 审批通过,仅可查看审批结果。':''; + document.getElementById('settlement-ap-approval-actions').style.display=actionState.canSubmit?'inline-flex':'none'; + showModal('modal-settlement-ap-approval'); +} + +function submitSettlementApApproval(action){ + var record=settlementApData.find(function(item){return item.id===currentSettlementApApprovalId;}); + if(!record)return; + var actionState=getSettlementApApprovalActionState(record.approveStatus); + if(!actionState.canSubmit){ + showToast('该结算单已审批通过','info'); + return; + } + var rejectReason=document.getElementById('settlement-ap-approval-reject-reason').value.trim(); + if(action==='reject'&&!rejectReason){ + showToast('驳回原因不能为空','error'); + return; + } + var result=getSettlementApApprovalResult(action); + record.approveStatus=result.approveStatus; + record.status=result.status; + record.reviewer='王建国'; + record.reviewTime=new Date().toLocaleString('zh-CN',{hour12:false}); + record.reviewRemark=document.getElementById('settlement-ap-approval-remark').value.trim(); + record.rejectReason=action==='reject'?rejectReason:''; + closeSettlementApApproval(); + renderSettleAp(); + if(document.getElementById('page-settlement-detail').classList.contains('active'))renderSettlementDetail(); + showToast(action==='pass'?'审批通过':'已驳回,可重新审批','success'); +} + +function closeSettlementApApproval(){ + hideModal('modal-settlement-ap-approval'); + currentSettlementApApprovalId=''; +} + var currentSettlementDetail=null; function settlementDetailRecord(){ @@ -10580,7 +13083,14 @@ function renderSettlementDetail(){ ]; document.getElementById('settlement-detail-info').innerHTML=info.map(function(item){return '
'+item[0]+''+item[1]+'
';}).join(''); var approved=record.approveStatus==='已审批'; - document.getElementById('settlement-detail-approval').innerHTML='
✓
结算单已创建
'+record.creator+' · '+record.genDate+'
'+(approved?'✓':'…')+'
'+record.approveStatus+'
'+(record.reviewer||'等待审核人处理')+'
'; + var rejected=record.approveStatus==='已驳回'; + var approvalBg=approved?'#dcfce7':rejected?'#fef2f2':'#fef3c7'; + var approvalColor=approved?'#16a34a':rejected?'#dc2626':'#d97706'; + var approvalIcon=approved?'✓':rejected?'!':'…'; + var approvalMeta=record.reviewer||'等待审核人处理'; + if(record.reviewTime)approvalMeta+=' · '+record.reviewTime; + var rejectReason=rejected&&record.rejectReason?'
驳回原因:'+escapeSettlementApHtml(record.rejectReason)+'
':''; + document.getElementById('settlement-detail-approval').innerHTML='
✓
结算单已创建
'+record.creator+' · '+record.genDate+'
'+approvalIcon+'
'+record.approveStatus+'
'+approvalMeta+'
'+rejectReason+'
'; document.getElementById('settlement-detail-fee-done-label').textContent='已'+action+'金额'; document.getElementById('settlement-detail-fee-summary').textContent='共 1 项费用'; @@ -10917,6 +13427,262 @@ function saveSupplier(){ document.addEventListener('DOMContentLoaded',renderSupplier); renderSupplier(); +// ===== 派送车队报价表 ===== +var deliveryFleetQuoteData=[ + {id:'DFQ001',origin:'洛杉矶, CA',warehouse:'LAX9',miles:42,fleet:'SMART',selfPickup:155,fullDelivery:175,looseDelivery:115,status:'启用',updatedAt:'2026-08-14 10:20',remark:'工作日预约'}, + {id:'DFQ002',origin:'洛杉矶, CA',warehouse:'ONT8',miles:68,fleet:'捷诚',selfPickup:180,fullDelivery:220,looseDelivery:140,status:'启用',updatedAt:'2026-08-13 16:45',remark:'可承接整车与散板'}, + {id:'DFQ003',origin:'芝加哥, IL',warehouse:'MDW2',miles:37,fleet:'纽酷',selfPickup:170,fullDelivery:200,looseDelivery:140,status:'启用',updatedAt:'2026-08-12 09:30',remark:'需提前一天预约'}, + {id:'DFQ004',origin:'芝加哥, IL',warehouse:'ORD2',miles:28,fleet:'隆盛',selfPickup:180,fullDelivery:230,looseDelivery:150,status:'启用',updatedAt:'2026-08-11 14:10',remark:''}, + {id:'DFQ005',origin:'芝加哥, IL',warehouse:'IGQ2',miles:41,fleet:'RIGLL',selfPickup:null,fullDelivery:230,looseDelivery:140,status:'停用',updatedAt:'2026-08-09 11:00',remark:'渠道价格待更新'}, + {id:'DFQ006',origin:'印第安纳波利斯, IN',warehouse:'IND9',miles:52,fleet:'SMART',selfPickup:160,fullDelivery:190,looseDelivery:110,status:'启用',updatedAt:'2026-08-08 15:25',remark:'夜间预约另计'}, + {id:'DFQ007',origin:'达拉斯, TX',warehouse:'FTW1',miles:35,fleet:'Habr',selfPickup:150,fullDelivery:185,looseDelivery:125,status:'启用',updatedAt:'2026-08-07 13:40',remark:''}, + {id:'DFQ008',origin:'纽约, NY',warehouse:'EWR9',miles:31,fleet:'蓝鲸',selfPickup:175,fullDelivery:215,looseDelivery:135,status:'启用',updatedAt:'2026-08-06 17:15',remark:'周末不派送'} +]; +var deliveryFleetQuoteSeq=9; +var deliveryFleetQuoteImportRows=[]; + +function deliveryFleetQuoteNow(){ + var date=new Date(); + var pad=function(value){return String(value).padStart(2,'0');}; + return date.getFullYear()+'-'+pad(date.getMonth()+1)+'-'+pad(date.getDate())+' '+pad(date.getHours())+':'+pad(date.getMinutes()); +} +function deliveryFleetQuoteHasPrice(value){return value!==null&&value!==undefined&&value!=='';} +function escapeDeliveryFleetQuoteHtml(value){ + return String(value==null?'':value).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/\u0027/g,'''); +} +function filterDeliveryFleetQuoteRows(records,filters){ + filters=filters||{}; + var origin=String(filters.origin||'').trim().toLowerCase(); + var warehouse=String(filters.warehouse||'').trim().toLowerCase(); + var fleet=String(filters.fleet||'').trim().toLowerCase(); + var keyword=String(filters.keyword||'').trim().toLowerCase(); + return records.filter(function(record){ + var recordOrigin=String(record.origin||'').toLowerCase(); + var recordWarehouse=String(record.warehouse||'').toLowerCase(); + var recordFleet=String(record.fleet||'').toLowerCase(); + if(origin&&recordOrigin.indexOf(origin)===-1)return false; + if(warehouse&&recordWarehouse.indexOf(warehouse)===-1)return false; + if(fleet&&recordFleet.indexOf(fleet)===-1)return false; + if(keyword&&(recordOrigin+' '+recordWarehouse+' '+recordFleet).indexOf(keyword)===-1)return false; + if(filters.method&&!deliveryFleetQuoteHasPrice(record[filters.method]))return false; + if(filters.status&&record.status!==filters.status)return false; + return true; + }); +} +function validateDeliveryFleetQuoteDraft(data){ + if(!String(data.origin||'').trim())return '请输入发货城市'; + if(!String(data.warehouse||'').trim())return '请输入目的 FBA 仓点'; + if(!String(data.fleet||'').trim())return '请输入车队渠道'; + if(data.miles===null||!Number.isFinite(Number(data.miles))||Number(data.miles)<0)return '请输入有效的非负迈数'; + var prices=[data.selfPickup,data.fullDelivery,data.looseDelivery]; + if(prices.some(function(value){return deliveryFleetQuoteHasPrice(value)&&(!Number.isFinite(Number(value))||Number(value)<0);})){return '报价只能填写非负数字';} + if(!prices.some(deliveryFleetQuoteHasPrice))return '请至少填写一种提货方式报价'; + return ''; +} +function deliveryFleetQuoteKey(record){ + var origin=String(record.origin==null?'':record.origin).trim().toLowerCase().replace(/\s*,\s*[a-z]{2}$/i,''); + return [origin,record.warehouse,Number(record.miles),record.fleet].map(function(value){return String(value==null?'':value).trim().toLowerCase();}).join('|'); +} +function hasDuplicateDeliveryFleetQuote(records,draft,excludeId){ + var key=deliveryFleetQuoteKey(draft); + return records.some(function(record){return record.id!==excludeId&&deliveryFleetQuoteKey(record)===key;}); +} +function splitDeliveryFleetQuoteCsvLine(line){ + var cells=[],value='',quoted=false; + for(var index=0;index=0?String(cells[index]||'').trim():'';}; + var numberValue=function(key,emptyValue){var raw=read(key);if(raw==='')return emptyValue;var value=Number(raw);return Number.isFinite(value)?value:NaN;}; + var data={origin:read('origin'),warehouse:read('warehouse').toUpperCase(),miles:numberValue('miles',null),fleet:read('fleet'),selfPickup:numberValue('selfPickup',null),fullDelivery:numberValue('fullDelivery',null),looseDelivery:numberValue('looseDelivery',null),status:read('status'),remark:read('remark')}; + var errors=[]; + var validationMessage=validateDeliveryFleetQuoteDraft(data); + if(validationMessage)errors.push(validationMessage); + if(data.status!=='启用'&&data.status!=='停用')errors.push('状态仅支持启用或停用'); + if(!errors.length&&hasDuplicateDeliveryFleetQuote(knownRecords,data,''))errors.push('相同维度组合重复'); + if(!errors.length)knownRecords.push(data); + return {row:rowIndex+2,data:data,valid:errors.length===0,error:errors.join(';')}; + }); +} +function formatDeliveryFleetQuotePrice(value){ + return deliveryFleetQuoteHasPrice(value)?'$'+Number(value).toFixed(2):'—'; +} +function renderDeliveryFleetQuotes(){ + var tbody=document.getElementById('tbody-delivery-fleet-quote'); + if(!tbody)return; + var rows=filterDeliveryFleetQuoteRows(deliveryFleetQuoteData,{ + origin:document.getElementById('dfq-search-origin').value, + warehouse:document.getElementById('dfq-search-warehouse').value, + fleet:document.getElementById('dfq-search-fleet').value, + keyword:document.getElementById('dfq-search-keyword').value, + method:document.getElementById('dfq-search-method').value, + status:document.getElementById('dfq-search-status').value + }); + tbody.innerHTML=rows.map(function(record){ + return '' + +'
' + +''+escapeDeliveryFleetQuoteHtml(record.origin)+'' + +''+escapeDeliveryFleetQuoteHtml(record.warehouse)+'' + +''+Number(record.miles).toLocaleString()+' mi' + +''+escapeDeliveryFleetQuoteHtml(record.fleet)+'' + +''+formatDeliveryFleetQuotePrice(record.selfPickup)+'' + +''+formatDeliveryFleetQuotePrice(record.fullDelivery)+'' + +''+formatDeliveryFleetQuotePrice(record.looseDelivery)+'' + +''+escapeDeliveryFleetQuoteHtml(record.status)+'' + +''+escapeDeliveryFleetQuoteHtml(record.updatedAt)+'' + +''+escapeDeliveryFleetQuoteHtml(record.remark||'—')+'' + +''; + }).join('')||'暂无符合条件的派送车队报价'; + document.getElementById('dfq-total').textContent='共 '+rows.length+' 条'; +} +function resetDeliveryFleetQuoteSearch(){ + ['dfq-search-origin','dfq-search-warehouse','dfq-search-fleet','dfq-search-keyword','dfq-search-method','dfq-search-status'].forEach(function(id){var element=document.getElementById(id);if(element)element.value='';}); + renderDeliveryFleetQuotes(); + showToast('筛选条件已重置','info'); +} +function renderDeliveryFleetQuoteImportPreview(){ + var tbody=document.getElementById('tbody-dfq-import-preview'); + var summary=document.getElementById('dfq-import-summary'); + var confirmButton=document.getElementById('dfq-import-confirm'); + if(!tbody||!summary||!confirmButton)return; + var validCount=deliveryFleetQuoteImportRows.filter(function(item){return item.valid;}).length; + var invalidCount=deliveryFleetQuoteImportRows.length-validCount; + summary.innerHTML=deliveryFleetQuoteImportRows.length?'共读取 '+deliveryFleetQuoteImportRows.length+' 条,可导入 '+validCount+' 条,失败 '+invalidCount+' 条':'尚未选择文件'; + tbody.innerHTML=deliveryFleetQuoteImportRows.slice(0,10).map(function(item){ + var data=item.data; + var values=[data.origin,data.warehouse,deliveryFleetQuoteHasPrice(data.miles)?data.miles:'—',data.fleet,deliveryFleetQuoteHasPrice(data.selfPickup)?data.selfPickup:'—',deliveryFleetQuoteHasPrice(data.fullDelivery)?data.fullDelivery:'—',deliveryFleetQuoteHasPrice(data.looseDelivery)?data.looseDelivery:'—',data.status||'—',data.remark||'—']; + return ''+(item.valid?'通过':escapeDeliveryFleetQuoteHtml(item.error))+''+values.map(function(value){return ''+escapeDeliveryFleetQuoteHtml(value)+'';}).join('')+''; + }).join('')||'文件中没有可读取的数据'; + confirmButton.disabled=validCount===0; +} +function openDeliveryFleetQuoteImport(){ + deliveryFleetQuoteImportRows=[]; + var file=document.getElementById('dfq-import-file'); + if(file)file.value=''; + renderDeliveryFleetQuoteImportPreview(); + document.getElementById('tbody-dfq-import-preview').innerHTML='选择文件后显示前 10 条数据'; + showModal('modal-delivery-fleet-quote-import'); +} +function downloadDeliveryFleetQuoteImportTemplate(){ + var headers=['发货城市','目的FBA仓点','迈数','车队渠道','整车自提','整车派送','散板派送','状态','备注']; + var sample=['洛杉矶, CA','LAX9','42','SMART','155','175','115','启用','工作日预约']; + var csv='\ufeff'+[headers,sample].map(function(row){return row.map(csvEscape).join(',');}).join('\r\n'); + downloadCsvFile('派送车队报价导入模板.csv',csv); +} +function handleDeliveryFleetQuoteImportFile(input){ + var file=input&&input.files&&input.files[0]; + if(!file)return; + if(!/\.csv$/i.test(file.name)){ + deliveryFleetQuoteImportRows=[]; + renderDeliveryFleetQuoteImportPreview(); + showToast('请选择 CSV 文件','error'); + return; + } + var reader=new FileReader(); + reader.onload=function(event){deliveryFleetQuoteImportRows=parseDeliveryFleetQuoteCsv(event.target.result,deliveryFleetQuoteData);renderDeliveryFleetQuoteImportPreview();}; + reader.onerror=function(){deliveryFleetQuoteImportRows=[];renderDeliveryFleetQuoteImportPreview();showToast('文件读取失败,请重新选择','error');}; + reader.readAsText(file,'utf-8'); +} +function confirmDeliveryFleetQuoteImport(){ + var successCount=0,failedCount=0; + deliveryFleetQuoteImportRows.forEach(function(item){ + if(!item.valid||hasDuplicateDeliveryFleetQuote(deliveryFleetQuoteData,item.data,'')){failedCount++;return;} + deliveryFleetQuoteData.unshift(Object.assign({id:'DFQ'+String(deliveryFleetQuoteSeq++).padStart(3,'0'),updatedAt:deliveryFleetQuoteNow()},item.data)); + successCount++; + }); + renderDeliveryFleetQuotes(); + hideModal('modal-delivery-fleet-quote-import'); + showToast('导入完成:成功 '+successCount+' 条,失败 '+failedCount+' 条',successCount?'success':'error'); +} +function openDeliveryFleetQuoteModal(id){ + var record=id?deliveryFleetQuoteData.find(function(item){return item.id===id;}):null; + if(id&&!record){showToast('未找到派送车队报价','error');return;} + document.getElementById('dfq-modal-title').textContent=record?'编辑派送车队报价':'新增派送车队报价'; + document.getElementById('dfq-edit-id').value=record?record.id:''; + document.getElementById('dfq-origin').value=record?record.origin:''; + document.getElementById('dfq-warehouse').value=record?record.warehouse:''; + document.getElementById('dfq-miles').value=record?record.miles:''; + document.getElementById('dfq-fleet').value=record?record.fleet:''; + document.getElementById('dfq-self-pickup').value=record&&deliveryFleetQuoteHasPrice(record.selfPickup)?record.selfPickup:''; + document.getElementById('dfq-full-delivery').value=record&&deliveryFleetQuoteHasPrice(record.fullDelivery)?record.fullDelivery:''; + document.getElementById('dfq-loose-delivery').value=record&&deliveryFleetQuoteHasPrice(record.looseDelivery)?record.looseDelivery:''; + document.getElementById('dfq-status').value=record?record.status:'启用'; + document.getElementById('dfq-remark').value=record?record.remark:''; + showModal('modal-delivery-fleet-quote'); +} +function deliveryFleetQuoteNumber(id){ + var raw=(document.getElementById(id).value||'').trim(); + if(raw==='')return null; + var value=Number(raw); + return Number.isFinite(value)&&value>=0?value:NaN; +} +function saveDeliveryFleetQuote(){ + var id=document.getElementById('dfq-edit-id').value; + var origin=document.getElementById('dfq-origin').value.trim(); + var warehouse=document.getElementById('dfq-warehouse').value.trim().toUpperCase(); + var fleet=document.getElementById('dfq-fleet').value.trim(); + var miles=deliveryFleetQuoteNumber('dfq-miles'); + var selfPickup=deliveryFleetQuoteNumber('dfq-self-pickup'); + var fullDelivery=deliveryFleetQuoteNumber('dfq-full-delivery'); + var looseDelivery=deliveryFleetQuoteNumber('dfq-loose-delivery'); + var data={origin:origin,warehouse:warehouse,miles:miles,fleet:fleet,selfPickup:selfPickup,fullDelivery:fullDelivery,looseDelivery:looseDelivery,status:document.getElementById('dfq-status').value,updatedAt:deliveryFleetQuoteNow(),remark:document.getElementById('dfq-remark').value.trim()}; + var validationMessage=validateDeliveryFleetQuoteDraft(data); + if(validationMessage){showToast(validationMessage,'error');return;} + if(hasDuplicateDeliveryFleetQuote(deliveryFleetQuoteData,data,id)){showToast('相同发货城市、目的仓、迈数和车队渠道的报价已存在','error');return;} + if(id){ + var record=deliveryFleetQuoteData.find(function(item){return item.id===id;}); + if(record)Object.assign(record,data); + }else{ + deliveryFleetQuoteData.unshift(Object.assign({id:'DFQ'+String(deliveryFleetQuoteSeq++).padStart(3,'0')},data)); + } + hideModal('modal-delivery-fleet-quote'); + renderDeliveryFleetQuotes(); + showToast(id?'派送车队报价修改成功':'派送车队报价新增成功','success'); +} +function toggleDeliveryFleetQuoteStatus(id){ + var record=deliveryFleetQuoteData.find(function(item){return item.id===id;}); + if(!record)return; + record.status=record.status==='启用'?'停用':'启用'; + record.updatedAt=deliveryFleetQuoteNow(); + renderDeliveryFleetQuotes(); + showToast('报价已'+record.status,'success'); +} +function deleteDeliveryFleetQuote(id){ + var record=deliveryFleetQuoteData.find(function(item){return item.id===id;}); + if(!record)return; + if(!confirm('确定删除“'+record.origin+' → '+record.warehouse+' / '+record.fleet+'”报价吗?'))return; + deliveryFleetQuoteData=deliveryFleetQuoteData.filter(function(item){return item.id!==id;}); + renderDeliveryFleetQuotes(); + showToast('派送车队报价已删除','success'); +} +document.addEventListener('DOMContentLoaded',renderDeliveryFleetQuotes); +renderDeliveryFleetQuotes(); + // ===== 海外用户管理 ===== var overseasUserList=[ {uid:'U001',username:'john_smith',password:'******',regTime:'2025-03-15',status:'正常'}, @@ -10956,9 +13722,9 @@ function saveOverseasUserAdd(){ // ===== 国内采购订单(独立页面、数据与处理逻辑) ===== var domesticPurchaseList=[ - {no:'DPO20260801001',clientName:'宁波海拓贸易有限公司',purchaseWarehouse:'宁波采购仓',category:'办公用品',name:'热敏标签纸',spec:'100×150mm / 500张',link:'https://detail.1688.com/offer/DP001.html',qty:500,inboundQty:500,outboundQty:180,stockQty:320,price:26.5,total:13250,address:'浙江省宁波市北仑区柏悦仓',contact:'刘敏',phone:'138-0000-1024',cnCarrier:'顺丰速运',cnTracking:'SF1435092876102',overseasCarrier:'-',usTracking:'-',eta:'2026-08-06T15:30',status:'已确认',remark:'常规采购补货',inventoryTransactions:[{time:'2026-08-06 15:30',type:'采购入库',no:'RK202608060021',inQty:500,outQty:0,balance:500,remark:'采购订单入库'},{time:'2026-08-09 10:15',type:'销售出库',no:'CK202608090118',inQty:0,outQty:180,balance:320,remark:'国内客户领用'}]}, - {no:'DPO20260803002',clientName:'上海鼎盛供应链有限公司',purchaseWarehouse:'上海松江采购仓',category:'包装耗材',name:'加厚纸箱',spec:'60×40×40cm / 五层',link:'https://detail.1688.com/offer/DP002.html',qty:800,inboundQty:800,outboundQty:260,stockQty:540,price:8.2,total:6560,address:'上海市松江区柏悦仓',contact:'陈强',phone:'139-0000-2086',cnCarrier:'京东物流',cnTracking:'JDVA0038271954',overseasCarrier:'-',usTracking:'-',eta:'2026-08-08T09:00',status:'采购中',remark:'大件货物包装使用',inventoryTransactions:[{time:'2026-08-08 09:00',type:'采购入库',no:'RK202608080037',inQty:800,outQty:0,balance:800,remark:'整批入库'},{time:'2026-08-11 14:20',type:'领料出库',no:'CK202608110076',inQty:0,outQty:260,balance:540,remark:'包装作业领用'}]}, - {no:'DPO20260805003',clientName:'深圳优航跨境电商有限公司',purchaseWarehouse:'深圳盐田采购仓',category:'仓储设备',name:'塑料托盘',spec:'1200×1000mm / 川字型',link:'https://detail.1688.com/offer/DP003.html',qty:120,inboundQty:90,outboundQty:30,stockQty:60,price:118,total:14160,address:'广东省深圳市盐田区柏悦仓',contact:'王芳',phone:'136-0000-3391',cnCarrier:'德邦快递',cnTracking:'DPK202608051903',overseasCarrier:'-',usTracking:'-',eta:'2026-08-14T16:00',status:'采购中',remark:'剩余30托待到货',inventoryTransactions:[{time:'2026-08-10 11:05',type:'部分入库',no:'RK202608100063',inQty:90,outQty:0,balance:90,remark:'首批到仓'},{time:'2026-08-12 08:40',type:'调拨出库',no:'CK202608120009',inQty:0,outQty:30,balance:60,remark:'调拨至美西仓备货区'}]} + {no:'DPO20260801001',clientName:'宁波海拓贸易有限公司',purchaseWarehouse:'宁波采购仓',category:'办公用品',name:'热敏标签纸',spec:'100×150mm / 500张',link:'https://detail.1688.com/offer/DP001.html',qty:500,inboundQty:500,outboundQty:180,stockQty:320,price:26.5,total:13250,address:'浙江省宁波市北仑区柏悦仓',contact:'刘敏',phone:'138-0000-1024',cnCarrier:'顺丰速运',cnTracking:'SF1435092876102',overseasCarrier:'-',usTracking:'-',eta:'2026-08-06T15:30',status:'已确认',remark:'常规采购补货',operationRecords:[{time:'2026-08-01 09:20',action:'创建采购订单',operator:'王芳',result:'成功',remark:'订单已提交'},{time:'2026-08-06 15:30',action:'更新到货信息',operator:'刘敏',result:'已完成',remark:'采购货物已到仓'}]}, + {no:'DPO20260803002',clientName:'上海鼎盛供应链有限公司',purchaseWarehouse:'上海松江采购仓',category:'包装耗材',name:'加厚纸箱',spec:'60×40×40cm / 五层',link:'https://detail.1688.com/offer/DP002.html',qty:800,inboundQty:800,outboundQty:260,stockQty:540,price:8.2,total:6560,address:'上海市松江区柏悦仓',contact:'陈强',phone:'139-0000-2086',cnCarrier:'京东物流',cnTracking:'JDVA0038271954',overseasCarrier:'-',usTracking:'-',eta:'2026-08-08T09:00',status:'采购中',remark:'大件货物包装使用',operationRecords:[{time:'2026-08-03 10:05',action:'创建采购订单',operator:'陈强',result:'成功',remark:'订单已提交'},{time:'2026-08-04 14:20',action:'确认采购进度',operator:'叶珊珊',result:'处理中',remark:'供应商正在备货'}]}, + {no:'DPO20260805003',clientName:'深圳优航跨境电商有限公司',purchaseWarehouse:'深圳盐田采购仓',category:'仓储设备',name:'塑料托盘',spec:'1200×1000mm / 川字型',link:'https://detail.1688.com/offer/DP003.html',qty:120,inboundQty:90,outboundQty:30,stockQty:60,price:118,total:14160,address:'广东省深圳市盐田区柏悦仓',contact:'王芳',phone:'136-0000-3391',cnCarrier:'德邦快递',cnTracking:'DPK202608051903',overseasCarrier:'-',usTracking:'-',eta:'2026-08-14T16:00',status:'采购中',remark:'剩余30托待到货',operationRecords:[{time:'2026-08-05 11:40',action:'创建采购订单',operator:'王芳',result:'成功',remark:'订单已提交'},{time:'2026-08-10 11:05',action:'更新到货信息',operator:'王芳',result:'处理中',remark:'首批90托已到仓'}]} ]; var currentDomesticPurchaseIdx=-1; function switchPurchaseOrderTab(type){ @@ -10995,14 +13761,14 @@ function showDomesticPurchaseDetail(i){ document.getElementById('domestic-detail-stock').innerHTML=fields([['入库量',r.inboundQty],['出库量',r.outboundQty],['库存量',r.stockQty],['库存状态',r.stockQty>0?'在库':'无库存']]); document.getElementById('domestic-detail-order').innerHTML=fields([['订单编号',r.no],['采购数量',r.qty],['预算单价','¥'+Number(r.price).toFixed(2)],['预算总价','¥'+Number(r.total).toFixed(2)],['订单状态',r.status],['联系人',r.contact],['联系电话',r.phone],['收货地址',r.address],['订单备注',r.remark]]); document.getElementById('domestic-detail-courier').innerHTML=fields([['国内承运商',r.cnCarrier],['国内运单号',r.cnTracking],['海外承运商',r.overseasCarrier],['海外运单号',r.usTracking],['预计到达时间',(r.eta||'-').replace('T',' ')]]); - var ledger=''+r.inventoryTransactions.map(function(t){return '';}).join('')+'
时间单据类型关联单号入库量出库量结存量备注
'+t.time+''+t.type+''+t.no+''+t.inQty+''+t.outQty+''+t.balance+''+t.remark+'
';document.getElementById('domestic-detail-ledger').innerHTML=ledger;switchPage('domestic-purchase-detail'); + var resultClass={成功:'tag-green','已完成':'tag-green','处理中':'tag-orange','待处理':'tag-blue','失败':'tag-red'};var records=Array.isArray(r.operationRecords)?r.operationRecords:[];var operationHtml=''+(records.length?records.map(function(log){return '';}).join(''):'')+'
操作时间操作内容操作人操作结果备注
'+(log.time||'-')+''+(log.action||'-')+''+(log.operator||'-')+''+(log.result||'-')+''+(log.remark||'-')+'
暂无操作记录
';document.getElementById('domestic-detail-operation-records').innerHTML=operationHtml;switchPage('domestic-purchase-detail'); } // ===== 海外采购订单(独立页面、数据与处理逻辑) ===== var overseasPurchaseList=[ - {no:'OPO20260722001',clientName:'Pacific Home LLC',purchaseWarehouse:'洛杉矶采购仓',category:'家居用品',name:'棉麻抱枕套',spec:'45×45cm / 藏青 / 4只装',link:'https://www.amazon.com/dp/OP001',qty:360,inboundQty:360,outboundQty:140,stockQty:220,price:8.5,total:3060,address:'ONT8, Moreno Valley, CA',contact:'Olivia Wilson',phone:'+1 626-555-0188',cnCarrier:'圆通国际',cnTracking:'YT9876543210',overseasCarrier:'UPS',usTracking:'1Z999AA10123456784',eta:'2026-08-02T13:30',status:'已完成',remark:'美西仓常备库存',inventoryTransactions:[{time:'2026-08-02 13:30',type:'海外入库',no:'USRK202608020016',inQty:360,outQty:0,balance:360,remark:'采购入仓'},{time:'2026-08-07 16:10',type:'一件代发',no:'USCK202608070084',inQty:0,outQty:140,balance:220,remark:'关联尾程订单'}]}, - {no:'OPO20260728002',clientName:'New Jersey Digital Inc.',purchaseWarehouse:'新泽西采购仓',category:'3C配件',name:'Type-C数据线',spec:'1.5m / 黑色 / 编织线',link:'https://www.amazon.com/dp/OP002',qty:600,inboundQty:480,outboundQty:120,stockQty:360,price:2.8,total:1680,address:'ABE8, Florence, NJ',contact:'Maria Garcia',phone:'+1 347-555-0142',cnCarrier:'云途物流',cnTracking:'YT202607281962',overseasCarrier:'FedEx',usTracking:'780512345678',eta:'2026-08-15T10:00',status:'采购中',remark:'第二批120件运输中',inventoryTransactions:[{time:'2026-08-08 09:45',type:'部分入库',no:'USRK202608080025',inQty:480,outQty:0,balance:480,remark:'首批到仓'},{time:'2026-08-11 11:20',type:'FBA出库',no:'USCK202608110031',inQty:0,outQty:120,balance:360,remark:'发往FBA仓'}]}, - {no:'OPO20260802003',clientName:'West Coast Outdoor Ltd.',purchaseWarehouse:'美西采购仓',category:'户外用品',name:'折叠露营椅',spec:'承重150kg / 黑色',link:'https://www.amazon.com/dp/OP003',qty:200,inboundQty:200,outboundQty:60,stockQty:140,price:24.6,total:4920,address:'LGB8, Rialto, CA',contact:'John Smith',phone:'+1 310-555-0123',cnCarrier:'递四方',cnTracking:'4PX3009817265',overseasCarrier:'USPS',usTracking:'9400111899223856928499',eta:'2026-08-20T14:00',status:'已确认',remark:'旺季备货',inventoryTransactions:[{time:'2026-08-10 14:00',type:'海外入库',no:'USRK202608100042',inQty:200,outQty:0,balance:200,remark:'整批到仓'},{time:'2026-08-12 10:30',type:'转仓出库',no:'USCK202608120014',inQty:0,outQty:60,balance:140,remark:'转仓至美东仓'}]} + {no:'OPO20260722001',clientName:'Pacific Home LLC',purchaseWarehouse:'洛杉矶采购仓',category:'家居用品',name:'棉麻抱枕套',spec:'45×45cm / 藏青 / 4只装',link:'https://www.amazon.com/dp/OP001',qty:360,inboundQty:360,outboundQty:140,stockQty:220,price:8.5,total:3060,address:'ONT8, Moreno Valley, CA',contact:'Olivia Wilson',phone:'+1 626-555-0188',cnCarrier:'圆通国际',cnTracking:'YT9876543210',overseasCarrier:'UPS',usTracking:'1Z999AA10123456784',eta:'2026-08-02T13:30',status:'已完成',remark:'美西仓常备库存',operationRecords:[{time:'2026-07-22 09:10',action:'创建采购订单',operator:'叶珊珊',result:'成功',remark:'订单已提交'},{time:'2026-08-02 13:30',action:'确认订单完成',operator:'李娜',result:'已完成',remark:'采购货物已到海外仓'}]}, + {no:'OPO20260728002',clientName:'New Jersey Digital Inc.',purchaseWarehouse:'新泽西采购仓',category:'3C配件',name:'Type-C数据线',spec:'1.5m / 黑色 / 编织线',link:'https://www.amazon.com/dp/OP002',qty:600,inboundQty:480,outboundQty:120,stockQty:360,price:2.8,total:1680,address:'ABE8, Florence, NJ',contact:'Maria Garcia',phone:'+1 347-555-0142',cnCarrier:'云途物流',cnTracking:'YT202607281962',overseasCarrier:'FedEx',usTracking:'780512345678',eta:'2026-08-15T10:00',status:'采购中',remark:'第二批120件运输中',operationRecords:[{time:'2026-07-28 10:15',action:'创建采购订单',operator:'李娜',result:'成功',remark:'订单已提交'},{time:'2026-08-08 09:45',action:'更新物流进度',operator:'李娜',result:'处理中',remark:'第二批120件运输中'}]}, + {no:'OPO20260802003',clientName:'West Coast Outdoor Ltd.',purchaseWarehouse:'美西采购仓',category:'户外用品',name:'折叠露营椅',spec:'承重150kg / 黑色',link:'https://www.amazon.com/dp/OP003',qty:200,inboundQty:200,outboundQty:60,stockQty:140,price:24.6,total:4920,address:'LGB8, Rialto, CA',contact:'John Smith',phone:'+1 310-555-0123',cnCarrier:'递四方',cnTracking:'4PX3009817265',overseasCarrier:'USPS',usTracking:'9400111899223856928499',eta:'2026-08-20T14:00',status:'已确认',remark:'旺季备货',operationRecords:[{time:'2026-08-02 09:30',action:'创建采购订单',operator:'王芳',result:'成功',remark:'订单已提交'},{time:'2026-08-10 14:00',action:'更新预计到达时间',operator:'王芳',result:'处理中',remark:'预计2026-08-20到达'}]} ]; var currentOverseasPurchaseIdx=-1; function renderOverseasPurchaseList(){ @@ -11013,7 +13779,7 @@ function resetOverseasPurchaseQuery(){document.getElementById('overseas-purchase function editOverseasPurchase(i){currentOverseasPurchaseIdx=i;var r=overseasPurchaseList[i];if(!r)return;document.getElementById('overseas-edit-no').value=r.no;document.getElementById('overseas-edit-category').value=r.category;document.getElementById('overseas-edit-name').value=r.name;document.getElementById('overseas-edit-spec').value=r.spec;document.getElementById('overseas-edit-link').value=r.link||'';document.getElementById('overseas-edit-inbound').value=r.inboundQty;document.getElementById('overseas-edit-outbound').value=r.outboundQty;document.getElementById('overseas-edit-status').value=r.status;document.getElementById('overseas-edit-cnCarrier').value=r.cnCarrier||'';document.getElementById('overseas-edit-cnTracking').value=r.cnTracking||'';document.getElementById('overseas-edit-overseasCarrier').value=r.overseasCarrier||'';document.getElementById('overseas-edit-usTracking').value=r.usTracking||'';document.getElementById('overseas-edit-eta').value=r.eta||'';document.getElementById('overseas-edit-remark').value=r.remark||'';switchPage('overseas-purchase-edit');} function saveOverseasPurchaseEdit(){var r=overseasPurchaseList[currentOverseasPurchaseIdx];if(!r)return;var inbound=Number(document.getElementById('overseas-edit-inbound').value);var outbound=Number(document.getElementById('overseas-edit-outbound').value);if(inbound<0||outbound<0){showToast('海外采购订单数量不能小于0','error');return;}if(outbound>inbound){showToast('海外采购订单出库量不能大于入库量','error');return;}r.category=document.getElementById('overseas-edit-category').value.trim()||'-';r.name=document.getElementById('overseas-edit-name').value.trim()||'-';r.spec=document.getElementById('overseas-edit-spec').value.trim()||'-';r.link=document.getElementById('overseas-edit-link').value.trim();r.inboundQty=inbound;r.outboundQty=outbound;r.stockQty=inbound-outbound;r.status=document.getElementById('overseas-edit-status').value;r.cnCarrier=document.getElementById('overseas-edit-cnCarrier').value.trim();r.cnTracking=document.getElementById('overseas-edit-cnTracking').value.trim();r.overseasCarrier=document.getElementById('overseas-edit-overseasCarrier').value.trim();r.usTracking=document.getElementById('overseas-edit-usTracking').value.trim();r.eta=document.getElementById('overseas-edit-eta').value;r.remark=document.getElementById('overseas-edit-remark').value.trim();switchPage('overseas-purchase');switchPurchaseOrderTab('overseas');showToast('海外采购订单已保存','success');} function showOverseasPurchaseDetail(i){ - var r=overseasPurchaseList[i];if(!r)return;var fields=function(rows){return rows.map(function(p){return '
'+p[0]+'
'+(p[1]===undefined||p[1]===''?'-':p[1])+'
';}).join('');};document.getElementById('overseas-detail-product').innerHTML=fields([['客户名称',r.clientName],['采购仓库',r.purchaseWarehouse],['采购品类',r.category],['商品名称',r.name],['商品规格',r.spec],['商品链接',r.link?'查看链接':'-']]);document.getElementById('overseas-detail-stock').innerHTML=fields([['入库量',r.inboundQty],['出库量',r.outboundQty],['库存量',r.stockQty],['库存状态',r.stockQty>0?'在库':'无库存']]);document.getElementById('overseas-detail-order').innerHTML=fields([['订单编号',r.no],['采购数量',r.qty],['预算单价','$'+Number(r.price).toFixed(2)],['预算总价','$'+Number(r.total).toFixed(2)],['订单状态',r.status],['联系人',r.contact],['联系电话',r.phone],['收货地址',r.address],['订单备注',r.remark]]);document.getElementById('overseas-detail-courier').innerHTML=fields([['国内承运商',r.cnCarrier],['国内运单号',r.cnTracking],['海外承运商',r.overseasCarrier],['海外运单号',r.usTracking],['预计到达时间',(r.eta||'-').replace('T',' ')]]);var ledger=''+r.inventoryTransactions.map(function(t){return '';}).join('')+'
时间单据类型关联单号入库量出库量结存量备注
'+t.time+''+t.type+''+t.no+''+t.inQty+''+t.outQty+''+t.balance+''+t.remark+'
';document.getElementById('overseas-detail-ledger').innerHTML=ledger;switchPage('overseas-purchase-detail'); + var r=overseasPurchaseList[i];if(!r)return;var fields=function(rows){return rows.map(function(p){return '
'+p[0]+'
'+(p[1]===undefined||p[1]===''?'-':p[1])+'
';}).join('');};document.getElementById('overseas-detail-product').innerHTML=fields([['客户名称',r.clientName],['采购仓库',r.purchaseWarehouse],['采购品类',r.category],['商品名称',r.name],['商品规格',r.spec],['商品链接',r.link?'查看链接':'-']]);document.getElementById('overseas-detail-stock').innerHTML=fields([['入库量',r.inboundQty],['出库量',r.outboundQty],['库存量',r.stockQty],['库存状态',r.stockQty>0?'在库':'无库存']]);document.getElementById('overseas-detail-order').innerHTML=fields([['订单编号',r.no],['采购数量',r.qty],['预算单价','$'+Number(r.price).toFixed(2)],['预算总价','$'+Number(r.total).toFixed(2)],['订单状态',r.status],['联系人',r.contact],['联系电话',r.phone],['收货地址',r.address],['订单备注',r.remark]]);document.getElementById('overseas-detail-courier').innerHTML=fields([['国内承运商',r.cnCarrier],['国内运单号',r.cnTracking],['海外承运商',r.overseasCarrier],['海外运单号',r.usTracking],['预计到达时间',(r.eta||'-').replace('T',' ')]]);var resultClass={成功:'tag-green','已完成':'tag-green','处理中':'tag-orange','待处理':'tag-blue','失败':'tag-red'};var records=Array.isArray(r.operationRecords)?r.operationRecords:[];var operationHtml=''+(records.length?records.map(function(log){return '';}).join(''):'')+'
操作时间操作内容操作人操作结果备注
'+(log.time||'-')+''+(log.action||'-')+''+(log.operator||'-')+''+(log.result||'-')+''+(log.remark||'-')+'
暂无操作记录
';document.getElementById('overseas-detail-operation-records').innerHTML=operationHtml;switchPage('overseas-purchase-detail'); } // ===== 本土卡车订单 ===== @@ -11221,6 +13987,28 @@ var truckList=[ {dispatchNo:'BYSE2606075_3',company:'宁波速通物流',driver:'李伟',trailerNo:'浙B·3D7L2',store:'慈溪门店',payable:1800,receivable:2200,etdDate:'2026-07-19',status:'已完成'}, {dispatchNo:'BYSE2606061_7',company:'上海港通运输',driver:'赵敏',trailerNo:'沪C·5T9M1',store:'宁波市区店',payable:4500,receivable:5200,etdDate:'2026-07-18',status:'已派车'} ]; +var truckRegion='domestic'; +var truckAddRegion='domestic'; +var truckEditRegion='domestic'; +var overseasTruckList=[ + {dispatchNo:'USDR2607012_1',company:'Pacific Drayage LLC',driver:'David Miller',trailerNo:'CA-8F2K9',store:'Los Angeles DC',payable:480,receivable:620,etdDate:'2026-07-20',status:'提柜中'}, + {dispatchNo:'USDR2607008_2',company:'West Coast Haulage',driver:'Emily Brown',trailerNo:'CA-3D7L2',store:'Ontario DC',payable:360,receivable:500,etdDate:'2026-07-19',status:'已完成'}, + {dispatchNo:'USDR2607001_3',company:'Global Port Transport',driver:'Michael Lee',trailerNo:'NJ-5T9M1',store:'New Jersey DC',payable:710,receivable:860,etdDate:'2026-07-18',status:'已派车'} +]; +function getTruckList(region){return region==='overseas'?overseasTruckList:truckList;} +function getActiveTruckList(){return getTruckList(truckRegion);} +function getTruckCurrency(){return truckRegion==='overseas'?{symbol:'$',unit:'USD',label:'海外'}:{symbol:'¥',unit:'RMB',label:'国内'};} +function updateTruckCurrencyLabels(){ + var currency=getTruckCurrency(); + var title=document.getElementById('truck-list-title'); + if(title)title.textContent='拖车列表 - '+currency.label; + ['truck-payable-unit','truck-receivable-unit','et-payable-unit','et-receivable-unit'].forEach(function(id){var el=document.getElementById(id);if(el)el.textContent=currency.unit;}); +} +function switchTruckRegion(region,el){ + truckRegion=region==='overseas'?'overseas':'domestic'; + document.querySelectorAll('#truck-region-tabs .tab-item').forEach(function(tab){tab.classList.toggle('active',tab.dataset.region===truckRegion);}); + renderTruckList(); +} var truckStatusStyle={ '待派车':'color:#fa8c16;background:#fff7e6;border:1px solid #ffd591', '已派车':'color:#1890ff;background:#e6f7ff;border:1px solid #91d5ff', @@ -11238,7 +14026,9 @@ function nextDispatchNo(){ function renderTruckList(){ var tb=document.getElementById('tbody-truck-list'); if(!tb) return; - tb.innerHTML=truckList.map(function(t,i){ + var list=getActiveTruckList(); + var currency=getTruckCurrency(); + tb.innerHTML=list.map(function(t,i){ var att=(t.attachments||[]).length; return ` ${t.dispatchNo} @@ -11246,8 +14036,8 @@ function renderTruckList(){ ${t.driver} ${t.trailerNo} ${t.store} - ¥${Number(t.payable).toLocaleString()} - ¥${Number(t.receivable).toLocaleString()} + ${currency.symbol}${Number(t.payable).toLocaleString()} + ${currency.symbol}${Number(t.receivable).toLocaleString()} ${t.etdDate} ${truckStatusSelect(t,i)} 📎 ${att} @@ -11256,7 +14046,8 @@ function renderTruckList(){ `; }).join(''); var cnt=document.getElementById('truck-count'); - if(cnt) cnt.textContent='共 '+truckList.length+' 条'; + if(cnt) cnt.textContent='共 '+list.length+' 条'; + updateTruckCurrencyLabels(); } function truckStatusSelect(t,i){ var opts=['待派车','已派车','提柜中','已完成','已取消']; @@ -11267,18 +14058,20 @@ function truckStatusSelect(t,i){ return html; } function changeTruckStatus(i,val){ - if(!truckList[i]) return; - truckList[i].status=val; + var list=getActiveTruckList(); + if(!list[i]) return; + list[i].status=val; renderTruckList(); showToast('状态已更新为:'+val,'success'); } var truckAttachIndex=-1; var truckAttachDraft=[]; function openTruckAttach(i){ + var list=getActiveTruckList(); truckAttachIndex=i; - truckAttachDraft=(truckList[i].attachments||[]).slice(); + truckAttachDraft=(list[i].attachments||[]).slice(); var dn=document.getElementById('attach-dispatch-no'); - if(dn) dn.value=truckList[i].dispatchNo||''; + if(dn) dn.value=list[i].dispatchNo||''; renderAttachList(); showModal('modal-truck-attach'); } @@ -11310,14 +14103,16 @@ function removeTruckAttach(idx){ } function saveTruckAttach(){ if(truckAttachIndex<0) return; - if(!truckList[truckAttachIndex]) truckList[truckAttachIndex]={}; - truckList[truckAttachIndex].attachments=truckAttachDraft.slice(); + var list=getActiveTruckList(); + if(!list[truckAttachIndex]) list[truckAttachIndex]={}; + list[truckAttachIndex].attachments=truckAttachDraft.slice(); renderTruckList(); hideModal('modal-truck-attach'); showToast('附件已保存','success'); } function $v(id){var e=document.getElementById(id);return e?e.value.trim():'';} function addTruck(){ + var list=getTruckList(truckAddRegion); var company=$v('truck-company'); if(!company){showToast('请选择运输公司','error');return;} var obj={ @@ -11346,7 +14141,8 @@ function addTruck(){ transitH:$v('truck-transit-h'),transitM:$v('truck-transit-m'), status:'待派车' }; - truckList.unshift(obj); + truckRegion=truckAddRegion; + list.unshift(obj); switchPage('truck-list'); showToast('拖车单新增成功,单号:'+obj.dispatchNo,'success'); // 清空表单 @@ -11355,7 +14151,7 @@ function addTruck(){ } function delTruck(i){ if(!confirm('确定删除该拖车单?')) return; - truckList.splice(i,1); + getActiveTruckList().splice(i,1); renderTruckList(); showToast('已删除拖车单','info'); } @@ -11363,7 +14159,8 @@ var truckEditIndex=-1; function gv(id){var e=document.getElementById(id);return e?e.value:'';} function editTruck(i){ truckEditIndex=i; - var t=truckList[i]; + truckEditRegion=truckRegion; + var t=getTruckList(truckEditRegion)[i]; if(!t) return; function set(id,val){var e=document.getElementById(id);if(e)e.value=val==null?'':val;} set('et-qty',t.qty);set('et-gw',t.gw);set('et-vol',t.vol); @@ -11381,7 +14178,8 @@ function editTruck(i){ } function saveTruckEdit(){ if(truckEditIndex<0) return; - var t=truckList[truckEditIndex]; + truckRegion=truckEditRegion; + var t=getTruckList(truckEditRegion)[truckEditIndex]; t.company=gv('et-company');t.driver=gv('et-driver');t.trailerNo=gv('et-trailer-no'); t.store=gv('et-store');t.payable=gv('et-payable')||'0';t.receivable=gv('et-receivable')||'0'; t.etdDate=gv('et-etd-date'); @@ -11402,6 +14200,7 @@ var releaseCurrentTd=null; function openRelease(span){ var td=span.closest('td'); releaseCurrentTd=td; + document.getElementById('release-vessel').value=''; document.getElementById('release-voyage').value=''; document.getElementById('release-bl').value=''; showModal('modal-release'); @@ -11409,18 +14208,20 @@ function openRelease(span){ function confirmRelease(){ var td=releaseCurrentTd; if(!td) return; + const vessel=document.getElementById('release-vessel').value.trim(); var v=document.getElementById('release-voyage').value.trim(); var bl=document.getElementById('release-bl').value.trim(); - if(!v||!bl){showToast('请填写航次和提单号','error');return;} - if(!window.confirm('确认放舱?\n航次:'+v+'\n提单号:'+bl)){return;} - td.innerHTML='是
航次:'+v+'
提单号:'+bl+'
修改'; - td.dataset.v=v; td.dataset.bl=bl; + if(!vessel||!v||!bl){showToast('请填写船名、航次和提单号','error');return;} + if(!window.confirm('确认放舱?\n船名:'+vessel+'\n航次:'+v+'\n提单号:'+bl)){return;} + td.innerHTML='是
船名:'+vessel+'
航次:'+v+'
提单号:'+bl+'
修改'; + td.dataset.vessel=vessel; td.dataset.v=v; td.dataset.bl=bl; hideModal('modal-release'); showToast('放舱信息已保存','success'); } function editRelease(a){ var td=a.closest('td'); releaseCurrentTd=td; + document.getElementById('release-vessel').value=td.dataset.vessel||''; document.getElementById('release-voyage').value=td.dataset.v||''; document.getElementById('release-bl').value=td.dataset.bl||''; showModal('modal-release'); @@ -11429,3 +14230,234 @@ function cancelRelease(){ releaseCurrentTd=null; hideModal('modal-release'); } + +// ===== 海外仓报价 ===== +function escapeOverseasWarehouseQuoteHtml(value){ + return String(value==null?'':value).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); +} +function overseasWarehouseQuoteNow(){ + var now=new Date(); + var pad=function(value){return String(value).padStart(2,'0');}; + return now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+pad(now.getHours())+':'+pad(now.getMinutes()); +} +function overseasWarehouseQuoteDefaultDraft(){ + return {id:'',name:'',warehouse:'',provider:'',currency:'USD',effectiveStart:'',effectiveEnd:'',version:'V1.0',status:'启用',updatedAt:'',remark:'',warehouseFees:[{item:'入库卸货',unit:'托',price:'',minimumCharge:'',remark:''}],transitPrices:[{warehouse:'',fbaWarehouse:'',method:'整车派送',miles:'',price:'',minimumCharge:'',remark:''}]}; +} +function overseasWarehouseQuoteInputValue(id,value){ + var element=document.getElementById(id); + if(element)element.value=value==null?'':value; +} +function renderOverseasWarehouseQuotes(){ + var tbody=document.getElementById('tbody-gen-overseas-quote'); + if(!tbody)return; + var read=function(id){var element=document.getElementById(id);return element?String(element.value||'').trim():'';}; + var keyword=read('goq-filter-keyword').toLowerCase(); + var warehouse=read('goq-filter-warehouse'); + var provider=read('goq-filter-provider').toLowerCase(); + var currency=read('goq-filter-currency'); + var status=read('goq-filter-status'); + var rows=overseasWarehouseQuoteData.filter(function(record){ + var searchable=[record.name,record.version,record.warehouse,record.provider].join(' ').toLowerCase(); + return (!keyword||searchable.indexOf(keyword)>=0)&&(!warehouse||record.warehouse===warehouse)&&(!provider||String(record.provider).toLowerCase().indexOf(provider)>=0)&&(!currency||record.currency===currency)&&(!status||record.status===status); + }); + tbody.innerHTML=rows.length?rows.map(function(record){ + var statusClass=record.status==='启用'?'tag-green':'tag-gray'; + return '' + +'
' + +''+escapeOverseasWarehouseQuoteHtml(record.name)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.warehouse)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.provider)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.currency)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.effectiveStart)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.effectiveEnd||'长期有效')+'' + +''+escapeOverseasWarehouseQuoteHtml(record.version)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.status)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.updatedAt)+'' + +''+escapeOverseasWarehouseQuoteHtml(record.remark||'—')+'' + +''; + }).join(''):'暂无符合条件的海外仓报价'; + var total=document.getElementById('goq-total'); + if(total)total.textContent='共 '+rows.length+' 条'; +} +function resetOverseasWarehouseQuoteFilters(){ + ['goq-filter-keyword','goq-filter-warehouse','goq-filter-provider','goq-filter-currency','goq-filter-status'].forEach(function(id){overseasWarehouseQuoteInputValue(id,'');}); + renderOverseasWarehouseQuotes(); +} +function renderOverseasWarehouseQuoteDetail(record){ + var escape=escapeOverseasWarehouseQuoteHtml; + var display=function(value){return value===null||value===undefined||String(value).trim()===''?'—':String(value);}; + var statusClass=record.status==='启用'?'tag-green':'tag-gray'; + var summary=[ + ['报价名称',record.name], + ['状态',''+escape(display(record.status))+'',true], + ['海外仓',record.warehouse], + ['服务商',record.provider], + ['币种',record.currency], + ['生效日期',record.effectiveStart], + ['失效日期',record.effectiveEnd||'长期有效'], + ['报价版本',record.version], + ['更新时间',record.updatedAt], + ['备注',record.remark] + ]; + document.getElementById('goq-detail-summary').innerHTML=summary.map(function(item){ + var value=item[2]?item[1]:escape(display(item[1])); + return '
'+escape(item[0])+''+value+'
'; + }).join(''); + var feeRows=record.warehouseFees||[]; + document.getElementById('tbody-goq-detail-fees').innerHTML=feeRows.length?feeRows.map(function(row){ + return ''+escape(display(row.item))+''+escape(display(row.unit))+''+escape(display(row.price))+''+escape(display(row.minimumCharge))+''+escape(display(row.remark))+''; + }).join(''):'暂无仓储作业费用'; + var transitRows=record.transitPrices||[]; + document.getElementById('tbody-goq-detail-transit').innerHTML=transitRows.length?transitRows.map(function(row){ + return ''+escape(display(row.warehouse))+''+escape(display(row.fbaWarehouse))+''+escape(display(row.method))+''+escape(display(row.miles))+''+escape(display(row.price))+''+escape(display(row.minimumCharge))+''+escape(display(row.remark))+''; + }).join(''):'暂无中转派送价格'; +} +function openOverseasWarehouseQuoteDetail(id){ + var record=overseasWarehouseQuoteData.find(function(item){return item.id===id;}); + if(!record){showToast('未找到海外仓报价','error');return;} + renderOverseasWarehouseQuoteDetail(record); + document.getElementById('goq-detail-edit').onclick=function(){ + hideModal('modal-gen-overseas-quote-detail'); + openOverseasWarehouseQuoteModal(id); + }; + showModal('modal-gen-overseas-quote-detail'); +} +function renderOverseasWarehouseFeeRows(){ + var tbody=document.getElementById('tbody-goq-warehouse-fees'); + if(!tbody||!overseasWarehouseQuoteDraft)return; + var escape=escapeOverseasWarehouseQuoteHtml; + tbody.innerHTML=overseasWarehouseQuoteDraft.warehouseFees.map(function(row,index){ + var items=['入库卸货','收货清点','上架','存储','出库操作','一件代发','换标','退件处理']; + var units=['箱','托','件','立方英尺/月','票']; + var options=function(values,current){return values.map(function(value){return ''+value+'';}).join('');}; + return ''; + }).join(''); +} +function renderOverseasTransitPriceRows(){ + var tbody=document.getElementById('tbody-goq-transit-prices'); + if(!tbody||!overseasWarehouseQuoteDraft)return; + var escape=escapeOverseasWarehouseQuoteHtml; + tbody.innerHTML=overseasWarehouseQuoteDraft.transitPrices.map(function(row,index){ + var methods=['整车自提','整车派送','散板派送']; + return ''; + }).join(''); +} +function collectOverseasWarehouseQuoteDetails(){ + if(!overseasWarehouseQuoteDraft)return; + var readRow=function(row,fields){var result={};fields.forEach(function(field){var element=row.querySelector('[data-field="'+field+'"]');result[field]=element?String(element.value||'').trim():'';});return result;}; + overseasWarehouseQuoteDraft.warehouseFees=Array.from(document.querySelectorAll('#tbody-goq-warehouse-fees tr')).map(function(row){return readRow(row,['item','unit','price','minimumCharge','remark']);}); + overseasWarehouseQuoteDraft.transitPrices=Array.from(document.querySelectorAll('#tbody-goq-transit-prices tr')).map(function(row){return readRow(row,['warehouse','fbaWarehouse','method','miles','price','minimumCharge','remark']);}); +} +function addOverseasWarehouseFeeRow(){ + collectOverseasWarehouseQuoteDetails(); + overseasWarehouseQuoteDraft.warehouseFees.push({item:'入库卸货',unit:'托',price:'',minimumCharge:'',remark:''}); + renderOverseasWarehouseFeeRows(); +} +function removeOverseasWarehouseFeeRow(index){ + collectOverseasWarehouseQuoteDetails(); + overseasWarehouseQuoteDraft.warehouseFees.splice(index,1); + renderOverseasWarehouseFeeRows(); +} +function addOverseasTransitPriceRow(){ + collectOverseasWarehouseQuoteDetails(); + overseasWarehouseQuoteDraft.transitPrices.push({warehouse:overseasWarehouseQuoteDraft.warehouse||'',fbaWarehouse:'',method:'整车派送',miles:'',price:'',minimumCharge:'',remark:''}); + renderOverseasTransitPriceRows(); +} +function removeOverseasTransitPriceRow(index){ + collectOverseasWarehouseQuoteDetails(); + overseasWarehouseQuoteDraft.transitPrices.splice(index,1); + renderOverseasTransitPriceRows(); +} +function syncOverseasTransitWarehouse(warehouse){ + if(!overseasWarehouseQuoteDraft)return; + collectOverseasWarehouseQuoteDetails(); + overseasWarehouseQuoteDraft.warehouse=warehouse; + overseasWarehouseQuoteDraft.transitPrices.forEach(function(row){row.warehouse=warehouse;}); + renderOverseasTransitPriceRows(); +} +function openOverseasWarehouseQuoteModal(id){ + var record=id?overseasWarehouseQuoteData.find(function(item){return item.id===id;}):null; + if(id&&!record){showToast('未找到海外仓报价','error');return;} + overseasWarehouseQuoteDraft=record?JSON.parse(JSON.stringify(record)):overseasWarehouseQuoteDefaultDraft(); + document.getElementById('goq-modal-title').textContent=record?'编辑海外仓报价':'新增海外仓报价'; + ['id','name','warehouse','provider','currency','effectiveStart','effectiveEnd','version','status','remark'].forEach(function(field){overseasWarehouseQuoteInputValue('goq-'+(field==='id'?'edit-id':field.replace(/[A-Z]/g,function(letter){return '-'+letter.toLowerCase();})),overseasWarehouseQuoteDraft[field]);}); + renderOverseasWarehouseFeeRows(); + renderOverseasTransitPriceRows(); + showModal('modal-gen-overseas-quote'); +} +function overseasWarehouseQuoteNumber(value,required){ + var raw=String(value==null?'':value).trim(); + if(raw==='')return required?null:''; + var number=Number(raw); + return Number.isFinite(number)&&number>=0?number:null; +} +function validateOverseasWarehouseQuote(draft){ + if(!draft.name||!draft.warehouse||!draft.provider||!draft.currency||!draft.effectiveStart||!draft.version)return '请填写所有必填的基础信息'; + if(draft.effectiveEnd&&draft.effectiveEnd + 示例收款二维码 + 仅用于原型展示,不包含真实收款信息 + + + + + + + 示例 + diff --git a/悦/货代SAAS平台后台/prototype-src/manifest.json b/悦/货代SAAS平台后台/prototype-src/manifest.json index 09a2fd0..8bf00fc 100644 --- a/悦/货代SAAS平台后台/prototype-src/manifest.json +++ b/悦/货代SAAS平台后台/prototype-src/manifest.json @@ -12,11 +12,15 @@ "outbound-dispatch", "outbound-bol", "outbound-selfpick", + "outbound-exception", "gen-product", "gen-fee", + "gen-exchange-rate", "outbound-vehicle", - "outbound-vehicle-edit", + "gen-owned-warehouse", "gen-fba", + "gen-partner-warehouse", + "gen-overseas-quote", "gen-download", "gen-pallet", "gen-location", @@ -92,6 +96,7 @@ "customer-account-detail", "finance-cost", "customer-arap", + "finance-ar-detail-report", "customer-arap-detail", "customer-recon-stmt", "settlement-ar", @@ -116,6 +121,7 @@ "ct-list", "ct-manifest", "fba-stock-management", + "overseas-location", "inventory-overview", "warehouse-stock", "overseas-stock", @@ -124,6 +130,8 @@ "overseas-relabel", "profit", "vehicle", + "delivery-fleet-quote", + "vehicle-detail", "fba-return-inbound", "fba-return-relabel", "fba-return-outbound", @@ -147,11 +155,12 @@ "inventory-transactions", "purchase-stock-detail", "fba-return-stock", - "overseas-location", + "domestic-location", "domestic-stock-management", "domestic-container-business", "domestic-container-detail", "pallet-manage", + "pallet-detail", "ct-preload", "ct-preload-detail", "ct-board", @@ -205,11 +214,12 @@ "wh-process", "wh-transfer", "wh-shelve", - "overseas-location", + "domestic-location", "domestic-stock-management", "domestic-container-business", "domestic-container-detail", - "pallet-manage" + "pallet-manage", + "pallet-detail" ] }, { @@ -217,6 +227,7 @@ "title": "海外仓", "pages": [ "fba-stock-management", + "overseas-location", "inventory-overview", "warehouse-stock", "overseas-stock", @@ -255,10 +266,16 @@ "outbound-bol", "outbound-selfpick", "outbound-vehicle", - "outbound-vehicle-edit", "outbound-vehicle-detail" ] }, + { + "file": "modules/04a-customer-service.html", + "title": "客户服务", + "pages": [ + "outbound-exception" + ] + }, { "file": "modules/05-suppliers.html", "title": "供应商中心", @@ -332,6 +349,7 @@ "customer-account-detail", "finance-cost", "customer-arap", + "finance-ar-detail-report", "customer-arap-detail", "customer-recon-stmt", "settlement-ar", @@ -356,13 +374,19 @@ "pages": [ "gen-product", "gen-fee", + "gen-exchange-rate", + "gen-owned-warehouse", "gen-fba", + "gen-partner-warehouse", + "gen-overseas-quote", "gen-download", "gen-pallet", "gen-location", "gen-route", "gen-voyage", - "vehicle" + "vehicle", + "delivery-fleet-quote", + "vehicle-detail" ] }, { diff --git a/悦/货代SAAS平台后台/prototype-src/modules/01-customers.html b/悦/货代SAAS平台后台/prototype-src/modules/01-customers.html index 6d666cd..fe02cd2 100644 --- a/悦/货代SAAS平台后台/prototype-src/modules/01-customers.html +++ b/悦/货代SAAS平台后台/prototype-src/modules/01-customers.html @@ -56,32 +56,6 @@
- - -
diff --git a/悦/货代SAAS平台后台/prototype-src/modules/02-domestic-warehouse.html b/悦/货代SAAS平台后台/prototype-src/modules/02-domestic-warehouse.html index 534b6d8..6749031 100644 --- a/悦/货代SAAS平台后台/prototype-src/modules/02-domestic-warehouse.html +++ b/悦/货代SAAS平台后台/prototype-src/modules/02-domestic-warehouse.html @@ -109,6 +109,16 @@ + + +详情 | +EXP260814001 +审核通过 +审核通过 +2026-08-14 +未录入费用 +义乌卓越义乌仓上海分拨仓未配载否---义乌卓越物流快递订单快递2026-08-1413800138000义乌市稠州北路322000ops@example.com国内快递-否不涉及--342420.250.250A141.6740国内地址上海分拨仓上海市青浦区201700王师傅139001390002026-08-14 10:202026-08-14 11:05---顺丰速运SF260814001当天寄出优先处理admin2026-08-14 + 详情 | PCKHK2606151047待接收审核未录入测量数据未录入费用杭州积乐义乌仓义乌仓未配载否-CSLU1234567ABC123杭州积乐贸易海运拼箱自提2024-01-1513800138000杭州市江干区XX路XX号310000contact@example.com海运买单否已完成2024-01-202024-02-1055004802.52.42A1520450FBA仓美国仓USA Address90210John123456789--file.pdfmark.pdforder.pdf顺丰SF123456789无内部备注admin2024-01-10 详情 | PCKHK2606151046待接收审核未录入测量数据未录入费用杭州积乐义乌仓义乌仓未配载否-CSLU1234568ABC124杭州积乐贸易海运拼箱送货上门2024-01-1613900139000杭州市西湖区XX路XX号310001contact2@example.com海运退税否已完成2024-01-212024-02-1188007804.03.83A2850720FBA仓美国仓USA Address 290211Mike987654321--file2.pdfmark2.pdforder2.pdf圆通YT123456789加急内部备注2user12024-01-11 详情 | HDHK2606151045待接收审核未录入测量数据未录入费用岩盛义乌仓义乌仓未配载否-CSLU1234569ABC125岩盛进出口空运自提2024-01-1713700137000深圳市南山区XX路XX号518000ys@rocksheng.com空运买单否已完成2024-01-222024-01-2531501450.50.454A3160130FBA仓德国仓Germany Address10178Tom456789012--file3.pdfmark3.pdforder3.pdfEMSEMS123456789无内部备注3user22024-01-12 @@ -707,7 +717,7 @@
-入库码:PCKK2606151065 +入库码:PCKK2606151065
@@ -1044,7 +1054,7 @@ @@ -1329,6 +1336,12 @@
+
+箱子是否计费: + + +
+
扣货理由: @@ -1784,56 +1797,48 @@
- -
- + +
+
-
库位管理
-
- - - - - - +
库位管理
+
+ + + + + +
-
- - - - - - - - - -
库位编码仓库库区库位类型最大承重(kg)状态备注操作
+
+ +
操作库位编码仓库库区库位类型最大承重(kg)状态备注
- +
- -
@@ -1939,9 +1944,10 @@ 托盘类型 托盘容积(m³) 托盘重量(kg) +采购价格 状态 备注 -操作 +操作
@@ -1960,12 +1966,27 @@
+
+
+
+ +
+ +
+
+
托盘详情
托盘编码 —
+
—
+
+
+
+
+ + + +
-
托盘管理
+
托盘管理
+
- +
+ + + @@ -588,14 +652,16 @@ + +
-
箱号管理
+
箱号管理
- + @@ -618,13 +684,13 @@
-
入库单详情
入库单号 —
—
+
入库单详情
入库单号 —
—
应收费用明细
托盘编码 托盘类型仓库 容积(m³)托盘重量(kg)采购价格 所属FBA仓 状态 备注
序号费用项目币种金额备注
暂无应收费用明细
应收费用合计(USD)$0.00
-
出库单详情
出库单号 —
—
+
出库单详情
出库单号 —
—
托盘信息
托盘号入仓码箱数重量体积
暂无托盘信息
应收费用明细
序号费用项目币种金额备注
暂无应收费用明细
应收费用合计(USD)$0.00
@@ -748,6 +814,8 @@ FORM: 采用现有后台的列表加标准详情结构,保持高信息密度 --> + +

应收款统计表

+ +
+
应收总金额CNY 0.00
+
已收合计CNY 0.00
+
零头减免CNY 0.00
+
余额未收CNY 0.00
+
+
应收款明细客户 / 备注随明细行展示
+ +
@@ -765,7 +802,7 @@ 费用单据详情 — — -
+
应收/应付
—
@@ -813,8 +850,9 @@
- + + @@ -934,7 +972,6 @@ - @@ -975,7 +1012,7 @@
- +付款状态: @@ -994,7 +1031,6 @@
- @@ -1058,13 +1094,28 @@
- +
财务利润表
+
+ + +
查询维度 + 时间 @@ -1080,11 +1131,11 @@
利润合计
¥0
综合利润率
0.0%
-
-
客户
-
货柜
-
单票
-
单月
+
+
客户
+
货柜
+
单票
+
单月
diff --git a/悦/货代SAAS平台后台/prototype-src/modules/09-sales.html b/悦/货代SAAS平台后台/prototype-src/modules/09-sales.html index 5439428..d06766e 100644 --- a/悦/货代SAAS平台后台/prototype-src/modules/09-sales.html +++ b/悦/货代SAAS平台后台/prototype-src/modules/09-sales.html @@ -86,7 +86,7 @@
-
操作操作 审核状态客户是否确认 账单编号 客户公司名 结算起始日操作 结算单号 客户公司名费用类型 币种 应收金额 已收 操作 结算单号 供应商费用类型 币种 应付金额 已付
销售编号销售姓名区域/团队客户数订单数销售额(元)综合提成率提成金额(元)操作
+
销售编号销售姓名区域/团队客户数订单数销售额(元)综合提成率固定提成(元)溢价提成(元)垫款利息(元)提成金额(元)操作
diff --git a/悦/货代SAAS平台后台/prototype-src/modules/10-general.html b/悦/货代SAAS平台后台/prototype-src/modules/10-general.html index 340ef1a..1a929a7 100644 --- a/悦/货代SAAS平台后台/prototype-src/modules/10-general.html +++ b/悦/货代SAAS平台后台/prototype-src/modules/10-general.html @@ -11,13 +11,205 @@
分类国内国际费用类型名称货柜应付货柜应收仓储应付仓储应收平摊费用说明创建人创建日期更新人更新日期操作
- + +
+
+
最新维护汇率
-
+
汇率月份
-
+
最后更新人
-
+
最后更新时间
-
+
+
+
美元兑人民币月平均汇率统一口径:1 USD = X CNY
+
+
汇率月份平均汇率换算说明状态更新人更新时间备注操作
+
+
+ + +
+
仓库管理
+
+
+
自有仓名称仓库地址城市州/省邮编国家状态操作
+
+
-
仓库管理
-
-
仓库代码仓库地址城市州/省邮编国家状态操作
+
仓库管理
+
+
自有仓
+
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+
仓库管理
+
+
自有仓
+
仓库代码仓库地址城市州/省邮编国家距离(MILES)状态操作
+
+ + + + +
+ +
+
海外仓报价
+
+ + + + + + + +
+
操作报价名称海外仓服务商币种生效日期失效日期报价版本状态更新时间备注
+ +
+
+ + + + +
下载中心
@@ -91,42 +283,40 @@
-
+
-
+
等待读取上月平均汇率
-
操作亚马逊仓AMS+换单费内陆清关/报关费关税提柜费拆柜费托盘费派送费费用小计海运费成本总成本(USD)汇率折人民币重量(kg)成本单价(元/kg)建议报价
-
计算公式:费用小计 = AMS/换单 + 内陆 + 清关/报关 + 关税 + 提柜 + 拆柜 + 托盘 + 派送;总成本 = 小计 + 海运费;成本单价 = 总成本 × 汇率 ÷ 计费基数。
+
操作亚马逊仓AMS+换单费内陆清关/报关费关税提柜费拆柜费托盘费派送费费用小计海运费成本总成本(USD)汇率折人民币重量(kg)成本单价(元/kg)销售底价建议报价
+
计算公式:费用小计 = AMS/换单 + 内陆 + 清关/报关 + 关税 + 提柜 + 拆柜 + 托盘 + 派送;总成本 = 小计 + 海运费;成本单价 = 总成本 × 汇率 ÷ 计费基数;销售底价 = 建议报价 - 0.6。
- +
车辆列表
+
+ + +
-
-
自有车辆
-
外派车辆
+
+ +
-
-区域: -全部 -国内 -国外 -
@@ -134,6 +324,7 @@ + @@ -142,19 +333,16 @@
车牌 车型当前公里码(km) 司机 联系电话 状态 区域 操作
+
+ + + @@ -183,7 +371,11 @@
-
+
+
+
+ +
@@ -196,12 +388,64 @@
- - + +
+ +
+
派送车队报价
+
+ + + + + + + + +
+
车牌 车型 油耗(L/100km) 当前公里码(km) 外派单位 联系电话当前派送单最近更换原因 状态 区域 操作
操作发货地(城市)目的仓(FBA仓点)迈数(预估距离)车队渠道整车自提整车派送散板派送状态更新时间备注
+ +
报价金额按美元记录;迈数为预估距离,实际派送费用以订单确认时的有效报价为准。
+
+
+ + + + + + +
+ +
+
+
车辆详情
——
+ +
+
+
+

车辆信息

+
+
+
+

派送订单明细

+
派送单号BOL / 来源单号客户目的仓预约日期派送状态关联关系
+
+
+

派送更换记录

+
时间派送单号动作关联车辆原因操作人
+
+
+
+
diff --git a/悦/货代SAAS平台后台/prototype-src/overlays.html b/悦/货代SAAS平台后台/prototype-src/overlays.html index 57d781d..4757501 100644 --- a/悦/货代SAAS平台后台/prototype-src/overlays.html +++ b/悦/货代SAAS平台后台/prototype-src/overlays.html @@ -12,7 +12,7 @@
+
+
+
+
@@ -570,6 +586,7 @@
+
@@ -1168,25 +1185,42 @@ .ds-channels .ds-channel{font-size:13px;padding:7px 18px;border:1px solid #d9d9d9;background:#fff;color:#374151;border-radius:6px;cursor:pointer;transition:.15s} .ds-channels .ds-channel:hover{border-color:#722ed1;color:#722ed1} .ds-channels .ds-channel.active{background:#722ed1;border-color:#722ed1;color:#fff} -.ds-layout{display:flex;gap:16px;align-items:stretch} -.ds-orders{flex:0 0 60%;max-width:60%;display:flex;flex-direction:column} -.ds-orders-list{max-height:520px;overflow-y:auto;border:1px solid #e5e7eb;border-radius:8px;background:#fff} +.ds-layout{display:flex;gap:12px;align-items:stretch} +.ds-orders{flex:44 1 0;display:flex;flex-direction:column;min-width:0} +.ds-orders-list{max-height:390px;overflow:auto;border:1px solid #e5e7eb;border-radius:8px;background:#fff} /* 订单表格样式 */ -.ds-order-table{width:100%;border-collapse:collapse;font-size:12px} +.ds-order-table{width:100%;min-width:980px;border-collapse:collapse;font-size:12px} .ds-order-table thead th{background:#f5f6f8;color:#4b5563;font-weight:600;padding:9px 8px;border-bottom:1px solid #e5e7eb;white-space:nowrap;font-size:12px;position:sticky;top:0;z-index:1} -.ds-order-table tbody tr{border-bottom:1px solid #f0f0f0;cursor:grab;transition:.15s} +.ds-order-table tbody tr{border-bottom:1px solid #f0f0f0;cursor:pointer;transition:.15s} .ds-order-table tbody tr:hover{background:#f0f5ff} -.ds-order-table tbody tr.placed{opacity:.35;cursor:not-allowed} +.ds-order-table tbody tr.selected{background:#eff6ff} +.ds-order-table tbody tr.selected td:first-child{box-shadow:inset 1px 0 #2563eb} .ds-order-table tbody td{padding:8px 6px;color:#374151;white-space:nowrap;font-size:12px} .ds-cn-select{display:inline-block;padding:2px 8px;border:1px solid #d9d9d9;border-radius:4px;font-size:11px;color:#1f2937;cursor:pointer;background:#fafafa} .ds-type-filter .ds-tf{font-size:12px;padding:3px 10px;border:1px solid #e5e7eb;border-radius:14px;background:#fff;color:#6b7280;cursor:pointer;transition:.15s} .ds-type-filter .ds-tf:hover{border-color:#722ed1;color:#722ed1} .ds-type-filter .ds-tf.active{background:#722ed1;border-color:#722ed1;color:#fff} .ds-otype{display:inline-block;font-size:10px;padding:1px 6px;border-radius:4px;margin-left:6px;vertical-align:middle} -.otype-合德正班{background:#e6f0ff;color:#1677ff} -.otype-合德海卡{background:#f6f0ff;color:#722ed1} -.otype-洛杉矶普通{background:#e8f7ee;color:#16a34a} -.ds-trucks-wrap{flex:0 0 40%;max-width:40%;display:flex;flex-direction:column;min-width:0} +.otype-一件代发{background:#e6f0ff;color:#1677ff} +.otype-头程{background:#f6f0ff;color:#722ed1} +.otype-仓储转运{background:#e8f7ee;color:#16a34a} +.ds-pallets-wrap{flex:22 1 0;display:flex;flex-direction:column;min-width:0} +.ds-pallet-detail{border:1px solid #dbe4f0;border-radius:8px;background:#fff;overflow:hidden;display:flex;flex-direction:column;min-height:170px;max-height:560px} +.ds-pallet-detail-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;background:#f8fafc;border-bottom:1px solid #e5e7eb;color:#334155;font-size:12px;font-weight:600} +.ds-pallet-detail-title span{min-width:0;color:#64748b;font-weight:400;overflow-wrap:anywhere} +.ds-pallet-detail-table-wrap{max-height:500px;overflow:auto} +.ds-pallet-detail-table{width:100%;border-collapse:collapse;table-layout:fixed;font-size:12px} +.ds-pallet-detail-table th,.ds-pallet-detail-table td{padding:7px 10px;border-bottom:1px solid #eef2f7;text-align:left;color:#475569;overflow-wrap:anywhere} +.ds-pallet-detail-table tr:last-child td{border-bottom:0} +.ds-pallet-detail-table .num{text-align:right;width:90px} +.ds-pallet-row{cursor:grab;background:#fff;transition:.15s} +.ds-pallet-row:hover{background:#f0f5ff} +.ds-pallet-row.assigned{cursor:not-allowed;background:#f8fafc;opacity:.62} +.ds-pallet-no{display:flex;align-items:center;gap:6px;min-width:0} +.ds-pallet-no>span:first-child{min-width:0;overflow-wrap:anywhere} +.ds-pallet-badge{flex:0 0 auto;padding:1px 5px;border-radius:4px;background:#e8f7ee;color:#15803d;font-size:10px;white-space:nowrap} +.ds-pallet-empty{text-align:center!important;color:#94a3b8!important;padding:14px 10px!important} +.ds-trucks-wrap{flex:34 1 0;display:flex;flex-direction:column;min-width:0} .ds-trucks{flex:1;display:flex;flex-direction:column;gap:12px;overflow-y:auto;max-height:560px;padding-right:2px} .ds-truck{border:2px dashed #d1d5db;border-radius:8px;background:#fafafa;display:flex;flex-direction:column;transition:.15s} .ds-truck.ds-over{border-color:#722ed1;background:#f6f0ff} @@ -1197,12 +1231,14 @@ .ds-truck-sum b{color:#722ed1;font-weight:700} .ds-truck-sum b.over{color:#ef4444} .ds-truck-body{flex:1;min-height:70px;padding:8px;overflow-y:auto} -.ds-truck-item{background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:6px 8px;margin-bottom:6px;font-size:12px;display:flex;justify-content:space-between;align-items:center;gap:6px} +.ds-truck-item{background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:6px 8px;margin-bottom:6px;font-size:12px;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:2px 8px;cursor:grab} .ds-truck-item .ds-zi-ono{font-weight:600;color:#374151} -.ds-truck-item .ds-zi-meta{color:#9ca3af;font-size:11px} -.ds-truck-item .ds-zi-del{color:#ef4444;cursor:pointer;font-size:14px;line-height:1} +.ds-truck-item .ds-zi-meta{color:#9ca3af;font-size:11px;grid-column:1;overflow-wrap:anywhere} +.ds-truck-item .ds-zi-del{color:#ef4444;cursor:pointer;font-size:14px;line-height:1;grid-column:2;grid-row:1/3} .ds-truck-del{font-size:11px;color:#ef4444;cursor:pointer;text-align:right;padding:4px 12px} .ds-truck-del:hover{text-decoration:underline} +@media(min-width:901px){.ds-pallet-detail{margin-top:57px}.ds-pallet-detail-table-wrap{padding-top:0}.ds-trucks{padding:24px 2px 0}} +@media(max-width:900px){.ds-layout{flex-direction:column}.ds-orders,.ds-pallets-wrap,.ds-trucks-wrap{flex:1 1 auto;max-width:100%;width:100%}.ds-orders-list{max-height:320px}.ds-pallet-detail{max-height:320px}.ds-pallet-detail-table-wrap{max-height:260px}.ds-trucks{max-height:360px}}
@@ -1259,7 +1295,7 @@
-
资料上传后会回写当前派送单,并沿用历史 BOL 资料0/5 已上传
+
资料上传后会回写当前派送单,并沿用历史 BOL 资料0/7 已上传
@@ -1375,12 +1411,12 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -1445,5 +1730,82 @@ + + + - + + diff --git a/悦/货代SAAS平台后台/prototype-src/shell.html b/悦/货代SAAS平台后台/prototype-src/shell.html index b710b36..157032d 100644 --- a/悦/货代SAAS平台后台/prototype-src/shell.html +++ b/悦/货代SAAS平台后台/prototype-src/shell.html @@ -37,6 +37,8 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Helv .top-message-dropdown button span{width:20px;text-align:center} .hamburger{color:#fff;font-size:24px;cursor:pointer;transition:all .3s;position:relative;z-index:1;padding:8px;border-radius:8px} .hamburger:hover{background:rgba(255,255,255,.15);transform:scale(1.1)} +@media(max-width:1100px){.top-nav .tenant-switch{display:none}} +@media(max-width:820px){.top-nav{padding:0 12px;gap:8px}.top-nav .logo{min-width:0}.top-nav .nav-right{display:none}} .layout{display:flex;margin-top:64px;height:calc(100vh - 64px);overflow:hidden} .sidebar{width:240px;background:rgba(255,255,255,.9);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-right:1px solid rgba(255,255,255,.3);position:fixed;top:64px;left:0;bottom:0;overflow-y:auto;z-index:90;transition:transform .35s cubic-bezier(.4,0,.2,1);padding:12px 0;box-shadow:4px 0 32px rgba(0,0,0,.08)} .sidebar.collapsed{transform:translateX(-240px)} @@ -81,6 +83,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Helv .stat-card:nth-child(3) .decorator{background:linear-gradient(135deg,#f59e0b,#ea580c)} .stat-card:nth-child(4) .decorator{background:linear-gradient(135deg,#7c3aed,#6d28d9)} .stat-card:nth-child(5) .decorator{background:linear-gradient(135deg,#ec4899,#db2777)} +#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:repeat(4,minmax(0,1fr))} +#page-gen-exchange-rate .exchange-rate-summary .stat-card{min-width:0} +#page-gen-exchange-rate .exchange-rate-summary .value{font-size:20px;line-height:1.35;letter-spacing:0;overflow-wrap:anywhere} +#page-gen-exchange-rate .table-toolbar{gap:12px;flex-wrap:wrap} +@media(max-width:1200px){#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:repeat(2,minmax(0,1fr))}} +@media(max-width:640px){#page-gen-exchange-rate .exchange-rate-summary{grid-template-columns:1fr}} /* CHART */ .chart-row{display:grid;grid-template-columns:2fr 1fr;gap:20px;margin-bottom:20px} .chart-row.equal{grid-template-columns:1fr 1fr} @@ -139,7 +147,7 @@ canvas{max-height:280px} #rsq-wrap.rsq-collapsed .rsq-toggle svg{transform:rotate(180deg)} .recon-main-table-wrap{overflow-x:auto} #page-customer-arap .arap-table-wrap{width:100%;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch} -#page-customer-arap .arap-table{width:2005px;min-width:2005px;table-layout:fixed;border-collapse:collapse;font-size:12.5px} +#page-customer-arap .arap-table{width:1800px;min-width:1800px;table-layout:fixed;border-collapse:collapse;font-size:12.5px} #page-customer-arap .arap-table th{height:44px;padding:10px 8px;background:#f5f6fb;color:#333;font-size:12px;font-weight:600;text-align:left;white-space:nowrap} #page-customer-arap .arap-table td{height:55px;padding:10px 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} #page-customer-arap .arap-table th:nth-child(1),#page-customer-arap .arap-table td:nth-child(1){padding-left:5px;padding-right:5px} @@ -147,26 +155,32 @@ canvas{max-height:280px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar{height:8px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar-thumb{background:#cfd6df;border-radius:8px} #page-customer-arap .arap-table-wrap::-webkit-scrollbar-track{background:#f3f4f6} -#page-customer-recon-stmt .recon-main-table{font-size:11px;min-width:1740px;table-layout:fixed} +#page-customer-recon-stmt .recon-main-table{font-size:11px;min-width:1880px;table-layout:fixed} #page-customer-recon-stmt .recon-main-table th{padding:9px 6px;font-size:11px;line-height:1.25;text-align:center;white-space:nowrap} -#page-customer-recon-stmt .recon-main-table td{height:34px;padding:7px 6px;font-size:11px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -#page-customer-recon-stmt .recon-main-table th:nth-child(1){width:190px;min-width:190px!important} +#page-customer-recon-stmt .recon-main-table td{height:38px;padding:7px 6px;font-size:11px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +#page-customer-recon-stmt .recon-main-table th:nth-child(1){width:260px;min-width:260px!important} #page-customer-recon-stmt .recon-main-table th:nth-child(2){width:70px} -#page-customer-recon-stmt .recon-main-table th:nth-child(3){width:80px} -#page-customer-recon-stmt .recon-main-table th:nth-child(4){width:150px} -#page-customer-recon-stmt .recon-main-table th:nth-child(5),#page-customer-recon-stmt .recon-main-table th:nth-child(6){width:86px} -#page-customer-recon-stmt .recon-main-table th:nth-child(7){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(8){width:45px} -#page-customer-recon-stmt .recon-main-table th:nth-child(9){width:88px} -#page-customer-recon-stmt .recon-main-table th:nth-child(10),#page-customer-recon-stmt .recon-main-table th:nth-child(11){width:80px} -#page-customer-recon-stmt .recon-main-table th:nth-child(12){width:115px} -#page-customer-recon-stmt .recon-main-table th:nth-child(13){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(14){width:68px} -#page-customer-recon-stmt .recon-main-table th:nth-child(15){width:60px} -#page-customer-recon-stmt .recon-main-table th:nth-child(16),#page-customer-recon-stmt .recon-main-table th:nth-child(18){width:55px} -#page-customer-recon-stmt .recon-main-table th:nth-child(17),#page-customer-recon-stmt .recon-main-table th:nth-child(19){width:120px} +#page-customer-recon-stmt .recon-main-table th:nth-child(3){width:86px} +#page-customer-recon-stmt .recon-main-table th:nth-child(4){width:80px} +#page-customer-recon-stmt .recon-main-table th:nth-child(5){width:150px} +#page-customer-recon-stmt .recon-main-table th:nth-child(6),#page-customer-recon-stmt .recon-main-table th:nth-child(7){width:86px} +#page-customer-recon-stmt .recon-main-table th:nth-child(8){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(9){width:45px} +#page-customer-recon-stmt .recon-main-table th:nth-child(10){width:88px} +#page-customer-recon-stmt .recon-main-table th:nth-child(11),#page-customer-recon-stmt .recon-main-table th:nth-child(12){width:80px} +#page-customer-recon-stmt .recon-main-table th:nth-child(13){width:115px} +#page-customer-recon-stmt .recon-main-table th:nth-child(14){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(15){width:68px} +#page-customer-recon-stmt .recon-main-table th:nth-child(16){width:60px} +#page-customer-recon-stmt .recon-main-table th:nth-child(17),#page-customer-recon-stmt .recon-main-table th:nth-child(19){width:55px} +#page-customer-recon-stmt .recon-main-table th:nth-child(18),#page-customer-recon-stmt .recon-main-table th:nth-child(20){width:120px} #page-customer-recon-stmt .recon-main-table td:first-child{overflow:visible;text-overflow:clip;text-align:left;font-size:9px} -#page-customer-recon-stmt .recon-main-table td:nth-child(12),#page-customer-recon-stmt .recon-main-table td:nth-child(14),#page-customer-recon-stmt .recon-main-table td:nth-child(17),#page-customer-recon-stmt .recon-main-table td:nth-child(19){font-size:10px} +#page-customer-recon-stmt .recon-main-table td:nth-child(13),#page-customer-recon-stmt .recon-main-table td:nth-child(15),#page-customer-recon-stmt .recon-main-table td:nth-child(18),#page-customer-recon-stmt .recon-main-table td:nth-child(20){font-size:10px} +#page-customer-recon-stmt .recon-action-link{border:0;background:transparent;padding:2px 3px;color:#1677ff;font:10px inherit;cursor:pointer} +#page-customer-recon-stmt .recon-action-link:hover{text-decoration:underline} +#page-customer-recon-stmt .recon-action-link.is-danger{color:#f5222d} +#page-customer-recon-stmt .recon-action-link.is-success{color:#16a34a} +#page-customer-recon-stmt .recon-action-link:disabled{color:#b8b8b8;cursor:not-allowed;text-decoration:none} #page-customer-recon-stmt .recon-detail-empty{padding:16px!important} @media(max-width:1500px){.rsq-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.rsq-span-2{grid-column:span 2}.rsq-actions{grid-column:span 2;justify-content:flex-end}} @media(max-width:900px){.rsq-grid{grid-template-columns:1fr}.rsq-span-2,.rsq-actions{grid-column:span 1}.rsq-field{align-items:flex-start;flex-direction:column}.rsq-field>input,.rsq-field>select,.rsq-date{width:100%}} @@ -545,6 +559,45 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .dispatch-actions{display:flex;flex-direction:column;align-items:flex-start;gap:5px;min-width:86px} .dispatch-actions a{color:#2563eb;font-size:11px;line-height:1.35;text-decoration:none;white-space:nowrap} .dispatch-actions a:hover{text-decoration:underline} +.dispatch-actions .dispatch-action-danger{color:#dc2626} +.dispatch-actions .dispatch-action-danger:hover{color:#b91c1c} +.dispatch-actions .dispatch-cancel-action.is-blocked{color:#9ca3af;text-decoration:none;cursor:not-allowed} +.dispatch-cancel-picking{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;margin-bottom:14px;border:1px solid #e5e7eb;border-radius:6px;background:#f9fafb} +.dispatch-cancel-picking span{color:#6b7280;font-size:12px} +.dispatch-cancel-picking strong{font-size:13px;color:#1f2937} +.dispatch-waybill{color:#2563eb;font-weight:500} +.dispatch-waybill-alert{color:#dc2626!important;text-decoration:underline;text-decoration-style:dotted;text-underline-offset:3px;cursor:help} +.dispatch-waybill-alert:hover,.dispatch-waybill-alert:focus-visible{color:#b91c1c!important;outline:none} +.dispatch-reject-close{font-size:20px;line-height:1;cursor:pointer;color:#6b7280} +.dispatch-reject-close:hover{color:#111827} +.dispatch-reject-meta{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:18px} +.dispatch-reject-meta>div{min-width:0;padding:10px 12px;border:1px solid #e5e7eb;border-radius:6px;background:#f9fafb} +.dispatch-reject-meta>div:first-child{grid-column:1/-1} +.dispatch-reject-meta span{display:block;margin-bottom:4px;color:#6b7280;font-size:12px} +.dispatch-reject-meta strong{display:block;overflow-wrap:anywhere;color:#1f2937;font-size:13px;font-weight:600} +.dispatch-reject-notify-row{display:flex;align-items:flex-start;gap:10px;padding:12px;border:1px solid #dbeafe;border-radius:6px;background:#eff6ff;cursor:pointer} +.dispatch-reject-notify-row input{width:16px;height:16px;margin:2px 0 0;accent-color:#2563eb;flex:0 0 auto} +.dispatch-reject-notify-row span{display:flex;flex-direction:column;gap:3px;min-width:0} +.dispatch-reject-notify-row strong{color:#1e3a8a;font-size:13px} +.dispatch-reject-notify-row small{color:#1e40af;font-size:12px;line-height:1.45} +.dispatch-exception-summary{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px} +.dispatch-exception-kpi{display:flex;align-items:baseline;gap:6px;padding:10px 14px;border:1px solid #e5e7eb;border-radius:6px;background:#fff} +.dispatch-exception-kpi strong{font-size:18px;color:#111827} +.dispatch-exception-kpi span{font-size:12px;color:#6b7280} +.dispatch-exception-no{color:#1f2937;font-weight:600;white-space:nowrap} +.dispatch-exception-relations{display:flex;min-width:190px;flex-direction:column;gap:3px} +.dispatch-exception-relation{display:grid;grid-template-columns:34px minmax(0,1fr);align-items:baseline;gap:6px;line-height:1.4} +.dispatch-exception-relation-label{color:#9ca3af;font-size:11px;white-space:nowrap} +.dispatch-exception-relation-no{min-width:0;color:#374151;font-size:12px;overflow-wrap:anywhere} +.dispatch-exception-related-meta{grid-column:1/-1} +.dispatch-exception-related-meta .dispatch-exception-relations{min-width:0} +.dispatch-exception-type{font-weight:600;white-space:nowrap} +.dispatch-exception-reason{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#4b5563} +.dispatch-exception-actions{display:flex;flex-wrap:wrap;gap:6px;white-space:nowrap} +.dispatch-exception-actions a{color:#2563eb;font-size:12px;text-decoration:none} +.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} .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} @@ -574,7 +627,62 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font .dispatch-doc-upload-label:hover,.dispatch-doc-upload-label:focus-within{border-color:#2563eb;background:#eff6ff} .dispatch-doc-delete{padding:4px 7px;border:1px solid #fecaca;border-radius:4px;background:#fff;color:#b91c1c;font-size:11px;cursor:pointer} .dispatch-doc-delete:disabled{border-color:#e5e7eb;color:#9ca3af;cursor:not-allowed} -@media(max-width:700px){.dispatch-doc-modal-meta{grid-template-columns:1fr}.dispatch-doc-row{grid-template-columns:1fr}.dispatch-doc-controls{justify-content:flex-start}} +.edit-fleet-form{display:flex;flex-direction:column;gap:14px} +.edit-fleet-field{display:grid;grid-template-columns:100px minmax(0,1fr);align-items:center;gap:12px} +.edit-fleet-field-top{align-items:start} +.edit-fleet-field>label{color:#374151;font-size:13px;text-align:right;white-space:nowrap} +.edit-fleet-field input,.edit-fleet-field select,.edit-fleet-field textarea{width:100%;padding:8px 10px;border:1px solid #d1d5db;border-radius:6px;background:#fff;color:#374151;font:inherit;outline:none} +.edit-fleet-field input:focus,.edit-fleet-field select:focus,.edit-fleet-field textarea:focus{border-color:#3b82f6;box-shadow:0 0 0 2px rgba(59,130,246,.08)} +.edit-fleet-field input[readonly]{background:#f5f7fa;color:#6b7280} +.edit-fleet-current{padding:9px 11px;border:1px solid #dbeafe;border-radius:6px;background:#eff6ff;color:#1e40af;font-size:13px;font-weight:600;min-height:38px;display:flex;align-items:center} +.edit-fleet-required{color:#ef4444;margin-right:2px} +.edit-fleet-reason-wrap{min-width:0} +.edit-fleet-reason-wrap textarea{resize:vertical;min-height:78px} +.edit-fleet-reason-wrap textarea:disabled{background:#f5f7fa;color:#9ca3af;cursor:not-allowed} +.edit-fleet-reason-hint{margin-top:5px;color:#6b7280;font-size:11px;line-height:1.4} +.edit-fleet-reason-hint.is-required{color:#b45309} +.vehicle-fleet-reason{max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#374151} +.vehicle-region-tabs{display:flex;align-items:center;gap:0;margin:0 0 14px;border-bottom:1px solid #dfe5ee} +.vehicle-region-tab{min-width:116px;height:42px;padding:0 22px;border:0;border-bottom:2px solid transparent;background:#fff;color:#5f6b7a;font-size:14px;font-weight:500;cursor:pointer} +.vehicle-region-tab:hover{color:#1677ff;background:#f7faff} +.vehicle-region-tab.active{border-bottom-color:#1677ff;color:#1677ff;font-weight:650} +.warehouse-page-tabs{display:flex;align-items:center;gap:0;margin:0 0 14px;border-bottom:1px solid #dfe5ee;overflow-x:auto} +.warehouse-page-tab{min-width:116px;height:42px;padding:0 22px;border:0;border-bottom:2px solid transparent;background:#fff;color:#5f6b7a;font-size:14px;font-weight:500;cursor:pointer} +.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} +.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} +.vehicle-owner-tab:hover{color:#1f2937} +.vehicle-owner-tab.active{background:#fff;color:#1f2937;font-weight:650;box-shadow:0 1px 3px rgba(15,23,42,.12)} +.vehicle-region-tab:focus-visible,.vehicle-owner-tab:focus-visible{outline:2px solid #1677ff;outline-offset:2px} +.vehicle-detail-card{width:100%;max-width:1280px;overflow:hidden} +.vehicle-detail-head{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;padding:18px 24px;border-bottom:1px solid #edf0f4;background:#fff} +.vehicle-detail-title{color:#1f2937;font-size:18px;font-weight:700;line-height:1.4} +.vehicle-detail-meta{display:flex;align-items:center;gap:10px;margin-top:6px;color:#64748b;font-size:13px} +.vehicle-detail-meta>span:first-child{color:#334155;font-weight:600} +.vehicle-detail-body{padding:20px 24px 24px} +.vehicle-detail-section{margin:0;padding:0} +.vehicle-detail-section+.vehicle-detail-section{margin-top:26px} +.vehicle-detail-section h3{margin:0 0 12px;color:#273449;font-size:14px;font-weight:650;line-height:1.5} +.vehicle-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 36px;border-top:1px solid #edf0f4} +.vehicle-detail-field{display:grid;grid-template-columns:124px minmax(0,1fr);align-items:start;min-height:44px;padding:11px 0;border-bottom:1px solid #edf0f4;font-size:13px;line-height:1.65} +.vehicle-detail-label{color:#768398} +.vehicle-detail-value{min-width:0;color:#273449;font-weight:500;overflow-wrap:anywhere} +.vehicle-detail-table-scroll{overflow-x:auto;border:1px solid #dfe5ee;border-radius:6px;background:#fff} +.vehicle-detail-table{width:100%;min-width:820px;border-collapse:collapse;font-size:12px} +.vehicle-detail-table th,.vehicle-detail-table td{padding:10px 12px;border-bottom:1px solid #edf0f4;text-align:left;white-space:nowrap} +.vehicle-detail-table th{background:#f5f7fa;color:#5f6b7a;font-weight:600} +.vehicle-detail-table td{color:#374151} +.vehicle-detail-table tbody tr:last-child td{border-bottom:0} +.vehicle-detail-empty{padding:24px!important;text-align:center!important;color:#94a3b8!important} +.vehicle-detail-relation{display:inline-block;padding:2px 9px;border-radius:10px;font-size:12px;line-height:1.5} +.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}} .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} @@ -888,6 +996,20 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font /* ===== 全局列表统一规范(以海外仓库存列表为基准) ===== */ .page .table-card{background:#fff;border:1px solid #e5eaf1;border-radius:12px;box-shadow:0 3px 12px rgba(15,23,42,.05);backdrop-filter:none} +.location-search-row{flex-wrap:wrap;gap:8px} +.location-search-row select,.location-search-row input{width:160px} +.location-search-row select:nth-child(2){width:140px} +.location-search-row select:nth-child(4){width:120px} +.location-table-scroll{overflow-x:auto} +.location-table-scroll table{min-width:1120px;font-size:12px} +.location-table-scroll th,.location-table-scroll td{white-space:nowrap} +.location-table-scroll .location-operation{width:92px} +.location-table-scroll .location-operation a{color:#1890ff;text-decoration:none;margin-right:14px} +.location-table-scroll .location-operation .location-delete{color:#f5222d;margin-right:0} +.location-table-scroll .location-code{font-weight:600;color:#1f2937} +.location-table-scroll .location-weight{text-align:right} +.location-table-scroll .location-remark{color:#94a3b8} +@media(max-width:600px){#modal-domestic-location .modal,#modal-overseas-location .modal{width:calc(100% - 24px);max-height:calc(100vh - 24px);border-radius:16px}#modal-domestic-location .modal-header,#modal-overseas-location .modal-header{padding:16px 18px}#modal-domestic-location .modal-body,#modal-overseas-location .modal-body{padding:18px}#modal-domestic-location .modal-footer,#modal-overseas-location .modal-footer{padding:14px 18px}#modal-domestic-location .form-row,#modal-overseas-location .form-row{grid-template-columns:minmax(0,1fr);gap:14px;margin-bottom:14px}#modal-domestic-location .form-group,#modal-overseas-location .form-group{min-width:0}#modal-domestic-location .form-group input,#modal-domestic-location .form-group select,#modal-domestic-location .form-group textarea,#modal-overseas-location .form-group input,#modal-overseas-location .form-group select,#modal-overseas-location .form-group textarea{width:100%;min-width:0}#modal-domestic-location .form-group[style*="visibility:hidden"],#modal-overseas-location .form-group[style*="visibility:hidden"]{display:none}} .page .table-toolbar{min-height:56px;box-sizing:border-box;padding:13px 18px;border-bottom:1px solid #e8edf3;background:#fff} .page .table-toolbar .title{font-size:15px;font-weight:700;color:#1f2937} .inventory-management-tabs{display:flex;align-items:center;gap:0;min-height:50px;margin-bottom:12px;padding:0 18px;overflow-x:auto;background:#fff;border:1px solid #e5eaf1;border-radius:8px;box-shadow:0 2px 8px rgba(15,23,42,.04)} @@ -979,6 +1101,82 @@ body.dashboard-fullscreen #page-dashboard>.table-card .btn{padding:4px 10px;font body.dashboard-fullscreen #page-dashboard table:has(>thead)>thead>tr>th{background:rgba(38,76,109,.35)!important;color:#8fa8be!important;border-color:rgba(92,141,184,.16)!important} body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{background:transparent!important;color:#c8d8e7!important;border-color:rgba(92,141,184,.12)!important} +.outbound-vehicle-modal{display:flex;flex-direction:column;width:min(1080px,calc(100vw - 32px));max-width:1080px;max-height:calc(100vh - 32px);border-radius:8px;overflow:hidden} +.outbound-vehicle-modal>.modal-header{flex:0 0 auto;padding:18px 20px;background:#fff;border-bottom:1px solid #e5e7eb;font-size:16px} +.outbound-vehicle-modal-body{flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;overflow-x:hidden;padding:18px 20px} +.outbound-vehicle-modal>.modal-footer{flex:0 0 auto;padding:14px 20px;border-top:1px solid #e5e7eb;background:#fff} +.outbound-vehicle-tabs{display:flex;border-bottom:1px solid #e5e7eb;padding:0 20px;background:#fff} +.outbound-vehicle-tabs button{min-height:42px;padding:0 16px;border:0;border-bottom:2px solid transparent;background:transparent;color:#64748b;cursor:pointer} +.outbound-vehicle-tabs button.active{border-bottom-color:#2563eb;color:#2563eb;font-weight:600} +.outbound-vehicle-modal-close{border:0;background:transparent;color:#64748b;cursor:pointer;font-size:22px;line-height:1} +.outbound-vehicle-form-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px 16px} +.outbound-vehicle-form-grid .form-group{min-width:0;margin:0}.outbound-vehicle-form-grid input,.outbound-vehicle-form-grid select{width:100%;box-sizing:border-box} +.outbound-vehicle-modal [hidden]{display:none!important} +.outbound-vehicle-section-title{margin:18px 0 12px;padding-bottom:8px;border-bottom:1px solid #e5e7eb;color:#334155;font-size:14px;font-weight:700}.outbound-vehicle-section-title:first-child{margin-top:0} +.outbound-vehicle-table-wrap{overflow:auto;border:1px solid #e5e7eb;border-radius:6px}.outbound-vehicle-table-wrap table{min-width:780px}.outbound-vehicle-empty{padding:36px 16px;text-align:center;color:#94a3b8} +.dispatch-row-located{animation:dispatch-row-located 1.8s ease-out}@keyframes dispatch-row-located{0%,45%{background:#fef3c7}100%{background:transparent}} +@media(max-width:760px){.outbound-vehicle-modal{width:calc(100vw - 16px);max-height:calc(100vh - 16px)}.outbound-vehicle-modal>.modal-header{padding:14px}.outbound-vehicle-modal-body{padding:14px}.outbound-vehicle-form-grid,.outbound-vehicle-edit-modal .form-row{grid-template-columns:1fr}.outbound-vehicle-section-title{margin-top:16px}.outbound-vehicle-modal>.modal-footer{padding:12px 14px}.outbound-vehicle-modal .modal-footer .btn{min-width:0}} +#modal-fba-carton-form .form-group{min-width:0} +#modal-fba-carton-form input,#modal-fba-carton-form select,#modal-fba-carton-form textarea{box-sizing:border-box;max-width:100%} +@media(max-width:600px){#modal-fba-carton-form .modal{display:flex;flex-direction:column;width:calc(100vw - 24px)!important;max-height:calc(100vh - 24px);overflow:hidden}#modal-fba-carton-form .modal-body{overflow-x:hidden;overflow-y:auto;padding:18px}#modal-fba-carton-form .form-row{grid-template-columns:minmax(0,1fr);gap:14px;margin-bottom:14px}#modal-fba-carton-form .modal-footer{flex:0 0 auto;padding:12px 18px}#modal-fba-carton-form .modal-footer .btn{min-width:0}} + +/* ===== 货柜托盘标全屏预览 ===== */ +.ct-pallet-preview-modal{--ct-pallet-code-size:120px;--ct-pallet-destination-size:180px;inset:0;padding:0;background:#1b1f22;backdrop-filter:none;align-items:stretch;justify-content:stretch} +.ct-pallet-preview-panel{width:100vw;max-width:none;height:100vh;max-height:none;border:0;border-radius:0;box-shadow:none;overflow:hidden;display:flex;flex-direction:column;background:#1b1f22;animation:none} +.ct-pallet-preview-toolbar{min-height:72px;flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:20px;padding:12px 18px;border-bottom:1px solid #343a3f;background:#252a2e;color:#fff;box-sizing:border-box} +.ct-pallet-preview-meta{flex:0 0 176px;display:grid;gap:3px;min-width:176px} +.ct-pallet-preview-meta>span{font-size:12px;color:#b9c0c5} +.ct-pallet-preview-meta strong{font-size:15px;color:#fff;white-space:nowrap} +.ct-pallet-preview-controls{display:flex;align-items:center;justify-content:flex-end;gap:10px;min-width:0;flex-wrap:wrap} +.ct-pallet-font-control{display:flex;align-items:center;gap:8px;white-space:nowrap;font-size:12px;color:#d9dee2} +.ct-pallet-font-stepper{height:34px;display:grid;grid-template-columns:34px 48px 34px;align-items:stretch;border:1px solid #535b61;border-radius:6px;overflow:hidden;background:#1b1f22} +.ct-pallet-font-stepper button{border:0;background:#343a3f;color:#fff;font-size:18px;line-height:1;cursor:pointer} +.ct-pallet-font-stepper button:hover{background:#454d53} +.ct-pallet-font-stepper button:focus-visible,.ct-pallet-preview-close:focus-visible,.ct-pallet-preview-toolbar .btn:focus-visible{outline:2px solid #69b1ff;outline-offset:2px} +.ct-pallet-font-stepper output{display:flex;align-items:center;justify-content:center;border-inline:1px solid #535b61;color:#fff;font-size:12px;font-variant-numeric:tabular-nums} +.ct-pallet-preview-toolbar .btn{height:34px;padding:0 14px;border-radius:6px;font-size:12px;box-shadow:none;transform:none} +.ct-pallet-preview-toolbar .btn-default{background:#fff;color:#374151;border:1px solid #d1d5db} +.ct-pallet-preview-toolbar .btn-primary{background:#1677ff;color:#fff;border:1px solid #1677ff} +.ct-pallet-print-action{background:#0958d9!important;border:1px solid #0958d9!important;color:#fff} +.ct-pallet-print-action:hover,.ct-pallet-print-action:focus{background:#003eb3!important;border-color:#003eb3!important;color:#fff} +.ct-pallet-preview-toolbar .btn:hover{transform:none;box-shadow:none} +.ct-pallet-preview-close{width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:6px;background:transparent;color:#d9dee2;font-size:24px;line-height:1;cursor:pointer} +.ct-pallet-preview-close:hover{background:#343a3f;color:#fff} +.ct-pallet-preview-scroll{flex:1;min-width:0;min-height:0;overflow:auto;padding:28px;background:#1b1f22;box-sizing:border-box} +#ct-pallet-label-list{width:max-content;min-width:100%;display:grid;justify-items:center;gap:28px} +.ct-pallet-label-sheet{page:ctPalletLabel;position:relative;width:297mm;height:210mm;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12mm;padding:14mm;background:#fff;color:#000;box-shadow:0 8px 28px rgba(0,0,0,.34);overflow:hidden;page-break-after:always;break-after:page;font-family:"Microsoft YaHei","SimHei",sans-serif} +.ct-pallet-label-sheet:last-child{page-break-after:auto;break-after:auto} +.ct-pallet-label-code,.ct-pallet-label-destination{width:100%;max-width:100%;margin:0;text-align:center;font-weight:900;line-height:.95;letter-spacing:0;overflow-wrap:anywhere;word-break:break-word} +.ct-pallet-label-code{font-size:var(--ct-pallet-code-size)} +.ct-pallet-label-destination{font-size:var(--ct-pallet-destination-size)} +.ct-pallet-label-empty{width:min(520px,calc(100vw - 48px));padding:28px;text-align:center;color:#c8cdd1;border:1px solid #454b50;border-radius:6px;background:#252a2e;box-sizing:border-box} +@media(max-width:900px){ + .ct-pallet-preview-toolbar{align-items:flex-start;gap:10px;padding:10px 12px;flex-wrap:wrap} + .ct-pallet-preview-meta{flex-basis:100%;min-width:0} + .ct-pallet-preview-controls{width:100%;justify-content:flex-start} + .ct-pallet-preview-scroll{padding:16px 12px} +} +@media(max-width:760px){ + .ct-pallet-preview-controls{gap:8px} + .ct-pallet-preview-controls .btn,.ct-pallet-preview-controls .booking-print-close,.ct-pallet-preview-controls .ct-pallet-preview-close,.ct-pallet-font-control button{min-height:40px} + .ct-pallet-preview-controls .ct-pallet-preview-close{min-width:40px} + .ct-pallet-font-stepper{height:40px;grid-template-columns:40px 48px 40px} + .ct-pallet-font-stepper button{width:40px;height:40px} +} +@page ctPalletLabel{size:A4 landscape;margin:0} +@media print{ + html:has(body.ct-pallet-printing),body.ct-pallet-printing{width:297mm!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.ct-pallet-printing>*:not(#modal-ct-pallet-label-preview){display:none!important} + body.ct-pallet-printing #modal-booking-print-preview{display:none!important} + body.ct-pallet-printing #modal-ct-pallet-label-preview{display:block!important;position:static!important;inset:auto!important;width:297mm!important;height:auto!important;padding:0!important;background:#fff!important} + body.ct-pallet-printing #modal-ct-pallet-label-preview,body.ct-pallet-printing #modal-ct-pallet-label-preview *{visibility:visible!important} + body.ct-pallet-printing .ct-pallet-preview-panel{display:block!important;position:static!important;width:297mm!important;height:auto!important;max-width:none!important;max-height:none!important;margin:0!important;background:#fff!important;overflow:visible!important} + body.ct-pallet-printing .ct-pallet-preview-toolbar{display:none!important} + body.ct-pallet-printing .ct-pallet-preview-scroll{display:block!important;position:static!important;width:297mm!important;height:auto!important;padding:0!important;background:#fff!important;overflow:visible!important} + body.ct-pallet-printing #ct-pallet-label-list{display:block!important;width:297mm!important;min-width:0!important;margin:0!important} + body.ct-pallet-printing .ct-pallet-label-sheet{display:flex!important;width:297mm!important;height:210mm!important;margin:0!important;box-shadow:none!important;page-break-after:always;break-after:page} + body.ct-pallet-printing .ct-pallet-label-sheet:last-child{page-break-after:auto;break-after:auto} +} @@ -1035,8 +1233,8 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - + @@ -1049,7 +1247,6 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou - @@ -1060,6 +1257,12 @@ body.dashboard-fullscreen #page-dashboard table:has(>thead)>tbody>tr>td{backgrou +