1、完善项目

2、完善合同
3、完善费用项
4、司机管理对接OCR
5、完善运输计划
6、完善临时额度
This commit is contained in:
2026-08-04 02:49:59 +08:00
387 changed files with 22482 additions and 110 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springblade</groupId>
<artifactId>blade-third-party-api</artifactId>
<version>${revision}</version>
</parent>
<artifactId>blade-mk-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,17 @@
package org.springblade.thirdparty.mk.config;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
/**
* @author bfhuange
* @since 2024/12/18
*/
public class MKFeignClientConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
// 空实现屏蔽 全局拦截器 BladeFeignRequestInterceptor
};
}
}

View File

@@ -0,0 +1,61 @@
package org.springblade.thirdparty.mk.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* mk配置类
* @author bfhuange
* @date 2024/9/11
*/
@Data
@ConfigurationProperties(prefix = "third-party.mk")
public class MKProperties {
/**
* 应用key mk-集成平台-本系统API网关-账号管理
*/
private String appKey;
/**
* 应用secret mk-集成平台-本系统API网关-账号管理
*/
private String appSecret;
/**
* mk基础url接口调用地址内网地址
*/
private String baseUrl;
/**
* mk 登录地址,外网地址
*/
private String loginUrl;
//======================== mk 认证相关配置================================
/**
* oauth 应用id mk-系统管理-安全管理-认证服务
*/
private String oauthAppId;
/**
* oauth 应用秘钥 mk-系统管理-安全管理-认证服务
*/
private String oauthAppSecret;
/**
* mk 流程提交标题前缀
*/
private String subjectPrefix;
/**
* mk 流程模板编码前缀
*/
private String templateCodePrefix;
/**
* sso登录地址
*/
private String mkSsoLoginUrl = "/data/sys-oauth/ssoLogin";
/**
* 校验请求登录页面的来源地址,
*/
private boolean checkReferer = true;
/**
* erp系统基础链接用于校验referer是否是erp的仅在 checkReferer 为true生效
*/
private String erpBaseUrls;
}

View File

@@ -0,0 +1,16 @@
package org.springblade.thirdparty.mk.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 第三方api mk配置类
* @author bfhuange
* @date 2024/9/11
*/
@ComponentScan("org.springblade.thirdparty.mk")
@EnableConfigurationProperties(MKProperties.class)
@Configuration
public class ThirdPartyMKAutoConfiguration {
}

View File

@@ -0,0 +1,73 @@
package org.springblade.thirdparty.mk.constant;
/**
* mk常量类
* @author bfhuange
* @date 2024/9/11
*/
public class MKConstant {
/**
* 获取token 成功状态码
*/
public static final int TOKEN_SUCCESS_CODE = 0;
/**
* mk token缓存key
*/
public static final String MK_TOKEN_KEY = "blade:third:mk:token";
/**
* 组织架构类型: org-机构
*/
public static final String ORG_TYPE_ORG = "org";
/**
* 组织架构类型: dept-部门
*/
public static final String ORG_TYPE_DEPT = "dept";
/**
* 性别 男性 M表示男性F表示女性UN-未知
*/
public static final String SEX_MAN = "M";
/**
* 性别 女性 M表示男性F表示女性UN-未知
*/
public static final String SEX_WOMAN = "F";
/**
* 性别 未知 M表示男性F表示女性UN-未知
*/
public static final String SEX_UNKONW = "UN";
/**
* 操作类型 起草人撤销
*/
public static final String OPERATE_TYPE_REVOKE = "drafter_retract";
/**
* 操作类型 起草人废弃
*/
public static final String OPERATE_TYPE_ABANDON = "drafter_abandon";
/**
* 起草节点id
*/
public static final String DAFTER_NODE_ID = "N2";
/**
* 抄送节点
*/
public static final String NODE_TYPE_SEND = "send";
/**
* 电子签名类型
*/
public static final String FILE_TYPE_SIGN = "electronicSign";
/**
* 排序
*/
public static class Sort {
/**
* 升序
*/
public static final String ASC = "asc";
/**
* 降序
*/
public static final String DESC = "desc";
}
}

View File

@@ -0,0 +1,56 @@
package org.springblade.thirdparty.mk.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 文档类型
* myDraft 我的起草
* myCreated 我发起的
* myCreatedAndDraft 我发起的和我起草的
* myApproving 我的待审
* myApproved 我的已审
* myReading 我的待阅
* myReaded 我的已阅
* myFocus 我关注的
* myAll 我所有的( 含我发起的,我审批的,待我审的)
* @author bfhuange
* @since 2025/4/2
*/
@AllArgsConstructor
@Getter
public enum MKDoc {
/**
* 我的待审
*/
APPROVING("myApproving", "我的待审"),
/**
* 我的已审
*/
APPROVED("myApproved", "我的已审"),
/**
* 我的待阅
*/
READING("myReading", "我的待阅"),
/**
* 我的已阅
*/
READ("myReaded", "我的已阅"),
/**
* 我发起的
*/
CREATE("myCreated", "我发起的"),
/**
* 我参与的
*/
RELATED("myRelated", "我参与的"),
;
/**
* 编码
*/
private final String code;
/**
* 名称
*/
private final String name;
}

View File

@@ -0,0 +1,17 @@
package org.springblade.thirdparty.mk.exception;
/**
* mk 接口异常
* @author bfhuange
* @date 2024/9/13
*/
public class MKException extends RuntimeException {
public MKException(String message) {
super(message);
}
public MKException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,28 @@
package org.springblade.thirdparty.mk.exception;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.utils.Func;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author bfhuange
* @since 2025/3/29
*/
@AllArgsConstructor
@Slf4j
@RestControllerAdvice
public class MKExceptionTranslator {
@ExceptionHandler(MKException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R handleError(MKException e) {
log.error("mk异常", e);
return R.fail(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
}
}

View File

@@ -0,0 +1,170 @@
package org.springblade.thirdparty.mk.feign;
import feign.Response;
import org.springblade.thirdparty.mk.config.MKFeignClientConfig;
import org.springblade.thirdparty.mk.pojo.dto.*;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalDTO;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO;
import org.springblade.thirdparty.mk.pojo.vo.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* MK接口
* @author bfhuange
* @date 2024/9/11
*/
@FeignClient(name = "MK", url = "${thirdParty.mk.baseUrl}", configuration = MKFeignClientConfig.class)
public interface IMKClient {
/**
* 获取mk token
* @param param
* @return
*/
@PostMapping("${thirdParty.mk.getTokenUrl:/authapi/getToken}")
MKTokenVO getToken(@RequestBody MKTokenDTO param);
/**
* 流程提交接口
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.processSubmitUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/submit}")
MKResultVO<String> processSubmit(@RequestBody MKProcessCreateDTO param, @RequestParam("access_token") String accessToken);
/**
* 流程执行接口
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.processExecuteUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}")
MKResultVO<Void> processExecute(@RequestBody MKProcessExecuteDTO param, @RequestParam("access_token") String accessToken);
/**
* 流程删除接口
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.processDeleteUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}")
MKResultVO<Void> processDelete(@RequestBody MKProcessDeleteDTO param, @RequestParam("access_token") String accessToken);
/**
* 获取流程当前节点详情
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.getCurrentNodesUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}")
MKResultVO<List<MKNodeVO>> getCurrentNodes(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
/**
* 获取节点处理人信息
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.getNodeHandlersUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}")
MKResultVO<MKAllHandlerVO> getNodeHandlers(@RequestBody MKNodeHandlersDTO param, @RequestParam("access_token") String accessToken);
/**
* 根据流程模板获取该模板下所有的人工节点信息
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.getManualNodeUrl:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}")
MKResultVO<List<MKManualNodeVO>> getManualNode(@RequestBody MKManualNodeDTO param, @RequestParam("access_token") String accessToken);
//===========================人员组织推送接口============================================
/**
* 推送公司部门
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.pushOrgDeptUrl:/openapi/sys-org/v2/push/orgDept}")
MKResultVO<Object> pushOrgDept(@RequestBody MKPushDTO<MKPushOrgDeptDTO> param, @RequestParam("access_token") String accessToken);
/**
* 推送人员
* @param param
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.pushPersonUrl:/openapi/sys-org/v2/push/person}")
MKResultVO<Object> pushPerson(@RequestBody MKPushDTO<MKPushPersonDTO> param, @RequestParam("access_token") String accessToken);
//===========================认证相关接口========================================
/**
* 获取oauth 认证code
* @param param
*/
@PostMapping("${thirdParty.mk.getOAuthCodeUrl:/openapi/sys-oauth/openOauth/getCode}")
MKResultVO<MKOAuthCodeVO> getOAuthCode(@RequestBody MKOAuthCodeDTO param, @RequestParam("access_token") String accessToken);
/**
* 获取oauth token
* @param param
*/
@PostMapping("${thirdParty.mk.getOAuthTokenUrl:/openapi/sys-oauth/openOauth/getToken}")
MKResultVO<MKOAuthTokenVO> getOAuthToken(@RequestBody MKOAuthTokenDTO param, @RequestParam("access_token") String accessToken);
/**
* 获取oauth 用户信息
* @param param
* @return
*/
@PostMapping("${thirdParty.mk.getOAuthUserInfoUrl:/openapi/sys-oauth/openOauth/getUserInfo}")
MKResultVO<MKOAuthUserVO> getOAuthUserInfo(@RequestBody MKOAuthUserDTO param, @RequestParam("access_token") String accessToken);
//===========================审批记录相关接口========================================
/**
* 流程审批意见信息API - 获取审批意见接口
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.queryAuditNotesUrl:/openapi/sys-lbpm/lbpmAuditNote/openSupport/listNote}")
MKResultVO<List<MKAuditNoteVO>> queryAuditNotes(@RequestBody MKAuditNoteDTO param, @RequestParam("access_token") String accessToken);
/**
* 流程卡片操作API- 获取抄送人列表
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.querySenderListUrl:/openapi/sys-lbpm/sysLbpmProcessCard/openSupport/getSenderList}")
MKResultVO<MKPageVO<MKSenderVO>> querySenderList(@RequestBody MKSenderDTO param, @RequestParam("access_token") String accessToken);
/**
* 附件文件流操作开放API- 附件下载
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.downloadFileUrl:/openapi/sys-attach/fileStream/download}")
Response downloadFile(@RequestBody MKFileDTO param, @RequestParam("access_token") String accessToken);
//===========================待办相关接口========================================
/**
* 审批中心-流程门户API-审批中心查询列表
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.queryApprovalListUrl:/openapi/lbpm-approval/lbpmApproval/portal/list}")
MKResultVO<MKPageVO<MKApprovalVO>> queryApprovalList(@RequestBody MKApprovalDTO param, @RequestParam("access_token") String accessToken);
/**
* 流程实例操作API-列表
* @param accessToken
* @return
*/
@PostMapping("${thirdParty.mk.queryProcessListUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/list}")
MKResultVO<MKPageVO<MKProcessVO>> queryProcessList(@RequestBody MKProcessDTO param, @RequestParam("access_token") String accessToken);
}

View File

@@ -0,0 +1,32 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 附加操作信息
*
* @author linbb
*/
@Data
public class MKAdditionOperationParameterDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 操作类型
*/
private String operationType;
/**
* 操作身份
*/
private String operationIdentity;
/**
* 操作参数
*/
private String parameter;
}

View File

@@ -0,0 +1,26 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/2/24
*/
@AllArgsConstructor
@Data
public class MKAuditNoteDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 登录账号 登录用户账号/手机号
*/
private String loginName;
/**
* 流程实例id
*/
private String processInstanceId;
}

View File

@@ -0,0 +1,25 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk 辅部门参数
* @author bfhuange
* @date 2024/9/24
*/
@Data
public class MKAuxiliaryDeptDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 对象主键
*/
private String fdId;
/**
* 对象显示名
*/
private String fdName;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @date 2024/9/19
*/
@Data
public class MKCurrentNodesDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 登录名
*/
private String loginName;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.thirdparty.mk.pojo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/2/24
*/
@AllArgsConstructor
@Data
public class MKFileDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 附件id
*/
@JsonProperty("fdId")
private String fileId;
}

View File

@@ -0,0 +1,28 @@
package org.springblade.thirdparty.mk.pojo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 人工节点查询参数
* @author bfhuange
* @since 2025/3/21
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class MKManualNodeDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 模板id
*/
@JsonProperty("fdId")
private String templateId;
}

View File

@@ -0,0 +1,28 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @date 2024/9/19
*/
@Data
public class MKNodeHandlersDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 登录名
*/
private String loginName;
/**
* 节点(定义)ID
*/
private String nodeId;
}

View File

@@ -0,0 +1,29 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取oauth 认证code参数
* @author bfhuange
* @date 2024/9/27
*/
@Data
public class MKOAuthCodeDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 申请的应⽤Id 认证
*/
private String appId;
/**
* 应⽤秘钥
*/
private String appSecret;
/**
* 登录名
*/
private String loginName;
}

View File

@@ -0,0 +1,29 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取oauth token参数
* @author bfhuange
* @date 2024/9/14
*/
@Data
public class MKOAuthTokenDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 申请的应⽤Id 认证
*/
private String appId;
/**
* 应⽤秘钥
*/
private String appSecret;
/**
* 授权codecode使⽤⼀次之后失效
*/
private String code;
}

View File

@@ -0,0 +1,23 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk oauth 获取用户信息参数
* @author bfhuange
* @date 2024/9/14
*/
@AllArgsConstructor
@Data
public class MKOAuthUserDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* token
*/
private String token;
}

View File

@@ -0,0 +1,25 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk 分页参数
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKPageDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 从第?条开始查询起始值为0
*/
private Integer offset = 0;
/**
* 每页?条
*/
private Integer pageSize = 20;
}

View File

@@ -0,0 +1,47 @@
package org.springblade.thirdparty.mk.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk 流程创建参数
* @author bfhuange
* @date 2024/9/11
*/
@Data
public class MKProcessCreateDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 表单实例id业务id
*/
private String formInstanceId;
/**
* 标题
*/
private String subject;
/**
* 提交人 登录用户账号/手机号
*/
private String submitIdentity;
/**
* 登录账号 登录用户账号/手机号
*/
private String loginName;
/**
* 模板编码 ProcessTypeEnum#templateCode
*/
private String templateCode;
/**
* 默认表单值
*/
private Object formValues;
/**
* 临时变量
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object tempVarData;
}

View File

@@ -0,0 +1,25 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk 流程删除参数
* @author bfhuange
* @since 2024/11/26
*/
@Data
public class MKProcessDeleteDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 登录账号 登录用户账号/手机号
*/
private String loginName;
/**
* 流程实例id
*/
private String processInstanceId;
}

View File

@@ -0,0 +1,79 @@
package org.springblade.thirdparty.mk.pojo.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 流程执行参数
* @author bfhuange
* @date 2024/9/26
*/
@Data
public class MKProcessExecuteDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 表单实例id业务id
*/
private String formInstanceId;
/**
* 登录账号 登录用户账号/手机号
*/
private String loginName;
/**
* 操作类型
*/
private String operationType;
//==========================mk 流程执行需要的参数,前端透传=========================
/**
* 流程标题
*/
private String subject;
/**
* 任务ID
*/
private String taskId;
/**
* 任务类型
*/
private String activityType;
/**
* 操作详细参数(json)
*/
private String parameter;
/**
* 流程实例ID
*/
private String processId;
/**
* 操作标识(相同操作类型和相同操作身份可能存在多个操作配置)
*/
private String operationId;
/**
* 操作身份
*/
private String operationIdentity;
/**
* 附加操作参数信息
*/
private List<MKAdditionOperationParameterDTO> additionParameters;
/**
* 表单实例Model Name
*/
private String formInstanceModel;
/**
* 业务表单字段值集合
*/
// private Map<String, Object> formValues;
private Object formValues;
/**
* 临时变量
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object tempVarData;
}

View File

@@ -0,0 +1,30 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 推送参数
* @author bfhuange
* @date 2024/9/24
*/
@Data
public class MKPushDTO<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 如果不传默认一次性推送mk这边生成批次如果一定量数据分页推送则第三方生成批次号批次号唯一
*/
private String batchId;
/**
* 结束标识 true-当前推送完毕false-还没推送完成。一次性推送的话,就传 true
*/
private boolean finish = true;
/**
* 推送的数据主体
*/
private List<T> message;
}

View File

@@ -0,0 +1,144 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 推送机构部门参数
* @author bfhuange
* @date 2024/9/24
*/
@Data
public class MKPushOrgDeptDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
//=================必填项开始================
/**
* 唯一标识 必填不能保证唯一的情况下建议id前面拼接上组织类型。 例org:1111dept:22222,person:333333,group:555555,post:6666666 进阶情况组织来源多个不同系统还可以拼接上来源系统唯一id
*/
private String fdId;
/**
* 是否有效,该属性决定该组织架构是否删除 必填
*/
private Boolean fdIsAvailable;
/**
* 名称 必填
*/
private String fdName;
/**
* 组织架构类型: org-机构,dept-部门
*/
private String fdOrgType;
/**
* 来源系统标识:例如EKP
*/
private String fdSourceSystem;
//=================必填项结束================
/**
* 所在部门-主部门只能一个有值情况当type为org,dept,post,person时为空表示在根节点
*/
private String fdParent;
/**
* 编号
*/
private String fdNo;
/**
* 排序号
*/
private Integer fdOrder;
/**
* 映射MK的fdId,用来和Mk数据进行绑定
*/
private String fdElementId;
/**
* 指定同步到mk的哪个节点下有parent则以parent为准没有则以mkParent为准。只能选择机构和部门同步对象如果是机构则mkParent也只能是机构机构不能挂部门下
*/
private String mkParent;
/**
* 部门领导有值情况当type为org,dept,post
*/
private String fdThisLeader;
/**
* 置空属性:字段传空过来不想Mk这边也更新为空可以指定这个属性。包含的字段如果为空则会被置为空不包含的如果为空则不会更新。例如["fdName","fdNo","fdEmail"]
*/
private List<String> nullValueProps;
//=======================一般不用的字段开始=========================
/**
* 机构简称
*/
private String fdAbbreviation;
/**
* 地址1
*/
private String fdAddress1;
/**
* 地址2
*/
private String fdAddress2;
/**
* 管理员,例:["113","43424",..]
*/
private List<String> fdAdmins;
/**
* 营业执照编号
*/
private String fdBusinessLicenseNo;
/**
* 群组分类id有值情况当type为group时
*/
private String fdCategoryName;
/**
* 扩展属性未定义的字段并且需要同步的可以传到此json对象中同步前需要去后台管理增加对应key值的扩展字段。例{"birthDate":"19000101","education":"本科","isSocialRecruitment":"true"}
*/
private Object fdCustomProps;
/**
* 说明
*/
private String fdDesc;
/**
* 外部组织显示位置:默认情况是内部组织都在行政组织树外部组织都在生态组织树。组织架构开启一体化后外部组织既可以出现在行政树下面也可以出现在生态组织树下。但行政里面的外部组织必须要有顶级机构。是否显示在生态组织目录true/null-显示在生态组织目录false-显示在行政组织
*/
private Boolean fdEosShowType;
/**
* 外部组织分类codeMK有外部组织分类需要提前在管理端建好
*/
private String fdExternalCode;
/**
* 是否外部组织默认不填表示内部组织true表示外部组织外部组织需要externalCode
*/
private Boolean fdIsExternal;
/**
* 关键字
*/
private String fdKeyword;
/**
* 多语言字段:例:{"fdNameUs":"Tom","fdNameCn":"张三"}
*/
private Object fdLangProps;
/**
* 是否法人
*/
private Boolean fdLegalPerson;
/**
* 上级领导有值情况当type为org,dept
*/
private String fdSuperLeader;
/**
* 多维分类编号当fdOrgType为org(机构),dept(部门) 时生效,表示当前组织/部门是该多维分类下的顶层组织。注:后续不允许变更。
*/
private String fdVirtualizeNo;
/**
* 可见性fdVisibleType:1-仅自己 2-所在组织同级及下级 3-指定组织/人员:例: {"fdVisibleType":1,"visibleOrgList":[{"fdId":"1feiglp6sw132weiw37cucsm1kqoe29hu4w0","fdName":"刘芬"}]}
*/
private Object fdVisible;
/**
* 机构网站地址
*/
private String fdWebAddress;
}

View File

@@ -0,0 +1,167 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 推送人员参数
* @author bfhuange
* @date 2024/9/24
*/
@Data
public class MKPushPersonDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
//=================必填项开始================
/**
* 唯一标识 必填不能保证唯一的情况下建议id前面拼接上组织类型。 例org:1111dept:22222,person:333333,group:555555,post:6666666 进阶情况组织来源多个不同系统还可以拼接上来源系统唯一id
*/
private String fdId;
/**
* 是否有效,该属性决定该组织架构是否删除 必填
*/
private Boolean fdIsAvailable;
/**
* 组织类型为用户时,登录名,有此信息且必填
*/
private String fdLoginName;
/**
* 名称 必填
*/
private String fdName;
/**
* 来源系统标识:例如EKP
*/
private String fdSourceSystem;
//=================必填项结束================
/**
* 辅部门,可以多个,只有用户才传此值,不能和主部门重复:例:[{"fdId":"222222222","fdName":"A部门"},{"fdId":"333333333","fdName":"B部门"}]
*/
private List<MKAuxiliaryDeptDTO> fdAuxiliaryDept;
/**
* 映射MK的fdId,用来和Mk数据进行绑定
*/
private String fdElementId;
/**
* 手机号
*/
private String fdMobileNo;
/**
* 编号
*/
private String fdNo;
/**
* 所在部门-主部门只能一个有值情况当type为org,dept,post,person时为空表示在根节点
*/
private String fdParent;
/**
* 排序号
*/
private Integer fdOrder;
/**
* 密码,Md5加密后的信息可以为空
*/
private String fdPassword;
/**
* 性别M表示男性F表示女性UN-未知
*/
private String fdSex;
/**
* 指定同步到mk的哪个节点下有parent则以parent为准没有则以mkParent为准。只能选择机构和部门同步对象如果是机构则mkParent也只能是机构机构不能挂部门下
*/
private String mkParent;
/**
* 置空属性:字段传空过来不想Mk这边也更新为空可以指定这个属性。包含的字段如果为空则会被置为空不包含的如果为空则不会更新。例如["fdName","fdNo","fdEmail"]
*/
private List<String> nullValueProps;
//=======================一般不用的字段开始=========================
/**
* 群组分类id有值情况当type为group时
*/
private String fdCategoryName;
/**
* 扩展属性未定义的字段并且需要同步的可以传到此json对象中同步前需要去后台管理增加对应key值的扩展字段。例{"birthDate":"19000101","education":"本科","isSocialRecruitment":"true"}
*/
private Object fdCustomProps;
/**
* 默认语言
*/
private String fdDefaultLang;
/**
* 说明
*/
private String fdDesc;
/**
* 邮件地址
*/
private String fdEmail;
/**
* 外部组织显示位置:默认情况是内部组织都在行政组织树外部组织都在生态组织树。组织架构开启一体化后外部组织既可以出现在行政树下面也可以出现在生态组织树下。但行政里面的外部组织必须要有顶级机构。是否显示在生态组织目录true/null-显示在生态组织目录false-显示在行政组织
*/
private Boolean fdEosShowType;
/**
* 外部组织分类codeMK有外部组织分类需要提前在管理端建好
*/
private String fdExternalCode;
/**
* 是否外部组织默认不填表示内部组织true表示外部组织外部组织需要externalCode
*/
private Boolean fdIsExternal;
/**
* 关键字
*/
private String fdKeyword;
/**
* 多语言字段:例:{"fdNameUs":"Tom","fdNameCn":"张三"}
*/
private Object fdLangProps;
/**
* 职级名称
*/
private String fdLevelName;
/**
* 职级oriId
*/
private String fdLevelOriId;
/**
* 主岗,只有一个
*/
private String fdMainPost;
/**
* 昵称
*/
private String fdNickName;
/**
* 辅岗,可以多个,例:["cbda73","bac67843"..]
*/
private List<String> fdPosts;
/**
* 短号
*/
private String fdShortNo;
/**
* 职务名称
*/
private String fdStaffingLevelName;
/**
* 职务oriId
*/
private String fdStaffingLevelOriId;
/**
* 多维分类编号当fdOrgType为org(机构),dept(部门) 时生效,表示当前组织/部门是该多维分类下的顶层组织。注:后续不允许变更。
*/
private String fdVirtualizeNo;
/**
* 可见性fdVisibleType:1-仅自己 2-所在组织同级及下级 3-指定组织/人员:例: {"fdVisibleType":1,"visibleOrgList":[{"fdId":"1feiglp6sw132weiw37cucsm1kqoe29hu4w0","fdName":"刘芬"}]}
*/
private Object fdVisible;
/**
* 办公电话
*/
private String fdWorkPhone;
}

View File

@@ -0,0 +1,26 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author bfhuange
* @since 2025/2/24
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class MKSenderDTO extends MKPageDTO {
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 节点实例id
*/
private String nodeInstanceId;
public MKSenderDTO(String processInstanceId, String nodeInstanceId) {
this.processInstanceId = processInstanceId;
this.nodeInstanceId = nodeInstanceId;
}
}

View File

@@ -0,0 +1,25 @@
package org.springblade.thirdparty.mk.pojo.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取token参数
* @author bfhuange
* @date 2024/9/11
*/
@Data
public class MKTokenDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用key
*/
private String appKey;
/**
* 应用secret
*/
private String appSecret;
}

View File

@@ -0,0 +1,86 @@
package org.springblade.thirdparty.mk.pojo.dto.approval;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import org.springblade.thirdparty.mk.support.MultiKeySerializer;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk审批中心查询条件
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKApprovalConditionDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 单据类型
*/
private MKConditionDTO mydoc;
/**
* 关键字
*/
@JsonSerialize(using = MultiKeySerializer.class)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<MKConditionDTO> keyword;
/**
* 申请时间
*/
@JsonProperty("fdStartTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO startTime;
/**
* 接收时间
*/
@JsonProperty("fdReceiveTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO receiveTime;
/**
* 模板名称
*/
@JsonProperty("fdTemplateName")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO templateName;
//======================已处理参数================================
/**
* 流程状态
*/
@JsonProperty("fdStatus")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO status;
/**
* 任务结束时间
*/
@JsonProperty("fdFinishTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO finishTime;
/**
* 最后处理时间(待审任务)
*/
@JsonProperty("fdLastHandleTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO lastHandleTime;
//======================已阅参数================================
/**
* 阅读时间
*/
@JsonProperty("fdReadTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO readTime;
//======================我参与的参数================================
/**
* 创建时间
*/
@JsonProperty("fdCreateTime")
@JsonInclude(JsonInclude.Include.NON_NULL)
private MKConditionDTO createTime;
}

View File

@@ -0,0 +1,70 @@
package org.springblade.thirdparty.mk.pojo.dto.approval;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import org.springblade.thirdparty.mk.pojo.dto.sort.ISort;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk审批中心查询参数
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKApprovalDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 查询条件
*/
private MKApprovalConditionDTO conditions;
/**
* 登录名
*/
private String loginName;
/**
* 获取内容
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean content;
/**
* 获取条目数
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean count;
/**
* 获取总数时最大条目数
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer maxCount;
/**
* 从第?条开始查询起始值为0
*/
private Integer offset;
/**
* 第?页
*/
private Integer pageNo;
/**
* 每页?条
*/
private Integer pageSize;
/**
* 排序列
*/
private ISort sorts;
/**
* 返回列
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<String> columns;
public void setPage(Integer pageNo, Integer pageSize) {
this.pageNo = pageNo;
this.pageSize = pageSize;
this.offset = (this.pageNo -1) * this.pageSize;
}
}

View File

@@ -0,0 +1,50 @@
package org.springblade.thirdparty.mk.pojo.dto.approval;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 条件
* @author bfhuange
* @since 2025/4/2
*/
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class MKConditionDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 相等
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonProperty("$eq")
private String eq;
/**
* 大于等于
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonProperty("$gte")
private String gte;
/**
* 小于等于
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonProperty("$lte")
private String lte;
/**
* 包含
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonProperty("$contains")
private String contains;
}

View File

@@ -0,0 +1,124 @@
package org.springblade.thirdparty.mk.pojo.dto.approval;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk流程列表查询参数
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKProcessDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 登录名
*/
private String loginName;
/**
* 查询数据模型 myAll(我的所有),myCreated(我创建的),myApproving(我的待办),myApproved(我的已办),myFollowed(我跟踪的),myReading(我待阅读),myReaded(我已阅读),myTransfer(我的转办),myCommunicate(我的沟通),myAuthorization(我的授权),my,myManage(我有特权人权限的)
*/
private String mydoc;
/**
* 流程状态
*/
private String status;
/**
* 搜索关键字
*/
private String keyword;
/**
* 创建时间:起始
*/
private Long createBeginTime;
/**
* 创建时间:截止
*/
private Long createEndTime;
/**
* 处理时间筛选(开始)
*/
@JsonProperty("fdHandleStartTime")
private Long handleStartTime;
/**
* 处理时间筛选(结束)
*/
@JsonProperty("fdHandleEndTime")
private Long handleEndTime;
/**
* 阅读时间筛选(开始)
*/
@JsonProperty("fdReadStartTime")
private Long readStartTime;
/**
* 阅读时间筛选(结束)
*/
@JsonProperty("fdReadEndTime")
private Long readEndTime;
/**
* 接收时间筛选(开始)
*/
@JsonProperty("fdReceiveStartTime")
private Long receiveStartTime;
/**
* 接收时间筛选(结束)
*/
@JsonProperty("fdReceiveEndTime")
private Long receiveEndTime;
/**
* 当前处理人 ','隔开, 支持Mk系统的组织架构id和loginName
*/
private String curHandlerIds;
/**
* 当前节点名称
*/
@JsonProperty("fdCurNodeName")
private String curNodeName;
/**
* 创建人, 支持Mk系统的组织架构id和loginName
*/
@JsonProperty("fdCreator")
private String creator;
/**
* 从第?条开始查询起始值为0
*/
private Integer offset;
/**
* 第?页
*/
private Integer pageNo;
/**
* 每页?条
*/
private Integer pageSize;
/**
* 创建时间正序(true)/倒序(false)
*/
private Boolean asc = false;
/**
* 阅读时间正序(true)/倒序(false)
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean readTimeAsc;
/**
* 接收时间正序(true)/倒序(false)
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean receiveTimeAsc;
/**
* 处理时间正序(true)/倒序(false)
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean handleTimeAsc;
public void setPage(Integer pageNo, Integer pageSize) {
this.pageNo = pageNo;
this.pageSize = pageSize;
this.offset = (this.pageNo -1) * this.pageSize;
}
}

View File

@@ -0,0 +1,8 @@
package org.springblade.thirdparty.mk.pojo.dto.sort;
/**
* @author bfhuange
* @since 2025/4/2
*/
public interface ISort {
}

View File

@@ -0,0 +1,24 @@
package org.springblade.thirdparty.mk.pojo.dto.sort;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springblade.thirdparty.mk.constant.MKConstant;
import java.io.Serial;
import java.io.Serializable;
/**
* 已处理排序
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKApprovedSortDTO implements Serializable, ISort {
@Serial
private static final long serialVersionUID = 1L;
/**
* 结束时间
*/
@JsonProperty("fdFinishTime")
private String finishTime = MKConstant.Sort.DESC;
}

View File

@@ -0,0 +1,29 @@
package org.springblade.thirdparty.mk.pojo.dto.sort;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springblade.thirdparty.mk.constant.MKConstant;
import java.io.Serial;
import java.io.Serializable;
/**
* 待处理、待阅排序
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKApprovingSortDTO implements Serializable, ISort {
@Serial
private static final long serialVersionUID = 1L;
/**
* 级别
*/
@JsonProperty("fdLevel")
private String level = MKConstant.Sort.ASC;
/**
* 接收时间
*/
@JsonProperty("fdReceiveTime")
private String receiveTime = MKConstant.Sort.DESC;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.thirdparty.mk.pojo.dto.sort;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springblade.thirdparty.mk.constant.MKConstant;
import java.io.Serial;
import java.io.Serializable;
/**
* 我发起的排序
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKCreateSortDTO implements Serializable, ISort {
@Serial
private static final long serialVersionUID = 1L;
/**
* 创建时间
*/
@JsonProperty("fdCreateTime")
private String createTime = MKConstant.Sort.DESC;
}

View File

@@ -0,0 +1,24 @@
package org.springblade.thirdparty.mk.pojo.dto.sort;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springblade.thirdparty.mk.constant.MKConstant;
import java.io.Serial;
import java.io.Serializable;
/**
* 已阅排序
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKReadSortDTO implements Serializable, ISort {
@Serial
private static final long serialVersionUID = 1L;
/**
* 已读时间
*/
@JsonProperty("fdReadTime")
private String readTime = MKConstant.Sort.DESC;
}

View File

@@ -0,0 +1,29 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author bfhuange
* @date 2024/9/20
*/
@Data
public class MKAllHandlerVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 已审批的处理人
*/
private List<MKApprovedHandlerVO> approvedHandlers;
/**
* 审批中的处理人
*/
private List<Object> approvingHandlers;
/**
* 解析的处理人
*/
private List<Object> parseHandlers;
}

View File

@@ -0,0 +1,153 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKApprovalVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@JsonProperty("fdId")
private String id;
/**
* 流程所属应用
*/
@JsonProperty("fdAppName")
private String appName;
/**
* 申请人名称
*/
@JsonProperty("fdApplicantName")
private String applicantName;
/**
* 申请人登录名
*/
@JsonProperty("fdApplicantLoginName")
private String applicantLoginName;
/**
* 发起人名称
*/
@JsonProperty("fdCreator")
private String creator;
/**
* 处理人名称
*/
@JsonProperty("fdHandlerName")
private String handlerName;
/**
* 当前处理人名称
*/
@JsonProperty("fdCurrentHandler")
private String currentHandler;
/**
* 处理人登录名
*/
@JsonProperty("fdHandlerLoginName")
private String handlerLoginName;
/**
* 节点名称
*/
@JsonProperty("fdNodeName")
private String nodeName;
/**
* 流程id
*/
@JsonProperty("fdProcessId")
private String processId;
/**
* 创建时间
*/
@JsonProperty("fdCreateTime")
private Date createTime;
/**
* 流程发起时间
*/
@JsonProperty("fdStartTime")
private Date startTime;
/**
* 如果是待办:待办接收时间 如果是待阅:传阅接收时间
*/
@JsonProperty("fdReceiveTime")
private Date receiveTime;
/**
* 任务结束时间
*/
@JsonProperty("fdFinishTime")
private Date finishTime;
/**
* 阅读时间(待阅任务)
*/
@JsonProperty("fdReadTime")
private Date readTime;
/**
* 最后处理时间(待审任务)
*/
@JsonProperty("fdLastHandleTime")
private Date lastHandleTime;
/**
* 流程结束时间
*/
@JsonProperty("fdProcessFinishTime")
private Date processFinishTime;
/**
* 流程状态 00 废弃、10 草稿、11 驳回 20 待审、21 异常、40 挂起 30 结束
*/
@JsonProperty("fdStatus")
private String status;
/**
* 流程主题
*/
@JsonProperty("fdSubject")
private String subject;
/**
* 模板编码
*/
@JsonProperty("fdTemplateCode")
private String templateCode;
/**
* 任务id
*/
@JsonProperty("fdTaskId")
private String taskId;
/**
* 任务状态 20 - 激活、30 - 结束、40 - 挂起、50 - 自动跳过
*/
@JsonProperty("fdTaskStatus")
private String taskStatus;
/**
* 任务标题
*/
@JsonProperty("fdTaskSubject")
private String taskSubject;
/**
* 催办标记
*/
@JsonProperty("fdUrgeTab")
private String urgeTab;
/**
* 任务类型 1待办,2待阅
*/
@JsonProperty("fdTaskType")
private Integer taskType;
/**
* 待办优先级
*/
@JsonProperty("fdLevel")
private Integer level;
/**
* 动态扩展属性
*/
private MKDynamicPropsVO dynamicProps;
}

View File

@@ -0,0 +1,33 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author bfhuange
* @date 2024/9/20
*/
@Data
public class MKApprovedHandlerVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 名称
*/
private String name;
/**
* 登录名
*/
private String loginName;
/**
* 操作时间
*/
private Date operationTime;
/**
* 操作名称
*/
private String operationName;
}

View File

@@ -0,0 +1,32 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKAttachmentVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private String id;
/**
* 附件名称
*/
private String name;
/**
* 附件类型 electronicSign 电子签名attachment 附件
*/
private String type;
/**
* 附件ID
*/
private String fileId;
}

View File

@@ -0,0 +1,102 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKAuditNoteVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 记录主键
*/
@JsonProperty("fdId")
private String id;
/**
* 处理人
*/
@JsonProperty("fdHandler")
private String handler;
/**
* 操作
*/
@JsonProperty("fdAction")
private String action;
/**
* 操作编码
*/
@JsonProperty("fdActionCode")
private String actionCode;
/**
* 操作描述(系统操作)
*/
@JsonProperty("fdActionDesc")
private String actionDesc;
/**
* 操作名称
*/
@JsonProperty("fdActionName")
private String actionName;
/**
* 处理意见
*/
@JsonProperty("fdMessage")
private String message;
/**
* 创建时间
*/
@JsonProperty("fdCreateTime")
private Date createTime;
/**
* 流程实例id
*/
@JsonProperty("fdProcessInstanceId")
private String processInstanceId;
/**
* 节点实例id
*/
@JsonProperty("fdNodeInstanceId")
private String nodeInstanceId;
/**
* 节点类型
*/
@JsonProperty("fdNodeType")
private String nodeType;
/**
* 节点id
*/
@JsonProperty("fdNodeId")
private String nodeId;
/**
* 节点名称
*/
@JsonProperty("fdNodeName")
private String nodeName;
/**
* 节点编号
*/
@JsonProperty("fdNodeNumber")
private String nodeNumber;
/**
* 附件参数
*/
private List<MKAttachmentVO> attachmentParameter;
/**
* 流程附言
*/
@JsonProperty("lbpmCommentPostscriptVOS")
private List<MKProcessCommentVO> processComments;
/**
* 机制数据
*/
private MKMechanismsVO mechanisms;
}

View File

@@ -0,0 +1,23 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKDynamicPropsVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 模板名称中文
*/
@JsonProperty("fdTemplateNameCn")
private String templateNameCn;
}

View File

@@ -0,0 +1,30 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk 返回结果错误堆栈
* @author bfhuange
* @date 2024/9/24
*/
@Data
public class MKErrorVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 服务名称
*/
private String app;
/**
* 错误编码
*/
private String code;
/**
* 错误描述
*/
private String message;
}

View File

@@ -0,0 +1,33 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 人工节点
* @author bfhuange
* @since 2025/3/21
*/
@Data
public class MKManualNodeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 节点id
*/
private String nodeId;
/**
* 节点名称
*/
private String nodeName;
/**
* 节点编号
*/
private String nodeNumber;
/**
* 节点类型
*/
private String nodeType;
}

View File

@@ -0,0 +1,21 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author bfhuange
* @since 2025/2/25
*/
@Data
public class MKMechanismsVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 附件信息
*/
private List<MKMetaAttachmentVO> attachment;
}

View File

@@ -0,0 +1,31 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/2/25
*/
@Data
public class MKMetaAttachmentVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@JsonProperty("fdId")
private String id;
/**
* 附件名称
*/
@JsonProperty("fdFileName")
private String fileName;
/**
* 附件全名
*/
private String fullName;
}

View File

@@ -0,0 +1,20 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @date 2024/9/20
*/
@Data
public class MKNodeHandlerOrgVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 登录名
*/
private String loginName;
}

View File

@@ -0,0 +1,29 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author bfhuange
* @date 2024/9/20
*/
@Data
public class MKNodeHandlerVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 处理人名称
*/
private String handlerName;
/**
* 接收时间
*/
private Date receiveTime;
/**
* 处理人组织信息
*/
private MKNodeHandlerOrgVO fdHandlerOrgInfo;
}

View File

@@ -0,0 +1,42 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 节点信息
* @author bfhuange
* @date 2024/9/20
*/
@Data
public class MKNodeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 节点id
*/
private String nodeId;
/**
* 节点名称
*/
private String nodeName;
/**
* 节点编号
*/
private String nodeNumber;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 节点实例id
*/
private String nodeInstanceId;
/**
* 节点处理人
*/
private List<MKNodeHandlerVO> nodeHandlers;
}

View File

@@ -0,0 +1,21 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk oauth 认证code响应参数
* @author bfhuange
* @date 2024/9/27
*/
@Data
public class MKOAuthCodeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 会话code
*/
private String code;
}

View File

@@ -0,0 +1,21 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk oauth token响应参数
* @author bfhuange
* @date 2024/9/14
*/
@Data
public class MKOAuthTokenVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* token
*/
private String token;
}

View File

@@ -0,0 +1,33 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* mk oauth 用户信息
* @author bfhuange
* @date 2024/9/14
*/
@Data
public class MKOAuthUserVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 登录名
*/
private String loginName;
/**
* ⽤户名
*/
private String name;
/**
* 编号信息
*/
private String fdNo;
/**
* 部⻔信息
*/
private String deptName;
}

View File

@@ -0,0 +1,50 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
/**
* @author bfhuange
* @since 2025/2/24
*/
@NoArgsConstructor
@Data
public class MKPageVO<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分页位移量
*/
private Integer offset;
/**
* 每页数目
*/
private Integer pageSize;
/**
* 总数
*/
private Integer totalSize;
/**
* 返回内容
*/
private List<T> content;
public MKPageVO(Integer totalSize) {
this.totalSize = totalSize;
this.content = Collections.emptyList();
}
/**
* 空的结果
* @return
* @param <T>
*/
public static <T> MKPageVO<T> empty() {
return new MKPageVO<>(0);
}
}

View File

@@ -0,0 +1,51 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 流程附言
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKProcessCommentVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private String id;
/**
* 附言内容
*/
private String content;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 用户id
*/
private String userId;
/**
* 处理人信息
*/
private MKUserOrgVO userOrgInfo;
/**
* 附言附件
*/
private List<MKAttachmentVO> attachments;
/**
* 机制数据
*/
private MKMechanismsVO mechanisms;
}

View File

@@ -0,0 +1,94 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author bfhuange
* @since 2025/4/2
*/
@Data
public class MKProcessVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@JsonProperty("fdId")
private String id;
/**
* 发起人名称
*/
@JsonProperty("fdCreator")
private String creator;
/**
* 当前处理人名称
*/
@JsonProperty("fdCurrentHandler")
private String currentHandler;
/**
* 当前节点 - 仅我参与的
*/
@JsonProperty("fdCurrentNode")
private String currentNode;
/**
* 流程id
*/
@JsonProperty("fdProcessId")
private String processId;
/**
* 创建时间
*/
@JsonProperty("fdCreateTime")
private Date createTime;
/**
* 如果是待办:待办接收时间 如果是待阅:传阅接收时间
*/
@JsonProperty("fdReceiveTime")
private Date receiveTime;
/**
* 阅读时间(待阅任务)
*/
@JsonProperty("fdReadTime")
private Date readTime;
/**
* 最后处理时间(待审任务)
*/
@JsonProperty("fdLastHandleTime")
private Date lastHandleTime;
/**
* 流程结束时间
*/
@JsonProperty("fdProcessFinishTime")
private Date processFinishTime;
/**
* 流程状态 00 废弃、10 草稿、11 驳回 20 待审、21 异常、40 挂起 30 结束
*/
@JsonProperty("fdStatus")
private String status;
/**
* 流程主题
*/
@JsonProperty("fdSubject")
private String subject;
/**
* 模板编码
*/
@JsonProperty("fdTemplateCode")
private String templateCode;
/**
* 模板名称 - 仅我参与的
*/
@JsonProperty("fdTemplateName")
private String templateName;
/**
* 催办标记
*/
@JsonProperty("fdUrgeTab")
private String urgeTab;
}

View File

@@ -0,0 +1,42 @@
package org.springblade.thirdparty.mk.pojo.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* mk 返回结果
* @author bfhuange
* @date 2024/9/11
*/
@Data
public class MKResultVO<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 是否成功
*/
private boolean success;
/**
* 响应码
*/
private String code;
/**
* 消息
*/
private String msg;
/**
* traceId
*/
private String traceId;
/**
* 数据
*/
private T data;
/**
* 错误堆栈
*/
private List<MKErrorVO> errStacks;
}

View File

@@ -0,0 +1,27 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 抄送人
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKSenderVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
private String id;
/**
* 处理人名称
*/
@JsonProperty("fdName")
private String name;
}

View File

@@ -0,0 +1,32 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @date 2024/9/11
*/
@Data
public class MKTokenVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* token
*/
@JsonProperty("access_token")
private String accessToken;
/**
* 过期时间
*/
@JsonProperty("expires_in")
private int expiresIn;
/**
* 错误码
*/
@JsonProperty("errcode")
private int errCode;
}

View File

@@ -0,0 +1,22 @@
package org.springblade.thirdparty.mk.pojo.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author bfhuange
* @since 2025/2/24
*/
@Data
public class MKUserOrgVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 名称
*/
@JsonProperty("fdName")
private String name;
}

View File

@@ -0,0 +1,148 @@
package org.springblade.thirdparty.mk.service;
import jakarta.servlet.http.HttpServletResponse;
import org.springblade.thirdparty.mk.pojo.dto.*;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalDTO;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO;
import org.springblade.thirdparty.mk.pojo.vo.*;
import java.util.List;
/**
* @author bfhuange
* @date 2024/9/11
*/
public interface IMKService {
/**
* 提交流程
* @param param
* @return
*/
String processSubmit(MKProcessCreateDTO param);
/**
* 执行流程
* @param param
* @return
*/
boolean processExecute(MKProcessExecuteDTO param);
/**
* 撤回流程,起草人撤回
* @param bizId
* @param loginName MK要的是手机号,不是登录名
* @return
*/
boolean processRevoke(String bizId, String loginName);
/**
* 删除流程
* @param processInstanceId 流程实例id
* @param loginName MK要的是手机号,不是登录名
* @return
*/
boolean processDelete(String processInstanceId, String loginName);
/**
* 废弃流程,起草人废弃
* @param bizId 业务id
* @param loginName MK要的是手机号,不是登录名
* @return
*/
boolean processAbandon(String bizId, String loginName);
/**
* 根据 mk code 获取mk账号
* @param mkCode
* @return
*/
String getMKAccount(String mkCode);
/**
* 获取流程当前节点详情
* @param processInstanceId
* @param loginName
* @return
*/
List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName);
/**
* 获取节点处理人信息
* @param processInstanceId
* @param loginName
* @param nodeId
* @return
*/
MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId);
/**
* 推送机构部门
* @param param
* @return
*/
boolean pushOrgDept(MKPushDTO<MKPushOrgDeptDTO> param);
/**
* 推送人员
* @param param
* @return
*/
boolean pushPerson(MKPushDTO<MKPushPersonDTO> param);
/**
* 获取mk审批链接
* @param processInstanceId
* @param loginName
* @return
*/
String getMKApprovalUrl(String processInstanceId, String loginName);
/**
* 查询流程审批记录
* @param param
* @return
*/
List<MKAuditNoteVO> queryAuditNotes(MKAuditNoteDTO param);
/**
* 查询抄送人列表
* @param param
* @return
*/
List<MKSenderVO> querySenderList(MKSenderDTO param);
/**
* 下载文件
* @param response
* @param fileId
*/
void downloadFile(HttpServletResponse response, String fileId);
/**
* 下载文件
* @param fileId
*/
String getFileBase64(String fileId);
/**
* 根据流程模板id和节点id查询节点编号
* @param templateId
* @param nodeId
* @return
*/
String getNodeNumber(String templateId, String nodeId);
/**
* 查询审批中心列表
* @param param
* @return
*/
MKPageVO<MKApprovalVO> queryApprovalList(MKApprovalDTO param);
/**
* 查询流程列表,我参与的 待办
* @param param
* @return
*/
MKPageVO<MKProcessVO> queryProcessList(MKProcessDTO param);
}

View File

@@ -0,0 +1,508 @@
package org.springblade.thirdparty.mk.service.impl;
import cn.hutool.json.JSONUtil;
import feign.Response;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.UrlUtil;
import org.springblade.thirdparty.mk.config.MKProperties;
import org.springblade.thirdparty.mk.constant.MKConstant;
import org.springblade.thirdparty.mk.exception.MKException;
import org.springblade.thirdparty.mk.feign.IMKClient;
import org.springblade.thirdparty.mk.pojo.dto.*;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalDTO;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO;
import org.springblade.thirdparty.mk.pojo.vo.*;
import org.springblade.thirdparty.mk.service.IMKService;
import org.springblade.thirdparty.mk.util.AssertUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author bfhuange
* @date 2024/9/11
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class MKServiceImpl implements IMKService {
/**
* mk审批页面链接
*/
private static final String APPROVAL_URL_FORMAT = "%s/web//#/current/sys-lbpm/lbpmIntegrate/formInFlow/view/%s?processInstanceId=%s";
/**
* mk sso回调地址
*/
private static final String SSO_CALLBACK_URL_FORMAT = "%s/data/sys-auth/ssoCallBack?mkCode=%s&redirectUrl=%s";
private final MKProperties properties;
private final IMKClient client;
private final BladeRedis bladeRedis;
@Override
public String processSubmit(MKProcessCreateDTO param) {
if (param == null) {
log.warn("调用mk接口 创建并提交流程参数为空");
return null;
}
return commonCall("创建并提交流程", token -> {
// 设置标题
String actualSubject = getActualSubject(param.getSubject());
param.setSubject(actualSubject);
log.info("调用mk提交流程开始");
long start = System.currentTimeMillis();
MKResultVO<String> result = client.processSubmit(param, token);
long end = System.currentTimeMillis();
log.info("调用mk提交流程结束 耗时:{}", end - start);
return result;
}, result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.orElse(null)
);
}
@Override
public boolean processExecute(MKProcessExecuteDTO param) {
if (param == null) {
log.warn("调用mk接口 执行流程参数为空");
return false;
}
return commonCall("执行流程", token -> client.processExecute(param, token));
}
@Override
public boolean processRevoke(String bizId, String loginName) {
if (StringUtil.isBlank(bizId) || StringUtil.isBlank(loginName)) {
log.warn("调用mk接口 撤回流程参数为空");
return false;
}
return commonCall("撤回流程", token -> {
MKProcessExecuteDTO param = new MKProcessExecuteDTO();
param.setFormInstanceId(bizId);
param.setLoginName(loginName);
param.setOperationType(MKConstant.OPERATE_TYPE_REVOKE);
return client.processExecute(param, token);
});
}
@Override
public boolean processDelete(String processInstanceId, String loginName) {
if (StringUtil.isBlank(processInstanceId) || StringUtil.isBlank(loginName)) {
log.warn("调用mk接口 删除流程参数为空");
return false;
}
return commonCall("删除流程", token -> {
MKProcessDeleteDTO param = new MKProcessDeleteDTO();
param.setProcessInstanceId(processInstanceId);
param.setLoginName(loginName);
return client.processDelete(param, token);
});
}
@Override
public boolean processAbandon(String bizId, String loginName) {
if (StringUtil.isBlank(bizId) || StringUtil.isBlank(loginName)) {
log.warn("调用mk接口 废弃流程参数为空");
return false;
}
return commonCall("废弃流程", token -> {
MKProcessExecuteDTO param = new MKProcessExecuteDTO();
param.setFormInstanceId(bizId);
param.setLoginName(loginName);
param.setOperationType(MKConstant.OPERATE_TYPE_ABANDON);
return client.processExecute(param, token);
});
}
/**
* 公共调用方法
* @param type
* @param function
* @return
*/
private <T> boolean commonCall(String type, Function<String, MKResultVO<T>> function) {
return commonCall(type, function, Objects::nonNull);
}
/**
* 公共调用方法
* @param type
* @param function
* @return
*/
private <T, R> R commonCall(String type, Function<String, MKResultVO<T>> function, Function<MKResultVO<T>, R> resultMapper) {
if (function == null) {
log.warn("实际调用接口为空");
return resultMapper.apply(null);
}
String token = this.getToken();
if (token == null) {
return resultMapper.apply(null);
}
try {
MKResultVO<T> result = function.apply(token);
if (result != null && result.isSuccess()) {
return resultMapper.apply(result);
}
log.error("调用mk接口 {}异常响应参数:{}", type, JSONUtil.toJsonStr(result));
String message = getMessage(result);
throw new MKException("调用mk接口" + type + "异常 " + message);
} catch (MKException e) {
throw e;
} catch (Exception e) {
log.error("调用mk接口 {}异常", type, e);
throw new MKException("调用mk接口" + type + "异常");
}
}
/**
* 获取消息
* @param result
* @return
*/
private <T> String getMessage(MKResultVO<T> result) {
return result == null ? "" : result.getMsg();
}
/**
* 获取实际的标题,拼接配置的前缀
* @param subject
* @return
*/
private String getActualSubject(String subject) {
if (StringUtil.isBlank(subject)) {
log.warn("调用mk接口 创建并提交流程标题为空");
return subject;
}
String subjectPrefix = properties.getSubjectPrefix();
if (StringUtil.isBlank(subjectPrefix)) {
return subject;
}
return subjectPrefix + subject;
}
@Override
public String getMKAccount(String mkCode) {
if (!StringUtil.hasText(mkCode)) {
log.warn("获取mk账号参数为空");
return null;
}
String accessToken = getToken();
MKOAuthTokenDTO tokenParam = new MKOAuthTokenDTO();
tokenParam.setAppId(properties.getOauthAppId());
tokenParam.setAppSecret(properties.getOauthAppSecret());
tokenParam.setCode(mkCode);
MKResultVO<MKOAuthTokenVO> tokenResult = client.getOAuthToken(tokenParam, accessToken);
if (tokenResult == null || !tokenResult.isSuccess()) {
log.error("调用mk接口 获取oauth token 异常:{}", JSONUtil.toJsonStr(tokenResult));
return null;
}
MKOAuthTokenVO tokenVO = tokenResult.getData();
if (tokenVO == null || tokenVO.getToken() == null) {
log.error("获取oauth token 为空:{}", JSONUtil.toJsonStr(tokenResult));
return null;
}
String token = tokenVO.getToken();
MKResultVO<MKOAuthUserVO> userResult = client.getOAuthUserInfo(new MKOAuthUserDTO(token), accessToken);
if (userResult == null || !userResult.isSuccess()) {
log.error("调用mk接口 获取oauth 用户信息异常:{}", JSONUtil.toJsonStr(userResult));
return null;
}
MKOAuthUserVO userVO = userResult.getData();
if (userVO != null) {
return userVO.getLoginName();
}
log.error("获取oauth 用户信息为空:{}", JSONUtil.toJsonStr(userResult));
return null;
}
@Override
public List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName) {
String accessToken = getToken();
MKCurrentNodesDTO param = new MKCurrentNodesDTO();
param.setProcessInstanceId(processInstanceId);
param.setLoginName(loginName);
MKResultVO<List<MKNodeVO>> nodesResult = client.getCurrentNodes(param, accessToken);
log.info("调用mk接口 获取流程当前节点详情 :{}", JSONUtil.toJsonStr(nodesResult));
if (nodesResult == null || !nodesResult.isSuccess()) {
log.error("调用mk接口 获取流程当前节点详情异常:{}", JSONUtil.toJsonStr(nodesResult));
return null;
}
return nodesResult.getData();
}
@Override
public MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId) {
String accessToken = getToken();
MKNodeHandlersDTO param = new MKNodeHandlersDTO();
param.setProcessInstanceId(processInstanceId);
param.setLoginName(loginName);
param.setNodeId(nodeId);
MKResultVO<MKAllHandlerVO> nodeHandlers = client.getNodeHandlers(param, accessToken);
log.info("调用mk接口 获取节点处理人详情 :{}", JSONUtil.toJsonStr(nodeHandlers));
if (nodeHandlers == null || !nodeHandlers.isSuccess()) {
log.error("调用mk接口 获取节点处理人详情异常:{}", JSONUtil.toJsonStr(nodeHandlers));
return null;
}
return nodeHandlers.getData();
}
@Override
public boolean pushOrgDept(MKPushDTO<MKPushOrgDeptDTO> param) {
String accessToken = getToken();
MKResultVO<Object> resultVO = client.pushOrgDept(param, accessToken);
log.info("调用mk接口 推送机构部门结果 :{}", JSONUtil.toJsonStr(resultVO));
if (resultVO == null || !resultVO.isSuccess()) {
log.error("调用mk接口 推送机构部门异常:{}", JSONUtil.toJsonStr(resultVO));
return false;
}
return true;
}
@Override
public boolean pushPerson(MKPushDTO<MKPushPersonDTO> param) {
String accessToken = getToken();
MKResultVO<Object> resultVO = client.pushPerson(param, accessToken);
log.info("调用mk接口 推送人员结果 :{}", JSONUtil.toJsonStr(resultVO));
if (resultVO == null || !resultVO.isSuccess()) {
log.error("调用mk接口 推送人员异常:{}", JSONUtil.toJsonStr(resultVO));
return false;
}
return true;
}
@Override
public String getMKApprovalUrl(String processInstanceId, String loginName) {
String accessToken = getToken();
MKOAuthCodeDTO codeParam = new MKOAuthCodeDTO();
codeParam.setAppId(properties.getOauthAppId());
codeParam.setAppSecret(properties.getOauthAppSecret());
codeParam.setLoginName(loginName);
MKResultVO<MKOAuthCodeVO> codeResult = client.getOAuthCode(codeParam, accessToken);
if (codeResult == null || !codeResult.isSuccess()) {
log.error("调用mk接口 获取oauth 认证code 异常:{}", JSONUtil.toJsonStr(codeResult));
String message = Optional.ofNullable(codeResult)
// 这个接口错误消息在 code没有 msg
.map(MKResultVO::getCode)
.orElse(StringPool.EMPTY);
throw new MKException(message);
}
MKOAuthCodeVO codeVO = codeResult.getData();
if (codeVO == null || codeVO.getCode() == null) {
log.error("获取oauth 认证code 为空:{}", JSONUtil.toJsonStr(codeVO));
return null;
}
String code = codeVO.getCode();
// 审批页面地址
String approvalUrl = String.format(APPROVAL_URL_FORMAT, properties.getLoginUrl(), processInstanceId, processInstanceId);
// sso回调地址
return String.format(SSO_CALLBACK_URL_FORMAT, properties.getLoginUrl(), code, UrlUtil.encode(approvalUrl));
}
@Override
public List<MKAuditNoteVO> queryAuditNotes(MKAuditNoteDTO param) {
AssertUtils.notNull(param, "参数不能为空");
AssertUtils.notBlank(param.getLoginName(),"登录名不能为空");
AssertUtils.notBlank(param.getProcessInstanceId(),"流程实例id不能为空");
List<MKAuditNoteVO> notes = commonCall("查询审批记录",
token -> client.queryAuditNotes(param, token),
result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.orElse(null));
if (CollectionUtil.isEmpty(notes)) {
return notes;
}
for (MKAuditNoteVO note : notes) {
// 处理审批意见的附件全名
handleFullName(note.getAttachmentParameter(), note.getMechanisms());
if (CollectionUtil.isNotEmpty(note.getProcessComments())) {
for (MKProcessCommentVO processComment : note.getProcessComments()) {
// 处理流程附言的附件全名
handleFullName(processComment.getAttachments(), processComment.getMechanisms());
}
}
}
return notes;
}
/**
* 处理附件全名
* @param attachments
* @param mechanisms
*/
private void handleFullName(List<MKAttachmentVO> attachments, MKMechanismsVO mechanisms) {
if (CollectionUtil.isNotEmpty(attachments) && mechanisms != null && CollectionUtil.isNotEmpty(mechanisms.getAttachment())) {
Map<String, String> fileIdFullNameMap = mechanisms.getAttachment().stream()
.collect(Collectors.toMap(MKMetaAttachmentVO::getId, MKMetaAttachmentVO::getFullName, (a, b) -> a));
for (MKAttachmentVO attachment : attachments) {
String fullName = fileIdFullNameMap.get(attachment.getFileId());
if (StringUtil.isNotBlank(fullName)) {
// 附件名替换为全名
attachment.setName(fullName);
}
}
}
}
@Override
public List<MKSenderVO> querySenderList(MKSenderDTO param) {
AssertUtils.notNull(param, "参数不能为空");
AssertUtils.notBlank(param.getNodeInstanceId(),"节点实例id不能为空");
AssertUtils.notBlank(param.getProcessInstanceId(),"流程实例id不能为空");
return commonCall("查询抄送人列表", token -> {
// 查询100一次都查完
param.setPageSize(100);
return client.querySenderList(param, token);
}, result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.map(MKPageVO::getContent)
.orElse(Collections.emptyList()));
}
@Override
public void downloadFile(HttpServletResponse response, String fileId) {
AssertUtils.notBlank(fileId,"附件id不能为空");
String accessToken = getToken();
try (OutputStream outputStream = response.getOutputStream();) {
try (Response feignResponse = client.downloadFile(new MKFileDTO(fileId), accessToken);) {
InputStream inputStream = feignResponse.body().asInputStream();
Map<String, Collection<String>> responseHeaders = feignResponse.headers();
response.setHeader("Content-disposition", getHeader(responseHeaders, "Content-disposition"));
// response.setHeader("Content-Type", getHeader(responseHeaders, "Content-Type"));
response.setHeader("Content-Type", "image/png");
IOUtils.copy(inputStream, outputStream);
} catch (MKException e) {
response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
outputStream.write(Optional.ofNullable(e.getMessage()).orElse("调用mk接口 下载附件异常").getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("调用mk接口 下载附件异常", e);
response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
outputStream.write("调用mk接口 下载附件异常".getBytes(StandardCharsets.UTF_8));
}
} catch (Exception e) {
log.error("下载mk附件异常", e);
}
}
@Override
public String getFileBase64(String fileId) {
AssertUtils.notBlank(fileId,"附件id不能为空");
String accessToken = getToken();
try (Response feignResponse = client.downloadFile(new MKFileDTO(fileId), accessToken);) {
InputStream inputStream = feignResponse.body().asInputStream();
byte[] bytes = IOUtils.toByteArray(inputStream);
return Base64.getEncoder().encodeToString(bytes);
} catch (MKException e) {
throw e;
} catch (Exception e) {
log.error("调用mk接口 下载附件异常", e);
}
return null;
}
@Override
public String getNodeNumber(String templateId, String nodeId) {
if (StringUtil.isBlank(templateId) || StringUtil.isBlank(nodeId)) {
log.warn("查询节点编号模板id或节点id为空 模板id{} 节点id{}", templateId, nodeId);
return null;
}
return commonCall("查询模板节点信息", token -> {
return client.getManualNode(new MKManualNodeDTO(templateId), token);
}, result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.flatMap(nodes -> nodes.stream()
.filter(node -> StringUtil.equals(node.getNodeId(), nodeId))
.findFirst()
.map(MKManualNodeVO::getNodeNumber)
).orElse(null));
}
@Override
public MKPageVO<MKApprovalVO> queryApprovalList(MKApprovalDTO param) {
AssertUtils.notNull(param, "参数不能为空");
AssertUtils.notNull(param.getConditions(),"条件不能为空");
AssertUtils.notNull(param.getConditions().getMydoc(),"类型不能为空");
return commonCall("查询审批中心列表", token -> client.queryApprovalList(param, token),
result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.orElse(MKPageVO.empty()));
}
@Override
public MKPageVO<MKProcessVO> queryProcessList(MKProcessDTO param) {
AssertUtils.notNull(param, "参数不能为空");
AssertUtils.notBlank(param.getLoginName(),"登录名不能为空");
AssertUtils.notNull(param.getMydoc(),"类型不能为空");
return commonCall("查询流程列表", token -> client.queryProcessList(param, token),
result -> Optional.ofNullable(result)
.map(MKResultVO::getData)
.orElse(MKPageVO.empty()));
}
/**
* 获取响应头
* @param responseHeaders
* @param header
* @return
*/
private String getHeader(Map<String, Collection<String>> responseHeaders, String header) {
Collection<String> collection = responseHeaders.get(header);
if (CollectionUtil.isEmpty(collection)) {
return null;
}
return collection.stream().findFirst().orElse(null);
}
/**
* 获取token
*
* @return
*/
private String getToken() {
String token = bladeRedis.get(MKConstant.MK_TOKEN_KEY);
if (token != null) {
return token;
}
try {
MKTokenDTO param = new MKTokenDTO();
param.setAppKey(properties.getAppKey());
param.setAppSecret(properties.getAppSecret());
long start = System.currentTimeMillis();
log.info("调用mk获取token开始");
MKTokenVO tokenResult = client.getToken(param);
long end = System.currentTimeMillis();
log.info("调用mk获取token结束 耗时:{}", end - start);
if (tokenResult != null && tokenResult.getErrCode() == MKConstant.TOKEN_SUCCESS_CODE) {
// 成功
String accessToken = tokenResult.getAccessToken();
int expiresIn = tokenResult.getExpiresIn();
// 过期时间 - 100秒防止刚好过期
bladeRedis.getValueOps().setIfAbsent(MKConstant.MK_TOKEN_KEY, accessToken, Duration.ofSeconds(expiresIn - 100));
return accessToken;
}
log.error("调用mk接口 获取token 异常响应参数:{}", JSONUtil.toJsonStr(tokenResult));
throw new MKException("调用mk接口获取token异常");
} catch (MKException e) {
throw e;
} catch (Exception e) {
log.error("调用mk接口 获取token 异常", e);
throw new MKException("调用mk接口获取token异常");
}
}
}

View File

@@ -0,0 +1,37 @@
package org.springblade.thirdparty.mk.support;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.thirdparty.mk.pojo.dto.approval.MKConditionDTO;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
/**
* @author bfhuange
* @since 2025/5/21
*/
public class MultiKeySerializer extends JsonSerializer<List<MKConditionDTO>> {
@Override
public void serialize(List<MKConditionDTO> values, JsonGenerator gen, SerializerProvider serializers) throws IOException {
values = values.stream()
.filter(Objects::nonNull)
.toList();
if (CollectionUtil.isNotEmpty(values)) {
// 获取当前字段名
String fieldName = gen.getOutputContext().getCurrentName();
boolean writeValue = false;
for (MKConditionDTO value : values) {
if (writeValue) {
// 写过值了,要再添加一个字段名
gen.writeFieldName(fieldName);
}
gen.writeObject(value);
writeValue = true;
}
}
}
}

View File

@@ -0,0 +1,266 @@
package org.springblade.thirdparty.mk.util;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.thirdparty.mk.exception.MKException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author bfhuange
* @since 2025/2/24
*/
public class AssertUtils {
/**
* 对象非空
* @param object
* @param message
*/
public static void notNull(Object object, String message) {
if (object == null) {
throw new MKException(message);
}
}
/**
* Map非空
* @param map
* @param message
*/
public static void notEmpty(Map<?, ?> map, String message) {
if (CollectionUtils.isEmpty(map)) {
throw new MKException(message);
}
}
/**
* 列表非空
* @param collection
* @param message
*/
public static void notEmpty(Collection<?> collection, String message) {
if (CollectionUtils.isEmpty(collection)) {
throw new MKException(message);
}
}
/**
* 数组非空
* @param array
* @param message
*/
public static void notEmpty(Object[] array, String message) {
if (ObjectUtils.isEmpty(array)) {
throw new MKException(message);
}
}
/**
* 字符串非空
* @param value
* @param message
*/
public static void notEmpty(String value, String message) {
if (StringUtil.hasLength(value)) {
throw new MKException(message);
}
}
/**
* 字符串去除空格非空
* @param value
* @param message
*/
public static void notBlank(String value, String message) {
if (StringUtil.isBlank(value)) {
throw new MKException(message);
}
}
/**
* 获取重复数据
* @param dataList
* @return
* @throws MKException
*/
public static List<String> getRepeatData(List<String> dataList) {
if(CollectionUtils.isEmpty(dataList)) {
return null;
}
//判断是否有重复数据
List<String> distinctDataList = dataList.stream().distinct().toList();
if(dataList.size() == distinctDataList.size()) {
return null;
}
List<String> repeatList = new ArrayList<>();
Map<String,Long> dataMap = dataList.stream().collect(Collectors.groupingBy(p -> p,Collectors.counting()));
//处理重复数据
for(Map.Entry<String,Long> entry:dataMap.entrySet()) {
if(entry.getValue() > 1) {
repeatList.add(entry.getKey());
}
}
return repeatList;
}
/**
* 数据不允许重复
* @param dataList
* @param message
* @throws MKException
*/
public static void notRepeat(List<String> dataList,String message) {
//获取重复数据
List<String> repeatList = getRepeatData(dataList);
//若有重复数据,则校验不通过处理
if(!CollectionUtils.isEmpty(repeatList)) {
String repeatData = String.join(",",repeatList);
throw new MKException(String.format(message,repeatData));
}
}
/**
* 字符串相等校验
* @param str1
* @param str2
* @param message
* @throws MKException
*/
public static void equals(String str1, String str2, String message) {
if (!StringUtil.equals(str1,str2)) {
throw new MKException(message);
}
}
/**
* 数字相等校验
* @param num1
* @param num2
* @param message
* @throws MKException
*/
public static void equals(BigDecimal num1, BigDecimal num2, String message) {
if (num1.compareTo(num2) != 0) {
throw new MKException(message);
}
}
/**
* 数字不大于校验
* @param num1
* @param num2
* @param message
* @throws MKException
*/
public static void notGreaterThan(BigDecimal num1, BigDecimal num2, String message) {
if(num1.compareTo(num2) > 0) {
throw new MKException(message);
}
}
/**
* 数字不大于校验
* @param num1
* @param num2
* @param message
* @throws MKException
*/
public static void notGreaterThan(Integer num1, Integer num2, String message) {
if(num1 > num2) {
throw new MKException(message);
}
}
/**
* 数字不小于校验
* @param num1
* @param num2
* @param message
* @throws MKException
*/
public static void notLessThan(BigDecimal num1, BigDecimal num2, String message) {
if(num1.compareTo(num2) < 0) {
throw new MKException(message);
}
}
/**
* 表达式为真判断校验
* @param expression
* @param message
* @throws MKException
*/
public static void isTrue(boolean expression, String message) {
if(!expression) {
throw new MKException(message);
}
}
/**
* 表达式判断为假校验
* @param expression
* @param message
* @throws MKException
*/
public static void isFalse(boolean expression, String message) {
if(expression) {
throw new MKException(message);
}
}
/**
* 字符串不相等校验
* @param str1
* @param str2
* @param message
* @throws MKException
*/
public static void notEquals(String str1, String str2, String message) {
if (StringUtil.equals(str1,str2)) {
throw new MKException(message);
}
}
/**
* 对象为空
* @param object
* @param message
*/
public static void isNull(Object object, String message) {
if (object != null) {
throw new MKException(message);
}
}
/**
* 对象为数值
* @param value
* @param message
* @throws MKException
*/
public static void isInteger(String value,String message) {
try {
Integer.valueOf(value);
} catch (NumberFormatException e) {
throw new MKException(message);
}
}
/**
* 列表为空
* @param collection
* @param message
*/
public static void isEmpty(Collection<?> collection, String message) {
if (!CollectionUtils.isEmpty(collection)) {
throw new MKException(message);
}
}
}

View File

@@ -0,0 +1 @@
org.springblade.thirdparty.mk.config.ThirdPartyMKAutoConfiguration