软件工程结对作业(第二次之程序实现)
这个作业属于哪个课程 | 首页 - 软件工程2024 - 福州大学 - 班级博客 - 博客园 |
---|---|
这个作业要求在哪里 | 2024秋软件工程结对作业(第二次之程序实现) |
这个作业的目标 | 站在程序员的角度,给出这个产品的核心模块的编码的原型 |
学号 | 102202130、042201401 |
github项目地址1 | linye2005/042201401-102202130 (github.com) |
github项目地址2 | 786260029/042201401-102202130 (github.com) |
第二次结对作业-程序实现
一、具体分工
学号 | 分工 |
---|---|
102202130 | 前端开发和用户界面设计、部分功能实现、博客 |
042201401 | 前端开发和用户界面设计、部分功能实现、README.md文件 |
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 120 | 120 |
·Estimate | 估计这个任务需要多少时间 | 120 | 120 |
Development | 开发 | 3860 | 3960 |
·Analysis | 需求分析 (包括学习新技术) | 630 | 700 |
·Design Spec | 生成设计文档 | 180 | 180 |
·Design Review | 设计复审 | 120 | 120 |
·Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 90 |
·Design | 具体设计 | 320 | 330 |
·Coding | 具体编码 | 2000 | 2040 |
·Code Review | 代码复审 | 150 | 150 |
·Test | 测试(自我测试,修改代码,提交修改) | 400 | 350 |
Reporting | 报告 | 760 | 710 |
·Test Repor | 测试报告 | 240 | 250 |
·Size Measurement | 计算工作量 | 120 | 100 |
·Postmortem&Process Improvement Plan | 事后总结, 并提出过程改进计划 | 400 | 360 |
合计 | 4740 | 4790 |
三、解题思路描述与设计实现说明
3.1代码实现思路与文字描述
概述: 我们的项目“ProjectPartner”旨在创建一个平台,让用户能够发布项目、招募合作伙伴,并进行实时交流。实现这个目标涉及到前端页面展示、用户输入验证、后端逻辑处理以及数据库交互。
用户输入验证:在前端使用JavaScript进行初步验证,确保用户输入符合要求(如邮箱格式、所有信息都填写)。
数据库交互:使用MySQL来存储用户信息、项目信息和聊天记录。
交流实现:使用WebSocket实现聊天功能。
基础功能:创建项目(完成创建后可以在管理项目的我创建的项目中查看)、加入项目(点击加入按钮后可以在管理项目的我加入的项目中查看)、聊天(聊天记录可以永久保存)。
附加功能:我的信息管理、首页欢迎与资讯、导航栏跳转、弹窗提示、注销账户。
为了符合大家的习惯,我们的消息页面左侧为用户栏,右侧为聊天窗口,右下方为输入栏。
3.2关键实现的流程图或数据流图
项目管理UML图:
说明
- Project: 表示单个项目,包含项目的名称、开始日期、招募人数、方向、标签、描述和ID。
- ProjectManagement: 负责管理项目,包括创建、删除、加入、退出和编辑项目。
- UserInterface: 表示用户界面,负责显示项目、显示项目表单、处理项目创建、删除、加入、退出和编辑。
- LocalStorage: 表示本地存储,用于存储和检索项目数据
项目管理系统结构图:
图解说明
- 项目管理系统: 顶层节点,表示整个系统。
- 项目信息: 包括创建、编辑和删除项目的操作。
- 用户信息: 表示系统中的用户数据。
- 用户操作: 包括用户对项目的加入和退出操作。
- 项目数据库: 存储所有项目和用户信息的数据库。
- 创建项目: 用户可以创建新项目。
- 编辑项目: 用户可以编辑已存在的项目。
- 删除项目: 用户可以删除项目。
- 加入项目: 用户可以加入已有的项目。
- 退出项目: 用户可以退出项目。
- 操作反馈: 系统对用户操作的反馈。
3.3重要的/有价值的代码片段及解释
代码片段 1: 表单字段更新逻辑
function updateFormFields() {
var identity = document.getElementById('identitySelect').value;
var studentNumberDiv = document.getElementById('studentNumberDiv');
var teacherNumberDiv = document.getElementById('teacherNumberDiv');
var majorDiv = document.getElementById('majorDiv');
var researchDiv = document.getElementById('researchDiv');
if (identity === 'student') {
studentNumberDiv.classList.remove('hidden');
teacherNumberDiv.classList.add('hidden');
majorDiv.classList.remove('hidden');
researchDiv.classList.add('hidden');
} else if (identity === 'teacher') {
studentNumberDiv.classList.add('hidden');
teacherNumberDiv.classList.remove('hidden');
majorDiv.classList.add('hidden');
researchDiv.classList.remove('hidden');
}
}
解释:
- 此函数
updateFormFields
根据用户选择的身份(学生或教师)动态显示或隐藏特定的表单字段。 - 使用
document.getElementById
获取相应的 DOM 元素。 - 使用
classList.add
和classList.remove
方法来控制元素的显示和隐藏。 - 如果身份是学生,则显示学生学号和专业相关的字段,隐藏教师相关的字段。
- 如果身份是教师,则显示教师工号和研究方向相关的字段,隐藏学生相关的字段。
代码片段 2: 表单提交逻辑
document.getElementById('registrationForm').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止表单默认提交行为
var identity = document.getElementById('identitySelect').value;
var studentNumber = document.getElementById('studentNumberDiv').getElementsByTagName('input')[0].value.trim();
var teacherNumber = document.getElementById('teacherNumberDiv').getElementsByTagName('input')[0].value.trim();
if ((identity === 'student' && studentNumber !== '') || (identity === 'teacher' && teacherNumber !== '')) {
// 如果用户填写了对应身份的信息,则跳转到登录页面
window.location.href = '登录.html';
} else {
alert('请填写完整您的信息。');
}
});
解释:
- 此段代码为注册表单添加了
submit
事件监听器。 - 使用
event.preventDefault()
阻止表单的默认提交行为,允许通过JavaScript进行进一步处理。 - 获取用户选择的身份以及学生学号或教师工号的输入值。
- 使用
trim()
方法去除输入值两端的空白字符。 - 根据用户选择的身份验证相应字段是否已填写。
- 如果验证通过,使用
window.location.href
跳转到登录页面。 - 如果验证失败,使用
alert
弹出提示信息,提醒用户填写完整信息。
代码片段3: 聊天窗口控制逻辑
document.querySelectorAll('.chat-item').forEach(item => {
item.addEventListener('click', function() {
// 隐藏所有聊天窗口
document.querySelectorAll('.chat-window').forEach(win => {
win.style.display = 'none';
});
// 移除所有聊天项的激活状态
document.querySelectorAll('.chat-item').forEach(item => {
item.classList.remove('active');
});
// 显示被点击的聊天窗口并添加激活状态
const target = this.getAttribute('data-target');
const chatWindow = document.getElementById(target);
chatWindow.style.display = 'flex';
this.classList.add('active');
});
});
解释:此代码片段用于控制聊天应用中的聊天窗口切换逻辑。使用 document.querySelectorAll
获取所有的聊天项(.chat-item
),并对每一个聊天项添加点击事件监听器。在点击事件中,首先遍历并隐藏所有的聊天窗口(.chat-window
),确保在切换聊天窗口时,其他聊天窗口是隐藏状态。接着,遍历并移除所有聊天项的激活状态(.active
),以确保只有当前被点击的聊天项处于激活状态。通过 this.getAttribute('data-target')
获取被点击聊天项关联的聊天窗口的ID。使用 document.getElementById
根据ID获取对应的聊天窗口元素,并将其设置为显示状态(flex
)。最后,给被点击的聊天项添加激活状态的样式(.active
)。
关键点:封装性 、用户交互、性能考虑、可维护性、扩展性(添加新的聊天窗口,只需添加相应的 .chat-item
和 .chat-window
元素)
代码片段4: 创建项目
document.getElementById('project-form').addEventListener('submit', function(event) {
event.preventDefault();
const project_name = document.getElementById('project-name').value;
const start_date = document.getElementById('start-date').value;
const recruit_people = document.getElementById('recruit-people').value;
const project_direction = document.getElementById('project-direction').value;
const add_tags = document.getElementById('add-tags').value;
const project_description = document.getElementById('project-description').value;
const newProject = {
name: project_name,
startDate: start_date,
recruitPeople: recruit_people,
direction: project_direction,
tags: add_tags,
description: project_description,
id: Date.now()
};
let createdProjects = JSON.parse(localStorage.getItem('createdProjects')) || [];
createdProjects.push(newProject);
localStorage.setItem('createdProjects', JSON.stringify(createdProjects));
updateProjectManagement();
document.getElementById('create-project').style.display = 'none';
});
解释:这段代码监听创建项目表单的提交事件。它获取表单中的输入数据,创建一个新的项目对象,并将其添加到本地存储中的项目数组。然后更新项目管理界面。
代码片段5: 动态生成项目卡片
function generateProjectCards(sectionId) {
if (sectionId === 'join-project') {
const container = document.querySelector('#join-project .cards-container');
container.innerHTML = '';
const projects = [
/* 省略部分项目信息*/
];
projects.forEach(project => {
const card = document.createElement('div');
card.className = 'project-card';
card.innerHTML = `
<h3>${project.title}</h3>
<p>创建人:${project.creator}</p>
<p>${project.description}</p>
<button onclick="applyJoinProject('${project.id}')">申请加入</button>
`;
container.appendChild(card);
});
}
}
解释:这个函数用于动态生成项目卡片。当用户点击侧边栏的“加入项目”链接时,它会清空现有的项目卡片并生成新的项目卡片。
四、附加特点设计与展示
4.1 导航栏(附加功能)
意义:导航栏是用户与网站交互的桥梁,它不仅提供了页面内各个部分的快速访问,还增强了用户体验。在“ProjectPartner”平台中,导航栏的附加功能可以包括动态高亮当前激活的链接、搜索框集成以及用户个人中心的快速访问,这些功能有助于用户更高效地找到所需信息。
实现思路:
- 动态高亮:使用JavaScript监听导航项的点击事件,并动态添加激活状态的样式。
- 用户个人中心:提供一个快速链接到用户个人中心,方便用户管理个人信息和参与的项目。
重要的/有价值的代码片段,并解释:
/* 导航栏样式 */
header {
background-color: #f8f9fa;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 导航项目样式 */
nav ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
}
nav ul li a {
text-decoration: none;
color: #333;
}
nav ul li a:hover {
text-decoration: underline;
}
nav ul li a.active {
font-weight: bold;
color: #000;
}
这段CSS代码定义了导航栏的基本样式。header
类设置了导航栏的背景颜色、内边距,并使用Flexbox布局确保内容水平和垂直居中。nav ul
类去除了列表的默认样式,并使用Flexbox布局导航链接。nav ul li a
类定义了链接的默认样式,包括无文本装饰、颜色等。nav ul li a:hover
类为鼠标悬停状态添加了下划线文本装饰,而nav ul li a.active
类则定义了激活状态的样式,包括字体加粗和颜色变化。
// 为侧边栏链接添加点击事件监听器
document.querySelectorAll('.sidebar ul li a').forEach(item => {
item.addEventListener('click', function(event) {
event.preventDefault(); // 阻止链接默认行为
const targetSection = this.getAttribute('href').substring(1);
const sections = document.querySelectorAll('.project-content > div');
// 隐藏所有内容部分
sections.forEach(section => {
section.style.display = 'none';
});
// 移除所有侧边栏链接的激活状态
document.querySelectorAll('.sidebar ul li a').forEach(link => {
link.classList.remove('active');
});
// 激活当前链接
this.classList.add('active');
// 显示对应的内容部分
document.getElementById(targetSection).style.display = 'block';
});
});
这段JavaScript代码为导航栏中的链接添加了点击事件监听器。当用户点击某个链接时,它会阻止默认的跳转行为,隐藏所有内容部分,移除其他链接的激活状态,并将当前点击的链接设置为激活状态,最后显示对应的内容部分。
成果展示:
4.2 首页(附加功能)
意义:首页是用户访问“ProjectPartner”平台时首先看到的页面,它不仅需要展示平台的核心价值和服务,还应该包含一些附加功能来提升用户体验和互动性。
实现思路:在首页集成一个资讯推送区域,实时展示最新的行业动态,以吸引用户进一步探索和参与。
重要的/有价值的代码片段,并解释:
<!-- 首页动态资讯推送区域 -->
<section class="news-feed">
<div class="news-item" onclick="location.href='#'">最新项目更新:云计算平台升级</div>
<div class="news-item" onclick="location.href='#'">行业动态:生物能源新突破</div>
<div class="news-item" onclick="location.href='#'">深度学习实验室新成果发布</div>
</section>
这展示了如何在首页集成资讯推送区域。<section>
标签用于定义页面的不同部分,<div>
用于创建资讯项和项目更新项。
成果展示:
4.3弹窗设置(附加功能)
意义: 弹窗是一种有效的用户交互方式,它可以用于各种场景,如提示信息、表单提交确认、广告展示等。在“ProjectPartner”平台中,弹窗可以用于申请加入项目时的确认提示,确保用户在提交申请前有机会再次确认自己的选择,从而提高用户体验和操作的准确性。
实现思路:
- 使用HTML和CSS创建弹窗结构:定义弹窗的HTML结构和样式,确保弹窗在视觉上与网站整体风格一致。
- 使用JavaScript控制弹窗显示和隐藏:通过监听用户的操作(如点击按钮)来控制弹窗的显示和隐藏。
- 弹窗内容动态加载:根据用户的操作动态加载弹窗内容,如显示用户即将加入的项目信息。
重要的/有价值的代码片段,并解释:
// 获取弹窗元素和关闭按钮
var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];
// 点击按钮打开弹窗
function openModal() {
modal.style.display = "block";
}
// 点击<span> (x) 关闭弹窗
span.onclick = function() {
modal.style.display = "none";
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
这段JavaScript代码控制弹窗的显示和隐藏。openModal
函数设置弹窗的显示,span.onclick
和window.onclick
函数设置点击关闭按钮和点击窗口之外区域时隐藏弹窗。
成果展示:
- 确认操作:用户在申请加入项目前,会弹出确认提示,确保用户明确自己的操作。
- 提升用户体验:通过弹窗提示,用户可以更清楚地了解自己的操作结果,减少误操作。
- 视觉一致性:弹窗的样式与网站整体风格一致,提升了整体的美观度。
通过这种弹窗设置,可以有效地提高用户的操作准确性和满意度,同时也增强了平台的交互性和专业性。
4.4成果展示
当前功能
-
登录界面针对“学工号”实施了限制,仅允许输入数字字符。
-
首页精心设计了项目推荐功能,根据用户偏好及历史行为,智能推荐几个合适的项目,助力用户快速发现心仪之选。
-
注册界面可选择身份,填写不同注册信息。针对“邮箱”,“电话”实施限制,要求必须填完所有注册信息方可注册。
-
导航栏可跳转至首页,消息,项目和我的页面,实现随心跳转,方便实现页面切换。
-
消息界面功能全面,支持消息的发送及历史记录的保存,便于用户随时回顾交流内容。
-
项目界面内容丰富,涵盖了项目的创建、加入及管理三大板块。其中,管理项目细分为“我加入的项目”与“我创建的项目”两大类别,所有相关操作在用户未注销账户前均持续有效。
-
在创建项目时,用户需填写项目名称、选择开始日期(通过日历便捷选取)、设定招募人数、明确项目方向、添加相关标签,并编辑正文内容。点击“创建项目”按钮后,所填信息将即时展示在项目管理界面中。
-
加入项目流程中,用户只需点击感兴趣项目下的“申请加入”按钮,系统会弹出确认弹窗,这一人性化设计旨在促使用户做出慎重选择。确认后,该项目将自动归入“项目管理”下的“我加入的项目”列表中,同时原“申请加入”按钮文字变更为“已加入”,清晰反映项目状态。
-
在“我加入的项目”管理下,每个项目均设有“退出”按钮,用户点击后,该项目内容将被删除,实现灵活管理。
-
对于“我创建的项目”,每个项目均配备删除与修改按钮。点击删除按钮,项目将从“我创建的项目”列表中移除;点击修改按钮,则跳转至创建项目页面,并预填充原项目信息,便于用户快速修改后更新项目信息。
-
-
我的界面允许用户填写并保存个人信息,这些信息在用户未注销账户前将长期保留,便于用户随时查看与更新。
-
每个界面增加背景图,增加美观。
未来功能
- 表单验证:为注册和登录页面增加表单验证功能,确保用户输入合法的内容。
- 动态内容加载:实现通过JavaScript动态加载项目数据,而不是仅使用静态HTML。
- 更多功能敬请期待!
五、目录说明和使用说明
5.1目录结构及说明
ProjectPartner/
│
├── pictures/ # 存放图片资源
│ ├── banner.jpg
│ ├── IMG_1921.JPG
│ ├── ...
│ └── IMG_1960J
│
├──注册.html # 存放HTML页面文件
│
├──登录.html
│
├──首页.html
│
├──消息.html
│
├──我的.html
│
├──项目.html
├──项目.css
├──项目.js
│
└── README.md # 项目说明文件
说明:
- 有一个
项目.css
文件,它包含项目页面的样式定义。 项目.js
文件包含用于项目页面交互的脚本。- 项目的所有HTML页面文件。每个文件代表应用程序的一个页面,如
登录.html
、首页.html
、我的.html
和项目.html
。 - pictures/: 这个文件夹包含项目中使用的所有图片资源。
- README.md: 这是一个文本文件,通常包含项目的描述、安装指南、使用说明等。
5.2测试人员运行网页步骤
- 准备环境:
- 确保你的计算机上安装了现代浏览器,如Google Chrome、Mozilla Firefox、Microsoft Edge等。
- 打开HTML文件:
- 双击任何一个HTML文件(如
登录.html
),这将使用默认的网页浏览器打开该文件。
- 双击任何一个HTML文件(如
- 在浏览器中查看:
- 浏览器将加载并显示网页内容。
- 页面跳转:
- 在打开的网页中,通常会有一些链接或按钮允许你跳转到其他页面(如从
首页.html
跳转到消息.html
或我的.html
)。 - 点击这些链接或按钮,即可实现页面之间的跳转。
- 在打开的网页中,通常会有一些链接或按钮允许你跳转到其他页面(如从
- 调试和测试:
- 如果需要对网页进行调试,可以右键点击页面元素,选择“检查”(Inspect),打开开发者工具进行调试。
- 测试人员可以检查页面的响应性、功能实现、链接是否正确等。
六、单元测试
6.1测试工具选择及单元测试简易教程
何为单元测试:对软件中的最小可测试单元进行检查和验证,“单元”可以是一个函数、方法、类、功能模块或者子系统。可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。测试用例要覆盖常用的输入组合、边界条件和异常。单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。
选用的测试工具: Jest
学习单元测试: 通过在线教程、官方文档、技术博客和实践项目来学习单元测试。Jest 是一个由Facebook开发的JavaScript测试框架,它非常适合用于前端项目的单元测试。
简易教程:
-
安装 Jest: 在你的项目中安装Jest。
bash
npm install --save-dev jest
-
配置 Jest: 在
package.json
文件中添加测试脚本。json
"scripts": { "test": "jest" }
-
编写测试用例: 创建一个测试文件,例如 6.2代码
-
运行测试: 在命令行中运行
npm test
来执行测试。
6.2部分单元测试代码及说明
用户注册功能
说明:register 测试正常用户注册后能否成功注册。(测试用例1)
import { register } from './UserService';
describe('UserService', () => {
it('should register a user successfully', () => {
const user = { username: 'testuser', email: 'test@example.com', password: 'password123' };
const result = register(user);
expect(result.success).toBe(true);
});
});
输入不符合要求的邮箱格式,验证是否阻止注册并返回错误。(测试用例2)
注册信息没有填完,验证是否阻止注册。(测试用例3)
用户登录功能—login测试登录界面学工号和密码是否符合要求,若不符合要求,验证是否阻止登录并返回错误。(测试用例4)
import { login } from './UserService';
describe('UserService', () => {
it('should not allow login with invalid credentials', () => {
const credentials = { username: 'wronguser', password: 'wrongpassword' };
const result = login(credentials);
expect(result.success).toBe(false);
expect(result.message).toContain('Invalid credentials');
});
});
用户退出功能
验证用户退出后,是否能够返回到登录界面。(测试用例5)
import { logout } from './UserService';
describe('UserService', () => {
it('should logout user and redirect to login screen', () => {
const result = logout();
expect(result.success).toBe(true);
expect(result.message).toBe('User logged out successfully');
});
});
聊天功能—说明:sendMessage函数测试聊天功能,消息点击发送,验证是否有消息出现到聊天窗口。(测试用例6)
import { sendMessage } from './ChatService';
describe('ChatService', () => {
it('should display message in chat window after sending', () => {
const message = 'Hello, World!';
const result = sendMessage(message);
expect(result.success).toBe(true);
expect(result.message).toBe(message);
});
});
项目发布功能—发布项目时项目标题为空,验证是否阻止发布并返回错误。(测试用例7)
说明: navigate函数测试点击导航栏的不同组件,验证是否会实现跳转。(测试用例8)
import { navigate } from './NavigationService';
describe('NavigationService', () => {
it('should navigate to different components on clicking navigation bar', () => {
const result = navigate('Home');
expect(result.success).toBe(true);
expect(result.component).toBe('Home');
});
});
消息中选择不同的人聊天,验证聊天窗口内信息是否不同。(测试用例9)
正常创建项目—正常创建项目,验证项目是否成功发布。(测试用例10)
6.构造思路与测试人员的***难
构造测试数据的思路:
- 边界值分析: 选择边界值作为测试数据,例如空字符串、特殊字符、极端值等。
- 等价类划分: 将输入数据分为有效等价类和无效等价类,确保每个类别都有测试用例。
- 错误推测法: 基于经验和直觉推测可能的错误,并构造相应的测试数据。
- 测试用例优先级: 优先测试核心功能和最可能出错的部分。
考虑测试人员的***难:
- 覆盖所有分支: 确保测试用例覆盖所有的代码分支,包括正常流程和异常流程。
- 使用 Mock 和 Spy: 对外部依赖进行模拟和监控,确保测试的独立性和可控性。
- 随机化测试数据: 使用随机化方法生成测试数据,以增加测试的不确定性和覆盖面。
- 持续集成: 将单元测试集成到持续集成流程中,确保每次代码提交都会自动运行测试。
七、Github签入截图
八、困难及解决方法
困难一:代码环境的选取
- 困难描述:在项目开发初期,面对众多的代码编辑器和开发环境选择,难以决定哪种工具最适合团队的开发需求和工作流程。
- 解决尝试:通过询问学长学姐和同学,对比不同编辑器的功能特性,如插件支持、代码提示、调试工具等。尽量使用我们电脑上现有软件。
- 是否解决:是
- 有何收获:提升了基于信息收集和分析做出决策的能力。意识到选择正确的开发环境对提升开发效率的重要性。学会了如何快速适应新工具,为未来可能的工具更换或技术更新做好准备。
困难二:页面刷新导致数据丢失
-
困难描述:在创建项目后,先前创建的项目记录会丢失。
-
解决尝试:使用浏览器的本地存储:尝试使用
localStorage
或sessionStorage
来保存数据,但发现这些方法只适用于小量数据且不便于管理。服务器端数据库存储:考虑将数据保存在服务器端的数据库中,这样即使页面刷新,数据也能从数据库中重新加载。
前端状态管理:使用前端状态管理库(如Redux)来管理状态,但发现对于本项目来说过于复杂。
-
是否解决:是
-
有何收获:学会了在Node.js环境下使用MongoDB进行数据的增删改查操作。加深了对前后端分离架构的理解,明确了前端发送请求和后端处理请求的流程。加深了API的理解,学会了如何开发用于处理增删改查的API。
困难三:消息聊天记录未持久化
-
困难描述:聊天应用中,用户发送的消息在页面刷新后丢失,无法持久化保存聊天记录。
-
解决尝试:使用浏览器的本地存储:尝试使用
localStorage
或sessionStorage
来保存数据,但发现这些方法只适用于小量数据且不便于管理。服务器端数据库存储:考虑将数据保存在服务器端的数据库中,这样即使页面刷新,数据也能从数据库中重新加载。
前端状态管理:使用前端状态管理库(如Redux)来管理状态,但发现对于本项目来说过于复杂。
-
是否解决:是
-
有何收获:学习了如何设计适合存储聊天记录的数据库模型。要多查阅资料,尝试各种方法。
困难四:后台环境配置困难
-
困难描述:在配置Node.js项目的后台环境时,遇到了依赖安装失败、数据库连接错误等问题。
-
解决尝试:依赖版本检查:确保所有依赖库的版本兼容。使用
npm
的--legacy-peer-deps
选项:解决依赖库之间的兼容性问题。 -
是否解决:是
-
有何收获:学会了如何使用
npm
管理项目依赖,解决依赖冲突问题。掌握了使用dotenv
库来管理环境变量的方法。:加深了对MongoDB数据库连接和配置的理解
九、评价你的队友
102202130林烨对042201401陈高菲的评价:陈高菲同学的动手实践能力和学习新技术的速度较强,经常我在犹犹豫豫不知道怎么下手寻找切入点的时候,她总是能很快地找到相应的解决方案并且实现它。我欣赏陈高菲同学出色的动手实践能力,她的敢想敢做的行事风格总是能有效推动我们的项目进度,期待未来能够有再次与他合作的机会。(值得学习的地方)她总体上做得很好,但在一些细节处理上还有提升空间,更加关注细节将有助于提高工作质量。(需要改进的地方)
042201401陈高菲对102202130林烨的评价:林烨同学在项目中展现出极高的逻辑思维能力和扎实的基础知识,总能帮我解决我死磕很久的问题。同时,她的耐心与细致也给我留下了深刻印象,在我遇到困惑时,他总能耐心指导并帮助我理清思路。她的思维敏捷,总是会考虑到一些我没有考虑到的问题。与林烨的合作让我看到了自己需要提升的地方。(值得学习的地方)在面对紧张的项目进度时,她有时会显得有些焦虑,可以进一步提高自己的压力管理能力,以更好地应对工作中的挑战。(需要改进的地方)