feat: 一键拉取教师组作为科室(办理人映射批量导入)+ 回调签名/编辑器存量
build / build-push (push) Successful in 46s

- FlowMapAdminService:previewGroupDepts/importGroups(学校子树 type=7 容器→子组为科室,
  deptKey=UserBase 组 id,成员=组内用户;已存在启用中映射跳过;语义与 svc-hall buildDeptTree 对齐)
- FlowAdminController:GET /map/groupPreview + POST /map/importGroups
- flow-center.map.dept-group-type(默认 7)
- 含 2026-09-13/14 存量:CallbackAppSigner 回调签名、流程编辑器 sql、示意图(F1-F4)
This commit is contained in:
chenxing
2026-09-16 01:20:59 +08:00
parent f116786846
commit 55e3a3f800
10 changed files with 475 additions and 20 deletions
@@ -1,6 +1,7 @@
package com.yunhai.flowcenter.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhai.flowcenter.callback.CallbackAppSigner;
import com.yunhai.flowcenter.entity.FlwCallbackReg;
import com.yunhai.flowcenter.entity.FlwDef;
import com.yunhai.flowcenter.entity.FlwInstance;
@@ -23,7 +24,6 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
@@ -63,6 +63,10 @@ public class OapiFlowService {
private final ObjectMapper objectMapper;
private final OpenApiUserClient userClient;
/** 本应用身份(回调探活补应用签名头;未装配时裸发,接收方 /oapi/* 会 401) */
private final org.springframework.beans.factory.ObjectProvider<com.yunhai.platform.appauth.LocalAppIdentityProvider>
appIdentityProvider;
/** 已发布流程列表(每条流程线取最高已发布版本) */
public List<OapiModels.FlowSummaryVo> listFlows(Long schId) {
List<OapiModels.FlowSummaryVo> out = new ArrayList<>();
@@ -134,10 +138,11 @@ public class OapiFlowService {
}
reg.setCallbackUrl(body.getCallbackUrl());
reg.setEventTypes(body.getEventTypes());
reg.setBasePath(body.getBasePath());
reg.setSecret(secret);
reg.setStatus(0);
regRepository.saveAndFlush(reg);
probeReachable(body.getCallbackUrl(), body.getFlowGuid(), secret);
probeReachable(body.getCallbackUrl(), body.getBasePath(), body.getFlowGuid(), secret);
OapiModels.CallbackRegResultVo vo = new OapiModels.CallbackRegResultVo();
vo.setSecret(secret);
return vo;
@@ -147,10 +152,14 @@ public class OapiFlowService {
* 可达性探活(概览 §十:拦住配错域名的低级故障)。只做连接级判定:
* 连不上(未知主机/拒绝/超时)视为不可达并拒绝注册;任何 HTTP 状态码(含 401/404)
* 都算可达——接收方验签过滤器在拿到 secret 前必然拒绝 ping,鉴权语义不在此验证。
* <p>
* 但探活请求必须带应用签名:回调端点挂在接收方 /oapi/* 下(强制应用验签)时,
* 裸 ping 会被 401 拦下,而 RestTemplate 对 4xx 抛异常 → 误判"不可达"拒绝注册。
*/
private void probeReachable(String callbackUrl, String flowGuid, String secret) {
private void probeReachable(String callbackUrl, String basePath, String flowGuid, String secret) {
try {
RestTemplate template = rawTemplate();
RestTemplate template = CallbackAppSigner.signedTemplate(
appIdentityProvider.getIfAvailable(), basePath, 3000, 3000);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("X-Flw-EventId", uuid32());
@@ -170,13 +179,6 @@ public class OapiFlowService {
}
}
private RestTemplate rawTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(3000);
factory.setReadTimeout(3000);
return new RestTemplate(factory);
}
private static Throwable rootCause(Throwable e) {
Throwable cur = e;
while (cur.getCause() != null && cur.getCause() != cur) {