Răsfoiți Sursa

Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro

# Conflicts:
#	yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
YunaiV 9 luni în urmă
părinte
comite
5d3bb791fd
13 a modificat fișierele cu 292 adăugiri și 132 ștergeri
  1. BIN
      .image/common/ai-feature.png
  2. 8 1
      README.md
  3. 7 3
      yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java
  4. 3 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
  5. 4 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
  6. 2 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
  7. 42 4
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
  8. 159 116
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
  9. 7 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
  10. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
  11. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java
  12. 8 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java
  13. 50 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java

BIN
.image/common/ai-feature.png


+ 8 - 1
README.md

@@ -112,7 +112,7 @@
 
 * 通用模块(必选):系统功能、基础设施
 * 通用模块(可选):工作流程、支付系统、数据报表、会员中心
-* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号
+* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型
 
 > 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
 >
@@ -248,6 +248,12 @@
 
 演示地址:<https://doc.iocoder.cn/crm-preview/>
 
+### AI 大模型
+
+![功能图](/.image/common/ai-feature.png)
+
+演示地址:<https://doc.iocoder.cn/ai-preview/>
+
 ## 🐨 技术栈
 
 ### 模块
@@ -265,6 +271,7 @@
 | `yudao-module-mall`   | 商城系统的 Module 模块    |
 | `yudao-module-erp`    | ERP 系统的 Module 模块  |
 | `yudao-module-crm`    | CRM 系统的 Module 模块  |
+| `yudao-module-ai`     | AI 大模型的 Module 模块  |
 | `yudao-module-mp`     | 微信公众号的 Module 模块   |
 | `yudao-module-report` | 大屏报表 Module 模块     |
 

+ 7 - 3
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java

@@ -34,20 +34,24 @@ public class CronUtils {
      * @return 满足条件的执行时间
      */
     public static List<LocalDateTime> getNextTimes(String cronExpression, int n) {
-        // 获得 CronExpression 对象
+        // 1. 获得 CronExpression 对象
         CronExpression cron;
         try {
             cron = new CronExpression(cronExpression);
         } catch (ParseException e) {
             throw new IllegalArgumentException(e.getMessage());
         }
-        // 从当前开始计算,n 个满足条件的
+        // 2. 从当前开始计算,n 个满足条件的
         Date now = new Date();
         List<LocalDateTime> nextTimes = new ArrayList<>(n);
         for (int i = 0; i < n; i++) {
             Date nextTime = cron.getNextValidTimeAfter(now);
+            // 2.1 如果 nextTime 为 null,说明没有更多的有效时间,退出循环
+            if (nextTime == null) {
+                break;
+            }
             nextTimes.add(LocalDateTimeUtil.of(nextTime));
-            // 切换现在,为下一个触发时间;
+            // 2.2 切换现在,为下一个触发时间;
             now = nextTime;
         }
         return nextTimes;

+ 3 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java

@@ -262,7 +262,9 @@ public class BpmModelServiceImpl implements BpmModelService {
     }
 
     private Model getModelByKey(String key) {
-        return repositoryService.createModelQuery().modelKey(key).singleResult();
+        return repositoryService.createModelQuery()
+                .modelTenantId(FlowableUtils.getTenantId())
+                .modelKey(key).singleResult();
     }
 
     @Override

+ 4 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java

@@ -79,7 +79,9 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
 
     @Override
     public ProcessDefinition getActiveProcessDefinition(String key) {
-        return repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).active().singleResult();
+        return repositoryService.createProcessDefinitionQuery()
+                .processDefinitionTenantId(FlowableUtils.getTenantId())
+                .processDefinitionKey(key).active().singleResult();
     }
 
     @Override
@@ -172,6 +174,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
     @Override
     public PageResult<ProcessDefinition> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) {
         ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
+        query.processDefinitionTenantId(FlowableUtils.getTenantId());
         if (StrUtil.isNotBlank(pageVO.getKey())) {
             query.processDefinitionKey(pageVO.getKey());
         }

+ 2 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java

@@ -30,7 +30,8 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
                 .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(ProductSpuDO::getSort);
+                .orderByDesc(ProductSpuDO::getSort)
+                .orderByDesc(ProductSpuDO::getId);
         appendTabQuery(tabType, queryWrapper);
         return selectPage(reqVO, queryWrapper);
     }

+ 42 - 4
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java

@@ -1,33 +1,49 @@
 package cn.iocoder.yudao.module.trade.service.order;
 
+import cn.hutool.core.util.IdUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
+import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
+import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
+import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
+import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
+import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
+import cn.iocoder.yudao.module.trade.service.cart.CartServiceImpl;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressServiceImpl;
+import cn.iocoder.yudao.module.trade.service.message.TradeMessageServiceImpl;
+import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
+import cn.iocoder.yudao.module.trade.service.price.TradePriceServiceImpl;
+import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator;
+import jakarta.annotation.Resource;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
 
-import javax.annotation.Resource;
 import java.time.Duration;
 
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -38,7 +54,9 @@ import static org.mockito.Mockito.when;
  * @since 2022-09-07
  */
 @Disabled // TODO 芋艿:后续 fix 补充的单测
-@Import({TradeOrderUpdateServiceImpl.class, TradeOrderConfig.class})
+@Import({TradeOrderUpdateServiceImpl.class, TradeOrderConfig.class, CartServiceImpl.class, TradePriceServiceImpl.class,
+        DeliveryExpressServiceImpl.class, TradeMessageServiceImpl.class
+})
 public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
 
     @Resource
@@ -55,7 +73,9 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
     private ProductSpuApi productSpuApi;
     @MockBean
     private ProductSkuApi productSkuApi;
-//    @MockBean
+    @MockBean
+    private ProductCommentApi productCommentApi;
+    //    @MockBean
 //    private PriceApi priceApi;
     @MockBean
     private PayOrderApi payOrderApi;
@@ -66,11 +86,22 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
 
     @MockBean
     private TradeOrderProperties tradeOrderProperties;
+    @MockBean
+    private TradeNoRedisDAO tradeNoRedisDAO;
+    @MockBean
+    private TradeOrderHandler tradeOrderHandler;
+    @MockBean
+    private TradePriceCalculator tradePriceCalculator;
+    @MockBean
+    private NotifyMessageSendApi notifyMessageSendApi;
+    @MockBean
+    private DeliveryExpressService deliveryExpressService;
 
     @BeforeEach
     public void setUp() {
         when(tradeOrderProperties.getAppId()).thenReturn(888L);
         when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
+        when(tradeNoRedisDAO.generate(anyString())).thenReturn(IdUtil.randomUUID());
     }
 
 //    @Test
@@ -259,11 +290,18 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
         TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> {
             o.setId(1L).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus());
             o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null);
+            o.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
+            o.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType());
         });
         tradeOrderMapper.insert(order);
+
+        DeliveryExpressCreateReqVO expressCreateReqVO = new DeliveryExpressCreateReqVO();
+        expressCreateReqVO.setCode("code").setName("Name").setLogo("logo").setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus());
+        Long deliveryExpressId = deliveryExpressService.createDeliveryExpress(expressCreateReqVO);
         // 准备参数
         TradeOrderDeliveryReqVO deliveryReqVO = new TradeOrderDeliveryReqVO().setId(1L)
-                .setLogisticsId(10L).setLogisticsNo("100");
+                .setLogisticsId(deliveryExpressId).setLogisticsNo("100");
+
         // mock 方法(支付单)
 
         // 调用

+ 159 - 116
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -1,128 +1,155 @@
-CREATE TABLE IF NOT EXISTS "trade_order" (
-     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-     "no" varchar NOT NULL,
-     "type" int NOT NULL,
-     "terminal" int NOT NULL,
-     "user_id" bigint NOT NULL,
-     "user_ip" varchar NOT NULL,
-     "user_remark" varchar,
-     "status" int NOT NULL,
-     "product_count" int NOT NULL,
-     "cancel_type" int,
-     "remark" varchar,
-     "pay_status" bit NOT NULL,
-     "pay_time" datetime,
-     "finish_time" datetime,
-     "cancel_time" datetime,
-     "original_price" int NOT NULL,
-     "order_price" int NOT NULL,
-     "discount_price" int NOT NULL,
-     "delivery_price" int NOT NULL,
-     "adjust_price" int NOT NULL,
-     "pay_price" int NOT NULL,
-     "pay_order_id" bigint,
-     "pay_channel_code" varchar,
-     "delivery_template_id" bigint,
-     "logistics_id" bigint,
-     "logistics_no" varchar,
-     "delivery_time" datetime,
-     "receive_time" datetime,
-     "receiver_name" varchar NOT NULL,
-     "receiver_mobile" varchar NOT NULL,
-     "receiver_area_id" int NOT NULL,
-     "receiver_post_code" int,
-     "receiver_detail_address" varchar NOT NULL,
-     "after_sale_status" int NOT NULL,
-     "refund_price" int NOT NULL,
-     "coupon_id" bigint NOT NULL,
-     "coupon_price" int NOT NULL,
-     "point_price" int NOT NULL,
-     "creator" varchar DEFAULT '',
-     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-     "updater" varchar DEFAULT '',
-     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-     "deleted" bit NOT NULL DEFAULT FALSE,
-     PRIMARY KEY ("id")
+CREATE TABLE IF NOT EXISTS "trade_order"
+(
+    "id"                      bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "no"                      varchar  NOT NULL,
+    "type"                    int      NOT NULL,
+    "terminal"                int      NOT NULL,
+    "user_id"                 bigint   NOT NULL,
+    "user_ip"                 varchar  NOT NULL,
+    "user_remark"             varchar,
+    "status"                  int      NOT NULL,
+    "product_count"           int      NOT NULL,
+    "cancel_type"             int,
+    "remark"                  varchar,
+    "comment_status"          boolean,
+    "brokerage_user_id"       bigint,
+    "pay_status"              bit      NOT NULL,
+    "pay_time"                datetime,
+    "finish_time"             datetime,
+    "cancel_time"             datetime,
+    "total_price"             int      NULL,
+    "order_price"             int      NULL,
+    "discount_price"          int      NOT NULL,
+    "delivery_price"          int      NOT NULL,
+    "adjust_price"            int      NOT NULL,
+    "pay_price"               int      NOT NULL,
+    "delivery_type"           int      NOT NULL,
+    "pay_order_id"            bigint,
+    "pay_channel_code"        varchar,
+    "delivery_template_id"    bigint,
+    "logistics_id"            bigint,
+    "logistics_no"            varchar,
+    "delivery_time"           datetime,
+    "receive_time"            datetime,
+    "receiver_name"           varchar  NOT NULL,
+    "receiver_mobile"         varchar  NOT NULL,
+    "receiver_area_id"        int      NOT NULL,
+    "receiver_post_code"      int,
+    "receiver_detail_address" varchar  NOT NULL,
+    "pick_up_store_id"        long     NULL,
+    "pick_up_verify_code"     varchar  NULL,
+    "refund_status"           int      NULL,
+    "refund_price"            int      NULL,
+    "after_sale_status"       int      NULL,
+    "coupon_id"               bigint   NOT NULL,
+    "coupon_price"            int      NOT NULL,
+    "use_point"               int      NULL,
+    "point_price"             int      NOT NULL,
+    "give_point"              int      NULL,
+    "refund_point"            int      NULL,
+    "vip_price"               int      NULL,
+    "seckill_activity_id"     long     NULL,
+    "bargain_activity_id"     long     NULL,
+    "bargain_record_id"       long     NULL,
+    "combination_activity_id" long     NULL,
+    "combination_head_id"     long     NULL,
+    "combination_record_id"   long     NULL,
+    "creator"                 varchar           DEFAULT '',
+    "create_time"             datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"                 varchar           DEFAULT '',
+    "update_time"             datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted"                 bit      NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
 ) COMMENT '交易订单表';
 
-CREATE TABLE IF NOT EXISTS "trade_order_item" (
-      "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-      "user_id" bigint NOT NULL,
-      "order_id" bigint NOT NULL,
-      "spu_id" bigint NOT NULL,
-      "spu_name" varchar NOT NULL,
-      "sku_id" bigint NOT NULL,
-      "properties" varchar,
-      "pic_url" varchar,
-      "count" int NOT NULL,
-      "original_price" int NOT NULL,
-      "original_unit_price" int NOT NULL,
-      "discount_price" int NOT NULL,
-      "pay_price" int NOT NULL,
-      "order_part_price" int NOT NULL,
-      "order_divide_price" int NOT NULL,
-      "after_sale_status" int NOT NULL,
-      "creator" varchar DEFAULT '',
-      "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-      "updater" varchar DEFAULT '',
-      "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-      "deleted" bit NOT NULL DEFAULT FALSE,
-      PRIMARY KEY ("id")
+CREATE TABLE IF NOT EXISTS "trade_order_item"
+(
+    "id"                bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "user_id"           bigint   NOT NULL,
+    "order_id"          bigint   NOT NULL,
+    "cart_id"           int      NULL,
+    "spu_id"            bigint   NOT NULL,
+    "spu_name"          varchar  NOT NULL,
+    "sku_id"            bigint   NOT NULL,
+    "properties"        varchar,
+    "pic_url"           varchar,
+    "count"             int      NOT NULL,
+    "comment_status"    boolean  NULL,
+    "price"             int      NOT NULL,
+    "discount_price"    int      NOT NULL,
+    "delivery_price"    int      NULL,
+    "adjust_price"      int      NULL,
+    "pay_price"         int      NOT NULL,
+    "coupon_price"      int      NULL,
+    "point_price"       int      NULL,
+    "use_point"         int      NULL,
+    "give_point"        int      NULL,
+    "vip_price"         int      NULL,
+    "after_sale_id"     long     NULL,
+    "after_sale_status" int      NOT NULL,
+    "creator"           varchar           DEFAULT '',
+    "create_time"       datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"           varchar           DEFAULT '',
+    "update_time"       datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted"           bit      NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
 ) COMMENT '交易订单明细表';
 
-CREATE TABLE IF NOT EXISTS "trade_after_sale" (
-    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    "no" varchar NOT NULL,
-    "status" int NOT NULL,
-    "type" int NOT NULL,
-    "way" int NOT NULL,
-    "user_id" bigint NOT NULL,
-    "apply_reason" varchar NOT NULL,
+CREATE TABLE IF NOT EXISTS "trade_after_sale"
+(
+    "id"             bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "no"             varchar  NOT NULL,
+    "status"         int      NOT NULL,
+    "type"           int      NOT NULL,
+    "way"            int      NOT NULL,
+    "user_id"        bigint   NOT NULL,
+    "apply_reason"   varchar  NOT NULL,
     "apply_description" varchar,
     "apply_pic_urls" varchar,
-    "order_id" bigint NOT NULL,
-    "order_no" varchar NOT NULL,
-    "order_item_id" bigint NOT NULL,
-    "spu_id" bigint NOT NULL,
-    "spu_name" varchar NOT NULL,
-    "sku_id" bigint NOT NULL,
-    "properties" varchar,
-    "pic_url" varchar,
-    "count" int NOT NULL,
-    "audit_time" varchar,
-    "audit_user_id" bigint,
-    "audit_reason" varchar,
-    "refund_price" int NOT NULL,
-    "pay_refund_id" bigint,
-    "refund_time" varchar,
-    "logistics_id" bigint,
-    "logistics_no" varchar,
-    "delivery_time" varchar,
-    "receive_time" varchar,
+    "order_id"       bigint   NOT NULL,
+    "order_no"       varchar  NOT NULL,
+    "order_item_id"  bigint   NOT NULL,
+    "spu_id"         bigint   NOT NULL,
+    "spu_name"       varchar  NOT NULL,
+    "sku_id"         bigint   NOT NULL,
+    "properties"     varchar,
+    "pic_url"        varchar,
+    "count"          int      NOT NULL,
+    "audit_time"     varchar,
+    "audit_user_id"  bigint,
+    "audit_reason"   varchar,
+    "refund_price"   int      NOT NULL,
+    "pay_refund_id"  bigint,
+    "refund_time"    varchar,
+    "logistics_id"   bigint,
+    "logistics_no"   varchar,
+    "delivery_time"  varchar,
+    "receive_time"   varchar,
     "receive_reason" varchar,
-    "creator" varchar DEFAULT '',
-    "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "updater" varchar DEFAULT '',
-    "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    "deleted" bit NOT NULL DEFAULT FALSE,
+    "creator"        varchar           DEFAULT '',
+    "create_time"    datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"        varchar           DEFAULT '',
+    "update_time"    datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted"        bit      NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '交易售后表';
 
-CREATE TABLE IF NOT EXISTS "trade_after_sale_log" (
-    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    "user_id" bigint NOT NULL,
-    "user_type" int NOT NULL,
-    "after_sale_id" bigint NOT NULL,
-    "order_id" bigint NOT NULL,
-    "order_item_id" bigint NOT NULL,
+CREATE TABLE IF NOT EXISTS "trade_after_sale_log"
+(
+    "id"            bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "user_id"       bigint   NOT NULL,
+    "user_type"     int      NOT NULL,
+    "after_sale_id" bigint   NOT NULL,
+    "order_id"      bigint   NOT NULL,
+    "order_item_id" bigint   NOT NULL,
     "before_status" int,
-    "after_status" int NOT NULL,
-    "content" varchar NOT NULL,
-    "creator" varchar DEFAULT '',
-    "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "updater" varchar DEFAULT '',
-    "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    "deleted" bit NOT NULL DEFAULT FALSE,
+    "after_status"  int      NOT NULL,
+    "content"       varchar  NOT NULL,
+    "creator"       varchar           DEFAULT '',
+    "create_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"       varchar           DEFAULT '',
+    "update_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted"       bit      NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '交易售后日志';
 
@@ -161,7 +188,7 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_record"
     "updater"       varchar           DEFAULT '',
     "update_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     "deleted"       bit      NOT NULL DEFAULT FALSE,
-    "tenant_id"      bigint   not null default '0',
+    "tenant_id" bigint not null default '0',
     PRIMARY KEY ("id")
 ) COMMENT '佣金记录';
 CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw"
@@ -186,6 +213,22 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw"
     "updater"             varchar           DEFAULT '',
     "update_time"         datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     "deleted"             bit      NOT NULL DEFAULT FALSE,
-    "tenant_id"      bigint   not null default '0',
+    "tenant_id" bigint not null default '0',
+    PRIMARY KEY ("id")
+) COMMENT '佣金提现';
+
+CREATE TABLE IF NOT EXISTS "trade_delivery_express"
+(
+    "id"          int      NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "code"        varchar  NULL,
+    "name"        varchar,
+    "logo"        varchar  NULL,
+    "sort"        int      NOT NULL,
+    "status"      int      NOT NULL,
+    "creator"     varchar           DEFAULT '',
+    "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"     varchar           DEFAULT '',
+    "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    "deleted"     bit      NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '佣金提现';

+ 7 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java

@@ -88,6 +88,12 @@ public class MemberAuthServiceImpl implements MemberAuthService {
         MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, getTerminal());
         Assert.notNull(user, "获取用户失败,结果为空");
 
+        // 校验是否禁用
+        if (CommonStatusEnum.isDisable(user.getStatus())) {
+            createLoginLog(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, LoginResultEnum.USER_DISABLED);
+            throw exception(AUTH_LOGIN_USER_DISABLED);
+        }
+
         // 如果 socialType 非空,说明需要绑定社交用户
         String openid = null;
         if (reqVO.getSocialType() != null) {
@@ -177,7 +183,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
             throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
         }
         // 校验是否禁用
-        if (ObjectUtil.notEqual(user.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+        if (CommonStatusEnum.isDisable(user.getStatus())) {
             createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED);
             throw exception(AUTH_LOGIN_USER_DISABLED);
         }

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java

@@ -109,7 +109,7 @@ public class AuthController {
         // 1.3 获得菜单列表
         Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
         List<MenuDO> menuList = menuService.getMenuList(menuIds);
-        menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
+        menuList = menuService.filterDisableMenus(menuList);
 
         // 2. 拼接结果返回
         return success(AuthConvert.INSTANCE.convert(user, roles, menuList));

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java

@@ -72,6 +72,7 @@ public class MenuController {
     public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() {
         List<MenuDO> list = menuService.getMenuListByTenant(
                 new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        list = menuService.filterDisableMenus(list);
         list.sort(Comparator.comparing(MenuDO::getSort));
         return success(BeanUtils.toBean(list, MenuSimpleRespVO.class));
     }

+ 8 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java

@@ -52,6 +52,14 @@ public interface MenuService {
      */
     List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO);
 
+    /**
+     * 过滤掉关闭的菜单及其子菜单
+     *
+     * @param list 菜单列表
+     * @return 过滤后的菜单列表
+     */
+    List<MenuDO> filterDisableMenus(List<MenuDO> list);
+
     /**
      * 筛选菜单列表
      *

+ 50 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java

@@ -1,6 +1,8 @@
 package cn.iocoder.yudao.module.system.service.permission;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
@@ -11,6 +13,7 @@ import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Lists;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
@@ -18,12 +21,11 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 
@@ -106,12 +108,57 @@ public class MenuServiceImpl implements MenuService {
 
     @Override
     public List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO) {
+        // 查询所有菜单,并过滤掉关闭的节点
         List<MenuDO> menus = getMenuList(reqVO);
         // 开启多租户的情况下,需要过滤掉未开通的菜单
         tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId())));
         return menus;
     }
 
+    @Override
+    public List<MenuDO> filterDisableMenus(List<MenuDO> menuList) {
+        if (CollUtil.isEmpty(menuList)){
+            return Collections.emptyList();
+        }
+        Map<Long, MenuDO> menuMap = convertMap(menuList, MenuDO::getId);
+
+        // 遍历 menu 菜单,查找不是禁用的菜单,添加到 enabledMenus 结果
+        List<MenuDO> enabledMenus = new ArrayList<>();
+        Set<Long> disabledMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索
+        for (MenuDO menu : menuList) {
+            if (isMenuDisabled(menu, menuMap, disabledMenuCache)) {
+                continue;
+            }
+            enabledMenus.add(menu);
+        }
+        return enabledMenus;
+    }
+
+    private boolean isMenuDisabled(MenuDO node, Map<Long, MenuDO> menuMap, Set<Long> disabledMenuCache) {
+        // 如果已经判定是禁用的节点,直接结束
+        if (disabledMenuCache.contains(node.getId())) {
+            return true;
+        }
+
+        // 1. 遍历到 parentId 为根节点,则无需判断
+        Long parentId = node.getParentId();
+        if (ObjUtil.equal(parentId, ID_ROOT)) {
+            if (CommonStatusEnum.isDisable(node.getStatus())) {
+                disabledMenuCache.add(node.getId());
+                return true;
+            }
+            return false;
+        }
+
+        // 2. 继续遍历 parent 节点
+        MenuDO parent = menuMap.get(parentId);
+        if (parent == null || isMenuDisabled(parent, menuMap, disabledMenuCache)) {
+            disabledMenuCache.add(node.getId());
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public List<MenuDO> getMenuList(MenuListReqVO reqVO) {
         return menuMapper.selectList(reqVO);