2020软工实践第二次结对作业

2020软工实践第二次结对作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277
这个作业的目标 锻炼协作能力,学习js、html知识,熟练github使用
学号 031802443
结对同学的博客链接: https://www.cnblogs.com/alangakong/p/13786718.html
你们队创建的仓库的GitHub项目地址 https://github.com/huipai/031802443-031802406

一、psp表格

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

二、成员及分工

成员 分工
胡烨艳 UI设计、后期美化
郑民浩 生成树js的编码实现

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

代码实现思路

本次编程使用了jstree插件,因此,关键在于如何对输入的数据进行转换,使其成为插件所能使用的对象。首先将输入数据按组分解,对每位导师独立的生成一组树,接着按关键字划分,从导师名下划分出代表不同学位的节点,不同学位节点中划分出不同年级的节点,年级节点内包含该级学生。

关键实现的流程图或数据流图

重要的/有价值的代码片段

function buildTree(str,num,submitNum)
   //submitNum为用户的输入次数,num为在该次输入中,这是第num组数据
{
    var supervisorPatt=/导师:.*/g;   //利用正则表达式提取导师与学生信息
    var doctorPatt=/\d{1,}级博士生:.*/g;   
    var postgraduatePatt=/\d{1,}级硕士生:.*/g;
    var undergraduatePatt=/\d{1,}级本科生:.*/g;
    var numberPatt=/\d{1,}/g;    //利用正则表达式提取入学年份
    var supervisor=str.match(supervisorPatt);    //得到导师信息
    if(supervisor==null)    //导师信息为空
    {
       alert("请按照格式输入导师名"); 
       throw new Error(result.error_code);
    }
    else if(supervisor.length>1)  //一组数据中读取到多位导师信息
    {
        alert("每位导师之间空行数为2");
        throw new Error(result.error_code);
    }
    var treeDiv=document.createElement('div');  //建立该树的div块
    treeDiv.setAttribute("id","tree"+submitNum+num);
    document.getElementById("studyTree").appendChild(treeDiv);
    var treeRoot=document.createElement('ul');  //根据jstree格式,建立根节点
    treeRoot.setAttribute("id","root"+submitNum+num);
    document.getElementById("tree"+submitNum+num).appendChild(treeRoot);
    supervisor=supervisor.join("").split(":");   //从提取出的导师信息中进行拆分得到导师名
    var ele = document.createElement('li');    //建立导师节点
    ele.setAttribute("id","supervisor"+submitNum+num);
    ele.innerHTML=supervisor[1];
    document.getElementById("root"+submitNum+num).appendChild(ele);
    var doctor=str.match(doctorPatt);   //在输入数据中寻找硕士,博士,本科三种学位
    var postgraduate=str.match(postgraduatePatt);
    var undergraduate=str.match(undergraduatePatt);
    if(doctor||postgraduate||undergraduate)  //如果有学生数据,则建立学位根节点
    {
        var degree = document.createElement('ul');     
        degree.setAttribute("id","degree"+submitNum+num);
        document.getElementById("supervisor"+submitNum+num).appendChild(degree);
    }
    else
    {
        alert("注意:输入的数据中导师"+supervisor[1]+"没有检测到学生数据,如果数据无误,请忽略该提示")
    }
    if(doctor)    //如果有博士数据,则按照插件格式建立节点
    {
        var doctorDegree=document.createElement('li');    //建立博士节点
        doctorDegree.setAttribute("id","doctorDegree"+submitNum+num);
        doctorDegree.innerHTML="博士生";
        document.getElementById("degree"+submitNum+num).appendChild(doctorDegree);
        var doctorGradeUl=document.createElement('ul');       //建立博士年级根节点
        doctorGradeUl.setAttribute("id","doctorGradeUl"+submitNum+num);
        document.getElementById("doctorDegree"+submitNum+num).appendChild(doctorGradeUl);
        for(var i=0;i<doctor.length;i++)     //读取所有年级的博士数据并建立各个年级节点
        {
            var doctorStr=doctor[i];  
            doctorStr=doctorStr.split(":");    //将冒号前后区分开,前为年级,后为具体学生
            var doctorGradeLi=document.createElement('li');     //建立年级节点
            doctorGradeLi.innerHTML=doctorStr[0].match(numberPatt);
            doctorGradeLi.setAttribute("id","doctorGradeLi"+submitNum+num+i);
            document.getElementById("doctorGradeUl"+submitNum+num).appendChild(doctorGradeLi);
            var doctorNameUl = document.createElement('ul');    //建立学生根节点
            doctorNameUl.setAttribute("id","doctorNameUl"+submitNum+num+i);
            document.getElementById("doctorGradeLi"+submitNum+num+i).appendChild(doctorNameUl);
            var nameValue=doctorStr[1].split("、");      //将所有学生拆分开
            for(var j=0;j<nameValue.length;j++)   //建立各个学生的独有节点
            {
                var doctorNameLi=document.createElement('li');
                doctorNameLi.setAttribute("id","暂无"+nameValue[j]+submitNum+num);
                doctorNameLi.innerHTML=nameValue[j];
                document.getElementById("doctorNameUl"+submitNum+num+i).appendChild(doctorNameLi);
            }
        }
    }
//硕士生与本科生节点建立过程类似,不再重复展示
    str=str.split("\n\n");    //拆分个人经历与技能
    for(var i=1;i<str.length;i++)   //遍历所有经历
    {
//由于学生节点id根据姓名生成,因此直接提取经历中的姓名,并进行搜索,将该学生id改为姓名+技能与经历,方便生成点击事件
  var abilityStr=str[i];
        abilityStr=abilityStr.split(":");
        if(!document.getElementById("暂无"+abilityStr[0]+submitNum+num))
        {
            alert("没有找到姓名为"+abilityStr[0]+"的学生,该条技能经历添加失败");
        }
        else
        {
            document.getElementById("暂无"+abilityStr[0]+submitNum+num).setAttribute("id",abilityStr[0]+"的技能及其经历:"+abilityStr[1]);
        }
    }

四、网页展示


五、附加特点设计与展示

设计的创意及设计的意义

考虑到多次输入数据可能会出现错误,提供了重置功能来清空树与文本框
考虑到可能会有新的数据,因此在已生成的树中提供了新增节点,删除节点与重命名节点功能
为了使修改方便,提供了拖动节点修改树的功能

实现思路

参考jstree api文档,与博客,对jstree进行配置
贴出你认为重要的/有价值的代码片段,并解释【2分】

    $(function(){$("#tree"+submitNum+num+"").jstree({
        plugins : ["types","contextmenu","state","dnd"], 
        'state': {
            "opened":true   //默认生成树展开
       },
        'core' : {
                    "check_callback" : true,}, //允许修改节点
        "types": {
          "default" : {
            "icon" :false,  //关闭图标
          },
      },
      'contextmenu':{
                    'items' : {
                        'add':{
                            'label':'新增节点',
                            'action':function(obj){
//reference调用当前节点引用
                                var inst = jQuery.jstree.reference(obj.reference);
//get_node方法获取节点信息
                                var clickedNode = inst.get_node(obj.reference);
//建立新节点
                                var newNode = inst.create_node(clickedNode,
                                    { 
                                        'icon' : false,//关闭默认图标
                                        'text':'新节点'},'last',function(node){
                                        inst.edit(node,node.val);
                                    },'');
                            }
                        },
                        'rename':{      //修改选中节点名
                            'label':'修改节点',
                            'action':function(obj){
                                var inst = jQuery.jstree.reference(obj.reference);
                                var clickedNode = inst.get_node(obj.reference);    
                                inst.edit(obj.reference,clickedNode.val);
                            }
                        },
                        'delete':{   //删除选中子节点
                            "label": "删除节点",
                            'action':function(obj){
                                var inst = jQuery.jstree.reference(obj.reference);
                                var clickedNode = inst.get_node(obj.reference);
                                inst.delete_node(obj.reference);
                            }
                        }
                    }
                }
      });});

支持多组输入、多次输入、多棵树并存,支持新增节点,删除节点,修改节点名,以及拖动节点来对树进行重新排列,以及重置功能

多组输入

多组输入

多次输入

右键点击子节点即可打开菜单栏

拖动节点进行修改

六、目录及使用说明

目录说明

  • JS文件夹:myJs.js文件包含了生成学术树的主体js代码以及所用到的jQuery和jsTree文件。

  • dist文件夹:jstree插件目录

  • image文件夹:插入的图片

  • css文件夹:网页的css文件

  • index.html:网页的html文件

  • REAMDE.md:目录说明与使用说明

使用说明

  • 请将上述的文件统一下载并放入同一文件夹中,以防出现异常。

  • 使用浏览器打开index.html文件,即可在浏览器中看到页面。

  • 在左侧的文本框输入数据,点击生成按钮,将会在右侧生成一棵以导师为根节点的树。

  • 输入时每组数据之间空两行,个人技能之间空一行,数据中的符号使用中文半角字符。

  • 点击重置按钮,将会清空文本框内容与已生成的树。

  • 点击学生类型节点,将会出现个人技能及经历。

  • 点击小三角或是双击节点内容如可展开或收起节点。

  • 在节点处单击右键,可进行修改、删除、添加节点的操作。

    • 修改节点:重新命名选中节点。

    • 删除节点:删除选中节点及其子节点。

    • 新增节点:在该节点处新增一个子节点。

    • 支持拖动节点进行树的修改。

如何运行网页

下载完整代码后,保证其他文件夹也在其中,都是引用本地相对路径的文件
使用谷歌浏览器打开index.html 即可打开网页

在学术树生成器中,按照样例输入并生成即可获得对应的生成树

点击姓名可查看技能树以及经历

七、单元测试

测试工具

选用了mocha测试工具,根据教程http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html学习mocha的使用

简易教程

首先安装node.js,安装参照https://www.runoob.com/nodejs/nodejs-install-setup.html
接着打开cmd,输入npm install --global mocha安装mocha
参照上文mocha教程编写测试代码

部分单元测试代码

利用describe块形成测试套件,调用node提供的assert断言完成测试

 describe('异常情况', () => {
        it('输入数据为空', () => {
            assert.throws(() => {//希望抛出异常
                test.spiltInput("")
            },Error);
        });
        it('导师信息格式错误1', () => {
            assert.throws(() => {
                test.buildTree(`导师张三
                2016级博士生:天一、王二、吴五
                2015级硕士生:李四、王五、许六
                2016级硕士生:刘一、李二、李三
                2017级本科生:刘六、琪七
                
                刘六:JAVA、数学建模
                
                李二:字节跳动、京东云`)},Error);
        });
});
  • 运行结果

构造测试思路

将测试分为正常情况与异常情况两种,考虑用户可能对格式的不熟悉,在异常情况中构造了不按格式输入的数据,在正常情况中则构造了单颗树与多颗树的输入数据

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

九、遇到的代码模块异常或结对困难及解决方法

问题:css界面设计不熟悉,网页ui不够美观
解决:通过查询文档,观看视频,略微美化了网页
问题:技能树的添加
解决:将技能作为个人id,添加点击事件显示节点id
问题: mocha环境搭建
解决: 看了很多博客,每次运行都报错,之后清理了数据才安装好
问题: 测试用例的编写
解决: 因为从前没有做测试的习惯,因此没有基础,跟着教程从头学习

十、收获

  • 在做中学习了js、html、css三种语言
  • 熟悉了github的团队开发
  • 熟悉了单元测试

十一、评价你的队友

值得学习的地方:做事认真仔细踏实,很好沟通,团队合作遇到问题可以很及时的解决
需要改进的地方:我们都是小白,还需提高代码能力

posted @ 2020-10-11 23:44  晖派  阅读(134)  评论(0编辑  收藏  举报