diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/InternshipInfoController.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/InternshipInfoController.java index e0638e8b..0d2b94e7 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/InternshipInfoController.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/InternshipInfoController.java @@ -10,6 +10,7 @@ import org.dromara.zsjy.domain.vo.InternshipInfoVO; import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO; import org.dromara.zsjy.domain.bo.InternshipInfoAddBO; import org.dromara.zsjy.domain.bo.InternshipInfoEditBO; +import org.dromara.zsjy.domain.bo.InternshipInfoChangeBO; import org.dromara.zsjy.service.IInternshipInfoService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -225,4 +226,29 @@ public class InternshipInfoController extends BaseController { return R.fail("获取实习信息失败:" + e.getMessage()); } } + + /** + * 实习信息变更 + */ + @Operation(summary = "实习信息变更", description = "变更学生实习信息,将原记录设置为失效,并新增一条新的实习记录") + @SaCheckPermission("zsjy:internship:change") + @PostMapping("/change") + public R changeInternship(@RequestBody @Validated InternshipInfoChangeBO changeBO) { + log.info("实习信息变更请求,参数:{}", changeBO); + try { + Boolean result = internshipInfoService.changeInternshipInfo(changeBO); + if (result) { + log.info("实习信息变更成功,原实习ID:{},学生ID:{}", + changeBO.getInternshipId(), changeBO.getStudentId()); + return R.ok(); + } else { + log.error("实习信息变更失败,原实习ID:{}", changeBO.getInternshipId()); + return R.fail("实习信息变更失败"); + } + } catch (Exception e) { + log.error("实习信息变更异常,原实习ID:{},错误信息:{}", + changeBO.getInternshipId(), e.getMessage(), e); + return R.fail("实习信息变更失败:" + e.getMessage()); + } + } } diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java index 523eafe1..2e5b7129 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java @@ -31,6 +31,11 @@ public class ZsjyInternshipInfo extends BaseEntity { @TableId(value = "internship_id") private Long internshipId; + /** + * 前一条实习记录ID(用于变更记录关联) + */ + private Long previousInternshipId; + /** * 学生ID */ @@ -166,5 +171,9 @@ public class ZsjyInternshipInfo extends BaseEntity { */ @TableLogic(value = "0", delval = "1") private Long deleted; + + /** + * 变更原因(用于记录实习信息变更的原因) + */ + private String changeReason; } - \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IInternshipInfoService.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IInternshipInfoService.java index 660703d5..38a30d2d 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IInternshipInfoService.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IInternshipInfoService.java @@ -6,6 +6,7 @@ import org.dromara.zsjy.domain.vo.InternshipInfoVO; import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO; import org.dromara.zsjy.domain.bo.InternshipInfoAddBO; import org.dromara.zsjy.domain.bo.InternshipInfoEditBO; +import org.dromara.zsjy.domain.bo.InternshipInfoChangeBO; import jakarta.servlet.http.HttpServletResponse; import java.util.List; @@ -105,4 +106,13 @@ public interface IInternshipInfoService { * @return 当前学生的实习信息,如果没有则返回null */ InternshipInfoVO getCurrentStudentInternship(); + + /** + * 实习信息变更 + *

将原实习记录设置为"已变更"状态,并新增一条新的实习记录

+ * + * @param changeBO 变更参数 + * @return 是否成功 + */ + Boolean changeInternshipInfo(InternshipInfoChangeBO changeBO); } diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/InternshipInfoServiceImpl.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/InternshipInfoServiceImpl.java index eba50d51..b6d524c6 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/InternshipInfoServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/InternshipInfoServiceImpl.java @@ -20,6 +20,7 @@ import org.dromara.common.core.exception.ServiceException; import org.dromara.zsjy.domain.bo.InternshipInfoQueryBO; import org.dromara.zsjy.domain.bo.InternshipInfoAddBO; import org.dromara.zsjy.domain.bo.InternshipInfoEditBO; +import org.dromara.zsjy.domain.bo.InternshipInfoChangeBO; import org.dromara.zsjy.domain.vo.InternshipInfoVO; import org.dromara.zsjy.domain.ZsjyInternshipInfo; import org.dromara.zsjy.mapper.InternshipInfoMapper; @@ -468,34 +469,34 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService { @Override public InternshipInfoVO getCurrentStudentInternship() { log.info("开始获取当前学生的实习信息"); - + // 获取当前登录用户ID Long currentUserId = LoginHelper.getUserId(); log.info("当前登录用户ID:{}", currentUserId); - + if (currentUserId == null) { log.error("当前用户未登录"); throw new ServiceException("用户未登录"); } - + // 根据用户ID查询实习信息 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ZsjyInternshipInfo::getStudentId, currentUserId) .eq(ZsjyInternshipInfo::getDeleted, 0) .orderByDesc(ZsjyInternshipInfo::getCreateTime) .last("LIMIT 1"); // 只取最新的一条记录 - + ZsjyInternshipInfo internshipInfo = zsjyInternshipInfoMapper.selectOne(wrapper); log.info("查询到的实习信息:{}", internshipInfo != null ? internshipInfo.getInternshipId() : "无"); - + if (internshipInfo == null) { log.info("当前学生没有实习信息"); return null; } - + // 转换为VO InternshipInfoVO vo = BeanUtil.toBean(internshipInfo, InternshipInfoVO.class); - + // 查询学生信息并设置到VO中 XgStudentMsgVo studentInfo = getStudentInfo(currentUserId); vo.setStudentName(studentInfo.getName()); @@ -504,8 +505,117 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService { vo.setMajorName(studentInfo.getMajorName()); vo.setCollegeName(studentInfo.getCollegeName()); vo.setGrade(studentInfo.getGrade()); - + log.info("成功获取当前学生实习信息,实习ID:{}", vo.getInternshipId()); return vo; } + + /** + * 实习信息变更 + *

业务逻辑:

+ *
    + *
  1. 将原实习记录的状态设置为"4已变更",标记为失效
  2. + *
  3. 新增一条实习记录,previous_internship_id指向原记录
  4. + *
  5. 保存变更原因到新记录的change_reason字段
  6. + *
+ * + * @param changeBO 变更参数 + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean changeInternshipInfo(InternshipInfoChangeBO changeBO) { + log.info("=== 实习信息变更开始 ==="); + log.info("1. 接收到的变更参数:{}", changeBO); + + // 1. 查询原实习记录 + ZsjyInternshipInfo oldInternshipInfo = zsjyInternshipInfoMapper.selectById(changeBO.getInternshipId()); + if (ObjectUtil.isNull(oldInternshipInfo)) { + log.error("原实习信息不存在,ID:{}", changeBO.getInternshipId()); + throw new ServiceException("原实习信息不存在"); + } + log.info("2. 查询到原实习记录:实习ID={}, 学生ID={}, 单位={}", + oldInternshipInfo.getInternshipId(), oldInternshipInfo.getStudentId(), + oldInternshipInfo.getCompanyName()); + + // 2. 验证学生ID是否匹配 + if (!oldInternshipInfo.getStudentId().equals(changeBO.getStudentId())) { + log.error("学生ID不匹配,原记录学生ID:{},变更请求学生ID:{}", + oldInternshipInfo.getStudentId(), changeBO.getStudentId()); + throw new ServiceException("学生ID不匹配,无法进行变更操作"); + } + + // 3. 检查原记录状态是否允许变更(只有"进行中"的实习可以变更) + if (!"1".equals(oldInternshipInfo.getInternshipStatus())) { + log.error("只有进行中的实习信息才能变更,当前状态:{}", oldInternshipInfo.getInternshipStatus()); + throw new ServiceException("只有进行中的实习信息才能变更"); + } + + // 4. 将原实习记录设置为"已变更"状态 + ZsjyInternshipInfo updateOldInfo = new ZsjyInternshipInfo(); + updateOldInfo.setInternshipId(oldInternshipInfo.getInternshipId()); + updateOldInfo.setInternshipStatus("4"); // 4=已变更 + int updateResult = zsjyInternshipInfoMapper.updateById(updateOldInfo); + log.info("3. 更新原实习记录状态为'已变更',结果:{}", updateResult > 0 ? "成功" : "失败"); + + if (updateResult <= 0) { + log.error("更新原实习记录状态失败"); + throw new ServiceException("更新原实习记录状态失败"); + } + + // 5. 创建新的实习记录 + ZsjyInternshipInfo newInternshipInfo = new ZsjyInternshipInfo(); + + // 复制学生基础信息(从原记录) + newInternshipInfo.setStudentId(oldInternshipInfo.getStudentId()); + newInternshipInfo.setStudentNo(oldInternshipInfo.getStudentNo()); + newInternshipInfo.setStudentName(oldInternshipInfo.getStudentName()); + newInternshipInfo.setGender(oldInternshipInfo.getGender()); + newInternshipInfo.setCollegeId(oldInternshipInfo.getCollegeId()); + newInternshipInfo.setMajorId(oldInternshipInfo.getMajorId()); + newInternshipInfo.setClassId(oldInternshipInfo.getClassId()); + newInternshipInfo.setPhone(oldInternshipInfo.getPhone()); + + // 设置变更关联信息 + newInternshipInfo.setPreviousInternshipId(oldInternshipInfo.getInternshipId()); // 关联原记录 + newInternshipInfo.setChangeReason(changeBO.getChangeReason()); // 变更原因 + + // 设置新的实习信息(来自changeBO) + newInternshipInfo.setInternshipStatus(changeBO.getInternshipStatus()); + newInternshipInfo.setCompanyName(changeBO.getCompanyName()); + newInternshipInfo.setCompanyAddress(changeBO.getCompanyAddress()); + newInternshipInfo.setCompanyContact(changeBO.getCompanyContact()); + newInternshipInfo.setCompanyPhone(changeBO.getCompanyPhone()); + newInternshipInfo.setCompanyIndustry(changeBO.getCompanyIndustry()); + newInternshipInfo.setCompanyScale(changeBO.getCompanyScale()); + newInternshipInfo.setPositionName(changeBO.getPositionName()); + newInternshipInfo.setPositionDuties(changeBO.getPositionDuties()); + newInternshipInfo.setInternshipAllowance(changeBO.getInternshipAllowance()); + newInternshipInfo.setWorkHours(changeBO.getWorkHours()); + newInternshipInfo.setAccommodationAddress(changeBO.getAccommodationAddress()); + newInternshipInfo.setAccommodationType(changeBO.getAccommodationType()); + newInternshipInfo.setAccommodationCost(changeBO.getAccommodationCost()); + newInternshipInfo.setStartDate(changeBO.getStartDate()); + newInternshipInfo.setEndDate(changeBO.getEndDate()); + newInternshipInfo.setStatus("0"); // 状态:0=正常 + + log.info("4. 准备插入新实习记录:学生ID={}, 新单位={}, 变更原因={}", + newInternshipInfo.getStudentId(), newInternshipInfo.getCompanyName(), + newInternshipInfo.getChangeReason()); + + // 6. 插入新记录 + int insertResult = zsjyInternshipInfoMapper.insert(newInternshipInfo); + log.info("5. 插入新实习记录,结果:{}", insertResult > 0 ? "成功" : "失败"); + log.info("6. 新实习记录ID:{}", newInternshipInfo.getInternshipId()); + + if (insertResult <= 0) { + log.error("插入新实习记录失败"); + throw new ServiceException("插入新实习记录失败"); + } + + boolean success = insertResult > 0; + log.info("=== 实习信息变更结束,结果:{} ===", success ? "成功" : "失败"); + + return success; + } } diff --git a/web/src/api/zsjy/internship.ts b/web/src/api/zsjy/internship.ts index 1d3b4fce..ecb57454 100644 --- a/web/src/api/zsjy/internship.ts +++ b/web/src/api/zsjy/internship.ts @@ -5,6 +5,7 @@ import { InternshipInfoQuery, InternshipInfoAddBO, InternshipInfoEditBO, + InternshipInfoChangeBO, ClassInfoVO, InternshipStatisticsVO } from '@/api/zsjy/types'; @@ -113,3 +114,15 @@ export const delInternshipInfo = (internshipId: string | number): AxiosPromise> => { + return request({ + url: '/zsjy/internship/change', + method: 'post', + data: data + }); +}; diff --git a/web/src/api/zsjy/types.ts b/web/src/api/zsjy/types.ts index 7ce13922..3ffec532 100644 --- a/web/src/api/zsjy/types.ts +++ b/web/src/api/zsjy/types.ts @@ -1139,6 +1139,111 @@ export interface InternshipInfoEditBO { remark?: string; } +/** + * 实习信息变更 BO + */ +export interface InternshipInfoChangeBO { + /** + * 原实习信息ID(要变更的实习记录ID) + */ + internshipId: string | number; + + /** + * 学生ID + */ + studentId: string | number; + + /** + * 变更原因(必填) + */ + changeReason: string; + + /** + * 实习状态(1进行中 2已完成 3中断) + */ + internshipStatus: string; + + /** + * 实习单位名称 + */ + companyName: string; + + /** + * 实习单位地址 + */ + companyAddress: string; + + /** + * 单位联系人 + */ + companyContact: string; + + /** + * 联系人电话 + */ + companyPhone: string; + + /** + * 行业类型 + */ + companyIndustry?: string; + + /** + * 单位规模 + */ + companyScale?: string; + + /** + * 岗位名称 + */ + positionName: string; + + /** + * 岗位职责 + */ + positionDuties?: string; + + /** + * 实习津贴 + */ + internshipAllowance?: number; + + /** + * 工作时长 + */ + workHours?: string; + + /** + * 住宿地址 + */ + accommodationAddress?: string; + + /** + * 住宿类型 + */ + accommodationType?: string; + + /** + * 住宿费用 + */ + accommodationCost?: number; + + /** + * 实习开始日期 + */ + startDate: string; + + /** + * 实习结束日期 + */ + endDate: string; + + /** + * 备注信息 + */ + remark?: string; +} + /** * 实习信息查询 BO */ diff --git a/web/src/views/zsjy/internship/msgmanage/index.vue b/web/src/views/zsjy/internship/msgmanage/index.vue index 56a5a311..49b078c6 100644 --- a/web/src/views/zsjy/internship/msgmanage/index.vue +++ b/web/src/views/zsjy/internship/msgmanage/index.vue @@ -167,7 +167,7 @@ - + @@ -247,6 +250,14 @@ + + + @@ -259,6 +270,7 @@ import { download } from '@/utils/request'; import { ElMessage } from 'element-plus'; import AddDialog from './components/AddDialog.vue'; import EditDialog from './components/EditDialog.vue'; +import ChangeDialog from './components/ChangeDialog.vue'; const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { internship_status, sys_user_sex } = toRefs(proxy?.useDict('internship_status', 'sys_user_sex')); @@ -280,6 +292,7 @@ const studentDetail = ref(); // 弹窗相关状态 const showAddDialog = ref(false); const showEditDialog = ref(false); +const showChangeDialog = ref(false); const selectedStudentInfo = ref<{ studentId: string; studentName: string; @@ -290,6 +303,7 @@ const selectedStudentInfo = ref<{ studentNo: '' }); const selectedStudentId = ref(''); +const selectedInternshipId = ref(''); const data = reactive({ queryParams: { @@ -433,6 +447,13 @@ const handleAdd = (row: InternshipInfoVO) => { showAddDialog.value = true; }; +/** 变更实习信息按钮操作 */ +const handleChange = (row: InternshipInfoVO) => { + selectedInternshipId.value = row.internshipId as string; + selectedStudentId.value = row.studentId as string; + showChangeDialog.value = true; +}; + /** 编辑实习信息按钮操作 */ const handleEdit = (row: InternshipInfoVO) => { selectedStudentId.value = row.studentId;