2026-08-08 13:32:20 +08:00
SET NAMES utf8mb4 ;
CREATE TABLE IF NOT EXISTS fl_truck_appointment (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '拖车预约ID' ,
appointment_no VARCHAR ( 40 ) NOT NULL COMMENT '平台拖车预约编号' ,
outbound_order_id BIGINT UNSIGNED NULL COMMENT '关联头程订单逻辑ID;不跨库建外键' ,
ocean_booking_id BIGINT UNSIGNED NULL COMMENT '关联海运订舱逻辑ID' ,
2026-09-01 16:21:27 +08:00
container_booking_id BIGINT UNSIGNED NULL COMMENT '停用保留列;订舱级拖车单不写入、不读取' ,
loading_plan_id BIGINT UNSIGNED NULL COMMENT '停用保留列;订舱级拖车单不写入、不读取' ,
2026-08-11 18:06:26 +08:00
warehouse_id BIGINT UNSIGNED NULL COMMENT '预约到仓的国内收货仓逻辑ID' ,
carrier_id BIGINT UNSIGNED NULL COMMENT '拖车服务商逻辑ID' ,
carrier_name VARCHAR ( 128 ) NULL COMMENT '拖车服务商名称快照' ,
2026-08-18 15:43:58 +08:00
bill_of_lading_no VARCHAR ( 128 ) NULL COMMENT '派车提单号快照;关联RELEASED订舱时由订舱事实源冻结' ,
2026-08-11 18:06:26 +08:00
fleet_contact VARCHAR ( 64 ) NULL COMMENT '车队联系人' ,
fleet_phone VARCHAR ( 32 ) NULL COMMENT '车队联系电话' ,
driver_name VARCHAR ( 64 ) NULL COMMENT '司机姓名' ,
driver_phone VARCHAR ( 32 ) NULL COMMENT '司机联系电话' ,
driver_id_card VARCHAR ( 32 ) NULL COMMENT '司机身份证号;平台内部敏感信息' ,
vehicle_no VARCHAR ( 32 ) NULL COMMENT '车辆车牌号' ,
store_name VARCHAR ( 128 ) NULL COMMENT '到仓装柜地点名称快照' ,
store_contact VARCHAR ( 64 ) NULL COMMENT '到仓地点联系人快照' ,
store_phone VARCHAR ( 32 ) NULL COMMENT '到仓地点联系电话快照' ,
store_address VARCHAR ( 255 ) NULL COMMENT '到仓装柜地点地址快照' ,
store_city VARCHAR ( 64 ) NULL COMMENT '到仓地点城市快照' ,
store_zipcode VARCHAR ( 16 ) NULL COMMENT '到仓地点邮编快照' ,
package_count INT UNSIGNED NULL COMMENT '预约货物包装件数快照' ,
gross_weight_kg DECIMAL ( 18 , 3 ) NULL COMMENT '预约货物毛重,单位千克' ,
volume_cbm DECIMAL ( 18 , 4 ) NULL COMMENT '预约货物体积,单位立方米' ,
pallet_count INT UNSIGNED NULL COMMENT '预约托盘数量' ,
2026-09-01 09:51:59 +08:00
po_no VARCHAR ( 255 ) NULL COMMENT '关联采购单号' ,
2026-08-11 18:06:26 +08:00
planned_loading_at DATETIME ( 3 ) NULL COMMENT '预约到仓装柜时间' ,
actual_arrived_warehouse_at DATETIME ( 3 ) NULL COMMENT '车辆实际到达收货仓时间' ,
actual_loading_at DATETIME ( 3 ) NULL COMMENT '实际开始装柜时间' ,
2026-09-14 20:03:22 +08:00
actual_departed_at DATETIME ( 3 ) NULL COMMENT '订舱全部要求货柜确认国内离仓的最终时间' ,
2026-08-11 18:06:26 +08:00
transit_minutes INT UNSIGNED NULL COMMENT '从到仓到离仓的运输作业耗时,单位分钟' ,
payable_amount DECIMAL ( 18 , 2 ) NULL COMMENT '应付拖车服务商金额;币种由currency指定' ,
2026-09-14 20:03:22 +08:00
currency VARCHAR ( 8 ) NOT NULL DEFAULT 'RMB' COMMENT '应付金额币种;国内拖车仅RMB,财务以CNY入池' ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'DRAFT' COMMENT '拖车预约状态:DRAFT草稿、PENDING_DISPATCH待派车、DISPATCHED已派车、PICKUP_IN_PROGRESS提货中、ARRIVED_WAREHOUSE已到仓、LOADING装柜中、COMPLETED已完成、RESCHEDULED已改约、EXCEPTION异常、CANCELLED已取消' ,
2026-09-01 16:21:27 +08:00
active_ocean_booking_id BIGINT UNSIGNED GENERATED ALWAYS AS ( CASE WHEN status NOT IN ( 'COMPLETED' , 'CANCELLED' , 'EXCEPTION' ) THEN ocean_booking_id ELSE NULL END ) STORED COMMENT '非终态预约的订舱唯一键' ,
2026-08-11 18:06:26 +08:00
revision INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '拖车预约业务修订号;每次状态或改约递增' ,
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号' ,
remark VARCHAR ( 1000 ) 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 '拖车预约最后更新时间' ,
2026-09-01 16:21:27 +08:00
PRIMARY KEY ( id ), UNIQUE KEY uk_truck_appointment_no ( appointment_no ), UNIQUE KEY uk_truck_active_ocean_booking ( active_ocean_booking_id ),
KEY idx_truck_appointment_status ( status , updated_at ), KEY idx_truck_appointment_ocean ( ocean_booking_id ),
2026-09-14 20:03:22 +08:00
CONSTRAINT chk_truck_appointment_status CHECK ( status IN ( 'DRAFT' , 'PENDING_DISPATCH' , 'DISPATCHED' , 'PICKUP_IN_PROGRESS' , 'ARRIVED_WAREHOUSE' , 'LOADING' , 'COMPLETED' , 'RESCHEDULED' , 'EXCEPTION' , 'CANCELLED' )),
CONSTRAINT chk_truck_appointment_currency CHECK ( currency IN ( 'RMB' ))
2026-08-08 13:32:20 +08:00
) ENGINE = InnoDB COMMENT = '三期拖车预约派车聚合' ;
CREATE TABLE IF NOT EXISTS fl_truck_appointment_history (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '拖车预约历史ID' , appointment_id BIGINT UNSIGNED NOT NULL COMMENT '所属拖车预约ID' , revision INT UNSIGNED NOT NULL COMMENT '该预约业务修订号' , action VARCHAR ( 32 ) NOT NULL COMMENT '触发状态或改约的业务动作' ,
from_status VARCHAR ( 32 ) NULL COMMENT '变更前拖车状态;创建时为空' , to_status VARCHAR ( 32 ) NULL COMMENT '变更后拖车状态;改约时可保持原状态' , reason VARCHAR ( 500 ) NULL COMMENT '状态或改约原因' , operator_id BIGINT UNSIGNED NOT NULL COMMENT '执行操作的平台用户ID' ,
operator_name VARCHAR ( 64 ) NULL COMMENT '操作人姓名快照' , request_id VARCHAR ( 128 ) NULL COMMENT '请求链路中的请求ID' , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '历史记录创建时间' , PRIMARY KEY ( id ), KEY idx_truck_history ( appointment_id , revision )
2026-08-08 13:32:20 +08:00
) ENGINE = InnoDB COMMENT = '拖车状态与改约历史' ;
CREATE TABLE IF NOT EXISTS fl_truck_appointment_attachment (
2026-08-31 19:55:58 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '拖车附件关系ID' , appointment_id BIGINT UNSIGNED NOT NULL COMMENT '所属拖车预约ID' , file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件逻辑ID' , attachment_type VARCHAR ( 32 ) NOT NULL COMMENT '附件类型:DISPATCH_ORDER派车单、DRIVER_DOCUMENT司机证件、VEHICLE_DOCUMENT车辆证件、OTHER其他;订舱确认与提单归订舱聚合' ,
2026-09-01 09:51:59 +08:00
file_name VARCHAR ( 255 ) NULL COMMENT '上传时文件名快照' , file_hash CHAR ( 64 ) NULL COMMENT '文件内容SHA-256摘要' , visibility VARCHAR ( 24 ) NOT NULL DEFAULT 'PLATFORM' COMMENT '可见范围:PLATFORM仅平台内部' , uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传操作人ID' ,
2026-08-31 19:55:58 +08:00
uploaded_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '附件上传时间' , PRIMARY KEY ( id ), UNIQUE KEY uk_truck_attachment ( appointment_id , file_id ), KEY idx_truck_attachment ( appointment_id ), CONSTRAINT chk_truck_attachment_type CHECK ( attachment_type IN ( 'DISPATCH_ORDER' , 'DRIVER_DOCUMENT' , 'VEHICLE_DOCUMENT' , 'OTHER' ))
2026-08-08 13:32:20 +08:00
) ENGINE = InnoDB COMMENT = '拖车附件文件引用' ;
CREATE TABLE IF NOT EXISTS fl_truck_appointment_operation (
2026-08-11 18:06:26 +08:00
id BIGINT UNSIGNED NOT NULL COMMENT '拖车写操作幂等记录ID' , appointment_id BIGINT UNSIGNED NOT NULL COMMENT '所属拖车预约ID' , idempotency_key VARCHAR ( 128 ) NOT NULL COMMENT '客户端写操作幂等键' , request_hash CHAR ( 64 ) NOT NULL COMMENT '规范化请求内容SHA-256摘要;用于识别同键不同请求' ,
action VARCHAR ( 32 ) NOT NULL COMMENT '执行的拖车业务动作' , response_snapshot JSON NULL COMMENT '成功响应JSON快照;供相同幂等请求重放' , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ) COMMENT '幂等记录创建时间' , PRIMARY KEY ( id ), UNIQUE KEY uk_truck_operation ( idempotency_key ), KEY idx_truck_operation_appointment ( appointment_id )
2026-08-08 13:32:20 +08:00
) ENGINE = InnoDB COMMENT = '拖车操作幂等记录' ;
2026-08-08 14:19:45 +08:00
2026-08-10 09:11:56 +08:00
DROP PROCEDURE IF EXISTS phase3_truck_add_column ;
DELIMITER $$
CREATE PROCEDURE phase3_truck_add_column (
IN p_column_name VARCHAR ( 64 ), IN p_definition TEXT
)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_schema = DATABASE ()
AND table_name = 'fl_truck_appointment'
AND column_name = p_column_name
) THEN
SET @ phase3_truck_ddl = CONCAT (
'ALTER TABLE fl_truck_appointment ADD COLUMN `' , p_column_name , '` ' , p_definition
);
PREPARE phase3_truck_stmt FROM @ phase3_truck_ddl ;
EXECUTE phase3_truck_stmt ;
DEALLOCATE PREPARE phase3_truck_stmt ;
END IF ;
END $$
DELIMITER ;
2026-08-18 19:04:22 +08:00
CALL phase3_truck_add_column (
'bill_of_lading_no' ,
'VARCHAR(128) NULL COMMENT ''派车提单号快照;关联RELEASED订舱时由订舱事实源冻结'' AFTER carrier_name'
);
2026-08-10 09:11:56 +08:00
CALL phase3_truck_add_column (
'actual_arrived_warehouse_at' ,
2026-08-11 18:06:26 +08:00
'DATETIME(3) NULL COMMENT ''车辆实际到达收货仓时间'' AFTER planned_loading_at'
2026-08-10 09:11:56 +08:00
);
2026-08-18 19:04:22 +08:00
CALL phase3_truck_add_column (
'actual_loading_at' ,
'DATETIME(3) NULL COMMENT ''实际开始装柜时间'' AFTER actual_arrived_warehouse_at'
);
2026-08-10 09:11:56 +08:00
CALL phase3_truck_add_column (
'actual_departed_at' ,
2026-09-14 20:03:22 +08:00
'DATETIME(3) NULL COMMENT ''订舱全部要求货柜确认国内离仓的最终时间'' AFTER actual_loading_at'
2026-08-10 09:11:56 +08:00
);
2026-09-01 09:51:59 +08:00
CALL phase3_truck_add_column (
2026-09-01 16:21:27 +08:00
'active_ocean_booking_id' ,
'BIGINT UNSIGNED GENERATED ALWAYS AS (CASE WHEN status NOT IN (''COMPLETED'',''CANCELLED'',''EXCEPTION'') THEN ocean_booking_id ELSE NULL END) STORED COMMENT ''非终态预约的订舱唯一键'' AFTER status'
2026-09-01 09:51:59 +08:00
);
2026-08-10 09:11:56 +08:00
DROP PROCEDURE IF EXISTS phase3_truck_add_column ;
2026-09-01 16:21:27 +08:00
SET @ phase3_truck_drop_old_active_index = IF (
2026-09-01 09:51:59 +08:00
EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE ()
AND table_name = 'fl_truck_appointment' AND index_name = 'uk_truck_active_container' AND non_unique = 0 ),
2026-09-01 16:21:27 +08:00
'ALTER TABLE fl_truck_appointment DROP INDEX uk_truck_active_container' ,
'SELECT 1'
);
PREPARE phase3_truck_active_stmt FROM @ phase3_truck_drop_old_active_index ;
EXECUTE phase3_truck_active_stmt ;
DEALLOCATE PREPARE phase3_truck_active_stmt ;
SET @ phase3_truck_active_index = IF (
EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE ()
AND table_name = 'fl_truck_appointment' AND index_name = 'uk_truck_active_ocean_booking' AND non_unique = 0 ),
2026-09-01 09:51:59 +08:00
'SELECT 1' ,
2026-09-01 16:21:27 +08:00
'ALTER TABLE fl_truck_appointment ADD UNIQUE KEY uk_truck_active_ocean_booking(active_ocean_booking_id)'
2026-09-01 09:51:59 +08:00
);
PREPARE phase3_truck_active_stmt FROM @ phase3_truck_active_index ;
EXECUTE phase3_truck_active_stmt ;
DEALLOCATE PREPARE phase3_truck_active_stmt ;
2026-08-08 14:19:45 +08:00
USE baiyue_iam ;
DROP PROCEDURE IF EXISTS assert_truck_appointment_permission_ids_available ;
DELIMITER $$
CREATE PROCEDURE assert_truck_appointment_permission_ids_available ()
BEGIN
IF EXISTS (
SELECT 1 FROM iam_permission
2026-08-20 13:34:29 +08:00
WHERE ( id = 5102150 AND permission_code <> 'platform:firstleg:truck-appointment:list' )
OR ( id = 5102151 AND permission_code NOT IN (
'platform:firstleg:truck-appointment:list' ,
2026-08-20 18:02:38 +08:00
CONCAT ( 'platform:firstleg:truck-appointment:' , 'view' )))
2026-08-20 13:34:29 +08:00
OR ( id = 5102152 AND permission_code <> 'platform:firstleg:truck-appointment:create' )
OR ( id = 5102153 AND permission_code <> 'platform:firstleg:truck-appointment:edit' )
OR ( id = 5102154 AND permission_code <> 'platform:firstleg:truck-appointment:operate' )
2026-08-08 14:19:45 +08:00
OR ( permission_code LIKE 'platform:firstleg:truck-appointment:%'
AND ( tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102150 AND 5102154 ))
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '三期拖车权限迁移失败:5102150-5102154 ID 或权限码被其他语义占用' ;
END IF ;
END $$
DELIMITER ;
CALL assert_truck_appointment_permission_ids_available ();
DROP PROCEDURE IF EXISTS assert_truck_appointment_permission_ids_available ;
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
( 5102150 , 0 , 'PLATFORM' , 'MENU' , 5102000 , 'platform:firstleg:truck-appointment:list' , '拖车预约' , '/first-leg/truck-appointments' , 'GET' , 90 , 'ACTIVE' , 1 , 0 ),
( 5102152 , 0 , 'PLATFORM' , 'BUTTON' , 5102150 , 'platform:firstleg:truck-appointment:create' , '创建拖车预约' , NULL , 'POST' , 20 , 'ACTIVE' , 1 , 0 ),
( 5102153 , 0 , 'PLATFORM' , 'BUTTON' , 5102150 , 'platform:firstleg:truck-appointment:edit' , '编辑拖车预约' , NULL , 'PUT' , 30 , 'ACTIVE' , 1 , 0 ),
( 5102154 , 0 , 'PLATFORM' , 'BUTTON' , 5102150 , 'platform:firstleg:truck-appointment:operate' , '操作拖车预约' , NULL , 'POST' , 40 , 'ACTIVE' , 1 , 0 )
ON DUPLICATE KEY UPDATE tenant_id = 0 , app_code = 'PLATFORM' , permission_type = VALUES ( permission_type ),
permission_code = VALUES ( permission_code ), permission_name = VALUES ( permission_name ), parent_id = VALUES ( parent_id ),
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 , 0 FROM iam_role role JOIN iam_permission permission
ON permission . tenant_id = 0 AND permission . app_code = 'PLATFORM'
AND permission . permission_code LIKE 'platform:firstleg:truck-appointment:%'
WHERE role . tenant_id = 0 AND role . role_code IN ( 'PLATFORM_ADMIN' , 'ORDER_OPERATOR' );
2026-08-13 12:22:31 +08:00
DELETE rp FROM iam_role_permission rp JOIN iam_permission p ON p . tenant_id = rp . tenant_id AND p . id = rp . permission_id
2026-08-13 12:54:34 +08:00
WHERE p . id = 5102151 ;
2026-08-20 18:02:38 +08:00
DELETE FROM iam_permission WHERE id = 5102151 ;
2026-08-13 12:22:31 +08:00
2026-08-08 14:19:45 +08:00
USE baiyue_firstleg ;