软件工程实践结对作业二

这个作业属于哪个课程<2022年福大-软件工程、实践-W班>
这个作业要求在哪里<软件工程实践结对作业二>
结对学号<221900112、221900104>
这个作业的目标<实现冬奥栏目原型中的功能、项目部署、结对合作>
其他参考文献见文章末尾


1、Gitcode仓库地址

我们的Gitcode仓库地址


2、代码规范地址

我们的代码规范地址


3、项目成果地址

我们的项目结果地址


4、PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
• Estimate• 估计这个任务需要多少时间3030
Development开发900993
• Analysis• 需求分析105
• Technology selection• 技术选择(包括学习)5065
• Code specification• 代码规范制定2030
• Front End前端
• Head• 网页首部1513
• Home Page• 首页90105
• Medal List• 奖牌榜6045
• Schedule• 赛程榜8095
• Map• 地图150160
• Expand• 拓展项目150160
• Back End后端
• Database• 数据库设计与导入3025
• Medal Data• 奖牌相关数据3540
• Schedule Data• 赛程相关数据4040
• Other Data• 拓展相关数据2030
• Other其他
• Revise• 整体完善和测试3030
• Deployment• 项目部署120150
Reporting报告90105
• Writing Repor• 撰写报告6075
• Size Measurement• 计算工作量1010
• Postmortem• 事后总结2020
合计10201128

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用于对国家的颜色进行填充;图例说明也直接通过circletext的组合使用嵌入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);
            });
        });
    });
});

  每日赛程的编写,通过selectoption构成选择框进行筛选赛程,给出日期后,后面的数据通过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 结对讨论过程描述

  

  首先,第一次阅读题目的时候,根据文中 “推荐基于Web来开发” 并且提供了一些参考用的框架,我们讨论了使用何种方法完成,但由于我们俩都没学过这些框架,鉴于上学期yii2框架的“试炼”,在较短时间内学习一个全新的技术,会被奇奇怪怪的配置环境问题给折磨,我们并不想选择这种方式,因此我们选择了用纯前端的方式(HTML+CSS+JS)。但是讨论到赛程筛选的时候,我们发现如果将数据集成在代码中,对于筛选功能并没有什么头绪,并且奖牌榜之类的数据有点长,手动集成有点累。因此我们最后又选择了加上PHP后端的编写,其中数据较多的与后端交互,三个小项目中数据较少的可以用静态方式。而至于用什么环境,我们选择我们彼此都学习过,并且在上学期有实践编写过的Wamp Server集成环境。至此方法讨论完成,进入设计过程 见6.1如何设计 跳转

8.3 讨论截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


9、心路历程和收获/评价结对队友

9.1 心路历程和收获

  林建辉:平时都是习惯了一个人完成任务,由于是自己的东西,经常会有点小拖拉。但是通过结对的形式完成任务,总是会想着要好好做,不能拖对方的后腿,这是我们两个人的事,通过这一点还是能够激励我做事情的,尤其是在自己快要开始想要摆烂的状态。接着就是我的主动有效沟通还是比较少,在结对中处于较为被动的那方,没有什么主见,所以冲突也比较少嘿嘿?但可能这样也并不是很好,适当的“激烈”讨论可能能带来更好的效果,希望要吸取这个教训,在后面的团队作业和未来的团队工作中多站出来,发表自己的意见,给团队带来更多的选择和方向。
  陈少峰:对于这一次的结对作业,首先是对于团队合作有了更近一步的理解,当自己一个人进行编写程序,开发时,可以按照自己的风格去进行编写代码,使用自己所擅长的工具等。在结对作业中,最重要的是沟通,良好的沟通是成功的一半,需要在程序开始时,与队友进行沟通洽谈,制定好一系列的计划以及规范,这样能够更有助于整体进度的推进。同时,在面对程序BUG或者有些不是很明确的编程目标时,可以进行沟通,加强理解,从而达到1 + 1 > 2的一个效果。

9.2 相互评价

  林建辉(对陈少峰):哈哈!首先当然是要感谢队友的两次作业配合,收获很足,相比于对方来说,我还是比较被动的,队友的积极性非常高,每次不用我说就会主动来找我分析任务、沟通遇到的问题、询问彼此的进度。并且很有自己的想法,总是能提出一些我想不到的点,让我眼前一亮还能这么做。个人的安排妥当且效率高,完成这一项需要多少时间总能按时保质的完成,不会拖拉,也不会消极对待问题,在遇到自己技术上的困难时,尤其是在环境的配置、项目的部署,会不厌其烦的去调试,不断的经历失败,最后得到成果,这点很值得我学习。
  陈少峰(对林建辉):首先,非常荣幸能够跟小林成为队友,并共同完成这次的结对作业,在结对作业一、二中,我们都能够很好的进行沟通,并且能够进行良好的讨论,达成共识。合作期间没有发生过较为偏执的争论,这对于团队合作起着一个良性的促进作用。在整个过程中,他能够高效高质量的完成我们一开始制定的分工,同时在我有疑惑等,能够给予我一些建议,让我能够顺利解决我的分内之事。他的身上有着很多的闪光点值得我去学习,人生路漫漫,且行且学习。


10、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值