Commit 810c7ed040242de3672494d6c366532757a70d9e

Authored by puhui999
1 parent c233ce1a

完善商品管理

sql/mysql/optional/mall.sql
... ... @@ -163,19 +163,20 @@ COMMIT;
163 163 -- Table structure for product_property
164 164 -- ----------------------------
165 165 DROP TABLE IF EXISTS `product_property`;
166   -CREATE TABLE `product_property` (
167   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
168   - `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格名称',
169   - `status` tinyint NULL DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用',
170   - `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
171   - `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
172   - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
173   - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
174   - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
175   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
176   - PRIMARY KEY (`id`) USING BTREE,
177   - INDEX `idx_name`(`name`(32) ASC) USING BTREE COMMENT '规格名称索引'
178   -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格名称';
  166 +CREATE TABLE `product_property` (
  167 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  168 + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规格名称',
  169 + `status` tinyint DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用',
  170 + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  171 + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  172 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
  173 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
  174 + `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  175 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  176 + `remark` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
  177 + PRIMARY KEY (`id`) USING BTREE,
  178 + KEY `idx_name` (`name`(32)) USING BTREE COMMENT '规格名称索引'
  179 +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='规格名称';
179 180  
180 181 -- ----------------------------
181 182 -- Records of product_property
... ... @@ -187,19 +188,20 @@ COMMIT;
187 188 -- Table structure for product_property_value
188 189 -- ----------------------------
189 190 DROP TABLE IF EXISTS `product_property_value`;
190   -CREATE TABLE `product_property_value` (
191   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
192   - `property_id` bigint NULL DEFAULT NULL COMMENT '规格键id',
193   - `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格值名字',
194   - `status` tinyint NULL DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用',
195   - `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
196   - `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
197   - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
198   - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
199   - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
200   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
201   - PRIMARY KEY (`id`) USING BTREE
202   -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格值';
  191 +CREATE TABLE `product_property_value` (
  192 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  193 + `property_id` bigint DEFAULT NULL COMMENT '规格键id',
  194 + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规格值名字',
  195 + `status` tinyint DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用',
  196 + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  197 + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  198 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
  199 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
  200 + `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  201 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  202 + `remark` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
  203 + PRIMARY KEY (`id`) USING BTREE
  204 +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='规格值';
203 205  
204 206 -- ----------------------------
205 207 -- Records of product_property_value
... ... @@ -325,3 +327,36 @@ INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `
325 327 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
326 328 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
327 329  
  330 +INSERT INTO `system_dict_data`(`sort`,`label`,`value`,`dict_type`,`status`,`color_type`,`css_class`,`remark`,`creator`,`create_time`,`updater`,`update_time`,`deleted`) VALUES
  331 + (1,'打',2,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  332 + (1,'盒',3,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  333 + (1,'袋',4,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  334 + (1,'箱',5,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  335 + (1,'套',6,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  336 + (1,'包',7,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  337 + (1,'双',8,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  338 + (1,'卷',9,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  339 + (1,'张',10,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  340 + (1,'克',11,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  341 + (1,'千克',12,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  342 + (1,'毫克',13,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  343 + (1,'微克',14,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  344 + (1,'吨',15,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  345 + (1,'升',16,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  346 + (1,'毫升',17,'product_unit',0,'','','',1, NOW(),1, NOW(),0),
  347 + (1, '平方米', 18, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  348 + (1, '平方千米', 19, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  349 + (1, '平方英里', 20, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  350 + (1, '平方码', 21, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  351 + (1, '平方英尺', 22, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  352 + (1, '立方米', 23, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  353 + (1, '立方厘米', 24, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  354 + (1, '立方英寸', 25, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  355 + (1, '米', 26, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  356 + (1, '千米', 27, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  357 + (1, '厘米', 28, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  358 + (1, '毫米', 29, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  359 + (1, '英寸', 30, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  360 + (1, '英尺', 31, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  361 + (1, '码', 32, 'product_unit', 0, '', '', '', 1, NOW(), 1, NOW(), 0),
  362 + (1,'个',1,'product_unit',0,'','','',1, NOW(),1, NOW(),0);
328 363 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuTabTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.enums.spu;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 商品spu标签枚举类型
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum ProductSpuTabTypeEnum {
  14 + FOR_SALE(0,"出售中商品"),
  15 + IN_WAREHOUSE(1,"仓库中商品"),
  16 + SOLD_OUT(2,"已售空商品"),
  17 + ALERT_STOCK(3,"警戒库存"),
  18 + RECYCLE_BIN(4,"商品回收站");
  19 + /**
  20 + * 状态
  21 + */
  22 + private final Integer type;
  23 + /**
  24 + * 状态名
  25 + */
  26 + private final String name;
  27 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
... ... @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*;
21 21 import javax.annotation.Resource;
22 22 import javax.validation.Valid;
23 23 import java.util.List;
  24 +import java.util.Map;
24 25  
25 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 27 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -54,6 +55,14 @@ public class ProductSpuController {
54 55 return success(true);
55 56 }
56 57  
  58 + @PutMapping("/updateStatus")
  59 + @Operation(summary = "更新商品 SPU Status")
  60 + @PreAuthorize("@ss.hasPermission('product:spu:update')")
  61 + public CommonResult<Boolean> updateStatus(@Valid @RequestBody ProductSpuUpdateStatusReqVO updateReqVO) {
  62 + productSpuService.updateStatus(updateReqVO);
  63 + return success(true);
  64 + }
  65 +
57 66 @DeleteMapping("/delete")
58 67 @Operation(summary = "删除商品 SPU")
59 68 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -85,5 +94,11 @@ public class ProductSpuController {
85 94 public CommonResult<PageResult<ProductSpuPageRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
86 95 return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
87 96 }
  97 + @GetMapping("/tabsCount")
  98 + @Operation(summary = "获得商品 SPU tabsCount")
  99 + @PreAuthorize("@ss.hasPermission('product:spu:query')")
  100 + public CommonResult<Map<Integer, Long>> getTabsCount() {
  101 + return success(productSpuService.getTabsCount());
  102 + }
88 103  
89 104 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
... ... @@ -5,6 +5,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
8 13  
9 14 @Schema(description = "管理后台 - 商品 SPU 分页 Request VO")
10 15 @Data
... ... @@ -15,7 +20,11 @@ public class ProductSpuPageReqVO extends PageParam {
15 20 @Schema(description = "商品名称", example = "yutou")
16 21 private String name;
17 22  
18   - @Schema(description = "分类编号", example = "1")
19   - private Long categoryId;
  23 + @Schema(description = "前端请求的tab类型", example = "1")
  24 + private Integer tabType;
  25 +
  26 + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
  27 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  28 + private LocalDateTime[] createTime;
20 29  
21 30 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
  2 +
  3 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.NotNull;
  11 +import java.util.List;
  12 +
  13 +@Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO")
  14 +@Data
  15 +public class ProductSpuUpdateStatusReqVO{
  16 +
  17 + @Schema(description = "商品编号", required = true, example = "1")
  18 + @NotNull(message = "商品编号不能为空")
  19 + private Long id;
  20 +
  21 + @Schema(description = "商品状态", required = true, example = "1")
  22 + @NotNull(message = "商品状态不能为空")
  23 + private Integer status;
  24 +
  25 +
  26 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
1 1 package cn.iocoder.yudao.module.product.dal.mysql.spu;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.hutool.core.util.StrUtil;
3 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 7 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
6 9 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
7 10 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
8 11 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
  12 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
  13 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuTabTypeEnum;
9 14 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
10 15 import org.apache.ibatis.annotations.Mapper;
11 16  
  17 +import java.util.Map;
12 18 import java.util.Objects;
13 19 import java.util.Set;
14 20  
... ... @@ -20,29 +26,51 @@ import java.util.Set;
20 26 @Mapper
21 27 public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
22 28  
  29 + //default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO) {
  30 + // return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
  31 + // .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
  32 + // .orderByDesc(ProductSpuDO::getSort));
  33 + //}
23 34 default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO) {
24 35 return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
  36 + // 商品名称
25 37 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
26   - .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
  38 + .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
  39 + // 出售中商品
  40 + .eq(ProductSpuTabTypeEnum.FOR_SALE.getType().equals(reqVO.getTabType()),ProductSpuDO::getStatus,ProductSpuStatusEnum.ENABLE.getStatus())
  41 + // 仓储中商品
  42 + .eq(ProductSpuTabTypeEnum.IN_WAREHOUSE.getType().equals(reqVO.getTabType()),ProductSpuDO::getStatus,ProductSpuStatusEnum.DISABLE.getStatus())
  43 + // 已售空商品
  44 + .eq(ProductSpuTabTypeEnum.SOLD_OUT.getType().equals(reqVO.getTabType()),ProductSpuDO::getStock,0)
  45 + // TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换
  46 + .le(ProductSpuTabTypeEnum.ALERT_STOCK.getType().equals(reqVO.getTabType()),ProductSpuDO::getStock,10)
  47 + // 回收站
  48 + .eq(ProductSpuTabTypeEnum.RECYCLE_BIN.getType().equals(reqVO.getTabType()),ProductSpuDO::getStatus,ProductSpuStatusEnum.RECYCLE.getStatus())
27 49 .orderByDesc(ProductSpuDO::getSort));
28 50 }
29 51  
30   - default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO, Set<Long> alarmStockSpuIds) {
31   - return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
32   - .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
33   - .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
34   - .inIfPresent(ProductSpuDO::getId, alarmStockSpuIds) // 库存告警
35   - .orderByDesc(ProductSpuDO::getSort));
36   - }
37   -
38   - default PageResult<ProductSpuDO> selectPage(AppProductSpuPageReqVO pageReqVO, Integer status) {
  52 + /**
  53 + * 获得商品 SPU 分页,提供给用户 App 使用
  54 + */
  55 + default PageResult<ProductSpuDO> selectPage(AppProductSpuPageReqVO pageReqVO, Set<Long> categoryIds) {
39 56 LambdaQueryWrapperX<ProductSpuDO> query = new LambdaQueryWrapperX<ProductSpuDO>()
40   - .eqIfPresent(ProductSpuDO::getCategoryId, pageReqVO.getCategoryId())
41   - .eqIfPresent(ProductSpuDO::getStatus, status);
  57 + .likeIfPresent(ProductSpuDO::getName, pageReqVO.getKeyword()) // 关键字匹配,目前只匹配商品名
  58 + .inIfPresent(ProductSpuDO::getCategoryId, categoryIds); // 分类
  59 + query.eq(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()) // 上架状态
  60 + .gt(ProductSpuDO::getStock, 0); // 有库存
  61 + // 推荐类型的过滤条件
  62 + if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_HOT)) {
  63 + query.eq(ProductSpuDO::getRecommendHot, true);
  64 + }
42 65 // 排序逻辑
43   - if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
44   - } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
45   - query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount);
  66 + if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
  67 + query.last(String.format(" ORDER BY (sales_count + virtual_sales_count) %s, sort DESC, id DESC",
  68 + pageReqVO.getSortAsc() ? "ASC" : "DESC"));
  69 + } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
  70 + query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getPrice)
  71 + .orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId);
  72 + } else {
  73 + query.orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId);
46 74 }
47 75 return selectPage(pageReqVO, query);
48 76 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
... ... @@ -75,7 +75,7 @@ public interface ProductSpuService {
75 75 List<ProductSpuDO> getSpuList();
76 76  
77 77 /**
78   - * 获得商品 SPU 分页
  78 + * 获得商品 SPU 分页,提供给挂你兰后台使用
79 79 *
80 80 * @param pageReqVO 分页查询
81 81 * @return 商品spu分页
... ... @@ -83,13 +83,12 @@ public interface ProductSpuService {
83 83 PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO);
84 84  
85 85 /**
86   - * 获得商品 SPU 分页
  86 + * 获得商品 SPU 分页,提供给用户 App 使用
87 87 *
88 88 * @param pageReqVO 分页查询
89   - * @param status 状态
90 89 * @return 商品 SPU 分页
91 90 */
92   - PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status);
  91 + PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO);
93 92  
94 93 /**
95 94 * 更新商品 SPU 库存(增量)
... ... @@ -105,4 +104,18 @@ public interface ProductSpuService {
105 104 * @return {@link ProductSpuDetailRespVO}
106 105 */
107 106 ProductSpuDetailRespVO getSpuDetail(Long id);
  107 +
  108 + /**
  109 + * 更新状态
  110 + *
  111 + * @param updateReqVO 更新请求签证官
  112 + */
  113 + void updateStatus(ProductSpuUpdateStatusReqVO updateReqVO);
  114 +
  115 + /**
  116 + * 获取spu列表标签对应的Count数量
  117 + *
  118 + * @return {@link Map}<{@link Integer}, {@link Integer}>
  119 + */
  120 + Map<Integer, Long> getTabsCount();
108 121 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.spu;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.convert.Convert;
  5 +import cn.hutool.core.util.ObjectUtil;
4 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  9 +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6 10 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
7 11 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
8   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
9   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO;
10   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
11   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
12 13 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
13 14 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
14 15 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
... ... @@ -16,11 +17,13 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
16 17 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
17 18 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
18 19 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
  20 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuTabTypeEnum;
19 21 import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
20 22 import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
21 23 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
22 24 import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
23 25 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
  26 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
24 27 import org.springframework.context.annotation.Lazy;
25 28 import org.springframework.stereotype.Service;
26 29 import org.springframework.transaction.annotation.Transactional;
... ... @@ -62,7 +65,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
62 65 public Long createSpu(ProductSpuCreateReqVO createReqVO) {
63 66 // 校验分类 TODO 暂不清楚为什么只能选择第三层的结点
64 67 //validateCategory(createReqVO.getCategoryId());
65   - // 校验品牌 TODO 暂不校验
  68 + // 校验品牌 TODO 暂不校验,前端没有做品牌选择
66 69 //brandService.validateProductBrand(createReqVO.getBrandId());
67 70  
68 71 List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = createReqVO.getSkus();
... ... @@ -84,14 +87,13 @@ public class ProductSpuServiceImpl implements ProductSpuService {
84 87 public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
85 88 // 校验 SPU 是否存在
86 89 validateSpuExists(updateReqVO.getId());
87   - // 校验分类
88   - validateCategory(updateReqVO.getCategoryId());
89   - // 校验品牌
90   - brandService.validateProductBrand(updateReqVO.getBrandId());
  90 + // 校验分类 TODO 暂不清楚为什么只能选择第三层的结点
  91 + //validateCategory(updateReqVO.getCategoryId());
  92 + // 校验品牌 TODO 暂不校验,前端没有做品牌选择
  93 + //brandService.validateProductBrand(updateReqVO.getBrandId());
91 94 // 校验SKU
92 95 List<ProductSkuCreateOrUpdateReqVO> skuSaveReqList = updateReqVO.getSkus();
93 96 productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());
94   -
95 97 // 更新 SPU
96 98 ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
97 99 initSpuFromSkus(updateObj, skuSaveReqList);
... ... @@ -176,21 +178,13 @@ public class ProductSpuServiceImpl implements ProductSpuService {
176 178  
177 179 @Override
178 180 public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
179   - // 库存告警的 SPU 编号的集合 TODO 一个接口一个接口来
180   - Set<Long> alarmStockSpuIds = null;
181   - //if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
182   - // alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkuListByAlarmStock(), ProductSkuDO::getSpuId);
183   - // if (CollUtil.isEmpty(alarmStockSpuIds)) {
184   - // return PageResult.empty();
185   - // }
186   - //}
187   - // 分页查询
188   - return productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds);
  181 + return productSpuMapper.selectPage(pageReqVO);
189 182 }
190 183  
191 184 @Override
192   - public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status) {
193   - return productSpuMapper.selectPage(pageReqVO, status);
  185 + public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
  186 + //return productSpuMapper.selectPage(pageReqVO); TODO 有差异接口接受参数类型不对
  187 + return null;
194 188 }
195 189  
196 190 @Override
... ... @@ -211,15 +205,45 @@ public class ProductSpuServiceImpl implements ProductSpuService {
211 205 List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
212 206 if (CollUtil.isNotEmpty(skus)){
213 207 List<ProductSkuRespVO> skuRespVoS = ProductSkuConvert.INSTANCE.convertList(skus);
214   - // 获取所有的属性值id
215   - Set<Long> valueIds = skus.stream().flatMap(p -> p.getProperties().stream()).map(ProductSkuDO.Property::getValueId).collect(Collectors.toSet());
216   - List<ProductPropertyValueDetailRespBO> valueDetailList = productPropertyValueService.getPropertyValueDetailList(valueIds);
217   - Map<Long, String> stringMap = valueDetailList.stream().collect(Collectors.toMap(ProductPropertyValueDetailRespBO::getValueId, ProductPropertyValueDetailRespBO::getValueName));
218   - // 设置属性值名称
219   - skuRespVoS.stream().flatMap(p -> p.getProperties().stream()).forEach(item ->item.setValueName(stringMap.get(item.getValueId())));
  208 + // 非多规格,不需要处理
  209 + if (ObjectUtil.equal(productSpuDetailRespVO.getSpecType(), true)) {
  210 + // 获取所有的属性值id
  211 + Set<Long> valueIds = skus.stream().flatMap(p -> p.getProperties().stream()).map(ProductSkuDO.Property::getValueId).collect(Collectors.toSet());
  212 + List<ProductPropertyValueDetailRespBO> valueDetailList = productPropertyValueService.getPropertyValueDetailList(valueIds);
  213 + Map<Long, String> stringMap = valueDetailList.stream().collect(Collectors.toMap(ProductPropertyValueDetailRespBO::getValueId, ProductPropertyValueDetailRespBO::getValueName));
  214 + // 设置属性值名称
  215 + skuRespVoS.stream().flatMap(p -> p.getProperties().stream()).forEach(item ->item.setValueName(stringMap.get(item.getValueId())));
  216 + }
220 217 productSpuDetailRespVO.setSkus(skuRespVoS);
221 218 }
222 219 return productSpuDetailRespVO;
223 220 }
224 221  
  222 + @Override
  223 + @Transactional(rollbackFor = Exception.class)
  224 + public void updateStatus(ProductSpuUpdateStatusReqVO updateReqVO) {
  225 + // 校验存在
  226 + validateSpuExists(updateReqVO.getId());
  227 + // 更新状态
  228 + ProductSpuDO productSpuDO = productSpuMapper.selectById(updateReqVO.getId()).setStatus(updateReqVO.getStatus());
  229 + productSpuMapper.updateById(productSpuDO);
  230 +
  231 + }
  232 +
  233 + @Override
  234 + public Map<Integer, Long> getTabsCount() {
  235 + Map<Integer, Long> map = new HashMap<>();
  236 + // 查询销售中的商品数量
  237 + map.put(ProductSpuTabTypeEnum.FOR_SALE.getType(), productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()));
  238 + // 查询仓库中的商品数量
  239 + map.put(ProductSpuTabTypeEnum.IN_WAREHOUSE.getType(),productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus()));
  240 + // 查询售空的商品数量
  241 + map.put(ProductSpuTabTypeEnum.SOLD_OUT.getType(),productSpuMapper.selectCount(ProductSpuDO::getStock, 0));
  242 + // 查询触发警戒库存的商品数量 TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换
  243 + map.put(ProductSpuTabTypeEnum.ALERT_STOCK.getType(),productSpuMapper.selectCount(new LambdaQueryWrapperX<ProductSpuDO>().le(ProductSpuDO::getStock, 10)));
  244 + // 查询回收站中的商品数量
  245 + map.put(ProductSpuTabTypeEnum.RECYCLE_BIN.getType(),productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
  246 + return map;
  247 + }
  248 +
225 249 }
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -189,7 +189,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
189 189 });
190 190 productSpuMapper.insert(createReqVO);
191 191  
192   - Set<Long> alarmStockSpuIds = SetUtils.asSet(createReqVO.getId());
  192 + //Set<Long> alarmStockSpuIds = SetUtils.asSet(createReqVO.getId()); TODO 查询接口已改变没有使用到这个变量
193 193  
194 194 List<ProductSkuDO> productSpuDOS = Arrays.asList(randomPojo(ProductSkuDO.class, o -> {
195 195 o.setSpuId(createReqVO.getId());
... ... @@ -204,7 +204,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
204 204 //productSpuPageReqVO.setAlarmStock(true);
205 205 PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
206 206  
207   - PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
  207 + PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO));
208 208 Assertions.assertIterableEquals(result.getList(), spuPage.getList());
209 209 assertEquals(spuPage.getTotal(), result.getTotal());
210 210 }
... ... @@ -249,14 +249,15 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
249 249  
250 250 // 调用
251 251 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
  252 + // TODO 已暂时没有相关属性,等用到时再添加
252 253 //productSpuPageReqVO.setAlarmStock(false);
253 254 //productSpuPageReqVO.setBrandId(brandId);
254 255 //productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
255   - productSpuPageReqVO.setCategoryId(categoryId);
  256 + //productSpuPageReqVO.setCategoryId(categoryId);
256 257  
257 258 PageResult<ProductSpuDO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
258 259  
259   - PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
  260 + PageResult<ProductSpuPageRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO));
260 261 assertEquals(result, spuPage);
261 262 }
262 263  
... ...