Initialize the Kindergarten platform source code.
This commit is contained in:
commit
54f6daea62
BIN
reading-platform-backend/.DS_Store
vendored
Normal file
BIN
reading-platform-backend/.DS_Store
vendored
Normal file
Binary file not shown.
6
reading-platform-backend/.env
Normal file
6
reading-platform-backend/.env
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
DATABASE_URL="file:/Users/retirado/ccProgram/reading-platform-backend/dev.db"
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
JWT_SECRET="your-super-secret-jwt-key"
|
||||||
|
JWT_EXPIRES_IN="7d"
|
||||||
|
FRONTEND_URL="http://localhost:5173"
|
||||||
6
reading-platform-backend/.env.development
Normal file
6
reading-platform-backend/.env.development
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
DATABASE_URL="file:/Users/retirado/ccProgram/reading-platform-backend/dev.db"
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
JWT_SECRET="your-super-secret-jwt-key"
|
||||||
|
JWT_EXPIRES_IN="7d"
|
||||||
|
FRONTEND_URL="http://localhost:5173"
|
||||||
BIN
reading-platform-backend/dist/.DS_Store
vendored
Normal file
BIN
reading-platform-backend/dist/.DS_Store
vendored
Normal file
Binary file not shown.
1
reading-platform-backend/dist/prisma/seed.d.ts
vendored
Normal file
1
reading-platform-backend/dist/prisma/seed.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
420
reading-platform-backend/dist/prisma/seed.js
vendored
Normal file
420
reading-platform-backend/dist/prisma/seed.js
vendored
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/prisma/seed.js.map
vendored
Normal file
1
reading-platform-backend/dist/prisma/seed.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
reading-platform-backend/dist/src/app.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/app.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class AppModule {
|
||||||
|
}
|
||||||
64
reading-platform-backend/dist/src/app.module.js
vendored
Normal file
64
reading-platform-backend/dist/src/app.module.js
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/app.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/app.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
5
reading-platform-backend/dist/src/common/filters/http-exception.filter.d.ts
vendored
Normal file
5
reading-platform-backend/dist/src/common/filters/http-exception.filter.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { ExceptionFilter, ArgumentsHost } from '@nestjs/common';
|
||||||
|
export declare class HttpExceptionFilter implements ExceptionFilter {
|
||||||
|
private readonly logger;
|
||||||
|
catch(exception: unknown, host: ArgumentsHost): void;
|
||||||
|
}
|
||||||
70
reading-platform-backend/dist/src/common/filters/http-exception.filter.js
vendored
Normal file
70
reading-platform-backend/dist/src/common/filters/http-exception.filter.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/common/filters/http-exception.filter.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/common/filters/http-exception.filter.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
2
reading-platform-backend/dist/src/database/prisma.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/database/prisma.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class PrismaModule {
|
||||||
|
}
|
||||||
22
reading-platform-backend/dist/src/database/prisma.module.js
vendored
Normal file
22
reading-platform-backend/dist/src/database/prisma.module.js
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/database/prisma.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/database/prisma.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
7
reading-platform-backend/dist/src/database/prisma.service.d.ts
vendored
Normal file
7
reading-platform-backend/dist/src/database/prisma.service.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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>;
|
||||||
|
}
|
||||||
45
reading-platform-backend/dist/src/database/prisma.service.js
vendored
Normal file
45
reading-platform-backend/dist/src/database/prisma.service.js
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/database/prisma.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/database/prisma.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
1
reading-platform-backend/dist/src/main.d.ts
vendored
Normal file
1
reading-platform-backend/dist/src/main.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
51
reading-platform-backend/dist/src/main.js
vendored
Normal file
51
reading-platform-backend/dist/src/main.js
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/main.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/main.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
54
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.d.ts
vendored
Normal file
54
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.d.ts
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
137
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.js
vendored
Normal file
137
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.js
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/admin/admin-settings.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"admin-settings.controller.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin-settings.controller.ts"],"names":[],"mappings":"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"}
|
||||||
44
reading-platform-backend/dist/src/modules/admin/admin-settings.service.d.ts
vendored
Normal file
44
reading-platform-backend/dist/src/modules/admin/admin-settings.service.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
105
reading-platform-backend/dist/src/modules/admin/admin-settings.service.js
vendored
Normal file
105
reading-platform-backend/dist/src/modules/admin/admin-settings.service.js
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/admin/admin-settings.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/admin/admin-settings.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"admin-settings.service.js","sourceRoot":"","sources":["../../../../src/modules/admin/admin-settings.service.ts"],"names":[],"mappings":"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"}
|
||||||
41
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.d.ts
vendored
Normal file
41
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
|
}[]>;
|
||||||
|
}
|
||||||
84
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.js
vendored
Normal file
84
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.js
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/admin/admin-stats.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
42
reading-platform-backend/dist/src/modules/admin/admin-stats.service.d.ts
vendored
Normal file
42
reading-platform-backend/dist/src/modules/admin/admin-stats.service.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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;
|
||||||
|
}[]>;
|
||||||
|
}
|
||||||
212
reading-platform-backend/dist/src/modules/admin/admin-stats.service.js
vendored
Normal file
212
reading-platform-backend/dist/src/modules/admin/admin-stats.service.js
vendored
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/admin/admin-stats.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/admin/admin-stats.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
reading-platform-backend/dist/src/modules/admin/admin.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/admin/admin.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class AdminModule {
|
||||||
|
}
|
||||||
27
reading-platform-backend/dist/src/modules/admin/admin.module.js
vendored
Normal file
27
reading-platform-backend/dist/src/modules/admin/admin.module.js
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/admin/admin.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/admin/admin.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
60
reading-platform-backend/dist/src/modules/auth/auth.controller.d.ts
vendored
Normal file
60
reading-platform-backend/dist/src/modules/auth/auth.controller.d.ts
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
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;
|
||||||
|
}[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
61
reading-platform-backend/dist/src/modules/auth/auth.controller.js
vendored
Normal file
61
reading-platform-backend/dist/src/modules/auth/auth.controller.js
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/auth/auth.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/auth/auth.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
2
reading-platform-backend/dist/src/modules/auth/auth.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/auth/auth.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class AuthModule {
|
||||||
|
}
|
||||||
42
reading-platform-backend/dist/src/modules/auth/auth.module.js
vendored
Normal file
42
reading-platform-backend/dist/src/modules/auth/auth.module.js
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/auth/auth.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/auth/auth.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
84
reading-platform-backend/dist/src/modules/auth/auth.service.d.ts
vendored
Normal file
84
reading-platform-backend/dist/src/modules/auth/auth.service.d.ts
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
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;
|
||||||
|
}[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
287
reading-platform-backend/dist/src/modules/auth/auth.service.js
vendored
Normal file
287
reading-platform-backend/dist/src/modules/auth/auth.service.js
vendored
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/auth/auth.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/auth/auth.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
5
reading-platform-backend/dist/src/modules/auth/dto/login.dto.d.ts
vendored
Normal file
5
reading-platform-backend/dist/src/modules/auth/dto/login.dto.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export declare class LoginDto {
|
||||||
|
account: string;
|
||||||
|
password: string;
|
||||||
|
role: string;
|
||||||
|
}
|
||||||
33
reading-platform-backend/dist/src/modules/auth/dto/login.dto.js
vendored
Normal file
33
reading-platform-backend/dist/src/modules/auth/dto/login.dto.js
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/auth/dto/login.dto.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/auth/dto/login.dto.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
18
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.d.ts
vendored
Normal file
18
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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 {};
|
||||||
42
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.js
vendored
Normal file
42
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.js
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/auth/strategies/jwt.strategy.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
2
reading-platform-backend/dist/src/modules/common/common.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/common/common.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class CommonModule {
|
||||||
|
}
|
||||||
26
reading-platform-backend/dist/src/modules/common/common.module.js
vendored
Normal file
26
reading-platform-backend/dist/src/modules/common/common.module.js
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/common.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/common.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
7
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.d.ts
vendored
Normal file
7
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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>;
|
||||||
10
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.js
vendored
Normal file
10
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.js
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/decorators/log-operation.decorator.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
2
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare const ROLES_KEY = "roles";
|
||||||
|
export declare const Roles: (...roles: string[]) => import("@nestjs/common").CustomDecorator<string>;
|
||||||
8
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.js
vendored
Normal file
8
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.js
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/decorators/roles.decorator.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
9
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.d.ts
vendored
Normal file
9
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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 {};
|
||||||
37
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.js
vendored
Normal file
37
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.js
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/guards/jwt-auth.guard.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
7
reading-platform-backend/dist/src/modules/common/guards/roles.guard.d.ts
vendored
Normal file
7
reading-platform-backend/dist/src/modules/common/guards/roles.guard.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
37
reading-platform-backend/dist/src/modules/common/guards/roles.guard.js
vendored
Normal file
37
reading-platform-backend/dist/src/modules/common/guards/roles.guard.js
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/guards/roles.guard.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/guards/roles.guard.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
13
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.d.ts
vendored
Normal file
13
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
115
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.js
vendored
Normal file
115
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.js
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/interceptors/log.interceptor.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"log.interceptor.js","sourceRoot":"","sources":["../../../../../src/modules/common/interceptors/log.interceptor.ts"],"names":[],"mappings":"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"}
|
||||||
101
reading-platform-backend/dist/src/modules/common/operation-log.controller.d.ts
vendored
Normal file
101
reading-platform-backend/dist/src/modules/common/operation-log.controller.d.ts
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
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;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
108
reading-platform-backend/dist/src/modules/common/operation-log.controller.js
vendored
Normal file
108
reading-platform-backend/dist/src/modules/common/operation-log.controller.js
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/operation-log.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/operation-log.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
62
reading-platform-backend/dist/src/modules/common/operation-log.service.d.ts
vendored
Normal file
62
reading-platform-backend/dist/src/modules/common/operation-log.service.d.ts
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
134
reading-platform-backend/dist/src/modules/common/operation-log.service.js
vendored
Normal file
134
reading-platform-backend/dist/src/modules/common/operation-log.service.js
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/common/operation-log.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/common/operation-log.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"operation-log.service.js","sourceRoot":"","sources":["../../../../src/modules/common/operation-log.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,kEAA8D;AAGvD,IAAM,mBAAmB,2BAAzB,MAAM,mBAAmB;IAG9B,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;QAFxB,WAAM,GAAG,IAAI,eAAM,CAAC,qBAAmB,CAAC,IAAI,CAAC,CAAC;IAEnB,CAAC;IAK7C,KAAK,CAAC,OAAO,CAAC,QAAuB,EAAE,KAStC;QACC,MAAM,EACJ,IAAI,GAAG,CAAC,EACR,QAAQ,GAAG,EAAE,EACb,MAAM,EACN,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,GACR,GAAG,KAAK,CAAC;QAEV,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC;QAEvB,MAAM,KAAK,GAAQ,EAAE,CAAC;QAEtB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC5B,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACxB,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC5B,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACxB,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACxB,CAAC;QAED,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;YACrB,IAAI,SAAS,EAAE,CAAC;gBACd,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;YAC5C,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC;gBAChC,KAAK;gBACL,IAAI;gBACJ,IAAI;gBACJ,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;aAC/B,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;SAC1C,CAAC,CAAC;QAEH,OAAO;YACL,KAAK;YACL,KAAK;YACL,IAAI,EAAE,CAAC,IAAI;YACX,QAAQ,EAAE,CAAC,QAAQ;SACpB,CAAC;IACJ,CAAC;IAKD,KAAK,CAAC,UAAU,CAAC,QAAuB,EAAE,EAAU;QAClD,MAAM,KAAK,GAAQ,EAAE,EAAE,EAAE,CAAC;QAE1B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC5B,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC;YACnD,KAAK;SACN,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,OAAO;YACL,GAAG,GAAG;YACN,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;YAChE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;SACjE,CAAC;IACJ,CAAC;IAKD,KAAK,CAAC,cAAc,CAAC,QAAuB,EAAE,SAAkB,EAAE,OAAgB;QAChF,MAAM,KAAK,GAAQ,EAAE,CAAC;QAEtB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC5B,CAAC;QAED,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;YACrB,IAAI,SAAS,EAAE,CAAC;gBACd,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;YAC5C,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC;YACnD,KAAK;YACL,MAAM,EAAE;gBACN,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;aACb;SACF,CAAC,CAAC;QAGH,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAE9C,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACnB,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;iBACvC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;iBACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;YACpC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;iBACvC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;iBACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;YACpC,KAAK,EAAE,IAAI,CAAC,MAAM;SACnB,CAAC;IACJ,CAAC;IAKO,aAAa,CAAC,GAAW;QAC/B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;CACF,CAAA;AAtKY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAIiB,8BAAa;GAH9B,mBAAmB,CAsK/B"}
|
||||||
42
reading-platform-backend/dist/src/modules/course/course-validation.service.d.ts
vendored
Normal file
42
reading-platform-backend/dist/src/modules/course/course-validation.service.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
190
reading-platform-backend/dist/src/modules/course/course-validation.service.js
vendored
Normal file
190
reading-platform-backend/dist/src/modules/course/course-validation.service.js
vendored
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/course/course-validation.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/course/course-validation.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
625
reading-platform-backend/dist/src/modules/course/course.controller.d.ts
vendored
Normal file
625
reading-platform-backend/dist/src/modules/course/course.controller.d.ts
vendored
Normal file
@ -0,0 +1,625 @@
|
|||||||
|
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;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
223
reading-platform-backend/dist/src/modules/course/course.controller.js
vendored
Normal file
223
reading-platform-backend/dist/src/modules/course/course.controller.js
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/course/course.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/course/course.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"course.controller.js","sourceRoot":"","sources":["../../../../src/modules/course/course.controller.ts"],"names":[],"mappings":"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"}
|
||||||
2
reading-platform-backend/dist/src/modules/course/course.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/course/course.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class CourseModule {
|
||||||
|
}
|
||||||
26
reading-platform-backend/dist/src/modules/course/course.module.js
vendored
Normal file
26
reading-platform-backend/dist/src/modules/course/course.module.js
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/course/course.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/course/course.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
627
reading-platform-backend/dist/src/modules/course/course.service.d.ts
vendored
Normal file
627
reading-platform-backend/dist/src/modules/course/course.service.d.ts
vendored
Normal file
@ -0,0 +1,627 @@
|
|||||||
|
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;
|
||||||
|
}[]>;
|
||||||
|
}
|
||||||
750
reading-platform-backend/dist/src/modules/course/course.service.js
vendored
Normal file
750
reading-platform-backend/dist/src/modules/course/course.service.js
vendored
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/course/course.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/course/course.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
10
reading-platform-backend/dist/src/modules/export/export.controller.d.ts
vendored
Normal file
10
reading-platform-backend/dist/src/modules/export/export.controller.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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>;
|
||||||
|
}
|
||||||
90
reading-platform-backend/dist/src/modules/export/export.controller.js
vendored
Normal file
90
reading-platform-backend/dist/src/modules/export/export.controller.js
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/export/export.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/export/export.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"export.controller.js","sourceRoot":"","sources":["../../../../src/modules/export/export.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AAExB,qDAAiD;AACjD,oEAA+D;AAC/D,8DAA0D;AAC1D,0EAA6D;AAKtD,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAGvD,AAAN,KAAK,CAAC,cAAc,CAAY,GAAQ,EAAS,GAAa;QAC5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE1E,GAAG,CAAC,SAAS,CACX,cAAc,EACd,mEAAmE,CACpE,CAAC;QACF,GAAG,CAAC,SAAS,CACX,qBAAqB,EACrB,iCAAiC,IAAI,CAAC,GAAG,EAAE,OAAO,CACnD,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IAGK,AAAN,KAAK,CAAC,cAAc,CAAY,GAAQ,EAAS,GAAa;QAC5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE1E,GAAG,CAAC,SAAS,CACX,cAAc,EACd,mEAAmE,CACpE,CAAC;QACF,GAAG,CAAC,SAAS,CACX,qBAAqB,EACrB,iCAAiC,IAAI,CAAC,GAAG,EAAE,OAAO,CACnD,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa,CAAY,GAAQ,EAAS,GAAa;QAC3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEzE,GAAG,CAAC,SAAS,CACX,cAAc,EACd,mEAAmE,CACpE,CAAC;QACF,GAAG,CAAC,SAAS,CACX,qBAAqB,EACrB,gCAAgC,IAAI,CAAC,GAAG,EAAE,OAAO,CAClD,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IAGK,AAAN,KAAK,CAAC,mBAAmB,CACZ,GAAQ,EACC,SAAiB,EAC9B,GAAa;QAEpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACzD,GAAG,CAAC,IAAI,CAAC,QAAQ,EACjB,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CACnC,CAAC;QAEF,GAAG,CAAC,SAAS,CACX,cAAc,EACd,mEAAmE,CACpE,CAAC;QACF,GAAG,CAAC,SAAS,CACX,qBAAqB,EACrB,uCAAuC,IAAI,CAAC,GAAG,EAAE,OAAO,CACzD,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;CACF,CAAA;AArEY,4CAAgB;AAIrB;IADL,IAAA,YAAG,EAAC,UAAU,CAAC;IACM,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,YAAG,GAAE,CAAA;;;;sDAY/C;AAGK;IADL,IAAA,YAAG,EAAC,UAAU,CAAC;IACM,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,YAAG,GAAE,CAAA;;;;sDAY/C;AAGK;IADL,IAAA,YAAG,EAAC,SAAS,CAAC;IACM,WAAA,IAAA,gBAAO,GAAE,CAAA;IAAY,WAAA,IAAA,YAAG,GAAE,CAAA;;;;qDAY9C;AAGK;IADL,IAAA,YAAG,EAAC,gBAAgB,CAAC;IAEnB,WAAA,IAAA,gBAAO,GAAE,CAAA;IACT,WAAA,IAAA,cAAK,EAAC,WAAW,CAAC,CAAA;IAClB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;2DAgBP;2BApEU,gBAAgB;IAH5B,IAAA,mBAAU,EAAC,eAAe,CAAC;IAC3B,IAAA,kBAAS,EAAC,6BAAY,EAAE,wBAAU,CAAC;IACnC,IAAA,uBAAK,EAAC,QAAQ,CAAC;qCAE8B,8BAAa;GAD9C,gBAAgB,CAqE5B"}
|
||||||
2
reading-platform-backend/dist/src/modules/export/export.module.d.ts
vendored
Normal file
2
reading-platform-backend/dist/src/modules/export/export.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export declare class ExportModule {
|
||||||
|
}
|
||||||
23
reading-platform-backend/dist/src/modules/export/export.module.js
vendored
Normal file
23
reading-platform-backend/dist/src/modules/export/export.module.js
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/export/export.module.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/export/export.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
10
reading-platform-backend/dist/src/modules/export/export.service.d.ts
vendored
Normal file
10
reading-platform-backend/dist/src/modules/export/export.service.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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>;
|
||||||
|
}
|
||||||
260
reading-platform-backend/dist/src/modules/export/export.service.js
vendored
Normal file
260
reading-platform-backend/dist/src/modules/export/export.service.js
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/export/export.service.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/export/export.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
23
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.d.ts
vendored
Normal file
23
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
89
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.js
vendored
Normal file
89
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.js
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
"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
|
||||||
1
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.js.map
vendored
Normal file
1
reading-platform-backend/dist/src/modules/file-upload/file-upload.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"file-upload.controller.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.controller.ts"],"names":[],"mappings":"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"}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user