package com.ruoyi.process.service.impl;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.*;
import com.deepoove.poi.data.style.*;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.utils.QueryWrappers;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SignatureImageUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.inspect.mapper.InsOrderMapper;
import com.ruoyi.inspect.mapper.InsReportMapper;
import com.ruoyi.inspect.pojo.InsOrder;
import com.ruoyi.inspect.pojo.InsReport;
import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
import com.ruoyi.process.dto.ProcessReportDto;
import com.ruoyi.process.mapper.ProcessReportMapper;
import com.ruoyi.process.pojo.ProcessReport;
import com.ruoyi.process.service.ProcessReportService;
import com.ruoyi.system.mapper.UserMapper;
import org.apache.commons.io.IOUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
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;
/**
*
* 检验报告发放登记表 服务实现类
*
*
* @author
* @since 2024-11-05 08:58:39
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ProcessReportServiceImpl extends ServiceImpl implements ProcessReportService {
@Resource
private ProcessReportMapper processReportMapper;
@Value("${file.path}")
private String imgUrl;
@Value("${wordUrl}")
private String wordUrl;
@Resource
private UserMapper userMapper;
@Resource
private InsReportMapper insReportMapper;
@Resource
private InsOrderMapper insOrderMapper;
@Override
public IPage pageProcessReport(Page page, ProcessReportDto processReport) {
// #21 打开列表时,自动带出已通过审批(批准状态=批准)但尚未登记的检验单
autoBringOutApproved();
IPage processReportIPage = processReportMapper.pageProcessReport(page, QueryWrappers.queryWrappers(processReport));
return processReportIPage;
}
/**
* 扫描已批准但尚未进入报告结果登记表的检验报告,自动生成待登记记录(以报告编号去重,幂等)。
*/
private void autoBringOutApproved() {
List approved = insReportMapper.selectList(Wrappers.lambdaQuery()
.eq(InsReport::getIsRatify, 1)
.eq(InsReport::getIsPass, 1));
if (approved.isEmpty()) {
return;
}
Set existing = this.list(Wrappers.lambdaQuery()
.select(ProcessReport::getInsReportCode)).stream()
.map(ProcessReport::getInsReportCode)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toCollection(HashSet::new));
for (InsReport report : approved) {
String code = report.getCode();
if (StringUtils.isBlank(code) || existing.contains(code)) {
continue;
}
ProcessReport pr = new ProcessReport();
pr.setInsReportCode(code);
pr.setInspectionOrderId(report.getInsOrderId());
if (report.getRatifyTime() != null) {
pr.setSendTime(report.getRatifyTime().toLocalDate());
}
if (report.getInsOrderId() != null) {
InsOrder order = insOrderMapper.selectById(report.getInsOrderId());
if (order != null) {
pr.setSend(order.getCompany());
pr.setMethod(getReportDeliveryName(order));
}
}
this.save(pr);
existing.add(code);
}
}
private String getReportDeliveryName(InsOrder order) {
if (order.getReportDelivery() != null) {
switch (order.getReportDelivery()) {
case 1:
return "自取";
case 2:
return "快递";
case 3:
return "电子传送";
default:
break;
}
}
// 兼容尚未维护 report_delivery 的历史委托单。
return order.getSend() != null && order.getSend() == 1 ? "自取" : "其他";
}
@Override
public void downloadStampedReport(Integer id, String format, HttpServletResponse response) {
if (id == null) {
throw new ErrorException("报告结果不能为空");
}
ProcessReport processReport = getById(id);
if (processReport == null) {
throw new ErrorException("报告结果不存在");
}
if (StringUtils.isBlank(processReport.getInsReportCode())
&& processReport.getInspectionOrderId() == null) {
throw new ErrorException("该记录未关联检验报告,无法下载");
}
String downloadFormat = StringUtils.isBlank(format) ? "pdf" : format.trim().toLowerCase();
if (!"pdf".equals(downloadFormat) && !"word".equals(downloadFormat)) {
throw new ErrorException("下载格式不正确");
}
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper query =
Wrappers.lambdaQuery()
.eq(InsReport::getIsRatify, 1)
.eq(StringUtils.isNotBlank(processReport.getInsReportCode()),
InsReport::getCode, processReport.getInsReportCode())
.eq(processReport.getInspectionOrderId() != null,
InsReport::getInsOrderId, processReport.getInspectionOrderId())
.orderByDesc(InsReport::getId)
.last("limit 1");
InsReport report = insReportMapper.selectOne(query);
if (report == null) {
throw new ErrorException("未找到已批准的报告,无法下载有章报告");
}
String fileUrl;
String extension;
String contentType;
if ("word".equals(downloadFormat)) {
fileUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl();
extension = ".docx";
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
} else {
fileUrl = report.getTempUrlPdf();
extension = ".pdf";
contentType = "application/pdf";
}
if ("pdf".equals(downloadFormat) && StringUtils.isBlank(fileUrl)) {
String reportUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl();
if (StringUtils.isNotBlank(reportUrl) && reportUrl.toLowerCase().endsWith(".docx")) {
fileUrl = reportUrl.substring(0, reportUrl.length() - 5) + ".pdf";
}
}
if (StringUtils.isBlank(fileUrl) || !fileUrl.replace('\\', '/').startsWith("/word/")) {
throw new ErrorException("有章报告尚未生成,请先完成报告批准");
}
Path root = Paths.get(wordUrl).toAbsolutePath().normalize();
Path file = root.resolve(fileUrl.replace('\\', '/').substring("/word/".length())).normalize();
if (!file.startsWith(root) || !Files.isRegularFile(file)) {
throw new ErrorException("有章报告文件不存在,请重新批准生成");
}
try {
String filename = StringUtils.isNotBlank(processReport.getInsReportCode())
? processReport.getInsReportCode() + extension : file.getFileName().toString();
String encodedName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20");
response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
response.setHeader("download-filename", encodedName);
response.setContentLengthLong(Files.size(file));
try (InputStream inputStream = Files.newInputStream(file);
OutputStream outputStream = response.getOutputStream()) {
IOUtils.copy(inputStream, outputStream);
outputStream.flush();
}
} catch (IOException e) {
throw new ErrorException("有章报告下载失败");
}
}
@Override
public void exportProcessReport(ProcessReportDto dto, HttpServletResponse response) {
List processReports = processReportMapper.exportProcessReport();
for (ProcessReportDto processReport : processReports) {
// 发送人生成签名图片
processReport.setSendUserRender(StringUtils.isNotBlank(processReport.getSendUserUrl())
? Pictures.ofLocal(imgUrl + "/" + processReport.getSendUserUrl()).create() : null);
// 签收人生成图片
processReport.setSignatoryRender(StringUtils.isNotBlank(processReport.getSignatory())
? Pictures.ofStream(SignatureImageUtil.saveImageToFile(processReport.getSignatory())).create() : null);
}
// 获取路径
InputStream inputStream = this.getClass().getResourceAsStream("/static/report-deal.docx");
Configure configure = Configure.builder()
.bind("reportList", new HackLoopTableRenderPolicy())
.build();
XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(
new HashMap() {{
put("reportList", processReports);
}});
try {
response.setContentType("application/msword");
String fileName = URLEncoder.encode(
"检验报告发放登记表", "UTF-8");
response.setHeader("Content-disposition",
"attachment;filename=" + fileName + ".docx");
OutputStream os = response.getOutputStream();
template.write(os);
os.flush();
os.close();
inputStream.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("导出失败");
}
}
}