fzu2020软工作业4

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277
这个作业的目标 利用github合作开发,前端开发设计
学号 031802504

一、结对信息

分工信息

学号 姓名 分工
031802504 陈新平 编写功能代码,UI 设计
031802506 程灵飞 单元测试代码,博客攥写

队友博客链接: https://www.cnblogs.com/fzu2018-clf-bky-blog/p/13786871.html
本次作业链接: https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277
对应 github 链接: https://github.com/Stareven233/031802504-031802506

二、PSP 表格

PSP 2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 10
Estimate 估计这个任务需要多少时间 10 10
Development 开发 500 720
Analysis 需求分析 (包括学习新技术) 120 120
Design Spec 生成设计文档 120 120
Design Review 设计复审 20 20
Coding Standard 代码规范 (为目前的开发制定合适的规范) 10 10
Design 具体设计 60 60
Coding 具体编码 120 180
Code Review 代码复审 30 30
Test 测试(自我测试,修改代码,提交修改) 120 300
Reporting 报告 30 30
Test Report 测试报告 10 10
Size Measurement 计算工作量 10 10
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 60 60
合计 1230 1690

三、项目速览

  • 项目链接
  • 若打不开很有可能需要修改dns,例如233.5.5.5或233.6.6.6
  • 或者在C:\Windows\System32\drivers\etc\hosts文件中某一行添加 185.199.110.153 stareven233.github.io
  • ps:修改hosts要求管理员权限

四、解题思路描述与设计说明

代码实现思路

  • 通过textareadu读取一串固定格式的师生信息
  • 用正则将字符串解析为树数据对象,四层结构(导师-年级-学历-学生姓名-学生详细信息)
  • 在页面上渲染出树状图,默认不展开
  • 缩放:点击相应按钮,修改对应节点的expand属性,实现节点的展开与收回
  • 多树并存:用数组(treeData)存储所有生成的树对象
  • 多树关联:对于新输入的树,调用find方法在节点对象(nodeData)(记录了每个师生对应的节点对象)中搜寻每个叶节点的名称,若有则将其合并到这棵树上

流程图

图 1 流程图

关键代码

mergeTree函数用于合并树,但本质上可以合并某个对象到一个同类对象数组中,要求为 {label: xx, children: [{}, ]} 类的嵌套对象
仅当obj的属性label与arr中某个对象label相同时递归合并二者的children属性,children是数组

    mergeTree (arr, obj) {
      // 若其中存在一个元素其label属性与obj的label相同则执行合并,否则obj推入arr中
      const tmp = arr.find(item => item.label === obj.label)
      if (tmp === undefined) {
        arr.push(obj)
        return
      }
      for (const c of obj.children || []) {
        this.mergeTree(tmp.children, c)
      }
      // 替换策略:不同label直接push,否则递归合并children;最终由于学生姓名处无children属性只比较label将脱离递归
    }

五、附加特点设计与展示

特点设计: 实现思路

  • 页面美观大方,正所谓 Simple is Better Than Complex: Element-ui
  • 树可动态添加,动态合并,自适应节点展开收缩,丝滑顺畅: 以数组存储每个树对象,每次生成新树时更新数组
  • 导师节点(包括动态合并后从叶节点升级的)高亮标出,容易区分: 为组件v-bind一个根据节点数据设置class的函数,生成时调用
  • 每个树都可独立拖动,再也不用担心放不下了: 监听鼠标事件onmousemove,实时调整组件位置
  • 方便易用,支持横纵切换,一键缩放: 为组件on-expand事件绑定函数,调整组件的expand属性
  • 节点点击后在旁边浮现节点信息(即学生的详细经历): 监听节点on-node-click事件,手动调整位置
  • 树支持放大缩小,简单易用,ctrl+鼠标滚轮: 无

代码片段

showPopover函数当节点被点击触发,仅当节点为师生时允许允许,效果是在节点旁边用一个tooltip框展示节点的附加信息

    showPopover (e, data) {
      e.stopPropagation()
      // 避免同时触发document上的close
      const node = e.target
      if (node.className.indexOf('tree-teacher') + node.className.indexOf('tree-student') === -2) {
        // 两个都找不到时返回值(每个为-1)加起来为-2
        return
      }
      this.popContent = data.tag || '暂无tag'
      const popNode = document.getElementById(this.$refs.popover.tooltipId)
      const pos = this.getAbsolutePos(node)
      // getAbsolutePos函数借助节点的offsetParent方法递归获取元素相对浏览器的绝对坐标
      if (popNode === null) {
        return
      }
      popNode.style.left = pos.left + 'px'
      popNode.style.top = pos.top + node.getBoundingClientRect().height + 10 + 'px'
      // 很坑,left与top必须用绝对坐标,而且popover show之前无法获取坐标等信息
      this.$refs.popover.doShow()
    }

成果展示

图 输入
图 节点展开显示
图 个人信息展示框
图 支持节点缩放
图 多树共存
图 合并树 1
图 合并树 2
图 双树关联 1
图 双树关联 2
图 支持横纵向显示切换
图 支持节点拖拽

六、目录结构

目录说明

使用说明

  • 安装nodejs: https://nodejs.org/
    注:本仓库使用的是v14.13.1

  • 安装vue-cli
    npm install -g @vue/cli

  • clone该仓库
    $ git clone git@github.com:Stareven233/031802504-031802506.git

  • 安装依赖
    cd 031802504-031802506
    npm install

  • 编译&运行
    npm run serve

  • 编译&运行(生产环境)
    npm run build

详见:README.md

七、单元测试

测试工具

选择

用的是与vue集成良好的jest,再准确一点是vue的插件cli-plugin-unit-jest,它开箱即用不需配置

学习

先去查了博客,很杂,很多都是jest而非cli-plugin-unit-jest,不大一样,而且年代有点久,内容还少。
后来照着官方文档学,中英文混杂

简易教程

https://www.cnblogs.com/Stareven233/p/13807613.html

代码

这3个测试用于测试generateTree函数(负责解析并生成树对象),通过wrapper.vm.treeData获取生成结果与已知正确的数据作比较来判断正误

  wrapper.findAllComponents({ name: 'el-button' }).at(0).trigger('click') // 先打开侧边输入框

  it('generateTree(expand)', () => {
    const button = wrapper.findAllComponents({ name: 'el-button' }).at(2)
    button.trigger('click')
    wrapper.vm.expandChange()
    // 先生成,再展开才有数据,而且还不能跟上方的侧边输入框打开放一起
  })

  it('generateTree(treeData)', () => {
    const tData = [{ label: '张三', tag: '导师', isTeacher: true, children: [...]...]
    expect(wrapper.vm.treeData).toEqual(tData)
  })

  it('generateTree(nodeData)', () => {
    const nData = { 张三: { isTeacher: true, node: { label: '张三', tag: '导师', isTeacher: true, children: [...]}
    expect(wrapper.vm.nodeData).toEqual(nData)
  })

构造思路

分成静态与动态两部分,静态指已知数据测试渲染是否正确,动态指给出原始文本能否通过页面输入、点击正确解析出数据并生成树
从组件的渲染、特定节点信息正误与内部变量三个方面综合考虑,重点放于树的生成合并与树渲染测试
站在测试员的角度,站在一般用户的角度思考,比如输入文本可能会是特殊结构,不同编码,或是大量数据造成处理过久溢出等错误

测试与覆盖率结果

图 单元测试

八、Github Commit 记录

图 1 Github Commit

九、总结

遇到的问题

  1. 问:久闻vue大名,但从没用过,时间紧任务重
    解:现卖现学
    学:nodejs、vue、less、jest等前端开发知识
  2. 问:vue难以调试,配合上eslint体验更糟,代码规范严格,定义语法,分号换行都非常严,仿佛在打python,最要命的是不允许暴露内部变量,渲染出错也不能查看数据,绝望。
    试:vue-devtools
    解:习惯它
    学:vue-devtools(但没想象的好用,编译半天还出错)、感受到了vue的两面性,也或许只是自己学的还不够...
  3. 问:想为节点添加popover弹出框,然而element的这个组件要求将按钮包裹在内共同渲染,但是树是动态生成的,页面初始化时无法确定。
    试:选用了ref引用方式绑定,然而还是没有响应,能弹出却不能自动定位。反复看文档也没用相关api提供
    解:最后手写定位,但一开始没搞清相对定位跟绝对定位差别,为此浪费了大量时间...
    学:组件props及原生js操作
  4. 问:jest文档不全,东拼西凑到处学...一开始由于用了element库一直报错说没注册组件
    试:查看文档、各论坛、不断调整代码
    解:在测试代码中组件要跟main.js一样用Vue.use注册,这些文档可都没说啊...
    学:jest单元测试
  5. 问:队友天天熬夜,然而我睡眠浅,因此一直没睡好,空耗了不少coding时间
    试:多次沟通,他也确实多有注意,但醒着总会发出声音...
    解:无
  6. 可能或者应该还有一些,但是忘记了

不足

  1. 时间没规划好,在不大重要的功能(popover)上花了太多时间
  2. 没做搜索功能,不难,但没时间,有些遗憾。
  3. 设想中还应该用element-ui的tree组件做一个侧边目录并集成搜索便于浏览...
  4. 没考虑师生同名的情况,如果有这种数据会因为相互递归而栈溢出。而且动态合并考虑的情况还不够充足。
  5. 页面效果还可以再好一些,奈何能力与时间都有限。

队友评价

  1. 大佬,稳,懂的都懂
  2. 喜欢熬夜,然而第二天又很晚起,我也得被迫晚睡,特别是这几天还要早起改bug
  3. 希望能一起早睡早起,同步合作的节奏
posted @ 2020-10-12 15:19  NoNoe  阅读(122)  评论(2编辑  收藏  举报