软工第四次作业
软件工程第二次结对作业:校园失物招领核心程序
本文作者:薛锦荣(102401213)
一、从原型到核心程序
第一次作业我们围绕校园卡、钥匙、雨伞等常见物品设计了寻物与招领流程。第二次作业从“画出操作”推进到“操作确实会改变数据”:用户可以发布寻物或招领信息,集中浏览与搜索,查看物品详情和联系方式,并在找回或归还后维护信息状态。
本次范围遵循题目要求,优先完成发布、浏览、搜索、详情、联系、状态更新闭环。没有实现后台、实名、即时聊天和地图;也不声称静态页面已解决身份认证、跨设备同步或真实校园信息验证。首次打开的七条记录是演示数据。新发布的信息、收藏和状态保存在当前浏览器 localStorage,不会同步到别的设备。
对于需求验证,我们目前有题目描述、第一次作业的设计和本次流程走查,没有可核验的校园用户访谈记录。所以本文不把“几小时内找回”等效果作为结论。下一步可分别访谈丢过物品和捡到物品的同学,记录问题、样本数量及原话,经同意后再公开匿名摘要。
二、功能和数据设计
核心条目包含编号、物品名称、类型、分类、地点、发生时间、描述、联系方式、发布者、发布状态和发布时间。寻物状态从“寻找中”转为“已找到”;招领状态从“待认领”转为“已归还”。类型决定表单中的地点语义,必填信息缺失时阻止发布并给出提示。
| 操作 | 页面入口 | 结果 |
|---|---|---|
| 浏览与类型筛选 | 首页“全部/寻物/招领” | 列表和状态标签更新 |
| 发布信息 | 首页“+”或底栏“发布” | 必填校验、成功提示、加入首页和“我的发布” |
| 搜索与筛选 | 首页搜索框 | 按名称、分类、地点、描述、发布者搜索,支持类型及最近三天筛选 |
| 查看详情与联系 | 信息卡片 | 展示地点、时间、描述及联系方式;联系按钮复制或显示联系方式 |
| 结束信息 | “我的 → 我的发布” | 发布者标记完成,状态同步到首页、搜索和详情 |
| 收藏 | 详情页 | 收藏条目在“我的收藏”中可见 |
数据流
发布与状态维护流程
三、实现结构与有价值的代码
仓库使用原生 HTML/CSS/JavaScript,没有构建步骤和第三方前端框架。页面负责交互及展示,js/lost-found.js 集中处理数据逻辑,使表单校验、搜索、状态与存储可以脱离 DOM 测试。
发布成功不能早于持久化:先校验并构造条目,尝试保存,再把条目加入当前页面状态。存储失败会停止成功流程并提示用户。
const errors = LostFound.validateItem(input);
if (errors.length) {
toast(errors[0]);
return;
}
const result = LostFound.createItem(ITEMS, input);
const nextItems = ITEMS.concat(result.item);
if (!persistState(nextItems, favorites)) return;
ITEMS.push(result.item);
同一状态函数根据寻物/招领类型生成准确状态,并阻止重复标记:
function resolveItem(item) {
if (!item || item.status === 'done') return false;
item.status = 'done';
item.state = item.type === 'lost' ? '已找到' : '已归还';
return true;
}
另一个重要细节是对用户输入进行 HTML 转义后再渲染卡片;详情字段使用 textContent 展示。界面也明确说明图片上传、后端和账号能力未实现,避免把占位控件误认为已经支持的功能。
四、单元测试
使用 Node.js 自带的 node:test 和 node:assert/strict,不需要安装 npm 包。在提交版根目录执行:
node --test 单元测试/lost-found.test.js
当前有 19 个测试用例,包括白盒分支和边界数据:
| # | 测试场景 | 目的 |
|---|---|---|
| 1 | 空表单 | 检查名称、地点、时间、联系方式四项提示 |
| 2 | 空对象/非对象 | 输入不是信息对象时拒绝处理 |
| 3 | 非法类型 | 只接受 lost 或 found |
| 4 | 字段两端空格 | 建立前清理用户输入 |
| 5 | 编号递增 | 处理非连续编号后仍得到唯一编号 |
| 6 | 寻物默认状态 | 新信息进入寻找中 |
| 7 | 招领默认状态 | 新信息进入待认领 |
| 8 | 可选描述为空 | 使用清晰默认描述 |
| 9 | 关键词大小写 | 英文关键词不区分大小写 |
| 10 | 描述命中 | 不只搜索物品名称 |
| 11 | 类型筛选 | 只返回寻物或招领目标类型 |
| 12 | 时间筛选 | 限制时间与不限时间两种情况 |
| 13 | 跨日动态时间边界 | 旧信息不会永久算成“最近” |
| 14 | 寻物状态修改 | 显示已找到且重复操作无副作用 |
| 15 | 招领状态修改 | 显示已归还 |
| 16 | 不存在的条目 | 不崩溃、不虚构更新成功 |
| 17 | 正常存储往返 | 发布数据与收藏恢复一致 |
| 18 | 损坏 JSON | 报错并保留示例数据 |
| 19 | 重复编号/无效收藏 | 拒绝不一致的持久化数据 |
学习方法是先选单一函数和可观察输出,再为正常、边界、错误输入分别写 test;运行 node --test,根据失败用例名称及断言差异定位。自动单元测试覆盖核心逻辑,但不能替代 Chrome 手工走查。我们对页面实际走查的路径为发布(含空表单提示)→搜索→详情→联系→标记状态→刷新检查本地恢复;提交前还需在实际 GitHub 下载版中复验一次。
五、附加的人性化设计
- 联系信息一键复制:减少用户手动选择号码/微信号的步骤;剪贴板不可用时直接显示联系方式,不让按钮静默失效。
- 本地持久化和异常提示:刷新保留发布、收藏和状态;保存失败或损坏数据可见提示,避免显示“发布成功”却没有保存。
- 搜索字段更完整:除物品名称外也查分类、地点、描述及发布者,减少只知道地点或物品特征时的查找成本。
以上是功能设计,不代表已经通过用户实验验证其能缩短找回时间。我们没有实名认证或跨浏览器同步,故“我的发布”只表示本浏览器中的本地记录。
六、目录说明和运行方法
GitHub仓库文件/ # 将此文件夹里的内容复制到 GitHub 仓库根目录
├── index.html # GitHub Pages 入口
├── 程序/
│ └── index.html # 主页面与交互
├── js/lost-found.js # 纯逻辑模块
├── 单元测试/ # node:test 测试
├── 项目文档/ # 设计、PSP与第一次作业参考
└── README.md # 运行和测试说明
程序文件/ # 同一程序的独立备份,便于在本机查看
博客文档/ # 总稿、吴怡霏稿、薛锦荣稿
作业资料/ # PSP记录、第一次作业与开发过程资料
建议使用 Chrome 打开 GitHub仓库文件/index.html;入口会跳至程序页面。若浏览器限制本地存储,可在 GitHub仓库文件 内运行 python -m http.server 8000,再访问 http://localhost:8000/。Node.js 测试与 Chrome 网页运行互相独立。
七、结对分工、困难与协作
本次按前后阶段衔接分工。分工表区分“已完成”和“待完成”,不把未出现于 GitHub 记录的工作写成既成事实:
| 阶段 | 负责人 | 具体任务 | 当前状态与可核验证据 |
|---|---|---|---|
| 前半段:基础实现与自动化验证 | 薛锦荣(102401213) | 根据第一次作业流程实现网页核心功能、业务逻辑模块、单元测试和项目使用/开发说明;按功能提交代码 | 已完成。现有核心功能、测试和文档提交可在仓库核对,提交账号为薛锦荣 |
| 后半段:浏览器走查与协作闭环 | 吴怡霏(102401206) | 接手现有版本,用 Chrome 独立走查发布、搜索、详情、联系、状态更新和刷新恢复;记录实际结果;若发现问题,提交有依据的修复/回归测试及相关说明,并通过 Fork/PR 协作 | 待吴怡霏本人完成。目前没有她账号的功能提交、PR 或 Review 记录;交接包提供走查记录模板,不等同于已完成测试 |
| 复审与交付 | 两人共同 | 吴怡霏发起 PR 后,由薛锦荣核对差异、测试结果并留下真实 Review;双方核对博客及最终提交材料 | 待实际 PR 发生后完成;不得将计划或模板当成协作证据 |
本次开发遇到的重点问题和处理方式:
| 问题 | 尝试与处理 | 结果/收获 |
|---|---|---|
| 旧原型只在内存中改数据,刷新即丢 | 统一以浏览器本地存储保存信息和收藏;加载时校验数据结构 | 当前浏览器能恢复,明确记录这不是云端同步 |
| 空字段也可能被拼成一条“成功”信息 | 把必填验证与纯逻辑模块分离,验证不通过就阻止发布 | 缺失信息有明确提示 |
| 状态在列表和详情容易不一致 | 用统一状态规则,更新后刷新相关列表和详情数据 | 寻物与招领显示各自正确的完成词 |
| 最近三天筛选容易依赖写死的天数样例 | 根据创建时间动态计算并加入跨日边界测试 | 新发布条目不会永远被视为最新 |
| 浏览器本地数据格式可能损坏 | 对 JSON、编号及收藏引用进行结构检查 | 异常时提示并回退演示数据 |
这些问题的核心逻辑有自动化测试覆盖;Chrome 页面端到端走查仍需吴怡霏按上述分工实际完成并记录。不要把自动化测试等同于人工页面走查。
八、PSP 时间记录
下表预估为开发计划值;实际值按薛锦荣提供的阶段记录填写。实际时间合计为 330 分钟,比预估少 95 分钟。该表记录本次项目各阶段时间,未拆分到每位成员个人;发布前两位同学应确认这些数值对应真实记录,并结合实际过程解释阶段差异,不应将其误读为两人的分别工时。
| 阶段 | 预估(分钟) | 实际(分钟) |
|---|---|---|
| 计划与范围确认 | 20 | 15 |
| 需求分析与边界 | 25 | 15 |
| 设计与数据结构 | 35 | 20 |
| 代码规范与实现方案 | 15 | 10 |
| 核心逻辑与持久化 | 100 | 100 |
| 页面交互与适配 | 100 | 90 |
| 复审与联调 | 35 | 20 |
| 测试与缺陷修复 | 50 | 40 |
| 报告与总结 | 45 | 20 |
| 合计 | 425 | 330 |
九、提交证据与展示图片
GitHub 功能提交记录
本次按“应用闭环、单元测试、文档整理”拆分为三次独立提交,提交前先运行相应测试;提交说明采用 feat、test、docs 前缀,便于从历史判断改动目的:
| Commit | 内容 |
|---|---|
| 9a68d36 | feat: 实现失物招领核心流程 |
| 416c861 | test: 添加核心流程单元测试 |
| 7aa5f01 | docs: 补充项目说明并整理目录 |
- 【GitHub 仓库首页:显示目录和 README】
![屏幕截图 2026-10-09 203650]()
- 【真实 commit 历史截图:能看到合理的功能提交信息】
![屏幕截图 2026-10-09 204617]()
- 【Chrome 首页、发布表单、搜索结果、详情、成功提示、我的发布/状态更新截图】
![屏幕截图 2026-10-09 204819]()

4. 【实际 PR / Review 截图】

十、我的总结与队友评价
薛锦荣(102401213)个人总结
这次实现让我体会到,原型阶段看似简单的“发布一条信息”,落实到程序后还要处理必填校验、状态初值、数据保存失败和刷新恢复等情况。把数据逻辑抽离到不依赖 DOM 的模块后,创建、搜索、状态变更和本地存储能够单独测试;页面层则负责把成功、错误和无结果状态反馈给用户。这样的拆分让问题更容易定位,也让测试不必依赖浏览器页面结构。
19 个单元测试覆盖了正常输入、非法输入、动态时间筛选、重复状态操作和损坏存储等情况,但测试通过并不等于真实用户流程已经全部验证。Chrome 走查仍需检查发布、搜索、详情、联系、结束信息以及刷新恢复,并留存真实截图。另一个明确限制是没有账号和服务端,所谓“我的发布”只是当前浏览器中的本地条目;这一边界需要在使用说明中讲清楚。
回看过程,PSP 的实际值、队友参与证据和用户反馈不能从最终代码倒推。下一次我会先拆分并确认两人任务,再边做边记录时间;每完成一个可复核的功能就提交,并尽早邀请队友通过 PR 检查,而不是等所有内容完成后才补协作过程。当前表格的 330 分钟是项目阶段合计,并未按两位成员拆分。
- 我认为吴怡霏值得学习的地方:从共同作业目标来看,需求边界和交付说明需要与程序实现保持一致;她对作业材料及目录、说明内容的关注提醒我,代码之外的可运行指引同样关系到助教能否复现项目。
- 我建议吴怡霏改进的地方:后续可以更早认领一个边界清楚的代码、测试或文档任务,并通过自己的分支提交 PR;同时在提交前附上运行步骤和验证结果,让队友能及时复核并共同维护交付质量。
吴怡霏(102401206)对薛锦荣的评价
- 值得学习的地方:从现有项目产出来看,核心页面、独立业务逻辑模块和自动化测试形成了可以运行和检查的基础;把“状态更新后多处显示一致”作为业务流程的一部分,而不是只完成按钮交互,这一点值得学习。
- 需要改进的地方:后续协作时可以更早把可独立完成的任务、接口约定和检查点同步给我,并在开发过程中安排实际 PR/Review;这样可以让双方贡献和反馈都在仓库中留下可核验记录。
这次作业让我们从交互原型进一步看到实现层面的细节:数据校验、状态一致性、边界输入和刷新恢复都需要在代码与测试中真正落地。



浙公网安备 33010602011771号