Extreme Programming
| Course for This Assignment | 2401_MU_SE_EE308 |
|---|---|
| Student ID and Name | 832201128_Xiong ZhiXue & 832201121_Gao Yu |
| Assignment Requirements | Develop a web-based contact management system with bookmarking, multiple contact methods, and import/export features. |
| Objectives of This Assignment | Practice modular design and collaborative software engineering techniques and achieve functional and collaborative milestones |
目录
- 1.Project address
- 2.Commit logs from Github
- 3.Description of functional implementation ideas
- 3.1 User interface
- 3.2 Bookmark contacts
- 3.3 Add multiple contact methods
- 3.4 Import and Export Contacts
- 3.5 Database
- 4.Division of labor among team members
- 5.Difficulties encountered in cooperation and solutions
- 6.PSP Table
1.Project address
https://github.com/xzx904/Contact-book.git
2.Commit logs from Github

3.Description of functional implementation ideas
3.1 User interface
This image shows an intuitive interface to an electronic address book, clearly listing the details of many contacts. Each contact is equipped with their name, phone number, email address, and a series of useful action buttons such as "Delete," "Edit," and "Top." This information is carefully organized in a tabular format, allowing users to view and manage their contacts at a glance.
In addition, the address book interface also provides the "Export Excel" function, which allows users to export contact information to an Excel table with one click for further data processing or backup. In one corner of the interface, there is also an option to "select File" to import an Excel table with contact information into the address book.

3.2 Bookmark contacts
Description:
This GIF demonstrates the Bookmark Contacts feature of the Contact book application. Users can move a specific contact to the top of the list by clicking the "top" button, and the font of all the information of the top contact will be bolded and blackened, making it easy to access important contacts. In addition, the app also supports the "untop" function, allowing users to untop at any time.
Implementation :
- Front-end integration: A "Top" button appears next to each contact in the list to toggle the top status. The bold and black font of the contact information indicates whether the contact is in the top state.
- Event handling: The user clicks the "Top" button to trigger the top function. This function identifies the contact by its unique ID and updates the status of the contac t at the top of the local contact number group.
- Status Update: Updates the top status of a contact in the local contact list. If the contact does not have a top, it is marked as the top, and a topOrder timestamp is assigned to determine the order between the top contacts. If the status of the contact is already top, cancel the top status and clear topOrder.
- Data synchronization: After the local status update, the renderContacts function is called to rerender the contact list. This function sorts contacts according to their highest state and order, and then updates the DOM to reflect the current state of the contact.

Code Reference:
// 渲染联系人列表
function renderContacts() {
// 将联系人按置顶顺序排序
contacts.sort((a, b) => {
if (a.isTop && b.isTop) {
return a.topOrder - b.topOrder; // 如果都置顶,按置顶顺序排列
}
return b.isTop - a.isTop; // 置顶的联系人排在最前面
});
contactTable.innerHTML = "";
contacts.forEach((contact) => {
const row = document.createElement("tr");
const rowClass = contact.isTop ? "highlight" : ""; // 如果置顶,添加加粗样式
const phoneList = contact.phone
.map((p, index) => `${p} <button class="delete-phone" data-id="${contact.id}" data-phone-index="${index}">删除</button>`)
.join("<br>");
const emailList = contact.email.join("<br>");
row.innerHTML = `
<td class="${rowClass}">${contact.name}</td>
<td class="${rowClass}">${phoneList || "无"}</td>
<td class="${rowClass}">${emailList || "无"}</td>
<td>
<button class="edit" data-id="${contact.id}">编辑</button>
<button class="delete" data-id="${contact.id}">删除</button>
<button class="top ${contact.isTop ? 'top-button' : ''}" data-id="${contact.id}">
${contact.isTop ? '取消置顶' : '置顶'}
</button>
</td>
`;
contactTable.appendChild(row);
});
}
// 置顶按钮点击事件
contactTable.addEventListener("click", (e) => {
if (e.target.classList.contains("top")) {
const contactId = e.target.dataset.id;
const contact = contacts.find((c) => c.id === contactId);
if (contact) {
if (!contact.isTop) {
// 置顶
contact.isTop = true;
contact.topOrder = Date.now(); // 用时间戳记录置顶顺序
} else {
// 取消置顶
contact.isTop = false;
contact.topOrder = null; // 取消置顶时清除顺序
}
renderContacts(); // 重新渲染
}
}
if (e.target.classList.contains("edit")) {
const contactId = e.target.dataset.id;
const contact = contacts.find((c) => c.id === contactId);
if (contact) {
document.getElementById("contactId").value = contact.id;
document.getElementById("name").value = contact.name;
document.getElementById("phone").value = contact.phone.join(", ");
document.getElementById("email").value = contact.email.join(", ");
}
}
if (e.target.classList.contains("delete")) {
const contactId = e.target.dataset.id;
contacts = contacts.filter((c) => c.id !== contactId);
renderContacts();
}
if (e.target.classList.contains("delete-phone")) {
const contactId = e.target.dataset.id;
const phoneIndex = e.target.dataset.phoneIndex;
const contact = contacts.find((c) => c.id === contactId);
if (contact) {
contact.phone.splice(phoneIndex, 1);
renderContacts();
}
}
});
3.3 Add multiple contact methods
Description:
This GIF shows the ability to add additional information about a contact in your address book. Users can re-edit the contact information by clicking the "Edit" button, then change the phone or email, and then click the "Add/Modify" button, you can reflect a variety of phones and email in the contact information, and equipped with a "delete" button for deleting redundant phones.
Implementation:
- Custom Input:
- Users can edit the same contact, enter a different phone and email, click the "Add" button.
- These fields are dynamically added to the contact form.
- Data Handling:
- The additional fields are collected and stored in an additionalInfo object within the contact object.
- When the form is submitted, the additionalInfo object is serialized into a JSON string.
- Front-End Storage:
The JSON string representing the additional information is stored in the contacts array along with the rest of the contact details. - Dynamic Rendering:
- When rendering the contact list, the renderContacts function checks for the presence of additionalInfo.
- If present, the additional information is parsed from JSON and displayed in the contact’s row.

Code Reference:
// 添加或修改联系人
contactForm.addEventListener("submit", (e) => {
e.preventDefault();
const id = document.getElementById("contactId").value; // 隐藏字段
const name = document.getElementById("name").value.trim();
const phone = document.getElementById("phone").value.trim();
const email = document.getElementById("email").value.trim();
if (id) {
// 编辑联系人
const contact = contacts.find((c) => c.id === id);
if (contact) {
contact.name = name;
if (phone && !contact.phone.includes(phone)) {
contact.phone.push(phone);
}
if (email && !contact.email.includes(email)) {
contact.email.push(email);
}
}
} else {
// 添加新联系人
let existingContact = contacts.find((c) => c.name === name);
if (existingContact) {
if (phone && !existingContact.phone.includes(phone)) {
existingContact.phone.push(phone);
}
if (email && !existingContact.email.includes(email)) {
existingContact.email.push(email);
}
} else {
contacts.push({
id: Date.now().toString(),
name,
phone: phone ? [phone] : [],
email: email ? [email] : [],
});
}
}
renderContacts();
contactForm.reset();
document.getElementById("contactId").value = ""; // 重置隐藏字段
});
// 编辑联系人信息
contactTable.addEventListener("click", (e) => {
const target = e.target;
const id = target.dataset.id;
if (target.classList.contains("edit")) {
const contact = contacts.find((c) => c.id === id);
if (contact) {
document.getElementById("contactId").value = contact.id;
document.getElementById("name").value = contact.name;
document.getElementById("phone").value = "";
document.getElementById("email").value = "";
}
}
if (target.classList.contains("delete")) {
contacts = contacts.filter((c) => c.id !== id);
renderContacts();
}
if (target.classList.contains("delete-phone")) {
const phoneIndex = target.dataset.phoneIndex;
const contact = contacts.find((c) => c.id === id);
if (contact) {
contact.phone.splice(phoneIndex, 1);
}
renderContacts();
}
});
3.4 Import and Export Contacts
Descruiption:
This GIF illustrates the Import and Export Contacts feature of the contact book application.
Export Function: Allows users to export all contact information from the address book into an Excel file, with each row representing a contact and each column corresponding to a specific contact information field (e.g., name, phone number, backup phone number, email,).
Import function: After clicking the "Select File" button in the address book, the user can choose to upload an Excel file with contact information. The system will automatically parse the content of the file and import the contact information strictly according to the order of name, phone number, and email address. After the "Select File" button, the file name of the imported Excel table will be displayed. If no file is imported, "No file selected" will be displayed.
Implementation:
Import function implementation:
- The user selects an Excel file by clicking the "Import" button or selecting the file input.
- The system uses a file reader (FileReader) to read user-selected Excel files.
- After reading, the system uses the XLSX library to convert the contents of the Excel file into an array of JavaScript objects.
- The system iterates over these objects, extracting name, phone, and email information.
- For each contact, the system checks to see if it already exists in the current contact list:
- If yes, the system adds a new phone number and email address to the corresponding contact information to avoid duplication.
- If it does not exist, a new contact record is created and added to the list.
- After the contact list is updated, the user is prompted "Import successful" and the contact list is re-rendered to display the newly imported data.
Export function implementation:
- The user clicks the "Export" button to trigger the export action.
- The system converts each contact in the current contact list into an object that contains a name, phone, and email address.
- The phone and mailbox fields, if they are arrays, are converted to comma-separated strings.
- Using the XLSX library, the system converts these objects into a worksheet.
- The system creates a new workbook and adds the worksheet to the workbook.
- Finally, the system saves the workbook as an Excel file called "contacts.xlsx" and makes it available for the user to download.

Code Reference:
// 导出为 Excel
exportButton.addEventListener("click", () => {
const data = contacts.map((contact) => ({
姓名: contact.name,
电话: contact.phone.join(", "),
邮箱: contact.email.join(", "),
}));
const ws = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "通讯录");
XLSX.writeFile(wb, "通讯录.xlsx");
});
// 导入 Excel
importFile.addEventListener("change", (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: "array" });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const importedData = XLSX.utils.sheet_to_json(worksheet);
if (!Array.isArray(importedData) || importedData.length === 0) {
alert("文件内容为空或格式不正确!");
return;
}
importedData.forEach((row) => {
const name = (row["姓名"] || "").toString().trim();
const phones = (row["电话"] || "")
.toString()
.split(",")
.map((p) => p.trim());
const emails = (row["邮箱"] || "")
.toString()
.split(",")
.map((e) => e.trim());
if (!name) return;
let existingContact = contacts.find((c) => c.name === name);
if (existingContact) {
phones.forEach((p) => {
if (p && !existingContact.phone.includes(p)) {
existingContact.phone.push(p);
}
});
emails.forEach((e) => {
if (e && !existingContact.email.includes(e)) {
existingContact.email.push(e);
}
});
} else {
contacts.push({
id: Date.now().toString(),
name,
phone: phones.filter(Boolean),
email: emails.filter(Boolean),
});
}
});
renderContacts();
alert("导入成功!");
} catch (err) {
alert("文件解析失败,请检查文件格式!");
console.error(err);
}
};
reader.readAsArrayBuffer(file);
});
3.5 Database(MySQL)

4.Division of labor among team members
| Team Member | Role | Responsibilities | Contribution (%) |
|---|---|---|---|
| Gao Yu | Frontend Developer | UI layout creation, implementing forms, integrating APIs, participating in tech stack selection, planning and design, testing, and project evaluation | 50% |
| Xiong ZhiXue | Backend Developer | Server and database setup, API development, system architecture design, deployment (server hosting and configuration), and back-end testing for robustness and functionality | 50% |
5.Difficulties encountered in cooperation and solutions
Challenges:
Challenge 1: When developing features to add additional information to contacts, we often encounter the problem that the back end frequently receives empty JSON objects. This phenomenon causes errors in data validation, which in turn affects the normal operation of the function.
Challenge 2: The deployment of multiple projects on low-cost micro-servers significantly increased the server burden, resulting in reduced processing power, especially during peak user hours, and significantly reduced system efficiency.
Challenge 3: In the process of building the Excel file import tool, we noticed that users often submitted incorrectly formatted files, which led to data processing failures and database data inconsistencies.
Challenge 4: In team collaboration, poor communication occasionally leads to unclear priorities, which leads to duplication of effort or delays in integrating back-end functionality with the front end.
6.PSP table
PSP Table for Member Gao Yu
| Modules | Task Description | Estimated Time | Actual Time |
|---|---|---|---|
| Group Discussion and Demand Analysis | Determine the required functions of the web page | 1 hour | 1 hour |
| Knowledge Learning | Learning about Excel Import and Export | 1 hour | 2 hour |
| Frontend Development | Create a Vue project | 1 hour | 2 hour |
| Frontend Test and Debug | Test the web page functions | 2 hour | 3 hour |
| Deploy | Deploy the application to the server (Huawei Cloud) | 1 hour | 2 hour |
| Total | 6 hour | 10 hour |
PSP Table for Member Xiong ZhiXue
| Modules | Task Description | Estimated Time | Actual Time |
|---|---|---|---|
| Group Discussion and Demand Analysis | Determine the required functions of the web page | 1 hour | 1 hour |
| Knowledge Learning | Learning about Excel Import and Export | 1 hour | 2 hour |
| Backend Development | Create a SpringBoot project | 3 hour | 5 hour |
| Backend Test and Debug | Test the web page functions | 1 hour | 2 hour |
| Deploy | Deploy the application to the server | 1 hour | 2 hour |
| Total | 7 hour | 12 hour |
相关推荐
论文复现基于欠谐振工作区间的全桥LLC变换器混合控制仿真建模与动态性能分析(Simulink仿真实现)
内容概要:本文系统解读了一套完整的多机器人路径规划(MAPF)MATLAB代码库,重点剖析了基于优先级规划与Petri网融合的多智能体无冲突路径生成框架。文章详细阐述了该框架的四层架构设计:几何层负责地图解析与栅格化处理,拓扑层构建四邻域图与Petri网模型,调度层实现基于优先级启发式的路径规划与冲突消解,呈现层完成动画与视频可视化输出。核心创新包括动态边权膨胀机制、节点预留历史查询、几何惩罚驱动的局部同步以及Petri网双阶段优化策略,显著提升了算法在大规模场景下的求解效率与鲁棒性。; 适合人群:具备一定编程基础和算法基础,从事机器人路径规划、智能交通、仓储物流调度等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:① 学习和复现基于优先级规划的多智能体无冲突路径生成方法;② 掌握动态边权膨胀、节点预留历史等关键技术以提升路径规划效率;③ 利用Petri网进行整数规划求解并实现双阶段优化;④ 构建可扩展的多机器人系统仿真平台并实现轨迹可视化。; 阅读建议:建议读者按照文中所述的数据流顺序逐步学习各模块设计,重点关注四层架构之间的接口关系与信息传递机制。在实践过程中应结合提供的完整代码与测试案例,调试并验证不同同步策略的效果差异,并尝试对框架进行功能扩展,如引入回溯机制以提高算法完备性。
基于容积卡尔曼滤波CKF的车辆状态估计Carsim和Matlab联合仿真(说明文档+仿真源文件+运行说明)
内容概要:本资源提供了基于容积卡尔曼滤波(CKF)的车辆状态估计算法在Carsim与Matlab/Simulink环境下的联合仿真解决方案,包含完整的说明文档、仿真源文件及运行指南。通过Carsim构建高精度车辆动力学模型,Simulink实现CKF算法设计与状态估计,有效融合两者优势,实现了对车辆关键状态参数(如质心侧偏角、横摆角速度、车速等)的高精度实时估计。该方法克服了传统传感器直接测量成本高、安装难的问题,提升了车辆动态性能分析与控制系统的智能化水平。; 适合人群:适用于从事车辆工程、智能驾驶、控制理论与应用等相关领域的科研人员、高校研究生及企业研发工程师,尤其适合具备一定Carsim和Matlab联合仿真基础的技术人员。; 使用场景及目标:①开展车辆状态估计算法的研究与验证,提升无人车、ADAS系统中的感知能力;②完成学术论文复现、毕业课题设计或工程项目开发中的核心算法模块搭建;③深入理解非线性滤波算法(如CKF)在实际车辆系统中的建模与应用流程。; 阅读建议:建议用户结合说明文档逐步运行仿真程序,重点关注Carsim与Simulink的接口设置、信号交互机制以及CKF算法模块的设计逻辑,同时可通过修改工况条件和噪声参数来测试算法鲁棒性,强化理论与实践的结合。
高校技术转移办公室在推动成果转化过程中面临哪些信息整合难题?.docx
高校技术转移办公室在推动成果转化过程中面临哪些信息整合难题?
回流焊温度曲线合格判据分析器
【适用方向】工程数据分析与报表 【工具用途】 「回流焊温度曲线合格判据分析器」用于半导体制造过程中的工程计算与分析, 帮助工艺、设备、质量与生产工程师快速完成日常数据处理工作。 【能解决什么】 · 免去手工Excel 反复整理与公式编写,直接导入数据即可出结果 · 计算过程透明,关键参数可按现场实际调整 · 输出图表与明细报表,便于直接用于汇报与存档 【包内内容】 · 工具源码(Python,可直接运行) · 使用说明(数据格式与操作步骤) · 依赖清单与示例数据 【适用人群】 半导体 FAB / 晶圆厂:工艺、设备、质量、IE、生产工程师; 以及 MES 与智能制造方向的技术人员。 【使用说明】 解压后按说明导入数据运行即可;工具在本地处理数据,不联网。
高校技术转移办公室人员如何高效开展科技成果评价与筛选工作?.docx
高校技术转移办公室人员如何高效开展科技成果评价与筛选工作?


