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

222200413陈志鸿 2024-09-30 23:09:02
这个作业属于哪个课程FZU_SE_teacherW_4
这个作业要求在哪里结对作业第二次——编程实现
结对学号222200413 ,222200415
这个作业的目标团队协作,完成2024年巴黎奥运会的编码
其他参考文献《构建之法》

目录

  • 一、CodeArt项目地址和代码规范链接
  • 二、PSP表格
  • 三、访问链接
  • 四、成品展示
  • 1、首页
  • 2、奖牌榜排名
  • 3、每日赛程&赛程详细信息
  • 4、对阵表
  • 5、了解更多
  • 五、实现过程&结对讨论过程
  • 1、功能结构图
  • 2、实现过程
  • 3、结对讨论截图
  • 六、代码说明
  • 1、前端
  • 关键代码&思路
  • 路由配置
  • 状态管理
  • 关键页面
  • 2、后端
  • 关键代码
  • 解释思路
  • 七、遇到的困难和解决方法
  • 1、前端
  • 遇到的困难
  • 解决方法
  • 2、 后端
  • 遇到的困难
  • 解决方法
  • 八、心路历程和收获
  • 心路历程
  • 收获
  • 九、评价结对队友

一、CodeArt项目地址和代码规范链接

CodeArt项目地址

代码规范链接

二、PSP表格

PSPPersonal Software Process Stages预估耗时(小时)实际耗时(小时)
Planning计划0.30.5
• Estimate• 估计这个任务需要多少时间0.30.5
Development开发42.8549.4
• Analysis• 需求分析 (包括学习新技术)0.50.6
• Design Spec• 生成设计文档11
• Design Review• 设计复审0.61
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)0.250.3
• Design• 具体设计22.5
• Coding• 具体编码3640
• Code Review• 代码复审0.51
• Test• 测试(自我测试,修改代码,提交修改)23
Reporting报告1.51.5
• Test Report• 测试报告0.50.3
• Size Measurement• 计算工作量0.50.2
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划0.51
合计44.6551.4

三、访问链接

http://121.36.224.55/

四、成品展示

1、首页

img

2、奖牌榜排名

img

3、每日赛程&赛程详细信息

img

4、对阵表

img

5、了解更多

img

五、实现过程&结对讨论过程

1、功能结构图

img

2、实现过程

对接: 通过apifox规定api接口,完成前后端对接

img

3、结对讨论截图

img

大部分讨论在线下进行

六、代码说明

1、前端

使用vue3+pinia+vue Router+Typescript+element plus+axios

关键代码&思路

路由配置
  1. 路由使用 HTML5 模式
  2. 部分路由使用独享前置路由守卫,在跳转之前获取数据,避免跳转后数据为空
import { createRouter, createWebHistory } from 'vue-router'
import { useDayResultStore } from '@/stores/dayResult'
import { useCompetitionStore } from '@/stores/competition'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/home',
      redirect: '/',
    },
    {
      path: '/',
      name: 'Home',
      component: ()=>import('@/views/home/index.vue')
    },
    {
      path: '/rankings',
      name: 'Rankings',
      component: ()=>import('@/views/rankings/index.vue')
    },
    {
      path: '/dayResult',
      name: 'DayResult',
      component: ()=>import('@/views/dayResult/index.vue'),
      beforeEnter: async (to, from, next) => {
        const dayResultStore = useDayResultStore()
        const res = await dayResultStore.fetchDayResults(dayResultStore.date)
        if (res.code===1){
          next()
        }
        else {
          alert(res.message)
          next(false)
        }
      }
    },
    {
      path: '/compete',
      name: 'Compete',
      component: ()=>import('@/views/compete/index.vue'),
      beforeEnter: async (to, from, next) => {
        const competitionStore = useCompetitionStore()
        const res1 = await competitionStore.fetchProject()
        if (res1.code===1){
          const res2 = await competitionStore.fetchTypes(competitionStore.selected.firstname)
          if (res2.code===1){
            const res3 = await competitionStore.fetchInfo(competitionStore.selected.type.id)
            if (res3.code===1){
              next()
            }
            else {
              alert(res3.message)
              next(false)
            }
          }
          else {
            alert(res2.message)
            next(false)
          }
        }
        else {
          alert(res1.message)
          next(false)
        }
      }
    },
    {
      path: '/about',
      name: 'About',
      component: ()=>import('@/views/about/index.vue'),
    },
    {
      path: '/detail',
      name: 'Detail',
      component: ()=>import('@/views/detail/index.vue'),
      children:[
        {
          path:'/matchDetail',
          name:'MatchDetail',
          component:()=>import('@/views/detail/matchDetail.vue')
        },
        {
          path:'/playerList',
          name:'PlayerList',
          component:()=>import('@/views/detail/playerList.vue')
        },
      ]
    },
  ]
})

export default router
状态管理
  1. 使用pinia进行状态管理
  2. 使用Axios与后端对接,发送请求
  3. 关键数据都进行了本地化存储,刷新之后可从本地获取加快访问速度
  • 奖牌榜
//获取奖牌榜信息
const fetchMedals = async ():Promise<Status> => {
try {
  const response = await axios.get('/api/dataget/GetAllNationalMedals');
  const { code, message, data } = response.data;

  if (code === 1) {
    medals.value = data;
    localStorage.setItem('medals', JSON.stringify(medals.value));
    // console.log(medals.value);
  }
  return { code, message };
} catch (error) {
  console.error(error);
  return { code: 0, message: '请求失败' };
}
};
  • 每日赛程
const fetchDayResults = async (date:string):Promise<Status> => {
try {
  const response = await axios.get(`/api/dataget/GetDayResult`, {
    params: { date },
  });
  if (response.data.code === 1) {
    dayResults.value = response.data.data;
    localStorage.setItem('dayResults', JSON.stringify(dayResults.value));
  }
  return { code:response.data.code, message:response.data.message };
} catch (error) {
  console.error('请求失败:', error);
  return { code: 0, message: '请求失败' };
}
};
  • 比赛信息
const fetchTypes = async (firstname:string):Promise<Status> => {
try {
  const response = await axios.get(`/api/dataget/GetAllMatchDetailName`,{
    params:{ firstname }
  });
  const { code, message, data } = response.data;

  if (code === 1) {
    types.value = data;
    localStorage.setItem('types', JSON.stringify(types.value));
    // console.log(types.value);
  }
  return { code, message };
} catch (error) {
  console.error(error);
  return { code: 0, message: '请求失败' };
}
};
const fetchProject = async ():Promise<Status> => {
try {
  const response = await axios.get('/api/dataget/GetAllMatchName');
  const { code, message, data } = response.data;

  if (code === 1) {
    projects.value = data;
    localStorage.setItem('projects', JSON.stringify(projects.value));
    // console.log(projects.value);
  }
  return { code, message };
} catch (error) {
  console.error(error);
  return { code: 0, message: '请求失败' };
}
};
const fetchInfo = async (id:string):Promise<Status> => {
try {
  const response = await axios.get(`/api/dataget/GetBattleTable`,{
    params:{ id }
  });
  const { code, message, data } = response.data;

  if (code === 1) {
    information.value = data;
    localStorage.setItem('information', JSON.stringify(information.value));
    // console.log(information.value);
  }
  return { code, message };
} catch (error) {
  console.error(error);
  return { code: 0, message: '请求失败' };
}
};
  • 对阵表
const fetchCompeteDetail = async (disciplineCode:string,eventId:string):Promise<Status> => {
try {
  const response = await axios.get(`api/dataget/GetResultCombine`,{
    params:{ disciplineCode,eventId }
  });

  const { code, message, data } = response.data;

  if (code === 1) {
    competeDetail.value = data;
    localStorage.setItem('competeDetail', JSON.stringify(competeDetail.value));
    // console.log(competeDetail.value);
  }
  return { code, message };
} catch (error) {
  console.error(error);
  return { code: 0, message: '请求失败' };
}
};
关键页面
  • 首页

轮播图使用element plus组件库中的el-carousel组件显示

<!--  轮播图-->
  <div class="carousel">
    <el-carousel :interval="3000" height="auto">
      <el-carousel-item v-for="(item, index) in swiperImages" :key="index" style=" height: 500px; !important;">
        <img :src="item" alt="" class="carousel-image"/>
      </el-carousel-item>
    </el-carousel>
  </div>
  • 对阵表

使用v-for遍历数据和对象,动态渲染相应的元素

<!--       1/4决赛-->
<div class="col">
<div
  class="item"
  v-for="(item,index) in competitionStore.information.qFinal.allMatch"
  :key="index"
>
  <div class="competitor">
    <div class="nation">
      <img
        :src="'https://olympics.com/OG2024/assets/images/flags/OG2024/' + item.competitor1.countryEN + '.webp'"
        alt=""
        style="height: 25px;margin-right: 10px;border: silver solid 1px;"
      >
      <p>{{ item.competitor1.name }}</p>
    </div>
    <p>{{ item.competitor1.score ? item.competitor1.score : '' }}</p>
  </div>
  <div class="competitor">
    <div class="nation">
      <img
        :src="'https://olympics.com/OG2024/assets/images/flags/OG2024/' + item.competitor2.countryEN + '.webp'"
        alt=""
        style="height: 25px;margin-right: 10px;border: silver solid 1px;"
      >
      <p>{{ item.competitor2.name }}</p>
    </div>
    <p>{{ item.competitor2.score ? item.competitor2.score : '' }}</p>
  </div>
</div>
</div>   
<!--      连线-->
<div class="col-gap">
<div class="line-box">
  <div class="line-left"></div>
  <div class="line-right">
    <div></div>
    <div></div>
  </div>
</div>
<div class="line-box">
  <div class="line-left"></div>
  <div class="line-right">
    <div></div>
    <div></div>
  </div>
</div>
</div>
<!--      css-->
.col-gap{
  width: 5%;
  height: 70vh;
  min-height: 528px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}

.line-box{
  width: 100%;
  height: 27%;
  display: flex;
  .line-left{
    width: 50%;
    height: 100%;
    border-top: silver solid 2px;
    border-right: silver solid 2px;
    border-bottom: silver solid 2px;
  }
  .line-right{
    width: 50%;
    height: 100%;
  }
  .line-right>div:first-child{
    width: 100%;
    height: 50%;
    border-bottom: silver solid 2px;
  }
}

2、后端

关键代码

后端数据传输服务器设置

static void Main(string[] args)
        {
            // 7595 是端口,可以改成喜欢的
            var config = new HttpSelfHostConfiguration("http://localhost:7595");
            config.EnableCors();
            config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
            config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

            // 定义路由,这里不需要改
            config.Routes.MapHttpRoute(
                name: "DefaultApi",  // 可以改成喜欢的名字,xxxApi
                routeTemplate: "api/{controller}/{action}",
                defaults: new { id = RouteParameter.Optional }
            );

            var server = new HttpSelfHostServer(config);
            server.OpenAsync().Wait();  // 启动服务器

            Console.WriteLine("服务器已启动,按回车停止。");

            Console.ReadLine();

        }

api类需要继承ApiController并且在命名为xxxController 具体的方法函数添加上标签[HttpGet]

如下声明

 public class DataGetController : ApiController

声明DataPraser静态类存放需要用到的数据以及http的获取方法,以及获取路由中json数据的方法

以下四个路由为获取数据使用的(无法获得所有数据,例如跳水比赛,无法使用对阵表)

public static string GetBracketTableHttp(string matchID)
{
    return $"https://olympics.com/OG2024/data/GLO_Bracket~comp=OG2024~rsc={matchID}~lang=CHI.json";
}
public static string GetDailyFixturesHttp(string date)
{
    return $"https://sph-s-api.olympics.com/summer/schedules/api/CHI/schedule/day/{date}";
}
public static string GetSchedulesHttp(string disciplineCode)
{
    return $"https://olympics.com/OG2024/data/SCH_StartList~comp=OG2024~disc={disciplineCode}~lang=CHI.json";
}
public static string GetScheduleResultsHttp(string disciplineCode, string id)
{
    return $"https://olympics.com/OG2024/data/RES_ByRSC_H2H~comp=OG2024~disc={disciplineCode}~rscResult={id}~lang=CHI.json";
}

以下为获取json的代码

public static string GetHttpJson(string httpPath)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(httpPath);
    request.Proxy = null;
    request.KeepAlive = false;
    request.Method = "GET";
    request.ContentType = "application/json; charset=UTF-8";
    request.AutomaticDecompression = DecompressionMethods.GZip;

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream myResponseStream = response.GetResponseStream();
    StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
    string retString = myStreamReader.ReadToEnd();

    myStreamReader.Close();
    myResponseStream.Close();

    if (response != null)
    {
        response.Close();
    }
    if (request != null)
    {
        request.Abort();
    }

    return retString;
}

除此之外的代码主要为分析数据并进行简化并保存(降低访问奥运官网带来的延迟)然后传输给前端

解释思路

对阵表数据去除了某些比赛中1/4决赛以前的比赛,仅从1/4决赛开始记录,通过数据中的bracketCode判断为什么比赛

public static BattleTableData GetBattleTable(string id)
{
    BattleTableData result = new BattleTableData();
    string savePath = Path.Combine(ResourcesPath, "BracketData", id + ".json");
    //获取已经存在的数据
    if (File.Exists(savePath))
    {
        string json = File.ReadAllText(savePath);
        result = JsonConvert.DeserializeObject<BattleTableData>(json);
        return result;
    }
    //若不存在则获取
    BattleTable data = new BattleTable();
    string httpPath = GetBracketTableHttp(id);
    var jsonResult = Communicable(httpPath);
    if (!jsonResult.Item1) return null;
    data = JsonConvert.DeserializeObject<BattleTable>(jsonResult.Item2);
    try
    {
        foreach (var a in data.bracket)
        {
            result.id = a.documentCode;
            Console.WriteLine(a.documentCode);
            if (!a.bracketCode.Equals("BRN") && !a.bracketCode.Equals("FNL")) continue;
            foreach (var b in a.bracketPhases)
            {
                BattleTableData.BattleResult target;
                if (b.phaseCode.Equals("QFNL"))
                {
                    target = result.qFinal;

                }
                else if (b.phaseCode.Equals("SFNL"))
                {
                    target = result.halfFinal;
                }
                else if (b.bracketItems.Count == 1)
                {
                    if (a.bracketCode.Equals("BRN")) target = result.final2;
                    else if (b.phaseCode.Equals("FNL-")) target = result.final;
                    else continue;
                }//若超过四分之一决赛,舍弃
                else continue;
                foreach (var c in b.bracketItems)
                {
                    target.description = c.eventUnit.description;
                    BattleTableData.BattleResult.MatchResult matchResult = new BattleTableData.BattleResult.MatchResult();

                    bool isWinner;
                    BattleTable.Bracket.BracketPhases.BracketItems.BracketCompetitors bracketCompetitors;
                    //参赛一
                    bracketCompetitors = c.bracketCompetitors[0];
                    isWinner = (bracketCompetitors.cp_wlt.Equals("W"));
                    if (bracketCompetitors.participant != null)
                        matchResult.competitor1 = new BattleTableData.BattleResult.MatchResult.Competitor(bracketCompetitors.participant.organisation.code, bracketCompetitors.participant.shortName, bracketCompetitors.cp_result, isWinner);
                    else matchResult.competitor1 = new BattleTableData.BattleResult.MatchResult.Competitor("", "轮空", "", false);
                    //参赛二
                    bracketCompetitors = c.bracketCompetitors[1];
                    isWinner = (bracketCompetitors.cp_wlt.Equals("W"));
                    if (bracketCompetitors.participant != null)
                        matchResult.competitor2 = new BattleTableData.BattleResult.MatchResult.Competitor(bracketCompetitors.participant.organisation.code, bracketCompetitors.participant.shortName, bracketCompetitors.cp_result, isWinner);
                    else matchResult.competitor2 = new BattleTableData.BattleResult.MatchResult.Competitor("", "轮空", "", false);
                    target.allMatch.Add(matchResult);
                }


            }

        }
        File.WriteAllText(savePath, JsonConvert.SerializeObject(result));
        Console.WriteLine("success");
        Console.WriteLine(savePath);
        Console.WriteLine(httpPath);

    }
    catch (Exception e)
    {
        Console.WriteLine("false");
        Console.WriteLine("false");
        Console.WriteLine("false");
        Console.WriteLine(savePath);
        Console.WriteLine(httpPath);
        Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine();
    }
    return result;

}

获取每日赛程判断了日期是否合法(虽然前端传的应该都是合法的)

在具体的实现过程中出现的存在参赛者但是不存在比赛数据的情况进行处理以及多个比赛结果最多保留前三名的数据进行显示

public GetResult<List<Units>> GetDayResult(string Date)
{
    
    GetResult <List<Units>> result = new GetResult<List<Units>>();

    string[] strings = Date.Split('-');
    int month= int.Parse(strings[1]), day= int.Parse(strings[2]);

    if (string.IsNullOrEmpty(Date) || strings.Length != 3 || !strings[0].Equals("2024") || month < 7|| month>8||(month==7&& (day <24|| day >31))||(month==8&&(day<1||day>11)))
    {
        result.code = 0;
        result.message = "日期错误!";
        Console.WriteLine($"参数  {Date} 的数据获取错误!");
        return result;
    }

    string savePath = Path.Combine(DataPraser.DayResultSavePath, Date + ".json");
    
    DateMatchDetails data;
    if (saveDayResult.ContainsKey(Date))
    {
        result.data = saveDayResult[Date].data;
    }
    else
    {
        if (File.Exists(savePath))
        {
            string jsonData = File.ReadAllText(savePath);
            data = JsonConvert.DeserializeObject<DateMatchDetails>(jsonData);
        }
        else
        {
            string httpPath = DataPraser.GetDailyFixturesHttp(Date);
            var jsonResult = DataPraser.Communicable(httpPath);
            data = JsonConvert.DeserializeObject<DateMatchDetails>(jsonResult.Item2);

            foreach (var a in data.units)
            {
                a.startDate = a.startDate.Substring(11, 5);
                if (a.competitors == null) continue;
                if (a.competitors.Count > 3)
                {
                    a.competitors.RemoveRange(3, a.competitors.Count - 3);
                }
                //存在参赛者但是不存在比赛数据,则不返回具体比赛情况
                if (a.competitors.Count > 0 && a.competitors[0].results == null) a.competitors = null;
            }
            ////进行筛选 个人赛保留三位competitor的数据

            File.WriteAllText(savePath, JsonConvert.SerializeObject(data));
            saveDayResult.Add(Date, result);
            useCheck.Add(new StringIntPair(Date, 5));
        }
        result.data = data.units;

    }
    //清理
    foreach (var a in useCheck)
    {
        a.value2--;
        if (a.value2 < 0) saveDayResult.Remove(a.value1);
        Console.WriteLine($"{a.value1}   {a.value2}");
    }
    useCheck.RemoveAll(x => x.value2 < 0);

    return result;
}

比赛详情的获取,由于某个比赛的所有比赛数据中并没有比分的数据,因此需要通过获取到的数据结合获取具体比赛result的路由来获取比分数据因此需要多次访问奥运官方数据,延迟较大,在获取过数据后进行保存使用。由于第一步获取的schedules数据中是某种比赛大类的所有比赛数据因此需要根据传入的eventId进行区分然后再对数据进行分析

public static ResultCombineJsonUse GetResultCombine(string disciplineCode, string eventId)
{
    string savePath = Path.Combine(ResourcesPath, "ResultCombine", eventId.Substring(0,11)+".json");
    if (File.Exists(savePath))
    {
        string json=File.ReadAllText(savePath);
        ResultCombineJsonUse result = JsonConvert.DeserializeObject<ResultCombineJsonUse>(json);
        return result;

    }

    string http = DataPraser.GetSchedulesHttp(disciplineCode);
    var jsonResult = DataPraser.Communicable(http);
    if (!jsonResult.Item1|| !eventId.Substring(0,3).Equals(disciplineCode))
    {
        Console.WriteLine($"{http}   数据获取错误");
        return null;
    }
    GetSchelusClass getSchelusClass;
    getSchelusClass = JsonConvert.DeserializeObject<GetSchelusClass>(jsonResult.Item2);
    eventId = eventId.Substring(0, 11);
    getSchelusClass.schedules.RemoveAll(x => !x.code.Contains(eventId)||!x.status.code.Equals("FINISHED"));

    List<ResultCombine> allResults = new List<ResultCombine>();
    foreach (var a in getSchelusClass.schedules)
    {
        string resultHttp = DataPraser.GetScheduleResultsHttp(disciplineCode, a.code);
        var jsonResult_mid = DataPraser.Communicable(resultHttp);
        if (!jsonResult_mid.Item1)
        {
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine(resultHttp);
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("");
            continue;
        }
        GetResultClass mid = JsonConvert.DeserializeObject<GetResultClass>(jsonResult_mid.Item2);

        if (!mid.results.schedule.status.code.Equals("FINISHED")) continue;
        if (mid.results.items.Count > 2)
        {
            Console.WriteLine($"{http}   该项目数据结构不支持期望");
            return null;
        }


        ResultCombine target = allResults.Find(x => x.stateName.Equals(mid.results.eventUnit.shortDescription));
        if (target == null || target.Equals(default(ResultCombine)))
        {
            target = new ResultCombine() { stateName = mid.results.eventUnit.shortDescription };
            allResults.Add(target);
        }
        NewMatchResult matchResult = new NewMatchResult();
        GetResultClass.Result.Item item;  
        item = mid.results.items[0];
        matchResult.competitor1 = new MatchResult.Competitor(item.participant.organisation.code, item.participant.shortName, item.resultData, !string.IsNullOrEmpty(item.resultWLT) &&item.resultWLT.Equals("W"));
        item = mid.results.items[1];
        matchResult.competitor2 = new MatchResult.Competitor(item.participant.organisation.code, item.participant.shortName, item.resultData, !string.IsNullOrEmpty(item.resultWLT) && item.resultWLT.Equals("W"));
        matchResult.startDate = mid.results.schedule.startDate.Substring(0,16);
        target.results.Add(matchResult);
    }
    //排序
    allResults.Sort((x, y) => x.results.Count.CompareTo(y.results.Count));
    foreach (var a in allResults)
    { 
        a.results.Sort((x, y) => TestCompare(x,y));
    }
    ResultCombineJsonUse resultCombineJsonUse = new ResultCombineJsonUse();
    resultCombineJsonUse.resultCombines = allResults;
    File.WriteAllText(savePath, JsonConvert.SerializeObject(resultCombineJsonUse));
    return resultCombineJsonUse;

}

七、遇到的困难和解决方法

1、前端

遇到的困难

对阵图的连线,原本是想使用svg或者 < canvas > 在晋级赛之间连线,但是都比较麻烦,后来尝试使用图片完成连线,但是经过缩放会导致连不上

解决方法

参考官网使用伪元素设置边框,最终用相似的思路在晋级赛之间填充两个div容器,每个div中包含三个div,使用flex完成布局,加上所需要的边框完成连线,同时使用%和vh,vw单位,防止缩放导致布局混乱

2、 后端

遇到的困难

由于获取的数据是通过奥运官网http获取的,但是不同的比赛的数据格式和特殊情况是不同的难以直接通过一两个获取到的数据分析出来,因此在对数据的处理过程中,遇到各种特殊情况,比如比赛取消,选手退赛等,这些特殊情况通常需要对代码进行修改。

解决方法

我的解决方法是在出现问题的时候,分析错误原因,以此对代码进行修改和完善,暂时没有好的处理方法

八、心路历程和收获

心路历程

222200413:

虽然我之前学过一些前端知识,具有一定基础,但在开发过程中仍然遇到了不少挑战。之前使用的是 JavaScript,这次决定尝试 TypeScript。在编码实现的过程中,发现了TypeScript与 JavaScript 的一些差异,例如类型定义和属性访问,这让我花了不少时间熟悉 TypeScript。此外,我还学习了新工具 Apifox 的使用,发现它大大简化了与后端的对接,并且通过 Apifox 集成的 Mock 功能,能够更方便地进行前端测试。在这次开发过程中,我学习并运用了许多新知识,使我对 Vue 3 的使用以及与后端对接的细节有了更深入的理解。总体而言,收获颇丰。

222200415:

在开发奥运赛事信息系统项目初期,我满怀热情投入开发,但遇到不少挑战。首先,数据获取是一大难题。我从奥运官网通过HTTP请求获取数据,却发现数据格式不统一,数据结构差异大,导致数据解析和处理变得复杂。有时参赛者信息完整但比赛数据缺失,我不得不花费大量时间清洗和补充数据。此外,处理比赛详情时,某些比赛数据缺少比分信息,需要多次访问奥运官方数据,导致系统响应变慢,用户体验下降。为解决这一问题,我引入缓存机制,将已获取数据保存在服务器中,减少后续访问延迟。在整个开发过程中,我不断迭代和优化代码,遇到问题就仔细分析并尝试解决。虽然充满挑战,但每当看到系统正确展示数据、处理特殊情况时,我都感到无比满足和自豪。这个项目让我深刻体会到,软件开发不仅是技术挑战,更是耐心和毅力的考验。

收获

222200413:

通过这次结对作业,我学习了很多新知识

1.能力提升:这次结对作业前端部分主要由我独立完成,这显著提高了我的前端开发能力,尤其是在项目协作和沟通方面的技能。

2.新知识学习:学习了许多新知识,包括 TypeScript 的使用,相较于 JavaScript,我对类型定义和属性访问有了更深入的理解。

3.Apifox 工具的使用:掌握了 Apifox 这一新工具,特别是其 Mock 功能,大大简化了与后端的对接流程,使得前端测试更加高效。

4.Vue Router 的理解:加深了对 Vue Router 的理解,特别是学习了路由守卫的使用,能够在页面跳转之前获取数据,确保数据的正确性和完整性。

5.数据本地持久化:加深了localStorage理解,使用localStorage,实现数据的本地持久化,确保用户在页面刷新或关闭后仍能保留必要的信息。

222200415:

通过这个项目,我收获了以下这些宝贵的经验和技能:

1.数据处理能力:我学会了如何高效地获取、解析和处理数据,特别是在数据格式不统一和存在特殊情况时。

2.问题解决能力:在面对各种问题和挑战时,我学会了如何分析问题原因、制定解决方案,并不断地对代码进行迭代和优化。

3.团队协作与沟通:虽然这个项目主要是我独自完成的,但在与前端开发人员和测试人员的沟通中,我学会了如何更好地协作和沟通,以确保项目的顺利进行。

4.技术视野的拓展:在开发过程中,我接触到了许多新的技术和工具,如HTTP请求、数据缓存等,这些都拓宽了我的技术视野。

5.心态的调整:在面对困难和挑战时,我学会了保持冷静和乐观的心态,相信通过不断的努力和学习,一定能够克服一切困难。

九、评价结对队友

222200413:

在这次结对作业中,我的队友展现了出色的团队协作能力和极强的行动力。他能够迅速定位并获取所需的数据,善于进行信息的筛选和“裁剪”,有效地减少了冗余数据。此外,他非常乐于倾听他人的意见,积极参与讨论,共同解决问题。在面对挑战时,他总是保持积极的态度,一起探讨解决方案,展现出良好的沟通能力和团队精神。能够与他合作完成这次作业,我感到非常高兴,也让我受益匪浅。

222200415:

我的队友展现出了扎实的专业基础和不断学习的态度。他总是愿意倾听他人的意见,能够迅速掌握新技术和工具,并将其有效应用于解决实际问题中。他能熟练运用前端的各种框架,实现流畅友好的交互编码实现,并且在面对复杂的问题时能够迅速分析问题的本质,在结对过程中体现了强大的技术能力。此次结对实践是一次非常愉快和富有成效的经历,期待我们能够继续保持这种积极向上的态度,继续学习进步。

...全文
17 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
AJAX——新手快车道 前言 AJAX是什么? 首先、AJAX是一种很酷的技术,一旦采用了AJAX,就能让你的Web页面, 你的网站,甚至连同你们公司,都变得很酷。在Web2.0的时代里,不使用一点 AJAX技术的网站,就会显得很老土,很落伍。 但是,这样的理解,其实是很肤浅的。仅仅是从一个外行,从一个使用者的 角度出发,来理解AJAX,就像我在本书的第一章AJAX我也行中那样,开发 出很愚蠢,甚至都没有资格被称之为AJAX应用的纯IE、XMLHTTP应用。 AJAX更酷的一点在于,对于传统的Web开发人员来说,AJAX所运用的, 是更加先进的,更加标准化的,更加和谐高效的,完整的Web开发技术体系。 遵循这样的体系开发Web应用,能让你的开发过程变得更加轻松,也能使你们 的开发团队,显得很酷。在Web2.0 的时代里,还在采用过时的技术来开发 Web,会显得很老土,很落伍。 AJAX的相关组成技术,每一个都已经出现了N年以上了,对这些技术的 组合运用,也远远早于AJAX这个名词出现之前。所以,我真正敬佩的,并非提 出 AJAX这个缩写的Jesse James Garrett。而是那些早在N年以前,就已经在探索、 实践的先行者,他们始终在追求的:是更好的用户体验,以及更好的开发体验。 这样的精神,才是最可宝贵的,也是最值得我们学习的。许多年过去以后,当我 们再回头来看当年的这些热门技术,也许早已经变得老土,变得落伍了。在这样 的历程中,哪些人会成长为高手?会成长为大师呢?就是那些永不满足,永远 在追求更好的用户体验,永远在追求更好的开发体验的人! 新手如何上路 软件开发这个领域,永远都在飞速发展,大家都必须不断的学习新的知识、 技能、框架、IDE、甚至新的语言。传说中的骨灰级高手们,就像传说中的大侠, 任何武器、哪怕是一块木头到了他们手里,也能发挥惊人的威力,人家练了几十 年的看家本领,他们随手使来,也竟然像是打娘胎里就开始练了一样。为什么? 就算不吹那么玄的,平常我们能够碰到的那些老手,在学新东西的时候, 也比那些新手学得更快,理解得更深,运用得更熟练。而新手们呢?往往就会漫 无头绪,焦头烂额,以一副张着茫然的大眼睛的经典表情,出现在各大论坛的 新手求助区里。他们欠缺的,究竟是什么呢?为什么老手学新东西,就没遇到那 么多困难呢? 泛泛地说,自然是经验上的欠缺。仔细地说来,又可以分为三个方面: 一、本质,一种技术与另一种技术之间,往往会有本质上的相通之处,当你 对一种技术的理解与思考越来越深入时,学习一种新技术也会更加容易。触类旁 通,举一反三的能力,就是来自于对于技术本质的追寻。 二、地图,本质上或多或少的相通,也提示着我们技术之间的相互关联,当 你了解的技术越多,了解得越是深入,在你的内心,就能建立起越发清晰的技 术地图。各种知识都有一个自然、合理的位置。那么当一个老手要学习一门新技术 的时候,他其实并非在探索一个全新的、未知的领域,而是有很多脉络可寻,也 很多已知可以帮助他们快速了解未知。 三、技巧,面对同样的未知,面对同样的难题,新手们一筹莫展,而老手们 却掌握着更多的技巧和手段,帮助他们试探可能性、缩小问题的范围、迅速定位 问题、不犯明显愚蠢的错误、甚至能够列举出更具命中力的搜索关键词,而这些 技巧,都帮助老手在前进的道路上,更少跌倒,即使跌倒,也能更快的爬起来。 作为一本写给新手的入门书籍,我们希望展现给读者的,是一个老手如何 学习新技术的过程。我们相信,这样的一个学习过程,对于新手来说,是更具有 价值的。 何谓快车道 必须老老实实的承认,我吹牛了!老手虽然会比新手学习得更快一些,但 是也同样会碰到麻烦,遇到障碍,感觉头痛。如果没有真正的专家的指导,我不 可能如此迅速地将AJAX掌握到目前这样的程度,要真是让我自学三个月,然 后就写出书来的话,那真是在骗钱了。 老手能够快速学习的另一个重要的诀窍是:认识很多牛人朋友 如果没有李锟与赵泽欣的专家级指导与帮助,如果没有与李锟AJAX结对 编程的体验,如果没有三个人在MSN上无数次的长聊,我想要在短期内建立起: 对于AJAX本质的理解; 对于整个AJAX以及相关技术地图的理解; 对于AJAX编程开发所需要的很多技巧、手段的掌握; 几乎是不可能的。 如果没有(N多需要感谢的人)的(N多方面的帮助),我们这本书,也 不可能以现在这样的深度,以(N个月)内完成的速度,送到读者的面前。 希望这本书,能够对大家快速学习AJAX,有所帮助。

110

社区成员

发帖
与我相关
我的任务
社区管理员
  • FZU_SE_teacherW
  • 助教赖晋松
  • D's Honey
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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