From 5f708178b260cabf081f9049cf51e9ad66ae2911 Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期四, 10 九月 2026 14:49:29 +0800
Subject: [PATCH] feat(erp/mes): 新增采购订单/销售订单/计量器具 Excel 导入,含导入菜单权限 SQL

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringServiceImpl.java |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 173 insertions(+), 0 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringServiceImpl.java
index 6c5ccbe..d7e0633 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/metering/MesDvMeteringServiceImpl.java
@@ -1,6 +1,12 @@
 package cn.iocoder.yudao.module.mes.service.dv.metering;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.mes.controller.admin.dv.metering.vo.MesDvMeteringImportExcelVO;
+import cn.iocoder.yudao.module.mes.controller.admin.dv.metering.vo.MesDvMeteringImportRespVO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -14,9 +20,14 @@
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -54,6 +65,11 @@
     @Resource
     private ConfigApi configApi;
 
+    @Resource
+    private DeptApi deptApi;
+    @Resource
+    private AdminUserApi adminUserApi;
+
     @Override
     public Long createMetering(MesDvMeteringSaveReqVO createReqVO) {
         // 鏍¢獙缂栫爜鍞竴
@@ -66,6 +82,163 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
+    public MesDvMeteringImportRespVO importMeteringList(List<MesDvMeteringImportExcelVO> importList) {
+        MesDvMeteringImportRespVO respVO = MesDvMeteringImportRespVO.builder()
+                .createList(new ArrayList<>())
+                .updateList(new ArrayList<>())
+                .failureList(new LinkedHashMap<>())
+                .build();
+        if (CollUtil.isEmpty(importList)) {
+            return respVO;
+        }
+
+        // 1. 棰勭儹鈥滈儴闂ㄥ悕绉� -> 閮ㄩ棬缂栧彿鈥濇槧灏勶紙閮ㄩ棬/璐d换浜轰负闈炲繀濉紝鍖归厤涓嶅埌璇ヨ澶辫触锛�
+        Map<String, Long> deptIdMap = new HashMap<>();
+        List<DeptRespDTO> depts = deptApi.getDeptList();
+        if (CollUtil.isNotEmpty(depts)) {
+            depts.forEach(dept -> {
+                if (StrUtil.isNotBlank(dept.getName())) {
+                    deptIdMap.putIfAbsent(dept.getName().trim(), dept.getId());
+                }
+            });
+        }
+
+        // 2. 閫愯瀵煎叆锛堝崟琛屽け璐ヤ笉褰卞搷鍏跺畠琛岋級
+        for (int i = 0; i < importList.size(); i++) {
+            MesDvMeteringImportExcelVO row = importList.get(i);
+            if (row == null || (StrUtil.isBlank(row.getCode()) && StrUtil.isBlank(row.getName()))) {
+                continue; // 璺宠繃绌鸿
+            }
+            String label = StrUtil.isNotBlank(row.getCode()) ? row.getCode().trim() : "绗� " + (i + 2) + " 琛�";
+            try {
+                boolean restored = createMeteringByImport(row, deptIdMap);
+                if (restored) {
+                    respVO.getUpdateList().add(row.getCode().trim()); // 鎭㈠/瑕嗙洊鏇存柊
+                } else {
+                    respVO.getCreateList().add(row.getCode().trim());
+                }
+            } catch (Exception ex) {
+                respVO.getFailureList().put(label, resolveImportErrorMessage(ex));
+            }
+        }
+        return respVO;
+    }
+
+    /**
+     * 渚濇嵁瀵煎叆琛屽垱寤轰竴鏉¤閲忓櫒鍏疯褰�
+     */
+    private boolean createMeteringByImport(MesDvMeteringImportExcelVO row, Map<String, Long> deptIdMap) {
+        // 1. 蹇呭~鏍¢獙
+        if (StrUtil.isBlank(row.getCode())) {
+            throw new IllegalArgumentException("璁¢噺鍣ㄥ叿缂栫爜涓嶈兘涓虹┖");
+        }
+        if (StrUtil.isBlank(row.getName())) {
+            throw new IllegalArgumentException("璁¢噺鍣ㄥ叿鍚嶇О涓嶈兘涓虹┖");
+        }
+        if (row.getCategory() == null) {
+            throw new IllegalArgumentException("鍣ㄥ叿绫诲埆涓嶈兘涓虹┖锛堣濉瓧鍏镐腑鏂囷紝濡� 鍗″昂/鍏朵粬锛�");
+        }
+        if (row.getStatus() == null) {
+            throw new IllegalArgumentException("鐘舵�佷笉鑳戒负绌猴紙璇峰~瀛楀吀涓枃锛屽 鍦ㄧ敤/鍋滅敤/鎶ュ簾锛�");
+        }
+        // 2. 缂栫爜鍒ら噸锛堝惈鈥滃凡琚�昏緫鍒犻櫎鈥濈殑璁板綍锛夛細鏈垹闄� => 鎶ラ敊锛涘凡鍒犻櫎 => 绋嶅悗鎭㈠骞舵洿鏂�
+        MesDvMeteringDO exist = meteringMapper.selectByCodeIncludeDeleted(row.getCode().trim());
+        if (exist != null && !Boolean.TRUE.equals(exist.getDeleted())) {
+            throw new IllegalArgumentException("璁¢噺鍣ㄥ叿缂栫爜宸插瓨鍦細" + row.getCode());
+        }
+
+        // 3. 缁勮
+        MesDvMeteringSaveReqVO reqVO = new MesDvMeteringSaveReqVO();
+        reqVO.setCode(row.getCode().trim());
+        reqVO.setName(row.getName().trim());
+        reqVO.setCategory(row.getCategory());
+        reqVO.setSpecification(row.getSpecification());
+        reqVO.setBrand(row.getBrand());
+        reqVO.setPrecision(row.getPrecision());
+        reqVO.setRange(row.getRange());
+        reqVO.setCheckCycleCount(row.getCheckCycleCount() == null ? 12 : row.getCheckCycleCount());
+        reqVO.setUseDate(parseImportUseDate(row.getUseDate()));
+        reqVO.setStatus(row.getStatus());
+        reqVO.setRemark(row.getRemark());
+        // 浣跨敤閮ㄩ棬锛氭寜鍚嶇О鍖归厤
+        if (StrUtil.isNotBlank(row.getDeptName())) {
+            Long deptId = deptIdMap.get(row.getDeptName().trim());
+            if (deptId == null) {
+                throw new IllegalArgumentException("浣跨敤閮ㄩ棬涓嶅瓨鍦細" + row.getDeptName());
+            }
+            reqVO.setDeptId(deptId);
+        }
+        // 璐d换浜猴細鎸夋樀绉板尮閰�
+        if (StrUtil.isNotBlank(row.getChargeUserName())) {
+            Long userId = matchUserIdByNickname(row.getChargeUserName().trim());
+            if (userId == null) {
+                throw new IllegalArgumentException("璐d换浜轰笉瀛樺湪锛�" + row.getChargeUserName());
+            }
+            reqVO.setChargeUserId(userId);
+        }
+
+        // 4. 钀藉簱锛氬懡涓�滃凡鍒犻櫎鈥濈殑鍚岀紪鐮� => 鍏堟仮澶嶅啀鏇存柊锛涘惁鍒欐柊澧�
+        if (exist != null) {
+            meteringMapper.restoreDeletedById(exist.getId());
+            reqVO.setId(exist.getId());
+            updateMetering(reqVO);
+            return true; // 琛ㄧず鈥滄仮澶�/鏇存柊鈥�
+        }
+        createMetering(reqVO);
+        return false;
+    }
+
+    /**
+     * 鎸夋樀绉板尮閰嶇敤鎴风紪鍙凤紙绮剧‘鍖归厤浼樺厛锛屽彇涓嶅埌鍒欑敤妯$硦缁撴灉绗竴鏉★級
+     */
+    private Long matchUserIdByNickname(String nickname) {
+        List<AdminUserRespDTO> users = adminUserApi.getUserListByNickname(nickname);
+        if (CollUtil.isEmpty(users)) {
+            return null;
+        }
+        return users.stream()
+                .filter(user -> nickname.equals(user.getNickname()))
+                .map(AdminUserRespDTO::getId)
+                .findFirst()
+                .orElseGet(() -> users.get(0).getId());
+    }
+
+    /**
+     * 瑙f瀽鎶曞叆浣跨敤鏃ユ湡锛坹yyy-MM-dd / yyyy/M/d锛夛紱涓虹┖杩斿洖 null
+     */
+    private LocalDate parseImportUseDate(String text) {
+        if (StrUtil.isBlank(text)) {
+            return null;
+        }
+        String value = text.trim();
+        for (String pattern : new String[]{"yyyy-MM-dd", "yyyy/M/d"}) {
+            try {
+                return LocalDate.parse(value, java.time.format.DateTimeFormatter.ofPattern(pattern));
+            } catch (Exception ignored) {
+                // 缁х画灏濊瘯涓嬩竴涓牸寮�
+            }
+        }
+        try {
+            return java.time.LocalDateTime.parse(value,
+                    java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toLocalDate();
+        } catch (Exception ignored) {
+            // 蹇界暐
+        }
+        throw new IllegalArgumentException("鎶曞叆浣跨敤鏃ユ湡鏍煎紡涓嶆纭細" + text + "锛岀ず渚� 2026-01-01");
+    }
+
+    /**
+     * 鎻愬彇瀵煎叆澶辫触鍘熷洜锛圫erviceException 鍙栦笟鍔℃彁绀猴級
+     */
+    private String resolveImportErrorMessage(Exception ex) {
+        if (ex instanceof cn.iocoder.yudao.framework.common.exception.ServiceException serviceException) {
+            return serviceException.getMessage();
+        }
+        return StrUtil.blankToDefault(ex.getMessage(), "瀵煎叆澶辫触");
+    }
+
+    @Override
     public void updateMetering(MesDvMeteringSaveReqVO updateReqVO) {
         // 鏍¢獙瀛樺湪
         validateMeteringExists(updateReqVO.getId());

--
Gitblit v1.9.3