|
@@ -105,3 +105,54 @@ test('写作报表的词汇掌握率不适用,普通单词报表仍计算掌
|
|
|
assert.equal(word.masteryRate, 100);
|
|
assert.equal(word.masteryRate, 100);
|
|
|
assert.equal(word.canExport, true);
|
|
assert.equal(word.canExport, true);
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+test('单词学习报表统一课型格式,优先显示保存时长并兼容旧课型', () => {
|
|
|
|
|
+ for(const minutes of [30,60]){
|
|
|
|
|
+ const report=gateway.learningReportProjection({classType:'2',courseId:203,durationMinutes:minutes,courseCategoryKey:'word',courseCategoryName:'单词课'});
|
|
|
|
|
+ assert.equal(report.classTypeLabel,'单词课 '+minutes+' 分钟');
|
|
|
|
|
+ }
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({legacyLesson:{classType:'1',courseId:'203'}}).classTypeLabel,'单词课 30 分钟');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({legacyLesson:{classType:'2',courseId:'161'}}).classTypeLabel,'单词课 60 分钟');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({classType:'1',courseId:203}).classTypeLabel,'单词课 30 分钟');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({classType:'2',courseId:203}).classTypeLabel,'单词课 60 分钟');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({classType:'2',courseId:398,isWriting:true}).classTypeLabel,'60 分钟');
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+test('批量读取已保存时长和旧课型时同时匹配帐套、预约与学员', async () => {
|
|
|
|
|
+ await db.exec(`
|
|
|
|
|
+ CREATE TABLE "LessonCompletionReport"(company text,"appointmentGeneralId" numeric,"studentId" numeric,"durationMinutes" numeric,"submittedAt" timestamptz,"objectId" text);
|
|
|
|
|
+ CREATE TABLE "LessonRecord"(company text,yyds text,xymz text,kclx text,kcid text,"updatedAt" timestamptz,"objectId" text);
|
|
|
|
|
+ INSERT INTO "LessonCompletionReport" VALUES
|
|
|
|
|
+ ('co',201,59,30,'2026-11-01','saved'),
|
|
|
|
|
+ ('other',201,59,60,'2026-11-02','other-company'),
|
|
|
|
|
+ ('co',201,60,60,'2026-11-02','other-student');
|
|
|
|
|
+ INSERT INTO "LessonRecord" VALUES
|
|
|
|
|
+ ('co','202','59','1','203','2026-11-01','legacy'),
|
|
|
|
|
+ ('other','202','59','2','203','2026-11-02','other-company'),
|
|
|
|
|
+ ('co','202','60','2','203','2026-11-02','other-student');
|
|
|
|
|
+ `);
|
|
|
|
|
+ gateway.Psql = { query: async (sql, values) => (await db.query(sql, values)).rows };
|
|
|
|
|
+ const enriched = await gateway.learningReportClassTypeRows([
|
|
|
|
|
+ { recordCompany: 'co', dsid: '201', userId: 59, appointmentObjectId: 'a', classType: '2', courseId: 203, durationMinutes: 60 },
|
|
|
|
|
+ { recordCompany: 'co', dsid: '202', userId: 59 },
|
|
|
|
|
+ ]);
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection(enriched[0]).classTypeLabel, '单词课 30 分钟');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection(enriched[1]).classTypeLabel, '单词课 30 分钟');
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+test('报表先定位课次时仍兼容报表对象、通用编号和原学习记录编号', async () => {
|
|
|
|
|
+ await db.exec(`
|
|
|
|
|
+ INSERT INTO "CommonModel" VALUES ('study-target','co',56,21,3021,NULL,NULL),('foreign-target','other',56,21,4021,NULL,NULL);
|
|
|
|
|
+ INSERT INTO "DailyStudyRecord" ("objectId",company,id) VALUES ('foreign-target-record','other',21);
|
|
|
|
|
+ `);
|
|
|
|
|
+ let lookup = '';
|
|
|
|
|
+ gateway.Psql = { query: async sql => { lookup = sql; return []; } };
|
|
|
|
|
+ await assert.rejects(gateway.learningReportDetail({ isSuperAdmin: true }, { targetId: 'study-target' }), /学习报表不存在/);
|
|
|
|
|
+ const end = lookup.indexOf(' SELECT c."objectId" AS "targetId"');
|
|
|
|
|
+ assert.ok(end > 0);
|
|
|
|
|
+ const targetSql = lookup.slice(0, end) + ' SELECT * FROM target_records';
|
|
|
|
|
+ for (const target of ['study-target', '3021', 'writing-report']) {
|
|
|
|
|
+ assert.deepEqual((await db.query(targetSql, ['co', target])).rows.map(row => row.objectId), ['writing-report']);
|
|
|
|
|
+ }
|
|
|
|
|
+ assert.deepEqual((await db.query(targetSql, ['co', 'foreign-target'])).rows, []);
|
|
|
|
|
+});
|