feat: 支持评分字段的导入

This commit is contained in:
richarjiang
2026-06-07 09:50:03 +08:00
parent e0b88e68e9
commit 588b6fbc77
8 changed files with 193 additions and 24 deletions

View File

@@ -44,6 +44,9 @@ interface ParsedItem {
hint1: string
hint2: string
hint3: string
// 评分1-5可空
difficultyScore: number | null
funScore: number | null
// 解析警告/错误信息
parseError?: string
// 上传/创建过程状态
@@ -76,6 +79,18 @@ interface RiddleConfigItem {
anchor_text?: string
reference_image?: string
riddle_image?: string
// JSON 里通常是字符串,容忍数字
difficulty_score?: string | number
fun_score?: string | number
}
/**
* 解析评分字段,失败/缺失静默置 null,导入流程不因此阻塞。
*/
function parseScoreField(raw: string | number | undefined): number | null {
if (raw === undefined || raw === null || raw === '') return null
const n = typeof raw === 'number' ? raw : Number(raw)
return Number.isInteger(n) && n >= 1 && n <= 5 ? n : null
}
function truncate(s: string | undefined, max: number): string {
@@ -181,6 +196,8 @@ async function parseConfigJson(
hint1: (hints[0] || '').trim(),
hint2: (hints[1] || '').trim(),
hint3: (hints[2] || '').trim(),
difficultyScore: parseScoreField(config.difficulty_score),
funScore: parseScoreField(config.fun_score),
status: 'pending',
}
@@ -250,6 +267,8 @@ async function parseFolders(files: FileList): Promise<ParsedItem[]> {
hint1: '',
hint2: '',
hint3: '',
difficultyScore: null,
funScore: null,
status: 'pending',
}
@@ -412,6 +431,11 @@ export function BatchImportDialog({
hint1: it.hint1 || '',
hint2: it.hint2 || '',
hint3: it.hint3 || '',
difficultyScore: it.difficultyScore,
funScore: it.funScore,
// 故意不传 position / sortKey。
// 命中存量关卡时POST /api/levels 的 riddleId-update 分支会忽略
// 这两个字段以保护用户手动维护的关卡顺序。
}
const res = await apiFetch('/api/levels', {
@@ -695,6 +719,45 @@ function ItemCard({ index, item, disabled, onChange, onRemove }: ItemCardProps)
/>
</div>
</div>
<div className="col-span-2 grid grid-cols-2 gap-2">
<div className="space-y-1">
<Label className="text-xs"> (1-5)</Label>
<Input
type="number"
min={1}
max={5}
step={1}
value={item.difficultyScore ?? ''}
onChange={(e) =>
onChange({
difficultyScore:
e.target.value === '' ? null : Number(e.target.value),
})
}
disabled={disabled}
placeholder="可选"
/>
</div>
<div className="space-y-1">
<Label className="text-xs"> (1-5)</Label>
<Input
type="number"
min={1}
max={5}
step={1}
value={item.funScore ?? ''}
onChange={(e) =>
onChange({
funScore:
e.target.value === '' ? null : Number(e.target.value),
})
}
disabled={disabled}
placeholder="可选"
/>
</div>
</div>
</div>
</div>
</div>