✨ 解耦MK表单实例与业务ID,公开页按formInstanceId反查业务数据
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+11
@@ -7,6 +7,7 @@ import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO;
|
||||
import org.springblade.process.pojo.dto.BusinessProcessSubmitDTO;
|
||||
import org.springblade.process.pojo.dto.BusinessProcessUpdateDTO;
|
||||
import org.springblade.process.pojo.vo.BusinessProcessVO;
|
||||
import org.springblade.process.pojo.vo.MkFormBindVO;
|
||||
import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
||||
import org.springblade.process.pojo.vo.ProcessTodoVO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
@@ -40,6 +41,7 @@ public interface IBusinessProcessClient {
|
||||
String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments";
|
||||
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
|
||||
String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo";
|
||||
String RESOLVE_BY_FORM_INSTANCE_ID = API_PREFIX + "/resolveByFormInstanceId";
|
||||
|
||||
/**
|
||||
* 提交业务流程
|
||||
@@ -126,4 +128,13 @@ public interface IBusinessProcessClient {
|
||||
@GetMapping(GET_PROCESS_INFO)
|
||||
FR<Object> getProcessInfo(@RequestParam("processInstanceId") String processInstanceId,
|
||||
@RequestParam(value = "loginName", required = false) String loginName);
|
||||
|
||||
/**
|
||||
* 按表单实例id解析业务绑定
|
||||
*
|
||||
* @param formInstanceId 表单实例id
|
||||
* @return 绑定信息(含业务主键)
|
||||
*/
|
||||
@GetMapping(RESOLVE_BY_FORM_INSTANCE_ID)
|
||||
FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId);
|
||||
}
|
||||
|
||||
+6
@@ -65,6 +65,12 @@ public class BusinessProcess implements Serializable {
|
||||
*/
|
||||
@Schema(description = "业务id")
|
||||
private Long bizId;
|
||||
/**
|
||||
* MK表单实例id
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "MK表单实例id")
|
||||
private Long formInstanceId;
|
||||
/**
|
||||
* 流程实例id
|
||||
*/
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.process.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MK表单实例绑定表 实体类
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Data
|
||||
@TableName("blade_mk_form_bind")
|
||||
@Schema(description = "MkFormBind对象")
|
||||
public class MkFormBind implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "主键")
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private String bizType;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "业务主键")
|
||||
private Long bizId;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "MK表单实例id")
|
||||
private Long formInstanceId;
|
||||
|
||||
@Schema(description = "MK流程实例id")
|
||||
private String processInstanceId;
|
||||
|
||||
@Schema(description = "是否当前生效(1是0否)")
|
||||
private Integer isCurrent;
|
||||
|
||||
@DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME)
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATETIME)
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
@DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME)
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATETIME)
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.process.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* MK表单实例绑定 VO
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "MkFormBindVO")
|
||||
public class MkFormBindVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "业务主键")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private String bizType;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "MK表单实例id")
|
||||
private Long formInstanceId;
|
||||
|
||||
@Schema(description = "MK流程实例id")
|
||||
private String processInstanceId;
|
||||
}
|
||||
+9
-3
@@ -13,6 +13,7 @@ import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.process.pojo.dto.ApprovalDTO;
|
||||
import org.springblade.process.pojo.vo.ApprovalVO;
|
||||
import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
||||
@@ -55,22 +56,27 @@ public class BusinessProcessController extends BladeController {
|
||||
|
||||
@PostMapping("/processSubmit")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Operation(summary = "提交MK审核流", description = "调用mk processSubmit,传入templateCode/submitIdentity/formInstanceId")
|
||||
@Operation(summary = "提交MK审核流", description = "传入bizId/bizType/templateCode,后端生成或复用formInstanceId后调用mk processSubmit")
|
||||
public R<String> processSubmit(@Validated @RequestBody MKProcessCreateDTO param) {
|
||||
return R.data(businessProcessService.processSubmit(param));
|
||||
}
|
||||
|
||||
@GetMapping("/hasMkProcessInstance")
|
||||
@ApiOperationSupport(order = 8)
|
||||
@Operation(summary = "查询MK流程实例是否存在", description = "传入业务id(formInstanceId),有数据则无需删除/重新提交")
|
||||
@Operation(summary = "查询MK流程实例是否存在", description = "传入业务主键bizId,有数据则无需删除/重新提交")
|
||||
public R<Boolean> hasMkProcessInstance(@Valid @NotBlank(message = "业务id不能为空") String bizId) {
|
||||
return R.data(businessProcessService.hasMkProcessInstance(bizId));
|
||||
}
|
||||
|
||||
@PostMapping("/processDelete")
|
||||
@ApiOperationSupport(order = 7)
|
||||
@Operation(summary = "删除MK审核流", description = "传入bizId,删除当前业务对应MK流程实例")
|
||||
public R<Boolean> processDelete(@RequestBody MKProcessCreateDTO param) {
|
||||
return R.data(businessProcessService.processDelete(param == null ? null : param.getFormInstanceId()));
|
||||
String bizId = null;
|
||||
if (param != null) {
|
||||
bizId = StringUtil.isNotBlank(param.getBizId()) ? param.getBizId() : param.getFormInstanceId();
|
||||
}
|
||||
return R.data(businessProcessService.processDelete(bizId));
|
||||
}
|
||||
|
||||
@GetMapping("/isEditView")
|
||||
|
||||
+8
@@ -11,6 +11,7 @@ import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO;
|
||||
import org.springblade.process.pojo.dto.BusinessProcessSubmitDTO;
|
||||
import org.springblade.process.pojo.dto.BusinessProcessUpdateDTO;
|
||||
import org.springblade.process.pojo.vo.BusinessProcessVO;
|
||||
import org.springblade.process.pojo.vo.MkFormBindVO;
|
||||
import org.springblade.process.pojo.vo.ProcessApprovedRecordVO;
|
||||
import org.springblade.process.pojo.vo.ProcessTodoVO;
|
||||
import org.springblade.process.service.IBusinessProcessService;
|
||||
@@ -94,4 +95,11 @@ public class BusinessProcessClient implements IBusinessProcessClient {
|
||||
@RequestParam(value = "loginName", required = false) String loginName) {
|
||||
return FR.data(businessProcessService.getProcessInfo(processInstanceId, loginName));
|
||||
}
|
||||
|
||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||
@GetMapping(RESOLVE_BY_FORM_INSTANCE_ID)
|
||||
@Override
|
||||
public FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId) {
|
||||
return FR.data(businessProcessService.resolveByFormInstanceId(formInstanceId));
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
<resultMap id="businessProcessResultMap" type="org.springblade.process.pojo.entity.BusinessProcess">
|
||||
<result column="id" property="id"/>
|
||||
<result column="biz_id" property="bizId"/>
|
||||
<result column="form_instance_id" property="formInstanceId"/>
|
||||
<result column="process_instance_id" property="processInstanceId"/>
|
||||
<result column="process_type" property="processType"/>
|
||||
<result column="doc_code" property="docCode"/>
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.process.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springblade.process.pojo.entity.MkFormBind;
|
||||
|
||||
/**
|
||||
* MK表单实例绑定表 Mapper 接口
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
public interface MkFormBindMapper extends BaseMapper<MkFormBind> {
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.springblade.process.mapper.MkFormBindMapper">
|
||||
|
||||
<resultMap id="mkFormBindResultMap" type="org.springblade.process.pojo.entity.MkFormBind">
|
||||
<result column="id" property="id"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
<result column="biz_type" property="bizType"/>
|
||||
<result column="biz_id" property="bizId"/>
|
||||
<result column="form_instance_id" property="formInstanceId"/>
|
||||
<result column="process_instance_id" property="processInstanceId"/>
|
||||
<result column="is_current" property="isCurrent"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
+13
-5
@@ -29,7 +29,7 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
|
||||
/**
|
||||
* 直接调用 MK processSubmit 提交流程
|
||||
*
|
||||
* @param param MK 流程创建参数
|
||||
* @param param MK 流程创建参数(传 bizId+bizType,后端生成/复用 formInstanceId)
|
||||
* @return 流程实例 id
|
||||
*/
|
||||
String processSubmit(MKProcessCreateDTO param);
|
||||
@@ -37,18 +37,26 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
|
||||
/**
|
||||
* 按业务 id 查询 MK 流程实例是否仍有数据(本地有 processInstanceId 且 MK getProcessInfo 有返回)
|
||||
*
|
||||
* @param bizId 业务 id(如客商 id / formInstanceId)
|
||||
* @param bizId 业务主键
|
||||
* @return true=流程实例仍存在
|
||||
*/
|
||||
boolean hasMkProcessInstance(String bizId);
|
||||
|
||||
/**
|
||||
* 按业务表单实例 id 删除 MK 流程(不删除本地业务流程记录,供驳回后重新提交使用)
|
||||
* 按业务主键删除 MK 流程(不删除本地业务流程记录与表单绑定,供驳回后重新提交使用)
|
||||
*
|
||||
* @param formInstanceId 业务表单实例 id
|
||||
* @param bizId 业务主键
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean processDelete(String formInstanceId);
|
||||
boolean processDelete(String bizId);
|
||||
|
||||
/**
|
||||
* 按表单实例id解析业务绑定
|
||||
*
|
||||
* @param formInstanceId 表单实例id
|
||||
* @return 绑定信息
|
||||
*/
|
||||
MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
|
||||
|
||||
/**
|
||||
* 获取流程当前节点详情
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.process.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.springblade.process.pojo.entity.MkFormBind;
|
||||
import org.springblade.process.pojo.vo.MkFormBindVO;
|
||||
|
||||
/**
|
||||
* MK表单实例绑定表 服务类
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
public interface IMkFormBindService extends IService<MkFormBind> {
|
||||
|
||||
/**
|
||||
* 查询业务当前生效的表单实例绑定
|
||||
*
|
||||
* @param bizType 业务类型(可空,空时仅按业务id查)
|
||||
* @param bizId 业务主键
|
||||
* @return 当前绑定,不存在返回 null
|
||||
*/
|
||||
MkFormBind getCurrentBind(String bizType, Long bizId);
|
||||
|
||||
/**
|
||||
* 按表单实例id查询绑定
|
||||
*
|
||||
* @param formInstanceId 表单实例id
|
||||
* @return 绑定记录
|
||||
*/
|
||||
MkFormBind getByFormInstanceId(Long formInstanceId);
|
||||
|
||||
/**
|
||||
* 按表单实例id解析业务主键等信息
|
||||
*
|
||||
* @param formInstanceId 表单实例id
|
||||
* @return 绑定 VO
|
||||
*/
|
||||
MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
|
||||
|
||||
/**
|
||||
* 解析或生成表单实例id:无当前绑定则新建;当前流程已审批通过则新建;否则复用
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param bizId 业务主键
|
||||
* @return 本次应使用的表单实例id
|
||||
*/
|
||||
Long resolveOrCreateFormInstanceId(String bizType, Long bizId);
|
||||
|
||||
/**
|
||||
* 回写流程实例id到当前绑定
|
||||
*
|
||||
* @param formInstanceId 表单实例id
|
||||
* @param processInstanceId 流程实例id
|
||||
*/
|
||||
void updateProcessInstanceId(Long formInstanceId, String processInstanceId);
|
||||
}
|
||||
+78
-18
@@ -25,6 +25,7 @@ import org.springblade.process.pojo.entity.BusinessProcess;
|
||||
import org.springblade.process.pojo.enums.TodoStatus;
|
||||
import org.springblade.process.pojo.vo.*;
|
||||
import org.springblade.process.service.IBusinessProcessService;
|
||||
import org.springblade.process.service.IMkFormBindService;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springblade.system.service.IUserService;
|
||||
import org.springblade.thirdparty.mk.config.MKProperties;
|
||||
@@ -72,6 +73,7 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
private final IUserService userService;
|
||||
private final ICustomerArchiveClient customerArchiveClient;
|
||||
private final IMkProcessClient mkProcessClient;
|
||||
private final IMkFormBindService mkFormBindService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
@@ -129,7 +131,6 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
@Override
|
||||
public String processSubmit(MKProcessCreateDTO param) {
|
||||
AssertUtils.notNull(param, "提交流程参数不能为空");
|
||||
AssertUtils.notBlank(param.getFormInstanceId(), "表单实例id不能为空");
|
||||
AssertUtils.notBlank(param.getTemplateCode(), "模板编码不能为空");
|
||||
// 前端拿到的手机号可能经 @Sensitive 脱敏(如 137****8880),这里从库取真实手机号覆盖
|
||||
String loginName = resolveCurrentUserPhone();
|
||||
@@ -138,36 +139,39 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
param.setLoginName(loginName);
|
||||
String bizType = param.getBizType();
|
||||
|
||||
Long bizId;
|
||||
try {
|
||||
bizId = Long.valueOf(param.getFormInstanceId());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException("表单实例id格式不正确");
|
||||
}
|
||||
Long bizId = resolveBizIdFromSubmitParam(param);
|
||||
Long formInstanceId = mkFormBindService.resolveOrCreateFormInstanceId(bizType, bizId);
|
||||
String formInstanceIdText = String.valueOf(formInstanceId);
|
||||
param.setFormInstanceId(formInstanceIdText);
|
||||
|
||||
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getBizId, bizId)
|
||||
.orderByDesc(BusinessProcess::getUpdateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
// 已有流程实例且 MK 仍能查到详情时,不再删除、不再重新创建提交
|
||||
if (businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId())) {
|
||||
if (businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId())
|
||||
&& Objects.equals(formInstanceId, businessProcess.getFormInstanceId())) {
|
||||
String existingProcessInstanceId = businessProcess.getProcessInstanceId();
|
||||
Object existingProcessInfo = this.getProcessInfo(existingProcessInstanceId, loginName);
|
||||
if (hasProcessInfoData(existingProcessInfo)) {
|
||||
log.info("MK流程实例已存在,跳过创建并提交流程 formInstanceId={} processInstanceId={}",
|
||||
param.getFormInstanceId(), existingProcessInstanceId);
|
||||
log.info("MK流程实例已存在,跳过创建并提交流程 bizId={} formInstanceId={} processInstanceId={}",
|
||||
bizId, formInstanceIdText, existingProcessInstanceId);
|
||||
businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue());
|
||||
if (StringUtil.isNotBlank(param.getSubject())) {
|
||||
businessProcess.setSubject(param.getSubject());
|
||||
}
|
||||
businessProcess.setPromoterLoginName(loginName);
|
||||
businessProcess.setFormInstanceId(formInstanceId);
|
||||
this.updateById(businessProcess);
|
||||
this.getCurrentNodes(existingProcessInstanceId, loginName);
|
||||
this.syncBizFromProcessInfo(bizType, param.getFormInstanceId(), existingProcessInfo);
|
||||
this.syncBizFromProcessInfo(bizType, String.valueOf(bizId), existingProcessInfo);
|
||||
return existingProcessInstanceId;
|
||||
}
|
||||
}
|
||||
|
||||
MKProcessCreateDTO mkParam = new MKProcessCreateDTO();
|
||||
mkParam.setFormInstanceId(param.getFormInstanceId());
|
||||
mkParam.setFormInstanceId(formInstanceIdText);
|
||||
mkParam.setSubject(param.getSubject());
|
||||
mkParam.setSubmitIdentity(loginName);
|
||||
mkParam.setLoginName(loginName);
|
||||
@@ -197,15 +201,35 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
businessProcess.setSubmitTime(new Date());
|
||||
}
|
||||
}
|
||||
businessProcess.setFormInstanceId(formInstanceId);
|
||||
businessProcess.setProcessInstanceId(processInstanceId);
|
||||
businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue());
|
||||
businessProcess.setIsCompleted(0);
|
||||
businessProcess.setCompleteTime(null);
|
||||
this.saveOrUpdate(businessProcess);
|
||||
mkFormBindService.updateProcessInstanceId(formInstanceId, processInstanceId);
|
||||
this.getCurrentNodes(processInstanceId, loginName);
|
||||
Object processInfo = this.getProcessInfo(processInstanceId, loginName);
|
||||
this.syncBizFromProcessInfo(bizType, param.getFormInstanceId(), processInfo);
|
||||
this.syncBizFromProcessInfo(bizType, String.valueOf(bizId), processInfo);
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从提交参数解析业务主键:优先 bizId,兼容旧调用把业务id放在 formInstanceId
|
||||
*/
|
||||
private Long resolveBizIdFromSubmitParam(MKProcessCreateDTO param) {
|
||||
String bizIdText = param.getBizId();
|
||||
if (StringUtil.isBlank(bizIdText)) {
|
||||
bizIdText = param.getFormInstanceId();
|
||||
}
|
||||
AssertUtils.notBlank(bizIdText, "业务id不能为空");
|
||||
try {
|
||||
return Long.valueOf(bizIdText);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException("业务id格式不正确");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMkProcessInstance(String bizId) {
|
||||
AssertUtils.notBlank(bizId, "业务id不能为空");
|
||||
@@ -217,11 +241,16 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
}
|
||||
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getBizId, id)
|
||||
.orderByDesc(BusinessProcess::getUpdateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
|
||||
return false;
|
||||
}
|
||||
// 审批通过后允许再次提交新表单实例,视为当前无有效待办流程
|
||||
if (Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus())) {
|
||||
return false;
|
||||
}
|
||||
String loginName = businessProcess.getPromoterLoginName();
|
||||
if (StringUtil.isBlank(loginName)) {
|
||||
loginName = resolveCurrentUserPhone();
|
||||
@@ -257,18 +286,20 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean processDelete(String formInstanceId) {
|
||||
AssertUtils.notBlank(formInstanceId, "表单实例id不能为空");
|
||||
AssertUtils.notBlank(formInstanceId, "业务id不能为空");
|
||||
Long bizId;
|
||||
try {
|
||||
bizId = Long.valueOf(formInstanceId);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException("表单实例id格式不正确");
|
||||
throw new ServiceException("业务id格式不正确");
|
||||
}
|
||||
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getBizId, bizId)
|
||||
.orderByDesc(BusinessProcess::getUpdateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
|
||||
log.warn("客商驳回后删除流程跳过,未找到流程实例 formInstanceId={}", formInstanceId);
|
||||
log.warn("驳回后删除流程跳过,未找到流程实例 bizId={}", bizId);
|
||||
return true;
|
||||
}
|
||||
String loginName = businessProcess.getPromoterLoginName();
|
||||
@@ -276,8 +307,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
loginName = resolveCurrentUserPhone();
|
||||
}
|
||||
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法删除审核流");
|
||||
log.info("调用mk processDelete processInstanceId={} loginName={} formInstanceId={}",
|
||||
businessProcess.getProcessInstanceId(), loginName, formInstanceId);
|
||||
log.info("调用mk processDelete processInstanceId={} loginName={} bizId={} formInstanceId={}",
|
||||
businessProcess.getProcessInstanceId(), loginName, bizId, businessProcess.getFormInstanceId());
|
||||
boolean deleted = mkService.processDelete(businessProcess.getProcessInstanceId(), loginName);
|
||||
if (!deleted) {
|
||||
throw new ServiceException("删除MK流程失败");
|
||||
@@ -285,6 +316,35 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MkFormBindVO resolveByFormInstanceId(Long formInstanceId) {
|
||||
AssertUtils.notNull(formInstanceId, "表单实例id不能为空");
|
||||
MkFormBindVO bindVO = mkFormBindService.resolveByFormInstanceId(formInstanceId);
|
||||
if (bindVO != null) {
|
||||
return bindVO;
|
||||
}
|
||||
// 兼容未迁移历史:formInstanceId 曾等于 bizId
|
||||
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getBizId, formInstanceId)
|
||||
.last("limit 1")
|
||||
);
|
||||
if (businessProcess == null) {
|
||||
businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getFormInstanceId, formInstanceId)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
if (businessProcess == null) {
|
||||
return null;
|
||||
}
|
||||
MkFormBindVO fallback = new MkFormBindVO();
|
||||
fallback.setBizId(businessProcess.getBizId());
|
||||
fallback.setFormInstanceId(businessProcess.getFormInstanceId() != null
|
||||
? businessProcess.getFormInstanceId() : businessProcess.getBizId());
|
||||
fallback.setProcessInstanceId(businessProcess.getProcessInstanceId());
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getCurrentNodes(String processInstanceId, String loginName) {
|
||||
if (StringUtils.isBlank(processInstanceId)) {
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.process.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.log.utils.AssertUtils;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.process.mapper.BusinessProcessMapper;
|
||||
import org.springblade.process.mapper.MkFormBindMapper;
|
||||
import org.springblade.process.pojo.entity.BusinessProcess;
|
||||
import org.springblade.process.pojo.entity.MkFormBind;
|
||||
import org.springblade.process.pojo.enums.ApproveStatusEnum;
|
||||
import org.springblade.process.pojo.vo.MkFormBindVO;
|
||||
import org.springblade.process.service.IMkFormBindService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* MK表单实例绑定表 服务实现类
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MkFormBindServiceImpl extends ServiceImpl<MkFormBindMapper, MkFormBind> implements IMkFormBindService {
|
||||
|
||||
private final BusinessProcessMapper businessProcessMapper;
|
||||
|
||||
@Override
|
||||
public MkFormBind getCurrentBind(String bizType, Long bizId) {
|
||||
AssertUtils.notNull(bizId, "业务id不能为空");
|
||||
MkFormBind bind = null;
|
||||
if (StringUtil.isNotBlank(bizType)) {
|
||||
bind = this.getOne(Wrappers.<MkFormBind>lambdaQuery()
|
||||
.eq(MkFormBind::getBizType, bizType)
|
||||
.eq(MkFormBind::getBizId, bizId)
|
||||
.eq(MkFormBind::getIsCurrent, 1)
|
||||
.orderByDesc(MkFormBind::getCreateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
if (bind == null) {
|
||||
// 兼容历史迁移数据 biz_type 为空,或未传 bizType
|
||||
bind = this.getOne(Wrappers.<MkFormBind>lambdaQuery()
|
||||
.eq(MkFormBind::getBizId, bizId)
|
||||
.eq(MkFormBind::getIsCurrent, 1)
|
||||
.orderByDesc(MkFormBind::getCreateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
return bind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MkFormBind getByFormInstanceId(Long formInstanceId) {
|
||||
AssertUtils.notNull(formInstanceId, "表单实例id不能为空");
|
||||
return this.getOne(Wrappers.<MkFormBind>lambdaQuery()
|
||||
.eq(MkFormBind::getFormInstanceId, formInstanceId)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MkFormBindVO resolveByFormInstanceId(Long formInstanceId) {
|
||||
MkFormBind bind = this.getByFormInstanceId(formInstanceId);
|
||||
if (bind == null) {
|
||||
return null;
|
||||
}
|
||||
MkFormBindVO vo = new MkFormBindVO();
|
||||
vo.setBizId(bind.getBizId());
|
||||
vo.setBizType(bind.getBizType());
|
||||
vo.setFormInstanceId(bind.getFormInstanceId());
|
||||
vo.setProcessInstanceId(bind.getProcessInstanceId());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long resolveOrCreateFormInstanceId(String bizType, Long bizId) {
|
||||
AssertUtils.notNull(bizId, "业务id不能为空");
|
||||
MkFormBind current = this.getCurrentBind(bizType, bizId);
|
||||
if (current == null) {
|
||||
return this.createNewBind(bizType, bizId);
|
||||
}
|
||||
BusinessProcess businessProcess = businessProcessMapper.selectOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||
.eq(BusinessProcess::getBizId, bizId)
|
||||
.orderByDesc(BusinessProcess::getUpdateTime)
|
||||
.last("limit 1")
|
||||
);
|
||||
boolean approvedPass = businessProcess != null
|
||||
&& Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus());
|
||||
if (approvedPass) {
|
||||
log.info("审核通过后再次提交,生成新表单实例 bizType={} bizId={} oldFormInstanceId={}",
|
||||
bizType, bizId, current.getFormInstanceId());
|
||||
this.lambdaUpdate()
|
||||
.eq(MkFormBind::getBizId, bizId)
|
||||
.eq(MkFormBind::getIsCurrent, 1)
|
||||
.set(MkFormBind::getIsCurrent, 0)
|
||||
.set(MkFormBind::getUpdateTime, new Date())
|
||||
.update();
|
||||
return this.createNewBind(bizType, bizId);
|
||||
}
|
||||
log.info("复用当前表单实例 bizType={} bizId={} formInstanceId={}",
|
||||
bizType, bizId, current.getFormInstanceId());
|
||||
if (StringUtil.isNotBlank(bizType) && StringUtil.isBlank(current.getBizType())) {
|
||||
current.setBizType(bizType);
|
||||
current.setUpdateTime(new Date());
|
||||
this.updateById(current);
|
||||
}
|
||||
return current.getFormInstanceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProcessInstanceId(Long formInstanceId, String processInstanceId) {
|
||||
AssertUtils.notNull(formInstanceId, "表单实例id不能为空");
|
||||
this.lambdaUpdate()
|
||||
.eq(MkFormBind::getFormInstanceId, formInstanceId)
|
||||
.set(MkFormBind::getProcessInstanceId, processInstanceId)
|
||||
.set(MkFormBind::getUpdateTime, new Date())
|
||||
.update();
|
||||
}
|
||||
|
||||
private Long createNewBind(String bizType, Long bizId) {
|
||||
Long formInstanceId = IdWorker.getId();
|
||||
MkFormBind bind = new MkFormBind();
|
||||
bind.setId(IdWorker.getId());
|
||||
bind.setTenantId(StringUtil.isBlank(AuthUtil.getTenantId()) ? "000000" : AuthUtil.getTenantId());
|
||||
bind.setBizType(StringUtil.isBlank(bizType) ? "" : bizType);
|
||||
bind.setBizId(bizId);
|
||||
bind.setFormInstanceId(formInstanceId);
|
||||
bind.setIsCurrent(1);
|
||||
bind.setCreateTime(new Date());
|
||||
bind.setUpdateTime(new Date());
|
||||
boolean saved = this.save(bind);
|
||||
if (!saved) {
|
||||
throw new ServiceException("保存表单实例绑定失败");
|
||||
}
|
||||
log.info("创建表单实例绑定 bizType={} bizId={} formInstanceId={}", bizType, bizId, formInstanceId);
|
||||
return formInstanceId;
|
||||
}
|
||||
}
|
||||
+13
@@ -26,6 +26,7 @@
|
||||
package org.springblade.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.system.pojo.vo.DeptVO;
|
||||
|
||||
@@ -66,6 +67,18 @@ public interface DeptMapper extends BaseMapper<Dept> {
|
||||
*/
|
||||
List<DeptVO> lazyTree(String tenantId, Long parentId);
|
||||
|
||||
/**
|
||||
* 按组织 ID 集合查询树节点(用于数据权限过滤后的根节点回显)
|
||||
*
|
||||
* @param tenantId 租户ID,空表示不限
|
||||
* @param ids 需要返回的组织 ID
|
||||
* @param childIds 计算 hasChildren 时允许计入的子组织 ID;为空则 hasChildren 恒为 false
|
||||
* @return 树节点列表
|
||||
*/
|
||||
List<DeptVO> treeNodesByIds(@Param("tenantId") String tenantId,
|
||||
@Param("ids") List<Long> ids,
|
||||
@Param("childIds") List<Long> childIds);
|
||||
|
||||
/**
|
||||
* 获取部门名
|
||||
*
|
||||
|
||||
@@ -115,6 +115,47 @@
|
||||
ORDER BY dept.sort
|
||||
</select>
|
||||
|
||||
<select id="treeNodesByIds" resultMap="treeNodeResultMap">
|
||||
SELECT
|
||||
dept.id,
|
||||
dept.parent_id,
|
||||
dept.dept_name AS title,
|
||||
dept.id AS "value",
|
||||
dept.id AS "key",
|
||||
(
|
||||
SELECT
|
||||
CASE WHEN count(1) > 0 THEN 1 ELSE 0 END
|
||||
FROM
|
||||
blade_dept child
|
||||
WHERE
|
||||
child.parent_id = dept.id
|
||||
AND child.is_deleted = 0
|
||||
<choose>
|
||||
<when test="childIds != null and childIds.size() > 0">
|
||||
AND child.id IN
|
||||
<foreach collection="childIds" item="childId" open="(" close=")" separator=",">
|
||||
#{childId}
|
||||
</foreach>
|
||||
</when>
|
||||
<otherwise>
|
||||
AND 1 = 0
|
||||
</otherwise>
|
||||
</choose>
|
||||
) AS "has_children"
|
||||
FROM
|
||||
blade_dept dept
|
||||
WHERE
|
||||
dept.is_deleted = 0
|
||||
AND dept.id IN
|
||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
<if test="tenantId != null and tenantId != ''">
|
||||
AND dept.tenant_id = #{tenantId}
|
||||
</if>
|
||||
ORDER BY dept.sort, dept.id
|
||||
</select>
|
||||
|
||||
<select id="getDeptNames" resultType="java.lang.String">
|
||||
SELECT
|
||||
dept_name
|
||||
|
||||
+5
-3
@@ -68,10 +68,10 @@ public interface IDeptService extends IService<Dept> {
|
||||
List<DeptVO> lazyList(String tenantId, Long parentId, Map<String, Object> param);
|
||||
|
||||
/**
|
||||
* 树形结构(含超管判定 + 当前租户隔离)
|
||||
* 树形结构(含超管判定 + 当前租户隔离 + 用户组织数据权限)
|
||||
* <p>
|
||||
* 仅超级管理员可指定任意 tenantId 查询;其他用户传入的 tenantId 一律被忽略,
|
||||
* 强制使用当前会话租户。
|
||||
* 强制使用当前会话租户,并按用户「数据权限范围」「数据层级范围」过滤可见组织。
|
||||
*
|
||||
* @param tenantId 入参 tenantId(仅超管生效)
|
||||
* @return 部门树
|
||||
@@ -79,9 +79,11 @@ public interface IDeptService extends IService<Dept> {
|
||||
List<DeptVO> tree(String tenantId);
|
||||
|
||||
/**
|
||||
* 懒加载树形结构(含超管判定 + 当前租户隔离)
|
||||
* 懒加载树形结构(含超管判定 + 当前租户隔离 + 用户组织数据权限)
|
||||
* <p>
|
||||
* 仅超级管理员可指定任意 tenantId,空值表示查询全部;其他用户强制使用当前会话租户。
|
||||
* 非超管按用户「数据权限范围」「数据层级范围」过滤可见组织:
|
||||
* 仅所属组织 / 自定义组织,并可选择是否包含无限下级。
|
||||
*
|
||||
* @param tenantId 入参 tenantId(仅超管生效)
|
||||
* @param parentId 父级部门ID
|
||||
|
||||
+154
-2
@@ -44,8 +44,10 @@ import org.springblade.core.tool.node.ForestNodeMerger;
|
||||
import org.springblade.core.tool.utils.*;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.mapper.DeptMapper;
|
||||
import org.springblade.system.mapper.UserDataScopeMapper;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springblade.system.pojo.entity.UserDataScope;
|
||||
import org.springblade.system.pojo.enums.DeptCategory;
|
||||
import org.springblade.system.pojo.vo.DeptVO;
|
||||
import org.springblade.system.pojo.vo.UserVO;
|
||||
@@ -90,8 +92,19 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
private static final String IAM_SYNC_TENANT_ID = "000000";
|
||||
private static final Long IAM_SYNC_PARENT_ID = 1123598813738675201L;
|
||||
private static final HttpClient IAM_HTTP_CLIENT = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
|
||||
/** 数据权限范围:仅所属组织 */
|
||||
private static final int DATA_SCOPE_OWN = 1;
|
||||
/** 数据权限范围:全部组织 */
|
||||
private static final int DATA_SCOPE_ALL = 2;
|
||||
/** 数据权限范围:自定义 */
|
||||
private static final int DATA_SCOPE_CUSTOM = 3;
|
||||
/** 数据层级范围:包含下级 */
|
||||
private static final int DATA_LEVEL_INCLUDE_CHILDREN = 1;
|
||||
/** 数据层级范围:仅本级 */
|
||||
private static final int DATA_LEVEL_CURRENT_ONLY = 2;
|
||||
|
||||
private final IUserService userService;
|
||||
private final UserDataScopeMapper userDataScopeMapper;
|
||||
private final IamSyncProperties iamSyncProperties;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@@ -144,7 +157,11 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
String resolvedTenantId = AuthUtil.isAdministrator()
|
||||
? Func.toStrWithEmpty(tenantId, AuthUtil.getTenantId())
|
||||
: AuthUtil.getTenantId();
|
||||
return ForestNodeMerger.merge(baseMapper.tree(resolvedTenantId));
|
||||
DeptDataScopeFilter scopeFilter = resolveDeptDataScopeFilter();
|
||||
if (scopeFilter == null || scopeFilter.allDept()) {
|
||||
return ForestNodeMerger.merge(baseMapper.tree(resolvedTenantId));
|
||||
}
|
||||
return buildScopedDeptTree(resolvedTenantId, scopeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,7 +170,142 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
String resolvedTenantId = AuthUtil.isAdministrator()
|
||||
? Func.toStr(tenantId, StringPool.EMPTY)
|
||||
: AuthUtil.getTenantId();
|
||||
return ForestNodeMerger.merge(baseMapper.lazyTree(resolvedTenantId, parentId));
|
||||
Long resolvedParentId = parentId == null ? BladeConstant.TOP_PARENT_ID : parentId;
|
||||
DeptDataScopeFilter scopeFilter = resolveDeptDataScopeFilter();
|
||||
if (scopeFilter == null || scopeFilter.allDept()) {
|
||||
return ForestNodeMerger.merge(baseMapper.lazyTree(resolvedTenantId, resolvedParentId));
|
||||
}
|
||||
Set<Long> allowedIds = scopeFilter.allowedDeptIds();
|
||||
if (Func.isEmpty(allowedIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
boolean includeChildren = scopeFilter.includeChildren();
|
||||
List<Long> childIdsForHasChildren = includeChildren ? new ArrayList<>(allowedIds) : Collections.emptyList();
|
||||
// 根层:返回「可见根」——权限集合中父节点不在集合内的组织,避免用户看不到深层权限节点。
|
||||
if (Objects.equals(resolvedParentId, BladeConstant.TOP_PARENT_ID)) {
|
||||
List<Long> visibleRootIds = resolveVisibleRootIds(allowedIds);
|
||||
if (Func.isEmpty(visibleRootIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ForestNodeMerger.merge(baseMapper.treeNodesByIds(resolvedTenantId, visibleRootIds, childIdsForHasChildren));
|
||||
}
|
||||
// 非根层:无权限的父节点不允许展开;仅本级时不允许继续下钻。
|
||||
if (!includeChildren || !allowedIds.contains(resolvedParentId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<DeptVO> children = baseMapper.lazyTree(resolvedTenantId, resolvedParentId);
|
||||
List<Long> filteredChildIds = children.stream()
|
||||
.map(DeptVO::getId)
|
||||
.filter(allowedIds::contains)
|
||||
.toList();
|
||||
if (Func.isEmpty(filteredChildIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ForestNodeMerger.merge(baseMapper.treeNodesByIds(resolvedTenantId, filteredChildIds, childIdsForHasChildren));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按数据权限构建完整组织树(用于 /dept/tree)。
|
||||
*/
|
||||
private List<DeptVO> buildScopedDeptTree(String tenantId, DeptDataScopeFilter scopeFilter) {
|
||||
Set<Long> allowedIds = scopeFilter.allowedDeptIds();
|
||||
if (Func.isEmpty(allowedIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Long> childIdsForHasChildren = scopeFilter.includeChildren()
|
||||
? new ArrayList<>(allowedIds)
|
||||
: Collections.emptyList();
|
||||
return ForestNodeMerger.merge(baseMapper.treeNodesByIds(tenantId, new ArrayList<>(allowedIds), childIdsForHasChildren));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算懒加载首层可见根:父级不在权限集合内的组织。
|
||||
*/
|
||||
private List<Long> resolveVisibleRootIds(Set<Long> allowedIds) {
|
||||
return listByIds(allowedIds).stream()
|
||||
.filter(dept -> dept.getParentId() == null
|
||||
|| Objects.equals(dept.getParentId(), BladeConstant.TOP_PARENT_ID)
|
||||
|| !allowedIds.contains(dept.getParentId()))
|
||||
.sorted(Comparator.comparing(Dept::getSort, Comparator.nullsLast(Integer::compareTo))
|
||||
.thenComparing(Dept::getId, Comparator.nullsLast(Long::compareTo)))
|
||||
.map(Dept::getId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析当前登录用户的组织树数据权限。
|
||||
* <p>
|
||||
* 超管或「全部组织」返回 allDept=true;其余按所属组织/自定义组织,并结合「包含下级/仅本级」展开。
|
||||
*
|
||||
* @return 过滤上下文;无法识别用户时按空权限处理
|
||||
*/
|
||||
private DeptDataScopeFilter resolveDeptDataScopeFilter() {
|
||||
if (AuthUtil.isAdministrator()) {
|
||||
return DeptDataScopeFilter.all();
|
||||
}
|
||||
Long userId = AuthUtil.getUserId();
|
||||
if (Func.isEmpty(userId) || userId <= 0) {
|
||||
return DeptDataScopeFilter.empty();
|
||||
}
|
||||
User user = userService.getById(userId);
|
||||
if (Func.isEmpty(user)) {
|
||||
return DeptDataScopeFilter.empty();
|
||||
}
|
||||
Integer dataScopeRange = user.getDataScopeRange() == null ? DATA_SCOPE_OWN : user.getDataScopeRange();
|
||||
Integer dataLevelRange = user.getDataLevelRange() == null ? DATA_LEVEL_INCLUDE_CHILDREN : user.getDataLevelRange();
|
||||
if (Objects.equals(dataScopeRange, DATA_SCOPE_ALL)) {
|
||||
return DeptDataScopeFilter.all();
|
||||
}
|
||||
List<Long> baseDeptIds;
|
||||
if (Objects.equals(dataScopeRange, DATA_SCOPE_CUSTOM)) {
|
||||
baseDeptIds = userDataScopeMapper.selectList(Wrappers.<UserDataScope>lambdaQuery()
|
||||
.eq(UserDataScope::getUserId, userId))
|
||||
.stream()
|
||||
.map(UserDataScope::getDeptId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
} else {
|
||||
// 仅所属组织:优先用户档案中的所属组织,其次当前会话组织。
|
||||
baseDeptIds = Func.toLongList(user.getDeptId());
|
||||
if (Func.isEmpty(baseDeptIds)) {
|
||||
baseDeptIds = Func.toLongList(AuthUtil.getDeptId());
|
||||
}
|
||||
}
|
||||
if (Func.isEmpty(baseDeptIds)) {
|
||||
return DeptDataScopeFilter.empty();
|
||||
}
|
||||
boolean includeChildren = !Objects.equals(dataLevelRange, DATA_LEVEL_CURRENT_ONLY);
|
||||
LinkedHashSet<Long> allowedDeptIds = new LinkedHashSet<>();
|
||||
for (Long deptId : baseDeptIds) {
|
||||
if (Func.isEmpty(deptId) || deptId <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (includeChildren) {
|
||||
List<Long> childIds = SysCache.getDeptChildIds(deptId);
|
||||
if (Func.isNotEmpty(childIds)) {
|
||||
allowedDeptIds.addAll(childIds);
|
||||
} else {
|
||||
allowedDeptIds.add(deptId);
|
||||
}
|
||||
} else {
|
||||
allowedDeptIds.add(deptId);
|
||||
}
|
||||
}
|
||||
return new DeptDataScopeFilter(false, includeChildren, allowedDeptIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组织懒加载树的数据权限过滤上下文。
|
||||
*/
|
||||
private record DeptDataScopeFilter(boolean allDept, boolean includeChildren, Set<Long> allowedDeptIds) {
|
||||
private static DeptDataScopeFilter all() {
|
||||
return new DeptDataScopeFilter(true, true, Collections.emptySet());
|
||||
}
|
||||
|
||||
private static DeptDataScopeFilter empty() {
|
||||
return new DeptDataScopeFilter(false, false, Collections.emptySet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+26
-3
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+27
-3
@@ -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")
|
||||
|
||||
+234
-53
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -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());
|
||||
|
||||
+26
@@ -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();
|
||||
}
|
||||
|
||||
+6
-1
@@ -17,9 +17,14 @@ public class MKProcessCreateDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 表单实例id,业务id
|
||||
* 表单实例id(传给 MK;由后端生成,前端勿传)
|
||||
*/
|
||||
private String formInstanceId;
|
||||
/**
|
||||
* 业务主键,仅 ERP 内部使用,不传给 MK
|
||||
*/
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
private String bizId;
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
-- MK 业务ID与表单实例ID绑定
|
||||
CREATE TABLE IF NOT EXISTS `blade_mk_form_bind`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`tenant_id` varchar(12) DEFAULT '000000' COMMENT '租户ID',
|
||||
`biz_type` varchar(64) NOT NULL DEFAULT '' COMMENT '业务类型',
|
||||
`biz_id` bigint NOT NULL COMMENT '业务主键',
|
||||
`form_instance_id` bigint NOT NULL COMMENT 'MK表单实例id',
|
||||
`process_instance_id` varchar(64) DEFAULT NULL COMMENT 'MK流程实例id',
|
||||
`is_current` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否当前生效(1是0否)',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_blade_mk_form_bind_form_instance_id` (`form_instance_id`) USING BTREE,
|
||||
KEY `idx_blade_mk_form_bind_biz_current` (`biz_type`, `biz_id`, `is_current`) USING BTREE
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci COMMENT ='MK表单实例绑定表';
|
||||
|
||||
-- 业务流程表增加表单实例id
|
||||
ALTER TABLE `blade_business_process`
|
||||
ADD COLUMN `form_instance_id` bigint DEFAULT NULL COMMENT 'MK表单实例id' AFTER `biz_id`;
|
||||
|
||||
-- 历史数据:原 biz_id 即 formInstanceId,回填并写入绑定表
|
||||
UPDATE `blade_business_process`
|
||||
SET `form_instance_id` = `biz_id`
|
||||
WHERE `form_instance_id` IS NULL;
|
||||
|
||||
INSERT INTO `blade_mk_form_bind` (`id`, `tenant_id`, `biz_type`, `biz_id`, `form_instance_id`,
|
||||
`process_instance_id`, `is_current`, `create_time`, `update_time`)
|
||||
SELECT `id`,
|
||||
IFNULL(`tenant_id`, '000000'),
|
||||
'',
|
||||
`biz_id`,
|
||||
`biz_id`,
|
||||
`process_instance_id`,
|
||||
1,
|
||||
IFNULL(`create_time`, NOW()),
|
||||
IFNULL(`update_time`, NOW())
|
||||
FROM `blade_business_process` bp
|
||||
WHERE NOT EXISTS (SELECT 1
|
||||
FROM `blade_mk_form_bind` b
|
||||
WHERE b.`form_instance_id` = bp.`biz_id`);
|
||||
Reference in New Issue
Block a user