软工实践结对编程第二次作业
这个作业属于哪个课程 | 2021春软件工程实践|W班(福州大学) |
---|---|
这个作业要求在哪里 | 作业要求 |
结对学号 | 221801433 |
221801407 | |
这个作业的目标 | 用web技术来实现原型中的功能 |
其他参考文献 | 无 |
github仓库地址和代码规范链接
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
-- | -- | -- | -- |
Planning | 计划 | 15 | 10 |
• Estimate | • 估计这个任务需要多少时间 | 15 | 10 |
Development | 开发 | 3060 | 3630 |
• Analysis | • 需求分析(包括学习新技术) | 300 | 250 |
• Design Spec | • 生成设计文档 | 30 | 20 |
• Design Review | • 设计复审 | 90 | 90 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 60 | 90 |
• Design | • 具体设计 | 30 | 40 |
• Coding | • 具体编码 | 2400 | 2810 |
• Code Review | • 代码复审 | 90 | 120 |
• Test | • 测试(自我测试,修改代码,提交修改) | 60 | 210 |
Reporting | 报告 | 55 | 50 |
• Test Report | • 测试报告 | 30 | 25 |
• Size Measurement | • 计算工作量 | 15 | 10 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 15 |
合计 | 3130 | 3690 |
访问链接
成品展示
首页查询
首页换页
对论文列表进行删除
对论文列表进行查询详细信息
热门领域、热门研究方向动图呈现
对论文进行进行编辑
结队讨论过程描述
刚拿到题目后,对如何实现这个作业感觉到一些迷茫,对于如何实现之前的设计的原型我们进行了讨论,并对框架的选择进行了斟酌,我们都是第一次接触框架,为了加深对新技术的学习,我们阅读文档和阅读其他博客,看教学视频等。
在开发的过程中,也是边写代码边学习新的知识,在开发过程中,我们经常约在一起写代码,在出现问题的时候沟通也比较方便,当两人空闲时间交错的时候,我们也会通过QQ进行交流,每次fetch代码的时候可以从新代码中学习到新的知识,互相交流,改进彼此的代码和巩固知识。
代码实现过程
描述设计实现过程、给出功能结构图
1. 框架使用:使用的是thinkphp5框架来实现构建,
2. 前端:采用HTML、CSS、JS的形式来编写代码,并且用Vue渲染Element,也用Ajax来进行POST对url发送请求,通过COOKIE来实现传值
3. 后端:采用think php5框架,通过PHP语言来进行数据库操作。(TP5框架采用了MVC结构,按着TP5框架实现网页功能思路清晰)
4. 数据库用的是phpyadmin数据库结构如下
> 功能结构图
代码说明
首页搜索栏
搜索拦HTML部分,可以通过el-select下拉框来选择所要搜索的部分来查询
<div class="search">
<el-row>
<el-col :span="20">
<el-input placeholder="请输入小写字母" icon="search" v-model="devfilter" class="search-input" clearable>
</el-input>
</el-col>
<el-col :span="4">
<el-select v-model="value" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
</div>
搜索栏Vue部分,根据搜索栏的值来判断对哪一部分进行搜索来缩小论文的范围,更容易的找到需要的论文
watch: {
devfilter: function (val, oldVal) {
console.log(this.value);
if (this.value == 'title') {
this.tableData = this.sourceData.filter(dataNews => {
return Object.keys(dataNews).some(key => {
return String(dataNews['title']).toLowerCase().indexOf(val) > -1
})
});
} else if (this.value == 'abstract') {
this.tableData = this.sourceData.filter(dataNews => {
return Object.keys(dataNews).some(key => {
return String(dataNews['abstract']).toLowerCase().indexOf(val) > -1
})
});
} else if (this.value == 'keyword') {
this.tableData = this.sourceData.filter(dataNews => {
return Object.keys(dataNews).some(key => {
return String(dataNews['keyword']).toLowerCase().indexOf(val) > -1
})
});
}
}
列表部分提供了标题、摘要、关键字、发布日期四项属性来显示论文信息
<el-table :data="tableData.slice((currpage-1)*4,currpage*4)" stripe style="width: 100%"
@cell-click="handleMainCellClick">
<el-table-column prop="title" label="标题·" width="180">
</el-table-column>
<el-table-column prop="abstract" label="摘要">
</el-table-column>
<el-table-column prop="keyword" label="关键字" width="180">
</el-table-column>
<el-table-column prop="releasetime" label="发布日期" width="180">
</el-table-column>
</el-table>
概况页面
HTML部分
通过动图形式来呈现Top10和历年峰会的关键词趋势
el-tab-pane label="概况" name="third">
<div id="top" style="width: 280px;height: 800px; float:right;">
<el-table :data="wordTableData" stripe @cell-click="handleCellClick" style="width: 100%">
<el-table-column prop="hot" label="TOP 10" align="center">
</el-table-column>
</el-table>
</div>
<div id="CVPR" style="height: 400px;width: 900px;"></div>
<div id="ECCV" style="height: 400px;width: 900px;"></div>
<div id="ICCV" style="height: 400px;width: 900px;"></div>
</el-tab-pane>
JS部分用echarst的时间轴与柱状图实现历年来不同峰会的关键词趋势。如CVPR峰会:
var chartDom = document.getElementById('CVPR');
var myChart = echarts.init(chartDom,'roma');
var option = {
//timeline基本配置都写在baseoption 中
baseOption: {
timeline: {
//loop: false,
axisType: 'category',
show: true,
autoPlay: true,
playInterval: 3000,
data: ['CVPR2020','CVPR2019','CVPR2018' ]
},
grid: { containLabel: true },
xAxis: [{
type: 'category',
name: 'KeyWord',
},],
yAxis: { type: 'value', name: '频率' },
series: [
{
type: 'bar',
},
],
tooltip: {}
},
编辑页面
编辑页面论文列表部分,列表显示论文题目、摘要、关键词可以通过按钮来对论文进行编辑和删除,通过分页器来让列表更加直观
<div id = "table" style = "margin-top:20px">`
<template>
<el-table :data="tableData.slice((currPage-1)*limitCount,currPage*limitCount)" border style = "width:100%;" >
<el-table-column fixed prop = "title" label="论文题目" align="center" min-width="20%"></el-table-column>
<el-table-column fixed prop = "abstract" label="论文摘要" align="center" min-width="30%">
<template slot-scope="scope" >
<span>{{scope.row.abstract|ellipsis}}</span>
</template>
</el-table-column>
<el-table-column fixed prop = "keyword" label="论文关键词" align="center" min-width="30%">
<template slot-scope="scope" >
<span>{{scope.row.keyword|ellipsis}}</span>
</template>
</el-table-column>
<el-table-column fixed prop = "url" label="论文链接" align="center" min-width="10%">
<template slot-scope="scope">
<span class="span-text" v-if="scope.row.link!== undefined && scope.row.link.length >=1">
<a link :href="scope.row.link" target="_blank">原文链接</a>
</span>
</template>
</el-table-column>
<el-table-column fixed prop = "operation" label="操作" align="center" min-width="15%">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="primary" size="small">编辑</el-button>
<el-button @click="handleDelete(scope.row)" type="danger" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
</div>
<div id = "page" style = "margin-top: 20px;">
<el-pagination
@current-change="currentChange"
:current-page= "currPage"
layout = "prev, pager, next"
:total="{$count}"
:page-size = "limitCount"
style="text-align: center"
>
</el-pagination>
</div>
script部分,列表部分添加过滤器,当题目摘要等文字长度过长的时候进行省略。当点击删除,通过ajax发送POST请求给PHP文件来进行数据库操作,当点击操作按钮,通过cookie来传递所需要的值,跳转到编辑表单部分,解析cookie给表单赋值。
<script type = "text/javascript">
var aa = {$tableData|raw};
var Main = {
methods:{
handleClick:function(row){
var list = {
"abstract":row.abstract,
"title":row.title,
"link":row.link,
"keyword":row.keyword
}
$.cookie("list",JSON.stringify(list));
$.cookie("page",this.currPage);
// document.getElementById("app").innerHTML =
window.location.href = "editdetail";
},
currentChange:function(val){
console.log(val);
this.currPage = val;
},
handleDelete:function(row){
var list = {
"abstract":row.abstract,
"title":row.title,
"link":row.link,
"keyword":row.keyword
}
$.cookie("deleteList",JSON.stringify(list));
$.cookie("page",this.currPage);
$.ajax({
type:"POST",
contentType: "application/x-www-form-urlencoded",
url:'editdetail/deletePaper',
data:{},
success:function(result){
location.href = "edit"
console.log("修改成功");
alert("删除成功")
},
error:function(msg){
console.log("传输失败");
alert("删除失败")
}
});
}
},
data(){
return {
tableData:aa,
limitCount:4,
currPage : parseInt($.cookie("page")??1),
input:'',
}
},
filters: {
ellipsis(value) {
if (!value) return "";
if (value.length > 150) {
return value.slice(0, 150) + "...";
}
return value;
}
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
</script>
编辑详情页面
表单部分HTML 表单输入框可以通过内容只适应高度
<el-form ref="form" label-width="100px">
<el-form-item label="论文名称">
<el-input v-model="form.title" type="textarea" :autosize="{minRows:1,maxRows:3}">
</el-input>
</el-form-item>
<el-form-item label="论文链接">
<el-input v-model="form.link" type="textarea" :autosize="{minRows:1,maxRows:3}">
</el-input>
</el-form-item>
<el-form-item label="论文关键词">
<el-input v-model="form.keyword" type="textarea" :autosize="{minRows:2,maxRows:10}">
</el-input>
</el-form-item>
<el-form-item label="论文摘要">
<el-input v-model="form.abstract" type="textarea" :autosize="{minRows:2,maxRows:10}">
</el-input>
</el-form-item>
<el-form-item type= "width:100%" align="center">
<el-button @click="commit()" type="success" size="small">完成修改</el-button>
<el-button @click="recover()" type="primary" size="small">重置</el-button>
</el-form-item>
</el-form>
JS部分 当需要重置的时候调用未修改的数据来对表单进行复制,需要进行修改时通过ajax发送请求给php文件,成功跳转回原页面,失败提示修改失败。
var formJSON = $.cookie("list");
$.cookie("list",null);
var editPaper = JSON.parse(formJSON);
console.log(editPaper);
var oldPaperString = JSON.stringify(editPaper);
var oldPaper = JSON.parse(oldPaperString);
var Main = {
methods: {
commit:function(){
var list = {
"oldTitle":oldPaper.title,
"title":editPaper.title,
"oldLink":oldPaper.link,
"link":editPaper.link,
"oldAbstract":oldPaper.abstract,
"abstract":editPaper.abstract,
"oldKeyword":oldPaper.keyword,
"keyword":editPaper.keyword
}
$.cookie("updateList",JSON.stringify(list));
$.ajax({
type:"POST",
contentType: "application/x-www-form-urlencoded",
url:'editdetail/updatePaper',
data:{},
success:function(result){
window.location.href = "edit";
console.log("修改成功");
},
error:function(msg){
console.log("传输失败");
}
});
},
recover:function(){
this.form=JSON.parse(oldPaperString);
console.log(oldPaperString);
}
},
data() {
return {
form: editPaper
}
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
</script>
PHP部分
php获取数据库中数据项的个数和数据,将数据项转化成json数据给页面赋值
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\Request;
class Edit extends Controller
{
protected $request;
public function index()
{
$count = Db::table('paper')->count();
$data = Db::table('paper')->select();
$this->assign('tableData',json_encode($data));
$this->assign('count',$count);
return $this->fetch();
}
}
对所要进行修改的论文数据进行数据库操作,修改和删除。
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
class Editdetail extends Controller{
public function index(){
return $this->fetch();
}
public function updatePaper(){
$listString = $_COOKIE["updateList"];
$list = json_decode($listString,true);
$oldTitle = $list["oldTitle"];
$title = $list["title"];
$oldLink = $list["oldLink"];
$link = $list["link"];
$oldAbstract = $list["oldAbstract"];
$abstract = $list["abstract"];
$oldKeyword = $list["oldKeyword"];
$keyword = $list["keyword"];
// $form = json_encode($_POST);
$result = Db::table('paper')
->where("title",$oldTitle)
->where("link",$oldLink)
->where("abstract",$oldAbstract)
->where("keyword",$oldKeyword)
->update([
"title"=>$title,
"link"=>$link,
"abstract"=>$abstract,
"keyword"=>$keyword
]);
if($result!==false){
return $this->success("编辑成功");
}
else {
return $this->error("编辑失败");
}
}
public function deletePaper(){
$listString = $_COOKIE["deleteList"];
$list = json_decode($listString,true);
$title = $list["title"];
$link = $list["link"];
$abstract = $list["abstract"];
$keyword = $list["keyword"];
$result = Db::table('paper')
->where("title",$title)
->where("link",$link)
->where("abstract",$abstract)
->where("keyword",$keyword)
->delete();
if($result!==false){
return $this->success("删除成功");
}
else {
return $this->error("删除失败");
}
}
}
热词top10排行
通过table来展示排行情况
<div id="top" style="width: 280px;height: 800px; float:right;">
<el-table :data="wordTableData" stripe @cell-click="handleCellClick" style="width: 100%">
<el-table-column prop="hot" label="TOP 10" align="center">
</el-table-column>
</el-table>
</div>
部署cell—click方法来实现点击列表进行转跳,转跳到首页搜索相关关键词的论文:
handleCellClick(row, event, column,cell) {
console.log(row['hot']);
this.activeName='first';
this.value='keyword';
this.devfilter=row['hot'];
},
心路历程和收获
心路历程
结合在构建之法,分别撰写结对开发的心路历程与收获
221801433的感想:
在一开始看到云服务器的时候整个人都蒙了,还好是个结对作业,两个人互相激励互相讨论才找到了方法。因为是全新的知识,都没有做过,我和队友先是开始一起学习,到有一定基础之后便进行了分工。在这过程中遇到了很多困难(相对路径一生之敌),也收获了很多,相比起结对作业前,得到了很大锻炼。
221801407的感想:
这次结对过程中,对作业的要求不是很理解,不知道要怎么开始,对于Web基础知识也没有掌握的很好,虽然遇到了许多困难,遇到了不少困难,但是有了队友的帮助,感觉解决困难的效率高了一倍,结对编程的过程中具体分工,除了完成自己的部分以外,互相帮助,通过沟通交流,做到了1+1>2。
评价结对队友
221801433对221801407的评价:
很庆幸能有这样的队友,在一开始迷茫的时候两个人一起坚持了下来。队友很耐心而且很可靠。虽然两个人一开始基础都不好,但是两个人都是行动派,互相督促相互交流学习,能力得到了迅速提升。在遇到相对路径问题时,我人都快奔溃了,他过来耐心地和我一起debug,最终解决了问题。从他身上我学到了很多,很感谢他。
221801407对221801433的评价:
结对的队友是一个认真负责,有耐心的同学,在结对的过程中,对于Web知识并不完全了解的自己遇到不少迷茫的地方,选择框架的时候,队友推荐可以用tp框架比较简单易学,并提供给我学习的资料;当Vue渲染遇到问题的时候,会给我一些建议和参考,帮我修bug(感动QAQ),同时他对自己的部分认真负责,对css样式非常仔细,感觉到能跟他组队真是太好了,从他的身上我学会了很多新的知识,也意识到了自己还有很多不足需要改进。