diff --git a/pom.xml b/pom.xml index 235580c..dcc3e62 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 1.0.0 4.4.7 3.5.5 - 8.5.4 + 7.1.4 diff --git a/src/main/java/com/zg/common/utils/MinioUtil.java b/src/main/java/com/zg/common/utils/MinioUtil.java index 352e9d7..2e1046d 100644 --- a/src/main/java/com/zg/common/utils/MinioUtil.java +++ b/src/main/java/com/zg/common/utils/MinioUtil.java @@ -1,13 +1,16 @@ package com.zg.common.utils; -import io.minio.*; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import io.minio.MakeBucketArgs; +import io.minio.BucketExistsArgs; +import io.minio.errors.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.PostConstruct; import java.io.InputStream; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.UUID; @Component @@ -23,38 +26,54 @@ public class MinioUtil { private String secretKey; @Value("${minio.bucketName}") - private String bucketName; + private String defaultBucket; - /** - * 上传文件到 MinIO,自动根据日期生成路径 - * 如:2025/07/10/uuid-xxx.jpg - */ - public String uploadFile(MultipartFile file) throws Exception { - MinioClient client = MinioClient.builder() + private MinioClient minioClient; + + @PostConstruct + public void init() { + minioClient = MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); + } - // 检查桶是否存在,不存在则创建 - boolean found = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); - if (!found) { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + /** + * 上传文件到指定 bucket + * @param file 文件 + * @param bucketName bucket 名称 + * @return 返回访问URL + */ + public String upload(MultipartFile file, String bucketName) throws Exception { + String originalName = file.getOriginalFilename(); + String ext = originalName != null && originalName.contains(".") + ? originalName.substring(originalName.lastIndexOf(".")) + : ""; + String objectName = UUID.randomUUID().toString().replace("-", "") + ext; + + InputStream in = file.getInputStream(); + + // 自动创建 bucket(如果不存在) + boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + if (!exists) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); } - String originalFilename = file.getOriginalFilename(); - String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); - String objectName = datePath + "/" + UUID.randomUUID().toString() + "-" + originalFilename; + // 上传文件 + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .stream(in, file.getSize(), -1) + .contentType(file.getContentType()) + .build()); - try (InputStream inputStream = file.getInputStream()) { - client.putObject(PutObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .stream(inputStream, file.getSize(), -1) - .contentType(file.getContentType()) - .build()); - } - - // 返回完整可访问 URL(前端可直接使用) return endpoint + "/" + bucketName + "/" + objectName; } + + /** + * 上传到默认 bucket + */ + public String upload(MultipartFile file) throws Exception { + return upload(file, defaultBucket); + } } diff --git a/src/main/java/com/zg/project/wisdom/controller/AuditSignatureController.java b/src/main/java/com/zg/project/wisdom/controller/AuditSignatureController.java new file mode 100644 index 0000000..47b57a2 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/controller/AuditSignatureController.java @@ -0,0 +1,156 @@ +package com.zg.project.wisdom.controller; + +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.zg.common.exception.ServiceException; +import com.zg.common.utils.MinioUtil; +import com.zg.common.utils.SecurityUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import com.zg.framework.aspectj.lang.annotation.Log; +import com.zg.framework.aspectj.lang.enums.BusinessType; +import com.zg.project.wisdom.domain.AuditSignature; +import com.zg.project.wisdom.service.IAuditSignatureService; +import com.zg.framework.web.controller.BaseController; +import com.zg.framework.web.domain.AjaxResult; +import com.zg.common.utils.poi.ExcelUtil; +import com.zg.framework.web.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +/** + * 审批记录Controller + * + * @author zg + * @date 2025-07-11 + */ +@RestController +@RequestMapping("/wisdom/signature") +public class AuditSignatureController extends BaseController +{ + @Autowired + private IAuditSignatureService auditSignatureService; + + @Autowired + private MinioUtil minioUtil; + + /** + * 上传签字图片到 MinIO + */ + @PostMapping("/upload") + public AjaxResult uploadSignatures(@RequestParam("files") MultipartFile[] files) { + if (files == null || files.length == 0) { + return AjaxResult.error("上传文件不能为空"); + } + + List urls = new ArrayList<>(); + for (MultipartFile file : files) { + if (file != null && !file.isEmpty()) { + try { + String url = minioUtil.upload(file, "signature/"); + urls.add(url); + } catch (Exception e) { + return AjaxResult.error("上传失败: " + e.getMessage()); + } + } + } + + return AjaxResult.success("上传成功").put("urls", urls); + } + + /** + * 查询审批记录列表 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:list')") + @GetMapping("/list") + public TableDataInfo list(AuditSignature auditSignature) + { + startPage(); + List list = auditSignatureService.selectAuditSignatureList(auditSignature); + return getDataTable(list); + } + + /** + * 导出审批记录列表 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:export')") + @Log(title = "审批记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, AuditSignature auditSignature) + { + List list = auditSignatureService.selectAuditSignatureList(auditSignature); + ExcelUtil util = new ExcelUtil(AuditSignature.class); + util.exportExcel(response, list, "审批记录数据"); + } + + /** + * 获取审批记录详细信息 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(auditSignatureService.selectAuditSignatureById(id)); + } + + /** + * 新增审批记录 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:add')") + @Log(title = "审批记录", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody AuditSignature auditSignature) + { + return toAjax(auditSignatureService.insertAuditSignature(auditSignature)); + } + + /** + * 修改审批记录 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:edit')") + @Log(title = "审批记录", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody AuditSignature auditSignature) + { + return toAjax(auditSignatureService.updateAuditSignature(auditSignature)); + } + + /** + * 删除审批记录 + */ + @PreAuthorize("@ss.hasPermi('wisdom:signature:remove')") + @Log(title = "审批记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(auditSignatureService.deleteAuditSignatureByIds(ids)); + } + + /** + * 待审核列表 + * @return + */ + @GetMapping("/pending") + public AjaxResult getPending() { + String userId = SecurityUtils.getUserId().toString(); + List list = auditSignatureService.selectPendingByUser(userId); + return AjaxResult.success(list); + } + + /** + * 审核操作(通过 / 驳回) + */ + @PostMapping("/audit") + public AjaxResult audit(@RequestBody AuditSignature audit) { + try { + auditSignatureService.audit(audit); + return AjaxResult.success("审核成功"); + } catch (ServiceException e) { + return AjaxResult.error("审核失败:" + e.getMessage()); + } catch (Exception e) { + return AjaxResult.error("系统异常,请联系管理员"); + } + } +} diff --git a/src/main/java/com/zg/project/wisdom/controller/RkInfoController.java b/src/main/java/com/zg/project/wisdom/controller/RkInfoController.java index 5b172e9..ffd1c03 100644 --- a/src/main/java/com/zg/project/wisdom/controller/RkInfoController.java +++ b/src/main/java/com/zg/project/wisdom/controller/RkInfoController.java @@ -7,19 +7,10 @@ import javax.servlet.http.HttpServletResponse; import com.zg.project.wisdom.domain.dto.PcRkInfoBatchDTO; import com.zg.project.wisdom.domain.dto.RefundRequestDTO; -import com.zg.project.wisdom.domain.dto.RkInfoBatchDTO; import com.zg.project.wisdom.domain.dto.StockOutDTO; -import com.zg.project.wisdom.service.IGysJhService; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import com.zg.framework.aspectj.lang.annotation.Log; import com.zg.framework.aspectj.lang.enums.BusinessType; import com.zg.project.wisdom.domain.RkInfo; @@ -42,6 +33,7 @@ public class RkInfoController extends BaseController @Autowired private IRkInfoService rkInfoService; + /** * 查询库存单据主列表 */ @@ -84,7 +76,8 @@ public class RkInfoController extends BaseController @PreAuthorize("@ss.hasPermi('wisdom:stock:add')") @Log(title = "库存单据主", businessType = BusinessType.INSERT) public AjaxResult batchAdd(@RequestBody PcRkInfoBatchDTO dto) { - return toAjax(rkInfoService.batchInsert(dto)); + rkInfoService.batchInsert(dto); + return AjaxResult.success("提交成功"); } /** @@ -166,4 +159,6 @@ public class RkInfoController extends BaseController public AjaxResult refundMaterial(@RequestBody RefundRequestDTO dto) { return toAjax(rkInfoService.refundMaterial(dto)); } + + } diff --git a/src/main/java/com/zg/project/wisdom/domain/AuditSignature.java b/src/main/java/com/zg/project/wisdom/domain/AuditSignature.java new file mode 100644 index 0000000..202ab73 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/domain/AuditSignature.java @@ -0,0 +1,238 @@ +package com.zg.project.wisdom.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.zg.framework.aspectj.lang.annotation.Excel; +import com.zg.framework.web.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.Date; + +/** + * 签字记录对象 audit_signature + */ +public class AuditSignature extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** 主键ID */ + private Long id; + + /** 单据编号 */ + @Excel(name = "单据编号") + private String billNo; + + /** 单据类型(0入库 1出库) */ + @Excel(name = "单据类型") + private String billType; + + /** 签字人ID */ + @Excel(name = "签字人ID") + private String signerId; + + /** 审批人ID */ + @Excel(name = "审批人ID") + private String approverId; + + /** 审批人签字图片URL */ + @Excel(name = "审批人签字图片URL") + private String approverSignUrl; + + /** 签字人角色(0发起人 1审批人 2拍照人) */ + @Excel(name = "签字人角色") + private String signerRole; + + /** 签名图片URL */ + @Excel(name = "签名图片URL") + private String signUrl; + + /** 签字时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "签字时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date signTime; + + /** 库位码 */ + @Excel(name = "库位码") + private String pcode; + + /** 托盘码 */ + @Excel(name = "托盘码") + private String trayCode; + + /** 审核结果(0通过 1驳回) */ + @Excel(name = "审核结果") + private String auditResult; + + /** 是否当前有效签字(1是 0否) */ + @Excel(name = "当前有效") + private String isCurrent; + + /** 图片类型(0签字 1现场图) */ + @Excel(name = "图片类型") + private String imageType; + + /** 备注 */ + @Excel(name = "备注") + private String remark; + + /** 逻辑删除(0正常 1删除) */ + private String isDelete; + + // ===== Getter & Setter ===== + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getBillNo() { + return billNo; + } + + public void setBillNo(String billNo) { + this.billNo = billNo; + } + + public String getBillType() { + return billType; + } + + public void setBillType(String billType) { + this.billType = billType; + } + + public String getSignerId() { + return signerId; + } + + public void setSignerId(String signerId) { + this.signerId = signerId; + } + + public String getApproverId() { + return approverId; + } + + public void setApproverId(String approverId) { + this.approverId = approverId; + } + + public String getApproverSignUrl() { + return approverSignUrl; + } + + public void setApproverSignUrl(String approverSignUrl) { + this.approverSignUrl = approverSignUrl; + } + + public String getSignerRole() { + return signerRole; + } + + public void setSignerRole(String signerRole) { + this.signerRole = signerRole; + } + + public String getSignUrl() { + return signUrl; + } + + public void setSignUrl(String signUrl) { + this.signUrl = signUrl; + } + + public Date getSignTime() { + return signTime; + } + + public void setSignTime(Date signTime) { + this.signTime = signTime; + } + + public String getPcode() { + return pcode; + } + + public void setPcode(String pcode) { + this.pcode = pcode; + } + + public String getTrayCode() { + return trayCode; + } + + public void setTrayCode(String trayCode) { + this.trayCode = trayCode; + } + + public String getAuditResult() { + return auditResult; + } + + public void setAuditResult(String auditResult) { + this.auditResult = auditResult; + } + + public String getIsCurrent() { + return isCurrent; + } + + public void setIsCurrent(String isCurrent) { + this.isCurrent = isCurrent; + } + + public String getImageType() { + return imageType; + } + + public void setImageType(String imageType) { + this.imageType = imageType; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getIsDelete() { + return isDelete; + } + + public void setIsDelete(String isDelete) { + this.isDelete = isDelete; + } + + // ===== toString ===== + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("billNo", getBillNo()) + .append("billType", getBillType()) + .append("signerId", getSignerId()) + .append("approverId", getApproverId()) + .append("approverSignUrl", getApproverSignUrl()) + .append("signerRole", getSignerRole()) + .append("signUrl", getSignUrl()) + .append("signTime", getSignTime()) + .append("pcode", getPcode()) + .append("trayCode", getTrayCode()) + .append("auditResult", getAuditResult()) + .append("isCurrent", getIsCurrent()) + .append("imageType", getImageType()) + .append("remark", getRemark()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("isDelete", getIsDelete()) + .toString(); + } +} diff --git a/src/main/java/com/zg/project/wisdom/domain/RkBill.java b/src/main/java/com/zg/project/wisdom/domain/RkBill.java index 20028c3..83cf74b 100644 --- a/src/main/java/com/zg/project/wisdom/domain/RkBill.java +++ b/src/main/java/com/zg/project/wisdom/domain/RkBill.java @@ -57,6 +57,7 @@ public class RkBill extends BaseEntity // @Excel(name = "理货员") private String lihuoY; + /** 出库类型 */ private String ckType; @@ -155,6 +156,7 @@ public class RkBill extends BaseEntity this.lihuoY = lihuoY; } + public String getCkType() { return ckType; } diff --git a/src/main/java/com/zg/project/wisdom/domain/dto/AuditSignatureDTO.java b/src/main/java/com/zg/project/wisdom/domain/dto/AuditSignatureDTO.java new file mode 100644 index 0000000..9a16354 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/domain/dto/AuditSignatureDTO.java @@ -0,0 +1,13 @@ +package com.zg.project.wisdom.domain.dto; + +public class AuditSignatureDTO { + private String billNo; + private String billType; // 0-入库,1-出库 + private String signerName; + private String signerRole; // 0-起始人,1-审核人,2-拍照人 + private String signUrl; // 签字图片URL + private String pcode; + private String trayCode; + private String auditResult; // 0-通过,1-驳回 + private String remark; +} \ No newline at end of file diff --git a/src/main/java/com/zg/project/wisdom/domain/dto/PcRkInfoBatchDTO.java b/src/main/java/com/zg/project/wisdom/domain/dto/PcRkInfoBatchDTO.java index 74b680c..2133a2d 100644 --- a/src/main/java/com/zg/project/wisdom/domain/dto/PcRkInfoBatchDTO.java +++ b/src/main/java/com/zg/project/wisdom/domain/dto/PcRkInfoBatchDTO.java @@ -1,12 +1,21 @@ package com.zg.project.wisdom.domain.dto; +import lombok.Data; + import java.util.List; /** * PC端 - 入库请求 DTO */ +@Data public class PcRkInfoBatchDTO { + /** 供应计划主键ID */ + private Long gysJhId; + + /** 审核人用户ID */ + private String approverId; + /** 入库类型 */ private String rkType; @@ -22,43 +31,10 @@ public class PcRkInfoBatchDTO { /** 入库记录列表(每条为完整入库项) */ private List rkList; - public String getRkType() { - return rkType; - } + /** 发起人签字图片 URL(单张) */ + private String signatureUrl; - public void setRkType(String rkType) { - this.rkType = rkType; - } - - public String getWlType() { - return wlType; - } - - public void setWlType(String wlType) { - this.wlType = wlType; - } - - public String getLihuoY() { - return lihuoY; - } - - public void setLihuoY(String lihuoY) { - this.lihuoY = lihuoY; - } - - public String getCangku() { - return cangku; - } - - public void setCangku(String cangku) { - this.cangku = cangku; - } - - public List getRkList() { - return rkList; - } - - public void setRkList(List rkList) { - this.rkList = rkList; - } + /** 现场照片 URL 列表(多张) */ + private List photoUrls; } + diff --git a/src/main/java/com/zg/project/wisdom/domain/dto/RkInfoBatchDTO.java b/src/main/java/com/zg/project/wisdom/domain/dto/RkInfoBatchDTO.java index a86114e..1abd9cd 100644 --- a/src/main/java/com/zg/project/wisdom/domain/dto/RkInfoBatchDTO.java +++ b/src/main/java/com/zg/project/wisdom/domain/dto/RkInfoBatchDTO.java @@ -1,9 +1,14 @@ package com.zg.project.wisdom.domain.dto; -import java.util.List; +import lombok.Data; +import java.util.List; +@Data public class RkInfoBatchDTO { + /** 审核人用户ID */ + private String approverId; + /** 入库类型 */ private String rkType; @@ -19,43 +24,9 @@ public class RkInfoBatchDTO { /** 入库物料列表 */ private List rkList; - public String getRkType() { - return rkType; - } + /** 发起人签字图片 URL(单张) */ + private String signatureUrl; - public void setRkType(String rkType) { - this.rkType = rkType; - } - - public String getWlType() { - return wlType; - } - - public void setWlType(String wlType) { - this.wlType = wlType; - } - - public String getLihuoY() { - return lihuoY; - } - - public void setLihuoY(String lihuoY) { - this.lihuoY = lihuoY; - } - - public String getCangku() { - return cangku; - } - - public void setCangku(String cangku) { - this.cangku = cangku; - } - - public List getRkList() { - return rkList; - } - - public void setRkList(List rkList) { - this.rkList = rkList; - } + /** 现场照片 URL 列表(多张) */ + private List photoUrls; } diff --git a/src/main/java/com/zg/project/wisdom/domain/dto/StockOutDTO.java b/src/main/java/com/zg/project/wisdom/domain/dto/StockOutDTO.java index ec39641..7bd5829 100644 --- a/src/main/java/com/zg/project/wisdom/domain/dto/StockOutDTO.java +++ b/src/main/java/com/zg/project/wisdom/domain/dto/StockOutDTO.java @@ -39,4 +39,14 @@ public class StockOutDTO { /** 出库列表 */ private List ckList; + + /** 审核签字图片(发起人签字) */ + private String signatureUrl; + + /** 审核照片列表(可多张) */ + private List photoUrls; + + /** 审批人ID(用于记录签字流转) */ + private String approverId; + } diff --git a/src/main/java/com/zg/project/wisdom/domain/vo/RkSubmitResultVO.java b/src/main/java/com/zg/project/wisdom/domain/vo/RkSubmitResultVO.java new file mode 100644 index 0000000..e9dfa29 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/domain/vo/RkSubmitResultVO.java @@ -0,0 +1,25 @@ +package com.zg.project.wisdom.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 入库提交返回 VO + * 返回入库单据号、是否需要审核、及托盘信息 + */ +@Data +public class RkSubmitResultVO { + + /** 单据号 */ + private String billNo; + + /** 是否需要审核流程 */ + private boolean needAudit; + + /** 所有库位码 */ + private List pcodeList; + + /** 所有托盘码 */ + private List trayCodeList; +} diff --git a/src/main/java/com/zg/project/wisdom/mapper/AuditSignatureMapper.java b/src/main/java/com/zg/project/wisdom/mapper/AuditSignatureMapper.java new file mode 100644 index 0000000..bd6d9ea --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/mapper/AuditSignatureMapper.java @@ -0,0 +1,89 @@ +package com.zg.project.wisdom.mapper; + +import java.util.List; +import com.zg.project.wisdom.domain.AuditSignature; + +/** + * 审批记录Mapper接口 + * + * @author zg + * @date 2025-07-11 + */ +public interface AuditSignatureMapper +{ + /** + * 查询审批记录 + * + * @param id 审批记录主键 + * @return 审批记录 + */ + public AuditSignature selectAuditSignatureById(Long id); + + /** + * 查询审批记录列表 + * + * @param auditSignature 审批记录 + * @return 审批记录集合 + */ + public List selectAuditSignatureList(AuditSignature auditSignature); + + /** + * 新增审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + public int insertAuditSignature(AuditSignature auditSignature); + + /** + * 修改审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + public int updateAuditSignature(AuditSignature auditSignature); + + /** + * 删除审批记录 + * + * @param id 审批记录主键 + * @return 结果 + */ + public int deleteAuditSignatureById(Long id); + + /** + * 批量删除审批记录 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteAuditSignatureByIds(Long[] ids); + + /** + * 查询待审批列表 + * @param userId + * @return + */ + List selectPendingByUser(String userId); + + /** + * 是否存在提交记录(第一次申请还是驳回后再次申请) + * @param + * @return + */ + boolean existsCurrentSigner(String billNo, String number); + + /** + * 修改当前申请数据的可用状态 + * @param + * @return + */ + void updateIsCurrentToZero(String billNo, String number); + + /** + * 新增审核记录 + * @param + * @return + */ + void batchInsert(List recordList); +} diff --git a/src/main/java/com/zg/project/wisdom/mapper/RkInfoMapper.java b/src/main/java/com/zg/project/wisdom/mapper/RkInfoMapper.java index 7c007d3..acccc2d 100644 --- a/src/main/java/com/zg/project/wisdom/mapper/RkInfoMapper.java +++ b/src/main/java/com/zg/project/wisdom/mapper/RkInfoMapper.java @@ -1,6 +1,7 @@ package com.zg.project.wisdom.mapper; import java.util.List; +import java.util.Map; import com.zg.project.Inventory.domain.vo.PcdeCntVO; import com.zg.project.Inventory.domain.vo.RkInfoMatchVO; @@ -170,4 +171,9 @@ public interface RkInfoMapper * @return */ int insertRkInfo(RkInfo newEntry); + + /** + * 修改入库单据状态 + */ + int updateStatusByBillNo(RkInfo rkInfo); } diff --git a/src/main/java/com/zg/project/wisdom/service/IAuditSignatureService.java b/src/main/java/com/zg/project/wisdom/service/IAuditSignatureService.java new file mode 100644 index 0000000..48be783 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/service/IAuditSignatureService.java @@ -0,0 +1,74 @@ +package com.zg.project.wisdom.service; + +import java.util.List; +import com.zg.project.wisdom.domain.AuditSignature; + +/** + * 审批记录Service接口 + * + * @author zg + * @date 2025-07-11 + */ +public interface IAuditSignatureService +{ + /** + * 查询审批记录 + * + * @param id 审批记录主键 + * @return 审批记录 + */ + public AuditSignature selectAuditSignatureById(Long id); + + /** + * 查询审批记录列表 + * + * @param auditSignature 审批记录 + * @return 审批记录集合 + */ + public List selectAuditSignatureList(AuditSignature auditSignature); + + /** + * 新增审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + public int insertAuditSignature(AuditSignature auditSignature); + + /** + * 修改审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + public int updateAuditSignature(AuditSignature auditSignature); + + /** + * 批量删除审批记录 + * + * @param ids 需要删除的审批记录主键集合 + * @return 结果 + */ + public int deleteAuditSignatureByIds(Long[] ids); + + /** + * 删除审批记录信息 + * + * @param id 审批记录主键 + * @return 结果 + */ + public int deleteAuditSignatureById(Long id); + + /** + * 查询待审核的申请 + * @param userId + * @return + */ + List selectPendingByUser(String userId); + + /** + * 审批申请 + * @param audit + */ + void audit(AuditSignature audit); +} diff --git a/src/main/java/com/zg/project/wisdom/service/IRkInfoService.java b/src/main/java/com/zg/project/wisdom/service/IRkInfoService.java index 3191c10..99ae5f0 100644 --- a/src/main/java/com/zg/project/wisdom/service/IRkInfoService.java +++ b/src/main/java/com/zg/project/wisdom/service/IRkInfoService.java @@ -10,6 +10,7 @@ import com.zg.project.wisdom.domain.dto.PcRkInfoBatchDTO; import com.zg.project.wisdom.domain.dto.RefundRequestDTO; import com.zg.project.wisdom.domain.dto.RkInfoBatchDTO; import com.zg.project.wisdom.domain.dto.StockOutDTO; +import com.zg.project.wisdom.domain.vo.RkSubmitResultVO; /** * 库存单据主Service接口 @@ -61,11 +62,11 @@ public interface IRkInfoService public int deleteRkInfoById(Long id); /** - * PC新增入库单据 - * @param dto - * @return + * 批量新增入库记录 + * @param dto 入库数据 + * @return RkSubmitResultVO 提交结果 */ - int batchInsert(PcRkInfoBatchDTO dto); + void batchInsert(PcRkInfoBatchDTO dto); /** * APP新增入库单据 diff --git a/src/main/java/com/zg/project/wisdom/service/impl/AuditSignatureServiceImpl.java b/src/main/java/com/zg/project/wisdom/service/impl/AuditSignatureServiceImpl.java new file mode 100644 index 0000000..ae0ff02 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/service/impl/AuditSignatureServiceImpl.java @@ -0,0 +1,156 @@ +package com.zg.project.wisdom.service.impl; + +import java.util.List; + +import com.zg.common.exception.ServiceException; +import com.zg.common.utils.DateUtils; +import com.zg.common.utils.SecurityUtils; +import com.zg.project.wisdom.domain.RkInfo; +import com.zg.project.wisdom.mapper.RkInfoMapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.zg.project.wisdom.mapper.AuditSignatureMapper; +import com.zg.project.wisdom.domain.AuditSignature; +import com.zg.project.wisdom.service.IAuditSignatureService; +import org.springframework.transaction.annotation.Transactional; + +/** + * 审批记录Service业务层处理 + * + * @author zg + * @date 2025-07-11 + */ +@Service +public class AuditSignatureServiceImpl implements IAuditSignatureService +{ + @Autowired + private AuditSignatureMapper auditSignatureMapper; + + @Autowired + private RkInfoMapper rkInfoMapper; + + /** + * 查询审批记录 + * + * @param id 审批记录主键 + * @return 审批记录 + */ + @Override + public AuditSignature selectAuditSignatureById(Long id) + { + return auditSignatureMapper.selectAuditSignatureById(id); + } + + /** + * 查询审批记录列表 + * + * @param auditSignature 审批记录 + * @return 审批记录 + */ + @Override + public List selectAuditSignatureList(AuditSignature auditSignature) + { + return auditSignatureMapper.selectAuditSignatureList(auditSignature); + } + + /** + * 新增审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + @Override + public int insertAuditSignature(AuditSignature auditSignature) + { + auditSignature.setCreateTime(DateUtils.getNowDate()); + return auditSignatureMapper.insertAuditSignature(auditSignature); + } + + /** + * 修改审批记录 + * + * @param auditSignature 审批记录 + * @return 结果 + */ + @Override + public int updateAuditSignature(AuditSignature auditSignature) + { + auditSignature.setUpdateTime(DateUtils.getNowDate()); + return auditSignatureMapper.updateAuditSignature(auditSignature); + } + + /** + * 批量删除审批记录 + * + * @param ids 需要删除的审批记录主键 + * @return 结果 + */ + @Override + public int deleteAuditSignatureByIds(Long[] ids) + { + return auditSignatureMapper.deleteAuditSignatureByIds(ids); + } + + /** + * 删除审批记录信息 + * + * @param id 审批记录主键 + * @return 结果 + */ + @Override + public int deleteAuditSignatureById(Long id) + { + return auditSignatureMapper.deleteAuditSignatureById(id); + } + + /** + * 查询待审核的申请 + * @param userId + * @return + */ + @Override + public List selectPendingByUser(String userId) { + return auditSignatureMapper.selectPendingByUser(userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void audit(AuditSignature audit) { + String userId = SecurityUtils.getUserId().toString(); + + // 1. 校验记录是否存在 + AuditSignature db = auditSignatureMapper.selectAuditSignatureById(audit.getId()); + if (db == null || "1".equals(db.getIsDelete())) { + throw new ServiceException("审核记录不存在"); + } + + // 2. 校验是否已审核 + if (db.getAuditResult() != null) { + throw new ServiceException("该记录已审核,不能重复操作"); + } + + // 3. 更新审核状态 + audit.setAuditResult(audit.getAuditResult()); // 必须为 "0"(通过)或 "1"(驳回) + audit.setApproverId(userId); // 设置审核人 + audit.setRemark(audit.getRemark()); // 设置审核意见 + audit.setUpdateBy(userId); + audit.setUpdateTime(DateUtils.getNowDate()); + + auditSignatureMapper.updateAuditSignature(audit); + + RkInfo rk = new RkInfo(); + rk.setBillNo(audit.getBillNo()); + rk.setUpdateBy(userId); + rk.setUpdateTime(DateUtils.getNowDate()); + if ("0".equals(audit.getAuditResult())) { + // 审核通过:rk_info.status = 1(已入库) + rk.setStatus("1"); + } else if ("1".equals(audit.getAuditResult())) { + // 审核驳回:rk_info.status = 2(驳回) + rk.setStatus("2"); + } + rkInfoMapper.updateStatusByBillNo(rk); + } + +} diff --git a/src/main/java/com/zg/project/wisdom/service/impl/RkInfoServiceImpl.java b/src/main/java/com/zg/project/wisdom/service/impl/RkInfoServiceImpl.java index 101332f..da80c00 100644 --- a/src/main/java/com/zg/project/wisdom/service/impl/RkInfoServiceImpl.java +++ b/src/main/java/com/zg/project/wisdom/service/impl/RkInfoServiceImpl.java @@ -2,28 +2,25 @@ package com.zg.project.wisdom.service.impl; import java.text.SimpleDateFormat; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; import com.zg.common.exception.ServiceException; import com.zg.common.utils.DateUtils; -import com.zg.common.utils.PageUtils; import com.zg.common.utils.SecurityUtils; -import com.zg.framework.web.page.TableDataInfo; import com.zg.project.Inventory.AutoInventory.mapper.InventoryMatchScanMapper; import com.zg.project.Inventory.Task.mapper.InventoryTaskMapper; import com.zg.project.Inventory.domain.dto.QueryDTO; import com.zg.project.Inventory.domain.entity.InventoryMatchScan; import com.zg.project.Inventory.domain.vo.ChartDataVO; import com.zg.project.Inventory.domain.vo.PcdeCntVO; -import com.zg.project.wisdom.domain.RkBill; +import com.zg.project.system.service.ISysConfigService; +import com.zg.project.wisdom.domain.AuditSignature; import com.zg.project.wisdom.domain.dto.*; +import com.zg.project.wisdom.mapper.AuditSignatureMapper; import com.zg.project.wisdom.mapper.GysJhMapper; -import com.zg.project.wisdom.mapper.RkBillMapper; import com.zg.project.wisdom.utils.BillNoUtil; import com.zg.project.wisdom.utils.CodeConvertUtil; import org.springframework.beans.BeanUtils; @@ -51,7 +48,7 @@ public class RkInfoServiceImpl implements IRkInfoService private GysJhMapper gysJhMapper; @Autowired - private RkBillMapper rkBillMapper; + private AuditSignatureMapper auditSignatureMapper; @Autowired private InventoryMatchScanMapper matchScanMapper; @@ -59,6 +56,9 @@ public class RkInfoServiceImpl implements IRkInfoService @Autowired private InventoryTaskMapper taskMapper; + @Autowired + private ISysConfigService configService; + /** * 查询库存单据主 * @@ -139,86 +139,97 @@ public class RkInfoServiceImpl implements IRkInfoService * @return */ @Override - public int batchInsert(PcRkInfoBatchDTO dto) { - List saveList = new ArrayList<>(); - String username = SecurityUtils.getUsername(); + @Transactional(rollbackFor = Exception.class) + public void batchInsert(PcRkInfoBatchDTO dto) { + String billNo = BillNoUtil.generateTodayBillNo("RK"); + List list = dto.getRkList(); + List rkInfos = new ArrayList<>(); + + boolean needAudit = "1".equals(configService.selectConfigByKey("stock.audit.enabled")); + String userId = SecurityUtils.getUserId().toString(); Date now = DateUtils.getNowDate(); - if (dto.getRkList() == null || dto.getRkList().isEmpty()) { - throw new ServiceException("rkList 入库明细列表不能为空"); + for (PcRkInfoItemDTO item : list) { + RkInfo rk = new RkInfo(); + BeanUtils.copyProperties(item, rk); + rk.setBillNo(billNo); + rk.setRkType(dto.getRkType()); + rk.setWlType(dto.getWlType()); + rk.setLihuoY(dto.getLihuoY()); + rk.setCangku(dto.getCangku()); + rk.setCreateBy(userId); + rk.setCreateTime(now); + rk.setIsDelete("0"); + if (needAudit) { + rk.setStatus("0"); // 入库待审核 + rk.setIsChuku("2"); // 待入库(审核中) + } else { + rk.setStatus("1"); // 审核通过 + rk.setIsChuku("0"); // 已入库 + } + rkInfos.add(rk); } -// // ✅ 生成统一单据号 - String billNo = BillNoUtil.generateTodayBillNo("RK"); -// -// // ✅ 插入单据主表 -// RkBill bill = new RkBill(); -// bill.setBillNo(billNo); -// bill.setRkType(dto.getRkType()); -// bill.setWlType(dto.getWlType()); -// bill.setCangku(dto.getCangku()); -// bill.setRkTime(now); -// bill.setLihuoY(dto.getLihuoY()); -// bill.setIsChuku("0"); -// bill.setIsDelete("0"); -// bill.setCreateBy(username); -// bill.setCreateTime(now); -// rkBillMapper.insertRkBill(bill); + rkInfoMapper.batchInsertRkInfo(rkInfos); - // ✅ 构建明细列表 - for (PcRkInfoItemDTO item : dto.getRkList()) { - RkInfo entity = new RkInfo(); + // ====== 写入签字记录(支持重新提交)====== + if (needAudit) { + List records = new ArrayList<>(); - entity.setRkType(dto.getRkType()); - entity.setWlType(dto.getWlType()); - entity.setCangku(dto.getCangku()); - entity.setLihuoY(dto.getLihuoY()); - - entity.setBillNo(billNo); - - entity.setXj(item.getXj()); - entity.setXmNo(item.getXmNo()); - entity.setXmMs(item.getXmMs()); - entity.setSapNo(item.getSapNo()); - entity.setJhQty(item.getJhQty()); - entity.setHtQty(item.getHtQty()); - entity.setJhAmt(item.getJhAmt()); - entity.setHtDj(item.getHtDj()); - entity.setDw(item.getDw()); - entity.setWlNo(item.getWlNo()); - entity.setWlMs(item.getWlMs()); - entity.setGysNo(item.getGysNo()); - entity.setGysMc(item.getGysMc()); - - entity.setRealQty(item.getRealQty()); - entity.setPcode(item.getPcode()); - if (item.getPcode() != null) { - entity.setPcodeId(CodeConvertUtil.stringToHex(item.getPcode())); + // === 检查是否已有发起人签字记录 === + boolean hasOldSign = auditSignatureMapper.existsCurrentSigner(billNo, "0"); // signerRole = 0 表示发起人 + if (hasOldSign) { + // 将旧记录设为历史 + auditSignatureMapper.updateIsCurrentToZero(billNo, "0"); } - entity.setTrayCode(item.getTrayCode()); - entity.setEntityId(item.getEntityId()); - entity.setRemark(item.getRemark()); - // 系统字段 - entity.setIsChuku("0"); - entity.setIsBorrowed("0"); - entity.setIsDelete("0"); - entity.setRkTime(now); - entity.setCreateBy(username); - entity.setCreateTime(now); + // === 新的主签字记录(发起人 + 审批人) === + AuditSignature mainSign = new AuditSignature(); + mainSign.setBillNo(billNo); // 单据号 + mainSign.setBillType("0"); // 单据类型(0:入库) + mainSign.setSignerId(userId); // 签字人ID(发起人) + mainSign.setSignerRole("0"); // 角色(0:发起人) + mainSign.setApproverId(dto.getApproverId()); // 审批人ID + mainSign.setSignUrl(dto.getSignatureUrl()); // 发起人签字图片URL + mainSign.setImageType("0"); // 图片类型(0:签字) + mainSign.setSignTime(now); // 签字时间 + mainSign.setIsCurrent("1"); // 当前记录 + mainSign.setIsDelete("0"); // 是否删除 + mainSign.setCreateBy(userId); // 创建人 + mainSign.setCreateTime(now); // 创建时间 + records.add(mainSign); - saveList.add(entity); + // === 现场照片(每张一条记录) === + if (dto.getPhotoUrls() != null && !dto.getPhotoUrls().isEmpty()) { + for (String url : dto.getPhotoUrls()) { + if (url == null || url.trim().isEmpty()) continue; - if (item.getGysJhId() != null) { - gysJhMapper.updateStatusById(item.getGysJhId()); + AuditSignature photo = new AuditSignature(); + photo.setBillNo(billNo); + photo.setBillType("0"); + photo.setSignerId(userId); + photo.setSignerRole("2"); // 拍照人 + photo.setImageType("1"); // 现场图片 + photo.setApproverId(dto.getApproverId()); + photo.setSignUrl(url); + photo.setSignTime(now); + photo.setIsCurrent("1"); + photo.setIsDelete("0"); + photo.setCreateBy(userId); + photo.setCreateTime(now); + records.add(photo); + } + } + + if (!records.isEmpty()) { + auditSignatureMapper.batchInsert(records); + } + + // ✅ 更新供应计划状态 + if (dto.getGysJhId() != null) { + gysJhMapper.updateStatusById(dto.getGysJhId()); } } - - if (saveList.isEmpty()) { - throw new ServiceException("未提取到任何可保存的数据"); - } - - return rkInfoMapper.batchInsertRkInfo(saveList); } @@ -228,97 +239,131 @@ public class RkInfoServiceImpl implements IRkInfoService * @return */ @Override + @Transactional(rollbackFor = Exception.class) public int batchInsertApp(RkInfoBatchDTO dto) { List saveList = new ArrayList<>(); - String username = SecurityUtils.getUsername(); + String userId = SecurityUtils.getUserId().toString(); Date now = DateUtils.getNowDate(); if (dto.getRkList() == null || dto.getRkList().isEmpty()) { throw new ServiceException("rkList 入库明细列表不能为空"); } - // ✅ 生成统一的单据号 + boolean needAudit = "1".equals(configService.selectConfigByKey("stock.audit.enabled")); String billNo = BillNoUtil.generateTodayBillNo("CK"); - RkBill bill = new RkBill(); - bill.setBillNo(billNo); - bill.setRkType(dto.getRkType()); - bill.setWlType(dto.getWlType()); - bill.setCangku(dto.getCangku()); - bill.setRkTime(now); - bill.setLihuoY(dto.getLihuoY()); - bill.setIsChuku("0"); - bill.setIsDelete("0"); - bill.setCreateBy(username); - bill.setCreateTime(now); - - rkBillMapper.insertRkBill(bill); - for (RkInfoItemDTO item : dto.getRkList()) { List scanList = item.getScanList(); - if (scanList == null || scanList.isEmpty()) { - continue; - } + if (scanList == null || scanList.isEmpty()) continue; for (RkInfoScanDTO scan : scanList) { - RkInfo entity = new RkInfo(); - - // 批次字段 - entity.setRkType(dto.getRkType()); - entity.setWlType(dto.getWlType()); - entity.setCangku(dto.getCangku()); - entity.setLihuoY(dto.getLihuoY()); - - entity.setBillNo(billNo); - - // 明细字段(RkInfoItemDTO) - entity.setXj(item.getXj()); - entity.setXmMs(item.getXmMs()); - entity.setXmNo(item.getXmNo()); - entity.setSapNo(item.getSapNo()); - entity.setJhQty(item.getJhQty()); - entity.setHtQty(item.getHtQty()); - entity.setJhAmt(item.getJhAmt()); - entity.setHtDj(item.getHtDj()); - entity.setDw(item.getDw()); - entity.setWlNo(item.getWlNo()); - entity.setWlMs(item.getWlMs()); - entity.setGysNo(item.getGysNo()); - entity.setGysMc(item.getGysMc()); - - // 扫码记录(RkInfoScanDTO) - entity.setPcode(scan.getPcode()); - if (scan.getPcode() != null) { - entity.setPcodeId(CodeConvertUtil.stringToHex(scan.getPcode())); + entity.setRkType(dto.getRkType()); // 入库类型 + entity.setWlType(dto.getWlType()); // 物资类型 + entity.setCangku(dto.getCangku()); // 所属仓库ID + entity.setLihuoY(dto.getLihuoY()); // 理货员 + entity.setBillNo(billNo); // 单据号(统一生成) + entity.setXj(item.getXj()); // 县局 + entity.setXmMs(item.getXmMs()); // 项目描述 + entity.setXmNo(item.getXmNo()); // 项目编号 + entity.setSapNo(item.getSapNo()); // SAP订单编号 + entity.setJhQty(item.getJhQty()); // 计划交货数量 + entity.setHtQty(item.getHtQty()); // 合同数量 + entity.setJhAmt(item.getJhAmt()); // 计划交货金额 + entity.setHtDj(item.getHtDj()); // 合同单价 + entity.setDw(item.getDw()); // 计量单位 + entity.setWlNo(item.getWlNo()); // 物料号 + entity.setWlMs(item.getWlMs()); // 物料描述 + entity.setGysNo(item.getGysNo()); // 供应商编号 + entity.setGysMc(item.getGysMc()); // 供应商名称 + entity.setPcode(scan.getPcode()); // 库位码(明细) + entity.setPcodeId(CodeConvertUtil.stringToHex(scan.getPcode())); // 库位码(16进制编码) + entity.setTrayCode(scan.getTrayCode()); // 托盘码 + entity.setRealQty(scan.getRealQty()); // 实际入库数量 + entity.setEntityId(scan.getEntityId()); // 实物ID + entity.setRemark(scan.getRemark()); // 备注 + entity.setIsDelete("0"); // 是否删除(0=正常) + entity.setIsChuku("0"); // 是否已出库(0=否) + if (needAudit) { + entity.setStatus("0"); // 入库待审核 + entity.setIsChuku("3"); // 待入库(审核中) + } else { + entity.setStatus("1"); // 审核通过 + entity.setIsChuku("0"); // 已入库 } - entity.setTrayCode(scan.getTrayCode()); - entity.setRealQty(scan.getRealQty()); - entity.setEntityId(scan.getEntityId()); - entity.setRemark(scan.getRemark()); - - // 系统字段 - entity.setIsDelete("0"); - entity.setIsChuku("0"); - entity.setRkTime(now); - entity.setCreateBy(username); - entity.setCreateTime(now); + entity.setRkTime(now); // 入库时间 + entity.setCreateBy(userId); // 创建人 + entity.setCreateTime(now); // 创建时间 saveList.add(entity); } - // 每个 item 的 供应计划主键ID 更新一次供应计划状态 if (item.getGysJhId() != null) { - gysJhMapper.updateStatusById(item.getGysJhId()); + gysJhMapper.updateStatusById(item.getGysJhId()); // 更新供应计划状态 } - } if (saveList.isEmpty()) { throw new ServiceException("未提取到任何可保存的数据"); } - return rkInfoMapper.batchInsertRkInfo(saveList); + rkInfoMapper.batchInsertRkInfo(saveList); // 批量插入入库数据 + + // ✅ 写入签字记录(支持重新提交) + if (needAudit) { + List recordList = new ArrayList<>(); + + // === 判断是否是重新提交 === + boolean isResubmit = auditSignatureMapper.existsCurrentSigner(billNo, "0"); + if (isResubmit) { + auditSignatureMapper.updateIsCurrentToZero(billNo, "0"); // 将旧签字记录置为历史 + } + + // === 发起人签字记录 === + AuditSignature mainSign = new AuditSignature(); + mainSign.setBillNo(billNo); // 单据号 + mainSign.setBillType("0"); // 单据类型:0=入库 + mainSign.setSignerId(userId); // 签字人ID(当前登录人) + mainSign.setSignerRole("0"); // 签字人角色:0=发起人 + mainSign.setSignUrl(dto.getSignatureUrl()); // 发起人签字图片URL + mainSign.setSignTime(now); // 签字时间 + mainSign.setIsCurrent("1"); // 是否当前记录(1=当前) + mainSign.setImageType("0"); // 图片类型:0=签字图 + mainSign.setApproverId(dto.getApproverId()); // 审批人ID + mainSign.setIsDelete("0"); // 是否删除(0=否) + mainSign.setCreateBy(userId); // 创建人 + mainSign.setCreateTime(now); // 创建时间 + recordList.add(mainSign); + + // === 现场照片记录 === + if (dto.getPhotoUrls() != null) { + for (String photoUrl : dto.getPhotoUrls()) { + if (photoUrl == null || photoUrl.trim().isEmpty()) continue; + + AuditSignature photo = new AuditSignature(); + photo.setBillNo(billNo); // 单据号 + photo.setBillType("0"); // 单据类型:0=入库 + photo.setSignerId(userId); // 拍照人ID(当前登录人) + photo.setSignerRole("2"); // 签字人角色:2=拍照人 + photo.setSignUrl(photoUrl); // 现场图片URL + photo.setImageType("1"); // 图片类型:1=现场图 + photo.setSignTime(now); // 拍照时间 + photo.setApproverId(dto.getApproverId()); // 审批人ID + photo.setIsCurrent("1"); // 是否当前记录 + photo.setIsDelete("0"); // 是否删除 + photo.setCreateBy(userId); // 创建人 + photo.setCreateTime(now); // 创建时间 + + recordList.add(photo); + } + } + + if (!recordList.isEmpty()) { + auditSignatureMapper.batchInsert(recordList); // 批量插入签字记录 + } + } + + return saveList.size(); } @Transactional @@ -373,38 +418,105 @@ public class RkInfoServiceImpl implements IRkInfoService throw new ServiceException("出库数据不能为空"); } - String username = SecurityUtils.getUsername(); + String userId = SecurityUtils.getUserId().toString(); Date now = DateUtils.getNowDate(); - // Step 1: 提前生成出库单据号(如 CK202406100001) + // Step 1: 判断是否需要审核 + boolean needAudit = "1".equals(configService.selectConfigByKey("stock.audit.enabled")); + + // Step 2: 生成出库单据号 String billNo = BillNoUtil.generateTodayBillNo("CK"); - // Step 2: 批量更新 rk_info(出库状态 + 单号 + 单据ID) + // Step 3: 批量更新 rk_info 出库字段 for (StockOutItemDTO item : dto.getCkList()) { RkInfo update = new RkInfo(); - update.setId(item.getId()); - update.setBillNoCk(billNo); - update.setIsChuku("1"); + update.setId(item.getId()); // 主键ID + update.setBillNoCk(billNo); // 出库单号 + update.setCkType(dto.getCkType()); // 出库类型 + update.setTeamCode(dto.getTeamCode()); // 施工队编码 + update.setLyTime(dto.getLyTime()); // 出库时间(领用时间) + update.setCkLihuoY(dto.getCkLihuoY()); // 出库理货员 + update.setCkRemark(item.getCkRemark()); // 出库备注 + update.setXmNoCk(dto.getXmNoCk()); // 项目编号 + update.setXmMsCk(dto.getXmMsCk()); // 项目描述 + update.setUpdateBy(userId); // 修改人 + update.setUpdateTime(now); // 修改时间 + if ("JLCK".equals(dto.getCkType())) { - update.setIsBorrowed("1"); - update.setBorrowTime(dto.getBorrowTime()); - update.setReturnTime(dto.getReturnTime()); + update.setIsBorrowed("1"); // 是否借料 + update.setBorrowTime(dto.getBorrowTime()); // 借用时间 + update.setReturnTime(dto.getReturnTime()); // 归还时间 } - update.setCkType(dto.getCkType()); - update.setLyTime(dto.getLyTime()); - update.setCkLihuoY(dto.getCkLihuoY()); - update.setTeamCode(dto.getTeamCode()); - update.setCkRemark(item.getCkRemark()); - update.setXmNoCk(dto.getXmNoCk()); - update.setXmMsCk(dto.getXmMsCk()); - update.setUpdateBy(username); - update.setUpdateTime(now); + + if (needAudit) { + update.setStatus("3"); // 出库待审核 + update.setIsChuku("0"); // 不可直接出库,等待审批 + } else { + update.setIsChuku("1"); // 审核关闭,直接出库 + update.setStatus("1"); // 设置为审核通过 + } + rkInfoMapper.updateById(update); } + // Step 4: 如果开启审核,写入签字记录 + if (needAudit) { + List recordList = new ArrayList<>(); + + // === 判断是否是重新提交(存在发起人记录) === + boolean hasOldSign = auditSignatureMapper.existsCurrentSigner(billNo, "0"); + + if (hasOldSign) { + auditSignatureMapper.updateIsCurrentToZero(billNo, "0"); // 标记旧记录为历史 + } + + // === 发起人签字记录 === + AuditSignature sign = new AuditSignature(); + sign.setBillNo(billNo); // 单据号(出库单号) + sign.setBillType("1"); // 单据类型:1=出库 + sign.setSignerId(userId); // 签字人ID(发起人) + sign.setSignerRole("0"); // 角色:0=发起人 + sign.setSignUrl(dto.getSignatureUrl()); // 签字图 URL + sign.setSignTime(now); // 签字时间 + sign.setImageType("0"); // 图片类型:0=签字图 + sign.setApproverId(dto.getApproverId()); // 审批人ID + sign.setIsCurrent("1"); // 当前记录 + sign.setIsDelete("0"); // 未删除 + sign.setCreateBy(userId); // 创建人 + sign.setCreateTime(now); // 创建时间 + recordList.add(sign); + + // === 多张现场照片记录 === + if (dto.getPhotoUrls() != null) { + for (String url : dto.getPhotoUrls()) { + if (url == null || url.trim().isEmpty()) continue; + + AuditSignature photo = new AuditSignature(); + photo.setBillNo(billNo); // 单据号 + photo.setBillType("1"); // 出库 + photo.setSignerId(userId); // 拍照人 + photo.setSignerRole("2"); // 角色:2=拍照人 + photo.setSignUrl(url); // 照片URL + photo.setImageType("1"); // 图片类型:1=照片 + photo.setSignTime(now); // 拍照时间 + photo.setApproverId(dto.getApproverId()); // 审批人ID + photo.setIsCurrent("1"); // 当前记录 + photo.setIsDelete("0"); // 未删除 + photo.setCreateBy(userId); // 创建人 + photo.setCreateTime(now); // 创建时间 + recordList.add(photo); + } + } + + if (!recordList.isEmpty()) { + auditSignatureMapper.batchInsert(recordList); // 批量插入签字记录 + } + } + return dto.getCkList().size(); } + @Override public void matchWithStatus(QueryDTO dto) { List pcdeIds = dto.getIds(); diff --git a/src/main/resources/mybatis/wisdom/AuditSignatureMapper.xml b/src/main/resources/mybatis/wisdom/AuditSignatureMapper.xml new file mode 100644 index 0000000..87abcc0 --- /dev/null +++ b/src/main/resources/mybatis/wisdom/AuditSignatureMapper.xml @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, bill_no, bill_type, signer_id, signer_role, sign_url, sign_time, pcode, tray_code, approver_id, approver_sign_url, audit_result, image_type, is_current, remark, create_by, create_time, update_by, update_time, is_delete from audit_signature + + + + + + + + + + + + insert into audit_signature + + bill_no, + bill_type, + signer_id, + signer_role, + sign_url, + sign_time, + pcode, + tray_code, + approver_id, + approver_sign_url, + audit_result, + image_type, + is_current, + remark, + create_by, + create_time, + update_by, + update_time, + is_delete, + + + #{billNo}, + #{billType}, + #{signerId}, + #{signerRole}, + #{signUrl}, + #{signTime}, + #{pcode}, + #{trayCode}, + #{approverId}, + #{approverSignUrl}, + #{auditResult}, + #{imageType}, + #{isCurrent}, + #{remark}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{isDelete}, + + + + + INSERT INTO audit_signature ( + bill_no, + bill_type, + signer_id, + signer_role, + sign_url, + sign_time, + image_type, + approver_id, + is_current, + is_delete, + create_by, + create_time + ) + VALUES + + ( + #{item.billNo}, + #{item.billType}, + #{item.signerId}, + #{item.signerRole}, + #{item.signUrl}, + #{item.signTime}, + #{item.imageType}, + #{item.approverId}, + #{item.isCurrent}, + #{item.isDelete}, + #{item.createBy}, + #{item.createTime} + ) + + + + + update audit_signature + + bill_no = #{billNo}, + bill_type = #{billType}, + signer_id = #{signerId}, + signer_role = #{signerRole}, + sign_url = #{signUrl}, + sign_time = #{signTime}, + pcode = #{pcode}, + tray_code = #{trayCode}, + approver_id = #{approverId}, + approver_sign_url = #{approverSignUrl}, + audit_result = #{auditResult}, + image_type = #{imageType}, + is_current = #{isCurrent}, + remark = #{remark}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + is_delete = #{isDelete}, + + where id = #{id} + + + + UPDATE audit_signature + SET is_current = '0', + update_time = NOW() + WHERE bill_no = #{billNo} + AND signer_role = #{signerRole} + AND is_current = '1' + AND is_delete = '0' + + + + delete from audit_signature where id = #{id} + + + + delete from audit_signature where id in + + #{id} + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/wisdom/RkInfoMapper.xml b/src/main/resources/mybatis/wisdom/RkInfoMapper.xml index 716ff39..1fcf986 100644 --- a/src/main/resources/mybatis/wisdom/RkInfoMapper.xml +++ b/src/main/resources/mybatis/wisdom/RkInfoMapper.xml @@ -93,7 +93,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" jh_qty, ht_qty, jh_amt, ht_dj, dw, borrow_time, return_time, pcode, pcode_id, tray_code, real_qty, entity_id, - remark, is_chuku,is_borrowed, is_delete, create_by, create_time + remark, is_chuku,is_borrowed, + is_delete, create_by, create_time ) VALUES @@ -105,7 +106,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{item.jhQty}, #{item.htQty}, #{item.jhAmt}, #{item.htDj}, #{item.dw}, #{item.borrowTime}, #{item.returnTime}, #{item.pcode}, #{item.pcodeId}, #{item.trayCode}, #{item.realQty}, #{item.entityId}, - #{item.remark}, #{item.isChuku}, #{item.isBorrowed},#{item.isDelete}, #{item.createBy}, #{item.createTime} + #{item.remark}, #{item.isChuku}, #{item.isBorrowed}, + #{item.isDelete}, #{item.createBy}, #{item.createTime} ) @@ -264,9 +266,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT ri.id, ri.rk_type, ri.wl_type, ri.cangku, ri.rk_time, ri.lihuo_y, ri.is_chuku, ri.bill_no, ri.bill_no_ck, - ri.remark, ri.xj, ri.xm_no, ri.xm_ms, ri.wl_no, ri.wl_ms,ri.is_borrowed, + ri.remark, ri.xj, ri.xm_no, ri.xm_ms, ri.wl_no, ri.wl_ms, ri.is_borrowed, ri.gys_no, ri.gys_mc, ri.jh_amt, ri.ht_dj, ri.sap_no, ri.xh, - ri.jh_qty, ri.ht_qty, ri.dw, ri.real_qty,ri.borrow_time, ri.return_time, + ri.jh_qty, ri.ht_qty, ri.dw, ri.real_qty, ri.borrow_time, ri.return_time, ri.pcode, ri.pcode_id, ri.tray_code, ri.entity_id, ri.ck_lihuo_y, ri.ck_type, ri.team_code, ri.ly_time, ri.ck_remark, ri.create_by, ri.create_time, ri.update_by, ri.update_time, ri.is_delete @@ -282,7 +284,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT id, rk_type, wl_type, cangku, rk_time, lihuo_y, is_chuku, bill_no, bill_no_ck, - remark, xj, xm_no, xm_ms, wl_no, wl_ms,is_borrowed, + remark, xj, xm_no, xm_ms, wl_no, wl_ms, is_borrowed, gys_no, gys_mc, jh_amt, ht_dj, sap_no, xh, jh_qty, ht_qty, dw, real_qty, pcode, pcode_id, tray_code, entity_id, @@ -422,4 +424,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHERE id = #{id} + + UPDATE rk_info + SET status = #{status}, + update_by = #{updateBy}, + update_time = #{updateTime} + WHERE bill_no = #{billNo} + AND is_delete = '0' + + \ No newline at end of file