From 22e17b6db03ca58bc477a35ca067e55a09cffce7 Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期三, 10 十二月 2025 17:04:08 +0800
Subject: [PATCH] 添加工程表及相关逻辑,防止重复导入Excel表序号重复生成

---
 mes-web/src/utils/constants.js                                                                          |    4 
 mes-web/public/config.js                                                                                |    4 
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java           |   56 +--------
 mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql       |   21 +++
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java          |   25 ++++
 mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java                  |   63 ++++++++++
 mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java            |   47 +++++++
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java |   81 +++++++++++++
 8 files changed, 248 insertions(+), 53 deletions(-)

diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java
new file mode 100644
index 0000000..73cf19f
--- /dev/null
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java
@@ -0,0 +1,63 @@
+package com.mes.device.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 宸ョ▼搴忓彿瀹炰綋绫�
+ * 瀵瑰簲鏁版嵁搴撹〃锛歟ngineering_sequence
+ * 鐢ㄤ簬绠$悊宸ョ▼鍙风敓鎴愶紝閬垮厤閲嶅
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("engineering_sequence")
+@ApiModel(value = "EngineeringSequence", description = "宸ョ▼搴忓彿淇℃伅")
+public class EngineeringSequence {
+
+    @ApiModelProperty(value = "涓婚敭ID", example = "1")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "宸ョ▼鍙凤紙鍞竴鏍囪瘑锛�", example = "P25010801")
+    @TableField("engineering_id")
+    private String engineeringId;
+
+    @ApiModelProperty(value = "鏃ユ湡锛坹yMMdd鏍煎紡瀵瑰簲鐨勬棩鏈燂級")
+    @TableField("date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date date;
+
+    @ApiModelProperty(value = "褰撳ぉ鐨勫簭鍙�", example = "1")
+    @TableField("sequence")
+    private Integer sequence;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "鍒涘缓浜�", example = "system")
+    @TableField(value = "created_by", fill = FieldFill.INSERT)
+    private String createdBy;
+
+    @ApiModelProperty(value = "鏇存柊浜�", example = "system")
+    @TableField(value = "updated_by", fill = FieldFill.INSERT_UPDATE)
+    private String updatedBy;
+
+    @ApiModelProperty(value = "鏄惁鍒犻櫎锛�0-鍚︼紝1-鏄�", example = "0")
+    @TableField("is_deleted")
+    @TableLogic
+    private Integer isDeleted;
+}
+
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java
new file mode 100644
index 0000000..422cc58
--- /dev/null
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java
@@ -0,0 +1,47 @@
+package com.mes.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.mes.device.entity.EngineeringSequence;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.Date;
+
+/**
+ * 宸ョ▼搴忓彿Mapper鎺ュ彛
+ * 
+ * @author mes
+ * @since 2024-11-20
+ */
+@Mapper
+public interface EngineeringSequenceMapper extends BaseMapper<EngineeringSequence> {
+
+    /**
+     * 鏌ヨ鎸囧畾鏃ユ湡鐨勬渶澶у簭鍙�
+     * 
+     * @param date 鏃ユ湡
+     * @return 鏈�澶у簭鍙凤紝濡傛灉娌℃湁璁板綍杩斿洖0
+     */
+    @Select("SELECT COALESCE(MAX(sequence), 0) FROM engineering_sequence WHERE date = #{date} AND is_deleted = 0")
+    Integer selectMaxSequenceByDate(@Param("date") Date date);
+
+    /**
+     * 鏌ヨ鎸囧畾鏃ユ湡鐨勬渶澶у簭鍙峰苟鍔犺閿侊紝閬垮厤骞跺彂鐢熸垚閲嶅搴忓彿
+     *
+     * @param date 鏃ユ湡
+     * @return 鏈�澶у簭鍙凤紝濡傛灉娌℃湁璁板綍杩斿洖0
+     */
+    @Select("SELECT COALESCE(MAX(sequence), 0) FROM engineering_sequence WHERE date = #{date} AND is_deleted = 0 FOR UPDATE")
+    Integer selectMaxSequenceByDateForUpdate(@Param("date") Date date);
+
+    /**
+     * 鏍规嵁宸ョ▼鍙锋煡璇㈠伐绋嬪簭鍙蜂俊鎭�
+     * 
+     * @param engineeringId 宸ョ▼鍙�
+     * @return 宸ョ▼搴忓彿淇℃伅
+     */
+    @Select("SELECT * FROM engineering_sequence WHERE engineering_id = #{engineeringId} AND is_deleted = 0 LIMIT 1")
+    EngineeringSequence selectByEngineeringId(@Param("engineeringId") String engineeringId);
+}
+
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
new file mode 100644
index 0000000..6ebaa44
--- /dev/null
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
@@ -0,0 +1,25 @@
+package com.mes.device.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.mes.device.entity.EngineeringSequence;
+
+import java.util.Date;
+
+/**
+ * 宸ョ▼搴忓彿淇℃伅鏈嶅姟鎺ュ彛
+ * 
+ * @author mes
+ * @since 2024-11-20
+ */
+public interface EngineeringSequenceService extends IService<EngineeringSequence> {
+
+    /**
+     * 鐢熸垚骞朵繚瀛樻柊鐨勫伐绋嬪彿
+     * 鏍规嵁鏃ユ湡鑾峰彇鏈�澶у簭鍙凤紝鐒跺悗鑷1鐢熸垚鏂扮殑宸ョ▼鍙�
+     * 
+     * @param date 鏃ユ湡
+     * @return 鐢熸垚鐨勫伐绋嬪彿锛堟牸寮忥細P + yyMMdd + 涓や綅搴忓彿锛�
+     */
+    String generateAndSaveEngineeringId(Date date);
+}
+
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
new file mode 100644
index 0000000..2eb888c
--- /dev/null
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
@@ -0,0 +1,81 @@
+package com.mes.device.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.mes.device.entity.EngineeringSequence;
+import com.mes.device.mapper.EngineeringSequenceMapper;
+import com.mes.device.service.EngineeringSequenceService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+/**
+ * 宸ョ▼搴忓彿淇℃伅鏈嶅姟瀹炵幇绫�
+ * 
+ * @author mes
+ * @since 2024-11-20
+ */
+@Slf4j
+@Service
+public class EngineeringSequenceServiceImpl extends ServiceImpl<EngineeringSequenceMapper, EngineeringSequence> implements EngineeringSequenceService {
+
+    // 鏃ユ湡鏍煎紡鍖栧櫒锛堢嚎绋嬩笉瀹夊叏锛屼娇鐢═hreadLocal淇濊瘉绾跨▼瀹夊叏锛�
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String generateAndSaveEngineeringId(Date date) {
+        // 涔愯閲嶈瘯锛岄槻姝㈠苟鍙戝啓鍏ラ�犳垚閲嶅閿�
+        int retry = 0;
+        final int maxRetry = 5;
+        while (true) {
+            try {
+                // 1. 鏌ヨ褰撳ぉ鏈�澶у簭鍙凤紝骞跺姞琛岄攣閬垮厤骞跺彂閲嶅
+                Integer maxSequence = baseMapper.selectMaxSequenceByDateForUpdate(date);
+                if (maxSequence == null) {
+                    maxSequence = 0;
+                }
+
+                // 2. 搴忓彿鑷1
+                int newSequence = maxSequence + 1;
+
+                // 3. 鐢熸垚宸ョ▼鍙凤細P + yyMMdd + 涓や綅搴忓彿
+                LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+                String dateStr = localDate.format(DATE_FORMATTER);
+                String engineeringId = "P" + dateStr + String.format("%02d", newSequence);
+
+                // 4. 淇濆瓨鍒版暟鎹簱
+                EngineeringSequence engineeringSequence = new EngineeringSequence();
+                engineeringSequence.setEngineeringId(engineeringId);
+                engineeringSequence.setDate(date);
+                engineeringSequence.setSequence(newSequence);
+                engineeringSequence.setCreatedTime(new Date());
+                engineeringSequence.setUpdatedTime(new Date());
+                engineeringSequence.setCreatedBy("system");
+                engineeringSequence.setUpdatedBy("system");
+
+                save(engineeringSequence);
+
+                log.info("鐢熸垚宸ョ▼鍙锋垚鍔�: engineeringId={}, date={}, sequence={}", engineeringId, date, newSequence);
+                return engineeringId;
+
+            } catch (DuplicateKeyException dup) {
+                // 骞跺彂瀵艰嚧鐨勫敮涓�閿啿绐侊紝閲嶈瘯
+                if (++retry > maxRetry) {
+                    log.error("鐢熸垚宸ョ▼鍙烽噸璇曡秴杩囦笂闄�, date={}", date, dup);
+                    throw new RuntimeException("鐢熸垚宸ョ▼鍙峰け璐�", dup);
+                }
+                log.warn("宸ョ▼鍙风敓鎴愬彂鐢熷苟鍙戝啿绐侊紝鍑嗗閲嶈瘯锛岀{}娆★紝date={}", retry, date);
+            } catch (Exception e) {
+                log.error("鐢熸垚宸ョ▼鍙峰け璐�, date={}", date, e);
+                throw new RuntimeException("鐢熸垚宸ョ▼鍙峰け璐�", e);
+            }
+        }
+    }
+}
+
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
index 9b1dd51..6c26414 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
@@ -5,19 +5,16 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.mes.device.entity.GlassInfo;
 import com.mes.device.mapper.DeviceGlassInfoMapper;
+import com.mes.device.service.EngineeringSequenceService;
 import com.mes.device.service.GlassInfoService;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import static java.util.stream.IntStream.range;
@@ -32,6 +29,9 @@
 @RefreshScope
 @Service("deviceGlassInfoService")
 public class GlassInfoServiceImpl extends ServiceImpl<DeviceGlassInfoMapper, GlassInfo> implements GlassInfoService {
+
+    @Autowired
+    private EngineeringSequenceService engineeringSequenceService;
 
     @Override
     public GlassInfo getGlassInfo(String glassId) {
@@ -230,9 +230,8 @@
             return result;
         }
 
-        // 宸ョ▼鍙风敓鎴愶細P + yyMMdd + 搴忓彿(2浣�)
-        AtomicInteger seq = new AtomicInteger(1);
-        final String engineerId = generateEngineerId(firstValue(excelRows, "glassId"), seq.getAndIncrement());
+        // 宸ョ▼鍙风敓鎴愶細浣跨敤鏁版嵁搴撹嚜澧炲簭鍙凤紝閬垮厤閲嶅
+        final String engineerId = engineeringSequenceService.generateAndSaveEngineeringId(new Date());
         final String filmsIdDefault = firstValue(excelRows, "filmsId", "鐧界幓");
         final double thicknessDefault = parseDouble(firstValue(excelRows, "thickness"), 0d);
 
@@ -389,47 +388,6 @@
         return result;
     }
 
-    // 鏃ユ湡鏍煎紡鍖栧櫒锛堢嚎绋嬩笉瀹夊叏锛屼娇鐢═hreadLocal淇濊瘉绾跨▼瀹夊叏锛�
-    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
-
-    // 鏁板瓧鍖归厤姝e垯锛堥缂栬瘧鎻愬崌鎬ц兘锛�
-    private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d+");
-
-    /**
-     * 鐢熸垚宸ョ▼甯圛D
-     * 鏍煎紡瑙勫垯锛歅 + 骞存湀鏃�(yyMMdd) + 涓や綅搴忓彿
-     * 搴忓彿浼樺厛浠巊lassId涓彁鍙栨湯灏句袱浣嶆暟瀛楋紝鍚﹀垯浣跨敤浼犲叆鐨刬ndex琛ラ浂
-     *
-     * @param glassId 鐜荤拑ID锛堝彲涓簄ull锛岀敤浜庢彁鍙栨暟瀛楀簭鍙凤級
-     * @param index   澶囩敤搴忓彿锛堝綋glassId鏃犳湁鏁堟暟瀛楁椂浣跨敤锛�
-     * @return 鏍煎紡鍖栫殑宸ョ▼甯圛D锛堝锛歅25010801锛�
-     */
-    private String generateEngineerId(Object glassId, int index) {
-        // 1. 鐢熸垚鏃ユ湡鍓嶇紑锛坹yMMdd锛�
-        String base = LocalDate.now().format(DATE_FORMATTER);
-
-        // 2. 鍒濆鍖栧簭鍙凤紙涓や綅琛ラ浂锛�
-        String seq = String.format("%02d", index);
-
-        // 3. 浠巊lassId涓彁鍙栨湯灏句袱浣嶆暟瀛楋紙瑕嗙洊榛樿搴忓彿锛�
-        if (glassId != null) {
-            String glassIdStr = glassId.toString();
-            Matcher matcher = DIGIT_PATTERN.matcher(glassIdStr);
-            String lastDigitStr = null;
-
-            // 閬嶅巻鍖归厤鎵�鏈夋暟瀛楁锛屽彇鏈�鍚庝竴涓�
-            while (matcher.find()) {
-                lastDigitStr = matcher.group();
-            }
-
-            // 鑻ユ暟瀛楁闀垮害鈮�2锛屽彇鏈�鍚庝袱浣嶏紱鍚﹀垯淇濈暀鍘熷簭鍙�
-            if (lastDigitStr != null && lastDigitStr.length() >= 2) {
-                seq = lastDigitStr.substring(lastDigitStr.length() - 2);
-            }
-        }
-
-        return "P" + base + seq;
-    }
 
     /**
      * 鎻愬彇List涓涓�涓狹ap鐨勬寚瀹歬ey鍊硷紙榛樿绌哄瓧绗︿覆锛�
diff --git a/mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql b/mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql
new file mode 100644
index 0000000..8b2157c
--- /dev/null
+++ b/mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql
@@ -0,0 +1,21 @@
+-- 宸ョ▼搴忓彿琛�
+-- 鐢ㄤ簬绠$悊宸ョ▼鍙风敓鎴愶紝閬垮厤閲嶅
+-- 姣忔瀵煎叆Excel鏃讹紝浼氭牴鎹棩鏈熻嚜鍔ㄧ敓鎴愰�掑鐨勫伐绋嬪彿
+
+CREATE TABLE IF NOT EXISTS engineering_sequence (
+    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '涓婚敭ID',
+    engineering_id VARCHAR(50) NOT NULL UNIQUE COMMENT '宸ョ▼鍙凤紙鍞竴鏍囪瘑锛屾牸寮忥細P + yyMMdd + 涓や綅搴忓彿锛�',
+    date DATE NOT NULL COMMENT '鏃ユ湡锛堢敤浜庢寜鏃ユ湡鍒嗙粍鐢熸垚搴忓彿锛�',
+    sequence INT NOT NULL COMMENT '褰撳ぉ鐨勫簭鍙凤紙浠�1寮�濮嬮�掑锛�',
+    created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+    created_by VARCHAR(50) DEFAULT 'system' COMMENT '鍒涘缓浜�',
+    updated_by VARCHAR(50) DEFAULT 'system' COMMENT '鏇存柊浜�',
+    is_deleted TINYINT DEFAULT 0 COMMENT '鏄惁鍒犻櫎锛�0-鍚︼紝1-鏄�',
+    
+    INDEX idx_engineering_id (engineering_id),
+    INDEX idx_date (date),
+    INDEX idx_date_sequence (date, sequence),
+    INDEX idx_created_time (created_time)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宸ョ▼搴忓彿琛�';
+
diff --git a/mes-web/public/config.js b/mes-web/public/config.js
index c92c07b..6088017 100644
--- a/mes-web/public/config.js
+++ b/mes-web/public/config.js
@@ -1,7 +1,7 @@
 // const ip = '127.0.0.1'
-const ip = '10.153.19.192'
+const ip = '10.153.19.182'
 // const ip = '10.100.0.183'
 // const ip = '192.168.2.8'
 window.ipConfig = {
-    serverUrl: `${ip}:88`,
+    serverUrl: `${ip}:89`,
 }
\ No newline at end of file
diff --git a/mes-web/src/utils/constants.js b/mes-web/src/utils/constants.js
index 44df4e3..9f70433 100644
--- a/mes-web/src/utils/constants.js
+++ b/mes-web/src/utils/constants.js
@@ -1,7 +1,7 @@
 // export const WebSocketHost = "10.153.19.150";
 // export const WebSocketHost = "172.17.2.7";
-export const WebSocketHost = "10.153.19.166";//hxl
+export const WebSocketHost = "10.153.19.192";//hxl
 // export const WebSocketHost = "10.153.19.2";//zt
 //export const WebSocketHost = "10.153.19.20";//wsx
 // export const WebSocketHost = "127.0.0.1";
-export const host = "88";
\ No newline at end of file
+export const host = "89";
\ No newline at end of file

--
Gitblit v1.8.0