Commit 16e0bebd30ed604e23f122faaeb43161c16c3ae4
Merge branch 'master-jdk17' of https://github.com/YunaiV/ruoyi-vue-pro into master-jdk17
Showing
2 changed files
with
45 additions
and
0 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
| ... | ... | @@ -44,6 +44,7 @@ public interface ErrorCodeConstants { |
| 44 | 44 | ErrorCode PROCESS_INSTANCE_HTTP_CALL_ERROR = new ErrorCode(1_009_004_006, "流程 Http 请求调用失败"); |
| 45 | 45 | ErrorCode PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_007, "下一个任务({})的审批人未配置"); |
| 46 | 46 | ErrorCode PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_008, "子流程取消失败,子流程不允许取消"); |
| 47 | + ErrorCode PROCESS_INSTANCE_START_FORM_FIELD_REQUIRED = new ErrorCode(1_009_004_009, "发起流程失败,表单字段({})为必填项,不能为空"); | |
| 47 | 48 | |
| 48 | 49 | // ========== 流程任务 1-009-005-000 ========== |
| 49 | 50 | ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你"); | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| ... | ... | @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; |
| 22 | 22 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| 23 | 23 | import cn.iocoder.yudao.module.bpm.dal.redis.BpmProcessIdRedisDAO; |
| 24 | 24 | import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; |
| 25 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; | |
| 25 | 26 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; |
| 26 | 27 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeTypeEnum; |
| 27 | 28 | import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; |
| ... | ... | @@ -763,11 +764,54 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 763 | 764 | // 获得流程定义 |
| 764 | 765 | ProcessDefinition definition = processDefinitionService |
| 765 | 766 | .getProcessDefinition(createReqVO.getProcessDefinitionId()); |
| 767 | + // 校验动态表单必填字段(前端校验可被接口直调绕过,后端必须兜底,否则必填缺失也会建成脏实例) | |
| 768 | + validateDynamicFormRequiredFields(definition, createReqVO.getVariables()); | |
| 766 | 769 | // 发起流程 |
| 767 | 770 | return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, |
| 768 | 771 | createReqVO.getStartUserSelectAssignees()); |
| 769 | 772 | } |
| 770 | 773 | |
| 774 | + /** | |
| 775 | + * 校验动态表单(formType=10 流程表单)的必填字段 | |
| 776 | + * | |
| 777 | + * 注意:仅校验接口发起(VO 路径)入口。内部业务链路(DTO 路径,例如 OA 请假) | |
| 778 | + * 由业务代码自行组装变量,不经过本校验,避免误伤。 | |
| 779 | + */ | |
| 780 | + private void validateDynamicFormRequiredFields(ProcessDefinition definition, Map<String, Object> variables) { | |
| 781 | + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService | |
| 782 | + .getProcessDefinitionInfo(definition.getId()); | |
| 783 | + if (processDefinitionInfo == null | |
| 784 | + || !BpmModelFormTypeEnum.NORMAL.getType().equals(processDefinitionInfo.getFormType()) | |
| 785 | + || CollUtil.isEmpty(processDefinitionInfo.getFormFields())) { | |
| 786 | + return; | |
| 787 | + } | |
| 788 | + List<String> fieldStrs = processDefinitionInfo.getFormFields(); | |
| 789 | + // formFields 是 JSON 数组,每个元素本身又是 JSON 字符串;两种表单设计器并存: | |
| 790 | + // 字段标识可能是 field 或 key,必填标记可能是数组 ["required"] 或对象 {"required": true} | |
| 791 | + for (String fieldStr : fieldStrs) { | |
| 792 | + Map<String, Object> field = JsonUtils.parseMap(fieldStr); | |
| 793 | + boolean required = false; | |
| 794 | + Object validate = field.get("validate"); | |
| 795 | + if (validate instanceof List) { | |
| 796 | + required = ((List<?>) validate).contains("required"); | |
| 797 | + } else if (validate instanceof Map) { | |
| 798 | + required = Boolean.TRUE.equals(((Map<?, ?>) validate).get("required")); | |
| 799 | + } | |
| 800 | + if (!required) { | |
| 801 | + continue; | |
| 802 | + } | |
| 803 | + String fieldId = Convert.toStr(field.get("field"), Convert.toStr(field.get("key"))); | |
| 804 | + if (StrUtil.isEmpty(fieldId)) { | |
| 805 | + continue; | |
| 806 | + } | |
| 807 | + Object value = variables == null ? null : variables.get(fieldId); | |
| 808 | + if (value == null || (value instanceof String && StrUtil.isBlank((String) value))) { | |
| 809 | + throw exception(PROCESS_INSTANCE_START_FORM_FIELD_REQUIRED, | |
| 810 | + Convert.toStr(field.get("title"), fieldId)); | |
| 811 | + } | |
| 812 | + } | |
| 813 | + } | |
| 814 | + | |
| 771 | 815 | @Override |
| 772 | 816 | @DataPermission(enable = false) // 关闭数据权限,避免查询不到用户数据。相关案例:https://gitee.com/zhijiantianya/yudao-cloud/issues/ID1UYA |
| 773 | 817 | public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { | ... | ... |