mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-21 20:29:03 +08:00
主页学生卡片支持长按右键快捷加减分
This commit is contained in:
+138
-2
@@ -76,6 +76,9 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
const [reasonContent, setReasonContent] = useState("")
|
const [reasonContent, setReasonContent] = useState("")
|
||||||
const [submitLoading, setSubmitLoading] = useState(false)
|
const [submitLoading, setSubmitLoading] = useState(false)
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
|
const [quickActionStudentId, setQuickActionStudentId] = useState<number | null>(null)
|
||||||
|
const longPressTimerRef = useRef<number | null>(null)
|
||||||
|
const suppressClickRef = useRef(false)
|
||||||
|
|
||||||
const emitDataUpdated = (category: "events" | "students" | "reasons" | "all") => {
|
const emitDataUpdated = (category: "events" | "students" | "reasons" | "all") => {
|
||||||
window.dispatchEvent(new CustomEvent("ss:data-updated", { detail: { category } }))
|
window.dispatchEvent(new CustomEvent("ss:data-updated", { detail: { category } }))
|
||||||
@@ -190,11 +193,25 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
if (searchAreaRef.current && target && !searchAreaRef.current.contains(target)) {
|
if (searchAreaRef.current && target && !searchAreaRef.current.contains(target)) {
|
||||||
setShowPinyinKeyboard(false)
|
setShowPinyinKeyboard(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const quickCard = (target as HTMLElement | null)?.closest?.('[data-student-quick-card="true"]')
|
||||||
|
if (!quickCard) {
|
||||||
|
setQuickActionStudentId(null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
document.addEventListener("mousedown", onDocumentClick)
|
document.addEventListener("mousedown", onDocumentClick)
|
||||||
return () => document.removeEventListener("mousedown", onDocumentClick)
|
return () => document.removeEventListener("mousedown", onDocumentClick)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (longPressTimerRef.current !== null) {
|
||||||
|
window.clearTimeout(longPressTimerRef.current)
|
||||||
|
longPressTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const t9KeyRows = [
|
const t9KeyRows = [
|
||||||
[
|
[
|
||||||
{ digit: "2", letters: "ABC" },
|
{ digit: "2", letters: "ABC" },
|
||||||
@@ -431,6 +448,42 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
performSubmit(selectedStudent, reason.delta, reason.content)
|
performSubmit(selectedStudent, reason.delta, reason.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cancelLongPress = () => {
|
||||||
|
if (longPressTimerRef.current !== null) {
|
||||||
|
window.clearTimeout(longPressTimerRef.current)
|
||||||
|
longPressTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const startLongPress = (student: student) => {
|
||||||
|
cancelLongPress()
|
||||||
|
longPressTimerRef.current = window.setTimeout(() => {
|
||||||
|
if (!canEdit) {
|
||||||
|
messageApi.error(t("common.readOnly"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setQuickActionStudentId(student.id)
|
||||||
|
suppressClickRef.current = true
|
||||||
|
longPressTimerRef.current = null
|
||||||
|
}, 450)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openQuickAction = (student: student) => {
|
||||||
|
cancelLongPress()
|
||||||
|
if (!canEdit) {
|
||||||
|
messageApi.error(t("common.readOnly"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setQuickActionStudentId(student.id)
|
||||||
|
suppressClickRef.current = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQuickAdjust = (student: student, delta: number) => {
|
||||||
|
const content = delta > 0 ? t("home.addPoints") : t("home.deductPoints")
|
||||||
|
performSubmit(student, delta, content)
|
||||||
|
setQuickActionStudentId(null)
|
||||||
|
}
|
||||||
|
|
||||||
const renderStudentCard = (student: student, index: number) => {
|
const renderStudentCard = (student: student, index: number) => {
|
||||||
const avatarText = getDisplayText(student.name)
|
const avatarText = getDisplayText(student.name)
|
||||||
const avatarColor = getAvatarColor(student.name)
|
const avatarColor = getAvatarColor(student.name)
|
||||||
@@ -442,10 +495,34 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
else if (index === 2) rankBadge = "🥉"
|
else if (index === 2) rankBadge = "🥉"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isQuickActionMode = quickActionStudentId === student.id
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={student.id}
|
key={student.id}
|
||||||
onClick={() => openOperation(student)}
|
data-student-quick-card="true"
|
||||||
|
onClick={(e) => {
|
||||||
|
if (suppressClickRef.current) {
|
||||||
|
suppressClickRef.current = false
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
openOperation(student)
|
||||||
|
}}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
if (e.button !== 0) return
|
||||||
|
startLongPress(student)
|
||||||
|
}}
|
||||||
|
onMouseUp={cancelLongPress}
|
||||||
|
onMouseLeave={cancelLongPress}
|
||||||
|
onTouchStart={() => startLongPress(student)}
|
||||||
|
onTouchEnd={cancelLongPress}
|
||||||
|
onTouchCancel={cancelLongPress}
|
||||||
|
onContextMenu={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
openQuickAction(student)
|
||||||
|
}}
|
||||||
style={{ cursor: "pointer", position: "relative" }}
|
style={{ cursor: "pointer", position: "relative" }}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
@@ -507,6 +584,61 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div style={{ flex: 1, overflow: "hidden" }}>
|
<div style={{ flex: 1, overflow: "hidden" }}>
|
||||||
|
{isQuickActionMode ? (
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleQuickAdjust(student, 1)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
minWidth: "54px",
|
||||||
|
height: "36px",
|
||||||
|
borderRadius: "18px",
|
||||||
|
fontWeight: 700,
|
||||||
|
paddingInline: "12px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+1
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleQuickAdjust(student, -1)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
minWidth: "54px",
|
||||||
|
height: "36px",
|
||||||
|
borderRadius: "18px",
|
||||||
|
fontWeight: 700,
|
||||||
|
paddingInline: "12px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
-1
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
setQuickActionStudentId(null)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: "36px",
|
||||||
|
height: "36px",
|
||||||
|
borderRadius: "18px",
|
||||||
|
paddingInline: 0,
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
@@ -519,7 +651,9 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
>
|
>
|
||||||
{student.name}
|
{student.name}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: "4px", marginTop: "2px" }}>
|
<div
|
||||||
|
style={{ display: "flex", alignItems: "center", gap: "4px", marginTop: "2px" }}
|
||||||
|
>
|
||||||
<Tag
|
<Tag
|
||||||
color={student.score > 0 ? "success" : student.score < 0 ? "error" : "default"}
|
color={student.score > 0 ? "success" : student.score < 0 ? "error" : "default"}
|
||||||
style={{ fontWeight: "bold" }}
|
style={{ fontWeight: "bold" }}
|
||||||
@@ -527,6 +661,8 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
{student.score > 0 ? `+${student.score}` : student.score}
|
{student.score > 0 ? `+${student.score}` : student.score}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user