提交 fdca879e 编写于 作者: 式部

fix

上级 1f5bd8ea
......@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<link rel="icon" type="image/svg+xml" href="/icon.png"/>
<link href="https://cdn.jsdelivr.net/npm/cn-fontsource-smiley-sans-oblique-regular@1.0.1/font.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Vite + React 18 + TS + TailwindCSS + ESLint + </title>
......
export interface Schedule {
UtcDateTime: string;
Date: string;
Time: string;
TimeZoneDisplayName: string;
}
export const getSchedules = async () => {
const response = await fetch('/api/fina/competitions/3337/schedule');
return response.json();
};
export interface Competition {
Id: string;
DisciplineName: string;
export const getResults = async (hash: string) => {
const response = await fetch(`/api/fina/events/${hash}`);
return await response.json();
};
export const getDailySchedule = async () => {
const schedules = (await getSchedules()).map((item: any) => {
return {
Date: item.Date,
id: item.DisciplineId,
Name: item.DisciplineName + ' ' + item.Name,
};
});
let dailySchedule = schedules.reduce((acc: any, cur: any) => {
if (!acc[cur.Date]) {
acc[cur.Date] = [];
}
acc[cur.Date].push(cur);
return acc;
}, {});
const map = new Map();
for (const key in dailySchedule) {
for (const [index, item] of dailySchedule[key].entries()) {
if (map.has(item.id)) {
dailySchedule[key][index].data = map.get(item.id);
continue;
}
const data = await getResults(item.id);
const flag = data['Heats'][0]['Results'][0]['Competitors'] === null;
dailySchedule[key][index].data = data['Heats'][0]['Results'].map((result: any) => {
return {
rank: result.Rank,
athlete: result.FullName,
country: result.NAT,
age: flag ? result.AthleteResultAge : (result.Competitors[0].AthleteResultAge || '?') + ' / ' + result.Competitors[1].AthleteResultAge,
points: result.TotalPoints,
ptsBehind: result.PointsBehind || '0'
};
});
map.set(item.id, dailySchedule[key][index].data);
}
}
dailySchedule = Object.entries(dailySchedule).map(([key, value]) => {
return {
Date: key,
data: value
};
});
return dailySchedule;
};
export interface RankListData {
rank: number;
athlete: string;
country: string;
age: number;
points: number;
}
export const getCompetitions = async (): Promise<Competition[]> => {
const response = await fetch('https://swimming.abdecd.xyz/api/fina/competitions/3337/events');
const data = await response.json() as { Sports: [{ DisciplineList: Competition[] }] };
return data.Sports?.[0]?.DisciplineList;
export const getRankList = async () => {
const hash = '108c795d-5e4f-4dc6-acea-0bc70bfd1928';
const data = await getResults(hash);
const result = data['Heats'][0]['Results'];
const rankList: RankListData[] = [];
for (const item of result) {
rankList.push({
rank: item.Rank,
athlete: item.FullName,
country: item.NAT,
age: item.AthleteResultAge,
points: item.TotalPoints
});
}
return rankList;
};
getCompetitions().then(console.log);
export const getResults = async (hash: string) => {
const response = await fetch(`https://swimming.abdecd.xyz/api/fina/events/${hash}`);
return await response.json();
export const getRankListAthletePhotos = async () => {
const hash = '108c795d-5e4f-4dc6-acea-0bc70bfd1928';
return await getAthletePhotosById(hash);
};
export const getAthletePhotosById = async (id: string) => {
const data = await getResults(id);
const result = data['Heats'][0]['Results'];
const rankListData: any[] = [];
for (const item of result) {
const ResultId = item.ResultId.substring(1);
const dat = (await getAthletePhoto(ResultId))[0];
rankListData.push(dat ? dat['imageUrl'] : '/defaultAvatar.webp');
}
return rankListData;
}
export const getCountryFlag = (country: string): string => {
if (!country) {
return '/defaultAvatar.webp';
}
return `https://www.worldaquatics.com/resources/v2.11.4/i/elements/flags/${country.toLowerCase()}.png`;
};
......
......@@ -11,8 +11,8 @@
display: inline-block;
width: 100%;
height: 100%;
background: linear-gradient(90deg, rgba(0, 0, 0, 0.04) 25%, rgba(0, 0, 0, 0.1) 50%, rgba(0, 0, 0, 0.04) 75%);
background: linear-gradient(90deg, rgba(255, 255, 255, 0.24) 25%, rgba(255, 255, 255, 0.34) 50%, rgba(255, 255, 255, 0.24) 75%);
background-size: 400% 100%;
border-radius: 4px;
animation: mika-skeleton-loading 1.3s ease infinite;
}
\ No newline at end of file
}
import Home from '../Home/Home';
import RankList from '../RankList/RankList';
import DailySchedule from '../DaliySchedule/DailySchedule';
import MedalTally from '../MedalTally/MedalTally';
import LearnMore from '../LearnMore/LearnMore';
import {getSchedules} from '../../common/api/api';
import './App.less';
import Header from '../../component/Header/Header';
const data = [
{
rank: 1,
name: 'John',
score: 100
}, {
rank: 2,
name: 'Doe',
score: 90
}, {
rank: 3,
name: 'Jane',
score: 80
}, {
rank: 4,
name: 'Dane',
score: 70
}, {
rank: 5,
name: 'Jone',
score: 60
}, {
rank: 6,
name: 'Jone',
score: 50
}, {
rank: 7,
name: 'Jone',
score: 40
}, {
rank: 8,
name: 'Jone',
score: 30
}, {
rank: 9,
name: 'Jone',
score: 20
}, {
rank: 10,
name: 'Jone',
score: 10
}
];
const dailyData = [
{
title: 'Day 1',
data: [
{
rank: 1,
athlete: 'John',
country: 'USA',
age: 20,
points: 100,
ptsBehind: 0
}, {
rank: 2,
athlete: 'Doe',
country: 'USA',
age: 21,
points: 90,
ptsBehind: 10
}, {
rank: 3,
athlete: 'Jane',
country: 'USA',
age: 22,
points: 80,
ptsBehind: 20
}, {
rank: 4,
athlete: 'Dane',
country: 'USA',
age: 23,
points: 70,
ptsBehind: 30
}, {
rank: 5,
athlete: 'Jone',
country: 'USA',
age: 24,
points: 60,
ptsBehind: 40
}
]
}, {
title: 'Day 2',
data: [
{
rank: 1,
athlete: 'John',
country: 'USA',
age: 20,
points: 100,
ptsBehind: 0
}, {
rank: 2,
athlete: 'Doe',
country: 'USA',
age: 21,
points: 90,
ptsBehind: 10
}, {
rank: 3,
athlete: 'Jane',
country: 'USA',
age: 22,
points: 80,
ptsBehind: 20
}, {
rank: 4,
athlete: 'Dane',
country: 'USA',
age: 23,
points: 70,
ptsBehind: 30
}, {
rank: 5,
athlete: 'Jone',
country: 'USA',
age: 24,
points: 60,
ptsBehind: 40
}
]
}
];
const content = {
title: 'WORLD AQUATICS - THE GLOBAL HOME OF AQUATIC SPORTS',
content: ['World Aquatics, formerly known as the Fédération Internationale de Natation (FINA), is the sole and exclusive world governing body for all Aquatics.  Since June 2021, under the presidency of Captain Husain Al Musallam, World Aquatics comprises 209 National Member Federations in the five continents.',
......@@ -142,14 +12,11 @@ const content = {
};
const App = () => {
getSchedules().then(console.log);
return (<div className="root-container">
<Header/>
<Home/>
<RankList data={data}/>
<DailySchedule data={dailyData}/>
<MedalTally/>
<RankList/>
<DailySchedule/>
<LearnMore {...content}/>
</div>);
};
......
import React from 'react';
import Panel from '../../component/Panel/Panel';
import Title from '../../component/Title/Title';
import DailyScheduleItem from './DailyScheduleItem';
import {theme} from '../../common/theme/theme';
import {getDailySchedule} from '../../common/api/api';
import DailyScheduleItem from './DailyScheduleItem';
import {Skeleton} from '../../component/mika-ui';
export interface DailyScheduleProps extends React.HTMLAttributes<HTMLDivElement> {
data: {
title: string;
const Loading = () => {
return (
<div className="p-4 flex flex-col gap-4 h-96">
<Skeleton type="box" height="30" width="200"/>
<Skeleton type="box" height="30" width="200"/>
<Skeleton type="box" height="30" width="200"/>
<Skeleton type="box" height="30" width="200"/>
</div>
);
};
const DailyScheduleDateItem = (props: {
item: {
Date: string;
data: {
rank: number;
athlete: string;
country: string;
age: number;
points: number;
ptsBehind: number;
Name: string;
data: {
rank: number;
athlete: string;
country: string;
age: number;
points: number;
ptsBehind: number;
}[];
}[];
}[];
}
}) => {
const {item} = props;
const [isOpen, setIsOpen] = React.useState(false);
return (<>
{
isOpen ? (<div
className="flex flex-col gap-4 bg-white m-4 rounded-lg shadow-xl"
>
<div
className="flex justify-between items-center text-black p-4 select-none text-2xl cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
>
<div>{item.Date}</div>
<div>{isOpen ? '-' : '+'}</div>
</div>
<div className="bg-black h-0.5 -mt-3 w-full rounded-lg"/>
<div className="overflow-y-auto">
{item.data && item.data.map((i: {
Name: string;
data: {
rank: number;
athlete: string;
country: string;
age: number;
points: number;
ptsBehind: number;
}[];
}, index: React.Key | null | undefined) => (
<DailyScheduleItem key={index} title={i.Name} data={i.data}/>
))}
</div>
</div>
) : (
<div
className="flex flex-col gap-4 bg-white m-4 rounded-lg shadow-xl"
>
<div
className="flex justify-between items-center text-black p-4 select-none text-2xl cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
>
<div>{item.Date}</div>
<div>{isOpen ? '-' : '+'}</div>
</div>
</div>
)
}
</>
);
};
}
const DailySchedule = () => {
const [list, setList] = React.useState([]);
const [loading, setLoading] = React.useState(true);
const DailySchedule = (props: DailyScheduleProps) => {
const {
data,
...rest
} = props;
React.useEffect(() => {
getDailySchedule().then((res) => {
setList(res);
setLoading(false);
});
}, []);
if (loading) {
return (
<div
className="flex flex-col h-screen"
id="dailyschedule"
style={{
backgroundColor: theme.background
}}
>
<div
className="flex flex-col gap-4 text-white"
style={{
margin: '12vh 10vw'
}}
>
<Title title="Daily Schedule"/>
<Panel>
<Loading/>
</Panel>
</div>
</div>
);
}
return (
<div
......@@ -32,7 +126,6 @@ const DailySchedule = (props: DailyScheduleProps) => {
style={{
backgroundColor: theme.background
}}
{...rest}
>
<div
className="flex flex-col gap-4 text-white"
......@@ -42,14 +135,25 @@ const DailySchedule = (props: DailyScheduleProps) => {
>
<Title title="Daily Schedule"/>
<Panel>
<div className="text-black text-4xl bg-white p-4 rounded-tl-lg rounded-tr-lg select-none mb-4">
{new Date().toLocaleDateString()}
</div>
<div className="overflow-y-auto">
{data.map((item, index) => (
<DailyScheduleItem key={index} title={item.title} data={item.data}/>
))}
</div>
{
list && list.map((item: {
Date: string;
data: {
Name: string;
data: {
rank: number;
athlete: string;
country: string;
age: number;
points: number;
ptsBehind: number;
}[];
}[];
}, index) => {
return (<DailyScheduleDateItem key={index} item={item}/>);
})
}
</Panel>
</div>
</div>
......
import React, {useState} from 'react';
import './DailyScheduleItem.less';
import {getCountryFlag} from '../../common/api/api';
export interface DailyScheduleItemProps {
title: string;
......@@ -18,11 +19,12 @@ const DailyScheduleItem = (props: DailyScheduleItemProps) => {
title,
data
} = props;
console.log(data);
const [isOpen, setIsOpen] = useState(false);
return (
<div
className="flex flex-col gap-4 bg-white m-4 rounded-lg shadow-xl"
className="flex flex-col gap-4 bg-white mb-4 ml-4 mr-4 rounded-lg shadow-xl"
>
<div
className="flex justify-between items-center text-black p-4 select-none text-2xl cursor-pointer"
......@@ -36,23 +38,30 @@ const DailyScheduleItem = (props: DailyScheduleItemProps) => {
<div className="pb-4">
<div className="item-container grid grid-cols-6 gap-4 text-black text-2xl p-4">
<div className="flex justify-center">Rank</div>
<div className="flex justify-center">Athlete</div>
<div className="flex justify-center">Country</div>
<div className="flex justify-center justify-self-start">Athlete</div>
<div className="flex justify-center justify-self-start">Country</div>
<div className="flex justify-center">Age</div>
<div className="flex justify-center">Points</div>
<div className="flex justify-center">Pts Behind</div>
<div className="bg-black h-0.5 w-full col-span-6 rounded-lg"/>
{data.map((item, index) => (
<div key={index} className="item col-span-6 grid grid-cols-6 gap-4 text-black text-2xl p-1 rounded-2xl"
<div key={index}
className="item col-span-6 grid grid-cols-6 gap-4 text-black text-2xl p-1 rounded-2xl"
style={{
boxShadow: '2px 2px 12px rgba(0, 0, 0, 0.1)'
}}>
<div className="flex justify-center">{item.rank}</div>
<div className="flex justify-center">{item.athlete}</div>
<div className="flex justify-center">{item.country}</div>
<div className="flex justify-center">{item.age}</div>
<div className="flex justify-center">{item.points}</div>
<div className="flex justify-center">{item.ptsBehind}</div>
<div className="flex justify-center items-center">{item.rank}</div>
<div className="flex justify-center justify-self-start items-center">
{item.athlete}
</div>
<div className="flex justify-center items-center justify-self-start gap-4">
<img src={getCountryFlag(item.country)} alt="country"
className="w-6 h-6" loading="lazy"/>
{item.country}
</div>
<div className="flex justify-center items-center">{item.age}</div>
<div className="flex justify-center items-center">{item.points}</div>
<div className="flex justify-center items-center">{item.ptsBehind}</div>
</div>
))}
</div>
......
import React from 'react';
import React, {useEffect} from 'react';
import {theme} from '../../common/theme/theme';
import Panel from '../../component/Panel/Panel';
import Title from '../../component/Title/Title';
import {getCountryFlag, getRankList, getRankListAthletePhotos, RankListData} from '../../common/api/api';
export interface RankListProps extends React.HTMLAttributes<HTMLDivElement> {
data: any;
}
const RankList = () => {
const [list, setList] = React.useState<RankListData[]>([]);
const [photoList, setPhotoList] = React.useState<string[]>([]);
useEffect(() => {
getRankList().then((res) => {
setList(res);
});
const RankList = (props: RankListProps) => {
const {
data,
...rest
} = props;
getRankListAthletePhotos().then((res) => {
setPhotoList(res);
});
}, []);
return (
<div
className="flex flex-col h-screen"
id="ranklist"
style={{backgroundColor: theme.background}}
{...rest}
>
<div
className="flex flex-col gap-4"
......@@ -30,12 +33,12 @@ const RankList = (props: RankListProps) => {
<Title title="Rank List"/>
<Panel>
<div className="text-black text-4xl bg-white p-4 rounded-tl-lg rounded-tr-lg select-none mb-4">
Women's Singles
Women 1m Springboard
</div>
<div className="grid grid-cols-5 gap-4 text-white text-2xl">
<div className="flex justify-center">Rank</div>
<div className="flex justify-center">Athlete</div>
<div className="flex justify-center">Country</div>
<div className="flex justify-center justify-self-start">Athlete</div>
<div className="flex justify-center justify-self-start">Country</div>
<div className="flex justify-center">Age</div>
<div className="flex justify-center">Points</div>
<div className="bg-white h-1 w-full col-span-5 rounded-lg"/>
......@@ -43,15 +46,23 @@ const RankList = (props: RankListProps) => {
<div
className="overflow-y-auto grid grid-cols-5 gap-4 text-white text-2xl pt-4 pb-4 rounded-2xl"
>
{data.map((item: any, index: number) => (
{list && list.map((item: any, index: number) => (
<React.Fragment key={index}>
<div className="flex justify-center" style={{
<div className="flex justify-center items-center" style={{
color: item.rank === 1 ? 'gold' : item.rank === 2 ? 'silver' : item.rank === 3 ? '#cd7f32' : 'white'
}}>{item.rank}</div>
<div className="flex justify-center">{item.name}</div>
<div className="flex justify-center">{item.country}</div>
<div className="flex justify-center">{item.age}</div>
<div className="flex justify-center">{item.points}</div>
<div className="flex justify-center items-center gap-4 justify-self-start">
<img src={photoList[index]} alt="athlete" className="w-10 h-10 rounded-full"
loading="lazy"/>
{item.athlete}
</div>
<div className="flex justify-center items-center gap-4 justify-self-start ">
<img src={getCountryFlag(item.country)} alt="country" className="w-10 h-10"
loading="lazy"/>
{item.country}
</div>
<div className="flex justify-center items-center">{item.age}</div>
<div className="flex justify-center items-center">{item.points}</div>
</React.Fragment>
))}
</div>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册