feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径

This commit is contained in:
yuzhiran-dev
2026-05-18 09:48:51 +08:00
commit 11bb86854c
277 changed files with 37755 additions and 0 deletions
@@ -0,0 +1,34 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ContentsService } from './contents.service';
@ApiTags('内容')
@Controller('contents')
export class ContentsController {
constructor(private contentsService: ContentsService) {}
@Get()
async findAll(@Query() query: { page?: number; pageSize?: number; categoryId?: number; contentType?: string }) {
return this.contentsService.findAll(query);
}
@Get(':id')
async findById(@Param('id') id: string) {
return this.contentsService.findById(+id);
}
@Post()
async create(@Body() body: any) {
return this.contentsService.create(body);
}
@Put(':id')
async update(@Param('id') id: string, @Body() body: any) {
return this.contentsService.update(+id, body);
}
@Delete(':id')
async remove(@Param('id') id: string) {
return this.contentsService.remove(+id);
}
}
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { ContentsController } from './contents.controller';
import { ContentsService } from './contents.service';
@Module({
controllers: [ContentsController],
providers: [ContentsService],
exports: [ContentsService],
})
export class ContentsModule {}
@@ -0,0 +1,52 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
@Injectable()
export class ContentsService {
constructor(private prisma: PrismaService) {}
async findAll(params: { page?: number; pageSize?: number; categoryId?: number; contentType?: string }) {
const page = Number(params.page ?? 1);
const pageSize = Number(params.pageSize ?? 20);
const { categoryId, contentType } = params;
const where: any = { status: 'PUBLISHED', deletedAt: null };
if (categoryId) where.categoryId = categoryId;
if (contentType) where.contentType = contentType;
const [items, total] = await Promise.all([
this.prisma.content.findMany({
where,
skip: (page - 1) * pageSize,
take: pageSize,
orderBy: { publishedAt: 'desc' },
select: {
id: true, title: true, summary: true, cover: true, contentType: true,
tags: true, authorName: true, viewCount: true, isAiGenerated: true,
publishedAt: true, createdAt: true, category: true,
},
}),
this.prisma.content.count({ where }),
]);
return { items, total, page, pageSize };
}
async findById(id: number) {
const content = await this.prisma.content.findUnique({ where: { id }, include: { category: true } });
if (!content) return null;
await this.prisma.content.update({ where: { id }, data: { viewCount: { increment: 1 } } });
return content;
}
async create(data: any) {
return this.prisma.content.create({ data });
}
async update(id: number, data: any) {
return this.prisma.content.update({ where: { id }, data });
}
async remove(id: number) {
return this.prisma.content.update({ where: { id }, data: { deletedAt: new Date() } });
}
}