这个作业属于哪个课程 | <2022年福大-软件工程、实践-W班> |
---|---|
这个作业要求在哪里 | <软件工程实践结对作业二> |
结对学号 | <221900112、221900104> |
这个作业的目标 | <实现冬奥栏目原型中的功能、项目部署、结对合作> |
其他参考文献 | 见文章末尾 |
文章目录
1、Gitcode仓库地址
2、代码规范地址
3、项目成果地址
4、PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 900 | 993 |
• Analysis | • 需求分析 | 10 | 5 |
• Technology selection | • 技术选择(包括学习) | 50 | 65 |
• Code specification | • 代码规范制定 | 20 | 30 |
• Front End | 前端 | ||
• Head | • 网页首部 | 15 | 13 |
• Home Page | • 首页 | 90 | 105 |
• Medal List | • 奖牌榜 | 60 | 45 |
• Schedule | • 赛程榜 | 80 | 95 |
• Map | • 地图 | 150 | 160 |
• Expand | • 拓展项目 | 150 | 160 |
• Back End | 后端 | ||
• Database | • 数据库设计与导入 | 30 | 25 |
• Medal Data | • 奖牌相关数据 | 35 | 40 |
• Schedule Data | • 赛程相关数据 | 40 | 40 |
• Other Data | • 拓展相关数据 | 20 | 30 |
• Other | 其他 | ||
• Revise | • 整体完善和测试 | 30 | 30 |
• Deployment | • 项目部署 | 120 | 150 |
Reporting | 报告 | 90 | 105 |
• Writing Repor | • 撰写报告 | 60 | 75 |
• Size Measurement | • 计算工作量 | 10 | 10 |
• Postmortem | • 事后总结 | 20 | 20 |
合计 | 1020 | 1128 |
5、项目成品展示
5.1 主页展示(关于冬奥)
部分展示因审核而做出模糊处理
主页(关于冬奥)由三个部分组成,第一个部分是今日要闻,第二部分是对冬奥的主要项目的介绍,最后一部分即冬奥锦集。其中,当用户点击今日要闻的链接时,即可跳转到相应的新闻页面。
今日要闻部分:
项目展示部分:
冬奥锦集展示部分:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yi2bLJmx-1648275318961)(https://img-community.csdnimg.cn/images/cd3eeef9d7c74f45aa09976987517bc5.JPG “#left”)]
新闻点击演示部分:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7yaNh84l-1648275318962)(https://img-community.csdnimg.cn/images/061f5990ae044ea28ec4f7ebf918b874.gif “#left”)]
5.2 奖牌榜展示
显示各个国家的金牌、银牌、铜牌、总奖牌数以及对应排名,并且高亮显示中国队的奖牌行。
5.3 赛程榜展示
分为两部分:快捷时间查询方式,通过点击上方对应的日期即可查询对应日期的赛程;或者通过三个选择框:日期、比赛项目、比赛场馆,来查询对应的比赛;
快捷时间查询方式展示:
选择框查询方式展示:
5.4 地图展示
左下为奖牌榜展示图,底下为图例,不同的国家根据获得的奖牌数不同而有不同层次的颜色。当移动到对应的国家奖牌榜奖牌榜将做出相应的变化,同时该国家颜色会高亮改变。
5.5 小项目展示
此次沿用原型设计的三个小项目,分别为男子滑降(02-07)、冰壶(02-20)和冰球(02-04)。其中,男子滑降展示选手比赛排名、出场顺序、背心号码、国家、成绩等信息; 冰壶展示对局总比分榜,出场名单,小局得分等信息;冰球展示对局总比分榜,小节的比分、出场名单、赛况具体数据等信息;
男子滑降展示:
冰壶展示:
冰球展示:
6、设计实现过程
6.1 如何设计
见8.2讨论过程
跳转,由于上一步已经确定了要编写前、后端,接着我们确定如何实现前后端的交互,首先是要把所需要的数据(来源自个人第一次作业的
.json
数据文件),例如国家奖牌榜、赛程数据放入
Mysql
数据库之中,通过后端
PHP
代码的编写,进行数据库的(增删)查(改)功能,接着传给前端的
javaScript/jQuery
进行处理,(由于一个较熟悉jQuery,一个较熟悉javaScript,就采用两种技术来编写从后端传来的数据),通过
JSON数组/html元素
标签作为传递媒介。然后给各个页面编写对应的三件套
HTML+CSS+JS
进一步细分要完成的功能,主要是以下这几部分,同时做出结构图:
- 固定头部部分、导航栏、冰壶、冰球、主页:通过网页和样式的编写完成,多用表格展示
- 奖牌榜:前端通过请求后端得到的数据,解析传来的JSON文件并通过表格进行展示
- 奖牌地图:前端通过请求后端得到的数据,解析JSON文件设置对应的属性以及交互事件
- 赛程榜:前端通过请求后端得到的数据,通过设置传来的HTML标签进行交互
- 男子滑降:前端通过请求后端得到的数据,解析JSON文件并通过表格进行展示
6.2 结构图
6.3 遇到的问题/以及解决方案
问题1:犹豫是直接使用读JSON文件还是从数据库读出再打包,最后衡量规范性以及数据安全性、可操作性的因素,还是选择用数据库作为数据存放,此时就出现问题,JSON如何又快又方便的进入数据库,由于MySQL仅支持sql语句,如果一个一个插入效率非常低,后考虑通过编写php代码,先读取并解析JSON文件,在将其导入。由于一些知识的遗忘,在这方面其实花费了我们很多的时间,后面发现Navicat可以直接导入多种形式的文件,追悔莫及,但复习了一遍php以及数据库知识还是值得的。
问题2:开发过程中,在localhost上调试的时候,经常修改了文件但不起作用,一度怀疑是自身的逻辑问题,疯狂的找自己代码的BUG,迟迟不能解决,最后通过F12审阅了一下,发现资源内容中并没有修改,但查看本地已经修改,又怀疑是自己的环境出现了奇怪的问题,几经重装也得不到好转,后经过同学提点,才发现是浏览器缓存导致页面内容没有及时更新!
7、代码说明
7.1 前端重要代码
地图的编写, 利用表格的形式对地图的小奖牌榜展示,先编写出表格的表头,表数据通过JavaScript
编写,接着就是svg
图形,在每个地图地形path
标签中有几个重要属性,countryId
用于识别是哪个国家,fill
用于对国家的颜色进行填充;图例说明也直接通过circle
和text
的组合使用嵌入svg标签中。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-Type" content="text/html; charset=utf-8" />
<title>奖牌地图</title>
<link rel="stylesheet" type="text/css" href="../css/head.css" />
<link rel="stylesheet" type="text/css" href="../css/map.css" />
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="../js/map.js"></script>
</head>
<body>
<div class="content">
<table id="medals">
<tr>
<th id="countryName" colspan="4">中国</th>
<th></th>
<th></th>
</tr>
<tr class="t1">
<td>奖牌榜第</td>
<td id="rank">3</td>
<td>名</td>
</tr>
<tr class="t2">
<td>金</td>
<td id="gold">9</td>
<td><img src="../image/gold.png" width="35px" height="35px"/></td>
</tr>
<tr class="t3">
<td>银</td>
<td id="silver">4</td>
<td><img src="../image/silver.png" width="35px" height="35px" /></td>
</tr>
<tr class="t4">
<td>铜</td>
<td id="bronze">2</td>
<td><img src="../image/bronze.png" width="35px" height="35px" /></td>
</tr>
<tr class="t5">
<td> </td>
<td>总数</td>
<td id="count">15</td>
</tr>
</table>
<svg id="mymap" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1280px" height="750px" transform="translate(140,0) scale(1, 1)" xml:space="preserve">
<g>
<path cs="100,100" d="M0.5,0.5 L1878.5,0.5 L1878.5,895.5 L0.5,895.5 Z" fill="#61ADE8" stroke="#000000" fill-opacity="1" stroke-width="1" stroke-opacity="1" class="amcharts-bg"></path>
<circle cx="390" cy="700" r="10" stroke="white" stroke-width="1" fill="#F87526"/>
<text class="number" x="410" y="708">20+</text>
<circle cx="490" cy="700" r="10" stroke="white" stroke-width="1" fill="#FB9337"/>
<text class="number" x="510" y="708">10~20</text>
<circle cx="610" cy="700" r="10" stroke="white" stroke-width="1" fill="#FAE369"/>
<text class="number" x="630" y="708">5~10</text>
<circle cx="730" cy="700" r="10" stroke="white" stroke-width="1" fill="#E8D163"/>
<text class="number" x="750" y="708">1~5</text>
<circle cx="840" cy="700" r="10" stroke="white" stroke-width="1" fill="#D7D7D7"/>
<text class="number" x="860" y="708">0</text>
</g>
<g>
<g transform="translate(205,250) scale(0.95)">
<g transform="translate(0,0) scale(1)">
<path cs="……" transform="translate(0,-230)" stroke-width="0.726492200578962" fill="#D7D7D7" fill-opacity="1" stroke="#505050" stroke-opacity="1" class="amcharts-map-area amcharts-map-area-AE" role="menuitem" aria-label="United Arab Emirates " countryId="AE"></path>
……
……
</g>
</g>
</g>
</svg>
</div>
</body>
</html>
地图的交互,利用getJSON
函数(ajax集成版),请求对应的php页面,将得到的json文件进行解析遍历,首先通过countryId
来识别对应的地图版图,接着将读取到的数据给对应的版图path
增设属性以便于交互,然后通过奖牌总数给予版图不一样的填充色,最后给每一个版图用hover
函数绑定鼠标移入移出的交互事件,即移入时设置地图页面的奖牌榜文本以及高亮,移出时取消。
$(document).ready(function(){
$.getJSON("../php/getTotal.php",function(data){
$.each(data,function(i,item){
//设置属性
var country=$("[countryId='"+item[0]+"']");
country.attr("rank",item[1]);
country.attr("gold",item[2]);
country.attr("silver",item[3]);
country.attr("bronze",item[4]);
country.attr("count",item[5]);
country.attr("countryName",item[6]);
//颜色
if(country.attr("count")>=20){
country.attr("fill","#F87526");
}
else if(country.attr("count")>=10){
country.attr("fill","#FB9337");
}
else if(country.attr("count")>=5){
country.attr("fill","#FAE369");
}
else if(country.attr("count")>=1){
country.attr("fill","#E8D163");
}
//设置交互事件
var color=country.attr("fill");
country.hover(function(){
country.attr("fill","red");
$("#countryName").text(country.attr("countryName"));
$("#rank").text(country.attr("rank"));
$("#gold").text(country.attr("gold"));
$("#silver").text(country.attr("silver"));
$("#bronze").text(country.attr("bronze"));
$("#count").text(country.attr("count"));
},function(){
country.attr("fill",color);
});
});
});
});
每日赛程的编写,通过select
和option
构成选择框进行筛选赛程,给出日期后,后面的数据通过JavaScrip
交互填充,也是通过表格编写。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>每日赛程</title>
<link rel="stylesheet" type="text/css" href="../css/daily.css" />
<script type="text/javascript" src="../js/daily.js"></script>
</head>
<body>
<div ><img id="winterimg" src="..\image\head.jpg" /> </div>
<div id="nav">
<a class="headnav" href="daily.html">每日赛程</a>
<a class="headnav" href="medals.html">奖牌榜</a>
<a class="headnav" href="map.html">奖牌地图</a>
<a class="headnav" href="index.html">关于冬奥</a>
</div>
<div id="search">
<div class="cx">
<select id="matchtime">
<option value ="0">选择比赛日期</option>
<option value ="2">2月2日</option>
<option value="3">2月3日</option>
<option value="4">2月4日</option>
<option value="5">2月5日</option>
<option value="6">2月6日</option>
<option value="7">2月7日</option>
<option value="8">2月8日</option>
<option value="9">2月9日</option>
<option value="10">2月10日</option>
……
</select>
<button class="btsearch" type="button" onclick="showSite(21)">查询</button>
</div>
<div class="cx">
<select id="matchname">
<option value ="0">选择比赛项目</option>
<option value ="1">高山滑雪</option>
<option value="2">雪车</option>
<option value="3">冬季两项</option>
<option value="4">越野滑雪</option>
<option value="5">冰壶</option>
<option value="6">自由式滑冰</option>
<option value="7">花样滑冰</option>
<option value="8">冰球</option>
<option value="9">雪橇</option>
……
</select>
<button class="btsearch" type="button" onclick="showSite(22)">查询</button>
</div>
<div class="cx">
<select id="matchaddr">
<option value ="0">选择比赛场馆</option>
<option value ="1">国家体育场</option>
<option value="2">首钢滑雪大跳台</option>
<option value="3">首都体育馆</option>
<option value="4">国家游泳中心</option>
……
</select>
<button class="btsearch" type="button" onclick="showSite(23)">查询</button>
</div>
</div>
<div><h1>每日赛程</h1></div>
<div >
<table id="a">
<td><a class="date" herf="#" id="0202" onclick="showSite(2)">2月2日 周三</button></td>
<td><a class="date" herf="#" id="0203" onclick="showSite(3)">2月3日 周四</button></td>
……
</table>
</div>
<div>
<table id="mes" >
<tr id="tbtitle">
<th class="time">时间</th>
<th class="type">大项</th>
<th class="match">比赛</th>
<th class="addr">场馆</th>
<th class="state">比赛状态</th>
<th class="data">数据</th>
</tr>
</table>
</div>
<div id="show">
<table id="xxmes">
</table>
</div>
</body>
</html>
每日赛程的交互编写,通过XMLHttpRquest
发起get请求给对应的php,将请求参数直接写在URL的尾部传输,通过正确的识别码以及返回数据,将html加入尾部,即填充表格的内容。
function showSite(str)
{
var stime = document.getElementById("matchtime").value;
var sname = document.getElementById("matchname").value;
var saddr = document.getElementById("matchaddr").value;
if (str=="")
{
document.getElementById("xxmes").innerHTML="";
return;
}
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("xxmes").innerHTML=xmlhttp.responseText;
}
}
if(str<=20)
xmlhttp.open("GET","../php/detail.php?q="+str,true);
else if(str==21)
{
xmlhttp.open("GET","../php/detail.php?q="+str+"&&stime="+stime,true)
}
else if(str==22)
{
xmlhttp.open("GET","../php/detail.php?q="+str+"&&id="+sname,true)
}
else if(str==23)
xmlhttp.open("GET","../php/detail.php?q="+str+"&&saddr="+saddr,true);
xmlhttp.send();
}
其他主要页面也主要是通过表格的形式编写,此处不再赘述
7.2 后端重要代码
获取奖牌榜,mysqli
与数据库连接,编写所需要查询数据的对应sql语句(以一定顺序排序),然后将读取到的数组用json_encode
打包发送给前端。
<?php
require('config.php');
header('Content-Type:application/json; charset=utf-8');
$db = new mysqli($db_host, $db_username, $db_password, $db_database);
if (mysqli_connect_errno()) {
echo '错误: 无法连接到数据库. 请稍后再次重试.';
exit;
}
$db->query("SET NAMES utf8");
$result=$db->query("select * from total order by rank");
$total=$result->fetch_all();
echo json_encode($total);
?>
获取赛程数据,mysqli
与数据库连接,通过超级全局变量_GET,先判断传来的参数,根据参数编写所需要查询数据的对应sql语句(以一定顺序排序),然后遍历读取到的数组向前端传递对应的标签元素。
<?php
$q = isset($_GET["q"]) ? intval($_GET["q"]) : '';
$con = mysqli_connect('localhost','root','');
if (!$con)
{
die('Could not connect: ' . mysqli_error($con));
}
// 选择数据库
mysqli_select_db($con,"dbtest");
// 设置编码,防止中文乱码
mysqli_set_charset($con, "utf8");
if($q<=20)
{
$sql="SELECT * FROM game WHERE day = '".$q."'"." order by time";
}
else if($q===21)
{
$stime = isset($_GET["stime"]) ? intval($_GET["stime"]) : '';
$sql="SELECT * FROM game WHERE day = '".$stime."'"." order by time";
}
else if($q===22)
{
$id = isset($_GET["id"]) ? intval($_GET["id"]) : '0';
$sql="SELECT * FROM game WHERE nameid = '".$id."'"." order by time";
}
else if($q===23)
{
$saddr = isset($_GET["saddr"]) ? intval($_GET["saddr"] ): '';
$sql="SELECT * FROM game WHERE saddr = '".$saddr."'"." order by time";
}
$result = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($result))
{
echo "<tr>";
echo '<td class="time">' . $row['time'] . "</td>";
echo '<td class="type">'. $row['type'] . "</td>";
echo '<td class="match">' . $row['match'] . "</td>";
echo '<td class="addr">' . $row['addr'] . "</td>";
echo '<td class="state">已结束</td>';
if($row['match'] == '开幕式' || $row['match'] == '闭幕式')
echo '<td class="data"></td>';
else
{
if($row['time']=='20日09:05' && $row['type']=='冰壶')
echo '<td class="data"><a href="curling.html">成绩公报</a></td>';
else if($row['time']=='04日12:10' && $row['addr']=='五棵松体育中心')
echo '<td class="data"><a href="hockey.html">成绩公报</a></td>';
else if($row['time']=='07日12:00' && $row['type']=='高山滑雪')
echo '<td class="data"><a href="slide.html">成绩公报</a></td>';
else
echo '<td class="data"><a herf="#">成绩公报</a></td>';
}
echo "</tr>";
}
mysqli_close($con);
?>
8、结对情况
8.1 小组成员
221900112 林建辉
221900104 陈少峰
8.2 结对讨论过程描述
见6.1如何设计
跳转
8.3 讨论截图
9、心路历程和收获/评价结对队友
9.1 心路历程和收获
林建辉:平时都是习惯了一个人完成任务,由于是自己的东西,经常会有点小拖拉。但是通过结对的形式完成任务,总是会想着要好好做,不能拖对方的后腿,这是我们两个人的事,通过这一点还是能够激励我做事情的,尤其是在自己快要开始想要摆烂的状态。接着就是我的主动有效沟通还是比较少,在结对中处于较为被动的那方,没有什么主见,所以冲突也比较少嘿嘿?但可能这样也并不是很好,适当的“激烈”讨论可能能带来更好的效果,希望要吸取这个教训,在后面的团队作业和未来的团队工作中多站出来,发表自己的意见,给团队带来更多的选择和方向。
陈少峰:对于这一次的结对作业,首先是对于团队合作有了更近一步的理解,当自己一个人进行编写程序,开发时,可以按照自己的风格去进行编写代码,使用自己所擅长的工具等。在结对作业中,最重要的是沟通,良好的沟通是成功的一半,需要在程序开始时,与队友进行沟通洽谈,制定好一系列的计划以及规范,这样能够更有助于整体进度的推进。同时,在面对程序BUG或者有些不是很明确的编程目标时,可以进行沟通,加强理解,从而达到1 + 1 > 2的一个效果。
9.2 相互评价
林建辉(对陈少峰):哈哈!首先当然是要感谢队友的两次作业配合,收获很足,相比于对方来说,我还是比较被动的,队友的积极性非常高,每次不用我说就会主动来找我分析任务、沟通遇到的问题、询问彼此的进度。并且很有自己的想法,总是能提出一些我想不到的点,让我眼前一亮还能这么做。个人的安排妥当且效率高,完成这一项需要多少时间总能按时保质的完成,不会拖拉,也不会消极对待问题,在遇到自己技术上的困难时,尤其是在环境的配置、项目的部署,会不厌其烦的去调试,不断的经历失败,最后得到成果,这点很值得我学习。
陈少峰(对林建辉):首先,非常荣幸能够跟小林成为队友,并共同完成这次的结对作业,在结对作业一、二中,我们都能够很好的进行沟通,并且能够进行良好的讨论,达成共识。合作期间没有发生过较为偏执的争论,这对于团队合作起着一个良性的促进作用。在整个过程中,他能够高效高质量的完成我们一开始制定的分工,同时在我有疑惑等,能够给予我一些建议,让我能够顺利解决我的分内之事。他的身上有着很多的闪光点值得我去学习,人生路漫漫,且行且学习。