Reviewed-on: #114
4.6 KiB
POST /api/v1/compare/record — 上报一次比价结果(幂等)
所属:比价记录组(前缀
/api/v1/compare) | 鉴权:Bearer | ← 返回 API 索引
比价 done 帧后上报一条比价结果,落 comparison_record 表,作为「我的比价记录」数据源 + 用户级行为画像。
⚠️ 灰度定位(2026-07):写
comparison_record现以透传壳compare.py的后端 harvest 为主(帧0 建running行 → done/finalize 落终态,新客户端不再 POST)。本接口降级为老客户端兼容通道,与 harvest 按trace_idreconcile(success 不被降级);新版覆盖够高后可下线本 POST。 与软鉴权透传端点/api/v1/price/step不同:那是转发壳(顺带 harvest 落库),本接口按用户维度显式上报,必须鉴权。
入参(JSON body)
字段刻意对齐 pricebot 协议(02_api_protocol.md 的 calibration + done.params),客户端把 Phase1 的 calibration 和 done 帧 params 零翻译映射上来即可。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
trace_id |
string | ✅ | — | 一次比价的唯一标识(app-server 帧0 签发)。幂等键(trace_id 单列唯一):同 trace_id 重复上报覆盖、返回同一 id;与 harvest 行按它 reconcile |
business_type |
string | ❌ | food |
food(外卖,当前唯一接通) / ecom(电商) / coupon(领券) |
device_id |
string | null | ❌ | null | 设备号 |
store_name |
string | null | ❌ | null | 店铺名(外卖,来自 calibration.result) |
source_platform_id |
string | null | ❌ | null | 源平台代号,如 taobao_flash |
source_platform_name |
string | null | ❌ | null | 源平台中文名 |
source_package |
string | null | ❌ | null | 源平台 Android 包名 |
source_price |
float | null | ❌ | null | 源平台到手价(元) |
items |
Item[] | ❌ | [] | 下单菜品,{name, qty, specs?} |
comparison_results |
Result[] | ❌ | [] | 逐平台对比,见下表(price 单位元) |
skipped_dish_count |
int | null | ❌ | null | 目标平台未找到、跳过的菜品数 |
skipped_dish_names |
string[] | ❌ | [] | 被跳过的菜名 |
total_dish_count |
int | null | ❌ | null | 原始菜品总数 |
information |
string | null | ❌ | null | done 帧文案(成功摘要 / 失败具体原因),持久化为列并在列表/详情返回,前端失败时当原因展示 |
status |
string | null | ❌ | null | success / failed。不传则服务端派生 |
Item:{ name: string, qty: int=1, specs: string[]\|null }
Result(comparison_results 元素):{ platform_id, platform_name, package, price(元,float\|null), is_source(bool), rank(int\|null), coupon_saved(元,float\|null), coupon_name(string\|null) }
coupon_saved:该平台本单平台主优惠额(元)——美团红包 / 淘宝平台红包 / 京东优惠券·百亿补贴,只取那一笔,不含配送费减免/共减总额。仅外卖目标平台带值,源平台/没用为null,前端记录页据此展示**「已优惠 ¥X」**(null 不展示)。coupon_name:优惠来源名(展示用,best-effort)——美团「外卖大额神券」/ 京东「百亿补贴」/ 淘宝「平台红包」。仅在该行有coupon_saved时带;null时前端走通用「红包」。非用户选中的具体券名(选中态不可读)。
服务端派生(客户端不用算)
从 comparison_results 派生并落结构化列:
best_*:取最便宜的一家(按rank升序、再按price),写best_platform_id/name/best_price_centssource_price_cents:优先用source_price,缺失则取comparison_results里is_source=true行的价saved_amount_cents=源价 − 最优价(可为 0 / 负:源平台本来就最便宜)is_source_best:最便宜的一家是否为源平台(= 这次没省到)status(未显式传时):存在「非源且有价」的结果 →success,否则 →failed- 金额一律
round(元 × 100)存分
comparison_results / items / skipped_dish_names 原样存 JSON;完整上报 body 另存 raw_payload(详情接口可取回)。
出参
响应 200:{ "id": int }(写入或已存在记录的 id)
错误
401未鉴权422缺trace_id或字段类型不符
说明
失败的比价(done 帧只有源/空 comparison_results)也会落一条 status=failed——「越详细越好」,是否在 UI 展示由前端过滤。