fix(schedules): support editable schedule notes
This commit is contained in:
@@ -947,6 +947,19 @@ const SchedulesPage: React.FC = () => {
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="notes"
|
||||
label="备注"
|
||||
rules={[{ max: 500, message: '备注不能超过500字' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={3}
|
||||
maxLength={500}
|
||||
showCount
|
||||
placeholder="可填写排课说明、设备需求或临时调整原因"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="timeRange"
|
||||
label="上课时段"
|
||||
|
||||
@@ -15,10 +15,12 @@ describe('schedule edit form mapping', () => {
|
||||
endTime: '18:00',
|
||||
startDate: '2026-07-01',
|
||||
endDate: '2026-07-31',
|
||||
notes: '需要投影设备',
|
||||
});
|
||||
|
||||
expect(values.classroomId).toBe(1);
|
||||
expect(values.weekDay).toBe(5);
|
||||
expect(values.notes).toBe('需要投影设备');
|
||||
expect(values.timeRange.map((item) => item.format('HH:mm'))).toEqual(['14:00', '18:00']);
|
||||
expect(values.dateRange.map((item) => item.format('YYYY-MM-DD'))).toEqual([
|
||||
'2026-07-01',
|
||||
@@ -36,6 +38,7 @@ describe('schedule edit form mapping', () => {
|
||||
teacherId: 4,
|
||||
timeRange: [dayjs('2026-01-01 13:30'), dayjs('2026-01-01 17:20')],
|
||||
dateRange: [dayjs('2026-08-01'), dayjs('2026-08-31')],
|
||||
notes: ' 临时调整教室 ',
|
||||
}),
|
||||
).toEqual({
|
||||
classId: 1,
|
||||
@@ -47,6 +50,24 @@ describe('schedule edit form mapping', () => {
|
||||
endTime: '17:20',
|
||||
startDate: '2026-08-01',
|
||||
endDate: '2026-08-31',
|
||||
notes: '临时调整教室',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('schedule notes normalization', () => {
|
||||
it('omits whitespace-only notes from the payload', () => {
|
||||
expect(
|
||||
buildSchedulePayload({
|
||||
classId: 1,
|
||||
classroomId: 2,
|
||||
weekDay: 6,
|
||||
subject: '作文',
|
||||
timeRange: [dayjs('2026-01-01 13:30'), dayjs('2026-01-01 17:20')],
|
||||
dateRange: [dayjs('2026-08-01'), dayjs('2026-08-31')],
|
||||
notes: ' ',
|
||||
}).notes,
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface ScheduleFormValues {
|
||||
weekDay: number;
|
||||
subject: string;
|
||||
teacherId?: number;
|
||||
notes?: string;
|
||||
timeRange: [Dayjs, Dayjs];
|
||||
dateRange: [Dayjs, Dayjs];
|
||||
}
|
||||
@@ -17,6 +18,7 @@ export interface EditableSchedule {
|
||||
weekDay: number;
|
||||
subject: string;
|
||||
teacherId: number | null;
|
||||
notes?: string | null;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
startDate: string;
|
||||
@@ -29,6 +31,7 @@ export const scheduleToFormValues = (schedule: EditableSchedule): ScheduleFormVa
|
||||
weekDay: schedule.weekDay,
|
||||
subject: schedule.subject,
|
||||
teacherId: schedule.teacherId ?? undefined,
|
||||
notes: schedule.notes ?? undefined,
|
||||
timeRange: [dayjs(`2000-01-01 ${schedule.startTime}`), dayjs(`2000-01-01 ${schedule.endTime}`)],
|
||||
dateRange: [dayjs(schedule.startDate), dayjs(schedule.endDate)],
|
||||
});
|
||||
@@ -39,6 +42,7 @@ export const buildSchedulePayload = (values: ScheduleFormValues) => ({
|
||||
weekDay: values.weekDay,
|
||||
subject: values.subject,
|
||||
teacherId: values.teacherId,
|
||||
notes: values.notes?.trim() || undefined,
|
||||
startTime: values.timeRange[0].format('HH:mm'),
|
||||
endTime: values.timeRange[1].format('HH:mm'),
|
||||
startDate: values.dateRange[0].format('YYYY-MM-DD'),
|
||||
|
||||
29
apps/server/src/schedules/dto/schedule.dto.spec.ts
Normal file
29
apps/server/src/schedules/dto/schedule.dto.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'reflect-metadata';
|
||||
import { validate } from 'class-validator';
|
||||
import { CreateScheduleDto, UpdateScheduleDto } from './schedule.dto';
|
||||
|
||||
const createSchedule = (notes: string) =>
|
||||
Object.assign(new CreateScheduleDto(), {
|
||||
classId: 1,
|
||||
classroomId: 2,
|
||||
weekDay: 1,
|
||||
startTime: '09:00',
|
||||
endTime: '10:00',
|
||||
startDate: '2026-07-01',
|
||||
endDate: '2026-07-31',
|
||||
subject: '语文',
|
||||
notes,
|
||||
});
|
||||
|
||||
describe('schedule notes validation', () => {
|
||||
it('rejects notes longer than 500 characters when creating', async () => {
|
||||
const errors = await validate(createSchedule('a'.repeat(501)));
|
||||
expect(errors.some((error) => error.property === 'notes')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects notes longer than 500 characters when updating', async () => {
|
||||
const dto = Object.assign(new UpdateScheduleDto(), { notes: 'a'.repeat(501) });
|
||||
const errors = await validate(dto);
|
||||
expect(errors.some((error) => error.property === 'notes')).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Matches,
|
||||
Min,
|
||||
Max,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
@@ -59,6 +60,7 @@ export class CreateScheduleDto {
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(500)
|
||||
notes?: string;
|
||||
|
||||
@IsOptional()
|
||||
@@ -115,6 +117,7 @@ export class UpdateScheduleDto {
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(500)
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user