Commit 1e30e4851a3841606292bf572c6a866bffae8c04

Authored by jason
1 parent 9456d461

仿钉钉流程设计- 流程表单字段权限测试

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +/**
  8 + * BPM 表单权限的枚举
  9 + *
  10 + * @author jason
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum BpmFieldPermissionEnum {
  15 +
  16 + EDITABLE(1, "可编辑"),
  17 + READONLY(2, "只读"),
  18 + HIDE(3, "隐藏");
  19 +
  20 + private final Integer permission;
  21 + private final String name;
  22 +
  23 + public static BpmFieldPermissionEnum valueOf(Integer permission) {
  24 + return ArrayUtil.firstMatch(item -> item.getPermission().equals(permission), values());
  25 + }
  26 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
8 8 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
9 9 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
10 10 import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
  11 +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
11 12 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
12 13 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
13 14 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
... ... @@ -19,6 +20,7 @@ import io.swagger.v3.oas.annotations.Parameter;
19 20 import io.swagger.v3.oas.annotations.tags.Tag;
20 21 import jakarta.annotation.Resource;
21 22 import jakarta.validation.Valid;
  23 +import org.flowable.bpmn.model.BpmnModel;
22 24 import org.flowable.bpmn.model.UserTask;
23 25 import org.flowable.engine.history.HistoricProcessInstance;
24 26 import org.flowable.engine.runtime.ProcessInstance;
... ... @@ -50,6 +52,8 @@ public class BpmTaskController {
50 52 private BpmProcessInstanceService processInstanceService;
51 53 @Resource
52 54 private BpmFormService formService;
  55 + @Resource
  56 + private BpmProcessDefinitionService bpmProcessDefinitionService;
53 57  
54 58 @Resource
55 59 private AdminUserApi adminUserApi;
... ... @@ -134,8 +138,10 @@ public class BpmTaskController {
134 138 // 获得 Form Map
135 139 Map<Long, BpmFormDO> formMap = formService.getFormMap(
136 140 convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey())));
  141 + // 获得 BpmnModel
  142 + BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId());
137 143 return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance,
138   - formMap, userMap, deptMap));
  144 + formMap, userMap, deptMap,bpmnModel));
139 145 }
140 146  
141 147 @PutMapping("/approve")
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
... ... @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
13 13 import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
14 14 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
15 15 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  16 +import org.flowable.bpmn.model.BpmnModel;
16 17 import org.flowable.engine.history.HistoricProcessInstance;
17 18 import org.flowable.engine.runtime.ProcessInstance;
18 19 import org.flowable.task.api.Task;
... ... @@ -81,7 +82,8 @@ public interface BpmTaskConvert {
81 82 HistoricProcessInstance processInstance,
82 83 Map<Long, BpmFormDO> formMap,
83 84 Map<Long, AdminUserRespDTO> userMap,
84   - Map<Long, DeptRespDTO> deptMap) {
  85 + Map<Long, DeptRespDTO> deptMap,
  86 + BpmnModel bpmnModel) {
85 87 List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(taskList, task -> {
86 88 BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
87 89 taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task));
... ... @@ -92,6 +94,10 @@ public interface BpmTaskConvert {
92 94 // 表单信息
93 95 BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class);
94 96 if (form != null) {
  97 + // 测试一下权限处理
  98 +// List<String> afterChangedFields = BpmnFormUtils.changeCreateFormFiledPermissionRule(form.getFields(),
  99 +// BpmnModelUtils.parseFormFieldsPermission(bpmnModel, task.getTaskDefinitionKey()));
  100 +
95 101 taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf())
96 102 .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task));
97 103 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/SimpleModelConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums;
  2 +
  3 +/**
  4 + * 仿钉钉快搭 JSON 常量信息
  5 + *
  6 + * @author jason
  7 + */
  8 +public interface SimpleModelConstants {
  9 +
  10 + /**
  11 + * 流程表单字段权限, 用于标记字段权限
  12 + */
  13 + String FIELDS_PERMISSION = "fieldsPermission";
  14 +
  15 + /**
  16 + * 字段属性
  17 + */
  18 + String FIELD_ATTRIBUTE = "field";
  19 +
  20 + /**
  21 + * 权限属性
  22 + */
  23 + String PERMISSION_ATTRIBUTE = "permission";
  24 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.map.MapUtil;
4 5 import cn.hutool.core.util.ArrayUtil;
  6 +import cn.hutool.core.util.StrUtil;
5 7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
6 8 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  9 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants;
7 10 import org.flowable.bpmn.converter.BpmnXMLConverter;
8 11 import org.flowable.bpmn.model.Process;
9 12 import org.flowable.bpmn.model.*;
... ... @@ -11,6 +14,9 @@ import org.flowable.common.engine.impl.util.io.BytesStreamSource;
11 14  
12 15 import java.util.*;
13 16  
  17 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELD_ATTRIBUTE;
  18 +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
  19 +
14 20 /**
15 21 * 流程模型转操作工具类
16 22 */
... ... @@ -38,6 +44,23 @@ public class BpmnModelUtils {
38 44 return candidateParam;
39 45 }
40 46  
  47 + public static Map<String,Integer> parseFormFieldsPermission(BpmnModel bpmnModel, String flowElementId) {
  48 + FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId);
  49 + if (flowElement == null) {
  50 + return null;
  51 + }
  52 + final HashMap<String, Integer> fieldsPermission = MapUtil.newHashMap();
  53 + List<ExtensionElement> extensionElements = flowElement.getExtensionElements().get(SimpleModelConstants.FIELDS_PERMISSION);
  54 + extensionElements.forEach(el -> {
  55 + String field = el.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FIELD_ATTRIBUTE);
  56 + String permission = el.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, SimpleModelConstants.PERMISSION_ATTRIBUTE);
  57 + if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) {
  58 + fieldsPermission.put(field, Integer.parseInt(permission));
  59 + }
  60 + });
  61 + return fieldsPermission;
  62 + }
  63 +
41 64 /**
42 65 * 根据节点,获取入口连线
43 66 *
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.lang.TypeReference;
4 6 import cn.hutool.core.map.MapUtil;
5 7 import cn.hutool.core.util.ArrayUtil;
6 8 import cn.hutool.core.util.StrUtil;
... ... @@ -8,11 +10,13 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp
8 10 import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
9 11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
10 12 import org.flowable.bpmn.BpmnAutoLayout;
11   -import org.flowable.bpmn.model.*;
12 13 import org.flowable.bpmn.model.Process;
  14 +import org.flowable.bpmn.model.*;
13 15  
14 16 import java.util.List;
  17 +import java.util.Map;
15 18  
  19 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELDS_PERMISSION;
16 20 import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
17 21 import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
18 22  
... ... @@ -71,7 +75,7 @@ public class SimpleModelUtils {
71 75 case USER_TASK:
72 76 case COPY_TASK:
73 77 case PARALLEL_GATEWAY_JOIN:
74   - case INCLUSIVE_GATEWAY_JOIN:{
  78 + case INCLUSIVE_GATEWAY_JOIN: {
75 79 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null);
76 80 mainProcess.addFlowElement(sequenceFlow);
77 81 // 递归调用后续节点
... ... @@ -80,7 +84,7 @@ public class SimpleModelUtils {
80 84 }
81 85 case PARALLEL_GATEWAY_FORK:
82 86 case EXCLUSIVE_GATEWAY:
83   - case INCLUSIVE_GATEWAY_FORK:{
  87 + case INCLUSIVE_GATEWAY_FORK: {
84 88 String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId();
85 89 List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
86 90 Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");
... ... @@ -202,15 +206,20 @@ public class SimpleModelUtils {
202 206 serviceTask.setName(node.getName());
203 207 // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现;
204 208 // @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners
205   - addExtensionElement(node, serviceTask);
  209 + addCandidateElements(node, serviceTask);
  210 +
206 211 return serviceTask;
207 212 }
208 213  
209   - private static void addExtensionElement(BpmSimpleModelNodeVO node, FlowElement flowElement) {
  214 +
  215 + /**
  216 + * 给节点添加候选人元素
  217 + */
  218 + private static void addCandidateElements(BpmSimpleModelNodeVO node, FlowElement flowElement) {
210 219 Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY);
211   - addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
  220 + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
212 221 candidateStrategy == null ? null : String.valueOf(candidateStrategy));
213   - addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM,
  222 + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM,
214 223 MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
215 224 }
216 225  
... ... @@ -245,16 +254,48 @@ public class SimpleModelUtils {
245 254 UserTask userTask = new UserTask();
246 255 userTask.setId(node.getId());
247 256 userTask.setName(node.getName());
248   - addExtensionElement(node, userTask);
  257 + // TODO 暂时测试,后面去掉
  258 + userTask.setFormKey("24");
  259 + // 添加候选人元素
  260 + addCandidateElements(node, userTask);
  261 + // 添加表单字段权限属性元素
  262 + addFormFieldsPermission(node, userTask);
249 263 return userTask;
250 264 }
251 265  
252   - private static void addExtensionElement(FlowElement element, String namespace, String name, String value) {
  266 + /**
  267 + * 给节点添加表单字段权限元素
  268 + */
  269 + private static void addFormFieldsPermission(BpmSimpleModelNodeVO node, FlowElement flowElement) {
  270 + List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(),
  271 + FIELDS_PERMISSION, new TypeReference<>() {});
  272 + if (CollUtil.isNotEmpty(fieldsPermissions)) {
  273 + fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FIELDS_PERMISSION, item));
  274 + }
  275 + }
  276 +
  277 + private static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) {
  278 + if (attributes == null) {
  279 + return;
  280 + }
  281 + ExtensionElement extensionElement = new ExtensionElement();
  282 + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  283 + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
  284 + extensionElement.setName(name);
  285 + attributes.forEach((key, value) -> {
  286 + ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value);
  287 + extensionAttribute.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  288 + extensionElement.addAttribute(extensionAttribute);
  289 + });
  290 + element.addExtensionElement(extensionElement);
  291 + }
  292 +
  293 + private static void addExtensionElement(FlowElement element, String name, String value) {
253 294 if (value == null) {
254 295 return;
255 296 }
256 297 ExtensionElement extensionElement = new ExtensionElement();
257   - extensionElement.setNamespace(namespace);
  298 + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
258 299 extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
259 300 extensionElement.setElementText(value);
260 301 extensionElement.setName(name);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/util/BpmnFormUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.util;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.map.MapUtil;
  6 +import cn.hutool.core.util.ObjUtil;
  7 +import cn.hutool.core.util.StrUtil;
  8 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  9 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmFieldPermissionEnum;
  10 +import com.fasterxml.jackson.core.type.TypeReference;
  11 +
  12 +import java.util.ArrayList;
  13 +import java.util.List;
  14 +import java.util.Map;
  15 +
  16 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELD_ATTRIBUTE;
  17 +
  18 +/**
  19 + * Bpmn 流程表单相关工具方法
  20 + *
  21 + * @author jason
  22 + */
  23 +public class BpmnFormUtils {
  24 + private static final String CREATE_FORM_DISPLAY_ATTRIBUTE = "display";
  25 + private static final String CREATE_FORM_DISABLED_ATTRIBUTE = "disabled";
  26 +
  27 + /**
  28 + * 修改 form-create 表单组件字段权限规则: 包括可编辑、只读、隐藏规则
  29 + * @param fields 字段规则
  30 + * @param fieldsPermission 字段权限
  31 + * @return 修改权限后的字段规则
  32 + */
  33 + public static List<String> changeCreateFormFiledPermissionRule(List<String> fields, Map<String,Integer> fieldsPermission) {
  34 + if ( CollUtil.isEmpty(fields) || MapUtil.isEmpty(fieldsPermission)) {
  35 + return fields;
  36 + }
  37 + List<String> afterChangedFields = new ArrayList<>(fields.size());
  38 + fields.forEach( f-> {
  39 + Map<String, Object> fieldMap = JsonUtils.parseObject(f, new TypeReference<>() {});
  40 + String field = ObjUtil.defaultIfNull(fieldMap.get(FIELD_ATTRIBUTE), Object::toString, "");
  41 + if (StrUtil.isEmpty(field) || !fieldsPermission.containsKey(field)) {
  42 + afterChangedFields.add(f);
  43 + return;
  44 + }
  45 + BpmFieldPermissionEnum fieldPermission = BpmFieldPermissionEnum.valueOf(fieldsPermission.get(field));
  46 + Assert.notNull(fieldPermission, "字段权限不匹配");
  47 + if (BpmFieldPermissionEnum.HIDE == fieldPermission) {
  48 + fieldMap.put(CREATE_FORM_DISPLAY_ATTRIBUTE, Boolean.FALSE);
  49 + } else if (BpmFieldPermissionEnum.EDITABLE == fieldPermission){
  50 + Map<String, Object> props = MapUtil.get(fieldMap, "props", new cn.hutool.core.lang.TypeReference<>() {});
  51 + if (props == null) {
  52 + props = MapUtil.newHashMap();
  53 + fieldMap.put("props", props);
  54 + }
  55 + props.put(CREATE_FORM_DISABLED_ATTRIBUTE, Boolean.FALSE);
  56 + } else if (BpmFieldPermissionEnum.READONLY == fieldPermission) {
  57 + Map<String, Object> props = MapUtil.get(fieldMap, "props", new cn.hutool.core.lang.TypeReference<>() {});
  58 + if (props == null) {
  59 + props = MapUtil.newHashMap();
  60 + fieldMap.put("props", props);
  61 + }
  62 + props.put(CREATE_FORM_DISABLED_ATTRIBUTE, Boolean.TRUE);
  63 + }
  64 + afterChangedFields.add(JsonUtils.toJsonString(fieldMap));
  65 + });
  66 + return afterChangedFields;
  67 + }
  68 +}
... ...