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 验证码式"嵌入)。 *

* 故意不落 /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 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 png(FlowModels.DiagramVo vo) { return ResponseEntity.ok() .contentType(MediaType.IMAGE_PNG) .cacheControl(org.springframework.http.CacheControl.noStore()) .body(imageService.renderPng(vo)); } private ResponseEntity notFound(String msg) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .contentType(MediaType.TEXT_PLAIN) .body(msg.getBytes()); } }