【同步】BOOT 和 CLOUD 的功能
parent
d6fa049f61
commit
c854fda3f1
|
@ -74,30 +74,30 @@ public class DateUtils {
|
|||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param month 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day) {
|
||||
return buildTime(year, mouth, day, 0, 0, 0);
|
||||
public static Date buildTime(int year, int month, int day) {
|
||||
return buildTime(year, month, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param month 月
|
||||
* @param day 日
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day,
|
||||
public static Date buildTime(int year, int month, int day,
|
||||
int hour, int minute, int second) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, mouth - 1);
|
||||
calendar.set(Calendar.MONTH, month - 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
calendar.set(Calendar.MINUTE, minute);
|
||||
|
|
|
@ -76,4 +76,9 @@ public class DictFrameworkUtils {
|
|||
return dictData!= null ? dictData.getValue(): null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static List<String> getDictDataValueList(String dictType) {
|
||||
List<DictDataRespDTO> dictDatas = GET_DICT_DATA_CACHE.get(dictType);
|
||||
return convertList(dictDatas, DictDataRespDTO::getValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package cn.iocoder.yudao.framework.dict.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({
|
||||
ElementType.METHOD,
|
||||
ElementType.FIELD,
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.PARAMETER,
|
||||
ElementType.TYPE_USE
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Constraint(
|
||||
validatedBy = {InDictValidator.class, InDictCollectionValidator.class}
|
||||
)
|
||||
public @interface InDict {
|
||||
|
||||
/**
|
||||
* 数据字典 type
|
||||
*/
|
||||
String type();
|
||||
|
||||
String message() default "必须在指定范围 {value}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package cn.iocoder.yudao.framework.dict.validation;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class InDictCollectionValidator implements ConstraintValidator<InDict, Collection<?>> {
|
||||
|
||||
private String dictType;
|
||||
|
||||
@Override
|
||||
public void initialize(InDict annotation) {
|
||||
this.dictType = annotation.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Collection<?> list, ConstraintValidatorContext context) {
|
||||
// 为空时,默认不校验,即认为通过
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return true;
|
||||
}
|
||||
// 校验全部通过
|
||||
List<String> dbValues = DictFrameworkUtils.getDictDataValueList(dictType);
|
||||
boolean match = list.stream().allMatch(v -> dbValues.stream()
|
||||
.anyMatch(dbValue -> dbValue.equalsIgnoreCase(v.toString())));
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 校验不通过,自定义提示语句
|
||||
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate().replaceAll("\\{value}", dbValues.toString())
|
||||
).addConstraintViolation(); // 重新添加错误提示语句
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package cn.iocoder.yudao.framework.dict.validation;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InDictValidator implements ConstraintValidator<InDict, Object> {
|
||||
|
||||
private String dictType;
|
||||
|
||||
@Override
|
||||
public void initialize(InDict annotation) {
|
||||
this.dictType = annotation.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
// 为空时,默认不校验,即认为通过
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
// 校验通过
|
||||
final List<String> values = DictFrameworkUtils.getDictDataValueList(dictType);
|
||||
boolean match = values.stream().anyMatch(v -> StrUtil.equalsIgnoreCase(v, value.toString()));
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 校验不通过,自定义提示语句
|
||||
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate().replaceAll("\\{value}", values.toString())
|
||||
).addConstraintViolation(); // 重新添加错误提示语句
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package cn.iocoder.yudao.framework.excel.core.util;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
|
||||
import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
|
||||
import cn.idev.excel.FastExcel;
|
||||
import cn.idev.excel.FastExcelFactory;
|
||||
import cn.idev.excel.converters.longconverter.LongStringConverter;
|
||||
import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
|
||||
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
|
||||
import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
@ -32,7 +32,7 @@ public class ExcelUtils {
|
|||
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
|
||||
Class<T> head, List<T> data) throws IOException {
|
||||
// 输出 Excel
|
||||
FastExcel.write(response.getOutputStream(), head)
|
||||
FastExcelFactory.write(response.getOutputStream(), head)
|
||||
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
|
||||
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
|
||||
.registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框
|
||||
|
@ -44,7 +44,7 @@ public class ExcelUtils {
|
|||
}
|
||||
|
||||
public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
|
||||
return FastExcel.read(file.getInputStream(), head, null)
|
||||
return FastExcelFactory.read(file.getInputStream(), head, null)
|
||||
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
|
||||
.doReadAllSync();
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public interface ErrorCodeConstants {
|
|||
ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在");
|
||||
ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复");
|
||||
ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复");
|
||||
ErrorCode CATEGORY_DELETE_FAIL_MODEL_USED = new ErrorCode(1_009_012_003, "删除失败,流程分类【{}】已被流程模型使用,请先删除对应的流程模型");
|
||||
|
||||
// ========== BPM 流程监听器 1-009-013-000 ==========
|
||||
ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在");
|
||||
|
|
|
@ -73,7 +73,7 @@ public class BpmApprovalDetailRespVO {
|
|||
private List<UserSimpleBaseVO> candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表
|
||||
|
||||
@Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf")
|
||||
private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段)
|
||||
private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 calledProcessInstanceId 字段)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
|||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.CallActivity;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
|
||||
|
@ -132,7 +129,7 @@ public class BpmTaskCandidateInvoker {
|
|||
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
|
||||
// 如果是 CallActivity 子流程,不进行计算候选人
|
||||
FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
|
||||
if (flowElement instanceof CallActivity) {
|
||||
if (flowElement instanceof CallActivity || flowElement instanceof SubProcess) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
// 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过
|
||||
|
|
|
@ -6,12 +6,12 @@ import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
|||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
|
||||
|
@ -24,6 +24,7 @@ import static java.util.Collections.emptySet;
|
|||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserDeptLeaderStrategy 替代
|
||||
public class BpmTaskAssignLeaderExpression {
|
||||
|
||||
@Resource
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.Set;
|
|||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserStrategy 替代
|
||||
public class BpmTaskAssignStartUserExpression {
|
||||
|
||||
@Resource
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.google.common.collect.Sets;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.common.engine.api.FlowableException;
|
||||
import org.flowable.common.engine.impl.javax.el.PropertyNotFoundException;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -48,10 +49,12 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat
|
|||
Object result = FlowableUtils.getExpressionValue(variables, param);
|
||||
return CollectionUtils.toLinkedHashSet(Long.class, result);
|
||||
} catch (FlowableException ex) {
|
||||
// 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常,
|
||||
log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex);
|
||||
// 不能预测候选人,返回空列表, 避免流程无法进行
|
||||
return Sets.newHashSet();
|
||||
// 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常,此时忽略该异常!相当于说,不做流程预测!!!
|
||||
if (ex.getCause() != null && ex.getCause() instanceof PropertyNotFoundException) {
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
log.error("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -37,18 +38,26 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
|
|||
|
||||
@Override
|
||||
protected void processCreated(FlowableEngineEntityEvent event) {
|
||||
processInstanceService.processProcessInstanceCreated((ProcessInstance)event.getEntity());
|
||||
ProcessInstance processInstance = (ProcessInstance) event.getEntity();
|
||||
FlowableUtils.execute(processInstance.getTenantId(),
|
||||
() -> processInstanceService.processProcessInstanceCreated(processInstance));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processCompleted(FlowableEngineEntityEvent event) {
|
||||
processInstanceService.processProcessInstanceCompleted((ProcessInstance)event.getEntity());
|
||||
ProcessInstance processInstance = (ProcessInstance) event.getEntity();
|
||||
FlowableUtils.execute(processInstance.getTenantId(),
|
||||
() -> processInstanceService.processProcessInstanceCompleted(processInstance));
|
||||
}
|
||||
|
||||
@Override // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法
|
||||
@Override
|
||||
protected void processCancelled(FlowableCancelledEvent event) {
|
||||
// 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法
|
||||
ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getProcessInstanceId());
|
||||
processInstanceService.processProcessInstanceCompleted(processInstance);
|
||||
if (processInstance != null) {
|
||||
FlowableUtils.execute(processInstance.getTenantId(),
|
||||
() -> processInstanceService.processProcessInstanceCompleted(processInstance));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventTypeEnum;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -58,17 +60,20 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
|
|||
|
||||
@Override
|
||||
protected void taskCreated(FlowableEngineEntityEvent event) {
|
||||
taskService.processTaskCreated((Task) event.getEntity());
|
||||
Task entity = (Task) event.getEntity();
|
||||
FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCreated(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void taskAssigned(FlowableEngineEntityEvent event) {
|
||||
taskService.processTaskAssigned((Task) event.getEntity());
|
||||
Task entity = (Task) event.getEntity();
|
||||
FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskAssigned(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void taskCompleted(FlowableEngineEntityEvent event) {
|
||||
taskService.processTaskCompleted((Task) event.getEntity());
|
||||
Task entity = (Task) event.getEntity();
|
||||
FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCompleted(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,6 +99,23 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
|
|||
String processDefinitionId = event.getProcessDefinitionId();
|
||||
BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processDefinitionId);
|
||||
Job entity = (Job) event.getEntity();
|
||||
// 特殊 from https://t.zsxq.com/h6oWr :当 elementId 为空时,尝试从 JobHandlerConfiguration 中解析 JSON 获取
|
||||
String elementId = entity.getElementId();
|
||||
if (elementId == null && entity.getJobHandlerConfiguration() != null) {
|
||||
try {
|
||||
String handlerConfig = entity.getJobHandlerConfiguration();
|
||||
if (handlerConfig.startsWith("{") && handlerConfig.contains("activityId")) {
|
||||
elementId = new JSONObject(handlerConfig).getStr("activityId");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[timerFired][解析 entity({}) 失败]", entity, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (elementId == null) {
|
||||
log.error("[timerFired][解析 entity({}) elementId 为空,跳过处理]", entity);
|
||||
return;
|
||||
}
|
||||
FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, entity.getElementId());
|
||||
if (!(element instanceof BoundaryEvent)) {
|
||||
return;
|
||||
|
|
|
@ -108,7 +108,9 @@ public class BpmHttpRequestUtils {
|
|||
Map<String, Object> processVariables = processInstance.getProcessVariables();
|
||||
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
|
||||
addHttpRequestParam(body, bodySettings, processVariables);
|
||||
body.add("processInstanceId", processInstance.getId());
|
||||
if (!body.containsKey("processInstanceId")) { // 避免重复添加
|
||||
body.add("processInstanceId", processInstance.getId());
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
|
@ -478,7 +478,11 @@ public class BpmnModelUtils {
|
|||
*/
|
||||
public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
|
||||
Process process = model.getMainProcess();
|
||||
return process.getFlowElement(flowElementId);
|
||||
FlowElement flowElement = process.getFlowElement(flowElementId);
|
||||
if (flowElement != null) {
|
||||
return flowElement;
|
||||
}
|
||||
return model.getFlowElement(flowElementId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,9 @@ public class BpmCategoryServiceImpl implements BpmCategoryService {
|
|||
@Resource
|
||||
private BpmCategoryMapper bpmCategoryMapper;
|
||||
|
||||
@Resource
|
||||
private BpmModelService modelService;
|
||||
|
||||
@Override
|
||||
public Long createCategory(BpmCategorySaveReqVO createReqVO) {
|
||||
// 校验唯一
|
||||
|
@ -77,15 +80,22 @@ public class BpmCategoryServiceImpl implements BpmCategoryService {
|
|||
@Override
|
||||
public void deleteCategory(Long id) {
|
||||
// 校验存在
|
||||
validateCategoryExists(id);
|
||||
BpmCategoryDO category = validateCategoryExists(id);
|
||||
// 校验是否被流程模型使用
|
||||
Long count = modelService.getModelCountByCategory(category.getCode());
|
||||
if (count > 0) {
|
||||
throw exception(CATEGORY_DELETE_FAIL_MODEL_USED, category.getName());
|
||||
}
|
||||
// 删除
|
||||
bpmCategoryMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void validateCategoryExists(Long id) {
|
||||
if (bpmCategoryMapper.selectById(id) == null) {
|
||||
private BpmCategoryDO validateCategoryExists(Long id) {
|
||||
BpmCategoryDO category = bpmCategoryMapper.selectById(id);
|
||||
if (category == null) {
|
||||
throw exception(CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
return category;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,14 @@ public interface BpmModelService {
|
|||
*/
|
||||
List<Model> getModelList(String name);
|
||||
|
||||
/**
|
||||
* 根据分类编码获得流程模型数量
|
||||
*
|
||||
* @param category 分类编码
|
||||
* @return 流程模型数量
|
||||
*/
|
||||
Long getModelCountByCategory(String category);
|
||||
|
||||
/**
|
||||
* 创建流程模型
|
||||
*
|
||||
|
|
|
@ -88,6 +88,14 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||
return modelQuery.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getModelCountByCategory(String category) {
|
||||
return repositoryService.createModelQuery()
|
||||
.modelCategory(category)
|
||||
.modelTenantId(FlowableUtils.getTenantId())
|
||||
.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String createModel(@Valid BpmModelSaveReqVO createReqVO) {
|
||||
|
|
|
@ -4,11 +4,9 @@ import cn.hutool.core.collection.CollUtil;
|
|||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
|
@ -61,12 +59,15 @@ import org.flowable.task.api.history.HistoricTaskInstance;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode;
|
||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
|
||||
|
@ -264,7 +265,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
// 3. 获取下一个将要执行的节点集合
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
|
||||
List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables);
|
||||
List<ActivityNode> nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId())
|
||||
// 仅仅获取 UserTask 节点 TODO add from jason:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。
|
||||
List<FlowNode> nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask);
|
||||
List<ActivityNode> nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId())
|
||||
.setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
|
||||
.setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
|
||||
.setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
|
||||
|
@ -449,7 +452,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
.setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus)
|
||||
.setStartTime(DateUtils.of(activity.getStartTime()))
|
||||
.setEndTime(DateUtils.of(activity.getEndTime()))
|
||||
.setProcessInstanceId(activity.getProcessInstanceId());
|
||||
.setProcessInstanceId(activity.getCalledProcessInstanceId());
|
||||
approvalNodes.add(callActivity);
|
||||
}
|
||||
});
|
||||
|
@ -521,7 +524,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
|
||||
}
|
||||
if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) {
|
||||
activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId());
|
||||
activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId());
|
||||
}
|
||||
return activityNode;
|
||||
});
|
||||
|
@ -771,17 +774,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule));
|
||||
}
|
||||
// 3.2 流程名称
|
||||
BpmModelMetaInfoVO.TitleSetting titleSetting = processDefinitionInfo.getTitleSetting();
|
||||
if (titleSetting != null && Boolean.TRUE.equals(titleSetting.getEnable())) {
|
||||
AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData();
|
||||
Map<String, Object> cloneVariables = new HashMap<>(variables);
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname());
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now());
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim());
|
||||
processInstanceBuilder.name(StrUtil.format(titleSetting.getTitle(), cloneVariables));
|
||||
} else {
|
||||
processInstanceBuilder.name(definition.getName().trim());
|
||||
}
|
||||
processInstanceBuilder.name(generateProcessInstanceName(userId, definition, processDefinitionInfo, variables));
|
||||
// 3.3 发起流程实例
|
||||
ProcessInstance instance = processInstanceBuilder.start();
|
||||
return instance.getId();
|
||||
|
@ -817,6 +810,25 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
});
|
||||
}
|
||||
|
||||
private String generateProcessInstanceName(Long userId,
|
||||
ProcessDefinition definition,
|
||||
BpmProcessDefinitionInfoDO definitionInfo,
|
||||
Map<String, Object> variables) {
|
||||
if (definition == null || definitionInfo == null) {
|
||||
return null;
|
||||
}
|
||||
BpmModelMetaInfoVO.TitleSetting titleSetting = definitionInfo.getTitleSetting();
|
||||
if (titleSetting == null || !BooleanUtil.isTrue(titleSetting.getEnable())) {
|
||||
return definition.getName();
|
||||
}
|
||||
AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData();
|
||||
Map<String, Object> cloneVariables = new HashMap<>(variables);
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname());
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now());
|
||||
cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim());
|
||||
return StrUtil.format(definitionInfo.getTitleSetting().getTitle(), cloneVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
|
||||
// 1.1 校验流程实例存在
|
||||
|
@ -833,7 +845,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
.getProcessDefinitionInfo(instance.getProcessDefinitionId());
|
||||
Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo);
|
||||
if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消
|
||||
&& Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) {
|
||||
&& BooleanUtil.isFalse(processDefinitionInfo.getAllowCancelRunningProcess())) {
|
||||
throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW);
|
||||
}
|
||||
// 1.4 子流程不允许取消
|
||||
|
@ -900,64 +912,77 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||
|
||||
@Override
|
||||
public void processProcessInstanceCompleted(ProcessInstance instance) {
|
||||
// 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
|
||||
FlowableUtils.execute(instance.getTenantId(), () -> {
|
||||
// 1.1 获取当前状态
|
||||
Integer status = (Integer) instance.getProcessVariables()
|
||||
.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
|
||||
String reason = (String) instance.getProcessVariables()
|
||||
.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
|
||||
// 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
|
||||
// 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
|
||||
status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
|
||||
runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
|
||||
status);
|
||||
// 1.1 获取当前状态
|
||||
Integer status = (Integer) instance.getProcessVariables()
|
||||
.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
|
||||
String reason = (String) instance.getProcessVariables()
|
||||
.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
|
||||
// 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
|
||||
// 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
|
||||
status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
|
||||
runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
|
||||
status);
|
||||
}
|
||||
|
||||
// 2. 发送对应的消息通知
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
||||
messageService.sendMessageWhenProcessInstanceApprove(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
|
||||
} else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
|
||||
messageService.sendMessageWhenProcessInstanceReject(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
|
||||
}
|
||||
|
||||
// 3. 发送流程实例的状态事件
|
||||
processInstanceEventPublisher.sendProcessInstanceResultEvent(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
|
||||
|
||||
// 4. 流程后置通知
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
||||
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
|
||||
getProcessDefinitionInfo(instance.getProcessDefinitionId());
|
||||
if (ObjUtil.isNotNull(processDefinitionInfo) &&
|
||||
ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) {
|
||||
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
|
||||
|
||||
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
||||
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
||||
}
|
||||
|
||||
// 2. 发送对应的消息通知
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
||||
messageService.sendMessageWhenProcessInstanceApprove(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
|
||||
} else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
|
||||
messageService.sendMessageWhenProcessInstanceReject(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
|
||||
}
|
||||
|
||||
// 3. 发送流程实例的状态事件
|
||||
processInstanceEventPublisher.sendProcessInstanceResultEvent(
|
||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
|
||||
|
||||
// 4. 流程后置通知
|
||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
||||
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
|
||||
getProcessDefinitionInfo(instance.getProcessDefinitionId());
|
||||
if (ObjUtil.isNotNull(processDefinitionInfo) &&
|
||||
ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) {
|
||||
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
|
||||
|
||||
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
||||
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processProcessInstanceCreated(ProcessInstance instance) {
|
||||
// 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
|
||||
FlowableUtils.execute(instance.getTenantId(), () -> {
|
||||
// 流程前置通知
|
||||
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
|
||||
getProcessDefinitionInfo(instance.getProcessDefinitionId());
|
||||
if (ObjUtil.isNull(processDefinitionInfo) ||
|
||||
ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
|
||||
return;
|
||||
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
|
||||
getProcessDefinitionInfo(instance.getProcessDefinitionId());
|
||||
ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId());
|
||||
if (processDefinition == null || processDefinitionInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 自定义标题。目的:主要处理子流程的标题无法处理
|
||||
// 注意:必须使用 TransactionSynchronizationManager 事务提交后,否则不生效!!!
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
String name = generateProcessInstanceName(Long.valueOf(instance.getStartUserId()),
|
||||
processDefinition, processDefinitionInfo, instance.getProcessVariables());
|
||||
if (ObjUtil.notEqual(instance.getName(), name)) {
|
||||
runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name);
|
||||
}
|
||||
}
|
||||
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
|
||||
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
||||
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
||||
|
||||
});
|
||||
|
||||
// 流程前置通知
|
||||
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
|
||||
return;
|
||||
}
|
||||
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
|
||||
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
||||
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -230,10 +230,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||
if (StrUtil.isNotBlank(pageVO.getName())) {
|
||||
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
|
||||
}
|
||||
if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
|
||||
taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
|
||||
}
|
||||
// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
|
||||
// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
|
||||
// }
|
||||
// 执行查询
|
||||
long count = taskQuery.count();
|
||||
if (count == 0) {
|
||||
|
@ -244,6 +244,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||
// 特殊:强制移除自动完成的“发起人”节点
|
||||
// 补充说明:由于 taskQuery 无法方面的过滤,所以暂时通过内存过滤
|
||||
tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID));
|
||||
// TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR
|
||||
if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
tasks.removeIf(task -> task.getCreateTime() == null
|
||||
|| task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0]))
|
||||
|| task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1])));
|
||||
}
|
||||
return new PageResult<>(tasks, count);
|
||||
}
|
||||
|
||||
|
@ -259,16 +265,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||
if (StrUtil.isNotEmpty(pageVO.getCategory())) {
|
||||
taskQuery.taskCategory(pageVO.getCategory());
|
||||
}
|
||||
if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
|
||||
taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
|
||||
}
|
||||
// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
|
||||
// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
|
||||
// }
|
||||
// 执行查询
|
||||
long count = taskQuery.count();
|
||||
if (count == 0) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
|
||||
// TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR
|
||||
if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
|
||||
tasks.removeIf(task -> task.getCreateTime() == null
|
||||
|| task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0]))
|
||||
|| task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1])));
|
||||
}
|
||||
return new PageResult<>(tasks, count);
|
||||
}
|
||||
|
||||
|
@ -886,7 +898,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||
if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
|
||||
return;
|
||||
}
|
||||
runExecutionIds.add(task.getExecutionId());
|
||||
if (task.getExecutionId() != null) {
|
||||
runExecutionIds.add(task.getExecutionId());
|
||||
}
|
||||
|
||||
// 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务
|
||||
if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记
|
||||
|
@ -1367,7 +1381,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||
PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class));
|
||||
if (userTaskElement.getId().equals(START_USER_NODE_ID)
|
||||
&& (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核
|
||||
|| Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核
|
||||
|| BooleanUtil.isTrue(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核
|
||||
&& ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
|
||||
getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
|
||||
.setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason()));
|
||||
|
|
|
@ -85,10 +85,15 @@ public class BpmCallActivityListener implements ExecutionListener {
|
|||
// 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人
|
||||
try {
|
||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue));
|
||||
} catch (Exception e) {
|
||||
log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]",
|
||||
DELEGATE_EXPRESSION, formFieldValue);
|
||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId()));
|
||||
} catch (NumberFormatException ex) {
|
||||
try {
|
||||
List<Long> formFieldValues = JsonUtils.parseArray(formFieldValue, Long.class);
|
||||
FlowableUtils.setAuthenticatedUserId(formFieldValues.get(0));
|
||||
} catch (Exception e) {
|
||||
log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]",
|
||||
DELEGATE_EXPRESSION, formFieldValue);
|
||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
|||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO;
|
||||
import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
|
@ -59,7 +58,7 @@ public class CrmProductRespVO implements VO {
|
|||
private String description;
|
||||
|
||||
@Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31926")
|
||||
@Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX,
|
||||
@Trans(type = TransType.SIMPLE, targetClassName = "cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO",
|
||||
fields = "nickname", ref = "ownerUserName")
|
||||
private Long ownerUserId;
|
||||
@Schema(description = "负责人的用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
|
||||
|
@ -67,7 +66,7 @@ public class CrmProductRespVO implements VO {
|
|||
private String ownerUserName;
|
||||
|
||||
@Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX,
|
||||
@Trans(type = TransType.SIMPLE, targetClassName = "cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO",
|
||||
fields = "nickname", ref = "creatorName")
|
||||
private String creator;
|
||||
@Schema(description = "创建人名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
|
||||
|
|
|
@ -6,11 +6,10 @@ import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
|||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.DemoReceiveMessage;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.DemoSendMessage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* WebSocket 示例:单发消息
|
||||
*
|
||||
|
@ -19,7 +18,8 @@ import jakarta.annotation.Resource;
|
|||
@Component
|
||||
public class DemoWebSocketMessageListener implements WebSocketMessageListener<DemoSendMessage> {
|
||||
|
||||
@Resource
|
||||
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
|
||||
@Autowired(required = false) // 由于 yudao.websocket.enable 配置项,可以关闭 WebSocket 的功能,所以这里只能不强制注入
|
||||
private WebSocketMessageSender webSocketMessageSender;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -138,6 +138,7 @@ watch(
|
|||
() => props.${subJoinColumn.javaField},
|
||||
(val: number) => {
|
||||
if (!val) {
|
||||
list.value = [] // 清空列表
|
||||
return
|
||||
}
|
||||
queryParams.${subJoinColumn.javaField} = val
|
||||
|
|
|
@ -353,6 +353,7 @@ const handleDelete = async (id: number) => {
|
|||
// 发起删除
|
||||
await ${simpleClassName}Api.delete${simpleClassName}(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
currentRow.value = {}
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.util.*;
|
||||
import com.alibaba.excel.annotation.*;
|
||||
import cn.idev.excel.annotation.*;
|
||||
|
||||
@Schema(description = "管理后台 - 分类 Response VO")
|
||||
@Data
|
||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.util.*;
|
||||
import com.alibaba.excel.annotation.*;
|
||||
import cn.idev.excel.annotation.*;
|
||||
|
||||
@Schema(description = "管理后台 - 分类 Response VO")
|
||||
@Data
|
||||
|
|
|
@ -303,7 +303,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
|||
throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR);
|
||||
}
|
||||
SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig();
|
||||
if (config == null || !CollectionUtil.contains(activity.getConfigIds(), config.getId())) {
|
||||
if (config == null
|
||||
|| !CollectionUtil.contains(activity.getConfigIds(), config.getId())
|
||||
|| !LocalDateTimeUtils.isBetween(config.getStartTime(), config.getEndTime())) {
|
||||
throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR);
|
||||
}
|
||||
// 1.3 超过单次购买限制
|
||||
|
|
|
@ -2,10 +2,11 @@ package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
|
|||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.framework.dict.validation.InDict;
|
||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 用户更新状态 Request VO")
|
||||
@Data
|
||||
|
@ -18,6 +19,7 @@ public class UserUpdateStatusReqVO {
|
|||
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||
@InDict(type = DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue