配送系统功能开发1205
This commit is contained in:
51
pom.xml
51
pom.xml
@@ -34,12 +34,21 @@
|
|||||||
<poi.version>4.1.2</poi.version>
|
<poi.version>4.1.2</poi.version>
|
||||||
<oshi.version>6.8.3</oshi.version>
|
<oshi.version>6.8.3</oshi.version>
|
||||||
<velocity.version>2.3</velocity.version>
|
<velocity.version>2.3</velocity.version>
|
||||||
|
|
||||||
<!-- override dependency version -->
|
<!-- override dependency version -->
|
||||||
<tomcat.version>9.0.108</tomcat.version>
|
<tomcat.version>9.0.108</tomcat.version>
|
||||||
<logback.version>1.2.13</logback.version>
|
<logback.version>1.2.13</logback.version>
|
||||||
<spring-security.version>5.7.14</spring-security.version>
|
<spring-security.version>5.7.14</spring-security.version>
|
||||||
<spring-framework.version>5.3.39</spring-framework.version>
|
<spring-framework.version>5.3.39</spring-framework.version>
|
||||||
<minio.version>7.1.4</minio.version>
|
<minio.version>7.1.4</minio.version>
|
||||||
|
|
||||||
|
<!-- ======= 阿里云 OCR SDK 统一版本管理 ======= -->
|
||||||
|
<aliyun.ocr.version>3.1.0</aliyun.ocr.version>
|
||||||
|
|
||||||
|
<!-- 确保编译使用UTF-8编码 -->
|
||||||
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -180,7 +189,7 @@
|
|||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
|
<!-- 防止进入swagger页面报类型转换错误 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.swagger</groupId>
|
<groupId>io.swagger</groupId>
|
||||||
<artifactId>swagger-models</artifactId>
|
<artifactId>swagger-models</artifactId>
|
||||||
@@ -239,12 +248,45 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.38</version>
|
<version>1.18.38</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ===== 阿里云 OCR SDK(统一版本管理) ===== -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>ocr_api20210707</artifactId>
|
||||||
|
<version>${aliyun.ocr.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Google Zxing 条形码识别 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>3.5.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>javase</artifactId>
|
||||||
|
<version>3.5.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 阿里云通义千问VL模型SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>dashscope-sdk-java</artifactId>
|
||||||
|
<version>2.16.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -253,13 +295,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<!-- 如有自定义 mainClass,请在这里配置;默认可省略 -->
|
|
||||||
<!--
|
|
||||||
<configuration>
|
|
||||||
<mainClass>com.delivery.DeliveryApplication</mainClass>
|
|
||||||
<fork>true</fork>
|
|
||||||
</configuration>
|
|
||||||
-->
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<fork>true</fork>
|
<fork>true</fork>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class SecurityConfig
|
|||||||
"/delivery/**",
|
"/delivery/**",
|
||||||
"/document/vehicle/**",
|
"/document/vehicle/**",
|
||||||
"/document/type/**",
|
"/document/type/**",
|
||||||
|
"/ocr/**",
|
||||||
"/document/location/**",
|
"/document/location/**",
|
||||||
"/document/mtd/**",
|
"/document/mtd/**",
|
||||||
"/document/info/**",
|
"/document/info/**",
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public class DeliveryOrderController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** 新增配送单据:同一单号多行写入 */
|
/** 发布配送单据:同一单号多行写入 */
|
||||||
@PreAuthorize("@ss.hasPermi('document:order:add')")
|
@PreAuthorize("@ss.hasPermi('document:order:add')")
|
||||||
@Log(title = "配送单据", businessType = BusinessType.INSERT)
|
@Log(title = "配送单据", businessType = BusinessType.INSERT)
|
||||||
@PostMapping("/batch")
|
@PostMapping("/batch")
|
||||||
@@ -141,7 +141,7 @@ public class DeliveryOrderController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 详情:按单号查询所有行 */
|
/** 详情:按单号查询所有行 */
|
||||||
@PreAuthorize("@ss.hasPermi('document:order:query')")
|
// @PreAuthorize("@ss.hasPermi('document:order:query')")
|
||||||
@GetMapping("/detail/{orderNo}")
|
@GetMapping("/detail/{orderNo}")
|
||||||
public AjaxResult detail(@PathVariable String orderNo) {
|
public AjaxResult detail(@PathVariable String orderNo) {
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.delivery.project.document.domain.dto.CalcSuggestFeeDTO;
|
|||||||
import com.delivery.project.document.domain.vo.CalcSuggestFeeVO;
|
import com.delivery.project.document.domain.vo.CalcSuggestFeeVO;
|
||||||
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.validation.annotation.Validated;
|
||||||
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;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import javax.validation.Valid;
|
||||||
import com.delivery.framework.aspectj.lang.annotation.Log;
|
import com.delivery.framework.aspectj.lang.annotation.Log;
|
||||||
import com.delivery.framework.aspectj.lang.enums.BusinessType;
|
import com.delivery.framework.aspectj.lang.enums.BusinessType;
|
||||||
import com.delivery.project.document.domain.VehicleType;
|
import com.delivery.project.document.domain.VehicleType;
|
||||||
@@ -32,6 +34,7 @@ import com.delivery.framework.web.page.TableDataInfo;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/document/type")
|
@RequestMapping("/document/type")
|
||||||
|
@Validated
|
||||||
public class VehicleTypeController extends BaseController
|
public class VehicleTypeController extends BaseController
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -107,7 +110,7 @@ public class VehicleTypeController extends BaseController
|
|||||||
|
|
||||||
/** 计算建议费用(支持前端指定车型重算) */
|
/** 计算建议费用(支持前端指定车型重算) */
|
||||||
@PostMapping("/fee")
|
@PostMapping("/fee")
|
||||||
public AjaxResult calcSuggestFee(@RequestBody CalcSuggestFeeDTO dto) {
|
public AjaxResult calcSuggestFee(@Valid @RequestBody CalcSuggestFeeDTO dto) {
|
||||||
CalcSuggestFeeVO vo = vehicleTypeService.calcSuggestFee(dto);
|
CalcSuggestFeeVO vo = vehicleTypeService.calcSuggestFee(dto);
|
||||||
return success(vo);
|
return success(vo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,25 @@ public class DeliveryOrder extends BaseEntity {
|
|||||||
@Excel(name = "配送单据号")
|
@Excel(name = "配送单据号")
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
|
||||||
|
/** rk_info主键ID */
|
||||||
|
@Excel(name = "rk_info主键ID")
|
||||||
|
private Long rkInfoId;
|
||||||
|
|
||||||
|
/** 制单人用户ID */
|
||||||
|
@Excel(name = "制单人ID")
|
||||||
|
private Long makerId;
|
||||||
|
|
||||||
|
/** 制单人用户名(不入库,用于返回给前端) */
|
||||||
|
private String makerUserName;
|
||||||
|
|
||||||
|
/** 接收物资状态(1数量齐全状态完好 2存在问题) */
|
||||||
|
@Excel(name = "接收物资状态", readConverterExp = "1=数量齐全状态完好,2=存在问题")
|
||||||
|
private Integer receiveStatus; // *** 修改:从 String 改为 Integer ***
|
||||||
|
|
||||||
|
/** 接收物资问题描述 */
|
||||||
|
@Excel(name = "存在问题描述")
|
||||||
|
private String receiveProblem;
|
||||||
|
|
||||||
/** 出库单据号 */
|
/** 出库单据号 */
|
||||||
@Excel(name = "出库单据号")
|
@Excel(name = "出库单据号")
|
||||||
private String billNoCk;
|
private String billNoCk;
|
||||||
@@ -148,9 +167,11 @@ public class DeliveryOrder extends BaseEntity {
|
|||||||
/** 连表查询用:附件列表 */
|
/** 连表查询用:附件列表 */
|
||||||
private List<DeliveryAttachment> attachments;
|
private List<DeliveryAttachment> attachments;
|
||||||
|
|
||||||
|
/** 查询用:多状态筛选 */
|
||||||
private List<String> orderStatusList;
|
private List<String> orderStatusList;
|
||||||
|
|
||||||
// ===================== 费用与里程 =====================
|
// ===================== 费用与里程 =====================
|
||||||
|
|
||||||
/** 建议费用(按车型单价*里程的推荐值) */
|
/** 建议费用(按车型单价*里程的推荐值) */
|
||||||
@Excel(name = "建议费用")
|
@Excel(name = "建议费用")
|
||||||
private BigDecimal suggestFee;
|
private BigDecimal suggestFee;
|
||||||
@@ -174,8 +195,33 @@ public class DeliveryOrder extends BaseEntity {
|
|||||||
|
|
||||||
public String getOrderNo() { return orderNo; }
|
public String getOrderNo() { return orderNo; }
|
||||||
public void setOrderNo(String orderNo) { this.orderNo = orderNo; }
|
public void setOrderNo(String orderNo) { this.orderNo = orderNo; }
|
||||||
|
|
||||||
|
public Long getRkInfoId() { return rkInfoId; }
|
||||||
|
public void setRkInfoId(Long rkInfoId) { this.rkInfoId = rkInfoId; }
|
||||||
|
|
||||||
|
public String getMakerUserName() {
|
||||||
|
return makerUserName;
|
||||||
|
}
|
||||||
|
public void setMakerUserName(String makerUserName) {
|
||||||
|
this.makerUserName = makerUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMakerId() { return makerId; }
|
||||||
|
public void setMakerId(Long makerId) { this.makerId = makerId; }
|
||||||
|
|
||||||
|
public Integer getReceiveStatus() { // *** 修改 ***
|
||||||
|
return receiveStatus;
|
||||||
|
}
|
||||||
|
public void setReceiveStatus(Integer receiveStatus) { // *** 修改 ***
|
||||||
|
this.receiveStatus = receiveStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReceiveProblem() { return receiveProblem; }
|
||||||
|
public void setReceiveProblem(String receiveProblem) { this.receiveProblem = receiveProblem; }
|
||||||
|
|
||||||
public String getBillNoCk() { return billNoCk; }
|
public String getBillNoCk() { return billNoCk; }
|
||||||
public void setBillNoCk(String billNoCk) { this.billNoCk = billNoCk; }
|
public void setBillNoCk(String billNoCk) { this.billNoCk = billNoCk; }
|
||||||
|
|
||||||
public String getXmMs() { return xmMs; }
|
public String getXmMs() { return xmMs; }
|
||||||
public void setXmMs(String xmMs) { this.xmMs = xmMs; }
|
public void setXmMs(String xmMs) { this.xmMs = xmMs; }
|
||||||
|
|
||||||
@@ -266,6 +312,9 @@ public class DeliveryOrder extends BaseEntity {
|
|||||||
public List<DeliveryAttachment> getAttachments() { return attachments; }
|
public List<DeliveryAttachment> getAttachments() { return attachments; }
|
||||||
public void setAttachments(List<DeliveryAttachment> attachments) { this.attachments = attachments; }
|
public void setAttachments(List<DeliveryAttachment> attachments) { this.attachments = attachments; }
|
||||||
|
|
||||||
|
public List<String> getOrderStatusList() { return orderStatusList; }
|
||||||
|
public void setOrderStatusList(List<String> orderStatusList) { this.orderStatusList = orderStatusList; }
|
||||||
|
|
||||||
public BigDecimal getSuggestFee() { return suggestFee; }
|
public BigDecimal getSuggestFee() { return suggestFee; }
|
||||||
public void setSuggestFee(BigDecimal suggestFee) { this.suggestFee = suggestFee; }
|
public void setSuggestFee(BigDecimal suggestFee) { this.suggestFee = suggestFee; }
|
||||||
|
|
||||||
@@ -278,19 +327,18 @@ public class DeliveryOrder extends BaseEntity {
|
|||||||
public BigDecimal getTotalKm() { return totalKm; }
|
public BigDecimal getTotalKm() { return totalKm; }
|
||||||
public void setTotalKm(BigDecimal totalKm) { this.totalKm = totalKm; }
|
public void setTotalKm(BigDecimal totalKm) { this.totalKm = totalKm; }
|
||||||
|
|
||||||
public List<String> getOrderStatusList() {
|
// ===================== toString =====================
|
||||||
return orderStatusList;
|
|
||||||
}
|
|
||||||
public void setOrderStatusList(List<String> orderStatusList) {
|
|
||||||
this.orderStatusList = orderStatusList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
.append("id", getId())
|
.append("id", getId())
|
||||||
.append("orderNo", getOrderNo())
|
.append("orderNo", getOrderNo())
|
||||||
|
.append("rkInfoId", getRkInfoId())
|
||||||
|
.append("makerId", getMakerId())
|
||||||
|
.append("makerUserName", getMakerUserName())
|
||||||
|
.append("receiveStatus", getReceiveStatus()) // *** 类型已是 Integer ***
|
||||||
|
.append("receiveProblem", getReceiveProblem())
|
||||||
.append("billNoCk", getBillNoCk())
|
.append("billNoCk", getBillNoCk())
|
||||||
.append("xmMs", getXmMs())
|
.append("xmMs", getXmMs())
|
||||||
.append("xmNo", getXmNo())
|
.append("xmNo", getXmNo())
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
package com.delivery.project.document.domain.dto;
|
package com.delivery.project.document.domain.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.DecimalMin;
|
||||||
|
import javax.validation.constraints.DecimalMax;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,12 +13,16 @@ import java.math.BigDecimal;
|
|||||||
@Data
|
@Data
|
||||||
public class CalcSuggestFeeDTO {
|
public class CalcSuggestFeeDTO {
|
||||||
/** 货物重量(单位:吨) */
|
/** 货物重量(单位:吨) */
|
||||||
|
@DecimalMin(value = "0.00", message = "货物重量不能小于0")
|
||||||
private BigDecimal weightTon;
|
private BigDecimal weightTon;
|
||||||
|
|
||||||
/** 货物体积(单位:立方米) */
|
/** 货物体积(单位:立方米) */
|
||||||
|
@DecimalMin(value = "0.00", message = "货物体积不能小于0")
|
||||||
private BigDecimal volumeM3;
|
private BigDecimal volumeM3;
|
||||||
|
|
||||||
/** 行程距离(单位:公里) */
|
/** 行程距离(单位:公里) */
|
||||||
|
@DecimalMin(value = "0.00", message = "行程距离不能小于0")
|
||||||
|
@DecimalMax(value = "999999.99", message = "行程距离不能超过999999.99公里")
|
||||||
private BigDecimal distanceKm;
|
private BigDecimal distanceKm;
|
||||||
|
|
||||||
/** 指定车型ID(可选;传入则按该车型计算建议费用) */
|
/** 指定车型ID(可选;传入则按该车型计算建议费用) */
|
||||||
|
|||||||
@@ -31,6 +31,15 @@ public class DeliveryExecuteBindDTO {
|
|||||||
private BigDecimal actualFee; // 实际费用
|
private BigDecimal actualFee; // 实际费用
|
||||||
private BigDecimal tollFee; // 高速费用
|
private BigDecimal tollFee; // 高速费用
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收物资状态:
|
||||||
|
* 0 待确认,1 齐全完好,2 存在问题
|
||||||
|
*/
|
||||||
|
private Integer receiveStatus;
|
||||||
|
|
||||||
|
/** 当 receiveStatus = 2 时,必须填写问题描述 */
|
||||||
|
private String receiveProblem;
|
||||||
|
|
||||||
/** 本次执行的附件条目(URL 列表) */
|
/** 本次执行的附件条目(URL 列表) */
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<DeliveryAttachItemDTO> attachments;
|
private List<DeliveryAttachItemDTO> attachments;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.delivery.project.document.domain.dto;
|
package com.delivery.project.document.domain.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -17,14 +16,9 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class DeliveryOrderCreateDTO {
|
public class DeliveryOrderCreateDTO {
|
||||||
|
|
||||||
/**
|
/** 配送单据号(可空,后台自动生成) */
|
||||||
* 配送单据号,可传可不传;
|
|
||||||
* 不传时由后端自动生成(格式如 DO202510280001)
|
|
||||||
*/
|
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
|
||||||
// ==================== 头部信息(整单通用) ====================
|
|
||||||
|
|
||||||
/** 起始地点名称 */
|
/** 起始地点名称 */
|
||||||
private String originName;
|
private String originName;
|
||||||
|
|
||||||
@@ -43,56 +37,70 @@ public class DeliveryOrderCreateDTO {
|
|||||||
/** 目的地点纬度 */
|
/** 目的地点纬度 */
|
||||||
private BigDecimal destLat;
|
private BigDecimal destLat;
|
||||||
|
|
||||||
/** 配送日期(yyyy-MM-dd 格式) */
|
/** 配送日期 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
private Date deliveryDate;
|
private Date deliveryDate;
|
||||||
|
|
||||||
/** 配送车辆车牌号 */
|
/** 车牌号 */
|
||||||
private String plateNo;
|
private String plateNo;
|
||||||
|
|
||||||
/** 发货人姓名 */
|
/** 发货人名称 */
|
||||||
private String shipperName;
|
private String shipperName;
|
||||||
|
|
||||||
/** 发货人联系电话 */
|
/** 发货人联系方式 */
|
||||||
private String shipperPhone;
|
private String shipperPhone;
|
||||||
|
|
||||||
/** 收货人姓名 */
|
/** 接收人名称 */
|
||||||
private String receiverName;
|
private String receiverName;
|
||||||
|
|
||||||
/** 收货人联系电话 */
|
/** 接收人联系方式 */
|
||||||
private String receiverPhone;
|
private String receiverPhone;
|
||||||
|
|
||||||
/** 收货单位名称 */
|
/** 接收单位 */
|
||||||
private String receiverOrgName;
|
private String receiverOrgName;
|
||||||
|
|
||||||
/** 配送吨位(单位:吨) */
|
/** 配送吨位 */
|
||||||
private BigDecimal deliveryTon;
|
private BigDecimal deliveryTon;
|
||||||
|
|
||||||
/** 货物体积(单位:立方米) */
|
/** 货物尺寸 */
|
||||||
private BigDecimal goodsSize;
|
private BigDecimal goodsSize;
|
||||||
|
|
||||||
/** 单据状态(默认 0:待发货,1:起运,2:送达) */
|
/**
|
||||||
|
* 接收物资状态:
|
||||||
|
* 1:数量齐全、状态完好(默认)
|
||||||
|
* 2:存在问题
|
||||||
|
*/
|
||||||
|
private Integer receiveStatus; // *** 修改:String -> Integer ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收物资问题描述(receiveStatus = 2 时必填)
|
||||||
|
*/
|
||||||
|
private String receiveProblem;
|
||||||
|
|
||||||
|
/** 制单人ID(前端可传;如果为空则后台自动取当前登录用户ID) */
|
||||||
|
private Long makerId;
|
||||||
|
|
||||||
|
/** 配送状态(默认:1 已接单 / 后续会调整) */
|
||||||
private String orderStatus;
|
private String orderStatus;
|
||||||
|
|
||||||
/** 车辆类型ID(外键,对应 vehicle_type 表主键) */
|
/** 车型 ID */
|
||||||
private Long vehicleTypeId;
|
private Long vehicleTypeId;
|
||||||
|
|
||||||
/** 车辆类型名称(如:小型面包车、9.6米货车等) */
|
/** 车型名称 */
|
||||||
private String vehicleTypeName;
|
private String vehicleTypeName;
|
||||||
|
|
||||||
/** 系统建议运费(根据车型和里程计算) */
|
/** 建议费用 */
|
||||||
private BigDecimal suggestFee;
|
private BigDecimal suggestFee;
|
||||||
|
|
||||||
/** 实际运费(人工调整或司机确认后) */
|
/** 实际费用 */
|
||||||
private BigDecimal actualFee;
|
private BigDecimal actualFee;
|
||||||
|
|
||||||
/** 过路费(收费站、高速费等额外费用) */
|
/** 高速费用 */
|
||||||
private BigDecimal tollFee;
|
private BigDecimal tollFee;
|
||||||
|
|
||||||
/** 配送总里程(单位:公里) */
|
/** 总公里数 */
|
||||||
private BigDecimal totalKm;
|
private BigDecimal totalKm;
|
||||||
|
|
||||||
/** 备注说明(可填写其他补充信息) */
|
/** 备注 */
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
// ==================== 行明细(多物料行) ====================
|
// ==================== 行明细(多物料行) ====================
|
||||||
|
|||||||
@@ -6,13 +6,38 @@ import java.math.BigDecimal;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class DeliveryOrderLineDTO {
|
public class DeliveryOrderLineDTO {
|
||||||
private String billNoCk; // 出库单据号
|
|
||||||
private String xmMs; // 项目描述
|
/**
|
||||||
private String xmNo; // 项目号
|
* 对应智慧实物系统 rk_info 表的主键 ID
|
||||||
private String wlNo; // 物料号
|
* detailList 里的 id 就是这个值
|
||||||
private String wlMs; // 物料描述
|
*/
|
||||||
private BigDecimal realQty; // 实际入库数量
|
private Long rkInfoId;
|
||||||
private String dw; // 计量单位
|
|
||||||
private String sapNo; // SAP订单编号
|
/** 出库单据号 */
|
||||||
private String gysMc; // 供应商名称
|
private String billNoCk;
|
||||||
|
|
||||||
|
/** 项目描述 */
|
||||||
|
private String xmMs;
|
||||||
|
|
||||||
|
/** 项目号 */
|
||||||
|
private String xmNo;
|
||||||
|
|
||||||
|
/** 物料号 */
|
||||||
|
private String wlNo;
|
||||||
|
|
||||||
|
/** 物料描述 */
|
||||||
|
private String wlMs;
|
||||||
|
|
||||||
|
/** 实际数量 */
|
||||||
|
private BigDecimal realQty;
|
||||||
|
|
||||||
|
/** 计量单位 */
|
||||||
|
private String dw;
|
||||||
|
|
||||||
|
/** SAP订单编号 */
|
||||||
|
private String sapNo;
|
||||||
|
|
||||||
|
/** 供应商名称 */
|
||||||
|
private String gysMc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ public class CalcSuggestFeeVO {
|
|||||||
/** 建议费用(单位:元,四舍五入保留2位小数) */
|
/** 建议费用(单位:元,四舍五入保留2位小数) */
|
||||||
private BigDecimal suggestFee;
|
private BigDecimal suggestFee;
|
||||||
|
|
||||||
|
/** 错误信息 */
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
/** 是否有适配车型 */
|
||||||
|
private Boolean hasSuitableType;
|
||||||
|
|
||||||
/** 候选车型列表(按价格/容量排序) */
|
/** 候选车型列表(按价格/容量排序) */
|
||||||
private List<VehicleTypeOptionVO> candidates;
|
private List<VehicleTypeOptionVO> candidates;
|
||||||
|
|
||||||
@@ -51,7 +57,7 @@ public class CalcSuggestFeeVO {
|
|||||||
/** 载方下限(单位:立方米,含) */
|
/** 载方下限(单位:立方米,含) */
|
||||||
private BigDecimal volumeMinM3;
|
private BigDecimal volumeMinM3;
|
||||||
|
|
||||||
/** 载方上限(单位:立方米,含) */
|
/** 载方上限(单位:吨,含) */
|
||||||
private BigDecimal volumeMaxM3;
|
private BigDecimal volumeMaxM3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.delivery.project.document.domain.vo;
|
||||||
|
|
||||||
|
import com.delivery.project.document.domain.DeliveryOrder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配送单据详情 VO(带图片)
|
||||||
|
* 继承 DeliveryOrder,只做返回展示使用,不参与持久化映射。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeliveryOrderDetailVO extends DeliveryOrder {
|
||||||
|
|
||||||
|
/** 当前登录用户ID(只做前端展示用) */
|
||||||
|
private Long makerId;
|
||||||
|
|
||||||
|
/** 当前登录用户名(只做前端展示用) */
|
||||||
|
private String makerUserName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.delivery.project.document.domain.DeliveryOrder;
|
|||||||
import com.delivery.project.document.domain.dto.DeliveryOrderCreateDTO;
|
import com.delivery.project.document.domain.dto.DeliveryOrderCreateDTO;
|
||||||
import com.delivery.project.document.domain.dto.DeliveryOrderSaveDTO;
|
import com.delivery.project.document.domain.dto.DeliveryOrderSaveDTO;
|
||||||
import com.delivery.project.document.domain.vo.DeliveryBillVO;
|
import com.delivery.project.document.domain.vo.DeliveryBillVO;
|
||||||
|
import com.delivery.project.document.domain.vo.DeliveryOrderDetailVO;
|
||||||
import com.delivery.project.document.domain.vo.DeliveryOrderGroupVO;
|
import com.delivery.project.document.domain.vo.DeliveryOrderGroupVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +93,7 @@ public interface IDeliveryOrderService
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
/** 详情:按单号查行 */
|
/** 详情:按单号查行 */
|
||||||
List<DeliveryOrder> listByOrderNo(String orderNo);
|
List<DeliveryOrderDetailVO> listByOrderNo(String orderNo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public interface IVehicleTypeService
|
|||||||
public int deleteVehicleTypeById(Long id);
|
public int deleteVehicleTypeById(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算建议运费
|
* 计算建议运费,推荐车型
|
||||||
* @param dto
|
* @param dto
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.nio.file.Paths;
|
|||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.delivery.common.exception.ServiceException;
|
import com.delivery.common.exception.ServiceException;
|
||||||
@@ -139,25 +140,32 @@ public class DeliveryAttachmentServiceImpl implements IDeliveryAttachmentService
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int executeBind(DeliveryExecuteBindDTO dto) {
|
public int executeBind(DeliveryExecuteBindDTO dto) {
|
||||||
// 1) 校验订单存在
|
// 1) 校验订单存在(一个单号多行)
|
||||||
List<DeliveryOrder> existList = deliveryOrderMapper.selectDeliveryOrderByOrderNo(dto.getOrderNo());
|
List<DeliveryOrder> existList = deliveryOrderMapper.selectDeliveryOrderByOrderNo(dto.getOrderNo());
|
||||||
if (existList == null || existList.isEmpty()) {
|
if (existList == null || existList.isEmpty()) {
|
||||||
throw new ServiceException("配送单不存在:" + dto.getOrderNo());
|
throw new ServiceException("配送单不存在:" + dto.getOrderNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
String billNoCk = existList.get(0).getBillNoCk();
|
// ====== 从配送单中拿到所有 rk_info_id 列表 ======
|
||||||
|
List<Long> rkInfoIdList = existList.stream()
|
||||||
|
.map(DeliveryOrder::getRkInfoId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (StringUtils.isBlank(billNoCk)) {
|
if (rkInfoIdList.isEmpty()) {
|
||||||
throw new ServiceException("配送单未绑定出库单号,无法回写库存状态!");
|
throw new ServiceException("配送单未绑定 rk_info_id,无法回写库存状态!");
|
||||||
}
|
}
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
if (dto.getAttachments() == null || dto.getAttachments().isEmpty()) {
|
if (dto.getAttachments() == null || dto.getAttachments().isEmpty()) {
|
||||||
throw new ServiceException("附件列表不能为空");
|
throw new ServiceException("附件列表不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) 批量插入附件(只传 URL)
|
// 2) 批量插入附件(只传 URL)
|
||||||
List<DeliveryAttachment> list = new ArrayList<>();
|
List<DeliveryAttachment> list = new ArrayList<>();
|
||||||
String username = getUsername();
|
|
||||||
// String username = "大爷的!!!";
|
String username = getUsername();
|
||||||
for (DeliveryAttachItemDTO it : dto.getAttachments()) {
|
for (DeliveryAttachItemDTO it : dto.getAttachments()) {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -215,24 +223,36 @@ public class DeliveryAttachmentServiceImpl implements IDeliveryAttachmentService
|
|||||||
patch.setTollFee(dto.getTollFee());
|
patch.setTollFee(dto.getTollFee());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Integer receiveStatus = dto.getReceiveStatus();
|
||||||
|
if (receiveStatus == null) {
|
||||||
|
throw new ServiceException("完成配送时必须选择接收物资状态");
|
||||||
|
}
|
||||||
|
if (receiveStatus != 0 && receiveStatus != 1 && receiveStatus != 2) {
|
||||||
|
throw new ServiceException("接收物资状态不合法");
|
||||||
|
}
|
||||||
|
patch.setReceiveStatus(receiveStatus);
|
||||||
|
|
||||||
|
if (receiveStatus == 2) {
|
||||||
|
// 有问题必须写说明
|
||||||
|
if (StringUtils.isBlank(dto.getReceiveProblem())) {
|
||||||
|
throw new ServiceException("存在问题时必须填写问题描述");
|
||||||
|
}
|
||||||
|
patch.setReceiveProblem(dto.getReceiveProblem());
|
||||||
|
}
|
||||||
|
|
||||||
patch.setOrderStatus("3"); // 已完成
|
patch.setOrderStatus("3"); // 已完成
|
||||||
}
|
}
|
||||||
|
|
||||||
deliveryOrderMapper.updateDeliveryOrder(patch);
|
deliveryOrderMapper.updateDeliveryOrder(patch);
|
||||||
|
|
||||||
// 4) ⭐ 如果是 DEST 场景,远程调用 WMS,把 rk_info.is_delivery 改成 3
|
// 4) ⭐ 如果是 DEST 场景,远程调用 WMS,把这些 rk_info 记录的 is_delivery 改成 3
|
||||||
if ("DEST".equals(scene)) {
|
if ("DEST".equals(scene)) {
|
||||||
|
|
||||||
if (StringUtils.isBlank(billNoCk)) {
|
// 这里已经不再按 billNoCk 整单更新,而是按 rk_info_id 列表更新
|
||||||
throw new ServiceException("配送单缺少对应的出库单号 billNoCk,无法回写库存状态!");
|
boolean ok = updateWmsIsDeliveryByIds(rkInfoIdList, 3);
|
||||||
}
|
|
||||||
|
|
||||||
// rkInfoMapper.updateDeliveryStatus(billNoCk, 3);
|
|
||||||
|
|
||||||
boolean ok = updateWmsIsDelivery(billNoCk, 3);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// 让整个事务回滚,附件 + 配送单状态都撤回
|
// 让整个事务回滚,附件 + 配送单状态都撤回
|
||||||
throw new ServiceException("回写 WMS 配送状态失败,出库单号:" + billNoCk);
|
throw new ServiceException("回写 WMS 配送状态失败,rk_info_id 列表:" + rkInfoIdList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,24 +260,28 @@ public class DeliveryAttachmentServiceImpl implements IDeliveryAttachmentService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 远程调用智慧实物管理系统,更新 rk_info.is_delivery 状态
|
* 远程调用智慧实物管理系统,按 rk_info 主键ID列表更新 is_delivery 状态
|
||||||
|
* 约定请求体结构:
|
||||||
|
* {
|
||||||
|
* "rkInfoIdList": [1, 2, 3],
|
||||||
|
* "isDelivery": 3
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
private boolean updateWmsIsDelivery(String billNoCk, int isDelivery) {
|
private boolean updateWmsIsDeliveryByIds(List<Long> rkInfoIdList, int isDelivery) {
|
||||||
|
|
||||||
String url = wisdomBaseUrl + "/wisdom/stock/updateDeliveryStatus";
|
String url = wisdomBaseUrl + "/wisdom/stock/updateDeliveryStatus";
|
||||||
|
|
||||||
Map<String, Object> body = new HashMap<>();
|
Map<String, Object> body = new HashMap<>();
|
||||||
body.put("billNoCk", billNoCk);
|
body.put("ids", rkInfoIdList);
|
||||||
body.put("isDelivery", isDelivery);
|
body.put("isDelivery", isDelivery);
|
||||||
|
|
||||||
String json = JSON.toJSONString(body);
|
String json = JSON.toJSONString(body);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 用你项目里的 HttpUtils 发 JSON POST
|
|
||||||
String resp = HttpUtils.sendPost(url, json, MediaType.APPLICATION_JSON_VALUE);
|
String resp = HttpUtils.sendPost(url, json, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
|
||||||
if (StringUtils.isBlank(resp)) {
|
if (StringUtils.isBlank(resp)) {
|
||||||
log.error("WMS 更新失败,响应为空,url={} billNoCk={}", url, billNoCk);
|
log.error("WMS 更新失败,响应为空,url={} rkInfoIdList={}", url, rkInfoIdList);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,16 +293,17 @@ public class DeliveryAttachmentServiceImpl implements IDeliveryAttachmentService
|
|||||||
String msg = (result == null)
|
String msg = (result == null)
|
||||||
? "响应为空"
|
? "响应为空"
|
||||||
: String.valueOf(result.get(AjaxResult.MSG_TAG));
|
: String.valueOf(result.get(AjaxResult.MSG_TAG));
|
||||||
log.error("WMS 更新失败,billNoCk={},原因={}", billNoCk, msg);
|
log.error("WMS 更新失败,rkInfoIdList={},原因={}", rkInfoIdList, msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("调用 WMS 接口异常,billNoCk={},error={}", billNoCk, e.getMessage(), e);
|
log.error("调用 WMS 接口异常,rkInfoIdList={},error={}", rkInfoIdList, e.getMessage(), e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 保存目录 D:\delivery
|
// 保存目录 D:\delivery
|
||||||
private static final String BASE_PATH = "D:/delivery";
|
private static final String BASE_PATH = "D:/delivery";
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.delivery.project.document.domain.dto.DeliveryOrderCreateDTO;
|
|||||||
import com.delivery.project.document.domain.dto.DeliveryOrderLineDTO;
|
import com.delivery.project.document.domain.dto.DeliveryOrderLineDTO;
|
||||||
import com.delivery.project.document.domain.dto.DeliveryOrderSaveDTO;
|
import com.delivery.project.document.domain.dto.DeliveryOrderSaveDTO;
|
||||||
import com.delivery.project.document.domain.vo.DeliveryBillVO;
|
import com.delivery.project.document.domain.vo.DeliveryBillVO;
|
||||||
|
import com.delivery.project.document.domain.vo.DeliveryOrderDetailVO;
|
||||||
import com.delivery.project.document.domain.vo.DeliveryOrderGroupVO;
|
import com.delivery.project.document.domain.vo.DeliveryOrderGroupVO;
|
||||||
import com.delivery.project.document.mapper.DeliveryAttachmentMapper;
|
import com.delivery.project.document.mapper.DeliveryAttachmentMapper;
|
||||||
import com.delivery.project.document.mapper.MtdMapper;
|
import com.delivery.project.document.mapper.MtdMapper;
|
||||||
@@ -51,8 +52,6 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DeliveryAttachmentMapper deliveryAttachmentMapper;
|
private DeliveryAttachmentMapper deliveryAttachmentMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RkInfoMapper rkInfoMapper;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MtdMapper mtdMapper;
|
private MtdMapper mtdMapper;
|
||||||
@@ -185,34 +184,67 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
public String createOrder(DeliveryOrderCreateDTO dto) {
|
public String createOrder(DeliveryOrderCreateDTO dto) {
|
||||||
|
|
||||||
// ========== 0. 参数校验 ==========
|
// ========== 0. 参数校验 ==========
|
||||||
|
|
||||||
if (dto == null || dto.getItems() == null || dto.getItems().isEmpty()) {
|
if (dto == null || dto.getItems() == null || dto.getItems().isEmpty()) {
|
||||||
throw new ServiceException("物料明细不能为空");
|
throw new ServiceException("物料明细不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有明细应是同一出库单据号,这里简单从第一条取出
|
// 取第一条,仍然要求同一出库单据号(暂不支持多出库单合并)
|
||||||
String billNoCk = dto.getItems().get(0).getBillNoCk();
|
String billNoCk = dto.getItems().get(0).getBillNoCk();
|
||||||
if (billNoCk == null || billNoCk.trim().isEmpty()) {
|
if (StringUtils.isBlank(billNoCk)) {
|
||||||
throw new ServiceException("明细行缺少出库单据号 billNoCk");
|
throw new ServiceException("明细行缺少出库单据号 billNoCk");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 收集 rk_info 主键 id(用于回写 WMS)
|
||||||
|
List<Long> rkInfoIds = dto.getItems().stream()
|
||||||
|
.map(DeliveryOrderLineDTO::getRkInfoId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (rkInfoIds.isEmpty()) {
|
||||||
|
throw new ServiceException("明细行缺少 rk_info 主键 id,无法回写配送状态");
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 1. 生成配送单号 ==========
|
// ========== 1. 生成配送单号 ==========
|
||||||
String orderNo = (dto.getOrderNo() == null || dto.getOrderNo().trim().isEmpty())
|
|
||||||
|
String orderNo = StringUtils.isBlank(dto.getOrderNo())
|
||||||
? "DO" + DateUtils.dateTimeNow("yyyyMMddHHmmssSSS")
|
? "DO" + DateUtils.dateTimeNow("yyyyMMddHHmmssSSS")
|
||||||
: dto.getOrderNo().trim();
|
: dto.getOrderNo().trim();
|
||||||
|
|
||||||
Date now = DateUtils.getNowDate();
|
Date now = DateUtils.getNowDate();
|
||||||
String username = SecurityUtils.getUsername();
|
String username = SecurityUtils.getUsername();
|
||||||
|
Long currentUserId = null;
|
||||||
|
try {
|
||||||
|
currentUserId = SecurityUtils.getUserId();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取当前登录用户ID失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 制单人用户ID:优先用前端传的 makerId,没有则回退到当前登录用户
|
||||||
|
Long makerId = dto.getMakerId();
|
||||||
|
if (makerId == null) {
|
||||||
|
if (currentUserId == null) {
|
||||||
|
throw new ServiceException("无法确定制单人用户ID,请重新登录后重试");
|
||||||
|
}
|
||||||
|
makerId = currentUserId;
|
||||||
|
}
|
||||||
|
|
||||||
List<DeliveryOrder> rows = new ArrayList<>();
|
List<DeliveryOrder> rows = new ArrayList<>();
|
||||||
|
|
||||||
// ========== 2. 遍历每一条物料明细 ==========
|
// ========== 2. 遍历每一条物料明细,组装行记录 ==========
|
||||||
|
|
||||||
for (DeliveryOrderLineDTO it : dto.getItems()) {
|
for (DeliveryOrderLineDTO it : dto.getItems()) {
|
||||||
|
|
||||||
// 这里如果允许多个出库单合并配送,可以去掉这个校验
|
// 仍然限制同一出库单(你后续要支持多出库单再放开)
|
||||||
if (!billNoCk.equals(it.getBillNoCk())) {
|
if (!billNoCk.equals(it.getBillNoCk())) {
|
||||||
throw new ServiceException("当前接口暂不支持多张出库单合并配送,请确保所有明细 billNoCk 相同");
|
throw new ServiceException("当前接口暂不支持多张出库单合并配送,请确保所有明细 billNoCk 相同");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (it.getRkInfoId() == null) {
|
||||||
|
throw new ServiceException("明细行缺少 rk_info 主键 id");
|
||||||
|
}
|
||||||
|
|
||||||
DeliveryOrder row = new DeliveryOrder();
|
DeliveryOrder row = new DeliveryOrder();
|
||||||
|
|
||||||
// 2.1 公共头部字段(整单一致)
|
// 2.1 公共头部字段(整单一致)
|
||||||
@@ -225,6 +257,7 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
row.setDestLat(dto.getDestLat());
|
row.setDestLat(dto.getDestLat());
|
||||||
row.setDeliveryDate(dto.getDeliveryDate());
|
row.setDeliveryDate(dto.getDeliveryDate());
|
||||||
row.setPlateNo(dto.getPlateNo());
|
row.setPlateNo(dto.getPlateNo());
|
||||||
|
|
||||||
row.setShipperName(dto.getShipperName());
|
row.setShipperName(dto.getShipperName());
|
||||||
row.setShipperPhone(dto.getShipperPhone());
|
row.setShipperPhone(dto.getShipperPhone());
|
||||||
row.setReceiverName(dto.getReceiverName());
|
row.setReceiverName(dto.getReceiverName());
|
||||||
@@ -232,9 +265,15 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
row.setReceiverOrgName(dto.getReceiverOrgName());
|
row.setReceiverOrgName(dto.getReceiverOrgName());
|
||||||
row.setDeliveryTon(dto.getDeliveryTon());
|
row.setDeliveryTon(dto.getDeliveryTon());
|
||||||
row.setGoodsSize(dto.getGoodsSize());
|
row.setGoodsSize(dto.getGoodsSize());
|
||||||
row.setOrderStatus(
|
|
||||||
StringUtils.isBlank(dto.getOrderStatus()) ? "1" : dto.getOrderStatus().trim()
|
// 制单人用户ID
|
||||||
);
|
row.setMakerId(makerId);
|
||||||
|
|
||||||
|
// 配送状态:前端不传时默认 1(已接单 / 待起运)
|
||||||
|
String orderStatus = StringUtils.isBlank(dto.getOrderStatus())
|
||||||
|
? "1" : dto.getOrderStatus().trim();
|
||||||
|
row.setOrderStatus(orderStatus);
|
||||||
|
|
||||||
row.setVehicleTypeId(dto.getVehicleTypeId());
|
row.setVehicleTypeId(dto.getVehicleTypeId());
|
||||||
row.setVehicleTypeName(dto.getVehicleTypeName());
|
row.setVehicleTypeName(dto.getVehicleTypeName());
|
||||||
row.setSuggestFee(dto.getSuggestFee());
|
row.setSuggestFee(dto.getSuggestFee());
|
||||||
@@ -244,6 +283,7 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
row.setRemark(dto.getRemark());
|
row.setRemark(dto.getRemark());
|
||||||
|
|
||||||
// 2.2 明细字段
|
// 2.2 明细字段
|
||||||
|
row.setRkInfoId(it.getRkInfoId()); // 关联 rk_info 主键ID
|
||||||
row.setBillNoCk(it.getBillNoCk());
|
row.setBillNoCk(it.getBillNoCk());
|
||||||
row.setXmMs(it.getXmMs());
|
row.setXmMs(it.getXmMs());
|
||||||
row.setXmNo(it.getXmNo());
|
row.setXmNo(it.getXmNo());
|
||||||
@@ -263,17 +303,16 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ========== 3. 批量落库 ==========
|
// ========== 3. 批量落库 ==========
|
||||||
|
|
||||||
if (!rows.isEmpty()) {
|
if (!rows.isEmpty()) {
|
||||||
deliveryOrderMapper.batchInsert(rows);
|
deliveryOrderMapper.batchInsert(rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rkInfoMapper.updateDeliveryStatus(billNoCk, 2);
|
// ========== 4. 回写 WMS:按 rk_info.id 更新 is_delivery = 2(配送中) ==========
|
||||||
|
|
||||||
// ========== 4. 回写 WMS:rk_info.is_delivery = 2(配送中) ==========
|
boolean ok = updateWmsIsDeliveryByIds(rkInfoIds, 2);
|
||||||
// 按出库单据号整单回写
|
|
||||||
boolean ok = updateWmsIsDelivery(billNoCk, 2);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// 这里直接抛异常,让当前事务回滚,避免出现“配送单已生成,WMS 状态没改”的脏数据
|
// 回写失败,整单回滚,避免脏数据
|
||||||
throw new ServiceException("已生成配送单,但回写 WMS 配送状态失败");
|
throw new ServiceException("已生成配送单,但回写 WMS 配送状态失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,34 +320,29 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 远程调用 WMS,按出库单据号修改 rk_info.is_delivery 状态
|
* 远程调用 WMS,按 rk_info 主键 ID 列表修改 is_delivery 状态
|
||||||
*
|
*
|
||||||
* 请求方式示例:
|
* 请求方式示例:
|
||||||
* POST ${delivery.wms-base-url}/delivery/rkInfo/updateDeliveryStatus
|
* POST ${delivery.wisdom-base-url}/wisdom/stock/updateDeliveryStatus
|
||||||
* Body: { "billNoCk": "CK202511200001", "isDelivery": 2 }
|
* Body: { "ids": [1, 2, 3], "isDelivery": 2 }
|
||||||
*/
|
*/
|
||||||
private boolean updateWmsIsDelivery(String billNoCk, int isDelivery) {
|
private boolean updateWmsIsDeliveryByIds(List<Long> rkInfoIds, int isDelivery) {
|
||||||
|
|
||||||
String url = wisdomBaseUrl + "/wisdom/stock/updateDeliveryStatus";
|
String url = wisdomBaseUrl + "/wisdom/stock/updateDeliveryStatus";
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("billNoCk", billNoCk);
|
map.put("ids", rkInfoIds);
|
||||||
map.put("isDelivery", isDelivery);
|
map.put("isDelivery", isDelivery);
|
||||||
|
|
||||||
String json = JSON.toJSONString(map);
|
String json = JSON.toJSONString(map);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 发送 JSON POST(你刚加的 sendJsonPost)
|
|
||||||
String resp = HttpUtils.sendJsonPost(url, json);
|
String resp = HttpUtils.sendJsonPost(url, json);
|
||||||
|
|
||||||
// 解析为 AjaxResult
|
|
||||||
AjaxResult result = JSON.parseObject(resp, AjaxResult.class);
|
AjaxResult result = JSON.parseObject(resp, AjaxResult.class);
|
||||||
|
|
||||||
if (result != null && result.isSuccess()) {
|
if (result != null && result.isSuccess()) {
|
||||||
// code == 200
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// 取 msg:从 Map 里按 key 取
|
|
||||||
String msg = (result != null)
|
String msg = (result != null)
|
||||||
? String.valueOf(result.get(AjaxResult.MSG_TAG))
|
? String.valueOf(result.get(AjaxResult.MSG_TAG))
|
||||||
: "响应为空";
|
: "响应为空";
|
||||||
@@ -317,7 +351,7 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("WMS 调用异常 billNoCk={} error={}", billNoCk, e.getMessage(), e);
|
log.error("WMS 调用异常 rkInfoIds={} error={}", rkInfoIds, e.getMessage(), e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,8 +363,24 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DeliveryOrder> listByOrderNo(String orderNo) {
|
public List<DeliveryOrderDetailVO> listByOrderNo(String orderNo) {
|
||||||
return deliveryOrderMapper.selectByOrderNo(orderNo);
|
|
||||||
|
// 1. 直接查出带附件、带 makerUserName 的明细列表
|
||||||
|
// 使用的是 resultMap="DeliveryOrderWithAttachResult"
|
||||||
|
List<DeliveryOrder> list = deliveryOrderMapper.selectByOrderNo(orderNo);
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 转成 VO 列表(继承自 DeliveryOrder,自动带上 makerId / makerUserName / attachments 等所有字段)
|
||||||
|
List<DeliveryOrderDetailVO> result = new ArrayList<>(list.size());
|
||||||
|
for (DeliveryOrder o : list) {
|
||||||
|
DeliveryOrderDetailVO vo = new DeliveryOrderDetailVO();
|
||||||
|
BeanUtils.copyProperties(o, vo);
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -419,7 +469,6 @@ public class DeliveryOrderServiceImpl implements IDeliveryOrderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,37 @@ public class MtdServiceImpl implements IMtdService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TotalWvVO calcTotalWv(CalcTotalWvDTO dto) {
|
public TotalWvVO calcTotalWv(CalcTotalWvDTO dto) {
|
||||||
if (dto == null || dto.getWlNos() == null || dto.getWlNos().isEmpty()) {
|
if (dto == null) {
|
||||||
|
TotalWvVO empty = new TotalWvVO();
|
||||||
|
empty.setTotalWeightKg(BigDecimal.ZERO);
|
||||||
|
empty.setTotalVolumeM3(BigDecimal.ZERO);
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用wlNos和items列表来统计物料
|
||||||
|
Map<String, BigDecimal> wlNoQtyMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// 如果提供了items列表,优先使用items(包含具体数量)
|
||||||
|
if (dto.getItems() != null && !dto.getItems().isEmpty()) {
|
||||||
|
for (CalcTotalWvDTO.Item item : dto.getItems()) {
|
||||||
|
if (item.getWlNo() != null && !item.getWlNo().trim().isEmpty()) {
|
||||||
|
BigDecimal qty = item.getQty();
|
||||||
|
if (qty == null || qty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
qty = BigDecimal.ONE; // 默认为1
|
||||||
|
}
|
||||||
|
wlNoQtyMap.put(item.getWlNo(), wlNoQtyMap.getOrDefault(item.getWlNo(), BigDecimal.ZERO).add(qty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (dto.getWlNos() != null && !dto.getWlNos().isEmpty()) {
|
||||||
|
// 如果只有wlNos列表,则每个物料号计数为1
|
||||||
|
for (String wlNo : dto.getWlNos()) {
|
||||||
|
if (wlNo != null && !wlNo.trim().isEmpty()) {
|
||||||
|
wlNoQtyMap.put(wlNo, wlNoQtyMap.getOrDefault(wlNo, BigDecimal.ZERO).add(BigDecimal.ONE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlNoQtyMap.isEmpty()) {
|
||||||
TotalWvVO empty = new TotalWvVO();
|
TotalWvVO empty = new TotalWvVO();
|
||||||
empty.setTotalWeightKg(BigDecimal.ZERO);
|
empty.setTotalWeightKg(BigDecimal.ZERO);
|
||||||
empty.setTotalVolumeM3(BigDecimal.ZERO);
|
empty.setTotalVolumeM3(BigDecimal.ZERO);
|
||||||
@@ -151,17 +181,20 @@ public class MtdServiceImpl implements IMtdService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询数据库中所有匹配的物料信息
|
// 查询数据库中所有匹配的物料信息
|
||||||
List<Mtd> list = mtdMapper.selectByWlNos(dto.getWlNos());
|
List<Mtd> list = mtdMapper.selectByWlNos(new ArrayList<>(wlNoQtyMap.keySet()));
|
||||||
|
|
||||||
BigDecimal totalWeight = BigDecimal.ZERO;
|
BigDecimal totalWeight = BigDecimal.ZERO;
|
||||||
BigDecimal totalVolume = BigDecimal.ZERO;
|
BigDecimal totalVolume = BigDecimal.ZERO;
|
||||||
|
|
||||||
for (Mtd m : list) {
|
for (Mtd m : list) {
|
||||||
BigDecimal w = m.getWeightKg() == null ? BigDecimal.ZERO : m.getWeightKg();
|
if (m.getWlNo() != null && wlNoQtyMap.containsKey(m.getWlNo())) {
|
||||||
BigDecimal v = m.getVolumeM3() == null ? BigDecimal.ZERO : m.getVolumeM3();
|
BigDecimal qty = wlNoQtyMap.get(m.getWlNo());
|
||||||
|
BigDecimal w = m.getWeightKg() == null ? BigDecimal.ZERO : m.getWeightKg();
|
||||||
|
BigDecimal v = m.getVolumeM3() == null ? BigDecimal.ZERO : m.getVolumeM3();
|
||||||
|
|
||||||
totalWeight = totalWeight.add(w);
|
totalWeight = totalWeight.add(w.multiply(qty));
|
||||||
totalVolume = totalVolume.add(v);
|
totalVolume = totalVolume.add(v.multiply(qty));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalWvVO vo = new TotalWvVO();
|
TotalWvVO vo = new TotalWvVO();
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ public class VehicleTypeServiceImpl implements IVehicleTypeService
|
|||||||
return vehicleTypeMapper.deleteVehicleTypeById(id);
|
return vehicleTypeMapper.deleteVehicleTypeById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算建议运费,推荐车型
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CalcSuggestFeeVO calcSuggestFee(CalcSuggestFeeDTO dto)
|
public CalcSuggestFeeVO calcSuggestFee(CalcSuggestFeeDTO dto)
|
||||||
{
|
{
|
||||||
@@ -113,8 +118,55 @@ public class VehicleTypeServiceImpl implements IVehicleTypeService
|
|||||||
if (candidates == null || candidates.isEmpty()) {
|
if (candidates == null || candidates.isEmpty()) {
|
||||||
candidates = vehicleTypeMapper.selectFallbackTypes(w, v);
|
candidates = vehicleTypeMapper.selectFallbackTypes(w, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 2) 检查是否存在适配车型 ==========
|
||||||
if (candidates == null || candidates.isEmpty()) {
|
if (candidates == null || candidates.isEmpty()) {
|
||||||
throw new RuntimeException("未找到适配车型,请检查车型配置或输入参数。");
|
// 如果没有适配车型,检查系统中是否至少存在一个车型配置
|
||||||
|
List<VehicleType> allVehicleTypes = vehicleTypeMapper.selectVehicleTypeList(new VehicleType());
|
||||||
|
if (allVehicleTypes == null || allVehicleTypes.isEmpty()) {
|
||||||
|
CalcSuggestFeeVO vo = new CalcSuggestFeeVO();
|
||||||
|
vo.setErrorMessage("系统中暂无车型配置,请先配置车型信息。");
|
||||||
|
vo.setHasSuitableType(false);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到最大承载能力的车型
|
||||||
|
VehicleType maxCapacityType = allVehicleTypes.stream()
|
||||||
|
.filter(type -> "0".equals(type.getStatus()) && !"1".equals(type.getIsDelete()))
|
||||||
|
.max(Comparator
|
||||||
|
.comparing(VehicleType::getWeightMaxTon, Comparator.nullsLast(BigDecimal::compareTo))
|
||||||
|
.thenComparing(VehicleType::getVolumeMaxM3, Comparator.nullsLast(BigDecimal::compareTo)))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (maxCapacityType != null) {
|
||||||
|
// 检查最大容量车型是否仍无法满足要求
|
||||||
|
String errorMsg = buildNoMatchErrorMessage(w, v, maxCapacityType);
|
||||||
|
CalcSuggestFeeVO vo = new CalcSuggestFeeVO();
|
||||||
|
vo.setErrorMessage(errorMsg);
|
||||||
|
vo.setHasSuitableType(false);
|
||||||
|
// 仍然返回候选车型列表供参考
|
||||||
|
List<CalcSuggestFeeVO.VehicleTypeOptionVO> list = new ArrayList<>(allVehicleTypes.size());
|
||||||
|
for (VehicleType t : allVehicleTypes) {
|
||||||
|
if ("0".equals(t.getStatus()) && !"1".equals(t.getIsDelete())) {
|
||||||
|
CalcSuggestFeeVO.VehicleTypeOptionVO o = new CalcSuggestFeeVO.VehicleTypeOptionVO();
|
||||||
|
o.setId(t.getId());
|
||||||
|
o.setName(t.getTypeName());
|
||||||
|
o.setUnitPricePerKm(t.getUnitPricePerKm());
|
||||||
|
o.setWeightMinTon(t.getWeightMinTon());
|
||||||
|
o.setWeightMaxTon(t.getWeightMaxTon());
|
||||||
|
o.setVolumeMinM3(t.getVolumeMinM3());
|
||||||
|
o.setVolumeMaxM3(t.getVolumeMaxM3());
|
||||||
|
list.add(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vo.setCandidates(list);
|
||||||
|
return vo;
|
||||||
|
} else {
|
||||||
|
CalcSuggestFeeVO vo = new CalcSuggestFeeVO();
|
||||||
|
vo.setErrorMessage("未找到适配车型,请检查车型配置或输入参数。");
|
||||||
|
vo.setHasSuitableType(false);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 稳定排序:单价升序 -> 承重上限升序 -> 载方上限升序 -> id 升序(数据库已排序,这里再兜一层)
|
// 稳定排序:单价升序 -> 承重上限升序 -> 载方上限升序 -> id 升序(数据库已排序,这里再兜一层)
|
||||||
@@ -124,7 +176,7 @@ public class VehicleTypeServiceImpl implements IVehicleTypeService
|
|||||||
.thenComparing(VehicleType::getVolumeMaxM3, Comparator.nullsLast(BigDecimal::compareTo))
|
.thenComparing(VehicleType::getVolumeMaxM3, Comparator.nullsLast(BigDecimal::compareTo))
|
||||||
.thenComparing(VehicleType::getId, Comparator.nullsLast(Long::compareTo)));
|
.thenComparing(VehicleType::getId, Comparator.nullsLast(Long::compareTo)));
|
||||||
|
|
||||||
// ========== 2) 选定车型:前端指定 or 系统推荐 ==========
|
// ========== 3) 选定车型:前端指定 or 系统推荐 ==========
|
||||||
VehicleType chosen;
|
VehicleType chosen;
|
||||||
if (dto.getVehicleTypeId() != null) {
|
if (dto.getVehicleTypeId() != null) {
|
||||||
// 前端点名车型:优先在候选中找,找不到则直接按主键查
|
// 前端点名车型:优先在候选中找,找不到则直接按主键查
|
||||||
@@ -139,19 +191,20 @@ public class VehicleTypeServiceImpl implements IVehicleTypeService
|
|||||||
chosen = candidates.get(0);
|
chosen = candidates.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 3) 计算建议费用:单价 × 公里数,保留2位 ==========
|
// ========== 4) 计算建议费用:单价 × 公里数,保留2位 ==========
|
||||||
BigDecimal price = chosen.getUnitPricePerKm();
|
BigDecimal price = chosen.getUnitPricePerKm();
|
||||||
if (price == null) {
|
if (price == null) {
|
||||||
throw new RuntimeException("车型【" + chosen.getTypeName() + "】未配置每公里单价(unit_price_per_km 为空)");
|
throw new RuntimeException("车型【" + chosen.getTypeName() + "】未配置每公里单价(unit_price_per_km 为空)");
|
||||||
}
|
}
|
||||||
BigDecimal fee = price.multiply(km).setScale(2, RoundingMode.HALF_UP);
|
BigDecimal fee = price.multiply(km).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
// ========== 4) 组装返回 ==========
|
// ========== 5) 组装返回 ==========
|
||||||
CalcSuggestFeeVO vo = new CalcSuggestFeeVO();
|
CalcSuggestFeeVO vo = new CalcSuggestFeeVO();
|
||||||
vo.setVehicleTypeId(chosen.getId());
|
vo.setVehicleTypeId(chosen.getId());
|
||||||
vo.setVehicleTypeName(chosen.getTypeName());
|
vo.setVehicleTypeName(chosen.getTypeName());
|
||||||
vo.setUnitPricePerKm(price);
|
vo.setUnitPricePerKm(price);
|
||||||
vo.setSuggestFee(fee);
|
vo.setSuggestFee(fee);
|
||||||
|
vo.setHasSuitableType(true); // 有适配车型
|
||||||
|
|
||||||
// 候选项
|
// 候选项
|
||||||
List<CalcSuggestFeeVO.VehicleTypeOptionVO> list = new ArrayList<>(candidates.size());
|
List<CalcSuggestFeeVO.VehicleTypeOptionVO> list = new ArrayList<>(candidates.size());
|
||||||
@@ -170,6 +223,33 @@ public class VehicleTypeServiceImpl implements IVehicleTypeService
|
|||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建无匹配车型的错误信息
|
||||||
|
*/
|
||||||
|
private String buildNoMatchErrorMessage(BigDecimal weight, BigDecimal volume, VehicleType maxCapacityType) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("无适配车型,原因:");
|
||||||
|
|
||||||
|
boolean weightExceeds = weight.compareTo(maxCapacityType.getWeightMaxTon()) > 0;
|
||||||
|
boolean volumeExceeds = volume.compareTo(maxCapacityType.getVolumeMaxM3()) > 0;
|
||||||
|
|
||||||
|
if (weightExceeds && volumeExceeds) {
|
||||||
|
sb.append("货物重量(").append(weight).append("吨)超过最大承重(")
|
||||||
|
.append(maxCapacityType.getWeightMaxTon()).append("吨),且货物体积(")
|
||||||
|
.append(volume).append("立方米)超过最大载方(")
|
||||||
|
.append(maxCapacityType.getVolumeMaxM3()).append("立方米)。");
|
||||||
|
} else if (weightExceeds) {
|
||||||
|
sb.append("货物重量(").append(weight).append("吨)超过最大承重(")
|
||||||
|
.append(maxCapacityType.getWeightMaxTon()).append("吨)。");
|
||||||
|
} else if (volumeExceeds) {
|
||||||
|
sb.append("货物体积(").append(volume).append("立方米)超过最大载方(")
|
||||||
|
.append(maxCapacityType.getVolumeMaxM3()).append("立方米)。");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("最大承载车型为:").append(maxCapacityType.getTypeName());
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private static BigDecimal nvl(BigDecimal x) {
|
private static BigDecimal nvl(BigDecimal x) {
|
||||||
return x == null ? BigDecimal.ZERO : x;
|
return x == null ? BigDecimal.ZERO : x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.delivery.project.ocr.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "qwen")
|
||||||
|
public class QwenProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通义千问 API Key
|
||||||
|
*/
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenAI 兼容 base url,例如:
|
||||||
|
* https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||||
|
*/
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型名称,例如:qwen-vl-ocr-latest
|
||||||
|
*/
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiKey(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseUrl() {
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseUrl(String baseUrl) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.delivery.project.ocr.controller;
|
||||||
|
|
||||||
|
import com.delivery.project.ocr.service.QwenOcrService;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ocr")
|
||||||
|
public class OcrController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private QwenOcrService qwenOcrService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方式一:上传文件(本地测试)
|
||||||
|
*/
|
||||||
|
@PostMapping("/extractErp")
|
||||||
|
public Map<String, Object> extractErpOrder(@RequestParam("file") MultipartFile file) {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "上传文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String erpOrderNo = qwenOcrService.extractErpOrderNo(file);
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("found", StringUtils.hasText(erpOrderNo));
|
||||||
|
result.put("erpOrderNo", erpOrderNo);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方式二:智慧实物管理系统调用 —— 直接传 Base64 图片
|
||||||
|
*
|
||||||
|
* JSON 示例:
|
||||||
|
* {
|
||||||
|
* "imageBase64": "data:image/jpeg;base64,xxxxxx"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
@PostMapping("/extractErpByBase64")
|
||||||
|
public Map<String, Object> extractErpByBase64(@RequestBody OcrBase64Request request) {
|
||||||
|
if (request == null || !StringUtils.hasText(request.getImageBase64())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "imageBase64 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String erpOrderNo = qwenOcrService.extractErpOrderNoFromBase64(request.getImageBase64());
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("found", StringUtils.hasText(erpOrderNo));
|
||||||
|
result.put("erpOrderNo", erpOrderNo);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收 Base64 JSON 的 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class OcrBase64Request {
|
||||||
|
private String imageBase64; // 支持带前缀的 data:image/jpeg;base64,xxxx
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
package com.delivery.project.ocr.service;
|
||||||
|
|
||||||
|
import com.delivery.project.ocr.config.QwenProperties;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QwenOcrService {
|
||||||
|
|
||||||
|
private final QwenProperties qwenProperties;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// OkHttp 可复用并加超时
|
||||||
|
private final OkHttpClient httpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(25, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(25, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MultipartFile → OCR
|
||||||
|
*/
|
||||||
|
public String extractErpOrderNo(MultipartFile file) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = file.getBytes();
|
||||||
|
String fileName = file.getOriginalFilename();
|
||||||
|
String contentType = file.getContentType();
|
||||||
|
return doExtractErpOrderNo(bytes, fileName, contentType);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("读取上传图片失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 → OCR
|
||||||
|
* 支持含前缀:data:image/jpeg;base64,xxxx
|
||||||
|
* 也支持纯 Base64 字串
|
||||||
|
*/
|
||||||
|
public String extractErpOrderNoFromBase64(String base64Str) {
|
||||||
|
|
||||||
|
// 1. 去掉 data:image/jpeg;base64, 前缀
|
||||||
|
String cleanBase64 = base64Str;
|
||||||
|
String contentType = "image/jpeg";
|
||||||
|
|
||||||
|
if (base64Str.startsWith("data:")) {
|
||||||
|
int commaIndex = base64Str.indexOf(",");
|
||||||
|
String meta = base64Str.substring(5, commaIndex); // image/jpeg;base64
|
||||||
|
cleanBase64 = base64Str.substring(commaIndex + 1);
|
||||||
|
|
||||||
|
int semiIndex = meta.indexOf(";");
|
||||||
|
if (semiIndex > 0) {
|
||||||
|
contentType = meta.substring(0, semiIndex);
|
||||||
|
} else {
|
||||||
|
contentType = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bytes = Base64.getDecoder().decode(cleanBase64);
|
||||||
|
|
||||||
|
return doExtractErpOrderNo(bytes, "upload.jpg", contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心 OCR 调用逻辑
|
||||||
|
*/
|
||||||
|
private String doExtractErpOrderNo(byte[] bytes, String fileName, String contentType) {
|
||||||
|
try {
|
||||||
|
if (contentType == null || contentType.isEmpty()) {
|
||||||
|
contentType = "image/jpeg";
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytes → base64 → data-url
|
||||||
|
String base64 = Base64.getEncoder().encodeToString(bytes);
|
||||||
|
String dataUrl = "data:" + contentType + ";base64," + base64;
|
||||||
|
|
||||||
|
// ------------ 拼接 Qwen 请求体 ------------
|
||||||
|
|
||||||
|
Map<String, Object> root = new HashMap<String, Object>();
|
||||||
|
root.put("model", qwenProperties.getModel());
|
||||||
|
|
||||||
|
List<Map<String, Object>> messages = new ArrayList<Map<String, Object>>();
|
||||||
|
Map<String, Object> message = new HashMap<String, Object>();
|
||||||
|
message.put("role", "user");
|
||||||
|
|
||||||
|
List<Object> contentList = new ArrayList<Object>();
|
||||||
|
|
||||||
|
// 图片部分
|
||||||
|
Map<String, Object> imagePart = new HashMap<String, Object>();
|
||||||
|
imagePart.put("type", "image_url");
|
||||||
|
Map<String, Object> imageUrlMap = new HashMap<String, Object>();
|
||||||
|
imageUrlMap.put("url", dataUrl);
|
||||||
|
imagePart.put("image_url", imageUrlMap);
|
||||||
|
contentList.add(imagePart);
|
||||||
|
|
||||||
|
// 文本提示部分
|
||||||
|
Map<String, Object> textPart = new HashMap<String, Object>();
|
||||||
|
textPart.put("type", "text");
|
||||||
|
textPart.put("text",
|
||||||
|
"你是一个票据识别助手,请严格按以下要求识别:\n" +
|
||||||
|
"1. 找到“采购订单号(ERP)”对应的数字。\n" +
|
||||||
|
"2. 如果其下方是条形码,请返回条形码下面的数字。\n" +
|
||||||
|
"3. 图片中可能同时存在 ERP 与“采购订单号(电商交易专区)”,必须忽略电商交易专区的编号。\n" +
|
||||||
|
"4. 只返回数字,不要返回任何文字、标点或空格。\n" +
|
||||||
|
"5. 如果找不到,请返回空字符串。"
|
||||||
|
);
|
||||||
|
contentList.add(textPart);
|
||||||
|
|
||||||
|
message.put("content", contentList);
|
||||||
|
messages.add(message);
|
||||||
|
root.put("messages", messages);
|
||||||
|
|
||||||
|
String json = objectMapper.writeValueAsString(root);
|
||||||
|
|
||||||
|
// ⚠ 这里参数顺序:先 MediaType 再 json(JDK8 + OkHttp3 正确用法)
|
||||||
|
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
|
||||||
|
String url = qwenProperties.getBaseUrl() + "/chat/completions";
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.header("Authorization", "Bearer " + qwenProperties.getApiKey())
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Response response = httpClient.newCall(request).execute();
|
||||||
|
try {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
String errorBody = response.body() != null ? response.body().string() : "no error body";
|
||||||
|
throw new RuntimeException("调用通义千问失败:" + response.code() + ",错误信息:" + errorBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
String resp = Objects.requireNonNull(response.body()).string();
|
||||||
|
JsonNode rootNode = objectMapper.readTree(resp);
|
||||||
|
JsonNode choices = rootNode.get("choices");
|
||||||
|
if (choices == null || !choices.isArray() || choices.size() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String content = choices.get(0).get("message").get("content").asText("");
|
||||||
|
return extractDigits(content);
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("调用通义千问异常:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正则提取最像 ERP 的数字串
|
||||||
|
*/
|
||||||
|
private String extractDigits(String text) {
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher m = Pattern.compile("\\d+").matcher(text);
|
||||||
|
List<String> nums = new ArrayList<String>();
|
||||||
|
|
||||||
|
while (m.find()) {
|
||||||
|
nums.add(m.group());
|
||||||
|
}
|
||||||
|
if (nums.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据长度筛选一遍(可以根据你实际 ERP 号长度调整)
|
||||||
|
for (String s : nums) {
|
||||||
|
if (s.length() >= 8 && s.length() <= 12) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 兜底:返回第一段数字
|
||||||
|
return nums.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,8 +52,8 @@ spring:
|
|||||||
active: druid
|
active: druid
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
max-file-size: 10MB
|
max-file-size: 20MB
|
||||||
max-request-size: 20MB
|
max-request-size: 50MB
|
||||||
devtools:
|
devtools:
|
||||||
restart:
|
restart:
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -128,3 +128,28 @@ upload:
|
|||||||
|
|
||||||
wisdom:
|
wisdom:
|
||||||
base-url: http://192.168.1.251:8086
|
base-url: http://192.168.1.251:8086
|
||||||
|
|
||||||
|
# =============== OCR 服务核心配置 ===============
|
||||||
|
ocr:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# 阿里云OCR配置
|
||||||
|
aliyun:
|
||||||
|
|
||||||
|
access-key: LTAI5tMi6fjhiQfDdzNpWavx
|
||||||
|
secret-key: PpDsoh11EptdQXcFDm9HkTB4Us4cd7
|
||||||
|
|
||||||
|
# 阿里云文档“服务接入点”里的正式 OCR endpoint
|
||||||
|
endpoint: ocr-api.cn-hangzhou.aliyuncs.com
|
||||||
|
region-id: cn-hangzhou
|
||||||
|
|
||||||
|
# 服务类型:通用文字识别 RecognizeGeneral
|
||||||
|
service-type: general
|
||||||
|
|
||||||
|
# 通义千问VL模型配置
|
||||||
|
qwen:
|
||||||
|
# 重要:请替换为有效的通义千问API密钥
|
||||||
|
# 注意:生产环境中应通过环境变量等方式配置,避免暴露API密钥
|
||||||
|
api-key: "sk-3dfb3f7b049d4010bddaff3ceee08f94"
|
||||||
|
base-url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||||
|
model: "qwen-vl-ocr-latest"
|
||||||
|
|||||||
@@ -11,6 +11,16 @@
|
|||||||
<!-- 单号 -->
|
<!-- 单号 -->
|
||||||
<result property="orderNo" column="order_no"/>
|
<result property="orderNo" column="order_no"/>
|
||||||
<result property="billNoCk" column="bill_no_ck"/>
|
<result property="billNoCk" column="bill_no_ck"/>
|
||||||
|
|
||||||
|
<!-- 新增:rk_info 主键ID -->
|
||||||
|
<result property="rkInfoId" column="rk_info_id"/>
|
||||||
|
|
||||||
|
<!-- 新增:制单人ID、接收物资状态、问题描述 -->
|
||||||
|
<result property="makerId" column="maker_id"/>
|
||||||
|
<result property="makerUserName" column="maker_user_name"/>
|
||||||
|
<result property="receiveStatus" column="receive_status"/>
|
||||||
|
<result property="receiveProblem" column="receive_problem"/>
|
||||||
|
|
||||||
<!-- 基础字段 -->
|
<!-- 基础字段 -->
|
||||||
<result property="xmMs" column="xm_ms"/>
|
<result property="xmMs" column="xm_ms"/>
|
||||||
<result property="xmNo" column="xm_no"/>
|
<result property="xmNo" column="xm_no"/>
|
||||||
@@ -31,7 +41,7 @@
|
|||||||
<result property="destLat" column="dest_lat" jdbcType="DECIMAL"/>
|
<result property="destLat" column="dest_lat" jdbcType="DECIMAL"/>
|
||||||
|
|
||||||
<result property="deliveryDate" column="delivery_date"/>
|
<result property="deliveryDate" column="delivery_date"/>
|
||||||
<result property="plateNo" column="plate_no"/>
|
<result property="plateNo" column="plate_no"/>
|
||||||
|
|
||||||
<!-- 司机 -->
|
<!-- 司机 -->
|
||||||
<result property="driverName" column="driver_name"/>
|
<result property="driverName" column="driver_name"/>
|
||||||
@@ -96,58 +106,78 @@
|
|||||||
<!-- ======================== 带附件的查询列(别名统一 dor) ======================== -->
|
<!-- ======================== 带附件的查询列(别名统一 dor) ======================== -->
|
||||||
<sql id="selectDeliveryOrderVoWithAttach">
|
<sql id="selectDeliveryOrderVoWithAttach">
|
||||||
select
|
select
|
||||||
dor.id, dor.order_no,
|
dor.id,
|
||||||
dor.xm_ms, dor.xm_no, dor.wl_no, dor.wl_ms, dor.real_qty, dor.dw, dor.sap_no, dor.gys_mc,
|
dor.order_no,
|
||||||
dor.remark, dor.origin_name, dor.origin_lng, dor.origin_lat,
|
dor.bill_no_ck,
|
||||||
dor.dest_name, dor.dest_lng, dor.dest_lat,
|
dor.rk_info_id,
|
||||||
dor.delivery_date, dor.plate_no, dor.order_status,
|
dor.maker_id,
|
||||||
dor.driver_name, dor.driver_phone,
|
-- 制单人用户名(连表 sys_user)
|
||||||
|
su.user_name AS maker_user_name,
|
||||||
|
dor.receive_status,
|
||||||
|
dor.receive_problem,
|
||||||
|
dor.xm_ms, dor.xm_no, dor.wl_no, dor.wl_ms, dor.real_qty, dor.dw, dor.sap_no, dor.gys_mc,
|
||||||
|
dor.remark,
|
||||||
|
dor.origin_name, dor.origin_lng, dor.origin_lat,
|
||||||
|
dor.dest_name, dor.dest_lng, dor.dest_lat,
|
||||||
|
dor.delivery_date, dor.plate_no, dor.order_status,
|
||||||
|
dor.driver_name, dor.driver_phone,
|
||||||
|
dor.shipper_name, dor.shipper_phone,
|
||||||
|
dor.receiver_name, dor.receiver_phone, dor.receiver_org_name,
|
||||||
|
dor.delivery_ton,
|
||||||
|
dor.goods_size,
|
||||||
|
-- 车型外键与名称
|
||||||
|
dor.vehicle_type_id, dor.vehicle_type_name,
|
||||||
|
-- 费用/里程
|
||||||
|
dor.suggest_fee, dor.actual_fee, dor.toll_fee, dor.total_km,
|
||||||
|
dor.create_by, dor.create_time, dor.update_by, dor.update_time, dor.is_delete,
|
||||||
|
|
||||||
dor.shipper_name, dor.shipper_phone,
|
-- 附件列(att_ 前缀)
|
||||||
dor.receiver_name, dor.receiver_phone, dor.receiver_org_name,
|
da.id AS att_id,
|
||||||
dor.delivery_ton,
|
da.order_no AS att_order_no,
|
||||||
dor.goods_size,
|
da.scene AS att_scene,
|
||||||
-- 车型外键与名称
|
da.biz_type AS att_biz_type,
|
||||||
dor.vehicle_type_id, dor.vehicle_type_name,
|
da.url AS att_url,
|
||||||
-- 费用/里程
|
da.status AS att_status,
|
||||||
dor.suggest_fee, dor.actual_fee, dor.toll_fee, dor.total_km,
|
da.sort_no AS att_sort_no,
|
||||||
dor.create_by, dor.create_time, dor.update_by, dor.update_time, dor.is_delete,
|
da.remark AS att_remark,
|
||||||
|
da.create_by AS att_create_by,
|
||||||
-- 附件列(att_ 前缀)
|
da.create_time AS att_create_time,
|
||||||
da.id AS att_id,
|
da.update_by AS att_update_by,
|
||||||
da.order_no AS att_order_no,
|
da.update_time AS att_update_time,
|
||||||
da.scene AS att_scene,
|
da.is_delete AS att_is_delete
|
||||||
da.biz_type AS att_biz_type,
|
|
||||||
da.url AS att_url,
|
|
||||||
da.status AS att_status,
|
|
||||||
da.sort_no AS att_sort_no,
|
|
||||||
da.remark AS att_remark,
|
|
||||||
da.create_by AS att_create_by,
|
|
||||||
da.create_time AS att_create_time,
|
|
||||||
da.update_by AS att_update_by,
|
|
||||||
da.update_time AS att_update_time,
|
|
||||||
da.is_delete AS att_is_delete
|
|
||||||
|
|
||||||
from delivery_order dor
|
from delivery_order dor
|
||||||
left join delivery_attachment da
|
left join delivery_attachment da
|
||||||
on da.order_no = dor.order_no
|
on da.order_no = dor.order_no
|
||||||
and da.is_delete = '0'
|
and da.is_delete = '0'
|
||||||
|
<!-- 报表/列表查询连表 sys_user,按制单人ID 取用户名 -->
|
||||||
|
left join sys_user su
|
||||||
|
on su.user_id = dor.maker_id
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<!-- ======================== 不带附件的查询列 ======================== -->
|
<!-- ======================== 不带附件的查询列 ======================== -->
|
||||||
<sql id="selectDeliveryOrderVo">
|
<sql id="selectDeliveryOrderVo">
|
||||||
select id, order_no, xm_ms, xm_no, wl_no, wl_ms, real_qty, dw, sap_no, gys_mc, remark,
|
select
|
||||||
origin_name, origin_lng, origin_lat, dest_name, dest_lng, dest_lat,
|
id,
|
||||||
delivery_date, plate_no,
|
order_no,
|
||||||
-- 司机
|
bill_no_ck,
|
||||||
driver_name, driver_phone,
|
rk_info_id,
|
||||||
shipper_name, shipper_phone, receiver_name,
|
maker_id,
|
||||||
receiver_phone, receiver_org_name, delivery_ton, goods_size, order_status,
|
receive_status,
|
||||||
-- 车型外键与名称
|
receive_problem,
|
||||||
vehicle_type_id, vehicle_type_name,
|
xm_ms, xm_no, wl_no, wl_ms, real_qty, dw, sap_no, gys_mc, remark,
|
||||||
-- 费用/里程
|
origin_name, origin_lng, origin_lat,
|
||||||
suggest_fee, actual_fee, toll_fee, total_km,
|
dest_name, dest_lng, dest_lat,
|
||||||
create_by, create_time, update_by, update_time, is_delete
|
delivery_date, plate_no,
|
||||||
|
-- 司机
|
||||||
|
driver_name, driver_phone,
|
||||||
|
shipper_name, shipper_phone, receiver_name,
|
||||||
|
receiver_phone, receiver_org_name, delivery_ton, goods_size, order_status,
|
||||||
|
-- 车型外键与名称
|
||||||
|
vehicle_type_id, vehicle_type_name,
|
||||||
|
-- 费用/里程
|
||||||
|
suggest_fee, actual_fee, toll_fee, total_km,
|
||||||
|
create_by, create_time, update_by, update_time, is_delete
|
||||||
from delivery_order
|
from delivery_order
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -166,6 +196,14 @@
|
|||||||
</otherwise>
|
</otherwise>
|
||||||
</choose>
|
</choose>
|
||||||
|
|
||||||
|
<!-- 制单人ID / 接收状态筛选(可选) -->
|
||||||
|
<if test="makerId != null">
|
||||||
|
and dor.maker_id = #{makerId}
|
||||||
|
</if>
|
||||||
|
<if test="receiveStatus != null">
|
||||||
|
and dor.receive_status = #{receiveStatus}
|
||||||
|
</if>
|
||||||
|
|
||||||
<if test="xmMs != null and xmMs != ''"> and dor.xm_ms = #{xmMs}</if>
|
<if test="xmMs != null and xmMs != ''"> and dor.xm_ms = #{xmMs}</if>
|
||||||
<if test="xmNo != null and xmNo != ''"> and dor.xm_no = #{xmNo}</if>
|
<if test="xmNo != null and xmNo != ''"> and dor.xm_no = #{xmNo}</if>
|
||||||
<if test="wlNo != null and wlNo != ''"> and dor.wl_no = #{wlNo}</if>
|
<if test="wlNo != null and wlNo != ''"> and dor.wl_no = #{wlNo}</if>
|
||||||
@@ -175,10 +213,14 @@
|
|||||||
<if test="sapNo != null and sapNo != ''"> and dor.sap_no = #{sapNo}</if>
|
<if test="sapNo != null and sapNo != ''"> and dor.sap_no = #{sapNo}</if>
|
||||||
<if test="gysMc != null and gysMc != ''"> and dor.gys_mc = #{gysMc}</if>
|
<if test="gysMc != null and gysMc != ''"> and dor.gys_mc = #{gysMc}</if>
|
||||||
|
|
||||||
<if test="originName != null and originName != ''"> and dor.origin_name like concat('%', #{originName}, '%')</if>
|
<if test="originName != null and originName != ''">
|
||||||
|
and dor.origin_name like concat('%', #{originName}, '%')
|
||||||
|
</if>
|
||||||
<if test="originLng != null "> and dor.origin_lng = #{originLng}</if>
|
<if test="originLng != null "> and dor.origin_lng = #{originLng}</if>
|
||||||
<if test="originLat != null "> and dor.origin_lat = #{originLat}</if>
|
<if test="originLat != null "> and dor.origin_lat = #{originLat}</if>
|
||||||
<if test="destName != null and destName != ''"> and dor.dest_name like concat('%', #{destName}, '%')</if>
|
<if test="destName != null and destName != ''">
|
||||||
|
and dor.dest_name like concat('%', #{destName}, '%')
|
||||||
|
</if>
|
||||||
<if test="destLng != null "> and dor.dest_lng = #{destLng}</if>
|
<if test="destLng != null "> and dor.dest_lng = #{destLng}</if>
|
||||||
<if test="destLat != null "> and dor.dest_lat = #{destLat}</if>
|
<if test="destLat != null "> and dor.dest_lat = #{destLat}</if>
|
||||||
|
|
||||||
@@ -186,18 +228,34 @@
|
|||||||
<if test="plateNo != null and plateNo != ''"> and dor.plate_no = #{plateNo}</if>
|
<if test="plateNo != null and plateNo != ''"> and dor.plate_no = #{plateNo}</if>
|
||||||
|
|
||||||
<!-- 司机筛选 -->
|
<!-- 司机筛选 -->
|
||||||
<if test="driverName != null and driverName != ''"> and dor.driver_name like concat('%', #{driverName}, '%')</if>
|
<if test="driverName != null and driverName != ''">
|
||||||
<if test="driverPhone != null and driverPhone != ''"> and dor.driver_phone = #{driverPhone}</if>
|
and dor.driver_name like concat('%', #{driverName}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="driverPhone != null and driverPhone != ''">
|
||||||
|
and dor.driver_phone = #{driverPhone}
|
||||||
|
</if>
|
||||||
|
|
||||||
<if test="shipperName != null and shipperName != ''"> and dor.shipper_name like concat('%', #{shipperName}, '%')</if>
|
<if test="shipperName != null and shipperName != ''">
|
||||||
<if test="shipperPhone != null and shipperPhone != ''"> and dor.shipper_phone = #{shipperPhone}</if>
|
and dor.shipper_name like concat('%', #{shipperName}, '%')
|
||||||
<if test="receiverName != null and receiverName != ''"> and dor.receiver_name like concat('%', #{receiverName}, '%')</if>
|
</if>
|
||||||
<if test="receiverPhone != null and receiverPhone != ''"> and dor.receiver_phone = #{receiverPhone}</if>
|
<if test="shipperPhone != null and shipperPhone != ''">
|
||||||
<if test="receiverOrgName != null and receiverOrgName != ''"> and dor.receiver_org_name like concat('%', #{receiverOrgName}, '%')</if>
|
and dor.shipper_phone = #{shipperPhone}
|
||||||
|
</if>
|
||||||
|
<if test="receiverName != null and receiverName != ''">
|
||||||
|
and dor.receiver_name like concat('%', #{receiverName}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="receiverPhone != null and receiverPhone != ''">
|
||||||
|
and dor.receiver_phone = #{receiverPhone}
|
||||||
|
</if>
|
||||||
|
<if test="receiverOrgName != null and receiverOrgName != ''">
|
||||||
|
and dor.receiver_org_name like concat('%', #{receiverOrgName}, '%')
|
||||||
|
</if>
|
||||||
|
|
||||||
<if test="deliveryTon != null "> and dor.delivery_ton = #{deliveryTon}</if>
|
<if test="deliveryTon != null "> and dor.delivery_ton = #{deliveryTon}</if>
|
||||||
<if test="goodsSize != null"> and dor.goods_size = #{goodsSize}</if>
|
<if test="goodsSize != null"> and dor.goods_size = #{goodsSize}</if>
|
||||||
<if test="orderStatus != null and orderStatus != ''"> and dor.order_status = #{orderStatus}</if>
|
<if test="orderStatus != null and orderStatus != ''">
|
||||||
|
and dor.order_status = #{orderStatus}
|
||||||
|
</if>
|
||||||
|
|
||||||
<!-- 车型筛选 -->
|
<!-- 车型筛选 -->
|
||||||
<if test="vehicleTypeId != null"> and dor.vehicle_type_id = #{vehicleTypeId}</if>
|
<if test="vehicleTypeId != null"> and dor.vehicle_type_id = #{vehicleTypeId}</if>
|
||||||
@@ -250,7 +308,7 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- 没有多选时,再走单个状态查询,兼容原有 App 逻辑 -->
|
<!-- 没有多选时,再走单个状态查询 -->
|
||||||
<if test="(orderStatusList == null or orderStatusList.size == 0)
|
<if test="(orderStatusList == null or orderStatusList.size == 0)
|
||||||
and orderStatus != null and orderStatus != ''">
|
and orderStatus != null and orderStatus != ''">
|
||||||
AND dor.order_status = #{orderStatus}
|
AND dor.order_status = #{orderStatus}
|
||||||
@@ -267,21 +325,23 @@
|
|||||||
ORDER BY MAX(dor.create_time) DESC
|
ORDER BY MAX(dor.create_time) DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 详情:同单号所有行 -->
|
<!-- 详情:同单号所有行(带附件 + makerUserName) -->
|
||||||
<select id="selectByOrderNo" parameterType="string" resultMap="DeliveryOrderResult">
|
<select id="selectByOrderNo"
|
||||||
SELECT * FROM delivery_order
|
parameterType="string"
|
||||||
WHERE order_no = #{orderNo,jdbcType=VARCHAR}
|
resultMap="DeliveryOrderWithAttachResult">
|
||||||
AND (is_delete = '0' OR is_delete = 0 OR is_delete IS NULL)
|
<include refid="selectDeliveryOrderVoWithAttach"/>
|
||||||
ORDER BY id
|
WHERE dor.order_no = #{orderNo}
|
||||||
|
AND (dor.is_delete = '0' OR dor.is_delete = 0 OR dor.is_delete IS NULL)
|
||||||
|
ORDER BY dor.id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 单条查询:按单号 -->
|
<!-- 单条查询:按单号(不带附件,简单版本) -->
|
||||||
<select id="selectDeliveryOrderByOrderNo"
|
<select id="selectDeliveryOrderByOrderNo"
|
||||||
parameterType="string"
|
parameterType="string"
|
||||||
resultMap="DeliveryOrderResult">
|
resultMap="DeliveryOrderResult">
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM delivery_order
|
FROM delivery_order
|
||||||
WHERE order_no = #{orderNo,jdbcType=VARCHAR}
|
WHERE order_no = #{orderNo}
|
||||||
AND (is_delete = '0' OR is_delete = 0 OR is_delete IS NULL)
|
AND (is_delete = '0' OR is_delete = 0 OR is_delete IS NULL)
|
||||||
ORDER BY id ASC
|
ORDER BY id ASC
|
||||||
</select>
|
</select>
|
||||||
@@ -289,10 +349,18 @@
|
|||||||
<!-- ======================== 插入 ======================== -->
|
<!-- ======================== 插入 ======================== -->
|
||||||
|
|
||||||
<!-- 单条插入 -->
|
<!-- 单条插入 -->
|
||||||
<insert id="insertDeliveryOrder" parameterType="DeliveryOrder" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insertDeliveryOrder"
|
||||||
|
parameterType="com.delivery.project.document.domain.DeliveryOrder"
|
||||||
|
useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into delivery_order
|
insert into delivery_order
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
<if test="orderNo != null">order_no,</if>
|
<if test="orderNo != null">order_no,</if>
|
||||||
|
<if test="billNoCk != null">bill_no_ck,</if>
|
||||||
|
<if test="rkInfoId != null">rk_info_id,</if>
|
||||||
|
<if test="makerId != null">maker_id,</if>
|
||||||
|
<if test="receiveStatus != null">receive_status,</if>
|
||||||
|
<if test="receiveProblem != null">receive_problem,</if>
|
||||||
|
|
||||||
<if test="xmMs != null">xm_ms,</if>
|
<if test="xmMs != null">xm_ms,</if>
|
||||||
<if test="xmNo != null">xm_no,</if>
|
<if test="xmNo != null">xm_no,</if>
|
||||||
<if test="wlNo != null">wl_no,</if>
|
<if test="wlNo != null">wl_no,</if>
|
||||||
@@ -339,6 +407,12 @@
|
|||||||
</trim>
|
</trim>
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
<if test="orderNo != null">#{orderNo,jdbcType=VARCHAR},</if>
|
<if test="orderNo != null">#{orderNo,jdbcType=VARCHAR},</if>
|
||||||
|
<if test="billNoCk != null">#{billNoCk},</if>
|
||||||
|
<if test="rkInfoId != null">#{rkInfoId},</if>
|
||||||
|
<if test="makerId != null">#{makerId},</if>
|
||||||
|
<if test="receiveStatus != null">#{receiveStatus},</if>
|
||||||
|
<if test="receiveProblem != null">#{receiveProblem},</if>
|
||||||
|
|
||||||
<if test="xmMs != null">#{xmMs},</if>
|
<if test="xmMs != null">#{xmMs},</if>
|
||||||
<if test="xmNo != null">#{xmNo},</if>
|
<if test="xmNo != null">#{xmNo},</if>
|
||||||
<if test="wlNo != null">#{wlNo},</if>
|
<if test="wlNo != null">#{wlNo},</if>
|
||||||
@@ -388,7 +462,7 @@
|
|||||||
<!-- 批量插入 -->
|
<!-- 批量插入 -->
|
||||||
<insert id="batchInsert" parameterType="java.util.List">
|
<insert id="batchInsert" parameterType="java.util.List">
|
||||||
INSERT INTO delivery_order
|
INSERT INTO delivery_order
|
||||||
(order_no, bill_no_ck,
|
(order_no, bill_no_ck, rk_info_id, maker_id, receive_status, receive_problem,
|
||||||
xm_ms, xm_no, wl_no, wl_ms, real_qty, dw, sap_no, gys_mc, remark,
|
xm_ms, xm_no, wl_no, wl_ms, real_qty, dw, sap_no, gys_mc, remark,
|
||||||
origin_name, origin_lng, origin_lat,
|
origin_name, origin_lng, origin_lat,
|
||||||
dest_name, dest_lng, dest_lat,
|
dest_name, dest_lng, dest_lat,
|
||||||
@@ -404,6 +478,10 @@
|
|||||||
(
|
(
|
||||||
#{it.orderNo},
|
#{it.orderNo},
|
||||||
#{it.billNoCk},
|
#{it.billNoCk},
|
||||||
|
#{it.rkInfoId},
|
||||||
|
#{it.makerId},
|
||||||
|
#{it.receiveStatus},
|
||||||
|
#{it.receiveProblem},
|
||||||
|
|
||||||
#{it.xmMs}, #{it.xmNo}, #{it.wlNo}, #{it.wlMs}, #{it.realQty}, #{it.dw},
|
#{it.xmMs}, #{it.xmNo}, #{it.wlNo}, #{it.wlMs}, #{it.realQty}, #{it.dw},
|
||||||
#{it.sapNo}, #{it.gysMc}, #{it.remark},
|
#{it.sapNo}, #{it.gysMc}, #{it.remark},
|
||||||
@@ -424,11 +502,17 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
|
||||||
<!-- ======================== 更新 ======================== -->
|
<!-- ======================== 更新 ======================== -->
|
||||||
<update id="updateDeliveryOrder" parameterType="com.delivery.project.document.domain.DeliveryOrder">
|
<update id="updateDeliveryOrder"
|
||||||
|
parameterType="com.delivery.project.document.domain.DeliveryOrder">
|
||||||
UPDATE delivery_order
|
UPDATE delivery_order
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="billNoCk != null">bill_no_ck = #{billNoCk},</if>
|
||||||
|
<if test="rkInfoId != null">rk_info_id = #{rkInfoId},</if>
|
||||||
|
<if test="makerId != null">maker_id = #{makerId},</if>
|
||||||
|
<if test="receiveStatus != null">receive_status = #{receiveStatus},</if>
|
||||||
|
<if test="receiveProblem != null">receive_problem = #{receiveProblem},</if>
|
||||||
|
|
||||||
<if test="xmMs != null">xm_ms = #{xmMs},</if>
|
<if test="xmMs != null">xm_ms = #{xmMs},</if>
|
||||||
<if test="xmNo != null">xm_no = #{xmNo},</if>
|
<if test="xmNo != null">xm_no = #{xmNo},</if>
|
||||||
<if test="wlNo != null">wl_no = #{wlNo},</if>
|
<if test="wlNo != null">wl_no = #{wlNo},</if>
|
||||||
@@ -479,11 +563,11 @@
|
|||||||
</update>
|
</update>
|
||||||
|
|
||||||
<!-- ======================== 删除 ======================== -->
|
<!-- ======================== 删除 ======================== -->
|
||||||
<delete id="deleteDeliveryOrderById" parameterType="Long">
|
<delete id="deleteDeliveryOrderById" parameterType="java.lang.Long">
|
||||||
delete from delivery_order where id = #{id}
|
delete from delivery_order where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<delete id="deleteDeliveryOrderByIds" parameterType="String">
|
<delete id="deleteDeliveryOrderByIds" parameterType="java.lang.String">
|
||||||
delete from delivery_order where id in
|
delete from delivery_order where id in
|
||||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
#{id}
|
#{id}
|
||||||
|
|||||||
Reference in New Issue
Block a user