系统完善

This commit is contained in:
zhonghua 2026-02-28 01:48:21 +08:00
parent 54f6daea62
commit 39b49bd808
254 changed files with 36 additions and 25096 deletions

33
.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
pnpm-lock.yaml
*/node_modules
*/dist/*
dist.zip
dist-ssr
*.local
package-lock.json
*/package-lock.json
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
/auto-imports.d.ts
/components.d.ts
/typed-router.d.ts
/locale.d.ts
stats.html

View File

@ -1,4 +1,4 @@
DATABASE_URL="file:/Users/retirado/ccProgram/reading-platform-backend/dev.db" DATABASE_URL="file:./dev.db"
NODE_ENV=development NODE_ENV=development
PORT=3000 PORT=3000
JWT_SECRET="your-super-secret-jwt-key" JWT_SECRET="your-super-secret-jwt-key"

Binary file not shown.

View File

@ -1 +0,0 @@
export {};

View File

@ -1,420 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const client_1 = require("@prisma/client");
const bcrypt = __importStar(require("bcrypt"));
const prisma = new client_1.PrismaClient();
async function main() {
console.log('开始种子数据...');
const tenant = await prisma.tenant.upsert({
where: { id: 1 },
update: {},
create: {
name: '阳光幼儿园',
address: '北京市朝阳区xxx街道',
contactPerson: '张园长',
contactPhone: '13800138000',
packageType: 'STANDARD',
teacherQuota: 20,
studentQuota: 200,
storageQuota: BigInt(5368709120),
startDate: '2024-01-01',
expireDate: '2025-12-31',
status: 'ACTIVE',
},
});
console.log('创建租户:', tenant.name);
const passwordHash = await bcrypt.hash('123456', 10);
const teacher = await prisma.teacher.upsert({
where: { loginAccount: 'teacher1' },
update: {},
create: {
tenantId: tenant.id,
name: '李老师',
phone: '13900139000',
email: 'teacher1@example.com',
loginAccount: 'teacher1',
passwordHash: passwordHash,
status: 'ACTIVE',
},
});
console.log('创建教师:', teacher.name);
const class1 = await prisma.class.upsert({
where: { id: 1 },
update: {},
create: {
tenantId: tenant.id,
name: '中一班',
grade: 'MIDDLE',
teacherId: teacher.id,
studentCount: 25,
},
});
console.log('创建班级:', class1.name);
const class2 = await prisma.class.upsert({
where: { id: 2 },
update: {},
create: {
tenantId: tenant.id,
name: '大一班',
grade: 'BIG',
teacherId: teacher.id,
studentCount: 30,
},
});
console.log('创建班级:', class2.name);
await prisma.teacher.update({
where: { id: teacher.id },
data: {
classIds: JSON.stringify([class1.id, class2.id]),
},
});
const students = [
{ name: '小明', gender: 'MALE', classId: class1.id },
{ name: '小红', gender: 'FEMALE', classId: class1.id },
{ name: '小华', gender: 'MALE', classId: class1.id },
{ name: '小丽', gender: 'FEMALE', classId: class2.id },
{ name: '小强', gender: 'MALE', classId: class2.id },
];
for (const studentData of students) {
await prisma.student.upsert({
where: {
id: students.indexOf(studentData) + 1,
},
update: {},
create: {
tenantId: tenant.id,
classId: studentData.classId,
name: studentData.name,
gender: studentData.gender,
},
});
}
console.log('创建学生:', students.length, '名');
const course = await prisma.course.upsert({
where: { id: 1 },
update: {},
create: {
name: '好饿的毛毛虫',
description: '这是一本经典的绘本,讲述了一只毛毛虫从孵化到变成蝴蝶的故事。通过这个故事,孩子们可以学习到星期的概念、数字的认知,以及毛毛虫变蝴蝶的科学知识。',
pictureBookName: '好饿的毛毛虫',
gradeTags: JSON.stringify(['SMALL', 'MIDDLE']),
domainTags: JSON.stringify(['LANGUAGE', 'SCIENCE', 'MATH']),
duration: 30,
status: 'PUBLISHED',
version: '1.0',
coverImagePath: '/uploads/covers/caterpillar.jpg',
},
});
console.log('创建课程:', course.name);
const scripts = [
{
stepIndex: 1,
stepName: '阅读导入',
stepType: 'INTRODUCTION',
duration: 5,
objective: '激发幼儿阅读兴趣,建立阅读期待',
teacherScript: '小朋友们,今天我们要认识一位新朋友——一只小小的毛毛虫。你们见过毛毛虫吗?它长什么样子呢?让我们一起来看看这只特别的毛毛虫的故事吧!',
interactionPoints: JSON.stringify([
'展示毛毛虫图片或玩偶',
'引导幼儿分享见过的毛毛虫',
'预测故事内容',
]),
},
{
stepIndex: 2,
stepName: '绘本共读',
stepType: 'READING',
duration: 10,
objective: '理解故事内容,发展语言能力',
teacherScript: '(逐页讲述)从前,有一颗小小的蛋躺在叶子上...月光下,一条又小又饿的毛毛虫从蛋里爬了出来...',
interactionPoints: JSON.stringify([
'提问预测',
'模仿毛毛虫吃东西的动作',
'一起数食物的数量',
]),
},
{
stepIndex: 3,
stepName: '理解讨论',
stepType: 'DISCUSSION',
duration: 5,
objective: '加深对故事的理解,发展思维能力',
teacherScript: '小朋友们,毛毛虫吃了哪些东西呢?为什么最后它肚子痛了?它最后变成了什么?',
interactionPoints: JSON.stringify([
'回顾毛毛虫吃的食物',
'讨论健康饮食的重要性',
'讨论毛毛虫的成长变化',
]),
},
{
stepIndex: 4,
stepName: '互动游戏',
stepType: 'ACTIVITY',
duration: 5,
objective: '通过游戏巩固学习内容',
teacherScript: '现在我们来玩一个游戏,老师说出星期几,小朋友们来模仿毛毛虫吃了什么!',
interactionPoints: JSON.stringify([
'星期与食物配对游戏',
'毛毛虫动作模仿',
'食物分类活动',
]),
},
{
stepIndex: 5,
stepName: '创意表达',
stepType: 'CREATIVE',
duration: 3,
objective: '发展创造力和表达能力',
teacherScript: '如果你是毛毛虫,你想吃什么?画一画你心目中的毛毛虫吧!',
interactionPoints: JSON.stringify([
'自由绘画',
'分享作品',
'创意表达',
]),
},
{
stepIndex: 6,
stepName: '总结延伸',
stepType: 'SUMMARY',
duration: 2,
objective: '总结学习内容,激发延伸探索兴趣',
teacherScript: '今天我们认识了一只可爱的毛毛虫,它从一颗小蛋,变成毛毛虫,最后变成了漂亮的蝴蝶!回家后可以和爸爸妈妈一起找找看,还有哪些动物会变形呢?',
interactionPoints: JSON.stringify([
'总结毛毛虫的成长过程',
'布置家庭延伸任务',
'预告下次活动',
]),
},
];
for (const script of scripts) {
await prisma.courseScript.upsert({
where: {
courseId_stepIndex: {
courseId: course.id,
stepIndex: script.stepIndex,
},
},
update: {},
create: {
courseId: course.id,
...script,
sortOrder: script.stepIndex,
},
});
}
console.log('创建课程脚本:', scripts.length, '个步骤');
const pages = [
{ pageNumber: 1, questions: '你们看到了什么?这是什么颜色的?', teacherNotes: '引导观察封面' },
{ pageNumber: 2, questions: '蛋在哪里?是谁的蛋呢?', teacherNotes: '引入故事悬念' },
{ pageNumber: 3, questions: '毛毛虫从蛋里出来了!它说了什么?', teacherNotes: '模仿毛毛虫的声音' },
{ pageNumber: 4, questions: '星期一,毛毛虫吃了什么?吃了几个?', teacherNotes: '学习星期和数字' },
{ pageNumber: 5, questions: '星期二,它又吃了什么?', teacherNotes: '继续学习星期' },
];
const readingScript = await prisma.courseScript.findFirst({
where: { courseId: course.id, stepType: 'READING' },
});
if (readingScript) {
for (const page of pages) {
await prisma.courseScriptPage.upsert({
where: {
scriptId_pageNumber: {
scriptId: readingScript.id,
pageNumber: page.pageNumber,
},
},
update: {},
create: {
scriptId: readingScript.id,
...page,
},
});
}
console.log('创建逐页配置:', pages.length, '页');
}
const activities = [
{
name: '毛毛虫手偶制作',
domain: 'ART',
activityType: 'HANDICRAFT',
duration: 20,
onlineMaterials: JSON.stringify(['毛毛虫模板PDF', '制作视频']),
offlineMaterials: '彩纸、剪刀、胶水、眼睛贴纸',
activityGuide: '1. 准备材料\n2. 按照模板剪裁\n3. 粘贴组装\n4. 添加装饰',
objectives: JSON.stringify(['锻炼手部精细动作', '培养创造力', '巩固毛毛虫认知']),
sortOrder: 1,
},
{
name: '健康饮食分类',
domain: 'SCIENCE',
activityType: 'GAME',
duration: 15,
onlineMaterials: JSON.stringify(['食物卡片PPT']),
offlineMaterials: '食物图片卡片、分类筐',
activityGuide: '1. 展示各种食物图片\n2. 讨论健康与不健康食物\n3. 进行分类游戏',
objectives: JSON.stringify(['认识健康饮食', '学习分类', '培养健康饮食习惯']),
sortOrder: 2,
},
{
name: '蝴蝶的生命周期',
domain: 'SCIENCE',
activityType: 'EXPLORATION',
duration: 25,
onlineMaterials: JSON.stringify(['蝴蝶生长视频', '生命周期图']),
offlineMaterials: '绘本、放大镜、观察记录本',
activityGuide: '1. 观看蝴蝶生长视频\n2. 讨论四个阶段\n3. 绘制生命周期图',
objectives: JSON.stringify(['了解变态发育', '培养科学探究精神', '学习观察记录']),
sortOrder: 3,
},
];
for (const activity of activities) {
await prisma.courseActivity.upsert({
where: { id: activities.indexOf(activity) + 1 },
update: {},
create: {
courseId: course.id,
...activity,
},
});
}
console.log('创建延伸活动:', activities.length, '个');
const tenantCourse = await prisma.tenantCourse.upsert({
where: {
tenantId_courseId: {
tenantId: tenant.id,
courseId: course.id,
},
},
update: {},
create: {
tenantId: tenant.id,
courseId: course.id,
authorized: true,
authorizedAt: new Date(),
},
});
console.log('授权课程给租户:', tenant.id, '->', course.id);
const course2 = await prisma.course.upsert({
where: { id: 2 },
update: {},
create: {
name: '猜猜我有多爱你',
description: '这是一本关于爱的温暖绘本,小兔子和大兔子用各种方式表达彼此的爱。通过这个故事,孩子们可以学习到表达爱的方式,感受亲情的温暖。',
pictureBookName: '猜猜我有多爱你',
gradeTags: JSON.stringify(['MIDDLE', 'BIG']),
domainTags: JSON.stringify(['LANGUAGE', 'SOCIAL']),
duration: 25,
status: 'PUBLISHED',
version: '1.0',
coverImagePath: '/uploads/covers/love.jpg',
},
});
console.log('创建课程:', course2.name);
const scripts2 = [
{
stepIndex: 1,
stepName: '导入环节',
stepType: 'INTRODUCTION',
duration: 3,
objective: '引入爱的主题',
teacherScript: '小朋友们,你们爱爸爸妈妈吗?你们是怎么表达爱的呢?',
interactionPoints: JSON.stringify(['分享表达爱的方式']),
},
{
stepIndex: 2,
stepName: '绘本共读',
stepType: 'READING',
duration: 10,
objective: '理解故事,感受爱的表达',
teacherScript: '小栗色兔子该上床睡觉了,可是他紧紧地抓住大栗色兔子的长耳朵不放...',
interactionPoints: JSON.stringify(['模仿动作', '感受爱的比较']),
},
{
stepIndex: 3,
stepName: '情感讨论',
stepType: 'DISCUSSION',
duration: 5,
objective: '表达自己的感受',
teacherScript: '小兔子和大兔子谁的爱更多呢?你们觉得呢?',
interactionPoints: JSON.stringify(['讨论爱的深度', '分享感受']),
},
{
stepIndex: 4,
stepName: '爱的表达',
stepType: 'ACTIVITY',
duration: 5,
objective: '学会表达爱',
teacherScript: '让我们也来学学小兔子,用手臂来量量我们有多爱爸爸妈妈!',
interactionPoints: JSON.stringify(['肢体表达', '语言表达']),
},
];
for (const script of scripts2) {
await prisma.courseScript.upsert({
where: {
courseId_stepIndex: {
courseId: course2.id,
stepIndex: script.stepIndex,
},
},
update: {},
create: {
courseId: course2.id,
...script,
sortOrder: script.stepIndex,
},
});
}
await prisma.tenantCourse.upsert({
where: {
tenantId_courseId: {
tenantId: tenant.id,
courseId: course2.id,
},
},
update: {},
create: {
tenantId: tenant.id,
courseId: course2.id,
authorized: true,
authorizedAt: new Date(),
},
});
console.log('授权课程给租户:', tenant.id, '->', course2.id);
console.log('\n种子数据创建完成');
console.log('====================');
console.log('测试账号信息:');
console.log('超管: admin / 123456');
console.log('教师: teacher1 / 123456');
console.log('====================');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
//# sourceMappingURL=seed.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
export declare class AppModule {
}

View File

@ -1,64 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppModule = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const throttler_1 = require("@nestjs/throttler");
const prisma_module_1 = require("./database/prisma.module");
const auth_module_1 = require("./modules/auth/auth.module");
const course_module_1 = require("./modules/course/course.module");
const tenant_module_1 = require("./modules/tenant/tenant.module");
const common_module_1 = require("./modules/common/common.module");
const file_upload_module_1 = require("./modules/file-upload/file-upload.module");
const teacher_course_module_1 = require("./modules/teacher-course/teacher-course.module");
const lesson_module_1 = require("./modules/lesson/lesson.module");
const school_module_1 = require("./modules/school/school.module");
const resource_module_1 = require("./modules/resource/resource.module");
const growth_module_1 = require("./modules/growth/growth.module");
const task_module_1 = require("./modules/task/task.module");
const parent_module_1 = require("./modules/parent/parent.module");
const notification_module_1 = require("./modules/notification/notification.module");
const export_module_1 = require("./modules/export/export.module");
const admin_module_1 = require("./modules/admin/admin.module");
let AppModule = class AppModule {
};
exports.AppModule = AppModule;
exports.AppModule = AppModule = __decorate([
(0, common_1.Module)({
imports: [
config_1.ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.env.${process.env.NODE_ENV || 'development'}`,
}),
throttler_1.ThrottlerModule.forRoot([
{
ttl: 60000,
limit: 100,
},
]),
prisma_module_1.PrismaModule,
auth_module_1.AuthModule,
course_module_1.CourseModule,
tenant_module_1.TenantModule,
common_module_1.CommonModule,
file_upload_module_1.FileUploadModule,
teacher_course_module_1.TeacherCourseModule,
lesson_module_1.LessonModule,
school_module_1.SchoolModule,
resource_module_1.ResourceModule,
growth_module_1.GrowthModule,
task_module_1.TaskModule,
parent_module_1.ParentModule,
notification_module_1.NotificationModule,
export_module_1.ExportModule,
admin_module_1.AdminModule,
],
})
], AppModule);
//# sourceMappingURL=app.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA6D;AAC7D,iDAAoD;AACpD,4DAAwD;AACxD,4DAAwD;AACxD,kEAA8D;AAC9D,kEAA8D;AAC9D,kEAA8D;AAC9D,iFAA4E;AAC5E,0FAAqF;AACrF,kEAA8D;AAC9D,kEAA8D;AAC9D,wEAAoE;AACpE,kEAA8D;AAC9D,4DAAwD;AACxD,kEAA8D;AAC9D,oFAAgF;AAChF,kEAA8D;AAC9D,+DAA2D;AAuCpD,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IArCrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YAEP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,QAAQ,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,EAAE;aAC7D,CAAC;YAGF,2BAAe,CAAC,OAAO,CAAC;gBACtB;oBACE,GAAG,EAAE,KAAK;oBACV,KAAK,EAAE,GAAG;iBACX;aACF,CAAC;YAGF,4BAAY;YAGZ,wBAAU;YACV,4BAAY;YACZ,4BAAY;YACZ,4BAAY;YACZ,qCAAgB;YAChB,2CAAmB;YACnB,4BAAY;YACZ,4BAAY;YACZ,gCAAc;YACd,4BAAY;YACZ,wBAAU;YACV,4BAAY;YACZ,wCAAkB;YAClB,4BAAY;YACZ,0BAAW;SACZ;KACF,CAAC;GACW,SAAS,CAAG"}

View File

@ -1,5 +0,0 @@
import { ExceptionFilter, ArgumentsHost } from '@nestjs/common';
export declare class HttpExceptionFilter implements ExceptionFilter {
private readonly logger;
catch(exception: unknown, host: ArgumentsHost): void;
}

View File

@ -1,70 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var HttpExceptionFilter_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpExceptionFilter = void 0;
const common_1 = require("@nestjs/common");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
let HttpExceptionFilter = HttpExceptionFilter_1 = class HttpExceptionFilter {
constructor() {
this.logger = new common_1.Logger(HttpExceptionFilter_1.name);
}
catch(exception, host) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception instanceof common_1.HttpException
? exception.getStatus()
: common_1.HttpStatus.INTERNAL_SERVER_ERROR;
const message = exception instanceof common_1.HttpException
? exception.getResponse()
: { message: 'Internal server error', statusCode: 500 };
const errorLog = {
timestamp: new Date().toISOString(),
path: request.url,
method: request.method,
body: request.body,
status,
exception: exception instanceof Error ? exception.message : String(exception),
stack: exception instanceof Error ? exception.stack : undefined,
};
const logPath = path.join(process.cwd(), 'error.log');
fs.appendFileSync(logPath, JSON.stringify(errorLog, null, 2) + '\n');
this.logger.error('Exception caught', errorLog);
response.status(status).json(message);
}
};
exports.HttpExceptionFilter = HttpExceptionFilter;
exports.HttpExceptionFilter = HttpExceptionFilter = HttpExceptionFilter_1 = __decorate([
(0, common_1.Catch)()
], HttpExceptionFilter);
//# sourceMappingURL=http-exception.filter.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["../../../../src/common/filters/http-exception.filter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA0G;AAE1G,uCAAyB;AACzB,2CAA6B;AAGtB,IAAM,mBAAmB,2BAAzB,MAAM,mBAAmB;IAAzB;QACY,WAAM,GAAG,IAAI,eAAM,CAAC,qBAAmB,CAAC,IAAI,CAAC,CAAC;IAoCjE,CAAC;IAlCC,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAY,CAAC;QAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAW,CAAC;QAE1C,MAAM,MAAM,GACV,SAAS,YAAY,sBAAa;YAChC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE;YACvB,CAAC,CAAC,mBAAU,CAAC,qBAAqB,CAAC;QAEvC,MAAM,OAAO,GACX,SAAS,YAAY,sBAAa;YAChC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;YACzB,CAAC,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;QAE5D,MAAM,QAAQ,GAAG;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI,EAAE,OAAO,CAAC,GAAG;YACjB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM;YACN,SAAS,EAAE,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;YAC7E,KAAK,EAAE,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;SAChE,CAAC;QAGF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;QACtD,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAGrE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAEhD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;CACF,CAAA;AArCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,cAAK,GAAE;GACK,mBAAmB,CAqC/B"}

View File

@ -1,2 +0,0 @@
export declare class PrismaModule {
}

View File

@ -1,22 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrismaModule = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("./prisma.service");
let PrismaModule = class PrismaModule {
};
exports.PrismaModule = PrismaModule;
exports.PrismaModule = PrismaModule = __decorate([
(0, common_1.Global)(),
(0, common_1.Module)({
providers: [prisma_service_1.PrismaService],
exports: [prisma_service_1.PrismaService],
})
], PrismaModule);
//# sourceMappingURL=prisma.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"prisma.module.js","sourceRoot":"","sources":["../../../src/database/prisma.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,qDAAiD;AAO1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,8BAAa,CAAC;QAC1B,OAAO,EAAE,CAAC,8BAAa,CAAC;KACzB,CAAC;GACW,YAAY,CAAG"}

View File

@ -1,7 +0,0 @@
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
export declare class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
onModuleInit(): Promise<void>;
onModuleDestroy(): Promise<void>;
cleanDatabase(): Promise<void>;
}

View File

@ -1,45 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrismaService = void 0;
const common_1 = require("@nestjs/common");
const client_1 = require("@prisma/client");
let PrismaService = class PrismaService extends client_1.PrismaClient {
async onModuleInit() {
await this.$connect();
console.log('✅ Database connected successfully');
}
async onModuleDestroy() {
await this.$disconnect();
console.log('👋 Database disconnected');
}
async cleanDatabase() {
if (process.env.NODE_ENV === 'production') {
throw new Error('Cannot clean database in production');
}
await this.studentRecord.deleteMany();
await this.lessonFeedback.deleteMany();
await this.lesson.deleteMany();
await this.tenantCourse.deleteMany();
await this.courseScriptPage.deleteMany();
await this.courseScript.deleteMany();
await this.courseActivity.deleteMany();
await this.courseResource.deleteMany();
await this.course.deleteMany();
await this.student.deleteMany();
await this.class.deleteMany();
await this.teacher.deleteMany();
await this.tenant.deleteMany();
await this.tag.deleteMany();
}
};
exports.PrismaService = PrismaService;
exports.PrismaService = PrismaService = __decorate([
(0, common_1.Injectable)()
], PrismaService);
//# sourceMappingURL=prisma.service.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"prisma.service.js","sourceRoot":"","sources":["../../../src/database/prisma.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA2E;AAC3E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAY;IAC7C,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAC1C,CAAC;IAGD,KAAK,CAAC,aAAa;QACjB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QAGD,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC;QACzC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC;CACF,CAAA;AAjCY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAiCzB"}

View File

@ -1 +0,0 @@
export {};

View File

@ -1,51 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@nestjs/core");
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const path_1 = require("path");
const app_module_1 = require("./app.module");
const http_exception_filter_1 = require("./common/filters/http-exception.filter");
async function bootstrap() {
const app = await core_1.NestFactory.create(app_module_1.AppModule, {
logger: ['error', 'warn', 'log', 'debug', 'verbose'],
});
app.useBodyParser('json', { limit: '1500mb' });
app.useBodyParser('urlencoded', { limit: '1500mb', extended: true });
const configService = app.get(config_1.ConfigService);
app.useGlobalPipes(new common_1.ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
}));
app.useGlobalFilters(new http_exception_filter_1.HttpExceptionFilter());
app.enableCors({
origin: configService.get('FRONTEND_URL') || 'http://localhost:5173',
credentials: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
allowedHeaders: 'Content-Type, Accept, Authorization',
});
const uploadsPath = (0, path_1.join)(__dirname, '..', '..', 'uploads');
app.useStaticAssets(uploadsPath, {
prefix: '/uploads/',
});
app.setGlobalPrefix('api/v1');
const port = configService.get('PORT') || 3000;
await app.listen(port);
console.log(`
🚀 幼儿阅读教学服务平台后端启动成功
📍 Local: http://localhost:${port} ║
📍 API: http://localhost:${port}/api/v1 ║
📍 Prisma: npx prisma studio
`);
}
bootstrap();
//# sourceMappingURL=main.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,2CAAwD;AACxD,2CAA+C;AAE/C,+BAA4B;AAC5B,6CAAyC;AAEzC,kFAA6E;AAE7E,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAyB,sBAAS,EAAE;QACtE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC;KACrD,CAAC,CAAC;IAIH,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAErE,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,sBAAa,CAAC,CAAC;IAG7C,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;QACf,gBAAgB,EAAE;YAChB,wBAAwB,EAAE,IAAI;SAC/B;KACF,CAAC,CACH,CAAC;IAGF,GAAG,CAAC,gBAAgB,CAAC,IAAI,2CAAmB,EAAE,CAAC,CAAC;IAMhD,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,uBAAuB;QACpE,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,wCAAwC;QACjD,cAAc,EAAE,qCAAqC;KACtD,CAAC,CAAC;IAIH,MAAM,WAAW,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3D,GAAG,CAAC,eAAe,CAAC,WAAW,EAAE;QAC/B,MAAM,EAAE,WAAW;KACpB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE9B,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAS,MAAM,CAAC,IAAI,IAAI,CAAC;IACvD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC;;;;;yCAK2B,IAAI;yCACJ,IAAI;;;;GAI1C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,EAAE,CAAC"}

View File

@ -1,54 +0,0 @@
import { AdminSettingsService } from './admin-settings.service';
export declare class AdminSettingsController {
private readonly settingsService;
constructor(settingsService: AdminSettingsService);
getAllSettings(): Promise<{
[x: string]: any;
}>;
updateSettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getBasicSettings(): Promise<{
systemName: any;
systemDesc: any;
contactPhone: any;
contactEmail: any;
systemLogo: any;
}>;
updateBasicSettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getSecuritySettings(): Promise<{
passwordStrength: any;
maxLoginAttempts: any;
tokenExpire: any;
forceHttps: any;
}>;
updateSecuritySettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getNotificationSettings(): Promise<{
emailEnabled: any;
smtpHost: any;
smtpPort: any;
fromEmail: any;
smsEnabled: any;
}>;
updateNotificationSettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getStorageSettings(): Promise<{
type: any;
maxFileSize: any;
allowedTypes: any;
}>;
updateStorageSettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getTenantDefaults(): Promise<{
defaultTeacherQuota: any;
defaultStudentQuota: any;
enableAutoExpire: any;
notifyBeforeDays: any;
}>;
}

View File

@ -1,137 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminSettingsController = void 0;
const common_1 = require("@nestjs/common");
const admin_settings_service_1 = require("./admin-settings.service");
const jwt_auth_guard_1 = require("../common/guards/jwt-auth.guard");
const roles_guard_1 = require("../common/guards/roles.guard");
const roles_decorator_1 = require("../common/decorators/roles.decorator");
let AdminSettingsController = class AdminSettingsController {
constructor(settingsService) {
this.settingsService = settingsService;
}
async getAllSettings() {
return this.settingsService.getSettings();
}
async updateSettings(data) {
return this.settingsService.updateSettings(data);
}
async getBasicSettings() {
return this.settingsService.getBasicSettings();
}
async updateBasicSettings(data) {
return this.settingsService.updateSettings(data);
}
async getSecuritySettings() {
return this.settingsService.getSecuritySettings();
}
async updateSecuritySettings(data) {
return this.settingsService.updateSettings(data);
}
async getNotificationSettings() {
return this.settingsService.getNotificationSettings();
}
async updateNotificationSettings(data) {
return this.settingsService.updateSettings(data);
}
async getStorageSettings() {
return this.settingsService.getStorageSettings();
}
async updateStorageSettings(data) {
return this.settingsService.updateSettings(data);
}
async getTenantDefaults() {
return this.settingsService.getTenantDefaults();
}
};
exports.AdminSettingsController = AdminSettingsController;
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getAllSettings", null);
__decorate([
(0, common_1.Put)(),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "updateSettings", null);
__decorate([
(0, common_1.Get)('basic'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getBasicSettings", null);
__decorate([
(0, common_1.Put)('basic'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "updateBasicSettings", null);
__decorate([
(0, common_1.Get)('security'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getSecuritySettings", null);
__decorate([
(0, common_1.Put)('security'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "updateSecuritySettings", null);
__decorate([
(0, common_1.Get)('notification'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getNotificationSettings", null);
__decorate([
(0, common_1.Put)('notification'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "updateNotificationSettings", null);
__decorate([
(0, common_1.Get)('storage'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getStorageSettings", null);
__decorate([
(0, common_1.Put)('storage'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "updateStorageSettings", null);
__decorate([
(0, common_1.Get)('tenant-defaults'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminSettingsController.prototype, "getTenantDefaults", null);
exports.AdminSettingsController = AdminSettingsController = __decorate([
(0, common_1.Controller)('admin/settings'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('admin'),
__metadata("design:paramtypes", [admin_settings_service_1.AdminSettingsService])
], AdminSettingsController);
//# sourceMappingURL=admin-settings.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"admin-settings.controller.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin-settings.controller.ts"],"names":[],"mappings":"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"}

View File

@ -1,44 +0,0 @@
import { PrismaService } from '../../database/prisma.service';
export declare class AdminSettingsService {
private prisma;
private settings;
constructor(prisma: PrismaService);
getSettings(): Promise<{
[x: string]: any;
}>;
getSetting(key: string): Promise<any>;
updateSettings(data: Record<string, any>): Promise<{
[x: string]: any;
}>;
getBasicSettings(): Promise<{
systemName: any;
systemDesc: any;
contactPhone: any;
contactEmail: any;
systemLogo: any;
}>;
getSecuritySettings(): Promise<{
passwordStrength: any;
maxLoginAttempts: any;
tokenExpire: any;
forceHttps: any;
}>;
getNotificationSettings(): Promise<{
emailEnabled: any;
smtpHost: any;
smtpPort: any;
fromEmail: any;
smsEnabled: any;
}>;
getStorageSettings(): Promise<{
type: any;
maxFileSize: any;
allowedTypes: any;
}>;
getTenantDefaults(): Promise<{
defaultTeacherQuota: any;
defaultStudentQuota: any;
enableAutoExpire: any;
notifyBeforeDays: any;
}>;
}

View File

@ -1,105 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminSettingsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../database/prisma.service");
let AdminSettingsService = class AdminSettingsService {
constructor(prisma) {
this.prisma = prisma;
this.settings = {
systemName: '幼儿阅读教学服务平台',
systemDesc: '',
contactPhone: '',
contactEmail: '',
systemLogo: '',
passwordStrength: 'medium',
maxLoginAttempts: 5,
tokenExpire: '7d',
forceHttps: false,
emailEnabled: true,
smtpHost: '',
smtpPort: 465,
smtpUser: '',
smtpPassword: '',
fromEmail: '',
smsEnabled: false,
storageType: 'local',
maxFileSize: 100,
allowedTypes: '.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.ppt,.pptx',
defaultTeacherQuota: 20,
defaultStudentQuota: 200,
enableAutoExpire: true,
notifyBeforeDays: 30,
};
}
async getSettings() {
return { ...this.settings };
}
async getSetting(key) {
return this.settings[key];
}
async updateSettings(data) {
for (const key of Object.keys(data)) {
if (key in this.settings) {
this.settings[key] = data[key];
}
}
return { ...this.settings };
}
async getBasicSettings() {
return {
systemName: this.settings.systemName,
systemDesc: this.settings.systemDesc,
contactPhone: this.settings.contactPhone,
contactEmail: this.settings.contactEmail,
systemLogo: this.settings.systemLogo,
};
}
async getSecuritySettings() {
return {
passwordStrength: this.settings.passwordStrength,
maxLoginAttempts: this.settings.maxLoginAttempts,
tokenExpire: this.settings.tokenExpire,
forceHttps: this.settings.forceHttps,
};
}
async getNotificationSettings() {
return {
emailEnabled: this.settings.emailEnabled,
smtpHost: this.settings.smtpHost,
smtpPort: this.settings.smtpPort,
fromEmail: this.settings.fromEmail,
smsEnabled: this.settings.smsEnabled,
};
}
async getStorageSettings() {
return {
type: this.settings.storageType,
maxFileSize: this.settings.maxFileSize,
allowedTypes: this.settings.allowedTypes,
};
}
async getTenantDefaults() {
return {
defaultTeacherQuota: this.settings.defaultTeacherQuota,
defaultStudentQuota: this.settings.defaultStudentQuota,
enableAutoExpire: this.settings.enableAutoExpire,
notifyBeforeDays: this.settings.notifyBeforeDays,
};
}
};
exports.AdminSettingsService = AdminSettingsService;
exports.AdminSettingsService = AdminSettingsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminSettingsService);
//# sourceMappingURL=admin-settings.service.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"admin-settings.service.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin-settings.service.ts"],"names":[],"mappings":"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"}

View File

@ -1,41 +0,0 @@
import { AdminStatsService } from './admin-stats.service';
export declare class AdminStatsController {
private readonly statsService;
constructor(statsService: AdminStatsService);
getStats(): Promise<{
tenantCount: number;
activeTenantCount: number;
courseCount: number;
publishedCourseCount: number;
studentCount: number;
teacherCount: number;
lessonCount: number;
monthlyLessons: number;
}>;
getTrendData(): Promise<{
month: string;
tenantCount: number;
lessonCount: number;
studentCount: number;
}[]>;
getActiveTenants(limit?: string): Promise<{
id: number;
name: string;
lessonCount: number;
teacherCount: number;
studentCount: number;
}[]>;
getPopularCourses(limit?: string): Promise<{
id: number;
name: string;
usageCount: number;
teacherCount: number;
}[]>;
getRecentActivities(limit?: string): Promise<{
time: string;
id: number;
type: string;
title: string;
description?: string;
}[]>;
}

View File

@ -1,84 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminStatsController = void 0;
const common_1 = require("@nestjs/common");
const admin_stats_service_1 = require("./admin-stats.service");
const jwt_auth_guard_1 = require("../common/guards/jwt-auth.guard");
const roles_guard_1 = require("../common/guards/roles.guard");
const roles_decorator_1 = require("../common/decorators/roles.decorator");
let AdminStatsController = class AdminStatsController {
constructor(statsService) {
this.statsService = statsService;
}
async getStats() {
return this.statsService.getStats();
}
async getTrendData() {
return this.statsService.getTrendData();
}
async getActiveTenants(limit) {
const limitNum = limit ? parseInt(limit, 10) : 5;
return this.statsService.getActiveTenants(limitNum);
}
async getPopularCourses(limit) {
const limitNum = limit ? parseInt(limit, 10) : 5;
return this.statsService.getPopularCourses(limitNum);
}
async getRecentActivities(limit) {
const limitNum = limit ? parseInt(limit, 10) : 10;
return this.statsService.getRecentActivities(limitNum);
}
};
exports.AdminStatsController = AdminStatsController;
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminStatsController.prototype, "getStats", null);
__decorate([
(0, common_1.Get)('trend'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AdminStatsController.prototype, "getTrendData", null);
__decorate([
(0, common_1.Get)('tenants/active'),
__param(0, (0, common_1.Query)('limit')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], AdminStatsController.prototype, "getActiveTenants", null);
__decorate([
(0, common_1.Get)('courses/popular'),
__param(0, (0, common_1.Query)('limit')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], AdminStatsController.prototype, "getPopularCourses", null);
__decorate([
(0, common_1.Get)('activities'),
__param(0, (0, common_1.Query)('limit')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], AdminStatsController.prototype, "getRecentActivities", null);
exports.AdminStatsController = AdminStatsController = __decorate([
(0, common_1.Controller)('admin/stats'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('admin'),
__metadata("design:paramtypes", [admin_stats_service_1.AdminStatsService])
], AdminStatsController);
//# sourceMappingURL=admin-stats.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"admin-stats.controller.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin-stats.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmE;AACnE,+DAA0D;AAC1D,oEAA+D;AAC/D,8DAA0D;AAC1D,0EAA6D;AAKtD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAC/B,YAA6B,YAA+B;QAA/B,iBAAY,GAAZ,YAAY,CAAmB;IAAG,CAAC;IAG1D,AAAN,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;IACtC,CAAC;IAGK,AAAN,KAAK,CAAC,YAAY;QAChB,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;IAC1C,CAAC;IAGK,AAAN,KAAK,CAAC,gBAAgB,CAAiB,KAAc;QACnD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAGK,AAAN,KAAK,CAAC,iBAAiB,CAAiB,KAAc;QACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAGK,AAAN,KAAK,CAAC,mBAAmB,CAAiB,KAAc;QACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC;CACF,CAAA;AA9BY,oDAAoB;AAIzB;IADL,IAAA,YAAG,GAAE;;;;oDAGL;AAGK;IADL,IAAA,YAAG,EAAC,OAAO,CAAC;;;;wDAGZ;AAGK;IADL,IAAA,YAAG,EAAC,gBAAgB,CAAC;IACE,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;4DAGrC;AAGK;IADL,IAAA,YAAG,EAAC,iBAAiB,CAAC;IACE,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;6DAGtC;AAGK;IADL,IAAA,YAAG,EAAC,YAAY,CAAC;IACS,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;+DAGxC;+BA7BU,oBAAoB;IAHhC,IAAA,mBAAU,EAAC,aAAa,CAAC;IACzB,IAAA,kBAAS,EAAC,6BAAY,EAAE,wBAAU,CAAC;IACnC,IAAA,uBAAK,EAAC,OAAO,CAAC;qCAE8B,uCAAiB;GADjD,oBAAoB,CA8BhC"}

View File

@ -1,42 +0,0 @@
import { PrismaService } from '../../database/prisma.service';
export declare class AdminStatsService {
private prisma;
constructor(prisma: PrismaService);
getStats(): Promise<{
tenantCount: number;
activeTenantCount: number;
courseCount: number;
publishedCourseCount: number;
studentCount: number;
teacherCount: number;
lessonCount: number;
monthlyLessons: number;
}>;
private getThisMonthLessonCount;
getTrendData(): Promise<{
month: string;
tenantCount: number;
lessonCount: number;
studentCount: number;
}[]>;
getActiveTenants(limit?: number): Promise<{
id: number;
name: string;
lessonCount: number;
teacherCount: number;
studentCount: number;
}[]>;
getPopularCourses(limit?: number): Promise<{
id: number;
name: string;
usageCount: number;
teacherCount: number;
}[]>;
getRecentActivities(limit?: number): Promise<{
time: string;
id: number;
type: string;
title: string;
description?: string;
}[]>;
}

View File

@ -1,212 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminStatsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../database/prisma.service");
let AdminStatsService = class AdminStatsService {
constructor(prisma) {
this.prisma = prisma;
}
async getStats() {
const [tenantCount, activeTenantCount, courseCount, publishedCourseCount, studentCount, teacherCount, lessonCount, monthlyLessons,] = await Promise.all([
this.prisma.tenant.count(),
this.prisma.tenant.count({ where: { status: 'ACTIVE' } }),
this.prisma.course.count(),
this.prisma.course.count({ where: { status: 'PUBLISHED' } }),
this.prisma.student.count(),
this.prisma.teacher.count(),
this.prisma.lesson.count(),
this.getThisMonthLessonCount(),
]);
return {
tenantCount,
activeTenantCount,
courseCount,
publishedCourseCount,
studentCount,
teacherCount,
lessonCount,
monthlyLessons,
};
}
async getThisMonthLessonCount() {
const now = new Date();
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
return this.prisma.lesson.count({
where: {
createdAt: {
gte: firstDayOfMonth,
},
},
});
}
async getTrendData() {
const months = [];
for (let i = 5; i >= 0; i--) {
const date = new Date();
date.setMonth(date.getMonth() - i);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const monthStr = `${year}-${String(month).padStart(2, '0')}`;
const firstDay = new Date(year, month - 1, 1);
const lastDay = new Date(year, month, 0, 23, 59, 59);
const [tenantCount, lessonCount, studentCount] = await Promise.all([
this.prisma.tenant.count({
where: {
createdAt: {
lte: lastDay,
},
},
}),
this.prisma.lesson.count({
where: {
createdAt: {
gte: firstDay,
lte: lastDay,
},
},
}),
this.prisma.student.count({
where: {
createdAt: {
lte: lastDay,
},
},
}),
]);
months.push({
month: monthStr,
tenantCount,
lessonCount,
studentCount,
});
}
return months;
}
async getActiveTenants(limit = 5) {
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const tenants = await this.prisma.tenant.findMany({
select: {
id: true,
name: true,
teacherCount: true,
studentCount: true,
_count: {
select: {
lessons: {
where: {
createdAt: {
gte: thirtyDaysAgo,
},
},
},
},
},
},
orderBy: {
lessons: {
_count: 'desc',
},
},
take: limit,
});
return tenants.map((t) => ({
id: t.id,
name: t.name,
lessonCount: t._count.lessons,
teacherCount: t.teacherCount,
studentCount: t.studentCount,
}));
}
async getPopularCourses(limit = 5) {
const courses = await this.prisma.course.findMany({
select: {
id: true,
name: true,
usageCount: true,
teacherCount: true,
},
where: {
status: 'PUBLISHED',
},
orderBy: {
usageCount: 'desc',
},
take: limit,
});
return courses;
}
async getRecentActivities(limit = 10) {
const activities = [];
const recentLessons = await this.prisma.lesson.findMany({
select: {
id: true,
createdAt: true,
tenant: {
select: {
name: true,
},
},
course: {
select: {
name: true,
},
},
},
orderBy: {
createdAt: 'desc',
},
take: limit,
});
for (const lesson of recentLessons) {
activities.push({
id: lesson.id,
type: 'lesson',
title: `${lesson.tenant.name} 完成了课程《${lesson.course.name}`,
time: lesson.createdAt,
});
}
const recentTenants = await this.prisma.tenant.findMany({
select: {
id: true,
name: true,
createdAt: true,
},
orderBy: {
createdAt: 'desc',
},
take: limit,
});
for (const tenant of recentTenants) {
activities.push({
id: tenant.id + 10000,
type: 'tenant',
title: `新租户注册: ${tenant.name}`,
time: tenant.createdAt,
});
}
return activities
.sort((a, b) => b.time.getTime() - a.time.getTime())
.slice(0, limit)
.map((a) => ({
...a,
time: a.time.toISOString(),
}));
}
};
exports.AdminStatsService = AdminStatsService;
exports.AdminStatsService = AdminStatsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminStatsService);
//# sourceMappingURL=admin-stats.service.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
export declare class AdminModule {
}

View File

@ -1,27 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminModule = void 0;
const common_1 = require("@nestjs/common");
const admin_settings_controller_1 = require("./admin-settings.controller");
const admin_settings_service_1 = require("./admin-settings.service");
const admin_stats_controller_1 = require("./admin-stats.controller");
const admin_stats_service_1 = require("./admin-stats.service");
const prisma_module_1 = require("../../database/prisma.module");
let AdminModule = class AdminModule {
};
exports.AdminModule = AdminModule;
exports.AdminModule = AdminModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule],
controllers: [admin_settings_controller_1.AdminSettingsController, admin_stats_controller_1.AdminStatsController],
providers: [admin_settings_service_1.AdminSettingsService, admin_stats_service_1.AdminStatsService],
exports: [admin_settings_service_1.AdminSettingsService, admin_stats_service_1.AdminStatsService],
})
], AdminModule);
//# sourceMappingURL=admin.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2EAAsE;AACtE,qEAAgE;AAChE,qEAAgE;AAChE,+DAA0D;AAC1D,gEAA4D;AAQrD,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IANvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,WAAW,EAAE,CAAC,mDAAuB,EAAE,6CAAoB,CAAC;QAC5D,SAAS,EAAE,CAAC,6CAAoB,EAAE,uCAAiB,CAAC;QACpD,OAAO,EAAE,CAAC,6CAAoB,EAAE,uCAAiB,CAAC;KACnD,CAAC;GACW,WAAW,CAAG"}

View File

@ -1,60 +0,0 @@
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
export declare class AuthController {
private authService;
constructor(authService: AuthService);
login(loginDto: LoginDto): Promise<{
token: string;
user: {
id: any;
name: any;
role: any;
tenantId: any;
tenantName: any;
};
}>;
logout(): Promise<{
message: string;
}>;
getProfile(req: any): Promise<{
id: number;
name: string;
role: string;
tenantId?: undefined;
tenantName?: undefined;
email?: undefined;
phone?: undefined;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email?: undefined;
phone?: undefined;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email: string;
phone: string;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email: string;
phone: string;
children: {
id: number;
name: string;
relationship: string;
}[];
}>;
}

View File

@ -1,61 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthController = void 0;
const common_1 = require("@nestjs/common");
const auth_service_1 = require("./auth.service");
const jwt_auth_guard_1 = require("../common/guards/jwt-auth.guard");
const login_dto_1 = require("./dto/login.dto");
let AuthController = class AuthController {
constructor(authService) {
this.authService = authService;
}
async login(loginDto) {
return this.authService.login(loginDto);
}
async logout() {
return { message: 'Logged out successfully' };
}
async getProfile(req) {
return this.authService.getProfile(req.user.userId, req.user.role);
}
};
exports.AuthController = AuthController;
__decorate([
(0, common_1.Post)('login'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [login_dto_1.LoginDto]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "login", null);
__decorate([
(0, common_1.Post)('logout'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AuthController.prototype, "logout", null);
__decorate([
(0, common_1.Get)('profile'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
__param(0, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "getProfile", null);
exports.AuthController = AuthController = __decorate([
(0, common_1.Controller)('auth'),
__metadata("design:paramtypes", [auth_service_1.AuthService])
], AuthController);
//# sourceMappingURL=auth.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAiF;AACjF,iDAA6C;AAC7C,oEAA+D;AAC/D,+CAA2C;AAGpC,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAAoB,WAAwB;QAAxB,gBAAW,GAAX,WAAW,CAAa;IAAG,CAAC;IAG1C,AAAN,KAAK,CAAC,KAAK,CAAS,QAAkB;QACpC,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAIK,AAAN,KAAK,CAAC,MAAM;QAEV,OAAO,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;IAChD,CAAC;IAIK,AAAN,KAAK,CAAC,UAAU,CAAY,GAAG;QAC7B,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrE,CAAC;CACF,CAAA;AApBY,wCAAc;AAInB;IADL,IAAA,aAAI,EAAC,OAAO,CAAC;IACD,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAW,oBAAQ;;2CAErC;AAIK;IAFL,IAAA,aAAI,EAAC,QAAQ,CAAC;IACd,IAAA,kBAAS,EAAC,6BAAY,CAAC;;;;4CAIvB;AAIK;IAFL,IAAA,YAAG,EAAC,SAAS,CAAC;IACd,IAAA,kBAAS,EAAC,6BAAY,CAAC;IACN,WAAA,IAAA,gBAAO,GAAE,CAAA;;;;gDAE1B;yBAnBU,cAAc;IAD1B,IAAA,mBAAU,EAAC,MAAM,CAAC;qCAEgB,0BAAW;GADjC,cAAc,CAoB1B"}

View File

@ -1,2 +0,0 @@
export declare class AuthModule {
}

View File

@ -1,42 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthModule = void 0;
const common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
const passport_1 = require("@nestjs/passport");
const config_1 = require("@nestjs/config");
const auth_service_1 = require("./auth.service");
const auth_controller_1 = require("./auth.controller");
const jwt_strategy_1 = require("./strategies/jwt.strategy");
const prisma_module_1 = require("../../database/prisma.module");
let AuthModule = class AuthModule {
};
exports.AuthModule = AuthModule;
exports.AuthModule = AuthModule = __decorate([
(0, common_1.Module)({
imports: [
passport_1.PassportModule,
jwt_1.JwtModule.registerAsync({
imports: [config_1.ConfigModule],
useFactory: async (configService) => ({
secret: configService.get('JWT_SECRET') || 'your-secret-key',
signOptions: {
expiresIn: configService.get('JWT_EXPIRES_IN') || '7d',
},
}),
inject: [config_1.ConfigService],
}),
prisma_module_1.PrismaModule,
],
controllers: [auth_controller_1.AuthController],
providers: [auth_service_1.AuthService, jwt_strategy_1.JwtStrategy],
exports: [auth_service_1.AuthService],
})
], AuthModule);
//# sourceMappingURL=auth.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qCAAwC;AACxC,+CAAkD;AAClD,2CAA6D;AAC7D,iDAA6C;AAC7C,uDAAmD;AACnD,4DAAwD;AACxD,gEAA4D;AAqBrD,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAnBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,yBAAc;YACd,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE,CAAC,CAAC;oBACnD,MAAM,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC,IAAI,iBAAiB;oBACpE,WAAW,EAAE;wBACX,SAAS,EAAE,aAAa,CAAC,GAAG,CAAS,gBAAgB,CAAC,IAAI,IAAI;qBAC/D;iBACF,CAAC;gBACF,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB,CAAC;YACF,4BAAY;SACb;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,EAAE,0BAAW,CAAC;QACrC,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAAG"}

View File

@ -1,84 +0,0 @@
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../../database/prisma.service';
export interface LoginDto {
account: string;
password: string;
role: string;
}
export interface JwtPayload {
sub: number;
role: string;
tenantId?: number;
}
export declare class AuthService {
private prisma;
private jwtService;
constructor(prisma: PrismaService, jwtService: JwtService);
validateUser(account: string, password: string): Promise<{
id: number;
tenantId: number;
name: string;
phone: string;
email: string | null;
loginAccount: string;
passwordHash: string;
classIds: string | null;
status: string;
lessonCount: number;
feedbackCount: number;
createdAt: Date;
updatedAt: Date;
lastLoginAt: Date | null;
}>;
login(dto: LoginDto): Promise<{
token: string;
user: {
id: any;
name: any;
role: any;
tenantId: any;
tenantName: any;
};
}>;
getProfile(userId: number, role: string): Promise<{
id: number;
name: string;
role: string;
tenantId?: undefined;
tenantName?: undefined;
email?: undefined;
phone?: undefined;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email?: undefined;
phone?: undefined;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email: string;
phone: string;
children?: undefined;
} | {
id: number;
name: string;
role: string;
tenantId: number;
tenantName: string;
email: string;
phone: string;
children: {
id: number;
name: string;
relationship: string;
}[];
}>;
}

View File

@ -1,287 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0;
const common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
const prisma_service_1 = require("../../database/prisma.service");
const bcrypt = __importStar(require("bcrypt"));
let AuthService = class AuthService {
constructor(prisma, jwtService) {
this.prisma = prisma;
this.jwtService = jwtService;
}
async validateUser(account, password) {
const user = await this.prisma.teacher.findUnique({
where: { loginAccount: account },
});
if (!user) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
if (!isPasswordValid) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
if (user.status !== 'ACTIVE') {
throw new common_1.UnauthorizedException('账号已被停用');
}
return user;
}
async login(dto) {
let user;
if (dto.role === 'admin') {
if (dto.account === 'admin' && dto.password === 'admin123') {
user = {
id: 1,
name: '超级管理员',
role: 'admin',
};
}
else {
throw new common_1.UnauthorizedException('账号或密码错误');
}
}
else if (dto.role === 'school') {
const tenant = await this.prisma.tenant.findUnique({
where: { loginAccount: dto.account },
});
if (!tenant) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
if (!tenant.passwordHash) {
throw new common_1.UnauthorizedException('账号未设置密码');
}
const isPasswordValid = await bcrypt.compare(dto.password, tenant.passwordHash);
if (!isPasswordValid) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
if (tenant.status !== 'ACTIVE') {
throw new common_1.UnauthorizedException('账号已被停用');
}
user = {
id: tenant.id,
name: tenant.name,
role: 'school',
tenantId: tenant.id,
tenantName: tenant.name,
};
}
else if (dto.role === 'teacher') {
const teacher = await this.prisma.teacher.findUnique({
where: { loginAccount: dto.account },
include: {
tenant: {
select: {
id: true,
name: true,
},
},
},
});
if (!teacher) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
const isPasswordValid = await bcrypt.compare(dto.password, teacher.passwordHash);
if (!isPasswordValid) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
if (teacher.status !== 'ACTIVE') {
throw new common_1.UnauthorizedException('账号已被停用');
}
user = {
id: teacher.id,
name: teacher.name,
role: 'teacher',
tenantId: teacher.tenantId,
tenantName: teacher.tenant?.name,
};
}
else if (dto.role === 'parent') {
const parent = await this.prisma.parent.findUnique({
where: { loginAccount: dto.account },
include: {
tenant: {
select: {
id: true,
name: true,
},
},
},
});
if (!parent) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
const isPasswordValid = await bcrypt.compare(dto.password, parent.passwordHash);
if (!isPasswordValid) {
throw new common_1.UnauthorizedException('账号或密码错误');
}
if (parent.status !== 'ACTIVE') {
throw new common_1.UnauthorizedException('账号已被停用');
}
user = {
id: parent.id,
name: parent.name,
role: 'parent',
tenantId: parent.tenantId,
tenantName: parent.tenant?.name,
};
await this.prisma.parent.update({
where: { id: parent.id },
data: { lastLoginAt: new Date() },
});
}
else {
throw new common_1.UnauthorizedException('无效的角色');
}
const payload = {
sub: user.id,
role: user.role,
tenantId: user.tenantId,
};
const token = this.jwtService.sign(payload);
if (dto.role === 'teacher') {
await this.prisma.teacher.update({
where: { id: user.id },
data: { lastLoginAt: new Date() },
});
}
return {
token,
user: {
id: user.id,
name: user.name,
role: user.role,
tenantId: user.tenantId,
tenantName: user.tenantName,
},
};
}
async getProfile(userId, role) {
if (role === 'admin') {
return {
id: 1,
name: '超级管理员',
role: 'admin',
};
}
else if (role === 'school') {
const tenant = await this.prisma.tenant.findUnique({
where: { id: userId },
});
if (!tenant) {
throw new common_1.UnauthorizedException('用户不存在');
}
return {
id: tenant.id,
name: tenant.name,
role: 'school',
tenantId: tenant.id,
tenantName: tenant.name,
};
}
else if (role === 'teacher') {
const teacher = await this.prisma.teacher.findUnique({
where: { id: userId },
include: {
tenant: {
select: {
id: true,
name: true,
},
},
},
});
if (!teacher) {
throw new common_1.UnauthorizedException('用户不存在');
}
return {
id: teacher.id,
name: teacher.name,
role: 'teacher',
tenantId: teacher.tenantId,
tenantName: teacher.tenant?.name,
email: teacher.email,
phone: teacher.phone,
};
}
else if (role === 'parent') {
const parent = await this.prisma.parent.findUnique({
where: { id: userId },
include: {
tenant: {
select: {
id: true,
name: true,
},
},
children: {
include: {
student: {
select: {
id: true,
name: true,
},
},
},
},
},
});
if (!parent) {
throw new common_1.UnauthorizedException('用户不存在');
}
return {
id: parent.id,
name: parent.name,
role: 'parent',
tenantId: parent.tenantId,
tenantName: parent.tenant?.name,
email: parent.email,
phone: parent.phone,
children: parent.children.map((c) => ({
id: c.student.id,
name: c.student.name,
relationship: c.relationship,
})),
};
}
throw new common_1.UnauthorizedException('无效的角色');
}
};
exports.AuthService = AuthService;
exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
jwt_1.JwtService])
], AuthService);
//# sourceMappingURL=auth.service.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
export declare class LoginDto {
account: string;
password: string;
role: string;
}

View File

@ -1,33 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoginDto = void 0;
const class_validator_1 = require("class-validator");
class LoginDto {
}
exports.LoginDto = LoginDto;
__decorate([
(0, class_validator_1.IsString)(),
(0, class_validator_1.IsNotEmpty)(),
__metadata("design:type", String)
], LoginDto.prototype, "account", void 0);
__decorate([
(0, class_validator_1.IsString)(),
(0, class_validator_1.IsNotEmpty)(),
__metadata("design:type", String)
], LoginDto.prototype, "password", void 0);
__decorate([
(0, class_validator_1.IsString)(),
(0, class_validator_1.IsIn)(['admin', 'school', 'teacher', 'parent']),
(0, class_validator_1.IsNotEmpty)(),
__metadata("design:type", String)
], LoginDto.prototype, "role", void 0);
//# sourceMappingURL=login.dto.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"login.dto.js","sourceRoot":"","sources":["../../../../../src/modules/auth/dto/login.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA6D;AAE7D,MAAa,QAAQ;CAapB;AAbD,4BAaC;AAVC;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;yCACG;AAIhB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0CACI;AAKjB;IAHC,IAAA,0BAAQ,GAAE;IACV,IAAA,sBAAI,EAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAA,4BAAU,GAAE;;sCACA"}

View File

@ -1,18 +0,0 @@
import { Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
export interface JwtPayload {
sub: number;
role: string;
tenantId?: number;
}
declare const JwtStrategy_base: new (...args: any[]) => Strategy;
export declare class JwtStrategy extends JwtStrategy_base {
private configService;
constructor(configService: ConfigService);
validate(payload: JwtPayload): Promise<{
userId: number;
role: string;
tenantId: number;
}>;
}
export {};

View File

@ -1,42 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JwtStrategy = void 0;
const common_1 = require("@nestjs/common");
const passport_1 = require("@nestjs/passport");
const passport_jwt_1 = require("passport-jwt");
const config_1 = require("@nestjs/config");
let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(passport_jwt_1.Strategy) {
constructor(configService) {
super({
jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get('JWT_SECRET') || 'your-secret-key',
});
this.configService = configService;
}
async validate(payload) {
if (!payload.sub || !payload.role) {
throw new common_1.UnauthorizedException();
}
return {
userId: payload.sub,
role: payload.role,
tenantId: payload.tenantId,
};
}
};
exports.JwtStrategy = JwtStrategy;
exports.JwtStrategy = JwtStrategy = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], JwtStrategy);
//# sourceMappingURL=jwt.strategy.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../../../../src/modules/auth/strategies/jwt.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAmE;AACnE,+CAAoD;AACpD,+CAAoD;AACpD,2CAA+C;AASxC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;IACzD,YAAoB,aAA4B;QAC9C,KAAK,CAAC;YACJ,cAAc,EAAE,yBAAU,CAAC,2BAA2B,EAAE;YACxD,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC,IAAI,iBAAiB;SAC1E,CAAC,CAAC;QALe,kBAAa,GAAb,aAAa,CAAe;IAMhD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAmB;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,CAAC;QAED,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,GAAG;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AApBY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;qCAEwB,sBAAa;GADrC,WAAW,CAoBvB"}

View File

@ -1,2 +0,0 @@
export declare class CommonModule {
}

View File

@ -1,26 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommonModule = void 0;
const common_1 = require("@nestjs/common");
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
const roles_guard_1 = require("./guards/roles.guard");
const log_interceptor_1 = require("./interceptors/log.interceptor");
const operation_log_service_1 = require("./operation-log.service");
const operation_log_controller_1 = require("./operation-log.controller");
let CommonModule = class CommonModule {
};
exports.CommonModule = CommonModule;
exports.CommonModule = CommonModule = __decorate([
(0, common_1.Module)({
controllers: [operation_log_controller_1.SchoolOperationLogController, operation_log_controller_1.AdminOperationLogController],
providers: [jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard, log_interceptor_1.LogInterceptor, operation_log_service_1.OperationLogService],
exports: [jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard, log_interceptor_1.LogInterceptor, operation_log_service_1.OperationLogService],
})
], CommonModule);
//# sourceMappingURL=common.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"common.module.js","sourceRoot":"","sources":["../../../../src/modules/common/common.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAuD;AACvD,sDAAkD;AAClD,oEAAgE;AAChE,mEAA8D;AAC9D,yEAAuG;AAOhG,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,uDAA4B,EAAE,sDAA2B,CAAC;QACxE,SAAS,EAAE,CAAC,6BAAY,EAAE,wBAAU,EAAE,gCAAc,EAAE,2CAAmB,CAAC;QAC1E,OAAO,EAAE,CAAC,6BAAY,EAAE,wBAAU,EAAE,gCAAc,EAAE,2CAAmB,CAAC;KACzE,CAAC;GACW,YAAY,CAAG"}

View File

@ -1,7 +0,0 @@
export declare const LOG_OPERATION_KEY = "log_operation";
export interface LogOperationOptions {
action: string;
module: string;
description: string;
}
export declare const LogOperation: (options: LogOperationOptions) => import("@nestjs/common").CustomDecorator<string>;

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogOperation = exports.LOG_OPERATION_KEY = void 0;
const common_1 = require("@nestjs/common");
exports.LOG_OPERATION_KEY = 'log_operation';
const LogOperation = (options) => {
return (0, common_1.SetMetadata)(exports.LOG_OPERATION_KEY, options);
};
exports.LogOperation = LogOperation;
//# sourceMappingURL=log-operation.decorator.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"log-operation.decorator.js","sourceRoot":"","sources":["../../../../../src/modules/common/decorators/log-operation.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAEhC,QAAA,iBAAiB,GAAG,eAAe,CAAC;AAY1C,MAAM,YAAY,GAAG,CAAC,OAA4B,EAAE,EAAE;IAC3D,OAAO,IAAA,oBAAW,EAAC,yBAAiB,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC,CAAC;AAFW,QAAA,YAAY,gBAEvB"}

View File

@ -1,2 +0,0 @@
export declare const ROLES_KEY = "roles";
export declare const Roles: (...roles: string[]) => import("@nestjs/common").CustomDecorator<string>;

View File

@ -1,8 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Roles = exports.ROLES_KEY = void 0;
const common_1 = require("@nestjs/common");
exports.ROLES_KEY = 'roles';
const Roles = (...roles) => (0, common_1.SetMetadata)(exports.ROLES_KEY, roles);
exports.Roles = Roles;
//# sourceMappingURL=roles.decorator.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"roles.decorator.js","sourceRoot":"","sources":["../../../../../src/modules/common/decorators/roles.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAEhC,QAAA,SAAS,GAAG,OAAO,CAAC;AAC1B,MAAM,KAAK,GAAG,CAAC,GAAG,KAAe,EAAE,EAAE,CAAC,IAAA,oBAAW,EAAC,iBAAS,EAAE,KAAK,CAAC,CAAC;AAA9D,QAAA,KAAK,SAAyD"}

View File

@ -1,9 +0,0 @@
import { ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
declare const JwtAuthGuard_base: import("@nestjs/passport").Type<import("@nestjs/passport").IAuthGuard>;
export declare class JwtAuthGuard extends JwtAuthGuard_base {
private reflector;
constructor(reflector: Reflector);
canActivate(context: ExecutionContext): boolean | Promise<boolean> | import("rxjs").Observable<boolean>;
}
export {};

View File

@ -1,37 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JwtAuthGuard = void 0;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const passport_1 = require("@nestjs/passport");
let JwtAuthGuard = class JwtAuthGuard extends (0, passport_1.AuthGuard)('jwt') {
constructor(reflector) {
super();
this.reflector = reflector;
}
canActivate(context) {
const requireAuth = this.reflector.getAllAndOverride('requireAuth', [
context.getHandler(),
context.getClass(),
]);
if (requireAuth === false) {
return true;
}
return super.canActivate(context);
}
};
exports.JwtAuthGuard = JwtAuthGuard;
exports.JwtAuthGuard = JwtAuthGuard = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [core_1.Reflector])
], JwtAuthGuard);
//# sourceMappingURL=jwt-auth.guard.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../../../src/modules/common/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA8D;AAC9D,uCAAyC;AACzC,+CAA6C;AAGtC,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,IAAA,oBAAS,EAAC,KAAK,CAAC;IAChD,YAAoB,SAAoB;QACtC,KAAK,EAAE,CAAC;QADU,cAAS,GAAT,SAAS,CAAW;IAExC,CAAC;IAED,WAAW,CAAC,OAAyB;QAEnC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAU,aAAa,EAAE;YAC3E,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QAEH,IAAI,WAAW,KAAK,KAAK,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;CACF,CAAA;AAlBY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAEoB,gBAAS;GAD7B,YAAY,CAkBxB"}

View File

@ -1,7 +0,0 @@
import { CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
export declare class RolesGuard implements CanActivate {
private reflector;
constructor(reflector: Reflector);
canActivate(context: ExecutionContext): boolean;
}

View File

@ -1,37 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RolesGuard = void 0;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const roles_decorator_1 = require("../decorators/roles.decorator");
let RolesGuard = class RolesGuard {
constructor(reflector) {
this.reflector = reflector;
}
canActivate(context) {
const requiredRoles = this.reflector.getAllAndOverride(roles_decorator_1.ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user?.role === role);
}
};
exports.RolesGuard = RolesGuard;
exports.RolesGuard = RolesGuard = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [core_1.Reflector])
], RolesGuard);
//# sourceMappingURL=roles.guard.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"roles.guard.js","sourceRoot":"","sources":["../../../../../src/modules/common/guards/roles.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA2E;AAC3E,uCAAyC;AACzC,mEAA0D;AAGnD,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,YAAoB,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAE5C,WAAW,CAAC,OAAyB;QACnC,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAW,2BAAS,EAAE;YAC1E,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QAGH,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAGrD,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC;IAC3D,CAAC;CACF,CAAA;AAnBY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;qCAEoB,gBAAS;GAD7B,UAAU,CAmBtB"}

View File

@ -1,13 +0,0 @@
import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { PrismaService } from '../../../database/prisma.service';
export declare class LogInterceptor implements NestInterceptor {
private reflector;
private prisma;
private readonly logger;
constructor(reflector: Reflector, prisma: PrismaService);
intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
private saveLog;
private getIpAddress;
}

View File

@ -1,115 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var LogInterceptor_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogInterceptor = void 0;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const rxjs_1 = require("rxjs");
const prisma_service_1 = require("../../../database/prisma.service");
const log_operation_decorator_1 = require("../decorators/log-operation.decorator");
let LogInterceptor = LogInterceptor_1 = class LogInterceptor {
constructor(reflector, prisma) {
this.reflector = reflector;
this.prisma = prisma;
this.logger = new common_1.Logger(LogInterceptor_1.name);
}
intercept(context, next) {
const logOptions = this.reflector.getAllAndOverride(log_operation_decorator_1.LOG_OPERATION_KEY, [context.getHandler(), context.getClass()]);
if (!logOptions) {
return next.handle();
}
const request = context.switchToHttp().getRequest();
const user = request.user;
const startTime = Date.now();
const body = request.body;
const params = request.params;
return next.handle().pipe((0, rxjs_1.tap)({
next: (response) => {
this.saveLog({
user,
logOptions,
body,
params,
response,
ipAddress: this.getIpAddress(request),
userAgent: request.headers['user-agent'],
duration: Date.now() - startTime,
});
},
error: (error) => {
this.saveLog({
user,
logOptions,
body,
params,
response: { error: error.message },
ipAddress: this.getIpAddress(request),
userAgent: request.headers['user-agent'],
duration: Date.now() - startTime,
isError: true,
});
},
}));
}
async saveLog(data) {
try {
const { user, logOptions, body, params, response, ipAddress, userAgent } = data;
let targetId;
if (params?.id) {
targetId = parseInt(params.id, 10);
}
else if (response?.id) {
targetId = response.id;
}
else if (body?.id) {
targetId = body.id;
}
let description = logOptions.description;
if (data.isError) {
description = `[失败] ${description}`;
}
await this.prisma.operationLog.create({
data: {
tenantId: user?.tenantId || null,
userId: user?.userId || 0,
userType: user?.role || 'UNKNOWN',
action: logOptions.action,
module: logOptions.module,
description,
targetId,
oldValue: body ? JSON.stringify(body) : null,
newValue: response ? JSON.stringify(response) : null,
ipAddress,
userAgent,
},
});
this.logger.debug(`Operation logged: ${logOptions.module} - ${logOptions.action} (${data.duration}ms)`);
}
catch (error) {
this.logger.error('Failed to save operation log:', error);
}
}
getIpAddress(request) {
return (request.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
request.headers['x-real-ip'] ||
request.connection?.remoteAddress ||
request.socket?.remoteAddress ||
'unknown');
}
};
exports.LogInterceptor = LogInterceptor;
exports.LogInterceptor = LogInterceptor = LogInterceptor_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [core_1.Reflector,
prisma_service_1.PrismaService])
], LogInterceptor);
//# sourceMappingURL=log.interceptor.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"log.interceptor.js","sourceRoot":"","sources":["../../../../../src/modules/common/interceptors/log.interceptor.ts"],"names":[],"mappings":"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"}

View File

@ -1,101 +0,0 @@
import { OperationLogService } from './operation-log.service';
export declare class SchoolOperationLogController {
private readonly logService;
constructor(logService: OperationLogService);
getLogs(req: any, query: any): Promise<{
items: {
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
oldValue: string | null;
newValue: string | null;
}[];
total: number;
page: number;
pageSize: number;
}>;
getStats(req: any, query: any): Promise<{
modules: {
name: string;
count: number;
}[];
actions: {
name: string;
count: number;
}[];
total: number;
}>;
getLogById(req: any, id: string): Promise<{
oldValue: any;
newValue: any;
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
}>;
}
export declare class AdminOperationLogController {
private readonly logService;
constructor(logService: OperationLogService);
getLogs(query: any): Promise<{
items: {
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
oldValue: string | null;
newValue: string | null;
}[];
total: number;
page: number;
pageSize: number;
}>;
getStats(query: any): Promise<{
modules: {
name: string;
count: number;
}[];
actions: {
name: string;
count: number;
}[];
total: number;
}>;
getLogById(id: string): Promise<{
oldValue: any;
newValue: any;
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
}>;
}

View File

@ -1,108 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminOperationLogController = exports.SchoolOperationLogController = void 0;
const common_1 = require("@nestjs/common");
const operation_log_service_1 = require("./operation-log.service");
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
const roles_guard_1 = require("./guards/roles.guard");
const roles_decorator_1 = require("./decorators/roles.decorator");
let SchoolOperationLogController = class SchoolOperationLogController {
constructor(logService) {
this.logService = logService;
}
getLogs(req, query) {
return this.logService.getLogs(req.user.tenantId, query);
}
getStats(req, query) {
return this.logService.getModuleStats(req.user.tenantId, query.startDate, query.endDate);
}
getLogById(req, id) {
return this.logService.getLogById(req.user.tenantId, +id);
}
};
exports.SchoolOperationLogController = SchoolOperationLogController;
__decorate([
(0, common_1.Get)('operation-logs'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], SchoolOperationLogController.prototype, "getLogs", null);
__decorate([
(0, common_1.Get)('operation-logs/stats'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], SchoolOperationLogController.prototype, "getStats", null);
__decorate([
(0, common_1.Get)('operation-logs/:id'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String]),
__metadata("design:returntype", void 0)
], SchoolOperationLogController.prototype, "getLogById", null);
exports.SchoolOperationLogController = SchoolOperationLogController = __decorate([
(0, common_1.Controller)('school'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('school'),
__metadata("design:paramtypes", [operation_log_service_1.OperationLogService])
], SchoolOperationLogController);
let AdminOperationLogController = class AdminOperationLogController {
constructor(logService) {
this.logService = logService;
}
getLogs(query) {
return this.logService.getLogs(null, query);
}
getStats(query) {
return this.logService.getModuleStats(null, query.startDate, query.endDate);
}
getLogById(id) {
return this.logService.getLogById(null, +id);
}
};
exports.AdminOperationLogController = AdminOperationLogController;
__decorate([
(0, common_1.Get)('operation-logs'),
__param(0, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminOperationLogController.prototype, "getLogs", null);
__decorate([
(0, common_1.Get)('operation-logs/stats'),
__param(0, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminOperationLogController.prototype, "getStats", null);
__decorate([
(0, common_1.Get)('operation-logs/:id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminOperationLogController.prototype, "getLogById", null);
exports.AdminOperationLogController = AdminOperationLogController = __decorate([
(0, common_1.Controller)('admin'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('admin'),
__metadata("design:paramtypes", [operation_log_service_1.OperationLogService])
], AdminOperationLogController);
//# sourceMappingURL=operation-log.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"operation-log.controller.js","sourceRoot":"","sources":["../../../../src/modules/common/operation-log.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAOwB;AACxB,mEAA8D;AAC9D,4DAAuD;AACvD,sDAAkD;AAClD,kEAAqD;AAK9C,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IACvC,YAA6B,UAA+B;QAA/B,eAAU,GAAV,UAAU,CAAqB;IAAG,CAAC;IAGhE,OAAO,CAAY,GAAQ,EAAW,KAAU;QAC9C,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAGD,QAAQ,CAAY,GAAQ,EAAW,KAAU;QAC/C,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3F,CAAC;IAGD,UAAU,CAAY,GAAQ,EAAe,EAAU;QACrD,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF,CAAA;AAjBY,oEAA4B;AAIvC;IADC,IAAA,YAAG,EAAC,gBAAgB,CAAC;IACb,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,cAAK,GAAE,CAAA;;;;2DAEpC;AAGD;IADC,IAAA,YAAG,EAAC,sBAAsB,CAAC;IAClB,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,cAAK,GAAE,CAAA;;;;4DAErC;AAGD;IADC,IAAA,YAAG,EAAC,oBAAoB,CAAC;IACd,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;8DAE3C;uCAhBU,4BAA4B;IAHxC,IAAA,mBAAU,EAAC,QAAQ,CAAC;IACpB,IAAA,kBAAS,EAAC,6BAAY,EAAE,wBAAU,CAAC;IACnC,IAAA,uBAAK,EAAC,QAAQ,CAAC;qCAE2B,2CAAmB;GADjD,4BAA4B,CAiBxC;AAKM,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACtC,YAA6B,UAA+B;QAA/B,eAAU,GAAV,UAAU,CAAqB;IAAG,CAAC;IAGhE,OAAO,CAAU,KAAU;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAGD,QAAQ,CAAU,KAAU;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9E,CAAC;IAGD,UAAU,CAAc,EAAU;QAChC,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;CACF,CAAA;AAjBY,kEAA2B;AAItC;IADC,IAAA,YAAG,EAAC,gBAAgB,CAAC;IACb,WAAA,IAAA,cAAK,GAAE,CAAA;;;;0DAEf;AAGD;IADC,IAAA,YAAG,EAAC,sBAAsB,CAAC;IAClB,WAAA,IAAA,cAAK,GAAE,CAAA;;;;2DAEhB;AAGD;IADC,IAAA,YAAG,EAAC,oBAAoB,CAAC;IACd,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;6DAEtB;sCAhBU,2BAA2B;IAHvC,IAAA,mBAAU,EAAC,OAAO,CAAC;IACnB,IAAA,kBAAS,EAAC,6BAAY,EAAE,wBAAU,CAAC;IACnC,IAAA,uBAAK,EAAC,OAAO,CAAC;qCAE4B,2CAAmB;GADjD,2BAA2B,CAiBvC"}

View File

@ -1,62 +0,0 @@
import { PrismaService } from '../../database/prisma.service';
export declare class OperationLogService {
private prisma;
private readonly logger;
constructor(prisma: PrismaService);
getLogs(tenantId: number | null, query: {
page?: number;
pageSize?: number;
userId?: number;
userType?: string;
action?: string;
module?: string;
startDate?: string;
endDate?: string;
}): Promise<{
items: {
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
oldValue: string | null;
newValue: string | null;
}[];
total: number;
page: number;
pageSize: number;
}>;
getLogById(tenantId: number | null, id: number): Promise<{
oldValue: any;
newValue: any;
id: number;
tenantId: number | null;
description: string;
createdAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: number;
userType: string;
action: string;
module: string;
targetId: number | null;
}>;
getModuleStats(tenantId: number | null, startDate?: string, endDate?: string): Promise<{
modules: {
name: string;
count: number;
}[];
actions: {
name: string;
count: number;
}[];
total: number;
}>;
private safeParseJson;
}

View File

@ -1,134 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var OperationLogService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OperationLogService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../database/prisma.service");
let OperationLogService = OperationLogService_1 = class OperationLogService {
constructor(prisma) {
this.prisma = prisma;
this.logger = new common_1.Logger(OperationLogService_1.name);
}
async getLogs(tenantId, query) {
const { page = 1, pageSize = 20, userId, userType, action, module, startDate, endDate, } = query;
const skip = (page - 1) * pageSize;
const take = +pageSize;
const where = {};
if (tenantId !== null) {
where.tenantId = tenantId;
}
if (userId) {
where.userId = userId;
}
if (userType) {
where.userType = userType;
}
if (action) {
where.action = action;
}
if (module) {
where.module = module;
}
if (startDate || endDate) {
where.createdAt = {};
if (startDate) {
where.createdAt.gte = new Date(startDate);
}
if (endDate) {
where.createdAt.lte = new Date(endDate);
}
}
const [items, total] = await Promise.all([
this.prisma.operationLog.findMany({
where,
skip,
take,
orderBy: { createdAt: 'desc' },
}),
this.prisma.operationLog.count({ where }),
]);
return {
items,
total,
page: +page,
pageSize: +pageSize,
};
}
async getLogById(tenantId, id) {
const where = { id };
if (tenantId !== null) {
where.tenantId = tenantId;
}
const log = await this.prisma.operationLog.findFirst({
where,
});
if (!log) {
return null;
}
return {
...log,
oldValue: log.oldValue ? this.safeParseJson(log.oldValue) : null,
newValue: log.newValue ? this.safeParseJson(log.newValue) : null,
};
}
async getModuleStats(tenantId, startDate, endDate) {
const where = {};
if (tenantId !== null) {
where.tenantId = tenantId;
}
if (startDate || endDate) {
where.createdAt = {};
if (startDate) {
where.createdAt.gte = new Date(startDate);
}
if (endDate) {
where.createdAt.lte = new Date(endDate);
}
}
const logs = await this.prisma.operationLog.findMany({
where,
select: {
module: true,
action: true,
},
});
const moduleStats = new Map();
const actionStats = new Map();
logs.forEach((log) => {
moduleStats.set(log.module, (moduleStats.get(log.module) || 0) + 1);
actionStats.set(log.action, (actionStats.get(log.action) || 0) + 1);
});
return {
modules: Array.from(moduleStats.entries())
.map(([name, count]) => ({ name, count }))
.sort((a, b) => b.count - a.count),
actions: Array.from(actionStats.entries())
.map(([name, count]) => ({ name, count }))
.sort((a, b) => b.count - a.count),
total: logs.length,
};
}
safeParseJson(str) {
try {
return JSON.parse(str);
}
catch {
return str;
}
}
};
exports.OperationLogService = OperationLogService;
exports.OperationLogService = OperationLogService = OperationLogService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], OperationLogService);
//# sourceMappingURL=operation-log.service.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"operation-log.service.js","sourceRoot":"","sources":["../../../../src/modules/common/operation-log.service.ts"],"names":[],"mappings":"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"}

View File

@ -1,42 +0,0 @@
export interface ValidationResult {
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
}
export interface ValidationError {
field: string;
message: string;
code: string;
}
export interface ValidationWarning {
field: string;
message: string;
code: string;
}
export interface CourseValidationData {
name?: string;
description?: string;
coverImagePath?: string;
gradeTags?: string;
domainTags?: string;
duration?: number;
ebookPaths?: string;
audioPaths?: string;
videoPaths?: string;
otherResources?: string;
scripts?: any[];
lessonPlanData?: string;
}
export declare class CourseValidationService {
private readonly logger;
validateForSubmit(course: CourseValidationData): Promise<ValidationResult>;
private validateBasicInfo;
private validateCover;
private validateGradeTags;
private validateDuration;
private validateResources;
private validateScripts;
private hasValidJsonArray;
canSubmit(course: CourseValidationData): Promise<boolean>;
getValidationSummary(result: ValidationResult): string;
}

View File

@ -1,190 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var CourseValidationService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseValidationService = void 0;
const common_1 = require("@nestjs/common");
let CourseValidationService = CourseValidationService_1 = class CourseValidationService {
constructor() {
this.logger = new common_1.Logger(CourseValidationService_1.name);
}
async validateForSubmit(course) {
const errors = [];
const warnings = [];
this.validateBasicInfo(course, errors);
this.validateCover(course, errors);
this.validateGradeTags(course, errors);
this.validateDuration(course, errors);
this.validateResources(course, warnings);
this.validateScripts(course, errors);
const result = {
valid: errors.length === 0,
errors,
warnings,
};
this.logger.log(`Validation result: valid=${result.valid}, errors=${errors.length}, warnings=${warnings.length}`);
return result;
}
validateBasicInfo(course, errors) {
if (!course.name || course.name.trim().length === 0) {
errors.push({
field: 'name',
message: '请输入课程名称',
code: 'NAME_REQUIRED',
});
}
else if (course.name.length < 2) {
errors.push({
field: 'name',
message: '课程名称至少需要2个字符',
code: 'NAME_TOO_SHORT',
});
}
else if (course.name.length > 50) {
errors.push({
field: 'name',
message: '课程名称不能超过50个字符',
code: 'NAME_TOO_LONG',
});
}
}
validateCover(course, errors) {
if (!course.coverImagePath) {
errors.push({
field: 'coverImagePath',
message: '请上传课程封面',
code: 'COVER_REQUIRED',
});
}
}
validateGradeTags(course, errors) {
if (!course.gradeTags) {
errors.push({
field: 'gradeTags',
message: '请选择适用年级',
code: 'GRADE_REQUIRED',
});
return;
}
try {
const grades = JSON.parse(course.gradeTags);
if (!Array.isArray(grades) || grades.length === 0) {
errors.push({
field: 'gradeTags',
message: '请至少选择一个适用年级',
code: 'GRADE_EMPTY',
});
}
}
catch {
errors.push({
field: 'gradeTags',
message: '年级标签格式错误',
code: 'GRADE_FORMAT_ERROR',
});
}
}
validateDuration(course, errors) {
if (course.duration === undefined || course.duration === null) {
errors.push({
field: 'duration',
message: '请设置课程时长',
code: 'DURATION_REQUIRED',
});
return;
}
if (course.duration < 5) {
errors.push({
field: 'duration',
message: '课程时长不能少于5分钟',
code: 'DURATION_TOO_SHORT',
});
}
else if (course.duration > 60) {
errors.push({
field: 'duration',
message: '课程时长不能超过60分钟',
code: 'DURATION_TOO_LONG',
});
}
}
validateResources(course, warnings) {
const hasEbook = this.hasValidJsonArray(course.ebookPaths);
const hasAudio = this.hasValidJsonArray(course.audioPaths);
const hasVideo = this.hasValidJsonArray(course.videoPaths);
const hasOther = this.hasValidJsonArray(course.otherResources);
if (!hasEbook && !hasAudio && !hasVideo && !hasOther) {
warnings.push({
field: 'resources',
message: '建议上传至少1个数字资源电子绘本、音频或视频',
code: 'RESOURCES_SUGGESTED',
});
}
}
validateScripts(course, errors) {
if (course.lessonPlanData) {
try {
const lessonPlan = JSON.parse(course.lessonPlanData);
if (!lessonPlan.phases || !Array.isArray(lessonPlan.phases) || lessonPlan.phases.length === 0) {
errors.push({
field: 'lessonPlanData',
message: '请至少配置一个教学环节',
code: 'SCRIPTS_REQUIRED',
});
}
return;
}
catch {
errors.push({
field: 'lessonPlanData',
message: '教学计划数据格式错误',
code: 'LESSON_PLAN_FORMAT_ERROR',
});
return;
}
}
if (course.scripts !== undefined) {
if (!Array.isArray(course.scripts) || course.scripts.length === 0) {
errors.push({
field: 'scripts',
message: '请至少配置一个教学环节',
code: 'SCRIPTS_REQUIRED',
});
}
}
}
hasValidJsonArray(jsonStr) {
if (!jsonStr)
return false;
try {
const arr = JSON.parse(jsonStr);
return Array.isArray(arr) && arr.length > 0;
}
catch {
return false;
}
}
async canSubmit(course) {
const result = await this.validateForSubmit(course);
return result.valid;
}
getValidationSummary(result) {
if (result.valid && result.warnings.length === 0) {
return '课程内容完整,可以提交审核';
}
if (result.valid && result.warnings.length > 0) {
return `课程可以提交,但有 ${result.warnings.length} 条建议`;
}
return `课程有 ${result.errors.length} 个问题需要修复`;
}
};
exports.CourseValidationService = CourseValidationService;
exports.CourseValidationService = CourseValidationService = CourseValidationService_1 = __decorate([
(0, common_1.Injectable)()
], CourseValidationService);
//# sourceMappingURL=course-validation.service.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,625 +0,0 @@
import { CourseService } from './course.service';
export declare class CourseController {
private readonly courseService;
constructor(courseService: CourseService);
findAll(query: any): Promise<{
items: {
id: number;
status: string;
createdAt: Date;
name: string;
pictureBookName: string;
gradeTags: string;
version: string;
submittedAt: Date;
reviewedAt: Date;
reviewComment: string;
usageCount: number;
teacherCount: number;
avgRating: number;
}[];
total: number;
page: number;
pageSize: number;
}>;
getReviewList(query: any): Promise<{
items: {
id: number;
status: string;
name: string;
coverImagePath: string;
gradeTags: string;
submittedAt: Date;
submittedBy: number;
reviewedAt: Date;
reviewedBy: number;
reviewComment: string;
}[];
total: number;
page: number;
pageSize: number;
}>;
findOne(id: string): Promise<{
resources: {
id: number;
createdAt: Date;
sortOrder: number;
courseId: number;
resourceType: string;
resourceName: string;
fileUrl: string;
fileSize: number | null;
mimeType: string | null;
metadata: string | null;
}[];
scripts: ({
pages: {
id: number;
createdAt: Date;
updatedAt: Date;
resourceIds: string | null;
pageNumber: number;
scriptId: number;
questions: string | null;
interactionComponent: string | null;
teacherNotes: string | null;
}[];
} & {
id: number;
createdAt: Date;
updatedAt: Date;
duration: number;
sortOrder: number;
courseId: number;
stepIndex: number;
stepName: string;
stepType: string;
objective: string | null;
teacherScript: string | null;
interactionPoints: string | null;
resourceIds: string | null;
})[];
activities: {
id: number;
createdAt: Date;
name: string;
duration: number | null;
sortOrder: number;
courseId: number;
domain: string | null;
domainTagId: number | null;
activityType: string;
onlineMaterials: string | null;
offlineMaterials: string | null;
activityGuide: string | null;
objectives: string | null;
}[];
} & {
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
getStats(id: string): Promise<{
courseName: string;
totalLessons: number;
totalTeachers: number;
totalStudents: number;
avgRating: number;
lessonTrend: any[];
feedbackDistribution: {
designQuality: number;
participation: number;
goalAchievement: number;
totalFeedbacks: number;
};
recentLessons: any[];
studentPerformance: {
avgFocus: number;
avgParticipation: number;
avgInterest: number;
avgUnderstanding: number;
};
}>;
validate(id: string): Promise<import("./course-validation.service").ValidationResult>;
getVersionHistory(id: string): Promise<{
id: number;
version: string;
changeLog: string;
publishedAt: Date;
publishedBy: number;
}[]>;
create(createCourseDto: any, req: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
update(id: string, updateCourseDto: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
remove(id: string): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
submit(id: string, body: {
copyrightConfirmed: boolean;
}, req: any): Promise<{
validationSummary: string;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
withdraw(id: string, req: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
approve(id: string, body: {
checklist?: any;
comment?: string;
}, req: any): Promise<{
authorizedTenantCount: number;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
reject(id: string, body: {
checklist?: any;
comment: string;
}, req: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
directPublish(id: string, body: {
skipValidation?: boolean;
}, req: any): Promise<{
authorizedTenantCount: number;
validationSkipped: boolean;
validationWarnings: import("./course-validation.service").ValidationWarning[];
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
publish(id: string): Promise<{
authorizedTenantCount: number;
validationSkipped: boolean;
validationWarnings: import("./course-validation.service").ValidationWarning[];
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
unpublish(id: string): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
republish(id: string): Promise<{
authorizedTenantCount: number;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
}

View File

@ -1,223 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseController = void 0;
const common_1 = require("@nestjs/common");
const course_service_1 = require("./course.service");
const jwt_auth_guard_1 = require("../common/guards/jwt-auth.guard");
const roles_guard_1 = require("../common/guards/roles.guard");
const roles_decorator_1 = require("../common/decorators/roles.decorator");
let CourseController = class CourseController {
constructor(courseService) {
this.courseService = courseService;
}
findAll(query) {
return this.courseService.findAll(query);
}
getReviewList(query) {
return this.courseService.getReviewList(query);
}
findOne(id) {
return this.courseService.findOne(+id);
}
getStats(id) {
return this.courseService.getStats(+id);
}
validate(id) {
return this.courseService.validate(+id);
}
getVersionHistory(id) {
return this.courseService.getVersionHistory(+id);
}
create(createCourseDto, req) {
return this.courseService.create({
...createCourseDto,
createdBy: req.user?.userId,
});
}
update(id, updateCourseDto) {
return this.courseService.update(+id, updateCourseDto);
}
remove(id) {
return this.courseService.remove(+id);
}
submit(id, body, req) {
const userId = req.user?.userId || 0;
return this.courseService.submit(+id, userId, body.copyrightConfirmed);
}
withdraw(id, req) {
const userId = req.user?.userId || 0;
return this.courseService.withdraw(+id, userId);
}
approve(id, body, req) {
const reviewerId = req.user?.userId || 0;
return this.courseService.approve(+id, reviewerId, body);
}
reject(id, body, req) {
const reviewerId = req.user?.userId || 0;
return this.courseService.reject(+id, reviewerId, body);
}
directPublish(id, body, req) {
const userId = req.user?.userId || 0;
return this.courseService.directPublish(+id, userId, body.skipValidation);
}
publish(id) {
return this.courseService.publish(+id);
}
unpublish(id) {
return this.courseService.unpublish(+id);
}
republish(id) {
return this.courseService.republish(+id);
}
};
exports.CourseController = CourseController;
__decorate([
(0, common_1.Get)(),
__param(0, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)('review'),
__param(0, (0, common_1.Query)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "getReviewList", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "findOne", null);
__decorate([
(0, common_1.Get)(':id/stats'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "getStats", null);
__decorate([
(0, common_1.Get)(':id/validate'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "validate", null);
__decorate([
(0, common_1.Get)(':id/versions'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "getVersionHistory", null);
__decorate([
(0, common_1.Post)(),
__param(0, (0, common_1.Body)()),
__param(1, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "create", null);
__decorate([
(0, common_1.Put)(':id'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "update", null);
__decorate([
(0, common_1.Delete)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "remove", null);
__decorate([
(0, common_1.Post)(':id/submit'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "submit", null);
__decorate([
(0, common_1.Post)(':id/withdraw'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "withdraw", null);
__decorate([
(0, common_1.Post)(':id/approve'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "approve", null);
__decorate([
(0, common_1.Post)(':id/reject'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "reject", null);
__decorate([
(0, common_1.Post)(':id/direct-publish'),
(0, roles_decorator_1.Roles)('admin'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Request)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "directPublish", null);
__decorate([
(0, common_1.Post)(':id/publish'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "publish", null);
__decorate([
(0, common_1.Post)(':id/unpublish'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "unpublish", null);
__decorate([
(0, common_1.Post)(':id/republish'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], CourseController.prototype, "republish", null);
exports.CourseController = CourseController = __decorate([
(0, common_1.Controller)('courses'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('admin'),
__metadata("design:paramtypes", [course_service_1.CourseService])
], CourseController);
//# sourceMappingURL=course.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"course.controller.js","sourceRoot":"","sources":["../../../../src/modules/course/course.controller.ts"],"names":[],"mappings":"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"}

View File

@ -1,2 +0,0 @@
export declare class CourseModule {
}

View File

@ -1,26 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseModule = void 0;
const common_1 = require("@nestjs/common");
const course_controller_1 = require("./course.controller");
const course_service_1 = require("./course.service");
const course_validation_service_1 = require("./course-validation.service");
const prisma_module_1 = require("../../database/prisma.module");
let CourseModule = class CourseModule {
};
exports.CourseModule = CourseModule;
exports.CourseModule = CourseModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule],
controllers: [course_controller_1.CourseController],
providers: [course_service_1.CourseService, course_validation_service_1.CourseValidationService],
exports: [course_service_1.CourseService, course_validation_service_1.CourseValidationService],
})
], CourseModule);
//# sourceMappingURL=course.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"course.module.js","sourceRoot":"","sources":["../../../../src/modules/course/course.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,qDAAiD;AACjD,2EAAsE;AACtE,gEAA4D;AAQrD,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IANxB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,CAAC,8BAAa,EAAE,mDAAuB,CAAC;QACnD,OAAO,EAAE,CAAC,8BAAa,EAAE,mDAAuB,CAAC;KAClD,CAAC;GACW,YAAY,CAAG"}

View File

@ -1,627 +0,0 @@
import { PrismaService } from '../../database/prisma.service';
import { CourseValidationService, ValidationResult } from './course-validation.service';
export declare class CourseService {
private prisma;
private validationService;
private readonly logger;
constructor(prisma: PrismaService, validationService: CourseValidationService);
findAll(query: any): Promise<{
items: {
id: number;
status: string;
createdAt: Date;
name: string;
pictureBookName: string;
gradeTags: string;
version: string;
submittedAt: Date;
reviewedAt: Date;
reviewComment: string;
usageCount: number;
teacherCount: number;
avgRating: number;
}[];
total: number;
page: number;
pageSize: number;
}>;
findOne(id: number): Promise<{
resources: {
id: number;
createdAt: Date;
sortOrder: number;
courseId: number;
resourceType: string;
resourceName: string;
fileUrl: string;
fileSize: number | null;
mimeType: string | null;
metadata: string | null;
}[];
scripts: ({
pages: {
id: number;
createdAt: Date;
updatedAt: Date;
resourceIds: string | null;
pageNumber: number;
scriptId: number;
questions: string | null;
interactionComponent: string | null;
teacherNotes: string | null;
}[];
} & {
id: number;
createdAt: Date;
updatedAt: Date;
duration: number;
sortOrder: number;
courseId: number;
stepIndex: number;
stepName: string;
stepType: string;
objective: string | null;
teacherScript: string | null;
interactionPoints: string | null;
resourceIds: string | null;
})[];
activities: {
id: number;
createdAt: Date;
name: string;
duration: number | null;
sortOrder: number;
courseId: number;
domain: string | null;
domainTagId: number | null;
activityType: string;
onlineMaterials: string | null;
offlineMaterials: string | null;
activityGuide: string | null;
objectives: string | null;
}[];
} & {
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
create(createCourseDto: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
update(id: number, updateCourseDto: any): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
private syncLessonPlanToScripts;
private syncActivitiesToTable;
private mapActivityType;
remove(id: number): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
validate(id: number): Promise<ValidationResult>;
submit(id: number, userId: number, copyrightConfirmed: boolean): Promise<{
validationSummary: string;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
withdraw(id: number, userId: number): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
approve(id: number, reviewerId: number, reviewData: {
checklist?: any;
comment?: string;
}): Promise<{
authorizedTenantCount: number;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
reject(id: number, reviewerId: number, reviewData: {
checklist?: any;
comment: string;
}): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
directPublish(id: number, userId: number, skipValidation?: boolean): Promise<{
authorizedTenantCount: number;
validationSkipped: boolean;
validationWarnings: import("./course-validation.service").ValidationWarning[];
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
publish(id: number): Promise<{
authorizedTenantCount: number;
validationSkipped: boolean;
validationWarnings: import("./course-validation.service").ValidationWarning[];
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
unpublish(id: number): Promise<{
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
republish(id: number): Promise<{
authorizedTenantCount: number;
id: number;
description: string | null;
createdBy: number | null;
status: string;
createdAt: Date;
updatedAt: Date;
name: string;
pictureBookId: number | null;
pictureBookName: string | null;
coverImagePath: string | null;
ebookPaths: string | null;
audioPaths: string | null;
videoPaths: string | null;
otherResources: string | null;
pptPath: string | null;
pptName: string | null;
posterPaths: string | null;
tools: string | null;
studentMaterials: string | null;
lessonPlanData: string | null;
activitiesData: string | null;
assessmentData: string | null;
gradeTags: string;
domainTags: string;
duration: number;
version: string;
submittedAt: Date | null;
submittedBy: number | null;
reviewedAt: Date | null;
reviewedBy: number | null;
reviewComment: string | null;
reviewChecklist: string | null;
parentId: number | null;
isLatest: boolean;
usageCount: number;
teacherCount: number;
avgRating: number;
publishedAt: Date | null;
}>;
getStats(id: number): Promise<{
courseName: string;
totalLessons: number;
totalTeachers: number;
totalStudents: number;
avgRating: number;
lessonTrend: any[];
feedbackDistribution: {
designQuality: number;
participation: number;
goalAchievement: number;
totalFeedbacks: number;
};
recentLessons: any[];
studentPerformance: {
avgFocus: number;
avgParticipation: number;
avgInterest: number;
avgUnderstanding: number;
};
}>;
getReviewList(query: any): Promise<{
items: {
id: number;
status: string;
name: string;
coverImagePath: string;
gradeTags: string;
submittedAt: Date;
submittedBy: number;
reviewedAt: Date;
reviewedBy: number;
reviewComment: string;
}[];
total: number;
page: number;
pageSize: number;
}>;
getVersionHistory(id: number): Promise<{
id: number;
version: string;
changeLog: string;
publishedAt: Date;
publishedBy: number;
}[]>;
}

View File

@ -1,750 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var CourseService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../database/prisma.service");
const course_validation_service_1 = require("./course-validation.service");
let CourseService = CourseService_1 = class CourseService {
constructor(prisma, validationService) {
this.prisma = prisma;
this.validationService = validationService;
this.logger = new common_1.Logger(CourseService_1.name);
}
async findAll(query) {
const { page = 1, pageSize = 10, grade, status, keyword } = query;
const skip = (page - 1) * pageSize;
const take = +pageSize;
const where = {};
if (status) {
where.status = status;
}
if (keyword) {
where.name = { contains: keyword };
}
if (grade) {
const gradeUpper = grade.toUpperCase();
where.OR = [
{ gradeTags: { contains: gradeUpper } },
{ gradeTags: { contains: grade.toLowerCase() } },
];
}
const [items, total] = await Promise.all([
this.prisma.course.findMany({
where,
skip,
take,
orderBy: { createdAt: 'desc' },
select: {
id: true,
name: true,
pictureBookName: true,
gradeTags: true,
status: true,
version: true,
usageCount: true,
teacherCount: true,
avgRating: true,
createdAt: true,
submittedAt: true,
reviewedAt: true,
reviewComment: true,
},
}),
this.prisma.course.count({ where }),
]);
return {
items,
total,
page: +page,
pageSize: +pageSize,
};
}
async findOne(id) {
const course = await this.prisma.course.findUnique({
where: { id },
include: {
resources: {
orderBy: { sortOrder: 'asc' },
},
scripts: {
orderBy: { sortOrder: 'asc' },
include: {
pages: {
orderBy: { pageNumber: 'asc' },
},
},
},
activities: {
orderBy: { sortOrder: 'asc' },
},
},
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
return course;
}
async create(createCourseDto) {
try {
this.logger.log(`Creating course with data: ${JSON.stringify(createCourseDto)}`);
const result = await this.prisma.course.create({
data: createCourseDto,
});
this.logger.log(`Course created successfully with ID: ${result.id}`);
return result;
}
catch (error) {
this.logger.error(`Error creating course: ${error.message}`, error.stack);
throw error;
}
}
async update(id, updateCourseDto) {
const fieldsToClear = [
'coverImagePath',
'ebookPaths',
'audioPaths',
'videoPaths',
'otherResources',
'pptPath',
'pptName',
'posterPaths',
'tools',
'studentMaterials',
'pictureBookName',
'lessonPlanData',
'activitiesData',
'assessmentData',
];
const cleanedData = {};
for (const [key, value] of Object.entries(updateCourseDto)) {
if (fieldsToClear.includes(key) && (value === null || value === '')) {
cleanedData[key] = null;
}
else if (value !== undefined) {
cleanedData[key] = value;
}
}
this.logger.log(`Updating course ${id} with data: ${JSON.stringify(Object.keys(cleanedData))}`);
return this.prisma.$transaction(async (tx) => {
const updatedCourse = await tx.course.update({
where: { id },
data: cleanedData,
});
if (updateCourseDto.lessonPlanData !== undefined) {
await this.syncLessonPlanToScripts(tx, id, updateCourseDto.lessonPlanData);
}
if (updateCourseDto.activitiesData !== undefined) {
await this.syncActivitiesToTable(tx, id, updateCourseDto.activitiesData);
}
return updatedCourse;
});
}
async syncLessonPlanToScripts(tx, courseId, lessonPlanData) {
await tx.courseScriptPage.deleteMany({
where: { script: { courseId } },
});
await tx.courseScript.deleteMany({
where: { courseId },
});
if (!lessonPlanData) {
this.logger.log(`Course ${courseId}: lessonPlanData is null, cleared scripts`);
return;
}
try {
const lessonPlan = JSON.parse(lessonPlanData);
const phases = lessonPlan.phases || [];
const topLevelScriptPages = lessonPlan.scriptPages || [];
this.logger.log(`=== 同步课程 ${courseId} 的教学脚本 ===`);
this.logger.log(`phases 数量: ${phases.length}`);
this.logger.log(`顶层 scriptPages 数量: ${topLevelScriptPages.length}`);
for (let i = 0; i < phases.length; i++) {
const phase = phases[i];
this.logger.log(`Phase ${i}: name=${phase.name}, pages=${phase.pages?.length || 0}, enablePageScript=${phase.enablePageScript}`);
const script = await tx.courseScript.create({
data: {
courseId,
stepIndex: i + 1,
stepName: phase.name || `步骤${i + 1}`,
stepType: phase.type || 'CUSTOM',
duration: phase.duration || 5,
objective: phase.objective || null,
teacherScript: phase.content || null,
interactionPoints: null,
resourceIds: phase.resourceIds ? JSON.stringify(phase.resourceIds) : null,
sortOrder: i,
},
});
let pagesToCreate = phase.pages || [];
if (pagesToCreate.length === 0 && topLevelScriptPages.length > 0 && i === 0) {
pagesToCreate = topLevelScriptPages;
}
if (pagesToCreate.length > 0) {
this.logger.log(`为 Phase ${i} 创建 ${pagesToCreate.length} 页逐页脚本`);
for (const page of pagesToCreate) {
await tx.courseScriptPage.create({
data: {
scriptId: script.id,
pageNumber: page.pageNumber,
questions: page.teacherScript || null,
interactionComponent: page.actions ? JSON.stringify(page.actions) : null,
teacherNotes: page.notes || null,
resourceIds: page.resourceIds ? JSON.stringify(page.resourceIds) : null,
},
});
}
}
}
this.logger.log(`Course ${courseId}: synced ${phases.length} scripts from lessonPlanData`);
}
catch (error) {
this.logger.error(`Failed to sync lessonPlanData for course ${courseId}: ${error.message}`);
}
}
async syncActivitiesToTable(tx, courseId, activitiesData) {
await tx.courseActivity.deleteMany({
where: { courseId },
});
if (!activitiesData) {
this.logger.log(`Course ${courseId}: activitiesData is null, cleared activities`);
return;
}
try {
const activities = JSON.parse(activitiesData);
for (let i = 0; i < activities.length; i++) {
const activity = activities[i];
await tx.courseActivity.create({
data: {
courseId,
name: activity.name || `活动${i + 1}`,
domain: activity.domain || null,
domainTagId: null,
activityType: this.mapActivityType(activity.type),
duration: activity.duration || 15,
onlineMaterials: activity.content ? JSON.stringify({ content: activity.content }) : null,
offlineMaterials: activity.materials || null,
activityGuide: null,
objectives: null,
sortOrder: i,
},
});
}
this.logger.log(`Course ${courseId}: synced ${activities.length} activities from activitiesData`);
}
catch (error) {
this.logger.error(`Failed to sync activitiesData for course ${courseId}: ${error.message}`);
}
}
mapActivityType(type) {
const typeMap = {
'family': 'FAMILY',
'art': 'ART',
'game': 'GAME',
'outdoor': 'OUTDOOR',
'other': 'OTHER',
'handicraft': 'HANDICRAFT',
'music': 'MUSIC',
'exploration': 'EXPLORATION',
'sports': 'SPORTS',
'家庭延伸': 'FAMILY',
'美工活动': 'ART',
'游戏活动': 'GAME',
'户外活动': 'OUTDOOR',
'其他': 'OTHER',
'手工活动': 'HANDICRAFT',
'音乐活动': 'MUSIC',
'探索活动': 'EXPLORATION',
'运动活动': 'SPORTS',
'亲子活动': 'FAMILY',
};
return typeMap[type || ''] || 'OTHER';
}
async remove(id) {
return this.prisma.course.delete({
where: { id },
});
}
async validate(id) {
const course = await this.findOne(id);
return this.validationService.validateForSubmit(course);
}
async submit(id, userId, copyrightConfirmed) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'DRAFT' && course.status !== 'REJECTED') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法提交审核`);
}
const validationResult = await this.validationService.validateForSubmit(course);
if (!validationResult.valid) {
throw new common_1.BadRequestException({
message: '课程内容不完整,请检查以下问题',
errors: validationResult.errors,
warnings: validationResult.warnings,
});
}
if (!copyrightConfirmed) {
throw new common_1.BadRequestException('请确认版权合规');
}
const updatedCourse = await this.prisma.course.update({
where: { id },
data: {
status: 'PENDING',
submittedAt: new Date(),
submittedBy: userId,
},
});
this.logger.log(`Course ${id} submitted for review by user ${userId}`);
return {
...updatedCourse,
validationSummary: this.validationService.getValidationSummary(validationResult),
};
}
async withdraw(id, userId) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'PENDING') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法撤销`);
}
const updatedCourse = await this.prisma.course.update({
where: { id },
data: {
status: 'DRAFT',
submittedAt: null,
submittedBy: null,
},
});
this.logger.log(`Course ${id} review withdrawn by user ${userId}`);
return updatedCourse;
}
async approve(id, reviewerId, reviewData) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'PENDING') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法审核`);
}
if (course.submittedBy === reviewerId) {
throw new common_1.BadRequestException('不能审核自己提交的课程');
}
const result = await this.prisma.$transaction(async (tx) => {
const updatedCourse = await tx.course.update({
where: { id },
data: {
status: 'PUBLISHED',
reviewedAt: new Date(),
reviewedBy: reviewerId,
reviewComment: reviewData.comment || null,
reviewChecklist: reviewData.checklist ? JSON.stringify(reviewData.checklist) : null,
publishedAt: new Date(),
},
});
await tx.courseVersion.create({
data: {
courseId: id,
version: course.version,
snapshotData: JSON.stringify(course),
changeLog: reviewData.comment || '审核通过发布',
publishedBy: reviewerId,
},
});
return updatedCourse;
});
const activeTenants = await this.prisma.tenant.findMany({
where: { status: 'ACTIVE' },
select: { id: true },
});
this.logger.log(`Publishing course ${id} to ${activeTenants.length} active tenants`);
for (const tenant of activeTenants) {
await this.prisma.tenantCourse.upsert({
where: {
tenantId_courseId: {
tenantId: tenant.id,
courseId: id,
},
},
update: {
authorized: true,
authorizedAt: new Date(),
},
create: {
tenantId: tenant.id,
courseId: id,
authorized: true,
authorizedAt: new Date(),
},
});
}
this.logger.log(`Course ${id} approved and published by reviewer ${reviewerId}`);
return {
...result,
authorizedTenantCount: activeTenants.length,
};
}
async reject(id, reviewerId, reviewData) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'PENDING') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法审核`);
}
if (course.submittedBy === reviewerId) {
throw new common_1.BadRequestException('不能审核自己提交的课程');
}
if (!reviewData.comment || reviewData.comment.trim().length === 0) {
throw new common_1.BadRequestException('请填写驳回原因');
}
const updatedCourse = await this.prisma.course.update({
where: { id },
data: {
status: 'REJECTED',
reviewedAt: new Date(),
reviewedBy: reviewerId,
reviewComment: reviewData.comment,
reviewChecklist: reviewData.checklist ? JSON.stringify(reviewData.checklist) : null,
},
});
this.logger.log(`Course ${id} rejected by reviewer ${reviewerId}: ${reviewData.comment}`);
return updatedCourse;
}
async directPublish(id, userId, skipValidation = false) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status === 'PUBLISHED') {
throw new common_1.BadRequestException('课程已发布');
}
const validationResult = await this.validationService.validateForSubmit(course);
if (!skipValidation && !validationResult.valid) {
throw new common_1.BadRequestException({
message: '课程内容不完整,请检查以下问题',
errors: validationResult.errors,
warnings: validationResult.warnings,
});
}
const result = await this.prisma.$transaction(async (tx) => {
const updatedCourse = await tx.course.update({
where: { id },
data: {
status: 'PUBLISHED',
publishedAt: new Date(),
reviewedAt: new Date(),
reviewedBy: userId,
reviewComment: '超级管理员直接发布',
},
});
await tx.courseVersion.create({
data: {
courseId: id,
version: course.version,
snapshotData: JSON.stringify(course),
changeLog: '超级管理员直接发布',
publishedBy: userId,
},
});
return updatedCourse;
});
const activeTenants = await this.prisma.tenant.findMany({
where: { status: 'ACTIVE' },
select: { id: true },
});
for (const tenant of activeTenants) {
await this.prisma.tenantCourse.upsert({
where: {
tenantId_courseId: {
tenantId: tenant.id,
courseId: id,
},
},
update: {
authorized: true,
authorizedAt: new Date(),
},
create: {
tenantId: tenant.id,
courseId: id,
authorized: true,
authorizedAt: new Date(),
},
});
}
this.logger.log(`Course ${id} directly published by super admin ${userId}`);
return {
...result,
authorizedTenantCount: activeTenants.length,
validationSkipped: skipValidation && !validationResult.valid,
validationWarnings: validationResult.warnings,
};
}
async publish(id) {
return this.directPublish(id, 0, false);
}
async unpublish(id) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'PUBLISHED') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法下架`);
}
const updatedCourse = await this.prisma.course.update({
where: { id },
data: {
status: 'ARCHIVED',
},
});
await this.prisma.tenantCourse.updateMany({
where: { courseId: id },
data: {
authorized: false,
},
});
this.logger.log(`Course ${id} unpublished`);
return updatedCourse;
}
async republish(id) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
if (course.status !== 'ARCHIVED') {
throw new common_1.BadRequestException(`课程状态为 ${course.status},无法重新发布`);
}
const updatedCourse = await this.prisma.course.update({
where: { id },
data: {
status: 'PUBLISHED',
},
});
const activeTenants = await this.prisma.tenant.findMany({
where: { status: 'ACTIVE' },
select: { id: true },
});
for (const tenant of activeTenants) {
await this.prisma.tenantCourse.upsert({
where: {
tenantId_courseId: {
tenantId: tenant.id,
courseId: id,
},
},
update: {
authorized: true,
authorizedAt: new Date(),
},
create: {
tenantId: tenant.id,
courseId: id,
authorized: true,
authorizedAt: new Date(),
},
});
}
this.logger.log(`Course ${id} republished`);
return {
...updatedCourse,
authorizedTenantCount: activeTenants.length,
};
}
async getStats(id) {
const course = await this.prisma.course.findUnique({
where: { id },
select: {
id: true,
name: true,
usageCount: true,
teacherCount: true,
avgRating: true,
},
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
const lessons = await this.prisma.lesson.findMany({
where: { courseId: id },
include: {
teacher: {
select: { id: true, name: true },
},
class: {
select: { id: true, name: true },
},
},
orderBy: { createdAt: 'desc' },
take: 10,
});
const feedbacks = await this.prisma.lessonFeedback.findMany({
where: {
lesson: {
courseId: id,
},
},
});
const calculateAverage = (field) => {
const validFeedbacks = feedbacks.filter((f) => f[field] != null);
if (validFeedbacks.length === 0)
return 0;
const sum = validFeedbacks.reduce((acc, f) => acc + f[field], 0);
return sum / validFeedbacks.length;
};
const studentRecords = await this.prisma.studentRecord.findMany({
where: {
lesson: {
courseId: id,
},
},
});
const calculateStudentAvg = (field) => {
const validRecords = studentRecords.filter((r) => r[field] != null);
if (validRecords.length === 0)
return 0;
const sum = validRecords.reduce((acc, r) => acc + r[field], 0);
return sum / validRecords.length;
};
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const recentLessons = await this.prisma.lesson.findMany({
where: {
courseId: id,
createdAt: { gte: weekAgo },
},
select: {
createdAt: true,
},
});
const lessonTrend = [];
for (let i = 6; i >= 0; i--) {
const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
const dateStr = date.toLocaleDateString('zh-CN', { weekday: 'short' });
const count = recentLessons.filter((lesson) => {
const lessonDate = new Date(lesson.createdAt);
return lessonDate.toDateString() === date.toDateString();
}).length;
lessonTrend.push({ date: dateStr, count });
}
const uniqueStudentIds = new Set();
lessons.forEach((lesson) => {
uniqueStudentIds.add(lesson.classId);
});
return {
courseName: course.name,
totalLessons: course.usageCount || lessons.length,
totalTeachers: course.teacherCount || new Set(lessons.map((l) => l.teacherId)).size,
totalStudents: uniqueStudentIds.size,
avgRating: course.avgRating || 0,
lessonTrend,
feedbackDistribution: {
designQuality: calculateAverage('designQuality'),
participation: calculateAverage('participation'),
goalAchievement: calculateAverage('goalAchievement'),
totalFeedbacks: feedbacks.length,
},
recentLessons: lessons.map((lesson) => ({
...lesson,
date: lesson.createdAt,
})),
studentPerformance: {
avgFocus: calculateStudentAvg('focus'),
avgParticipation: calculateStudentAvg('participation'),
avgInterest: calculateStudentAvg('interest'),
avgUnderstanding: calculateStudentAvg('understanding'),
},
};
}
async getReviewList(query) {
const { page = 1, pageSize = 10, status, submittedBy } = query;
const skip = (page - 1) * pageSize;
const take = +pageSize;
const where = {
status: { in: ['PENDING', 'REJECTED'] },
};
if (status) {
where.status = status;
}
if (submittedBy) {
where.submittedBy = +submittedBy;
}
const [items, total] = await Promise.all([
this.prisma.course.findMany({
where,
skip,
take,
orderBy: { submittedAt: 'desc' },
select: {
id: true,
name: true,
status: true,
submittedAt: true,
submittedBy: true,
reviewedAt: true,
reviewedBy: true,
reviewComment: true,
coverImagePath: true,
gradeTags: true,
},
}),
this.prisma.course.count({ where }),
]);
return {
items,
total,
page: +page,
pageSize: +pageSize,
};
}
async getVersionHistory(id) {
const course = await this.prisma.course.findUnique({
where: { id },
});
if (!course) {
throw new common_1.NotFoundException(`Course #${id} not found`);
}
const versions = await this.prisma.courseVersion.findMany({
where: { courseId: id },
orderBy: { publishedAt: 'desc' },
});
return versions.map((v) => ({
id: v.id,
version: v.version,
changeLog: v.changeLog,
publishedAt: v.publishedAt,
publishedBy: v.publishedBy,
}));
}
};
exports.CourseService = CourseService;
exports.CourseService = CourseService = CourseService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
course_validation_service_1.CourseValidationService])
], CourseService);
//# sourceMappingURL=course.service.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,10 +0,0 @@
import { Response } from 'express';
import { ExportService } from './export.service';
export declare class ExportController {
private readonly exportService;
constructor(exportService: ExportService);
exportTeachers(req: any, res: Response): Promise<void>;
exportStudents(req: any, res: Response): Promise<void>;
exportLessons(req: any, res: Response): Promise<void>;
exportGrowthRecords(req: any, studentId: string, res: Response): Promise<void>;
}

View File

@ -1,90 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportController = void 0;
const common_1 = require("@nestjs/common");
const export_service_1 = require("./export.service");
const jwt_auth_guard_1 = require("../common/guards/jwt-auth.guard");
const roles_guard_1 = require("../common/guards/roles.guard");
const roles_decorator_1 = require("../common/decorators/roles.decorator");
let ExportController = class ExportController {
constructor(exportService) {
this.exportService = exportService;
}
async exportTeachers(req, res) {
const buffer = await this.exportService.exportTeachers(req.user.tenantId);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=teachers_${Date.now()}.xlsx`);
res.send(buffer);
}
async exportStudents(req, res) {
const buffer = await this.exportService.exportStudents(req.user.tenantId);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=students_${Date.now()}.xlsx`);
res.send(buffer);
}
async exportLessons(req, res) {
const buffer = await this.exportService.exportLessons(req.user.tenantId);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=lessons_${Date.now()}.xlsx`);
res.send(buffer);
}
async exportGrowthRecords(req, studentId, res) {
const buffer = await this.exportService.exportGrowthRecords(req.user.tenantId, studentId ? +studentId : undefined);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=growth_records_${Date.now()}.xlsx`);
res.send(buffer);
}
};
exports.ExportController = ExportController;
__decorate([
(0, common_1.Get)('teachers'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ExportController.prototype, "exportTeachers", null);
__decorate([
(0, common_1.Get)('students'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ExportController.prototype, "exportStudents", null);
__decorate([
(0, common_1.Get)('lessons'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ExportController.prototype, "exportLessons", null);
__decorate([
(0, common_1.Get)('growth-records'),
__param(0, (0, common_1.Request)()),
__param(1, (0, common_1.Query)('studentId')),
__param(2, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String, Object]),
__metadata("design:returntype", Promise)
], ExportController.prototype, "exportGrowthRecords", null);
exports.ExportController = ExportController = __decorate([
(0, common_1.Controller)('school/export'),
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, roles_guard_1.RolesGuard),
(0, roles_decorator_1.Roles)('school'),
__metadata("design:paramtypes", [export_service_1.ExportService])
], ExportController);
//# sourceMappingURL=export.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"export.controller.js","sourceRoot":"","sources":["../../../../src/modules/export/export.controller.ts"],"names":[],"mappings":"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"}

View File

@ -1,2 +0,0 @@
export declare class ExportModule {
}

View File

@ -1,23 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportModule = void 0;
const common_1 = require("@nestjs/common");
const export_controller_1 = require("./export.controller");
const export_service_1 = require("./export.service");
let ExportModule = class ExportModule {
};
exports.ExportModule = ExportModule;
exports.ExportModule = ExportModule = __decorate([
(0, common_1.Module)({
controllers: [export_controller_1.ExportController],
providers: [export_service_1.ExportService],
exports: [export_service_1.ExportService],
})
], ExportModule);
//# sourceMappingURL=export.module.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"export.module.js","sourceRoot":"","sources":["../../../../src/modules/export/export.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,qDAAiD;AAO1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,CAAC,8BAAa,CAAC;QAC1B,OAAO,EAAE,CAAC,8BAAa,CAAC;KACzB,CAAC;GACW,YAAY,CAAG"}

View File

@ -1,10 +0,0 @@
import { PrismaService } from '../../database/prisma.service';
export declare class ExportService {
private prisma;
private readonly logger;
constructor(prisma: PrismaService);
exportTeachers(tenantId: number): Promise<Buffer>;
exportStudents(tenantId: number): Promise<Buffer>;
exportLessons(tenantId: number): Promise<Buffer>;
exportGrowthRecords(tenantId: number, studentId?: number): Promise<Buffer>;
}

View File

@ -1,260 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var ExportService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../../database/prisma.service");
const ExcelJS = __importStar(require("exceljs"));
let ExportService = ExportService_1 = class ExportService {
constructor(prisma) {
this.prisma = prisma;
this.logger = new common_1.Logger(ExportService_1.name);
}
async exportTeachers(tenantId) {
const teachers = await this.prisma.teacher.findMany({
where: { tenantId },
include: {
classes: {
select: { name: true },
},
},
orderBy: { createdAt: 'desc' },
});
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('教师列表');
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '姓名', key: 'name', width: 15 },
{ header: '手机号', key: 'phone', width: 15 },
{ header: '邮箱', key: 'email', width: 25 },
{ header: '登录账号', key: 'loginAccount', width: 15 },
{ header: '负责班级', key: 'classes', width: 20 },
{ header: '授课次数', key: 'lessonCount', width: 10 },
{ header: '状态', key: 'status', width: 10 },
{ header: '创建时间', key: 'createdAt', width: 20 },
];
worksheet.getRow(1).font = { bold: true };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' },
};
teachers.forEach((teacher) => {
worksheet.addRow({
id: teacher.id,
name: teacher.name,
phone: teacher.phone,
email: teacher.email || '-',
loginAccount: teacher.loginAccount,
classes: teacher.classes.map((c) => c.name).join('、') || '-',
lessonCount: teacher.lessonCount,
status: teacher.status === 'ACTIVE' ? '正常' : '停用',
createdAt: teacher.createdAt.toLocaleDateString('zh-CN'),
});
});
const buffer = await workbook.xlsx.writeBuffer();
return Buffer.from(buffer);
}
async exportStudents(tenantId) {
const students = await this.prisma.student.findMany({
where: { tenantId },
include: {
class: {
select: { name: true },
},
},
orderBy: [{ classId: 'asc' }, { createdAt: 'asc' }],
});
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('学生列表');
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '姓名', key: 'name', width: 15 },
{ header: '性别', key: 'gender', width: 8 },
{ header: '班级', key: 'className', width: 15 },
{ header: '生日', key: 'birthDate', width: 15 },
{ header: '家长姓名', key: 'parentName', width: 15 },
{ header: '家长电话', key: 'parentPhone', width: 15 },
{ header: '阅读次数', key: 'readingCount', width: 10 },
{ header: '创建时间', key: 'createdAt', width: 20 },
];
worksheet.getRow(1).font = { bold: true };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' },
};
students.forEach((student) => {
worksheet.addRow({
id: student.id,
name: student.name,
gender: student.gender || '-',
className: student.class?.name || '-',
birthDate: student.birthDate
? new Date(student.birthDate).toLocaleDateString('zh-CN')
: '-',
parentName: student.parentName || '-',
parentPhone: student.parentPhone || '-',
readingCount: student.readingCount,
createdAt: student.createdAt.toLocaleDateString('zh-CN'),
});
});
const buffer = await workbook.xlsx.writeBuffer();
return Buffer.from(buffer);
}
async exportLessons(tenantId) {
const lessons = await this.prisma.lesson.findMany({
where: { tenantId },
include: {
course: {
select: { name: true, pictureBookName: true },
},
class: {
select: { name: true },
},
teacher: {
select: { name: true },
},
},
orderBy: { createdAt: 'desc' },
});
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('授课记录');
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '课程名称', key: 'courseName', width: 25 },
{ header: '绘本名称', key: 'pictureBookName', width: 20 },
{ header: '授课班级', key: 'className', width: 15 },
{ header: '授课教师', key: 'teacherName', width: 12 },
{ header: '计划时间', key: 'plannedDatetime', width: 18 },
{ header: '开始时间', key: 'startDatetime', width: 18 },
{ header: '结束时间', key: 'endDatetime', width: 18 },
{ header: '实际时长(分钟)', key: 'actualDuration', width: 12 },
{ header: '状态', key: 'status', width: 10 },
];
worksheet.getRow(1).font = { bold: true };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' },
};
const statusMap = {
PLANNED: '已计划',
IN_PROGRESS: '进行中',
COMPLETED: '已完成',
CANCELLED: '已取消',
};
lessons.forEach((lesson) => {
worksheet.addRow({
id: lesson.id,
courseName: lesson.course?.name || '-',
pictureBookName: lesson.course?.pictureBookName || '-',
className: lesson.class?.name || '-',
teacherName: lesson.teacher?.name || '-',
plannedDatetime: lesson.plannedDatetime
? new Date(lesson.plannedDatetime).toLocaleString('zh-CN')
: '-',
startDatetime: lesson.startDatetime
? new Date(lesson.startDatetime).toLocaleString('zh-CN')
: '-',
endDatetime: lesson.endDatetime
? new Date(lesson.endDatetime).toLocaleString('zh-CN')
: '-',
actualDuration: lesson.actualDuration || '-',
status: statusMap[lesson.status] || lesson.status,
});
});
const buffer = await workbook.xlsx.writeBuffer();
return Buffer.from(buffer);
}
async exportGrowthRecords(tenantId, studentId) {
const where = { tenantId };
if (studentId) {
where.studentId = studentId;
}
const records = await this.prisma.growthRecord.findMany({
where,
include: {
student: {
select: { name: true },
},
class: {
select: { name: true },
},
},
orderBy: { recordDate: 'desc' },
});
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('成长档案');
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '学生姓名', key: 'studentName', width: 15 },
{ header: '班级', key: 'className', width: 15 },
{ header: '标题', key: 'title', width: 25 },
{ header: '内容', key: 'content', width: 50 },
{ header: '记录类型', key: 'recordType', width: 12 },
{ header: '记录日期', key: 'recordDate', width: 15 },
{ header: '创建时间', key: 'createdAt', width: 20 },
];
worksheet.getRow(1).font = { bold: true };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' },
};
records.forEach((record) => {
worksheet.addRow({
id: record.id,
studentName: record.student?.name || '-',
className: record.class?.name || '-',
title: record.title,
content: record.content || '-',
recordType: record.recordType,
recordDate: record.recordDate
? new Date(record.recordDate).toLocaleDateString('zh-CN')
: '-',
createdAt: record.createdAt.toLocaleDateString('zh-CN'),
});
});
const buffer = await workbook.xlsx.writeBuffer();
return Buffer.from(buffer);
}
};
exports.ExportService = ExportService;
exports.ExportService = ExportService = ExportService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], ExportService);
//# sourceMappingURL=export.service.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
import { FileUploadService } from './file-upload.service';
export declare class FileUploadController {
private readonly fileUploadService;
private readonly logger;
constructor(fileUploadService: FileUploadService);
uploadFile(file: Express.Multer.File, body: {
type?: string;
courseId?: string;
}): Promise<{
success: boolean;
filePath: string;
fileName: string;
originalName: string;
fileSize: number;
mimeType: string;
}>;
deleteFile(body: {
filePath: string;
}): Promise<{
success: boolean;
message: string;
}>;
}

View File

@ -1,89 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var FileUploadController_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileUploadController = void 0;
const common_1 = require("@nestjs/common");
const platform_express_1 = require("@nestjs/platform-express");
const multer_1 = require("multer");
const file_upload_service_1 = require("./file-upload.service");
let FileUploadController = FileUploadController_1 = class FileUploadController {
constructor(fileUploadService) {
this.fileUploadService = fileUploadService;
this.logger = new common_1.Logger(FileUploadController_1.name);
}
async uploadFile(file, body) {
this.logger.log(`Uploading file: ${file.originalname}, type: ${body.type || 'unknown'}`);
if (!file) {
throw new common_1.BadRequestException('没有上传文件');
}
const fileType = body.type || 'other';
const validationResult = this.fileUploadService.validateFile(file, fileType);
if (!validationResult.valid) {
throw new common_1.BadRequestException(validationResult.error);
}
const savedFile = await this.fileUploadService.saveFile(file, fileType, body.courseId);
this.logger.log(`File uploaded successfully: ${savedFile.filePath}`);
return {
success: true,
filePath: savedFile.filePath,
fileName: savedFile.fileName,
originalName: file.originalname,
fileSize: file.size,
mimeType: file.mimetype,
};
}
async deleteFile(body) {
this.logger.log(`Deleting file: ${body.filePath}`);
if (!body.filePath) {
throw new common_1.BadRequestException('缺少文件路径');
}
const result = await this.fileUploadService.deleteFile(body.filePath);
if (!result.success) {
throw new common_1.BadRequestException(result.error);
}
this.logger.log(`File deleted successfully: ${body.filePath}`);
return {
success: true,
message: '文件删除成功',
};
}
};
exports.FileUploadController = FileUploadController;
__decorate([
(0, common_1.Post)('upload'),
(0, common_1.UseInterceptors)((0, platform_express_1.FileInterceptor)('file', {
storage: (0, multer_1.memoryStorage)(),
limits: {
fileSize: 300 * 1024 * 1024,
},
})),
__param(0, (0, common_1.UploadedFile)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], FileUploadController.prototype, "uploadFile", null);
__decorate([
(0, common_1.Delete)('delete'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], FileUploadController.prototype, "deleteFile", null);
exports.FileUploadController = FileUploadController = FileUploadController_1 = __decorate([
(0, common_1.Controller)('files'),
__metadata("design:paramtypes", [file_upload_service_1.FileUploadService])
], FileUploadController);
//# sourceMappingURL=file-upload.controller.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"file-upload.controller.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.controller.ts"],"names":[],"mappings":"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"}

View File

@ -1,2 +0,0 @@
export declare class FileUploadModule {
}

Some files were not shown because too many files have changed in this diff Show More