教学大纲新增导出模板和导入按钮

This commit is contained in:
2026-09-17 10:03:29 +08:00
parent 9af6de6ff3
commit f7299c36e8
7 changed files with 602 additions and 41 deletions
@@ -659,37 +659,86 @@ public class ExcelParseUtil {
* @return 专业教学计划实体列表
* @throws Exception 解析异常
*/
public static List<ZYJXJHB> parseZYJXJHBExcel(InputStream inputStream, String fileName) throws Exception {
List<ZYJXJHB> result = new ArrayList<>();
/**
* 教学大纲导入模板支持的表头名 → 实体字段标识。
* 兼容导出文件与新增页字段两种叫法。
*/
private static final Map<String, String> ZYJXJHB_HEADER_FIELDS;
static {
Map<String, String> map = new LinkedHashMap<>();
map.put("专业代号", "zydh");
map.put("专业", "zydh");
map.put("课编号", "kbh");
map.put("课程", "kbh");
map.put("学期第次", "xqdc");
map.put("课类型", "klx");
map.put("学时", "xs");
map.put("停用", "ty");
map.put("简称", "jc");
map.put("学分", "xf");
map.put("课程定位", "kcdw");
map.put("模块", "mk");
map.put("成绩分制", "cjfz");
map.put("教研室代号", "jysdh");
map.put("教研室", "jysdh");
map.put("考试课时", "ksks");
map.put("理论学时", "llxs");
map.put("实践学时", "sjxs");
map.put("周课时", "zks");
map.put("不计入平均分", "bjrxypjf");
map.put("不计入学员平均分", "bjrxypjf");
map.put("考试课时不显示", "ksksbxs");
map.put("大纲课程", "dgkc");
ZYJXJHB_HEADER_FIELDS = java.util.Collections.unmodifiableMap(map);
}
/**
* 按表头名称解析教学大纲导入 Excel(第一个 sheet)。
* <p>列位置不固定,按表头名匹配;必填列「专业代号」「课编号」缺失时报错。
* 是否类列(停用/不计入平均分/考试课时不显示/大纲课程)支持 是/否/1/0。</p>
*
* @return Excel 行号(1-based)→ 实体,跳过整行空白行
*/
public static Map<Integer, ZYJXJHB> parseZYJXJHBExcel(InputStream inputStream, String fileName) throws Exception {
Map<Integer, ZYJXJHB> result = new LinkedHashMap<>();
Workbook workbook = createWorkbook(inputStream, fileName);
try {
Sheet sheet = workbook.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum();
for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) {
Row headerRow = sheet.getRow(0);
if (headerRow == null) {
throw new IllegalArgumentException("Excel缺少表头行,请下载导入模板填写");
}
Map<Integer, String> colField = new LinkedHashMap<>();
for (int c = 0; c < headerRow.getLastCellNum(); c++) {
String header = getCellStringValue(headerRow.getCell(c));
if (header == null) {
continue;
}
String field = ZYJXJHB_HEADER_FIELDS.get(header.replace("*", "").replace(" ", "").trim());
if (field != null) {
colField.put(c, field);
}
}
if (!colField.containsValue("zydh") || !colField.containsValue("kbh")) {
throw new IllegalArgumentException("表头缺少必需列「专业代号」「课编号」,请下载导入模板填写");
}
for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row row = sheet.getRow(rowNum);
if (row == null) {
continue;
}
ZYJXJHB entity = new ZYJXJHB();
entity.setZydh(getCellStringValue(row.getCell(0)));
entity.setKbh(getCellStringValue(row.getCell(1)));
entity.setXqdc(parseIntCell(row.getCell(2)));
entity.setKlx(getCellStringValue(row.getCell(3)));
entity.setXs(parseIntCell(row.getCell(4)));
entity.setXf(parseFloatCell(row.getCell(5)));
entity.setZks(parseIntCell(row.getCell(6)));
entity.setKcdw(getCellStringValue(row.getCell(7)));
entity.setMk(getCellStringValue(row.getCell(8)));
entity.setCjfz(getCellStringValue(row.getCell(9)));
entity.setLlxs(parseIntCell(row.getCell(10)));
entity.setSjxs(parseIntCell(row.getCell(11)));
entity.setKsks(parseIntCell(row.getCell(12)));
entity.setJysdh(getCellStringValue(row.getCell(13)));
entity.setJc(getCellStringValue(row.getCell(14)));
// 至少要有专业代号或课编号才视为有效行
if (entity.getZydh() != null && !entity.getZydh().isEmpty()
|| entity.getKbh() != null && !entity.getKbh().isEmpty()) {
result.add(entity);
boolean hasValue = false;
for (Map.Entry<Integer, String> entry : colField.entrySet()) {
Cell cell = row.getCell(entry.getKey());
if (getCellStringValue(cell) != null) {
hasValue = true;
}
applyZYJXJHBField(entity, entry.getValue(), cell);
}
if (hasValue) {
result.put(rowNum + 1, entity);
}
}
} finally {
@@ -698,6 +747,49 @@ public class ExcelParseUtil {
return result;
}
private static void applyZYJXJHBField(ZYJXJHB entity, String field, Cell cell) {
switch (field) {
case "zydh": entity.setZydh(getCellStringValue(cell)); break;
case "kbh": entity.setKbh(getCellStringValue(cell)); break;
case "xqdc": entity.setXqdc(parseIntCell(cell)); break;
case "klx": entity.setKlx(getCellStringValue(cell)); break;
case "xs": entity.setXs(parseIntCell(cell)); break;
case "ty": entity.setTy(parseYesNoCell(cell)); break;
case "jc": entity.setJc(getCellStringValue(cell)); break;
case "xf": entity.setXf(parseFloatCell(cell)); break;
case "kcdw": entity.setKcdw(getCellStringValue(cell)); break;
case "mk": entity.setMk(getCellStringValue(cell)); break;
case "cjfz": entity.setCjfz(getCellStringValue(cell)); break;
case "jysdh": entity.setJysdh(getCellStringValue(cell)); break;
case "ksks": entity.setKsks(parseIntCell(cell)); break;
case "llxs": entity.setLlxs(parseIntCell(cell)); break;
case "sjxs": entity.setSjxs(parseIntCell(cell)); break;
case "zks": entity.setZks(parseIntCell(cell)); break;
case "bjrxypjf": entity.setBjrxypjf(parseYesNoCell(cell)); break;
case "ksksbxs": entity.setKsksbxs(parseYesNoCell(cell)); break;
case "dgkc": entity.setDgkc(parseYesNoCell(cell)); break;
default: break;
}
}
/**
* 解析是否类单元格:是/Y/1/true → 1,否/N/0/false → 0,空或无法识别 → null。
*/
private static Integer parseYesNoCell(Cell cell) {
String value = getCellStringValue(cell);
if (value == null || value.isEmpty()) {
return null;
}
String v = value.trim();
if ("是".equals(v) || "1".equals(v) || "Y".equalsIgnoreCase(v) || "true".equalsIgnoreCase(v)) {
return 1;
}
if ("否".equals(v) || "0".equals(v) || "N".equalsIgnoreCase(v) || "false".equalsIgnoreCase(v)) {
return 0;
}
return null;
}
private static Workbook createWorkbook(InputStream inputStream, String fileName) throws Exception {
String name = fileName == null ? "" : fileName.toLowerCase();
if (!name.endsWith(".xlsx") && !name.endsWith(".xls")) {