第4次作业-结对编程之实验室程序实现

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277
这个作业的目标 <你理解的作业目标具体内容>
学号 031802406
结对同学的博客链接: https://www.cnblogs.com/ljhsb/p/13800209.html
你们队创建的仓库的GitHub项目地址 https://github.com/huipai/031802443-031802406

一、具体分工

成员 学号 分工 博客
胡烨艳 031802406 UI设计、归纳总结 https://www.cnblogs.com/alangakong/p/13786718.html
郑民浩 031802443 代码编写 https://www.cnblogs.com/ljhsb/p/13800209.html

二、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

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

代码实现思路,文字描述
本次编程使用了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进行配置

贴出你认为重要的/有价值的代码片段,并解释

$(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测试工具,根据教程测试框架 Mocha 实例教程
简易教程
首先安装node.js,安装参照Node.js 安装配置
接着打开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);
        });
});

说明构造测试数据的思路,你是如何考虑各种情况的?你如何考虑将来测试人员的刁难?
1、 首先对一棵标准生成树的样例的进行测试
2、 对一棵生成树的输入格式不标准的样例进行测试
3、 对多棵树的正常情况进行测试
4、 对多棵树中存在输入格式不标准情况进行测试
5、 对一棵树中存在重名的情况进行测试
6、 对多棵树中存在重名的情况进行测试

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

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

代码上,多棵树中,技能树仅显示在第一棵树上。同名节点id设置相同,通过添加参数使两棵树的同名节点获得不同的id 。目前问题已解决,

九、评价你的队友

队友是个努力上进、自学能力强的人,学习的效率很高,比较不善于表达自己的想法,但是会找到解决的办法。

posted @ 2020-10-12 08:00  yeah9999  阅读(138)  评论(0编辑  收藏  举报