新增根据word模版生成word方法;新增质量管理相关接口;优化,修改HSE管理相关代码逻辑

This commit is contained in:
lcj
2025-04-17 17:40:24 +08:00
parent 86745097ca
commit 3a8538fc6a
35 changed files with 2788 additions and 86 deletions

Binary file not shown.

Binary file not shown.

View File

@ -222,9 +222,11 @@ springdoc:
packages-to-scan: org.dromara.machinery packages-to-scan: org.dromara.machinery
- group: 6.安全模块 - group: 6.安全模块
packages-to-scan: org.dromara.safety packages-to-scan: org.dromara.safety
- group: 7.代码生成模块 - group: 7.质量模块
packages-to-scan: org.dromara.quality
- group: 8.代码生成模块
packages-to-scan: org.dromara.generator packages-to-scan: org.dromara.generator
- group: 8.工作流模块 - group: 9.工作流模块
packages-to-scan: org.dromara.workflow packages-to-scan: org.dromara.workflow
# 防止XSS攻击 # 防止XSS攻击

View File

@ -3,6 +3,7 @@ package org.dromara.common.oss.core;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.core.utils.file.FileUtils;
@ -31,6 +32,7 @@ import java.net.URI;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration; import java.time.Duration;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -235,6 +237,41 @@ public class OssClient {
return tempFilePath; return tempFilePath;
} }
/**
* 下载文件从 Amazon S3 到临时目录
*
* @param path 文件在 Amazon S3 中的对象键
* @param fileName 文件名
* @param filePath 文件路径
* @return 下载后的文件在本地的临时路径
* @throws OssException 如果下载失败,抛出自定义异常
*/
public String fileDownload(String path, String fileName, String filePath) {
// 构建临时文件
Path targetDir = Paths.get(filePath);
try {
if (Files.notExists(targetDir)) {
Files.createDirectories(targetDir);
}
} catch (IOException e) {
throw new ServiceException("无法创建目标目录: " + targetDir + e);
}
// 拼出本地完整路径
Path destinationPath = targetDir.resolve(fileName);
// 使用 S3TransferManager 下载文件
FileDownload downloadFile = transferManager.downloadFile(
x -> x.getObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(removeBaseUrl(path))
.build())
.addTransferListener(LoggingTransferListener.create())
.destination(destinationPath)
.build());
// 等待文件下载操作完成
downloadFile.completionFuture().join();
return filePath + "/" + fileName;
}
/** /**
* 下载文件从 Amazon S3 到 输出流 * 下载文件从 Amazon S3 到 输出流
* *

View File

@ -0,0 +1,47 @@
package org.dromara.quality.constant;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.quality.domain.BusQualityConstructionLog;
import org.dromara.quality.domain.BusQualityInspection;
import java.text.SimpleDateFormat;
/**
* @author lcj
* @date 2025/4/17 14:36
*/
public interface QualityConstant {
String QUALITY_INSPECTION_CHECK_TYPE = "quality_inspection_check_type";
String QUALITY_INSPECTION_STATUS_TYPE = "quality_inspection_status_type";
String QUALITY_CONSTRUCTION_LOG_TEMPLATE_PATH = "docs/template/施工日志模版.docx";
String QUALITY_CONSTRUCTION_LOG_FILE_URL = "docs/quality/constructionLog/";
static String getQualityConstructionLogFileUrl(BusQualityConstructionLog qualityConstructionLog) {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(qualityConstructionLog.getUpdateTime());
return String.format("%s%s/%s", QUALITY_CONSTRUCTION_LOG_FILE_URL, qualityConstructionLog.getId(), timestamp);
}
static String getQualityConstructionLogFileName(BusQualityConstructionLog qualityConstructionLog) {
String createDate = DateUtils.formatDate(qualityConstructionLog.getCreateTime());
return String.format("施工日志(%s.docx", createDate);
}
String QUALITY_INSPECTION_TEMPLATE_PATH = "docs/template/整改通知单模版.docx";
String QUALITY_INSPECTION_FILE_URL = "docs/quality/inspection/";
static String getQualityInspectionFileUrl(BusQualityInspection qualityInspection) {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(qualityInspection.getUpdateTime());
return String.format("%s%s/%s", QUALITY_INSPECTION_FILE_URL, qualityInspection.getId(), timestamp);
}
static String getQualityInspectionFileName(BusQualityInspection qualityInspection) {
String createDate = DateUtils.formatDate(qualityInspection.getCreateTime());
return String.format("整改通知单(%s.docx", createDate);
}
}

View File

@ -0,0 +1,119 @@
package org.dromara.quality.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogCreateReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogQueryReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogUpdateReq;
import org.dromara.quality.domain.vo.BusQualityConstructionLogVo;
import org.dromara.quality.service.IBusQualityConstructionLogService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 质量-施工日志
*
* @author lcj
* @date 2025-04-16
*/
@Validated
@RestController
@RequestMapping("/quality/qualityConstructionLog")
public class BusQualityConstructionLogController extends BaseController {
@Resource
private IBusQualityConstructionLogService busQualityConstructionLogService;
/**
* 查询质量-施工日志列表
*/
@SaCheckPermission("quality:qualityConstructionLog:list")
@GetMapping("/list")
public TableDataInfo<BusQualityConstructionLogVo> list(QualityConstructionLogQueryReq req, PageQuery pageQuery) {
return busQualityConstructionLogService.queryPageList(req, pageQuery);
}
/**
* 导出质量-施工日志列表
*/
@SaCheckPermission("quality:qualityConstructionLog:export")
@Log(title = "质量-施工日志", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(QualityConstructionLogQueryReq req, HttpServletResponse response) {
List<BusQualityConstructionLogVo> list = busQualityConstructionLogService.queryList(req);
ExcelUtil.exportExcel(list, "质量-施工日志", BusQualityConstructionLogVo.class, response);
}
/**
* 根据主键导出质量-施工日志
*/
@SaCheckPermission("quality:qualityConstructionLog:export")
@Log(title = "质量-施工日志", businessType = BusinessType.EXPORT)
@PostMapping("/export/word")
public void exportWordById(@NotNull(message = "主键不能为空") Long id,
HttpServletResponse response) {
busQualityConstructionLogService.exportWordById(id, response);
}
/**
* 获取质量-施工日志详细信息
*
* @param id 主键
*/
@SaCheckPermission("quality:qualityConstructionLog:query")
@GetMapping("/{id}")
public R<BusQualityConstructionLogVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busQualityConstructionLogService.queryById(id));
}
/**
* 新增质量-施工日志
*/
@SaCheckPermission("quality:qualityConstructionLog:add")
@Log(title = "质量-施工日志", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody QualityConstructionLogCreateReq req) {
return R.ok(busQualityConstructionLogService.insertByBo(req));
}
/**
* 修改质量-施工日志
*/
@SaCheckPermission("quality:qualityConstructionLog:edit")
@Log(title = "质量-施工日志", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody QualityConstructionLogUpdateReq req) {
return toAjax(busQualityConstructionLogService.updateByBo(req));
}
/**
* 删除质量-施工日志
*
* @param ids 主键串
*/
@SaCheckPermission("quality:qualityConstructionLog:remove")
@Log(title = "质量-施工日志", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busQualityConstructionLogService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,119 @@
package org.dromara.quality.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionCreateReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionQueryReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionUpdateReq;
import org.dromara.quality.domain.vo.BusQualityInspectionVo;
import org.dromara.quality.service.IBusQualityInspectionService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 质量-检查工单
*
* @author lcj
* @date 2025-04-16
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/quality/qualityInspection")
public class BusQualityInspectionController extends BaseController {
private final IBusQualityInspectionService busQualityInspectionService;
/**
* 查询质量-检查工单列表
*/
@SaCheckPermission("quality:qualityInspection:list")
@GetMapping("/list")
public TableDataInfo<BusQualityInspectionVo> list(QualityInspectionQueryReq req, PageQuery pageQuery) {
return busQualityInspectionService.queryPageList(req, pageQuery);
}
/**
* 导出质量-检查工单列表
*/
@SaCheckPermission("quality:qualityInspection:export")
@Log(title = "质量-检查工单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(QualityInspectionQueryReq req, HttpServletResponse response) {
List<BusQualityInspectionVo> list = busQualityInspectionService.queryList(req);
ExcelUtil.exportExcel(list, "质量-检查工单", BusQualityInspectionVo.class, response);
}
/**
* 根据主键导出质量-检查工单
*/
@SaCheckPermission("quality:qualityInspection:export")
@Log(title = "质量-检查工单", businessType = BusinessType.EXPORT)
@PostMapping("/export/word")
public void exportWordById(@NotNull(message = "主键不能为空") Long id,
HttpServletResponse response) {
busQualityInspectionService.exportWordById(id, response);
}
/**
* 获取质量-检查工单详细信息
*
* @param id 主键
*/
@SaCheckPermission("quality:qualityInspection:query")
@GetMapping("/{id}")
public R<BusQualityInspectionVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busQualityInspectionService.queryById(id));
}
/**
* 新增质量-检查工单
*/
@SaCheckPermission("quality:qualityInspection:add")
@Log(title = "质量-检查工单", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody QualityInspectionCreateReq req) {
return R.ok(busQualityInspectionService.insertByBo(req));
}
/**
* 修改质量-检查工单
*/
@SaCheckPermission("quality:qualityInspection:edit")
@Log(title = "质量-检查工单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody QualityInspectionUpdateReq req) {
return toAjax(busQualityInspectionService.updateByBo(req));
}
/**
* 删除质量-检查工单
*
* @param ids 主键串
*/
@SaCheckPermission("quality:qualityInspection:remove")
@Log(title = "质量-检查工单", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busQualityInspectionService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,74 @@
package org.dromara.quality.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 质量-施工日志对象 bus_quality_construction_log
*
* @author lcj
* @date 2025-04-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_quality_construction_log")
public class BusQualityConstructionLog extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 发生日期
*/
private Date happenDate;
/**
* 生产情况
*/
private String productionStatus;
/**
* 技术质量安全工作
*/
private String technologyQuality;
/**
* 附件
*/
private String file;
/**
* 备注
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -0,0 +1,129 @@
package org.dromara.quality.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 质量-检查工单对象 bus_quality_inspection
*
* @author lcj
* @date 2025-04-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_quality_inspection")
public class BusQualityInspection extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 巡检类型
*/
private String inspectionType;
/**
* 巡检标题
*/
private String inspectionHeadline;
/**
* 巡检结果
*/
private String inspectionResult;
/**
* 工单状态1通知 2整改 3验证
*/
private String inspectionStatus;
/**
* 巡检附件
*/
private String inspectionFile;
/**
* 班组id
*/
private Long teamId;
/**
* 整改人(班组长)
*/
private Long corrector;
/**
* 是否回复1回复 2不回复
*/
private String isReply;
/**
* 回复期限日期
*/
private Date replyPeriodDate;
/**
* 整改反馈
*/
private String rectificationResult;
/**
* 整改时间
*/
private Date rectificationTime;
/**
* 整改附件
*/
private String rectificationFile;
/**
* 验证结果
*/
private String verificationResult;
/**
* 验证状态1通过 2未通过
*/
private String verificationType;
/**
* 验证时间
*/
private Date verificationTime;
/**
* 备注
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -0,0 +1,26 @@
package org.dromara.quality.domain.enums;
import lombok.Getter;
/**
* @author lcj
* @date 2025/4/16 14:26
*/
@Getter
public enum QualityInspectionStatusEnum {
INFORM("通知", "1"),
RECTIFICATION("整改", "2"),
VERIFICATION("验证", "3"),
PASS("通过", "4");
private final String text;
private final String value;
QualityInspectionStatusEnum(String text, String value) {
this.text = text;
this.value = value;
}
}

View File

@ -0,0 +1,51 @@
package org.dromara.quality.domain.req.qualityconstructionlog;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/4/16 11:54
*/
@Data
public class QualityConstructionLogCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = -9122588005233479105L;
/**
* 项目id
*/
private Long projectId;
/**
* 发生日期
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date happenDate;
/**
* 生产情况
*/
private String productionStatus;
/**
* 技术质量安全工作
*/
private String technologyQuality;
/**
* 附件
*/
private String file;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,31 @@
package org.dromara.quality.domain.req.qualityconstructionlog;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/4/16 11:55
*/
@Data
public class QualityConstructionLogQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -4555254995729496353L;
/**
* 项目id
*/
private Long projectId;
/**
* 发生日期
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date happenDate;
}

View File

@ -0,0 +1,48 @@
package org.dromara.quality.domain.req.qualityconstructionlog;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/16 11:57
*/
@Data
public class QualityConstructionLogUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = 5378506292803717193L;
/**
* 主键id
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 生产情况
*/
private String productionStatus;
/**
* 技术质量安全工作
*/
private String technologyQuality;
/**
* 附件
*/
private String file;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,64 @@
package org.dromara.quality.domain.req.qualityinspection;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/4/16 14:03
*/
@Data
public class QualityInspectionCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = -4466466614771971424L;
/**
* 项目id
*/
private Long projectId;
/**
* 巡检类型
*/
private String inspectionType;
/**
* 巡检标题
*/
private String inspectionHeadline;
/**
* 巡检结果
*/
private String inspectionResult;
/**
* 巡检附件
*/
private String inspectionFile;
/**
* 班组id
*/
private Long teamId;
/**
* 整改人(班组长)
*/
private Long corrector;
/**
* 回复期限日期
*/
private Date replyPeriodDate;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,38 @@
package org.dromara.quality.domain.req.qualityinspection;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/16 14:04
*/
@Data
public class QualityInspectionQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 3468757869732753393L;
/**
* 项目id
*/
private Long projectId;
/**
* 巡检类型
*/
private String inspectionType;
/**
* 工单状态1通知 2整改 3验证
*/
private String inspectionStatus;
/**
* 班组id
*/
private Long teamId;
}

View File

@ -0,0 +1,109 @@
package org.dromara.quality.domain.req.qualityinspection;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/4/16 14:04
*/
@Data
public class QualityInspectionUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = -8931016399391922936L;
/**
* 主键id
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 巡检类型
*/
private String inspectionType;
/**
* 巡检标题
*/
private String inspectionHeadline;
/**
* 巡检结果
*/
private String inspectionResult;
/**
* 工单状态1通知 2整改 3验证
*/
private String inspectionStatus;
/**
* 巡检附件
*/
private String inspectionFile;
/**
* 班组id
*/
private Long teamId;
/**
* 整改人(班组长)
*/
private Long corrector;
/**
* 是否回复1回复 2不回复
*/
private String isReply;
/**
* 回复期限日期
*/
private Date replyPeriodDate;
/**
* 整改反馈
*/
private String rectificationResult;
/**
* 整改时间
*/
private Date rectificationTime;
/**
* 整改附件
*/
private String rectificationFile;
/**
* 验证结果
*/
private String verificationResult;
/**
* 验证状态1通过 2未通过
*/
private String verificationType;
/**
* 验证时间
*/
private Date verificationTime;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,85 @@
package org.dromara.quality.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.quality.domain.BusQualityConstructionLog;
import org.dromara.system.domain.vo.SysOssVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 质量-施工日志视图对象 bus_quality_construction_log
*
* @author lcj
* @date 2025-04-16
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusQualityConstructionLog.class)
public class BusQualityConstructionLogVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long id;
/**
* 项目名称
*/
private String projectName;
/**
* 发生日期
*/
@ExcelProperty(value = "发生日期")
private Date happenDate;
/**
* 生产情况
*/
@ExcelProperty(value = "生产情况")
private String productionStatus;
/**
* 技术质量安全工作
*/
@ExcelProperty(value = "技术质量安全工作")
private String technologyQuality;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 附件
*/
private String file;
/**
* 附件列表
*/
private List<SysOssVo> fileList;
/**
* 创建者
*/
@ExcelProperty(value = "创建者")
private String createBy;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,157 @@
package org.dromara.quality.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.quality.domain.BusQualityInspection;
import org.dromara.system.domain.vo.SysOssVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 质量-检查工单视图对象 bus_quality_inspection
*
* @author lcj
* @date 2025-04-16
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusQualityInspection.class)
public class BusQualityInspectionVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 项目名称
*/
private String projectName;
/**
* 巡检类型
*/
@ExcelProperty(value = "巡检类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "quality_inspection_check_type")
private String inspectionType;
/**
* 巡检标题
*/
@ExcelProperty(value = "巡检标题")
private String inspectionHeadline;
/**
* 巡检结果
*/
@ExcelProperty(value = "巡检结果")
private String inspectionResult;
/**
* 工单状态1通知 2整改 3验证
*/
@ExcelProperty(value = "工单状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "quality_inspection_status_type")
private String inspectionStatus;
/**
* 巡检附件
*/
private String inspectionFile;
/**
* 巡检附件列表
*/
private List<SysOssVo> inspectionFileList;
/**
* 班组id
*/
private Long teamId;
/**
* 整改人(班组长)
*/
private Long corrector;
/**
* 整改人姓名
*/
private String correctorName;
/**
* 是否回复1回复 2不回复
*/
private String isReply;
/**
* 回复期限日期
*/
private Date replyPeriodDate;
/**
* 整改反馈
*/
private String rectificationResult;
/**
* 整改时间
*/
private Date rectificationTime;
/**
* 整改附件
*/
private String rectificationFile;
/**
* 整改附件列表
*/
private List<SysOssVo> rectificationFileList;
/**
* 验证结果
*/
private String verificationResult;
/**
* 验证状态1通过 2未通过
*/
private String verificationType;
/**
* 验证时间
*/
private Date verificationTime;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建者
*/
@ExcelProperty(value = "创建者")
private String createBy;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
}

View File

@ -0,0 +1,15 @@
package org.dromara.quality.mapper;
import org.dromara.quality.domain.BusQualityConstructionLog;
import org.dromara.quality.domain.vo.BusQualityConstructionLogVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 质量-施工日志Mapper接口
*
* @author lcj
* @date 2025-04-16
*/
public interface BusQualityConstructionLogMapper extends BaseMapperPlus<BusQualityConstructionLog, BusQualityConstructionLogVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.quality.mapper;
import org.dromara.quality.domain.BusQualityInspection;
import org.dromara.quality.domain.vo.BusQualityInspectionVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 质量-检查工单Mapper接口
*
* @author lcj
* @date 2025-04-16
*/
public interface BusQualityInspectionMapper extends BaseMapperPlus<BusQualityInspection, BusQualityInspectionVo> {
}

View File

@ -0,0 +1,108 @@
package org.dromara.quality.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.quality.domain.BusQualityConstructionLog;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogCreateReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogQueryReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogUpdateReq;
import org.dromara.quality.domain.vo.BusQualityConstructionLogVo;
import java.util.Collection;
import java.util.List;
/**
* 质量-施工日志Service接口
*
* @author lcj
* @date 2025-04-16
*/
public interface IBusQualityConstructionLogService extends IService<BusQualityConstructionLog> {
/**
* 查询质量-施工日志
*
* @param id 主键
* @return 质量-施工日志
*/
BusQualityConstructionLogVo queryById(Long id);
/**
* 分页查询质量-施工日志列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 质量-施工日志分页列表
*/
TableDataInfo<BusQualityConstructionLogVo> queryPageList(QualityConstructionLogQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的质量-施工日志列表
*
* @param req 查询条件
* @return 质量-施工日志列表
*/
List<BusQualityConstructionLogVo> queryList(QualityConstructionLogQueryReq req);
/**
* 新增质量-施工日志
*
* @param req 质量-施工日志
* @return 新增日志主键
*/
Long insertByBo(QualityConstructionLogCreateReq req);
/**
* 修改质量-施工日志
*
* @param req 质量-施工日志
* @return 是否修改成功
*/
Boolean updateByBo(QualityConstructionLogUpdateReq req);
/**
* 校验并批量删除质量-施工日志信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取质量-施工日志视图对象
*
* @param qualityConstructionLog 质量-施工日志对象
* @return 质量-施工日志视图对象
*/
BusQualityConstructionLogVo getVo(BusQualityConstructionLog qualityConstructionLog);
/**
* 获取质量-施工日志查询条件封装
*
* @param req 质量-施工日志查询条件
* @return 质量-施工日志查询条件封装
*/
LambdaQueryWrapper<BusQualityConstructionLog> buildQueryWrapper(QualityConstructionLogQueryReq req);
/**
* 获取质量-施工日志分页对象视图
*
* @param qualityConstructionLogPage 质量-施工日志分页对象
* @return 质量-施工日志分页对象视图
*/
Page<BusQualityConstructionLogVo> getVoPage(Page<BusQualityConstructionLog> qualityConstructionLogPage);
/**
* 导出质量-施工日志
*
* @param id 主键
* @param response 响应
*/
void exportWordById(Long id, HttpServletResponse response);
}

View File

@ -0,0 +1,108 @@
package org.dromara.quality.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.quality.domain.BusQualityInspection;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionCreateReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionQueryReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionUpdateReq;
import org.dromara.quality.domain.vo.BusQualityInspectionVo;
import java.util.Collection;
import java.util.List;
/**
* 质量-检查工单Service接口
*
* @author lcj
* @date 2025-04-16
*/
public interface IBusQualityInspectionService extends IService<BusQualityInspection> {
/**
* 查询质量-检查工单
*
* @param id 主键
* @return 质量-检查工单
*/
BusQualityInspectionVo queryById(Long id);
/**
* 分页查询质量-检查工单列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 质量-检查工单分页列表
*/
TableDataInfo<BusQualityInspectionVo> queryPageList(QualityInspectionQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的质量-检查工单列表
*
* @param req 查询条件
* @return 质量-检查工单列表
*/
List<BusQualityInspectionVo> queryList(QualityInspectionQueryReq req);
/**
* 新增质量-检查工单
*
* @param req 质量-检查工单
* @return 新增检查工单id
*/
Long insertByBo(QualityInspectionCreateReq req);
/**
* 修改质量-检查工单
*
* @param req 质量-检查工单
* @return 是否修改成功
*/
Boolean updateByBo(QualityInspectionUpdateReq req);
/**
* 校验并批量删除质量-检查工单信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取质量-检查工单视图对象
*
* @param qualityInspection 质量-检查工单对象
* @return 质量-检查工单视图对象
*/
BusQualityInspectionVo getVo(BusQualityInspection qualityInspection);
/**
* 获取质量-检查工单查询条件封装
*
* @param req 质量-检查工单查询条件
* @return 质量-检查工单查询条件封装
*/
LambdaQueryWrapper<BusQualityInspection> buildQueryWrapper(QualityInspectionQueryReq req);
/**
* 获取质量-检查工单分页对象视图
*
* @param qualityInspectionPage 质量-检查工单分页对象
* @return 质量-检查工单分页对象视图
*/
Page<BusQualityInspectionVo> getVoPage(Page<BusQualityInspection> qualityInspectionPage);
/**
* 导出质量-检查工单
*
* @param id 质量-检查工单id
* @param response HttpServletResponse
*/
void exportWordById(Long id, HttpServletResponse response);
}

View File

@ -0,0 +1,461 @@
package org.dromara.quality.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.dromara.quality.constant.QualityConstant;
import org.dromara.quality.domain.BusQualityConstructionLog;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogCreateReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogQueryReq;
import org.dromara.quality.domain.req.qualityconstructionlog.QualityConstructionLogUpdateReq;
import org.dromara.quality.domain.vo.BusQualityConstructionLogVo;
import org.dromara.quality.mapper.BusQualityConstructionLogMapper;
import org.dromara.quality.service.IBusQualityConstructionLogService;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;
/**
* 质量-施工日志Service业务层处理
*
* @author lcj
* @date 2025-04-16
*/
@Service
public class BusQualityConstructionLogServiceImpl extends ServiceImpl<BusQualityConstructionLogMapper, BusQualityConstructionLog>
implements IBusQualityConstructionLogService {
@Resource
private IBusProjectService projectService;
@Resource
private ISysUserService userService;
@Resource
private ISysOssService ossService;
/**
* 查询质量-施工日志
*
* @param id 主键
* @return 质量-施工日志
*/
@Override
public BusQualityConstructionLogVo queryById(Long id) {
BusQualityConstructionLog qualityConstructionLog = this.getById(id);
if (qualityConstructionLog == null) {
throw new ServiceException("施工日志信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(qualityConstructionLog);
}
/**
* 分页查询质量-施工日志列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 质量-施工日志分页列表
*/
@Override
public TableDataInfo<BusQualityConstructionLogVo> queryPageList(QualityConstructionLogQueryReq req, PageQuery pageQuery) {
Page<BusQualityConstructionLog> result = this.page(pageQuery.build(), buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的质量-施工日志列表
*
* @param req 查询条件
* @return 质量-施工日志列表
*/
@Override
public List<BusQualityConstructionLogVo> queryList(QualityConstructionLogQueryReq req) {
LambdaQueryWrapper<BusQualityConstructionLog> lqw = buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 新增质量-施工日志
*
* @param req 质量-施工日志
* @return 新增日志主键
*/
@Override
public Long insertByBo(QualityConstructionLogCreateReq req) {
// 将实体类和 DTO 进行转换
BusQualityConstructionLog qualityConstructionLog = new BusQualityConstructionLog();
BeanUtils.copyProperties(req, qualityConstructionLog);
// 数据校验
validEntityBeforeSave(qualityConstructionLog, true);
// 写入数据库
boolean save = this.save(qualityConstructionLog);
if (!save) {
throw new ServiceException("新增施工日志信息失败,数据库异常", HttpStatus.ERROR);
}
// 返回新写入的数据
return qualityConstructionLog.getId();
}
/**
* 修改质量-施工日志
*
* @param req 质量-施工日志
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(QualityConstructionLogUpdateReq req) {
// 将实体类和 DTO 进行转换
BusQualityConstructionLog qualityConstructionLog = new BusQualityConstructionLog();
BeanUtils.copyProperties(req, qualityConstructionLog);
// 数据校验
validEntityBeforeSave(qualityConstructionLog, false);
// 判断是否存在
BusQualityConstructionLog oldQualityConstructionLog = this.getById(qualityConstructionLog.getId());
if (oldQualityConstructionLog == null) {
throw new ServiceException("修改施工日志信息失败,数据不存在", HttpStatus.NOT_FOUND);
}
// 操作数据库
return this.updateById(qualityConstructionLog);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusQualityConstructionLog entity, Boolean create) {
// TODO 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
if (create) {
if (projectId == null) {
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
}
}
if (projectId != null && projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
}
/**
* 校验并批量删除质量-施工日志信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return this.removeBatchByIds(ids);
}
/**
* 获取质量-施工日志视图对象
*
* @param qualityConstructionLog 质量-施工日志对象
* @return 质量-施工日志视图对象
*/
@Override
public BusQualityConstructionLogVo getVo(BusQualityConstructionLog qualityConstructionLog) {
// 对象转封装类
BusQualityConstructionLogVo qualityConstructionLogVo = new BusQualityConstructionLogVo();
if (qualityConstructionLog == null) {
return qualityConstructionLogVo;
}
BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo);
// 关联项目信息
Long projectId = qualityConstructionLog.getProjectId();
if (projectId != null) {
qualityConstructionLogVo.setProjectName(projectService.getById(projectId).getProjectName());
}
// 关联创建用户信息
Long createBy = qualityConstructionLog.getCreateBy();
if (createBy != null) {
SysUserVo sysUserVo = userService.selectUserById(createBy);
qualityConstructionLogVo.setCreateBy(sysUserVo.getNickName());
}
// 关联附件信息
String file = qualityConstructionLog.getFile();
if (StringUtils.isNotBlank(file)) {
List<Long> ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
qualityConstructionLogVo.setFileList(ossVoList);
}
return qualityConstructionLogVo;
}
/**
* 获取质量-施工日志查询条件封装
*
* @param req 质量-施工日志查询条件
* @return 质量-施工日志查询条件封装
*/
@Override
public LambdaQueryWrapper<BusQualityConstructionLog> buildQueryWrapper(QualityConstructionLogQueryReq req) {
LambdaQueryWrapper<BusQualityConstructionLog> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long projectId = req.getProjectId();
Date happenDate = req.getHappenDate();
// 精准查询
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusQualityConstructionLog::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(happenDate), BusQualityConstructionLog::getHappenDate, happenDate);
return lqw;
}
/**
* 获取质量-施工日志分页对象视图
*
* @param qualityConstructionLogPage 质量-施工日志分页对象
* @return 质量-施工日志分页对象视图
*/
@Override
public Page<BusQualityConstructionLogVo> getVoPage(Page<BusQualityConstructionLog> qualityConstructionLogPage) {
// 获取质量-施工日志列表
List<BusQualityConstructionLog> qualityConstructionLogList = qualityConstructionLogPage.getRecords();
// 添加分页信息
Page<BusQualityConstructionLogVo> qualityConstructionLogVoPage = new Page<>(
qualityConstructionLogPage.getCurrent(),
qualityConstructionLogPage.getSize(),
qualityConstructionLogPage.getTotal());
if (CollUtil.isEmpty(qualityConstructionLogList)) {
return qualityConstructionLogVoPage;
}
// 获取项目名称
List<Long> projectIdList = qualityConstructionLogList.stream().map(BusQualityConstructionLog::getProjectId).distinct().toList();
if (projectIdList.size() != 1) {
throw new ServiceException("仅能查询单个项目下的施工日志", HttpStatus.BAD_REQUEST);
}
BusProject project = projectService.getById(projectIdList.get(0));
if (project == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取创建用户信息
List<Long> createByList = qualityConstructionLogList.stream().map(BusQualityConstructionLog::getCreateBy).distinct().toList();
List<SysUserVo> userVoList = userService.selectUserByIds(createByList, null);
Map<Long, String> userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName));
// 获取附件信息
List<Long> ossIdList = qualityConstructionLogList.stream().map(BusQualityConstructionLog::getFile).filter(StringUtils::isNotBlank)
.flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList();
Map<Long, List<SysOssVo>> ossMap = ossService.listByIds(ossIdList)
.stream().collect(Collectors.groupingBy(SysOssVo::getOssId));
// 对象列表 => 封装对象列表
List<BusQualityConstructionLogVo> qualityConstructionLogVoList = qualityConstructionLogList.stream().map(qualityConstructionLog -> {
BusQualityConstructionLogVo qualityConstructionLogVo = new BusQualityConstructionLogVo();
// 对象转封装类
BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo);
// 项目名称
qualityConstructionLogVo.setProjectName(project.getProjectName());
// 创建用户姓名
Long createBy = qualityConstructionLog.getCreateBy();
String createByName = null;
if (userMap.containsKey(createBy)) {
createByName = userMap.get(createBy);
}
qualityConstructionLogVo.setCreateBy(createByName);
// 附件信息
String file = qualityConstructionLog.getFile();
List<SysOssVo> fileList = new ArrayList<>();
if (StringUtils.isNotBlank(file)) {
List<Long> fileIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList();
for (Long fileId : fileIdList) {
if (ossMap.containsKey(fileId)) {
fileList.add(ossMap.get(fileId).get(0));
}
}
}
qualityConstructionLogVo.setFileList(fileList);
return qualityConstructionLogVo;
}).toList();
qualityConstructionLogVoPage.setRecords(qualityConstructionLogVoList);
return qualityConstructionLogVoPage;
}
/**
* 导出质量-施工日志
*
* @param id 主键
* @param response 响应
*/
@Override
public void exportWordById(Long id, HttpServletResponse response) {
BusQualityConstructionLog qualityConstructionLog = this.getById(id);
if (qualityConstructionLog == null) {
throw new ServiceException("质量-施工日志不存在");
}
Map<String, String> replacementMap = getReplacementMap(qualityConstructionLog);
Path targetDir = Paths.get(QualityConstant.getQualityConstructionLogFileUrl(qualityConstructionLog));
try (FileInputStream fis = new FileInputStream(QualityConstant.QUALITY_CONSTRUCTION_LOG_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
for (XWPFParagraph paragraph : document.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, qualityConstructionLog);
}
// 替换表格中的文本(如果模板中有表格)
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, qualityConstructionLog);
}
}
}
}
// 创建目标目录
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
// 组合目标文件名
String fileName = QualityConstant.getQualityConstructionLogFileName(qualityConstructionLog);
// 保存修改后的文件
try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) {
document.write(fos);
}
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);
zos.flush();
} catch (Exception e) {
throw new OssException("生成ZIP文件失败错误信息: " + e.getMessage());
}
}
/**
* 根据实体获取Word的文本Map
*
* @param qualityConstructionLog 施工日志对象
* @return Map
*/
public Map<String, String> getReplacementMap(BusQualityConstructionLog qualityConstructionLog) {
Map<String, String> replacementMap = new HashMap<>();
String createName = userService.selectUserById(qualityConstructionLog.getCreateBy()).getNickName();
replacementMap.put("${createName}", createName);
Date createTime = qualityConstructionLog.getCreateTime();
replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : "");
String projectName = projectService.getById(qualityConstructionLog.getProjectId()).getProjectName();
replacementMap.put("${projectName}", projectName);
Date happenDate = qualityConstructionLog.getHappenDate();
replacementMap.put("${happenDate}", happenDate != null ? DateUtils.formatDate(happenDate) : "");
replacementMap.put("${productionStatus}", qualityConstructionLog.getProductionStatus());
replacementMap.put("${technologyQuality}", qualityConstructionLog.getTechnologyQuality());
replacementMap.put("${remark}", qualityConstructionLog.getRemark());
replacementMap.put("${file}", qualityConstructionLog.getFile());
return replacementMap;
}
/**
* 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile
* 插入图片或超链接(附件)展示。
*
* @param paragraph 当前段落
* @param replacements 占位符与替换内容的映射
* @param document 当前文档,用于插入图片或创建超链接
*/
public void replaceInParagraph(XWPFParagraph paragraph,
Map<String, String> replacements,
XWPFDocument document,
BusQualityConstructionLog qualityConstructionLog) throws InvalidFormatException, IOException {
// 先拷贝 paragraph 里所有的 run
List<XWPFRun> runs = new ArrayList<>(paragraph.getRuns());
// 在拷贝上遍历,修改原 paragraph增删 run都不会抛 CME
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
// 针对每个占位符进行检查
for (Map.Entry<String, String> entry : replacements.entrySet()) {
String placeholder = entry.getKey();
String value = entry.getValue();
if (text.contains(placeholder)) {
// 针对 file 进行特殊处理
if (placeholder.equals("${file}")) {
// 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行)
if (text.trim().equals(placeholder)) {
// 清空原有文本
run.setText("", 0);
// 根据附件的后缀决定以图片或超链接展示
if (StringUtils.isBlank(value)) {
continue;
}
// 获取附件的ossId
List<Long> ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
String baseFile = QualityConstant.getQualityConstructionLogFileUrl(qualityConstructionLog) + "/file";
for (SysOssVo ossVo : ossVoList) {
String lowerVal = ossVo.getUrl().toLowerCase();
OssClient storage = OssFactory.instance(ossVo.getService());
String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile);
if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) {
try {
DocumentUtils.insertImageDynamic(run, fileDownload, document, 300);
} catch (Exception e) {
throw new ServiceException("插入图片失败");
}
} else {
// —— 非图片:插入超链接 ——
XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl());
link.setText(ossVo.getOriginalName());
link.setColor("0000FF");
link.setUnderline(UnderlinePatterns.SINGLE);
}
}
} else {
// 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符
text = text.replace(placeholder, "[附件]");
run.setText(text, 0);
}
} else {
// 普通文本占位符直接替换
if (StringUtils.isBlank(value)) {
// 如果填入值为空,清空原有文本
run.setText("", 0);
continue;
}
text = text.replace(placeholder, value);
run.setText(text, 0);
}
}
}
}
}
}
}

View File

@ -0,0 +1,524 @@
package org.dromara.quality.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.project.domain.BusConstructionUser;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusConstructionUserService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.quality.constant.QualityConstant;
import org.dromara.quality.domain.BusQualityInspection;
import org.dromara.quality.domain.enums.QualityInspectionStatusEnum;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionCreateReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionQueryReq;
import org.dromara.quality.domain.req.qualityinspection.QualityInspectionUpdateReq;
import org.dromara.quality.domain.vo.BusQualityInspectionVo;
import org.dromara.quality.mapper.BusQualityInspectionMapper;
import org.dromara.quality.service.IBusQualityInspectionService;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;
/**
* 质量-检查工单Service业务层处理
*
* @author lcj
* @date 2025-04-16
*/
@Service
public class BusQualityInspectionServiceImpl extends ServiceImpl<BusQualityInspectionMapper, BusQualityInspection>
implements IBusQualityInspectionService {
@Resource
private IBusProjectService projectService;
@Resource
private ISysUserService userService;
@Resource
private ISysOssService ossService;
@Resource
private IBusConstructionUserService constructionUserService;
@Resource
private ISysDictDataService dictDataService;
/**
* 查询质量-检查工单
*
* @param id 主键
* @return 质量-检查工单
*/
@Override
public BusQualityInspectionVo queryById(Long id) {
BusQualityInspection qualityInspection = this.getById(id);
if (qualityInspection == null) {
throw new ServiceException("检查工单信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(qualityInspection);
}
/**
* 分页查询质量-检查工单列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 质量-检查工单分页列表
*/
@Override
public TableDataInfo<BusQualityInspectionVo> queryPageList(QualityInspectionQueryReq req, PageQuery pageQuery) {
Page<BusQualityInspection> result = this.page(pageQuery.build(), buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的质量-检查工单列表
*
* @param req 查询条件
* @return 质量-检查工单列表
*/
@Override
public List<BusQualityInspectionVo> queryList(QualityInspectionQueryReq req) {
LambdaQueryWrapper<BusQualityInspection> lqw = buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 新增质量-检查工单
*
* @param req 质量-检查工单
* @return 新增检查工单id
*/
@Override
public Long insertByBo(QualityInspectionCreateReq req) {
// 将实体类和 DTO 进行转换
BusQualityInspection qualityInspection = new BusQualityInspection();
BeanUtils.copyProperties(req, qualityInspection);
// 数据校验
validEntityBeforeSave(qualityInspection, true);
// 填充默认值
qualityInspection.setInspectionStatus(QualityInspectionStatusEnum.INFORM.getValue());
// 写入数据库
boolean save = this.save(qualityInspection);
if (!save) {
throw new ServiceException("新增检查工单信息失败,数据库异常", HttpStatus.ERROR);
}
// 返回新写入的数据
return qualityInspection.getId();
}
/**
* 修改质量-检查工单
*
* @param req 质量-检查工单
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(QualityInspectionUpdateReq req) {
// 将实体类和 DTO 进行转换
BusQualityInspection qualityInspection = new BusQualityInspection();
BeanUtils.copyProperties(req, qualityInspection);
// 数据校验
validEntityBeforeSave(qualityInspection, false);
// 判断是否存在
BusQualityInspection oldQualityInspection = this.getById(qualityInspection.getId());
if (oldQualityInspection == null) {
throw new ServiceException("修改检查工单信息失败,数据不存在", HttpStatus.NOT_FOUND);
}
// 操作数据库
return this.updateById(qualityInspection);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusQualityInspection entity, Boolean create) {
// TODO 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
if (create) {
if (projectId == null) {
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
}
}
if (projectId != null && projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
}
/**
* 校验并批量删除质量-检查工单信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return this.removeBatchByIds(ids);
}
/**
* 获取质量-检查工单视图对象
*
* @param qualityInspection 质量-检查工单对象
* @return 质量-检查工单视图对象
*/
@Override
public BusQualityInspectionVo getVo(BusQualityInspection qualityInspection) {
// 对象转封装类
BusQualityInspectionVo qualityInspectionVo = new BusQualityInspectionVo();
if (qualityInspection == null) {
return qualityInspectionVo;
}
BeanUtils.copyProperties(qualityInspection, qualityInspectionVo);
// 关联项目信息
Long projectId = qualityInspection.getProjectId();
if (projectId != null) {
qualityInspectionVo.setProjectName(projectService.getById(projectId).getProjectName());
}
// 关联创建用户信息
Long createBy = qualityInspection.getCreateBy();
if (createBy != null) {
SysUserVo sysUserVo = userService.selectUserById(createBy);
qualityInspectionVo.setCreateBy(sysUserVo.getNickName());
}
// 关联整改人信息
Long corrector = qualityInspection.getCorrector();
if (corrector != null) {
String userName = constructionUserService.getById(corrector).getUserName();
qualityInspectionVo.setCorrectorName(userName);
}
// 关联附件信息
String inspectionFile = qualityInspection.getInspectionFile();
if (StringUtils.isNotBlank(inspectionFile)) {
List<Long> ossIdList = Arrays.stream(inspectionFile.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
qualityInspectionVo.setInspectionFileList(ossVoList);
}
String rectificationFile = qualityInspection.getRectificationFile();
if (StringUtils.isNotBlank(rectificationFile)) {
List<Long> ossIdList = Arrays.stream(rectificationFile.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
qualityInspectionVo.setRectificationFileList(ossVoList);
}
return qualityInspectionVo;
}
/**
* 获取质量-检查工单查询条件封装
*
* @param req 质量-检查工单查询条件
* @return 质量-检查工单查询条件封装
*/
@Override
public LambdaQueryWrapper<BusQualityInspection> buildQueryWrapper(QualityInspectionQueryReq req) {
LambdaQueryWrapper<BusQualityInspection> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long projectId = req.getProjectId();
String inspectionType = req.getInspectionType();
String inspectionStatus = req.getInspectionStatus();
Long teamId = req.getTeamId();
// 精确查询
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusQualityInspection::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(inspectionType), BusQualityInspection::getInspectionType, inspectionType);
lqw.eq(ObjectUtils.isNotEmpty(inspectionStatus), BusQualityInspection::getInspectionStatus, inspectionStatus);
lqw.eq(ObjectUtils.isNotEmpty(teamId), BusQualityInspection::getTeamId, teamId);
return lqw;
}
/**
* 获取质量-检查工单分页对象视图
*
* @param qualityInspectionPage 质量-检查工单分页对象
* @return 质量-检查工单分页对象视图
*/
@Override
public Page<BusQualityInspectionVo> getVoPage(Page<BusQualityInspection> qualityInspectionPage) {
// 获取质量-检查工单列表
List<BusQualityInspection> qualityInspectionList = qualityInspectionPage.getRecords();
// 添加分页信息
Page<BusQualityInspectionVo> qualityInspectionVoPage = new Page<>(
qualityInspectionPage.getCurrent(),
qualityInspectionPage.getSize(),
qualityInspectionPage.getTotal());
if (CollUtil.isEmpty(qualityInspectionList)) {
return qualityInspectionVoPage;
}
// 获取项目名称
List<Long> projectIdList = qualityInspectionList.stream().map(BusQualityInspection::getProjectId).distinct().toList();
if (projectIdList.size() != 1) {
throw new ServiceException("仅能查询单个项目下的施工日志", HttpStatus.BAD_REQUEST);
}
BusProject project = projectService.getById(projectIdList.get(0));
if (project == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取整改人信息
List<Long> correctorList = qualityInspectionList.stream().map(BusQualityInspection::getCorrector).distinct().toList();
Map<Long, String> correctorMap = constructionUserService.listByIds(correctorList)
.stream().collect(Collectors.toMap(BusConstructionUser::getId, BusConstructionUser::getUserName));
// 获取创建用户信息
List<Long> createByList = qualityInspectionList.stream().map(BusQualityInspection::getCreateBy).distinct().toList();
List<SysUserVo> userVoList = userService.selectUserByIds(createByList, null);
Map<Long, String> userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName));
// 获取附件信息
List<Long> ossInspectionFileIdList = qualityInspectionList.stream().map(BusQualityInspection::getInspectionFile).filter(StringUtils::isNotBlank)
.flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList();
List<Long> ossIdList = new ArrayList<>(ossInspectionFileIdList);
List<Long> ossRectificationFileIdList = qualityInspectionList.stream().map(BusQualityInspection::getRectificationFile).filter(StringUtils::isNotBlank)
.flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList();
ossIdList.addAll(ossRectificationFileIdList);
Map<Long, List<SysOssVo>> ossMap = ossService.listByIds(ossIdList)
.stream().collect(Collectors.groupingBy(SysOssVo::getOssId));
// 对象列表 => 封装对象列表
List<BusQualityInspectionVo> qualityInspectionVoList = qualityInspectionList.stream().map(qualityInspection -> {
BusQualityInspectionVo qualityInspectionVo = new BusQualityInspectionVo();
BeanUtils.copyProperties(qualityInspection, qualityInspectionVo);
qualityInspectionVo.setProjectName(project.getProjectName());
// 关联整改人信息
Long corrector = qualityInspection.getCorrector();
String correctorName = null;
if (correctorMap.containsKey(corrector)) {
correctorName = correctorMap.get(corrector);
}
qualityInspectionVo.setCorrectorName(correctorName);
// 关联创建用户信息
Long createBy = qualityInspection.getCreateBy();
String createByName = null;
if (userMap.containsKey(createBy)) {
createByName = userMap.get(createBy);
}
qualityInspectionVo.setCreateBy(createByName);
// 关联附件信息
String inspectionFile = qualityInspection.getInspectionFile();
List<SysOssVo> inspectionFileList = new ArrayList<>();
if (StringUtils.isNotBlank(inspectionFile)) {
List<Long> inspectionFileIdList = Arrays.stream(inspectionFile.split(",")).map(Long::parseLong).toList();
for (Long id : inspectionFileIdList) {
if (ossMap.containsKey(id)) {
inspectionFileList.add(ossMap.get(id).get(0));
}
}
}
qualityInspectionVo.setInspectionFileList(inspectionFileList);
String rectificationFile = qualityInspection.getRectificationFile();
List<SysOssVo> rectificationFileList = new ArrayList<>();
if (StringUtils.isNotBlank(rectificationFile)) {
List<Long> rectificationFileIdList = Arrays.stream(rectificationFile.split(",")).map(Long::parseLong).toList();
for (Long id : rectificationFileIdList) {
if (ossMap.containsKey(id)) {
rectificationFileList.add(ossMap.get(id).get(0));
}
}
}
qualityInspectionVo.setRectificationFileList(rectificationFileList);
return qualityInspectionVo;
}).toList();
qualityInspectionVoPage.setRecords(qualityInspectionVoList);
return qualityInspectionVoPage;
}
/**
* 导出质量-检查工单
*
* @param id 质量-检查工单id
* @param response HttpServletResponse
*/
@Override
public void exportWordById(Long id, HttpServletResponse response) {
BusQualityInspection qualityInspection = this.getById(id);
if (qualityInspection == null) {
throw new ServiceException("质量-检查工单不存在");
}
Map<String, String> replacementMap = getReplacementMap(qualityInspection);
Path targetDir = Paths.get(QualityConstant.getQualityInspectionFileUrl(qualityInspection));
try (FileInputStream fis = new FileInputStream(QualityConstant.QUALITY_INSPECTION_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
for (XWPFParagraph paragraph : document.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, qualityInspection);
}
// 替换表格中的文本(如果模板中有表格)
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, qualityInspection);
}
}
}
}
// 创建目标目录
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
// 组合目标文件名
String fileName = QualityConstant.getQualityInspectionFileName(qualityInspection);
// 保存修改后的文件
try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) {
document.write(fos);
}
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);
zos.flush();
} catch (Exception e) {
throw new OssException("生成ZIP文件失败错误信息: " + e.getMessage());
}
}
/**
* 根据实体获取Word的文本Map
*
* @param qualityInspection 质量-检查工单对象
* @return Map
*/
public Map<String, String> getReplacementMap(BusQualityInspection qualityInspection) {
Map<String, String> replacementMap = new HashMap<>();
String createName = userService.selectUserById(qualityInspection.getCreateBy()).getNickName();
replacementMap.put("${createName}", createName);
Date createTime = qualityInspection.getCreateTime();
replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : "");
String projectName = projectService.getById(qualityInspection.getProjectId()).getProjectName();
replacementMap.put("${projectName}", projectName);
replacementMap.put("${inspectionHeadline}", qualityInspection.getInspectionHeadline());
String correctorName = constructionUserService.getById(qualityInspection.getCorrector()).getUserName();
replacementMap.put("${correctorName}", correctorName);
Date rectificationTime = qualityInspection.getRectificationTime();
replacementMap.put("${rectificationTime}", rectificationTime != null ? DateUtils.formatDateTime(rectificationTime) : "");
String inspectionType = dictDataService.selectDictLabel(QualityConstant.QUALITY_INSPECTION_CHECK_TYPE, qualityInspection.getInspectionType());
replacementMap.put("${inspectionType}", inspectionType);
Date replyPeriodDate = qualityInspection.getReplyPeriodDate();
replacementMap.put("${replyPeriodDate}", replyPeriodDate != null ? DateUtils.formatDate(replyPeriodDate) : "");
replacementMap.put("${inspectionResult}", qualityInspection.getInspectionResult());
replacementMap.put("${inspectionFile}", qualityInspection.getInspectionFile());
String inspectionStatus = dictDataService.selectDictLabel(QualityConstant.QUALITY_INSPECTION_STATUS_TYPE, qualityInspection.getInspectionStatus());
replacementMap.put("${inspectionStatus}", inspectionStatus);
replacementMap.put("${rectificationResult}", qualityInspection.getRectificationResult());
replacementMap.put("${rectificationFile}", qualityInspection.getRectificationFile());
replacementMap.put("${verificationResult}", qualityInspection.getVerificationResult());
return replacementMap;
}
/**
* 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile
* 插入图片或超链接(附件)展示。
*
* @param paragraph 当前段落
* @param replacements 占位符与替换内容的映射
* @param document 当前文档,用于插入图片或创建超链接
*/
public void replaceInParagraph(XWPFParagraph paragraph,
Map<String, String> replacements,
XWPFDocument document,
BusQualityInspection qualityInspection)
throws InvalidFormatException, IOException {
// 先拷贝 paragraph 里所有的 run
List<XWPFRun> runs = new ArrayList<>(paragraph.getRuns());
// 在拷贝上遍历,修改原 paragraph增删 run都不会抛 CME
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
// 针对每个占位符进行检查
for (Map.Entry<String, String> entry : replacements.entrySet()) {
String placeholder = entry.getKey();
String value = entry.getValue();
if (text.contains(placeholder)) {
// 针对 file 进行特殊处理
if (placeholder.equals("${inspectionFile}") || placeholder.equals("${rectificationFile}")) {
// 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行)
if (text.trim().equals(placeholder)) {
// 清空原有文本
run.setText("", 0);
// 根据附件的后缀决定以图片或超链接展示
if (StringUtils.isBlank(value)) {
continue;
}
// 获取附件的ossId
List<Long> ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
String baseFile = QualityConstant.getQualityInspectionFileUrl(qualityInspection) + "/file";
for (SysOssVo ossVo : ossVoList) {
String lowerVal = ossVo.getUrl().toLowerCase();
OssClient storage = OssFactory.instance(ossVo.getService());
String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile);
if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) {
try {
DocumentUtils.insertImageDynamic(run, fileDownload, document, 300);
} catch (Exception e) {
throw new ServiceException("插入图片失败");
}
} else {
// —— 非图片:插入超链接 ——
XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl());
link.setText(ossVo.getOriginalName());
link.setColor("0000FF");
link.setUnderline(UnderlinePatterns.SINGLE);
}
}
} else {
// 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符
text = text.replace(placeholder, "[附件]");
run.setText(text, 0);
}
} else {
// 普通文本占位符直接替换
if (StringUtils.isBlank(value)) {
// 如果填入值为空,清空原有文本
run.setText("", 0);
continue;
}
text = text.replace(placeholder, value);
run.setText(text, 0);
}
}
}
}
}
}
}

View File

@ -0,0 +1,34 @@
package org.dromara.safety.constant;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.safety.domain.BusSafetyInspection;
import java.text.SimpleDateFormat;
/**
* @author lcj
* @date 2025/4/16 23:09
*/
public interface SafetyConstant {
String SAFETY_INSPECTION_TYPE = "safety_inspection_type";
String SAFETY_INSPECTION_CHECK_TYPE = "safety_inspection_check_type";
String SAFETY_INSPECTION_VIOLATION_TYPE = "safety_inspection_violation_type";
String SAFETY_INSPECTION_FILE_URL = "docs/safety/inspection/";
String SAFETY_INSPECTION_TEMPLATE_PATH = "docs/template/安全生产监督检查通知书模版.docx";
static String getSafetyInspectionFileUrl(BusSafetyInspection safetyInspection) {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(safetyInspection.getUpdateTime());
return String.format("%s%s/%s", SAFETY_INSPECTION_FILE_URL, safetyInspection.getId(), timestamp);
}
static String getSafetyInspectionFileName(BusSafetyInspection safetyInspection) {
String createDate = DateUtils.formatDate(safetyInspection.getCreateTime());
return String.format("安全生产监督检查通知书(%s.docx", createDate);
}
}

View File

@ -59,6 +59,17 @@ public class BusSafetyInspectionController extends BaseController {
ExcelUtil.exportExcel(list, "安全巡检工单", BusSafetyInspectionVo.class, response); ExcelUtil.exportExcel(list, "安全巡检工单", BusSafetyInspectionVo.class, response);
} }
/**
* 根据主键导出安全巡检工单
*/
@SaCheckPermission("safety:safetyInspection:export")
@Log(title = "安全巡检工单", businessType = BusinessType.EXPORT)
@PostMapping("/export/word")
public void exportWordById(@NotNull(message = "主键不能为空") Long id,
HttpServletResponse response) {
busSafetyInspectionService.exportWordById(id, response);
}
/** /**
* 获取安全巡检工单详细信息 * 获取安全巡检工单详细信息
* *

View File

@ -4,7 +4,6 @@ import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
/** /**
* @author lcj * @author lcj
@ -16,11 +15,6 @@ public class SafetyInspectionQueryReq implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 8880866939746311233L; private static final long serialVersionUID = 8880866939746311233L;
/**
* 主键ID
*/
private Long id;
/** /**
* 父id默认为0 * 父id默认为0
*/ */
@ -41,11 +35,6 @@ public class SafetyInspectionQueryReq implements Serializable {
*/ */
private String violationType; private String violationType;
/**
* 巡检结果
*/
private String inspectionResult;
/** /**
* 整改班组id * 整改班组id
*/ */
@ -56,59 +45,14 @@ public class SafetyInspectionQueryReq implements Serializable {
*/ */
private Long correctorId; private Long correctorId;
/**
* 是否回复1回复 2不回复
*/
private String isReply;
/**
* 回复日期
*/
private String replyDate;
/** /**
* 工单状态1通知 2整改 3复查 * 工单状态1通知 2整改 3复查
*/ */
private String status; private String status;
/**
* 问题隐患
*/
private String hiddenDanger;
/**
* 整改措施
*/
private String measure;
/**
* 复查情况
*/
private String review;
/** /**
* 复查状态1通过 2未通过 * 复查状态1通过 2未通过
*/ */
private String reviewType; private String reviewType;
/**
* 检查时间
*/
private Date checkTime;
/**
* 整改时间
*/
private Date rectificationTime;
/**
* 复查时间
*/
private Date reviewTime;
/**
* 备注
*/
private String remark;
} }

View File

@ -3,6 +3,7 @@ package org.dromara.safety.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.safety.domain.BusSafetyInspection; import org.dromara.safety.domain.BusSafetyInspection;
@ -96,4 +97,12 @@ public interface IBusSafetyInspectionService extends IService<BusSafetyInspectio
*/ */
Page<BusSafetyInspectionVo> getVoPage(Page<BusSafetyInspection> safetyInspectionPage); Page<BusSafetyInspectionVo> getVoPage(Page<BusSafetyInspection> safetyInspectionPage);
/**
* 根据id导出word
*
* @param id 主键
* @param response 响应
*/
void exportWordById(Long id, HttpServletResponse response);
} }

View File

@ -6,17 +6,25 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.project.domain.BusConstructionUser; import org.dromara.project.domain.BusConstructionUser;
import org.dromara.project.domain.BusProjectTeam; import org.dromara.project.domain.BusProjectTeam;
import org.dromara.project.service.IBusConstructionUserService; import org.dromara.project.service.IBusConstructionUserService;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusProjectTeamService; import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.safety.constant.SafetyConstant;
import org.dromara.safety.domain.BusSafetyInspection; import org.dromara.safety.domain.BusSafetyInspection;
import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionCreateReq; import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionCreateReq;
import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionQueryReq; import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionQueryReq;
@ -24,15 +32,26 @@ import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionUpdateReq;
import org.dromara.safety.domain.vo.BusSafetyInspectionVo; import org.dromara.safety.domain.vo.BusSafetyInspectionVo;
import org.dromara.safety.mapper.BusSafetyInspectionMapper; import org.dromara.safety.mapper.BusSafetyInspectionMapper;
import org.dromara.safety.service.IBusSafetyInspectionService; import org.dromara.safety.service.IBusSafetyInspectionService;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService; import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Collection; import java.io.FileInputStream;
import java.util.Date; import java.io.FileOutputStream;
import java.util.List; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.zip.ZipOutputStream;
/** /**
* 安全巡检工单Service业务层处理 * 安全巡检工单Service业务层处理
@ -56,6 +75,15 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
@Resource @Resource
private ISysUserService userService; private ISysUserService userService;
@Resource
private ISysDictDataService dictDataService;
@Resource
private ISysOssService ossService;
@Resource
private ResourceLoader resourceLoader;
/** /**
* 查询安全巡检工单 * 查询安全巡检工单
* *
@ -231,7 +259,7 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
if (createBy != null) { if (createBy != null) {
SysUserVo createUser = userService.selectUserById(createBy); SysUserVo createUser = userService.selectUserById(createBy);
safetyInspectionVo.setCreatorId(createUser.getUserId()); safetyInspectionVo.setCreatorId(createUser.getUserId());
safetyInspectionVo.setCreatorName(createUser.getUserName()); safetyInspectionVo.setCreatorName(createUser.getNickName());
} }
return safetyInspectionVo; return safetyInspectionVo;
} }
@ -248,46 +276,23 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
if (req == null) { if (req == null) {
return lqw; return lqw;
} }
Long id = req.getId();
Long pid = req.getPid(); Long pid = req.getPid();
Long projectId = req.getProjectId(); Long projectId = req.getProjectId();
String checkType = req.getCheckType(); String checkType = req.getCheckType();
String violationType = req.getViolationType(); String violationType = req.getViolationType();
String inspectionResult = req.getInspectionResult();
Long teamId = req.getTeamId(); Long teamId = req.getTeamId();
Long correctorId = req.getCorrectorId(); Long correctorId = req.getCorrectorId();
String isReply = req.getIsReply();
String replyDate = req.getReplyDate();
String status = req.getStatus(); String status = req.getStatus();
String hiddenDanger = req.getHiddenDanger();
String measure = req.getMeasure();
String review = req.getReview();
String reviewType = req.getReviewType(); String reviewType = req.getReviewType();
Date checkTime = req.getCheckTime();
Date rectificationTime = req.getRectificationTime();
Date reviewTime = req.getReviewTime();
String remark = req.getRemark();
// 模糊查询
lqw.like(StringUtils.isNotBlank(inspectionResult), BusSafetyInspection::getInspectionResult, inspectionResult);
lqw.like(StringUtils.isNotBlank(hiddenDanger), BusSafetyInspection::getHiddenDanger, hiddenDanger);
lqw.like(StringUtils.isNotBlank(measure), BusSafetyInspection::getMeasure, measure);
lqw.like(StringUtils.isNotBlank(review), BusSafetyInspection::getReview, review);
lqw.like(StringUtils.isNotBlank(remark), BusSafetyInspection::getRemark, remark);
// 精准查询 // 精准查询
lqw.eq(ObjectUtils.isNotEmpty(id), BusSafetyInspection::getId, id);
lqw.eq(ObjectUtils.isNotEmpty(pid), BusSafetyInspection::getPid, pid); lqw.eq(ObjectUtils.isNotEmpty(pid), BusSafetyInspection::getPid, pid);
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusSafetyInspection::getProjectId, projectId); lqw.eq(ObjectUtils.isNotEmpty(projectId), BusSafetyInspection::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(checkType), BusSafetyInspection::getCheckType, checkType); lqw.eq(ObjectUtils.isNotEmpty(checkType), BusSafetyInspection::getCheckType, checkType);
lqw.eq(ObjectUtils.isNotEmpty(violationType), BusSafetyInspection::getViolationType, violationType); lqw.eq(ObjectUtils.isNotEmpty(violationType), BusSafetyInspection::getViolationType, violationType);
lqw.eq(ObjectUtils.isNotEmpty(teamId), BusSafetyInspection::getTeamId, teamId); lqw.eq(ObjectUtils.isNotEmpty(teamId), BusSafetyInspection::getTeamId, teamId);
lqw.eq(ObjectUtils.isNotEmpty(correctorId), BusSafetyInspection::getCorrectorId, correctorId); lqw.eq(ObjectUtils.isNotEmpty(correctorId), BusSafetyInspection::getCorrectorId, correctorId);
lqw.eq(ObjectUtils.isNotEmpty(isReply), BusSafetyInspection::getIsReply, isReply);
lqw.eq(ObjectUtils.isNotEmpty(replyDate), BusSafetyInspection::getReplyDate, replyDate);
lqw.eq(ObjectUtils.isNotEmpty(status), BusSafetyInspection::getStatus, status); lqw.eq(ObjectUtils.isNotEmpty(status), BusSafetyInspection::getStatus, status);
lqw.eq(ObjectUtils.isNotEmpty(reviewType), BusSafetyInspection::getReviewType, reviewType); lqw.eq(ObjectUtils.isNotEmpty(reviewType), BusSafetyInspection::getReviewType, reviewType);
lqw.eq(ObjectUtils.isNotEmpty(checkTime), BusSafetyInspection::getCheckTime, checkTime);
lqw.eq(ObjectUtils.isNotEmpty(rectificationTime), BusSafetyInspection::getRectificationTime, rectificationTime);
lqw.eq(ObjectUtils.isNotEmpty(reviewTime), BusSafetyInspection::getReviewTime, reviewTime);
return lqw; return lqw;
} }
@ -314,4 +319,170 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
safetyInspectionVoPage.setRecords(safetyInspectionVoList); safetyInspectionVoPage.setRecords(safetyInspectionVoList);
return safetyInspectionVoPage; return safetyInspectionVoPage;
} }
/**
* 根据id导出word
*
* @param id 主键
* @param response 响应
*/
@Override
public void exportWordById(Long id, HttpServletResponse response) {
BusSafetyInspection safetyInspection = this.getById(id);
if (safetyInspection == null) {
throw new ServiceException("安全巡检工单不存在");
}
Map<String, String> replacementMap = getReplacementMap(safetyInspection);
Path targetDir = Paths.get(SafetyConstant.getSafetyInspectionFileUrl(safetyInspection));
try (FileInputStream fis = new FileInputStream(SafetyConstant.SAFETY_INSPECTION_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
for (XWPFParagraph paragraph : document.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, safetyInspection);
}
// 替换表格中的文本(如果模板中有表格)
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
replaceInParagraph(paragraph, replacementMap, document, safetyInspection);
}
}
}
}
// 创建目标目录
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
// 组合目标文件名
String fileName = SafetyConstant.getSafetyInspectionFileName(safetyInspection);
// 保存修改后的文件
try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) {
document.write(fos);
}
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);
zos.flush();
} catch (Exception e) {
throw new OssException("生成ZIP文件失败错误信息: " + e.getMessage());
}
}
/**
* 根据实体获取Word的文本Map
*
* @param safetyInspection 安全巡检工单对象
* @return Map
*/
public Map<String, String> getReplacementMap(BusSafetyInspection safetyInspection) {
Map<String, String> replacementMap = new HashMap<>();
String createBy = userService.selectUserById(safetyInspection.getCreateBy()).getNickName();
replacementMap.put("${createBy}", createBy);
Date createTime = safetyInspection.getCreateTime();
replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : "");
String projectName = projectService.getById(safetyInspection.getProjectId()).getProjectName();
replacementMap.put("${projectName}", projectName);
String checkType = dictDataService.selectDictLabel(SafetyConstant.SAFETY_INSPECTION_CHECK_TYPE, safetyInspection.getCheckType());
replacementMap.put("${checkType}", checkType);
String violationType = dictDataService.selectDictLabel(SafetyConstant.SAFETY_INSPECTION_VIOLATION_TYPE, safetyInspection.getViolationType());
replacementMap.put("${violationType}", violationType);
Date checkTime = safetyInspection.getCheckTime();
replacementMap.put("${checkTime}", checkTime != null ? DateUtils.formatDateTime(checkTime) : "");
String correctorName = constructionUserService.getById(safetyInspection.getCorrectorId()).getUserName();
replacementMap.put("${correctorName}", correctorName);
replacementMap.put("${replyDate}", safetyInspection.getReplyDate());
replacementMap.put("${hiddenDanger}", safetyInspection.getHiddenDanger());
replacementMap.put("${checkFile}", safetyInspection.getCheckFile());
String status = dictDataService.selectDictLabel(SafetyConstant.SAFETY_INSPECTION_TYPE, safetyInspection.getStatus());
replacementMap.put("${status}", status);
String teamName = projectTeamService.getById(safetyInspection.getTeamId()).getTeamName();
replacementMap.put("${teamName}", teamName);
Date rectificationTime = safetyInspection.getRectificationTime();
replacementMap.put("${rectificationTime}", rectificationTime != null ? DateUtils.formatDateTime(rectificationTime) : "");
replacementMap.put("${measure}", safetyInspection.getMeasure());
replacementMap.put("${rectificationFile}", safetyInspection.getRectificationFile());
Date reviewTime = safetyInspection.getReviewTime();
replacementMap.put("${reviewTime}", reviewTime != null ? DateUtils.formatDateTime(reviewTime) : "");
replacementMap.put("${review}", safetyInspection.getReview());
return replacementMap;
}
/**
* 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile
* 插入图片或超链接(附件)展示。
*
* @param paragraph 当前段落
* @param replacements 占位符与替换内容的映射
* @param document 当前文档,用于插入图片或创建超链接
*/
public void replaceInParagraph(XWPFParagraph paragraph, Map<String, String> replacements, XWPFDocument document, BusSafetyInspection safetyInspection) throws InvalidFormatException, IOException {
// 先拷贝 paragraph 里所有的 run
List<XWPFRun> runs = new ArrayList<>(paragraph.getRuns());
// 在拷贝上遍历,修改原 paragraph增删 run都不会抛 CME
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
// 针对每个占位符进行检查
for (Map.Entry<String, String> entry : replacements.entrySet()) {
String placeholder = entry.getKey();
String value = entry.getValue();
if (text.contains(placeholder)) {
// 针对 checkFile 和 rectificationFile 进行特殊处理
if (placeholder.equals("${checkFile}") || placeholder.equals("${rectificationFile}")) {
// 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行)
if (text.trim().equals(placeholder)) {
// 清空原有文本
run.setText("", 0);
// 根据附件的后缀决定以图片或超链接展示
if (StringUtils.isBlank(value)) {
continue;
}
// 获取附件的ossId
List<Long> ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
String baseFile = SafetyConstant.getSafetyInspectionFileUrl(safetyInspection) + "/file";
for (SysOssVo ossVo : ossVoList) {
String lowerVal = ossVo.getUrl().toLowerCase();
OssClient storage = OssFactory.instance(ossVo.getService());
String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile);
if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) {
try {
DocumentUtils.insertImageDynamic(run, fileDownload, document, 300);
} catch (Exception e) {
throw new ServiceException("插入图片失败");
}
} else {
// —— 非图片:插入超链接 ——
XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl());
link.setText(ossVo.getOriginalName());
link.setColor("0000FF");
link.setUnderline(UnderlinePatterns.SINGLE);
}
}
} else {
// 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符
text = text.replace(placeholder, "[附件]");
run.setText(text, 0);
}
} else {
// 普通文本占位符直接替换
if (StringUtils.isBlank(value)) {
// 如果填入值为空,清空原有文本
run.setText("", 0);
continue;
}
text = text.replace(placeholder, value);
run.setText(text, 0);
}
}
}
}
}
}
} }

View File

@ -181,7 +181,7 @@ public class BusSafetyLogServiceImpl extends ServiceImpl<BusSafetyLogMapper, Bus
Long createBy = safetyLog.getCreateBy(); Long createBy = safetyLog.getCreateBy();
if (createBy != null) { if (createBy != null) {
SysUserVo sysUserVo = userMapper.selectVoById(createBy); SysUserVo sysUserVo = userMapper.selectVoById(createBy);
safetyLogVo.setCreator(IdAndNameVO.build(sysUserVo.getUserId(), sysUserVo.getUserName())); safetyLogVo.setCreator(IdAndNameVO.build(sysUserVo.getUserId(), sysUserVo.getNickName()));
} }
return safetyLogVo; return safetyLogVo;
} }

View File

@ -0,0 +1,100 @@
package org.dromara.utils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author lcj
* @date 2025/4/17 14:53
*/
public class DocumentUtils {
/**
* 在给定的 run 里插入图片,并按原始大小(或缩放后大小)设置宽高。
*
* @param run 要插入图片的 XWPFRun
* @param imagePath 本地图片路径或 URL这里示例用本地文件
* @param document 当前文档对象
* @param maxWidthPx 最大允许宽度(像素),如果原图更宽就按比例缩放;设置为 <=0 则不缩放
*/
public static void insertImageDynamic(XWPFRun run,
String imagePath,
XWPFDocument document,
int maxWidthPx) throws Exception {
// 1. 先把图片读到 byte[]
byte[] imgBytes = Files.readAllBytes(Paths.get(imagePath));
// 2. 用 ImageIO 读出宽高(像素)
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imgBytes));
int widthPx = img.getWidth();
int heightPx = img.getHeight();
// 3. 如果指定了最大宽度,而且原图更宽,则按比例缩放
if (maxWidthPx > 0 && widthPx > maxWidthPx) {
double ratio = (double) maxWidthPx / widthPx;
widthPx = maxWidthPx;
heightPx = (int) (heightPx * ratio);
}
// 4. 把像素转换成 EMU
int widthEmu = Units.pixelToEMU(widthPx);
int heightEmu = Units.pixelToEMU(heightPx);
// 5. 插入图片
String lower = imagePath.toLowerCase();
int format = lower.endsWith(".png") ? XWPFDocument.PICTURE_TYPE_PNG
: lower.endsWith(".gif") ? XWPFDocument.PICTURE_TYPE_GIF
: lower.endsWith(".jpeg") ? XWPFDocument.PICTURE_TYPE_JPEG
: lower.endsWith(".jpg") ? XWPFDocument.PICTURE_TYPE_JPEG
: XWPFDocument.PICTURE_TYPE_PNG; // 默认当 PNG
try (InputStream picIn = new ByteArrayInputStream(imgBytes)) {
run.addPicture(picIn, format, imagePath, widthEmu, heightEmu);
}
}
/**
* 递归将 sourceDir 中的所有文件和子目录,按照相对于 rootDir 的路径写入 ZipOutputStream。
*
* @param rootDir 源目录的根,用来计算相对路径
* @param sourceDir 当前递归到的目录
* @param zos ZIP 输出流
*/
public static void zipDirectory(Path rootDir, Path sourceDir, ZipOutputStream zos) throws IOException {
// 遍历当前目录下的所有文件和文件夹
try (DirectoryStream<Path> stream = Files.newDirectoryStream(sourceDir)) {
for (Path entry : stream) {
if (Files.isDirectory(entry)) {
// 如果是目录,递归
zipDirectory(rootDir, entry, zos);
} else {
// 如果是文件,创建一个 ZipEntry路径以 '/' 分隔
Path relativePath = rootDir.relativize(entry);
String zipEntryName = relativePath.toString().replace(File.separatorChar, '/');
ZipEntry zipEntry = new ZipEntry(zipEntryName);
zos.putNextEntry(zipEntry);
// 把文件内容写入 ZIP
try (InputStream is = Files.newInputStream(entry)) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) != -1) {
zos.write(buffer, 0, len);
}
}
zos.closeEntry();
}
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.quality.mapper.BusQualityConstructionLogMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.quality.mapper.BusQualityInspectionMapper">
</mapper>

View File

@ -690,3 +690,55 @@ CREATE TABLE `bus_questions_category`
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '题库类别' COLLATE = utf8mb4_unicode_ci; ) comment = '题库类别' COLLATE = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_quality_inspection`;
CREATE TABLE `bus_quality_inspection`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint null comment '项目id',
`inspection_type` char(1) null comment '巡检类型',
`inspection_headline` varchar(64) null comment '巡检标题',
`inspection_result` varchar(300) null comment '巡检结果',
`inspection_status` char(1) null comment '工单状态1通知 2整改 3验证',
`inspection_file` varchar(1024) null comment '巡检附件',
`team_id` bigint null comment '班组id',
`corrector` varchar(128) null comment '整改人(班组长)',
`is_reply` char(1) null comment '是否回复1回复 2不回复',
`reply_period_date` date null comment '回复期限日期',
`rectification_result` varchar(300) null comment '整改反馈',
`rectification_time` datetime null comment '整改时间',
`rectification_file` varchar(1024) null comment '整改附件',
`verification_result` varchar(300) null comment '验证结果',
`verification_type` char(1) null comment '验证状态1通过 2未通过',
`verification_time` datetime null comment '验证时间',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `project_id` (`project_id` ASC) USING BTREE,
INDEX `team_id` (`team_id` ASC) USING BTREE
) comment = '质量-检查工单' COLLATE = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_quality_construction_log`;
CREATE TABLE `bus_quality_construction_log`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint null comment '项目id',
`happen_date` date null comment '发生日期',
`production_status` varchar(300) null comment '生产情况',
`technology_quality` varchar(300) null comment '技术质量安全工作',
`file` varchar(1024) null comment '附件',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '质量-施工日志' COLLATE = utf8mb4_unicode_ci;