联教编辑报错

This commit is contained in:
2026-09-20 15:24:07 +08:00
parent 5e3bee9c5f
commit f5a5c89ee3
6 changed files with 165 additions and 21 deletions
@@ -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", "联教联训测试项目甲", "集中", "训练计划〔20261号", "2026-03-01", "2026-03-10",
"联合教学演练", "导入测试样例1", "战术教研室", "张三", "16", "含备课课时"},
{"2", "联教联训测试项目乙", "分散", "训练计划〔20262号", "2026-05-08", "2026-05-20",
"跨校区联训", "导入测试样例2", "射击教研室", "李四", "24", ""},
{"3", "联教联训测试项目丙", "集中", "训练计划〔20263号", "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) {
}
}
}
/**
@@ -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);
};
}
}
@@ -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<KSBZXM> list = ksbzxmMapper.selectList(
+3 -1
View File
@@ -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
})
}
@@ -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(() => {})
}
@@ -61,13 +61,15 @@
</div>
<el-table v-loading="loading" :data="tableData" stripe border highlight-current-row>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="bh" label="编号" width="100" show-overflow-tooltip />
<el-table-column prop="mc" label="名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="pxlx" label="培训类型" width="120" show-overflow-tooltip />
<el-table-column prop="pxcc" label="培训层次" width="120" show-overflow-tooltip />
<el-table-column prop="bb" label="版本" width="100" show-overflow-tooltip />
<el-table-column prop="xgsj" label="修改时间" width="170" show-overflow-tooltip />
<el-table-column label="停用" width="80" align="center">
<el-table-column prop="bh" label="编号" width="150" align="center" show-overflow-tooltip />
<el-table-column prop="mc" label="名称" width="200" align="center" show-overflow-tooltip />
<el-table-column prop="pxlx" label="培训类型" width="200" align="center" show-overflow-tooltip />
<el-table-column prop="pxcc" label="培训层次" width="200" align="center" show-overflow-tooltip />
<el-table-column prop="bb" label="版本" width="200" align="center" show-overflow-tooltip />
<el-table-column label="修改时间" width="200" align="center" show-overflow-tooltip>
<template slot-scope="{ row }">{{ fmtDateTime(row.xgsj) || '-' }}</template>
</el-table-column>
<el-table-column label="停用" width="120" align="center">
<template slot-scope="scope">
<el-tag
:type="scope.row.ty === 1 || scope.row.ty === true ? 'danger' : 'success'"
@@ -78,7 +80,7 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center" fixed="right">
<el-table-column label="操作" align="center" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="small" icon="el-icon-view" @click="handleView(scope.row)">详情</el-button>
<el-button type="text" size="small" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
@@ -240,7 +242,7 @@
<el-descriptions-item label="培训类型">{{ viewForm.pxlx || '-' }}</el-descriptions-item>
<el-descriptions-item label="培训层次">{{ viewForm.pxcc || '-' }}</el-descriptions-item>
<el-descriptions-item label="版本">{{ viewForm.bb || '-' }}</el-descriptions-item>
<el-descriptions-item label="修改时间">{{ viewForm.xgsj || '-' }}</el-descriptions-item>
<el-descriptions-item label="修改时间">{{ fmtDateTime(viewForm.xgsj) || '-' }}</el-descriptions-item>
<el-descriptions-item label="当前学期考试不及格门数下限">{{ formatValue(viewForm.dqxqksbjgmsxx) }}</el-descriptions-item>
<el-descriptions-item label="当前学期考试不及格门数上限">{{ formatValue(viewForm.dqxqksbjgmssx) }}</el-descriptions-item>
<el-descriptions-item label="当前学期考查不及格门数下限">{{ formatValue(viewForm.dqxqkcbjgmsxx) }}</el-descriptions-item>
@@ -514,6 +516,14 @@ export default {
/** 空值显示占位符 */
formatValue(val) {
return val !== null && val !== undefined ? val : '-'
},
/** 统一格式化后端 LocalDateTime(去除 T、截断到秒) */
fmtDateTime(val) {
if (val === null || val === undefined || val === '') {
return ''
}
return String(val).replace('T', ' ').slice(0, 19)
}
}
}