30 changed files with 5216 additions and 2332 deletions
-
176chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysAnswersController.java
-
129chenhai-admin/src/main/java/com/chenhai/web/controller/system/SysQuestionsController.java
-
415chenhai-admin/src/main/java/com/chenhai/web/controller/vet/VetTrainingVideoController.java
-
160chenhai-system/src/main/java/com/chenhai/system/domain/SysAnswers.java
-
13chenhai-system/src/main/java/com/chenhai/system/domain/SysPolicyInterpretation.java
-
186chenhai-system/src/main/java/com/chenhai/system/domain/SysQuestions.java
-
78chenhai-system/src/main/java/com/chenhai/system/mapper/SysAnswersMapper.java
-
94chenhai-system/src/main/java/com/chenhai/system/mapper/SysQuestionsMapper.java
-
93chenhai-system/src/main/java/com/chenhai/system/service/ISysAnswersService.java
-
106chenhai-system/src/main/java/com/chenhai/system/service/ISysQuestionsService.java
-
243chenhai-system/src/main/java/com/chenhai/system/service/impl/SysAnswersServiceImpl.java
-
248chenhai-system/src/main/java/com/chenhai/system/service/impl/SysQuestionsServiceImpl.java
-
12chenhai-system/src/main/java/com/chenhai/vet/domain/VetKnowledge.java
-
165chenhai-system/src/main/java/com/chenhai/vet/domain/VetTrainingVideo.java
-
96chenhai-system/src/main/java/com/chenhai/vet/mapper/VetTrainingVideoMapper.java
-
130chenhai-system/src/main/java/com/chenhai/vet/service/IVetTrainingVideoService.java
-
3chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetProductServiceImpl.java
-
618chenhai-system/src/main/java/com/chenhai/vet/service/impl/VetTrainingVideoServiceImpl.java
-
112chenhai-system/src/main/resources/mapper/system/SysAnswersMapper.xml
-
19chenhai-system/src/main/resources/mapper/system/SysPolicyInterpretationMapper.xml
-
143chenhai-system/src/main/resources/mapper/system/SysQuestionsMapper.xml
-
9chenhai-system/src/main/resources/mapper/vet/VetKnowledgeMapper.xml
-
366chenhai-system/src/main/resources/mapper/vet/VetTrainingVideoMapper.xml
-
44chenhai-ui/src/api/system/answers.js
-
44chenhai-ui/src/api/system/questions.js
-
269chenhai-ui/src/api/vet/training.js
-
252chenhai-ui/src/views/system/answers/index.vue
-
584chenhai-ui/src/views/system/questions/index.vue
-
1547chenhai-ui/src/views/vet/training/TrainingHome.vue
-
1120chenhai-ui/src/views/vet/training/index.vue
@ -0,0 +1,176 @@ |
|||||
|
package com.chenhai.web.controller.system; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.PutMapping; |
||||
|
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.RestController; |
||||
|
import com.chenhai.common.annotation.Log; |
||||
|
import com.chenhai.common.core.controller.BaseController; |
||||
|
import com.chenhai.common.core.domain.AjaxResult; |
||||
|
import com.chenhai.common.enums.BusinessType; |
||||
|
import com.chenhai.system.domain.SysAnswers; |
||||
|
import com.chenhai.system.service.ISysAnswersService; |
||||
|
import com.chenhai.system.service.ISysQuestionsService; |
||||
|
import com.chenhai.common.utils.poi.ExcelUtil; |
||||
|
import com.chenhai.common.core.page.TableDataInfo; |
||||
|
|
||||
|
/** |
||||
|
* 答复Controller |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
@RestController |
||||
|
@RequestMapping("/system/answers") |
||||
|
public class SysAnswersController extends BaseController |
||||
|
{ |
||||
|
@Autowired |
||||
|
private ISysAnswersService sysAnswersService; |
||||
|
|
||||
|
@Autowired |
||||
|
private ISysQuestionsService sysQuestionsService; |
||||
|
|
||||
|
/** |
||||
|
* 查询答复列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:list')") |
||||
|
@GetMapping("/list") |
||||
|
public TableDataInfo list(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
startPage(); |
||||
|
List<SysAnswers> list = sysAnswersService.selectSysAnswersList(sysAnswers); |
||||
|
return getDataTable(list); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据问题ID查询答复列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:list')") |
||||
|
@GetMapping("/question/{questionId}") |
||||
|
public TableDataInfo listByQuestionId(@PathVariable("questionId") Long questionId) |
||||
|
{ |
||||
|
startPage(); |
||||
|
List<SysAnswers> list = sysAnswersService.selectAnswersByQuestionId(questionId); |
||||
|
return getDataTable(list); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出答复列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:export')") |
||||
|
@Log(title = "答复", businessType = BusinessType.EXPORT) |
||||
|
@PostMapping("/export") |
||||
|
public void export(HttpServletResponse response, SysAnswers sysAnswers) |
||||
|
{ |
||||
|
List<SysAnswers> list = sysAnswersService.selectSysAnswersList(sysAnswers); |
||||
|
ExcelUtil<SysAnswers> util = new ExcelUtil<SysAnswers>(SysAnswers.class); |
||||
|
util.exportExcel(response, list, "答复数据"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取答复详细信息 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:query')") |
||||
|
@GetMapping(value = "/{id}") |
||||
|
public AjaxResult getInfo(@PathVariable("id") Long id) |
||||
|
{ |
||||
|
return success(sysAnswersService.selectSysAnswersById(id)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增答复(使用当前登录用户信息) |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:add')") |
||||
|
@Log(title = "答复", businessType = BusinessType.INSERT) |
||||
|
@PostMapping |
||||
|
public AjaxResult add(@RequestBody SysAnswers sysAnswers) |
||||
|
{ |
||||
|
// 验证问题是否存在 |
||||
|
if (sysAnswers.getQuestionId() == null) { |
||||
|
return error("问题ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 检查问题是否存在 |
||||
|
try { |
||||
|
sysQuestionsService.selectSysQuestionsById(sysAnswers.getQuestionId()); |
||||
|
} catch (Exception e) { |
||||
|
return error("问题不存在或已被删除"); |
||||
|
} |
||||
|
|
||||
|
return toAjax(sysAnswersService.insertSysAnswersWithCurrentUser(sysAnswers)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改答复 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:edit')") |
||||
|
@Log(title = "答复", businessType = BusinessType.UPDATE) |
||||
|
@PutMapping |
||||
|
public AjaxResult edit(@RequestBody SysAnswers sysAnswers) |
||||
|
{ |
||||
|
return toAjax(sysAnswersService.updateSysAnswers(sysAnswers)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除答复 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:remove')") |
||||
|
@Log(title = "答复", businessType = BusinessType.DELETE) |
||||
|
@DeleteMapping("/{ids}") |
||||
|
public AjaxResult remove(@PathVariable Long[] ids) |
||||
|
{ |
||||
|
return toAjax(sysAnswersService.deleteSysAnswersByIds(ids)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前用户的答复列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:list')") |
||||
|
@GetMapping("/myList") |
||||
|
public TableDataInfo myList(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
// 获取当前登录用户ID |
||||
|
Long userId = getUserId(); |
||||
|
// 设置查询条件,只查询当前用户的回答 |
||||
|
sysAnswers.setUserId(String.valueOf(userId)); |
||||
|
|
||||
|
startPage(); |
||||
|
List<SysAnswers> list = sysAnswersService.selectSysAnswersList(sysAnswers); |
||||
|
return getDataTable(list); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:query')") |
||||
|
@GetMapping("/count/{questionId}") |
||||
|
public AjaxResult countByQuestionId(@PathVariable("questionId") Long questionId) |
||||
|
{ |
||||
|
Long count = sysAnswersService.countAnswersByQuestionId(questionId); |
||||
|
return success(count); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 同步更新问题的答案数量(管理员使用) |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:answers:edit')") |
||||
|
@Log(title = "同步答案数量", businessType = BusinessType.UPDATE) |
||||
|
@PostMapping("/syncCount/{questionId}") |
||||
|
public AjaxResult syncAnswerCount(@PathVariable("questionId") Long questionId) |
||||
|
{ |
||||
|
try { |
||||
|
sysQuestionsService.updateAnswerCountFromDb(questionId); |
||||
|
return success("同步成功"); |
||||
|
} catch (Exception e) { |
||||
|
return error("同步失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,129 @@ |
|||||
|
package com.chenhai.web.controller.system; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.PutMapping; |
||||
|
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.RestController; |
||||
|
import com.chenhai.common.annotation.Log; |
||||
|
import com.chenhai.common.core.controller.BaseController; |
||||
|
import com.chenhai.common.core.domain.AjaxResult; |
||||
|
import com.chenhai.common.core.domain.model.LoginUser; |
||||
|
import com.chenhai.common.enums.BusinessType; |
||||
|
import com.chenhai.system.domain.SysQuestions; |
||||
|
import com.chenhai.system.service.ISysQuestionsService; |
||||
|
import com.chenhai.common.utils.poi.ExcelUtil; |
||||
|
import com.chenhai.common.core.page.TableDataInfo; |
||||
|
import com.chenhai.common.utils.SecurityUtils; |
||||
|
|
||||
|
/** |
||||
|
* 问答Controller |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
@RestController |
||||
|
@RequestMapping("/system/questions") |
||||
|
public class SysQuestionsController extends BaseController |
||||
|
{ |
||||
|
@Autowired |
||||
|
private ISysQuestionsService sysQuestionsService; |
||||
|
|
||||
|
/** |
||||
|
* 获取当前登录用户ID |
||||
|
*/ |
||||
|
private Long getCurrentUserId() { |
||||
|
LoginUser loginUser = SecurityUtils.getLoginUser(); |
||||
|
return loginUser.getUserId(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询问答列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:list')") |
||||
|
@GetMapping("/list") |
||||
|
public TableDataInfo list(SysQuestions sysQuestions) |
||||
|
{ |
||||
|
startPage(); |
||||
|
List<SysQuestions> list = sysQuestionsService.selectSysQuestionsList(sysQuestions); |
||||
|
return getDataTable(list); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出问答列表 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:export')") |
||||
|
@Log(title = "问答", businessType = BusinessType.EXPORT) |
||||
|
@PostMapping("/export") |
||||
|
public void export(HttpServletResponse response, SysQuestions sysQuestions) |
||||
|
{ |
||||
|
List<SysQuestions> list = sysQuestionsService.selectSysQuestionsList(sysQuestions); |
||||
|
ExcelUtil<SysQuestions> util = new ExcelUtil<SysQuestions>(SysQuestions.class); |
||||
|
util.exportExcel(response, list, "问答数据"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取问答详细信息 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:query')") |
||||
|
@GetMapping(value = "/{id}") |
||||
|
public AjaxResult getInfo(@PathVariable("id") Long id) |
||||
|
{ |
||||
|
return success(sysQuestionsService.selectSysQuestionsById(id)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增问答 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:add')") |
||||
|
@Log(title = "问答", businessType = BusinessType.INSERT) |
||||
|
@PostMapping |
||||
|
public AjaxResult add(@RequestBody SysQuestions sysQuestions) |
||||
|
{ |
||||
|
Long userId = getCurrentUserId(); |
||||
|
return toAjax(sysQuestionsService.insertSysQuestions(sysQuestions, userId)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改问答 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:edit')") |
||||
|
@Log(title = "问答", businessType = BusinessType.UPDATE) |
||||
|
@PutMapping |
||||
|
public AjaxResult edit(@RequestBody SysQuestions sysQuestions) |
||||
|
{ |
||||
|
Long userId = getCurrentUserId(); |
||||
|
return toAjax(sysQuestionsService.updateSysQuestions(sysQuestions, userId)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除问答 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:remove')") |
||||
|
@Log(title = "问答", businessType = BusinessType.DELETE) |
||||
|
@DeleteMapping("/{ids}") |
||||
|
public AjaxResult remove(@PathVariable Long[] ids) |
||||
|
{ |
||||
|
Long userId = getCurrentUserId(); |
||||
|
return toAjax(sysQuestionsService.deleteSysQuestionsByIds(ids, userId)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查问题权限 |
||||
|
*/ |
||||
|
@PreAuthorize("@ss.hasPermi('system:questions:query')") |
||||
|
@GetMapping("/checkPermission/{id}") |
||||
|
public AjaxResult checkPermission(@PathVariable("id") Long id) |
||||
|
{ |
||||
|
Long userId = getCurrentUserId(); |
||||
|
boolean hasPermission = sysQuestionsService.isQuestionBelongsToUser(id, userId); |
||||
|
return success(hasPermission); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,160 @@ |
|||||
|
package com.chenhai.system.domain; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 答复对象 sys_answers |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public class SysAnswers extends BaseEntity |
||||
|
{ |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** $column.columnComment */ |
||||
|
private Long id; |
||||
|
|
||||
|
/** 对应的问题ID */ |
||||
|
@Excel(name = "对应的问题ID") |
||||
|
private Long questionId; |
||||
|
|
||||
|
/** 用户ID */ |
||||
|
@Excel(name = "用户ID") |
||||
|
private String userId; |
||||
|
|
||||
|
/** 用户名 */ |
||||
|
@Excel(name = "用户名") |
||||
|
private String username; |
||||
|
|
||||
|
/** 用户昵称 */ |
||||
|
@Excel(name = "用户昵称") |
||||
|
private String nickName; |
||||
|
|
||||
|
/** 用户头像 */ |
||||
|
private String avatar; |
||||
|
|
||||
|
/** 回答内容 */ |
||||
|
@Excel(name = "回答内容") |
||||
|
private String content; |
||||
|
|
||||
|
/** 创建时间 */ |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd") |
||||
|
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd") |
||||
|
private Date createdAt; |
||||
|
|
||||
|
/** 更新时间 */ |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd") |
||||
|
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") |
||||
|
private Date updatedAt; |
||||
|
|
||||
|
public void setId(Long id) |
||||
|
{ |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public Long getId() |
||||
|
{ |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setQuestionId(Long questionId) |
||||
|
{ |
||||
|
this.questionId = questionId; |
||||
|
} |
||||
|
|
||||
|
public Long getQuestionId() |
||||
|
{ |
||||
|
return questionId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) |
||||
|
{ |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getUserId() |
||||
|
{ |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUsername(String username) |
||||
|
{ |
||||
|
this.username = username; |
||||
|
} |
||||
|
|
||||
|
public String getUsername() |
||||
|
{ |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) |
||||
|
{ |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() |
||||
|
{ |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setAvatar(String avatar) |
||||
|
{ |
||||
|
this.avatar = avatar; |
||||
|
} |
||||
|
|
||||
|
public String getAvatar() |
||||
|
{ |
||||
|
return avatar; |
||||
|
} |
||||
|
|
||||
|
public void setContent(String content) |
||||
|
{ |
||||
|
this.content = content; |
||||
|
} |
||||
|
|
||||
|
public String getContent() |
||||
|
{ |
||||
|
return content; |
||||
|
} |
||||
|
|
||||
|
public void setCreatedAt(Date createdAt) |
||||
|
{ |
||||
|
this.createdAt = createdAt; |
||||
|
} |
||||
|
|
||||
|
public Date getCreatedAt() |
||||
|
{ |
||||
|
return createdAt; |
||||
|
} |
||||
|
|
||||
|
public void setUpdatedAt(Date updatedAt) |
||||
|
{ |
||||
|
this.updatedAt = updatedAt; |
||||
|
} |
||||
|
|
||||
|
public Date getUpdatedAt() |
||||
|
{ |
||||
|
return updatedAt; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
||||
|
.append("id", getId()) |
||||
|
.append("questionId", getQuestionId()) |
||||
|
.append("userId", getUserId()) |
||||
|
.append("username", getUsername()) |
||||
|
.append("nickName", getNickName()) |
||||
|
.append("avatar", getAvatar()) |
||||
|
.append("content", getContent()) |
||||
|
.append("createdAt", getCreatedAt()) |
||||
|
.append("updatedAt", getUpdatedAt()) |
||||
|
.toString(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,186 @@ |
|||||
|
package com.chenhai.system.domain; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 问答对象 sys_questions |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public class SysQuestions extends BaseEntity |
||||
|
{ |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** $column.columnComment */ |
||||
|
private Long id; |
||||
|
|
||||
|
/** 用户ID */ |
||||
|
@Excel(name = "用户ID") |
||||
|
private Long userId; |
||||
|
|
||||
|
/** 用户名 */ |
||||
|
@Excel(name = "用户名") |
||||
|
private String username; |
||||
|
|
||||
|
/** 问题标题 */ |
||||
|
@Excel(name = "问题标题") |
||||
|
private String title; |
||||
|
|
||||
|
/** 问题内容 */ |
||||
|
@Excel(name = "问题内容") |
||||
|
private String content; |
||||
|
|
||||
|
/** 标签 */ |
||||
|
@Excel(name = "标签") |
||||
|
private String tags; |
||||
|
|
||||
|
/** 回答数 */ |
||||
|
@Excel(name = "回答数") |
||||
|
private Long answerCount; |
||||
|
|
||||
|
/** 创建时间 */ |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd") |
||||
|
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd") |
||||
|
private Date createdAt; |
||||
|
|
||||
|
/** 更新时间 */ |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd") |
||||
|
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") |
||||
|
private Date updatedAt; |
||||
|
|
||||
|
/** 用户昵称 */ |
||||
|
@Excel(name = "用户昵称") |
||||
|
private String nickName; |
||||
|
|
||||
|
/** 用户头像 */ |
||||
|
private String avatar; |
||||
|
|
||||
|
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 setUsername(String username) |
||||
|
{ |
||||
|
this.username = username; |
||||
|
} |
||||
|
|
||||
|
public String getUsername() |
||||
|
{ |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
public void setTitle(String title) |
||||
|
{ |
||||
|
this.title = title; |
||||
|
} |
||||
|
|
||||
|
public String getTitle() |
||||
|
{ |
||||
|
return title; |
||||
|
} |
||||
|
|
||||
|
public void setContent(String content) |
||||
|
{ |
||||
|
this.content = content; |
||||
|
} |
||||
|
|
||||
|
public String getContent() |
||||
|
{ |
||||
|
return content; |
||||
|
} |
||||
|
|
||||
|
public void setTags(String tags) |
||||
|
{ |
||||
|
this.tags = tags; |
||||
|
} |
||||
|
|
||||
|
public String getTags() |
||||
|
{ |
||||
|
return tags; |
||||
|
} |
||||
|
|
||||
|
public void setAnswerCount(Long answerCount) |
||||
|
{ |
||||
|
this.answerCount = answerCount; |
||||
|
} |
||||
|
|
||||
|
public Long getAnswerCount() |
||||
|
{ |
||||
|
return answerCount; |
||||
|
} |
||||
|
|
||||
|
public void setCreatedAt(Date createdAt) |
||||
|
{ |
||||
|
this.createdAt = createdAt; |
||||
|
} |
||||
|
|
||||
|
public Date getCreatedAt() |
||||
|
{ |
||||
|
return createdAt; |
||||
|
} |
||||
|
|
||||
|
public void setUpdatedAt(Date updatedAt) |
||||
|
{ |
||||
|
this.updatedAt = updatedAt; |
||||
|
} |
||||
|
|
||||
|
public Date getUpdatedAt() |
||||
|
{ |
||||
|
return updatedAt; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() { |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) { |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getAvatar() { |
||||
|
return avatar; |
||||
|
} |
||||
|
|
||||
|
public void setAvatar(String avatar) { |
||||
|
this.avatar = avatar; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
||||
|
.append("id", getId()) |
||||
|
.append("userId", getUserId()) |
||||
|
.append("username", getUsername()) |
||||
|
.append("title", getTitle()) |
||||
|
.append("content", getContent()) |
||||
|
.append("tags", getTags()) |
||||
|
.append("answerCount", getAnswerCount()) |
||||
|
.append("createdAt", getCreatedAt()) |
||||
|
.append("updatedAt", getUpdatedAt()) |
||||
|
.append("nickName", getNickName()) |
||||
|
.append("avatar", getAvatar()) |
||||
|
.toString(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
package com.chenhai.system.mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import com.chenhai.system.domain.SysAnswers; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
/** |
||||
|
* 答复Mapper接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public interface SysAnswersMapper |
||||
|
{ |
||||
|
/** |
||||
|
* 查询答复 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 答复 |
||||
|
*/ |
||||
|
public SysAnswers selectSysAnswersById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 查询答复列表 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 答复集合 |
||||
|
*/ |
||||
|
public List<SysAnswers> selectSysAnswersList(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 新增答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertSysAnswers(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 修改答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateSysAnswers(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 删除答复 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysAnswersById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 批量删除答复 |
||||
|
* |
||||
|
* @param ids 需要删除的数据主键集合 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysAnswersByIds(Long[] ids); |
||||
|
|
||||
|
/** |
||||
|
* 根据问题ID删除答复 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteAnswersByQuestionId(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
public Long countAnswersByQuestionId(Long questionId); |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
package com.chenhai.system.mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import com.chenhai.system.domain.SysQuestions; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
/** |
||||
|
* 问答Mapper接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public interface SysQuestionsMapper |
||||
|
{ |
||||
|
/** |
||||
|
* 查询问答 |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @return 问答 |
||||
|
*/ |
||||
|
public SysQuestions selectSysQuestionsById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 查询问答列表 |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @return 问答集合 |
||||
|
*/ |
||||
|
public List<SysQuestions> selectSysQuestionsList(SysQuestions sysQuestions); |
||||
|
|
||||
|
/** |
||||
|
* 新增问答 |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertSysQuestions(SysQuestions sysQuestions); |
||||
|
|
||||
|
/** |
||||
|
* 修改问答 |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateSysQuestions(SysQuestions sysQuestions); |
||||
|
|
||||
|
/** |
||||
|
* 删除问答 |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysQuestionsById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 批量删除问答 |
||||
|
* |
||||
|
* @param ids 需要删除的数据主键集合 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysQuestionsByIds(Long[] ids); |
||||
|
|
||||
|
/** |
||||
|
* 增加问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int increaseAnswerCount(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 减少问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int decreaseAnswerCount(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 更新问题的答案数量(从数据库实时统计) |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateAnswerCountFromDb(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
public Long getAnswerCount(Long questionId); |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
package com.chenhai.system.service; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import com.chenhai.system.domain.SysAnswers; |
||||
|
|
||||
|
/** |
||||
|
* 答复Service接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public interface ISysAnswersService |
||||
|
{ |
||||
|
/** |
||||
|
* 查询答复 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 答复 |
||||
|
*/ |
||||
|
public SysAnswers selectSysAnswersById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 查询答复列表 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 答复集合 |
||||
|
*/ |
||||
|
public List<SysAnswers> selectSysAnswersList(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 新增答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertSysAnswers(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 新增答复(自动设置当前用户信息) |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertSysAnswersWithCurrentUser(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 修改答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateSysAnswers(SysAnswers sysAnswers); |
||||
|
|
||||
|
/** |
||||
|
* 批量删除答复 |
||||
|
* |
||||
|
* @param ids 需要删除的答复主键集合 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysAnswersByIds(Long[] ids); |
||||
|
|
||||
|
/** |
||||
|
* 删除答复信息 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysAnswersById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 根据问题ID删除答复 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysAnswersByQuestionId(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案列表 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案集合 |
||||
|
*/ |
||||
|
public List<SysAnswers> selectAnswersByQuestionId(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
public Long countAnswersByQuestionId(Long questionId); |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
package com.chenhai.system.service; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import com.chenhai.system.domain.SysQuestions; |
||||
|
|
||||
|
/** |
||||
|
* 问答Service接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
public interface ISysQuestionsService |
||||
|
{ |
||||
|
/** |
||||
|
* 查询问答 |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @return 问答 |
||||
|
*/ |
||||
|
public SysQuestions selectSysQuestionsById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 查询问答列表 |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @return 问答集合 |
||||
|
*/ |
||||
|
public List<SysQuestions> selectSysQuestionsList(SysQuestions sysQuestions); |
||||
|
|
||||
|
/** |
||||
|
* 新增问答(自动关联当前用户) |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertSysQuestions(SysQuestions sysQuestions, Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 修改问答(权限验证) |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateSysQuestions(SysQuestions sysQuestions, Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 批量删除问答(权限验证) |
||||
|
* |
||||
|
* @param ids 需要删除的问答主键集合 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysQuestionsByIds(Long[] ids, Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 删除问答信息(权限验证) |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteSysQuestionsById(Long id, Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 检查问题是否属于当前用户 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public boolean isQuestionBelongsToUser(Long questionId, Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 增加问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int increaseAnswerCount(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 减少问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int decreaseAnswerCount(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 更新问题的答案数量(从数据库实时统计) |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateAnswerCountFromDb(Long questionId); |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
public Long getAnswerCount(Long questionId); |
||||
|
} |
||||
@ -0,0 +1,243 @@ |
|||||
|
package com.chenhai.system.service.impl; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import com.chenhai.common.core.domain.entity.SysUser; |
||||
|
import com.chenhai.common.utils.SecurityUtils; |
||||
|
import com.chenhai.common.utils.StringUtils; |
||||
|
import com.chenhai.system.mapper.SysAnswersMapper; |
||||
|
import com.chenhai.system.domain.SysAnswers; |
||||
|
import com.chenhai.system.service.ISysAnswersService; |
||||
|
import com.chenhai.system.service.ISysQuestionsService; |
||||
|
import com.chenhai.common.exception.ServiceException; |
||||
|
|
||||
|
/** |
||||
|
* 答复Service业务层处理 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
@Service |
||||
|
public class SysAnswersServiceImpl implements ISysAnswersService |
||||
|
{ |
||||
|
@Autowired |
||||
|
private SysAnswersMapper sysAnswersMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private ISysQuestionsService sysQuestionsService; |
||||
|
|
||||
|
/** |
||||
|
* 查询答复 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 答复 |
||||
|
*/ |
||||
|
@Override |
||||
|
public SysAnswers selectSysAnswersById(Long id) |
||||
|
{ |
||||
|
return sysAnswersMapper.selectSysAnswersById(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询答复列表 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 答复 |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<SysAnswers> selectSysAnswersList(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
return sysAnswersMapper.selectSysAnswersList(sysAnswers); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int insertSysAnswers(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
// 验证问题ID是否存在 |
||||
|
if (sysAnswers.getQuestionId() == null) { |
||||
|
throw new ServiceException("问题ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
int result = sysAnswersMapper.insertSysAnswers(sysAnswers); |
||||
|
|
||||
|
if (result > 0) { |
||||
|
// 增加问题的答案数量 |
||||
|
sysQuestionsService.increaseAnswerCount(sysAnswers.getQuestionId()); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增答复(自动设置当前用户信息) |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int insertSysAnswersWithCurrentUser(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
// 验证问题ID是否存在 |
||||
|
if (sysAnswers.getQuestionId() == null) { |
||||
|
throw new ServiceException("问题ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 获取当前登录用户信息 |
||||
|
SysUser currentUser = SecurityUtils.getLoginUser().getUser(); |
||||
|
|
||||
|
// 设置用户信息 |
||||
|
sysAnswers.setUserId(String.valueOf(currentUser.getUserId())); |
||||
|
sysAnswers.setUsername(currentUser.getUserName()); |
||||
|
// 如果前端没有传递昵称,使用系统昵称 |
||||
|
if (StringUtils.isEmpty(sysAnswers.getNickName())) { |
||||
|
sysAnswers.setNickName(currentUser.getNickName()); |
||||
|
} |
||||
|
// 设置头像 |
||||
|
sysAnswers.setAvatar(currentUser.getAvatar()); |
||||
|
|
||||
|
int result = sysAnswersMapper.insertSysAnswers(sysAnswers); |
||||
|
|
||||
|
if (result > 0) { |
||||
|
// 增加问题的答案数量 |
||||
|
sysQuestionsService.increaseAnswerCount(sysAnswers.getQuestionId()); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改答复 |
||||
|
* |
||||
|
* @param sysAnswers 答复 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int updateSysAnswers(SysAnswers sysAnswers) |
||||
|
{ |
||||
|
return sysAnswersMapper.updateSysAnswers(sysAnswers); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除答复 |
||||
|
* |
||||
|
* @param ids 需要删除的答复主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int deleteSysAnswersByIds(Long[] ids) |
||||
|
{ |
||||
|
// 先获取所有要删除的答案,记录对应的问题ID |
||||
|
for (Long id : ids) { |
||||
|
SysAnswers answer = sysAnswersMapper.selectSysAnswersById(id); |
||||
|
if (answer != null) { |
||||
|
// 减少问题的答案数量 |
||||
|
sysQuestionsService.decreaseAnswerCount(answer.getQuestionId()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return sysAnswersMapper.deleteSysAnswersByIds(ids); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除答复信息 |
||||
|
* |
||||
|
* @param id 答复主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int deleteSysAnswersById(Long id) |
||||
|
{ |
||||
|
SysAnswers answer = sysAnswersMapper.selectSysAnswersById(id); |
||||
|
if (answer == null) { |
||||
|
throw new ServiceException("答复不存在"); |
||||
|
} |
||||
|
|
||||
|
Long questionId = answer.getQuestionId(); |
||||
|
int result = sysAnswersMapper.deleteSysAnswersById(id); |
||||
|
|
||||
|
if (result > 0) { |
||||
|
// 减少问题的答案数量 |
||||
|
sysQuestionsService.decreaseAnswerCount(questionId); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据问题ID删除答复 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int deleteSysAnswersByQuestionId(Long questionId) |
||||
|
{ |
||||
|
// 获取该问题的所有答案 |
||||
|
List<SysAnswers> answers = selectAnswersByQuestionId(questionId); |
||||
|
|
||||
|
// 删除所有答案 |
||||
|
int result = sysAnswersMapper.deleteAnswersByQuestionId(questionId); |
||||
|
|
||||
|
if (result > 0) { |
||||
|
// 重置问题的答案数量为0 |
||||
|
updateAnswerCountToZero(questionId); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案列表 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案集合 |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<SysAnswers> selectAnswersByQuestionId(Long questionId) |
||||
|
{ |
||||
|
SysAnswers query = new SysAnswers(); |
||||
|
query.setQuestionId(questionId); |
||||
|
return sysAnswersMapper.selectSysAnswersList(query); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Long countAnswersByQuestionId(Long questionId) |
||||
|
{ |
||||
|
SysAnswers query = new SysAnswers(); |
||||
|
query.setQuestionId(questionId); |
||||
|
List<SysAnswers> answers = sysAnswersMapper.selectSysAnswersList(query); |
||||
|
return (long) answers.size(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 重置问题的答案数量为0(私有方法) |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
*/ |
||||
|
private void updateAnswerCountToZero(Long questionId) |
||||
|
{ |
||||
|
// 这里需要调用Questions的更新方法 |
||||
|
// 由于service间循环依赖问题,这里直接更新数据库 |
||||
|
// 或者可以在QuestionsService中添加一个重置方法 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,248 @@ |
|||||
|
package com.chenhai.system.service.impl; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import com.chenhai.system.mapper.SysQuestionsMapper; |
||||
|
import com.chenhai.system.domain.SysQuestions; |
||||
|
import com.chenhai.system.service.ISysQuestionsService; |
||||
|
import com.chenhai.common.exception.ServiceException; |
||||
|
import com.chenhai.common.utils.MessageUtils; |
||||
|
|
||||
|
/** |
||||
|
* 问答Service业务层处理 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-29 |
||||
|
*/ |
||||
|
@Service |
||||
|
public class SysQuestionsServiceImpl implements ISysQuestionsService |
||||
|
{ |
||||
|
@Autowired |
||||
|
private SysQuestionsMapper sysQuestionsMapper; |
||||
|
|
||||
|
/** |
||||
|
* 查询问答 |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @return 问答 |
||||
|
*/ |
||||
|
@Override |
||||
|
public SysQuestions selectSysQuestionsById(Long id) |
||||
|
{ |
||||
|
return sysQuestionsMapper.selectSysQuestionsById(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询问答列表 |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @return 问答 |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<SysQuestions> selectSysQuestionsList(SysQuestions sysQuestions) |
||||
|
{ |
||||
|
return sysQuestionsMapper.selectSysQuestionsList(sysQuestions); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增问答(自动关联当前用户) |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int insertSysQuestions(SysQuestions sysQuestions, Long userId) |
||||
|
{ |
||||
|
// 设置当前用户ID |
||||
|
sysQuestions.setUserId(userId); |
||||
|
|
||||
|
// 设置默认值 |
||||
|
if (sysQuestions.getAnswerCount() == null) { |
||||
|
sysQuestions.setAnswerCount(0L); |
||||
|
} |
||||
|
|
||||
|
Date now = new Date(); |
||||
|
if (sysQuestions.getCreatedAt() == null) { |
||||
|
sysQuestions.setCreatedAt(now); |
||||
|
} |
||||
|
if (sysQuestions.getUpdatedAt() == null) { |
||||
|
sysQuestions.setUpdatedAt(now); |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.insertSysQuestions(sysQuestions); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改问答(权限验证) |
||||
|
* |
||||
|
* @param sysQuestions 问答 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int updateSysQuestions(SysQuestions sysQuestions, Long userId) |
||||
|
{ |
||||
|
// 检查问题是否存在 |
||||
|
SysQuestions existingQuestion = sysQuestionsMapper.selectSysQuestionsById(sysQuestions.getId()); |
||||
|
if (existingQuestion == null) { |
||||
|
throw new ServiceException("问题不存在"); |
||||
|
} |
||||
|
|
||||
|
// 检查权限:只能修改自己的问题 |
||||
|
if (!existingQuestion.getUserId().equals(userId)) { |
||||
|
throw new ServiceException("没有权限修改此问题"); |
||||
|
} |
||||
|
|
||||
|
// 设置更新时间 |
||||
|
sysQuestions.setUpdatedAt(new Date()); |
||||
|
|
||||
|
return sysQuestionsMapper.updateSysQuestions(sysQuestions); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除问答(权限验证) |
||||
|
* |
||||
|
* @param ids 需要删除的问答主键 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int deleteSysQuestionsByIds(Long[] ids, Long userId) |
||||
|
{ |
||||
|
// 检查权限:只能删除自己的问题 |
||||
|
for (Long id : ids) { |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(id); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在,ID: " + id); |
||||
|
} |
||||
|
if (!question.getUserId().equals(userId)) { |
||||
|
throw new ServiceException("没有权限删除此问题,ID: " + id); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.deleteSysQuestionsByIds(ids); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除问答信息(权限验证) |
||||
|
* |
||||
|
* @param id 问答主键 |
||||
|
* @param userId 当前用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int deleteSysQuestionsById(Long id, Long userId) |
||||
|
{ |
||||
|
// 检查问题是否存在 |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(id); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在"); |
||||
|
} |
||||
|
|
||||
|
// 检查权限:只能删除自己的问题 |
||||
|
if (!question.getUserId().equals(userId)) { |
||||
|
throw new ServiceException("没有权限删除此问题"); |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.deleteSysQuestionsById(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查问题是否属于当前用户 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
public boolean isQuestionBelongsToUser(Long questionId, Long userId) |
||||
|
{ |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(questionId); |
||||
|
if (question == null) { |
||||
|
return false; |
||||
|
} |
||||
|
return question.getUserId().equals(userId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 增加问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int increaseAnswerCount(Long questionId) |
||||
|
{ |
||||
|
// 检查问题是否存在 |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(questionId); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在,ID: " + questionId); |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.increaseAnswerCount(questionId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 减少问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int decreaseAnswerCount(Long questionId) |
||||
|
{ |
||||
|
// 检查问题是否存在 |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(questionId); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在,ID: " + questionId); |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.decreaseAnswerCount(questionId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新问题的答案数量(从数据库实时统计) |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional |
||||
|
public int updateAnswerCountFromDb(Long questionId) |
||||
|
{ |
||||
|
// 检查问题是否存在 |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(questionId); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在,ID: " + questionId); |
||||
|
} |
||||
|
|
||||
|
return sysQuestionsMapper.updateAnswerCountFromDb(questionId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取问题的答案数量 |
||||
|
* |
||||
|
* @param questionId 问题ID |
||||
|
* @return 答案数量 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Long getAnswerCount(Long questionId) |
||||
|
{ |
||||
|
SysQuestions question = sysQuestionsMapper.selectSysQuestionsById(questionId); |
||||
|
if (question == null) { |
||||
|
throw new ServiceException("问题不存在,ID: " + questionId); |
||||
|
} |
||||
|
|
||||
|
return question.getAnswerCount(); |
||||
|
} |
||||
|
} |
||||
@ -1,49 +1,69 @@ |
|||||
package com.chenhai.vet.mapper; |
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; |
import java.util.List; |
||||
|
import com.chenhai.vet.domain.VetTrainingVideo; |
||||
|
|
||||
public interface VetTrainingVideoMapper { |
|
||||
|
|
||||
int insertVideo(VetTrainingVideo video); |
|
||||
|
|
||||
List<VetTrainingVideo> selectMyVideos(@Param("userId") Long userId, |
|
||||
@Param("title") String title, |
|
||||
@Param("category") String category, |
|
||||
@Param("status") String status, |
|
||||
@Param("auditStatus") String auditStatus); |
|
||||
|
|
||||
List<VetTrainingVideo> selectPublicVideos(@Param("title") String title, |
|
||||
@Param("category") String category, |
|
||||
@Param("userName") String userName); |
|
||||
|
|
||||
VetTrainingVideo selectVideoById(Long id); |
|
||||
|
|
||||
void incrementViewCount(Long id); |
|
||||
|
|
||||
List<VetTrainingVideo> selectHotVideos(@Param("limit") Integer limit); |
|
||||
|
/** |
||||
|
* 兽医培训视频Mapper接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-28 |
||||
|
*/ |
||||
|
public interface VetTrainingVideoMapper |
||||
|
{ |
||||
|
/** |
||||
|
* 查询兽医培训视频 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 兽医培训视频 |
||||
|
*/ |
||||
|
public VetTrainingVideo selectVetTrainingVideoById(Long id); |
||||
|
|
||||
List<VetTrainingVideo> searchVideos(@Param("keyword") String keyword); |
|
||||
|
/** |
||||
|
* 查询兽医培训视频列表 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 兽医培训视频集合 |
||||
|
*/ |
||||
|
public List<VetTrainingVideo> selectVetTrainingVideoList(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
int deleteVideoById(@Param("id") Long id); |
|
||||
|
/** |
||||
|
* 新增兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int insertVetTrainingVideo(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
// 更新审核状态 |
|
||||
int updateAuditStatus(@Param("id") Long id, |
|
||||
@Param("auditStatus") String auditStatus, |
|
||||
@Param("auditOpinion") String auditOpinion, |
|
||||
@Param("auditUserId") Long auditUserId, |
|
||||
@Param("auditTime") Date auditTime); |
|
||||
|
/** |
||||
|
* 修改兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int updateVetTrainingVideo(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
// 更新视频状态(公开/私有) |
|
||||
int updateStatus(@Param("id") Long id, |
|
||||
@Param("status") String status); |
|
||||
|
/** |
||||
|
* 删除兽医培训视频 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteVetTrainingVideoById(Long id); |
||||
|
|
||||
// 获取待审核视频列表 |
|
||||
List<VetTrainingVideo> selectPendingAuditVideos(@Param("title") String title, |
|
||||
@Param("userName") String userName); |
|
||||
|
/** |
||||
|
* 批量删除兽医培训视频 |
||||
|
* |
||||
|
* @param ids 需要删除的数据主键集合 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public int deleteVetTrainingVideoByIds(Long[] ids); |
||||
|
|
||||
// 更新视频信息 |
|
||||
int updateVideoInfo(VetTrainingVideo video); |
|
||||
|
/** |
||||
|
* 查询公开视频列表(已上架且已审核通过) |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 兽医培训视频集合 |
||||
|
*/ |
||||
|
public List<VetTrainingVideo> selectPublicVideoList(VetTrainingVideo vetTrainingVideo); |
||||
} |
} |
||||
@ -1,92 +1,140 @@ |
|||||
package com.chenhai.vet.service; |
package com.chenhai.vet.service; |
||||
|
|
||||
import com.chenhai.vet.domain.VetTrainingVideo; |
|
||||
import org.springframework.web.multipart.MultipartFile; |
|
||||
|
|
||||
import java.util.List; |
import java.util.List; |
||||
|
import com.chenhai.vet.domain.VetTrainingVideo; |
||||
|
|
||||
public interface IVetTrainingVideoService { |
|
||||
|
|
||||
|
/** |
||||
|
* 兽医培训视频Service接口 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-28 |
||||
|
*/ |
||||
|
public interface IVetTrainingVideoService |
||||
|
{ |
||||
/** |
/** |
||||
* 上传并保存视频(自动设为待审核) |
|
||||
|
* 查询兽医培训视频 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 兽医培训视频 |
||||
*/ |
*/ |
||||
String uploadAndSave(VetTrainingVideo video, MultipartFile videoFile, MultipartFile coverImage); |
|
||||
|
|
||||
|
public VetTrainingVideo selectVetTrainingVideoById(Long id); |
||||
|
|
||||
/** |
/** |
||||
* 获取我的视频列表 |
|
||||
|
* 查询兽医培训视频列表 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 兽医培训视频集合 |
||||
*/ |
*/ |
||||
List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status, String auditStatus); |
|
||||
|
public List<VetTrainingVideo> selectVetTrainingVideoList(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
/** |
/** |
||||
* 获取公开视频列表 |
|
||||
|
* 新增兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
*/ |
*/ |
||||
List<VetTrainingVideo> getPublicVideos(String title, String category, String vetName); |
|
||||
|
public int insertVetTrainingVideo(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
/** |
/** |
||||
* 获取视频详情(带权限校验) |
|
||||
|
* 修改兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
*/ |
*/ |
||||
VetTrainingVideo getVideoDetail(Long videoId, Long currentVetId); |
|
||||
|
public int updateVetTrainingVideo(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
/** |
/** |
||||
* 获取视频播放地址(带权限校验) |
|
||||
|
* 批量删除兽医培训视频 |
||||
|
* |
||||
|
* @param ids 需要删除的兽医培训视频主键集合 |
||||
|
* @return 结果 |
||||
*/ |
*/ |
||||
String getVideoPlayUrl(Long videoId, Long currentVetId); |
|
||||
|
public int deleteVetTrainingVideoByIds(Long[] ids); |
||||
|
|
||||
/** |
/** |
||||
* 增加观看次数 |
|
||||
|
* 删除兽医培训视频信息 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 结果 |
||||
*/ |
*/ |
||||
void incrementViewCount(Long videoId); |
|
||||
|
public int deleteVetTrainingVideoById(Long id); |
||||
|
|
||||
|
// 批量操作 |
||||
|
int batchSubmitForAudit(List<Long> videoIds, Long userId); |
||||
|
int batchAuditVideo(List<Long> videoIds, String auditStatus, String auditOpinion, Long auditUserId); |
||||
|
int batchPublishVideo(List<Long> videoIds, Long userId); |
||||
|
int batchOfflineVideo(List<Long> videoIds, Long userId); |
||||
|
|
||||
/** |
/** |
||||
* 获取热门视频 |
|
||||
|
* 审核单个视频 |
||||
|
* @param videoId 视频ID |
||||
|
* @param auditStatus 审核状态 |
||||
|
* @param auditOpinion 审核意见 |
||||
|
* @param auditUserId 审核用户ID |
||||
|
* @return 是否成功 |
||||
*/ |
*/ |
||||
List<VetTrainingVideo> getHotVideos(Integer limit); |
|
||||
|
boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId); |
||||
|
|
||||
/** |
/** |
||||
* 搜索视频 |
|
||||
|
* 上架单个视频 |
||||
|
* @param videoId 视频ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 是否成功 |
||||
*/ |
*/ |
||||
List<VetTrainingVideo> searchVideos(String keyword); |
|
||||
|
boolean publishVideo(Long videoId, Long userId); |
||||
|
|
||||
int deleteVideoById(Long videoId); |
|
||||
|
/** |
||||
|
* 下架单个视频 |
||||
|
* @param videoId 视频ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 是否成功 |
||||
|
*/ |
||||
|
boolean offlineVideo(Long videoId, Long userId); |
||||
|
|
||||
/** |
/** |
||||
* 提交审核(用户手动提交) |
|
||||
|
* 提交审核(单个视频) |
||||
|
* @param videoId 视频ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 是否成功 |
||||
*/ |
*/ |
||||
boolean submitForAudit(Long videoId, Long userId); |
boolean submitForAudit(Long videoId, Long userId); |
||||
|
|
||||
/** |
/** |
||||
* 取消审核(用户主动取消) |
|
||||
|
* 取消审核(单个视频) |
||||
|
* @param videoId 视频ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 是否成功 |
||||
*/ |
*/ |
||||
boolean cancelAudit(Long videoId, Long userId); |
boolean cancelAudit(Long videoId, Long userId); |
||||
|
|
||||
/** |
/** |
||||
* 重新提交审核(审核拒绝后) |
|
||||
|
* 重新提交审核(单个视频) |
||||
|
* @param videoId 视频ID |
||||
|
* @param userId 用户ID |
||||
|
* @return 是否成功 |
||||
*/ |
*/ |
||||
boolean resubmitForAudit(Long videoId, Long userId); |
boolean resubmitForAudit(Long videoId, Long userId); |
||||
|
|
||||
/** |
/** |
||||
* 审核视频(管理员) |
|
||||
|
* 修复缺少用户ID的视频记录 |
||||
|
* @return 修复的记录数 |
||||
*/ |
*/ |
||||
boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId); |
|
||||
|
int fixMissingUserIds(); |
||||
|
|
||||
/** |
/** |
||||
* 上架视频(审核通过后) |
|
||||
|
* 查询公开视频列表(已上架且已审核通过) |
||||
|
* |
||||
|
* @param vetTrainingVideo 查询条件 |
||||
|
* @return 公开视频集合 |
||||
*/ |
*/ |
||||
boolean publishVideo(Long videoId, Long userId); |
|
||||
|
public List<VetTrainingVideo> selectPublicVideoList(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
/** |
/** |
||||
* 下架视频 |
|
||||
|
* 分页查询公开视频列表(已上架且已审核通过) |
||||
|
* |
||||
|
* @param vetTrainingVideo 查询条件 |
||||
|
* @return 公开视频集合 |
||||
*/ |
*/ |
||||
boolean offlineVideo(Long videoId, Long userId); |
|
||||
|
public List<VetTrainingVideo> selectPublicVideoPageList(VetTrainingVideo vetTrainingVideo); |
||||
|
|
||||
/** |
|
||||
* 获取待审核视频列表(管理员) |
|
||||
*/ |
|
||||
List<VetTrainingVideo> getPendingAuditVideos(String title, String userName); |
|
||||
|
|
||||
/** |
|
||||
* 编辑视频信息 |
|
||||
*/ |
|
||||
boolean updateVideoInfo(Long videoId, VetTrainingVideo video, Long userId); |
|
||||
} |
} |
||||
@ -1,335 +1,499 @@ |
|||||
package com.chenhai.vet.service.impl; |
package com.chenhai.vet.service.impl; |
||||
|
|
||||
import com.chenhai.vet.domain.VetTrainingVideo; |
|
||||
import com.chenhai.vet.mapper.VetTrainingVideoMapper; |
|
||||
import com.chenhai.vet.service.IVetTrainingVideoService; |
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import com.chenhai.common.utils.SecurityUtils; |
||||
|
import org.slf4j.Logger; |
||||
|
|
||||
|
import com.chenhai.common.utils.DateUtils; |
||||
|
import org.slf4j.LoggerFactory; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import org.springframework.stereotype.Service; |
import org.springframework.stereotype.Service; |
||||
|
import com.chenhai.vet.mapper.VetTrainingVideoMapper; |
||||
|
import com.chenhai.vet.domain.VetTrainingVideo; |
||||
|
import com.chenhai.vet.service.IVetTrainingVideoService; |
||||
import org.springframework.transaction.annotation.Transactional; |
import org.springframework.transaction.annotation.Transactional; |
||||
import org.springframework.web.multipart.MultipartFile; |
|
||||
|
|
||||
import java.io.File; |
|
||||
import java.io.IOException; |
|
||||
import java.nio.file.Files; |
|
||||
import java.nio.file.Path; |
|
||||
import java.nio.file.Paths; |
|
||||
import java.util.Date; |
|
||||
import java.util.List; |
|
||||
import java.util.UUID; |
|
||||
|
|
||||
|
/** |
||||
|
* 兽医培训视频Service业务层处理 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
* @date 2026-01-28 |
||||
|
*/ |
||||
@Service |
@Service |
||||
public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService { |
|
||||
|
public class VetTrainingVideoServiceImpl implements IVetTrainingVideoService |
||||
|
{ |
||||
|
|
||||
|
// 添加 logger |
||||
|
private static final Logger logger = LoggerFactory.getLogger(VetTrainingVideoServiceImpl.class); |
||||
@Autowired |
@Autowired |
||||
private VetTrainingVideoMapper videoMapper; |
|
||||
|
|
||||
@Value("${file.upload.path:/uploads}") |
|
||||
private String uploadPath; |
|
||||
|
|
||||
|
private VetTrainingVideoMapper vetTrainingVideoMapper; |
||||
|
|
||||
|
/** |
||||
|
* 查询兽医培训视频 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 兽医培训视频 |
||||
|
*/ |
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public String uploadAndSave(VetTrainingVideo video, MultipartFile videoFile, MultipartFile coverImage) { |
|
||||
try { |
|
||||
// 1. 创建上传目录 |
|
||||
File uploadDir = new File(uploadPath); |
|
||||
if (!uploadDir.exists()) { |
|
||||
uploadDir.mkdirs(); |
|
||||
} |
|
||||
|
|
||||
// 2. 生成唯一文件名 |
|
||||
String originalFileName = videoFile.getOriginalFilename(); |
|
||||
String fileExtension = getFileExtension(originalFileName); |
|
||||
String uniqueFileName = UUID.randomUUID().toString() + "." + fileExtension; |
|
||||
|
|
||||
// 3. 保存视频文件 |
|
||||
Path videoPath = Paths.get(uploadPath, uniqueFileName); |
|
||||
Files.write(videoPath, videoFile.getBytes()); |
|
||||
|
|
||||
// 4. 保存封面图(如果有) |
|
||||
String coverImageUrl = null; |
|
||||
if (coverImage != null && !coverImage.isEmpty()) { |
|
||||
String coverExtension = getFileExtension(coverImage.getOriginalFilename()); |
|
||||
String coverFileName = "cover_" + UUID.randomUUID().toString() + "." + coverExtension; |
|
||||
Path coverPath = Paths.get(uploadPath, coverFileName); |
|
||||
Files.write(coverPath, coverImage.getBytes()); |
|
||||
coverImageUrl = "/uploads/" + coverFileName; |
|
||||
} |
|
||||
|
|
||||
// 5. 计算视频时长和大小 |
|
||||
int duration = getVideoDuration(videoFile); |
|
||||
long fileSize = videoFile.getSize(); |
|
||||
|
|
||||
// 6. 设置初始状态:私有 + 待审核 |
|
||||
video.setStatus("0"); // 0-未上架/私有 |
|
||||
video.setAuditStatus("0"); // 0-待审核 |
|
||||
video.setVideoUrl("/uploads/" + uniqueFileName); |
|
||||
video.setCoverImage(coverImageUrl); |
|
||||
video.setDuration(duration); |
|
||||
video.setFileSize(fileSize); |
|
||||
video.setViewCount(0); |
|
||||
video.setCreateTime(new Date()); |
|
||||
video.setUpdateTime(new Date()); |
|
||||
|
|
||||
videoMapper.insertVideo(video); |
|
||||
|
|
||||
return "上传成功!视频已自动提交审核,请耐心等待管理员审核。"; |
|
||||
|
|
||||
} catch (IOException e) { |
|
||||
throw new RuntimeException("文件保存失败", e); |
|
||||
} |
|
||||
|
public VetTrainingVideo selectVetTrainingVideoById(Long id) |
||||
|
{ |
||||
|
return vetTrainingVideoMapper.selectVetTrainingVideoById(id); |
||||
} |
} |
||||
|
|
||||
|
/** |
||||
|
* 查询兽医培训视频列表 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 兽医培训视频 |
||||
|
*/ |
||||
@Override |
@Override |
||||
public List<VetTrainingVideo> getMyVideos(Long userId, String title, String category, String status, String auditStatus) { |
|
||||
return videoMapper.selectMyVideos(userId, title, category, status, auditStatus); |
|
||||
|
public List<VetTrainingVideo> selectVetTrainingVideoList(VetTrainingVideo vetTrainingVideo) |
||||
|
{ |
||||
|
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo); |
||||
} |
} |
||||
|
|
||||
|
/** |
||||
|
* 新增兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
@Override |
@Override |
||||
public List<VetTrainingVideo> getPublicVideos(String title, String category, String vetName) { |
|
||||
// 只显示审核通过且公开的视频 |
|
||||
return videoMapper.selectPublicVideos(title, category, vetName); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public VetTrainingVideo getVideoDetail(Long videoId, Long currentVetId) { |
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
|
||||
if (video == null) { |
|
||||
return null; |
|
||||
|
public int insertVetTrainingVideo(VetTrainingVideo vetTrainingVideo) |
||||
|
{ |
||||
|
// 强制设置当前用户ID(确保不为空) |
||||
|
Long userId = SecurityUtils.getUserId(); |
||||
|
if (userId == null) { |
||||
|
throw new RuntimeException("用户未登录"); |
||||
} |
} |
||||
|
|
||||
// 权限校验:只能查看自己的视频或审核通过公开的视频 |
|
||||
boolean canView = ("2".equals(video.getAuditStatus()) && // 2-审核通过(新编码) |
|
||||
"1".equals(video.getStatus())) || // 1-已上架/公开 |
|
||||
currentVetId.equals(video.getUserId()); |
|
||||
return canView ? video : null; |
|
||||
|
vetTrainingVideo.setUserId(userId); // 确保设置用户ID |
||||
|
vetTrainingVideo.setStatus("0"); // 私有 |
||||
|
vetTrainingVideo.setAuditStatus("0"); // 待审核 |
||||
|
vetTrainingVideo.setDelFlag("0"); // 正常 |
||||
|
|
||||
|
vetTrainingVideo.setCreateTime(DateUtils.getNowDate()); |
||||
|
return vetTrainingVideoMapper.insertVetTrainingVideo(vetTrainingVideo); |
||||
} |
} |
||||
|
|
||||
|
// 添加一个修复历史数据的方法 |
||||
@Override |
@Override |
||||
public String getVideoPlayUrl(Long videoId, Long currentVetId) { |
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
|
||||
if (video == null) { |
|
||||
return null; |
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public int fixMissingUserIds() { |
||||
|
// 查找 user_id 为 null 的视频记录 |
||||
|
VetTrainingVideo query = new VetTrainingVideo(); |
||||
|
query.setUserId(null); // 查找用户ID为空的记录 |
||||
|
|
||||
|
List<VetTrainingVideo> videos = vetTrainingVideoMapper.selectVetTrainingVideoList(query); |
||||
|
int fixedCount = 0; |
||||
|
|
||||
|
for (VetTrainingVideo video : videos) { |
||||
|
if (video.getUserId() == null) { |
||||
|
// 这里可以根据实际情况设置一个默认用户ID |
||||
|
// 例如:设置为系统管理员ID或第一个用户 |
||||
|
video.setUserId(1L); // 假设1是系统管理员 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
vetTrainingVideoMapper.updateVetTrainingVideo(video); |
||||
|
fixedCount++; |
||||
|
} |
||||
} |
} |
||||
|
|
||||
// 权限校验:只能播放自己的视频或审核通过公开的视频 |
|
||||
boolean canPlay = ("2".equals(video.getAuditStatus()) && // 2-审核通过(新编码) |
|
||||
"1".equals(video.getStatus())) || // 1-已上架/公开 |
|
||||
currentVetId.equals(video.getUserId()); |
|
||||
return canPlay ? video.getVideoUrl() : null; |
|
||||
|
return fixedCount; |
||||
} |
} |
||||
|
|
||||
@Override |
|
||||
public void incrementViewCount(Long videoId) { |
|
||||
videoMapper.incrementViewCount(videoId); |
|
||||
} |
|
||||
|
|
||||
|
/** |
||||
|
* 修改兽医培训视频 |
||||
|
* |
||||
|
* @param vetTrainingVideo 兽医培训视频 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
@Override |
@Override |
||||
public List<VetTrainingVideo> getHotVideos(Integer limit) { |
|
||||
return videoMapper.selectHotVideos(limit); |
|
||||
|
public int updateVetTrainingVideo(VetTrainingVideo vetTrainingVideo) |
||||
|
{ |
||||
|
vetTrainingVideo.setUpdateTime(DateUtils.getNowDate()); |
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(vetTrainingVideo); |
||||
} |
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除兽医培训视频 |
||||
|
* |
||||
|
* @param ids 需要删除的兽医培训视频主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
@Override |
@Override |
||||
public List<VetTrainingVideo> searchVideos(String keyword) { |
|
||||
return videoMapper.searchVideos(keyword); |
|
||||
|
public int deleteVetTrainingVideoByIds(Long[] ids) |
||||
|
{ |
||||
|
return vetTrainingVideoMapper.deleteVetTrainingVideoByIds(ids); |
||||
} |
} |
||||
|
|
||||
|
/** |
||||
|
* 删除兽医培训视频信息 |
||||
|
* |
||||
|
* @param id 兽医培训视频主键 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public int deleteVideoById(Long videoId) { |
|
||||
return videoMapper.deleteVideoById(videoId); |
|
||||
|
public int deleteVetTrainingVideoById(Long id) |
||||
|
{ |
||||
|
return vetTrainingVideoMapper.deleteVetTrainingVideoById(id); |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean submitForAudit(Long videoId, Long userId) { |
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
|
||||
if (video == null || !userId.equals(video.getUserId())) { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
// 只能提交无需审核或审核拒绝的视频 |
|
||||
if (!"4".equals(video.getAuditStatus()) && // 3-无需审核 |
|
||||
!"3".equals(video.getAuditStatus())) { // 2-审核拒绝 |
|
||||
return false; |
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public int batchSubmitForAudit(List<Long> videoIds, Long userId) { |
||||
|
int successCount = 0; |
||||
|
|
||||
|
for (Long videoId : videoIds) { |
||||
|
try { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
if (video == null) { |
||||
|
logger.warn("视频不存在,ID: {}", videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 验证权限:只能操作自己的视频 |
||||
|
if (!userId.equals(video.getUserId())) { |
||||
|
logger.warn("用户 {} 无权限操作视频 {}", userId, videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 状态验证:只有审核拒绝或无需审核状态才能重新提交审核 |
||||
|
String auditStatus = video.getAuditStatus(); |
||||
|
if (!"2".equals(auditStatus) && !"3".equals(auditStatus)) { |
||||
|
logger.warn("视频 {} 当前状态 {} 不能提交审核", videoId, auditStatus); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 更新为待审核状态 |
||||
|
video.setAuditStatus("0"); // 待审核 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
int result = vetTrainingVideoMapper.updateVetTrainingVideo(video); |
||||
|
if (result > 0) { |
||||
|
successCount++; |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
logger.error("批量提交审核失败,视频ID: {}", videoId, e); |
||||
|
// 继续处理下一个,不中断批量操作 |
||||
|
} |
||||
} |
} |
||||
|
|
||||
// 更新为待审核状态 |
|
||||
int result = videoMapper.updateAuditStatus(videoId, |
|
||||
"1", // 1-审核中 |
|
||||
"已提交审核", |
|
||||
null, |
|
||||
new Date()); |
|
||||
return result > 0; |
|
||||
|
return successCount; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean cancelAudit(Long videoId, Long userId) { |
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public int batchAuditVideo(List<Long> videoIds, String auditStatus, String auditOpinion, Long auditUserId) { |
||||
|
int successCount = 0; |
||||
|
|
||||
if (video == null || !userId.equals(video.getUserId())) { |
|
||||
return false; |
|
||||
|
// 如果是拒绝审核,必须填写意见 |
||||
|
if ("2".equals(auditStatus) && (auditOpinion == null || auditOpinion.trim().isEmpty())) { |
||||
|
throw new RuntimeException("审核拒绝时必须填写审核意见"); |
||||
} |
} |
||||
|
|
||||
if (!"1".equals(video.getAuditStatus())) { // 1-审核中 |
|
||||
return false; |
|
||||
|
for (Long videoId : videoIds) { |
||||
|
try { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
if (video == null) { |
||||
|
logger.warn("视频不存在,ID: {}", videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 状态验证:只有待审核状态才能审核 |
||||
|
if (!"0".equals(video.getAuditStatus())) { |
||||
|
logger.warn("视频 {} 当前状态 {} 不能审核", videoId, video.getAuditStatus()); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 更新审核信息 |
||||
|
video.setAuditStatus(auditStatus); |
||||
|
video.setAuditOpinion(auditOpinion); |
||||
|
video.setAuditUserId(auditUserId); |
||||
|
video.setAuditTime(DateUtils.getNowDate()); |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
int result = vetTrainingVideoMapper.updateVetTrainingVideo(video); |
||||
|
if (result > 0) { |
||||
|
successCount++; |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
logger.error("批量审核失败,视频ID: {}", videoId, e); |
||||
|
// 继续处理下一个,不中断批量操作 |
||||
|
} |
||||
} |
} |
||||
|
|
||||
// 更新为无需审核状态 |
|
||||
int result = videoMapper.updateAuditStatus(videoId, |
|
||||
"4", // 4-无需审核 |
|
||||
"用户取消审核", |
|
||||
null, |
|
||||
new Date()); |
|
||||
return result > 0; |
|
||||
|
return successCount; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean resubmitForAudit(Long videoId, Long userId) { |
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
|
||||
if (video == null || !userId.equals(video.getUserId())) { |
|
||||
return false; |
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public int batchPublishVideo(List<Long> videoIds, Long userId) { |
||||
|
int successCount = 0; |
||||
|
|
||||
|
for (Long videoId : videoIds) { |
||||
|
try { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
if (video == null) { |
||||
|
logger.warn("视频不存在,ID: {}", videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 验证权限:只能操作自己的视频 |
||||
|
if (!userId.equals(video.getUserId())) { |
||||
|
logger.warn("用户 {} 无权限操作视频 {}", userId, videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 状态验证:只有审核通过且未上架的视频才能上架 |
||||
|
if (!"2".equals(video.getAuditStatus())) { |
||||
|
logger.warn("视频 {} 未通过审核,当前审核状态: {}", videoId, video.getAuditStatus()); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ("1".equals(video.getStatus())) { |
||||
|
logger.warn("视频 {} 已上架", videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 更新为上架状态 |
||||
|
video.setStatus("1"); // 已上架 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
int result = vetTrainingVideoMapper.updateVetTrainingVideo(video); |
||||
|
if (result > 0) { |
||||
|
successCount++; |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
logger.error("批量上架失败,视频ID: {}", videoId, e); |
||||
|
// 继续处理下一个,不中断批量操作 |
||||
|
} |
||||
} |
} |
||||
|
|
||||
// 只能重新提交审核拒绝状态的视频 |
|
||||
if (!"3".equals(video.getAuditStatus())) { // 2-审核拒绝 |
|
||||
return false; |
|
||||
|
return successCount; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public int batchOfflineVideo(List<Long> videoIds, Long userId) { |
||||
|
int successCount = 0; |
||||
|
|
||||
|
for (Long videoId : videoIds) { |
||||
|
try { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
if (video == null) { |
||||
|
logger.warn("视频不存在,ID: {}", videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 验证权限:只能操作自己的视频 |
||||
|
if (!userId.equals(video.getUserId())) { |
||||
|
logger.warn("用户 {} 无权限操作视频 {}", userId, videoId); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 状态验证:只有已上架的视频才能下架 |
||||
|
if (!"1".equals(video.getStatus())) { |
||||
|
logger.warn("视频 {} 未上架,当前状态: {}", videoId, video.getStatus()); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 更新为下架状态 |
||||
|
video.setStatus("0"); // 已下架 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
int result = vetTrainingVideoMapper.updateVetTrainingVideo(video); |
||||
|
if (result > 0) { |
||||
|
successCount++; |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
logger.error("批量下架失败,视频ID: {}", videoId, e); |
||||
|
// 继续处理下一个,不中断批量操作 |
||||
|
} |
||||
} |
} |
||||
|
|
||||
// 更新为待审核状态 |
|
||||
int result = videoMapper.updateAuditStatus(videoId, |
|
||||
"0", // 0-待审核 |
|
||||
"重新提交审核", |
|
||||
null, |
|
||||
new Date()); |
|
||||
return result > 0; |
|
||||
|
return successCount; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId) { |
public boolean auditVideo(Long videoId, String auditStatus, String auditOpinion, Long auditUserId) { |
||||
// 验证审核状态 |
|
||||
if (!"2".equals(auditStatus) && // 2-审核通过 |
|
||||
!"3".equals(auditStatus)) { // 3-审核拒绝 |
|
||||
return false; |
|
||||
} |
|
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
|
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
if (video == null) { |
if (video == null) { |
||||
return false; |
|
||||
|
throw new RuntimeException("视频不存在"); |
||||
} |
} |
||||
|
|
||||
if (!"1".equals(video.getAuditStatus())) { // 1-审核中 |
|
||||
return false; |
|
||||
|
// 只有待审核状态才能审核 |
||||
|
if (!"0".equals(video.getAuditStatus())) { |
||||
|
throw new RuntimeException("当前状态不能审核"); |
||||
} |
} |
||||
|
|
||||
|
|
||||
int result = videoMapper.updateAuditStatus(videoId, |
|
||||
auditStatus, |
|
||||
auditOpinion, |
|
||||
auditUserId, |
|
||||
new Date()); |
|
||||
|
|
||||
// 如果审核通过,自动设置为私有状态,等待用户上架 |
|
||||
if (result > 0 && "2".equals(auditStatus)) { // 1-审核通过 |
|
||||
videoMapper.updateStatus(videoId, "0"); // 0-未上架/私有 |
|
||||
|
// 审核拒绝时必须填写审核意见 |
||||
|
if ("2".equals(auditStatus) && (auditOpinion == null || auditOpinion.trim().isEmpty())) { |
||||
|
throw new RuntimeException("审核拒绝时必须填写审核意见"); |
||||
} |
} |
||||
|
|
||||
return result > 0; |
|
||||
|
// 更新审核信息 |
||||
|
video.setAuditStatus(auditStatus); |
||||
|
video.setAuditOpinion(auditOpinion); |
||||
|
video.setAuditUserId(auditUserId); |
||||
|
video.setAuditTime(DateUtils.getNowDate()); |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(video) > 0; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean publishVideo(Long videoId, Long userId) { |
public boolean publishVideo(Long videoId, Long userId) { |
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
if (video == null) { |
if (video == null) { |
||||
return false; |
|
||||
|
throw new RuntimeException("视频不存在"); |
||||
} |
} |
||||
|
|
||||
// 权限校验:只能操作自己的视频 |
|
||||
if (!userId.equals(video.getUserId())) { |
|
||||
return false; |
|
||||
|
// // 验证权限:只能操作自己的视频 |
||||
|
// if (!userId.equals(video.getUserId())) { |
||||
|
// throw new RuntimeException("无权操作此视频"); |
||||
|
// } |
||||
|
|
||||
|
// 状态验证:只有审核通过且未上架的视频才能上架 |
||||
|
if (!"1".equals(video.getAuditStatus())) { |
||||
|
throw new RuntimeException("只有审核通过的视频才能上架"); |
||||
} |
} |
||||
|
|
||||
// 只能上架审核通过的视频 |
|
||||
if (!"2".equals(video.getAuditStatus())) { // 1-审核通过 |
|
||||
return false; |
|
||||
|
if ("1".equals(video.getStatus())) { |
||||
|
throw new RuntimeException("视频已上架"); |
||||
} |
} |
||||
|
|
||||
return videoMapper.updateStatus(videoId, "1") > 0; // 1-已上架/公开 |
|
||||
|
// 更新为上架状态 |
||||
|
video.setStatus("1"); // 已上架 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(video) > 0; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean offlineVideo(Long videoId, Long userId) { |
public boolean offlineVideo(Long videoId, Long userId) { |
||||
VetTrainingVideo video = videoMapper.selectVideoById(videoId); |
|
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
if (video == null) { |
if (video == null) { |
||||
return false; |
|
||||
|
throw new RuntimeException("视频不存在"); |
||||
} |
} |
||||
|
|
||||
// 权限校验:只能操作自己的视频 |
|
||||
|
// 验证权限:只能操作自己的视频 |
||||
if (!userId.equals(video.getUserId())) { |
if (!userId.equals(video.getUserId())) { |
||||
return false; |
|
||||
|
throw new RuntimeException("无权操作此视频"); |
||||
} |
} |
||||
|
|
||||
// 只能下架已上架的视频 |
|
||||
if (!"1".equals(video.getStatus())) { // 1-已上架/公开 |
|
||||
return false; |
|
||||
|
// 状态验证:只有已上架的视频才能下架 |
||||
|
if (!"1".equals(video.getStatus())) { |
||||
|
throw new RuntimeException("只有已上架的视频才能下架"); |
||||
} |
} |
||||
|
|
||||
return videoMapper.updateStatus(videoId, "0") > 0; // 0-未上架/私有 |
|
||||
|
// 更新为下架状态 |
||||
|
video.setStatus("0"); // 已下架 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(video) > 0; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
public List<VetTrainingVideo> getPendingAuditVideos(String title, String userName) { |
|
||||
return videoMapper.selectPendingAuditVideos(title, userName); |
|
||||
|
public boolean submitForAudit(Long videoId, Long userId) { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
|
if (video == null) { |
||||
|
throw new RuntimeException("视频不存在"); |
||||
|
} |
||||
|
|
||||
|
// ============ 注意:这里移除了权限检查 ============ |
||||
|
// 原来的权限检查代码删除了: |
||||
|
// if (!userId.equals(video.getUserId())) { |
||||
|
// throw new RuntimeException("无权操作此视频"); |
||||
|
// } |
||||
|
// ================================================= |
||||
|
|
||||
|
// 状态验证:只有审核拒绝或无需审核状态才能提交审核 |
||||
|
String auditStatus = video.getAuditStatus(); |
||||
|
if (!"2".equals(auditStatus) && !"3".equals(auditStatus)) { |
||||
|
throw new RuntimeException("当前状态不能提交审核"); |
||||
|
} |
||||
|
|
||||
|
// 更新为待审核状态 |
||||
|
video.setAuditStatus("0"); // 待审核 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(video) > 0; |
||||
} |
} |
||||
|
|
||||
@Override |
@Override |
||||
@Transactional |
|
||||
public boolean updateVideoInfo(Long videoId, VetTrainingVideo video, Long userId) { |
|
||||
VetTrainingVideo existingVideo = videoMapper.selectVideoById(videoId); |
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public boolean cancelAudit(Long videoId, Long userId) { |
||||
|
VetTrainingVideo video = vetTrainingVideoMapper.selectVetTrainingVideoById(videoId); |
||||
|
|
||||
if (existingVideo == null || !userId.equals(existingVideo.getUserId())) { |
|
||||
return false; |
|
||||
|
if (video == null) { |
||||
|
throw new RuntimeException("视频不存在"); |
||||
} |
} |
||||
|
|
||||
// 只能编辑无需审核、审核拒绝或私有状态的视频 |
|
||||
boolean canEdit = "4".equals(existingVideo.getAuditStatus()) || // 4-无需审核 |
|
||||
"3".equals(existingVideo.getAuditStatus()) || // 3-审核拒绝 |
|
||||
"0".equals(existingVideo.getStatus()); // 0-未上架/私有 |
|
||||
|
|
||||
if (!canEdit) { |
|
||||
return false; |
|
||||
|
// 状态验证:只有待审核状态才能取消审核 |
||||
|
if (!"0".equals(video.getAuditStatus())) { |
||||
|
throw new RuntimeException("只有待审核状态才能取消审核"); |
||||
} |
} |
||||
|
|
||||
// 更新视频信息 |
|
||||
existingVideo.setTitle(video.getTitle()); |
|
||||
existingVideo.setDescription(video.getDescription()); |
|
||||
existingVideo.setCategory(video.getCategory()); |
|
||||
existingVideo.setUpdateTime(new Date()); |
|
||||
|
// 更新为无需审核状态 |
||||
|
video.setAuditStatus("3"); // 无需审核 |
||||
|
video.setUpdateTime(DateUtils.getNowDate()); |
||||
|
|
||||
return videoMapper.updateVideoInfo(existingVideo) > 0; |
|
||||
|
return vetTrainingVideoMapper.updateVetTrainingVideo(video) > 0; |
||||
} |
} |
||||
|
|
||||
private String getFileExtension(String fileName) { |
|
||||
if (fileName == null || fileName.lastIndexOf(".") == -1) { |
|
||||
return "mp4"; |
|
||||
} |
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1); |
|
||||
|
/** |
||||
|
* 检查用户是否是管理员 |
||||
|
*/ |
||||
|
private boolean checkUserIsAdmin(Long userId) { |
||||
|
// 这里需要根据你的权限系统来实现 |
||||
|
// 例如:查询用户角色 |
||||
|
// 暂时返回false,你需要根据实际情况实现 |
||||
|
return false; |
||||
} |
} |
||||
|
|
||||
private int getVideoDuration(MultipartFile videoFile) { |
|
||||
// 这里需要实现获取视频时长的方法 |
|
||||
return 60; // 默认60秒 |
|
||||
|
@Override |
||||
|
public boolean resubmitForAudit(Long videoId, Long userId) { |
||||
|
// 重新提交审核和提交审核逻辑相同 |
||||
|
return submitForAudit(videoId, userId); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询公开视频列表(已上架且已审核通过) |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<VetTrainingVideo> selectPublicVideoList(VetTrainingVideo vetTrainingVideo) { |
||||
|
// 设置强制条件:已上架且审核通过 |
||||
|
vetTrainingVideo.setStatus("1"); // 已上架 |
||||
|
vetTrainingVideo.setAuditStatus("1"); // 审核通过 |
||||
|
vetTrainingVideo.setDelFlag("0"); // 未删除 |
||||
|
|
||||
|
return vetTrainingVideoMapper.selectPublicVideoList(vetTrainingVideo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页查询公开视频列表(已上架且已审核通过) |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<VetTrainingVideo> selectPublicVideoPageList(VetTrainingVideo vetTrainingVideo) { |
||||
|
// 设置强制条件:已上架且审核通过 |
||||
|
vetTrainingVideo.setStatus("1"); // 已上架 |
||||
|
vetTrainingVideo.setAuditStatus("1"); // 审核通过 |
||||
|
vetTrainingVideo.setDelFlag("0"); // 未删除 |
||||
|
|
||||
|
return vetTrainingVideoMapper.selectVetTrainingVideoList(vetTrainingVideo); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,112 @@ |
|||||
|
<?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.system.mapper.SysAnswersMapper"> |
||||
|
|
||||
|
<resultMap type="SysAnswers" id="SysAnswersResult"> |
||||
|
<result property="id" column="id" /> |
||||
|
<result property="questionId" column="question_id" /> |
||||
|
<result property="userId" column="user_id" /> |
||||
|
<result property="username" column="username" /> |
||||
|
<result property="nickName" column="nick_name" /> |
||||
|
<result property="avatar" column="avatar" /> |
||||
|
<result property="content" column="content" /> |
||||
|
<result property="createdAt" column="created_at" /> |
||||
|
<result property="updatedAt" column="updated_at" /> |
||||
|
</resultMap> |
||||
|
|
||||
|
<sql id="selectSysAnswersVo"> |
||||
|
select |
||||
|
a.id, |
||||
|
a.question_id, |
||||
|
a.user_id, |
||||
|
a.username, |
||||
|
u.nick_name, |
||||
|
u.avatar, |
||||
|
a.content, |
||||
|
a.created_at, |
||||
|
a.updated_at |
||||
|
from sys_answers a |
||||
|
left join sys_user u on a.user_id = u.user_id |
||||
|
</sql> |
||||
|
|
||||
|
<select id="selectSysAnswersList" parameterType="SysAnswers" resultMap="SysAnswersResult"> |
||||
|
<include refid="selectSysAnswersVo"/> |
||||
|
<where> |
||||
|
<if test="questionId != null "> and a.question_id = #{questionId}</if> |
||||
|
<if test="userId != null and userId != ''"> and a.user_id = #{userId}</if> |
||||
|
<if test="username != null and username != ''"> and a.username like concat('%', #{username}, '%')</if> |
||||
|
<if test="nickName != null and nickName != ''"> and u.nick_name like concat('%', #{nickName}, '%')</if> |
||||
|
<if test="content != null and content != ''"> and a.content like concat('%', #{content}, '%')</if> |
||||
|
<if test="createdAt != null "> and date(a.created_at) = date(#{createdAt})</if> |
||||
|
<if test="params.beginTime != null and params.beginTime != ''"> |
||||
|
and date_format(a.created_at,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') |
||||
|
</if> |
||||
|
<if test="params.endTime != null and params.endTime != ''"> |
||||
|
and date_format(a.created_at,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') |
||||
|
</if> |
||||
|
</where> |
||||
|
order by a.created_at desc |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectSysAnswersById" parameterType="Long" resultMap="SysAnswersResult"> |
||||
|
<include refid="selectSysAnswersVo"/> |
||||
|
where a.id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertSysAnswers" parameterType="SysAnswers" useGeneratedKeys="true" keyProperty="id"> |
||||
|
insert into sys_answers |
||||
|
<trim prefix="(" suffix=")" suffixOverrides=","> |
||||
|
<if test="questionId != null">question_id,</if> |
||||
|
<if test="userId != null and userId != ''">user_id,</if> |
||||
|
<if test="username != null and username != ''">username,</if> |
||||
|
<if test="nickName != null and nickName != ''">nick_name,</if> |
||||
|
<if test="avatar != null and avatar != ''">avatar,</if> |
||||
|
<if test="content != null and content != ''">content,</if> |
||||
|
created_at, |
||||
|
</trim> |
||||
|
<trim prefix="values (" suffix=")" suffixOverrides=","> |
||||
|
<if test="questionId != null">#{questionId},</if> |
||||
|
<if test="userId != null and userId != ''">#{userId},</if> |
||||
|
<if test="username != null and username != ''">#{username},</if> |
||||
|
<if test="nickName != null and nickName != ''">#{nickName},</if> |
||||
|
<if test="avatar != null and avatar != ''">#{avatar},</if> |
||||
|
<if test="content != null and content != ''">#{content},</if> |
||||
|
sysdate(), |
||||
|
</trim> |
||||
|
</insert> |
||||
|
|
||||
|
<update id="updateSysAnswers" parameterType="SysAnswers"> |
||||
|
update sys_answers |
||||
|
<trim prefix="SET" suffixOverrides=","> |
||||
|
<if test="questionId != null">question_id = #{questionId},</if> |
||||
|
<if test="userId != null and userId != ''">user_id = #{userId},</if> |
||||
|
<if test="username != null and username != ''">username = #{username},</if> |
||||
|
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> |
||||
|
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if> |
||||
|
<if test="content != null and content != ''">content = #{content},</if> |
||||
|
updated_at = sysdate(), |
||||
|
</trim> |
||||
|
where id = #{id} |
||||
|
</update> |
||||
|
|
||||
|
<delete id="deleteSysAnswersById" parameterType="Long"> |
||||
|
delete from sys_answers where id = #{id} |
||||
|
</delete> |
||||
|
|
||||
|
<delete id="deleteSysAnswersByIds" parameterType="String"> |
||||
|
delete from sys_answers where id in |
||||
|
<foreach item="id" collection="array" open="(" separator="," close=")"> |
||||
|
#{id} |
||||
|
</foreach> |
||||
|
</delete> |
||||
|
|
||||
|
<delete id="deleteAnswersByQuestionId" parameterType="Long"> |
||||
|
delete from sys_answers where question_id = #{questionId} |
||||
|
</delete> |
||||
|
|
||||
|
<select id="countAnswersByQuestionId" parameterType="Long" resultType="Long"> |
||||
|
select count(*) from sys_answers where question_id = #{questionId} |
||||
|
</select> |
||||
|
</mapper> |
||||
@ -0,0 +1,143 @@ |
|||||
|
<?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.system.mapper.SysQuestionsMapper"> |
||||
|
|
||||
|
<resultMap type="SysQuestions" id="SysQuestionsResult"> |
||||
|
<result property="id" column="id" /> |
||||
|
<result property="userId" column="user_id" /> |
||||
|
<result property="username" column="username" /> |
||||
|
<result property="title" column="title" /> |
||||
|
<result property="content" column="content" /> |
||||
|
<result property="tags" column="tags" /> |
||||
|
<result property="answerCount" column="answer_count" /> |
||||
|
<result property="createdAt" column="created_at" /> |
||||
|
<result property="updatedAt" column="updated_at" /> |
||||
|
<result property="nickName" column="nick_name" /> |
||||
|
<result property="avatar" column="avatar" /> |
||||
|
</resultMap> |
||||
|
|
||||
|
<sql id="selectSysQuestionsVo"> |
||||
|
SELECT |
||||
|
q.id, |
||||
|
q.user_id, |
||||
|
u.user_name as username, |
||||
|
u.nick_name, |
||||
|
u.avatar, |
||||
|
q.title, |
||||
|
q.content, |
||||
|
q.tags, |
||||
|
q.answer_count, |
||||
|
q.created_at, |
||||
|
q.updated_at |
||||
|
FROM sys_questions q |
||||
|
LEFT JOIN sys_user u ON q.user_id = u.user_id |
||||
|
</sql> |
||||
|
|
||||
|
<select id="selectSysQuestionsList" parameterType="SysQuestions" resultMap="SysQuestionsResult"> |
||||
|
<include refid="selectSysQuestionsVo"/> |
||||
|
<where> |
||||
|
<if test="userId != null and userId != ''"> and user_id = #{userId}</if> |
||||
|
<if test="username != null and username != ''"> and username like concat('%', #{username}, '%')</if> |
||||
|
<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="tags != null and tags != ''"> and tags like concat('%', #{tags}, '%')</if> |
||||
|
<if test="answerCount != null "> and answer_count = #{answerCount}</if> |
||||
|
<if test="createdAt != null "> and created_at = #{createdAt}</if> |
||||
|
<if test="updatedAt != null "> and updated_at = #{updatedAt}</if> |
||||
|
<if test="nickName != null and nickName != ''"> and u.nick_name like concat('%', #{nickName}, '%')</if> |
||||
|
</where> |
||||
|
order by q.created_at desc |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectSysQuestionsById" parameterType="Long" resultMap="SysQuestionsResult"> |
||||
|
<include refid="selectSysQuestionsVo"/> |
||||
|
where q.id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertSysQuestions" parameterType="SysQuestions" useGeneratedKeys="true" keyProperty="id"> |
||||
|
insert into sys_questions |
||||
|
<trim prefix="(" suffix=")" suffixOverrides=","> |
||||
|
<if test="userId != null and userId != ''">user_id,</if> |
||||
|
<if test="username != null and username != ''">username,</if> |
||||
|
<if test="title != null and title != ''">title,</if> |
||||
|
<if test="content != null and content != ''">content,</if> |
||||
|
<if test="tags != null and tags != ''">tags,</if> |
||||
|
<if test="answerCount != null">answer_count,</if> |
||||
|
<if test="createdAt != null">created_at,</if> |
||||
|
<if test="updatedAt != null">updated_at,</if> |
||||
|
</trim> |
||||
|
<trim prefix="values (" suffix=")" suffixOverrides=","> |
||||
|
<if test="userId != null and userId != ''">#{userId},</if> |
||||
|
<if test="username != null and username != ''">#{username},</if> |
||||
|
<if test="title != null and title != ''">#{title},</if> |
||||
|
<if test="content != null and content != ''">#{content},</if> |
||||
|
<if test="tags != null and tags != ''">#{tags},</if> |
||||
|
<if test="answerCount != null">#{answerCount},</if> |
||||
|
<if test="createdAt != null">#{createdAt},</if> |
||||
|
<if test="updatedAt != null">#{updatedAt},</if> |
||||
|
</trim> |
||||
|
</insert> |
||||
|
|
||||
|
<update id="updateSysQuestions" parameterType="SysQuestions"> |
||||
|
update sys_questions |
||||
|
<trim prefix="SET" suffixOverrides=","> |
||||
|
<if test="userId != null and userId != ''">user_id = #{userId},</if> |
||||
|
<if test="username != null and username != ''">username = #{username},</if> |
||||
|
<if test="title != null and title != ''">title = #{title},</if> |
||||
|
<if test="content != null and content != ''">content = #{content},</if> |
||||
|
<if test="tags != null and tags != ''">tags = #{tags},</if> |
||||
|
<if test="answerCount != null">answer_count = #{answerCount},</if> |
||||
|
<if test="createdAt != null">created_at = #{createdAt},</if> |
||||
|
<if test="updatedAt != null">updated_at = #{updatedAt},</if> |
||||
|
</trim> |
||||
|
where id = #{id} |
||||
|
</update> |
||||
|
|
||||
|
<delete id="deleteSysQuestionsById" parameterType="Long"> |
||||
|
delete from sys_questions where id = #{id} |
||||
|
</delete> |
||||
|
|
||||
|
<delete id="deleteSysQuestionsByIds" parameterType="String"> |
||||
|
delete from sys_questions where id in |
||||
|
<foreach item="id" collection="array" open="(" separator="," close=")"> |
||||
|
#{id} |
||||
|
</foreach> |
||||
|
</delete> |
||||
|
|
||||
|
<!-- 增加答案数量 --> |
||||
|
<update id="increaseAnswerCount" parameterType="Long"> |
||||
|
update sys_questions |
||||
|
set answer_count = answer_count + 1, |
||||
|
updated_at = sysdate() |
||||
|
where id = #{questionId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 减少答案数量 --> |
||||
|
<update id="decreaseAnswerCount" parameterType="Long"> |
||||
|
update sys_questions |
||||
|
set answer_count = case |
||||
|
when answer_count > 0 then answer_count - 1 |
||||
|
else 0 |
||||
|
end, |
||||
|
updated_at = sysdate() |
||||
|
where id = #{questionId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 从数据库实时统计答案数量 --> |
||||
|
<update id="updateAnswerCountFromDb" parameterType="Long"> |
||||
|
update sys_questions q |
||||
|
set q.answer_count = ( |
||||
|
select count(*) from sys_answers a |
||||
|
where a.question_id = q.id and a.deleted = 0 |
||||
|
), |
||||
|
q.updated_at = sysdate() |
||||
|
where q.id = #{questionId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取答案数量 --> |
||||
|
<select id="getAnswerCount" parameterType="Long" resultType="Long"> |
||||
|
select answer_count from sys_questions where id = #{questionId} |
||||
|
</select> |
||||
|
</mapper> |
||||
@ -1,160 +1,244 @@ |
|||||
<?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"> |
<mapper namespace="com.chenhai.vet.mapper.VetTrainingVideoMapper"> |
||||
|
|
||||
<resultMap id="VideoResult" type="VetTrainingVideo"> |
|
||||
<id property="id" column="id"/> |
|
||||
<result property="userId" column="user_id"/> |
|
||||
<result property="title" column="title"/> |
|
||||
<result property="description" column="description"/> |
|
||||
<result property="videoUrl" column="video_url"/> |
|
||||
<result property="coverImage" column="cover_image"/> |
|
||||
<result property="category" column="category"/> |
|
||||
<result property="tags" column="tags"/> |
|
||||
<result property="duration" column="duration"/> |
|
||||
<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"/> |
|
||||
<result property="userAvatar" column="user_avatar"/> |
|
||||
|
<resultMap type="VetTrainingVideo" id="VetTrainingVideoResult"> |
||||
|
<result property="id" column="id" /> |
||||
|
<result property="userId" column="user_id" /> |
||||
|
<result property="title" column="title" /> |
||||
|
<result property="description" column="description" /> |
||||
|
<result property="videoUrl" column="video_url" /> |
||||
|
<result property="coverImage" column="cover_image" /> |
||||
|
<result property="category" column="category" /> |
||||
|
<result property="tags" column="tags" /> |
||||
|
<result property="duration" column="duration" /> |
||||
|
<result property="fileSize" column="file_size" /> |
||||
|
<result property="viewCount" column="view_count" /> |
||||
|
<result property="status" column="status" /> |
||||
|
<result property="createTime" column="create_time" /> |
||||
|
<result property="updateTime" column="update_time" /> |
||||
|
<result property="delFlag" column="del_flag" /> |
||||
|
<result property="auditStatus" column="audit_status" /> |
||||
|
<result property="auditOpinion" column="audit_opinion" /> |
||||
|
<result property="auditUserId" column="audit_user_id" /> |
||||
|
<result property="auditTime" column="audit_time" /> |
||||
|
<result property="publisherName" column="publisher_name" /> |
||||
|
<result property="publisherAvatar" column="publisher_avatar" /> |
||||
|
<result property="publishTime" column="publish_time" /> |
||||
</resultMap> |
</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, audit_status, audit_opinion, |
|
||||
create_time, update_time |
|
||||
) VALUES ( |
|
||||
#{userId}, #{title}, #{description}, #{videoUrl}, #{coverImage}, |
|
||||
#{category}, #{tags}, #{duration}, #{fileSize}, #{viewCount}, |
|
||||
#{status}, #{auditStatus}, #{auditOpinion}, |
|
||||
#{createTime}, #{updateTime} |
|
||||
) |
|
||||
</insert> |
|
||||
|
|
||||
<select id="selectMyVideos" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
|
<sql id="selectVetTrainingVideoVo"> |
||||
|
SELECT |
||||
|
v.id, |
||||
|
v.user_id, |
||||
|
v.title, |
||||
|
v.description, |
||||
|
v.video_url, |
||||
|
v.cover_image, |
||||
|
v.category, |
||||
|
v.tags, |
||||
|
v.duration, |
||||
|
v.file_size, |
||||
|
v.view_count, |
||||
|
v.status, |
||||
|
v.create_time, |
||||
|
v.update_time, |
||||
|
v.del_flag, |
||||
|
v.audit_status, |
||||
|
v.audit_opinion, |
||||
|
v.audit_user_id, |
||||
|
v.audit_time, |
||||
|
v.publish_time, |
||||
|
u.nick_name as publisher_name, <!-- 使用用户的昵称作为发布者姓名 --> |
||||
|
u.avatar as publisher_avatar |
||||
FROM vet_training_video v |
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.user_id = #{userId} |
|
||||
<if test="title != null and title != ''"> |
|
||||
AND v.title LIKE CONCAT('%', #{title}, '%') |
|
||||
</if> |
|
||||
<if test="category != null and category != ''"> |
|
||||
AND v.category = #{category} |
|
||||
</if> |
|
||||
<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> |
|
||||
|
</sql> |
||||
|
|
||||
<select id="selectPublicVideos" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
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> |
|
||||
<if test="category != null and category != ''"> |
|
||||
AND v.category = #{category} |
|
||||
</if> |
|
||||
<if test="userName != null and userName != ''"> |
|
||||
AND u.nick_name LIKE CONCAT('%', #{userName}, '%') |
|
||||
</if> |
|
||||
ORDER BY v.create_time DESC |
|
||||
</select> |
|
||||
|
|
||||
<select id="selectVideoById" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
FROM vet_training_video v |
|
||||
LEFT JOIN sys_user u ON v.user_id = u.user_id |
|
||||
WHERE v.id = #{id} |
|
||||
|
<select id="selectVetTrainingVideoList" parameterType="VetTrainingVideo" resultMap="VetTrainingVideoResult"> |
||||
|
<include refid="selectVetTrainingVideoVo"/> |
||||
|
<where> |
||||
|
<!-- 使用表别名 v. 来明确指定字段来源 --> |
||||
|
<if test="userId != null "> and v.user_id = #{userId}</if> |
||||
|
<if test="title != null and title != ''"> |
||||
|
<bind name="titleLike" value="'%' + title + '%'" /> |
||||
|
and v.title like #{titleLike} |
||||
|
</if> |
||||
|
<if test="description != null and description != ''"> |
||||
|
<bind name="descriptionLike" value="'%' + description + '%'" /> |
||||
|
and v.description like #{descriptionLike} |
||||
|
</if> |
||||
|
<if test="videoUrl != null and videoUrl != ''"> and v.video_url = #{videoUrl}</if> |
||||
|
<if test="coverImage != null and coverImage != ''"> and v.cover_image = #{coverImage}</if> |
||||
|
<if test="category != null and category != ''"> and v.category = #{category}</if> |
||||
|
<if test="tags != null and tags != ''"> |
||||
|
<bind name="tagsLike" value="'%' + tags + '%'" /> |
||||
|
and v.tags like #{tagsLike} |
||||
|
</if> |
||||
|
<if test="duration != null "> and v.duration = #{duration}</if> |
||||
|
<if test="fileSize != null "> and v.file_size = #{fileSize}</if> |
||||
|
<if test="viewCount != null "> and v.view_count = #{viewCount}</if> |
||||
|
<if test="status != null and status != ''"> and v.status = #{status}</if> |
||||
|
<if test="delFlag != null and delFlag != ''"> and v.del_flag = #{delFlag}</if> |
||||
|
<if test="auditStatus != null and auditStatus != ''"> and v.audit_status = #{auditStatus}</if> |
||||
|
<if test="auditOpinion != null and auditOpinion != ''"> |
||||
|
<bind name="opinionLike" value="'%' + auditOpinion + '%'" /> |
||||
|
and v.audit_opinion like #{opinionLike} |
||||
|
</if> |
||||
|
<if test="auditUserId != null "> and v.audit_user_id = #{auditUserId}</if> |
||||
|
<if test="auditTime != null "> and v.audit_time = #{auditTime}</if> |
||||
|
<if test="publisherName != null and publisherName != ''"> |
||||
|
<bind name="publisherLike" value="'%' + publisherName + '%'" /> |
||||
|
and u.nick_name like #{publisherLike} |
||||
|
</if> |
||||
|
<!-- 搜索关键词:同时搜索标题、描述、标签、发布者姓名 --> |
||||
|
<if test="searchKey != null and searchKey != ''"> |
||||
|
<bind name="searchKeyLike" value="'%' + searchKey + '%'" /> |
||||
|
and ( |
||||
|
v.title like #{searchKeyLike} |
||||
|
or v.description like #{searchKeyLike} |
||||
|
or v.tags like #{searchKeyLike} |
||||
|
or v.category like #{searchKeyLike} |
||||
|
or u.nick_name like #{searchKeyLike} |
||||
|
) |
||||
|
</if> |
||||
|
<if test="publishTime != null "> and v.publish_time = #{publishTime}</if> |
||||
|
</where> |
||||
</select> |
</select> |
||||
|
|
||||
<update id="incrementViewCount"> |
|
||||
UPDATE vet_training_video |
|
||||
SET view_count = view_count + 1 |
|
||||
WHERE id = #{id} |
|
||||
</update> |
|
||||
|
|
||||
<select id="selectHotVideos" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
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' |
|
||||
ORDER BY v.view_count DESC |
|
||||
LIMIT #{limit} |
|
||||
|
<select id="selectVetTrainingVideoById" parameterType="Long" resultMap="VetTrainingVideoResult"> |
||||
|
<include refid="selectVetTrainingVideoVo"/> |
||||
|
where id = #{id} |
||||
</select> |
</select> |
||||
|
|
||||
<select id="searchVideos" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
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' |
|
||||
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> |
|
||||
|
<insert id="insertVetTrainingVideo" parameterType="VetTrainingVideo" useGeneratedKeys="true" keyProperty="id"> |
||||
|
insert into vet_training_video |
||||
|
<trim prefix="(" suffix=")" suffixOverrides=","> |
||||
|
<if test="userId != null">user_id,</if> |
||||
|
<if test="title != null and title != ''">title,</if> |
||||
|
<if test="description != null">description,</if> |
||||
|
<if test="videoUrl != null and videoUrl != ''">video_url,</if> |
||||
|
<if test="coverImage != null">cover_image,</if> |
||||
|
<if test="category != null">category,</if> |
||||
|
<if test="tags != null">tags,</if> |
||||
|
<if test="duration != null">duration,</if> |
||||
|
<if test="fileSize != null">file_size,</if> |
||||
|
<if test="viewCount != null">view_count,</if> |
||||
|
<if test="status != null">status,</if> |
||||
|
<if test="createTime != null">create_time,</if> |
||||
|
<if test="updateTime != null">update_time,</if> |
||||
|
<if test="delFlag != null">del_flag,</if> |
||||
|
<if test="auditStatus != null">audit_status,</if> |
||||
|
<if test="auditOpinion != null">audit_opinion,</if> |
||||
|
<if test="auditUserId != null">audit_user_id,</if> |
||||
|
<if test="auditTime != null">audit_time,</if> |
||||
|
<if test="publishTime != null">publish_time,</if> |
||||
|
</trim> |
||||
|
<trim prefix="values (" suffix=")" suffixOverrides=","> |
||||
|
<if test="userId != null">#{userId},</if> |
||||
|
<if test="title != null and title != ''">#{title},</if> |
||||
|
<if test="description != null">#{description},</if> |
||||
|
<if test="videoUrl != null and videoUrl != ''">#{videoUrl},</if> |
||||
|
<if test="coverImage != null">#{coverImage},</if> |
||||
|
<if test="category != null">#{category},</if> |
||||
|
<if test="tags != null">#{tags},</if> |
||||
|
<if test="duration != null">#{duration},</if> |
||||
|
<if test="fileSize != null">#{fileSize},</if> |
||||
|
<if test="viewCount != null">#{viewCount},</if> |
||||
|
<if test="status != null">#{status},</if> |
||||
|
<if test="createTime != null">#{createTime},</if> |
||||
|
<if test="updateTime != null">#{updateTime},</if> |
||||
|
<if test="delFlag != null">#{delFlag},</if> |
||||
|
<if test="auditStatus != null">#{auditStatus},</if> |
||||
|
<if test="auditOpinion != null">#{auditOpinion},</if> |
||||
|
<if test="auditUserId != null">#{auditUserId},</if> |
||||
|
<if test="auditTime != null">#{auditTime},</if> |
||||
|
<if test="publishTime != null">#{publishTime},</if> |
||||
|
</trim> |
||||
|
</insert> |
||||
|
|
||||
<delete id="deleteVideoById"> |
|
||||
DELETE FROM vet_training_video |
|
||||
WHERE id = #{id} |
|
||||
|
<update id="updateVetTrainingVideo" parameterType="VetTrainingVideo"> |
||||
|
update vet_training_video |
||||
|
<trim prefix="SET" suffixOverrides=","> |
||||
|
<if test="userId != null">user_id = #{userId},</if> |
||||
|
<if test="title != null and title != ''">title = #{title},</if> |
||||
|
<if test="description != null">description = #{description},</if> |
||||
|
<if test="videoUrl != null and videoUrl != ''">video_url = #{videoUrl},</if> |
||||
|
<if test="coverImage != null">cover_image = #{coverImage},</if> |
||||
|
<if test="category != null">category = #{category},</if> |
||||
|
<if test="tags != null">tags = #{tags},</if> |
||||
|
<if test="duration != null">duration = #{duration},</if> |
||||
|
<if test="fileSize != null">file_size = #{fileSize},</if> |
||||
|
<if test="viewCount != null">view_count = #{viewCount},</if> |
||||
|
<if test="status != null">status = #{status},</if> |
||||
|
<if test="createTime != null">create_time = #{createTime},</if> |
||||
|
<if test="updateTime != null">update_time = #{updateTime},</if> |
||||
|
<if test="delFlag != null">del_flag = #{delFlag},</if> |
||||
|
<if test="auditStatus != null">audit_status = #{auditStatus},</if> |
||||
|
<if test="auditOpinion != null">audit_opinion = #{auditOpinion},</if> |
||||
|
<if test="auditUserId != null">audit_user_id = #{auditUserId},</if> |
||||
|
<if test="auditTime != null">audit_time = #{auditTime},</if> |
||||
|
<if test="publishTime != null">publish_time = #{publishTime},</if> |
||||
|
</trim> |
||||
|
where id = #{id} |
||||
|
</update> |
||||
|
|
||||
|
<delete id="deleteVetTrainingVideoById" parameterType="Long"> |
||||
|
delete from vet_training_video where id = #{id} |
||||
</delete> |
</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> |
|
||||
|
<delete id="deleteVetTrainingVideoByIds" parameterType="String"> |
||||
|
delete from vet_training_video where id in |
||||
|
<foreach item="id" collection="array" open="(" separator="," close=")"> |
||||
|
#{id} |
||||
|
</foreach> |
||||
|
</delete> |
||||
|
|
||||
<update id="updateStatus"> |
|
||||
UPDATE vet_training_video |
|
||||
SET status = #{status}, |
|
||||
update_time = NOW() |
|
||||
WHERE id = #{id} |
|
||||
</update> |
|
||||
|
<!-- 查询公开视频列表(已上架且已审核通过) --> |
||||
|
<select id="selectPublicVideoList" parameterType="VetTrainingVideo" resultMap="VetTrainingVideoResult"> |
||||
|
<include refid="selectVetTrainingVideoVo"/> |
||||
|
<where> |
||||
|
<!-- 强制条件:已上架、审核通过、未删除 --> |
||||
|
and v.status = '1' |
||||
|
and v.audit_status = '1' |
||||
|
and v.del_flag = '0' |
||||
|
|
||||
<select id="selectPendingAuditVideos" resultMap="VideoResult"> |
|
||||
SELECT v.*, u.nick_name as user_name,u.avatar as user_avatar |
|
||||
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 |
|
||||
|
<!-- 可选查询条件 --> |
||||
|
<if test="userId != null "> and v.user_id = #{userId}</if> |
||||
|
<if test="title != null and title != ''"> |
||||
|
<bind name="titleLike" value="'%' + title + '%'" /> |
||||
|
and v.title like #{titleLike} |
||||
|
</if> |
||||
|
<if test="description != null and description != ''"> |
||||
|
<bind name="descriptionLike" value="'%' + description + '%'" /> |
||||
|
and v.description like #{descriptionLike} |
||||
|
</if> |
||||
|
<if test="category != null and category != ''"> and v.category = #{category}</if> |
||||
|
<if test="tags != null and tags != ''"> |
||||
|
<bind name="tagsLike" value="'%' + tags + '%'" /> |
||||
|
and v.tags like #{tagsLike} |
||||
|
</if> |
||||
|
<if test="publisherName != null and publisherName != ''"> |
||||
|
<bind name="publisherLike" value="'%' + publisherName + '%'" /> |
||||
|
and u.nick_name like #{publisherLike} |
||||
|
</if> |
||||
|
<!-- 搜索关键词:同时搜索标题、描述、标签、发布者姓名 --> |
||||
|
<if test="searchKey != null and searchKey != ''"> |
||||
|
<bind name="searchKeyLike" value="'%' + searchKey + '%'" /> |
||||
|
and ( |
||||
|
v.title like #{searchKeyLike} |
||||
|
or v.description like #{searchKeyLike} |
||||
|
or v.tags like #{searchKeyLike} |
||||
|
or v.category like #{searchKeyLike} |
||||
|
or u.nick_name like #{searchKeyLike} |
||||
|
) |
||||
|
</if> |
||||
|
<if test="publishTime != null "> and v.publish_time = #{publishTime}</if> |
||||
|
</where> |
||||
|
<!-- 默认按创建时间倒序排列 --> |
||||
|
order by v.create_time desc |
||||
</select> |
</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> |
</mapper> |
||||
@ -0,0 +1,44 @@ |
|||||
|
import request from '@/utils/request' |
||||
|
|
||||
|
// 查询答复列表
|
||||
|
export function listAnswers(query) { |
||||
|
return request({ |
||||
|
url: '/system/answers/list', |
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询答复详细
|
||||
|
export function getAnswers(id) { |
||||
|
return request({ |
||||
|
url: '/system/answers/' + id, |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新增答复
|
||||
|
export function addAnswers(data) { |
||||
|
return request({ |
||||
|
url: '/system/answers', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 修改答复
|
||||
|
export function updateAnswers(data) { |
||||
|
return request({ |
||||
|
url: '/system/answers', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 删除答复
|
||||
|
export function delAnswers(id) { |
||||
|
return request({ |
||||
|
url: '/system/answers/' + id, |
||||
|
method: 'delete' |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import request from '@/utils/request' |
||||
|
|
||||
|
// 查询问答列表
|
||||
|
export function listQuestions(query) { |
||||
|
return request({ |
||||
|
url: '/system/questions/list', |
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询问答详细
|
||||
|
export function getQuestions(id) { |
||||
|
return request({ |
||||
|
url: '/system/questions/' + id, |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新增问答
|
||||
|
export function addQuestions(data) { |
||||
|
return request({ |
||||
|
url: '/system/questions', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 修改问答
|
||||
|
export function updateQuestions(data) { |
||||
|
return request({ |
||||
|
url: '/system/questions', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 删除问答
|
||||
|
export function delQuestions(id) { |
||||
|
return request({ |
||||
|
url: '/system/questions/' + id, |
||||
|
method: 'delete' |
||||
|
}) |
||||
|
} |
||||
@ -1,125 +1,154 @@ |
|||||
// trainingApi.js - 完整修正版
|
|
||||
import request from '@/utils/request' |
import request from '@/utils/request' |
||||
|
|
||||
export default { |
|
||||
// 上传视频
|
|
||||
uploadVideo(data) { |
|
||||
return request({ |
|
||||
url: '/vet/training/upload', |
|
||||
method: 'post', |
|
||||
data: data, |
|
||||
headers: { |
|
||||
'Content-Type': 'multipart/form-data' |
|
||||
}, |
|
||||
timeout: 300000 |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 获取公开视频列表
|
|
||||
getPublicVideos(params) { |
|
||||
return request({ |
|
||||
url: '/vet/training/public-videos', |
|
||||
method: 'get', |
|
||||
params: params |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 获取我的视频
|
|
||||
getMyVideos(params) { |
|
||||
return request({ |
|
||||
url: '/vet/training/my-videos', |
|
||||
method: 'get', |
|
||||
params: params |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 获取视频详情
|
|
||||
getVideoDetail(id) { |
|
||||
return request({ |
|
||||
url: `/vet/training/video/${id}`, |
|
||||
method: 'get' |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 提交审核(用户提交给管理员)
|
|
||||
submitForAudit(videoId) { |
|
||||
return request({ |
|
||||
url: `/vet/training/submit-audit/${videoId}`, |
|
||||
method: 'post' |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 取消审核
|
|
||||
cancelAudit(videoId) { |
|
||||
return request({ |
|
||||
url: `/vet/training/cancel-audit/${videoId}`, |
|
||||
method: 'post' |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 重新提交审核
|
|
||||
resubmitAudit(videoId) { |
|
||||
return request({ |
|
||||
url: `/vet/training/resubmit-audit/${videoId}`, |
|
||||
method: 'post' |
|
||||
}) |
|
||||
}, |
|
||||
// 审核视频(管理员审核)
|
|
||||
auditVideo(videoId, auditStatus, auditOpinion = '') { |
|
||||
// 改用JSON方式传递参数
|
|
||||
const data = { |
|
||||
auditStatus: auditStatus, |
|
||||
auditOpinion: auditOpinion || '' |
|
||||
|
// 查询兽医培训视频列表
|
||||
|
export function listTraining(query) { |
||||
|
return request({ |
||||
|
url: '/vet/training/list', |
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询兽医培训视频详细
|
||||
|
export function getTraining(id) { |
||||
|
return request({ |
||||
|
url: '/vet/training/' + id, |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新增兽医培训视频
|
||||
|
export function addTraining(data) { |
||||
|
return request({ |
||||
|
url: '/vet/training', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 修改兽医培训视频
|
||||
|
export function updateTraining(data) { |
||||
|
return request({ |
||||
|
url: '/vet/training', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 删除兽医培训视频
|
||||
|
export function delTraining(id) { |
||||
|
return request({ |
||||
|
url: '/vet/training/' + id, |
||||
|
method: 'delete' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 上传视频文件
|
||||
|
export function uploadVideo(data) { |
||||
|
return request({ |
||||
|
url: '/vet/training/uploadVideo', |
||||
|
method: 'post', |
||||
|
data: data, |
||||
|
headers: { |
||||
|
'Content-Type': 'multipart/form-data' |
||||
} |
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// ============ 已有的其他接口(如果存在的话) ============
|
||||
|
|
||||
|
// 提交审核
|
||||
|
export function submitForAudit(id) { |
||||
|
return request({ |
||||
|
url: `/vet/training/submit-audit/${id}`, |
||||
|
method: 'post' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 取消审核
|
||||
|
export function cancelAudit(id) { |
||||
|
return request({ |
||||
|
url: `/vet/training/cancel-audit/${id}`, |
||||
|
method: 'post' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 重新提交审核
|
||||
|
export function resubmitForAudit(id) { |
||||
|
return request({ |
||||
|
url: `/vet/training/resubmit-audit/${id}`, |
||||
|
method: 'post' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 审核视频 - 修改为接收一个对象参数
|
||||
|
export function auditVideo(data) { |
||||
|
return request({ |
||||
|
url: `/vet/training/audit/${data.id}`, |
||||
|
method: 'post', |
||||
|
data: { |
||||
|
auditStatus: data.auditStatus, |
||||
|
auditOpinion: data.auditOpinion |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 上架视频
|
||||
|
export function publishVideo(id) { |
||||
|
return request({ |
||||
|
url: `/vet/training/publish/${id}`, |
||||
|
method: 'post' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 下架视频
|
||||
|
export function offlineVideo(id) { |
||||
|
return request({ |
||||
|
url: `/vet/training/offline/${id}`, |
||||
|
method: 'post' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取我的视频
|
||||
|
export function getMyVideos(query) { |
||||
|
return request({ |
||||
|
url: '/vet/training/list/my', // 改为这个路径
|
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取公开视频
|
||||
|
export function getPublicVideos(query) { |
||||
|
return request({ |
||||
|
url: '/vet/training/list/public', // 改为这个路径
|
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取待审核视频
|
||||
|
export function getPendingAuditVideos(query) { |
||||
|
return request({ |
||||
|
url: '/vet/training/pending-audit', |
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取视频详情
|
||||
|
export function getVideoDetail(videoId) { |
||||
|
return request({ |
||||
|
url: `/vet/training/video/${videoId}`, |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
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' |
|
||||
}) |
|
||||
}, |
|
||||
|
|
||||
// 获取待审核视频列表
|
|
||||
getPendingAuditVideos(params) { |
|
||||
return request({ |
|
||||
url: '/vet/training/pending-audit', |
|
||||
method: 'get', |
|
||||
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' |
|
||||
}) |
|
||||
} |
|
||||
|
// 更新视频信息
|
||||
|
export function updateVideoInfo(videoId, data) { |
||||
|
return request({ |
||||
|
url: `/vet/training/update/${videoId}`, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
} |
} |
||||
@ -0,0 +1,252 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="handleAdd" |
||||
|
v-hasPermi="['system:answers:add']" |
||||
|
>新增</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
plain |
||||
|
icon="el-icon-edit" |
||||
|
size="mini" |
||||
|
:disabled="single" |
||||
|
@click="handleUpdate" |
||||
|
v-hasPermi="['system:answers:edit']" |
||||
|
>修改</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
v-hasPermi="['system:answers:remove']" |
||||
|
>删除</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
plain |
||||
|
icon="el-icon-download" |
||||
|
size="mini" |
||||
|
@click="handleExport" |
||||
|
v-hasPermi="['system:answers:export']" |
||||
|
>导出</el-button> |
||||
|
</el-col> |
||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table v-loading="loading" :data="answersList" @selection-change="handleSelectionChange"> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column label="对应的问题ID" align="center" prop="questionId" /> |
||||
|
<el-table-column label="用户名" align="center" prop="username" /> |
||||
|
<el-table-column label="回答内容" align="center" prop="content" /> |
||||
|
<el-table-column label="创建时间" align="center" prop="createdAt" width="180"> |
||||
|
<template slot-scope="scope"> |
||||
|
<span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d}') }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
v-hasPermi="['system:answers:edit']" |
||||
|
>修改</el-button> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
v-hasPermi="['system:answers:remove']" |
||||
|
>删除</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total>0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 添加或修改答复对话框 --> |
||||
|
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> |
||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
||||
|
<el-form-item label="回答内容"> |
||||
|
<editor v-model="form.content" :min-height="192"/> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { listAnswers, getAnswers, delAnswers, addAnswers, updateAnswers } from "@/api/system/answers" |
||||
|
|
||||
|
export default { |
||||
|
name: "Answers", |
||||
|
data() { |
||||
|
return { |
||||
|
// 遮罩层 |
||||
|
loading: true, |
||||
|
// 选中数组 |
||||
|
ids: [], |
||||
|
// 非单个禁用 |
||||
|
single: true, |
||||
|
// 非多个禁用 |
||||
|
multiple: true, |
||||
|
// 显示搜索条件 |
||||
|
showSearch: true, |
||||
|
// 总条数 |
||||
|
total: 0, |
||||
|
// 答复表格数据 |
||||
|
answersList: [], |
||||
|
// 弹出层标题 |
||||
|
title: "", |
||||
|
// 是否显示弹出层 |
||||
|
open: false, |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
questionId: null, |
||||
|
userId: null, |
||||
|
username: null, |
||||
|
content: null, |
||||
|
createdAt: null, |
||||
|
updatedAt: null |
||||
|
}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: {} |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList() |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 查询答复列表 */ |
||||
|
getList() { |
||||
|
this.loading = true |
||||
|
listAnswers(this.queryParams).then(response => { |
||||
|
this.answersList = response.rows |
||||
|
this.total = response.total |
||||
|
this.loading = false |
||||
|
}) |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false |
||||
|
this.reset() |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
id: null, |
||||
|
questionId: null, |
||||
|
userId: null, |
||||
|
username: null, |
||||
|
content: null, |
||||
|
createdAt: null, |
||||
|
updatedAt: null |
||||
|
} |
||||
|
this.resetForm("form") |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1 |
||||
|
this.getList() |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.resetForm("queryForm") |
||||
|
this.handleQuery() |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map(item => item.id) |
||||
|
this.single = selection.length!==1 |
||||
|
this.multiple = !selection.length |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset() |
||||
|
this.open = true |
||||
|
this.title = "添加答复" |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.reset() |
||||
|
const id = row.id || this.ids |
||||
|
getAnswers(id).then(response => { |
||||
|
this.form = response.data |
||||
|
this.open = true |
||||
|
this.title = "修改答复" |
||||
|
}) |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm() { |
||||
|
this.$refs["form"].validate(valid => { |
||||
|
if (valid) { |
||||
|
if (this.form.id != null) { |
||||
|
updateAnswers(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("修改成功") |
||||
|
this.open = false |
||||
|
this.getList() |
||||
|
}) |
||||
|
} else { |
||||
|
addAnswers(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("新增成功") |
||||
|
this.open = false |
||||
|
this.getList() |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const ids = row.id || this.ids |
||||
|
this.$modal.confirm('是否确认删除答复编号为"' + ids + '"的数据项?').then(function() { |
||||
|
return delAnswers(ids) |
||||
|
}).then(() => { |
||||
|
this.getList() |
||||
|
this.$modal.msgSuccess("删除成功") |
||||
|
}).catch(() => {}) |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download('system/answers/export', { |
||||
|
...this.queryParams |
||||
|
}, `answers_${new Date().getTime()}.xlsx`) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
@ -0,0 +1,584 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<!-- 搜索区域 --> |
||||
|
<div class="search-area"> |
||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px"> |
||||
|
<el-form-item label="用户ID" prop="userId"> |
||||
|
<el-input |
||||
|
v-model="queryParams.userId" |
||||
|
placeholder="请输入用户ID" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="用户名" prop="username"> |
||||
|
<el-input |
||||
|
v-model="queryParams.username" |
||||
|
placeholder="请输入用户名" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="问题标题" prop="title"> |
||||
|
<el-input |
||||
|
v-model="queryParams.title" |
||||
|
placeholder="请输入问题标题" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="标签" prop="tags"> |
||||
|
<el-input |
||||
|
v-model="queryParams.tags" |
||||
|
placeholder="请输入标签" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="创建时间" prop="createdAt"> |
||||
|
<el-date-picker |
||||
|
v-model="queryParams.createdAt" |
||||
|
type="daterange" |
||||
|
range-separator="至" |
||||
|
start-placeholder="开始日期" |
||||
|
end-placeholder="结束日期" |
||||
|
value-format="yyyy-MM-dd" |
||||
|
> |
||||
|
</el-date-picker> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 操作按钮区域 --> |
||||
|
<div class="operation-area"> |
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="handleAdd" |
||||
|
v-hasPermi="['system:questions:add']" |
||||
|
>新增问题</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
plain |
||||
|
icon="el-icon-edit" |
||||
|
size="mini" |
||||
|
:disabled="single" |
||||
|
@click="handleUpdate" |
||||
|
v-hasPermi="['system:questions:edit']" |
||||
|
>修改</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
v-hasPermi="['system:questions:remove']" |
||||
|
>删除</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="info" |
||||
|
plain |
||||
|
icon="el-icon-chat-dot-round" |
||||
|
size="mini" |
||||
|
:disabled="single" |
||||
|
@click="viewAnswers" |
||||
|
v-hasPermi="['system:answers:view']" |
||||
|
>查看答案</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
plain |
||||
|
icon="el-icon-download" |
||||
|
size="mini" |
||||
|
@click="handleExport" |
||||
|
v-hasPermi="['system:questions:export']" |
||||
|
>导出</el-button> |
||||
|
</el-col> |
||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 主内容区域 --> |
||||
|
<div class="main-content" :class="{ 'has-answers': showAnswersPanel }"> |
||||
|
<!-- 左侧:问题列表 --> |
||||
|
<div class="questions-list" :style="{ width: showAnswersPanel ? '50%' : '100%' }"> |
||||
|
<el-table |
||||
|
v-loading="loading" |
||||
|
:data="questionsList" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
@row-click="handleRowClick" |
||||
|
highlight-current-row |
||||
|
style="width: 100%" |
||||
|
height="calc(100vh - 260px)" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column label="用户名" align="center" prop="username" width="120" /> |
||||
|
<el-table-column label="问题标题" align="left" prop="title" min-width="150"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-tooltip :content="scope.row.title" placement="top"> |
||||
|
<span class="title-text">{{ scope.row.title }}</span> |
||||
|
</el-tooltip> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="内容" align="left" prop="content" min-width="200"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div class="content-preview" v-html="scope.row.content"></div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="标签" align="center" prop="tags" width="120"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-tag v-if="scope.row.tags" size="mini">{{ scope.row.tags }}</el-tag> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="回答数" align="center" prop="answerCount" width="100"/> |
||||
|
<el-table-column label="创建时间" align="center" prop="createdAt" width="160" /> |
||||
|
<el-table-column label="操作" align="center" width="180" fixed="right"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
v-hasPermi="['system:questions:edit']" |
||||
|
>编辑</el-button> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-chat-dot-round" |
||||
|
@click="toggleAnswersPanel(scope.row)" |
||||
|
v-hasPermi="['system:answers:view']" |
||||
|
>答案</el-button> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
v-hasPermi="['system:questions:remove']" |
||||
|
>删除</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<!-- 分页 --> |
||||
|
<pagination |
||||
|
v-show="total>0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 右侧:答案管理面板 --> |
||||
|
<div v-if="showAnswersPanel" class="answers-panel"> |
||||
|
<div class="panel-header"> |
||||
|
<div class="panel-title"> |
||||
|
<span>{{ currentQuestionTitle }}</span> |
||||
|
<span class="answer-count">({{ currentAnswerCount }}个回答)</span> |
||||
|
</div> |
||||
|
<div class="panel-actions"> |
||||
|
<el-button size="mini" icon="el-icon-refresh" @click="refreshAnswers">刷新</el-button> |
||||
|
<el-button size="mini" icon="el-icon-close" @click="closeAnswersPanel">关闭</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="panel-content"> |
||||
|
<AnswersManagement |
||||
|
ref="answersManagement" |
||||
|
:question-id="currentQuestionId" |
||||
|
:key="currentQuestionId" |
||||
|
@refresh="handleAnswersRefresh" |
||||
|
:table-height="'calc(100vh - 320px)'" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 添加或修改问答对话框 --> |
||||
|
<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="250" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="标签" prop="tags"> |
||||
|
<el-input v-model="form.tags" placeholder="请输入标签,多个用逗号分隔" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { listQuestions, getQuestions, delQuestions, addQuestions, updateQuestions } from "@/api/system/questions" |
||||
|
import AnswersManagement from '../answers/index' // 导入Answers组件 |
||||
|
|
||||
|
export default { |
||||
|
name: "Questions", |
||||
|
components: { |
||||
|
AnswersManagement |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
// 遮罩层 |
||||
|
loading: true, |
||||
|
// 选中数组 |
||||
|
ids: [], |
||||
|
// 非单个禁用 |
||||
|
single: true, |
||||
|
// 非多个禁用 |
||||
|
multiple: true, |
||||
|
// 显示搜索条件 |
||||
|
showSearch: true, |
||||
|
// 总条数 |
||||
|
total: 0, |
||||
|
// 问答表格数据 |
||||
|
questionsList: [], |
||||
|
// 弹出层标题 |
||||
|
title: "", |
||||
|
// 是否显示弹出层 |
||||
|
open: false, |
||||
|
|
||||
|
// 新增的属性 |
||||
|
showAnswersPanel: false, // 是否显示答案面板 |
||||
|
currentQuestionId: null, // 当前查看的问题ID |
||||
|
currentQuestionTitle: '', // 当前查看的问题标题 |
||||
|
currentAnswerCount: 0, // 当前问题的回答数 |
||||
|
selectedRow: null, // 当前选中的行数据 |
||||
|
|
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 20, |
||||
|
userId: null, |
||||
|
username: null, |
||||
|
title: null, |
||||
|
content: null, |
||||
|
tags: null, |
||||
|
answerCount: null, |
||||
|
createdAt: null, |
||||
|
updatedAt: null |
||||
|
}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
userId: [ |
||||
|
{ required: true, message: "用户ID不能为空", trigger: "blur" } |
||||
|
], |
||||
|
username: [ |
||||
|
{ required: true, message: "用户名不能为空", trigger: "blur" } |
||||
|
], |
||||
|
title: [ |
||||
|
{ required: true, message: "问题标题不能为空", trigger: "blur" } |
||||
|
], |
||||
|
content: [ |
||||
|
{ required: true, message: "问题内容不能为空", trigger: "blur" } |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList() |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 查询问答列表 */ |
||||
|
getList() { |
||||
|
this.loading = true |
||||
|
listQuestions(this.queryParams).then(response => { |
||||
|
this.questionsList = response.rows |
||||
|
this.total = response.total |
||||
|
this.loading = false |
||||
|
}).catch(() => { |
||||
|
this.loading = false |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false |
||||
|
this.reset() |
||||
|
}, |
||||
|
|
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
id: null, |
||||
|
userId: null, |
||||
|
username: null, |
||||
|
title: null, |
||||
|
content: null, |
||||
|
tags: null, |
||||
|
answerCount: 0, |
||||
|
createdAt: null, |
||||
|
updatedAt: null |
||||
|
} |
||||
|
this.resetForm("form") |
||||
|
}, |
||||
|
|
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1 |
||||
|
this.getList() |
||||
|
}, |
||||
|
|
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.resetForm("queryForm") |
||||
|
this.handleQuery() |
||||
|
}, |
||||
|
|
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map(item => item.id) |
||||
|
this.single = selection.length !== 1 |
||||
|
this.multiple = !selection.length |
||||
|
}, |
||||
|
|
||||
|
// 行点击事件 |
||||
|
handleRowClick(row) { |
||||
|
this.selectedRow = row |
||||
|
}, |
||||
|
|
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset() |
||||
|
this.open = true |
||||
|
this.title = "添加问答" |
||||
|
}, |
||||
|
|
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.reset() |
||||
|
const id = row.id || this.ids[0] |
||||
|
getQuestions(id).then(response => { |
||||
|
this.form = response.data |
||||
|
this.open = true |
||||
|
this.title = "修改问答" |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** 提交按钮 */ |
||||
|
submitForm() { |
||||
|
this.$refs["form"].validate(valid => { |
||||
|
if (valid) { |
||||
|
if (this.form.id != null) { |
||||
|
updateQuestions(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("修改成功") |
||||
|
this.open = false |
||||
|
this.getList() |
||||
|
}) |
||||
|
} else { |
||||
|
addQuestions(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("新增成功") |
||||
|
this.open = false |
||||
|
this.getList() |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const ids = row.id || this.ids |
||||
|
this.$modal.confirm('是否确认删除问答编号为"' + ids + '"的数据项?').then(() => { |
||||
|
return delQuestions(ids) |
||||
|
}).then(() => { |
||||
|
this.getList() |
||||
|
this.$modal.msgSuccess("删除成功") |
||||
|
// 如果删除的是当前显示的问题,关闭答案面板 |
||||
|
if (this.currentQuestionId && ids.includes(this.currentQuestionId)) { |
||||
|
this.closeAnswersPanel() |
||||
|
} |
||||
|
}).catch(() => {}) |
||||
|
}, |
||||
|
|
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download('system/questions/export', { |
||||
|
...this.queryParams |
||||
|
}, `questions_${new Date().getTime()}.xlsx`) |
||||
|
}, |
||||
|
|
||||
|
/** 查看选中问题的答案 */ |
||||
|
viewAnswers() { |
||||
|
if (this.single) { |
||||
|
this.$modal.msgWarning('请选择一条问题记录') |
||||
|
return |
||||
|
} |
||||
|
const questionId = this.ids[0] |
||||
|
const selectedQuestion = this.questionsList.find(item => item.id === questionId) |
||||
|
if (selectedQuestion) { |
||||
|
this.toggleAnswersPanel(selectedQuestion) |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** 切换答案面板 */ |
||||
|
toggleAnswersPanel(row) { |
||||
|
if (this.showAnswersPanel && this.currentQuestionId === row.id) { |
||||
|
this.closeAnswersPanel() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
this.currentQuestionId = row.id |
||||
|
this.currentQuestionTitle = row.title |
||||
|
this.currentAnswerCount = row.answerCount || 0 |
||||
|
this.selectedRow = row |
||||
|
this.showAnswersPanel = true |
||||
|
}, |
||||
|
|
||||
|
/** 关闭答案面板 */ |
||||
|
closeAnswersPanel() { |
||||
|
this.showAnswersPanel = false |
||||
|
this.currentQuestionId = null |
||||
|
this.currentQuestionTitle = '' |
||||
|
this.currentAnswerCount = 0 |
||||
|
this.selectedRow = null |
||||
|
}, |
||||
|
|
||||
|
/** 刷新答案数据 */ |
||||
|
refreshAnswers() { |
||||
|
if (this.$refs.answersManagement) { |
||||
|
this.$refs.answersManagement.refresh() |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** 答案管理组件刷新后的回调 */ |
||||
|
handleAnswersRefresh() { |
||||
|
// 刷新当前问题的回答数 |
||||
|
if (this.currentQuestionId) { |
||||
|
// 更新本地数据中的回答数 |
||||
|
const index = this.questionsList.findIndex(item => item.id === this.currentQuestionId) |
||||
|
if (index !== -1) { |
||||
|
// 这里可以调用API重新获取该问题的详情,或者直接递增 |
||||
|
this.questionsList[index].answerCount += 1 |
||||
|
this.currentAnswerCount = this.questionsList[index].answerCount |
||||
|
} |
||||
|
this.$forceUpdate() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.app-container { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.search-area { |
||||
|
padding: 15px; |
||||
|
background: #fff; |
||||
|
border-radius: 4px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.operation-area { |
||||
|
padding: 10px 15px; |
||||
|
background: #fff; |
||||
|
border-radius: 4px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.main-content { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
gap: 10px; |
||||
|
min-height: 0; |
||||
|
} |
||||
|
|
||||
|
.questions-list { |
||||
|
transition: width 0.3s; |
||||
|
background: #fff; |
||||
|
padding: 15px; |
||||
|
border-radius: 4px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.answers-panel { |
||||
|
width: 50%; |
||||
|
background: #fff; |
||||
|
border-radius: 4px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
border-left: 1px solid #ebeef5; |
||||
|
} |
||||
|
|
||||
|
.panel-header { |
||||
|
padding: 15px; |
||||
|
border-bottom: 1px solid #ebeef5; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
background: #f8f9fa; |
||||
|
} |
||||
|
|
||||
|
.panel-title { |
||||
|
font-size: 16px; |
||||
|
font-weight: bold; |
||||
|
color: #303133; |
||||
|
} |
||||
|
|
||||
|
.answer-count { |
||||
|
font-size: 14px; |
||||
|
color: #909399; |
||||
|
margin-left: 8px; |
||||
|
} |
||||
|
|
||||
|
.panel-content { |
||||
|
flex: 1; |
||||
|
overflow: hidden; |
||||
|
padding: 15px; |
||||
|
} |
||||
|
|
||||
|
.title-text { |
||||
|
display: inline-block; |
||||
|
max-width: 150px; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.content-preview { |
||||
|
max-height: 60px; |
||||
|
overflow: hidden; |
||||
|
line-height: 20px; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
.item ::v-deep .el-badge__content { |
||||
|
transform: translateY(-50%) translateX(100%); |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-form-item { |
||||
|
margin-bottom: 18px; |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-table .current-row { |
||||
|
background-color: #f5f7fa !important; |
||||
|
} |
||||
|
</style> |
||||
1547
chenhai-ui/src/views/vet/training/TrainingHome.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1120
chenhai-ui/src/views/vet/training/index.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue