2026秋软件工程结对作业(二)

2026秋软件工程结对作业(二):校园失物招领 WEB 程序实现
一、具体分工

成员 负责模块 具体工作
崔佳静102402155 数据与发布 js/data.js 数据持久层、publish 发布页面、单元测试脚本、PSP 记录与博客撰写
王昊102402156 展示与交互 index 首页与搜索、detail 详情与状态修改、css 样式、README 编写、GitHub 仓库与 fork、签入记录与截图
二、PSP 表格

以下"实际耗时"为我们真实记录,含返工与排查时间,与预估并不一致,便于复盘低估环节。
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
| --- | --- | --- | --- |
| 计划 | 需求分析与范围把控 | 30 | 40 |
| 计划 | 生成设计文档(流程/数据结构设计) | 40 | 35 |
| 设计 | 代码规范与目录结构设计 | 15 | 10 |
| 开发 | 数据层 data.js 与 localStorage 封装 | 40 | 60 |
| 开发 | 发布页面 publish 表单与校验 | 50 | 70 |
| 开发 | 首页 index 列表与关键词搜索 | 40 | 55 |
| 开发 | 详情页 detail 与状态更新 | 40 | 65 |
| 测试 | 单元测试编写与执行 | 50 | 45 |
| 报告 | 博客撰写、README、截图整理 | 60 | 80 |
| 合计 | — | 365 | 460 |

复盘:发布表单校验与"状态修改后首页同步刷新"两个环节实际耗时明显超出预估,原因分别是空输入提示的边界处理和 URL 传参取值问题,属于低估项,后续可据此改进时间分配。

三、解题思路描述与设计实现说明

  1. 需求分析与范围把控
    针对老师上次指出的"功能铺得过开、缺用户反馈、流程交代不清"的问题,我们这次做了三件事:
    (1)严格圈定核心功能。本次只实现作业要求的六项核心流程:发布寻物、发布招领、集中浏览、关键词搜索、查看详情与联系方式、发布者更新状态。明确不做复杂后台、实名认证、即时聊天、地图定位,页面里也不再出现"收藏、浏览记录、站内消息"等冗余模块。
    (2)补一次真实的用户反馈
    。我们访谈了两位丢过东西的同学和一位捡到物品的同学:
    丢校园卡的同学:最难的不是发布,而是"不知道去哪查",群聊消息第二天就被刷没了;
    丢钥匙的同学:希望搜索时直接按物品名称找,别翻几十条;
    捡到东西的同学:最想让人知道"东西在哪领、怎么联系失主",但不想留太多个人信息。

据此确认了核心诉求:集中可见 + 关键词可搜 + 有联系方式 + 物品状态能闭环。
(3)把状态流程讲清楚。针对上次"联系之后如何结束这条信息没交代",我们明确了完整链路:发布者点进自己发布的详情 → 点击"已找到/已归还" → 状态写回本地存储 → 首页对应卡片同步更新状态标签,所有人能看到这条信息已经处理完,减少重复联系。

  1. 代码实现思路
    技术选型:纯前端 HTML + CSS + JavaScript,数据用浏览器 localStorage 持久化,无需后端和数据库。理由是满足"谷歌浏览器打开 html 即可运行"的作业要求,也方便其他同学下载复现。
    核心流程:
  2. 用户打开 index.html,从 localStorage 读取全部物品数据,渲染卡片列表;
  3. 点"发布信息"进入 publish.html,选类型(寻物/招领)、填物品信息,前端校验通过后写入 localStorage;
  4. 首页搜索框输入关键词,调用 searchItems 按物品名称过滤并重渲染;
  5. 点击卡片跳转 detail.html?id=xxx,读取该物品完整信息与联系方式;
  6. 在详情页发布者点击状态按钮,更新状态后回到首页能看到标签变化。

整个实现遵循"数据层与页面层分离":data.js 统一封装增删改查,页面文件只调用函数、不直接操作存储字符串,便于维护和测试。
3. 关键流程图 / 数据流图
主流程(数据流图)

┌─────────────┐
│ index.html │
│ 首页列表/搜索│
└─────┬───────┘
│ 读取/过滤
▼
┌───────────────────────┐
│ data.js (localStorage)│
│ 读取 / 新增 / 搜索 / 更新 │
└───┬─────┬───────┬─────┘
│ │ │
┌─────▼─┐ ┌─▼─────┐ ┌▼────────┐
│publish│ │search │ │ detail │
│ 发布 │ │ 搜索 │ │ 详情/状态 │
└───────┘ └───────┘ └──────────┘

用户操作流程(状态修改闭环)

打开首页 → 浏览卡片
├─ 点击"发布信息" → 选寻物/招领 → 填表单 → 校验通过 → 存入存储 → 返回首页可看到新卡片
├─ 输入关键词搜索 → 过滤展示匹配卡片 → 点击看详情
└─ 点击卡片 → 详情页查看完整信息+联系方式
└─ 发布者点击"已找到/已归还" → 更新状态 → 首页卡片标签同步变化

4.有价值代码片段及解释
![zy5](https://img2024.cnblogs.com/blog/3849139/202610/3849139-20261008201001581-1862815634.png)
![zy5-2](https://img2024.cnblogs.com/blog/3849139/202610/3849139-20261008201020097-841446903.png)
> 解释:使用标准 API `URLSearchParams` 解析 `?id=xxx`,比直接切字符串更稳;状态更新走统一数据层,改完刷新即生效,保证"发布者改状态 → 全站可见"闭环。

四、附加特点设计与展示

特点一:寻物 / 招领类型标签区分
创意与意义:浏览首页时一眼区分【寻物】与【招领】,不用逐条点开,快速定位自己需要的信息,提升检索效率。
实现思路:发布表单选择类型并写入数据 `type` 字段,首页渲染时按 type 拼接前缀标签。
关键代码片段
const typeText = item.type === "lost" ? "【寻物】" : "【招领】";
const card = document.createElement("div");
card.innerHTML = `<h3>${typeText} ${item.title}</h3>`;
特点二:物品状态标签可视化 + 一键复制联系方式

创意与意义:物品找到/归还后卡片显示状态标签,避免无效联系;提供"一键复制联系方式"按钮,省去手抄号码,契合老师评分规则里举例的便捷性加分点。
实现思路:状态存于 `status` 字段,渲染时映射为中文标签;复制按钮调用 `navigator.clipboard.writeText` 复制 `contact`。
关键代码片段
const statusText = { normal: "进行中", found: "已找到", returned: "已归还" }[item.status];
// 一键复制联系方式
copyBtn.onclick = () => navigator.clipboard.writeText(item.contact).then(() => alert("联系方式已复制"));
成果展示:详情页有"复制联系方式"按钮,首页卡片状态标签随状态变化实时更新。

五、目录说明和使用说明
1. 目录是如何组织的
campus-lost-found/
├── index.html          # 首页:物品列表 + 关键词搜索
├── publish.html        # 发布页面:寻物/招领表单
├── detail.html         # 物品详情页:查看信息 + 修改状态
├── css/
│   └── style.css       # 全局样式
├── js/
│   ├── data.js         # 数据层:localStorage 封装(核心)
│   ├── index.js        # 首页渲染与搜索逻辑
│   ├── publish.js      # 发布表单校验与提交
│   ├── detail.js       # 详情展示与状态更新
│   └── unittest.js     # 单元测试脚本(不上传 GitHub)
└── README.md           # 项目说明:目录 + 使用指南

结构按"页面文件 / 样式 / 逻辑脚本"分层:HTML 负责结构,CSS 负责表现,JS 负责行为,其中数据逻辑独立成 data.js,方便复用与测试。

  1. 测试人员如何运行网页
  2. 从 GitHub 下载全部文件,解压到本地文件夹;
  3. 用谷歌 Chrome 打开 index.html(双击即可,无需启动服务器);
  4. 即可进行发布、搜索、查看详情、修改状态等操作;
  5. 单元测试:按 F12 打开开发者工具,在 Console 输入 runAllTest() 回车,自动执行全部测试用例。

六、单元测试

  1. 测试工具与学习过程
    我们选用原生 JavaScript 手写断言,不依赖 Jest 等第三方库,理由:项目是纯前端,无需装环境,浏览器控制台即可运行,符合"打开即用"要求。
    学习思路:单元测试的核心是"构造输入 → 调用目标函数 → 断言返回与预期是否一致",并同时覆盖正常场景与边界场景(空关键词、不存在的 id、空输入提交)。
  2. 单元测试代码及测试的函数

zy5-3
// 测试5:空关键词返回全部
assertTrue(LostFoundDB.searchItems("").length > 0, "空关键词返回全部");
console.log("=全部 5 个用例执行完成=");
}


> 测试的函数:`addItem`(新增)、`getItemById`(读取)、`searchItems`(搜索)、`updateItemStatus`(更新状态)。

 3. 构造测试数据的思路 / 如何应对测试人员的刁难(3分)

考虑正常 + 异常两类情况:
正常 :新增一条寻物记录、按 id 读取、关键词命中搜索、状态正常修改;
边界/刁难:空关键词应返回全部而不是报错;输入不存在的 id 读取应返回 undefined 而不崩溃;无匹配关键词返回空数组;状态字段枚举值校验;空字符串搜索、超长描述输入不报错。
刁难应对:数据层函数全部做了空值保护(`getAllItems` 对空存储返回 `[]`,`searchItems` 对空关键词返回全部),保证测试人员无论怎么输入都不会抛异常。 
七、GitHub 代码签入记录截图

八、遇到的代码模块异常、结对困难及解决方案
1. 详情页读取 **URL** **参数为空,物品加载不出来。** 一开始直接切 `location.href` 取 id,兼容性差;后改用标准 API `URLSearchParams` 解析 `?id=xxx`,问题解决。 
2.localStorage 存入对象后取出来是字符串,无法读属性。** 起初直接赋值;解决方案是在 data.js 统一 `JSON.stringify` 序列化、`JSON.parse` 反序列化,页面不再手动处理。    
3."修改状态后首页不更新"的交互问题。** 详情页改状态后立即 `reload()` 刷新,首页读取最新数据,卡片标签同步,补上了老师上次指出的"状态流程交代不清"。    
4.结对困难:两人代码风格不一致,****pull request** **合并冲突。** 提前约定目录结构与变量命名规范;A 建主仓库、B fork,各自改独立文件,合并前互相 review,减少冲突。

九、评价队友

值得学习:搭档数据层写得很干净,注释规范;测试时很细心,主动找边界输入(空关键词、不存在 id),帮助发现了 localStorage 序列化的坑;commit 信息规范。
需要改进:前期对页面交互提示考虑不足(如搜索无结果、发布成功提示),后期补了不少 alert 提示;建议下次先一起把异常态走一遍再编码。
posted @ 2026-10-08 20:21  崔jj  阅读(5)  评论(0)    收藏  举报