Commit d92d2576196ffca0e881385194d496efda26c91f

Authored by luowenfeng
2 parents dc4e3fcd 7bf37fcb

Merge branch 'feature/1.8.0-uniapp' of https://gitee.com/zhijiantianya/ruoyi-vue…

…-pro into feature/1.8.0-uniapp

 Conflicts:
	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
Showing 16 changed files with 133 additions and 193 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java
... ... @@ -31,7 +31,7 @@ public class SpuInfoRespDTO {
31 31 */
32 32 private String code;
33 33 /**
34   - * 商品卖点
  34 + * 促销语
35 35 */
36 36 private String sellPoint;
37 37 /**
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
5 4 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
6 5 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
7 6 import io.swagger.annotations.ApiModelProperty;
... ... @@ -25,7 +24,7 @@ public class ProductSpuBaseVO {
25 24 @ApiModelProperty(value = "商品编码", example = "yudaoyuanma")
26 25 private String code;
27 26  
28   - @ApiModelProperty(value = "商品卖点", example = "好吃!")
  27 + @ApiModelProperty(value = "促销语", example = "好吃!")
29 28 private String sellPoint;
30 29  
31 30 @ApiModelProperty(value = "商品详情", required = true, example = "我是商品描述")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2  
3   -import lombok.*;
4   -import java.util.*;
5   -import io.swagger.annotations.*;
6 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
7   -import org.springframework.format.annotation.DateTimeFormat;
8   -
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
10 9  
11 10 @ApiModel("管理后台 - 商品 SPU 分页 Request VO")
12 11 @Data
... ... @@ -26,7 +25,7 @@ public class ProductSpuPageReqVO extends PageParam {
26 25 @ApiModelProperty(value = "商品品牌编号", example = "1")
27 26 private Long brandId;
28 27  
29   - @ApiModelProperty(value = "上下架状态", example = "1", notes = "参见 CommonStatusEnum 枚举值")
  28 + @ApiModelProperty(value = "上下架状态", example = "1", notes = "参见 ProductSpuStatusEnum 枚举值")
30 29 private Integer status;
31 30  
32 31 @ApiModelProperty(value = "销量最小值", example = "1")
... ... @@ -41,8 +40,7 @@ public class ProductSpuPageReqVO extends PageParam {
41 40 @ApiModelProperty(value = "市场价最大值", example = "1024")
42 41 private Integer marketPriceMax;
43 42  
44   - // TODO @luowenfeng: 这个可以改成前端基于 tab, 传递不同的条件么?
45   - @ApiModelProperty(value = "tab 状态 null 全部, 0:销售中(上架) 1:仓库中(下架) 2:预警中", example = "1")
46   - private Integer tabStatus;
  43 + @ApiModelProperty(value = "是否库存告警", example = "true")
  44 + private Boolean alarmStock;
47 45  
48 46 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
... ... @@ -47,7 +47,7 @@ public class ProductSpuDO extends BaseDO {
47 47 */
48 48 private String code;
49 49 /**
50   - * 商品卖点
  50 + * 促销语
51 51 */
52 52 private String sellPoint;
53 53 /**
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
... ... @@ -40,7 +40,7 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
40 40 }
41 41 }
42 42  
43   - default List<ProductSkuDO> selectListByRemind(){
  43 + default List<ProductSkuDO> selectListByAlarmStock(){
44 44 return selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
45 45 }
46 46  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReq
7 7 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
10   -import java.util.List;
  10 +import java.util.Set;
11 11  
12 12 /**
13 13 * 商品spu Mapper
... ... @@ -29,8 +29,8 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
29 29 .orderByDesc(ProductSpuDO::getSort));
30 30 }
31 31  
32   - default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO, List<Long> spuIds) {
33   - LambdaQueryWrapperX<ProductSpuDO> productSpuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<ProductSpuDO>()
  32 + default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO, Set<Long> alarmStockSpuIds) {
  33 + return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
34 34 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
35 35 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
36 36 .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
... ... @@ -38,16 +38,9 @@ public interface ProductSpuMapper extends BaseMapperX&lt;ProductSpuDO&gt; {
38 38 .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
39 39 .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
40 40 .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
41   - .orderByDesc(ProductSpuDO::getSort);
42   - // TODO @芋艿: 需要优化下这里的代码
43   - if(reqVO.getTabStatus()!= null && reqVO.getTabStatus() == 2){
44   - productSpuDOLambdaQueryWrapperX.inIfPresent(ProductSpuDO::getId, spuIds);
45   - }else{
46   - productSpuDOLambdaQueryWrapperX.eqIfPresent(ProductSpuDO::getStatus, reqVO.getTabStatus());
47   - }
48   -
49   - return selectPage(reqVO, productSpuDOLambdaQueryWrapperX);
  41 + .inIfPresent(ProductSpuDO::getId, alarmStockSpuIds) // 库存告警
  42 + .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
  43 + .orderByDesc(ProductSpuDO::getSort));
50 44 }
51 45  
52   -
53 46 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.product.service.sku;
3 3 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
4 4 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
5 5  
6   -import javax.validation.Valid;
7 6 import java.util.Collection;
8 7 import java.util.List;
9 8  
... ... @@ -84,10 +83,10 @@ public interface ProductSkuService {
84 83 void deleteSkuBySpuId(Long spuId);
85 84  
86 85 /**
87   - * 获得商品预警中的 SPU 集合
  86 + * 获得库存预警的 SKU 数组
88 87 *
89   - * @return 商品spuId集合
  88 + * @return SKU 数组
90 89 */
91   - List<ProductSkuDO> getRemindSpuIds();
  90 + List<ProductSkuDO> getSkusByAlarmStock();
92 91  
93 92 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.sku;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.collection.CollectionUtil;
5 3 import cn.hutool.core.util.ObjectUtil;
6   -import cn.hutool.core.util.StrUtil;
7 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
9 5 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
10 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
11 7 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
... ... @@ -17,18 +13,15 @@ import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
17 13 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
18 14 import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
19 15 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
20   -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
21 16 import org.springframework.stereotype.Service;
22 17 import org.springframework.transaction.annotation.Transactional;
23 18 import org.springframework.validation.annotation.Validated;
24 19  
25 20 import javax.annotation.Resource;
26 21 import java.util.*;
27   -import java.util.function.Function;
28 22 import java.util.stream.Collectors;
29 23  
30 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
32 25 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
33 26  
34 27 /**
... ... @@ -138,8 +131,8 @@ public class ProductSkuServiceImpl implements ProductSkuService {
138 131 }
139 132  
140 133 @Override
141   - public List<ProductSkuDO> getRemindSpuIds() {
142   - return productSkuMapper.selectListByRemind();
  134 + public List<ProductSkuDO> getSkusByAlarmStock() {
  135 + return productSkuMapper.selectListByAlarmStock();
143 136 }
144 137  
145 138 @Override
... ...
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.bean.BeanUtil;
  4 +import cn.hutool.core.collection.CollUtil;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 7 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
... ... @@ -28,10 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
28 29 import org.springframework.validation.annotation.Validated;
29 30  
30 31 import javax.annotation.Resource;
31   -import java.util.ArrayList;
32   -import java.util.Collection;
33   -import java.util.List;
34   -import java.util.Map;
  32 +import java.util.*;
35 33 import java.util.stream.Collectors;
36 34  
37 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -180,18 +178,21 @@ public class ProductSpuServiceImpl implements ProductSpuService {
180 178  
181 179 @Override
182 180 public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
183   - List<Long> remindSpuIds = null;
184   - if (pageReqVO.getTabStatus() != null && pageReqVO.getTabStatus() == 2) {
185   - remindSpuIds = productSkuService.getRemindSpuIds().stream().map(ProductSkuDO::getSpuId).distinct().collect(Collectors.toList());
186   - if (remindSpuIds.isEmpty()) {
187   - remindSpuIds.add(null);
  181 + // 库存告警的 SPU 编号的集合
  182 + Set<Long> alarmStockSpuIds = null;
  183 + if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) {
  184 + alarmStockSpuIds = CollectionUtils.convertSet(productSkuService.getSkusByAlarmStock(), ProductSkuDO::getSpuId);
  185 + if (CollUtil.isEmpty(alarmStockSpuIds)) {
  186 + return PageResult.empty();
188 187 }
189 188 }
190   - return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, remindSpuIds));
  189 + // 分页查询
  190 + return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds));
191 191 }
192 192  
193 193 @Override
194 194 public PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO) {
  195 + // TODO 芋艿:貌似实现不太合理
195 196 PageResult<ProductSpuDO> productSpuDOPageResult = productSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
196 197 PageResult<AppSpuPageRespVO> pageResult = new PageResult<>();
197 198 // TODO @芋艿 这里用convert如何解决
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -208,6 +208,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
208 208 Assertions.assertIterableEquals(createReqVO, spuList);
209 209 }
210 210  
  211 + // TODO @luowenfeng:单测要分情况;类似你这个,可以分 2 个单测;一个是有预存预警的;一个是没库存预警的;
  212 + // 然后,参考其它模块的 getPage 类型的方法的单测。
211 213 @Test
212 214 void getSpuPage() {
213 215 // 准备参数
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order;
3 3 import cn.hutool.core.bean.BeanUtil;
4 4 import cn.hutool.core.text.StrBuilder;
5 5 import cn.hutool.core.util.IdUtil;
6   -import cn.hutool.core.util.StrUtil;
7 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 7 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
9 8 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
... ... @@ -15,8 +14,8 @@ import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO;
15 14 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
16 15 import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO;
17 16 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
18   -import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
19 17 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  18 +import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
20 19 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
21 20 import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO;
22 21 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
... ... @@ -181,7 +180,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
181 180  
182 181 private void checkSaleableFromSpu(List<SpuInfoRespDTO> spuInfos) {
183 182 SpuInfoRespDTO spu = CollectionUtils.findFirst(spuInfos,
184   - spuInfoDTO -> !Objects.equals(ProductSpuStatusEnum.ENABLE.getStyle(), spuInfoDTO.getStatus()));
  183 + spuInfoDTO -> !Objects.equals(ProductSpuStatusEnum.ENABLE.getStatus(), spuInfoDTO.getStatus()));
185 184 if (Objects.isNull(spu)) {
186 185 throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SPU_NOT_SALE);
187 186 }
... ...
yudao-server/src/main/resources/application-local.yaml
... ... @@ -45,33 +45,33 @@ spring:
45 45 datasource:
46 46 master:
47 47 name: ruoyi-vue-pro
48   - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
  48 + url: jdbc:mysql://139.9.196.247:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
49 49 # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
50 50 # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
51 51 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
52 52 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例
53 53 username: root
54   - password: 123456
  54 + password: ${RUOYI_VUE_PRO}
55 55 # username: sa
56 56 # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
57 57 slave: # 模拟从库,可根据自己需要修改
58 58 name: ruoyi-vue-pro
59   - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
  59 + url: jdbc:mysql://139.9.196.247:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
60 60 # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
61 61 # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例
62 62 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
63 63 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.slave.name} # SQLServer 连接的示例
64 64 username: root
65   - password: 123456
  65 + password: ${RUOYI_VUE_PRO}
66 66 # username: sa
67 67 # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
68 68  
69 69 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
70 70 redis:
71   - host: 127.0.0.1 # 地址
  71 + host: 139.9.196.247 # 地址
72 72 port: 6379 # 端口
73 73 database: 0 # 数据库索引
74   -# password: 123456 # 密码,建议生产环境开启
  74 + password: 123456 # 密码,建议生产环境开启
75 75  
76 76 jasypt:
77 77 encryptor:
... ...
yudao-ui-admin/src/utils/constants.js
... ... @@ -185,37 +185,54 @@ export const PayOrderRefundStatusEnum = {
185 185 * 支付退款订单状态枚举
186 186 */
187 187 export const PayRefundStatusEnum = {
188   - CREATE:{
189   - status:0,
  188 + CREATE: {
  189 + status: 0,
190 190 name: '退款订单生成'
191 191 },
192   - SUCCESS:{
193   - status:1,
  192 + SUCCESS: {
  193 + status: 1,
194 194 name: '退款成功'
195 195 },
196   - FAILURE:{
197   - status:2,
  196 + FAILURE: {
  197 + status: 2,
198 198 name: '退款失败'
199 199 },
200   - PROCESSING_NOTIFY:{
201   - status:3,
  200 + PROCESSING_NOTIFY: {
  201 + status: 3,
202 202 name: '退款中,渠道通知结果'
203 203 },
204   - PROCESSING_QUERY:{
205   - status:4,
  204 + PROCESSING_QUERY: {
  205 + status: 4,
206 206 name: '退款中,系统查询结果'
207 207 },
208   - UNKNOWN_RETRY:{
209   - status:5,
  208 + UNKNOWN_RETRY: {
  209 + status: 5,
210 210 name: '状态未知,请重试'
211 211 },
212   - UNKNOWN_QUERY:{
213   - status:6,
  212 + UNKNOWN_QUERY: {
  213 + status: 6,
214 214 name: '状态未知,系统查询结果'
215 215 },
216   - CLOSE:{
217   - status:99,
  216 + CLOSE: {
  217 + status: 99,
218 218 name: '退款关闭'
219 219 }
220 220 }
221 221  
  222 +/**
  223 + * 商品 SPU 状态
  224 + */
  225 +export const ProductSpuStatusEnum = {
  226 + RECYCLE: {
  227 + status: -1,
  228 + name: '回收站'
  229 + },
  230 + DISABLE: {
  231 + status: 0,
  232 + name: '下架'
  233 + },
  234 + ENABLE: {
  235 + status: 1,
  236 + name: '上架'
  237 + },
  238 +}
... ...
yudao-ui-admin/src/utils/dict.js
... ... @@ -56,6 +56,9 @@ export const DICT_TYPE = {
56 56 PAY_ORDER_REFUND_STATUS: 'pay_order_refund_status', // 商户支付订单退款状态
57 57 PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态
58 58 PAY_REFUND_ORDER_TYPE: 'pay_refund_order_type', // 退款订单类别
  59 +
  60 + // ========== MALL - PRODUCT 模块 ==========
  61 + PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
59 62 }
60 63  
61 64 /**
... ... @@ -114,6 +117,3 @@ export function getDictDataLabel(dictType, value) {
114 117 const dict = getDictData(dictType, value);
115 118 return dict ? dict.label : '';
116 119 }
117   -
118   -export class getDictDataL {
119   -}
... ...
yudao-ui-admin/src/views/mall/product/spu/index.vue
... ... @@ -4,74 +4,48 @@
4 4 <el-form-item label="商品名称" prop="name">
5 5 <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
6 6 </el-form-item>
7   -
8 7 <el-form-item label="商品编码" prop="code">
9 8 <el-input v-model="queryParams.code" placeholder="请输入商品编码" clearable @keyup.enter.native="handleQuery"/>
10 9 </el-form-item>
11   -
12 10 <el-form-item label="商品分类" prop="categoryIds">
13 11 <el-cascader v-model="queryParams.categoryIds" placeholder="请输入商品分类"
14 12 :options="categoryList" :props="propName" clearable ref="category"/>
15 13 </el-form-item>
16   -
17 14 <el-form-item label="商品品牌" prop="brandId">
18 15 <el-select v-model="queryParams.brandId" placeholder="请输入商品品牌" clearable @keyup.enter.native="handleQuery">
19 16 <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
20 17 </el-select>
21 18 </el-form-item>
22   -
  19 + <!-- TODO 待实现:商品类型 -->
  20 + <!-- TODO 待实现:商品标签 -->
  21 + <!-- TODO 待实现:营销活动 -->
  22 + <!-- TODO 前端优化:商品销量、商品价格,排的整齐一点 -->
23 23 <el-form-item label="商品销量">
24   - <el-col
25   - :span="6"
26   - style="padding-left:0"
27   - >
  24 + <el-col :span="7" style="padding-left:0">
28 25 <el-form-item prop="salesCountMin">
29   - <el-input v-model="queryParams.salesCountMin" placeholder="最小值" clearable
30   - @keyup.enter.native="handleQuery"/>
  26 + <el-input v-model="queryParams.salesCountMin" placeholder="最低销量" clearable @keyup.enter.native="handleQuery"/>
31 27 </el-form-item>
32 28 </el-col>
33   - <el-col
34   - :span="1"
35   - >
36   - -
37   - </el-col>
38   - <el-col
39   - :span="6"
40   - style="padding-left:0"
41   - >
  29 + <el-col :span="1">-</el-col>
  30 + <el-col :span="7" style="padding-left:0">
42 31 <el-form-item prop="salesCountMax">
43   - <el-input v-model="queryParams.salesCountMax" placeholder="最大值" clearable
44   - @keyup.enter.native="handleQuery"/>
  32 + <el-input v-model="queryParams.salesCountMax" placeholder="最高销量" clearable @keyup.enter.native="handleQuery"/>
45 33 </el-form-item>
46 34 </el-col>
47 35 </el-form-item>
48   -
49 36 <el-form-item label="商品价格" prop="code">
50   - <el-col
51   - :span="6"
52   - style="padding-left:0"
53   - >
  37 + <el-col :span="7" style="padding-left:0">
54 38 <el-form-item prop="marketPriceMin">
55   - <el-input v-model="queryParams.marketPriceMin" placeholder="最小值" clearable
56   - @keyup.enter.native="handleQuery"/>
  39 + <el-input v-model="queryParams.marketPriceMin" placeholder="最低价格" clearable @keyup.enter.native="handleQuery"/>
57 40 </el-form-item>
58 41 </el-col>
59   - <el-col
60   - :span="1"
61   - >
62   - -
63   - </el-col>
64   - <el-col
65   - :span="6"
66   - style="padding-left:0"
67   - >
  42 + <el-col :span="1">-</el-col>
  43 + <el-col :span="7" style="padding-left:0">
68 44 <el-form-item prop="marketPriceMax">
69   - <el-input v-model="queryParams.marketPriceMax" placeholder="最大值" clearable
70   - @keyup.enter.native="handleQuery"/>
  45 + <el-input v-model="queryParams.marketPriceMax" placeholder="最高价格" clearable @keyup.enter.native="handleQuery"/>
71 46 </el-form-item>
72 47 </el-col>
73 48 </el-form-item>
74   -
75 49 <el-form-item>
76 50 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
77 51 <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
... ... @@ -82,8 +56,7 @@
82 56 <el-row :gutter="10" class="mb8">
83 57 <el-col :span="1.5">
84 58 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
85   - v-hasPermi="['product:spu:create']">新增
86   - </el-button>
  59 + v-hasPermi="['product:spu:create']">添加商品</el-button>
87 60 </el-col>
88 61 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"/>
89 62 </el-row>
... ... @@ -96,17 +69,13 @@
96 69 <el-table-column label="商品信息" align="center" width="260">
97 70 <template slot-scope="scope">
98 71 <div class="product-info">
99   - <img
100   - v-if="scope.row.picUrls"
101   - :src="scope.row.picUrls[0]"
102   - alt="分类图片"
103   - class="img-height"
104   - />
  72 + <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height" />
105 73 <div class="message">{{ scope.row.name }}</div>
106 74 </div>
107 75 </template>
  76 + <!-- TODO 前端优化:可以有个 + 号,点击后,展示每个 sku -->
108 77 </el-table-column>
109   - <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  78 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
110 79 <el-table-column label="库存" align="center" prop="totalStock"/>
111 80 <el-table-column label="销量" align="center" prop="salesCount"/>
112 81 <el-table-column label="排序" align="center" prop="sort"/>
... ... @@ -117,18 +86,15 @@
117 86 </el-table-column>
118 87 <el-table-column label="状态" align="center" prop="status">
119 88 <template slot-scope="scope">
120   - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  89 + <dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
121 90 </template>
122 91 </el-table-column>
123   -
124 92 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
125 93 <template slot-scope="scope">
126 94 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
127   - v-hasPermi="['product:spu:update']">修改
128   - </el-button>
  95 + v-hasPermi="['product:spu:update']">修改</el-button>
129 96 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
130   - v-hasPermi="['product:spu:delete']">删除
131   - </el-button>
  97 + v-hasPermi="['product:spu:delete']">删除</el-button>
132 98 </template>
133 99 </el-table-column>
134 100 </el-table>
... ... @@ -141,17 +107,12 @@
141 107 <el-table-column label="商品信息" align="center" width="260">
142 108 <template slot-scope="scope">
143 109 <div class="product-info">
144   - <img
145   - v-if="scope.row.picUrls"
146   - :src="scope.row.picUrls[0]"
147   - alt="分类图片"
148   - class="img-height"
149   - />
  110 + <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
150 111 <div class="message">{{ scope.row.name }}</div>
151 112 </div>
152 113 </template>
153 114 </el-table-column>
154   - <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  115 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
155 116 <el-table-column label="库存" align="center" prop="totalStock"/>
156 117 <el-table-column label="销量" align="center" prop="salesCount"/>
157 118 <el-table-column label="排序" align="center" prop="sort"/>
... ... @@ -162,18 +123,15 @@
162 123 </el-table-column>
163 124 <el-table-column label="状态" align="center" prop="status">
164 125 <template slot-scope="scope">
165   - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  126 + <dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
166 127 </template>
167 128 </el-table-column>
168   -
169 129 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
170 130 <template slot-scope="scope">
171 131 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
172   - v-hasPermi="['product:spu:update']">修改
173   - </el-button>
  132 + v-hasPermi="['product:spu:update']">修改</el-button>
174 133 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
175   - v-hasPermi="['product:spu:delete']">删除
176   - </el-button>
  134 + v-hasPermi="['product:spu:delete']">删除</el-button>
177 135 </template>
178 136 </el-table-column>
179 137 </el-table>
... ... @@ -186,17 +144,12 @@
186 144 <el-table-column label="商品信息" align="center" width="260">
187 145 <template slot-scope="scope">
188 146 <div class="product-info">
189   - <img
190   - v-if="scope.row.picUrls"
191   - :src="scope.row.picUrls[0]"
192   - alt="分类图片"
193   - class="img-height"
194   - />
  147 + <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
195 148 <div class="message">{{ scope.row.name }}</div>
196 149 </div>
197 150 </template>
198 151 </el-table-column>
199   - <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  152 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
200 153 <el-table-column label="库存" align="center" prop="totalStock"/>
201 154 <el-table-column label="销量" align="center" prop="salesCount"/>
202 155 <el-table-column label="排序" align="center" prop="sort"/>
... ... @@ -207,18 +160,15 @@
207 160 </el-table-column>
208 161 <el-table-column label="状态" align="center" prop="status">
209 162 <template slot-scope="scope">
210   - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  163 + <dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
211 164 </template>
212 165 </el-table-column>
213   -
214 166 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
215 167 <template slot-scope="scope">
216 168 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
217   - v-hasPermi="['product:spu:update']">修改
218   - </el-button>
  169 + v-hasPermi="['product:spu:update']">修改</el-button>
219 170 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
220   - v-hasPermi="['product:spu:delete']">删除
221   - </el-button>
  171 + v-hasPermi="['product:spu:delete']">删除</el-button>
222 172 </template>
223 173 </el-table-column>
224 174 </el-table>
... ... @@ -231,17 +181,12 @@
231 181 <el-table-column label="商品信息" align="center" width="260">
232 182 <template slot-scope="scope">
233 183 <div class="product-info">
234   - <img
235   - v-if="scope.row.picUrls"
236   - :src="scope.row.picUrls[0]"
237   - alt="分类图片"
238   - class="img-height"
239   - />
  184 + <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
240 185 <div class="message">{{ scope.row.name }}</div>
241 186 </div>
242 187 </template>
243 188 </el-table-column>
244   - <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  189 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
245 190 <el-table-column label="库存" align="center" prop="totalStock"/>
246 191 <el-table-column label="销量" align="center" prop="salesCount"/>
247 192 <el-table-column label="排序" align="center" prop="sort"/>
... ... @@ -252,27 +197,24 @@
252 197 </el-table-column>
253 198 <el-table-column label="状态" align="center" prop="status">
254 199 <template slot-scope="scope">
255   - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  200 + <dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
256 201 </template>
257 202 </el-table-column>
258   -
259 203 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
260 204 <template slot-scope="scope">
261 205 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
262   - v-hasPermi="['product:spu:update']">修改
263   - </el-button>
  206 + v-hasPermi="['product:spu:update']">修改</el-button>
264 207 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
265   - v-hasPermi="['product:spu:delete']">删除
266   - </el-button>
  208 + v-hasPermi="['product:spu:delete']">删除</el-button>
267 209 </template>
268 210 </el-table-column>
269 211 </el-table>
270 212 </el-tab-pane>
271 213 </el-tabs>
  214 +
272 215 <!-- 分页组件 -->
273 216 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
274 217 @pagination="getList"/>
275   -
276 218 </div>
277 219 </template>
278 220  
... ... @@ -280,6 +222,7 @@
280 222 import {deleteSpu, getSpuPage,} from "@/api/mall/product/spu";
281 223 import {getProductCategoryList} from "@/api/mall/product/category";
282 224 import {getBrandList} from "@/api/mall/product/brand";
  225 +import {ProductSpuStatusEnum} from "@/utils/constants";
283 226  
284 227 export default {
285 228 name: "Spu",
... ... @@ -318,7 +261,6 @@ export default {
318 261 salesCountMax: null,
319 262 marketPriceMin: null,
320 263 marketPriceMax: null,
321   - tabStatus: null,
322 264 },
323 265 };
324 266 },
... ... @@ -353,9 +295,6 @@ export default {
353 295 this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
354 296 // 执行查询
355 297 getSpuPage(params).then((response) => {
356   - response.data.list.forEach(element => {
357   - element.price = this.divide(element.minPrice, 100) + "~" + this.divide(element.maxPrice, 100)
358   - });
359 298 this.list = response.data.list;
360 299 this.total = response.data.total;
361 300 this.loading = false;
... ... @@ -390,29 +329,29 @@ export default {
390 329 .confirm('是否确认删除商品spu编号为"' + id + '"的数据项?')
391 330 .then(function () {
392 331 return deleteSpu(id);
393   - })
394   - .then(() => {
  332 + }).then(() => {
395 333 this.getList();
396 334 this.$modal.msgSuccess("删除成功");
397   - })
398   - .catch(() => {
  335 + }).catch(() => {
399 336 });
400 337 },
401   - unitConversion(row, column, cellValue) {
402   - return this.divide(cellValue, 100);
  338 + formatPrice(row, column, cellValue) {
  339 + return '¥' + this.divide(cellValue, 100);
403 340 },
404   - // 选中tab
  341 + // 选中 tab
405 342 handleClick(val) {
406 343 if (val.name === "all") {
407   - this.queryParams.tabStatus = null;
  344 + this.queryParams.status = undefined;
  345 + this.queryParams.alarmStock = undefined;
408 346 } else if (val.name === "on") {
409   - this.queryParams.tabStatus = 0;
  347 + this.queryParams.status = ProductSpuStatusEnum.ENABLE.status;
  348 + this.queryParams.alarmStock = undefined;
410 349 } else if (val.name === "off") {
411   - this.queryParams.tabStatus = 1;
  350 + this.queryParams.status = ProductSpuStatusEnum.DISABLE.status;
  351 + this.queryParams.alarmStock = undefined;
412 352 } else if (val.name === "remind") {
413   - this.queryParams.tabStatus = 2;
414   - } else {
415   - this.queryParams.tabStatus = null;
  353 + this.queryParams.status = undefined;
  354 + this.queryParams.alarmStock = true;
416 355 }
417 356 this.getList();
418 357 }
... ...
yudao-ui-admin/src/views/mall/product/spu/save.vue
... ... @@ -7,8 +7,8 @@
7 7 <el-form-item label="商品名称" prop="name">
8 8 <el-input v-model="baseForm.name" placeholder="请输入商品名称"/>
9 9 </el-form-item>
10   - <el-form-item label="商品卖点">
11   - <el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入商品卖点"/>
  10 + <el-form-item label="促销语">
  11 + <el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入促销语"/>
12 12 </el-form-item>
13 13 <el-form-item label="商品主图" prop="picUrls">
14 14 <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image"/>
... ...