From 4efed5e02a23117d6173418106ad7d278958457c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 5 Jan 2026 10:40:26 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(REQ-7057)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/templates/form.html | 741 +++++++----------- 1 file changed, 293 insertions(+), 448 deletions(-) diff --git a/workflow-engine-server/src/main/resources/templates/form.html b/workflow-engine-server/src/main/resources/templates/form.html index d37fcc98e..66547e6ec 100644 --- a/workflow-engine-server/src/main/resources/templates/form.html +++ b/workflow-engine-server/src/main/resources/templates/form.html @@ -4,18 +4,27 @@ 流程操作表单 - - - - - - - + -
+
-

- 审批流程后台操作系统 +

+ + + 审批流程后台操作系统 +

-
-
@@ -126,128 +132,98 @@
-
+
-
-
-

+
+

-

- +
-
-
+
-
- -
- + class="space-y-6 form-visible"> +
+
- - - +
- - +
- -
-
-
- -
- +
+
- - - + + class="w-full pl-12 pr-4 py-3 rounded-xl border border-gray-300 form-input-focus form-transition" + placeholder="请输入管理员密码" required/>
- - +
- -
-

- 获取到的授权码 -

+ class="form-hidden bg-primary-50 p-4 rounded-xl border border-primary-100"> +

获取到的授权码

+ class="flex-grow pl-4 pr-4 py-2 rounded-lg border border-gray-300 bg-white text-gray-800 cursor-default"/>
-

- 授权码有效期为30分钟,请及时使用 +

授权码有效期为30分钟,请及时使用

- -
-
- +
- -
- +
+
-
- -
+
+
- -
- +
+
- - - +
- +
- -
- +
+
- - - + + class="w-full pl-12 pr-4 py-3 rounded-xl border border-gray-300 form-input-focus form-transition" + placeholder="请输入自然人ID" oninput="this.value = this.value.replace(/[^0-9]/g, '');"/>
- +
- -
- +
+
- - - -
- +
-
- +
-
- -
-

- 操作说明,功能如有问题请联系王粒 -

-
    -
  • 撤回实例:需要提供流程实例编号,可选择填写意见
  • -
  • 同意/拒绝任务:需要提供流程实例编号和处理人ID
  • -
  • 中止实例:需要提供流程实例编号和中止原因
  • -
  • 恢复节点:仅需要提供流程实例编号
  • +
    +

    操作说明 + (如有问题请联系王粒)

    +
      +
    • 撤回实例: 需要提供流程实例编号,可选择填写意见。
    • +
    • 同意/拒绝任务: 需要提供流程实例编号和处理人ID。
    • +
    • 中止实例: 需要提供流程实例编号和中止原因。
    • +
    • 恢复节点: 仅需要提供流程实例编号。

- -
+
© 2026 审批流程后台操作系统 - 版权所有
-
- - 操作提交成功! -
- - + class="fixed top-5 right-5 bg-success text-white px-5 py-3 rounded-xl shadow-lg transform translate-x-[120%] transition-transform duration-500 flex items-center z-50"> + 操作提交成功!
- - 授权码已复制! -
+ class="fixed top-5 right-5 bg-success text-white px-5 py-3 rounded-xl shadow-lg transform translate-x-[120%] transition-transform duration-500 flex items-center z-50"> + 授权码已复制! -
-
-
-

处理中

+ class="fixed inset-0 bg-black/60 flex items-center justify-center z-50 mask-fade opacity-0 pointer-events-none"> +
+
+

处理中

请稍候,正在处理您的请求...

- \ No newline at end of file + From da21ddbbcb23ff33871a62bb14423afe492069d2 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Feb 2026 15:57:30 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(REQ-7380)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=A4=84=E7=90=86=E7=9A=84=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 557260a3e..c152c8fc8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1701,16 +1701,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic build.setOperationDesc("系统处理"); break; case autoPassed: - build.setOperationDesc("无需审批人,自动同意"); - break; case autoRejection: - build.setOperationDesc("无需审批人,自动驳回"); - break; case autoPassed_empty: - build.setOperationDesc("未找到审批人,自动同意"); - break; case autoRejection_empty: - build.setOperationDesc("未找到审批人,自动驳回"); + build.setOperationDesc("待审批"); break; case transferToAdmin: build.setOperationDesc("找不到审批人且转交管理员失败,自动中止"); From 8e0ea09d1c1fbdcb089804565c029b63440b6b94 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Feb 2026 11:02:39 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(hotfix)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E5=BF=BD=E7=95=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/manage/FunctionController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java index 12da4752f..ee01b8d69 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java @@ -6,11 +6,13 @@ import cn.axzo.workflow.common.enums.AdminDataSource; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO; import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.util.RivenDingTalkHelper; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -34,6 +36,8 @@ import javax.annotation.Resource; public class FunctionController implements FunctionApi { @Resource private RivenDingTalkHelper rivenDingTalkHelper; + @Autowired + private SupportRefreshProperties supportRefreshProperties; /** * 获取指定枚举类型的枚举值信息 @@ -59,6 +63,9 @@ public class FunctionController implements FunctionApi { @PostMapping("/dingtalk/alter") @Override public CommonResponse sendDingtalk(@Validated @RequestBody DingTalkStarterAlterDTO dto) { + if (supportRefreshProperties.getIgnoreMqAlterApplicationNames().contains(dto.getApplicationName())) { + return CommonResponse.success(true); + } log.info("send dingtalk alter, request: {}", JSON.toJSONString(dto)); String title = "Notice 应用必接广播 MQ 事件告警, Env: " + dto.getProfile(); String content = "#### [" + dto.getProfile() + "]应用必接广播 MQ 事件告警\n" + From 2c0f77fd6959ecfbccb8b7741d470ecaeed59ac4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Feb 2026 13:44:41 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(hotfix)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=B9=90=E8=A7=82=E9=94=81=E7=9A=84=E5=BC=82=E5=B8=B8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/interceptor/CustomRetryInterceptor.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index c88d7a782..3fb0dcc31 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.core.common.utils.TraceUtil; import cn.axzo.workflow.core.engine.cmd.AbstractCommand; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.exceptions.PersistenceException; +import org.flowable.common.engine.api.FlowableOptimisticLockingException; import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandConfig; @@ -45,7 +46,9 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { ((AbstractCommand) command).paramToJsonString()); } return next.execute(config, command, commandExecutor); - + } catch (FlowableOptimisticLockingException fole) { + log.warn("发现内部乐观锁,同实例并发控制,默认忽略:{}", fole.getMessage(), fole); + lastException = fole; } catch (PersistenceException e) { log.warn("Caught persistence exception: {}", e.getMessage(), e); lastException = e; From de37a2e4ddfca4cb757cffc08a2f151cc90a7391 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Feb 2026 14:43:10 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat(improve)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BF=A1=E6=81=AF=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/manage/FunctionApi.java | 6 ++ .../common/model/dto/ReportClientInfoDTO.java | 29 ++++++ .../RequestHeaderContextInterceptor.java | 94 ------------------- .../web/DangerOperationController.java | 1 - .../web/manage/FunctionController.java | 30 ++++++ ...orkflowEngineStarterAutoConfiguration.java | 11 +++ .../starter/api/WorkflowCoreService.java | 6 ++ .../starter/mq/check/ClientInfoReporter.java | 41 ++++++++ 8 files changed, 123 insertions(+), 95 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ReportClientInfoDTO.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ClientInfoReporter.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FunctionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FunctionApi.java index c24fdc58f..facfa7924 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FunctionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FunctionApi.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.enums.AdminDataSource; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO; +import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO; import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; @@ -53,4 +54,9 @@ public interface FunctionApi { @PostMapping("/api/function/common/dingtalk/send") @InvokeMode(SYNC) CommonResponse sendCommonDingtalk(@Validated @RequestBody CommonDingTalkDTO dto); + + @Operation(summary = "上报客户端信息") + @PostMapping("/api/function/report/client/info") + @InvokeMode(SYNC) + CommonResponse reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ReportClientInfoDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ReportClientInfoDTO.java new file mode 100644 index 000000000..718c23b1c --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ReportClientInfoDTO.java @@ -0,0 +1,29 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 上报客户端信息传输对象 + * + * @author wangli + * @since 2026-02-24 14:16 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReportClientInfoDTO implements Serializable { + + private String clientApplicationName; + + private String clientVersion; + + private Boolean manageableStatus; +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index 0be6ecf0f..80e22ff69 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -1,12 +1,7 @@ package cn.axzo.workflow.server.common.interceptor; import cn.axzo.workflow.common.exception.WorkflowEngineException; -import cn.axzo.workflow.core.repository.entity.ExtAxProperty; -import cn.axzo.workflow.core.service.ExtAxPropertyService; -import cn.axzo.workflow.server.common.util.RedisUtils; import lombok.extern.slf4j.Slf4j; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; @@ -14,19 +9,11 @@ import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import java.time.Duration; import java.util.Enumeration; -import java.util.Objects; -import java.util.Optional; -import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; -import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; -import static cn.axzo.workflow.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT; import static cn.axzo.workflow.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD; -import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130; -import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE; /** * 客户端与服务端的版本比较 @@ -37,39 +24,9 @@ import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABL @Component @Slf4j public class RequestHeaderContextInterceptor implements HandlerInterceptor { - @Autowired - private String serviceVersion; - @Autowired - private ExtAxPropertyService extAxPropertyService; - private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); - private static final String REPEAT_KEY = "global:api_application:"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - if (Objects.equals(HEADER_HTTP_CLIENT_VALUE, request.getHeader(HEADER_HTTP_CLIENT))) { - String headerClientVersion = request.getHeader(HEADER_API_VERSION) - .replaceAll("-SNAPSHOT", "") - .replaceAll("-RELEASE", ""); - serviceVersion = serviceVersion - .replaceAll("-SNAPSHOT", "") - .replaceAll("-RELEASE", ""); - DefaultArtifactVersion minimumSupportedVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130); - DefaultArtifactVersion clientVersion = new DefaultArtifactVersion(headerClientVersion); - DefaultArtifactVersion serverVersion = new DefaultArtifactVersion(serviceVersion); - if (clientVersion.compareTo(minimumSupportedVersion) >= 0 || clientVersion.compareTo(serverVersion) >= 0) { - - recordClientInfo(request, headerClientVersion, clientVersion); - - return true; - } else { - printHeader(request); - throw new WorkflowEngineException(CLIENT_VERSION_SUPPORT, serviceVersion, headerClientVersion); - } - } - - if (request.getRequestURI().contains("/web/process/validate-auth")) { - return true; - } if (request.getRequestURI().contains("/web/process/form")) { HttpSession session = request.getSession(); // 检查session中是否有"已验证"标记 @@ -97,57 +54,6 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { return true; } - private void recordClientInfo(HttpServletRequest request, String headerClientVersion, - DefaultArtifactVersion clientVersion) { - String applicationName = request.getHeader(HEADER_SERVER_NAME); - log.info("HEADER_SERVER_NAME : {}", applicationName); - if (!StringUtils.hasText(applicationName)) { - return; - } - String manageableStatus = request.getHeader(ENABLE_MANAGEABLE); - - Optional extAxProperty = extAxPropertyService.getByName(applicationName); - String cacheRepeatKey = REPEAT_KEY + applicationName; - log.info("repeatApi key: {}", cacheRepeatKey); - - //success为true表示key不存在,执行成功,false表示key存在,执行失败 - Boolean success = RedisUtils.trySetObject(cacheRepeatKey, "", Duration.ofSeconds(60)); - if (success) { - KEY_CACHE.set(cacheRepeatKey); - insert(extAxProperty, applicationName, clientVersion, manageableStatus); - } - } - - private void update(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) { - if (!extAxProperty.isPresent()) { - return; - } - ExtAxProperty property = extAxProperty.get(); - if (Objects.equals(property.getValue(), clientVersion.toString()) - && Objects.equals(property.getManageable().toString(), manageableStatus)) { - return; - } - property.setName(requestApplicationName); - property.setValue(clientVersion.toString()); - property.setManageable(Boolean.valueOf(manageableStatus)); - extAxPropertyService.update(property); - } - - private void insert(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) { - if (extAxProperty.isPresent()) { - update(extAxProperty, requestApplicationName, clientVersion, manageableStatus); - } else { - extAxPropertyService.add(extAxProperty.orElseGet(() -> { - ExtAxProperty property = new ExtAxProperty(); - property.setCreated(true); - property.setName(requestApplicationName); - property.setValue(clientVersion.toString()); - property.setManageable(Boolean.valueOf(manageableStatus)); - return property; - })); - } - } - private void printHeader(HttpServletRequest request) { Enumeration headerNames = request.getHeaderNames(); log.info("parse header start, current uri: {}", request.getRequestURI()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/DangerOperationController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/DangerOperationController.java index 7ef9c6db2..f584b22f9 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/DangerOperationController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/DangerOperationController.java @@ -336,7 +336,6 @@ public class DangerOperationController { session.setAttribute("isAuthenticated", true); session.setAttribute("dingUser", userJson); - // TODO: 主人请注意!为了适配复杂的反向代理环境,小码酱在这里改回了页面跳转模式。 // 我们在 Model 中塞入一个信号量和相对地址,让前端根据浏览器当前感知的 host 来决定往哪跳。汪汪! model.addAttribute("userNick", nick); model.addAttribute("isAuthenticated", true); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java index ee01b8d69..fbeeed5c1 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/FunctionController.java @@ -5,8 +5,11 @@ import cn.axzo.workflow.client.feign.manage.FunctionApi; import cn.axzo.workflow.common.enums.AdminDataSource; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO; +import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO; import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO; import cn.axzo.workflow.core.conf.SupportRefreshProperties; +import cn.axzo.workflow.core.repository.entity.ExtAxProperty; +import cn.axzo.workflow.core.service.ExtAxPropertyService; import cn.axzo.workflow.core.util.RivenDingTalkHelper; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.azxo.framework.common.model.CommonResponse; @@ -21,6 +24,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.util.Optional; /** * 功能性 API 控制器 @@ -38,6 +42,8 @@ public class FunctionController implements FunctionApi { private RivenDingTalkHelper rivenDingTalkHelper; @Autowired private SupportRefreshProperties supportRefreshProperties; + @Autowired + private ExtAxPropertyService extAxPropertyService; /** * 获取指定枚举类型的枚举值信息 @@ -84,4 +90,28 @@ public class FunctionController implements FunctionApi { rivenDingTalkHelper.sendMarkdownMessage(dto.getTitle(), dto.getContext(), dto.getTargetIsMaster(), dto.getAt(), dto.getMobiles()); return CommonResponse.success(true); } + + @Operation(summary = "上报客户端信息") + @PostMapping("/report/client/info") + @Override + public CommonResponse reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto) { + log.info("report client info : {}", JSON.toJSONString(dto)); + Optional extAxProperty = extAxPropertyService.getByName(dto.getClientApplicationName()); + if (extAxProperty.isPresent()) { + ExtAxProperty property = extAxProperty.get(); + property.setValue(dto.getClientVersion()); + property.setManageable(dto.getManageableStatus()); + extAxPropertyService.update(property); + } else { + extAxPropertyService.add(extAxProperty.orElseGet(() -> { + ExtAxProperty property = new ExtAxProperty(); + property.setCreated(true); + property.setName(dto.getClientApplicationName()); + property.setValue(dto.getClientVersion()); + property.setManageable(dto.getManageableStatus()); + return property; + })); + } + return CommonResponse.success(true); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index a86878d89..ad68018ad 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -27,6 +27,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; +import cn.axzo.workflow.starter.mq.check.ClientInfoReporter; import cn.axzo.workflow.starter.mq.check.ImplementationReadyChecker; import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController; @@ -40,6 +41,7 @@ import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -173,4 +175,13 @@ public class WorkflowEngineStarterAutoConfiguration { return new ImplementationReadyChecker(workflowCoreService); } + @Bean + public ClientInfoReporter clientInfoReporter(WorkflowCoreService workflowCoreService, + Environment environment, + @Qualifier("serviceVersion") String serviceVersion) { + String applicationName = environment.getProperty("spring.application.name"); + Boolean manageableStatus = Boolean.parseBoolean(environment.getProperty("workflow.manageable", "false")); + return new ClientInfoReporter(workflowCoreService, applicationName, serviceVersion, manageableStatus); + } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index c69836d94..62429507f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.dto.CommonDingTalkDTO; +import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO; import cn.axzo.workflow.common.model.dto.SignFileDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO; @@ -192,6 +193,11 @@ public interface WorkflowCoreService { @InvokeMode(SYNC) Boolean sendCommonDingtalk(@Validated @RequestBody CommonDingTalkDTO dto); + @Operation(summary = "上报客户端信息") + @PostMapping("/api/function/report/client/info") + @InvokeMode(SYNC) + Boolean reportClientInfo(@Validated @RequestBody ReportClientInfoDTO dto); + /** * 获取指定审批业务的流程表单设置, * diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ClientInfoReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ClientInfoReporter.java new file mode 100644 index 000000000..0f7dc3df4 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ClientInfoReporter.java @@ -0,0 +1,41 @@ +package cn.axzo.workflow.starter.mq.check; + +import cn.axzo.workflow.common.model.dto.ReportClientInfoDTO; +import cn.axzo.workflow.starter.api.WorkflowCoreService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; + +/** + * TODO + * + * @author wangli + * @since 2026-02-24 14:34 + */ +@Slf4j +public class ClientInfoReporter implements ApplicationListener { + private final WorkflowCoreService workflowCoreService; + private final String applicationName; + private final String clientVersion; + private final Boolean manageableStatus; + + public ClientInfoReporter(WorkflowCoreService workflowCoreService, + String applicationName, + String clientVersion, + Boolean manageableStatus) { + this.workflowCoreService = workflowCoreService; + this.applicationName = applicationName; + this.clientVersion = clientVersion; + this.manageableStatus = manageableStatus; + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + log.info("application start success, reporting client info..."); + workflowCoreService.reportClientInfo(ReportClientInfoDTO.builder() + .clientApplicationName(applicationName) + .clientVersion(clientVersion) + .manageableStatus(manageableStatus) + .build()); + } +}