| mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-web/public/config.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| mes-web/src/utils/constants.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
mes-processes/mes-plcSend/src/main/java/com/mes/device/entity/EngineeringSequence.java
New file @@ -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; /** * 工程序号实体类 * 对应数据库表:engineering_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 = "日期(yyMMdd格式对应的日期)") @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; } mes-processes/mes-plcSend/src/main/java/com/mes/device/mapper/EngineeringSequenceMapper.java
New file @@ -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); } mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
New file @@ -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); } mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
New file @@ -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 { // 日期格式化器(线程不安全,使用ThreadLocal保证线程安全) 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); } } } } 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; } // 日期格式化器(线程不安全,使用ThreadLocal保证线程安全) private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd"); // 数字匹配正则(预编译提升性能) private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d+"); /** * 生成工程师ID * 格式规则:P + 年月日(yyMMdd) + 两位序号 * 序号优先从glassId中提取末尾两位数字,否则使用传入的index补零 * * @param glassId 玻璃ID(可为null,用于提取数字序号) * @param index 备用序号(当glassId无有效数字时使用) * @return 格式化的工程师ID(如:P25010801) */ private String generateEngineerId(Object glassId, int index) { // 1. 生成日期前缀(yyMMdd) String base = LocalDate.now().format(DATE_FORMATTER); // 2. 初始化序号(两位补零) String seq = String.format("%02d", index); // 3. 从glassId中提取末尾两位数字(覆盖默认序号) 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中第一个Map的指定key值(默认空字符串) mes-processes/mes-plcSend/src/main/resources/db/migration/V20241121__create_engineering_table.sql
New file @@ -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='工程序号表'; 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`, } 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"; export const host = "89";