From 8bd3c94fac29a4f4972cdf03f1b62a7f486f4796 Mon Sep 17 00:00:00 2001 From: zou-y-t <1354410159@qq.com> Date: Wed, 26 Jun 2024 19:25:00 +0800 Subject: [PATCH] : --- src/app/InfoSite/MentorApplicationPage.tsx | 1133 ++++++++++++++------ src/app/InfoSite/index.tsx | 9 +- src/generated/graphql.tsx | 85 +- src/graphql/info/mentor.graphql | 41 + 4 files changed, 910 insertions(+), 358 deletions(-) diff --git a/src/app/InfoSite/MentorApplicationPage.tsx b/src/app/InfoSite/MentorApplicationPage.tsx index 0590d9991..d5b4b9af7 100644 --- a/src/app/InfoSite/MentorApplicationPage.tsx +++ b/src/app/InfoSite/MentorApplicationPage.tsx @@ -2,8 +2,11 @@ import { useEffect, useState, useRef } from "react"; import { Badge, Button, + Card, Col, + DatePicker, Descriptions, + Divider, Form, Input, InputRef, @@ -31,6 +34,8 @@ import { ExclamationCircleFilled, UploadOutlined, DownloadOutlined, + EyeOutlined, + EyeInvisibleOutlined, } from "@ant-design/icons"; import { getStatusText } from "../../api/utils/application"; import { pick } from "../../api/utils/pick"; @@ -62,6 +67,8 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { }, }); + const [hasGetTime, setHasGetTime] = useState(false); + useEffect(() => { const fetch = async () => { try { @@ -80,6 +87,7 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { end_E: new Date(response.data.time.end_E), }, }); + setHasGetTime(true); } catch (e) { const err = e as AxiosError; if (err.response?.status === 401) { @@ -94,6 +102,32 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { fetch(); }, []); + const [updateMentorTime] = graphql.useUpdateMentorTimeMutation(); + useEffect(() => { + if (!hasGetTime) return; //未获取到时间信息的时候,info的全部都是默认值,不进行数据库更改操作 + if (user.role !== "counselor" && user.role !== "root") return; + try { + updateMentorTime({ + variables: { + start_A: info.mentor.start_A, + start_B: info.mentor.start_B, + start_C: info.mentor.start_C, + start_D: info.mentor.start_D, + start_E: info.mentor.start_E, + end_A: info.mentor.end_A, + end_B: info.mentor.end_B, + end_C: info.mentor.end_C, + end_D: info.mentor.end_D, + end_E: info.mentor.end_E, + activateIn: new Date().getFullYear(), + }, + }); + } catch (err) { + console.log(err); + message.error("时间更新失败"); + } + }, [info, updateMentorTime, hasGetTime, user.role]); + const { loading: applicationLoading, error: applicationError, @@ -174,19 +208,6 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { } }, [updateApplicationStatusError]); - const handleApplicationStatusChange = async ( - status: "approved" | "submitted" | "rejected", - item: graphql.GetMentorApplicationsQuery["mentor_application"][0], - ) => { - await updateApplicationStatus({ - variables: { - id: item.id, - status: status, - }, - }); - await refetchApplications(); - }; - const [modalVisible, setModalVisible] = useState(false); const [editingApplication, setEditingApplication] = useState(); @@ -406,6 +427,14 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { (a.total_for_grade.aggregate?.count ?? 0) - (b.total_for_grade.aggregate?.count ?? 0), }, + { + title: "已接收人数", + dataIndex: ["total_for_match", "aggregate", "count"], + key: "matchedApplicants", + sorter: (a, b) => + (a.total_for_match.aggregate?.count ?? 0) - + (b.total_for_match.aggregate?.count ?? 0), + }, { title: "操作", key: "action", @@ -588,7 +617,7 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { const { data: freshmanList, error: freshmanListError, - // refetch: refetchFreshmanList, + refetch: refetchFreshmanList, } = graphql.useGetFreshmanListQuery({ skip: user.role !== "counselor" && user.role !== "root", }); @@ -601,66 +630,73 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { }, [freshmanListError]); const handleAttribute = async () => { - setAttributing(true); - - try { - const freshmanToAttribute = freshmanList!.users.filter( - (item) => item.mentor_application_as_student.length === 0, - ); - const teachersToAttribute = mentorList!.users.filter( - (item) => - item.mentor_available?.available === true && - (item.matched.aggregate?.count ?? 0) < 5, - ); - - if (teachersToAttribute.length === 0) { + let freshmanToAttribute = freshmanList!.users.filter( + (item) => item.mentor_application_as_student.length === 0, + ); + let teachersToAttribute = new Map(); + let teachersHash = new Array(); + //建立哈希映射,key为老师,value为匹配数,记录匹配数不超过5的老师 + let len = 0; + mentorList!.users.forEach((item) => { + if ( + item.mentor_available?.available === true && + (item.matched.aggregate?.count ?? 0) < 5 + ) { + teachersToAttribute.set(item, item.matched.aggregate?.count ?? 0); + teachersHash.push(item); + len++; + } + }); + let matched = new Map(); + let numOfStudents = freshmanToAttribute.length; + for (let i = 0; i < numOfStudents; i++) { + if (len === 0) { message.error("没有可用的导师"); - return; + break; } - if (freshmanToAttribute.length === 0) { - message.success("随机分配完成"); - return; + let randomIndex = Math.floor(Math.random() * len); //范围[0,len-1]随机 + let tmpTeacher = teachersHash[randomIndex]; + matched.set(freshmanToAttribute[i], tmpTeacher); + + //更新老师的匹配数 + if ((teachersToAttribute.get(tmpTeacher) ?? 0) < 4) { + teachersToAttribute.set( + tmpTeacher, + (teachersToAttribute.get(tmpTeacher) ?? 0) + 1, + ); + } else { + teachersToAttribute.delete(tmpTeacher); + teachersHash.splice(randomIndex, 1); + len--; } + } - const student = - freshmanToAttribute[Date.now() % freshmanToAttribute.length]; - - const minCount = Math.min( - ...teachersToAttribute.map( - (item) => item.matched.aggregate?.count ?? 0, - ), - ); - const teachersWithMinCount = teachersToAttribute.filter( - (item) => item.matched.aggregate?.count === minCount, - ); - - const teacher = - teachersWithMinCount[Date.now() % teachersWithMinCount.length]; - - const { data } = await addApplication({ - variables: { - student_uuid: student.uuid, - mentor_uuid: teacher.uuid, - statement: "系统随机分配", - }, - }); - - await updateApplicationStatus({ - variables: { - id: data?.insert_mentor_application?.returning[0].id!, - status: "approved", - }, - }); - - message.success("分配成功"); - window.location.reload(); - return; - } catch { - message.error("分配失败"); - } finally { - setAttributing(false); + //更新数据库 + for (const [student, teacher] of matched) { + try { + const { data } = await addApplication({ + variables: { + student_uuid: student.uuid, + mentor_uuid: teacher.uuid, + statement: "系统随机分配", + }, + }); + await updateApplicationStatus({ + variables: { + id: data?.insert_mentor_application?.returning[0].id!, + status: "approved", + }, + }); + } catch { + message.error("分配失败"); + } } + + message.success("随机分配已完成"); + setAttributing(false); + window.location.reload(); + return; }; const [importing, setImporting] = useState(false); @@ -846,6 +882,18 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { } }; + const [hideReject, setHideReject] = useState(false); + const [openDetails, setOpenDetails] = useState(false); + const [studentDetails, setStudentDetails] = useState([ + "", + "", + "", + "", + "", + "", + "", + "", + ]); return ( = ({ mode, user }) => { width: 100%; `} > - 关键时间点 - - {user.role === "teacher" && ( - = info.mentor.start_A && - new Date() <= info.mentor.end_A - ? "green" - : "red" - } - > -

预备阶段:导师更新个人信息

-

- {info.mentor.start_A.toLocaleString()} ~{" "} - {info.mentor.end_A.toLocaleString()} -

-
- )} - = info.mentor.start_B && new Date() <= info.mentor.end_B - ? "green" - : "red" - } - > -

预备阶段:学生了解导师信息

-

- {info.mentor.start_B.toLocaleString()} ~{" "} - {info.mentor.end_B.toLocaleString()} -

-
- = info.mentor.start_C && new Date() <= info.mentor.end_C - ? "green" - : "red" - } - > -

第一阶段:自由申请与匹配

-

- {info.mentor.start_C.toLocaleString()} ~{" "} - {info.mentor.end_C.toLocaleString()} -

-
- = info.mentor.start_D && new Date() <= info.mentor.end_D - ? "green" - : "red" - } - > -

第二阶段:未匹配同学补选

-

- {info.mentor.start_D.toLocaleString()} ~{" "} - {info.mentor.end_D.toLocaleString()} -

-
- = info.mentor.start_E && new Date() <= info.mentor.end_E - ? "green" - : "red" - } - > -

第三阶段:系统随机分配

-

- {info.mentor.start_E.toLocaleString()} ~{" "} - {info.mentor.end_E.toLocaleString()} -

-
-
- {user.role === "student" && ( - <> - 已申请 - { - return ( - - - {item.mentor?.realname} - - - {item.mentor?.department} - - - {dayjs(item.created_at).format("YYYY-MM-DD HH:mm")} - - - {item.status === "submitted" ? ( - - ) : item.status === "approved" ? ( - - ) : ( - - )} - - - - {item.statement} - -
-
+ + {user.role !== "counselor" && ( + <> + + {user.role === "teacher" && ( + <> + - - + + - + -
- {item.status === "approved" && ( - - - - {item.chat_status === false ? ( - - ) : ( - - )} + +
+ + + 未处理 + { + if (item.status === "rejected") return null; + if (item.status === "approved") return null; + return ( + + + {item.student?.realname} + + + {item.student?.department} + + + {item.status === "submitted" ? ( + + ) : item.status === "approved" ? ( + + ) : ( + + )} + + {item.status === "approved" && ( + + {item.chat_status === false ? ( + + ) : ( + + + + + + + + + )} + + )} + + + + + ); + }} + /> + + + + 已处理 - - { - handleUploadRecord(e, item.id); - }} - onChange={handleOnchangeRecord} - showUploadList={false} - // onRemove={handleRemoveRecord} - // multiple={false} + + - - - - {item.chat_status === true && ( - - - )} + shape="circle" + icon={ + hideReject ? ( + + ) : ( + + ) + } + type="default" + onClick={() => { + setHideReject(!hideReject); + }} + /> + + -
- )} -
- ); - }} - /> - - )} - {user.role === "teacher" && ( - <> - - - - - - - - + { + if (item.status === "rejected" && hideReject) + return null; + if (item.status === "submitted") return null; + return ( + + + {item.student?.realname} + + + {item.student?.department} + + + {item.status === "submitted" ? ( + + ) : item.status === "approved" ? ( + + ) : ( + + )} + + + + + {item.status === "approved" && ( + + {item.chat_status === false ? ( + + ) : ( + + + + + + + + + + )} + + )} + + ); + }} + /> + + + + )} - { - return ( - - - {item.student?.realname} - - - {item.student?.department} - - - {item.student?.email} - - {item.status === "approved" && ( - - {item.student?.phone} - + {user.role === "student" && ( + + 已申请 + { + return ( + + + {item.mentor?.realname} + + + {item.mentor?.department} + + + {dayjs(item.created_at).format("YYYY-MM-DD HH:mm")} + + + {item.status === "submitted" ? ( + + ) : item.status === "approved" ? ( + + ) : ( + + )} + + + + {item.statement} + +
+
+ + + + + + + + +
+ {item.status === "approved" && ( + + + + {item.chat_status === false ? ( + + ) : ( + + )} + + + + { + handleUploadRecord(e, item.id); + }} + onChange={handleOnchangeRecord} + showUploadList={false} + // onRemove={handleRemoveRecord} + // multiple={false} + > + + + + {item.chat_status === true && ( + <> + + + + + + )} + + + )} +
+ ); + }} + /> +
+ )} + + + + 关键时间点 +
+ + {user.role === "teacher" && ( + = info.mentor.start_A && + new Date() <= info.mentor.end_A + ? "green" + : "gray" + } + > +

预备阶段:导师更新个人信息

+
+

+ {dayjs(info.mentor.start_A).format("YYYY-MM-DD")} ~{" "} + {dayjs(info.mentor.end_A).format("YYYY-MM-DD")} +

+
)} - - {dayjs(item.created_at).format("YYYY-MM-DD HH:mm")} - - - {item.status === "submitted" ? ( - - ) : item.status === "approved" ? ( - - ) : ( - - )} - - - - {item.statement} - + = info.mentor.start_B && + new Date() <= info.mentor.end_B + ? "green" + : "gray" + } + > +

预备阶段:学生了解导师信息


+

+ {dayjs(info.mentor.start_B).format("YYYY-MM-DD")} ~{" "} + {dayjs(info.mentor.end_B).format("YYYY-MM-DD")} +

+
+ = info.mentor.start_C && + new Date() <= info.mentor.end_C + ? "green" + : "gray" + } + > +

第一阶段:自由申请与匹配


- { - handleApplicationStatusChange(e.target.value, item); - }} - > - 接收该同学 - 尚未处理 - 拒绝该同学 - -
- {item.status === "approved" && ( - - {item.chat_status === false ? ( - - ) : ( - - - - - - - - - )} - - )} -
- ); - }} - /> - - )} +

+ {dayjs(info.mentor.start_C).format("YYYY-MM-DD")} ~{" "} + {dayjs(info.mentor.end_C).format("YYYY-MM-DD")} +

+ + = info.mentor.start_D && + new Date() <= info.mentor.end_D + ? "green" + : "gray" + } + > +

第二阶段:未匹配同学补选

+
+

+ {dayjs(info.mentor.start_D).format("YYYY-MM-DD")} ~{" "} + {dayjs(info.mentor.end_D).format("YYYY-MM-DD")} +

+
+ = info.mentor.start_E && + new Date() <= info.mentor.end_E + ? "green" + : "gray" + } + > +

第三阶段:系统随机分配

+
+

+ {dayjs(info.mentor.start_E).format("YYYY-MM-DD")} ~{" "} + {dayjs(info.mentor.end_E).format("YYYY-MM-DD")} +

+
+ + + + + )} + {user.role === "counselor" && ( + <> + + + 管理时间设置 + {hasGetTime && ( + + + + 预备阶段 +
+ { + if (date && date[0] && date[1]) { + setInfo({ + ...info, + mentor: { + ...info.mentor, + start_A: date[0].toDate(), + end_A: date[1].toDate(), + }, + }); + } + }} + /> +
+ + 预备阶段 +
+ { + if (date && date[0] && date[1]) { + setInfo({ + ...info, + mentor: { + ...info.mentor, + start_B: date[0].toDate(), + end_B: date[1].toDate(), + }, + }); + } + }} + /> +
+ + 第一阶段 +
+ { + if (date && date[0] && date[1]) { + setInfo({ + ...info, + mentor: { + ...info.mentor, + start_C: date[0].toDate(), + end_C: date[1].toDate(), + }, + }); + } + }} + /> +
+ + 第二阶段 +
+ { + if (date && date[0] && date[1]) { + setInfo({ + ...info, + mentor: { + ...info.mentor, + start_D: date[0].toDate(), + end_D: date[1].toDate(), + }, + }); + } + }} + /> +
+ + 第三阶段 +
+ { + if (date && date[0] && date[1]) { + setInfo({ + ...info, + mentor: { + ...info.mentor, + start_E: date[0].toDate(), + end_E: date[1].toDate(), + }, + }); + } + }} + /> +
+
+
+ )} +
+ + + )} + + {user.role === "student" && ( <> 导师列表 @@ -1231,17 +1552,35 @@ const MentorApplicationPage: React.FC = ({ mode, user }) => { 导入信息 + + + + +