[audit] P6.2 F9 embed/url 支持 mode=task 直跳任务办理页(taskId 必填,无 token CAS 页;front-url fail-fast 纪律不变)
This commit is contained in:
@@ -111,8 +111,9 @@ public class OapiFlowController {
|
|||||||
@RequestParam(value = "bizType", required = false) String bizType,
|
@RequestParam(value = "bizType", required = false) String bizType,
|
||||||
@RequestParam(value = "bizId", required = false) String bizId,
|
@RequestParam(value = "bizId", required = false) String bizId,
|
||||||
@RequestParam(value = "mode", required = false) String mode,
|
@RequestParam(value = "mode", required = false) String mode,
|
||||||
|
@RequestParam(value = "taskId", required = false) Long taskId,
|
||||||
@RequestParam("schId") Long schId) {
|
@RequestParam("schId") Long schId) {
|
||||||
return flowService.embedUrl(schId, instanceId, bizType, bizId, mode);
|
return flowService.embedUrl(schId, instanceId, bizType, bizId, mode, taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -518,10 +518,34 @@ public class OapiFlowService {
|
|||||||
* 接收人;签发侧必须与之一致,否则"抄送我的"点开得、进度嵌入页换址却拒发(2026-10-17 记)。
|
* 接收人;签发侧必须与之一致,否则"抄送我的"点开得、进度嵌入页换址却拒发(2026-10-17 记)。
|
||||||
*/
|
*/
|
||||||
public OapiModels.EmbedUrlVo embedUrl(Long schId, Long instanceId, String bizType, String bizId, String mode) {
|
public OapiModels.EmbedUrlVo embedUrl(Long schId, Long instanceId, String bizType, String bizId, String mode) {
|
||||||
|
return embedUrl(schId, instanceId, bizType, bizId, mode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mode=task(F9)直跳中心任务办理页:pageUrl = front-url + {@code #/task/{taskId}},
|
||||||
|
* 无 token(CAS 会话鉴权页,办理权由该页加载时的用户面接口按 assigneeId 复核)——
|
||||||
|
* 子应用"在自家页放办理入口"场景用;taskId 必填,缺则 PARAM_ERROR。
|
||||||
|
*/
|
||||||
|
public OapiModels.EmbedUrlVo embedUrl(Long schId, Long instanceId, String bizType, String bizId,
|
||||||
|
String mode, Long taskId) {
|
||||||
// 配置缺失优先于办件定位:fail-fast 纪律要的是"无论如何都不发打不开的地址"
|
// 配置缺失优先于办件定位:fail-fast 纪律要的是"无论如何都不发打不开的地址"
|
||||||
if (embedFrontUrl == null || embedFrontUrl.trim().isEmpty()) {
|
if (embedFrontUrl == null || embedFrontUrl.trim().isEmpty()) {
|
||||||
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "嵌入页地址未配置:flow-center.embed.front-url");
|
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "嵌入页地址未配置:flow-center.embed.front-url");
|
||||||
}
|
}
|
||||||
|
String base = embedFrontUrl.trim();
|
||||||
|
if (!base.endsWith("/")) {
|
||||||
|
base = base + "/";
|
||||||
|
}
|
||||||
|
String normMode = mode == null || mode.trim().isEmpty() ? "auto" : mode.trim();
|
||||||
|
if ("task".equals(normMode)) {
|
||||||
|
if (taskId == null) {
|
||||||
|
throw new BizException(ErrorCode.PARAM_ERROR, "mode=task 需要 taskId(任务办理页定位)");
|
||||||
|
}
|
||||||
|
OapiModels.EmbedUrlVo out = new OapiModels.EmbedUrlVo();
|
||||||
|
out.setPageUrl(base + "#/task/" + taskId);
|
||||||
|
out.setExpiresIn(0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
Long resolvedInstanceId;
|
Long resolvedInstanceId;
|
||||||
if (instanceId != null) {
|
if (instanceId != null) {
|
||||||
resolvedInstanceId = requireInstance(schId, instanceId).getId();
|
resolvedInstanceId = requireInstance(schId, instanceId).getId();
|
||||||
@@ -536,12 +560,7 @@ public class OapiFlowService {
|
|||||||
resolvedInstanceId = vo.getInstanceId();
|
resolvedInstanceId = vo.getInstanceId();
|
||||||
}
|
}
|
||||||
// mode 与 DiagramTokenService 内部缺省同值("auto"),URL 里显式带上仅为前端展示冗余
|
// mode 与 DiagramTokenService 内部缺省同值("auto"),URL 里显式带上仅为前端展示冗余
|
||||||
String normMode = mode == null || mode.trim().isEmpty() ? "auto" : mode.trim();
|
|
||||||
String token = tokenService.issue(schId, resolvedInstanceId, null, normMode);
|
String token = tokenService.issue(schId, resolvedInstanceId, null, normMode);
|
||||||
String base = embedFrontUrl.trim();
|
|
||||||
if (!base.endsWith("/")) {
|
|
||||||
base = base + "/";
|
|
||||||
}
|
|
||||||
OapiModels.EmbedUrlVo out = new OapiModels.EmbedUrlVo();
|
OapiModels.EmbedUrlVo out = new OapiModels.EmbedUrlVo();
|
||||||
out.setPageUrl(base + "#/embed/instance?token=" + token + "&mode=" + normMode);
|
out.setPageUrl(base + "#/embed/instance?token=" + token + "&mode=" + normMode);
|
||||||
out.setExpiresIn(DiagramTokenService.TTL_MS / 1000);
|
out.setExpiresIn(DiagramTokenService.TTL_MS / 1000);
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.yunhai.flowcenter.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.yunhai.flowcenter.engine.AssigneeResolver;
|
||||||
|
import com.yunhai.flowcenter.engine.FlowEngine;
|
||||||
|
import com.yunhai.flowcenter.model.OapiModels;
|
||||||
|
import com.yunhai.flowcenter.repository.FlwCallbackRegRepository;
|
||||||
|
import com.yunhai.flowcenter.repository.FlwCcRepository;
|
||||||
|
import com.yunhai.flowcenter.repository.FlwDefRepository;
|
||||||
|
import com.yunhai.flowcenter.repository.FlwInstanceRepository;
|
||||||
|
import com.yunhai.flowcenter.repository.FlwTaskRepository;
|
||||||
|
import com.yunhai.platform.apistd.BizException;
|
||||||
|
import com.yunhai.platform.openapi.base.OpenApiAppClient;
|
||||||
|
import com.yunhai.platform.openapi.base.OpenApiUserClient;
|
||||||
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* F9 mode=task 直跳任务办理页(P6.2):pageUrl = front-url + #/task/{taskId}(无 token);
|
||||||
|
* taskId 缺失 PARAM_ERROR;front-url 未配置沿用 fail-fast 纪律(先于一切定位)。
|
||||||
|
*/
|
||||||
|
@DisplayName("embed/url mode=task(F9 任务页直跳)")
|
||||||
|
class OapiFlowEmbedTaskUrlTest {
|
||||||
|
|
||||||
|
private OapiFlowService service;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
service = new OapiFlowService(Mockito.mock(FlwDefRepository.class),
|
||||||
|
Mockito.mock(FlwInstanceRepository.class), Mockito.mock(FlwTaskRepository.class),
|
||||||
|
Mockito.mock(FlwCcRepository.class), Mockito.mock(FlwCallbackRegRepository.class),
|
||||||
|
Mockito.mock(FlowInstanceService.class), Mockito.mock(FlowTaskService.class),
|
||||||
|
Mockito.mock(FlowEngine.class), Mockito.mock(AssigneeResolver.class),
|
||||||
|
new ObjectMapper(), Mockito.mock(OpenApiUserClient.class),
|
||||||
|
Mockito.mock(OpenApiAppClient.class), Mockito.mock(DiagramTokenService.class),
|
||||||
|
Mockito.mock(ObjectProvider.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void frontUrl(String value) {
|
||||||
|
org.springframework.test.util.ReflectionTestUtils.setField(service, "embedFrontUrl", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void taskModeIssuesCenterTaskPageUrlWithoutToken() {
|
||||||
|
frontUrl("http://fc.local/flow-center");
|
||||||
|
OapiModels.EmbedUrlVo vo = service.embedUrl(1L, null, null, null, "task", 88L);
|
||||||
|
assertEquals("http://fc.local/flow-center/#/task/88", vo.getPageUrl(),
|
||||||
|
"pageUrl = front-url(补尾斜杠)+ #/task/{taskId}");
|
||||||
|
assertEquals(0L, vo.getExpiresIn(), "无 token 模式无有效期,expiresIn=0");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void taskModeWithoutTaskIdRejected() {
|
||||||
|
frontUrl("http://fc.local/flow-center");
|
||||||
|
BizException e = assertThrows(BizException.class,
|
||||||
|
() -> service.embedUrl(1L, null, null, null, "task", null));
|
||||||
|
assertEquals(ErrorCode.PARAM_ERROR, e.getErrorCode(), "缺 taskId 是参数错误");
|
||||||
|
assertTrue(e.getMessage().contains("taskId"), "报错须点名缺失参数");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void missingFrontUrlStillFailsFastEvenForTaskMode() {
|
||||||
|
frontUrl(" ");
|
||||||
|
BizException e = assertThrows(BizException.class,
|
||||||
|
() -> service.embedUrl(1L, null, null, null, "task", 88L));
|
||||||
|
assertEquals(ErrorCode.INTERNAL_SERVER_ERROR, e.getErrorCode(),
|
||||||
|
"配置缺失优先于 mode 分支:宁可拒绝也不发打不开的地址");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user