自定义UI对象转流程节点
自定义UI对象转流程节点
- 实体
- 自定义对象转bpmn
activitiy学习 (动态加签,动态流程图,指定节点跳转,指定多人节点跳转)
前端页面仿的这个
提供一个思路
实体
- ActivitiValueVo
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;
import java.util.Map;@Data
@ApiModel(value = "ActivitiValueVo对象", description = "流程设计主体对象")
public class ActivitiValueVo implements Serializable {private static final long serialVersionUID = -3200115152519475826L;private Integer tableId;/*** 审批名称*/private String workFlowDef;private Integer directorMaxLevel;private String flowPermission;@ApiModelProperty("流程节点")private ChildNodeVo nodeConfig;@ApiModelProperty("发起人提交参数")private Map<String, Object> paramValueMap;@ApiModelProperty(value = "租户id")private Long tenantId;
}
- ChildNodeVo
import cn.morimatsu.phegda.pojo.dto.activiti.ActivitiUserDTO;
import cn.morimatsu.phegda.pojo.vo.common.ActOrderTableFieldVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;
import java.util.List;
import java.util.Map;@Data
@ApiModel(value = "ChildNodeVo对象", description = "流程节点对象")
public class ChildNodeVo implements Serializable {private static final long serialVersionUID = -5222393104041946672L;/*** 前端展示唯一标识*/@ApiModelProperty("前端展示唯一标识")private String id;/*** 节点Id*/@ApiModelProperty("节点Id")private String nodeId;/*** 节点名称*/@ApiModelProperty("节点名称")private String nodeName;private String error;/*** 类型 : 0,发起人;1,审核人;2,抄送人;3,条件;4,路由;5,条件默认*/@ApiModelProperty("类型 : 0,发起人;1,审核人;2,抄送人;3,条件;4,路由;5,条件默认")private Integer type;@ApiModelProperty("是否禁止编辑: true:禁止编辑")private Boolean disabled;private Integer priorityLevel;/*** 操作类型:1,指定成员;5,发起人;2,部门负责人;*/@ApiModelProperty("操作类型:4,指定成员;5,发起人;2,部门负责人;3:报修人(仅工单验收);")private Integer settype;/*** 部门负责人操作类型:null or 0,自动通过;1,指定审批人*/@ApiModelProperty("部门负责人找不到操作类型:null or 0,自动通过;1,指定审批人")private Integer deptDirectorTaskType;@ApiModelProperty("部门负责人找不到指定审批人")private ActivitiUserDTO deptDirectorTaskUser;private Integer selectMode;private Integer selectRange;private Integer directorLevel;/*** 多人审批时采用的审批方式:0,会签(需所有审批人同意);1,或签(一名审批人同意或拒绝即可)*/@ApiModelProperty("多人审批时采用的审批方式:0,会签(需所有审批人同意);1,或签(一名审批人同意或拒绝即可)")private Integer examineMode;private Integer noHanderAction;private Integer examineEndDirectorLevel;/*** 抄送标志 (弃用)*/@ApiModelProperty("抄送标志 (弃用)")private Integer ccSelfSelectFlag;/*** 条件信息数据*/@ApiModelProperty("条件信息数据")private List<ConditionVo> conditionList;/*** 当前节点操作人员信息*/@ApiModelProperty("当前节点操作人员信息")private List<ActivitiUserDTO> nodeUserList;/*** 下一节点数据 null 为 指向结束节点*/@ApiModelProperty("下一节点数据 null 为 指向结束节点")private ChildNodeVo childNode;/*** type=4时 存放分支数据*/@ApiModelProperty("type=4时 存放分支数据")private List<ChildNodeVo> conditionNodes;/*** type=1时 存放编辑权限字段*/@ApiModelProperty("type=1时 编辑权限字段")private List<ActOrderTableFieldVO> editPermissionsFields;/*** 节点更改数据项 (节点有编辑权限时且也变更了数据时,记录变更字段及数据)*/@ApiModelProperty("节点更改数据项")private List<Map<String, Object>> updateList;/*** 条件为false or true*/@ApiModelProperty("条件为false or true")private Boolean conditionBoo;}
- ConditionVo
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;
import java.util.List;@Data
@ApiModel(value = "ConditionVo对象", description = "条件信息对象")
public class ConditionVo implements Serializable {private static final long serialVersionUID = -1597728589377233523L;/*** 字段key*/@ApiModelProperty("字段key")private String fieldKey;/*** 字段类型 1:下拉; 2 :区间; 3:单选; 4:时间; 5:选择部门; 6:选择人员; 7 文本; 8 级联; 9 选择供应商; 10 地址; 11 下拉单选;* 12 下拉多选; 13 起止日期; 14 数字; 15 设备分类; 16 员工选择; 17 部门选择; 18 周期; 999,额外挂载部门*/@ApiModelProperty("fieldDataType")private Integer fieldDataType;/*** 字段名称*/@ApiModelProperty("字段名称")private String label;/*** 连接符 1,or;2。and;*/@ApiModelProperty("连接符 1,or;2。and;")private Integer connectors;/*** 文本*/@ApiModelProperty("文本 fieldDataType 1:下拉; 3:单选; 5:选择部门; 6:选择人员; 8 级联; 9 选择供应商; 14 数字; 999,额外挂载部门")private Object text;@ApiModelProperty("文本名称 fieldDataType 4:时间; 7 文本; 10 地址; 11 下拉单选; 13 起止日期; 16 员工选择; 17 部门选择; 18 周期;")private String textName;/*** 数值 最小值*/@ApiModelProperty("数值 最小值 fieldDataType 2 :区间;")private String min;/*** 数值 最大值*/@ApiModelProperty("数值 最大值 fieldDataType 2 :区间;")private String max;/*** 集合值集* { <p/>* "123",<p/>* 123 <p/>* }*/@ApiModelProperty("集合值集 12:下拉多选; 15:设备分类;")private List<Object> list;private Object dataInfo;}
自定义对象转bpmn
/*** 递归 转 bpmnModel* @param childNode 数据节点* @param process process* @param paramMap 流程参数* @param nodeId 路由节点 下游节点id (非路由节点传 null)* @param paramValueMap 启动流程参数 非启动时 null* @param keys 非启动流程时 不能为null 获取全部动态参数*/String recursionToBpmnModel(ChildNodeVo childNode, Process process, Map<String, Object> paramMap, String nodeId, Map<String, Object> paramValueMap, Set<String> keys);@Overridepublic String recursionToBpmnModel(ChildNodeVo childNode, Process process, Map<String, Object> paramMap, String nodeId, Map<String, Object> paramValueMap, Set<String> keys) {//主线 结束 拼接 end节点if ((childNode == null || ObjectUtils.isEmpty(childNode.getType())) && ObjectUtils.isEmpty(nodeId)) {EndEvent endEvent = new EndEvent();endEvent.setId(String.format("end_%s", RandomStringUtils.randomAlphabetic(10)));endEvent.setName("结束");process.addFlowElement(endEvent);return endEvent.getId();} else if (childNode == null || ObjectUtils.isEmpty(childNode.getType())) { //&& routing != null//分支线 结束 回归主线return nodeId;}switch (childNode.getType()) {//发起人节点case 0:StartEvent startEvent = new StartEvent();startEvent.setId(String.format("start_%s", RandomStringUtils.randomAlphabetic(10)));startEvent.setName(childNode.getNodeName());childNode.setNodeId(startEvent.getId());childNode.setConditionBoo(Boolean.TRUE);process.addFlowElement(startEvent);SequenceFlow sequenceFlow = new SequenceFlow();sequenceFlow.setId(String.format("flow_%s", RandomStringUtils.randomAlphabetic(10)));sequenceFlow.setSourceRef(startEvent.getId());sequenceFlow.setTargetRef(this.recursionToBpmnModel(childNode.getChildNode(), process, paramMap, nodeId, paramValueMap, keys));if (childNode.getChildNode() == null || ObjectUtils.isEmpty(childNode.getChildNode().getType()))childNode.setChildNode(null);process.addFlowElement(sequenceFlow);return startEvent.getId();//审核人case 1:UserTask userTask = new UserTask();userTask.setName(childNode.getNodeName());String randomStr = RandomStringUtils.randomAlphabetic(5);//固定格式userTask.setAssignee(String.format("${userId_%s}", randomStr));//报修人节点 允许为空 验证阶段if (ObjectUtils.isEmpty(childNode.getNodeUserList())&& !childNode.getSettype().equals(3)) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_NOT_SET_APPROVE,childNode.getNodeName()));//多人会签final MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();String str = "userTask"; //userList_是否会签_是否或签//是否会签if (childNode.getExamineMode() == null) {str = String.format("%s_%s", str, 0);} else {str = String.format("%s_%s", str, 1);//固定格式if (Objects.equals(childNode.getExamineMode(), 0)) {//0,会签(需所有审批人同意)loopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances==1}");str = String.format("%s_%s", str, 0);} else {//或签(一名审批人同意或拒绝即可)loopCharacteristics.setCompletionCondition("${nrOfCompletedInstances==1}");str = String.format("%s_%s", str, 1);}}userTask.setId(String.format("%s_%s", str, RandomStringUtils.randomAlphabetic(10)));childNode.setNodeId(userTask.getId());childNode.setConditionBoo(Boolean.TRUE);final String userStr = String.format("userList_%s", randomStr);final List<String> users = childNode.getNodeUserList().stream().map(ActivitiUserDTO::getEmployeeNumber).collect(Collectors.toList());paramMap.put(userStr, users);loopCharacteristics.setInputDataItem(String.format("${%s}", userStr));//固定格式loopCharacteristics.setElementVariable(String.format("userId_%s", randomStr));userTask.setLoopCharacteristics(loopCharacteristics);//部门负责人找不到操作类型:null or 0,自动通过;1,指定审批人if (Objects.equals(childNode.getSettype(), 2)) {final ActivitiListener activitiListener = new ActivitiListener();activitiListener.setEvent("create");activitiListener.setImplementationType("class");activitiListener.setImplementation("cn.morimatsu.phegda.config.activitiListener.MakeDeptDirectorTask");userTask.setTaskListeners(Collections.singletonList(activitiListener));}process.addFlowElement(userTask);sequenceFlow = new SequenceFlow();sequenceFlow.setId(String.format("flow_%s", RandomStringUtils.randomAlphabetic(10)));sequenceFlow.setSourceRef(userTask.getId());sequenceFlow.setTargetRef(this.recursionToBpmnModel(childNode.getChildNode(), process, paramMap, nodeId, paramValueMap, keys));if (childNode.getChildNode() == null || ObjectUtils.isEmpty(childNode.getChildNode().getType()))childNode.setChildNode(null);process.addFlowElement(sequenceFlow);return userTask.getId();//抄送人case 2:userTask = new UserTask();userTask.setId(String.format("carbonCopy_%s", RandomStringUtils.randomAlphabetic(10)));userTask.setName(childNode.getNodeName());childNode.setNodeId(userTask.getId());childNode.setConditionBoo(Boolean.TRUE);randomStr = RandomStringUtils.randomAlphabetic(5);//固定格式userTask.setAssignee(String.format("${copyUserId_%s}", randomStr));if (ObjectUtils.isEmpty(childNode.getNodeUserList())) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_NOT_SET_CC_PERSON,childNode.getNodeName()));//多人会签final MultiInstanceLoopCharacteristics loop = new MultiInstanceLoopCharacteristics();final String copyUser = String.format("carbonCopyUserList_%s", randomStr);final List<String> copyUsers = childNode.getNodeUserList().stream().map(ActivitiUserDTO::getEmployeeNumber).collect(Collectors.toList());paramMap.put(copyUser, copyUsers);loop.setInputDataItem(String.format("${%s}", copyUser));//固定格式 抄送人loop.setElementVariable(String.format("copyUserId_%s", randomStr));loop.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances==1}");userTask.setLoopCharacteristics(loop);//抄送final ActivitiListener activitiListener = new ActivitiListener();activitiListener.setEvent("create");activitiListener.setImplementationType("class");activitiListener.setImplementation("cn.morimatsu.phegda.config.activitiListener.MakeCopyUserTask");userTask.setTaskListeners(Collections.singletonList(activitiListener));process.addFlowElement(userTask);sequenceFlow = new SequenceFlow();sequenceFlow.setId(String.format("flow_%s", RandomStringUtils.randomAlphabetic(10)));sequenceFlow.setSourceRef(userTask.getId());sequenceFlow.setTargetRef(this.recursionToBpmnModel(childNode.getChildNode(), process, paramMap, nodeId, paramValueMap, keys));if (childNode.getChildNode() == null || ObjectUtils.isEmpty(childNode.getChildNode().getType()))childNode.setChildNode(null);process.addFlowElement(sequenceFlow);return userTask.getId();//路由case 4:ExclusiveGateway exclusiveGateway = new ExclusiveGateway();exclusiveGateway.setId(String.format("exclusiveGateway_%s", RandomStringUtils.randomAlphabetic(10)));childNode.setNodeId(exclusiveGateway.getId());childNode.setConditionBoo(Boolean.TRUE);process.addFlowElement(exclusiveGateway);if (ObjectUtils.isEmpty(childNode.getConditionNodes())) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_NOT_SET_CONDITION, childNode.getNodeName()));String nodeKey = this.recursionToBpmnModel(childNode.getChildNode(), process, paramMap, nodeId, paramValueMap, keys);if (childNode.getChildNode() == null || ObjectUtils.isEmpty(childNode.getChildNode().getType()))childNode.setChildNode(null);final long count = childNode.getConditionNodes().stream().filter(item -> Objects.equals(item.getType(), 5)).count();if (count > 1) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_DEFAULT_CONDITION_EXCEED_ONE));final Boolean[] bol = new Boolean[]{false};final SequenceFlow[] flows = new SequenceFlow[1];childNode.getConditionNodes()//分支数据.forEach(item -> {//条件节点类型 为 3 or 5if (!Arrays.asList(3, 5).contains(item.getType())) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_CONDITION_NODE_ERROR));//非默认条件 判断分支if (Objects.equals(item.getType(), 3) && ObjectUtils.isEmpty(item.getConditionList())) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_NOT_SET_CONDITION, item.getNodeName()));if (Objects.equals(item.getType(), 3)) {if (ObjectUtils.isEmpty(item.getConditionList())) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_NOT_SET_CONDITION, item.getNodeName()));long c = item.getConditionList().stream().filter(i -> StringUtils.isBlank(i.getFieldKey())).count();if (c > 0) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_NOT_SET_CONDITION, item.getNodeName()));c = item.getConditionList().stream().filter(i -> {switch (i.getFieldDataType()) {case 12: //12:下拉多选case 15: //15:设备分类if (ObjectUtils.isEmpty(i.getList())) return Boolean.TRUE;else return Boolean.FALSE;case 1: //1:下拉;case 3: //3:单选;case 5: //5:选择部门;case 6: //6:选择人员;case 8: //8,级联case 9: //9:选择供应商case 14: //14:数字case 999: //999,额外挂载部门if (ObjectUtils.isEmpty(i.getText())) return Boolean.TRUE;else return Boolean.FALSE;case 4: //4:时间;case 7: //7 文本;case 10: //10:地址case 11: //11:下拉单选case 13: //13:起止日期case 16: //16:员工选择case 17: //17:部门选择case 18: //18:周期if (StringUtils.isBlank(i.getTextName())) return Boolean.TRUE;else return Boolean.FALSE;case 2: //区间if (ObjectUtils.isEmpty(i.getMin()) || ObjectUtils.isEmpty(i.getMax())) return Boolean.TRUE;else return Boolean.FALSE;default: throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_UNKNOWN_COMPUTE_SYMBOL));}}).count();if (c > 0) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_NOT_SET_CONDITION, item.getNodeName()));}SequenceFlow flow = new SequenceFlow();Boolean symbol = false;//顺序 第一条true后 不判断其他分支if (Objects.equals(item.getType(), 3)) {final List<ConditionVo> list = new ArrayList<>(item.getConditionList());//倒叙 因为前台是按照顺序传入 计算也要 顺序计算 迭代器是倒叙计算的。 所以需要倒叙Collections.reverse(list);//非默认条件分支 做判断处理symbol = getSymbol(0, list, paramValueMap, keys);}flow.setId(String.format("flow_%s", RandomStringUtils.randomAlphabetic(10)));//分支条件结果 true 保存对应的节点id//顺序 第一条true后 不判断其他分支item.setNodeId(flow.getId());if (symbol && !bol[0]) {//是否存在true的条件bol[0] = symbol;item.setConditionBoo(Boolean.TRUE);flow.setConditionExpression(String.format("${%s}", symbol));} else {item.setConditionBoo(Boolean.FALSE);flow.setConditionExpression("${false}");}if (Objects.equals(item.getType(), 5)) item.setNodeId(flow.getId());flow.setSourceRef(exclusiveGateway.getId());flow.setTargetRef(this.recursionToBpmnModel(item.getChildNode(), process, paramMap, nodeKey, paramValueMap, keys));if (item.getChildNode() == null || ObjectUtils.isEmpty(item.getChildNode().getType()))item.setChildNode(null);//排除默认线if (Objects.equals(item.getType(), 5)) {flows[0] = flow;} else {//条件分支有true时 移除 默认分支的nodeIdchildNode.getConditionNodes().stream().filter(i -> Objects.equals(i.getType(), 5)).forEach(i -> i.setConditionBoo(Boolean.FALSE));process.addFlowElement(flow);}});//条件中 没有true条件 讲默认置为true条件if (flows[0] == null) throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_BRANCH_CONDITION_NOT_DEFAULT));if (bol[0] == null || !bol[0]) {flows[0].setConditionExpression("${true}");//将默认的条件boo 改为truechildNode.getConditionNodes().stream().filter(item -> Objects.equals(item.getType(), 5)).forEach(item -> item.setConditionBoo(Boolean.TRUE));} else {//将默认条件对应的 nodeId 置空childNode.getConditionNodes().stream().filter(item -> Objects.equals(item.getType(), 5)).forEach(item -> item.setConditionBoo(Boolean.FALSE));}//连默认线process.addFlowElement(flows[0]);return exclusiveGateway.getId();default:throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_UNKNOWN_LABEL_TYPE));}}@Overridepublic Boolean getSymbol(Integer i, List<ConditionVo> conditionVo, Map<String, Object> paramValueMap, Set<String> keys) {if (paramValueMap == null) {//验证流程时写入参数keys.addAll(conditionVo.stream().map(ConditionVo::getFieldKey).collect(Collectors.toSet()));return Boolean.TRUE;}boolean b;//未传参数 条件当 false 处理if (paramValueMap.containsKey(conditionVo.get(i).getFieldKey())) {switch (conditionVo.get(i).getFieldDataType()) {case 12: //12:下拉多选case 15: //15:设备分类final List<String> list = conditionVo.get(i).getList().stream().filter(ObjectUtils::isNotEmpty).map(Object::toString).collect(Collectors.toList());final List<String> list1 = JSONArray.parseArray(paramValueMap.get(conditionVo.get(i).getFieldKey()).toString(), String.class);//无提交数据 falseif (ObjectUtils.isEmpty(list1)) {b = false;break;}list1.removeAll(list);//条件全包含提交内容 差集为空 不为空则非全包含b = ObjectUtils.isEmpty(list1);break;case 1: //1:下拉;case 3: //3:单选;case 5: //5:选择部门;case 6: //6:选择人员;case 8: //8,级联case 9: //9:选择供应商case 999: //999,额外挂载部门String value = String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey()));if (StringUtils.isNotBlank(value)) {b = Objects.equals(value, String.valueOf(conditionVo.get(i).getText()));} else b = false;break;case 14: //14:数字value = String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey()));if (StringUtils.isNotBlank(value)) {b = new BigDecimal(value).compareTo(new BigDecimal(String.valueOf(conditionVo.get(i).getText()))) == 0;} else b = false;break;case 4: //4:时间;case 7: //7 文本;case 11: //11:下拉单选case 13: //13:起止日期case 18: //18:周期value = String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey()));if (StringUtils.isNotBlank(value)) {b = Objects.equals(value, conditionVo.get(i).getTextName());} else b = false;break;case 16: //16:员工选择Map<String, String> hashMap = JSONObject.<HashMap<String, String>>parseObject(conditionVo.get(i).getTextName(), HashMap.class);value = String.valueOf(hashMap.get("managerId"));if (!paramValueMap.containsKey(conditionVo.get(i).getFieldKey())) {b = false;break;}Map<String, String> hashMap1 = JSONObject.<HashMap<String, String>>parseObject(String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey())), HashMap.class);String value1 = String.valueOf(hashMap1.get("managerId"));b = Objects.equals(value, value1);break;case 17: //17:部门选择hashMap = JSONObject.<HashMap<String, String>>parseObject(conditionVo.get(i).getTextName(), HashMap.class);value = String.valueOf(hashMap.get("userDepartmentId"));if (!paramValueMap.containsKey(conditionVo.get(i).getFieldKey())|| ObjectUtils.isEmpty(paramValueMap.get(conditionVo.get(i).getFieldKey()))) {b = false;break;}hashMap1 = JSONObject.<HashMap<String, String>>parseObject(String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey())), HashMap.class);value1 = String.valueOf(hashMap1.get("userDepartmentId"));b = Objects.equals(value, value1);break;case 10: //10:地址hashMap = JSONObject.<HashMap<String, String>>parseObject(conditionVo.get(i).getTextName(), HashMap.class);List<String> city = JSONArray.parseArray(String.valueOf(hashMap.get("city")), String.class);if (!paramValueMap.containsKey(conditionVo.get(i).getFieldKey())|| ObjectUtils.isEmpty(paramValueMap.get(conditionVo.get(i).getFieldKey()))) {b = false;break;}hashMap1 = JSONObject.<HashMap<String, String>>parseObject(String.valueOf(paramValueMap.get(conditionVo.get(i).getFieldKey())), HashMap.class);List<String> city1 = JSONArray.parseArray(JSONObject.toJSONString(hashMap1.get("city")), String.class);if (ObjectUtils.isEmpty(city1)) {b = false;break;}city.removeAll(city1);b = city.size() == 0;break;case 2: //区间final BigDecimal decimal = new BigDecimal(paramValueMap.get(conditionVo.get(i).getFieldKey()).toString());final BigDecimal min = new BigDecimal(conditionVo.get(i).getMin());final BigDecimal max = new BigDecimal(conditionVo.get(i).getMax());// 原型 数值 min <= decimal <= maxb = min.compareTo(decimal) <= 0 && max.compareTo(decimal) >= 0;break;default: throw new BusinessException(MessageUtils.message(MessagesConstants.ACT_ORDER_UNKNOWN_COMPUTE_SYMBOL));}} else {b = false;}//最后一条 跳出if (i >= conditionVo.size() - 1) {return b;} else {if (conditionVo.get(i).getConnectors() == null || Objects.equals(conditionVo.get(i).getConnectors(), 1)) {i++;return b || getSymbol(i, conditionVo, paramValueMap, keys);} else {i++;return b && getSymbol(i, conditionVo, paramValueMap, keys);}}}
相关文章:

自定义UI对象转流程节点
自定义UI对象转流程节点 实体自定义对象转bpmn activitiy学习 (动态加签,动态流程图,指定节点跳转,指定多人节点跳转) 前端页面仿的这个 提供一个思路 实体 ActivitiValueVo import io.swagger.annotations.ApiModel; import io.swagger.a…...

P1-P5_动手学深度学习-pytorch(李沐版,粗浅的笔记)
目录 预告 1.学习深度学习的关键是动手 2.什么是《动手学深度学习》 3.曾经推出的版本(含github链接) 一、课程安排 1.目标 2.内容 3.上课形式 4.你将学到什么 5.资源 二、深度学习的介绍 1.AI地图 2.深度学习在一些应用上…...

Android Studio修改模拟器AVD Manger目录
Android Studio修改虚拟机AVD Manger目录 1、在AS的设备管理器Device Manager中删除原来创建的所有虚拟机(Android Virtual Device); 2、新建一个自定义的AVD目录,例如:D:\Android\AndroidAVD 3、在高级系统设置中增加…...

STM32--MQ2烟雾传感器
本文主要介绍STM32F103C8T6和烟雾传感器模块的控制算法 简介 烟雾模块选用MQ-2气体传感器,根据传感器的电导率随空气中可燃气体浓度的增加而增大的特性检测空气中可燃气体,然后将电导率的变化转换成对应的电信号 MQ系列烟雾传感分类如下: 该…...

GitHub要求开启2FA,否则不让用了。
背景 其实大概在一个多月前,在 GitHub 网页端以及邮箱里都被提示:要求开启 2FA ,即双因子认证;但是当时由于拖延症和侥幸心理作祟,直接忽略了相关信息,毕竟“又不是不能用”。。 只到今天发现 GitHub 直接…...

Python 编程基础 | 第三章-数据类型 | 3.6、元组
一、元组 Python 的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。 1、创建元组 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可,例如: tup1 (physics, ch…...

2023/10/7 -- ARM
【程序状态寄存器读写指令】 1.指令码以及格式 mrs:读取CPSR寄存器的值 mrs 目标寄存器 CPSR:读取CPSR的数值保存到目标寄存器中msr:修改CPSR寄存器的数值msr CPSR,第一操作数:将第一操作数的数值保存到CPSR寄存器中//修改CPSR寄存器,也就表示程序的状…...

yolov5加关键点回归
文章目录 一、数据1)数据准备2)标注文件说明 二、基于yolov5-face 修改自己的yolov5加关键点回归1、dataloader,py2、augmentations.py3、loss.py4、yolo.py 一、数据 1)数据准备 1、手动创建文件夹: yolov5-face-master/data/widerface/tr…...

untitle
实用的科研图形美化处理教程分享 显微照片排版标记 除了统计图表之外,显微照片也是文章中必不可少的实验结果呈现方式。除了常规实验的各种组织切片照片,在空间转录组文章中显微照片更是常见。显微照片的呈现方式也是有讲究的,比如对照片…...

《论文阅读》监督对抗性对比学习在对话中的情绪识别 ACL2023
《论文阅读》监督对抗性对比学习在对话中的情绪识别 前言摘要相关知识最坏样本干扰监督对比学习生成式对抗网络纳什均衡琴森香农散度范式球模型架构监督对抗性对比学习模型结构图实验结果问题前言 你是否也对于理解论文存在困惑? 你是否也像我之前搜索论文解读,得到只是中文…...

2023-10-07 LeetCode每日一题(股票价格跨度)
2023-10-07每日一题 一、题目编号 901. 股票价格跨度二、题目链接 点击跳转到题目位置 三、题目描述 设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(…...

聊聊分布式架构04——RPC通信原理
目录 RPC通信的基本原理 RPC结构 手撸简陋版RPC 知识点梳理 1.Socket套接字通信机制 2.通信过程的序列化与反序列化 3.动态代理 4.反射 思维流程梳理 码起来 服务端时序图 服务端—Api与Provider模块 客户端时序图 RPC通信的基本原理 RPC(Remote Proc…...

维吉尼亚密码
维吉尼亚密码属于多表代换密码 其中A<–>0,B<–>1,…,Z<–>25,则每个密钥K相当于一个长度为m的字母串,称为密钥字。维吉尼亚密码一次加密m个明文字母。 示例:设m6,密钥字为…...

ubuntu20.04挂载拓展盘保姆级流程
背景:跑模型玩时,发现机子硬盘太小了,搞个1t固态作为挂载盘。以下为操作全流程记录 1、开始root权限操作 sudo su若进不去,考虑是否给root设置过密码,新系统第一次进入需要设置密码。 进入成功: rooty:…...

顶顶通电话机器人接口对接开源ASR(语音识别)
前景介绍 目前大部分用户使用的都是在线ASR按照分钟或者按次付费,之前开源ASR效果太差不具备商用的条件,随着 阿里达摩院发布了大量开源数据集或者海量工业数据训练的模型,识别效果已经和商用ASR差距非常小,完全具备了很多场景代…...

windows消息机制
windows开发比较简单,首先要理解的就是消息机制。 Windows消息机制是指Windows操作系统中的消息传递机制。在Windows中,应用程序通过消息进行通信和交互。消息是一种轻量级的通信方式,用于在不同的窗口、线程或进程之间传递信息。 在Windows…...

整数划分——DP
用 j j j 个数表示 i i i 的方案数,考虑dp 转移考虑最小值是否为1 无限制 若为1,则转移到 f ( i 1 , j 1 ) f(i1, j1) f(i1,j1)不为1,则全部1,转移到 f ( i j , j ) f(ij, j) f(ij,j) 数之间不能重复 那么相当于每次整…...

Git切换用户常用命令
1、查看 查看用户名 : git config user.name查看密码: git config user.password查看邮箱: git config user.email查看配置信息(包含上面的信息): $ git config --list2、新增、切换 修改用户名 git…...

一般香港服务器带宽选多大够用?(带宽计算方法)
在海外IDC市场份额中,香港服务器依托自身优越的服务器资源条件,在各个行业中发挥的重要作用。但是,不同业务对网络带宽的要求各不相同,弄清楚如何计算带宽需求对于确保业务平稳运行至关重要,最好从一开始就使用正…...

vue中使用ali-oss上传文件到阿里云上
1.使用 npm 安装ali-oss npm install ali-oss --save2.写ali-oss.js // 引入ali-oss let OSS require(ali-oss) let client new OSS({region: oss-cn-xxx, // bucket所在的区域, 默认oss-cn-hangzhousecure: true, // secure: 配合region使用,如果指…...

php实战案例记录(17)计算时间的函数及其示例说明
在PHP中,有许多函数可以用于计算和处理时间。以下是一些常用的计算时间的函数及其示例说明: time():获取当前时间的Unix时间戳。 $currentTimestamp time(); echo $currentTimestamp;date():将Unix时间戳格式化为指定的日期和时…...

基于Keil a51汇编 —— MPL 宏定义
MPL 宏 Ax51汇编程序支持的宏处理语言(MPL)是一种字符串替换工具,使您能够编写可修复的代码块(宏)并将其插入源文本中的一个或多个位置。 宏处理器查看源文件的方式与汇编程序不同。 对于汇编程序来说,源…...

Android 13 骁龙相机点击拍照流程分析(二)——点击拍照到存入相册
一.前言 本篇是在Android 13 骁龙相机点击拍照流程分析(一)——点击拍照到更新到左下角缩略图文章的基础上进行延申的,前面的预览、点击拍照的过程参考第一篇:Android 13 骁龙相机点击拍照流程分析(一)——点击拍照到更新到左下角缩略图-CSDN博客 二.生成图片并保存 从第…...

常见算法-巴斯卡三角形(Pascal)
常见算法-巴斯卡三角形(Pascal) 1、说明 巴斯卡(Pascal)三角形基本上就是在解 nCr,因为三角形上的每一个数字各对应一个nCr,其中 n 为 row,而 r 为 column,如下: 0C0 1…...

AI:09-基于深度学习的图像场景分类
图像场景分类是计算机视觉领域的重要任务之一,它涉及将图像分为不同的场景类别,如城市街景、山脉风景、海滩等。本文将介绍基于深度学习的图像场景分类方法,并提供相应的代码实例,展示了深度学习在图像场景分类中的技术深度和应用前景。 图像场景分类是计算机视觉中的一项…...

uni-app:引入echarts(使用renderjs)
效果 代码 <template><view click"echarts.onClick" :prop"option" :change:prop"echarts.updateEcharts" id"echarts" class"echarts"></view> </template><script>export default {data()…...

使用wireshark解析ipsec esp包
Ipsec esp包就是ipsec通过ike协议协商好后建立的通信隧道使用的加密包,该加密包里面就是用户的数据,比如通过的语音等。 那么如何将抓出来的esp包解析出来看呢? 获取相关的esp的key信息. 打开wireshark -> edit->preferences 找到pr…...

linux如何删除最近操作的日志
Linux系统下,不同的应用程序可能会生成不同的日志文件。如果你想要删除最近一段时间内的操作日志,可以使用一些命令来完成。 以下是一些常见的命令: dmesg:该命令用于显示内核环境下的运行信息和警告信息。如果你需要清空dmesg缓…...

android端MifareClassicTool
github地址 GitHub - ikarus23/MifareClassicTool: An Android NFC app for reading, writing, analyzing, etc. MIFARE Classic RFID tags. 开源项目 下载: https://www.icaria.de/mct/releases/ 功能 1、读取Mifare Classic卡片 2、编辑并保存卡片的数据 3、写入Mifare C…...

设计模式 - 迭代器模式
目录 一. 前言 二. 实现 三. 优缺点 一. 前言 迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按…...