Skip to content

Commit 34202be

Browse files
committed
feat: writeup review
1 parent d59bc94 commit 34202be

File tree

13 files changed

+233
-50
lines changed

13 files changed

+233
-50
lines changed

GZCTF/ClientApp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@mdi/js": "^7.0.96",
2424
"@mdi/react": "^1.6.1",
2525
"@microsoft/signalr": "^7.0.0",
26+
"@types/react-pdf": "^5.7.4",
2627
"dayjs": "^1.11.6",
2728
"echarts": "^5.4.0",
2829
"echarts-for-react": "^3.0.2",

GZCTF/ClientApp/pnpm-lock.yaml

Lines changed: 43 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

GZCTF/ClientApp/src/Api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ export interface GameInfoModel {
548548
* Writeup 附加说明
549549
* @minLength 1
550550
*/
551-
wpnote: string
551+
wpnote?: string
552552
}
553553

554554
/**
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { FC, useState } from 'react'
2+
import { Document, Page, pdfjs } from 'react-pdf'
3+
import 'react-pdf/dist/esm/Page/AnnotationLayer.css'
4+
import 'react-pdf/dist/esm/Page/TextLayer.css'
5+
import { createStyles, Paper, ScrollArea, Stack } from '@mantine/core'
6+
import { showErrorNotification } from '@Utils/ApiErrorHandler'
7+
8+
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`
9+
10+
interface PDFViewerProps {
11+
url?: string
12+
height?: number | string
13+
}
14+
15+
const useStyles = createStyles((theme, { height }: PDFViewerProps) => ({
16+
layout: {
17+
marginLeft: theme.spacing.md,
18+
marginRight: theme.spacing.md,
19+
borderRadius: theme.radius.md,
20+
21+
[theme.fn.largerThan(1100 + theme.spacing.md * 2)]: {
22+
maxWidth: 900,
23+
marginLeft: 'auto',
24+
marginRight: 'auto',
25+
},
26+
27+
'& canvas': {
28+
minWidth: '100% !important',
29+
maxWidth: '100% !important',
30+
height: 'auto !important',
31+
borderRadius: theme.radius.md,
32+
},
33+
34+
'& .react-pdf__Page__textContent': {
35+
display: 'none',
36+
},
37+
},
38+
39+
doc: {
40+
maxHeight: height,
41+
},
42+
43+
paper: {
44+
marginBottom: theme.spacing.md,
45+
},
46+
}))
47+
48+
const PDFViewer: FC<PDFViewerProps> = (props) => {
49+
const [numPages, setNumPages] = useState(0)
50+
const { classes } = useStyles(props)
51+
52+
return (
53+
<ScrollArea className={classes.layout} type="never">
54+
<Document
55+
file={props.url}
56+
className={classes.doc}
57+
onLoadSuccess={({ numPages }) => {
58+
setNumPages(numPages)
59+
}}
60+
onLoadError={showErrorNotification}
61+
>
62+
<Stack>
63+
{Array.from(new Array(numPages), (el, index) => (
64+
<Paper className={classes.paper} key={`page_${index + 1}`}>
65+
<Page width={900} pageNumber={index + 1} renderAnnotationLayer={false} />
66+
</Paper>
67+
))}
68+
</Stack>
69+
</Document>
70+
</ScrollArea>
71+
)
72+
}
73+
74+
export default PDFViewer
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import dayjs from 'dayjs'
2+
import { FC } from 'react'
3+
import { ActionIcon, Avatar, Card, Group, PaperProps, Stack, Text } from '@mantine/core'
4+
import { mdiDownload } from '@mdi/js'
5+
import { Icon } from '@mdi/react'
6+
import { WriteupInfoModel } from '@Api'
7+
8+
interface TeamWriteupCardProps extends PaperProps {
9+
writeup: WriteupInfoModel
10+
selected?: boolean
11+
onClick: () => void
12+
}
13+
14+
const TeamWriteupCard: FC<TeamWriteupCardProps> = ({ writeup, selected, ...props }) => {
15+
return (
16+
<Card
17+
{...props}
18+
p="sm"
19+
shadow="sm"
20+
sx={(theme) => ({
21+
border: selected
22+
? `2px solid ${theme.colors.brand[theme.colorScheme === 'dark' ? 8 : 6]}`
23+
: 'none',
24+
cursor: 'pointer',
25+
})}
26+
>
27+
<Group noWrap spacing={3} position="apart">
28+
<Group noWrap position="apart">
29+
<Avatar src={writeup.team?.avatar} size="md">
30+
{writeup.team?.name?.slice(0, 1)}
31+
</Avatar>
32+
<Stack spacing={0}>
33+
<Text lineClamp={1} weight={600}>
34+
{writeup.team?.name}
35+
</Text>
36+
<Text lineClamp={1} size="xs" color="dimmed">
37+
{dayjs(writeup.uploadTimeUTC).format('YYYY-MM-DD HH:mm')}
38+
</Text>
39+
</Stack>
40+
</Group>
41+
<ActionIcon onClick={() => window.open(writeup.url, '_blank')}>
42+
<Icon path={mdiDownload} size={1} />
43+
</ActionIcon>
44+
</Group>
45+
</Card>
46+
)
47+
}
48+
49+
export default TeamWriteupCard

GZCTF/ClientApp/src/pages/admin/games/Index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const Games: FC = () => {
7676
<Button leftIcon={<Icon path={mdiPlus} size={1} />} onClick={() => setCreateOpened(true)}>
7777
新建比赛
7878
</Button>
79-
<Group position="right">
79+
<Group style={{ width: 'calc(100% - 9rem)' }} position="right">
8080
<ActionIcon size="lg" disabled={page <= 1} onClick={() => setPage(page - 1)}>
8181
<Icon path={mdiArrowLeftBold} size={1} />
8282
</ActionIcon>

GZCTF/ClientApp/src/pages/admin/games/[id]/Notices.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const GameNoticeEdit: FC = () => {
6363
返回上级
6464
</Button>
6565

66-
<Group position="center">
66+
<Group position="right">
6767
<Button
6868
leftIcon={<Icon path={mdiPlus} size={1} />}
6969
onClick={() => {

GZCTF/ClientApp/src/pages/admin/games/[id]/Review.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ const GameTeamReview: FC = () => {
292292
>
293293
返回上级
294294
</Button>
295-
<Group style={{ width: 'calc(100% - 9rem)' }} position="apart">
295+
<Group w="calc(100% - 9rem)" position="left">
296296
<Select
297297
placeholder="全部显示"
298298
clearable

0 commit comments

Comments
 (0)