Skip to content

Commit

Permalink
feat: update scoreboard
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Sep 28, 2022
1 parent 46e1fb6 commit 473a936
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 38 deletions.
11 changes: 7 additions & 4 deletions GZCTF/ClientApp/src/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,11 +1078,8 @@ export interface ScoreboardModel {
*/
updateTimeUTC?: string

/** 参赛组织 */
organizations?: string[] | null

/** 前十名的时间线 */
timeLine?: TopTimeLine[]
timeLines?: Record<string, TopTimeLine[]>

/** 队伍信息 */
items?: ScoreboardItem[]
Expand Down Expand Up @@ -1147,6 +1144,12 @@ export interface ScoreboardItem {
*/
rank?: number

/**
* 参赛所属组织排名
* @format int32
*/
organizationRank?: number | null

/**
* 已解出的题目数量
* @format int32
Expand Down
2 changes: 1 addition & 1 deletion GZCTF/ClientApp/src/components/ChallengePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ChallengePanel: FC = () => {
const [hideSolved, setHideSolved] = useLocalStorage({
key: 'hide-solved',
defaultValue: false,
getInitialValueInEffect: false
getInitialValueInEffect: false,
})

const allChallenges = Object.values(challenges ?? {}).flat()
Expand Down
46 changes: 24 additions & 22 deletions GZCTF/ClientApp/src/components/ScoreboardTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import dayjs from 'dayjs'
import React, { FC, useState } from 'react'
import { useParams } from 'react-router-dom'
import {
Paper,
createStyles,
Expand All @@ -18,7 +17,7 @@ import {
} from '@mantine/core'
import { Icon } from '@mdi/react'
import { useTooltipStyles } from '@Utils/ThemeOverride'
import api, { ChallengeInfo, ChallengeTag, ScoreboardItem, SubmissionType } from '@Api'
import { ChallengeInfo, ChallengeTag, ScoreboardItem, ScoreboardModel, SubmissionType } from '@Api'
import { BloodsTypes, ChallengeTagLabelMap, SubmissionTypeIconMap } from '../utils/ChallengeItem'
import ScoreboardItemModal from './ScoreboardItemModal'

Expand Down Expand Up @@ -143,11 +142,12 @@ const TableHeader = (table: Record<string, ChallengeInfo[]>) => {

const TableRow: FC<{
item: ScoreboardItem
orgRank: number
allRank: boolean
tableRank: number
onOpenDetail: () => void
iconMap: Map<SubmissionType, React.ReactNode>
challenges?: Record<string, ChallengeInfo[]>
}> = ({ item, challenges, onOpenDetail, iconMap, orgRank }) => {
}> = ({ item, challenges, onOpenDetail, iconMap, tableRank, allRank }) => {
const { classes, cx, theme } = useStyles()
const { classes: tooltipClasses } = useTooltipStyles()
const solved = item.challenges?.filter((c) => c.type !== SubmissionType.Unaccepted)
Expand All @@ -157,7 +157,7 @@ const TableRow: FC<{
{item.rank}
</td>
<td className={cx(classes.theadMono, classes.theadFixLeft)} style={{ left: Lefts[1] }}>
{orgRank}
{allRank ? item.rank : item.organizationRank ?? tableRank}
</td>
<td className={cx(classes.theadFixLeft)} style={{ left: Lefts[2] }}>
<Group position="left" spacing={5} noWrap onClick={onOpenDetail}>
Expand Down Expand Up @@ -246,20 +246,21 @@ const BloodData = [

const ITEM_COUNT_PER_PAGE = 30

const ScoreboardTable: FC = () => {
const { id } = useParams()
const numId = parseInt(id ?? '-1')
interface ScoreboardProps {
scoreboard?: ScoreboardModel
organization: string | null
setOrganization: (org: string | null) => void
}

const ScoreboardTable: FC<ScoreboardProps> = ({ scoreboard, organization, setOrganization }) => {
const { classes } = useStyles()
const { data: scoreboard } = api.game.useGameScoreboard(numId, {
refreshInterval: 0,
})
const { iconMap } = SubmissionTypeIconMap(1)
const [activePage, setPage] = useState(1)
const [organization, setOrganization] = useState<string | null>('')

const filtered = !organization
? scoreboard?.items
: scoreboard?.items?.filter((s) => s.organization === organization)
const filtered =
organization === 'all'
? scoreboard?.items
: scoreboard?.items?.filter((s) => s.organization === organization)

const base = (activePage - 1) * ITEM_COUNT_PER_PAGE
const currentItems = filtered?.slice(base, base + ITEM_COUNT_PER_PAGE)
Expand All @@ -270,14 +271,14 @@ const ScoreboardTable: FC = () => {
return (
<Paper shadow="md" p="md">
<Stack spacing="xs">
{scoreboard?.organizations && scoreboard.organizations.length > 0 && (
{scoreboard?.timeLines && Object.keys(scoreboard.timeLines).length > 1 && (
<Group>
<Select
defaultValue=""
data={[
{ value: '', label: '总排行' },
...scoreboard.organizations.map((o) => ({ value: o, label: o })),
]}
defaultValue="all"
data={Object.keys(scoreboard.timeLines).map((o) => ({
value: o,
label: o === 'all' ? '总排行' : o,
}))}
value={organization}
onChange={(org) => {
setOrganization(org)
Expand Down Expand Up @@ -308,7 +309,8 @@ const ScoreboardTable: FC = () => {
currentItems?.map((item, idx) => (
<TableRow
key={base + idx}
orgRank={base + idx + 1}
allRank={organization === 'all'}
tableRank={base + idx + 1}
item={item}
onOpenDetail={() => {
setCurrentItem(item)
Expand Down
14 changes: 7 additions & 7 deletions GZCTF/ClientApp/src/components/TimeLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import ReactEcharts from 'echarts-for-react'
import { FC } from 'react'
import { useParams } from 'react-router-dom'
import { useMantineTheme } from '@mantine/core'
import api from '@Api'
import api, { TopTimeLine } from '@Api'

const TimeLine: FC = () => {
interface TimeLineProps {
timeLine?: TopTimeLine[]
}

const TimeLine: FC<TimeLineProps> = ({ timeLine }) => {
const { id } = useParams()
const numId = parseInt(id ?? '-1')
const theme = useMantineTheme()

const { data: scoreboard } = api.game.useGameScoreboard(numId, {
refreshInterval: 0,
})

const { data: game } = api.game.useGameGames(numId, {
refreshInterval: 0,
revalidateOnFocus: false,
Expand All @@ -25,7 +25,7 @@ const TimeLine: FC = () => {

const last = now < endTime ? now : endTime

const chartData = scoreboard?.timeLine?.map((team) => ({
const chartData = timeLine?.map((team) => ({
type: 'line',
step: 'end',
name: team.name,
Expand Down
24 changes: 20 additions & 4 deletions GZCTF/ClientApp/src/pages/games/[id]/Scoreboard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import { FC } from 'react'
import { FC, useState } from 'react'
import { useParams } from 'react-router-dom'
import { Stack } from '@mantine/core'
import ScoreboardTable from '@Components/ScoreboardTable'
import TimeLine from '@Components/TimeLine'
import WithGameTab from '@Components/WithGameTab'
import WithNavBar from '@Components/WithNavbar'
import api from '@Api'

const Scoreboard: FC = () => {
const { id } = useParams()
const numId = parseInt(id ?? '-1')
const [organization, setOrganization] = useState<string | null>('all')
const { data: scoreboard } = api.game.useGameScoreboard(numId, {
refreshInterval: 0,
})

const currentTimeLine =
scoreboard?.timeLines && (scoreboard?.timeLines[organization ?? 'all'] ?? [])

return (
<WithNavBar width="90%">
<WithNavBar width="90%" isLoading={!scoreboard}>
<WithGameTab>
<Stack>
<TimeLine />
<ScoreboardTable />
<TimeLine timeLine={currentTimeLine} />
<ScoreboardTable
scoreboard={scoreboard!}
organization={organization ?? 'all'}
setOrganization={setOrganization}
/>
</Stack>
</WithGameTab>
</WithNavBar>
Expand Down

0 comments on commit 473a936

Please sign in to comment.