| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.controller.ts
- import {
- Controller,
- Get,
- Param,
- Query,
- Patch,
- Body,
- Post,
- Delete,
- Req,
- BadRequestException,
- } from '@nestjs/common';
- import type { FastifyRequest } from 'fastify';
- import {
- ApiTags,
- ApiOperation,
- ApiParam,
- ApiConsumes,
- ApiBody,
- ApiResponse,
- ApiOkResponse,
- ApiNotFoundResponse,
- ApiBadRequestResponse,
- } from '@nestjs/swagger';
- import { VideoMediaService } from './video-media.service';
- import {
- VideoMediaListQueryDto,
- UpdateVideoMediaManageDto,
- UpdateVideoMediaStatusDto,
- BatchUpdateVideoMediaStatusDto,
- VideoMediaListItemDto,
- VideoMediaDetailDto,
- UpdateVideoMediaCoverResponseDto,
- } from './video-media.dto';
- @ApiTags('视频管理 (Video Media Management)')
- @Controller('video-media')
- export class VideoMediaController {
- constructor(private readonly videoMediaService: VideoMediaService) {}
- /**
- * 列表查询
- * POST /video-media/list
- */
- @ApiOperation({
- summary: '获取视频媒体列表',
- description: '分页查询视频列表,支持关键词搜索和上下架状态过滤',
- })
- @ApiOkResponse({
- description: '返回视频媒体分页列表',
- schema: {
- type: 'object',
- properties: {
- data: {
- type: 'array',
- items: { $ref: '#/components/schemas/VideoMediaListItemDto' },
- },
- total: { type: 'number', example: 100 },
- page: { type: 'number', example: 1 },
- pageSize: { type: 'number', example: 20 },
- },
- },
- })
- @ApiBadRequestResponse({
- description: '请求参数验证失败',
- })
- @Post('list')
- async findAll(@Body() dto: VideoMediaListQueryDto) {
- return this.videoMediaService.findAll(dto);
- }
- /**
- * 详情(管理弹窗)
- * GET /video-media/:id
- */
- @ApiOperation({
- summary: '获取视频媒体详情',
- description:
- '获取单个视频媒体的完整详细信息,包括基础属性、管理信息和反范式化数据',
- })
- @ApiParam({
- name: 'id',
- type: String,
- description: '视频媒体 MongoDB ID',
- example: '507f1f77bcf86cd799439011',
- })
- @ApiOkResponse({
- description: '返回视频媒体详情',
- type: VideoMediaDetailDto,
- })
- @ApiNotFoundResponse({
- description: '视频媒体不存在',
- })
- @Get(':id')
- async findOne(@Param('id') id: string) {
- return this.videoMediaService.findOne(id);
- }
- /**
- * 管理弹窗保存(标题 / 分类 / 标签 / 上下架)
- * PATCH /video-media/:id/manage
- */
- @ApiOperation({
- summary: '更新视频媒体管理信息',
- description: '更新视频的标题、分类、标签、上下架状态等管理级别信息',
- })
- @ApiParam({
- name: 'id',
- type: String,
- description: '视频媒体 MongoDB ID',
- example: '507f1f77bcf86cd799439011',
- })
- @ApiBody({
- type: UpdateVideoMediaManageDto,
- description: '更新的管理信息',
- })
- @ApiOkResponse({
- description: '更新成功',
- type: VideoMediaDetailDto,
- })
- @ApiNotFoundResponse({
- description: '视频媒体不存在',
- })
- @ApiBadRequestResponse({
- description: '请求参数验证失败',
- })
- @Patch(':id/manage')
- async updateManage(
- @Param('id') id: string,
- @Body() dto: UpdateVideoMediaManageDto,
- ) {
- return this.videoMediaService.updateManage(id, dto);
- }
- /**
- * 单个上/下架
- * PATCH /video-media/:id/status
- */
- @ApiOperation({
- summary: '更新视频媒体上下架状态',
- description: '对单个视频进行上架(1)或下架(0)操作',
- })
- @ApiParam({
- name: 'id',
- type: String,
- description: '视频媒体 MongoDB ID',
- example: '507f1f77bcf86cd799439011',
- })
- @ApiBody({
- type: UpdateVideoMediaStatusDto,
- description: '上下架状态信息',
- })
- @ApiOkResponse({
- description: '状态更新成功',
- type: VideoMediaDetailDto,
- })
- @ApiNotFoundResponse({
- description: '视频媒体不存在',
- })
- @ApiBadRequestResponse({
- description: '请求参数验证失败',
- })
- @Patch(':id/status')
- async updateStatus(
- @Param('id') id: string,
- @Body() dto: UpdateVideoMediaStatusDto,
- ) {
- return this.videoMediaService.updateStatus(id, dto);
- }
- /**
- * 批量上/下架
- * POST /video-media/batch/status
- */
- @ApiOperation({
- summary: '批量更新视频媒体上下架状态',
- description: '对多个视频进行批量上架或下架操作',
- })
- @ApiBody({
- type: BatchUpdateVideoMediaStatusDto,
- description: '批量更新信息,包含 ID 列表和目标状态',
- })
- @ApiOkResponse({
- description: '批量更新成功',
- schema: {
- type: 'object',
- properties: {
- success: { type: 'number', example: 10 },
- failed: { type: 'number', example: 0 },
- },
- },
- })
- @ApiBadRequestResponse({
- description: '请求参数验证失败',
- })
- @Post('batch/status')
- async batchUpdateStatus(@Body() dto: BatchUpdateVideoMediaStatusDto) {
- return this.videoMediaService.batchUpdateStatus(dto);
- }
- /**
- * 封面上传:
- * - 前端通过 multipart/form-data 上传文件
- * - 这里示例使用 FileInterceptor;实际中你会上传到 S3,得到一个 URL / key
- * POST /video-media/:id/cover
- */
- @ApiOperation({
- summary: '上传视频封面',
- description: '为指定视频上传或更新自定义封面图片,支持上传至 S3 存储',
- })
- @ApiParam({
- name: 'id',
- type: String,
- description: '视频媒体 MongoDB ID',
- example: '507f1f77bcf86cd799439011',
- })
- @ApiConsumes('multipart/form-data')
- @ApiBody({
- description: '封面图片文件上传',
- schema: {
- type: 'object',
- properties: {
- file: {
- type: 'string',
- format: 'binary',
- description: '图片文件(支持 JPG、PNG 等常见格式)',
- },
- },
- required: ['file'],
- },
- })
- @ApiOkResponse({
- description: '封面上传成功',
- type: UpdateVideoMediaCoverResponseDto,
- })
- @ApiNotFoundResponse({
- description: '视频媒体不存在',
- })
- @ApiBadRequestResponse({
- description: '文件格式或大小不符合要求',
- })
- @Post(':id/cover')
- async updateCover(@Param('id') id: string, @Req() req: FastifyRequest) {
- const reqAny = req as any;
- const bodyFile = reqAny.body?.file;
- let mpFile = Array.isArray(bodyFile) ? bodyFile[0] : bodyFile;
- if (!mpFile && reqAny.isMultipart?.()) {
- mpFile = await reqAny.file();
- }
- if (!mpFile) {
- throw new BadRequestException('No file uploaded');
- }
- return this.videoMediaService.updateCover(id, mpFile);
- }
- // TODO: 删除视频媒体
- @ApiOperation({
- summary: '删除视频媒体',
- description: '根据 ID 删除指定的视频媒体',
- })
- @ApiParam({
- name: 'id',
- type: String,
- description: '视频媒体 MongoDB ID',
- example: '507f1f77bcf86cd799439011',
- })
- @ApiOkResponse({
- description: '删除成功',
- schema: {
- type: 'object',
- properties: {
- id: { type: 'string', example: '507f1f77bcf86cd799439011' },
- },
- },
- })
- @ApiNotFoundResponse({
- description: '视频媒体不存在',
- })
- @Delete(':id')
- async delete(@Param('id') id: string) {
- return this.videoMediaService.delete(id);
- }
- }
|