软件工程第二次结对作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 作业要求链接
这个作业的目标 根据上次作业的原型,设计一个微信小程序
学号 102202111
合作伙伴 102202103王文豪
Github仓库地址 https://github.com/noen-hh/102202111-102202103.git

(小程序还在审核中,等审核完就可以扫码体验)

1.具体分工

王文豪(前端开发):

1,负责WXML和WXSS进行主页、项目、项目创建与发布模块页面布局与设计,包括导航栏、项目列表等关键UI组件。
2,实现交互效果,如按钮点击、动态页面跳转等。

刘哲睿(后端开发):

1,负责管理用户的注册登录信息,确保用户登录信息不会丢失。
2,负责编写和维护微信云函数,实现获取项目详情、申请加入/退出项目、删除项目以及更新项目状态等功能。
3,设计和优化数据库结构,确保数据的高效存储与检索,通过数据库实现项目的增删改查。

2.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(小时) 实际耗时(小时)
Planning 计划 3 4
Estimate 估计这个任务需要多少时间 70 102
Development 开发 24 40
Analysis 需求分析 (包括学习新技术) 4 6
Design Spec 生成设计文档 2 2
Design Review 设计复审 1 2
Coding Standard 代码规范 (为目前的开发制定合适的规范) 3 4
Design 具体设计 8 10
Coding 具体编码 8 10
Code Review 代码复审 4 6
Test 测试(自我测试,修改代码,提交修改) 5 6
Reporting 报告 2 3
Test Repor 测试报告 2 3
Size Measurement 计算工作量 2 3
Postmortem&Process Improvement Plan 事后总结, 并提出过程改进计划 2 3
合计 70 102

3.解题思路描述与设计实现说明

  • 代码实现思路,文字描述

通过微信开发者工具创建一个可供多人交流合作的项目平台小程序,在该项目平台上,用户在注册一个账号登陆后,可以实现自己项目的创建与发布,参加他人的项目,修改与删除自己的项目。首先,用户登陆进入后处在主页中,主页中可以查看已发布的项目,顶部附带搜索框可按项目名称关键词进行查找,点击相应的项目跳转进入后可了解项目详情,如项目的具体任务,参加该项目所需的技能,项目内已参加的人数等。根据个人的意愿可在相应的项目内进行项目申请,项目的发布人将会受到申请者的申请,并根据自身意愿进行回应。在主页下方的导航栏中,点击“项目”即可跳转到“我的项目”,用户可以看到自己已经参加的项目并且进行查看,同时可以对项目进行删除操作,页面右下角有个项目创建按钮,用户可以根据自己的自身情况选择是否创建自己的项目。点击导航栏中的“我的”前往个人中心,可对自身的个人信息进行查看和修改,并且附带与客服对话的功能。

  • 实现的方法

  • 云函数

  • 数据库

  • 前端:使用WXML和WXSS设计页面布局和样式,使用JavaScript编写页面逻辑,处理用户交互和数据绑定

  • 后端:编写后端业务逻辑,处理数据的增删改查。

  • 关键功能实现

  • 注册登录

  • 项目创建发布,申请,修改,删除

  • 查看他人信息

  • 关键实现的流程图

  • 我们认为重要的/有价值的代码片段

  • 登陆页面:
// 验证密码是否匹配
if (password !== confirmPassword) {
 wx.showToast({
   title: '密码不一致',
   icon: 'none'
 });
 return;
}

// 调用后端API进行注册
// ...

}
Page({
 data: {
   phone: '',
   password: ''
 },

 // 绑定手机号输入
 bindPhoneInput: function(e) {
   this.setData({
     phone: e.detail.value
   });
 },

 // 绑定密码输入
 bindPasswordInput: function(e) {
   this.setData({
     password: e.detail.value
   });
 },

 // 提交登录
 submitLogin: function() {
   const { phone, password } = this.data;

   // 输入验证
   if (!phone || !password) {
     wx.showToast({
       title: '请输入手机号和密码',
       icon: 'none'
     });
     return;
   }

   // 从云数据库中读取用户数据
   const db = wx.cloud.database();
   db.collection('user').where({
     phone: phone
   }).get()
     .then(res => {
       if (res.data.length > 0) {
         // 找到用户,进行密码匹配
         const user = res.data[0];
         if (user.password === password) {
           wx.showToast({
             title: '登录成功',
           });
           wx.navigateTo({
             url: '/pages/home/home' // 登录成功后跳转到主页
           });
         } else {
           wx.showToast({
             title: '密码错误',
             icon: 'none'
           });
         }
       } else {
         wx.showToast({
           title: '用户不存在',
           icon: 'none'
         });
       }
     })
     .catch(err => {
       wx.showToast({
         title: '查询失败',
         icon: 'none'
       });
       console.error(err);
     });
 }
});
  • 代码解释:类似于注册功能,使用 data 对象存储用户输入的手机号和密码,在 submitLogin 函数中,检查手机号和密码是否已填写,如果任一字段为空,显示提示信息。登录主要靠云数据库查询,查询云数据库中是否存在匹配的手机号。

  • 项目搜索:

// 处理搜索框输入事件
 onSearchInput(e) {
   this.setData({
     searchText: e.detail.value,
   });
 },

 // 处理搜索按钮点击事件
 onSearch() {
   const { searchText, works } = this.data;

   // 如果搜索框为空,展示所有项目
   if (!searchText) {
     this.setData({ filteredWorks: works });
     return;
   }

   const filteredWorks = works.filter(work => 
     this.matchTitle(work.title, searchText) // 使用匹配函数
   );
   this.setData({ filteredWorks });
 },

 // 匹配项目名称的函数
 matchTitle(title, searchText) {
   let matchCount = 0;
   for (let char of searchText) {
     if (title.includes(char)) {
       matchCount++;
     }
     if (matchCount >= 2) return true;
   }
   return false;
 }, 

代码解释:当用户点击搜索按钮时,onSearch 函数会被触发。这个函数首先检查搜索框是否为空。如果为空,则将所有项目设置为过滤后的项目列表。如果不为空,则使用 filter 方法和 matchTitle 函数来过滤项目列表,只保留那些项目名称中包含搜索关键词的项目。

  • 获取项目详情:
addProject: function() {
   // 跳转到添加项目的页面
   wx.navigateTo({
     url: '/pages/project/project'
   });
 },
 goToProjectDetail: function(e) {
   // 从事件对象获取项目ID
   const projectId = e.currentTarget.dataset.id;
   // 跳转到项目详情页面
   wx.navigateTo({
     url: '/pages/project-detail/project-detail?id=${projectId}'
   });
 }
代码解释:使用 wx.navigateTo 方法可以实现页面的跳转,触发事件的元素中获取 data-id 属性,该属性包含了项目的ID,然后使用这个ID来构建跳转URL。

项目申请:
applyForProject: function() {
   // 处理项目申请逻辑
   wx.showModal({
     title: '申请项目',
     content: '您确定要申请加入这个项目吗?',
     success: function(res) {
       if (res.confirm) {
         console.log('用户点击确定');
         // 发起网络请求提交申请
         wx.showToast({
           title: '申请已提交',
           icon: 'success',
           duration: 2000
         });
         // 可以在这里添加跳转逻辑,例如返回项目列表或到其他页面
         wx.reLaunch({
           url: '/pages/home/home'
         });
       } else if (res.cancel) {
         console.log('用户点击取消');
       }
     }
   });
 }

代码解释:通过一个模态对话框询问用户是否确定要申请加入某个项目,并根据不同的用户响应执行不同的操作。

  • 附加特点设计与展示

  • 在register.js中通过 bindPhoneInput、bindPasswordInput 和 bindConfirmPasswordInput 函数,将用户在输入框中输入的内容实时更新到页面的 data 对象中。在 submitRegister 函数中,首先检查所有字段是否已填写。如果有任何字段为空,显示提示信息并终止进一步的操作,使用正则表达式 ^1\d{10}$ 验证手机号是否为11位数字,且以1开头。
  • 以下是代码:
Page({
 data: {
   phone: '',
   password: '',
   confirmPassword: ''
 },

 // 绑定手机号输入
 bindPhoneInput: function(e) {
   this.setData({
     phone: e.detail.value
   });
 },

 // 绑定密码输入
 bindPasswordInput: function(e) {
   this.setData({
     password: e.detail.value
   });
 },

 // 绑定确认密码输入
 bindConfirmPasswordInput: function(e) {
   this.setData({
     confirmPassword: e.detail.value
   });
 },

 // 提交注册
 submitRegister: function() {
   const { phone, password, confirmPassword } = this.data;

   // 验证输入
   if (!phone || !password || !confirmPassword) {
     wx.showToast({
       title: '请填写所有字段',
       icon: 'none'
     });
     return;
   }

   // 验证手机号码
   if (!/^1\d{10}$/.test(phone)) {
     wx.showToast({
       title: '手机号必须为11位',
       icon: 'none'
     });
     return;
   }
  • 实现成果展示



  • 目录结构

miniprogram
├── images/                 # 存放图片资源的目录
│   ├── project.png
│   ├── avatar.png
│   └── 其他图片文件...
├── pages/                  # 存放小程序页面文件的目录
│   ├── home/                 # 主页
│   │   ├── home.js
│   │   ├── home.json
│   │   ├── home.wxss
│   │   └── home.wxml
│   ├── register/            # 注册页面
│   │   ├── register.js
│   │   ├── register.json
│   │   ├── register.wxss
│   │   └── register.wxml
│   ├── chat/                # 聊天页面
│   │   ├── chat.js
│   │   ├── chat.json
│   │   ├── chat.wxss
│   │   └── chat.wxml
│   ├── login/               # 登录页面
│   │   ├── login.js
│   │   ├── login.json
│   │   ├── login.wxss
│   │   └── login.wxml
│   ├── profile/            # 用户个人资料页面
│   │   ├── profile.js
│   │   ├── profile.json
│   │   ├── profile.wxss
│   │   └── profile.wxml
│   ├── project/             # 项目相关页面
│   │   ├── project.js
│   │   ├── project.json
│   │   ├── project.wxss
│   │   └── project.wxml
│   ├── project_1/           # 项目1页面
│   │   ├── project_1.js
│   │   ├── project_1.json
│   │   ├── project_1.wxss
│   │   └── project_1.wxml
│   ├── project_2/           # 项目2页面
│   │   ├── project_2.js
│   │   ├── project_2.json
│   │   ├── project_2.wxss
│   │   └── project_2.wxml
│   ├── project-detail/      # 项目详情页面
│   │   ├── project-detail.js
│   │   ├── project-detail.json
│   │   ├── project-detail.wxss
│   │   └── project-detail.wxml
│   └── utils/               # 工具函数目录
│       ├── utils.js
│       └── typings/           # TypeScript 类型声明文件
│           └── index.d.ts
├── app.json              # 小程序全局配置文件
├── app.ts                 # 小程序入口文件(TypeScript)
├── app.wxss               # 小程序全局样式文件
├── envList.js             # 环境变量配置文件
└── .gitignore             # Git 忽略文件配置
  • 单元测试

  • 学习单元测试
    理解概念:了解什么是单元测试,以及它在软件开发中的重要性。
    阅读文档:学习测试框架的官方文档,了解如何编写测试用例。
    观看教程:通过在线教程和课程学习单元测试的最佳实践。
    实践操作:在实际项目中编写单元测试,从简单到复杂逐步掌握。
    代码审查:学习他人的测试代码,理解不同的测试策略和方法。

  • 使用步骤
    1,在项目中安装了 jest,npm init -y npm install --save-dev jest
    2,部分单元测试代码

// projectPublish.test.js
const { publishProject } = require('./projectPublish');

describe('publishProject', () => {
 test('should publish a project successfully', async () => {
   const projectData = {
     name: '新项目',
     summary: '这是一个新项目的简介',
   };
   const result = await publishProject(projectData);
   expect(result.success).toBe(true);
   expect(result.message).toBe('项目发布成功');
 });

 test('should throw an error if project name or summary is missing', () => {
   expect(() => publishProject({ name: '新项目' })))
     .toThrow('项目名称和简介不能为空');
   expect(() => publishProject({ summary: '这是一个新项目的简介' })))
     .toThrow('项目名称和简介不能为空');
 });
});
  • 构造测试数据的思路
    1,边界值:测试数据的边界值,例如数组的空值、最大长度、最小长度等。
    2,异常值:测试异常或错误输入,例如无效的输入、负数等。
    3,典型值:测试正常使用情况下的典型值。
    4,组合值:测试不同数据组合的情况。
    5,依赖关系:如果函数之间存在依赖关系,构造测试数据时需要考虑这些依赖。

  • Github的代码签入记录截图



  • 请合理记录commit信息
  • 遇到的代码模块异常或结对困难及解决方法

  • 问题描述
    在开发微信小程序项目时,数据库出现了某些问题,导致数据查询异常,用户和项目数据无法正确存储及读取。
  • 做过哪些尝试
    检查数据库连接:确保数据库服务正在运行,并且小程序的数据库连接配置是正确的。
  • 是否解决
    已解决
  • 有何收获
    问题解决能力:提升了定位和解决复杂问题的能力。
    沟通协作:在结对编程中,我们学会了更好地与队友沟通和协作,共同面对挑战。
  • 评价你的队友

结对队友:102202111刘哲睿

  • 值得学习的地方
    1.技术能力:他对JavaScript和相关框架(如WeChat小程序)的掌握非常熟练,能够快速解决各种技术难题。
    2.团队合作:他在团队合作中表现出色,能够积极沟通,分享自己的见解和经验,帮助团队成员共同进步。
  • 需要改进的地方    
    1.在项目开发过程中,他没有很好地管理时间,提前规划每个阶段的任务,导致整体的开发效率较慢。
    2.在编写代码时,他有时没有充分利用已有的代码模块,导致一些功能的重复编写。提高代码的复用性可以减少工作量并降低出错率.
posted @ 2024-10-10 22:40  Con1427  阅读(9)  评论(0编辑  收藏  举报