library-picturebook-activity/backend/src/public/content-review.controller.ts
aid f246b38fc1 Day5: 超管端内容管理模块全面优化 + 广场推荐作品展示
作品审核:
- 批量通过/批量拒绝 + 撤销审核机制
- 默认筛选待审核,表格加描述预览+审核时间列
- 详情Drawer加上一个/下一个导航,审核后自动跳下一个
- 操作日志时间线展示,筛选下拉自动查询

作品管理:
- 修复筛选/排序失效,新增推荐中筛选
- 下架改为弹窗选择原因,取消推荐二次确认
- 详情Drawer补全描述/标签/操作按钮/操作日志
- 统计卡片可点击筛选,下架自动取消推荐

标签管理:
- 按分类分组卡片式展示,分类改为下拉选择
- 新增标签颜色字段(预设色+自定义)
- 上移/下移排序按钮,使用次数可点击跳转作品管理
- 新增/编辑时实时预览用户端标签效果

广场推荐:
- 新增推荐作品列表接口 GET /public/gallery/recommended
- 广场顶部新增「编辑推荐」横向滚动栏

文档更新:内容管理设计文档补充实施记录,UGC开发计划P1-1标记已完成

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:21:21 +08:00

122 lines
3.3 KiB
TypeScript

import {
Controller, Get, Post, Param, Query, Body,
ParseIntPipe, UseGuards, Request,
} from '@nestjs/common';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { ContentReviewService } from './content-review.service';
@Controller('content-review')
@UseGuards(JwtAuthGuard)
export class ContentReviewController {
constructor(private readonly reviewService: ContentReviewService) {}
// ========== 作品审核 ==========
@Get('works/stats')
getWorkStats() {
return this.reviewService.getWorkStats();
}
@Get('works')
getWorkQueue(
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
@Query('status') status?: string,
@Query('keyword') keyword?: string,
@Query('startTime') startTime?: string,
@Query('endTime') endTime?: string,
@Query('sortBy') sortBy?: string,
@Query('isRecommended') isRecommended?: string,
) {
return this.reviewService.getWorkQueue({
page: page ? parseInt(page) : 1,
pageSize: pageSize ? parseInt(pageSize) : 10,
status,
keyword,
startTime,
endTime,
sortBy,
isRecommended: isRecommended === '1',
});
}
@Get('works/:id')
getWorkDetail(@Param('id', ParseIntPipe) id: number) {
return this.reviewService.getWorkDetail(id);
}
@Post('works/batch-approve')
batchApprove(@Request() req, @Body() dto: { ids: number[] }) {
return this.reviewService.batchApprove(dto.ids || [], req.user.userId);
}
@Post('works/batch-reject')
batchReject(@Request() req, @Body() dto: { ids: number[]; reason: string }) {
return this.reviewService.batchReject(dto.ids || [], req.user.userId, dto.reason);
}
@Post('works/:id/approve')
approveWork(
@Param('id', ParseIntPipe) id: number,
@Request() req,
@Body() dto: { note?: string },
) {
return this.reviewService.approve(id, req.user.userId, dto.note);
}
@Post('works/:id/reject')
rejectWork(
@Param('id', ParseIntPipe) id: number,
@Request() req,
@Body() dto: { reason: string; note?: string },
) {
return this.reviewService.reject(id, req.user.userId, dto.reason, dto.note);
}
@Post('works/:id/revoke')
revokeWork(@Param('id', ParseIntPipe) id: number, @Request() req) {
return this.reviewService.revoke(id, req.user.userId);
}
@Post('works/:id/takedown')
takedownWork(
@Param('id', ParseIntPipe) id: number,
@Request() req,
@Body() dto: { reason: string },
) {
return this.reviewService.takedown(id, req.user.userId, dto.reason);
}
@Post('works/:id/restore')
restoreWork(@Param('id', ParseIntPipe) id: number, @Request() req) {
return this.reviewService.restore(id, req.user.userId);
}
@Post('works/:id/recommend')
toggleRecommend(@Param('id', ParseIntPipe) id: number) {
return this.reviewService.toggleRecommend(id);
}
// ========== 作品管理 ==========
@Get('management/stats')
getManagementStats() {
return this.reviewService.getManagementStats();
}
// ========== 审核日志 ==========
@Get('logs')
getLogs(
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
@Query('workId') workId?: string,
) {
return this.reviewService.getLogs({
page: page ? parseInt(page) : 1,
pageSize: pageSize ? parseInt(pageSize) : 20,
workId: workId ? parseInt(workId) : undefined,
});
}
}