软件工程第四次作业

从原型到程序:校园拾光——第二次结对编程作业

项目 内容
所属课程 2026 软件工程与软件工程实践
作业要求 第二次结对作业:程序实现
本人 032401339 沈冠宇 · 队友博客
结对同学 052402234 郭泽强 · 个人博客
GitHub 主仓库 monkery-king-nice/052402234-032401339
队友 Fork 2074599796-cpu/052402234-032401339
协作 PR PR #1:日期筛选、本地评论与界面完善,已合并
第一次作业原型 Figma:校园失物招领原型

一、项目介绍与分工

上一次作业完成了校园失物招领的原型设计,这次作业则需要让页面上的操作真正生效。我们将项目命名为“校园拾光”,围绕“发布信息—浏览或搜索—查看详情—联系发布者—更新状态”完成核心流程,并增加照片上传、日期筛选、本地评论等功能。

项目使用 HTML、CSS 和 JavaScript,下载后可直接用 Google Chrome 打开 index.html。启事、照片和评论保存在当前浏览器的 localStorage 中,无需服务器。联系方式由发布者填写,联系与交接在线下或其他通信工具中完成,页面不提供即时聊天。

1.1 分工

以下按本次主仓库与 Fork 的开发范围整理。

成员 负责范围 主要产出
郭泽强 基础功能与主仓库整合;发布、搜索、详情、状态维护;照片上传和删除功能;提交版本检查与博客整理 基础页面与业务模型、原有单元测试、图片资源、主仓库开发记录
沈冠宇 在 Fork 中增加日期范围筛选、本地评论和界面优化;补充测试与展示材料;向主仓库提交 PR 日期及评论规则、新增测试、Chrome 验收脚本、截图、PR #1

协作采用“主仓库维护基础版本—队友 Fork 后在功能分支开发—提交 PR—合并回主仓库”的方式。队友的开发分支为 feat/date-filter-comments-ui,PR #1 已合并,合并提交为 ff5ffd1。

开发过程中使用了 Codex 辅助编码、测试和文档整理。本文中的功能结论以代码、提交记录与实际运行结果为依据;个人工作量不能直接用 AI 的运行时间或提交之间的时间间隔代替。

二、PSP 与时间复盘

PSP2.1 工作内容 参考估算 本次实际耗时
Planning / Estimate 明确范围、拆分任务与安排顺序 30 40
Analysis 分析核心流程、学习本地存储及测试方法 90 100
Design Spec 整理数据结构、页面与异常流程 60 65
Design Review 检查原型与课程范围是否一致 30 40
Coding Standard 约定命名、目录、校验与提交方式 20 30
Design 设计模型函数、筛选条件与交互细节 90 120
Coding 实现基础功能、图片、日期、评论及样式 360 450
Code Review 检查数据兼容、保存顺序和权限判断 60 80
Test 单元测试、Chrome 页面测试与问题修正 180 150
Reporting / Test Report 整理测试结果、说明与截图 60 60
Size Measurement 统计模块、测试和有效提交 20 30
Postmortem & Process Improvement Plan 总结问题、整理博客和改进计划 80 60

三、解题思路与设计实现

3.1 先完成一个能走通的流程

用户操作 页面入口 程序处理 用户得到的结果
发布寻物或招领 首页“我丢了东西”“我捡到了”或发布按钮 校验必填项、处理图片、写入本地存储 在“我的发布”及广场看到新启事
搜索或筛选 广场搜索框和筛选区域 组合关键词、类型、类别、状态、日期条件 展示匹配结果;无结果时可清除筛选
查看与联系 物品卡片的详情入口 展示描述、地点、日期、图片和联系方式 复制联系方式,进一步核实物品
结束信息 “我的发布”中打开详情 核对当前浏览器的发布者标识,保存新状态 寻物显示“已找到”,招领显示“已归还”
补充线索 详情下方“评论与线索” 校验昵称和正文,按启事 ID 保存 当前浏览器刷新后仍可查看留言

状态由发布者维护,更新入口在“我的发布”的详情中。完成后,广场卡片和详情都会显示新状态;误操作时可以恢复为进行中,减少错误结束信息带来的影响。

3.2 模块与数据结构

程序将业务规则和页面交互分开:model.js 管理校验、筛选、状态和存储;app.js 绑定事件并刷新界面;images.js 处理照片;seed.js 提供演示启事。这样测试核心规则时不必启动整个页面。

一条启事包含 id、ownerId、type、title、category、location、date、description、contact、publisher、images、status、createdAt。其中 date 是丢失或拾取日期,createdAt 是发布时间,两者分别用于日期筛选和列表排序。

数据 存储键 作用
启事列表及照片 campus-light-items-v1 保存物品信息和状态
当前发布者标识 campus-light-owner-v1 限制页面上维护他人启事的操作
单条启事评论 campus-light-comments-v1: + 编码后的启事 ID 避免不同物品的留言混在一起

3.3 核心流程图

发布、寻找、联系和更新状态的完整流程

图中的“联系与交接”属于页面之外的用户行为。程序提供联系方式及状态维护入口,不会把复制联系方式视为物品已经找回。

3.4 关键代码一:先校验,再创建记录

下面节选自 js/model.js 的 createItem:

const errors = validateDraft(draft);
if (Object.keys(errors).length) {
  const error = new Error('信息不完整,请检查表单');
  error.fields = errors;
  throw error;
}
if (!clean(ownerId)) throw new Error('缺少发布者标识');

validateDraft 会分别检查类型、名称、类别、地点、真实日历日期、描述、联系方式、称呼和照片。例如物品名称为 2~40 个字符,详细描述为 10~500 个字符。错误返回到具体字段,页面能够提示用户修改哪一项;通过校验后才创建默认状态为 active 的记录。

保存时也遵循“先保存、后更新界面”的顺序,下面是 app.js 中实际使用的函数:

function commitItems(next) {
  M.saveItems(storage, next);
  items = next;
}

如果本地存储已满,saveItems 会抛出明确错误,内存中的启事列表不会提前切换成未保存的结果,避免页面提示成功而刷新后数据消失。

3.5 关键代码二:由发布者维护状态

function updateStatus(items, id, ownerId, status) {
  if (!['active', 'resolved'].includes(status)) {
    throw new Error('无效状态');
  }
  const item = items.find(entry => entry.id === id);
  if (!item) throw new Error('信息不存在');
  if (!ownerId || item.ownerId !== ownerId) {
    throw new Error('只有发布者可以更新状态');
  }
  return items.map(entry =>
    entry.id === id ? { ...entry, status } : entry
  );
}

这里分别检查状态是否合法、记录是否存在、操作者是否匹配。函数返回新数组,并保留照片等其他字段。对于同一个 resolved 状态,寻物信息展示“已找到”,招领信息展示“已归还”,使结果符合业务含义。

四、附加特点及展示

4.1 按丢失或拾取日期组合筛选

只记得物品大概在哪几天丢失时,可以设置日期范围,再结合类别和关键词缩小查找范围。开始和结束当天都包含在结果内;仅填写一端时,另一端不限;起始日期晚于结束日期时显示错误,保留原输入。

下面节选自 filterItems:

if (validateDateRange(filters)) return [];
const start = clean(filters.startDate), end = clean(filters.endDate);
// 以下判断位于 items.filter 的回调中。
if (start && (!validDate(item.date) || item.date < start)) return false;
if (end && (!validDate(item.date) || item.date > end)) return false;

在确认日期有效后,固定格式的 YYYY-MM-DD 字符串可按日历顺序比较,避免将日期转成本地时区时间点后产生一天偏差。类型、类别、状态和关键词判断继续在同一筛选函数中执行。

桌面广场:关键词、类别、状态与日期范围筛选

4.2 每条启事独立的本地评论

详情下方可以填写昵称和线索,昵称为 2~24 个字符,正文为 1~500 个字符。提交前清除首尾空白;保存中禁用提交按钮;成功后清空正文;失败时保留输入和原评论,方便重试。

function commentStorageKey(itemId) {
  if (!clean(itemId)) throw new Error('缺少启事标识');
  return COMMENTS_KEY + encodeURIComponent(itemId);
}

每条启事使用不同存储键,因此校园卡的线索不会出现在耳机的详情下。展示正文时采用以下代码:

const text = document.createElement('p');
text.textContent = comment.body;

使用 textContent 后,即便正文包含 <script> 或 <img> 字样,也会作为文字显示,而不会作为 HTML 执行。评论按发表时间从早到晚显示;已完成的启事仍能查看和补充留言。

评论校验、读取与保存流程

详情中的本地评论与线索

本功能是纯前端本地留言演示,评论仅保存在当前浏览器,不同用户的设备和不同浏览器之间不会同步。它能演示补充线索的交互,但不能称为已上线的公共聊天室。

4.3 照片上传、压缩与预览

每条启事可上传最多 3 张 JPG、PNG 或 WebP 图片,单张原图不超过 5 MB。图片先在浏览器解码,最长边缩至不超过 1280 像素,再通过 JPEG 编码质量和必要的继续缩放,将每张保存图片控制在 200 KB 以内;压缩失败会提示重新选择。

images.js 中缩放比例的关键计算如下:

const scale = Math.min(
  1, 1280 / Math.max(image.naturalWidth, image.naturalHeight)
);
let width = Math.max(1, Math.round(image.naturalWidth * scale));
let height = Math.max(1, Math.round(image.naturalHeight * scale));

等比例缩放避免物品变形,上传前可预览和移除照片。详情优先展示发布者实际上传的照片;六条演示启事使用与名称对应的写实示例图片,并标注为示例图。示例素材用于展示界面,不代表真实失物。

4.4 其他便捷设计

设计 使用意义 实现方式
一键复制联系方式 减少手动抄录 优先剪贴板 API,失败时尝试兼容复制,并反馈结果
状态恢复 修正误标记 发布者可将已完成信息恢复为进行中
删除前二次确认 减少误删 确认后保存新列表,再清理对应评论
空结果与清除筛选 帮助用户继续搜索 显示明确空状态,统一清空筛选条件
手机布局与键盘焦点 方便不同屏幕和操作方式 响应式布局、底部导航、可见焦点;桌面 / 聚焦搜索

mobile-square

mobile-comments

mobile-publish

五、目录组织与使用说明

052402234-032401339/
├─ index.html                 页面入口,Chrome 直接打开
├─ css/
│  └─ style.css               配色、布局和手机适配
├─ js/
│  ├─ model.js                业务规则与本地存储
│  ├─ app.js                  页面渲染、事件和反馈
│  ├─ images.js               上传照片的校验与压缩
│  └─ seed.js                 六条演示启事
├─ assets/items/              本地示例图片及素材说明
├─ tests/
│  ├─ model.test.js           基础功能及照片相关测试
│  ├─ date-comments.test.js   日期范围与评论输入测试
│  ├─ comments.test.js        评论存储、隔离与异常测试
│  └─ browser.cjs             Chrome 页面自动验收
├─ docs/
│  ├─ screenshots/           界面及异常状态截图
│  ├─ diagrams/              核心流程和评论流程图
│  ├─ browser-tests.json     队友提交的浏览器测试记录
│  └─ unit-tests.xml         队友提交的单元测试记录
├─ package.json              开发测试命令
├─ package-lock.json         开发依赖版本锁定
├─ README.md                 下载、操作与限制说明
├─ BLOG_DRAFT.md             早期博客草稿
└─ BLOG_FINAL.md             本文整理稿

5.1 测试人员如何运行

  1. 打开主仓库,选择 Code → Download ZIP,将整个压缩包解压。
  2. 保持 index.html、css、js、assets 的相对位置,用 Google Chrome 打开 index.html。
  3. 在广场浏览示例信息,输入关键词或日期筛选,点击卡片查看详情和复制联系方式。
  4. 发布一条自己的测试信息,可选上传照片;在“我的发布”中修改状态或删除。
  5. 打开任意启事,在评论区域填写昵称和线索,刷新后检查本地保存结果。

日常使用不需要 Node.js、服务器或联网。Node.js 和浏览器测试依赖只用于开发验收。请勿只下载 HTML 而遗漏资源,也不要继续使用合并前的旧压缩包。

5.2 数据保存范围

同一 Chrome 用户配置、同一路径下可继续读取原数据。更换设备、浏览器用户配置、无痕会话或移动文件路径后,不应假定旧数据会自动出现。清除浏览器存储会删除本地记录;升级时保留原存储键,无需清空数据。

六、单元测试与自动化验收

6.1 工具选择及学习思路

单元测试使用 Node.js 内置的 node:test 和 node:assert/strict。业务函数不依赖页面,通过输入、返回值和异常即可检查;存储测试使用内存中的 Map 模拟浏览器存储,因此不会修改用户实际发布的信息。

学习和应用这套方法可以分成四步:先找出可独立调用的函数;再写清给定输入的预期结果;然后使用 assert.equal、assert.deepEqual 或 assert.throws 表达预期;最后运行测试,从失败信息定位具体分支。修正后重新运行整个测试集,检查是否破坏原功能。

6.2 一份可以照着操作的简易教程

第一步: 安装 Node.js 20 或以上版本,仅做测试时需要。打开项目目录中的 CMD,输入:

node --version
node --test tests/*.test.js

第二步: 理解一个最小测试。下面是可运行的教学示例,数据使用固定日期,不受运行当天影响。需要实践时可另存为 tests/tutorial.example.js,再执行 node --test tests/tutorial.example.js;它不计入仓库现有的 47 个测试。

const test = require('node:test');
const assert = require('node:assert/strict');
const M = require('../js/model.js');

test('起止日期相同时,包含当天的物品', () => {
  const items = [
    { id: 'a', date: '2026-09-28', createdAt: '2026-10-01' },
    { id: 'b', date: '2026-09-29', createdAt: '2026-10-01' }
  ];
  const result = M.filterItems(items, {
    startDate: '2026-09-28', endDate: '2026-09-28'
  });
  assert.deepEqual(result.map(item => item.id), ['a']);
});

这个测试刻意让发布时间与物品日期不同,可以发现“错误地使用发布时间筛选”的问题。把日期比较中的 >= 边界理解成严格大于时,同一天测试就会失败。

第三步: 阅读项目中的实际异常测试。下面节选自评论测试,用配额异常模拟存储已满:

const full = {
  getItem: storage.getItem,
  setItem: () => {
    throw Object.assign(new Error('quota'), {
      name: 'QuotaExceededError'
    });
  }
};
assert.throws(() => M.addComment(full, 'a', draft), /存储空间不足/);
assert.equal(storage.getItem(M.commentStorageKey('a')), before);

测试前已创建内存存储、保存原评论,并将原值记录为 before。两条断言同时检查“有明确提示”和“旧记录没有被覆盖”,而不仅是检查函数有没有抛出异常。

第四步: 页面功能还需要 Chrome 测试。安装仓库锁定的开发依赖后执行:

npm ci
npm run test:browser

脚本使用独立浏览器上下文,在离线模式下直接访问本地 HTML,覆盖真实点击、输入、上传、刷新和手机视口。运行时会生成截图及 test-results/browser.json。这与只检查模型函数的单元测试相互补充。

6.3 白盒思路与用例设计

用例围绕代码中的条件判断设计:有效/无效输入、合法/非法状态、发布者匹配/不匹配、存在/不存在记录、正常/失败存储。对于长度、日期和文件大小采用边界值;对于列表筛选采用条件组合;对于可能破坏原数据的操作检查写入前后是否一致。

下表列出实际测试覆盖的代表性情形,部分行对应同一个测试函数中的多条断言;全套测试共 47 项。

编号 函数或场景 输入与构造方式 预期结果 结果
1 createItem 完整合法的寻物信息 创建成功,默认进行中 通过
2 validateDraft 空物品名称 返回名称错误 通过
3 validateDraft 不存在的日历日期 拒绝创建 通过
4 filterItems 名称、地点、描述中的关键词及大小写变化 匹配对应启事 通过
5 filterItems 同时指定类型、类别、状态 只保留全部符合条件的记录 通过
6 updateStatus 正确发布者标记完成,再恢复 状态正确变化 通过
7 updateStatus 非发布者、记录不存在或非法状态 分别拒绝 通过
8 removeItem 删除自己的某条信息 其他启事和照片不变 通过
9 removeItem 尝试删除他人或演示信息 拒绝删除 通过
10 照片规则 无照片、三张以内、超过三张 接受可选合法照片,拒绝超量 通过
11 照片规则 空文件、不支持格式、超过 5 MB 返回明确错误 通过
12 图片数据 200 KB 边界与超出边界、外链或 SVG 只接受受限图片数据 通过
13 日期筛选 起止日期与物品日期相同 包含当天 通过
14 日期筛选 仅开始、仅结束、两端为空 单侧限制或不限日期 通过
15 日期校验 开始晚于结束、2 月 30 日 提示错误并返回空结果 通过
16 日期组合筛选 日期与类型、类别、状态、关键词组合 正确匹配或明确空结果 通过
17 评论校验 空白、昵称 24/25 字、正文 500/501 字 接受合法边界,拒绝超长或空白 通过
18 评论持久化 保存后重新读取 内容、时间和启事关联保持一致 通过
19 评论隔离 两个启事 ID,包括特殊字符 分别保存,不串条 通过
20 评论排序 时间乱序及相同时间 时间升序,同时间保持插入顺序 通过
21 保存失败 注入 QuotaExceededError 提示失败,原记录不变 通过
22 损坏评论 无效 JSON、错误结构、关联错误 读取报错,提交不覆盖原数据 通过
23 评论清理 删除目标启事的评论 不影响其他启事、照片和评论 通过
24 页面安全展示 含 HTML 标签的昵称和正文 作为文字显示,无脚本执行 Chrome 验收通过

对于测试人员可能输入的异常数据,重点考虑了空格与换行、不存在的日期、相反的日期范围、超量图片、超长评论、错误的发布者标识和保存失败。测试关注具体可观察结果,而不是只走一次正常发布流程。

6.4 实际结果与测试边界

验证轮次 环境与方式 结果
队友提交前验收 2026-10-10,Chrome 154.0.8037.93;记录已随 PR 提交 47/47 单元测试,10/10 页面场景
合并后复验 2026-10-10,合并版本 ff5ffd1;Chrome 155.0.8059.39 47/47 单元测试,10/10 页面场景

合并后页面复验在独立副本中使用已有 Playwright 1.62.1 的测试接口,未重新验证 package-lock.json 所锁定的 Playwright 1.64.0 安装过程。两轮环境不同,分别记录,不把它们混写为同一环境。合并后页面复验未出现页面脚本错误,也没有 HTTP 资源请求;覆盖了 320、390、768 像素宽度下的布局检查。

invalid-date

comment-storage-error

这些测试覆盖了主要业务分支、关键边界和保存异常,能够支持本次纯前端演示验收;没有生成分支覆盖率报告,因此不声称达到 100% 代码覆盖率,也不能据此保证没有任何缺陷。尚未验证真实多用户并发、跨设备共享或大量数据下的性能,因为本版没有对应的服务端能力。后续可补充更全面的可访问性检查和大数据量测试。

七、GitHub 协作与分阶段提交

本次保留了真实开发提交,功能完成后的本地 commit 与上传远程的 push 并不总是一一对应。早期受上传环境影响,曾通过 GitHub 网页上传并调整文件目录,随后合并保留了原有本地开发历史;后续部分本地提交由一次 push 一起上传。

阶段 提交或 PR 内容
基础模型 77c68cc 发布校验、筛选和状态规则
基础交互 27969a0 响应式页面与失物招领流程
测试与说明 55d1924 基础测试、使用文档
网页上传与目录整理 bedbb3d、daedfbd、71d5ee9、fd202be、3810bae、d8fa1db 上传文件并整理 CSS、JS 和测试文件的位置
历史整合 5a02abf 保留最初本地开发提交,整合网页上传历史
照片功能 104cb16 图片上传、压缩与详情图库
图片展示 6e2d334 示例物品与写实照片对应
删除功能 eb6ec0b 发布者二次确认后删除
队友功能开发 78cb701 日期筛选、评论与界面;此时包含共享服务方案
调整运行范围 6e48bbf 移除共享服务依赖,评论改为本地存储
验收与文档 2ab1d54、8f43d7a 测试记录、截图、运行说明和提交链接
合并协作成果 ff5ffd1 / PR #1 队友功能分支合并到主仓库

查看主仓库真实提交历史;查看队友 PR 与合并情况。

以下截图于 2026 年 10 月 10 日(北京时间)在 Chrome 中直接打开 GitHub 公开页面取得,保留网页显示的日期、提交信息和合并状态。页面原始日期显示与本地日期口径可能不同,未对截图内容进行改写。

github-commits-recent

上图可看到照片上传、图片匹配、删除功能,以及队友的日期筛选、评论调整和最终合并记录。

github-commits-earlier

上图保留了基础模型、页面流程和测试阶段,也如实展示了网页上传期间的目录移动提交。

github-pr-merged

PR 页面显示 Merged,从队友 Fork 的功能分支合并了 4 个提交。完整提交历史长截图另存于 github-commits-full
,截图来源及浏览器记录见 docs/github-screenshot-evidence.json。

八、遇到的问题、尝试与收获

8.1 本地有提交,远程却看不到完整开发过程

问题: 早期上传遇到 TLS、Git 辅助进程和认证相关错误,网页上传又产生了文件移动等提交,远程记录一度不能直观反映最初的开发阶段。

尝试: 检查远程地址和本地分支,先保留原开发历史;通过网页上传处理文件,再整合历史。后续在本机 CMD 中执行 push,确认本地提交上传成功,并用 git status -sb 检查本地与远程跟踪分支的关系。

结果: 原始开发提交已保留,照片、删除等后续成果也进入远程,队友 PR 已合并。不过 Codex 内的 Git 辅助进程故障尚未修复,不能把本地 CMD 上传成功写成所有环境都恢复正常。

收获: commit 是保存开发阶段,push 是同步到远程,两者要分别检查;目录整理提交应如实说明,不能充当新的功能开发记录。

8.2 评论方案超出了最终运行范围

问题: 希望不同浏览器看到公共评论时,需要共享数据来源,最初方案引入了本地共享服务,与最终“直接打开 HTML 使用”的要求不一致。

尝试: 重新明确纯前端范围,改为按启事 ID 保存本地评论,同时更新页面提示、README 和自动化测试,移除服务入口与运行依赖。

结果: 在关闭共享服务、浏览器离线的条件下,仍可直接打开 HTML 使用日期筛选、留言和原有功能;不同浏览器不会同步,文档与页面明确说明这一限制。

收获: 增加一个功能时,要一起确认它的运行条件和数据范围。提出“公共评论”与实现“本地留言”代表不同能力,验收材料必须与实际功能一致。

8.3 图片与旧数据的兼容

问题: 增加上传图片后,旧启事可能没有照片,例如此前自己发布的手机信息。图片较大时,还会增加本地存储压力。

尝试: 图片设为可选字段,读取旧记录时兼容缺失的照片数组;实际上传照片优先展示,示例图片只匹配对应演示启事;对原图限制数量、格式和大小,并在保存前压缩。

结果: 没有照片的旧记录仍可读取,不会错误地使用无关物品照片。测试验证了照片刷新保存、状态更新保留照片,以及容量不足时的错误提示。

收获: 新增字段不能要求用户清空旧数据才能升级,演示图片也不能假装成用户已经上传的照片。

九、对队友的评价

这次合作中,我最认可郭泽强的一点,是他先把项目的核心流程做完整,再继续补充使用细节。他完成了发布、搜索、详情和状态维护等基础功能,并负责主仓库的整合。我在这个版本上增加日期筛选、本地评论和界面优化时,能够沿着已有的代码结构继续开发,也更容易判断新增功能是否影响原有操作。这让我体会到,结对开发中的基础工作不仅要能运行,还要方便另一个人理解和接着修改。

在具体功能上,照片上传后的压缩与预览、删除前的二次确认,以及误标记状态后的恢复,都是郭泽强这部分工作中值得我学习的地方。这些处理对应的是用户实际会遇到的问题:图片太大、选错照片、误删信息或误结束启事。它们让我认识到,完善功能不能只看正常操作是否成功,也要考虑出错后用户能否理解提示、修正操作。

我觉得我们还可以改进版本同步和阶段检查。基础版本上传时经历过目录调整,我负责的评论方案也在后期改变了运行方式,两部分都增加了整理和复验的工作。下一次合作时,我希望我们更早统一目录、运行条件和验收方法;郭泽强更新主仓库、我更新功能分支后,都及时检查提交是否同步、说明是否与代码一致,让双方更容易掌握项目当前的状态。

对我自己来说,也不能把范围变化带来的返工都归到协作安排上。评论功能由共享服务改为本地保存,提醒我在动手前要把数据保存在哪里、是否需要联网、最终怎样运行确认清楚。郭泽强完成的基础版本和这次整合过程,让我更清楚自己在合作中既要完成负责的模块,也要保证它能顺利接入两人的共同成果。

十、总结

这次作业中,我和郭泽强一起把第一次的原型落实成了可以操作的“校园拾光”网页。郭泽强负责基础流程、照片和删除等功能,我在此基础上完成日期筛选、本地评论和界面优化,并通过自己的 Fork 和 PR 将修改交回主仓库。最终页面能够用 Google Chrome 直接打开 index.html 使用,原有发布、搜索、详情、联系方式和状态维护也得到了保留。

我最大的收获,是对“一个功能完成了”有了更具体的判断。日期筛选不仅是增加两个输入框,还要区分丢失或拾取日期与发布时间,处理当天边界、单侧条件和无效范围;评论也不仅是把文字显示出来,还要保证每条启事的留言独立、刷新后保留、保存失败时不丢输入,并把用户输入当作普通文字展示。这些细节需要逐项检查,不能只凭一次正常操作就判断功能已经完成。

这次保留并补充的测试,让这些判断有了可以复查的依据。最终的 47 项业务测试和 10 项 Chrome 页面场景通过,覆盖了日期、评论、图片及原有功能,也验证了关闭共享程序、离线直接打开页面的运行方式。同时,我明确了本版的能力范围:评论只保存在当前浏览器,不同浏览器或设备不会同步。测试结果、页面提示和 README 都应围绕这个实际范围说明。

在协作方面,我也更清楚了本地提交、远程推送和 PR 各自的作用。完成自己的模块后,还需要检查代码是否上传、合并后的功能是否正常,以及文档是否同步更新。以后再做类似项目,我会更早确认运行条件,在每个阶段记录自己的投入,并把边界测试、异常反馈和使用说明与功能一起完成。这些是我希望从这次作业中继续保留下来的做法。

posted @ 2026-10-10 17:23  天地玄黄人  阅读(7)  评论(0)    收藏  举报