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

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

项目 内容
课程 H202601软件工程与软件工程实践
作业要求 2026秋软件工程结对作业(第二次之程序实现)
GitHub仓库 Lin-fzu/102401415-102401428
学号姓名 102401415 林豪;102401428 魏怡健
原型链接 墨刀原型(第一次结对作业)

一、具体分工

成员 分工
林豪(102401415) 需求梳理与功能范围界定;整体UI设计与样式实现;个人中心页面开发;数据模块设计;PSP记录;博客整体架构
魏怡健(102401428) 发布表单与详情页开发;页面交互与跳转逻辑;单元测试设计与执行;GitHub仓库管理;博客撰写与排版;bug修改

两人共同完成:功能走查、问题排查、博客校对。

二、PSP表格

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

实际编码与测试比预估多了约10分钟,原因是开发过程中根据墨刀原型优化了UI设计,新增了"我的"页面和返回按钮,这些内容在最初预估时没有完全考虑到。


三、解题思路与设计实现

3.1 实现思路

需求回顾:基于第一次结对作业的墨刀原型,在WEB上实现"发布寻物/招领 → 集中浏览 → 关键词搜索 → 查看详情与联系方式 → 发布者标记已找回/已归还"的完整闭环,不实现登录、实名认证、聊天、地图定位。

技术选型:纯原生 HTML + CSS + JavaScript 静态网页。理由:

  1. 作业要求"下载全部文件后用谷歌浏览器运行html即可展现预期结果",零依赖、无环境是最稳妥的交付方式;
  2. 数据量小,用浏览器localStorage即可完成持久化,不需要后端;
  3. 原生JS便于理解和调试,适合课程作业。

架构分层:

  • data.js(数据层):数据模型 + 示例数据 + localStorage读写;
  • common.js(工具层):公共函数、提示消息、时间格式化等;
  • 各页面独立JS(交互层):首页、发布页、详情页、我的页各自的业务逻辑;
  • style.css(视图层):全局样式、组件样式、响应式布局。

关键设计决策:

  1. 状态闭环:信息标记为"已找到/已归还"后写入localStorage,首页、搜索、详情都从同一数据源渲染,保证状态更新后所有页面都能看到最新结果;
  2. 异常路径全覆盖:发布信息不完整提示、搜索无结果提示、列表为空提示——不只按一条顺利成功的路线设计产品;
  3. 统一风格:所有页面采用蓝色渐变主题,卡片式设计,底部统一导航栏,顶部统一返回按钮,保持视觉一致性。

3.2 核心代码片段

数据管理模块(data.js)

使用LocalStorage实现数据的增删改查:

// 获取所有物品
function getAllItems() {
    const data = localStorage.getItem('lost_found_items');
    return data ? JSON.parse(data) : [];
}

// 添加新物品
function addItem(item) {
    const items = getAllItems();
    items.unshift(item);
    localStorage.setItem('lost_found_items', JSON.stringify(items));
}

// 根据ID获取物品
function getItemById(id) {
    const items = getAllItems();
    return items.find(item => item.id === parseInt(id));
}

// 更新物品状态
function updateItemStatus(id, status) {
    const items = getAllItems();
    const index = items.findIndex(item => item.id === parseInt(id));
    if (index !== -1) {
        items[index].status = status;
        localStorage.setItem('lost_found_items', JSON.stringify(items));
    }
}

搜索与筛选功能(index.js)

根据关键词和分类过滤物品列表:

function filterItems() {
    const keyword = searchInput.value.trim().toLowerCase();
    const type = currentFilter;
    
    let items = getAllItems();
    
    // 按类型筛选
    if (type !== 'all') {
        items = items.filter(item => item.type === type);
    }
    
    // 按关键词搜索
    if (keyword) {
        items = items.filter(item => 
            item.name.toLowerCase().includes(keyword) || 
            item.description.toLowerCase().includes(keyword)
        );
    }
    
    renderItems(items);
}

表单验证(publish.js)

提交前验证所有必填字段:

function validateForm() {
    const name = document.getElementById('itemName').value.trim();
    const description = document.getElementById('itemDesc').value.trim();
    const location = document.getElementById('itemLocation').value.trim();
    const time = document.getElementById('itemTime').value;
    const contact = document.getElementById('itemContact').value.trim();
    
    if (!name) { alert('请输入物品名称'); return false; }
    if (!description) { alert('请输入物品描述'); return false; }
    if (!location) { alert('请输入地点'); return false; }
    if (!time) { alert('请选择时间'); return false; }
    if (!contact) { alert('请输入联系方式'); return false; }
    
    return true;
}

四、附加特点设计与展示

作业要求的功能之外,我们做了两个额外设计。选它们的标准是:真正解决了失物招领这个场景里的痛点,而不是为了加功能而加功能。


特点:关键词图标映射 —— 让列表一眼可扫

1. 创意独到之处与意义

失物招领的列表页有个特点:用户是在「扫」而不是在「读」。一个人丢了一把伞,他会快速划过列表找和伞有关的条目。

问题是项目没有图片上传功能,所有卡片都是纯文字,看起来长得一模一样,找东西很费眼。

我们的做法是:从物品名称里提取关键词,映射成对应的 emoji 图标。

名称含 显示图标
校园卡 💳
雨伞 ☂️
耳机 🎧
钥匙 🔑
手机 📱
钱包 👛
书 📚
水杯 🥤
都没命中 📦(兜底)

意义:用户扫列表时,视线可以直接跟着图标走,不用逐条读文字。而且这个方案零成本 —— 不需要图床、不需要上传接口、不需要后端存储,纯前端十几行代码就实现了视觉区分度。

2. 实现思路

用一个「关键词 → emoji」的映射表,渲染每条记录时拿标题去匹配,命中就返回对应图标,都没命中就返回默认的 📦。

顺序遍历映射表、返回第一个命中的结果。因为映射表的顺序是人为安排的,把更具体的词放前面即可。

3. 代码片段

位置:js/index.js

// 物品图标映射
const itemIcons = {
    '校园卡': '💳',
    '雨伞': '☂️',
    '耳机': '🎧',
    '钥匙': '🔑',
    '手机': '📱',
    '钱包': '👛',
    '书': '📚',
    '水杯': '🥤'
};

// 获取物品图标
function getItemIcon(title) {
    for (let key in itemIcons) {
        if (title.includes(key)) {
            return itemIcons[key];
        }
    }
    return '📦';
}

五、页面展示

5.1 首页

image

  • 蓝色渐变顶部导航栏,包含平台标题
  • 白色圆角搜索栏 + 分类筛选标签(全部/寻物/招领)
  • 两个大按钮:"我丢东西了"(蓝色)和"我捡到东西了"(绿色)
  • 物品卡片列表:缩略图标、类型标签、状态、名称、地点时间
  • 底部固定导航栏:首页、发布、我的

5.2 发布页

image

  • 顶部返回按钮 + 页面标题
  • 寻物/招领类型选择器
  • 表单字段:物品名称、描述、地点、时间、联系方式
  • 必填字段验证,提交成功后跳转首页

5.3 详情页

image

  • 顶部返回按钮 + 页面标题
  • 物品完整信息展示
  • 联系方式高亮显示
  • 发布者本人可见状态更新按钮

5.4 我的页面

image

  • 蓝色渐变用户卡片:头像、姓名、已实名标签、学院信息
  • 数据统计:我的发布数、成功归还数、帮助他人数
  • 我的发布列表:展示自己发布的所有物品
  • 功能按钮组:消息通知、我的收藏、浏览记录、去搜索
  • 设置列表:默认联系方式(可弹窗修改)、认领提醒、帮助与反馈

六、目录结构与运行说明

6.1 目录结构

102401415-102401428/
├── index.html          # 首页 - 信息列表与搜索
├── publish.html        # 发布页 - 发布新信息
├── detail.html         # 详情页 - 查看物品详情
├── profile.html        # 我的 - 个人中心页面
├── list.html           # 列表页 - 通用空状态列表
├── css/
│   └── style.css       # 全局样式
├── js/
│   ├── data.js        # 数据管理与本地存储
│   ├── common.js      # 公共函数工具
│   ├── index.js       # 首页逻辑
│   ├── publish.js     # 发布页逻辑
│   ├── detail.js       # 详情页逻辑
│   └── profile.js      # 我的页面逻辑
└── README.md           # 项目说明文档

6.2 运行说明

  1. 从GitHub仓库下载全部文件(保持目录结构不变)
  2. 用谷歌浏览器(Chrome)打开 index.html,即可使用全部功能
  3. 无需安装任何环境、无需联网
  4. 数据保存在浏览器localStorage中,关闭页面再打开记录仍在

七、单元测试

7.1 测试说明

采用白盒测试方法,针对核心功能模块设计测试用例,覆盖正常流程、异常处理和边界情况。

7.2 测试用例列表

序号 测试用例 预期结果 是否通过
1 正常发布寻物信息 填写完整表单,提交后列表显示新信息 ✅
2 正常发布招领信息 切换类型为招领,提交后类型标签正确显示 ✅
3 发布信息缺少必填字段 留空字段提交,弹出提示错误 ✅
4 关键词搜索匹配结果 输入已有物品关键词,显示匹配结果 ✅
5 关键词搜索无结果 输入不存在的关键词,显示空状态提示 ✅
6 分类筛选 切换"寻物/招领"标签,列表正确过滤 ✅
7 查看物品详情 点击卡片,跳转到详情页并显示完整信息 ✅
8 更新物品状态 发布者点击标记按钮,状态变为已解决 ✅
9 数据持久化 刷新页面后,已发布的信息仍然存在 ✅
10 状态更新权限 非发布者看不到状态修改按钮 ✅
11 我的发布列表 个人中心正确显示当前用户发布的所有物品 ✅
12 返回按钮 所有二级页面点击返回按钮可正确返回上一页 ✅

7.3 测试评价

以上12个测试用例覆盖了正常流程、异常处理、边界情况和权限控制,能够基本验证程序的正确性。测试根据代码逻辑设计用例,确保核心功能模块都被覆盖到。

八、Github的代码签入记录截图

image

九、遇到的代码模块异常或结对困难及解决方法

详情页「标记为已找到」按钮完全失效

问题描述:按钮点了没反应,不报错,还时好时坏 —— 从首页进能点,刷新后就不能点。

一、做过哪些尝试:

  1. 怀疑 CSS 遮挡 → 加 z-index,无效

  2. 怀疑 id 取错 → 打印元素,拿到的是对的,排除

  3. 在绑定处打日志 → 刷新后日志不打印,说明代码没执行到

根因:事件绑定写在 renderDetail() 里,该函数在「非发布者」分支会提前 return,后面的绑定被跳过。

二、是否解决:

​ 已解决。绑定移到 DOMContentLoaded 里无条件执行,renderDetail() 只管按钮显不显示。

三、有何收获:

​ 事件绑定不要写在带条件分支的函数里。函数只要有提前 return,后面的绑定就是定时炸弹 —— 静默失效还不报错。另外,「不报错但没反应」的问题,先确认代码有没有执行到,再确认逻辑对不对。

十、个人总结

林豪(102401415)

通过本次结对作业,我将第一次的原型设计转化为了可运行的WEB程序,对前后端分离的开发模式有了更直观的理解。在实现列表展示和搜索功能时,我学习了JavaScript的DOM操作和数组过滤方法。遇到的主要问题是页面之间的数据传递,通过LocalStorage的统一管理解决了这个问题。这次开发让我体会到,把设计图变成真正能用的产品,需要考虑很多细节,比如表单验证、空状态提示、错误处理等等。后续根据墨刀原型优化了UI,加入了底部导航和个人中心页面,让整个产品更加完整。

魏怡健(102401428)

本次结对实现让我体会到从设计到代码的转化过程。在开发发布表单和详情页时,我深入学习了表单验证和URL参数传递的方法。与林豪的协作中,我们通过明确的模块划分提高了开发效率,也遇到了接口对接的问题,通过沟通及时调整了数据格式。这次作业让我更加理解了软件工程中模块划分和接口设计的重要性。


十一、评价队友

评价魏怡健(102401428)

值得学习的地方:在发布表单开发中考虑周全,对用户输入的验证处理细致,代码结构清晰,注释完整。
需要改进的地方:可以在开发前多与队友沟通数据格式和接口定义,减少后续对接调整的时间。

评价林豪(102401415)

值得学习的地方:UI设计美观,整体风格统一,对细节把控到位,能快速把设计想法转化为可运行的界面。
需要改进的地方:可以在开发前更明确地拆分任务,让分工更均衡。

posted @ 2026-10-09 11:05  Winksong  阅读(6)  评论(0)    收藏  举报