This commit is contained in:
YunaiV 2025-10-12 15:13:11 +08:00
commit 909890f68c
11 changed files with 48 additions and 131 deletions

View File

@ -6,12 +6,12 @@ Author: dhb52 (https://gitee.com/dhb52)
pip install simple-ddl-parser
or with uv
uv run --with simple-ddl-parser convertor.py postgres > ../postgresql/ruoyi-vue-pro.sql 239ms 5/22 21:03:16 2025
uv run --with simple-ddl-parser convertor.py sqlserver > ../sqlserver/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py kingbase > ../kingbase/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py opengauss > ../opengauss/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py oracle > ../oracle/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py dm8 > ../dm/ruoyi-vue-pro-dm8.sql
uv run --with simple-ddl-parser convertor.py postgres ../mysql/ruoyi-vue-pro.sql > ../postgresql/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py sqlserver ../mysql/ruoyi-vue-pro.sql > ../sqlserver/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py kingbase ../mysql/ruoyi-vue-pro.sql > ../kingbase/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py opengauss ../mysql/ruoyi-vue-pro.sql > ../opengauss/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py oracle ../mysql/ruoyi-vue-pro.sql > ../oracle/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py dm8 ../mysql/ruoyi-vue-pro.sql > ../dm/ruoyi-vue-pro-dm8.sql
"""
import argparse
@ -24,6 +24,9 @@ from typing import Dict, Generator, Optional, Tuple, Union
from simple_ddl_parser import DDLParser
# 避免 Windows 系统使用默认的 GBK 编码
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf-8', buffering=1)
PREAMBLE = """/*
Yudao Database Transfer Tool
@ -919,9 +922,15 @@ def main():
help="目标数据库类型",
choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss"],
)
parser.add_argument(
"path",
type=str,
help="源数据库脚本路径",
default="../mysql/ruoyi-vue-pro.sql"
)
args = parser.parse_args()
sql_file = pathlib.Path("../mysql/ruoyi-vue-pro.sql").resolve().as_posix()
sql_file = pathlib.Path(args.path).resolve().as_posix()
convertor = None
if args.type == "postgres":
convertor = PostgreSQLConvertor(sql_file)

View File

@ -234,8 +234,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
needSimulateTaskDefKeysByReturn.add(StrUtil.removePrefix(key, PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX)));
}
// 移除运行中的节点运行中的节点无需预测
// TODO @jason是不是 foreach runActivityNodes然后移除 needSimulateTaskDefKeysByReturn 更好理解成本低一点
CollectionUtils.convertList(runActivityNodes, ActivityNode::getId).forEach(needSimulateTaskDefKeysByReturn::remove);
if (CollUtil.isNotEmpty(runActivityNodes)) {
runActivityNodes.forEach( activityNode -> needSimulateTaskDefKeysByReturn.remove(activityNode.getId()));
}
// 3.3 预测未运行节点的审批信息
List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel,

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.*;
import cn.hutool.extra.spring.SpringUtil;
@ -939,9 +938,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 3. 构建需要预测的任务流程变量
// TODO @jason驳回预测相关是不是搞成一个变量里面是 set 更简洁一点呀
Set<String> taskDefinitionKeyList = getNeedSimulateTaskDefinitionKeys(bpmnModel, currentTask, targetElement);
Map<String, Object> needSimulateVariables = convertMap(taskDefinitionKeyList,
taskId -> StrUtil.concat(false, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_PREFIX, taskId), item -> Boolean.TRUE);
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 原因
@ -962,22 +962,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 1. 获取需要预测的任务的 definition key因为当前任务还没完成也需要预测
Set<String> taskDefinitionKeys = CollUtil.newHashSet(currentTask.getTaskDefinitionKey());
// 2.1 从已结束任务中找到要回退的目标任务按时间倒序最近的一个目标任务
// 2.1 获取已结束任务按时间倒序排序
List<HistoricTaskInstance> endTaskList = CollectionUtils.filterList(
getTaskListByProcessInstanceId(currentTask.getProcessInstanceId(), Boolean.FALSE),
item -> item.getEndTime() != null);
// 2.2 遍历已结束的任务找到在 targetTask 之后生成的任务且串行可达的任务
// 2.2 从结束任务中找到最近一个的目标任务
HistoricTaskInstance targetTask = findFirst(endTaskList,
item -> item.getTaskDefinitionKey().equals(targetElement.getId()));
// TODO @jason驳回预测相关是不是 if targetTask 先判空
if (targetTask == null) {
return taskDefinitionKeys;
}
// 2.3 遍历已结束的任务找到在 targetTask 之后生成的任务且串行可达的任务
endTaskList.forEach(item -> {
FlowElement element = getFlowElementById(bpmnModel, item.getTaskDefinitionKey());
// 如果已结束的任务在回退目标节点之后生成且串行可达则标记为需要预算节点
// 如果已结束的任务在回退目标节点之后生成且串行可达加到需要预测节点中
// TODO 串行可达的方法需要和判断可回退节点 validateTargetTaskCanReturn 分开吗 并行网关可能会有问题
// TODO @jason驳回预测相关这里是不是判断 element
if (targetTask != null
// TODO @jason驳回预测相关这里直接 createTime compare 更简单因为不太会出现空哈
&& DateUtil.compare(item.getCreateTime(), targetTask.getCreateTime()) > 0
if (item.getCreateTime().compareTo(targetTask.getCreateTime()) > 0
&& BpmnModelUtils.isSequentialReachable(element, targetElement, null)) {
taskDefinitionKeys.add(item.getTaskDefinitionKey());
}

View File

@ -124,7 +124,6 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end
@ -326,7 +325,6 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end
@ -560,7 +558,6 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end

View File

@ -127,9 +127,7 @@ const [Modal, modalApi] = useVbenModal({
try {
formData.value = await get${simpleClassName}(data.id);
// 设置到 values
if (formData.value) {
await formApi.setValues(formData.value);
}
await formApi.setValues(formData.value);
} finally {
modalApi.unlock();
}

View File

@ -124,8 +124,9 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
controlsPosition: 'right',
class: '!w-full',
},
#end
},
@ -326,8 +327,9 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
controlsPosition: 'right',
class: '!w-full',
},
#end
},
@ -560,8 +562,9 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
controlsPosition: 'right',
class: '!w-full',
},
#end
},

View File

@ -127,9 +127,7 @@ const [Modal, modalApi] = useVbenModal({
try {
formData.value = await get${simpleClassName}(data.id);
// 设置到 values
if (formData.value) {
await formApi.setValues(formData.value);
}
await formApi.setValues(formData.value);
} finally {
modalApi.unlock();
}

View File

@ -1,86 +0,0 @@
package cn.iocoder.yudao.module.iot.core.enums;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Set;
/**
* IoT 设备消息的方法枚举
*
* @author haohao
*/
@Getter
@AllArgsConstructor
public enum IotDeviceMessageMethodEnum implements ArrayValuable<String> {
// ========== 设备状态 ==========
STATE_UPDATE("thing.state.update", "设备状态更新", true),
// TODO 芋艿要不要加个 ping 消息
// ========== 设备属性 ==========
// 可参考https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services
PROPERTY_POST("thing.property.post", "属性上报", true),
PROPERTY_SET("thing.property.set", "属性设置", false),
// ========== 设备事件 ==========
// 可参考https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services
EVENT_POST("thing.event.post", "事件上报", true),
// ========== 设备服务调用 ==========
// 可参考https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services
SERVICE_INVOKE("thing.service.invoke", "服务调用", false),
// ========== 设备配置 ==========
// 可参考https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1
CONFIG_PUSH("thing.config.push", "配置推送", false),
// ========== OTA 固件 ==========
// 可参考https://help.aliyun.com/zh/iot/user-guide/perform-ota-updates
OTA_UPGRADE("thing.ota.upgrade", "OTA 固定信息推送", false),
OTA_PROGRESS("thing.ota.progress", "OTA 升级进度上报", true),
;
public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageMethodEnum::getMethod)
.toArray(String[]::new);
/**
* 不进行 reply 回复的方法集合
*/
public static final Set<String> REPLY_DISABLED = SetUtils.asSet(
STATE_UPDATE.getMethod(),
OTA_PROGRESS.getMethod() // 参考阿里云OTA 升级进度上报不进行回复
);
private final String method;
private final String name;
private final Boolean upstream;
@Override
public String[] array() {
return ARRAYS;
}
public static IotDeviceMessageMethodEnum of(String method) {
return ArrayUtil.firstMatch(item -> item.getMethod().equals(method),
IotDeviceMessageMethodEnum.values());
}
public static boolean isReplyDisabled(String method) {
return REPLY_DISABLED.contains(method);
}
}

View File

@ -240,24 +240,20 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
* @return 规则场景列表
*/
private List<IotSceneRuleDO> getMatchedSceneRuleListByMessage(IotDeviceMessage message) {
// 1. 匹配设备
// TODO 缓存 @puhui999可能需要 getSelf()
// 1.1 通过 deviceId 获取设备信息
IotDeviceDO device = getSelf().deviceService.getDeviceFromCache(message.getDeviceId());
if (device == null) {
log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId());
return ListUtil.of();
}
// 1.2 通过 productId 获取产品信息
IotProductDO product = getSelf().productService.getProductFromCache(device.getProductId());
if (product == null) {
log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId());
return ListUtil.of();
}
// 1.3 获取匹配的规则场景
List<IotSceneRuleDO> sceneRules = getSceneRuleListByProductIdAndDeviceIdFromCache(
List<IotSceneRuleDO> sceneRules = getSelf().getSceneRuleListByProductIdAndDeviceIdFromCache(
product.getId(), device.getId());
if (CollUtil.isEmpty(sceneRules)) {
return sceneRules;

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
@ -14,7 +15,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* IoT 设备属性设置的 {@link IotSceneRuleAction} 实现类
@ -126,7 +126,7 @@ public class IotDeviceControlSceneRuleAction implements IotSceneRuleAction {
private IotDeviceMessage buildPropertySetMessage(IotSceneRuleDO.Action actionConfig, IotDeviceDO device) {
try {
// 属性设置参数格式: {"properties": {"identifier": value}}
Object params = Map.of("properties", Map.of(actionConfig.getIdentifier(), actionConfig.getParams()));
Object params = MapUtil.of("properties", MapUtil.of(actionConfig.getIdentifier(), actionConfig.getParams()));
return IotDeviceMessage.requestOf(IotDeviceMessageMethodEnum.PROPERTY_SET.getMethod(), params);
} catch (Exception e) {
log.error("[buildPropertySetMessage][构建属性设置消息异常]", e);

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
@ -13,8 +14,8 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* IoT 设备服务调用的 {@link IotSceneRuleAction} 实现类
@ -126,10 +127,10 @@ public class IotDeviceServiceInvokeSceneRuleAction implements IotSceneRuleAction
private IotDeviceMessage buildServiceInvokeMessage(IotSceneRuleDO.Action actionConfig, IotDeviceDO device) {
try {
// 服务调用参数格式: {"identifier": "serviceId", "params": {...}}
Object params = Map.of(
"identifier", actionConfig.getIdentifier(),
"params", actionConfig.getParams() != null ? actionConfig.getParams() : Map.of()
);
Object params = MapUtil.builder()
.put("identifier", actionConfig.getIdentifier())
.put("params", actionConfig.getParams() != null ? actionConfig.getParams() : Collections.emptyMap())
.build();
return IotDeviceMessage.requestOf(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod(), params);
} catch (Exception e) {
log.error("[buildServiceInvokeMessage][构建服务调用消息异常]", e);