diff --git a/RuoYi-Vue-Plus/docs/template/安全生产监督检查通知书模版.docx b/RuoYi-Vue-Plus/docs/template/安全生产监督检查通知书模版.docx new file mode 100644 index 00000000..d46710a6 Binary files /dev/null and b/RuoYi-Vue-Plus/docs/template/安全生产监督检查通知书模版.docx differ diff --git a/RuoYi-Vue-Plus/docs/template/整改通知单模版.docx b/RuoYi-Vue-Plus/docs/template/整改通知单模版.docx new file mode 100644 index 00000000..194fea9b Binary files /dev/null and b/RuoYi-Vue-Plus/docs/template/整改通知单模版.docx differ diff --git a/RuoYi-Vue-Plus/docs/template/施工日志模版.docx b/RuoYi-Vue-Plus/docs/template/施工日志模版.docx new file mode 100644 index 00000000..ad163504 Binary files /dev/null and b/RuoYi-Vue-Plus/docs/template/施工日志模版.docx differ diff --git a/RuoYi-Vue-Plus/ruoyi-admin/src/main/resources/application.yml b/RuoYi-Vue-Plus/ruoyi-admin/src/main/resources/application.yml index 72e71df1..d3c96139 100644 --- a/RuoYi-Vue-Plus/ruoyi-admin/src/main/resources/application.yml +++ b/RuoYi-Vue-Plus/ruoyi-admin/src/main/resources/application.yml @@ -222,9 +222,11 @@ springdoc: packages-to-scan: org.dromara.machinery - group: 6.安全模块 packages-to-scan: org.dromara.safety - - group: 7.代码生成模块 + - group: 7.质量模块 + packages-to-scan: org.dromara.quality + - group: 8.代码生成模块 packages-to-scan: org.dromara.generator - - group: 8.工作流模块 + - group: 9.工作流模块 packages-to-scan: org.dromara.workflow # 防止XSS攻击 diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java index 8ff11c96..b43b00de 100644 --- a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java +++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java @@ -3,6 +3,7 @@ package org.dromara.common.oss.core; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; 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.StringUtils; import org.dromara.common.core.utils.file.FileUtils; @@ -31,6 +32,7 @@ import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Duration; import java.util.function.Consumer; @@ -235,6 +237,41 @@ public class OssClient { 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 到 输出流 * diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QualityConstant.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QualityConstant.java new file mode 100644 index 00000000..85540e25 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QualityConstant.java @@ -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); + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityConstructionLogController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityConstructionLogController.java new file mode 100644 index 00000000..6917c039 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityConstructionLogController.java @@ -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 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 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 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 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 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 remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busQualityConstructionLogService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityInspectionController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityInspectionController.java new file mode 100644 index 00000000..b7335822 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/BusQualityInspectionController.java @@ -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 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 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 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 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 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 remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busQualityInspectionService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityConstructionLog.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityConstructionLog.java new file mode 100644 index 00000000..a8df87b6 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityConstructionLog.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityInspection.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityInspection.java new file mode 100644 index 00000000..323951c4 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/BusQualityInspection.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QualityInspectionStatusEnum.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QualityInspectionStatusEnum.java new file mode 100644 index 00000000..7058762b --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QualityInspectionStatusEnum.java @@ -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; + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogCreateReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogCreateReq.java new file mode 100644 index 00000000..b66f17be --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogCreateReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogQueryReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogQueryReq.java new file mode 100644 index 00000000..a3c3a8ae --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogQueryReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogUpdateReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogUpdateReq.java new file mode 100644 index 00000000..3f5fe465 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityconstructionlog/QualityConstructionLogUpdateReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionCreateReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionCreateReq.java new file mode 100644 index 00000000..1be78cc4 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionCreateReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionQueryReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionQueryReq.java new file mode 100644 index 00000000..f944336d --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionQueryReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionUpdateReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionUpdateReq.java new file mode 100644 index 00000000..e84ca0d9 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/req/qualityinspection/QualityInspectionUpdateReq.java @@ -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; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityConstructionLogVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityConstructionLogVo.java new file mode 100644 index 00000000..7df12069 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityConstructionLogVo.java @@ -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 fileList; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private String createBy; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityInspectionVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityInspectionVo.java new file mode 100644 index 00000000..f30f6e22 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/BusQualityInspectionVo.java @@ -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 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 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; + + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityConstructionLogMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityConstructionLogMapper.java new file mode 100644 index 00000000..040fa5c2 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityConstructionLogMapper.java @@ -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 { + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityInspectionMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityInspectionMapper.java new file mode 100644 index 00000000..47571d80 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/BusQualityInspectionMapper.java @@ -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 { + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityConstructionLogService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityConstructionLogService.java new file mode 100644 index 00000000..0791c7af --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityConstructionLogService.java @@ -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 { + + /** + * 查询质量-施工日志 + * + * @param id 主键 + * @return 质量-施工日志 + */ + BusQualityConstructionLogVo queryById(Long id); + + /** + * 分页查询质量-施工日志列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-施工日志分页列表 + */ + TableDataInfo queryPageList(QualityConstructionLogQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的质量-施工日志列表 + * + * @param req 查询条件 + * @return 质量-施工日志列表 + */ + List 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 ids, Boolean isValid); + + /** + * 获取质量-施工日志视图对象 + * + * @param qualityConstructionLog 质量-施工日志对象 + * @return 质量-施工日志视图对象 + */ + BusQualityConstructionLogVo getVo(BusQualityConstructionLog qualityConstructionLog); + + /** + * 获取质量-施工日志查询条件封装 + * + * @param req 质量-施工日志查询条件 + * @return 质量-施工日志查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(QualityConstructionLogQueryReq req); + + /** + * 获取质量-施工日志分页对象视图 + * + * @param qualityConstructionLogPage 质量-施工日志分页对象 + * @return 质量-施工日志分页对象视图 + */ + Page getVoPage(Page qualityConstructionLogPage); + + /** + * 导出质量-施工日志 + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityInspectionService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityInspectionService.java new file mode 100644 index 00000000..3a519ed5 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IBusQualityInspectionService.java @@ -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 { + + /** + * 查询质量-检查工单 + * + * @param id 主键 + * @return 质量-检查工单 + */ + BusQualityInspectionVo queryById(Long id); + + /** + * 分页查询质量-检查工单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-检查工单分页列表 + */ + TableDataInfo queryPageList(QualityInspectionQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + List 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 ids, Boolean isValid); + + /** + * 获取质量-检查工单视图对象 + * + * @param qualityInspection 质量-检查工单对象 + * @return 质量-检查工单视图对象 + */ + BusQualityInspectionVo getVo(BusQualityInspection qualityInspection); + + /** + * 获取质量-检查工单查询条件封装 + * + * @param req 质量-检查工单查询条件 + * @return 质量-检查工单查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(QualityInspectionQueryReq req); + + /** + * 获取质量-检查工单分页对象视图 + * + * @param qualityInspectionPage 质量-检查工单分页对象 + * @return 质量-检查工单分页对象视图 + */ + Page getVoPage(Page qualityInspectionPage); + + /** + * 导出质量-检查工单 + * + * @param id 质量-检查工单id + * @param response HttpServletResponse + */ + void exportWordById(Long id, HttpServletResponse response); + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityConstructionLogServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityConstructionLogServiceImpl.java new file mode 100644 index 00000000..d66cb36a --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityConstructionLogServiceImpl.java @@ -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 + 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 queryPageList(QualityConstructionLogQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的质量-施工日志列表 + * + * @param req 查询条件 + * @return 质量-施工日志列表 + */ + @Override + public List queryList(QualityConstructionLogQueryReq req) { + LambdaQueryWrapper 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 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 ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityConstructionLogVo.setFileList(ossVoList); + } + return qualityConstructionLogVo; + } + + /** + * 获取质量-施工日志查询条件封装 + * + * @param req 质量-施工日志查询条件 + * @return 质量-施工日志查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(QualityConstructionLogQueryReq req) { + LambdaQueryWrapper 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 getVoPage(Page qualityConstructionLogPage) { + // 获取质量-施工日志列表 + List qualityConstructionLogList = qualityConstructionLogPage.getRecords(); + // 添加分页信息 + Page qualityConstructionLogVoPage = new Page<>( + qualityConstructionLogPage.getCurrent(), + qualityConstructionLogPage.getSize(), + qualityConstructionLogPage.getTotal()); + if (CollUtil.isEmpty(qualityConstructionLogList)) { + return qualityConstructionLogVoPage; + } + // 获取项目名称 + List 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 createByList = qualityConstructionLogList.stream().map(BusQualityConstructionLog::getCreateBy).distinct().toList(); + List userVoList = userService.selectUserByIds(createByList, null); + Map userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName)); + // 获取附件信息 + List ossIdList = qualityConstructionLogList.stream().map(BusQualityConstructionLog::getFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + Map> ossMap = ossService.listByIds(ossIdList) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 对象列表 => 封装对象列表 + List 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 fileList = new ArrayList<>(); + if (StringUtils.isNotBlank(file)) { + List 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 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 getReplacementMap(BusQualityConstructionLog qualityConstructionLog) { + Map 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 replacements, + XWPFDocument document, + BusQualityConstructionLog qualityConstructionLog) throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry 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 ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List 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); + } + } + } + } + } + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityInspectionServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityInspectionServiceImpl.java new file mode 100644 index 00000000..e563f4d7 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/BusQualityInspectionServiceImpl.java @@ -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 + 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 queryPageList(QualityInspectionQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + @Override + public List queryList(QualityInspectionQueryReq req) { + LambdaQueryWrapper 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 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 ossIdList = Arrays.stream(inspectionFile.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityInspectionVo.setInspectionFileList(ossVoList); + } + String rectificationFile = qualityInspection.getRectificationFile(); + if (StringUtils.isNotBlank(rectificationFile)) { + List ossIdList = Arrays.stream(rectificationFile.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityInspectionVo.setRectificationFileList(ossVoList); + } + return qualityInspectionVo; + } + + /** + * 获取质量-检查工单查询条件封装 + * + * @param req 质量-检查工单查询条件 + * @return 质量-检查工单查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(QualityInspectionQueryReq req) { + LambdaQueryWrapper 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 getVoPage(Page qualityInspectionPage) { + // 获取质量-检查工单列表 + List qualityInspectionList = qualityInspectionPage.getRecords(); + // 添加分页信息 + Page qualityInspectionVoPage = new Page<>( + qualityInspectionPage.getCurrent(), + qualityInspectionPage.getSize(), + qualityInspectionPage.getTotal()); + if (CollUtil.isEmpty(qualityInspectionList)) { + return qualityInspectionVoPage; + } + // 获取项目名称 + List 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 correctorList = qualityInspectionList.stream().map(BusQualityInspection::getCorrector).distinct().toList(); + Map correctorMap = constructionUserService.listByIds(correctorList) + .stream().collect(Collectors.toMap(BusConstructionUser::getId, BusConstructionUser::getUserName)); + // 获取创建用户信息 + List createByList = qualityInspectionList.stream().map(BusQualityInspection::getCreateBy).distinct().toList(); + List userVoList = userService.selectUserByIds(createByList, null); + Map userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName)); + // 获取附件信息 + List ossInspectionFileIdList = qualityInspectionList.stream().map(BusQualityInspection::getInspectionFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + List ossIdList = new ArrayList<>(ossInspectionFileIdList); + List ossRectificationFileIdList = qualityInspectionList.stream().map(BusQualityInspection::getRectificationFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + ossIdList.addAll(ossRectificationFileIdList); + Map> ossMap = ossService.listByIds(ossIdList) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 对象列表 => 封装对象列表 + List 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 inspectionFileList = new ArrayList<>(); + if (StringUtils.isNotBlank(inspectionFile)) { + List 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 rectificationFileList = new ArrayList<>(); + if (StringUtils.isNotBlank(rectificationFile)) { + List 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 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 getReplacementMap(BusQualityInspection qualityInspection) { + Map 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 replacements, + XWPFDocument document, + BusQualityInspection qualityInspection) + throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry 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 ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List 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); + } + } + } + } + } + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/SafetyConstant.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/SafetyConstant.java new file mode 100644 index 00000000..671e2f18 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/SafetyConstant.java @@ -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); + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/BusSafetyInspectionController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/BusSafetyInspectionController.java index 77e2bbf1..a3d866bd 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/BusSafetyInspectionController.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/BusSafetyInspectionController.java @@ -59,6 +59,17 @@ public class BusSafetyInspectionController extends BaseController { 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); + } + /** * 获取安全巡检工单详细信息 * diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/req/safetyinspection/SafetyInspectionQueryReq.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/req/safetyinspection/SafetyInspectionQueryReq.java index 8b33a0d6..c4c60bd2 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/req/safetyinspection/SafetyInspectionQueryReq.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/req/safetyinspection/SafetyInspectionQueryReq.java @@ -4,7 +4,6 @@ import lombok.Data; import java.io.Serial; import java.io.Serializable; -import java.util.Date; /** * @author lcj @@ -16,11 +15,6 @@ public class SafetyInspectionQueryReq implements Serializable { @Serial private static final long serialVersionUID = 8880866939746311233L; - /** - * 主键ID - */ - private Long id; - /** * 父id(默认为0) */ @@ -41,11 +35,6 @@ public class SafetyInspectionQueryReq implements Serializable { */ private String violationType; - /** - * 巡检结果 - */ - private String inspectionResult; - /** * 整改班组id */ @@ -56,59 +45,14 @@ public class SafetyInspectionQueryReq implements Serializable { */ private Long correctorId; - /** - * 是否回复(1回复 2不回复) - */ - private String isReply; - - /** - * 回复日期 - */ - private String replyDate; - /** * 工单状态(1通知 2整改 3复查) */ private String status; - /** - * 问题隐患 - */ - private String hiddenDanger; - - /** - * 整改措施 - */ - private String measure; - - /** - * 复查情况 - */ - private String review; - /** * 复查状态(1通过 2未通过) */ private String reviewType; - /** - * 检查时间 - */ - private Date checkTime; - - /** - * 整改时间 - */ - private Date rectificationTime; - - /** - * 复查时间 - */ - private Date reviewTime; - - /** - * 备注 - */ - private String remark; - } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IBusSafetyInspectionService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IBusSafetyInspectionService.java index 72e0adf1..4f6107f6 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IBusSafetyInspectionService.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IBusSafetyInspectionService.java @@ -3,6 +3,7 @@ package org.dromara.safety.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.safety.domain.BusSafetyInspection; @@ -96,4 +97,12 @@ public interface IBusSafetyInspectionService extends IService getVoPage(Page safetyInspectionPage); + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyInspectionServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyInspectionServiceImpl.java index 732fa510..487a39ea 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyInspectionServiceImpl.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyInspectionServiceImpl.java @@ -6,17 +6,25 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.BusProjectTeam; import org.dromara.project.service.IBusConstructionUserService; import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectTeamService; +import org.dromara.safety.constant.SafetyConstant; import org.dromara.safety.domain.BusSafetyInspection; import org.dromara.safety.domain.req.safetyinspection.SafetyInspectionCreateReq; 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.mapper.BusSafetyInspectionMapper; import org.dromara.safety.service.IBusSafetyInspectionService; +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.core.io.ResourceLoader; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collection; -import java.util.Date; -import java.util.List; +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.zip.ZipOutputStream; /** * 安全巡检工单Service业务层处理 @@ -56,6 +75,15 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl 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 getReplacementMap(BusSafetyInspection safetyInspection) { + Map 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 replacements, XWPFDocument document, BusSafetyInspection safetyInspection) throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry 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 ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List 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); + } + } + } + } + } + } + } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyLogServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyLogServiceImpl.java index 410fabf9..620821b7 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyLogServiceImpl.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/BusSafetyLogServiceImpl.java @@ -181,7 +181,7 @@ public class BusSafetyLogServiceImpl extends ServiceImpl 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 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(); + } + } + } + } + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityConstructionLogMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityConstructionLogMapper.xml new file mode 100644 index 00000000..d2a00884 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityConstructionLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityInspectionMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityInspectionMapper.xml new file mode 100644 index 00000000..3858e218 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/BusQualityInspectionMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/RuoYi-Vue-Plus/script/sql/xinnengyuan.sql b/RuoYi-Vue-Plus/script/sql/xinnengyuan.sql index 0daf84ad..4a7dd444 100644 --- a/RuoYi-Vue-Plus/script/sql/xinnengyuan.sql +++ b/RuoYi-Vue-Plus/script/sql/xinnengyuan.sql @@ -690,3 +690,55 @@ CREATE TABLE `bus_questions_category` PRIMARY KEY (`id`) USING BTREE, INDEX `idx_project_id` (`project_id` ASC) USING BTREE ) 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;