提交
This commit is contained in:
@@ -0,0 +1,775 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS baiyue_firstleg
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||
USE baiyue_firstleg;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_container_booking (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID(雪花ID)',
|
||||
booking_no VARCHAR(40) NOT NULL COMMENT '平台唯一货柜预订单号',
|
||||
container_no VARCHAR(64) NULL COMMENT '集装箱号;确认前允许修订',
|
||||
cabinet_no VARCHAR(64) NOT NULL COMMENT '平台唯一内部柜号',
|
||||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '装柜仓库ID;平台公共资源',
|
||||
warehouse_name VARCHAR(128) NOT NULL COMMENT '装柜仓库名称快照',
|
||||
bill_of_lading_no VARCHAR(128) NULL COMMENT '提单号',
|
||||
vessel_name VARCHAR(128) NULL COMMENT '船名快照',
|
||||
voyage_no VARCHAR(64) NULL COMMENT '航次;确认前允许修订',
|
||||
container_type VARCHAR(32) NOT NULL COMMENT '箱型,例如20GP、40GP、40HQ',
|
||||
shipping_company_id BIGINT UNSIGNED NULL COMMENT '船司ID快照',
|
||||
shipping_company_name VARCHAR(128) NULL COMMENT '船司名称快照',
|
||||
departure_port_code VARCHAR(32) NULL COMMENT '起运港编码快照',
|
||||
departure_port_name VARCHAR(128) NULL COMMENT '起运港名称快照',
|
||||
destination_port_code VARCHAR(32) NULL COMMENT '目的港编码快照',
|
||||
destination_port_name VARCHAR(128) NULL COMMENT '目的港名称快照',
|
||||
destination_warehouse_code VARCHAR(64) NULL COMMENT '目的仓编码快照',
|
||||
destination_warehouse_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||||
capacity_cbm DECIMAL(18,4) NULL COMMENT '货柜容量m3',
|
||||
max_weight_kg DECIMAL(18,3) NULL COMMENT '货柜最大承重kg',
|
||||
terminal_trucking_company VARCHAR(128) NULL COMMENT '码头拖车公司',
|
||||
loading_at DATETIME(3) NULL COMMENT '计划或实际装柜时间',
|
||||
estimated_sailing_at DATETIME(3) NULL COMMENT '预计开船时间',
|
||||
actual_sailing_at DATETIME(3) NULL COMMENT '实际开船时间',
|
||||
estimated_port_arrival_at DATETIME(3) NULL COMMENT '预计到港时间',
|
||||
actual_port_arrival_at DATETIME(3) NULL COMMENT '实际到港时间',
|
||||
estimated_warehouse_arrival_at DATETIME(3) NULL COMMENT '预计到仓时间',
|
||||
actual_warehouse_arrival_at DATETIME(3) NULL COMMENT '实际到仓时间',
|
||||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||||
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||||
updated_by_name VARCHAR(64) NULL COMMENT '最后修改人名称快照',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
COMMENT '更新时间',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_container_booking_no (booking_no),
|
||||
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
|
||||
KEY idx_container_booking_container (container_no),
|
||||
KEY idx_container_booking_warehouse (warehouse_id, updated_at, id),
|
||||
KEY idx_container_booking_voyage (voyage_no, updated_at),
|
||||
CONSTRAINT chk_container_booking_capacity CHECK (capacity_cbm IS NULL OR capacity_cbm > 0),
|
||||
CONSTRAINT chk_container_booking_weight CHECK (max_weight_kg IS NULL OR max_weight_kg > 0)
|
||||
) ENGINE=InnoDB COMMENT='平台货柜预订资料;预装状态唯一来源为装柜计划';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_plan (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '智能装柜计划ID(雪花ID)',
|
||||
plan_no VARCHAR(40) NOT NULL COMMENT '平台唯一装柜计划号',
|
||||
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID',
|
||||
plan_status VARCHAR(24) NOT NULL DEFAULT 'EDITING'
|
||||
COMMENT '唯一装柜状态:EDITING、LOADING、COMPLETED',
|
||||
push_idempotency_key VARCHAR(128) NULL COMMENT '推送预装幂等键',
|
||||
preload_pushed_by BIGINT UNSIGNED NULL COMMENT '推送预装操作人ID',
|
||||
preload_pushed_by_name VARCHAR(64) NULL COMMENT '推送预装操作人名称快照',
|
||||
preload_pushed_at DATETIME(3) NULL COMMENT '开始装柜并进入LOADING的时间',
|
||||
preload_completed_by BIGINT UNSIGNED NULL COMMENT '预装完成操作人ID',
|
||||
preload_completed_by_name VARCHAR(64) NULL COMMENT '预装完成操作人名称快照',
|
||||
preload_completed_at DATETIME(3) NULL COMMENT '预装完成时间',
|
||||
confirmed_by BIGINT UNSIGNED NULL COMMENT '确认操作人ID',
|
||||
confirmed_by_name VARCHAR(64) NULL COMMENT '确认操作人名称快照',
|
||||
confirmed_at DATETIME(3) NULL COMMENT '确认时间',
|
||||
remark VARCHAR(500) NULL COMMENT '平台装柜计划备注',
|
||||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||||
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||||
updated_by_name VARCHAR(64) NULL COMMENT '最后修改人名称快照',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
COMMENT '更新时间',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_plan_no (plan_no),
|
||||
UNIQUE KEY uk_loading_plan_booking (container_booking_id),
|
||||
UNIQUE KEY uk_loading_plan_push_key (push_idempotency_key),
|
||||
KEY idx_loading_plan_status (plan_status, updated_at, id),
|
||||
CONSTRAINT fk_loading_plan_booking FOREIGN KEY (container_booking_id)
|
||||
REFERENCES fl_container_booking (id),
|
||||
CONSTRAINT chk_loading_plan_status
|
||||
CHECK (plan_status IN ('EDITING', 'LOADING', 'COMPLETED'))
|
||||
) ENGINE=InnoDB COMMENT='平台智能装柜计划与唯一预装状态源';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_plan_item (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '装柜计划明细ID(雪花ID)',
|
||||
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '智能装柜计划ID',
|
||||
account_id BIGINT UNSIGNED NOT NULL COMMENT '客户账号ID;装柜业务唯一客户归属字段',
|
||||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT 'Firstleg入库单ID',
|
||||
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '订单货物或入库货物明细ID,不建立跨库外键',
|
||||
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单服务订单ID快照,不建立跨库外键',
|
||||
order_no VARCHAR(32) NOT NULL COMMENT '订单号快照',
|
||||
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
|
||||
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '目的仓ID快照',
|
||||
destination_warehouse_code VARCHAR(64) NULL COMMENT '目的仓编码快照',
|
||||
destination_warehouse_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||||
sku_code VARCHAR(128) NULL COMMENT 'SKU编码快照',
|
||||
product_name_zh VARCHAR(255) NULL COMMENT '中文品名快照',
|
||||
product_name_en VARCHAR(255) NULL COMMENT '英文品名快照',
|
||||
product_image_file_id BIGINT UNSIGNED NULL COMMENT '产品图片File对象ID',
|
||||
product_image_url VARCHAR(1000) NULL COMMENT '产品图片访问地址快照',
|
||||
package_count INT UNSIGNED NOT NULL COMMENT '本次装柜箱数',
|
||||
product_quantity INT UNSIGNED NULL COMMENT '产品总数量',
|
||||
units_per_carton INT UNSIGNED NULL COMMENT '每箱产品数',
|
||||
pallet_count INT UNSIGNED NULL COMMENT '托盘数',
|
||||
gross_weight_kg DECIMAL(18,3) NULL COMMENT '本次装柜毛重kg',
|
||||
net_weight_kg DECIMAL(18,3) NULL COMMENT '本次装柜净重kg',
|
||||
dimensional_weight_kg DECIMAL(18,3) NULL COMMENT '本次装柜材积重kg',
|
||||
volume_cbm DECIMAL(18,4) NULL COMMENT '本次装柜体积m3',
|
||||
fba_tracking_no VARCHAR(128) NULL COMMENT 'FBA追踪号快照',
|
||||
shipment_no VARCHAR(128) NULL COMMENT '货件编号快照',
|
||||
shipping_mark VARCHAR(500) NULL COMMENT '唛头快照',
|
||||
load_sequence INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '装柜顺序',
|
||||
position_snapshot JSON NULL COMMENT '智能装柜位置与摆放结果快照',
|
||||
internal_remark VARCHAR(1000) NULL COMMENT '平台内部备注',
|
||||
customer_remark VARCHAR(1000) NULL COMMENT '客户备注快照',
|
||||
warehouse_remark VARCHAR(1000) NULL COMMENT '仓库备注快照',
|
||||
frozen_at DATETIME(3) NULL COMMENT '装柜完成后的永久冻结时间',
|
||||
frozen_by BIGINT UNSIGNED NULL COMMENT '冻结操作人ID',
|
||||
removed_by BIGINT UNSIGNED NULL COMMENT '推送前逻辑删除操作人ID',
|
||||
removed_by_name VARCHAR(64) NULL COMMENT '推送前逻辑删除操作人名称快照',
|
||||
removed_at DATETIME(3) NULL COMMENT '推送前逻辑删除时间',
|
||||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '推送前逻辑删除标记;冻结后不可修改',
|
||||
active_inbound_detail_id BIGINT UNSIGNED GENERATED ALWAYS AS (
|
||||
CASE WHEN deleted = 0 THEN inbound_detail_id ELSE NULL END
|
||||
) STORED COMMENT '未删除明细唯一锁;删除后返回NULL释放分配资格',
|
||||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||||
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||||
updated_by_name VARCHAR(64) NULL COMMENT '最后修改人名称快照',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
COMMENT '更新时间',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_item_active_detail (account_id, active_inbound_detail_id),
|
||||
KEY idx_loading_item_plan (loading_plan_id, deleted, load_sequence, id),
|
||||
KEY idx_loading_item_account (account_id, created_at, id),
|
||||
KEY idx_loading_item_inbound (account_id, inbound_id, deleted),
|
||||
KEY idx_loading_item_order (account_id, order_id, deleted),
|
||||
CONSTRAINT fk_loading_item_plan FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id),
|
||||
CONSTRAINT chk_loading_item_account CHECK (account_id > 0),
|
||||
CONSTRAINT chk_loading_item_package CHECK (package_count > 0),
|
||||
CONSTRAINT chk_loading_item_product_quantity CHECK (product_quantity IS NULL OR product_quantity > 0),
|
||||
CONSTRAINT chk_loading_item_units CHECK (units_per_carton IS NULL OR units_per_carton > 0),
|
||||
CONSTRAINT chk_loading_item_pallet CHECK (pallet_count IS NULL OR pallet_count >= 0),
|
||||
CONSTRAINT chk_loading_item_weight CHECK (
|
||||
(gross_weight_kg IS NULL OR gross_weight_kg >= 0)
|
||||
AND (net_weight_kg IS NULL OR net_weight_kg >= 0)
|
||||
AND (dimensional_weight_kg IS NULL OR dimensional_weight_kg >= 0)
|
||||
),
|
||||
CONSTRAINT chk_loading_item_volume CHECK (volume_cbm IS NULL OR volume_cbm >= 0),
|
||||
CONSTRAINT chk_loading_item_deleted CHECK (deleted IN (0, 1))
|
||||
) ENGINE=InnoDB COMMENT='智能装柜客户货物明细;客户归属仅在明细层';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_container_document (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '货柜文件关联ID(雪花ID)',
|
||||
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID',
|
||||
document_type VARCHAR(32) NOT NULL COMMENT 'CUSTOMS_CLEARANCE、DELIVERY_ORDER、PICKUP_ORDER',
|
||||
file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件ID,不建立跨库外键',
|
||||
file_name VARCHAR(255) NOT NULL COMMENT '文件名称快照',
|
||||
file_url VARCHAR(1000) NULL COMMENT '文件访问地址快照',
|
||||
uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传操作人ID',
|
||||
uploaded_by_name VARCHAR(64) NULL COMMENT '上传操作人名称快照',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
COMMENT '更新时间',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_container_document_type (container_booking_id, document_type),
|
||||
KEY idx_container_document_file (file_id),
|
||||
CONSTRAINT fk_container_document_booking FOREIGN KEY (container_booking_id)
|
||||
REFERENCES fl_container_booking (id),
|
||||
CONSTRAINT chk_container_document_type
|
||||
CHECK (document_type IN ('CUSTOMS_CLEARANCE', 'DELIVERY_ORDER', 'PICKUP_ORDER'))
|
||||
) ENGINE=InnoDB COMMENT='平台货柜清关、DO与PU文件关联';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_plan_history (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '装柜操作历史ID(雪花ID)',
|
||||
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '智能装柜计划ID',
|
||||
loading_plan_item_id BIGINT UNSIGNED NULL COMMENT '装柜计划明细ID',
|
||||
operation_id VARCHAR(128) NOT NULL COMMENT '操作幂等ID',
|
||||
action_type VARCHAR(32) NOT NULL
|
||||
COMMENT 'CREATE_PLAN、ADD_ITEM、ADJUST_ITEM、REMOVE_ITEM、START_LOADING、COMPLETE_LOADING、PICK_ITEM',
|
||||
from_status VARCHAR(24) NULL COMMENT '变更前状态',
|
||||
to_status VARCHAR(24) NULL COMMENT '变更后状态',
|
||||
before_snapshot JSON NULL COMMENT '变更前快照',
|
||||
after_snapshot JSON NULL COMMENT '变更后快照',
|
||||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||||
operation_reason VARCHAR(500) NULL COMMENT '操作原因',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_history_operation (operation_id),
|
||||
KEY idx_loading_history_plan (loading_plan_id, created_at, id),
|
||||
KEY idx_loading_history_item (loading_plan_item_id, created_at, id),
|
||||
CONSTRAINT fk_loading_history_plan FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id),
|
||||
CONSTRAINT fk_loading_history_item FOREIGN KEY (loading_plan_item_id)
|
||||
REFERENCES fl_loading_plan_item (id)
|
||||
) ENGINE=InnoDB COMMENT='智能装柜追加式不可变操作历史';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_pick_task (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货任务ID',
|
||||
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '装柜计划ID',
|
||||
container_no VARCHAR(64) NOT NULL COMMENT '集装箱号快照',
|
||||
task_status VARCHAR(16) NOT NULL DEFAULT 'LOADING' COMMENT 'LOADING、COMPLETED',
|
||||
started_by BIGINT UNSIGNED NOT NULL COMMENT '开始装柜人',
|
||||
started_by_name VARCHAR(64) NULL COMMENT '开始装柜人名称',
|
||||
started_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '开始时间',
|
||||
completed_by BIGINT UNSIGNED NULL COMMENT '完成装柜人',
|
||||
completed_by_name VARCHAR(64) NULL COMMENT '完成装柜人名称',
|
||||
completed_at DATETIME(3) NULL COMMENT '完成时间',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_pick_task_plan (loading_plan_id),
|
||||
KEY idx_loading_pick_container (container_no, task_status, started_at),
|
||||
CONSTRAINT fk_loading_pick_task_plan FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id),
|
||||
CONSTRAINT chk_loading_pick_task_status CHECK (task_status IN ('LOADING', 'COMPLETED'))
|
||||
) ENGINE=InnoDB COMMENT='PDA装柜拣货任务';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_pick_item (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货明细ID',
|
||||
pick_task_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货任务ID',
|
||||
loading_plan_item_id BIGINT UNSIGNED NOT NULL COMMENT '装柜计划明细ID',
|
||||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '父入库单ID',
|
||||
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '订单货物明细ID',
|
||||
planned_package_count INT UNSIGNED NOT NULL COMMENT '计划拣货箱数;上层拆分按业务规则向上取整',
|
||||
picked_package_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已拣货箱数',
|
||||
item_status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING、PICKING、PICKED',
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_pick_item_plan_item (loading_plan_item_id),
|
||||
KEY idx_loading_pick_item_task (pick_task_id, item_status, id),
|
||||
CONSTRAINT fk_loading_pick_item_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
|
||||
CONSTRAINT fk_loading_pick_item_plan_item FOREIGN KEY (loading_plan_item_id) REFERENCES fl_loading_plan_item (id),
|
||||
CONSTRAINT chk_loading_pick_item_planned CHECK (planned_package_count > 0),
|
||||
CONSTRAINT chk_loading_pick_item_count CHECK (picked_package_count <= planned_package_count),
|
||||
CONSTRAINT chk_loading_pick_item_status CHECK (item_status IN ('PENDING', 'PICKING', 'PICKED'))
|
||||
) ENGINE=InnoDB COMMENT='PDA装柜拣货明细';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_loading_pick_history (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货操作历史ID',
|
||||
pick_task_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货任务ID',
|
||||
pick_item_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货明细ID',
|
||||
operation_id VARCHAR(128) NOT NULL COMMENT '客户端幂等操作号',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '请求指纹',
|
||||
picked_package_count INT UNSIGNED NOT NULL COMMENT '本次拣货箱数',
|
||||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人',
|
||||
operator_name VARCHAR(64) NULL COMMENT '操作人名称',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_loading_pick_history_operation (operation_id),
|
||||
KEY idx_loading_pick_history_item (pick_item_id, created_at),
|
||||
CONSTRAINT fk_loading_pick_history_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
|
||||
CONSTRAINT fk_loading_pick_history_item FOREIGN KEY (pick_item_id) REFERENCES fl_loading_pick_item (id)
|
||||
) ENGINE=InnoDB COMMENT='PDA拣货幂等和操作审计历史';
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_container_booking_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_container_booking_before_update
|
||||
BEFORE UPDATE ON fl_container_booking
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status
|
||||
FROM fl_loading_plan WHERE container_booking_id = OLD.id;
|
||||
IF current_plan_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜全部只读,不允许修改';
|
||||
END IF;
|
||||
IF current_plan_status = 'LOADING' AND (
|
||||
NOT (OLD.id <=> NEW.id) OR NOT (OLD.booking_no <=> NEW.booking_no)
|
||||
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
||||
OR NOT (OLD.warehouse_id <=> NEW.warehouse_id)
|
||||
OR NOT (OLD.warehouse_name <=> NEW.warehouse_name)
|
||||
OR NOT (OLD.bill_of_lading_no <=> NEW.bill_of_lading_no)
|
||||
OR NOT (OLD.vessel_name <=> NEW.vessel_name)
|
||||
OR NOT (OLD.container_type <=> NEW.container_type)
|
||||
OR NOT (OLD.shipping_company_id <=> NEW.shipping_company_id)
|
||||
OR NOT (OLD.shipping_company_name <=> NEW.shipping_company_name)
|
||||
OR NOT (OLD.departure_port_code <=> NEW.departure_port_code)
|
||||
OR NOT (OLD.departure_port_name <=> NEW.departure_port_name)
|
||||
OR NOT (OLD.destination_port_code <=> NEW.destination_port_code)
|
||||
OR NOT (OLD.destination_port_name <=> NEW.destination_port_name)
|
||||
OR NOT (OLD.destination_warehouse_code <=> NEW.destination_warehouse_code)
|
||||
OR NOT (OLD.destination_warehouse_name <=> NEW.destination_warehouse_name)
|
||||
OR NOT (OLD.capacity_cbm <=> NEW.capacity_cbm)
|
||||
OR NOT (OLD.max_weight_kg <=> NEW.max_weight_kg)
|
||||
OR NOT (OLD.terminal_trucking_company <=> NEW.terminal_trucking_company)
|
||||
OR NOT (OLD.loading_at <=> NEW.loading_at)
|
||||
OR NOT (OLD.estimated_sailing_at <=> NEW.estimated_sailing_at)
|
||||
OR NOT (OLD.actual_sailing_at <=> NEW.actual_sailing_at)
|
||||
OR NOT (OLD.estimated_port_arrival_at <=> NEW.estimated_port_arrival_at)
|
||||
OR NOT (OLD.actual_port_arrival_at <=> NEW.actual_port_arrival_at)
|
||||
OR NOT (OLD.estimated_warehouse_arrival_at <=> NEW.estimated_warehouse_arrival_at)
|
||||
OR NOT (OLD.actual_warehouse_arrival_at <=> NEW.actual_warehouse_arrival_at)
|
||||
OR NOT (OLD.created_by <=> NEW.created_by)
|
||||
OR NOT (OLD.created_by_name <=> NEW.created_by_name)
|
||||
OR NOT (OLD.created_at <=> NEW.created_at)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '装柜中仅允许修改集装箱号与航次';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_plan_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_plan_before_update
|
||||
BEFORE UPDATE ON fl_loading_plan
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF OLD.plan_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已完成装柜计划全部只读';
|
||||
END IF;
|
||||
IF NOT (
|
||||
(OLD.plan_status = 'EDITING' AND NEW.plan_status IN ('EDITING', 'LOADING'))
|
||||
OR (OLD.plan_status = 'LOADING'
|
||||
AND NEW.plan_status IN ('LOADING', 'COMPLETED'))
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜状态只允许单向推进';
|
||||
END IF;
|
||||
IF OLD.plan_status = 'LOADING' AND (
|
||||
NOT (OLD.id <=> NEW.id) OR NOT (OLD.plan_no <=> NEW.plan_no)
|
||||
OR NOT (OLD.container_booking_id <=> NEW.container_booking_id)
|
||||
OR NOT (OLD.push_idempotency_key <=> NEW.push_idempotency_key)
|
||||
OR NOT (OLD.preload_pushed_by <=> NEW.preload_pushed_by)
|
||||
OR NOT (OLD.preload_pushed_by_name <=> NEW.preload_pushed_by_name)
|
||||
OR NOT (OLD.preload_pushed_at <=> NEW.preload_pushed_at)
|
||||
OR NOT (OLD.remark <=> NEW.remark)
|
||||
OR NOT (OLD.created_by <=> NEW.created_by)
|
||||
OR NOT (OLD.created_by_name <=> NEW.created_by_name)
|
||||
OR NOT (OLD.created_at <=> NEW.created_at)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '装柜中计划仅允许乐观锁触碰或完成装柜';
|
||||
END IF;
|
||||
IF OLD.plan_status = NEW.plan_status
|
||||
AND OLD.plan_status = 'LOADING' AND (
|
||||
NOT (OLD.preload_completed_by <=> NEW.preload_completed_by)
|
||||
OR NOT (OLD.preload_completed_by_name <=> NEW.preload_completed_by_name)
|
||||
OR NOT (OLD.preload_completed_at <=> NEW.preload_completed_at)
|
||||
OR NOT (OLD.confirmed_by <=> NEW.confirmed_by)
|
||||
OR NOT (OLD.confirmed_by_name <=> NEW.confirmed_by_name)
|
||||
OR NOT (OLD.confirmed_at <=> NEW.confirmed_at)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '同状态乐观锁触碰不得修改阶段审计字段';
|
||||
END IF;
|
||||
IF OLD.plan_status = 'EDITING' AND NEW.plan_status = 'LOADING' THEN
|
||||
IF NEW.push_idempotency_key IS NULL OR CHAR_LENGTH(TRIM(NEW.push_idempotency_key)) = 0 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '开始装柜必须提供幂等键';
|
||||
END IF;
|
||||
SET NEW.preload_pushed_at = COALESCE(NEW.preload_pushed_at, CURRENT_TIMESTAMP(3));
|
||||
ELSEIF OLD.plan_status = 'LOADING' AND NEW.plan_status = 'COMPLETED' THEN
|
||||
IF EXISTS (SELECT 1 FROM fl_loading_plan_item item
|
||||
LEFT JOIN fl_loading_pick_item pick_item
|
||||
ON pick_item.loading_plan_item_id = item.id
|
||||
LEFT JOIN fl_loading_pick_task pick_task
|
||||
ON pick_task.id = pick_item.pick_task_id
|
||||
AND pick_task.loading_plan_id = OLD.id
|
||||
WHERE item.loading_plan_id = OLD.id AND item.deleted = 0
|
||||
AND (pick_task.id IS NULL
|
||||
OR pick_item.picked_package_count <> pick_item.planned_package_count)) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仍有未完成拣货明细,不能完成装柜';
|
||||
END IF;
|
||||
SET NEW.confirmed_at = COALESCE(NEW.confirmed_at, CURRENT_TIMESTAMP(3));
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_plan_after_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_plan_after_update
|
||||
AFTER UPDATE ON fl_loading_plan
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF OLD.plan_status = 'LOADING' AND NEW.plan_status = 'COMPLETED' THEN
|
||||
UPDATE fl_loading_plan_item
|
||||
SET frozen_at = COALESCE(frozen_at, NEW.confirmed_at, CURRENT_TIMESTAMP(3)),
|
||||
frozen_by = COALESCE(frozen_by, NEW.updated_by),
|
||||
updated_by = NEW.updated_by,
|
||||
updated_by_name = NEW.updated_by_name,
|
||||
version = version + 1
|
||||
WHERE loading_plan_id = NEW.id AND deleted = 0;
|
||||
UPDATE fl_loading_pick_task
|
||||
SET task_status = 'COMPLETED', completed_by = NEW.updated_by,
|
||||
completed_by_name = NEW.updated_by_name, completed_at = CURRENT_TIMESTAMP(3),
|
||||
version = version + 1
|
||||
WHERE loading_plan_id = NEW.id AND task_status = 'LOADING';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_item_before_insert;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_item_before_insert
|
||||
BEFORE INSERT ON fl_loading_plan_item
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan WHERE id = NEW.loading_plan_id;
|
||||
IF current_plan_status IS NULL OR current_plan_status NOT IN ('EDITING', 'LOADING') THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅编辑中或装柜中的计划允许新增明细';
|
||||
END IF;
|
||||
IF NEW.deleted <> 0 OR NEW.frozen_at IS NOT NULL OR NEW.frozen_by IS NOT NULL THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '新增装柜明细必须为未删除且未冻结状态';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_item_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_item_before_update
|
||||
BEFORE UPDATE ON fl_loading_plan_item
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status
|
||||
FROM fl_loading_plan WHERE id = OLD.loading_plan_id;
|
||||
IF current_plan_status = 'LOADING' AND EXISTS (
|
||||
SELECT 1 FROM fl_loading_pick_item
|
||||
WHERE loading_plan_item_id = OLD.id AND picked_package_count > 0) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已有PDA拣货记录的装柜明细不可修改或删除';
|
||||
END IF;
|
||||
IF OLD.frozen_at IS NOT NULL THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后的明细永久冻结';
|
||||
END IF;
|
||||
IF OLD.deleted = 1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已删除装柜明细不可恢复或修改';
|
||||
END IF;
|
||||
IF NEW.loading_plan_id <> OLD.loading_plan_id OR NEW.account_id <> OLD.account_id
|
||||
OR NEW.inbound_detail_id <> OLD.inbound_detail_id THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜明细归属键不可修改,请删除后重新分配';
|
||||
END IF;
|
||||
IF NEW.deleted = 1 THEN
|
||||
IF NEW.removed_by IS NULL THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '删除装柜明细必须记录操作人';
|
||||
END IF;
|
||||
SET NEW.removed_at = COALESCE(NEW.removed_at, CURRENT_TIMESTAMP(3));
|
||||
ELSEIF NEW.removed_by IS NOT NULL OR NEW.removed_by_name IS NOT NULL OR NEW.removed_at IS NOT NULL THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '删除审计字段只能在逻辑删除时写入';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_pick_task_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_pick_task_before_update
|
||||
BEFORE UPDATE ON fl_loading_pick_task
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF OLD.task_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已完成PDA拣货任务不可修改';
|
||||
END IF;
|
||||
IF NEW.loading_plan_id <> OLD.loading_plan_id OR NOT (NEW.container_no <=> OLD.container_no) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PDA拣货任务归属不可修改';
|
||||
END IF;
|
||||
IF NOT (OLD.task_status = 'LOADING' AND NEW.task_status IN ('LOADING', 'COMPLETED')) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PDA拣货任务状态只允许完成';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_pick_item_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_pick_item_before_update
|
||||
BEFORE UPDATE ON fl_loading_pick_item
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_task_status VARCHAR(16);
|
||||
SELECT MAX(task_status) INTO current_task_status
|
||||
FROM fl_loading_pick_task WHERE id = OLD.pick_task_id;
|
||||
IF current_task_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后PDA拣货明细不可修改';
|
||||
END IF;
|
||||
IF NEW.pick_task_id <> OLD.pick_task_id
|
||||
OR NEW.loading_plan_item_id <> OLD.loading_plan_item_id
|
||||
OR NEW.inbound_id <> OLD.inbound_id
|
||||
OR NEW.inbound_detail_id <> OLD.inbound_detail_id THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PDA拣货明细归属不可修改';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_pick_item_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_pick_item_before_delete
|
||||
BEFORE DELETE ON fl_loading_pick_item
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_task_status VARCHAR(16);
|
||||
SELECT MAX(task_status) INTO current_task_status
|
||||
FROM fl_loading_pick_task WHERE id = OLD.pick_task_id;
|
||||
IF current_task_status = 'COMPLETED' OR OLD.picked_package_count > 0 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已拣货或已完成的PDA明细不可删除';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_pick_history_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_pick_history_before_update
|
||||
BEFORE UPDATE ON fl_loading_pick_history
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PDA拣货历史不可修改';
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_pick_history_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_pick_history_before_delete
|
||||
BEFORE DELETE ON fl_loading_pick_history
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'PDA拣货历史不可删除';
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_item_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_item_before_delete
|
||||
BEFORE DELETE ON fl_loading_plan_item
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜明细只允许推送前逻辑删除';
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_container_document_before_insert;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_container_document_before_insert
|
||||
BEFORE INSERT ON fl_container_document
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan
|
||||
WHERE container_booking_id = NEW.container_booking_id;
|
||||
IF current_plan_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜文件不可新增';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_container_document_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_container_document_before_update
|
||||
BEFORE UPDATE ON fl_container_document
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan
|
||||
WHERE container_booking_id = OLD.container_booking_id;
|
||||
IF current_plan_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜文件不可修改';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_container_document_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_container_document_before_delete
|
||||
BEFORE DELETE ON fl_container_document
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE current_plan_status VARCHAR(24);
|
||||
SELECT MAX(plan_status) INTO current_plan_status FROM fl_loading_plan
|
||||
WHERE container_booking_id = OLD.container_booking_id;
|
||||
IF current_plan_status = 'COMPLETED' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜完成后货柜文件不可删除';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_history_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_history_before_update
|
||||
BEFORE UPDATE ON fl_loading_plan_history
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜操作历史不可修改';
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_loading_history_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_loading_history_before_delete
|
||||
BEFORE DELETE ON fl_loading_plan_history
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '装柜操作历史不可删除';
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
-- 三期智能装柜、预装清单和装柜清单平台权限;与一期平台根菜单幂等合并。
|
||||
USE baiyue_iam;
|
||||
INSERT INTO iam_permission
|
||||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||||
permission_name, route_path, http_method, sort_no, status, built_in, deleted)
|
||||
VALUES
|
||||
(5102090, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:container:list',
|
||||
'货柜', '/first-leg/containers', 'GET', 40, 'ACTIVE', 1, 0),
|
||||
(5102091, 0, 'PLATFORM', 'BUTTON', 5102090, 'platform:firstleg:container:view',
|
||||
'查看货柜', NULL, 'GET', 10, 'ACTIVE', 1, 0),
|
||||
(5102092, 0, 'PLATFORM', 'BUTTON', 5102090, 'platform:firstleg:container:create',
|
||||
'建立货柜', NULL, 'POST', 20, 'ACTIVE', 1, 0),
|
||||
(5102093, 0, 'PLATFORM', 'BUTTON', 5102090, 'platform:firstleg:container:edit',
|
||||
'编辑货柜', NULL, 'PUT', 30, 'ACTIVE', 1, 0),
|
||||
(5102094, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:smart-loading:list',
|
||||
'智能装柜', '/first-leg/smart-loading', 'GET', 50, 'ACTIVE', 1, 0),
|
||||
(5102096, 0, 'PLATFORM', 'BUTTON', 5102094, 'platform:firstleg:smart-loading:create',
|
||||
'创建智能装柜计划', NULL, 'POST', 20, 'ACTIVE', 1, 0),
|
||||
(5102097, 0, 'PLATFORM', 'BUTTON', 5102094, 'platform:firstleg:smart-loading:assign',
|
||||
'分配装柜明细', NULL, 'POST', 30, 'ACTIVE', 1, 0),
|
||||
(5102098, 0, 'PLATFORM', 'BUTTON', 5102094, 'platform:firstleg:smart-loading:delete',
|
||||
'删除装柜明细', NULL, 'DELETE', 40, 'ACTIVE', 1, 0),
|
||||
(5102099, 0, 'PLATFORM', 'BUTTON', 5102094, 'platform:firstleg:smart-loading:push',
|
||||
'推送预装', NULL, 'POST', 50, 'ACTIVE', 1, 0),
|
||||
(5102100, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:preload:list',
|
||||
'预装清单', '/first-leg/preload-list', 'GET', 60, 'ACTIVE', 1, 0),
|
||||
(5102102, 0, 'PLATFORM', 'BUTTON', 5102100, 'platform:firstleg:preload:view',
|
||||
'查看预装详情', NULL, 'GET', 20, 'ACTIVE', 1, 0),
|
||||
(5102103, 0, 'PLATFORM', 'BUTTON', 5102100, 'platform:firstleg:preload:edit',
|
||||
'编辑预装运输字段', NULL, 'PUT', 30, 'ACTIVE', 1, 0),
|
||||
(5102104, 0, 'PLATFORM', 'BUTTON', 5102100, 'platform:firstleg:preload:complete',
|
||||
'完成预装', NULL, 'POST', 40, 'ACTIVE', 1, 0),
|
||||
(5102105, 0, 'PLATFORM', 'BUTTON', 5102100, 'platform:firstleg:preload:confirm',
|
||||
'确认预装', NULL, 'POST', 50, 'ACTIVE', 1, 0),
|
||||
(5102106, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:loading-list:list',
|
||||
'装柜清单', '/first-leg/loading-list', 'GET', 70, 'ACTIVE', 1, 0),
|
||||
(5102108, 0, 'PLATFORM', 'BUTTON', 5102106, 'platform:firstleg:loading-list:view',
|
||||
'查看装柜详情', NULL, 'GET', 20, 'ACTIVE', 1, 0)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||||
http_method = VALUES(http_method), sort_no = VALUES(sort_no), status = 'ACTIVE',
|
||||
built_in = 1, deleted = 0;
|
||||
|
||||
INSERT IGNORE INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||||
SELECT role.id, permission.id, role.tenant_id
|
||||
FROM iam_role role
|
||||
JOIN iam_permission permission
|
||||
ON permission.tenant_id = 0
|
||||
AND permission.permission_code IN (
|
||||
'platform:firstleg:container:list', 'platform:firstleg:container:view',
|
||||
'platform:firstleg:container:create',
|
||||
'platform:firstleg:container:edit', 'platform:firstleg:smart-loading:list',
|
||||
'platform:firstleg:smart-loading:create', 'platform:firstleg:smart-loading:assign',
|
||||
'platform:firstleg:smart-loading:delete', 'platform:firstleg:smart-loading:push',
|
||||
'platform:firstleg:preload:list', 'platform:firstleg:preload:view',
|
||||
'platform:firstleg:preload:edit', 'platform:firstleg:preload:complete',
|
||||
'platform:firstleg:preload:confirm', 'platform:firstleg:loading-list:list',
|
||||
'platform:firstleg:loading-list:view')
|
||||
WHERE role.tenant_id = 0
|
||||
AND role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR');
|
||||
|
||||
USE baiyue_firstleg;
|
||||
|
||||
DROP PROCEDURE IF EXISTS assert_phase3_smart_loading_schema;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_phase3_smart_loading_schema()
|
||||
BEGIN
|
||||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema = 'baiyue_firstleg'
|
||||
AND table_name IN ('fl_container_booking', 'fl_loading_plan', 'fl_loading_plan_item',
|
||||
'fl_container_document', 'fl_loading_plan_history',
|
||||
'fl_loading_pick_task', 'fl_loading_pick_item',
|
||||
'fl_loading_pick_history')) <> 8 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:核心表未完整创建';
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM fl_loading_plan
|
||||
WHERE plan_status NOT IN ('EDITING', 'LOADING', 'COMPLETED')) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:存在旧装柜状态';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.check_constraints
|
||||
WHERE constraint_schema = 'baiyue_firstleg'
|
||||
AND constraint_name = 'chk_loading_plan_status'
|
||||
AND check_clause LIKE '%''EDITING''%'
|
||||
AND check_clause LIKE '%''LOADING''%'
|
||||
AND check_clause LIKE '%''COMPLETED''%') <> 1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:装柜状态约束不是最终三状态';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_container_booking'
|
||||
AND column_name IN ('booking_no', 'cabinet_no', 'warehouse_id', 'bill_of_lading_no',
|
||||
'vessel_name', 'voyage_no', 'container_type', 'capacity_cbm',
|
||||
'max_weight_kg', 'terminal_trucking_company')) <> 10 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:货柜原型字段缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_plan_item'
|
||||
AND column_name IN ('account_id', 'customer_name', 'active_inbound_detail_id', 'frozen_at',
|
||||
'destination_warehouse_name', 'product_name_zh', 'product_name_en',
|
||||
'product_image_file_id', 'pallet_count', 'net_weight_kg',
|
||||
'dimensional_weight_kg', 'product_quantity', 'units_per_carton',
|
||||
'fba_tracking_no', 'shipment_no', 'shipping_mark', 'version')) <> 17 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:明细归属、清单快照或冻结字段缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.statistics
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_plan_item'
|
||||
AND index_name = 'uk_loading_item_active_detail' AND non_unique = 0) <> 2 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:唯一活动明细锁缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg'
|
||||
AND table_name = 'fl_loading_pick_item'
|
||||
AND column_name IN ('pick_task_id', 'loading_plan_item_id', 'inbound_id',
|
||||
'inbound_detail_id', 'planned_package_count',
|
||||
'picked_package_count', 'item_status', 'version')) <> 8 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:PDA拣货明细字段缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.statistics
|
||||
WHERE table_schema = 'baiyue_firstleg' AND non_unique = 0
|
||||
AND index_name IN ('uk_loading_pick_task_plan',
|
||||
'uk_loading_pick_item_plan_item',
|
||||
'uk_loading_pick_history_operation')) <> 3 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:PDA唯一索引缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.triggers
|
||||
WHERE trigger_schema = 'baiyue_firstleg'
|
||||
AND trigger_name IN ('trg_container_booking_before_update',
|
||||
'trg_loading_plan_before_update', 'trg_loading_plan_after_update',
|
||||
'trg_loading_item_before_insert', 'trg_loading_item_before_update',
|
||||
'trg_loading_item_before_delete', 'trg_container_document_before_insert',
|
||||
'trg_container_document_before_update', 'trg_container_document_before_delete',
|
||||
'trg_loading_history_before_update', 'trg_loading_history_before_delete',
|
||||
'trg_loading_pick_task_before_update',
|
||||
'trg_loading_pick_item_before_update',
|
||||
'trg_loading_pick_item_before_delete',
|
||||
'trg_loading_pick_history_before_update',
|
||||
'trg_loading_pick_history_before_delete')) <> 16 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:不可逆状态或冻结触发器缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(DISTINCT permission_code) FROM baiyue_iam.iam_permission
|
||||
WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND status = 'ACTIVE' AND deleted = 0
|
||||
AND permission_code IN (
|
||||
'platform:firstleg:container:list', 'platform:firstleg:container:view',
|
||||
'platform:firstleg:container:create', 'platform:firstleg:container:edit',
|
||||
'platform:firstleg:smart-loading:list', 'platform:firstleg:smart-loading:create',
|
||||
'platform:firstleg:smart-loading:assign', 'platform:firstleg:smart-loading:delete',
|
||||
'platform:firstleg:smart-loading:push', 'platform:firstleg:preload:list',
|
||||
'platform:firstleg:preload:view', 'platform:firstleg:preload:edit',
|
||||
'platform:firstleg:preload:complete', 'platform:firstleg:preload:confirm',
|
||||
'platform:firstleg:loading-list:list', 'platform:firstleg:loading-list:view')) <> 16 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:平台权限资源未完整创建';
|
||||
END IF;
|
||||
IF (SELECT COUNT(DISTINCT CONCAT(role.role_code, ':', permission.permission_code))
|
||||
FROM baiyue_iam.iam_role role
|
||||
JOIN baiyue_iam.iam_role_permission grant_row ON grant_row.role_id = role.id
|
||||
JOIN baiyue_iam.iam_permission permission ON permission.id = grant_row.permission_id
|
||||
WHERE role.tenant_id = 0 AND role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR')
|
||||
AND permission.tenant_id = 0
|
||||
AND permission.permission_code IN (
|
||||
'platform:firstleg:container:list', 'platform:firstleg:container:view',
|
||||
'platform:firstleg:container:create',
|
||||
'platform:firstleg:container:edit', 'platform:firstleg:smart-loading:list',
|
||||
'platform:firstleg:smart-loading:create', 'platform:firstleg:smart-loading:assign',
|
||||
'platform:firstleg:smart-loading:delete', 'platform:firstleg:smart-loading:push',
|
||||
'platform:firstleg:preload:list', 'platform:firstleg:preload:view',
|
||||
'platform:firstleg:preload:edit', 'platform:firstleg:preload:complete',
|
||||
'platform:firstleg:preload:confirm', 'platform:firstleg:loading-list:list',
|
||||
'platform:firstleg:loading-list:view')) <> 32 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:平台角色授权未完整写入';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_phase3_smart_loading_schema();
|
||||
DROP PROCEDURE IF EXISTS assert_phase3_smart_loading_schema;
|
||||
@@ -67,6 +67,90 @@ paths:
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 无分配权限}
|
||||
/api/platform/v1/containers:
|
||||
get:
|
||||
summary: 分页查询平台货柜
|
||||
description: 需要 platform:firstleg:container:list 权限;货柜为平台级数据,不传 tenant/account
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {name: keyword, in: query, schema: {type: string, maxLength: 128}}
|
||||
- {name: containerNo, in: query, schema: {type: string, maxLength: 64}}
|
||||
- {name: cabinetNo, in: query, schema: {type: string, maxLength: 64}}
|
||||
- {name: warehouseId, in: query, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: status, in: query, schema: {type: string, enum: [EDITING, LOADING, COMPLETED]}}
|
||||
responses:
|
||||
'200':
|
||||
description: 成功或业务失败,按响应体 code 判断
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ContainerBookingPageEnvelope'}
|
||||
'403': {description: 无货柜查询权限}
|
||||
post:
|
||||
summary: 新增平台货柜
|
||||
description: 需要 platform:firstleg:container:create 权限;新增后聚合状态为 EDITING
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ContainerSaveRequest'}
|
||||
responses:
|
||||
'200': {description: 成功或重复号、参数校验等业务失败}
|
||||
'403': {description: 无新增按钮权限}
|
||||
/api/platform/v1/containers/{id}:
|
||||
get:
|
||||
summary: 查询平台货柜详情
|
||||
description: 需要 platform:firstleg:container:view 权限
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/ContainerBookingId'}
|
||||
responses:
|
||||
'200': {description: 成功或货柜不存在}
|
||||
'403': {description: 无货柜查询权限}
|
||||
put:
|
||||
summary: 草稿阶段完整编辑货柜
|
||||
description: 需要 platform:firstleg:container:edit 权限;仅无装柜计划或计划为 EDITING 时允许
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/ContainerBookingId'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ContainerFullUpdateRequest'}
|
||||
responses:
|
||||
'200': {description: 成功或状态、版本、重复号冲突}
|
||||
'403': {description: 无货柜编辑权限}
|
||||
/api/platform/v1/containers/{id}/transport:
|
||||
patch:
|
||||
summary: 修改集装箱号和航次
|
||||
description: 需要 platform:firstleg:container:edit 权限;LOADING 仅开放此白名单,COMPLETED 全部只读
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/ContainerBookingId'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ContainerTransportUpdateRequest'}
|
||||
responses:
|
||||
'200': {description: 成功或状态、版本、重复号冲突}
|
||||
'403': {description: 无货柜编辑权限}
|
||||
/api/platform/v1/first-leg/smart-loading/plans/by-booking/{bookingId}:
|
||||
get:
|
||||
summary: 按货柜恢复智能装柜草稿
|
||||
description: 需要 platform:firstleg:smart-loading:list 权限;仅返回 EDITING 草稿
|
||||
parameters:
|
||||
- {name: bookingId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200': {description: 成功、草稿不存在或计划已进入预装流程}
|
||||
'403': {description: 无智能装柜查询权限}
|
||||
/api/platform/v1/first-leg/smart-loading/plans/{planId}:
|
||||
get:
|
||||
summary: 查询智能装柜草稿详情
|
||||
description: 需要 platform:firstleg:smart-loading:list 权限;返回草稿及当前未删除明细
|
||||
parameters:
|
||||
- {name: planId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200': {description: 成功、计划不存在或计划已进入预装流程}
|
||||
'403': {description: 无智能装柜查询权限}
|
||||
/openapi/v1/inbound-measurements:
|
||||
post:
|
||||
summary: 提交一条第三方箱规测量结果和一张图片
|
||||
@@ -258,7 +342,103 @@ components:
|
||||
name: size
|
||||
in: query
|
||||
schema: {type: integer, format: int64, minimum: 1, maximum: 200, default: 20}
|
||||
ContainerBookingId:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
schemas:
|
||||
ContainerBookingPageEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string, example: '200'}
|
||||
message: {type: string}
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/ContainerBooking'}}
|
||||
page: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
size: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
total: {type: string, pattern: '^[0-9]+$'}
|
||||
pages: {type: string, pattern: '^[0-9]+$'}
|
||||
ContainerBooking:
|
||||
type: object
|
||||
required: [id, bookingNo, cabinetNo, warehouseId, warehouseName, containerType, planStatus, version]
|
||||
properties:
|
||||
id: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
planId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 关联智能装柜计划ID;未创建计划时为空}
|
||||
bookingNo: {type: string, maxLength: 40}
|
||||
containerNo: {type: string, maxLength: 64, nullable: true}
|
||||
cabinetNo: {type: string, maxLength: 64}
|
||||
warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
warehouseName: {type: string, maxLength: 128}
|
||||
billOfLadingNo: {type: string, maxLength: 128, nullable: true}
|
||||
vesselName: {type: string, maxLength: 128, nullable: true}
|
||||
voyageNo: {type: string, maxLength: 64, nullable: true}
|
||||
containerType: {type: string, maxLength: 32}
|
||||
shippingCompanyId: {type: string, nullable: true}
|
||||
shippingCompanyName: {type: string, maxLength: 128, nullable: true}
|
||||
departurePortCode: {type: string, maxLength: 32, nullable: true}
|
||||
departurePortName: {type: string, maxLength: 128, nullable: true}
|
||||
destinationPortCode: {type: string, maxLength: 32, nullable: true}
|
||||
destinationPortName: {type: string, maxLength: 128, nullable: true}
|
||||
destinationWarehouseCode: {type: string, maxLength: 64, nullable: true}
|
||||
destinationWarehouseName: {type: string, maxLength: 128, nullable: true}
|
||||
capacityCbm: {type: number, exclusiveMinimum: true, minimum: 0, nullable: true}
|
||||
maxWeightKg: {type: number, exclusiveMinimum: true, minimum: 0, nullable: true}
|
||||
terminalTruckingCompany: {type: string, maxLength: 128, nullable: true}
|
||||
loadingAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedSailingAt: {type: string, format: date-time, nullable: true}
|
||||
actualSailingAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedPortArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
actualPortArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
actualWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
planStatus: {type: string, enum: [EDITING, LOADING, COMPLETED]}
|
||||
version: {type: integer, minimum: 0}
|
||||
ContainerSaveRequest:
|
||||
type: object
|
||||
required: [cabinetNo, warehouseId, warehouseName, containerType]
|
||||
properties:
|
||||
containerNo: {type: string, maxLength: 64, nullable: true}
|
||||
cabinetNo: {type: string, maxLength: 64}
|
||||
warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
warehouseName: {type: string, maxLength: 128}
|
||||
billOfLadingNo: {type: string, maxLength: 128, nullable: true}
|
||||
vesselName: {type: string, maxLength: 128, nullable: true}
|
||||
voyageNo: {type: string, maxLength: 64, nullable: true}
|
||||
containerType: {type: string, maxLength: 32}
|
||||
shippingCompanyId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true}
|
||||
shippingCompanyName: {type: string, maxLength: 128, nullable: true}
|
||||
departurePortCode: {type: string, maxLength: 32, nullable: true}
|
||||
departurePortName: {type: string, maxLength: 128, nullable: true}
|
||||
destinationPortCode: {type: string, maxLength: 32, nullable: true}
|
||||
destinationPortName: {type: string, maxLength: 128, nullable: true}
|
||||
destinationWarehouseCode: {type: string, maxLength: 64, nullable: true}
|
||||
destinationWarehouseName: {type: string, maxLength: 128, nullable: true}
|
||||
capacityCbm: {type: number, exclusiveMinimum: true, minimum: 0, nullable: true}
|
||||
maxWeightKg: {type: number, exclusiveMinimum: true, minimum: 0, nullable: true}
|
||||
terminalTruckingCompany: {type: string, maxLength: 128, nullable: true}
|
||||
loadingAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedSailingAt: {type: string, format: date-time, nullable: true}
|
||||
actualSailingAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedPortArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
actualPortArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
estimatedWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
actualWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
ContainerFullUpdateRequest:
|
||||
type: object
|
||||
required: [version, data]
|
||||
properties:
|
||||
version: {type: integer, minimum: 0}
|
||||
data: {$ref: '#/components/schemas/ContainerSaveRequest'}
|
||||
ContainerTransportUpdateRequest:
|
||||
type: object
|
||||
required: [version]
|
||||
properties:
|
||||
containerNo: {type: string, maxLength: 64, nullable: true}
|
||||
voyageNo: {type: string, maxLength: 64, nullable: true}
|
||||
version: {type: integer, minimum: 0}
|
||||
MerchantInboundBillingEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 头程装柜与完成装柜清单接口
|
||||
version: 1.0.0
|
||||
description: 装柜计划仅允许 EDITING 到 LOADING 再到 COMPLETED 单向推进;EDITING 和 LOADING 均可维护未拣货明细,COMPLETED 后计划、明细与货柜运输信息永久只读,不提供回退或撤回接口。
|
||||
paths:
|
||||
/api/platform/v1/first-leg/loading-plans:
|
||||
get:
|
||||
summary: 分页查询预装清单
|
||||
description: 仅返回预装柜中或预装柜完成的计划,计划为平台作业数据,客户账号仅作为明细筛选条件。
|
||||
x-permission: platform:firstleg:preload:list
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {$ref: '#/components/parameters/Keyword'}
|
||||
- name: status
|
||||
in: query
|
||||
description: 预装状态
|
||||
schema: {type: string, enum: [LOADING]}
|
||||
- {$ref: '#/components/parameters/AccountId'}
|
||||
- {$ref: '#/components/parameters/WarehouseId'}
|
||||
- {$ref: '#/components/parameters/CreatedFrom'}
|
||||
- {$ref: '#/components/parameters/CreatedTo'}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/PreloadPageResponse'}
|
||||
/api/platform/v1/first-leg/loading-plans/{planId}:
|
||||
get:
|
||||
summary: 查询预装清单详情
|
||||
description: 返回同一装柜计划的汇总、冻结明细和完整操作历史。
|
||||
x-permission: platform:firstleg:preload:view
|
||||
parameters: [{$ref: '#/components/parameters/PlanId'}]
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/PreloadDetailResponse'}
|
||||
/api/platform/v1/first-leg/loading-plans/{planId}/transport:
|
||||
patch:
|
||||
summary: 修改预装运输信息
|
||||
description: 仅 LOADING 状态允许修改集装箱号与航次;装柜中可以维护未拣货明细。
|
||||
x-permission: platform:firstleg:preload:edit
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/PlanId'}
|
||||
- {$ref: '#/components/parameters/IdempotencyKey'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/TransportUpdateRequest'}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/PreloadDetailResponse'}
|
||||
/api/platform/v1/first-leg/loading-plans/{planId}/complete:
|
||||
post:
|
||||
summary: 完成预装
|
||||
description: 仅允许将 LOADING 单向推进为 COMPLETED;完成前必须完成全部 PDA 拣货。
|
||||
x-permission: platform:firstleg:preload:complete
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/PlanId'}
|
||||
- {$ref: '#/components/parameters/IdempotencyKey'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/AdvanceRequest'}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/PreloadDetailResponse'}
|
||||
/api/platform/v1/first-leg/loading-lists:
|
||||
get:
|
||||
summary: 分页查询装柜清单
|
||||
description: 读取同一个装柜计划聚合,仅返回 COMPLETED 状态记录。
|
||||
x-permission: platform:firstleg:loading-list:list
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {$ref: '#/components/parameters/Keyword'}
|
||||
- {$ref: '#/components/parameters/AccountId'}
|
||||
- {$ref: '#/components/parameters/WarehouseId'}
|
||||
- {$ref: '#/components/parameters/CreatedFrom'}
|
||||
- {$ref: '#/components/parameters/CreatedTo'}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/ConfirmedPageResponse'}
|
||||
/api/platform/v1/first-leg/loading-lists/{planId}:
|
||||
get:
|
||||
summary: 查询装柜清单详情
|
||||
description: 返回已确认计划的汇总、冻结明细和操作历史,全部只读。
|
||||
x-permission: platform:firstleg:loading-list:view
|
||||
parameters: [{$ref: '#/components/parameters/PlanId'}]
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/ConfirmedDetailResponse'}
|
||||
components:
|
||||
parameters:
|
||||
PlanId:
|
||||
name: planId
|
||||
in: path
|
||||
required: true
|
||||
description: 装柜计划 ID
|
||||
schema: {$ref: '#/components/schemas/LongId'}
|
||||
IdempotencyKey:
|
||||
name: Idempotency-Key
|
||||
in: header
|
||||
required: true
|
||||
description: 写操作幂等键,同一业务操作重试时必须保持不变
|
||||
schema: {type: string, minLength: 1, maxLength: 128}
|
||||
Page:
|
||||
name: page
|
||||
in: query
|
||||
description: 页码,从 1 开始
|
||||
schema: {type: integer, format: int64, minimum: 1, default: 1}
|
||||
Size:
|
||||
name: size
|
||||
in: query
|
||||
description: 每页条数
|
||||
schema: {type: integer, format: int64, minimum: 1, maximum: 200, default: 20}
|
||||
Keyword:
|
||||
name: keyword
|
||||
in: query
|
||||
description: 按预装单号、集装箱号或柜号模糊查询
|
||||
schema: {type: string, maxLength: 128}
|
||||
AccountId:
|
||||
name: accountId
|
||||
in: query
|
||||
description: 客户账号 ID 筛选条件,计划本身仍属于平台作业数据
|
||||
schema: {$ref: '#/components/schemas/LongId'}
|
||||
WarehouseId:
|
||||
name: warehouseId
|
||||
in: query
|
||||
description: 仓库 ID
|
||||
schema: {$ref: '#/components/schemas/LongId'}
|
||||
CreatedFrom:
|
||||
name: createdFrom
|
||||
in: query
|
||||
description: 创建时间起点,包含该时间
|
||||
schema: {type: string, format: date-time}
|
||||
CreatedTo:
|
||||
name: createdTo
|
||||
in: query
|
||||
description: 创建时间终点,包含该时间
|
||||
schema: {type: string, format: date-time}
|
||||
responses:
|
||||
PreloadPageResponse:
|
||||
description: 预装清单分页查询成功或业务失败,按响应体 code 判断
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/PreloadPageEnvelope'}}}
|
||||
PreloadDetailResponse:
|
||||
description: 预装清单详情查询或操作成功,也可能返回业务失败
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/PreloadDetailEnvelope'}}}
|
||||
ConfirmedPageResponse:
|
||||
description: 装柜清单分页查询成功或业务失败,按响应体 code 判断
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmedPageEnvelope'}}}
|
||||
ConfirmedDetailResponse:
|
||||
description: 装柜清单详情查询或确认成功,也可能返回业务失败
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmedDetailEnvelope'}}}
|
||||
schemas:
|
||||
LongId:
|
||||
type: string
|
||||
pattern: '^[1-9][0-9]*$'
|
||||
example: '1900000000000000001'
|
||||
description: 长整型 ID,JSON 中使用字符串避免前端精度丢失
|
||||
NullableLongId:
|
||||
allOf: [{$ref: '#/components/schemas/LongId'}]
|
||||
nullable: true
|
||||
ApiEnvelope:
|
||||
type: object
|
||||
required: [code, message, timestamp]
|
||||
properties:
|
||||
code: {type: string, description: 业务结果码,仅字符串 200 表示成功, example: '200'}
|
||||
message: {type: string, description: 结果说明}
|
||||
requestId: {type: string, nullable: true, description: 请求标识}
|
||||
traceId: {type: string, nullable: true, description: 链路标识}
|
||||
timestamp: {type: string, format: date-time, description: 服务端响应时间}
|
||||
PreloadPageEnvelope:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiEnvelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
allOf: [{$ref: '#/components/schemas/PreloadPage'}]
|
||||
nullable: true
|
||||
PreloadDetailEnvelope:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiEnvelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
allOf: [{$ref: '#/components/schemas/PreloadDetail'}]
|
||||
nullable: true
|
||||
ConfirmedPageEnvelope:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiEnvelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
allOf: [{$ref: '#/components/schemas/ConfirmedPage'}]
|
||||
nullable: true
|
||||
ConfirmedDetailEnvelope:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiEnvelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
allOf: [{$ref: '#/components/schemas/ConfirmedDetail'}]
|
||||
nullable: true
|
||||
PreloadPage:
|
||||
type: object
|
||||
required: [records, page, size, total, pages]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/PreloadSummary'}}
|
||||
page: {type: string, pattern: '^[1-9][0-9]*$', description: 当前页码}
|
||||
size: {type: string, pattern: '^[1-9][0-9]*$', description: 每页条数}
|
||||
total: {type: string, pattern: '^[0-9]+$', description: 总记录数}
|
||||
pages: {type: string, pattern: '^[0-9]+$', description: 总页数}
|
||||
ConfirmedPage:
|
||||
type: object
|
||||
required: [records, page, size, total, pages]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/ConfirmedSummary'}}
|
||||
page: {type: string, pattern: '^[1-9][0-9]*$', description: 当前页码}
|
||||
size: {type: string, pattern: '^[1-9][0-9]*$', description: 每页条数}
|
||||
total: {type: string, pattern: '^[0-9]+$', description: 总记录数}
|
||||
pages: {type: string, pattern: '^[0-9]+$', description: 总页数}
|
||||
Customer:
|
||||
type: object
|
||||
required: [accountId, customerName]
|
||||
properties:
|
||||
accountId: {$ref: '#/components/schemas/LongId'}
|
||||
customerName: {type: string, nullable: true, description: 客户名称}
|
||||
PreloadSummary:
|
||||
type: object
|
||||
required: [planId, preloadNo, customers, status, skuCount, totalPackageCount, totalVolumeCbm, totalGrossWeightKg, createdAt, version]
|
||||
properties:
|
||||
planId: {$ref: '#/components/schemas/LongId'}
|
||||
preloadNo: {type: string, description: 预装单号}
|
||||
containerNo: {type: string, nullable: true, description: 集装箱号}
|
||||
internalContainerNo: {type: string, nullable: true, description: 内部柜号}
|
||||
customers: {type: array, description: 计划包含的客户, items: {$ref: '#/components/schemas/Customer'}}
|
||||
warehouseId: {$ref: '#/components/schemas/NullableLongId'}
|
||||
warehouseName: {type: string, nullable: true, description: 仓库名称}
|
||||
vesselName: {type: string, nullable: true, description: 船名}
|
||||
voyageNo: {type: string, nullable: true, description: 航次}
|
||||
containerType: {type: string, nullable: true, description: 货柜类型}
|
||||
status: {type: string, enum: [LOADING], description: 装柜状态}
|
||||
skuCount: {type: string, pattern: '^[0-9]+$', description: SKU 种类数}
|
||||
totalPackageCount: {type: string, pattern: '^[0-9]+$', description: 总箱数}
|
||||
totalVolumeCbm: {type: number, description: 总体积,单位立方米}
|
||||
totalGrossWeightKg: {type: number, description: 总毛重,单位千克}
|
||||
createdAt: {type: string, format: date-time, description: 创建时间}
|
||||
version: {type: integer, format: int32, minimum: 0, description: 乐观锁版本}
|
||||
ConfirmedSummary:
|
||||
type: object
|
||||
required: [planId, loadingListNo, status, totalPackageCount, totalGrossWeightKg, totalNetWeightKg, totalVolumeCbm, totalQuantity, createdAt, version]
|
||||
properties:
|
||||
planId: {$ref: '#/components/schemas/LongId'}
|
||||
loadingListNo: {type: string, description: 装柜清单号}
|
||||
warehouseId: {$ref: '#/components/schemas/NullableLongId'}
|
||||
warehouseName: {type: string, nullable: true, description: 仓库名称}
|
||||
containerNo: {type: string, nullable: true, description: 集装箱号}
|
||||
internalContainerNo: {type: string, nullable: true, description: 内部柜号}
|
||||
status: {type: string, enum: [COMPLETED], description: 装柜清单状态}
|
||||
totalPackageCount: {type: string, pattern: '^[0-9]+$', description: 总箱数}
|
||||
totalGrossWeightKg: {type: number, description: 总毛重,单位千克}
|
||||
totalNetWeightKg: {type: number, description: 总净重,单位千克}
|
||||
totalVolumeCbm: {type: number, description: 总体积,单位立方米}
|
||||
totalQuantity: {type: string, pattern: '^[0-9]+$', description: 产品总数量}
|
||||
remark: {type: string, nullable: true, description: 备注}
|
||||
createdBy: {$ref: '#/components/schemas/NullableLongId'}
|
||||
createdByName: {type: string, nullable: true, description: 创建人姓名}
|
||||
createdAt: {type: string, format: date-time, description: 创建时间}
|
||||
version: {type: integer, format: int32, minimum: 0, description: 乐观锁版本}
|
||||
LoadingItem:
|
||||
type: object
|
||||
required: [itemId, accountId, inboundId, inboundDetailId, packageCount, palletCount, grossWeightKg, netWeightKg, volumeCbm, dimensionalWeightKg, productQuantity, unitsPerPackage, loadSequence]
|
||||
properties:
|
||||
itemId: {$ref: '#/components/schemas/LongId'}
|
||||
accountId: {$ref: '#/components/schemas/LongId'}
|
||||
customerName: {type: string, nullable: true, description: 客户名称快照}
|
||||
inboundId: {$ref: '#/components/schemas/LongId'}
|
||||
inboundDetailId: {$ref: '#/components/schemas/LongId'}
|
||||
inboundCode: {type: string, nullable: true, description: 入仓码}
|
||||
skuCode: {type: string, nullable: true, description: SKU 编码快照}
|
||||
destinationWarehouse: {type: string, nullable: true, description: 目的仓名称快照}
|
||||
chineseName: {type: string, nullable: true, description: 中文品名快照}
|
||||
englishName: {type: string, nullable: true, description: 英文品名快照}
|
||||
goodsImageUrl: {type: string, nullable: true, description: 产品图片地址快照}
|
||||
packageCount: {type: integer, format: int32, minimum: 0, description: 箱数}
|
||||
palletCount: {type: integer, format: int32, minimum: 0, description: 托盘数}
|
||||
grossWeightKg: {type: number, description: 毛重,单位千克}
|
||||
netWeightKg: {type: number, description: 净重,单位千克}
|
||||
volumeCbm: {type: number, description: 体积,单位立方米}
|
||||
dimensionalWeightKg: {type: number, description: 材积重,单位千克}
|
||||
productQuantity: {type: string, pattern: '^[0-9]+$', description: 产品数量}
|
||||
unitsPerPackage: {type: integer, format: int32, minimum: 0, description: 每箱数量}
|
||||
fbaTrackingNo: {type: string, nullable: true, description: FBA 跟踪编号}
|
||||
shipmentNo: {type: string, nullable: true, description: 货件号}
|
||||
shippingMark: {type: string, nullable: true, description: 唛头}
|
||||
internalRemark: {type: string, nullable: true, description: 内部备注}
|
||||
customerRemark: {type: string, nullable: true, description: 客户备注}
|
||||
warehouseRemark: {type: string, nullable: true, description: 仓库备注}
|
||||
loadSequence: {type: integer, format: int32, minimum: 0, description: 装柜顺序}
|
||||
frozenAt: {type: string, format: date-time, nullable: true, description: 明细冻结时间}
|
||||
OperationHistory:
|
||||
type: object
|
||||
required: [historyId, actionType, operatorId, occurredAt]
|
||||
properties:
|
||||
historyId: {$ref: '#/components/schemas/LongId'}
|
||||
itemId: {$ref: '#/components/schemas/NullableLongId'}
|
||||
actionType: {type: string, description: 操作类型}
|
||||
fromStatus: {type: string, nullable: true, description: 操作前状态}
|
||||
toStatus: {type: string, nullable: true, description: 操作后状态}
|
||||
beforeSnapshot: {type: string, nullable: true, description: 操作前快照}
|
||||
afterSnapshot: {type: string, nullable: true, description: 操作后快照}
|
||||
operatorId: {$ref: '#/components/schemas/LongId'}
|
||||
operatorName: {type: string, nullable: true, description: 操作人姓名}
|
||||
operationReason: {type: string, nullable: true, description: 操作原因}
|
||||
occurredAt: {type: string, format: date-time, description: 操作时间}
|
||||
PreloadDetail:
|
||||
type: object
|
||||
required: [summary, items, histories]
|
||||
properties:
|
||||
summary: {$ref: '#/components/schemas/PreloadSummary'}
|
||||
items: {type: array, description: 装柜中明细,可维护未拣货项, items: {$ref: '#/components/schemas/LoadingItem'}}
|
||||
histories: {type: array, description: 计划操作历史, items: {$ref: '#/components/schemas/OperationHistory'}}
|
||||
ConfirmedDetail:
|
||||
type: object
|
||||
required: [summary, items, histories]
|
||||
properties:
|
||||
summary: {$ref: '#/components/schemas/ConfirmedSummary'}
|
||||
items: {type: array, description: 已完成且永久只读的装柜明细, items: {$ref: '#/components/schemas/LoadingItem'}}
|
||||
histories: {type: array, description: 计划操作历史, items: {$ref: '#/components/schemas/OperationHistory'}}
|
||||
TransportUpdateRequest:
|
||||
type: object
|
||||
required: [expectedVersion]
|
||||
additionalProperties: false
|
||||
properties:
|
||||
containerNo: {type: string, maxLength: 64, nullable: true, description: 集装箱号}
|
||||
voyageNo: {type: string, maxLength: 64, nullable: true, description: 航次}
|
||||
expectedVersion: {type: integer, format: int32, minimum: 0, description: 当前乐观锁版本}
|
||||
operationReason: {type: string, maxLength: 500, nullable: true, description: 操作原因}
|
||||
AdvanceRequest:
|
||||
type: object
|
||||
required: [expectedVersion]
|
||||
additionalProperties: false
|
||||
properties:
|
||||
expectedVersion: {type: integer, format: int32, minimum: 0, description: 当前乐观锁版本}
|
||||
operationReason: {type: string, maxLength: 500, nullable: true, description: 操作原因}
|
||||
Reference in New Issue
Block a user