This commit is contained in:
@@ -13,6 +13,8 @@ import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import com.yunhai.platform.utils.model.BasePageResult;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -37,6 +39,7 @@ public class FlowUserController {
|
||||
private final FlowInstanceService instanceService;
|
||||
private final FlowAccessGuard accessGuard;
|
||||
private final FlowDiagramService diagramService;
|
||||
private final com.yunhai.flowcenter.service.DiagramImageService imageService;
|
||||
|
||||
/** 我提交的办件 */
|
||||
@GetMapping("/my")
|
||||
@@ -155,6 +158,23 @@ public class FlowUserController {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "缺少必要参数:flowGuid 或 instanceId");
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程图图片流(CAS 会话版"CAS 验证码式嵌入",2026-09-16):流程中心自有页面 <img src>
|
||||
* 直嵌(办件详情页内嵌运行时状态图),免跳 /diagram 全屏页。可见性与 /diagram 同口径。
|
||||
* 外部系统(img 带不了会话)走 /oapi/flow/diagram/url 换 token + /open/flow/diagram/img。
|
||||
*/
|
||||
@GetMapping("/diagram.png")
|
||||
public ResponseEntity<byte[]> diagramPng(BoaUser user,
|
||||
@RequestParam(value = "flowGuid", required = false) String flowGuid,
|
||||
@RequestParam(value = "instanceId", required = false) Long instanceId,
|
||||
@RequestParam(value = "mode", required = false) String mode) {
|
||||
FlowModels.DiagramVo vo = diagram(user, flowGuid, instanceId, mode);
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.IMAGE_PNG)
|
||||
.cacheControl(org.springframework.http.CacheControl.noStore())
|
||||
.body(imageService.renderPng(vo));
|
||||
}
|
||||
|
||||
private Long requireSchId(BoaUser user) {
|
||||
if (user == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "未登录");
|
||||
|
||||
@@ -21,7 +21,12 @@ import java.util.List;
|
||||
* - GET /oapi/flow/{flowGuid}?schId= → data={flowGuid,name,version,nodeSummary}
|
||||
* - POST /oapi/flow/apply → data={instanceId,duplicated}
|
||||
* - GET /oapi/flow/instance?bizType=&bizId=&schId= → data={status,version,instanceId,nodeSummary,traceJson,…}
|
||||
* - POST /oapi/flow/instance/{instanceId}/withdraw?schId=&submitterId= → data=null(提交人复核后撤回)
|
||||
* - GET /oapi/flow/progress?instanceId=|bizType=&bizId=&schId= → data={status,steps:[…]}
|
||||
* - GET /oapi/flow/diagram/url?instanceId=|flowGuid=&mode=&schId= → data={imgUrl,expiresIn}
|
||||
* - POST /oapi/flow/callback/reg?schId= → data={secret}
|
||||
* 刻意不提供审批动作(同意/拒绝/退回/移交/催办):那是"人"的决策,必须带登录身份走 CAS 用户面,
|
||||
* 应用间签名不得代签——谁办理谁负责,审计链不能断在应用上。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/oapi/flow")
|
||||
@@ -54,6 +59,42 @@ public class OapiFlowController {
|
||||
return flowService.instanceByBiz(schId, bizType, bizId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 办件进度(结构化轨迹,SDK FlowProgress 契约):instanceId 或 bizType/bizId 定位。
|
||||
* 消费方渲染时间线(发起申请→各节点办理人行),SDK com.yunhai.platform.openapi.flow.model 同构。
|
||||
*/
|
||||
@GetMapping("/progress")
|
||||
public OapiModels.ProgressVo progress(@RequestParam(value = "instanceId", required = false) Long instanceId,
|
||||
@RequestParam(value = "bizType", required = false) String bizType,
|
||||
@RequestParam(value = "bizId", required = false) String bizId,
|
||||
@RequestParam("schId") Long schId) {
|
||||
return flowService.progress(schId, instanceId, bizType, bizId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程图换图(token 模式,"CAS 验证码式嵌入"):img 标签带不了签名,本端点在 app-sign 保护下
|
||||
* 签发短时 token,返回可直接放 {@code <img src>} 的免签路径 {@code /open/flow/diagram/img?token=}。
|
||||
* 口径:instanceId=办件运行时状态图;flowGuid=最高已发布版定义图。
|
||||
*/
|
||||
@GetMapping("/diagram/url")
|
||||
public OapiModels.DiagramUrlVo diagramUrl(@RequestParam(value = "instanceId", required = false) Long instanceId,
|
||||
@RequestParam(value = "flowGuid", required = false) String flowGuid,
|
||||
@RequestParam(value = "mode", required = false) String mode,
|
||||
@RequestParam("schId") Long schId) {
|
||||
return flowService.diagramUrl(schId, instanceId, flowGuid, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回(提交人本人;仅尚无任务被办理时)。submitterId 由业务应用按其办件归属传入,
|
||||
* 本端与办件提交人复核——应用签名不替代"谁在撤"的身份证明。
|
||||
*/
|
||||
@PostMapping("/instance/{instanceId}/withdraw")
|
||||
public void withdraw(@RequestParam("schId") Long schId,
|
||||
@RequestParam("submitterId") Integer submitterId,
|
||||
@PathVariable("instanceId") Long instanceId) {
|
||||
flowService.withdraw(schId, instanceId, submitterId);
|
||||
}
|
||||
|
||||
@PostMapping("/callback/reg")
|
||||
public OapiModels.CallbackRegResultVo registerCallback(
|
||||
@RequestParam("schId") Long schId,
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.yunhai.flowcenter.controller.open;
|
||||
|
||||
import com.yunhai.flowcenter.entity.FlwInstance;
|
||||
import com.yunhai.flowcenter.model.FlowModels;
|
||||
import com.yunhai.flowcenter.repository.FlwDefRepository;
|
||||
import com.yunhai.flowcenter.repository.FlwInstanceRepository;
|
||||
import com.yunhai.flowcenter.service.DiagramImageService;
|
||||
import com.yunhai.flowcenter.service.DiagramTokenService;
|
||||
import com.yunhai.flowcenter.service.FlowDiagramService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 免签图片流端点(/open/flow/**,用户拍板 2026-09-16,"CAS 验证码式"嵌入)。
|
||||
* <p>
|
||||
* 故意不落 /api/**(CAS 会话)也不落 /oapi/**(app-sign):<img src> 两者都带不了鉴权头;
|
||||
* 免签资格由 10 分钟短时 token 承担(DiagramTokenService,token 由 app-sign 的
|
||||
* GET /oapi/flow/diagram/url 签发)。token 分发点之外,本端点不接受任何业务参数直接定位——
|
||||
* 免签面收窄到"只认 token",定位与可见性全在签发侧(OapiFlowService.diagramUrl)完成。
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/open/flow")
|
||||
@RequiredArgsConstructor
|
||||
public class OpenDiagramImageController {
|
||||
|
||||
private final DiagramTokenService tokenService;
|
||||
private final DiagramImageService imageService;
|
||||
private final FlwInstanceRepository instanceRepository;
|
||||
private final FlwDefRepository defRepository;
|
||||
private final FlowDiagramService diagramService;
|
||||
|
||||
@GetMapping("/diagram/img")
|
||||
public ResponseEntity<byte[]> diagramImg(@RequestParam("token") String token) {
|
||||
DiagramTokenService.TokenEntry entry = tokenService.resolve(token);
|
||||
if (entry == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.body("流程图已过期,请刷新页面重新获取".getBytes());
|
||||
}
|
||||
// 办件口径:节点带运行时状态(token 已收 schId,出图前再二次比对防漂移)
|
||||
if (entry.getInstanceId() != null) {
|
||||
FlwInstance instance = instanceRepository.findById(entry.getInstanceId()).orElse(null);
|
||||
if (instance == null || !entry.getSchId().equals(instance.getSchId())) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.body("办件不存在".getBytes());
|
||||
}
|
||||
return png(diagramService.byInstance(instance, entry.getMode()));
|
||||
}
|
||||
// 定义口径(flowGuid 预览)
|
||||
return defRepository.findById(entry.getDefId())
|
||||
.map(def -> entry.getSchId().equals(def.getSchId())
|
||||
? png(diagramService.build(def, null, entry.getMode()))
|
||||
: notFound("流程不存在"))
|
||||
.orElseGet(() -> notFound("流程不存在"));
|
||||
}
|
||||
|
||||
private ResponseEntity<byte[]> png(FlowModels.DiagramVo vo) {
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.IMAGE_PNG)
|
||||
.cacheControl(org.springframework.http.CacheControl.noStore())
|
||||
.body(imageService.renderPng(vo));
|
||||
}
|
||||
|
||||
private ResponseEntity<byte[]> notFound(String msg) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.body(msg.getBytes());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user