班次编号生成,改为XYD+年度+补零序号

This commit is contained in:
2026-09-21 16:36:09 +08:00
parent 035c01e90b
commit 1482bfd31c
9 changed files with 112 additions and 18 deletions
@@ -31,6 +31,7 @@ import com.roomroot.jwgl.service.ElectiveCourseService;
import com.roomroot.jwgl.unit.PageQuery; import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.SemesterCodeUtil; import com.roomroot.jwgl.utils.SemesterCodeUtil;
import com.roomroot.jwgl.utils.TeamCodeUtil;
import com.roomroot.jwgl.utils.UuidUtil; import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.vo.jys.ElectiveCourseStudentVO; import com.roomroot.jwgl.vo.jys.ElectiveCourseStudentVO;
import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; import com.roomroot.jwgl.vo.jys.ElectiveCourseVO;
@@ -93,6 +94,9 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
@Resource @Resource
private ClassSemesterMapper classSemesterMapper; private ClassSemesterMapper classSemesterMapper;
@Resource
private TeamCodeUtil teamCodeUtil;
@Override @Override
public PageResult<ElectiveCourseVO> pageList(PageQuery query, ElectiveCourseQuery cond) { public PageResult<ElectiveCourseVO> pageList(PageQuery query, ElectiveCourseQuery cond) {
ElectiveCourseQuery filter = normalizeQuery(cond); ElectiveCourseQuery filter = normalizeQuery(cond);
@@ -379,13 +383,13 @@ public class ElectiveCourseServiceImpl implements ElectiveCourseService {
throw new ServiceException("选修班不存在:" + xxbmc, NOT_FOUND); throw new ServiceException("选修班不存在:" + xxbmc, NOT_FOUND);
} }
XYDB created = new XYDB(); XYDB created = new XYDB();
created.setXydbh(UuidUtil.getOriginalUUID());
created.setXydmc(xxbmc.trim()); created.setXydmc(xxbmc.trim());
created.setNj(blankToNull(nj)); created.setNj(blankToNull(nj));
created.setXydlx(CLASS_TYPE_ELECTIVE); created.setXydlx(CLASS_TYPE_ELECTIVE);
created.setXslx(0); created.setXslx(0);
created.setXydrs(rs != null ? rs : 0); created.setXydrs(rs != null ? rs : 0);
fillTeamRequiredDefaults(created); fillTeamRequiredDefaults(created);
created.setXydbh(teamCodeUtil.nextXydbhForNj(created.getNj()));
xydbMapper.insert(created); xydbMapper.insert(created);
return created.getXydbh(); return created.getXydbh();
} }
@@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.jwgl.dto.elective.AddClassDTO; import com.roomroot.jwgl.dto.elective.AddClassDTO;
import com.roomroot.jwgl.entity.*; import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.mapper.*; import com.roomroot.jwgl.mapper.*;
import com.roomroot.jwgl.utils.TeamCodeUtil;
import com.roomroot.jwgl.vo.elective.*; import com.roomroot.jwgl.vo.elective.*;
import com.roomroot.jwgl.mapper.*;
import com.roomroot.jwgl.service.BuildService; import com.roomroot.jwgl.service.BuildService;
import com.roomroot.jwgl.service.ElectiveService; import com.roomroot.jwgl.service.ElectiveService;
import com.roomroot.jwgl.unit.BusinessException; import com.roomroot.jwgl.unit.BusinessException;
@@ -14,7 +14,6 @@ import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.SemesterCodeUtil; import com.roomroot.jwgl.utils.SemesterCodeUtil;
import com.roomroot.jwgl.utils.UuidUtil; import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.vo.elective.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -56,10 +55,18 @@ public class ElectiveServiceImpl implements ElectiveService {
@Resource @Resource
private ClassSemesterMapper classSemesterMapper; private ClassSemesterMapper classSemesterMapper;
@Resource
private TeamCodeUtil teamCodeUtil;
@Override @Override
@Transactional @Transactional
public void add(AddClassDTO dto) { public void add(AddClassDTO dto) {
XYDB entity = dto.getClazz(); XYDB entity = dto.getClazz();
if (entity.getXydbh() == null || entity.getXydbh().isEmpty()) {
entity.setXydbh(teamCodeUtil.nextXydbhForNj(entity.getNj()));
} else if (xydbMapper.selectById(entity.getXydbh()) != null) {
throw new BusinessException("学员队编号已存在:" + entity.getXydbh());
}
xydbMapper.insert(entity); xydbMapper.insert(entity);
// 同时写入学员队期表(学号规则、注册设置) // 同时写入学员队期表(学号规则、注册设置)
XYDQB period = dto.getPeriod(); XYDQB period = dto.getPeriod();
@@ -29,6 +29,7 @@ import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult; import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.ExcelParseUtil; import com.roomroot.jwgl.utils.ExcelParseUtil;
import com.roomroot.jwgl.utils.JwglRoleHelper; import com.roomroot.jwgl.utils.JwglRoleHelper;
import com.roomroot.jwgl.utils.TeamCodeUtil;
import com.roomroot.jwgl.utils.UuidUtil; import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.vo.StudentListEchoVO; import com.roomroot.jwgl.vo.StudentListEchoVO;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@@ -90,6 +91,9 @@ public class StudentRecordsServiceImpl implements StudentRecordsService {
@Resource @Resource
private JwglRoleHelper jwglRoleHelper; private JwglRoleHelper jwglRoleHelper;
@Resource
private TeamCodeUtil teamCodeUtil;
@Override @Override
@Transactional @Transactional
public void add(XYXX xyxx) { public void add(XYXX xyxx) {
@@ -704,7 +708,9 @@ public class StudentRecordsServiceImpl implements StudentRecordsService {
@Transactional @Transactional
public void addTeam(XYDB entity) { public void addTeam(XYDB entity) {
if (entity.getXydbh() == null || entity.getXydbh().isEmpty()) { if (entity.getXydbh() == null || entity.getXydbh().isEmpty()) {
throw new RuntimeException("学员队编号不能为空"); entity.setXydbh(teamCodeUtil.nextXydbhForNj(entity.getNj()));
} else if (xydbMapper.selectById(entity.getXydbh()) != null) {
throw new RuntimeException("学员队编号已存在:" + entity.getXydbh());
} }
xydbMapper.insert(entity); xydbMapper.insert(entity);
} }
@@ -748,10 +754,18 @@ public class StudentRecordsServiceImpl implements StudentRecordsService {
if (list.isEmpty()) { if (list.isEmpty()) {
throw new RuntimeException("Excel中无有效数据"); throw new RuntimeException("Excel中无有效数据");
} }
int count = 0;
for (XYDB entity : list) { for (XYDB entity : list) {
if (entity.getXydbh() == null || entity.getXydbh().isEmpty()) {
entity.setXydbh(teamCodeUtil.nextXydbhForNj(entity.getNj()));
} else if (xydbMapper.selectById(entity.getXydbh()) != null) {
// 编号已存在的跳过,避免整批导入因主键冲突中断
continue;
}
xydbMapper.insert(entity); xydbMapper.insert(entity);
count++;
} }
return list.size(); return count;
} }
@Override @Override
@@ -0,0 +1,69 @@
package com.roomroot.jwgl.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.mapper.XYDBMapper;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 班次(学员队)编号生成器。
* <p>
* 规则:XYD + 年度(4位) + 四位补零序号,序号在年度内递增,如 XYD20260001。
* 所有系统建队入口统一走此生成器;调用方传入手工编号时仍按手工编号落库。
* </p>
*/
@Component
public class TeamCodeUtil {
private static final String PREFIX = "XYD";
private static final Pattern YEAR_PATTERN = Pattern.compile("\\d{4}");
@Resource
private XYDBMapper xydbMapper;
/**
* 取指定年度下一个班次编号。
* synchronized 避免单实例内并发取到同一序号;跨实例并发由主键约束兜底。
*/
public synchronized String nextXydbh(Integer year) {
int y = (year != null && year > 0) ? year : LocalDate.now().getYear();
String prefix = PREFIX + y;
List<XYDB> rows = xydbMapper.selectList(new LambdaQueryWrapper<XYDB>()
.select(XYDB::getXydbh)
.likeRight(XYDB::getXydbh, prefix));
int max = 0;
for (XYDB row : rows) {
String code = row.getXydbh();
if (code == null || code.length() <= prefix.length()) {
continue;
}
String tail = code.substring(prefix.length());
// 只把 1-4 位纯数字后缀计入序号(兼容 XYD202601 这类两位序号存量数据),其它形态跳过
if (tail.length() > 4 || !tail.chars().allMatch(Character::isDigit)) {
continue;
}
max = Math.max(max, Integer.parseInt(tail));
}
return prefix + String.format("%04d", max + 1);
}
/**
* 按年级文本解析年度后取号(如 "2026级" → 2026),解析不出取当前年度。
*/
public String nextXydbhForNj(String nj) {
Integer year = null;
if (nj != null) {
Matcher m = YEAR_PATTERN.matcher(nj);
if (m.find()) {
year = Integer.valueOf(m.group());
}
}
return nextXydbh(year);
}
}
@@ -1,6 +1,6 @@
import request from '@/utils/request' import request from '@/utils/request'
// ======================== 班次教学任务(实体 XYDRWB 学员队任务表,不是班历) ======================== // ======================== 班次课程(实体 XYDRWB 学员队任务表,不是班历) ========================
// 接口依据:api2.txt「班次学期日历(班历)」分组 + StudentTeamTaskController // 接口依据:api2.txt「班次学期日历(班历)」分组 + StudentTeamTaskController
// 每个班次学期(xydxqbh)下挂若干条课程任务记录: // 每个班次学期(xydxqbh)下挂若干条课程任务记录:
// bh 编号、nd 年度、xydbh 学员队编号、kbh 课编号、xqdc 学期第次、jybh 教员编号、kcxh 课次序号、 // bh 编号、nd 年度、xydbh 学员队编号、kbh 课编号、xqdc 学期第次、jybh 教员编号、kcxh 课次序号、
@@ -133,7 +133,7 @@
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="学员队编号" prop="xydbh"> <el-form-item label="学员队编号" prop="xydbh">
<el-input v-model="form.xydbh" placeholder="请输入学员队编号" :disabled="!isAdd" /> <el-input v-model="form.xydbh" placeholder="留空自动生成(XYD+年级+四位序号)" :disabled="!isAdd" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -408,7 +408,7 @@ export default {
formSaving: false, formSaving: false,
form: this.createEmptyForm(), form: this.createEmptyForm(),
formRules: { formRules: {
xydbh: [{ required: true, message: '请输入学员队编号', trigger: 'blur' }], xydbh: [{ required: false }],
xydmc: [{ required: true, message: '请输入学员队名称', trigger: 'blur' }], xydmc: [{ required: true, message: '请输入学员队名称', trigger: 'blur' }],
xydrs: [{ required: true, message: '请输入学员队人数', trigger: 'change' }], xydrs: [{ required: true, message: '请输入学员队人数', trigger: 'change' }],
zydh: [{ required: true, message: '请选择专业', trigger: 'change' }], zydh: [{ required: true, message: '请选择专业', trigger: 'change' }],
@@ -1,7 +1,7 @@
<template> <template>
<el-dialog <el-dialog
:visible="dialogVisible" :visible="dialogVisible"
:title="`班次教学任务——${semesterTitle}`" :title="`班次课程——${semesterTitle}`"
width="1200px" width="1200px"
top="6vh" top="6vh"
:close-on-click-modal="false" :close-on-click-modal="false"
@@ -33,7 +33,7 @@
<el-button size="small" :disabled="!selection.length" @click="handleSyncPlan">同步人培</el-button> <el-button size="small" :disabled="!selection.length" @click="handleSyncPlan">同步人培</el-button>
<el-button size="small" type="danger" plain :disabled="!selection.length" @click="handleBatchDelete">批量删除</el-button> <el-button size="small" type="danger" plain :disabled="!selection.length" @click="handleBatchDelete">批量删除</el-button>
<el-button size="small" @click="handleApplyRegion">选定区域应用于其它班次</el-button> <el-button size="small" @click="handleApplyRegion">选定区域应用于其它班次</el-button>
<el-button size="small" @click="handleApplyWhole">整个班次教学任务应用于其它班次</el-button> <el-button size="small" @click="handleApplyWhole">整个班次课程应用于其它班次</el-button>
<el-button size="small" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button> <el-button size="small" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
</div> </div>
</div> </div>
@@ -912,7 +912,7 @@ export default {
handleApplyWhole() { handleApplyWhole() {
this.applyMode = 'whole' this.applyMode = 'whole'
this.copyNote = '将整个班次教学任务复制到所选班次' this.copyNote = '将整个班次课程复制到所选班次'
this.teamSelectVisible = true this.teamSelectVisible = true
}, },
@@ -935,7 +935,7 @@ export default {
targetBhList: targetBhList targetBhList: targetBhList
}).then(res => { }).then(res => {
const data = (res && res.data) || {} const data = (res && res.data) || {}
this.$message.success(`已复制整个班次教学任务,共新增 ${data.count || 0} 条记录`) this.$message.success(`已复制整个班次课程,共新增 ${data.count || 0} 条记录`)
this.loadData() this.loadData()
}) })
} else { } else {
@@ -1051,7 +1051,7 @@ export default {
/* ---------- 刷新 ---------- */ /* ---------- 刷新 ---------- */
handleRefresh() { handleRefresh() {
this.loadData() this.loadData()
this.$message.success('已刷新班次教学任务') this.$message.success('已刷新班次课程')
} }
} }
} }
@@ -151,7 +151,7 @@
</tr> </tr>
<tr v-if="!view.tasks.length"> <tr v-if="!view.tasks.length">
<td :colspan="12 + axisCols.length" class="empty-row"> <td :colspan="12 + axisCols.length" class="empty-row">
该班次学期暂无课程任务请先在班次教学任务中生成/添加课程 该班次学期暂无课程任务请先在班次课程中生成/添加课程
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -62,7 +62,7 @@
<el-button type="warning" plain :disabled="!selection.length" @click="handleWaveSplit">预设拆班</el-button> <el-button type="warning" plain :disabled="!selection.length" @click="handleWaveSplit">预设拆班</el-button>
<el-button type="primary" plain :disabled="!selection.length" @click="handleBatchGenerateTasks">批量生成必修课程</el-button> <el-button type="primary" plain :disabled="!selection.length" @click="handleBatchGenerateTasks">批量生成必修课程</el-button>
<el-button type="success" plain icon="el-icon-date" :disabled="selection.length !== 1" @click="handleEditEventCalendar()">编辑班历</el-button> <el-button type="success" plain icon="el-icon-date" :disabled="selection.length !== 1" @click="handleEditEventCalendar()">编辑班历</el-button>
<el-button type="success" plain icon="el-icon-calendar" :disabled="selection.length !== 1" @click="handleEditCalendar()">编辑班次教学任务</el-button> <el-button type="success" plain icon="el-icon-calendar" :disabled="selection.length !== 1" @click="handleEditCalendar()">编辑班次课程</el-button>
<el-button type="success" plain icon="el-icon-data-line" :disabled="selection.length !== 1" @click="handleAllocation()">教学配当</el-button> <el-button type="success" plain icon="el-icon-data-line" :disabled="selection.length !== 1" @click="handleAllocation()">教学配当</el-button>
<el-button type="success" plain icon="el-icon-download" :disabled="!selection.length" @click="handleExportAllocation">导出配当</el-button> <el-button type="success" plain icon="el-icon-download" :disabled="!selection.length" @click="handleExportAllocation">导出配当</el-button>
<el-button type="primary" plain icon="el-icon-upload2" :disabled="!selection.length" @click="handlePublishRunning">发布运行课表</el-button> <el-button type="primary" plain icon="el-icon-upload2" :disabled="!selection.length" @click="handlePublishRunning">发布运行课表</el-button>
@@ -124,7 +124,7 @@
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button> <el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" size="small" @click="handleEditEventCalendar(row)">班历</el-button> <el-button type="text" size="small" @click="handleEditEventCalendar(row)">班历</el-button>
<el-button type="text" size="small" @click="handleEditCalendar(row)">教学任务</el-button> <el-button type="text" size="small" @click="handleEditCalendar(row)">班次课程</el-button>
<el-button type="text" size="small" @click="handleSchedule(row)">排课</el-button> <el-button type="text" size="small" @click="handleSchedule(row)">排课</el-button>
<el-button type="text" size="small" class="text-danger" @click="handleDeleteRow(row)">删除</el-button> <el-button type="text" size="small" class="text-danger" @click="handleDeleteRow(row)">删除</el-button>
</template> </template>
@@ -156,7 +156,7 @@
@submit="handleDetailSubmit" @submit="handleDetailSubmit"
/> />
<!-- ==================== 班次教学任务弹窗 ==================== --> <!-- ==================== 班次课程弹窗 ==================== -->
<ClassCalendarDialog <ClassCalendarDialog
:visible="calendarVisible" :visible="calendarVisible"
:semester="calendarSemester" :semester="calendarSemester"
@@ -763,7 +763,7 @@ export default {
}).catch(() => {}) }).catch(() => {})
}, },
/* ==================== 编辑班次教学任务 ==================== */ /* ==================== 编辑班次课程 ==================== */
handleEditCalendar(row) { handleEditCalendar(row) {
const target = row || this.selection[0] const target = row || this.selection[0]
if (!target) { if (!target) {