|
@@ -0,0 +1,48 @@
|
|
|
|
|
+import { after, before, test } from 'node:test';
|
|
|
|
|
+import assert from 'node:assert/strict';
|
|
|
|
|
+import { readFileSync } from 'node:fs';
|
|
|
|
|
+import vm from 'node:vm';
|
|
|
|
|
+import { PGlite } from '@electric-sql/pglite';
|
|
|
|
|
+
|
|
|
|
|
+const db = new PGlite();
|
|
|
|
|
+const source = readFileSync(new URL('../deploy-admin-functions.mjs', import.meta.url), 'utf8');
|
|
|
|
|
+const gateway = {};
|
|
|
|
|
+vm.createContext(gateway);
|
|
|
|
|
+vm.runInContext(source.match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1], gateway);
|
|
|
|
|
+gateway.companyIdOf = () => 'co';
|
|
|
|
|
+before(async () => {
|
|
|
|
|
+ await db.exec(`
|
|
|
|
|
+ CREATE TABLE "DailyStudyRecord"("objectId" text,"company" text,"id" int,"userId" int,"pl" text,"dsid" text,"dqrq" text,"xxqs" text,"createdAt" timestamptz);
|
|
|
|
|
+ CREATE TABLE "CommonModel"("objectId" text,"company" text,"modelId" int,"itemId" int,"generalId" int,"createTime" timestamptz,"createdAt" timestamptz);
|
|
|
|
|
+ CREATE TABLE "_User"("objectId" text,"company" text,"legacyUserId" int,"legacyUserData" jsonb,"realName" text,"nickname" text,"username" text,"mobile" text);
|
|
|
|
|
+ CREATE TABLE "CourseAppointment"("objectId" text,"company" text,"id" int,"kcid" text,"dszt" text);
|
|
|
|
|
+ CREATE TABLE "Node"("company" text,"nodeId" int,"nodeName" text);
|
|
|
|
|
+ INSERT INTO "DailyStudyRecord" VALUES
|
|
|
|
|
+ ('compact','co',1,20,'30','','20261004','[]','2026-10-04T00:00:00Z'),
|
|
|
|
|
+ ('dashed','co',2,20,'30','','2026-10-04','[]','2026-10-04T00:00:00Z'),
|
|
|
|
|
+ ('slash','co',3,20,'30','','2026/10/03','[]','2026-10-03T00:00:00Z'),
|
|
|
|
|
+ ('fallback','co',4,20,'30','',NULL,'[]','2026-09-30T16:01:00Z'),
|
|
|
|
|
+ ('history','co',5,20,'30','','20260930','[]','2026-09-30T00:00:00Z'),
|
|
|
|
|
+ ('foreign','other',6,20,'30','','20261004','[]','2026-10-04T00:00:00Z');
|
|
|
|
|
+ `);
|
|
|
|
|
+});
|
|
|
|
|
+after(() => db.close());
|
|
|
|
|
+async function rows(filters) {
|
|
|
|
|
+ const query = gateway.learningReportQueryParts({}, { page: 1, pageSize: 20, filters });
|
|
|
|
|
+ return (await db.query('SELECT d."objectId"' + query.from + query.where + ' ORDER BY ' + query.studyDateSql + ' DESC,d."objectId"', query.values)).rows.map(row => row.objectId);
|
|
|
|
|
+}
|
|
|
|
|
+test('月份筛选兼容三种日期格式,并按北京时间补齐缺失学习日期', async () => {
|
|
|
|
|
+ assert.deepEqual(await rows({ month: '2026-10' }), ['compact','dashed','slash','fallback']);
|
|
|
|
|
+});
|
|
|
|
|
+test('全部月份包含历史记录,保持帐套隔离', async () => {
|
|
|
|
|
+ assert.deepEqual(await rows({ month: '' }), ['compact','dashed','slash','fallback','history']);
|
|
|
|
|
+});
|
|
|
|
|
+test('日期范围包含首尾当天,兼容不同保存格式', async () => {
|
|
|
|
|
+ assert.deepEqual(await rows({ dateFrom: '2026-10-03', dateTo: '2026-10-04' }), ['compact','dashed','slash']);
|
|
|
|
|
+ assert.deepEqual(await rows({ month: '2026-09' }), ['history']);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+test('报表展示与筛选使用同一个学习日期,斜线日期与 UTC 时间不会少一天', () => {
|
|
|
|
|
+ for(const raw of ['20261004','2026-10-04','2026/10/04'])assert.equal(gateway.learningReportProjection({dqrq:raw}).studyDate,'2026-10-04');
|
|
|
|
|
+ assert.equal(gateway.learningReportProjection({recordCreatedAt:'2026-09-30T16:01:00Z'}).studyDate,'2026-10-01');
|
|
|
|
|
+});
|