diff --git a/components/extraReact.ts b/components/extraReact.ts new file mode 100644 index 0000000..564b61d --- /dev/null +++ b/components/extraReact.ts @@ -0,0 +1,6 @@ +export function useClassState( + useState: [S, React.Dispatch>] +): [S, (newState: Partial) => void] { + const setState = (newState: Partial) => useState[1]((preState) => ({ ...preState, ...newState })); + return [useState[0], setState]; +} \ No newline at end of file diff --git a/components/main.tsx b/components/main.tsx index ed3d97a..61121f4 100644 --- a/components/main.tsx +++ b/components/main.tsx @@ -25,7 +25,7 @@ function MTBarLink({ type }: { type: string }) { ); } -export default function MainNode({ children }: { children: JSX.Element | JSX.Element[] }) { +export default function MainNode({ children }: { children: React.ReactNode }) { return (
diff --git a/components/randomId.ts b/components/randomId.ts new file mode 100644 index 0000000..8e16231 --- /dev/null +++ b/components/randomId.ts @@ -0,0 +1,3 @@ +export default function randomId() { + return Math.random().toString(16).slice(2); +} \ No newline at end of file diff --git a/components/repeat.tsx b/components/repeat.tsx new file mode 100644 index 0000000..7f60eb0 --- /dev/null +++ b/components/repeat.tsx @@ -0,0 +1,15 @@ +interface RepeatProps { + variable: T, + repeat: number, + func: (variable: T) => T, + components: (variable: T) => React.ReactNode, +} + +export default function Repeat({ variable, repeat, func, components }: RepeatProps) { + const array = new Array(repeat).fill(null); + array.forEach((_, i) => { + array[i] = components(variable); + variable = func(variable); + }); + return <>{array}; +} \ No newline at end of file diff --git a/components/student.tsx b/components/student.tsx new file mode 100644 index 0000000..2e7dd93 --- /dev/null +++ b/components/student.tsx @@ -0,0 +1,32 @@ +import ItemStyles from '@/styles/Item.module.scss'; +import { studentsJson } from './students/students'; +import { getStudentInfo } from './students/infoStudents'; + +interface StudentProps { + id: number, + allInfo: studentsJson, + onClick: React.MouseEventHandler, + select: boolean, + onError: (id: number) => void, +} + +export default function Student({ id, allInfo, onClick, select, onError }: StudentProps) { + const info = getStudentInfo(allInfo, id); + return ( +
+
+ {`${info.schale?.Name} onError(id)} + /> +
+
+

{info.schale?.Name}

+

{info.file?.info}

+
+
+
+ ); +} \ No newline at end of file diff --git a/components/window.tsx b/components/window.tsx new file mode 100644 index 0000000..9faca29 --- /dev/null +++ b/components/window.tsx @@ -0,0 +1,118 @@ +import React from "react"; +import Repeat from "./repeat"; +import { useClassState } from './extraReact'; +import randomId from "./randomId"; + +interface WindowProps { + /**标题 */ + title: string; + /**关闭窗口时调用的函数 */ + closeWindow: () => C; + /**窗口渲染的元素 */ + element: (closeWindow: () => C) => React.ReactNode; + /**窗口zIndex */ + zIndex: number; + /**窗口是否显示 */ + display: boolean; +} + +interface WindowTypeAll { + name: string, + id: string, + display: boolean, + arg: any +} + +type WindowTypeComArg = ( + zIndex: number, + id: string, + display: boolean, + arg: A, + all: AllWindow['all'] +) => React.ReactNode; + +export interface AllWindow { + all?: WindowTypeAll[]; + component?: { + [x: string]: WindowTypeComArg + }; +} + +export default class Window { + name: string; + + constructor(name: string) { + this.name = name; + } + + Component({ closeWindow, element, zIndex, display, title }: WindowProps) { + return (<> + {display && ( +
+
+

{title}

+

closeWindow()}>x

+
+
+
+ )} + ); + } +} + +export function AllWindows({ zIndex, allWindow }: { + zIndex: number, + allWindow: AllWindow +}) { + if (allWindow.all?.length !== 0) + return (<> + v + 1} + components={v => { + if (allWindow.component && allWindow.all) + return ( + +
+ {allWindow.component[allWindow.all[v].name]( + zIndex + 1 + (2 * v), + allWindow.all[v].id, + allWindow.all[v].display, + allWindow.all[v].arg, + allWindow.all + )} + + ); + }} + /> + ); + return null; +} + +export function getWindowFun( + useState: [AllWindow, React.Dispatch>] +) { + const [allWindow, setAllWindow] = useClassState(useState); + function addNewWindow( + window: Window, + Component: WindowTypeComArg + ) { + let component = allWindow.component || {}; + component[window.name] = Component; + return setAllWindow({ component }); + }; + function openWindow(all: AllWindow['all'], window: Window, arg: A) { + const { name } = window; + all?.push({ name, id: randomId(), display: true, arg }); + setAllWindow({ all }); + }; + const closeWindow = (all: AllWindow['all'], id: string) => { + all = all?.filter(v => v.id !== id); + setAllWindow({ all }); + }; + return { allWindow, setAllWindow, addNewWindow, openWindow, closeWindow }; +} \ No newline at end of file diff --git a/pages/_document.tsx b/pages/_document.tsx index 19fd80d..0398eda 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -2,7 +2,7 @@ import { Html, Head, Main, NextScript } from 'next/document' export default function Document() { return ( - + diff --git a/pages/chat.tsx b/pages/chat.tsx index ef89db5..27402a9 100644 --- a/pages/chat.tsx +++ b/pages/chat.tsx @@ -1,63 +1,25 @@ //Components import { NextSeo } from 'next-seo'; import MainNode from '@/components/main'; +import Student from '@/components/student'; //Styles import ItemStyles from '@/styles/Item.module.scss'; import ChatStyles from '@/styles/Chat.module.scss'; //Methods -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; import getTitle from '@/components/title'; import { studentsJson } from '@/components/students/students'; import { getStudentInfo, getStudentsJson } from '@/components/students/infoStudents'; - -interface RepeatProps { - variable: T, - repeat: number, - func: (variable: T) => T, - components: (variable: T) => JSX.Element, -} - -interface StudentProps { - id: number, - allInfo: studentsJson, - onClick: React.MouseEventHandler, - select: boolean, -} +import Window, { AllWindow, getWindowFun } from '@/components/window'; +import Repeat from '@/components/repeat'; +import { AllWindows } from '@/components/window'; +import { useClassState } from '@/components/extraReact'; interface ContentProps { id: number, - allInfo: studentsJson -} - -function Repeat({ variable, repeat, func, components }: RepeatProps) { - const array = new Array(repeat).fill(null); - array.forEach((_, i) => { - array[i] = components(variable); - variable = func(variable); - }); - return <>{array}; -} - -function Student({ id, allInfo, onClick, select }: StudentProps) { - const info = getStudentInfo(allInfo, id); - return ( -
-
- {`${info.schale?.Name} -
-
-

{info.schale?.Name}

-

{info.file?.info}

-
-
-
- ); + allInfo: studentsJson, } function Content({ id, allInfo }: ContentProps) { @@ -86,42 +48,127 @@ function Content({ id, allInfo }: ContentProps) { ); } +interface State { + student?: number, + studentsList?: number[], + studentsJson?: { + data: studentsJson, + } +} + +interface IdPromptArg { + studentsList?: number[]; + type?: '+' | '-'; +} + +interface TextAlertArg { + title: string; + elem: React.ReactNode; + fun?: () => any; +} + export default function Info() { - const [state, setState] = useState<{ - student: number, - studentsList: number[], - studentsJson: { - data: studentsJson, - fetch: boolean, - } - }>({ + const [state, setState] = useClassState(useState({ student: 0, studentsList: [10000, 10002], - studentsJson: { data: {}, fetch: false }, - }); - if (!state.studentsJson.fetch) getStudentsJson().then(r => setState({ - student: state.student, - studentsList: state.studentsList, - studentsJson: { data: r, fetch: true }, + studentsJson: { data: {} }, })); + + useEffect(() => { + getStudentsJson().then(r => setState({ studentsJson: { data: r } })); + }, []); + + //Window + const { + allWindow, + addNewWindow, + openWindow, + closeWindow, + } = getWindowFun(useState({ all: [], component: {} })); + + //IdPrompt + const idPromptInputRef = useRef(0); + const IdPrompt = new Window('IdPrompt'); + + //Alert + const TextAlert = new Window('TextAlert'); + + useEffect(() => { + const IdPromptTypeText = { '+': '添加', '-': '去除' }; + addNewWindow(IdPrompt, (zIndex, id, display, { studentsList, type }, all) => ( + closeWindow(all, id)} + element={close => (<> +

请输入需要在列表{IdPromptTypeText[type || '+']}的学生的Id

+ { idPromptInputRef.current = Number(e.target.value); }} /> +