成绩录入页面优化

This commit is contained in:
biss committed 2026-08-15 18:57:39 +08:00
1 parent 53bee58a84
commit 7124011da9
3 files changed
+234 -54

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
import { nextTick } from 'vue'
type Direction = 'up' | 'down' | 'left' | 'right'
/**
* Makes an editable score table behave like a spreadsheet without changing
* the normal keyboard behaviour of selects, switches, or free-text fields.
*/
export function useScoreGridNavigation(grid: string) {
function handleScoreGridKeydown(event: KeyboardEvent) {
const directionByKey: Record<string, Direction | undefined> = {
Enter: 'down',
ArrowUp: 'up',
ArrowDown: 'down',
ArrowLeft: 'left',
ArrowRight: 'right',
}
const direction = directionByKey[event.key]
if (!direction) return
const current = event.currentTarget as HTMLElement
const row = Number(current.dataset.scoreRow)
const column = Number(current.dataset.scoreColumn)
if (!Number.isFinite(row) || !Number.isFinite(column)) return
const cells = Array.from(
document.querySelectorAll<HTMLElement>(`[data-score-grid="${grid}"]`),
).filter((cell) => {
const input = cell.querySelector<HTMLInputElement>('input')
return input && !input.disabled && !input.readOnly
})
const findCell = (targetRow: number, targetColumn: number) =>
cells.find((cell) =>
Number(cell.dataset.scoreRow) === targetRow
&& Number(cell.dataset.scoreColumn) === targetColumn)
let target: HTMLElement | undefined
if (direction === 'left' || direction === 'right') {
const rowCells = cells
.filter((cell) => Number(cell.dataset.scoreRow) === row)
.sort((left, right) => Number(left.dataset.scoreColumn) - Number(right.dataset.scoreColumn))
const currentIndex = rowCells.indexOf(current)
target = rowCells[currentIndex + (direction === 'left' ? -1 : 1)]
} else {
const columnCells = cells
.filter((cell) => Number(cell.dataset.scoreColumn) === column)
.sort((top, bottom) => Number(top.dataset.scoreRow) - Number(bottom.dataset.scoreRow))
const currentIndex = columnCells.indexOf(current)
target = columnCells[currentIndex + (direction === 'up' ? -1 : 1)]
?? findCell(row + (direction === 'up' ? -1 : 1), column)
}
// Keep arrow keys from changing an input-number value; navigation is the
// expected spreadsheet action even at an edge where no next cell exists.
event.preventDefault()
if (!target) return
void nextTick(() => {
const input = target?.querySelector<HTMLInputElement>('input')
input?.focus()
input?.select()
})
}
return { handleScoreGridKeydown }
}