Files
flow-center-service/src/main/java/com/yunhai/flowcenter/controller/oapi/OapiFlowController.java
T

210 lines
12 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yunhai.flowcenter.controller.oapi;
import com.yunhai.flowcenter.model.OapiModels;
import com.yunhai.flowcenter.service.FlowRouterAdminService;
import com.yunhai.flowcenter.service.OapiFlowService;
import com.yunhai.platform.utils.model.BasePageResult;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 托管接入件(/oapi/flow/**,appKey 签名强制,V2.0 Part D #5 前置 M1)。
* 出入参逐字对齐 svc-hall FlowCenterClient(《流程中心M1开工说明.md》§5 契约锚点):
* - GET /oapi/flow/list?schId= → data=[{flowGuid,name,version,nodeSummary}]
* - 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}
* - GET /oapi/flow/embed/url?instanceId=|bizType=&bizId=&mode=&schId= → data={pageUrl,expiresIn}
* - POST /oapi/flow/callback/reg?schId= → data={secret}
* - POST /oapi/flow/router/reg → data=null(判断服务自注册,归属=appKey)
* 应用内审批(2026-09 第三步,原"刻意不提供审批动作"立场由该方案修订:登录身份由调用方
* 应用按其 CAS 会话保证并以 operatorId 传入,本端按任务办理人逐字复核,审计链不断):
* - GET /oapi/flow/tasks/todo?schId=&assigneeId=&bizType=&page=&size= → data=分页待办
* - GET /oapi/flow/tasks/by-biz?schId=&bizType=&bizId=&operatorId= → data=当前人在该单据的待办(0/1/N)
* - GET /oapi/flow/instances?schId=&bizType=&status=&page=&size= → data=分页办件
* - POST /oapi/flow/task/{taskId}/approve?schId=&operatorId=&operatorName=(body: opinion/edgeName)
* - POST /oapi/flow/task/{taskId}/reject?schId=&operatorId=&operatorName=(body: opinion 必填)
*/
@RestController
@RequestMapping("/oapi/flow")
@RequiredArgsConstructor
public class OapiFlowController {
private final OapiFlowService flowService;
private final FlowRouterAdminService routerAdminService;
@GetMapping("/list")
public List<OapiModels.FlowSummaryVo> list(@RequestParam("schId") Long schId) {
return flowService.listFlows(schId);
}
@GetMapping("/{flowGuid}")
public OapiModels.FlowSummaryVo getFlow(@PathVariable("flowGuid") String flowGuid,
@RequestParam("schId") Long schId) {
return flowService.getFlow(schId, flowGuid);
}
@PostMapping("/apply")
public OapiModels.ApplyResultVo apply(@RequestParam("schId") Long schId,
@RequestAttribute(value = "yh.app.auth", required = false) String appKey,
@RequestBody OapiModels.ApplyBody body) {
return flowService.apply(schId, appKey, body);
}
/** 发起预览:返回开启发起时指派的节点与候选人(已剔除发起人本人),供子应用提交页选人 */
@GetMapping("/apply/preview")
public OapiModels.ApplyPreviewVo applyPreview(@RequestParam("schId") Long schId,
@RequestParam("flowGuid") String flowGuid, @RequestParam("submitterId") Integer submitterId) {
return flowService.applyPreview(schId, flowGuid, submitterId);
}
@GetMapping("/instance")
public OapiModels.InstanceVo instance(@RequestParam("bizType") String bizType,
@RequestParam("bizId") String bizId,
@RequestParam("schId") Long schId) {
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);
}
/**
* 办件进度嵌入页换址(iframe 场景,token 模式与换图同构):pageUrl 为 flow-center 前端
* 绝对地址,子应用直接放 {@code <iframe src>}。用户级可见性(本人/办理人/管理员)由
* 子应用后端在调本端点前完成——oapi 层只认 schId,应用签名不替代"谁能看"。
*/
@GetMapping("/embed/url")
public OapiModels.EmbedUrlVo embedUrl(@RequestParam(value = "instanceId", required = false) Long instanceId,
@RequestParam(value = "bizType", required = false) String bizType,
@RequestParam(value = "bizId", required = false) String bizId,
@RequestParam(value = "mode", required = false) String mode,
@RequestParam(value = "taskId", required = false) Long taskId,
@RequestParam("schId") Long schId) {
return flowService.embedUrl(schId, instanceId, bizType, bizId, mode, taskId);
}
/**
* 撤回(提交人本人;仅尚无任务被办理时)。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,
@RequestAttribute(value = "yh.app.auth", required = false) String appKey,
@RequestBody OapiModels.CallbackRegBody body) {
return flowService.registerCallback(schId, appKey, body);
}
/**
* 判断服务登记(2026-10-12 SERVICE 收口):由 {@code yh-flow-callback-spring-boot-starter} 启动自注册调用。
* 无 schId——{@code flw_router} 是全局表;归属即验签后的 appKey(登记即持有,跨应用覆盖拒绝)。
*/
@PostMapping("/router/reg")
public void registerRouter(@RequestAttribute(value = "yh.app.auth", required = false) String appKey,
@RequestBody OapiModels.RouterRegBody body) {
routerAdminService.registerByApp(appKey, body);
}
// ===== 应用内审批(第三步):查询 + 办理 =====
/** 我的待办(oapi):assigneeId 维度分页,bizType 可选过滤 */
@GetMapping("/tasks/todo")
public BasePageResult<OapiModels.TodoTaskVo> todoTasks(
@RequestParam("schId") Long schId,
@RequestParam("assigneeId") Integer assigneeId,
@RequestParam(value = "bizType", required = false) String bizType,
@RequestParam(value = "page", required = false) Integer page,
@RequestParam(value = "size", required = false) Integer size) {
return flowService.pageTodoTasks(schId, assigneeId, bizType, page, size);
}
/**
* 按业务单据查当前人待办(v2.1 业务详情卡片数据源):与 tasks/todo 互补——那个是"人→单据",
* 这个是"单据→我的待办"。0/1/N 三种计数都由 HTTP 200 + tasks 数组表达,办件不存在与
* 他人待办同样出空(不用于探测)。operatorId 由子应用后端从 CAS 会话取,前端不可传。
*/
@GetMapping("/tasks/by-biz")
public OapiModels.ByBizTasksVo tasksByBiz(
@RequestParam("schId") Long schId,
@RequestParam("bizType") String bizType,
@RequestParam("bizId") String bizId,
@RequestParam("operatorId") Integer operatorId) {
return flowService.tasksByBiz(schId, bizType, bizId, operatorId);
}
/** 办件分页(oapi):bizType/status 可选过滤 */
@GetMapping("/instances")
public BasePageResult<OapiModels.InstanceItemVo> instances(
@RequestParam("schId") Long schId,
@RequestParam(value = "bizType", required = false) String bizType,
@RequestParam(value = "status", required = false) Integer status,
@RequestParam(value = "page", required = false) Integer page,
@RequestParam(value = "size", required = false) Integer size) {
return flowService.pageInstances(schId, bizType, status, page, size);
}
/** 同意(oapi):operatorId 按任务办理人逐字复核,非办理人→业务码拒绝 */
@PostMapping("/task/{taskId}/approve")
public void approve(@RequestParam("schId") Long schId,
@RequestParam("operatorId") Integer operatorId,
@RequestParam("operatorName") String operatorName,
@PathVariable("taskId") Long taskId,
@RequestBody(required = false) OapiModels.HandleBody body) {
flowService.approveTask(schId, taskId, operatorId, operatorName,
body == null ? null : body.getOpinion(),
body == null ? null : body.getEdgeName());
}
/** 拒绝(oapi):opinion 必填,非办理人→业务码拒绝 */
@PostMapping("/task/{taskId}/reject")
public void reject(@RequestParam("schId") Long schId,
@RequestParam("operatorId") Integer operatorId,
@RequestParam("operatorName") String operatorName,
@PathVariable("taskId") Long taskId,
@RequestBody(required = false) OapiModels.HandleBody body) {
flowService.rejectTask(schId, taskId, operatorId, operatorName,
body == null ? null : body.getOpinion());
}
}