feat: 07 创作者中心批 2(内容编辑 / 分集 / 提交审核)
为什么:批 1 只给了创作者"看"的能力(工作台、审核进度、通知),内容还是得后台代建。 批 2 补上"改":创作者自己建草稿、编分集、提交审核,后台只管审。落地过程中发现三个必须一起修的问题: 1. 【会卡死创作者】后台驳回提交时不动短剧状态,剧会永远停在 reviewing, 而批 2 里 reviewing 是只读 —— 创作者既改不了也提不了。现在驳回与撤回都会把剧退回 draft。 2. 【上线了却放不出来】C 端只播 status=published 的分集,但没有任何地方在剧上线时把分集带上线。 审核通过 PUBLISH 时,仍处于草稿的分集一并上线。 3. 【编辑会误删字段】底层 apply() 对 null 会写空串/默认值:只想改封面的一次调用会把标题、时长、 排序一起清掉(自测时两集排序都变成 1 才发现)。creator 侧改成"未传字段沿用现值"。 - 新增 CreatorContentService + /admin/creator-center 的 10 个写接口与 2 个读接口, 一律不接收 creatorId,归属走 requireMyDrama,改别人的作品/分集统一 403 - 状态闸:只有 draft / offline 可直接编辑;reviewing / approved / published 只读并给出下一步动作 - 提交矩阵:draft→CREATE(首次)/UPDATE/PUBLISH,offline→UPDATE/PUBLISH,reviewing/approved→PUBLISH,published→OFFLINE; 同剧同时只允许一条在审提交;撤回后作品退回草稿,支持撤回重提 - 权限点 creator-center:drama:edit(创作者角色 + 超管),docs/api-phase1.md 2.10 补批 2 接口与规则表 - 分集收费与试看秒数本批不碰(批 3 的收费配置页负责),新增分集默认免费,避免误定价
This commit is contained in:
1 parent
ea875c3e2b
commit
255bcbf02b
11 files changed
+616
-5
No files matched your search
+143
@@ -9,7 +9,9 @@ import com.fruitshorts.common.pojo.PageResult;
|
||||
import com.fruitshorts.content.dal.entity.Drama;
|
||||
import com.fruitshorts.content.enums.ContentStatus;
|
||||
import com.fruitshorts.content.service.DramaService;
|
||||
import com.fruitshorts.content.service.EpisodeService;
|
||||
import com.fruitshorts.creator.dal.entity.ContentSubmission;
|
||||
import com.fruitshorts.creator.dal.entity.Creator;
|
||||
import com.fruitshorts.creator.dal.mapper.ContentSubmissionMapper;
|
||||
import com.fruitshorts.creator.vo.SubmissionAuditReqVO;
|
||||
import com.fruitshorts.creator.vo.SubmissionQueryReqVO;
|
||||
@@ -19,6 +21,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** 创作者内容提交:后台检索、审核,通过后按 type 落到短剧状态机。 */
|
||||
@@ -40,8 +44,12 @@ public class ContentSubmissionService {
|
||||
|
||||
private static final Set<String> REVIEWABLE = Set.of(STATUS_SUBMITTED, STATUS_REVIEWING);
|
||||
|
||||
/** 在审(还没出结果)的提交:同一部剧同时只允许一条,避免审核结论互相打架。 */
|
||||
public static final Set<String> PENDING = Set.of(STATUS_SUBMITTED, STATUS_REVIEWING);
|
||||
|
||||
private final ContentSubmissionMapper submissionMapper;
|
||||
private final DramaService dramaService;
|
||||
private final EpisodeService episodeService;
|
||||
|
||||
public PageResult<ContentSubmission> page(SubmissionQueryReqVO req) {
|
||||
Page<ContentSubmission> page = new Page<>(req.getSafePageIndex(), req.getSafePageSize());
|
||||
@@ -63,6 +71,138 @@ public class ContentSubmissionService {
|
||||
return submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创作者提交内容。
|
||||
*
|
||||
* 规则(和短剧状态机对齐,不新造状态):
|
||||
* - 同一部剧不能有第二条在审提交;
|
||||
* - 草稿 / 已下线:可以「新建 / 编辑 / 申请上线」,提交后剧进入 reviewing(申请下线除外);
|
||||
* - 待发布(approved):只能「申请上线」,由后台审核通过后上线;
|
||||
* - 已上线:只能「申请下线」,审核通过才真正下线。
|
||||
*
|
||||
* 创作者归属在这里再校验一次:即使调用方漏了,creatorId 对不上也进不来。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContentSubmission submit(Creator creator, Long dramaId, String type) {
|
||||
Drama drama = dramaService.getExisting(dramaId);
|
||||
if (!Objects.equals(drama.getCreatorId(), creator.getId())) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN, "无权访问该作品");
|
||||
}
|
||||
if (!Set.of(TYPE_CREATE, TYPE_UPDATE, TYPE_PUBLISH, TYPE_OFFLINE).contains(type)) {
|
||||
throw new ServiceException(ErrorCode.BAD_REQUEST, "未知的提交类型: " + type);
|
||||
}
|
||||
|
||||
Long pending = submissionMapper.selectCount(Wrappers.<ContentSubmission>lambdaQuery()
|
||||
.eq(ContentSubmission::getDramaId, dramaId)
|
||||
.in(ContentSubmission::getStatus, PENDING));
|
||||
if (pending != null && pending > 0) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "已有待审核的提交,请先撤回后再提交");
|
||||
}
|
||||
|
||||
Long history = submissionMapper.selectCount(Wrappers.<ContentSubmission>lambdaQuery()
|
||||
.eq(ContentSubmission::getDramaId, dramaId));
|
||||
boolean firstSubmit = history == null || history == 0;
|
||||
String status = drama.getStatus();
|
||||
ContentStatus current = ContentStatus.of(status);
|
||||
if (current == null) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "未知的作品状态: " + status);
|
||||
}
|
||||
switch (current) {
|
||||
case DRAFT -> {
|
||||
if (TYPE_CREATE.equals(type) && !firstSubmit) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"该作品已经提交过,请用「编辑」提交变更");
|
||||
}
|
||||
}
|
||||
case OFFLINE -> {
|
||||
if (TYPE_CREATE.equals(type)) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"已下线的作品请用「编辑」或「申请上线」提交");
|
||||
}
|
||||
}
|
||||
case APPROVED -> {
|
||||
if (!TYPE_PUBLISH.equals(type)) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "待发布的作品只能提交「申请上线」");
|
||||
}
|
||||
}
|
||||
case REVIEWING -> {
|
||||
// 内容审核(CREATE/UPDATE)通过后剧还停在 reviewing:这一步允许再提交「申请上线」,
|
||||
// 由后台再走一次上线审核(applyToDrama 会把 reviewing 顺推成 approved → published)。
|
||||
if (!TYPE_PUBLISH.equals(type)) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"审核中的作品只能提交「申请上线」,或先撤回提交");
|
||||
}
|
||||
}
|
||||
case PUBLISHED -> {
|
||||
if (!TYPE_OFFLINE.equals(type)) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"已上线的作品只读,请提交「申请下线」后再改");
|
||||
}
|
||||
}
|
||||
default -> throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"当前状态(" + ContentStatus.textOf(status) + ")不允许提交");
|
||||
}
|
||||
|
||||
ContentSubmission submission = new ContentSubmission();
|
||||
submission.setCreatorId(creator.getId());
|
||||
submission.setDramaId(dramaId);
|
||||
submission.setType(type);
|
||||
submission.setStatus(STATUS_SUBMITTED);
|
||||
submission.setVersion((int) (history + 1));
|
||||
submission.setSubmitAt(LocalDateTime.now());
|
||||
submission.setReviewerId(0L);
|
||||
submission.setReviewNote("");
|
||||
submission.setRejectCode("");
|
||||
submissionMapper.insert(submission);
|
||||
|
||||
// 申请上线/申请下线要靠后台审核结论去动状态;新建与编辑提交则先推到 reviewing,让创作者看得到进度
|
||||
if (!TYPE_OFFLINE.equals(type)
|
||||
&& (ContentStatus.DRAFT.getCode().equals(status)
|
||||
|| ContentStatus.OFFLINE.getCode().equals(status))) {
|
||||
dramaService.changeStatus(dramaId, "SUBMIT", "创作者提交审核", creator.getId(), creator.getName());
|
||||
}
|
||||
return submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创作者撤回自己的提交(撤回重提)。
|
||||
* 只有还没出结果的提交能撤回;撤回后短剧退回草稿,创作者可以继续改。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContentSubmission withdraw(Creator creator, Long submissionId) {
|
||||
ContentSubmission submission = getExisting(submissionId);
|
||||
if (!Objects.equals(submission.getCreatorId(), creator.getId())) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN, "无权撤回他人的提交");
|
||||
}
|
||||
requireState(submission.getStatus(), "撤回", Set.of(STATUS_SUBMITTED, STATUS_REVIEWING));
|
||||
submission.setStatus(STATUS_WITHDRAWN);
|
||||
submission.setReviewerId(creator.getId());
|
||||
submission.setReviewAt(LocalDateTime.now());
|
||||
submission.setReviewNote("创作者撤回");
|
||||
submissionMapper.updateById(submission);
|
||||
rejectOnDrama(submission, "创作者撤回提交", creator.getId(), creator.getName());
|
||||
return submission;
|
||||
}
|
||||
|
||||
/** 某部剧的提交历史(新的在前),创作者侧看进度用。 */
|
||||
public List<ContentSubmission> listByDrama(Long creatorId, Long dramaId) {
|
||||
return submissionMapper.selectList(Wrappers.<ContentSubmission>lambdaQuery()
|
||||
.eq(ContentSubmission::getCreatorId, creatorId)
|
||||
.eq(ContentSubmission::getDramaId, dramaId)
|
||||
.orderByDesc(ContentSubmission::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回 / 撤回之后把短剧从「审核中」退回草稿。
|
||||
* 不做这件事的话,创作者的剧会永远停在只读的审核中状态 —— 既改不了也提不了。
|
||||
*/
|
||||
private void rejectOnDrama(ContentSubmission submission, String reason, Long operatorId, String operatorName) {
|
||||
Drama drama = dramaService.getExisting(submission.getDramaId());
|
||||
if (ContentStatus.REVIEWING.getCode().equals(drama.getStatus())) {
|
||||
dramaService.changeStatus(submission.getDramaId(), "REJECT", reason, operatorId, operatorName);
|
||||
}
|
||||
}
|
||||
|
||||
/** 审核:通过 / 驳回 / 撤回。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContentSubmission audit(Long id, SubmissionAuditReqVO req, Long operatorId, String operatorName) {
|
||||
@@ -82,6 +222,7 @@ public class ContentSubmissionService {
|
||||
throw new ServiceException(ErrorCode.BAD_REQUEST, "驳回必须填写原因");
|
||||
}
|
||||
submission.setStatus(STATUS_REJECTED);
|
||||
rejectOnDrama(submission, req.getReason(), operatorId, operatorName);
|
||||
}
|
||||
case "WITHDRAW" -> {
|
||||
requireState(current, "撤回", Set.of(STATUS_DRAFT, STATUS_SUBMITTED));
|
||||
@@ -120,6 +261,8 @@ public class ContentSubmissionService {
|
||||
dramaService.changeStatus(dramaId, "APPROVE", reason, operatorId, operatorName);
|
||||
}
|
||||
dramaService.changeStatus(dramaId, "PUBLISH", reason, operatorId, operatorName);
|
||||
// 分集还停在草稿的话一并上线,否则会出现"剧上线了却一集都播不了"
|
||||
episodeService.publishDraftEpisodes(dramaId);
|
||||
} else if ("OFFLINE".equals(type)) {
|
||||
Drama drama = dramaService.getExisting(dramaId);
|
||||
if (ContentStatus.PUBLISHED.getCode().equals(drama.getStatus())) {
|
||||
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
package com.fruitshorts.creator.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fruitshorts.common.exception.ErrorCode;
|
||||
import com.fruitshorts.common.exception.ServiceException;
|
||||
import com.fruitshorts.content.dal.entity.Drama;
|
||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||
import com.fruitshorts.content.dal.mapper.DramaEpisodeMapper;
|
||||
import com.fruitshorts.content.enums.ContentStatus;
|
||||
import com.fruitshorts.content.service.DramaService;
|
||||
import com.fruitshorts.content.service.EpisodeService;
|
||||
import com.fruitshorts.content.vo.DramaSaveReqVO;
|
||||
import com.fruitshorts.content.vo.EpisodeRespVO;
|
||||
import com.fruitshorts.content.vo.EpisodeSaveReqVO;
|
||||
import com.fruitshorts.creator.dal.entity.ContentSubmission;
|
||||
import com.fruitshorts.creator.dal.entity.Creator;
|
||||
import com.fruitshorts.creator.vo.CreatorDramaEditReqVO;
|
||||
import com.fruitshorts.creator.vo.CreatorEpisodeReqVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 创作者中心 · 内容编辑(剧信息、分集、提交审核、撤回)。
|
||||
*
|
||||
* 与 {@link CreatorCenterService} 分工:那边是"看"(工作台 / 通知),这边是"改"。
|
||||
* 归属一律走 `requireMyDrama`,**接口不接收 creatorId**;改之前还要过 {@link #requireEditable} 这道状态闸:
|
||||
* 只有草稿和已下线能直接改,审核中 / 待发布 / 已上线都只读,改动必须走提交审核。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CreatorContentService {
|
||||
|
||||
private final CreatorCenterService centerService;
|
||||
private final ContentSubmissionService submissionService;
|
||||
private final DramaService dramaService;
|
||||
private final EpisodeService episodeService;
|
||||
private final DramaEpisodeMapper episodeMapper;
|
||||
|
||||
/** 新建草稿:归属写自己,状态固定 draft(是否上线由后续提交审核决定)。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createDrama(CreatorDramaEditReqVO req) {
|
||||
Creator creator = centerService.requireCurrentCreator();
|
||||
requireApprovedCreator(creator);
|
||||
return dramaService.createForCreator(toSaveReq(req), creator.getId(), creator.getAdminUserId());
|
||||
}
|
||||
|
||||
/** 编辑作品信息。定价、热门、排序不在本接口的可改范围,原样回填,避免被默认值冲掉。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateDrama(Long dramaId, CreatorDramaEditReqVO req) {
|
||||
Drama drama = centerService.requireMyDrama(dramaId);
|
||||
requireEditable(drama);
|
||||
// 没传的字段沿用现值:底层 apply() 对 null 会写空串 / 默认值,直接透传会把"没改的字段"抹掉
|
||||
DramaSaveReqVO vo = toSaveReq(req, drama);
|
||||
vo.setFreeEpisodes(drama.getFreeEpisodes());
|
||||
vo.setUnlockCoin(drama.getUnlockCoin());
|
||||
vo.setIsHot(drama.getIsHot() != null && drama.getIsHot() == 1);
|
||||
vo.setSort(drama.getSort());
|
||||
dramaService.update(dramaId, vo);
|
||||
}
|
||||
|
||||
public List<EpisodeRespVO> listEpisodes(Long dramaId) {
|
||||
centerService.requireMyDrama(dramaId);
|
||||
return episodeService.listByDrama(dramaId, null);
|
||||
}
|
||||
|
||||
/** 新增分集:集号不传就接在当前最大集号后面;新分集默认免费,收费由批 3 的配置页决定。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long addEpisode(Long dramaId, CreatorEpisodeReqVO req) {
|
||||
Drama drama = centerService.requireMyDrama(dramaId);
|
||||
requireEditable(drama);
|
||||
|
||||
Integer epNo = req.getEpNo();
|
||||
if (epNo == null) {
|
||||
DramaEpisode last = episodeMapper.selectOne(Wrappers.<DramaEpisode>lambdaQuery()
|
||||
.eq(DramaEpisode::getDramaId, dramaId)
|
||||
.orderByDesc(DramaEpisode::getEpNo)
|
||||
.last("limit 1"));
|
||||
epNo = last == null || last.getEpNo() == null ? 1 : last.getEpNo() + 1;
|
||||
}
|
||||
|
||||
EpisodeSaveReqVO vo = new EpisodeSaveReqVO();
|
||||
vo.setDramaId(dramaId);
|
||||
vo.setNumber(epNo);
|
||||
vo.setTitle(req.getTitle());
|
||||
vo.setDurationSec(req.getDurationSec());
|
||||
vo.setCover(req.getCover());
|
||||
vo.setVideoUrl(req.getVideoUrl());
|
||||
vo.setSort(req.getSort());
|
||||
vo.setIsFree(true);
|
||||
vo.setUnlockCoin(0);
|
||||
return episodeService.create(vo);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateEpisode(Long dramaId, Long episodeId, CreatorEpisodeReqVO req) {
|
||||
Drama drama = centerService.requireMyDrama(dramaId);
|
||||
requireEditable(drama);
|
||||
DramaEpisode episode = requireMyEpisode(dramaId, episodeId);
|
||||
|
||||
EpisodeSaveReqVO vo = new EpisodeSaveReqVO();
|
||||
vo.setDramaId(dramaId);
|
||||
vo.setNumber(req.getEpNo() == null ? episode.getEpNo() : req.getEpNo());
|
||||
// 同样是"没传就沿用现值":否则只想改封面的一次调用会把标题、时长和排序一起清掉
|
||||
vo.setTitle(req.getTitle() == null ? episode.getTitle() : req.getTitle());
|
||||
vo.setDurationSec(req.getDurationSec() == null ? episode.getDurationSec() : req.getDurationSec());
|
||||
vo.setCover(req.getCover() == null ? episode.getCoverUrl() : req.getCover());
|
||||
vo.setVideoUrl(req.getVideoUrl() == null ? episode.getVideoUrl() : req.getVideoUrl());
|
||||
vo.setSort(req.getSort() == null ? episode.getSort() : req.getSort());
|
||||
// 收费与试看秒数属于批 3 的收费配置,这里原样带回,别顺手改掉
|
||||
vo.setIsFree(episode.getIsFree() != null && episode.getIsFree() == 1);
|
||||
vo.setUnlockCoin(episode.getUnlockCoin());
|
||||
episodeService.update(episodeId, vo);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteEpisode(Long dramaId, Long episodeId) {
|
||||
Drama drama = centerService.requireMyDrama(dramaId);
|
||||
requireEditable(drama);
|
||||
requireMyEpisode(dramaId, episodeId);
|
||||
episodeService.delete(episodeId);
|
||||
}
|
||||
|
||||
/** 批量排序:先确认列表里每一集都属于这部剧,避免借排序接口动别人的分集。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void sortEpisodes(Long dramaId, List<Long> ids) {
|
||||
Drama drama = centerService.requireMyDrama(dramaId);
|
||||
requireEditable(drama);
|
||||
List<DramaEpisode> episodes = episodeMapper.selectBatchIds(ids);
|
||||
boolean allMine = episodes.size() == ids.size()
|
||||
&& episodes.stream().allMatch(episode -> Objects.equals(episode.getDramaId(), dramaId));
|
||||
if (!allMine) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN, "排序列表里含有不属于该作品的分集");
|
||||
}
|
||||
episodeService.updateSort(ids);
|
||||
}
|
||||
|
||||
public ContentSubmission submit(Long dramaId, String type) {
|
||||
Creator creator = centerService.requireCurrentCreator();
|
||||
requireApprovedCreator(creator);
|
||||
return submissionService.submit(creator, dramaId, type);
|
||||
}
|
||||
|
||||
public ContentSubmission withdraw(Long submissionId) {
|
||||
Creator creator = centerService.requireCurrentCreator();
|
||||
return submissionService.withdraw(creator, submissionId);
|
||||
}
|
||||
|
||||
public List<ContentSubmission> listSubmissions(Long dramaId) {
|
||||
Creator creator = centerService.requireCurrentCreator();
|
||||
centerService.requireMyDrama(dramaId);
|
||||
return submissionService.listByDrama(creator.getId(), dramaId);
|
||||
}
|
||||
|
||||
/** 分集归属:分集必须属于这部剧,否则 403(防止拿自己的剧 id 配别人的分集 id)。 */
|
||||
private DramaEpisode requireMyEpisode(Long dramaId, Long episodeId) {
|
||||
DramaEpisode episode = episodeId == null ? null : episodeMapper.selectById(episodeId);
|
||||
if (episode == null || !Objects.equals(episode.getDramaId(), dramaId)) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN, "无权访问该分集");
|
||||
}
|
||||
return episode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 可编辑状态闸:只有草稿与已下线能直接改。
|
||||
* 审核中改内容会让审核结论对不上;已上线必须走「申请下线」,待发布等后台发布。
|
||||
*/
|
||||
private void requireEditable(Drama drama) {
|
||||
ContentStatus status = ContentStatus.of(drama.getStatus());
|
||||
if (status == ContentStatus.DRAFT || status == ContentStatus.OFFLINE) {
|
||||
return;
|
||||
}
|
||||
if (status == null) {
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"作品状态异常(" + drama.getStatus() + "),暂不可编辑");
|
||||
}
|
||||
String reason = switch (status) {
|
||||
case PUBLISHED -> ":已上线的作品只读,请先提交「申请下线」";
|
||||
case REVIEWING -> ":提交正在审核中,请先撤回再改";
|
||||
case APPROVED -> ":作品已通过审核待发布,暂不可编辑";
|
||||
default -> ":当前状态不可编辑";
|
||||
};
|
||||
throw new ServiceException(ErrorCode.OPERATION_NOT_ALLOWED,
|
||||
"「" + ContentStatus.textOf(drama.getStatus()) + "」" + reason);
|
||||
}
|
||||
|
||||
private void requireApprovedCreator(Creator creator) {
|
||||
if (!CreatorService.STATUS_APPROVED.equals(creator.getStatus())) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN,
|
||||
"入驻审核通过后才能提交作品,当前状态:" + CreatorService.statusText(creator.getStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
/** 新建:null 走底层默认值;编辑:null 表示"这次不改这个字段"。 */
|
||||
private DramaSaveReqVO toSaveReq(CreatorDramaEditReqVO req) {
|
||||
return toSaveReq(req, null);
|
||||
}
|
||||
|
||||
private DramaSaveReqVO toSaveReq(CreatorDramaEditReqVO req, Drama current) {
|
||||
DramaSaveReqVO vo = new DramaSaveReqVO();
|
||||
vo.setTitle(req.getTitle());
|
||||
vo.setSubtitle(req.getSubtitle() == null && current != null ? current.getSubtitle() : req.getSubtitle());
|
||||
vo.setCategoryId(req.getCategoryId() == null && current != null ? current.getCategoryId() : req.getCategoryId());
|
||||
vo.setGenre(req.getGenre() == null && current != null ? current.getGenre() : req.getGenre());
|
||||
vo.setDescription(req.getDescription() == null && current != null
|
||||
? current.getSynopsis() : req.getDescription());
|
||||
vo.setCover(req.getCover() == null && current != null ? current.getCoverUrl() : req.getCover());
|
||||
vo.setTrailerUrl(req.getTrailerUrl() == null && current != null
|
||||
? current.getTrailerUrl() : req.getTrailerUrl());
|
||||
vo.setLanguage(req.getLanguage() == null && current != null ? current.getLanguage() : req.getLanguage());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.fruitshorts.creator.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创作者中心 · 作品基本信息(新建 / 编辑共用)。
|
||||
*
|
||||
* 这里**故意只放内容字段**:免费集数、解锁金币这类定价,以及是否热门、排序等运营字段,
|
||||
* 由后台或专门的收费配置页改(批 3),创作者编辑内容时不会把定价顺手改掉。
|
||||
*/
|
||||
@Data
|
||||
public class CreatorDramaEditReqVO {
|
||||
|
||||
@NotBlank(message = "请填写作品名称")
|
||||
private String title;
|
||||
|
||||
private String subtitle;
|
||||
private Long categoryId;
|
||||
private String genre;
|
||||
private String description;
|
||||
private String cover;
|
||||
/** 整剧预告片(复用 drama.trailer_url) */
|
||||
private String trailerUrl;
|
||||
private String language;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.fruitshorts.creator.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创作者中心 · 分集(新增 / 编辑共用)。
|
||||
*
|
||||
* 集号不传时按"当前最大集号 + 1"自动排;收费与试看秒数不在这里改(批 3 的收费配置页负责),
|
||||
* 新增分集默认免费,避免不小心把内容做成收费。
|
||||
*/
|
||||
@Data
|
||||
public class CreatorEpisodeReqVO {
|
||||
|
||||
/** 不传则自动取下一集 */
|
||||
private Integer epNo;
|
||||
private String title;
|
||||
private Integer durationSec;
|
||||
private String cover;
|
||||
/** 片源地址(批 3 接分片上传后会写这里) */
|
||||
private String videoUrl;
|
||||
private Integer sort;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.fruitshorts.creator.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/** 创作者中心 · 提交审核:type 取 CREATE / UPDATE / PUBLISH / OFFLINE。 */
|
||||
@Data
|
||||
public class CreatorSubmitReqVO {
|
||||
|
||||
@NotBlank(message = "请选择提交类型")
|
||||
private String type;
|
||||
}
|
||||
Reference in new issue
Block a user