结对作业二——编程实现

222000331林玥利 学生 2023-03-24 23:34:42
这个作业属于哪个课程2023年福大-软件工程实践-W班
这个作业要求在哪里结对第二次作业——编码实现
结对学号222000334
222000331
这个作业的目标1.fork仓库,使用Git合作完成项目
2.制定代码规范
3.编码实现原型,完成指定功能
4.将项目部署到云服务器
5.撰写博客
其他参考文献VUE官网,
Nodejs官网,
基于 Vue 2.x 的 Element UI,
百度前端代码规范

@

文章目录

  • 1 项目链接
  • 1.1 Gitcode仓库地址
  • 1.2 代码规范地址
  • 1.3 云服务器地址
  • 2 PSP表格
  • 3 项目成果展示
  • 3.1 基础功能
  • 3.1.1 功能1:选手排名
  • 3.1.2 功能2:每日赛况
  • 3.1.3 功能3:晋级图
  • 3.2 附加功能
  • 3.2.1 附加功能1:详细赛况
  • 3.2.2 附加功能2:了解更多(澳网小知识)
  • 3.3 更多功能
  • 3.3.1 首页轮播图展示
  • 3.3.2 首页选手展示效果
  • 4 设计实现过程
  • 4.1 功能结构图
  • 4.2 设计概述
  • 4.3 数据设计
  • 4.3.1 每日赛程数据设计
  • 4.3.2 晋级图数据设计
  • 4.4 遇到的问题与解决办法
  • 5 代码说明
  • 5.1 前端关键代码
  • 5.2 数据获取代码
  • 6 结对讨论过程
  • 7 心路历程和收获
  • 8 结对队友互评

1 项目链接

1.1 Gitcode仓库地址

我们的代码仓库

1.2 代码规范地址

我们的代码规范

1.3 云服务器地址

我们的web项目

2 PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
• Planning• 计划3020
• Estimate• 估计这个任务需要多少时间1010
• Analysis• 需求分析300450
• Development• 开发18001920
•Discussion• 讨论交流6060
• Design Spec• 生成设计文档6090
• Design Review• 设计复审6060
• Coding Standard• 制定代码规范3060
• Coding• 具体编码12001320
• Test• 测试12090
Reporting• 报告120180
• Size Measurement• 计算工作量55
• Postmortem & Process Improvement Plan• 事后总结,, 并提出过程改进计划3030
合计20252375

3 项目成果展示

3.1 基础功能

3.1.1 功能1:选手排名

展示男女Singles Aces leaders排名,排名展示选择斑马纹表格,添加鼠标悬浮变色,方便聚焦浏览信息

在这里插入图片描述

3.1.2 功能2:每日赛况

滑动按钮组选择具体某一天,鼠标悬浮不同颜色凸显,鼠标点击变色

在这里插入图片描述


在这里插入图片描述

3.1.3 功能3:晋级图

在这里插入图片描述


在这里插入图片描述

3.2 附加功能

3.2.1 附加功能1:详细赛况

Day14的第一个赛程的详细赛况

在这里插入图片描述

在这里插入图片描述

3.2.2 附加功能2:了解更多(澳网小知识)

在这里插入图片描述

3.3 更多功能

3.3.1 首页轮播图展示

在这里插入图片描述

3.3.2 首页选手展示效果

在这里插入图片描述

4 设计实现过程

描述设计实现过程,给出功能结构图。

4.1 功能结构图

在这里插入图片描述

4.2 设计概述

数据获取部分

本次作业的Json数据较复杂,各种对象之间存在映射关系不能直接拿到需要的信息。于是根据需要的信息设计新的Json文件格式,通过代码将原Json文件处理成新的数据,直接配置在web项目中,方便前端数据渲染。

在这里插入图片描述

前端渲染页面
负责后端的同学将原本复杂的json数据处理成简单的格式,方便前端渲染。

  • 采用技术:vue,ElementUi...
  • 设计思路:前端部分利用vue脚手架部署项目,主要分为页面布局数据渲染两部分实现。
    • 页面布局:页面布局参照第一次作业的原型设计实现,通过开发者工具测量元素的大小样式,并编写css代码调整样式。其中,表格、轮播图、卡片、选择器、菜单栏、导航栏等内容通过ElementUi实现。通过查阅官网的官方文档编写并修改相应代码。
    • 数据渲染:数据渲染主要通过js编写模板字符串实现,可以动态生成满足要求的HTML代码,并利用innerHTML渲染到dom元素中。

4.3 数据设计

4.3.1 每日赛程数据设计

在这里插入图片描述

4.3.2 晋级图数据设计

在这里插入图片描述

4.4 遇到的问题与解决办法

  • git协同合作
    第一次使用Git协同开发项目,对分支的理解有偏差,实际上每个分支是并行的,没有优先级的概念。基本了解了Git的一些分支操作后,我们创建了三个分支:dev分支用于合并其他分支的代码,我们二人分别在各自的331,334分支进行开发工作,需要合并项目时先切换到dev分支,使用git merge 3331/334来合并项目。最后所有代码完成时切换到master分支,使用git merge dev来获取整个项目。但是由于对Git协同开发不熟悉,导致了一些操作上的不规范,比如没有在约定好的自己的分支上开发;不知道当前是什么分支以至于找不到代码(很慌);push后远程仓库没有变化(vscode自带的Git管理器同步不及时,需要手动刷新);修改代码时没有先同步dev分支,导致合并时报错;编写的文件和已经上传到远程仓库中的代码冲突导致合并冲突等等等等(心累),解决办法就是发生错误时去查看相关技术博客,照着操作,学习了很多git的操作,比如强制推送git push --force,撤销前一次提交git reset --hard HEAD^等等。所以团队开发时一定要规范操作,避免分支管理上的错误造成代码混乱,甚至代码丢失。

开发分支设计图

在这里插入图片描述

相关学习资料: Updates were rejected, Git撤销操作,Git pull/push冲突

  • 云服务器部署问题
    购买云服务器时没有留意系统镜像,选择了windows系统,进行了一次系统的重装。通过远程工具下载宝塔面板后建立站点,一开始用新买的域名建站,可以成功访问,过一会访问就显示域名没有备案(被发现了)。后来发现可以在建站后进行域名管理,添加服务器IP 作为新域名,然后删除之前的域名,这样就可以通过云服务器的IP地址访问项目了。如果默认的端口80被其他程序占用可以在设置域名时设置端口,同时在服务器上开放该端口。还有一点,访问项目时需要使用http协议,通过https协议访问要求网站配置ssl证书(好贵),否则会显示该连接不安全无法访问到项目。HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议

相关学习资料:腾讯云重装系统,无域名建立网站,从购买服务器到网站搭建成功,HTTP 和 HTTPS 的区别

前端问题:

日期切换按钮组

  • 问题描述:想在每日赛程界面设置可以滑动的日期按钮组,但是日期切换按钮组在elementui、bootstrap等一系列组件库中找不到相似组件,不知道如何实现。
  • 解决方案:在网上查阅资料之后发现可以通过设置两个组件层来实现,上一层为显示层,下面一层为滑动层。滑动层中放置14个日前按钮,其长度要比显示层长,然后用overflow:hidden将超出显示层的部分隐藏,即可实现效果。但是学习和实现花了好长的时间。

winner样式加粗

  • 问题描述:题目要求的winner要加粗显示,但是我的html是通过js生成的,不知道该如何添加类。
  • 解决方案:后面翻看了自己的前端笔记,再尝试后发现可以通过if-else判断是否是赢家,然后为是赢家的元素添加winner类。在winner类中编写加粗样式。

    5 代码说明

    5.1 前端关键代码

渲染每日赛程

// 每日赛程
    getResults (e) {
      // 获取results元素
      const results = document.querySelector('.results')
      //获取选择的日期
      this.date = e.currentTarget.firstElementChild.innerHTML
      for (let cout = 0; cout < 18; cout++) {
        if (e.currentTarget.parentNode.parentNode.children[cout].children[0].classList.contains('selected')) {
          e.currentTarget.parentNode.parentNode.children[cout].children[0].classList.remove('selected')
        }
      }
      e.currentTarget.classList.add('selected')
      console.log(e.currentTarget.parentNode.parentNode.children[0].children[0])
      const jsonStr = require(`../../../public/data/${this.date}.json`)
      let htmlStr = ``
      jsonStr.matches.forEach(item => {
        let resultStr = ''
        let firstStr = ''
        let secondStr = ''
        let flag = 0
        遍历teams数组
        item.teams.forEach(item_teams => {
          let playerStr = ``
          let scoreStr = ``
          //如果选手人数为1,则调整名字到中间位置
          if(item_teams.players.length === 1){
            // 遍历players数组
            item_teams.players.forEach(item_players => {
              playerStr += `<div class="player" style="margin-top:12px;">${item_players.short_name}<span>${item_players.nationality}</span></div>`
            })
          } else {
            // eslint-disable-next-line
            item_teams.players.forEach(item_players => {
              playerStr += `<div class="player">${item_players.short_name}<span>${item_players.nationality}</span></div>`
            })
          }
          // 遍历score数组
          item_teams.score.forEach(item_score => {
            scoreStr += `
              <span>${item_score.game}</span>
            `
          })
          //处理winner样式加粗
          if (flag === 0) {
            if (item_teams.is_winner === true) {
              firstStr = '<div class="first winner"><div class="left">' + playerStr + '</div><div class="right">' + scoreStr + '</div></div>'
            } else {
              firstStr = '<div class="first"><div class="left">' + playerStr + '</div><div class="right">' + scoreStr + '</div></div>'
            }
            console.log(firstStr)
          } else {
            if (item_teams.is_winner === true) {
              secondStr = '<div class="second winner"><div class="left">' + playerStr + '</div><div class="right">' + scoreStr + '</div></div>'
            } else {
              secondStr = '<div class="second"><div class="left">' + playerStr + '</div><div class="right">' + scoreStr + '</div></div>'
            }
            console.log(secondStr)
          }
          flag = 1
        })
        // eslint-disable-next-line
        resultStr = firstStr + secondStr + '</el-card>'
        //拼接模板字符串
        htmlStr += `
        <el-card class="box-card is-always-shadow el-card">
        <div class="event">
          <div class="top">
            <span class="title">${item.event_type}</span>
            <span class="status">Complete</span>
          </div>
          <div class="bottom">
            <span class="court"><span>${item.round_type} • </span>${item.court}</span>
            <span class="time">${item.duration}</span>
          </div>
        </div>` + resultStr
        // console.log(playerStr)
      })
      // eslint-disable-next-line
      // console.log(htmlStr);
      //插入模板字符串到dom元素中(results)
      results.innerHTML = htmlStr
    }

晋级图渲染

renderDraws (data) {
        //根据data,得到相应的json文件
      if (data === 'MS') {
        jsonStr = require('../../../public/data/MS.json')
      } else if (data === 'MD') {
        jsonStr = require('../../../public/data/MD.json')
      } else if (data === 'WS') {
        jsonStr = require('../../../public/data/WS.json')
      } else {
        jsonStr = require('../../../public/data/WD.json')
      }
      //以Quarterfinals(四分之一决赛)为例,遍历数据
      jsonStr.Quarterfinals.forEach(item => {
          if (item_teams.players.length === 1) {
          }
          //遍历players数组
          item_teams.players.forEach(item_players => {
            if (item_teams.players.length === 1) {
            //添加winner样式,加粗
              if (item_teams.is_winner === true) {
                playerStr += `
              <div class="player" style="margin-bottom:0px !important;margin-top:13px !important;font-weight:900;">
              <span class="name">${item_players.short_name}</span>
              <span class="guoji">${item_players.nationality}</span>
              </div>
            `
              } else {
                playerStr += `
              <div class="player" style="margin-bottom:0px !important;margin-top:13px !important;">
              <span class="name">${item_players.short_name}</span>
              <span class="guoji">${item_players.nationality}</span>
              </div>
            `
              }
            } else {
              if (item_teams.is_winner === true) {
                playerStr += `
              <div class="player" style="font-weight:900;">
              <span class="name">${item_players.short_name}</span>
              <span class="guoji">${item_players.nationality}</span>
              </div>
            `
              } else {
                playerStr += `
              <div class="player">
              <span class="name">${item_players.short_name}</span>
              <span class="guoji">${item_players.nationality}</span>
              </div>
            `
              }
            }
          })
          //遍历得分数组,渲染数据
          item_teams.score.forEach(item_score => {
            scoreStr += `<span>${item_score.game}</span>`
          })
          if (flag === 0) {
            teamResult1 = '<div class="first"><div class="left">' + playerStr + '</div><div class="right"><span class="score">' + scoreStr + '</span></div></div>'
          } else {
            teamResult2 = '<div class="second"><div class="left">' + playerStr + '</div><div class="right"><span class="score">' + scoreStr + '</span></div></div>'
          }
          flag = 1
        })
        //拼接结果
        quarStr += '<el-card class="box-card carousel-index-0 el-card" style="width:300px;">' + teamResult1 + teamResult2 + '</el-card>'
      })
      // console.log(quarStr)
      //将结果添加到dom元素中
      quar.innerHTML = quarStr

5.2 数据获取代码

使用开发者工具在官网上爬取原数据(此数据爬取行为仅用于作业),再使用Gson序列化将写好的数据类自动映射成对应格式的Json对象,输出到文件中。

原数据类

package org.example;

import java.util.List;

public class OldMatches {
  private List<match> matches;
  private List<round> rounds;

  private List<event> events;

  private List<court> courts;

  private List<teamOut> teams;

  private List<player> players;
}

    public class match{
        private String event_uuid; //未转化的比赛类型
        private String round_id;//未转化的回合id
        private String court_id;//未转化的场地id
        private String duration;//格式为"2:56"的比赛持续时间
        private List<team> teams;
        
        public class team{ //match里的team
            private String team_id; //某一方的team_id,用于查找成员信息
            private String status; //是否获胜,输的一方没有这个属性
            private List<scoreResult> score ;
            public class scoreResult{
                private int set;
                private String game;//单局分数
            }
        }
  }
    public class round{
        private String uuid; //比赛回合的uuid
         private String name;//比赛回合名字
    }
    public class event{
        private String uuid;
        private String name;//比赛类型名字

    }
    public class court{
        private String uuid;
        private String name;//比赛场地名字

        
    }
    public class teamOut{
        private String uuid;
        List<String> players; //存储运动员id的字符串数组
    }
    public class player{
        private String uuid;
        private String short_name;
        private Nationality nationality;

        public class Nationality{
            String name;
        }
    }

}

新数据类

package org.example;

import java.util.List;

public class NewMatches {
    private List<match> matches;

    public class match{

        private String event_type;
        private String round_type;
        private String court;
        private String duration;

        private List<team> teams;

        public class  team{
            private List<player> players;
            private List<aSingleScore> score;
            private boolean is_winner; //是否是赢家
            public class player{
                private String short_name;
                private String nationality;
        
            }
            public class aSingleScore{
                private int set;
                private String game;//单局分数
            }
        }

    }

}

生成新的Json数据代码

package org.example;
import com.google.gson.Gson;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        //创建文件

 //       generateJsonFile("0129.json");
        Gson gson  = new Gson();
        OldMatches oldMatches = getOldMatches();
        List<OldMatches.player> playerList = oldMatches.getPlayers();
        //获取Matches对象中的所有相关列表属性...
        List<OldMatches.match> oldMatchList = oldMatches.getMatches();
        List<OldMatches.court> courtList = oldMatches.getCourts();
        List<OldMatches.event> eventList = oldMatches.getEvents();
        List<OldMatches.round> roundList = oldMatches.getRounds();
        List<OldMatches.teamOut> teamOutList = oldMatches.getTeams(); //与match数组并列的外部team列表
        //遍历每一场match,将每一个oldMatch封装成对应的newMatch,存储在newMatch列表中

        List<NewMatches.match> matches = new ArrayList<>();
        for(OldMatches.match singleMatch: oldMatchList){


            //获得match中的参数
            String event_uuid = singleMatch.getEvent_uuid();
            String round_id = singleMatch.getRound_id();
            String court_id = singleMatch.getCourt_id();

            String duration = singleMatch.getDuration();

            //遍历其他List找到uuid对应的name属性
            String event_type = getEventName(event_uuid, eventList);
            String round_type = getRoundName(round_id, roundList);
            String court = getCourtName(court_id,courtList);

            //遍历 单个match中teams列表,将每个team封装成newTeam, 再得到newTeamList
            List<OldMatches.match.team> oldTeams = singleMatch.getTeams();
            List<NewMatches.match.team> teams = new ArrayList<>();
            for(OldMatches.match.team oldTeam : oldTeams){
                NewMatches.match.team singleNewTeam = getSingleNewTeam(oldTeam, teamOutList, playerList);
                teams.add(singleNewTeam);
            }
            //将四个属性封装成新match
            NewMatches.match newMatch = new NewMatches().new match();
            newMatch.setEvent_type(event_type);
            newMatch.setRound_type(round_type);
            newMatch.setCourt(court);
            newMatch.setDuration(duration);
            newMatch.setTeams(teams);

            matches.add(newMatch);
        }

        NewMatches newMatches = new NewMatches();
        newMatches.setMatchList(matches);
        String result = gson.toJson(newMatches);
      // System.out.println(result);
        generateJsonFile("Day14.json", result);
    }
    /**
     * 功能:根据单个oldteam,封装单个新的team
     */
    public static  NewMatches.match.team  getSingleNewTeam(OldMatches.match.team team, List<OldMatches.teamOut> teams,List<OldMatches.player> oldPlayers){
    }


    /**
     * 对于每个oldMatch中的teams中的team获取 ,新的score列表
     */
    public static   List< NewMatches.match.team.aSingleScore>  getNewScores(OldMatches.match.team team){
    }




    /**
     * 功能:根据单个match中teams数组的单个team的team_id找到对应的新类球员列表
     * @param team_id
     * @param teams
     * @param players
     * @return
     */

    public static  List<NewMatches.match.team.player> getNewTeamsPlayers(String team_id, List<OldMatches.teamOut> teams, List<OldMatches.player> players){  }


    /**
     * 功能:根据给定的输出路径生成文件
     * @param outputPath
     * @throws IOException
     */
    public static void generateJsonFile(String outputPath, String result) throws IOException { }
    /**
     * 功能:获取某一天比赛的集合
     */
    public static OldMatches getOldMatches() throws FileNotFoundException, UnsupportedEncodingException {  }

    /**
     * 功能:根据某场match的event_uuid得到对应的event_name
     * @param event_uuid
     * @return
     */
    public static String getEventName( String event_uuid, List<OldMatches.event> eventList){ }

    /**
     * 功能:根据某场match的court_id得到对应的court_name
     * @param court_id
     * @param courtList
     * @return
     */
    public  static  String getCourtName(String court_id,   List<OldMatches.court> courtList){
    }

    /**
     * 功能:根据某场match的round_id得到对应的round_name
     *
     * @param round_id
     * @param roundList
     * @return
     */
    public  static  String getRoundName(String round_id,   List<OldMatches.round> roundList){ 
    }



}

得到每日赛程部分需要的数据

{
  "matches": [{
    "event_type": "Women's Doubles",
    "round_type": "Final",
    "court": "Rod Laver Arena",
    "duration": "1:29",
    "teams": [{
      "players": [{
        "short_name": "B. Krejcikova",
        "nationality": "Czech Republic"
      }, {
        "short_name": "K. Siniakova",
        "nationality": "Czech Republic"
      }],
      "score": [{
        "set": 1,
        "game": "6"
      }, {
        "set": 2,
        "game": "6"
      }],
      "is_winner": true
    }, {
      "players": [{
        "short_name": "S. Aoyama",
        "nationality": "Japan"
      }, {
        "short_name": "E. Shibahara",
        "nationality": "Japan"
      }],
      "score": [{
        "set": 1,
        "game": "4"
      }, {
        "set": 2,
        "game": "3"
      }],
      "is_winner": false
    }]
  }, {
    "event_type": "Men's Singles",
    "round_type": "Final",
    "court": "Rod Laver Arena",
    "duration": "2:56",
    "teams": [{
      "players": [{
        "short_name": "S. Tsitsipas",
        "nationality": "Greece"
      }],
      "score": [{
        "set": 1,
        "game": "3"
      }, {
        "set": 2,
        "game": "6"
      }, {
        "set": 3,
        "game": "6"
      }],
      "is_winner": false
    }, {
      "players": [{
        "short_name": "N. Djokovic",
        "nationality": "Serbia"
      }],
      "score": [{
        "set": 1,
        "game": "6"
      }, {
        "set": 2,
        "game": "7"
      }, {
        "set": 3,
        "game": "7"
      }],
      "is_winner": true
    }]
  }]
}

在这里插入图片描述

6 结对讨论过程

在这里插入图片描述


在这里插入图片描述


7 心路历程和收获

  • 郑朋友的心路历程和收获

  • 这次作业主要学习了前端技能,对前端工作有了更全面的认识,写前端代码不是简单的把组件添加到页面里,其中各种复杂的动画,交互事件,数据渲染和后端代码一样需要细致的逻辑(因为一直学习的都是后端技术,对前端技术不是很了解)。此外还学习了网站的部署,看到一个属于自己的可以访问的网站,心情很奇妙(虽然这不是什么高深的东西)。

  • 终于了解前端的所谓的框架是什么了。前端框架,比如BootStrap, ElementUI,
    Layui等自带了大量可复用的组件,这些组件封装了行为层结构层表现层的代码,可以非常方便地用于网页实现;此外还有vue这样的js框架,提供了一套开发规则,大大提高开发效率。真是前端工程师的好帮手。

  • 因为时间精力有限,这次作业选择了纯前端方式完成,没有涉及到前后端交互。这一块知识会在今后的学习中补上。

  • 林朋友的心路历程和收获

  • 这次的作业工作量是巨大的,在短短的一周时间内要掌握的东西实在是太多了,主要是这些内容在之前的课程中几乎是没有涉及的。在我有一定前端基础的情况下,编写代码还是要花费很多时间。毕竟是一个完完整整网站的开发,在短时间内学会技能并且将其实现谈何容易。

  • 这一周的学习可以说是“暴风吸入”,每天都在各种博客中试图搜索有用的信息。但是大多数博客都是水出来的,找起资料相当的麻烦,时常一个路由问题就要找半个多小时。所以几乎所有的课余时间都用在了搜集资料 、学习技术、代码实现上。

  • 这是我第一次完全使用vue开发项目,也是对自己的一种挑战。因为前面有前端的基础,所以上手比较快。虽然说代码量减少,但是思考的时间是不会减少的,在思考拼接模板字符串的逻辑时,我花费了好多时间去设计该如何实现。

  • 虽然工作量很大,实现起来很不容易,但是我从中学到了很多。我觉得最重要的应该就是抗压能力。在上课和这个作业中平衡,还要保证充足的睡眠。其次是和队友的合作能力,刚开始合作的时候会有些不适应,但后面慢慢磨合好了,效率也高了。还有就是技术方面,这次作业之后我也会进行整理反思,接下来的目标是深入学习vue,为后面的团队作业打好基础。


8 结对队友互评

  • 郑朋友to林朋友:动手能力很强,看的出来对代码非常有兴趣(甚至看不得其他同学的代码报错)。有一定的前端技术基础,多亏林朋友的帮助使得我对前端技术了解得非常快。从Vue项目环境的搭建到具体某一块网页效果的实现都过了一遍,收获满满。
  • 林朋友to郑朋友:学习能力强, 对新东西接收很快,有一点强迫症,用到哪个知识就一定要求弄清来龙去脉(也是个学习的好习惯)。对Java代码比较熟悉,处理数据的部分很让人省心。愿意付出,主动负责了力所能及的部分,是个不错的伙伴噢。
...全文
317 回复 打赏 收藏 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

688

社区成员

发帖
与我相关
我的任务
社区描述
2023年福州大学软件工程实践课程W班的教学社区
软件工程团队开发软件构建 高校 福建省·福州市
社区管理员
  • FZU_SE_teacherW
  • 张书旖
  • 郭渊伟
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧