software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,342 @@
/*
* 自然写教学资源管理与内容分发系统软件 V1.0
* service/AuditService.java - 内容审核服务
*/
package com.writech.resource.service;
import java.util.*;
import java.util.logging.Logger;
/**
* 内容审核服务
*
* 教师上传的资源需经过管理员审核后才能被其他用户检索和使用。
* 审核流程支持:
* - 自动预审(AI内容安全检测)
* - 人工审核(管理员审核通过/驳回/退回修改)
* - 审核记录全程留痕
* - 批量审核
*/
public class AuditService {
private static final Logger logger =
Logger.getLogger(AuditService.class.getName());
// ============================================================
// 审核数据模型
// ============================================================
/** 审核操作类型 */
public enum AuditAction {
APPROVE, // 审核通过
REJECT, // 驳回
RETURN, // 退回修改
WITHDRAW // 上传者撤回
}
/** 审核记录(对应MySQL audit_record表) */
public static class AuditRecord {
private String id;
private String resourceId;
private String resourceName;
private String auditorId; // 审核人ID
private String auditorName; // 审核人姓名
private AuditAction action;
private String comment; // 审核意见
private String preStatus; // 审核前状态
private String postStatus; // 审核后状态
private Date createdAt;
// Getter/Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getResourceId() { return resourceId; }
public void setResourceId(String rid) { this.resourceId = rid; }
public String getResourceName() { return resourceName; }
public void setResourceName(String name) { this.resourceName = name; }
public String getAuditorId() { return auditorId; }
public void setAuditorId(String id) { this.auditorId = id; }
public AuditAction getAction() { return action; }
public void setAction(AuditAction action) { this.action = action; }
public String getComment() { return comment; }
public void setComment(String comment) { this.comment = comment; }
public Date getCreatedAt() { return createdAt; }
}
/** 审核请求 */
public static class AuditRequest {
private String resourceId;
private AuditAction action;
private String comment;
private String auditorId;
public String getResourceId() { return resourceId; }
public void setResourceId(String id) { this.resourceId = id; }
public AuditAction getAction() { return action; }
public void setAction(AuditAction action) { this.action = action; }
public String getComment() { return comment; }
public void setComment(String c) { this.comment = c; }
public String getAuditorId() { return auditorId; }
public void setAuditorId(String id) { this.auditorId = id; }
}
/** 自动预审结果 */
public static class PreAuditResult {
private boolean safe;
private double safeScore; // 安全评分(0-1
private List<String> warnings; // 警告信息
private String category; // 内容分类
public PreAuditResult(boolean safe, double score) {
this.safe = safe;
this.safeScore = score;
this.warnings = new ArrayList<>();
}
public boolean isSafe() { return safe; }
public double getSafeScore() { return safeScore; }
public List<String> getWarnings() { return warnings; }
public void addWarning(String w) { this.warnings.add(w); }
}
// ============================================================
// 审核业务方法
// ============================================================
/**
* 执行审核操作 PUT /api/v1/resource/audit/{id}
*
* @param request 审核请求
* @return 审核结果
*/
public Map<String, Object> performAudit(AuditRequest request) {
logger.info(String.format(
"执行审核: resource=%s, action=%s, auditor=%s",
request.getResourceId(), request.getAction(), request.getAuditorId()
));
// 查询资源当前状态
// ResourceMetadata resource = resourceMapper.selectById(request.getResourceId());
// if (resource == null) {
// return errorResponse(404, "资源不存在");
// }
// 状态机校验:只有PENDING状态可被审核
// if (resource.getAuditStatus() != AuditStatus.PENDING) {
// return errorResponse(400, "当前状态不可审核");
// }
// 创建审核记录
AuditRecord record = new AuditRecord();
record.setId(UUID.randomUUID().toString().replace("-", ""));
record.setResourceId(request.getResourceId());
record.setAuditorId(request.getAuditorId());
record.setAction(request.getAction());
record.setComment(request.getComment());
record.setPreStatus("PENDING");
// 根据审核动作更新资源状态
String newStatus;
switch (request.getAction()) {
case APPROVE:
newStatus = "APPROVED";
// 审核通过后,同步更新Elasticsearch索引状态
// updateEsAuditStatus(request.getResourceId(), "APPROVED");
// 预热CDN缓存(使资源可被终端下载)
// cdnService.preheatResource(request.getResourceId());
break;
case REJECT:
newStatus = "REJECTED";
break;
case RETURN:
newStatus = "PENDING"; // 退回修改后重新提交
break;
default:
newStatus = "PENDING";
}
record.setPostStatus(newStatus);
// 持久化
// auditRecordMapper.insert(record);
// resourceMapper.updateAuditStatus(request.getResourceId(), newStatus);
// 通知上传者审核结果(消息推送)
// notifyUploader(request.getResourceId(), request.getAction(), request.getComment());
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("message", "审核操作成功");
result.put("data", Map.of(
"resource_id", request.getResourceId(),
"new_status", newStatus,
"audit_record_id", record.getId()
));
return result;
}
/**
* 批量审核
*
* @param resourceIds 资源ID列表
* @param action 审核动作
* @param comment 审核意见
* @param auditorId 审核人
* @return 批量审核结果
*/
public Map<String, Object> batchAudit(
List<String> resourceIds,
AuditAction action,
String comment,
String auditorId
) {
logger.info(String.format(
"批量审核: count=%d, action=%s", resourceIds.size(), action
));
int successCount = 0;
int failCount = 0;
List<String> failedIds = new ArrayList<>();
for (String resourceId : resourceIds) {
try {
AuditRequest request = new AuditRequest();
request.setResourceId(resourceId);
request.setAction(action);
request.setComment(comment);
request.setAuditorId(auditorId);
Map<String, Object> result = performAudit(request);
if ((int) result.get("code") == 0) {
successCount++;
} else {
failCount++;
failedIds.add(resourceId);
}
} catch (Exception e) {
failCount++;
failedIds.add(resourceId);
logger.warning("批量审核失败: resource=" + resourceId + ", error=" + e.getMessage());
}
}
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("data", Map.of(
"total", resourceIds.size(),
"success", successCount,
"failed", failCount,
"failed_ids", failedIds
));
return result;
}
/**
* AI自动预审
*
* 在人工审核前,自动进行内容安全检测:
* - 文本内容是否包含违禁词
* - 图片是否包含不当内容
* - 文件格式是否合规
* - 文件大小是否超限
*
* @param resourceId 资源ID
* @return 预审结果
*/
public PreAuditResult performPreAudit(String resourceId) {
logger.info("AI预审: resource=" + resourceId);
PreAuditResult result = new PreAuditResult(true, 1.0);
// 1. 文件格式和大小检查
// ResourceMetadata resource = resourceMapper.selectById(resourceId);
// if (resource.getFileSize() > MAX_FILE_SIZE) {
// result = new PreAuditResult(false, 0.0);
// result.addWarning("文件大小超过限制");
// return result;
// }
// 2. 文本内容安全检测(提取PDF/PPT中的文字进行违禁词检查)
// String textContent = extractTextContent(resource.getFileKey());
// ContentSafetyResult textSafety = contentSafetyApi.checkText(textContent);
// if (!textSafety.isSafe()) {
// result.addWarning("文本内容包含敏感词: " + textSafety.getDetails());
// }
// 3. 图片内容安全检测(提取文档中的图片进行AI审核)
// List<byte[]> images = extractImages(resource.getFileKey());
// for (byte[] image : images) {
// ImageSafetyResult imageSafety = contentSafetyApi.checkImage(image);
// if (!imageSafety.isSafe()) {
// result.addWarning("图片内容不合规: " + imageSafety.getCategory());
// }
// }
// 综合评分
if (!result.getWarnings().isEmpty()) {
double penalty = result.getWarnings().size() * 0.2;
double finalScore = Math.max(0.0, 1.0 - penalty);
result = new PreAuditResult(finalScore >= 0.6, finalScore);
}
logger.info(String.format(
"预审完成: resource=%s, safe=%b, score=%.2f",
resourceId, result.isSafe(), result.getSafeScore()
));
return result;
}
/**
* 查询审核记录列表
*
* @param resourceId 资源ID(可选,为空则查所有)
* @param auditorId 审核人ID(可选)
* @param page 页码
* @param pageSize 每页大小
* @return 审核记录列表
*/
public Map<String, Object> queryAuditRecords(
String resourceId,
String auditorId,
int page,
int pageSize
) {
logger.info(String.format(
"查询审核记录: resource=%s, auditor=%s, page=%d",
resourceId, auditorId, page
));
// List<AuditRecord> records = auditRecordMapper.selectByCondition(
// resourceId, auditorId, page, pageSize
// );
// int total = auditRecordMapper.countByCondition(resourceId, auditorId);
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("data", Map.of(
"total", 0,
"page", page,
"items", new ArrayList<>()
));
return result;
}
/**
* 获取待审核资源数量(仪表盘统计用)
*/
public Map<String, Object> getAuditStats() {
// int pendingCount = resourceMapper.countByStatus("PENDING");
// int approvedToday = auditRecordMapper.countTodayByAction("APPROVE");
// int rejectedToday = auditRecordMapper.countTodayByAction("REJECT");
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("data", Map.of(
"pending_count", 0,
"approved_today", 0,
"rejected_today", 0
));
return result;
}
}