From f72dd272a22ffa63bde3f156be2fb43cd6ba2555 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 2 Oct 2024 15:26:25 +0800 Subject: [PATCH 01/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91=E5=95=86=E5=9F=8E:=20APP=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=A7=AF=E5=88=86=E5=95=86=E5=9F=8E=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/app/point/AppPointActivityController.java | 4 ++++ .../app/point/vo/AppPointActivityDetailRespVO.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java index 20cc8b6c33..ed6998340e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java @@ -74,7 +74,11 @@ public class AppPointActivityController { // 2. 拼接数据 List products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id)); AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class); + // 设置 product 信息 respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class)); + PointProductDO minProduct = getMinPropertyObj(products, PointProductDO::getPoint); + assert minProduct != null; + respVO.setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice()); return success(respVO); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java index 8253e4fe20..9153d68b66 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java @@ -30,6 +30,14 @@ public class AppPointActivityDetailRespVO { @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) private List products; + //======================= 显示所需兑换积分最少的 sku 信息 ======================= + + @Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer point; + + @Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860") + private Integer price; + @Schema(description = "商品信息") @Data public static class Product { From f01c600492b29c0e24a99c1e77150a679846729f Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 4 Oct 2024 11:44:58 +0800 Subject: [PATCH 02/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91=E5=95=86=E5=9F=8E:=20APP=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=A7=AF=E5=88=86=E5=95=86=E5=9F=8E=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E4=BB=B7=E6=A0=BC=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/point/PointActivityApi.java | 25 ++++++ .../point/dto/PointValidateJoinRespDTO.java | 24 ++++++ .../promotion/enums/ErrorCodeConstants.java | 4 + .../api/point/PointActivityApiImpl.java | 26 ++++++ .../dal/mysql/point/PointProductMapper.java | 5 ++ .../service/point/PointActivityService.java | 13 +++ .../point/PointActivityServiceImpl.java | 25 ++++++ .../trade/enums/ErrorCodeConstants.java | 11 +-- .../trade/enums/order/TradeOrderTypeEnum.java | 1 + .../vo/AppTradeOrderSettlementReqVO.java | 8 +- .../convert/order/TradeOrderConvert.java | 3 +- .../service/order/TradeOrderQueryService.java | 6 +- .../order/TradeOrderQueryServiceImpl.java | 4 +- .../price/bo/TradePriceCalculateReqBO.java | 10 ++- .../TradePointActivityPriceCalculator.java | 81 +++++++++++++++++++ .../calculator/TradePriceCalculator.java | 1 + .../TradePriceCalculatorHelper.java | 3 + .../TradeSeckillActivityPriceCalculator.java | 5 +- 18 files changed, 237 insertions(+), 18 deletions(-) create mode 100644 yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java create mode 100644 yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java new file mode 100644 index 0000000000..6e4250c67d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.api.point; + +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; + +/** + * 积分商城活动 API 接口 + * + * @author HUIHUI + */ +public interface PointActivityApi { + + /** + * 【下单前】校验是否参与积分商城活动 + * + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 + * @return 积分商城商品信息 + */ + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); + + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java new file mode 100644 index 0000000000..e3b993461b --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.api.point.dto; + +import lombok.Data; + +/** + * 校验参与积分商城 Response DTO + */ +@Data +public class PointValidateJoinRespDTO { + + /** + * 可兑换次数 + */ + private Integer count; + /** + * 所需兑换积分 + */ + private Integer point; + /** + * 所需兑换金额,单位:分 + */ + private Integer price; + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index af8206d2d3..514cb27aff 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -50,6 +50,10 @@ public interface ErrorCodeConstants { ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改"); ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除"); ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭"); + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_007_005, "积分商品兑换失败,原因:积分商城活动已关闭"); + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_007_006, "积分商品兑换失败,原因:单次限购超出"); + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_007_007, "积分商品兑换失败,原因:商品不存在"); + ErrorCode POINT_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_007_008, "积分商品兑换失败,原因:积分商品库存不足"); // ========== 秒杀活动 1-013-008-000 ========== ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在"); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java new file mode 100644 index 0000000000..7295517975 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.api.point; + +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.service.point.PointActivityService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 积分商城活动 Api 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class PointActivityApiImpl implements PointActivityApi { + + @Resource + private PointActivityService pointActivityService; + + @Override + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { + return pointActivityService.validateJoinPointActivity(activityId, skuId, count); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java index cfa10a5156..1169d8f53c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java @@ -29,4 +29,9 @@ public interface PointProductMapper extends BaseMapperX { .eq(PointProductDO::getActivityId, pointProductDO.getActivityId())); } + default PointProductDO selectListByActivityIdAndSkuId(Long activityId, Long skuId) { + return selectOne(PointProductDO::getActivityId, activityId, + PointProductDO::getSkuId, skuId); + } + } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java index 24facb1824..f93a89f3e5 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.promotion.service.point; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; @@ -78,4 +79,16 @@ public interface PointActivityService { */ List getPointProductListByActivityIds(Collection activityIds); + /** + * 【下单前】校验是否参与积分商城活动 + * + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 + * @return 积分商城商品信息 + */ + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); + } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java index bfce27e1c8..cd03bc45d8 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO; @@ -244,4 +245,28 @@ public class PointActivityServiceImpl implements PointActivityService { return pointProductMapper.selectListByActivityId(activityIds); } + @Override + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { + // 1. 校验积分商城活动是否存在 + PointActivityDO activity = validatePointActivityExists(activityId); + if (CommonStatusEnum.isDisable(activity.getStatus())) { + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED); + } + + // 2.1 校验积分商城商品是否存在 + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(activityId, skuId); + if (product == null) { + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); + } + // 2.2 超过单次购买限制 + if (count > product.getCount()) { + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); + } + // 2.2 校验库存是否充足 + if (count > product.getStock()) { + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); + } + return BeanUtils.toBean(product, PointValidateJoinRespDTO.class); + } + } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 2ab726ec4e..be0ef51ae8 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -58,11 +58,12 @@ public interface ErrorCodeConstants { // ========== Price 相关 1-011-003-000 ============ ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); - ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); - ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配"); - ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_007, "该优惠劵无法使用,原因:{}」"); + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_001, "计算快递运费异常,找不到对应的运费模板"); + ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_002, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); + ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_003, "参与秒杀的商品,超过了秒杀总限购数量"); + ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量"); + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配"); + ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」"); // ========== 物流 Express 模块 1-011-004-000 ========== ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java index f820712068..0e6aad735b 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java @@ -20,6 +20,7 @@ public enum TradeOrderTypeEnum implements IntArrayValuable { SECKILL(1, "秒杀订单"), BARGAIN(2, "砍价订单"), COMBINATION(3, "拼团订单"), + POINT(4, "积分商城"), ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray(); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java index f846ef1d15..7188bc17cc 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java @@ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - import jakarta.validation.Valid; import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; + import java.util.List; @Schema(description = "用户 App - 交易订单结算 Request VO") @@ -62,6 +62,10 @@ public class AppTradeOrderSettlementReqVO { @Schema(description = "砍价记录编号", example = "123") private Long bargainRecordId; + // ========== 积分商城活动相关字段 ========== + @Schema(description = "积分商城活动编号", example = "123") + private Long pointActivityId; + @AssertTrue(message = "活动商品每次只能购买一种规格") @JsonIgnore public boolean isValidActivityItems() { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 60b81057ff..45462a5bee 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -219,7 +219,8 @@ public interface TradeOrderConvert { .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) .setBargainRecordId(settlementReqVO.getBargainRecordId()) .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) - .setCombinationHeadId(settlementReqVO.getCombinationHeadId()); + .setCombinationHeadId(settlementReqVO.getCombinationHeadId()) + .setPointActivityId(settlementReqVO.getPointActivityId()); // 商品项的构建 Map cartMap = convertMap(cartList, CartDO::getId); for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java index 445792232a..b2b8bca981 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java @@ -42,9 +42,9 @@ public interface TradeOrderQueryService { /** * 获得指定用户,指定活动,指定状态的交易订单 * - * @param userId 用户编号 + * @param userId 用户编号 * @param combinationActivityId 活动编号 - * @param status 订单状态 + * @param status 订单状态 * @return 交易订单 */ TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status); @@ -116,7 +116,7 @@ public interface TradeOrderQueryService { * @param activityId 活动编号 * @return 秒杀商品数量 */ - int getSeckillProductCount(Long userId, Long activityId); + int getActivityProductCount(Long userId, Long activityId); // =================== Order Item =================== diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java index 68c549891d..04cd1b6ff1 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -23,10 +23,10 @@ import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClien import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import jakarta.annotation.Resource; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -174,7 +174,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { } @Override - public int getSeckillProductCount(Long userId, Long activityId) { + public int getActivityProductCount(Long userId, Long activityId) { // 获得订单列表 List orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId); orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java index 9b6f1d6bda..ada677f366 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.trade.service.price.bo; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; -import lombok.Data; - import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import lombok.Data; + import java.util.List; /** @@ -84,6 +84,12 @@ public class TradePriceCalculateReqBO { */ private Long bargainRecordId; + // ========== 积分商城活动相关字段 ========== + /** + * 积分商城活动编号 + */ + private Long pointActivityId; + /** * 商品 SKU */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java new file mode 100644 index 0000000000..a220584c7e --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT; + +/** + * 积分商城的 {@link TradePriceCalculator} 实现类 + * + * @author owen + */ +@Component +@Order(TradePriceCalculator.ORDER_POINT_ACTIVITY) +@Slf4j +public class TradePointActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private PointActivityApi pointActivityApi; + + @Resource + private TradeOrderQueryService tradeOrderQueryService; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1. 判断订单类型是否为积分商城活动 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) { + return; + } + + Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品"); + // 2. 校验是否可以参与积分商城活动 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); + PointValidateJoinRespDTO activity = validateJoinSeckill( + param.getUserId(), param.getPointActivityId(), + orderItem.getSkuId(), orderItem.getCount()); + + // 3.1 记录优惠明细 + int discountPrice = 0; + Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); + // 情况一:单使用积分兑换 + if (activity.getPrice() == null || activity.getPrice() == 0) { + discountPrice = orderItem.getPayPrice(); + } else { // 情况二:积分 + 金额 + discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); + } + TradePriceCalculatorHelper.addPromotion(result, orderItem, + param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(), + StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), + discountPrice); + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private PointValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) { + // 1. 校验是否可以参与积分商城活动 + PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count); + // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 + int activityProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); + if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) { + throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT); + } + return pointValidateJoinRespDTO; + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java index 9ed7d9a2fa..a37048b3b8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java @@ -16,6 +16,7 @@ public interface TradePriceCalculator { int ORDER_SECKILL_ACTIVITY = 8; int ORDER_BARGAIN_ACTIVITY = 8; int ORDER_COMBINATION_ACTIVITY = 8; + int ORDER_POINT_ACTIVITY = 8; int ORDER_DISCOUNT_ACTIVITY = 10; int ORDER_REWARD_ACTIVITY = 20; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java index 323b50e93d..0b24e2ea03 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java @@ -90,6 +90,9 @@ public class TradePriceCalculatorHelper { if (param.getBargainRecordId() != null) { return TradeOrderTypeEnum.BARGAIN.getType(); } + if (param.getPointActivityId() != null) { + return TradeOrderTypeEnum.POINT.getType(); + } return TradeOrderTypeEnum.NORMAL.getType(); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java index fe984ec0e0..e1b4ba1945 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java @@ -8,11 +8,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import jakarta.annotation.Resource; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import jakarta.annotation.Resource; - import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; @@ -61,7 +60,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator // 1. 校验是否可以参与秒杀 SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count); // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 - int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); + int seckillProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) { throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT); } From d7236068b98d9f471fb90a0f296d50fe33167927 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 4 Oct 2024 13:08:55 +0800 Subject: [PATCH 03/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91=E5=95=86=E5=9F=8E:=20APP=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=A7=AF=E5=88=86=E5=95=86=E5=9F=8E=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E4=BB=B7=E6=A0=BC=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/price/TradePriceServiceImpl.java | 2 +- .../TradePointActivityPriceCalculator.java | 22 ++++++++++++++----- .../TradePointUsePriceCalculator.java | 6 +++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java index fcf0950550..560056a569 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java @@ -69,7 +69,7 @@ public class TradePriceServiceImpl implements TradePriceService { .buildCalculateResp(calculateReqBO, spuList, skuList); priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 - if (calculateRespBO.getPrice().getPayPrice() <= 0) { + if (calculateReqBO.getPointActivityId() == null && calculateRespBO.getPrice().getPayPrice() <= 0) { log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", calculateReqBO, calculateRespBO); throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java index a220584c7e..3bec8e3436 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; @@ -30,16 +32,26 @@ public class TradePointActivityPriceCalculator implements TradePriceCalculator { @Resource private PointActivityApi pointActivityApi; + @Resource + private MemberUserApi memberUserApi; @Resource private TradeOrderQueryService tradeOrderQueryService; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { - // 1. 判断订单类型是否为积分商城活动 + // 1.1 判断订单类型是否为积分商城活动 if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) { return; } + // 1.2 初始化积分 + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); + result.setTotalPoint(user.getPoint()).setUsePoint(0); + + // 1.3 校验用户积分余额 + if (user.getPoint() == null || user.getPoint() <= 0) { + return; + } Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品"); // 2. 校验是否可以参与积分商城活动 @@ -49,12 +61,10 @@ public class TradePointActivityPriceCalculator implements TradePriceCalculator { orderItem.getSkuId(), orderItem.getCount()); // 3.1 记录优惠明细 - int discountPrice = 0; + int discountPrice = orderItem.getPayPrice(); // 情况一:单使用积分兑换 Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); - // 情况一:单使用积分兑换 - if (activity.getPrice() == null || activity.getPrice() == 0) { - discountPrice = orderItem.getPayPrice(); - } else { // 情况二:积分 + 金额 + result.setUsePoint(activity.getPoint()); + if (activity.getPrice() != null && activity.getPrice() > 0) { // 情况二:积分 + 金额 discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); } TradePriceCalculatorHelper.addPromotion(result, orderItem, diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java index 8dc2b30d0e..0555153513 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java @@ -1,12 +1,14 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import jakarta.annotation.Resource; @@ -37,6 +39,10 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 判断订单类型是否不为积分商城活动 + if (ObjectUtil.equal(result.getType(), TradeOrderTypeEnum.POINT.getType())) { + return; + } // 0. 初始化积分 MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); result.setTotalPoint(user.getPoint()).setUsePoint(0); From 67809be46d94a124d0bb7a92171f1f672072a791 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 4 Oct 2024 13:46:20 +0800 Subject: [PATCH 04/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91=E5=95=86=E5=9F=8E:=20APP=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=A7=AF=E5=88=86=E5=95=86=E5=9F=8E=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E4=B8=8B=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/point/PointActivityApi.java | 17 +++++ .../api/point/PointActivityApiImpl.java | 10 +++ .../dal/mysql/point/PointActivityMapper.java | 31 +++++++++ .../dal/mysql/point/PointProductMapper.java | 29 +++++++++ .../service/point/PointActivityService.java | 18 ++++++ .../point/PointActivityServiceImpl.java | 37 +++++++++++ .../seckill/SeckillActivityServiceImpl.java | 2 +- .../trade/enums/order/TradeOrderTypeEnum.java | 4 ++ .../dal/dataobject/order/TradeOrderDO.java | 7 ++ .../order/handler/TradePointOrderHandler.java | 64 +++++++++++++++++++ .../TradePointActivityPriceCalculator.java | 7 +- 11 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java index 6e4250c67d..0b612cf215 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java @@ -21,5 +21,22 @@ public interface PointActivityApi { */ PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); + /** + * 更新积分商城商品库存(减少) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updatePointStockDecr(Long id, Long skuId, Integer count); + + /** + * 更新积分商城商品库存(增加) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updatePointStockIncr(Long id, Long skuId, Integer count); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java index 7295517975..e97e54c8d3 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java @@ -23,4 +23,14 @@ public class PointActivityApiImpl implements PointActivityApi { return pointActivityService.validateJoinPointActivity(activityId, skuId, count); } + @Override + public void updatePointStockDecr(Long id, Long skuId, Integer count) { + pointActivityService.updatePointStockDecr(id, skuId, count); + } + + @Override + public void updatePointStockIncr(Long id, Long skuId, Integer count) { + pointActivityService.updatePointStockIncr(id, skuId, count); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java index 46db5841e8..d724c32ee5 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.point; +import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; /** @@ -25,4 +27,33 @@ public interface PointActivityMapper extends BaseMapperX { .orderByDesc(PointActivityDO::getId)); } + /** + * 更新活动库存(减少) + * + * @param id 活动编号 + * @param count 扣减的库存数量(正数) + * @return 影响的行数 + */ + default int updateStockDecr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(PointActivityDO::getId, id) + .ge(PointActivityDO::getStock, count) + .setSql("stock = stock - " + count)); + } + + /** + * 更新活动库存(增加) + * + * @param id 活动编号 + * @param count 增加的库存数量(正数) + * @return 影响的行数 + */ + default int updateStockIncr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(PointActivityDO::getId, id) + .setSql("stock = stock + " + count)); + } + } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java index 1169d8f53c..3c6d469a2c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.point; +import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -34,4 +35,32 @@ public interface PointProductMapper extends BaseMapperX { PointProductDO::getSkuId, skuId); } + /** + * 更新活动库存(减少) + * + * @param id 活动编号 + * @param count 扣减的库存数量(减少库存) + * @return 影响的行数 + */ + default int updateStockDecr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(PointProductDO::getId, id) + .ge(PointProductDO::getStock, count) + .setSql("stock = stock - " + count)); + } + + /** + * 更新活动库存(增加) + * + * @param id 活动编号 + * @param count 需要增加的库存(增加库存) + * @return 影响的行数 + */ + default int updateStockIncr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(PointProductDO::getId, id) + .setSql("stock = stock + " + count)); + } } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java index f93a89f3e5..b2b039570b 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java @@ -33,6 +33,24 @@ public interface PointActivityService { */ void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO); + /** + * 更新积分商城商品库存(减少) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updatePointStockDecr(Long id, Long skuId, Integer count); + + /** + * 更新积分商城商品库存(增加) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updatePointStockIncr(Long id, Long skuId, Integer count); + /** * 关闭积分商城活动 * diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java index cd03bc45d8..8e88c5026f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java @@ -103,6 +103,43 @@ public class PointActivityServiceImpl implements PointActivityService { updateSeckillProduct(updateObj, updateReqVO.getProducts()); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePointStockDecr(Long id, Long skuId, Integer count) { + // 1.1 校验活动库存是否充足 + PointActivityDO activity = validatePointActivityExists(id); + if (count > activity.getStock()) { + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); + } + // 1.2 校验商品库存是否充足 + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); + if (product == null || count > product.getStock()) { + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); + } + + // 2.1 更新活动商品库存 + int updateCount = pointProductMapper.updateStockDecr(product.getId(), count); + if (updateCount == 0) { + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); + } + + // 2.2 更新活动库存 + updateCount = pointActivityMapper.updateStockDecr(id, count); + if (updateCount == 0) { + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePointStockIncr(Long id, Long skuId, Integer count) { + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); + // 更新活动商品库存 + pointProductMapper.updateStockIncr(product.getId(), count); + // 更新活动库存 + pointActivityMapper.updateStockIncr(id, count); + } + @Override @Transactional(rollbackFor = Exception.class) public void closePointActivity(Long id) { diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java index 3b7ab3d640..dd8495ae53 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -160,7 +160,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { // 1.1 校验活动库存是否充足 SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); - if (count > seckillActivity.getTotalStock()) { + if (count > seckillActivity.getStock()) { throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); } // 1.2 校验商品库存是否充足 diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java index 0e6aad735b..0fccebb471 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java @@ -55,4 +55,8 @@ public enum TradeOrderTypeEnum implements IntArrayValuable { return ObjectUtil.equal(type, COMBINATION.getType()); } + public static boolean isPoint(Integer type) { + return ObjectUtil.equal(type, POINT.getType()); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index 399b692ede..4c06c80134 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -353,4 +353,11 @@ public class TradeOrderDO extends BaseDO { */ private Long combinationRecordId; + /** + * 积分商城活动的编号 + * + * 关联 PointActivityDO 的 id 字段 + */ + private Long pointActivityId; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java new file mode 100644 index 0000000000..11ca73f6b0 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 积分商城活动订单的 {@link TradeOrderHandler} 实现类 + * + * @author HUIHUI + */ +@Component +public class TradePointOrderHandler implements TradeOrderHandler { + + @Resource + private PointActivityApi pointActivityApi; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isPoint(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); + + // 扣减积分商城活动的库存 + pointActivityApi.updatePointStockDecr(order.getPointActivityId(), + orderItems.get(0).getSkuId(), orderItems.get(0).getCount()); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isPoint(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); + + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + afterCancelOrderItem(order, orderItems.get(0)); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + if (!TradeOrderTypeEnum.isPoint(order.getType())) { + return; + } + // 恢复积分商城活动的库存 + pointActivityApi.updatePointStockIncr(order.getPointActivityId(), + orderItem.getSkuId(), orderItem.getCount()); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java index 3bec8e3436..158eaa3d94 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java @@ -63,15 +63,18 @@ public class TradePointActivityPriceCalculator implements TradePriceCalculator { // 3.1 记录优惠明细 int discountPrice = orderItem.getPayPrice(); // 情况一:单使用积分兑换 Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); - result.setUsePoint(activity.getPoint()); + result.setUsePoint(activity.getPoint() * orderItem.getCount()); + orderItem.setUsePoint(activity.getPoint() * orderItem.getCount()); if (activity.getPrice() != null && activity.getPrice() > 0) { // 情况二:积分 + 金额 discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); } + // 3.2 记录优惠明细 TradePriceCalculatorHelper.addPromotion(result, orderItem, param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(), StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), discountPrice); - // 3.2 更新 SKU 优惠金额 + + // 3.3 更新 SKU 优惠金额 orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); TradePriceCalculatorHelper.recountPayPrice(orderItem); TradePriceCalculatorHelper.recountAllPrice(result); From 5f75fcb0fb1943bd5932827a3a2bc25ecc52c4af Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 4 Oct 2024 17:17:01 +0800 Subject: [PATCH 05/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E5=B7=A5=E4=BD=9C=E6=B5=81=EF=BC=9A=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E7=94=A8=E4=B8=8D=E5=88=B0=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- yudao-server/pom.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index f826064cd7..908c3808fd 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - yudao-module-bpm + diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index b20dd47280..efd53c84a5 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - cn.iocoder.boot - yudao-module-bpm-biz - ${revision} - + + + + + From e604cba3bf9ab489d6e4596a66713676982b85b1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 4 Oct 2024 18:40:33 +0800 Subject: [PATCH 06/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91=E5=95=86=E5=9F=8E=EF=BC=9A=E7=A7=AF=E5=88=86?= =?UTF-8?q?=E5=95=86=E5=9F=8E=E7=9A=84=E4=B8=8B=E5=8D=95=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/app/point/AppPointActivityController.java | 9 ++++----- .../app/point/vo/AppPointActivityDetailRespVO.java | 2 +- .../trade/service/order/TradeOrderQueryService.java | 2 +- .../trade/service/order/TradeOrderQueryServiceImpl.java | 2 +- .../trade/service/price/TradePriceServiceImpl.java | 3 ++- .../calculator/TradePointActivityPriceCalculator.java | 2 +- .../calculator/TradeSeckillActivityPriceCalculator.java | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java index f607aea777..1ffeb770f7 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java @@ -73,12 +73,11 @@ public class AppPointActivityController { // 2. 拼接数据 List products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id)); - AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class); - // 设置 product 信息 - respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class)); - PointProductDO minProduct = getMinPropertyObj(products, PointProductDO::getPoint); + PointProductDO minProduct = getMinObject(products, PointProductDO::getPoint); assert minProduct != null; - respVO.setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice()); + AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class) + .setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class)) + .setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice()); return success(respVO); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java index 9153d68b66..2e02f107a9 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java @@ -30,7 +30,7 @@ public class AppPointActivityDetailRespVO { @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) private List products; - //======================= 显示所需兑换积分最少的 sku 信息 ======================= + //======================= 显示所需兑换积分最少的 SKU 信息 ======================= @Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED) private Integer point; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java index b2b8bca981..5e436d959a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java @@ -116,7 +116,7 @@ public interface TradeOrderQueryService { * @param activityId 活动编号 * @return 秒杀商品数量 */ - int getActivityProductCount(Long userId, Long activityId); + int getSeckillProductCount(Long userId, Long activityId); // =================== Order Item =================== diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java index 04cd1b6ff1..b105e93eae 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -174,7 +174,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { } @Override - public int getActivityProductCount(Long userId, Long activityId) { + public int getSeckillProductCount(Long userId, Long activityId) { // 获得订单列表 List orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId); orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java index 560056a569..72102a6d3c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java @@ -69,7 +69,8 @@ public class TradePriceServiceImpl implements TradePriceService { .buildCalculateResp(calculateReqBO, spuList, skuList); priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 - if (calculateReqBO.getPointActivityId() == null && calculateRespBO.getPrice().getPayPrice() <= 0) { + if (calculateReqBO.getPointActivityId() == null // 积分订单,允许支付金额为 0 + && calculateRespBO.getPrice().getPayPrice() <= 0) { log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", calculateReqBO, calculateRespBO); throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java index 158eaa3d94..4670cf9dec 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java @@ -84,7 +84,7 @@ public class TradePointActivityPriceCalculator implements TradePriceCalculator { // 1. 校验是否可以参与积分商城活动 PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count); // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 - int activityProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); + int activityProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) { throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java index e1b4ba1945..90ae4fb25b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java @@ -60,7 +60,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator // 1. 校验是否可以参与秒杀 SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count); // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 - int seckillProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); + int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) { throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT); } From 2c4d8298cfe3d349149ab76729bf77d1c453542a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 4 Oct 2024 19:17:16 +0800 Subject: [PATCH 07/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91=E5=95=86=E5=9F=8E=EF=BC=9A=E7=BA=AF=E7=A7=AF?= =?UTF-8?q?=E5=88=86=E5=85=91=E6=8D=A2=E6=97=B6=EF=BC=8C=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=B8=BA=E5=BE=85=E5=8F=91=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/service/order/TradeOrderUpdateServiceImpl.java | 5 ++++- .../service/order/handler/TradePointOrderHandler.java | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index e0c303ed36..74a2643e37 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -245,7 +245,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { } // 3. 生成预支付 - createPayOrder(order, orderItems); + // 特殊情况:积分兑换时,可能支付金额为零 + if (order.getPayPrice() > 0) { + createPayOrder(order, orderItems); + } // 4. 插入订单日志 TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java index 11ca73f6b0..9c60accef4 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java @@ -5,11 +5,13 @@ import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; import java.util.List; +import java.util.Objects; /** * 积分商城活动订单的 {@link TradeOrderHandler} 实现类 @@ -33,6 +35,11 @@ public class TradePointOrderHandler implements TradeOrderHandler { // 扣减积分商城活动的库存 pointActivityApi.updatePointStockDecr(order.getPointActivityId(), orderItems.get(0).getSkuId(), orderItems.get(0).getCount()); + + // 如果支付金额为 0,则直接设置为已支付 + if (Objects.equals(order.getPayPrice(), 0)) { + order.setPayStatus(true).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()); + } } @Override From f9ce9703bf44655be07c1f89e7492f1cea814e80 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 7 Oct 2024 15:54:30 +0800 Subject: [PATCH 08/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91=E5=B7=A5=E4=BD=9C=E6=B5=81=EF=BC=9ACandidate?= =?UTF-8?q?GroupStrategyTest=20=E5=8D=95=E6=B5=8B=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E7=A6=81=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../strategy/BpmTaskCandidateDeptLeaderStrategyTest.java | 2 ++ .../strategy/BpmTaskCandidateDeptMemberStrategyTest.java | 2 ++ .../strategy/BpmTaskCandidateExpressionStrategyTest.java | 4 +++- .../candidate/strategy/BpmTaskCandidateGroupStrategyTest.java | 2 ++ .../candidate/strategy/BpmTaskCandidatePostStrategyTest.java | 2 ++ .../candidate/strategy/BpmTaskCandidateRoleStrategyTest.java | 2 ++ .../candidate/strategy/BpmTaskCandidateUserStrategyTest.java | 2 ++ 7 files changed, 15 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java index 9b89e2bd38..0d19b4004e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -16,6 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java index 4e72c0281a..a0e75fccc3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -16,6 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java index eaa2ef7b58..5182ab03b3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java @@ -1,8 +1,9 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.MockedStatic; @@ -14,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java index 8bd2c88afd..3977879cee 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -16,6 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java index a30ce28eb0..dab58d4c2e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.system.api.dept.PostApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -17,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java index 7c4247bcd1..838cb1b5d9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -14,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest { @InjectMocks diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java index d71ccebfd7..ca1b71e98d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -9,6 +10,7 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static org.junit.jupiter.api.Assertions.assertEquals; +@Disabled // TODO 芋艿:临时注释 public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest { @InjectMocks From 47fa66a41206c5397d67ddddd53b7aa744391cbe Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 7 Oct 2024 15:57:12 +0800 Subject: [PATCH 09/43] =?UTF-8?q?V2.3.0=20=E7=89=88=E6=9C=AC=E5=8F=91?= =?UTF-8?q?=E5=B8=83~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/bpm_update.sql | 11 ---- sql/mysql/ruoyi-vue-pro.sql | 109 ++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 58 deletions(-) delete mode 100644 sql/mysql/bpm_update.sql diff --git a/sql/mysql/bpm_update.sql b/sql/mysql/bpm_update.sql deleted file mode 100644 index 40a5bc973d..0000000000 --- a/sql/mysql/bpm_update.sql +++ /dev/null @@ -1,11 +0,0 @@ --- ---------------------------- --- 流程抄送表新加流程活动编号 --- ---------------------------- -ALTER TABLE `pro-test`.`bpm_process_instance_copy` - ADD COLUMN `activity_id` varchar(64) NULL COMMENT '流程活动编号' AFTER `category`, - MODIFY COLUMN `task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务编号' AFTER `category`; - -ALTER TABLE `pro-test`.`bpm_process_definition_info` - ADD COLUMN `model_type` tinyint NOT NULL DEFAULT 10 COMMENT '流程模型的类型' AFTER `model_id`, - ADD COLUMN `simple_model` json NULL COMMENT 'SIMPLE 设计器模型数据' AFTER `form_custom_view_path`, - ADD COLUMN `visible` bit(1) NOT NULL DEFAULT 1 COMMENT '是否可见' AFTER `simple_model`; \ No newline at end of file diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 405fd743ff..6f71bc6802 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -11,7 +11,7 @@ Target Server Version : 80200 (8.2.0) File Encoding : 65001 - Date: 31/08/2024 09:22:45 + Date: 07/10/2024 15:55:58 */ SET NAMES utf8mb4; @@ -91,7 +91,7 @@ CREATE TABLE `infra_api_error_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 20014 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 21016 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; -- ---------------------------- -- Records of infra_api_error_log @@ -250,7 +250,7 @@ CREATE TABLE `infra_file` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1472 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1509 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; -- ---------------------------- -- Records of infra_file @@ -328,13 +328,13 @@ CREATE TABLE `infra_job` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; +) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; -- ---------------------------- -- Records of infra_job -- ---------------------------- BEGIN; -INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2024-09-12 13:32:48', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0'); @@ -344,7 +344,7 @@ INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param` INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', b'0'); -INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2024-09-12 13:40:34', b'0'); COMMIT; -- ---------------------------- @@ -368,7 +368,7 @@ CREATE TABLE `infra_job_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 395 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; +) ENGINE = InnoDB AUTO_INCREMENT = 634 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; -- ---------------------------- -- Records of infra_job_log @@ -405,7 +405,7 @@ BEGIN; INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', b'0', 1); -INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-10-02 10:22:03', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', b'0', 1); @@ -438,7 +438,7 @@ CREATE TABLE `system_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1592 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1593 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; -- ---------------------------- -- Records of system_dict_data @@ -597,8 +597,8 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, 2, '砍价订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2024-09-07 14:18:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1202, 3, '拼团订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2024-09-07 14:18:32', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', b'0'); @@ -628,7 +628,6 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', b'0'); @@ -862,6 +861,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1589, 10, 'BPMN 设计器', '10', 'bpm_model_type', 0, 'primary', '', '', '1', '2024-08-26 15:22:17', '1', '2024-08-26 16:46:02', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1590, 20, 'SIMPLE 设计器', '20', 'bpm_model_type', 0, 'success', '', '', '1', '2024-08-26 15:22:27', '1', '2024-08-26 16:45:58', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1591, 4, '七牛云', 'QINIU', 'system_sms_channel_code', 0, '', '', '', '1', '2024-08-31 08:45:03', '1', '2024-08-31 08:45:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1592, 3, '新人券', '3', 'promotion_coupon_take_type', 0, 'info', '', '新人注册后,自动发放', '1', '2024-09-03 11:57:16', '1', '2024-09-03 11:57:28', b'0'); COMMIT; -- ---------------------------- @@ -1003,7 +1003,7 @@ CREATE TABLE `system_login_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 3289 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; +) ENGINE = InnoDB AUTO_INCREMENT = 3335 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; -- ---------------------------- -- Records of system_login_log @@ -1069,7 +1069,7 @@ CREATE TABLE `system_mail_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 356 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; +) ENGINE = InnoDB AUTO_INCREMENT = 359 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; -- ---------------------------- -- Records of system_mail_log @@ -1134,7 +1134,7 @@ CREATE TABLE `system_menu` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2808 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; +) ENGINE = InnoDB AUTO_INCREMENT = 2814 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; -- ---------------------------- -- Records of system_menu @@ -1332,7 +1332,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, b'1', b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2024-09-06 09:19:42', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); @@ -1589,7 +1589,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, b'1', b'1', b'1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2364, '用户余额修改', 'pay:wallet:update-balance', 3, 7, 2317, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '1', '2024-10-01 09:42:57', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, b'1', b'1', b'1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', b'0'); @@ -1977,6 +1977,12 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2805, '会话删除', 'promotion:kefu-conversation:delete', 3, 3, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:19:51', '1', '2024-08-31 09:20:32', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2806, '消息发送', 'promotion:kefu-message:send', 3, 12, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:20:06', '1', '2024-08-31 09:20:06', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2807, '消息更新', 'promotion:kefu-message:update', 3, 11, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:20:22', '1', '2024-08-31 09:20:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2808, '积分商城', '', 2, 5, 2030, 'point-activity', 'ep:bowl', 'mall/promotion/point/activity/index', 'PointActivity', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-23 09:14:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2809, '积分商城活动查询', 'promotion:point-activity:query', 3, 1, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2810, '积分商城活动创建', 'promotion:point-activity:create', 3, 2, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2811, '积分商城活动更新', 'promotion:point-activity:update', 3, 3, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2812, '积分商城活动删除', 'promotion:point-activity:delete', 3, 4, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2813, '积分商城活动导出', 'promotion:point-activity:export', 3, 5, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:27', b'0'); COMMIT; -- ---------------------------- @@ -2003,7 +2009,7 @@ CREATE TABLE `system_notice` ( -- ---------------------------- BEGIN; INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', b'0', 1); -INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

\"\"11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', b'0', 1); +INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

\"\"11112222\"image\"

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2024-09-24 20:48:09', b'0', 1); INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', b'0', 121); COMMIT; @@ -2098,7 +2104,7 @@ CREATE TABLE `system_oauth2_access_token` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_access_token`(`access_token` ASC) USING BTREE, INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 9563 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 10113 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; -- ---------------------------- -- Records of system_oauth2_access_token @@ -2220,7 +2226,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 1652 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; -- ---------------------------- -- Records of system_oauth2_refresh_token @@ -2253,7 +2259,7 @@ CREATE TABLE `system_operate_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 9056 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; +) ENGINE = InnoDB AUTO_INCREMENT = 9063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; -- ---------------------------- -- Records of system_operate_log @@ -3203,7 +3209,7 @@ CREATE TABLE `system_sms_channel` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信渠道'; +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信渠道'; -- ---------------------------- -- Records of system_sms_channel @@ -3211,6 +3217,7 @@ CREATE TABLE `system_sms_channel` ( BEGIN; INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2024-08-04 08:53:26', b'0'); INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', b'0'); +INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 'mock腾讯云', 'TENCENT', 0, '', '1 2', '2 3', '', '1', '2024-09-30 08:53:45', '1', '2024-09-30 08:55:01', b'0'); COMMIT; -- ---------------------------- @@ -3235,7 +3242,7 @@ CREATE TABLE `system_sms_code` ( `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' -) ENGINE = InnoDB AUTO_INCREMENT = 632 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; +) ENGINE = InnoDB AUTO_INCREMENT = 639 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; -- ---------------------------- -- Records of system_sms_code @@ -3276,7 +3283,7 @@ CREATE TABLE `system_sms_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1088 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 1147 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; -- ---------------------------- -- Records of system_sms_log @@ -3315,7 +3322,7 @@ BEGIN; INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '[\"operation\",\"code\"]', '测试备注', '4383920', 4, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2024-08-18 11:57:18', b'0'); INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '[\"code\"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', b'0'); INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '[\"name\"]', 'f哈哈哈', '4383920', 4, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2024-08-18 11:57:07', b'0'); -INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '[\"name\",\"code\"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '[\"name\",\"code\"]', '哈哈哈哈', 'suibian', 7, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2024-09-30 00:56:24', b'0'); INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '[\"code\"]', NULL, '4372216', 4, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2024-08-18 11:57:06', b'0'); INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '[\"processInstanceName\",\"taskName\",\"startUserNickname\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', b'0'); INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '[\"processInstanceName\",\"reason\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', b'0'); @@ -3381,7 +3388,7 @@ CREATE TABLE `system_social_user` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; +) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; -- ---------------------------- -- Records of system_social_user @@ -3406,7 +3413,7 @@ CREATE TABLE `system_social_user_bind` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 120 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; +) ENGINE = InnoDB AUTO_INCREMENT = 121 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; -- ---------------------------- -- Records of system_social_user_bind @@ -3443,7 +3450,7 @@ CREATE TABLE `system_tenant` ( BEGIN; INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', b'0'); INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2025-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2024-07-20 22:21:53', b'0'); -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-07-20 15:51:18', b'0'); +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', b'0'); COMMIT; -- ---------------------------- @@ -3518,7 +3525,7 @@ CREATE TABLE `system_user_role` ( `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; +) ENGINE = InnoDB AUTO_INCREMENT = 47 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; -- ---------------------------- -- Records of system_user_role @@ -3539,6 +3546,7 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', b'0', 1); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', b'0', 1); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (46, 117, 1, '1', '2024-10-02 10:16:11', '1', '2024-10-02 10:16:11', b'0', 1); COMMIT; -- ---------------------------- @@ -3567,16 +3575,16 @@ CREATE TABLE `system_users` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 139 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表'; +) ENGINE = InnoDB AUTO_INCREMENT = 140 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表'; -- ---------------------------- -- Records of system_users -- ---------------------------- BEGIN; -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-08-26 16:54:00', 'admin', '2021-01-05 17:03:47', NULL, '2024-08-26 16:54:00', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', '1', '2024-08-17 11:06:13', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-10-07 15:05:17', 'admin', '2021-01-05 17:03:47', NULL, '2024-10-07 15:05:17', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', '1', '2024-09-22 14:55:06', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$04$fUBSmjKCPYAUmnMzOb6qE.eZCGPhHi1JmAKclODbfS/O7fHOl2bH6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', NULL, '2024-08-11 17:48:12', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$jDFLttgfik0QqJKAbfhMa.2A9xXoZmAIxakdFJUzkX.MgBKT6ddo6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-08-11 09:38:08', '', '2021-01-21 02:13:53', NULL, '2024-08-11 09:38:08', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$jDFLttgfik0QqJKAbfhMa.2A9xXoZmAIxakdFJUzkX.MgBKT6ddo6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-09-17 15:05:43', '', '2021-01-21 02:13:53', NULL, '2024-09-17 15:05:43', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); @@ -3586,9 +3594,10 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', b'0', 122); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号02', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2024-08-11 10:12:03', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$04$sEtimsHu9YCkYY4/oqElHem2Ijc9ld20eYO6lN.g/21NfLUTDLB9W', '测试号02', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', NULL, '2024-10-02 10:16:20', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-09-06 21:40:43', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (139, 'wwbwwb', '$2a$04$aOHoFbQU6zfBk/1Z9raF/ugTdhjNdx7culC1HhO0zvoczAnahCiMq', '小秃头', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', b'0', 1); COMMIT; -- ---------------------------- @@ -3663,22 +3672,28 @@ CREATE TABLE `yudao_demo03_course` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表'; +) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表'; -- ---------------------------- -- Records of yudao_demo03_course -- ---------------------------- BEGIN; -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', b'1', 1); INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1); INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1); INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1); INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1); -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', b'1', 1); INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', b'1', 1); -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:26', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (14, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:49', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (15, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (16, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (17, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (19, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 18:55:50', b'0', 1); COMMIT; -- ---------------------------- @@ -3703,9 +3718,9 @@ CREATE TABLE `yudao_demo03_grade` ( -- Records of yudao_demo03_grade -- ---------------------------- BEGIN; -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', b'0', 1); +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1); +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1); +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2024-09-17 18:55:50', b'0', 1); COMMIT; -- ---------------------------- @@ -3731,9 +3746,9 @@ CREATE TABLE `yudao_demo03_student` ( -- Records of yudao_demo03_student -- ---------------------------- BEGIN; -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', b'0', 1); -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', b'0', 1); -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', b'0', 1); +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1); +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1); +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2024-09-17 18:55:50', b'0', 1); COMMIT; SET FOREIGN_KEY_CHECKS = 1; From 8da00083d8fa5c4edcef8196eac46cda7eff04ef Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 7 Oct 2024 16:03:05 +0800 Subject: [PATCH 10/43] =?UTF-8?q?V2.3.0=20=E7=89=88=E6=9C=AC=E5=8F=91?= =?UTF-8?q?=E5=B8=83~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- yudao-dependencies/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 908c3808fd..97a28af11c 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 2.2.0-SNAPSHOT + 2.3.0-SNAPSHOT 17 ${java.version} diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 1cc3111cdd..0238c75b3e 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -14,7 +14,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 2.2.0-SNAPSHOT + 2.3.0-SNAPSHOT 1.6.0 3.3.4 From 6f7fe84c41d23d3f67ca043efef680d5c0973a25 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 12 Oct 2024 19:47:18 +0800 Subject: [PATCH 11/43] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91AI=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=9AMidjourney=20notify=20=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E7=BC=BA=E5=B0=91=E7=A7=9F=E6=88=B7=E7=9A=84=E5=BF=BD?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/ai/controller/admin/image/AiImageController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java index 4cd8e55c2e..aaa142b7c3 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*; import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO; import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO; @@ -95,6 +96,7 @@ public class AiImageController { @Operation(summary = "【Midjourney】通知图片进展", description = "由 Midjourney Proxy 回调") @PostMapping("/midjourney/notify") // 必须是 POST 方法,否则会报错 @PermitAll + @TenantIgnore public CommonResult midjourneyNotify(@Valid @RequestBody MidjourneyApi.Notify notify) { imageService.midjourneyNotify(notify); return success(true); From 7e3f92c3a320c9fada0f7bee84afee5dd955b2db Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 12 Oct 2024 19:55:13 +0800 Subject: [PATCH 12/43] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E5=A4=9A=E7=A7=9F=E6=88=B7=E7=9A=84=E8=A1=A8?= =?UTF-8?q?=EF=BC=8C=E5=85=BC=E5=AE=B9=E8=A1=A8=E5=90=8D=E5=B8=A6=E6=9C=89?= =?UTF-8?q?=E5=8C=85=E8=A3=B9=E7=AC=A6=E5=8F=B7=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/tenant/core/db/TenantDatabaseInterceptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java index 8ea1a96b87..8f1c8acca6 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.tenant.config.TenantProperties; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; @@ -37,7 +38,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler { @Override public boolean ignoreTable(String tableName) { return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户 - || CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表 + || CollUtil.contains(ignoreTables, SqlParserUtils.removeWrapperSymbol(tableName)); // 情况二,忽略多租户的表 } } From 6e7db6ebd02b323090d289df58ed9093ee7d8900 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 12 Oct 2024 20:38:22 +0800 Subject: [PATCH 13/43] =?UTF-8?q?!144=20=E3=80=90=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E3=80=91=E5=95=86=E5=9F=8E=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0@PermitAll=E5=92=8C=E9=83=A8=E5=88=86DO?= =?UTF-8?q?=E7=BC=BA=E5=B0=91@KeySequence=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/ai/dal/dataobject/image/AiImageDO.java | 3 ++- .../ai/dal/dataobject/knowledge/AiKnowledgeDO.java | 2 ++ .../dal/dataobject/knowledge/AiKnowledgeDocumentDO.java | 2 ++ .../dal/dataobject/knowledge/AiKnowledgeSegmentDO.java | 2 ++ .../module/ai/dal/dataobject/mindmap/AiMindMapDO.java | 3 ++- .../module/ai/dal/dataobject/model/AiChatRoleDO.java | 4 +++- .../yudao/module/ai/dal/dataobject/music/AiMusicDO.java | 3 ++- .../yudao/module/ai/dal/dataobject/write/AiWriteDO.java | 3 ++- .../bpm/dal/dataobject/definition/BpmCategoryDO.java | 5 ++++- .../module/bpm/dal/dataobject/definition/BpmFormDO.java | 7 ++++++- .../definition/BpmProcessDefinitionInfoDO.java | 2 ++ .../dataobject/definition/BpmProcessExpressionDO.java | 9 ++++----- .../dal/dataobject/definition/BpmProcessListenerDO.java | 2 ++ .../bpm/dal/dataobject/definition/BpmUserGroupDO.java | 2 ++ .../yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java | 7 ++++++- .../dal/dataobject/task/BpmProcessInstanceCopyDO.java | 7 ++++++- .../product/dal/dataobject/brand/ProductBrandDO.java | 2 ++ .../dal/dataobject/category/ProductCategoryDO.java | 2 ++ .../module/promotion/dal/dataobject/banner/BannerDO.java | 2 ++ .../controller/app/order/AppTradeOrderController.java | 1 + .../trade/dal/dataobject/aftersale/AfterSaleDO.java | 2 ++ .../yudao/module/trade/dal/dataobject/cart/CartDO.java | 2 ++ .../trade/dal/dataobject/order/TradeOrderItemDO.java | 2 ++ .../member/dal/dataobject/address/MemberAddressDO.java | 2 ++ .../module/system/dal/dataobject/mail/MailAccountDO.java | 2 ++ .../module/system/dal/dataobject/mail/MailLogDO.java | 2 ++ .../system/dal/dataobject/mail/MailTemplateDO.java | 2 ++ 27 files changed, 70 insertions(+), 14 deletions(-) diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java index 579952f716..56749a1d00 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -24,6 +24,7 @@ import java.util.Map; * @author fansili */ @TableName(value = "ai_image", autoResultMap = true) +@KeySequence("ai_image_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiImageDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java index b1706154a1..638a8ba50b 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -16,6 +17,7 @@ import java.util.List; * @author xiaoxin */ @TableName(value = "ai_knowledge", autoResultMap = true) +@KeySequence("ai_knowledge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiKnowledgeDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java index 297944611e..ee8bfd5aab 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.enums.knowledge.AiKnowledgeDocumentStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -13,6 +14,7 @@ import lombok.Data; * @author xiaoxin */ @TableName(value = "ai_knowledge_document") +@KeySequence("ai_knowledge_document_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiKnowledgeDocumentDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java index 9bb3d33380..b08e960d14 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -12,6 +13,7 @@ import lombok.Data; * @author xiaoxin */ @TableName(value = "ai_knowledge_segment") +@KeySequence("ai_knowledge_segment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiKnowledgeSegmentDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java index 824881bf35..b9768529f1 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.mindmap; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -13,6 +13,7 @@ import lombok.Data; * @author xiaoxin */ @TableName(value = "ai_mind_map") +@KeySequence("ai_mind_map_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiMindMapDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java index 28f6cda43d..f5ed533a92 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; /** diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java index 97491ec4f5..e03d62c162 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; -import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -19,6 +19,7 @@ import java.util.List; * @author xiaoxin */ @TableName(value = "ai_music", autoResultMap = true) +@KeySequence("ai_music_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiMusicDO extends BaseDO { diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java index 5d2f6dcf1b..0d6f9c5e64 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.write; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum; -import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -14,6 +14,7 @@ import lombok.Data; * @author xiaoxin */ @TableName("ai_write") +@KeySequence("ai_write_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class AiWriteDO extends BaseDO { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java index 916009d377..01c71ebac9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java @@ -4,7 +4,10 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * BPM 流程分类 DO diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java index 4c0218896d..21080cbb18 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java @@ -1,11 +1,15 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; @@ -16,6 +20,7 @@ import java.util.List; * @author 芋道源码 */ @TableName(value = "bpm_form", autoResultMap = true) +@KeySequence("bpm_form_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java index d6a3093d88..35864f4a6a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -25,6 +26,7 @@ import java.util.List; * @author 芋道源码 */ @TableName(value = "bpm_process_definition_info", autoResultMap = true) +@KeySequence("bpm_process_definition_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java index 6f6be586ec..18494b68de 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java @@ -1,11 +1,10 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * BPM 流程表达式 DO diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java index 56be88ff3c..08ecebe112 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; @@ -16,6 +17,7 @@ import lombok.NoArgsConstructor; * @author 芋道源码 */ @TableName(value = "bpm_process_listener") +@KeySequence("bpm_process_listener_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java index 2de62c7f64..7b9f480b56 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -19,6 +20,7 @@ import java.util.Set; * @author 芋道源码 */ @TableName(value = "bpm_user_group", autoResultMap = true) +@KeySequence("bpm_user_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java index 6c5b648dac..e75c974738 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.time.LocalDateTime; @@ -17,6 +21,7 @@ import java.time.LocalDateTime; * @author 芋道源码 */ @TableName("bpm_oa_leave") +@KeySequence("bpm_oa_leave_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java index 29da3fcfcb..4150612efb 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java @@ -1,9 +1,13 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.task; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * 流程抄送 DO @@ -12,6 +16,7 @@ import lombok.*; * @since 2024-01-22 */ @TableName(value = "bpm_process_instance_copy", autoResultMap = true) +@KeySequence("bpm_process_instance_copy_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java index e2178d5c4c..72654409fe 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.dal.dataobject.brand; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -12,6 +13,7 @@ import lombok.*; * @author 芋道源码 */ @TableName("product_brand") +@KeySequence("product_brand_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java index 78e35d6f55..44c6c0953b 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.dal.dataobject.category; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -12,6 +13,7 @@ import lombok.*; * @author 芋道源码 */ @TableName("product_category") +@KeySequence("product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java index fad9385b2b..cb5ee344b3 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.banner; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.promotion.enums.banner.BannerPositionEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -12,6 +13,7 @@ import lombok.*; * @author xia */ @TableName("promotion_banner") +@KeySequence("promotion_banner_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 40342a16ae..b2b887050a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -80,6 +80,7 @@ public class AppTradeOrderController { @PostMapping("/update-paid") @Operation(summary = "更新订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll public CommonResult updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), notifyReqDTO.getPayOrderId()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java index 98dfbd4e20..40a9c88956 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -22,6 +23,7 @@ import java.util.List; * @author 芋道源码 */ @TableName(value = "trade_after_sale", autoResultMap = true) +@KeySequence("trade_after_sale_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java index d8bf140883..dd85220a82 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.cart; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -14,6 +15,7 @@ import lombok.experimental.Accessors; * @author 芋道源码 */ @TableName("trade_cart") +@KeySequence("trade_cart_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index 450bc764fd..ed1bef3d3c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -20,6 +21,7 @@ import java.util.List; * @author 芋道源码 */ @TableName(value = "trade_order_item", autoResultMap = true) +@KeySequence("trade_order_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Accessors(chain = true) @EqualsAndHashCode(callSuper = true) diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java index f2e43b563e..0679a8c0c8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.member.dal.dataobject.address; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -11,6 +12,7 @@ import lombok.*; * @author 芋道源码 */ @TableName("member_address") +@KeySequence("member_address_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java index 0f9588616a..1fcd22f5b2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -15,6 +16,7 @@ import lombok.EqualsAndHashCode; * @since 2022-03-21 */ @TableName(value = "system_mail_account", autoResultMap = true) +@KeySequence("system_mail_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) public class MailAccountDO extends BaseDO { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java index 0d08c71175..76e1e2ec5d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -20,6 +21,7 @@ import java.util.Map; * @since 2022-03-21 */ @TableName(value = "system_mail_log", autoResultMap = true) +@KeySequence("system_mail_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java index f669b455f0..69e4909db9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -17,6 +18,7 @@ import java.util.List; * @since 2022-03-21 */ @TableName(value = "system_mail_template", autoResultMap = true) +@KeySequence("system_mail_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) public class MailTemplateDO extends BaseDO { From 9ad95223d1787e39818140d7562fb89165236ed3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 13 Oct 2024 17:00:14 +0800 Subject: [PATCH 14/43] =?UTF-8?q?=E3=80=90=E4=BE=9D=E8=B5=96=E9=99=8D?= =?UTF-8?q?=E7=BA=A7=E3=80=91weixin-java=20from=204.6.5B=20to=204.6.0?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=20privateCertPath=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 0238c75b3e..35c712062b 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -73,7 +73,7 @@ 8.5.7 2.0.5 1.8.1 - 4.6.5.B + 4.6.0 From 7fbdf24bcaa2a14f4d08f279c6f33ec2936c2d95 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 13 Oct 2024 17:10:45 +0800 Subject: [PATCH 15/43] =?UTF-8?q?1103=20=E3=80=90=E8=BD=BB=E9=87=8F?= =?UTF-8?q?=E7=BA=A7=20PR=E3=80=91=EF=BC=9A=E3=80=90=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E3=80=91=E8=A1=A5=E5=85=A8=E9=80=80=E6=AC=BE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/pay/api/order/dto/PayOrderRespDTO.java | 7 +++++++ .../yudao/module/pay/api/refund/dto/PayRefundRespDTO.java | 7 +++++++ .../module/pay/dal/dataobject/refund/PayRefundDO.java | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java index 583d6d54d7..a1c9c32b3b 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.api.order.dto; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import lombok.Data; +import java.time.LocalDateTime; + /** * 支付单信息 Response DTO * @@ -41,6 +43,11 @@ public class PayOrderRespDTO { */ private Integer status; + /** + * 订单支付成功时间 + */ + private LocalDateTime successTime; + // ========== 渠道相关字段 ========== } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java index bcc2b7ffae..0065cb4934 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java @@ -18,6 +18,13 @@ public class PayRefundRespDTO { */ private Long id; + /** + * 渠道编码 + * + * 枚举 PayChannelEnum + */ + private String channelCode; + // ========== 退款相关字段 ========== /** * 退款状态 diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java index 5d9c612a33..475f62a96f 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java @@ -59,7 +59,7 @@ public class PayRefundDO extends BaseDO { */ private Long channelId; /** - * 商户编码 + * 渠道编码 * * 枚举 {@link PayChannelEnum} */ From 88f1af6d2ebd38348ee77ce0cfa7d1b2625079f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=9D=B0?= <827807823> Date: Wed, 16 Oct 2024 20:26:11 +0800 Subject: [PATCH 16/43] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=BB=91?= =?UTF-8?q?=E5=8A=A8=E8=84=B1=E6=95=8F=E5=A4=84=E7=90=86=E5=99=A8=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E8=84=B1=E6=95=8F=E7=9A=84=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slider/handler/AbstractSliderDesensitizationHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java index 66933f7cdb..018fc87893 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java @@ -17,7 +17,7 @@ public abstract class AbstractSliderDesensitizationHandler public String desensitize(String origin, T annotation) { // 1. 判断是否禁用脱敏 Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation)); - if (Boolean.FALSE.equals(disable)) { + if (Boolean.TRUE.equals(disable)) { return origin; } From 922aa0678d982a2378eef5132f15da0577d6c05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=87=E5=BA=86?= Date: Wed, 16 Oct 2024 16:32:50 +0000 Subject: [PATCH 17/43] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BD=93=E4=B8=8D=E5=AD=98=E5=9C=A8=E4=BC=98?= =?UTF-8?q?=E6=83=A0=E4=BB=B7=E6=A0=BC=E6=97=B6=EF=BC=8C=E5=95=86=E5=9F=8E?= =?UTF-8?q?=E5=8D=B4=E6=98=BE=E7=A4=BA=E4=BC=98=E6=83=A0=E4=BB=B7=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨宇庆 --- .../yudao/module/trade/service/price/TradePriceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java index 3bcc004431..70e9115601 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java @@ -122,7 +122,7 @@ public class TradePriceServiceImpl implements TradePriceService { List skuList = spuIdAndSkuListMap.get(spuId); List skuVOList = convertList(skuList, sku -> { AppTradeProductSettlementRespVO.Sku skuVO = new AppTradeProductSettlementRespVO.Sku() - .setId(sku.getId()).setPromotionPrice(sku.getPrice()); + .setId(sku.getId()); TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem() .setPayPrice(sku.getPrice()).setCount(1); // 计算限时折扣的优惠价格 From c3e1374b1e08df8041368c42173f90a774d08f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=87=E5=BA=86?= Date: Wed, 23 Oct 2024 09:02:41 +0000 Subject: [PATCH 18/43] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95=E5=8F=91=E8=B5=B7=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E5=BC=82=E5=B8=B8=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨宇庆 --- .../pay/core/client/impl/weixin/AbstractWxPayClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index 298e314d85..73d482a5bf 100644 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -88,6 +88,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient Date: Fri, 25 Oct 2024 10:26:35 +0800 Subject: [PATCH 19/43] =?UTF-8?q?postgresql=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E5=BB=BA=E8=A1=A8sql=E6=96=87=E4=BB=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3AI=E5=8A=9F=E8=83=BD=E7=9A=84=E8=8F=9C?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/postgresql/ruoyi-vue-pro.sql | 97 ++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index 526d5a40df..e5e6d1e2de 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -1126,6 +1126,55 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1537, 1, 'OpenAI', 'OpenAI', 'ai_platform', 0, '', '', '', '1', '2024-05-09 22:33:47', '1', '2024-05-09 22:58:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1538, 2, 'Ollama', 'Ollama', 'ai_platform', 0, '', '', '', '1', '2024-05-17 23:02:55', '1', '2024-05-17 23:02:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1539, 3, '文心一言', 'YiYan', 'ai_platform', 0, '', '', '', '1', '2024-05-18 09:24:20', '1', '2024-05-18 09:29:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1540, 4, '讯飞星火', 'XingHuo', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:08:56', '1', '2024-05-18 10:08:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1541, 5, '通义千问', 'TongYi', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:32:29', '1', '2024-07-06 15:42:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1542, 6, 'StableDiffusion', 'StableDiffusion', 'ai_platform', 0, '', '', '', '1', '2024-06-01 15:09:31', '1', '2024-06-01 15:10:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1543, 10, '进行中', '10', 'ai_image_status', 0, 'primary', '', '', '1', '2024-06-26 20:51:41', '1', '2024-06-26 20:52:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1544, 20, '已完成', '20', 'ai_image_status', 0, 'success', '', '', '1', '2024-06-26 20:52:07', '1', '2024-06-26 20:52:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1545, 30, '已失败', '30', 'ai_image_status', 0, 'warning', '', '', '1', '2024-06-26 20:52:25', '1', '2024-06-26 20:52:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1546, 7, 'Midjourney', 'Midjourney', 'ai_platform', 0, '', '', '', '1', '2024-06-26 22:14:46', '1', '2024-06-26 22:14:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1547, 10, '进行中', '10', 'ai_music_status', 0, 'primary', '', '', '1', '2024-06-27 22:45:22', '1', '2024-06-28 00:56:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1548, 20, '已完成', '20', 'ai_music_status', 0, 'success', '', '', '1', '2024-06-27 22:45:33', '1', '2024-06-28 00:56:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1549, 30, '已失败', '30', 'ai_music_status', 0, 'danger', '', '', '1', '2024-06-27 22:45:44', '1', '2024-06-28 00:56:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1550, 1, '歌词模式', '1', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:31', '1', '2024-06-28 01:22:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1551, 2, '描述模式', '2', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:37', '1', '2024-06-28 01:22:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1552, 8, 'Suno', 'Suno', 'ai_platform', 0, '', '', '', '1', '2024-06-29 09:13:36', '1', '2024-06-29 09:13:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1553, 9, 'DeepSeek', 'DeepSeek', 'ai_platform', 0, '', '', '', '1', '2024-07-06 12:04:30', '1', '2024-07-06 12:05:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1554, 10, '智谱', 'ZhiPu', 'ai_platform', 0, '', '', '', '1', '2024-07-06 18:00:35', '1', '2024-07-06 18:00:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1555, 4, '长', '4', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1556, 5, '段落', '5', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1557, 6, '文章', '6', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:05', '1', '2024-07-07 15:50:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1558, 7, '博客文章', '7', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:23', '1', '2024-07-07 15:50:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1559, 8, '想法', '8', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:31', '1', '2024-07-07 15:50:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1560, 9, '大纲', '9', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:37', '1', '2024-07-07 15:50:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1561, 1, '自动', '1', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:06', '1', '2024-07-07 15:51:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1562, 2, '友善', '2', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:19', '1', '2024-07-07 15:51:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1563, 3, '随意', '3', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:27', '1', '2024-07-07 15:51:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1564, 4, '友好', '4', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:37', '1', '2024-07-07 15:51:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1565, 5, '专业', '5', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:49', '1', '2024-07-07 15:52:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1566, 6, '诙谐', '6', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:15', '1', '2024-07-07 15:52:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1567, 7, '有趣', '7', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:24', '1', '2024-07-07 15:52:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1568, 8, '正式', '8', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:54:33', '1', '2024-07-07 15:54:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1569, 5, '段落', '5', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1570, 1, '自动', '1', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:34', '1', '2024-07-07 15:19:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1571, 2, '电子邮件', '2', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:50', '1', '2024-07-07 15:49:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1572, 3, '消息', '3', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:01', '1', '2024-07-07 15:49:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1573, 4, '评论', '4', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:13', '1', '2024-07-07 15:49:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1574, 1, '自动', '1', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:18', '1', '2024-07-07 15:44:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1575, 2, '中文', '2', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:28', '1', '2024-07-07 15:44:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1576, 3, '英文', '3', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:37', '1', '2024-07-07 15:44:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1577, 4, '韩语', '4', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:28', '1', '2024-07-07 15:46:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1578, 5, '日语', '5', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:44', '1', '2024-07-07 15:46:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1579, 1, '自动', '1', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:34', '1', '2024-07-07 15:48:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1580, 2, '短', '2', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:44', '1', '2024-07-07 15:48:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1581, 3, '中等', '3', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:52', '1', '2024-07-07 15:48:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1582, 4, '长', '4', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1584, 1, '撰写', '1', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:00', '1', '2024-07-10 21:26:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1585, 2, '回复', '2', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:06', '1', '2024-07-10 21:26:06', '0'); + COMMIT; -- @formatter:on @@ -2328,6 +2377,54 @@ INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2758, 'AI 大模型', '', 1, 400, 0, '/ai', 'fa:apple', '', '', 0, '1', '1', '1', '1', '2024-05-07 15:07:56', '1', '2024-05-25 12:36:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2759, 'AI 对话', '', 2, 1, 2758, 'chat', 'ep:message', 'ai/chat/index/index.vue', 'AiChat', 0, '1', '1', '1', '1', '2024-05-07 15:09:14', '1', '2024-07-07 17:15:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2760, '控制台', '', 1, 100, 2758, 'console', 'ep:setting', '', '', 0, '1', '1', '1', '1', '2024-05-09 22:39:09', '1', '2024-05-24 23:34:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2761, 'API 密钥', '', 2, 0, 2760, 'api-key', 'ep:key', 'ai/model/apiKey/index.vue', 'AiApiKey', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-10 22:44:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2762, 'API 密钥查询', 'ai:api-key:query', 3, 1, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2763, 'API 密钥创建', 'ai:api-key:create', 3, 2, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2764, 'API 密钥更新', 'ai:api-key:update', 3, 3, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2765, 'API 密钥删除', 'ai:api-key:delete', 3, 4, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2767, '聊天模型', '', 2, 0, 2760, 'chat-model', 'fa-solid:abacus', 'ai/model/chatModel/index.vue', 'AiChatModel', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-10 22:44:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2768, '聊天模型查询', 'ai:chat-model:query', 3, 1, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2769, '聊天模型创建', 'ai:chat-model:create', 3, 2, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2770, '聊天模型更新', 'ai:chat-model:update', 3, 3, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2771, '聊天模型删除', 'ai:chat-model:delete', 3, 4, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2773, '聊天角色', '', 2, 0, 2760, 'chat-role', 'fa:user-secret', 'ai/model/chatRole/index.vue', 'AiChatRole', 0, '1', '1', '1', '', '2024-05-13 12:39:28', '1', '2024-05-13 20:41:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2774, '聊天角色查询', 'ai:chat-role:query', 3, 1, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2775, '聊天角色创建', 'ai:chat-role:create', 3, 2, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2776, '聊天角色更新', 'ai:chat-role:update', 3, 3, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2777, '聊天角色删除', 'ai:chat-role:delete', 3, 4, 2773, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-13 21:43:38', '1', '2024-05-13 21:43:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2778, '聊天管理', '', 2, 10, 2760, 'chat-conversation', 'ep:chat-square', 'ai/chat/manager/index.vue', 'AiChatManager', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-06-26 21:36:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2779, '会话查询', 'ai:chat-conversation:query', 3, 1, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2780, '会话删除', 'ai:chat-conversation:delete', 3, 2, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2781, '消息查询', 'ai:chat-message:query', 3, 11, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:38:56', '1', '2024-05-25 08:38:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2782, '消息删除', 'ai:chat-message:delete', 3, 12, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:39:10', '1', '2024-05-25 08:39:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2783, 'AI 绘画', '', 2, 2, 2758, 'image', 'ep:picture-rounded', 'ai/image/index/index.vue', 'AiImage', 0, '1', '1', '1', '1', '2024-05-26 11:45:17', '1', '2024-07-07 17:18:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2784, '绘画管理', '', 2, 11, 2760, 'image', 'fa:file-image-o', 'ai/image/manager/index.vue', 'AiImageManager', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 21:37:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2785, '绘画查询', 'ai:image:query', 3, 1, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:21:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2786, '绘画删除', 'ai:image:delete', 3, 4, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:22:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2787, '绘图更新', 'ai:image:update', 3, 2, 2784, '', '', '', '', 0, '1', '1', '1', '1', '2024-06-26 22:47:56', '1', '2024-08-31 09:21:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2788, '音乐管理', '', 2, 12, 2760, 'music', 'fa:music', 'ai/music/manager/index.vue', 'AiMusicManager', 0, '1', '1', '1', '', '2024-06-27 15:03:33', '1', '2024-06-27 23:04:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2789, '音乐查询', 'ai:music:query', 3, 1, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2790, '音乐更新', 'ai:music:update', 3, 3, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2791, '音乐删除', 'ai:music:delete', 3, 4, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2792, 'AI 写作', '', 2, 3, 2758, 'write', 'fa-solid:book-reader', 'ai/write/index/index.vue', 'AiWrite', 0, '1', '1', '1', '1', '2024-07-08 09:26:44', '1', '2024-07-16 13:03:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2793, '写作管理', '', 2, 13, 2760, 'write', 'fa:bookmark-o', 'ai/write/manager/index.vue', 'AiWriteManager', 0, '1', '1', '1', '', '2024-07-10 13:24:34', '1', '2024-07-10 21:31:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2794, 'AI 写作查询', 'ai:write:query', 3, 1, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2795, 'AI 写作删除', 'ai:write:delete', 3, 4, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2796, 'AI 音乐', '', 2, 4, 2758, 'music', 'fa:music', 'ai/music/index/index.vue', 'AiMusic', 0, '1', '1', '1', '1', '2024-07-17 09:21:12', '1', '2024-07-29 21:11:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2797, '客服中心', '', 2, 100, 2362, 'kefu', 'fa-solid:user-alt', 'mall/promotion/kefu/index', 'KeFu', 0, '1', '1', '1', '1', '2024-07-17 23:49:05', '1', '2024-07-17 23:49:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2798, 'AI 思维导图', '', 2, 5, 2758, 'mind-map', 'fa:sitemap', 'ai/mindmap/index/index.vue', 'AiMindMap', 0, '1', '1', '1', '1', '2024-07-29 21:31:59', '1', '2024-07-29 21:33:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2799, '导图管理', '', 2, 14, 2760, 'mind-map', 'fa:map', 'ai/mindmap/manager/index', 'AiMindMapManager', 0, '1', '1', '1', '', '2024-08-10 09:15:09', '1', '2024-08-10 17:24:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2800, '思维导图查询', 'ai:mind-map:query', 3, 1, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2801, '思维导图删除', 'ai:mind-map:delete', 3, 4, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2802, '会话查询', 'promotion:kefu-conversation:query', 3, 1, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:17:52', '1', '2024-08-31 09:18:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2803, '会话更新', 'promotion:kefu-conversation:update', 3, 2, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:15', '1', '2024-08-31 09:19:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2804, '消息查询', 'promotion:kefu-message:query', 3, 10, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:42', '1', '2024-08-31 09:18:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2805, '会话删除', 'promotion:kefu-conversation:delete', 3, 3, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:19:51', '1', '2024-08-31 09:20:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2806, '消息发送', 'promotion:kefu-message:send', 3, 12, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:06', '1', '2024-08-31 09:20:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2807, '消息更新', 'promotion:kefu-message:update', 3, 11, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:22', '1', '2024-08-31 09:20:22', '0'); COMMIT; -- @formatter:on From cf1b41741e05de8e8994bda8719263d1280cf041 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 27 Oct 2024 15:14:18 +0800 Subject: [PATCH 20/43] =?UTF-8?q?!1108=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E6=8E=92=E5=BA=8F=EF=BC=9A=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E9=A9=BC=E5=B3=B0=E6=94=B9=E4=B8=BA=E4=B8=8B=E5=88=92=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/mybatis/core/util/MyBatisUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java index 0f93517910..ccd9412a48 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java @@ -36,8 +36,9 @@ public class MyBatisUtils { Page page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize()); // 排序字段 if (!CollectionUtil.isEmpty(sortingFields)) { - page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? - OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) + page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) + ? OrderItem.asc(StrUtil.toUnderlineCase(sortingField.getField())) + : OrderItem.desc(StrUtil.toUnderlineCase(sortingField.getField()))) .collect(Collectors.toList())); } return page; From c6f67a5a0236a38090fc0b5a394894234c65fcf6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 27 Oct 2024 15:16:35 +0800 Subject: [PATCH 21/43] =?UTF-8?q?!1112=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E6=94=AF=E4=BB=98=EF=BC=9A=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E9=80=80=E6=AC=BE=E6=97=B6=EF=BC=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E5=8F=91=E8=B5=B7=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=BC=82=E5=B8=B8=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/core/client/impl/weixin/AbstractWxPayClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index 73d482a5bf..cb5506c9db 100644 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -88,7 +88,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient Date: Sun, 27 Oct 2024 17:36:45 +0800 Subject: [PATCH 22/43] =?UTF-8?q?148=20fix=EF=BC=9A=E5=95=86=E5=9F=8E?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F->=E8=90=A5=E9=94=80=E4=B8=AD=E5=BF=83->?= =?UTF-8?q?=E4=BC=98=E6=83=A0=E6=B4=BB=E5=8A=A8->=E9=99=90=E6=97=B6?= =?UTF-8?q?=E6=8A=98=E6=89=A3=EF=BC=8C=E6=8A=98=E6=89=A3=E7=99=BE=E5=88=86?= =?UTF-8?q?=E6=AF=94=E6=8C=89=E6=AD=A3=E5=B8=B8=E6=8A=98=E6=89=A3=EF=BC=88?= =?UTF-8?q?=E6=AF=94=E5=A6=82=E8=AF=B490%=EF=BC=89=E5=A1=AB=E5=86=99?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=90=8E=E7=AB=AF=E6=8A=A5=E9=94=99=E2=80=9C?= =?UTF-8?q?=E6=8A=98=E6=89=A3=E7=99=BE=E5=88=86=E6=AF=94=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E5=A4=A7=E4=BA=8E=E7=AD=89=E4=BA=8E=201=EF=BC=8C=E5=B0=8F?= =?UTF-8?q?=E4=BA=8E=E7=AD=89=E4=BA=8E=2099=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/discount/vo/DiscountActivityBaseVO.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java index b983e7cb51..9b3a641a31 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java @@ -63,11 +63,11 @@ public class DiscountActivityBaseVO { @Min(value = 0, message = "优惠金额需要大于等于 0") private Integer discountPrice; - @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99") + @AssertTrue(message = "折扣百分比需要大于等于 0.01%,小于等于 99.99%") @JsonIgnore public boolean isDiscountPercentValid() { return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) - || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99); + || (discountPercent != null && discountPercent >= 1 && discountPercent <= 9999); } @AssertTrue(message = "优惠金额不能为空") From b1ad2f8176c74589075ef0fc0e14c7eb6affb67f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 27 Oct 2024 20:00:00 +0800 Subject: [PATCH 23/43] =?UTF-8?q?=E3=80=90=E7=BC=BA=E9=99=B7=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91=E5=95=86=E5=9F=8E=EF=BC=9A=E6=8B=BC=E5=9B=A2?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E5=B7=B2=E6=94=AF=E4=BB=98=E7=9A=84=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E6=97=B6=EF=BC=8C=E7=BC=BA=E5=B0=91=20ip=20=E5=92=8C?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A3=80=E6=9F=A5=E4=B8=8D=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/service/order/TradeOrderUpdateServiceImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index caf789cd84..deacdf189c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.net.NetUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; @@ -888,8 +889,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { if (!order.getPayStatus()) { throw exception(ORDER_CANCEL_PAID_FAIL, "已支付"); } - // 1.3 校验订单是否已退款 - if (ObjUtil.equal(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { + // 1.3 校验订单是否未退款 + if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { throw exception(ORDER_CANCEL_PAID_FAIL, "未退款"); } @@ -897,7 +898,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { cancelOrder0(order, TradeOrderCancelTypeEnum.COMBINATION_CLOSE); // 2.2 创建退款单 payRefundApi.createRefund(new PayRefundCreateReqDTO() - .setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用 + .setAppKey(tradeOrderProperties.getPayAppKey()) // 支付应用 + .setUserIp(NetUtil.getLocalhostStr()) // 使用本机 IP,因为是服务器发起退款的 .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 .setMerchantRefundId(String.valueOf(order.getId())) .setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())); // 价格信息 From 8d4cc35cde8fd7174bb0eaa60d5af56c150224d8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 27 Oct 2024 20:33:49 +0800 Subject: [PATCH 24/43] =?UTF-8?q?=E3=80=90=E7=BC=BA=E9=99=B7=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91=E5=95=86=E5=9F=8E=EF=BC=9A=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=8A=B5=E5=9C=A8=E4=B8=8D=E9=99=90=E5=88=B6=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=8F=91=E9=80=81=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/dal/dataobject/coupon/CouponTemplateDO.java | 5 +++++ .../module/promotion/service/coupon/CouponServiceImpl.java | 3 ++- .../promotion/service/coupon/CouponTemplateServiceImpl.java | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java index 10fe302a3b..91216bf184 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java @@ -30,6 +30,11 @@ import java.util.List; @EqualsAndHashCode(callSuper = true) public class CouponTemplateDO extends BaseDO { + /** + * 不限制领取数量 + */ + public static final Integer TIME_LIMIT_COUNT_MAX = -1; + // ========== 基本信息 BEGIN ========== /** * 模板编号,自增唯一 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index 9ceb9507df..c4d17cc4eb 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -269,7 +269,8 @@ public class CouponServiceImpl implements CouponService { throw exception(COUPON_TEMPLATE_NOT_EXISTS); } // 校验剩余数量 - if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { + if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制 + && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { throw exception(COUPON_TEMPLATE_NOT_ENOUGH); } // 校验"固定日期"的有效期类型是否过期 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java index 100f5541b4..0267e3ea43 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi; @@ -59,7 +60,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId()); // 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时) if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType()) - && updateReqVO.getTotalCount() > 0 // 大于 0 的原因,是因为 -1 不限制 + && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制 && updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) { throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount()); } From d97ba8d4d8fdc095c9a41290f33a83875165c515 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 1 Nov 2024 21:22:23 +0800 Subject: [PATCH 25/43] =?UTF-8?q?=E3=80=90=E7=BC=BA=E9=99=B7=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91=E5=95=86=E5=9F=8E=EF=BC=9A=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E7=9A=84=E5=BA=93=E5=AD=98=E6=A0=A1=E9=AA=8C=EF=BC=8C=E4=BB=8E?= =?UTF-8?q?=20>=20=E6=94=B9=E6=88=90=20>=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/combination/CombinationRecordServiceImpl.java | 2 +- .../promotion/service/point/PointActivityServiceImpl.java | 2 +- .../promotion/service/seckill/SeckillActivityServiceImpl.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java index 6f5ac3f625..bdf2d33985 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java @@ -131,7 +131,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); } // 4.3 校验库存是否充足 - if (count > sku.getStock()) { + if (count >= sku.getStock()) { throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java index 8e88c5026f..21e9ce233a 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java @@ -300,7 +300,7 @@ public class PointActivityServiceImpl implements PointActivityService { throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); } // 2.2 校验库存是否充足 - if (count > product.getStock()) { + if (count >= product.getStock()) { throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); } return BeanUtils.toBean(product, PointValidateJoinRespDTO.class); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java index dcc5596f25..7e6c31571d 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -317,7 +317,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { throw exception(SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); } // 2.2 校验库存是否充足 - if (count > product.getStock()) { + if (count >= product.getStock()) { throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); } return SeckillActivityConvert.INSTANCE.convert02(activity, product); From ad00fbc566aed49a8ff23c1a5c2f516ce5c12ca1 Mon Sep 17 00:00:00 2001 From: segerts <150045299+segerts@users.noreply.github.com> Date: Sun, 3 Nov 2024 19:28:23 +0800 Subject: [PATCH 26/43] =?UTF-8?q?S3=20minio=20sdk=20=E6=9B=BF=E6=8D=A2?= =?UTF-8?q?=E4=B8=BA=20aws=20sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-module-infra-biz/pom.xml | 4 +- .../file/core/client/s3/S3FileClient.java | 148 ++++++++++++------ 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/yudao-module-infra/yudao-module-infra-biz/pom.xml b/yudao-module-infra/yudao-module-infra-biz/pom.xml index f2840cfc7a..9786c000dd 100644 --- a/yudao-module-infra/yudao-module-infra-biz/pom.xml +++ b/yudao-module-infra/yudao-module-infra-biz/pom.xml @@ -116,8 +116,8 @@ jsch - io.minio - minio + com.amazonaws + aws-java-sdk-s3 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 29f6fc34f9..7b84b6941e 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -4,10 +4,17 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; -import io.minio.*; -import io.minio.http.Method; +import com.amazonaws.HttpMethod; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.*; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.S3Object; + import java.io.ByteArrayInputStream; +import java.util.Date; import java.util.concurrent.TimeUnit; /** @@ -19,7 +26,7 @@ import java.util.concurrent.TimeUnit; */ public class S3FileClient extends AbstractFileClient { - private MinioClient client; + private AmazonS3Client client; public S3FileClient(Long id, S3FileClientConfig config) { super(id, config); @@ -32,26 +39,57 @@ public class S3FileClient extends AbstractFileClient { config.setDomain(buildDomain()); } // 初始化客户端 - client = MinioClient.builder() - .endpoint(buildEndpointURL()) // Endpoint URL - .region(buildRegion()) // Region - .credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥 + + client = (AmazonS3Client)AmazonS3ClientBuilder.standard() + .withCredentials(buildCredentials()) + .withEndpointConfiguration(buildEndpointConfiguration()) .build(); - enableVirtualStyleEndpoint(); + +// enableVirtualStyleEndpoint(); + +// client = AmazonS3ClientBuilder.builder() +// .endpoint(buildEndpointURL()) // Endpoint URL +// .region(buildRegion()) // Region +// .credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥 +// .build(); +// enableVirtualStyleEndpoint(); + } + /** + * 基于config秘钥 构建 S3 客户端的认证信息 + * + * @return S3 客户端的认证信息 + */ + private AWSStaticCredentialsProvider buildCredentials() { + AWSStaticCredentialsProvider awsStaticCredentialsProvider = new AWSStaticCredentialsProvider( + new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret())); + return awsStaticCredentialsProvider; + } + /** + * 构建 S3 客户端的 Endpoint 配置包括 region、endpoint + * + * @return S3 客户端的 EndpointConfiguration 配置 + */ + private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() { + AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration( + config.getEndpoint(), buildRegion()); + return endpointConfiguration; } - /** - * 基于 endpoint 构建调用云服务的 URL 地址 - * - * @return URI 地址 - */ - private String buildEndpointURL() { - // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO - if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { - return config.getEndpoint(); - } - return StrUtil.format("https://{}", config.getEndpoint()); - } + + + +// /** +// * 基于 endpoint 构建调用云服务的 URL 地址 +// * +// * @return URI 地址 +// */ +// private String buildEndpointURL() { +// // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO +// if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { +// return config.getEndpoint(); +// } +// return StrUtil.format("https://{}", config.getEndpoint()); +// } /** * 基于 bucket + endpoint 构建访问的 Domain 地址 @@ -88,55 +126,69 @@ public class S3FileClient extends AbstractFileClient { } /** - * 开启 VirtualStyle 模式 + * 开启 PathStyle模式 */ private void enableVirtualStyleEndpoint() { - if (StrUtil.containsAny(config.getEndpoint(), - S3FileClientConfig.ENDPOINT_TENCENT, // 腾讯云 https://cloud.tencent.com/document/product/436/41284 - S3FileClientConfig.ENDPOINT_VOLCES)) { // 火山云 https://www.volcengine.com/docs/6349/1288493 - client.enableVirtualStyleEndpoint(); - } +// if (StrUtil.containsAny(config.getEndpoint(), +// S3FileClientConfig.ENDPOINT_TENCENT, // 腾讯云 https://cloud.tencent.com/document/product/436/41284 +// S3FileClientConfig.ENDPOINT_VOLCES)) { // 火山云 https://www.volcengine.com/docs/6349/1288493 +// +// } + S3ClientOptions clientOptions = S3ClientOptions.builder() + .setPathStyleAccess(true) + .build(); } @Override public String upload(byte[] content, String path, String type) throws Exception { // 执行上传 - client.putObject(PutObjectArgs.builder() - .bucket(config.getBucket()) // bucket 必须传递 - .contentType(type) - .object(path) // 相对路径作为 key - .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容 - .build()); + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(type); + + client.putObject(config.getBucket(), path, new ByteArrayInputStream(content), objectMetadata); +// client.putObject(PutObjectArgs.builder() +// .bucket(config.getBucket()) // bucket 必须传递 +// .contentType(type) +// .object(path) // 相对路径作为 key +// .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容 +// .build()); // 拼接返回路径 return config.getDomain() + "/" + path; } @Override public void delete(String path) throws Exception { - client.removeObject(RemoveObjectArgs.builder() - .bucket(config.getBucket()) // bucket 必须传递 - .object(path) // 相对路径作为 key - .build()); + + client.deleteObject(config.getBucket(), path); + +// client.removeObject(RemoveObjectArgs.builder() +// .bucket(config.getBucket()) // bucket 必须传递 +// .object(path) // 相对路径作为 key +// .build()); } @Override public byte[] getContent(String path) throws Exception { - GetObjectResponse response = client.getObject(GetObjectArgs.builder() - .bucket(config.getBucket()) // bucket 必须传递 - .object(path) // 相对路径作为 key - .build()); - return IoUtil.readBytes(response); + S3Object tempS3Object = client.getObject(config.getBucket(), path); +// GetObjectResponse response = client.getObject(GetObjectArgs.builder() +// .bucket(config.getBucket()) // bucket 必须传递 +// .object(path) // 相对路径作为 key +// .build()); + return IoUtil.readBytes(tempS3Object.getObjectContent()); } @Override public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { - String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) - .bucket(config.getBucket()) - .object(path) - .expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天 - .build() - ); + //设定过期时间为24小时 + Date expiration = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(24)); + String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path,expiration , HttpMethod.PUT)); +// String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() +// .method(Method.PUT) +// .bucket(config.getBucket()) +// .object(path) +// .expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天 +// .build() +// ); return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path); } From 00c2205442e1a0219e6ed686f5e4b768cd8adf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=87=E5=BA=86?= Date: Mon, 4 Nov 2024 17:21:38 +0000 Subject: [PATCH 27/43] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=97=A5=E5=BF=97=E8=A1=A8=E4=B8=ADuser=5Fid?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E4=B8=8D=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨宇庆 --- sql/mysql/ruoyi-vue-pro.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 6f71bc6802..901fe8ee97 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -64,7 +64,7 @@ DROP TABLE IF EXISTS `infra_api_error_log`; CREATE TABLE `infra_api_error_log` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '链路追踪编号', - `user_id` int NOT NULL DEFAULT 0 COMMENT '用户编号', + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号', `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求方法名', From 72d2d81d6a4d940a3f1d19929159b0184c3b2f21 Mon Sep 17 00:00:00 2001 From: wct <2207561089@qq.com> Date: Wed, 6 Nov 2024 17:32:35 +0800 Subject: [PATCH 28/43] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=B1=E4=BA=8E?= =?UTF-8?q?=E5=A4=9A=E7=A7=9F=E6=88=B7=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E8=BF=94=E5=9B=9E=20void=20=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E6=89=A7=E8=A1=8C=20xxlJob=20=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/tenant/core/job/TenantJobAspect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java index de409a4a3a..a58887a78e 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java @@ -46,7 +46,7 @@ public class TenantJobAspect { TenantUtils.execute(tenantId, () -> { try { Object result = joinPoint.proceed(); - results.put(tenantId, StrUtil.toStringOrNull(result)); + results.put(tenantId, StrUtil.toStringOrEmpty(result)); } catch (Throwable e) { log.error("[execute][租户({}) 执行 Job 发生异常", tenantId, e); results.put(tenantId, ExceptionUtil.getRootCauseMessage(e)); From c776371d484425100c43a2c5284e1d2e6c7d3472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=87=E5=BA=86?= Date: Wed, 6 Nov 2024 15:21:25 +0000 Subject: [PATCH 29/43] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BC=9A=E5=91=98=E5=8F=96=E6=B6=88=E9=80=80?= =?UTF-8?q?=E6=AC=BE=E6=8E=A5=E5=8F=A3=E4=B8=AD=E6=9C=AA=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E7=94=A8=E6=88=B7ID=E7=9A=84=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨宇庆 --- .../module/trade/service/aftersale/AfterSaleServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java index f191723c5d..bcac6b5b6a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java @@ -399,7 +399,7 @@ public class AfterSaleServiceImpl implements AfterSaleService { @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL) public void cancelAfterSale(Long userId, Long id) { // 校验售后单的状态,并状态待退款 - AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); + AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(id, userId); if (afterSale == null) { throw exception(AFTER_SALE_NOT_FOUND); } From 0bbc682ba42ef31dffeeb3347b64af70771c4cc6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 Nov 2024 18:33:52 +0800 Subject: [PATCH 30/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91infra=EF=BC=9As3=20minio=20sdk=20=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E4=B8=BA=20aws=20sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/ruoyi-vue-pro.sql | 107 ++++++++++++---- yudao-dependencies/pom.xml | 20 +-- .../file/core/client/s3/S3FileClient.java | 121 ++++-------------- .../core/client/s3/S3FileClientConfig.java | 5 +- 4 files changed, 114 insertions(+), 139 deletions(-) diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 901fe8ee97..b5ccf2b00e 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -11,7 +11,7 @@ Target Server Version : 80200 (8.2.0) File Encoding : 65001 - Date: 07/10/2024 15:55:58 + Date: 09/11/2024 18:16:12 */ SET NAMES utf8mb4; @@ -91,7 +91,7 @@ CREATE TABLE `infra_api_error_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 21016 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 21213 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; -- ---------------------------- -- Records of infra_api_error_log @@ -250,7 +250,7 @@ CREATE TABLE `infra_file` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1509 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1558 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; -- ---------------------------- -- Records of infra_file @@ -275,14 +275,19 @@ CREATE TABLE `infra_file_config` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表'; +) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表'; -- ---------------------------- -- Records of infra_file_config -- ---------------------------- BEGIN; -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器', 20, '', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2024-11-09 18:09:28', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\"}', '1', '2024-01-13 22:11:12', '1', '2024-11-09 18:09:28', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:03:22', '1', '2024-11-09 18:15:39', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:47:08', '1', '2024-11-09 18:15:43', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\"}', '1', '2024-11-09 16:56:42', '1', '2024-11-09 18:15:46', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\"}', '1', '2024-11-09 17:18:41', '1', '2024-11-09 18:15:49', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\"}', '1', '2024-11-09 17:43:10', '1', '2024-11-09 18:15:52', b'0'); COMMIT; -- ---------------------------- @@ -328,7 +333,7 @@ CREATE TABLE `infra_job` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; +) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; -- ---------------------------- -- Records of infra_job @@ -345,6 +350,7 @@ INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param` INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2024-09-12 13:40:34', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (33, 'demoJob', 2, 'demoJob', '', '0 * * * * ?', 1, 1, 0, '1', '2024-10-27 19:38:46', '1', '2024-10-27 19:40:23', b'0'); COMMIT; -- ---------------------------- @@ -368,7 +374,7 @@ CREATE TABLE `infra_job_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 634 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; +) ENGINE = InnoDB AUTO_INCREMENT = 638 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; -- ---------------------------- -- Records of infra_job_log @@ -438,7 +444,7 @@ CREATE TABLE `system_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1593 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1683 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; -- ---------------------------- -- Records of system_dict_data @@ -509,6 +515,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (112, 0, '微信 Wap 网站支付', 'wx_wap', 'pay_channel_code', 0, 'success', '', '微信 Wap 网站支付', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', b'0'); @@ -659,7 +666,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', '手动打款', '', '2023-09-28 02:46:05', '1', '2024-10-13 11:06:54', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); @@ -682,9 +689,9 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1389, 0, '拼团中', '0', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2024-10-13 10:08:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1390, 1, '拼团成功', '1', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2024-10-13 10:08:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1391, 2, '拼团失败', '2', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2024-10-13 10:08:24', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', b'0'); @@ -862,6 +869,32 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1590, 20, 'SIMPLE 设计器', '20', 'bpm_model_type', 0, 'success', '', '', '1', '2024-08-26 15:22:27', '1', '2024-08-26 16:45:58', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1591, 4, '七牛云', 'QINIU', 'system_sms_channel_code', 0, '', '', '', '1', '2024-08-31 08:45:03', '1', '2024-08-31 08:45:24', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1592, 3, '新人券', '3', 'promotion_coupon_take_type', 0, 'info', '', '新人注册后,自动发放', '1', '2024-09-03 11:57:16', '1', '2024-09-03 11:57:28', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1593, 5, '微信零钱', '5', 'brokerage_withdraw_type', 0, '', '', '自动打款', '1', '2024-10-13 11:06:48', '1', '2024-10-13 11:06:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1655, 0, '标准数据格式(JSON)', '0', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:26', '1', '2024-09-06 14:31:02', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1656, 1, '透传/自定义', '1', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:37', '1', '2024-09-06 14:30:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1657, 0, '直连设备', '0', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:54:58', '1', '2024-09-06 21:57:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1658, 2, '网关设备', '2', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:08', '1', '2024-09-06 21:56:46', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1659, 1, '网关子设备', '1', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:20', '1', '2024-09-06 21:57:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1661, 1, '已发布', '1', 'iot_product_status', 0, 'success', '', '', '1', '2024-08-10 12:10:33', '1', '2024-09-06 22:06:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1663, 0, '开发中', '0', 'iot_product_status', 0, 'default', '', '', '1', '2024-08-10 14:19:18', '1', '2024-09-07 10:58:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1665, 0, '弱校验', '0', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:05:48', '1', '2024-09-06 22:02:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1666, 1, '免校验', '1', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:06:03', '1', '2024-09-06 22:02:51', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1667, 0, 'Wi-Fi', '0', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:04:47', '1', '2024-09-06 22:04:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1668, 1, '蜂窝(2G / 3G / 4G / 5G)', '1', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:14', '1', '2024-09-06 22:05:14', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1669, 2, '以太网', '2', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:35', '1', '2024-09-06 22:05:35', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1670, 3, '其他', '3', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:52', '1', '2024-09-06 22:05:52', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1671, 0, '自定义', '0', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:10', '1', '2024-09-06 22:26:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1672, 1, 'Modbus', '1', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:21', '1', '2024-09-06 22:26:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1673, 2, 'OPC UA', '2', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:31', '1', '2024-09-06 22:26:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1674, 3, 'ZigBee', '3', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:39', '1', '2024-09-06 22:26:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1675, 4, 'BLE', '4', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:48', '1', '2024-09-06 22:26:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1676, 0, '未激活', '0', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:34', '1', '2024-09-21 08:13:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1677, 1, '在线', '1', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:48', '1', '2024-09-21 08:13:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1678, 2, '离线', '2', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:59', '1', '2024-09-21 08:13:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1679, 3, '已禁用', '3', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:14:13', '1', '2024-09-21 08:14:13', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1680, 1, '属性', '1', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:01', '1', '2024-09-29 20:09:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1681, 2, '服务', '2', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:11', '1', '2024-09-29 20:08:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1682, 3, '事件', '3', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:20', '1', '2024-09-29 20:08:20', b'0'); COMMIT; -- ---------------------------- @@ -881,7 +914,7 @@ CREATE TABLE `system_dict_type` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 630 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; +) ENGINE = InnoDB AUTO_INCREMENT = 640 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; -- ---------------------------- -- Records of system_dict_type @@ -980,6 +1013,14 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (627, '写作格式', 'ai_write_format', 0, '', '1', '2024-07-07 15:14:34', '1', '2024-07-07 15:14:34', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (628, 'AI 写作类型', 'ai_write_type', 0, '', '1', '2024-07-10 21:25:29', '1', '2024-07-10 21:25:29', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (629, 'BPM 流程模型类型', 'bpm_model_type', 0, '', '1', '2024-08-26 15:21:43', '1', '2024-08-26 15:21:43', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (630, 'IOT 接入网关协议', 'iot_protocol_type', 0, '', '1', '2024-09-06 22:20:17', '1', '2024-09-06 22:20:17', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (631, 'IOT 设备状态', 'iot_device_status', 0, '', '1', '2024-09-21 08:12:55', '1', '2024-09-21 08:12:55', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (632, 'IOT 物模型功能类型', 'iot_product_function_type', 0, '', '1', '2024-09-29 20:02:36', '1', '2024-09-29 20:09:26', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (634, 'IOT 数据格式', 'iot_data_format', 0, '', '1', '2024-08-10 11:52:58', '1', '2024-09-06 14:30:14', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (635, 'IOT 产品设备类型', 'iot_product_device_type', 0, '', '1', '2024-08-10 11:54:30', '1', '2024-08-10 04:06:56', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (637, 'IOT 产品状态', 'iot_product_status', 0, '', '1', '2024-08-10 12:06:09', '1', '2024-08-10 12:06:09', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (638, 'IOT 数据校验级别', 'iot_validate_type', 0, '', '1', '2024-09-06 20:05:13', '1', '2024-09-06 20:05:13', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (639, 'IOT 联网方式', 'iot_net_type', 0, '', '1', '2024-09-06 22:04:13', '1', '2024-09-06 22:04:13', b'0', '1970-01-01 00:00:00'); COMMIT; -- ---------------------------- @@ -1003,7 +1044,7 @@ CREATE TABLE `system_login_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 3335 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; +) ENGINE = InnoDB AUTO_INCREMENT = 3370 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; -- ---------------------------- -- Records of system_login_log @@ -1134,7 +1175,7 @@ CREATE TABLE `system_menu` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2814 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; +) ENGINE = InnoDB AUTO_INCREMENT = 2912 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; -- ---------------------------- -- Records of system_menu @@ -1983,6 +2024,26 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2811, '积分商城活动更新', 'promotion:point-activity:update', 3, 3, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2812, '积分商城活动删除', 'promotion:point-activity:delete', 3, 4, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2813, '积分商城活动导出', 'promotion:point-activity:export', 3, 5, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2892, 'IOT 物联网', '', 1, 500, 0, '/iot', 'fa-solid:hdd', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:55:29', '1', '2024-08-10 09:55:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2893, '设备接入', '', 1, 1, 2892, 'device', 'ep:platform', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:57:56', '1', '2024-10-20 18:57:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2894, '产品管理', '', 2, 0, 2893, 'product', '', 'iot/product/index', 'IoTProduct', 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '1', '2024-09-16 19:50:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2895, '产品查询', 'iot:product:query', 3, 1, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2896, '产品创建', 'iot:product:create', 3, 2, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2897, '产品更新', 'iot:product:update', 3, 3, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2898, '产品删除', 'iot:product:delete', 3, 4, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2899, '产品导出', 'iot:product:export', 3, 5, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2900, '设备管理', '', 2, 0, 2893, 'device', '', 'iot/device/index', 'IoTDevice', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:50:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2901, '设备查询', 'iot:device:query', 3, 1, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2902, '设备创建', 'iot:device:create', 3, 2, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2903, '设备更新', 'iot:device:update', 3, 3, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2904, '设备删除', 'iot:device:delete', 3, 4, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2905, '设备导出', 'iot:device:export', 3, 5, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2906, 'IoT 产品物模型管理', '', 1, 0, 2893, 'think-model-function', '', '', '', 0, b'0', b'1', b'1', '', '2024-09-25 22:12:09', '1', '2024-09-29 20:52:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2907, 'IoT 产品物模型查询', 'iot:think-model-function:query', 3, 1, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2908, 'IoT 产品物模型创建', 'iot:think-model-function:create', 3, 2, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2909, 'IoT 产品物模型更新', 'iot:think-model-function:update', 3, 3, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2910, 'IoT 产品物模型删除', 'iot:think-model-function:delete', 3, 4, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2911, 'IoT 产品物模型导出', 'iot:think-model-function:export', 3, 5, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0'); COMMIT; -- ---------------------------- @@ -2104,7 +2165,7 @@ CREATE TABLE `system_oauth2_access_token` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_access_token`(`access_token` ASC) USING BTREE, INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 10113 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 11308 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; -- ---------------------------- -- Records of system_oauth2_access_token @@ -2226,7 +2287,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1652 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 1676 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; -- ---------------------------- -- Records of system_oauth2_refresh_token @@ -2259,7 +2320,7 @@ CREATE TABLE `system_operate_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 9063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; +) ENGINE = InnoDB AUTO_INCREMENT = 9064 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; -- ---------------------------- -- Records of system_operate_log @@ -3242,7 +3303,7 @@ CREATE TABLE `system_sms_code` ( `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' -) ENGINE = InnoDB AUTO_INCREMENT = 639 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; +) ENGINE = InnoDB AUTO_INCREMENT = 642 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; -- ---------------------------- -- Records of system_sms_code @@ -3283,7 +3344,7 @@ CREATE TABLE `system_sms_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1147 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 1234 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; -- ---------------------------- -- Records of system_sms_log @@ -3581,8 +3642,8 @@ CREATE TABLE `system_users` ( -- Records of system_users -- ---------------------------- BEGIN; -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-10-07 15:05:17', 'admin', '2021-01-05 17:03:47', NULL, '2024-10-07 15:05:17', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', '1', '2024-09-22 14:55:06', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-11-08 19:27:07', 'admin', '2021-01-05 17:03:47', NULL, '2024-11-08 19:27:07', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$04$IgUse/ibRzAZ3rngCThmtemJeoh15Ux1TQ2hIMe4iwt/K3LcFHEda', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-11-02 14:00:46', '', '2021-01-07 09:07:17', NULL, '2024-11-02 14:00:46', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$04$fUBSmjKCPYAUmnMzOb6qE.eZCGPhHi1JmAKclODbfS/O7fHOl2bH6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', NULL, '2024-08-11 17:48:12', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$jDFLttgfik0QqJKAbfhMa.2A9xXoZmAIxakdFJUzkX.MgBKT6ddo6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-09-17 15:05:43', '', '2021-01-21 02:13:53', NULL, '2024-09-17 15:05:43', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 35c712062b..4ecaa83e29 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -66,11 +66,9 @@ 4.1.113.Final 1.2.5 - 3.5.0 - 4.11.0 2.17.0 1.27.1 - 8.5.7 + 1.12.777 2.0.5 1.8.1 4.6.0 @@ -542,19 +540,9 @@ - com.squareup.okio - okio - ${okio.version} - - - com.squareup.okhttp3 - okhttp - ${okhttp3.version} - - - io.minio - minio - ${minio.version} + com.amazonaws + aws-java-sdk-s3 + ${aws-java-sdk-s3.version} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 7b84b6941e..5c76e1a7c8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -8,11 +8,11 @@ import com.amazonaws.HttpMethod; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.*; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.S3Object; - import java.io.ByteArrayInputStream; import java.util.Date; import java.util.concurrent.TimeUnit; @@ -39,58 +39,32 @@ public class S3FileClient extends AbstractFileClient { config.setDomain(buildDomain()); } // 初始化客户端 - - client = (AmazonS3Client)AmazonS3ClientBuilder.standard() + client = (AmazonS3Client)AmazonS3ClientBuilder.standard() .withCredentials(buildCredentials()) .withEndpointConfiguration(buildEndpointConfiguration()) .build(); - -// enableVirtualStyleEndpoint(); - -// client = AmazonS3ClientBuilder.builder() -// .endpoint(buildEndpointURL()) // Endpoint URL -// .region(buildRegion()) // Region -// .credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥 -// .build(); -// enableVirtualStyleEndpoint(); } + /** - * 基于config秘钥 构建 S3 客户端的认证信息 + * 基于 config 秘钥,构建 S3 客户端的认证信息 * - * @return S3 客户端的认证信息 + * @return S3 客户端的认证信息 */ private AWSStaticCredentialsProvider buildCredentials() { - AWSStaticCredentialsProvider awsStaticCredentialsProvider = new AWSStaticCredentialsProvider( + return new AWSStaticCredentialsProvider( new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret())); - return awsStaticCredentialsProvider; } + /** - * 构建 S3 客户端的 Endpoint 配置包括 region、endpoint + * 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint * * @return S3 客户端的 EndpointConfiguration 配置 */ private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() { - AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration( - config.getEndpoint(), buildRegion()); - return endpointConfiguration; + return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(), + null); // 无需设置 region } - - - -// /** -// * 基于 endpoint 构建调用云服务的 URL 地址 -// * -// * @return URI 地址 -// */ -// private String buildEndpointURL() { -// // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO -// if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { -// return config.getEndpoint(); -// } -// return StrUtil.format("https://{}", config.getEndpoint()); -// } - /** * 基于 bucket + endpoint 构建访问的 Domain 地址 * @@ -105,90 +79,39 @@ public class S3FileClient extends AbstractFileClient { return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); } - /** - * 基于 bucket 构建 region 地区 - * - * @return region 地区 - */ - private String buildRegion() { - // 阿里云必须有 region,否则会报错 - if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_ALIYUN)) { - return StrUtil.subBefore(config.getEndpoint(), '.', false) - .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀 - .replaceAll("https://", ""); - } - // 腾讯云必须有 region,否则会报错 - if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_TENCENT)) { - return StrUtil.subAfter(config.getEndpoint(), "cos.", false) - .replaceAll("." + S3FileClientConfig.ENDPOINT_TENCENT, ""); // 去除 Endpoint - } - return null; - } - - /** - * 开启 PathStyle模式 - */ - private void enableVirtualStyleEndpoint() { -// if (StrUtil.containsAny(config.getEndpoint(), -// S3FileClientConfig.ENDPOINT_TENCENT, // 腾讯云 https://cloud.tencent.com/document/product/436/41284 -// S3FileClientConfig.ENDPOINT_VOLCES)) { // 火山云 https://www.volcengine.com/docs/6349/1288493 -// -// } - S3ClientOptions clientOptions = S3ClientOptions.builder() - .setPathStyleAccess(true) - .build(); - } - @Override public String upload(byte[] content, String path, String type) throws Exception { - // 执行上传 + // 元数据,主要用于设置文件类型 ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType(type); + objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志 + // 执行上传 + client.putObject(config.getBucket(), + path, // 相对路径 + new ByteArrayInputStream(content), // 文件内容 + objectMetadata); - client.putObject(config.getBucket(), path, new ByteArrayInputStream(content), objectMetadata); -// client.putObject(PutObjectArgs.builder() -// .bucket(config.getBucket()) // bucket 必须传递 -// .contentType(type) -// .object(path) // 相对路径作为 key -// .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容 -// .build()); // 拼接返回路径 return config.getDomain() + "/" + path; } @Override public void delete(String path) throws Exception { - client.deleteObject(config.getBucket(), path); - -// client.removeObject(RemoveObjectArgs.builder() -// .bucket(config.getBucket()) // bucket 必须传递 -// .object(path) // 相对路径作为 key -// .build()); } @Override public byte[] getContent(String path) throws Exception { S3Object tempS3Object = client.getObject(config.getBucket(), path); -// GetObjectResponse response = client.getObject(GetObjectArgs.builder() -// .bucket(config.getBucket()) // bucket 必须传递 -// .object(path) // 相对路径作为 key -// .build()); return IoUtil.readBytes(tempS3Object.getObjectContent()); } @Override public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { - //设定过期时间为24小时 - Date expiration = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(24)); - String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path,expiration , HttpMethod.PUT)); -// String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() -// .method(Method.PUT) -// .bucket(config.getBucket()) -// .object(path) -// .expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天 -// .build() -// ); + // 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天 + Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10)); + // 生成上传 URL + String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT)); return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java index e8f8bacec5..e59a7594d2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java @@ -28,7 +28,8 @@ public class S3FileClientConfig implements FileClientConfig { * 2. 阿里云:https://help.aliyun.com/document_detail/31837.html * 3. 腾讯云:https://cloud.tencent.com/document/product/436/6224 * 4. 七牛云:https://developer.qiniu.com/kodo/4088/s3-access-domainname - * 5. 华为云:https://developer.huaweicloud.com/endpoint?OBS + * 5. 华为云:https://console.huaweicloud.com/apiexplorer/#/endpoint/OBS + * 6. 火山云:https://www.volcengine.com/docs/6349/107356 */ @NotNull(message = "endpoint 不能为空") private String endpoint; @@ -39,6 +40,7 @@ public class S3FileClientConfig implements FileClientConfig { * 3. 腾讯云:https://cloud.tencent.com/document/product/436/11142 * 4. 七牛云:https://developer.qiniu.com/kodo/8556/set-the-custom-source-domain-name * 5. 华为云:https://support.huaweicloud.com/usermanual-obs/obs_03_0032.html + * 6. 火山云:https://www.volcengine.com/docs/6349/128983 */ @URL(message = "domain 必须是 URL 格式") private String domain; @@ -55,6 +57,7 @@ public class S3FileClientConfig implements FileClientConfig { * 3. 腾讯云:https://console.cloud.tencent.com/cam/capi * 4. 七牛云:https://portal.qiniu.com/user/key * 5. 华为云:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html + * 6. 火山云:https://console.volcengine.com/iam/keymanage/ */ @NotNull(message = "accessKey 不能为空") private String accessKey; From f782e3a9af717cf72cab1f983f78ea19a45163d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=87=E5=BA=86?= Date: Mon, 18 Nov 2024 08:06:52 +0000 Subject: [PATCH 31/43] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E5=A5=97=E9=A4=90=E6=97=B6=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=9B=A0=E7=BC=93=E5=AD=98=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E7=94=9F=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨宇庆 --- .../system/service/permission/PermissionServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java index afb62c7f9f..2d9e12fe68 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java @@ -132,8 +132,12 @@ public class PermissionServiceImpl implements PermissionService { @Override @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 - @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + @Caching(evict = { + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true), + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 + }) public void assignRoleMenu(Long roleId, Set menuIds) { // 获得角色拥有菜单编号 Set dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); From 4d4df7bd0c56b98dfab5bee5d0af8db807c0bdac Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 22 Nov 2024 20:33:31 +0800 Subject: [PATCH 32/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91websocket=EF=BC=9A=E6=89=BE=E4=B8=8D=E5=88=B0?= =?UTF-8?q?=20session=20=E6=97=B6=EF=BC=8C=E6=97=A5=E5=BF=97=E7=BA=A7?= =?UTF-8?q?=E5=88=AB=E4=BB=8E=20info=20=E5=88=B0=20debug=20=E7=BA=A7?= =?UTF-8?q?=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/sender/AbstractWebSocketMessageSender.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java index 4e0db44c9d..9309fd2f3c 100644 --- a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java +++ b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java @@ -64,8 +64,10 @@ public abstract class AbstractWebSocketMessageSender implements WebSocketMessage sessions = (List) sessionManager.getSessionList(userType); } if (CollUtil.isEmpty(sessions)) { - log.info("[send][sessionId({}) userType({}) userId({}) messageType({}) messageContent({}) 未匹配到会话]", - sessionId, userType, userId, messageType, messageContent); + if (log.isDebugEnabled()) { + log.debug("[send][sessionId({}) userType({}) userId({}) messageType({}) messageContent({}) 未匹配到会话]", + sessionId, userType, userId, messageType, messageContent); + } } // 2. 执行发送 doSend(sessions, messageType, messageContent); From c616066a6048d01cd75bde374e863c3884016dcf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 23 Nov 2024 10:08:19 +0800 Subject: [PATCH 33/43] =?UTF-8?q?README=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E7=9A=84=E6=BC=94=E7=A4=BA=E5=9B=BE?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .image/工作流设计器-bpmn.jpg | Bin 0 -> 181405 bytes .image/工作流设计器-simple.jpg | Bin 0 -> 129583 bytes README.md | 22 +++++++++++++--------- 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 .image/工作流设计器-bpmn.jpg create mode 100644 .image/工作流设计器-simple.jpg diff --git a/.image/工作流设计器-bpmn.jpg b/.image/工作流设计器-bpmn.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2a61f60f869b28dce151f0964a1aaad8c0b333cd GIT binary patch literal 181405 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

3SP)i)UQi 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 CczQ?x literal 0 HcmV?d00001 diff --git a/.image/工作流设计器-simple.jpg b/.image/工作流设计器-simple.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ef2c9e293b2eb91f0e0b19c63bdbda263f3254b GIT binary patch literal 129583 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 Date: Mon, 25 Nov 2024 01:50:58 +0000 Subject: [PATCH 34/43] =?UTF-8?q?fix:=20=E4=BC=9A=E7=AD=BE=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B,=E5=AD=98=E5=9C=A8=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=9A=84=E5=AE=A1=E6=89=B9=E5=8D=B4=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=B7=B2=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceServiceImpl.java | 709 +++++++++++++++++- 1 file changed, 708 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 0de51dc148..878de1b43e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1,708 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNodeTask; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; 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.framework.flowable.core.util.SimpleModelUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.constants.BpmnXMLConstants; import org.flowable.bpmn.model.*; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; 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.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.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 java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.flowable.bpmn.constants.BpmnXMLConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource @Lazy // 避免循环依赖 private BpmTaskService taskService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Resource private BpmTaskCandidateInvoker taskCandidateInvoker; // ========== Query 查询相关方法 ========== @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) { processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey()); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } private Map getFormFieldsPermission(BpmnModel bpmnModel, String activityId, String taskId) { // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) .map(HistoricTaskInstance::getTaskDefinitionKey).orElse(null); } if (StrUtil.isEmpty(activityId)) { return null; } // 2. 从 BpmnModel 中解析表单字段权限 return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId); } @Override public BpmApprovalDetailRespVO getApprovalDetail(Long loginUserId, BpmApprovalDetailReqVO reqVO) { // 1.1 从 reqVO 中,读取公共变量 Long startUserId = loginUserId; // 流程发起人 HistoricProcessInstance historicProcessInstance = null; // 流程实例 Integer processInstanceStatus = BpmProcessInstanceStatusEnum.NOT_START.getStatus(); // 流程状态 Map processVariables = reqVO.getProcessVariables(); // 流程变量 // 1.2 如果是流程已发起的场景,则使用流程实例的数据 if (reqVO.getProcessInstanceId() != null) { historicProcessInstance = getHistoricProcessInstance(reqVO.getProcessInstanceId()); if (historicProcessInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); } startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); processVariables = historicProcessInstance.getProcessVariables(); } // 1.3 读取其它相关数据 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId() : reqVO.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId()); BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); // 2.1 已结束 + 进行中的活动节点 List endActivityNodes = null; // 已结束的审批信息 List runActivityNodes = null; // 进行中的审批信息 List activities = null; // 流程实例列表 if (reqVO.getProcessInstanceId() != null) { activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId()); List tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(), true); endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo, historicProcessInstance, processInstanceStatus, activities, tasks); runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables, activities, tasks); } // 2.2 流程已经结束,直接 return,无需预测 if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) { return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, processInstanceStatus, endActivityNodes, runActivityNodes, null, null); } // 3.1 计算当前登录用户的待办任务 // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到 B,会不会表单权限不一致哈。 BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId()); // 3.2 预测未运行节点的审批信息 List simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, processDefinitionInfo, processVariables, activities); // 4. 拼接最终数据 return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask); } /** * 拼接审批详情的最终数据 *

* 主要是,拼接审批人的用户信息、部门信息 */ private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, BpmnModel bpmnModel, ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionInfo, HistoricProcessInstance processInstance, Integer processInstanceStatus, List endApprovalNodeInfos, List runningApprovalNodeInfos, List simulateApprovalNodeInfos, BpmTaskRespVO todoTask) { // 1. 获取所有需要读取用户信息的 userIds List approveNodes = newArrayList(asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos)); Set userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask); Map userMap = adminUserApi.getUserMap(userIds); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 2. 表单权限 Map formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), reqVO.getTaskId()); // 3. 拼接数据 return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, processDefinitionInfo, processInstance, processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap); } /** * 获得【已结束】的活动节点们 */ private List getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus, List activities, List tasks) { // 遍历 tasks 列表,只处理已结束的 UserTask // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 List endTasks = filterList(tasks, task -> task.getEndTime() != null); List approvalNodes = convertList(endTasks, task -> { FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName()) .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ? BpmSimpleModelNodeType.START_USER_NODE.getType() : BpmSimpleModelNodeType.APPROVE_NODE.getType()) .setStatus(FlowableUtils.getTaskStatus(task)) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); // 如果是取消状态,则跳过 if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) { return null; } return activityNode; }); // 遍历 activities,只处理已结束的 StartEvent、EndEvent List endActivities = filterList(activities, activity -> activity.getEndTime() != null && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END))); endActivities.forEach(activity -> { // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 if (ELEMENT_EVENT_START.equals(activity.getActivityType()) && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType())) { ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID) .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus()); ActivityNode startNode = new ActivityNode().setId(startTask.getId()) .setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()) .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask)) .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); approvalNodes.add(0, startNode); return; } // EndEvent if (ELEMENT_EVENT_END.equals(activity.getActivityType())) { if (BpmProcessInstanceStatusEnum.isRejectStatus(processInstanceStatus)) { // 拒绝情况下,不需要展示 EndEvent 结束节点。原因是:前端已经展示 x 效果,无需重复展示 return; } ActivityNode endNode = new ActivityNode().setId(activity.getId()) .setName(BpmSimpleModelNodeType.END_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()).setStatus(processInstanceStatus) .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance); if (StrUtil.isNotEmpty(reason)) { endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId()) .setStatus(endNode.getStatus()).setReason(reason))); } approvalNodes.add(endNode); } }); return approvalNodes; } /** * 获得【进行中】的活动节点们 */ private List getRunApproveNodeList(Long startUserId, BpmnModel bpmnModel, ProcessDefinition processDefinition, Map processVariables, List activities, List tasks) { // 构建运行中的任务,基于 activityId 分组 List runActivities = filterList(activities, activity -> activity.getEndTime() == null && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER))); Map> runningTaskMap = convertMultiMap(runActivities, HistoricActivityInstance::getActivityId); // 按照 activityId 分组,构建 ApprovalNodeInfo 节点 Map taskMap = convertMap(tasks, HistoricTaskInstance::getId); return convertList(runningTaskMap.entrySet(), entry -> { String activityId = entry.getKey(); List taskActivities = entry.getValue(); // 构建活动节点 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同 ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()).setName(firstActivity.getActivityName()) .setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime())) .setTasks(new ArrayList<>()); // 处理每个任务的 tasks 属性 for (HistoricActivityInstance activity : taskActivities) { HistoricTaskInstance task = taskMap.get(activity.getTaskId()); activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)); // 加签子任务,需要过滤掉已经完成的加签子任务 List childrenTasks = filterList( taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks), childTask -> childTask.getEndTime() == null); if (CollUtil.isNotEmpty(childrenTasks)) { activityNode.getTasks().addAll(convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo)); } } // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task if (BpmnModelUtils.isSequentialUserTask(flowNode)) { List candidateUserIds = getTaskCandidateUserList(bpmnModel, flowNode.getId(), startUserId, processDefinition.getId(), processVariables); // 截取当前审批人位置后面的候选人,不包含当前审批人 ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks()); Assert.notNull(approvalTaskInfo, "任务不能为空"); int index = CollUtil.indexOf(candidateUserIds, userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(), approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } return activityNode; }); } /** * 获得【预测(未来)】的活动节点们 */ private List getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, List activities) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 Set runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId); // 情况一:BPMN 设计器 if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { List flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables); return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn(startUserId, bpmnModel, processDefinitionInfo, processVariables, flowElement, runActivityIds)); } // 情况二:SIMPLE 设计器 if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) { BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); List simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel, processDefinitionInfo, processVariables, simpleNode, runActivityIds)); } throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType()); } private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, BpmSimpleModelNodeVO node, Set runActivityIds) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 if (runActivityIds.contains(node.getId())) { return null; } ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName()) .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy()) .setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); // 1. 开始节点/审批节点 if (ObjectUtils.equalsAny(node.getType(), BpmSimpleModelNodeType.START_USER_NODE.getType(), BpmSimpleModelNodeType.APPROVE_NODE.getType())) { List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); activityNode.setCandidateUserIds(candidateUserIds); return activityNode; } // 2. 结束节点 if (BpmSimpleModelNodeType.END_NODE.getType().equals(node.getType())) { return activityNode; } // 3. 抄送节点 if (CollUtil.isEmpty(runActivityIds) && // 流程发起时:需要展示抄送节点,用于选择抄送人 BpmSimpleModelNodeType.COPY_NODE.getType().equals(node.getType())) { return activityNode; } return null; } private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, FlowElement node, Set runActivityIds) { if (runActivityIds.contains(node.getId())) { return null; } ActivityNode activityNode = new ActivityNode().setId(node.getId()).setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); // 1. 开始节点 if (node instanceof StartEvent) { return activityNode.setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()); } // 2. 审批节点 if (node instanceof UserTask) { List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); return activityNode.setName(node.getName()).setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) .setCandidateUserIds(candidateUserIds); } // 3. 结束节点 if (node instanceof EndEvent) { return activityNode.setName(BpmSimpleModelNodeType.END_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()); } return null; } private List getTaskCandidateUserList(BpmnModel bpmnModel, String activityId, Long startUserId, String processDefinitionId, Map processVariables) { Set userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId, startUserId, processDefinitionId, processVariables); return new ArrayList<>(userIds); } @Override public BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id) { // 1.1 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 1.2 获得流程定义 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); if (bpmnModel == null) { return null; } BpmSimpleModelNodeVO simpleModel = null; BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); if (processDefinitionInfo != null && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) { simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); } // 1.3 获得流程实例对应的活动实例列表 + 任务列表 List activities = taskService.getActivityListByProcessInstanceId(id); List tasks = taskService.getTaskListByProcessInstanceId(id, true); // 2.1 拼接进度信息 Set unfinishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() == null); Set finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.notEqual(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); Set finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点 Set rejectTaskActivityIds = CollUtil.newHashSet(); if (BpmProcessInstanceStatusEnum.isRejectStatus(FlowableUtils.getProcessInstanceStatus(processInstance))) { tasks.stream() .filter(task -> BpmTaskStatusEnum.isRejectStatus(FlowableUtils.getTaskStatus(task))) .max(Comparator.comparing(HistoricTaskInstance::getEndTime)) .ifPresent(reject -> rejectTaskActivityIds.add(reject.getTaskDefinitionKey())); finishedTaskActivityIds.removeAll(rejectTaskActivityIds); } // 2.2 拼接基础信息 Set userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks); Map userMap = adminUserApi.getUserMap(userIds); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel, simpleModel, unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds, rejectTaskActivityIds, userMap, deptMap); } // ========== Update 写入相关方法 ========== @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(definition.getId()); if (processDefinitionInfo == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } // 1.2 校验是否能够发起 if (!processDefinitionService.canUserStartProcessDefinition(processDefinitionInfo, userId)) { throw exception(PROCESS_INSTANCE_START_USER_CAN_START); } // 1.3 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel); if (CollUtil.isEmpty(tasks)) { return; } // 2. 校验发起人自选审批人的审批人和抄送人是否都配置了 tasks.forEach(task -> { List assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(task.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, task.getName()); } Map userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, task.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 取消流程 updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 2. 取消流程 AdminUserRespDTO user = adminUserApi.getUser(userId); updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); } private void updateProcessInstanceCancel(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); // 2. 结束流程 taskService.moveTaskToEnd(id); } @Override public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, BpmReasonEnum.REJECT_TASK.format(reason)); } // ========== Event 事件相关方法 ========== @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); } // 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)); }); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +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; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNodeTask; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; +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.framework.flowable.core.util.SimpleModelUtils; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; +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 jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.constants.BpmnXMLConstants; +import org.flowable.bpmn.model.*; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +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.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.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 java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.flowable.bpmn.constants.BpmnXMLConstants.*; + +/** + * 流程实例 Service 实现类 + *

+ * ProcessDefinition & ProcessInstance & Execution & Task 的关系: + * 1. + *

+ * HistoricProcessInstance & ProcessInstance 的关系: + * 1. + *

+ * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { + + @Resource + private RuntimeService runtimeService; + @Resource + private HistoryService historyService; + + @Resource + private BpmProcessDefinitionService processDefinitionService; + @Resource + @Lazy // 避免循环依赖 + private BpmTaskService taskService; + @Resource + private BpmMessageService messageService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Resource + private BpmProcessInstanceEventPublisher processInstanceEventPublisher; + + @Resource + private BpmTaskCandidateInvoker taskCandidateInvoker; + + // ========== Query 查询相关方法 ========== + + @Override + public ProcessInstance getProcessInstance(String id) { + return runtimeService.createProcessInstanceQuery() + .includeProcessVariables() + .processInstanceId(id) + .singleResult(); + } + + @Override + public List getProcessInstances(Set ids) { + return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); + } + + @Override + public HistoricProcessInstance getHistoricProcessInstance(String id) { + return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); + } + + @Override + public List getHistoricProcessInstances(Set ids) { + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); + } + + @Override + public PageResult getProcessInstancePage(Long userId, + BpmProcessInstancePageReqVO pageReqVO) { + // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 + HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() + .includeProcessVariables() + .processInstanceTenantId(FlowableUtils.getTenantId()) + .orderByProcessInstanceStartTime().desc(); + if (userId != null) { // 【我的流程】菜单时,需要传递该字段 + processInstanceQuery.startedBy(String.valueOf(userId)); + } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 + processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); + } + if (StrUtil.isNotEmpty(pageReqVO.getName())) { + processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); + } + if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) { + processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey()); + } + if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { + processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); + } + if (pageReqVO.getStatus() != null) { + processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); + } + if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { + processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); + processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); + } + // 查询数量 + long processInstanceCount = processInstanceQuery.count(); + if (processInstanceCount == 0) { + return PageResult.empty(processInstanceCount); + } + // 查询列表 + List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); + return new PageResult<>(processInstanceList, processInstanceCount); + } + + + private Map getFormFieldsPermission(BpmnModel bpmnModel, + String activityId, String taskId) { + // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id + if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { + activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) + .map(HistoricTaskInstance::getTaskDefinitionKey).orElse(null); + } + if (StrUtil.isEmpty(activityId)) { + return null; + } + + // 2. 从 BpmnModel 中解析表单字段权限 + return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId); + } + + @Override + public BpmApprovalDetailRespVO getApprovalDetail(Long loginUserId, BpmApprovalDetailReqVO reqVO) { + // 1.1 从 reqVO 中,读取公共变量 + Long startUserId = loginUserId; // 流程发起人 + HistoricProcessInstance historicProcessInstance = null; // 流程实例 + Integer processInstanceStatus = BpmProcessInstanceStatusEnum.NOT_START.getStatus(); // 流程状态 + Map processVariables = reqVO.getProcessVariables(); // 流程变量 + // 1.2 如果是流程已发起的场景,则使用流程实例的数据 + if (reqVO.getProcessInstanceId() != null) { + historicProcessInstance = getHistoricProcessInstance(reqVO.getProcessInstanceId()); + if (historicProcessInstance == null) { + throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); + } + startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); + processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); + processVariables = historicProcessInstance.getProcessVariables(); + } + // 1.3 读取其它相关数据 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId() : reqVO.getProcessDefinitionId()); + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId()); + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); + + // 2.1 已结束 + 进行中的活动节点 + List endActivityNodes = null; // 已结束的审批信息 + List runActivityNodes = null; // 进行中的审批信息 + List activities = null; // 流程实例列表 + if (reqVO.getProcessInstanceId() != null) { + activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId()); + List tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(), true); + endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo, + historicProcessInstance, processInstanceStatus, activities, tasks); + runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables, activities, tasks); + } + + // 2.2 流程已经结束,直接 return,无需预测 + if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) { + return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, + processInstanceStatus, endActivityNodes, runActivityNodes, null, null); + } + + // 3.1 计算当前登录用户的待办任务 + // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到 B,会不会表单权限不一致哈。 + BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId()); + + // 3.2 预测未运行节点的审批信息 + List simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, processDefinitionInfo, + processVariables, activities); + + // 4. 拼接最终数据 + return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, + processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask); + } + + /** + * 拼接审批详情的最终数据 + *

+ * 主要是,拼接审批人的用户信息、部门信息 + */ + private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, + BpmnModel bpmnModel, + ProcessDefinition processDefinition, + BpmProcessDefinitionInfoDO processDefinitionInfo, + HistoricProcessInstance processInstance, + Integer processInstanceStatus, + List endApprovalNodeInfos, + List runningApprovalNodeInfos, + List simulateApprovalNodeInfos, + BpmTaskRespVO todoTask) { + // 1. 获取所有需要读取用户信息的 userIds + List approveNodes = newArrayList(asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos)); + Set userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + + // 2. 表单权限 + Map formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), reqVO.getTaskId()); + + // 3. 拼接数据 + return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, processDefinitionInfo, processInstance, + processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap); + } + + /** + * 获得【已结束】的活动节点们 + */ + private List getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel, + BpmProcessDefinitionInfoDO processDefinitionInfo, + HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus, + List activities, List tasks) { + // 遍历 tasks 列表,只处理已结束的 UserTask + // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 + List endTasks = filterList(tasks, task -> task.getEndTime() != null); + List approvalNodes = convertList(endTasks, task -> { + FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); + ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName()) + .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ? + BpmSimpleModelNodeType.START_USER_NODE.getType() : BpmSimpleModelNodeType.APPROVE_NODE.getType()) + .setStatus(FlowableUtils.getTaskStatus(task)) + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) + .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) + .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); + // 如果是取消状态,则跳过 + if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) { + return null; + } + return activityNode; + }); + + // 遍历 activities,只处理已结束的 StartEvent、EndEvent + List endActivities = filterList(activities, activity -> activity.getEndTime() != null + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END))); + endActivities.forEach(activity -> { + // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 + if (ELEMENT_EVENT_START.equals(activity.getActivityType()) + && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType())) { + ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID) + .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus()); + ActivityNode startNode = new ActivityNode().setId(startTask.getId()) + .setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) + .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()) + .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask)) + .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); + approvalNodes.add(0, startNode); + return; + } + // EndEvent + if (ELEMENT_EVENT_END.equals(activity.getActivityType())) { + if (BpmProcessInstanceStatusEnum.isRejectStatus(processInstanceStatus)) { + // 拒绝情况下,不需要展示 EndEvent 结束节点。原因是:前端已经展示 x 效果,无需重复展示 + return; + } + ActivityNode endNode = new ActivityNode().setId(activity.getId()) + .setName(BpmSimpleModelNodeType.END_NODE.getName()) + .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()).setStatus(processInstanceStatus) + .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); + String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance); + if (StrUtil.isNotEmpty(reason)) { + endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId()) + .setStatus(endNode.getStatus()).setReason(reason))); + } + approvalNodes.add(endNode); + } + }); + return approvalNodes; + } + + /** + * 获得【进行中】的活动节点们 + */ + private List getRunApproveNodeList(Long startUserId, + BpmnModel bpmnModel, + ProcessDefinition processDefinition, + Map processVariables, + List activities, + List tasks) { + // 构建运行中的任务,基于 activityId 分组 + List runActivities = filterList(activities, activity -> activity.getEndTime() == null + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER))); + Map> runningTaskMap = convertMultiMap(runActivities, HistoricActivityInstance::getActivityId); + + // 按照 activityId 分组,构建 ApprovalNodeInfo 节点 + Map taskMap = convertMap(tasks, HistoricTaskInstance::getId); + return convertList(runningTaskMap.entrySet(), entry -> { + String activityId = entry.getKey(); + List taskActivities = entry.getValue(); + // 构建活动节点 + FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); + HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同 + ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()).setName(firstActivity.getActivityName()) + .setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) + .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime())) + .setTasks(new ArrayList<>()); + // 处理每个任务的 tasks 属性 + for (HistoricActivityInstance activity : taskActivities) { + HistoricTaskInstance task = taskMap.get(activity.getTaskId()); + activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)); + // 加签子任务,需要过滤掉已经完成的加签子任务 + List childrenTasks = filterList( + taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks), + childTask -> childTask.getEndTime() == null); + if (CollUtil.isNotEmpty(childrenTasks)) { + activityNode.getTasks().addAll(convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo)); + } + } + // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task + if (BpmnModelUtils.isSequentialUserTask(flowNode)) { + List candidateUserIds = getTaskCandidateUserList(bpmnModel, flowNode.getId(), + startUserId, processDefinition.getId(), processVariables); + // 截取当前审批人位置后面的候选人,不包含当前审批人 + ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks()); + Assert.notNull(approvalTaskInfo, "任务不能为空"); + int index = CollUtil.indexOf(candidateUserIds, userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(), + approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner + activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); + } + return activityNode; + }); + } + + /** + * 获得【预测(未来)】的活动节点们 + */ + private List getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel, + BpmProcessDefinitionInfoDO processDefinitionInfo, + Map processVariables, + List activities) { + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 + Set runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId); + // 情况一:BPMN 设计器 + if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { + List flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables); + return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn(startUserId, bpmnModel, + processDefinitionInfo, processVariables, flowElement, runActivityIds)); + } + // 情况二:SIMPLE 设计器 + if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) { + BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); + List simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); + return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel, + processDefinitionInfo, processVariables, simpleNode, runActivityIds)); + } + throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType()); + } + + private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel, + BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, + BpmSimpleModelNodeVO node, Set runActivityIds) { + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 + if (runActivityIds.contains(node.getId())) { + return null; + } + + ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName()) + .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy()) + .setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); + + // 1. 开始节点/审批节点 + if (ObjectUtils.equalsAny(node.getType(), + BpmSimpleModelNodeType.START_USER_NODE.getType(), + BpmSimpleModelNodeType.APPROVE_NODE.getType())) { + List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), + startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); + activityNode.setCandidateUserIds(candidateUserIds); + return activityNode; + } + + // 2. 结束节点 + if (BpmSimpleModelNodeType.END_NODE.getType().equals(node.getType())) { + return activityNode; + } + + // 3. 抄送节点 + if (CollUtil.isEmpty(runActivityIds) && // 流程发起时:需要展示抄送节点,用于选择抄送人 + BpmSimpleModelNodeType.COPY_NODE.getType().equals(node.getType())) { + return activityNode; + } + return null; + } + + private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, + BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, + FlowElement node, Set runActivityIds) { + if (runActivityIds.contains(node.getId())) { + return null; + } + ActivityNode activityNode = new ActivityNode().setId(node.getId()).setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); + + // 1. 开始节点 + if (node instanceof StartEvent) { + return activityNode.setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) + .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()); + } + + // 2. 审批节点 + if (node instanceof UserTask) { + List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), + startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); + return activityNode.setName(node.getName()).setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()) + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) + .setCandidateUserIds(candidateUserIds); + } + + // 3. 结束节点 + if (node instanceof EndEvent) { + return activityNode.setName(BpmSimpleModelNodeType.END_NODE.getName()) + .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()); + } + return null; + } + + private List getTaskCandidateUserList(BpmnModel bpmnModel, String activityId, + Long startUserId, String processDefinitionId, Map processVariables) { + Set userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId, + startUserId, processDefinitionId, processVariables); + return new ArrayList<>(userIds); + } + + @Override + public BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id) { + // 1.1 获得流程实例 + HistoricProcessInstance processInstance = getHistoricProcessInstance(id); + if (processInstance == null) { + return null; + } + // 1.2 获得流程定义 + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); + if (bpmnModel == null) { + return null; + } + BpmSimpleModelNodeVO simpleModel = null; + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( + processInstance.getProcessDefinitionId()); + if (processDefinitionInfo != null && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) { + simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); + } + // 1.3 获得流程实例对应的活动实例列表 + 任务列表 + List activities = taskService.getActivityListByProcessInstanceId(id); + List tasks = taskService.getTaskListByProcessInstanceId(id, true); + + // 2.1 拼接进度信息 + Set unfinishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, + activityInstance -> activityInstance.getEndTime() == null); + Set finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, + activityInstance -> activityInstance.getEndTime() != null + && ObjectUtil.notEqual(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); + Set finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, + activityInstance -> activityInstance.getEndTime() != null + && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); + // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 + // unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); + finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds); + // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 + // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点 + Set rejectTaskActivityIds = CollUtil.newHashSet(); + if (BpmProcessInstanceStatusEnum.isRejectStatus(FlowableUtils.getProcessInstanceStatus(processInstance))) { + tasks.stream() + .filter(task -> BpmTaskStatusEnum.isRejectStatus(FlowableUtils.getTaskStatus(task))) + .max(Comparator.comparing(HistoricTaskInstance::getEndTime)) + .ifPresent(reject -> rejectTaskActivityIds.add(reject.getTaskDefinitionKey())); + finishedTaskActivityIds.removeAll(rejectTaskActivityIds); + } + + // 2.2 拼接基础信息 + Set userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel, simpleModel, + unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds, rejectTaskActivityIds, + userMap, deptMap); + } + + // ========== Update 写入相关方法 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { + // 获得流程定义 + ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); + // 发起流程 + return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, + createReqVO.getStartUserSelectAssignees()); + } + + @Override + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { + // 获得流程定义 + ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); + // 发起流程 + return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), + createReqDTO.getStartUserSelectAssignees()); + } + + private String createProcessInstance0(Long userId, ProcessDefinition definition, + Map variables, String businessKey, + Map> startUserSelectAssignees) { + // 1.1 校验流程定义 + if (definition == null) { + throw exception(PROCESS_DEFINITION_NOT_EXISTS); + } + if (definition.isSuspended()) { + throw exception(PROCESS_DEFINITION_IS_SUSPENDED); + } + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(definition.getId()); + if (processDefinitionInfo == null) { + throw exception(PROCESS_DEFINITION_NOT_EXISTS); + } + // 1.2 校验是否能够发起 + if (!processDefinitionService.canUserStartProcessDefinition(processDefinitionInfo, userId)) { + throw exception(PROCESS_INSTANCE_START_USER_CAN_START); + } + // 1.3 校验发起人自选审批人 + validateStartUserSelectAssignees(definition, startUserSelectAssignees); + + // 2. 创建流程实例 + if (variables == null) { + variables = new HashMap<>(); + } + FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 + BpmProcessInstanceStatusEnum.RUNNING.getStatus()); + if (CollUtil.isNotEmpty(startUserSelectAssignees)) { + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); + } + ProcessInstance instance = runtimeService.createProcessInstanceBuilder() + .processDefinitionId(definition.getId()) + .businessKey(businessKey) + .name(definition.getName().trim()) + .variables(variables) + .start(); + return instance.getId(); + } + + private void validateStartUserSelectAssignees(ProcessDefinition definition, Map> startUserSelectAssignees) { + // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表 + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); + List tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel); + if (CollUtil.isEmpty(tasks)) { + return; + } + + // 2. 校验发起人自选审批人的审批人和抄送人是否都配置了 + tasks.forEach(task -> { + List assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(task.getId()) : null; + if (CollUtil.isEmpty(assignees)) { + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, task.getName()); + } + Map userMap = adminUserApi.getUserMap(assignees); + assignees.forEach(assignee -> { + if (userMap.get(assignee) == null) { + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, task.getName(), assignee); + } + }); + }); + } + + @Override + public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { + // 1.1 校验流程实例存在 + ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); + } + // 1.2 只能取消自己的 + if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); + } + + // 2. 取消流程 + updateProcessInstanceCancel(cancelReqVO.getId(), + BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); + } + + @Override + public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { + // 1.1 校验流程实例存在 + ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); + } + + // 2. 取消流程 + AdminUserRespDTO user = adminUserApi.getUser(userId); + updateProcessInstanceCancel(cancelReqVO.getId(), + BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); + } + + private void updateProcessInstanceCancel(String id, String reason) { + // 1. 更新流程实例 status + runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, + BpmProcessInstanceStatusEnum.CANCEL.getStatus()); + runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); + + // 2. 结束流程 + taskService.moveTaskToEnd(id); + } + + @Override + public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { + runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, + BpmProcessInstanceStatusEnum.REJECT.getStatus()); + runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, + BpmReasonEnum.REJECT_TASK.format(reason)); + } + + // ========== Event 事件相关方法 ========== + + @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); + } + + // 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)); + }); + } + +} From ca6121b2054061917169fe26d4b63b6d3ac4368f Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Mon, 25 Nov 2024 01:57:05 +0000 Subject: [PATCH 35/43] =?UTF-8?q?fix:=20=E4=BC=9A=E7=AD=BE=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B,=E5=AD=98=E5=9C=A8=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=9A=84=E5=AE=A1=E6=89=B9=E5=8D=B4=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=B7=B2=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 959a51664b..83f3dca0e0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -520,7 +520,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 - unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); + // unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); + finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds); // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点 Set rejectTaskActivityIds = CollUtil.newHashSet(); From 98b2e41414ec68b43b94199ce59beacfbfc9f8df Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Mon, 25 Nov 2024 06:19:37 +0000 Subject: [PATCH 36/43] =?UTF-8?q?feat:=20bpm=E8=AE=BE=E8=AE=A1=E5=99=A8?= =?UTF-8?q?=E9=80=82=E9=85=8DSimple=E8=AE=BE=E8=AE=A1=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/BpmnModelUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 0d93fdfac1..44fbc218f8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -321,9 +321,9 @@ public class BpmnModelUtils { } Map buttonSettings = Maps.newHashMapWithExpectedSize(extensionElements.size()); extensionElements.forEach(element -> { - String id = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE); - String displayName = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE); - String enable = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE); + String id = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE); + String displayName = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE); + String enable = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE); if (StrUtil.isNotEmpty(id)) { BpmTaskRespVO.OperationButtonSetting setting = new BpmTaskRespVO.OperationButtonSetting(); buttonSettings.put(Integer.valueOf(id), setting.setDisplayName(displayName).setEnable(Boolean.parseBoolean(enable))); From 26a1d6362bd2e47f7a69682a8c0c2e1b7a6c4b22 Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Tue, 26 Nov 2024 01:52:13 +0000 Subject: [PATCH 37/43] =?UTF-8?q?feat:=20bpm=E8=AE=BE=E8=AE=A1=E5=99=A8?= =?UTF-8?q?=E9=80=82=E9=85=8DSimple=E8=AE=BE=E8=AE=A1=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/BpmnModelUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 44fbc218f8..3495a45262 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -278,8 +278,8 @@ public class BpmnModelUtils { } Map fieldsPermission = MapUtil.newHashMap(); extensionElements.forEach(element -> { - String field = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE); - String permission = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE); + String field = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE); + String permission = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE); if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) { fieldsPermission.put(field, permission); } From 39ee47d9d2814e04ef04fb04ca9e27f44e9db606 Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Tue, 26 Nov 2024 08:14:12 +0000 Subject: [PATCH 38/43] =?UTF-8?q?fix:=20=E5=BD=93=E6=97=A0=E6=BB=A1?= =?UTF-8?q?=E8=B6=B3=E6=9D=A1=E4=BB=B6=E6=97=B6=E9=80=89=E6=8B=A9=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E8=B7=AF=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/BpmnModelUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 3495a45262..4351c2b24a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -720,7 +720,7 @@ public class BpmnModelUtils { && evalConditionExpress(variables, flow.getConditionExpression())); if (matchSequenceFlow == null) { matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), - flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())); + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) { matchSequenceFlow = gateway.getOutgoingFlows().get(0); @@ -742,7 +742,7 @@ public class BpmnModelUtils { && evalConditionExpress(variables, flow.getConditionExpression())); if (CollUtil.isEmpty(matchSequenceFlows)) { matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), - flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())); + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) { matchSequenceFlows = gateway.getOutgoingFlows(); From 840517511e40ac757f2304e33a7536898bd85b46 Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Wed, 27 Nov 2024 10:50:44 +0800 Subject: [PATCH 39/43] =?UTF-8?q?fix:=20=E6=9C=AA=E4=BC=A0=E9=80=92?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/convert/task/BpmTaskConvert.java | 10 ++++++++-- .../module/bpm/service/task/BpmTaskServiceImpl.java | 13 ++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index b44c91951e..a68df4f4b3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -124,12 +124,18 @@ public interface BpmTaskConvert { } default BpmTaskRespVO buildTodoTask(Task todoTask, List childrenTasks, - Map buttonsSetting) { - return BeanUtils.toBean(todoTask, BpmTaskRespVO.class) + Map buttonsSetting, + BpmFormDO taskForm) { + BpmTaskRespVO bpmTaskRespVO = BeanUtils.toBean(todoTask, BpmTaskRespVO.class) .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask)) .setButtonsSetting(buttonsSetting) .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class) .setStatus(FlowableUtils.getTaskStatus(childTask)))); + if (taskForm != null) { + bpmTaskRespVO.setFormId(taskForm.getId()).setFormName(taskForm.getName()) + .setFormConf(taskForm.getConf()).setFormFields(taskForm.getFields()); + } + return bpmTaskRespVO; } default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 919240df2c..c03d35f876 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.enums.definition.*; import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; @@ -20,6 +21,7 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; 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.BpmFormService; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; @@ -91,6 +93,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { private BpmModelService modelService; @Resource private BpmMessageService messageService; + @Resource + private BpmFormService formService; @Resource private AdminUserApi adminUserApi; @@ -153,7 +157,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId()); Map buttonsSetting = BpmnModelUtils.parseButtonsSetting( bpmnModel, todoTask.getTaskDefinitionKey()); - return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting); + + // 4. 任务表单 + BpmFormDO taskForm = null; + if (StrUtil.isNotBlank(todoTask.getFormKey())){ + taskForm = formService.getForm(NumberUtils.parseLong(todoTask.getFormKey())); + } + + return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm); } @Override From 8b8fecc70829a28a7c56f9273bf450a9e1e2c98b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 28 Nov 2024 09:28:28 +0800 Subject: [PATCH 40/43] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E5=B7=A5=E4=BD=9C=E6=B5=81=EF=BC=9A=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/convert/task/BpmTaskConvert.java | 10 +++++----- .../service/task/BpmProcessInstanceServiceImpl.java | 1 - .../module/bpm/service/task/BpmTaskServiceImpl.java | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index a68df4f4b3..37c7218e05 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -124,16 +124,16 @@ public interface BpmTaskConvert { } default BpmTaskRespVO buildTodoTask(Task todoTask, List childrenTasks, - Map buttonsSetting, - BpmFormDO taskForm) { + Map buttonsSetting, + BpmFormDO form) { BpmTaskRespVO bpmTaskRespVO = BeanUtils.toBean(todoTask, BpmTaskRespVO.class) .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask)) .setButtonsSetting(buttonsSetting) .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class) .setStatus(FlowableUtils.getTaskStatus(childTask)))); - if (taskForm != null) { - bpmTaskRespVO.setFormId(taskForm.getId()).setFormName(taskForm.getName()) - .setFormConf(taskForm.getConf()).setFormFields(taskForm.getFields()); + if (form != null) { + bpmTaskRespVO.setFormId(form.getId()).setFormName(form.getName()) + .setFormConf(form.getConf()).setFormFields(form.getFields()); } return bpmTaskRespVO; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 83f3dca0e0..f07a3cf82c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -520,7 +520,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 - // unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds); // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index c03d35f876..46788fb25c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -163,7 +163,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotBlank(todoTask.getFormKey())){ taskForm = formService.getForm(NumberUtils.parseLong(todoTask.getFormKey())); } - return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm); } From 75f6eceea795714246513d06c580bb36c3772a90 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Dec 2024 15:48:54 +0800 Subject: [PATCH 41/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91=E5=B7=A5=E4=BD=9C=E6=B5=81=EF=BC=9A=E6=88=91?= =?UTF-8?q?=E7=9A=84=E5=AE=A1=E6=89=B9=EF=BC=8C=E6=94=AF=E6=8C=81=20catego?= =?UTF-8?q?ry=20=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java | 5 +++-- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java index d90eb632a9..11c59ce3ed 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java @@ -4,8 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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; @@ -17,6 +15,9 @@ public class BpmTaskPageReqVO extends PageParam { @Schema(description = "流程任务名", example = "芋道") private String name; + @Schema(description = "流程分类", example = "1") + private String category; + @Schema(description = "创建时间") @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 46788fb25c..7ba362b9ba 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -113,6 +113,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } + 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])); @@ -198,6 +201,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } + 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])); From dc1da29452f076a5f5286e85504b3e1d45652b47 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Dec 2024 17:36:48 +0800 Subject: [PATCH 42/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91=E5=B7=A5=E4=BD=9C=E6=B5=81=EF=BC=9Amodel=20n?= =?UTF-8?q?ame=20=E7=9A=84=E6=A8=A1=E7=B3=8A=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/service/definition/BpmModelServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index ed845d155e..8ec9999c02 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -65,7 +65,7 @@ public class BpmModelServiceImpl implements BpmModelService { public List getModelList(String name) { ModelQuery modelQuery = repositoryService.createModelQuery(); if (StrUtil.isNotEmpty(name)) { - modelQuery.modelNameLike(name); + modelQuery.modelNameLike("%" + name + "%"); } return modelQuery.list(); } From 466a3b068027159dd79d301804be166cb9d05ff6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Dec 2024 17:48:29 +0800 Subject: [PATCH 43/43] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91ERP=EF=BC=9A=E8=A7=A3=E5=86=B3=20Finance=20?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/finance/vo/payment/ErpFinancePaymentRespVO.java | 2 ++ .../admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java index 43820a7d27..12b5a7df8e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -11,6 +12,7 @@ import java.util.List; @Schema(description = "管理后台 - ERP 付款单 Response VO") @Data +@ExcelIgnoreUnannotated public class ErpFinancePaymentRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java index 5c7133fe68..ec82875957 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -11,6 +12,7 @@ import java.util.List; @Schema(description = "管理后台 - ERP 收款单 Response VO") @Data +@ExcelIgnoreUnannotated public class ErpFinanceReceiptRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")