2026年秋软件工程第二次结对作业

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

一、具体分工

成员 负责模块 具体工作
崔佳静 数据与发布 js/data.js 数据持久层、publish 发布页面、单元测试脚本、PSP 记录与博客撰写
王昊 展示与交互 index 首页与搜索、detail 详情与状态修改、css 样式、README 编写、GitHub 仓库与 fork、签入记录与截图
GitHub 仓库 https://github.com/WANGHAO123123-C/campus--lost-found/blob/main/readme.md

二、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)把状态流程讲清楚。针对上次"联系之后如何结束这条信息没交代",我们明确了完整链路:发布者点进自己发布的详情 → 点击"已找到/已归还" → 状态写回本地存储 → 首页对应卡片同步更新状态标签,所有人能看到这条信息已经处理完,减少重复联系。

2.代码实现思路

技术选型:纯前端 HTML + CSS + JavaScript,数据用浏览器 localStorage 持久化,无需后端和数据库。理由是满足"谷歌浏览器打开 html 即可运行"的作业要求,也方便其他同学下载复现。
核心流程:
1.用户打开 index.html,从 localStorage 读取全部物品数据,渲染卡片列表;
2..点"发布信息"进入 publish.html,选类型(寻物/招领)、填物品信息,前端校验通过后写入 localStorage;
3.首页搜索框输入关键词,调用 searchItems 按物品名称过滤并重渲染;
4.点击卡片跳转 detail.html?id=xxx,读取该物品完整信息与联系方式;
5.在详情页发布者点击状态按钮,更新状态后回到首页能看到标签变化。
整个实现遵循"数据层与页面层分离":data.js 统一封装增删改查,页面文件只调用函数、不直接操作存储字符串,便于维护和测试。

3. 关键流程图 / 数据流图

主流程(数据流图)

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

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

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

4.有价值代码片段及解释

`zy5
zy5-2

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

六、单元测试

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

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

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

七、GitHub 代码签入记录

image

八、遇到的代码模块异常、结对困难及解决方案

  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 信息语义清晰,便于追溯迭代历史,具备协作开发的良好素养

posted @ 2026-10-08 23:37  WANGHAO2026  阅读(9)  评论(0)    收藏  举报