结对第二次作业-编程实现

这个作业属于哪个课程2302软件工程
这个作业要求在哪里结对第二次作业-编程实现
结对学号<222100302 222100101>
这个作业的目标采用web技术来实现上次作业中原型中的功能,实现一个界面友好的网站。
其他参考文献《构建之法》

1. Gitcode仓库链接和代码规范链接

1.1 Gitcode仓库链接

我们的仓库链接

1.2 代码规范链接

代码规范链接

2. PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
• Estimate• 估计这个任务需要多少时间3030
Development开发15601590
• Analysis• 需求分析 (包括学习新技术)300500
• Design Spec• 生成设计文档6090
• Design Review• 设计复审3040
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)3060
• Design• 具体设计3060
• Coding• 具体编码1000720
• Code Review• 代码复审1030
• Test• 测试(接口测试,修改代码,提交修改)10090
Reporting报告100160
• Test and use Repor• 接口、使用报告60120
• Size Measurement• 计算工作量2020
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划2020
合计16901780

3. 成品展示

网页链接

首页

页面头部包含一个带有Logo和标题的header,以及一个离开的导航栏nav,导航栏链接到不同页面。在header和nav之间有一个带有欢迎信息的div,通过背景色和字体样式突出显示。页面主体部分有一个容器div,内部包含一个轮播图slide,展示多个项目item,通过不同的背景图片和描述信息展示内容。页面采用响应式布局,使元素在不同屏幕大小下可以适应良好。使用了一些CSS动画效果,如文字跳动动画和内容显示动画,增强页面的吸引力和互动性。
首页

选手信息

运动员信息展示页面,包括顶部的带有logo的标题栏、导航栏(默认隐藏)、运动员信息标题部分、以列表形式展示的运动员数据等。页面主题色调为蓝色和白色,整体布局简洁明了,使用了flex布局和斑马线效果优化视觉体验。每位运动员数据以国家、姓名、性别和出生日期等信息呈现,通过异步加载JSON数据实现动态展示运动员信息。整体设计使用户能方便查看运动员信息并跟随简单列表样式浏览。
选手信息

每日赛况

每日赛况页面包括顶部的导航栏、赛程标题部分、日期选择按钮组、每日赛况内容展示区域等。页面主题色调为蓝色和白色,整体布局清晰,使用了阴影、边框和圆角等样式元素增加视觉效果。赛程内容分为不同日期的比赛项目信息,包含比赛类型、进行阶段、比赛时间等信息,还提供了查看详情按钮。整体设计使用户能方便浏览每日赛程信息和选择日期查看相应内容。
每日赛况

详细赛况

详细赛况页面,具有带有logo的标题栏和返回按钮。页面主题色调为蓝色和白色,整体布局简洁明了。运动员数据以表格形式呈现,包括排名、国家代码、姓名、年龄、总积分、距离领先积分等字段。页面中部显示了比赛类型和阶段的标题。用户可以通过返回按钮返回上一页,通过表格清楚地查看运动员数据。整体设计使用户可以快速浏览和了解运动员的相关信息。
请添加图片描述

奖牌榜

页面包含一个带有Logo和标题的header,以及一个水平导航栏nav,导航栏链接到不同页面。页面主体部分包含一个展示奖牌榜信息的div,其中包含一个标题"h2"和一个用来展示图表的div。使用了echarts库来创建奖牌榜图表,并从Medal.json文件中获取奖牌数据进行展示。图表包括了金牌、银牌、铜牌的数据展示,以柱状图形式呈现各个国家的奖牌情况。页面采用响应式设计,使得页面在不同屏幕大小下能够良好展示。页面整体UI设计简洁,颜色搭配清晰,使得用户可以清晰地获取到奖牌榜信息。
奖牌榜

扩展功能:了解更多

了解更多页面是一个展示赛事信息和视频的页面。页面上方有包含logo的标题栏,包括赛事名称和一组导航链接。用户可以通过导航链接访问不同的页面,如首页、选手信息、每日赛况和奖牌榜等。在页面中间是一个3D旋转轮播图,展示不同图片以吸引用户注意。下方有一个视频部分,展示了不同的视频。页面整体设计现代且吸引人,用户可以方便地浏览赛事信息和观看相关视频。
了解更多

4. 结对讨论过程描述

聊天截图
聊天截图

聊天截图

5. 设计实现过程

5.1 功能结构图

功能结构图

5.2 设计实现过程

开发过程中所使用的是node.js和vue。

  • 页面整体结构: 每个页面都包含一个header用于展示Logo和标题,以及一个导航栏nav用于导航到不同页面,除此之外,每个页面还有独特的区块来展示特定内容。
  • 页面动效: 通过JavaScript监听鼠标事件,实现在鼠标悬停时显示导航栏,鼠标移开时隐藏导航栏的效果。
  • 数据展示: 页面涉及展示不同类型的信息,如赛程信息、运动员信息、奖牌榜等,数据通过JSON文件加载并展示在页面上。
  • 页面布局: 根据不同页面的设计需求,使用不同的CSS样式对页面元素进行布局和美化,包括背景图、文字样式、按钮样式等。
  • 页面交互:每日赛况页面中实现了按钮点击事件,根据不同按钮的点击跳转到对应的详细内容页面。
  • 使用Echarts库: 奖牌榜页面使用了Echarts库创建图表来呈现数据,如奖牌榜页面展示各国家的奖牌数据。
  • 3D翻转效果: 借助CSS3的3D效果,在了解更多页面展示了图片的3D翻转效果,增加页面的视觉吸引力。
  • 总结:
    • 整体设计过程通过HTML结构、JavaScript交互逻辑和CSS样式美化,展示了不同页面的内容和特点,提升了用户体验和页面的可读性。
    • 前端主要负责展示页面的内容,包括页面布局、样式设计、交互效果等,使用Vue框架实现了动态数据绑定、路由导航等功能。
    • 后端则主要负责数据的处理和提供接口供前端调用,包括提供运动员信息的JSON数据、奖牌榜信息的JSON数据、每日赛程数据等,使前端能够动态展示相关内容。

6. 代码说明

1.AthletesPage.vue

我们基于 Vue 3 的组件,使用了 Vue 3 的 Composition API,实现了一个页面组件,包括了页面的结构、交互逻辑和样式定义。通过 Vue 3 的 Composition API,实现了组件的数据响应和逻辑处理。。<template> 部分包含页面的 HTML 结构,包括页面的头部、导航、选手信息以及相关样式。<script setup> 部分使用了 Vue 3 的 <script setup> 语法糖,可以简化 Vue 组件的写法。在这里,它包含了组件的逻辑部分,包括数据处理和事件监听。首先,从 Vue 中引入了 ref 和 onMounted。ref 用于创建响应式数据,onMounted 用于在组件挂载后执行某个函数。创建了一个 athletes 的响应式数据,用于存储运动员信息。在 onMounted 钩子中,注册了一些事件监听,当鼠标移动到头部标题(ID 为 "tournament")上时,显示导航栏(ID 为 "nav"),移出时隐藏导航栏。导航栏的显示和隐藏是通过改变其 style.display 属性实现的。通过 fetch 方法获取了一个 JSON 文件 /athletes.json 中的数据,对数据进行处理后存储在 athletes 中。<style scoped> 部分定义了组件的样式,其中包括页面布局、字体样式、颜色等。部分样式是针对特定的元素或类进行定义的,以确保样式的局部性。
<template>
  <header>
      <img src="../assets/logo.png" alt="Logo" class="small-logo">
      <h1 id="tournament">TOURNAMENT</h1>
  </header>
  <nav style="display: none;">
      <a href="FirstPage">首页</a> <!-- 指向主页 -->  
      <a href="AthletesPage" style="text-shadow: 2px 2px 4px #9ec4ec;">选手信息</a> <!-- 指向运动员页面 -->
      <a href="SchedualPage">每日赛况</a> <!-- 指向每日赛况页面 -->
      <a href="MedalPage">奖牌榜</a> <!-- 指向奖牌榜页面 -->  
      <a href="MorePage">了解更多</a> <!-- 指向了解更多页面 --> 
  </nav>
  <div id="Athletes">
      <h2>Athletes</h2>
  </div>
  <div id="message">
      <ul id="athletesList">  
          <!-- 添加标题行 -->  
          <li class="header">  
              <div>Country</div>  
              <div>Athlete</div>  
              <div>Gender</div>  
              <div>DOB</div>  
          </li>  
          <!-- 运动员列表项 -->  
          <li v-for="(athlete, index) in athletes" :key="index">  
              <div>{{ athlete.country }}</div>  
              <div>{{ athlete.fullName }}</div>  
              <div>{{ athlete.gender }}</div>  
              <div>{{ athlete.dob }}</div>  
          </li>  
      </ul>  
  </div>
</template>
  
<script setup>
import { ref, onMounted } from 'vue';

const images = ref(null);
let currentIndex = 0;
let intervalId;

onMounted(() => {
  const tournament = document.getElementById("tournament");
  const nav = document.querySelector("nav");
  const slideshow = document.getElementById("slideshow");

  tournament.addEventListener("mouseover", function() {
    nav.style.display = "block";
    nav.addEventListener("mouseover", function() {
      nav.style.display = "block";
    });
    nav.addEventListener("mouseout", function() {
      nav.style.display = "none";
    });
  });

  tournament.addEventListener("mouseout", function() {
    nav.style.display = "none";
  });
});

const athletes = ref([]);

fetch('/athletes.json')
  .then(response => response.json())
  .then(data => {
    data.forEach(user => {
      user.Participations.forEach(participation => {
        const fullName = participation.PreferredFirstName ? `${participation.PreferredFirstName} ${participation.PreferredLastName}` : participation.PreferredLastName;
        const gender = participation.Gender === 0 ? 'Male' : 'Female';
        const dob = new Date(participation.DOB).toLocaleDateString('en-US');

        athletes.value.push({
          country: user.CountryName,
          fullName,
          gender,
          dob
        });
      });
    });
  })
  .catch(error => {
    console.error('Failed to fetch JSON:', error);
  });

2.SchedualPage.vue

我们实现了一个赛程页面组件,包括了日期选择按钮和每日赛况的展示区域,以及相应的事件处理逻辑和页面跳转功能。,我们看到了 <template> 部分的内容,这部分主要描述了页面的结构,包括头部、导航栏、赛程信息展示区域等。其中:头部包括了一个图像标志和一个标题 "TOURNAMENT"。导航栏包含了几个链接,分别指向不同的页面,如主页、选手信息、每日赛况、奖牌榜和了解更多。<div id="Schedual"> 标签下是每日赛况的展示区域,其中包含了日期选择按钮和每日赛况的主要内容区域。日期选择按钮使用了 Element UI 的 <el-button> 组件,每个按钮上附带了一个日期,点击按钮可以显示对应日期的赛况信息。主要内容区域使用了 Element UI 的 <el-card> 组件,每个卡片展示了一场比赛的相关信息,包括比赛类型、是否结束、比赛时间等。在每个卡片的底部有一个按钮 "查看详情",点击该按钮可以跳转到详细赛况页面。接着,在 <script> 部分:使用了 onMounted 钩子来监听页面加载完成事件,当页面加载完成后,为标题 "TOURNAMENT" 添加了鼠标悬停事件的监听器,以控制导航栏的显示与隐藏。导出了一个对象,包含了组件的一些属性和方法:name 属性指定了组件的名称为 "SchedulePage"。components 属性为空,表示该组件不包含其他子组件。computed 属性包含了一个计算属性 content,根据 message 的值来决定返回哪个日期对应的赛程信息,以实现日期按钮的切换功能。methods 属性包含了两个方法:setMessage(value) 方法用于设置当前选中的日期,参数 value 为日期的序号。toDetails(panel) 方法用于跳转到详细赛况页面,它将选中比赛的类型和场次存储在 localStorage 中,并通过路由跳转到名为 "DetailsPage" 的页面。
<template>
  <header>
    <img src="../assets/logo.png" alt="Logo" class="small-logo">
    <h1 id="tournament">TOURNAMENT</h1>
  </header>
  <nav>
    <a href="FirstPage">首页</a> <!-- 指向主页 -->  
    <a href="AthletesPage">选手信息</a> <!-- 指向运动员页面 -->
    <a href="SchedualPage" style="text-shadow: 2px 2px 4px #9ec4ec;">每日赛况</a> <!-- 指向每日赛况页面 -->
    <a href="MedalPage">奖牌榜</a> <!-- 指向奖牌榜页面 -->  
    <a href="MorePage">了解更多</a> <!-- 指向了解更多页面 --> 
  </nav>
  <div id="Schedual">
    <h2>Schedual</h2>
  </div>

  <!--  -->
  <div id="daily" style="text-align:center; margin-top: 40px;">
    <el-row class="buttonGroup" style="height: 80px;margin: 20px auto">
      <el-button round @click="setMessage(1)" :class="{ 'clickedButton': message === 1 }" class="dayButton">Thursday 18th January</el-button>
      <el-button round @click="setMessage(2)" :class="{ 'clickedButton': message === 2 }" class="dayButton">Friday 19th January</el-button>
      <el-button round @click="setMessage(3)" :class="{ 'clickedButton': message === 3 }" class="dayButton">Saturday 20th January</el-button>
      <el-button round @click="setMessage(4)" :class="{ 'clickedButton': message === 4 }" class="dayButton">Sunday 21st January</el-button>
    </el-row>

    <!-- 每日赛况主要内容区域 -->
    <div class="mainContent" style="margin: 0 auto;width: 900px;margin-top: 70px;">
      <el-card class="box-card" v-for="(item, index) in content" :key="index"
        style="margin: 10px 10px;display: inline-block;width: 400px; border-radius: 30px">
        <el-row :gutter="10">
          <el-col class="show" :span="14">
            <!-- 比赛类型 -->
            <strong>{{ item.type }}</strong>
            <br>
          </el-col>
          <el-col class="show" :span="5" :offset="3">
            <strong>Complete</strong>
            <br>
            <!-- 比赛时间 -->
            <span class="text">{{ item.time }}</span>
          </el-col>
        </el-row>
        <hr class="divide">
        <el-row :gutter="10">
          <!-- <el-col :span="2">
            <img :src="item.playimg" class="playIcon" />
          </el-col> -->
          <!-- 比赛场次 -->
          <!-- 动态绑定 -->
          <el-col class="show" :span="7" :offset="2" :class="{ 'gold': item.play === 'Finals' }">
            {{ item.play }}
          </el-col>
        </el-row>
        
        <hr class="divide">
        <!-- 跳转到详细赛况 -->
        <el-row>
          <el-button round class="more" @click="toDetails(item)">查看详情</el-button>
        </el-row>
      </el-card>
    </div>
  </div>
</template>


<script>
import { ref, onMounted } from 'vue';

onMounted(() => {
  const tournament = document.getElementById("tournament");
  const nav = document.querySelector("nav");
  const slideshow = document.getElementById("slideshow");

  tournament.addEventListener("mouseover", function() {
    nav.style.display = "block";
    nav.addEventListener("mouseover", function() {
      nav.style.display = "block";
    });
    nav.addEventListener("mouseout", function() {
      nav.style.display = "none";
    });
  });

  tournament.addEventListener("mouseout", function() {
    nav.style.display = "none";
  });
});

export default {
  name: "SchedulePage",
  components: {  },
  computed: {
    content() {  
      switch (this.message) {  
        case 1: return this.content1;  
        case 2: return this.content2;  
        case 3: return this.content3;  
        case 4: return this.content4; 
        default: return null; // 或者返回某个默认值或执行其他逻辑  
      }  
    }
  },
  methods: {
    // 传递消息方法
    setMessage(value) {
      this.message = value
    },
    
    // 跳转到详细界面方法
    toDetails(panel) {
      localStorage.setItem('detailType', panel.type);
      localStorage.setItem('detailPlay', panel.play);
      this.$router.push({ name: 'DetailsPage' });
    }
  },

3.Router

我们配置了一个路由器,用于创建应用程序的路由。首先导入了 createRouter、createWebHistory 以及 RouteRecordRaw 三个函数或类型,这些都是从 Vue Router 中导入的。routes 是一个数组,包含了应用程序的所有路由信息。每个路由对象都描述了一个路径 (path),路由的名称 (name),以及路由对应的组件 (component)。每个路由对象的 component 属性都是一个函数调用,这个函数调用返回了一个动态导入的组件。这种方式可以实现懒加载,即在需要时再加载对应的组件,而不是一开始就加载所有组件。注释 webpackChunkName 指定了生成的 chunk 的名称。创建了路由对象 router,通过调用 createRouter 函数,传入了一个配置对象,其中包含了路由的模式 (history) 和定义的路由数组 (routes)。最后通过 export default router 导出了创建的路由对象,以便在应用程序的入口文件中使用。综上所述,这段代码配置了一个基于 Vue Router 的路由器,定义了应用程序中的所有路由信息,并创建了一个路由对象供应用程序使用。
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/FirstPage'
    
  },
  {
    path: '/FirstPage',
    name: 'FirstPage',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/FirstPage.vue')
  },
 
  {
    path: '/AthletesPage',
    name: 'AthletesPage',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AthletesPage.vue')
  },
  {
    path: '/MorePage',
    name: 'MorePage',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/MorePage.vue')
  },
  {
    path: '/SchedualPage',
    name: 'SchedualPage',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/SchedualPage.vue')
  },
  {
    path: '/MedalPage',
    name: 'MedalPage',
    
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/MedalPage.vue')
  },
  {
    path: '/DetailsPage',
    name: 'DetailsPage',
    
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/DetailsPage.vue')
  }

]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

7. 心路历程和收获

  • Y同学: 在软件开发的道路上,每一次项目都是一次宝贵的经历。我们深有感触地体会到了框架的强大之处,它可以大大提高项目开发的效率,让我们见识到了自己还有许多需要学习和提升的地方,不过因为时间比较赶,对框架的理解和掌握能力还远远不够,需要继续提升自己的专业素养。其次,对git的使用还需要更为熟练地掌握,比如这次如何新建分支,共同在分支上合作写代码耗费了我们很长时间。
  • L同学: 团队合作也是我们在这次实践中学到的重要一课。有效的沟通和合作可以帮助团队更好地解决问题,确保项目的成功。总的来说,软件工程实践需要不断学习和改进,每一次的实践都是一次宝贵的经验,让我们明白了自己的不足之处,并激励继续努力学习,不断提升自己的能力。在未来的路上,我会继续努力,不断前行,只有不断学习和实践,才能成为一名真正优秀的软件工程师。

8. 评价结对队友

L->Y:这次的作业我们深刻反思了上次团队作业中的不足,共同商讨并积极改进。在遇到困难时,大家都能够积极面对,没有互相指责,我觉得小杨同学是一个值得信赖的队友,她的专业素养和积极态度都让人印象深刻。

Y->L:针对上次作业中暴露出的问题,我们在这次作业中进行了深入的讨论和改进。面对挑战,我们都能够齐心协力,共同应对,我认为小L同学是一个非常出色的合作伙伴,她的创新思维和高效执行力让我受益匪浅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值