From e60161f7b9f7d1e3c24d3e3e99e548a88e776db2 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Sat, 16 Aug 2025 14:51:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/XgDormViolationController.java | 73 ++++++++++ .../xg/domain/vo/XgDormViolationImportVo.java | 96 +++++++++++++ .../xg/service/IXgDormViolationService.java | 11 ++ .../impl/XgDormViolationServiceImpl.java | 92 ++++++++++++ .../dormViolation/dormViolation/index.vue | 136 +++++++++++++++++- 5 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormViolationImportVo.java diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormViolationController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormViolationController.java index c7ec24b7..9d22ce90 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormViolationController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormViolationController.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; @@ -23,9 +24,12 @@ import org.dromara.xg.domain.vo.XgDormViolationVo; import org.dromara.xg.domain.bo.XgDormViolationBo; import org.dromara.xg.domain.vo.StudentOptionVo; import org.dromara.xg.domain.vo.XgDormViolationExportVo; +import org.dromara.xg.domain.vo.XgDormViolationImportVo; import org.dromara.xg.domain.bo.StudentOptionBo; import org.dromara.xg.service.IXgDormViolationService; +import org.springframework.web.multipart.MultipartFile; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; /** * 宿舍违纪记录 @@ -37,6 +41,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; @RequiredArgsConstructor @RestController @RequestMapping("/dormViolation/dormViolation") +@Slf4j public class XgDormViolationController extends BaseController { private final IXgDormViolationService xgDormViolationService; @@ -131,4 +136,72 @@ public class XgDormViolationController extends BaseController { public R getStudentById(@NotNull(message = "学生ID不能为空") @PathVariable Long studentId) { return R.ok(xgDormViolationService.getStudentById(studentId)); } + + /** + * 下载宿舍违纪记录导入模板 + */ + @Log(title = "宿舍违纪记录", businessType = BusinessType.EXPORT) + @SaCheckPermission("dormViolation:dormViolation:import") + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + // ExcelUtil.exportExcel( + // List.of(new XgDormViolationImportVo()), + // "宿舍违纪记录", + // XgDormViolationImportVo.class, + // response); + try { + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = "宿舍违纪信息导入模板.xlsx"; + fileName = java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", + "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + + fileName); + + // 读取模板文件 + org.springframework.core.io.Resource resource = new org.springframework.core.io.ClassPathResource( + "dormViolation_template.xlsx"); + java.io.InputStream inputStream = resource.getInputStream(); + java.io.OutputStream outputStream = response.getOutputStream(); + + // 复制文件内容到响应流 + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + // 关闭流 + inputStream.close(); + outputStream.flush(); + outputStream.close(); + + } catch (Exception e) { + log.error("宿舍违纪信息导入模板失败", e); + try { + response.setContentType("text/html;charset=utf-8"); + response.getWriter().write("下载模板失败:" + e.getMessage()); + } catch (Exception ex) { + log.error("写入错误响应失败", ex); + } + } + } + + /** + * 导入宿舍违纪记录数据 + * + * @param file Excel文件 + * @param updateSupport 是否更新支持,如果已存在,则进行更新数据 + */ + @Log(title = "宿舍违纪记录", businessType = BusinessType.IMPORT) + @SaCheckPermission("dormViolation:dormViolation:import") + @PostMapping("/importData") + public R importData(MultipartFile file, boolean updateSupport) throws Exception { + List violationList = ExcelUtil.importExcel(file.getInputStream(), + XgDormViolationImportVo.class); + String operName = LoginHelper.getUsername(); + String message = xgDormViolationService.importDormViolation(violationList, updateSupport, operName); + return R.ok(message); + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormViolationImportVo.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormViolationImportVo.java new file mode 100644 index 00000000..41453ec4 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormViolationImportVo.java @@ -0,0 +1,96 @@ +package org.dromara.xg.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 宿舍违纪记录导入视图对象 xg_dorm_violation_import + * + * @author zlwu + * @date 2025-01-31 + */ +@Data +@ExcelIgnoreUnannotated +public class XgDormViolationImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 学生姓名 + */ + @NotBlank(message = "学生姓名不能为空") + @ExcelProperty(value = "学生姓名") + private String studentName; + + /** + * 学号 + */ + @NotBlank(message = "学号不能为空") + @ExcelProperty(value = "学号") + private String studentNo; + + /** + * 学院名称 + */ + @ExcelProperty(value = "学院名称") + private String collegeName; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 违纪类型 + */ + @NotBlank(message = "违纪类型不能为空") + @ExcelProperty(value = "违纪类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "dorm_violation_type") + private String violationType; + + /** + * 违纪等级 + */ + @NotBlank(message = "违纪等级不能为空") + @ExcelProperty(value = "违纪等级", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "dorm_violation_level") + private String violationLevel; + + /** + * 违纪发生时间 + */ + @NotNull(message = "违纪发生时间不能为空") + @ExcelProperty(value = "违纪发生时间") + private Date violationTime; + + /** + * 违纪行为描述 + */ + @NotBlank(message = "违纪行为描述不能为空") + @ExcelProperty(value = "违纪行为描述") + private String violationDescription; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormViolationService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormViolationService.java index 0d4b2783..41336518 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormViolationService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormViolationService.java @@ -4,6 +4,7 @@ import org.dromara.xg.domain.vo.XgDormViolationVo; import org.dromara.xg.domain.bo.XgDormViolationBo; import org.dromara.xg.domain.vo.StudentOptionVo; import org.dromara.xg.domain.bo.StudentOptionBo; +import org.dromara.xg.domain.vo.XgDormViolationImportVo; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; @@ -92,4 +93,14 @@ public interface IXgDormViolationService { * @return 学生详细信息 */ StudentOptionVo getStudentByStudentNo(String studentNo); + + /** + * 导入宿舍违纪记录数据 + * + * @param importList 导入的宿舍违纪记录列表 + * @param isUpdateSupport 是否支持更新已存在的记录 + * @param operName 操作人员名称 + * @return 导入结果信息 + */ + String importDormViolation(List importList, boolean isUpdateSupport, String operName); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormViolationServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormViolationServiceImpl.java index 2d415c44..83c9ad67 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormViolationServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormViolationServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.xg.service.impl; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; +import cn.hutool.core.util.ObjectUtil; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -14,6 +15,7 @@ import org.dromara.xg.domain.bo.XgDormViolationBo; import org.dromara.xg.domain.vo.XgDormViolationVo; import org.dromara.xg.domain.bo.StudentOptionBo; import org.dromara.xg.domain.vo.StudentOptionVo; +import org.dromara.xg.domain.vo.XgDormViolationImportVo; import org.dromara.xg.domain.XgDormViolation; import org.dromara.xg.mapper.XgDormViolationMapper; import org.dromara.xg.service.IXgDormViolationService; @@ -195,4 +197,94 @@ public class XgDormViolationServiceImpl implements IXgDormViolationService { public StudentOptionVo getStudentByStudentNo(String studentNo) { return baseMapper.selectStudentByStudentNo(studentNo); } + + /** + * 导入宿舍违纪记录数据 + * + * @param importList 导入的宿舍违纪记录列表 + * @param isUpdateSupport 是否支持更新已存在的记录 + * @param operName 操作人员名称 + * @return 导入结果信息 + */ + @Override + public String importDormViolation(List importList, boolean isUpdateSupport, + String operName) { + if (ObjectUtil.isNull(importList) || importList.isEmpty()) { + throw new RuntimeException("导入宿舍违纪记录数据不能为空!"); + } + + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + + for (XgDormViolationImportVo importVo : importList) { + try { + // 通过学号查询学生信息 + StudentOptionVo student = this.getStudentByStudentNo(importVo.getStudentNo()); + if (student == null) { + failureNum++; + String msg = "
" + failureNum + "、学号 " + importVo.getStudentNo() + " 的学生信息不存在"; + failureMsg.append(msg); + continue; + } + + // 验证学生姓名是否匹配 + // if (!student.getStudentName().equals(importVo.getStudentName())) { + // failureNum++; + // String msg = "
" + failureNum + "、学号 " + importVo.getStudentNo() + " + // 对应的学生姓名不匹配,数据库中为:" + // + student.getStudentName() + ",导入数据为:" + importVo.getStudentName(); + // failureMsg.append(msg); + // continue; + // } + + // 创建宿舍违纪记录 + XgDormViolation violation = new XgDormViolation(); + violation.setStudentId(student.getId()); + violation.setStudentName(student.getName()); + violation.setStudentNo(student.getStudentNo()); + violation.setCollegeId(student.getCollegeId()); + violation.setCollegeName(student.getCollegeName()); + violation.setMajorId(student.getMajorId()); + violation.setMajorName(student.getMajorName()); + violation.setClassId(student.getClassId()); + violation.setClassName(student.getClassName()); + violation.setCampusId(student.getDormInfo().getCampusId()); + violation.setCampusName(student.getDormInfo().getCampusName()); + violation.setAreaId(student.getDormInfo().getAreaId()); + violation.setAreaName(student.getDormInfo().getAreaName()); + violation.setBuildingId(student.getDormInfo().getBuildingId()); + violation.setBuildingName(student.getDormInfo().getBuildingName()); + violation.setRoomId(student.getDormInfo().getRoomId()); + violation.setRoomName(student.getDormInfo().getRoomName()); + violation.setBedId(student.getDormInfo().getBedId()); + violation.setBedName(student.getDormInfo().getBedName()); + violation.setViolationType(importVo.getViolationType()); + violation.setViolationLevel(importVo.getViolationLevel()); + violation.setViolationTime(importVo.getViolationTime()); + violation.setViolationDescription(importVo.getViolationDescription()); + violation.setRemark(importVo.getRemark()); + + // 插入数据 + baseMapper.insert(violation); + successNum++; + successMsg.append("
" + successNum + "、学号 " + importVo.getStudentNo() + " 的宿舍违纪记录导入成功"); + + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、学号 " + importVo.getStudentNo() + " 导入失败:" + e.getMessage(); + failureMsg.append(msg); + log.error("导入宿舍违纪记录失败", e); + } + } + + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new RuntimeException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } } diff --git a/web/src/views/xg/xgss/dormViolation/dormViolation/index.vue b/web/src/views/xg/xgss/dormViolation/dormViolation/index.vue index 8a651e7c..8aec0707 100644 --- a/web/src/views/xg/xgss/dormViolation/dormViolation/index.vue +++ b/web/src/views/xg/xgss/dormViolation/dormViolation/index.vue @@ -120,6 +120,20 @@ 导出 + + + + 更多 + + + + + @@ -551,6 +565,41 @@ + + + + + + + +
将文件拖到此处,或点击上传
+ +
+ +
@@ -559,10 +608,11 @@ import { ref, reactive, toRefs, onMounted, getCurrentInstance, ComponentInternal import ElMessage from 'element-plus/es/components/message/index'; import ElMessageBox from 'element-plus/es/components/message-box/index'; import ElLoading from 'element-plus/es/components/loading/index'; -import { UploadFilled, Document, Loading, Download, Delete, InfoFilled } from '@element-plus/icons-vue'; +import { UploadFilled, Document, Loading, Download, Delete, InfoFilled, ArrowDown } from '@element-plus/icons-vue'; import { getToken } from '@/utils/auth'; import ImagePreview from '@/components/ImagePreview/index.vue'; import request from '@/utils/request'; +import { globalHeaders } from '@/utils/request'; import { listDormViolation, getDormViolation, @@ -709,12 +759,29 @@ const attachmentList = ref([]); const queryFormRef = ref(); const dormViolationFormRef = ref(); +const uploadRef = ref(); const dialog = reactive({ visible: false, title: '' }); +// 导入参数 +const upload = reactive({ + // 是否显示弹出层 + open: false, + // 弹出层标题 + title: '', + // 是否禁用上传 + isUploading: false, + // 是否更新已经存在的数据 + updateSupport: false, + // 设置上传的请求头部 + headers: globalHeaders(), + // 上传的地址 + url: import.meta.env.VITE_APP_BASE_API + '/dormViolation/dormViolation/importData' +}); + const initFormData: DormViolationForm = { id: undefined, studentId: undefined, @@ -999,6 +1066,73 @@ const handleExport = () => { ); }; +/** 导入按钮操作 */ +const handleImport = () => { + upload.title = '宿舍违纪导入'; + upload.open = true; +}; + +/** 下载模板操作 */ +const importTemplate = () => { + proxy?.download('dormViolation/dormViolation/importTemplate', {}, `宿舍违纪导入模板_${new Date().getTime()}.xlsx`); +}; + +/** 文件上传中处理 */ +const handleFileUploadProgress = () => { + upload.isUploading = true; +}; + +/** 文件上传成功处理 */ +const handleFileSuccess = (response: any) => { + upload.open = false; + upload.isUploading = false; + uploadRef.value?.clearFiles(); + + // 关闭所有loading消息 + ElMessage.closeAll(); + + ElMessageBox.alert("
" + response.msg + '
', '导入结果', { + dangerouslyUseHTMLString: true + }); + getList(); +}; + +/** 文件上传失败处理 */ +const handleFileError = (error: any) => { + upload.isUploading = false; + uploadRef.value?.clearFiles(); + + // 关闭所有loading消息 + ElMessage.closeAll(); + + console.error('文件上传失败:', error); + ElMessage.error('导入失败,请检查文件格式或网络连接'); +}; + +/** 获取导入URL */ +const getImportUrl = () => { + const baseUrl = upload.url; + const params = new URLSearchParams(); + params.append('updateSupport', 'false'); + return `${baseUrl}?${params.toString()}`; +}; + +/** 提交上传文件 */ +const submitFileForm = () => { + // 显示导入loading效果 + ElMessage({ + message: '正在导入数据,请耐心等待...', + type: 'info', + duration: 0 + }); + + // 设置上传中状态 + upload.isUploading = true; + + // 提交文件上传 + uploadRef.value?.submit(); +}; + /** 远程搜索学生 */ const remoteSearchStudents = async (query: string) => { studentLoading.value = true;