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

222000322许影杰 学生 2023-03-24 21:57:14
这个作业属于哪个课程2023年福大-软件工程实践-W班
这个作业要求在哪里结对第二次作业--编程实现
结对学号222000322 & 222000323
这个作业的目标学习前后端开发框架,编码实现原型设计,部署网站到云服务器上。
其他参考文献CSDN

目录

  • 一、相关链接
  • 1.1 Gitcode仓库地址
  • 1.2 网站链接
  • 1.3 代码规范
  • 二、PSP表格&效能分析
  • 2.1 PSP表格
  • 2.2 效能分析
  • 三、 成果展示
  • 3.1 Heade&Footer
  • 3.2 首页
  • 3.3 导航栏跳转演示
  • 3.4 选手排名
  • 3.5 每日赛况
  • 3.6 晋级图
  • 3.7 详细赛况(附加)
  • 3.8 了解更多(附加)
  • 3.8 登录界面(拓展)
  • 3.9 注册界面(拓展)
  • 四、 编码过程
  • 4.1 技术栈
  • 4.2 编码工具
  • 4.3 功能结构图
  • 4.4 数据来源
  • 4.5 实现思路
  • 4.6 编码中困难(过程)
  • Barrier 1:如何使轮播图中间图片大,两边图像小并显示一半
  • Barrier 2:如何实现日期滚动栏
  • Barrier 3:如何通过点击按钮切换晋级图组件数据源
  • Barrier 4:如何解决改变了数据源但UI渲染效果不变
  • Barrier 5:如何实现晋级图中的线
  • 五、 关键代码展示
  • 5.1 前端关键代码
  • 5.2 后端关键代码
  • 六、 网站部署过程
  • 后端部署
  • 前端部署
  • 七、 结对过程
  • 7.1 分工情况
  • 7.2 结对记录
  • 7.3 心路历程&收获
  • 7.4 队友互评


一、相关链接

1.1 Gitcode仓库地址

pair_project

1.2 网站链接

我的澳网

1.3 代码规范


二、PSP表格&效能分析

2.1 PSP表格

322同学的PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3040
• Estimate• 估计这个任务需要多少时间3040
Development开发15501960
• Comunicate• 讨论开发流程与使用框架3030
• Analysis• 技术学习500600
• Coding Standard• 代码规范3030
• Coding• 具体编码9001200
• Code Review• 代码复审3040
• Test• 测试6060
Reporting报告290340
• Test Repor• 博客编写240300
• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划3030
合计18702340

323同学的PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3040
• Estimate• 估计这个任务需要多少时间3040
Development开发19502160
• Comunicate• 讨论开发流程与使用框架3030
• Analysis• 技术学习600600
• Coding Standard• 代码规范3030
• Coding• 具体编码12001400
• Code Review• 代码复审3040
• Test• 测试6060
Reporting报告290340
• Test Repor• 博客编写240300
• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划3030
合计22702540

2.2 效能分析

  • 322同学:通过完成PSP表格,发现在实现前端部分时存在效率低下的情况,耗费时间远超预期时间。主要原因是先前没接触过Vue3框架再加上时间紧张,导致未能系统学习Vue3技术栈,只能一边写一边学,一边学一边写,这使得整个编写过程不仅十分折磨,而且效率极低,到后面基本上是抱着能跑就行的心态在进行,这显然不是良性的完成项目的方式,这也警示我在平时应当积极学习技术,扩宽自己的技术栈,避免像这种接触到一个项目后不知所措、手忙脚乱的情况再次发生。
  • 323同学:本次作业中大部分时间花在了学习技术栈上,同时由于自身对于技术栈学习的偏少,只能一变摸索一边实现功能,效率也不是很高,一些前端部分功能的实现也是队友帮忙实现的。整体时间紧,任务重,Vue只能跟着现有的实例教程学习,对于其中一些细节也仍是一知半解,可能现在还没有摸到这门技术的入门。而且,在本次实践中大部分时间花在了资料的查找和试错上,一些功能实现并没有找到教程(如日期滚动栏的实现),只能一步步地试错,其中也是浪费了一些时间。总体来说,技术还是第一生产力,没有技术真的是寸步难行

三、 成果展示

3.1 Heade&Footer

Header包含了导航栏以及登录、注销按钮

在这里插入图片描述


Footer设计简约大气一目了然

在这里插入图片描述

3.2 首页

复现了原型中设计的首页,点击按钮可以进入了解更多页面

在这里插入图片描述

3.3 导航栏跳转演示

通过点击按钮能够切换路由,同时每个按钮都设有hover样式

在这里插入图片描述

3.4 选手排名

展示男女单打选手排名

在这里插入图片描述

3.5 每日赛况

每日赛况展现当天的比赛信息,可以通过日期滚动栏选择显示相应日期比赛

在这里插入图片描述

3.6 晋级图

可以通过点击按钮查看每轮轮对应的对阵信息,对每轮比赛的胜者做了标红,每轮比赛悬停时有高光样式

在这里插入图片描述

3.7 详细赛况(附加)

点击比赛标签可以查看详细赛况。
注:只做了Day1的第一场比赛的详细赛况

在这里插入图片描述

3.8 了解更多(附加)

了解更多页面显示了澳网的介绍,以轮播图的形式展现了历年比赛精彩瞬间

在这里插入图片描述

3.8 登录界面(拓展)

对错误信息进行alert显示,用户可以通过提示重新尝试登录

在这里插入图片描述

3.9 注册界面(拓展)

提供了再次输入密码框对两次输入的密码进行比对,避免用户输错密码。同样对错误信息进行alert显示

在这里插入图片描述


注:原型中有设计收藏比赛的功能,因此设计了登录注册页面以及接口,但时间原因未能实现收藏功能

四、 编码过程

4.1 技术栈

  • 前端:Vue3+axios+element plus+swiper
  • 后端:Springboot + SpringMVC + MybatisPlus

4.2 编码工具

  • 前端:VSCode
  • 后端:IntelliJ IDEA

4.3 功能结构图

在这里插入图片描述

4.4 数据来源

  • 通过官网获取的api爬取数据(注:该爬取行为仅用于课程教学)
  • 通过Navicat工具将json文件导入数据库

4.5 实现思路

项目实现基于第一次原型设计结对作业,功能结构图见上,经过讨论我们前端采用vue后端采用Springboot实现相应功能,实现流程展示如下:

  1. 首先通过api爬取数据并存入数据库
  2. 后端通过Springboot编写相关接口
  3. 前端编写页面路由和界面
  4. 前后端对接,测试接口
  5. 前端调用接口填充数据

4.6 编码中困难(过程)

Barrier 1:如何使轮播图中间图片大,两边图像小并显示一半

 轮播图主要依靠组件来实现,但如element组件中的轮播图是最基本的轮播效果,要实现原型设计中轮播图展现中间图片时放大的效果有些困难,所以另外下载了swiper组件来实现这一功能,通过查询资料,发现了有人实现了这一效果,但是经过试验发现效果还是不尽人意,同时我们在其他回答下面获得了启发,通过调整css代码,经过试验最终达到了想要的效果,后期分析造成这个问题的原因还是由于对于vue语句和组件属性的不了解。

具体代码在后面展示

Barrier 2:如何实现日期滚动栏

 原型中实现这个效果还是比较容易,但是要编码实现还是有一些困难,我们最初也是想在网上查看是否有人做过类似功能,但是不知道是问题描述得不清楚还是其他原因,我们并没有找到相关案例,但是轮播图的制作还是给了我们一些启发,是否可以通过轮播图来实现滚动栏?我们将按钮替换图片,通过调整swiper一次性展现图片的个数和相关css代码,我们实现了这一效果,但是还是存在一个问题就是滚动栏的样式会受页面缩放的影响,可能对于这一问题还有其他更好的解法。

Barrier 3:如何通过点击按钮切换晋级图组件数据源

 在设计晋级图时我沿用了制作原型时的组件的思想,将晋级图分为了3个组件来实现,这需要组件间进行数据的传输,这就导致了数据不同步或者说渲染和数据改变异步的问题出现,最后是通过将数据源声明为computed对象,监听按钮属性的变化,以此来实现数据源的切换。

Barrier 4:如何解决改变了数据源但UI渲染效果不变

 解决了数据源切换的问题,但是出现了新的问题,由于我晋级图按照原型的设计选择一次展示两轮比赛,这也就是说每个数据源都是一个2层二叉树数组,数组的对象数量不同。但在渲染时看见的现象是先前以及渲染过的二叉树组件并没有渲染为新的二叉树(假如说第一次展示只有一个二叉树,当切换数据源变为两个二叉树时,先前的一个二叉树中的数据并没有变为新的数据),最后通过在PromoteItem的onUpdated方法中,对数据进行赋值,成功解决问题。

Barrier 5:如何实现晋级图中的线

 一开始打算通过已有组件实现晋级图,但找了半天找到的不是不能插槽就是晋级图的方向不对,最后决定自己划线。由于只需要实现一层二叉树,不需要考虑嵌套递归的问题,这使得实现变得不那么复杂。最后了解到可以通过伪类来实现,在大佬的帮助下成功实现想要的效果。

五、 关键代码展示

5.1 前端关键代码

轮播图实现
主要是通过CSS代码和swiper属性实现,思路见上问题描述

<div class="swiper-container">
    <swiper :modules="modules"
            :effect="'coverflow'"
            :loop="true"
            :slidesPerView= "'auto'"
            :centeredSlides="true"
            :space-between="100"
            :autoplay="{ delay: 800, disableOnInteraction: false }"
            :observer = true
            :observeParents = "false"        
        class="swiper-wrapper">
        <swiper-slide><img src="src\assets\rowplay\6.jpeg"  alt="" /></swiper-slide>
        <swiper-slide><img src="src\assets\rowplay\1.jpeg"  alt="" /></swiper-slide>
        <swiper-slide><img src="src\assets\rowplay\2.jpeg"  alt="" /></swiper-slide>
        <swiper-slide><img src="src\assets\rowplay\3.jpeg"  alt="" /></swiper-slide>
        <swiper-slide><img src="src\assets\rowplay\4.jpeg"  alt="" /></swiper-slide>
        <swiper-slide><img src="src\assets\rowplay\5.jpeg"  alt="" /></swiper-slide>
      </swiper>
  </div>
.swiper-container {
  margin: auto;
    margin-top: 30px;
    width: 1300px;
    height: 500px;
    margin-bottom: 53px;
    overflow: visible
}
.swiper-container .swiper-wrapper .swiper-slide{ width: 620px; border-radius: 20px;}
.swiper-container .swiper-wrapper .swiper-slide img{width: 100%; height: 420px; border-radius: 20px;}
.swiper-container .swiper-wrapper .swiper-slide-prev{ margin-top: 60px; height: 300px;}
.swiper-container .swiper-wrapper .swiper-slide-prev img{ height: 300px;}
.swiper-container .swiper-wrapper .swiper-slide-next{ margin-top: 60px; height: 300px;}
.swiper-container .swiper-wrapper .swiper-slide-next img{ height: 300px;}
.swiper-container .swiper-wrapper .swiper-slide-active{ width: 620px;}

日期滚动栏
通过设置CSS将原来轮播图箭头移至两边,同时为了解决swiperelement按钮悬停和按下时效果出现异常的bug,另外编写了相关代码,思路见上问题描述

<script setup lang="ts">
const change = (index: number) => {
    currentButton.value = index;
    getMatch(index+1).then(res => {
    CommunityList.value = res.data.data;
  })
}
</script>
<div class="wrap" style="margin: 0 100px;">
  <div class="swiper-no-swiping" style="position: relative;padding:0px 0px;margin: 10px;">
    <swiper
    ref="{swiperRef}"
    :slidesPerView="12"
    :centeredSlides="false"
    :spaceBetween="0"
    :navigation="true"
    :modules="modules"
    class="mySwiper"
    style="height: 100px;margin-top: 0px; position: initial;"
  >
    <swiper-slide><el-button  @click="change(0)" :class="{ newStyle:0===currentButton}">Day 1</el-button></swiper-slide>
    <swiper-slide><el-button  @click="change(1)" :class="{ newStyle:1===currentButton}">Day 2</el-button></swiper-slide>
    ···
  </swiper>
  </div>
</div>

晋级图组件
封装了三个组件如下


PromoteItem实现单个比赛信息组件,在onUpdated对数据进行更新,避免出现不同步的现象

<script setup lang="ts">
import { ref, onMounted, onUpdated, reactive } from 'vue';


const props = defineProps({
    data: Object
})
const round = ref<any>({});
const teams = ref<any>([])

onMounted(() => {
    round.value = props.data?.round;
    teams.value = props.data?.teams;
    console.log(props.data)
})
onUpdated(() => {
    round.value = props.data?.round;
    teams.value = props.data?.teams;
    console.log(props.data)
})
</script>
<template>
    <div class="container">
        <div class="head">{{ round }}</div>
        <div :class="team.win ? 'winner' : 'loser'" v-for="(team, index) in teams">
            <div class="leftBox">
                <img class="nation" :src="team.players[0].nationality">
                <div class="name">{{ team.players[0].shortName }}</div>

            </div>
            <div class="sets">
                <div class="game" v-for="(set, index) in team.scores">{{ set.game }}</div>
            </div>
        </div>
    </div>
</template>

PromoteTree实现由三个PromoteItem对象构成的二叉树

<script setup lang="ts">
import { ref, onMounted, onUpdated, reactive } from 'vue';
import PromoteItem from '../components/PromoteItem.vue'

defineProps({
    tree: Object
})
</script>
<template>
    <div class="tree">
        <div class="parent">
            <PromoteItem :data="tree?.match"></PromoteItem>
        </div>
        <div class="line">
            <div></div>
        </div>
        <div class="child">
            <PromoteItem :data="node.match" v-for="(node, index) in tree?.child"></PromoteItem>
        </div>
    </div>
</template>

PromoteContainer用于封装整个二叉树列表

<script setup lang="ts">
import { ref, onMounted, onUpdated, reactive, watch } from 'vue';
import PromoteTree from '../components/PromoteTree.vue'

const props = defineProps({
    list: Array<Object>
})
watch(() =>
    props.list
    , () => {
        console.log(props.list?.length)
    }, {
    deep: true,
    immediate: true
})

</script>
<template>
    <div class="main">
        <div class="tree" v-for="(t, index) in list" :key="index">
            <PromoteTree :tree="t"></PromoteTree>
        </div>
    </div>
</template>

选手排名: 通过v-for循环显示数组中的对象

          <tr v-for="(item, index) in mPlayers" :key="index">
            <th style="text-align: left;">{{ item["fullName"] }}</th>
            <td>{{ index + 1 }}</td>
            <td>{{ item["matches"] }}</td>
            <td>{{ item["value"] }}</td>
          </tr>

将后端传来的完整二叉树分割为三组二叉树列表,finalsTree需要展示根节点,于是数组中传入完整的二叉树,semifinalsTree需要展示倒数第二轮比赛,因此在数组中传入root节点的两个子二叉树,以此类推,quarterFinalsTree也是同样的逻辑,存入semifinalsTree中的每个子二叉树。

onMounted(() => {
  getPlayerPromote().then(res => {
    promoteDataTree.value = res.data.data;
    finalsTree.value.push(promoteDataTree.value);
    promoteDataTree.value.child.forEach((semiNode: any) => {
      semifinalsTree.value.push(semiNode);
    });
    semifinalsTree.value.forEach((node: any) => {
      node.child.forEach((quarNode: any) => {
        quarterFinalsTree.value.push(quarNode);
      })
    })
  })

})

定义了一个computed对象,监听按钮的变化,给PromoteContainer提供对应的数据

const treeLists = computed(() => {
  switch (currentButton.value) {
    case 0:
      return quarterFinalsTree.value
    case 1:
      return semifinalsTree.value
    case 2:
      return finalsTree.value
    default:
      return []
  }
})

登录表单中去除输入的空格

onkeyup="value = value.replace(/[, ]/g,'')"

5.2 后端关键代码

获取晋级图二叉树:首先根据round字段,从数据库中分别取出finals ,semifinals ,quarterfinals ,forthRound 轮的数据。选手的名字在一轮比赛中只会出现一次,那么当选手名字出现在下一轮中的比赛就说明他这场比赛是他晋级后参加的比赛,由此构建出父子关系。通过以上逻辑,从finals根节点开始,向下寻找,便成功构建出一个晋级二叉树。

public ResponseResult getPromoteTree() {
        ///获取每一轮的比赛信息
        Map<String, List<MatchVo>> matchMap = new HashMap<>();
        for (int i = 0; i < BusinessConstants.ROUND.length; i++) {
            List<MatchTemp> teamTemps = matchMapper.getTeamListByRoundAndType(BusinessConstants.ROUND[i], BusinessConstants.REQUIRED_TYPE);
            List<MatchVo> matchVos = getMatchVosByTempList(teamTemps);
            matchMap.put(BusinessConstants.ROUND[i], matchVos);
        }
        //构建二叉树
        MatchVo finals = matchMap.get(BusinessConstants.ROUND[0]).get(0);
        List<MatchVo> semifinals = matchMap.get(BusinessConstants.ROUND[1]);
        List<MatchVo> quarterfinals = matchMap.get(BusinessConstants.ROUND[2]);
        List<MatchVo> forthRound = matchMap.get(BusinessConstants.ROUND[3]);
        PromoteTreeNode root = new PromoteTreeNode(finals, new ArrayList<>());
        for (int i = 0; i < semifinals.size(); i++) {
            MatchVo semiMath = semifinals.get(i);
            PromoteTreeNode semiNode = new PromoteTreeNode(semiMath, new ArrayList<>());
            if (getPlayerShortName(finals).containsAll(getWinnerShortName(semiMath))) {
                for (int j = 0; j < quarterfinals.size(); j++) {
                    MatchVo quarMath = quarterfinals.get(j);
                    PromoteTreeNode quarNode = new PromoteTreeNode(quarMath, new ArrayList<>());
                    if (getPlayerShortName(semiMath).containsAll(getWinnerShortName(quarMath))) {
                        for (int k = 0; k < forthRound.size(); k++) {
                            MatchVo forthMath = forthRound.get(k);
                            PromoteTreeNode forthNode = new PromoteTreeNode(forthMath, new ArrayList<>());
                            if (getPlayerShortName(quarMath).containsAll(getWinnerShortName(forthMath))){
                                quarNode.getChild().add(forthNode);
                            }
                        }
                        semiNode.getChild().add(quarNode);
                    }
                }
                root.getChild().add(semiNode);
            }
        }


        return ResponseResult.okResult(root);
    }

六、 网站部署过程

后端部署

  • 使用Maven打包项目jar包
  • 在服务器上运行jar包
  • 在服务器系统防火墙中添加端口规则,放行后端项目端口
  • 在腾讯云控制台添加域名解析

前端部署

  • 使用npm run build指令打包成dist
  • 在宝塔面板中添加站点
  • 将dist中的文件放入生成的站点根目录

七、 结对过程

7.1 分工情况

  • 322同学:后端;前端首页、晋级图页面、选手排名页面、登录注册页面、博客编写
  • 323同学:前端了解更多页面,每日赛程页面,每日赛程接口,博客编写

    7.2 结对记录

    讨论图片

    在这里插入图片描述


    聊天截图

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


宿舍较近,大部分讨论为当面交流

7.3 心路历程&收获

  • 322同学
    心路历程:我认为本次作业的难点主要在于前端的实现。一方面是不熟悉Vue3框架,另一方面是任务时间有限,可谓是时间紧任务重。在参考教程以及大佬的帮助下,初步搭建好Vue3项目框架后便是本着能跑就行的原则,猛猛的就写写,出bug了就去找,找不到就去学,学不明白就找大佬帮忙...在囫囵吞枣的学习以及编写了几个组件后,我对vue的语法以及常用方法有了基本的掌握,编写过程逐渐变得顺利起来,最后也是成功完成了任务。
    收获:通过这次作业,我加强了对html、JavaScript、css语法的掌握,尤其是CSS,在进行页面设计时给我好好的补了课,同时学习了TypeScript语法;对Vue3框架有了初步的认识,包括ajax的封装调用,Vue3中的监听对象等等;熟悉了网站前后端项目的部署。也算是成了一个小小的“全栈工程师”(bushi)。
  • 323同学
    心路历程:收到本次作业要求时是比较有压力的,可以说我在技术栈方面是一个新手小白,对与各种框架也是两眼一抹黑,要在一周内完成技术的学习和需求实现,当时感觉十分头疼,不知道如何入手,还是我的队友在本次作业初期对前后端编码和使用框架同我讲解让我对整体编码流程有了初步的了解。
     然后是对于vue的学习,我是通过实际项目代码来了解vue框架,不求完全理解vue,只求能够会用vue,以便于最快来上手,但过程还是磕磕绊绊,对于内容也是囫囵吞枣,在使用中对于要实现的效果(如轮播图,日期滚动栏)也是不断试验出来的,在布局上可能没有那么完美,但都尽力做了,主要还是自身对于技术的不熟悉,在试错上浪费了比较多的时间。临阵磨枪,在短时间就想学会一门技术还是比较困难的。
    收获:主要的收获是了解了vue框架和其中一些语句的使用,对于前后端工作内容和流程有了一定的了解,同时了解了前后端合作中需要注意的一些方面(如接口的对接),也了解了对于页面布局的一些知识,了解了swiper和element组件。

7.4 队友互评

  • 322同学对323同学:正如上次结对一样,在本次结对任务中,我的队友依旧维持了他积极讨论,高执行力的风格。主动承担任务,常常奋战到深夜。同时也给了我很多设计上的灵感,整体来说结对过程十分顺利,虽然有不小的挑战,但也算是圆满完成任务。
  • 323同学对322同学:我的队友比较熟悉后端技术栈,也有很多项目经验,教了我这个新手小白很多相关知识,完成任务过程中十分有效率,同时他在完成后端编写的情况下也愿意分担前端的工作,让我们能够得以完成作业要求,在我遇到问题时也十分乐意帮我解决问题,是一个十分强力、可靠、有责任感的队友(抱紧大腿)
...全文
363 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
郭渊伟 2023-04-05
  • 打赏
  • 举报
回复

博客内容条理清楚,网站也较为美观,完成度很高,赞!

  • 打赏
  • 举报
回复

1.晋级图涉及多种颜色,是否从醒目的角度出发?有找同学评价过吗?2.长列的日期轮播效果是否达到?为何不考虑借鉴日历的形式?

222000322许影杰 学生 2023-03-25
  • 举报
回复
@2023年福大-软件工程实践-W班 ①我在设计时将胜者和败者分别设为红色与白色,使胜者更为醒目,以及hover时的颜色也是通过修改透明度来实现高光。至于同学的评价主要都是说颜色太丑,所以后期对于颜色的调整都是在区分胜败者的基础上,以美观为主选取颜色(我感觉还行)。 ②首先,我们本次日期轮播条的设计主要是以还原原型设计为主。其次,由于这次比赛只有14天,所以我们认为使用日期滚动也能达到不错的视觉效果和使用体验,至于老师您说的奥运会日期很多的情况下确实是使用日历的形式实现更为合理,也给了我们一个启发,在之后遇到日期很多的情况时会考虑优先使用日历来实现。

688

社区成员

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

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