diff --git a/aucma-dms/DMS_SEQUENCES.sql b/aucma-dms/DMS_SEQUENCES.sql
index 86f5620..ea7ec40 100644
--- a/aucma-dms/DMS_SEQUENCES.sql
+++ b/aucma-dms/DMS_SEQUENCES.sql
@@ -295,6 +295,7 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_BILLS_INSPECT_ACTIVITY"
-- 14. SEQ_DMS_MAINT_INST (保养工单)
-- 表: DMS_BILLS_MAINT_INSTANCE
+-- 当前保养计划定时生成工单使用序列之一
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_MAINT_INST"';
@@ -329,6 +330,7 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_MAINT_INST_ACTIVITY"
-- ----------------------------
-- 15. SEQ_DMS_MAINT_DETAIL (保养工单明细)
-- 表: DMS_BILLS_MAINT_DETAIL
+-- 当前保养计划定时生成工单使用序列之一
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_MAINT_DETAIL"';
@@ -346,6 +348,7 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_MAINT_DETAIL"
-- ----------------------------
-- 16. SEQ_DMS_MAINT_DTL_PROJ (保养明细项目)
-- 表: DMS_BILLS_MAINT_DETAIL_PROJECT
+-- 当前保养计划定时生成工单使用序列之一
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_MAINT_DTL_PROJ"';
diff --git a/aucma-dms/src/main/java/com/aucma/dms/domain/DmsInspectInstanceDetail.java b/aucma-dms/src/main/java/com/aucma/dms/domain/DmsInspectInstanceDetail.java
index e5ce1d2..0d7bf69 100644
--- a/aucma-dms/src/main/java/com/aucma/dms/domain/DmsInspectInstanceDetail.java
+++ b/aucma-dms/src/main/java/com/aucma/dms/domain/DmsInspectInstanceDetail.java
@@ -47,6 +47,9 @@ public class DmsInspectInstanceDetail extends DmsBaseEntity
@Excel(name = "巡检标准")
private String inspectStandard;
+ /** 巡检标准名称(连表查询) */
+ private String standardName;
+
/** 操作描述 */
@Excel(name = "操作描述")
private String inspectDesc;
@@ -132,6 +135,15 @@ public class DmsInspectInstanceDetail extends DmsBaseEntity
{
return inspectStandard;
}
+ public void setStandardName(String standardName)
+ {
+ this.standardName = standardName;
+ }
+
+ public String getStandardName()
+ {
+ return standardName;
+ }
public void setInspectDesc(String inspectDesc)
{
this.inspectDesc = inspectDesc;
@@ -210,6 +222,7 @@ public class DmsInspectInstanceDetail extends DmsBaseEntity
.append("deviceId", getDeviceId())
.append("instanceDetailStatus", getInstanceDetailStatus())
.append("inspectStandard", getInspectStandard())
+ .append("standardName", getStandardName())
.append("inspectDesc", getInspectDesc())
.append("inspectValue", getInspectValue())
.append("inspectStatus", getInspectStatus())
diff --git a/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsBillsMaintInstanceMapper.java b/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsBillsMaintInstanceMapper.java
index 38c824e..ccf6c45 100644
--- a/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsBillsMaintInstanceMapper.java
+++ b/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsBillsMaintInstanceMapper.java
@@ -6,6 +6,7 @@ import com.aucma.dms.domain.DmsBillsMaintInstance;
import com.aucma.dms.domain.DmsMaintInstanceActivity;
import org.apache.ibatis.annotations.Param;
+import java.util.Date;
import java.util.List;
/**
@@ -92,4 +93,10 @@ public interface DmsBillsMaintInstanceMapper {
* @return 工单数量
*/
int countByPlanIdAndToday(@Param("planMaintId") Long planMaintId);
+
+ /**
+ * 统一从 DB 获取当前时间,避免应用机与数据库时钟偏差
+ * @return DB 当前时间
+ */
+ Date selectDbNow();
}
diff --git a/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsPlanMaintMapper.java b/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsPlanMaintMapper.java
index e73a742..11d5754 100644
--- a/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsPlanMaintMapper.java
+++ b/aucma-dms/src/main/java/com/aucma/dms/mapper/DmsPlanMaintMapper.java
@@ -123,4 +123,11 @@ public interface DmsPlanMaintMapper
int updatePlanNextTime(@Param("planMaintId") Long planMaintId,
@Param("maintTime") Date maintTime);
+ /**
+ * 锁定保养计划行,避免并发重复生成工单
+ * @param planMaintId 计划ID
+ * @return 锁定到的计划ID
+ */
+ Long lockPlanById(@Param("planMaintId") Long planMaintId);
+
}
diff --git a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsBillsMaintInstanceServiceImpl.java b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsBillsMaintInstanceServiceImpl.java
index 49abb21..41114da 100644
--- a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsBillsMaintInstanceServiceImpl.java
+++ b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsBillsMaintInstanceServiceImpl.java
@@ -11,6 +11,8 @@ import com.aucma.dms.service.IDmsBillsMaintInstanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -432,7 +434,27 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
log.info("开始创建已完成保养工单 | planMaintCode={}, planMaintId={}, 明细数量={}",
planMaintCodeS, dmsPlanMaint.getPlanMaintId(), planMaintDetails.size());
- Date now = new Date();
+ Long planMaintId = dmsPlanMaint.getPlanMaintId();
+ if (planMaintId != null) {
+ // 1) 先锁计划行,串行化同一计划的并发生成请求
+ Long lockedId = dmsPlanMaintMapper.lockPlanById(planMaintId);
+ if (lockedId == null) {
+ log.warn("保养计划不存在,跳过工单生成 | planMaintId={}, planMaintCode={}", planMaintId, planMaintCodeS);
+ return 0;
+ }
+ // 2) 再做当天查重(应用层幂等)
+ int existCount = dmsBillsMaintInstanceMapper.countByPlanIdAndToday(planMaintId);
+ if (existCount > 0) {
+ log.debug("保养计划今天已生成工单,跳过 | planMaintId={}, planMaintCode={}", planMaintId, planMaintCodeS);
+ return 0;
+ }
+ }
+
+ // 3) 统一使用 DB 时间,减少应用机/DB 机时钟差异
+ Date now = dmsBillsMaintInstanceMapper.selectDbNow();
+ if (now == null) {
+ now = new Date();
+ }
DmsBillsMaintInstance instance = new DmsBillsMaintInstance();
instance.setCreateTime(now);
@@ -451,7 +473,21 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
// 创建人优先使用计划的创建人,若无则使用-1L表示系统自动创建
instance.setCreateBy(dmsPlanMaint.getCreateBy() != null ? dmsPlanMaint.getCreateBy() : -1L);
- int i = dmsBillsMaintInstanceMapper.insertDmsBillsMaintInstance(instance);
+ int i;
+ try {
+ i = dmsBillsMaintInstanceMapper.insertDmsBillsMaintInstance(instance);
+ } catch (DuplicateKeyException e) {
+ log.debug("保养工单触发唯一约束(重复生成),跳过 | planMaintId={}, billsMaintCode={}",
+ instance.getPlanMaintId(), instance.getBillsMaintCode());
+ return 0;
+ } catch (DataIntegrityViolationException e) {
+ if (isOracleUniqueViolation(e)) {
+ log.debug("保养工单触发 ORA-00001(重复生成),跳过 | planMaintId={}, billsMaintCode={}",
+ instance.getPlanMaintId(), instance.getBillsMaintCode());
+ return 0;
+ }
+ throw e;
+ }
// 创建工单实例节点(第一步)
DmsMaintInstanceActivity activity = new DmsMaintInstanceActivity();
@@ -502,4 +538,16 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
return i;
}
+ private boolean isOracleUniqueViolation(Throwable e) {
+ Throwable cursor = e;
+ while (cursor != null) {
+ String msg = cursor.getMessage();
+ if (msg != null && msg.contains("ORA-00001")) {
+ return true;
+ }
+ cursor = cursor.getCause();
+ }
+ return false;
+ }
+
}
diff --git a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsPlanMaintServiceImpl.java b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsPlanMaintServiceImpl.java
index b5e19f2..3b50774 100644
--- a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsPlanMaintServiceImpl.java
+++ b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsPlanMaintServiceImpl.java
@@ -8,7 +8,6 @@ import com.aucma.common.utils.StringUtils;
import com.aucma.common.utils.uuid.Seq;
import com.aucma.dms.domain.DmsPlanMaint;
import com.aucma.dms.domain.DmsPlanMaintDetail;
-import com.aucma.dms.mapper.DmsBillsMaintInstanceMapper;
import com.aucma.dms.mapper.DmsPlanMaintMapper;
import com.aucma.dms.service.IDmsBillsMaintInstanceService;
import com.aucma.dms.service.IDmsPlanMaintService;
@@ -38,9 +37,6 @@ public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
@Autowired
private DmsPlanMaintMapper dmsPlanMaintMapper;
- @Autowired
- private DmsBillsMaintInstanceMapper dmsBillsMaintInstanceMapper;
-
@Autowired
private IDmsBillsMaintInstanceService dmsBillsMaintInstanceService;
@@ -342,13 +338,6 @@ public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
continue;
}
- // 通过Mapper检查今天是否已生成工单(避免重复)
- int existCount = dmsBillsMaintInstanceMapper.countByPlanIdAndToday(planMaintId);
- if (existCount > 0) {
- log.debug("保养计划[{}]今天已生成工单,跳过", planMaintCode);
- continue;
- }
-
// 通过Service创建已完成状态的保养工单(含明细,工单中所有设备默认保养完成,异常可在网页端维护)
int insertRows = dmsBillsMaintInstanceService.insertCompletedMaintInstance(planMaintCode);
if (insertRows > 0) {
diff --git a/aucma-dms/src/main/resources/mapper/dms/DmsBillsMaintInstanceMapper.xml b/aucma-dms/src/main/resources/mapper/dms/DmsBillsMaintInstanceMapper.xml
index 4e4563f..218f360 100644
--- a/aucma-dms/src/main/resources/mapper/dms/DmsBillsMaintInstanceMapper.xml
+++ b/aucma-dms/src/main/resources/mapper/dms/DmsBillsMaintInstanceMapper.xml
@@ -167,13 +167,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
insert into dms_bills_maint_detail( bills_maint_detail_id, maint_instance_id, device_id, station_id, maint_standard_id, operation_description, maint_status, is_flag, remark, create_by, create_time, update_by, update_time) values
- ( #{item.billsMaintDetailId}, #{item.maintInstanceId}, #{item.deviceId}, #{item.stationId}, #{item.maintStandardId}, #{item.operationDescription}, #{item.maintStatus}, #{item.isFlag}, #{item.remark}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime})
+ ( HAIWEI.SEQ_DMS_MAINT_DETAIL.NEXTVAL,
+ #{item.maintInstanceId,jdbcType=NUMERIC},
+ #{item.deviceId,jdbcType=NUMERIC},
+ #{item.stationId,jdbcType=NUMERIC},
+ #{item.maintStandardId,jdbcType=NUMERIC},
+ #{item.operationDescription,jdbcType=VARCHAR},
+ #{item.maintStatus,jdbcType=NUMERIC},
+ #{item.isFlag,jdbcType=NUMERIC},
+ #{item.remark,jdbcType=VARCHAR},
+ #{item.createBy,jdbcType=NUMERIC},
+ #{item.createTime,jdbcType=TIMESTAMP},
+ #{item.updateBy,jdbcType=NUMERIC},
+ #{item.updateTime,jdbcType=TIMESTAMP})
- insert into dms_bills_maint_detail_project( bills_maint_detail_id, maint_project_id, maint_project_name, maint_project_desc, maint_project_status, remark, create_by, create_time, update_by, update_time) values
+ insert into dms_bills_maint_detail_project( maint_detail_project_id, bills_maint_detail_id, maint_project_id, maint_project_name, maint_project_desc, maint_project_status, remark, create_by, create_time, update_by, update_time) values
- ( #{item.billsMaintDetailId}, #{item.maintProjectId}, #{item.maintProjectName}, #{item.maintProjectDesc}, #{item.maintProjectStatus}, #{item.remark}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime})
+ ( HAIWEI.SEQ_DMS_MAINT_DTL_PROJ.NEXTVAL,
+ #{item.billsMaintDetailId,jdbcType=NUMERIC},
+ #{item.maintProjectId,jdbcType=NUMERIC},
+ #{item.maintProjectName,jdbcType=VARCHAR},
+ #{item.maintProjectDesc,jdbcType=VARCHAR},
+ #{item.maintProjectStatus,jdbcType=VARCHAR},
+ #{item.remark,jdbcType=VARCHAR},
+ #{item.createBy,jdbcType=NUMERIC},
+ #{item.createTime,jdbcType=TIMESTAMP},
+ #{item.updateBy,jdbcType=NUMERIC},
+ #{item.updateTime,jdbcType=TIMESTAMP})
@@ -222,6 +244,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT COUNT(1)
FROM dms_bills_maint_instance
WHERE plan_maint_id = #{planMaintId}
- AND TRUNC(create_time) = TRUNC(SYSDATE)
+ -- 使用 [当天00:00, 次日00:00) 范围,避免 TRUNC(create_time) 带来的索引失效风险
+ AND create_time >= TRUNC(SYSDATE)
+ AND create_time < TRUNC(SYSDATE) + 1
+
+
+
+
diff --git a/aucma-dms/src/main/resources/mapper/dms/DmsInspectInstanceDetailMapper.xml b/aucma-dms/src/main/resources/mapper/dms/DmsInspectInstanceDetailMapper.xml
index 4c38423..acdaff1 100644
--- a/aucma-dms/src/main/resources/mapper/dms/DmsInspectInstanceDetailMapper.xml
+++ b/aucma-dms/src/main/resources/mapper/dms/DmsInspectInstanceDetailMapper.xml
@@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+
@@ -122,6 +123,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
diid.machine_id,
diid.instance_detail_status,
diid.inspect_standard,
+ dbis.standard_name,
a.inspect_project_desc inspect_desc,
diid.inspect_status,
dbdl.device_code,
@@ -130,6 +132,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
dms_inspect_instance_detail diid
left join HAIWEI.base_deviceledger dbdl on
diid.machine_id = dbdl.OBJ_ID
+ left join dms_base_inspect_standard dbis on to_char(dbis.inspect_standard_id) = diid.inspect_standard
left join dms_inspect_inst_det_proj a on diid.instance_detail_id = a.instance_detail_id
diff --git a/aucma-dms/src/main/resources/mapper/dms/DmsPlanMaintMapper.xml b/aucma-dms/src/main/resources/mapper/dms/DmsPlanMaintMapper.xml
index 0e9ee31..f67a0ac 100644
--- a/aucma-dms/src/main/resources/mapper/dms/DmsPlanMaintMapper.xml
+++ b/aucma-dms/src/main/resources/mapper/dms/DmsPlanMaintMapper.xml
@@ -229,4 +229,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE plan_maint_id = #{planMaintId}
+
+
+