配送单据接口修改

This commit is contained in:
2025-10-17 09:33:53 +08:00
parent ab9a48f968
commit e24d6ef0b4
5 changed files with 339 additions and 64 deletions

View File

@@ -0,0 +1,189 @@
package com.delivery.common.utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 本地图片保存工具
* - 根目录photo.root默认 /data/upload/images
* - 目录结构:{documentType}/yyyy-MM-dd/
* - 文件命名:
* 入库billNo_gysMc_yyyyMMddHHmmssSSS_index.ext
* 出库billNo_xmMs_yyyyMMddHHmmssSSS_index.ext
*/
@Component
public class LocalPhotoUtil {
/** 磁盘根目录Linux 默认) */
@Value("${photo.root:/data/upload/images}")
private String rootPath;
@Value("${photo.base-url:http://192.168.1.28/files}")
private String baseUrl;
private static final String ILLEGAL_CHARS = "\\/:*?\"<>|";
private static final long MAX_SIZE = 10 * 1024 * 1024; // 10MB
private static final Set<String> ALLOWED =
new HashSet<>(Arrays.asList("jpg","jpeg","png","gif","webp","bmp"));
/** yyyy-MM-dd目录 */
private String today() {
return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
}
/** yyyyMMddHHmmssSSS文件戳 */
private String nowStamp() {
return new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
}
/**
* 生成基础名:
* - 入库(photoType=0)billNo_gysMc
* - 出库(photoType=1)billNo_xmMs
* - 若为空 → 一律替换成 "无"
*/
public String buildBaseName(String photoType, String billNo, String xmMs, String gysMc) {
String safeBillNo = sanitize(defaultString(billNo));
String part;
if ("0".equals(photoType)) {
part = sanitize(defaultString(gysMc, ""));
} else {
part = sanitize(defaultString(xmMs, ""));
}
return sanitize(safeBillNo + "_" + part);
}
/**
* 保存单个文件
* @param file 文件
* @param subDir 一级子目录documentType
* @param baseName 基础名
* @param index 序号(从1开始)
*/
public SaveResult saveOne(MultipartFile file, String subDir, String baseName, int index) throws Exception {
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("文件为空");
}
if (file.getSize() > MAX_SIZE) {
throw new IllegalArgumentException("图片不能超过10MB");
}
String ext = resolveExt(file);
String safeSub = sanitize(limitLen(defaultString(subDir, ""), 40));
String dirPart = (safeSub.isEmpty() ? "" : safeSub + File.separator) + today() + File.separator;
String stamp = nowStamp();
String safeBase = sanitize(limitLen(baseName, 80));
String fileName = safeBase + "_" + stamp + "_" + index + ext;
File dir = new File(ensureTrailingSlash(rootPath), dirPart);
Files.createDirectories(dir.toPath());
File dest = new File(dir, fileName);
File tmp = new File(dir, fileName + ".uploading");
try (InputStream in = file.getInputStream()) {
Files.copy(in, tmp.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
}
Files.move(tmp.toPath(), dest.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
SaveResult r = new SaveResult();
String webPath = (dirPart + fileName).replace("\\", "/");
r.setWebPath(webPath); // /{subDir}/yyyy-MM-dd/xxx.jpg
r.setFileName(fileName);
r.setAbsPath(dest.getAbsolutePath());
r.setUrl(joinUrl(baseUrl, webPath)); // http://ip/files/...
r.setSize(file.getSize());
return r;
}
/** 批量保存 */
public List<SaveResult> saveBatch(List<MultipartFile> files, String subDir, String baseName) throws Exception {
if (files == null || files.isEmpty()) return Collections.emptyList();
List<SaveResult> list = new ArrayList<>(files.size());
for (int i = 0; i < files.size(); i++) {
list.add(saveOne(files.get(i), subDir, baseName, i + 1));
}
return list;
}
/** 扩展名解析 + 白名单校验 */
private String resolveExt(MultipartFile file) {
String origin = file.getOriginalFilename();
if (origin != null) {
int dot = origin.lastIndexOf('.');
if (dot >= 0) {
String pure = origin.substring(dot + 1).toLowerCase(Locale.ROOT);
if (ALLOWED.contains(pure)) return "." + pure;
}
}
String ct = String.valueOf(file.getContentType()).toLowerCase(Locale.ROOT);
if (ct.contains("png")) return ".png";
if (ct.contains("jpeg") || ct.contains("jpg")) return ".jpg";
if (ct.contains("gif")) return ".gif";
if (ct.contains("webp")) return ".webp";
if (ct.contains("bmp")) return ".bmp";
return ".bin";
}
/** 清洗文件名 */
public String sanitize(String name) {
if (name == null) return "unnamed";
String t = name.trim().replaceAll("\\s+", " ");
StringBuilder sb = new StringBuilder(t.length());
for (int i = 0; i < t.length(); i++) {
char c = t.charAt(i);
sb.append(ILLEGAL_CHARS.indexOf(c) >= 0 ? '_' : c);
}
String out = sb.toString();
String upper = out.toUpperCase(Locale.ROOT);
if (upper.matches("CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]")) {
out = "_" + out;
}
if (out.length() > 100) out = out.substring(0, 100);
return out;
}
private String defaultString(String s) { return s == null ? "" : s; }
private String defaultString(String s, String def) { return (s == null || s.isEmpty()) ? def : s; }
private String ensureTrailingSlash(String p) {
return (p.endsWith("/") || p.endsWith("\\")) ? p : (p + File.separator);
}
private String limitLen(String s, int max) {
if (s == null) return "";
return s.length() > max ? s.substring(0, max) : s;
}
private String joinUrl(String base, String path) {
String b = base.endsWith("/") ? base.substring(0, base.length()-1) : base;
String p = path.startsWith("/") ? path.substring(1) : path;
return b + "/" + p;
}
/** 返回值对象 */
public static class SaveResult {
private String webPath; // 相对Web路径(/subDir/yyyy-MM-dd/xxx.jpg)
private String fileName; // 文件名
private String absPath; // 服务器绝对路径
private String url; // 可直接访问的URL
private long size; // 字节
public String getWebPath() { return webPath; }
public void setWebPath(String webPath) { this.webPath = webPath; }
public String getFileName() { return fileName; }
public void setFileName(String fileName) { this.fileName = fileName; }
public String getAbsPath() { return absPath; }
public void setAbsPath(String absPath) { this.absPath = absPath; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public long getSize() { return size; }
public void setSize(long size) { this.size = size; }
}
}

View File

@@ -39,7 +39,7 @@ public class DeliveryOrderController extends BaseController
/**
* 查询配送单据主列表
*/
@PreAuthorize("@ss.hasPermi('document:order:list')")
// @PreAuthorize("@ss.hasPermi('document:order:list')")
@GetMapping("/list")
public TableDataInfo list(DeliveryOrder deliveryOrder)
{
@@ -64,7 +64,7 @@ public class DeliveryOrderController extends BaseController
/**
* 获取配送单据主详细信息
*/
@PreAuthorize("@ss.hasPermi('document:order:query')")
// @PreAuthorize("@ss.hasPermi('document:order:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
@@ -105,6 +105,11 @@ public class DeliveryOrderController extends BaseController
}
/**
* 保存配送单
* @param dto
* @return
*/
// @PreAuthorize("@ss.hasPermi('document:order:add')")
// @Log(title = "配送单据主-保存(含附件)", businessType = BusinessType.INSERT)
@PostMapping("/save")

View File

@@ -2,6 +2,7 @@ package com.delivery.project.document.domain;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.delivery.framework.web.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -115,6 +116,12 @@ public class DeliveryOrder extends BaseEntity
@Excel(name = "是否删除", readConverterExp = "0=正常,1=已删除")
private String isDelete;
/** 连表查询用:附件列表 */
private List<DeliveryAttachment> attachments;
public List<DeliveryAttachment> getAttachments() { return attachments; }
public void setAttachments(List<DeliveryAttachment> attachments) { this.attachments = attachments; }
public void setId(Long id)
{
this.id = id;