← 返回文章列表
所属专题:AI 外骨骼

统一码 + 上传文件:一张 jpeg 逼我重新认 API 的券码改造复盘

更新于 2026-06-25年份:2026字数:3,600阅读时长:11 分钟

一句话:当 orderType=13 且 voucherType=5 时,券码红框整块不渲染,只留券图;判定逻辑外置到 Api.js 纯函数,Voucher.js 只管编排,其他场景一行不动。

TL;DR · 核心结论

  • 1判定钉死在后端契约:orderType=13 + voucherType=5,不靠 URL 猜、不靠 voucherType≠0 宽杀。
  • 2规则外置 Api.js(resolveOrderType / isUnifiedCodeFileVoucher / getVoucherDisplayCode),Voucher.js 只改 renderDetail 分支,11 条单测守住边界。
  • 3枚举型需求先拿文档或抓包 JSON 再写码;推断可以当假设,但必须标注风险,否则前期搜索成本会白烧。

AI Coding · 统一码文件型券展示改造

13+5
判定
3
纯函数
11
单测
最小
diff
零误伤

产品需求写得很直白:国际版 xxx 订单详情,商品是"统一码",兑换方式是"上传文件"——券码信息区只展示券图,红框里的数字码模块(文案、长串码、复制按钮、"待使用"状态)全部藏起来。

技术约束同样直白:改动要小,只动这一个场景,别的券类型一行别碰;代码得能测、能维护,别把 Voucher.js 再堆成意大利面。

听起来像"加个 if 的事儿"。我一开始也这么以为。

开局

开局:我在代码里"猜"了一轮

没有接口文档的时候,人很容易用 UI 现象反推后端语义。我(以及 AI 助手)早期走的就是这条路:

  • orderType === 13 像是统一码 ✓
  • voucherType !== 0 像是"非纯数字码"→ 当成上传文件?✗
  • voucherValue 是个 jpeg URL → 有图就是文件型?✗

全仓搜 sendCodeType、exchangeType、git 历史、Jest 缓存……有效信息密度低得可怜。backEnd 仓库还是空的,没法交叉验证。

转折点来了:你扔过来两样东西——ws 商城 orderDetails 接口文档截图(voucherList 字段枚举),再加一条真实响应 JSON。局面才从"推断"变成"对照":

统一码
字段
voucherList[].orderType
枚举值
13
上传文件(文件型券)
字段
voucherList[].voucherType
枚举值
5

JSON 里 orderType: 13voucherType: 5voucherValue 指向 jpeg——和文档严丝合缝。这次改造最关键的质量保障,就在这一张截图 + 一条 JSON 上。

做对了

改对了什么

1

招式 1:展示规则和 UI 解耦(SRP 那种)

判定和取码逻辑抽到 Api.js 三个纯函数:

- resolveOrderType() — 处理字段层级差异(券级 → 子单级 → 订单级) - isUnifiedCodeFileVoucher() — 唯一的业务开关 - getVoucherDisplayCode() — 展示层取码

Voucher.js 只负责一件事:红框模块渲不渲染。好处很实在:

- 11 个单测覆盖层级解析与边界(13+5 / 13+1 / 12+5) - 以后改 UI 不用再把 orderType 判断抄第三遍 - 类组件里常见且稳妥:业务规则进无副作用模块,组件做编排

// 层级回退:?? 只对 null/undefined 生效,0 不会被误判成"缺失"
item?.orderType ?? subOrderType ?? orderData?.orderType
2

招式 2:改动面卡得紧

没动 getStatus、退款参数 voucherCode、图片轮播、voucherType != 7 过滤。非 13+5 仍走原 renderDetail 分支;统一码非文件型券仍用 code,其他场景仍用 voucherCode(commit 48e51aa8 的老规矩保留)。

这就是"只改上传文件场景"该有的样子。

3

招式 3:主动避开同名字段的坑

排查过程中特意区分了几组容易看岔的字段:

- subOrderDetailsList[0].voucherType: 13 — 子单级,含义不同于券级 - orderProductDetails.exchangeType: 104 — 商品兑换配置,不是券展示类型 - voucherCreateMethond / createVoucherWay — 发码方式,文档没定义成"上传文件展示类型"

JSON 扁平嵌套下,同名不同义是集成前端最常见的 bug 来源。路径写不对,测再多也白搭。

待改进

还能更好的地方

4

前期探索成本偏高

根因很简单:需求里的"上传文件"是后端枚举,不能从前端 UI 反推;backEnd 仓库又空的。类似任务,文档/抓包前置能砍掉大量无效搜索。推断不是不能用,得标明"可能误伤 13+1 二维码"这种风险。

5

测试覆盖还有洞

Api.test.js 把判定函数盖住了,但缺:

- 组件级测试:13+5 下红框 DOM 是否真的消失 - 混合券列表:第一张非文件型、后面是文件型时的展示(renderContent 仍按第一张 voucherType===0 决定图片区,这是历史隐患)

Review 还点出一个产品边界:13+5 在 refunding/refunded 仍渲染"退款详情"按钮,和"严格只展示图片"可能不一致——待产品确认,目前算半开着的门。

6

文档可以再沉淀一行

voucherType 枚举 0~5 现在只散落在注释里。建议在 Api.js 或内部 wiki 补一句"来源:ws 商城 orderDetails 文档",后人改代码时少踩一次坑。

原理

原理,不废话版

1. 业务规则绑后端契约,不绑 UI 现象

voucherValue 有 URL → 有图,不能说明"兑换方式 = 上传文件"。voucherType=5 → 文档定义"文件",才是契约。宽条件(比如 voucherType≠0)的典型后果:统一码 + 二维码(13+1)被误隐藏数字码。

2. 空字符串驱动 UI,结构分支防空壳

getVoucherDisplayCode 在 13+5 返回 ''renderCode / renderCopyif (!voucherCode) return null。数据层空值驱动不渲染,比在多处重复 if (isUnifiedCodeFileVoucher) 更 DRY;renderDetail 仍对整个红框做分支,是为了避免只剩"券码"标题、下面啥也没有的空壳 DOM——数据驱动和结构分支的折中。

3. 单测金字塔

纯函数单测:快、稳,11 条已够判定逻辑回归。组件测试要 mock intl / CopyToClipboard,成本高,但适合锁 UI 契约。E2E 用真实 13+5 订单走查。三层各干各的,别指望一层包打天下。

4. 遗留类组件上的最小 diff

Voucher.js 还扛着轮播、Popup、CopyToClipboard、路由跳转。这次只动 renderDetail 分支,没重构 Hooks——交付风险可控。规则外置到 Api.js,已经为将来抽 useVoucherDisplayPolicy(orderData, item) 留了接口。

结语

结语

需求符合度

核心场景(13+5 待使用)符合;退款态按钮待产品拍板

范围控制

判定精确,13+1 等场景未误伤

工程质量

规则外置 + 单测较好;缺组件级与混合券回归

效率

文档/抓包前置可显著缩短前期搜索

这次改造的价值,不在于又隐藏了一个红框,而在于用后端明确枚举替代前端推断,再用纯函数 + 精准分支实现"只改上传文件场景"。

下次接到"枚举型展示规则"的需求,我会先把文档或一条 orderDetails JSON 甩到聊天框里,再让 AI 写第一行代码。推断可以留着当草稿,但别把它当交付标准——不然你和我都会在前仓里多绕好几圈。

本文属于 AI 实用主义流派 的第 41 篇肉身实战。

阅读时长:11 分钟


文档信息

版权声明:自由转载-非商用-非衍生-保持署名(CC BY-NC-ND 3.0)

原文链接:https://yijinlee.com/articles/article-54

作者:李奕锦

商业用途或修改衍生请联系授权。


李奕锦
李奕锦

全栈工程师,业余马拉松选手。

TL;DR

  • 判定钉死在后端契约:orderType=13 + voucherType=5,不靠 URL 猜、不靠 voucherType≠0 宽杀。
  • 规则外置 Api.js(resolveOrderType / isUnifiedCodeFileVoucher / getVoucherDisplayCode),Voucher.js 只改 renderDetail 分支,11 条单测守住边界。
  • 枚举型需求先拿文档或抓包 JSON 再写码;推断可以当假设,但必须标注风险,否则前期搜索成本会白烧。
Tags:AI CodingCursorReactorderDetailsvoucherType纯函数单元测试最小 diff国际版 xxx

该专题下的阅读路径

AI Coding架构排障

常见问题 FAQ

Q1. 为什么不能靠 voucherValue 是 URL 来判断"上传文件"?
URL 只说明后端给了张图,不能说明兑换方式是文件型券。voucherType=5 才是 ws 商城文档里"文件"的契约定义;用 voucherType≠0 之类的宽条件会把 13+1 二维码场景误伤。
Q2. subOrderDetailsList[0].voucherType: 13 和券级 voucherType: 5 怎么区分?
同名不同义。子单级的 13 是子单业务类型,券级的 5 才是展示类型。判定必须写清路径 voucherList[].voucherType,不能读 subOrderDetailsList。
Q3. 为什么把判定抽到 Api.js 而不是写在 Voucher.js 里?
类组件里散落 orderType/voucherType 判断,改 UI 就要重复写一遍。纯函数可单测(11 条覆盖 13+5 / 13+1 / 12+5 和层级回退),组件只负责"红框渲不渲染"。
Q4. 退款态还显示"退款详情"按钮,算不算需求没闭环?
待使用态已符合"只展示券图";refunding/refunded 下按钮仍渲染,和"严格只展示图片"可能有出入——这块需要产品确认,目前算已知边界。

发表评论

分享你的想法和反馈

支持 Markdown 格式

0/5000