22 changed files with 969 additions and 7 deletions
@ -0,0 +1,40 @@ |
|||||
|
package com.youlai.boot.admin.constant; |
||||
|
|
||||
|
/** |
||||
|
* 内容审核状态常量 |
||||
|
*/ |
||||
|
public final class AuditConstants { |
||||
|
|
||||
|
private AuditConstants() {} |
||||
|
|
||||
|
/** 审核状态: 机审中 */ |
||||
|
public static final String AUDIT_REVIEWING = "reviewing"; |
||||
|
/** 审核状态: 通过 */ |
||||
|
public static final String AUDIT_PASSED = "passed"; |
||||
|
/** 审核状态: 不通过 */ |
||||
|
public static final String AUDIT_FAILED = "failed"; |
||||
|
/** 审核状态: 待人工 */ |
||||
|
public static final String AUDIT_MANUAL_REVIEW = "manual_review"; |
||||
|
/** 审核状态: 申诉中 */ |
||||
|
public static final String AUDIT_APPEALING = "appealing"; |
||||
|
|
||||
|
/** 任务状态: 审核中 */ |
||||
|
public static final String TASK_REVIEWING = "reviewing"; |
||||
|
/** 任务状态: 机审成功 */ |
||||
|
public static final String TASK_SUCCESS = "success"; |
||||
|
/** 任务状态: 转人工 */ |
||||
|
public static final String TASK_TO_MANUAL = "to_manual"; |
||||
|
|
||||
|
/** 任务结果: 通过 */ |
||||
|
public static final String RESULT_PASSED = "passed"; |
||||
|
/** 任务结果: 未通过 */ |
||||
|
public static final String RESULT_FAILED = "failed"; |
||||
|
|
||||
|
/** 机审建议: 通过 */ |
||||
|
public static final String SUGGESTION_PASS = "pass"; |
||||
|
/** 机审建议: 复审 */ |
||||
|
public static final String SUGGESTION_REVIEW = "review"; |
||||
|
/** 机审建议: 违规 */ |
||||
|
public static final String SUGGESTION_BLOCK = "block"; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
package com.youlai.boot.admin.controller; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.youlai.boot.admin.model.form.AuditConfigForm; |
||||
|
import com.youlai.boot.admin.model.query.AuditConfigQuery; |
||||
|
import com.youlai.boot.admin.model.vo.AuditConfigVO; |
||||
|
import com.youlai.boot.admin.service.ContentAuditConfigService; |
||||
|
import com.youlai.boot.common.annotation.Log; |
||||
|
import com.youlai.boot.common.enums.ActionTypeEnum; |
||||
|
import com.youlai.boot.common.enums.LogModuleEnum; |
||||
|
import com.youlai.boot.common.result.PageResult; |
||||
|
import com.youlai.boot.common.result.Result; |
||||
|
import io.swagger.v3.oas.annotations.Operation; |
||||
|
import io.swagger.v3.oas.annotations.tags.Tag; |
||||
|
import jakarta.validation.Valid; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
@Tag(name = "管理端-审核配置相关接口") |
||||
|
@RestController |
||||
|
@RequestMapping("/api/v1/admin/auditConfig") |
||||
|
@RequiredArgsConstructor |
||||
|
public class ContentAuditConfigController { |
||||
|
|
||||
|
private final ContentAuditConfigService contentAuditConfigService; |
||||
|
|
||||
|
@Operation(summary = "分页查询审核配置列表") |
||||
|
@GetMapping("/list") |
||||
|
@Log(module = LogModuleEnum.CONTENT_AUDIT_CONFIG, value = ActionTypeEnum.LIST) |
||||
|
public PageResult<AuditConfigVO> listConfig(@Valid AuditConfigQuery query) { |
||||
|
IPage<AuditConfigVO> result = contentAuditConfigService.pageConfig(query); |
||||
|
return PageResult.success(result); |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "新增审核配置") |
||||
|
@PostMapping("/add") |
||||
|
@Log(module = LogModuleEnum.CONTENT_AUDIT_CONFIG, value = ActionTypeEnum.INSERT) |
||||
|
public Result<AuditConfigVO> addConfig(@Valid @RequestBody AuditConfigForm form) { |
||||
|
AuditConfigVO vo = contentAuditConfigService.addConfig(form); |
||||
|
return Result.success(vo); |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "修改审核配置") |
||||
|
@PostMapping("/update/{uuid}") |
||||
|
@Log(module = LogModuleEnum.CONTENT_AUDIT_CONFIG, value = ActionTypeEnum.UPDATE) |
||||
|
public Result<AuditConfigVO> updateConfig(@PathVariable String uuid, @Valid @RequestBody AuditConfigForm form) { |
||||
|
AuditConfigVO vo = contentAuditConfigService.updateConfig(uuid, form); |
||||
|
return Result.success(vo); |
||||
|
} |
||||
|
|
||||
|
@Operation(summary = "删除审核配置") |
||||
|
@PostMapping("/delete/{uuid}") |
||||
|
@Log(module = LogModuleEnum.CONTENT_AUDIT_CONFIG, value = ActionTypeEnum.DELETE) |
||||
|
public Result<Void> deleteConfig(@PathVariable String uuid) { |
||||
|
contentAuditConfigService.deleteConfig(uuid); |
||||
|
return Result.success(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.youlai.boot.admin.converter; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditConfig; |
||||
|
import com.youlai.boot.admin.model.form.AuditConfigForm; |
||||
|
import com.youlai.boot.admin.model.vo.AuditConfigVO; |
||||
|
import org.mapstruct.Mapper; |
||||
|
|
||||
|
@Mapper(componentModel = "spring") |
||||
|
public interface AuditConfigConverter { |
||||
|
|
||||
|
Page<AuditConfigVO> toPageVo(Page<MiniContentAuditConfig> page); |
||||
|
|
||||
|
AuditConfigVO toVo(MiniContentAuditConfig entity); |
||||
|
|
||||
|
MiniContentAuditConfig toEntity(AuditConfigForm form); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
package com.youlai.boot.admin.model.dto; |
||||
|
|
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
@Schema(description = "审核内容入参") |
||||
|
public class AuditContentDTO { |
||||
|
|
||||
|
@Schema(description = "待审核文本列表") |
||||
|
private List<String> texts; |
||||
|
|
||||
|
@Schema(description = "待审核图片URL列表") |
||||
|
private List<String> images; |
||||
|
|
||||
|
@Schema(description = "待审核视频URL列表") |
||||
|
private List<String> videos; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
package com.youlai.boot.admin.model.form; |
||||
|
|
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
@Schema(description = "审核配置表单") |
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class AuditConfigForm { |
||||
|
|
||||
|
@NotBlank(message = "业务模块编码不能为空") |
||||
|
@Schema(description = "业务模块: animal_note / adoption_diary / user_post / note_comment / diary_comment / post_comment / user_avatar / user_nickname / user_introduction") |
||||
|
private String moduleCode; |
||||
|
|
||||
|
@NotNull(message = "是否开启审核不能为空") |
||||
|
@Schema(description = "是否开启审核, false-开启, true-关闭") |
||||
|
private Boolean auditEnable; |
||||
|
|
||||
|
@Schema(description = "审核类型: machine / manual / mixed") |
||||
|
private String auditType; |
||||
|
|
||||
|
@Schema(description = "机器审核风险策略: none / medium / high") |
||||
|
private String riskStrategy; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
package com.youlai.boot.admin.model.query; |
||||
|
|
||||
|
import com.youlai.boot.common.base.BaseQuery; |
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Schema(description = "审核配置分页查询") |
||||
|
public class AuditConfigQuery extends BaseQuery { |
||||
|
|
||||
|
@Schema(description = "业务模块编码") |
||||
|
private String moduleCode; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
package com.youlai.boot.admin.model.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Builder; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Data |
||||
|
@Builder |
||||
|
@Schema(description = "审核配置列表VO") |
||||
|
public class AuditConfigVO { |
||||
|
|
||||
|
@Schema(description = "主键ID") |
||||
|
private Long id; |
||||
|
|
||||
|
@Schema(description = "UUID") |
||||
|
private String uuid; |
||||
|
|
||||
|
@Schema(description = "业务模块编码") |
||||
|
private String moduleCode; |
||||
|
|
||||
|
@Schema(description = "是否开启审核, false-开启, true-关闭") |
||||
|
private Boolean auditEnable; |
||||
|
|
||||
|
@Schema(description = "审核类型: machine / manual / mixed") |
||||
|
private String auditType; |
||||
|
|
||||
|
@Schema(description = "机器审核风险策略: none / medium / high") |
||||
|
private String riskStrategy; |
||||
|
|
||||
|
@Schema(description = "创建时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date createTime; |
||||
|
|
||||
|
@Schema(description = "创建人ID") |
||||
|
private Long createBy; |
||||
|
|
||||
|
@Schema(description = "更新时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date updateTime; |
||||
|
|
||||
|
@Schema(description = "修改人ID") |
||||
|
private Long updateBy; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.youlai.boot.admin.service; |
||||
|
|
||||
|
import com.youlai.boot.admin.model.dto.AuditContentDTO; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
public interface AuditExecutorService { |
||||
|
|
||||
|
/** |
||||
|
* 执行内容审核(供业务层调用) |
||||
|
* |
||||
|
* @param moduleCode 业务模块: animal_note / adoption_diary / user_post / *_comment / user_avatar / user_nickname / user_introduction |
||||
|
* @param bizId 业务数据ID |
||||
|
* @param content 待审核内容 {text, images[], video} |
||||
|
* @return {status: "passed"|"failed"|"manual_review", auditId: Long},配置关闭或无配置时返回null |
||||
|
*/ |
||||
|
Map<String, Object> executeAudit(String moduleCode, String bizId, AuditContentDTO content); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
package com.youlai.boot.admin.service; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditConfig; |
||||
|
import com.youlai.boot.admin.model.form.AuditConfigForm; |
||||
|
import com.youlai.boot.admin.model.query.AuditConfigQuery; |
||||
|
import com.youlai.boot.admin.model.vo.AuditConfigVO; |
||||
|
|
||||
|
public interface ContentAuditConfigService extends IService<MiniContentAuditConfig> { |
||||
|
|
||||
|
IPage<AuditConfigVO> pageConfig(AuditConfigQuery query); |
||||
|
|
||||
|
AuditConfigVO getConfigByUuid(String uuid); |
||||
|
|
||||
|
AuditConfigVO addConfig(AuditConfigForm form); |
||||
|
|
||||
|
AuditConfigVO updateConfig(String uuid, AuditConfigForm form); |
||||
|
|
||||
|
void deleteConfig(String uuid); |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
package com.youlai.boot.admin.service; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAudit; |
||||
|
|
||||
|
public interface ContentAuditService extends IService<MiniContentAudit> { |
||||
|
|
||||
|
MiniContentAudit createAudit(String moduleCode, String bizId, String auditType); |
||||
|
|
||||
|
void updateAuditStatus(Long auditId, String status, String finalResult); |
||||
|
|
||||
|
MiniContentAudit getByModuleAndBizId(String moduleCode, String bizId); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.youlai.boot.admin.service; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditTask; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public interface ContentAuditTaskService extends IService<MiniContentAuditTask> { |
||||
|
|
||||
|
/** 批量创建审核任务(按内容类型拆分:text/image/video) */ |
||||
|
void batchCreateTasks(Long auditId, String auditType, List<String> texts, List<String> images, List<String> videos); |
||||
|
|
||||
|
/** 更新单个任务的机审结果 */ |
||||
|
void updateTaskMachineResult(Long taskId, String machineResult, String riskLevel, String result, String status); |
||||
|
|
||||
|
/** 查询某个审核汇总下的所有任务明细 */ |
||||
|
List<MiniContentAuditTask> listTasksByAuditId(Long auditId); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,398 @@ |
|||||
|
package com.youlai.boot.admin.service.impl; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.aliyun.green20220302.models.ImageModerationResponse; |
||||
|
import com.aliyun.green20220302.models.TextModerationResponse; |
||||
|
import com.aliyun.green20220302.models.VideoModerationResponse; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.youlai.boot.admin.constant.AuditConstants; |
||||
|
import com.youlai.boot.admin.model.dto.AuditContentDTO; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAudit; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditConfig; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditTask; |
||||
|
import com.youlai.boot.admin.service.*; |
||||
|
import com.youlai.boot.common.util.AliyunContentAuditUtil; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.lang.reflect.Method; |
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* 内容审核核心执行器 |
||||
|
* <p> |
||||
|
* 职责:编排审核全流程——查配置 → 创建汇总 → 拆解内容创建任务 → 调用阿里云机审 → 按策略判定结果 → 汇总最终状态 |
||||
|
* 供业务层(创建/修改内容时)注入调用。 |
||||
|
*/ |
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
public class AuditExecutorServiceImpl implements AuditExecutorService { |
||||
|
|
||||
|
private final ContentAuditConfigService contentAuditConfigService; |
||||
|
private final ContentAuditService contentAuditService; |
||||
|
private final ContentAuditTaskService contentAuditTaskService; |
||||
|
private final AliyunContentAuditUtil aliyunContentAuditUtil; |
||||
|
|
||||
|
/** |
||||
|
* 执行内容审核(供业务层在内容创建/修改后调用)。 |
||||
|
* |
||||
|
* @param moduleCode 业务模块编码,对应 mini_content_audit_config.module_code |
||||
|
* @param bizId 业务数据ID(日记ID / 评论ID 等) |
||||
|
* @param content 待审核内容 {texts, images, videos} |
||||
|
* @return {status, auditId};配置关闭或无配置时返回 null,调用方以此判断是否跳过审核 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Map<String, Object> executeAudit(String moduleCode, String bizId, AuditContentDTO content) { |
||||
|
// 1) 查询对应模块的审核配置
|
||||
|
MiniContentAuditConfig config = findAuditConfig(moduleCode); |
||||
|
if (config == null || isAuditDisabled(config)) { |
||||
|
// 无配置 或 审核开关已关闭 → 跳过审核,业务层直接放行
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 2) 创建审核汇总记录(MiniContentAudit 表)
|
||||
|
MiniContentAudit audit = contentAuditService.createAudit(moduleCode, bizId, config.getAuditType()); |
||||
|
Long auditId = audit.getId(); |
||||
|
// 风险策略取自配置,默认为 medium
|
||||
|
String riskStrategy = config.getRiskStrategy() != null ? config.getRiskStrategy() : "medium"; |
||||
|
|
||||
|
// 3) 拆解待审核内容,批量创建审核任务明细(MiniContentAuditTask 表)
|
||||
|
contentAuditTaskService.batchCreateTasks(auditId, config.getAuditType(), |
||||
|
content.getTexts(), content.getImages(), content.getVideos()); |
||||
|
|
||||
|
// 4) 读取已创建的所有任务,逐一调用阿里云内容审核API
|
||||
|
List<MiniContentAuditTask> tasks = contentAuditTaskService.listTasksByAuditId(auditId); |
||||
|
for (MiniContentAuditTask task : tasks) { |
||||
|
executeSingleTaskAudit(task, riskStrategy); |
||||
|
} |
||||
|
|
||||
|
// 5) 重新加载任务(机审结果已回填),汇总判定 audit 的最终状态
|
||||
|
List<MiniContentAuditTask> updatedTasks = contentAuditTaskService.listTasksByAuditId(auditId); |
||||
|
return aggregateTaskResultsAndUpdateAudit(auditId, updatedTasks); |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 配置查询
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 查找审核配置。 |
||||
|
* LambdaQueryWrapper 构建条件:module_code = ? AND deleted = false(未逻辑删除) |
||||
|
*/ |
||||
|
private MiniContentAuditConfig findAuditConfig(String moduleCode) { |
||||
|
LambdaQueryWrapper<MiniContentAuditConfig> queryWrapper = new LambdaQueryWrapper<>(); |
||||
|
queryWrapper.eq(MiniContentAuditConfig::getModuleCode, moduleCode); |
||||
|
queryWrapper.eq(MiniContentAuditConfig::getDeleted, false); |
||||
|
// MyBatis-Plus getOne:根据 Wrapper 条件返回单条记录,多于1条时抛异常
|
||||
|
return contentAuditConfigService.getOne(queryWrapper); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断审核是否已关闭。 |
||||
|
* MiniContentAuditConfig.auditEnable: false=开启审核, true=关闭审核 |
||||
|
*/ |
||||
|
private boolean isAuditDisabled(MiniContentAuditConfig config) { |
||||
|
Boolean auditEnable = config.getAuditEnable(); |
||||
|
return Boolean.TRUE.equals(auditEnable); |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 单条任务机审
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 对一条审核任务调用阿里云内容安全API,并将结果回填到任务记录。 |
||||
|
* text/image 同步返回 suggestion,video 异步返回 taskId 后续轮询。 |
||||
|
* 依赖方法说明: |
||||
|
* - AliyunContentAuditUtil.textModeration(String) → 阿里云文本审核(同步) |
||||
|
* - AliyunContentAuditUtil.imageModeration(String) → 阿里云图片审核(同步) |
||||
|
* - AliyunContentAuditUtil.videoModeration(String) → 阿里云视频审核(异步,返回taskId) |
||||
|
*/ |
||||
|
private void executeSingleTaskAudit(MiniContentAuditTask task, String riskStrategy) { |
||||
|
String contentType = task.getContentType(); |
||||
|
String contentValue = task.getContentValue(); |
||||
|
|
||||
|
try { |
||||
|
switch (contentType) { |
||||
|
case "text" -> handleTextAudit(task, contentValue, riskStrategy); |
||||
|
case "image" -> handleImageAudit(task, contentValue, riskStrategy); |
||||
|
case "video" -> handleVideoAudit(task, contentValue); |
||||
|
default -> log.warn("未知内容类型: {}", contentType); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.error("机审调用失败, taskId={}, contentType={}", task.getId(), contentType, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文本审核(同步)。 |
||||
|
* TextModerationResponse.getBody().getData() 包含 suggestion,值为 pass/review/block |
||||
|
*/ |
||||
|
private void handleTextAudit(MiniContentAuditTask task, String textContent, String riskStrategy) { |
||||
|
TextModerationResponse response = aliyunContentAuditUtil.textModeration(textContent); |
||||
|
String suggestion = extractSuggestionFromResponse(response); |
||||
|
String machineResultJson = JSON.toJSONString(response); |
||||
|
applyAuditResultToTask(task, suggestion, machineResultJson, riskStrategy); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 图片审核(同步)。 |
||||
|
* ImageModerationResponse.getBody().getData() 包含 suggestion,值为 pass/review/block |
||||
|
*/ |
||||
|
private void handleImageAudit(MiniContentAuditTask task, String imageUrl, String riskStrategy) { |
||||
|
ImageModerationResponse response = aliyunContentAuditUtil.imageModeration(imageUrl); |
||||
|
String suggestion = extractSuggestionFromResponse(response); |
||||
|
String machineResultJson = JSON.toJSONString(response); |
||||
|
applyAuditResultToTask(task, suggestion, machineResultJson, riskStrategy); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 视频审核(异步)。 |
||||
|
* VideoModerationResponse.getBody().getData().getTaskId() 返回异步任务ID, |
||||
|
* 写入 task.taskId 供后续 VideoModerationResult 轮询查询结果。 |
||||
|
* 视频不参与本轮汇总,task.result 暂不设置。 |
||||
|
*/ |
||||
|
private void handleVideoAudit(MiniContentAuditTask task, String videoUrl) { |
||||
|
VideoModerationResponse response = aliyunContentAuditUtil.videoModeration(videoUrl); |
||||
|
if (response == null) { |
||||
|
log.warn("视频审核请求返回null, taskId={}", task.getId()); |
||||
|
return; |
||||
|
} |
||||
|
// 提取异步 taskId 并写入任务记录
|
||||
|
String asyncTaskId = extractVideoTaskIdFromResponse(response); |
||||
|
if (asyncTaskId != null) { |
||||
|
task.setTaskId(asyncTaskId); |
||||
|
// MyBatis-Plus updateById:按主键id更新实体,此处只更新 task_id 字段
|
||||
|
contentAuditTaskService.updateById(task); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从 VideoModerationResponse 中提取异步 taskId。 |
||||
|
* 调用路径:response.getBody().getData().getTaskId() |
||||
|
*/ |
||||
|
private String extractVideoTaskIdFromResponse(VideoModerationResponse response) { |
||||
|
if (response.getBody() == null) { |
||||
|
return null; |
||||
|
} |
||||
|
if (response.getBody().getData() == null) { |
||||
|
return null; |
||||
|
} |
||||
|
// VideoModerationResponseBody.getData() 返回 VideoModerationResponseBodyData,含 getTaskId()
|
||||
|
return response.getBody().getData().getTaskId(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将机审建议应用到任务记录:suggestion → risk_level → 按策略判定 result → 任务最终 status |
||||
|
*/ |
||||
|
private void applyAuditResultToTask(MiniContentAuditTask task, String suggestion, String machineResultJson, String riskStrategy) { |
||||
|
if (suggestion == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 1. suggestion → risk_level(none/medium/high)
|
||||
|
String riskLevel = mapSuggestionToRiskLevel(suggestion); |
||||
|
|
||||
|
// 2. risk_level + 策略 → result(passed / failed / to_manual)
|
||||
|
String result = applyRiskStrategy(suggestion, riskStrategy); |
||||
|
|
||||
|
// 3. result 决定任务最终状态
|
||||
|
boolean needManual = AuditConstants.TASK_TO_MANUAL.equals(result); |
||||
|
String taskStatus = needManual ? AuditConstants.TASK_TO_MANUAL : AuditConstants.TASK_SUCCESS; |
||||
|
|
||||
|
// 回填任务表:machine_result(JSON) / risk_level / result / status
|
||||
|
contentAuditTaskService.updateTaskMachineResult( |
||||
|
task.getId(), machineResultJson, riskLevel, result, taskStatus); |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 从阿里云响应中提取 suggestion
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 从阿里云审核响应中提取 suggestion 值(pass/review/block)。 |
||||
|
* 使用反射调用 getBody() → getData() → getSuggestion(),兼容 Text 和 Image 两种 Response。 |
||||
|
* <p> |
||||
|
* 如果 Data 为 List 类型,取第一个元素的 getSuggestion()。 |
||||
|
*/ |
||||
|
private String extractSuggestionFromResponse(Object response) { |
||||
|
if (response == null) { |
||||
|
return null; |
||||
|
} |
||||
|
try { |
||||
|
// 调用 response.getBody()
|
||||
|
Object body = invokeGetter(response, "getBody"); |
||||
|
if (body == null) { |
||||
|
return null; |
||||
|
} |
||||
|
// 调用 body.getData()
|
||||
|
Object data = invokeGetter(body, "getData"); |
||||
|
if (data == null) { |
||||
|
return null; |
||||
|
} |
||||
|
// 如果 Data 是 List,取第一个元素
|
||||
|
if (data instanceof List<?> dataList && !dataList.isEmpty()) { |
||||
|
data = dataList.get(0); |
||||
|
} |
||||
|
// 调用 data.getSuggestion()
|
||||
|
Object suggestion = invokeGetter(data, "getSuggestion"); |
||||
|
return suggestion != null ? suggestion.toString() : null; |
||||
|
} catch (Exception e) { |
||||
|
log.error("提取suggestion失败", e); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 反射调用目标对象的 getter 方法 |
||||
|
*/ |
||||
|
private Object invokeGetter(Object target, String methodName) throws Exception { |
||||
|
Method method = target.getClass().getMethod(methodName); |
||||
|
return method.invoke(target); |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 策略映射
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 将阿里云机审 suggestion 映射为风险等级。 |
||||
|
* pass → none(无风险) / review → medium(中等风险) / block → high(高风险) |
||||
|
*/ |
||||
|
private String mapSuggestionToRiskLevel(String suggestion) { |
||||
|
if (AuditConstants.SUGGESTION_PASS.equals(suggestion)) { |
||||
|
return "none"; |
||||
|
} |
||||
|
if (AuditConstants.SUGGESTION_REVIEW.equals(suggestion)) { |
||||
|
return "medium"; |
||||
|
} |
||||
|
if (AuditConstants.SUGGESTION_BLOCK.equals(suggestion)) { |
||||
|
return "high"; |
||||
|
} |
||||
|
return "none"; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据 risk_strategy 配置,将机审 suggestion 映射为任务 result。 |
||||
|
* <pre> |
||||
|
* none 策略: pass→passed, 其余→failed (机审直接决定,无人工环节) |
||||
|
* medium策略: pass→passed, review→to_manual, block→failed |
||||
|
* high策略: pass→passed, 其余→to_manual (中高风险一律转人工) |
||||
|
* </pre> |
||||
|
* |
||||
|
* @param suggestion 阿里云机审建议:pass / review / block |
||||
|
* @param strategy 审核配置中的 risk_strategy:none / medium / high |
||||
|
* @return passed / failed / to_manual |
||||
|
*/ |
||||
|
private String applyRiskStrategy(String suggestion, String strategy) { |
||||
|
boolean isPassSuggestion = AuditConstants.SUGGESTION_PASS.equals(suggestion); |
||||
|
|
||||
|
if ("none".equals(strategy)) { |
||||
|
// none策略:pass→通过,其余→不通过
|
||||
|
if (isPassSuggestion) { |
||||
|
return AuditConstants.RESULT_PASSED; |
||||
|
} |
||||
|
return AuditConstants.RESULT_FAILED; |
||||
|
} |
||||
|
|
||||
|
if ("high".equals(strategy)) { |
||||
|
// high策略:pass→通过,其余→转人工
|
||||
|
if (isPassSuggestion) { |
||||
|
return AuditConstants.RESULT_PASSED; |
||||
|
} |
||||
|
return AuditConstants.TASK_TO_MANUAL; |
||||
|
} |
||||
|
|
||||
|
// medium策略(默认):pass→通过,review→转人工,block→不通过
|
||||
|
if (AuditConstants.SUGGESTION_REVIEW.equals(suggestion)) { |
||||
|
return AuditConstants.TASK_TO_MANUAL; |
||||
|
} |
||||
|
if (AuditConstants.SUGGESTION_BLOCK.equals(suggestion)) { |
||||
|
return AuditConstants.RESULT_FAILED; |
||||
|
} |
||||
|
return AuditConstants.RESULT_PASSED; |
||||
|
} |
||||
|
|
||||
|
// ================================================================
|
||||
|
// 结果汇总
|
||||
|
// ================================================================
|
||||
|
|
||||
|
/** |
||||
|
* 汇总所有任务结果,更新 audit 最终状态。 |
||||
|
* <p> |
||||
|
* 汇总规则: |
||||
|
* - 任一 task.result = failed → audit.status = failed |
||||
|
* - 有 task.result = to_manual → audit.status = manual_review |
||||
|
* - 全部 task.result = passed → audit.status = passed |
||||
|
* - 视频任务未完成(result 为 null)→ 保持 reviewing |
||||
|
* </pre> |
||||
|
* <p> |
||||
|
* MiniContentAudit 字段含义: |
||||
|
* - status: reviewing(机审中) / passed(通过) / failed(不通过) / manual_review(待人工) / appealing(申诉中) |
||||
|
* - final_result: passed / failed / manual_review |
||||
|
*/ |
||||
|
private Map<String, Object> aggregateTaskResultsAndUpdateAudit(Long auditId, List<MiniContentAuditTask> tasks) { |
||||
|
boolean hasFailedTask = false; |
||||
|
boolean hasManualTask = false; |
||||
|
boolean allTasksPassed = true; |
||||
|
|
||||
|
for (MiniContentAuditTask task : tasks) { |
||||
|
String taskResult = task.getResult(); |
||||
|
|
||||
|
if (AuditConstants.RESULT_FAILED.equals(taskResult)) { |
||||
|
hasFailedTask = true; |
||||
|
allTasksPassed = false; |
||||
|
break; // 已有 failed,无需继续遍历
|
||||
|
} |
||||
|
if (AuditConstants.TASK_TO_MANUAL.equals(taskResult) |
||||
|
|| AuditConstants.TASK_TO_MANUAL.equals(task.getStatus())) { |
||||
|
hasManualTask = true; |
||||
|
allTasksPassed = false; |
||||
|
} else if (!AuditConstants.RESULT_PASSED.equals(taskResult)) { |
||||
|
// result 为 null 或其他未知值 → 未完成
|
||||
|
allTasksPassed = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 视频任务 result 为 null 时, 不能算通过
|
||||
|
for (MiniContentAuditTask task : tasks) { |
||||
|
if ("video".equals(task.getContentType()) && task.getResult() == null) { |
||||
|
allTasksPassed = false; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 根据汇总结果确定 audit 状态
|
||||
|
String auditStatus; |
||||
|
String finalResultValue; |
||||
|
|
||||
|
if (hasFailedTask) { |
||||
|
auditStatus = AuditConstants.AUDIT_FAILED; |
||||
|
finalResultValue = "failed"; |
||||
|
} else if (hasManualTask) { |
||||
|
auditStatus = AuditConstants.AUDIT_MANUAL_REVIEW; |
||||
|
finalResultValue = "manual_review"; |
||||
|
} else if (allTasksPassed && !tasks.isEmpty()) { |
||||
|
auditStatus = AuditConstants.AUDIT_PASSED; |
||||
|
finalResultValue = "passed"; |
||||
|
} else { |
||||
|
// 有任务未完成(如视频异步等待中)
|
||||
|
auditStatus = AuditConstants.AUDIT_REVIEWING; |
||||
|
finalResultValue = null; |
||||
|
} |
||||
|
|
||||
|
// 汇总结果已确定则更新 audit 表
|
||||
|
if (finalResultValue != null) { |
||||
|
// ContentAuditService.updateAuditStatus:按 auditId 更新 status 和 final_result
|
||||
|
contentAuditService.updateAuditStatus(auditId, auditStatus, finalResultValue); |
||||
|
} |
||||
|
|
||||
|
// 返回给业务层的审核结果
|
||||
|
Map<String, Object> resultMap = new HashMap<>(); |
||||
|
resultMap.put("status", auditStatus); |
||||
|
resultMap.put("auditId", auditId); |
||||
|
return resultMap; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
package com.youlai.boot.admin.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.util.IdUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import com.youlai.boot.admin.converter.AuditConfigConverter; |
||||
|
import com.youlai.boot.admin.mapper.MiniContentAuditConfigMapper; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditConfig; |
||||
|
import com.youlai.boot.admin.model.form.AuditConfigForm; |
||||
|
import com.youlai.boot.admin.model.query.AuditConfigQuery; |
||||
|
import com.youlai.boot.admin.model.vo.AuditConfigVO; |
||||
|
import com.youlai.boot.admin.service.ContentAuditConfigService; |
||||
|
import com.youlai.boot.common.exception.MsgException; |
||||
|
import com.youlai.boot.framework.security.util.SecurityUtils; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
public class ContentAuditConfigServiceImpl extends ServiceImpl<MiniContentAuditConfigMapper, MiniContentAuditConfig> implements ContentAuditConfigService { |
||||
|
|
||||
|
private final AuditConfigConverter auditConfigConverter; |
||||
|
|
||||
|
@Override |
||||
|
public IPage<AuditConfigVO> pageConfig(AuditConfigQuery query) { |
||||
|
Page<MiniContentAuditConfig> page = new Page<>(query.getPageNum(), query.getPageSize()); |
||||
|
LambdaQueryWrapper<MiniContentAuditConfig> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(query.getModuleCode() != null && !query.getModuleCode().isBlank(), |
||||
|
MiniContentAuditConfig::getModuleCode, query.getModuleCode()); |
||||
|
wrapper.orderByDesc(MiniContentAuditConfig::getCreateTime); |
||||
|
Page<MiniContentAuditConfig> result = this.page(page, wrapper); |
||||
|
return auditConfigConverter.toPageVo(result); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AuditConfigVO getConfigByUuid(String uuid) { |
||||
|
MiniContentAuditConfig entity = getByUuidOrThrow(uuid); |
||||
|
return auditConfigConverter.toVo(entity); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AuditConfigVO addConfig(AuditConfigForm form) { |
||||
|
// 同一 moduleCode 只能有一条配置
|
||||
|
long count = this.count(new LambdaQueryWrapper<MiniContentAuditConfig>() |
||||
|
.eq(MiniContentAuditConfig::getModuleCode, form.getModuleCode())); |
||||
|
if (count > 0) { |
||||
|
throw new MsgException("该业务模块已存在审核配置"); |
||||
|
} |
||||
|
|
||||
|
MiniContentAuditConfig entity = auditConfigConverter.toEntity(form); |
||||
|
entity.setUuid(IdUtil.fastSimpleUUID()); |
||||
|
entity.setCreateBy(SecurityUtils.getUserId()); |
||||
|
entity.setCreateTime(new Date()); |
||||
|
this.save(entity); |
||||
|
return auditConfigConverter.toVo(entity); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AuditConfigVO updateConfig(String uuid, AuditConfigForm form) { |
||||
|
MiniContentAuditConfig entity = getByUuidOrThrow(uuid); |
||||
|
|
||||
|
// 如果修改了 moduleCode,校验唯一性
|
||||
|
if (!entity.getModuleCode().equals(form.getModuleCode())) { |
||||
|
long count = this.count(new LambdaQueryWrapper<MiniContentAuditConfig>() |
||||
|
.eq(MiniContentAuditConfig::getModuleCode, form.getModuleCode()) |
||||
|
.ne(MiniContentAuditConfig::getId, entity.getId())); |
||||
|
if (count > 0) { |
||||
|
throw new MsgException("该业务模块已存在审核配置"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
entity.setModuleCode(form.getModuleCode()); |
||||
|
entity.setAuditEnable(form.getAuditEnable()); |
||||
|
entity.setAuditType(form.getAuditType()); |
||||
|
entity.setRiskStrategy(form.getRiskStrategy()); |
||||
|
entity.setUpdateBy(SecurityUtils.getUserId()); |
||||
|
entity.setUpdateTime(new Date()); |
||||
|
this.updateById(entity); |
||||
|
return auditConfigConverter.toVo(entity); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void deleteConfig(String uuid) { |
||||
|
MiniContentAuditConfig entity = getByUuidOrThrow(uuid); |
||||
|
entity.setDeleted(true); |
||||
|
entity.setUpdateBy(SecurityUtils.getUserId()); |
||||
|
entity.setUpdateTime(new Date()); |
||||
|
this.updateById(entity); |
||||
|
} |
||||
|
|
||||
|
private MiniContentAuditConfig getByUuidOrThrow(String uuid) { |
||||
|
MiniContentAuditConfig entity = this.getOne(new LambdaQueryWrapper<MiniContentAuditConfig>() |
||||
|
.eq(MiniContentAuditConfig::getUuid, uuid)); |
||||
|
if (entity == null) { |
||||
|
throw new MsgException("审核配置不存在"); |
||||
|
} |
||||
|
return entity; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
package com.youlai.boot.admin.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.util.IdUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import com.youlai.boot.admin.constant.AuditConstants; |
||||
|
import com.youlai.boot.admin.mapper.MiniContentAuditMapper; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAudit; |
||||
|
import com.youlai.boot.admin.service.ContentAuditService; |
||||
|
import com.youlai.boot.framework.security.util.SecurityUtils; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Service |
||||
|
public class ContentAuditServiceImpl extends ServiceImpl<MiniContentAuditMapper, MiniContentAudit> implements ContentAuditService { |
||||
|
|
||||
|
@Override |
||||
|
public MiniContentAudit createAudit(String moduleCode, String bizId, String auditType) { |
||||
|
MiniContentAudit entity = new MiniContentAudit(); |
||||
|
entity.setUuid(IdUtil.fastSimpleUUID()); |
||||
|
entity.setModuleCode(moduleCode); |
||||
|
entity.setBizId(bizId); |
||||
|
entity.setAuditType(auditType); |
||||
|
entity.setStatus(AuditConstants.AUDIT_REVIEWING); |
||||
|
entity.setCreateBy(SecurityUtils.getUserId()); |
||||
|
entity.setCreateTime(new Date()); |
||||
|
entity.setCreateTimestamp(System.currentTimeMillis()); |
||||
|
this.save(entity); |
||||
|
return entity; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void updateAuditStatus(Long auditId, String status, String finalResult) { |
||||
|
MiniContentAudit entity = new MiniContentAudit(); |
||||
|
entity.setId(auditId); |
||||
|
entity.setStatus(status); |
||||
|
entity.setFinalResult(finalResult); |
||||
|
entity.setUpdateBy(SecurityUtils.getUserId()); |
||||
|
entity.setUpdateTime(new Date()); |
||||
|
entity.setUpdateTimestamp(System.currentTimeMillis()); |
||||
|
this.updateById(entity); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public MiniContentAudit getByModuleAndBizId(String moduleCode, String bizId) { |
||||
|
return this.getOne(new LambdaQueryWrapper<MiniContentAudit>() |
||||
|
.eq(MiniContentAudit::getModuleCode, moduleCode) |
||||
|
.eq(MiniContentAudit::getBizId, bizId)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,100 @@ |
|||||
|
package com.youlai.boot.admin.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.util.IdUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import com.youlai.boot.admin.constant.AuditConstants; |
||||
|
import com.youlai.boot.admin.mapper.MiniContentAuditTaskMapper; |
||||
|
import com.youlai.boot.admin.model.entity.MiniContentAuditTask; |
||||
|
import com.youlai.boot.admin.service.ContentAuditTaskService; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Service |
||||
|
public class ContentAuditTaskServiceImpl extends ServiceImpl<MiniContentAuditTaskMapper, MiniContentAuditTask> implements ContentAuditTaskService { |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void batchCreateTasks(Long auditId, String auditType, List<String> texts, List<String> images, List<String> videos) { |
||||
|
List<MiniContentAuditTask> tasks = new ArrayList<>(); |
||||
|
Date now = new Date(); |
||||
|
Long nowTs = System.currentTimeMillis(); |
||||
|
|
||||
|
// 文本内容:每条文本单独一个任务
|
||||
|
if (texts != null) { |
||||
|
for (String text : texts) { |
||||
|
if (text != null && !text.isBlank()) { |
||||
|
tasks.add(buildTask(auditId, auditType, "text", text, now, nowTs)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 图片内容:每张图片URL单独一个任务
|
||||
|
if (images != null) { |
||||
|
for (String imageUrl : images) { |
||||
|
if (imageUrl != null && !imageUrl.isBlank()) { |
||||
|
tasks.add(buildTask(auditId, auditType, "image", imageUrl, now, nowTs)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 视频内容:每个视频URL单独一个任务
|
||||
|
if (videos != null) { |
||||
|
for (String videoUrl : videos) { |
||||
|
if (videoUrl != null && !videoUrl.isBlank()) { |
||||
|
tasks.add(buildTask(auditId, auditType, "video", videoUrl, now, nowTs)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!tasks.isEmpty()) { |
||||
|
// MyBatis-Plus saveBatch:批量插入任务记录
|
||||
|
this.saveBatch(tasks); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构建单个审核任务实体 |
||||
|
* MiniContentAuditTask字段:uuid(前端交互) / contentAuditId(关联汇总) / contentType(内容类型) / contentValue(待审核值) |
||||
|
* / auditType(审核类型) / status(任务状态) / createTime / createTimestamp |
||||
|
*/ |
||||
|
private MiniContentAuditTask buildTask(Long auditId, String auditType, String contentType, String contentValue, Date now, Long nowTs) { |
||||
|
MiniContentAuditTask task = new MiniContentAuditTask(); |
||||
|
task.setUuid(IdUtil.fastSimpleUUID()); |
||||
|
task.setContentAuditId(auditId); |
||||
|
task.setContentType(contentType); |
||||
|
task.setContentValue(contentValue); |
||||
|
task.setAuditType(auditType); |
||||
|
task.setStatus(AuditConstants.TASK_REVIEWING); |
||||
|
task.setCreateTime(now); |
||||
|
task.setCreateTimestamp(nowTs); |
||||
|
return task; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void updateTaskMachineResult(Long taskId, String machineResult, String riskLevel, String result, String status) { |
||||
|
MiniContentAuditTask entity = new MiniContentAuditTask(); |
||||
|
entity.setId(taskId); |
||||
|
// machineResult 字段存储阿里云机审返回的完整JSON,供后续复查
|
||||
|
entity.setMachineResult(machineResult); |
||||
|
// riskLevel 字段:none(低风险) / medium(中风险) / high(高风险)
|
||||
|
entity.setRiskLevel(riskLevel); |
||||
|
// result 字段:passed(通过) / failed(不通过),由策略映射得到
|
||||
|
entity.setResult(result); |
||||
|
// status 字段:success(机审完成) / to_manual(转人工),最终状态
|
||||
|
entity.setStatus(status); |
||||
|
entity.setUpdateTime(new Date()); |
||||
|
entity.setUpdateTimestamp(System.currentTimeMillis()); |
||||
|
// MyBatis-Plus updateById:按主键id更新指定字段
|
||||
|
this.updateById(entity); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MiniContentAuditTask> listTasksByAuditId(Long auditId) { |
||||
|
// LambdaQueryWrapper:构建查询条件 content_audit_id = auditId
|
||||
|
return this.list(new LambdaQueryWrapper<MiniContentAuditTask>() |
||||
|
.eq(MiniContentAuditTask::getContentAuditId, auditId)); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue