fix(server,admin): 成绩/班级均分/排名超列宽写入 MySQL 报 500

score/class_avg 为 decimal(5,2)(上限 999.99)、rank 为 int,越界值直写库抛
ER_WARN_DATA_OUT_OF_RANGE。DTO 加 @Max 与列宽对齐返回 400 清晰报错,
前端单元格与表单 InputNumber 同步加 max 阻止输入
This commit is contained in:
2026-08-11 15:18:30 +08:00
parent 0a685c8ea6
commit 01ca0c6f4b
2 changed files with 11 additions and 9 deletions

View File

@@ -125,7 +125,7 @@ export const ExamScoresTab: React.FC<
title: '成绩',
dataIndex: 'score',
render: (v: number | null, r) => (
<EditableArchiveCell value={v ?? undefined} field={EXAM_SCORE_FIELDS.score} record={r} editor="number" min={0} onSave={saveCell}>
<EditableArchiveCell value={v ?? undefined} field={EXAM_SCORE_FIELDS.score} record={r} editor="number" min={0} max={999.99} onSave={saveCell}>
{v ?? '-'}
</EditableArchiveCell>
),
@@ -134,7 +134,7 @@ export const ExamScoresTab: React.FC<
title: '班级均分',
dataIndex: 'classAvg',
render: (v: number | undefined, r) => (
<EditableArchiveCell value={v} field={EXAM_SCORE_FIELDS.classAvg} record={r} editor="number" min={0} onSave={saveCell}>
<EditableArchiveCell value={v} field={EXAM_SCORE_FIELDS.classAvg} record={r} editor="number" min={0} max={999.99} onSave={saveCell}>
{v !== undefined ? v : '-'}
</EditableArchiveCell>
),
@@ -143,7 +143,7 @@ export const ExamScoresTab: React.FC<
title: '排名',
dataIndex: 'rank',
render: (v: number | undefined, r) => (
<EditableArchiveCell value={v} field={EXAM_SCORE_FIELDS.rank} record={r} editor="number" min={1} onSave={saveCell}>
<EditableArchiveCell value={v} field={EXAM_SCORE_FIELDS.rank} record={r} editor="number" min={1} max={2147483647} onSave={saveCell}>
{v !== undefined ? v : '-'}
</EditableArchiveCell>
),
@@ -247,13 +247,13 @@ export const ExamScoresTab: React.FC<
<AutoComplete options={SUBJECT_OPTIONS} placeholder="输入或选择科目" />
</Form.Item>
<Form.Item name="score" label="成绩" rules={[{ required: true, message: '请输入成绩' }]}>
<InputNumber min={0} style={{ width: '100%' }} />
<InputNumber min={0} max={999.99} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="classAvg" label="班级均分">
<InputNumber min={0} style={{ width: '100%' }} />
<InputNumber min={0} max={999.99} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="rank" label="排名">
<InputNumber min={1} style={{ width: '100%' }} />
<InputNumber min={1} max={2147483647} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="examDate" label="考试日期">
<DatePicker style={{ width: '100%' }} />

View File

@@ -6,6 +6,7 @@ import {
IsDateString,
IsNotEmpty,
Min,
Max,
IsInt,
} from 'class-validator';
@@ -38,9 +39,10 @@ export class CreateExamScoreDto {
@IsString() @IsNotEmpty() examType: string;
@IsOptional() @IsString() examName?: string;
@IsString() @IsNotEmpty() subject: string;
@IsNumber() @Min(0) score: number;
@IsOptional() @IsNumber() @Min(0) classAvg?: number;
@IsOptional() @IsNumber() @Min(1) rank?: number;
// 列类型 decimal(5,2)/int上限与列宽对齐避免超范围写入 MySQL 报 500
@IsNumber() @Min(0) @Max(999.99) score: number;
@IsOptional() @IsNumber() @Min(0) @Max(999.99) classAvg?: number;
@IsOptional() @IsNumber() @Min(1) @Max(2147483647) rank?: number;
@IsOptional() @IsDateString() examDate?: string;
@IsOptional() @IsNumber() enrollmentId?: number;
}