From f5a5c89ee3d2094d94cf57985f11541a0024eba2 Mon Sep 17 00:00:00 2001 From: zhaichao Date: Sun, 20 Sep 2026 15:24:07 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=94=E6=95=99=E7=BC=96=E8=BE=91=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/jwgl/DownloadController.java | 63 ++++++++++++++++++- .../framework/config/JacksonConfig.java | 37 +++++++++++ .../jwgl/service/impl/LogServiceImpl.java | 48 ++++++++++++-- frontend/src/api/classHour/jointTraining.js | 4 +- .../views/classHour/jointTraining/index.vue | 6 +- .../views/student/warningCondition/index.vue | 28 ++++++--- 6 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 backend/roomroot-framework/src/main/java/com/roomroot/framework/config/JacksonConfig.java diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/DownloadController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/DownloadController.java index 1ab621dd0..ff24c9416 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/DownloadController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/DownloadController.java @@ -163,11 +163,70 @@ public class DownloadController { } /** - * 联教连训管理模板 + * 联教联训导入模板(动态生成:宋体表头 + 测试样例)。 + * 列序与 ExcelParseUtil.parseKSBZXMExcel 一致。 */ @GetMapping("/joint-training") public void downloadJointTraining(HttpServletResponse response) throws IOException { - downloadTemplate(response, "联教连训管理.xls"); + org.apache.poi.ss.usermodel.Workbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(); + try { + org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont(); + headerFont.setFontName("宋体"); + headerFont.setBold(true); + headerFont.setFontHeightInPoints((short) 11); + org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle(); + headerStyle.setFont(headerFont); + + org.apache.poi.ss.usermodel.Font dataFont = workbook.createFont(); + dataFont.setFontName("宋体"); + dataFont.setFontHeightInPoints((short) 11); + org.apache.poi.ss.usermodel.CellStyle dataStyle = workbook.createCellStyle(); + dataStyle.setFont(dataFont); + + String[] headers = { + "序号", "补助项目名称", "性质", "依据", "开始日期", "结束日期", + "项目说明", "项目备注", "教研室名称", "补助教员姓名", "补助课时量", "课时量备注" + }; + org.apache.poi.ss.usermodel.Sheet sheet = workbook.createSheet("联教联训"); + org.apache.poi.ss.usermodel.Row headerRow = sheet.createRow(0); + for (int i = 0; i < headers.length; i++) { + org.apache.poi.ss.usermodel.Cell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(headerStyle); + sheet.setColumnWidth(i, 18 * 256); + } + + String[][] samples = { + {"1", "联教联训测试项目甲", "集中", "训练计划〔2026〕1号", "2026-03-01", "2026-03-10", + "联合教学演练", "导入测试样例1", "战术教研室", "张三", "16", "含备课课时"}, + {"2", "联教联训测试项目乙", "分散", "训练计划〔2026〕2号", "2026-05-08", "2026-05-20", + "跨校区联训", "导入测试样例2", "射击教研室", "李四", "24", ""}, + {"3", "联教联训测试项目丙", "集中", "训练计划〔2026〕3号", "2026-09-01", "2026-09-15", + "联训考核", "导入测试样例3", "指挥教研室", "王五", "12", "按天数核算"} + }; + for (int r = 0; r < samples.length; r++) { + org.apache.poi.ss.usermodel.Row row = sheet.createRow(r + 1); + for (int c = 0; c < samples[r].length; c++) { + org.apache.poi.ss.usermodel.Cell cell = row.createCell(c); + cell.setCellValue(samples[r][c]); + cell.setCellStyle(dataStyle); + } + } + + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + FileUtils.setAttachmentResponseHeader(response, "联教联训数据文件模板.xlsx"); + workbook.write(response.getOutputStream()); + response.getOutputStream().flush(); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new ServiceException("生成联教联训导入模板失败:" + e.getMessage()); + } finally { + try { + workbook.close(); + } catch (IOException ignored) { + } + } } /** diff --git a/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/JacksonConfig.java b/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/JacksonConfig.java new file mode 100644 index 000000000..f1846b3e3 --- /dev/null +++ b/backend/roomroot-framework/src/main/java/com/roomroot/framework/config/JacksonConfig.java @@ -0,0 +1,37 @@ +package com.roomroot.framework.config; + +import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.module.SimpleModule; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; + +/** + * 兼容前端常用的 {@code yyyy-MM-dd HH:mm:ss} 与 ISO {@code yyyy-MM-ddTHH:mm:ss}。 + */ +@Configuration +public class JacksonConfig { + + @Bean + public JsonMapperBuilderCustomizer flexibleLocalDateTimeCustomizer() { + DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .optionalStart() + .optionalStart().appendLiteral('T').optionalEnd() + .optionalStart().appendLiteral(' ').optionalEnd() + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .optionalEnd() + .toFormatter(); + return (JsonMapper.Builder builder) -> { + SimpleModule module = new SimpleModule("FlexibleLocalDateTime"); + module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.addModule(module); + }; + } +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/LogServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/LogServiceImpl.java index 79907eb15..6d84be144 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/LogServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/LogServiceImpl.java @@ -577,6 +577,7 @@ public class LogServiceImpl implements LogService { @Override @Transactional public void addSubsidyProject(KSBZXM entity) { + fillSubsidyProjectDefaults(entity); entity.setCjsj(LocalDateTime.now()); entity.setXgsj(LocalDateTime.now()); ksbzxmMapper.insert(entity); @@ -622,12 +623,7 @@ public class LogServiceImpl implements LogService { } LocalDateTime now = LocalDateTime.now(); for (KSBZXM entity : list) { - if (entity.getBh() == null || entity.getBh().isEmpty()) { - entity.setBh(com.roomroot.jwgl.utils.UuidUtil.getUUID()); - } - if (entity.getXmlx() == null || entity.getXmlx().isEmpty()) { - entity.setXmlx("联教联训"); - } + fillSubsidyProjectDefaults(entity); entity.setCjsj(now); entity.setXgsj(now); ksbzxmMapper.insert(entity); @@ -635,6 +631,46 @@ public class LogServiceImpl implements LogService { return list.size(); } + /** 课时补助项目非空列兜底。达梦空串等同 NULL。 */ + private void fillSubsidyProjectDefaults(KSBZXM entity) { + if (entity.getBh() == null || entity.getBh().trim().isEmpty()) { + entity.setBh(UuidUtil.getUUID()); + } + if (entity.getMc() == null || entity.getMc().trim().isEmpty()) { + throw new ServiceException("名称不能为空"); + } + if (entity.getXmlx() == null || entity.getXmlx().trim().isEmpty()) { + entity.setXmlx("联教联训"); + } + if (entity.getXz() == null || entity.getXz().trim().isEmpty()) { + entity.setXz("-"); + } + if (entity.getYj() == null || entity.getYj().trim().isEmpty()) { + entity.setYj("-"); + } + if (entity.getKslx() == null || entity.getKslx().trim().isEmpty()) { + entity.setKslx("-"); + } + if (entity.getSm() == null || entity.getSm().trim().isEmpty()) { + entity.setSm("-"); + } + if (entity.getBz() == null || entity.getBz().trim().isEmpty()) { + entity.setBz("-"); + } + if (entity.getTs() == null) { + entity.setTs(0f); + } + if (entity.getJbksl() == null) { + entity.setJbksl(0f); + } + if (entity.getTjzt() == null) { + entity.setTjzt(0); + } + if (entity.getSpzt() == null) { + entity.setSpzt(0); + } + } + @Override public void exportSubsidyProject(jakarta.servlet.http.HttpServletResponse response) throws Exception { List list = ksbzxmMapper.selectList( diff --git a/frontend/src/api/classHour/jointTraining.js b/frontend/src/api/classHour/jointTraining.js index 901fdc00a..0dd12de30 100644 --- a/frontend/src/api/classHour/jointTraining.js +++ b/frontend/src/api/classHour/jointTraining.js @@ -55,7 +55,9 @@ export function importJointTraining(file) { return request({ url: '/ks/yjlx/import', method: 'post', - data: formData + data: formData, + headers: { 'Content-Type': 'multipart/form-data' }, + timeout: 60000 }) } diff --git a/frontend/src/views/classHour/jointTraining/index.vue b/frontend/src/views/classHour/jointTraining/index.vue index 0e3793e29..4a682c574 100644 --- a/frontend/src/views/classHour/jointTraining/index.vue +++ b/frontend/src/views/classHour/jointTraining/index.vue @@ -362,8 +362,8 @@ export default { if (f.mc && f.mc.trim()) payload.mc = f.mc.trim() if (f.xz && f.xz.trim()) payload.xz = f.xz.trim() if (f.yj && f.yj.trim()) payload.yj = f.yj.trim() - if (f.ksrq) payload.ksrq = f.ksrq - if (f.jsrq) payload.jsrq = f.jsrq + if (f.ksrq) payload.ksrq = String(f.ksrq).replace(' ', 'T') + if (f.jsrq) payload.jsrq = String(f.jsrq).replace(' ', 'T') if (f.ts !== null && f.ts !== undefined) payload.ts = f.ts if (f.jbksl !== null && f.jbksl !== undefined) payload.jbksl = f.jbksl if (f.kslx && f.kslx.trim()) payload.kslx = f.kslx.trim() @@ -435,7 +435,7 @@ export default { handleDownloadTemplate() { downloadJointTrainingTemplate().then(blob => { - saveAs(blob, '联教连训管理.xls') + saveAs(blob, '联教联训数据文件模板.xlsx') this.$message.success('模板下载成功') }).catch(() => {}) } diff --git a/frontend/src/views/student/warningCondition/index.vue b/frontend/src/views/student/warningCondition/index.vue index 6562539d2..071e8289c 100644 --- a/frontend/src/views/student/warningCondition/index.vue +++ b/frontend/src/views/student/warningCondition/index.vue @@ -61,13 +61,15 @@ - - - - - - - + + + + + + + + + - +