[feat] Support empty numeric inputs & UI improvements for real app

This commit is contained in:
He
2026-06-16 19:00:03 +08:00
parent b926a6e30d
commit b86716e952
7 changed files with 183 additions and 87 deletions
+39 -19
View File
@@ -54,9 +54,9 @@ function generateGroups(
export interface RollCallState {
mode: Mode
totalTasks: number
pickCount: number
rounds: number
totalTasks: number | string
pickCount: number | string
rounds: number | string
allowRepeat: boolean
// Multi mode
groups: { numbers: number[]; colorIndex: number }[]
@@ -77,9 +77,9 @@ export interface RollCallState {
export interface RollCallActions {
setMode: (v: Mode) => void
setTotalTasks: (v: number) => void
setPickCount: (v: number) => void
setRounds: (v: number) => void
setTotalTasks: (v: number | string) => void
setPickCount: (v: number | string) => void
setRounds: (v: number | string) => void
setAllowRepeat: (v: boolean) => void
setSingleAllowRepeat: (v: boolean) => void
handleRoll: () => void
@@ -113,9 +113,9 @@ export const COLORS = [
export function useRollCallLogic(): [RollCallState, RollCallActions] {
const [mode, setMode] = useState<Mode>("single")
const [totalTasks, setTotalTasks] = useState(35)
const [pickCount, setPickCount] = useState(1)
const [rounds, setRounds] = useState(1)
const [totalTasks, setTotalTasks] = useState<number | string>(35)
const [pickCount, setPickCount] = useState<number | string>(1)
const [rounds, setRounds] = useState<number | string>(1)
const [allowRepeat, setAllowRepeat] = useState(false)
// Multi mode state
const [groups, setGroups] = useState<{ numbers: number[]; colorIndex: number }[]>([])
@@ -147,7 +147,7 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
setPlaceholder(undefined)
}, [])
const handleTotalChange = useCallback((v: number) => {
const handleTotalChange = useCallback((v: number | string) => {
setTotalTasks(v)
setHighlighted(new Set())
setUsedAll(new Set())
@@ -161,23 +161,33 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
setPlaceholder(undefined)
}, [])
const handleRoundsChange = useCallback((v: number) => {
const handleRoundsChange = useCallback((v: number | string) => {
setRounds(v)
if (v < 2) setAllowRepeat(false)
if (typeof v === 'number' && v < 2) setAllowRepeat(false)
setHighlighted(new Set())
setGroups([])
setHasResult(false)
setErrorMsg("")
setPlaceholder("参数已修改,请重新执行")
}, [])
const handleRoll = useCallback(async () => {
setErrorMsg("")
// 检查空值
if (totalTasks === "" || pickCount === "" || rounds === "") {
setErrorMsg("请填写所有参数")
return
}
const total = totalTasks as number
const pick = pickCount as number
const roundCount = rounds as number
setIsRolling(true)
await new Promise((r) => setTimeout(r, 240))
const effectiveRepeat = rounds < 2 ? false : allowRepeat
const result = generateGroups(totalTasks, pickCount, rounds, effectiveRepeat)
const effectiveRepeat = roundCount < 2 ? false : allowRepeat
const result = generateGroups(total, pick, roundCount, effectiveRepeat)
if (!result.success) {
setErrorMsg(result.errorMsg)
@@ -200,6 +210,16 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
const handleSingleRoll = useCallback(async () => {
setErrorMsg("")
// 检查空值
if (totalTasks === "" || pickCount === "") {
setErrorMsg("请填写所有参数")
return
}
const total = totalTasks as number
const pick = pickCount as number
setIsRolling(true)
setIsSingleComplete(false)
await new Promise((r) => setTimeout(r, 240))
@@ -207,15 +227,15 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
const usedNumbers = new Set(selectedRecords.map(r => r.number))
// 如果不允许重复,检查剩余人数
if (!singleAllowRepeat && pickCount > totalTasks - usedNumbers.size) {
setErrorMsg(`剩余可选人数不足 ${pickCount}`)
if (!singleAllowRepeat && pick > total - usedNumbers.size) {
setErrorMsg(`剩余可选人数不足 ${pick}`)
setIsRolling(false)
return
}
// 允许重复时,不需要检查人数
const forbidSet = singleAllowRepeat ? new Set<number>() : usedNumbers
const nums = getRandomDistinct(totalTasks, pickCount, forbidSet)
const nums = getRandomDistinct(total, pick, forbidSet)
if (!nums) {
setErrorMsg("抽取失败,人数不足")
setIsRolling(false)
@@ -308,7 +328,7 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
const actions: RollCallActions = {
setMode: handleModeChange,
setTotalTasks: handleTotalChange,
setPickCount: (v: number) => { setPickCount(v); setErrorMsg("") },
setPickCount: (v: number | string) => { setPickCount(v); setErrorMsg("") },
setRounds: handleRoundsChange,
setAllowRepeat,
setSingleAllowRepeat,