课时统计功能提交

This commit is contained in:
2026-09-24 14:08:44 +08:00
parent d9f8bf705d
commit bd395a5504
5 changed files with 135 additions and 0 deletions
@@ -32,4 +32,13 @@ public interface KSService {
* 导出课时费统计。
*/
void exportFeeStatistics(HourStatisticsQuery cond, HttpServletResponse response);
/**
* 课时核算:按已排课次(实施_课程表)聚合指定自然年各教员上下半年课时,
* 覆盖写入课时统计表。仅教务人员可执行。
*
* @param year 自然年(如 2026);为空取当前年
* @return 写入统计表的教员行数
*/
int recalcHourStatistics(Integer year);
}
@@ -6,9 +6,18 @@ import com.roomroot.common.exception.ServiceException;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.jwgl.dto.ks.HourStatisticsQuery;
import com.roomroot.jwgl.entity.JYB;
import com.roomroot.jwgl.entity.KSFBZ;
import com.roomroot.jwgl.entity.KSTJB;
import com.roomroot.jwgl.entity.SSKC;
import com.roomroot.jwgl.entity.SSKCB;
import com.roomroot.jwgl.entity.SSKCBFZJY;
import com.roomroot.jwgl.mapper.JYBMapper;
import com.roomroot.jwgl.mapper.KSFBZMapper;
import com.roomroot.jwgl.mapper.KSTJBMapper;
import com.roomroot.jwgl.mapper.SSKCBFZJYMapper;
import com.roomroot.jwgl.mapper.SSKCBMapper;
import com.roomroot.jwgl.mapper.SSKCMapper;
import com.roomroot.jwgl.mapper.SystemInitializationMapper;
import com.roomroot.jwgl.service.KSService;
import com.roomroot.jwgl.unit.PageQuery;
@@ -18,14 +27,22 @@ import com.roomroot.jwgl.vo.ks.HourStatisticsVO;
import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
import static com.roomroot.jwgl.utils.BasicManagementConstants.FORBIDDEN;
import static com.roomroot.jwgl.utils.BasicManagementConstants.NOT_FOUND;
/**
@@ -49,6 +66,18 @@ public class KSServiceImpl implements KSService {
@Resource
private JwglRoleHelper jwglRoleHelper;
@Resource
private SSKCBMapper sskcbMapper;
@Resource
private SSKCBFZJYMapper sskcbfzjyMapper;
@Resource
private SSKCMapper sskcMapper;
@Resource
private JYBMapper jybMapper;
@Override
public PageResult<HourStatisticsVO> pageHourStatistics(PageQuery query, HourStatisticsQuery cond) {
Page<HourStatisticsVO> page = queryHours(query, cond);
@@ -136,6 +165,66 @@ public class KSServiceImpl implements KSService {
return systemInitializationMapper.selectCurrentSemester();
}
/**
* 课时核算:把指定自然年已排课次(每课次 2 + 节次调节 学时)按教员聚合到课时统计表。
* 归属:课次主讲教员(实施_课程表_辅助教员 zjy=1),无主讲记录回退课程责任教员。
* 半年口径:1-6 月上半年、7-12 月下半年。该年原有统计行先整体清掉再重写。
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int recalcHourStatistics(Integer year) {
if (!jwglRoleHelper.isDepartmentPersonnel()) {
throw new ServiceException("只有教务人员可以执行课时核算", FORBIDDEN);
}
int y = year != null ? year : LocalDate.now().getYear();
List<SSKCB> yearLessons = sskcbMapper.selectList(new LambdaQueryWrapper<SSKCB>()
.eq(SSKCB::getSczt, 0).isNotNull(SSKCB::getRq)).stream()
.filter(l -> l.getRq().getYear() == y).collect(Collectors.toList());
if (yearLessons.isEmpty()) {
kstjbMapper.delete(new LambdaQueryWrapper<KSTJB>().eq(KSTJB::getNf, y));
return 0;
}
// 课次主讲教员(zjy=1,每课次取一条)
List<String> lessonIds = yearLessons.stream().map(SSKCB::getBh).collect(Collectors.toList());
Map<String, String> mainTeacher = new HashMap<>();
for (SSKCBFZJY f : sskcbfzjyMapper.selectList(new LambdaQueryWrapper<SSKCBFZJY>()
.in(SSKCBFZJY::getSskcbbh, lessonIds).eq(SSKCBFZJY::getZjy, 1))) {
if (f.getFzjybh() != null && !f.getFzjybh().isEmpty()) {
mainTeacher.putIfAbsent(f.getSskcbbh(), f.getFzjybh());
}
}
// 课程责任教员兜底
Set<String> courseIds = yearLessons.stream().map(SSKCB::getSskcbh).collect(Collectors.toSet());
Map<String, String> courseTeacher = new HashMap<>();
if (!courseIds.isEmpty()) {
for (SSKC c : sskcMapper.selectByBhs(new ArrayList<>(courseIds))) {
courseTeacher.put(c.getBh(), c.getJybh());
}
}
// 按教员累计上/下半年课时
Map<String, double[]> hours = new HashMap<>();
for (SSKCB l : yearLessons) {
String jybh = mainTeacher.getOrDefault(l.getBh(), courseTeacher.get(l.getSskcbh()));
if (jybh == null || jybh.isEmpty()) continue;
double h = 2D + (l.getJcdj() == null ? 0 : l.getJcdj());
int half = l.getRq().getMonthValue() <= 6 ? 0 : 1;
hours.computeIfAbsent(jybh, k -> new double[2])[half] += h;
}
kstjbMapper.delete(new LambdaQueryWrapper<KSTJB>().eq(KSTJB::getNf, y));
for (Map.Entry<String, double[]> e : hours.entrySet()) {
KSTJB row = new KSTJB();
row.setNf(y);
row.setJybh(e.getKey());
row.setSbn(e.getValue()[0]);
row.setXbn(e.getValue()[1]);
JYB teacher = jybMapper.selectById(e.getKey());
// 职称列为 NOT NULL 且达梦空串等同 NULL,无职称须给兜底值
row.setZc(teacher != null && StringUtils.isNotEmpty(teacher.getZc()) ? teacher.getZc() : "未定级");
kstjbMapper.insert(row);
}
return hours.size();
}
private KSFBZ resolveFeeStandard(HourStatisticsQuery cond) {
if (cond != null && StringUtils.isNotEmpty(cond.getKsfbzbh())) {
KSFBZ specified = ksfbzMapper.selectById(cond.getKsfbzbh());