From f0fcb3ab63e05eeee9107085104f47b546c5a5ab Mon Sep 17 00:00:00 2001 From: wangzhibiao Date: Mon, 14 Sep 2026 10:59:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9F=B9=E8=AE=AD=EF=BC=9A?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=AF=BE=E7=A8=8B=E4=B8=BB=E6=95=B0=E6=8D=AE?= =?UTF-8?q?P0=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../train/TrainCourseController.java | 82 ++--- .../com/ruoyi/train/domain/TrainCourse.java | 190 ++++++----- .../ruoyi/train/domain/vo/CourseDetailVO.java | 298 ++++++++++++++++++ .../ruoyi/train/mapper/TrainCourseMapper.java | 32 +- .../train/service/ITrainCourseService.java | 41 ++- .../service/impl/TrainCourseServiceImpl.java | 155 ++++++++- .../mapper/train/TrainCourseMapper.xml | 102 +++--- build_ui/src/api/train/course.js | 12 +- build_ui/src/views/train/course/index.vue | 226 ++++++------- docs/development/issue-01-03-course.md | 195 ++++++++++++ 10 files changed, 1000 insertions(+), 333 deletions(-) create mode 100644 RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/vo/CourseDetailVO.java create mode 100644 docs/development/issue-01-03-course.md diff --git a/RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/web/controller/train/TrainCourseController.java b/RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/web/controller/train/TrainCourseController.java index 0beccbc13..e27f40ccc 100644 --- a/RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/web/controller/train/TrainCourseController.java +++ b/RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/web/controller/train/TrainCourseController.java @@ -1,13 +1,11 @@ package com.ruoyi.web.controller.train; import java.util.List; -import javax.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; @@ -16,16 +14,17 @@ import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.train.domain.TrainCourse; +import com.ruoyi.train.domain.vo.CourseDetailVO; import com.ruoyi.train.service.ITrainCourseService; -import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.core.page.TableDataInfo; /** * 课程信息Controller - * + * * @author ruoyi - * @date 2026-09-08 + * @date 2026-09-14 */ @RestController @RequestMapping("/train/course") @@ -35,9 +34,9 @@ public class TrainCourseController extends BaseController private ITrainCourseService trainCourseService; /** - * 查询课程信息列表 + * 查询课程信息列表 【P0】 */ - @PreAuthorize("@ss.hasPermi('system:course:list')") + @PreAuthorize("@ss.hasPermi('train:course:list')") @GetMapping("/list") public TableDataInfo list(TrainCourse trainCourse) { @@ -47,58 +46,61 @@ public class TrainCourseController extends BaseController } /** - * 导出课程信息列表 + * 获取课程信息详细信息 【P0】 + * 返回结构:CourseDetailVO (包含课程基础字段与契约预留resources列表) */ - @PreAuthorize("@ss.hasPermi('system:course:export')") - @Log(title = "课程信息", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, TrainCourse trainCourse) - { - List list = trainCourseService.selectTrainCourseList(trainCourse); - ExcelUtil util = new ExcelUtil(TrainCourse.class); - util.exportExcel(response, list, "课程信息数据"); - } - - /** - * 获取课程信息详细信息 - */ - @PreAuthorize("@ss.hasPermi('system:course:query')") + @PreAuthorize("@ss.hasPermi('train:course:query')") @GetMapping(value = "/{cId}") public AjaxResult getInfo(@PathVariable("cId") String cId) { - return success(trainCourseService.selectTrainCourseByCId(cId)); + CourseDetailVO detailVO = trainCourseService.selectCourseDetailByCId(cId); + if (detailVO == null) + { + return AjaxResult.error(404, "课程不存在"); + } + return success(detailVO); } /** - * 新增课程信息 + * 新增课程信息 【P0】 */ - @PreAuthorize("@ss.hasPermi('system:course:add')") + @PreAuthorize("@ss.hasPermi('train:course:add')") @Log(title = "课程信息", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody TrainCourse trainCourse) { + if (StringUtils.isEmpty(trainCourse.getcName())) + { + return AjaxResult.error(400, "课程名称不能为空"); + } + if (StringUtils.isNotEmpty(trainCourse.getcCode()) && !trainCourseService.checkCCodeUnique(trainCourse)) + { + return AjaxResult.error(40003, "课程编码已存在"); + } + if (trainCourse.getcDuration() != null && trainCourse.getcDuration() <= 0) + { + return AjaxResult.error(400, "课程学时必须为正整数"); + } return toAjax(trainCourseService.insertTrainCourse(trainCourse)); } /** - * 修改课程信息 + * 修改课程信息 (API Contract 3.4 【P1】: PUT /train/course/{cId}) */ - @PreAuthorize("@ss.hasPermi('system:course:edit')") + @PreAuthorize("@ss.hasPermi('train:course:edit')") @Log(title = "课程信息", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody TrainCourse trainCourse) + @PutMapping("/{cId}") + public AjaxResult edit(@PathVariable("cId") String cId, @RequestBody TrainCourse trainCourse) { + trainCourse.setcId(cId); + if (StringUtils.isNotEmpty(trainCourse.getcCode()) && !trainCourseService.checkCCodeUnique(trainCourse)) + { + return AjaxResult.error(40003, "课程编码已存在"); + } + if (trainCourse.getcDuration() != null && trainCourse.getcDuration() <= 0) + { + return AjaxResult.error(400, "课程学时必须为正整数"); + } return toAjax(trainCourseService.updateTrainCourse(trainCourse)); } - - /** - * 删除课程信息 - */ - @PreAuthorize("@ss.hasPermi('system:course:remove')") - @Log(title = "课程信息", businessType = BusinessType.DELETE) - @DeleteMapping("/{cIds}") - public AjaxResult remove(@PathVariable String[] cIds) - { - return toAjax(trainCourseService.deleteTrainCourseByCIds(cIds)); - } } diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/TrainCourse.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/TrainCourse.java index 08a6c22cf..e2d379227 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/TrainCourse.java +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/TrainCourse.java @@ -2,14 +2,15 @@ package com.ruoyi.train.domain; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonProperty; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; /** * 课程信息对象 train_course - * + * * @author ruoyi - * @date 2026-09-08 + * @date 2026-09-14 */ public class TrainCourse extends BaseEntity { @@ -18,6 +19,10 @@ public class TrainCourse extends BaseEntity /** 课程编号主键 */ private String cId; + /** 课程统一业务编码 */ + @Excel(name = "课程统一业务编码") + private String cCode; + /** 课程名称 */ @Excel(name = "课程名称") private String cName; @@ -26,163 +31,190 @@ public class TrainCourse extends BaseEntity @Excel(name = "课程类型") private String cType; - /** 课程时长 (分钟) */ - @Excel(name = "课程时长 (分钟)") - private Long cDuration; + /** 课程学时 */ + @Excel(name = "课程学时") + private Integer cDuration; /** 教学目标 */ @Excel(name = "教学目标") private String teachingObjective; - /** 课程内容 */ + /** 课程内容/摘要 */ @Excel(name = "课程内容") private String courseContent; - /** 配套文档,多个逗号分隔 */ - @Excel(name = "配套文档,多个逗号分隔") - private String attachDoc; + /** 课程状态 (1:正常, 0:停用) */ + @Excel(name = "课程状态", readConverterExp = "1=正常,0=停用") + private Integer status; - /** 配套视频地址 */ - @Excel(name = "配套视频地址") - private String attachVideo; + /** 删除标志 (0:存在, 2:删除) */ + private String delFlag; - /** 配套模型链接 */ - @Excel(name = "配套模型链接") - private String attachModelLink; - - /** 关联3D设备拆解模型、实训场景资源ID,多ID逗号分隔 */ - @Excel(name = "关联3D设备拆解模型、实训场景资源ID,多ID逗号分隔") - private String modelResourceIds; - - /** 创建人 (管理员 / 教师) */ - @Excel(name = "创建人 (管理员 / 教师)") - private String createUser; - - public void setcId(String cId) + @JsonProperty("cId") + public void setcId(String cId) { this.cId = cId; } - public String getcId() + @JsonProperty("cId") + public String getcId() { return cId; } - public void setcName(String cName) + public void setCId(String cId) + { + this.cId = cId; + } + + public String getCId() + { + return cId; + } + + @JsonProperty("cCode") + public void setcCode(String cCode) + { + this.cCode = cCode; + } + + @JsonProperty("cCode") + public String getcCode() + { + return cCode; + } + + public void setCCode(String cCode) + { + this.cCode = cCode; + } + + public String getCCode() + { + return cCode; + } + + @JsonProperty("cName") + public void setcName(String cName) { this.cName = cName; } - public String getcName() + @JsonProperty("cName") + public String getcName() { return cName; } - public void setcType(String cType) + public void setCName(String cName) + { + this.cName = cName; + } + + public String getCName() + { + return cName; + } + + @JsonProperty("cType") + public void setcType(String cType) { this.cType = cType; } - public String getcType() + @JsonProperty("cType") + public String getcType() { return cType; } - public void setcDuration(Long cDuration) + public void setCType(String cType) + { + this.cType = cType; + } + + public String getCType() + { + return cType; + } + + @JsonProperty("cDuration") + public void setcDuration(Integer cDuration) { this.cDuration = cDuration; } - public Long getcDuration() + @JsonProperty("cDuration") + public Integer getcDuration() { return cDuration; } - public void setTeachingObjective(String teachingObjective) + public void setCDuration(Integer cDuration) + { + this.cDuration = cDuration; + } + + public Integer getCDuration() + { + return cDuration; + } + + public void setTeachingObjective(String teachingObjective) { this.teachingObjective = teachingObjective; } - public String getTeachingObjective() + public String getTeachingObjective() { return teachingObjective; } - public void setCourseContent(String courseContent) + public void setCourseContent(String courseContent) { this.courseContent = courseContent; } - public String getCourseContent() + public String getCourseContent() { return courseContent; } - public void setAttachDoc(String attachDoc) + public void setStatus(Integer status) { - this.attachDoc = attachDoc; + this.status = status; } - public String getAttachDoc() + public Integer getStatus() { - return attachDoc; + return status; } - public void setAttachVideo(String attachVideo) + public void setDelFlag(String delFlag) { - this.attachVideo = attachVideo; + this.delFlag = delFlag; } - public String getAttachVideo() + public String getDelFlag() { - return attachVideo; - } - - public void setAttachModelLink(String attachModelLink) - { - this.attachModelLink = attachModelLink; - } - - public String getAttachModelLink() - { - return attachModelLink; - } - - public void setModelResourceIds(String modelResourceIds) - { - this.modelResourceIds = modelResourceIds; - } - - public String getModelResourceIds() - { - return modelResourceIds; - } - - public void setCreateUser(String createUser) - { - this.createUser = createUser; - } - - public String getCreateUser() - { - return createUser; + return delFlag; } @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) .append("cId", getcId()) + .append("cCode", getcCode()) .append("cName", getcName()) .append("cType", getcType()) .append("cDuration", getcDuration()) .append("teachingObjective", getTeachingObjective()) .append("courseContent", getCourseContent()) - .append("attachDoc", getAttachDoc()) - .append("attachVideo", getAttachVideo()) - .append("attachModelLink", getAttachModelLink()) - .append("modelResourceIds", getModelResourceIds()) - .append("createUser", getCreateUser()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) .append("updateTime", getUpdateTime()) .append("remark", getRemark()) .toString(); diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/vo/CourseDetailVO.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/vo/CourseDetailVO.java new file mode 100644 index 000000000..c6c04d6bf --- /dev/null +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/domain/vo/CourseDetailVO.java @@ -0,0 +1,298 @@ +package com.ruoyi.train.domain.vo; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.ruoyi.train.domain.TrainCourse; + +/** + * 课程详情视图对象 (API Contract: CourseDetailVO) + * 聚合返回课程基础信息及已绑定的教学资源列表 + * + * @author ruoyi + * @date 2026-09-14 + */ +public class CourseDetailVO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 课程编号主键 */ + private String cId; + + /** 课程统一业务编码 */ + private String cCode; + + /** 课程名称 */ + private String cName; + + /** 课程类型 */ + private String cType; + + /** 课程学时 */ + private Integer cDuration; + + /** 教学目标 */ + private String teachingObjective; + + /** 课程内容/摘要 */ + private String courseContent; + + /** 课程状态 (1:正常, 0:停用) */ + private Integer status; + + /** 备注 */ + private String remark; + + /** 创建者 */ + private String createBy; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 更新者 */ + private String updateBy; + + /** 更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** + * 已关联的教学资源列表 + * 注:当前 ISSUE-01-03 未实现真实 Course<->Resource 查询; + * 绑定/解绑及真实关联能力属于 P1。为保证集合字段结构稳定,默认返回空列表 (empty list)。 + */ + private List resources; + + public CourseDetailVO() + { + } + + public static CourseDetailVO from(TrainCourse course) + { + if (course == null) + { + return null; + } + CourseDetailVO vo = new CourseDetailVO(); + vo.setcId(course.getcId()); + vo.setcCode(course.getcCode()); + vo.setcName(course.getcName()); + vo.setcType(course.getcType()); + vo.setcDuration(course.getcDuration()); + vo.setTeachingObjective(course.getTeachingObjective()); + vo.setCourseContent(course.getCourseContent()); + vo.setStatus(course.getStatus()); + vo.setRemark(course.getRemark()); + vo.setCreateBy(course.getCreateBy()); + vo.setCreateTime(course.getCreateTime()); + vo.setUpdateBy(course.getUpdateBy()); + vo.setUpdateTime(course.getUpdateTime()); + // 资源绑定/解绑能力属于 P1,当前返回空列表保持响应结构稳定 + vo.setResources(Collections.emptyList()); + return vo; + } + + @JsonProperty("cId") + public String getcId() + { + return cId; + } + + @JsonProperty("cId") + public void setcId(String cId) + { + this.cId = cId; + } + + public String getCId() + { + return cId; + } + + public void setCId(String cId) + { + this.cId = cId; + } + + @JsonProperty("cCode") + public String getcCode() + { + return cCode; + } + + @JsonProperty("cCode") + public void setcCode(String cCode) + { + this.cCode = cCode; + } + + public String getCCode() + { + return cCode; + } + + public void setCCode(String cCode) + { + this.cCode = cCode; + } + + @JsonProperty("cName") + public String getcName() + { + return cName; + } + + @JsonProperty("cName") + public void setcName(String cName) + { + this.cName = cName; + } + + public String getCName() + { + return cName; + } + + public void setCName(String cName) + { + this.cName = cName; + } + + @JsonProperty("cType") + public String getcType() + { + return cType; + } + + @JsonProperty("cType") + public void setcType(String cType) + { + this.cType = cType; + } + + public String getCType() + { + return cType; + } + + public void setCType(String cType) + { + this.cType = cType; + } + + @JsonProperty("cDuration") + public Integer getcDuration() + { + return cDuration; + } + + @JsonProperty("cDuration") + public void setcDuration(Integer cDuration) + { + this.cDuration = cDuration; + } + + public Integer getCDuration() + { + return cDuration; + } + + public void setCDuration(Integer cDuration) + { + this.cDuration = cDuration; + } + + public String getTeachingObjective() + { + return teachingObjective; + } + + public void setTeachingObjective(String teachingObjective) + { + this.teachingObjective = teachingObjective; + } + + public String getCourseContent() + { + return courseContent; + } + + public void setCourseContent(String courseContent) + { + this.courseContent = courseContent; + } + + public Integer getStatus() + { + return status; + } + + public void setStatus(Integer status) + { + this.status = status; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } + + public String getCreateBy() + { + return createBy; + } + + public void setCreateBy(String createBy) + { + this.createBy = createBy; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public String getUpdateBy() + { + return updateBy; + } + + public void setUpdateBy(String updateBy) + { + this.updateBy = updateBy; + } + + public Date getUpdateTime() + { + return updateTime; + } + + public void setUpdateTime(Date updateTime) + { + this.updateTime = updateTime; + } + + public List getResources() + { + return resources; + } + + public void setResources(List resources) + { + this.resources = resources; + } +} diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/mapper/TrainCourseMapper.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/mapper/TrainCourseMapper.java index 4d941bf04..59dbf0ad1 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/mapper/TrainCourseMapper.java +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/mapper/TrainCourseMapper.java @@ -5,15 +5,15 @@ import com.ruoyi.train.domain.TrainCourse; /** * 课程信息Mapper接口 - * + * * @author ruoyi * @date 2026-09-08 */ -public interface TrainCourseMapper +public interface TrainCourseMapper { /** * 查询课程信息 - * + * * @param cId 课程信息主键 * @return 课程信息 */ @@ -21,7 +21,7 @@ public interface TrainCourseMapper /** * 查询课程信息列表 - * + * * @param trainCourse 课程信息 * @return 课程信息集合 */ @@ -29,7 +29,7 @@ public interface TrainCourseMapper /** * 新增课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @@ -37,7 +37,7 @@ public interface TrainCourseMapper /** * 修改课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @@ -45,15 +45,31 @@ public interface TrainCourseMapper /** * 删除课程信息 - * + * * @param cId 课程信息主键 * @return 结果 */ public int deleteTrainCourseByCId(String cId); + /** + * 校验课程统一业务编码是否唯一 + * + * @param cCode 课程统一业务编码 + * @return 课程信息 + */ + public TrainCourse checkCCodeUnique(String cCode); + + /** + * 根据课程统一业务编码查询课程信息 + * + * @param cCode 课程统一业务编码 + * @return 课程信息 + */ + public TrainCourse selectTrainCourseByCCode(String cCode); + /** * 批量删除课程信息 - * + * * @param cIds 需要删除的数据主键集合 * @return 结果 */ diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/ITrainCourseService.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/ITrainCourseService.java index b5dc4979b..f01ec5893 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/ITrainCourseService.java +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/ITrainCourseService.java @@ -2,18 +2,27 @@ package com.ruoyi.train.service; import java.util.List; import com.ruoyi.train.domain.TrainCourse; +import com.ruoyi.train.domain.vo.CourseDetailVO; /** * 课程信息Service接口 - * + * * @author ruoyi * @date 2026-09-08 */ -public interface ITrainCourseService +public interface ITrainCourseService { + /** + * 查询课程详情视图 (CourseDetailVO) + * + * @param cId 课程信息主键 + * @return 课程详情VO + */ + public CourseDetailVO selectCourseDetailByCId(String cId); + /** * 查询课程信息 - * + * * @param cId 课程信息主键 * @return 课程信息 */ @@ -21,7 +30,7 @@ public interface ITrainCourseService /** * 查询课程信息列表 - * + * * @param trainCourse 课程信息 * @return 课程信息集合 */ @@ -29,7 +38,7 @@ public interface ITrainCourseService /** * 新增课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @@ -37,7 +46,7 @@ public interface ITrainCourseService /** * 修改课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @@ -45,15 +54,31 @@ public interface ITrainCourseService /** * 批量删除课程信息 - * + * * @param cIds 需要删除的课程信息主键集合 * @return 结果 */ public int deleteTrainCourseByCIds(String[] cIds); + /** + * 校验课程统一业务编码是否唯一 + * + * @param trainCourse 课程信息 + * @return 结果 + */ + public boolean checkCCodeUnique(TrainCourse trainCourse); + + /** + * 根据课程统一业务编码查询课程信息 + * + * @param cCode 课程统一业务编码 + * @return 课程信息 + */ + public TrainCourse selectTrainCourseByCCode(String cCode); + /** * 删除课程信息信息 - * + * * @param cId 课程信息主键 * @return 结果 */ diff --git a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/TrainCourseServiceImpl.java b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/TrainCourseServiceImpl.java index d8c9c32f6..dc4622212 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/TrainCourseServiceImpl.java +++ b/RuoYi-Vue/ruoyi-train/src/main/java/com/ruoyi/train/service/impl/TrainCourseServiceImpl.java @@ -1,28 +1,46 @@ package com.ruoyi.train.service.impl; import java.util.List; -import com.ruoyi.common.utils.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.train.mapper.TrainCourseMapper; import com.ruoyi.train.domain.TrainCourse; +import com.ruoyi.train.domain.vo.CourseDetailVO; import com.ruoyi.train.service.ITrainCourseService; /** * 课程信息Service业务层处理 - * + * * @author ruoyi - * @date 2026-09-08 + * @date 2026-09-14 */ @Service -public class TrainCourseServiceImpl implements ITrainCourseService +public class TrainCourseServiceImpl implements ITrainCourseService { @Autowired private TrainCourseMapper trainCourseMapper; + /** + * 查询课程详情视图 (CourseDetailVO) + * + * @param cId 课程信息主键 + * @return 课程详情VO + */ + @Override + public CourseDetailVO selectCourseDetailByCId(String cId) + { + TrainCourse course = trainCourseMapper.selectTrainCourseByCId(cId); + return CourseDetailVO.from(course); + } + /** * 查询课程信息 - * + * * @param cId 课程信息主键 * @return 课程信息 */ @@ -34,7 +52,7 @@ public class TrainCourseServiceImpl implements ITrainCourseService /** * 查询课程信息列表 - * + * * @param trainCourse 课程信息 * @return 课程信息 */ @@ -46,33 +64,150 @@ public class TrainCourseServiceImpl implements ITrainCourseService /** * 新增课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @Override public int insertTrainCourse(TrainCourse trainCourse) { + // 1. 课程名称校验 + if (StringUtils.isEmpty(trainCourse.getcName())) + { + throw new ServiceException("课程名称不能为空", 400); + } + if (trainCourse.getcName().length() > 100) + { + throw new ServiceException("课程名称长度不能超过100个字符", 400); + } + + // 2. 课程统一编码唯一性校验 + if (StringUtils.isNotEmpty(trainCourse.getcCode())) + { + if (trainCourse.getcCode().length() > 50) + { + throw new ServiceException("课程编码长度不能超过50个字符", 400); + } + if (!checkCCodeUnique(trainCourse)) + { + throw new ServiceException("课程编码已存在", 40003); + } + } + + // 3. 课程学时正整数校验 + if (trainCourse.getcDuration() != null && trainCourse.getcDuration() <= 0) + { + throw new ServiceException("课程学时必须为正整数", 400); + } + + // 4. 生成 32 位无短横线 UUID 主键 + if (StringUtils.isEmpty(trainCourse.getcId())) + { + trainCourse.setcId(IdUtils.fastSimpleUUID()); + } + + // 5. 初始默认状态与逻辑删除标志 + if (trainCourse.getStatus() == null) + { + trainCourse.setStatus(1); + } + trainCourse.setDelFlag("0"); trainCourse.setCreateTime(DateUtils.getNowDate()); + + try + { + trainCourse.setCreateBy(SecurityUtils.getUsername()); + } + catch (Exception e) + { + // 兜底处理 (如无上下文或测试环境) + } + return trainCourseMapper.insertTrainCourse(trainCourse); } /** * 修改课程信息 - * + * * @param trainCourse 课程信息 * @return 结果 */ @Override public int updateTrainCourse(TrainCourse trainCourse) { + // 1. 课程名称校验 + if (StringUtils.isNotEmpty(trainCourse.getcName()) && trainCourse.getcName().length() > 100) + { + throw new ServiceException("课程名称长度不能超过100个字符", 400); + } + + // 2. 课程统一编码唯一性校验 + if (StringUtils.isNotEmpty(trainCourse.getcCode())) + { + if (trainCourse.getcCode().length() > 50) + { + throw new ServiceException("课程编码长度不能超过50个字符", 400); + } + if (!checkCCodeUnique(trainCourse)) + { + throw new ServiceException("课程编码已存在", 40003); + } + } + + // 3. 课程学时正整数校验 + if (trainCourse.getcDuration() != null && trainCourse.getcDuration() <= 0) + { + throw new ServiceException("课程学时必须为正整数", 400); + } + trainCourse.setUpdateTime(DateUtils.getNowDate()); + try + { + trainCourse.setUpdateBy(SecurityUtils.getUsername()); + } + catch (Exception e) + { + // 兜底处理 + } return trainCourseMapper.updateTrainCourse(trainCourse); } + /** + * 校验课程统一业务编码是否唯一 + * + * @param trainCourse 课程信息 + * @return 结果 (true: 唯一可用, false: 已存在重复) + */ + @Override + public boolean checkCCodeUnique(TrainCourse trainCourse) + { + if (StringUtils.isEmpty(trainCourse.getcCode())) + { + return true; + } + TrainCourse info = trainCourseMapper.checkCCodeUnique(trainCourse.getcCode()); + if (info != null && (StringUtils.isEmpty(trainCourse.getcId()) || !info.getcId().equals(trainCourse.getcId()))) + { + return false; + } + return true; + } + + /** + * 根据课程统一业务编码查询课程信息 + * + * @param cCode 课程统一业务编码 + * @return 课程信息 + */ + @Override + public TrainCourse selectTrainCourseByCCode(String cCode) + { + return trainCourseMapper.selectTrainCourseByCCode(cCode); + } + /** * 批量删除课程信息 - * + * * @param cIds 需要删除的课程信息主键 * @return 结果 */ @@ -84,7 +219,7 @@ public class TrainCourseServiceImpl implements ITrainCourseService /** * 删除课程信息信息 - * + * * @param cId 课程信息主键 * @return 结果 */ diff --git a/RuoYi-Vue/ruoyi-train/src/main/resources/mapper/train/TrainCourseMapper.xml b/RuoYi-Vue/ruoyi-train/src/main/resources/mapper/train/TrainCourseMapper.xml index cd789806a..5a0db4dce 100644 --- a/RuoYi-Vue/ruoyi-train/src/main/resources/mapper/train/TrainCourseMapper.xml +++ b/RuoYi-Vue/ruoyi-train/src/main/resources/mapper/train/TrainCourseMapper.xml @@ -3,99 +3,103 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + + - - - - - + + + + - select c_id, c_name, c_type, c_duration, teaching_objective, course_content, attach_doc, attach_video, attach_model_link, model_resource_ids, create_user, create_time, update_time, remark from train_course + select c_id, c_code, c_name, c_type, c_duration, teaching_objective, course_content, status, del_flag, create_by, create_time, update_by, update_time, remark from train_course - + + + + + insert into train_course - c_id, + c_id, + c_code, c_name, - c_type, + c_type, c_duration, - teaching_objective, - course_content, - attach_doc, - attach_video, - attach_model_link, - model_resource_ids, - create_user, + teaching_objective, + course_content, + status, + del_flag, + create_by, create_time, + update_by, update_time, - remark, + remark, - #{cId}, + #{cId}, + #{cCode}, #{cName}, - #{cType}, + #{cType}, #{cDuration}, - #{teachingObjective}, - #{courseContent}, - #{attachDoc}, - #{attachVideo}, - #{attachModelLink}, - #{modelResourceIds}, - #{createUser}, + #{teachingObjective}, + #{courseContent}, + #{status}, + #{delFlag}, + #{createBy}, #{createTime}, + #{updateBy}, #{updateTime}, - #{remark}, + #{remark}, update train_course + c_code = #{cCode}, c_name = #{cName}, c_type = #{cType}, c_duration = #{cDuration}, teaching_objective = #{teachingObjective}, course_content = #{courseContent}, - attach_doc = #{attachDoc}, - attach_video = #{attachVideo}, - attach_model_link = #{attachModelLink}, - model_resource_ids = #{modelResourceIds}, - create_user = #{createUser}, - create_time = #{createTime}, + status = #{status}, + update_by = #{updateBy}, update_time = #{updateTime}, remark = #{remark}, @@ -103,13 +107,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - delete from train_course where c_id = #{cId} + update train_course set del_flag = '2' where c_id = #{cId} - delete from train_course where c_id in + update train_course set del_flag = '2' where c_id in #{cId} - \ No newline at end of file + diff --git a/build_ui/src/api/train/course.js b/build_ui/src/api/train/course.js index 593fa3670..11b422c17 100644 --- a/build_ui/src/api/train/course.js +++ b/build_ui/src/api/train/course.js @@ -26,19 +26,11 @@ export function addCourse(data) { }) } -// 修改课程信息 +// 修改课程信息 (API Contract 3.4: PUT /train/course/{cId}) export function updateCourse(data) { return request({ - url: '/train/course', + url: '/train/course/' + data.cId, method: 'put', data: data }) } - -// 删除课程信息 -export function delCourse(cId) { - return request({ - url: '/train/course/' + cId, - method: 'delete' - }) -} diff --git a/build_ui/src/views/train/course/index.vue b/build_ui/src/views/train/course/index.vue index 61880c578..f353dd1cc 100644 --- a/build_ui/src/views/train/course/index.vue +++ b/build_ui/src/views/train/course/index.vue @@ -1,6 +1,14 @@