Compare commits
5
Commits
09eb27c6cf
...
5efe9c09fd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5efe9c09fd | ||
|
|
e6e91157be | ||
|
|
0721cf3b7f | ||
|
|
867809fe37 | ||
|
|
a103d661fc |
@@ -22,6 +22,8 @@ import java.util.Map;
|
|||||||
* <li>POST Flow/Binding/Save:保存/解除应用级绑定(仅本校管理员);</li>
|
* <li>POST Flow/Binding/Save:保存/解除应用级绑定(仅本校管理员);</li>
|
||||||
* <li>POST Flow/TrySubmit:提交/重提审核(幂等,bizId=notice.id;apply 失败保持待提交可重推);</li>
|
* <li>POST Flow/TrySubmit:提交/重提审核(幂等,bizId=notice.id;apply 失败保持待提交可重推);</li>
|
||||||
* <li>GET Flow/Trace:审批进度(后端 getInstanceByBiz 组装,前端不直调 oapi——放行判定必须收在后端)。</li>
|
* <li>GET Flow/Trace:审批进度(后端 getInstanceByBiz 组装,前端不直调 oapi——放行判定必须收在后端)。</li>
|
||||||
|
* <li>GET Flow/Embed:办件进度嵌入页地址(Drawer iframe 直嵌,可见性与 Trace 同口径)。</li>
|
||||||
|
* <li>GET Flow/DiagramDef:流程定义示意图(绑定页/发通知页 Drawer,登录即可读——与 Binding 同口径)。</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@@ -30,6 +32,8 @@ import java.util.Map;
|
|||||||
public class NoticeFlowController {
|
public class NoticeFlowController {
|
||||||
|
|
||||||
private final NoticeFlowService noticeFlowService;
|
private final NoticeFlowService noticeFlowService;
|
||||||
|
private final com.yunhai.notice.service.flow.NoticeFlowEmbedService noticeFlowEmbedService;
|
||||||
|
private final com.yunhai.notice.service.flow.FlowClient flowClient;
|
||||||
|
|
||||||
/** 审核流程下拉选项(流程中心未启用时返回空列表,前端隐藏选择器) */
|
/** 审核流程下拉选项(流程中心未启用时返回空列表,前端隐藏选择器) */
|
||||||
@GetMapping("Options")
|
@GetMapping("Options")
|
||||||
@@ -81,6 +85,30 @@ public class NoticeFlowController {
|
|||||||
return noticeFlowService.diagramImage(serid, user);
|
return noticeFlowService.diagramImage(serid, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程定义示意图(PNG 流,绑定页/发通知页 Drawer 同源直嵌 img)。def 口径无办件,
|
||||||
|
* 不适用 NoticeFlowGuard 办件守卫——与绑定读取(Binding,登录即可读)同口径:CAS 登录即可,
|
||||||
|
* schId 从登录用户推导,本校限定由 flow-center 按 schId+flowGuid 收敛;
|
||||||
|
* 绑定已解除/无已发布版时对端报业务错(JSON 信封),前端 img onerror 转提示,不留 500。
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "DiagramDef", produces = org.springframework.http.MediaType.IMAGE_PNG_VALUE)
|
||||||
|
public byte[] diagramDef(@RequestParam("flowGuid") String flowGuid, BoaUser user) {
|
||||||
|
if (flowGuid == null || flowGuid.trim().isEmpty()) {
|
||||||
|
throw new com.yunhai.platform.apistd.BizException(
|
||||||
|
com.yunhai.platform.utils.exception.ErrorCode.PARAM_ERROR, "缺少流程标识");
|
||||||
|
}
|
||||||
|
return flowClient.diagramImageByFlowGuid(currentSchId(user), flowGuid.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办件进度嵌入页地址(详情页 Drawer 内 iframe 直嵌 flow-center 统一进度页)。
|
||||||
|
* 可见性与 Trace/Diagram 同口径;pageUrl 含短时 token,现取现发不落前端缓存。
|
||||||
|
*/
|
||||||
|
@GetMapping("Embed")
|
||||||
|
public Map<String, String> embed(@RequestParam("serid") Integer serid, BoaUser user) {
|
||||||
|
return noticeFlowEmbedService.embedUrl(serid, user);
|
||||||
|
}
|
||||||
|
|
||||||
private Integer currentSchId(BoaUser user) {
|
private Integer currentSchId(BoaUser user) {
|
||||||
if (user == null || user.getCurrentRole() == null) {
|
if (user == null || user.getCurrentRole() == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -197,6 +197,37 @@ public class FlowCenterClient implements FlowClient {
|
|||||||
return token.isEmpty() ? null : token;
|
return token.isEmpty() ? null : token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] diagramImageByFlowGuid(Integer schId, String flowGuid) {
|
||||||
|
requireEnabled();
|
||||||
|
String imgUrl;
|
||||||
|
if (directoryResolved) {
|
||||||
|
FlowModels.DiagramUrlVo dto = com.yunhai.platform.openapi.flow.YschFlowOpenApi.diagramUrl(
|
||||||
|
null, flowGuid, null, schId, FlowModels.DiagramUrlVo.class);
|
||||||
|
imgUrl = dto == null ? null : dto.getImgUrl();
|
||||||
|
} else {
|
||||||
|
Map<String, String> query = new HashMap<>();
|
||||||
|
query.put("flowGuid", flowGuid);
|
||||||
|
query.put("schId", String.valueOf(schId));
|
||||||
|
FlowModels.DiagramUrlVo dto =
|
||||||
|
openCall.get(target(), "/oapi/flow/diagram/url", query, FlowModels.DiagramUrlVo.class);
|
||||||
|
imgUrl = dto == null ? null : dto.getImgUrl();
|
||||||
|
}
|
||||||
|
String token = tokenOf(imgUrl);
|
||||||
|
if (token == null) {
|
||||||
|
throw new BizException(ErrorCode.PARAM_ERROR, "流程中心未返回有效的示意图地址");
|
||||||
|
}
|
||||||
|
Map<String, String> imgQuery = new HashMap<>();
|
||||||
|
imgQuery.put("token", token);
|
||||||
|
byte[] bytes = directoryResolved
|
||||||
|
? com.yunhai.platform.openapi.flow.YschFlowOpenApi.raw().download(DIAGRAM_IMG_PATH, imgQuery)
|
||||||
|
: openCall.download(target(), DIAGRAM_IMG_PATH, imgQuery);
|
||||||
|
if (bytes == null || bytes.length == 0) {
|
||||||
|
throw new BizException(ErrorCode.PARAM_ERROR, "流程示意图为空(流程可能未发布节点)");
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
private TargetSpec target() {
|
private TargetSpec target() {
|
||||||
// base-path 空:本地/容器裸地址直连(两级模型 §2.2 对齐不变式的现行约定)
|
// base-path 空:本地/容器裸地址直连(两级模型 §2.2 对齐不变式的现行约定)
|
||||||
return TargetSpec.of(properties.getBaseUrl(), "");
|
return TargetSpec.of(properties.getBaseUrl(), "");
|
||||||
|
|||||||
@@ -33,4 +33,11 @@ public interface FlowClient {
|
|||||||
|
|
||||||
/** 流程示意图字节(token 换图两步都在本方法内,浏览器只拿同源 PNG,token 不落前端) */
|
/** 流程示意图字节(token 换图两步都在本方法内,浏览器只拿同源 PNG,token 不落前端) */
|
||||||
byte[] diagramImage(Integer schId, Long instanceId);
|
byte[] diagramImage(Integer schId, Long instanceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程定义示意图字节(def 口径,绑定页/发通知页 Drawer):按 flowGuid 取最高已发布版出图。
|
||||||
|
* 与办件图同一免签 token 通道;本校限定由 flow-center 按 schId+flowGuid 收敛(绑定已解除/
|
||||||
|
* 无已发布版 → 业务异常文案,不留 500)。
|
||||||
|
*/
|
||||||
|
byte[] diagramImageByFlowGuid(Integer schId, String flowGuid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.yunhai.notice.service.flow;
|
||||||
|
|
||||||
|
import com.yunhai.notice.entity.Notice;
|
||||||
|
import com.yunhai.notice.repository.NoticeRepository;
|
||||||
|
import com.yunhai.platform.apistd.BizException;
|
||||||
|
import com.yunhai.platform.openapi.flow.YschFlowOpenApi;
|
||||||
|
import com.yunhai.platform.openapi.flow.model.FlowEmbedUrl;
|
||||||
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||||
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办件进度嵌入页换址(2026-10-03 嵌入页方案):子应用 Drawer 内 iframe 直嵌 flow-center
|
||||||
|
* 统一进度页,零样式复制。与 Diagram 同口径的用户级守卫(未发布仅提交人/管理员/办理人
|
||||||
|
* /被抄送人可见);oapi 层只认 schId——"谁能看"必须落在本端点,应用签名不替代身份。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class NoticeFlowEmbedService {
|
||||||
|
|
||||||
|
private final NoticeRepository noticeRepository;
|
||||||
|
private final NoticeFlowGuard noticeFlowGuard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取嵌入页地址(pageUrl 含 10 分钟短时 token):现取现发、不缓存、不落库、
|
||||||
|
* 不打进应用日志(token 泄露窗口即有效期,纪律见方案 §6.1/§7)。
|
||||||
|
*/
|
||||||
|
public Map<String, String> embedUrl(Integer noticeId, BoaUser user) {
|
||||||
|
Notice notice = noticeRepository.findById(noticeId)
|
||||||
|
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "通知不存在: " + noticeId));
|
||||||
|
if (notice.getStatus() == null || notice.getStatus() != 1) {
|
||||||
|
noticeFlowGuard.requireUnpublishedVisible(notice, user);
|
||||||
|
}
|
||||||
|
if (notice.getFlowInstanceId() == null || notice.getSchId() == null) {
|
||||||
|
throw new BizException(ErrorCode.PARAM_ERROR, "该通知尚未进入流程");
|
||||||
|
}
|
||||||
|
FlowEmbedUrl embed = YschFlowOpenApi.embedUrl(
|
||||||
|
null, FlowCenterClient.BIZ_TYPE, String.valueOf(notice.getId()),
|
||||||
|
notice.getSchId(), FlowEmbedUrl.class);
|
||||||
|
if (embed == null || !StringUtils.hasText(embed.getPageUrl())) {
|
||||||
|
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "嵌入页地址获取失败,请稍后重试");
|
||||||
|
}
|
||||||
|
return Collections.singletonMap("pageUrl", embed.getPageUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user