从总纲文档提取:6.2 匹配管理 + 12.3 供应商自动接入流水线
优先级: P0(核心基础模块)
开发周期: 2 周
每个供应商-酒店映射有一个 connection_mode 属性,决定平台与该供应商-酒店的交互方式。这不是 supplier_type(wholesaler/chain_hotel/independent_hotel),而是独立的连接维度——同一种 supplier_type 可以有不同的 connection_mode。
重要:
connection_mode配置在supplier_hotels表(供应商-酒店映射级别),而非suppliers表。支持同一供应商的不同酒店使用不同的连接模式。
| 维度 | 直连 direct_connect | 直采 direct_procure |
|---|---|---|
| 含义 | 平台实时调用供应商 API 查价 | 供应商价格通过拉取/推送预先同步到平台 |
| 价格查询 | 实时调用供应商 API 查价 | 查本地 inventory_snapshots + Redis 缓存 |
| 价格来源 | 供应商 API 实时返回 | 定时拉取或供应商推送 |
| 库存管理 | 不管理库存,有价即有房(但直采也可能有价即有房) | 可能管理库存(available_rooms 有值),也可能有价即有房(available_rooms=NULL) |
| 下单/取消/确认 | 调用供应商 API | 同左,也调用供应商 API |
| 下单确认 | 需等待供应商确认(PENDING_CONFIRMATION),可能被拒 | 同左,也需调用供应商 API 确认 |
| 典型供应商 | 支持实时 API 的批发商、直连酒店 CRS | 需批量同步价格的批发商 |
适配器处理差异:
- direct_connect:适配器需实现实时查询接口(search/price),下单后需轮询/Webhook 等待供应商确认
- direct_procure:适配器需实现拉取(Pull)和推送解析(ParsePush)接口,负责将供应商数据转为平台标准格式
详细设计见: 价格同步模块
解决多供应商的酒店/房型数据与平台标准数据之间的映射问题。这是 B2B2B 平台最核心的难点之一——不同供应商对同一酒店有不同编码、不同名称、不同房型描述。
| 功能 | 描述 |
|---|---|
| 自动匹配 | 基于多维度特征(名称相似度、坐标距离、地址、电话、星级)自动匹配 |
| 人工审核 | 低置信度匹配进入人工审核队列 |
| 批量匹配 | 支持新供应商接入时批量匹配历史数据 |
| 匹配置信度 | 输出 0-100 的匹配置信度分数,自动通过阈值可配置 |
| 反向映射 | 支持从平台酒店反查各供应商对应编码 |
| 匹配日志 | 记录匹配过程和变更历史,便于问题排查 |
| 房型匹配 | 酒店匹配后,自动/半自动匹配房型(床型、面积、人数等) |
综合匹配置信度 = W1 × 名称相似度 + W2 × 坐标距离分 + W3 × 地址相似度 + W4 × 星级匹配 + W5 × 链品牌匹配
名称相似度: Levenshtein Distance + Jaro-Winkler
坐标距离分: Haversine 公式,< 500m 得满分,> 5km 得 0 分
地址相似度: 去除标点空格后的编辑距离
星级匹配: 精确匹配 100%,差 1 级 50%,差 2 级 0%
默认权重: W1=0.35, W2=0.30, W3=0.15, W4=0.10, W5=0.10
通过阈值: >= 85 分自动匹配,60-85 人工审核,< 60 标记为不匹配
-- 匹配规则表
CREATE TABLE match_rules (
id SERIAL PRIMARY KEY,
supplier_code VARCHAR(32) NOT NULL,
rule_type VARCHAR(32) NOT NULL, -- hotel/room_type
field_name VARCHAR(64) NOT NULL, -- name/lat_lng/address/star
algorithm VARCHAR(64) NOT NULL, -- levenshtein/haversine/exact/regex
weight DECIMAL(3, 2) NOT NULL, -- 权重 0.00-1.00
threshold DECIMAL(5, 2), -- 单字段阈值
params JSONB, -- 算法参数
priority SMALLINT DEFAULT 0,
enabled BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 匹配任务表
CREATE TABLE match_tasks (
id BIGSERIAL PRIMARY KEY,
task_type VARCHAR(32) NOT NULL, -- hotel/room_type
supplier_code VARCHAR(32) NOT NULL,
total_count INT DEFAULT 0,
matched_count INT DEFAULT 0,
pending_count INT DEFAULT 0,
failed_count INT DEFAULT 0,
status VARCHAR(20) DEFAULT 'pending', -- pending/running/completed/failed
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
created_by VARCHAR(64),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 匹配历史表(审计)
CREATE TABLE match_history (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT REFERENCES match_tasks(id),
supplier_code VARCHAR(32),
match_type VARCHAR(32), -- hotel/room_type
supplier_id VARCHAR(64) NOT NULL,
platform_id BIGINT, -- 匹配到的平台ID
confidence DECIMAL(5, 2),
match_method VARCHAR(32), -- auto/manual/unmatched
old_platform_id BIGINT, -- 变更前的映射(如重新匹配)
details JSONB, -- 各维度得分明细
operator VARCHAR(64), -- 操作人(auto/manual)
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_match_history_task ON match_history (task_id);
CREATE INDEX idx_match_history_supplier ON match_history (supplier_code);
# 匹配操作 API
POST /api/v1/match/hotels # 触发酒店匹配任务
POST /api/v1/match/room-types # 触发房型匹配任务
GET /api/v1/match/tasks # 匹配任务列表
GET /api/v1/match/tasks/:id # 匹配任务详情+进度
GET /api/v1/match/pending # 待人工审核的匹配列表
POST /api/v1/match/pending/:id/confirm # 确认匹配
POST /api/v1/match/pending/:id/reject # 拒绝匹配
# 映射查询 API
GET /api/v1/mappings/hotel?supplier=XXX&supplier_hotel_id=YYY
GET /api/v1/mappings/hotel/:platform_hotel_id/suppliers # 反向查映射
GET /api/v1/mappings/room-type?supplier=XXX&supplier_room_code=YYY
| 关联模块 | 关系 |
|---|---|
| 酒店基库 | 读写标准酒店/房型数据 |
| 查价引擎 | direct_connect 供应商提供实时查价接口;direct_procure 供应商查本地 snapshot + Redis,详见价格同步模块 |
| 库存管理 | direct_procure 供应商的库存通过拉取/推送同步,详见价格同步模块;available_rooms=NULL 表示有价即有房 |
| 订单管理 | 两种模式都需调用供应商 API 确认;直采取消订单如有库存数则立即原子释放 |
| 管理后台 | 人工审核界面 |
供应商接入标准化流程:商务签约 → 技术适配 → 自动测试 → 灰度上线。
流程图:供应商接入流程
flowchart TD
A[商务签约完成] --> B[提交 API 文档和测试凭证]
B --> C[创建 supplier_onboarding]
C --> D[AI 生成适配器代码]
D --> E[Mock 测试
基于模拟数据]
E --> F{测试通过?}
F -->|否| G[AI 修复代码]
G --> E
F -->|是| H[集成测试
连接真实供应商测试环境]
H --> I{集成测试通过?}
I -->|否| J[生成诊断报告]
J --> K[通知人工介入]
K --> H
I -->|是| L[数据质量校验]
L --> M{质量达标?}
M -->|否| N[标记问题
部分上线]
N --> O
M -->|是| O[灰度发布 5%流量]
O --> P[监控灰度指标
响应时间/错误率/数据质量]
P --> Q{灰度正常?}
Q -->|否| R[自动回滚]
R --> H
Q -->|是| S[逐步扩大流量
10%→30%→50%→100%]
S --> T[正式上线]
T --> U[进入每日回归测试]
class F,I,M,Q decision
class A,T,U done
class R error
class G,J,K,N warning
class B,C,D,E,H,L,O,P,S process
classDef process fill:#1a2744,stroke:#58a6ff,stroke-width:1px,color:#c9d1d9
classDef decision fill:#3a2a1a,stroke:#f0883e,stroke-width:2px,color:#f0883e
classDef done fill:#1a3a2a,stroke:#3fb950,stroke-width:1px,color:#3fb950
classDef error fill:#3a1a1a,stroke:#f85149,stroke-width:2px,color:#f85149
classDef warning fill:#3a2a1a,stroke:#d29922,stroke-width:1px,color:#d29922
classDef skip fill:#21262d,stroke:#484f58,color:#8b949e
数据模型
CREATE TABLE supplier_onboarding (
id BIGSERIAL PRIMARY KEY,
supplier_id BIGINT REFERENCES suppliers(id),
status VARCHAR(32) DEFAULT 'pending',
-- pending/adapter_dev/mock_test/integration_test/staging/production/failed
api_doc_url VARCHAR(512),
test_credentials JSONB,
adapter_code TEXT,
test_results JSONB,
staging_config JSONB,
production_config JSONB,
health_score DECIMAL(5,2),
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
notes TEXT
);
CREATE TABLE supplier_test_suite (
id BIGSERIAL PRIMARY KEY,
onboarding_id BIGINT REFERENCES supplier_onboarding(id),
test_type VARCHAR(32) NOT NULL, -- mock/integration/regression
test_name VARCHAR(128) NOT NULL,
status VARCHAR(16), -- passed/failed/skipped
duration_ms INT,
error_detail TEXT,
executed_at TIMESTAMPTZ DEFAULT now()
);
API 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/suppliers/onboarding | 创建供应商接入任务 |
| PUT | /api/suppliers/onboarding/{id}/advance | 推进到下一阶段 |
| GET | /api/suppliers/onboarding/{id}/test-results | 获取测试结果 |
业务逻辑
创建 supplier_onboarding 记录后,状态机驱动整个流程。每个阶段有对应的自动化任务:adapter_dev 阶段根据 API 文档自动生成适配器骨架代码;mock_test 阶段运行 Mock 测试用例;integration_test 阶段对接真实供应商沙箱环境;staging 阶段小流量灰度验证;全部通过后进入 production。任何阶段失败进入 failed 状态,记录 notes 供人工排查。