结对第二次作业——编程实现
| 这个作业属于哪个课程 | 2401_CS_SE_FZU |
|---|---|
| 这个作业要求在哪里 | 结对第二次作业——编程实现 |
| 结对学号 | 222200234 222200404 |
| 这个作业的目标 | 基于Web技术的原型结对实现,项目部署 |
| 其他参考文献 | 《构建之法》 |
目录
- 1、项目地址
- 1.1 git仓库链接
- 1.2 代码规范链接
- 1.3 部署链接
- 2、PSP表格
- 3、成品展示
- 3.1 首页
- 3.2 奖牌榜
- 3.3 每日赛程
- 3.4 比赛详情
- 3.4.1 赛程详情
- 3.4.2 出赛名单
- 3.4.3 比赛过程详情
- 3.5 对阵图
- 3.6 了解更多
- 4、结对讨论过程
- 4.1 结对讨论截图
- 4.2 结对过程描述
- 5、设计实现过程
- 5.1 功能结构图
- 5.2 分析阶段
- 5.3 设计阶段
- 5.4 实现阶段
- 5.5 遇到的问题及解决方式
- 6、关键代码及思路
- 6.1 后端
- 爬取每日赛程数据
- 加工出赛名单数据
- 6.2前端
- 赛程详情的滚动实现
- 对阵图—国家高亮显示
- 7、心路历程和收获
- 8、评价结对队友
1、项目地址
1.1 git仓库链接
1.2 代码规范链接
1.3 部署链接
http://1.94.207.111:8801/#/home
2、PSP表格
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时 (分钟) |
|---|---|---|---|
| Planning | 计划 | 60 | 40 |
| • Estimate | • 估计这个任务需要多少时间 | 60 | 40 |
| Development | 开发 | 2650 | 2940 |
| • Analysis | • 需求分析(包括学习新技术) | 420 | 480 |
| • Design Spec | • 生成设计文档 | 30 | 30 |
| • Design Review | • 设计复审 | 60 | 40 |
| • Coding Standard | • 代码规范(为目前的开发制定合适的规范) | 60 | 30 |
| • Design | • 具体设计 | 400 | 420 |
| • Coding | • 具体编码 | 1200 | 1400 |
| • Code Review | • 代码复审 | 240 | 240 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 240 | 300 |
| Reporting | 报告 | 240 | 300 |
| • Test Report | • 测试报告 | 120 | 180 |
| • Size Measurement | • 计算工作量 | 20 | 20 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 100 | 100 |
| 合计 | 2950 | 3280 |
3、成品展示
3.1 首页
首页采取自己实现的轮播图展示奥运会标志性图片。导航栏提供奖牌榜、每日赛程、了解更多的入口。

3.2 奖牌榜
奖牌榜界面完成对奖牌的排名,展示各国所获金牌、银牌、铜牌的数量及总数。可滚动查看。

3.3 每日赛程
设有日期下拉框,滚动并点击日期,实现日期切换功能,查询该日期的赛程信息;

点击具体赛程信息,可查看具体比赛详情。(3.4)

3.4 比赛详情
3.4.1 赛程详情
可进行组别的切换来查看不同组别赛程

3.4.2 出赛名单
展示此场比赛双方国家出赛运动员名单,位置等信息

3.4.3 比赛过程详情
展示了具体比赛过程的情况,可通过点击分别查看上下半场的详情。
再次点击即可收起上下半场详细信息。

3.5 对阵图
通过比赛详情中部导航栏,分别选择查看男子足球对阵图或女子足球对阵图。

3.6 了解更多
向用户科普了一些奥运知识,如巴黎奥运会举办背景、吉祥物及会徽。
添加了相应的超链接以便用户了解更多。

4、结对讨论过程
4.1 结对讨论截图



4.2 结对过程描述
拿到题目后,首先通过讨论,确定具体技术路线。我们采用Vue作为前端的主要框架,Python作为后端(爬取数据同时传输数据)进行开发。接着由刘嘉榕同学起型,开始搭建项目框架,以及配置好各种需要用到的环境和依赖和必要的函数,并配置好git仓库,便于后续协作。
再往后我们采用线上+线下的方式进行开发协作。分工协作部分主要体现在不同页面的内容和博客撰写,其中马思敏同学负责首页轮播、奖牌榜、对阵图部分界面设计和博客主要内容的撰写;刘嘉榕同学负责每日赛程,初赛名单,了解更多界面设计,后端,对接,部署和博客界面展示、思路过程等撰写。
主要遇到的问题为数据问题,我们爬取相应的数据,后端处理后返回给前端;这部分需要极大的耐心和细心进行分析。虽然过程比较艰辛,但是总体的合作讨论紧密高效,较高质量完成作业任务。
5、设计实现过程
5.1 功能结构图

5.2 分析阶段
在项目的初始分析阶段,明确了系统需要满足的功能要求:主要展示奥运会相关的信息,包括奖牌榜、每日赛程和详细赛程。因此,首先需要获取相应的数据,然后需要处理大量的数据文件,并动态加载不同日期或赛事的详细信息。
5.3 设计阶段
项目的设计围绕Vue 框架展开,遵循组件化和模块化的设计思想。系统的每个功能模块(如奖牌榜、对阵图)都设计为独立的Vue组件,以便于维护和扩展。
关键设计点:
组件化设计:系统的功能模块,如奖牌榜、每日赛程、详细赛程和对阵图,均设计为独立的Vue组件。这种设计不仅提高了代码的组织性,也便于未来的维护和扩展。
组件复用:为了提高开发效率和减少代码冗余,我们对Nav导航栏和banner每日赛程展示框等在多个页面中重复使用的组件进行了提取和封装。这样的复用策略不仅简化了开发流程,也使得界面的一致性得到了保障。
动态数据加载:利用Vue的watch特性,我们实现了对日期变化的监听,从而动态加载相应日期的赛程信息。这种即时渲染机制确保了用户界面能够根据用户的选择快速响应,提升了用户体验。
Vuex状态管理:为了更好地管理全局状态,我们采用了Vuex。通过Vuex,我们能够集中管理和保存全局状态,如当前活跃页面(activePage)和奖牌榜(medals)。activePage有助于跟踪和管理用户的导航路径,而medals则在首次从后端获取数据后存储起来,避免了不必要的重复请求,提高了应用的性能。
5.4 实现阶段
为了满足用户对巴黎奥运会比赛结果的查询需求,我们计划开发一个高效、直观的前后端分离Web应用。以下是项目的详细规划:
技术栈:
- 前端:使用Vue.js框架构建用户界面和交互,提供动态和响应式的用户体验。
- 后端:采用Python语言配合Tornado框架开发RESTful API,确保服务的高性能和异步处理能力。
- 数据爬取:利用Selenium和Requests库进行数据爬取,以模拟用户行为和发送HTTP请求。
- 数据处理:通过Pandas库进行数据处理,确保数据的准确性和可用性。
- 数据交互:使用Axios和WebSocket技术在前后端之间实时传递数据。
功能特点:
- 奖牌榜展示:用户可以查看实时更新的奖牌榜,了解各国在奥运会上的表现。
- 特定日期比赛结果查询:用户可以通过选择日期来查询特定日期的比赛结果。
- 数据准确性:通过自动化爬虫定期更新数据,结合人工审核机制,确保数据的准确性。:利用Selenium和Requests库进行数据爬取,以模拟用户行为和发送HTTP请求。
5.5 遇到的问题及解决方式
- 问题:由于CSS样式冲突,导致布局错乱
解决方式:使用浏览器的开发者工具检查元素,找出导致布局问题的CSS规则,并进行相应的调整。使用媒体查询和灵活的布局模式(如Flexbox或Grid)来实现响应式设计。
- 问题:动态网页的数据加载通常依赖于JavaScript,这可能导致爬虫无法一次性获取所有数据,或者数据加载速度慢。
解决方式:使用像Selenium这样的工具来模拟浏览器行为,以便能够执行JavaScript并获取动态生成的内容。 对于数据加载慢的问题,可以在爬虫中设置适当的等待时间,或者使用异步加载技术来优化数据获取过程。
考虑使用API(如果可用)来获取数据,这通常比爬取网页更可靠、更高效。
- 问题:git无法将本地仓库的更改推送到远程仓库
解决方式:未得到解决,已使用git remote -v命令查看远程仓库的地址正确,且有足够的权限将更改推送到远程仓库。但在git push时出现错误。尝试了多种方法,都无法解决问题。
6、关键代码及思路
6.1 后端
爬取每日赛程数据
这个页面数据都是动态加载的,所以处理相当复杂
def scroll_down(driver, distance):
# 执行 JavaScript 滚动操作,滚动距离是 distance
driver.execute_script(f"window.scrollBy(0, {distance});")
# 等待几秒,确保内容加载
time.sleep(3)
# 创建一个空列表来存储格式化后的数据
formatted_data = []
# 获取当前页面的高度
last_height = driver.execute_script("return document.body.scrollHeight")
scroll_distance = last_height // 6 # 每次滚动页面的 1/6 高度
container = driver.find_element_by_class_name("ribbon-bg-container")
print(container)
items = driver.find_elements_by_tag_name("a")
cards = []
for item in items:
card = {}
head = item.find_element_by_class_name("score-header").text.strip()
countries_ele = item.find_elements_by_class_name("score-line d-flex flex-row ")
countries = []
for country in countries_ele:
countries.append( country.text.strip())
footer = item.find_element_by_class_name("card-footer").text.strip()
card["head"] = head
card["countries"] = countries
card['footer'] = footer
cards.append(card)
print(card)
加工出赛名单数据
使用正则表达式匹配
def get_player(country1, country2):
import re
# 初始化一个空列表来存储解析后的事件
events = []
up_events = []
down_events = []
# 读取文件
filename = "./data/" + country1 + "&" + country2 + ".txt"
with open(filename, 'r', encoding='utf-8') as file:
# 初始化变量
event = {}
time = None
scores = []
countries = []
players = []
situations = []
real_time = None
for line in file:
line = line.strip()
# 检查时间行
if line.startswith('上半场') or line.startswith('上半场结束'):
continue
if line.startswith('比赛开始'):
up_events = events
events = []
continue
if line.startswith('下半场') or line.startswith('比赛'):
continue
if line.startswith('下半场开始'):
down_events = events
events = []
if re.match(r"(\d+\'\s*\+\d*)|(\d+\')", line) or re.match(r"(\d+-\d+)", line):
if time is None:
# 保存上一个事件
if countries and players and situations:
event["time"] = real_time
event["scores"] = scores
event["countries"] = countries
event["players"] = players
event["situations"] = situations
events.append(event)
# 初始化新事件
event = {}
time = None
scores = []
countries = []
players = []
situations = []
time = line
else:
time += line
else:
if time:
real_time = time
time = None
if line.isdigit():
scores.append(int(line))
elif line:
player_match = re.match(r'(\w+\s\w+)', line)
if player_match:
players.append(player_match.group(1))
continue
situation_match = re.match(
r"(犯规|被犯规|射门|被守门员扑救|黄牌|换人|越位|点球射门|核查是否判罚点球|未犯规|有可能犯规|射门未中|角球|直接任意球(射门)|未中|助攻)",
line)
if situation_match:
situations.append(situation_match.group(1))
continue
country_match = re.match(r'(\w+)', line)
if country_match:
countries.append(country_match.group(1))
continue
for up in up_events:
print(up)
for down in down_events:
print(down)
return up_events, down_events
6.2前端
赛程详情的滚动实现
methods: {
showEvent(group){
this.activeGroup = group;
},
scrollLeft() {
if (this.scrollPosition > 0) {
console.log(this.scrollPosition)
this.scrollPosition -= 0.05; // 根据实际的间隙调整步长
}
},
scrollRight() {
if (this.scrollPosition < this.events[this.groups.indexOf(this.activeGroup)].length - 1) {
this.scrollPosition += 0.05;
}
},
}
对阵图—国家高亮显示
<div class="pk-box" style="position: absolute; top: 50px; left: 125px;">
<div class="pk-item" v-bind:class="{ highlighted: highlightedCountry === '法国' }"
@mouseover="highlightCountry('法国')" @mouseleave="highlightCountry(null)">
<img src="..\assets\images\法国.png">
<span class="winner">法国</span>
<span>1</span>
</div>
</div>
data() {
return {
highlightedCountry: null
}
},
methods: {
highlightCountry(countryName) {
this.highlightedCountry = countryName;
}
},
.pk-item.highlighted {
background-color: #8EB1E3;
padding: 5px;
/* 可以添加其他样式,如背景色、阴影等 */
}
7、心路历程和收获
222200234: 在项目开始之前,我对前端开发并不熟悉。因此,我通过在线教程、B站和社区论坛等,了解并初步学习了基础的HTML、CSS、JavaScript和Vue框架。在实践中,我遇到了布局错乱、样式冲突等问题,但通过不断尝试和调整,我逐渐熟悉了前端开发的流程,技巧。除此之外,协作让我认识到了团队合作的重要性。我们相互之间的沟通和协作,使得整个项目能够更加顺利地推进。
222200404: 在这次项目中,我最初认为,尽管界面不多,但带领团队应该是游刃有余的。然而,数据处理方面的挑战远远超出了我的预期,这让我深刻意识到自己的不足和需要提升的空间。这次经历不仅让我认识到了自己在技术深度上的欠缺,也激发了我进一步学习的动力。通过这次实践,我重温了服务器部署的流程,并且对Python的Tornado框架有了更深入的掌握。同时,我也加深了对爬虫技术的理解,并且在前端布局设计方面获得了更为深刻的认识。在这个过程中,我学会了耐心,尤其是在处理复杂的数据时。此外,我也体会到了团队合作的重要性,同伴的支持和帮助在面对挑战时显得尤为宝贵。
8、评价结对队友
222200234 to 222200404
由于我之前未曾涉足实际前端开发工作,嘉榕同学给予了我极大的帮助。他不仅耐心地解答了我众多的疑问,还协助我解决了诸多我自身难以克服的难题。此外,他的积极主动性体现在与我沟通细节上,这无疑确保了作业的顺利完成。222200404 to 2222004234
尽管思敏同学刚开始没有太多基础,但她展现出了极强的学习意愿和勤奋精神。她不仅认真学习新知识,还严格按照我的指导行动,为我提供了实质性的帮助。她的努力和贡献是项目完成不可或缺的一部分。
相关推荐
CISP-CSE注册云安全工程师备考资源包基础教程
随着云计算技术的普及,云安全已成为网络安全领域的核心议题。CISP-CSE(注册云安全工程师)认证由中国信息安全测评中心颁发,旨在培养具备云安全专业知识和实践能力的实战型人才。本教程将结合"CISP-CSE注册云安全工程师备考资源包",系统性地为您梳理云安全的核心知识体系,并提供实战案例分析,助您高效备考。
绘图模拟:在冲动环境中固定时间的示例 附matlab代码.rar
绘图模拟:在冲动环境中固定时间的示例 附matlab代码.rar
基于规则的电动汽车混合能源管理系统,采用MATLAB、Simulink、Simscape Electrical和Stateflow。.zip
1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
完全复现虚拟同步发电机VSG自适应惯量阻尼控制仿真、根轨迹、调节系数对比(Simulink仿真、Matlab代码实现)
内容概要:本文围绕虚拟同步发电机(VSG)的自适应惯量阻尼控制展开深入研究,通过Simulink搭建详细的系统仿真模型,并结合Matlab代码实现控制算法,系统分析了根轨迹特性及不同调节系数对系统动态响应的影响。研究重点在于设计并验证一种能够根据电网频率变化自动调整惯量和阻尼参数的自适应控制策略,有效提升了VSG在面对负载突变或新能源波动时的频率稳定性与抗干扰能力,为高比例可再生能源接入下的电力系统稳定运行提供了关键技术支撑。; 适合人群:具备电力系统分析、自动控制理论及新能源并网技术基础的研究生、科研人员以及从事微电网、分布式能源系统设计与运维的工程技术人员。; 使用场景及目标:①深入理解虚拟同步发电机的工作原理及其在提升电网惯性方面的关键作用;②掌握基于Simulink的电力电子与控制系统建模与仿真方法;③学习并实践惯量和阻尼自适应控制策略的设计流程,通过根轨迹分析手段优化控制器参数,提升系统动态性能。; 阅读建议:建议读者结合所提供的Simulink仿真模型与Matlab代码进行同步操作,重点关注控制器设计逻辑与参数整定过程,通过改变调节系数观察系统响应变化,深化对稳定性判据与控制性能之间关系的理解。
【雷达信号处理】数字下变频(DDC)(Matlab代码实现)
【雷达信号处理】数字下变频(DDC)(Matlab代码实现)内容概要:本文主要介绍了数字下变频(DDC)技术在雷达信号处理中的应用,并提供了基于Matlab的代码实现。DDC作为现代雷达系统中的关键环节,主要用于将高频接收信号转换为便于后续处理的低频或基带信号,从而提高信号处理效率与精度。文中详细阐述了DDC的基本原理,包括混频、低通滤波和抽取等步骤,并通过Matlab代码展示了其实现过程,帮助读者理解如何在实际工程中构建和调试DDC模块。此外,文档还提及该资源属于一个涵盖多个科研方向的技术资料集合,如路径规划、电力系统优化、机器学习、通信系统仿真等,强调借助成熟工具与方法可提升科研效率。 适合人群:具备一定信号处理基础知识和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适用于从事雷达系统设计、通信工程或相关领域研究的人员。 使用场景及目标:① 学习和掌握数字下变频(DDC)在雷达信号处理中的基本原理与实现方法;② 利用Matlab进行算法仿真与验证,辅助完成课程设计、毕业课题或科研项目中的信号处理部分;③ 借助提供的代码框架拓展至其他通信或雷达系统仿真任务中。 阅读建议:此资源以Matlab代码为核心载体,注重理论与实践结合,建议读者在学习过程中同步运行代码并调整参数,观察不同设置对下变频结果的影响,加深对混频泄漏、滤波器设计和采样率变化等问题的理解,从而真正掌握DDC的关键技术细节。


