课程、文章审核
This commit is contained in:
@@ -84,6 +84,7 @@ CREATE TABLE `tb_course_node` (
|
|||||||
`duration` INT(11) DEFAULT 0 COMMENT '节点时长(分钟)',
|
`duration` INT(11) DEFAULT 0 COMMENT '节点时长(分钟)',
|
||||||
`order_num` INT(4) DEFAULT 0 COMMENT '排序号',
|
`order_num` INT(4) DEFAULT 0 COMMENT '排序号',
|
||||||
`is_required` TINYINT(1) DEFAULT 1 COMMENT '是否必修(1必修 0选修)',
|
`is_required` TINYINT(1) DEFAULT 1 COMMENT '是否必修(1必修 0选修)',
|
||||||
|
`is_audited` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已审核',
|
||||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||||
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
||||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ CREATE TABLE `tb_data_collection_item` (
|
|||||||
`images` TEXT DEFAULT NULL COMMENT '图片列表(JSON)',
|
`images` TEXT DEFAULT NULL COMMENT '图片列表(JSON)',
|
||||||
`tags` VARCHAR(500) DEFAULT NULL COMMENT '标签(逗号分隔)',
|
`tags` VARCHAR(500) DEFAULT NULL COMMENT '标签(逗号分隔)',
|
||||||
`status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '状态(0未处理 1已转换为资源 2已忽略)',
|
`status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '状态(0未处理 1已转换为资源 2已忽略)',
|
||||||
|
`is_audited` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已审核',
|
||||||
`execute_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '执行状态(0未执行 1已执行)',
|
`execute_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '执行状态(0未执行 1已执行)',
|
||||||
`execute_message` TEXT DEFAULT NULL COMMENT '执行结果信息',
|
`execute_message` TEXT DEFAULT NULL COMMENT '执行结果信息',
|
||||||
`resource_id` VARCHAR(64) DEFAULT NULL COMMENT '转换后的资源ID',
|
`resource_id` VARCHAR(64) DEFAULT NULL COMMENT '转换后的资源ID',
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ CREATE TABLE `tb_resource` (
|
|||||||
`like_count` INT(11) DEFAULT 0 COMMENT '点赞次数',
|
`like_count` INT(11) DEFAULT 0 COMMENT '点赞次数',
|
||||||
`collect_count` INT(11) DEFAULT 0 COMMENT '收藏次数',
|
`collect_count` INT(11) DEFAULT 0 COMMENT '收藏次数',
|
||||||
`status` INT(4) DEFAULT 0 COMMENT '状态(0草稿 1已发布 2下架)',
|
`status` INT(4) DEFAULT 0 COMMENT '状态(0草稿 1已发布 2下架)',
|
||||||
|
`is_audited` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已审核',
|
||||||
`is_recommend` TINYINT(1) DEFAULT 0 COMMENT '是否推荐',
|
`is_recommend` TINYINT(1) DEFAULT 0 COMMENT '是否推荐',
|
||||||
`is_banner` TINYINT(1) DEFAULT 0 COMMENT '是否轮播',
|
`is_banner` TINYINT(1) DEFAULT 0 COMMENT '是否轮播',
|
||||||
`publish_time` TIMESTAMP NULL DEFAULT NULL COMMENT '发布时间',
|
`publish_time` TIMESTAMP NULL DEFAULT NULL COMMENT '发布时间',
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.xyzh.api.news.resource;
|
||||||
|
|
||||||
|
import org.xyzh.common.core.domain.ResultDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 资源审核服务接口
|
||||||
|
* @filename ResourceAuditService.java
|
||||||
|
* @author yslg
|
||||||
|
*/
|
||||||
|
public interface ResourceAuditService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本内容审核
|
||||||
|
* @param text 待审核文本
|
||||||
|
* @return ResultDomain<Boolean> 审核结果(true 表示通过)
|
||||||
|
*/
|
||||||
|
ResultDomain<Boolean> auditText(String text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件ID进行审核(fileId 对应 tb_sys_file.id)
|
||||||
|
* @param fileId 文件ID
|
||||||
|
* @return ResultDomain<Boolean> 审核结果(true 表示通过)
|
||||||
|
*/
|
||||||
|
ResultDomain<Boolean> auditByFileId(String fileId);
|
||||||
|
}
|
||||||
@@ -115,6 +115,19 @@ public class TbDataCollectionItem extends BaseDTO {
|
|||||||
*/
|
*/
|
||||||
private String executeMessage;
|
private String executeMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否已审核
|
||||||
|
*/
|
||||||
|
private Boolean isAudited;
|
||||||
|
|
||||||
|
public Boolean getIsAudited() {
|
||||||
|
return isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAudited(Boolean isAudited) {
|
||||||
|
this.isAudited = isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
public String getTaskId() {
|
public String getTaskId() {
|
||||||
return taskId;
|
return taskId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ public class TbResource extends BaseDTO {
|
|||||||
*/
|
*/
|
||||||
private Boolean isRecommend;
|
private Boolean isRecommend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否已审核
|
||||||
|
*/
|
||||||
|
private Boolean isAudited;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 是否轮播
|
* @description 是否轮播
|
||||||
*/
|
*/
|
||||||
@@ -176,6 +181,16 @@ public class TbResource extends BaseDTO {
|
|||||||
this.sourceUrl = sourceUrl;
|
this.sourceUrl = sourceUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean getIsAudited() {
|
||||||
|
return isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAudited(Boolean isAudited) {
|
||||||
|
this.isAudited = isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getViewCount() {
|
public Integer getViewCount() {
|
||||||
return viewCount;
|
return viewCount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,18 @@ public class TbCourseNode extends BaseDTO {
|
|||||||
* @description 是否删除
|
* @description 是否删除
|
||||||
*/
|
*/
|
||||||
private Boolean deleted;
|
private Boolean deleted;
|
||||||
|
/**
|
||||||
|
* @description 是否已审核
|
||||||
|
*/
|
||||||
|
private Boolean isAudited;
|
||||||
|
|
||||||
|
public Boolean getIsAudited() {
|
||||||
|
return isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAudited(Boolean isAudited) {
|
||||||
|
this.isAudited = isAudited;
|
||||||
|
}
|
||||||
public String getNodeID() {
|
public String getNodeID() {
|
||||||
return nodeID;
|
return nodeID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ public class DataCollectionItemVO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已审核
|
||||||
|
*/
|
||||||
|
private Boolean isAudited;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换后的资源ID
|
* 转换后的资源ID
|
||||||
*/
|
*/
|
||||||
@@ -194,6 +199,14 @@ public class DataCollectionItemVO implements Serializable {
|
|||||||
|
|
||||||
// ==================== Getter/Setter ====================
|
// ==================== Getter/Setter ====================
|
||||||
|
|
||||||
|
public Boolean getIsAudited() {
|
||||||
|
return isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAudited(Boolean isAudited) {
|
||||||
|
this.isAudited = isAudited;
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.xyzh.api.crontab.DataCollectionItemService;
|
|||||||
import org.xyzh.api.crontab.EmailDefaultService;
|
import org.xyzh.api.crontab.EmailDefaultService;
|
||||||
import org.xyzh.api.crontab.EmailRecipientService;
|
import org.xyzh.api.crontab.EmailRecipientService;
|
||||||
import org.xyzh.api.crontab.TaskMetaService;
|
import org.xyzh.api.crontab.TaskMetaService;
|
||||||
|
import org.xyzh.api.news.resource.ResourceAuditService;
|
||||||
import org.xyzh.api.news.resource.ResourceService;
|
import org.xyzh.api.news.resource.ResourceService;
|
||||||
import org.xyzh.api.system.role.RoleService;
|
import org.xyzh.api.system.role.RoleService;
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
import org.xyzh.common.core.domain.ResultDomain;
|
||||||
@@ -66,6 +67,9 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmailRecipientService emailRecipientService;
|
private EmailRecipientService emailRecipientService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceAuditService auditService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmailUtils emailUtils;
|
private EmailUtils emailUtils;
|
||||||
|
|
||||||
@@ -196,7 +200,6 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
logger.info("开始保存 {} 条新闻到数据库,任务ID: {},日志ID: {}", newsList.size(), taskId, logId);
|
logger.info("开始保存 {} 条新闻到数据库,任务ID: {},日志ID: {}", newsList.size(), taskId, logId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<TbDataCollectionItem> itemList = new ArrayList<>();
|
|
||||||
ResultDomain<TbCrontabTaskMeta> metaResult = taskMetaService.getTaskMetaByTaskId(taskId);
|
ResultDomain<TbCrontabTaskMeta> metaResult = taskMetaService.getTaskMetaByTaskId(taskId);
|
||||||
if (!metaResult.isSuccess() || metaResult.getData() == null) {
|
if (!metaResult.isSuccess() || metaResult.getData() == null) {
|
||||||
throw new Exception("未找到任务元数据: taskId=" + taskId);
|
throw new Exception("未找到任务元数据: taskId=" + taskId);
|
||||||
@@ -206,7 +209,9 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
SimpleDateFormat parser = new SimpleDateFormat("yyyy年MM月dd日HH:mm");
|
SimpleDateFormat parser = new SimpleDateFormat("yyyy年MM月dd日HH:mm");
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
List<TbDataCollectionItem> itemList = new ArrayList<>();
|
||||||
|
List<TbDataCollectionItem> notPassList = new ArrayList<>();
|
||||||
|
List<TbDataCollectionItem> passList = new ArrayList<>();
|
||||||
for (ArticleStruct news : newsList) {
|
for (ArticleStruct news : newsList) {
|
||||||
try {
|
try {
|
||||||
TbDataCollectionItem item = new TbDataCollectionItem();
|
TbDataCollectionItem item = new TbDataCollectionItem();
|
||||||
@@ -260,7 +265,14 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
// 状态和时间
|
// 状态和时间
|
||||||
item.setStatus(0); // 未处理
|
item.setStatus(0); // 未处理
|
||||||
item.setCrawlTime(now);
|
item.setCrawlTime(now);
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditText(item.getContent());
|
||||||
|
if(pass.isSuccess() && pass.getData()){
|
||||||
|
item.setIsAudited(true);
|
||||||
|
passList.add(item);
|
||||||
|
}else{
|
||||||
|
item.setIsAudited(false);
|
||||||
|
notPassList.add(item);
|
||||||
|
}
|
||||||
itemList.add(item);
|
itemList.add(item);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("转换新闻数据失败: ", e);
|
logger.error("转换新闻数据失败: ", e);
|
||||||
@@ -269,26 +281,40 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
|
|
||||||
// 批量保存
|
// 批量保存
|
||||||
Set<String> insertedUrls = new HashSet<>();
|
Set<String> insertedUrls = new HashSet<>();
|
||||||
ResultDomain<TbDataCollectionItem> dataResult = new ResultDomain<>();
|
ResultDomain<TbDataCollectionItem> passDataResult = new ResultDomain<>();
|
||||||
if (!itemList.isEmpty()) {
|
if (!passList.isEmpty()) {
|
||||||
dataResult = itemService.batchCreateItems(itemList);
|
passDataResult = itemService.batchCreateItems(passList);
|
||||||
if (dataResult.isSuccess()) {
|
if (passDataResult.isSuccess()) {
|
||||||
logger.info("成功保存 {} 条新闻到数据库", itemList.size());
|
logger.info("成功保存 {} 条新闻到数据库", passList.size());
|
||||||
insertedUrls.addAll(dataResult.getDataList().stream().map(TbDataCollectionItem::getSourceUrl).toList());
|
insertedUrls.addAll(passDataResult.getDataList().stream().map(TbDataCollectionItem::getSourceUrl).toList());
|
||||||
} else {
|
} else {
|
||||||
logger.error("保存新闻到数据库失败: {}", dataResult.getMessage());
|
logger.error("保存新闻到数据库失败: {}", passDataResult.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("没有有效的新闻数据需要保存");
|
logger.warn("没有有效的新闻数据需要保存");
|
||||||
}
|
}
|
||||||
|
ResultDomain<TbDataCollectionItem> notPassDataResult = new ResultDomain<>();
|
||||||
|
if (!notPassList.isEmpty()) {
|
||||||
|
notPassDataResult = itemService.batchCreateItems(notPassList);
|
||||||
|
if (notPassDataResult.isSuccess()) {
|
||||||
|
logger.info("成功保存 {} 条新闻到数据库", notPassList.size());
|
||||||
|
insertedUrls.addAll(notPassDataResult.getDataList().stream().map(TbDataCollectionItem::getSourceUrl).toList());
|
||||||
|
} else {
|
||||||
|
logger.error("保存新闻到数据库失败: {}", notPassDataResult.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn("没有有效的新闻数据需要保存");
|
||||||
|
}
|
||||||
|
|
||||||
// 自动发布并记录成功发布的 URL 集合
|
// 自动发布并记录成功发布的 URL 集合
|
||||||
Set<String> publishedUrls = new HashSet<>();
|
Set<String> publishedUrls = new HashSet<>();
|
||||||
if (taskMeta.getAutoPublish().booleanValue()){
|
if (taskMeta.getAutoPublish().booleanValue()){
|
||||||
publishedUrls = publishNewsToArticle(dataResult.getDataList(), task, logId);
|
publishedUrls = publishNewsToArticle(passDataResult.getDataList(), task, logId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<String> notPathUrls = new HashSet<>(notPassList.stream().map(TbDataCollectionItem::getSourceUrl).toList());
|
||||||
// 发送邮件通知,包含自动发布与新增信息
|
// 发送邮件通知,包含自动发布与新增信息
|
||||||
sendEmailNotification(task.getTaskId(), task, newsList, insertedUrls, publishedUrls);
|
sendEmailNotification(task.getTaskId(), task, newsList, insertedUrls, publishedUrls, notPathUrls);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("保存新闻数据到数据库异常: ", e);
|
logger.error("保存新闻数据到数据库异常: ", e);
|
||||||
@@ -300,7 +326,9 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
*/
|
*/
|
||||||
private void sendEmailNotification(String taskId, TbCrontabTask task, List<ArticleStruct> newsList,
|
private void sendEmailNotification(String taskId, TbCrontabTask task, List<ArticleStruct> newsList,
|
||||||
Set<String> insertedUrls,
|
Set<String> insertedUrls,
|
||||||
Set<String> publishedUrls) {
|
Set<String> publishedUrls,
|
||||||
|
Set<String> notPassUrls
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
List<String> recipients = new ArrayList<>();
|
List<String> recipients = new ArrayList<>();
|
||||||
|
|
||||||
@@ -336,7 +364,7 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
|
|
||||||
// 5. 构建邮件内容
|
// 5. 构建邮件内容
|
||||||
String subject = "【新闻爬虫通知】" + task.getTaskName() + " 执行完成";
|
String subject = "【新闻爬虫通知】" + task.getTaskName() + " 执行完成";
|
||||||
String content = buildEmailContent(task.getTaskName(), newsList, insertedUrls, publishedUrls);
|
String content = buildEmailContent(task.getTaskName(), newsList, insertedUrls, publishedUrls, notPassUrls);
|
||||||
|
|
||||||
// 6. 发送邮件
|
// 6. 发送邮件
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
@@ -357,8 +385,9 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
* 构建邮件HTML内容
|
* 构建邮件HTML内容
|
||||||
*/
|
*/
|
||||||
private String buildEmailContent(String taskName, List<ArticleStruct> newsList,
|
private String buildEmailContent(String taskName, List<ArticleStruct> newsList,
|
||||||
java.util.Set<String> insertedUrls,
|
Set<String> insertedUrls,
|
||||||
java.util.Set<String> publishedUrls) {
|
Set<String> publishedUrls,
|
||||||
|
Set<String> notPathUrls) {
|
||||||
StringBuilder html = new StringBuilder();
|
StringBuilder html = new StringBuilder();
|
||||||
html.append("<!DOCTYPE html>")
|
html.append("<!DOCTYPE html>")
|
||||||
.append("<html>")
|
.append("<html>")
|
||||||
@@ -416,6 +445,7 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
html.append(" | <a href='").append(news.getUrl()).append("' class='news-link' target='_blank'>查看原文</a>");
|
html.append(" | <a href='").append(news.getUrl()).append("' class='news-link' target='_blank'>查看原文</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 入库标记(新增 / 历史已存在)
|
// 入库标记(新增 / 历史已存在)
|
||||||
if (news.getUrl() != null && !news.getUrl().isEmpty() && insertedUrls != null) {
|
if (news.getUrl() != null && !news.getUrl().isEmpty() && insertedUrls != null) {
|
||||||
if (insertedUrls.contains(news.getUrl())) {
|
if (insertedUrls.contains(news.getUrl())) {
|
||||||
@@ -425,6 +455,12 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果该未审核通过,追加标记
|
||||||
|
if (notPathUrls != null && !notPathUrls.isEmpty()
|
||||||
|
&& news.getUrl() != null && notPathUrls.contains(news.getUrl())) {
|
||||||
|
html.append(" | <span style='color:#ff0000;font-weight:bold;'>【未通过审核】</span>");
|
||||||
|
}
|
||||||
|
|
||||||
// 如果该新闻已自动发布,追加标记
|
// 如果该新闻已自动发布,追加标记
|
||||||
if (publishedUrls != null && !publishedUrls.isEmpty()
|
if (publishedUrls != null && !publishedUrls.isEmpty()
|
||||||
&& news.getUrl() != null && publishedUrls.contains(news.getUrl())) {
|
&& news.getUrl() != null && publishedUrls.contains(news.getUrl())) {
|
||||||
@@ -435,12 +471,6 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
.append("</div>");
|
.append("</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newsList.size() > 10) {
|
|
||||||
html.append("<p style='text-align: center; color: #666; margin-top: 15px;'>")
|
|
||||||
.append("还有 ").append(newsList.size() - 10).append(" 条新闻未显示,请登录系统查看详情")
|
|
||||||
.append("</p>");
|
|
||||||
}
|
|
||||||
|
|
||||||
html.append("</div>"); // news-list
|
html.append("</div>"); // news-list
|
||||||
html.append("</div>"); // content
|
html.append("</div>"); // content
|
||||||
|
|
||||||
@@ -498,7 +528,7 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
resource.setAuthor(item.getAuthor());
|
resource.setAuthor(item.getAuthor());
|
||||||
resource.setSource(item.getSource());
|
resource.setSource(item.getSource());
|
||||||
resource.setSourceUrl(item.getSourceUrl());
|
resource.setSourceUrl(item.getSourceUrl());
|
||||||
|
resource.setIsAudited(true);
|
||||||
// 发布时间:优先使用采集表中的时间
|
// 发布时间:优先使用采集表中的时间
|
||||||
Date publishTime = item.getPublishTime() != null ? item.getPublishTime() : now;
|
Date publishTime = item.getPublishTime() != null ? item.getPublishTime() : now;
|
||||||
resource.setPublishTime(publishTime);
|
resource.setPublishTime(publishTime);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
<result column="images" property="images" />
|
<result column="images" property="images" />
|
||||||
<result column="tags" property="tags" />
|
<result column="tags" property="tags" />
|
||||||
<result column="status" property="status" />
|
<result column="status" property="status" />
|
||||||
|
<result column="is_audited" property="isAudited" />
|
||||||
<result column="resource_id" property="resourceId" />
|
<result column="resource_id" property="resourceId" />
|
||||||
<result column="crawl_time" property="crawlTime" />
|
<result column="crawl_time" property="crawlTime" />
|
||||||
<result column="process_time" property="processTime" />
|
<result column="process_time" property="processTime" />
|
||||||
@@ -51,6 +52,7 @@
|
|||||||
<result column="images" property="images" />
|
<result column="images" property="images" />
|
||||||
<result column="tags" property="tags" />
|
<result column="tags" property="tags" />
|
||||||
<result column="status" property="status" />
|
<result column="status" property="status" />
|
||||||
|
<result column="is_audited" property="isAudited" />
|
||||||
<result column="resource_id" property="resourceId" />
|
<result column="resource_id" property="resourceId" />
|
||||||
<result column="crawl_time" property="crawlTime" />
|
<result column="crawl_time" property="crawlTime" />
|
||||||
<result column="process_time" property="processTime" />
|
<result column="process_time" property="processTime" />
|
||||||
@@ -77,7 +79,7 @@
|
|||||||
<!-- 字段列表 -->
|
<!-- 字段列表 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, task_id, log_id, title, content, summary, source, source_url, category, author,
|
id, task_id, log_id, title, content, summary, source, source_url, category, author,
|
||||||
publish_time, cover_image, images, tags, status, resource_id, crawl_time, process_time,
|
publish_time, cover_image, images, tags, status, is_audited, resource_id, crawl_time, process_time,
|
||||||
processor, execute_status, execute_message, create_time, update_time, delete_time, deleted
|
processor, execute_status, execute_message, create_time, update_time, delete_time, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -98,6 +100,7 @@
|
|||||||
i.images,
|
i.images,
|
||||||
i.tags,
|
i.tags,
|
||||||
i.status,
|
i.status,
|
||||||
|
i.is_audited,
|
||||||
i.resource_id,
|
i.resource_id,
|
||||||
i.crawl_time,
|
i.crawl_time,
|
||||||
i.process_time,
|
i.process_time,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.xyzh.common.vo.TaskItemVO;
|
|||||||
import org.xyzh.news.mapper.ResourceMapper;
|
import org.xyzh.news.mapper.ResourceMapper;
|
||||||
import org.xyzh.news.mapper.ResourceTagMapper;
|
import org.xyzh.news.mapper.ResourceTagMapper;
|
||||||
import org.xyzh.system.utils.LoginUtil;
|
import org.xyzh.system.utils.LoginUtil;
|
||||||
|
import org.xyzh.api.news.resource.ResourceAuditService;
|
||||||
import org.xyzh.api.news.resource.ResourceService;
|
import org.xyzh.api.news.resource.ResourceService;
|
||||||
import org.xyzh.api.system.permission.ResourcePermissionService;
|
import org.xyzh.api.system.permission.ResourcePermissionService;
|
||||||
import org.xyzh.common.vo.UserDeptRoleVO;
|
import org.xyzh.common.vo.UserDeptRoleVO;
|
||||||
@@ -54,6 +55,9 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ResourcePermissionService resourcePermissionService;
|
private ResourcePermissionService resourcePermissionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceAuditService auditService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResultDomain<TbResource> getResourceList(TbResource filter) {
|
public ResultDomain<TbResource> getResourceList(TbResource filter) {
|
||||||
ResultDomain<TbResource> resultDomain = new ResultDomain<>();
|
ResultDomain<TbResource> resultDomain = new ResultDomain<>();
|
||||||
@@ -256,6 +260,9 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
if (resourceVO.getResource().getStatus() == null) {
|
if (resourceVO.getResource().getStatus() == null) {
|
||||||
resourceVO.getResource().setStatus(0); // 默认草稿状态
|
resourceVO.getResource().setStatus(0); // 默认草稿状态
|
||||||
}
|
}
|
||||||
|
if (resourceVO.getResource().getIsAudited() == null) {
|
||||||
|
resourceVO.getResource().setIsAudited(false); // 默认草稿状态
|
||||||
|
}
|
||||||
if (resourceVO.getResource().getViewCount() == null) {
|
if (resourceVO.getResource().getViewCount() == null) {
|
||||||
resourceVO.getResource().setViewCount(0);
|
resourceVO.getResource().setViewCount(0);
|
||||||
}
|
}
|
||||||
@@ -271,6 +278,14 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
if (resourceVO.getResource().getIsBanner() == null) {
|
if (resourceVO.getResource().getIsBanner() == null) {
|
||||||
resourceVO.getResource().setIsBanner(false);
|
resourceVO.getResource().setIsBanner(false);
|
||||||
}
|
}
|
||||||
|
TbResource resource = resourceVO.getResource();
|
||||||
|
if(resource.getStatus()==1 && !resource.getIsAudited()){
|
||||||
|
// 进行审核
|
||||||
|
ResultDomain<Boolean> pass =auditService.auditText(resource.getContent());
|
||||||
|
if(pass.isSuccess() && pass.getData()){
|
||||||
|
resource.setIsAudited(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 插入数据库
|
// 插入数据库
|
||||||
int result = resourceMapper.insertResource(resourceVO.getResource());
|
int result = resourceMapper.insertResource(resourceVO.getResource());
|
||||||
@@ -345,14 +360,9 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果修改了标题,检查标题是否已被使用
|
resource.setIsAudited(existing.getIsAudited());
|
||||||
if (StringUtils.hasText(resource.getTitle()) && !resource.getTitle().equals(existing.getTitle())) {
|
if(!existing.getContent().equals(resource.getContent())){
|
||||||
List<UserDeptRoleVO> userDeptRoles = LoginUtil.getCurrentDeptRole();
|
resource.setIsAudited(false);
|
||||||
int count = resourceMapper.countByTitle(resource.getTitle(), resource.getResourceID(), userDeptRoles);
|
|
||||||
if (count > 0) {
|
|
||||||
resultDomain.fail("资源标题已存在");
|
|
||||||
return resultDomain;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
// tag先删后增
|
// tag先删后增
|
||||||
@@ -447,7 +457,20 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
resultDomain.fail("资源不存在");
|
resultDomain.fail("资源不存在");
|
||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
if (status == 1 && !resource.getIsAudited()) {
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditText(resource.getContent());
|
||||||
|
if (pass.isSuccess() && pass.getData()) {
|
||||||
|
resource.setIsAudited(true);
|
||||||
|
} else {
|
||||||
|
// 审核失败,标记状态为3(审核失败)
|
||||||
|
resource.setStatus(3);
|
||||||
|
resource.setUpdateTime(new Date());
|
||||||
|
resourceMapper.updateResource(resource);
|
||||||
|
|
||||||
|
resultDomain.fail("审核失败");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
// 更新状态
|
// 更新状态
|
||||||
resource.setStatus(status);
|
resource.setStatus(status);
|
||||||
resource.setUpdateTime(new Date());
|
resource.setUpdateTime(new Date());
|
||||||
@@ -488,6 +511,21 @@ public class NCResourceServiceImpl implements ResourceService {
|
|||||||
return resultDomain;
|
return resultDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!resource.getIsAudited()) {
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditText(resource.getContent());
|
||||||
|
if (pass.isSuccess() && pass.getData()) {
|
||||||
|
resource.setIsAudited(true);
|
||||||
|
} else {
|
||||||
|
// 审核失败,标记状态为3(审核失败)
|
||||||
|
resource.setStatus(3);
|
||||||
|
resource.setUpdateTime(new Date());
|
||||||
|
resourceMapper.updateResource(resource);
|
||||||
|
|
||||||
|
resultDomain.fail("审核失败");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新状态为已发布
|
// 更新状态为已发布
|
||||||
resource.setStatus(1);
|
resource.setStatus(1);
|
||||||
resource.setPublishTime(new Date());
|
resource.setPublishTime(new Date());
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.xyzh.news.service.impl;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.xyzh.api.news.resource.ResourceAuditService;
|
||||||
|
import org.xyzh.common.core.domain.ResultDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 资源审核服务实现类
|
||||||
|
* @filename ResourceAuditServiceImpl.java
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ResourceAuditServiceImpl implements ResourceAuditService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultDomain<Boolean> auditText(String text) {
|
||||||
|
ResultDomain<Boolean> result = new ResultDomain<Boolean>();
|
||||||
|
// TODO: 文本审核逻辑(敏感词、违规词等规则校验)
|
||||||
|
// 示例:直接通过
|
||||||
|
result.success("审核通过", Boolean.TRUE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultDomain<Boolean> auditByFileId(String fileId) {
|
||||||
|
ResultDomain<Boolean> result = new ResultDomain<Boolean>();
|
||||||
|
// TODO:
|
||||||
|
// 1. 根据 tb_sys_file.id 查询文件信息
|
||||||
|
// 2. 读取文件内容,提取文本
|
||||||
|
// 3. 调用 auditText(text) 进行审核
|
||||||
|
// 4. 审核通过后,更新对应业务记录(tb_resource / tb_data_collection_item / tb_course_node) 的 is_audited = 1
|
||||||
|
result.success("审核通过", Boolean.TRUE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
<result column="like_count" property="likeCount" jdbcType="INTEGER"/>
|
<result column="like_count" property="likeCount" jdbcType="INTEGER"/>
|
||||||
<result column="collect_count" property="collectCount" jdbcType="INTEGER"/>
|
<result column="collect_count" property="collectCount" jdbcType="INTEGER"/>
|
||||||
<result column="status" property="status" jdbcType="INTEGER"/>
|
<result column="status" property="status" jdbcType="INTEGER"/>
|
||||||
|
<result column="is_audited" property="isAudited" jdbcType="BOOLEAN"/>
|
||||||
<result column="is_recommend" property="isRecommend" jdbcType="BOOLEAN"/>
|
<result column="is_recommend" property="isRecommend" jdbcType="BOOLEAN"/>
|
||||||
<result column="is_banner" property="isBanner" jdbcType="BOOLEAN"/>
|
<result column="is_banner" property="isBanner" jdbcType="BOOLEAN"/>
|
||||||
<result column="publish_time" property="publishTime" jdbcType="TIMESTAMP"/>
|
<result column="publish_time" property="publishTime" jdbcType="TIMESTAMP"/>
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
||||||
source_url, view_count, like_count, collect_count, status, is_recommend,
|
source_url, view_count, like_count, collect_count, status, is_audited, is_recommend,
|
||||||
is_banner, publish_time, creator, updater, create_time, update_time,
|
is_banner, publish_time, creator, updater, create_time, update_time,
|
||||||
delete_time, deleted
|
delete_time, deleted
|
||||||
</sql>
|
</sql>
|
||||||
@@ -205,10 +206,10 @@
|
|||||||
<!-- 插入资源 -->
|
<!-- 插入资源 -->
|
||||||
<insert id="insertResource" parameterType="org.xyzh.common.dto.resource.TbResource">
|
<insert id="insertResource" parameterType="org.xyzh.common.dto.resource.TbResource">
|
||||||
INSERT INTO tb_resource (
|
INSERT INTO tb_resource (
|
||||||
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, source, is_audited,
|
||||||
source_url, creator,create_time
|
source_url, creator,create_time
|
||||||
) VALUES (
|
) VALUES (
|
||||||
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{tagID}, #{author}, #{source},
|
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{tagID}, #{author}, #{source}, #{isAudited},
|
||||||
#{sourceUrl}, #{creator}, #{createTime}
|
#{sourceUrl}, #{creator}, #{createTime}
|
||||||
)
|
)
|
||||||
</insert>
|
</insert>
|
||||||
@@ -259,6 +260,9 @@
|
|||||||
<if test="isBanner != null">
|
<if test="isBanner != null">
|
||||||
is_banner = #{isBanner},
|
is_banner = #{isBanner},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="isAudited != null">
|
||||||
|
is_audited = #{isAudited},
|
||||||
|
</if>
|
||||||
<if test="publishTime != null">
|
<if test="publishTime != null">
|
||||||
publish_time = #{publishTime},
|
publish_time = #{publishTime},
|
||||||
</if>
|
</if>
|
||||||
@@ -287,14 +291,14 @@
|
|||||||
<!-- 批量插入资源 -->
|
<!-- 批量插入资源 -->
|
||||||
<insert id="batchInsertResources" parameterType="java.util.List">
|
<insert id="batchInsertResources" parameterType="java.util.List">
|
||||||
INSERT INTO tb_resource (
|
INSERT INTO tb_resource (
|
||||||
id, resource_id, title, content, summary, cover_image, tag_id, author, source,
|
id, resource_id, title, content, summary, cover_image, tag_id, author, is_audited,
|
||||||
source_url, status, is_recommend, is_banner, publish_time,
|
source, source_url, status, is_recommend, is_banner, publish_time,
|
||||||
creator, updater, create_time, update_time, deleted
|
creator, updater, create_time, update_time, deleted
|
||||||
) VALUES
|
) VALUES
|
||||||
<foreach collection="resourceList" item="item" separator=",">
|
<foreach collection="resourceList" item="item" separator=",">
|
||||||
(
|
(
|
||||||
#{item.id}, #{item.resourceID}, #{item.title}, #{item.content}, #{item.summary}, #{item.coverImage},
|
#{item.id}, #{item.resourceID}, #{item.title}, #{item.content}, #{item.summary}, #{item.coverImage},
|
||||||
#{item.tagID}, #{item.author}, #{item.source}, #{item.sourceUrl},
|
#{item.tagID}, #{item.author}, #{item.isAudited}, #{item.source}, #{item.sourceUrl},
|
||||||
#{item.status}, #{item.isRecommend}, #{item.isBanner}, #{item.publishTime},
|
#{item.status}, #{item.isRecommend}, #{item.isBanner}, #{item.publishTime},
|
||||||
#{item.creator}, #{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleted}
|
#{item.creator}, #{item.updater}, #{item.createTime}, #{item.updateTime}, #{item.deleted}
|
||||||
)
|
)
|
||||||
@@ -360,6 +364,7 @@
|
|||||||
<result column="like_count" property="likeCount" jdbcType="INTEGER"/>
|
<result column="like_count" property="likeCount" jdbcType="INTEGER"/>
|
||||||
<result column="collect_count" property="collectCount" jdbcType="INTEGER"/>
|
<result column="collect_count" property="collectCount" jdbcType="INTEGER"/>
|
||||||
<result column="status" property="status" jdbcType="INTEGER"/>
|
<result column="status" property="status" jdbcType="INTEGER"/>
|
||||||
|
<result column="is_audited" property="isAudited" jdbcType="BOOLEAN"/>
|
||||||
<result column="is_recommend" property="isRecommend" jdbcType="BOOLEAN"/>
|
<result column="is_recommend" property="isRecommend" jdbcType="BOOLEAN"/>
|
||||||
<result column="is_banner" property="isBanner" jdbcType="BOOLEAN"/>
|
<result column="is_banner" property="isBanner" jdbcType="BOOLEAN"/>
|
||||||
<result column="publish_time" property="publishTime" jdbcType="TIMESTAMP"/>
|
<result column="publish_time" property="publishTime" jdbcType="TIMESTAMP"/>
|
||||||
|
|||||||
@@ -27,6 +27,11 @@
|
|||||||
<artifactId>api-study</artifactId>
|
<artifactId>api-study</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xyzh</groupId>
|
||||||
|
<artifactId>api-new</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xyzh</groupId>
|
<groupId>org.xyzh</groupId>
|
||||||
<artifactId>system</artifactId>
|
<artifactId>system</artifactId>
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ public interface CourseNodeMapper extends BaseMapper<TbCourseNode> {
|
|||||||
*/
|
*/
|
||||||
List<TbCourseNode> selectByChapterId(@Param("chapterId") String chapterId);
|
List<TbCourseNode> selectByChapterId(@Param("chapterId") String chapterId);
|
||||||
|
|
||||||
|
List<TbCourseNode> selectByCourseId(@Param("courseId")String courseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 根据节点名称查询节点
|
* @description 根据节点名称查询节点
|
||||||
* @param name 节点名称
|
* @param name 节点名称
|
||||||
@@ -146,6 +148,8 @@ public interface CourseNodeMapper extends BaseMapper<TbCourseNode> {
|
|||||||
*/
|
*/
|
||||||
int batchDeleteCourseNodes(@Param("nodeIDs") List<String> nodeIDs);
|
int batchDeleteCourseNodes(@Param("nodeIDs") List<String> nodeIDs);
|
||||||
|
|
||||||
|
int batchUpdateNodeAudited(@Param("courseNodeList")List<TbCourseNode> nodeList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 根据章节ID批量删除节点
|
* @description 根据章节ID批量删除节点
|
||||||
* @param chapterId 章节ID
|
* @param chapterId 章节ID
|
||||||
|
|||||||
@@ -13,21 +13,26 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.xyzh.common.core.domain.ResultDomain;
|
import org.xyzh.common.core.domain.ResultDomain;
|
||||||
import org.xyzh.common.core.page.PageDomain;
|
import org.xyzh.common.core.page.PageDomain;
|
||||||
import org.xyzh.common.core.page.PageParam;
|
import org.xyzh.common.core.page.PageParam;
|
||||||
import org.xyzh.common.core.page.PageRequest;
|
import org.xyzh.common.core.page.PageRequest;
|
||||||
|
import org.xyzh.common.dto.resource.TbResource;
|
||||||
import org.xyzh.common.dto.study.TbCourse;
|
import org.xyzh.common.dto.study.TbCourse;
|
||||||
import org.xyzh.common.dto.study.TbCourseChapter;
|
import org.xyzh.common.dto.study.TbCourseChapter;
|
||||||
import org.xyzh.common.dto.study.TbCourseNode;
|
import org.xyzh.common.dto.study.TbCourseNode;
|
||||||
import org.xyzh.common.dto.user.TbSysUser;
|
import org.xyzh.common.dto.user.TbSysUser;
|
||||||
import org.xyzh.common.utils.IDUtils;
|
import org.xyzh.common.utils.IDUtils;
|
||||||
import org.xyzh.common.vo.CourseItemVO;
|
import org.xyzh.common.vo.CourseItemVO;
|
||||||
|
import org.xyzh.common.vo.ResourceVO;
|
||||||
import org.xyzh.study.mapper.CourseMapper;
|
import org.xyzh.study.mapper.CourseMapper;
|
||||||
import org.xyzh.study.mapper.CourseChapterMapper;
|
import org.xyzh.study.mapper.CourseChapterMapper;
|
||||||
import org.xyzh.study.mapper.CourseNodeMapper;
|
import org.xyzh.study.mapper.CourseNodeMapper;
|
||||||
import org.xyzh.study.service.SCCourseService;
|
import org.xyzh.study.service.SCCourseService;
|
||||||
import org.xyzh.system.utils.LoginUtil;
|
import org.xyzh.system.utils.LoginUtil;
|
||||||
|
import org.xyzh.api.news.resource.ResourceAuditService;
|
||||||
|
import org.xyzh.api.news.resource.ResourceService;
|
||||||
import org.xyzh.api.system.permission.ResourcePermissionService;
|
import org.xyzh.api.system.permission.ResourcePermissionService;
|
||||||
import org.xyzh.common.vo.UserDeptRoleVO;
|
import org.xyzh.common.vo.UserDeptRoleVO;
|
||||||
import org.xyzh.common.core.enums.ResourceType;
|
import org.xyzh.common.core.enums.ResourceType;
|
||||||
@@ -53,6 +58,12 @@ public class SCCourseServiceImpl implements SCCourseService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CourseNodeMapper courseNodeMapper;
|
private CourseNodeMapper courseNodeMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceAuditService auditService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceService resourceService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ResourcePermissionService resourcePermissionService;
|
private ResourcePermissionService resourcePermissionService;
|
||||||
|
|
||||||
@@ -414,8 +425,70 @@ public class SCCourseServiceImpl implements SCCourseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
public ResultDomain<TbCourse> updateCourseStatus(TbCourse course) {
|
public ResultDomain<TbCourse> updateCourseStatus(TbCourse course) {
|
||||||
ResultDomain<TbCourse> resultDomain = new ResultDomain<>();
|
ResultDomain<TbCourse> resultDomain = new ResultDomain<>();
|
||||||
|
if(course.getStatus()==1){ // 发布前审核
|
||||||
|
// 获取所有课程节点
|
||||||
|
List<TbCourseNode> nodeList = courseNodeMapper.selectByCourseId(course.getCourseID());
|
||||||
|
List<TbCourseNode> notPassList = new ArrayList<>();
|
||||||
|
for(TbCourseNode node: nodeList){
|
||||||
|
if(!node.getIsAudited()){
|
||||||
|
// 重新审核
|
||||||
|
int type = node.getNodeType();
|
||||||
|
// auditService.
|
||||||
|
if(type==1){ //文章类型
|
||||||
|
ResultDomain<ResourceVO> resourceDomain = resourceService.getResourceById(node.getResourceID());
|
||||||
|
if (resourceDomain.isSuccess()) {
|
||||||
|
if (!resourceDomain.getData().getResource().getIsAudited()) {
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditText(resourceDomain.getData().getResource().getContent());
|
||||||
|
if(!pass.isSuccess() || !pass.getData()){
|
||||||
|
// 审核失败,标记课程状态为3(审核失败)
|
||||||
|
course.setStatus(3);
|
||||||
|
course.setUpdateTime(new Date());
|
||||||
|
courseMapper.updateCourse(course);
|
||||||
|
|
||||||
|
resultDomain.fail("课程节点:"+node.getName()+"审核未通过");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if (type == 2){
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditByFileId(node.getResourceID());
|
||||||
|
if(!pass.isSuccess() || !pass.getData()){
|
||||||
|
// 审核失败,标记课程状态为3(审核失败)
|
||||||
|
course.setStatus(3);
|
||||||
|
course.setUpdateTime(new Date());
|
||||||
|
courseMapper.updateCourse(course);
|
||||||
|
|
||||||
|
resultDomain.fail("课程节点:"+node.getName()+"审核未通过");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
ResultDomain<Boolean> pass = auditService.auditText(node.getContent());
|
||||||
|
if(!pass.isSuccess() || !pass.getData()){
|
||||||
|
// 审核失败,标记课程状态为3(审核失败)
|
||||||
|
course.setStatus(3);
|
||||||
|
course.setUpdateTime(new Date());
|
||||||
|
courseMapper.updateCourse(course);
|
||||||
|
|
||||||
|
resultDomain.fail("课程节点:"+node.getName()+"审核未通过");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.setIsAudited(true);
|
||||||
|
notPassList.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!notPassList.isEmpty()){
|
||||||
|
int i = courseNodeMapper.batchUpdateNodeAudited(notPassList);
|
||||||
|
if(i<=0){
|
||||||
|
resultDomain.fail("课程节点审核状态更新失败");
|
||||||
|
return resultDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
int result = courseMapper.updateCourse(course);
|
int result = courseMapper.updateCourse(course);
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
resultDomain.success("更新课程状态成功", course);
|
resultDomain.success("更新课程状态成功", course);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<result column="duration" property="duration" jdbcType="INTEGER"/>
|
<result column="duration" property="duration" jdbcType="INTEGER"/>
|
||||||
<result column="order_num" property="orderNum" jdbcType="INTEGER"/>
|
<result column="order_num" property="orderNum" jdbcType="INTEGER"/>
|
||||||
<result column="is_required" property="isRequired" jdbcType="INTEGER"/>
|
<result column="is_required" property="isRequired" jdbcType="INTEGER"/>
|
||||||
|
<result column="is_audited" property="isAudited" jdbcType="BOOLEAN"/>
|
||||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||||
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
||||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
|
|
||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, node_id, chapter_id, name, content, node_type, resource_id, video_url, duration, order_num, is_required,
|
id, node_id, chapter_id, name, content, node_type, resource_id, video_url, duration, order_num, is_required, is_audited,
|
||||||
creator, updater, create_time, update_time, delete_time, deleted
|
creator, updater, create_time, update_time, delete_time, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -98,6 +99,20 @@
|
|||||||
ORDER BY order_num ASC, create_time ASC
|
ORDER BY order_num ASC, create_time ASC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByCourseId">
|
||||||
|
SELECT
|
||||||
|
tcn.id, tcn.node_id, tcn.chapter_id, tcn.name,
|
||||||
|
tcn.content, tcn.node_type, tcn.resource_id, tcn.video_url, tcn.duration,
|
||||||
|
tcn.order_num, tcn.is_required, tcn.is_audited, tcn.creator, tcn.updater,
|
||||||
|
tcn.create_time, tcn.update_time, tcn.delete_time, tcn.deleted
|
||||||
|
FROM tb_course_node tcn
|
||||||
|
LEFT JOIN tb_course_chapter tcc ON tcc.chapter_id = tcn.chapter_id
|
||||||
|
LEFT JOIN tb_course tc ON tcc.course_id = tc.course_id
|
||||||
|
WHERE tc.course_id=#{courseId} AND tcn.deleted = 0
|
||||||
|
ORDER BY order_num ASC, create_time ASC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<!-- 根据节点名称查询节点 -->
|
<!-- 根据节点名称查询节点 -->
|
||||||
<select id="selectByName" resultMap="BaseResultMap">
|
<select id="selectByName" resultMap="BaseResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
@@ -149,47 +164,48 @@
|
|||||||
<update id="updateCourseNode" parameterType="org.xyzh.common.dto.study.TbCourseNode">
|
<update id="updateCourseNode" parameterType="org.xyzh.common.dto.study.TbCourseNode">
|
||||||
UPDATE tb_course_node
|
UPDATE tb_course_node
|
||||||
<set>
|
<set>
|
||||||
|
is_audited = 0
|
||||||
<if test="chapterID != null and chapterID != ''">
|
<if test="chapterID != null and chapterID != ''">
|
||||||
chapter_id = #{chapterID},
|
,chapter_id = #{chapterID}
|
||||||
</if>
|
</if>
|
||||||
<if test="name != null and name != ''">
|
<if test="name != null and name != ''">
|
||||||
name = #{name},
|
,name = #{name}
|
||||||
</if>
|
</if>
|
||||||
<if test="content != null and content != ''">
|
<if test="content != null and content != ''">
|
||||||
content = #{content},
|
,content = #{content}
|
||||||
</if>
|
</if>
|
||||||
<if test="nodeType != null">
|
<if test="nodeType != null">
|
||||||
node_type = #{nodeType},
|
,node_type = #{nodeType}
|
||||||
</if>
|
</if>
|
||||||
<if test="resourceID != null">
|
<if test="resourceID != null">
|
||||||
resource_id = #{resourceID},
|
,resource_id = #{resourceID}
|
||||||
</if>
|
</if>
|
||||||
<if test="videoUrl != null and videoUrl != ''">
|
<if test="videoUrl != null and videoUrl != ''">
|
||||||
video_url = #{videoUrl},
|
,video_url = #{videoUrl}
|
||||||
</if>
|
</if>
|
||||||
<if test="duration != null">
|
<if test="duration != null">
|
||||||
duration = #{duration},
|
,duration = #{duration}
|
||||||
</if>
|
</if>
|
||||||
<if test="orderNum != null">
|
<if test="orderNum != null">
|
||||||
order_num = #{orderNum},
|
,order_num = #{orderNum}
|
||||||
</if>
|
</if>
|
||||||
<if test="isRequired != null">
|
<if test="isRequired != null">
|
||||||
is_required = #{isRequired},
|
,is_required = #{isRequired}
|
||||||
</if>
|
</if>
|
||||||
<if test="updater != null and updater != ''">
|
<if test="updater != null and updater != ''">
|
||||||
updater = #{updater},
|
,updater = #{updater}
|
||||||
</if>
|
</if>
|
||||||
<if test="updateTime != null">
|
<if test="updateTime != null">
|
||||||
update_time = #{updateTime},
|
,update_time = #{updateTime}
|
||||||
</if>
|
</if>
|
||||||
<if test="deleteTime != null">
|
<if test="deleteTime != null">
|
||||||
delete_time = #{deleteTime},
|
,delete_time = #{deleteTime}
|
||||||
</if>
|
</if>
|
||||||
<if test="deleted != null">
|
<if test="deleted != null">
|
||||||
deleted = #{deleted},
|
,deleted = #{deleted}
|
||||||
</if>
|
</if>
|
||||||
</set>
|
</set>
|
||||||
WHERE id = #{id}
|
WHERE node_id = #{nodeID}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<!-- 删除学习节点 -->
|
<!-- 删除学习节点 -->
|
||||||
@@ -222,6 +238,15 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<!-- batchUpdateNodeAudited -->
|
||||||
|
<update id="batchUpdateNodeAudited">
|
||||||
|
<foreach collection="courseNodeList" item="item" separator=";">
|
||||||
|
UPDATE tb_course_node
|
||||||
|
SET is_audited = #{item.isAudited}
|
||||||
|
WHERE node_id = #{item.nodeID}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
|
||||||
<!-- 根据章节ID批量删除节点 -->
|
<!-- 根据章节ID批量删除节点 -->
|
||||||
<delete id="deleteByChapterId">
|
<delete id="deleteByChapterId">
|
||||||
DELETE FROM tb_course_node
|
DELETE FROM tb_course_node
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ export interface DataCollectionItem extends BaseDTO {
|
|||||||
title?: string;
|
title?: string;
|
||||||
/** 内容(HTML格式) */
|
/** 内容(HTML格式) */
|
||||||
content?: string;
|
content?: string;
|
||||||
|
isAudited?:boolean;
|
||||||
/** 来源URL */
|
/** 来源URL */
|
||||||
sourceUrl?: string;
|
sourceUrl?: string;
|
||||||
/** 发布时间 */
|
/** 发布时间 */
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ export enum ResourceStatus {
|
|||||||
/** 已发布 */
|
/** 已发布 */
|
||||||
PUBLISHED = 1,
|
PUBLISHED = 1,
|
||||||
/** 下架 */
|
/** 下架 */
|
||||||
OFFLINE = 2
|
OFFLINE = 2,
|
||||||
|
/** 审核失败 */
|
||||||
|
FAILED = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +99,9 @@ export enum CourseStatus {
|
|||||||
/** 已上线 */
|
/** 已上线 */
|
||||||
ONLINE = 1,
|
ONLINE = 1,
|
||||||
/** 已下架 */
|
/** 已下架 */
|
||||||
DISABLED = 2
|
DISABLED = 2,
|
||||||
|
/** 审核失败 */
|
||||||
|
FAILED = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,7 +135,9 @@ export enum ArticleStatus {
|
|||||||
/** 已发布 */
|
/** 已发布 */
|
||||||
PUBLISHED = 1,
|
PUBLISHED = 1,
|
||||||
/** 下架 */
|
/** 下架 */
|
||||||
OFFLINE = 2
|
OFFLINE = 2,
|
||||||
|
/** 审核失败 */
|
||||||
|
FAILED = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export interface Resource extends BaseDTO {
|
|||||||
tagID?: string;
|
tagID?: string;
|
||||||
/** 作者 */
|
/** 作者 */
|
||||||
author?: string;
|
author?: string;
|
||||||
|
isAudited?:boolean;
|
||||||
/** 来源 */
|
/** 来源 */
|
||||||
source?: string;
|
source?: string;
|
||||||
/** 来源URL */
|
/** 来源URL */
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export interface CourseNode extends BaseDTO {
|
|||||||
nodeType?: number;
|
nodeType?: number;
|
||||||
/** 资源ID */
|
/** 资源ID */
|
||||||
resourceID?: string;
|
resourceID?: string;
|
||||||
|
isAudited?:boolean;
|
||||||
/** 视频URL */
|
/** 视频URL */
|
||||||
videoUrl?: string;
|
videoUrl?: string;
|
||||||
/** 节点时长(分钟) */
|
/** 节点时长(分钟) */
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ function getStatusType(status: number) {
|
|||||||
const typeMap: Record<number, any> = {
|
const typeMap: Record<number, any> = {
|
||||||
[ArticleStatus.DRAFT]: 'info',
|
[ArticleStatus.DRAFT]: 'info',
|
||||||
[ArticleStatus.PUBLISHED]: 'success',
|
[ArticleStatus.PUBLISHED]: 'success',
|
||||||
[ArticleStatus.OFFLINE]: 'warning'
|
[ArticleStatus.OFFLINE]: 'warning',
|
||||||
|
[ArticleStatus.FAILED]: 'danger'
|
||||||
};
|
};
|
||||||
return typeMap[status] || 'info';
|
return typeMap[status] || 'info';
|
||||||
}
|
}
|
||||||
@@ -217,14 +218,15 @@ function getStatusText(status: number) {
|
|||||||
const textMap: Record<number, string> = {
|
const textMap: Record<number, string> = {
|
||||||
[ArticleStatus.DRAFT]: '草稿',
|
[ArticleStatus.DRAFT]: '草稿',
|
||||||
[ArticleStatus.PUBLISHED]: '已发布',
|
[ArticleStatus.PUBLISHED]: '已发布',
|
||||||
[ArticleStatus.OFFLINE]: '已下架'
|
[ArticleStatus.OFFLINE]: '已下架',
|
||||||
|
[ArticleStatus.FAILED]: '审核失败'
|
||||||
};
|
};
|
||||||
return textMap[status] || '未知';
|
return textMap[status] || '未知';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActionButtonType(status: number) {
|
function getActionButtonType(status: number) {
|
||||||
// 草稿或下架状态显示主要按钮(发布), 已发布状态显示警告按钮(下架)
|
// 草稿或下架状态显示主要按钮(发布), 已发布状态显示警告按钮(下架)
|
||||||
if (status === ArticleStatus.DRAFT || status === ArticleStatus.OFFLINE) {
|
if (status === ArticleStatus.DRAFT || status === ArticleStatus.OFFLINE || status === ArticleStatus.FAILED) {
|
||||||
return 'primary';
|
return 'primary';
|
||||||
} else if (status === ArticleStatus.PUBLISHED) {
|
} else if (status === ArticleStatus.PUBLISHED) {
|
||||||
return 'warning';
|
return 'warning';
|
||||||
@@ -234,7 +236,7 @@ function getActionButtonType(status: number) {
|
|||||||
|
|
||||||
function getActionButtonText(status: number) {
|
function getActionButtonText(status: number) {
|
||||||
// 草稿或下架状态显示"发布", 已发布状态显示"下架"
|
// 草稿或下架状态显示"发布", 已发布状态显示"下架"
|
||||||
if (status === ArticleStatus.DRAFT || status === ArticleStatus.OFFLINE) {
|
if (status === ArticleStatus.DRAFT || status === ArticleStatus.OFFLINE || status === ArticleStatus.FAILED) {
|
||||||
return '发布';
|
return '发布';
|
||||||
} else if (status === ArticleStatus.PUBLISHED) {
|
} else if (status === ArticleStatus.PUBLISHED) {
|
||||||
return '下架';
|
return '下架';
|
||||||
|
|||||||
@@ -221,14 +221,18 @@ function handleBack() {
|
|||||||
async function handlePublish() {
|
async function handlePublish() {
|
||||||
try {
|
try {
|
||||||
await formRef.value?.validate();
|
await formRef.value?.validate();
|
||||||
|
|
||||||
publishing.value = true;
|
publishing.value = true;
|
||||||
|
|
||||||
// 如果是从数据采集转换过来的,使用转换接口
|
// 新建或“立即发布”时,明确标记为已发布
|
||||||
|
// 对新建文章:status 没有值,这里设为 1
|
||||||
|
// 对草稿->发布:也会变成 1
|
||||||
|
articleForm.value.resource.status = 1;
|
||||||
|
// 确保走审核流程
|
||||||
|
articleForm.value.resource.isAudited = false;
|
||||||
|
|
||||||
if (props.collectionItemId) {
|
if (props.collectionItemId) {
|
||||||
await handleConvertFromCollection();
|
await handleConvertFromCollection();
|
||||||
} else {
|
} else {
|
||||||
// 普通创建资源
|
|
||||||
const result = await resourceApi.createResource(articleForm.value);
|
const result = await resourceApi.createResource(articleForm.value);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const resourceID = result.data?.resource?.resourceID || '';
|
const resourceID = result.data?.resource?.resourceID || '';
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<option :value="0">未上线</option>
|
<option :value="0">未上线</option>
|
||||||
<option :value="1">已上线</option>
|
<option :value="1">已上线</option>
|
||||||
<option :value="2">已下架</option>
|
<option :value="2">已下架</option>
|
||||||
|
<option :value="3">审核失败</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
@@ -65,7 +66,8 @@
|
|||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-if="row.status === 0" type="info">未上线</el-tag>
|
<el-tag v-if="row.status === 0" type="info">未上线</el-tag>
|
||||||
<el-tag v-else-if="row.status === 1" type="success">已上线</el-tag>
|
<el-tag v-else-if="row.status === 1" type="success">已上线</el-tag>
|
||||||
<el-tag v-else-if="row.status === 2" type="danger">已下架</el-tag>
|
<el-tag v-else-if="row.status === 2" type="warning">已下架</el-tag>
|
||||||
|
<el-tag v-else-if="row.status === 3" type="danger">审核失败</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="orderNum" label="排序" width="80" />
|
<el-table-column prop="orderNum" label="排序" width="80" />
|
||||||
@@ -75,7 +77,7 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="row.status === 0 || row.status === 2"
|
v-if="row.status === 0 || row.status === 2 || row.status === 3"
|
||||||
type="success"
|
type="success"
|
||||||
size="small"
|
size="small"
|
||||||
link
|
link
|
||||||
|
|||||||
Reference in New Issue
Block a user