Commit 3b506006ddcc116647648a9cb2794d908feaae1b

Authored by YunaiV
2 parents 5c4b61f5 e035e66f

Merge remote-tracking branch 'origin/feature/1.8.0-uniapp' into feature/1.8.0-uniapp

yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueUpdateReqVO.java
@@ -12,6 +12,6 @@ public class ProductPropertyValueUpdateReqVO extends ProductPropertyValueBaseVO @@ -12,6 +12,6 @@ public class ProductPropertyValueUpdateReqVO extends ProductPropertyValueBaseVO
12 12
13 @ApiModelProperty(value = "主键", required = true, example = "1024") 13 @ApiModelProperty(value = "主键", required = true, example = "1024")
14 @NotNull(message = "主键不能为空") 14 @NotNull(message = "主键不能为空")
15 - private Integer id; 15 + private Long id;
16 16
17 } 17 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
@@ -55,9 +55,8 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { @@ -55,9 +55,8 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
55 55
56 } 56 }
57 57
58 - // TODO @luowenfeng: categoryIds => categoryId,example 也要改下哈  
59 - @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "[1,2,4]")  
60 - private Long categoryIds; 58 + @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "4")
  59 + private Long categoryId;
61 60
62 // TODO @芋艿:在瞅瞅~ 61 // TODO @芋艿:在瞅瞅~
63 @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") 62 @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]")
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java
@@ -25,10 +25,9 @@ public interface ProductPropertyMapper extends BaseMapperX<ProductPropertyDO> { @@ -25,10 +25,9 @@ public interface ProductPropertyMapper extends BaseMapperX<ProductPropertyDO> {
25 .orderByDesc(ProductPropertyDO::getId)); 25 .orderByDesc(ProductPropertyDO::getId));
26 } 26 }
27 27
28 - // TODO @luowenfeng: selectByNameLike,这样更清晰哈。  
29 default ProductPropertyDO selectByName(String name) { 28 default ProductPropertyDO selectByName(String name) {
30 return selectOne(new LambdaQueryWrapperX<ProductPropertyDO>() 29 return selectOne(new LambdaQueryWrapperX<ProductPropertyDO>()
31 - .likeIfPresent(ProductPropertyDO::getName, name)); 30 + .eqIfPresent(ProductPropertyDO::getName, name));
32 } 31 }
33 32
34 } 33 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
@@ -17,8 +17,7 @@ import java.util.List; @@ -17,8 +17,7 @@ import java.util.List;
17 @Mapper 17 @Mapper
18 public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> { 18 public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> {
19 19
20 - // TODO @luowenfeng: selectListByPropertyId 是不是就可以啦  
21 - default List<ProductPropertyValueDO> selectListByPropertyValueListByPropertyId(List<Long> propertyIds) { 20 + default List<ProductPropertyValueDO> selectListByPropertyId(List<Long> propertyIds) {
22 return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>() 21 return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>()
23 .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); 22 .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds));
24 } 23 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java
@@ -19,6 +19,7 @@ import javax.annotation.Resource; @@ -19,6 +19,7 @@ import javax.annotation.Resource;
19 import java.util.Collection; 19 import java.util.Collection;
20 import java.util.List; 20 import java.util.List;
21 import java.util.Map; 21 import java.util.Map;
  22 +import java.util.Objects;
22 23
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_EXISTS; 25 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_EXISTS;
@@ -58,8 +59,8 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { @@ -58,8 +59,8 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
58 public void updateProperty(ProductPropertyUpdateReqVO updateReqVO) { 59 public void updateProperty(ProductPropertyUpdateReqVO updateReqVO) {
59 // 校验存在 60 // 校验存在
60 this.validatePropertyExists(updateReqVO.getId()); 61 this.validatePropertyExists(updateReqVO.getId());
61 - // TODO @luowenfeng:如果是自己的情况下,名字相同也是 ok 的呀~  
62 - if (productPropertyMapper.selectByName(updateReqVO.getName()) != null) { 62 + ProductPropertyDO productPropertyDO = productPropertyMapper.selectByName(updateReqVO.getName());
  63 + if (productPropertyDO != null && !productPropertyDO.getId().equals(updateReqVO.getId())) {
63 throw exception(PROPERTY_EXISTS); 64 throw exception(PROPERTY_EXISTS);
64 } 65 }
65 // 更新 66 // 更新
@@ -97,10 +98,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { @@ -97,10 +98,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
97 return ProductPropertyConvert.INSTANCE.convertPage(pageResult); 98 return ProductPropertyConvert.INSTANCE.convertPage(pageResult);
98 } 99 }
99 100
100 - private List<ProductPropertyValueDO> getPropertyValueListByPropertyId(List<Long> propertyIds) {  
101 - return productPropertyValueMapper.selectListByPropertyValueListByPropertyId(propertyIds);  
102 - }  
103 -  
104 @Override 101 @Override
105 public ProductPropertyRespVO getProperty(Long id) { 102 public ProductPropertyRespVO getProperty(Long id) {
106 ProductPropertyDO property = productPropertyMapper.selectById(id); 103 ProductPropertyDO property = productPropertyMapper.selectById(id);
@@ -117,7 +114,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { @@ -117,7 +114,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
117 List<ProductPropertyRespVO> propertyList = getPropertyList(listReqVO); 114 List<ProductPropertyRespVO> propertyList = getPropertyList(listReqVO);
118 115
119 // 查询属性值 116 // 查询属性值
120 - List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectListByPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId)); 117 + List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId));
121 Map<Long, List<ProductPropertyValueDO>> valueDOMap = CollectionUtils.convertMultiMap(valueDOList, ProductPropertyValueDO::getPropertyId); 118 Map<Long, List<ProductPropertyValueDO>> valueDOMap = CollectionUtils.convertMultiMap(valueDOList, ProductPropertyValueDO::getPropertyId);
122 return CollectionUtils.convertList(propertyList, m -> { 119 return CollectionUtils.convertList(propertyList, m -> {
123 ProductPropertyAndValueRespVO productPropertyAndValueRespVO = ProductPropertyConvert.INSTANCE.convert(m); 120 ProductPropertyAndValueRespVO productPropertyAndValueRespVO = ProductPropertyConvert.INSTANCE.convert(m);
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
@@ -14,6 +14,7 @@ import org.springframework.validation.annotation.Validated; @@ -14,6 +14,7 @@ import org.springframework.validation.annotation.Validated;
14 14
15 import javax.annotation.Resource; 15 import javax.annotation.Resource;
16 import java.util.List; 16 import java.util.List;
  17 +import java.util.Objects;
17 18
18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS; 20 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS;
@@ -42,8 +43,8 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ @@ -42,8 +43,8 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
42 43
43 @Override 44 @Override
44 public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) { 45 public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) {
45 - // TODO @luowenfeng:如果是自己的情况下,名字相同也是 ok 的呀~  
46 - if (productPropertyValueMapper.selectByName(updateReqVO.getPropertyId(), updateReqVO.getName()) != null) { 46 + ProductPropertyValueDO productPropertyValueDO = productPropertyValueMapper.selectByName(updateReqVO.getPropertyId(), updateReqVO.getName());
  47 + if (productPropertyValueDO != null && !productPropertyValueDO.getId().equals(updateReqVO.getId())) {
47 throw exception(PROPERTY_VALUE_EXISTS); 48 throw exception(PROPERTY_VALUE_EXISTS);
48 } 49 }
49 ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); 50 ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO);
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -162,7 +162,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -162,7 +162,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
162 }); 162 });
163 respVO.setProductPropertyViews(productPropertyViews); 163 respVO.setProductPropertyViews(productPropertyViews);
164 } 164 }
165 - respVO.setCategoryIds(respVO.getCategoryId());  
166 } 165 }
167 return respVO; 166 return respVO;
168 } 167 }
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
1 package cn.iocoder.yudao.module.product.service.spu; 1 package cn.iocoder.yudao.module.product.service.spu;
2 2
  3 +import cn.hutool.core.date.DateUtil;
  4 +import cn.hutool.core.util.RandomUtil;
3 import cn.iocoder.yudao.framework.common.exception.ServiceException; 5 import cn.iocoder.yudao.framework.common.exception.ServiceException;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 9 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; 10 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
8 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; 11 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
@@ -33,10 +36,12 @@ import java.util.*; @@ -33,10 +36,12 @@ import java.util.*;
33 import java.util.stream.Collectors; 36 import java.util.stream.Collectors;
34 import java.util.stream.Stream; 37 import java.util.stream.Stream;
35 38
  39 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
36 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 40 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
37 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 41 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
38 42
39 // TODO @芋艿:review 下单元测试 43 // TODO @芋艿:review 下单元测试
  44 +
40 /** 45 /**
41 * {@link ProductSpuServiceImpl} 的单元测试类 46 * {@link ProductSpuServiceImpl} 的单元测试类
42 * 47 *
@@ -67,6 +72,13 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { @@ -67,6 +72,13 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
67 @MockBean 72 @MockBean
68 private ProductPropertyValueService productPropertyValueService; 73 private ProductPropertyValueService productPropertyValueService;
69 74
  75 + public String generateNo() {
  76 + return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999);
  77 + }
  78 +
  79 + public Long generateId() {
  80 + return RandomUtil.randomLong(100000, 999999);
  81 + }
70 82
71 @Test 83 @Test
72 public void testCreateSpu_success() { 84 public void testCreateSpu_success() {
@@ -206,35 +218,120 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { @@ -206,35 +218,120 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
206 Assertions.assertIterableEquals(createReqVO, spuList); 218 Assertions.assertIterableEquals(createReqVO, spuList);
207 } 219 }
208 220
209 - // TODO @luowenfeng:单测要分情况;类似你这个,可以分 2 个单测;一个是有预存预警的;一个是没库存预警的;  
210 - // 然后,参考其它模块的 getPage 类型的方法的单测。  
211 @Test 221 @Test
212 - void getSpuPage() { 222 + void getSpuPage_alarmStock_empty() {
  223 + // 调用
  224 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
  225 + productSpuPageReqVO.setAlarmStock(true);
  226 +
  227 + PageResult<ProductSpuRespVO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
  228 +
  229 + PageResult<Object> result = PageResult.empty();
  230 + Assertions.assertIterableEquals(result.getList(), spuPage.getList());
  231 + Assertions.assertEquals(spuPage.getTotal(), result.getTotal());
  232 + }
  233 +
  234 + @Test
  235 + void getSpuPage_alarmStock() {
  236 + // mock 数据
  237 + Long brandId = generateId();
  238 + Long categoryId = generateId();
  239 + String code = generateNo();
  240 +
213 // 准备参数 241 // 准备参数
214 - ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class); 242 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o->{
  243 + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  244 + o.setTotalStock(500);
  245 + o.setMinPrice(1);
  246 + o.setMaxPrice(50);
  247 + o.setMarketPrice(25);
  248 + o.setSpecType(ProductSpuSpecTypeEnum.RECYCLE.getType());
  249 + o.setBrandId(brandId);
  250 + o.setCategoryId(categoryId);
  251 + o.setClickCount(100);
  252 + o.setCode(code);
  253 + o.setDescription("测试商品");
  254 + o.setPicUrls(new ArrayList<>());
  255 + o.setName("测试");
  256 + o.setSalesCount(100);
  257 + o.setSellPoint("超级加倍");
  258 + o.setShowStock(true);
  259 + o.setVideoUrl("");
  260 + });
215 productSpuMapper.insert(createReqVO); 261 productSpuMapper.insert(createReqVO);
216 262
217 - ArrayList<ProductSkuDO> remindSpuIds = Lists.newArrayList(  
218 -// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())),  
219 -// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId()))  
220 - ); 263 + Set<Long> alarmStockSpuIds = SetUtils.asSet(createReqVO.getId());
  264 +
  265 + List<ProductSkuDO> productSpuDOS = Arrays.asList(randomPojo(ProductSkuDO.class, o -> {
  266 + o.setSpuId(createReqVO.getId());
  267 + }), randomPojo(ProductSkuDO.class, o -> {
  268 + o.setSpuId(createReqVO.getId());
  269 + }));
221 270
222 -// Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds); 271 + Mockito.when(productSkuService.getSkusByAlarmStock()).thenReturn(productSpuDOS);
223 272
224 // 调用 273 // 调用
225 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); 274 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
226 -// productSpuPageReqVO.setTabStatus(2);  
227 - 275 + productSpuPageReqVO.setAlarmStock(true);
228 PageResult<ProductSpuRespVO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO); 276 PageResult<ProductSpuRespVO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
229 277
230 - Set<Long> resultRemindSpuIds = new HashSet<>();  
231 - resultRemindSpuIds.add(null);  
232 - PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, resultRemindSpuIds)); 278 + PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds));
233 Assertions.assertIterableEquals(result.getList(), spuPage.getList()); 279 Assertions.assertIterableEquals(result.getList(), spuPage.getList());
234 Assertions.assertEquals(spuPage.getTotal(), result.getTotal()); 280 Assertions.assertEquals(spuPage.getTotal(), result.getTotal());
235 } 281 }
236 282
237 @Test 283 @Test
  284 + void getSpuPage() {
  285 + // mock 数据
  286 + Long brandId = generateId();
  287 + Long categoryId = generateId();
  288 +
  289 + // 准备参数
  290 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o->{
  291 + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  292 + o.setTotalStock(1);
  293 + o.setMinPrice(1);
  294 + o.setMaxPrice(1);
  295 + o.setMarketPrice(1);
  296 + o.setSpecType(ProductSpuSpecTypeEnum.RECYCLE.getType());
  297 + o.setBrandId(brandId);
  298 + o.setCategoryId(categoryId);
  299 + o.setClickCount(1);
  300 + o.setCode(generateNo());
  301 + o.setDescription("测试商品");
  302 + o.setPicUrls(new ArrayList<>());
  303 + o.setName("测试");
  304 + o.setSalesCount(1);
  305 + o.setSellPoint("卖点");
  306 + o.setShowStock(true);
  307 + });
  308 +
  309 + // 准备参数
  310 + productSpuMapper.insert(createReqVO);
  311 + // 测试 status 不匹配
  312 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus())));
  313 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.RECYCLE.getStatus())));
  314 + // 测试 SpecType 不匹配
  315 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType())));
  316 + // 测试 BrandId 不匹配
  317 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setBrandId(generateId())));
  318 + // 测试 CategoryId 不匹配
  319 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setCategoryId(generateId())));
  320 +
  321 + // 调用
  322 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
  323 + productSpuPageReqVO.setAlarmStock(false);
  324 + productSpuPageReqVO.setBrandId(brandId);
  325 + productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  326 + productSpuPageReqVO.setCategoryId(categoryId);
  327 +
  328 + PageResult<ProductSpuRespVO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
  329 +
  330 + PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set<Long>) null));
  331 + Assertions.assertEquals(result, spuPage);
  332 + }
  333 +
  334 + @Test
238 void testGetSpuPage() { 335 void testGetSpuPage() {
239 // 准备参数 336 // 准备参数
240 ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> { 337 ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> {
@@ -242,13 +339,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { @@ -242,13 +339,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
242 }); 339 });
243 productSpuMapper.insert(createReqVO); 340 productSpuMapper.insert(createReqVO);
244 341
245 - ArrayList<ProductSkuDO> remindSpuIds = Lists.newArrayList(  
246 -// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())),  
247 -// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId()))  
248 - );  
249 -  
250 -// Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds);  
251 -  
252 // 调用 342 // 调用
253 AppSpuPageReqVO appSpuPageReqVO = new AppSpuPageReqVO(); 343 AppSpuPageReqVO appSpuPageReqVO = new AppSpuPageReqVO();
254 appSpuPageReqVO.setCategoryId(2L); 344 appSpuPageReqVO.setCategoryId(2L);
yudao-ui-admin/src/router/index.js
@@ -196,6 +196,21 @@ export const constantRoutes = [ @@ -196,6 +196,21 @@ export const constantRoutes = [
196 meta: {title: '流程详情', activeMenu: '/bpm/task/my'} 196 meta: {title: '流程详情', activeMenu: '/bpm/task/my'}
197 } 197 }
198 ] 198 ]
  199 + },
  200 + {
  201 + path: '/order',
  202 + component: Layout,
  203 + name: '订单管理',
  204 + meta: { title: '订单管理' },
  205 + alwaysShow: true,
  206 + children: [
  207 + {
  208 + path: '/order/goods-order',
  209 + name: '商品订单',
  210 + meta: { title: '商品订单' },
  211 + component: (resolve) => require(['@/views/order/goodsOrder'], resolve)
  212 + }
  213 + ]
199 } 214 }
200 ] 215 ]
201 216
yudao-ui-admin/src/views/mall/product/spu/save.vue
@@ -453,7 +453,7 @@ export default { @@ -453,7 +453,7 @@ export default {
453 this.baseForm.id = data.id; 453 this.baseForm.id = data.id;
454 this.baseForm.name = data.name; 454 this.baseForm.name = data.name;
455 this.baseForm.sellPoint = data.sellPoint; 455 this.baseForm.sellPoint = data.sellPoint;
456 - this.baseForm.categoryIds = data.categoryIds; 456 + this.baseForm.categoryIds = data.categoryId;
457 this.baseForm.videoUrl = data.videoUrl; 457 this.baseForm.videoUrl = data.videoUrl;
458 this.baseForm.sort = data.sort; 458 this.baseForm.sort = data.sort;
459 this.baseForm.description = data.description; 459 this.baseForm.description = data.description;
yudao-ui-admin/src/views/order/goodsOrder/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <el-row :gutter="20">
  4 + <el-form
  5 + :model="queryParams"
  6 + label-width="68px"
  7 + size="small"
  8 + >
  9 + <el-col :span="6" :xs="24">
  10 + <el-form-item label="搜索方式">
  11 + <el-input style="width: 240px">
  12 + <el-select
  13 + v-model="queryParams.searchType"
  14 + slot="prepend"
  15 + clearable
  16 + style="width: 100px"
  17 + >
  18 + <el-option
  19 + v-for="dict in dicData.searchType"
  20 + v-bind="dict"
  21 + :key="dict.value"
  22 + />
  23 + </el-select>
  24 + </el-input>
  25 + </el-form-item>
  26 + </el-col>
  27 + <el-col :span="6" :xs="24">
  28 + <el-form-item label="订单类型">
  29 + <el-select
  30 + v-model="queryParams.orderType"
  31 + clearable
  32 + style="width: 240px"
  33 + >
  34 + <el-option
  35 + v-for="dict in dicData.orderType"
  36 + v-bind="dict"
  37 + :key="dict.value"
  38 + />
  39 + </el-select>
  40 + </el-form-item>
  41 + </el-col>
  42 + <el-col :span="6" :xs="24">
  43 + <el-form-item label="订单状态">
  44 + <el-select
  45 + v-model="queryParams.orderStatus"
  46 + clearable
  47 + style="width: 240px"
  48 + >
  49 + <el-option
  50 + v-for="dict in dicData.orderStatus"
  51 + v-bind="dict"
  52 + :key="dict.value"
  53 + />
  54 + </el-select>
  55 + </el-form-item>
  56 + </el-col>
  57 + <el-col :span="6" :xs="24">
  58 + <el-form-item label="订单来源">
  59 + <el-select
  60 + v-model="queryParams.orderSource"
  61 + clearable
  62 + style="width: 240px"
  63 + >
  64 + <el-option
  65 + v-for="dict in dicData.orderSource"
  66 + v-bind="dict"
  67 + :key="dict.value"
  68 + />
  69 + </el-select>
  70 + </el-form-item>
  71 + </el-col>
  72 + <el-col :span="6" :xs="24">
  73 + <el-form-item label="付款方式">
  74 + <el-select
  75 + v-model="queryParams.payWay"
  76 + clearable
  77 + style="width: 240px"
  78 + >
  79 + <el-option
  80 + v-for="dict in dicData.payWay"
  81 + v-bind="dict"
  82 + :key="dict.value"
  83 + />
  84 + </el-select>
  85 + </el-form-item>
  86 + </el-col>
  87 + <el-col :span="6" :xs="24">
  88 + <el-form-item label="营销类型">
  89 + <el-select
  90 + v-model="queryParams.marketingType"
  91 + clearable
  92 + style="width: 240px"
  93 + >
  94 + <el-option
  95 + v-for="dict in dicData.marketingType"
  96 + v-bind="dict"
  97 + :key="dict.value"
  98 + />
  99 + </el-select>
  100 + </el-form-item>
  101 + </el-col>
  102 + <el-col :span="6" :xs="24">
  103 + <el-form-item label="下单时间">
  104 + <el-date-picker
  105 + v-model="queryParams.date"
  106 + type="daterange"
  107 + range-separator="至"
  108 + start-placeholder="开始日期"
  109 + end-placeholder="结束日期"
  110 + :picker-options="rangePickerOptions"
  111 + style="width: 240px"
  112 + />
  113 + </el-form-item>
  114 + </el-col>
  115 + <el-col :span="6" :xs="24" style="line-height: 32px">
  116 + <el-button type="primary" icon="el-icon-search" size="mini">搜索</el-button>
  117 + <el-button icon="el-icon-refresh" size="mini">重置</el-button>
  118 + <el-button icon="el-icon-document" size="mini">导出订单</el-button>
  119 + </el-col>
  120 + </el-form>
  121 + </el-row>
  122 +
  123 + <el-radio-group v-model="activeTabName">
  124 + <el-radio-button
  125 + v-for="tabPane in tabPanes"
  126 + :label="tabPane.label"
  127 + >{{tabPane.text}}</el-radio-button>
  128 + </el-radio-group>
  129 +
  130 + <el-table
  131 + :data="tableData"
  132 + :span-method="spanMethod"
  133 + :row-class-name="rowClassName"
  134 + border
  135 + >
  136 + <el-table-column type="selection" :selectable="(row, index) => index % 2"/>
  137 + <el-table-column label="商品" prop="goods" width="360">
  138 + <template slot-scope="{ row, $index }">
  139 + <el-row
  140 + v-if="$index % 2 === 0"
  141 + class="card-header"
  142 + >
  143 + <el-col :span="5">
  144 + 订单号:{{row.orderNo}}
  145 + <el-popover
  146 + title="支付流水号:"
  147 + :content="row.payNo"
  148 + ref="popover"
  149 + placement="right"
  150 + width="200"
  151 + trigger="click"
  152 + />
  153 + <el-button type="text" v-popover:popover>
  154 + 更多
  155 + </el-button>
  156 + </el-col>
  157 + <el-col :span="5">下单时间:{{row.time}}</el-col>
  158 + <el-col :span="5">订单来源:{{row.orderSource}}</el-col>
  159 + <el-col :span="5">支付方式:{{row.payWay}}</el-col>
  160 + <el-col :span="4" align="right">
  161 + <el-button type="text">打印发货单</el-button>
  162 + <el-button type="text">详情</el-button>
  163 + <el-button type="text">备注</el-button>
  164 + </el-col>
  165 + </el-row>
  166 + <div v-else class="goods-info">
  167 + <img :src="row.picture"/>
  168 + <span class="ellipsis-2">{{row.name}}</span>
  169 + </div>
  170 + </template>
  171 + </el-table-column>
  172 + <el-table-column label="单价(元)/数量" prop="fee" align="center" width="115">
  173 + <template slot-scope="{ row }">
  174 + <div>{{row.price}}</div>
  175 + <div>{{row.count}}</div>
  176 + </template>
  177 + </el-table-column>
  178 + <el-table-column label="维权" prop="safeguard" align="center" width="115"/>
  179 + <el-table-column label="实付金额(元)" prop="amount" align="center" width="115"/>
  180 + <el-table-column label="买家/收货人" prop="buyer" width="360">
  181 + <template slot-scope="{ row }">
  182 + <div>{{row.buyer}}</div>
  183 + <div>{{row.receiver}}{{row.tel}}</div>
  184 + <div class="ellipsis-2">{{row.address}}</div>
  185 + </template>
  186 + </el-table-column>
  187 + <el-table-column label="配送方式" prop="sendWay" width="115"/>
  188 + <el-table-column label="交易状态" prop="status"/>
  189 + </el-table>
  190 +
  191 + <pagination/>
  192 + </div>
  193 +</template>
  194 +
  195 +<script>
  196 +const dicData = {
  197 + searchType: [
  198 + { label: '订单号', value: 'ddh' },
  199 + { label: '交易流水号', value: 'jylsh' },
  200 + { label: '订单备注', value: 'ddbz' },
  201 + { label: '收货人姓名', value: 'shrxm' },
  202 + { label: '商品名称', value: 'spmc' },
  203 + { label: '收货人电话', value: 'shrdh' },
  204 + { label: '会员昵称', value: 'hync' },
  205 + { label: '商品编号', value: 'spbh' }
  206 + ],
  207 + orderType: [
  208 + { label: '全部', value: 'qb' },
  209 + { label: '物流订单', value: 'wldd' },
  210 + { label: '自提订单', value: 'ztdd' },
  211 + { label: '外卖订单', value: 'wmdd' },
  212 + { label: '虚拟订单', value: 'xndd' },
  213 + { label: '收银订单', value: 'sydd' }
  214 + ],
  215 + orderStatus: [
  216 + { label: '全部', value: 'qb' },
  217 + { label: '待支付', value: 'dzf' },
  218 + { label: '待发货', value: 'dfh' },
  219 + { label: '已发货', value: 'yfh' },
  220 + { label: '已收货', value: 'ysh' },
  221 + { label: '已完成', value: 'ywc' },
  222 + { label: '已关闭', value: 'ygb' },
  223 + { label: '退款中', value: 'tkz' }
  224 + ],
  225 + orderSource: [
  226 + { label: '全部', value: 'qb' },
  227 + { label: '微信公众号', value: 'wxgzh' },
  228 + { label: '微信小程序', value: 'wxxcx' },
  229 + { label: 'PC', value: 'pc' },
  230 + { label: 'H5', value: 'h5' },
  231 + { label: 'APP', value: 'app' },
  232 + { label: '收银台', value: 'syt' },
  233 + { label: '代客下单', value: 'dkxd' }
  234 + ],
  235 + payWay: [
  236 + { label: '全部', value: 'qb' },
  237 + { label: '在线支付', value: 'zxzf' },
  238 + { label: '余额支付', value: 'yezf' },
  239 + { label: '线下支付', value: 'xxzf' },
  240 + { label: '积分兑换', value: 'jfdh' },
  241 + { label: '支付宝支付', value: 'zfbzf' },
  242 + { label: '微信支付', value: 'wxzf' }
  243 + ],
  244 + marketingType: [
  245 + { label: '全部', value: 'qb' },
  246 + { label: '一口价', value: 'ykj' },
  247 + { label: '专题', value: 'zt' },
  248 + { label: '团购', value: 'tg' },
  249 + { label: '拼团', value: 'pt' },
  250 + { label: '拼团返利', value: 'ptfl' },
  251 + { label: '盲盒', value: 'mh' },
  252 + { label: '砍价', value: 'kj' },
  253 + { label: '礼品卡优惠', value: 'lpkyh' },
  254 + { label: '秒杀', value: 'ms' },
  255 + { label: '积分兑换', value: 'jfdh' },
  256 + { label: '组合套餐', value: 'zhtc' },
  257 + { label: '预售', value: 'ys' }
  258 + ]
  259 +}
  260 +const rangePickerOptions = {
  261 + shortcuts: [{
  262 + text: '最近一周',
  263 + onClick(picker) {
  264 + const end = new Date();
  265 + const start = new Date();
  266 + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
  267 + picker.$emit('pick', [start, end]);
  268 + }
  269 + }, {
  270 + text: '最近一个月',
  271 + onClick(picker) {
  272 + const end = new Date();
  273 + const start = new Date();
  274 + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
  275 + picker.$emit('pick', [start, end]);
  276 + }
  277 + }, {
  278 + text: '最近三个月',
  279 + onClick(picker) {
  280 + const end = new Date();
  281 + const start = new Date();
  282 + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
  283 + picker.$emit('pick', [start, end]);
  284 + }
  285 + }]
  286 +}
  287 +export default {
  288 + name: "index",
  289 + data () {
  290 + return {
  291 + dicData,
  292 + rangePickerOptions,
  293 + queryParams: {
  294 + searchType: 'ddh',
  295 + orderType: ''
  296 + },
  297 + activeTabName: 'all',
  298 + tabPanes: [
  299 + { text: '全部', label: 'all' },
  300 + { text: '待支付', label: 'toBePay' },
  301 + { text: '待发货', label: 'toBeSend' },
  302 + { text: '已发货', label: 'send' },
  303 + { text: '已收货', label: 'received' },
  304 + { text: '已完成', label: 'finished' },
  305 + { text: '已关闭', label: 'closed' },
  306 + { text: '退款中', label: 'refund' }
  307 + ],
  308 + tableData: []
  309 + }
  310 + },
  311 + mounted () {
  312 + const data = [
  313 + {
  314 + orderNo: '20221026220424001',
  315 + payNo: '20221026220424001',
  316 + time: '2022-10-26 22:04:20',
  317 + orderSource: 'PC',
  318 + payWay: '微信支付',
  319 + name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
  320 + picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
  321 + price: '199',
  322 + count: '5件',
  323 + amount: 460,
  324 + safeguard: '主动退款',
  325 + buyer: '小明',
  326 + receiver: '小花',
  327 + tel: '15823655095',
  328 + address: '北京市-北京市-东城区 观音桥',
  329 + sendWay: '物流配送',
  330 + status: '已完成'
  331 + },
  332 + {
  333 + orderNo: '20221026220424001',
  334 + payNo: '20221026220424001',
  335 + time: '2022-10-26 22:04:20',
  336 + orderSource: 'PC',
  337 + payWay: '微信支付',
  338 + name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
  339 + picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
  340 + price: '199',
  341 + count: '5件',
  342 + amount: 460,
  343 + safeguard: '主动退款',
  344 + buyer: '小明',
  345 + receiver: '小花',
  346 + tel: '15823655095',
  347 + address: '北京市-北京市-东城区 观音桥',
  348 + sendWay: '物流配送',
  349 + status: '已完成'
  350 + },
  351 + {
  352 + orderNo: '20221026220424001',
  353 + payNo: '20221026220424001',
  354 + time: '2022-10-26 22:04:20',
  355 + orderSource: 'PC',
  356 + payWay: '微信支付',
  357 + name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
  358 + picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
  359 + price: '199',
  360 + count: '5件',
  361 + amount: 460,
  362 + safeguard: '主动退款',
  363 + buyer: '小明',
  364 + receiver: '小花',
  365 + tel: '15823655095',
  366 + address: '北京市-北京市-东城区 观音桥',
  367 + sendWay: '物流配送',
  368 + status: '已完成'
  369 + },
  370 + {
  371 + orderNo: '20221026220424001',
  372 + payNo: '20221026220424001',
  373 + time: '2022-10-26 22:04:20',
  374 + orderSource: 'PC',
  375 + payWay: '微信支付',
  376 + name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
  377 + picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
  378 + price: '199',
  379 + count: '5件',
  380 + amount: 460,
  381 + safeguard: '主动退款',
  382 + buyer: '小明',
  383 + receiver: '小花',
  384 + tel: '15823655095',
  385 + address: '北京市-北京市-东城区 观音桥',
  386 + sendWay: '物流配送',
  387 + status: '已完成'
  388 + }
  389 + ]
  390 + data.forEach((record, index) => {
  391 + data.splice(index, 0, record)
  392 + })
  393 + this.tableData = data
  394 + },
  395 + methods: {
  396 + spanMethod ({ row, column, rowIndex, columnIndex }) {
  397 + if (rowIndex % 2 === 0) {
  398 + if (columnIndex === 1) {
  399 + return [1, 8]
  400 + } else {
  401 + return [0, 0]
  402 + }
  403 + }
  404 + },
  405 + rowClassName ({ rowIndex }) {
  406 + if (rowIndex % 2 === 0) {
  407 + return 'even-row'
  408 + } else {
  409 + return 'odd-row'
  410 + }
  411 + }
  412 + }
  413 +}
  414 +</script>
  415 +
  416 +<style lang="scss" scoped>
  417 + ::v-deep .el-table {
  418 + margin-top: 20px;
  419 + .el-table__row{
  420 + &.even-row{
  421 + >.el-table__cell{
  422 + padding: 0;
  423 + .cell{
  424 + padding: 0;
  425 + .card-header{
  426 + padding: 0 10px;
  427 + line-height: 44px;
  428 + background: #f7f7f7;
  429 + color: #333;
  430 + }
  431 + }
  432 + }
  433 + }
  434 + >.el-table__cell{
  435 + .goods-info{
  436 + display: flex;
  437 + img{
  438 + margin-right: 10px;
  439 + width: 60px;
  440 + height: 60px;
  441 + border: 1px solid #e2e2e2;
  442 + }
  443 + }
  444 + .ellipsis-2{
  445 + display: -webkit-box;
  446 + overflow: hidden;
  447 + text-overflow: ellipsis;
  448 + white-space: normal;
  449 + -webkit-line-clamp: 2; /* 要显示的行数 */
  450 + -webkit-box-orient: vertical;
  451 + word-break: break-all;
  452 + line-height: 22px !important;
  453 + max-height: 44px !important;
  454 + }
  455 + }
  456 + }
  457 + }
  458 +</style>