找回密码
立即注册
搜索
发回帖 发新帖

6138

积分

0

好友

778

主题
发表于 2 小时前 | 查看: 4| 回复: 0

最近跟朋友聊天,发现一些基金购买限额,需要“开超市”在多个基金 app 定投。每天想看总盈亏都要挨个切换 App;每月定投日回头看当月投入、累计年化,更费事。参考养基宝 app 的功能,借助 Claude Code,搭建了一个投资记录的纯前端工具 fund-tracker。

这篇文章讲 4 层架构和 5 个选型为什么这么选,再讲 AI 哪些地方写代码省心、哪些地方漏了要靠业务经验补。下一篇再展开工具能做什么、怎么用。

投资有风险,入市需谨慎。本文工具仅用于投资记录与收益计算,非投资平台,不提供交易功能。

一、整体架构:4 层分法

先说这 4 层分别是什么。打个比方:页面是装修工,状态是仓管,服务是加工产线,数据是货架。一句话概括——谁渲染、谁存状态、谁做事、谁落盘,全部单向调用。

  • 页面层:7 个页面(Dashboard / 基金 / 交易 / 定投 / 报表 / 设置 / 数据管理),AntD 组件 + ECharts 图表。
  • 状态层:1 个 Zustand store,18 个状态分片(持仓 / 交易 / NAV 历史 / 刷新队列 / 定投计划 / 设置)。
  • 服务层:东方财富 JSONP 拉取、NAV 增量合并、交易记账、XIRR / 收益日历计算。
  • 数据层:localStorage 落盘 + JSON 备份导入导出。

调用方向是:页面订阅 store,store 调用 service,service 读写 localStorage。以后如果要换 JSONP 数据源或加缓存,只需动对应层。

二、5 个核心选型

选型 1:无后端(纯前端)

为什么不用服务端?

  • 数据是用户级的,持仓、交易、NAV 全都属于个人隐私。
  • 数据量小:一年几百条交易,加上每只基金几百到几千条 NAV,实测只有 100-500 KB。
  • 浏览器一开通常就一个人用,没有并发压力。

如果引入服务端,反而要搭鉴权、同步、备份一整套流程。所以纯前端在这里是最自然的选择。

选型 2:Zustand 单 store(不是 Redux Toolkit)

项目里有 18 个状态分片,覆盖持仓、交易、NAV 历史、刷新队列、定投计划和设置。如果按 Redux Toolkit 的套路拆 slice,每个 slice 都要配一套 reducer + selector + action,心智成本不低。Zustand 把所有状态集中在 1 个 store,actions 写成方法挂上去,组件按需 useStore(s => s.x) 订阅,反而更清楚。

calculator.ts 走纯函数 + fixture 单测,不依赖 React 渲染。

选型 3:东方财富 JSONP(跨域唯一办法)

pingzhongdata 接口不支持 CORS,前端直接 fetch 会撞上跨域失败。浏览器同源策略挡在那里,可行的办法就是 JSONP 风格:用 <script> 注入加载 JS,脚本执行后再从 window 读 fS_name、Data_netWorthTrend 等 globals。

同时配了 15000ms 超时,以及三条出口(onload / onerror / timeout)来清理 globals,避免读到上一只基金的脏数据。落地细节在第四节展开。

选型 4:GitHub Pages(不是 Vercel / 自建)

零运维成本:HTTPS、CDN、自定义域名全部免费。零运行时:整个工具就是纯静态资源(HTML / JS / CSS / 字体),没有服务端运行时。子路径对齐:vite.config.ts 里把 base 设为 /fund-tracker/,跟 GitHub Pages 的默认子路径部署保持一致。部署流程也很直接:dist/ 走 Actions 推到 gh-pages 分支。

选型 5:localStorage(不是 IndexedDB)

5MB 配额足够装下几百条交易,以及每只基金的日级 NAV 历史。key-value 结构正好适配状态分片,按 store 命名空间拆开写,刷新页面后还能自动恢复。

版本号 version: 1 写在 payload 里,将来 schema 升级时,比如新增定投分组字段,可以识别老数据走迁移,兼容已有用户的备份。

5 个选型其实互相咬合成链:选型 1(无后端)是地基,它决定了选型 4(GitHub Pages 部署)、选型 5(localStorage 落盘)和选型 2(Zustand 单 store 集中管理);选型 3(JSONP)只解决第三方数据源没有 CORS 的问题,独立于这条链。

三、AI 辅助搭建:vibe coding 节奏

整个工具一共 119 次 commit,AI 协作占比约 65-70%,集中在架构骨架、重构和测试;人工微调约 30-35%,主要补业务判断和 bug 细节。

AI 写得最顺手的是有现成约定的代码,比如 Zustand store 设计、JSONP 封装。真正需要人工盯的是业务边界判断:QDII 美股节假日规则、T+N 自动确认的严格校验。

节奏分 V1 / V2 / V3 三段:

  • V1 跑通(3 天):AI 一次性把骨架出完,包括 7 个页面、store、API、utils。出代码快,但只是能过编译,边界没过,比如 QDII 净值延迟被写死成 T+1。
  • V2 加功能(1 周):补上 XIRR、收益日历、定投自动生成、刷新队列。
  • V3 优化(1 周):把“按基金类型推算发布日”换成 navPair(最新一对可用 NAV 配对)+ navFreshness(对照上次刷新判断 NAV 是否更新)的观测法。V1 / V2 的数据模型有结构性偏差,V3 基本重做。

四、1 个架构亮点:JSONP 三条出口清理

JSONP 落地时有 3 个非主线但必须处理的脏活。其中第 3 条 AI 默认会漏,后来靠人工跑测试、看执行时序才补上。

3 条都在 loadPingzhongScript 这一层:

  • ES Module 严格模式下 var 是 non-configurable(不可删除):delete window.fS_name(window 上的全局变量)会静默失败,所以要改用 = undefined 来清理,即保留键、把值抹掉。
  • <script> 标签带 referrerpolicy="no-referrer":否则 referer header(请求头里的来源 URL)会触发东方财富拦截。
  • 脚本注入之前先把旧的 25 个 globals 显式置 undefined:避免新一轮 <script> 还没执行完时,前一帧 globals 还留在 window 上,造成新旧数据交叉污染。

第 3 条 AI 默认忽略,是因为它默认按“onload 会清 globals”来假设。但 onload 是异步的,新旧 <script> 之间存在时序窗口,前一帧 globals 这时候还挂在 window 上。

小结

回头看这 5 个选型,其实是串成一条链的:选型 1 是地基,推出 4(GitHub Pages)、5(localStorage)、2(Zustand 单 store);选型 3(JSONP)只解决第三方数据源无 CORS,独立于这条链。AI 协作占比约 65-70%,剩下的业务边界靠人工补。

下一篇讲工具能做什么、怎么用。

工具链接

标签:#vibe coding #GitHub Pages #人人都是程序员




上一篇:个人投资记录工具 fund-tracker:跨平台记持仓、算 XIRR 年化、自动出周报月报
下一篇:ChatGPT 为什么会被骗?Prompt Injection 攻防与 6 层防线实测
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-6 22:59 , Processed in 0.071416 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表