From efc2c7c7349c84712912e179aa9bcbe0f74000ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=85=9C?= <1871263099@qq.com> Date: Sat, 3 Oct 2026 22:57:19 +0800 Subject: [PATCH] fix: refresh metal valuation after automatic quotes complete --- apps/web/src/MetalPanel.tsx | 14 ++++++++++++-- docs/mcp-coverage.md | 4 +++- docs/mcp.md | 2 +- docs/update-metal-grams-2026-10-03.md | 5 ++++- update.md | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/web/src/MetalPanel.tsx b/apps/web/src/MetalPanel.tsx index 3e70fb3..1d9f15c 100644 --- a/apps/web/src/MetalPanel.tsx +++ b/apps/web/src/MetalPanel.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { api, money, type Position, currencies } from './api'; import { t as tr } from './i18n'; import { useToast } from './Toast'; @@ -11,6 +11,8 @@ export function MetalPanel({ position?: Position; refresh: () => Promise; }) { + const refreshRef = useRef(refresh); + refreshRef.current = refresh; const [data, setData] = useState(), [busy, setBusy] = useState(false), [error, setError] = useState(''), @@ -39,7 +41,15 @@ export function MetalPanel({ const timer = setInterval(() => { void api('/metals') .then((v) => { - if (active) setData(v); + if (active) { + setData(v); + if (v.status.state !== 'updating') { + clearInterval(timer); + void refreshRef.current().catch((e) => { + if (active) setError(e.message); + }); + } + } }) .catch((e) => { if (active) { diff --git a/docs/mcp-coverage.md b/docs/mcp-coverage.md index e865133..df485ce 100644 --- a/docs/mcp-coverage.md +++ b/docs/mcp-coverage.md @@ -4,6 +4,8 @@ 验证记号:**M** `test/mcp.test.ts` 第一组真实官方 SDK/MySQL;**C** 第二组并发/图标/密码修改;**O** 第三组 OAuth;**R** 18 组真实 REST/MySQL 回归;**U** 原单元计算/行情/ZIP 测试。均有实际业务断言。M 中公共刷新验证无需要更新资产时的真实调用;外部行情响应和失败回退由 U 验证,未声称行情供应商稳定可用。 +**B**:2026-10-03 22:55(UTC+8)真实浏览器验证黄金/白银创建、可选买入价与盈亏、清空成本、估值历史及报价完成后自动同步,临时用户已清理。 + 普通写入需要 draft 或 write,且受用户 readonly/draft/direct 策略约束;敏感操作额外要求 sensitive 并强制网页确认。所有写入工具要求幂等键和 expectedState。每项都先检查可信用户归属;annotations 不替代权限。 | 现有页面/API 与功能 | MCP 操作路径 | 权限 | 确认方式 | 验证 | @@ -11,7 +13,7 @@ | 账户/独立资产/债务列表 GET positions | positions_list:kind、名称、归档、方向、币种、分组、排序、offset/limit | read | 无 | M:查询、重名、分页和外用户隔离 | | 项目详情 GET positions/:id | position_get | read | 隐藏项目须连接独立网页解锁 | M:当前余额、隐藏/外用户拒绝 | | 创建项目 POST positions | position_create,保留账户/资产/债务初始绝对余额语义 | draft/write | 策略决定草稿或直接 | M/C:3 类对象、重复调用、无效金额、并发 | -| 按克数创建贵金属 POST metals/holdings | metal_holding_create | draft/write | 策略 | M/R/U:无报价待估值、现有报价估值、可选成本盈亏、旧备份 | +| 按克数创建贵金属 POST metals/holdings | metal_holding_create | draft/write | 策略 | M/R/U/B:待估值、报价、成本盈亏、旧备份 | | 元数据、分类、分组、图标、归档/恢复、隐藏、计入开关 PATCH positions/:id | position_update,完整 metadata;币种与方向固定 | draft/write | 策略 | M:分组、归档禁止金额更新与恢复;R:隐藏和开关 | | 分组拖拽排序 PATCH settings | settings_update.accountGroupOrder | draft/write | 策略 | M/R:持久化、排序、备份 | | 类别选项、名称与分组配置 | position_create/update;positions_list 读取现有值,Schema/描述提供规则 | read + draft/write | 策略 | M/R;当前没有独立分类/分组实体 CRUD | diff --git a/docs/mcp.md b/docs/mcp.md index 0d76071..7a8478b 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -136,6 +136,6 @@ location /api/ { 主要修改:原 8 个业务模块及 auth 抽取 BusinessService;database 增加事务上下文;新增 `src/mcp/{oauth,catalogue,operations,files,management,transport}.ts`;设置页新增 AgentConnections;SDK 精确版本和 pnpm lock;新增真实 MCP 测试及只读 probe。 -实际通过:前后端 typecheck/build、36 项单元检查、18 组真实 REST/MySQL 回归、3 组真实官方 MCP SDK 端到端检查,工具发现验证 49 个工具(原 mcp:probe 的 48 个工具上增加 metal_holding_create)。新迁移 deploy 成功,实际 MySQL 17 张表(含 Prisma 迁移表)、159 个字段注释完整。测试真实连接 MySQL,使用随机临时用户并清理,未替代现有 REST 回归。端到端文件传输、事务回滚、归属、金额精度、幂等、并发、失效/撤销和 OAuth 均在测试中检查;外部行情源的正常和失败路径由原业务单元测试验证,不保证外部报价服务实时可用。 +实际通过:前后端 typecheck/build、36 项单元检查、18 组真实 REST/MySQL 回归、3 组真实官方 MCP SDK 端到端检查,工具发现验证 49 个工具(原 mcp:probe 的 48 个工具上增加 metal_holding_create)。新迁移 deploy 成功,实际 MySQL 17 张表(含 Prisma 迁移表)、159 个字段注释完整。测试真实连接 MySQL,使用随机临时用户并清理,未替代现有 REST 回归。贵金属创建、待估值、买入成本、盈亏及报价完成后的页面自动同步已通过真实浏览器验证,测试用户已清理。端到端文件传输、事务回滚、归属、金额精度、幂等、并发、失效/撤销和 OAuth 均在测试中检查;外部行情源的正常和失败路径由原业务单元测试验证,不保证外部报价服务实时可用。 部署未执行;未推送代码;其他客户端及实际 HTTPS/代理兼容性尚未验证。 diff --git a/docs/update-metal-grams-2026-10-03.md b/docs/update-metal-grams-2026-10-03.md index 4c29b3d..09113bc 100644 --- a/docs/update-metal-grams-2026-10-03.md +++ b/docs/update-metal-grams-2026-10-03.md @@ -24,6 +24,9 @@ ZIP v8 增加可选成本字段,既有备份缺少字段仍可验证恢复; - 36 项单元测试通过:待估值完整性、精确克数成本、行情/失败回退、原计算和 ZIP 等。 - 18 组真实 REST/MySQL 测试通过:无价格克数创建、拥有报价创建、精确盈亏、成本保留/清除、外用户拒绝、无效克数拒绝、新备份恢复和旧备份兼容,以及原业务回归。 - 3 组官方 SDK/MySQL MCP 测试通过:包含新增克数工具真实写入和查询;原 OAuth、确认、幂等、并发与失败回滚继续通过。 -- 登录后的新增弹窗尚未通过浏览器人工端到端验证:自动审批拒绝临时测试账号登录,等待用户授权。已有 MCP 管理页在前一阶段已浏览器验证。无其他商业 Agent 客户端或生产代理部署验证。 +- 2026-10-03 22:55(UTC+8)用户授权后,使用临时本地账号完成真实浏览器验证:黄金/白银按克数创建;不填市场价格或买入价也能保存;初始待估值;保存/清空买入成本;现有估值历史显示;报价自动更新后的详情同步。2.5 克 × 纯度 0.8 × 测试报价 20 = 40 CNY;每克买入价 12.8 得成本 32 CNY、盈亏 8 CNY。 +- 浏览器发现并修复报价已完成但父页面金额仍待估值的问题:MetalPanel 轮询离开 updating 状态时刷新持仓和历史,回调使用 ref 保持当前引用。真实白银报价完成后,无需点击刷新即可显示估值、成本、盈亏与历史。 +- 修复后前端 typecheck 和生产 build 再次通过。另通过 Prisma 检查浏览器写入持久化结果,并清理临时用户、两个测试持仓、报价和登录会话。截图保存在独立验证目录,没有写入 docs。 +- 已有 MCP 管理页在前一阶段已浏览器验证。其他商业 Agent 客户端和生产代理部署仍未验证。 本次不部署、不推送、不改本地 .env,也不把图片保存进 docs。 diff --git a/update.md b/update.md index 1bf9234..82473f3 100644 --- a/update.md +++ b/update.md @@ -52,7 +52,7 @@ - ~~转账转入转出对账号选择没有要求,信用卡等也可以转账~~ — 已完成并验证:2026-10-03 18:56 - ~~设置中可以设置独立资产是否计入资产,每一个资产、账号、债务都可以设置是否计入资产~~ — 已完成并验证:2026-10-03 18:56 - ~~独立资产中贵金属支持估价,更新方式和汇率一致~~ — 已完成并验证:2026-10-03 18:56 -- ~~贵金属为克数,不用设置价格,可以设置买入价格(当设置了之后会显示盈亏)~~ — 已完成并通过真实 REST/MCP 测试:2026-10-03 22:40(UTC+8);浏览器登录验证待授权,见 docs/update-metal-grams-2026-10-03.md +- ~~贵金属为克数,不用设置价格,可以设置买入价格(当设置了之后会显示盈亏)~~ — 已完成并通过真实 REST/MCP 测试:2026-10-03 22:40(UTC+8);浏览器补充验证与自动估价同步修复完成:2026-10-03 22:55(UTC+8),见 docs/update-metal-grams-2026-10-03.md - ~~所有MySQL数据表要补充注释~~ — 已完成并验证:2026-10-03 22:40(UTC+8),17 张表、159 个字段,包括 Prisma 迁移表。 验证与部署边界见 [更新说明](docs/update-2026-10-02.md)。