package cn.iocoder.yudao.module.mes.service.safety;
|
|
import cn.idev.excel.FastExcelFactory;
|
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
|
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.ledger.SafetyLedgerExportReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.*;
|
import cn.iocoder.yudao.module.mes.enums.safety.*;
|
import jakarta.annotation.Resource;
|
import jakarta.servlet.http.HttpServletResponse;
|
import org.springframework.stereotype.Service;
|
|
import java.io.IOException;
|
import java.time.LocalDate;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.List;
|
import java.util.Objects;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.SafetyErrorCodeConstants.SAFETY_LEDGER_DATE_RANGE_INVALID;
|
|
/**
|
* 安全生产 - 电力行业标准化台账导出 Service
|
*
|
* <p>按「全套」导出时一次生成多 Sheet 工作簿,覆盖安全标准化检查所需的全部台账:
|
* 组织架构、特种作业证、巡检记录、隐患台账、作业票、监护记录、物资台账、
|
* 出入库流水、培训记录、演练记录、事故登记。</p>
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
public class SafetyLedgerExportService {
|
|
@Resource
|
private SafetyOrgService orgService;
|
@Resource
|
private SafetyCertificateService certificateService;
|
@Resource
|
private SafetyInspectionService inspectionService;
|
@Resource
|
private SafetyHazardService hazardService;
|
@Resource
|
private SafetyWorkPermitService permitService;
|
@Resource
|
private SafetyMaterialService materialService;
|
@Resource
|
private SafetyTrainingService trainingService;
|
|
/**
|
* 导出标准化台账
|
*/
|
public void export(SafetyLedgerExportReqVO reqVO, HttpServletResponse response) throws IOException {
|
LocalDate start = reqVO.getStartDate();
|
LocalDate end = reqVO.getEndDate();
|
if (start != null && end != null && start.isAfter(end)) {
|
throw exception(SAFETY_LEDGER_DATE_RANGE_INVALID);
|
}
|
String type = reqVO.getType() == null ? "ALL" : reqVO.getType();
|
List<Sheet> sheets = new ArrayList<>();
|
if ("ALL".equals(type) || "CERT".equals(type)) {
|
sheets.add(certSheet());
|
}
|
if ("ALL".equals(type) || "INSPECTION".equals(type)) {
|
sheets.add(inspectionSheet(start, end));
|
}
|
if ("ALL".equals(type) || "HAZARD".equals(type)) {
|
sheets.add(hazardSheet(start, end));
|
}
|
if ("ALL".equals(type) || "PERMIT".equals(type)) {
|
sheets.add(permitSheet(start, end));
|
sheets.add(monitorSheet());
|
}
|
if ("ALL".equals(type) || "MATERIAL".equals(type)) {
|
sheets.add(materialSheet());
|
sheets.add(stockSheet(start, end));
|
}
|
if ("ALL".equals(type) || "TRAINING".equals(type)) {
|
sheets.add(trainingSheet(start, end));
|
}
|
if ("ALL".equals(type) || "DRILL".equals(type)) {
|
sheets.add(drillSheet(start, end));
|
}
|
if ("ALL".equals(type) || "ACCIDENT".equals(type)) {
|
sheets.add(accidentSheet(start, end));
|
}
|
String filename = switch (type) {
|
case "CERT" -> "特种作业证台账.xlsx";
|
case "INSPECTION" -> "安全巡检台账.xlsx";
|
case "HAZARD" -> "隐患台账.xlsx";
|
case "PERMIT" -> "高危作业票台账.xlsx";
|
case "MATERIAL" -> "应急物资台账.xlsx";
|
case "TRAINING" -> "安全培训台账.xlsx";
|
case "DRILL" -> "消防演练台账.xlsx";
|
case "ACCIDENT" -> "事故登记台账.xlsx";
|
default -> "安全生产标准化台账.xlsx";
|
};
|
write(response, filename, sheets);
|
}
|
|
// ==================== 各 Sheet ====================
|
|
private Sheet certSheet() {
|
List<String> headers = List.of("持证人", "工号", "部门", "证件类型", "证件编号", "发证机关",
|
"发证日期", "有效期至", "下次复审", "状态", "预警天数", "备注");
|
var pageReqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.cert.SafetyCertificatePageReqVO();
|
pageReqVO.setPageNo(1);
|
pageReqVO.setPageSize(50_000);
|
var certs = certificateService.getCertificatePage(pageReqVO).getList();
|
// 导出时用员工档案的最新姓名/工号/部门
|
certificateService.fillEmployeeInfo(certs);
|
List<List<Object>> rows = certs.stream()
|
.map(c -> Arrays.<Object>asList(
|
str(c.getEmployeeName()), str(c.getEmployeeNo()), str(c.getDeptName()),
|
SafetyCertificateTypeEnum.getNameByType(c.getCertType()), str(c.getCertNo()),
|
str(c.getIssuer()), date(c.getIssueDate()), date(c.getExpireDate()),
|
date(c.getReviewDate()),
|
SafetyCertificateStatusEnum.getNameByStatus(SafetyCertificateService.resolveStatus(
|
c.getExpireDate(), c.getWarnDays(), c.getStatus())),
|
Objects.toString(c.getWarnDays(), ""), str(c.getRemark())))
|
.toList();
|
return new Sheet("特种作业证台账", headers, rows);
|
}
|
|
private Sheet inspectionSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("巡检时间", "点位名称", "点位类型", "巡检人", "结果", "巡检情况", "发现隐患数");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.inspection.SafetyInspectionPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(50_000);
|
if (start != null && end != null) {
|
reqVO.setInspectTime(new java.time.LocalDateTime[]{start.atStartOfDay(), end.atTime(23, 59, 59)});
|
}
|
var inspections = inspectionService.getInspectionPage(reqVO).getList();
|
inspectionService.fillInspectorNames(inspections);
|
List<List<Object>> rows = inspections.stream()
|
.map(i -> Arrays.<Object>asList(
|
dateTime(i.getInspectTime()), str(i.getPointName()),
|
SafetyInspectionPointTypeEnum.getNameByType(i.getPointType()),
|
str(i.getInspector()),
|
"NORMAL".equals(i.getResult()) ? "正常" : "异常",
|
str(i.getContent()), Objects.toString(i.getHazardCount(), "0")))
|
.toList();
|
return new Sheet("安全巡检台账", headers, rows);
|
}
|
|
private Sheet hazardSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("隐患编号", "标题", "等级", "来源", "位置", "上报人", "上报时间",
|
"整改责任人", "整改期限", "整改措施", "整改时间", "复查人", "复查时间", "复查结论", "状态", "闭环时间");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.hazard.SafetyHazardPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(50_000);
|
if (start != null && end != null) {
|
reqVO.setReportTime(new java.time.LocalDateTime[]{start.atStartOfDay(), end.atTime(23, 59, 59)});
|
}
|
var hazards = hazardService.getHazardPage(reqVO).getList();
|
hazardService.fillPersonNames(hazards);
|
List<List<Object>> rows = hazards.stream()
|
.map(h -> Arrays.<Object>asList(
|
str(h.getCode()), str(h.getTitle()),
|
SafetyHazardLevelEnum.getNameByLevel(h.getLevel()),
|
SafetyHazardSourceEnum.getNameBySource(h.getSource()),
|
str(h.getLocation()), str(h.getReporter()), dateTime(h.getReportTime()),
|
str(h.getAssignee()), date(h.getRectifyDeadline()), str(h.getRectifyDesc()),
|
dateTime(h.getRectifyTime()), str(h.getRechecker()), dateTime(h.getRecheckTime()),
|
"PASSED".equals(str(h.getRecheckResult())) ? "通过"
|
: "REJECTED".equals(str(h.getRecheckResult())) ? "不通过" : "",
|
SafetyHazardStatusEnum.getNameByStatus(h.getStatus()), dateTime(h.getCloseTime())))
|
.toList();
|
return new Sheet("隐患台账", headers, rows);
|
}
|
|
private Sheet permitSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("作业票编号", "作业类型", "作业名称", "作业区域", "作业地点", "申请人",
|
"申请时间", "计划开始", "计划结束", "实际开始", "实际结束", "风险等级", "监护人",
|
"审批人", "审批时间", "审批意见", "状态");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.permit.SafetyWorkPermitPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(50_000);
|
if (start != null && end != null) {
|
reqVO.setPlanStartTime(new java.time.LocalDateTime[]{start.atStartOfDay(), end.atTime(23, 59, 59)});
|
}
|
var permits = permitService.getPermitPage(reqVO).getList();
|
permitService.fillPermitRefs(permits);
|
List<List<Object>> rows = permits.stream()
|
.map(p -> Arrays.<Object>asList(
|
str(p.getCode()), SafetyPermitTypeEnum.getNameByType(p.getPermitType()),
|
str(p.getTitle()), str(p.getWorkshopName()), str(p.getLocation()),
|
str(p.getApplicant()), dateTime(p.getApplyTime()), dateTime(p.getPlanStartTime()),
|
dateTime(p.getPlanEndTime()), dateTime(p.getActualStartTime()), dateTime(p.getActualEndTime()),
|
SafetyRiskLevelEnum.getNameByLevel(p.getRiskLevel()), str(p.getGuardian()),
|
str(p.getApprover()), dateTime(p.getApproveTime()), str(p.getApproveComment()),
|
SafetyPermitStatusEnum.getNameByStatus(p.getStatus())))
|
.toList();
|
return new Sheet("高危作业票台账", headers, rows);
|
}
|
|
private Sheet monitorSheet() {
|
List<String> headers = List.of("作业票编号", "监护时间", "监护人", "监护内容", "异常情况");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.permit.SafetyWorkPermitPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(5_000);
|
List<List<Object>> rows = new ArrayList<>();
|
for (SafetyWorkPermitDO permit : permitService.getPermitPage(reqVO).getList()) {
|
var monitors = permitService.getMonitorList(permit.getId());
|
permitService.fillMonitorGuardians(monitors);
|
for (SafetyWorkPermitMonitorDO monitor : monitors) {
|
rows.add(Arrays.asList(str(permit.getCode()), dateTime(monitor.getMonitorTime()),
|
str(monitor.getGuardian()), str(monitor.getMonitorContent()), str(monitor.getAbnormal())));
|
}
|
}
|
return new Sheet("作业监护记录", headers, rows);
|
}
|
|
private Sheet materialSheet() {
|
List<String> headers = List.of("物资编码", "物资名称", "类别", "规格型号", "单位", "库存数量",
|
"安全库存", "存放位置", "有效期至", "保管人", "状态");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.material.SafetyMaterialPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(50_000);
|
var materials = materialService.getMaterialPage(reqVO).getList();
|
materialService.fillManagers(materials);
|
List<List<Object>> rows = materials.stream()
|
.map(m -> Arrays.<Object>asList(
|
str(m.getCode()), str(m.getName()),
|
SafetyMaterialCategoryEnum.getNameByCategory(m.getCategory()),
|
str(m.getSpec()), str(m.getUnit()), number(m.getStockQty()), number(m.getSafeStock()),
|
str(m.getStorageLocation()), date(m.getExpireDate()), str(m.getManager()),
|
Integer.valueOf(0).equals(m.getStatus()) ? "启用" : "停用"))
|
.toList();
|
return new Sheet("应急物资台账", headers, rows);
|
}
|
|
private Sheet stockSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("业务日期", "物资名称", "类别", "业务类型", "数量",
|
"操作前库存", "操作后库存", "经办人", "领用人", "用途/去向");
|
var reqVO = new cn.iocoder.yudao.module.mes.controller.admin.safety.vo.material.SafetyMaterialStockPageReqVO();
|
reqVO.setPageNo(1);
|
reqVO.setPageSize(50_000);
|
if (start != null && end != null) {
|
reqVO.setBizDate(new LocalDate[]{start, end});
|
}
|
List<List<Object>> rows = materialService.getStockPage(reqVO).getList().stream()
|
.map(s -> Arrays.<Object>asList(
|
date(s.getBizDate()), str(s.getMaterialName()),
|
SafetyMaterialCategoryEnum.getNameByCategory(s.getCategory()),
|
"IN".equals(s.getBizType()) ? "入库" : "出库",
|
number(s.getQuantity()), number(s.getStockBefore()), number(s.getStockAfter()),
|
str(s.getOperator()), str(s.getReceiver()), str(s.getPurpose())))
|
.toList();
|
return new Sheet("物资出入库流水", headers, rows);
|
}
|
|
private Sheet trainingSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("培训日期", "培训主题", "培训类型", "学时", "讲师/组织人",
|
"培训地点", "参加人数", "培训内容", "考核情况");
|
var trainings = trainingService.listTrainingBetween(start, end);
|
trainingService.fillTrainers(trainings);
|
List<List<Object>> rows = trainings.stream()
|
.map(t -> Arrays.<Object>asList(
|
date(t.getTrainDate()), str(t.getTitle()),
|
SafetyTrainingTypeEnum.getNameByType(t.getTrainingType()),
|
number(t.getDurationHours()), str(t.getTrainer()), str(t.getLocation()),
|
Objects.toString(t.getParticipantCount(), "0"),
|
str(t.getContent()), str(t.getExamResult())))
|
.toList();
|
return new Sheet("安全培训台账", headers, rows);
|
}
|
|
private Sheet drillSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("演练日期", "演练名称", "演练类型", "地点", "组织人",
|
"参加人数", "时长(分钟)", "演练过程", "总结与改进");
|
var drills = trainingService.listDrillBetween(start, end);
|
trainingService.fillOrganizers(drills);
|
List<List<Object>> rows = drills.stream()
|
.map(d -> Arrays.<Object>asList(
|
date(d.getDrillDate()), str(d.getTitle()),
|
SafetyDrillTypeEnum.getNameByType(d.getDrillType()), str(d.getLocation()),
|
str(d.getOrganizer()), Objects.toString(d.getParticipantCount(), "0"),
|
Objects.toString(d.getDurationMinutes(), ""),
|
str(d.getProcessDesc()), str(d.getSummary())))
|
.toList();
|
return new Sheet("消防演练台账", headers, rows);
|
}
|
|
private Sheet accidentSheet(LocalDate start, LocalDate end) {
|
List<String> headers = List.of("事故编号", "事故名称", "事故类型", "等级", "发生时间", "发生地点",
|
"伤亡情况", "经济损失(元)", "事故经过", "原因分析", "处理措施", "状态");
|
var accidents = trainingService.listAccidentBetween(start, end);
|
trainingService.fillAccidentRefs(accidents);
|
List<List<Object>> rows = accidents.stream()
|
.map(a -> Arrays.<Object>asList(
|
str(a.getCode()), str(a.getTitle()),
|
SafetyAccidentTypeEnum.getNameByType(a.getAccidentType()),
|
SafetyAccidentLevelEnum.getNameByLevel(a.getLevel()),
|
dateTime(a.getOccurTime()), str(a.getLocation()), str(a.getCasualtyDesc()),
|
number(a.getEconomicLoss()), str(a.getDescription()), str(a.getCauseAnalysis()),
|
str(a.getMeasures()), SafetyAccidentStatusEnum.getNameByStatus(a.getStatus())))
|
.toList();
|
return new Sheet("事故登记台账", headers, rows);
|
}
|
|
// ==================== 工具方法 ====================
|
|
private static String str(String value) {
|
return value == null ? "" : value;
|
}
|
|
private static String date(LocalDate value) {
|
return value == null ? "" : value.toString();
|
}
|
|
private static String dateTime(java.time.LocalDateTime value) {
|
return value == null ? "" : value.toString().replace('T', ' ');
|
}
|
|
private static String number(java.math.BigDecimal value) {
|
return value == null ? "" : value.stripTrailingZeros().toPlainString();
|
}
|
|
private record Sheet(String name, List<String> headers, List<List<Object>> rows) {
|
}
|
|
private void write(HttpServletResponse response, String filename, List<Sheet> sheets) throws IOException {
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
|
try (var writer = FastExcelFactory.write(response.getOutputStream()).autoCloseStream(false).build()) {
|
for (int i = 0; i < sheets.size(); i++) {
|
Sheet sheet = sheets.get(i);
|
writer.write(sheet.rows(), FastExcelFactory.writerSheet(i, sheet.name())
|
.head(sheet.headers().stream().map(List::of).toList()).build());
|
}
|
}
|
}
|
|
}
|