Skip to content

ui: 价格提醒的目标价渲染丢失币种 —— 卡片显示「Above 350」,纯函数孪生体硬编码「$」 #260

Description

@wxrbyte

现象

价格类提醒(price_above / price_below)的目标价在列表里完全没有币种:

(fail) states the currency of a Hong Kong price alert
  Expected to contain: "Above HK$350.00"
  Received: "0700.HKActivePrice Above·Above 350×Created: 1970/1/1"

(fail) states the currency of a mainland price alert
  Expected to contain: "Above CN¥350.00"
  Received: "600519.SHActivePrice Above·Above 350×Created: 1970/1/1"

(fail) keeps a US price alert in USD
  Expected to contain: "Above $350.00"
  Received: "AAPL.USActivePrice Above·Above 350×Created: 1970/1/1"

注意第三条:连美股提醒也只显示 Above 350 —— 不是币种错了,而是币种信息整个丢了。

同时存在一个自相矛盾的孪生实现:packages/ui/src/atoms/alertAtoms.ts:97-99 的纯函数 ruleSummary() 走另一个极端,把 $ 硬编码进字符串:

(fail) ruleSummary > states the price threshold in the rule symbol currency
  Expected: "Above HK$100.00"
  Received: "Above $100.00"

同一个数据在两条渲染路径上得到两种都不正确的表示。

根因

两个原因,方向相反:

  1. 实时渲染路径(用户可见):packages/ui/src/components/alert/AlertCard.tsx:52-55 调用 formatCurrency(rule.targetPrice) —— 不传币种。而 packages/ui/src/i18n 的 formatCurrency 在 currency 为空时会退化成「分组后的裸数字 + 无代码」(packages/i18n/src/format.ts:64-82),于是渲染出 Above 350。文案本身是 above: 'Above {{price}}' / 高于 {{price}},币种只能由 {{price}} 承载,所以这里丢失后无法从别处补回来。
  2. 纯函数孪生体:ruleSummary() 用模板字符串拼 `Above $${...}`,违反 packages/i18n/src/format.ts 与 packages/ui/src/lib/money.ts 的「NEVER hardcode $」约定。(该函数目前仅被自身单测引用,但它是 AlertCard.summary() 注释中明确声明的「mirrors the atoms ruleSummary logic」孪生体,两者必须一致。)

AlertRule 本身没有 currency 字段,所以币种只能由 rule.symbol 的市场后缀推导 —— 这与行情展示层用的是同一条规则。

复现

新增 packages/ui/src/components/alert/AlertCard.test.tsx(happy-dom + TestI18n,直接渲染 AlertCard)并在 packages/ui/src/atoms/alertAtoms.test.ts 补充带 .HK / .SH 后缀的用例:

# 修复前
 10 pass / 4 fail

# 修复后
 14 pass / 0 fail

修复前的失败信息即问题本身(见上方原文)。

修复方案

两条路径统一改用 formatMoney(value, currencyForSymbol(rule.symbol))(packages/ui/src/lib/money.ts),即行情展示层同一个格式入口:

  • AlertCard.tsx:新增 alertPrice(rule) 辅助函数,price_above / price_below 分支共用;不再直接依赖 @finagent/i18n 的 formatCurrency。
  • alertAtoms.ts ruleSummary():同样改为 formatMoney(...),去掉硬编码 $。

不新增 i18n key、不改动任何文案;展示形态(en-US HK$100.00 / zh-CN HK$100.00、US$100.00)交给既有 locale 策略。

与 #259 的关系(前置改动)

本修复依赖 lib/money.ts 中的 currencyForSymbol(),该函数由 #259 引入(同一条约定:UI 包不能 import @finagent/shared,故把符号→币种映射镜像到渲染进程)。本 PR 的 lib/money.ts 改动与 #259 逐字节一致,两个 PR 可独立合并:先合并者生效,后合并者的该 hunk 自动变为空。

验证

TDD 顺序:先写测试 → 在未修复代码上确认失败 → 修复 → 全部通过。

文件 覆盖内容
components/alert/AlertCard.test.tsx 港股 HK$350.00 / A 股 CN¥350.00 / 美股 $350.00 三条
atoms/alertAtoms.test.ts(新增用例) ruleSummary 对 .HK、.SH 规则的输出;原有 US 用例保持不变(防过度修正)

回归对照:

命令 修复前 修复后
bun test packages/ui --isolate 332 pass / 0 fail 336 pass / 0 fail
bun test apps/electron --isolate 32 pass / 0 fail 32 pass / 0 fail
bun run typecheck 5/5 exit 0 5/5 exit 0

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

claimedClaimed by a contributor and currently in progress

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions