有数记账:现场编程团队项目总结
| 项目 | 内容 |
|---|---|
| 作业所属课程 | H202601 软件工程与软件工程实践 |
| 作业要求 | 现场编程 |
| 作业目标 | 开发一款可在本地运行的个人记账本,记录、查询和统计日常收入与支出,并通过 GitHub 分工协作完成多模块实现。 |
| 团队名称 | fzu-404-team |
| 团队成员学号-姓名 | 102401614-林志涛,102401512-任奥辉,102401509-吴瑞鹏,102401625-朱铮睿,102401635-尼玛顿珠,102401510-林富强,102401525-丁鑫河,102401526-林鹏远,102401511-何锦宏,102401519-曾林远见,102401623-杜佳伟,102401632-翁斌,102401633-严科儒 |
一、项目简介
「有数记账」是一款通过浏览器使用、由本机 Python 服务提供接口、以 JSON 文件保存账目的个人记账软件。用户可以新增、编辑、删除收入和支出,按日期、收支类型、类别、金额和备注组合筛选,查看汇总和支出分类图。项目还加入了 CSV 导出、月度预算、JSON 备份恢复、一句话记账和新版概览页面等功能。
本项目把金额保存为整数分,避免浮点数累计误差;账本默认位于项目目录的 data/ledger.json。应用只监听本机地址,适合本地个人使用和课堂演示,不提供公网或多人共享服务。
二、职责分工与 GitHub 协作
团队按功能模块划分开发工作,并安排文档、测试和演示协作。
| 学号 | 姓名 | 负责模块或协作任务 | 具体职责与交付内容 | 对应记录 |
|---|---|---|---|---|
| 102401614 | 林志涛 | 基础记账应用与模块集成 | 负责基础 Web 应用及账目操作流程;集成各模块接口,处理备份恢复整合和前端合并问题,与各模块负责人核对功能衔接。 | zhitaolin30-blip;初始提交;PR #17 |
| 102401512 | 任奥辉 | JSON 备份与恢复前端 | 提供备份下载、文件选择、恢复预览和确认界面;与集成人员核对恢复失败提示及账本替换流程。 | ren3717;PR #7 |
| 102401509 | 吴瑞鹏 | 博客统稿与材料组织 | 汇总功能说明、亮点和成员体验;向开发负责人核对代码说明与功能描述,整理开头信息、时间记录和博客结构。 | 博客统稿及修改记录 |
| 102401625 | 朱铮睿 | CSV 下载前端交互 | 实现导出按钮、下载进度、重复点击限制和错误提示;与何锦宏核对筛选参数、文件响应及空结果行为。 | Ruiii1124;PR #13 |
| 102401635 | 尼玛顿珠 | 月度预算前端 | 实现月份选择、设置预算、进度条及剩余额度显示;与严科儒核对未设置、正常使用和超支状态。 | kwndl108;PR #12 |
| 102401510 | 林富强 | 接口与运行文档协作 | 整理运行环境、启动命令、数据文件位置和接口字段;与前后端成员核对金额单位及统计范围,补充便于复现的使用说明。 | 运行说明与接口核对记录 |
| 102401525 | 丁鑫河 | 测试协作与问题整理 | 按功能清单检查新增、修改、删除、筛选、导出和恢复流程;记录输入、预期及实际结果,反馈问题并整理博客测试说明。 | 验收清单、问题记录与复查结果 |
| 102401526 | 林鹏远 | 截图、视频与演示协作 | 整理演示账本,准备新版 UI 截图和操作视频;组织演示步骤,检查素材与最终版本一致性及播放链接可访问性。 | 截图、录屏及演示流程 |
| 102401511 | 何锦宏 | CSV 导出后端 | 实现按已应用筛选导出全部匹配记录;处理中文表头、UTF-8 BOM、CSV 转义和备注公式前缀,配合前端核对下载结果。 | rohitpyarepur2006-coder;PR #10 |
| 102401519 | 曾林远见 | 连续月份收支统计 | 负责连续月份收支统计接口相关工作;与统计展示负责人核对月份顺序、跨年边界、金额单位及无记录月份的表示方式。 | xiaozenglin;PR #15 |
| 102401623 | 杜佳伟 | GitHub 协作与交付核查 | 整理成员、模块与 PR/commit 的对应关系;检查仓库、Release、博客及素材链接,汇总缺项并向对应负责人反馈。 | 协作记录汇总及交付检查表 |
| 102401632 | 翁斌 | 一句话记账、UI 及概览展示 | 实现本地短句解析与表单预填、暖橙主题和概览布局;整理相关测试及文档,与基础模块负责人核对页面元素和数据展示口径。 | 5-bin;PR #19、#20、#21、#23 |
| 102401633 | 严科儒 | 月度预算后端 | 实现月份和预算金额校验、预算本地保存、整月支出汇总及超支计算;与尼玛顿珠核对响应字段和边界状态。 | Clu3y;PR #11 |
三、运行环境与启动方式
- Python 3.10 或更新版本;开发验证记录使用 Python 3.13。
- 现代浏览器:Chrome、Edge、Firefox 或 Safari(需支持 HTML
dialog元素)。 - 前端使用原生 HTML、CSS 和 JavaScript,后端使用 Python 标准库,无需安装第三方运行依赖。
- 在项目目录运行:
python app.py --open
浏览器访问 http://127.0.0.1:8000。首次保存时会生成 data/ledger.json。如需课堂演示,建议用独立演示账本,避免录入或展示个人真实收支:
python app.py --data .qa/demo.json --port 8001 --open
运行测试:
python -m unittest discover -s tests -v
四、软件截图与演示视频
演示视频:点击观看《记账本演示》
五、关键代码
1. 金额精度与输入校验
ledger/models.py 使用 Decimal 解析金额,并转换为整数分。这样 0.10 和 0.20 相加时不会受到二进制浮点表示误差影响;同时拒绝负数、超出范围的金额及超过两位的小数。
def parse_amount(value, allow_zero=False):if isinstance(value, bool) or not isinstance(value, (str, int, float)):raise ValueError("请输入正确的金额")try:amount = Decimal(str(value).strip()) # 使用十进制解析,避免二进制浮点误差if not amount.is_finite() or amount < 0 or amount > Decimal(MAX_CENTS) / 100:raise ValueError("金额应在 0.01 至 9,999,999,999.99 元之间")cents = amount * 100 # 统一转换为整数分保存if cents != cents.to_integral_value():raise ValueError("金额最多保留两位小数")if cents == 0 and not allow_zero:raise ValueError("金额必须大于 0")return int(cents)except (InvalidOperation, OverflowError):raise ValueError("请输入正确的金额") from None
2. 组合筛选并统一汇总口径
ledger/service.py 的 LedgerService.query 将日期、金额、类型、类别和备注关键字条件应用到同一组记录,再从筛选结果计算收入、支出、结余和分类统计。因此明细与基础汇总使用同一数据范围。
selected = [r for r in self.records if(not start or r.date >= start) and (not end or r.date <= end)and (low is None or r.amount_cents >= low)and (high is None or r.amount_cents <= high)and (not kind or r.kind == kind)and (not category or r.category == category)and (not search or search in (r.note + " " + r.category).casefold())]income = sum(r.amount_cents for r in selected if r.kind == "income")
expense = sum(r.amount_cents for r in selected if r.kind == "expense")
return {"summary": {"income_cents": income, "expense_cents": expense,"balance_cents": income - expense, "count": len(selected)},# 分类统计也从同一筛选结果计算,保证汇总口径一致。"expense_categories": [{"category": name, "amount_cents": amount}for name, amount in sorted(by_category.items(),key=lambda item: (-item[1], item[0]))],
}
3. JSON 原子写入
ledger/storage.py 在写入前检查账本是否被外部修改,将新内容写到同目录临时文件并原子替换目标文件。成功后才更新内存中的文件快照;写入失败时保留原账本。
current = self.path.read_bytes() if self.path.exists() else None
if current != self._snapshot:raise StorageError("账本文件已被其他程序修改,请重启本程序后再操作")
raw = (json.dumps({"version": 1, "records": [r.to_dict() for r in records]},ensure_ascii=False, indent=2) + "\n").encode("utf-8")
_write_atomic(self.path, raw, ".ledger-")
self._snapshot = raw
以上为便于说明的节选,完整校验和异常处理请以仓库源码为准。
六、项目亮点
- 精确金额与可靠本地保存:金额以整数分存储;写入采用原子替换,并对损坏文件、外部修改和写入失败提供保护。
- 多条件查询与 CSV 导出:日期、类别、收支类型、金额范围和备注关键字可以组合筛选;CSV 导出全部匹配记录而非仅当前分页,包含中文表头,并对备注中的公式前缀进行处理。
- 便捷录入与数据保护:一句话解析会生成待确认草稿,不会在解析时直接写入账本;JSON 恢复前会校验文件、展示预览并保留恢复前账本。
以上功能可在演示视频里查看
七、编码与复审中的收获
以下事件依据项目测试和交付记录整理。总投入约 4 小时,各事件没有单独计时,表中耗时为回顾估算。
| 事件 | 问题与处理 | 收获 | 实际耗时(回顾估算) |
|---|---|---|---|
| CSV 导出范围与安全 | 导出需要覆盖全部筛选匹配记录,而非仅当前分页。接口与按钮应使用同一筛选条件,并检查中文编码、逗号/引号/换行转义和公式前缀处理。项目验证记录覆盖了多页导出、空结果及特殊备注。 | 下载功能除了生成文件,还要明确数据范围、表格软件兼容性和异常状态;前后端共同核对样例有助于避免“下载成功但内容不正确”。 | 约 45 分钟 |
| 备份恢复与账本保护 | 恢复前校验备份结构并展示预览,用户确认后才替换账目;替换前保留旧账本,并验证写入失败时磁盘和内存状态不被破坏。 | 文件恢复应覆盖校验、确认、保存与失败保护整个流程,不能只测试成功导入;界面提示与后端保护需要配合。 | 约 40 分钟 |
| 跨平台测试误报 | macOS 上临时目录 /var 会解析到 /private/var,导致直接比较路径字符串的测试出现平台差异;改为比较解析后的路径。 |
测试应比较实际资源及其语义,关注操作系统差异,避免把环境导致的路径变化误判为业务功能失败。 | 约 15 分钟 |
这三个事件的估算合计约 100 分钟,仅覆盖部分重点工作,其余投入用于需求分析、设计、其他模块编码、界面调整及交付材料整理。
八、团队编程体验
林志涛(102401614)
围绕基础记账应用和模块整合,我最关注的是各部分连接后能否形成完整的使用流程。记录、查询、统计和备份分别能够运行,还需要共同遵守数据格式与接口约定。我认为集成工作应尽早开展,后续希望把模块边界和验收条件写得更清楚,方便组员并行推进。
任奥辉(102401512)
备份恢复界面让我关注数据操作的确认流程。用户需要在恢复前看清记录数量、日期范围和替换范围,不能仅凭一个成功提示判断结果。我认为与后端协作时,除了明确成功返回的数据,还要约定校验失败时怎样提示,以及如何保护原账本。
吴瑞鹏(102401509)
在博客统稿这项任务中,我希望把成员提供的材料整理为连贯的项目说明,让功能介绍、代码节选、截图和提交记录相互对应。整理时需要向模块负责人核对信息,避免只列出功能名称。完成后,我也希望通过这份文档帮助读者理解团队的设计选择和协作过程。
朱铮睿(102401625)
CSV 下载交互需要把已应用的筛选条件准确传给接口,并清楚反馈下载状态。我最关注的是导出范围:用户应当得到全部匹配记录,而不是只得到当前页。前后端需要共同约定文件格式、错误提示和按钮状态,这也让我认识到交互细节属于功能完整性的一部分。
尼玛顿珠(102401635)
预算前端需要把月份、已用金额、剩余额度和超支状态组织成容易理解的信息。我认为界面设计不仅要展示数值,还应说明统计范围。与后端对接时,应先确认未设置预算、正常使用和超支等状态,减少界面显示与实际数据含义不一致的问题。
林富强(102401510)
在接口和运行文档整理中,我希望从首次使用者的角度检查说明是否充分。启动命令、端口、数据文件位置和接口字段都应能够直接核对。我认为文档应跟随代码更新,尤其需要区分筛选统计与整月统计,帮助开发人员和使用者理解同一组数据。
丁鑫河(102401525)
测试协作需要把“看起来能用”转化为可以重复检查的结果。我计划同时关注正常流程和边界情况,例如空结果、无效金额、下载失败及恢复取消。记录问题时,应保留明确的复现步骤,并分别记录自动化测试与浏览器操作结果,方便模块负责人定位问题。
林鹏远(102401526)
准备截图和录屏时,我希望通过简短的操作顺序展示完整流程,而不只是展示静态页面。演示数据需要容易核算,截图也应与最终界面保持一致。录制前应先走通新增、筛选、导出和备份等步骤,再检查画面清晰度以及视频链接是否能够正常访问。
何锦宏(102401511)
CSV 导出接口让我关注筛选结果、文件编码和表格兼容性之间的联系。导出需要与查询保持同一口径,同时处理中文、逗号、换行和公式前缀等内容。我认为先与前端负责人明确接口参数和响应约定,再用样例核对文件内容,可以减少对接时的理解偏差。
曾林远见(102401519)
月份统计需要明确月份顺序、跨年边界和无记录月份的处理方式。我最关注的是接口数据是否稳定、便于前端直接展示。与图表负责人协作时,应先约定返回结构和金额单位,再核对不同日期范围的汇总结果,避免统计与展示分别采用不同口径。
杜佳伟(102401623)
协作记录和交付核查需要把人员分工、代码提交与最终成果对应起来。我计划逐项检查 PR、commit、Release 和博客链接,并向成员确认缺失的信息。我认为交付材料应当反映真实工作,同时提供清晰的入口,让助教能够核对模块实现与成员贡献。
翁斌(102401632)
一句话记账和新版概览需要同时考虑录入效率、识别边界与展示口径。我认为识别结果应先让用户确认,再写入账本;界面图表也应明确采用全部账目还是筛选结果。后续希望继续完善异常输入提示,并在界面更新后检查资源加载和实际浏览器表现。
严科儒(102401633)
预算后端需要让月份校验、金额存储和支出汇总保持一致。我最关注的是预算与账目之间的关系:新增、修改或删除支出后,预算使用情况应准确反映变化。与前端协作时,应把字段含义和特殊状态约定清楚,并通过边界数据检查计算结果。
九、SP / PSP 时间记录
本次团队现场编程总耗时约 4 小时(240 分钟)。由于没有逐项计时,以下各阶段时间为根据任务内容整理的回顾估算,需结合成员实际投入核对,不作为精确计时记录。表中统计的是团队任务推进的时间分配,不是 13 位成员累计的人时;计划时间未单独记录,无法准确计算计划与实际的偏差。
| 阶段 | 计划时间(分钟) | 回顾估算时间(分钟) | 对应工作 |
|---|---|---|---|
| 需求理解与任务拆分 | 未单独记录 | 约 20 | 梳理基础记账、查询统计和附加功能,划分模块与协作任务。 |
| 设计接口与数据结构 | 未单独记录 | 约 25 | 确定账目字段、JSON 存储结构,以及前后端接口和筛选参数。 |
| 编码与模块集成 | 未单独记录 | 约 110 | 实现各功能模块、调整界面,通过分支和 PR 集成代码。 |
| 测试、复审与修复 | 未单独记录 | 约 55 | 检查金额精度、筛选结果、CSV 导出、备份恢复和页面资源加载,处理集成问题。 |
| 文档、演示与发布 | 未单独记录 | 约 30 | 整理运行说明、截图和演示材料,准备 Release 与博客。 |
| 合计 | 未单独记录 | 约 240(4 小时) | 各阶段分配为估算,实际工作可能交叉进行。 |
时间复盘:后续协作应从任务开始时分别记录计划与实际耗时,特别是模块集成、代码复审和问题修复的时间,便于区分编码投入与沟通成本,并改进下一次任务估算。
十、仓库、Release 与提交记录
- GitHub 仓库:fzu-404-team/account-book
- 已关闭 PR:Pull Requests
- 主分支提交记录:Commits
- Release:
demo(标题:有数记账 v1.0.0) - 测试命令:
python -m unittest discover -s tests。 - 最终测试结果:2026 年 11 月 7 日重新运行全部自动化测试,共 28 项,全部通过,输出为
Ran 28 tests和OK。 - 测试范围:金额精度与输入校验、账目增删改查及持久化、组合筛选与汇总、CSV 导出、备份恢复、一句话记账解析,以及 HTTP 接口和静态资源访问。
- 验证限制:上述结果为自动化测试结果,不代表所有浏览器和真实手机均已完成验证。
十一、贡献评分
按组长提供的贡献分配结果,各成员贡献系数如下。设小组最终得分为 S,则个人分数为 S × 贡献系数;其中 100% 表示获得与小组分数相同的个人分数,并非占全组贡献的 100%。
| 学号 | 姓名 | 贡献系数 | 个人分数计算 |
|---|---|---|---|
| 102401614 | 林志涛 | 110% | 1.10 × S |
| 102401633 | 严科儒 | 105% | 1.05 × S |
| 102401511 | 何锦宏 | 110% | 1.10 × S |
| 102401632 | 翁斌 | 110% | 1.10 × S |
| 102401625 | 朱铮睿 | 100% | 1.00 × S |
| 102401635 | 尼玛顿珠 | 100% | 1.00 × S |
| 102401519 | 曾林远见 | 100% | 1.00 × S |
| 102401509 | 吴瑞鹏 | 95% | 0.95 × S |
| 102401512 | 任奥辉 | 100% | 1.00 × S |
| 102401510 | 林富强 | 95% | 0.95 × S |
| 102401526 | 林鹏远 | 95% | 0.95 × S |
| 102401525 | 丁鑫河 | 90% | 0.90 × S |
| 102401623 | 杜佳伟 | 90% | 0.90 × S |
| 合计 | 13 人 | 1300% | 13 × S |
十二、工具使用说明
本项目使用 Git、GitHub 进行版本管理和协作,通过 Issue 拆分任务、Pull Request 复审与合并代码。开发过程中使用了 Codex 辅助工具,协助分析问题、检查代码和测试结果、排查页面资源加载故障、修改局域网访问配置,以及整理博客初稿、时间估算和个人体验草稿。项目部分代码包含辅助生成内容,具体范围由对应成员核实。