feat: 新增剧集封面、集数管理与上传优化功能
1. 新增Cover实体类并注册到数据库模块 2. 为剧集添加总集数字段及自动创建集数槽功能 3. 新增管理员更新剧集集数接口 4. 优化发布剧集列表:支持标题过滤与默认分页大小10 5. 扩展MediaUploadJob实体字段,完善媒体上传流程 6. 重构订单与媒体服务,新增数据库持久化支持 7. 新增剧集标题过滤的端到端测试用例
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { DataSource, Like } from 'typeorm';
|
||||
import { PaginatedResponse } from '../../common/dto/paginated-response.dto';
|
||||
import { ConfigureEpisodesDto } from './dto/configure-episodes.dto';
|
||||
import { CreateDramaDto } from './dto/create-drama.dto';
|
||||
@@ -26,6 +26,10 @@ interface PaginationInput {
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
interface PublishedDramaListInput extends PaginationInput {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DramasService {
|
||||
private dramaSequence = 1;
|
||||
@@ -40,6 +44,7 @@ export class DramasService {
|
||||
) {}
|
||||
|
||||
async createDrama(dto: CreateDramaDto): Promise<DramaRecord> {
|
||||
const { totalEpisodes } = dto;
|
||||
if (this.hasDatabase()) {
|
||||
const repository = this.dataSource.getRepository(Drama);
|
||||
const entity = repository.create({
|
||||
@@ -61,6 +66,12 @@ export class DramasService {
|
||||
onlineVersion: dto.onlineVersion ?? 1,
|
||||
});
|
||||
const saved = await repository.save(entity);
|
||||
if (totalEpisodes) {
|
||||
await this.configureEpisodes(Number(saved.id), {
|
||||
episodeCount: totalEpisodes,
|
||||
});
|
||||
return this.getDramaOrThrow(Number(saved.id));
|
||||
}
|
||||
return this.toDramaRecord(saved, 0, 0);
|
||||
}
|
||||
|
||||
@@ -90,6 +101,10 @@ export class DramasService {
|
||||
};
|
||||
|
||||
this.dramas.push(drama);
|
||||
if (totalEpisodes) {
|
||||
await this.configureEpisodes(drama.id, { episodeCount: totalEpisodes });
|
||||
return this.getDramaOrThrow(drama.id);
|
||||
}
|
||||
return drama;
|
||||
}
|
||||
|
||||
@@ -137,14 +152,23 @@ export class DramasService {
|
||||
}
|
||||
|
||||
async updateDrama(id: number, dto: UpdateDramaDto): Promise<DramaRecord> {
|
||||
const { totalEpisodes, ...dramaUpdates } = dto;
|
||||
if (this.hasDatabase()) {
|
||||
const repository = this.dataSource.getRepository(Drama);
|
||||
const drama = await repository.findOne({ where: { id } });
|
||||
if (!drama) {
|
||||
throw new NotFoundException('Drama not found');
|
||||
}
|
||||
repository.merge(drama, { ...dto, tags: dto.tags ?? drama.tags });
|
||||
repository.merge(drama, {
|
||||
...dramaUpdates,
|
||||
tags: dramaUpdates.tags ?? drama.tags,
|
||||
});
|
||||
const saved = await repository.save(drama);
|
||||
if (totalEpisodes) {
|
||||
await this.configureEpisodes(Number(saved.id), {
|
||||
episodeCount: totalEpisodes,
|
||||
});
|
||||
}
|
||||
return this.toDramaRecordWithCounts(saved);
|
||||
}
|
||||
|
||||
@@ -154,10 +178,13 @@ export class DramasService {
|
||||
}
|
||||
|
||||
Object.assign(drama, {
|
||||
...dto,
|
||||
tags: dto.tags ?? drama.tags,
|
||||
...dramaUpdates,
|
||||
tags: dramaUpdates.tags ?? drama.tags,
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
if (totalEpisodes) {
|
||||
await this.configureEpisodes(drama.id, { episodeCount: totalEpisodes });
|
||||
}
|
||||
return this.withEpisodeCounts(drama);
|
||||
}
|
||||
|
||||
@@ -474,6 +501,28 @@ export class DramasService {
|
||||
return episode;
|
||||
}
|
||||
|
||||
async updateDramaEpisode(
|
||||
dramaId: number,
|
||||
episodeId: number,
|
||||
dto: UpdateEpisodeDto,
|
||||
): Promise<EpisodeRecord> {
|
||||
if (this.hasDatabase()) {
|
||||
const episode = await this.dataSource.getRepository(Episode).findOne({
|
||||
where: { id: episodeId, dramaId },
|
||||
});
|
||||
if (!episode) {
|
||||
throw new NotFoundException('Episode not found');
|
||||
}
|
||||
} else {
|
||||
const episode = await this.getMemEpisodeOrThrow(episodeId);
|
||||
if (episode.dramaId !== dramaId) {
|
||||
throw new NotFoundException('Episode not found');
|
||||
}
|
||||
}
|
||||
|
||||
return this.updateEpisode(episodeId, { ...dto, dramaId });
|
||||
}
|
||||
|
||||
async attachEpisodeMedia(input: {
|
||||
episodeId: number;
|
||||
byteplusVid: string;
|
||||
@@ -546,14 +595,18 @@ export class DramasService {
|
||||
}
|
||||
|
||||
async listPublishedDramas(
|
||||
pagination: PaginationInput,
|
||||
input: PublishedDramaListInput,
|
||||
): Promise<PaginatedResponse<DramaRecord>> {
|
||||
const title = input.title?.trim();
|
||||
if (this.hasDatabase()) {
|
||||
const { page, pageSize, skip, take } = this.resolvePagination(pagination);
|
||||
const { page, pageSize, skip, take } = this.resolvePagination(input);
|
||||
const [records, total] = await this.dataSource
|
||||
.getRepository(Drama)
|
||||
.findAndCount({
|
||||
where: { status: PublishStatus.Published },
|
||||
where: {
|
||||
status: PublishStatus.Published,
|
||||
...(title ? { title: Like(`%${title}%`) } : {}),
|
||||
},
|
||||
order: { sortOrder: 'DESC', id: 'DESC' },
|
||||
skip,
|
||||
take,
|
||||
@@ -568,9 +621,10 @@ export class DramasService {
|
||||
this.sortDramas(
|
||||
this.dramas
|
||||
.filter((item) => item.status === PublishStatus.Published)
|
||||
.filter((item) => !title || item.title.includes(title))
|
||||
.map((drama) => this.withEpisodeCounts(drama)),
|
||||
),
|
||||
pagination,
|
||||
input,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user