From a0e8d1bbff7a02f538be76e852aa233324bd8810 Mon Sep 17 00:00:00 2001
From: fuliqi <fuliqi@qq.com>
Date: 星期五, 03 一月 2025 13:31:51 +0800
Subject: [PATCH] 赋码

---
 flowable/src/main/java/com/ycl/service/impl/ProcessCodingServiceImpl.java      |  119 ++++++++
 business/src/main/java/com/ycl/listener/flowable/FlowableOverTimeListener.java |   96 ++++++
 flowable/src/main/java/com/ycl/common/constant/ProcessOverTimeConstants.java   |   18 +
 flowable/src/main/java/com/ycl/service/ProcessCodingService.java               |   66 ++++
 flowable/src/main/java/com/ycl/mapper/ProcessCodingMapper.java                 |   39 ++
 flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java           |  104 +++---
 flowable/src/main/java/com/ycl/domain/vo/ProcessCodingVO.java                  |   59 ++++
 flowable/src/main/resources/mapper/ProcessCodingMapper.xml                     |   73 +++++
 flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java                     |    2 
 flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java                   |    4 
 flowable/src/main/java/com/ycl/domain/query/ProcessCodingQuery.java            |   22 +
 flowable/src/main/java/com/ycl/domain/form/ProcessCodingForm.java              |   62 ++++
 business/src/main/java/com/ycl/task/FlowableTask.java                          |   94 +++++-
 flowable/src/main/java/com/ycl/domain/entity/ProcessCoding.java                |   49 +++
 14 files changed, 734 insertions(+), 73 deletions(-)

diff --git a/business/src/main/java/com/ycl/listener/flowable/FlowableOverTimeListener.java b/business/src/main/java/com/ycl/listener/flowable/FlowableOverTimeListener.java
new file mode 100644
index 0000000..6fde445
--- /dev/null
+++ b/business/src/main/java/com/ycl/listener/flowable/FlowableOverTimeListener.java
@@ -0,0 +1,96 @@
+package com.ycl.listener.flowable;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ycl.common.utils.spring.SpringUtils;
+import com.ycl.domain.entity.ProcessCoding;
+import com.ycl.factory.FlowServiceFactory;
+import com.ycl.mapper.ProcessCodingMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.impl.el.FixedValue;
+import org.flowable.engine.delegate.TaskListener;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.service.delegate.DelegateTask;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+import static com.ycl.common.constant.ProcessOverTimeConstants.GREEN;
+
+/**
+ * 浠诲姟鐩戝惉鍣�
+ *
+ * create锛堝垱寤猴級:鍦ㄤ换鍔¤鍒涘缓涓旀墍鏈夌殑浠诲姟灞炴�ц缃畬鎴愬悗鎵嶈Е鍙�
+ * assignment锛堟寚娲撅級锛氬湪浠诲姟琚垎閰嶇粰鏌愪釜鍔炵悊浜轰箣鍚庤Е鍙�
+ * complete锛堝畬鎴愶級锛氬湪閰嶇疆浜嗙洃鍚櫒鐨勪笂涓�涓换鍔″畬鎴愭椂瑙﹀彂
+ * delete锛堝垹闄わ級锛氬湪浠诲姟鍗冲皢琚垹闄ゅ墠瑙﹀彂銆傝娉ㄦ剰浠诲姟鐢眂ompleteTask姝e父瀹屾垚鏃朵篃浼氳Е鍙�
+ *
+ * @author Tony
+ * @date 2021/4/20
+ */
+@Slf4j
+@Component
+public class FlowableOverTimeListener extends FlowServiceFactory implements TaskListener {
+    /**
+     * 榛勭爜鏃堕棿
+     */
+    private FixedValue yellowTime;
+    /**
+     * 绾㈢爜鏃堕棿
+     */
+    private FixedValue redTime;
+    /**
+     * 璁℃椂璧峰鑺傜偣瀹氫箟Id
+     */
+    private FixedValue startTaskId;
+
+    @Override
+    public void notify(DelegateTask delegateTask) {
+        log.info("瑙﹀彂瓒呮椂鐩戝惉鍣�:{}", delegateTask);
+        //Flowable鐨刡ean鑷繁绠$悊鐨勯渶瑕佹墜鍔ㄨ幏鍙�
+        ProcessCodingMapper processCodingMapper = SpringUtils.getBean(ProcessCodingMapper.class);
+        //浠诲姟id
+        String taskId = delegateTask.getId();
+        //娴佺▼瀹炰緥id
+        String processInstanceId = delegateTask.getProcessInstanceId();
+        ProcessCoding processCoding = new ProcessCoding();
+        processCoding.setTaskId(taskId);
+        processCoding.setProcessInsId(processInstanceId);
+        processCoding.setTaskDefKey(delegateTask.getTaskDefinitionKey());
+        //娑夊強鍒伴┏鍥烇紝闇�瑕佹煡涓�涓嬭繖涓妭鐐规槸鍚﹀凡缁忔坊鍔犺繃浜嗭紝濡傛灉娣诲姞杩囧氨涓嶈繘琛屽悗缁搷浣�
+        List<ProcessCoding> processCodings = processCodingMapper.selectList(new QueryWrapper<ProcessCoding>()
+                .eq("process_ins_id", processInstanceId)
+                .eq("task_def_key", delegateTask.getTaskDefinitionKey()));
+        if (CollectionUtils.isEmpty(processCodings)) {
+            processCoding.setStatus(GREEN);
+            if (yellowTime != null && yellowTime.getValue(delegateTask) != null) {
+                processCoding.setYellowTime(Integer.parseInt(yellowTime.getValue(delegateTask).toString()));
+            }
+            if (redTime != null && redTime.getValue(delegateTask) != null) {
+                processCoding.setRedTime(Integer.parseInt(redTime.getValue(delegateTask).toString()));
+            }
+            if (startTaskId != null && startTaskId.getValue(delegateTask) != null) {
+                String taskDefKey = startTaskId.getValue(delegateTask).toString();
+                //閫氳繃娴佺▼瀹炰緥id鍜岃妭鐐瑰畾涔塱d鎵惧埌瀵瑰簲taskId
+                if (delegateTask.getTaskDefinitionKey().equals(taskDefKey)) {
+                    //褰撳墠鑺傜偣涓哄紑濮嬭鏃惰妭鐐�
+                    processCoding.setStartTaskId(delegateTask.getId());
+                } else {
+                    //寮�濮嬭妭鐐逛粠鍘嗗彶鑺傜偣鏌ヨ 鍙栧鏉′腑鏈�鏃╃殑涓�鏉�
+                    List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
+                            .processInstanceId(processInstanceId)
+                            .taskDefinitionKey(delegateTask.getTaskDefinitionKey())
+                            .orderByHistoricTaskInstanceStartTime()
+                            .asc()
+                            .list();
+                    if (!CollectionUtils.isEmpty(list)) {
+                        HistoricTaskInstance hisTask = list.get(0);
+                        processCoding.setStartTaskId(hisTask.getId());
+                    }
+                }
+            }
+            processCodingMapper.insert(processCoding);
+            log.info("娣诲姞鑺傜偣鍒板畾鏃跺櫒");
+        }
+    }
+}
diff --git a/business/src/main/java/com/ycl/task/FlowableTask.java b/business/src/main/java/com/ycl/task/FlowableTask.java
index 7336100..5842b3b 100644
--- a/business/src/main/java/com/ycl/task/FlowableTask.java
+++ b/business/src/main/java/com/ycl/task/FlowableTask.java
@@ -2,23 +2,27 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
+import com.ycl.domain.entity.ProcessCoding;
 import com.ycl.domain.entity.ProjectInfo;
 import com.ycl.domain.entity.ProjectProcess;
 import com.ycl.factory.FlowServiceFactory;
+import com.ycl.mapper.ProcessCodingMapper;
 import com.ycl.mapper.ProjectInfoMapper;
 import com.ycl.mapper.ProjectProcessMapper;
-import com.ycl.service.ProjectProcessService;
+import com.ycl.service.ProcessCodingService;
 import lombok.extern.slf4j.Slf4j;
 import org.flowable.task.api.Task;
 import org.flowable.task.api.TaskInfo;
+import org.flowable.task.api.history.HistoricTaskInstance;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
+
+import static com.ycl.common.constant.ProcessOverTimeConstants.*;
 
 @Slf4j
 @Component("flowableTask")
@@ -27,28 +31,88 @@
     private ProjectProcessMapper projectProcessMapper;
     @Autowired
     private ProjectInfoMapper projectInfoMapper;
-
+    @Autowired
+    private ProcessCodingMapper processCodingMapper;
     /**
      * 璧嬬爜浠诲姟
+     * 涓や釜閫昏緫 鏀归」鐩爜銆佹敼鑺傜偣棰滆壊
      */
     public void expireTask() {
         log.info("寮�濮嬭祴鐮�");
+        //褰撳墠姝e湪杩愯鐨勬墍鏈変换鍔¤妭鐐�
         List<Task> taskList = taskService.createTaskQuery().list();
-        if (!CollectionUtils.isEmpty(taskList)) {
+        if(CollectionUtils.isEmpty(taskList)) return;
+        List<String> taskIds = taskList.stream().map(TaskInfo::getId).collect(Collectors.toList());
+        //闇�瑕佺洃鎺х殑璧嬬爜浠诲姟
+        List<ProcessCoding> processCodingList = processCodingMapper.selectList(new QueryWrapper<ProcessCoding>().in("task_id",taskIds));
+        if (!CollectionUtils.isEmpty(processCodingList)) {
+            //key涓簍askId value涓烘湰浣撳璞�
+            Map<String, ProcessCoding> taskMap = processCodingList.stream().collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity()));
+            //鎷垮埌寮�濮嬭鏃剁殑鑺傜偣闆嗗悎 key:taskId value:寮�濮嬫椂闂�
+            Map<String, Date> startTaskMap = getStartTaskList(processCodingList);
+            //鎻愬墠鍑嗗鎺ユ敹鏁版嵁鐨刴ap key:娴佺▼瀹炰緥id value:闇�瑕佹敼鍙樼殑棰滆壊
+            Map<String, List<String>> map = new HashMap<>();
+            List<ProcessCoding> list = new ArrayList<>();
+            map.put(GREEN, new ArrayList<>());
+            map.put(RED, new ArrayList<>());
+            map.put(YELLOW, new ArrayList<>());
             Date now = new Date();
-            // 鎸夎秴鏃剁姸鎬佸垎缁勪换鍔�
-            Map<Boolean, List<String>> processInstanceMap = taskList.stream()
-                    .collect(Collectors.groupingBy(
-                            task -> task.getDueDate() != null && now.after(task.getDueDate()),
-                            Collectors.mapping(TaskInfo::getProcessInstanceId, Collectors.toList())
-                    ));
-            // 澶勭悊瓒呮椂鍜屾湭瓒呮椂鐨勯」鐩�
-            updateProjectCoding(processInstanceMap.get(true), "red");    // 瓒呮椂椤圭洰
-            updateProjectCoding(processInstanceMap.get(false), "green"); // 鏈秴鏃堕」鐩�
+            //閬嶅巻鎵�鏈変唬鍔炵殑鑺傜偣
+            for (Task task : taskList) {
+                String taskId = task.getId();
+                ProcessCoding processCoding = taskMap.get(taskId);
+                if (processCoding == null) {
+                    //涓嶉渶瑕佺洃鎺х殑浠诲姟鑺傜偣鐩存帴鏀逛负缁胯壊
+                    List<String> processInsIds = map.get(GREEN);
+                    processInsIds.add(task.getProcessInstanceId());
+                    continue;
+                }
+                //鍒ゆ柇鏄惁瓒呮椂
+                Date startTime = startTaskMap.get(processCoding.getStartTaskId());
+                Integer yellowTime = processCoding.getYellowTime();
+                Integer redTime = processCoding.getRedTime();
+                if (startTime == null) continue;
+//                long durationDay = (now.getTime() - startTime.getTime()) / (1000 * 60 * 60 * 24);
+                long durationDay = (now.getTime() - startTime.getTime()) / (1000 * 60);
+                String status = GREEN; // 榛樿鐘舵�佷负缁胯壊
+                if (redTime != null && durationDay >= redTime) {
+                    status = RED; // 濡傛灉瓒呰繃绾㈣壊鏃堕棿闃堝�硷紝鍒欑姸鎬佷负绾㈣壊
+                } else if (yellowTime != null && durationDay >= yellowTime) {
+                    status = YELLOW; // 鍚﹀垯锛屽鏋滆秴杩囬粍鑹叉椂闂撮槇鍊硷紝鍒欑姸鎬佷负榛勮壊
+                }
+                List<String> processInsIds = map.get(status);
+                processInsIds.add(task.getProcessInstanceId());
+                processCoding.setStatus(status);
+                list.add(processCoding);
+            }
+            //鏇存柊椤圭洰鐮�
+            map.forEach((key,value)-> updateProjectCoding(value, key));
+            //鏇存柊鑺傜偣鐘舵�� 鑷畾涔夌殑mybatis鏂规硶
+            if(!CollectionUtils.isEmpty(list)) processCodingMapper.updateBatch(list);
         }
         log.info("缁撴潫璧嬬爜");
     }
 
+    private Map<String, Date> getStartTaskList(List<ProcessCoding> processCodingList) {
+        //鏌ュ嚭浠诲姟璁℃椂璧峰鑺傜偣闆嗗悎
+        List<String> startTaskIds = processCodingList.stream().map(ProcessCoding::getStartTaskId).collect(Collectors.toList());
+        //鏌ュ嚭璧峰璁℃椂鑺傜偣鏁版嵁 娉ㄦ剰姝e湪杩涜鐨勪换鍔′笉浼氳繘鍏is琛� 缁撴潫浜嗘墠浼氳繘鍏� 鎵�浠ラ渶瑕佹煡涓ゅ紶琛�
+        Map<String, Date> startDateMap = new HashMap<>();
+        List<Task> startTasks = taskService.createTaskQuery().taskIds(startTaskIds).list();
+        List<HistoricTaskInstance> hisStartTasks = historyService.createHistoricTaskInstanceQuery().taskIds(startTaskIds).list();
+        if (!CollectionUtils.isEmpty(startTasks)) {
+            startTasks.forEach(task -> {
+                startDateMap.put(task.getId(), task.getCreateTime());
+            });
+        }
+        if (!CollectionUtils.isEmpty(hisStartTasks)) {
+            hisStartTasks.forEach(hisTask -> {
+                startDateMap.put(hisTask.getId(), hisTask.getStartTime());
+            });
+        }
+        return startDateMap;
+    }
+
     /**
      * 璧嬬爜
      *
diff --git a/flowable/src/main/java/com/ycl/common/constant/ProcessOverTimeConstants.java b/flowable/src/main/java/com/ycl/common/constant/ProcessOverTimeConstants.java
new file mode 100644
index 0000000..10d736b
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/common/constant/ProcessOverTimeConstants.java
@@ -0,0 +1,18 @@
+package com.ycl.common.constant;
+
+public class ProcessOverTimeConstants {
+    /**
+     * 缁跨爜
+     */
+    public static final String GREEN = "green";
+
+    /**
+     * 绾㈢爜
+     */
+    public static final String RED = "red";
+
+    /**
+     * 榛勭爜
+     */
+    public static final String YELLOW = "yellow";
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java
index 1e639a4..d4af86e 100644
--- a/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java
@@ -99,6 +99,6 @@
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date finishTime;
 
-    private Boolean overtime;
+    private String overtime;
 
 }
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java
index 63f252f..73ba121 100644
--- a/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java
@@ -22,7 +22,7 @@
     private boolean completed;
 
     /**
-     * 鏄惁宸茬粡瓒呮椂
+     * 椤圭洰瓒呮椂棰滆壊鐮� green/yellow/red
      */
-    private boolean overtime;
+    private String overtime;
 }
diff --git a/flowable/src/main/java/com/ycl/domain/entity/ProcessCoding.java b/flowable/src/main/java/com/ycl/domain/entity/ProcessCoding.java
new file mode 100644
index 0000000..4820b53
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/ProcessCoding.java
@@ -0,0 +1,49 @@
+package com.ycl.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ycl.system.domain.base.AbsEntity;
+import lombok.Data;
+
+/**
+ *
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Data
+@TableName("t_process_coding")
+public class ProcessCoding extends AbsEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("task_id")
+    /** 鑺傜偣id */
+    private String taskId;
+
+    @TableField("task_def_key")
+    /** 鑺傜偣瀹氫箟key */
+    private String taskDefKey;
+
+    @TableField("start_task_id")
+    /** 璁℃椂鐨勮捣濮嬭妭鐐筰d */
+    private String startTaskId;
+
+    @TableField("process_ins_id")
+    /** 娴佺▼瀹炰緥id */
+    private String processInsId;
+
+    @TableField("yellow_time")
+    /** 鍙橀粍鐮佺殑澶╂暟 */
+    private Integer yellowTime;
+
+    @TableField("red_time")
+    /** 鍙樼孩鐮佺殑澶╂暟 */
+    private Integer redTime;
+
+    @TableField("status")
+    /** 浠诲姟鐘舵�� */
+    private String status;
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/form/ProcessCodingForm.java b/flowable/src/main/java/com/ycl/domain/form/ProcessCodingForm.java
new file mode 100644
index 0000000..933a331
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/form/ProcessCodingForm.java
@@ -0,0 +1,62 @@
+package com.ycl.domain.form;
+
+import com.ycl.common.group.Update;
+import com.ycl.common.group.Add;
+import com.ycl.system.domain.base.AbsForm;
+import com.ycl.domain.entity.ProcessCoding;
+import org.springframework.beans.BeanUtils;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import org.springframework.lang.NonNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 琛ㄥ崟
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Data
+@ApiModel(value = "ProcessCoding琛ㄥ崟", description = "琛ㄥ崟")
+public class ProcessCodingForm extends AbsForm {
+
+    @NotBlank(message = "鑺傜偣id涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鑺傜偣id")
+    private String taskId;
+
+    @NotBlank(message = "鑺傜偣瀹氫箟key涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鑺傜偣瀹氫箟key")
+    private String taskDefKey;
+
+    @NotBlank(message = "璁℃椂鐨勮捣濮嬭妭鐐筰d涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("璁℃椂鐨勮捣濮嬭妭鐐筰d")
+    private String startTaskId;
+
+    @NotBlank(message = "娴佺▼瀹炰緥id涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("娴佺▼瀹炰緥id")
+    private String processInsId;
+
+    @NotNull(message = "鍙橀粍鐮佺殑澶╂暟涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鍙橀粍鐮佺殑澶╂暟")
+    private Integer yellowTime;
+
+    @NotNull(message = "鍙樼孩鐮佺殑澶╂暟涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鍙樼孩鐮佺殑澶╂暟")
+    private Integer redTime;
+
+    @NotNull(message = "浠诲姟鐘舵��", groups = {Add.class, Update.class})
+    @ApiModelProperty("浠诲姟鐘舵�乬reen/yellow/red")
+    private String status;
+
+    public static ProcessCoding getEntityByForm(@NonNull ProcessCodingForm form, ProcessCoding entity) {
+        if(entity == null) {
+          entity = new ProcessCoding();
+        }
+        BeanUtils.copyProperties(form, entity);
+        return entity;
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/query/ProcessCodingQuery.java b/flowable/src/main/java/com/ycl/domain/query/ProcessCodingQuery.java
new file mode 100644
index 0000000..67bd159
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/query/ProcessCodingQuery.java
@@ -0,0 +1,22 @@
+package com.ycl.domain.query;
+
+import com.ycl.system.domain.base.AbsQuery;
+import java.util.List;
+import org.springframework.lang.NonNull;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 鏌ヨ
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Data
+@ApiModel(value = "ProcessCoding鏌ヨ鍙傛暟", description = "鏌ヨ鍙傛暟")
+public class ProcessCodingQuery extends AbsQuery {
+}
+
diff --git a/flowable/src/main/java/com/ycl/domain/vo/ProcessCodingVO.java b/flowable/src/main/java/com/ycl/domain/vo/ProcessCodingVO.java
new file mode 100644
index 0000000..7282c21
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/vo/ProcessCodingVO.java
@@ -0,0 +1,59 @@
+package com.ycl.domain.vo;
+
+import com.ycl.system.domain.base.AbsVo;
+import com.ycl.domain.entity.ProcessCoding;
+import java.util.List;
+import org.springframework.lang.NonNull;
+import org.springframework.beans.BeanUtils;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 灞曠ず
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Data
+@ApiModel(value = "鍝嶅簲鏁版嵁", description = "鍝嶅簲鏁版嵁")
+public class ProcessCodingVO extends AbsVo {
+
+    /** 鑺傜偣id */
+    @ApiModelProperty("鑺傜偣id")
+    private String taskId;
+
+    /** 鑺傜偣瀹氫箟key */
+    @ApiModelProperty("鑺傜偣瀹氫箟key")
+    private String taskDefKey;
+
+    /** 璁℃椂鐨勮捣濮嬭妭鐐筰d */
+    @ApiModelProperty("璁℃椂鐨勮捣濮嬭妭鐐筰d")
+    private String startTaskId;
+
+    /** 娴佺▼瀹炰緥id */
+    @ApiModelProperty("娴佺▼瀹炰緥id")
+    private String processInsId;
+
+    /** 鍙橀粍鐮佺殑澶╂暟 */
+    @ApiModelProperty("鍙橀粍鐮佺殑澶╂暟")
+    private Integer yellowTime;
+
+    /** 鍙樼孩鐮佺殑澶╂暟 */
+    @ApiModelProperty("鍙樼孩鐮佺殑澶╂暟")
+    private Integer redTime;
+
+    /** 浠诲姟鐘舵��0杩涜涓�1缁撴潫 */
+    @ApiModelProperty("浠诲姟鐘舵�乬reen/red/yellow")
+    private String status;
+
+    public static ProcessCodingVO getVoByEntity(@NonNull ProcessCoding entity, ProcessCodingVO vo) {
+        if(vo == null) {
+            vo = new ProcessCodingVO();
+        }
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/ProcessCodingMapper.java b/flowable/src/main/java/com/ycl/mapper/ProcessCodingMapper.java
new file mode 100644
index 0000000..829157c
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/ProcessCodingMapper.java
@@ -0,0 +1,39 @@
+package com.ycl.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.ycl.domain.entity.ProcessCoding;
+import com.ycl.domain.query.ProcessCodingQuery;
+import com.ycl.domain.vo.ProcessCodingVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *  Mapper 鎺ュ彛
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Mapper
+public interface ProcessCodingMapper extends BaseMapper<ProcessCoding> {
+
+    /**
+     * id鏌ユ壘
+     * @param id
+     * @return
+     */
+    ProcessCodingVO getById(Integer id);
+
+    /**
+    *  鍒嗛〉
+    */
+    IPage getPage(IPage page, @Param("query") ProcessCodingQuery query);
+
+    /**
+     * 鑷畾涔夋壒閲忔洿鏂�
+     * @param list
+     */
+    void updateBatch(@Param("list") List<ProcessCoding> list);
+}
diff --git a/flowable/src/main/java/com/ycl/service/ProcessCodingService.java b/flowable/src/main/java/com/ycl/service/ProcessCodingService.java
new file mode 100644
index 0000000..a270408
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/ProcessCodingService.java
@@ -0,0 +1,66 @@
+package com.ycl.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ycl.common.base.Result;
+import com.ycl.domain.entity.ProcessCoding;
+import com.ycl.domain.form.ProcessCodingForm;
+import com.ycl.domain.query.ProcessCodingQuery;
+
+import java.util.List;
+
+/**
+ *  鏈嶅姟绫�
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+public interface ProcessCodingService extends IService<ProcessCoding> {
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    Result add(ProcessCodingForm form);
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    Result update(ProcessCodingForm form);
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    Result remove(List<String> ids);
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    Result removeById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    Result page(ProcessCodingQuery query);
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    Result detail(Integer id);
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    Result all();
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
index 09202bf..26a400d 100644
--- a/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
+++ b/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
@@ -4,6 +4,7 @@
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
 import com.alibaba.fastjson2.TypeReference;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ycl.common.constant.ProcessConstants;
 import com.ycl.common.core.domain.AjaxResult;
@@ -17,6 +18,7 @@
 import com.ycl.domain.dto.FlowNextDto;
 import com.ycl.domain.dto.FlowTaskDto;
 import com.ycl.domain.dto.FlowViewerDto;
+import com.ycl.domain.entity.ProcessCoding;
 import com.ycl.domain.entity.SysForm;
 import com.ycl.domain.vo.FlowQueryVo;
 import com.ycl.domain.vo.FlowTaskVo;
@@ -25,6 +27,7 @@
 import com.ycl.flow.CustomProcessDiagramGenerator;
 import com.ycl.flow.FindNextNodeUtil;
 import com.ycl.flow.FlowableUtils;
+import com.ycl.mapper.ProcessCodingMapper;
 import com.ycl.service.IFlowTaskService;
 import com.ycl.service.ISysDeployFormService;
 import com.ycl.service.ISysFormService;
@@ -71,6 +74,9 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import static com.ycl.common.constant.ProcessOverTimeConstants.RED;
+import static com.ycl.common.constant.ProcessOverTimeConstants.YELLOW;
+
 /**
  * @author Tony
  * @date 2021-04-03
@@ -86,6 +92,7 @@
     private final ISysDeployFormService sysInstanceFormService;
     private final ISysFormService sysFormService;
     private final TaskCommonService taskCommonService;
+    private final ProcessCodingMapper processCodingMapper;
 
     /**
      * 瀹屾垚瀹℃牳浠诲姟
@@ -114,8 +121,8 @@
     /**
      * 瀹屾垚琛ㄥ崟鎻愪氦浠诲姟/鏅�氫换鍔�
      *
-     * @param taskId  浠诲姟id
-     * @param variables  琛ㄥ崟鏁版嵁
+     * @param taskId    浠诲姟id
+     * @param variables 琛ㄥ崟鏁版嵁
      * @return
      */
     @Override
@@ -126,7 +133,7 @@
             return AjaxResult.error("浠诲姟涓嶅瓨鍦�");
         }
         Map<String, Object> newV = new HashMap<>(2);
-        if (! org.springframework.util.CollectionUtils.isEmpty(variables)) {
+        if (!org.springframework.util.CollectionUtils.isEmpty(variables)) {
             for (String key : variables.keySet()) {
                 newV.put(task.getTaskDefinitionKey() + "&" + key, variables.get(key));
 //                if (ProcessConstants.TASK_FORM_KEY.equals(key)) {
@@ -310,7 +317,6 @@
         if (!isSequential) {
             throw new CustomException("褰撳墠鑺傜偣鐩稿浜庣洰鏍囪妭鐐癸紝涓嶅睘浜庝覆琛屽叧绯伙紝鏃犳硶鍥為��");
         }
-
 
         // 鑾峰彇鎵�鏈夋甯歌繘琛岀殑浠诲姟鑺傜偣 Key锛岃繖浜涗换鍔′笉鑳界洿鎺ヤ娇鐢紝闇�瑕佹壘鍑哄叾涓渶瑕佹挙鍥炵殑浠诲姟
         List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
@@ -792,11 +798,11 @@
                     .processInstanceId(procInsId)
                     .orderByHistoricActivityInstanceStartTime()
                     .desc().list();
-            Date now =new Date();
-            //鎵╁睍
-            List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
-                    .processInstanceId(procInsId)
-                    .list();
+            Date now = new Date();
+            //鎵╁睍 鑾峰彇杩欎釜娴佺▼瀹炰緥鐨勭洃鎺т俊鎭� key:TaskId value:瀹炰綋绫�
+            Map<String, ProcessCoding> processCodingMap = processCodingMapper.selectList(new QueryWrapper<ProcessCoding>().eq("process_ins_id", procInsId))
+                    .stream()
+                    .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity()));
             List<FlowTaskDto> hisFlowList = new ArrayList<>();
             for (HistoricActivityInstance histIns : list) {
                 // 灞曠ず寮�濮嬭妭鐐�
@@ -855,21 +861,19 @@
                     }
 
                     flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
-                    String taskId = histIns.getTaskId();
-
                     //鎵╁睍 鍒ゆ柇鏄惁瓒呮椂
-                    for (HistoricTaskInstance taskInstance : taskList) {
-                        Date dueDate = taskInstance.getDueDate();
-                        //鎵惧埌瀵瑰簲浠诲姟鑺傜偣
-                        if(dueDate!=null && taskInstance.getId().equals(taskId) ) {
-                            //濡傛灉浠诲姟杩樻病瀹屾垚
-                            if(flowTask.getDuration()==null) {
-                                //鍒ゆ柇褰撳墠鏃堕棿鏄惁瓒呰繃鍒版湡鏃堕棿
-                                if (now.after(dueDate)) flowTask.setOvertime(Boolean.TRUE);
-                            }else {
-                                //濡傛灉浠诲姟鑺傜偣宸茬粡瀹屾垚浜嗭紝鐢ㄥ畬鎴愭椂闂村垽鏂�
-                                if(histIns.getEndTime().after(dueDate)) flowTask.setOvertime(Boolean.TRUE);
+                    ProcessCoding processCoding = processCodingMap.get(histIns.getTaskId());
+                    if(processCoding!=null){
+                        //濡傛灉浠诲姟鏄唬鍔炶妭鐐�
+                        if (flowTask.getDuration() == null) {
+                            if(RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus())){
+                                flowTask.setOvertime(processCoding.getStatus());
                             }
+                        }else {
+                            //濡傛灉浠诲姟鑺傜偣灞炰簬鍘嗗彶鑺傜偣
+                            if(RED.equals(processCoding.getStatus())){
+                                flowTask.setOvertime(processCoding.getStatus());
+                            };
                         }
                     }
                     // 鑾峰彇鎰忚璇勮鍐呭
@@ -1117,35 +1121,28 @@
     @Override
     public AjaxResult flowXmlAndNode(String procInsId, String deployId) {
         try {
-            Date now = new Date();
+
             List<FlowViewerDto> flowViewerList = new ArrayList<>();
             // 鑾峰彇宸茬粡瀹屾垚鐨勮妭鐐�
             List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                     .processInstanceId(procInsId)
                     .finished()
                     .list();
-            //鑾峰彇鎵�鏈夊巻鍙蹭换鍔¤妭鐐逛俊鎭�(鎵╁睍)
-            List<HistoricTaskInstance> taskHistoryList = historyService.createHistoricTaskInstanceQuery()
-                    .processInstanceId(procInsId)
-                    .finished()
-                    .list();
-            //鑾峰彇鎵�鏈夊綋鍓嶄换鍔¤妭鐐逛俊鎭�(鎵╁睍)
-            List<Task> taskList = taskService.createTaskQuery()
-                    .processInstanceId(procInsId)
-                    .list();
+
+            //鑾峰彇杩欎釜娴佺▼瀹炰緥鐨勭洃鎺т俊鎭� key:TaskId value:瀹炰綋绫�
+            Map<String, ProcessCoding> processCodingMap = processCodingMapper.selectList(new QueryWrapper<ProcessCoding>().eq("process_ins_id", procInsId))
+                    .stream()
+                    .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity()));
             // 淇濆瓨宸茬粡瀹屾垚鐨勬祦绋嬭妭鐐圭紪鍙�
             listFinished.forEach(s -> {
                 FlowViewerDto flowViewerDto = new FlowViewerDto();
                 flowViewerDto.setKey(s.getActivityId());
                 flowViewerDto.setCompleted(true);
-                //鎵╁睍鍐呭 宸插畬鎴愮殑鐢ㄥ畬鎴愭椂闂村垽鏂�
-                Date endTime = s.getEndTime();
-                for (HistoricTaskInstance task : taskHistoryList) {
-                    if(s.getTaskId()!=null && s.getTaskId().equals(task.getId())){
-                        if(task.getDueDate()!=null && endTime.after(task.getDueDate())){
-                            flowViewerDto.setOvertime(true);
-                        }
-                    }
+                //鎵╁睍鍐呭 涓嶅弽overtime鍓嶇榛樿鏄豢鑹�
+                ProcessCoding processCoding = processCodingMap.get(s.getTaskId());
+                //濡傛灉鏈夌洃鎺ф暟鎹�, 鍘嗗彶鑺傜偣鍙垽鏂孩鐮�
+                if (processCoding != null && RED.equals(processCoding.getStatus())) {
+                    flowViewerDto.setOvertime(processCoding.getStatus());
                 }
                 // 閫�鍥炶妭鐐逛笉杩涜灞曠ず
                 if (StringUtils.isBlank(s.getDeleteReason())) {
@@ -1158,7 +1155,6 @@
                     .processInstanceId(procInsId)
                     .unfinished()
                     .list();
-
             // 淇濆瓨闇�瑕佷唬鍔炵殑鑺傜偣缂栧彿
             listUnFinished.forEach(s -> {
                 // 鍒犻櫎宸查��鍥炶妭鐐�
@@ -1166,13 +1162,11 @@
                 FlowViewerDto flowViewerDto = new FlowViewerDto();
                 flowViewerDto.setKey(s.getActivityId());
                 flowViewerDto.setCompleted(false);
-                //鎵╁睍鍐呭 浠e姙鐨勯�氳繃褰撳墠鏃堕棿鍘诲垽鏂�
-                for (Task task : taskList) {
-                    if(s.getTaskId()!=null && s.getTaskId().equals(task.getId())){
-                        if(task.getDueDate()!=null && now.after(task.getDueDate())){
-                            flowViewerDto.setOvertime(true);
-                        }
-                    }
+                // 鎵╁睍鍐呭 浠e姙鐨勯�氳繃褰撳墠鏃堕棿浣滀负endTime
+                ProcessCoding processCoding = processCodingMap.get(s.getTaskId());
+                //濡傛灉鏈夌洃鎺ф暟鎹� 涓嶅弽鐨勮瘽鍓嶇榛樿鏄繘琛屼腑(钃濊壊)
+                if (processCoding != null && (RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus()))) {
+                    flowViewerDto.setOvertime(processCoding.getStatus());
                 }
                 flowViewerList.add(flowViewerDto);
             });
@@ -1185,6 +1179,7 @@
             result.put("xmlData", xmlData);
             return AjaxResult.success(result);
         } catch (Exception e) {
+            e.printStackTrace();
             return AjaxResult.error("楂樹寒鍘嗗彶浠诲姟澶辫触");
         }
     }
@@ -1234,15 +1229,15 @@
     /**
      * 鑾峰彇褰撳墠鑺傜偣鍜屼笂涓�鑺傜偣鐨勮〃鍗曞唴瀹�
      *
-     * @param parameters 鏍规嵁浠诲姟鏌ユ壘鍑烘潵鐨勫弬鏁�
-     * @param formKey task鑷韩鍏宠仈鐨勮〃鍗昳d
-     * @param taskName task鑷韩鐨勪换鍔″悕
-     * @param processDefId 娴佺▼瀹氫箟id
+     * @param parameters    鏍规嵁浠诲姟鏌ユ壘鍑烘潵鐨勫弬鏁�
+     * @param formKey       task鑷韩鍏宠仈鐨勮〃鍗昳d
+     * @param taskName      task鑷韩鐨勪换鍔″悕
+     * @param processDefId  娴佺▼瀹氫箟id
      * @param processDefKey 娴佺▼瀹炰緥id
      * @return
      */
     private List<FormDetailVO> getBeforeNodeForm(Map<String, Object> parameters, String formKey, String taskName, String processDefId, String processDefKey, Boolean currentNeedData) {
-        if (! parameters.keySet().stream().anyMatch(key -> key.contains(ProcessConstants.TASK_FORM_KEY))) {
+        if (!parameters.keySet().stream().anyMatch(key -> key.contains(ProcessConstants.TASK_FORM_KEY))) {
             // 濡傛灉鏄┖鐨勶紝浣跨敤formId鍘绘煡
             if (StringUtils.isNotBlank(formKey)) {
                 SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(formKey));
@@ -1277,8 +1272,7 @@
                     if (key.startsWith(formDetailVO.getBeforeNodeDefId())) {
                         if (key.contains(ProcessConstants.TASK_FORM_KEY)) {
                             newP.put(key, parameters.get(key));
-                        }
-                        else {
+                        } else {
                             newP.put(key.split("&")[1], parameters.get(key));
                         }
                     }
diff --git a/flowable/src/main/java/com/ycl/service/impl/ProcessCodingServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/ProcessCodingServiceImpl.java
new file mode 100644
index 0000000..a40d634
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/ProcessCodingServiceImpl.java
@@ -0,0 +1,119 @@
+package com.ycl.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ycl.common.base.Result;
+import com.ycl.domain.entity.ProcessCoding;
+import com.ycl.domain.form.ProcessCodingForm;
+import com.ycl.domain.query.ProcessCodingQuery;
+import com.ycl.domain.vo.ProcessCodingVO;
+import com.ycl.framework.utils.PageUtil;
+import com.ycl.mapper.ProcessCodingMapper;
+import com.ycl.service.ProcessCodingService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *  鏈嶅姟瀹炵幇绫�
+ *
+ * @author flq
+ * @since 2025-01-02
+ */
+@Service
+@RequiredArgsConstructor
+public class ProcessCodingServiceImpl extends ServiceImpl<ProcessCodingMapper, ProcessCoding> implements ProcessCodingService {
+
+    private final ProcessCodingMapper processCodingMapper;
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    @Override
+    public Result add(ProcessCodingForm form) {
+        ProcessCoding entity = ProcessCodingForm.getEntityByForm(form, null);
+        baseMapper.insert(entity);
+        return Result.ok("娣诲姞鎴愬姛");
+    }
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    @Override
+    public Result update(ProcessCodingForm form) {
+        ProcessCoding entity = baseMapper.selectById(form.getId());
+
+        // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊
+        Assert.notNull(entity, "璁板綍涓嶅瓨鍦�");
+        BeanUtils.copyProperties(form, entity);
+        baseMapper.updateById(entity);
+        return Result.ok("淇敼鎴愬姛");
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    @Override
+    public Result remove(List<String> ids) {
+        baseMapper.deleteBatchIds(ids);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    @Override
+    public Result removeById(String id) {
+        baseMapper.deleteById(id);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    @Override
+    public Result page(ProcessCodingQuery query) {
+        IPage<ProcessCodingVO> page = PageUtil.getPage(query, ProcessCodingVO.class);
+        baseMapper.getPage(page, query);
+        return Result.ok().data(page.getRecords()).total(page.getTotal());
+    }
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    @Override
+    public Result detail(Integer id) {
+        ProcessCodingVO vo = baseMapper.getById(id);
+        Assert.notNull(vo, "璁板綍涓嶅瓨鍦�");
+        return Result.ok().data(vo);
+    }
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    @Override
+    public Result all() {
+        List<ProcessCoding> entities = baseMapper.selectList(null);
+        List<ProcessCodingVO> vos = entities.stream()
+                .map(entity -> ProcessCodingVO.getVoByEntity(entity, null))
+                .collect(Collectors.toList());
+        return Result.ok().data(vos);
+    }
+}
diff --git a/flowable/src/main/resources/mapper/ProcessCodingMapper.xml b/flowable/src/main/resources/mapper/ProcessCodingMapper.xml
new file mode 100644
index 0000000..c87910b
--- /dev/null
+++ b/flowable/src/main/resources/mapper/ProcessCodingMapper.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.ProcessCodingMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ycl.domain.vo.ProcessCodingVO">
+        <result column="task_id" property="taskId" />
+        <result column="task_def_key" property="taskDefKey" />
+        <result column="start_task_id" property="startTaskId" />
+        <result column="process_ins_id" property="processInsId" />
+        <result column="yellow_time" property="yellowTime" />
+        <result column="red_time" property="redTime" />
+        <result column="status" property="status" />
+    </resultMap>
+
+
+    <select id="getById" resultMap="BaseResultMap">
+        SELECT
+            TPC.task_id,
+            TPC.task_def_key,
+            TPC.start_task_id,
+            TPC.process_ins_id,
+            TPC.yellow_time,
+            TPC.red_time,
+            TPC.status,
+            TPC.id
+        FROM
+            t_process_coding TPC
+        WHERE
+            TPC.id = #{id} AND TPC.deleted = 0
+    </select>
+
+
+    <select id="getPage" resultMap="BaseResultMap">
+        SELECT
+            TPC.task_id,
+            TPC.task_def_key,
+            TPC.start_task_id,
+            TPC.process_ins_id,
+            TPC.yellow_time,
+            TPC.red_time,
+            TPC.status,
+            TPC.id
+        FROM
+            t_process_coding TPC
+        WHERE
+            TPC.deleted = 0
+    </select>
+
+    <!-- 鑷畾涔夋壒閲忔洿鏂�,浣跨敤鍓嶅垽鏂璴ist鏄惁涓虹┖ 杞崲涓簊ql
+    update t_process_coding
+    set status =
+    case
+        when id = #{item.id} then #{item.status}
+        ...
+    end
+    where id in (...);-->
+    <update id="updateBatch" parameterType="java.util.List">
+        update t_process_coding
+        <trim prefix="set" suffixOverrides=","><!-- 琛ㄧず鍦ㄧ敓鎴愮殑 SQL 璇彞鍓嶉潰娣诲姞 set 鍏抽敭瀛楋紝骞剁Щ闄ゆ湯灏鹃�楀彿 -->
+            <trim prefix="status =case" suffix="end,"><!-- 鏋勯�燾ase璇硶 鏈熬鍔犱笂end锛屽鏋滈渶瑕佹洿鏂板涓瓧娈靛鍒惰繖涓猼rim -->
+                <foreach collection="list" item="item">
+                    when id=#{item.id} then #{item.status}
+                </foreach>
+            </trim>
+        </trim>
+        where id in
+        <foreach collection="list" index="index" item="item" separator="," open="(" close=")">
+            #{item.id,jdbcType=BIGINT}
+        </foreach>
+    </update>
+
+</mapper>

--
Gitblit v1.8.0