zlwu vor 7 Monaten
Ursprung
Commit
7e122d76dd

+ 11 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentStatusChangeController.java

@@ -5,7 +5,6 @@ import java.util.List;
 import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
-import cn.dev33.satoken.annotation.SaCheckPermission;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -18,6 +17,7 @@ import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.xg.domain.vo.XgStudentStatusChangeVo;
+import org.dromara.xg.domain.bo.XgStudentResumeWithClassChangeBo;
 import org.dromara.xg.domain.bo.XgStudentStatusChangeBo;
 import org.dromara.xg.service.IXgStudentStatusChangeService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -93,6 +93,16 @@ public class XgStudentStatusChangeController extends BaseController {
         return toAjax(result);
     }
 
+    /**
+     * 复学并换班级(一次提交,事务化写入两条记录)
+     */
+    @Log(title = "学生复学并换班级", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/resume-with-class-change")
+    public R<Void> resumeWithClassChange(@Validated(AddGroup.class) @RequestBody XgStudentResumeWithClassChangeBo bo) {
+        return toAjax(xgStudentStatusChangeService.insertResumeWithClassChange(bo));
+    }
+
     /**
      * 修改学生学籍异动
      */

+ 123 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgStudentResumeWithClassChangeBo.java

@@ -0,0 +1,123 @@
+package org.dromara.xg.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * 复学并换班级组合业务对象
+ *
+ * @author AI Assistant
+ * @date 2026-03-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class XgStudentResumeWithClassChangeBo extends BaseEntity {
+
+    /**
+     * 学生ID
+     */
+    @NotNull(message = "学生ID不能为空", groups = { AddGroup.class })
+    private Long studentId;
+
+    /**
+     * 学号
+     */
+    @NotBlank(message = "学号不能为空", groups = { AddGroup.class })
+    private String studentNo;
+
+    /**
+     * 学生姓名
+     */
+    private String studentName;
+
+    /**
+     * 原学院ID
+     */
+    private Long originalCollegeId;
+
+    /**
+     * 原学院名称
+     */
+    private String originalCollegeName;
+
+    /**
+     * 原专业ID
+     */
+    private Long originalMajorId;
+
+    /**
+     * 原专业名称
+     */
+    private String originalMajorName;
+
+    /**
+     * 原班级ID
+     */
+    private Long originalClassId;
+
+    /**
+     * 原班级名称
+     */
+    private String originalClassName;
+
+    /**
+     * 新学院ID
+     */
+    @NotNull(message = "新学院不能为空", groups = { AddGroup.class })
+    private Long newCollegeId;
+
+    /**
+     * 新学院名称
+     */
+    private String newCollegeName;
+
+    /**
+     * 新专业ID
+     */
+    @NotNull(message = "新专业不能为空", groups = { AddGroup.class })
+    private Long newMajorId;
+
+    /**
+     * 新专业名称
+     */
+    private String newMajorName;
+
+    /**
+     * 新班级ID
+     */
+    @NotNull(message = "新班级不能为空", groups = { AddGroup.class })
+    private Long newClassId;
+
+    /**
+     * 新班级名称
+     */
+    private String newClassName;
+
+    /**
+     * 生效日期(复学与换班级共用)
+     */
+    @NotNull(message = "生效时间不能为空", groups = { AddGroup.class })
+    private Date effectiveDate;
+
+    /**
+     * 原因(复学原因,同时作为换班级原因)
+     */
+    @NotBlank(message = "原因不能为空", groups = { AddGroup.class })
+    private String reason;
+
+    /**
+     * 经办人ID
+     */
+    private Long operatorId;
+
+    /**
+     * 经办人姓名
+     */
+    private String operatorName;
+}

+ 9 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentStatusChangeService.java

@@ -1,6 +1,7 @@
 package org.dromara.xg.service;
 
 import org.dromara.xg.domain.vo.XgStudentStatusChangeVo;
+import org.dromara.xg.domain.bo.XgStudentResumeWithClassChangeBo;
 import org.dromara.xg.domain.bo.XgStudentStatusChangeBo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
@@ -49,6 +50,14 @@ public interface IXgStudentStatusChangeService {
      */
     Boolean insertByBo(XgStudentStatusChangeBo bo);
 
+    /**
+     * 复学并换班级(事务化组合提交)
+     *
+     * @param bo 组合业务参数
+     * @return 是否新增成功
+     */
+    Boolean insertResumeWithClassChange(XgStudentResumeWithClassChangeBo bo);
+
     /**
      * 修改学生学籍异动
      *

+ 57 - 2
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentStatusChangeServiceImpl.java

@@ -9,16 +9,19 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.exception.ServiceException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.dromara.xg.domain.bo.XgStudentClassChangeBo;
+import org.dromara.xg.domain.bo.XgStudentResumeWithClassChangeBo;
 import org.dromara.xg.domain.bo.XgStudentStatusChangeBo;
 import org.dromara.xg.domain.vo.XgStudentStatusChangeVo;
 import org.dromara.xg.domain.XgStudentStatusChange;
 import org.dromara.xg.mapper.XgStudentStatusChangeMapper;
+import org.dromara.xg.service.IXgStudentClassChangeService;
 import org.dromara.xg.service.IXgStudentStatusChangeService;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Collection;
 
 /**
@@ -33,6 +36,7 @@ import java.util.Collection;
 public class XgStudentStatusChangeServiceImpl implements IXgStudentStatusChangeService {
 
     private final XgStudentStatusChangeMapper baseMapper;
+    private final IXgStudentClassChangeService xgStudentClassChangeService;
 
     /**
      * 查询学生学籍异动
@@ -73,7 +77,6 @@ public class XgStudentStatusChangeServiceImpl implements IXgStudentStatusChangeS
     }
 
     private LambdaQueryWrapper<XgStudentStatusChange> buildQueryWrapper(XgStudentStatusChangeBo bo) {
-        Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<XgStudentStatusChange> lqw = Wrappers.lambdaQuery();
         lqw.eq(bo.getId() != null, XgStudentStatusChange::getId, bo.getId());
         lqw.eq(bo.getStudentId() != null, XgStudentStatusChange::getStudentId, bo.getStudentId());
@@ -106,6 +109,58 @@ public class XgStudentStatusChangeServiceImpl implements IXgStudentStatusChangeS
         return flag;
     }
 
+    /**
+     * 复学并换班级(事务化组合提交)
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertResumeWithClassChange(XgStudentResumeWithClassChangeBo bo) {
+        XgStudentStatusChangeBo statusChangeBo = new XgStudentStatusChangeBo();
+        statusChangeBo.setStudentId(bo.getStudentId());
+        statusChangeBo.setStudentNo(bo.getStudentNo());
+        statusChangeBo.setChangeType("FU_XUE");
+        statusChangeBo.setApplyDate(new java.util.Date());
+        statusChangeBo.setEffectiveDate(bo.getEffectiveDate());
+        statusChangeBo.setReason(bo.getReason());
+        statusChangeBo.setOperatorId(bo.getOperatorId());
+        statusChangeBo.setOperatorName(bo.getOperatorName());
+        statusChangeBo.setSource("manual");
+        statusChangeBo.setProcessStatus(0);
+
+        boolean statusInserted = insertByBo(statusChangeBo);
+        if (!statusInserted) {
+            throw new ServiceException("复学记录保存失败");
+        }
+
+        XgStudentClassChangeBo classChangeBo = new XgStudentClassChangeBo();
+        classChangeBo.setStudentId(bo.getStudentId());
+        classChangeBo.setStudentNo(bo.getStudentNo());
+        classChangeBo.setStudentName(bo.getStudentName());
+        classChangeBo.setOriginalCollegeId(bo.getOriginalCollegeId());
+        classChangeBo.setOriginalCollegeName(bo.getOriginalCollegeName());
+        classChangeBo.setOriginalMajorId(bo.getOriginalMajorId());
+        classChangeBo.setOriginalMajorName(bo.getOriginalMajorName());
+        classChangeBo.setOriginalClassId(bo.getOriginalClassId());
+        classChangeBo.setOriginalClassName(bo.getOriginalClassName());
+        classChangeBo.setNewCollegeId(bo.getNewCollegeId());
+        classChangeBo.setNewCollegeName(bo.getNewCollegeName());
+        classChangeBo.setNewMajorId(bo.getNewMajorId());
+        classChangeBo.setNewMajorName(bo.getNewMajorName());
+        classChangeBo.setNewClassId(bo.getNewClassId());
+        classChangeBo.setNewClassName(bo.getNewClassName());
+        classChangeBo.setChangeReason(bo.getReason());
+        classChangeBo.setChangeType("2");
+        classChangeBo.setChangeTime(new java.util.Date());
+        classChangeBo.setEffectiveTime(bo.getEffectiveDate());
+        classChangeBo.setStatus("0");
+
+        boolean classInserted = xgStudentClassChangeService.insertByBo(classChangeBo);
+        if (!classInserted) {
+            throw new ServiceException("换班级记录保存失败");
+        }
+        return true;
+    }
+
     /**
      * 修改学生学籍异动
      *

+ 2 - 0
docs/开发文档/API/API文档总览.md

@@ -100,6 +100,7 @@
 
 | 日期 | 版本 | 更新内容 | 更新人 |
 |------|------|---------|-------|
+| 2026-03-13 | 1.7 | 新增学生学籍异动与换班级API文档,补充复学+换班级事务化组合接口 | Cursor |
 | 2025-12-26 | 1.6 | 新增专业信息管理API,支持树形菜单+列表的专业管理 | Cursor |
 | 2025-12-26 | 1.5 | 新增二级学院管理API,支持二级学院的增删改查 | Cursor |
 | 2025-01-03 | 1.1 | 社团管理API更新:删除副社长信息卡片,role_type字段改为字符串类型 | 系统管理员 |
@@ -168,6 +169,7 @@
 |---------|------|------|----------|
 | [学生信息收集批次管理API](./学生信息收集批次管理API.md) | 学生信息收集批次班级权限管理 | ✅ 完成 | 2025-01-27 |
 | [学生信息批次收集API](./学生信息批次收集API.md) | 学生信息批次收集管理(新增) | ✅ 完成 | 2025-01-27 |
+| [学生学籍异动与换班级API](./学生学籍异动与换班级API.md) | 学籍异动与换班级(含复学+换班级事务接口) | ✅ 完成 | 2026-03-13 |
 | [班级信息管理API](./班级信息管理API.md) | 班级基础信息增删改查 | ✅ 完成 | 2025-01-27 |
 | [二级学院管理API](./二级学院管理API.md) | 二级学院组织信息管理 | ✅ 完成 | 2025-12-26 |
 | [专业信息管理API](./专业信息管理API.md) | 专业信息管理(树形菜单+列表) | ✅ 完成 | 2025-12-26 |

+ 84 - 0
docs/开发文档/API/学生学籍异动与换班级API.md

@@ -0,0 +1,84 @@
+# 学生学籍异动与换班级API
+
+## 模块说明
+
+本文档用于说明学生学籍异动(退学、休学、复学、毕业)与换班级相关接口,重点包含“复学并换班级”事务化组合接口。
+
+- 基础路径:`/studentMsg/studentStatusChange`
+- 关联模块:`/studentMsg/studentClassChange`
+
+## 1. 批量新增学籍异动
+
+- 请求方式:`POST`
+- 请求路径:`/studentMsg/studentStatusChange/batch`
+- 功能描述:批量提交学籍异动记录(适用于退学、休学、毕业、普通复学)
+
+## 2. 复学并换班级(事务化组合接口)
+
+- 请求方式:`POST`
+- 请求路径:`/studentMsg/studentStatusChange/resume-with-class-change`
+- 功能描述:一次提交同时写入
+  - 学籍异动表 1 条(`changeType=FU_XUE`)
+  - 换班级表 1 条(新学院/新专业/新班级)
+- 事务说明:任一写入失败则整体回滚,避免“只复学未换班”或“只换班未复学”的数据不一致
+
+### 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|---|---|---|---|
+| studentId | Long | 是 | 学生ID |
+| studentNo | String | 是 | 学号 |
+| studentName | String | 否 | 学生姓名 |
+| originalCollegeId | Long | 否 | 原学院ID |
+| originalCollegeName | String | 否 | 原学院名称 |
+| originalMajorId | Long | 否 | 原专业ID |
+| originalMajorName | String | 否 | 原专业名称 |
+| originalClassId | Long | 否 | 原班级ID |
+| originalClassName | String | 否 | 原班级名称 |
+| newCollegeId | Long | 是 | 新学院ID |
+| newCollegeName | String | 否 | 新学院名称 |
+| newMajorId | Long | 是 | 新专业ID |
+| newMajorName | String | 否 | 新专业名称 |
+| newClassId | Long | 是 | 新班级ID |
+| newClassName | String | 否 | 新班级名称 |
+| effectiveDate | Date | 是 | 生效日期(复学与换班级共用) |
+| reason | String | 是 | 原因(复学原因,同时写入换班级原因) |
+| operatorId | Long | 否 | 经办人ID |
+| operatorName | String | 否 | 经办人姓名 |
+
+### 请求示例
+
+```json
+{
+  "studentId": 197001010001,
+  "studentNo": "20240001",
+  "studentName": "张三",
+  "originalCollegeId": 201,
+  "originalCollegeName": "信息工程学院",
+  "originalMajorId": 301,
+  "originalMajorName": "软件技术",
+  "originalClassId": 401,
+  "originalClassName": "软技2401",
+  "newCollegeId": 202,
+  "newCollegeName": "智能制造学院",
+  "newMajorId": 302,
+  "newMajorName": "机电一体化技术",
+  "newClassId": 402,
+  "newClassName": "机电2402",
+  "effectiveDate": "2026-03-13",
+  "reason": "学生复学并调整到新班级",
+  "operatorId": 100,
+  "operatorName": "管理员"
+}
+```
+
+### 响应说明
+
+- 成功响应:`R<Void>`,`code=200`
+- 失败响应:`R<Void>`,`code!=200`,并返回错误信息
+
+## 更新记录
+
+| 日期 | 更新内容 | 更新人 |
+|---|---|---|
+| 2026-03-13 | 新增“复学并换班级”事务化组合接口文档 | Cursor |

+ 0 - 2
web/src/views/login.vue

@@ -58,11 +58,9 @@
             <span v-else>{{ proxy.$t('login.logging') }}</span>
           </el-button>
 
-          <!-- 统一认证登录按钮(已注释,方便恢复)
           <el-button size="large" class="login-button cas-login" type="primary" @click.prevent="handleUnifiedLogin">
             统一认证登录
           </el-button>
-          -->
         </div>
 
         <div v-if="register" style="float: right">

+ 188 - 1
web/src/views/xg/xsjcxx/studentMsg/studentMsg/index.vue

@@ -1676,6 +1676,37 @@
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row v-if="isResumeChangeType" :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="新学院" prop="newCollegeId">
+              <el-select v-model="statusChangeForm.newCollegeId" placeholder="请选择学院" @change="handleStatusChangeCollegeChange" style="width: 100%">
+                <el-option v-for="college in resumeCollegeOptions" :key="college.id" :label="college.label" :value="college.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="新专业" prop="newMajorId">
+              <el-select
+                v-model="statusChangeForm.newMajorId"
+                placeholder="请选择专业"
+                :disabled="!statusChangeForm.newCollegeId"
+                @change="handleStatusChangeMajorChange"
+                style="width: 100%"
+              >
+                <el-option v-for="major in resumeMajorOptions" :key="major.id" :label="major.label" :value="major.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="isResumeChangeType" :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="新班级" prop="newClassId">
+              <el-select v-model="statusChangeForm.newClassId" placeholder="请选择班级" :disabled="!statusChangeForm.newMajorId" style="width: 100%">
+                <el-option v-for="classItem in resumeClassOptions" :key="classItem.id" :label="classItem.label" :value="classItem.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="经办人ID" prop="operatorId">
@@ -1864,6 +1895,9 @@ const rawDeptOptions = ref<any[]>([]);
 const majorOptions = ref([]);
 const classOptions = ref([]);
 const collegeOptions = ref([]); // 学院选项
+const resumeCollegeOptions = ref<any[]>([]); // 复学弹窗学院选项
+const resumeMajorOptions = ref<any[]>([]); // 复学弹窗专业选项
+const resumeClassOptions = ref<any[]>([]); // 复学弹窗班级选项
 const regionOptions = ref([]); // 行政区划选项
 const dormBuildingOptions = ref([]); // 宿舍楼栋选项
 const currentSelectedNode = ref<any>(null); // 当前选中的部门节点
@@ -1945,6 +1979,9 @@ const statusChangeForm = reactive({
   reason: '',
   operatorId: '',
   operatorName: '',
+  newCollegeId: '',
+  newMajorId: '',
+  newClassId: '',
   selectedStudents: [] as StudentVO[]
 });
 
@@ -2103,7 +2140,10 @@ const rules = reactive({
 const statusChangeRules = reactive({
   changeType: [{ required: true, message: '异动类型不能为空', trigger: 'change' }],
   effectiveDate: [{ required: true, message: '生效日期不能为空', trigger: 'blur' }],
-  reason: [{ required: true, message: '异动原因不能为空', trigger: 'blur' }]
+  reason: [{ required: true, message: '异动原因不能为空', trigger: 'blur' }],
+  newCollegeId: [{ required: true, message: '请选择新学院', trigger: 'change' }],
+  newMajorId: [{ required: true, message: '请选择新专业', trigger: 'change' }],
+  newClassId: [{ required: true, message: '请选择新班级', trigger: 'change' }]
 });
 
 // 换班级表单验证规则
@@ -3090,8 +3130,13 @@ const openStatusChangeModal = (changeType?: string) => {
   statusChangeForm.reason = '';
   statusChangeForm.operatorId = userStore.userId || '';
   statusChangeForm.operatorName = userStore.nickname || '';
+  resetResumeClassSelection();
   statusChangeForm.selectedStudents = selectedStudents;
 
+  if (changeType === 'FU_XUE') {
+    loadResumeCollegeOptions();
+  }
+
   statusChangeDialog.visible = true;
 };
 
@@ -3112,6 +3157,99 @@ const disabledDate = (time: Date) => {
   return time.getTime() < Date.now() - 24 * 60 * 60 * 1000; // 不能选择昨天及以前的日期
 };
 
+const isResumeChangeType = computed(() => statusChangeForm.changeType === 'FU_XUE');
+
+const resetResumeClassSelection = () => {
+  statusChangeForm.newCollegeId = '';
+  statusChangeForm.newMajorId = '';
+  statusChangeForm.newClassId = '';
+  resumeMajorOptions.value = [];
+  resumeClassOptions.value = [];
+};
+
+const loadResumeCollegeOptions = async () => {
+  try {
+    const res = await service.get('/system/dept/list', {
+      params: {
+        parentId: 101, // 二级学院节点
+        deptCategory: 'xy-' // 学院标识
+      }
+    });
+    if (res && res.code === 200) {
+      resumeCollegeOptions.value = (res.data || []).map((dept: any) => ({
+        id: dept.deptId,
+        label: dept.deptName
+      }));
+    }
+  } catch (error) {
+    console.error('获取复学学院列表失败:', error);
+    resumeCollegeOptions.value = [];
+  }
+};
+
+const handleStatusChangeCollegeChange = async (collegeId: string) => {
+  statusChangeForm.newMajorId = '';
+  statusChangeForm.newClassId = '';
+  resumeMajorOptions.value = [];
+  resumeClassOptions.value = [];
+
+  if (!collegeId) return;
+
+  try {
+    const res = await service.get('/system/dept/list', {
+      params: {
+        parentId: collegeId,
+        deptCategory: 'zy-'
+      }
+    });
+    if (res && res.code === 200) {
+      resumeMajorOptions.value = (res.data || []).map((dept: any) => ({
+        id: dept.deptId,
+        label: dept.deptName
+      }));
+    }
+  } catch (error) {
+    console.error('获取复学专业列表失败:', error);
+    resumeMajorOptions.value = [];
+  }
+};
+
+const handleStatusChangeMajorChange = async (majorId: string) => {
+  statusChangeForm.newClassId = '';
+  resumeClassOptions.value = [];
+
+  if (!majorId) return;
+
+  try {
+    const res = await service.get('/system/dept/list', {
+      params: {
+        parentId: majorId,
+        deptCategory: 'bj-'
+      }
+    });
+    if (res && res.code === 200) {
+      resumeClassOptions.value = (res.data || []).map((dept: any) => ({
+        id: dept.deptId,
+        label: dept.deptName
+      }));
+    }
+  } catch (error) {
+    console.error('获取复学班级列表失败:', error);
+    resumeClassOptions.value = [];
+  }
+};
+
+watch(
+  () => statusChangeForm.changeType,
+  (value) => {
+    if (value === 'FU_XUE') {
+      loadResumeCollegeOptions();
+      return;
+    }
+    resetResumeClassSelection();
+  }
+);
+
 /** 提交学籍异动 */
 const submitStatusChange = async () => {
   const formRef = statusChangeFormRef.value;
@@ -3120,6 +3258,55 @@ const submitStatusChange = async () => {
   await formRef.validate(async (valid: boolean) => {
     if (valid) {
       try {
+        if (isResumeChangeType.value) {
+          if (statusChangeForm.selectedStudents.length !== 1) {
+            ElMessage.warning('复学并换班级仅支持单个学生操作');
+            return;
+          }
+          if (!statusChangeForm.newCollegeId || !statusChangeForm.newMajorId || !statusChangeForm.newClassId) {
+            ElMessage.warning('请选择新学院、新专业和新班级');
+            return;
+          }
+
+          const selectedStudent = statusChangeForm.selectedStudents[0];
+          if (String(statusChangeForm.newClassId) === String(selectedStudent.classId || '')) {
+            ElMessage.warning('请选择与原班级不同的新班级');
+            return;
+          }
+
+          const resumePayload = {
+            studentId: selectedStudent.id,
+            studentNo: selectedStudent.studentNo,
+            studentName: selectedStudent.name,
+            originalCollegeId: selectedStudent.collegeId || undefined,
+            originalCollegeName: (selectedStudent as any).collegeName || (selectedStudent as any).colegeName || '',
+            originalMajorId: selectedStudent.majorId || undefined,
+            originalMajorName: selectedStudent.majorName || '',
+            originalClassId: selectedStudent.classId || undefined,
+            originalClassName: selectedStudent.className || '',
+            newCollegeId: statusChangeForm.newCollegeId,
+            newCollegeName: resumeCollegeOptions.value.find((item: any) => String(item.id) === String(statusChangeForm.newCollegeId))?.label || '',
+            newMajorId: statusChangeForm.newMajorId,
+            newMajorName: resumeMajorOptions.value.find((item: any) => String(item.id) === String(statusChangeForm.newMajorId))?.label || '',
+            newClassId: statusChangeForm.newClassId,
+            newClassName: resumeClassOptions.value.find((item: any) => String(item.id) === String(statusChangeForm.newClassId))?.label || '',
+            effectiveDate: statusChangeForm.effectiveDate,
+            reason: statusChangeForm.reason,
+            operatorId: statusChangeForm.operatorId || undefined,
+            operatorName: statusChangeForm.operatorName
+          };
+
+          const res = await service.post('/studentMsg/studentStatusChange/resume-with-class-change', resumePayload);
+          if (res && res.code === 200) {
+            ElMessage.success('复学并换班级提交成功');
+            statusChangeDialog.visible = false;
+            await getList();
+          } else {
+            ElMessage.error(res?.msg || '提交失败');
+          }
+          return;
+        }
+
         const submitData = statusChangeForm.selectedStudents.map((student) => ({
           studentId: student.id,
           studentNo: student.studentNo,