行程预定是通过第三方平台进行的,但是我们也会在本系统落一条记录,方便用户查询。
- 预订记录(booking_record):真正花了钱的机票/酒店/火车票,来自 tuniu、rolling-go-hotel、flight-manager 等多个外部平台,每个平台返回的明细字段都不一样。共性字段(金额、状态、联系人)该建列,个性明细(航班号、房型、乘客)无法穷举,只能用一个 JSON 列兜底。
预定记录和差旅单之间的关系是多对1的,即一个差旅单可能有多条记录,比如2条火车票记录,1条酒店记录。
booking_record表结构如下:
CREATE TABLE IF NOT EXISTS `booking_record` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增主键', -- 与 travel_order 不同:这里用自增
`booking_id` VARCHAR(64) NOT NULL COMMENT '内部预订单号(系统生成,全局唯一)',
`user_id` VARCHAR(64) NOT NULL,
`conversation_id` VARCHAR(64) DEFAULT NULL COMMENT '关联会话ID',
`travel_order_id` VARCHAR(64) DEFAULT NULL COMMENT '关联差旅单ID(可为空)', -- 预订可挂靠差旅单,也可独立
`biz_type` VARCHAR(16) NOT NULL COMMENT '业务类型: FLIGHT/HOTEL/TRAIN/TICKET/CRUISE/VACATION',
`platform` VARCHAR(32) NOT NULL COMMENT '平台: tuniu / rolling-go-hotel / flight-manager 等',
`external_order_no` VARCHAR(128) DEFAULT NULL COMMENT '外部平台主订单号',
`status` VARCHAR(32) NOT NULL DEFAULT 'CREATED' COMMENT '统一状态', -- 屏蔽平台差异的内部统一态
`external_status` VARCHAR(64) DEFAULT NULL COMMENT '外部平台原始状态码/文案', -- 保留平台原值以便追溯
`payment_status` VARCHAR(32) DEFAULT NULL COMMENT '支付状态: UNPAID/PAID/REFUNDED',
`title` VARCHAR(256) DEFAULT NULL,
`total_amount` DECIMAL(12,2) DEFAULT NULL COMMENT '订单总金额(元)', -- 金额用 DECIMAL,不用 double
`currency` VARCHAR(8) DEFAULT 'CNY',
`contact_name` VARCHAR(64) DEFAULT NULL,
`contact_phone` VARCHAR(32) DEFAULT NULL,
`start_time` DATETIME DEFAULT NULL COMMENT '服务开始时间(出发/入住)',
`end_time` DATETIME DEFAULT NULL COMMENT '服务结束时间(到达/离店)',
`detail` JSON DEFAULT NULL COMMENT '平台原始/明细信息JSON(航班号、房型、乘客、行程等)',
`remark` VARCHAR(512) DEFAULT NULL,
`booked_at` DATETIME DEFAULT NULL COMMENT '下单时间',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标志',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_booking_id` (`booking_id`),
UNIQUE KEY `uk_platform_order` (`platform`, `biz_type`, `external_order_no`), -- 幂等去重的核心约束
KEY `idx_user_id` (`user_id`),
KEY `idx_user_biz` (`user_id`, `biz_type`),
KEY `idx_travel_order_id` (`travel_order_id`),
KEY `idx_status` (`status`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
- 双单号体系:booking_id(内部生成、全局唯一)对外,external_order_no(平台主单号)对下游平台。查询用内部单号,对账用外部单号。
- 双状态体系:status 是屏蔽平台差异的内部统一态(见枚举),external_status 原样保留平台文案便于追溯——典型的"防腐层"字段设计。
- uk_platform_order(platform, biz_type, external_order_no) 唯一键是幂等落库的地基:同一平台同一类型同一外部单号只能有一条,自动挡住重复下单的脏数据。
- detail JSON 是整张表的"弹性内容"——航班号、房型、乘客名单这些随品类而变的明细,全塞进这一列,新增品类不用改表结构。
- 金额用 DECIMAL(12,2) 而非 double,避免浮点误差;deleted TINYINT 走逻辑删除,预订这种涉及资损的数据不做物理删除。