Files
NoticeService/src/main/java/com/yunhai/notice/service/flow/NoticeApprovalClient.java
T

153 lines
7.4 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.notice.service.flow;
import com.yunhai.platform.openapi.core.PlatformService;
import com.yunhai.platform.openapi.core.YschOpenCall;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 应用内审批出站客户端(第三步 T-C4):待办/办件查询 + 通过/驳回,经网关打 flow-center
* {@code /oapi/flow/tasks|task/**}(2026-09-23 已上线)。
* <p>
* <b>刻意用 {@link YschOpenCall} 泛化调用而非 YschFlowOpenApi 新门面方法</b>——四方法
* (todoTasks/instances/approveTask/rejectTask)在 SDK main 已编码但**未发版**,notice 运行时
* 依赖的是 nexus 已发布快照;泛化调用与 FlowCenterClient legacy 分支同一条
* resolveTarget 解析链(targets &gt; services &gt; 枚举 base-host 兜底=网关),零发版依赖。
* SDK 发版后可平替为门面方法(行为等价,测试锁 URL 不变)。
* <p>
* 身份口径:operatorId/operatorName 由调用方(controller)从 CAS 登录态取,本类不猜身份;
* 对端按任务办理人逐字复核(非办理人→业务码拒绝),notice 不重复校验。
*/
@Slf4j
@Service
public class NoticeApprovalClient {
private static final String TARGET = PlatformService.FLOW_CENTER.key();
private static final String NOT_CONNECTED = "流程中心未接入,审批功能不可用";
private final NoticeFlowProperties properties;
private final YschOpenCall openCall;
public NoticeApprovalClient(NoticeFlowProperties properties,
ObjectProvider<YschOpenCall> openCallProvider) {
this.properties = properties;
this.openCall = openCallProvider.getIfAvailable();
}
/** 我的待办(bizType 固定 notice):Map 形态即 flow-center BasePageResult JSON(total/content/…) */
public Map<String, Object> todoTasks(Integer schId, Integer assigneeId, Integer page, Integer size) {
requireEnabled();
Map<String, String> query = new LinkedHashMap<>();
query.put("schId", String.valueOf(schId));
query.put("assigneeId", String.valueOf(assigneeId));
query.put("bizType", FlowCenterClient.BIZ_TYPE);
if (page != null) {
query.put("page", String.valueOf(page));
}
if (size != null) {
query.put("size", String.valueOf(size));
}
return openCall.get(TARGET, "/oapi/flow/tasks/todo", query, Map.class);
}
/** 办件分页(bizType 固定 notice;status 可空) */
public Map<String, Object> instances(Integer schId, Integer status, Integer page, Integer size) {
requireEnabled();
Map<String, String> query = new LinkedHashMap<>();
query.put("schId", String.valueOf(schId));
query.put("bizType", FlowCenterClient.BIZ_TYPE);
if (status != null) {
query.put("status", String.valueOf(status));
}
if (page != null) {
query.put("page", String.valueOf(page));
}
if (size != null) {
query.put("size", String.valueOf(size));
}
return openCall.get(TARGET, "/oapi/flow/instances", query, Map.class);
}
/**
* 当前人在本通知上的待办(v2.1 业务详情卡片数据源,{@code /oapi/flow/tasks/by-biz})。
* <p>返回 Map 即对端 {@code ByBizTasksVo} JSON:{@code tasks[]} 0/1/N 三种计数都走 HTTP 200,
* <b>调用方不得据 tasks 反推"这个通知上有没有别人的待办"</b>——办件不存在、错学校、错 bizType、
* 非办理人四种情形出参完全同形(都是空 tasks),这是对端的防探测设计,本端不要试图区分。
* <p>{@code currentNodes} 是节点 <b>id</b> 逗号串(办件原文口径),人读名称取 {@code tasks[].nodeName}。
*/
@SuppressWarnings("unchecked")
public Map<String, Object> byBiz(Integer schId, Integer operatorId, Integer noticeId) {
requireEnabled();
Map<String, String> query = new LinkedHashMap<>();
query.put("schId", String.valueOf(schId));
query.put("bizType", FlowCenterClient.BIZ_TYPE);
query.put("bizId", String.valueOf(noticeId));
query.put("operatorId", String.valueOf(operatorId));
return openCall.get(TARGET, "/oapi/flow/tasks/by-biz", query, Map.class);
}
/**
* 完整办理任务页地址({@code /oapi/flow/embed/url?mode=task}):返回 CAS 会话页
* {@code {front}/#/task/{taskId}},<b>无 token</b>(写面,办理权由该页加载时的用户面接口按
* assigneeId 复核)。仍走 {@link YschOpenCall} 泛化调用——nexus 已发布快照的
* {@code YschFlowOpenApi} 只有 embedUrl/todoTasks/instances,没有 taskPageUrl 门面方法,
* 而本批纪律是不动 BasePlatform。SDK 补齐后可平替(URL 不变,测试锁死)。
*/
@SuppressWarnings("unchecked")
public Map<String, Object> taskPageUrl(Integer schId, Long taskId) {
requireEnabled();
Map<String, String> query = new LinkedHashMap<>();
query.put("schId", String.valueOf(schId));
query.put("mode", "task");
query.put("taskId", String.valueOf(taskId));
return openCall.get(TARGET, "/oapi/flow/embed/url", query, Map.class);
}
/** 同意(opinion 可空;多出口 edgeName 透传) */
public void approve(Long taskId, Integer schId, Integer operatorId, String operatorName,
String opinion, String edgeName) {
requireEnabled();
Map<String, Object> body = new LinkedHashMap<>();
if (opinion != null && !opinion.trim().isEmpty()) {
body.put("opinion", opinion.trim());
}
if (edgeName != null && !edgeName.trim().isEmpty()) {
body.put("edgeName", edgeName.trim());
}
openCall.post(TARGET, "/oapi/flow/task/" + taskId + "/approve",
operatorQuery(schId, operatorId, operatorName), body, Void.class);
}
/** 拒绝(opinion 必填由对端强制;此处前置校验给前端更快的反馈) */
public void reject(Long taskId, Integer schId, Integer operatorId, String operatorName, String opinion) {
requireEnabled();
if (opinion == null || opinion.trim().isEmpty()) {
throw new com.yunhai.platform.apistd.BizException(
com.yunhai.platform.utils.exception.ErrorCode.PARAM_ERROR, "驳回必须填写意见");
}
Map<String, Object> body = new LinkedHashMap<>();
body.put("opinion", opinion.trim());
openCall.post(TARGET, "/oapi/flow/task/" + taskId + "/reject",
operatorQuery(schId, operatorId, operatorName), body, Void.class);
}
private static Map<String, String> operatorQuery(Integer schId, Integer operatorId, String operatorName) {
Map<String, String> query = new LinkedHashMap<>();
query.put("schId", String.valueOf(schId));
query.put("operatorId", String.valueOf(operatorId));
query.put("operatorName", operatorName);
return query;
}
private void requireEnabled() {
if (!properties.isEnabled() || openCall == null) {
throw new com.yunhai.platform.apistd.BizException(
com.yunhai.platform.utils.exception.ErrorCode.FORBIDDEN, NOT_CONNECTED);
}
}
}