mirror of
https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
synced 2026-03-22 05:07:17 +08:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package cn.iocoder.yudao.framework.common.util.json.databind;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 基于时间戳的 LocalDateTime 序列化器
|
||||
@@ -19,7 +23,19 @@ public class TimestampLocalDateTimeSerializer extends JsonSerializer<LocalDateTi
|
||||
|
||||
@Override
|
||||
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
// 将 LocalDateTime 对象,转换为 Long 时间戳
|
||||
String fieldName = gen.getOutputContext().getCurrentName();
|
||||
Class<?> clazz = gen.getOutputContext().getCurrentValue().getClass();
|
||||
Field field = FieldUtils.getField(clazz, fieldName, true);
|
||||
// 情况一:有 JsonFormat 自定义注解,则使用它。https://github.com/YunaiV/ruoyi-vue-pro/pull/1019
|
||||
JsonFormat[] jsonFormats = field.getAnnotationsByType(JsonFormat.class);
|
||||
if (jsonFormats.length > 0) {
|
||||
String pattern = jsonFormats[0].pattern();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||
gen.writeString(formatter.format(value));
|
||||
return;
|
||||
}
|
||||
|
||||
// 情况二:默认将 LocalDateTime 对象,转换为 Long 时间戳
|
||||
gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder;
|
||||
import com.fhs.trans.service.impl.SimpleTransService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -31,32 +32,53 @@ public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory
|
||||
|
||||
@Override // mappedStatementId 参数,暂时没有用。以后,可以基于 mappedStatementId + DataPermission 进行缓存
|
||||
public List<DataPermissionRule> getDataPermissionRule(String mappedStatementId) {
|
||||
// 1. 无数据权限
|
||||
// 1.1 无数据权限
|
||||
if (CollUtil.isEmpty(rules)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2. 未配置,则默认开启
|
||||
// 1.2 未配置,则默认开启
|
||||
DataPermission dataPermission = DataPermissionContextHolder.get();
|
||||
if (dataPermission == null) {
|
||||
return rules;
|
||||
}
|
||||
// 3. 已配置,但禁用
|
||||
// 1.3 已配置,但禁用
|
||||
if (!dataPermission.enable()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 1.4 特殊:数据翻译时,强制忽略数据权限 https://github.com/YunaiV/ruoyi-vue-pro/issues/1007
|
||||
if (isTranslateCall()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 4. 已配置,只选择部分规则
|
||||
// 2.1 情况一:已配置,只选择部分规则
|
||||
if (ArrayUtil.isNotEmpty(dataPermission.includeRules())) {
|
||||
return rules.stream().filter(rule -> ArrayUtil.contains(dataPermission.includeRules(), rule.getClass()))
|
||||
.collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询
|
||||
}
|
||||
// 5. 已配置,只排除部分规则
|
||||
// 2.2 已配置,只排除部分规则
|
||||
if (ArrayUtil.isNotEmpty(dataPermission.excludeRules())) {
|
||||
return rules.stream().filter(rule -> !ArrayUtil.contains(dataPermission.excludeRules(), rule.getClass()))
|
||||
.collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询
|
||||
}
|
||||
// 6. 已配置,全部规则
|
||||
// 2.3 已配置,全部规则
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为数据翻译 {@link com.fhs.core.trans.anno.Trans} 的调用
|
||||
*
|
||||
* 目前暂时只有这个办法,已经和 easy-trans 做过沟通
|
||||
*
|
||||
* @return 是否
|
||||
*/
|
||||
private boolean isTranslateCall() {
|
||||
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||
for (StackTraceElement e : stack) {
|
||||
if (SimpleTransService.class.getName().equals(e.getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -103,6 +104,7 @@ public class YudaoWebAutoConfiguration {
|
||||
* 创建 CorsFilter Bean,解决跨域问题
|
||||
*/
|
||||
@Bean
|
||||
@Order(value = WebFilterOrderEnum.CORS_FILTER) // 特殊:修复因执行顺序影响到跨域配置不生效问题
|
||||
public FilterRegistrationBean<CorsFilter> corsFilterBean() {
|
||||
// 创建 CorsConfiguration 对象
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
|
||||
@@ -54,11 +54,11 @@ public class BpmnVariableConstants {
|
||||
public static final String PROCESS_INSTANCE_VARIABLE_RETURN_FLAG = "RETURN_FLAG_%s";
|
||||
|
||||
/**
|
||||
* 流程实例的变量前缀 - 用于退回操作,记录需要预测的节点:格式 NEED_SIMULATE_TASK_{节点定义 id}
|
||||
* 流程实例的变量 - 用于退回操作,记录需要预测的节点 ids, 变量值类型为 Set
|
||||
*
|
||||
* 目的是:退回操作,预测节点会不准,在流程变量中记录需要预测的节点,来辅助预测
|
||||
*/
|
||||
public static final String PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX = "NEED_SIMULATE_TASK_";
|
||||
public static final String PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS = "NEED_SIMULATE_TASK_IDS";
|
||||
|
||||
/**
|
||||
* 流程实例的变量 - 是否跳过表达式
|
||||
|
||||
@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.bpm.service.task;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
@@ -72,7 +72,6 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
|
||||
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;
|
||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX;
|
||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseNodeType;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
@@ -227,11 +226,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
||||
// 3.2 获取由于退回操作,需要预测的节点。从流程变量中获取,回退操作会设置这些变量
|
||||
Set<String> needSimulateTaskDefKeysByReturn = new HashSet<>();
|
||||
if (StrUtil.isNotEmpty(reqVO.getProcessInstanceId())) {
|
||||
Map<String, Object> variables = runtimeService.getVariables(reqVO.getProcessInstanceId());
|
||||
Map<String, Object> simulateTaskVariables = MapUtil.filter(variables,
|
||||
item -> item.getKey().startsWith(PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX));
|
||||
simulateTaskVariables.forEach((key, value) ->
|
||||
needSimulateTaskDefKeysByReturn.add(StrUtil.removePrefix(key, PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX)));
|
||||
Object needSimulateTaskIds = runtimeService.getVariable(reqVO.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS);
|
||||
needSimulateTaskDefKeysByReturn.addAll(Convert.toSet(String.class, needSimulateTaskIds));
|
||||
}
|
||||
// 移除运行中的节点,运行中的节点无需预测
|
||||
if (CollUtil.isNotEmpty(runActivityNodes)) {
|
||||
|
||||
@@ -69,7 +69,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
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;
|
||||
//import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.*;
|
||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
|
||||
|
||||
/**
|
||||
@@ -604,11 +603,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||
bpmnModel, reqVO.getNextAssignees(), instance);
|
||||
runtimeService.setVariables(task.getProcessInstanceId(), variables);
|
||||
|
||||
// 5. 移除辅助预测的流程变量,这些变量在回退操作中设置
|
||||
// todo @jason:可以直接 + 拼接哈
|
||||
String simulateVariableName = StrUtil.concat(false,
|
||||
BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX, task.getTaskDefinitionKey());
|
||||
runtimeService.removeVariable(task.getProcessInstanceId(), simulateVariableName);
|
||||
// 5. 如果当前节点 Id 存在于需要预测的流程节点中,从中移除。 流程变量在回退操作中设置
|
||||
Object needSimulateTaskIds = runtimeService.getVariable(task.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS);
|
||||
Set<String> needSimulateTaskIdsByReturn = Convert.toSet(String.class, needSimulateTaskIds);
|
||||
if (needSimulateTaskIdsByReturn.contains(task.getTaskDefinitionKey())) {
|
||||
needSimulateTaskIdsByReturn.remove(task.getTaskDefinitionKey());
|
||||
runtimeService.setVariable(task.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskIdsByReturn);
|
||||
}
|
||||
|
||||
// 6. 调用 BPM complete 去完成任务
|
||||
taskService.complete(task.getId(), variables, true);
|
||||
@@ -937,11 +938,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||
});
|
||||
|
||||
// 3. 构建需要预测的任务流程变量
|
||||
// TODO @jason:【驳回预测相关】是不是搞成一个变量,里面是 set 更简洁一点呀?
|
||||
Set<String> needSimulateTaskDefinitionKeys = getNeedSimulateTaskDefinitionKeys(bpmnModel, currentTask, targetElement);
|
||||
Map<String, Object> needSimulateVariables = convertMap(needSimulateTaskDefinitionKeys,
|
||||
key -> StrUtil.concat(false, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX, key), item -> Boolean.TRUE);
|
||||
|
||||
|
||||
// 4. 执行驳回
|
||||
// 使用 moveExecutionsToSingleActivityId 替换 moveActivityIdsToSingleActivityId 原因:
|
||||
@@ -949,12 +946,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(currentTask.getProcessInstanceId())
|
||||
.moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey())
|
||||
// 设置需要预测的任务流程变量,用于辅助预测
|
||||
.processVariables(needSimulateVariables)
|
||||
// 设置流程变量(local)节点退回标记, 用于退回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略,导致自动通过
|
||||
// 设置需要预测的任务 ids 的流程变量,用于辅助预测
|
||||
.processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys)
|
||||
// 设置流程变量(local)节点退回标记, 用于退回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略,导致自动通过
|
||||
.localVariable(reqVO.getTargetTaskDefinitionKey(),
|
||||
String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()),
|
||||
Boolean.TRUE)
|
||||
String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()), Boolean.TRUE)
|
||||
.changeState();
|
||||
}
|
||||
|
||||
|
||||
@@ -353,7 +353,9 @@ const handleDelete = async (id: number) => {
|
||||
// 发起删除
|
||||
await ${simpleClassName}Api.delete${simpleClassName}(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
#if ( $table.templateType == 11 )
|
||||
currentRow.value = {}
|
||||
#end
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
|
||||
@@ -114,6 +114,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'x',
|
||||
class: '!w-full',
|
||||
},
|
||||
#elseif($column.htmlType == "textarea")## 文本域
|
||||
component: 'Textarea',
|
||||
@@ -317,6 +318,7 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'x',
|
||||
class: '!w-full',
|
||||
},
|
||||
#elseif($column.htmlType == "textarea")## 文本域
|
||||
component: 'Textarea',
|
||||
@@ -552,6 +554,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'x',
|
||||
class: '!w-full',
|
||||
},
|
||||
#elseif($column.htmlType == "textarea")## 文本域
|
||||
component: 'Textarea',
|
||||
|
||||
@@ -85,7 +85,9 @@ public interface DeliveryExpressTemplateConvert {
|
||||
.setChargeMode(template.getChargeMode())
|
||||
.setCharge(convertTemplateCharge(findFirst(templateIdChargeMap.get(template.getId()), charge -> charge.getAreaIds().contains(areaId))))
|
||||
.setFree(convertTemplateFree(findFirst(templateIdFreeMap.get(template.getId()), free -> free.getAreaIds().contains(areaId))));
|
||||
result.put(template.getId(), bo);
|
||||
if (bo.getCharge() != null || bo.getFree() != null) {
|
||||
result.put(template.getId(), bo);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||
payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
|
||||
// 参考 https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues/ICUE53 和 https://t.zsxq.com/ODR5V
|
||||
if (StrUtil.isNotBlank(config.getPublicKeyContent())) {
|
||||
payConfig.setPrivateCertPath(FileUtils.createTempFile(Base64.decode(config.getPublicKeyContent())).getPath());
|
||||
payConfig.setPublicKeyPath(FileUtils.createTempFile(config.getPublicKeyContent()).getPath());
|
||||
}
|
||||
// 特殊:强制使用微信公钥模式,避免灰度期间的问题!!!
|
||||
payConfig.setStrictlyNeedWechatPaySerial(true);
|
||||
|
||||
Reference in New Issue
Block a user