2024软工现场编程实践

作业所属课程 https://edu.cnblogs.com/campus/fzu/SE2024
作业要求 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13302
作业的目标 在三个小时内编写出一个个人记账本,用户可以对自己平时的收入和支出情况进行简单的记录,查看和统计
团队名称 “研途无忧”
团队成员学号-名字 102202101-马鑫102202141-黄昕怡102202123-张铭心102202112-刘莹102202145-谢含102202115-孙佳会102202106-王强102201317-陈磊102201439-谢芳菲

个人记账本项目报告

https://github.com/fufubuff/fu_ledger

一、项目概述 🎯

1. 作业所属课程 📚

软件工程2024

2. 作业要求 📝

查看作业要求

3. 项目目标 🚀

在三个小时内开发一个个人记账小程序,用户能够简便地记录、查看和统计日常的收入与支出情况。


二、团队职责分工 🤝

  • 马鑫、王强:负责博客撰写与程序优化协助 📝🔧
  • 黄昕怡:搭建程序框架,细化各成员工作板块 🛠️📋
  • 张铭心:界面设计 🎨
  • 孙佳会:Bug检查与修复 🐞🔍
  • 刘莹、谢含:功能开发与界面美化 💻✨
  • 陈磊、谢芳菲:程序测试与界面优化 🧪🔧

三、开发环境与技术栈 🛠️💻

  • 编程语言:JavaScript 🟨
  • 前端框架:WXML(微信标记语言)、WXSS(微信样式表) 📐✨
  • 后端服务:云函数、云数据库 ☁️🗄️
  • 开发工具:微信开发者工具 🛠️

三、软件运行截图和视频
1.登陆我们的小程序,引入眼帘的就是非常可爱的个人页面

2.如果你有更喜欢的背景图片也可以选择更换

3.接下来的是我们的添加支出界面,这个界面有多种类型供你选择,可以清楚为自己的花销分类

4.选择我们的类别添加具体的消费(想去北京)

5.同时我们不止有记录支出的功能,还有记录收入的功能,这也是一个记账app必不可少的(相中彩票)

6.这是我们的记账详情界面,它可以查看不同年月的具体支出,同时会统计年月的总支出与总收入,非常实用

7.同时为了满足j人需求,我们还推出了计划功能,可以说是相当人性化

8.添加计划后马上在我的计划界面显示,完成每一个功能的实现,绝不画饼(想换手机了)

9.可以在添加账单时选择计划,同时在添加账单的时候也可实时增添计划

10.将每次选择计划的账单金额同步到对应计划里

11.同时我们也提供人性化服务更改账单

四.关键代码

1.基础记账:

实现基础的记账功能,记录每笔支出或收入,包括:日期、金额、类别(如饮食、交通、工资等)、备注。

点我查看关键代码
saveBook(){//保存记账功能
  let _this = this;
  let data = this.data;
  if(data.activeType == -1 || data.amt == 0){
    return; // 如果未选择类型或金额为0,则不保存
  }
  let date = app.getDateInfo(this.data.selectDay); // 获取选择的日期信息
  let bookType = data.bookTypeList[data.activeType]; // 获取选中的账单类型
  let params = {
    amtType: data.activeTab, // 支出或收入类型
    bookAmt:data.amt-0, // 账单金额
    bookDate:date.date, // 账单日期
    bookMonth:date.month, // 账单月份
    bookYear:date.year, // 账单年份
    week:date.week, // 账单星期
    remark:data.remark, // 备注
    bookTypeName: bookType.name, // 账单类型名称
    bookTypeIcon: bookType.icon, // 账单类型图标
    bookTypeId: bookType._id, // 账单类型ID
    planId:data.planList[data.planIdx]._id // 计划ID
  }
  if (data.remark) {
    let remarkArr = this.data.remarkArr;
    if (remarkArr[bookType._id]){
      if (remarkArr[bookType._id].indexOf(data.remark) == -1) {
        remarkArr[bookType._id].push(data.remark); // 添加新的备注
        this.setData({
          remarkArr:remarkArr
        });
        _this.setStorage('remarks', remarkArr); // 更新缓存中的备注
      }
    }else{
      remarkArr[bookType._id] = [data.remark];
      this.setData({
        remarkArr: remarkArr
      });
      _this.setStorage('remarks', remarkArr); // 更新缓存中的备注
    }
  }
  if(this.data.bookId){
    params.id = this.data.bookId;
    app.getAjax({
      url:'editBook', // 编辑账单
      params:params,
      success(res){
        console.log("editBook:",res);
        wx.navigateBack(); // 返回上一页
      }
    });
  }else{
    app.getAjax({
      url:'addBook', // 添加账单
      params:params,
      success(res){
        console.log("addBook:",res);
        wx.navigateBack(); // 返回上一页
      },
      fail(res){
        console.log("addBookFail:",res);
        common.showModal('添加失败,请稍后重试!'); // 显示添加失败提示
      }
    });
  }
}

2.查看数据:

用户可以通过小程序查看最近的几笔记录。

点我查看关键代码
onShow: function () {
  app.getAjax({
    url:'login',
    params:{},
    success:res=>{
      console.log('[云函数] [login] user openid: ', res.result.openid)
      app.globalData.openid = res.result.openid // 获取用户的openid并存储到全局变量
    }
  })
  let dateObj = app.getDateInfo(); // 获取当前日期信息
  this.initData(dateObj.year, dateObj.month); // 初始化数据
},

initData(year, month) {//初始化数据
  let _this = this;
  app.getAjax({
    url:'getUserBookList', // 获取用户账单列表
    params:{
      bookYear: year - 0, // 账单年份
      bookMonth: month - 0 // 账单月份
    },
    success(res){
      console.log("getUserBookList:", res);
      let sortedBookList = _this.sortBookList(res.result.data); // 对账单列表进行排序和格式化
      _this.setData({
        bookList: sortedBookList.sortData, // 设置账单列表数据
        incomeAmt: sortedBookList.incomeAmt, // 设置收入金额
        payAmt: sortedBookList.payAmt, // 设置支出金额
        selectYear: year, // 设置选中的年份
        selectMonth: month // 设置选中的月份
      });
      console.log("bookList:", sortedBookList.sortData)
    }
  });
},

sortBookList(data) {//格式化账单列表
  let dateArr = [],
      sortData = [],
      incomeAmt = 0,
      payAmt = 0;
  for(var key in data){
    let index = dateArr.indexOf(data[key].bookDate);
    let amtType = data[key].amtType;
    if (index == -1){
      dateArr.push(data[key].bookDate);
      sortData.push({
        date: data[key].bookDate,
        week: ['日', '一', '二', '三', '四', '五', '六'][data[key].week], // 将星期数转换为中文
        incomeAmt: amtType == '0' ? 0 : data[key].bookAmt, // 如果是收入,设置收入金额
        payAmt: amtType == '0' ? data[key].bookAmt : 0, // 如果是支出,设置支出金额
        list: [data[key]] // 初始化账单列表
      });
    } else {
      if(amtType == 0){
        sortData[index].payAmt = (sortData[index].payAmt * 100 + data[key].bookAmt * 100) / 100; // 累加支出金额
      } else {
        sortData[index].incomeAmt = (sortData[index].incomeAmt * 100 + data[key].bookAmt * 100) / 100; // 累加收入金额
      }
      sortData[index].list.push(data[key]); // 添加账单记录到列表
    }
    if(amtType == 0){
      payAmt += data[key].bookAmt; // 累加总支出金额
    } else {
      incomeAmt += data[key].bookAmt; // 累加总收入金额
    }
  }
  return {
    sortData: sortData, // 返回格式化后的账单列表
    incomeAmt: parseInt(incomeAmt * 100) / 100, // 返回总收入金额
    payAmt: parseInt(payAmt * 100) / 100 // 返回总支出金额
  }
}

3.收支统计:

用户可以根据日期,类别,金额等查看总支出和收入情况。

点我查看关键代码
onLoad: function (options) {
  if(options.id){
    this.setData({
      amtType:options.type, // 设置收支类型
      id:options.id, // 设置类型ID
      year:options.year, // 设置年份
      beginMonth:options.mon1, // 设置开始月份
      endMonth:options.mon2 // 设置结束月份
    });
    this.getChartDetail(); // 获取统计详情
  }else{
    let month = new Date().getMonth() + 1;
    let year = new Date().getFullYear();
    this.setData({
      year:year, // 设置当前年份
      beginMonth:month, // 设置当前月份
      endMonth:month, // 设置当前月份
      monthArr:this.data.monthArr.slice(12-month), // 设置月份数组
      dateTypeIdx:0 // 设置日期类型索引
    });
    this.initData(); // 初始化数据
  }
},

initData(){
  let _this = this;
  let data = this.data;
  this.setData({
    chartList:[] // 清空统计列表
  });
  app.getAjax({
    url:'getChartData', // 获取统计数据
    params:{
      amtType:data.amtType, // 收支类型
      year: data.year-0, // 年份
      beginMonth: data.beginMonth, // 开始月份
      endMonth:data.endMonth // 结束月份
    },
    success(res){
      console.log("getChartData:",res);
      let data = res.result.list;
      let count = 0;
      for(var key in data){
        data[key].count = parseInt(data[key].count*100)/100; // 格式化金额
        count += data[key].count; // 计算总金额
      }
      _this.setData({
        chartList:data, // 设置统计列表
        chartListCount:count // 设置总金额
      });
    }
  });
},

getChartDetail(){
  let _this = this;
  let data = this.data;
  app.getAjax({
    url:'getChartDetailData', // 获取统计详情数据
    params:{
      id:data.id, // 类型ID
      year:data.year, // 年份
      beginMonth:data.beginMonth, // 开始月份
      endMonth:data.endMonth // 结束月份
    },
    success(res){
      console.log("getChartDetailData:",res);
      let data = res.result.data;
      let count = 0;
      for(var key in data){
        count += data[key].bookAmt; // 计算总金额
      }
      _this.setData({
        chartList: data, // 设置统计详情列表
        chartListCount: count // 设置总金额
      });
    }
  });
}

4.花销管理计划:

用户可以根据消费意愿设置计划,查看计划。

点我查看关键代码
onLoad: function (options) {
  if(options.pid){
    this.setData({
      planId:options.pid, // 设置计划ID
      plan:app.globalData.plan // 设置全局计划数据
    });
    this.initData(); // 初始化数据
  }
},

initData(){
  let _this = this;
  app.getAjax({
    url:'getPlanBookList', // 获取计划账单列表
    params:{
      planId:_this.data.planId // 传递计划ID参数
    },
    success(res){
      console.log("getPlanBookList:",res);
      _this.setData({
        bookList:res.result.data // 设置账单列表数据
      });
    }
  });
}

onShow: function () {
  this.getPlanList(); // 页面显示时获取计划列表
},

getPlanList(){//获取计划列表
  let _this = this;
  app.getAjax({
    url: 'getPlanList', // 请求获取计划列表
    params: {
      type: _this.data.amtType // 传递收支类型参数
    },
    success(res) {
      console.log("getPlanList:", res);
      let planList = res.result;
      for(var key in planList){
        planList[key].diffAmt = planList[key].planAmt - planList[key].total; // 计算计划剩余金额
        planList[key].showInfo = false; // 初始化计划详情显示状态
      }
      _this.setData({
        planList: planList // 设置计划列表数据
      });
    }
  });
},

setAmtType(e) {//选择收入支出类型
  this.setData({
    amtType: e.currentTarget.dataset.type // 设置收支类型
  });
  this.getPlanList(); // 重新获取计划列表
},

showPlanInfo(e){//显示计划进度
  let idx = e.currentTarget.dataset.idx;
  this.setData({
    [`planList[${idx}].showInfo`]:!this.data.planList[idx].showInfo // 切换计划详情显示状态
  });
},

toPlanDetail(e){//到计划详情页
  let idx = e.currentTarget.dataset.idx;
  let plan = this.data.planList[idx];
  if(plan.total == 0){
    return; // 如果计划总金额为0,则不跳转
  }
  app.globalData.plan = plan; // 设置全局计划数据
  app.navigate(`/pages/planBookList/planBookList?pid=${plan._id}`); // 跳转到计划详情页
}

五、设计亮点 ✨🔍

1. 计划管理功能 📅💡

  • 计划创建与管理:用户可以创建不同的消费计划,并根据计划进行消费管理。每个计划都有详细的金额记录和剩余金额显示,帮助用户更好地控制支出。 💰📊

  • 动态显示计划详情:通过 showPlanInfo 方法,用户可以动态展开或收起计划的详细信息,查看每个计划的进度和具体消费记录。 🔄📈

  • 收支类型切换:用户可以通过 setAmtType 方法切换查看支出或收入的计划列表,方便用户分类管理不同类型的计划。 🔀💵

  • 计划删除功能:通过 showDeleteBtndeletePlanList 方法,用户可以方便地删除不需要的计划,保持计划列表的整洁。 🗑️✨

  • 计划详情跳转:通过 toPlanDetail 方法,用户可以跳转到具体计划的详情页面,查看该计划下的所有消费记录,帮助用户更详细地了解每个计划的执行情况。 🔗📋

2. 账单管理功能 🧾🔧

  • 账单记录与编辑:用户可以记录每一笔支出或收入,并可以随时编辑已记录的账单。 ✍️🖥️

  • 账单类型与备注管理:用户有多种图标进行选择账单类型,并添加备注。用户可以根据账单类型获取相应的备注提示,方便用户快速输入常用备注。 🖼️✏️

  • 日期选择与金额输入:用户可以选择账单日期,并通过数字键盘输入金额。通过 bindDateChangesetAmt 方法,用户可以方便地选择日期和输入金额。 📅🔢

这些设计亮点使得计划管理功能更加实用和人性化,帮助用户更好地进行财务规划和管理。 🌟💼

六、项目开发过程与收获 🚀✨

在整个项目开发过程中,我们团队经历了紧张而充实的时光。每个成员都在各自的岗位上发挥了重要作用,以下是我们在项目中的一些关键经历和收获:

1. 计划管理功能的设计与实现 📅💡

过程描述
一开始,我们就明确了计划管理功能的重要性。大家集思广益,讨论如何让用户能够轻松创建和管理消费计划。特别是在设计界面时,我们希望既简洁又直观,让用户一目了然每个计划的进度和剩余金额。经过多次头脑风暴和设计迭代,最终确定了动态显示计划详情的功能,让用户可以随时查看和调整自己的消费计划。

收获
通过这个过程,我们学会了如何从用户体验出发进行功能设计,确保每一个功能都贴近用户的实际需求。同时,团队成员在前端动态数据更新和显示方面的技能得到了显著提升。

2. 收支统计功能的优化 📊🔍

过程描述
在实现收支统计功能时,我们遇到了如何高效处理大量账单数据的问题。为了确保数据统计的准确性和展示的流畅性,我们优化了数据处理算法,并引入了分页加载技术。团队成员之间紧密合作,反复测试和调整,最终实现了一个高效且用户友好的统计模块。

收获
这一阶段让我们深入理解了数据处理和优化的重要性。通过优化算法,我们不仅提升了应用的性能,还增强了团队解决复杂问题的能力。

3. 数据同步与缓存机制的实现 ☁️🔄

过程描述
考虑到用户可能会在网络不稳定或离线的情况下使用小程序,我们决定实现数据同步与缓存机制。团队成员研究了微信小程序的本地存储API,设计了一套可靠的数据缓存方案。我们还编写了自动同步的逻辑,确保本地数据与服务器数据的一致性。

收获
通过这部分的开发,我们掌握了本地缓存技术和数据同步的实现方法。这不仅提升了应用的稳定性和用户体验,也增强了我们对后端数据管理的理解。

4. 账单详情页面的设计与实现 📄🖌️

过程描述
账单详情页面是用户查看和编辑账单的重要入口。我们希望这个页面既美观又实用,因此在设计时花费了大量时间优化界面布局和交互体验。团队成员密切合作,反复讨论和调整,确保每一个细节都符合用户的使用习惯。

收获
这一过程中,我们学会了如何通过细致的界面设计提升用户体验。同时,团队成员在前端开发和UI设计方面的技能也得到了显著提升。

5. 数据统计与图表展示 📈🖼️

过程描述
为了让用户更直观地了解自己的收支情况,我们决定在统计功能中加入图表展示。团队选择了ECharts作为图表库,并学习了如何将统计数据与图表进行有效结合。经过多次调试和优化,最终实现了动态更新的图表展示功能,让用户可以清晰地看到自己的财务趋势。

收获
通过这部分的开发,我们不仅提升了数据可视化的能力,还学会了如何将复杂的数据通过图表直观地展示给用户。这极大地增强了应用的实用性和用户的满意度。


总结
整个项目的开发过程虽然紧张,但也充满了挑战和乐趣。每个成员都在项目中学到了新的技能,提升了自己的技术水平。同时,通过团队的协作与沟通,我们也增强了彼此之间的默契和合作能力。这次项目不仅让我们完成了一个功能完善的记账小程序,也为我们的未来开发工作积累了宝贵的经验。

七、每个组员的团队编程体验

姓名 贡献分
马鑫 8%
黄昕怡 18%
王强 9%
陈磊 8%
谢芳菲 7%
张铭心 13%
孙佳会 13%
谢含 13%
刘莹 13%
  • 马鑫:在此次随堂编程中,我体会到了速度与激情,在短短的三个小时内制作成了一个功能完整的记账小程序,从设计到编码的过程中再到最后的优化阶段,感受到团队前所未有的凝聚力。在初期,我并不熟悉微信开发小程序的使用,在编码中期我也遇到了许多困难,期间在队友的帮助下,我解决了一个又一个困难,最后我要感谢我们的团队,谢谢大家。
  • 黄昕怡:建议软件工程取消小组作业。
  • 孙佳会:这次团队编程作业时间很紧急,只有三个小时,但是大家分工很明确很完善。每个人负责自己的部分,在写的过程中都非常迅速,最后整合给演示的同学,也在GitHub上上传了代码,我们团队最后的完成程度很不错,基础的功能都实现了。在这次团队作业中,我深刻体会到了团队合作的重要性,自己的代码速度以及与队友配合的能力都得到了很好的锻炼。
  • 谢含:在这次现场编程中,通过快速开发记账小程序,我了解道每个成员之间熟悉的领域,大家集思广益快速分工,在有限的时间push出一个简单的成品,心酸苦楚只有自己知道,但也是这种有压力的感觉,激发出最大的潜力,我主要负责的是前端开发(美工),看见页面成果就会很开心呀呀呀,我爱软件工程(不要现场编程)。
  • 刘莹:在本次记账小程序的团队编程过程中,大家刚开始共同商量小程序的风格并快速领取了自己要完成的代码部分,最后在fu姐的领导和明星姐的整合下完成了最后的展示,最终的效果还是非常令人满意的,很高兴和大家一起完成这次编程任务!
  • 张铭心:和优秀的组员们一起,能在这么短的时间内开发出功能完备的记账小程序使我收获颇丰,关键是每个类型消费收入的统计我们也考虑在内,并且实现了可视化,这点更是让人欣喜。
    非常有趣的小组编程,使我的大脑高速运转。ps:一起扣头也是有趣👍
  • 王强:通过本次项目,我受益匪浅,收获了关于数据同步与缓存机制的实现的相关知识,了解了如何通过图表和数据可视化技术,直观地展示统计结果等技术。我们不仅提升了编程技能,还学会了如何进行团队协作和项目管理。每个成员都在项目中发挥了重要作用,大家共同努力,最终成功实现了项目目标。希望在未来的项目中,我们能够继续保持这种良好的合作精神,不断提升自己的技术水平和项目管理能力。
  • 磊弟:我负责的是项目详情(book detail)页面和部分首页(index) 内容的开发,为保证页面与整体项目风格的一致性,我们团队在开始编码前定义了统一的编码规范、UI风格。在代码编写过程中,我更加注重代码的清晰性、可读性。严格遵守编码规范,包括代码命名、注释、模块划分等,确保团队其他成员能够理解我的代码。由于开发时间仅有三小时,一些复杂的UI细节被暂时放弃,我负责的页面也遵循了简洁、实用的原则。在时间紧迫的情况下,我们团队本次采用了敏捷开发的方式,将整个项目进行了多次迭代,在迭代结束时进行总结,很有效地推进了项目。项目完成后,我对最终开发出来的产品感到十分自豪。我们团队默契配合,每个人的努力都汇聚在一起,才很好地完成了本次任务。。
    谢芳菲:在编程的过程中,感觉非常的吃力,因为对于很多东西都不太理解,但是正是这种吃力也让我学到了很多新的东西。编程的过程就是不断克服困难。

八、PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 240 270
· Estimate · 估计这个任务需要多少时间 240 270
Development 开发 180 195
· Analysis · 需求分析 (包括学习新技术) 10 5
· Design Spec · 生成设计文档 10 10
· Design Review · 设计复审 (和同事审核设计文档) 5 5
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 5
· Design · 具体设计 25 25
· Coding · 具体编码 100 120
· Code Review · 代码复审 10 15
· Test · 测试(自我测试,修改代码,提交修改) 10 10
Reporting 报告 60 75
· Test Report · 测试报告 30 45
· Size Measurement · 计算工作量 15 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 15 20
合计 240 270
posted @ 2024-11-02 23:04  fufubuff  阅读(58)  评论(0编辑  收藏  举报