forked from wangziqi/gongxue-base
feat: add student followup report
This commit is contained in:
@@ -9341,6 +9341,21 @@ async function testTenantStudentOperations() {
|
||||
assert.equal(completedFollowup.item?.status, 'done', 'teacher should complete scoped follow-up');
|
||||
assert.equal(completedFollowup.item?.completedBy, TENANT_TEACHER_USER_ID, 'completed follow-up should record completer');
|
||||
|
||||
const teacherFollowupReport = await request('/api/tenant-admin/students/followups/report', {
|
||||
userId: TENANT_TEACHER_USER_ID,
|
||||
query: { timeRange: '30d', limit: 10 },
|
||||
});
|
||||
assert.equal(teacherFollowupReport.item?.filters?.scoped, true, 'teacher follow-up report should be class scoped');
|
||||
assert.equal(teacherFollowupReport.item?.summary?.total >= 1, true, 'teacher follow-up report should include scoped follow-up');
|
||||
assert.ok(
|
||||
teacherFollowupReport.item?.byAssignee?.some(item => item.assignedToUserId === TENANT_TEACHER_USER_ID),
|
||||
'teacher follow-up report should include scoped assignee summary',
|
||||
);
|
||||
assert.ok(
|
||||
!teacherFollowupReport.item?.overdueItems?.some(item => item.studentUserId === SECOND_STUDENT_USER_ID),
|
||||
'teacher follow-up report must not expose unscoped students',
|
||||
);
|
||||
|
||||
const teacherOtherFollowupDenied = await request('/api/tenant-admin/students/followups', {
|
||||
userId: TENANT_TEACHER_USER_ID,
|
||||
method: 'PUT',
|
||||
@@ -9354,6 +9369,20 @@ async function testTenantStudentOperations() {
|
||||
});
|
||||
assert.equal(teacherOtherFollowupDenied.code, 'STUDENT_SCOPE_REQUIRED', 'teacher should not create follow-up for unscoped student');
|
||||
|
||||
const invalidFollowupReportRange = await request('/api/tenant-admin/students/followups/report', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { timeRange: '365d' },
|
||||
expectStatus: 400,
|
||||
});
|
||||
assert.equal(invalidFollowupReportRange.code, 'INVALID_FOLLOWUP_REPORT_RANGE', 'follow-up report should validate time range');
|
||||
|
||||
const invalidFollowupReportDate = await request('/api/tenant-admin/students/followups/report', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { startDate: '2026-02-31', endDate: '2026-03-01' },
|
||||
expectStatus: 400,
|
||||
});
|
||||
assert.equal(invalidFollowupReportDate.code, 'INVALID_DATE_RANGE', 'follow-up report should reject impossible calendar dates');
|
||||
|
||||
const studentStatusDenied = await request('/api/tenant-admin/students/status', {
|
||||
userId: TENANT_TEACHER_USER_ID,
|
||||
method: 'POST',
|
||||
@@ -9525,6 +9554,35 @@ async function testReferralAndCrmGrowth() {
|
||||
'student CRM class scoped push should reject students outside the selected class',
|
||||
);
|
||||
|
||||
const followupReport = await request('/api/tenant-admin/students/followups/report', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { timeRange: '30d', limit: 10 },
|
||||
});
|
||||
assert.equal(followupReport.item?.summary?.crmPushTasks >= 2, true, 'follow-up report should count CRM push tasks');
|
||||
assert.equal(followupReport.item?.crmQueue?.total >= 2, true, 'follow-up report should include student CRM queue totals');
|
||||
assert.ok(
|
||||
followupReport.item?.byAssignee?.some(item => item.assignedToUserId === TENANT_SALES_USER_ID && Number(item.crmPushTasks || 0) >= 2),
|
||||
'follow-up report should group CRM push tasks by assignee',
|
||||
);
|
||||
assert.ok(
|
||||
followupReport.item?.dailyTrend?.some(item => Number(item.crmPushCreated || 0) >= 1),
|
||||
'follow-up report should include CRM push daily trend',
|
||||
);
|
||||
|
||||
const classFollowupReport = await request('/api/tenant-admin/students/followups/report', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { timeRange: '30d', classId: ids.tenantClass, limit: 10 },
|
||||
});
|
||||
assert.equal(
|
||||
classFollowupReport.item?.summary?.crmPushTasks >= 1,
|
||||
true,
|
||||
'class-scoped follow-up report should include in-class CRM push tasks',
|
||||
);
|
||||
assert.ok(
|
||||
!classFollowupReport.item?.overdueItems?.some(item => item.studentUserId === SECOND_STUDENT_USER_ID),
|
||||
'class-scoped follow-up report should not expose another class student overdue items',
|
||||
);
|
||||
|
||||
const operatorCrmPushDenied = await request('/api/tenant-admin/students/crm-push', {
|
||||
userId: TENANT_OPERATOR_USER_ID,
|
||||
method: 'POST',
|
||||
|
||||
Reference in New Issue
Block a user