这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277 |
这个作业的目标 | 学习前端编程,实现学术家族树的展现以及在 Github 上进行结对作业 |
学号 | 031802329 031802330 |
一、开头
| 标题 | 链接 |
| ---- | ---- | ---- |
| 结对同学博客链接 | https://www.cnblogs.com/yiqn/ |
| 本作业博客链接 | https://www.cnblogs.com/xldtf/ |
| Github 仓库链接 | https://github.com/031802330/031802329-031802330 |
二、具体分工
031802329 | 完成页面设计和实现 |
---|---|
031802330 | 完成测试代码检查 |
共同完成 | 编码实现以及博客编写 |
三、PSP 表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 120 | 150 |
Estimate | 估计这个任务需要多少时间 | 1435 | 1970 |
Development | 开发 | 300 | 360 |
Analysis | 需求分析 (包括学习新技术) | 360 | 400 |
Design Spec | 生成设计文档 | 30 | 30 |
Design Review | 设计复审 | 20 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 15 | 30 |
Design | 具体设计 | 60 | 90 |
Coding | 具体编码 | 300 | 500 |
Code Review | 代码复审 | 60 | 100 |
Test | 测试(自我测试,修改代码,提交修改) | 50 | 60 |
Reporting | 报告 | 30 | 40 |
Test Report | 测试报告 | 10 | 20 |
Size Measurement | 计算工作量 | 20 | 40 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 120 |
合计 | 1435 | 1970 |
四、解题思路描述与设计实现说明
-
实现思路
从网页文本框获取文字,按行将文字分割
1.遍历每行,提取是{学生: "技能"}格式的行,处理成 JSON 格式的数据
2.遍历每行,提取是{年级:学生}格式的行,查找1步骤中得到的数据是否有匹配的学生,再将其处理成 JSON 格式的数据
3.遍历每行,提取是导师的行,为导师添加各个年级的学生,处理成 JSON 数据
4.将 JSON 数据传给表格,用 EasyUI 前端框架将其变成树状结构
(其中,"导师:","级博士生:","级硕士生:","级本科生:"和"、"当做关键词处理) -
数据流图
-
代码片段
function show() {
text = $("#text").val();//获取文本框文字
text_arr = text.split('\n');//文字按行分割
var flag_count = [];
//记录导师所在行的索引
for (var f = 0; f < text_arr.length; f++) {
if (text_arr[f].indexOf("导师") !== -1) {
flag_count.push(f);
}
}
var mentor = [];
var id = 0;
for (var ff = 0; ff < flag_count.length; ff++) {
//确定一个导师下的所有学生的起始索引和终止索引
var begin = flag_count[ff];
var end = 0;
if (flag_count.length === 1 || ff === flag_count.length - 1) {
end = text_arr.length;
} else {
end = flag_count[ff + 1];
}
var student = [];
var grade = [];
//获取学生的技能,使之转成JSON数据
for (var i = begin; i < end; i++) {
if (text_arr[i].indexOf("博士生") === -1 && text_arr[i].indexOf("硕士生") === -1 &&
text_arr[i].indexOf("本科生") === -1 && text_arr[i].indexOf("导师") === -1 && text_arr[i] !== "") {
var temp1 = text_arr[i].split(':');
var temp2 = temp1[0];
var temp3 = temp1[1].split('、');
var temp4 = [];
for (var j = 0; j < temp3.length; j++) {
temp4.push({"id": id++, "name": temp3[j], "skills": temp3[j]});
}
student.push({"id": id++, "name": temp2, "student": temp2, "children": temp4});
}
}
//获取每个年级下的学生,并将学生技能补充进来
for (var q = begin; q < end; q++) {
if (text_arr[q].indexOf("博士生") !== -1 || text_arr[q].indexOf("硕士生") !== -1 ||
text_arr[q].indexOf("本科生") !== -1 && text_arr[q] !== "") {
var demo1 = text_arr[q].split(':');
var demo2 = demo1[0];
var demo3 = demo1[1].split('、');
var demo4 = [];
for (var k = 0; k < demo3.length; k++) {
var flag = 0;
for (var m = 0; m < student.length; m++) {
if (student[m].student === demo3[k]) {
demo4.push({
"id": id++,
"name": demo3[k],
"student": demo3[k],
"children": student[m].children
})
flag = 1;
}
}
if (flag === 0) {
demo4.push({"id": id++, "name": demo3[k], "student": demo3[k]});
}
}
grade.push({"id": id++, "name": demo2, "grade": demo2, "children": demo4});
}
}
//获取导师数据,补充年级学生技能数据,使之成为JSON格式的数据(导师-年级-学生-技能)
for (var n = begin; n < end; n++) {
if (text_arr[n].indexOf("导师") !== -1 && text_arr[n] !== "") {
var t = text_arr[n].split(":");
var men = t[1];
mentor.push({"id": id++, "name": '导师:'+men, "mentor": men, "children": grade});
}
}
}
console.log(mentor);
var Mentor = [];
var delete_num = [];
//以下几个循环的目的是补充导师下的学生是导师的情况,可以支持N重导师嵌套
for (var me = mentor.length-1; me >=0 ;me--){
var mentor_name = [];
for (var ment = 0; ment < mentor.length; ment++){
// if (ment !== me){
mentor_name.push(mentor[ment]);
// }
}
for (var mento = 0; mento < mentor[me].children.length;mento++){
for (var mentoe = 0; mentoe < mentor[me].children[mento].children.length;mentoe++){
var name_test = mentor[me].children[mento].children[mentoe].name;
for (var fg = 0; fg < mentor_name.length;fg++){
if ('导师:' + name_test === mentor_name[fg].name && ment !== me){
// alert(name_test);
mentor[me].children[mento].children[mentoe].name = mentor_name[fg].name;
mentor[me].children[mento].children[mentoe].children = mentor_name[fg].children;
// delete mentor[fg];
Mentor.push(mentor[me]);
delete_num.push(fg);
// alert(fg);
}
}
}
}
}
var new_mentor = [];
for (var new_ = 0; new_ < mentor.length;new_++){
var flag_new = 0;
for (var new_1 = 0; new_1 < delete_num.length;new_1++){
if (delete_num[new_1] === new_){
flag = 1;
}
}
if (flag !== 1) {
new_mentor.push(mentor[new_]);
}
}
console.log(Mentor);
$('#dg').treegrid('loadData', new_mentor);
}
五、附加特点设计与展示
设计的创意独到之处,这个设计的意义
- 在输入框上方设计了一个提示按钮,点击即可获得提示页面
- 意义:可以帮助第一次使用的用户提供输入的格式,防止出现无法输出的情况
实现思路
- 使用 Easyui Messager 框架中的 $.messager.show 函数来实现
代码片段
function pro() {
$.messager.show({
title: '输入实例', //头部面板上显示的标题文本
msg: '导师:张三<br>2016级博士生:天一、王二、吴五<br>刘六:JAVA、数学建模', //要显示的消息文本
showType: 'slide', // 定义消息窗口如何显示,默认是 slide
style: { //定义消息窗口的自定义样式
right: '',
top: document.body.scrollTop + document.documentElement.scrollTop,
bottom: ''
}
});
}
成果展示
六、目录说明和使用说明
目录
-
work2
- demo.html(在chrome上运行)
- jquery-easyui-1.3.3/themes/default/easyui.css(调用的外部框架)
- jquery-easyui-1.3.3/themes/icon.css
- jquery-easyui-1.3.3/demo/demo.css
- jquery-easyui-1.3.3/jquery.min.js(调用的js函数)
- jquery-easyui-1.3.3/jquery.easyui.min.js
- jquery-easyui-1.3.3/locale/easyui-lang-zh_CN.js
-
README 使用说明
使用方式
-
下载work2到本地,解压后文件本地,用chrome打开demo.html,在左侧文本框输入文本并且有输入提示。
学术家族树以文本形式输入,点击展示成树。
文本格式
输入:
学术家族树以文本形式输入,点击展示成树即可生成,学术家族树的文本格式是这样的:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
刘六:JAVA、数学建模
李二:字节跳动、京东云
其中,"导师:","级博士生:","级硕士生:","级本科生:"和"、"当做关键词处理;若有多组输入,中间空一行。
输出:
-
树的节点,鼠标点击后是可以缩放的。同时,支持呈现多棵树并存、两棵关联树共存等形式。
在右侧家族树下会显示可缩放的树状结构,即生成的家族树。
七、测试
单元测试
-
单元测试思路
选取三种异常情况和4种正常情况,对于代码中的主要函数进行测试
异常情况设定为丢失关键字和输入为空的情况
-
测试工具
选用mocha进行测试,调用node自带的assert断言库
-
简易安装教程
-
首先需要安装 node.js,参照教程 https://www.runoob.com/nodejs/nodejs-install-setup.html
-
下载zip压缩包 https://github.com/ruanyf/mocha-demos/archive/master.zip
打开解压后的文件夹目录里面安装依赖(npm install),最后在全局安装 mocha(npm install --global mocha) -
在mocha的根目录下创建 test 文件夹,并将 HTML 代码中选取要测试的函数,在 test 文件中保存为.js文件
-
编写测试文件与运行测试文件,具体可参照 https://www.liaoxuefeng.com/wiki/1022910821149312/1101756368943712
- 单元测试部分代码
describe('异常情况', () => {
it('输入数据为空', () => {
assert.throws(() => {//希望抛出异常
test.show("")
},Error);
});
it('导师信息格式错误', () => {
assert.throws(() => {
test.show(`导:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
刘六:JAVA、数学建模
李二:字节跳动、京东云`)},Error);
});
- 单元测试截图
多组数据测试
数据一:
导师:张三
数据二:
导师:张三
2016级博士生:天一
2015级硕士生:李四
2016级硕士生:刘一
2017级本科生:刘六
数据三:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
缩放
数据四:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
数据五:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
导师:吴五
2016级博士生:天一、王二、吴
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘2、琪七、司四
数据六:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
导师:吴3
2016级博士生:天二、王四、吴六
2015级硕士生:李一、王八、许七
2016级硕士生:刘三、李八、李二
2017级本科生:刘一、琪八、司四九
导师:刘2
2016级博士生:天四、王九
2015级硕士生:李四
2016级硕士生:刘一
2017级本科生:刘一
缩放
数据七:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
刘六:JAVA、数学建模
李二:字节跳动、京东云
数据八:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
刘六:JAVA、数学建模
李二:字节跳动、京东云
导师:吴五
2016级博士生:天一、王二、吴
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘2、琪七、司四
数据九:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四
刘六:java、python
导师:刘2
2016级博士生:天四、王九
2015级硕士生:李四
2016级硕士生:刘三
2017级本科生:刘四
天四:java、python
八、Github 的代码签入记录截图
九、遇到的代码模块异常或结对困难及解决方法
-
刚开始时树状结构难以实现,不熟悉编码,后来通过学习 HTML+JS+CSS 以及学习并使用 jquery-easyui 框架将问题解决
-
第一次编码完成后通过测试发现只实现了单棵树的生成而无法实现多棵树并存、两棵关联树共存,在实现了第一棵树之后发现后面的
树都会将前面的树再重新生成一次,被这个问题困扰了很久。最后通过面向 CSDN 和面向博客园编程,发现了问题所在,最后得以解决 -
收获:学会了初步使用 HTML+CSS+JS 进行编程,并且通过结对编程,我们能够有效的实现知识间的互补,提高效率。
十、评价队友
值得学习的地方
不轻易放弃,学习能力强
需要改进的地方
- 页面设计较为简洁,不是很好看
- 需要更加熟悉编程语言,增加知识的储备量