优化集成:实现课程资源关系表权威存储与旧字段兼容修复

This commit is contained in:
wangzhibiao committed 2026-10-09 21:49:54 +08:00
1 parent 9030d797f4
commit 353bfcd3fa
6 files changed
+54 -10

No files matched your search

@@ -94,6 +94,10 @@ train:
identity: identity:
encryption-key: ${TRAIN_STUDENT_IDENTITY_ENCRYPTION_KEY:} encryption-key: ${TRAIN_STUDENT_IDENTITY_ENCRYPTION_KEY:}
hash-key: ${TRAIN_STUDENT_IDENTITY_HASH_KEY:} hash-key: ${TRAIN_STUDENT_IDENTITY_HASH_KEY:}
mock:
device:
# 模拟设备打卡接口开关 (生产环境与公共配置必须默认关闭,仅允许在测试环境显式开启)
enabled: ${TRAIN_MOCK_DEVICE_ENABLED:false}
# token配置 # token配置
token: token:
@@ -142,10 +146,3 @@ xss:
# 匹配链接 # 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/* urlPatterns: /system/*,/monitor/*,/tool/*
# 培训业务配置
train:
mock:
device:
# 模拟设备打卡接口开关 (生产环境与公共配置必须默认关闭,仅允许在测试环境显式开启)
enabled: false
@@ -43,6 +43,10 @@ public class TrainCourse extends BaseEntity
@Excel(name = "课程内容") @Excel(name = "课程内容")
private String courseContent; private String courseContent;
/** 关联教学资源ID (历史兼容字段,新系统权威关联存储为 train_course_resource) */
@Excel(name = "课程资源ID")
private String resourceId;
/** 课程状态 (1:正常, 0:停用) */ /** 课程状态 (1:正常, 0:停用) */
@Excel(name = "课程状态", readConverterExp = "1=正常,0=停用") @Excel(name = "课程状态", readConverterExp = "1=正常,0=停用")
private Integer status; private Integer status;
@@ -180,6 +184,16 @@ public class TrainCourse extends BaseEntity
return courseContent; return courseContent;
} }
public void setResourceId(String resourceId)
{
this.resourceId = resourceId;
}
public String getResourceId()
{
return resourceId;
}
public void setStatus(Integer status) public void setStatus(Integer status)
{ {
this.status = status; this.status = status;
@@ -210,6 +224,7 @@ public class TrainCourse extends BaseEntity
.append("cDuration", getcDuration()) .append("cDuration", getcDuration())
.append("teachingObjective", getTeachingObjective()) .append("teachingObjective", getTeachingObjective())
.append("courseContent", getCourseContent()) .append("courseContent", getCourseContent())
.append("resourceId", getResourceId())
.append("status", getStatus()) .append("status", getStatus())
.append("delFlag", getDelFlag()) .append("delFlag", getDelFlag())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
@@ -60,6 +60,9 @@ public class CourseDetailVO implements Serializable
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime; private Date updateTime;
/** 关联教学资源ID (兼容旧接口,优先使用关系表首个资源ID) */
private String resourceId;
/** /**
* 已关联的教学资源列表 * 已关联的教学资源列表
*/ */
@@ -89,6 +92,7 @@ public class CourseDetailVO implements Serializable
vo.setCreateTime(course.getCreateTime()); vo.setCreateTime(course.getCreateTime());
vo.setUpdateBy(course.getUpdateBy()); vo.setUpdateBy(course.getUpdateBy());
vo.setUpdateTime(course.getUpdateTime()); vo.setUpdateTime(course.getUpdateTime());
vo.setResourceId(course.getResourceId());
return vo; return vo;
} }
@@ -282,6 +286,16 @@ public class CourseDetailVO implements Serializable
this.updateTime = updateTime; this.updateTime = updateTime;
} }
public String getResourceId()
{
return resourceId;
}
public void setResourceId(String resourceId)
{
this.resourceId = resourceId;
}
public List<TrainResource> getResources() public List<TrainResource> getResources()
{ {
return resources; return resources;
@@ -12,6 +12,7 @@ import com.ruoyi.train.mapper.TrainCourseMapper;
import com.ruoyi.train.mapper.TrainCourseResourceMapper; import com.ruoyi.train.mapper.TrainCourseResourceMapper;
import com.ruoyi.train.mapper.TrainPlanCourseMapper; import com.ruoyi.train.mapper.TrainPlanCourseMapper;
import com.ruoyi.train.domain.TrainCourse; import com.ruoyi.train.domain.TrainCourse;
import com.ruoyi.train.domain.TrainResource;
import com.ruoyi.train.domain.vo.CourseDetailVO; import com.ruoyi.train.domain.vo.CourseDetailVO;
import com.ruoyi.train.service.ITrainCourseService; import com.ruoyi.train.service.ITrainCourseService;
@@ -46,7 +47,14 @@ public class TrainCourseServiceImpl implements ITrainCourseService
CourseDetailVO detail = CourseDetailVO.from(course); CourseDetailVO detail = CourseDetailVO.from(course);
if (detail != null) if (detail != null)
{ {
detail.setResources(trainCourseResourceMapper.selectResourcesByCourseId(cId)); List<TrainResource> resources = trainCourseResourceMapper.selectResourcesByCourseId(cId);
detail.setResources(resources);
// 规范权威读取:优先以 train_course_resource 规范关联表首个资源派生兼容 resourceId;
// 若关系表暂无关联但实体存在历史 resourceId,则保留历史 resourceId
if (resources != null && !resources.isEmpty())
{
detail.setResourceId(resources.get(0).getResourceId());
}
} }
return detail; return detail;
} }
@@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="cDuration" column="c_duration" /> <result property="cDuration" column="c_duration" />
<result property="teachingObjective" column="teaching_objective" /> <result property="teachingObjective" column="teaching_objective" />
<result property="courseContent" column="course_content" /> <result property="courseContent" column="course_content" />
<result property="resourceId" column="resource_id" />
<result property="status" column="status" /> <result property="status" column="status" />
<result property="delFlag" column="del_flag" /> <result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" /> <result property="createBy" column="create_by" />
@@ -22,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectTrainCourseVo"> <sql id="selectTrainCourseVo">
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 select c_id, c_code, c_name, c_type, c_duration, teaching_objective, course_content, resource_id, status, del_flag, create_by, create_time, update_by, update_time, remark from train_course
</sql> </sql>
<select id="selectTrainCourseList" parameterType="TrainCourse" resultMap="TrainCourseResult"> <select id="selectTrainCourseList" parameterType="TrainCourse" resultMap="TrainCourseResult">
@@ -63,6 +64,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="cDuration != null">c_duration,</if> <if test="cDuration != null">c_duration,</if>
<if test="teachingObjective != null and teachingObjective != ''">teaching_objective,</if> <if test="teachingObjective != null and teachingObjective != ''">teaching_objective,</if>
<if test="courseContent != null and courseContent != ''">course_content,</if> <if test="courseContent != null and courseContent != ''">course_content,</if>
<if test="resourceId != null and resourceId != ''">resource_id,</if>
<if test="status != null">status,</if> <if test="status != null">status,</if>
<if test="delFlag != null and delFlag != ''">del_flag,</if> <if test="delFlag != null and delFlag != ''">del_flag,</if>
<if test="createBy != null and createBy != ''">create_by,</if> <if test="createBy != null and createBy != ''">create_by,</if>
@@ -79,6 +81,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="cDuration != null">#{cDuration},</if> <if test="cDuration != null">#{cDuration},</if>
<if test="teachingObjective != null and teachingObjective != ''">#{teachingObjective},</if> <if test="teachingObjective != null and teachingObjective != ''">#{teachingObjective},</if>
<if test="courseContent != null and courseContent != ''">#{courseContent},</if> <if test="courseContent != null and courseContent != ''">#{courseContent},</if>
<if test="resourceId != null and resourceId != ''">#{resourceId},</if>
<if test="status != null">#{status},</if> <if test="status != null">#{status},</if>
<if test="delFlag != null and delFlag != ''">#{delFlag},</if> <if test="delFlag != null and delFlag != ''">#{delFlag},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if> <if test="createBy != null and createBy != ''">#{createBy},</if>
@@ -98,6 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="cDuration != null">c_duration = #{cDuration},</if> <if test="cDuration != null">c_duration = #{cDuration},</if>
<if test="teachingObjective != null">teaching_objective = #{teachingObjective},</if> <if test="teachingObjective != null">teaching_objective = #{teachingObjective},</if>
<if test="courseContent != null">course_content = #{courseContent},</if> <if test="courseContent != null">course_content = #{courseContent},</if>
<if test="resourceId != null">resource_id = #{resourceId},</if>
<if test="status != null">status = #{status},</if> <if test="status != null">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if> <if test="updateTime != null">update_time = #{updateTime},</if>
@@ -51,7 +51,7 @@ END $$;
-- 步骤 3: 幂等迁移历史 train_course.resource_id 字段数据 -- 步骤 3: 幂等迁移历史 train_course.resource_id 字段数据
-- 仅当 train_course.resource_id 非空且关联在 train_resource 中有效(del_flag='0')时迁移, -- 仅当 train_course.resource_id 非空且关联在 train_resource 中有效(del_flag='0')时迁移,
-- 且 ON CONFLICT (c_id, resource_id) DO NOTHING 避免覆盖已存在的关联,亦不破坏已解绑关系。 -- 且具有重复部署防恢复机制:一旦完成迁移,不会在重复部署时重新恢复用户已解绑的资源关系。
DO $$ DO $$
BEGIN BEGIN
IF EXISTS ( IF EXISTS (
@@ -59,6 +59,8 @@ BEGIN
WHERE table_schema = 'public' WHERE table_schema = 'public'
AND table_name = 'train_course' AND table_name = 'train_course'
AND column_name = 'resource_id' AND column_name = 'resource_id'
) AND NOT EXISTS (
SELECT 1 FROM public.train_course_resource WHERE create_by = 'migration_012'
) THEN ) THEN
INSERT INTO public.train_course_resource INSERT INTO public.train_course_resource
(c_id, resource_id, sort_no, create_by, create_time) (c_id, resource_id, sort_no, create_by, create_time)
@@ -82,6 +84,10 @@ BEGIN
AND r.del_flag = '0' AND r.del_flag = '0'
WHERE legacy.resource_id <> '' WHERE legacy.resource_id <> ''
ON CONFLICT (c_id, resource_id) DO NOTHING; ON CONFLICT (c_id, resource_id) DO NOTHING;
-- 历史关联已安全迁移至 train_course_resource 规范关系表,清空旧有历史字符串以防解绑后重复恢复,
-- 物理字段 resource_id 依然保留在 train_course 表中,满足旧系统只读与字段兼容契约。
UPDATE public.train_course SET resource_id = NULL WHERE resource_id IS NOT NULL;
END IF; END IF;
END $$; END $$;