软件工程实践2019第五次作业
前言
结对同学博客:
本次作业博客:
GitHub项目地址:
git@github.com:ThinMoon/031702541-031702543.git
或 https://github.com/ThinMoon/031702541-031702543.git
分工:
林志全同学负责UI设计,博客编写
温俊欣同学负责核心算法设计,部分博客编写
PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时 | 实际耗时 |
---|---|---|---|
Planning | 计划 | 50h | 50h |
Estimate | 估计这个任务需要多少时间 | 50h | 50h |
Development | 开发 | 44h | 40h |
Analysis | 需求分析 (包括学习新技术) | 16h | 15h |
Design Spec | 生成设计文档 | 0.5h | 0.5h |
Design Review | 设计复审 | 0.5h | 0.25h |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 0.5h | 0.25h |
Design | 具体设计 | 1h | 2h |
Coding | 具体编码 | 20h | 18h |
Code Review | 代码复审 | 0.5h | 1h |
Test | 测试(自我测试,修改代码,提交修改) | 5h | 3h |
Reporting | 报告 | 7h | 5.75h |
Test Repor | 测试报告 | 6h | 5h |
Size Measurement | 计算工作量 | 0.5h | 0.25h |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 0.5h | 0.5h |
合计 | 51h | 45.75h |
解题思路描述与设计实现说明
代码组织和内部实现设计
本次我们使用了面向过程的编程方法,我们先是从输入页面文本框返回一个值,然后将这个值进行处理变成json对象,然后将json对象传入生成树的函数中。内部主要有处理文本框返回值的函数以及生成树的函数。
算法的关键与关键实现部分流程图
-
算法关键
算法的关键在于输入文本转json以及按json内容生成树
-
总体流程图
重要的/有价值的代码片段
这次作业其实有两个难点:
1.如何将文本框中的信息提取出并转化成有用的格式,在这我们选择的是将文本框中的内容按级转换成json格式
2.如何生成树,生成树应该是这次作业最大的难点了,我们查找了大量的资料,最终找到了一个可以直接套用的模板,我们要做的只是动态生成json变量即可
所以,在这我们只贴出了转json的核心算法
function setJson()
{
var data = localStorage.getItem("str");
var teaCnt = 0;
var teacherIndex = new Array();//获得教师位置下标
var teacherPatt = /导师:/g;
var block = new Array();//块数组
while(teacherPatt.test(data) == true){
teacherIndex[teaCnt++] = teacherPatt.lastIndex - 3;
}
//将data数据按导师划分成不同块
//若只有一块这默认放置block[0]
if(teacherIndex.length < 1){
block[0] = data;
}else{
for(var i = 0; i < teacherIndex.length; i++){
block[i] = '';
var last = i + 1 == teacherIndex.length? data.length : teacherIndex[i + 1];
for(var j = teacherIndex[i]; j < last; j++){
block[i] += data[j];
}
}
}
for(var i = 0; i < block.length; i++){
// console.log(block[i]);
}
for(var k = 0; k < block.length; k++){
//导师节点
json[k] = {};
json[k].name = block[k].match(/(?<=导师:).*/) + '';//name属性
// console.log(json[k].name);
json[k].code = json[k].name;
json[k].icon = "icon-th";
json[k].child = [];
var count = 0;//确定子节点
//分不同类学生节点
//博士生
if(/级博士生/.test(data)){
//博士生节点
var doc = {};
doc.name = "博士生";
doc.code =json[k].code + doc.name;
doc.icon = "icon-minus-sign";
doc.parentCode = json[k].code;
doc.child = [];
var docArray = block[k].match(/\d{4}级博士生\:.*/g);
// console.log(docArray);
//分不同级博士生
for(var i = 0; i < docArray.length; i++){
var year = {};
year.name = docArray[i].match(/\d{4}/) + '';
// console.log(year.name);
year.code = doc.code + year.name;
year.icon = "icon-minus-sign";
year.parentCode = doc.code;
year.child = [];
//学生名节点
var stuName = docArray[i].match(/(?<=级博士生:).*/) + '';
// console.log(stuName);
var stuNameArray = stuName.split("、");
// console.log(stuNameArray);
//同级不同学生
for(var j = 0; j < stuNameArray.length; j++){
var stu = {};
stu.name = stuNameArray[j];
stu.code = year.code + stu.name;
stu.icon = "";
stu.parentCode = year.code;
stu.child = [];
year.child[j] = stu;
// console.log(stu.name);
}
doc.child[i] = year;
}
json[k].child[count++] = doc;
}
//硕士生
if(/级硕士生/.test(data)){
//硕士生节点
var doc = {};
doc.name = "硕士生";
doc.code = json[k].code + doc.name;
doc.icon = "icon-minus-sign";
doc.parentCode = json[k].code;
doc.child = [];
var docArray = block[k].match(/\d{4}级硕士生\:.*/g);
// console.log(docArray);
//分不同级硕士生
for(var i = 0; i < docArray.length; i++){
var year = {};
year.name = docArray[i].match(/\d{4}/) + '';
// console.log(year.name);
year.code = doc.code + year.name;
year.icon = "icon-minus-sign";
year.parentCode = doc.code;
year.child = [];
//学生名节点
var stuName = docArray[i].match(/(?<=级硕士生:).*/) + '';
// console.log(stuName);
var stuNameArray = stuName.split("、");
// console.log(stuNameArray);
//同级不同学生
for(var j = 0; j < stuNameArray.length; j++){
var stu = {};
stu.name = stuNameArray[j];
stu.code = year.code + stu.name;
stu.icon = "";
stu.parentCode = year.code;
stu.child = [];
year.child[j] = stu;
// console.log(stu.name);
}
doc.child[i] = year;
}
json[k].child[count++] = doc;
}
//本科生
if(/级本科生/.test(data)){
//本科生节点
var doc = {};
doc.name = "本科生";
doc.code = json[k].name + doc.name;
doc.icon = "icon-minus-sign";
doc.parentCode = json[k].code;
doc.child = [];
var docArray = block[k].match(/\d{4}级本科生\:.*/g);
//console.log(docArray);
//分不同级本科生
for(var i = 0; i < docArray.length; i++){
var year = {};
year.name = docArray[i].match(/\d{4}/) + '';
// console.log(year.name);
year.code = doc.code + year.name;
year.icon = "icon-minus-sign";
year.parentCode = doc.code;
year.child = [];
//学生名节点
var stuName = docArray[i].match(/(?<=级本科生:).*/) + '';
// console.log(stuName);
var stuNameArray = stuName.split("、");
// console.log(stuNameArray);
//同级不同学生
for(var j = 0; j < stuNameArray.length; j++){
var stu = {};
stu.name = stuNameArray[j];
stu.code =year.code + stu.name;
stu.icon = "";
stu.parentCode = year.code;
stu.child = [];
year.child[j] = stu;
// console.log(stu.name);
}
doc.child[i] = year;
}
json[k].child[count++] = doc;
}
//console.log(json[k]);
}
}
这边对上述算法进行简单的分析:
1.将文本框中读入的内容按导师分块
2.按学位对每个块分割出不同学位的学生
3.按级对每个学位中的学生分块
代码中都有详细注释,所以具体内容可以看代码
以下是一个成功转换后json对象
目录说明与使用说明
-
目录组织形式
CSS文件夹存放对网页进行渲染的.css文件和bootstrap文件,img文件夹存放背景图以及按钮图,js文件夹中test.js文件包含了生成家族树的主体js代码以及jQuery文件。
-
如何运行网页
- 通过Chrome浏览器打开JStext.html,在输入框中输入符合格式的信息,点击按钮便会跳转到家族树界面
- 在家族树界面若想重新生成新的树,可点击主页按钮跳回文本框界面
单元测试
-
选用工具及其学习方法
我们选用了Qunit作为我们的测试工具,关于学习Qunit我们是在网上搜索了许多教程才略懂一些,CSDN以及博客园有很多Qunit简易教程
-
单元测试代码及其说明
- 单棵树样例:
//...省略setJson函数 QUnit.test( "test", function(assert) { var obj1 = "导师:张三\n2016级博士生:天一、王二、吴五\n2015级硕士生:李四、王五、许六\n2016级硕士生:刘一、李二、李三\n2017级本科生:刘六、琪七、司四"; var temp = [{"name":"张三","code":"张三","icon":"icon-th","child":[{"name":"博士生","code":"张三博士生","icon":"icon-minus-sign","parentCode":"张三","child":[{"name":"2016","code":"张三博士生2016","icon":"icon-minus-sign","parentCode":"张三博士生","child":[{"name":"天一","code":"张三博士生2016天一","icon":"","parentCode":"张三博士生2016","child":[]},{"name":"王二","code":"张三博士生2016王二","icon":"","parentCode":"张三博士生2016","child":[]},{"name":"吴五","code":"张三博士生2016吴五","icon":"","parentCode":"张三博士生2016","child":[]}]}]},{"name":"硕士生","code":"张三硕士生","icon":"icon-minus-sign","parentCode":"张三","child":[{"name":"2015","code":"张三硕士生2015","icon":"icon-minus-sign","parentCode":"张三硕士生","child":[{"name":"李四","code":"张三硕士生2015李四","icon":"","parentCode":"张三硕士生2015","child":[]},{"name":"王五","code":"张三硕士生2015王五","icon":"","parentCode":"张三硕士生2015","child":[]},{"name":"许六","code":"张三硕士生2015许六","icon":"","parentCode":"张三硕士生2015","child":[]}]},{"name":"2016","code":"张三硕士生2016","icon":"icon-minus-sign","parentCode":"张三硕士生","child":[{"name":"刘一","code":"张三硕士生2016刘一","icon":"","parentCode":"张三硕士生2016","child":[]},{"name":"李二","code":"张三硕士生2016李二","icon":"","parentCode":"张三硕士生2016","child":[]},{"name":"李三","code":"张三硕士生2016李三","icon":"","parentCode":"张三硕士生2016","child":[]}]}]},{"name":"本科生","code":"张三本科生","icon":"icon-minus-sign","parentCode":"张三","child":[{"name":"2017","code":"张三本科生2017","icon":"icon-minus-sign","parentCode":"张三本科生","child":[{"name":"刘六","code":"张三本科生2017刘六","icon":"","parentCode":"张三本科生2017","child":[]},{"name":"琪七","code":"张三本科生2017琪七","icon":"","parentCode":"张三本科生2017","child":[]},{"name":"司四","code":"张三本科生2017司四","icon":"","parentCode":"张三本科生2017","child":[]}]}]}]}]; setJson(obj1); assert.deepEqual(json ,temp, "Two objects can be the same in value" ); });
-
测试结果
-
构造数据思路
首先我们先构造了只有一组老师一棵树的情况一组数据,然后我们构造了多组老师多棵树的情况一组数据
GitHub代码签入记录
遇到的困难及解决方法
-
问题描述
在编码的过程中,因为是第一次接触前端,我们遇到了很多困难,首先我们一开始并不清楚如何实现树形结构,然后我们在找到解决树形结构的方法后,又遇到了如何将输入文本转json对象的问题,最后还有进行界面美化的时候,树的线条消失的问题。
-
尝试及解决
-
实现树形结构
我们先在网上的前端教程里寻找有没有实现树形结构的方法结果找不到,然后就在网上搜索树形结构的实现方法,我们找到了一些实现数据可视化的框架如echarts、D3等,本来打算就利用这些框架实现,结果在进一步学习后,我们觉得学习框架太难了就又放弃了使用框架实现,最后我们找到了利用JQuery实现树形结构的方法,学习了jQuery后解决了这个问题。
-
将输入文本转json对象
在上面的重要代码部分就是我们解决后的成果。
别问,问就是四层for循环 -
线条消失
我们在美化完网页界面后发现了家族树节点缩放后在点击放大节点之间连接的线条会消失,研究了很久后发现是我们两人使用的bootstrap版本不一致,在之前修改时没有版本统一起来而是两个版本并用统一版本后解决问题。
-
-
收获
遇到困难时要善于在网络上寻找解决方案,还要自己多加尝试各种解决方案
(遇到无法修改的错误删库跑路即可)
对队友的评价
031702543:
-
值得学习的地方
有强大的动手能力,能很快在网络上寻找有用资源
-
需要改进的地方
在代码编写时的沟通能力不足
031702541:
别问,问就是牛逼!
-
值得学习的地方
learning by doing 我队友很好的向我展示了什么叫做中学,在我还在学的时候他就已经把基础页面做出来了,所以我只需实现下算法即可,很舒服。
-
需要改进的地方
想要实现的太多,奈何时间太短能力不够!