|
@@ -0,0 +1,101 @@
|
|
|
+package com.malk.mcli.controller;
|
|
|
+
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.malk.server.aliwork.YDConf;
|
|
|
+import com.malk.server.aliwork.YDParam;
|
|
|
+import com.malk.server.common.McException;
|
|
|
+import com.malk.server.common.McR;
|
|
|
+import com.malk.service.aliwork.YDClient;
|
|
|
+import com.malk.utils.UtilMap;
|
|
|
+import com.malk.utils.UtilServlet;
|
|
|
+import lombok.SneakyThrows;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 错误抛出与拦截详见CatchException
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RestController
|
|
|
+@RequestMapping("/matrix")
|
|
|
+public class ApprovalMatrixController {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 审批矩阵验证说明
|
|
|
+ * 1. 审批预览
|
|
|
+ * - 审批预览会调用矩阵接口, 预览开启若存在超时情况不能发起
|
|
|
+ * - 预览若是节点报错, 则可以正常发起, 预览时该节点不会显示 [ 若是通过预览实现强管控, 可在异常内添加超时机制, 控制不能发起 ]
|
|
|
+ * 2. 超时情况
|
|
|
+ * - 目前官方给到默认 timeout 5s, 且不支持配置
|
|
|
+ * - 审批流程会等待全部节点请求返回后才会显示, 数据提交后若某一个节点超时, 则该节点审批人不显示 [ 可搭配缓存逻辑, 关闭提交预览 ]
|
|
|
+ * 3. 抛出异常
|
|
|
+ * - 触发: 1. 节点返回为空, 且未配置为空自动通过; 2. 节点抛出异常
|
|
|
+ * - 若是第一个节点就异常, 管理员可在管理后台, 数据列表页面点击重试按钮进行重新激活
|
|
|
+ * - 若是中途节点, 该节点审批会发挥接口抛出异常信息, 若是返回空切设置为空不自动通过, 则会抛出审批人不能为空异常提醒, 流程点击同意都不能向下流转
|
|
|
+ * 4. 缓存逻辑
|
|
|
+ * - 原理: 缓存机制基于唯一ID, 自定义或数据实例Id, 否则额若传递矩阵参数会增加矩阵配置复杂度\降低其灵活性
|
|
|
+ * - 1. 若是节点可保障在 timeout 前返回, 可基于自定义 ID 进行数据缓存, 通过预览触发缓存, 节点异常通过超时控制不能发起, 同时解决发起异常问题
|
|
|
+ * - 2. 若节点存在超时情况多, 且可忽略预览效果情况下, 可通过数据实例ID缓存, 首次打开可能显示不全, 缓存成功后直接加载
|
|
|
+ * - 兜底: 缓存成功先返回缓存数据, 后台持续执行更新逻辑, 兼容条件\人员矩阵变更, 未到达审批节点更新. 若是存在退回场景, 可触发新的审批人员修正
|
|
|
+ * 5. 待办推送
|
|
|
+ * - 第一个节点异常重新激活的流程, 待办会正常触发推送
|
|
|
+ * - 未执行到节点, 若人员变更, 会在执行到该节点时触发待办推送 [ 目前转交有api可调用 ]
|
|
|
+ * 6. 补充说明
|
|
|
+ * - 已跳过/审批中节点, 再次打开不会触发调用, 未触发的节点, 每次页面打开都会触发调用 [ 缓存可很好降低并发问题 ]
|
|
|
+ * - 若是设置了为空自动通过, 流程会自动忽略该节点, 自动到下一个节点. 已跳过/审批中节点, 再次打开不会触发调用, 通过退回到该节点前可重新激活
|
|
|
+ * 7. 功能优化
|
|
|
+ * - 目前采用缓存方案2, 后续可考虑切换缓存方案1, 若是存在超时场景, 需要对组织架构\矩阵数据缓存, 解决QPS导致超时问题
|
|
|
+ * - 矩阵审批节点全部配置为空不允许自动通过 (默认配置), 是否为空可配置矩阵逻辑内, 避免审批节点丢失 [ 实现逻辑: 若审批可为空, 且该节点为空, 返回系统审批账号, 再调用自动同意 ]
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ @PostMapping("approval")
|
|
|
+ List<String> approvalMatrix(HttpServletRequest request) {
|
|
|
+
|
|
|
+ Map data = UtilServlet.getParamMap(request);
|
|
|
+ log.info("审批矩阵, {}", data);
|
|
|
+
|
|
|
+ McException.assertAccessException("是".equals(UtilMap.getString(data, "exception")), "抛出异常");
|
|
|
+
|
|
|
+ if (!"是".equals(UtilMap.getString(data, "cache_r"))) {
|
|
|
+ int s = UtilMap.getInt(data, "sleep_s");
|
|
|
+ if (s > 0) {
|
|
|
+ Thread.sleep(s * 1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (List<String>) JSONObject.parse(String.valueOf(JSONObject.parse(UtilMap.getString(data, "employeeField_"))));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static final String appType_Tech = "APP_H3A35LRTTIQZE14NMCIA";
|
|
|
+ private static final String systemToken_Tech = "1IC66671L7UO3SA58DBNM6269FP12LNO9YE1MHA1";
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private YDClient ydClient;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 审批记录接口,会返回未执行的节点. 同时返回 type \ actionExit, 可用于区分 历史 \ 进行中 \ 未到达 状态
|
|
|
+ */
|
|
|
+ @GetMapping("record")
|
|
|
+ McR approvalRecord(@RequestParam String processInstanceId) {
|
|
|
+
|
|
|
+ log.info("审批记录, {}", processInstanceId);
|
|
|
+
|
|
|
+ List<Map> records = (List<Map>) ydClient.queryData(YDParam.builder()
|
|
|
+ .appType(appType_Tech)
|
|
|
+ .systemToken(systemToken_Tech)
|
|
|
+ .processInstanceId(processInstanceId)
|
|
|
+ .build(), YDConf.FORM_QUERY.retrieve_approval_record).getResult();
|
|
|
+ return McR.success(records);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自动化、编辑事件则是只要更新就会执行。通过api 则需要传递更新执行参数,才会触发业务规则
|
|
|
+ */
|
|
|
+
|
|
|
+}
|