diff --git a/src/main/java/com/yunhai/flowcenter/controller/api/FlowAdminController.java b/src/main/java/com/yunhai/flowcenter/controller/api/FlowAdminController.java index d132bce..23c0558 100644 --- a/src/main/java/com/yunhai/flowcenter/controller/api/FlowAdminController.java +++ b/src/main/java/com/yunhai/flowcenter/controller/api/FlowAdminController.java @@ -102,7 +102,7 @@ public class FlowAdminController { return defAdminService.get(adminGuard.requireAdmin(user, null), id); } - /** 保存(新建草稿/编辑;已发布定义保存=升版本,flowGuid 不变;baseGuid=在指定流程线上开新版本草稿) */ + /** 保存(新建草稿/编辑;已发布定义保存=升版本,flowGuid 不变;baseGuid=在指定流程线上开新版本草稿;changeLog=升版本改动说明,仅新版本行落库,>500 截断) */ @PostMapping("/def/save") public FlwDef defSave(BoaUser user, @RequestBody Map body) { Long schId = adminGuard.requireAdmin(user, null); @@ -110,7 +110,7 @@ public class FlowAdminController { return defAdminService.save(schId, id, (String) body.get("code"), (String) body.get("name"), (String) body.get("contentJson"), (String) body.get("baseGuid"), - (String) body.get("appKey")); + (String) body.get("appKey"), (String) body.get("changeLog")); } /** @@ -146,6 +146,16 @@ public class FlowAdminController { return defAdminService.versions(adminGuard.requireAdmin(user, null), flowGuid); } + /** 在途办件数(议题二④):flowGuids 逗号分隔,去重后最多 100;返回 flowGuid → 审批中办件数(无在途也返 0 键) */ + @GetMapping("/def/inflight") + public Map defInflight(BoaUser user, @RequestParam("flowGuids") String flowGuids) { + Long schId = adminGuard.requireAdmin(user, null); + List guids = java.util.Arrays.stream(flowGuids.split(",")) + .map(String::trim).filter(s -> !s.isEmpty()).distinct().limit(100) + .collect(java.util.stream.Collectors.toList()); + return defAdminService.inflightCounts(schId, guids); + } + /** 流程定义示意图(方案 §3.1):requireAdmin 后按 defId 任意版本出图(草稿可预览) */ @GetMapping("/def/diagram") public FlowModels.DiagramVo defDiagram(BoaUser user, @RequestParam("id") Long id, diff --git a/src/main/java/com/yunhai/flowcenter/entity/FlwDef.java b/src/main/java/com/yunhai/flowcenter/entity/FlwDef.java index 13ac96f..f053583 100644 --- a/src/main/java/com/yunhai/flowcenter/entity/FlwDef.java +++ b/src/main/java/com/yunhai/flowcenter/entity/FlwDef.java @@ -71,4 +71,8 @@ public class FlwDef extends BaseEntity { /** 发布时间 */ @Column(name = "publish_time") private LocalDateTime publishTime; + + /** 升版本改动说明(议题二③,可跳过;仅新版本行有值,草稿直改不写) */ + @Column(name = "change_log", length = 500) + private String changeLog; } diff --git a/src/main/java/com/yunhai/flowcenter/repository/FlwDefRepository.java b/src/main/java/com/yunhai/flowcenter/repository/FlwDefRepository.java index 521a266..83f11b7 100644 --- a/src/main/java/com/yunhai/flowcenter/repository/FlwDefRepository.java +++ b/src/main/java/com/yunhai/flowcenter/repository/FlwDefRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -36,4 +37,7 @@ public interface FlwDefRepository extends JpaRepository { + "and d.version = (select max(d2.version) from FlwDef d2 where d2.schId = d.schId " + "and d2.flowGuid = d.flowGuid and d2.status = 1) order by d.updateTime desc") List findPublishedLatestPerGuid(@Param("schId") Long schId); + + /** 在途统计(议题二④):一次取回多条流程线的全部版本行 */ + List findBySchIdAndFlowGuidIn(Long schId, Collection flowGuids); } diff --git a/src/main/java/com/yunhai/flowcenter/repository/FlwInstanceRepository.java b/src/main/java/com/yunhai/flowcenter/repository/FlwInstanceRepository.java index c225ec4..1748828 100644 --- a/src/main/java/com/yunhai/flowcenter/repository/FlwInstanceRepository.java +++ b/src/main/java/com/yunhai/flowcenter/repository/FlwInstanceRepository.java @@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -39,4 +40,8 @@ public interface FlwInstanceRepository extends JpaRepository + "and (:status is null or i.status = :status) order by i.id desc") Page pageByBiz(@Param("schId") Long schId, @Param("bizType") String bizType, @Param("status") Integer status, Pageable pageable); + + /** 在途办件数(议题二④):按 def_id 分组统计审批中(10)办件,一行一版本 */ + @Query("select i.defId, count(i) from FlwInstance i where i.schId = :schId and i.defId in :defIds and i.status = 10 group by i.defId") + List countApprovingByDefIds(@Param("schId") Long schId, @Param("defIds") Collection defIds); } diff --git a/src/main/java/com/yunhai/flowcenter/service/FlowDefAdminService.java b/src/main/java/com/yunhai/flowcenter/service/FlowDefAdminService.java index ecce6da..ceec023 100644 --- a/src/main/java/com/yunhai/flowcenter/service/FlowDefAdminService.java +++ b/src/main/java/com/yunhai/flowcenter/service/FlowDefAdminService.java @@ -18,7 +18,10 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.UUID; @@ -36,6 +39,7 @@ public class FlowDefAdminService { private final com.yunhai.flowcenter.repository.FlwRouterRepository routerRepository; private final com.yunhai.flowcenter.repository.FlwCallbackRegRepository regRepository; private final com.yunhai.flowcenter.repository.FlwAppRepository appRepository; + private final com.yunhai.flowcenter.repository.FlwInstanceRepository instanceRepository; private final FlowDeptAdminService deptAdminService; private final FlowEngine flowEngine; private final ObjectMapper objectMapper; @@ -77,9 +81,13 @@ public class FlowDefAdminService { * - id 空:永远新开一条流程线(flowGuid 生成,version=1);同编码多条线合法,前端保存前有软提示 * appKey=归属应用(筛选维度,2026-10-12 拍板必填):新建必须显式传;升版本/直改可继承源行, * 但源行为空时必须显式补填——存量 NULL 线随编辑自然收敛(白名单只校验显式传入值,继承值不重校) + * changeLog=升版本改动说明(议题二③):只随新建行落库(三个建新行分支),草稿直改行不写也不清空 */ @Transactional - public FlwDef save(Long schId, Long id, String code, String name, String contentJson, String baseGuid, String appKey) { + public FlwDef save(Long schId, Long id, String code, String name, String contentJson, + String baseGuid, String appKey, String changeLog) { + String cleanLog = (changeLog == null || changeLog.trim().isEmpty()) ? null + : changeLog.trim().substring(0, Math.min(500, changeLog.trim().length())); String cleanAppKey = (appKey == null || appKey.trim().isEmpty()) ? null : appKey.trim(); // 归属应用白名单(2026-10-10 应用设置):显式传入非空时必须 ∈ flw_app(sch, enabled=1); // 继承值不重校(既成事实,应用停用不应卡死升版本)。不在校池/未开启的应用由此拦下(拍板 D2:不做存量兜底) @@ -141,6 +149,10 @@ public class FlowDefAdminService { throw new BizException(ErrorCode.PARAM_ERROR, "归属应用必填:请选择归属应用后再保存(应用需先在 流程管理 > 应用设置 中开启)"); } + // 改动说明只写新建行(新建/baseGuid 开版/已发布复制升版三分支 id 必为 null);草稿直改不动 + if (def.getId() == null) { + def.setChangeLog(cleanLog); + } def.setContentJson(contentJson); // 定义 JSON 里的 code/name 与行字段一致性校验(给绑定回显用行字段,JSON 内为主) if (parsed.code != null && !parsed.code.trim().isEmpty() && !parsed.code.trim().equals(def.getCode())) { @@ -205,6 +217,23 @@ public class FlowDefAdminService { return defRepository.findBySchIdAndFlowGuidOrderByVersionDesc(schId, flowGuid); } + /** 在途办件数(议题二④):flowGuid → 审批中(10)办件数;口径=def_id 精确匹配该线各版本;请求的 guid 全部有键(无在途=0) */ + public Map inflightCounts(Long schId, Collection flowGuids) { + Map result = new HashMap<>(); + if (flowGuids == null || flowGuids.isEmpty()) return result; + flowGuids.forEach(g -> result.put(g, 0L)); + List defs = defRepository.findBySchIdAndFlowGuidIn(schId, flowGuids); + if (defs.isEmpty()) return result; + Map idToGuid = new HashMap<>(); + defs.forEach(d -> idToGuid.put(d.getId(), d.getFlowGuid())); + instanceRepository.countApprovingByDefIds(schId, idToGuid.keySet()).forEach(r -> { + Long defId = ((Number) r[0]).longValue(); + Long cnt = ((Number) r[1]).longValue(); + result.merge(idToGuid.get(defId), cnt, Long::sum); + }); + return result; + } + /** * 元数据原地编辑(2026-10-10 四议题·议题2,拍板 D4):已发布/停用/草稿均可只改 name/appKey * 而不升版本——结构改动仍走 save 的升版本路径,两者完全隔离(本方法不碰 diff --git a/src/main/java/com/yunhai/flowcenter/service/FlowQueryService.java b/src/main/java/com/yunhai/flowcenter/service/FlowQueryService.java index 20e2a44..cee4437 100644 --- a/src/main/java/com/yunhai/flowcenter/service/FlowQueryService.java +++ b/src/main/java/com/yunhai/flowcenter/service/FlowQueryService.java @@ -383,6 +383,9 @@ public class FlowQueryService { row.put("attempt", r.getAttempt()); row.put("status", null); row.put("time", str(r.getDecideTime())); + // 议题三②:调试弹窗「从路由日志导入」需要看失败摘要(>500 截断) + row.put("rawResponse", r.getRawResponse() == null ? "" : + (r.getRawResponse().length() > 500 ? r.getRawResponse().substring(0, 500) + "…" : r.getRawResponse())); return row; } diff --git a/src/main/resources/sql/20261012_add_flw_def_change_log.sql b/src/main/resources/sql/20261012_add_flw_def_change_log.sql new file mode 100644 index 0000000..79566e8 --- /dev/null +++ b/src/main/resources/sql/20261012_add_flw_def_change_log.sql @@ -0,0 +1,4 @@ +-- 2026-10-12 议题二:升版本改动说明(版本行即说明;独立版本日志表留 P2) +-- ddl-auto=update 会自动加列;本脚本为生产备案(生产建议停自动 DDL 后手工执行) +ALTER TABLE `flw_def` + ADD COLUMN `change_log` VARCHAR(500) NULL COMMENT '升版本改动说明(可跳过;NULL=未填写)' AFTER `name`;