From d39006059700d2de49ec2b6961ff7719a50550d8 Mon Sep 17 00:00:00 2001 From: wenshijun Date: Fri, 19 Sep 2025 11:23:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=BA=E5=BA=93=E5=9B=BE=E7=89=87=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E9=80=BB=E8=BE=91=E4=BF=AE=E6=94=B9=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=89=93=E5=8D=B0=E6=A0=87=E7=AD=BE=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E5=90=91pk=E6=95=B0=E6=8D=AE=E5=BA=93=E6=8F=92?= =?UTF-8?q?=E5=85=A5=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zg/common/utils/LocalPhotoUtil.java | 67 +++++++------------ .../wisdom/controller/PhotoController.java | 26 ++++--- .../wisdom/controller/PkDatController.java | 27 ++++++++ .../project/wisdom/domain/dto/PkDatDTO.java | 26 +++++++ .../zg/project/wisdom/mapper/PkDatMapper.java | 11 +++ .../project/wisdom/service/IPkDatService.java | 14 ++++ .../project/wisdom/service/PhotoService.java | 18 +++-- .../wisdom/service/impl/PhotoServiceImpl.java | 45 +++++++------ .../wisdom/service/impl/PkDatServiceImpl.java | 24 +++++++ .../resources/mybatis/wisdom/PkDatMapper.xml | 18 +++++ .../resources/mybatis/wisdom/RkInfoMapper.xml | 2 + 11 files changed, 196 insertions(+), 82 deletions(-) create mode 100644 src/main/java/com/zg/project/wisdom/controller/PkDatController.java create mode 100644 src/main/java/com/zg/project/wisdom/domain/dto/PkDatDTO.java create mode 100644 src/main/java/com/zg/project/wisdom/mapper/PkDatMapper.java create mode 100644 src/main/java/com/zg/project/wisdom/service/IPkDatService.java create mode 100644 src/main/java/com/zg/project/wisdom/service/impl/PkDatServiceImpl.java create mode 100644 src/main/resources/mybatis/wisdom/PkDatMapper.xml diff --git a/src/main/java/com/zg/common/utils/LocalPhotoUtil.java b/src/main/java/com/zg/common/utils/LocalPhotoUtil.java index 7747295..082951b 100644 --- a/src/main/java/com/zg/common/utils/LocalPhotoUtil.java +++ b/src/main/java/com/zg/common/utils/LocalPhotoUtil.java @@ -13,18 +13,17 @@ import java.util.*; /** * 本地图片保存工具 * - 根目录:photo.root(默认 D:\photo) - * - 目录结构:{subDir}/yyyy-MM-dd/ - * - 文件命名:{billNo}_{sapNo}_{xmMs}_{yyyyMMddHHmmssSSS}_{index}.{ext} - * - 返回:相对web路径(用于拼接 /photo/ 前缀生成可访问URL)与文件名 + * - 目录结构:{documentType}/yyyy-MM-dd/ + * - 文件命名: + * 入库:billNo_gysMc_yyyyMMddHHmmssSSS_index.ext + * 出库:billNo_xmMs_yyyyMMddHHmmssSSS_index.ext */ @Component public class LocalPhotoUtil { - /** 本地根目录,可在 yml 配置:photo.root: D:\photo */ @Value("${photo.root:D:\\\\photo}") private String rootPath; - /** 非法文件名字符(Windows) */ private static final String ILLEGAL_CHARS = "\\/:*?\"<>|"; /** yyyy-MM-dd(目录) */ @@ -38,22 +37,28 @@ public class LocalPhotoUtil { } /** - * 组装基础文件名:billNo_sapNo_xmMs(不含后缀、不含时间戳/序号) + * 生成基础名: + * - 入库(photoType=0):billNo_gysMc + * - 出库(photoType=1):billNo_xmMs + * - 若为空 → 一律替换成 "无" */ - public String buildBaseName(String billNo, String xmMs) { - String b = defaultString(billNo); - String x = defaultString(xmMs); - String joined = String.join("_", b, x); - return sanitize(joined); + 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 一级子目录(建议 "photo" 固定,也可按业务传入) - * @param baseName 基础名(不含扩展名;可用 buildBaseName 生成) - * @param index 序号(从1开始),用于同批次区分 - * @return SaveResult(webPath, fileName) + * @param subDir 一级子目录(documentType) + * @param baseName 基础名 + * @param index 序号 */ public SaveResult saveOne(MultipartFile file, String subDir, String baseName, int index) throws Exception { String ext = resolveExt(file); @@ -62,7 +67,6 @@ public class LocalPhotoUtil { String stamp = nowStamp(); String safeBase = sanitize(baseName); - // 最终文件名:base_时间戳_序号.ext String fileName = safeBase + "_" + stamp + "_" + index + ext; File dir = new File(rootPath, dirPart); @@ -76,16 +80,13 @@ public class LocalPhotoUtil { } SaveResult r = new SaveResult(); - r.setWebPath((dirPart + fileName).replace("\\", "/")); // e.g. photo/2025-09-01/xxx.jpg + r.setWebPath((dirPart + fileName).replace("\\", "/")); r.setFileName(fileName); return r; } /** - * 批量保存(顺序与入参 files 一致) - * @param files 文件列表 - * @param subDir 一级子目录(建议传 "photo") - * @param baseName 基础名(不含扩展名) + * 批量保存 */ public List saveBatch(List files, String subDir, String baseName) throws Exception { if (files == null || files.isEmpty()) { @@ -98,27 +99,14 @@ public class LocalPhotoUtil { return list; } - /** - * 便捷方法:直接传业务字段(内部会调用 buildBaseName) - * @param files 多文件 - * @param subDir 一级子目录(建议 "photo") - * @param billNo 单据号 - * @param xmMs 项目描述 - */ - public List saveBatchByBiz(List files, String subDir, - String billNo, String xmMs) throws Exception { - String base = buildBaseName(billNo, xmMs); - return saveBatch(files, subDir, base); - } - - /** 解析扩展名:优先取原文件名,其次按 contentType 兜底 */ + /** 解析扩展名 */ private String resolveExt(MultipartFile file) { String origin = file.getOriginalFilename(); if (origin != null) { int dot = origin.lastIndexOf('.'); if (dot >= 0) { String ext = origin.substring(dot); - if (ext.length() <= 10) { // 简单防御:避免异常超长扩展名 + if (ext.length() <= 10) { return ext; } } @@ -129,7 +117,7 @@ public class LocalPhotoUtil { return ".bin"; } - /** 清洗文件名:去空白、替换非法字符、规避Windows保留名、限长 */ + /** 清洗文件名 */ public String sanitize(String name) { if (name == null) return "unnamed"; String t = name.trim().replaceAll("\\s+", " "); @@ -143,14 +131,12 @@ public class LocalPhotoUtil { 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; } - /** null 转空串;带默认值重载 */ private String defaultString(String s) { return s == null ? "" : s; } @@ -160,11 +146,8 @@ public class LocalPhotoUtil { /** 返回值对象 */ public static class SaveResult { - /** 相对web路径,例如 photo/2025-09-01/xxx.jpg(用于拼接 /photo/ 前缀生成URL) */ private String webPath; - /** 最终文件名(含扩展名) */ private String fileName; - public String getWebPath() { return webPath; } public void setWebPath(String webPath) { this.webPath = webPath; } public String getFileName() { return fileName; } diff --git a/src/main/java/com/zg/project/wisdom/controller/PhotoController.java b/src/main/java/com/zg/project/wisdom/controller/PhotoController.java index 16fea77..9526282 100644 --- a/src/main/java/com/zg/project/wisdom/controller/PhotoController.java +++ b/src/main/java/com/zg/project/wisdom/controller/PhotoController.java @@ -33,15 +33,19 @@ public class PhotoController { * - photoType:0(入库相关) / 1(出库相关) * - billNo:单据号 * - xmMs:项目描述 - * - sapNo:订单号 + * - documentType:单据类型(建文件夹用,不入库) + * - gysMc:供应商名称(入库时命名用) * 返回:每张图片的可访问 URL 列表 */ @PostMapping(value = "/upload/batch", consumes = "multipart/form-data") public AjaxResult uploadBatch(@RequestPart("files") List files, @RequestParam("photoType") String photoType, @RequestParam("billNo") String billNo, - @RequestParam("xmMs") String xmMs) { - List urls = photoService.uploadAndSave(files, photoType, billNo, xmMs); + @RequestParam(value = "xmMs", required = false, defaultValue = "") String xmMs, + @RequestParam(value = "documentType", required = false, defaultValue = "default") String documentType, + @RequestParam(value = "gysMc", required = false, defaultValue = "") String gysMc) { + // 有新参数就走新方法;没有则兼容旧逻辑 + List urls = photoService.uploadAndSave(files, photoType, billNo, xmMs, documentType, gysMc); return AjaxResult.success("上传成功", urls); } @@ -50,14 +54,14 @@ public class PhotoController { * 与多图参数一致,只是文件字段为 file * 返回:单张图片的可访问 URL */ - @PostMapping(value = "/upload", consumes = "multipart/form-data") - public AjaxResult upload(@RequestPart("file") MultipartFile file, - @RequestParam("photoType") String photoType, - @RequestParam("billNo") String billNo, - @RequestParam("xmMs") String xmMs) { - List urls = photoService.uploadAndSave(Collections.singletonList(file), photoType, billNo, xmMs); - return AjaxResult.success("上传成功", urls.isEmpty() ? null : urls.get(0)); - } +// @PostMapping(value = "/upload", consumes = "multipart/form-data") +// public AjaxResult upload(@RequestPart("file") MultipartFile file, +// @RequestParam("photoType") String photoType, +// @RequestParam("billNo") String billNo, +// @RequestParam("xmMs") String xmMs) { +// List urls = photoService.uploadAndSave(Collections.singletonList(file), photoType, billNo, xmMs); +// return AjaxResult.success("上传成功", urls.isEmpty() ? null : urls.get(0)); +// } /** * 【查询:按 billNo(可选photoType)取照片URL列表】 diff --git a/src/main/java/com/zg/project/wisdom/controller/PkDatController.java b/src/main/java/com/zg/project/wisdom/controller/PkDatController.java new file mode 100644 index 0000000..f701e5b --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/controller/PkDatController.java @@ -0,0 +1,27 @@ +package com.zg.project.wisdom.controller; + +import com.zg.framework.web.domain.AjaxResult; +import com.zg.project.wisdom.domain.dto.PkDatDTO; +import com.zg.project.wisdom.service.IPkDatService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RestController +@RequestMapping("/pk/dat") +public class PkDatController { + + @Resource + private IPkDatService pkDatService; + + /** + * 批量新增 pk.dat 数据 + */ + @PostMapping("/batchAdd") + public AjaxResult batchAdd(@RequestBody List list) { + int rows = pkDatService.batchInsertPkDat(list); + return rows > 0 ? AjaxResult.success("成功插入 " + rows + " 条记录") + : AjaxResult.error("插入失败"); + } +} diff --git a/src/main/java/com/zg/project/wisdom/domain/dto/PkDatDTO.java b/src/main/java/com/zg/project/wisdom/domain/dto/PkDatDTO.java new file mode 100644 index 0000000..f21952c --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/domain/dto/PkDatDTO.java @@ -0,0 +1,26 @@ +package com.zg.project.wisdom.domain.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 前端传参 DTO + */ +@Data +public class PkDatDTO { + /** 物料号 */ + private String wlNo; + /** 数量 */ + private BigDecimal realQty; + /** 物料凭证(SAP单号) */ + private String sapNo; + /** 供应商 */ + private String gysMc; + /** 备注 */ + private String remark; + /** 项目描述 */ + private String xmMs; + /** 库位 */ + private String pcode; +} diff --git a/src/main/java/com/zg/project/wisdom/mapper/PkDatMapper.java b/src/main/java/com/zg/project/wisdom/mapper/PkDatMapper.java new file mode 100644 index 0000000..e2d9656 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/mapper/PkDatMapper.java @@ -0,0 +1,11 @@ +package com.zg.project.wisdom.mapper; + +import com.zg.project.wisdom.domain.dto.PkDatDTO; + +import java.util.List; + +public interface PkDatMapper { + + int batchInsertPkDat(List list); + +} diff --git a/src/main/java/com/zg/project/wisdom/service/IPkDatService.java b/src/main/java/com/zg/project/wisdom/service/IPkDatService.java new file mode 100644 index 0000000..290d0cb --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/service/IPkDatService.java @@ -0,0 +1,14 @@ +package com.zg.project.wisdom.service; + +import com.zg.project.wisdom.domain.dto.PkDatDTO; + +import java.util.List; + +public interface IPkDatService { + /** + * 批量插入 pk.dat 数据 + * @param list DTO 列表 + * @return 插入行数 + */ + int batchInsertPkDat(List list); +} diff --git a/src/main/java/com/zg/project/wisdom/service/PhotoService.java b/src/main/java/com/zg/project/wisdom/service/PhotoService.java index 62d744d..fc656e0 100644 --- a/src/main/java/com/zg/project/wisdom/service/PhotoService.java +++ b/src/main/java/com/zg/project/wisdom/service/PhotoService.java @@ -14,16 +14,20 @@ public interface PhotoService { /** * 多图上传并落库,返回每张图片的可访问URL * - * @param files 图片文件列表(必传) - * @param photoType 照片业务类型:0=入库相关,1=出库相关(必填) - * @param billNo 单据号(必填,用于关联) - * @param xmMs 项目描述(用于文件命名,可为空) + * @param files 图片文件列表(必传) + * @param photoType 照片业务类型:0=入库相关,1=出库相关(必填) + * @param billNo 单据号(必填,用于关联) + * @param xmMs 项目描述(出库时命名用,可为空) + * @param documentType 单据类型(用于目录结构,不入库表) + * @param gysMc 供应商名称(入库时命名用) * @return URLs 列表(每个元素都是可直接 的地址) */ List uploadAndSave(List files, - String photoType, String billNo, - String xmMs); - + String photoType, + String billNo, + String xmMs, + String documentType, + String gysMc); /** * 按 billNo(可选 photoType)查询照片 URL 列表 diff --git a/src/main/java/com/zg/project/wisdom/service/impl/PhotoServiceImpl.java b/src/main/java/com/zg/project/wisdom/service/impl/PhotoServiceImpl.java index 78341a0..9aff2ee 100644 --- a/src/main/java/com/zg/project/wisdom/service/impl/PhotoServiceImpl.java +++ b/src/main/java/com/zg/project/wisdom/service/impl/PhotoServiceImpl.java @@ -38,10 +38,13 @@ public class PhotoServiceImpl implements PhotoService { @Override @Transactional(rollbackFor = Exception.class) public List uploadAndSave(List files, - String photoType, String billNo, - String xmMs) { + String photoType, + String billNo, + String xmMs, + String documentType, + String gysMc) { - // ========= 1. 入参校验 ========= + // 1. 基础校验 if (files == null || files.isEmpty()) { throw new IllegalArgumentException("请选择要上传的图片"); } @@ -51,48 +54,46 @@ public class PhotoServiceImpl implements PhotoService { if (StringUtils.isBlank(billNo)) { throw new IllegalArgumentException("billNo 不能为空"); } + if (StringUtils.isBlank(documentType)) { + documentType = "default"; // 硬编码兜底 + } - // 组装基础文件名:billNo_sapNo_xmMs(内部会做非法字符清洗) - final String baseName = localPhotoUtil.buildBaseName( - StringUtils.defaultString(billNo), - StringUtils.defaultString(xmMs)); + // 2. xmMs / gysMc 兜底处理 + String safeXmMs = StringUtils.isBlank(xmMs) ? "无" : xmMs; + String safeGysMc = StringUtils.isBlank(gysMc) ? "无" : gysMc; + + // 3. 基础名(入库用供应商,出库用项目) + final String baseName = localPhotoUtil.buildBaseName(photoType, billNo, safeXmMs, safeGysMc); try { - // ========= 2. 本地落盘 ========= - // 目录:D:\photo\photo\yyyy-MM-dd\ - List saved = localPhotoUtil.saveBatch(files, "", baseName); + // 4. 保存文件 + List saved = localPhotoUtil.saveBatch(files, documentType, baseName); - // ========= 3. 生成URL + 组装入库对象 ========= - List urls = new ArrayList(saved.size()); - List rows = new ArrayList(saved.size()); + // 5. 拼 URL + 入库对象 + List urls = new ArrayList<>(saved.size()); + List rows = new ArrayList<>(saved.size()); - for (SaveResult s : saved) { - // 根据当前上下文拼 URL,例如:http://host:port/photo/photo/2025-09-01/xxx.jpg + for (LocalPhotoUtil.SaveResult s : saved) { String url = ServletUriComponentsBuilder.fromCurrentContextPath() - .path("/photo/") // 与 StaticResourceConfig.addResourceHandlers 保持一致 - .path(s.getWebPath()) // 形如:photo/2025-09-01/xxx.jpg + .path("/photo/") + .path(s.getWebPath()) .toUriString(); urls.add(url); - // 只存一个URL到表中(其余信息按你最简诉求不存) StockPhoto p = new StockPhoto(); p.setBillNo(billNo); p.setPhotoType(photoType); p.setFileName(s.getFileName()); p.setUrl(url); - // 如需记录创建人:p.setCreateBy(SecurityUtils.getUserId().toString()); rows.add(p); } - // ========= 4. 批量入库 ========= if (!rows.isEmpty()) { stockPhotoMapper.batchInsert(rows); } return urls; } catch (Exception e) { - // Service 层抛出 RuntimeException,触发 @Transactional 回滚数据库写入 - // (注意:文件已落盘无法自动回滚,必要时可加失败清理逻辑) throw new RuntimeException("上传/保存失败:" + e.getMessage(), e); } } diff --git a/src/main/java/com/zg/project/wisdom/service/impl/PkDatServiceImpl.java b/src/main/java/com/zg/project/wisdom/service/impl/PkDatServiceImpl.java new file mode 100644 index 0000000..0bbf4f9 --- /dev/null +++ b/src/main/java/com/zg/project/wisdom/service/impl/PkDatServiceImpl.java @@ -0,0 +1,24 @@ +package com.zg.project.wisdom.service.impl; + +import com.zg.project.wisdom.domain.dto.PkDatDTO; +import com.zg.project.wisdom.mapper.PkDatMapper; +import com.zg.project.wisdom.service.IPkDatService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +@Service +public class PkDatServiceImpl implements IPkDatService { + + @Resource + private PkDatMapper pkDatMapper; + + @Override + public int batchInsertPkDat(List list) { + if (list == null || list.isEmpty()) { + return 0; + } + return pkDatMapper.batchInsertPkDat(list); + } +} diff --git a/src/main/resources/mybatis/wisdom/PkDatMapper.xml b/src/main/resources/mybatis/wisdom/PkDatMapper.xml new file mode 100644 index 0000000..d06ad63 --- /dev/null +++ b/src/main/resources/mybatis/wisdom/PkDatMapper.xml @@ -0,0 +1,18 @@ + + + + + + + INSERT INTO pk.dat + (wlh, num, ste, lnum, prf, gys, mrk, des_pro, inf, printer) + VALUES + + (#{item.wlNo}, #{item.realQty}, 1, 1, #{item.sapNo}, + #{item.gysMc}, #{item.remark}, #{item.xmMs}, #{item.pcode}, 1) + + + + diff --git a/src/main/resources/mybatis/wisdom/RkInfoMapper.xml b/src/main/resources/mybatis/wisdom/RkInfoMapper.xml index 23f84b8..50e24e6 100644 --- a/src/main/resources/mybatis/wisdom/RkInfoMapper.xml +++ b/src/main/resources/mybatis/wisdom/RkInfoMapper.xml @@ -340,6 +340,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.xm_ms, a.xm_no_ck, a.xm_ms_ck, + a.gys_mc, a.wl_no, a.wl_ms, a.gys_no, @@ -365,6 +366,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" MIN(t.xm_ms) AS xm_ms, MIN(t.xm_no_ck) AS xm_no_ck, MIN(t.xm_ms_ck) AS xm_ms_ck, + MIN(t.gys_mc) AS gys_mc, MIN(t.wl_no) AS wl_no, MIN(t.wl_ms) AS wl_ms, MIN(t.gys_no) AS gys_no,