V1: 从零开始 —— 「老板说做个记账工具」
你刚入职一家20人的创业公司,老板说公司报销全靠Excel,经常对不上账,让你做个简单的记账系统,先自己用着试试。
当前状态: 什么都没有,从零开始。 目标: 做一个个人记账工具,能增删改查费用记录,有个仪表盘看月度总额和分类汇总。 约束: 只有你一个人用,不需要服务器,打开 HTML 文件就能用。
问题分析(5层框架)
Section titled “问题分析(5层框架)”| 层级 | 问题 | 思考 |
|---|---|---|
| Why | 为什么要做这个? | Excel无法追踪变更历史,数据不结构化无法做统计 |
| What | 做什么? | 费用CRUD + 月度统计仪表盘 |
| How (架构) | 怎么组织? | 纯前端,localStorage存数据,不需要后端 |
| How (实现) | 具体怎么写? | 单HTML文件 + JS + CSS,数据存浏览器本地 |
| How (部署) | 怎么跑起来? | 直接双击打开HTML文件,零安装零配置 |
为什么不直接用后端? 现在只有你一个人用,不需要共享数据。localStorage完全够用。等团队其他人也要用了,再考虑加后端——那是V2的事。
graph LR subgraph 浏览器 HTML["HTML + JS + CSS"] --> LS["localStorage<br/>(数据)"] end
style 浏览器 fill:#e8f4f8,stroke:#333没有服务器,没有数据库,数据就在浏览器里。 双击 HTML 文件就能用。
// 数据直接存在浏览器的 localStorageconst expenses = JSON.parse(localStorage.getItem('expenses') || '[]')
// 每条记录的结构{ id: Date.now(), // 用时间戳做唯一ID,够用了 amount: 1050, // 单位:分,避免浮点精度问题(10.50元 = 1050分) category: '餐饮', // 餐饮/交通/办公/团建/其他 date: '2024-01-15', // 字符串格式 note: '团队午餐'}| 功能 | 实现方式 |
|---|---|
| 新增费用 | 表单提交 → 存入 localStorage |
| 查看列表 | 读取 localStorage → 渲染表格 |
| 按月筛选 | JS 过滤数组 |
| 编辑费用 | 表单回填 → 更新 localStorage |
| 删除费用 | 过滤数组 → 重新存入 |
| 月度汇总 | JS 计算 → 展示总额和分类统计 |
| 决策点 | 选项A | 选项B | 选择 | 理由 |
|---|---|---|---|---|
| 金额存储 | float(元) | int(分) | int(分) | 避免浮点精度问题,0.1+0.2≠0.3 |
| 存储方案 | localStorage | indexedDB | localStorage | 数据量小,JSON够用 |
| 框架 | React/Vue | 原生JS | 原生JS | 单文件工具,不需要构建环境 |
| 样式 | 自己写CSS | CDN引入Tailwind | CDN Tailwind | 零安装,直接用 |
给AI的Prompt
Section titled “给AI的Prompt”帮我做一个单文件的个人记账工具,就一个 HTML 文件,打开就能用,不需要服务器。
## 需求1. 费用CRUD:新增、列表、编辑、删除2. 按月筛选,默认显示本月3. 仪表盘:当月总支出、按分类(餐饮/交通/办公/团建/其他)的汇总金额4. 数据用 localStorage 存储,刷新不丢失
## 数据结构(存到 localStorage 的 JSON)每条记录:- id: 时间戳- amount: 整数,单位是分(10元 = 1000分)- category: 字符串,枚举:餐饮/交通/办公/团建/其他- date: 字符串,格式 2024-01-15- note: 字符串,备注
## 技术要求- 单个 HTML 文件,不需要构建工具- 用 CDN 引入 Tailwind CSS(直接加 script 标签)- 金额显示用元(/100),存储用分(*100),避免浮点问题- 金额输入框允许小数点两位(如 10.50 元)
## UI 要求- 顶部:月份选择器 + 总支出显示- 分类汇总:各分类金额列表- 费用列表:日期、分类、金额、备注、编辑/删除按钮- 新增/编辑:一个表单,填完点保存
请直接输出完整的 HTML 文件。- 双击 HTML 文件能在浏览器打开,不报错
- 新增一条费用,刷新页面后数据还在
- 金额显示正确(输入 10.50,显示 ¥10.50)
- 按月筛选后只显示当月记录
- 月度总额计算正确(手动验算)
- 编辑费用后数据正确更新
- 删除费用后从列表消失
- 分类汇总金额与列表明细之和一致
你学到了什么
Section titled “你学到了什么”| 知识点 | 对应模块 |
|---|---|
| localStorage:浏览器本地存储的工作原理 | → Module 2(数据存储) |
| JSON序列化/反序列化:数据如何在内存和字符串之间转换 | → Module 2(数据存储) |
| 整数存储金额:为什么0.1+0.2≠0.3 | → Module 2(数据模型) |
| 前端CRUD:DOM操作和事件处理的基础模式 | → Module 1(API设计) |
1. 金额精度丢失
Section titled “1. 金额精度丢失”// 错误:用浮点数存金额{ amount: 10.50 } // 10.5 * 3 = 31.500000000000004
// 正确:用整数存分{ amount: 1050 } // 1050 * 3 = 3150(分)
// 输入时转换(元 → 分)const cents = Math.round(parseFloat(input.value) * 100)
// 显示时转换(分 → 元)const yuan = (cents / 100).toFixed(2) // "10.50"2. localStorage 存储上限
Section titled “2. localStorage 存储上限”localStorage 上限约 5MB,存文本数据一条记录大概 200 字节5MB / 200B = 约 25000 条记录
个人记账每天最多几十条,几年也不会满如果数据多了,V2 再考虑后端存储3. 刷新后数据消失
Section titled “3. 刷新后数据消失”// 错误:忘了从 localStorage 读取,每次页面加载都用空数组let expenses = []
// 正确:页面加载时从 localStorage 初始化let expenses = JSON.parse(localStorage.getItem('expenses') || '[]')4. 多标签页数据不同步
Section titled “4. 多标签页数据不同步”localStorage 数据只在同一浏览器的同一域下共享如果你在两个标签页同时打开同一 HTML 文件(file:// 协议),改一个标签页,另一个不会自动更新
暂时无解——这就是 V1 的限制。等 V2 加了后端,所有人都从服务器读数据,就解决了。V1 的局限,以及为什么 V2 需要后端
Section titled “V1 的局限,以及为什么 V2 需要后端”V1 用 localStorage 有一个根本限制:数据只在你自己的电脑上。
- 换台电脑就没数据了
- 同事无法看到你的记录
- 老板要查账,你得把 HTML 文件发给他
当老板说「给团队10个人也用上」,你就会发现 localStorage 不够用了——那时候才真正需要引入后端。
这就是 V2 要解决的问题。