审核模块相关接口开发

This commit is contained in:
2025-07-16 11:03:25 +08:00
parent 7c4b5e71e9
commit 16c1b403ed
23 changed files with 758 additions and 538 deletions

View File

@@ -291,7 +291,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>NewInventory</finalName> <finalName>WisdomManagement</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@@ -1,9 +1,6 @@
package com.zg.common.utils; package com.zg.common.utils;
import io.minio.MinioClient; import io.minio.*;
import io.minio.PutObjectArgs;
import io.minio.MakeBucketArgs;
import io.minio.BucketExistsArgs;
import io.minio.errors.*; import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -13,6 +10,9 @@ import javax.annotation.PostConstruct;
import java.io.InputStream; import java.io.InputStream;
import java.util.UUID; import java.util.UUID;
/**
* MinIO 工具类(支持上传并设置 bucket 公共访问权限)
*/
@Component @Component
public class MinioUtil { public class MinioUtil {
@@ -39,41 +39,72 @@ public class MinioUtil {
} }
/** /**
* 上传文件到指定 bucket * 上传文件到指定 bucket 的指定目录(自动设置公共权限)
* @param file 文件 *
* @param file 上传的文件
* @param bucketName bucket 名称 * @param bucketName bucket 名称
* @return 返回访问URL * @param folder 目录前缀(如 "signature/"
* @return 返回公网可访问的 URL
* @throws Exception 异常
*/ */
public String upload(MultipartFile file, String bucketName) throws Exception { public String upload(MultipartFile file, String bucketName, String folder) throws Exception {
String originalName = file.getOriginalFilename(); String originalName = file.getOriginalFilename();
String ext = originalName != null && originalName.contains(".") String ext = originalName != null && originalName.contains(".")
? originalName.substring(originalName.lastIndexOf(".")) ? originalName.substring(originalName.lastIndexOf("."))
: ""; : "";
String objectName = UUID.randomUUID().toString().replace("-", "") + ext; String objectName = folder + UUID.randomUUID().toString().replace("-", "") + ext;
InputStream in = file.getInputStream(); try (InputStream in = file.getInputStream()) {
// 如果 bucket 不存在,则创建
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
// 自动创建 bucket(如果不存在 // 强制设置 bucket 策略为 public-read幂等
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); String policyJson = "{\n" +
if (!exists) { " \"Version\":\"2012-10-17\",\n" +
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); " \"Statement\":[\n" +
" {\n" +
" \"Effect\":\"Allow\",\n" +
" \"Principal\":{\"AWS\":\"*\"},\n" +
" \"Action\":[\"s3:GetObject\"],\n" +
" \"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]\n" +
" }\n" +
" ]\n" +
"}";
minioClient.setBucketPolicy(
SetBucketPolicyArgs.builder()
.bucket(bucketName)
.config(policyJson)
.build()
);
// 上传文件
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(in, file.getSize(), -1)
.contentType(file.getContentType())
.build());
} }
// 上传文件
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(in, file.getSize(), -1)
.contentType(file.getContentType())
.build());
return endpoint + "/" + bucketName + "/" + objectName; return endpoint + "/" + bucketName + "/" + objectName;
} }
/** /**
* 上传到默认 bucket * 上传文件到默认 bucket 根目录
*/ */
public String upload(MultipartFile file) throws Exception { public String upload(MultipartFile file) throws Exception {
return upload(file, defaultBucket); return upload(file, defaultBucket, "");
} }
/**
* 上传文件到默认 bucket 指定目录
*/
public String upload(MultipartFile file, String folder) throws Exception {
return upload(file, defaultBucket, folder);
}
} }

View File

@@ -116,6 +116,8 @@ public class SecurityConfig
"/captchaImage", "/captchaImage",
"/user/**", "/user/**",
"/query/jh/**", "/query/jh/**",
"/wisdom/signature/**",
"/system/config/**",
"/AutoInventory/**", "/AutoInventory/**",
"/ws/**", "/ws/**",
"/information/device/**", "/information/device/**",

View File

@@ -2,6 +2,10 @@ package com.zg.project.system.controller;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import com.zg.framework.manager.AsyncManager;
import com.zg.framework.manager.factory.AsyncFactory;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -19,6 +23,8 @@ import com.zg.project.system.domain.SysMenu;
import com.zg.project.system.domain.SysUser; import com.zg.project.system.domain.SysUser;
import com.zg.project.system.service.ISysMenuService; import com.zg.project.system.service.ISysMenuService;
import javax.servlet.http.HttpServletRequest;
/** /**
* 登录验证 * 登录验证
* *
@@ -94,4 +100,27 @@ public class SysLoginController
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId); List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus)); return AjaxResult.success(menuService.buildMenus(menus));
} }
/**
* APP登出接口
*
* @param request
* @return
*/
@ApiOperation("APP登出接口")
@PostMapping("/app/logout")
public AjaxResult appLogout(HttpServletRequest request) {
LoginUser loginUser = tokenService.getLoginUser(request);
if (loginUser != null) {
String token = loginUser.getToken();
// 删除 Redis 中的登录用户缓存
tokenService.delLoginUser(token);
// 异步记录登出日志
AsyncManager.me().execute(
AsyncFactory.recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, "APP退出成功"));
}
return AjaxResult.success("APP退出成功");
}
} }

View File

@@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletResponse;
import com.zg.common.exception.ServiceException; import com.zg.common.exception.ServiceException;
import com.zg.common.utils.MinioUtil; import com.zg.common.utils.MinioUtil;
import com.zg.common.utils.SecurityUtils; import com.zg.common.utils.SecurityUtils;
import com.zg.project.wisdom.domain.vo.AuditSignatureReviewVO;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -40,35 +41,39 @@ public class AuditSignatureController extends BaseController
* 上传签字图片到 MinIO * 上传签字图片到 MinIO
*/ */
@PostMapping("/upload") @PostMapping("/upload")
public AjaxResult uploadSignatures(@RequestParam("files") MultipartFile[] files) { public AjaxResult uploadSignature(@RequestParam("file") MultipartFile file) {
if (files == null || files.length == 0) { if (file == null || file.isEmpty()) {
return AjaxResult.error("上传文件不能为空"); return AjaxResult.error("上传文件不能为空");
} }
try {
List<String> urls = new ArrayList<>(); String url = minioUtil.upload(file, "jaz", "signature/");
for (MultipartFile file : files) { return AjaxResult.success("上传成功").put("url", url);
if (file != null && !file.isEmpty()) { } catch (Exception e) {
try { return AjaxResult.error("上传失败: " + e.getMessage());
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')") // @PreAuthorize("@ss.hasPermi('wisdom:signature:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(AuditSignature auditSignature) public TableDataInfo list(AuditSignature auditSignature) {
startPage();
List<AuditSignatureReviewVO> list = auditSignatureService.selectAuditSignatureReviewList(auditSignature);
return getDataTable(list);
}
/**
* 查询个人提交审批记录
*/
// @PreAuthorize("@ss.hasPermi('wisdom:signature:list')")
@GetMapping("/user/list")
public TableDataInfo listMySubmitRecords(AuditSignature auditSignature)
{ {
startPage(); startPage();
List<AuditSignature> list = auditSignatureService.selectAuditSignatureList(auditSignature); auditSignature.setSignerId(SecurityUtils.getUserId().toString()); // 当前用户
List<AuditSignatureReviewVO> list = auditSignatureService.selectMySubmittedAuditList(auditSignature);
return getDataTable(list); return getDataTable(list);
} }
@@ -107,14 +112,13 @@ public class AuditSignatureController extends BaseController
} }
/** /**
* 修改审批记录 * 审批
*/ */
@PreAuthorize("@ss.hasPermi('wisdom:signature:edit')") @PreAuthorize("@ss.hasPermi('wisdom:signature:edit')")
@Log(title = "审批记录", businessType = BusinessType.UPDATE) @Log(title = "审批记录", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody AuditSignature auditSignature) public AjaxResult approve(@RequestBody AuditSignature auditSignature) {
{ return toAjax(auditSignatureService.approveAuditSignature(auditSignature));
return toAjax(auditSignatureService.updateAuditSignature(auditSignature));
} }
/** /**

View File

@@ -22,6 +22,10 @@ public class AuditSignature extends BaseEntity {
@Excel(name = "单据编号") @Excel(name = "单据编号")
private String billNo; private String billNo;
/** 入库记录ID物理外键绑定rk_info.id */
@Excel(name = "入库记录ID")
private Long rkId;
/** 单据类型0入库 1出库 */ /** 单据类型0入库 1出库 */
@Excel(name = "单据类型") @Excel(name = "单据类型")
private String billType; private String billType;
@@ -96,6 +100,14 @@ public class AuditSignature extends BaseEntity {
this.billNo = billNo; this.billNo = billNo;
} }
public Long getRkId() {
return rkId;
}
public void setRkId(Long rkId) {
this.rkId = rkId;
}
public String getBillType() { public String getBillType() {
return billType; return billType;
} }
@@ -215,6 +227,7 @@ public class AuditSignature extends BaseEntity {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId()) .append("id", getId())
.append("billNo", getBillNo()) .append("billNo", getBillNo())
.append("rkId", getRkId())
.append("billType", getBillType()) .append("billType", getBillType())
.append("signerId", getSignerId()) .append("signerId", getSignerId())
.append("approverId", getApproverId()) .append("approverId", getApproverId())

View File

@@ -162,6 +162,10 @@ public class RkInfo extends BaseEntity
@Excel(name = "实物ID") @Excel(name = "实物ID")
private String entityId; private String entityId;
/** 一货一图 - 货物照片URL */
@TableField(exist = false)
private String photoUrl;
@Excel(name = "出库理货员") @Excel(name = "出库理货员")
private String ckLihuoY; private String ckLihuoY;
@@ -193,6 +197,18 @@ public class RkInfo extends BaseEntity
@Excel(name = "是否借料", readConverterExp = "0=否,1=是") @Excel(name = "是否借料", readConverterExp = "0=否,1=是")
private String isBorrowed; private String isBorrowed;
/** 签字图片URLimage_type = 0 */
@TableField(exist = false)
private String signImageUrl;
/** 现场图片URLimage_type = 1 */
@TableField(exist = false)
private String scenePhotoUrl;
/** 当前审批结果0通过1驳回 */
@TableField(exist = false)
private String auditResult;
/** 入库开始时间 */ /** 入库开始时间 */
private Date startTime; private Date startTime;
@@ -283,6 +299,13 @@ public class RkInfo extends BaseEntity
public void setTrayCode(String trayCode) { this.trayCode = trayCode; } public void setTrayCode(String trayCode) { this.trayCode = trayCode; }
public String getEntityId() { return entityId; } public String getEntityId() { return entityId; }
public void setEntityId(String entityId) { this.entityId = entityId; } public void setEntityId(String entityId) { this.entityId = entityId; }
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
public String getCkLihuoY() { return ckLihuoY; } public String getCkLihuoY() { return ckLihuoY; }
public void setCkLihuoY(String ckLihuoY) { this.ckLihuoY = ckLihuoY; } public void setCkLihuoY(String ckLihuoY) { this.ckLihuoY = ckLihuoY; }
public String getCkType() { return ckType; } public String getCkType() { return ckType; }
@@ -341,6 +364,29 @@ public class RkInfo extends BaseEntity
this.isBorrowed = isBorrowed; this.isBorrowed = isBorrowed;
} }
public String getSignImageUrl() {
return signImageUrl;
}
public void setSignImageUrl(String signImageUrl) {
this.signImageUrl = signImageUrl;
}
public String getScenePhotoUrl() {
return scenePhotoUrl;
}
public void setScenePhotoUrl(String scenePhotoUrl) {
this.scenePhotoUrl = scenePhotoUrl;
}
public String getAuditResult() {
return auditResult;
}
public void setAuditResult(String auditResult) {
this.auditResult = auditResult;
}
public String getIsDelete() { return isDelete; } public String getIsDelete() { return isDelete; }
public void setIsDelete(String isDelete) { this.isDelete = isDelete; } public void setIsDelete(String isDelete) { this.isDelete = isDelete; }
@@ -378,6 +424,7 @@ public class RkInfo extends BaseEntity
.append("pcodeId", getPcodeId()) .append("pcodeId", getPcodeId())
.append("trayCode", getTrayCode()) .append("trayCode", getTrayCode())
.append("entityId", getEntityId()) .append("entityId", getEntityId())
.append("photoUrl", getPhotoUrl())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())
.append("updateBy", getUpdateBy()) .append("updateBy", getUpdateBy())
@@ -396,6 +443,9 @@ public class RkInfo extends BaseEntity
.append("startTime", getStartTime()) .append("startTime", getStartTime())
.append("endTime", getEndTime()) .append("endTime", getEndTime())
.append("isBorrowed", getIsBorrowed()) .append("isBorrowed", getIsBorrowed())
.append("signImageUrl", getSignImageUrl())
.append("scenePhotoUrl", getScenePhotoUrl())
.append("auditResult", getAuditResult())
.append("isDelete", getIsDelete()) .append("isDelete", getIsDelete())
.toString(); .toString();
} }

View File

@@ -34,7 +34,5 @@ public class PcRkInfoBatchDTO {
/** 发起人签字图片 URL单张 */ /** 发起人签字图片 URL单张 */
private String signatureUrl; private String signatureUrl;
/** 现场照片 URL 列表(多张) */
private List<String> photoUrls;
} }

View File

@@ -1,10 +1,13 @@
package com.zg.project.wisdom.domain.dto; package com.zg.project.wisdom.domain.dto;
import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* PC端 - 入库明细 DTO字段驼峰命名规范 * PC端 - 入库明细 DTO字段驼峰命名规范
*/ */
@Data
public class PcRkInfoItemDTO { public class PcRkInfoItemDTO {
/** 县局 */ /** 县局 */
@@ -73,181 +76,7 @@ public class PcRkInfoItemDTO {
/** 备注 */ /** 备注 */
private String remark; private String remark;
// ======= Getter / Setter ======= /** 单条货物对应的现场照片 URL */
private String photoUrl;
public String getXj() {
return xj;
}
public void setXj(String xj) {
this.xj = xj;
}
public Long getGysJhId() {
return gysJhId;
}
public void setGysJhId(Long gysJhId) {
this.gysJhId = gysJhId;
}
public String getWlNo() {
return wlNo;
}
public void setWlNo(String wlNo) {
this.wlNo = wlNo;
}
public String getWlMs() {
return wlMs;
}
public void setWlMs(String wlMs) {
this.wlMs = wlMs;
}
public String getXmMs() {
return xmMs;
}
public void setXmMs(String xmMs) {
this.xmMs = xmMs;
}
public String getXmNo() {
return xmNo;
}
public void setXmNo(String xmNo) {
this.xmNo = xmNo;
}
public String getSapWlNo() {
return sapWlNo;
}
public void setSapWlNo(String sapWlNo) {
this.sapWlNo = sapWlNo;
}
public String getSapWlMs() {
return sapWlMs;
}
public void setSapWlMs(String sapWlMs) {
this.sapWlMs = sapWlMs;
}
public String getGysNo() {
return gysNo;
}
public void setGysNo(String gysNo) {
this.gysNo = gysNo;
}
public String getGysMc() {
return gysMc;
}
public void setGysMc(String gysMc) {
this.gysMc = gysMc;
}
public String getSapNo() {
return sapNo;
}
public void setSapNo(String sapNo) {
this.sapNo = sapNo;
}
public Long getJhQty() {
return jhQty;
}
public void setJhQty(Long jhQty) {
this.jhQty = jhQty;
}
public Long getHtQty() {
return htQty;
}
public void setHtQty(Long htQty) {
this.htQty = htQty;
}
public String getDw() {
return dw;
}
public void setDw(String dw) {
this.dw = dw;
}
public BigDecimal getJhAmt() {
return jhAmt;
}
public void setJhAmt(BigDecimal jhAmt) {
this.jhAmt = jhAmt;
}
public BigDecimal getHtDj() {
return htDj;
}
public void setHtDj(BigDecimal htDj) {
this.htDj = htDj;
}
public BigDecimal getRealQty() {
return realQty;
}
public void setRealQty(BigDecimal realQty) {
this.realQty = realQty;
}
public String getPcode() {
return pcode;
}
public void setPcode(String pcode) {
this.pcode = pcode;
}
public String getPcodeId() {
return pcodeId;
}
public void setPcodeId(String pcodeId) {
this.pcodeId = pcodeId;
}
public String getTrayCode() {
return trayCode;
}
public void setTrayCode(String trayCode) {
this.trayCode = trayCode;
}
public String getEntityId() {
return entityId;
}
public void setEntityId(String entityId) {
this.entityId = entityId;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
} }

View File

@@ -27,6 +27,4 @@ public class RkInfoBatchDTO {
/** 发起人签字图片 URL单张 */ /** 发起人签字图片 URL单张 */
private String signatureUrl; private String signatureUrl;
/** 现场照片 URL 列表(多张) */
private List<String> photoUrls;
} }

View File

@@ -1,11 +1,14 @@
package com.zg.project.wisdom.domain.dto; package com.zg.project.wisdom.domain.dto;
import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
* APP端 - 入库明细 DTO * APP端 - 入库明细 DTO
*/ */
@Data
public class RkInfoItemDTO { public class RkInfoItemDTO {
/** 供应计划主键ID */ /** 供应计划主键ID */
@@ -52,124 +55,4 @@ public class RkInfoItemDTO {
/** 实物扫码记录列表 */ /** 实物扫码记录列表 */
private List<RkInfoScanDTO> scanList; private List<RkInfoScanDTO> scanList;
public Long getGysJhId() {
return gysJhId;
}
public void setGysJhId(Long gysJhId) {
this.gysJhId = gysJhId;
}
public String getWlNo() {
return wlNo;
}
public void setWlNo(String wlNo) {
this.wlNo = wlNo;
}
public String getWlMs() {
return wlMs;
}
public void setWlMs(String wlMs) {
this.wlMs = wlMs;
}
public String getXmNo() {
return xmNo;
}
public void setXmNo(String xmNo) {
this.xmNo = xmNo;
}
public String getXmMs() {
return xmMs;
}
public void setXmMs(String xmMs) {
this.xmMs = xmMs;
}
public String getXj() {
return xj;
}
public void setXj(String xj) {
this.xj = xj;
}
public String getGysNo() {
return gysNo;
}
public void setGysNo(String gysNo) {
this.gysNo = gysNo;
}
public String getGysMc() {
return gysMc;
}
public void setGysMc(String gysMc) {
this.gysMc = gysMc;
}
public String getSapNo() {
return sapNo;
}
public void setSapNo(String sapNo) {
this.sapNo = sapNo;
}
public Long getJhQty() {
return jhQty;
}
public void setJhQty(Long jhQty) {
this.jhQty = jhQty;
}
public Long getHtQty() {
return htQty;
}
public void setHtQty(Long htQty) {
this.htQty = htQty;
}
public String getDw() {
return dw;
}
public void setDw(String dw) {
this.dw = dw;
}
public BigDecimal getJhAmt() {
return jhAmt;
}
public void setJhAmt(BigDecimal jhAmt) {
this.jhAmt = jhAmt;
}
public BigDecimal getHtDj() {
return htDj;
}
public void setHtDj(BigDecimal htDj) {
this.htDj = htDj;
}
public List<RkInfoScanDTO> getScanList() {
return scanList;
}
public void setScanList(List<RkInfoScanDTO> scanList) {
this.scanList = scanList;
}
} }

View File

@@ -1,7 +1,9 @@
package com.zg.project.wisdom.domain.dto; package com.zg.project.wisdom.domain.dto;
import java.math.BigDecimal; import lombok.Data;
import java.math.BigDecimal;
@Data
public class RkInfoScanDTO { public class RkInfoScanDTO {
/** 库位码 */ /** 库位码 */
@@ -19,54 +21,9 @@ public class RkInfoScanDTO {
/** 实物 ID */ /** 实物 ID */
private String entityId; private String entityId;
/** 现场照片URL单张 */
private String photoUrl;
/** 备注 */ /** 备注 */
private String remark; private String remark;
public String getPcode() {
return pcode;
}
public void setPcode(String pcode) {
this.pcode = pcode;
}
public String getPcodeId() {
return pcodeId;
}
public void setPcodeId(String pcodeId) {
this.pcodeId = pcodeId;
}
public String getTrayCode() {
return trayCode;
}
public void setTrayCode(String trayCode) {
this.trayCode = trayCode;
}
public BigDecimal getRealQty() {
return realQty;
}
public void setRealQty(BigDecimal realQty) {
this.realQty = realQty;
}
public String getEntityId() {
return entityId;
}
public void setEntityId(String entityId) {
this.entityId = entityId;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
} }

View File

@@ -0,0 +1,75 @@
package com.zg.project.wisdom.domain.vo;
import com.zg.project.wisdom.domain.AuditSignature;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 审核记录封装VO包含一条审核记录 + 多张现场照片)
*/
@Data
public class AuditSignatureReviewVO {
/** 主键ID审核记录的ID */
private Long id;
/** 单据编号 */
private String billNo;
/** 入库记录ID对应rk_info.id */
private Long rkId;
/** 单据类型0入库1出库 */
private String billType;
/** 审核人ID */
private String approverId;
/** 审核人签字图片URL签字图 */
private String approverSignUrl;
/** 审核结果0通过1驳回 */
private String auditResult;
/** 是否当前记录1是0否 */
private String isCurrent;
/** 审核时间 */
private Date signTime;
/** 审核备注 */
private String remark;
/** 创建人 */
private String createBy;
/** 创建时间 */
private Date createTime;
/** 更新人 */
private String updateBy;
/** 更新时间 */
private Date updateTime;
/** 逻辑删除标记0正常1删除 */
private String isDelete;
/** 携带入库信息的现场图片列表 */
private List<AuditSignatureVo> scenePhotos;
/** 入库类型名称(中文) */
private String rkTypeName;
/** 所属仓库名称(中文) */
private String cangkuName;
/** 物资类型名称(中文) */
private String wlTypeName;
/** 理货员名称(原本就是中文) */
private String lihuoY;
}

View File

@@ -0,0 +1,42 @@
package com.zg.project.wisdom.domain.vo;
import com.zg.project.wisdom.domain.AuditSignature;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 签字记录 + 入库货物信息 展示用 VO
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class AuditSignatureVo extends AuditSignature {
/** 项目号 */
private String xmNo;
/** 项目描述 */
private String xmMs;
/** 物料描述 */
private String wlMs;
/** 供应商名称 */
private String gysMc;
/** 物料号 */
private String wlNo;
/** 实际入库数量 */
private BigDecimal realQty;
/** 计量单位 */
private String dw;
/** 库位码(覆盖 a.pcode改为取 r.pcode */
private String pcode;
/** 入库备注rk_info 表里的) */
private String rkRemark;
}

View File

@@ -2,6 +2,8 @@ package com.zg.project.wisdom.mapper;
import java.util.List; import java.util.List;
import com.zg.project.wisdom.domain.AuditSignature; import com.zg.project.wisdom.domain.AuditSignature;
import com.zg.project.wisdom.domain.vo.AuditSignatureVo;
import org.apache.ibatis.annotations.Param;
/** /**
* 审批记录Mapper接口 * 审批记录Mapper接口
@@ -71,7 +73,7 @@ public interface AuditSignatureMapper
* @param * @param
* @return * @return
*/ */
boolean existsCurrentSigner(String billNo, String number); boolean existsCurrentSigner(@Param("billNo") String billNo, @Param("signerRole") String signerRole);
/** /**
* 修改当前申请数据的可用状态 * 修改当前申请数据的可用状态
@@ -86,4 +88,32 @@ public interface AuditSignatureMapper
* @return * @return
*/ */
void batchInsert(List<AuditSignature> recordList); void batchInsert(List<AuditSignature> recordList);
/**
* 查询现场图片URL按入库ID
*/
AuditSignature selectPhotoUrlByRkId(@Param("rkId") Long rkId);
/**
* 查询审批记录列表按主表ID
*/
List<AuditSignature> selectAuditMainList(AuditSignature filter);
/**
* 获取包含入库货物信息的现场图记录
*/
List<AuditSignatureVo> selectScenePhotosWithGoodsByBillNo(@Param("billNo") String billNo);
/**
* 获取提交人列表
*/
List<AuditSignature> selectAuditMainListBySubmitter(AuditSignature filter);
/**
* 审核
* @param auditSignature
* @return
*/
int approveAuditByBillNo(AuditSignature auditSignature);
} }

View File

@@ -1,5 +1,6 @@
package com.zg.project.wisdom.mapper; package com.zg.project.wisdom.mapper;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -176,4 +177,10 @@ public interface RkInfoMapper
* 修改入库单据状态 * 修改入库单据状态
*/ */
int updateStatusByBillNo(RkInfo rkInfo); int updateStatusByBillNo(RkInfo rkInfo);
/**
* 查询每个 billNo 对应的一条入库记录(用于获取公共字段)
*/
List<RkInfo> selectOneForEachBillNo(@Param("billNos") List<String> billNos);
} }

View File

@@ -2,6 +2,7 @@ package com.zg.project.wisdom.service;
import java.util.List; import java.util.List;
import com.zg.project.wisdom.domain.AuditSignature; import com.zg.project.wisdom.domain.AuditSignature;
import com.zg.project.wisdom.domain.vo.AuditSignatureReviewVO;
/** /**
* 审批记录Service接口 * 审批记录Service接口
@@ -71,4 +72,27 @@ public interface IAuditSignatureService
* @param audit * @param audit
*/ */
void audit(AuditSignature audit); void audit(AuditSignature audit);
/**
* 查询审批记录列表
*
* @param auditSignature 审批记录
* @return 审批记录集合
*/
List<AuditSignatureReviewVO> selectAuditSignatureReviewList(AuditSignature auditSignature);
/**
* 查询我提交的审批列表
*
* @param auditSignature 审批记录
* @return 审批记录集合
*/
List<AuditSignatureReviewVO> selectMySubmittedAuditList(AuditSignature auditSignature);
/**
* 审批
* @param auditSignature
* @return
*/
int approveAuditSignature(AuditSignature auditSignature);
} }

View File

@@ -1,13 +1,19 @@
package com.zg.project.wisdom.service.impl; package com.zg.project.wisdom.service.impl;
import java.util.List; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.zg.common.exception.ServiceException; import com.zg.common.exception.ServiceException;
import com.zg.common.utils.DateUtils; import com.zg.common.utils.DateUtils;
import com.zg.common.utils.SecurityUtils; import com.zg.common.utils.SecurityUtils;
import com.zg.common.utils.StringUtils;
import com.zg.project.wisdom.domain.RkInfo; import com.zg.project.wisdom.domain.RkInfo;
import com.zg.project.wisdom.domain.vo.AuditSignatureReviewVO;
import com.zg.project.wisdom.domain.vo.AuditSignatureVo;
import com.zg.project.wisdom.mapper.RkInfoMapper; import com.zg.project.wisdom.mapper.RkInfoMapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.zg.project.wisdom.mapper.AuditSignatureMapper; import com.zg.project.wisdom.mapper.AuditSignatureMapper;
@@ -153,4 +159,78 @@ public class AuditSignatureServiceImpl implements IAuditSignatureService
rkInfoMapper.updateStatusByBillNo(rk); rkInfoMapper.updateStatusByBillNo(rk);
} }
@Override
public List<AuditSignatureReviewVO> selectAuditSignatureReviewList(AuditSignature filter) {
// 1. 查询主记录列表(发起人签字图)
List<AuditSignature> mainList = auditSignatureMapper.selectAuditMainList(filter);
// ✅ 批量提取所有 billNo
Set<String> billNoSet = mainList.stream()
.map(AuditSignature::getBillNo)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
// 2. 一次性查询所有 billNo 对应的入库公共字段
Map<String, RkInfo> rkInfoMap = new HashMap<>();
if (!billNoSet.isEmpty()) {
List<RkInfo> rkInfoList = rkInfoMapper.selectOneForEachBillNo(new ArrayList<>(billNoSet));
rkInfoMap = rkInfoList.stream()
.collect(Collectors.toMap(RkInfo::getBillNo, Function.identity(), (a, b) -> a));
}
// 3. 构造返回结果列表
List<AuditSignatureReviewVO> resultList = new ArrayList<>();
for (AuditSignature main : mainList) {
AuditSignatureReviewVO vo = new AuditSignatureReviewVO();
BeanUtils.copyProperties(main, vo);
// 设置入库公共字段(若存在)
RkInfo rk = rkInfoMap.get(main.getBillNo());
if (rk != null) {
vo.setRkTypeName(rk.getRkTypeName());
vo.setCangkuName(rk.getCangkuName());
vo.setWlTypeName(rk.getWlTypeName());
vo.setLihuoY(rk.getLihuoY());
}
// 查询该 billNo 下的现场照片 + 入库字段
List<AuditSignatureVo> photoList = auditSignatureMapper.selectScenePhotosWithGoodsByBillNo(main.getBillNo());
vo.setScenePhotos(photoList);
resultList.add(vo);
}
return resultList;
}
@Override
public List<AuditSignatureReviewVO> selectMySubmittedAuditList(AuditSignature filter) {
// 查询发起人/现场拍照图中主图image_type = 0记录
List<AuditSignature> mainList = auditSignatureMapper.selectAuditMainListBySubmitter(filter);
List<AuditSignatureReviewVO> resultList = new ArrayList<>();
for (AuditSignature main : mainList) {
AuditSignatureReviewVO vo = new AuditSignatureReviewVO();
BeanUtils.copyProperties(main, vo);
// 查询现场图(包含货物信息)
String billNo = main.getBillNo();
List<AuditSignatureVo> scenePhotos = auditSignatureMapper.selectScenePhotosWithGoodsByBillNo(billNo);
vo.setScenePhotos(scenePhotos);
resultList.add(vo);
}
return resultList;
}
@Override
public int approveAuditSignature(AuditSignature auditSignature) {
auditSignature.setUpdateTime(DateUtils.getNowDate());
auditSignature.setSignerRole("1"); // 审核人
auditSignature.setIsCurrent("1"); // 当前记录
return auditSignatureMapper.approveAuditByBillNo(auditSignature);
}
} }

View File

@@ -10,6 +10,7 @@ import java.util.stream.Collectors;
import com.zg.common.exception.ServiceException; import com.zg.common.exception.ServiceException;
import com.zg.common.utils.DateUtils; import com.zg.common.utils.DateUtils;
import com.zg.common.utils.SecurityUtils; import com.zg.common.utils.SecurityUtils;
import com.zg.common.utils.StringUtils;
import com.zg.project.Inventory.AutoInventory.mapper.InventoryMatchScanMapper; import com.zg.project.Inventory.AutoInventory.mapper.InventoryMatchScanMapper;
import com.zg.project.Inventory.Task.mapper.InventoryTaskMapper; import com.zg.project.Inventory.Task.mapper.InventoryTaskMapper;
import com.zg.project.Inventory.domain.dto.QueryDTO; import com.zg.project.Inventory.domain.dto.QueryDTO;
@@ -79,10 +80,13 @@ public class RkInfoServiceImpl implements IRkInfoService
*/ */
@Override @Override
public List<RkInfo> selectRkInfoList(RkInfo rkInfo) { public List<RkInfo> selectRkInfoList(RkInfo rkInfo) {
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
List<RkInfo> list = rkInfoMapper.selectRkInfoList(rkInfo); List<RkInfo> list = rkInfoMapper.selectRkInfoList(rkInfo);
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
for (RkInfo info : list) { for (RkInfo info : list) {
// 计算库龄
if (info.getRkTime() != null) { if (info.getRkTime() != null) {
LocalDate rkDate = info.getRkTime().toInstant() LocalDate rkDate = info.getRkTime().toInstant()
.atZone(ZoneId.systemDefault()) .atZone(ZoneId.systemDefault())
@@ -90,12 +94,28 @@ public class RkInfoServiceImpl implements IRkInfoService
long days = ChronoUnit.DAYS.between(rkDate, today); long days = ChronoUnit.DAYS.between(rkDate, today);
info.setStockAge(days); info.setStockAge(days);
} }
// 查询现场图片 + 审核结果image_type = '1'
AuditSignature signature = auditSignatureMapper.selectPhotoUrlByRkId(info.getId());
if (signature != null) {
info.setScenePhotoUrl(signature.getSignUrl());
info.setAuditResult(signature.getAuditResult());
} else {
info.setScenePhotoUrl(null);
info.setAuditResult(null);
}
}
// 审核开启,过滤掉未通过的(只有 auditResult = '0' 保留)
if (needAudit) {
list = list.stream()
.filter(info -> "0".equals(info.getAuditResult()))
.collect(Collectors.toList());
} }
return list; return list;
} }
/** /**
* 修改库存单据主 * 修改库存单据主
* *
@@ -145,10 +165,13 @@ public class RkInfoServiceImpl implements IRkInfoService
List<PcRkInfoItemDTO> list = dto.getRkList(); List<PcRkInfoItemDTO> list = dto.getRkList();
List<RkInfo> rkInfos = new ArrayList<>(); List<RkInfo> rkInfos = new ArrayList<>();
boolean needAudit = "1".equals(configService.selectConfigByKey("stock.audit.enabled")); boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
String userId = SecurityUtils.getUserId().toString(); String userId = SecurityUtils.getUserId().toString();
Date now = DateUtils.getNowDate(); Date now = DateUtils.getNowDate();
List<AuditSignature> records = new ArrayList<>();
// ✅ 第一步:先构造 RkInfo 列表(不保存照片)
for (PcRkInfoItemDTO item : list) { for (PcRkInfoItemDTO item : list) {
RkInfo rk = new RkInfo(); RkInfo rk = new RkInfo();
BeanUtils.copyProperties(item, rk); BeanUtils.copyProperties(item, rk);
@@ -156,10 +179,12 @@ public class RkInfoServiceImpl implements IRkInfoService
rk.setRkType(dto.getRkType()); rk.setRkType(dto.getRkType());
rk.setWlType(dto.getWlType()); rk.setWlType(dto.getWlType());
rk.setLihuoY(dto.getLihuoY()); rk.setLihuoY(dto.getLihuoY());
rk.setRkTime(now);
rk.setCangku(dto.getCangku()); rk.setCangku(dto.getCangku());
rk.setCreateBy(userId); rk.setCreateBy(userId);
rk.setCreateTime(now); rk.setCreateTime(now);
rk.setIsDelete("0"); rk.setIsDelete("0");
if (needAudit) { if (needAudit) {
rk.setStatus("0"); // 入库待审核 rk.setStatus("0"); // 入库待审核
rk.setIsChuku("2"); // 待入库(审核中) rk.setIsChuku("2"); // 待入库(审核中)
@@ -167,60 +192,64 @@ public class RkInfoServiceImpl implements IRkInfoService
rk.setStatus("1"); // 审核通过 rk.setStatus("1"); // 审核通过
rk.setIsChuku("0"); // 已入库 rk.setIsChuku("0"); // 已入库
} }
rkInfos.add(rk); rkInfos.add(rk);
} }
// ✅ 第二步:批量保存入库记录,回填主键 ID
rkInfoMapper.batchInsertRkInfo(rkInfos); rkInfoMapper.batchInsertRkInfo(rkInfos);
// ====== 写入签字记录(支持重新提交)====== // ✅ 第三步:根据主键构造照片记录
if (needAudit) { for (int i = 0; i < rkInfos.size(); i++) {
List<AuditSignature> records = new ArrayList<>(); RkInfo rk = rkInfos.get(i);
PcRkInfoItemDTO item = list.get(i);
if (needAudit && StringUtils.isNotBlank(item.getPhotoUrl())) {
AuditSignature photo = new AuditSignature();
photo.setRkId(rk.getId()); // ✅ 此时已填充 ID
photo.setBillNo(billNo);
photo.setBillType("0");
photo.setAuditResult("2");
photo.setSignerId(userId);
photo.setSignerRole("2"); // 拍照人
photo.setImageType("1"); // 现场图
photo.setSignUrl(item.getPhotoUrl());
photo.setSignTime(now);
photo.setPcode(item.getPcode());
photo.setTrayCode(item.getTrayCode());
photo.setApproverId(dto.getApproverId());
photo.setIsCurrent("1");
photo.setIsDelete("0");
photo.setCreateBy(userId);
photo.setCreateTime(now);
records.add(photo);
}
}
// ✅ 第四步:如果启用审核,添加发起人签字记录
if (needAudit) {
// === 检查是否已有发起人签字记录 === // === 检查是否已有发起人签字记录 ===
boolean hasOldSign = auditSignatureMapper.existsCurrentSigner(billNo, "0"); // signerRole = 0 表示发起人 boolean hasOldSign = auditSignatureMapper.existsCurrentSigner(billNo, "0");
if (hasOldSign) { if (hasOldSign) {
// 将旧记录设为历史
auditSignatureMapper.updateIsCurrentToZero(billNo, "0"); auditSignatureMapper.updateIsCurrentToZero(billNo, "0");
} }
// === 新的主签字记录(发起人 + 审批人) ===
AuditSignature mainSign = new AuditSignature(); AuditSignature mainSign = new AuditSignature();
mainSign.setBillNo(billNo); // 单据号 mainSign.setBillNo(billNo);
mainSign.setBillType("0"); // 单据类型0入库 mainSign.setBillType("0");
mainSign.setSignerId(userId); // 签字人ID发起人 mainSign.setSignerId(userId);
mainSign.setSignerRole("0"); // 角色0发起人 mainSign.setSignerRole("0"); // 发起人
mainSign.setApproverId(dto.getApproverId()); // 审批人ID mainSign.setApproverId(dto.getApproverId());
mainSign.setSignUrl(dto.getSignatureUrl()); // 发起人签字图片URL mainSign.setSignUrl(dto.getSignatureUrl());
mainSign.setImageType("0"); // 图片类型0签字 mainSign.setImageType("0"); // 签字
mainSign.setSignTime(now); // 签字时间 mainSign.setSignTime(now);
mainSign.setIsCurrent("1"); // 当前记录 mainSign.setIsCurrent("1");
mainSign.setIsDelete("0"); // 是否删除 mainSign.setIsDelete("0");
mainSign.setCreateBy(userId); // 创建人 mainSign.setCreateBy(userId);
mainSign.setCreateTime(now); // 创建时间 mainSign.setCreateTime(now);
records.add(mainSign); records.add(mainSign);
// === 现场照片(每张一条记录) === // ✅ 写入照片 + 签字图
if (dto.getPhotoUrls() != null && !dto.getPhotoUrls().isEmpty()) {
for (String url : dto.getPhotoUrls()) {
if (url == null || url.trim().isEmpty()) continue;
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()) { if (!records.isEmpty()) {
auditSignatureMapper.batchInsert(records); auditSignatureMapper.batchInsert(records);
} }
@@ -232,7 +261,6 @@ public class RkInfoServiceImpl implements IRkInfoService
} }
} }
/** /**
* 新增入库单据APP * 新增入库单据APP
* @param dto * @param dto
@@ -249,57 +277,58 @@ public class RkInfoServiceImpl implements IRkInfoService
throw new ServiceException("rkList 入库明细列表不能为空"); throw new ServiceException("rkList 入库明细列表不能为空");
} }
boolean needAudit = "1".equals(configService.selectConfigByKey("stock.audit.enabled")); boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
String billNo = BillNoUtil.generateTodayBillNo("CK"); String billNo = BillNoUtil.generateTodayBillNo("RK");
// ✅ 第一步:构造入库数据列表
for (RkInfoItemDTO item : dto.getRkList()) { for (RkInfoItemDTO item : dto.getRkList()) {
List<RkInfoScanDTO> scanList = item.getScanList(); List<RkInfoScanDTO> scanList = item.getScanList();
if (scanList == null || scanList.isEmpty()) continue; if (scanList == null || scanList.isEmpty()) continue;
for (RkInfoScanDTO scan : scanList) { for (RkInfoScanDTO scan : scanList) {
RkInfo entity = new RkInfo(); RkInfo entity = new RkInfo();
entity.setRkType(dto.getRkType()); // 入库类型 entity.setRkType(dto.getRkType());
entity.setWlType(dto.getWlType()); // 物资类型 entity.setWlType(dto.getWlType());
entity.setCangku(dto.getCangku()); // 所属仓库ID entity.setCangku(dto.getCangku());
entity.setLihuoY(dto.getLihuoY()); // 理货员 entity.setLihuoY(dto.getLihuoY());
entity.setBillNo(billNo); // 单据号(统一生成) entity.setBillNo(billNo);
entity.setXj(item.getXj()); // 县局 entity.setXj(item.getXj());
entity.setXmMs(item.getXmMs()); // 项目描述 entity.setXmMs(item.getXmMs());
entity.setXmNo(item.getXmNo()); // 项目编号 entity.setXmNo(item.getXmNo());
entity.setSapNo(item.getSapNo()); // SAP订单编号 entity.setSapNo(item.getSapNo());
entity.setJhQty(item.getJhQty()); // 计划交货数量 entity.setJhQty(item.getJhQty());
entity.setHtQty(item.getHtQty()); // 合同数量 entity.setHtQty(item.getHtQty());
entity.setJhAmt(item.getJhAmt()); // 计划交货金额 entity.setJhAmt(item.getJhAmt());
entity.setHtDj(item.getHtDj()); // 合同单价 entity.setHtDj(item.getHtDj());
entity.setDw(item.getDw()); // 计量单位 entity.setDw(item.getDw());
entity.setWlNo(item.getWlNo()); // 物料号 entity.setWlNo(item.getWlNo());
entity.setWlMs(item.getWlMs()); // 物料描述 entity.setWlMs(item.getWlMs());
entity.setGysNo(item.getGysNo()); // 供应商编号 entity.setGysNo(item.getGysNo());
entity.setGysMc(item.getGysMc()); // 供应商名称 entity.setGysMc(item.getGysMc());
entity.setPcode(scan.getPcode()); // 库位码(明细) entity.setPcode(scan.getPcode());
entity.setPcodeId(CodeConvertUtil.stringToHex(scan.getPcode())); // 库位码16进制编码 entity.setPcodeId(CodeConvertUtil.stringToHex(scan.getPcode()));
entity.setTrayCode(scan.getTrayCode()); // 托盘码 entity.setTrayCode(scan.getTrayCode());
entity.setRealQty(scan.getRealQty()); // 实际入库数量 entity.setRealQty(scan.getRealQty());
entity.setEntityId(scan.getEntityId()); // 实物ID entity.setEntityId(scan.getEntityId());
entity.setRemark(scan.getRemark()); // 备注 entity.setRemark(scan.getRemark());
entity.setIsDelete("0"); // 是否删除0=正常) entity.setIsDelete("0");
entity.setIsChuku("0"); // 是否已出库0=否) entity.setRkTime(now);
entity.setCreateBy(userId);
entity.setCreateTime(now);
if (needAudit) { if (needAudit) {
entity.setStatus("0"); // 入库待审核 entity.setStatus("0"); // 待审核
entity.setIsChuku("3"); // 待入库(审核中) entity.setIsChuku("3"); // 待入库(审核中)
} else { } else {
entity.setStatus("1"); // 审核通过 entity.setStatus("1"); // 审核通过
entity.setIsChuku("0"); // 已入库 entity.setIsChuku("0"); // 已入库
} }
entity.setRkTime(now); // 入库时间
entity.setCreateBy(userId); // 创建人
entity.setCreateTime(now); // 创建时间
saveList.add(entity); saveList.add(entity);
} }
if (item.getGysJhId() != null) { if (item.getGysJhId() != null) {
gysJhMapper.updateStatusById(item.getGysJhId()); // 更新供应计划状态 gysJhMapper.updateStatusById(item.getGysJhId());
} }
} }
@@ -307,59 +336,69 @@ public class RkInfoServiceImpl implements IRkInfoService
throw new ServiceException("未提取到任何可保存的数据"); throw new ServiceException("未提取到任何可保存的数据");
} }
rkInfoMapper.batchInsertRkInfo(saveList); // 批量插入入库数据 // ✅ 第二步:批量插入入库数据回填主键ID
rkInfoMapper.batchInsertRkInfo(saveList);
// ✅ 写入签字记录(支持重新提交 // ✅ 第三步:处理签字与照片记录(仅启用审核时
if (needAudit) { if (needAudit) {
List<AuditSignature> recordList = new ArrayList<>(); List<AuditSignature> recordList = new ArrayList<>();
// === 判断是否重新提交 === // 检查是否重新提交,旧记录置为非当前
boolean isResubmit = auditSignatureMapper.existsCurrentSigner(billNo, "0"); boolean isResubmit = auditSignatureMapper.existsCurrentSigner(billNo, "0");
if (isResubmit) { if (isResubmit) {
auditSignatureMapper.updateIsCurrentToZero(billNo, "0"); // 将旧签字记录置为历史 auditSignatureMapper.updateIsCurrentToZero(billNo, "0");
} }
// === 发起人签字记录 === // ✅ 1. 添加发起人签字记录
AuditSignature mainSign = new AuditSignature(); AuditSignature mainSign = new AuditSignature();
mainSign.setBillNo(billNo); // 单据号 mainSign.setBillNo(billNo);
mainSign.setBillType("0"); // 单据类型0=入库 mainSign.setBillType("0");
mainSign.setSignerId(userId); // 签字人ID当前登录人 mainSign.setSignerId(userId);
mainSign.setSignerRole("0"); // 签字人角色0=发起人 mainSign.setSignerRole("0"); // 发起人
mainSign.setSignUrl(dto.getSignatureUrl()); // 发起人签字图片URL mainSign.setSignUrl(dto.getSignatureUrl());
mainSign.setSignTime(now); // 签字时间 mainSign.setImageType("0"); // 签字
mainSign.setIsCurrent("1"); // 是否当前记录1=当前) mainSign.setSignTime(now);
mainSign.setImageType("0"); // 图片类型0=签字图 mainSign.setApproverId(dto.getApproverId());
mainSign.setApproverId(dto.getApproverId()); // 审批人ID mainSign.setIsCurrent("1");
mainSign.setIsDelete("0"); // 是否删除0=否) mainSign.setIsDelete("0");
mainSign.setCreateBy(userId); // 创建人 mainSign.setCreateBy(userId);
mainSign.setCreateTime(now); // 创建时间 mainSign.setCreateTime(now);
recordList.add(mainSign); recordList.add(mainSign);
// === 现场照片记录 === // ✅ 2. 绑定每条 rkInfo 与对应 scanList 的 photoUrl
if (dto.getPhotoUrls() != null) { int index = 0;
for (String photoUrl : dto.getPhotoUrls()) { for (RkInfoItemDTO item : dto.getRkList()) {
if (photoUrl == null || photoUrl.trim().isEmpty()) continue; List<RkInfoScanDTO> scanList = item.getScanList();
if (scanList == null || scanList.isEmpty()) continue;
AuditSignature photo = new AuditSignature(); for (RkInfoScanDTO scan : scanList) {
photo.setBillNo(billNo); // 单据号 RkInfo rk = saveList.get(index++);
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 (StringUtils.isNotBlank(scan.getPhotoUrl())) {
AuditSignature photo = new AuditSignature();
photo.setBillNo(billNo);
photo.setBillType("0");
photo.setRkId(rk.getId());
photo.setSignerId(userId);
photo.setSignerRole("2"); // 拍照人
photo.setSignUrl(scan.getPhotoUrl());
photo.setImageType("1"); // 现场图
photo.setSignTime(now);
photo.setApproverId(dto.getApproverId());
photo.setIsCurrent("1");
photo.setIsDelete("0");
photo.setCreateBy(userId);
photo.setCreateTime(now);
photo.setPcode(rk.getPcode());
photo.setTrayCode(rk.getTrayCode());
recordList.add(photo);
}
} }
} }
// ✅ 3. 批量写入 audit_signature
if (!recordList.isEmpty()) { if (!recordList.isEmpty()) {
auditSignatureMapper.batchInsert(recordList); // 批量插入签字记录 auditSignatureMapper.batchInsert(recordList);
} }
} }

View File

@@ -7,6 +7,7 @@ spring:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://192.168.1.20:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://192.168.1.20:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# url: jdbc:mysql://192.168.1.251:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root username: root
password: shzg password: shzg

View File

@@ -69,6 +69,7 @@ spring:
redis: redis:
# 地址 # 地址
host: 192.168.1.20 host: 192.168.1.20
# host: 192.168.1.251
# host: localhost # host: localhost
# 端口默认为6379 # 端口默认为6379
port: 6379 port: 6379

View File

@@ -4,27 +4,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zg.project.wisdom.mapper.AuditSignatureMapper"> <mapper namespace="com.zg.project.wisdom.mapper.AuditSignatureMapper">
<resultMap type="AuditSignature" id="AuditSignatureResult"> <!-- 主记录映射 -->
<result property="id" column="id" /> <resultMap type="com.zg.project.wisdom.domain.AuditSignature" id="AuditSignatureResult">
<result property="billNo" column="bill_no" /> <result property="id" column="id" />
<result property="billType" column="bill_type" /> <result property="billNo" column="bill_no" />
<result property="signerId" column="signer_id" /> <result property="rkId" column="rk_id" />
<result property="signerRole" column="signer_role" /> <result property="billType" column="bill_type" />
<result property="signUrl" column="sign_url" /> <result property="signerId" column="signer_id" />
<result property="signTime" column="sign_time" /> <result property="signerRole" column="signer_role" />
<result property="pcode" column="pcode" /> <result property="signUrl" column="sign_url" />
<result property="trayCode" column="tray_code" /> <result property="signTime" column="sign_time" />
<result property="approverId" column="approver_id" /> <result property="pcode" column="pcode" />
<result property="approverSignUrl" column="approver_sign_url" /> <result property="trayCode" column="tray_code" />
<result property="auditResult" column="audit_result" /> <result property="approverId" column="approver_id" />
<result property="imageType" column="image_type" /> <result property="approverSignUrl" column="approver_sign_url" />
<result property="isCurrent" column="is_current" /> <result property="auditResult" column="audit_result" />
<result property="remark" column="remark" /> <result property="imageType" column="image_type" />
<result property="createBy" column="create_by" /> <result property="isCurrent" column="is_current" />
<result property="createTime" column="create_time" /> <result property="remark" column="remark" />
<result property="updateBy" column="update_by" /> <result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" /> <result property="createTime" column="create_time" />
<result property="isDelete" column="is_delete" /> <result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="isDelete" column="is_delete" />
</resultMap>
<!-- VO对象映射带扩展字段 -->
<resultMap id="AuditSignatureVoResult"
type="com.zg.project.wisdom.domain.vo.AuditSignatureVo"
extends="AuditSignatureResult">
<result column="xmNo" property="xmNo"/>
<result column="xmMs" property="xmMs"/>
<result column="wlMs" property="wlMs"/>
<result column="gysMc" property="gysMc"/>
<result column="wlNo" property="wlNo"/>
<result column="realQty" property="realQty"/>
<result column="dw" property="dw"/>
<result column="pcode" property="pcode"/>
<result column="rkRemark" property="rkRemark"/>
</resultMap> </resultMap>
<sql id="selectAuditSignatureVo"> <sql id="selectAuditSignatureVo">
@@ -77,6 +94,77 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND is_delete = '0' AND is_delete = '0'
</select> </select>
<select id="selectPhotoUrlByRkId"
resultMap="AuditSignatureResult"
parameterType="java.lang.Long">
SELECT sign_url, audit_result
FROM audit_signature
WHERE is_delete = '0'
AND rk_id = #{rkId}
AND image_type = '1'
ORDER BY create_time DESC
LIMIT 1
</select>
<!-- 查询主记录列表(审批记录) signer_role=1 image_type=0 -->
<select id="selectAuditMainList" parameterType="com.zg.project.wisdom.domain.AuditSignature" resultMap="AuditSignatureResult">
SELECT * FROM audit_signature
<where>
AND signer_role = '0'
AND image_type = '0'
<if test="billNo != null and billNo != ''">AND bill_no = #{billNo}</if>
<if test="billType != null and billType != ''">AND bill_type = #{billType}</if>
<if test="auditResult != null and auditResult != ''">AND audit_result = #{auditResult}</if>
<if test="approverId != null and approverId != ''">AND approver_id = #{approverId}</if>
<if test="isDelete != null and isDelete != ''">AND is_delete = #{isDelete}</if>
</where>
</select>
<!-- 查询关联入库信息的现场照片 -->
<select id="selectScenePhotosWithGoodsByBillNo"
parameterType="String"
resultMap="AuditSignatureVoResult">
SELECT
a.id,
a.rk_id,
a.bill_no,
a.sign_url,
a.sign_time,
a.signer_role,
a.image_type,
a.tray_code,
a.is_delete,
a.remark AS remark,
r.xm_no AS xmNo,
r.xm_ms AS xmMs,
r.wl_ms AS wlMs,
r.gys_mc AS gysMc,
r.wl_no AS wlNo,
r.real_qty AS realQty,
r.dw AS dw,
r.pcode AS pcode,
r.remark AS rkRemark
FROM audit_signature a
LEFT JOIN rk_info r ON a.rk_id = r.id
WHERE a.bill_no = #{billNo}
AND a.signer_role = '2'
AND a.image_type = '1'
AND a.is_delete = '0'
</select>
<select id="selectAuditMainListBySubmitter" parameterType="AuditSignature" resultMap="AuditSignatureResult">
<include refid="selectAuditSignatureVo"/>
<where>
and signer_id = #{signerId}
and signer_role in ('0', '2')
and image_type = '0'
and is_delete = '0'
<if test="billNo != null and billNo != ''"> and bill_no = #{billNo}</if>
<if test="billType != null and billType != ''"> and bill_type = #{billType}</if>
</where>
</select>
<insert id="insertAuditSignature" parameterType="AuditSignature" useGeneratedKeys="true" keyProperty="id"> <insert id="insertAuditSignature" parameterType="AuditSignature" useGeneratedKeys="true" keyProperty="id">
insert into audit_signature insert into audit_signature
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -136,7 +224,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
is_current, is_current,
is_delete, is_delete,
create_by, create_by,
create_time create_time,
rk_id
) )
VALUES VALUES
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
@@ -152,7 +241,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{item.isCurrent}, #{item.isCurrent},
#{item.isDelete}, #{item.isDelete},
#{item.createBy}, #{item.createBy},
#{item.createTime} #{item.createTime},
#{item.rkId}
) )
</foreach> </foreach>
</insert> </insert>
@@ -193,6 +283,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND is_delete = '0' AND is_delete = '0'
</update> </update>
<update id="approveAuditByBillNo" parameterType="AuditSignature">
UPDATE audit_signature
<set>
<if test="auditResult != null"> audit_result = #{auditResult},</if>
<if test="approverSignUrl != null"> approver_sign_url = #{approverSignUrl},</if>
<if test="remark != null"> remark = #{remark},</if>
<if test="updateBy != null"> update_by = #{updateBy},</if>
<if test="updateTime != null"> update_time = #{updateTime},</if>
</set>
WHERE bill_no = #{billNo}
AND signer_role = '1'
AND is_delete = '0'
AND is_current = '1'
</update>
<delete id="deleteAuditSignatureById" parameterType="Long"> <delete id="deleteAuditSignatureById" parameterType="Long">
delete from audit_signature where id = #{id} delete from audit_signature where id = #{id}
</delete> </delete>

View File

@@ -84,7 +84,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN construction_team ct ON ri.team_code = ct.team_code LEFT JOIN construction_team ct ON ri.team_code = ct.team_code
</sql> </sql>
<insert id="batchInsertRkInfo" parameterType="java.util.List"> <insert id="batchInsertRkInfo"
parameterType="java.util.List"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO rk_info ( INSERT INTO rk_info (
bill_no, bill_no,
rk_type, wl_type, cangku, lihuo_y, rk_time, rk_type, wl_type, cangku, lihuo_y, rk_time,
@@ -340,6 +343,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
GROUP BY pcode GROUP BY pcode
</select> </select>
<select id="selectOneForEachBillNo" parameterType="java.util.List" resultType="com.zg.project.wisdom.domain.RkInfo">
SELECT
r.bill_no AS billNo,
MAX(r.lihuo_y) AS lihuoY,
MAX(rkType.type_name) AS rkTypeName,
MAX(cangku.warehouse_name) AS cangkuName,
MAX(wlType.type_name) AS wlTypeName
FROM rk_info r
LEFT JOIN stock_in_type rkType ON r.rk_type = rkType.type_code
LEFT JOIN warehouse_info cangku ON r.cangku = cangku.warehouse_code
LEFT JOIN material_type wlType ON r.wl_type = wlType.type_code
WHERE r.is_delete = '0'
AND r.bill_no IN
<foreach collection="billNos" item="billNo" open="(" separator="," close=")">
#{billNo}
</foreach>
GROUP BY r.bill_no
</select>
<update id="updateRkInfo" parameterType="RkInfo"> <update id="updateRkInfo" parameterType="RkInfo">
update rk_info update rk_info
<trim prefix="SET" suffixOverrides=","> <trim prefix="SET" suffixOverrides=",">