fix(attendance): 默认周范围改为中国日期周一起点
generateFromSchedules / getCalendar 原来用本地周一零点转 UTC 日期, 在上海时区会得到前一天的日期,导致默认范围变成周日~周日(8 天)。 改为 dayjs().utcOffset(8) 按中国日期计算,与 getTodayDateOnly 语义一致。 新增测试锁定:默认周 = 本周一~本周日,周日晚上仍归本周,显式传参原样透传。
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
import { AttendanceCalendarService } from './attendance-calendar.service';
|
||||||
|
|
||||||
|
describe('AttendanceCalendarService — 默认周起点', () => {
|
||||||
|
function createService() {
|
||||||
|
return new AttendanceCalendarService({} as never, {} as never);
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => jest.useRealTimers());
|
||||||
|
|
||||||
|
it('未传 weekStart 时默认本周一(中国日期)', async () => {
|
||||||
|
jest.useFakeTimers().setSystemTime(new Date('2026-08-05T10:00:00+08:00')); // 周三
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'buildCalendar' as never)
|
||||||
|
.mockResolvedValue([] as never);
|
||||||
|
|
||||||
|
await service.getCalendar({ classId: 1 } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith(1, '2026-08-03');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('周日晚间仍归入本周一', async () => {
|
||||||
|
jest.useFakeTimers().setSystemTime(new Date('2026-08-09T22:00:00+08:00')); // 周日晚上
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'buildCalendar' as never)
|
||||||
|
.mockResolvedValue([] as never);
|
||||||
|
|
||||||
|
await service.getCalendar({ classId: 1 } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith(1, '2026-08-03');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('传入 weekStart 时原样透传', async () => {
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'buildCalendar' as never)
|
||||||
|
.mockResolvedValue([] as never);
|
||||||
|
|
||||||
|
await service.getCalendar({ classId: 1, weekStart: '2026-08-10' } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith(1, '2026-08-10');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -18,13 +18,11 @@ export class AttendanceCalendarService {
|
|||||||
const { classId, weekStart } = query;
|
const { classId, weekStart } = query;
|
||||||
|
|
||||||
if (!weekStart) {
|
if (!weekStart) {
|
||||||
// Default to the Monday of the current week
|
// Default to the Monday of the current week (China calendar)
|
||||||
const now = new Date();
|
const now = dayjs().utcOffset(8);
|
||||||
const day = now.getDay();
|
const day = now.day();
|
||||||
const diff = day === 0 ? -6 : 1 - day; // Monday offset
|
const monday = now.subtract(day === 0 ? 6 : day - 1, 'day');
|
||||||
const monday = new Date(now);
|
const mondayStr = monday.format('YYYY-MM-DD');
|
||||||
monday.setDate(now.getDate() + diff);
|
|
||||||
const mondayStr = dayjs(monday).utc().format('YYYY-MM-DD');
|
|
||||||
|
|
||||||
return this.buildCalendar(classId, mondayStr);
|
return this.buildCalendar(classId, mondayStr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { AttendanceGenerationService } from './attendance-generation.service';
|
||||||
|
|
||||||
|
describe('AttendanceGenerationService — 默认周范围', () => {
|
||||||
|
function createService() {
|
||||||
|
return new AttendanceGenerationService(
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
{} as never,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => jest.useRealTimers());
|
||||||
|
|
||||||
|
it('未传 startDate/endDate 时默认生成本周一~本周日(中国日期)', async () => {
|
||||||
|
jest.useFakeTimers().setSystemTime(new Date('2026-08-05T10:00:00+08:00')); // 周三
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'generateAttendanceFromSchedules' as never)
|
||||||
|
.mockResolvedValue({ count: 0, records: [] } as never);
|
||||||
|
|
||||||
|
await service.generateFromSchedules({ classId: 1 } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith({
|
||||||
|
classId: 1,
|
||||||
|
dateFrom: '2026-08-03',
|
||||||
|
dateTo: '2026-08-09',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('周日晚间仍归入本周(周一起点)', async () => {
|
||||||
|
jest.useFakeTimers().setSystemTime(new Date('2026-08-09T22:00:00+08:00')); // 周日晚上
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'generateAttendanceFromSchedules' as never)
|
||||||
|
.mockResolvedValue({ count: 0, records: [] } as never);
|
||||||
|
|
||||||
|
await service.generateFromSchedules({ classId: 1 } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith({
|
||||||
|
classId: 1,
|
||||||
|
dateFrom: '2026-08-03',
|
||||||
|
dateTo: '2026-08-09',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('传入 startDate/endDate 时原样透传', async () => {
|
||||||
|
jest.useFakeTimers().setSystemTime(new Date('2026-08-05T10:00:00+08:00'));
|
||||||
|
const service = createService();
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(service as never, 'generateAttendanceFromSchedules' as never)
|
||||||
|
.mockResolvedValue({ count: 0, records: [] } as never);
|
||||||
|
|
||||||
|
await service.generateFromSchedules({ classId: 1, startDate: '2026-08-01', endDate: '2026-08-31' } as never);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledWith({
|
||||||
|
classId: 1,
|
||||||
|
dateFrom: '2026-08-01',
|
||||||
|
dateTo: '2026-08-31',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -136,19 +136,14 @@ export class AttendanceGenerationService {
|
|||||||
): Promise<{ count: number; records: AttendanceRecord[] }> {
|
): Promise<{ count: number; records: AttendanceRecord[] }> {
|
||||||
const { classId, startDate, endDate } = dto;
|
const { classId, startDate, endDate } = dto;
|
||||||
|
|
||||||
// Default to current week (Monday–Sunday)
|
// Default to current week (Monday–Sunday), China calendar
|
||||||
const now = new Date();
|
const now = dayjs().utcOffset(8);
|
||||||
const dayOfWeek = now.getDay();
|
const day = now.day();
|
||||||
const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
|
const monday = now.subtract(day === 0 ? 6 : day - 1, 'day').startOf('day');
|
||||||
const monday = new Date(now);
|
const sunday = monday.add(6, 'day').endOf('day');
|
||||||
monday.setDate(now.getDate() + mondayOffset);
|
|
||||||
monday.setHours(0, 0, 0, 0);
|
|
||||||
const sunday = new Date(monday);
|
|
||||||
sunday.setDate(monday.getDate() + 6);
|
|
||||||
sunday.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
const dateFrom = startDate ?? dayjs(monday).utc().format('YYYY-MM-DD');
|
const dateFrom = startDate ?? monday.format('YYYY-MM-DD');
|
||||||
const dateTo = endDate ?? dayjs(sunday).utc().format('YYYY-MM-DD');
|
const dateTo = endDate ?? sunday.format('YYYY-MM-DD');
|
||||||
|
|
||||||
return this.generateAttendanceFromSchedules({
|
return this.generateAttendanceFromSchedules({
|
||||||
classId,
|
classId,
|
||||||
|
|||||||
Reference in New Issue
Block a user