From da060a077c105959a11b666ff6043526fca2fe88 Mon Sep 17 00:00:00 2001 From: JingZi Fang Date: Sat, 19 Aug 2023 22:32:22 +0800 Subject: [PATCH] ui: make ui interface with json --- packages/core/model/problem.ts | 3 +- packages/declare/problem.ts | 5 +- packages/ui/package.json | 1 + packages/ui/src/app.tsx | 9 +- packages/ui/src/components/problem.tsx | 192 +++++++++- packages/ui/src/handlers/problemHandler.ts | 26 ++ packages/ui/src/pages/login.tsx | 60 +--- packages/ui/src/pages/problemView.tsx | 392 +++++++-------------- packages/ui/src/structure/root.tsx | 13 + packages/ui/src/styles/select.tsx | 11 + yarn.lock | 12 + 11 files changed, 381 insertions(+), 343 deletions(-) create mode 100644 packages/ui/src/handlers/problemHandler.ts diff --git a/packages/core/model/problem.ts b/packages/core/model/problem.ts index 8da7825..8444545 100644 --- a/packages/core/model/problem.ts +++ b/packages/core/model/problem.ts @@ -25,9 +25,8 @@ export interface ProblemSchema { sourceid?: string[]; pid: number; sources?: ProblemSource[]; - content?: ProblemContent; + defaultVersion?: string; version?: Record; - versionDisplay?: Record; tags?: string[]; algorithm?: string[]; timeLimit: number | string; diff --git a/packages/declare/problem.ts b/packages/declare/problem.ts index c5ca35e..d0f06bd 100644 --- a/packages/declare/problem.ts +++ b/packages/declare/problem.ts @@ -23,7 +23,8 @@ export interface StandardProblemStatement extends Record | * 标准格式 / 全局传输格式 * */ export interface Problem { //Standard Problem Schema - statement: StandardProblemStatement; // Statement + version: Record; // Statement + defaultVersion: string; // default title: string; sources: { platform: string; // 中文 @@ -36,7 +37,7 @@ export interface Problem { //Standard Problem Schema platform: string; pid: string; allowPublic: boolean; - }[]; // 可接受的平台及其题目提交位置 + }[]; // 可接受提交的平台及其题目提交位置 history?: { score: string; }; // If user login. diff --git a/packages/ui/package.json b/packages/ui/package.json index f74f9bc..5697139 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -48,6 +48,7 @@ "moment": "^2.29.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", "react-redux": "^8.0.5", "react-router-dom": "^6.9.0", "react-use": "^17.4.0", diff --git a/packages/ui/src/app.tsx b/packages/ui/src/app.tsx index ed1e62e..29d3bc6 100644 --- a/packages/ui/src/app.tsx +++ b/packages/ui/src/app.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { MantineProvider, ColorScheme, createEmotionCache } from '@mantine/core'; +import { MantineProvider, ColorScheme, createEmotionCache, useMantineTheme } from '@mantine/core'; import { BrowserRouter, Route, Routes } from 'react-router-dom'; import { Root } from './structure/root'; import HomePage from './pages/home'; @@ -67,13 +67,14 @@ function App() { }, 'html, body': { backgroundColor: theme.colorScheme === 'dark' ? '#2C2E33 !important' : 'white !important', - } + }, }), shadows: { xs: '0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1);', }, }} > + {window?.web?.type === 'back' ? ( {// eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -87,8 +88,8 @@ function App() { }> } /> } /> - - } /> + + } /> } /> diff --git a/packages/ui/src/components/problem.tsx b/packages/ui/src/components/problem.tsx index af37cbf..5aead6c 100644 --- a/packages/ui/src/components/problem.tsx +++ b/packages/ui/src/components/problem.tsx @@ -1,8 +1,9 @@ import { PlatformToCNName, StandardProblemStatement, StatementToCNName } from 'rmjac-declare/problem'; -import { Box, Button, Code, Group, Space, Text, Tooltip, useMantineTheme } from '@mantine/core'; +import { Alert, Box, Button, Center, Code, Divider, Grid, Group, Input, NativeSelect, Space, Tabs, Text, Tooltip, useMantineTheme } from '@mantine/core'; import React from 'react'; import { NoStyleCard } from './card'; -import { IconArrowLeft } from '@tabler/icons-react'; +import { IconAlertCircle, IconArrowLeft, IconChevronsDown } from '@tabler/icons-react'; +import { Editor } from '@monaco-editor/react'; interface SimpleShowProp { key: number | string; @@ -16,25 +17,43 @@ function ShowSimple({ id, ind, out }: SimpleShowProp) { return ( <> - 样例# {id} + 样例 #{id} - +
- - 输入样例 - + + + + 输入样例 + + + + + + - + {ind}
- - 输出样例 - + + + + 输出样例 + + + + + + - + {out}
@@ -47,13 +66,12 @@ function ShowSimple({ id, ind, out }: SimpleShowProp) { export function ProblemStatementShow({ data }: { data: StandardProblemStatement }) { const items = data.showProp.map((id) => { const item = data[id] as string; - if (item !== 'simples') + if (id !== 'simples') return ( <> - {' '} {/* deepscan-disable-line */} - {StatementToCNName[item]} + {StatementToCNName[id] || id}
@@ -71,8 +89,9 @@ export function ProblemStatementShow({ data }: { data: StandardProblemStatement 样例组 - + {res} + ); } @@ -193,6 +212,147 @@ export function ProblemDescription({ time, memory, difficult }: ProblemDescripti ); } +//TODO +export function SyncProblemSubmit() { + + return ( + + } + rightSectionWidth={1} + /> + } + rightSectionWidth={20} + /> + + + + +
+ + + } + rightSectionWidth={1} + /> + + + + + + +
+
 通过记录同步
+
); +} + + +//TODO +export function DirectProblemSubmit() { + const theme = useMantineTheme(); + return ( + + } + rightSectionWidth={1} + /> + } + rightSectionWidth={1} + /> + } + rightSectionWidth={20} + /> + + + + } title="提示" color="red"> + + 您的帐号未配置 / 您可以点击 + 这里 进行临时登录。 + + + + + + + + ); +} + export function ProblemSubmit() { } diff --git a/packages/ui/src/handlers/problemHandler.ts b/packages/ui/src/handlers/problemHandler.ts new file mode 100644 index 0000000..e52c2e4 --- /dev/null +++ b/packages/ui/src/handlers/problemHandler.ts @@ -0,0 +1,26 @@ +import { fetch } from '../interfaces/data'; + +interface RegisterProp { + email: string; + username: string; + password: string; + gender: string; +} + +interface LoginProp { + email: string; + password: string; +} + +interface Response { + status: 'success' | 'error'; + msg?: string; + type?: string; + data?: unknown; + param?: string; +} + +export async function handleProblem(pid: string): Promise { + const data = await fetch('problem', 'view', { pid }); + return data; +} \ No newline at end of file diff --git a/packages/ui/src/pages/login.tsx b/packages/ui/src/pages/login.tsx index 69246a2..6b44902 100644 --- a/packages/ui/src/pages/login.tsx +++ b/packages/ui/src/pages/login.tsx @@ -26,6 +26,7 @@ import { standardSelect } from '../styles/select'; import { standardTitleColor } from '../styles/color'; import { alarm } from '../styles/alarm'; import Cookies from 'js-cookie'; +import { toast } from 'react-hot-toast'; // eslint-disable-next-line @typescript-eslint/no-unused-vars const useStyles = createStyles((theme) => ({ @@ -123,24 +124,11 @@ export default function LoginPage() {
{ const value = await handleRegister(data); - notifications.show({ - title: value.status === 'success' ? '🎉 All Done! ' : '注册失败', - message: ( - <> - {value.status === 'success' - ? '您的帐号已经准备就绪。即将跳转至登录界面。' - : `错误!${registerError[value.type || ''] || '未知错误'}${registerError[value.param || 'default'] || - ''}`} - {value.status === 'error' ?
: <>} - {value.status === 'error' ? '若您还需要知道更多信息请查看控制台。' : ''} - - ), - color: value.status === 'error' ? 'red' : 'green', - icon: value.status === 'error' ? : , - withCloseButton: false, - - styles: alarm(value.status), - }); + if (value.status === 'success') { + toast.success('🎉 All Done! 您的帐号已经准备就绪。'); + } else { + toast.error(`${registerError[value.type || ''] || '未知错误'}${registerError[value.param || 'default'] ||''} `) + } console.info('技术参数'); console.info(value); if (value.status === 'success') { @@ -148,12 +136,7 @@ export default function LoginPage() { if (window.web?.disableJump !== true) { location.href = '/login'; } else { - notifications.show({ - title: '通知', - message: '跳转请求已忽略。', - color: 'blue', - icon: , - }); + toast.success('已忽略请求。'); } }, 2000); } @@ -243,22 +226,11 @@ export default function LoginPage() { // if (!value.data || value.data?.token) { // value.status === 'error'; // } - notifications.show({ - title: value.status === 'success' ? '' : '登录失败', - message: ( - <> - {value.status === 'success' - ? '欢迎回来!即将返回首页。' - : `错误!${loginError[value.type || ''] || '未知错误'}${loginError[value.param || 'default'] || ''}。`} - {value.status === 'error' ?
: <>} - {value.status === 'error' ? '若您还需要知道更多信息请查看控制台。' : ''} - - ), - color: value.status === 'error' ? 'red' : 'green', - icon: value.status === 'error' ? : , - withCloseButton: false, - styles: alarm(value.status), - }); + if (value.status === 'success') { + toast.success('欢迎回来!即将返回首页。'); + } else { + toast.error(`${loginError[value.type || ''] || '未知错误'}${loginError[value.param || 'default'] || ''}`); + } console.info('技术参数'); console.info(value); if (value.status === 'success') { @@ -266,12 +238,8 @@ export default function LoginPage() { if (window.web?.disableJump !== true) { location.href = '/'; } else { - notifications.show({ - title: '通知', - message: '跳转请求已忽略。', - color: 'blue', - icon: , - }); + toast.success('已忽略。'); + } }, 2000); Cookies.set('token', value.data?.token || ''); diff --git a/packages/ui/src/pages/problemView.tsx b/packages/ui/src/pages/problemView.tsx index 27a60ad..1050f3b 100644 --- a/packages/ui/src/pages/problemView.tsx +++ b/packages/ui/src/pages/problemView.tsx @@ -19,7 +19,7 @@ import { Tooltip, Tabs, Input, Alert, Menu, Code } from '@mantine/core'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { NoStyleCard, StandardCard } from '../components/card'; import { IconAlertCircle, @@ -38,10 +38,13 @@ import { IconTransferIn, IconChevronsUp, IconArrowLeft } from '@tabler/icons-react'; import Editor from '@monaco-editor/react'; -import { standardSelect } from '../styles/select'; +import { standardSelect, standardTab } from '../styles/select'; import {Prism} from '@mantine/prism'; -import { Problem, StandardProblemStatement } from 'rmjac-declare/problem'; -import { ProblemDescription, ProblemStatementShow, ProblemTitle } from '../components/problem'; +import { PlatformToCNName, Problem, StandardProblemStatement } from 'rmjac-declare/problem'; +import { DirectProblemSubmit, ProblemDescription, ProblemStatementShow, ProblemTitle, SyncProblemSubmit } from '../components/problem'; +import { useParams } from 'react-router-dom'; +import { handleProblem } from '../handlers/problemHandler'; +import { toast } from 'react-hot-toast'; const useStyles = createStyles((theme) => ({ link: { @@ -99,291 +102,89 @@ export function RightIcons({ links, active }: TableOfContentsProps) { ); } -export function ProblemViewPageIn({data, state}: {data: Problem, state: 'view' | 'submit'}) { +interface ProblemViewPage { + data: Problem; + islogin: boolean; + state: 'view' | 'submit'; +} + + +export function ProblemViewPageIn({data, state, islogin}: ProblemViewPage) { const [mode, setMode] = useState(state); + const [submit, setSubmitMode] = useState('direct'); + const [statement, setStatement] = useState(data.version[data.defaultVersion]); + const statementVersion = Object.keys(data.version).map((item, index) => { + if (item !== data.defaultVersion) + return ({PlatformToCNName[item] || item}) + else + return (<>); {/* deepscan-disable-line */} + }) + console.log(statementVersion); const LeftGrid = mode === 'view' ? (<> - + { + setStatement(data.version[item as string]) + }} defaultValue={data.defaultVersion} styles={standardTab}> + + + {PlatformToCNName[data.defaultVersion] || data.defaultVersion} + {statementVersion} + + + + + ) : (<> - + { + setSubmitMode(item as string) + }} value={submit} styles={standardTab}> + + + 直接提交 + 同步提交 + + + + + + + + ); const RightGrid = (<> + + {islogin ? + + + 历史得分 + + + 100 + + + +  历史提交, keys:'send', order: 1, link: '#'}, + {label:
 原题链接
, order: 1, keys:'re', link: '#'}, //alot of origin how to choose? + ]} active={''} /> +
: + +  原题链接, order: 1, keys:'re', link: '#'}, //alot of origin how to choose? + ]} active={''} /> + } ); return ( <> - + {LeftGrid} {RightGrid} - - - - - ) -} - -export function ProblemViewPage() { - const theme = useMantineTheme(); - const [mode, setMode] = useState('view'); - return ( - <> - - - - - - { - console.log(item); - }} defaultValue="chat" styles={(theme) => ({ - tab: { - borderBottomWidth: 3, - fontWeight: 700 - }, - tabsList: { - borderBottomWidth: 0, - } - })}> - - - - 原版 - 翻译 - {/* 直接提交 - 同步提交 */} - {/*存档*/} - - - - {/* - - - } - rightSectionWidth={1} - /> - } - rightSectionWidth={20} - /> - - - - -
- - - } - rightSectionWidth={1} - /> - - - - - - -
-
 通过记录同步
-
- - - } - rightSectionWidth={1} - /> - } - rightSectionWidth={1} - /> - } - rightSectionWidth={20} - /> - - - - } title="提示" color="red"> - - 您的帐号未配置 / 您可以点击 - 这里 进行临时登录。 - - - - - - - - -
*/} - - - - 题目背景 - - 有一个 - -a×b 的整数组成的矩阵,现请你从中找出一个 - -n×n 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。 - - - 样例组 - - - 样例#1 - - - -
- - 输入样例 - - 10 12 -
-
- 输出样例 - - 10 12 -
-
- - 样例 #2 - - - -
- - - - 输入样例 - - - - - - - - 10 12 -
-
- 输出样例 - - 10 12 -
-
- - - 输入格式 - - 一行两个整数A, B - - 输出格式 - - 一个整数C, 表示A+B -
- - -
- - -
- - - - - - - - 历史得分 - - - 100 - - - -  历史提交, keys:'send', order: 1, link: '#'}, - {label:
 原题链接
, order: 1, keys:'re', link: '#'}, - ]} active={''} /> -
NOIP @@ -394,5 +195,50 @@ n×n 的正方形区域,使得该区域所有数中的最大值和最小值的
- ); + ) +} + +export function ProblemViewPage() { + const param = useParams(); + const [pdata, setPdata] = useState({ + version: { + 'default': { + simples: [], + showProp: ['loading'], + loading: 'loading..' + }, + 'ver2': { + simples: [{in: '无输入内容', out: 'Hello world!\nHere is rmj.ac'}], + statement: '题目描述。', + showProp: ['statement', 'simples'], + } + }, + defaultVersion: 'default', + title: 'Loading...', + sources: [], + limit: { + time: '-', + memory: '-', + difficult: { + text: '-', + color: '', + hint: '' + } + } + + }); + const pid = param.pid || ''; + useEffect(() => { + try { + handleProblem(pid as string).then((res: any) => { + if (res.status === 'success') { + setPdata(pdata); + } else { + toast.error('题目查询错误。'); + } + }) } catch(err) { + toast.error('题目查询错误。'); + } + }, [pid]); + return () } diff --git a/packages/ui/src/structure/root.tsx b/packages/ui/src/structure/root.tsx index 31cc584..1ae4c41 100644 --- a/packages/ui/src/structure/root.tsx +++ b/packages/ui/src/structure/root.tsx @@ -6,6 +6,7 @@ import { Navbar } from '../components/navbar'; import React from 'react'; import { AppFooter } from '../structure/footer'; import { updateNewPageBackEndData } from '../interfaces/data'; +import { Toaster } from 'react-hot-toast'; const useStyles = createStyles((theme) => ({})); @@ -40,6 +41,18 @@ export function Root({ onThemeChange, type, children }: RootProps) { footer={} header={} > + {type === 'route' ? : children} diff --git a/packages/ui/src/styles/select.tsx b/packages/ui/src/styles/select.tsx index ff4e82d..d7c4bd4 100644 --- a/packages/ui/src/styles/select.tsx +++ b/packages/ui/src/styles/select.tsx @@ -11,3 +11,14 @@ export const standardSelect = (theme: MantineTheme) => ({ '&[data-hovered]': {}, }, }); + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const standardTab = (theme: MantineTheme) => ({ + tab: { + borderBottomWidth: 3, + fontWeight: 700 + }, + tabsList: { + borderBottomWidth: 0, + } +}) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 81ddda0..effc6fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4214,6 +4214,11 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +goober@^2.1.10: + version "2.1.13" + resolved "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz#e3c06d5578486212a76c9eba860cbc3232ff6d7c" + integrity sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ== + gopd@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -5710,6 +5715,13 @@ react-dropzone@14.2.3: file-selector "^0.6.0" prop-types "^15.8.1" +react-hot-toast@^2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994" + integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ== + dependencies: + goober "^2.1.10" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"