提交
This commit is contained in:
1 parent
f3869785ff
commit
4ada3c6f01
8 files changed
+724
-5
No files matched your search
+103
@@ -1,27 +1,41 @@
|
|||||||
package org.dromara.xg.controller;
|
package org.dromara.xg.controller;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
import org.dromara.common.log.annotation.Log;
|
import org.dromara.common.log.annotation.Log;
|
||||||
import org.dromara.common.web.core.BaseController;
|
import org.dromara.common.web.core.BaseController;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
import org.dromara.common.core.validate.EditGroup;
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
import org.dromara.common.log.enums.BusinessType;
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.dromara.common.excel.core.DropDownOptions;
|
||||||
|
import org.dromara.common.excel.core.ExcelResult;
|
||||||
import org.dromara.common.excel.utils.ExcelUtil;
|
import org.dromara.common.excel.utils.ExcelUtil;
|
||||||
|
import org.dromara.xg.domain.vo.XgClassMsgImportVo;
|
||||||
import org.dromara.xg.domain.vo.XgClassMsgVo;
|
import org.dromara.xg.domain.vo.XgClassMsgVo;
|
||||||
|
import org.dromara.xg.domain.vo.XgSysDeptVo;
|
||||||
import org.dromara.xg.domain.bo.XgClassMsgBo;
|
import org.dromara.xg.domain.bo.XgClassMsgBo;
|
||||||
import org.dromara.xg.domain.bo.XgClassStatusBo;
|
import org.dromara.xg.domain.bo.XgClassStatusBo;
|
||||||
import org.dromara.xg.domain.bo.XgClassStatusBatchBo;
|
import org.dromara.xg.domain.bo.XgClassStatusBatchBo;
|
||||||
|
import org.dromara.xg.excel.XgClassMsgImportTemplateWriter;
|
||||||
|
import org.dromara.xg.listener.XgClassMsgImportListener;
|
||||||
import org.dromara.xg.service.IXgClassMsgService;
|
import org.dromara.xg.service.IXgClassMsgService;
|
||||||
|
import org.dromara.xg.service.IXgSysDeptService;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
|
|
||||||
@@ -31,6 +45,7 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
|||||||
* @author zlwu
|
* @author zlwu
|
||||||
* @date 2025-07-23
|
* @date 2025-07-23
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Validated
|
@Validated
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController
|
@RestController
|
||||||
@@ -38,6 +53,7 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
|||||||
public class XgClassMsgController extends BaseController {
|
public class XgClassMsgController extends BaseController {
|
||||||
|
|
||||||
private final IXgClassMsgService xgClassMsgService;
|
private final IXgClassMsgService xgClassMsgService;
|
||||||
|
private final IXgSysDeptService xgSysDeptService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询班级信息-新版列表
|
* 查询班级信息-新版列表
|
||||||
@@ -146,4 +162,91 @@ public class XgClassMsgController extends BaseController {
|
|||||||
List<XgClassMsgVo> list = xgClassMsgService.queryList(bo);
|
List<XgClassMsgVo> list = xgClassMsgService.queryList(bo);
|
||||||
return R.ok(list);
|
return R.ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载班级信息导入模板(含字典下拉、学院-专业联动下拉)
|
||||||
|
*/
|
||||||
|
// @SaCheckPermission("classMsg:classMsg:import")
|
||||||
|
@PostMapping("/importTemplate")
|
||||||
|
public void importTemplate(HttpServletResponse response) {
|
||||||
|
try {
|
||||||
|
List<XgClassMsgImportVo> templateData = new ArrayList<>();
|
||||||
|
XgClassMsgImportVo example = new XgClassMsgImportVo();
|
||||||
|
int currentYear = java.time.Year.now().getValue();
|
||||||
|
example.setClassName("示例:" + currentYear + "计算机1班");
|
||||||
|
example.setClassType("1");
|
||||||
|
example.setGrade(String.valueOf(currentYear));
|
||||||
|
example.setEnrollmentYear((long) currentYear);
|
||||||
|
example.setSchoolSystem(3L);
|
||||||
|
// 毕业年份由模板公式自动计算:入学年份+学制
|
||||||
|
example.setGraduationYear(null);
|
||||||
|
example.setIsGraduation(0L);
|
||||||
|
example.setClassLocation("教学楼A101");
|
||||||
|
example.setClassStatus("1");
|
||||||
|
example.setClassDescription("示例数据,导入前请删除或修改");
|
||||||
|
example.setRemark("班主任选填:姓名唯一匹配才写入");
|
||||||
|
templateData.add(example);
|
||||||
|
|
||||||
|
List<DropDownOptions> options = buildImportDropDownOptions();
|
||||||
|
XgClassMsgImportTemplateWriter.write(templateData, response, options);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成班级信息导入模板失败", e);
|
||||||
|
throw new ServiceException("生成模板失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入班级信息
|
||||||
|
*/
|
||||||
|
// @SaCheckPermission("classMsg:classMsg:import")
|
||||||
|
@Log(title = "班级信息-新版", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
|
||||||
|
ExcelResult<XgClassMsgImportVo> result = ExcelUtil.importExcel(
|
||||||
|
file.getInputStream(),
|
||||||
|
XgClassMsgImportVo.class,
|
||||||
|
new XgClassMsgImportListener());
|
||||||
|
return R.ok(result.getAnalysis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建导入模板下拉:学院-专业联动 + 常见学制
|
||||||
|
*/
|
||||||
|
private List<DropDownOptions> buildImportDropDownOptions() {
|
||||||
|
List<XgSysDeptVo> collegeList = xgSysDeptService.selectCollegeList();
|
||||||
|
List<XgSysDeptVo> majorList = new ArrayList<>();
|
||||||
|
for (XgSysDeptVo college : collegeList) {
|
||||||
|
List<XgSysDeptVo> majors = xgSysDeptService.selectMajorListByCollegeId(college.getDeptId());
|
||||||
|
if (majors != null) {
|
||||||
|
majorList.addAll(majors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int collegeIndex = 0;
|
||||||
|
int majorIndex = 1;
|
||||||
|
DropDownOptions collegeToMajor = DropDownOptions.buildLinkedOptions(
|
||||||
|
collegeList,
|
||||||
|
collegeIndex,
|
||||||
|
majorList,
|
||||||
|
majorIndex,
|
||||||
|
XgSysDeptVo::getDeptId,
|
||||||
|
XgSysDeptVo::getParentId,
|
||||||
|
this::buildDeptOptionValue
|
||||||
|
);
|
||||||
|
|
||||||
|
// 学制常见可选值
|
||||||
|
DropDownOptions schoolSystemOptions = new DropDownOptions(6, Arrays.asList("2", "3", "4", "5", "6"));
|
||||||
|
|
||||||
|
List<DropDownOptions> options = new ArrayList<>();
|
||||||
|
options.add(collegeToMajor);
|
||||||
|
options.add(schoolSystemOptions);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成学院/专业下拉选项值:仅展示名称(导入时按名称解析为 ID)
|
||||||
|
*/
|
||||||
|
private String buildDeptOptionValue(XgSysDeptVo dept) {
|
||||||
|
return StringUtils.blankToDefault(dept.getDeptName(), "未命名");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
package org.dromara.xg.domain.vo;
|
||||||
|
|
||||||
|
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||||
|
import org.dromara.common.excel.annotation.ExcelNotation;
|
||||||
|
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级信息导入VO
|
||||||
|
*
|
||||||
|
* @author zlwu
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class XgClassMsgImportVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学院(下拉:学院名称,与专业联动)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "学院", index = 0)
|
||||||
|
@ColumnWidth(24)
|
||||||
|
@NotBlank(message = "学院不能为空")
|
||||||
|
private String college;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专业(下拉:专业名称,随学院联动)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "专业", index = 1)
|
||||||
|
@ColumnWidth(30)
|
||||||
|
@NotBlank(message = "专业不能为空")
|
||||||
|
private String major;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级名称(同时作为班级代码)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "班级名称", index = 2)
|
||||||
|
@NotBlank(message = "班级名称不能为空")
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学历层级(字典下拉:zsjy_education_level)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "学历层级", index = 3, converter = ExcelDictConvert.class)
|
||||||
|
@ExcelDictFormat(dictType = "zsjy_education_level")
|
||||||
|
@ColumnWidth(20)
|
||||||
|
@NotBlank(message = "学历层级不能为空")
|
||||||
|
private String classType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 年级
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "年级", index = 4)
|
||||||
|
@NotBlank(message = "年级不能为空")
|
||||||
|
private String grade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 入学年份
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "入学年份", index = 5)
|
||||||
|
@NotNull(message = "入学年份不能为空")
|
||||||
|
private Long enrollmentYear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学制(年)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "学制(年)", index = 6)
|
||||||
|
@NotNull(message = "学制不能为空")
|
||||||
|
private Long schoolSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 毕业年份(模板内公式:入学年份+学制;可不填,导入时也会自动计算)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "毕业年份", index = 7)
|
||||||
|
@ExcelNotation(value = "自动计算:入学年份+学制,也可留空由系统计算")
|
||||||
|
private Long graduationYear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已毕业(字典下拉:is_graduation)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "是否已毕业", index = 8, converter = ExcelDictConvert.class)
|
||||||
|
@ExcelDictFormat(dictType = "is_graduation")
|
||||||
|
@NotNull(message = "是否已毕业不能为空")
|
||||||
|
private Long isGraduation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级教室位置
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "班级教室位置", index = 9)
|
||||||
|
private String classLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级状态(字典下拉:xg_class_status)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "班级状态", index = 10, converter = ExcelDictConvert.class)
|
||||||
|
@ExcelDictFormat(dictType = "xg_class_status")
|
||||||
|
@NotBlank(message = "班级状态不能为空")
|
||||||
|
private String classStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班主任(选填,填写姓名;仅唯一匹配时写入,不影响班级保存)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "班主任", index = 11)
|
||||||
|
@ExcelNotation(value = "选填,填写姓名。匹配到唯一人员才写入;未匹配或多人同名则不写入,不影响班级导入")
|
||||||
|
private String classTeacherName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级描述
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "班级描述", index = 12)
|
||||||
|
private String classDescription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注信息
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "备注信息", index = 13)
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
+291
@@ -0,0 +1,291 @@
|
|||||||
|
package org.dromara.xg.listener;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
|
import cn.hutool.http.HtmlUtil;
|
||||||
|
import cn.idev.excel.context.AnalysisContext;
|
||||||
|
import cn.idev.excel.event.AnalysisEventListener;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import jakarta.validation.ConstraintViolation;
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.core.utils.ValidatorUtils;
|
||||||
|
import org.dromara.common.excel.core.DropDownOptions;
|
||||||
|
import org.dromara.common.excel.core.ExcelListener;
|
||||||
|
import org.dromara.common.excel.core.ExcelResult;
|
||||||
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
|
import org.dromara.xg.domain.XgClassMsg;
|
||||||
|
import org.dromara.xg.domain.XgSysDept;
|
||||||
|
import org.dromara.xg.domain.XgSysUser;
|
||||||
|
import org.dromara.xg.domain.bo.XgClassMsgBo;
|
||||||
|
import org.dromara.xg.domain.bo.XgClassTeacherCounselorRelBo;
|
||||||
|
import org.dromara.xg.domain.vo.XgClassMsgImportVo;
|
||||||
|
import org.dromara.xg.domain.vo.XgSysDeptVo;
|
||||||
|
import org.dromara.xg.mapper.XgClassMsgMapper;
|
||||||
|
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||||
|
import org.dromara.xg.mapper.XgSysUserMapper;
|
||||||
|
import org.dromara.xg.service.IXgClassMsgService;
|
||||||
|
import org.dromara.xg.service.IXgClassTeacherCounselorRelService;
|
||||||
|
import org.dromara.xg.service.IXgSysDeptService;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 班级信息导入监听器
|
||||||
|
*
|
||||||
|
* @author zlwu
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class XgClassMsgImportListener extends AnalysisEventListener<XgClassMsgImportVo>
|
||||||
|
implements ExcelListener<XgClassMsgImportVo> {
|
||||||
|
|
||||||
|
private final IXgClassMsgService classMsgService;
|
||||||
|
private final IXgSysDeptService deptService;
|
||||||
|
private final IXgClassTeacherCounselorRelService classTeacherCounselorRelService;
|
||||||
|
private final XgSysDeptMapper deptMapper;
|
||||||
|
private final XgClassMsgMapper classMsgMapper;
|
||||||
|
private final XgSysUserMapper sysUserMapper;
|
||||||
|
private final Long operUserId;
|
||||||
|
|
||||||
|
private int successNum = 0;
|
||||||
|
private int failureNum = 0;
|
||||||
|
private final StringBuilder successMsg = new StringBuilder();
|
||||||
|
private final StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
|
public XgClassMsgImportListener() {
|
||||||
|
this.classMsgService = SpringUtils.getBean(IXgClassMsgService.class);
|
||||||
|
this.deptService = SpringUtils.getBean(IXgSysDeptService.class);
|
||||||
|
this.classTeacherCounselorRelService = SpringUtils.getBean(IXgClassTeacherCounselorRelService.class);
|
||||||
|
this.deptMapper = SpringUtils.getBean(XgSysDeptMapper.class);
|
||||||
|
this.classMsgMapper = SpringUtils.getBean(XgClassMsgMapper.class);
|
||||||
|
this.sysUserMapper = SpringUtils.getBean(XgSysUserMapper.class);
|
||||||
|
this.operUserId = LoginHelper.getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(XgClassMsgImportVo importVo, AnalysisContext context) {
|
||||||
|
Integer rowIndex = context.readRowHolder().getRowIndex() + 1;
|
||||||
|
try {
|
||||||
|
if (isBlankRow(importVo)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 跳过模板自带的示例行
|
||||||
|
if (StringUtils.isNotBlank(importVo.getClassName()) && importVo.getClassName().startsWith("示例")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ValidatorUtils.validate(importVo);
|
||||||
|
|
||||||
|
Long collegeId = resolveCollegeId(importVo.getCollege());
|
||||||
|
XgSysDept college = deptMapper.selectById(collegeId);
|
||||||
|
if (college == null || !"0".equals(college.getDelFlag())) {
|
||||||
|
throw new ServiceException("学院不存在或已停用:" + importVo.getCollege());
|
||||||
|
}
|
||||||
|
if (college.getParentId() == null || college.getParentId() != 101L) {
|
||||||
|
throw new ServiceException("所选不是有效学院:" + importVo.getCollege());
|
||||||
|
}
|
||||||
|
|
||||||
|
Long majorId = resolveMajorId(importVo.getMajor(), collegeId);
|
||||||
|
XgSysDept major = deptMapper.selectById(majorId);
|
||||||
|
if (major == null || !"0".equals(major.getDelFlag())) {
|
||||||
|
throw new ServiceException("专业不存在或已停用:" + importVo.getMajor());
|
||||||
|
}
|
||||||
|
if (!collegeId.equals(major.getParentId())) {
|
||||||
|
throw new ServiceException("专业不属于所选学院,请重新从下拉框选择学院和专业");
|
||||||
|
}
|
||||||
|
|
||||||
|
String className = StringUtils.trim(importVo.getClassName());
|
||||||
|
LambdaQueryWrapper<XgClassMsg> existWrapper = Wrappers.lambdaQuery();
|
||||||
|
existWrapper.and(w -> w.eq(XgClassMsg::getClassName, className).or().eq(XgClassMsg::getClassCode, className));
|
||||||
|
Long existCount = classMsgMapper.selectCount(existWrapper);
|
||||||
|
if (existCount != null && existCount > 0) {
|
||||||
|
throw new ServiceException("班级名称已存在:" + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
XgClassMsgBo bo = new XgClassMsgBo();
|
||||||
|
bo.setCollegeId(collegeId);
|
||||||
|
bo.setCollegeName(college.getDeptName());
|
||||||
|
bo.setMajorId(majorId);
|
||||||
|
bo.setMajorName(major.getDeptName());
|
||||||
|
bo.setClassName(className);
|
||||||
|
bo.setClassCode(className);
|
||||||
|
bo.setClassType(importVo.getClassType());
|
||||||
|
bo.setGrade(StringUtils.trim(importVo.getGrade()));
|
||||||
|
bo.setEnrollmentYear(importVo.getEnrollmentYear());
|
||||||
|
bo.setSchoolSystem(importVo.getSchoolSystem());
|
||||||
|
// 统一按入学年份+学制计算,与模板公式一致
|
||||||
|
Long graduationYear = importVo.getEnrollmentYear() + importVo.getSchoolSystem();
|
||||||
|
bo.setGraduationYear(graduationYear);
|
||||||
|
bo.setIsGraduation(importVo.getIsGraduation());
|
||||||
|
bo.setClassLocation(importVo.getClassLocation());
|
||||||
|
bo.setClassStatus(importVo.getClassStatus());
|
||||||
|
bo.setClassDescription(importVo.getClassDescription());
|
||||||
|
bo.setRemark(importVo.getRemark());
|
||||||
|
bo.setCreateBy(operUserId);
|
||||||
|
|
||||||
|
classMsgService.insertByBo(bo);
|
||||||
|
|
||||||
|
String teacherTip = bindClassTeacherIfUnique(bo.getId(), importVo.getClassTeacherName());
|
||||||
|
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、第").append(rowIndex)
|
||||||
|
.append("行班级 ").append(className).append(" 导入成功");
|
||||||
|
if (StringUtils.isNotBlank(teacherTip)) {
|
||||||
|
successMsg.append("(").append(teacherTip).append(")");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = e.getMessage();
|
||||||
|
if (e instanceof ConstraintViolationException cvException) {
|
||||||
|
msg = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
|
||||||
|
}
|
||||||
|
String className = importVo == null ? "" : StringUtils.blankToDefault(importVo.getClassName(), "");
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、第").append(rowIndex)
|
||||||
|
.append("行班级 ").append(HtmlUtil.cleanHtmlTag(className)).append(" 导入失败:")
|
||||||
|
.append(HtmlUtil.cleanHtmlTag(StringUtils.blankToDefault(msg, e.getClass().getSimpleName())));
|
||||||
|
log.warn("班级信息导入失败,行号: {}, 原因: {}", rowIndex, msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按姓名匹配班主任:仅唯一命中时写入;空值/未匹配/多人同名均跳过,不影响班级保存。
|
||||||
|
*
|
||||||
|
* @return 提示文案,无需提示时返回空
|
||||||
|
*/
|
||||||
|
private String bindClassTeacherIfUnique(Long classId, String teacherNameRaw) {
|
||||||
|
String teacherName = StringUtils.trim(teacherNameRaw);
|
||||||
|
if (StringUtils.isBlank(teacherName) || classId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<XgSysUser> users = sysUserMapper.selectActiveStaffByNickName(teacherName);
|
||||||
|
if (users == null || users.isEmpty()) {
|
||||||
|
log.info("班级导入班主任未匹配到人员,classId={}, name={}", classId, teacherName);
|
||||||
|
return "班主任「" + teacherName + "」未匹配到人员,已跳过";
|
||||||
|
}
|
||||||
|
if (users.size() > 1) {
|
||||||
|
log.info("班级导入班主任姓名匹配到多人,跳过设置,classId={}, name={}, count={}",
|
||||||
|
classId, teacherName, users.size());
|
||||||
|
return "班主任「" + teacherName + "」匹配到多人,已跳过";
|
||||||
|
}
|
||||||
|
XgSysUser teacher = users.get(0);
|
||||||
|
XgClassTeacherCounselorRelBo relBo = new XgClassTeacherCounselorRelBo();
|
||||||
|
relBo.setClassId(classId);
|
||||||
|
relBo.setTeacherId(teacher.getUserId());
|
||||||
|
relBo.setTeacherName(teacher.getNickName());
|
||||||
|
relBo.setTeacherType("class_teacher");
|
||||||
|
relBo.setStartDate(new Date());
|
||||||
|
classTeacherCounselorRelService.insertByBo(relBo);
|
||||||
|
return "已设置班主任「" + teacher.getNickName() + "」";
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 班主任设置失败不影响班级导入结果
|
||||||
|
log.warn("班级导入后设置班主任失败,classId={}, name={}, cause={}", classId, teacherName, e.getMessage(), e);
|
||||||
|
return "班主任设置失败已跳过";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlankRow(XgClassMsgImportVo importVo) {
|
||||||
|
if (importVo == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 毕业年份、班主任为辅助字段,不参与空行判断
|
||||||
|
return StringUtils.isAllBlank(
|
||||||
|
importVo.getCollege(),
|
||||||
|
importVo.getMajor(),
|
||||||
|
importVo.getClassName(),
|
||||||
|
importVo.getClassType(),
|
||||||
|
importVo.getGrade(),
|
||||||
|
importVo.getClassStatus(),
|
||||||
|
importVo.getClassLocation(),
|
||||||
|
importVo.getClassDescription(),
|
||||||
|
importVo.getRemark()
|
||||||
|
) && importVo.getEnrollmentYear() == null
|
||||||
|
&& importVo.getSchoolSystem() == null
|
||||||
|
&& importVo.getIsGraduation() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveCollegeId(String optionValue) {
|
||||||
|
Long id = parseOptionId(optionValue);
|
||||||
|
if (id != null) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
String name = StringUtils.trim(optionValue);
|
||||||
|
return deptService.selectCollegeList().stream()
|
||||||
|
.filter(item -> name.equals(item.getDeptName()))
|
||||||
|
.map(XgSysDeptVo::getDeptId)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ServiceException("未找到学院:" + name + ",请从模板下拉框中选择"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveMajorId(String optionValue, Long collegeId) {
|
||||||
|
Long id = parseOptionId(optionValue);
|
||||||
|
if (id != null) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
String name = StringUtils.trim(optionValue);
|
||||||
|
return deptService.selectMajorListByCollegeId(collegeId).stream()
|
||||||
|
.filter(item -> name.equals(item.getDeptName()))
|
||||||
|
.map(XgSysDeptVo::getDeptId)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ServiceException("未找到专业:" + name + ",请从模板下拉框中选择"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容旧模板「名称_ID」格式;新模板仅名称时返回 null,改走名称匹配。
|
||||||
|
*/
|
||||||
|
private Long parseOptionId(String optionValue) {
|
||||||
|
String value = StringUtils.trim(optionValue);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
throw new ServiceException("学院/专业不能为空");
|
||||||
|
}
|
||||||
|
// 纯名称(无下划线)直接走名称匹配,避免误把名称解析为 ID
|
||||||
|
if (!value.contains("_")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<String> parts = DropDownOptions.analyzeOptionValue(value);
|
||||||
|
if (!parts.isEmpty()) {
|
||||||
|
String idStr = parts.get(parts.size() - 1);
|
||||||
|
if (NumberUtil.isLong(idStr)) {
|
||||||
|
return Long.parseLong(idStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExcelResult<XgClassMsgImportVo> getExcelResult() {
|
||||||
|
return new ExcelResult<>() {
|
||||||
|
@Override
|
||||||
|
public List<XgClassMsgImportVo> getList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getErrorList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAnalysis() {
|
||||||
|
if (failureNum > 0) {
|
||||||
|
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||||
|
throw new ServiceException(failureMsg.toString());
|
||||||
|
}
|
||||||
|
if (successNum == 0) {
|
||||||
|
throw new ServiceException("未读取到有效数据,请检查是否填写了班级信息");
|
||||||
|
}
|
||||||
|
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||||
|
return successMsg.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -28,4 +28,12 @@ public interface XgSysUserMapper extends BaseMapperPlus<XgSysUser, XgSysUser> {
|
|||||||
*/
|
*/
|
||||||
List<XgSysUser> selectActiveUserListByAccountType(String accountType);
|
List<XgSysUser> selectActiveUserListByAccountType(String accountType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按昵称精确匹配有效教职工
|
||||||
|
*
|
||||||
|
* @param nickName 用户昵称(姓名)
|
||||||
|
* @return 匹配用户列表
|
||||||
|
*/
|
||||||
|
List<XgSysUser> selectActiveStaffByNickName(String nickName);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -34,4 +34,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
order by user_name asc, create_time desc
|
order by user_name asc, create_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 按昵称精确匹配有效教职工(account_type=1) -->
|
||||||
|
<select id="selectActiveStaffByNickName" parameterType="String" resultMap="XgSysUserResult">
|
||||||
|
select user_id, user_name, nick_name, phonenumber, account_type
|
||||||
|
from sys_user
|
||||||
|
where status = '0' and del_flag = '0' and account_type = '1'
|
||||||
|
and nick_name = #{nickName}
|
||||||
|
order by user_id asc
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
| [学生信息收集批次管理API](./学生信息收集批次管理API.md) | 学生信息收集批次班级权限管理 | ✅ 完成 | 2025-01-27 |
|
| [学生信息收集批次管理API](./学生信息收集批次管理API.md) | 学生信息收集批次班级权限管理 | ✅ 完成 | 2025-01-27 |
|
||||||
| [学生信息批次收集API](./学生信息批次收集API.md) | 学生信息批次收集管理(新增) | ✅ 完成 | 2025-01-27 |
|
| [学生信息批次收集API](./学生信息批次收集API.md) | 学生信息批次收集管理(新增) | ✅ 完成 | 2025-01-27 |
|
||||||
| [学生学籍异动与换班级API](./学生学籍异动与换班级API.md) | 学籍异动与换班级(含复学+换班级事务接口) | ✅ 完成 | 2026-03-13 |
|
| [学生学籍异动与换班级API](./学生学籍异动与换班级API.md) | 学籍异动与换班级(含复学+换班级事务接口) | ✅ 完成 | 2026-03-13 |
|
||||||
| [班级信息管理API](./班级信息管理API.md) | 班级基础信息增删改查 | ✅ 完成 | 2025-01-27 |
|
| [班级信息管理API](./班级信息管理API.md) | 班级基础信息增删改查、Excel导入(字典下拉+学院专业联动) | ✅ 完成 | 2026-07-22 |
|
||||||
| [二级学院管理API](./二级学院管理API.md) | 二级学院组织信息管理 | ✅ 完成 | 2025-12-26 |
|
| [二级学院管理API](./二级学院管理API.md) | 二级学院组织信息管理 | ✅ 完成 | 2025-12-26 |
|
||||||
| [专业信息管理API](./专业信息管理API.md) | 专业信息管理(树形菜单+列表) | ✅ 完成 | 2025-12-26 |
|
| [专业信息管理API](./专业信息管理API.md) | 专业信息管理(树形菜单+列表) | ✅ 完成 | 2025-12-26 |
|
||||||
| [班级干部信息管理API](./班级干部信息管理API.md) | 班级干部信息管理(含用户角色关联) | ✅ 完成 | 2025-01-27 |
|
| [班级干部信息管理API](./班级干部信息管理API.md) | 班级干部信息管理(含用户角色关联) | ✅ 完成 | 2025-01-27 |
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# 班级信息管理 API
|
||||||
|
|
||||||
|
**模块名称**:classMsg / 班级信息
|
||||||
|
**基础路径**:`/classMsg/classMsg`
|
||||||
|
**更新时间**:2026-07-22
|
||||||
|
|
||||||
|
## 模块功能
|
||||||
|
|
||||||
|
班级基础信息的增删改查、状态批量变更,以及 Excel 批量导入(模板含字典下拉、学院-专业联动下拉)。
|
||||||
|
|
||||||
|
## 导入相关接口
|
||||||
|
|
||||||
|
### 1. 下载导入模板
|
||||||
|
|
||||||
|
- **URL**:`POST /classMsg/classMsg/importTemplate`
|
||||||
|
- **说明**:生成带下拉校验的 Excel 模板
|
||||||
|
- **模板列**:
|
||||||
|
|
||||||
|
| 列名 | 填写方式 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| 学院 | 下拉(联动) | 仅显示学院名称,请从下拉选择;列已加宽 |
|
||||||
|
| 专业 | 下拉(联动) | 随学院变化,仅显示专业名称;列已加宽 |
|
||||||
|
| 班级名称 | 文本 | 必填;同时作为班级代码写入系统 |
|
||||||
|
| 学历层级 | 字典下拉 | `zsjy_education_level` 中文标签;列已加宽 |
|
||||||
|
| 年级 | 文本 | 如当前年份 |
|
||||||
|
| 入学年份 | 数字 | 如当前年份 |
|
||||||
|
| 学制(年) | 下拉 | 常见值 2/3/4/5/6 |
|
||||||
|
| 毕业年份 | 公式自动计算 | Excel 公式:`入学年份+学制`;导入时同样按此规则计算 |
|
||||||
|
| 是否已毕业 | 字典下拉 | `is_graduation`(未毕业/已毕业) |
|
||||||
|
| 班级教室位置 | 文本 | 可选 |
|
||||||
|
| 班级状态 | 字典下拉 | `xg_class_status`(正常/暂停/毕业/解散) |
|
||||||
|
| 班主任 | 文本(姓名) | 选填;按教职工姓名精确匹配。唯一命中才写入;未匹配或多人同名则跳过,**不影响班级保存** |
|
||||||
|
| 班级描述 | 文本 | 可选 |
|
||||||
|
| 备注信息 | 文本 | 可选 |
|
||||||
|
|
||||||
|
- **注意**:
|
||||||
|
- 模板首行示例数据以「示例」开头,导入时会自动跳过
|
||||||
|
- 学院、专业、字典项请务必从下拉框选择,避免手填错误
|
||||||
|
- 班主任匹配失败不会导致该行班级导入失败,可事后在列表中单独设置
|
||||||
|
|
||||||
|
### 2. 导入班级数据
|
||||||
|
|
||||||
|
- **URL**:`POST /classMsg/classMsg/importData`
|
||||||
|
- **Content-Type**:`multipart/form-data`
|
||||||
|
- **参数**:`file`(Excel 文件)
|
||||||
|
- **成功响应**:`R`,`msg` 为导入成功明细(HTML,含班主任匹配提示)
|
||||||
|
- **失败响应**:抛出业务异常,`msg` 含失败行号与原因
|
||||||
|
- **处理逻辑**:
|
||||||
|
1. 解析学院/专业名称,并校验专业属于所选学院
|
||||||
|
2. 字典中文标签自动转换为字典值
|
||||||
|
3. 班级名称作为 `classCode` / `className`,重复则该行失败
|
||||||
|
4. 毕业年份按 `入学年份 + 学制` 自动计算
|
||||||
|
5. 调用既有新增逻辑,同步创建对应 `sys_dept` 班级节点
|
||||||
|
6. 班主任按姓名匹配有效教职工:0 人或多人 → 不写班主任;1 人 → 写入并同步关联/角色
|
||||||
|
|
||||||
|
## 其他已有接口(摘要)
|
||||||
|
|
||||||
|
| 接口 | 方法 | 路径 |
|
||||||
|
|------|------|------|
|
||||||
|
| 分页列表 | GET | `/classMsg/classMsg/list` |
|
||||||
|
| 详情 | GET | `/classMsg/classMsg/{id}` |
|
||||||
|
| 新增 | POST | `/classMsg/classMsg` |
|
||||||
|
| 修改 | PUT | `/classMsg/classMsg` |
|
||||||
|
| 删除 | DELETE | `/classMsg/classMsg/{ids}` |
|
||||||
|
| 更新状态 | PUT | `/classMsg/classMsg/status` |
|
||||||
|
| 批量更新状态 | PUT | `/classMsg/classMsg/status/batch` |
|
||||||
|
| 导出 | POST | `/classMsg/classMsg/export` |
|
||||||
|
| 我作为班主任的班级 | GET | `/classMsg/classMsg/myClassListAsTeacher` |
|
||||||
|
|
||||||
|
## 前端入口
|
||||||
|
|
||||||
|
- 页面:`web/src/views/xg/xsjcxx/classmsg/classMsg/index.vue`
|
||||||
|
- 操作:工具栏「导入」→ 下载模板 / 上传 Excel
|
||||||
@@ -49,6 +49,17 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['classMsg:classMsg:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['classMsg:classMsg:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-dropdown v-hasPermi="['classMsg:classMsg:add']" split-button type="info" plain @click="handleImport">
|
||||||
|
导入
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
|
||||||
|
<el-dropdown-item icon="Upload" @click="handleImport">导入数据</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['classMsg:classMsg:edit']"
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['classMsg:classMsg:edit']"
|
||||||
>修改</el-button
|
>修改</el-button
|
||||||
@@ -194,13 +205,13 @@
|
|||||||
<el-input v-model="form.grade" placeholder="请输入年级" />
|
<el-input v-model="form.grade" placeholder="请输入年级" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="入学年份" prop="enrollmentYear">
|
<el-form-item label="入学年份" prop="enrollmentYear">
|
||||||
<el-input v-model="form.enrollmentYear" placeholder="请输入入学年份" />
|
<el-input v-model="form.enrollmentYear" placeholder="请输入入学年份" @input="syncGraduationYear" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="学制(年)" prop="schoolSystem">
|
<el-form-item label="学制(年)" prop="schoolSystem">
|
||||||
<el-input v-model="form.schoolSystem" placeholder="请输入学制(年)" />
|
<el-input v-model="form.schoolSystem" placeholder="请输入学制(年)" @input="syncGraduationYear" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="毕业年份" prop="graduationYear">
|
<el-form-item label="毕业年份" prop="graduationYear">
|
||||||
<el-input v-model="form.graduationYear" placeholder="请输入毕业年份" />
|
<el-input v-model="form.graduationYear" placeholder="入学年份+学制自动计算,可修改" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="辅导员ID" prop="counselorId" v-if="false">
|
<el-form-item label="辅导员ID" prop="counselorId" v-if="false">
|
||||||
<el-input v-model="form.counselorId" placeholder="请输入辅导员ID" />
|
<el-input v-model="form.counselorId" placeholder="请输入辅导员ID" />
|
||||||
@@ -386,6 +397,41 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 班级信息导入对话框 -->
|
||||||
|
<el-dialog v-model="upload.open" :title="upload.title" width="420px" append-to-body>
|
||||||
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
:limit="1"
|
||||||
|
accept=".xlsx, .xls"
|
||||||
|
:headers="upload.headers"
|
||||||
|
:action="upload.url"
|
||||||
|
:disabled="upload.isUploading"
|
||||||
|
:on-progress="handleFileUploadProgress"
|
||||||
|
:on-success="handleFileSuccess"
|
||||||
|
:on-error="handleFileError"
|
||||||
|
:auto-upload="false"
|
||||||
|
drag
|
||||||
|
>
|
||||||
|
<el-icon class="el-icon--upload"><i-ep-upload-filled /></el-icon>
|
||||||
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip text-center">
|
||||||
|
<div>请先下载模板,通过下拉框选择学院、专业及字典项后上传。</div>
|
||||||
|
<span>仅允许导入 xls、xlsx 格式文件。</span>
|
||||||
|
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">
|
||||||
|
下载模板
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" :loading="upload.isUploading" @click="submitFileForm">确 定</el-button>
|
||||||
|
<el-button @click="upload.open = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 设置辅导员对话框 -->
|
<!-- 设置辅导员对话框 -->
|
||||||
<el-dialog title="设置辅导员" v-model="counselorDialog.visible" width="500px" append-to-body>
|
<el-dialog title="设置辅导员" v-model="counselorDialog.visible" width="500px" append-to-body>
|
||||||
<el-descriptions title="班级信息" :column="1" border>
|
<el-descriptions title="班级信息" :column="1" border>
|
||||||
@@ -446,7 +492,9 @@ import {
|
|||||||
import { listColleges, collegeTree, listMajorsByCollegeId } from '@/api/xg/xsjcxx/classmsg/college';
|
import { listColleges, collegeTree, listMajorsByCollegeId } from '@/api/xg/xsjcxx/classmsg/college';
|
||||||
import { ClassMsgVO, ClassMsgQuery, ClassMsgForm, SysDeptVo } from '@/api/xg/xsjcxx/classmsg/types';
|
import { ClassMsgVO, ClassMsgQuery, ClassMsgForm, SysDeptVo } from '@/api/xg/xsjcxx/classmsg/types';
|
||||||
import { ComponentInternalInstance, ref, reactive, toRefs, onMounted, getCurrentInstance, watch } from 'vue';
|
import { ComponentInternalInstance, ref, reactive, toRefs, onMounted, getCurrentInstance, watch } from 'vue';
|
||||||
import type { FormInstance as ElFormInstance } from 'element-plus';
|
import type { FormInstance as ElFormInstance, UploadFile, UploadInstance } from 'element-plus';
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import { globalHeaders } from '@/utils/request';
|
||||||
import { getActiveUserList } from '@/api/xg/sysUser'; // 添加用户API导入
|
import { getActiveUserList } from '@/api/xg/sysUser'; // 添加用户API导入
|
||||||
import { addClassTeacherCounselorRel, updateClassTeacherCounselorRel } from '@/api/xg/classTeacherCounselorRel'; // 添加班级辅导员关联API导入
|
import { addClassTeacherCounselorRel, updateClassTeacherCounselorRel } from '@/api/xg/classTeacherCounselorRel'; // 添加班级辅导员关联API导入
|
||||||
|
|
||||||
@@ -526,6 +574,16 @@ const collegeTreeData = ref<SysDeptVo[]>([]); // 学院专业树形数据
|
|||||||
|
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const classMsgFormRef = ref<ElFormInstance>();
|
const classMsgFormRef = ref<ElFormInstance>();
|
||||||
|
const uploadRef = ref<UploadInstance>();
|
||||||
|
|
||||||
|
/** 班级导入参数 */
|
||||||
|
const upload = reactive({
|
||||||
|
open: false,
|
||||||
|
title: '',
|
||||||
|
isUploading: false,
|
||||||
|
headers: globalHeaders(),
|
||||||
|
url: import.meta.env.VITE_APP_BASE_API + '/classMsg/classMsg/importData'
|
||||||
|
});
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -705,6 +763,15 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 根据入学年份 + 学制自动计算毕业年份 */
|
||||||
|
const syncGraduationYear = () => {
|
||||||
|
const enrollmentYear = Number(form.value.enrollmentYear);
|
||||||
|
const schoolSystem = Number(form.value.schoolSystem);
|
||||||
|
if (Number.isFinite(enrollmentYear) && Number.isFinite(schoolSystem) && schoolSystem > 0) {
|
||||||
|
form.value.graduationYear = enrollmentYear + schoolSystem;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
@@ -744,6 +811,46 @@ const handleAdd = () => {
|
|||||||
dialog.title = '添加班级信息';
|
dialog.title = '添加班级信息';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 导入按钮操作 */
|
||||||
|
const handleImport = () => {
|
||||||
|
upload.title = '班级信息导入';
|
||||||
|
upload.open = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 下载导入模板 */
|
||||||
|
const importTemplate = () => {
|
||||||
|
proxy?.download('classMsg/classMsg/importTemplate', {}, `班级信息导入模板_${new Date().getTime()}.xlsx`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 文件上传中处理 */
|
||||||
|
const handleFileUploadProgress = () => {
|
||||||
|
upload.isUploading = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 文件上传成功处理 */
|
||||||
|
const handleFileSuccess = (response: any, file: UploadFile) => {
|
||||||
|
upload.open = false;
|
||||||
|
upload.isUploading = false;
|
||||||
|
uploadRef.value?.handleRemove(file);
|
||||||
|
ElMessageBox.alert(
|
||||||
|
"<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + (response.msg || '导入完成') + '</div>',
|
||||||
|
'导入结果',
|
||||||
|
{ dangerouslyUseHTMLString: true }
|
||||||
|
);
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 文件上传失败处理 */
|
||||||
|
const handleFileError = () => {
|
||||||
|
upload.isUploading = false;
|
||||||
|
proxy?.$modal.msgError('导入失败,请检查文件格式或网络连接');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交上传文件 */
|
||||||
|
const submitFileForm = () => {
|
||||||
|
uploadRef.value?.submit();
|
||||||
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: ClassMsgVO) => {
|
const handleUpdate = async (row?: ClassMsgVO) => {
|
||||||
reset();
|
reset();
|
||||||
|
|||||||
Reference in new issue
Block a user