diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index a0dc51b6e..5b0b228c2 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -18690,6 +18690,9 @@ DELIMITER ; CALL migrate_container_workspace_permissions(); DROP PROCEDURE IF EXISTS migrate_container_workspace_permissions; +-- 货柜双工作台权限结束,恢复头程数据库上下文 +USE baiyue_firstleg; + -- 财务 P0:海外费用原币、计费依据与钱包结算关联 DROP PROCEDURE IF EXISTS add_finance_p0_column; DELIMITER $$ @@ -18721,8 +18724,6 @@ DROP PROCEDURE IF EXISTS add_finance_p0_column; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_finance' AND table_name='fin_fee_source' AND index_name='idx_fin_fee_source_wallet_hold'), 'SELECT 1', 'ALTER TABLE baiyue_finance.fin_fee_source ADD KEY idx_fin_fee_source_wallet_hold(wallet_hold_id)')); PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement; --- 货柜双工作台权限结束,恢复头程数据库上下文 -USE baiyue_firstleg; CALL baiyue_firstleg.assert_unified_final_schema(); DROP PROCEDURE IF EXISTS baiyue_firstleg.assert_unified_final_schema; diff --git a/deploy/sql/海外区域统一增量-MySQL8.sql b/deploy/sql/海外区域统一增量-MySQL8.sql index 365e522e3..81c076182 100644 --- a/deploy/sql/海外区域统一增量-MySQL8.sql +++ b/deploy/sql/海外区域统一增量-MySQL8.sql @@ -2045,15 +2045,15 @@ CREATE TABLE IF NOT EXISTS ll_return_inventory_operation ( id BIGINT NOT NULL COMMENT '退货库存PDA操作ID', operator_id VARCHAR(128) NOT NULL COMMENT 'PDA操作人ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型,当前MERGE', result_carton_id BIGINT NULL COMMENT '合箱结果退货库存箱ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_operation_operator_key(operator_id,idempotency_key), KEY idx_ll_return_inventory_operation_result(result_carton_id) ) ENGINE=InnoDB COMMENT='退货库存PDA合箱幂等操作审计'; -SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='bol_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN bol_no VARCHAR(128) NULL')); +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='bol_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN bol_no VARCHAR(128) NULL COMMENT ''派送资料BOL号,不作为文件归属标识''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='documents_json'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN documents_json JSON NULL')); +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='documents_json'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN documents_json JSON NULL COMMENT ''派送三类资料当前绑定及权威文件元数据快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_id VARCHAR(128) NULL')); +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_id VARCHAR(128) NULL COMMENT ''换标申请总资料文件ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_name VARCHAR(255) NULL')); +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_name VARCHAR(255) NULL COMMENT ''换标申请总资料文件名''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_url VARCHAR(1000) NULL')); +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_url VARCHAR(1000) NULL COMMENT ''换标申请总资料下载地址''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='pallet_no' AND column_type='varchar(128)' AND is_nullable='NO'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN pallet_no VARCHAR(128) NOT NULL COMMENT ''海外仓资源服务返回的真实托盘码''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/DeliveryTransferController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/DeliveryTransferController.java index 5568f4b1c..3934c7380 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/DeliveryTransferController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/DeliveryTransferController.java @@ -37,7 +37,7 @@ public class DeliveryTransferController { @PreAuthorize("hasAuthority('" + OverseasPermissions.OUTBOUND_CREATE + "')") @Operation(summary = "Create one-click dropship outbound and push a PDA picking task") public ApiResponse createOneClick( - @AuthenticationPrincipal AuthenticatedUser user, @RequestParam(required = false) String customerId, + @AuthenticationPrincipal AuthenticatedUser user, @RequestParam String customerId, @Valid @RequestBody DeliveryRequests.OneClickOutbound request) { return ApiResponse.success(service.createOneClick(requiredCustomer(user, customerId), operator(user), request)); } diff --git a/scripts/README.md b/scripts/README.md index 36fa19d82..a706e34a4 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -80,7 +80,7 @@ Client 全量、Client 入库测量与计费、待审核订单和批量待分柜 | 订单与客户本地验收 | `phase1-business-maturity-regression.ps1` | 订单与客户业务成熟度回归,调用本地服务并生成报告 | | 订单与客户本地验收 | `phase1-onboarding-order-e2e.ps1` | 注册、资质、审核到下单的本地 E2E,会创建客户、仓库、往来单位和订单 | | 本地质量 | `backend-full-regression.ps1` | Mapper 门禁后执行受影响后端 Maven 测试;`-DryRun` 只打印与校验 | -| 本地质量 | `frontend-full-regression.ps1` | 编排 Admin/Client 本地测试、类型检查及国内 PDA Node 全量测试,不访问 Gateway | +| 本地质量 | `frontend-full-regression.ps1` | 编排 Admin/Client 本地测试、类型检查及国内/海外 PDA Node 全量测试,不访问 Gateway | | 本地质量 | `database-comment-audit.ps1` | 离线扫描数据库中文注释,不连接数据库 | | 本地质量 | `local-db-full-acceptance.ps1` | 只允许本机 MySQL 的受控 SQL 验收;非 dry-run 会写本地测试库 | | 本地质量 | `mapper-scan-contract.mjs` | 离线检查 Mapper 注解与扫描入口,不启动 Spring、不连接数据库 | @@ -89,6 +89,7 @@ Client 全量、Client 入库测量与计费、待审核订单和批量待分柜 | 契约数据 | `synchronous-dependency-baseline.mjs` | 同步服务依赖合同的数据源,只由相邻合同测试导入,不是 CLI | | OpenAPI | `openapi-validation/validate-openapi.mjs` | 发现并解析各服务 OpenAPI,检查跨文件引用;只读源码 | | 本地环境 | `local-env.ps1` | 本地开发环境公共参数/辅助函数,由其他 PowerShell 脚本加载 | +| 本地环境 | `start-gateway-overseas-local.ps1` | 使用本地 Maven 启动海外 Gateway,并将海外安全投影地址指向本机;会启动本地 Java 进程,不访问或修改共享环境 | | 本地环境 | `publish-local-nacos-config.ps1` | 将 `config/nacos/local/*.yml` 发布到指定本地 Nacos,会修改 Nacos 配置 | | Nacos 环境选择 | `use-nacos-environment.ps1` | 按显式环境与区域设置当前 PowerShell 进程的 Nacos、Spring Profile 和运行区域变量;开发/测试密码必须由参数或环境变量提供,不发布配置 | | Nacos 配置发布 | `publish-nacos-config.ps1` | 将 `config/nacos/{local|cn|overseas}/*.yml` 发布到显式指定的 Nacos;非本地环境强制要求非 public namespace,会修改目标 Nacos 配置,执行前须取得对应环境授权 | @@ -154,7 +155,7 @@ node scripts/create-pending-review-orders.mjs | 检查 | 入口 | |---|---| | 后端 Maven 契约/单元测试 | `scripts/backend-full-regression.ps1` | -| Admin/Client/国内 PDA 本地全量回归 | `scripts/frontend-full-regression.ps1` | +| Admin/Client/国内与海外 PDA 本地全量回归 | `scripts/frontend-full-regression.ps1` | | PDA 本地页面和状态定向测试 | `../apps/pda-uniapp/tests/*.test.mjs` | | 本地数据库 SQL 静态/受控验收 | `scripts/local-db-full-acceptance.ps1` | | AGENTS 快速索引一致性 | `scripts/agents-index-contract.ps1`;只读核对根快速表唯一性、部署单元、业务模块、Client active 路由、海外仓业务范围漂移、仓库主档唯一权威、订舱候选与柜量语义、整柜出仓与船节点单调性、海外 Gateway 覆盖、PDA 页面/运行配置/独立更新/语言预留/能力开关、人工分段验收链、Maven 模块、Lastleg 海外安全投影、同步 Trace、关键入口与排除目录 | @@ -183,7 +184,7 @@ Admin/Client HTTP 脚本的离线合同只验证脚本结构、参数和模块 ## 前端全量回归 -`frontend-full-regression.ps1` 编排本地 Admin/Client 的 `pnpm test`、`pnpm typecheck`,并默认执行国内 PDA 的 `node --test tests/*.test.mjs`;不调用 Gateway、不部署、不连接数据库。 +`frontend-full-regression.ps1` 编排本地 Admin/Client 的 `pnpm test`、`pnpm typecheck`,并默认执行国内与海外 PDA 的 `node --test tests/*.test.mjs`;不调用 Gateway、不部署、不连接数据库。 ```powershell .\scripts\frontend-full-regression.ps1 -DryRun diff --git a/scripts/admin-test-env-modules/fulfillment-prototype-field-matrix-contract.test.mjs b/scripts/admin-test-env-modules/fulfillment-prototype-field-matrix-contract.test.mjs index 3252d2fbb..276c88666 100644 --- a/scripts/admin-test-env-modules/fulfillment-prototype-field-matrix-contract.test.mjs +++ b/scripts/admin-test-env-modules/fulfillment-prototype-field-matrix-contract.test.mjs @@ -34,7 +34,7 @@ test('原型锁定货柜、预装、装柜、订舱与拖车关键列表字段', test('现行 Admin 履约列表均以左固定操作列开头', () => { const sources = [ - ['container-loading/pages/ContainersView.vue', 1], + ['container-loading/pages/ContainersView.vue', 2], ['loading-lists/components/LoadingListsView.vue', 2], ['ocean-bookings/pages/OceanBookingsView.vue', 1], ['port-schedules/pages/PortSchedulesView.vue', 1], diff --git a/scripts/frontend-full-regression.ps1 b/scripts/frontend-full-regression.ps1 index 62da1863c..3baa4a15b 100644 --- a/scripts/frontend-full-regression.ps1 +++ b/scripts/frontend-full-regression.ps1 @@ -53,12 +53,17 @@ foreach ($target in $targets) { } if (-not $SkipPda) { - $pdaDirectory = Join-Path $repoRoot 'apps/pda-uniapp' - if (-not (Test-Path -LiteralPath (Join-Path $pdaDirectory 'tests'))) { - Write-Error "PDA tests directory not found: $pdaDirectory"; exit 2 + $pdaTargets = @( + @{ Name = 'Domestic PDA'; Directory = Join-Path $repoRoot 'apps/pda-uniapp' }, + @{ Name = 'Overseas PDA'; Directory = Join-Path $repoRoot 'apps/pda-overseas-uniapp' } + ) + foreach ($pdaTarget in $pdaTargets) { + if (-not (Test-Path -LiteralPath (Join-Path $pdaTarget.Directory 'tests'))) { + Write-Error "$($pdaTarget.Name) tests directory not found: $($pdaTarget.Directory)"; exit 2 + } + Write-Host "[$($pdaTarget.Name)]" + Invoke-PdaTests $pdaTarget.Directory } - Write-Host '[PDA]' - Invoke-PdaTests $pdaDirectory } Write-Host 'Frontend regression completed.' diff --git a/scripts/full-regression-entry-contract.test.mjs b/scripts/full-regression-entry-contract.test.mjs index 747b9542f..74939ae8a 100644 --- a/scripts/full-regression-entry-contract.test.mjs +++ b/scripts/full-regression-entry-contract.test.mjs @@ -10,9 +10,12 @@ const backendScript = readFileSync(resolve(scriptsDir, 'backend-full-regression. const frontendScript = readFileSync(resolve(scriptsDir, 'frontend-full-regression.ps1'), 'utf8') const adminAcceptance = readFileSync(resolve(scriptsDir, 'admin-test-env-acceptance.mjs'), 'utf8') -test('frontend full regression includes domestic PDA node tests by default', () => { +test('frontend full regression includes domestic and overseas PDA node tests by default', () => { assert.match(frontendScript, /\[switch\]\$SkipPda/) assert.match(frontendScript, /apps\/pda-uniapp/) + assert.match(frontendScript, /apps\/pda-overseas-uniapp/) + assert.match(frontendScript, /Domestic PDA/) + assert.match(frontendScript, /Overseas PDA/) assert.match(frontendScript, /node --test/) assert.match(frontendScript, /tests\/\*\.test\.mjs/) })