添加功能下载验收单
This commit is contained in:
@@ -19,9 +19,18 @@ import com.aiotagro.cattletrade.business.service.IXqClientService;
|
||||
import com.aiotagro.common.core.context.SecurityContextHolder;
|
||||
import com.aiotagro.common.core.utils.SecurityUtil;
|
||||
import com.aiotagro.common.core.constant.RoleConstants;
|
||||
import com.aiotagro.common.core.constant.TencentCloudConstants;
|
||||
import com.aiotagro.common.core.web.domain.AjaxResult;
|
||||
import com.qcloud.cos.COSClient;
|
||||
import com.qcloud.cos.model.GetObjectRequest;
|
||||
import com.aiotagro.common.core.web.domain.PageResultResponse;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.aiotagro.cattletrade.business.mapper.MemberMapper;
|
||||
import com.aiotagro.cattletrade.business.mapper.OrderMapper;
|
||||
import com.aiotagro.cattletrade.business.entity.Order;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -31,8 +40,10 @@ import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -50,6 +61,8 @@ import java.util.zip.ZipOutputStream;
|
||||
@RestController
|
||||
@RequestMapping("/delivery")
|
||||
public class DeliveryController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeliveryController.class);
|
||||
|
||||
@Autowired
|
||||
private IDeliveryService deliveryService;
|
||||
@@ -65,6 +78,12 @@ public class DeliveryController {
|
||||
|
||||
@Autowired
|
||||
private com.aiotagro.cattletrade.business.mapper.IotDeviceDataMapper iotDeviceDataMapper;
|
||||
|
||||
@Autowired
|
||||
private MemberMapper memberMapper;
|
||||
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
|
||||
|
||||
|
||||
@@ -700,10 +719,12 @@ public class DeliveryController {
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOut = null;
|
||||
COSClient cosClient = null;
|
||||
|
||||
try {
|
||||
if (id == null) {
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("运单ID不能为空");
|
||||
return;
|
||||
}
|
||||
@@ -712,6 +733,7 @@ public class DeliveryController {
|
||||
Delivery delivery = deliveryService.getById(id);
|
||||
if (delivery == null) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("运单不存在");
|
||||
return;
|
||||
}
|
||||
@@ -723,29 +745,47 @@ public class DeliveryController {
|
||||
// 1. 创建信息文本文件
|
||||
addDeliveryInfoToZip(zipOut, delivery);
|
||||
|
||||
// 创建COS客户端(如果URL是COS URL,将在addFileToZip中创建)
|
||||
// 预先创建COS客户端,避免重复创建
|
||||
if (delivery.getQuarantineTickeyUrl() != null &&
|
||||
delivery.getQuarantineTickeyUrl().contains(TencentCloudConstants.TENCENT_CLOUD_BUCKET + ".cos")) {
|
||||
com.qcloud.cos.auth.BasicCOSCredentials cred = new com.qcloud.cos.auth.BasicCOSCredentials(
|
||||
TencentCloudConstants.TENCENT_CLOUD_SECRETID,
|
||||
TencentCloudConstants.TENCENT_CLOUD_SECRETKEY
|
||||
);
|
||||
com.qcloud.cos.region.Region region = new com.qcloud.cos.region.Region(TencentCloudConstants.TENCENT_CLOUD_REGION);
|
||||
com.qcloud.cos.ClientConfig clientConfig = new com.qcloud.cos.ClientConfig(region);
|
||||
clientConfig.setHttpProtocol(com.qcloud.cos.http.HttpProtocol.https);
|
||||
cosClient = new COSClient(cred, clientConfig);
|
||||
logger.debug("创建COS客户端用于下载文件");
|
||||
}
|
||||
|
||||
// 2. 下载并添加所有照片
|
||||
int photoCount = 0;
|
||||
photoCount += addFileToZip(zipOut, delivery.getQuarantineTickeyUrl(), "照片/检疫票.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getPoundListImg(), "照片/纸质磅单.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getEmptyVehicleFrontPhoto(), "照片/空车过磅车头照片.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleFrontPhoto(), "照片/装车过磅车头照片.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleWeightPhoto(), "照片/装车过磅磅单.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getCarFrontPhoto(), "照片/车头照片.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getCarBehindPhoto(), "照片/车尾照片.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getDriverIdCardPhoto(), "照片/司机身份证照片.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getDestinationPoundListImg(), "照片/到地磅单.jpg");
|
||||
photoCount += addFileToZip(zipOut, delivery.getDestinationVehicleFrontPhoto(), "照片/到地车辆过重磅车头照片.jpg");
|
||||
|
||||
logger.info("开始添加照片到ZIP,运单ID: {}", id);
|
||||
photoCount += addFileToZip(zipOut, delivery.getQuarantineTickeyUrl(), "照片/检疫票.jpg", "检疫票", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getPoundListImg(), "照片/纸质磅单.jpg", "纸质磅单", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getEmptyVehicleFrontPhoto(), "照片/空车过磅车头照片.jpg", "空车过磅车头照片", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleFrontPhoto(), "照片/装车过磅车头照片.jpg", "装车过磅车头照片", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleWeightPhoto(), "照片/装车过磅磅单.jpg", "装车过磅磅单", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getCarFrontPhoto(), "照片/车头照片.jpg", "车头照片", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getCarBehindPhoto(), "照片/车尾照片.jpg", "车尾照片", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getDriverIdCardPhoto(), "照片/司机身份证照片.jpg", "司机身份证照片", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getDestinationPoundListImg(), "照片/到地磅单.jpg", "到地磅单", cosClient);
|
||||
photoCount += addFileToZip(zipOut, delivery.getDestinationVehicleFrontPhoto(), "照片/到地车辆过重磅车头照片.jpg", "到地车辆过重磅车头照片", cosClient);
|
||||
logger.info("照片添加完成,成功添加 {} 张照片", photoCount);
|
||||
|
||||
// 3. 下载并添加所有视频
|
||||
int videoCount = 0;
|
||||
videoCount += addFileToZip(zipOut, delivery.getEmptyWeightVideo(), "视频/空车过磅视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getEntruckWeightVideo(), "视频/装车过磅视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getEntruckVideo(), "视频/装车视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getControlSlotVideo(), "视频/消毒槽视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getCattleLoadingCircleVideo(), "视频/牛只装车环视视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getUnloadCattleVideo(), "视频/卸牛视频.mp4");
|
||||
videoCount += addFileToZip(zipOut, delivery.getDestinationWeightVideo(), "视频/到地过磅视频.mp4");
|
||||
logger.info("开始添加视频到ZIP,运单ID: {}", id);
|
||||
videoCount += addFileToZip(zipOut, delivery.getEmptyWeightVideo(), "视频/空车过磅视频.mp4", "空车过磅视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getEntruckWeightVideo(), "视频/装车过磅视频.mp4", "装车过磅视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getEntruckVideo(), "视频/装车视频.mp4", "装车视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getControlSlotVideo(), "视频/消毒槽视频.mp4", "消毒槽视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getCattleLoadingCircleVideo(), "视频/牛只装车环视视频.mp4", "牛只装车环视视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getUnloadCattleVideo(), "视频/卸牛视频.mp4", "卸牛视频", cosClient);
|
||||
videoCount += addFileToZip(zipOut, delivery.getDestinationWeightVideo(), "视频/到地过磅视频.mp4", "到地过磅视频", cosClient);
|
||||
logger.info("视频添加完成,成功添加 {} 个视频", videoCount);
|
||||
|
||||
|
||||
zipOut.finish();
|
||||
@@ -767,12 +807,16 @@ public class DeliveryController {
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("打包文件失败,运单ID: {}", id, e);
|
||||
try {
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
response.getWriter().write("打包文件失败:" + e.getMessage());
|
||||
// 确保响应头已设置,避免被错误处理为登录过期
|
||||
if (!response.isCommitted()) {
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("打包文件失败:" + e.getMessage());
|
||||
}
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
logger.error("写入错误响应失败", ioException);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
@@ -780,8 +824,12 @@ public class DeliveryController {
|
||||
zipOut.close();
|
||||
}
|
||||
byteArrayOutputStream.close();
|
||||
// 关闭COS客户端
|
||||
if (cosClient != null) {
|
||||
cosClient.shutdown();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
logger.warn("关闭资源失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,45 +870,663 @@ public class DeliveryController {
|
||||
|
||||
/**
|
||||
* 从URL下载文件并添加到ZIP
|
||||
* 优先使用腾讯云COS SDK下载,如果URL不是COS URL则使用HttpURLConnection
|
||||
* @param zipOut ZIP输出流
|
||||
* @param fileUrl 文件URL
|
||||
* @param fileName ZIP中的文件名
|
||||
* @param fileDescription 文件描述(用于日志)
|
||||
* @param cosClient COS客户端(如果已创建,可复用;如果为null,会在需要时创建)
|
||||
* @return 成功添加返回1,失败或URL为空返回0
|
||||
*/
|
||||
private int addFileToZip(ZipOutputStream zipOut, String fileUrl, String fileName) {
|
||||
private int addFileToZip(ZipOutputStream zipOut, String fileUrl, String fileName, String fileDescription, COSClient cosClient) {
|
||||
if (fileUrl == null || fileUrl.trim().isEmpty()) {
|
||||
logger.debug("跳过添加文件: {} (URL为空)", fileDescription);
|
||||
return 0;
|
||||
}
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
logger.debug("开始下载文件: {},URL: {}", fileDescription, fileUrl);
|
||||
|
||||
URL url = new URL(fileUrl);
|
||||
inputStream = url.openStream();
|
||||
// 检查是否是腾讯云COS的URL
|
||||
if (fileUrl.contains(TencentCloudConstants.TENCENT_CLOUD_BUCKET + ".cos")) {
|
||||
// 使用COS SDK下载文件
|
||||
try {
|
||||
// 从URL中提取COS对象键(key)
|
||||
// URL格式: https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/11/04/文件名.jpg
|
||||
String cosKey = extractCosKeyFromUrl(fileUrl);
|
||||
if (cosKey == null) {
|
||||
logger.warn("无法从URL中提取COS键: {},URL: {}", fileDescription, fileUrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 使用COS客户端下载文件
|
||||
// 如果传入的cosClient为null,则创建新的客户端
|
||||
COSClient clientToUse = cosClient;
|
||||
if (clientToUse == null) {
|
||||
com.qcloud.cos.auth.BasicCOSCredentials cred = new com.qcloud.cos.auth.BasicCOSCredentials(
|
||||
TencentCloudConstants.TENCENT_CLOUD_SECRETID,
|
||||
TencentCloudConstants.TENCENT_CLOUD_SECRETKEY
|
||||
);
|
||||
com.qcloud.cos.region.Region region = new com.qcloud.cos.region.Region(TencentCloudConstants.TENCENT_CLOUD_REGION);
|
||||
com.qcloud.cos.ClientConfig clientConfig = new com.qcloud.cos.ClientConfig(region);
|
||||
clientConfig.setHttpProtocol(com.qcloud.cos.http.HttpProtocol.https);
|
||||
clientToUse = new COSClient(cred, clientConfig);
|
||||
}
|
||||
|
||||
GetObjectRequest getObjectRequest = new GetObjectRequest(
|
||||
TencentCloudConstants.TENCENT_CLOUD_BUCKET,
|
||||
cosKey
|
||||
);
|
||||
com.qcloud.cos.model.COSObject cosObject = clientToUse.getObject(getObjectRequest);
|
||||
inputStream = cosObject.getObjectContent();
|
||||
|
||||
logger.debug("使用COS SDK下载文件: {},COS键: {}", fileDescription, cosKey);
|
||||
} catch (Exception e) {
|
||||
logger.warn("使用COS SDK下载文件失败: {},URL: {},错误: {},尝试使用HttpURLConnection",
|
||||
fileDescription, fileUrl, e.getMessage());
|
||||
// 如果COS SDK失败,回退到HttpURLConnection
|
||||
inputStream = downloadViaHttp(fileUrl);
|
||||
}
|
||||
} else {
|
||||
// 非COS URL,使用HttpURLConnection
|
||||
inputStream = downloadViaHttp(fileUrl);
|
||||
}
|
||||
|
||||
if (inputStream == null) {
|
||||
logger.warn("无法获取文件输入流: {},URL: {}", fileDescription, fileUrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZipEntry entry = new ZipEntry(fileName);
|
||||
zipOut.putNextEntry(entry);
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
int totalBytes = 0;
|
||||
long totalBytes = 0;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
zipOut.write(buffer, 0, bytesRead);
|
||||
totalBytes += bytesRead;
|
||||
}
|
||||
|
||||
zipOut.closeEntry();
|
||||
logger.debug("成功添加文件: {},大小: {} 字节", fileDescription, totalBytes);
|
||||
return 1;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("添加文件到ZIP时发生错误: {},URL: {}", fileDescription, fileUrl, e);
|
||||
return 0;
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
logger.warn("关闭输入流失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从COS URL中提取对象键(key)
|
||||
* @param fileUrl COS文件URL
|
||||
* @return COS对象键,如果无法提取则返回null
|
||||
*/
|
||||
private String extractCosKeyFromUrl(String fileUrl) {
|
||||
try {
|
||||
// URL格式: https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/11/04/文件名.jpg
|
||||
URL url = new URL(fileUrl);
|
||||
String path = url.getPath();
|
||||
if (path != null && path.startsWith("/")) {
|
||||
return path.substring(1); // 移除开头的 "/"
|
||||
}
|
||||
return path;
|
||||
} catch (Exception e) {
|
||||
logger.warn("提取COS键失败,URL: {},错误: {}", fileUrl, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用HttpURLConnection下载文件
|
||||
* @param fileUrl 文件URL
|
||||
* @return 输入流,如果失败返回null
|
||||
*/
|
||||
private InputStream downloadViaHttp(String fileUrl) {
|
||||
try {
|
||||
// 对URL进行编码处理(特别是中文字符)
|
||||
URL url = new URL(fileUrl);
|
||||
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10秒连接超时
|
||||
connection.setReadTimeout(30000); // 30秒读取超时
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != java.net.HttpURLConnection.HTTP_OK) {
|
||||
logger.warn("HTTP下载失败,响应码: {},URL: {}", responseCode, fileUrl);
|
||||
return null;
|
||||
}
|
||||
|
||||
return connection.getInputStream();
|
||||
} catch (Exception e) {
|
||||
logger.warn("HttpURLConnection下载失败,URL: {},错误: {}", fileUrl, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载验收单(生成HTML格式的牛只发车验收单)
|
||||
*
|
||||
* @param id 运单ID
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
@SaCheckPermission("delivery:export")
|
||||
@GetMapping("/downloadAcceptanceForm")
|
||||
public void downloadAcceptanceForm(@RequestParam Integer id, HttpServletResponse response) {
|
||||
logger.info("开始生成验收单,运单ID: {}", id);
|
||||
|
||||
try {
|
||||
if (id == null) {
|
||||
logger.warn("运单ID不能为空");
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("运单ID不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询运单详情
|
||||
Delivery delivery = deliveryService.getById(id);
|
||||
if (delivery == null) {
|
||||
logger.warn("运单不存在,ID: {}", id);
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("运单不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("查询到运单信息,运单号: {}, 车牌号: {}", delivery.getDeliveryNumber(), delivery.getLicensePlate());
|
||||
|
||||
// 查询供应商名称(如果supplierName为空)
|
||||
if (delivery.getSupplierName() == null || delivery.getSupplierName().isEmpty()) {
|
||||
if (delivery.getSupplierId() != null && !delivery.getSupplierId().isEmpty()) {
|
||||
try {
|
||||
String[] supplierIds = delivery.getSupplierId().split(",");
|
||||
List<String> supplierNames = new ArrayList<>();
|
||||
for (String supplierId : supplierIds) {
|
||||
if (StringUtils.isNotEmpty(supplierId.trim())) {
|
||||
try {
|
||||
Integer sid = Integer.parseInt(supplierId.trim());
|
||||
Map<String, Object> supplierInfo = memberMapper.selectMemberUserById(sid);
|
||||
if (supplierInfo != null) {
|
||||
String username = (String) supplierInfo.get("username");
|
||||
if (StringUtils.isNotEmpty(username)) {
|
||||
supplierNames.add(username);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("供应商ID格式错误: {}", supplierId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supplierNames.isEmpty()) {
|
||||
delivery.setSupplierName(String.join(",", supplierNames));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("查询供应商信息失败,运单ID: {}", id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询采购商名称(如果buyerName为空)
|
||||
if (delivery.getBuyerName() == null || delivery.getBuyerName().isEmpty()) {
|
||||
if (delivery.getBuyerId() != null) {
|
||||
try {
|
||||
Map<String, Object> buyerInfo = memberMapper.selectMemberUserById(delivery.getBuyerId());
|
||||
if (buyerInfo != null) {
|
||||
String username = (String) buyerInfo.get("username");
|
||||
String mobile = (String) buyerInfo.get("mobile");
|
||||
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(mobile)) {
|
||||
delivery.setBuyerName(username + "/" + mobile);
|
||||
} else if (StringUtils.isNotEmpty(username)) {
|
||||
delivery.setBuyerName(username);
|
||||
} else if (StringUtils.isNotEmpty(mobile)) {
|
||||
delivery.setBuyerName(mobile);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("查询采购商信息失败,运单ID: {}", id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 准备数据 - 供货单位(卖方字段,只取姓名,不要手机号)
|
||||
String supplierName = delivery.getSupplierName();
|
||||
if (supplierName != null && !supplierName.isEmpty()) {
|
||||
// 如果包含"/",取"/"前面的部分(姓名部分)
|
||||
if (supplierName.contains("/")) {
|
||||
supplierName = supplierName.split("/")[0].trim();
|
||||
}
|
||||
// 如果包含逗号分隔(多个供应商),取第一个并处理"/"
|
||||
if (supplierName.contains(",")) {
|
||||
String[] parts = supplierName.split(",");
|
||||
supplierName = parts[0].trim();
|
||||
if (supplierName.contains("/")) {
|
||||
supplierName = supplierName.split("/")[0].trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果supplierName为空,使用supplierMobile作为备选(但通常不应该这样做,因为这是姓名字段)
|
||||
supplierName = "";
|
||||
}
|
||||
|
||||
// 准备数据 - 收货单位(买方字段,只取姓名,不要手机号)
|
||||
String buyerName = delivery.getBuyerName();
|
||||
if (buyerName != null && !buyerName.isEmpty()) {
|
||||
// 如果包含"/",取"/"前面的部分(姓名部分)
|
||||
if (buyerName.contains("/")) {
|
||||
buyerName = buyerName.split("/")[0].trim();
|
||||
}
|
||||
// 如果包含逗号分隔(多个采购商),取第一个并处理"/"
|
||||
if (buyerName.contains(",")) {
|
||||
String[] parts = buyerName.split(",");
|
||||
buyerName = parts[0].trim();
|
||||
if (buyerName.contains("/")) {
|
||||
buyerName = buyerName.split("/")[0].trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果buyerName为空,使用buyerMobile作为备选(但通常不应该这样做,因为这是姓名字段)
|
||||
buyerName = "";
|
||||
}
|
||||
|
||||
logger.info("提取的供货单位: {}, 收货单位: {}", supplierName, buyerName);
|
||||
|
||||
String startLocation = delivery.getStartLocation() != null ? delivery.getStartLocation() : "";
|
||||
String endLocation = delivery.getEndLocation() != null ? delivery.getEndLocation() : "";
|
||||
String licensePlate = delivery.getLicensePlate() != null ? delivery.getLicensePlate() : "";
|
||||
|
||||
// 格式化发车时间
|
||||
String departureTime = "";
|
||||
if (delivery.getEstimatedDepartureTime() != null) {
|
||||
try {
|
||||
// Date 转 LocalDateTime
|
||||
java.time.LocalDateTime localDateTime = delivery.getEstimatedDepartureTime().toInstant()
|
||||
.atZone(java.time.ZoneId.systemDefault())
|
||||
.toLocalDateTime();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
|
||||
departureTime = localDateTime.format(formatter);
|
||||
} catch (Exception e) {
|
||||
logger.warn("格式化发车时间失败,使用默认格式,运单ID: {}", id, e);
|
||||
// 如果格式化失败,使用默认格式
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
|
||||
departureTime = sdf.format(delivery.getEstimatedDepartureTime());
|
||||
}
|
||||
}
|
||||
|
||||
// 处理司机姓名和联系方式
|
||||
String driverName = delivery.getDriverName() != null ? delivery.getDriverName() : "";
|
||||
String driverMobile = delivery.getDriverMobile() != null ? delivery.getDriverMobile() : "";
|
||||
String driverInfo = "";
|
||||
if (!driverName.isEmpty() && driverName.contains("/")) {
|
||||
// 如果司机姓名包含"/",取前面部分作为姓名
|
||||
String[] parts = driverName.split("/");
|
||||
driverInfo = parts[0];
|
||||
if (parts.length > 1) {
|
||||
driverInfo += " " + parts[1];
|
||||
} else if (!driverMobile.isEmpty()) {
|
||||
driverInfo += " " + driverMobile;
|
||||
}
|
||||
} else {
|
||||
driverInfo = driverName;
|
||||
if (!driverMobile.isEmpty()) {
|
||||
driverInfo += " " + driverMobile;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取检疫证号(从检疫票URL中提取,如果有的话)
|
||||
String quarantineCertNo = "";
|
||||
if (delivery.getQuarantineTickeyUrl() != null && !delivery.getQuarantineTickeyUrl().isEmpty()) {
|
||||
// 可以根据实际情况提取检疫证号,这里暂时留空
|
||||
quarantineCertNo = "";
|
||||
}
|
||||
|
||||
// 获取订单编号(优先使用deliveryNumber,如果没有则使用orderId)
|
||||
String orderNumber = delivery.getDeliveryNumber() != null ? delivery.getDeliveryNumber() : "";
|
||||
if (orderNumber.isEmpty() && delivery.getOrderId() != null) {
|
||||
orderNumber = "ORDER-" + delivery.getOrderId();
|
||||
}
|
||||
|
||||
// 查询订单信息,获取结算方式描述、单价等信息
|
||||
String weightColumnTitle = "下车总重量(斤)"; // 默认值
|
||||
Integer settlementType = null; // 结算方式:1-上车重量,2-下车重量,3-按肉价结算
|
||||
java.math.BigDecimal unitPrice = null; // 单价(元/斤)
|
||||
|
||||
if (delivery.getOrderId() != null) {
|
||||
try {
|
||||
Order order = orderMapper.selectById(delivery.getOrderId());
|
||||
if (order != null) {
|
||||
// 获取结算方式
|
||||
if (order.getSettlementType() != null) {
|
||||
settlementType = order.getSettlementType();
|
||||
if (settlementType == 1) {
|
||||
// 上车重量 -> 上车总重量(斤)
|
||||
weightColumnTitle = "上车总重量(斤)";
|
||||
logger.info("订单结算方式为上车重量,使用重量字段标题: {}", weightColumnTitle);
|
||||
} else if (settlementType == 2) {
|
||||
// 下车重量 -> 下车总重量(斤)
|
||||
weightColumnTitle = "下车总重量(斤)";
|
||||
logger.info("订单结算方式为下车重量,使用重量字段标题: {}", weightColumnTitle);
|
||||
} else if (settlementType == 3) {
|
||||
// 按肉价结算 -> 保持默认"下车总重量(斤)"
|
||||
weightColumnTitle = "下车总重量(斤)";
|
||||
logger.info("订单结算方式为按肉价结算,使用默认重量字段标题: {}", weightColumnTitle);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取单价(元/斤)
|
||||
if (order.getFirmPrice() != null) {
|
||||
unitPrice = order.getFirmPrice();
|
||||
logger.info("获取订单单价: firmPrice={}", unitPrice);
|
||||
} else {
|
||||
logger.warn("订单单价为空,订单ID: {}", delivery.getOrderId());
|
||||
}
|
||||
} else {
|
||||
logger.warn("订单不存在,订单ID: {}, 使用默认值", delivery.getOrderId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("查询订单信息失败,订单ID: {}", delivery.getOrderId(), e);
|
||||
}
|
||||
} else {
|
||||
logger.warn("运单没有关联订单,使用默认值");
|
||||
}
|
||||
|
||||
// 计算总重量(斤)和总金额(元)
|
||||
Integer ratedQuantity = delivery.getRatedQuantity(); // 下车总数量(头)
|
||||
Double totalWeightJin = null; // 总重量(斤)
|
||||
Double totalAmount = null; // 总金额(元)
|
||||
|
||||
// 解析重量字段(String类型,如"1000.00")
|
||||
Double emptyWeightKg = null;
|
||||
Double entruckWeightKg = null;
|
||||
Double landingEntruckWeightKg = null;
|
||||
|
||||
try {
|
||||
if (delivery.getEmptyWeight() != null && !delivery.getEmptyWeight().trim().isEmpty()) {
|
||||
emptyWeightKg = Double.parseDouble(delivery.getEmptyWeight().trim());
|
||||
}
|
||||
if (delivery.getEntruckWeight() != null && !delivery.getEntruckWeight().trim().isEmpty()) {
|
||||
entruckWeightKg = Double.parseDouble(delivery.getEntruckWeight().trim());
|
||||
}
|
||||
if (delivery.getLandingEntruckWeight() != null && !delivery.getLandingEntruckWeight().trim().isEmpty()) {
|
||||
landingEntruckWeightKg = Double.parseDouble(delivery.getLandingEntruckWeight().trim());
|
||||
}
|
||||
|
||||
// 根据结算方式计算总重量(斤)
|
||||
// 注意:重量字段存储的是公斤(kg),需要转换为斤(斤 = kg * 2)
|
||||
if (settlementType != null && emptyWeightKg != null) {
|
||||
if (settlementType == 1) {
|
||||
// 上车重量:计算 (entruckWeight - emptyWeight) * 2
|
||||
if (entruckWeightKg != null) {
|
||||
totalWeightJin = (entruckWeightKg - emptyWeightKg) * 2;
|
||||
logger.info("计算上车总重量: entruckWeight={}kg, emptyWeight={}kg, 总重量={}斤",
|
||||
entruckWeightKg, emptyWeightKg, totalWeightJin);
|
||||
}
|
||||
} else if (settlementType == 2) {
|
||||
// 下车重量:计算 (landingEntruckWeight - emptyWeight) * 2
|
||||
if (landingEntruckWeightKg != null) {
|
||||
totalWeightJin = (landingEntruckWeightKg - emptyWeightKg) * 2;
|
||||
logger.info("计算下车总重量: landingEntruckWeight={}kg, emptyWeight={}kg, 总重量={}斤",
|
||||
landingEntruckWeightKg, emptyWeightKg, totalWeightJin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算总金额(元) = 总重量(斤) * 单价(元/斤)
|
||||
if (totalWeightJin != null && unitPrice != null) {
|
||||
totalAmount = totalWeightJin * unitPrice.doubleValue();
|
||||
// 四舍五入保留2位小数
|
||||
totalAmount = java.math.BigDecimal.valueOf(totalAmount)
|
||||
.setScale(2, java.math.RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
logger.info("计算总金额: 总重量={}斤, 单价={}元/斤, 总金额={}元",
|
||||
totalWeightJin, unitPrice, totalAmount);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.error("解析重量字段失败: emptyWeight={}, entruckWeight={}, landingEntruckWeight={}",
|
||||
delivery.getEmptyWeight(), delivery.getEntruckWeight(),
|
||||
delivery.getLandingEntruckWeight(), e);
|
||||
}
|
||||
|
||||
// 格式化数值为字符串(保留2位小数)
|
||||
String ratedQuantityStr = ratedQuantity != null ? String.valueOf(ratedQuantity) : "";
|
||||
String totalWeightStr = totalWeightJin != null ?
|
||||
String.format("%.2f", totalWeightJin) : "";
|
||||
String unitPriceStr = unitPrice != null ?
|
||||
unitPrice.setScale(2, java.math.RoundingMode.HALF_UP).toString() : "";
|
||||
String totalAmountStr = totalAmount != null ?
|
||||
String.format("%.2f", totalAmount) : "";
|
||||
|
||||
// 生成HTML内容
|
||||
String htmlContent = generateAcceptanceFormHtml(
|
||||
orderNumber, supplierName, buyerName, startLocation,
|
||||
departureTime, endLocation, quarantineCertNo,
|
||||
driverInfo, licensePlate, weightColumnTitle,
|
||||
ratedQuantityStr, totalWeightStr, unitPriceStr, totalAmountStr
|
||||
);
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setHeader("Content-Disposition",
|
||||
"inline; filename=\"" + URLEncoder.encode("牛只发车验收单_" + orderNumber + ".html", "UTF-8") + "\"");
|
||||
|
||||
// 写入响应
|
||||
response.getWriter().write(htmlContent);
|
||||
response.getWriter().flush();
|
||||
|
||||
logger.info("验收单生成成功,运单ID: {}, 运单号: {}", id, orderNumber);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("生成验收单失败,运单ID: {}", id, e);
|
||||
try {
|
||||
if (!response.isCommitted()) {
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
response.setContentType("text/plain;charset=UTF-8");
|
||||
response.getWriter().write("生成验收单失败:" + e.getMessage());
|
||||
}
|
||||
} catch (IOException ioException) {
|
||||
logger.error("写入错误响应失败", ioException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验收单HTML内容(严格按照图片格式要求)
|
||||
* @param weightColumnTitle 重量字段标题(根据结算方式动态设置:上车总重量(斤) 或 下车总重量(斤))
|
||||
* @param ratedQuantity 下车总数量(头)
|
||||
* @param totalWeight 总重量(斤)
|
||||
* @param unitPrice 单价(元/斤)
|
||||
* @param totalAmount 总金额(元)
|
||||
*/
|
||||
private String generateAcceptanceFormHtml(String orderNumber, String supplierName,
|
||||
String buyerName, String startLocation,
|
||||
String departureTime, String endLocation,
|
||||
String quarantineCertNo, String driverInfo,
|
||||
String licensePlate, String weightColumnTitle,
|
||||
String ratedQuantity, String totalWeight,
|
||||
String unitPrice, String totalAmount) {
|
||||
|
||||
StringBuilder html = new StringBuilder();
|
||||
html.append("<!DOCTYPE html>\n");
|
||||
html.append("<html>\n");
|
||||
html.append("<head>\n");
|
||||
html.append(" <meta charset=\"UTF-8\">\n");
|
||||
html.append(" <title>牛只发车验收单</title>\n");
|
||||
html.append(" <style>\n");
|
||||
html.append(" @media print {\n");
|
||||
html.append(" body { margin: 0; }\n");
|
||||
html.append(" .no-print { display: none; }\n");
|
||||
html.append(" }\n");
|
||||
html.append(" body { \n");
|
||||
html.append(" font-family: \"Microsoft YaHei\", \"SimSun\", Arial, sans-serif; \n");
|
||||
html.append(" margin: 20px; \n");
|
||||
html.append(" line-height: 1.4;\n");
|
||||
html.append(" }\n");
|
||||
html.append(" .header { \n");
|
||||
html.append(" text-align: center; \n");
|
||||
html.append(" font-size: 20px; \n");
|
||||
html.append(" font-weight: bold; \n");
|
||||
html.append(" margin-bottom: 30px;\n");
|
||||
html.append(" border-bottom: 2px solid #000;\n");
|
||||
html.append(" padding-bottom: 10px;\n");
|
||||
html.append(" }\n");
|
||||
html.append(" .order-number { \n");
|
||||
html.append(" text-align: right; \n");
|
||||
html.append(" margin-bottom: 10px; \n");
|
||||
html.append(" font-size: 14px;\n");
|
||||
html.append(" }\n");
|
||||
html.append(" table { \n");
|
||||
html.append(" width: 100%; \n");
|
||||
html.append(" border-collapse: collapse; \n");
|
||||
html.append(" margin-bottom: 20px; \n");
|
||||
html.append(" }\n");
|
||||
html.append(" table td, table th { \n");
|
||||
html.append(" border: 1px solid #000; \n");
|
||||
html.append(" padding: 8px; \n");
|
||||
html.append(" text-align: left; \n");
|
||||
html.append(" }\n");
|
||||
html.append(" table th { \n");
|
||||
html.append(" background-color: #f0f0f0; \n");
|
||||
html.append(" font-weight: bold; \n");
|
||||
html.append(" }\n");
|
||||
html.append(" .print-button { \n");
|
||||
html.append(" padding: 10px 20px; \n");
|
||||
html.append(" background-color: #409EFF; \n");
|
||||
html.append(" color: white; \n");
|
||||
html.append(" border: none; \n");
|
||||
html.append(" border-radius: 4px; \n");
|
||||
html.append(" cursor: pointer; \n");
|
||||
html.append(" font-size: 14px; \n");
|
||||
html.append(" }\n");
|
||||
html.append(" .print-button:hover { \n");
|
||||
html.append(" background-color: #66b1ff; \n");
|
||||
html.append(" }\n");
|
||||
html.append(" </style>\n");
|
||||
html.append("</head>\n");
|
||||
html.append("<body>\n");
|
||||
|
||||
// 附件2(左上角)
|
||||
html.append(" <div style=\"text-align: left; margin-bottom: 10px;\">附件2</div>\n");
|
||||
|
||||
// 标题(居中,带下划线)
|
||||
html.append(" <div class=\"header\">牛只发车验收单</div>\n");
|
||||
|
||||
// 订单编号(右上角)
|
||||
html.append(" <div class=\"order-number\">订单编号: ").append(orderNumber).append("</div>\n");
|
||||
|
||||
// 基本信息表格(4行2列)
|
||||
html.append(" <table>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td style=\"width: 15%;\">供货单位</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\">").append(supplierName).append("</td>\n");
|
||||
html.append(" <td style=\"width: 15%;\">收货单位</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\">").append(buyerName).append("</td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>发车地点</td>\n");
|
||||
html.append(" <td>").append(startLocation).append("</td>\n");
|
||||
html.append(" <td>发车时间</td>\n");
|
||||
html.append(" <td>").append(departureTime).append("</td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>到达地点</td>\n");
|
||||
html.append(" <td>").append(endLocation).append("</td>\n");
|
||||
html.append(" <td>动物检疫合格证明编号</td>\n");
|
||||
html.append(" <td>").append(quarantineCertNo).append("</td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>司机姓名及联系方式</td>\n");
|
||||
html.append(" <td>").append(driverInfo).append("</td>\n");
|
||||
html.append(" <td>装车车牌号</td>\n");
|
||||
html.append(" <td>").append(licensePlate).append("</td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" </table>\n");
|
||||
|
||||
// 牛只明细表格(完整保留,但数据为空)
|
||||
html.append(" <table>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <th style=\"width: 5%;\">序号</th>\n");
|
||||
html.append(" <th style=\"width: 15%;\">活牛品种</th>\n");
|
||||
html.append(" <th style=\"width: 15%;\">单只体重范围</th>\n");
|
||||
html.append(" <th style=\"width: 12%;\">下车总数量(头)</th>\n");
|
||||
html.append(" <th style=\"width: 12%;\">").append(weightColumnTitle).append("</th>\n");
|
||||
html.append(" <th style=\"width: 10%;\">单价(元/斤)</th>\n");
|
||||
html.append(" <th style=\"width: 15%;\">总金额(元)</th>\n");
|
||||
html.append(" <th style=\"width: 16%;\">备注</th>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td>").append(ratedQuantity).append("</td>\n");
|
||||
html.append(" <td>").append(totalWeight).append("</td>\n");
|
||||
html.append(" <td>").append(unitPrice).append("</td>\n");
|
||||
html.append(" <td>").append(totalAmount).append("</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" </table>\n");
|
||||
|
||||
// 支付信息表格(完整保留,但数据为空)
|
||||
html.append(" <table>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td style=\"width: 15%;\">已支付货款时间</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\"></td>\n");
|
||||
html.append(" <td style=\"width: 15%;\">已支付货款金额</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\"></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>应支付尾款时间</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td>应支付尾款金额</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" </table>\n");
|
||||
|
||||
// 验收结论和签字盖章区域(完整保留,但数据为空)
|
||||
html.append(" <table>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td style=\"width: 15%;\">验收结论</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\"></td>\n");
|
||||
html.append(" <td style=\"width: 15%;\">验收时间</td>\n");
|
||||
html.append(" <td style=\"width: 35%;\"></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>供货单位指定验收人签字及联系方式</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td>收货单位指定验收人签字及联系方式</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" <tr>\n");
|
||||
html.append(" <td>供货单位盖章</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" <td>收货单位盖章</td>\n");
|
||||
html.append(" <td></td>\n");
|
||||
html.append(" </tr>\n");
|
||||
html.append(" </table>\n");
|
||||
|
||||
// 打印按钮(不打印时显示)
|
||||
html.append(" <div class=\"no-print\">\n");
|
||||
html.append(" <button class=\"print-button\" onclick=\"window.print()\">打印/保存为PDF</button>\n");
|
||||
html.append(" <p style=\"color: #666; font-size: 12px;\">\n");
|
||||
html.append(" 提示:点击\"打印/保存为PDF\"按钮可以将此文档打印或保存为PDF格式。\n");
|
||||
html.append(" 在打印对话框中,您也可以选择\"另存为PDF\"来保存文档。\n");
|
||||
html.append(" </p>\n");
|
||||
html.append(" </div>\n");
|
||||
html.append("</body>\n");
|
||||
html.append("</html>\n");
|
||||
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -107,13 +107,6 @@ public class DeliveryCreateDto {
|
||||
@Min(value = 1, message = "牛只数量至少为1")
|
||||
private Integer cattleCount;
|
||||
|
||||
/**
|
||||
* 预估重量(公斤)
|
||||
*/
|
||||
@NotNull(message = "预估重量不能为空")
|
||||
@DecimalMin(value = "0.01", message = "预估重量必须大于0")
|
||||
private Double estimatedWeight;
|
||||
|
||||
/**
|
||||
* 检疫证号
|
||||
*/
|
||||
|
||||
@@ -47,6 +47,12 @@ public class Order implements Serializable {
|
||||
@TableField("settlement_type")
|
||||
private Integer settlementType;
|
||||
|
||||
/**
|
||||
* 约定价格(元/斤)
|
||||
*/
|
||||
@TableField("firm_price")
|
||||
private java.math.BigDecimal firmPrice;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记(0-正常,1-已删除)
|
||||
*/
|
||||
|
||||
@@ -468,8 +468,8 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
@Override
|
||||
public AjaxResult createDelivery(DeliveryCreateDto dto) {
|
||||
// 入参日志
|
||||
logger.info("创建装车订单: shipperId={}, buyerId={}, plateNumber={}, driverName={}",
|
||||
dto.getShipperId(), dto.getBuyerId(), dto.getPlateNumber(), dto.getDriverName());
|
||||
logger.info("创建装车订单: shipperId={}, buyerId={}, plateNumber={}, driverName={}, cattleCount={}",
|
||||
dto.getShipperId(), dto.getBuyerId(), dto.getPlateNumber(), dto.getDriverName(), dto.getCattleCount());
|
||||
// 校验时间逻辑
|
||||
if (dto.getEstimatedArrivalTime().before(dto.getEstimatedDepartureTime())) {
|
||||
return AjaxResult.error("预计到达时间必须晚于出发时间");
|
||||
@@ -546,6 +546,14 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
delivery.setEstimatedDepartureTime(dto.getEstimatedDepartureTime());
|
||||
// 预计到达时间
|
||||
delivery.setEstimatedDeliveryTime(dto.getEstimatedArrivalTime());
|
||||
// 装车数量(牛只数量)
|
||||
if (dto.getCattleCount() != null && dto.getCattleCount() > 0) {
|
||||
delivery.setRatedQuantity(dto.getCattleCount());
|
||||
logger.info("设置装车数量: ratedQuantity={}", dto.getCattleCount());
|
||||
} else {
|
||||
logger.warn("装车数量为空或无效: cattleCount={}, 跳过设置", dto.getCattleCount());
|
||||
delivery.setRatedQuantity(null);
|
||||
}
|
||||
// 过磅重量:将空字符串转换为null,避免数据库DECIMAL字段类型错误
|
||||
delivery.setEmptyWeight(StringUtils.isNotEmpty(dto.getEmptyWeight()) ? dto.getEmptyWeight() : null);
|
||||
delivery.setEntruckWeight(StringUtils.isNotEmpty(dto.getEntruckWeight()) ? dto.getEntruckWeight() : null);
|
||||
@@ -592,8 +600,9 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
|
||||
// 保存运送清单
|
||||
boolean saved = this.save(delivery);
|
||||
logger.info("保存装车订单: deliveryNumber={}, licensePlate={}, driverName={}, status={}",
|
||||
delivery.getDeliveryNumber(), delivery.getLicensePlate(), delivery.getDriverName(), delivery.getStatus());
|
||||
logger.info("保存装车订单: deliveryNumber={}, licensePlate={}, driverName={}, status={}, ratedQuantity={}",
|
||||
delivery.getDeliveryNumber(), delivery.getLicensePlate(), delivery.getDriverName(),
|
||||
delivery.getStatus(), delivery.getRatedQuantity());
|
||||
if (!saved) {
|
||||
return AjaxResult.error("创建失败");
|
||||
}
|
||||
@@ -679,6 +688,9 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
// 获取当前登录用户
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
|
||||
// 入参日志
|
||||
logger.info("更新运送清单: deliveryId={}, ratedQuantity={}", dto.getDeliveryId(), dto.getRatedQuantity());
|
||||
|
||||
// 查询运送清单是否存在
|
||||
Delivery delivery = this.getById(dto.getDeliveryId());
|
||||
if (delivery == null) {
|
||||
@@ -694,8 +706,11 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
if (dto.getDeliveryTitle() != null) {
|
||||
delivery.setDeliveryTitle(dto.getDeliveryTitle());
|
||||
}
|
||||
if (dto.getRatedQuantity() != null) {
|
||||
if (dto.getRatedQuantity() != null && dto.getRatedQuantity() > 0) {
|
||||
delivery.setRatedQuantity(dto.getRatedQuantity());
|
||||
logger.info("更新装车数量: ratedQuantity={}", dto.getRatedQuantity());
|
||||
} else if (dto.getRatedQuantity() != null && dto.getRatedQuantity() <= 0) {
|
||||
logger.warn("装车数量无效: ratedQuantity={}, 跳过更新", dto.getRatedQuantity());
|
||||
}
|
||||
if (dto.getStartLocation() != null) {
|
||||
delivery.setStartLocation(dto.getStartLocation());
|
||||
@@ -775,6 +790,7 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
|
||||
// 保存更新
|
||||
boolean updated = this.updateById(delivery);
|
||||
logger.info("更新运送清单成功: deliveryId={}, ratedQuantity={}", dto.getDeliveryId(), delivery.getRatedQuantity());
|
||||
if (updated) {
|
||||
return AjaxResult.success("编辑成功");
|
||||
} else {
|
||||
|
||||
@@ -119,7 +119,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult addOrder(Order order) {
|
||||
logger.info("开始新增订单,买方:{},卖方:{},结算方式:{}", order.getBuyerId(), order.getSellerId(), order.getSettlementType());
|
||||
logger.info("开始新增订单,买方:{},卖方:{},结算方式:{},约定价格:{}",
|
||||
order.getBuyerId(), order.getSellerId(), order.getSettlementType(), order.getFirmPrice());
|
||||
|
||||
try {
|
||||
// 验证结算方式
|
||||
@@ -128,6 +129,17 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
return AjaxResult.error("结算方式无效");
|
||||
}
|
||||
|
||||
// 验证约定价格(firm_price 字段是 NOT NULL)
|
||||
if (order.getFirmPrice() == null) {
|
||||
logger.error("约定价格不能为空");
|
||||
return AjaxResult.error("约定价格不能为空");
|
||||
}
|
||||
// 确保约定价格不为负数
|
||||
if (order.getFirmPrice().compareTo(java.math.BigDecimal.ZERO) < 0) {
|
||||
logger.error("约定价格不能小于0:{}", order.getFirmPrice());
|
||||
return AjaxResult.error("约定价格不能小于0");
|
||||
}
|
||||
|
||||
// 设置创建人和创建时间
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
order.setCreatedBy(userId);
|
||||
@@ -160,7 +172,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
logger.info("开始更新订单,订单ID:{}", order.getId());
|
||||
logger.info("开始更新订单,订单ID:{},约定价格:{}", order.getId(), order.getFirmPrice());
|
||||
|
||||
try {
|
||||
// 验证订单是否存在
|
||||
@@ -176,6 +188,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
return AjaxResult.error("结算方式无效");
|
||||
}
|
||||
|
||||
// 验证约定价格(如果提供了)
|
||||
if (order.getFirmPrice() != null) {
|
||||
// 确保约定价格不为负数
|
||||
if (order.getFirmPrice().compareTo(java.math.BigDecimal.ZERO) < 0) {
|
||||
logger.error("约定价格不能小于0:{}", order.getFirmPrice());
|
||||
return AjaxResult.error("约定价格不能小于0");
|
||||
}
|
||||
} else {
|
||||
// 如果更新时没有提供 firm_price,保留原有值(因为字段是 NOT NULL)
|
||||
order.setFirmPrice(existingOrder.getFirmPrice());
|
||||
}
|
||||
|
||||
// 设置更新人和更新时间
|
||||
try {
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
|
||||
@@ -81,5 +81,12 @@ public class TencentCloudUtil {
|
||||
return targetUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取COS客户端
|
||||
* @return COS客户端实例
|
||||
*/
|
||||
public static COSClient getCosClient() {
|
||||
return cosClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user