liusz 1 týždeň pred
rodič
commit
712a008500
78 zmenil súbory, kde vykonal 2984 pridanie a 1271 odobranie
  1. 2 1
      README.md
  2. 5 4
      py-app-starter/src/main/java/com/poyee/controller/EcologyGoodsController.java
  3. 5 3
      py-app-starter/src/main/resources/application.yml
  4. 15 0
      py-base/src/main/java/com/poyee/annotation/db/JdbcType.java
  5. 1 1
      py-base/src/main/java/com/poyee/annotation/ds/CustomTransactional.java
  6. 3 3
      py-base/src/main/java/com/poyee/aspectj/DataSourceAspect.java
  7. 13 0
      py-base/src/main/java/com/poyee/base/dto/Result.java
  8. 13 0
      py-base/src/main/java/com/poyee/base/mapper/provider/BaseProvider.java
  9. 9 0
      py-base/src/main/java/com/poyee/base/mapper/provider/IBaseProvider.java
  10. 117 0
      py-base/src/main/java/com/poyee/base/mapper/provider/util/DeleteUtil.java
  11. 25 0
      py-base/src/main/java/com/poyee/base/mapper/provider/util/InsertUtil.java
  12. 4 2
      py-base/src/main/java/com/poyee/base/mapper/provider/util/SelectUtil.java
  13. 49 2
      py-base/src/main/java/com/poyee/base/mapper/provider/util/SqlUtil.java
  14. 15 2
      py-base/src/main/java/com/poyee/base/mapper/provider/util/UpdateUtil.java
  15. 11 5
      py-base/src/main/java/com/poyee/datasource/DataSourceConfig.java
  16. 2 6
      py-base/src/main/java/com/poyee/datasource/DynamicDataSource.java
  17. 33 0
      py-base/src/main/java/com/poyee/datasource/enums/TransactionState.java
  18. 128 30
      py-base/src/main/java/com/poyee/datasource/handler/MybatisMetaObjectHandler.java
  19. 29 18
      py-base/src/main/java/com/poyee/datasource/holder/CustomTransactionAspect.java
  20. 93 0
      py-base/src/main/java/com/poyee/datasource/holder/CustomTransactionManager.java
  21. 25 8
      py-base/src/main/java/com/poyee/datasource/holder/TransactionManagerHolder.java
  22. 7 8
      py-base/src/main/java/com/poyee/framework/handler/MyRequestInterceptor.java
  23. 7 1
      py-base/src/main/java/com/poyee/util/ObjectUtil.java
  24. 5 0
      py-dao/src/main/java/com/poyee/mapper/EcologySkuMapper.java
  25. 4 0
      py-dao/src/main/java/com/poyee/mapper/EcologySpuMapper.java
  26. 4 0
      py-domain/src/main/java/com/poyee/dto/EcologySkuDto.java
  27. 5 1
      py-domain/src/main/java/com/poyee/dto/detail/EcologyGoodsDetailDto.java
  28. 127 0
      py-domain/src/main/java/com/poyee/dto/detail/EcologySkuDetailDto.java
  29. 113 0
      py-domain/src/main/java/com/poyee/dto/detail/EcologySpuDetailDto.java
  30. 1 1
      py-domain/src/main/java/com/poyee/dto/page/EcologyGoodsPageDto.java
  31. 94 0
      py-domain/src/main/java/com/poyee/dto/page/EcologySkuPageDto.java
  32. 92 0
      py-domain/src/main/java/com/poyee/dto/page/EcologySpuPageDto.java
  33. 19 0
      py-domain/src/main/java/com/poyee/dto/where/EcologySkuWhereReq.java
  34. 0 98
      py-domain/src/main/java/com/poyee/entity/EcologyCourierRecord.java
  35. 0 69
      py-domain/src/main/java/com/poyee/entity/EcologyGoodsConfig.java
  36. 0 110
      py-domain/src/main/java/com/poyee/entity/EcologyMerCustomize.java
  37. 0 211
      py-domain/src/main/java/com/poyee/entity/EcologyOrderInfo.java
  38. 0 119
      py-domain/src/main/java/com/poyee/entity/EcologyOrderInvoice.java
  39. 0 107
      py-domain/src/main/java/com/poyee/entity/EcologyOrderItem.java
  40. 0 150
      py-domain/src/main/java/com/poyee/entity/EcologySku.java
  41. 0 199
      py-domain/src/main/java/com/poyee/entity/EcologySpu.java
  42. 1 3
      py-domain/src/main/java/com/poyee/entity/SkuInsertDao.java
  43. 1 1
      py-domain/src/main/java/com/poyee/entity/SpuInsertDao.java
  44. 49 0
      py-domain/src/main/java/com/poyee/enums/EcologySpuStatusEnum.java
  45. 2 1
      py-domain/src/main/java/com/poyee/enums/GoodsQueryTypeEnums.java
  46. 1 3
      py-domain/src/main/java/com/poyee/req/EcologyGoodsBuyReq.java
  47. 4 1
      py-domain/src/main/java/com/poyee/req/EcologySkuReq.java
  48. 151 0
      py-domain/src/main/java/com/poyee/req/insert/EcologySkuInsertReq.java
  49. 146 0
      py-domain/src/main/java/com/poyee/req/insert/EcologySpuInsertReq.java
  50. 34 1
      py-domain/src/main/java/com/poyee/req/page/EcologyGoodsBuyPageReq.java
  51. 1 2
      py-domain/src/main/java/com/poyee/req/page/EcologyGoodsPageReq.java
  52. 32 0
      py-domain/src/main/java/com/poyee/req/page/EcologySkuPageReq.java
  53. 92 0
      py-domain/src/main/java/com/poyee/req/page/EcologySpuPageReq.java
  54. 47 0
      py-domain/src/main/java/com/poyee/req/update/EcologySkuDelReq.java
  55. 36 0
      py-domain/src/main/java/com/poyee/req/update/EcologySkuStockReq.java
  56. 41 0
      py-domain/src/main/java/com/poyee/req/update/EcologySkuUpReq.java
  57. 121 0
      py-domain/src/main/java/com/poyee/req/update/EcologySkuUpdateReq.java
  58. 47 0
      py-domain/src/main/java/com/poyee/req/update/EcologySpuDelReq.java
  59. 54 0
      py-domain/src/main/java/com/poyee/req/update/EcologySpuReviewReq.java
  60. 46 0
      py-domain/src/main/java/com/poyee/req/update/EcologySpuUpReq.java
  61. 64 0
      py-domain/src/main/java/com/poyee/req/update/EcologySpuUpdateReq.java
  62. 3 6
      py-feign-clients/src/main/java/com/poyee/feign/AdminFeignService.java
  63. 20 0
      py-feign-clients/src/main/java/com/poyee/feign/CheckListFeignService.java
  64. 151 5
      py-service/src/main/java/com/poyee/build/ProductBeanBuildFactory.java
  65. 5 4
      py-service/src/main/java/com/poyee/service/EcologyGoodsService.java
  66. 0 3
      py-service/src/main/java/com/poyee/service/IEcologyCourierRecordService.java
  67. 0 3
      py-service/src/main/java/com/poyee/service/IEcologyGoodsConfigService.java
  68. 0 3
      py-service/src/main/java/com/poyee/service/IEcologyOrderInvoiceService.java
  69. 0 3
      py-service/src/main/java/com/poyee/service/IEcologyOrderItemService.java
  70. 13 0
      py-service/src/main/java/com/poyee/service/IEcologySkuService.java
  71. 20 0
      py-service/src/main/java/com/poyee/service/IEcologySpuService.java
  72. 104 63
      py-service/src/main/java/com/poyee/service/impl/EcologyGoodsServiceImpl.java
  73. 141 0
      py-service/src/main/java/com/poyee/service/impl/EcologySkuServiceImpl.java
  74. 269 4
      py-service/src/main/java/com/poyee/service/impl/EcologySpuServiceImpl.java
  75. 76 2
      py-starter/src/main/java/com/poyee/controller/EcologySkuController.java
  76. 129 2
      py-starter/src/main/java/com/poyee/controller/EcologySpuController.java
  77. 4 2
      py-starter/src/main/resources/application.yml
  78. 4 0
      py-starter/src/main/resources/db/V1.0.11__ecology_sku_update.sql

+ 2 - 1
README.md

@@ -33,4 +33,5 @@
 > 
       
 ### 接口文档
-> http://localhost:8080/doc.html </br>
+> app http://localhost:8087/doc.html </br>
+> admin http://localhost:8086/doc.html </br>

+ 5 - 4
py-app-starter/src/main/java/com/poyee/controller/EcologyGoodsController.java

@@ -8,11 +8,12 @@ import com.poyee.base.dto.Result;
 import com.poyee.common.enums.BusinessType;
 import com.poyee.common.enums.Roles;
 import com.poyee.dto.EcologyMerCustomizeDto;
-import com.poyee.dto.goods.EcologyGoodsPageDto;
+import com.poyee.dto.detail.EcologyGoodsDetailDto;
+import com.poyee.dto.page.EcologyGoodsPageDto;
 import com.poyee.dto.permission.CheckMerPermissionDto;
 import com.poyee.req.EcologyMerCustomizeReq;
-import com.poyee.req.goods.EcologyGoodsBuyPageReq;
-import com.poyee.req.goods.EcologyGoodsPageReq;
+import com.poyee.req.page.EcologyGoodsBuyPageReq;
+import com.poyee.req.page.EcologyGoodsPageReq;
 import com.poyee.service.EcologyGoodsService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -84,7 +85,7 @@ public class EcologyGoodsController extends BaseController<EcologyGoodsService,
     @GetMapping("/buyTop")
     @UserLoginToken( roles = {Roles.ADMIN, Roles.SHIPPING} )
     @ResponseBody
-    public Result<EcologyGoodsPageDto> buyTop() {
+    public Result<EcologyGoodsDetailDto> buyTop() {
         console("获取单个求购令商品 [top 排名最高的]", "");
         return baseService.buyTop();
     }

+ 5 - 3
py-app-starter/src/main/resources/application.yml

@@ -38,6 +38,8 @@ logging:
 
 
 # 商家用户信息服务URL配置
-mer-user-info:
-  service:
-    url: http://localhost
+feign:
+  admin-service:
+    url: http://localhost
+  checklist-service:
+    url: http://localhost:8084

+ 15 - 0
py-base/src/main/java/com/poyee/annotation/db/JdbcType.java

@@ -0,0 +1,15 @@
+package com.poyee.annotation.db;
+
+import com.poyee.enums.FieldType;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface JdbcType {
+
+    //字段类型
+    FieldType columnType() default FieldType.STRING;
+
+}

+ 1 - 1
py-base/src/main/java/com/poyee/annotation/ds/Transactional.java → py-base/src/main/java/com/poyee/annotation/ds/CustomTransactional.java

@@ -12,7 +12,7 @@ import java.lang.annotation.*;
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-public @interface Transactional {
+public @interface CustomTransactional {
 
     Propagation propagation() default Propagation.REQUIRED;
 

+ 3 - 3
py-base/src/main/java/com/poyee/aspectj/DataSourceAspect.java

@@ -2,7 +2,7 @@ package com.poyee.aspectj;
 
 import com.poyee.annotation.ds.DataSource;
 import com.poyee.datasource.DynamicDataSource;
-import com.poyee.datasource.holder.DataSourceContextHolder;
+import com.poyee.datasource.holder.TransactionManagerHolder;
 import com.poyee.util.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.ProceedingJoinPoint;
@@ -82,13 +82,13 @@ public class DataSourceAspect {
             log.info("Switching to data source: {}", name);
 
             dynamicDataSource.initDataSource(name);
-            DataSourceContextHolder.setDataSource(name);
+            TransactionManagerHolder.setDataSourceKey(name);
         }
 
         try {
             return point.proceed();
         } finally {
-            DataSourceContextHolder.clearDataSource();
+            TransactionManagerHolder.clear();
         }
     }
 

+ 13 - 0
py-base/src/main/java/com/poyee/base/dto/Result.java

@@ -84,6 +84,19 @@ public class Result<T> {
         return result;
     }
 
+    /**
+     * @param data
+     * @param <T>
+     * @return
+     */
+    public static <T> Result<T> success(Integer code, Object data) {
+        Result<T> result = new Result<>();
+        result.setCode(code);
+        result.setMsg(ResultCode.SUCCESS.getMsg());
+        result.setData(data);
+        return result;
+    }
+
     /**
      * @param rows
      * @param <T>

+ 13 - 0
py-base/src/main/java/com/poyee/base/mapper/provider/BaseProvider.java

@@ -37,6 +37,8 @@ public abstract class BaseProvider {
     public Object update;
     // 记录 SELECT
     public Object select;
+    // 存储 delete
+    public Object delete;
     // 请求对象
     public Object req;
     // 返回对象
@@ -170,6 +172,17 @@ public abstract class BaseProvider {
         throw new ServiceException("传入的对象为空!");
     }
 
+    public String delete(Object object){
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.DELETE;
+            DeleteUtil.init(this).initDelete(object);
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).toSql();
+        }
+        throw new ServiceException("传入的对象为空!");
+    }
+
     /**
      *
      * @param object

+ 9 - 0
py-base/src/main/java/com/poyee/base/mapper/provider/IBaseProvider.java

@@ -112,6 +112,15 @@ public interface IBaseProvider<T extends BaseReq, R extends BaseDto> {
     @UpdateProvider(type = FinalProviderSql.class, method = "update")
     int update(T req);
 
+
+    /**
+     * 根据条件物理删除
+     * @param req
+     * @return
+     */
+    @DeleteProvider(type = FinalProviderSql.class, method = "delete")
+    int deleteByReq(T req);
+
     /**
      * 根据id查询
      * @param id

+ 117 - 0
py-base/src/main/java/com/poyee/base/mapper/provider/util/DeleteUtil.java

@@ -0,0 +1,117 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.alibaba.excel.util.StringUtils;
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.TableInfo;
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.DbMethodEnums;
+import com.poyee.enums.FieldOperator;
+import com.poyee.util.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.poyee.base.mapper.provider.ErrMessageContent.*;
+
+@Slf4j
+public class DeleteUtil {
+
+    private BaseProvider parent;
+
+    private DeleteUtil(BaseProvider parent) {
+        this.parent = parent;
+    }
+
+    public static DeleteUtil init(BaseProvider parent) {
+        return new DeleteUtil(parent);
+    }
+
+    public void initDelete(Object object) {
+        if(Objects.isNull(object)){
+            log.warn("传入的对象为空!");
+            throw new ServiceException(ERROR_MESSAGE_OBJECT_IS_NULL);
+        }
+        Class<?> aClass = object.getClass();
+        if(!aClass.isAnnotationPresent(TableName.class)){
+            log.warn("对象必须包含@TableName注解");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_MISSING_2);
+        }
+        TableName tableNameAnnotation = aClass.getAnnotation(TableName.class);
+        if(Objects.isNull(tableNameAnnotation.value()) || tableNameAnnotation.value().trim().isEmpty()){
+            log.warn("表名不能为空");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_IS_NULL);
+        }
+
+        // 初始化表信息
+        TableInfo tableInfo = TableInfoUtil.init(parent)
+                                           .initTableInfo(aClass);
+        parent.superTable = tableInfo;
+        parent.delete = object;
+        try {
+            //设置where 条件
+            processFields(object);
+
+        } catch (IllegalAccessException e) {
+            log.error("访问字段时发生错误", e);
+            throw new ServiceException(ERROR_MESSAGE_FIELD_ACCESS);
+        } catch (IllegalArgumentException e) {
+            log.error("非法参数错误", e);
+            throw new ServiceException(ERROR_MESSAGE_ILLEGAL_ARGUMENT);
+        } catch (Exception e) {
+            log.error(getErrorMessage(ERROR_MESSAGE_BUILD_SQL,"更新"), e);
+            throw new ServiceException(getErrorMessage(ERROR_MESSAGE_BUILD_SQL,"更新"));
+        }
+    }
+    /**
+     * 处理字段并填充到映射中
+     *
+     * @param object    对象
+     * @throws IllegalAccessException 如果字段访问失败
+     */
+    private void processFields(Object object) throws IllegalAccessException {
+        Class<?> aClass = object.getClass();
+        Field[] declaredFields = aClass.getDeclaredFields();
+
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            // 获取字段注解
+            if(field.isAnnotationPresent(Where.class)) {
+                //设置where 条件
+                Where where = field.getAnnotation(Where.class);
+                try {
+                    Object value = field.get(object);
+                    // 根据 Where 注解配置和字段值,决定是否创建 WHERE 信息
+                    if ( (value instanceof String && StringUtils.isNotBlank(String.valueOf(value)))
+                            || (!(value instanceof String) && Objects.nonNull(value))
+                            || FieldOperator.checkEmptyValue(where)) {
+                        Class<?> table = where.table();
+                        String tableName = parent.classAlias.get(table);
+                        // 确保表信息已初始化
+                        if (StringUtils.isBlank(tableName ) || !parent.tableInfos.containsKey(tableName)) {
+                            TableInfoUtil.init(parent).initTableInfo(table);
+                            tableName = parent.classAlias.get(table);
+                        }
+                        WhereInfo whereInfo = new WhereInfo(parent.tableInfos.get(tableName));
+                        whereInfo.setColumn(where.field());
+                        whereInfo.setValue(value);
+                        whereInfo.setOperator(where.operator());
+                        whereInfo.setFieldType(where.columnType());
+                        parent.whereInfos.add(whereInfo);
+                    }
+                } catch (IllegalAccessException e) {
+                    throw new ServiceException("无法访问字段:" + field.getName(), e);
+                }
+            }
+        }
+    }
+
+}

+ 25 - 0
py-base/src/main/java/com/poyee/base/mapper/provider/util/InsertUtil.java

@@ -1,13 +1,16 @@
 package com.poyee.base.mapper.provider.util;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.JdbcType;
 import com.poyee.base.mapper.provider.BaseProvider;
 import com.poyee.common.exception.ServiceException;
 import com.poyee.enums.DbMethodEnums;
 import com.poyee.util.DateUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 
 import java.lang.reflect.Field;
 import java.util.Date;
@@ -202,6 +205,28 @@ public class InsertUtil {
                             insertMap.put(tableField.value(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, (Date) value));
                         }else{
                             insertMap.put(tableField.value(), value);
+                            //判断是否有 JdbcType 注解 如果有则需要转换为指定类型
+                            if (field.isAnnotationPresent(JdbcType.class)) {
+                                JdbcType jdbcType = field.getAnnotation(JdbcType.class);
+                                switch (jdbcType.columnType()) {
+                                    case DATE:
+                                        insertMap.put(tableField.value(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, (Date) value));
+                                        break;
+                                    case JSONB:
+                                        if (value instanceof String) {
+                                            if(StringUtils.isNotBlank(String.valueOf(value))){
+                                                value = value+"::jsonb";
+                                                insertMap.put(tableField.value(), value);
+                                            }else{
+                                                //值为空时删除字段
+                                                insertMap.remove(tableField.value());
+                                            }
+                                        }else{
+                                            insertMap.put(tableField.value(), JSONObject.toJSONString(value)+"::jsonb");
+                                        }
+                                        break;
+                                }
+                            }
                         }
                     }
                 }

+ 4 - 2
py-base/src/main/java/com/poyee/base/mapper/provider/util/SelectUtil.java

@@ -196,7 +196,7 @@ public class SelectUtil {
                             sort = sortField.get(req).toString();
                         }
                         //获取返回类的字段的 表的别名
-                        Class<?> resClass = res.getClass();
+                        Class<?> resClass = (Class<?>) res;
                         Field declaredField = resClass.getDeclaredField(String.valueOf(sidxObj));
                         String alias = parent.superTable.getAlias();
                         if(Objects.nonNull(declaredField)){
@@ -237,7 +237,9 @@ public class SelectUtil {
                                 }
                             }
                         }
-                        parent.orderByMap.put(Objects.equals(sort,"desc") ? -1 : 0 ,alias +"."+ String.valueOf(sidxObj));
+                        String sidxStr = alias + "." + sidxObj;
+                        boolean desc = Objects.equals(sort, "desc");
+                        parent.orderByMap.put( desc ? -1 : 0 , desc ? sidxStr  + " desc " : sidxStr );
                     }
                 }catch (NoSuchFieldException | IllegalAccessException e) {
                     throw new RuntimeException(e);

+ 49 - 2
py-base/src/main/java/com/poyee/base/mapper/provider/util/SqlUtil.java

@@ -64,6 +64,9 @@ public class SqlUtil {
             case UPDATE:
                 sqlString = buildUpdateSql();
                 break;
+            case DELETE:
+                sqlString = buildDeleteSql();
+                break;
             default:
                 log.warn("No select columns or parent is null, returning empty SQL.");
                 throw new ServiceException("No select columns or parent is null.");
@@ -127,6 +130,50 @@ public class SqlUtil {
         }
     }
 
+
+    /**
+     * 构建删除 SQL 语句
+     * @return
+     */
+    private String buildDeleteSql() {
+        // 非空检查
+        if (parent == null ) {
+            log.warn("Parent is null or empty, returning empty SQL.");
+            throw new ServiceException("Parent is null or empty.");
+        }
+
+        if ( parent.whereInfos == null || parent.whereInfos.isEmpty() ) {
+            log.warn("No where condition found.");
+            throw new ServiceException("No where condition found.");
+        }
+
+        if (parent.superTable == null || parent.superTable.getTableName() == null || parent.superTable.getTableName().isEmpty()) {
+            log.warn("Super table or table name is null or empty, returning empty SQL.");
+            throw new ServiceException("Super table or table name is null or empty.");
+        }
+
+
+        try {
+            // 构建 SQL 字符串
+            StringBuilder sql = new StringBuilder();
+            sql.append("DELETE from ")
+               .append(parent.superTable.getTableName())
+               .append(" ");
+            //判断where 是否有值
+            appendWhereClauses(sql);
+            //判断是否有条件
+            if(!sql.toString().contains(" WHERE ")){
+                log.warn("No where condition found.");
+                throw new ServiceException("No where condition found.");
+            }
+            return sql.toString();
+        } catch (Exception e) {
+            log.error("Error building update SQL. Parent: {}, where: {} ", parent, parent.whereInfos,  e);
+            throw new ServiceException("Error building update SQL.", e);
+        }
+
+    }
+
     /**
      * 构建更新 SQL 语句
      * @return
@@ -391,8 +438,8 @@ public class SqlUtil {
         // 使用StringBuilder来构建WHERE子句
         StringBuilder clause = new StringBuilder();
         // 添加表别名和列名到WHERE子句中
-        //如果是更新 则不加别名
-        if(parent.dbMethod == DbMethodEnums.UPDATE){
+        //如果是更新|删除 则不加别名
+        if(parent.dbMethod == DbMethodEnums.UPDATE || parent.dbMethod == DbMethodEnums.DELETE){
             clause.append(whereInfo.getColumn())
                   .append(" ")
                   .append(whereInfo.getOperator().getOperator())

+ 15 - 2
py-base/src/main/java/com/poyee/base/mapper/provider/util/UpdateUtil.java

@@ -13,6 +13,7 @@ import com.poyee.common.exception.ServiceException;
 import com.poyee.enums.DbMethodEnums;
 import com.poyee.enums.FieldOperator;
 import com.poyee.util.DateUtils;
+import com.poyee.util.ServletUtils;
 import lombok.extern.slf4j.Slf4j;
 
 import java.lang.reflect.Field;
@@ -121,11 +122,23 @@ public class UpdateUtil {
                     }
                     //判断是否需要设置 创建,更新时间
                     if ( Objects.equals(parent.dbMethod, DbMethodEnums.UPDATE)
-                        && Objects.equals(tableField.fill() , FieldFill.INSERT_UPDATE)
-                        && Objects.equals(field.getName(), "updateTime")
+                        && (Objects.equals(tableField.fill() , FieldFill.INSERT_UPDATE) || Objects.equals(tableField.fill() , FieldFill.UPDATE))
+                        && field.getType() == Date.class
                         ) {
                         updateMap.put(tableField.value(), new Date());
                     }
+
+                    //判断是否需要设置 操作人
+                    if ( Objects.equals(parent.dbMethod, DbMethodEnums.UPDATE)
+                            && (Objects.equals(tableField.fill() , FieldFill.INSERT_UPDATE) || Objects.equals(tableField.fill() , FieldFill.UPDATE))
+                            && field.getType() == String.class && (field.getName().contains("User") || field.getName().contains("By"))
+                    ) {
+                        try {
+                            updateMap.put(tableField.value(), ServletUtils.getUserInfo().getId());
+                        }catch (Exception e) {
+                            log.warn("设置操作人失败");
+                        }
+                    }
                 }else if (field.isAnnotationPresent(TableId.class)) {
                     TableId tableId = field.getAnnotation(TableId.class);
                     Object value = field.get(object);

+ 11 - 5
py-base/src/main/java/com/poyee/datasource/DataSourceConfig.java

@@ -11,6 +11,8 @@ import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import com.github.yulichang.injector.MPJSqlInjector;
 import com.github.yulichang.interceptor.MPJInterceptor;
 import com.poyee.datasource.common.DbInitUtil;
+import com.poyee.datasource.handler.MybatisMetaObjectHandler;
+import com.poyee.datasource.holder.CustomTransactionManager;
 import com.poyee.datasource.modal.DbConfigModal;
 import com.poyee.util.ParseUtil;
 import lombok.extern.slf4j.Slf4j;
@@ -19,6 +21,7 @@ import org.apache.ibatis.session.SqlSessionFactory;
 import org.jetbrains.annotations.Nullable;
 import org.mybatis.spring.annotation.MapperScan;
 import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
+import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
@@ -36,7 +39,6 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
 import org.springframework.core.type.classreading.MetadataReader;
 import org.springframework.core.type.classreading.MetadataReaderFactory;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.CollectionUtils;
 
@@ -122,11 +124,12 @@ public class DataSourceConfig {
      */
     @Bean("masterDataSource")
     @Primary
-    @Qualifier("masterDataSource")
+//    @Qualifier("masterDataSource")
     @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.master")
     public DruidDataSource dataSource() {
         //注册时 使用多数据源中 的master数据源 配置
         DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+//        dataSource.setDefaultAutoCommit(false);
         return dataSource;
     }
 
@@ -153,6 +156,8 @@ public class DataSourceConfig {
         sessionFactory.setGlobalConfig(globalConfig);
         //加载插件
         sessionFactory.setPlugins(mybatisPlusInterceptor(), new MPJInterceptor());
+        // 关键:使用Spring管理的事务
+        sessionFactory.setTransactionFactory(new SpringManagedTransactionFactory());
         return sessionFactory.getObject();
     }
     @Bean
@@ -167,7 +172,7 @@ public class DataSourceConfig {
      * @return
      */
     @Bean(name = "dynamicDataSource")
-    @Qualifier("dynamicDataSource")
+//    @Qualifier("dynamicDataSource")
     public DynamicDataSource dynamicDataSource() {
         DynamicDataSource dynamicDataSource = new DynamicDataSource();
         //配置缺省的数据源
@@ -259,6 +264,7 @@ public class DataSourceConfig {
         datasource.setRemoveAbandoned(true); //是否移除泄露的连接/超过时间限制是否回收。
         datasource.setRemoveAbandonedTimeout(3600); //泄露连接的定义时间(要超过最大事务的处理时间);单位为秒。这里配置为1小时
         datasource.setLogAbandoned(true); ////移除泄露连接发生是是否记录日志
+//        datasource.setDefaultAutoCommit(false);//设置为false,默认是true 是否自动提交事务
         return datasource;
     }
 
@@ -270,7 +276,7 @@ public class DataSourceConfig {
      */
     @Bean("masterTransactionManager")
     @Primary
-    public PlatformTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
+    public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
         return new DataSourceTransactionManager(dataSource);
     }
 
@@ -279,7 +285,7 @@ public class DataSourceConfig {
      * 推荐与 @DS 注解配合使用,能感知数据源切换
      */
     @Bean("dynamicTransactionManager")
-    public PlatformTransactionManager dynamicTransactionManager( @Qualifier("dynamicDataSource") DataSource dataSource) {
+    public DataSourceTransactionManager dynamicTransactionManager( @Qualifier("dynamicDataSource") DataSource dataSource) {
         return new DataSourceTransactionManager(dataSource);
     }
 

+ 2 - 6
py-base/src/main/java/com/poyee/datasource/DynamicDataSource.java

@@ -4,17 +4,13 @@ import com.alibaba.druid.pool.DruidDataSource;
 import com.alibaba.druid.stat.DruidDataSourceStatManager;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
-import com.poyee.datasource.holder.DataSourceContextHolder;
 import com.poyee.datasource.holder.TransactionManagerHolder;
 import com.poyee.datasource.modal.DataSourceInfoModal;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationContext;
 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
-import org.springframework.transaction.PlatformTransactionManager;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
@@ -49,7 +45,7 @@ public class DynamicDataSource extends AbstractRoutingDataSource {
      */
     @Override
     protected Object determineCurrentLookupKey() {
-        String dataSource = DataSourceContextHolder.getDataSource();
+        String dataSource = TransactionManagerHolder.getDataSourceKey();
         log.info("当前数据源为:{}", dataSource);
         if (StringUtils.isNotBlank(dataSource)) {
             if (CollectionUtils.isEmpty(targetDataSources) || !targetDataSources.containsKey(dataSource)) {
@@ -233,7 +229,7 @@ public class DynamicDataSource extends AbstractRoutingDataSource {
             dataSource = "master";
         }
         log.info("🔧 初始化数据源: {}", dataSource);
-        DataSourceContextHolder.setDataSource(dataSource); // 设置默认数据源
+        TransactionManagerHolder.setDataSourceKey(dataSource); // 设置默认数据源
         return dataSource;
     }
 

+ 33 - 0
py-base/src/main/java/com/poyee/datasource/enums/TransactionState.java

@@ -0,0 +1,33 @@
+package com.poyee.datasource.enums;
+
+public enum TransactionState {
+    /**
+     * 事务已开始但未进行任何操作
+     */
+    ACTIVE,
+
+    /**
+     * 事务已标记为提交
+     */
+    COMMITTING,
+
+    /**
+     * 事务已标记为回滚
+     */
+    ROLLING_BACK,
+
+    /**
+     * 事务已提交
+     */
+    COMMITTED,
+
+    /**
+     * 事务已回滚
+     */
+    ROLLED_BACK,
+
+    /**
+     * 事务状态未知
+     */
+    UNKNOWN
+}

+ 128 - 30
py-base/src/main/java/com/poyee/datasource/handler/MybatisMetaObjectHandler.java

@@ -1,55 +1,153 @@
 package com.poyee.datasource.handler;
 
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 import com.poyee.util.ServletUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.list.TreeList;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.ibatis.reflection.MetaObject;
 import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 
 @Slf4j
 @Component
 public class MybatisMetaObjectHandler implements MetaObjectHandler {
+    
+    // 缓存类的字段信息,提高性能
+    private static final ConcurrentHashMap<Class<?>, List<FieldInfo>> FIELD_INFO_CACHE = new ConcurrentHashMap<>();
+
     @Override
     public void insertFill(MetaObject metaObject) {
-        this.setFieldValByName("createTime", new Date(), metaObject);
-        this.setFieldValByName("updateTime", new Date(), metaObject);
-        try {
-            this.setFieldValByName("createBy", ServletUtils.getUserInfo().getId(), metaObject);
-        } catch (Exception e) {
-            log.info(" 自动填充操作人【createBy】失败! ");
-        }
-        try {
-            this.setFieldValByName("updateBy", ServletUtils.getUserInfo().getId(), metaObject);
-        }catch (Exception e) {
-            log.info(" 自动填充操作人【updateBy】失败! ");
-        }
-        try {
-            this.setFieldValByName("createUser", ServletUtils.getUserInfo().getId(), metaObject);
-        } catch (Exception e) {
-            log.info(" 自动填充操作人【createUser】失败! ");
-        }
-        try {
-            this.setFieldValByName("updateUser", ServletUtils.getUserInfo().getId(), metaObject);
-        }catch (Exception e) {
-            log.info(" 自动填充操作人【updateUser】失败! ");
+        Class<?> entityClass = metaObject.getOriginalObject().getClass();
+        List<FieldInfo> fieldInfos = getFieldInfo(entityClass);
+
+        if(CollectionUtils.isNotEmpty(fieldInfos)){
+            for(FieldInfo fieldInfo : fieldInfos){
+                // 设置创建,更新时间
+                Date now = new Date();
+                if (Objects.nonNull(fieldInfo.timeField)) {
+                    this.strictUpdateFill(metaObject, fieldInfo.timeField.getName(), Date.class, now);
+                }
+
+                // 设置 创建 ,更新操作人
+                try {
+                    Object userId = ServletUtils.getUserInfo().getId();
+                    if (Objects.nonNull(fieldInfo.userField)) {
+                        this.strictUpdateFill(metaObject, fieldInfo.userField.getName(), (Class) fieldInfo.userField.getType(), userId);
+                    }
+                } catch (Exception e) {
+                    log.debug("自动填充更新人信息失败: {}", e.getMessage());
+                }
+            }
         }
 
     }
 
     @Override
     public void updateFill(MetaObject metaObject) {
-        this.setFieldValByName("updateTime", new Date(), metaObject);
-        try {
-            this.setFieldValByName("updateBy", ServletUtils.getUserInfo().getId(), metaObject);
-        } catch (Exception e) {
-            log.info(" 自动填充操作人【updateBy】失败! ");
+        Class<?> entityClass = metaObject.getOriginalObject().getClass();
+        List<FieldInfo> fieldInfos = getFieldInfo(entityClass);
+
+        if(CollectionUtils.isNotEmpty(fieldInfos)){
+            for(FieldInfo fieldInfo : fieldInfos){
+                // 只更新时间
+                Date now = new Date();
+                if (Objects.nonNull(fieldInfo.timeField)) {
+                    this.strictUpdateFill(metaObject, fieldInfo.timeField.getName(), Date.class, now);
+                }
+
+                // 更新人
+                try {
+                    Object userId = ServletUtils.getUserInfo().getId();
+                    if (Objects.nonNull(fieldInfo.userField)) {
+                        this.strictUpdateFill(metaObject, fieldInfo.userField.getName(), (Class) fieldInfo.userField.getType(), userId);
+                    }
+                } catch (Exception e) {
+                    log.debug("自动填充更新人信息失败: {}", e.getMessage());
+                }
+
+            }
         }
-        try {
-            this.setFieldValByName("updateBy", ServletUtils.getUserInfo().getId(), metaObject);
-        } catch (Exception e) {
-            log.info(" 自动填充操作人【updateUser】失败! ");
+    }
+    
+    /**
+     * 获取实体类的字段信息
+     * @param clazz 实体类
+     * @return 字段信息
+     */
+    private List<FieldInfo> getFieldInfo(Class<?> clazz) {
+        return FIELD_INFO_CACHE.computeIfAbsent(clazz, this::analyzeClass);
+    }
+    
+    /**
+     * 分析类的字段信息
+     * @param clazz 实体类
+     * @return 字段信息
+     */
+    private List<FieldInfo> analyzeClass(Class<?> clazz) {
+        List<FieldInfo> fieldInfos = new TreeList();
+        fieldInfos.add(0,new FieldInfo());
+        // 遍历所有字段(包括父类字段)
+        Class<?> currentClass = clazz;
+        while (currentClass != null && !ClassUtils.isAssignable(currentClass, Object.class)) {
+            Field[] fields = currentClass.getDeclaredFields();
+            for (Field field : fields) {
+                if (field.isAnnotationPresent(TableField.class)) {
+                    TableField tableField = field.getAnnotation(TableField.class);
+                    FieldFill fill = tableField.fill();
+                    FieldInfo fieldInfo = fieldInfos.get(0);
+                    // 根据fill属性分类字段
+                    if (fill == FieldFill.INSERT || fill == FieldFill.UPDATE
+                            || fill == FieldFill.INSERT_UPDATE) {
+                        if (isDateField(field) && fieldInfo.timeField == null) {
+                            fieldInfo.timeField = field;
+                        }else if(isDateField(field) && Objects.nonNull(fieldInfo.timeField )){
+                            fieldInfos.add(0,new FieldInfo());
+                            fieldInfos.get(0).timeField = field;
+                        }
+                        if (isUserField(field) && fieldInfo.userField == null) {
+                            fieldInfo.userField = field;
+                        }else if(isUserField(field) && Objects.nonNull(fieldInfo.userField)){
+                            fieldInfos.add(0,new FieldInfo());
+                            fieldInfos.get(0).userField = field;
+                        }
+                    }
+                }
+            }
+            currentClass = currentClass.getSuperclass();
         }
+        return fieldInfos;
+    }
+    
+    /**
+     * 判断字段是否为日期类型
+     */
+    private boolean isDateField(Field field) {
+        return ClassUtils.isAssignable(field.getType(), Date.class);
+    }
+    
+    /**
+     * 判断字段是否为用户相关字段
+     */
+    private boolean isUserField(Field field) {
+        String fieldName = field.getName().toLowerCase();
+        return fieldName.contains("user") || fieldName.contains("by");
+    }
+    
+    /**
+     * 字段信息类
+     */
+    private static class FieldInfo {
+        Field timeField;
+        Field userField;
     }
 }

+ 29 - 18
py-base/src/main/java/com/poyee/datasource/holder/CustomTransactionAspect.java

@@ -1,14 +1,14 @@
 package com.poyee.datasource.holder;
 
-import com.poyee.annotation.ds.Transactional;
+import com.poyee.annotation.ds.CustomTransactional;
 import com.poyee.framework.handler.MyRequestInterceptor;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.springframework.core.annotation.Order;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.TransactionException;
 import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
@@ -22,7 +22,7 @@ import java.util.List;
 /**
  * 自定义事务切面(AOP 实现)
  * <p>
- * 该切面用于拦截带有 {@link com.poyee.annotation.ds.Transactional} 注解的方法,
+ * 该切面用于拦截带有 {@link com.poyee.annotation.ds.CustomTransactional} 注解的方法,
  * 并为其开启事务控制。与 Spring 原生 @Transactional 不同的是:
  * - 它使用线程上下文绑定的动态事务管理器(来自 {@link TransactionManagerHolder})
  * - 支持多数据源场景下的事务切换
@@ -41,7 +41,7 @@ public class CustomTransactionAspect {
      * 环绕通知:拦截所有标记了 @Transactional 的方法
      *
      * @param joinPoint    切入点,代表目标方法的执行上下文
-     * @param transactional 方法上的自定义事务注解,可用于读取事务属性(当前未扩展)
+     * @param customTransactional 方法上的自定义事务注解,可用于读取事务属性(当前未扩展)
      * @return 目标方法执行结果
      * @throws Throwable 方法执行异常或事务处理失败时抛出
      *
@@ -55,20 +55,22 @@ public class CustomTransactionAspect {
      * 6. 清理事务资源
      * </pre>
      */
-    @Around("@annotation(transactional)")
-    public Object manageTransaction(ProceedingJoinPoint joinPoint, Transactional transactional) throws Throwable {
+    @Around("@annotation(customTransactional)")
+    public Object manageTransaction(ProceedingJoinPoint joinPoint, CustomTransactional customTransactional) throws Throwable {
         // 从线程上下文中获取当前事务管理器(由 MyRequestInterceptor 设置)
-        PlatformTransactionManager tm = TransactionManagerHolder.getTransactionManager();
+        DataSourceTransactionManager tm = TransactionManagerHolder.getTransactionManager();
         if (tm == null) {
             throw new IllegalStateException("当前线程未绑定事务管理器,请检查是否在拦截器中正确设置");
         }
 
         // 定义事务属性
-        TransactionAttribute txAttr = createTransactionAttribute(transactional);
+        TransactionAttribute txAttr = createTransactionAttribute(customTransactional);
 
         // 开启事务
         TransactionStatus status = tm.getTransaction(txAttr);
-
+        if (status.isRollbackOnly()) {
+            log.warn("⚠️  事务已被标记为回滚,将执行回滚操作");
+        }
         try {
             // 执行业务逻辑
             Object result = invokeInTransaction(joinPoint, tm, status);
@@ -90,7 +92,7 @@ public class CustomTransactionAspect {
     /**
      * 创建事务属性(参考 RuleBasedTransactionAttribute)
      */
-    private TransactionAttribute createTransactionAttribute(Transactional ann) {
+    private TransactionAttribute createTransactionAttribute(CustomTransactional ann) {
         RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();
 
         // 设置传播行为
@@ -100,7 +102,7 @@ public class CustomTransactionAspect {
         attr.setIsolationLevel(ann.isolation().value());
 
         // 设置只读
-        attr.setReadOnly(ann.readOnly());
+//        attr.setReadOnly(ann.readOnly());
 
         // 设置超时
         if (ann.timeout() >= 0) {
@@ -135,7 +137,7 @@ public class CustomTransactionAspect {
     /**
      * 在事务中执行目标方法(类似 TransactionTemplate.doExecute)
      */
-    private Object invokeInTransaction(ProceedingJoinPoint jp, PlatformTransactionManager tm, TransactionStatus status) throws Throwable {
+    private Object invokeInTransaction(ProceedingJoinPoint jp, DataSourceTransactionManager tm, TransactionStatus status) throws Throwable {
         try {
             log.debug("✅ 开始执行事务内业务逻辑 [{}]", status);
             return jp.proceed();
@@ -152,7 +154,7 @@ public class CustomTransactionAspect {
     /**
      * 成功时提交事务(参考 AbstractPlatformTransactionManager.commit())
      */
-    private void commitTransactionAfterReturning(PlatformTransactionManager tm, TransactionStatus status) {
+    private void commitTransactionAfterReturning(DataSourceTransactionManager tm, TransactionStatus status) {
         if (status != null && !status.isCompleted()) {
             if (status.isNewTransaction()) {
                 log.debug(" committing new transaction");
@@ -166,17 +168,26 @@ public class CustomTransactionAspect {
     /**
      * 异常时回滚事务(参考 AbstractPlatformTransactionManager.rollback())
      */
-    private void rollbackOnException(PlatformTransactionManager tm, TransactionStatus status, Exception ex) {
+    private void rollbackOnException(DataSourceTransactionManager tm, TransactionStatus status, Throwable ex) {
         if (status != null && !status.isCompleted()) {
             try {
                 log.error("❌ 事务执行失败,准备回滚: {}", ex.getMessage(), ex);
+                log.debug("事务状态详情 - isNewTransaction: {}, isCompleted: {}, hasSavepoint: {}", 
+                         status.isNewTransaction(), status.isCompleted(), status.hasSavepoint());
+                
+                // 记录回滚前的数据状态
+                log.debug("准备执行回滚操作...");
                 tm.rollback(status);
-                log.debug(" rollback completed");
+                log.info("✅ 事务已成功回滚");
+                
+                // 验证回滚后状态
+                log.debug("回滚后事务状态 - isCompleted: {}", status.isCompleted());
             } catch (TransactionException tex) {
-                log.error(" rollback exception", tex);
+                log.error("❌ 事务回滚过程中发生异常", tex);
             }
         } else {
-            log.warn("Cannot rollback because transaction is already completed or null");
+            log.warn("无法回滚事务,因为事务已完成或为空 - isCompleted: {}, status: {}", 
+                     status != null ? status.isCompleted() : "null", status);
         }
     }
 
@@ -184,7 +195,7 @@ public class CustomTransactionAspect {
      * 清理事务资源(避免资源泄漏)
      * 注意:不再直接调用私有的 cleanupAfterCompletion
      */
-    private void cleanupTransaction(PlatformTransactionManager tm, TransactionStatus status) {
+    private void cleanupTransaction(DataSourceTransactionManager tm, TransactionStatus status) {
         if (status != null && status.isNewTransaction()) {
             log.debug("🧹 不再手动清理事务资源,Spring会在 commit/rollback 后自动处理");
             // Spring 在 tm.commit(status) 或 tm.rollback(status) 内部已调用 cleanupAfterCompletion

+ 93 - 0
py-base/src/main/java/com/poyee/datasource/holder/CustomTransactionManager.java

@@ -0,0 +1,93 @@
+package com.poyee.datasource.holder;
+
+import com.poyee.datasource.enums.TransactionState;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+
+import javax.sql.DataSource;
+
+public class CustomTransactionManager extends DataSourceTransactionManager {
+
+    private final ThreadLocal<TransactionState> transactionState = new ThreadLocal<>();
+
+    public CustomTransactionManager(DataSource dataSource) {
+        super(dataSource);
+    }
+
+    @Override
+    protected void doBegin(Object transaction, TransactionDefinition definition) {
+        super.doBegin(transaction, definition);
+        transactionState.set(TransactionState.ACTIVE);
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务开始 - 状态: ACTIVE");
+    }
+
+    @Override
+    protected void doCommit(DefaultTransactionStatus status) {
+        TransactionState currentState = transactionState.get();
+
+        if (currentState == TransactionState.ROLLING_BACK || currentState == TransactionState.ROLLED_BACK) {
+            System.out.println("[" + Thread.currentThread().getName() + "] 警告: 尝试在回滚状态下提交事务,操作被拒绝");
+            return;
+        }
+
+        if (currentState == TransactionState.COMMITTED) {
+            System.out.println("[" + Thread.currentThread().getName() + "] 警告: 事务已提交,重复提交操作被拒绝");
+            return;
+        }
+
+        transactionState.set(TransactionState.COMMITTING);
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务提交中 - 状态: COMMITTING");
+
+        super.doCommit(status);
+
+        transactionState.set(TransactionState.COMMITTED);
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务已提交 - 状态: COMMITTED");
+    }
+
+    @Override
+    protected void doRollback(DefaultTransactionStatus status) {
+        TransactionState currentState = transactionState.get();
+
+        if (currentState == TransactionState.COMMITTED) {
+            System.out.println("[" + Thread.currentThread().getName() + "] 警告: 事务已提交,无法回滚");
+            return;
+        }
+
+        if (currentState == TransactionState.ROLLED_BACK) {
+            System.out.println("[" + Thread.currentThread().getName() + "] 警告: 事务已回滚,重复回滚操作被拒绝");
+            return;
+        }
+
+        transactionState.set(TransactionState.ROLLING_BACK);
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务回滚中 - 状态: ROLLING_BACK");
+
+        super.doRollback(status);
+
+        transactionState.set(TransactionState.ROLLED_BACK);
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务已回滚 - 状态: ROLLED_BACK");
+    }
+
+    /**
+     * 获取当前事务状态
+     */
+    public TransactionState getCurrentTransactionState() {
+        return transactionState.get();
+    }
+
+    /**
+     * 清理事务状态
+     */
+    public void clearTransactionState() {
+        transactionState.remove();
+        System.out.println("[" + Thread.currentThread().getName() + "] 事务状态已清理");
+    }
+
+    /**
+     * 检查事务是否处于有效状态
+     */
+    public boolean isValidTransactionState() {
+        TransactionState state = transactionState.get();
+        return state != null && state != TransactionState.UNKNOWN;
+    }
+}

+ 25 - 8
py-base/src/main/java/com/poyee/datasource/holder/TransactionManagerHolder.java

@@ -1,22 +1,39 @@
 package com.poyee.datasource.holder;
 
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 
 @Slf4j
 public class TransactionManagerHolder {
 
-    private static final ThreadLocal<PlatformTransactionManager> CONTEXT = new ThreadLocal<>();
+    private static final ThreadLocal<DataSourceTransactionManager> transactionManagerHolder = new ThreadLocal<>();
+    private static final ThreadLocal<String> dataSourceKeyHolder = new ThreadLocal<>();
 
-    public static void setTransactionManager(PlatformTransactionManager transactionManager) {
-        CONTEXT.set(transactionManager);
+    public static void setTransactionManager(DataSourceTransactionManager transactionManager) {
+        transactionManagerHolder.set(transactionManager);
+        log.debug("设置事务管理器: {}", transactionManager != null ? transactionManager.getClass().getSimpleName() : "null");
     }
 
-    public static PlatformTransactionManager getTransactionManager() {
-        return CONTEXT.get();
+    public static DataSourceTransactionManager getTransactionManager() {
+        DataSourceTransactionManager tm = transactionManagerHolder.get();
+        log.debug("获取事务管理器: {}", tm != null ? tm.getClass().getSimpleName() : "null");
+        return tm;
     }
 
-    public static void clearTransactionManager() {
-        CONTEXT.remove();
+    public static void setDataSourceKey(String dataSourceKey) {
+        dataSourceKeyHolder.set(dataSourceKey);
+        log.debug("设置数据源键: {}", dataSourceKey);
+    }
+
+    public static String getDataSourceKey() {
+        String key = dataSourceKeyHolder.get();
+        log.debug("获取数据源键: {}", key);
+        return key;
+    }
+
+    public static void clear() {
+        transactionManagerHolder.remove();
+        dataSourceKeyHolder.remove();
+        log.debug("清除事务管理器和数据源键");
     }
 }

+ 7 - 8
py-base/src/main/java/com/poyee/framework/handler/MyRequestInterceptor.java

@@ -1,15 +1,14 @@
 package com.poyee.framework.handler;
 
 import com.poyee.datasource.DynamicDataSource;
-import com.poyee.datasource.holder.DataSourceContextHolder;
 import com.poyee.datasource.holder.TransactionManagerHolder;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.annotation.Order;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.web.servlet.HandlerInterceptor;
 
 import javax.servlet.http.HttpServletRequest;
@@ -73,12 +72,12 @@ public class MyRequestInterceptor implements HandlerInterceptor {
             dataSource = dynamicDataSource.initDataSource(dataSource);
 
             // 设置事务管理器(假设你已定义 masterTransactionManager 和 dynamicTransactionManager)
-            PlatformTransactionManager txManager;
+            DataSourceTransactionManager txManager;
 
             if ("master".equalsIgnoreCase(dataSource)) {
-                txManager = applicationContext.getBean("masterTransactionManager", PlatformTransactionManager.class);
+                txManager = applicationContext.getBean("masterTransactionManager", DataSourceTransactionManager.class);
             } else {
-                txManager = applicationContext.getBean("dynamicTransactionManager", PlatformTransactionManager.class);
+                txManager = applicationContext.getBean("dynamicTransactionManager", DataSourceTransactionManager.class);
             }
 
             TransactionManagerHolder.setTransactionManager(txManager);
@@ -124,12 +123,12 @@ public class MyRequestInterceptor implements HandlerInterceptor {
      * @throws Exception 异常信息
      */
     @Override
-    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  {
         // 清理当前线程的数据源上下文
-        DataSourceContextHolder.clearDataSource();
+//        DataSourceContextHolder.clearDataSource();
 
         // 清理事务管理器上下文
-        TransactionManagerHolder.clearTransactionManager();
+        TransactionManagerHolder.clear();
 
         // 清理日志链路追踪 ID
         MDC.remove(TRACE_ID);

+ 7 - 1
py-base/src/main/java/com/poyee/util/ObjectUtil.java

@@ -468,7 +468,13 @@ public class ObjectUtil {
         for (Object o : list) {
             //如果是字符串类型则加上单引号
             if (o instanceof String) {
-                sb.append(escapeValue(o)).append(",");
+                String str = String.valueOf(o);
+                if(StringUtils.isNotBlank(str) && str.endsWith("::jsonb")){
+                    str = str.replace("::jsonb", "'::jsonb");
+                    sb.append("'" +str).append(",");
+                }else{
+                    sb.append(escapeValue(o)).append(",");
+                }
             }else if (o instanceof Date){
                 sb.append("'" +escapeValue(o) + "'").append(",");
             }else{

+ 5 - 0
py-dao/src/main/java/com/poyee/mapper/EcologySkuMapper.java

@@ -3,7 +3,10 @@ package com.poyee.mapper;
 import com.poyee.base.mapper.IBaseMapper;
 import com.poyee.base.mapper.provider.IBaseProvider;
 import com.poyee.dto.EcologySkuDto;
+import com.poyee.req.update.EcologySkuStockReq;
+import org.apache.ibatis.annotations.Delete;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Update;
 
 /**
  * <p>
@@ -16,4 +19,6 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface EcologySkuMapper extends IBaseMapper<EcologySkuDto>, IBaseProvider {
 
+    @Update("update ecology_sku set stock = stock + #{stock} ,update_time = #{updateTime} ,update_by = #{updateUser} where id = #{id}")
+    int updateStock(EcologySkuStockReq req);
 }

+ 4 - 0
py-dao/src/main/java/com/poyee/mapper/EcologySpuMapper.java

@@ -4,6 +4,7 @@ import com.poyee.base.mapper.IBaseMapper;
 import com.poyee.base.mapper.provider.IBaseProvider;
 import com.poyee.dto.EcologySpuDto;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Update;
 
 /**
  * <p>
@@ -16,4 +17,7 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface EcologySpuMapper extends IBaseMapper<EcologySpuDto>, IBaseProvider {
 
+    @Update("update ecology_spu set del_flag = 1 where id = #{id}")
+    public int deleteLogicById(Long id);
+
 }

+ 4 - 0
py-domain/src/main/java/com/poyee/dto/EcologySkuDto.java

@@ -54,6 +54,10 @@ public class EcologySkuDto extends BaseDto {
       @TableField("stock")
     private Integer stock;
 
+      @ApiModelProperty("已售数量")
+      @TableField("sold_stock")
+      private Integer soldStock;
+
       @ApiModelProperty("SKU轮播图")
       @TableField("image_url")
     private String imageUrl;

+ 5 - 1
py-domain/src/main/java/com/poyee/dto/goods/EcologyGoodsDetailDto.java → py-domain/src/main/java/com/poyee/dto/detail/EcologyGoodsDetailDto.java

@@ -1,4 +1,4 @@
-package com.poyee.dto.goods;
+package com.poyee.dto.detail;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -51,6 +51,10 @@ public class EcologyGoodsDetailDto extends BaseDto {
     @TableField(value = "stock")
     private Integer stock;
 
+    @ApiModelProperty("已售数量")
+    @TableField("sold_stock")
+    private Integer soldStock;
+
     //SKU轮播图
     @ApiModelProperty(value = "商品轮播图")
     @TableField(value = "image_url")

+ 127 - 0
py-domain/src/main/java/com/poyee/dto/detail/EcologySkuDetailDto.java

@@ -0,0 +1,127 @@
+package com.poyee.dto.detail;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.poyee.annotation.db.JdbcType;
+import com.poyee.base.dto.BaseDto;
+import com.poyee.enums.FieldType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel(value = "产品SKU详情", description = "B2B产品详情")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuDetailDto extends BaseDto {
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("SPU ID")
+    @TableField("spu_id")
+    private Long spuId;
+
+    @ApiModelProperty(value = "商家ID")
+    @TableField("merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "SKU编码")
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty(value = "SKU名称")
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty(value = "状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架",example = "1")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "规格:nimibox=mini箱,xbox箱,box盒等")
+    @TableField("spec")
+    private String spec;
+
+    @ApiModelProperty(value = "库存")
+    @TableField("stock")
+    private Integer stock;
+
+    @ApiModelProperty("已售数量")
+    @TableField("sold_stock")
+    private Integer soldStock;
+
+    @ApiModelProperty(value = "SKU轮播图")
+    @TableField("image_url")
+    private String imageUrl;
+
+    @ApiModelProperty("详情图")
+    @TableField("detail_url")
+    private String detailUrl;
+
+    @ApiModelProperty(value = "业务类型:求购(buy)、热卖(hot)、专供(supply)等",example = "hot")
+    @TableField("business_type")
+    private String businessType;
+
+    @ApiModelProperty(value = "业务价格配置:json字符串:根据需求设置:[{\"price\": \"\"}] = hot," +
+            "[{\"price\": \"\", \"dealProbability\": \"10\"}, {\"price\": \"\", \"dealProbability\": \"60\"}, {\"price\": \"\", \"dealProbability\": \"90\"}] = buy",
+            required = true)
+    @TableField("business_price_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String businessPriceConfig;
+
+    @ApiModelProperty(value = "标签:热卖(hot),新品(new),促销(promotion)等",example = "hot")
+    @TableField("tags")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String tags;
+
+    @ApiModelProperty("是否参与活动")
+    @TableField("is_activity")
+    private Boolean isActivity;
+
+    @ApiModelProperty("活动配置")
+    @TableField("activity_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String activityConfig;
+
+    @ApiModelProperty("活动开始时间")
+    @TableField("activity_start_time")
+    private Date activityStartTime;
+
+    @ApiModelProperty("活动结束时间")
+    @TableField("activity_end_time")
+    private Date activityEndTime;
+
+    @ApiModelProperty("是否限购")
+    @TableField("is_limit")
+    private Boolean isLimit;
+
+    @ApiModelProperty("限购数量")
+    @TableField("limit_num")
+    private Integer limitNum;
+
+    @ApiModelProperty("限购条件:user=用户,order=订单等")
+    @TableField("limit_condition")
+    private String limitCondition;
+
+    @ApiModelProperty("限购类型:day,month,week,默认空,永久")
+    @TableField("limit_type")
+    private String limitType;
+
+    @ApiModelProperty("限购值")
+    @TableField("limit_value")
+    private Integer limitValue;
+
+    @ApiModelProperty("是否可用优惠券")
+    @TableField("is_coupon")
+    private Boolean isCoupon;
+
+    @ApiModelProperty("是否赠送积分")
+    @TableField("is_point")
+    private Boolean isPoint;
+
+    @ApiModelProperty("赠送积分倍率[1.0]")
+    @TableField("point_num")
+    private Integer pointNum;
+
+
+}

+ 113 - 0
py-domain/src/main/java/com/poyee/dto/detail/EcologySpuDetailDto.java

@@ -0,0 +1,113 @@
+package com.poyee.dto.detail;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.poyee.base.dto.BaseDto;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ *
+ */
+@ApiModel(value = "产品SPU详情", description = "B2B产品详情")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuDetailDto extends BaseDto {
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "产品类型:top15_by_last_7day=top15,HS=HS,ecology=生态购,panini=帕尼尼官方等",example = "HS")
+    @TableField("type")
+    private String type;
+
+    @ApiModelProperty(value = "产品子类型:time_out=超时售卖,direct_ale=直销;[类型暂未定义]",example = "time_out")
+    @TableField("sub_type")
+    private String subType;
+
+    @ApiModelProperty(value = "商家ID",hidden = true)
+    @TableField("merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "编码")
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty(value = "产品名称",example = "2024-25 Soccer Topps Chrome UEFA Club Competitions", required = true)
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty(value = "产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架",example = "1")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "赛季",example = "2024-25")
+    @TableField("year")
+    private String year;
+
+    @ApiModelProperty(value = "运动类型",example = "basketBall" )
+    @TableField("sport")
+    private String sport;
+
+    @ApiModelProperty(value = "发行商",example = "Panini")
+    @TableField("manufacturer")
+    private String manufacturer;
+
+    @ApiModelProperty(value = "系列",example = "Chrome UEFA Club Competitions")
+    @TableField("sets")
+    private String sets;
+
+    @ApiModelProperty(value = "系列版本[可选]",example = "HOBBY")
+    @TableField("sets_version")
+    private String setsVersion;
+
+    @ApiModelProperty("产品描述")
+    @TableField("description")
+    private String description;
+
+    @ApiModelProperty("商品主图(以逗号隔开)")
+    @TableField("carousel_img_url")
+    private String carouselImgUrl;
+
+    @ApiModelProperty("轮播图(以逗号隔开)")
+    @TableField("detail_img_url")
+    private String detailImgUrl;
+
+    @ApiModelProperty(value = "公私域:0=私域,1=公域",example = "1")
+    @TableField("show_applet")
+    private Integer showApplet;
+
+    @ApiModelProperty(value = "发货限制天数",example = "7")
+    @TableField("delivery_limit_day")
+    private Integer deliveryLimitDay;
+
+    @ApiModelProperty("是否允许自提:默认0=否,1=是")
+    @TableField("pick_up")
+    private Integer pickUp;
+
+    @ApiModelProperty("是否支持港澳台发货:默认0否 1是")
+    @TableField("ship_region")
+    private Integer shipRegion;
+
+    @ApiModelProperty("免运费条件金额")
+    @TableField("free_freight_amount")
+    private BigDecimal freeFreightAmount;
+
+    @ApiModelProperty("基础运费")
+    @TableField("base_shipping_cost")
+    private BigDecimal baseShippingCost;
+
+    @ApiModelProperty("偏远地区运费")
+    @TableField("remote_shipping_cost")
+    private BigDecimal remoteShippingCost;
+
+    @ApiModelProperty(value = "sku信息")
+    @TableField(exist = false)
+    private List<EcologySkuDetailDto> skus;
+
+}

+ 1 - 1
py-domain/src/main/java/com/poyee/dto/goods/EcologyGoodsPageDto.java → py-domain/src/main/java/com/poyee/dto/page/EcologyGoodsPageDto.java

@@ -1,4 +1,4 @@
-package com.poyee.dto.goods;
+package com.poyee.dto.page;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;

+ 94 - 0
py-domain/src/main/java/com/poyee/dto/page/EcologySkuPageDto.java

@@ -0,0 +1,94 @@
+package com.poyee.dto.page;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseDto;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * sku
+ */
+@ApiModel(description = "sku分页结果[admin]")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuPageDto extends BaseDto {
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("spuId")
+    @TableField("spu_id")
+    private Long spuId;
+
+    @ApiModelProperty("SKU编码")
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty("SKU名称")
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty("规格:箱,盒等")
+    @TableField("spec")
+    private String spec;
+
+    @ApiModelProperty("库存")
+    @TableField("stock")
+    private Integer stock;
+
+    @ApiModelProperty("已售数量")
+    @TableField("sold_stock")
+    private Integer soldStock;
+
+    @ApiModelProperty("SKU轮播图")
+    @TableField("image_url")
+    private String imageUrl;
+
+    @ApiModelProperty("详情图")
+    @TableField("detail_url")
+    private String detailUrl;
+
+    @ApiModelProperty("业务类型:求购(buy)、热卖(hot)、专供(supply)等")
+    @TableField("business_type")
+    private String businessType;
+
+    @ApiModelProperty("业务价格配置")
+    @TableField("business_price_config")
+    private String businessPriceConfig;
+
+    @ApiModelProperty("标签:热卖(hot),新品(new),促销(promotion)等")
+    @TableField("tags")
+    private String tags;
+
+    @ApiModelProperty("是否限购")
+    @TableField("is_limit")
+    private Boolean isLimit;
+
+    @ApiModelProperty("是否可用优惠券")
+    @TableField("is_coupon")
+    private Boolean isCoupon;
+
+    @ApiModelProperty("是否赠送积分")
+    @TableField("is_point")
+    private Boolean isPoint;
+
+    @ApiModelProperty("产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty("创建时间")
+    @TableField("create_time")
+    private Date createTime;
+
+    @ApiModelProperty("更新时间")
+    @TableField("update_time")
+    private Date updateTime;
+
+}

+ 92 - 0
py-domain/src/main/java/com/poyee/dto/page/EcologySpuPageDto.java

@@ -0,0 +1,92 @@
+package com.poyee.dto.page;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Distinct;
+import com.poyee.annotation.db.LeftJoin;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseDto;
+import com.poyee.enums.FieldOperator;
+import com.poyee.req.page.EcologySpuPageReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ *  spu分页返回
+ */
+@ApiModel(description = "spu分页返回结果[admin]")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuPageDto extends BaseDto {
+
+    @ApiModelProperty(value = "ID", example = "151")
+    @TableField(value = "id")
+    @Distinct
+    private Long id;
+
+    @ApiModelProperty(value = "商户名称", example = "平台运营")
+    @TableField(value = "merchant_name")
+    private String merchantName;
+
+    @ApiModelProperty(value = "类型", example = "top15_by_last_7day")
+    @TableField(value = "type")
+    private String type;
+
+    @ApiModelProperty(value = "编码", example = "SP20251125523212")
+    @TableField(value = "code")
+    private String code;
+
+    @ApiModelProperty(value = "名称", example = "Immaculate")
+    @TableField(value = "name" , exist = false)
+    @Where(table = EcologySpuPageReq.class, field = "name", operator = FieldOperator.ILIKE)
+    private String name;
+
+    @ApiModelProperty(value = "赛季", example = "2024-25")
+    @TableField(value = "year")
+    private String year;
+
+    @ApiModelProperty(value = "运动", example = "Basketball")
+    @TableField(value = "sport")
+    private String sport;
+
+    @ApiModelProperty(value = "发行商", example = "Panini")
+    @TableField(value = "manufacturer")
+    private String manufacturer;
+
+    @ApiModelProperty(value = "系列", example = "Immaculate")
+    @TableField(value = "sets")
+    private String sets;
+
+    @ApiModelProperty(value = "总销售库存", example = "0")
+    @TableField(value = "spu_sold_stock")
+    private Integer spuSoldStock;
+
+    @ApiModelProperty(value = "产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架", example = "300")
+    @TableField(value = "status")
+    private Integer status;
+
+    @ApiModelProperty(value = "公私域:0=私域,1=公域", example = "1")
+    @TableField(value = "show_applet")
+    private Integer showApplet;
+
+    @ApiModelProperty(value = "售卖属性:预售:pre_sale,预定:pre_book,现货:spot_sale")
+    @TableField(value = "sale_type")
+    private String saleType;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    @ApiModelProperty(value = "更新时间")
+    @TableField(value = "update_time")
+    private Date updateTime;
+
+    @ApiModelProperty(value = "sku")
+    @TableField(exist = false)
+    private List<EcologySkuPageDto> skus;
+
+}

+ 19 - 0
py-domain/src/main/java/com/poyee/dto/where/EcologySkuWhereReq.java

@@ -0,0 +1,19 @@
+package com.poyee.dto.where;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@ApiModel(description = "查询条件对象")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuWhereReq extends BaseReq {
+
+    @TableField("spu_id")
+    @Where(table = EcologySkuWhereReq.class, field = "spu_id" )
+    private Long spuId;
+
+}

+ 0 - 98
py-domain/src/main/java/com/poyee/entity/EcologyCourierRecord.java

@@ -1,98 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * 生态购订单快递信息表
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_courier_record")
-@ApiModel(value = "EcologyCourierRecord对象", description = "生态购订单快递信息表")
-public class EcologyCourierRecord extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("类型:main=主包裹、sub=子包裹")
-      @TableField("type")
-    private String type;
-
-      @ApiModelProperty("子类型:main=主订单,sub=子订单")
-      @TableField("sub_type")
-    private String subType;
-
-      @ApiModelProperty("订单ID(关联订单主表)")
-      @TableField("order_id")
-      private Long orderId;
-
-      @ApiModelProperty("子订单ID")
-      @TableField("sub_order_id")
-      private Long subOrderId;
-
-      @ApiModelProperty("订单编码")
-      @TableField("order_no")
-      private String orderNo;
-
-      @ApiModelProperty("子订单编码")
-      @TableField("sub_order_no")
-      private String subOrderNo;
-
-      @ApiModelProperty("快递信息ID")
-      @TableField("courier_id")
-    private Long courierId;
-
-      @ApiModelProperty("快递内部编码")
-      @TableField("courier_no")
-    private String courierNo;
-
-      @ApiModelProperty("快递公司")
-      @TableField("courier_company")
-      private String courierCompany;
-
-      @ApiModelProperty("快递单号")
-      @TableField("courier_number")
-      private String courierNumber;
-
-      @ApiModelProperty("状态")
-      @TableField("status")
-      private String status;
-
-      @ApiModelProperty("物流轨迹")
-      @TableField("trace")
-    private String trace;
-
-      @ApiModelProperty("类别:1=物流,2=售后")
-      @TableField("category")
-      private String category;
-
-      @ApiModelProperty("备注")
-      @TableField("remark")
-    private String remark;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-      private Date createTime;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-
-}

+ 0 - 69
py-domain/src/main/java/com/poyee/entity/EcologyGoodsConfig.java

@@ -1,69 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * SPU产品扩展配置表
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_goods_config")
-@ApiModel(value = "EcologyGoodsConfig对象", description = "SPU产品扩展配置表")
-public class EcologyGoodsConfig extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("商品id")
-      @TableField("spu_id")
-      private Long spuId;
-
-      @ApiModelProperty("商家id")
-      @TableField("merchant_id")
-      private Long merchantId;
-
-      @ApiModelProperty("商家名称")
-      @TableField("merchant_name")
-    private String merchantName;
-
-      @ApiModelProperty("主体id")
-      @TableField("archives_id")
-      private Long archivesId;
-
-      @ApiModelProperty("主体名称")
-      @TableField("archives_name")
-    private String archivesName;
-
-      @ApiModelProperty("是否开票: 0=否, 1=是")
-      @TableField("is_invoice")
-    private Integer isInvoice;
-
-      @ApiModelProperty("开票信息")
-      @TableField("invoice_info")
-    private String invoiceInfo;
-
-      @ApiModelProperty("是否支持对公: 0=否, 1=是")
-      @TableField("is_public")
-    private Integer isPublic;
-
-      @ApiModelProperty("对公转账信息-收款")
-      @TableField("public_info")
-    private String publicInfo;
-
-
-}

+ 0 - 110
py-domain/src/main/java/com/poyee/entity/EcologyMerCustomize.java

@@ -1,110 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * 商家生态购商品推广定制表
- * </p>
- *
- * @author lsz
- * @since 2025-11-19
- */
-@Data
-  @TableName("ecology_mer_customize")
-@ApiModel(value = "EcologyMerCustomize对象", description = "商家生态购商品推广定制表")
-public class EcologyMerCustomize extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("商家ID")
-        @TableField("merchant_id")
-      private Long merchantId;
-
-      @ApiModelProperty("商家名称")
-      @TableField("merchant_name")
-    private String merchantName;
-
-      @ApiModelProperty("SPU ID")
-        @TableField("spu_id")
-      private Long spuId;
-
-      @ApiModelProperty("SPU编码")
-      @TableField("spu_code")
-    private String spuCode;
-
-      @ApiModelProperty("SPU名称")
-      @TableField("spu_name")
-    private String spuName;
-
-      @ApiModelProperty("SKU ID")
-        @TableField("sku_id")
-      private Long skuId;
-
-      @ApiModelProperty("SKU编码")
-      @TableField("sku_code")
-    private String skuCode;
-
-      @ApiModelProperty("SKU名称")
-      @TableField("sku_name")
-    private String skuName;
-
-      @ApiModelProperty("产品类型")
-      @TableField("product_type")
-    private String productType;
-
-      @ApiModelProperty("分类:求购(buy)、热卖(hot)、专供(supply)")
-      @TableField("category")
-    private String category;
-
-      @ApiModelProperty("推广类型: hot(热销), new(新品), promotion(促销)等")
-        @TableField("recommend_type")
-      private String recommendType;
-
-      @ApiModelProperty("推广优先级 数字越小优先级越高")
-      @TableField("priority")
-    private Integer priority;
-
-      @ApiModelProperty("是否启用: 0=禁用, 1=启用")
-        @TableField("enabled")
-      private Integer enabled;
-
-      @ApiModelProperty("开始时间")
-      @TableField("start_time")
-    private Date startTime;
-
-      @ApiModelProperty("结束时间")
-      @TableField("end_time")
-    private Date endTime;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-    private Date createTime;
-
-      @ApiModelProperty("创建人")
-      @TableField("create_user")
-    private String createUser;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-      @ApiModelProperty("更新人")
-      @TableField("update_user")
-    private String updateUser;
-
-
-}

+ 0 - 211
py-domain/src/main/java/com/poyee/entity/EcologyOrderInfo.java

@@ -1,211 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * 订单主表
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_order_info")
-@ApiModel(value = "EcologyOrderInfo对象", description = "订单主表")
-public class EcologyOrderInfo extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("订单类型")
-      @TableField("order_type")
-      private String orderType;
-
-      @ApiModelProperty("订单编号")
-      @TableField("order_no")
-      private String orderNo;
-
-      @ApiModelProperty("用户ID")
-      @TableField("user_id")
-      private Long userId;
-
-      @ApiModelProperty("用户名")
-      @TableField("username")
-    private String username;
-
-      @ApiModelProperty("商家ID")
-      @TableField("merchant_id")
-      private Long merchantId;
-
-      @ApiModelProperty("商家名称")
-      @TableField("merchant_name")
-    private String merchantName;
-
-      @ApiModelProperty("订单总金额")
-      @TableField("total_amount")
-    private BigDecimal totalAmount;
-
-      @ApiModelProperty("实际支付金额")
-      @TableField("pay_amount")
-    private BigDecimal payAmount;
-
-      @ApiModelProperty("商品总金额")
-      @TableField("goods_amount")
-    private BigDecimal goodsAmount;
-
-      @ApiModelProperty("运费")
-      @TableField("shipping_cost")
-    private BigDecimal shippingCost;
-
-      @ApiModelProperty("优惠券抵扣金额")
-      @TableField("coupon_discount")
-    private BigDecimal couponDiscount;
-
-      @ApiModelProperty("积分抵扣金额")
-      @TableField("point_discount")
-    private BigDecimal pointDiscount;
-
-      @ApiModelProperty("订单状态: 100= 待支付, 101= 已支付[待发货]  103=已发货 104=已签收 ,201=超时取消, 202=用户取消 ,204=退款中, 205=退款完成,206=退款失败,301=已完成")
-      @TableField("order_status")
-      private Integer orderStatus;
-
-      @ApiModelProperty("过期时间")
-      @TableField("expire_time")
-    private Date expireTime;
-
-      @ApiModelProperty("支付方式:alipay=支付宝,wechat=微信,balance=余额")
-      @TableField("payment_type")
-    private String paymentType;
-
-      @ApiModelProperty("支付通道")
-      @TableField("payment_sub_type")
-    private String paymentSubType;
-
-      @ApiModelProperty("支付参数")
-      @TableField("pay_data")
-    private String payData;
-
-      @ApiModelProperty("支付编号")
-      @TableField("trade_no")
-    private String tradeNo;
-
-      @ApiModelProperty("预支付ID")
-      @TableField("prepay_id")
-    private String prepayId;
-
-      @ApiModelProperty("支付时间")
-      @TableField("payment_time")
-    private Date paymentTime;
-
-      @ApiModelProperty("支付成功时间")
-      @TableField("payment_success_time")
-    private Date paymentSuccessTime;
-
-      @ApiModelProperty("支付状态:SUCCESS=支付成功,FAIL=支付失败,WAIT_BUYER_PAY=交易创建,NOTPAY=未支付")
-      @TableField("payment_status")
-      private String paymentStatus;
-
-      @ApiModelProperty("退款类型:FULL=全退,PARTIAL=部分退")
-      @TableField("refund_type")
-    private String refundType;
-
-      @ApiModelProperty("退款状态:SUCCESS=退款成功,FAIL=退款失败,PROCESSING=退款处理中,NOTSURE=未确定,REVOKED=已撤销")
-      @TableField("refund_status")
-      private String refundStatus;
-
-      @ApiModelProperty("退款时间")
-      @TableField("refund_time")
-    private Date refundTime;
-
-      @ApiModelProperty("退款成功时间")
-      @TableField("refund_success_time")
-    private Date refundSuccessTime;
-
-      @ApiModelProperty("退款编号")
-      @TableField("refund_no")
-    private String refundNo;
-
-      @ApiModelProperty("退款金额")
-      @TableField("refund_amount")
-    private BigDecimal refundAmount;
-
-      @ApiModelProperty("退款原因")
-      @TableField("refund_reason")
-    private String refundReason;
-
-      @ApiModelProperty("快递公司")
-      @TableField("courier_company")
-    private String courierCompany;
-
-      @ApiModelProperty("快递单号")
-      @TableField("courier_number")
-    private String courierNumber;
-
-      @ApiModelProperty("发货时间")
-      @TableField("delivery_time")
-    private Date deliveryTime;
-
-      @ApiModelProperty("签收时间")
-      @TableField("sign_time")
-    private Date signTime;
-
-      @ApiModelProperty("完成时间")
-      @TableField("complete_time")
-    private Date completeTime;
-
-      @ApiModelProperty("收货人姓名")
-      @TableField("receiver_name")
-    private String receiverName;
-
-      @ApiModelProperty("收货人电话")
-      @TableField("receiver_phone")
-    private String receiverPhone;
-
-      @ApiModelProperty("收货地址")
-      @TableField("receiver_address")
-    private String receiverAddress;
-
-      @ApiModelProperty("省份")
-      @TableField("province")
-    private String province;
-
-      @ApiModelProperty("城市")
-      @TableField("city")
-    private String city;
-
-      @ApiModelProperty("区县")
-      @TableField("district")
-    private String district;
-
-      @ApiModelProperty("售后状态:0=无售后,1=售后中,2=售后完成")
-      @TableField("after_sale_status")
-    private Integer afterSaleStatus;
-
-      @ApiModelProperty("备注信息")
-      @TableField("remark")
-    private String remark;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-      private Date createTime;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-
-}

+ 0 - 119
py-domain/src/main/java/com/poyee/entity/EcologyOrderInvoice.java

@@ -1,119 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * 生态购订单发票表
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_order_invoice")
-@ApiModel(value = "EcologyOrderInvoice对象", description = "生态购订单发票表")
-public class EcologyOrderInvoice extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("订单ID")
-      @TableField("order_id")
-      private Long orderId;
-
-      @ApiModelProperty("订单编号")
-      @TableField("order_no")
-      private String orderNo;
-
-      @ApiModelProperty("发票类型:1=电子发票,2=纸质发票")
-      @TableField("invoice_type")
-    private Integer invoiceType;
-
-      @ApiModelProperty("发票抬头类型:1=个人,2=企业")
-      @TableField("title_type")
-    private Integer titleType;
-
-      @ApiModelProperty("发票抬头")
-      @TableField("invoice_title")
-      private String invoiceTitle;
-
-      @ApiModelProperty("税号")
-      @TableField("tax_number")
-    private String taxNumber;
-
-      @ApiModelProperty("发票内容")
-      @TableField("invoice_content")
-    private String invoiceContent;
-
-      @ApiModelProperty("发票金额")
-      @TableField("invoice_amount")
-    private BigDecimal invoiceAmount;
-
-      @ApiModelProperty("收票人邮箱")
-      @TableField("receiver_email")
-    private String receiverEmail;
-
-      @ApiModelProperty("收票人手机")
-      @TableField("receiver_phone")
-    private String receiverPhone;
-
-      @ApiModelProperty("收票地址")
-      @TableField("receiver_address")
-    private String receiverAddress;
-
-      @ApiModelProperty("开票状态:0=未开票,1=开票中,2=已开票,3=开票失败")
-      @TableField("invoice_status")
-      private Integer invoiceStatus;
-
-      @ApiModelProperty("发票代码")
-      @TableField("invoice_code")
-    private String invoiceCode;
-
-      @ApiModelProperty("发票号码")
-      @TableField("invoice_number")
-    private String invoiceNumber;
-
-      @ApiModelProperty("开票时间")
-      @TableField("invoice_time")
-    private Date invoiceTime;
-
-      @ApiModelProperty("快递公司")
-      @TableField("express_company")
-    private String expressCompany;
-
-      @ApiModelProperty("快递单号")
-      @TableField("express_number")
-    private String expressNumber;
-
-      @ApiModelProperty("发票pdf 地址")
-      @TableField("invoice_pdf_url")
-    private String invoicePdfUrl;
-
-      @ApiModelProperty("备注")
-      @TableField("remark")
-    private String remark;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-      private Date createTime;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-
-}

+ 0 - 107
py-domain/src/main/java/com/poyee/entity/EcologyOrderItem.java

@@ -1,107 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * 订单明细表(子表)
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_order_item")
-@ApiModel(value = "EcologyOrderItem对象", description = "订单明细表(子表)")
-public class EcologyOrderItem extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("订单ID(关联订单主表)")
-      @TableField("order_id")
-      private Long orderId;
-
-      @ApiModelProperty("子订单编号")
-      @TableField("order_no")
-      private String orderNo;
-
-      @ApiModelProperty("SPU ID")
-      @TableField("spu_id")
-      private Long spuId;
-
-      @ApiModelProperty("SKU ID")
-      @TableField("sku_id")
-      private Long skuId;
-
-      @ApiModelProperty("子订单状态:100=待支付,101=待发货,103=已发货,104=已签收,201=超时取消,202=用户取消,204=退款中,205=退款完成,206=退款失败,301=已完成")
-      @TableField("order_status")
-      private Integer orderStatus;
-
-      @ApiModelProperty("商品名称")
-      @TableField("product_name")
-    private String productName;
-
-      @ApiModelProperty("商品规格描述")
-      @TableField("product_spec")
-    private String productSpec;
-
-      @ApiModelProperty("商品单价")
-      @TableField("unit_price")
-    private BigDecimal unitPrice;
-
-      @ApiModelProperty("购买数量")
-      @TableField("quantity")
-    private Integer quantity;
-
-      @ApiModelProperty("小计金额")
-      @TableField("subtotal_amount")
-    private BigDecimal subtotalAmount;
-
-      @ApiModelProperty("快递公司")
-      @TableField("express_company")
-    private String expressCompany;
-
-      @ApiModelProperty("快递单号")
-      @TableField("express_no")
-      private String expressNo;
-
-      @ApiModelProperty("退款金额")
-      @TableField("refund_amount")
-    private BigDecimal refundAmount;
-
-      @ApiModelProperty("退款原因")
-      @TableField("refund_reason")
-    private String refundReason;
-
-      @ApiModelProperty("退款时间")
-      @TableField("refund_time")
-    private Date refundTime;
-
-      @ApiModelProperty("退款编码")
-      @TableField("refund_no")
-      private String refundNo;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-      private Date createTime;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-
-}

+ 0 - 150
py-domain/src/main/java/com/poyee/entity/EcologySku.java

@@ -1,150 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * B2B产品生态购产品SKU表
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_sku")
-@ApiModel(value = "EcologySku对象", description = "B2B产品生态购产品SKU表")
-public class EcologySku extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("SPU ID")
-      @TableField("spu_id")
-      private Long spuId;
-
-      @ApiModelProperty("商家ID")
-      @TableField("merchant_id")
-      private Long merchantId;
-
-      @ApiModelProperty("SKU编码")
-      @TableField("code")
-      private String code;
-
-      @ApiModelProperty("SKU名称")
-      @TableField("name")
-    private String name;
-
-      @ApiModelProperty("规格:箱,盒等")
-      @TableField("spec")
-    private String spec;
-
-      @ApiModelProperty("库存")
-      @TableField("stock")
-    private Integer stock;
-
-      @ApiModelProperty("SKU轮播图")
-      @TableField("image_url")
-    private String imageUrl;
-
-      @ApiModelProperty("详情图")
-      @TableField("detail_url")
-    private String detailUrl;
-
-      @ApiModelProperty("业务类型:求购(buy)、热卖(hot)、专供(supply)等")
-      @TableField("business_type")
-      private String businessType;
-
-      @ApiModelProperty("业务价格配置")
-      @TableField("business_price_config")
-    private String businessPriceConfig;
-
-      @ApiModelProperty("标签:热卖(hot),新品(new),促销(promotion)等")
-      @TableField("tags")
-      private String tags;
-
-      @ApiModelProperty("是否参与活动")
-      @TableField("is_activity")
-    private Boolean isActivity;
-
-      @ApiModelProperty("活动配置")
-      @TableField("activity_config")
-    private String activityConfig;
-
-      @ApiModelProperty("活动开始时间")
-      @TableField("activity_start_time")
-    private Date activityStartTime;
-
-      @ApiModelProperty("活动结束时间")
-      @TableField("activity_end_time")
-    private Date activityEndTime;
-
-      @ApiModelProperty("是否限购")
-      @TableField("is_limit")
-    private Boolean isLimit;
-
-      @ApiModelProperty("限购数量")
-      @TableField("limit_num")
-    private Integer limitNum;
-
-      @ApiModelProperty("限购条件:用户,订单等")
-      @TableField("limit_condition")
-    private String limitCondition;
-
-      @ApiModelProperty("限购类型:day,month,week,默认空,永久")
-      @TableField("limit_type")
-    private String limitType;
-
-      @ApiModelProperty("限购值")
-      @TableField("limit_value")
-    private Integer limitValue;
-
-      @ApiModelProperty("是否可用优惠券")
-      @TableField("is_coupon")
-    private Boolean isCoupon;
-
-      @ApiModelProperty("是否赠送积分")
-      @TableField("is_point")
-    private Boolean isPoint;
-
-      @ApiModelProperty("赠送积分倍率[1.0]")
-      @TableField("point_num")
-    private Integer pointNum;
-
-      @ApiModelProperty("产品状态:0=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架")
-      @TableField("status")
-      private Integer status;
-
-      @ApiModelProperty("删除标记:0=正常,1=删除")
-      @TableField("del_flag")
-    private Integer delFlag;
-
-      @ApiModelProperty("创建人")
-      @TableField("create_by")
-    private String createBy;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-      private Date createTime;
-
-      @ApiModelProperty("更新人")
-      @TableField("update_by")
-    private String updateBy;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-
-}

+ 0 - 199
py-domain/src/main/java/com/poyee/entity/EcologySpu.java

@@ -1,199 +0,0 @@
-package com.poyee.entity;
-
-import com.poyee.base.entity.BaseEntity;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * <p>
- * B2B产品 生态购产品表(spu)
- * </p>
- *
- * @author lsz
- * @since 2025-11-18
- */
-@Data
-  @TableName("ecology_spu")
-@ApiModel(value = "EcologySpu对象", description = "B2B产品 生态购产品表(spu)")
-public class EcologySpu extends BaseEntity  {
-
-    private static final long serialVersionUID = 1L;
-
-      @ApiModelProperty("主键ID")
-        @TableId(value = "id", type = IdType.AUTO)
-      private Long id;
-
-      @ApiModelProperty("产品类型:top15")
-      @TableField("type")
-      private String type;
-
-      @ApiModelProperty("产品子类型:超时售卖")
-      @TableField("sub_type")
-    private String subType;
-
-      @ApiModelProperty("一级分类:定制")
-      @TableField("first_category")
-      private String firstCategory;
-
-      @ApiModelProperty("二级分类:top15商家")
-      @TableField("second_category")
-      private String secondCategory;
-
-      @ApiModelProperty("商家id")
-      @TableField("merchant_id")
-      private Long merchantId;
-
-      @ApiModelProperty("商家名称")
-      @TableField("merchant_name")
-    private String merchantName;
-
-      @ApiModelProperty("编码")
-      @TableField("code")
-      private String code;
-
-      @ApiModelProperty("产品名称")
-      @TableField("name")
-      private String name;
-
-      @ApiModelProperty("产品源 表__id [由表+id组合]")
-      @TableField("source")
-    private String source;
-
-      @ApiModelProperty("赛季")
-      @TableField("year")
-    private String year;
-
-      @ApiModelProperty("运动类型")
-      @TableField("sport")
-      private String sport;
-
-      @ApiModelProperty("发行商")
-      @TableField("manufacturer")
-    private String manufacturer;
-
-      @ApiModelProperty("系列")
-      @TableField("sets")
-      private String sets;
-
-      @ApiModelProperty("系列版本")
-      @TableField("sets_version")
-    private String setsVersion;
-
-      @ApiModelProperty("产品描述")
-      @TableField("description")
-    private String description;
-
-      @ApiModelProperty("产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架")
-      @TableField("status")
-      private Integer status;
-
-      @ApiModelProperty("删除标记:0=正常,1=删除")
-      @TableField("del_flag")
-    private Integer delFlag;
-
-      @ApiModelProperty("商品主图(以逗号隔开)")
-      @TableField("carousel_img_url")
-    private String carouselImgUrl;
-
-      @ApiModelProperty("轮播图(以逗号隔开)")
-      @TableField("detail_img_url")
-    private String detailImgUrl;
-
-      @ApiModelProperty("公私域:0=私域,1=公域")
-      @TableField("show_applet")
-      private Integer showApplet;
-
-      @ApiModelProperty("总spu售出数量")
-      @TableField("spu_sold_stock")
-    private Long spuSoldStock;
-
-      @ApiModelProperty("售卖属性:预售:pre_sale,预定:pre_book,现货:spot_sale")
-      @TableField("sale_type")
-      private String saleType;
-
-      @ApiModelProperty("总预售[预定]出数量")
-      @TableField("pre_sale_stock")
-    private Long preSaleStock;
-
-      @ApiModelProperty("是否开启预售[预定]:0=否,1=是")
-      @TableField("sale_open")
-    private Integer saleOpen;
-
-      @ApiModelProperty("预售[预定]时间[开始时间]")
-      @TableField("sale_start_time")
-    private Date saleStartTime;
-
-      @ApiModelProperty("预售[预定]时间[结束时间]")
-      @TableField("sale_end_time")
-    private Date saleEndTime;
-
-      @ApiModelProperty("预定定金")
-      @TableField("pre_book_deposit")
-    private BigDecimal preBookDeposit;
-
-      @ApiModelProperty("定金是否允许计算在订单总价中:0=否,1=是")
-      @TableField("pre_book_deposit_include")
-    private Integer preBookDepositInclude;
-
-      @ApiModelProperty("发货限制天数")
-      @TableField("delivery_limit_day")
-    private Integer deliveryLimitDay;
-
-      @ApiModelProperty("是否允许自提:默认0=否,1=是")
-      @TableField("pick_up")
-    private Integer pickUp;
-
-      @ApiModelProperty("是否支持港澳台发货:默认0否 1是")
-      @TableField("ship_region")
-    private Integer shipRegion;
-
-      @ApiModelProperty("免运费条件金额")
-      @TableField("free_freight_amount")
-    private BigDecimal freeFreightAmount;
-
-      @ApiModelProperty("基础运费")
-      @TableField("base_shipping_cost")
-    private BigDecimal baseShippingCost;
-
-      @ApiModelProperty("偏远地区运费")
-      @TableField("remote_shipping_cost")
-    private BigDecimal remoteShippingCost;
-
-      @ApiModelProperty("审核时间")
-      @TableField("review_time")
-    private Date reviewTime;
-
-      @ApiModelProperty("审核操作人")
-      @TableField("review_user")
-    private String reviewUser;
-
-      @ApiModelProperty("审核描述")
-      @TableField("review_desc")
-    private String reviewDesc;
-
-      @ApiModelProperty("创建时间")
-      @TableField("create_time")
-    private Date createTime;
-
-      @ApiModelProperty("创建人")
-      @TableField("create_user")
-    private String createUser;
-
-      @ApiModelProperty("更新时间")
-      @TableField("update_time")
-    private Date updateTime;
-
-      @ApiModelProperty("更新人")
-      @TableField("update_user")
-    private String updateUser;
-
-
-}

+ 1 - 3
py-domain/src/main/java/com/poyee/insert/SkuInsertDao.java → py-domain/src/main/java/com/poyee/entity/SkuInsertDao.java

@@ -1,7 +1,6 @@
-package com.poyee.insert;
+package com.poyee.entity;
 
 import com.baomidou.mybatisplus.annotation.*;
-import com.poyee.base.dto.BaseDto;
 import com.poyee.base.dto.BaseReq;
 import com.poyee.enums.ProductBusinessTypeEnums;
 import io.swagger.annotations.ApiModel;
@@ -18,7 +17,6 @@ import java.util.Date;
 @ApiModel(value = "EcologySku对象", description = "B2B产品生态购产品SKU表")
 public class SkuInsertDao extends BaseReq {
 
-
     @ApiModelProperty("主键ID")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;

+ 1 - 1
py-domain/src/main/java/com/poyee/insert/SpuInsertDao.java → py-domain/src/main/java/com/poyee/entity/SpuInsertDao.java

@@ -1,4 +1,4 @@
-package com.poyee.insert;
+package com.poyee.entity;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.poyee.base.dto.BaseReq;

+ 49 - 0
py-domain/src/main/java/com/poyee/enums/EcologySpuStatusEnum.java

@@ -0,0 +1,49 @@
+package com.poyee.enums;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Getter
+public enum EcologySpuStatusEnum {
+    //产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架
+    WAIT_SUBMIT(000, "待提交"),
+    WAIT_AUDIT(100, "待审核"),
+    AUDIT_PASS(200, "审核通过"),
+    AUDIT_REJECT(201, "审核驳回"),
+    ON_SHELF(300, "上架"),
+    OFF_SHELF(999, "下架");
+    private Integer code;
+    private String message;
+    EcologySpuStatusEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+
+    public static List<EcologySpuStatusEnum>  canUpOperateStatusList = Arrays.asList(AUDIT_PASS, ON_SHELF, OFF_SHELF);
+
+    /**
+     * 是否可上架
+     * @param status
+     * @return
+     */
+    public static boolean canUpOperate(Integer status) {
+        return canUpOperateStatusList.stream().anyMatch(e -> e.code.equals(status));
+    }
+
+    /**
+     * 根据code获取描述
+     * @param status
+     * @return
+     */
+    public static String getDescByCode(Integer status) {
+        // 修复Optional.get()未检查的问题
+        return Arrays.stream(EcologySpuStatusEnum.values())
+                     .filter(e -> e.code.equals(status))
+                     .findFirst()
+                     .map(e -> e.message)
+                     .orElse("未知状态");
+    }
+}

+ 2 - 1
py-domain/src/main/java/com/poyee/enums/GoodsQueryTypeEnums.java

@@ -8,7 +8,8 @@ import lombok.Getter;
 @Getter
 public enum GoodsQueryTypeEnums {
 
-    HOT("hot", "热卖"),//热卖 默认
+    BUY("buy", "求购"),//求购 默认1
+    HOT("hot", "热卖"),//热卖 默认2
     RECOMMEND("recommend", "推荐"),
     BASKET_BALL("Basketball", "篮球"),
     SOCCER("Soccer", "足球"),

+ 1 - 3
py-domain/src/main/java/com/poyee/req/goods/EcologyGoodsBuyReq.java → py-domain/src/main/java/com/poyee/req/EcologyGoodsBuyReq.java

@@ -1,4 +1,4 @@
-package com.poyee.req.goods;
+package com.poyee.req;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -9,8 +9,6 @@ import com.poyee.base.dto.BaseReq;
 import com.poyee.enums.FieldOperator;
 import com.poyee.enums.OrderBySortEnums;
 import com.poyee.enums.ProductBusinessTypeEnums;
-import com.poyee.req.EcologySkuReq;
-import com.poyee.req.EcologySpuReq;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;

+ 4 - 1
py-domain/src/main/java/com/poyee/req/EcologySkuReq.java

@@ -54,6 +54,10 @@ public class EcologySkuReq extends BaseReq {
       @TableField("stock")
     private Integer stock;
 
+    @ApiModelProperty("已售数量")
+    @TableField("sold_stock")
+    private Integer soldStock;
+
       @ApiModelProperty("SKU轮播图")
       @TableField("image_url")
     private String imageUrl;
@@ -146,5 +150,4 @@ public class EcologySkuReq extends BaseReq {
       @TableField("update_time")
     private Date updateTime;
 
-
 }

+ 151 - 0
py-domain/src/main/java/com/poyee/req/insert/EcologySkuInsertReq.java

@@ -0,0 +1,151 @@
+package com.poyee.req.insert;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.*;
+import com.poyee.annotation.db.JdbcType;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.enums.FieldType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+/**
+ *
+ */
+@ApiModel(value = "SKU[新增]", description = "SKU[新增]")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuInsertReq extends BaseReq {
+
+    @ApiModelProperty(value = "主键ID",hidden = true)
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "SPU ID", example = "220", required = true)
+    @TableField("spu_id")
+    @NotNull(message = "spuId不能为空")
+    private Long spuId;
+
+    @ApiModelProperty(value = "商家ID",hidden = true)
+    @TableField("merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "SKU编码",hidden = true)
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty(value = "SKU名称",example = "2024-25 Soccer Topps Chrome UEFA Club Competitions", required = true)
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty(value = "规格:nimibox=mini箱,xbox箱,box盒等",example = "nimibox", required = true)
+    @TableField("spec")
+    @NotBlank(message = "规格不能为空")
+    private String spec;
+
+    @ApiModelProperty(value = "库存",example = "100",required = true)
+    @TableField("stock")
+    @NotNull(message = "库存不能为空")
+    private Integer stock;
+
+    @ApiModelProperty(value = "SKU轮播图",example = "FtEF5gCuWn7u6RyGVtukq1NP7a_l",required = true)
+    @TableField("image_url")
+    @NotBlank(message = "轮播图不能为空")
+    private String imageUrl;
+
+    @ApiModelProperty("详情图")
+    @TableField("detail_url")
+    private String detailUrl;
+
+    @ApiModelProperty(value = "业务类型:求购(buy)、热卖(hot)、专供(supply)等", example = "hot",required = true)
+    @TableField("business_type")
+    @NotBlank(message = "业务类型不能为空")
+    private String businessType;
+
+    @ApiModelProperty(value = "业务价格配置:json字符串:根据需求设置:[{\"price\": \"\"}] = hot," +
+            "[{\"price\": \"\", \"dealProbability\": \"10\"}, {\"price\": \"\", \"dealProbability\": \"60\"}, {\"price\": \"\", \"dealProbability\": \"90\"}] = buy",
+            example = "[{\"price\": \"\"}]",
+            required = true)
+    @TableField("business_price_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    @NotBlank(message = "业务价格配置不能为空")
+    private String businessPriceConfig;
+
+    @ApiModelProperty(value = "标签:热卖(hot),新品(new),促销(promotion)等",example = "hot")
+    @TableField("tags")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String tags;
+
+    @ApiModelProperty("是否参与活动")
+    @TableField("is_activity")
+    private Boolean isActivity;
+
+    @ApiModelProperty("活动配置")
+    @TableField("activity_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String activityConfig;
+
+    @ApiModelProperty("活动开始时间")
+    @TableField("activity_start_time")
+    private Date activityStartTime;
+
+    @ApiModelProperty("活动结束时间")
+    @TableField("activity_end_time")
+    private Date activityEndTime;
+
+    @ApiModelProperty("是否限购")
+    @TableField("is_limit")
+    private Boolean isLimit;
+
+    @ApiModelProperty("限购数量")
+    @TableField("limit_num")
+    private Integer limitNum;
+
+    @ApiModelProperty("限购条件:user=用户,order=订单等")
+    @TableField("limit_condition")
+    private String limitCondition;
+
+    @ApiModelProperty("限购类型:day,month,week,默认空,永久")
+    @TableField("limit_type")
+    private String limitType;
+
+    @ApiModelProperty("限购值")
+    @TableField("limit_value")
+    private Integer limitValue;
+
+    @ApiModelProperty("是否可用优惠券")
+    @TableField("is_coupon")
+    private Boolean isCoupon;
+
+    @ApiModelProperty("是否赠送积分")
+    @TableField("is_point")
+    private Boolean isPoint;
+
+    @ApiModelProperty("赠送积分倍率[1.0]")
+    @TableField("point_num")
+    private Integer pointNum;
+
+    @ApiModelProperty(value = "创建人",hidden = true)
+    @TableField(value = "create_by",fill = FieldFill.INSERT)
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间",hidden = true)
+    @TableField(value = "create_time",fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_by",fill = FieldFill.INSERT_UPDATE)
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+
+
+}

+ 146 - 0
py-domain/src/main/java/com/poyee/req/insert/EcologySpuInsertReq.java

@@ -0,0 +1,146 @@
+package com.poyee.req.insert;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *  插入
+ */
+@ApiModel(value = "SPU[新增]", description = "SPU[新增]")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuInsertReq extends BaseReq {
+    @ApiModelProperty(value = "主键ID",hidden = true)
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "产品类型:top15_by_last_7day=top15,HS=HS,ecology=生态购,panini=帕尼尼官方等",example = "HS",required = true)
+    @TableField("type")
+    @NotBlank(message = "请选择产品类型")
+    private String type;
+
+    @ApiModelProperty(value = "产品子类型:time_out=超时售卖,direct_ale=直销;[类型暂未定义]",example = "time_out")
+    @TableField("sub_type")
+    private String subType;
+
+    @ApiModelProperty(value = "商家id",hidden = true)
+    @TableField("merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "商家名称",hidden = true)
+    @TableField("merchant_name")
+    private String merchantName;
+
+    @ApiModelProperty(value = "编码",hidden = true)
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty(value = "产品名称",example = "2024-25 Soccer Topps Chrome UEFA Club Competitions", required = true)
+    @TableField("name")
+    @NotBlank(message = "请输入产品名称")
+    private String name;
+
+    @ApiModelProperty(value = "基础库id", required = true)
+    @TableField(exist = false)
+    @NotNull(message = "请选择基础库id")
+    private Long baseInfoId;
+
+    @ApiModelProperty(value = "产品源 表__id [由表+id组合]",hidden = true)
+    @TableField("source")
+    private String source;
+
+    @ApiModelProperty(value = "赛季",example = "2024-25",required = true)
+    @TableField("year")
+    @NotBlank(message = "请输入赛季")
+    private String year;
+
+    @ApiModelProperty(value = "运动类型",example = "basketBall" ,required = true)
+    @TableField("sport")
+    @NotBlank(message = "请输入运动类型")
+    private String sport;
+
+    @ApiModelProperty(value = "发行商",example = "Panini",required = true)
+    @TableField("manufacturer")
+    @NotBlank(message = "请输入发行商")
+    private String manufacturer;
+
+    @ApiModelProperty(value = "系列",example = "Chrome UEFA Club Competitions",required = true)
+    @TableField("sets")
+    @NotBlank(message = "请输入系列")
+    private String sets;
+
+    @ApiModelProperty(value = "系列版本[可选]",example = "HOBBY")
+    @TableField("sets_version")
+    private String setsVersion;
+
+    @ApiModelProperty("产品描述")
+    @TableField("description")
+    private String description;
+
+    @ApiModelProperty("商品主图(以逗号隔开)")
+    @TableField("carousel_img_url")
+    private String carouselImgUrl;
+
+    @ApiModelProperty("轮播图(以逗号隔开)")
+    @TableField("detail_img_url")
+    private String detailImgUrl;
+
+    @ApiModelProperty(value = "公私域:0=私域,1=公域",example = "1")
+    @TableField("show_applet")
+    private Integer showApplet;
+
+    @ApiModelProperty(value = "发货限制天数",example = "7")
+    @TableField("delivery_limit_day")
+    private Integer deliveryLimitDay;
+
+    @ApiModelProperty("是否允许自提:默认0=否,1=是")
+    @TableField("pick_up")
+    private Integer pickUp;
+
+    @ApiModelProperty("是否支持港澳台发货:默认0否 1是")
+    @TableField("ship_region")
+    private Integer shipRegion;
+
+    @ApiModelProperty("免运费条件金额")
+    @TableField("free_freight_amount")
+    private BigDecimal freeFreightAmount;
+
+    @ApiModelProperty("基础运费")
+    @TableField("base_shipping_cost")
+    private BigDecimal baseShippingCost;
+
+    @ApiModelProperty("偏远地区运费")
+    @TableField("remote_shipping_cost")
+    private BigDecimal remoteShippingCost;
+
+    @ApiModelProperty(value = "创建人",hidden = true)
+    @TableField(value = "create_by",fill = FieldFill.INSERT)
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间",hidden = true)
+    @TableField(value = "create_time",fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_by",fill = FieldFill.INSERT_UPDATE)
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @ApiModelProperty(value = "sku信息")
+    @TableField(exist = false)
+    private List<EcologySkuInsertReq> skus;
+
+}

+ 34 - 1
py-domain/src/main/java/com/poyee/req/goods/EcologyGoodsBuyPageReq.java → py-domain/src/main/java/com/poyee/req/page/EcologyGoodsBuyPageReq.java

@@ -1,4 +1,4 @@
-package com.poyee.req.goods;
+package com.poyee.req.page;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -30,6 +30,13 @@ public class EcologyGoodsBuyPageReq extends BaseReq {
     @TableField("name")
     private String name;
 
+    /**
+     * @see GoodsQueryTypeEnums
+     */
+    @ApiModelProperty(value = "tab类型:热卖=hot,推荐=recommend,篮球=basketBall,足球=soccer,其他=other", example = "hot")
+    @TableField(exist = false)
+    private String type;
+
     /**
      * 类别:求购(buy)、热卖(hot)、专供(supply)
      * @see ProductBusinessTypeEnums
@@ -74,5 +81,31 @@ public class EcologyGoodsBuyPageReq extends BaseReq {
     @LeftJoin(table = EcologySkuReq.class , fieldName = "id" , leftFieldName = "sku_id")
     private String skuId;
 
+    @ApiModelProperty(value = "标签:recommend=推荐", example = "recommend")
+    @TableField(value = "tags",exist = false)
+    @Where(table = EcologySkuReq.class , field = "tags" ,columnType = FieldType.JSONB, operator = FieldOperator.JSONB_CONTAINS)
+    private String tags;
+
+    @ApiModelProperty(value = "运动类型", example = "basketBall", hidden = true)
+    @TableField(exist = false)
+    @Where(table = EcologySpuReq.class , field = "sport" ,operator = FieldOperator.ILIKE)
+    @LeftJoin(table = EcologySpuReq.class , leftTable = EcologySkuReq.class , fieldName = "id" , leftFieldName = "spu_id")
+    private String sport;
+
+    @ApiModelProperty(value = "运动类型", example = "basketBall", hidden = true)
+    @TableField(exist = false)
+    @Where(table = EcologySpuReq.class , field = "sport" ,operator = FieldOperator.IN)
+    @LeftJoin(table = EcologySpuReq.class , leftTable = EcologySkuReq.class , fieldName = "id" , leftFieldName = "spu_id")
+    private List<String> inSports;
+
+    @ApiModelProperty(value = "运动类型", example = "basketBall", hidden = true)
+    @TableField(exist = false)
+    @Where(table = EcologySpuReq.class , field = "sport" ,operator = FieldOperator.NOTIN)
+    @LeftJoin(table = EcologySpuReq.class , leftTable = EcologySkuReq.class , fieldName = "id" , leftFieldName = "spu_id")
+    private List<String> notInSports;
+
+    @ApiModelProperty(value = "商户业务类型:对应产品的运动类型", example = "buy",hidden = true)
+    @TableField(exist = false)
+    private String merBusinessType;
 
 }

+ 1 - 2
py-domain/src/main/java/com/poyee/req/goods/EcologyGoodsPageReq.java → py-domain/src/main/java/com/poyee/req/page/EcologyGoodsPageReq.java

@@ -1,11 +1,10 @@
-package com.poyee.req.goods;
+package com.poyee.req.page;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.poyee.annotation.db.LeftJoin;
 import com.poyee.annotation.db.Where;
 import com.poyee.base.dto.BaseReq;
-import com.poyee.dto.EcologySpuDto;
 import com.poyee.enums.FieldOperator;
 import com.poyee.enums.FieldType;
 import com.poyee.enums.GoodsQueryTypeEnums;

+ 32 - 0
py-domain/src/main/java/com/poyee/req/page/EcologySkuPageReq.java

@@ -0,0 +1,32 @@
+package com.poyee.req.page;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.enums.FieldOperator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@ApiModel(description = "sku分页参数")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuPageReq extends BaseReq {
+
+        @ApiModelProperty(value = "ID", example = "151")
+        @TableField(value = "id")
+        private Long id;
+
+        @ApiModelProperty(value = "删除标记:0=正常,1=删除", example = "0" , hidden = true)
+        @TableField(value = "del_flag")
+        private Integer delFlg = 0;
+
+        @ApiModelProperty(value = "spuId", example = "301",hidden = true)
+        @TableField(value = "spu_id",exist = false)
+        @Where(table = EcologySkuPageReq.class, field = "spu_id", operator = FieldOperator.IN)
+        private List<Long> inSpuIds;
+
+}

+ 92 - 0
py-domain/src/main/java/com/poyee/req/page/EcologySpuPageReq.java

@@ -0,0 +1,92 @@
+package com.poyee.req.page;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Distinct;
+import com.poyee.annotation.db.LeftJoin;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.enums.FieldOperator;
+import com.poyee.enums.FieldType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *  spu分页参数
+ */
+@ApiModel(description = "spu分页请求参数[admin]")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuPageReq extends BaseReq {
+
+    @ApiModelProperty(value = "ID", example = "151")
+    @TableField(value = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "商户ID", example = "0",hidden = true)
+    @TableField(value = "merchant_id")
+    private Long merchantId;
+
+    @ApiModelProperty(value = "商户名称", example = "平台运营")
+    @TableField(value = "merchant_name")
+    private String merchantName;
+
+    @ApiModelProperty(value = "类型", example = "top15_by_last_7day")
+    @TableField(value = "type")
+    private String type;
+
+    @ApiModelProperty(value = "编码", example = "SP20251125523212")
+    @TableField(value = "code")
+    private String code;
+
+    @ApiModelProperty(value = "名称", example = "Immaculate")
+    @TableField(value = "name" , exist = false)
+    @Where(table = EcologySpuPageReq.class, field = "name", operator = FieldOperator.ILIKE)
+    private String name;
+
+    @ApiModelProperty(value = "运动", example = "Basketball")
+    @TableField(value = "sport")
+    private String sport;
+
+    @ApiModelProperty(value = "产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架", example = "300")
+    @TableField(value = "status")
+    private Integer status;
+
+    @ApiModelProperty(value = "公私域:0=私域,1=公域", example = "1")
+    @TableField(value = "show_applet")
+    private Integer showApplet;
+
+    @ApiModelProperty(value = "售卖属性:预售:pre_sale,预定:pre_book,现货:spot_sale")
+    @TableField(value = "sale_type")
+    private String saleType;
+
+    @ApiModelProperty(value = "删除标记:0=正常,1=删除", example = "0" , hidden = true)
+    @TableField(value = "del_flag")
+    private Integer delFlg = 0;
+
+    @ApiModelProperty(value = "skuId", example = "301")
+    @TableField(value = "id",exist = false)
+    @Where(table = EcologySkuPageReq.class, field = "id", operator = FieldOperator.EQ)
+    @LeftJoin(table = EcologySkuPageReq.class , fieldName = "spu_id" ,leftFieldName = "id")
+    private Long skuId;
+
+    @ApiModelProperty(value = "sku编码", example = "SK20251125997992")
+    @TableField(value = "code",exist = false)
+    @Where(table = EcologySkuPageReq.class, field = "code", operator = FieldOperator.ILIKE)
+    private String skuCode;
+
+    @ApiModelProperty(value = "业务类型:求购(buy)、热卖(hot)、专供(supply)等", example = "buy")
+    @TableField(value = "business_type",exist = false)
+    @Where(table = EcologySkuPageReq.class, field = "business_type", operator = FieldOperator.EQ)
+    private String businessType;
+
+    @ApiModelProperty(value = "标签:热卖(hot),新品(new),促销(promotion),推荐(recommend)等", example = "recommend")
+    @TableField(value = "tags",exist = false)
+    @Where(table = EcologySkuPageReq.class, field = "tags",columnType = FieldType.JSONB,  operator = FieldOperator.JSONB_CONTAINS)
+    private String tags;
+
+
+
+}
+

+ 47 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySkuDelReq.java

@@ -0,0 +1,47 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+@ApiModel(value = "删除商品请求对象")
+@Data
+@TableName("ecology_sku")
+@NoArgsConstructor
+@AllArgsConstructor
+public class EcologySkuDelReq extends BaseReq {
+
+    public EcologySkuDelReq(Long spuId, Integer delFlag){
+        this.spuId = spuId;
+        this.delFlag = delFlag;
+
+    }
+
+    @ApiModelProperty(value = "商品ID", required = true, example = "1")
+    @TableField(exist = false)
+    @Where(table= EcologySkuDelReq.class ,field = "spu_id"  )
+    private Long spuId;
+
+    @ApiModelProperty(value = "删除标记", hidden = true)
+    @TableField("del_flag")
+    private Integer delFlag;
+
+    @ApiModelProperty(value = "更新时间", hidden = true)
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    @ApiModelProperty(value = "更新时间", hidden = true)
+    @TableField(value = "update_by", fill = FieldFill.UPDATE)
+    private String updateUser;
+
+
+}

+ 36 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySkuStockReq.java

@@ -0,0 +1,36 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+@ApiModel(value = "SKU 库存变更", description = "SKU 库存变更")
+@Data
+public class EcologySkuStockReq extends BaseReq {
+
+    @ApiModelProperty(value = "产品[sku]ID",example = "1",required = true)
+    @NotNull(message = "产品[sku]ID不能为空")
+    private Long id;
+
+    @ApiModelProperty(value = "增|减 :true = 增 false=减",example = "true",required = true)
+    @NotNull(message = "需设置增|减")
+    private boolean up;
+
+    @ApiModelProperty(value = "库存",example = "1",required = true)
+    @NotNull(message = "库存不能为空")
+    private Integer stock;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    private Date UpdateTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    private String updateUser;
+
+}

+ 41 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySkuUpReq.java

@@ -0,0 +1,41 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+@ApiModel(value = "SKU上架下架", description = "SKU上架下架")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuUpReq extends BaseReq {
+
+    @ApiModelProperty(value = "产品[sku]ID",example = "1",required = true)
+    @NotNull(message = "产品[sku]ID不能为空")
+    @TableField("id")
+    private Long id;
+
+    @ApiModelProperty(value = "是否上架",example = "true",required = true)
+    @NotNull(message = "是否上架不能为空")
+    @TableField(exist = false)
+    private boolean up;
+
+    @ApiModelProperty(value = "状态",example = "1",hidden = true)
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    private Date UpdateTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_by", fill = FieldFill.UPDATE)
+    private String updateUser;
+
+}

+ 121 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySkuUpdateReq.java

@@ -0,0 +1,121 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.JdbcType;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.enums.FieldType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+@ApiModel(value = "更新商品SKU请求对象")
+@Data
+@TableName("ecology_sku")
+public class EcologySkuUpdateReq extends BaseReq {
+
+    @ApiModelProperty(value = "主键ID",required = true)
+    @TableField("id")
+    @NotNull(message = "主键ID不能为空")
+    @Where(table = EcologySkuUpdateReq.class, field = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "SKU名称")
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty(value = "规格:nimibox=mini箱,xbox箱,box盒等")
+    @TableField("spec")
+    private String spec;
+
+    @ApiModelProperty(value = "SKU轮播图")
+    @TableField("image_url")
+    private String imageUrl;
+
+    @ApiModelProperty("详情图")
+    @TableField("detail_url")
+    private String detailUrl;
+
+    @ApiModelProperty(value = "业务类型:求购(buy)、热卖(hot)、专供(supply)等",example = "hot")
+    @TableField("business_type")
+    private String businessType;
+
+    @ApiModelProperty(value = "业务价格配置:json字符串:根据需求设置:[{\"price\": \"\"}] = hot," +
+            "[{\"price\": \"\", \"dealProbability\": \"10\"}, {\"price\": \"\", \"dealProbability\": \"60\"}, {\"price\": \"\", \"dealProbability\": \"90\"}] = buy")
+    @TableField("business_price_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String businessPriceConfig;
+
+    @ApiModelProperty(value = "标签:热卖(hot),新品(new),促销(promotion)等",example = "hot")
+    @TableField("tags")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String tags;
+
+    @ApiModelProperty("是否参与活动")
+    @TableField("is_activity")
+    private Boolean isActivity;
+
+    @ApiModelProperty("活动配置")
+    @TableField("activity_config")
+    @JdbcType(columnType = FieldType.JSONB)
+    private String activityConfig;
+
+    @ApiModelProperty("活动开始时间")
+    @TableField("activity_start_time")
+    private Date activityStartTime;
+
+    @ApiModelProperty("活动结束时间")
+    @TableField("activity_end_time")
+    private Date activityEndTime;
+
+    @ApiModelProperty("是否限购")
+    @TableField("is_limit")
+    private Boolean isLimit;
+
+    @ApiModelProperty("限购数量")
+    @TableField("limit_num")
+    private Integer limitNum;
+
+    @ApiModelProperty("限购条件:user=用户,order=订单等")
+    @TableField("limit_condition")
+    private String limitCondition;
+
+    @ApiModelProperty("限购类型:day,month,week,默认空,永久")
+    @TableField("limit_type")
+    private String limitType;
+
+    @ApiModelProperty("限购值")
+    @TableField("limit_value")
+    private Integer limitValue;
+
+    @ApiModelProperty("是否可用优惠券")
+    @TableField("is_coupon")
+    private Boolean isCoupon;
+
+    @ApiModelProperty("是否赠送积分")
+    @TableField("is_point")
+    private Boolean isPoint;
+
+    @ApiModelProperty("赠送积分倍率[1.0]")
+    @TableField("point_num")
+    private Integer pointNum;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_by",fill = FieldFill.UPDATE)
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time",fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    @ApiModelProperty(value = "产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架", hidden = true)
+    @TableField("status")
+    private Integer status;
+
+
+}

+ 47 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySpuDelReq.java

@@ -0,0 +1,47 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+@ApiModel(value = "删除商品请求对象")
+@Data
+@TableName("ecology_spu")
+@NoArgsConstructor
+@AllArgsConstructor
+public class EcologySpuDelReq extends BaseReq {
+
+    public EcologySpuDelReq(Long id, Integer delFlag){
+        this.id = id;
+        this.delFlag = delFlag;
+
+    }
+
+    @ApiModelProperty(value = "商品ID", required = true, example = "1")
+    @TableField(exist = false)
+    @Where(table= EcologySpuDelReq.class ,field = "id"  )
+    private Long id;
+
+    @ApiModelProperty(value = "删除标记", hidden = true)
+    @TableField("del_flag")
+    private Integer delFlag;
+
+    @ApiModelProperty(value = "更新时间", hidden = true)
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    @ApiModelProperty(value = "更新时间", hidden = true)
+    @TableField(value = "update_user", fill = FieldFill.UPDATE)
+    private String updateUser;
+
+
+}

+ 54 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySpuReviewReq.java

@@ -0,0 +1,54 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+@ApiModel(value = "SPU审核", description = "SPU审核")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuReviewReq extends BaseReq {
+
+    @ApiModelProperty(value = "产品[spu]ID",example = "1",required = true)
+    @NotNull(message = "产品[spu]ID不能为空")
+    @TableField("id")
+    private Long id;
+
+    @ApiModelProperty(value = "是否通过",example = "true",required = true)
+    @NotNull(message = "是否通过不能为空")
+    @TableField(exist = false)
+    private boolean pass;
+
+    @ApiModelProperty(value = "状态",example = "1",hidden = true)
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "审核驳回原因",example = "审核驳回原因")
+    @TableField(value="review_desc")
+    private String reason;
+
+    @ApiModelProperty(value = "审核人",example = "1",hidden = true)
+    @TableField(value="review_user" ,fill = FieldFill.UPDATE)
+    private String reviewUser;
+
+    @ApiModelProperty(value = "审核时间",example = "1",hidden = true)
+    @TableField(value="review_time" ,fill = FieldFill.UPDATE)
+    private Date reviewTime;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    private Date UpdateTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_user", fill = FieldFill.UPDATE)
+    private String updateUser;
+
+}

+ 46 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySpuUpReq.java

@@ -0,0 +1,46 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+@ApiModel(value = "SPU上架下架", description = "SPU上架下架")
+@Data
+@TableName("ecology_spu")
+public class EcologySpuUpReq extends BaseReq {
+
+    @ApiModelProperty(value = "产品[spu]ID",example = "1",required = true)
+    @NotNull(message = "产品[spu]ID不能为空")
+    @TableField("id")
+    private Long id;
+
+    @ApiModelProperty(value = "是否上架",example = "true",required = true)
+    @NotNull(message = "是否上架不能为空")
+    @TableField(exist = false)
+    private boolean up;
+
+    @ApiModelProperty(value = "状态",example = "1",hidden = true)
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "下架原因",example = "下架原因")
+    @TableField(value="review_desc")
+    private String reason;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    private Date UpdateTime;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_user", fill = FieldFill.UPDATE)
+    private String updateUser;
+
+}

+ 64 - 0
py-domain/src/main/java/com/poyee/req/update/EcologySpuUpdateReq.java

@@ -0,0 +1,64 @@
+package com.poyee.req.update;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ */
+@Data
+@TableName("ecology_spu")
+@ApiModel(value = "EcologySpu对象", description = "B2B产品生态购产品(spu)")
+public class EcologySpuUpdateReq extends BaseReq {
+
+    @ApiModelProperty(value = "主键ID",required = true)
+    @TableId(value = "id", type = IdType.AUTO)
+    @NotNull(message = "ID不能为空")
+    private Long id;
+
+    @ApiModelProperty(value = "商户ID",hidden = true)
+    @TableField(value = "merchant_id",exist = false)
+    private Long merchantId;
+
+    @ApiModelProperty("产品描述")
+    @TableField("description")
+    private String description;
+
+    @ApiModelProperty("商品主图(以逗号隔开)")
+    @TableField("carousel_img_url")
+    private String carouselImgUrl;
+
+    @ApiModelProperty("轮播图(以逗号隔开)")
+    @TableField("detail_img_url")
+    private String detailImgUrl;
+
+    @ApiModelProperty("公私域:0=私域,1=公域")
+    @TableField("show_applet")
+    private Integer showApplet;
+
+    @ApiModelProperty(value = "产品状态:000=待提交,100=待审核,200=审核通过,201=审核驳回,300=上架,999=下架", hidden = true)
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "sku信息",hidden = true)
+    @TableField(exist = false)
+    private List<EcologySkuInsertReq> skus;
+
+    @ApiModelProperty(value = "更新人",hidden = true)
+    @TableField(value = "update_by",fill = FieldFill.INSERT_UPDATE)
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间",hidden = true)
+    @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+}

+ 3 - 6
py-feign-clients/src/main/java/com/poyee/feign/MerAndUserInfoFeignService.java → py-feign-clients/src/main/java/com/poyee/feign/AdminFeignService.java

@@ -1,22 +1,19 @@
 package com.poyee.feign;
 
-import com.poyee.base.dto.Result;
 import com.poyee.config.FeignConfig;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 
-import java.util.Map;
-
 /**
  * 商家及用户信息Feign服务接口
  */
 @FeignClient(
-        name = "mer-user-info-service",
-        url = "${mer-user-info.service.url:http://localhost}",
+        name = "admin-service",
+        url = "${feign.admin-service.url:http://localhost}",
         configuration = FeignConfig.class
 )
-public interface MerAndUserInfoFeignService {
+public interface AdminFeignService {
 
     @GetMapping("/p1/api/info/merchant/{id}")
     Object getMerchantId(@PathVariable("id") String id);

+ 20 - 0
py-feign-clients/src/main/java/com/poyee/feign/CheckListFeignService.java

@@ -0,0 +1,20 @@
+package com.poyee.feign;
+
+import com.poyee.config.FeignConfig;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.Map;
+
+@FeignClient(
+        name = "checklist-service",
+        url = "${feign.checklist-service.url:http://localhost:8084}",
+        configuration = FeignConfig.class
+)
+public interface CheckListFeignService {
+
+    @PostMapping("/local/panini")
+    Object getPaniniListInfoById( @RequestBody Map<String, Object> data);
+
+}

+ 151 - 5
py-service/src/main/java/com/poyee/build/ProductBeanBuildFactory.java

@@ -1,20 +1,24 @@
 package com.poyee.build;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.poyee.constant.DomainConstants;
-import com.poyee.dto.EcologyMerCustomizeDto;
 import com.poyee.dto.EcologySkuDto;
 import com.poyee.enums.GoodsQueryTypeEnums;
 import com.poyee.enums.ProductBusinessTypeEnums;
 import com.poyee.enums.RandomTypeEnums;
-import com.poyee.insert.SkuInsertDao;
-import com.poyee.insert.SpuInsertDao;
+import com.poyee.entity.SkuInsertDao;
+import com.poyee.entity.SpuInsertDao;
 import com.poyee.req.EcologyMerCustomizeReq;
-import com.poyee.req.goods.EcologyGoodsBuyPageReq;
-import com.poyee.req.goods.EcologyGoodsPageReq;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import com.poyee.req.insert.EcologySpuInsertReq;
+import com.poyee.req.page.EcologyGoodsBuyPageReq;
+import com.poyee.req.page.EcologyGoodsPageReq;
 import com.poyee.req.sync.EcologySpuSyncReq;
 import com.poyee.util.RandomUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 
 import java.util.*;
@@ -170,5 +174,147 @@ public class ProductBeanBuildFactory {
         }
     }
 
+    /**
+     *  构建求购列表查询参数
+     * @param req
+     */
+    public static void builderBuysParamByType(EcologyGoodsBuyPageReq req) {
+        req.setSpuStatus(300);//显示上架商品
+        req.setShowApplet(1);//显示公域商品
+        req.setSkuStatus(300);//显示上架商品
+        req.setSkuBusinessType("buy");//求购
+        switch (GoodsQueryTypeEnums.getByType(req.getType())) {
+            case BUY://求购
+                req.setCategory(req.getType());
+                break;
+            case RECOMMEND://推荐
+                //设置 标签
+                req.setTags("recommend");
+                req.setMerchantId(null);
+                //如果是推荐 则设置 商家的主营业务类型到 运动类型
+                //调用接口查询商家信息
+                if(Objects.nonNull(req.getMerBusinessType())) {
+                    req.setSport(req.getMerBusinessType());
+                }
+                break;
+            case BASKET_BALL://篮球
+                req.setSport("Basketball");
+                req.setMerchantId(null);
+                break;
+            case SOCCER://足球
+                req.setSport("Soccer");
+                req.setMerchantId(null);
+                break;
+            case OTHER://其他
+                req.setNotInSports(Arrays.asList("Basketball", "Soccer"));
+                req.setMerchantId(null);
+                break;
+            default:
+                req.setCategory(req.getType());
+                break;
+        }
+    }
+
+
+    /**
+     * 构建spu插入参数
+     * @param req
+     * @return
+     */
+    public static SpuInsertDao builderInsertParam(EcologySpuInsertReq req) {
+        req.setCode(RandomUtils.generateRandomString(DomainConstants.SPU, RandomTypeEnums.YYYYMMDD,16));
+        SpuInsertDao insertDao = new SpuInsertDao();
+        BeanUtils.copyProperties(req, insertDao);
+        insertDao.setSource("panini_checklist_base_info__"+req.getBaseInfoId());
+        //如有新增继续可在此添加
+        return insertDao;
+    }
+
+    /**
+     * 构建sku插入参数
+     * @param req
+     * @param paniniBaseInfoRet
+     */
+    public static void builderSpuInsertPaniniBaseInfo(EcologySpuInsertReq req, Object paniniBaseInfoRet) {
+        String displayName = "";
+        try{
+            //转换为 json
+            JSONObject retJson = JSONObject.parseObject(JSONObject.toJSONString(paniniBaseInfoRet));
+            if(Objects.equals(retJson.getInteger("code") ,200)){
+                JSONArray data = retJson.getJSONArray("data");
+                if(Objects.nonNull(data) && !data.isEmpty()){
+                    JSONObject paniniBaseInfo = data.getJSONObject(0);
+                    req.setName(paniniBaseInfo.getString("displayName"));
+                }
+            }
+        }catch (Exception e){
+            log.error("构建sku插入参数异常", e);
+        }finally {
+            if(StringUtils.isBlank(displayName)){
+                //进行组装
+                displayName = req.getYear() + " " +req.getSport() + " " +req.getManufacturer()+ " " + req.getSets() +(StringUtils.isBlank(req.getSetsVersion())?"": " " + req.getSetsVersion());
+            }
+            req.setName(displayName);
+            String finalDisplayName = displayName;
+            req.getSkus().forEach(sku -> sku.setName(finalDisplayName));
+        }
+    }
+
+    /**
+     * @param req
+     * @param spuId
+     * @param businessType
+     * @return
+     */
+    public static EcologySkuInsertReq builderSkuInsertParam(EcologySkuInsertReq req, Long spuId, String businessType) {
+        String skuCode = RandomUtils.generateRandomString(DomainConstants.SKU, RandomTypeEnums.YYYYMMDD, 16);
+        req.setSpuId(spuId);
+        req.setCode(skuCode);
+        //处理 标签   "recommend,hot" ->  "[\"recommend\", \"hot\"]"
+        if(StringUtils.isNotBlank(req.getTags())) {
+            req.setTags(builderSkuTags(req.getTags()));
+        }
+        //如果没有设置价格 则进行默认处理
+        if(StringUtils.isBlank(req.getBusinessPriceConfig())) {
+            //根据业务类型设置 业务价格
+            switch (ProductBusinessTypeEnums.getByCode(businessType)) {
+                case BUY: //求购
+                    //可设置3阶 价格设置【后续可扩展】 json 数据 {价格,成交概率} 价格默认空
+                    JSONArray jsonArray = new JSONArray();
+                    jsonArray.add(new JSONObject());
+                    jsonArray.add(new JSONObject());
+                    jsonArray.add(new JSONObject());
+                    req.setBusinessPriceConfig("[{\"price\":\"\",\"dealProbability\":\"10\"},{\"price\":\"\",\"dealProbability\":\"60\"},{\"price\":\"\",\"dealProbability\":\"90\"}]");
+                    break;
+                case HOT: //热卖
+                    //设置单阶 价格  默认空
+                    req.setBusinessPriceConfig("[{\"price\":\"\"}]");
+                    break;
+            }
+        }
+        return req;
+    }
+
+    /**
+     *  拆解SKU标签
+     *  "[\"recommend\", \"hot\"]"  ->  "recommend,hot"
+     */
+    public static String parseSkuTags(String tags){
+        if(StringUtils.isNotBlank(tags)){
+            return tags.replaceAll("\"", "").replaceAll("\\[", "").replaceAll("\\]", "").replaceAll(" ", "");
+        }
+        return tags;
+    }
+
+    /**
+     * 转换 sku标签  "recommend,hot" -> "[\"recommend\", \"hot\"]"
+     */
+    public static String builderSkuTags(String tags){
+        if(StringUtils.isNotBlank(tags)){
+            return "[\""+tags.replaceAll(",", "\",\"")+"\"]";
+        }
+        return tags;
+    }
+
 
 }

+ 5 - 4
py-service/src/main/java/com/poyee/service/EcologyGoodsService.java

@@ -4,11 +4,12 @@ import com.poyee.base.dto.Page;
 import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologyMerCustomizeDto;
-import com.poyee.dto.goods.EcologyGoodsPageDto;
+import com.poyee.dto.detail.EcologyGoodsDetailDto;
+import com.poyee.dto.page.EcologyGoodsPageDto;
 import com.poyee.dto.permission.CheckMerPermissionDto;
 import com.poyee.req.EcologyMerCustomizeReq;
-import com.poyee.req.goods.EcologyGoodsBuyPageReq;
-import com.poyee.req.goods.EcologyGoodsPageReq;
+import com.poyee.req.page.EcologyGoodsBuyPageReq;
+import com.poyee.req.page.EcologyGoodsPageReq;
 
 public interface EcologyGoodsService extends BaseService<EcologyMerCustomizeReq, EcologyMerCustomizeDto> {
 
@@ -20,5 +21,5 @@ public interface EcologyGoodsService extends BaseService<EcologyMerCustomizeReq,
 
     Result detailById(Long id);
 
-    Result<EcologyGoodsPageDto> buyTop();
+    Result<EcologyGoodsDetailDto> buyTop();
 }

+ 0 - 3
py-service/src/main/java/com/poyee/service/IEcologyCourierRecordService.java

@@ -1,11 +1,8 @@
 package com.poyee.service;
 
-import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologyCourierRecordDto;
 import com.poyee.req.EcologyCourierRecordReq;
-import com.poyee.entity.EcologyCourierRecord;
-import com.baomidou.mybatisplus.extension.service.IService;
 
 /**
  * <p>

+ 0 - 3
py-service/src/main/java/com/poyee/service/IEcologyGoodsConfigService.java

@@ -1,11 +1,8 @@
 package com.poyee.service;
 
-import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologyGoodsConfigDto;
 import com.poyee.req.EcologyGoodsConfigReq;
-import com.poyee.entity.EcologyGoodsConfig;
-import com.baomidou.mybatisplus.extension.service.IService;
 
 /**
  * <p>

+ 0 - 3
py-service/src/main/java/com/poyee/service/IEcologyOrderInvoiceService.java

@@ -1,11 +1,8 @@
 package com.poyee.service;
 
-import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologyOrderInvoiceDto;
 import com.poyee.req.EcologyOrderInvoiceReq;
-import com.poyee.entity.EcologyOrderInvoice;
-import com.baomidou.mybatisplus.extension.service.IService;
 
 /**
  * <p>

+ 0 - 3
py-service/src/main/java/com/poyee/service/IEcologyOrderItemService.java

@@ -1,11 +1,8 @@
 package com.poyee.service;
 
-import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologyOrderItemDto;
 import com.poyee.req.EcologyOrderItemReq;
-import com.poyee.entity.EcologyOrderItem;
-import com.baomidou.mybatisplus.extension.service.IService;
 
 /**
  * <p>

+ 13 - 0
py-service/src/main/java/com/poyee/service/IEcologySkuService.java

@@ -4,6 +4,12 @@ import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologySkuDto;
 import com.poyee.req.EcologySkuReq;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import com.poyee.req.update.EcologySkuStockReq;
+import com.poyee.req.update.EcologySkuUpReq;
+import com.poyee.req.update.EcologySkuUpdateReq;
+
+import javax.validation.Valid;
 
 /**
  * <p>
@@ -15,4 +21,11 @@ import com.poyee.req.EcologySkuReq;
  */
 public interface IEcologySkuService extends BaseService<EcologySkuReq, EcologySkuDto>  {
 
+    Result updateById( EcologySkuUpdateReq req);
+
+    Result up( EcologySkuUpReq req);
+
+    Result updateStock(@Valid EcologySkuStockReq req);
+
+    Result add(@Valid EcologySkuInsertReq req);
 }

+ 20 - 0
py-service/src/main/java/com/poyee/service/IEcologySpuService.java

@@ -1,9 +1,17 @@
 package com.poyee.service;
 
+import com.poyee.base.dto.Page;
 import com.poyee.base.dto.Result;
 import com.poyee.base.service.BaseService;
 import com.poyee.dto.EcologySpuDto;
+import com.poyee.dto.detail.EcologySpuDetailDto;
+import com.poyee.dto.page.EcologySpuPageDto;
 import com.poyee.req.EcologySpuReq;
+import com.poyee.req.page.EcologySpuPageReq;
+import com.poyee.req.update.EcologySpuReviewReq;
+import com.poyee.req.update.EcologySpuUpReq;
+import com.poyee.req.update.EcologySpuUpdateReq;
+import com.poyee.req.insert.EcologySpuInsertReq;
 import com.poyee.req.sync.EcologySpuSyncReq;
 
 /**
@@ -18,5 +26,17 @@ public interface IEcologySpuService extends BaseService<EcologySpuReq, EcologySp
 
     Result sync(EcologySpuSyncReq req);
 
+    Result save( EcologySpuInsertReq req);
 
+    Result updateById( EcologySpuUpdateReq req);
+
+    Result<EcologySpuDetailDto> detail(Long id);
+
+    Page<EcologySpuPageDto> listPage(EcologySpuPageReq req);
+
+    Result deleteById(Long id);
+
+    Result up(EcologySpuUpReq req);
+
+    Result review(EcologySpuReviewReq req);
 }

+ 104 - 63
py-service/src/main/java/com/poyee/service/impl/EcologyGoodsServiceImpl.java

@@ -1,30 +1,32 @@
 package com.poyee.service.impl;
 
 import com.alibaba.excel.util.StringUtils;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.poyee.annotation.ds.Transactional;
-import com.poyee.base.dto.BaseDto;
+import com.poyee.annotation.ds.CustomTransactional;
 import com.poyee.base.dto.Page;
 import com.poyee.base.dto.Result;
 import com.poyee.base.service.impl.BaseServiceImpl;
 import com.poyee.build.ProductBeanBuildFactory;
 import com.poyee.common.exception.ServiceException;
 import com.poyee.dto.EcologyMerCustomizeDto;
-import com.poyee.dto.goods.EcologyGoodsDetailDto;
-import com.poyee.dto.goods.EcologyGoodsPageDto;
+import com.poyee.dto.detail.EcologyGoodsDetailDto;
+import com.poyee.dto.page.EcologyGoodsPageDto;
 import com.poyee.dto.permission.CheckMerPermissionDto;
-import com.poyee.feign.MerAndUserInfoFeignService;
+import com.poyee.feign.AdminFeignService;
 import com.poyee.mapper.EcologyGoodsMapper;
 import com.poyee.query.CheckMerPermissionQuery;
 import com.poyee.req.EcologyMerCustomizeReq;
-import com.poyee.req.goods.EcologyGoodsBuyPageReq;
-import com.poyee.req.goods.EcologyGoodsBuyReq;
-import com.poyee.req.goods.EcologyGoodsPageReq;
+import com.poyee.req.page.EcologyGoodsBuyPageReq;
+import com.poyee.req.EcologyGoodsBuyReq;
+import com.poyee.req.page.EcologyGoodsPageReq;
 import com.poyee.service.EcologyGoodsService;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -33,7 +35,7 @@ import java.util.stream.Collectors;
 public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper, EcologyMerCustomizeReq, EcologyMerCustomizeDto> implements EcologyGoodsService {
 
     @Autowired
-    protected MerAndUserInfoFeignService merAndUserInfoFeignService;
+    protected AdminFeignService adminFeignService;
 
     /**
      *  检查用户是否有求购令和热卖商品的权限
@@ -46,7 +48,7 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
         checkAndSetMerchantId(req);
         req.setEnabled(1);//启用
         List<CheckMerPermissionDto> list = baseMapper.selectList(req, CheckMerPermissionDto.class);
-        return Result.success(list);
+        return Result.success(0, list);
     }
 
     /**
@@ -55,7 +57,7 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
      * @return
      */
     @Override
-    @Transactional
+    @CustomTransactional
     public Page<EcologyGoodsPageDto> hots(EcologyGoodsPageReq req) {
         checkAndSetMerchantId(req);
         //组装查询实体类对象
@@ -65,7 +67,7 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
         }
         //设置商家业务类型
         if(Objects.nonNull(req.getMerchantId())){
-            Object merInfoRet = merAndUserInfoFeignService.getMerchantId(req.getMerchantId().toString());
+            Object merInfoRet = adminFeignService.getMerchantId(req.getMerchantId().toString());
             log.info("商家信息:{}",merInfoRet);
             if(Objects.nonNull(merInfoRet)){
                 try{
@@ -85,53 +87,66 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
         if(Objects.nonNull(page.getRows())){
             page.getRows().forEach(item->{
                 // "tags": "\"recommend\",\"hot\"" 
-                // 移除前后方括号并去除recommend标签,然后去除前后多余的逗号和空格 
-                String tags = item.getTags();
-                if (tags != null && !tags.isEmpty()) {
-                    // 移除首尾的方括号,移除双引号并按逗号分割
-                    String processedTags = Arrays.stream(tags.replaceAll("^\\[|\\]$", "").split(","))
-                            .map(tag -> tag.trim().replaceAll("^\"|\"$", "")) // 去除每个标签的首尾空格和双引号
-                            .filter(tag -> !tag.isEmpty() && !"recommend".equals(tag)) // 过滤空标签和recommend标签
-                            .collect(Collectors.joining(",")); // 重新用逗号连接
-                    item.setTags(processedTags);
-                } else {
-                    item.setTags("");
-                }
-
+                // 移除前后方括号并去除recommend标签,然后去除前后多余的逗号和空格
+                item.setTags(handleProcessEdTags(item.getTags()));
             });
         }
+        page.setCode(0);
         return page;
     }
 
     @Override
+    @CustomTransactional
     public Page<EcologyGoodsPageDto> buys(EcologyGoodsBuyPageReq req) {
         checkAndSetMerchantId(req);
+        //设置商家业务类型
+        if(Objects.nonNull(req.getMerchantId())){
+            Object merInfoRet = adminFeignService.getMerchantId(req.getMerchantId().toString());
+            log.info("商家信息:{}",merInfoRet);
+            if(Objects.nonNull(merInfoRet)){
+                try{
+                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(merInfoRet));
+                    if(jsonObject.containsKey("merMainBusiness")
+                            &&  StringUtils.isNotBlank(jsonObject.getString("merMainBusiness"))){
+                        req.setMerBusinessType(jsonObject.getString("merMainBusiness"));
+                    }
+                }catch (Exception e){
+                    log.error("获取商家信息异常:{}",e);
+                }
+            }
+        }
         //组装查询实体类对象
         req.setCategory("buy");
-        req.setSpuStatus(300);//显示上架商品
-        req.setShowApplet(1);//显示公域商品
-        req.setSkuStatus(300);//显示上架商品
-        req.setSkuBusinessType("buy");//求购
+        ProductBeanBuildFactory.builderBuysParamByType(req);
         Page<EcologyGoodsPageDto> page = baseMapper.selectPage(req, EcologyGoodsPageDto.class);
         //对查询值进行处理
         if(Objects.nonNull(page.getRows())){
+            //查询当前商家 top 产品 并添加进 page 中 并排到第一位 保留前5个
+            Result<EcologyGoodsDetailDto> buyTop = buyTop();
+            if(Objects.equals(0, buyTop.getCode())) {
+                try {
+                    EcologyGoodsPageDto firstBuy = new EcologyGoodsPageDto();
+                    EcologyGoodsDetailDto buyTopData = (EcologyGoodsDetailDto) buyTop.getData();
+                    BeanUtils.copyProperties(buyTopData, firstBuy);
+                    //移除 id 相同产品
+                    page.getRows().removeIf(item -> Objects.equals(firstBuy.getId(), item.getId()));
+                    page.getRows().add(0, firstBuy);
+                }catch (Exception e){
+                    log.error("获取求购令商品异常:{}",e);
+                }
+            }
+           //对查询值进行处理
             page.getRows().forEach(item->{
                 // "tags": "\"recommend\",\"hot\""
                 // 移除前后方括号并去除recommend标签,然后去除前后多余的逗号和空格
-                String tags = item.getTags();
-                if (tags != null && !tags.isEmpty()) {
-                    // 移除首尾的方括号,移除双引号并按逗号分割
-                    String processedTags = Arrays.stream(tags.replaceAll("^\\[|\\]$", "").split(","))
-                                                 .map(tag -> tag.trim().replaceAll("^\"|\"$", "")) // 去除每个标签的首尾空格和双引号
-                                                 .filter(tag -> !tag.isEmpty() && !"recommend".equals(tag)) // 过滤空标签和recommend标签
-                                                 .collect(Collectors.joining(",")); // 重新用逗号连接
-                    item.setTags(processedTags);
-                } else {
-                    item.setTags("");
-                }
-
+                item.setTags(handleProcessEdTags(item.getTags()));
+                // 处理中间档价格
+                item.setBusinessPriceConfig(handleBuyBusinessPriceConfig(item.getBusinessPriceConfig()));
             });
+            //取得前5条数据
+            page.setRows(page.getRows().stream().limit(5).collect(Collectors.toList()));
         }
+        page.setCode(0);
         return page;
     }
 
@@ -147,18 +162,8 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
                 .orElseThrow(() -> new ServiceException("商品不存在"));
         // "tags": "\"recommend\",\"hot\""
         // 移除前后方括号并去除recommend标签,然后去除前后多余的逗号和空格
-        String tags = baseDto.getTags();
-        if (tags != null && !tags.isEmpty()) {
-            // 移除首尾的方括号,移除双引号并按逗号分割
-            String processedTags = Arrays.stream(tags.replaceAll("^\\[|\\]$", "").split(","))
-                                         .map(tag -> tag.trim().replaceAll("^\"|\"$", "")) // 去除每个标签的首尾空格和双引号
-                                         .filter(tag -> !tag.isEmpty() && !"recommend".equals(tag)) // 过滤空标签和recommend标签
-                                         .collect(Collectors.joining(",")); // 重新用逗号连接
-            baseDto.setTags(processedTags);
-        } else {
-            baseDto.setTags("");
-        }
-        return Result.success(baseDto);
+        baseDto.setTags(handleProcessEdTags(baseDto.getTags()));
+        return Result.success(0,baseDto);
     }
 
     /**
@@ -166,12 +171,13 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
      * @return
      */
     @Override
-    public Result<EcologyGoodsPageDto> buyTop() {
+    public Result<EcologyGoodsDetailDto> buyTop() {
         //设置商家id
         EcologyGoodsBuyReq req = new EcologyGoodsBuyReq();
         checkAndSetMerchantId(req);
         //组装查询实体类对象
         req.setCategory("buy");
+        //todo 上线时 打开注释
 //        req.setSpuStatus(300);//显示上架商品
 //        req.setShowApplet(1);//显示公域商品
 //        req.setSkuStatus(300);//显示上架商品
@@ -180,18 +186,53 @@ public class EcologyGoodsServiceImpl extends BaseServiceImpl<EcologyGoodsMapper,
                                                  .orElseThrow(() -> new ServiceException("商品不存在"));
         // "tags": "\"recommend\",\"hot\""
         // 移除前后方括号并去除recommend标签,然后去除前后多余的逗号和空格
-        String tags = baseDto.getTags();
+        baseDto.setTags(handleProcessEdTags(baseDto.getTags()));
+        return Result.success(0,baseDto);
+    }
+
+    /**
+     * 移除标签
+     * @param tags
+     * @return
+     */
+    private static String handleProcessEdTags(String tags) {
         if (tags != null && !tags.isEmpty()) {
             // 移除首尾的方括号,移除双引号并按逗号分割
-            String processedTags = Arrays.stream(tags.replaceAll("^\\[|\\]$", "").split(","))
-                                         .map(tag -> tag.trim().replaceAll("^\"|\"$", "")) // 去除每个标签的首尾空格和双引号
-                                         .filter(tag -> !tag.isEmpty() && !"recommend".equals(tag)) // 过滤空标签和recommend标签
-                                         .collect(Collectors.joining(",")); // 重新用逗号连接
-            baseDto.setTags(processedTags);
-        } else {
-            baseDto.setTags("");
+            return  Arrays.stream(tags.replaceAll("^\\[|\\]$", "").split(","))
+                                  .map(tag -> tag.trim().replaceAll("^\"|\"$", "")) // 去除每个标签的首尾空格和双引号
+                                  .filter(tag -> !tag.isEmpty() && !"recommend".equals(tag)) // 过滤空标签和recommend标签
+                                  .collect(Collectors.joining(","));
+        }
+        return "";
+    }
+
+    /**
+     * 处理求购 价格 中间档价格
+     */
+    private String handleBuyBusinessPriceConfig(String businessPriceConfig) {
+        if(StringUtils.isNotBlank(businessPriceConfig)){
+            try {
+                JSONArray jsonArray = JSONArray.parseArray(businessPriceConfig);
+                //根据价格进行正序排序, 且取出中间档价格
+                if(!jsonArray.isEmpty()){
+                    jsonArray.sort((o1, o2) -> {
+                        JSONObject jo1 = (JSONObject) o1;
+                        JSONObject jo2 = (JSONObject) o2;
+                        BigDecimal price1 = StringUtils.isNotBlank(jo1.getString("price"))?jo1.getBigDecimal("price") : BigDecimal.ZERO;
+                        BigDecimal price2 = StringUtils.isNotBlank(jo2.getString("price"))?jo2.getBigDecimal("price") : BigDecimal.ZERO;
+                        return price1.compareTo(price2);
+                    });
+                    JSONObject jsonObject = jsonArray.getJSONObject(jsonArray.size() / 2);
+                    JSONArray priceArray = new JSONArray();
+                    priceArray.add(jsonObject);
+                    return priceArray.toJSONString();
+                }
+
+            }catch (Exception e){
+                log.error("处理求购价格中间档价格异常:{}",e);
+            }
         }
-        return Result.success(baseDto);
+        return businessPriceConfig;
     }
 
 

+ 141 - 0
py-service/src/main/java/com/poyee/service/impl/EcologySkuServiceImpl.java

@@ -1,12 +1,29 @@
 package com.poyee.service.impl;
 
+import com.poyee.annotation.ds.CustomTransactional;
+import com.poyee.base.dto.Result;
 import com.poyee.base.service.impl.BaseServiceImpl;
+import com.poyee.build.ProductBeanBuildFactory;
+import com.poyee.common.exception.ServiceException;
 import com.poyee.dto.EcologySkuDto;
+import com.poyee.dto.where.EcologySkuWhereReq;
+import com.poyee.enums.EcologySpuStatusEnum;
 import com.poyee.req.EcologySkuReq;
 import com.poyee.mapper.EcologySkuMapper;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import com.poyee.req.update.EcologySkuStockReq;
+import com.poyee.req.update.EcologySkuUpReq;
+import com.poyee.req.update.EcologySkuUpdateReq;
 import com.poyee.service.IEcologySkuService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 /**
  * <p>
  * B2B产品生态购产品SKU表 服务实现类
@@ -18,4 +35,128 @@ import org.springframework.stereotype.Service;
 @Service
 public class EcologySkuServiceImpl extends BaseServiceImpl<EcologySkuMapper, EcologySkuReq, EcologySkuDto> implements IEcologySkuService {
 
+    /**
+     * @param req
+     * @return
+     */
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result add(EcologySkuInsertReq req) {
+        checkAndPutMerchantId(req);
+        if(Objects.isNull(req.getMerchantId())){
+            //如果merchantId为空 默认设置merchantId = 0 merchantName = '平台运营'
+            req.setMerchantId(0L);
+        }
+        //处理sku 参数
+        EcologySkuInsertReq skuInsertReq = ProductBeanBuildFactory.builderSkuInsertParam(req, req.getSpuId(), req.getBusinessType());
+        log.debug("开始保存SKU数据");
+        int save = baseMapper.save(skuInsertReq);
+        if(save > 0) {
+            return Result.success(0, "商品[sku]添加成功");
+        }
+        return Result.fail("商品[sku]添加失败");
+    }
+    /**
+     * 修改商品信息
+     * @param req
+     * @return
+     */
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result updateById(EcologySkuUpdateReq req) {
+        checkSkuInfo("update", req.getId());
+        //进行后续处理
+        //设置状态为待审核
+        req.setStatus(EcologySpuStatusEnum.WAIT_AUDIT.getCode());
+        //处理 标签   "recommend,hot" ->  "[\"recommend\", \"hot\"]"
+        if(StringUtils.isNotBlank(req.getTags())) {
+            req.setTags(ProductBeanBuildFactory.builderSkuTags(req.getTags()));
+        }
+        int update = baseMapper.update(req);
+        return update > 0 ? Result.success(0, "商品[sku]修改成功") : Result.fail("商品修改失败");
+    }
+
+    /**
+     * 商品上架
+     * @param req
+     * @return
+     */
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result up(EcologySkuUpReq req) {
+        checkSkuInfo("up", req.getId());
+        req.setStatus(req.isUp()? EcologySpuStatusEnum.ON_SHELF.getCode() : EcologySpuStatusEnum.OFF_SHELF.getCode());
+        int update = baseMapper.update(req);
+        if(update > 0){
+            return Result.success(0,"商品[sku]" + (req.isUp()?"上架成功":"下架成功"));
+        }
+        return Result.fail("商品[sku]" + (req.isUp()?"上架失败":"下架失败"));
+    }
+
+    /**
+     * 修改商品库存
+     * @param req
+     * @return
+     */
+    @Override
+    public Result updateStock(EcologySkuStockReq req) {
+        EcologySkuDto skuDto = checkSkuInfo("stock", req.getId());
+        int hasStock = skuDto.getStock() - skuDto.getSoldStock();
+        if(!req.isUp() && (hasStock) < req.getStock() ){
+            throw new ServiceException("商品[sku]库存[减少]不能大于现有库存:"+hasStock);
+        }
+        req.setStock(req.isUp()? req.getStock() : -req.getStock());
+        req.setCreateBy(getUserInfo().getUserId());
+        req.setUpdateTime(new Date());
+        int update = baseMapper.updateStock(req);
+        if(update > 0){
+            return Result.success(0,"商品[sku]库存修改成功");
+        }
+        return Result.fail("商品[sku]库存修改失败");
+    }
+
+    /**
+     * 检测商品信息
+     * @param methodType
+     * @param id
+     */
+    private EcologySkuDto checkSkuInfo(String methodType, Long id){
+        EcologySkuDto sku = Optional.ofNullable(baseMapper.selectById(id))
+                                    .orElseThrow(() -> new ServiceException("商品不存在"));
+        if(getUserInfo().isMerchant() && !Objects.equals(sku.getMerchantId(), Long.valueOf(getUserInfo().getMerchantId()))){
+            log.warn("无权操作[商家越权]");
+            throw new ServiceException("无权操作");
+        }
+        //如果状态为上架状态  则返回异常
+        if( !Objects.equals(methodType,"up")
+                && Objects.equals(EcologySpuStatusEnum.ON_SHELF.getCode(), sku.getStatus())){
+            throw new ServiceException("商品[sku]已上架,请勿此操作");
+        }
+        switch (methodType) {
+            case "update":
+                //如果状态为审核中状态  则返回异常
+                if(Objects.equals(EcologySpuStatusEnum.WAIT_AUDIT.getCode(), sku.getStatus())){
+                    throw new ServiceException("商品[sku]正在审核中,请勿修改");
+                }
+                // 如果状态为审核通过状态  则返回异常
+                if(Objects.equals(EcologySpuStatusEnum.AUDIT_PASS.getCode(), sku.getStatus())){
+                    throw new ServiceException("商品[sku]审核通过,请勿修改");
+                }
+                break;
+            case "delete":
+
+
+                break;
+            case "up":
+
+                break;
+            case "review":
+
+                break;
+
+        }
+        return sku;
+    }
+
+
 }

+ 269 - 4
py-service/src/main/java/com/poyee/service/impl/EcologySpuServiceImpl.java

@@ -1,29 +1,47 @@
 package com.poyee.service.impl;
 
-import com.poyee.annotation.ds.Transactional;
+import com.poyee.annotation.ds.CustomTransactional;
+import com.poyee.base.dto.Page;
 import com.poyee.base.dto.Result;
 import com.poyee.base.service.impl.BaseServiceImpl;
 import com.poyee.build.ProductBeanBuildFactory;
+import com.poyee.common.exception.AuthException;
+import com.poyee.common.exception.ServiceException;
 import com.poyee.dto.EcologyMerCustomizeDto;
 import com.poyee.dto.EcologySkuDto;
 import com.poyee.dto.EcologySpuDto;
-import com.poyee.insert.SkuInsertDao;
-import com.poyee.insert.SpuInsertDao;
+import com.poyee.dto.detail.EcologySkuDetailDto;
+import com.poyee.dto.detail.EcologySpuDetailDto;
+import com.poyee.dto.page.EcologySkuPageDto;
+import com.poyee.dto.page.EcologySpuPageDto;
+import com.poyee.dto.where.EcologySkuWhereReq;
+import com.poyee.entity.SkuInsertDao;
+import com.poyee.entity.SpuInsertDao;
+import com.poyee.enums.EcologySpuStatusEnum;
+import com.poyee.feign.CheckListFeignService;
 import com.poyee.mapper.EcologyMerCustomizeMapper;
 import com.poyee.mapper.EcologySkuMapper;
 import com.poyee.req.EcologyMerCustomizeReq;
 import com.poyee.req.EcologySkuReq;
 import com.poyee.req.EcologySpuReq;
 import com.poyee.mapper.EcologySpuMapper;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import com.poyee.req.page.EcologySkuPageReq;
+import com.poyee.req.page.EcologySpuPageReq;
+import com.poyee.req.update.*;
+import com.poyee.req.insert.EcologySpuInsertReq;
 import com.poyee.req.sync.EcologySpuSyncReq;
 import com.poyee.service.IEcologySpuService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 /**
@@ -43,6 +61,8 @@ public class EcologySpuServiceImpl extends BaseServiceImpl<EcologySpuMapper, Eco
     private EcologySkuMapper skuMapper;
     @Resource
     private EcologyMerCustomizeMapper merCustomizeMapper;
+    @Autowired
+    private CheckListFeignService checkListFeignService;
 
     //业务类型:求购(buy)、热卖(hot) [自动生成暂定类型]
     private List<String> bussinessTypes = Arrays.asList("buy", "hot");
@@ -53,7 +73,7 @@ public class EcologySpuServiceImpl extends BaseServiceImpl<EcologySpuMapper, Eco
      * @return
      */
     @Override
-    @Transactional(rollbackFor = Exception.class)
+    @CustomTransactional(rollbackFor = Exception.class)
     public Result sync(EcologySpuSyncReq req) {
         // build spu 信息
         SpuInsertDao spuInsertDao = ProductBeanBuildFactory.builderInsertParam(req);
@@ -144,6 +164,190 @@ public class EcologySpuServiceImpl extends BaseServiceImpl<EcologySpuMapper, Eco
         return Result.fail("商品新增失败");
     }
 
+    /**
+     *
+     * @param req
+     * @return
+     */
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result save(EcologySpuInsertReq req) {
+        log.debug("开始执行SPU保存操作,事务已启动");
+        checkAndPutMerchantId(req);
+        if(Objects.isNull(req.getMerchantId())){
+            //如果merchantId为空 设置默认 merchantId = 0 merchantName = '平台运营'
+            req.setMerchantId(0L);
+            req.setMerchantName("平台运营");
+        }
+        if(StringUtils.isBlank(req.getName())){
+            //调用接口查询基础库信息
+            Map<String, Object> params = new HashMap<>();
+            params.put("ids", Collections.singletonList(req.getBaseInfoId()));
+            Object paniniBaseInfoRet = checkListFeignService.getPaniniListInfoById(params);
+            ProductBeanBuildFactory.builderSpuInsertPaniniBaseInfo(req ,paniniBaseInfoRet);
+        }
+        SpuInsertDao spuInsertDao = ProductBeanBuildFactory.builderInsertParam(req);
+        Long hasSpu = checkSpu(spuInsertDao);
+        if(Objects.nonNull(hasSpu) && hasSpu > 0){
+            return Result.fail("商品已存在【同商家下的同产品】");
+        }
+        //保存数据
+        log.debug("开始保存SPU数据");
+        int save = baseMapper.save(spuInsertDao);
+        if(save > 0) {
+            Long spuId = spuInsertDao.getId();
+            try {
+                log.debug("SPU数据保存成功,SPU ID: {}", spuId);
+                //判断是否有 skus
+                List<EcologySkuInsertReq> skus = req.getSkus();
+                if (CollectionUtils.isNotEmpty(skus)) {
+                    AtomicInteger skuSuccessCount = new AtomicInteger();
+                    skus.forEach(item -> {
+                        //设置 spuid
+                        item.setSpuId(spuId);
+                        item.setName(req.getName());
+                        //设置商家id, sku code,
+                        item.setMerchantId(req.getMerchantId());
+                        EcologySkuInsertReq skuInsertReq = ProductBeanBuildFactory.builderSkuInsertParam(item, spuId, item.getBusinessType());
+                        log.debug("开始保存SKU数据");
+                        int skuSaveResult = skuMapper.save(skuInsertReq);
+                        log.debug("SKU数据保存结果: {}", skuSaveResult);
+                        skuSuccessCount.set(skuSuccessCount.get() + skuSaveResult);
+                    });
+                    log.debug("SPU保存完成,共保存 {} 个SKU", skuSuccessCount.get());
+                    return Result.success(0,"商品新增成功【" + save + "】,sku新增成功【" + skuSuccessCount.get() + "】");
+                } else {
+                    log.debug("SPU保存完成,无SKU数据");
+                    return Result.success(0,"商品新增成功【" + save + "】");
+                }
+            }catch (Exception e) {
+                //如果新增失败 手动 回滚数据[手动删除已创建好的spu]
+                EcologySkuWhereReq skuWhereReq = new EcologySkuWhereReq();
+                skuWhereReq.setSpuId(spuId);
+                int skuDel = skuMapper.deleteByReq(skuWhereReq);
+                log.debug("已删除SKU数据【{}】", skuDel);
+                //删除spu
+                int del = baseMapper.deleteById(spuId);
+                log.debug("已删除SPU数据【{}】", del);
+            }
+        }
+        log.warn("SPU数据保存失败");
+        return Result.fail("商品新增失败");
+    }
+
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result updateById(EcologySpuUpdateReq req) {
+        checkAndPutMerchantId(req);
+        checkSpuInfo("update" ,req.getId());
+        //只更新限定数据和更新时间更新人
+        //同时状态设置为: WAIT_AUDIT
+        req.setStatus(EcologySpuStatusEnum.WAIT_AUDIT.getCode());
+        int update = baseMapper.update(req);
+        return update > 0 ? Result.success(0,"商品修改成功") : Result.fail("商品修改失败");
+    }
+
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result<EcologySpuDetailDto> detail(Long id) {
+        //获取
+        EcologySpuDetailDto detail = (EcologySpuDetailDto) Optional.of(baseMapper.selectByPrimaryKey(id, EcologySpuDetailDto.class))
+                                                                   .orElseThrow(()->new ServiceException("商品不存在"));
+        //判断商家
+        if(getUserInfo().isMerchant() && !Objects.equals(detail.getMerchantId(), Long.valueOf(getUserInfo().getMerchantId()))){
+            log.warn("无权限访问[越权]");
+            throw new AuthException("无权限访问[越权]");
+        }
+        //查询sku 信息
+        EcologySkuWhereReq req = new EcologySkuWhereReq();
+        req.setSpuId(id);
+        List<EcologySkuDetailDto> skus = skuMapper.selectList(req, EcologySkuDetailDto.class);
+        if(CollectionUtils.isNotEmpty(skus)) {
+            skus.forEach(item -> item.setTags(ProductBeanBuildFactory.parseSkuTags(item.getTags())));
+            detail.setSkus(skus);
+        }
+        return Result.success(0,detail);
+    }
+
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Page<EcologySpuPageDto> listPage(EcologySpuPageReq req) {
+        checkAndPutMerchantId(req);
+        Page<EcologySpuPageDto> page = baseMapper.selectPage(req, EcologySpuPageDto.class);
+        if(page != null && page.getRows() != null && !page.getRows().isEmpty()) {
+            //获取spuId
+            List<Long> spuIds = page.getRows()
+                                  .stream()
+                                  .map(EcologySpuPageDto::getId)
+                                  .filter(Objects::nonNull)
+                                  .distinct()
+                                  .collect(Collectors.toList());
+            EcologySkuPageReq skuPageReq = new EcologySkuPageReq();
+            skuPageReq.setInSpuIds(spuIds);
+            List<EcologySkuPageDto> skus = skuMapper.selectList(skuPageReq, EcologySkuPageDto.class);
+            //根据 spuId 进行 分组
+            if(CollectionUtils.isNotEmpty(skus)) {
+                //对 sku 标签进行处理 "[\"recommend\", \"hot\"]"  ->  "recommend,hot"
+                skus.forEach(item -> item.setTags(ProductBeanBuildFactory.parseSkuTags(item.getTags())));
+                Map<Long, List<EcologySkuPageDto>> skuMap = skus.stream().collect(Collectors.groupingBy(EcologySkuPageDto::getSpuId));
+                page.getRows().forEach(item -> item.setSkus(skuMap.get(item.getId())));
+            }
+        }
+        page.setCode(0);
+        return page;
+    }
+
+    @Override
+    @CustomTransactional(rollbackFor = Exception.class)
+    public Result deleteById(Long id) {
+        checkSpuInfo("delete" ,id);
+        //先删除 sku 信息
+        EcologySkuDelReq skuReq = new EcologySkuDelReq(id, 1);
+        //逻辑删除
+        int del = skuMapper.update(skuReq);
+        if(del > 0){
+            //删除 spu
+            EcologySpuDelReq req = new EcologySpuDelReq(id, 1);
+            int delSpu = baseMapper.update(req);
+            if(delSpu > 0){
+                return Result.success(0,"商品删除成功【" + delSpu + "】");
+            }
+        }
+        return Result.fail("商品删除失败【" + del + "】");
+    }
+
+    @Override
+    public Result up(EcologySpuUpReq req) {
+        checkAndPutMerchantId(req);
+        checkSpuInfo("up" ,req.getId());
+        //如果是下架 设置下架原因
+        if(!req.isUp() && StringUtils.isBlank(req.getReason())){
+            throw new ServiceException("请填写下架原因");
+        }
+        req.setStatus(req.isUp()?EcologySpuStatusEnum.ON_SHELF.getCode():EcologySpuStatusEnum.OFF_SHELF.getCode());
+        int update = baseMapper.update(req);
+        if(update > 0){
+            return Result.success(0,"商品" + (req.isUp()?"上架成功":"下架成功"));
+        }
+        return Result.fail("商品" + (req.isUp()?"上架失败":"下架失败"));
+    }
+
+    @Override
+    public Result review(EcologySpuReviewReq req) {
+        checkAndPutMerchantId(req);
+        checkSpuInfo("review" ,req.getId());
+        //如果是审核驳回 设置审核驳回原因
+        if(!req.isPass() && StringUtils.isBlank(req.getReason())){
+            throw new ServiceException("请填写审核驳回原因");
+        }
+        req.setStatus(req.isPass()?EcologySpuStatusEnum.AUDIT_PASS.getCode():EcologySpuStatusEnum.AUDIT_REJECT.getCode());
+        int update = baseMapper.update(req);
+        if(update > 0){
+            return Result.success(0,"商品" + (req.isPass()?"审核通过成功":"审核驳回成功"));
+        }
+        return Result.fail("商品" + (req.isPass()?"审核通过失败":"审核驳回失败"));
+    }
+
     /**
      * 检查商品
      * @param spuInsertDao
@@ -157,6 +361,8 @@ public class EcologySpuServiceImpl extends BaseServiceImpl<EcologySpuMapper, Eco
         queryReq.setName(null);
         queryReq.setCarouselImgUrl(null);
         queryReq.setDetailImgUrl(null);
+        queryReq.setStatus(null);
+        queryReq.setShowApplet(null);
         queryReq.setSource(spuInsertDao.getSource());
         List<EcologySpuDto> list = baseMapper.selectList(queryReq, EcologySpuDto.class);
         if(CollectionUtils.isNotEmpty(list)){
@@ -166,5 +372,64 @@ public class EcologySpuServiceImpl extends BaseServiceImpl<EcologySpuMapper, Eco
         return null;
     }
 
+    /**
+     * 编辑删除商品时前置验证条件
+     * @param spuId
+     */
+    private void checkSpuInfo(String methodType ,Long spuId) {
+        //判断当前spu 信息
+        EcologySpuDto spuDto = Optional.ofNullable(baseMapper.selectById(spuId))
+                                              .orElseThrow(() -> new ServiceException("商品不存在"));
+        if(getUserInfo().isMerchant() && !Objects.equals(spuDto.getMerchantId(), Long.valueOf(getUserInfo().getMerchantId()))){
+            log.warn("无权操作[商家越权]");
+            throw new AuthException("无权操作[越权]");
+        }
+        //如果状态为上架状态  则返回异常
+        if( !Objects.equals(methodType,"up")
+                && Objects.equals(EcologySpuStatusEnum.ON_SHELF.getCode(), spuDto.getStatus())){
+            throw new ServiceException("商品已上架,请勿此操作");
+        }
+        switch (methodType) {
+            case "update":
+                //如果状态为审核中状态  则返回异常
+                if(Objects.equals(EcologySpuStatusEnum.WAIT_AUDIT.getCode(), spuDto.getStatus())){
+                    throw new ServiceException("商品正在审核中,请勿修改");
+                }
+                // 如果状态为审核通过状态  则返回异常
+                if(Objects.equals(EcologySpuStatusEnum.AUDIT_PASS.getCode(), spuDto.getStatus())){
+                    throw new ServiceException("商品审核通过,请勿修改");
+                }
+            case "delete":
+                //验证 sku
+                EcologySkuWhereReq skuWhereReq = new EcologySkuWhereReq();
+                skuWhereReq.setSpuId(spuId);
+                List<EcologySkuDto> skus = skuMapper.selectList(skuWhereReq, EcologySkuDto.class);
+                if(CollectionUtils.isNotEmpty(skus)){
+                    //判断 sku 状态
+                    long count = skus.stream()
+                                     .filter(item -> Objects.equals(EcologySpuStatusEnum.ON_SHELF.getCode(), item.getStatus()))
+                                     .count();
+                    if(count > 0){
+                        throw new ServiceException("商品存在上架的SKU,请勿此操作");
+                    }
+                }
+                break;
+            case "up":
+                //如果不在审核通过,上架,下架状态中 则返回异常
+                if(!EcologySpuStatusEnum.canUpOperate(spuDto.getStatus())){
+                    throw new ServiceException("商品状态为["+EcologySpuStatusEnum.getDescByCode(spuDto.getStatus())+"],请勿此操作");
+                }
+                break;
+            case "review":
+                //如果状态为审核中状态  则返回异常
+                if(!Objects.equals(EcologySpuStatusEnum.WAIT_AUDIT.getCode(), spuDto.getStatus())){
+                    throw new ServiceException("商品不在审核中状态,请勿此操作");
+                }
+                break;
+        }
+
+    }
+
+
 
 }

+ 76 - 2
py-starter/src/main/java/com/poyee/controller/EcologySkuController.java

@@ -1,11 +1,24 @@
 package com.poyee.controller;
 
+import com.poyee.annotation.Log;
+import com.poyee.annotation.UserLoginToken;
 import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Result;
+import com.poyee.common.enums.BusinessType;
+import com.poyee.common.enums.Roles;
 import com.poyee.dto.EcologySkuDto;
 import com.poyee.req.EcologySkuReq;
+import com.poyee.req.insert.EcologySkuInsertReq;
+import com.poyee.req.update.EcologySkuStockReq;
+import com.poyee.req.update.EcologySkuUpReq;
+import com.poyee.req.update.EcologySkuUpdateReq;
 import com.poyee.service.IEcologySkuService;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
 
 /**
  * <p>
@@ -15,8 +28,69 @@ import org.springframework.web.bind.annotation.RestController;
  * @author lsz
  * @since 2025-11-18
  */
+@Api(tags = "B2B产品 生态购产品SKU")
+@Slf4j
 @RestController
 @RequestMapping("/adm/ecologySku")
 public class EcologySkuController extends BaseController<IEcologySkuService, EcologySkuReq, EcologySkuDto> {
 
+
+    /**
+     * 新增 sku
+     */
+    @Log(title = "新增SKU", businessType = BusinessType.INSERT)
+    @ApiOperation("新增SKU@(admin 1.0.1)")
+    @PostMapping("/add")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result add(@Valid @RequestBody EcologySkuInsertReq req){
+        console("新增SKU", req);
+        return baseService.add(req);
+    }
+
+
+
+    /**
+     * 编辑
+     */
+    @Log(title = "编辑生态购SKU", businessType = BusinessType.UPDATE)
+    @ApiOperation("编辑@(admin 1.0.1)")
+    @PutMapping("/update")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result update(@Valid @RequestBody EcologySkuUpdateReq req){
+        console("编辑生态购SKU", req);
+        return baseService.updateById(req);
+    }
+
+    /**
+     * 上下架
+     */
+    @Log(title = "上下架", businessType = BusinessType.UPDATE)
+    @ApiOperation("上下架@(admin 1.0.1)")
+    @PutMapping("/up")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result updateSaleStatus(@Valid @RequestBody EcologySkuUpReq req){
+        console("上下架", req);
+        return baseService.up(req);
+    }
+
+
+    /**
+     * 库存操作
+     */
+    @Log(title = "库存操作", businessType = BusinessType.UPDATE)
+    @ApiOperation(value = "库存操作@(admin 1.0.1)", notes = "库存操作[根据操作标记:以现有库存为基准 增减 指定数量的库存]")
+    @PutMapping("/stock")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result updateStock(@Valid @RequestBody EcologySkuStockReq req){
+        console("库存操作", req);
+        return baseService.updateStock(req);
+    }
+
+
+
+
 }

+ 129 - 2
py-starter/src/main/java/com/poyee/controller/EcologySpuController.java

@@ -1,11 +1,31 @@
 package com.poyee.controller;
 
+import com.poyee.annotation.Log;
+import com.poyee.annotation.UserLoginToken;
 import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.base.dto.Result;
+import com.poyee.common.enums.BusinessType;
+import com.poyee.common.enums.Roles;
 import com.poyee.dto.EcologySpuDto;
+import com.poyee.dto.detail.EcologySpuDetailDto;
+import com.poyee.dto.page.EcologySpuPageDto;
 import com.poyee.req.EcologySpuReq;
+import com.poyee.req.page.EcologySpuPageReq;
+import com.poyee.req.update.EcologySpuReviewReq;
+import com.poyee.req.update.EcologySpuUpReq;
+import com.poyee.req.update.EcologySpuUpdateReq;
+import com.poyee.req.insert.EcologySpuInsertReq;
 import com.poyee.service.IEcologySpuService;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.Objects;
 
 /**
  * <p>
@@ -15,8 +35,115 @@ import org.springframework.web.bind.annotation.RestController;
  * @author lsz
  * @since 2025-11-18
  */
+@Slf4j
+@Api(tags = "B2B产品 生态购产品(spu)")
 @RestController
 @RequestMapping("/adm/ecologySpu")
 public class EcologySpuController extends BaseController<IEcologySpuService, EcologySpuReq, EcologySpuDto> {
+    
+    /**
+     *  新增生态购SPU
+     * @param req
+     * @return
+     */
+    @Log(title = "新增生态购SPU", businessType = BusinessType.INSERT)
+    @ApiOperation("新增生态购SPU@(admin 1.0.1)")
+    @PostMapping("/save")
+    @UserLoginToken(roles = {Roles.ADMIN, Roles.SHIPPING} )
+    @ResponseBody
+    public Result save( @Valid @RequestBody EcologySpuInsertReq req) {
+        console("新增生态购SPU", req);
+        return baseService.save(req);
+    }
+    
+    /**
+     *  更新生态购SPU
+     * @param req
+     * @return
+     */
+    @Log(title = "更新生态购SPU", businessType = BusinessType.UPDATE)
+    @ApiOperation("根据ID更新生态购SPU@(admin 1.0.1)")
+    @PutMapping("/update")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result update( @Valid @RequestBody EcologySpuUpdateReq req) {
+        console("更新生态购SPU", req);
+        return baseService.updateById(req);
+    }
+    
+    /**
+     *  删除生态购SPU
+     * @param id
+     * @return
+     */
+    @Log(title = "删除生态购SPU", businessType = BusinessType.DELETE)
+    @ApiOperation(value = "根据ID删除SPU@(admin 1.0.1)", notes = "同时删除 sku ")
+    @DeleteMapping("/delete/{id}")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result delete(@ApiParam("生态购SPU ID") @PathVariable Long id) {
+        console("删除生态购SPU", id);
+        if(Objects.isNull(id)){
+            return Result.error("参数错误");
+        }
+        return baseService.deleteById(id);
+    }
+    
+    /**
+     *  查询生态购SPU详情
+     * @param id
+     * @return
+     */
+    @Log(title = "查询生态购SPU详情", businessType = BusinessType.SEARCH)
+    @ApiOperation("根据ID获取生态购SPU详情@(admin 1.0.1)")
+    @GetMapping("/info/{id}")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result<EcologySpuDetailDto> info(@ApiParam("生态购SPU ID") @PathVariable Long id) {
+        console("查询生态购SPU详情", id);
+        return baseService.detail(id);
+    }
+    
+    /**
+     *  分页查询生态购SPU列表
+     * @param req
+     * @return
+     */
+    @Log(title = "分页查询生态购SPU列表", businessType = BusinessType.SEARCH)
+    @ApiOperation("分页查询生态购SPU列表@(admin 1.0.1)")
+    @PostMapping("/page")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Page<EcologySpuPageDto> listPage(@ApiParam("查询条件") @RequestBody EcologySpuPageReq req) {
+        console("分页查询生态购SPU列表", req);
+        return baseService.listPage(req);
+    }
+    
+
+    /**
+     * 上下架
+     */
+    @Log(title = "上下架", businessType = BusinessType.UPDATE)
+    @ApiOperation("上下架@(admin 1.0.1)")
+    @PostMapping("/up")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result up( @RequestBody @Valid EcologySpuUpReq req) {
+        console("上下架", req);
+        return baseService.up(req);
+    }
+
+    /**
+     * 审核
+     */
+    @Log(title = "审核", businessType = BusinessType.UPDATE)
+    @ApiOperation("审核@(admin 1.0.1)")
+    @PostMapping("/review")
+    @UserLoginToken(roles = {Roles.ADMIN,Roles.SHIPPING} )
+    @ResponseBody
+    public Result review( @RequestBody @Valid EcologySpuReviewReq req) {
+        console("审核", req);
+        return baseService.review(req);
+    }
 
 }

+ 4 - 2
py-starter/src/main/resources/application.yml

@@ -48,6 +48,8 @@ logging:
     port: ${FLUENTD_PORT:24225}
 
 # 商家用户信息服务URL配置
-mer-user-info:
-  service:
+feign:
+  admin-service:
     url: http://localhost
+  checklist-service:
+    url: http://localhost:8084

+ 4 - 0
py-starter/src/main/resources/db/V1.0.11__ecology_sku_update.sql

@@ -0,0 +1,4 @@
+ALTER TABLE "ecology_sku"
+    ADD COLUMN "sold_stock" int4 DEFAULT 0;
+
+COMMENT ON COLUMN "ecology_sku"."sold_stock" IS '已售库存';