✨ 解耦MK表单实例与业务ID,公开页按formInstanceId反查业务数据

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 02:23:19 +08:00
parent 247440288b
commit beb0850644
24 changed files with 1172 additions and 96 deletions
@@ -30,12 +30,16 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.constant.AuthConstant;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.api.FR;
import org.springblade.core.tool.api.R;
import org.springblade.process.feign.IBusinessProcessClient;
import org.springblade.process.pojo.vo.MkFormBindVO;
import org.springblade.transport.pojo.vo.CustomerArchiveVO;
import org.springblade.transport.pojo.vo.CustomerChangeRecordVO;
import org.springblade.transport.service.ICustomerArchiveService;
@@ -65,15 +69,34 @@ public class CustomerArchivePublicController {
private final ICustomerArchiveService customerArchiveService;
private final CustomerArchivePublicProcessService customerArchivePublicProcessService;
private final IBusinessProcessClient businessProcessClient;
/**
* 公开详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "公开详情", description = "传入id,无需登录")
public R<CustomerArchiveVO> detail(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.data(customerArchiveService.publicDetail(id));
@Operation(summary = "公开详情", description = "传入表单实例id,无需登录;内部反查业务主键后加载详情")
public R<CustomerArchiveVO> detail(@Parameter(description = "表单实例id", required = true) @RequestParam Long id) {
return R.data(customerArchiveService.publicDetail(resolveBizId(id)));
}
/**
* 公开页传入的 id 为 formInstanceId,反查业务主键;查不到时兼容历史(id 即 bizId)
*/
private Long resolveBizId(Long formInstanceId) {
if (formInstanceId == null) {
throw new ServiceException("表单实例id不能为空");
}
try {
FR<MkFormBindVO> result = businessProcessClient.resolveByFormInstanceId(formInstanceId);
if (result != null && result.isSuccess() && result.getData() != null && result.getData().getBizId() != null) {
return result.getData().getBizId();
}
} catch (Exception e) {
log.warn("按表单实例id解析客商业务主键失败,回退按业务主键查询 formInstanceId={}", formInstanceId, e);
}
return formInstanceId;
}
/**
@@ -7,10 +7,14 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.constant.AuthConstant;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.api.FR;
import org.springblade.core.tool.api.R;
import org.springblade.process.feign.IBusinessProcessClient;
import org.springblade.process.pojo.vo.MkFormBindVO;
import org.springblade.transport.mk.MkProcessMessageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -35,13 +39,33 @@ import java.util.Map;
public class MkProcessPublicController {
private final MkProcessMessageService mkProcessMessageService;
private final IBusinessProcessClient businessProcessClient;
@GetMapping("/{bizType}/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "公开详情", description = "无需登录")
@Operation(summary = "公开详情", description = "无需登录;id 为 MK 表单实例id,内部反查业务主键后加载详情")
public R detail(@PathVariable String bizType,
@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.data(mkProcessMessageService.handler(bizType).publicDetail(id));
@Parameter(description = "表单实例id", required = true) @RequestParam Long id) {
Long bizId = resolveBizId(id);
return R.data(mkProcessMessageService.handler(bizType).publicDetail(bizId));
}
/**
* 公开页传入的 id 为 formInstanceId,反查业务主键;查不到时兼容历史(id 即 bizId)
*/
private Long resolveBizId(Long formInstanceId) {
if (formInstanceId == null) {
throw new ServiceException("表单实例id不能为空");
}
try {
FR<MkFormBindVO> result = businessProcessClient.resolveByFormInstanceId(formInstanceId);
if (result != null && result.isSuccess() && result.getData() != null && result.getData().getBizId() != null) {
return result.getData().getBizId();
}
} catch (Exception e) {
log.warn("按表单实例id解析业务主键失败,回退按业务主键查询 formInstanceId={}", formInstanceId, e);
}
return formInstanceId;
}
@PostMapping("/{bizType}/process-message")
@@ -3,19 +3,26 @@ package org.springblade.transport.mk;
import lombok.RequiredArgsConstructor;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.utils.Func;
import org.springblade.transport.pojo.dto.BillPaymentStatusRequest;
import org.springblade.transport.pojo.dto.InvoiceApplicationStatusRequest;
import org.springblade.transport.pojo.dto.InvoiceReceiptStatusRequest;
import org.springblade.transport.pojo.entity.BillPayment;
import org.springblade.transport.pojo.entity.ContractManage;
import org.springblade.transport.pojo.entity.FormalSettlement;
import org.springblade.transport.pojo.entity.InvoiceApplication;
import org.springblade.transport.pojo.entity.InvoiceReceipt;
import org.springblade.transport.pojo.entity.PaymentApplication;
import org.springblade.transport.pojo.entity.PreSettlement;
import org.springblade.transport.pojo.entity.ProjectApply;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.service.IBillPaymentService;
import org.springblade.transport.service.IContractManageService;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springblade.transport.service.IFormalSettlementService;
import org.springblade.transport.service.IInvoiceApplicationService;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.service.IPaymentApplicationService;
import org.springblade.transport.service.IPreSettlementService;
import org.springblade.transport.service.IProjectApplyService;
import org.springblade.transport.service.IWaybillService;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@@ -198,57 +205,6 @@ public final class MkProcessBizHandlers {
}
}
@Component
@TenantIgnore
@RequiredArgsConstructor
public static class WaybillHandler implements IMkProcessBizHandler {
private final IWaybillService service;
@Override
public String bizType() {
return "waybill-manage";
}
@Override
public Object publicDetail(Long id) {
return service.publicDetail(id);
}
@Override
public boolean syncFromProcessInfo(Long id, Object processInfo) {
Waybill entity = service.getById(id);
if (entity == null) {
return false;
}
String node = MkProcessNodeHelper.currentNode(processInfo);
if (Func.isEmpty(node)) {
return false;
}
entity.setCurrentProcessNode(node);
return service.updateById(entity);
}
@Override
public boolean approveFromProcess(Long id, String processorName) {
Waybill entity = service.getById(id);
if (entity == null) {
return false;
}
entity.setCurrentProcessNode("审核通过");
return service.updateById(entity);
}
@Override
public boolean rejectFromProcess(Long id, String processorName) {
Waybill entity = service.getById(id);
if (entity == null) {
return false;
}
entity.setCurrentProcessNode("审核不通过");
return service.updateById(entity);
}
}
@Component
@TenantIgnore
@RequiredArgsConstructor
@@ -436,4 +392,229 @@ public final class MkProcessBizHandlers {
return service.updateById(entity);
}
}
@Component
@TenantIgnore
@RequiredArgsConstructor
public static class InvoiceApplicationHandler implements IMkProcessBizHandler {
private final IInvoiceApplicationService service;
@Override
public String bizType() {
return "invoice-application";
}
@Override
public Object publicDetail(Long id) {
return service.detail(id);
}
@Override
public boolean syncFromProcessInfo(Long id, Object processInfo) {
InvoiceApplication entity = service.getById(id);
if (entity == null) {
return false;
}
String node = MkProcessNodeHelper.currentNode(processInfo);
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
return false;
}
if (Func.isNotEmpty(node)) {
entity.setCurrentNode(node);
}
if (Func.isNotEmpty(processor)) {
entity.setCurrentProcessor(processor);
}
entity.setApprovalStatus("reviewing");
return service.updateById(entity);
}
@Override
public boolean approveFromProcess(Long id, String processorName) {
InvoiceApplication entity = service.getById(id);
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
return entity != null;
}
InvoiceApplicationStatusRequest request = new InvoiceApplicationStatusRequest();
request.setId(id);
service.approve(request);
InvoiceApplication updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
@Override
public boolean rejectFromProcess(Long id, String processorName) {
InvoiceApplication entity = service.getById(id);
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
return entity != null;
}
InvoiceApplicationStatusRequest request = new InvoiceApplicationStatusRequest();
request.setId(id);
request.setReason("MK流程驳回");
service.returnBill(request);
InvoiceApplication updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核不通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
}
@Component
@TenantIgnore
@RequiredArgsConstructor
public static class InvoiceReceiptHandler implements IMkProcessBizHandler {
private final IInvoiceReceiptService service;
@Override
public String bizType() {
return "invoice-receipt";
}
@Override
public Object publicDetail(Long id) {
return service.detail(id);
}
@Override
public boolean syncFromProcessInfo(Long id, Object processInfo) {
InvoiceReceipt entity = service.getById(id);
if (entity == null) {
return false;
}
String node = MkProcessNodeHelper.currentNode(processInfo);
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
return false;
}
if (Func.isNotEmpty(node)) {
entity.setCurrentNode(node);
}
if (Func.isNotEmpty(processor)) {
entity.setCurrentProcessor(processor);
}
entity.setApprovalStatus("reviewing");
return service.updateById(entity);
}
@Override
public boolean approveFromProcess(Long id, String processorName) {
InvoiceReceipt entity = service.getById(id);
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
return entity != null;
}
InvoiceReceiptStatusRequest request = new InvoiceReceiptStatusRequest();
request.setId(id);
service.approve(request);
InvoiceReceipt updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
@Override
public boolean rejectFromProcess(Long id, String processorName) {
InvoiceReceipt entity = service.getById(id);
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
return entity != null;
}
InvoiceReceiptStatusRequest request = new InvoiceReceiptStatusRequest();
request.setId(id);
request.setReason("MK流程驳回");
service.returnBill(request);
InvoiceReceipt updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核不通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
}
@Component
@TenantIgnore
@RequiredArgsConstructor
public static class BillPaymentHandler implements IMkProcessBizHandler {
private final IBillPaymentService service;
@Override
public String bizType() {
return "bill-payment";
}
@Override
public Object publicDetail(Long id) {
return service.detail(id);
}
@Override
public boolean syncFromProcessInfo(Long id, Object processInfo) {
BillPayment entity = service.getById(id);
if (entity == null) {
return false;
}
String node = MkProcessNodeHelper.currentNode(processInfo);
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
return false;
}
if (Func.isNotEmpty(node)) {
entity.setCurrentNode(node);
}
if (Func.isNotEmpty(processor)) {
entity.setCurrentProcessor(processor);
}
entity.setApprovalStatus("reviewing");
return service.updateById(entity);
}
@Override
public boolean approveFromProcess(Long id, String processorName) {
BillPayment entity = service.getById(id);
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
return entity != null;
}
BillPaymentStatusRequest request = new BillPaymentStatusRequest();
request.setId(id);
service.approve(request);
BillPayment updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
@Override
public boolean rejectFromProcess(Long id, String processorName) {
BillPayment entity = service.getById(id);
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
return entity != null;
}
BillPaymentStatusRequest request = new BillPaymentStatusRequest();
request.setId(id);
request.setReason("MK流程驳回");
service.returnBill(request);
BillPayment updated = service.getById(id);
if (updated != null) {
updated.setCurrentNode("审核不通过");
updated.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
service.updateById(updated);
}
return true;
}
}
}
@@ -211,12 +211,14 @@ public class CommonCargoServiceImpl extends BaseServiceImpl<CommonCargoMapper, C
}
private LambdaQueryWrapper<CommonCargo> buildQuery(CommonCargoVO commonCargo) {
TransportBusinessSupport.validateAllDept(commonCargo.getAllDept(), "常用货物");
LambdaQueryWrapper<CommonCargo> queryWrapper = Wrappers.<CommonCargo>lambdaQuery().eq(CommonCargo::getIsDeleted, 0);
if (!Objects.equals(commonCargo.getAllDept(), 1)) {
queryWrapper.eq(CommonCargo::getDeptId, TransportBusinessSupport.currentDeptId("常用货物"));
} else if (Func.isNotEmpty(commonCargo.getDeptId())) {
queryWrapper.eq(CommonCargo::getDeptId, commonCargo.getDeptId());
List<Long> deptIdList = TransportBusinessSupport.resolveDeptFilterIds(commonCargo.getAllDept(), commonCargo.getDeptId(), "常用货物");
if (Func.isNotEmpty(deptIdList)) {
if (deptIdList.size() == 1) {
queryWrapper.eq(CommonCargo::getDeptId, deptIdList.get(0));
} else {
queryWrapper.in(CommonCargo::getDeptId, deptIdList);
}
}
if (Func.isNotEmpty(commonCargo.getFirstCargoTypeId())) {
queryWrapper.eq(CommonCargo::getFirstCargoTypeId, commonCargo.getFirstCargoTypeId());
@@ -31,6 +31,8 @@ import org.springblade.system.pojo.entity.Dept;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
@@ -83,6 +85,30 @@ public final class TransportBusinessSupport {
}
}
/**
* 解析列表组织筛选 ID。
* <p>
* allDept!=1 时强制当前组织;allDept=1 且传入 deptId 时仅精确匹配该组织;
* allDept=1 且未传 deptId 时返回空集合,表示不按组织过滤。
*
* @param allDept 是否查看全部组织
* @param deptId 筛选组织 ID
* @param moduleName 模块名称
* @return 需要过滤的组织 ID 集合;空集合表示不过滤组织
*/
public static List<Long> resolveDeptFilterIds(Integer allDept, Long deptId, String moduleName) {
validateAllDept(allDept, moduleName);
if (!Objects.equals(allDept, 1)) {
return Collections.singletonList(currentDeptId(moduleName));
}
// Jackson 空值可能被反序列化为 -1,这里与空值同等对待,避免误过滤。
if (Func.isEmpty(deptId) || deptId <= 0) {
return Collections.emptyList();
}
// 列表组织筛选项为单选,按所选组织精确过滤,不自动展开下级。
return Collections.singletonList(deptId);
}
public static String trimToEmpty(String value) {
return value == null ? "" : value.trim();
}