mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 21:14:21 +08:00
feat: 优化分组编辑弹窗滚动并支持新建分组拖拽
This commit is contained in:
@@ -210,3 +210,17 @@ html.platform-macos #root {
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ss-group-board-modal .ant-modal {
|
||||||
|
max-height: calc(100vh - 24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-group-board-modal .ant-modal-content {
|
||||||
|
max-height: calc(100vh - 24px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-group-board-modal .ant-modal-body {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
} from "antd"
|
} from "antd"
|
||||||
import type { ColumnsType } from "antd/es/table"
|
import type { ColumnsType } from "antd/es/table"
|
||||||
import { UploadOutlined, MoreOutlined } from "@ant-design/icons"
|
import { UploadOutlined, MoreOutlined, PlusOutlined } from "@ant-design/icons"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { TagEditorDialog } from "./TagEditorDialog"
|
import { TagEditorDialog } from "./TagEditorDialog"
|
||||||
import { getAvatarFromExtraJson, setAvatarInExtraJson } from "../utils/studentAvatar"
|
import { getAvatarFromExtraJson, setAvatarInExtraJson } from "../utils/studentAvatar"
|
||||||
@@ -104,6 +104,7 @@ export const StudentManager: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
const [groupBoardSaving, setGroupBoardSaving] = useState(false)
|
const [groupBoardSaving, setGroupBoardSaving] = useState(false)
|
||||||
const [groupBoard, setGroupBoard] = useState<Record<string, student[]>>({})
|
const [groupBoard, setGroupBoard] = useState<Record<string, student[]>>({})
|
||||||
const [groupBoardOrder, setGroupBoardOrder] = useState<string[]>([])
|
const [groupBoardOrder, setGroupBoardOrder] = useState<string[]>([])
|
||||||
|
const [groupBoardNewGroupName, setGroupBoardNewGroupName] = useState("")
|
||||||
const [pointerDraggingStudentId, setPointerDraggingStudentId] = useState<number | null>(null)
|
const [pointerDraggingStudentId, setPointerDraggingStudentId] = useState<number | null>(null)
|
||||||
const [pointerTargetGroup, setPointerTargetGroup] = useState<string | null>(null)
|
const [pointerTargetGroup, setPointerTargetGroup] = useState<string | null>(null)
|
||||||
const [pointerDragStudentName, setPointerDragStudentName] = useState("")
|
const [pointerDragStudentName, setPointerDragStudentName] = useState("")
|
||||||
@@ -378,9 +379,33 @@ export const StudentManager: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
})
|
})
|
||||||
setGroupBoardOrder(order)
|
setGroupBoardOrder(order)
|
||||||
setGroupBoard(board)
|
setGroupBoard(board)
|
||||||
|
setGroupBoardNewGroupName("")
|
||||||
setGroupBoardVisible(true)
|
setGroupBoardVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleCreateGroupInBoard = () => {
|
||||||
|
const name = groupBoardNewGroupName.trim()
|
||||||
|
if (!name) {
|
||||||
|
messageApi.warning(t("students.groupBoardGroupNameRequired"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (name === UNGROUPED_KEY) {
|
||||||
|
messageApi.warning(t("students.groupBoardGroupNameInvalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (groupBoardOrder.includes(name)) {
|
||||||
|
messageApi.warning(t("students.groupBoardGroupExists"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setGroupBoard((prev) => ({ ...prev, [name]: [] }))
|
||||||
|
setGroupBoardOrder((prev) => {
|
||||||
|
const withoutUngrouped = prev.filter((key) => key !== UNGROUPED_KEY)
|
||||||
|
return [...withoutUngrouped, name, UNGROUPED_KEY]
|
||||||
|
})
|
||||||
|
setGroupBoardNewGroupName("")
|
||||||
|
}
|
||||||
|
|
||||||
const moveStudentToGroup = (studentId: number, targetGroup: string) => {
|
const moveStudentToGroup = (studentId: number, targetGroup: string) => {
|
||||||
setGroupBoard((prev) => {
|
setGroupBoard((prev) => {
|
||||||
let movingStudent: student | null = null
|
let movingStudent: student | null = null
|
||||||
@@ -1356,6 +1381,7 @@ export const StudentManager: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
open={groupBoardVisible}
|
open={groupBoardVisible}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setGroupBoardVisible(false)
|
setGroupBoardVisible(false)
|
||||||
|
setGroupBoardNewGroupName("")
|
||||||
draggingStudentIdRef.current = null
|
draggingStudentIdRef.current = null
|
||||||
pointerDragSourceGroupRef.current = null
|
pointerDragSourceGroupRef.current = null
|
||||||
pointerDragTargetGroupRef.current = null
|
pointerDragTargetGroupRef.current = null
|
||||||
@@ -1369,11 +1395,25 @@ export const StudentManager: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
cancelText={t("common.cancel")}
|
cancelText={t("common.cancel")}
|
||||||
okButtonProps={{ loading: groupBoardSaving }}
|
okButtonProps={{ loading: groupBoardSaving }}
|
||||||
width="90%"
|
width="90%"
|
||||||
|
wrapClassName="ss-group-board-modal"
|
||||||
|
styles={{ body: { maxHeight: "calc(100vh - 220px)", overflowY: "auto" } }}
|
||||||
destroyOnHidden
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<div style={{ color: "var(--ss-text-secondary)", marginBottom: 12, fontSize: 12 }}>
|
<div style={{ color: "var(--ss-text-secondary)", marginBottom: 12, fontSize: 12 }}>
|
||||||
{t("students.groupBoardHint")}
|
{t("students.groupBoardHint")}
|
||||||
</div>
|
</div>
|
||||||
|
<Space style={{ marginBottom: 12, width: "100%" }}>
|
||||||
|
<Input
|
||||||
|
value={groupBoardNewGroupName}
|
||||||
|
onChange={(e) => setGroupBoardNewGroupName(e.target.value)}
|
||||||
|
onPressEnter={handleCreateGroupInBoard}
|
||||||
|
placeholder={t("students.groupBoardNewGroupPlaceholder")}
|
||||||
|
maxLength={32}
|
||||||
|
/>
|
||||||
|
<Button icon={<PlusOutlined />} onClick={handleCreateGroupInBoard}>
|
||||||
|
{t("students.groupBoardAddGroup")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|||||||
@@ -520,6 +520,11 @@
|
|||||||
"groupBoardEdit": "Edit Groups",
|
"groupBoardEdit": "Edit Groups",
|
||||||
"groupBoardTitle": "Quick Group Editor",
|
"groupBoardTitle": "Quick Group Editor",
|
||||||
"groupBoardHint": "Drag students across group columns and save to apply in batch.",
|
"groupBoardHint": "Drag students across group columns and save to apply in batch.",
|
||||||
|
"groupBoardNewGroupPlaceholder": "Enter new group name",
|
||||||
|
"groupBoardAddGroup": "New Group",
|
||||||
|
"groupBoardGroupExists": "Group already exists",
|
||||||
|
"groupBoardGroupNameRequired": "Please enter group name",
|
||||||
|
"groupBoardGroupNameInvalid": "Invalid group name",
|
||||||
"groupBoardEmpty": "Drag students here",
|
"groupBoardEmpty": "Drag students here",
|
||||||
"groupBoardNoChanges": "No group changes",
|
"groupBoardNoChanges": "No group changes",
|
||||||
"groupBoardSaveSuccess": "Updated groups for {{count}} students",
|
"groupBoardSaveSuccess": "Updated groups for {{count}} students",
|
||||||
|
|||||||
@@ -520,6 +520,11 @@
|
|||||||
"groupBoardEdit": "编辑分组",
|
"groupBoardEdit": "编辑分组",
|
||||||
"groupBoardTitle": "快速编辑分组",
|
"groupBoardTitle": "快速编辑分组",
|
||||||
"groupBoardHint": "拖动学生到不同小组卡片中,点击保存后批量生效。",
|
"groupBoardHint": "拖动学生到不同小组卡片中,点击保存后批量生效。",
|
||||||
|
"groupBoardNewGroupPlaceholder": "输入新分组名称",
|
||||||
|
"groupBoardAddGroup": "新建分组",
|
||||||
|
"groupBoardGroupExists": "该分组已存在",
|
||||||
|
"groupBoardGroupNameRequired": "请输入分组名称",
|
||||||
|
"groupBoardGroupNameInvalid": "分组名称无效",
|
||||||
"groupBoardEmpty": "可将学生拖拽到这里",
|
"groupBoardEmpty": "可将学生拖拽到这里",
|
||||||
"groupBoardNoChanges": "分组未发生变化",
|
"groupBoardNoChanges": "分组未发生变化",
|
||||||
"groupBoardSaveSuccess": "已更新 {{count}} 名学生的小组",
|
"groupBoardSaveSuccess": "已更新 {{count}} 名学生的小组",
|
||||||
|
|||||||
Reference in New Issue
Block a user