Browse Source

文章发布、视频培训:添加审核状态字段,设计提交审核接口,上架下架功能

master
ChaiNingQi 4 weeks ago
parent
commit
4a73376b73
  1. 62
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetKnowledgeController.java
  2. 2
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java
  3. 152
      chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java
  4. 94
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetKnowledge.java
  5. 283
      chenhai-system/src/main/java/com/chenhai/vet/domain/VetTrainingVideo.java
  6. 23
      chenhai-system/src/main/java/com/chenhai/vet/mapper/VetTrainingVideoMapper.java
  7. 48
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetKnowledgeService.java
  8. 1
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java
  9. 44
      chenhai-system/src/main/java/com/chenhai/vet/service/IVetTrainingVideoService.java
  10. 257
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetKnowledgeServiceImpl.java
  11. 4
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java
  12. 223
      chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetTrainingVideoServiceImpl.java
  13. 43
      chenhai-system/src/main/resources/mapper/vet/VetKnowledgeMapper.xml
  14. 2
      chenhai-system/src/main/resources/mapper/vet/VetProductMapper.xml
  15. 88
      chenhai-system/src/main/resources/mapper/vet/VetTrainingVideoMapper.xml
  16. 39
      chenhai-ui/src/api/vet/knowledge.js
  17. 101
      chenhai-ui/src/api/vet/training.js
  18. 585
      chenhai-ui/src/views/vet/knowledge/index.vue
  19. 1851
      chenhai-ui/src/views/vet/product/index.vue
  20. 2208
      chenhai-ui/src/views/vet/training/TrainingHome.vue

62
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetKnowledgeController.java

@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.chenhai.common.annotation.Log;
import com.chenhai.common.core.controller.BaseController;
@ -23,7 +24,7 @@ import com.chenhai.common.core.page.TableDataInfo;
/**
* 兽医文章Controller
*
*
* @author ruoyi
* @date 2026-01-08
*/
@ -77,7 +78,8 @@ public class VetKnowledgeController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody VetKnowledge vetKnowledge)
{
vetKnowledge.setStatus("0");
vetKnowledge.setArticleStatus("0"); // 草稿
vetKnowledge.setAuditStatus("0"); // 待审核
return toAjax(vetKnowledgeService.insertVetKnowledge(vetKnowledge));
}
@ -97,24 +99,39 @@ public class VetKnowledgeController extends BaseController
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:remove')")
@Log(title = "兽医文章", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(vetKnowledgeService.deleteVetKnowledgeByIds(ids));
}
/**
* 上传文章待审核
* 提交审核
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:upload')")
@Log(title = "兽医文章", businessType = BusinessType.INSERT)
@PostMapping("/upload")
public AjaxResult upload(@RequestBody VetKnowledge vetKnowledge) {
return vetKnowledgeService.uploadVetKnowledge(vetKnowledge);
@PreAuthorize("@ss.hasPermi('vet:knowledge:submit')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@PutMapping("/submit/{id}")
public AjaxResult submitForAudit(@PathVariable Long id) {
return vetKnowledgeService.submitForAudit(id);
}
/**
* 发布文章更新状态
* 审核文章
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:audit')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@PutMapping("/audit/{id}")
public AjaxResult audit(@PathVariable Long id,
@RequestParam String auditStatus, // 注意参数名改为auditStatus
@RequestParam(required = false) String auditComment) {
// 验证状态值是否合法
if (!"2".equals(auditStatus) && !"3".equals(auditStatus)) {
return AjaxResult.error("无效的审核状态值");
}
return vetKnowledgeService.auditVetKnowledge(id, auditStatus, auditComment);
}
/**
* 发布文章
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:publish')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@ -122,4 +139,27 @@ public class VetKnowledgeController extends BaseController
public AjaxResult publish(@PathVariable Long id) {
return vetKnowledgeService.publishVetKnowledge(id);
}
}
/**
* 上架文章
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:publish')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@PutMapping("/online/{id}")
public AjaxResult online(@PathVariable Long id) {
return vetKnowledgeService.onlineVetKnowledge(id);
}
/**
* 下架文章
*/
@PreAuthorize("@ss.hasPermi('vet:knowledge:publish')")
@Log(title = "兽医文章", businessType = BusinessType.UPDATE)
@PutMapping("/offline/{id}")
public AjaxResult offline(@PathVariable Long id, @RequestParam(required = false) String auditComment) {
if (auditComment == null || auditComment.trim().isEmpty()) {
return AjaxResult.error("请输入下架原因");
}
return vetKnowledgeService.offlineVetKnowledge(id, auditComment);
}
}

2
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetProductController.java

@ -101,4 +101,6 @@ public class VetProductController extends BaseController
{
return toAjax(vetProductService.deleteVetProductByIds(ids));
}
}

152
chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java

@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/vet/training")
@ -31,11 +32,11 @@ public class VetTrainingVideoController extends BaseController {
*/
@PostMapping("/upload")
public AjaxResult uploadVideo(
@RequestParam("title") String title, // 改为 @RequestParam
@RequestParam("videoFile") MultipartFile videoFile, // 文件字段保持 @RequestPart 或改为 @RequestParam
@RequestParam("title") String title,
@RequestParam("videoFile") MultipartFile videoFile,
@RequestParam(value = "description", required = false) String description,
@RequestParam(value = "category", required = false) String category,
@RequestParam(value = "status", required = false, defaultValue = "1") String status) {
@RequestParam(value = "coverImage", required = false) MultipartFile coverImage) {
Long userId = getCurrentUserId();
@ -45,9 +46,8 @@ public class VetTrainingVideoController extends BaseController {
video.setTitle(title);
video.setDescription(description);
video.setCategory(category);
video.setStatus(status);
String result = trainingVideoService.uploadAndSave(video, videoFile, null);
String result = trainingVideoService.uploadAndSave(video, videoFile, coverImage);
return success(result);
} catch (Exception e) {
e.printStackTrace();
@ -55,37 +55,6 @@ public class VetTrainingVideoController extends BaseController {
}
}
/**
* 批量上传视频可选功能
*/
@PostMapping("/upload/batch")
public AjaxResult uploadBatch(
@RequestParam String[] titles,
@RequestParam MultipartFile[] videoFiles,
@RequestParam(required = false) String[] categories) {
Long userId = getCurrentUserId();
try {
int successCount = 0;
for (int i = 0; i < videoFiles.length; i++) {
if (i < titles.length) {
VetTrainingVideo video = new VetTrainingVideo();
video.setUserId(userId); // 修正变量名
video.setTitle(titles[i]);
video.setCategory(categories != null && i < categories.length ? categories[i] : null);
video.setStatus("1");
trainingVideoService.uploadAndSave(video, videoFiles[i], null);
successCount++;
}
}
return success("成功上传 " + successCount + " 个视频");
} catch (Exception e) {
return error("批量上传失败:" + e.getMessage());
}
}
/**
* 查看我上传的视频
*/
@ -93,11 +62,12 @@ public class VetTrainingVideoController extends BaseController {
public TableDataInfo getMyVideos(
@RequestParam(required = false) String title,
@RequestParam(required = false) String category,
@RequestParam(required = false) String status) {
@RequestParam(required = false) String status,
@RequestParam(required = false) String auditStatus) {
startPage();
Long userId = getCurrentUserId(); // 修正变量名
List<VetTrainingVideo> list = trainingVideoService.getMyVideos(userId, title, category, status);
Long userId = getCurrentUserId();
List<VetTrainingVideo> list = trainingVideoService.getMyVideos(userId, title, category, status, auditStatus);
return getDataTable(list);
}
@ -108,7 +78,7 @@ public class VetTrainingVideoController extends BaseController {
public TableDataInfo getPublicVideos(
@RequestParam(required = false) String title,
@RequestParam(required = false) String category,
@RequestParam(required = false) String userName) { // 参数名改为userName
@RequestParam(required = false) String userName) {
startPage();
List<VetTrainingVideo> list = trainingVideoService.getPublicVideos(title, category, userName);
@ -120,15 +90,16 @@ public class VetTrainingVideoController extends BaseController {
*/
@GetMapping("/video/{videoId}")
public AjaxResult getVideoDetail(@PathVariable Long videoId) {
Long userId = getCurrentUserId(); // 修正变量名
Long userId = getCurrentUserId();
VetTrainingVideo video = trainingVideoService.getVideoDetail(videoId, userId);
if (video == null) {
return error("视频不存在或无权限查看");
}
// 如果是公开视频或自己的视频增加观看次数
if ("1".equals(video.getStatus()) || userId.equals(video.getUserId())) {
// 如果是审核通过且公开的视频增加观看次数
if ("1".equals(video.getAuditStatus()) && // 1-审核通过
"1".equals(video.getStatus())) { // 1-已上架/公开
trainingVideoService.incrementViewCount(videoId);
video.setViewCount(video.getViewCount() + 1);
}
@ -137,45 +108,104 @@ public class VetTrainingVideoController extends BaseController {
}
/**
* 获取视频播放地址带权限校验- 可选功能
* 提交审核手动提交
*/
@PostMapping("/submit-audit/{videoId}")
public AjaxResult submitForAudit(@PathVariable Long videoId) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.submitForAudit(videoId, userId);
return success ? success("提交审核成功") : error("提交审核失败");
}
/**
* 取消审核
*/
@PostMapping("/cancel-audit/{videoId}")
public AjaxResult cancelAudit(@PathVariable Long videoId) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.cancelAudit(videoId, userId);
return success ? success("取消审核成功") : error("取消审核失败");
}
/**
* 重新提交审核
*/
@PostMapping("/resubmit-audit/{videoId}")
public AjaxResult resubmitForAudit(@PathVariable Long videoId) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.resubmitForAudit(videoId, userId);
return success ? success("重新提交审核成功") : error("重新提交审核失败");
}
/**
* 审核视频管理员接口- 使用JSON接收
*/
@GetMapping("/video/play/{videoId}")
public AjaxResult getPlayUrl(@PathVariable Long videoId) {
Long userId = getCurrentUserId(); // 修正变量名
String playUrl = trainingVideoService.getVideoPlayUrl(videoId, userId);
@PostMapping("/audit/{videoId}")
public AjaxResult auditVideo(@PathVariable Long videoId,
@RequestBody Map<String, String> auditData) {
if (playUrl == null) {
return error("无权限播放此视频");
String auditStatus = auditData.get("auditStatus");
String auditOpinion = auditData.get("auditOpinion");
if (auditStatus == null || auditStatus.trim().isEmpty()) {
return error("审核状态不能为空");
}
return success(playUrl);
Long auditUserId = getCurrentUserId();
boolean success = trainingVideoService.auditVideo(videoId, auditStatus, auditOpinion, auditUserId);
return success ? success("审核操作成功") : error("审核操作失败");
}
/**
* 获取热门视频按观看次数排序
* 上架视频审核通过后才能上架
*/
@GetMapping("/hot-videos")
public AjaxResult getHotVideos(@RequestParam(defaultValue = "10") Integer limit) {
List<VetTrainingVideo> list = trainingVideoService.getHotVideos(limit);
return success(list);
@PostMapping("/publish/{videoId}")
public AjaxResult publishVideo(@PathVariable Long videoId) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.publishVideo(videoId, userId);
return success ? success("视频已上架") : error("上架失败,请确保视频已通过审核");
}
/**
* 搜索视频
* 下架视频
*/
@GetMapping("/search")
public TableDataInfo searchVideos(@RequestParam String keyword) {
@PostMapping("/offline/{videoId}")
public AjaxResult offlineVideo(@PathVariable Long videoId) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.offlineVideo(videoId, userId);
return success ? success("视频已下架") : error("下架失败");
}
/**
* 获取待审核视频列表管理员接口
*/
@GetMapping("/pending-audit")
public TableDataInfo getPendingAuditVideos(
@RequestParam(required = false) String title,
@RequestParam(required = false) String userName) {
startPage();
List<VetTrainingVideo> list = trainingVideoService.searchVideos(keyword);
List<VetTrainingVideo> list = trainingVideoService.getPendingAuditVideos(title, userName);
return getDataTable(list);
}
/**
* 编辑视频信息
*/
@PutMapping("/update/{videoId}")
public AjaxResult updateVideoInfo(@PathVariable Long videoId,
@RequestBody VetTrainingVideo video) {
Long userId = getCurrentUserId();
boolean success = trainingVideoService.updateVideoInfo(videoId, video, userId);
return success ? success("更新成功") : error("更新失败");
}
/**
* 删除我的视频
*/
@DeleteMapping("/{videoId}")
public AjaxResult deleteVideo(@PathVariable Long videoId) {
Long userId = getCurrentUserId(); // 修正变量名
Long userId = getCurrentUserId();
VetTrainingVideo video = trainingVideoService.getVideoDetail(videoId, userId);
if (video == null) {

94
chenhai-system/src/main/java/com/chenhai/vet/domain/VetKnowledge.java

@ -7,7 +7,7 @@ import com.chenhai.common.core.domain.BaseEntity;
/**
* 兽医文章对象 vet_knowledge
*
*
* @author ruoyi
* @date 2026-01-08
*/
@ -27,91 +27,115 @@ public class VetKnowledge extends BaseEntity
private String content;
/** 文章分类(治疗防治/饲养管理/其他) */
@Excel(name = "文章分类", readConverterExp = "治=疗防治/饲养管理/其他")
@Excel(name = "文章分类", dictType = "article_category")
private String category;
/** 检测出的敏感词 */
@Excel(name = "检测出的敏感词")
private String sensitiveWords;
/** 状态(0-待审核 1-已发布 2-敏感内容驳回) */
@Excel(name = "状态", readConverterExp = "0=-待审核,1=-已发布,2=-敏感内容驳回")
private String status;
/** 文章状态(0-草稿 1-已发布 2-已下架) */
@Excel(name = "文章状态", dictType = "article_status")
private String articleStatus;
public void setId(Long id)
/** 审核状态(0-待审核 1-审核中 2-审核通过 3-审核驳回 4-敏感内容驳回) */
@Excel(name = "审核状态", dictType = "vet_audit_status")
private String auditStatus;
/** 审核意见 */
@Excel(name = "审核意见")
private String auditComment;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
public Long getId()
{
return id;
}
public void setTitle(String title)
public void setTitle(String title)
{
this.title = title;
}
public String getTitle()
public String getTitle()
{
return title;
}
public void setContent(String content)
public void setContent(String content)
{
this.content = content;
}
public String getContent()
public String getContent()
{
return content;
}
public void setCategory(String category)
public void setCategory(String category)
{
this.category = category;
}
public String getCategory()
public String getCategory()
{
return category;
}
public void setSensitiveWords(String sensitiveWords)
public void setSensitiveWords(String sensitiveWords)
{
this.sensitiveWords = sensitiveWords;
}
public String getSensitiveWords()
public String getSensitiveWords()
{
return sensitiveWords;
}
public void setStatus(String status)
{
this.status = status;
public String getArticleStatus() {
return articleStatus;
}
public String getStatus()
{
return status;
public void setArticleStatus(String articleStatus) {
this.articleStatus = articleStatus;
}
public String getAuditStatus() {
return auditStatus;
}
public void setAuditStatus(String auditStatus) {
this.auditStatus = auditStatus;
}
public String getAuditComment() {
return auditComment;
}
public void setAuditComment(String auditComment) {
this.auditComment = auditComment;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("title", getTitle())
.append("content", getContent())
.append("category", getCategory())
.append("sensitiveWords", getSensitiveWords())
.append("status", getStatus())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}
.append("id", getId())
.append("title", getTitle())
.append("content", getContent())
.append("category", getCategory())
.append("sensitiveWords", getSensitiveWords())
.append("articleStatus", getArticleStatus())
.append("auditStatus", getAuditStatus())
.append("auditComment", getAuditComment())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

283
chenhai-system/src/main/java/com/chenhai/vet/domain/VetTrainingVideo.java

@ -1,26 +1,287 @@
package com.chenhai.vet.domain;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.chenhai.common.annotation.Excel;
import com.chenhai.common.core.domain.BaseEntity;
import java.util.Date;
@Data
public class VetTrainingVideo {
/**
* 兽医培训视频对象 vet_training_video
*
* @author ruoyi
* @date 2026-01-08
*/
public class VetTrainingVideo extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 用户ID */
private Long userId;
/** 视频标题 */
@Excel(name = "视频标题")
private String title;
/** 视频描述 */
@Excel(name = "视频描述")
private String description;
/** 视频URL */
@Excel(name = "视频URL")
private String videoUrl;
/** 封面图片 */
@Excel(name = "封面图片")
private String coverImage;
/** 视频分类(手术技巧/疾病诊断/药物使用/其他) */
@Excel(name = "视频分类", dictType = "video_category")
private String category;
/** 视频标签 */
@Excel(name = "视频标签")
private String tags;
private Integer duration; // 视频时长
private Long fileSize; // 文件大小字节
/** 视频时长(秒) */
@Excel(name = "视频时长")
private Integer duration;
/** 文件大小(字节) */
@Excel(name = "文件大小")
private Long fileSize;
/** 观看次数 */
@Excel(name = "观看次数")
private Integer viewCount;
private String status; // 0-私有 1-公开
private Date createTime;
private Date updateTime;
// 非数据库字段
private String userName; // 兽医姓名
private String durationStr; // 格式化后的时长12:30
/** 上架状态(0-私有 1-公开) */
@Excel(name = "上架状态", dictType = "video_status")
private String status;
/** 审核状态(0-待审核 1-审核通过 2-审核拒绝 3-无需审核) */
@Excel(name = "审核状态", dictType = "video_audit_status")
private String auditStatus;
/** 审核意见 */
@Excel(name = "审核意见")
private String auditOpinion;
/** 审核人ID */
private Long auditUserId;
/** 审核时间 */
private Date auditTime;
/** 格式化后的时长(如:12:30) */
private String durationStr;
/** 用户名称(非数据库字段) */
private String userName;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public Long getUserId()
{
return userId;
}
public void setTitle(String title)
{
this.title = title;
}
public String getTitle()
{
return title;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setVideoUrl(String videoUrl)
{
this.videoUrl = videoUrl;
}
public String getVideoUrl()
{
return videoUrl;
}
public void setCoverImage(String coverImage)
{
this.coverImage = coverImage;
}
public String getCoverImage()
{
return coverImage;
}
public void setCategory(String category)
{
this.category = category;
}
public String getCategory()
{
return category;
}
public void setTags(String tags)
{
this.tags = tags;
}
public String getTags()
{
return tags;
}
public void setDuration(Integer duration)
{
this.duration = duration;
}
public Integer getDuration()
{
return duration;
}
public void setFileSize(Long fileSize)
{
this.fileSize = fileSize;
}
public Long getFileSize()
{
return fileSize;
}
public void setViewCount(Integer viewCount)
{
this.viewCount = viewCount;
}
public Integer getViewCount()
{
return viewCount;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setAuditStatus(String auditStatus)
{
this.auditStatus = auditStatus;
}
public String getAuditStatus()
{
return auditStatus;
}
public void setAuditOpinion(String auditOpinion)
{
this.auditOpinion = auditOpinion;
}
public String getAuditOpinion()
{
return auditOpinion;
}
public void setAuditUserId(Long auditUserId)
{
this.auditUserId = auditUserId;
}
public Long getAuditUserId()
{
return auditUserId;
}
public void setAuditTime(Date auditTime)
{
this.auditTime = auditTime;
}
public Date getAuditTime()
{
return auditTime;
}
public String getDurationStr() {
return durationStr;
}
public void setDurationStr(String durationStr) {
this.durationStr = durationStr;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("userId", getUserId())
.append("title", getTitle())
.append("description", getDescription())
.append("videoUrl", getVideoUrl())
.append("coverImage", getCoverImage())
.append("category", getCategory())
.append("tags", getTags())
.append("duration", getDuration())
.append("fileSize", getFileSize())
.append("viewCount", getViewCount())
.append("status", getStatus())
.append("auditStatus", getAuditStatus())
.append("auditOpinion", getAuditOpinion())
.append("auditUserId", getAuditUserId())
.append("auditTime", getAuditTime())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.toString();
}
}

23
chenhai-system/src/main/java/com/chenhai/vet/mapper/VetTrainingVideoMapper.java

@ -2,6 +2,7 @@ package com.chenhai.vet.mapper;
import com.chenhai.vet.domain.VetTrainingVideo;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
public interface VetTrainingVideoMapper {
@ -11,7 +12,8 @@ public interface VetTrainingVideoMapper {
List<VetTrainingVideo> selectMyVideos(@Param("userId") Long userId,
@Param("title") String title,
@Param("category") String category,
@Param("status") String status);
@Param("status") String status,
@Param("auditStatus") String auditStatus);
List<VetTrainingVideo> selectPublicVideos(@Param("title") String title,
@Param("category") String category,
@ -24,5 +26,24 @@ public interface VetTrainingVideoMapper {
List<VetTrainingVideo> selectHotVideos(@Param("limit") Integer limit);
List<VetTrainingVideo> searchVideos(@Param("keyword") String keyword);
int deleteVideoById(@Param("id") Long id);
// 更新审核状态
int updateAuditStatus(@Param("id") Long id,
@Param("auditStatus") String auditStatus,
@Param("auditOpinion") String auditOpinion,
@Param("auditUserId") Long auditUserId,
@Param("auditTime") Date auditTime);
// 更新视频状态公开/私有
int updateStatus(@Param("id") Long id,
@Param("status") String status);
// 获取待审核视频列表
List<VetTrainingVideo> selectPendingAuditVideos(@Param("title") String title,
@Param("userName") String userName);
// 更新视频信息
int updateVideoInfo(VetTrainingVideo video);
}

48
chenhai-system/src/main/java/com/chenhai/vet/service/IVetKnowledgeService.java

@ -7,15 +7,15 @@ import com.chenhai.vet.domain.VetKnowledge;
/**
* 兽医文章Service接口
*
*
* @author ruoyi
* @date 2026-01-08
*/
public interface IVetKnowledgeService
public interface IVetKnowledgeService
{
/**
* 查询兽医文章
*
*
* @param id 兽医文章主键
* @return 兽医文章
*/
@ -23,7 +23,7 @@ public interface IVetKnowledgeService
/**
* 查询兽医文章列表
*
*
* @param vetKnowledge 兽医文章
* @return 兽医文章集合
*/
@ -31,7 +31,7 @@ public interface IVetKnowledgeService
/**
* 新增兽医文章
*
*
* @param vetKnowledge 兽医文章
* @return 结果
*/
@ -39,7 +39,7 @@ public interface IVetKnowledgeService
/**
* 修改兽医文章
*
*
* @param vetKnowledge 兽医文章
* @return 结果
*/
@ -47,7 +47,7 @@ public interface IVetKnowledgeService
/**
* 批量删除兽医文章
*
*
* @param ids 需要删除的兽医文章主键集合
* @return 结果
*/
@ -55,20 +55,44 @@ public interface IVetKnowledgeService
/**
* 删除兽医文章信息
*
*
* @param id 兽医文章主键
* @return 结果
*/
public int deleteVetKnowledgeById(Long id);
/**
* 上传文章待审核
* 提交审核
* @param id 文章ID
* @return 结果
*/
AjaxResult submitForAudit(Long id);
/**
* 审核文章
* @param id 文章ID
* @param auditStatus 审核状态2-审核通过 3-审核驳回
* @param auditComment 审核意见
* @return 结果
*/
AjaxResult uploadVetKnowledge(VetKnowledge vetKnowledge);
AjaxResult auditVetKnowledge(Long id, String auditStatus, String auditComment);
/**
* 发布文章更新状态为已发布
* 发布文章更新文章状态为已发布
*/
AjaxResult publishVetKnowledge(Long id);
}
/**
* 上架文章
* @param id 文章ID
* @return 结果
*/
AjaxResult onlineVetKnowledge(Long id);
/**
* 下架文章
* @param id 文章ID
* @return 结果
*/
AjaxResult offlineVetKnowledge(Long id, String auditComment);
}

1
chenhai-system/src/main/java/com/chenhai/vet/service/IVetProductService.java

@ -58,4 +58,5 @@ public interface IVetProductService
* @return 结果
*/
public int deleteVetProductById(Long id);
}

44
chenhai-system/src/main/java/com/chenhai/vet/service/IVetTrainingVideoService.java

@ -8,14 +8,14 @@ import java.util.List;
public interface IVetTrainingVideoService {
/**
* 上传并保存视频
* 上传并保存视频自动设为待审核
*/
String uploadAndSave(VetTrainingVideo video, MultipartFile videoFile, MultipartFile coverImage);
/**
* 获取我的视频列表
*/
List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status);
List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status, String auditStatus);
/**
* 获取公开视频列表
@ -48,4 +48,44 @@ public interface IVetTrainingVideoService {
List<VetTrainingVideo> searchVideos(String keyword);
int deleteVideoById(Long videoId);
/**
* 提交审核用户手动提交
*/
boolean submitForAudit(Long videoId, Long userId);
/**
* 取消审核用户主动取消
*/
boolean cancelAudit(Long videoId, Long userId);
/**
* 重新提交审核审核拒绝后
*/
boolean resubmitForAudit(Long videoId, Long userId);
/**
* 审核视频管理员
*/
boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId);
/**
* 上架视频审核通过后
*/
boolean publishVideo(Long videoId, Long userId);
/**
* 下架视频
*/
boolean offlineVideo(Long videoId, Long userId);
/**
* 获取待审核视频列表管理员
*/
List<VetTrainingVideo> getPendingAuditVideos(String title, String userName);
/**
* 编辑视频信息
*/
boolean updateVideoInfo(Long videoId, VetTrainingVideo video, Long userId);
}

257
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetKnowledgeServiceImpl.java

@ -13,21 +13,18 @@ import com.chenhai.vet.service.IVetKnowledgeService;
/**
* 兽医文章Service业务层处理
*
*
* @author ruoyi
* @date 2026-01-08
*/
@Service
public class VetKnowledgeServiceImpl implements IVetKnowledgeService
public class VetKnowledgeServiceImpl implements IVetKnowledgeService
{
@Autowired
private VetKnowledgeMapper vetKnowledgeMapper;
/**
* 查询兽医文章
*
* @param id 兽医文章主键
* @return 兽医文章
*/
@Override
public VetKnowledge selectVetKnowledgeById(Long id)
@ -37,9 +34,6 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
/**
* 查询兽医文章列表
*
* @param vetKnowledge 兽医文章
* @return 兽医文章
*/
@Override
public List<VetKnowledge> selectVetKnowledgeList(VetKnowledge vetKnowledge)
@ -49,22 +43,23 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
/**
* 新增兽医文章
*
* @param vetKnowledge 兽医文章
* @return 结果
*/
@Override
public int insertVetKnowledge(VetKnowledge vetKnowledge)
{
vetKnowledge.setCreateTime(DateUtils.getNowDate());
// 新增文章时默认状态为草稿审核状态为待审核
if (vetKnowledge.getArticleStatus() == null) {
vetKnowledge.setArticleStatus("0"); // 草稿
}
if (vetKnowledge.getAuditStatus() == null) {
vetKnowledge.setAuditStatus("0"); // 待审核
}
return vetKnowledgeMapper.insertVetKnowledge(vetKnowledge);
}
/**
* 修改兽医文章
*
* @param vetKnowledge 兽医文章
* @return 结果
*/
@Override
public int updateVetKnowledge(VetKnowledge vetKnowledge)
@ -75,9 +70,6 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
/**
* 批量删除兽医文章
*
* @param ids 需要删除的兽医文章主键
* @return 结果
*/
@Override
public int deleteVetKnowledgeByIds(Long[] ids)
@ -87,9 +79,6 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
/**
* 删除兽医文章信息
*
* @param id 兽医文章主键
* @return 结果
*/
@Override
public int deleteVetKnowledgeById(Long id)
@ -98,37 +87,223 @@ public class VetKnowledgeServiceImpl implements IVetKnowledgeService
}
/**
* 上传文章默认状态为0-待审核
* 提交审核将审核状态改为审核中
*/
@Override
public AjaxResult uploadVetKnowledge(VetKnowledge vetKnowledge) {
// 填充基础信息
vetKnowledge.setCreateBy(SecurityUtils.getUsername());
vetKnowledge.setCreateTime(DateUtils.getNowDate());
vetKnowledge.setStatus("0"); // 固定为待审核
public AjaxResult submitForAudit(Long id) {
try {
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) {
return AjaxResult.error("文章不存在");
}
// 只有草稿状态(0)且待审核状态(0)的文章才能提交审核
if (!"0".equals(current.getArticleStatus())) {
return AjaxResult.error("只有草稿状态的文章可以提交审核");
}
if (!"0".equals(current.getAuditStatus())) {
return AjaxResult.error("文章当前状态不能提交审核");
}
String username = SecurityUtils.getUsername();
if (username == null || username.trim().isEmpty()) {
username = "system";
}
System.out.println("当前用户: " + username);
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setAuditStatus("1"); // 审核中
vetKnowledge.setUpdateBy(username);
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
int result = vetKnowledgeMapper.insertVetKnowledge(vetKnowledge);
if (result > 0) {
return AjaxResult.success("文章上传成功,等待审核");
// 验证更新是否真的成功
if (result > 0) {
// 重新查询验证
VetKnowledge updated = vetKnowledgeMapper.selectVetKnowledgeById(id);
return AjaxResult.success("文章已提交审核,等待审核");
} else {
return AjaxResult.error("提交审核失败");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("提交审核失败: " + e.getMessage());
}
return AjaxResult.error("文章上传失败");
}
/**
* 发布文章更新状态为1-已发布
* 审核文章
*/
@Override
public AjaxResult auditVetKnowledge(Long id, String auditStatus, String auditComment) {
try {
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) {
return AjaxResult.error("文章不存在");
}
// 只有审核中状态(1)才能进行审核
if (!"1".equals(current.getAuditStatus())) {
return AjaxResult.error("只有审核中状态的文章可以审核");
}
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setAuditStatus(auditStatus); // 审核状态
vetKnowledge.setAuditComment(auditComment); // 审核意见
String username = SecurityUtils.getUsername();
if (username == null || username.trim().isEmpty()) {
username = "system";
}
vetKnowledge.setUpdateBy(username);
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
if (result > 0) {
String message = "2".equals(auditStatus) ? "文章审核通过" : "文章审核驳回";
return AjaxResult.success(message);
}
return AjaxResult.error("审核操作失败");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("审核操作失败: " + e.getMessage());
}
}
/**
* 发布文章审核通过的文章才能发布
*/
@Override
public AjaxResult publishVetKnowledge(Long id) {
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setStatus("1"); // 已发布
vetKnowledge.setUpdateBy(SecurityUtils.getUsername());
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
if (result > 0) {
return AjaxResult.success("文章发布成功");
try {
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) {
return AjaxResult.error("文章不存在");
}
// 只有审核通过(2)且为草稿状态(0)的文章才能发布
if (!"2".equals(current.getAuditStatus())) {
return AjaxResult.error("只有审核通过的文章可以发布");
}
if (!"0".equals(current.getArticleStatus())) {
return AjaxResult.error("文章当前状态不能发布");
}
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setArticleStatus("1"); // 已发布
String username = SecurityUtils.getUsername();
if (username == null || username.trim().isEmpty()) {
username = "system";
}
vetKnowledge.setUpdateBy(username);
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
if (result > 0) {
return AjaxResult.success("文章发布成功");
}
return AjaxResult.error("文章发布失败");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("文章发布失败: " + e.getMessage());
}
}
/**
* 上架文章将已下架的文章重新上架
*/
@Override
public AjaxResult onlineVetKnowledge(Long id) {
try {
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) {
return AjaxResult.error("文章不存在");
}
// 只有已下架状态(2)的文章才能上架
if (!"2".equals(current.getArticleStatus())) {
return AjaxResult.error("只有已下架的文章可以上架");
}
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setArticleStatus("1"); // 上架后变为已发布
String username = SecurityUtils.getUsername();
if (username == null || username.trim().isEmpty()) {
username = "system";
}
vetKnowledge.setUpdateBy(username);
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
if (result > 0) {
return AjaxResult.success("文章上架成功");
}
return AjaxResult.error("文章上架失败");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("文章上架失败: " + e.getMessage());
}
}
/**
* 下架文章将已发布的文章下架增加下架原因参数
*/
@Override
public AjaxResult offlineVetKnowledge(Long id, String auditComment) {
try {
VetKnowledge current = vetKnowledgeMapper.selectVetKnowledgeById(id);
if (current == null) {
return AjaxResult.error("文章不存在");
}
// 只有已发布状态(1)的文章才能下架
if (!"1".equals(current.getArticleStatus())) {
return AjaxResult.error("只有已发布的文章可以下架");
}
// 验证下架原因前端已经验证这里再次确认
if (auditComment == null || auditComment.trim().length() < 2) {
return AjaxResult.error("下架原因不能少于2个字");
}
if (auditComment.trim().length() > 200) {
return AjaxResult.error("下架原因不能超过200字");
}
VetKnowledge vetKnowledge = new VetKnowledge();
vetKnowledge.setId(id);
vetKnowledge.setArticleStatus("2"); // 已下架
vetKnowledge.setAuditComment(auditComment.trim()); // 存储下架原因到审核意见字段
String username = SecurityUtils.getUsername();
if (username == null || username.trim().isEmpty()) {
username = "system";
}
vetKnowledge.setUpdateBy(username);
vetKnowledge.setUpdateTime(DateUtils.getNowDate());
int result = vetKnowledgeMapper.updateVetKnowledge(vetKnowledge);
if (result > 0) {
return AjaxResult.success("文章下架成功");
}
return AjaxResult.error("文章下架失败");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("文章下架失败: " + e.getMessage());
}
return AjaxResult.error("文章发布失败");
}
}
}

4
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java

@ -1,11 +1,15 @@
package com.chenhai.vet.service.impl;
import java.util.Date;
import java.util.List;
import com.chenhai.vet.domain.VetTrainingVideo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.chenhai.vet.mapper.VetProductMapper;
import com.chenhai.vet.domain.VetProduct;
import com.chenhai.vet.service.IVetProductService;
import org.springframework.transaction.annotation.Transactional;
/**
* 兽医产品信息Service业务层处理

223
chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetTrainingVideoServiceImpl.java

@ -6,6 +6,7 @@ import com.chenhai.vet.service.IVetTrainingVideoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@ -27,6 +28,7 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
private String uploadPath;
@Override
@Transactional
public String uploadAndSave(VetTrainingVideo video, MultipartFile videoFile, MultipartFile coverImage) {
try {
// 1. 创建上传目录
@ -55,10 +57,12 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
}
// 5. 计算视频时长和大小
int duration = getVideoDuration(videoFile); // 需要实现这个方法
int duration = getVideoDuration(videoFile);
long fileSize = videoFile.getSize();
// 6. 保存到数据库
// 6. 设置初始状态私有 + 待审核
video.setStatus("0"); // 0-未上架/私有
video.setAuditStatus("0"); // 0-待审核
video.setVideoUrl("/uploads/" + uniqueFileName);
video.setCoverImage(coverImageUrl);
video.setDuration(duration);
@ -69,7 +73,7 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
videoMapper.insertVideo(video);
return "上传成功!视频ID:" + video.getId();
return "上传成功!视频已自动提交审核,请耐心等待管理员审核。";
} catch (IOException e) {
throw new RuntimeException("文件保存失败", e);
@ -77,12 +81,13 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
}
@Override
public List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status) {
return videoMapper.selectMyVideos(userId, title, category, status);
public List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status, String auditStatus) {
return videoMapper.selectMyVideos(userId, title, category, status, auditStatus);
}
@Override
public List<VetTrainingVideo> getPublicVideos(String title, String category, String vetName) {
// 只显示审核通过且公开的视频
return videoMapper.selectPublicVideos(title, category, vetName);
}
@ -94,8 +99,10 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
return null;
}
// 权限校验只能查看公开视频或自己的视频
boolean canView = "1".equals(video.getStatus()) || currentVetId.equals(video.getUserId());
// 权限校验只能查看自己的视频或审核通过公开的视频
boolean canView = "1".equals(video.getAuditStatus()) && // 1-审核通过
"1".equals(video.getStatus()) || // 1-已上架/公开
currentVetId.equals(video.getUserId());
return canView ? video : null;
}
@ -107,8 +114,10 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
return null;
}
// 权限校验
boolean canPlay = "1".equals(video.getStatus()) || currentVetId.equals(video.getUserId());
// 权限校验只能播放自己的视频或审核通过公开的视频
boolean canPlay = "1".equals(video.getAuditStatus()) && // 1-审核通过
"1".equals(video.getStatus()) || // 1-已上架/公开
currentVetId.equals(video.getUserId());
return canPlay ? video.getVideoUrl() : null;
}
@ -127,20 +136,200 @@ public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService {
return videoMapper.searchVideos(keyword);
}
@Override
@Transactional
public int deleteVideoById(Long videoId) {
return videoMapper.deleteVideoById(videoId);
}
@Override
@Transactional
public boolean submitForAudit(Long videoId, Long userId) {
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null || !userId.equals(video.getUserId())) {
return false;
}
// 只能提交无需审核或审核拒绝的视频
if (!"3".equals(video.getAuditStatus()) && // 3-无需审核
!"2".equals(video.getAuditStatus())) { // 2-审核拒绝
return false;
}
// 更新为待审核状态
int result = videoMapper.updateAuditStatus(videoId,
"0", // 0-待审核
"已提交审核",
null,
new Date());
return result > 0;
}
@Override
@Transactional
public boolean cancelAudit(Long videoId, Long userId) {
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null || !userId.equals(video.getUserId())) {
return false;
}
// 只能取消待审核状态的视频
if (!"0".equals(video.getAuditStatus())) { // 0-待审核
return false;
}
// 更新为无需审核状态
int result = videoMapper.updateAuditStatus(videoId,
"3", // 3-无需审核
"用户取消审核",
null,
new Date());
return result > 0;
}
@Override
@Transactional
public boolean resubmitForAudit(Long videoId, Long userId) {
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null || !userId.equals(video.getUserId())) {
return false;
}
// 只能重新提交审核拒绝状态的视频
if (!"2".equals(video.getAuditStatus())) { // 2-审核拒绝
return false;
}
// 更新为待审核状态
int result = videoMapper.updateAuditStatus(videoId,
"0", // 0-待审核
"重新提交审核",
null,
new Date());
return result > 0;
}
@Override
@Transactional
public boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId) {
// 验证审核状态
if (!"1".equals(auditStatus) && // 1-审核通过
!"2".equals(auditStatus)) { // 2-审核拒绝
return false;
}
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null) {
return false;
}
// 只能审核待审核状态的视频
if (!"0".equals(video.getAuditStatus())) { // 0-待审核
return false;
}
int result = videoMapper.updateAuditStatus(videoId,
auditStatus,
auditOpinion,
auditUserId,
new Date());
// 如果审核通过自动设置为私有状态等待用户上架
if (result > 0 && "1".equals(auditStatus)) { // 1-审核通过
videoMapper.updateStatus(videoId, "0"); // 0-未上架/私有
}
return result > 0;
}
@Override
@Transactional
public boolean publishVideo(Long videoId, Long userId) {
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null) {
return false;
}
// 权限校验只能操作自己的视频
if (!userId.equals(video.getUserId())) {
return false;
}
// 只能上架审核通过的视频
if (!"1".equals(video.getAuditStatus())) { // 1-审核通过
return false;
}
return videoMapper.updateStatus(videoId, "1") > 0; // 1-已上架/公开
}
@Override
@Transactional
public boolean offlineVideo(Long videoId, Long userId) {
VetTrainingVideo video = videoMapper.selectVideoById(videoId);
if (video == null) {
return false;
}
// 权限校验只能操作自己的视频
if (!userId.equals(video.getUserId())) {
return false;
}
// 只能下架已上架的视频
if (!"1".equals(video.getStatus())) { // 1-已上架/公开
return false;
}
return videoMapper.updateStatus(videoId, "0") > 0; // 0-未上架/私有
}
@Override
public List<VetTrainingVideo> getPendingAuditVideos(String title, String userName) {
return videoMapper.selectPendingAuditVideos(title, userName);
}
@Override
@Transactional
public boolean updateVideoInfo(Long videoId, VetTrainingVideo video, Long userId) {
VetTrainingVideo existingVideo = videoMapper.selectVideoById(videoId);
if (existingVideo == null || !userId.equals(existingVideo.getUserId())) {
return false;
}
// 只能编辑无需审核审核拒绝或私有状态的视频
boolean canEdit = "3".equals(existingVideo.getAuditStatus()) || // 3-无需审核
"2".equals(existingVideo.getAuditStatus()) || // 2-审核拒绝
"0".equals(existingVideo.getStatus()); // 0-未上架/私有
if (!canEdit) {
return false;
}
// 更新视频信息
existingVideo.setTitle(video.getTitle());
existingVideo.setDescription(video.getDescription());
existingVideo.setCategory(video.getCategory());
existingVideo.setUpdateTime(new Date());
return videoMapper.updateVideoInfo(existingVideo) > 0;
}
private String getFileExtension(String fileName) {
if (fileName == null || fileName.lastIndexOf(".") == -1) {
return "mp4";
}
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
private int getVideoDuration(MultipartFile videoFile) {
// 这里需要实现获取视频时长的方法
// 可以使用 FFmpeg Java 的库来获取
// 暂时返回一个默认值
return 60; // 默认60秒
}
@Override
public int deleteVideoById(Long videoId) {
// 逻辑删除设置 del_flag = '1'
return videoMapper.deleteVideoById(videoId);
}
}

43
chenhai-system/src/main/resources/mapper/vet/VetKnowledgeMapper.xml

@ -1,16 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.vet.mapper.VetKnowledgeMapper">
<resultMap type="VetKnowledge" id="VetKnowledgeResult">
<result property="id" column="id" />
<result property="title" column="title" />
<result property="content" column="content" />
<result property="category" column="category" />
<result property="sensitiveWords" column="sensitive_words" />
<result property="status" column="status" />
<result property="articleStatus" column="article_status" />
<result property="auditStatus" column="audit_status" />
<result property="auditComment" column="audit_comment" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@ -19,20 +21,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectVetKnowledgeVo">
select id, title, content, category, sensitive_words, status, create_by, create_time, update_by, update_time, remark from vet_knowledge
select id, title, content, category, sensitive_words, article_status, audit_status, audit_comment, create_by, create_time, update_by, update_time, remark from vet_knowledge
</sql>
<select id="selectVetKnowledgeList" parameterType="VetKnowledge" resultMap="VetKnowledgeResult">
<include refid="selectVetKnowledgeVo"/>
<where>
<if test="title != null and title != ''"> and title = #{title}</if>
<if test="content != null and content != ''"> and content = #{content}</if>
<where>
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
<if test="content != null and content != ''"> and content like concat('%', #{content}, '%')</if>
<if test="category != null and category != ''"> and category = #{category}</if>
<if test="sensitiveWords != null and sensitiveWords != ''"> and sensitive_words = #{sensitiveWords}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="sensitiveWords != null and sensitiveWords != ''"> and sensitive_words like concat('%', #{sensitiveWords}, '%')</if>
<if test="articleStatus != null and articleStatus != ''"> and article_status = #{articleStatus}</if>
<if test="auditStatus != null and auditStatus != ''"> and audit_status = #{auditStatus}</if>
</where>
</select>
<select id="selectVetKnowledgeById" parameterType="Long" resultMap="VetKnowledgeResult">
<include refid="selectVetKnowledgeVo"/>
where id = #{id}
@ -45,25 +48,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="content != null and content != ''">content,</if>
<if test="category != null and category != ''">category,</if>
<if test="sensitiveWords != null">sensitive_words,</if>
<if test="status != null">status,</if>
<if test="articleStatus != null">article_status,</if>
<if test="auditStatus != null">audit_status,</if>
<if test="auditComment != null">audit_comment,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
</trim>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="title != null and title != ''">#{title},</if>
<if test="content != null and content != ''">#{content},</if>
<if test="category != null and category != ''">#{category},</if>
<if test="sensitiveWords != null">#{sensitiveWords},</if>
<if test="status != null">#{status},</if>
<if test="articleStatus != null">#{articleStatus},</if>
<if test="auditStatus != null">#{auditStatus},</if>
<if test="auditComment != null">#{auditComment},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</trim>
</insert>
<update id="updateVetKnowledge" parameterType="VetKnowledge">
@ -73,7 +80,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="content != null and content != ''">content = #{content},</if>
<if test="category != null and category != ''">category = #{category},</if>
<if test="sensitiveWords != null">sensitive_words = #{sensitiveWords},</if>
<if test="status != null">status = #{status},</if>
<if test="articleStatus != null">article_status = #{articleStatus},</if>
<if test="auditStatus != null">audit_status = #{auditStatus},</if>
<if test="auditComment != null">audit_comment = #{auditComment},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
@ -88,7 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deleteVetKnowledgeByIds" parameterType="String">
delete from vet_knowledge where id in
delete from vet_knowledge where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>

2
chenhai-system/src/main/resources/mapper/vet/VetProductMapper.xml

@ -36,7 +36,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectVetProductVo">
select id, name, type, category, specification, unit, manufacturer, approval_number, ingredients, indications, usage_dosage, price, cost_price, stock, min_stock, main_image, images, treat_animals, treat_diseases, treatment_content, treatment_duration, precautions, status, is_deleted, clinic_id, vet_id, created_at, updated_at from vet_product
select id, name, type, category, specification, unit, manufacturer, approval_number, ingredients, indications, usage_dosage, price, cost_price, stock, min_stock, main_image, images, treat_animals, treat_diseases, treatment_content, treatment_duration, precautions, status, is_deleted, clinic_id, user_id, created_at, updated_at from vet_product
</sql>
<select id="selectVetProductList" parameterType="VetProduct" resultMap="VetProductResult">

88
chenhai-system/src/main/resources/mapper/vet/VetTrainingVideoMapper.xml

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenhai.vet.mapper.VetTrainingVideoMapper">
<resultMap id="VideoResult" type="VetTrainingVideo">
@ -17,21 +15,27 @@
<result property="fileSize" column="file_size"/>
<result property="viewCount" column="view_count"/>
<result property="status" column="status"/>
<result property="auditStatus" column="audit_status"/>
<result property="auditOpinion" column="audit_opinion"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="userName" column="user_name"/>
<result property="auditUserId" column="audit_user_id"/>
<result property="auditTime" column="audit_time"/>
</resultMap>
<insert id="insertVideo" parameterType="VetTrainingVideo" useGeneratedKeys="true" keyProperty="id">
INSERT INTO vet_training_video (
user_id, title, description, video_url, cover_image,
category, tags, duration, file_size, view_count,
status, create_time, update_time
user_id, title, description, video_url, cover_image,
category, tags, duration, file_size, view_count,
status, audit_status, audit_opinion,
create_time, update_time
) VALUES (
#{userId}, #{title}, #{description}, #{videoUrl}, #{coverImage},
#{category}, #{tags}, #{duration}, #{fileSize}, #{viewCount},
#{status}, #{createTime}, #{updateTime}
)
#{userId}, #{title}, #{description}, #{videoUrl}, #{coverImage},
#{category}, #{tags}, #{duration}, #{fileSize}, #{viewCount},
#{status}, #{auditStatus}, #{auditOpinion},
#{createTime}, #{updateTime}
)
</insert>
<select id="selectMyVideos" resultMap="VideoResult">
@ -48,6 +52,9 @@
<if test="status != null and status != ''">
AND v.status = #{status}
</if>
<if test="auditStatus != null and auditStatus != ''">
AND v.audit_status = #{auditStatus}
</if>
ORDER BY v.create_time DESC
</select>
@ -56,6 +63,7 @@
FROM vet_training_video v
LEFT JOIN sys_user u ON v.user_id = u.user_id
WHERE v.status = '1'
AND v.audit_status = '1'
<if test="title != null and title != ''">
AND v.title LIKE CONCAT('%', #{title}, '%')
</if>
@ -71,7 +79,7 @@
<select id="selectVideoById" resultMap="VideoResult">
SELECT v.*, u.nick_name as user_name
FROM vet_training_video v
LEFT JOIN sys_user u ON v.user_id = u.user_id
LEFT JOIN sys_user u ON v.user_id = u.user_id
WHERE v.id = #{id}
</select>
@ -84,21 +92,23 @@
<select id="selectHotVideos" resultMap="VideoResult">
SELECT v.*, u.nick_name as user_name
FROM vet_training_video v
LEFT JOIN sys_user u ON v.user_id = u.user_id
LEFT JOIN sys_user u ON v.user_id = u.user_id
WHERE v.status = '1'
AND v.audit_status = '1'
ORDER BY v.view_count DESC
LIMIT #{limit}
LIMIT #{limit}
</select>
<select id="searchVideos" resultMap="VideoResult">
SELECT v.*, u.nick_name as user_name
FROM vet_training_video v
LEFT JOIN sys_user u ON v.user_id = u.user_id
LEFT JOIN sys_user u ON v.user_id = u.user_id
WHERE v.status = '1'
AND (v.title LIKE CONCAT('%', #{keyword}, '%')
OR v.description LIKE CONCAT('%', #{keyword}, '%')
OR v.tags LIKE CONCAT('%', #{keyword}, '%')
OR u.nick_name LIKE CONCAT('%', #{keyword}, '%'))
AND v.audit_status = '1'
AND (v.title LIKE CONCAT('%', #{keyword}, '%')
OR v.description LIKE CONCAT('%', #{keyword}, '%')
OR v.tags LIKE CONCAT('%', #{keyword}, '%')
OR u.nick_name LIKE CONCAT('%', #{keyword}, '%'))
ORDER BY v.create_time DESC
</select>
@ -106,4 +116,44 @@
DELETE FROM vet_training_video
WHERE id = #{id}
</delete>
<update id="updateAuditStatus">
UPDATE vet_training_video
SET audit_status = #{auditStatus},
audit_opinion = #{auditOpinion},
audit_user_id = #{auditUserId},
audit_time = #{auditTime},
update_time = NOW()
WHERE id = #{id}
</update>
<update id="updateStatus">
UPDATE vet_training_video
SET status = #{status},
update_time = NOW()
WHERE id = #{id}
</update>
<select id="selectPendingAuditVideos" resultMap="VideoResult">
SELECT v.*, u.nick_name as user_name
FROM vet_training_video v
LEFT JOIN sys_user u ON v.user_id = u.user_id
WHERE v.audit_status = '0'
<if test="title != null and title != ''">
AND v.title LIKE CONCAT('%', #{title}, '%')
</if>
<if test="userName != null and userName != ''">
AND u.nick_name LIKE CONCAT('%', #{userName}, '%')
</if>
ORDER BY v.create_time DESC
</select>
<update id="updateVideoInfo" parameterType="VetTrainingVideo">
UPDATE vet_training_video
SET title = #{title},
description = #{description},
category = #{category},
update_time = NOW()
WHERE id = #{id}
</update>
</mapper>

39
chenhai-ui/src/api/vet/knowledge.js

@ -42,12 +42,22 @@ export function delKnowledge(id) {
method: 'delete'
})
}
// 上传文章(待审核)
export function uploadKnowledge(data) {
// 提交审核
export function submitForAudit(id) {
return request({
url: '/vet/knowledge/upload',
method: 'post',
data: data
url: '/vet/knowledge/submit/' + id,
method: 'put'
})
}
export function auditVetKnowledge(id, auditStatus, auditComment) {
return request({
url: '/vet/knowledge/audit/' + id,
method: 'put',
params: { // 使用params传递查询参数
auditStatus: auditStatus, // 参数名改为auditStatus
auditComment: auditComment
}
})
}
@ -58,3 +68,22 @@ export function publishKnowledge(id) {
method: 'put'
})
}
// 上架文章
export function onlineVetKnowledge(id) {
return request({
url: '/vet/knowledge/online/' + id,
method: 'put'
})
}
// 下架文章
export function offlineVetKnowledge(id, auditComment) {
return request({
url: '/vet/knowledge/offline/' + id,
method: 'put',
params: {
auditComment: auditComment // 使用 auditComment 作为参数名,后端会存储到 audit_comment 字段
}
})
}

101
chenhai-ui/src/api/vet/training.js

@ -1,21 +1,18 @@
// src/api/vet/training.js
// trainingApi.js - 完整修正版
import request from '@/utils/request'
// 兽医培训视频相关接口
export default {
// 上传视频
uploadVideo(data) {
// 注意:这里直接返回请求,不要重新创建 FormData
return request({
url: '/vet/training/upload',
method: 'post',
data: data, // data 已经是 FormData 对象
data: data,
headers: {
'Content-Type': 'multipart/form-data'
},
timeout: 300000
})
},
// 获取公开视频列表
@ -23,22 +20,16 @@ export default {
return request({
url: '/vet/training/public-videos',
method: 'get',
params
params: params
})
},
// 获取我的视频
getMyVideos(params = {}) {
getMyVideos(params) {
return request({
url: '/vet/training/my-videos',
method: 'get',
params: {
pageNum: params.pageNum || 1,
pageSize: params.pageSize || 10,
title: params.title || '',
category: params.category || '',
status: params.status || ''
}
params: params
})
},
@ -50,37 +41,85 @@ export default {
})
},
// 获取播放地址(可选
getPlayUrl(id) {
// 提交审核(用户提交给管理员
submitForAudit(videoId) {
return request({
url: `/vet/training/video/play/${id}`,
method: 'get'
url: `/vet/training/submit-audit/${videoId}`,
method: 'post'
})
},
// 删除视频
deleteVideo(id) {
// 取消审核
cancelAudit(videoId) {
return request({
url: `/vet/training/${id}`,
method: 'delete'
url: `/vet/training/cancel-audit/${videoId}`,
method: 'post'
})
},
// 搜索视频
searchVideos(keyword) {
// 重新提交审核
resubmitAudit(videoId) {
return request({
url: '/vet/training/search',
method: 'get',
params: { keyword }
url: `/vet/training/resubmit-audit/${videoId}`,
method: 'post'
})
},
// 审核视频(管理员审核)
auditVideo(videoId, auditStatus, auditOpinion = '') {
// 改用JSON方式传递参数
const data = {
auditStatus: auditStatus,
auditOpinion: auditOpinion || ''
}
return request({
url: `/vet/training/audit/${videoId}`,
method: 'post',
data: data,
headers: {
'Content-Type': 'application/json'
}
})
},
// 上架视频
publishVideo(videoId) {
return request({
url: `/vet/training/publish/${videoId}`,
method: 'post'
})
},
// 下架视频
offlineVideo(videoId) {
return request({
url: `/vet/training/offline/${videoId}`,
method: 'post'
})
},
// 获取热门视频
getHotVideos(limit = 10) {
// 获取待审核视频列表
getPendingAuditVideos(params) {
return request({
url: '/vet/training/hot-videos',
url: '/vet/training/pending-audit',
method: 'get',
params: { limit }
params: params
})
},
// 更新视频信息
updateVideoInfo(videoId, data) {
return request({
url: `/vet/training/update/${videoId}`,
method: 'put',
data: data
})
},
// 删除视频
deleteVideo(videoId) {
return request({
url: `/vet/training/${videoId}`,
method: 'delete'
})
}
}

585
chenhai-ui/src/views/vet/knowledge/index.vue

@ -10,27 +10,45 @@
/>
</el-form-item>
<el-form-item label="文章分类" prop="category">
<!-- 优化分类改为下拉选择避免手动输入不规范 -->
<el-select
v-model="queryParams.category"
placeholder="请选择文章分类"
clearable
@keyup.enter.native="handleQuery"
>
<el-option label="治疗防治" value="治疗防治" />
<el-option label="饲养管理" value="饲养管理" />
<el-option label="其他" value="其他" />
<el-option
v-for="dict in categoryOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-form-item label="文章状态" prop="articleStatus">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
v-model="queryParams.articleStatus"
placeholder="请选择文章状态"
clearable
>
<el-option
v-for="dict in articleStatusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="auditStatus">
<el-select
v-model="queryParams.auditStatus"
placeholder="请选择审核状态"
clearable
@keyup.enter.native="handleQuery"
>
<el-option label="待审核" value="0" />
<el-option label="已发布" value="1" />
<el-option
v-for="dict in auditStatusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item>
@ -44,33 +62,44 @@
<el-button
type="primary"
plain
icon="el-icon-upload2"
icon="el-icon-plus"
size="mini"
@click="handleUpload"
v-hasPermi="['vet:knowledge:upload']"
>上传文章</el-button>
@click="handleAdd"
v-hasPermi="['vet:knowledge:add']"
>新增文章</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
type="info"
plain
icon="el-icon-check"
icon="el-icon-s-promotion"
size="mini"
:disabled="single"
@click="handlePublish"
v-hasPermi="['vet:knowledge:publish']"
>发布文章</el-button>
@click="handleSubmitAudit"
v-hasPermi="['vet:knowledge:submit']"
>提交审核</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
type="primary"
plain
icon="el-icon-edit"
icon="el-icon-finished"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['vet:knowledge:edit']"
>修改</el-button>
@click="handleAuditDialog"
v-hasPermi="['vet:knowledge:audit']"
>审核</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-check"
size="mini"
:disabled="single"
@click="handlePublish"
v-hasPermi="['vet:knowledge:publish']"
>发布文章</el-button>
</el-col>
<el-col :span="1.5">
<el-button
@ -98,41 +127,110 @@
<el-table v-loading="loading" :data="knowledgeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键" align="center" prop="id" />
<el-table-column label="文章标题" align="center" prop="title" min-width="200" />
<el-table-column label="文章分类" align="center" prop="category" width="120" />
<!-- 优化状态显示为标签样式更直观 -->
<el-table-column label="状态" align="center" prop="status" width="100">
<el-table-column label="文章标题" align="center" prop="title" min-width="200" show-overflow-tooltip />
<!-- 文章分类列 - 使用 el-tag 显示颜色 -->
<el-table-column label="文章分类" align="center" prop="category" width="120">
<template slot-scope="scope">
<el-tag :type="getCategoryTagType(scope.row.category)">
{{ scope.row.category }}
</el-tag>
</template>
</el-table-column>
<!-- 文章状态列 - 使用 el-tag 显示颜色 -->
<el-table-column label="文章状态" align="center" prop="articleStatus" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === '0'" type="warning">待审核</el-tag>
<el-tag v-if="scope.row.status === '1'" type="success">已发布</el-tag>
<el-tag :type="getArticleStatusTagType(scope.row.articleStatus)" size="small">
{{ getArticleStatusLabel(scope.row.articleStatus) }}
</el-tag>
</template>
</el-table-column>
<!-- 审核状态列 - 使用 el-tag 显示颜色 -->
<el-table-column label="审核状态" align="center" prop="auditStatus" width="120">
<template slot-scope="scope">
<el-tag :type="getAuditStatusTagType(scope.row.auditStatus)" size="small">
{{ getAuditStatusLabel(scope.row.auditStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审核意见" align="center" prop="auditComment" width="150" show-overflow-tooltip>
<template slot-scope="scope">
<span v-if="scope.row.auditComment">{{ scope.row.auditComment }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createBy" width="100" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
>查看</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['vet:knowledge:edit']"
v-if="scope.row.articleStatus === '0' && scope.row.auditStatus === '0'"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-promotion"
@click="handleSubmitAudit(scope.row.id)"
v-hasPermi="['vet:knowledge:submit']"
v-if="scope.row.articleStatus === '0' && scope.row.auditStatus === '0'"
>提交审核</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-finished"
@click="handleAuditDialog(scope.row.id)"
v-hasPermi="['vet:knowledge:audit']"
v-if="scope.row.auditStatus === '1'"
>审核</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-check"
@click="handlePublish(scope.row.id)"
v-hasPermi="['vet:knowledge:publish']"
v-if="scope.row.status === '0'"
v-if="scope.row.auditStatus === '2' && scope.row.articleStatus === '0'"
>发布</el-button>
<!-- 下架按钮已发布状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-bottom"
style="color: #E6A23C"
@click="handleOffline(scope.row)"
v-hasPermi="['vet:knowledge:publish']"
v-if="scope.row.articleStatus === '1'"
>下架</el-button>
<!-- 上架按钮已下架状态显示 -->
<el-button
size="mini"
type="text"
icon="el-icon-top"
style="color: #67C23A"
@click="handleOnline(scope.row)"
v-hasPermi="['vet:knowledge:publish']"
v-if="scope.row.articleStatus === '2'"
>上架</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['vet:knowledge:remove']"
v-if="scope.row.articleStatus === '0'"
>删除</el-button>
</template>
</el-table-column>
@ -146,21 +244,23 @@
@pagination="getList"
/>
<!-- 添加/上传/修改兽医文章对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
<!-- 新增/修改文章对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文章标题" prop="title">
<el-input v-model="form.title" placeholder="请输入文章标题" />
</el-form-item>
<el-form-item label="文章内容" prop="content">
<editor v-model="form.content" :min-height="200"/>
<editor v-model="form.content" :min-height="300"/>
</el-form-item>
<el-form-item label="文章分类" prop="category">
<!-- 优化分类下拉选择固定选项 -->
<el-select v-model="form.category" placeholder="请选择文章分类">
<el-option label="治疗防治" value="治疗防治" />
<el-option label="饲养管理" value="饲养管理" />
<el-option label="其他" value="其他" />
<el-option
v-for="dict in categoryOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
@ -172,12 +272,81 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 审核对话框 -->
<el-dialog title="文章审核" :visible.sync="auditOpen" width="500px" append-to-body>
<el-form ref="auditForm" :model="auditForm" label-width="80px">
<el-form-item label="审核结果" prop="auditStatus" required>
<el-radio-group v-model="auditForm.auditStatus">
<el-radio label="2">审核通过</el-radio>
<el-radio label="3">审核驳回</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="审核意见" prop="auditComment">
<el-input
v-model="auditForm.auditComment"
type="textarea"
:rows="4"
placeholder="请输入审核意见(可选)"
maxlength="500"
show-word-limit
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAudit"> </el-button>
<el-button @click="cancelAudit"> </el-button>
</div>
</el-dialog>
<!-- 查看详情对话框 -->
<el-dialog title="文章详情" :visible.sync="viewOpen" width="900px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="文章标题">{{ viewData.title }}</el-descriptions-item>
<el-descriptions-item label="文章分类">
<el-tag :type="getCategoryTagType(viewData.category)">
{{ viewData.category }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="文章状态">
<el-tag :type="getArticleStatusTagType(viewData.articleStatus)">
{{ getArticleStatusLabel(viewData.articleStatus) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="审核状态">
<el-tag :type="getAuditStatusTagType(viewData.auditStatus)">
{{ getAuditStatusLabel(viewData.auditStatus) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="审核意见" :span="2">
{{ viewData.auditComment || '无' }}
</el-descriptions-item>
<el-descriptions-item label="创建人">{{ viewData.createBy }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ viewData.createTime }}</el-descriptions-item>
</el-descriptions>
<el-divider>文章内容</el-divider>
<div class="content-view" v-html="viewData.content"></div>
<div slot="footer" class="dialog-footer">
<el-button @click="viewOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
// APIuploadKnowledgepublishKnowledge
import { listKnowledge, getKnowledge, delKnowledge, addKnowledge, updateKnowledge, uploadKnowledge, publishKnowledge } from "@/api/vet/knowledge"
import {
listKnowledge,
getKnowledge,
delKnowledge,
addKnowledge,
updateKnowledge,
submitForAudit,
auditVetKnowledge,
publishKnowledge,
onlineVetKnowledge,
offlineVetKnowledge
} from "@/api/vet/knowledge"
import { getDicts } from "@/api/system/dict/data" //
export default {
name: "Knowledge",
@ -201,16 +370,33 @@ export default {
title: "",
//
open: false,
//
auditOpen: false,
//
viewOpen: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
category: null,
status: null, //
articleStatus: null,
auditStatus: null,
},
//
form: {},
//
auditForm: {
id: null,
auditStatus: "2", //
auditComment: ""
},
//
viewData: {},
//
categoryOptions: [], //
articleStatusOptions: [], //
auditStatusOptions: [], //
//
rules: {
title: [
@ -226,23 +412,124 @@ export default {
}
},
created() {
this.getDictsData() //
this.getList()
},
methods: {
/** 获取字典数据 */
getDictsData() {
//
getDicts("article_category").then(response => {
this.categoryOptions = response.data
}).catch(error => {
console.error("获取文章分类字典失败:", error)
this.categoryOptions = []
})
//
getDicts("article_status").then(response => {
this.articleStatusOptions = response.data
}).catch(error => {
console.error("获取文章状态字典失败:", error)
this.articleStatusOptions = []
})
//
getDicts("vet_audit_status").then(response => {
this.auditStatusOptions = response.data
}).catch(error => {
console.error("获取审核状态字典失败:", error)
this.auditStatusOptions = []
})
},
/** 查询兽医文章列表 */
getList() {
this.loading = true
listKnowledge(this.queryParams).then(response => {
this.knowledgeList = response.rows
//
const list = response.rows.map(item => ({
...item,
articleStatus: String(item.articleStatus || '0'),
auditStatus: String(item.auditStatus || '0')
}))
this.knowledgeList = list
this.total = response.total
this.loading = false
}).catch(error => {
console.error("获取文章列表失败:", error)
this.loading = false
this.$modal.msgError("获取文章列表失败")
})
},
//
getCategoryTagType(category) {
const map = {
'治疗防治': 'primary', //
'饲养管理': 'success', // 绿
'其他': 'info' //
}
return map[category] || 'info'
},
//
getArticleStatusTagType(status) {
const map = {
'0': 'info', // 稿 -
'1': 'success', // - 绿
'2': 'warning' // -
}
return map[status] || 'info'
},
//
getArticleStatusLabel(status) {
const map = {
'0': '草稿',
'1': '已发布',
'2': '已下架'
}
return map[status] || status
},
//
getAuditStatusTagType(status) {
const map = {
'0': 'info', // -
'1': 'warning', // -
'2': 'success', // - 绿
'3': 'danger', // -
'4': 'danger' // -
}
return map[status] || 'info'
},
//
getAuditStatusLabel(status) {
const map = {
'0': '待审核',
'1': '审核中',
'2': '审核通过',
'3': '审核驳回',
'4': '敏感内容驳回'
}
return map[status] || status
},
//
cancel() {
this.open = false
this.reset()
},
//
cancelAudit() {
this.auditOpen = false
this.resetAuditForm()
},
//
reset() {
this.form = {
@ -250,7 +537,9 @@ export default {
title: null,
content: null,
category: null,
status: null, //
articleStatus: "0", // 稿
auditStatus: "0", //
auditComment: null,
createBy: null,
createTime: null,
updateBy: null,
@ -259,11 +548,25 @@ export default {
}
this.resetForm("form")
},
//
resetAuditForm() {
this.auditForm = {
id: null,
auditStatus: "2",
auditComment: ""
}
if (this.$refs.auditForm) {
this.$refs.auditForm.resetFields()
}
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
@ -272,48 +575,185 @@ export default {
pageSize: 10,
title: null,
category: null,
status: null,
articleStatus: null,
auditStatus: null,
}
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 上传文章按钮操作(替代原新增) */
handleUpload() {
/** 新增文章按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "上传兽医文章"
this.title = "新增文章"
},
/** 提交审核按钮操作 */
handleSubmitAudit(id) {
const articleId = id || this.ids[0]
if (!articleId) {
this.$modal.msgWarning("请选择需要提交审核的文章")
return
}
this.$modal.confirm('是否确认提交文章进行审核?').then(() => {
return submitForAudit(articleId)
}).then(response => {
this.getList()
this.$modal.msgSuccess(response.msg || "提交审核成功")
}).catch(() => {})
},
/** 打开审核对话框 */
handleAuditDialog(id) {
const articleId = id || this.ids[0]
if (!articleId) {
this.$modal.msgWarning("请选择需要审核的文章")
return
}
this.auditForm.id = articleId
this.auditOpen = true
},
/** 提交审核 */
submitAudit() {
this.$refs["auditForm"].validate(valid => {
if (valid) {
auditVetKnowledge(this.auditForm.id, this.auditForm.auditStatus, this.auditForm.auditComment).then(response => {
this.$modal.msgSuccess(response.msg || "审核成功")
this.auditOpen = false
this.getList()
this.resetAuditForm()
})
}
})
},
/** 发布文章按钮操作 */
handlePublish(id) {
// /
const ids = id || this.ids
if (ids.length === 0) {
const articleId = id || this.ids[0]
if (!articleId) {
this.$modal.msgWarning("请选择需要发布的文章")
return
}
this.$modal.confirm('是否确认发布选中的文章?').then(() => {
return publishKnowledge(ids)
}).then(() => {
this.$modal.confirm('是否确认发布文章?').then(() => {
return publishKnowledge(articleId)
}).then(response => {
this.getList()
this.$modal.msgSuccess("发布成功")
this.$modal.msgSuccess(response.msg || "发布成功")
}).catch(() => {})
},
/** 上架文章操作 */
handleOnline(row) {
const articleId = row.id || this.ids[0]
if (!articleId) {
this.$modal.msgWarning("请选择需要上架的文章")
return
}
this.$confirm('确认要上架此文章吗?', '上架确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.loading = true
onlineVetKnowledge(articleId).then(response => {
this.loading = false
if (response.code === 200) {
this.$modal.msgSuccess('上架成功')
this.getList() //
} else {
this.$modal.msgError(response.msg || '上架失败')
}
}).catch(error => {
this.loading = false
this.$modal.msgError(error.msg || '上架失败')
})
}).catch(() => {
//
})
},
/** 下架文章操作 */
handleOffline(row) {
const articleId = row.id || this.ids[0]
if (!articleId) {
this.$modal.msgWarning("请选择需要下架的文章")
return
}
this.$prompt('请输入下架原因', '下架确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPlaceholder: '请输入下架原因(如:内容过时、违规操作等)',
inputValidator: (value) => {
if (!value || value.trim().length < 2) {
return '下架原因不能少于2个字'
}
if (value.trim().length > 200) {
return '下架原因不能超过200字'
}
return true
}
}).then(({ value }) => {
this.loading = true
offlineVetKnowledge(articleId, value.trim()).then(response => {
this.loading = false
if (response.code === 200) {
this.$modal.msgSuccess('下架成功')
this.getList() //
} else {
this.$modal.msgError(response.msg || '下架失败')
}
}).catch(error => {
this.loading = false
this.$modal.msgError(error.msg || '下架失败')
})
}).catch(() => {
//
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
const id = row.id || this.ids[0]
getKnowledge(id).then(response => {
this.form = response.data
const data = response.data
//
this.form = {
...data,
articleStatus: String(data.articleStatus || '0'),
auditStatus: String(data.auditStatus || '0')
}
this.open = true
this.title = "修改兽医文章"
this.title = "修改文章"
})
},
/** 提交按钮(区分上传/修改) */
/** 查看按钮操作 */
handleView(row) {
const id = row.id || this.ids[0]
getKnowledge(id).then(response => {
const data = response.data
//
this.viewData = {
...data,
articleStatus: String(data.articleStatus || '0'),
auditStatus: String(data.auditStatus || '0')
}
this.viewOpen = true
})
},
/** 提交按钮(区分新增/修改) */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
@ -325,9 +765,9 @@ export default {
this.getList()
})
} else {
//
uploadKnowledge(this.form).then(response => {
this.$modal.msgSuccess(response.msg || "上传成功")
//
addKnowledge(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
@ -335,16 +775,18 @@ export default {
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除兽医文章编号为"' + ids + '"的数据项?').then(() => {
this.$modal.confirm('是否确认删除选中的文章?').then(() => {
return delKnowledge(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('vet/knowledge/export', {
@ -354,3 +796,14 @@ export default {
}
}
</script>
<style scoped>
.content-view {
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 4px;
min-height: 200px;
max-height: 400px;
overflow-y: auto;
}
</style>

1851
chenhai-ui/src/views/vet/product/index.vue
File diff suppressed because it is too large
View File

2208
chenhai-ui/src/views/vet/training/TrainingHome.vue
File diff suppressed because it is too large
View File

Loading…
Cancel
Save