软件工程第二次结对作业
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2024 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281 |
这个作业的目标 | 通过代码实现校园项目招募平台的设计 |
姓名及学号 | 黎曼 102201140 |
结对成员及学号 | 黄俊瑶 102201138 |
结对同学博客链接 | https://www.cnblogs.com/littlyellowduck |
Github仓库地址 | https://github.com/pear-09/102201140-102201138 |
0.Markdown编辑器
1.具体分工
本项目的具体分工如下:
黄俊瑶同学:
- 前端开发:
- 负责首页、项目、发布模块页面布局与设计,包括导航栏、侧边栏、项目列表等关键UI组件。
- 实现交互效果,如按钮点击、下拉菜单、悬浮效果、动态页面跳转等。
- 使用Vue.js构建项目的动态内容,确保用户能够查看和管理项目。
- 后端开发:
- 实现项目发布、成员管理、组队请求处理等后端逻辑。
- 接口开发:
- 负责与后端的接口对接,确保前端能够通过API获取和更新数据。
- 实现接口调用,如获取项目列表、发布项目、查看组队请求等。
- 处理与用户角色相关的权限逻辑,例如项目发布者和参与者不同的功能权限。
黎曼同学:
-
前端开发:
-负责登录、聊天、发现等页面的实现。使用Vue.js构建项目的动态内容,确保能够根据分类显示项目,以及用户的实时聊天功能。
-
后端开发:
- 负责项目数据的存储与管理,设计并实现项目的API接口。
- 实现用户登录、组队审核和请求数据等后端逻辑。
- 使用Node.js或其他后端框架进行开发,并与前端的API接口无缝对接。
-
测试:
- 负责功能模块的测试,包括前后端接口的联调测试,确保各模块的稳定性。
- 编写测试用例,验证项目功能,如发布项目、组队请求、项目进度更新等。
- 使用自动化测试工具或手动测试,检查各类交互和功能是否按预期运行。
2.PSP表格
PSP 表格 | 校园合作网页设计项目 |
---|---|
项目名称 | ProjectPartner |
开发者姓名 | 黎曼 |
开发者姓名 | 黄俊瑶 |
日期 | 2024年9月28日至2024年10月9日 |
任务/活动 | 估算(小时) |
用户界面设计 | 15 |
前端开发 | |
- HTML结构搭建 | 10 |
- CSS样式编写 | 10 |
- JavaScript交互实现 | 20 |
后端开发 | |
- 数据库设计 | 5 |
- 服务器逻辑编写 | 10 |
- API接口开发 | 2 |
功能测试 | 5 |
单元测试 | 5 |
博客撰写 | 4 |
总计 | 86 |
备注:
- 前端开发:构建用户通过浏览器与之交互网页界面的过程。
- 后端开发:实现网页的具体功能,和前端实现数据交互。
- 单元测试:用户测试,各种请求能否实现。
- 博客撰写:将开发过程和结果详细分析呈现。
3.解题思路描述与设计实现说明
代码实现思路
问题分析
在本次项目中,用户不仅需要发布项目、参与他人的项目还要管理已经参与和发布的项目。项目发布者和参与者具有不同的权限和功能要求。我们的目标是设计一个系统,用户无论是作为项目的发布者还是参与者,都能通过统一的界面进行管理。主要挑战包括:
- 项目的管理逻辑:如何根据用户身份(发布者或参与者)动态展示不同的管理权限。
- 用户组队请求的处理:如何合理设计组队申请的审核与状态反馈机制。
- 项目进度的可视化管理:如何方便发布者更新项目进度,并让参与者清晰地查看项目进展。
- 项目的分类检索:用户如何根据不同项目的分类或子分类迅速筛选寻找合适的项目。
- 实时聊天功能的实现:不同用户之间如何进行实时的聊天交流,提高沟通效率。
模块划分
基于上述分析,系统主要划分为以下功能模块:
- 项目列表模块:展示用户发布的项目和加入的项目,方便用户查看不同项目的标题和内容。
- 项目管理模块:该模块区分发布者和参与者的权限,发布者可以在该模块中更新项目内容、状态,可以删除任务,管理项目成员;参与者可以查看成员列表,或退出项目。
- 项目详情模块:显示项目的详细信息,包括项目的名称、内容、进度、开始日期等。参与者可以发起申请,参与项目。
- 组队申请模块:用于管理组队请求的发送和审核。发布者可以审核组队申请,参与者可以查看自己发出的组队请求状态。
- 实时聊天模块:用户之间可以实时聊天沟通。
用户角色逻辑
我们设计了以下用户角色的逻辑:
- 项目发布者:拥有完整的管理权限,包括编辑项目内容、审核组队请求、更新项目进度、管理成员等。
- 项目参与者:可以查看项目进展、查看和退出项目。
- 权限动态切换:系统根据用户的身份,在同一个页面中动态加载相应的功能和权限。
技术实现
系统使用 Vue.js 实现前端页面的动态渲染,Node.js 实现后端逻辑处理。具体的实现步骤如下:
-
前端实现
- Vue.js 组件化设计:使用 Vue.js 创建各个模块的组件,如项目列表、项目详情、组队申请等,每个组件独立开发,具有较好的复用性。
- 动态渲染与角色判断:通过 Vue Router 实现页面的动态跳转,根据用户的身份不同,展示不同的功能按钮。利用条件渲染 (
v-if
/v-show
) 实现发布者和参与者界面的差异化。 - 接口对接:通过 Axios 发起与后端 API 的请求,获取项目列表、组队申请等数据,并实时更新页面内容。
-
后端实现
- API 设计:使用 Node.js 和 Express 框架开发,包括用户登录、项目管理、组队申请处理、任务管理等接口。
- 权限管理:通过后端校验用户身份,确保用户只能对自己发布的项目进行管理,对他人项目只能作为参与者进行操作。
流程图
项目信息数据流图
代码片段:项目发布功能
methods: {
updateSubcategories() {
this.subcategories = this.categories[this.category];
this.subcategory = this.subcategories.length > 0 ? this.subcategories[0] : '';
},
async submitNewProject() {
if (!this.title || !this.num || !this.date || !this.category || !this.subcategory) {
alert('请填写所有必填字段!');
return;
}
// 获取已登录的用户名
const username = localStorage.getItem('loggedInUser');
// 使用当前时间戳生成唯一 ID
const projectData = {
id: Date.now(), // 使用时间戳作为 ID
title: this.title,
num: this.num,
members: [],
category: this.category,
subcategory: this.subcategory,
startDate: this.date,
skills: this.jineng,
content: this.content,
status: '招募中', // 默认状态为"招募中"
};
const userProjectData = {
username: username,
projects: [projectData],
joinRequests: [],
sentRequests: [],
alert: [],
};
try {
const response = await axios.post('http://localhost:3000/api/projects', userProjectData);
alert('项目发布成功');
this.resetForm(); // 清空表单
} catch (error) {
console.error('项目发布失败', error);
if (error.response) {
alert(`项目发布失败: ${error.response.data.error || '未知错误'}`);
} else {
alert('网络错误,请检查服务器是否运行。');
}
}
},
async submitUpdatedProject() {
if (!this.title || !this.num || !this.date || !this.category || !this.subcategory) {
alert('请填写所有必填字段!');
return;
}
const updatedProjectData = {
id: currentId,
title: this.title,
num: this.num,
category: this.category,
subcategory: this.subcategory,
startDate: this.date,
skills: this.jineng,
content: this.content,
};
try {
await axios.put(`http://localhost:3000/api/projects/${localStorage.getItem('loggedInUser')}/${currentId}`, updatedProjectData);
alert('项目更新成功');
this.resetForm();
} catch (error) {
console.error('项目更新失败', error);
alert(`项目更新失败: ${error.response.data.error || '未知错误'}`);
}
},
resetForm() {
this.title = '';
this.num = '';
this.date = '';
this.jineng = '';
this.content = '';
this.category = '';
this.subcategory = '';
this.subcategories = [];
this.isEditing = false;
currentId = 0;
},
}
功能分析:
-
项目分类和子分类选择:
updateSubcategories()
函数用于在用户选择项目分类时,自动更新相应的子分类列表。通过动态设置subcategories
,子分类的select
列表会随着分类的变化自动更新。
-
新项目提交:
submitNewProject()
是一个异步函数,处理用户提交新项目的请求。- 首先检查表单中所有必填字段是否填写完整,若有遗漏则提醒用户。
- 通过
localStorage
获取已登录的用户名,并使用当前时间戳Date.now()
生成一个唯一的项目ID。 - 组装
projectData
对象,其中包含项目的标题、人数、技能、分类、子分类等信息,并将状态设为 "招募中"。 - 通过
axios.post()
发送数据到服务器端,并捕获成功或失败的情况。在成功发布项目后,重置表单。
-
项目更新:
submitUpdatedProject()
是用于更新已有项目的功能,与新项目提交类似,但它会根据currentId
来更新项目。- 它检查是否有未填写的必填字段,确保更新信息的完整性。
- 通过
axios.put()
向后端发送更新后的项目数据。
-
表单重置:
resetForm()
清空所有表单字段,并重置相关变量,如isEditing
和currentId
,确保表单可以用于新项目的创建。
在你提供的代码中,有几个关键的功能模块,其中最有价值的片段之一是项目的状态更新逻辑和成员管理逻辑。它们实现了对项目的动态操作,下面是对其详细的解释:
代码片段:状态更新功能
changeStatus(project, index) {
this.selectedStatus = project.status || '招募中';
this.showStatusSelect = true;
this.currentProjectIndex = index;
},
async updateProjectStatus() {
const project = this.projects[this.currentProjectIndex];
project.status = this.selectedStatus;
try {
await axios.put(`http://localhost:3000/api/projects/${localStorage.getItem('loggedInUser')}/${project.id}`, project);
alert('状态更新成功');
this.showStatusSelect = false;
} catch (error) {
console.error('状态更新失败', error);
}
},
cancelStatusChange() {
this.showStatusSelect = false;
}
解释:
- 功能:此功能让用户能够修改项目状态(如项目是否在招募成员),并将更新发送到后端 API。
changeStatus
方法:打开状态选择框,并设置当前正在操作的项目索引。selectedStatus
保存项目的当前状态,若无状态则默认“招募中”。showStatusSelect
为true
,打开状态选择的 UI。
updateProjectStatus
方法:将用户选择的新状态通过axios.put
请求发送给后端,成功后关闭状态选择框,并弹出提示信息。- 更新后的项目数据通过 PUT 请求发送到
/api/projects/
端点,按用户及项目 ID 更新状态。 - 若成功,则提示用户“状态更新成功”,否则记录错误信息。
- 更新后的项目数据通过 PUT 请求发送到
cancelStatusChange
方法:如果用户取消操作,关闭状态选择框。
代码片段:成员管理功能
showMembers(members, creator, index) {
this.currentMembers = members;
this.currentCreator = creator;
this.currentProjectIndex = index;
this.showMembersList = true;
},
async removeMember(member) {
if (this.currentProjectIndex === null) {
console.error('当前项目索引未设置');
return;
}
const projectId = this.projects[this.currentProjectIndex].id;
const username = localStorage.getItem('loggedInUser');
try {
await axios.put(`http://localhost:3000/api/projects/removeMember/${username}/${projectId}`, { member });
this.currentMembers = this.currentMembers.filter(m => m !== member); // 更新当前成员列表
alert(`${member} 已被删除`);
} catch (error) {
console.error('删除成员失败', error);
}
}
解释:
- 功能:该部分实现了显示项目成员列表以及删除项目成员的功能。
showMembers
方法:展示项目成员列表,保存当前项目成员members
及项目创建者creator
。showMembersList = true
:显示成员列表 UI。
removeMember
方法:用户可以删除指定项目中的成员,通过axios.put
请求将操作发送至后端,更新成功后刷新成员列表。filter
方法从当前成员列表中过滤掉被删除的成员,动态更新页面上的成员列表。- 若成功,弹出提示信息;若失败,记录错误信息。
vue-router路由跳转:
模块化结构
- 清晰的组织:将不同的视图组件与其路由路径分开,使代码结构清晰,易于理解和维护。
- 增强可读性:模块化的路由定义提高了代码的可读性,开发者可以快速定位和理解每个路由的功能。
动态路由支持
- 灵活性:使用动态路由参数(如
:project
和:id
)允许在 URL 中传递不同的项目标识符,能够根据不同项目动态加载相应的组件和数据。 - 适应性强:可以轻松处理不同的项目详情,使得应用更具适应性,满足不同用户需求。
嵌套路由功能
- 层次化的视图结构:支持嵌套路由,使得应用能够展示具有层次结构的视图,如
/xiangmu
路由下的多个子路由(如wofabu
,wocanyu
等)。 - 导航的流畅性:子路由的设计使得用户可以更自然地在应用的不同部分之间切换,提升用户体验。
路由重定向
- 用户体验提升:通过设置默认重定向(如
/xiangmu
自动重定向到/xiangmu/wofabu
),确保用户在访问某个路径时能够快速跳转到预期的子路由,减少了用户的操作步骤。 - 简化导航:减少了用户记忆多个路径的负担,使得应用的使用更加直观。
Props传递
- 组件间数据传递:通过设置
props: true
,可以将路由参数直接传递给组件,简化了数据传递的过程,减少了不必要的状态管理。 - 提高组件复用性:组件能够更独立地处理其接收到的数据,增强了组件的复用性和模块化。
便于调试和测试
- 简化测试:路由分离使得单元测试和集成测试变得更加简单,可以独立地测试每个组件的路由逻辑。
- 快速迭代:模块化的设计使得在开发过程中能够快速迭代和修改路由配置,而不影响其他部分。
4.附加特点设计与展示
项目分类与标签系统
平台支持项目分类和标签系统,使用户在发布项目时可以为项目添加多个标签,帮助其他用户更准确地查找和筛选项目。此功能尤其适用于跨领域项目的招募,满足不同兴趣和背景的用户需求。
代码实现思路
发布界面选择分类,保存至后端
<label for="">项目分类:</label>
<select id="category" v-model="category" @change="updateSubcategories" required>
<option v-for="(subcategories, key) in categories" :key="key" :value="key">{{ key }}</option>
</select>
<label for="">子分类:</label>
<select id="subcategory" v-model="subcategory" required>
<option v-for="sub in subcategories" :key="sub">{{ sub }}</option>
</select>
methods: {
updateSubcategories() {
this.subcategories = this.categories[this.category];
this.subcategory = this.subcategories.length > 0 ? this.subcategories[0] : '';
},
发现界面
通过点击分类向后端获取相应数据
methods: {
toggleSubcategory(category) {
this.expandedCategory = this.expandedCategory === category ? null : category;
this.isClicked = !this.isClicked; // 切换状态
},
selectSubcategory(subcategory) {
this.selectedSubcategory = subcategory;
this.loadProjects();
},
关键部分相关图示
在发布界面即可实现分类标签的选择
在发现界面选择分类可以显示当前子分类的所有项目
5.网页功能展示
用户登录
- 简化了登录模块,用户通过登录系统,进入项目管理页面。根据用户身份自动加载相应的权限和功能模块。
首页展示模块
- 用户登录后首先进入首页,首页展示最新的项目动态、推荐项目、以及用户可能感兴趣的项目类别。同时提供快速入口,便于用户快速发布或加入项目。
项目列表
- 系统展示用户发布的项目和参与的项目。
项目管理
- 发布者:可以管理项目的详细信息,包括编辑项目内容、更新项目进度、添加和删除成员、解散队伍等功能。
- 参与者:可以查看项目的进展,退出项目,查看队伍成员信息等。
申请状态列表
- 参与者可以查看自己发出的组队申请的处理状态(审核中、已通过、已拒绝),了解项目参与进展。
组队审核列表
- 发布者可以在该模块中查看并审核其他用户发来的组队请求,选择接受或拒绝申请。
项目发布编辑功能
- 用户可以自由选择和填写相应的项目内容,选择标签可以让平台更好地分类项目。
项目详情查看及申请加入功能
- 用户可以通过点击项目,查看项目的详细信息,并且申请加入该项目。
项目分类筛选
- 用户可以根据项目的类别(如技术方向、项目类型)进行筛选,快速找到感兴趣的项目。
实时聊天
- 项目成员之间可以通过嵌入的聊天功能进行实时沟通,方便协作和任务分配,提升团队合作效率。
6.目录说明和使用说明
目录说明如下
前端代码目录
D:\zuoye\zuoye\homework1\homework1
│
├── .git/ # Git 相关文件
├── coverage/ # 测试覆盖率报告
│ ├── lcov-report/ # lcov 格式的测试报告
│ ├── clover.xml # Clover 格式的覆盖率报告
│ ├── coverage-final.json # 最终的覆盖率报告
│ └── lcov.info # lcov 信息文件
│
├── node_modules/ # 项目依赖库
├── public/ # 公共资源目录
├── src/ # 源代码目录
│ ├── assets/ # 资源文件(如图片、字体等)
│ ├── components/ # Vue 组件
│ ├── router/ # 路由配置
│ ├── views/ # 页面视图
│ │ ├── DengLu.vue # 登录页面
│ │ ├── FaBu.vue # 发布项目页面
│ │ ├── FaXian.vue # 发现页面
│ │ ├── HomeProjectDetail.vue # 项目详情页面
│ │ ├── LiaoTian.vue # 聊天页面
│ │ ├── ProgramDetail.vue # 程序详情页面
│ │ ├── ShouYe.vue # 首页
│ │ ├── WoCanyu.vue # 我参与的项目页面
│ │ ├── WoFabu.vue # 我发布的项目页面
│ │ ├── WoShenghe.vue # 我审核的项目页面
│ │ ├── WoShenqing.vue # 我申请的项目页面
│ │ └── XiangMu.vue # 项目页面
│ ├── App.vue # Vue 主组件文件
│ └── main.js # 应用入口文件
│
├── tests/ # 测试代码
│ └── unit/ # 单元测试
│ ├── FaBu.spec.js # FaBu 组件的测试
│ ├── FaXian.spec.js # FaXian 组件的测试
│ ├── LiaoTian.spec.js # LiaoTian 组件的测试
│ ├── WoCanyu.spec.js # WoCanyu 组件的测试
│ ├── WoFabu.spec.js # WoFabu 组件的测试
│ ├── WoShenghe.spec.js # WoShenghe 组件的测试
│ ├── WoShenqin.spec.js # WoShenqin 组件的测试
│ └── XiangMu.spec.js # XiangMu 组件的测试
│
├── .gitignore # Git 忽略文件配置
├── babel.config.js # Babel 编译配置
├── jest.config.js # Jest 测试配置
├── jsconfig.json # JavaScript 配置文件
├── package.json # 项目依赖及脚本配置
├── README.md # 项目说明文件
└── vue.config.js # Vue 项目配置文件
后端代码目录
D:\zuoye (99)\zuoye\zuoye\homework2\homework2
│
├── data/ # 数据文件目录
│ ├── homeProjects.json # 存储用户的项目数据
│ └── projects.json # 存储项目的详细信息
├── node_modules/ # 项目依赖库
├── homework2.exe # 可执行文件
├── package-lock.json # 项目依赖的锁定文件
├── package.json # 项目依赖及脚本配置
└── server.js # 后端服务器文件
使用说明(更详细的使用说明在github的README文件)
1.从我们的Github仓库"https://github.com/pear-09/102201140-102201138"下载我们的网页源代码,进行解压缩。
2.安装VScode,并且安装Live Server插件。
3.打开dist文件夹,点击index.html文件运行在Google浏览器;
4.同时通过VScode打开backend文件夹:
如果你安装了node插件
找到server.js文件,右键->点击在集成终端中打开 -> 直接在终端输入"node server.js" 即可运行服务器,此时网页可以正常运行和使用;
如果你未安装node插件
通过以下步骤运行:
- Windows 系统
①下载 Node.js:访问 Node.js 官网。选择适合你电脑的版本(LTS 版本更稳定,适合大多数用户)。
②运行安装程序:下载完成后,双击安装文件(.msi)。在安装向导中,点击 Next。接受许可协议:阅读并接受许可协议,然后点击 Next。选择安装位置:选择安装目录(默认即可),然后点击 Next。
③选择安装组件:可以保持默认选项,确保勾选了 Automatically install the necessary tools 选项,以便后续使用 npm(Node.js 的包管理器),然后点击 Next。
④开始安装:点击 Install 开始安装。安装完成后,点击 Finish。 - macOS 系统
①下载 Node.js:访问 Node.js 官网。下载 macOS 安装包(.pkg 文件)。运行安装程序:双击下载的 .pkg 文件,按照安装向导的提示进行安装。
安装成功之后找到server.js文件,右键->点击在集成终端中打开 -> 直接在终端输入"node server.js" 即可运行服务器,此时网页可以正常运行和使用;
同时附上我和队友的联系方式,有任何问题可以联系我们:黎曼 2901868597;黄俊瑶 2790599728
6.单元测试
我们主要使用jest对发布、发现、聊天和项目管理等核心模块进行了单元测试,具体编写了如下.spec.js文件,同时由于篇幅问题,仅附上发布界面的测试代码,具体可见github:
测试用例
D:\zuoye\zuoye\homework1\homework1\tests\unit
│
├── FaBu.spec.js # 测试发布功能
├── FaXian.spec.js # 测试发现功能
├── LiaoTian.spec.js # 测试聊天功能
├── WoCanyu.spec.js # 测试我的参与
├── WoFabu.spec.js # 测试我发布
├── WoShenghe.spec.js # 测试我审核
├── WoShenqin.spec.js # 测试我申请
└── XiangMu.spec.js # 测试项目
测试代码
import { shallowMount } from '@vue/test-utils';
import FaBu from '@/views/FaBu.vue';
import axios from 'axios';
jest.mock('axios'); // 模拟 axios
describe('FaBu.vue', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(FaBu, {
mocks: {
$route: {
query: {}
}
}
});
localStorage.setItem('loggedInUser', 'testUser'); // 模拟用户登录
});
afterEach(() => {
wrapper.destroy();
localStorage.clear();
});
it('should submit a new project successfully', async () => {
// 模拟 axios post 成功的响应
axios.post.mockResolvedValueOnce({ status: 200 });
// 填写表单数据
wrapper.setData({
title: '测试项目',
num: 5,
date: '2024-10-10',
category: '创业',
subcategory: '科技创业',
jineng: '前端开发',
content: '这是一个测试项目的详细信息'
});
// 调用提交方法
await wrapper.vm.submitNewProject();
// 检查是否调用了 axios post 请求
expect(axios.post).toHaveBeenCalledWith('http://localhost:3000/api/projects', {
username: 'testUser',
projects: [
{
id: expect.any(Number), // 时间戳生成的 id
title: '测试项目',
num: 5,
members: [],
category: '创业',
subcategory: '科技创业',
startDate: '2024-10-10',
skills: '前端开发',
content: '这是一个测试项目的详细信息',
status: '招募中'
}
],
joinRequests: [],
sentRequests: [],
alert: []
});
expect(wrapper.vm.title).toBe(''); // 提交成功后表单被清空
});
it('should handle project submission failure', async () => {
// 模拟 axios 请求失败
axios.post.mockRejectedValueOnce(new Error('网络错误'));
// 填写表单数据
wrapper.setData({
title: '测试项目',
num: 5,
date: '2024-10-10',
category: '创业',
subcategory: '科技创业',
jineng: '前端开发',
content: '这是一个测试项目的详细信息'
});
// 调用提交方法并捕获错误
await wrapper.vm.submitNewProject();
// 检查是否调用了 axios post 请求
expect(axios.post).toHaveBeenCalled();
expect(wrapper.vm.title).toBe('测试项目'); // 提交失败后表单数据保持不变
});
});
7.Github代码签入记录截图
8.代码模块异常及解决方法
数据库连接异常
异常描述:
数据库连接失败,出现无法读出后端数据的情况。
解决方法:
- 检查数据库服务是否启动。
- 确定数据库的数据格式是否正确。
- 确定前端相应位置的请求路径是否正确
无效的API请求参数
异常描述:
API请求的参数不符合预期,导致服务器端无法正确处理。
解决方法:
- 确保前端发送的请求参数符合后端API的要求。
- 在后端输出结果进行参数验证。
9.评价
在过去的几周里,我与我的队友一起开发我们的校园项目招募平台。以下是我的评价:
-
技术能力:
- 我们一起开发网页的前后端,她能够快速地解决复杂的技术问题,并确保我们的API既高效又安全。
-
团队合作:
- 我们能够很好地沟通和协作,确保项目按时进展。
- 我们在国庆期间通过线上腾讯会议,积极参与讨论,提出建设性的意见。
-
责任感:
- 她对自己的工作负责,即使面临困难,也从不推卸责任。
- 她总是能够按时完成任务,并且质量上乘。
-
适应能力:
- 在开发过程中,需求经常变化,但队友总是能够迅速适应这些变化,调整工作计划。
- 面对紧急的bug修复,能够冷静应对,快速找到解决方案。
-
个人品质:
- 我的队友非常友好和乐于助人,无论是在工作还是在生活中。
- 她总是乐观向上,即使在压力下也能保持积极的态度。