update:将飞书对接代码移动到对接模块中
This commit is contained in:
+92
@@ -0,0 +1,92 @@
|
||||
package com.jero.modules.docking.feishu.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jero.common.api.vo.Result;
|
||||
import com.jero.modules.docking.feishu.dto.BotMessageDto;
|
||||
import com.jero.modules.docking.feishu.dto.InstanceDto;
|
||||
import com.jero.modules.docking.feishu.service.IFeiShuDockingService;
|
||||
import com.jero.modules.docking.feishu.vo.definition.ApprovalsDefinitionVo;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 飞书对接
|
||||
* </p>
|
||||
*/
|
||||
@Api(tags = "飞书对接")
|
||||
@RestController
|
||||
@RequestMapping("/feishu")
|
||||
@Slf4j
|
||||
public class FeiShuDockingController {
|
||||
|
||||
@Resource
|
||||
private IFeiShuDockingService feiShuDockingService;
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getAccessToken")
|
||||
public String getAccessToken() {
|
||||
return feiShuDockingService.getAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建三方审批定义
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/createApprovalDefinition")
|
||||
public String createApprovalDefinition() {
|
||||
return feiShuDockingService.createApprovalDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定三方审批定义
|
||||
* @param approvalDefinitionCode
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getApprovalDefinition")
|
||||
public ApprovalsDefinitionVo getApprovalDefinition(String approvalDefinitionCode) {
|
||||
return feiShuDockingService.getApprovalDefinition(approvalDefinitionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机号获取用户的user_id
|
||||
* @param phones
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/getUserId")
|
||||
public String getUserId(String phones) {
|
||||
return feiShuDockingService.getUserId(phones);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步三方审批实例
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/synchronizeApprovalInstance")
|
||||
public void synchronizeApprovalInstance(@RequestBody InstanceDto instanceDto) {
|
||||
feiShuDockingService.synchronizeApprovalInstance(instanceDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Bot发送富文本消息
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/sendHrefMessageByBot")
|
||||
public void sendHrefMessageByBot(@RequestBody BotMessageDto botMessageDto) {
|
||||
feiShuDockingService.sendHrefMessageByBot(botMessageDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据预授权码获取用户信息
|
||||
*/
|
||||
@PostMapping("/getUserInfoByCode")
|
||||
public Result<JSONObject> getUserInfoByCode(@RequestBody JSONObject codeObject) {
|
||||
return feiShuDockingService.getUserInfoByCode(codeObject);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.jero.modules.docking.feishu.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BotMessageDto {
|
||||
|
||||
@ApiModelProperty("消息接收者的id,可以为多个,逗号拼接")
|
||||
private String receiveIds;
|
||||
|
||||
@ApiModelProperty("超链接的文字")
|
||||
private String hrefText;
|
||||
|
||||
@ApiModelProperty("超链接前面的普通文字")
|
||||
private String textBeforeHref;
|
||||
|
||||
@ApiModelProperty("超链接后面的普通文字")
|
||||
private String textAfterHref;
|
||||
|
||||
@ApiModelProperty("消息的标题")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty("超链接的跳转地址")
|
||||
private String hrefUrl;
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.jero.modules.docking.feishu.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class InstanceDto {
|
||||
|
||||
@ApiModelProperty("发起人的id")
|
||||
private String promoterUserId;
|
||||
|
||||
@ApiModelProperty("审核人的ids,可能为多个,逗号分割")
|
||||
private String reviewedIds;
|
||||
|
||||
@ApiModelProperty("标题")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty("审核实例的id")
|
||||
private String processInstanceId;
|
||||
|
||||
@ApiModelProperty("审核任务的ids,有几个审核人就对应几个任务id,逗号分割")
|
||||
private String taskIds;
|
||||
|
||||
/**
|
||||
* 审批实例状态
|
||||
* 示例值:"PENDING"
|
||||
* PENDING: 审批中
|
||||
* APPROVED: 审批流程结束,结果为同意
|
||||
* REJECTED: 审批流程结束,结果为拒绝
|
||||
* CANCELED: 审批发起人撤回
|
||||
* DELETED: 审批被删除
|
||||
* HIDDEN: 状态隐藏(不显示状态)
|
||||
* TERMINATED:审批终止
|
||||
*/
|
||||
@ApiModelProperty("审核实例的状态")
|
||||
private String instanceStatus;
|
||||
|
||||
@ApiModelProperty("审核实例的开始时间")
|
||||
private Date instanceStartTime;
|
||||
|
||||
/**
|
||||
* 任务状态
|
||||
* 示例值:"PENDING"
|
||||
* 可选值有:
|
||||
* PENDING:待审批
|
||||
* APPROVED:任务同意
|
||||
* REJECTED:任务拒绝
|
||||
* TRANSFERRED:任务转交
|
||||
* DONE:任务通过但审批人未操作;审批人看不到这个任务, 若想要看到, 可以通过抄送该人.
|
||||
*/
|
||||
@ApiModelProperty("审核任务的状态,有几个审核人对应几个审核任务的状态,逗号分割")
|
||||
private String taskStatus;
|
||||
|
||||
@ApiModelProperty("发起人的PC跳转地址")
|
||||
private String promoterPcLink;
|
||||
|
||||
@ApiModelProperty("发起人的移动端跳转地址")
|
||||
private String promoterMobileLink;
|
||||
|
||||
@ApiModelProperty("审核人的PC端跳转地址,有几个审核人对应几条链接,逗号分割")
|
||||
private String reviewPcLink;
|
||||
|
||||
@ApiModelProperty("审核人的移动端跳转地址,有几个审核人对应几条链接,逗号分割")
|
||||
private String reviewMobileLink;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.jero.modules.docking.feishu.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jero.common.api.vo.Result;
|
||||
import com.jero.modules.docking.feishu.dto.BotMessageDto;
|
||||
import com.jero.modules.docking.feishu.dto.InstanceDto;
|
||||
import com.jero.modules.docking.feishu.vo.definition.ApprovalsDefinitionVo;
|
||||
|
||||
public interface IFeiShuDockingService {
|
||||
|
||||
/**
|
||||
* 获取飞书应用的token
|
||||
* @return
|
||||
*/
|
||||
String getAccessToken();
|
||||
|
||||
/**
|
||||
* 创建三方审批的定义
|
||||
* @return
|
||||
*/
|
||||
String createApprovalDefinition();
|
||||
|
||||
/**
|
||||
* 查看指定三方审批定义
|
||||
* @return
|
||||
*/
|
||||
ApprovalsDefinitionVo getApprovalDefinition(String approvalDefinitionCode);
|
||||
|
||||
/**
|
||||
* 获取用户id
|
||||
* @return
|
||||
*/
|
||||
String getUserId(String phones);
|
||||
|
||||
/**
|
||||
* 同步三方审批实例
|
||||
* @return
|
||||
*/
|
||||
void synchronizeApprovalInstance(InstanceDto instanceDto);
|
||||
|
||||
/**
|
||||
* 使用机器人发送消息
|
||||
* @param botMessageDto
|
||||
* @return
|
||||
*/
|
||||
void sendHrefMessageByBot(BotMessageDto botMessageDto);
|
||||
|
||||
/**
|
||||
* 根据预授权码获取用户信息
|
||||
* @param codeObject
|
||||
* @return
|
||||
*/
|
||||
Result<JSONObject> getUserInfoByCode(JSONObject codeObject);
|
||||
}
|
||||
+604
@@ -0,0 +1,604 @@
|
||||
package com.jero.modules.docking.feishu.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.jero.common.api.CommonAPI;
|
||||
import com.jero.common.api.vo.Result;
|
||||
import com.jero.common.constant.CommonConstant;
|
||||
import com.jero.common.exception.JeroBootException;
|
||||
import com.jero.common.system.util.JwtUtil;
|
||||
import com.jero.common.system.vo.SysDictItemCore;
|
||||
import com.jero.common.util.RedisUtil;
|
||||
import com.jero.common.util.oConvertUtils;
|
||||
import com.jero.modules.docking.feishu.dto.BotMessageDto;
|
||||
import com.jero.modules.docking.feishu.dto.InstanceDto;
|
||||
import com.jero.modules.docking.feishu.service.IFeiShuDockingService;
|
||||
import com.jero.modules.docking.feishu.vo.bot.BotMessageVo;
|
||||
import com.jero.modules.docking.feishu.vo.definition.*;
|
||||
import com.jero.modules.docking.feishu.vo.instance.ApprovalsInstanceVo;
|
||||
import com.jero.modules.docking.feishu.vo.instance.InstanceLink;
|
||||
import com.jero.modules.docking.feishu.vo.instance.InstanceTask;
|
||||
import com.jero.modules.system.entity.*;
|
||||
import com.jero.modules.system.service.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FeiShuDockingServiceImpl implements IFeiShuDockingService {
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
@Resource
|
||||
private Environment env;
|
||||
@Resource
|
||||
private ISysUserService sysUserService;
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
@Autowired
|
||||
private ISysDepartService sysDepartService;
|
||||
@Autowired
|
||||
private ISysTenantService sysTenantService;
|
||||
@Autowired
|
||||
private ISysDictService sysDictService;
|
||||
@Resource
|
||||
private ISysUserRoleService sysUserRoleService;
|
||||
@Resource
|
||||
private ISysRoleService sysRoleService;
|
||||
@Resource
|
||||
private CommonAPI commonAPI;
|
||||
@Value("${feishu.app_id}")
|
||||
private String appId;
|
||||
@Value("${feishu.app_secret}")
|
||||
private String appSecret;
|
||||
@Value("${feishu.managersIds}")
|
||||
private String managersIds;
|
||||
@Value("${feishu.approvalName}")
|
||||
private String approvalName;
|
||||
|
||||
private static final String USER_INFO = "userInfo";
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
String url = env.getProperty("feishu.get_token");
|
||||
assert url != null;
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("app_id", appId);
|
||||
jsonObject.put("app_secret", appSecret);
|
||||
String res = restTemplate.postForObject(url, jsonObject, String.class);
|
||||
JSONObject result = JSON.parseObject(res);
|
||||
String code = result.getString("code");
|
||||
if ("0".equals(code)) {
|
||||
return result.getString("tenant_access_token");
|
||||
} else {
|
||||
throw new JeroBootException("获取飞书token失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createApprovalDefinition() {
|
||||
String url = env.getProperty("feishu.create_approval_definition");
|
||||
assert url != null;
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 构建对象
|
||||
ApprovalsDefinitionVo approvalsDefinitionVo = buildDefinitionVo();
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 构建包含查询参数的 URL
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
|
||||
.queryParam("department_id_type", "open_department_id")
|
||||
.queryParam("user_id_type", "user_id");
|
||||
// 创建 HttpEntity
|
||||
HttpEntity<ApprovalsDefinitionVo> entity = new HttpEntity<>(approvalsDefinitionVo, headers);
|
||||
// 发送请求
|
||||
ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class);
|
||||
// 处理响应
|
||||
JSONObject jsonResponse = JSON.parseObject(response.getBody());
|
||||
if ("0".equals((String.valueOf(jsonResponse.get("code"))))) {
|
||||
JSONObject data = (JSONObject) jsonResponse.get("data");
|
||||
return data.getString("approval_code");
|
||||
} else {
|
||||
log.error(jsonResponse.get("msg").toString());
|
||||
throw new JeroBootException("创建三方审批定义失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 构建创建审批定义的入参对象
|
||||
public ApprovalsDefinitionVo buildDefinitionVo() {
|
||||
ApprovalsDefinitionVo approvalsDefinitionVo = new ApprovalsDefinitionVo();
|
||||
// 构建审批定义vo
|
||||
approvalsDefinitionVo.setApproval_name("@i18n@1");
|
||||
approvalsDefinitionVo.setApproval_code("permission_test3");
|
||||
approvalsDefinitionVo.setGroup_code("work_group");
|
||||
approvalsDefinitionVo.setGroup_name("@i18n@2");
|
||||
// 构建三方审批相关对象.
|
||||
DefinitionExternal definitionExternal = new DefinitionExternal();
|
||||
definitionExternal.setCreate_link_pc("");
|
||||
definitionExternal.setCreate_link_mobile("");
|
||||
definitionExternal.setSupport_pc(true);
|
||||
definitionExternal.setSupport_mobile(true);
|
||||
definitionExternal.setSupport_batch_read(true);
|
||||
definitionExternal.setEnable_mark_readed(true);
|
||||
// 构建可见人列表对象
|
||||
DefinitionViewers definitionViewers = new DefinitionViewers();
|
||||
definitionViewers.setViewer_type("NONE");
|
||||
List<DefinitionViewers> viewers = new ArrayList<>();
|
||||
viewers.add(definitionViewers);
|
||||
// 构建语言文案
|
||||
List<DefinitionTexts> texts = new ArrayList<>();
|
||||
texts.add(new DefinitionTexts("@i18n@1",approvalName));
|
||||
texts.add(new DefinitionTexts("@i18n@2",approvalName));
|
||||
texts.add(new DefinitionTexts("@i18n@3","飞书"));
|
||||
// 构建国际化文案对象
|
||||
DefinitionI18nResources definitionI18nResources = new DefinitionI18nResources();
|
||||
definitionI18nResources.setLocale("zh-CN");
|
||||
definitionI18nResources.setIs_default(true);
|
||||
definitionI18nResources.setTexts(texts);
|
||||
List<DefinitionI18nResources> i18n_resources = new ArrayList<>();
|
||||
i18n_resources.add(definitionI18nResources);
|
||||
approvalsDefinitionVo.setExternal(definitionExternal);
|
||||
approvalsDefinitionVo.setViewers(viewers);
|
||||
approvalsDefinitionVo.setI18n_resources(i18n_resources);
|
||||
List<String> mangers = Arrays.asList(managersIds.split(","));
|
||||
String[] mangersString = mangers.toArray(new String[0]);
|
||||
approvalsDefinitionVo.setManagers(mangersString);
|
||||
return approvalsDefinitionVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApprovalsDefinitionVo getApprovalDefinition(String approvalDefinitionCode) {
|
||||
String url = env.getProperty("feishu.get_approval_definition");
|
||||
assert url != null;
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 拼接URL
|
||||
String fullUrl = url + "/" + approvalDefinitionCode;
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 创建 HttpEntity
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
// 发送请求
|
||||
ResponseEntity<String> response = restTemplate.exchange(fullUrl, HttpMethod.GET, entity, String.class);
|
||||
JSONObject jsonResponse = JSON.parseObject(response.getBody());
|
||||
if ("0".equals((String.valueOf(jsonResponse.get("code"))))) {
|
||||
JSONObject dataJson = jsonResponse.getJSONObject("data");
|
||||
return JSON.toJavaObject(dataJson, ApprovalsDefinitionVo.class);
|
||||
} else {
|
||||
log.error(jsonResponse.get("msg").toString());
|
||||
throw new JeroBootException("查看三方审批定义失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserId(String phones) {
|
||||
try {
|
||||
String url = env.getProperty("feishu.get_user_id");
|
||||
assert url != null;
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 构建请求对象
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
List<String> phonesList = Arrays.asList(phones.split(","));
|
||||
String[] phonesString = phonesList.toArray(new String[0]);
|
||||
jsonObject.put("mobiles", phonesString);
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 构建包含查询参数的 URL
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
|
||||
.queryParam("user_id_type", "user_id");
|
||||
// 创建 HttpEntity
|
||||
HttpEntity<JSONObject> entity = new HttpEntity<>(jsonObject, headers);
|
||||
// 发送请求
|
||||
ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class);
|
||||
// 处理响应
|
||||
JSONObject jsonResponse = JSON.parseObject(response.getBody());
|
||||
if ("0".equals((String.valueOf(jsonResponse.get("code"))))) {
|
||||
JSONObject data = jsonResponse.getJSONObject("data");
|
||||
JSONArray userList = data.getJSONArray("user_list");
|
||||
// 将 JSONArray 转换为 List<JSONObject>
|
||||
List<JSONObject> userListObjects = userList.toJavaList(JSONObject.class);
|
||||
return userListObjects.get(0).getString("user_id");
|
||||
} else {
|
||||
log.error("获取飞书用户id失败" + jsonResponse.get("msg").toString());
|
||||
return "";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步三方审批实例
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public void synchronizeApprovalInstance(InstanceDto instanceDto) {
|
||||
String url = env.getProperty("feishu.synchronize_approval_instance");
|
||||
assert url != null;
|
||||
try {
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 构建对象
|
||||
ApprovalsInstanceVo approvalsInstanceVo = buildApprovalsInstanceVo(instanceDto);
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 创建 HttpEntity
|
||||
HttpEntity<ApprovalsInstanceVo> entity = new HttpEntity<>(approvalsInstanceVo, headers);
|
||||
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
}catch (Exception e) {
|
||||
log.error("同步三方审批实例异常" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private ApprovalsInstanceVo buildApprovalsInstanceVo(InstanceDto instanceDto) {
|
||||
// 转换userId为飞书Id
|
||||
// 发起人的id
|
||||
String promoterUserId = instanceDto.getPromoterUserId();
|
||||
if (StringUtils.isNoneBlank(promoterUserId)) {
|
||||
SysUser promoterUser = sysUserService.getById(promoterUserId);
|
||||
promoterUserId = promoterUser.getFeishuId();
|
||||
}
|
||||
// 审核人的id(可能为多个),查出对应的飞书id
|
||||
String reviewedIds = instanceDto.getReviewedIds();
|
||||
List<String> newReviewedIds = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(reviewedIds)) {
|
||||
List<String> reviewedIdList = Arrays.asList(reviewedIds.split(","));
|
||||
for (String reviewedId : reviewedIdList) {
|
||||
SysUser reviewUser = sysUserService.getById(reviewedId);
|
||||
if (!Objects.isNull(reviewUser) && StringUtils.isNotBlank(reviewUser.getFeishuId())) {
|
||||
newReviewedIds.add(reviewUser.getFeishuId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 任务id
|
||||
String taskIds = instanceDto.getTaskIds();
|
||||
List<String> taskIdList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(taskIds)) {
|
||||
taskIdList = Arrays.asList(instanceDto.getTaskIds().split(","));
|
||||
}
|
||||
// 任务状态
|
||||
String taskStatus = instanceDto.getTaskStatus();
|
||||
List<String> taskStatusList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(taskIds)) {
|
||||
taskStatusList = Arrays.asList(taskStatus.split(","));
|
||||
}
|
||||
|
||||
// 替换跳转的地址为单点登录的地址
|
||||
String url = env.getProperty("feishu.sign_login_in");
|
||||
assert url != null;
|
||||
// 审核人对应的 pc 跳转地址
|
||||
String reviewPcLink = instanceDto.getReviewPcLink();
|
||||
List<String> reviewPcLinkList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(reviewPcLink)) {
|
||||
reviewPcLinkList = Arrays.asList(reviewPcLink.split(","));
|
||||
reviewPcLinkList = reviewPcLinkList.stream()
|
||||
.map(link -> url.replace("{REDIRECT_URI}", link))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// 审核人对应的 mobile 跳转地址
|
||||
String reviewMobileLink = instanceDto.getReviewMobileLink();
|
||||
List<String> reviewMobileLinkList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(reviewMobileLink)) {
|
||||
reviewMobileLinkList = Arrays.asList(reviewMobileLink.split(","));
|
||||
reviewMobileLinkList = reviewMobileLinkList.stream()
|
||||
.map(link -> url.replace("{REDIRECT_URI}", link))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// 发起人对应的pc的跳转地址
|
||||
String promoterPcLink = instanceDto.getPromoterPcLink();
|
||||
if (StringUtils.isNotBlank(promoterPcLink)) {
|
||||
promoterPcLink = url.replace("{REDIRECT_URI}", promoterPcLink);
|
||||
}
|
||||
// 发起人移动端的跳转地址
|
||||
String promoterMobileLink = instanceDto.getPromoterMobileLink();
|
||||
if (StringUtils.isNotBlank(promoterMobileLink)) {
|
||||
promoterMobileLink = url.replace("{REDIRECT_URI}", promoterMobileLink);
|
||||
}
|
||||
// 审批定义的code
|
||||
String approvalDefinition = createApprovalDefinition();
|
||||
// 发起人相关的信息
|
||||
ApprovalsInstanceVo approvalsInstanceVo = new ApprovalsInstanceVo();
|
||||
approvalsInstanceVo.setApproval_code(approvalDefinition);
|
||||
approvalsInstanceVo.setStatus(instanceDto.getInstanceStatus());
|
||||
approvalsInstanceVo.setInstance_id(instanceDto.getProcessInstanceId());
|
||||
InstanceLink instanceLink = new InstanceLink();
|
||||
instanceLink.setPc_link(promoterPcLink);
|
||||
instanceLink.setMobile_link(promoterMobileLink);
|
||||
approvalsInstanceVo.setLinks(instanceLink);
|
||||
approvalsInstanceVo.setTitle("@i18n@1");
|
||||
approvalsInstanceVo.setUser_id(promoterUserId); // 审批发起人的user_id
|
||||
approvalsInstanceVo.setStart_time(String.valueOf(instanceDto.getInstanceStartTime().getTime()));
|
||||
approvalsInstanceVo.setEnd_time("0");
|
||||
approvalsInstanceVo.setUpdate_time(String.valueOf(System.currentTimeMillis()));
|
||||
approvalsInstanceVo.setUpdate_mode("UPDATE");
|
||||
approvalsInstanceVo.setDisplay_method("BROWSER");
|
||||
List<InstanceTask> instanceTasks = new ArrayList<>();
|
||||
for (int i = 0; i < newReviewedIds.size(); i++) {
|
||||
// 审核人相关的信息
|
||||
InstanceTask instanceTask = new InstanceTask();
|
||||
instanceTask.setUser_id(newReviewedIds.get(i)); // 审批人的id
|
||||
if (!taskIdList.isEmpty()) {
|
||||
instanceTask.setTask_id(taskIdList.get(i));
|
||||
}
|
||||
InstanceLink taskLink = new InstanceLink();
|
||||
if (!reviewPcLinkList.isEmpty()) {
|
||||
taskLink.setPc_link(reviewPcLinkList.get(i));
|
||||
}
|
||||
if (!reviewMobileLinkList.isEmpty()) {
|
||||
taskLink.setMobile_link(reviewMobileLinkList.get(i));
|
||||
}
|
||||
instanceTask.setLinks(taskLink);
|
||||
if (!taskStatusList.isEmpty()) {
|
||||
instanceTask.setStatus(taskStatusList.get(i));
|
||||
}
|
||||
instanceTask.setTitle("@i18n@1");
|
||||
instanceTask.setCreate_time(String.valueOf(System.currentTimeMillis()));
|
||||
instanceTask.setEnd_time(String.valueOf(System.currentTimeMillis()));
|
||||
instanceTask.setUpdate_time(String.valueOf(System.currentTimeMillis()));
|
||||
instanceTask.setDisplay_method("BROWSER");
|
||||
instanceTasks.add(instanceTask);
|
||||
}
|
||||
approvalsInstanceVo.setTask_list(instanceTasks);
|
||||
// 国际化文案
|
||||
DefinitionI18nResources definitionI18nResources = new DefinitionI18nResources();
|
||||
definitionI18nResources.setLocale("zh-CN");
|
||||
definitionI18nResources.setIs_default(true);
|
||||
List<DefinitionTexts> texts = new ArrayList<>();
|
||||
texts.add(new DefinitionTexts("@i18n@1",instanceDto.getTitle()));
|
||||
definitionI18nResources.setTexts(texts);
|
||||
List<DefinitionI18nResources> i18n_resources = new ArrayList<>();
|
||||
i18n_resources.add(definitionI18nResources);
|
||||
approvalsInstanceVo.setI18n_resources(i18n_resources);
|
||||
return approvalsInstanceVo;
|
||||
}
|
||||
|
||||
private HttpHeaders createHeaders(String accessToken) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + accessToken);
|
||||
headers.set("Content-Type", "application/json");
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHrefMessageByBot(BotMessageDto botMessageDto) {
|
||||
String url = env.getProperty("feishu.bot_send_message");
|
||||
String signLoginUrl = env.getProperty("feishu.sign_login_in");
|
||||
assert url != null;
|
||||
assert signLoginUrl != null;
|
||||
try {
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 构建参数
|
||||
List<String> newPushRange = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(botMessageDto.getReceiveIds())) {
|
||||
List<String> pushRangeList = Arrays.asList(botMessageDto.getReceiveIds().split(","));
|
||||
for (String id : pushRangeList) {
|
||||
SysUser reviewUser = sysUserService.getById(id);
|
||||
if (!Objects.isNull(reviewUser) && StringUtils.isNotBlank(reviewUser.getFeishuId())) {
|
||||
newPushRange.add(reviewUser.getFeishuId());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newPushRange.isEmpty()) {
|
||||
log.error("接收消息的飞书用户均不存在,消息发送终止");
|
||||
return;
|
||||
}
|
||||
// 将url替换为单点登录的地址
|
||||
String hrefUrl = botMessageDto.getHrefUrl();
|
||||
if (StringUtils.isNotBlank(hrefUrl)) {
|
||||
hrefUrl = signLoginUrl.replace("{REDIRECT_URI}", hrefUrl);
|
||||
}
|
||||
// 构建消息内容部分
|
||||
JSONArray contentArray = new JSONArray();
|
||||
// 构建普通文本前缀
|
||||
if (StringUtils.isNotBlank(botMessageDto.getTextBeforeHref())) {
|
||||
JSONObject textBeforeHrefObject = new JSONObject();
|
||||
textBeforeHrefObject.put("tag", "text");
|
||||
textBeforeHrefObject.put("text", botMessageDto.getTextBeforeHref());
|
||||
contentArray.add(textBeforeHrefObject);
|
||||
}
|
||||
// 构建超链接文本
|
||||
if (StringUtils.isNotBlank(botMessageDto.getHrefText()) && StringUtils.isNotBlank(hrefUrl)) {
|
||||
JSONObject hrefContentObject = new JSONObject();
|
||||
hrefContentObject.put("tag", "a");
|
||||
hrefContentObject.put("href", hrefUrl);
|
||||
hrefContentObject.put("text", botMessageDto.getHrefText());
|
||||
contentArray.add(hrefContentObject);
|
||||
}
|
||||
// 构建普通文本后缀
|
||||
if (StringUtils.isNotBlank(botMessageDto.getTextAfterHref())) {
|
||||
JSONObject textAfterHrefObject = new JSONObject();
|
||||
textAfterHrefObject.put("tag", "text");
|
||||
textAfterHrefObject.put("text", botMessageDto.getTextAfterHref());
|
||||
contentArray.add(textAfterHrefObject);
|
||||
}
|
||||
|
||||
List<JSONArray> contentList = new ArrayList<>();
|
||||
contentList.add(contentArray);
|
||||
JSONObject zhCnObject = new JSONObject();
|
||||
zhCnObject.put("title", botMessageDto.getTitle());
|
||||
zhCnObject.put("content", contentList);
|
||||
JSONObject finalObject = new JSONObject();
|
||||
finalObject.put("zh_cn", zhCnObject);
|
||||
String content = finalObject.toJSONString();
|
||||
BotMessageVo botMessageVo = new BotMessageVo();
|
||||
botMessageVo.setMsg_type("post");
|
||||
botMessageVo.setContent(content);
|
||||
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 构建包含查询参数的 URL
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParam("receive_id_type", "user_id");
|
||||
// 创建 HttpEntity
|
||||
for (String pushId : newPushRange) {
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||
botMessageVo.setReceive_id(pushId);
|
||||
botMessageVo.setUuid(uuid);
|
||||
HttpEntity<BotMessageVo> entity = new HttpEntity<>(botMessageVo, headers);
|
||||
restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("飞书发送消息异常" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据预授权码获取用户信息
|
||||
*
|
||||
* @param codeObject
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Result<JSONObject> getUserInfoByCode(JSONObject codeObject) {
|
||||
String url = env.getProperty("feishu.get_userinfo_by_code");
|
||||
assert url != null;
|
||||
String code = codeObject.getString("code");
|
||||
// 获取token
|
||||
String accessToken = getAccessToken();
|
||||
// 设置请求头
|
||||
HttpHeaders headers = createHeaders(accessToken);
|
||||
// 创建 HttpEntity
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("grant_type","authorization_code");
|
||||
jsonObject.put("code",code);
|
||||
HttpEntity<JSONObject> entity = new HttpEntity<>(jsonObject, headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
// 处理响应
|
||||
Result<JSONObject> result = new Result<>();
|
||||
JSONObject jsonResponse = JSON.parseObject(response.getBody());
|
||||
if ("0".equals((String.valueOf(jsonResponse.get("code"))))) {
|
||||
JSONObject dataJson = jsonResponse.getJSONObject("data");
|
||||
String feishuId = dataJson.getString("user_id");
|
||||
// 从sys_user表查询对应的用户信息
|
||||
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(SysUser::getFeishuId,feishuId);
|
||||
SysUser suer = sysUserService.getOne(lambdaQueryWrapper);
|
||||
//用户登录信息
|
||||
userInfo(suer, result);
|
||||
} else {
|
||||
log.error("获取用户信息失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {
|
||||
String multiDepart ="multi_depart";
|
||||
String syspassword = sysUser.getPassword();
|
||||
String username = sysUser.getUsername();
|
||||
//获取用户角色信息
|
||||
String userId = sysUser.getId();
|
||||
if (StringUtils.isNotBlank(userId)){
|
||||
LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SysUserRole::getUserId, userId);
|
||||
List<SysUserRole> sysUserRoles = sysUserRoleService.list(wrapper);
|
||||
if (!sysUserRoles.isEmpty()){
|
||||
List<String> collect = sysUserRoles.stream().map(SysUserRole::getRoleId).distinct().collect(Collectors.toList());
|
||||
List<SysRole> roles = sysRoleService.listByIds(collect);
|
||||
String code = roles.stream().map(SysRole::getRoleCode).collect(Collectors.joining(","));
|
||||
sysUser.setRoleCode(code);
|
||||
}
|
||||
}
|
||||
// 获取用户部门信息
|
||||
JSONObject obj = new JSONObject();
|
||||
List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
|
||||
obj.put("departs", departs);
|
||||
if (departs == null || departs.isEmpty()) {
|
||||
obj.put(multiDepart, 0);
|
||||
} else if (departs.size() == 1) {
|
||||
sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
|
||||
obj.put(multiDepart, 1);
|
||||
} else {
|
||||
//查询当前是否有登录部门
|
||||
SysUser sysUserById = sysUserService.getById(sysUser.getId());
|
||||
if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){
|
||||
sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
|
||||
}
|
||||
obj.put(multiDepart, 2);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(departs)) {
|
||||
List<String> departIdList = departs.stream().map(SysDepart::getId).collect(Collectors.toList());
|
||||
sysUser.setDepartIds(StringUtils.join(departIdList, ","));
|
||||
}
|
||||
|
||||
String tenantIds = sysUser.getRelTenantIds();
|
||||
if (oConvertUtils.isNotEmpty(tenantIds)) {
|
||||
List<String> tenantIdList = Arrays.asList(tenantIds.split(","));
|
||||
// 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。
|
||||
List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList);
|
||||
if (tenantList.isEmpty()) {
|
||||
return Result.error("与该用户关联的租户均已被冻结,无法登录!");
|
||||
} else {
|
||||
obj.put("tenantList", tenantList);
|
||||
}
|
||||
}
|
||||
// 生成token
|
||||
String token = JwtUtil.sign(username, syspassword);
|
||||
// 设置token缓存有效时间
|
||||
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
|
||||
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
|
||||
String departIds = sysUser.getDepartIds();
|
||||
if (StringUtils.isNotBlank(departIds)) {
|
||||
String departIds_dicText = translateDictValue("id", "depart_name", "sys_depart", departIds, null);
|
||||
sysUser.setDepartIds_dicText(departIds_dicText);
|
||||
}
|
||||
obj.put("token", token);
|
||||
obj.put(USER_INFO, sysUser);
|
||||
obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
|
||||
result.setResult(obj);
|
||||
result.setMessage("登录成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
private String translateDictValue(String code, String text, String table, String key, List<SysDictItemCore> listDict) {
|
||||
if (oConvertUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder textValue = new StringBuilder();
|
||||
String[] keys = key.split(",");
|
||||
for (String k : keys) {
|
||||
String tmpValue = null;
|
||||
if (k.trim().length() == 0) {
|
||||
continue; //跳过循环
|
||||
}
|
||||
if (!org.springframework.util.StringUtils.isEmpty(table)) {
|
||||
tmpValue = commonAPI.queryTableDictTextByKey(table, text, code, k.trim());
|
||||
} else {
|
||||
List<SysDictItemCore> listNew = listDict.stream()
|
||||
.filter(o -> Objects.equals(o.getDictCode(), code) && Objects.equals(o.getItemValue(), k.trim())).collect(Collectors.toList());
|
||||
if (!org.springframework.util.CollectionUtils.isEmpty(listNew)) {
|
||||
tmpValue = listNew.get(0).getItemText();
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpValue != null) {
|
||||
if (!"".contentEquals(textValue)) {
|
||||
textValue.append(",");
|
||||
}
|
||||
textValue.append(tmpValue);
|
||||
}
|
||||
}
|
||||
return textValue.toString();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.jero.modules.docking.feishu.vo.bot;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BotMessageVo {
|
||||
|
||||
/**
|
||||
* 消息接收者的id
|
||||
*/
|
||||
@ApiModelProperty("消息接收者的ID")
|
||||
private String receive_id;
|
||||
|
||||
/**
|
||||
* 消息类型 包括:text、post、image、file、audio、media、
|
||||
* sticker、interactive、share_chat、share_user等
|
||||
*/
|
||||
@ApiModelProperty("消息类型")
|
||||
private String msg_type;
|
||||
|
||||
/**
|
||||
* 消息内容,JSON结构序列化后的字符串
|
||||
*/
|
||||
@ApiModelProperty("消息内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 由开发者生成的唯一字符串序列,用于发送消息请求去重;
|
||||
* 持有相同uuid的请求1小时内至多成功发送一条消息
|
||||
*/
|
||||
@ApiModelProperty("UUID")
|
||||
private String uuid;
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.jero.modules.docking.feishu.vo.definition;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApprovalsDefinitionVo {
|
||||
|
||||
/**
|
||||
*
|
||||
* 审批名称的国际化文案 Key,以 @i18n@ 开头,长度不得少于 9 个字符
|
||||
* 示例值: @i18n@1
|
||||
*/
|
||||
@ApiModelProperty("审批名称的国际化文案")
|
||||
private String approval_name;
|
||||
|
||||
/**
|
||||
*
|
||||
* 审批定义 code,用户自定义,定义的唯一标识,如果不存在该 code,则创建,否则更新
|
||||
* 示例值: permission_test
|
||||
*/
|
||||
@ApiModelProperty("审批定义code")
|
||||
private String approval_code;
|
||||
|
||||
/**
|
||||
*
|
||||
* 审批定义所属审批分组,用户自定义; 如果group_code当前不存在,则会新建审批分组;
|
||||
* 如果group_code已经存在,则会使用group_name更新审批分组名称
|
||||
* 示例值: work_group
|
||||
*/
|
||||
@ApiModelProperty("审批定义所属审批分组")
|
||||
private String group_code;
|
||||
|
||||
/**
|
||||
* 分组名称,值的格式是 i18n key,文案放在 i18n_resource;
|
||||
* 如果是 group_code 当前不存在,则该 group_name 必填,否则,
|
||||
* 如果填写了则会更新分组名称,不填则不更新分组名称;
|
||||
* 审批发起页 审批定义的分组名称来自该字段
|
||||
* 示例值: @i18n@2
|
||||
*/
|
||||
@ApiModelProperty("审批定义所属审批分组")
|
||||
private String group_name;
|
||||
|
||||
/**
|
||||
* 审批定义的说明,值的格式是 i18n key,文案放在 i18n_resource;
|
||||
* 审批发起页 审批定义的说明内容来自该字段
|
||||
* 示例值: @i18n@2
|
||||
*/
|
||||
@ApiModelProperty("审批定义的说明")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 三方审批相关
|
||||
*/
|
||||
@ApiModelProperty("三方审批相关")
|
||||
private DefinitionExternal external;
|
||||
|
||||
/**
|
||||
* 可见人列表(最大支持长度200),可通知配置多个可见人,
|
||||
* 只有在配置的范围内用户可以在审批发起页看到该审批,
|
||||
* 默认不传,则是任何人不可见
|
||||
*/
|
||||
@ApiModelProperty("可见人列表")
|
||||
private List<DefinitionViewers> viewers;
|
||||
|
||||
/**
|
||||
* 国际化文案
|
||||
*/
|
||||
@ApiModelProperty("国际化文案")
|
||||
private List<DefinitionI18nResources> i18n_resources;
|
||||
|
||||
/**
|
||||
* 根据user_id_type填写流程管理员id列表(最大支持长度200)
|
||||
* 示例值:["19a294c2"]
|
||||
*/
|
||||
@ApiModelProperty("流程管理员id列表")
|
||||
private String[] managers;
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package com.jero.modules.docking.feishu.vo.definition;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 三方审批相关
|
||||
*/
|
||||
@Data
|
||||
public class DefinitionExternal {
|
||||
|
||||
/**
|
||||
*
|
||||
* 列表中用于提示审批来自哪里,i18n key,
|
||||
* 注意不需要“来自”前缀,审批中心会拼上前缀
|
||||
* 示例值:"@i18n@3"
|
||||
*/
|
||||
@ApiModelProperty("列表中用于提示审批来自哪里")
|
||||
private String biz_name;
|
||||
|
||||
/**
|
||||
* 审批定义业务类别
|
||||
* 示例值:"permission"
|
||||
*/
|
||||
@ApiModelProperty("审批定义业务类别")
|
||||
private String biz_type;
|
||||
|
||||
/**
|
||||
* 移动端发起链接,如果设置了该链接,则会在移动端审批发起页展示该审批,
|
||||
* 用户点击后会跳转到该链接进行发起;
|
||||
* 如果不填,则在mobile端不显示该审批
|
||||
*/
|
||||
@ApiModelProperty("移动端发起链接")
|
||||
private String create_link_mobile;
|
||||
|
||||
/**
|
||||
* PC端发起链接,如果设置了该链接,则会在PC端审批发起页展示该审批,
|
||||
* 用户点击后会跳转到该链接进行发起;
|
||||
* 如果不填,则在PC端不显示该审批;
|
||||
*/
|
||||
@ApiModelProperty("PC端发起链接")
|
||||
private String create_link_pc;
|
||||
|
||||
/**
|
||||
* 审批实例、审批任务、审批抄送是否要在PC端展示,
|
||||
* 如果为 true,则PC端列表会展示该定义下的实例信息,否则,不展示
|
||||
*/
|
||||
@ApiModelProperty("审批实例、审批任务、审批抄送是否要在PC端展示")
|
||||
private boolean support_pc;
|
||||
|
||||
/**
|
||||
* 审批实例、审批任务、审批抄送是否要在移动端展示,
|
||||
* 如果为 true,则PC端列表会展示该定义下的实例信息,否则,不展示
|
||||
*/
|
||||
@ApiModelProperty("审批实例、审批任务、审批抄送是否要在移动端展示")
|
||||
private boolean support_mobile;
|
||||
|
||||
/**
|
||||
* 是否支持批量已读
|
||||
*/
|
||||
@ApiModelProperty("是否支持批量已读")
|
||||
private boolean support_batch_read;
|
||||
|
||||
/**
|
||||
* 是否支持批量已读(该字段无效)
|
||||
*/
|
||||
@ApiModelProperty("是否支持标注可读(该字段无效)")
|
||||
private boolean enable_mark_readed;
|
||||
|
||||
/**
|
||||
* 是否支持快速操作
|
||||
*/
|
||||
@ApiModelProperty("是否支持快速操作")
|
||||
private boolean enable_quick_operate;
|
||||
|
||||
/**
|
||||
* 三方系统的操作回调 url,【待审批】列表的任务审批人点同意或拒绝操作后,审批中心调用该地址通知三方系统
|
||||
*/
|
||||
@ApiModelProperty("三方系统的操作回调 url")
|
||||
private String action_callback_url;
|
||||
|
||||
/**
|
||||
* 回调时带的 token, 用于业务系统验证请求来自审批,
|
||||
*/
|
||||
@ApiModelProperty("回调时带的token")
|
||||
private String action_callback_token;
|
||||
|
||||
/**
|
||||
* 请求参数加密密钥,如果配置了该参数,则会对请求参数进行加密,业务需要对请求进行解密
|
||||
*/
|
||||
@ApiModelProperty("请求参数加密密钥")
|
||||
private String action_callback_key;
|
||||
|
||||
/**
|
||||
* 是否支持批量审批
|
||||
*/
|
||||
@ApiModelProperty("是否支持批量审批")
|
||||
private boolean allow_batch_operate;
|
||||
|
||||
/**
|
||||
* 审批流程数据是否不纳入效率统计
|
||||
*/
|
||||
@ApiModelProperty("审批流程数据是否不纳入效率统计")
|
||||
private boolean exclude_efficiency_statistics;
|
||||
|
||||
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.jero.modules.docking.feishu.vo.definition;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 国际化文案
|
||||
*/
|
||||
@Data
|
||||
public class DefinitionI18nResources {
|
||||
|
||||
/**
|
||||
* 语言可选值有: zh-CN:中文 en-US:英文 ja-JP:日文
|
||||
* 示例值:"zh-CN"
|
||||
* zh-CN:中文
|
||||
* en-US:英文
|
||||
* ja-JP:日文
|
||||
*/
|
||||
@ApiModelProperty("语言可选值有: zh-CN:中文 en-US:英文 ja-JP:日文")
|
||||
private String locale;
|
||||
|
||||
/**
|
||||
* 是否默认语言,默认语言需要包含所有key,非默认语言如果key不存在会使用默认语言代替
|
||||
*/
|
||||
@ApiModelProperty("是否默认语言,默认语言需要包含所有key,非默认语言如果key不存在会使用默认语言代替")
|
||||
@JSONField(name = "is_default")
|
||||
private boolean is_default;
|
||||
|
||||
/**
|
||||
* 示例值: "{ @i18n@1: 权限申请 }"
|
||||
*/
|
||||
@ApiModelProperty("{ @i18n@1: 权限申请 }")
|
||||
private List<DefinitionTexts> texts;
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public boolean isIs_default() {
|
||||
return is_default;
|
||||
}
|
||||
|
||||
public void setIs_default(boolean is_default) {
|
||||
this.is_default = is_default;
|
||||
}
|
||||
|
||||
public List<DefinitionTexts> getTexts() {
|
||||
return texts;
|
||||
}
|
||||
|
||||
public void setTexts(List<DefinitionTexts> texts) {
|
||||
this.texts = texts;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.jero.modules.docking.feishu.vo.definition;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DefinitionTexts {
|
||||
|
||||
public DefinitionTexts(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DefinitionTexts() {
|
||||
}
|
||||
|
||||
/**
|
||||
文案key
|
||||
示例值:"@i18n@1"
|
||||
*/
|
||||
@ApiModelProperty("文案key")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
文案
|
||||
示例值:"people"
|
||||
*/
|
||||
@ApiModelProperty("文案")
|
||||
private String value;
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.jero.modules.docking.feishu.vo.definition;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 可见人列表
|
||||
*/
|
||||
@Data
|
||||
public class DefinitionViewers {
|
||||
|
||||
/**
|
||||
可见人类型 示例值:"USER"
|
||||
* 可选值有:
|
||||
TENANT:租户内可见
|
||||
DEPARTMENT:指定部门
|
||||
USER:指定用户
|
||||
NONE:任何人都不可见
|
||||
*/
|
||||
@ApiModelProperty("可见人类型 TENANT:租户内可见 DEPARTMENT:指定部门 USER:指定用户 NONE:任何人都不可见")
|
||||
private String viewer_type;
|
||||
|
||||
/**
|
||||
* 当 viewer_type 是 USER,根据user_id_type填写用户id
|
||||
* 示例值:"19a294c2"
|
||||
*/
|
||||
@ApiModelProperty("当 viewer_type 是 USER,根据user_id_type填写用户id")
|
||||
private String viewer_user_id;
|
||||
|
||||
/**
|
||||
* 当 viewer_type 为DEPARTMENT,根据department_id_type填写部门id
|
||||
* 示例值:"od-ac9d697abfa990b715dcc33d58a62a9d"
|
||||
*/
|
||||
@ApiModelProperty("当 viewer_type 为DEPARTMENT,根据department_id_type填写部门id")
|
||||
private String viewer_department_id;
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package com.jero.modules.docking.feishu.vo.instance;
|
||||
|
||||
import com.jero.modules.docking.feishu.vo.definition.DefinitionI18nResources;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApprovalsInstanceVo {
|
||||
|
||||
/**
|
||||
* 审批定义 code, 创建审批定义返回的值,表示该实例属于哪个流程;
|
||||
* 该字段会影响到列表中该实例的标题,标题取自对应定义的 name 字段
|
||||
* 示例值:"81D31358-93AF-92D6-7425-01A5D67C4E71"
|
||||
*/
|
||||
@ApiModelProperty("审批定义 code")
|
||||
private String approval_code;
|
||||
|
||||
/**
|
||||
* 审批实例状态
|
||||
* 示例值:"PENDING"
|
||||
* PENDING: 审批中
|
||||
* APPROVED: 审批流程结束,结果为同意
|
||||
* REJECTED: 审批流程结束,结果为拒绝
|
||||
* CANCELED: 审批发起人撤回
|
||||
* DELETED: 审批被删除
|
||||
* HIDDEN: 状态隐藏(不显示状态)
|
||||
* TERMINATED:审批终止
|
||||
*/
|
||||
@ApiModelProperty("审批实例状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 审批实例扩展 JSON。单据编号通过传business_key字段来实现。
|
||||
* 以下示例值未转义,使用时请注意转义。
|
||||
* 你可查看请求体示例中转义后的 extra 示例值
|
||||
* 示例值:"{"xxx":"xxx","business_key":"xxx"}"
|
||||
*/
|
||||
@ApiModelProperty("审批实例扩展JSON")
|
||||
private String extra;
|
||||
|
||||
/**
|
||||
*
|
||||
* 审批实例唯一标识,用户自定义,需确保证租户和应用下都唯一
|
||||
* 示例值:"24492654"
|
||||
*/
|
||||
@ApiModelProperty("审批实例唯一标识")
|
||||
private String instance_id;
|
||||
|
||||
/**
|
||||
* 审批实例链接集合 ,
|
||||
* 用于【已发起】列表的跳转,跳转回三方系统
|
||||
*/
|
||||
@ApiModelProperty("审批实例链接集合")
|
||||
private InstanceLink links;
|
||||
|
||||
/**
|
||||
* 审批展示名称,如果填写了该字段,则审批列表中的审批名称使用该字段,
|
||||
* 如果不填该字段,则审批名称使用审批定义的名称
|
||||
* 示例值:"@i18n@1"
|
||||
*/
|
||||
@ApiModelProperty("审批展示名称")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 用户提交审批时填写的表单数据,用于所有审批列表中展示。可传多个值,
|
||||
* 但审批中心pc展示前2个,移动端展示前3个,长度不超过2048字符
|
||||
* 示例值:[{ "name": "@i18n@2", "value": "@i18n@3" }]
|
||||
*/
|
||||
@ApiModelProperty("用户提交审批时填写的表单数据")
|
||||
private List<InstanceForm> form;
|
||||
|
||||
/**
|
||||
*
|
||||
* 审批发起人 user_id,发起人可在【已发起】列表中看到所有已发起的审批;
|
||||
* 在【待审批】,【已审批】【抄送我】列表中,该字段展示审批是谁发起的。
|
||||
* 示例值:"a987sf9s"
|
||||
*/
|
||||
@ApiModelProperty("审批发起人 user_id")
|
||||
private String user_id;
|
||||
|
||||
/**
|
||||
* 审批发起人 用户名,如果发起人不是真实的用户(例如是某个部门),
|
||||
* 没有 user_id,则可以使用该字段传名称
|
||||
* 示例值:"@i18n@9"
|
||||
*/
|
||||
@ApiModelProperty("审批发起人 用户名")
|
||||
private String user_name;
|
||||
|
||||
/**
|
||||
* 审批发起人 open id
|
||||
* 示例值:"ou_be73cbc0ee35eb6ca54e9e7cc14998c1"
|
||||
*/
|
||||
@ApiModelProperty("审批发起人 open id")
|
||||
private String open_id;
|
||||
|
||||
/**
|
||||
* 发起人部门,用于列表中展示发起人所属部门。不传则不展示。
|
||||
* 如果用户没加入任何部门,传 "",将展示租户名称传 department_name 展示部门名称
|
||||
* 示例值:"od-8ec33278bc2"
|
||||
*/
|
||||
@ApiModelProperty("发起人部门")
|
||||
private String department_id;
|
||||
|
||||
/**
|
||||
* 审批发起人 部门,如果发起人不是真实的用户(例如是某个部门),
|
||||
* 没有 department_id,则可以使用该字段传名称
|
||||
* 示例值:"@i18n@10"
|
||||
*/
|
||||
@ApiModelProperty("审批发起人 部门")
|
||||
private String department_name;
|
||||
|
||||
/**
|
||||
* 审批发起时间,Unix毫秒时间戳
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("审批发起时间 Unix毫秒时间戳")
|
||||
private String start_time;
|
||||
|
||||
/**
|
||||
* 审批实例结束时间,Unix毫秒时间戳
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("审批实例结束时间 Unix毫秒时间戳")
|
||||
private String end_time;
|
||||
|
||||
/**
|
||||
* 审批实例最近更新时间;用于推送数据版本控制如果 update_mode 值为 UPDATE,
|
||||
* 则只有传过来的 update_time 有变化时(变大),才会更新审批中心中的审批实例信息。
|
||||
* 使用该字段主要用来避免并发时老的数据更新了新的数据
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("审批实例最近更新时间 Unix毫秒时间戳")
|
||||
private String update_time;
|
||||
|
||||
/**
|
||||
* 列表页打开审批实例的方式
|
||||
* 示例值:"BROWSER"
|
||||
* BROWSER:跳转系统默认浏览器打开
|
||||
* SIDEBAR:飞书中侧边抽屉打开
|
||||
* NORMAL:飞书内嵌页面打开
|
||||
* TRUSTEESHIP:以托管打开
|
||||
*/
|
||||
@ApiModelProperty("列表页打开审批实例的方式")
|
||||
private String display_method;
|
||||
|
||||
/**
|
||||
* 更新方式, 当 update_mode=REPLACE时,每次都以当前推送的数据为最终数据,会删掉审批中心中多余的任务、抄送数据(不在这次推送的数据中);
|
||||
* 当 update_mode=UPDATE时,则不会删除审批中心的数据,而只是进行新增和更新实例、任务数据
|
||||
* 示例值:"UPDATE"
|
||||
* 可选值有:
|
||||
* REPLACE:全量替换,默认值
|
||||
* UPDATE:增量更新
|
||||
*/
|
||||
@ApiModelProperty("列表页打开审批实例的方式")
|
||||
private String update_mode;
|
||||
|
||||
/**
|
||||
* 抄送列表
|
||||
*/
|
||||
@ApiModelProperty("任务列表")
|
||||
private List<InstanceTask> task_list;
|
||||
|
||||
/**
|
||||
* 国际化文案
|
||||
*/
|
||||
@ApiModelProperty("国际化文案")
|
||||
private List<DefinitionI18nResources> i18n_resources;
|
||||
|
||||
/**
|
||||
* 单据托管认证token,托管回调会附带此token,帮助业务方认证
|
||||
* 示例值:"788981c886b1c28ac29d1e68efd60683d6d90dfce80938ee9453e2a5f3e9e306"
|
||||
*/
|
||||
@ApiModelProperty("单据托管认证token")
|
||||
private String trusteeship_url_token;
|
||||
|
||||
/**
|
||||
* 用户的类型,会影响请求参数用户标识域的选择,包括加签操作回传的目标用户, 目前仅支持 "user_id"
|
||||
* 示例值:"user_id"
|
||||
*/
|
||||
@ApiModelProperty("用户的类型")
|
||||
private String trusteeship_user_id_type;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.jero.modules.docking.feishu.vo.instance;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class InstanceForm {
|
||||
|
||||
/**
|
||||
* 表单字段名称
|
||||
* 示例值:"@i18n@2"
|
||||
*/
|
||||
@ApiModelProperty("表单字段名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 表单值
|
||||
* 示例值:"@i18n@3"
|
||||
*/
|
||||
@ApiModelProperty("表单值")
|
||||
private String value;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.jero.modules.docking.feishu.vo.instance;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class InstanceLink {
|
||||
|
||||
/**
|
||||
* pc端的跳转链接,当用户使用飞书 pc 端时,
|
||||
* 使用该字段进行跳转,托管的链接保持不变。
|
||||
*/
|
||||
@ApiModelProperty("pc端的跳转链接")
|
||||
private String pc_link;
|
||||
|
||||
/**
|
||||
* 移动端的跳转链接,当用户使用飞书 pc 端时,
|
||||
* 使用该字段进行跳转,托管的链接保持不变。
|
||||
*/
|
||||
@ApiModelProperty("移动端的跳转链接")
|
||||
private String mobile_link;
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package com.jero.modules.docking.feishu.vo.instance;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 任务列表
|
||||
*/
|
||||
@Data
|
||||
public class InstanceTask {
|
||||
|
||||
/**
|
||||
* 审批实例内的唯一标识,用于更新审批任务时定位数据
|
||||
*/
|
||||
@ApiModelProperty("审批实例内的唯一标识")
|
||||
private String task_id;
|
||||
|
||||
/**
|
||||
* 审批人 user_id,和 open_id 二者至少填一个。
|
||||
* 该任务会出现在审批人的【待审批】或【已审批】列表中
|
||||
*/
|
||||
@ApiModelProperty("审批人 user_id")
|
||||
private String user_id;
|
||||
|
||||
/**
|
||||
* 审批人 open_id,和 user_id 二者至少填一个
|
||||
* 示例值:"ou_be73cbc0ee35eb6ca54e9e7cc14998c1"
|
||||
*/
|
||||
@ApiModelProperty("审批人 open_id")
|
||||
private String open_id;
|
||||
|
||||
/**
|
||||
* 审批任务名称
|
||||
* 示例值:"i18n1"
|
||||
*/
|
||||
@ApiModelProperty("审批任务名称")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 【待审批】或【已审批】中使用的跳转链接,
|
||||
* 用于跳转回三方系统pc_link 和 mobile_link 必须填一个,
|
||||
* 填写的是哪一端的链接,即会跳转到该链接,不受平台影响
|
||||
*/
|
||||
@ApiModelProperty("跳转链接")
|
||||
private InstanceLink links;
|
||||
|
||||
/**
|
||||
* 任务状态
|
||||
* 示例值:"PENDING"
|
||||
* 可选值有:
|
||||
* PENDING:待审批
|
||||
* APPROVED:任务同意
|
||||
* REJECTED:任务拒绝
|
||||
* TRANSFERRED:任务转交
|
||||
* DONE:任务通过但审批人未操作;审批人看不到这个任务, 若想要看到, 可以通过抄送该人.
|
||||
*/
|
||||
@ApiModelProperty("任务状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 扩展 json,任务结束原因需传complete_reason字段。枚举值与对应说明:
|
||||
* approved:同意
|
||||
* rejected:拒绝
|
||||
* node_auto_reject:(因逻辑判断产生的)自动拒绝
|
||||
* specific_rollback:退回(包括退回到发起人、退回到中间任一审批人)
|
||||
* add:并加签(添加新审批人,和我一起审批)
|
||||
* add_pre:前加签(添加新审批人,在我之前审批)
|
||||
* add_post:后加签(添加新审批人,在我之后审批)
|
||||
* delete_assignee:减签
|
||||
* forward: 手动转交
|
||||
* forward_resign:离职自动转交
|
||||
* recall:撤销(撤回单据,单据失效)
|
||||
* delete :删除审批单
|
||||
* admin_forward:管理员在后台操作转交
|
||||
* system_forward:系统自动转交
|
||||
* auto_skip:自动通过
|
||||
* manual_skip:手动跳过
|
||||
* submit_again:重新提交任务
|
||||
* restart:重新启动流程
|
||||
* others:其他(作为兜底)
|
||||
* 示例值:"{"xxx":"xxx","complete_reason":"approved"}"
|
||||
*/
|
||||
@ApiModelProperty("扩展 json")
|
||||
private String extra;
|
||||
|
||||
/**
|
||||
* 任务创建时间,Unix 毫秒时间戳
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("任务创建时间,Unix 毫秒时间戳")
|
||||
private String create_time;
|
||||
|
||||
/**
|
||||
* 任务完成时间:未结束的审批为 0,Unix 毫秒时间戳
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("任务完成时间:未结束的审批为 0,Unix 毫秒时间戳")
|
||||
private String end_time;
|
||||
|
||||
/**
|
||||
* task最近更新时间,用于推送数据版本控制; 更新策略同 instance 中的 update_time
|
||||
* 示例值:"1556468012678"
|
||||
*/
|
||||
@ApiModelProperty("任务完成时间:未结束的审批为 0,Unix 毫秒时间戳")
|
||||
private String update_time;
|
||||
|
||||
/**
|
||||
* 操作上下文,当用户操作时,
|
||||
* 回调请求中带上该参数,用于传递该任务的上下文数据
|
||||
* 示例值:"123456"
|
||||
*/
|
||||
@ApiModelProperty("操作上下文")
|
||||
private String action_context;
|
||||
|
||||
/**
|
||||
* 列表页打开审批任务的方式
|
||||
* 示例值:"BROWSER"
|
||||
* 可选值有:
|
||||
* BROWSER:跳转系统默认浏览器打开
|
||||
* SIDEBAR:飞书中侧边抽屉打开
|
||||
* NORMAL:飞书内嵌页面打开
|
||||
* TRUSTEESHIP:以托管模式打开
|
||||
*/
|
||||
@ApiModelProperty("列表页打开审批任务的方式")
|
||||
private String display_method;
|
||||
|
||||
/**
|
||||
* 三方任务支持不纳入效率统计。false:纳入效率统计。true:不纳入效率统计
|
||||
* 示例值:false
|
||||
* 默认值:false
|
||||
*/
|
||||
@ApiModelProperty("三方任务支持不纳入效率统计")
|
||||
private boolean exclude_statistics;
|
||||
|
||||
/**
|
||||
* 节点id:必须同时满足
|
||||
* 一个流程内,每个节点id唯一。如一个流程下「直属上级」、「隔级上级」等每个节点的Node_id均不一样
|
||||
* 同一个流程定义内,不同审批实例中的相同节点,Node_id要保持不变。例如张三和李四分别发起了请假申请,这2个审批实例中的「直属上级」节点的node_id应该保持一致
|
||||
* 示例值:"node"
|
||||
*/
|
||||
@ApiModelProperty("节点id")
|
||||
private String node_id;
|
||||
|
||||
/**
|
||||
* 节点名称,如「财务审批」「法务审批」,支持中英日三种语言。示例:i18n@name。需要在i18n_resources中传该名称对应的国际化文案
|
||||
* 示例值:"i18n@name"
|
||||
*/
|
||||
@ApiModelProperty("节点名称")
|
||||
private String node_name;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user