2026秋软件工程结对作业(第二次之程序实现)
校园失物招领 —— 结对作业 2(程序实现)
1. 开头信息:队员信息与仓库地址
表格
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 软件工程 |
| 这个作业要求在哪里 | 结对作业 2 |
| 这个作业的目标 | 完成一个校园失物招领程序 |
| 仓库地址 | https://github.com/ACAct/102402120-102402119 |
| 本人 | 学号:102402119 姓名:陈封 |
| 结对同学 | 学号:102402120 姓名:陈睿涛 |
呈现形式:PC 端 Web 网页。原生 HTML + CSS + JavaScript,零依赖、零构建,用谷歌浏览器打开根目录 index.html 即可运行。
2. 具体分工
分工依据来自仓库的真实 commit 记录(可执行 git shortlog -sne 复核):ACAct 13 次提交,cf919 4 次提交 + 1 个 Pull Request。
表格
| 成员 | 承担内容 | 对应提交 |
|---|---|---|
| cf919(本人) | Fork 仓库、创建功能分支 feat/publish‑flow,基于主干已有的数据模型、公共组件开展开发 |
— |
| 发布页完整表单实现、寻物 / 招领切换逻辑、字段级表单校验、表单状态保留 | 4dfddcd |
|
| 发布成功页面、我的发布页面开发;实现状态标记 / 撤销标记业务逻辑;本地身份识别演示模式 | f24715f |
|
| 编写发布流程整套冒烟测试,覆盖表单校验、提交入库、状态流转、空状态等场景 | 6cede20 |
|
| 完善项目 README 文档,编写目录结构、运行指引、操作走查表 | 662b0bb |
|
| 提交 Pull Request #1,整理改动清单,等待主干复审合并 | PR #1 | |
| ACAct(结对队友) | 归档第一次作业原型,搭建项目基础目录、公共框架、全局组件、路由体系 | caf45df、027cc85 |
| 数据模型 Item、仓储 repository、种子演示数据,完成核心单元测试 | 283eb17 |
|
| 首页、搜索页、详情页业务实现与对应单元、冒烟测试 | 4eac818、6019208、1ef6232 |
|
| PR 复审合并,定位并修复合并引入的样式丢失缺陷,完善样式完整性自动化检查 | 57482d1、511ef5f |
协作方式:队友搭建主干框架、数据层、首页 / 搜索 / 详情页面,把公共组件、数据访问接口全部封装完毕。我 Fork 主干,新建独立功能分支,专注开发发布全链路模块:发布页表单、发布成功页、我的发布状态管理;写完业务代码之后同步编写对应冒烟测试,最后提交 PR;队友做代码复审合并,合并后暴露出样式冲突缺陷,双方共同定位问题修复主干。
结对编程的收获:
- 前置接口约定,降低并行开发冲突。开发前约定好数据模型、组件调用方式、路由常量,我不需要修改底层 core/data,只调用对外暴露的 API,实现两人并行开发,减少代码互相覆盖。
- 功能分支 + PR 模式,变更可控。整块业务放在独立分支开发,PR 可以清晰看到全部改动文件,测试用例也一并附带,复审者可以完整评审逻辑、测试、文档,比直接向主干 push 更加安全。
- 缺陷复现优先于主观描述。合并后出现样式丢失问题,一开始只描述 “页面样式没了” 很难定位,借助 git diff 比对文件差异,精准定位 css 合并冲突,极大提升排错效率。
- 测试跟随业务同步开发,不是写完功能再补测试。写发布表单业务逻辑的时候同步写冒烟用例,每一个交互逻辑对应一条断言,改动业务可以快速验证是否破坏原有逻辑。
3. PSP 表格
表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 20 | 25 |
| Estimate | 估计这个任务需要多少时间 | 15 | 15 |
| Development | 开发 | 750 | 845 |
| Analysis | 需求分析(包括学习新技术) | 60 | 75 |
| Design Spec | 生成设计文档 | 45 | 55 |
| Design Review | 设计复审 | 20 | 20 |
| Coding Standard | 代码规范 | 20 | 15 |
| Design | 具体设计 | 90 | 110 |
| Coding | 具体编码 | 330 | 400 |
| Code Review | 代码复审 | 40 | 60 |
| Test | 测试(自我测试,修改代码,提交修改) | 90 | 110 |
| Reporting | 报告 | 160 | 190 |
| Test Report | 测试报告 | 40 | 45 |
| Size Measurement | 计算工作量 | 20 | 20 |
| Postmortem & Process Improvement Plan | 事后总结,并提出过程改进计划 | 45 | 55 |
| 合计 | 1030 | 1155 |
4. 解题思路描述与设计实现说明
4.1 代码实现思路,文字描述
技术选型
继承主干确定的技术方案:原生 HTML+CSS+JavaScript,零依赖零构建,双击 index.html 直接 Chrome 打开运行。
- UMD 模块包装 JS 脚本,一份代码同时支持浏览器挂载
window.LF全局对象、Node 环境 require 导入用于单元冒烟测试。 - 页面跳转全部使用原生
<a href>,兼容file://本地文件协议,不使用 history API。 - 存储层全部调用
repository对外 API,不直接操作 localStorage,自动适配存储不可用降级为内存。
分工模块分层理解
主干已经完成:core通用工具函数、schema常量枚举、data数据模型与仓储、components通用 UI 组件(图标、布局、卡片);
我负责实现的页面层(pages):
- publish.js 发布页:表单 UI 渲染、寻物 / 招领切换、表单内存状态维护、字段级校验、提交调用
item.create+repository.add完成新建信息;切换类型保留用户已经填写表单内容;提交失败定位到首个错误字段;记录发布者称呼用于我的发布身份识别。 - success.js 发布成功页:读取 url 参数 id,渲染发布信息摘要,提供三个跳转入口;id 不存在优雅降级。
- myposts.js 我的发布页:读取本地存储的发布者名字筛选本人发布记录;无本地记录进入演示模式展示全部数据;实现标记已找到 / 已归还、撤销标记;调用
repository.updateStatus完成状态更新;支持类型筛选、空状态引导发布。
页面控制器尽量薄,业务校验、数据操作全部复用 core/data 层提供函数,不在页面内部重复写校验逻辑。页面只负责:渲染 DOM、绑定事件、收集表单输入、调用底层 API、处理页面跳转。
三个关键设计决策
① 表单内存状态与 DOM 分离,切换类型保留填写内容
如果直接操作 DOM 取值,切换寻物 / 招领卡片会造成输入丢失。维护一份内存 state 对象,所有表单修改同步更新 state;切换类型只修改 state.type,重渲染页面,state 其他字段保留不变,不会清空用户填写。
var state = {
type: schema.TYPE.LOST,
title: '',
description: '',
// 其他表单字段
};
② 我的发布不实现登录,使用本地存储发布者称呼做身份识别
作业不要求登录注册,使用发布表单提交的时候存入lf.myPublisher.v1本地存储的发布者名字。
- 有记录:过滤列表,只展示 publisher.name 匹配本人称呼的数据。
- 无记录:演示模式展示全部种子数据,页面给出明确文字提示,告知用户当前是演示。
③ 表单校验复用 item 模型 validate,不重复手写校验规则
不在页面写一堆 if 判断做校验,直接调用itemModel.validate()复用底层已经写好的字段约束。页面只负责把返回的 errors 集合渲染到界面。好处:底层修改字段长度、约束规则,发布页面不需要同步修改代码,避免两套校验逻辑不一致。
4.2 关键实现的流程图 / 数据流图
图 1:发布模块完整业务流程
图 2:我的发布状态变更流程
图 3:发布表单数据流
4.3 贴出重要的代码片段并解释
片段一:发布页切换类型保留表单状态
function setType(type) {
if (type !== schema.TYPE.LOST && type !== schema.TYPE.FOUND) return;
if (state.type === type) return;
syncFromDom(); // 先把当前DOM输入同步到内存state
state.type = type;
errors = {}; // 切换类型清空旧错误提示
render(); // 重渲染页面,state其他字段不会被清空
}
解释:syncFromDom()读取 DOM 当前输入同步到内存 state;修改 type 之后直接重渲染页面,title、location 等用户已经填写内容保存在 state 对象中不会丢失,仅仅修改标签文案、占位符、提交按钮文字,解决切换类型表单内容清空的糟糕体验。
片段二:发布页表单校验复用底层 item 模型,页面只负责渲染错误
function validateForm() {
var result = itemModel.validate({
type: state.type,
title: state.title,
description: state.description,
category: state.category,
location: state.location,
lostAt: state.lostAt,
contactType: state.contactType,
contactValue: state.contactValue
}, { now: Date.now() });
errors = {};
Object.keys(result.errors).forEach(function (key) { errors[key] = result.errors[key]; });
// 补充表单独有的发布者称呼校验
if (!util.normalize(state.publisherName)) {
errors.publisherName = '请填写你的称呼,方便同学联系你';
}
return Object.keys(errors).length === 0;
}
解释:表单校验不自己写一大堆 if 条件,复用itemModel.validate(),底层 schema 定义的全部约束(长度、时间不能为未来、枚举合法)全部复用。页面仅补充发布者称呼这个表单层特有校验,拿到 errors 集合直接渲染到各个表单字段。后续修改字段限制只需要修改 data 层,不需要修改发布页代码。
片段三:我的发布身份识别逻辑,区分正常模式与演示模式
function myItems() {
var all = repository.list({ type: state.type });
var name = state.publisherName;
if (!name) {
state.demoMode = true;
return all; // 无身份记录,演示模式返回全部信息
}
state.demoMode = false;
var mine = all.filter(function (item) {
return item.publisher.name === name;
});
return mine;
}
解释:没有登录系统,读取浏览器本地存储的发布者名字;没有记录打开页面直接展示全部种子数据,同时页面展示demo‑tip提示文字告知用户当前是演示模式;当用户真正发布一条信息写入本地称呼之后,自动切换正常模式只展示本人发布记录。
片段四:提交发布成功,记录发布者身份用于我的发布识别
repository.add(created.item);
// 将本次发布者称呼存入本地存储,作为我的发布识别依据
util.storage.set('lf.myPublisher.v1', created.item.publisher.name);
layout.go('success', 'id=' + encodeURIComponent(created.item.id));
解释:发布成功之后,把填写的发布者称呼存入 storage;进入我的发布页面读取这个 key 的值做数据过滤,实现 “只看我发布” 的效果。
片段五:冒烟测试,模拟发布完整流程
fill(h, {
type: 'found',
title: '捡到一只黑色保温杯',
description: '杯身有划痕,贴着星星贴纸',
category: 'bottle',
location: '三食堂二楼',
locationDetail: '二楼服务台',
lostAt: '2026-09-25T12:30',
contactType: 'wechat',
contactValue: 'finder_wx',
publisherName: '测试同学',
publisherDept: '计算机学院'
});
page.submit();
assert.strictEqual(repo.list().length, before + 1, '应新增 1 条信息');
assert.strictEqual(calls.length, 1, '应发生一次跳转');
assert.strictEqual(calls[0].name, 'success');
解释:在 dom‑harness 测试桩环境,模拟完整填写表单、提交,断言仓储新增数据,跳转 success 成功页,在无浏览器环境验证发布全链路流程。
5. 附加特点设计与展示(本人负责模块相关)
5.1 特点一:发布页切换寻物 / 招领,保留用户已经填写表单内容
设计的创意独到之处与意义
用户填了一半表单,切换 “寻物 / 招领”,如果直接清空全部输入,会严重打击用户体验。很多同类表单切换类型直接清空所有输入,需要用户重新填写。这里做到切换类型,只修改标签文案、占位提示文字,物品名称、地点、描述、联系方式等用户输入全部保留,用户只需要修改少量不匹配内容。
实现思路
表单数据和 DOM 解耦,全部维护在页面内存state对象。切换类型之前,调用syncFromDom()把当前 DOM 输入同步到内存 state,仅仅修改 state.type,清空旧的校验错误,然后调用 render 重渲染页面。内存 state 保存用户填写的其他字段,渲染的时候回写到 input value,实现内容保留。
代码片段
/** 从DOM读取全部表单值写入state(重绘前调用,避免丢输入) */
function syncFromDom() {
var fields = document.querySelectorAll('[data-field]');
Array.prototype.forEach.call(fields, function (el) {
var key = el.getAttribute('data-field');
if (key && Object.prototype.hasOwnProperty.call(state, key)) {
state[key] = el.value;
}
});
}
function setType(type) {
if (type !== schema.TYPE.LOST && type !== schema.TYPE.FOUND) return;
if (state.type === type) return;
syncFromDom();
state.type = type;
errors = {};
render();
}
实现成果说明
- 用户填写物品名称、地点、联系方式,切换寻物 / 招领卡片,已填写内容不会丢失;
- 仅动态切换:丢失 / 拾取时间、丢失 / 拾取地点标签、输入框 placeholder、底部提交按钮文案;
- 切换同时清空之前表单校验错误提示,避免旧错误残留。
实现结果展示


5.2 特点二:表单字段级校验,提交失败自动滚动并聚焦第一个错误项
设计的创意独到之处与意义
表单提交全部不合法的时候,不能只是弹一句 “表单有误”,用户不知道哪里填错。需要每一个字段展示对应的错误文字;并且自动滚动视图定位到第一个出错输入框,光标聚焦,直接引导用户修改第一项错误,减少用户查找错误的成本。
实现思路
- 提交表单调用 validateForm,得到 errors 对象;
- render 页面,每个表单字段读取 errors,渲染
.has‑error样式和field‑error错误提示; - 获取 errors 第一个 key,用
document.querySelector拿到对应data‑fieldDOM 元素;执行scrollIntoView平滑滚动,并且调用 focus 聚焦输入框。
代码片段
/** 把首个出错的字段滚动到可视区并聚焦 */
function focusFirstError() {
var names = Object.keys(errors);
if (!names.length) return;
var el = document.querySelector('[data-field="' + names[0] + '"]');
if (!el) return;
if (el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'center' });
if (el.focus) el.focus();
}
实现成果说明
全部留空直接提交发布,页面逐项标红报错,页面平滑滚动到第一个必填项(物品名称输入框),输入框自动获得焦点。
实现结果展示

6. 目录说明和使用说明
项目完整目录同仓库 README,本人主要负责开发文件清单
102402120‑102402119/
├── publish.html 发布页(本人开发)
├── success.html 发布成功页(本人开发)
├── myposts.html 我的发布页面(本人开发)
│
├── js/pages/
│ ├── publish.js 发布页控制器:表单、校验、提交(本人开发)
│ ├── success.js 发布成功页控制器(本人开发)
│ └── myposts.js 我的发布控制器:身份识别、状态标记撤销(本人开发)
│
├── tests/
│ ├── smoke‑publish.js 发布页冒烟测试(本人编写)
│ ├── smoke‑myposts.js 成功页、我的发布冒烟测试(本人编写)
│
├── README.md 项目使用文档(本人补充完善)
测试人员如何运行
环境:谷歌 Chrome 浏览器,无需 Node、npm,双击 index.html 直接打开
- git clone 或者下载 zip 解压整个仓库;
- 双击
index.html打开首页; - 核心操作走查表(本人负责模块相关)
表格
| 步骤 | 操作 | 预期结果 |
|---|---|---|
| 1 | 首页点击我要寻物,填写部分表单,切换 “我要招领” | 已填写表单保留,标签文字切换 |
| 2 | 发布页全部留空直接提交 | 逐项标红报错,滚动聚焦第一个错误,不会新增数据 |
| 3 | 填写完整表单提交 | 跳转发布成功页,展示发布信息摘要卡片 |
| 4 | 发布成功页点击前往我的发布 | 进入我的发布,看到刚刚发布的条目 |
| 5 | 我的发布点击标记已找到 | 卡片状态更新,统计数字同步变化,按钮变成撤销标记 |
| 6 | 点击撤销标记 | 恢复为寻找中 |
| 7 | 清除浏览器本地存储打开我的发布 | 展示全部演示数据,顶部演示模式提示 |
| 8 | 直接访问 success.html 不带 id | 不白屏,显示发布成功通用提示 |
边界说明:
本项目纯前端演示,没有后端登录;我的发布依靠浏览器本地存储记录发布称呼;file:// 协议 localStorage 不可用时数据刷新重置。
7. 单元冒烟测试(本人负责模块部分)
7.1 测试工具
复用项目统一方案,Node 内置node:test+node:assert,搭配dom‑harness.jsDOM 桩,不启动真实浏览器,在 Node 环境模拟页面初始化、DOM 渲染。
本人编写:smoke‑publish.js、smoke‑myposts.js两套冒烟测试,覆盖发布全链路。
7.2 代表性冒烟测试代码片段
用例 1:发布页切换类型,保留已经填写的输入
/* ---- 6. 类型切换保留已填内容 ---- */
{
const h = buildPage('');
const page = h.global.LF.pages.publish;
fill(h, { title: '已填写的名称', location: '已填写的地点' });
page.setType('found');
assert.strictEqual(page.state.title, '已填写的名称', '切换类型不应丢失名称');
assert.strictEqual(page.state.location, '已填写的地点', '切换类型不应丢失地点');
assert.strictEqual(page.state.type, 'found');
console.log('类型切换 -> 保留输入 + 拒绝非法值 OK');
}
用例 2:发布页表单全部为空提交,校验失败,不写入仓储
/* ----3. 必填校验:全空提交应逐项报错且不入库 ---- */
{
const h = buildPage('');
const page = h.global.LF.pages.publish;
const repo = h.global.LF.repository;
const before = repo.list().length;
page.state.title = '';
page.state.location = '';
page.state.contactValue = '';
page.state.publisherName = '';
page.state.lostAt = '';
page.submit();
const errs = page.errors();
assert.ok(errs.title, '应提示物品名称必填');
assert.ok(errs.location, '应提示地点必填');
assert.ok(errs.contactValue, '应提示联系方式必填');
assert.ok(errs.publisherName, '应提示称呼必填');
assert.ok(errs.lostAt, '应提示时间必填');
assert.strictEqual(repo.list().length, before, '校验失败不应写入数据');
console.log('必填校验 -> 逐项报错且不入库 OK');
}
用例 3:我的发布状态闭环:标记已解决,撤销标记
/* ----5. 状态维护闭环:标记已解决 → 状态与统计同步 → 撤销 ---- */
{
const h = buildPage('');
const repo = h.global.LF.repository;
const page = h.global.LF.pages.myposts;
const target = repo.list().find((i) => !i.resolved && i.type === 'lost');
page.toggleStatus(target.id, true);
const after = repo.get(target.id);
assert.strictEqual(after.resolved, true, '应已标记为已解决');
assert.strictEqual(after.status, 'found', '寻物信息应变为已找到');
assert.ok(after.resolvedAt, '应记录解决时间');
page.toggleStatus(target.id, false);
const reverted = repo.get(target.id);
assert.strictEqual(reverted.resolved, false, '应已撤销标记');
assert.strictEqual(reverted.status, 'ongoing', '应回到寻找中');
assert.strictEqual(reverted.resolvedAt, null, '撤销后清空解决时间');
console.log('状态维护闭环 -> 标记/撤销 + 统计同步 OK');
}
用例 4:我的发布无身份记录,进入演示模式
/* ----3. 无身份记录:演示模式展示全部信息并给出说明 ---- */
{
const h = buildPage('');
h.global.LF.pages.myposts.init();
const html = h.document.getElementById('content').innerHTML;
assert.ok(html.includes('本地还没有你的发布记录'), '应说明处于演示模式');
console.log('我的发布(演示) -> 全部信息 + 说明 OK');
}
7.3 测试设计思路与边界考虑
针对发布链路,重点覆盖等价类、边界、异常场景:
- 正常流程:完整填写表单提交,入库,跳转成功页;
- 表单边界:字段最大长度、时间不能选择未来;切换类型表单保留;
- 异常表单:全部为空提交;部分字段空白;未来时间提交;非法枚举;
- 我的发布边界:无本地身份演示模式;有身份但是零发布的空状态;标记、撤销状态闭环;操作不存在 id 不抛出异常;
- 页面降级:success 页面不带 id 参数,不会白屏;
- DOM 桩环境模拟,不依赖浏览器,运行
node tests/run‑all.js即可执行冒烟。
局限:DOM‑harness 只是简易 DOM 桩,不会执行真实浏览器布局,剪贴板、真实交互需要人工浏览器验证。自动化测试保证业务逻辑、渲染结构正确。
8. GitHub 的代码签入记录截图
命令行等价输出(截至最新提交):
$ git log --oneline -13
511ef5f fix: 修复合并后丢失的页面样式与冒烟测试调度
57482d1 Merge pull request #1 from cf919/feat/publish-flow
6cede20 test: 新增发布流程冒烟测试用例
f24715f feat(flow): 实现发布成功页与我的发布页面
4dfddcd feat(publish): 实现发布页表单、字段级校验与提交入库
662b0bb docs: 补充 README 的目录说明与使用说明
1ef6232 feat(detail): 实现信息详情页与联系方式、状态处理
6019208 feat(search): 实现搜索页与关键词检索、相关性排序
4eac818 feat(home): 实现首页信息流、类型筛选与排序
283eb17 feat(data): 设计数据结构与数据访问层,并补充单元测试
027cc85 feat(structure): 搭建项目目录结构与公共框架
caf45df chore: 归档第一次结对作业的6页HTML原型
5235606 Merge branch 'main' of https://github.com/ACAct/102402120-102402119
$ git shortlog -sne
13 ACAct <13505079463@163.com>
4 cf919 <3468918156@qq.com>
commit 信息是如何合理记录的:
- 按功能划分,每完成一个可运行的功能提交一次,而不是攒到最后一次性提交。提交信息采用
type(scope): 摘要格式(feat/fix/docs/chore/test)。 - 提交正文说明「为什么」而不只是「做了什么」。例如数据层那次提交在正文里写明「status 一律由 type + resolved 派生,杜绝『寻物 + 已归还』这类矛盾状态」,让复审者能直接看懂设计意图,不必反推代码。
- 修复类提交说明问题现象与影响范围。例如
511ef5f的正文写明了「发布页、我的发布、发布成功页的样式在合并后全部丢失,三个页面渲染出来是没有任何样式的裸 HTML」,便于日后追溯。
9. 遇到的代码模块异常或结对困难及解决方法
问题一:切换寻物招领卡片,填写的表单输入全部丢失
- 问题描述:一开始切换类型卡片,DOM 重渲染,用户已经输入全部清空。一开始只操作 DOM,每次 setType 之后直接清空重渲染 HTML,内存没有保存表单数据。
- 尝试:一开始尝试只修改标签文字,不重渲染整个表单;但是标签、placeholder、提交按钮分散多处,改动复杂,容易遗漏。
- 解决:把全部表单状态抽离到 JS 内存 state 对象;每次重渲染之前调用
syncFromDom()把 DOM 输入同步到 state,渲染的时候再把 state 写回 input value。切换 type 仅仅修改 state.type,其他字段保留。 - 收获:复杂表单,DOM 只做渲染,业务状态保存在 JS 内存对象,避免完全依赖 DOM 取值,是保留输入的关键。
问题二:表单校验写完,但是底层 item 模型校验和页面表单校验两套规则不一致
- 问题描述:一开始我自己在页面写一堆 if 判断做表单校验,后来发现和
item.js底层 validate 的约束出现冲突,比如最大长度一个改了另一个没改。 - 尝试:把页面手写的 if 校验全部删掉,页面表单收集完输入,直接调用
itemModel.validate()复用底层校验规则,页面只补充发布者称呼这个表单特有校验。 - 解决:表单校验全部复用 data 层模型,页面只负责展示错误;后续修改字段约束,只需要修改一处,避免两套规则不一致。
- 收获:业务校验逻辑下沉到领域模型,页面控制器尽量薄,不要重复实现业务规则。
结对协作上的困难
- 接口约定的问题:两人分别实现不同页面,容易出现「我封装的函数对方不知道怎么用」。应对方式是把公共部件(状态栏、底部导航、卡片、路由表)全部收敛到
js/components/,页面只调用不重写;数据访问统一走repository,页面不直接读写存储。 - 合并时机的选择:队友的分支存在时间较长,导致样式文件与主干长期分叉。教训是公共文件(尤其是样式)的改动应尽早合入主干,或者开工前先同步一次主干。
- 问题复现比描述更有效:样式丢失问题如果只说「页面变丑了」,很难定位;先在本地用
git diff定位到具体文件与行数差异,沟通效率完全不同。
10. 评价队友
值得学习的地方
- 队友搭建了完整底层框架、数据模型、公共组件、首页搜索详情页面,设计分层架构 core/data/components/pages,做好接口封装,让我可以专注开发发布模块,不用从零搭建底层。
- 设计非常多健壮性处理:数据 normalize 降级处理脏数据、派生 status 避免矛盾状态、存储自动降级、DOM‑harness 测试桩,工程意识很强。
- PR 合并后出现样式冲突,快速定位 git diff,新增样式完整性检查补齐自动化测试,快速修复主干缺陷。
需要改进的地方
- 开发过程中部分接口文档只有代码没有单独文档,需要读源码看懂 API;后续可以补充简单的对外接口注释,降低阅读框架成本。
附:本人交付模块规模
表格
| 项目 | 数量 |
|---|---|
| 负责页面 | publish.html、success.html、myposts.html,共 3 个页面 |
| JS 页面控制器 | publish.js、success.js、myposts.js |
| 冒烟测试脚本 | smoke‑publish.js、smoke‑myposts.js |
| 文档 | README.md 目录与运行指引补充 |
| 对应自动化断言 | 发布 + 成功 + 我的发布合计80 + 处冒烟断言 |
| 运行依赖 | 0,Chrome 浏览器直接打开 |

浙公网安备 33010602011771号