mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 21:14:21 +08:00
fix: 优化主页卡片到弹窗过渡与遮罩动画
This commit is contained in:
@@ -229,6 +229,80 @@ html.platform-macos #root {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ss-reward-morph-modal {
|
||||||
|
--ss-modal-from-x: 0px;
|
||||||
|
--ss-modal-from-y: 0px;
|
||||||
|
--ss-modal-scale-x: 1;
|
||||||
|
--ss-modal-scale-y: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-reward-morph-modal.is-preparing {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-reward-morph-modal .ant-modal-content {
|
||||||
|
transform-origin: center;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-enter,
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-appear,
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-leave,
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-enter-active,
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-appear-active,
|
||||||
|
.ss-reward-morph-wrap.ss-reward-noop-motion-leave-active,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-enter,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-appear,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-leave,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-enter-active,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-appear-active,
|
||||||
|
.ss-reward-morph-root .ss-reward-morph-modal.ss-reward-noop-motion-leave-active {
|
||||||
|
animation: none !important;
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-reward-morph-modal.is-enter .ant-modal-content {
|
||||||
|
animation: ss-reward-modal-morph-in 300ms cubic-bezier(0.2, 0.82, 0.22, 1) both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-home-operation-morph-modal .ant-modal-content {
|
||||||
|
transform-origin: center;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-operation-mask-fade-enter,
|
||||||
|
.ss-operation-mask-fade-appear {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-operation-mask-fade-enter-active,
|
||||||
|
.ss-operation-mask-fade-appear-active {
|
||||||
|
opacity: 1 !important;
|
||||||
|
transition: opacity 260ms cubic-bezier(0.2, 0, 0, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-operation-mask-fade-leave {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ss-operation-mask-fade-leave-active {
|
||||||
|
opacity: 0 !important;
|
||||||
|
transition: opacity 220ms cubic-bezier(0.4, 0, 1, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ss-reward-modal-morph-in {
|
||||||
|
from {
|
||||||
|
transform: translate3d(var(--ss-modal-from-x), var(--ss-modal-from-y), 0)
|
||||||
|
scale(var(--ss-modal-scale-x), var(--ss-modal-scale-y));
|
||||||
|
opacity: 0.94;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translate3d(0, 0, 0) scale(1, 1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ss-immersive-sidebar {
|
.ss-immersive-sidebar {
|
||||||
--ss-sidebar-width: 200px;
|
--ss-sidebar-width: 200px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
+289
-11
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback, useMemo, useRef } from "react"
|
import React, { useState, useEffect, useLayoutEffect, useCallback, useMemo, useRef } from "react"
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
Space,
|
Space,
|
||||||
@@ -127,6 +127,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
const [batchMode, setBatchMode] = useState(false)
|
const [batchMode, setBatchMode] = useState(false)
|
||||||
const [selectedStudentIds, setSelectedStudentIds] = useState<number[]>([])
|
const [selectedStudentIds, setSelectedStudentIds] = useState<number[]>([])
|
||||||
const [operationVisible, setOperationVisible] = useState(false)
|
const [operationVisible, setOperationVisible] = useState(false)
|
||||||
|
const [operationOriginRect, setOperationOriginRect] = useState<DOMRect | null>(null)
|
||||||
const [customScore, setCustomScore] = useState<number | undefined>(undefined)
|
const [customScore, setCustomScore] = useState<number | undefined>(undefined)
|
||||||
const [reasonContent, setReasonContent] = useState("")
|
const [reasonContent, setReasonContent] = useState("")
|
||||||
const [submitLoading, setSubmitLoading] = useState(false)
|
const [submitLoading, setSubmitLoading] = useState(false)
|
||||||
@@ -141,6 +142,13 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
const longPressTimerRef = useRef<number | null>(null)
|
const longPressTimerRef = useRef<number | null>(null)
|
||||||
const suppressClickRef = useRef(false)
|
const suppressClickRef = useRef(false)
|
||||||
const fetchRequestIdRef = useRef(0)
|
const fetchRequestIdRef = useRef(0)
|
||||||
|
const operationMorphAnimationRef = useRef<Animation | null>(null)
|
||||||
|
const operationMaskAnimationRef = useRef<Animation | null>(null)
|
||||||
|
const operationMorphRafRef = useRef<number | null>(null)
|
||||||
|
const operationClosingRef = useRef(false)
|
||||||
|
const operationCloseTokenRef = useRef(0)
|
||||||
|
const operationModalRootClass = "ss-home-operation-morph-root"
|
||||||
|
const operationModalClass = "ss-home-operation-morph-modal"
|
||||||
|
|
||||||
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 } }))
|
||||||
@@ -589,7 +597,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const openOperation = (student: student) => {
|
const openOperation = (student: student, sourceEl?: HTMLElement | null) => {
|
||||||
if (!canEdit) {
|
if (!canEdit) {
|
||||||
messageApi.error(t("common.readOnly"))
|
messageApi.error(t("common.readOnly"))
|
||||||
return
|
return
|
||||||
@@ -605,12 +613,277 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cardEl = sourceEl?.querySelector(".ant-card") as HTMLElement | null
|
||||||
|
const sourceRect = (cardEl ?? sourceEl)?.getBoundingClientRect() ?? null
|
||||||
|
logHome("operation:morph:open", {
|
||||||
|
student: student.name,
|
||||||
|
hasSourceEl: Boolean(sourceEl),
|
||||||
|
hasCardEl: Boolean(cardEl),
|
||||||
|
sourceRect: sourceRect
|
||||||
|
? {
|
||||||
|
left: sourceRect.left,
|
||||||
|
top: sourceRect.top,
|
||||||
|
width: sourceRect.width,
|
||||||
|
height: sourceRect.height,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
})
|
||||||
|
setOperationOriginRect(sourceRect)
|
||||||
|
operationClosingRef.current = false
|
||||||
|
operationCloseTokenRef.current += 1
|
||||||
|
operationMorphAnimationRef.current?.cancel()
|
||||||
|
operationMaskAnimationRef.current?.cancel()
|
||||||
|
|
||||||
setSelectedStudent(student)
|
setSelectedStudent(student)
|
||||||
setCustomScore(undefined)
|
setCustomScore(undefined)
|
||||||
setReasonContent("")
|
setReasonContent("")
|
||||||
setOperationVisible(true)
|
setOperationVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const playOperationMorph = useCallback((attempt = 0) => {
|
||||||
|
if (isPortraitMode || !operationOriginRect) return false
|
||||||
|
const modalEl = document.querySelector(`.${operationModalClass}`) as HTMLElement | null
|
||||||
|
if (!modalEl) {
|
||||||
|
const byClassCount = document.querySelectorAll(`.${operationModalClass}`).length
|
||||||
|
const byRootCount = document.querySelectorAll(`.${operationModalRootClass}`).length
|
||||||
|
const modalCount = document.querySelectorAll(".ant-modal").length
|
||||||
|
const rootExists = Boolean(document.querySelector(`.${operationModalRootClass}`))
|
||||||
|
logHome("operation:morph:modal-miss", {
|
||||||
|
attempt,
|
||||||
|
rootExists,
|
||||||
|
byClassCount,
|
||||||
|
byRootCount,
|
||||||
|
modalCount,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any leftover transform from previous close animation before measuring.
|
||||||
|
operationMorphAnimationRef.current?.cancel()
|
||||||
|
for (const animation of modalEl.getAnimations()) {
|
||||||
|
animation.cancel()
|
||||||
|
}
|
||||||
|
modalEl.style.transform = ""
|
||||||
|
modalEl.style.opacity = ""
|
||||||
|
modalEl.style.visibility = ""
|
||||||
|
const maskEl = document.querySelector(`.${operationModalRootClass} .ant-modal-mask`) as
|
||||||
|
| HTMLElement
|
||||||
|
| null
|
||||||
|
if (maskEl) {
|
||||||
|
operationMaskAnimationRef.current?.cancel()
|
||||||
|
maskEl.style.opacity = ""
|
||||||
|
maskEl.style.visibility = ""
|
||||||
|
operationMaskAnimationRef.current = maskEl.animate([{ opacity: 0 }, { opacity: 1 }], {
|
||||||
|
duration: 220,
|
||||||
|
easing: "cubic-bezier(0.2, 0, 0, 1)",
|
||||||
|
fill: "both",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const modalRect = modalEl.getBoundingClientRect()
|
||||||
|
if (modalRect.width <= 0 || modalRect.height <= 0) {
|
||||||
|
logHome("operation:morph:modal-rect-invalid", {
|
||||||
|
attempt,
|
||||||
|
width: modalRect.width,
|
||||||
|
height: modalRect.height,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const fromX = operationOriginRect.left - modalRect.left
|
||||||
|
const fromY = operationOriginRect.top - modalRect.top
|
||||||
|
const scaleX = operationOriginRect.width / modalRect.width
|
||||||
|
const scaleY = operationOriginRect.height / modalRect.height
|
||||||
|
|
||||||
|
logHome("operation:morph:computed", {
|
||||||
|
modalRect: {
|
||||||
|
left: modalRect.left,
|
||||||
|
top: modalRect.top,
|
||||||
|
width: modalRect.width,
|
||||||
|
height: modalRect.height,
|
||||||
|
},
|
||||||
|
fromX,
|
||||||
|
fromY,
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
expectedStartRect: {
|
||||||
|
left: modalRect.left + fromX,
|
||||||
|
top: modalRect.top + fromY,
|
||||||
|
width: modalRect.width * scaleX,
|
||||||
|
height: modalRect.height * scaleY,
|
||||||
|
},
|
||||||
|
animateSupported: typeof modalEl.animate === "function",
|
||||||
|
})
|
||||||
|
|
||||||
|
modalEl.style.transformOrigin = "top left"
|
||||||
|
modalEl.style.willChange = "transform, opacity"
|
||||||
|
operationMorphAnimationRef.current = modalEl.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: `translate3d(${fromX}px, ${fromY}px, 0) scale(${scaleX}, ${scaleY})`,
|
||||||
|
opacity: 0.86,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transform: "translate3d(0, 0, 0) scale(1, 1)",
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 480,
|
||||||
|
easing: "cubic-bezier(0.16, 1, 0.3, 1)",
|
||||||
|
fill: "both",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
logHome("operation:morph:animation-start", {
|
||||||
|
attempt,
|
||||||
|
currentTime: operationMorphAnimationRef.current.currentTime,
|
||||||
|
playState: operationMorphAnimationRef.current.playState,
|
||||||
|
})
|
||||||
|
operationMorphAnimationRef.current.onfinish = () => {
|
||||||
|
logHome("operation:morph:animation-finish")
|
||||||
|
}
|
||||||
|
operationMorphAnimationRef.current.oncancel = () => {
|
||||||
|
logHome("operation:morph:animation-cancel")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, [isPortraitMode, operationOriginRect, operationModalClass, operationModalRootClass])
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (isPortraitMode || !operationVisible) return
|
||||||
|
|
||||||
|
logHome("operation:morph:layout-open", {
|
||||||
|
hasOriginRect: Boolean(operationOriginRect),
|
||||||
|
})
|
||||||
|
let attempt = 0
|
||||||
|
const maxAttempts = 120
|
||||||
|
|
||||||
|
const run = () => {
|
||||||
|
operationMorphRafRef.current = null
|
||||||
|
const done = playOperationMorph(attempt)
|
||||||
|
if (done) return
|
||||||
|
if (attempt >= maxAttempts) {
|
||||||
|
logHome("operation:morph:retry-exhausted", { attempts: attempt + 1 })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
attempt += 1
|
||||||
|
operationMorphRafRef.current = window.requestAnimationFrame(run)
|
||||||
|
}
|
||||||
|
operationMorphRafRef.current = window.requestAnimationFrame(run)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (operationMorphRafRef.current !== null) {
|
||||||
|
window.cancelAnimationFrame(operationMorphRafRef.current)
|
||||||
|
operationMorphRafRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isPortraitMode, operationVisible, operationOriginRect, playOperationMorph])
|
||||||
|
|
||||||
|
const finishCloseOperationModal = useCallback((skipCancelMorph = false, skipCancelMask = false) => {
|
||||||
|
if (!skipCancelMorph) {
|
||||||
|
operationMorphAnimationRef.current?.cancel()
|
||||||
|
}
|
||||||
|
operationMorphAnimationRef.current = null
|
||||||
|
if (!skipCancelMask) {
|
||||||
|
operationMaskAnimationRef.current?.cancel()
|
||||||
|
}
|
||||||
|
operationMaskAnimationRef.current = null
|
||||||
|
if (operationMorphRafRef.current !== null) {
|
||||||
|
window.cancelAnimationFrame(operationMorphRafRef.current)
|
||||||
|
operationMorphRafRef.current = null
|
||||||
|
}
|
||||||
|
operationClosingRef.current = false
|
||||||
|
setOperationVisible(false)
|
||||||
|
setOperationOriginRect(null)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const closeOperationModal = useCallback(() => {
|
||||||
|
logHome("operation:morph:close", {
|
||||||
|
hasAnimation: Boolean(operationMorphAnimationRef.current),
|
||||||
|
playState: operationMorphAnimationRef.current?.playState,
|
||||||
|
currentTime: operationMorphAnimationRef.current?.currentTime,
|
||||||
|
})
|
||||||
|
if (operationMorphRafRef.current !== null) {
|
||||||
|
window.cancelAnimationFrame(operationMorphRafRef.current)
|
||||||
|
operationMorphRafRef.current = null
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!isPortraitMode &&
|
||||||
|
operationVisible &&
|
||||||
|
operationOriginRect &&
|
||||||
|
!operationClosingRef.current
|
||||||
|
) {
|
||||||
|
const modalEl = document.querySelector(`.${operationModalClass}`) as HTMLElement | null
|
||||||
|
if (modalEl) {
|
||||||
|
const modalRect = modalEl.getBoundingClientRect()
|
||||||
|
if (modalRect.width > 0 && modalRect.height > 0) {
|
||||||
|
const toX = operationOriginRect.left - modalRect.left
|
||||||
|
const toY = operationOriginRect.top - modalRect.top
|
||||||
|
const toScaleX = operationOriginRect.width / modalRect.width
|
||||||
|
const toScaleY = operationOriginRect.height / modalRect.height
|
||||||
|
const closeToken = ++operationCloseTokenRef.current
|
||||||
|
operationClosingRef.current = true
|
||||||
|
operationMorphAnimationRef.current?.cancel()
|
||||||
|
operationMaskAnimationRef.current?.cancel()
|
||||||
|
modalEl.style.transformOrigin = "top left"
|
||||||
|
modalEl.style.willChange = "transform, opacity"
|
||||||
|
const maskEl = document.querySelector(
|
||||||
|
`.${operationModalRootClass} .ant-modal-mask`
|
||||||
|
) as HTMLElement | null
|
||||||
|
if (maskEl) {
|
||||||
|
operationMaskAnimationRef.current = maskEl.animate([{ opacity: 1 }, { opacity: 0 }], {
|
||||||
|
duration: 320,
|
||||||
|
easing: "cubic-bezier(0.4, 0, 1, 1)",
|
||||||
|
fill: "both",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
operationMorphAnimationRef.current = modalEl.animate(
|
||||||
|
[
|
||||||
|
{ transform: "translate3d(0, 0, 0) scale(1, 1)", opacity: 1 },
|
||||||
|
{
|
||||||
|
transform: `translate3d(${toX}px, ${toY}px, 0) scale(${toScaleX}, ${toScaleY})`,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 320,
|
||||||
|
easing: "cubic-bezier(0.4, 0, 1, 1)",
|
||||||
|
fill: "both",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
operationMorphAnimationRef.current.onfinish = () => {
|
||||||
|
if (operationCloseTokenRef.current !== closeToken || !operationClosingRef.current) {
|
||||||
|
logHome("operation:morph:close-animation-finish:stale", { closeToken })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logHome("operation:morph:close-animation-finish")
|
||||||
|
modalEl.style.opacity = "0"
|
||||||
|
modalEl.style.visibility = "hidden"
|
||||||
|
if (maskEl) {
|
||||||
|
maskEl.style.opacity = "0"
|
||||||
|
maskEl.style.visibility = "hidden"
|
||||||
|
}
|
||||||
|
finishCloseOperationModal(true, true)
|
||||||
|
}
|
||||||
|
operationMorphAnimationRef.current.oncancel = () => {
|
||||||
|
if (operationCloseTokenRef.current !== closeToken || !operationClosingRef.current) {
|
||||||
|
logHome("operation:morph:close-animation-cancel:stale", { closeToken })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logHome("operation:morph:close-animation-cancel")
|
||||||
|
finishCloseOperationModal()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finishCloseOperationModal()
|
||||||
|
}, [
|
||||||
|
finishCloseOperationModal,
|
||||||
|
isPortraitMode,
|
||||||
|
operationModalClass,
|
||||||
|
operationOriginRect,
|
||||||
|
operationVisible,
|
||||||
|
])
|
||||||
|
|
||||||
const handleToggleRewardMode = () => {
|
const handleToggleRewardMode = () => {
|
||||||
if (!canEdit) {
|
if (!canEdit) {
|
||||||
messageApi.error(t("common.readOnly"))
|
messageApi.error(t("common.readOnly"))
|
||||||
@@ -623,7 +896,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
setRewardMode((prev) => !prev)
|
setRewardMode((prev) => !prev)
|
||||||
setBatchMode(false)
|
setBatchMode(false)
|
||||||
setSelectedStudentIds([])
|
setSelectedStudentIds([])
|
||||||
setOperationVisible(false)
|
closeOperationModal()
|
||||||
setQuickActionStudentId(null)
|
setQuickActionStudentId(null)
|
||||||
setRewardStudent(null)
|
setRewardStudent(null)
|
||||||
setRewardModalVisible(false)
|
setRewardModalVisible(false)
|
||||||
@@ -717,7 +990,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
setSelectedStudentIds([])
|
setSelectedStudentIds([])
|
||||||
setBatchMode(false)
|
setBatchMode(false)
|
||||||
setSelectedStudent(null)
|
setSelectedStudent(null)
|
||||||
setOperationVisible(false)
|
closeOperationModal()
|
||||||
setCustomScore(undefined)
|
setCustomScore(undefined)
|
||||||
setReasonContent("")
|
setReasonContent("")
|
||||||
setQuickActionStudentId(null)
|
setQuickActionStudentId(null)
|
||||||
@@ -846,7 +1119,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
}
|
}
|
||||||
setBatchMode(true)
|
setBatchMode(true)
|
||||||
setSelectedStudent(null)
|
setSelectedStudent(null)
|
||||||
setOperationVisible(false)
|
closeOperationModal()
|
||||||
setQuickActionStudentId(null)
|
setQuickActionStudentId(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,7 +1168,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
openOperation(student)
|
openOperation(student, e.currentTarget as HTMLElement)
|
||||||
}}
|
}}
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
if (batchMode) return
|
if (batchMode) return
|
||||||
@@ -1113,7 +1386,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
openOperation(student)
|
openOperation(student, e.currentTarget as HTMLElement)
|
||||||
}}
|
}}
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
if (batchMode) return
|
if (batchMode) return
|
||||||
@@ -1280,7 +1553,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
openOperation(student)
|
openOperation(student, e.currentTarget as HTMLElement)
|
||||||
}}
|
}}
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
if (batchMode) return
|
if (batchMode) return
|
||||||
@@ -2705,7 +2978,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
placement="bottom"
|
placement="bottom"
|
||||||
height="100%"
|
height="100%"
|
||||||
open={operationVisible}
|
open={operationVisible}
|
||||||
onClose={() => setOperationVisible(false)}
|
onClose={closeOperationModal}
|
||||||
afterOpenChange={applyDrawerDragRegion}
|
afterOpenChange={applyDrawerDragRegion}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
styles={{
|
styles={{
|
||||||
@@ -2713,7 +2986,7 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
}}
|
}}
|
||||||
footer={
|
footer={
|
||||||
<Space style={{ width: "100%", justifyContent: "flex-end" }}>
|
<Space style={{ width: "100%", justifyContent: "flex-end" }}>
|
||||||
<Button onClick={() => setOperationVisible(false)}>{t("common.cancel")}</Button>
|
<Button onClick={closeOperationModal}>{t("common.cancel")}</Button>
|
||||||
<Button type="primary" onClick={handleSubmit} loading={submitLoading}>
|
<Button type="primary" onClick={handleSubmit} loading={submitLoading}>
|
||||||
{t("home.submitOperation")}
|
{t("home.submitOperation")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -2730,13 +3003,18 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
: t("home.operationTitle", { name: selectedStudent?.name })
|
: t("home.operationTitle", { name: selectedStudent?.name })
|
||||||
}
|
}
|
||||||
open={operationVisible}
|
open={operationVisible}
|
||||||
onCancel={() => setOperationVisible(false)}
|
onCancel={closeOperationModal}
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
confirmLoading={submitLoading}
|
confirmLoading={submitLoading}
|
||||||
okText={t("home.submitOperation")}
|
okText={t("home.submitOperation")}
|
||||||
cancelText={t("common.cancel")}
|
cancelText={t("common.cancel")}
|
||||||
width={560}
|
width={560}
|
||||||
centered
|
centered
|
||||||
|
forceRender
|
||||||
|
transitionName=""
|
||||||
|
maskTransitionName=""
|
||||||
|
rootClassName={operationModalRootClass}
|
||||||
|
className={operationModalClass}
|
||||||
styles={{
|
styles={{
|
||||||
body: {
|
body: {
|
||||||
maxHeight: "calc(100vh - 220px)",
|
maxHeight: "calc(100vh - 220px)",
|
||||||
|
|||||||
Reference in New Issue
Block a user