diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java new file mode 100644 index 000000000..18cc5e4ca --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 表单权限的枚举 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum BpmFieldPermissionEnum { + + EDITABLE(1, "可编辑"), + READONLY(2, "只读"), + HIDE(3, "隐藏"); + + private final Integer permission; + private final String name; + + public static BpmFieldPermissionEnum valueOf(Integer permission) { + return ArrayUtil.firstMatch(item -> item.getPermission().equals(permission), values()); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index 7d72a133b..1491e5fdd 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/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.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -19,6 +20,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; @@ -50,6 +52,8 @@ public class BpmTaskController { private BpmProcessInstanceService processInstanceService; @Resource private BpmFormService formService; + @Resource + private BpmProcessDefinitionService bpmProcessDefinitionService; @Resource private AdminUserApi adminUserApi; @@ -134,8 +138,10 @@ public class BpmTaskController { // 获得 Form Map Map formMap = formService.getFormMap( convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); + // 获得 BpmnModel + BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, - formMap, userMap, deptMap)); + formMap, userMap, deptMap,bpmnModel)); } @PutMapping("/approve") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 5f4e915d3..25fa107b0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/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; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.bpmn.model.BpmnModel; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; @@ -81,7 +82,8 @@ public interface BpmTaskConvert { HistoricProcessInstance processInstance, Map formMap, Map userMap, - Map deptMap) { + Map deptMap, + BpmnModel bpmnModel) { List taskVOList = CollectionUtils.convertList(taskList, task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); @@ -92,6 +94,10 @@ public interface BpmTaskConvert { // 表单信息 BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); if (form != null) { + // 测试一下权限处理 +// List afterChangedFields = BpmnFormUtils.changeCreateFormFiledPermissionRule(form.getFields(), +// BpmnModelUtils.parseFormFieldsPermission(bpmnModel, task.getTaskDefinitionKey())); + taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/SimpleModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/SimpleModelConstants.java new file mode 100644 index 000000000..bada4ecb8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/SimpleModelConstants.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +/** + * 仿钉钉快搭 JSON 常量信息 + * + * @author jason + */ +public interface SimpleModelConstants { + + /** + * 流程表单字段权限, 用于标记字段权限 + */ + String FIELDS_PERMISSION = "fieldsPermission"; + + /** + * 字段属性 + */ + String FIELD_ATTRIBUTE = "field"; + + /** + * 权限属性 + */ + String PERMISSION_ATTRIBUTE = "permission"; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index c514a97d7..56edb8c3d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; @@ -11,6 +14,9 @@ import org.flowable.common.engine.impl.util.io.BytesStreamSource; import java.util.*; +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELD_ATTRIBUTE; +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE; + /** * 流程模型转操作工具类 */ @@ -38,6 +44,23 @@ public class BpmnModelUtils { return candidateParam; } + public static Map parseFormFieldsPermission(BpmnModel bpmnModel, String flowElementId) { + FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId); + if (flowElement == null) { + return null; + } + final HashMap fieldsPermission = MapUtil.newHashMap(); + List extensionElements = flowElement.getExtensionElements().get(SimpleModelConstants.FIELDS_PERMISSION); + extensionElements.forEach(el -> { + String field = el.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FIELD_ATTRIBUTE); + String permission = el.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, SimpleModelConstants.PERMISSION_ATTRIBUTE); + if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) { + fieldsPermission.put(field, Integer.parseInt(permission)); + } + }); + return fieldsPermission; + } + /** * 根据节点,获取入口连线 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index dbf7d6473..c4d39709e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.TypeReference; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; @@ -8,11 +10,13 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import org.flowable.bpmn.BpmnAutoLayout; -import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.*; import java.util.List; +import java.util.Map; +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELDS_PERMISSION; import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE; import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX; @@ -71,7 +75,7 @@ public class SimpleModelUtils { case USER_TASK: case COPY_TASK: case PARALLEL_GATEWAY_JOIN: - case INCLUSIVE_GATEWAY_JOIN:{ + case INCLUSIVE_GATEWAY_JOIN: { SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null); mainProcess.addFlowElement(sequenceFlow); // 递归调用后续节点 @@ -80,7 +84,7 @@ public class SimpleModelUtils { } case PARALLEL_GATEWAY_FORK: case EXCLUSIVE_GATEWAY: - case INCLUSIVE_GATEWAY_FORK:{ + case INCLUSIVE_GATEWAY_FORK: { String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); List conditionNodes = node.getConditionNodes(); Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); @@ -202,15 +206,20 @@ public class SimpleModelUtils { serviceTask.setName(node.getName()); // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现; // @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners - addExtensionElement(node, serviceTask); + addCandidateElements(node, serviceTask); + return serviceTask; } - private static void addExtensionElement(BpmSimpleModelNodeVO node, FlowElement flowElement) { + + /** + * 给节点添加候选人元素 + */ + private static void addCandidateElements(BpmSimpleModelNodeVO node, FlowElement flowElement) { Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); - addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, candidateStrategy == null ? null : String.valueOf(candidateStrategy)); - addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); } @@ -245,16 +254,48 @@ public class SimpleModelUtils { UserTask userTask = new UserTask(); userTask.setId(node.getId()); userTask.setName(node.getName()); - addExtensionElement(node, userTask); + // TODO 暂时测试,后面去掉 + userTask.setFormKey("24"); + // 添加候选人元素 + addCandidateElements(node, userTask); + // 添加表单字段权限属性元素 + addFormFieldsPermission(node, userTask); return userTask; } - private static void addExtensionElement(FlowElement element, String namespace, String name, String value) { + /** + * 给节点添加表单字段权限元素 + */ + private static void addFormFieldsPermission(BpmSimpleModelNodeVO node, FlowElement flowElement) { + List> fieldsPermissions = MapUtil.get(node.getAttributes(), + FIELDS_PERMISSION, new TypeReference<>() {}); + if (CollUtil.isNotEmpty(fieldsPermissions)) { + fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FIELDS_PERMISSION, item)); + } + } + + private static void addExtensionElement(FlowElement element, String name, Map attributes) { + if (attributes == null) { + return; + } + ExtensionElement extensionElement = new ExtensionElement(); + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE); + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); + extensionElement.setName(name); + attributes.forEach((key, value) -> { + ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value); + extensionAttribute.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE); + extensionElement.addAttribute(extensionAttribute); + }); + element.addExtensionElement(extensionElement); + } + + private static void addExtensionElement(FlowElement element, String name, String value) { if (value == null) { return; } ExtensionElement extensionElement = new ExtensionElement(); - extensionElement.setNamespace(namespace); + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE); extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); extensionElement.setElementText(value); extensionElement.setName(name); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/util/BpmnFormUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/util/BpmnFormUtils.java new file mode 100644 index 000000000..c22385ea8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/util/BpmnFormUtils.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.bpm.service.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmFieldPermissionEnum; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.FIELD_ATTRIBUTE; + +/** + * Bpmn 流程表单相关工具方法 + * + * @author jason + */ +public class BpmnFormUtils { + private static final String CREATE_FORM_DISPLAY_ATTRIBUTE = "display"; + private static final String CREATE_FORM_DISABLED_ATTRIBUTE = "disabled"; + + /** + * 修改 form-create 表单组件字段权限规则: 包括可编辑、只读、隐藏规则 + * @param fields 字段规则 + * @param fieldsPermission 字段权限 + * @return 修改权限后的字段规则 + */ + public static List changeCreateFormFiledPermissionRule(List fields, Map fieldsPermission) { + if ( CollUtil.isEmpty(fields) || MapUtil.isEmpty(fieldsPermission)) { + return fields; + } + List afterChangedFields = new ArrayList<>(fields.size()); + fields.forEach( f-> { + Map fieldMap = JsonUtils.parseObject(f, new TypeReference<>() {}); + String field = ObjUtil.defaultIfNull(fieldMap.get(FIELD_ATTRIBUTE), Object::toString, ""); + if (StrUtil.isEmpty(field) || !fieldsPermission.containsKey(field)) { + afterChangedFields.add(f); + return; + } + BpmFieldPermissionEnum fieldPermission = BpmFieldPermissionEnum.valueOf(fieldsPermission.get(field)); + Assert.notNull(fieldPermission, "字段权限不匹配"); + if (BpmFieldPermissionEnum.HIDE == fieldPermission) { + fieldMap.put(CREATE_FORM_DISPLAY_ATTRIBUTE, Boolean.FALSE); + } else if (BpmFieldPermissionEnum.EDITABLE == fieldPermission){ + Map props = MapUtil.get(fieldMap, "props", new cn.hutool.core.lang.TypeReference<>() {}); + if (props == null) { + props = MapUtil.newHashMap(); + fieldMap.put("props", props); + } + props.put(CREATE_FORM_DISABLED_ATTRIBUTE, Boolean.FALSE); + } else if (BpmFieldPermissionEnum.READONLY == fieldPermission) { + Map props = MapUtil.get(fieldMap, "props", new cn.hutool.core.lang.TypeReference<>() {}); + if (props == null) { + props = MapUtil.newHashMap(); + fieldMap.put("props", props); + } + props.put(CREATE_FORM_DISABLED_ATTRIBUTE, Boolean.TRUE); + } + afterChangedFields.add(JsonUtils.toJsonString(fieldMap)); + }); + return afterChangedFields; + } +}