From 3c52254077c2da0e87156a6ddd6e415dd3fc40da Mon Sep 17 00:00:00 2001 From: Leo Date: Mon, 9 Mar 2026 22:52:21 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=BA=BF=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ContestSite/ManagerPage/EditTimeline.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/app/ContestSite/ManagerPage/EditTimeline.tsx b/src/app/ContestSite/ManagerPage/EditTimeline.tsx index a0ef82432..10164f109 100644 --- a/src/app/ContestSite/ManagerPage/EditTimeline.tsx +++ b/src/app/ContestSite/ManagerPage/EditTimeline.tsx @@ -42,6 +42,9 @@ const EditTimeline: React.FC = ({ mode, user }) => { }); const [addContestTime, { error: addContestTimeError }] = graphql.useAddContestTimeMutation(); + const [deleteContestTime, { error: deleteContestTimeError }] = + graphql.useDeleteContestTimeMutation(); // 添加删除事件的 mutation + /* ---------------- useEffect ---------------- */ useEffect(() => { if (getContestTimesError) { @@ -53,6 +56,11 @@ const EditTimeline: React.FC = ({ mode, user }) => { message.error("添加事件失败"); } }, [addContestTimeError]); + useEffect(() => { + if (deleteContestTimeError) { + message.error("删除事件失败"); + } + }, [deleteContestTimeError]); /* ---------------- 业务逻辑函数 ---------------- */ const handleAdd = async () => { try { @@ -75,6 +83,24 @@ const EditTimeline: React.FC = ({ mode, user }) => { } }; + const handleDelete = async (event: string) => { + try { + await deleteContestTime({ + variables: { + contest_id: Contest_id, + event: event, + }, + }); + if (deleteContestTimeError) + throw new Error(deleteContestTimeError.message); + message.success("事件删除成功"); + refetchContestTimes(); // 刷新事件列表 + } catch (e) { + console.log(e); + message.error("删除事件失败"); + } + }; + const panelStyle: React.CSSProperties = { marginBottom: 12, background: token.colorFillAlter, @@ -92,9 +118,18 @@ const EditTimeline: React.FC = ({ mode, user }) => { {dayjs(item.end).format("YYYY-MM-DD")}
描述:{item.description} +
+ ), })); + /* ---------------- ⻚⾯组件 ---------------- */ return ( From fbdb3fa9d368ea5a6d03b6a9cf624f2b7feb503c Mon Sep 17 00:00:00 2001 From: Leo Date: Mon, 11 May 2026 21:22:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=A1=B5=E9=9D=A2=E7=BC=96=E8=BE=91=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/ContestSite/ManagerPage/Setting.tsx | 164 ++++++++++---------- src/app/ContestSite/ManagerPage/index.tsx | 148 +++++++----------- 2 files changed, 138 insertions(+), 174 deletions(-) diff --git a/src/app/ContestSite/ManagerPage/Setting.tsx b/src/app/ContestSite/ManagerPage/Setting.tsx index 1547a837e..1258c34bd 100644 --- a/src/app/ContestSite/ManagerPage/Setting.tsx +++ b/src/app/ContestSite/ManagerPage/Setting.tsx @@ -3,11 +3,13 @@ import { Card, Checkbox, message, Space, Typography } from "antd"; import { useUrl } from "../../../api/hooks/url"; import * as graphql from "@/generated/graphql"; import { ContestProps } from ".."; -/* ---------------- 不随渲染刷新的常量 ---------------- */ -const { Title } = Typography; -/* ---------------- 主页面 ---------------- */ -const Setting: React.FC = (props) => { - //获取比赛ID + +// 扩展 Props 类型,增加 isHardware +interface SettingProps extends ContestProps { + isHardware?: boolean; +} + +const Setting: React.FC = (props) => { const url = useUrl(); const Contest_id = url.query.get("contest"); @@ -27,29 +29,15 @@ const Setting: React.FC = (props) => { useEffect(() => { if (updateSwitchError) { message.error("比赛状态更新失败"); - console.log(updateSwitchError.message); } }, [updateSwitchError]); - useEffect(() => { - if (contestSwitchError) { - message.error("获取比赛状态失败"); - console.log(contestSwitchError.message); - } - }, [contestSwitchError]); - return ( - - + <Card hoverable style={{ height: "100%" }}> + <Typography.Title level={2} style={{ margin: `0 0 24px` }}> 比赛设置 - - + + { @@ -82,66 +70,76 @@ const Setting: React.FC = (props) => { > 上传代码 - { - await updateContestSwitch({ - variables: { - contest_id: Contest_id, - ...contestSwitchData?.contest_by_pk!, - arena_switch: e.target.checked, - }, - }); - refetchContestSwitch(); - }} - > - 天梯对战 - - { - await updateContestSwitch({ - variables: { - contest_id: Contest_id, - ...contestSwitchData?.contest_by_pk!, - playground_switch: e.target.checked, - }, - }); - refetchContestSwitch(); - }} - > - 试玩功能 - - { - await updateContestSwitch({ - variables: { - contest_id: Contest_id, - ...contestSwitchData?.contest_by_pk!, - stream_switch: e.target.checked, - }, - }); - refetchContestSwitch(); - }} - > - 直播功能 - - { - await updateContestSwitch({ - variables: { - contest_id: Contest_id, - ...contestSwitchData?.contest_by_pk!, - playback_switch: e.target.checked, - }, - }); - refetchContestSwitch(); - }} - > - 回放功能 - + + {/* 如果是硬件设计,隐藏以下所有与 WebGL/对战相关的开关 */} + {!props.isHardware && ( + <> + { + await updateContestSwitch({ + variables: { + contest_id: Contest_id, + ...contestSwitchData?.contest_by_pk!, + arena_switch: e.target.checked, + }, + }); + refetchContestSwitch(); + }} + > + 天梯功能 + + { + await updateContestSwitch({ + variables: { + contest_id: Contest_id, + ...contestSwitchData?.contest_by_pk!, + playground_switch: e.target.checked, + }, + }); + refetchContestSwitch(); + }} + > + 试玩功能 + + { + await updateContestSwitch({ + variables: { + contest_id: Contest_id, + ...contestSwitchData?.contest_by_pk!, + stream_switch: e.target.checked, + }, + }); + refetchContestSwitch(); + }} + > + 直播功能 + + { + await updateContestSwitch({ + variables: { + contest_id: Contest_id, + ...contestSwitchData?.contest_by_pk!, + playback_switch: e.target.checked, + }, + }); + refetchContestSwitch(); + }} + > + 回放功能 + + + )} ); diff --git a/src/app/ContestSite/ManagerPage/index.tsx b/src/app/ContestSite/ManagerPage/index.tsx index 262204a42..fcbad5628 100644 --- a/src/app/ContestSite/ManagerPage/index.tsx +++ b/src/app/ContestSite/ManagerPage/index.tsx @@ -1,99 +1,72 @@ -// 需要整合到此页面的功能有: - -//* 1. 导出队伍信息(JoinPage.tsx) -// 2. 修改比赛信息(ListPage.tsx,已注释) -//* 3. 上传代码和天梯功能的开关(SettingPage.tsx) -//* 4. 开启单双循环赛的按钮和配置(SettingPage.tsx) -// 5. 复赛、决赛的得分展示(ManageTeamsPage.tsx) -//* 6. 队伍管理功能(ManageTeamsPage.tsx,考虑是否必要,可转化为统计数据) - -// 注:除 NoticePage.tsx 上的管理员功能暂时保留,其余功能和页面在整合后均在原处删除 - -// 其他有需求的功能: - -// 1. 比赛报名、组队情况和代码提交的统计数据 -// 2. 复赛、决赛的轮赛进度和得分展示,以及表格导出功能(效仿天梯) -// 3. 比赛地图的添加和管理 - -// 锦上添花的功能: - -// 1. 角色强度的统计分析 -// 2. 在比赛记录基础上,允许一键重跑,在线观看回放、下载回放,甚至观看直播(效仿天梯) -// 3. 在线提交WebGL,同时更改是否允许试玩、回放、直播的开关 -// 4. 加入在线地图编辑器 -import React, { useEffect } from "react"; -import { Col, message, Layout, Row, Space } from "antd"; +import React from "react"; +import { Col, Row, Space } from "antd"; import { ContestProps } from ".."; import { useUrl } from "../../../api/hooks/url"; import * as graphql from "@/generated/graphql"; +import EditInfo from "./EditInfo"; import Setting from "./Setting"; +import EditTimeline from "./EditTimeline"; +import UploadWebGL from "./UploadWebGL"; import ManageTeams from "./ManageTeams"; -import EditInfo from "./EditInfo"; -import Forbidden from "@/app/Components/Forbidden"; -import Competition from "./Competition"; import EditPlayer from "./EditPlayer"; import UploadMap from "./UploadMap"; -import UploadWebGL from "./UploadWebGL"; -import EditTimeline from "./EditTimeline"; - -/* ---------------- 不随渲染刷新的常量 ---------------- */ - -/* ---------------- 不随渲染刷新的组件 ---------------- */ -const ManagerPage: React.FC = ({ mode, user }) => { - /* ---------------- States 和常量 Hooks ---------------- */ +const ContestAdmin: React.FC = ({ mode, user }) => { const url = useUrl(); const Contest_id = url.query.get("contest"); - const { data: getContestManagersData, error: getContestManagersError } = - graphql.useGetContestManagersSuspenseQuery({ - variables: { - contest_id: Contest_id, - }, - }); - useEffect(() => { - if (getContestManagersError) { - message.error("管理员加载失败"); - console.log(getContestManagersError.message); - } - }, [getContestManagersError]); + // 关键修改:获取比赛信息以判断名称 + const { data: contestInfoData } = graphql.useGetContestInfoSuspenseQuery({ + variables: { contest_id: Contest_id }, + }); - return getContestManagersData?.contest_by_pk?.contest_managers.some( - (manager) => manager.user_uuid === user.uuid, - ) ? ( - - - - - - - - - - - - - - + const contestName = contestInfoData?.contest_by_pk?.fullname || ""; + // 判断逻辑:名称包含“硬件设计”则为硬件比赛 + const isHardware = contestName.includes("硬件设计"); + + return ( + + {/* 第一行:信息编辑 + 比赛设置 */} + + + + + + {/* 传参给 Setting */} + + + + + {/* 第二行:时间线 + (WebGL管理) */} + + + + + {!isHardware && ( - - - - - - - + )} + + + {/* 第三行:队伍管理 (所有比赛都保留) */} + + + + + + + {/* 隐藏行:硬件设计不需要角色和地图管理 */} + {!isHardware && ( + @@ -101,16 +74,9 @@ const ManagerPage: React.FC = ({ mode, user }) => { - - - - - - - - ) : ( - + )} + ); }; -export default ManagerPage; +export default ContestAdmin;