2024秋软件工程结对作业(第二次之程序实现)

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2024
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281
这个作业的目标 根据需求分析和原型设计,通过代码实现项目互通小程序
学号 102202131
合作伙伴 102202132 林鑫
博客链接 https://www.cnblogs.com/PZn000/p/18457483
合作伙伴博客链接 https://www.cnblogs.com/zhengbingzhi/p/18457479
github项目仓库地址 https://github.com/PZn000/102202131-102202132

一、具体分工

102202132 郑冰智

  1. 模块开发

    • 聊天论坛模块:负责开发小程序的聊天论坛功能。实现聊天信息的存储、发布和查询,通过云数据库和云函数进行数据处理。在前端提供实时更新的聊天界面,方便用户交流和讨论项目。
    • 我的收藏模块:开发“我的收藏”功能,实现项目的收藏和管理。与后端交互,将收藏信息存储在云数据库中,并在前端提供收藏列表展示和删除功能。
    • 主页模块:设计并实现主页界面,包括搜索栏、项目发布按钮和项目列表展示。与后端接口配合,实现搜索栏的高效检索功能,项目发布按钮触发后端数据录入操作,项目列表从云数据库获取数据并在前端展示。
    • 我的项目模块:开发“我的项目”功能,自动查询用户参与的项目。通过前后端通信,从云数据库获取用户参与项目信息并在前端呈现。
  2. 后端开发

    • 云数据库配置:合理规划云数据库结构,为用户信息、项目信息等数据创建相应的数据表和字段。设置索引以提高数据查询效率,确保数据存储的安全性和稳定性。
    • 云函数开发:编写云函数实现用户认证、项目发布、项目查询等业务逻辑。利用云函数的触发机制,实时处理数据变化并通知前端更新界面。
  3. 特色功能

    • 我的项目自动查询功能:通过优化数据库查询语句和前后端通信机制,实现快速准确地自动查询用户参与的项目。在前端提供清晰的项目列表展示,方便用户管理和查看自己参与的项目。
    • 数据安全特色:加强用户密码加密存储,采用多因素认证等安全措施,保障用户数据的安全性。对敏感数据进行加密传输,防止数据泄露。
  4. 博客撰写

    • 记录小程序开发过程中的技术挑战和解决方案,分享开发经验和心得。撰写关于小程序功能介绍、使用教程等内容的博客文章,为用户提供使用指导和帮助。
    • 定期更新博客,回应用户反馈和问题,与用户进行互动交流,不断改进小程序的功能和用户体验。

102202131 林鑫

  1. 模块开发

    • 用户认证模块:负责开发小程序的登入、注册和找回密码界面。通过前后端交互,将用户输入信息发送至后端,后端利用云数据库存储用户信息并进行验证。采用加密算法保障用户密码安全,实现身份验证机制以判断用户是否存在。
    • 聊天论坛模块:负责开发小程序的聊天论坛功能。实现聊天信息的存储、发布和查询,通过云数据库和云函数进行数据处理。在前端提供实时更新的聊天界面,方便用户交流和讨论项目。
    • 项目发布模块:负责项目发布功能的实现。在前端提供简洁易用的项目发布界面,用户可以输入项目名称、描述、所需专业等信息。通过与后端接口交互,将项目信息存储到云数据库中,并触发相关的云函数进行数据处理和通知。确保项目发布的流程顺畅,数据准确存储。
    • 项目申请加入模块:开发项目申请加入功能。在前端展示项目详情页面时,提供申请加入按钮。用户点击后,弹出申请信息输入框,用户填写相关信息后提交申请。后端接收申请信息,进行数据校验和处理,将申请信息存储到项目对应的数据库表中,
  2. 页面优化

    • 界面美化:运用专业的设计工具和技术,对小程序的界面进行美化设计。选择合适的色彩搭配、字体样式和图标,提升小程序的视觉效果和用户体验。
    • 弹窗和滑动优化:优化小程序中的弹窗效果,使其更加简洁美观、易于操作。对页面滑动效果进行优化,提高页面切换的流畅性和响应速度。
  3. 小程序测试

    • 功能测试:对小程序的各个功能模块进行全面的功能测试,确保功能的正确性和稳定性。编写测试用例,覆盖各种场景和用户操作,及时发现并修复功能缺陷。
    • 性能测试:进行小程序的性能测试,包括页面加载速度、响应时间等方面的测试。优化小程序的性能,提高用户使用的流畅性和满意度。
  4. 博客优化

    • 对成员一撰写的博客文章进行优化,提高文章的可读性和专业性。检查文章中的语法错误和排版问题,确保文章质量。
    • 根据大家对小程序的反馈和建议,及时转达给开发团队,促进小程序的不断改进和完善。

二、PSP 表格

PSP2.1 Personal Software Process Stages 预估耗时(小时) 实际耗时(小时)
Planning (计划) 2 2.5
Estimate (估计这个任务需要多少时间) 48 48
Development (开发) 15 15
Analysis (需求分析,包括学习新技术) 3 3.5
Design Review (设计复审) 1.5 1.5
Coding Standard (代码规范,为开发制定规范) 1 1.5
Design (具体设计) 2.5 3
Coding (具体编码) 12 14
Code Review (代码复审) 2 3
Test (测试,自我测试,修改代码,提交修改) 4 4
Reporting(报告) 2 1.5
Test Report (测试报告) 1.5 1.5
Size Measurement (计算工作量) 0.5 0.5
Postmortem & Process Improvement Plan (总结) 0.5 0.75
合计 48 52.25

三、解题思路与设计实现说明

一、需求分析

(一)功能需求(附带伪代码)

  1. 登入注册功能
    • 用户可以通过输入用户名、密码进行注册,注册成功后可以使用用户名和密码进行登录。
    • 代码实现思路:前端通过表单收集用户输入的注册信息,使用表单验证技术确保信息格式正确。然后通过 axios 等工具向后端接口发送 POST 请求,携带用户信息。后端接收到请求后,将用户信息存储到数据库中,同时对密码进行加密处理。登录时,前端同样发送请求,后端验证用户名和密码是否匹配,如果匹配则返回登录成功的响应。
# 后端
def get_projects_from_database():
    """
    从数据库获取项目列表。
    """
    pass
# 前端
def display_projects(projects):
    """
    展示项目列表。
    """
    pass
  1. 主页项目分布功能
    • 在主页上展示项目列表,包括项目名称、描述等信息。用户可以浏览项目列表,了解不同的项目。
    • 代码实现思路:后端从数据库中读取项目信息,通过接口将项目列表数据返回给前端。前端使用列表渲染的方式展示项目列表,每个项目可以点击进入项目详情页面。
# 前端
def get_search_keyword():
    """
    获取用户输入的搜索关键词。
    """
    pass
def send_search_request(keyword):
    """
    发送搜索请求。
    """
    pass
# 后端
def search_projects(keyword):
    """
    根据关键词在数据库中搜索项目。
    """
    pass
  1. 主页搜索功能
    • 用户可以在主页的搜索栏中输入关键词,搜索相关的项目。
    • 代码实现思路:前端获取用户输入的搜索关键词,发送请求到后端。后端使用数据库的搜索功能,如倒排索引等,根据关键词在项目信息中进行检索,然后将搜索结果返回给前端进行展示。
# 前端
def get_search_keyword():
    """
    获取用户输入的搜索关键词。
    """
    pass
def send_search_request(keyword):
    """
    发送搜索请求。
    """
    pass
# 后端
def search_projects(keyword):
    """
    根据关键词在数据库中搜索项目。
    """
    pass
  1. 论坛讨论功能
    • 用户可以在论坛中发布消息、回复消息,进行项目相关的讨论。
    • 代码实现思路:前端提供论坛页面,用户输入消息后发送请求到后端。后端将消息存储到数据库中,并通过实时更新的技术,如 WebSocket 等,将新消息推送给所有在线的用户。
# 前端
def get_message_input():
    """
    获取用户输入的消息。
    """
    pass
def send_message_request(message):
    """
    发送消息请求。
    """
    pass
# 后端
def save_message_to_database(message):
    """
    将消息保存到数据库。
    """
    pass
def push_new_message_to_users(new_message):
    """
    将新消息推送给用户。
    """
    pass
  1. 我的界面收藏模块和参与项目模块
    • 收藏模块:用户可以收藏感兴趣的项目,在我的收藏页面中查看和管理收藏的项目。
    • 参与项目模块:展示用户参与的项目列表,方便用户快速访问自己参与的项目。
    • 代码实现思路:收藏模块,前端通过接口将收藏操作发送到后端,后端将收藏信息存储到数据库中。在我的收藏页面,从数据库中读取收藏信息并展示给用户。参与项目模块,后端通过数据库查询和关联技术,获取用户参与的项目信息,返回给前端展示。
# 前端
def send_favorite_request(project_id):
    """
    发送收藏请求。
    """
    pass
# 后端
def save_favorite_to_database(user_id, project_id):
    """
    将项目收藏信息保存到数据库。
    """
    pass
def get_favorites_from_database(user_id):
    """
    从数据库获取用户收藏的项目。
    """
    pass
#后端
def get_user_participated_projects(user_id):
    """
    获取用户参与的项目。
    """
    pass

(二)个人信息分析(伪代码)

  1. 全局变量:可以设置一些全局变量来存储用户的登录状态、用户信息等。例如,在用户登录成功后,将用户信息存储在全局变量中,方便在不同页面中使用。
    • 代码实现思路:在 Vue.js 项目中,可以使用 Vuex 等状态管理工具来管理全局变量。在用户登录成功后,将用户信息存储到 Vuex 的 state 中,在需要使用用户信息的组件中,可以通过mapState等方式获取全局变量中的用户信息。
// 定义全局状态存储
const globalState = {
  isLoggedIn: false,
  userInfo: null
};
// 设置登录状态和用户信息
function setLoginStatus(status, info) {
  globalState.isLoggedIn = status;
  globalState.userInfo = info;
}
// 获取登录状态和用户信息
function getLoginStatus() {
  return globalState.isLoggedIn;
}
function getUserInfo() {
  return globalState.userInfo;
}
  1. 数据库:存储用户信息、项目信息、聊天信息、收藏信息等。合理设计数据库结构,确保数据的存储和查询效率。
    • 代码实现思路:根据不同的功能需求,设计相应的数据表结构。例如,用户信息表可以包括用户名、密码、邮箱等字段;项目信息表可以包括项目名称、描述、发布者等字段。使用云数据库等工具,通过设置索引、优化查询语句等方式提高数据存储和查询的性能。
// 添加用户信息到数据库
function addUserToDatabase(username, password, email) {
  // 使用云数据库 API 添加用户信息
}

// 查询用户信息
function queryUserFromDatabase(username) {
  // 使用云数据库 API 根据用户名查询用户信息
}

// 添加项目信息到数据库
function addProjectToDatabase(name, description, publisher) {
  // 使用云数据库 API 添加项目信息
}

// 查询项目信息
function queryProjectsFromDatabase() {
  // 使用云数据库 API 查询项目信息
}

(三)性能优化分析

  1. 优化代码,更换部分函数以及调用云数据库的方法等,提高小程序性能。例如,优化数据库查询语句,避免不必要的查询和数据加载。
    • 代码实现思路:对代码进行性能分析,找出性能瓶颈。如果数据库查询耗时较长,可以通过优化查询语句、添加索引等方式提高查询效率。同时,检查代码中是否存在不必要的循环、重复计算等问题,进行优化。
  2. 对于数据不同步的问题,增加刷新功能,确保用户能够及时看到最新的数据。
    • 代码实现思路:在前端页面中添加刷新按钮,用户点击刷新按钮时,发送请求到后端获取最新的数据。后端可以通过缓存技术等方式,提高数据的获取速度,确保数据的实时性。

4. 关键实现流程图

  • 流程图:
graph TD; A[登入界面] --> B{有账户?}; B -- 否 --> C[注册界面]; C --> D[登入界面]; B -- 是 --> E[输入密码]; E --> F{密码正确?}; F -- 是 --> G[主菜单]; F -- 否 --> E; G --> H[主页]; G --> I[聊天论坛]; G --> J[我的]; H --> K[搜索框]; K --> L[项目栏]; H --> M[项目发布按钮]; M --> N[项目发布界面]; N --> O[项目栏]; H --> P[项目栏]; P --> Q[项目详情界面]; Q --> R[收藏功能]; R --> S[我的收藏]; Q --> T[讨论区按钮]; T --> U[讨论区]; I --> V[输入框]; V --> W[聊天记录]; J --> X[个人信息]; X --> Y[个人信息界面]; J --> Z[我的收藏]; Z --> Q; J --> AA[我的项目]; AA --> AB[我参与的项目]; AB --> Q; AA --> AC[设置按钮]; AC --> AD[设置界面]; AA --> AE[退出账户按钮]; AE --> A;
  • 项目信息数据流图:
graph TD; subgraph 用户层 A[用户] --> B[用户操作界面]; B --> C[输入账号密码]; B --> D[项目发布]; B --> E[项目收藏]; B --> F[论坛互动]; end subgraph 数据层 G[用户账号数据库] --> H[账号密码验证]; I[项目发布数据库] --> J[项目展示]; K[项目详情数据库] --> L[项目详细信息]; M[我的收藏数据库] --> N[收藏管理]; O[论坛数据库] --> P[论坛交流]; end subgraph 管理层 Q[管理系统] --> R[数据监控]; R --> S[故障处理]; S --> T[性能优化]; end C --> H; D --> I; E --> M; F --> O; H --> B; J --> B; L --> B; N --> B; P --> B;

5. 代码片段:

  • 代码片段1:通过数据库申请项目并输出项目:
const app = getApp();
const db = wx.cloud.database(); // 获取数据库引用

Page({
  data: {
    projectName: '',
    projectType: '',
    majorsRequired: '',
    timeSchedule: '',
    contactInfo: '',
    memberRequirements: '',
    projectIntroduction: ''
  },

  inputProjectName: function(e) { this.setData({ projectName: e.detail.value }); },
  inputProjectType: function(e) { this.setData({ projectType: e.detail.value }); },
  inputMajorsRequired: function(e) { this.setData({ majorsRequired: e.detail.value }); },
  inputTimeSchedule: function(e) { this.setData({ timeSchedule: e.detail.value }); },
  inputContactInfo: function(e) { this.setData({ contactInfo: e.detail.value }); },
  inputMemberRequirements: function(e) { this.setData({ memberRequirements: e.detail.value }); },
  inputProjectIntroduction: function(e) { this.setData({ projectIntroduction: e.detail.value }); },

  // 提交项目到数据库
  submitProject: function() {
    if (this.validateInput()) {
      let projectData = {
        user: app.globalData.user,
        projectName: this.data.projectName,
        projectType: this.data.projectType,
        majorsRequired: this.data.majorsRequired,
        timeSchedule: this.data.timeSchedule,
        contactInfo: this.data.contactInfo,
        memberRequirements: this.data.memberRequirements,
        projectIntroduction: this.data.projectIntroduction,
        participator: []
      };

      db.collection('project').add({
        data: projectData,
        success: function(res) {
          wx.showToast({ title: '提交成功', icon: 'success', duration: 2000 });
          wx.navigateBack(); // 返回上一页
        },
        fail: function(error) {
          wx.showToast({ title: '提交失败,请重试', icon: 'none', duration: 2000 });
        }
      });
    }
  },

  // 输入验证函数
  validateInput: function() {
    let { projectName, projectType, majorsRequired, timeSchedule, contactInfo, memberRequirements, projectIntroduction } = this.data;
    let isValid = true;

    if (!projectName.trim()) { wx.showToast({ title: '请输入项目名称', icon: 'none' }); isValid = false; }
    if (!projectType.trim()) { wx.showToast({ title: '请输入项目类型', icon: 'none' }); isValid = false; }
    if (!majorsRequired.trim()) { wx.showToast({ title: '请输入所需专业', icon: 'none' }); isValid = false; }
    if (!timeSchedule.trim()) { wx.showToast({ title: '请输入时间安排', icon: 'none' }); isValid = false; }
    if (!contactInfo.trim()) { wx.showToast({ title: '请输入联系方式', icon: 'none' }); isValid = false; }
    if (!memberRequirements.trim()) { wx.showToast({ title: '请输入成员要求', icon: 'none' }); isValid = false; }
    if (!projectIntroduction.trim()) { wx.showToast({ title: '请输入项目简介', icon: 'none' }); isValid = false; }

    return isValid;
  }
});

--------------------------------------------------------------------------------------------------------------------------------------------

// 从数据库加载项目
  loadProjectsFromDB: function(callback) {
    const db = wx.cloud.database();
    const that = this;
    db.collection('project').get({
      success: function(res) {
        that.setData({ allCategory: res.data });
        if (callback) callback();
      },
      fail: function(error) {
        wx.showToast({ title: '加载项目失败', icon: 'none' });
        if (callback) callback();
      }
    });
  },


项目数据提交:
用户输入项目信息后,调用 submitProject 函数,先通过 validateInput 验证必填项。验证成功后,将项目数据作为 JSON 对象存入云数据库的 project 集合。数据库操作使用 wx.cloud.database().collection('project').add(),成功提交后提示并返回上一页。

项目数据展示:
主页加载时,onLoad 函数调用 loadProjectsFromDB,从数据库提取项目并存储到 allCategory,项目数据展示在页面上。

  • 代码片段2:搜索功能:
// 处理搜索框输入
handleInput: function(e) {
  const value = e.detail.value;
  this.setData({
    searchKeyword: value
  });

  // 如果搜索框为空,重新加载所有项目
  if (value.trim() === '') {
    this.loadProjectsFromDB(); // 重新加载所有项目
  }
},

// 处理搜索图标点击
handleSearch: function() {
  this.setData({
    isCategory: true
  });
  const keyword = this.data.searchKeyword.trim().toLowerCase();
  if (keyword === '') {
    // 如果关键词为空,恢复显示所有项目
    this.loadProjectsFromDB(); // 重新加载所有项目
    return;
  }

  // 通过关键词筛选项目
  let results = this.data.allCategory.filter(project => {
    return Object.values(project).some(prop => 
      prop.toString().toLowerCase().includes(keyword)
    );
  });

  if (results.length === 0) {
    wx.showToast({
      title: '未找到匹配内容',
      icon: 'none'
    });
  }

  this.setData({
    searchResults: results
  });
},

搜索栏搜索

点击分类搜索

搜索框输入处理 (handleInput):
用户输入时,内容会存入 searchKeyword。若搜索框为空(清空输入),系统调用 loadProjectsFromDB 重新加载并显示所有项目。

点击搜索按钮处理 (handleSearch):
点击搜索按钮后,isCategory 设置为 true,获取并小写化用户输入的关键词。如果为空,恢复显示所有项目;否则,根据关键词在 allCategory 中进行模糊匹配。若无结果,显示“未找到匹配内容”,否则更新 searchResults 以展示匹配的项目。

关键点:
模糊匹配:项目字段与关键词进行模糊匹配,使用 includes 查找。
实时反馈:根据用户输入动态过滤显示项目。
空输入恢复:若输入为空,恢复项目列表。

  • 代码片段3:刷新功能:
// 点击刷新图片时触发,从数据库重新加载项目
handleRefreshTap: function() {
  this.setData({
    isCategory: false // 将 isCategory 设置为 false,表明当前处于非分类或搜索状态
  });
  console.log(this.data.isCategory);
  
  // 显示顶部加载动画
  wx.showNavigationBarLoading();
  
  // 重新加载项目数据
  this.loadProjectsFromDB(() => {
    // 隐藏顶部加载动画
    wx.hideNavigationBarLoading();
    
    // 显示刷新成功的提示
    wx.showToast({
      title: '刷新成功',
      icon: 'success'
    });
  });
}

代码解释:
状态更新:将 isCategory 设置为 false,表明当前状态不是分类或搜索状态。
显示加载动画:调用 wx.showNavigationBarLoading() 在页面顶部显示加载动画,提示用户正在刷新。
重新加载项目:调用 loadProjectsFromDB() 函数从数据库重新获取项目数据。
加载完成处理:
隐藏加载动画:调用 wx.hideNavigationBarLoading() 停止顶部加载动画。
显示提示信息:刷新完成后,通过 wx.showToast() 显示 "刷新成功" 的提示消息,告知用户刷新已完成。
关键点:
用户反馈:通过顶部加载动画和提示信息,提供了实时的用户反馈,改善用户体验。
数据重新加载:每次点击刷新按钮时,项目数据会从数据库中重新提取并更新显示。

四、附加特点设计与展示

-特色部分:搜索功能具有历史记录和猜你想搜的功能,可以根据不同用户的搜索记录等等来判断个人喜好:

代码:

updateSuggestedTags: function () {
  const { recentSearches, tagLibrary } = this.data;
  let suggestedTags = [];

  if (recentSearches.length > 0) {
    // 遍历最近搜索记录,查找相关标签
    recentSearches.forEach(search => {
      Object.keys(tagLibrary).forEach(category => {
        if (search.includes(category)) {
          // 如果搜索关键词匹配某个类别,获取相关标签
          suggestedTags = [...new Set([...suggestedTags,...tagLibrary[category]])];
        }
      });
    });
  }

  // 如果没有匹配到标签,则从分类中随机挑选一些标签
  if (suggestedTags.length === 0) {
    const shuffledCategories = this.data.categories.sort(() => 0.5 - Math.random());
    suggestedTags = shuffledCategories.slice(0, 6); // 随机选取6个标签
  }

  this.setData({
    suggestedTags: suggestedTags
  });
},


handleInput: function (e) {
  const value = e.detail.value;
  this.setData({
    searchKeyword: value
  });

  // 如果搜索框为空,重新加载所有项目并隐藏搜索记录
  if (value.trim() === '') {
    this.setData({
      showRecentSearches: false // 隐藏最近搜索
    });
    this.loadProjectsFromDB(); // 重新加载所有项目
  }
},


handleTagTap: function (e) {
  const tag = e.currentTarget.dataset.tag;
  this.setData({
    searchKeyword: tag
  });

  this.handleSearch(); // 直接进行搜索
},


handleDeleteSearch: function (e) {
  const keywordToDelete = e.currentTarget.dataset.keyword;
  let recentSearches = this.data.recentSearches.filter(item => item!== keywordToDelete);
  this.setData({
    recentSearches: recentSearches
  });

  // 更新猜你想搜标签
  this.updateSuggestedTags();
},

更新猜你想搜标签的函数:这个函数用于更新猜你想搜的标签列表。如果最近搜索记录不为空,遍历最近搜索记录,检查是否包含在tagLibrary中的学科名称,如果包含,则将对应的相关标签添加到suggestedTags中。如果没有匹配到任何标签,则从分类列表中随机选取 6 个作为猜你想搜的标签。最后,通过setData更新suggestedTags数据。
处理猜你想搜标签点击的函数:当猜你想搜的标签被点击时,将标签设置为搜索关键词,并调用搜索函数进行搜索。
删除单个搜索记录的函数:这个函数在删除单个搜索记录时被调用。根据点击的关键词从最近搜索记录中删除该关键词,然后更新最近搜索记录数据,并更新猜你想搜的标签。

成果展示:

五、目录说明和使用说明

1. 目录结构

卷 新加卷 的文件夹 PATH 列表
卷序列号为 9A71-4E3F
E:.
+---102202131-102202132
+---miniprogram_npm
|   +---@cloudbase
|   |   +---database
|   |   +---node-sdk
|   |   +---signature-nodejs
|   |   \---wx-cloud-client-sdk
|   +---@tootallnate
|   |   \---once
|   +---agent-base
|   +---agentkeepalive
|   +---asynckit
|   +---axios
|   +---base64-js
|   +---bson
|   +---buffer
|   +---buffer-equal-constant-time
|   +---call-bind
|   +---clone
|   +---combined-stream
|   +---debug
|   +---define-data-property
|   +---delayed-stream
|   +---ecdsa-sig-formatter
|   +---es-define-property
|   +---es-errors
|   +---follow-redirects
|   +---form-data
|   +---function-bind
|   +---get-intrinsic
|   +---gopd
|   +---has-property-descriptors
|   +---has-proto
|   +---has-symbols
|   +---hasown
|   +---http-proxy-agent
|   +---https-proxy-agent
|   +---humanize-ms
|   +---ieee754
|   +---is-stream
|   +---jsonwebtoken
|   +---jwa
|   +---jws
|   +---lodash.clonedeep
|   +---lodash.includes
|   +---lodash.isboolean
|   +---lodash.isinteger
|   +---lodash.isnumber
|   +---lodash.isplainobject
|   +---lodash.isstring
|   +---lodash.once
|   +---lodash.set
|   +---lodash.unset
|   +---mime-db
|   +---mime-types
|   +---ms
|   +---object-inspect
|   +---punycode
|   +---qs
|   +---regenerator-runtime
|   +---retry
|   +---safe-buffer
|   +---sax
|   +---semver
|   +---set-function-length
|   +---side-channel
|   +---url
|   +---xml2js
|   \---xmlbuilder
+---node_modules
|   +---.bin
|   +---@cloudbase
|   |   +---database
|   |   |   +---.trunk
|   |   |   |   \---configs
|   |   |   +---dist
|   |   |   |   \---commonjs
|   |   |   |       +---commands
|   |   |   |       +---config
|   |   |   |       +---const
|   |   |   |       +---geo
|   |   |   |       +---helper
|   |   |   |       +---ObjectId
|   |   |   |       +---realtime
|   |   |   |       +---regexp
|   |   |   |       +---serializer
|   |   |   |       +---serverDate
|   |   |   |       +---transaction
|   |   |   |       +---typings
|   |   |   |       \---utils
|   |   |   \---src
|   |   |       +---commands
|   |   |       +---config
|   |   |       +---const
|   |   |       +---geo
|   |   |       +---helper
|   |   |       +---ObjectId
|   |   |       +---realtime
|   |   |       +---regexp
|   |   |       +---serializer
|   |   |       +---serverDate
|   |   |       +---transaction
|   |   |       +---typings
|   |   |       \---utils
|   |   +---node-sdk
|   |   |   +---dist
|   |   |   |   +---analytics
|   |   |   |   +---auth
|   |   |   |   +---const
|   |   |   |   +---database
|   |   |   |   +---functions
|   |   |   |   +---logger
|   |   |   |   +---notification
|   |   |   |   +---storage
|   |   |   |   +---utils
|   |   |   |   \---wx
|   |   |   +---src
|   |   |   |   +---analytics
|   |   |   |   +---auth
|   |   |   |   +---const
|   |   |   |   +---database
|   |   |   |   +---functions
|   |   |   |   +---logger
|   |   |   |   +---notification
|   |   |   |   +---storage
|   |   |   |   +---utils
|   |   |   |   \---wx
|   |   |   \---types
|   |   +---signature-nodejs
|   |   |   +---lib
|   |   |   \---typings
|   |   \---wx-cloud-client-sdk
|   |       \---lib
|   |           +---api
|   |           +---orm
|   |           \---types
|   +---@tootallnate
|   |   \---once
|   |       \---dist
|   +---@types
|   |   \---clone
|   +---agent-base
|   |   +---dist
|   |   |   \---src
|   |   \---src
|   +---agentkeepalive
|   |   \---lib
|   +---asynckit
|   |   \---lib
|   +---axios
|   |   +---dist
|   |   \---lib
|   |       +---adapters
|   |       +---cancel
|   |       +---core
|   |       +---defaults
|   |       |   \---env
|   |       +---env
|   |       \---helpers
|   +---base64-js
|   +---bson
|   |   +---dist
|   |   +---etc
|   |   +---lib
|   |   |   +---parser
|   |   |   \---utils
|   |   \---src
|   |       +---parser
|   |       \---utils
|   +---buffer
|   +---buffer-equal-constant-time
|   +---call-bind
|   |   +---.github
|   |   \---test
|   +---clone
|   +---combined-stream
|   |   \---lib
|   +---debug
|   |   \---src
|   +---define-data-property
|   |   +---.github
|   |   \---test
|   +---delayed-stream
|   |   \---lib
|   +---ecdsa-sig-formatter
|   |   \---src
|   +---es-define-property
|   |   +---.github
|   |   \---test
|   +---es-errors
|   |   +---.github
|   |   \---test
|   +---follow-redirects
|   +---form-data
|   |   \---lib
|   +---function-bind
|   |   +---.github
|   |   \---test
|   +---get-intrinsic
|   |   +---.github
|   |   \---test
|   +---gopd
|   |   +---.github
|   |   \---test
|   +---has-property-descriptors
|   |   +---.github
|   |   \---test
|   +---has-proto
|   |   +---.github
|   |   \---test
|   +---has-symbols
|   |   +---.github
|   |   \---test
|   |       \---shams
|   +---hasown
|   |   \---.github
|   +---http-proxy-agent
|   |   \---dist
|   +---https-proxy-agent
|   |   \---dist
|   +---humanize-ms
|   +---ieee754
|   +---is-stream
|   +---jsonwebtoken
|   |   \---lib
|   +---jwa
|   +---jws
|   |   \---lib
|   +---lodash.clonedeep
|   +---lodash.includes
|   +---lodash.isboolean
|   +---lodash.isinteger
|   +---lodash.isnumber
|   +---lodash.isplainobject
|   +---lodash.isstring
|   +---lodash.once
|   +---lodash.set
|   +---lodash.unset
|   +---mime-db
|   +---mime-types
|   +---ms
|   +---object-inspect
|   |   +---.github
|   |   +---example
|   |   \---test
|   |       \---browser
|   +---punycode
|   +---qs
|   |   +---.github
|   |   +---dist
|   |   +---lib
|   |   \---test
|   +---regenerator-runtime
|   +---retry
|   |   +---example
|   |   \---lib
|   +---safe-buffer
|   +---sax
|   |   \---lib
|   +---semver
|   |   +---bin
|   |   +---classes
|   |   +---functions
|   |   +---internal
|   |   \---ranges
|   +---set-function-length
|   |   \---.github
|   +---side-channel
|   |   +---.github
|   |   \---test
|   +---url
|   |   \---test
|   +---xml2js
|   |   \---lib
|   \---xmlbuilder
|       +---lib
|       \---typings
+---pages
|   +---addProject
|   +---chatPage
|   +---collectionPage
|   |   \---image
|   +---discussionArea
|   +---forgotPassword
|   +---forum
|   |   \---image
|   +---homePage
|   |   \---image
|   +---index
|   +---joinedProject
|   +---loginRegisterPage
|   +---logs
|   +---mainPage
|   +---messagePage
|   |   \---image
|   +---my
|   |   \---image
|   +---myPage
|   |   \---images
|   +---projectDetail
|   |   \---images
|   +---projectResults
|   +---test
|   \---text
\---utils

2. 使用步骤:

  • 获取小程序二维码

    向开发团队申请成为体验者。
  • 扫码进入小程序
  1. 打开手机微信,使用“扫一扫”功能扫描测试版二维码。
  2. 微信会自动识别二维码并打开小程序。
  • 功能测试
  1. 登录注册功能:
    • 尝试使用不同的用户名、密码组合进行登录和注册操作,检查输入验证和错误提示是否正确。
    • 测试忘记密码功能,验证找回密码的流程是否顺畅。
  2. 项目发布功能:
    • 检查是否能够顺利发布项目。
    • 确认发布后的项目是否能在项目列表中正确显示,并且信息完整准确。
  3. 项目申请加入功能:
    • 申请加入不同的项目,检查申请信息的填写和提交过程是否简便流畅。
    • 观察申请提交后,系统是否有相应的提示和反馈。
  4. 聊天论坛功能:
    • 能否收到不同测试人员在论坛发布的消息。
  5. 我的收藏功能:
    • 收藏项目,检查收藏列表的更新是否及时。
  • 性能测试
  1. 在使用小程序的过程中,注意观察页面加载速度、操作响应时间等性能指标。
    • 打开不同的页面,记录加载时间,判断是否在可接受范围内。
    • 进行频繁的操作,如快速切换页面、发送多条消息等,观察小程序是否出现卡顿或崩溃现象。
  • 问题反馈
  1. 如果在测试过程中发现问题,及时记录问题的详细情况。
    • 包括操作步骤、出现问题的页面、错误现象、手机型号和微信版本等信息。
  2. 将问题反馈给开发团队,可以通过邮件、项目管理工具或直接沟通的方式,以便开发团队及时修复问题。

六、单元测试

为了测试上述代码,我选择使用 Jest 作为单元测试工具。Jest 是一个流行的 JavaScript 测试框架,支持模块化测试、异步测试和快照测试,适合与小程序进行集成。以下是对单元测试的解释、部分代码示例和测试数据构造思路。

1. 测试工具与学习方式【4分】

选用的测试工具

Jest 是我选择的测试工具,主要原因包括:

  • 简单易用:Jest 的 API 简单且直观,适合初学者。
  • 良好的社区支持:有丰富的文档和示例,便于学习和解决问题。
  • 支持异步测试:可以处理 Promises 和异步函数,适合用于测试小程序中的异步 API。

学习单元测试的方法

我主要通过以下方式学习单元测试:

  1. 官方文档:阅读 Jest 官方文档 了解基本用法和高级功能。
  2. 示例项目:查找和分析开源项目中的测试示例,理解最佳实践。
  3. 在线教程:观看 YouTube 和 Coursera 上的相关教程,结合视频和实践加深理解。

简易教程

以下是一个简易的 Jest 测试教程:

安装 Jest

npm install --save-dev jest

创建测试文件

在项目目录中,创建一个 __tests__ 文件夹,并在其中创建测试文件,例如 app.test.js

编写测试代码

const app = require('../app.js'); // 导入要测试的模块

test('用户名和密码不能为空', () => {
  expect(app.validateCredentials('', '')).toBe(false);
});

运行测试

在命令行中,运行以下命令以执行测试:

npx jest


## 2. 项目部分单元测试代码【3分】

### 测试代码示例
以下是针对注册和登录功能的部分单元测试代码:

```javascript
const app = require('../app.js'); // 假设 app.js 是要测试的模块

describe('User Registration and Login', () => {
  
  test('should not allow empty username and password', () => {
    const result = app.submit('', '');
    expect(result).toBe('账号密码不能为空');
  });

  test('should show error if username already exists', async () => {
    // 构造测试数据
    const existingUser = { user: 'testuser', password: 'testpass' };
    await app.models.userInfo.create({ data: existingUser }); // 创建一个用户

    const result = await app.submit('testuser', 'newpass');
    expect(result).toBe('账号已存在');
  });

  test('should successfully register a new user', async () => {
    const result = await app.submit('newuser', 'newpass');
    expect(result).toBe('注册成功');
  });

  test('should show error for incorrect login', async () => {
    const result = await app.submit('wronguser', 'wrongpass');
    expect(result).toBe('账号密码不存在');
  });

  test('should successfully login with correct credentials', async () => {
    await app.models.userInfo.create({ data: { user: 'loginuser', password: 'loginpass' } });

    const result = await app.submit('loginuser', 'loginpass');
    expect(result).toBe('登录成功');
  });
});

测试的函数

  • submit(): 此函数用于处理用户的注册和登录逻辑,并根据不同的情况返回相应的提示信息。

3. 构造测试数据的思路【3分】

测试数据构造思路

在构造测试数据时,我考虑以下几点:

  1. 边界情况:确保测试包括空输入、过长的用户名或密码等情况。例如:

    • 空用户名和密码。
    • 已存在的用户名。
    • 不匹配的登录凭据。
  2. 有效数据:创建有效的用户数据用于测试注册和登录,例如:

    • 一个有效的用户名和密码组合。
    • 一个只包含字母和数字的用户名。
  3. 异常情况:模拟可能发生的异常,例如数据库错误、网络问题等,通过 mock 处理这些情况。

考虑将来的测试人员的***难

为了考虑将来的测试人员的***难,我会:

  • 保持代码的可扩展性:确保测试代码易于修改和扩展,以适应新需求。
  • 编写详细的文档:提供清晰的测试说明和测试数据的背景,让其他人可以快速理解和修改。
  • 添加更多的测试用例:针对可能的边界情况和潜在的失败场景添加更多测试用例。

通过这种方式,可以确保我们的单元测试能够应对各种场景,并且为将来的维护和扩展打下良好的基础。

七、Github 的代码签入记录截图

八、问题及解决方法

一、数据内存太多,小程序无法在手机上呈现

  • 问题描述:由于数据内存占用过多,导致小程序在手机上运行时出现卡顿甚至无法呈现的情况。其中部分图片数据占用了大量内存空间。
  • 解决方法:将部分图片载入数据库,通过优化图片存储方式,减少内存占用。在需要展示图片时,从数据库中动态加载图片,而不是一次性将所有图片加载到内存中。

二、数据库连接异常,无法建立数据库

  • 问题描述:在开发过程中,出现数据库连接异常的情况,导致无法成功建立数据库连接。
  • 解决方法:确保环境 ID 配置正确,成员协作配置数据库环境。检查数据库配置参数,如数据库地址、端口号、用户名和密码等是否正确。同时,检查网络连接是否正常,确保小程序能够与数据库服务器进行通信。

三、数据不同步(比如发布项目后在项目栏里无法出现新发布的项目)

  • 问题描述:数据不同步问题表现为发布项目后,项目栏中无法及时出现新发布的项目,影响用户体验。
  • 解决方法:增加刷新功能,用户点击即可刷新项目列表。在发布项目后,通过触发刷新事件,从数据库中重新获取项目数据并更新项目栏的显示。同时,优化数据同步机制,确保新发布的项目能够及时同步到各个客户端。

四、反应速度慢

  • 问题描述:小程序反应速度慢,影响用户操作的流畅性和体验。
  • 解决方法:优化代码,更换部分函数以及调用云数据库的方法等,提高小程序性能。对代码进行性能分析,找出性能瓶颈并进行优化。例如,优化数据库查询语句,减少不必要的数据库访问;采用缓存技术,提高数据访问速度;优化界面渲染,减少不必要的界面更新等。

九、评价

一、值得学习的地方

(一)专业能力

在技术方面表现出较高的专业水准,对小程序开发涉及的前端和后端技术都有深入的理解。例如,在处理用户认证模块时,能够熟练运用加密算法确保用户密码的安全性,同时通过前后端的紧密配合实现高效的身份验证机制。

(二)团队协作

  1. 具有良好的团队协作精神,能够积极与其他成员沟通和协作,共同解决项目中遇到的问题。在分工明确的基础上,能够主动承担一些额外的任务,为团队的整体目标贡献自己的力量。

二、需要改进的地方

(一)时间管理

在项目开发过程中,有时会出现时间预估不准确的情况,导致部分任务未能按时完成。在处理一些紧急问题时,可能会因为过于专注于问题的解决而忽略了其他任务的进度。

(二)沟通方式

在与其他成员沟通时,有时会因为表达不够清晰而导致误解。需要进一步提高沟通能力,更加清晰地表达自己的观点和想法,确保信息的准确传递。

posted @ 2024-10-10 23:50  PZn  阅读(14)  评论(0编辑  收藏  举报