mirror of
https://gitee.com/zhijiantianya/yudao-cloud.git
synced 2025-12-30 09:22:27 +00:00
【同步】BOOT 和 CLOUD 的功能
This commit is contained in:
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fhs.core.trans.vo.TransPojo;
|
||||
import lombok.Data;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -37,14 +38,14 @@ public abstract class BaseDO implements Serializable, TransPojo {
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
|
||||
private String creator;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
|
||||
private String updater;
|
||||
/**
|
||||
* 是否删除
|
||||
|
||||
@@ -60,6 +60,12 @@ public enum DbTypeEnum {
|
||||
* 人大金仓
|
||||
*/
|
||||
KINGBASE_ES(DbType.KINGBASE_ES, "KingbaseES", "POSITION('#{value}' IN #{column}) <> 0"),
|
||||
|
||||
/**
|
||||
* OceanBase
|
||||
*/
|
||||
OCEAN_BASE(DbType.OCEAN_BASE, "OceanBase", "FIND_IN_SET('#{value}', #{column}) <> 0")
|
||||
|
||||
;
|
||||
|
||||
public static final Map<String, DbTypeEnum> MAP_BY_NAME = Arrays.stream(values())
|
||||
|
||||
@@ -63,7 +63,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode TASK_WITHDRAW_FAIL_PROCESS_NOT_RUNNING = new ErrorCode(1_009_005_017, "撤回失败,流程实例未运行!");
|
||||
ErrorCode TASK_WITHDRAW_FAIL_TASK_NOT_EXISTS = new ErrorCode(1_009_005_018, "撤回失败,未查询到用户已办任务!");
|
||||
ErrorCode TASK_WITHDRAW_FAIL_NOT_ALLOW = new ErrorCode(1_009_005_019, "撤回失败,此流程不允许撤回操作!");
|
||||
ErrorCode TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW = new ErrorCode(1_009_005_019, "撤回失败,下一节点不满足撤回条件!");
|
||||
ErrorCode TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW = new ErrorCode(1_009_005_020, "撤回失败,下一节点不满足撤回条件!");
|
||||
|
||||
// ========== 动态表单模块 1-009-010-000 ==========
|
||||
ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums.task;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -47,4 +48,8 @@ public enum BpmProcessInstanceStatusEnum implements ArrayValuable<Integer> {
|
||||
APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus());
|
||||
}
|
||||
|
||||
public static BpmProcessInstanceStatusEnum valueOf(Integer status) {
|
||||
return ArrayUtil.firstMatch(item -> item.getStatus().equals(status), values());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums.task;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 流程任务 Task 的状态枚举
|
||||
*
|
||||
@@ -12,7 +16,7 @@ import lombok.Getter;
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BpmTaskStatusEnum {
|
||||
public enum BpmTaskStatusEnum implements ArrayValuable<Integer> {
|
||||
|
||||
SKIP(-2, "跳过"),
|
||||
NOT_START(-1, "未开始"),
|
||||
@@ -35,6 +39,8 @@ public enum BpmTaskStatusEnum {
|
||||
*/
|
||||
WAIT(0, "待审批");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmTaskStatusEnum::getStatus).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* <p>
|
||||
@@ -46,6 +52,11 @@ public enum BpmTaskStatusEnum {
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static boolean isRejectStatus(Integer status) {
|
||||
return REJECT.getStatus().equals(status);
|
||||
}
|
||||
@@ -68,4 +79,8 @@ public enum BpmTaskStatusEnum {
|
||||
return ObjUtil.equal(status, CANCEL.getStatus());
|
||||
}
|
||||
|
||||
public static BpmTaskStatusEnum valueOf(Integer status) {
|
||||
return ArrayUtil.firstMatch(item -> item.getStatus().equals(status), values());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -224,4 +224,10 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting;
|
||||
|
||||
/**
|
||||
* 自定义打印模板设置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private BpmModelMetaInfoVO.PrintTemplateSetting printTemplateSetting;
|
||||
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ public class BpmProcessIdRedisDAO {
|
||||
String noPrefix = processIdRule.getPrefix() + infix + processIdRule.getPostfix();
|
||||
String key = RedisKeyConstants.BPM_PROCESS_ID + noPrefix;
|
||||
Long no = stringRedisTemplate.opsForValue().increment(key);
|
||||
if (StrUtil.isNotEmpty(infix)) {
|
||||
// 特殊:没有前缀,则不能过期,不能每次都是从 0 开始
|
||||
if (StrUtil.isEmpty(infix)) {
|
||||
// 特殊:没有前缀,则不能过期,不能每次都是从 0 开始。可见 https://t.zsxq.com/MU1E2 讨论
|
||||
stringRedisTemplate.expire(key, Duration.ofDays(1L));
|
||||
}
|
||||
return noPrefix + String.format("%0" + processIdRule.getLength() + "d", no);
|
||||
|
||||
@@ -658,10 +658,11 @@ public class BpmnModelUtils {
|
||||
|
||||
// 根据类型,获取入口连线
|
||||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||
// 1. 没有入口连线,则返回 false
|
||||
if (CollUtil.isEmpty(sequenceFlows)) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// 循环找到目标元素
|
||||
// 2. 循环找目标元素, 找到目标节点
|
||||
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||
if (visitedElements.contains(sequenceFlow.getId())) {
|
||||
@@ -669,21 +670,22 @@ public class BpmnModelUtils {
|
||||
}
|
||||
// 添加已经走过的连线
|
||||
visitedElements.add(sequenceFlow.getId());
|
||||
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
||||
// 这条线路存在目标节点,直接返回 true
|
||||
FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
|
||||
if (target.getId().equals(sourceFlowElement.getId())) {
|
||||
return true;
|
||||
}
|
||||
// 如果目标节点为并行网关,跳过这个循环 (TODO 疑问:这个判断作用是防止回退到并行网关分支上的节点吗?)
|
||||
if (sourceFlowElement instanceof ParallelGateway) {
|
||||
continue;
|
||||
}
|
||||
// 如果目标节点为并行网关,则不继续
|
||||
if (sourceFlowElement instanceof ParallelGateway) {
|
||||
return false;
|
||||
}
|
||||
// 否则就继续迭代
|
||||
if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) {
|
||||
return false;
|
||||
// 继续迭代,如果找到目标节点直接返回 true
|
||||
if (isSequentialReachable(sourceFlowElement, target, visitedElements)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// 未找到返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -783,7 +785,6 @@ public class BpmnModelUtils {
|
||||
return resultElements;
|
||||
}
|
||||
|
||||
@SuppressWarnings("PatternVariableCanBeUsed")
|
||||
private static void simulateNextFlowElements(FlowElement currentElement, Map<String, Object> variables,
|
||||
List<FlowElement> resultElements, Set<FlowElement> visitElements) {
|
||||
// 如果为空,或者已经遍历过,则直接结束
|
||||
|
||||
@@ -737,10 +737,10 @@ public class SimpleModelUtils {
|
||||
BoundaryEvent boundaryEvent = null;
|
||||
if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) {
|
||||
boundaryEvent = buildTimeoutBoundaryEvent(receiveTask, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT.getType(),
|
||||
node.getDelaySetting().getDelayTime(), null, null);
|
||||
null, null, node.getDelaySetting().getDelayTime());
|
||||
} else if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) {
|
||||
boundaryEvent = buildTimeoutBoundaryEvent(receiveTask, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT.getType(),
|
||||
null, null, node.getDelaySetting().getDelayTime());
|
||||
node.getDelaySetting().getDelayTime(), null, null);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("不支持的延迟类型:" + node.getDelaySetting());
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 线索分页 Request VO")
|
||||
@Data
|
||||
@@ -42,4 +47,8 @@ public class CrmCluePageReqVO extends PageParam {
|
||||
@Schema(description = "跟进状态", example = "true")
|
||||
private Boolean followUpStatus;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2023-01-01 00:00:00, 2023-01-31 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ public interface CrmClueMapper extends BaseMapperX<CrmClueDO> {
|
||||
.eqIfPresent(CrmClueDO::getLevel, pageReqVO.getLevel())
|
||||
.eqIfPresent(CrmClueDO::getSource, pageReqVO.getSource())
|
||||
.eqIfPresent(CrmClueDO::getFollowUpStatus, pageReqVO.getFollowUpStatus())
|
||||
.betweenIfPresent(CrmClueDO::getCreateTime, pageReqVO.getCreateTime())
|
||||
.orderByDesc(CrmClueDO::getId);
|
||||
return selectJoinPage(pageReqVO, CrmClueDO.class, query);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,8 @@ public enum CodegenFrontTypeEnum {
|
||||
VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版
|
||||
VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 标准模版
|
||||
|
||||
// TODO @puhui999::50、51 会好点;
|
||||
VUE3_VBEN5_EP_SCHEMA(42), // Vue3 VBEN5 + EP + schema 模版
|
||||
VUE3_VBEN5_EP_GENERAL(43), // Vue3 VBEN5 + EP 标准模版
|
||||
VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 模版
|
||||
VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 标准模版
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@@ -99,8 +100,10 @@ public class FileController {
|
||||
if (StrUtil.isEmpty(path)) {
|
||||
throw new IllegalArgumentException("结尾的 path 路径必须传递");
|
||||
}
|
||||
// 解码,解决中文路径的问题 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
|
||||
path = URLUtil.decode(path);
|
||||
// 解码,解决中文路径的问题
|
||||
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
|
||||
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
|
||||
path = URLUtil.decode(path, StandardCharsets.UTF_8, false);
|
||||
|
||||
// 读取内容
|
||||
byte[] content = fileService.getFileContent(configId, path);
|
||||
|
||||
@@ -343,7 +343,7 @@ public class CodegenEngine {
|
||||
filePath = formatFilePath(filePath, bindingMap);
|
||||
String content = templateEngine.getTemplate(vmPath).render(bindingMap);
|
||||
// 格式化代码
|
||||
content = prettyCode(content);
|
||||
content = prettyCode(content, vmPath);
|
||||
result.put(filePath, content);
|
||||
}
|
||||
|
||||
@@ -383,11 +383,14 @@ public class CodegenEngine {
|
||||
* 如果不处理,Vue 的 Pretty 格式校验可能会报错
|
||||
*
|
||||
* @param content 格式化前的代码
|
||||
* @param vmPath 模板路径
|
||||
* @return 格式化后的代码
|
||||
*/
|
||||
private String prettyCode(String content) {
|
||||
// Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错
|
||||
content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
|
||||
private String prettyCode(String content, String vmPath) {
|
||||
// Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错(需要排除 vben5)
|
||||
if (!StrUtil.contains(vmPath, "vben5")) {
|
||||
content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
|
||||
}
|
||||
// Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到
|
||||
if (StrUtil.count(content, "dateFormatter") == 1) {
|
||||
content = StrUtils.removeLineContains(content, "dateFormatter");
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Arrays;
|
||||
@Getter
|
||||
public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
// TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完;
|
||||
/**
|
||||
* 设备上下线变更
|
||||
*
|
||||
|
||||
@@ -76,4 +76,12 @@ public interface RedisKeyConstants {
|
||||
*/
|
||||
String DATA_SINK = "iot:data_sink";
|
||||
|
||||
/**
|
||||
* 场景联动规则的数据缓存,使用 Spring Cache 操作
|
||||
* <p>
|
||||
* KEY 格式:scene_rule_list_${productId}_${deviceId}
|
||||
* VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO} 列表
|
||||
*/
|
||||
String SCENE_RULE_LIST = "iot:scene_rule_list";
|
||||
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
FROM device_property_${reqVO.deviceId}
|
||||
WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL
|
||||
AND ts BETWEEN ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[0])}
|
||||
AND ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[1])}
|
||||
AND ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[1])}
|
||||
ORDER BY ts DESC
|
||||
</select>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.time.LocalDateTime;
|
||||
public class RewardActivityRespVO extends RewardActivityBaseVO {
|
||||
|
||||
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer id;
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@@ -68,8 +68,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||
payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath());
|
||||
} else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) {
|
||||
payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
|
||||
payConfig.setPublicKeyPath(FileUtils.createTempFile(config.getPublicKeyContent()).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.setStrictlyNeedWechatPaySerial(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ public class WxPayClientConfig implements PayClientConfig {
|
||||
/**
|
||||
* pub_key.pem 证书文件的对应字符串
|
||||
*/
|
||||
@NotBlank(message = "pub_key.pem 不能为空", groups = V3.class)
|
||||
private String publicKeyContent;
|
||||
@NotBlank(message = "publicKeyId 不能为空", groups = V3.class)
|
||||
private String publicKeyId;
|
||||
|
||||
@@ -54,6 +54,7 @@ import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -101,7 +102,8 @@ public class SocialClientServiceImpl implements SocialClientService {
|
||||
@Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}")
|
||||
public String miniprogramState;
|
||||
|
||||
@Resource
|
||||
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
|
||||
@Autowired(required = false) // 由于 justauth.enable 配置项,可以关闭 AuthRequestFactory 的功能,所以这里只能不强制注入
|
||||
private AuthRequestFactory authRequestFactory;
|
||||
|
||||
@Resource
|
||||
|
||||
Reference in New Issue
Block a user