修复培训:修复Wave2浏览器验收阻断问题
This commit is contained in:
1 parent
20694559d7
commit
06c077c023
10 files changed
+255
-7
No files matched your search
+4
@@ -6,6 +6,7 @@ import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 排课冲突预检请求 DTO (UC-10)。
|
||||
@@ -29,6 +30,7 @@ public class LessonConflictCheckDTO implements Serializable
|
||||
/** 授课教师工号/标识 */
|
||||
@NotBlank(message = "授课教师工号/标识不能为空")
|
||||
@Size(max = 32, message = "教师工号长度不能超过32个字符")
|
||||
@JsonProperty("tId")
|
||||
private String tId;
|
||||
|
||||
/** 课次开始时间 */
|
||||
@@ -83,11 +85,13 @@ public class LessonConflictCheckDTO implements Serializable
|
||||
this.planCourseId = planCourseId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public String getTId()
|
||||
{
|
||||
return tId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public void setTId(String tId)
|
||||
{
|
||||
this.tId = tId;
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 新增课次请求 DTO (UC-07)。
|
||||
@@ -23,6 +24,7 @@ public class LessonCreateDTO implements Serializable
|
||||
/** 授课教师工号/标识 */
|
||||
@NotBlank(message = "授课教师工号/标识不能为空")
|
||||
@Size(max = 32, message = "教师工号长度不能超过32个字符")
|
||||
@JsonProperty("tId")
|
||||
private String tId;
|
||||
|
||||
/** 课次开始时间 */
|
||||
@@ -61,11 +63,13 @@ public class LessonCreateDTO implements Serializable
|
||||
this.planCourseId = planCourseId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public String getTId()
|
||||
{
|
||||
return tId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public void setTId(String tId)
|
||||
{
|
||||
this.tId = tId;
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 修改课次请求 DTO (UC-08)。
|
||||
@@ -23,6 +24,7 @@ public class LessonUpdateDTO implements Serializable
|
||||
/** 授课教师工号/标识 */
|
||||
@NotBlank(message = "授课教师工号/标识不能为空")
|
||||
@Size(max = 32, message = "教师工号长度不能超过32个字符")
|
||||
@JsonProperty("tId")
|
||||
private String tId;
|
||||
|
||||
/** 课次开始时间 */
|
||||
@@ -61,11 +63,13 @@ public class LessonUpdateDTO implements Serializable
|
||||
this.planCourseId = planCourseId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public String getTId()
|
||||
{
|
||||
return tId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public void setTId(String tId)
|
||||
{
|
||||
this.tId = tId;
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.train.domain.vo;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 本期已配置课程视图 VO。
|
||||
@@ -18,18 +19,23 @@ public class PlanCourseItemVO implements Serializable
|
||||
private String planId;
|
||||
|
||||
/** 课程ID */
|
||||
@JsonProperty("cId")
|
||||
private String cId;
|
||||
|
||||
/** 课程业务编码 */
|
||||
@JsonProperty("cCode")
|
||||
private String cCode;
|
||||
|
||||
/** 课程名称 */
|
||||
@JsonProperty("cName")
|
||||
private String cName;
|
||||
|
||||
/** 课程类型 */
|
||||
@JsonProperty("cType")
|
||||
private String cType;
|
||||
|
||||
/** 课程学时 */
|
||||
@JsonProperty("cDuration")
|
||||
private Integer cDuration;
|
||||
|
||||
/** 教学目标 */
|
||||
@@ -65,51 +71,61 @@ public class PlanCourseItemVO implements Serializable
|
||||
this.planId = planId;
|
||||
}
|
||||
|
||||
@JsonProperty("cId")
|
||||
public String getCId()
|
||||
{
|
||||
return cId;
|
||||
}
|
||||
|
||||
@JsonProperty("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;
|
||||
}
|
||||
|
||||
@JsonProperty("cName")
|
||||
public String getCName()
|
||||
{
|
||||
return cName;
|
||||
}
|
||||
|
||||
@JsonProperty("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;
|
||||
}
|
||||
|
||||
@JsonProperty("cDuration")
|
||||
public Integer getCDuration()
|
||||
{
|
||||
return cDuration;
|
||||
}
|
||||
|
||||
@JsonProperty("cDuration")
|
||||
public void setCDuration(Integer cDuration)
|
||||
{
|
||||
this.cDuration = cDuration;
|
||||
|
||||
+4
@@ -3,6 +3,7 @@ package com.ruoyi.train.domain.vo;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 计划课表课次明细项 VO (API Contract 1.2 / CG-02 / 回显表单必需)。
|
||||
@@ -23,6 +24,7 @@ public class TimetableLessonItemVO implements Serializable
|
||||
private String courseName;
|
||||
|
||||
/** 授课教师工号/标识 (回显表单必需) */
|
||||
@JsonProperty("tId")
|
||||
private String tId;
|
||||
|
||||
/** 授课教师姓名 */
|
||||
@@ -90,11 +92,13 @@ public class TimetableLessonItemVO implements Serializable
|
||||
this.courseName = courseName;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public String getTId()
|
||||
{
|
||||
return tId;
|
||||
}
|
||||
|
||||
@JsonProperty("tId")
|
||||
public void setTId(String tId)
|
||||
{
|
||||
this.tId = tId;
|
||||
|
||||
+3
-3
@@ -150,9 +150,9 @@ public class EnrollmentAppServiceImpl implements EnrollmentAppService
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 校验学员档案有效性
|
||||
// 4. 校验学员档案有效性 (严格要求 1:正常, 0:停用, null:无效)
|
||||
TrainStudent student = studentMapper.selectTrainStudentBySId(dto.getStudentId());
|
||||
if (student == null || "2".equals(student.getDelFlag()) || (student.getStatus() != null && student.getStatus() != 0))
|
||||
if (student == null || "2".equals(student.getDelFlag()) || !Integer.valueOf(1).equals(student.getStatus()))
|
||||
{
|
||||
throw new ServiceException(StudentErrorCode.STUDENT_NOT_FOUND_MESSAGE, StudentErrorCode.STUDENT_NOT_FOUND);
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class EnrollmentAppServiceImpl implements EnrollmentAppService
|
||||
student.setsName(StringUtils.isNotEmpty(dto.getRemark()) ? dto.getRemark() : "导入学员_" + dto.getStudentId());
|
||||
student.setOrgName(dto.getOrgName());
|
||||
student.setSourceType(2); // 2:Excel批量导入
|
||||
student.setStatus(0);
|
||||
student.setStatus(1); // 1:正常
|
||||
student.setDelFlag("0");
|
||||
student.setCreateBy(operator);
|
||||
student.setCreateTime(DateUtils.getNowDate());
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.ruoyi.train.domain.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.train.domain.vo.TimetableLessonItemVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* 验证排课调度相关 DTO/VO 的 tId 属性在 Jackson 序列化/反序列化时的 Contract 绑定。
|
||||
*/
|
||||
public class SchedulingDtoJsonBindingTest
|
||||
{
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessonCreateDtoTIdBinding() throws Exception
|
||||
{
|
||||
String json = "{\"planCourseId\":101,\"tId\":\"T2026001\",\"startTime\":\"2026-09-15 09:00:00\",\"endTime\":\"2026-09-15 11:30:00\",\"venueType\":1,\"classRoomId\":\"CR-101\"}";
|
||||
LessonCreateDTO dto = objectMapper.readValue(json, LessonCreateDTO.class);
|
||||
assertNotNull("DTO should not be null", dto);
|
||||
assertEquals("tId must be correctly bound from JSON 'tId'", "T2026001", dto.getTId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessonUpdateDtoTIdBinding() throws Exception
|
||||
{
|
||||
String json = "{\"planCourseId\":102,\"tId\":\"T2026002\",\"startTime\":\"2026-09-15 14:00:00\",\"endTime\":\"2026-09-15 16:30:00\",\"venueType\":2,\"siteId\":\"SITE-01\"}";
|
||||
LessonUpdateDTO dto = objectMapper.readValue(json, LessonUpdateDTO.class);
|
||||
assertNotNull("DTO should not be null", dto);
|
||||
assertEquals("tId must be correctly bound from JSON 'tId'", "T2026002", dto.getTId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLessonConflictCheckDtoTIdBinding() throws Exception
|
||||
{
|
||||
String json = "{\"planId\":\"PLAN-2026-001\",\"planCourseId\":101,\"tId\":\"T2026003\",\"startTime\":\"2026-09-15 09:00:00\",\"endTime\":\"2026-09-15 11:30:00\",\"venueType\":1,\"classRoomId\":\"CR-101\"}";
|
||||
LessonConflictCheckDTO dto = objectMapper.readValue(json, LessonConflictCheckDTO.class);
|
||||
assertNotNull("DTO should not be null", dto);
|
||||
assertEquals("tId must be correctly bound from JSON 'tId'", "T2026003", dto.getTId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimetableLessonItemVoTIdSerializationAndBinding() throws Exception
|
||||
{
|
||||
TimetableLessonItemVO vo = new TimetableLessonItemVO();
|
||||
vo.setLessonId(1L);
|
||||
vo.setPlanCourseId(101L);
|
||||
vo.setCourseName("高速铁路信号基础");
|
||||
vo.setTId("T2026004");
|
||||
vo.setTeacherName("张讲师");
|
||||
|
||||
String json = objectMapper.writeValueAsString(vo);
|
||||
JsonNode jsonNode = objectMapper.readTree(json);
|
||||
|
||||
assertTrue("Serialized JSON must contain field 'tId'", jsonNode.has("tId"));
|
||||
assertEquals("tId field in JSON must match", "T2026004", jsonNode.get("tId").asText());
|
||||
|
||||
TimetableLessonItemVO deserialized = objectMapper.readValue(json, TimetableLessonItemVO.class);
|
||||
assertEquals("Deserialized VO must preserve tId", "T2026004", deserialized.getTId());
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.ruoyi.train.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* 验证 PlanCourseItemVO 字段命名及其在 Jackson 序列化与反序列化下的稳定性。
|
||||
*/
|
||||
public class PlanCourseItemVOTest
|
||||
{
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlanCourseItemVoSerialization() throws Exception
|
||||
{
|
||||
PlanCourseItemVO vo = new PlanCourseItemVO();
|
||||
vo.setPlanCourseId(1001L);
|
||||
vo.setPlanId("PLAN-2026-001");
|
||||
vo.setCId("C-101");
|
||||
vo.setCCode("TR-001");
|
||||
vo.setCName("高速铁路信号基础");
|
||||
vo.setCType("专业课");
|
||||
vo.setCDuration(16);
|
||||
vo.setSortNo(1);
|
||||
vo.setRemark("重点必修");
|
||||
|
||||
String json = objectMapper.writeValueAsString(vo);
|
||||
JsonNode node = objectMapper.readTree(json);
|
||||
|
||||
assertTrue("JSON must contain 'cId'", node.has("cId"));
|
||||
assertEquals("C-101", node.get("cId").asText());
|
||||
|
||||
assertTrue("JSON must contain 'cCode'", node.has("cCode"));
|
||||
assertEquals("TR-001", node.get("cCode").asText());
|
||||
|
||||
assertTrue("JSON must contain 'cName'", node.has("cName"));
|
||||
assertEquals("高速铁路信号基础", node.get("cName").asText());
|
||||
|
||||
assertTrue("JSON must contain 'cType'", node.has("cType"));
|
||||
assertEquals("专业课", node.get("cType").asText());
|
||||
|
||||
assertTrue("JSON must contain 'cDuration'", node.has("cDuration"));
|
||||
assertEquals(16, node.get("cDuration").asInt());
|
||||
|
||||
assertTrue("JSON must contain 'sortNo'", node.has("sortNo"));
|
||||
assertEquals(1, node.get("sortNo").asInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlanCourseItemVoDeserialization() throws Exception
|
||||
{
|
||||
String json = "{\"planCourseId\":1002,\"planId\":\"PLAN-2026-002\",\"cId\":\"C-102\",\"cCode\":\"TR-002\",\"cName\":\"列车运行控制系统\",\"cType\":\"实训课\",\"cDuration\":24,\"sortNo\":2}";
|
||||
PlanCourseItemVO vo = objectMapper.readValue(json, PlanCourseItemVO.class);
|
||||
|
||||
assertNotNull(vo);
|
||||
assertEquals(Long.valueOf(1002L), vo.getPlanCourseId());
|
||||
assertEquals("PLAN-2026-002", vo.getPlanId());
|
||||
assertEquals("C-102", vo.getCId());
|
||||
assertEquals("TR-002", vo.getCCode());
|
||||
assertEquals("列车运行控制系统", vo.getCName());
|
||||
assertEquals("实训课", vo.getCType());
|
||||
assertEquals(Integer.valueOf(24), vo.getCDuration());
|
||||
assertEquals(Integer.valueOf(2), vo.getSortNo());
|
||||
}
|
||||
}
|
||||
+70
-3
@@ -107,7 +107,7 @@ public class EnrollmentAppServiceImplTest
|
||||
s1.setOrgName("沈阳电务段");
|
||||
s1.setsPhone("13800000001");
|
||||
s1.setIdCardLast4("1234");
|
||||
s1.setStatus(0);
|
||||
s1.setStatus(1);
|
||||
s1.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S001", s1);
|
||||
|
||||
@@ -118,7 +118,7 @@ public class EnrollmentAppServiceImplTest
|
||||
s2.setOrgName("大连电务段");
|
||||
s2.setsPhone("13800000002");
|
||||
s2.setIdCardLast4("5678");
|
||||
s2.setStatus(0);
|
||||
s2.setStatus(1);
|
||||
s2.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S002", s2);
|
||||
|
||||
@@ -129,7 +129,7 @@ public class EnrollmentAppServiceImplTest
|
||||
s3.setOrgName("锦州电务段");
|
||||
s3.setsPhone("13800000003");
|
||||
s3.setIdCardLast4("9012");
|
||||
s3.setStatus(0);
|
||||
s3.setStatus(1);
|
||||
s3.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S003", s3);
|
||||
}
|
||||
@@ -260,6 +260,73 @@ public class EnrollmentAppServiceImplTest
|
||||
() -> appService.addEnrollment("PLAN-001", dto, "admin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNormalStudentEnrollmentSuccess()
|
||||
{
|
||||
// 1. 创建一个按正式流程得到的正常学员 (status=1)
|
||||
TrainStudent normalStudent = new TrainStudent();
|
||||
normalStudent.setsId("S_NORMAL_01");
|
||||
normalStudent.setsName("赵六");
|
||||
normalStudent.setStatus(1); // 正常
|
||||
normalStudent.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S_NORMAL_01", normalStudent);
|
||||
|
||||
// 2. 添加到 Enrollment
|
||||
EnrollmentAddDTO dto = new EnrollmentAddDTO();
|
||||
dto.setStudentId("S_NORMAL_01");
|
||||
dto.setSourceType(1);
|
||||
dto.setAccommodationRequired(0);
|
||||
Long id = appService.addEnrollment("PLAN-001", dto, "admin");
|
||||
|
||||
// 3. 必须成功
|
||||
assertNotNull(id);
|
||||
TrainEnrollment enrollment = enrollmentRepository.selectTrainEnrollmentById(id);
|
||||
assertNotNull(enrollment);
|
||||
assertEquals(Integer.valueOf(0), enrollment.getEnrollmentStatus()); // 待报到
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDisabledStudentEnrollmentRejected()
|
||||
{
|
||||
// 1. 创建一个停用学员 (status=0)
|
||||
TrainStudent disabledStudent = new TrainStudent();
|
||||
disabledStudent.setsId("S_DISABLED_01");
|
||||
disabledStudent.setsName("钱七");
|
||||
disabledStudent.setStatus(0); // 停用
|
||||
disabledStudent.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S_DISABLED_01", disabledStudent);
|
||||
|
||||
// 2. 非正常/停用 Student 应按真实业务规则被拒绝
|
||||
EnrollmentAddDTO dto = new EnrollmentAddDTO();
|
||||
dto.setStudentId("S_DISABLED_01");
|
||||
dto.setSourceType(1);
|
||||
dto.setAccommodationRequired(0);
|
||||
|
||||
assertError(StudentErrorCode.STUDENT_NOT_FOUND,
|
||||
() -> appService.addEnrollment("PLAN-001", dto, "admin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNullStatusStudentEnrollmentRejected()
|
||||
{
|
||||
// 1. 创建一个 status 为 null 的学员
|
||||
TrainStudent nullStatusStudent = new TrainStudent();
|
||||
nullStatusStudent.setsId("S_NULL_STATUS_01");
|
||||
nullStatusStudent.setsName("孙八");
|
||||
nullStatusStudent.setStatus(null); // null 状态
|
||||
nullStatusStudent.setDelFlag("0");
|
||||
studentMapper.studentStore.put("S_NULL_STATUS_01", nullStatusStudent);
|
||||
|
||||
// 2. status 为 null 的 Student 应按严格规则被拒绝
|
||||
EnrollmentAddDTO dto = new EnrollmentAddDTO();
|
||||
dto.setStudentId("S_NULL_STATUS_01");
|
||||
dto.setSourceType(1);
|
||||
dto.setAccommodationRequired(0);
|
||||
|
||||
assertError(StudentErrorCode.STUDENT_NOT_FOUND,
|
||||
() -> appService.addEnrollment("PLAN-001", dto, "admin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListEnrollmentsAndDetailWithMasking()
|
||||
{
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
<el-option
|
||||
v-for="c in planCourseOptions"
|
||||
:key="c.planCourseId"
|
||||
:label="`${c.cName || c.courseName} (${c.cCode || '无编码'}) - ${c.cDuration || 0}学时`"
|
||||
:label="`${c.cName || '未命名'} (${c.cCode || '无编码'}) - ${c.cDuration != null ? c.cDuration : 0}学时`"
|
||||
:value="c.planCourseId"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
Reference in new issue
Block a user