|
|
@@ -0,0 +1,421 @@
|
|
|
+package com.usky.fire.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.usky.common.core.bean.CommonPage;
|
|
|
+import com.usky.common.core.exception.BusinessException;
|
|
|
+import com.usky.fire.domain.MhCompany;
|
|
|
+import com.usky.fire.domain.MhFireDuty;
|
|
|
+import com.usky.fire.domain.MhFireDutyBusiness;
|
|
|
+import com.usky.fire.mapper.MhFireDutyBusinessMapper;
|
|
|
+import com.usky.fire.mapper.MhFireDutyMapper;
|
|
|
+import com.usky.fire.service.MhFireDutyBusinessService;
|
|
|
+import com.usky.fire.service.MhFireDutyService;
|
|
|
+import com.usky.common.mybatis.core.AbstractCrudService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>
|
|
|
+ * 防火值班主表 服务实现类
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @author han
|
|
|
+ * @since 2025-10-10
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class MhFireDutyServiceImpl extends AbstractCrudService<MhFireDutyMapper, MhFireDuty> implements MhFireDutyService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MhFireDutyBusinessService businessService;
|
|
|
+ @Autowired
|
|
|
+ private MhFireDutyBusinessMapper businessMapper;
|
|
|
+
|
|
|
+ // private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean saveWithSubTables(MhFireDuty fireDuty) {
|
|
|
+ checkEmpty(fireDuty);
|
|
|
+ boolean isSaved = this.save(fireDuty);
|
|
|
+ if (!isSaved) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime createTime = fireDuty.getCreateTime();
|
|
|
+ handleSubTableData(fireDuty.getId(), createTime, null,
|
|
|
+ fireDuty.getDataDocking(), 1);
|
|
|
+ handleSubTableData(fireDuty.getId(), createTime, null,
|
|
|
+ fireDuty.getIntercomSpotCheck(), 2);
|
|
|
+ handleSubTableData(fireDuty.getId(), createTime, null,
|
|
|
+ fireDuty.getSafetySupervision(), 3);
|
|
|
+ handleSubTableData(fireDuty.getId(), createTime, null,
|
|
|
+ fireDuty.getTechnicalService(), 4);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleSubTableData(Long dutyId, LocalDateTime createTime, LocalDateTime updateTime,
|
|
|
+ List<MhFireDutyBusiness> businessList, Integer businessType) {
|
|
|
+ if (CollectionUtils.isEmpty(businessList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 批量设置公共字段
|
|
|
+ businessList.forEach(business -> {
|
|
|
+ business.setDutyId(dutyId);
|
|
|
+ business.setBusinessType(businessType);
|
|
|
+ business.setCreateTime(createTime);
|
|
|
+ business.setIsDeleted(0);
|
|
|
+
|
|
|
+ if (Objects.nonNull(updateTime)) {
|
|
|
+ business.setUpdateTime(updateTime);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 批量保存
|
|
|
+ businessService.saveBatch(businessList);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 空数据校验
|
|
|
+ */
|
|
|
+ private void checkEmpty(MhFireDuty fireDuty) {
|
|
|
+ if (StringUtils.isBlank(fireDuty.getMember())) {
|
|
|
+ throw new BusinessException("请填写值班人员!");
|
|
|
+ }
|
|
|
+ if (fireDuty.getDutyDate() == null) {
|
|
|
+ throw new BusinessException("请填写值班日期!");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(fireDuty.getCreator())) {
|
|
|
+ throw new BusinessException("创建人不能为空!");
|
|
|
+ }
|
|
|
+ if (fireDuty.getCreateTime() == null) {
|
|
|
+ throw new BusinessException("创建时间不能为空!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 逻辑删除
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean removeById(Long id) {
|
|
|
+ try {
|
|
|
+ MhFireDuty fireDuty = new MhFireDuty();
|
|
|
+ fireDuty.setId(id);
|
|
|
+ fireDuty.setIsDeleted(1);
|
|
|
+ baseMapper.updateById(fireDuty);
|
|
|
+
|
|
|
+ MhFireDutyBusiness business = new MhFireDutyBusiness();
|
|
|
+ business.setIsDeleted(1);
|
|
|
+ LambdaQueryWrapper<MhFireDutyBusiness> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(MhFireDutyBusiness::getDutyId, id);
|
|
|
+ businessMapper.update(business, wrapper);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("删除防火值班记录[{}]失败", id, e);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新主表及子表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean updateWithSubTables(MhFireDuty fireDuty) {
|
|
|
+ checkEmpty(fireDuty);
|
|
|
+ fireDuty.setUpdateTime(LocalDateTime.now());
|
|
|
+ boolean isUpdated = this.updateById(fireDuty);
|
|
|
+ if (!isUpdated) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ Long dutyId = fireDuty.getId();
|
|
|
+ LambdaQueryWrapper<MhFireDutyBusiness> delWrapper = new LambdaQueryWrapper<>();
|
|
|
+ delWrapper.eq(MhFireDutyBusiness::getDutyId, dutyId);
|
|
|
+ businessMapper.delete(delWrapper);
|
|
|
+
|
|
|
+ LocalDateTime updateTime = fireDuty.getUpdateTime();
|
|
|
+ handleSubTableData(dutyId, fireDuty.getCreateTime(), updateTime,
|
|
|
+ fireDuty.getDataDocking(), 1);
|
|
|
+ handleSubTableData(dutyId, fireDuty.getCreateTime(), updateTime,
|
|
|
+ fireDuty.getIntercomSpotCheck(), 2);
|
|
|
+ handleSubTableData(dutyId, fireDuty.getCreateTime(), updateTime,
|
|
|
+ fireDuty.getSafetySupervision(), 3);
|
|
|
+ handleSubTableData(dutyId, fireDuty.getCreateTime(), updateTime,
|
|
|
+ fireDuty.getTechnicalService(), 4);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页查询(优化子表数据关联逻辑,使用Map分组提升性能)
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public CommonPage<MhFireDuty> getPage(Integer pageNum, Integer pageSize,
|
|
|
+ LocalDate startTime, LocalDate endTime,
|
|
|
+ String memberName, Long id, Integer type) {
|
|
|
+
|
|
|
+ IPage<MhFireDuty> page = new Page<>(pageNum, pageSize);
|
|
|
+ LambdaQueryWrapper<MhFireDuty> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(Objects.nonNull(id), MhFireDuty::getId, id)
|
|
|
+ .like(StringUtils.isNotBlank(memberName), MhFireDuty::getMember, memberName)
|
|
|
+ .between(Objects.nonNull(startTime) && Objects.nonNull(endTime),
|
|
|
+ MhFireDuty::getDutyDate, startTime, endTime)
|
|
|
+ .eq(MhFireDuty::getIsDeleted, 0)
|
|
|
+ .orderByDesc(MhFireDuty::getDutyDate);
|
|
|
+
|
|
|
+ page = this.page(page, queryWrapper);
|
|
|
+ List<MhFireDuty> dutyList = page.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(dutyList)) {
|
|
|
+ return new CommonPage<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> dutyIds = dutyList.stream().map(MhFireDuty::getId).collect(Collectors.toList());
|
|
|
+ LambdaQueryWrapper<MhFireDutyBusiness> businessWrapper = new LambdaQueryWrapper<>();
|
|
|
+ businessWrapper.eq(Objects.nonNull(type), MhFireDutyBusiness::getBusinessType, type)
|
|
|
+ .in(MhFireDutyBusiness::getDutyId, dutyIds);
|
|
|
+ List<MhFireDutyBusiness> businessList = businessMapper.selectList(businessWrapper);
|
|
|
+
|
|
|
+ Map<String, List<MhFireDutyBusiness>> businessMap = businessList.stream()
|
|
|
+ .collect(Collectors.groupingBy(biz -> biz.getDutyId() + "_" + biz.getBusinessType()));
|
|
|
+
|
|
|
+ dutyList.forEach(duty -> {
|
|
|
+ Long dutyId = duty.getId();
|
|
|
+ duty.setDataDocking(getBusinessByType(businessMap, dutyId, 1));
|
|
|
+ duty.setIntercomSpotCheck(getBusinessByType(businessMap, dutyId, 2));
|
|
|
+ duty.setSafetySupervision(getBusinessByType(businessMap, dutyId, 3));
|
|
|
+ duty.setTechnicalService(getBusinessByType(businessMap, dutyId, 4));
|
|
|
+ });
|
|
|
+
|
|
|
+ page.setRecords(dutyList);
|
|
|
+ return new CommonPage<>(page.getRecords(), page.getTotal(), page.getSize(), page.getCurrent());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从分组Map中获取指定dutyId和业务类型的子表数据
|
|
|
+ */
|
|
|
+ private List<MhFireDutyBusiness> getBusinessByType(Map<String, List<MhFireDutyBusiness>> businessMap,
|
|
|
+ Long dutyId, Integer businessType) {
|
|
|
+ return businessMap.getOrDefault(dutyId + "_" + businessType, Collections.emptyList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成Excel
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void exportExcel(List<Long> ids, HttpServletResponse response) throws IOException {
|
|
|
+ if (ids.isEmpty()) {
|
|
|
+ throw new BusinessException("请选择需要导出的记录!");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 查询所有主表数据
|
|
|
+ List<MhFireDuty> dutyList = new ArrayList<>();
|
|
|
+ for (Long id : ids) {
|
|
|
+ MhFireDuty duty = this.getById(id);
|
|
|
+ if (duty != null) {
|
|
|
+ dutyList.add(duty);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (dutyList.isEmpty()) {
|
|
|
+ throw new BusinessException("所选记录不存在!");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> dutyIds = dutyList.stream().map(MhFireDuty::getId).collect(Collectors.toList());
|
|
|
+ List<MhFireDutyBusiness> allBusiness = businessMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<MhFireDutyBusiness>()
|
|
|
+ .in(MhFireDutyBusiness::getDutyId, dutyIds)
|
|
|
+ .eq(MhFireDutyBusiness::getIsDeleted, 0)
|
|
|
+ );
|
|
|
+ Map<Long, Map<Integer, List<MhFireDutyBusiness>>> dutyBusinessMap = allBusiness.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ MhFireDutyBusiness::getDutyId,
|
|
|
+ Collectors.groupingBy(MhFireDutyBusiness::getBusinessType)
|
|
|
+ ));
|
|
|
+
|
|
|
+ Workbook workbook = new XSSFWorkbook();
|
|
|
+ Sheet sheet = workbook.createSheet("批量坐班值守任务表");
|
|
|
+
|
|
|
+ CellStyle titleStyle = createTitleStyle(workbook);
|
|
|
+ CellStyle headerStyle = createHeaderStyle(workbook);
|
|
|
+ CellStyle contentStyle = createContentStyle(workbook);
|
|
|
+
|
|
|
+ List<TaskDef> taskDefs = Arrays.asList(
|
|
|
+ new TaskDef(1, "通过指挥中心可视化和对讲机,抽查不少于3家消防安全重点单位消控室值班值守、消防控制柜、疏散通道及消防车道情况。"),
|
|
|
+ new TaskDef(2, "通过上海消防数据对接平台,抽查不少于3家消防安全重点单位物联网系统近72小时在线情况。"),
|
|
|
+ new TaskDef(3, "通过社会单位消防安全监管平台,抽查不少于3家消防安全重点单位近7天消防控制室人员持证上岗情况。"),
|
|
|
+ new TaskDef(4, "通过上海市消防技术服务管理系统V2.0,抽查不少于3家消防安全重点单位消防设施长期处于报修状态情况。"),
|
|
|
+ new TaskDef(5, "做好舆情跟踪和应对处置工作。"),
|
|
|
+ new TaskDef(6, "提示出警队站做好灭火救援现场素材搜集工作。"),
|
|
|
+ new TaskDef(7, "高温气温35℃以上时,每日10:00-16:00期间,调取营区监控等方式,对各训练区域进行动态监测。重点排查是否存在违规训练行为,做好监控画面截图留存,发现问题立即汇报。")
|
|
|
+ );
|
|
|
+
|
|
|
+ int currentRow = 0; // 当前行指针,逐行填充
|
|
|
+ for (MhFireDuty duty : dutyList) {
|
|
|
+ // 获取当前记录的子表分组数据(默认空Map)
|
|
|
+ Map<Integer, List<MhFireDutyBusiness>> businessMap = dutyBusinessMap.getOrDefault(
|
|
|
+ duty.getId(), new HashMap<>()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 6.1 填充标题行(合并4列)
|
|
|
+ Row titleRow = sheet.createRow(currentRow);
|
|
|
+ Cell titleCell = titleRow.createCell(0);
|
|
|
+ titleCell.setCellValue("坐班值守岗位工作量化任务(防火值班员/行政值班员)");
|
|
|
+ titleCell.setCellStyle(titleStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow, 0, 3));
|
|
|
+ currentRow++;
|
|
|
+
|
|
|
+ // 6.2 填充表头行
|
|
|
+ Row headerRow = sheet.createRow(currentRow);
|
|
|
+ String[] headers = {"时间", "值班人员", "工作任务", "完成情况"};
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ Cell cell = headerRow.createCell(i);
|
|
|
+ cell.setCellValue(headers[i]);
|
|
|
+ cell.setCellStyle(headerStyle);
|
|
|
+ // 仅在第一组数据时设置列宽(避免重复设置)
|
|
|
+ if (dutyList.indexOf(duty) == 0) {
|
|
|
+ sheet.setColumnWidth(i, i == 2 ? 256 * 60 : 256 * 20);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ currentRow++;
|
|
|
+
|
|
|
+ // 6.3 填充7行任务数据
|
|
|
+ int taskStartRow = currentRow; // 任务起始行(用于合并单元格)
|
|
|
+ for (TaskDef task : taskDefs) {
|
|
|
+ Row dataRow = sheet.createRow(currentRow);
|
|
|
+
|
|
|
+ // 时间列(首行填充,后续合并)
|
|
|
+ Cell dateCell = dataRow.createCell(0);
|
|
|
+ if (currentRow == taskStartRow) {
|
|
|
+ dateCell.setCellValue(duty.getDutyDate().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
|
|
|
+ }
|
|
|
+ dateCell.setCellStyle(contentStyle);
|
|
|
+
|
|
|
+ // 值班人员列(首行填充,后续合并)
|
|
|
+ Cell memberCell = dataRow.createCell(1);
|
|
|
+ if (currentRow == taskStartRow) {
|
|
|
+ memberCell.setCellValue(duty.getMember());
|
|
|
+ }
|
|
|
+ memberCell.setCellStyle(contentStyle);
|
|
|
+
|
|
|
+ // 工作任务列
|
|
|
+ Cell taskCell = dataRow.createCell(2);
|
|
|
+ taskCell.setCellValue(task.getTaskContent());
|
|
|
+ taskCell.setCellStyle(contentStyle);
|
|
|
+
|
|
|
+ // 完成情况列
|
|
|
+ Cell statusCell = dataRow.createCell(3);
|
|
|
+ statusCell.setCellValue(getCompletionStatus(task.getTaskType(), businessMap, duty));
|
|
|
+ statusCell.setCellStyle(contentStyle);
|
|
|
+
|
|
|
+ currentRow++;
|
|
|
+ }
|
|
|
+
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(taskStartRow, currentRow - 1, 0, 0));
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(taskStartRow, currentRow - 1, 1, 1));
|
|
|
+
|
|
|
+ currentRow++;
|
|
|
+ }
|
|
|
+
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ String fileName = URLEncoder.encode("批量坐班值守任务表.xlsx", "UTF-8");
|
|
|
+ response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
|
|
|
+ workbook.write(response.getOutputStream());
|
|
|
+ workbook.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取任务完成情况(复用单条导出逻辑)
|
|
|
+ */
|
|
|
+ private String getCompletionStatus(int taskType, Map<Integer, List<MhFireDutyBusiness>> businessMap, MhFireDuty fireDuty) {
|
|
|
+ if (taskType >= 1 && taskType <= 4) {
|
|
|
+ List<MhFireDutyBusiness> businessList = businessMap.getOrDefault(taskType, Collections.emptyList());
|
|
|
+ return businessList.stream()
|
|
|
+ .map(biz -> biz.getUnit() + "-" + biz.getStatus())
|
|
|
+ .collect(Collectors.joining(";"));
|
|
|
+ } else if (taskType == 5) {
|
|
|
+ return Optional.ofNullable(fireDuty.getDisposalContent()).orElse("");
|
|
|
+ } else if (taskType == 6) {
|
|
|
+ return Optional.ofNullable(fireDuty.getMaterialCollection()).orElse("");
|
|
|
+ } else if (taskType == 7) {
|
|
|
+ return Optional.ofNullable(fireDuty.getDynamicMonitoring()).orElse("");
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 样式创建方法(与之前一致)
|
|
|
+ private CellStyle createTitleStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 14);
|
|
|
+ style.setFont(font);
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ private CellStyle createHeaderStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ style.setFont(font);
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ private CellStyle createContentStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ style.setAlignment(HorizontalAlignment.LEFT);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.TOP);
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ style.setWrapText(true);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 任务定义内部类
|
|
|
+ private static class TaskDef {
|
|
|
+ private final int taskType;
|
|
|
+ private final String taskContent;
|
|
|
+
|
|
|
+ public TaskDef(int taskType, String taskContent) {
|
|
|
+ this.taskType = taskType;
|
|
|
+ this.taskContent = taskContent;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getTaskType() {
|
|
|
+ return taskType;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getTaskContent() {
|
|
|
+ return taskContent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|