本次作业所属课程 EE308FZ(Software Engineering)
团队名称 兑怼对队
作业要求 Extreme Programming
本次作业目标 基础要求博客格式,使用Markdown格式;正确提供Github仓库链接和代码规范链接。功能实现思路说明、程序截图、成员分工说明。代码实现 页面样式;收藏联系人功能;添加多种联系方式功能;导入与导出功能

一、链接

Github仓库链接:https://github.com/duiduiduidui-team/duiduiduidui/tree/master
代码规范链接:https://github.com/2625690482/Code-Standards/tree/master
云服务器链接:https://brandy666666.github.io/address-book-system/

二、团队成员信息

姓名 李奕霏 杨璐
FZU学号 832301118 832301123
MU学号 23125535 23132604
分工 HTML/CSS界面实现、收藏功能、多联系方式管理、搜索筛选;撰写博客整理程序截图和视频、制作个人PSP表 Excel导入导出功能、模态框交互、云服务器部署、项目测试;整理Git提交记录、部署文档、制作个人PSP表
贡献比例 50% 50%

三、Github提交日志

在这里插入图片描述

姓名 李奕霏 杨璐
提交次数 3 2

四、功能实现思路说明

4.1 整体架构设计

系统采用MVVM(Model-View-ViewModel)轻量级架构,通过清晰的三层分离实现:

  1. 数据层(Model)

    • 联系人数据存储在localStorage
    • 使用contacts数组作为内存缓存
    • 数据格式为标准的JSON对象
  2. 视图层(View)

    • index.html:页面结构
    • style.css:样式表现
    • DOM元素构成用户界面组件
  3. 控制层(Controller)

    • script.js:连接数据和视图
    • 通过事件监听实现用户交互
    • 数据变更自动同步到视图

4.2 模块架构设计

系统模块划分为:

核心模块架构:
├── 初始化模块(DOMContentLoaded)
│   ├── 加载联系人数据
│   ├── 设置事件监听器
│   └── 更新统计信息
├── 数据管理模块
│   ├── loadContacts() - 数据加载
│   ├── saveContacts() - 数据保存
│   └── updateStats() - 统计更新
├── 联系人操作模块
│   ├── 增:saveContact()
│   ├── 删:deleteContact()
│   ├── 改:editContact()
│   └── 查:renderContacts()
├── 搜索筛选模块
│   ├── performSearch() - 搜索功能
│   └── 筛选按钮事件 - 筛选功能
└── 导入导出模块
    ├── exportToExcel() - 导出Excel
    └── importFromExcel() - 导入Excel

4.3 Excel处理技术

SheetJS库的实现方法

// Excel导出实现流程(从exportToExcel函数提取)
1. 数据验证:检查contacts数组是否为空
2. 数据转换:contacts对象 → 二维数组worksheetData
3. 创建列头:定义Excel表头结构
4. 填充数据:遍历contacts,提取各字段数据
5. 格式设置:设置列宽(colWidths)
6. 文件生成:使用XLSX库生成Excel文件
7. 触发下载:创建虚拟标签触发下载

关键转换逻辑

// 数据转换逻辑
contacts.forEach(contact => {
    // 初始化联系方式映射
    const methods = {
        '手机': '', '电话': '', '邮箱': '', 
        '微信': '', 'QQ': '', '其他': ''
    };
    
    // 填充联系方式(扁平化处理)
    contact.methods.forEach(method => {
        if (methods.hasOwnProperty(method.type)) {
            methods[method.type] = method.value;
        }
    });
    
    // 构建Excel行数据
    const row = [
        contact.name || '',
        contact.company || '',
        contact.position || '',
        methods['手机'],
        methods['电话'],
        methods['邮箱'],
        methods['微信'],
        methods['QQ'],
        methods['其他'],
        contact.notes || '',
        contact.isFavorite ? '是' : '否'
    ];
});

4.4 搜索功能实现

搜索算法(基于performSearch函数)

// 多字段模糊搜索实现
function performSearch() {
    const searchTerm = searchInput.value.trim().toLowerCase();
    
    // 1. 空搜索词处理
    if (!searchTerm) {
        renderContacts();
        return;
    }
    
    // 2. 多字段搜索逻辑
    const searchResults = contacts.filter(contact => 
        // 姓名搜索(必填字段)
        contact.name.toLowerCase().includes(searchTerm) ||
        
        // 可选字段搜索(使用可选链操作符)
        contact.company?.toLowerCase().includes(searchTerm) ||
        contact.position?.toLowerCase().includes(searchTerm) ||
        contact.notes?.toLowerCase().includes(searchTerm) ||
        
        // 联系方式搜索(遍历数组)
        contact.methods.some(method => 
            method.value.toLowerCase().includes(searchTerm)
        )
    );
    
    // 3. 搜索结果渲染
    if (searchResults.length === 0) {
        // 空状态提示
        contactList.innerHTML = `...`;
    } else {
        // 渲染搜索结果
        contactList.innerHTML = '';
        searchResults.forEach(contact => {
            // 使用相同的renderContacts逻辑但只渲染搜索结果
        });
    }
}

算法特点

  1. 大小写不敏感:统一转为小写比较
  2. 模糊匹配:使用includes而非===精确匹配
  3. 多字段搜索:覆盖所有可能的信息字段
  4. 实时性:即时搜索,无延迟

4.5 数据存储方案选择

选择localStorage

// 1. 零配置
let contacts = JSON.parse(localStorage.getItem('addressBookContacts')) || [];

// 2. 同步API,操作简便
function saveContacts() {
    localStorage.setItem('addressBookContacts', JSON.stringify(contacts));
    updateStats();
}

// 3. 足够容量:每个联系人约200-500字节,5MB localStorage可存储约10000-25000个联系人

具体实现方法

// 数据加载 - 带容错处理
function loadContacts() {
    const saved = localStorage.getItem('addressBookContacts');
    if (saved) {
        // 防止JSON解析失败导致程序崩溃
        try {
            contacts = JSON.parse(saved);
        } catch (e) {
            console.error('数据解析失败,使用默认值');
            contacts = [];
        }
    }
    renderContacts();
}

// 数据保存 - 自动序列化
function saveContacts() {
    localStorage.setItem('addressBookContacts', JSON.stringify(contacts));
    updateStats(); // 保存后自动更新统计
}

4.6联系人保存流程

function saveContact(e) {
    e.preventDefault();
    
    // 1. 收集表单数据
    const id = document.getElementById('contactId').value || generateId();
    const name = document.getElementById('name').value.trim();
    
    // 2. 表单验证
    if (!name) {
        alert('请输入姓名');
        return;
    }
    
    // 3. 收集联系方式(动态表单处理)
    const methods = [];
    const methodRows = contactMethodsContainer.querySelectorAll('.method-row');
    methodRows.forEach(row => {
        const type = row.querySelector('.method-type').value;
        const value = row.querySelector('.method-value').value.trim();
        if (value) {
            methods.push({ type, value });
        }
    });
    
    // 4. 构建完整联系人对象
    const contactData = {
        id,
        name,
        company: document.getElementById('company').value.trim(),
        position: document.getElementById('position').value.trim(),
        notes: document.getElementById('notes').value.trim(),
        methods,
        isFavorite: document.getElementById('isFavorite').checked,
        createdAt: new Date().toISOString()
    };
    
    // 5. 区分新增和编辑
    const index = contacts.findIndex(c => c.id === id);
    if (index > -1) {
        contacts[index] = contactData; // 编辑
    } else {
        contacts.push(contactData);    // 新增
    }
    
    // 6. 保存并更新UI
    saveContacts();
    renderContacts();
    contactModal.style.display = 'none';
}

4.7 交互设计实现

// 1. 即时反馈机制
// 搜索框Enter键支持
searchInput.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') performSearch();
});

// 2. 模态框管理
// 点击外部关闭模态框
window.addEventListener('click', (e) => {
    if (e.target === contactModal) contactModal.style.display = 'none';
    if (e.target === confirmModal) confirmModal.style.display = 'none';
});

// 3. 动态表单交互
// 联系方式动态添加/删除
addMethodBtn.addEventListener('click', addContactMethod);

function addContactMethod(type = '', value = '') {
    // 动态创建表单行
    const methodRow = document.createElement('div');
    methodRow.className = 'method-row';
    methodRow.innerHTML = `
        <select class="method-type">...</select>
        <input type="text" class="method-value" value="${value}">
        <button type="button" class="remove-method">X</button>
    `;
    
    // 添加删除功能
    const removeBtn = methodRow.querySelector('.remove-method');
    removeBtn.addEventListener('click', () => {
        methodRow.remove();
    });
}

4.8 错误处理和用户引导

// 1. 删除确认(防止误操作)
function showDeleteConfirm(id) {
    contactToDelete = id;
    confirmModal.style.display = 'flex'; // 显示确认对话框
}

// 2. 导入文件验证
function importFromExcel(event) {
    const file = event.target.files[0];
    
    // 文件类型验证
    if (!file.name.match(/\.(xlsx|xls)$/i)) {
        alert('请选择Excel文件 (.xlsx 或 .xls)');
        return;
    }
    
    // 文件读取和错误处理
    const reader = new FileReader();
    reader.onload = function(e) {
        try {
            // 数据处理逻辑...
        } catch (error) {
            console.error('导入失败:', error);
            alert('导入失败,请检查Excel文件格式是否正确');
        }
    };
}

// 3. 空状态提示
function renderContacts() {
    if (filteredContacts.length === 0) {
        contactList.innerHTML = `
            <div class="empty-state">
                <i class="fas fa-address-book fa-3x"></i>
                <p>暂无联系人,点击"添加联系人"开始</p>
            </div>
        `;
        return;
    }
}

五、程序运行展示

5.1收藏联系人

在这里插入图片描述
在这里插入图片描述

5.2添加多种联系方式

在这里插入图片描述

5.3导入与导出

在这里插入图片描述

在这里插入图片描述

5.4搜索联系人

在这里插入图片描述

5.5演示视频

六、合作中遇到的困难及解决方案

  1. 功能需求理解不一致
    初期对"多种联系方式"的具体实现方式理解不同
    解决方案:沟通明确详细的功能说明,确保理解一致
  2. 代码风格不统一
    变量命名、注释格式、文件结构等存在差异
    解决方案:制定了团队代码规范文档,并随时沟通理解对方内容
  3. 分工覆盖不足
    某些边界情况未充分明确分工,导致合并运行出现bug
    解决方案:检查出错问题,明确责任边界
  4. 项目进度把控困难
    某些任务耗时超出预期,影响整体进度
    解决方案:设定明确的里程碑和检查点

七、PSP表格

  • 李奕霏
PSP阶段 任务内容 预估时间(分钟) 实际时间(分钟)
计划 需求分析与功能规划 10 7
界面设计草稿 20 23
技术方案选择 20 18
设计 HTML结构设计 20 45
CSS样式方案设计 20 14
响应式布局规划 20 19
组件交互设计 20 20
开发 HTML基础框架搭建 60 73
CSS样式编写 120 107
响应式设计实现 90 68
收藏功能开发 60 74
多联系方式管理 90 88
搜索筛选功能 90 59
界面交互优化 60 68
文档 程序截图制作 30 27
操作视频录制 10 23
PSP表整理 20 21
博客撰写整理 60 132
总计 820 886
  • 杨璐
PSP阶段 任务内容 预估时间(分钟) 实际时间(分钟)
计划 功能需求分析 20 10
接口设计 20 24
设计 数据导入导出方案设计 20 12
模态框交互流程设计 20 18
数据库结构设计 20 27
开发 Excel导入功能开发 120 113
Excel导出功能开发 120 94
模态框交互逻辑 90 102
表单验证与提交处理 60 77
数据存储管理 60 54
测试及调整 90 124
部署 90 48
文档 Git提交记录整理 10 7
PSP表整理 20 26
总计 760 736
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐