软件工程第二次结对作业

2026 秋软件工程第二次结对作业:校园失物招领程序实现

项目 内容
课程 2026 秋软件工程
作业要求 第二次结对作业之程序实现
本人 秦文贵,102401615
结对同学 吴圣洲,102401622
GitHub 仓库 vg666-NiKo/102401615-102401622
项目形式 PC Web,兼顾手机尺寸;HTML、CSS、原生 JavaScript
运行方式 完整下载仓库并解压,使用 Chrome 打开根目录 index.html

一、项目简介:从原型到可以操作的网页

第一次结对作业中,我们使用墨刀设计了校园失物招领原型,确定了首页、搜索、发布、详情和“我的发布”等页面。本次沿着原来的使用流程,把按钮背后的数据处理和异常情况补齐。

校园失物信息经常分散在班级群、宿舍群和朋友圈里。想找东西的人需要反复翻消息,捡到东西的人也未必知道应该发到哪里。我们希望用一个统一入口,把寻物与招领信息按照名称、类别和地点组织起来,让“发布—查找—联系—结束信息”能够接着完成。

本次程序保留了蓝白配色和底部导航,实现以下三条主要路径:

  1. 发布信息:选择寻物/招领,填写物品信息,选填照片,校验通过后保存。
  2. 浏览查找:首页浏览或组合搜索,进入详情,查看或复制联系方式,再通过外部渠道核对和交接。
  3. 结束与维护:在“我的发布”中编辑、删除、标记已找回/已归还,必要时恢复进行中。

程序使用浏览器 localStorage 保存记录和照片,适合下载后直接验收。它目前是本地运行的功能实现版本,没有后台账号、跨设备同步、地图定位或应用内聊天。联系功能提供联系方式,实际沟通与物品交接在应用外完成。

截图-首页浏览

二、具体分工与协作过程

我们采用先完成主体、再由搭档完善的方式推进。我的重点是把页面和核心流程接起来,吴圣洲在 fork 仓库中补充功能、调整界面和完善说明,最后通过 PR 合并到主仓库。

成员 主要工作 可以核对的成果
秦文贵(102401615) 原型归档、项目目录和页面框架;首页、发布、校验、本地保存;搜索、详情和复制;我的发布、编辑删除、状态更新;照片上传和线索推荐;初始测试与阶段文档 主仓库各阶段功能提交、业务与页面模块、初始 80 个单元测试
吴圣洲(102401622) 首页最新 30 条限制;新增边界测试;全局样式和页面视觉优化;README 重写;发布、浏览查找、我的管理三张流程图 faaedf8d、f0d2a302 等提交,以及 PR #2
交接与整合 我将已完成的主体交给搭档继续完善;搭档提交 PR 后,我查看变更并合并到主仓库 已合并 PR #2

协作过程中没有把 fork 仓库里的文件再手动复制一遍,而是通过 Pull Request 查看修改内容、比较差异并合并。这让新增功能和界面调整能够对应到具体提交,也便于后续发现问题时回查版本。

PR #2 包含 4 个提交、9 个文件的变更。最终测试由原来的 80 个增加到 85 个,其中新增的 5 个主要覆盖首页 30 条上限及其边界。

三、PSP 2.1 表格与时间分析

下表采用老师提供的 PSP 2.1 阶段,保留 Planning、Development、Reporting 及其子项。单位均为分钟。

PSP 2.1 阶段 内容 102401615 预估 102401615 实际 102401622 预估 102401622 实际
Estimate 估计任务时间 15 20 15 15
Analysis 需求与技术分析 40 45 30 35
Design Spec 生成设计文档 30 25 20 30
Design Review 设计复审 15 15 20 20
Coding Standard 代码规范 15 10 10 10
Design 具体设计 45 40 25 30
Coding 编码/功能完善 240 260 100 90
Code Review 代码复审 30 25 50 45
Test 测试、修复和回归 80 90 120 110
Test Report 测试报告 20 20 30 25
Size Measurement 工作量统计 10 10 10 10
Postmortem 总结与改进计划 40 35 40 40
合计 不重复计入分组 580 595 470 460

我的投入主要增加在测试、复审和材料整理:首次发布成功只是开始,还要检查保存失败、取消编辑、连续选图以及删除后的搜索结果。AI 辅助减少了重复编码,但对照需求审阅代码、复跑测试和验证页面仍需要投入时间。

吴圣洲的完善工作集中在界面、文档和首页列表边界。首页限制为最新 30 条之后,还必须确认搜索仍可查到全部记录、类型筛选统计正确以及原数据没有被截断。这些工作说明“小功能”也需要明确边界和对应测试。

四、解题思路与设计实现

4.1 原型中保留什么,程序中补充什么

我们保留了第一次原型的五个主要页面和核心操作顺序,重点补充真实的数据处理:

  • 发布前清理首尾空格,检查必填项、类别、长度和日期。
  • 每条信息使用唯一编号,详情按编号读取,避免展示错位。
  • 只有本浏览器标记为自己发布的记录可以编辑、删除或更新状态。
  • 更新前先保存;写入失败时保留原记录和表单,不提示成功。
  • 从搜索结果进入详情后,返回列表保留已有搜索条件。
  • 补充无结果、信息不存在、复制失败、照片处理失败和存储异常等分支。

原型中“点一下有反应”与程序中“操作完成并正确保存”是两件事。这次我们主要把后者落实到函数、状态和反馈中。

4.2 模块划分

模块 职责
js/core.js 发布校验、数据创建、搜索、首页 30 条限制、状态规则、编辑删除和个人统计
js/storage.js 数据读取、格式与版本检查、本地写入及失败反馈
js/app.js 共享数据、导航、通用卡片、首页和发布/编辑表单
js/pages/search.js 搜索条件、组合筛选、清空条件和结果列表
js/pages/detail.js 详情、联系、复制和相似线索展示
js/pages/my-posts.js 我的统计、状态筛选及管理操作
js/images.js 图片校验、压缩、选择状态和图片渲染
js/recommendations.js 名称相似度、类别与时间筛选、排序及推荐理由
js/clipboard.js 联系方式复制的异步成功/失败判断

业务规则尽量不直接操作 DOM,因此可以在 Node.js 中单独测试。页面模块负责展示结果,保存模块统一处理写入。首页、搜索、详情和“我的发布”读取同一份数据,减少各页面状态不一致的可能。

4.3 数据结构与状态

一条记录的主要字段如下,示例联系方式为虚构内容:

{
  id: 'post-example',
  type: 'lost',
  title: '黑色雨伞',
  category: '生活用品',
  place: '食堂门口',
  eventTime: '2026-10-06 12:00',
  createdAt: '2026-10-06T04:10:00.000Z',
  description: '黑色长柄,伞柄有蓝色标签',
  contact: '演示微信 demo',
  owner: '我',
  isMine: true,
  status: 'active',
  image: ''
}

eventTime 是丢失/捡到时间,createdAt 是发布时间。列表按发布时间排序,推荐使用事件时间比较,避免混用这两个概念。

信息类型 active 显示 completed 显示
寻物 lost 待寻找 已找回
招领 found 待认领 已归还

编辑保留编号、发布时间、归属和完成状态;照片通过独立的图片更新规则更换或移除。状态完成后可以恢复进行中。本地 isMine 是演示版本的归属标记,不是登录认证。

4.4 主要业务流程图

以下三张图已由搭档整理并合并到仓库。

发布信息流程:

图1-发布信息流程图

填写文字和照片后,先检查输入,再尝试保存。任一步失败都应有提示,并允许用户修正后重试。

浏览、搜索、详情与联系流程:

图2-浏览查找与线索流程图

搜索条件可以组合使用。详情与联系方式对应同一条编号,线索卡片可继续进入另一条详情。

我的发布管理流程:

图3-我的发布管理流程图

状态更新、编辑和删除都要考虑取消与保存失败。取消操作不写入数据;保存成功后,各页面读取更新后的记录。

4.5 关键数据流

数据流图-模块与数据流

发布/编辑表单把输入交给业务函数,生成下一份记录集合。saveItems 调用统一存储接口,只有写入成功才替换内存中的 items,然后刷新页面。失败时保留当前数据和待提交输入。首次打开时读取本地记录;没有已存记录才使用演示数据,保存过的空列表不会重新灌入演示信息。

4.6 关键代码:保存成功后才更新页面数据

以下代码来自最终版本的 js/app.js:

function saveItems(nextItems) {
  const result = store.save(nextItems);
  if (result.ok) items = nextItems;
  return result;
}

这里不是先修改页面再尝试保存,而是依据保存结果决定是否替换共享数据。这样,存储容量不足时不会出现“页面说保存了,刷新却消失”的误导。

4.7 关键代码:组合搜索

以下代码来自 js/core.js:

function searchItems(items, options) {
  const opts = options || {};
  const type = opts.type || 'all';
  const category = opts.category || 'all';
  const words = String(opts.keyword || '').trim()
    .toLocaleLowerCase().split(/\s+/).filter(Boolean);
  return filterItems(items, type).filter(function (item) {
    if (category !== 'all' && item.category !== category) return false;
    if (opts.activeOnly && item.status !== 'active') return false;
    const haystack = [item.title, item.place, item.category, item.description]
      .join(' ').toLocaleLowerCase();
    return words.every(word => haystack.includes(word));
  });
}

例如“黑色 图书馆”要求同一条记录同时包含两个词,但两个词可以分别出现在名称和地点中。联系方式不纳入检索。首页最多显示 30 条,搜索查询的是完整数据集,因此首页的展示限制不会删除旧信息。

五、附加功能设计与展示

5.1 照片上传、压缩与保存

纯文字描述有时难以区分相似物品,因此我们给发布表单增加了选填照片。照片会出现在首页、搜索和我的卡片中,也能在详情查看较完整的比例。

图片支持 JPG、PNG、WebP,原文件不能超过 5 MB。处理时把最长边缩到 1280 像素以内,再转换为 JPEG;透明背景填充白色,图片数据控制在 500000 字符以内。图片处理完只表示预览准备完成,仍需提交并保存成功才会更新记录。

连续选择不同照片时,先选的照片可能更晚读取完。我们用递增编号判断回调是否仍属于最新选择;用户移除照片或取消编辑时,也会让旧任务失效。

下面节选自 js/images.js:

const current = ++ticket;
const previous = state.image;
emit({image: previous, busy: true, error: ''});
try {
  validateFile(file);
  const image = await process(file);
  if (!image || !validImage(image)) {
    throw Error('图片处理失败或压缩后仍过大,请换一张图片。');
  }
  if (current === ticket) emit({image, busy: false, error: ''});
} catch (error) {
  if (current === ticket) {
    emit({image: previous, busy: false,
      error: error.message || '无法读取图片,请重新选择。'});
  }
}

这个处理也覆盖“处理中移除照片”和“取消编辑恢复原发布草稿”。读取失败时保留之前照片,显示错误,不把失败当作成功。

截图-发布照片压缩预览

5.2 可解释的相似线索推荐

寻物者可能不知道已经有人发布了招领信息。我们在未完成信息的详情页增加“相似线索”,主动推荐相反类型的未完成记录,并显示推荐理由。

推荐规则先筛选,再评分:

项目 规则
类型与状态 寻物推荐招领,招领推荐寻物;排除自己和已完成记录
类别 必须属于同一类别
名称 规范化后计算相似度;低于 0.25 不推荐
时间 两条事件时间都有效时,相差超过 7 天排除
地点 根据地点文字的相似程度加分,没有地图定位
排序 名称为主,结合地点与时间;同分按发布时间和编号排序
展示 最多 3 条,显示名称、类别、地点与时间方面的匹配理由

名称相同得到最高相似度;至少两个字符的包含关系次之;其余比较连续双字集合。比如“黑色雨伞”和“蓝色雨伞”共享“色雨”“雨伞”,可以成为待核对线索;“黑色雨伞”和“黑色水杯”的相似度较低,会被排除。

以下代码来自 js/recommendations.js:

if (item.id === source.id || item.type !== opposite ||
    item.status !== 'active' || item.category !== source.category) return;
const name = similarity(source.title, item.title);
if (name < 0.25) return;
const targetTime = eventTimestamp(item.eventTime);
const validTime = Number.isFinite(sourceTime) && Number.isFinite(targetTime);
const gap = validTime ? Math.abs(sourceTime - targetTime) / DAY : NaN;
if (validTime && gap > 7) return;

推荐只是缩小人工核对范围,不代表两条信息一定属于同一物品。照片和联系方式不参与评分,地点也是文字匹配。详情每次根据最新记录重新计算,状态完成或删除后不会继续推荐该记录。

截图-相似线索推荐

5.3 首页展示上限与界面完善

搭档在最终版本中增加首页最新 30 条限制,避免记录较多时首页过长。限制发生在筛选与排序之后,同时返回筛选后的总数;超出部分仍保存在本地,可从搜索页查询。

const homeLimit = 30;
function homeItems(items, type) {
  const sorted = filterItems(items, type);
  return {
    items: sorted.slice(0, homeLimit),
    total: sorted.length,
    limit: homeLimit
  };
}

搭档还统一了渐变、徽标、卡片、输入框和导航样式,并添加窄屏适配及减弱动效设置。这里更看重操作入口、错误反馈和内容层次是否清楚,最终显示效果需要通过浏览器截图展示。

六、目录说明与使用说明

6.1 目录说明

路径 内容与作用
index.html 正式程序入口
README.md 使用流程、规则和运行方法
css/style.css 全局视觉、卡片、表单、导航与响应式样式
js/core.js、js/storage.js 业务规则与本地存储
js/app.js 应用导航、共享数据、首页及发布/编辑
js/pages/ 搜索、详情和我的发布模块
js/images.js、js/clipboard.js、js/recommendations.js 图片、复制和线索推荐
js/data.js 首次运行的虚构演示记录
tests/ 9 个测试文件,共 85 个单元测试
docs/images/ 发布、浏览查找与我的发布三张流程图
docs/开发计划.md、docs/PSP.md 开发计划及初始化 PSP 预估
docs/阶段2验收.md 至 docs/阶段8验收.md 各阶段自动检查与人工验收步骤
docs/线索推荐设计.md 推荐功能规则和设计说明
prototype/ 第一次作业的参考原型及归档材料

6.2 测试人员运行方法

  1. 打开 GitHub 仓库,点击 Code → Download ZIP。
  2. 完整解压,保留 HTML、CSS、JavaScript 和目录关系。
  3. 使用 Google Chrome 打开根目录的 index.html。网页运行无需 Node.js、npm 安装或服务器。
  4. 首次会显示 5 条虚构演示信息,可先浏览、搜索和查看详情。
  5. 发布自己的寻物/招领信息,再到“我的发布”检查编辑、删除和状态更新。
  6. 在相同目录、相同 Chrome 用户配置下刷新,检查保存结果。

推荐的验收路线是:搜索“校园卡”并打开详情;展开联系方式;发布一条带照片的寻物信息;发布一条名称、类别、时间接近的招领信息;查看相似线索;取消一次状态更新,再确认完成;最后刷新页面核对状态和照片。

浏览器本地数据不跨设备共享。未提交的草稿只在本次页面运行中暂存,刷新后不会恢复;搜索条件也不持久化。读取到损坏数据时,程序显示警告并暂停写入,避免自动覆盖原记录。

七、单元测试:从“看起来正常”到明确预期

7.1 测试工具与学习过程

本项目采用 Node.js 内置的 node:test 和 node:assert/strict,无需额外安装测试库。test() 定义用例,断言比较实际结果与预期;异常分支通过 assert.throws() 检查,异步选择则控制 Promise 的完成顺序。

学习资料与复跑入口:

在 Windows 安装 Node.js 22 或更新版本后,用 PowerShell 切换到包含 index.html 和 tests 的项目根目录,执行:

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

我第一次复跑时在解压目录的上一层执行了测试,输出的测试数为 0,看起来像命令执行成功,实际没有运行项目用例。进入正确的仓库文件夹后才得到正常结果。

7.2 最终结果与测试分布

2026 年 10 月 7 日,按仓库提交 94858a87 读取最终代码,在 Node.js v24.19.0 中复跑,结果为:

tests 85
pass 85
fail 0
cancelled 0
skipped 0
todo 0
测试文件 数量 主要检查内容
core.test.js 11 排序、类型、状态文案、首页 30 条边界
publish.test.js 8 必填、空白、长度、类别与时间、创建记录
storage.test.js 7 初次载入、恢复、空列表、损坏数据和写入失败
search.test.js 10 多词、大小写、组合筛选、空结果与详情编号
my-posts.test.js 8 归属、统计、完成与恢复、持久化
manage-posts.test.js 10 编辑字段保留、权限、删除与同步
clipboard.test.js 4 成功、拒绝、接口缺失与空文本
images.test.js 15 图片规则、缩放、连续选择、取消与恢复
recommendations.test.js 12 类型、类别、名称、七天边界、排序与状态变化
合计 85 正常、异常、边界和数据一致性

image

7.3 白盒测试用例设计

下面按代码中的判断分支说明部分用例。表中“通过”指对应自动用例已通过。

编号 检查目标 输入或操作 预期结果 结果
T01 发布必填校验 名称、地点、联系方式只填空格 校验失败,错误定位到对应字段 通过
T02 文本边界 名称 40/41 字,描述 500/501 字 边界值通过,超出值拒绝 通过
T03 时间有效性 2024-02-29 与 2026-02-30 闰日通过,非法日期拒绝 通过
T04 类型与类别 非法枚举值 不创建记录 通过
T05 多关键词 AND “黑色 图书馆”及“雨伞 食堂” 前者命中对应记录,后者无结果 通过
T06 组合条件 名称、类别、类型与仅未完成叠加 必须同时满足条件 通过
T07 检索边界 查询联系方式或 .* 联系方式不参与匹配,特殊字符不作正则 通过
T08 首页上限 3/30/35 条场景 不足全部显示,正好不截断,超出只显示最新 30 条 通过
T09 数据不变性 排序、搜索、截断、编辑或删除 不修改传入数组与原记录 通过
T10 修改归属 他人记录或不存在编号 业务函数拒绝操作 通过
T11 状态恢复 标记完成,再恢复进行中 文案、未完成检索及推荐对应变化 通过
T12 编辑保持字段 修改名称和地点,并传入伪造 ID/状态 更新允许字段,保留编号与完成状态 通过
T13 空列表保存 删除全部自己的记录后保存空数组 重新读取仍为空,不恢复演示数据 通过
T14 存储异常 损坏 JSON、读取受限、容量不足 不覆盖原记录,返回失败或警告 通过
T15 图片校验 SVG、空文件、超过 5 MB 和无效数据 拒绝处理,保留原照片 通过
T16 图片异步顺序 第二张先完成,第一张后完成 以最后选择的照片为准 通过
T17 移除与取消 图片处理中移除或恢复草稿 迟到回调不能重新覆盖照片 通过
T18 推荐时间边界 相差 7 天及 7 天零 1 分钟 前者保留,后者排除 通过
T19 推荐更新 候选完成、恢复或删除 线索相应消失、恢复或移除 通过
T20 复制异常 剪贴板拒绝、接口缺失、空文本 不误报复制成功 通过

7.4 部分真实测试代码

以下节选自 tests/search.test.js。items 是文件中定义的固定样例:

const ids = options => searchItems(items, options).map(x => x.id);
test('多个关键词需同时命中,可分别命中不同字段', () => {
  assert.deepEqual(ids({keyword: '黑色  图书馆'}), ['1']);
  assert.deepEqual(ids({keyword: '黑色 食堂'}), ['2']);
  assert.deepEqual(ids({keyword: '雨伞 食堂'}), []);
});

第一条判断两个词能否分别命中不同字段,第二条确认描述中的颜色也参与匹配,第三条提供不命中的情况。这样测试的是检索规则,不只是“返回了一个数组”。

以下来自搭档补充的 tests/core.test.js:

test('首页上限为 30 条,超出时只保留最新 30 条', () => {
  const list = manyItems(35);
  const shown = homeItems(list, 'all');
  assert.equal(homeLimit, 30);
  assert.equal(shown.limit, 30);
  assert.equal(shown.total, 35);
  assert.equal(shown.items.length, 30);
  assert.deepEqual(shown.items.map(x => x.id),
    list.slice().reverse().slice(0, 30).map(x => x.id));
});

它同时检查总数、显示数量和具体顺序,防止把“删除了旧数据”误写成“只限制首页展示”。

7.5 如何考虑测试人员的“刁难”

设计测试时,我不只考虑完整输入,而是先找出每个分支的触发条件:空串与空白、恰好到上限与超出一字、合法闰日与日期溢出、本人和他人记录、先后顺序相反的异步任务,以及保存成功和失败。

真实浏览器还需要补充另一类检查:照片是否显示正确,确认框选取消后是否保持原状态,复制成功后能否粘贴到记事本,返回详情是否保留筛选,窄屏中按钮是否可点击。这些检查要按“操作、预期、实际”记录,而不能用函数测试代替。

八、GitHub 签入与协作记录

我们按功能逐步提交,使原型归档、页面搭建、核心操作、附加功能和搭档完善可以分开检查。下面列出主要提交;短编号可以在仓库中检索。

提交 提交内容 贡献者
0d81baed 归档第一次原型,添加开发计划和 PSP 预估 秦文贵
4e8a216f 页面框架、首页浏览和类型筛选 秦文贵
6c2c49dc 发布、表单校验和本地保存 秦文贵
e8d3fee9 组合搜索、详情和返回列表 秦文贵
2bbfba06 复制、我的发布和状态更新 秦文贵
eaf8c0b5 编辑、删除和取消编辑 秦文贵
565d9f8d 照片上传、预览和本地保存 秦文贵
f10a6062 相似线索推荐与匹配理由 秦文贵
06a8664f 按使用流程重写 README 吴圣洲
16e27afc 补充三张使用流程图 吴圣洲
faaedf8d 首页最新 30 条限制与新增单元测试 吴圣洲
f0d2a302 重构全局样式,优化页面视觉与图标 吴圣洲
1c40e6ad 合并 PR #2 秦文贵

image

九、遇到的问题、尝试与解决方法

9.1 解压和增量更新容易混淆

开发采用分阶段更新,我曾不确定应该上传累积项目的全部文件,还是只上传新阶段解压出的内容。外层压缩包目录如果直接上传,也可能让代码多出一层目录,导致 HTML 找不到脚本。

处理方法是:本地把本次包内内容合并到同一个项目根目录,替换同名文件并保留之前文件;GitHub 上传本次增量包内的内容,保持根目录下的 index.html、css/、js/ 等结构。更新后再检查路径和测试数量。

9.2 保存失败与异步选图的潜在问题

这两类不是已确认发生在我电脑上的故障,而是实现时主动处理并用测试检查的风险:保存失败后如果仍然更新内存,页面与刷新结果会不一致;连续选图如果不区分任务,较早的读取可能覆盖最新选择。

我们分别采用“先保存、后更新共享数据”和“递增任务编号、忽略过期回调”。对应存储失败、图片乱序与取消操作的自动测试已通过,浏览器层面的反馈仍按验收步骤核对。

十、个人总结与对搭档的评价

10.1 我的总结

这次作业让我更明确地理解了从原型到程序的差别。原型主要描述页面和操作顺序,程序则必须说明输入怎样进入记录、记录怎样保存、失败时怎么办,以及一次修改如何影响其他页面。

我负责主体实现,开始时更关注发布、搜索和详情能否跑通。随着功能增加,我发现最容易遗漏的往往是边界:编辑是否保留完成状态,取消是否恢复草稿,删除后搜索能否继续找到旧记录,照片读取先后顺序是否影响结果。这些问题需要用规则和测试表达,而不是仅凭点几次页面判断。

本次使用 Codex 辅助代码生成、规则整理、测试和文档初稿。我负责明确需求、按阶段整合与提交、安装环境并复跑测试,再根据实际结果调整。AI 能帮助加快实现,但测试数量、权限范围、保存能力和协作贡献仍需要自己核对,不能把生成结果直接当作已经验收的成果。

后续我会改进两点:一是在开发开始时就统一数据字段、目录和测试命令,减少交接时的歧义;二是把实际时间与问题记录同步写下来,避免最后只能靠回顾估算。功能增加时,也应尽早讨论分工,让搭档更早参与接口和边界的确认。

10.2 我对吴圣洲的评价

值得学习的地方:

吴圣洲在这次合作中表现出了认真负责的态度,也能主动考虑项目还有哪些地方需要完善。主体功能完成后,他没有只停留在“程序能够运行”,而是进一步调整页面样式、补充使用说明和流程图,让项目更便于使用和验收。我觉得他比较突出的优点是做事细致,既关注功能,也重视用户能否看懂、操作是否顺畅以及文档是否清楚。

他值得我学习的一点,是修改功能时会同时考虑边界和验证。例如,增加首页最新 30 条限制时,他也补充了相应测试,检查数量、排序和类型筛选,避免界面调整影响已有数据。这让我认识到,完善一个功能不能只看正常情况下的效果,还应该说明它在不同条件下是否正确。

需要改进的地方:

我认为吴圣洲还可以改进的地方,是更早参与整体设计,并在提交修改时补充更具体的说明。这次他的工作主要集中在主体完成后的完善,如果能在开发初期就一起讨论界面布局、功能边界和验收标准,一些调整就可以提前落实,减少后期集中修改的压力。另外,PR 中除了说明“完善了什么”,还可以写清修改原因、测试方法和结果,让我在合并时更容易判断改动的影响。这也是我们双方下一次合作都需要加强的地方:及时沟通,并把修改依据和验证过程记录清楚。

十一、成果展示与后续改进

本次完成了首页浏览、发布校验、本地保存、组合搜索、详情与联系方式、我的发布管理、照片和相似线索推荐。搭档进一步补充首页展示限制、视觉样式和使用流程说明。项目按功能提交,并通过 PR 合并双方成果,最终 85 个单元测试全部通过。

当前版本仍受本地数据范围限制,规则推荐也可能遗漏同义词或产生相似物品误报。后续可以评估统一后端数据、真实身份机制、同义词和地点规范化,但应先确保当前的核心流程与异常反馈在最终浏览器验收中稳定。

对我而言,这次最主要的收获是:完成项目不只是让功能出现,还要让数据、页面、测试、文档和协作记录彼此一致。

posted @ 2026-10-07 17:20  vvgor  阅读(6)  评论(0)    收藏  举报