软件工程第二次结对作业

第二次结对作业:校园失物信息共享平台

一、作业信息

这个作业属于哪个课程 202601 软件工程
这个作业要求在哪里 [2026秋软件工程结对作业(第二次之程序实现)](https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/16744
这个作业的目标 1. 完成校园失物信息共享平台的前端程序实现
2. 实现失物和招领信息的发布、查询、筛选与详情查看
3. 完善数据校验、状态管理、图片处理和主题切换等功能
4. 使用测试和 GitHub 协作记录验证程序质量
学号 102401608
结对成员 成员一:102401608 魏之皓;成员二:102401609 王智钦
个人 GitHub 仓库 wizneko/102401609-102401608
队友 GitHub 仓库 King-Zhi/102401609-102401608
项目名称 福州大学失物信息共享平台
项目形式 PC 端 Web 页面,纯前端、免部署运行
结对同学的博客链接 魏之皓:https://www.cnblogs.com/wizneko/p/23255881 王智钦:https://www.cnblogs.com/zhiking/p/23257216
本作业博客链接 https://www.cnblogs.com/wizneko/p/23255881

二、结对分工

魏之皓(102401608)

  • 参与最新首页方案的确定和页面结构调整,将入口页面统一为 index.html。
  • 负责日间/夜间主题切换、主题记忆和首页视觉层级调整。
  • 协助补充首页顶部最新线索区域,并检查列表、卡片和窄屏布局。
  • 参与近 90 天日期校验、微信号格式校验和页面说明同步。
  • 负责本地浏览器验证及 README、项目说明文档更新。

王智钦(102401609)

  • 负责核心数据管理、发布/编辑/删除/结贴等功能的实现与维护。
  • 负责搜索、关键词高亮、相关度排序、状态分层和图片上传校验等功能。
  • 增加福州大学七大校区筛选、发布校区绑定和校区与地点联合筛选。
  • 编写和维护核心单元测试、页面逻辑测试及测试运行器。
  • 负责主仓库的功能合并和整体版本维护。

三、PSP 表格

PSP各阶段耗时如下,单位为分钟。

PSP2.1 Personal Software Process Stages 预计耗时(分钟) 实际耗时(分钟)
Planning 计划 20 25
Estimate 估计这个任务需要多少时间 20 25
Development 开发 40 45
Analysis 需求分析(包括学习新技术) 40 50
Design Spec 生成设计文档 30 40
Design Review 设计复审 20 25
Coding Standard 代码规范(为目前的开发制定合适的规范) 10 15
Design 具体设计 50 60
Coding 具体编码 180 235
Code Review 代码复审 30 35
Test 测试(自我测试,修改代码,提交修改) 60 75
Reporting 报告 40 50
Test Report 测试报告 20 30
Size Measurement 计算工作量 10 10
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 20 30
合计 580 750

四、项目简介与需求分析

校园失物信息通常散落在班级群、年级群和社交平台中,信息容易被新消息覆盖,也不便于按物品、地点和状态查找。本项目面向福州大学校园场景,提供一个即开即用的失物信息共享页面:用户可以发布寻物或招领信息,按关键词和多个条件检索物品,查看详情并复制联系方式,最后把已经找回或归还的记录标记为已解决。

本项目采用本地浏览器 localStorage 保存数据,不包含服务器、账号系统和真实的多用户权限控制。isMine 只用于本地示例中区分“我的发布”,不能等同于后端鉴权。

五、设计与实现思路

5.1 页面结构

页面分为四个主要区域:

  1. 顶部导航:平台名称、日间/夜间切换、浏览信息、我的发布和发布信息。
  2. 最新线索:自动展示当前进行中的三条信息,帮助用户快速看到最新内容。
  3. 搜索与筛选:关键词搜索、寻物/招领切换、物品分类、校区、地点大区和状态筛选。
  4. 全部物品信息:按照状态和搜索相关度排列的卡片列表,支持详情查看和状态操作。

5.2 数据流

用户操作
   |
   v
index.html 事件入口
   |
   v
js/app.js 组织页面状态、弹窗和重新渲染
   |
   +--> js/utils.js:校验、搜索、排序、关键词高亮
   |
   +--> js/data.js:读取/保存 localStorage,增删改和状态流转
   |
   v
DOM 卡片、弹窗、Toast 提示和主题样式

发布信息时,表单先生成待校验对象,再依次经过字段校验、日期范围校验和图片读取状态检查;校验成功后由数据管理层保存,并调用页面刷新。搜索时先执行多条件过滤,再在相同状态内按相关度排序,最后由页面重新生成卡片。

5.3 关键代码片段:校区与多条件筛选

if (campus && campus !== 'all') {
  const itemCampus = item.campus || this.detectCampus(item);
  if (itemCampus !== campus && !String(item.location || '').includes(campus)) {
    return false;
  }
}

if (location !== 'all' && !item.location.includes(location)) {
  return false;
}

if (kw) {
  const fields = [item.title, item.desc, item.location, item.category, item.campus || ''];
  if (!fields.some(field => this.matchKeyword(field, kw))) return false;
}

这里将校区、地点和关键词作为独立条件处理,只有同时满足条件的记录才会保留。detectCampus 还可以从旧数据的地点文字中补齐校区字段,兼容升级前的本地缓存。

5.4 关键代码片段:状态分层与相关度排序

return filtered.slice().sort((a, b) => {
  const solvedA = a.status === 'solved' ? 1 : 0;
  const solvedB = b.status === 'solved' ? 1 : 0;
  if (solvedA !== solvedB) return solvedA - solvedB;

  if (calculateScore) {
    const scoreDiff = calculateScore(b) - calculateScore(a);
    if (scoreDiff !== 0) return scoreDiff;
  }
  return 0;
});

排序先把进行中的记录放在前面,再在同一状态内使用标题、地点、校区、分类和描述的权重计算相关度。这样用户优先看到仍需要处理的信息,同时搜索结果也更符合使用习惯。

5.5 关键代码片段:发布信息的数据保存

const validation = Utils.validateItem(itemPayload);
if (!validation.isValid || date < minAllowedDate) {
  // 保留输入内容,显示错误原因,允许用户修正后重试
  return;
}

const updatedItem = DataManager.addItem({
  ...itemPayload,
  img: this.uploadedImageBase64 || '',
  publisherName: '校内同学(我)'
});

发布失败时不关闭表单,保存成功后才刷新列表。图片为选填项,未上传图片时保持空值,并由界面显示统一的无图占位,避免把其他物品的示例图片错误套到新记录上。

图片格式和大小校验属于发布流程的边界保护,测试结果统一放在第八章展示。

六、项目特色设计

  1. 七大校区全局筛选:支持旗山、铜盘、怡山、泉港、晋江、厦门集美和厦门鼓浪屿校区,并可以与地点大区组合筛选。
  2. 状态分层展示:进行中的信息自动置前,已解决信息自动后移,减少用户在历史记录中寻找有效信息的成本。
  3. 搜索结果有依据:标题、地点、校区、分类和描述使用不同权重;当关键词只命中描述时,卡片展示上下文摘要。
  4. 日间/夜间主题:切换主题后首页、筛选区域和弹窗一起更新,并使用浏览器本地存储记住选择。
  5. 发布流程有边界保护:对标题、地点、日期、联系方式、图片格式和图片大小进行校验;上传图片的异步读取不会覆盖后一次选择。
  6. 本地可运行:无需安装数据库和后端服务,下载完整仓库后使用现代浏览器打开 index.html 即可体验。

七、目录结构与运行说明

campus-lost-found/
├── index.html              # 网页唯一入口
├── README.md               # 项目简介、目录、运行和测试说明
├── css/
│   ├── style.css           # 公共样式、弹窗和基础状态
│   └── home.css            # 首页布局、日间/夜间主题
├── js/
│   ├── app.js              # 页面控制器和交互事件
│   ├── home.js             # 首页最新线索、主题切换
│   ├── data.js             # localStorage 数据层和示例数据
│   └── utils.js            # 校验、过滤、排序和安全转义
├── assets/
│   ├── favicon.svg         # 网站图标
│   ├── images/             # 预设物品图片
│   ├── web_preview.png     # 夜间首页截图
│   └── web_preview_day.png # 日间首页截图
├── docs/
│   ├── 开发记录.md          # 问题、修改和验证过程
│   ├── PSP记录表.md         # PSP 估计与实际耗时
│   └── images/             # 开发验证截图
└── test/
    ├── test_runner.html    # 浏览器单元测试运行器
    ├── unit_tests.js       # 54 个核心测试用例
    ├── app_tests.js        # 15 个页面逻辑测试
    ├── test_helpers.js     # 测试隔离辅助代码
    └── run_tests.js        # Node.js 命令行入口

运行方法:

  1. 下载或 Clone GitHub 仓库,保持整个目录结构不变。
  2. 使用 Chrome、Edge 等现代浏览器打开根目录下的 index.html。
  3. 点击顶部主题按钮可以切换日间/夜间模式;点击校区胶囊可以切换浏览校区。
  4. 通过搜索框、类型标签和三个筛选下拉框查找物品;点击卡片查看详情。
  5. 点击“发布信息”填写表单,可以选择校区和上传不超过 2MB 的图片。
  6. 打开“我的发布”可以编辑、删除或标记自己发布的记录。

八、单元测试

8.1 测试工具与学习过程

本项目使用 JavaScript 自定义断言实现轻量级测试,没有额外依赖。测试按照“准备输入数据—调用函数—判断结果”的方式编写,并按表单校验、搜索筛选、数据持久化、图片上传和校区功能分类。浏览器测试运行器显示每个用例的通过状态和耗时,Node.js 入口用于重复运行整套测试。

8.2 测试数据设计

  • 正常数据:包含寻物、招领、不同分类、不同校区和已解决记录。
  • 边界数据:空标题、超长标题、未来日期、闰年日期、非法日期、空图片和超过 2MB 的图片。
  • 组合数据:校区 + 地点、类型 + 分类 + 状态、标题命中 + 描述命中。
  • 异常数据:损坏 JSON、非法校区、非法联系方式、存储失败和连续选择图片。
  • 安全数据:包含 <script>、特殊字符和正则字符的搜索词,确认输出经过 HTML 转义。

8.3 测试结果

在项目根目录运行:

node test/run_tests.js

最终结果:

54/54 PASSED, 0 FAILED
15/15 application checks passed

重点测试用例包括:

测试方向 验证内容
表单校验 标题、地点、日期、手机号、QQ、微信号和非法校区拦截
搜索功能 大小写、空格、简称、子序列匹配、描述摘要和高亮
筛选排序 类型、分类、校区、地点、状态联合筛选;进行中优先
数据管理 发布、编辑、删除、结贴、空列表和存储失败保护
图片处理 类型、扩展名、大小、损坏图片、异步回调和重复提交
安全性 特殊字符和恶意脚本输入不会直接生成可执行 HTML

九、截图与展示材料

主要功能展示截图如下:

夜间首页

final-night-home

首页总览展示平台名称、最新线索、搜索筛选和物品列表。日间主题与夜间主题使用相同的页面结构,仅调整颜色和对比度。

正常文字搜索

search-airpods

输入正常关键词“耳机”后,页面筛选出对应的白色 AirPods 记录,并在结果标题中高亮关键词。

物品详情

item-detail

点击物品卡片后打开详情弹窗,展示物品图片、拾获地点、日期、状态、特征描述和联系方式,并提供一键复制功能。

发布信息

publish-modal

发布信息表单包含信息类型、物品名称、分类、日期、地点、详细描述、实物照片和联系方式等字段,提交前会进行输入校验。

展示内容 对应功能
夜间主题首页 首页布局、最新线索、主题切换和信息卡片
正常文字搜索结果 关键词搜索、结果筛选和关键词高亮
物品详情弹窗 物品信息查看、联系方式复制和状态操作
发布信息表单 信息录入、图片上传和表单校验
GitHub 提交与 Pull Request 记录 GitHub 分支协作、功能提交和合并过程

十、GitHub 提交记录

组长仓库 main 分支的相关提交如下:

9433a1f fix(home): ensure latest clues section dynamically displays without page reload and bust script cache
490a43f fix(home): retain latest clues after publishing and support type switching
9f266c5 fix(home): allow latest clues to display per-campus without disappearing
c3517c5 docs: correct member name to 王智钦 across README and development log
84d88a5 docs: clean up defensive notes and update development log for blog synthesis
23f152d docs: update README, development log and add .gitignore for multi-campus support and test suite expansion
b6dc50d feat: 将校区选择移至顶部地标定位栏作为全局切换胶囊,简化搜索栏
4805f9e feat: 支持福州大学全7大校区精细化筛选与发布绑定 (测试用例扩充至54项全绿)
61aaddb style: remove redundant footer action buttons and center brand note

其中,9433a1f 是组长最后一次首页修复。之前页面在发布信息、切换寻物/招领类型或切换校区后,顶部“最新线索”区域可能不刷新或直接消失。修复后,首页根据当前筛选条件重新计算进行中的最新记录;发布成功时清除会造成误过滤的搜索条件,并在必要时自动调整校区、分类和状态筛选。页面资源同时增加版本参数,避免浏览器继续使用旧缓存脚本。

个人参与的页面相关提交包括:

7404683 更新首页布局并加入日间夜间切换
45741c8 同步组长仓库的日期校验和页面更新
eadae48 更新日夜首页截图和使用说明

Pull Request 协作记录

pull-requests

图 5 GitHub Pull Request 页面:仓库中保留了首页布局、图片处理、搜索日期校验、发布管理和 README 更新等协作记录。

GitHub 提交记录截图

以下截图展示了仓库中按日期排列的实际提交记录,内容包括首页功能修复、成员信息更正、文档整理、校区筛选、搜索排序、图片处理和测试完善等工作。

github-commits-2026-10-09

图 6 2026 年 10 月 9 日的提交记录:完成首页最新线索显示、类型切换、成员信息和文档内容的修正。

github-commits-2026-10-08

图 7 2026 年 10 月 8 日的提交记录:包含主题切换、日期校验、搜索排序、文案调整、单元测试和多个 Pull Request 合并记录。

github-commits-2026-10-07

图 8 2026 年 10 月 7 日的提交记录:包含数据修复、图片处理、搜索高亮、测试隔离和项目文档整理等提交。

十一、遇到的问题、尝试与解决

1. 首页版本合并后功能和视觉风格不一致

问题:第一次页面方案与主仓库的功能分支同时修改入口文件和样式,直接合并容易覆盖校区、搜索和发布功能。
尝试:先比较主分支和个人分支的文件差异,再保留主仓库的数据层和交互函数,将主题与首页布局放到 home.css、home.js,最后在 index.html 统一入口。
结果:保留了主仓库功能,并完成日间/夜间主题和首页布局调整。收获是合并前先划分文件职责,比直接覆盖文件更容易定位冲突。

2. 用户发布的物品图片与文字不对应

问题:未上传实物图片时,旧逻辑会套用分类示例图,导致“手机”等新记录显示成其他物品。
解决:发布时未上传图片保持空字符串,卡片和详情使用“暂无实物图片”占位;预设数据继续使用对应的本地示例图片。
结果:新增图片相关测试,并验证图片为空时不会误用其他物品图片。

3. 已解决信息和进行中信息混在一起

问题:按照原始数组显示时,已解决记录会穿插在仍需处理的记录中。
解决:在过滤结果上增加状态分层,open 优先,solved 后移;有搜索词时再按标题、地点、分类和描述的权重排序。
结果:列表更符合失物招领的实际使用优先级。

4. 搜索结果命中描述但用户看不出原因

问题:关键词只出现在描述中时,卡片没有展示描述内容,用户难以理解为什么出现该结果。
解决:增加描述上下文摘要和关键词高亮,并对标题、地点、校区、分类和描述设置不同权重。
结果:搜索结果能说明命中原因,同时使用 HTML 转义防止恶意输入生成标签。

5. 首页最新线索在筛选和发布后显示异常

问题:发布新信息、切换寻物/招领类型或选择具体校区后,顶部最新线索区域可能仍使用旧状态,甚至因为筛选条件不兼容而不显示。

解决:在 js/home.js 中根据当前关键词、类型和校区重新计算最新的进行中记录,并分别显示“最新寻物”“最新招领”或对应校区标题;在 js/app.js 中发布成功后清理遗留关键词,遇到校区、分类和状态冲突时自动调整筛选条件,再重新渲染页面。同时在 index.html 的 CSS 和 JavaScript 引用后加入版本参数,降低浏览器缓存旧脚本造成的影响。

验证:通过发布信息、切换类型、切换校区和刷新页面进行浏览器验证,确认新记录能够进入最新线索区域,已有线索不会因为视图切换消失;核心测试保持 54/54 通过,页面逻辑测试保持 15/15 通过。

十二、队友评价

王智钦同学做事认真,遇到问题会主动排查,也能及时沟通修改方案。合作过程中,他对细节和测试的重视让我学到了不少,整体配合也很顺利。

十三、个人总结

这次作业让我更清楚地认识到,一个页面能打开并不代表程序已经完成。需求分析、模块划分、GitHub 分支协作、边界测试和文档整理都会影响最终质量。实际开发中,日夜主题、校区筛选和图片处理都经历了多次调整,很多问题只有在真实浏览器操作后才会暴露。通过这次作业,我对前端页面状态管理、localStorage 数据持久化、纯函数测试和 GitHub 协作流程有了更具体的认识,也体会到先写清楚数据结构和交互规则,再开始修改代码,能够减少返工。

posted @ 2026-10-10 18:16  Wizneko  阅读(12)  评论(0)    收藏  举报