结对第二次作业——编程实现
| 这个作业属于哪个课程 | 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
尽管思敏同学刚开始没有太多基础,但她展现出了极强的学习意愿和勤奋精神。她不仅认真学习新知识,还严格按照我的指导行动,为我提供了实质性的帮助。她的努力和贡献是项目完成不可或缺的一部分。
相关推荐
JEP30-PX100A PartModel Product Guidelines for Electronic-Device Substrates and Assemblies – XML Requ
JEP30-PX100A PartModel Product Guidelines for Electronic-Device Substrates and Assemblies – XML Requirements
基于Matlab的自动睡眠粒状结构检测算法,从脑电信号中进行。.zip
1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
JEP375 2.5D_3D Silicon thinned wafers with Through Silicon Vias (TSV’s) and Backside Redistribution
JEP375 2.5D_3D Silicon thinned wafers with Through Silicon Vias (TSV’s) and Backside Redistribution Layer (RDL).pdf
考虑供电可靠性与算力柔性的数据中心园区源‑储‑荷一体化规划研究(Matlab代码实现)
考虑供电可靠性与算力柔性的数据中心园区源‑储‑荷一体化规划研究(Matlab代码实现)内容概要:本文围绕“考虑供电可靠性与算力柔性的数据中心园区源-储-荷一体化规划”展开研究,提出了一种综合能源系统优化规划方法。该方法充分考虑数据中心对供电可靠性的高要求以及算力负载的灵活性特征,将电力供应、储能配置与计算负荷进行协同优化。通过建立数学模型,整合光伏发电、储能系统与数据中心负荷调度,利用Matlab代码实现优化求解,旨在提升能源利用效率、降低运营成本并增强系统韧性。研究涵盖了对新能源出力不确定性、负荷波动以及储能动态行为的建模与仿真分析,最终验证了所提一体化规划方案在提高供电可靠性和实现算力资源柔性调度方面的有效性。; 适合人群:具备一定电气工程、能源系统或计算机科学背景,从事数据中心、智能电网、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 为数据中心园区的绿色低碳与高可靠运行提供规划设计方案;② 实现可再生能源的高效消纳与储能系统的优化配置;③ 探索算力作为柔性负荷参与电力系统互动的潜力,支撑新型电力系统建设。; 阅读建议:此资源以Matlab代码为核心,辅以理论模型,建议读者在理解基本原理的基础上,动手运行和调试所提供的代码,通过修改参数和场景设置来深入掌握一体化规划的优化逻辑与关键技术细节。
歌曲爆款传播预测数据集10000首曲目Spotify音频特征机器学习
本数据集为合成音乐数据,包含2010至2025年间10000首曲目的Spotify风格音频特征与明确的爆款(viral)目标标签。现有音乐数据集常缺少可用建模目标或存在授权限制,本数据集提供了干净、字段完整、可直接用于监督学习的基准语料。字段涵盖节奏、能量、可舞性、声学度、效价等音频属性,以及曲目元数据与年份信息,目标列viral基于传播表现定义,可直接用于二分类建模。适合开展爆款歌曲预测、音频特征与传播关系分析、年代音乐风格演变可视化、特征重要性排序等分析任务,也可作为分类、回归与特征工程教学的演示数据。数据结构清晰、无缺失值,适合数据科学课程、音乐媒体分析与推荐算法原型验证使用。


