Commit 1976571ae8cf91f377c06a09edce0cf2dab5dd92

Authored by YunaiV
2 parents 2866b587 af6a0224

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

# Conflicts:
#	yudao-ui-admin/src/views/mall/product/spu/index.vue
Showing 23 changed files with 1386 additions and 647 deletions
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.admin.property.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.ToString;
  7 +
  8 +import java.util.Set;
  9 +
  10 +/**
  11 + * @Description: ProductPropertyViewRespVO
  12 + * @Author: franky
  13 + * @CreateDate: 2022/7/5 21:29
  14 + * @Version: 1.0.0
  15 + */
  16 +@ApiModel("管理后台 - 规格名称详情展示 Request VO")
  17 +@Data
  18 +@ToString(callSuper = true)
  19 +public class ProductPropertyViewRespVO {
  20 +
  21 + @ApiModelProperty(value = "规格名称id", example = "1")
  22 + public Long propertyId;
  23 +
  24 + @ApiModelProperty(value = "规格名称", example = "内存")
  25 + public String name;
  26 +
  27 + @ApiModelProperty(value = "规格属性值集合", example = "[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]")
  28 + public Set<Tuple2> propertyValues;
  29 +
  30 + @Data
  31 + @ApiModel(value = "规格属性值元组")
  32 + public static class Tuple2 {
  33 + private final long v1;
  34 + private final String v2;
  35 + public Tuple2(Long v1, String v2) {
  36 + this.v1 = v1;
  37 + this.v2 = v2;
  38 + }
  39 +
  40 + }
  41 +
  42 +
  43 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/SpuRespVO.java
1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo; 1 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
2 2
  3 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
3 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; 4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
4 import io.swagger.annotations.ApiModel; 5 import io.swagger.annotations.ApiModel;
5 import io.swagger.annotations.ApiModelProperty; 6 import io.swagger.annotations.ApiModelProperty;
@@ -19,7 +20,7 @@ public class SpuRespVO extends ProductSpuBaseVO { @@ -19,7 +20,7 @@ public class SpuRespVO extends ProductSpuBaseVO {
19 20
20 // TODO @franky:注解要完整 21 // TODO @franky:注解要完整
21 22
22 - @ApiModelProperty(value = "主键", required = true) 23 + @ApiModelProperty(value = "主键", required = true, example = "1")
23 private Long id; 24 private Long id;
24 25
25 @ApiModelProperty(value = "创建时间") 26 @ApiModelProperty(value = "创建时间")
@@ -28,9 +29,13 @@ public class SpuRespVO extends ProductSpuBaseVO { @@ -28,9 +29,13 @@ public class SpuRespVO extends ProductSpuBaseVO {
28 /** 29 /**
29 * SKU 数组 30 * SKU 数组
30 */ 31 */
31 - List<ProductSkuRespVO> skus; 32 + @ApiModelProperty(value = "sku 数组", example = "[{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":10}],\"price\":12,\"originalPrice\":32,\"costPrice\":22,\"barCode\":\"765670123123\",\"picUrl\":\"http://test.yudao.iocoder.cn/72938088f1ca8438837c3b51394aea43.jpg\",\"status\":0,\"id\":7,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":11}],\"price\":13,\"originalPrice\":33,\"costPrice\":23,\"barCode\":\"888788770999\",\"picUrl\":\"http://test.yudao.iocoder.cn/6b902c700e5d32e862b6fd9af2e1c0e4.jpg\",\"status\":0,\"id\":8,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":10}],\"price\":14,\"originalPrice\":34,\"costPrice\":24,\"barCode\":\"9999981212\",\"picUrl\":\"http://test.yudao.iocoder.cn/eddf3c79b1917160d94d05244e1f47da.jpg\",\"status\":0,\"id\":9,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":11}],\"price\":15,\"originalPrice\":35,\"costPrice\":25,\"barCode\":\"4444121212\",\"picUrl\":\"http://test.yudao.iocoder.cn/88ac3eb068ea9cfac4726879b2776ccf.jpg\",\"status\":0,\"id\":10,\"createTime\":1656683270000}]")
  33 + private List<ProductSkuRespVO> skus;
32 34
33 @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]") 35 @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
34 - LinkedList<Long> categoryIds; 36 + private LinkedList<Long> categoryIds;
  37 +
  38 + @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\"}]}]")
  39 + private List<ProductPropertyViewRespVO> productPropertyViews;
35 40
36 } 41 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.category;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
  5 +import cn.iocoder.yudao.module.product.convert.category.CategoryConvert;
  6 +import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;
  7 +import cn.iocoder.yudao.module.product.service.category.CategoryService;
  8 +import io.swagger.annotations.Api;
  9 +import io.swagger.annotations.ApiOperation;
  10 +import org.springframework.validation.annotation.Validated;
  11 +import org.springframework.web.bind.annotation.GetMapping;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +
  15 +import javax.annotation.Resource;
  16 +import java.util.Comparator;
  17 +import java.util.List;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +@Api(tags = "用户 APP - 商品分类")
  22 +@RestController
  23 +@RequestMapping("/product/category")
  24 +@Validated
  25 +public class AppCategoryController {
  26 +
  27 + @Resource
  28 + private CategoryService categoryService;
  29 +
  30 + @GetMapping("/list")
  31 + @ApiOperation("获得商品分类列表")
  32 + public CommonResult<List<AppCategoryListRespVO>> listByQuery() {
  33 + List<CategoryDO> list = categoryService.getCategoryList();
  34 + list.sort(Comparator.comparing(CategoryDO::getSort));
  35 + return success(CategoryConvert.INSTANCE.convertList03(list));
  36 + }
  37 +
  38 +
  39 +
  40 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/vo/AppCategoryListRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.category.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotBlank;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@Data
  11 +@ApiModel(value = "App - 商品分类 列表 Request VO", description = "参数和 CategoryBaseVO 是一致的")
  12 +public class AppCategoryListRespVO {
  13 +
  14 + @ApiModelProperty(value = "分类编号", required = true, example = "2")
  15 + private Long id;
  16 +
  17 + @ApiModelProperty(value = "父分类编号", required = true, example = "1")
  18 + @NotNull(message = "父分类编号不能为空")
  19 + private Long parentId;
  20 +
  21 + @ApiModelProperty(value = "分类名称", required = true, example = "办公文具")
  22 + @NotBlank(message = "分类名称不能为空")
  23 + private String name;
  24 +
  25 + @ApiModelProperty(value = "分类图标")
  26 + @NotBlank(message = "分类图标不能为空")
  27 + private String icon;
  28 +
  29 + @ApiModelProperty(value = "分类图片", required = true)
  30 + @NotBlank(message = "分类图片不能为空")
  31 + private String bannerUrl;
  32 +
  33 + @ApiModelProperty(value = "分类排序", required = true, example = "1")
  34 + private Integer sort;
  35 +
  36 + @ApiModelProperty(value = "分类描述", required = true, example = "描述")
  37 + private String description;
  38 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.spu;
  2 +
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
  8 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
  9 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuRespVO;
  10 +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
  11 +import io.swagger.annotations.Api;
  12 +import io.swagger.annotations.ApiOperation;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.GetMapping;
  15 +import org.springframework.web.bind.annotation.RequestMapping;
  16 +import org.springframework.web.bind.annotation.RequestParam;
  17 +import org.springframework.web.bind.annotation.RestController;
  18 +
  19 +import javax.annotation.Resource;
  20 +import javax.validation.Valid;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Api(tags = "用户 APP - 商品spu")
  25 +@RestController
  26 +@RequestMapping("/product/spu")
  27 +@Validated
  28 +public class AppProductSpuController {
  29 +
  30 + @Resource
  31 + private ProductSpuService spuService;
  32 +
  33 + @GetMapping("/page")
  34 + @ApiOperation("获得商品spu分页")
  35 + public CommonResult<PageResult<AppSpuPageRespVO>> getSpuPage(@Valid AppSpuPageReqVO pageVO) {
  36 + return success(spuService.getSpuPage(pageVO));
  37 + }
  38 +
  39 + @GetMapping("/")
  40 + @ApiOperation("获取商品 - 通过商品id")
  41 + public CommonResult<AppSpuRespVO> getSpu(@RequestParam("spuId") Long spuId) {
  42 + AppSpuRespVO appSpuRespVO = BeanUtil.toBean(spuService.getSpu(spuId), AppSpuRespVO.class);
  43 + return success(appSpuRespVO);
  44 + }
  45 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.spu.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +
  10 +@ApiModel("App - 商品spu分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class AppSpuPageReqVO extends PageParam {
  15 +
  16 + @ApiModelProperty(value = "分类id")
  17 + private Long categoryId;
  18 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.spu.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.util.List;
  9 +
  10 +@ApiModel("App - 商品spu分页 Request VO")
  11 +@Data
  12 +public class AppSpuPageRespVO {
  13 +
  14 + @ApiModelProperty(value = "主键", required = true, example = "1")
  15 + private Long id;
  16 +
  17 + @ApiModelProperty(value = "商品名称")
  18 + private String name;
  19 +
  20 + @ApiModelProperty(value = "卖点", required = true)
  21 + @NotNull(message = "卖点不能为空")
  22 + private String sellPoint;
  23 +
  24 + @ApiModelProperty(value = "描述", required = true)
  25 + @NotNull(message = "描述不能为空")
  26 + private String description;
  27 +
  28 + @ApiModelProperty(value = "分类id", required = true)
  29 + @NotNull(message = "分类id不能为空")
  30 + private Long categoryId;
  31 +
  32 + @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张", required = true)
  33 + @NotNull(message = "商品主图地址,* 数组,以逗号分隔,最多上传15张不能为空")
  34 + private List<String> picUrls;
  35 +
  36 + @ApiModelProperty(value = "排序字段", required = true)
  37 + @NotNull(message = "排序字段不能为空")
  38 + private Integer sort;
  39 +
  40 + @ApiModelProperty(value = "点赞初始人数")
  41 + private Integer likeCount;
  42 +
  43 + @ApiModelProperty(value = "价格 单位使用:分")
  44 + private Integer price;
  45 +
  46 + @ApiModelProperty(value = "库存数量")
  47 + private Integer quantity;
  48 +
  49 + @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
  50 + private Boolean status;
  51 +
  52 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.spu.vo;
  2 +
  3 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuRespVO;
  4 +import io.swagger.annotations.ApiModel;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +/**
  10 + * <p>
  11 + *
  12 + * </p>
  13 + *
  14 + * @author LuoWenFeng
  15 + */
  16 +@ApiModel("App - 商品spu Response VO")
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +public class AppSpuRespVO extends SpuRespVO {
  20 +
  21 +
  22 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/category/CategoryConvert.java
@@ -4,6 +4,7 @@ import java.util.*; @@ -4,6 +4,7 @@ import java.util.*;
4 4
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6
  7 +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
7 import org.mapstruct.Mapper; 8 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
9 import cn.iocoder.yudao.module.product.controller.admin.category.vo.*; 10 import cn.iocoder.yudao.module.product.controller.admin.category.vo.*;
@@ -31,4 +32,5 @@ public interface CategoryConvert { @@ -31,4 +32,5 @@ public interface CategoryConvert {
31 32
32 List<CategoryExcelVO> convertList02(List<CategoryDO> list); 33 List<CategoryExcelVO> convertList02(List<CategoryDO> list);
33 34
  35 + List<AppCategoryListRespVO> convertList03(List<CategoryDO> list);
34 } 36 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
@@ -4,6 +4,8 @@ import java.util.*; @@ -4,6 +4,8 @@ import java.util.*;
4 4
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6
  7 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
  8 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
7 import org.mapstruct.Mapper; 9 import org.mapstruct.Mapper;
8 import org.mapstruct.Mapping; 10 import org.mapstruct.Mapping;
9 import org.mapstruct.Named; 11 import org.mapstruct.Named;
@@ -40,6 +42,11 @@ public interface ProductSpuConvert { @@ -40,6 +42,11 @@ public interface ProductSpuConvert {
40 42
41 List<SpuExcelVO> convertList02(List<ProductSpuDO> list); 43 List<SpuExcelVO> convertList02(List<ProductSpuDO> list);
42 44
  45 + SpuPageReqVO convert(AppSpuPageReqVO bean);
  46 +
  47 + @Mapping(source = "picUrls", target = "picUrls", qualifiedByName = "tokenizeToStringArray")
  48 + AppSpuPageRespVO convertAppResp(ProductSpuDO list);
  49 +
43 @Named("tokenizeToStringArray") 50 @Named("tokenizeToStringArray")
44 default List<String> translatePicUrlsArrayFromString(String picUrls) { 51 default List<String> translatePicUrlsArrayFromString(String picUrls) {
45 return Arrays.asList(StringUtils.tokenizeToStringArray(picUrls, ",")); 52 return Arrays.asList(StringUtils.tokenizeToStringArray(picUrls, ","));
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/CategoryService.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.service.category; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.service.category;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.product.controller.admin.category.vo.*; 4 import cn.iocoder.yudao.module.product.controller.admin.category.vo.*;
  5 +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
5 import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO; 6 import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;
6 7
7 import javax.validation.Valid; 8 import javax.validation.Valid;
@@ -83,4 +84,11 @@ public interface CategoryService { @@ -83,4 +84,11 @@ public interface CategoryService {
83 * @param categoryId 分类id 84 * @param categoryId 分类id
84 */ 85 */
85 void validatedCategoryById(Long categoryId); 86 void validatedCategoryById(Long categoryId);
  87 +
  88 + /**
  89 + * app端获得商品分类列表
  90 + *
  91 + * @return 商品分类列表
  92 + */
  93 + List<CategoryDO> getCategoryList();
86 } 94 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/CategoryServiceImpl.java
1 package cn.iocoder.yudao.module.product.service.category; 1 package cn.iocoder.yudao.module.product.service.category;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.exception.ErrorCode; 4 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated; @@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated;
13 import javax.annotation.Resource; 14 import javax.annotation.Resource;
14 import java.util.Collection; 15 import java.util.Collection;
15 import java.util.List; 16 import java.util.List;
  17 +import java.util.stream.Collectors;
16 18
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
18 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; 20 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
@@ -106,4 +108,13 @@ public class CategoryServiceImpl implements CategoryService { @@ -106,4 +108,13 @@ public class CategoryServiceImpl implements CategoryService {
106 return categoryMapper.selectList(treeListReqVO); 108 return categoryMapper.selectList(treeListReqVO);
107 } 109 }
108 110
  111 + @Override
  112 + public List<CategoryDO> getCategoryList() {
  113 + return categoryMapper.selectList()
  114 + .stream()
  115 + .filter(v->v.getStatus().equals(CommonStatusEnum.ENABLE.getStatus()))
  116 + .collect(Collectors.toList());
  117 + }
  118 +
  119 +
109 } 120 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.product.service.spu; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.product.service.spu;
3 import java.util.*; 3 import java.util.*;
4 import javax.validation.*; 4 import javax.validation.*;
5 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; 5 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
  6 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
  7 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
6 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; 8 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 10
@@ -67,4 +69,13 @@ public interface ProductSpuService { @@ -67,4 +69,13 @@ public interface ProductSpuService {
67 */ 69 */
68 List<ProductSpuDO> getSpuList(SpuExportReqVO exportReqVO); 70 List<ProductSpuDO> getSpuList(SpuExportReqVO exportReqVO);
69 71
  72 + /**
  73 + * 获得商品spu分页
  74 + *
  75 + * @param pageReqVO 分页查询
  76 + * @return 商品spu分页
  77 + */
  78 + PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO);
  79 +
  80 +
70 } 81 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
1 package cn.iocoder.yudao.module.product.service.spu; 1 package cn.iocoder.yudao.module.product.service.spu;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
  5 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
  6 +import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO; 8 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO;
5 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; 9 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
6 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; 10 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
  11 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
7 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; 13 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
8 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; 14 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
9 -import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;  
10 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 15 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
11 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; 16 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
12 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; 17 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
13 import cn.iocoder.yudao.module.product.service.category.CategoryService; 18 import cn.iocoder.yudao.module.product.service.category.CategoryService;
  19 +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
14 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; 20 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
15 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
16 import org.springframework.transaction.annotation.Transactional; 22 import org.springframework.transaction.annotation.Transactional;
@@ -41,6 +47,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -41,6 +47,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
41 @Resource 47 @Resource
42 private ProductSkuService productSkuService; 48 private ProductSkuService productSkuService;
43 49
  50 + @Resource
  51 + private ProductPropertyService productPropertyService;
  52 +
44 @Override 53 @Override
45 @Transactional 54 @Transactional
46 public Long createSpu(ProductSpuCreateReqVO createReqVO) { 55 public Long createSpu(ProductSpuCreateReqVO createReqVO) {
@@ -104,6 +113,29 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -104,6 +113,29 @@ public class ProductSpuServiceImpl implements ProductSpuService {
104 if (null != spuVO) { 113 if (null != spuVO) {
105 List<ProductSkuRespVO> skuReqs = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuId(id)); 114 List<ProductSkuRespVO> skuReqs = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuId(id));
106 spuVO.setSkus(skuReqs); 115 spuVO.setSkus(skuReqs);
  116 + List<ProductSkuRespVO.Property> properties = new ArrayList<>();
  117 + // 组合 sku 规格属性
  118 + for (ProductSkuRespVO productSkuRespVO : skuReqs) {
  119 + properties.addAll(productSkuRespVO.getProperties());
  120 + }
  121 + Map<Long, List<ProductSkuBaseVO.Property>> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId));
  122 + List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(new ArrayList<>(propertyMaps.keySet()));
  123 + // 装载组装过后的属性
  124 + List<ProductPropertyViewRespVO> productPropertyViews = new ArrayList<>();
  125 + propertyAndValueList.forEach(p -> {
  126 + ProductPropertyViewRespVO productPropertyViewRespVO = new ProductPropertyViewRespVO();
  127 + productPropertyViewRespVO.setPropertyId(p.getId());
  128 + productPropertyViewRespVO.setName(p.getName());
  129 + Set<ProductPropertyViewRespVO.Tuple2> propertyValues = new HashSet<>();
  130 + Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getPropertyValueList().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
  131 + propertyMaps.get(p.getId()).forEach(pv -> {
  132 + ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName());
  133 + propertyValues.add(tuple2);
  134 + });
  135 + productPropertyViewRespVO.setPropertyValues(propertyValues);
  136 + productPropertyViews.add(productPropertyViewRespVO);
  137 + });
  138 + spuVO.setProductPropertyViews(productPropertyViews);
107 // 组合分类 139 // 组合分类
108 if (null != spuVO.getCategoryId()) { 140 if (null != spuVO.getCategoryId()) {
109 LinkedList<Long> categoryArray = new LinkedList<>(); 141 LinkedList<Long> categoryArray = new LinkedList<>();
@@ -144,4 +176,17 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -144,4 +176,17 @@ public class ProductSpuServiceImpl implements ProductSpuService {
144 return ProductSpuMapper.selectList(exportReqVO); 176 return ProductSpuMapper.selectList(exportReqVO);
145 } 177 }
146 178
  179 + @Override
  180 + public PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO) {
  181 + PageResult<ProductSpuDO> productSpuDOPageResult = ProductSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
  182 + PageResult<AppSpuPageRespVO> pageResult = new PageResult<>();
  183 + List<AppSpuPageRespVO> collect = productSpuDOPageResult.getList()
  184 + .stream()
  185 + .map(ProductSpuConvert.INSTANCE::convertAppResp)
  186 + .collect(Collectors.toList());
  187 + pageResult.setList(collect);
  188 + pageResult.setTotal(productSpuDOPageResult.getTotal());
  189 + return pageResult;
  190 + }
  191 +
147 } 192 }
yudao-ui-admin/src/views/mall/product/spu/index.vue
@@ -25,9 +25,9 @@ @@ -25,9 +25,9 @@
25 <el-option label="下架" value="1"/> 25 <el-option label="下架" value="1"/>
26 </el-select> 26 </el-select>
27 </el-form-item> 27 </el-form-item>
28 - <el-form-item label="创建时间" prop="createTime">  
29 - <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"  
30 - range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" /> 28 + <el-form-item label="创建时间">
  29 + <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
  30 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
31 </el-form-item> 31 </el-form-item>
32 <el-form-item> 32 <el-form-item>
33 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> 33 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
@@ -55,8 +55,8 @@ @@ -55,8 +55,8 @@
55 <el-table v-loading="loading" :data="list"> 55 <el-table v-loading="loading" :data="list">
56 <el-table-column label="主键" align="center" prop="id"/> 56 <el-table-column label="主键" align="center" prop="id"/>
57 <el-table-column label="商品名称" align="center" prop="name"/> 57 <el-table-column label="商品名称" align="center" prop="name"/>
58 -<!-- <el-table-column label="卖点" align="center" prop="sellPoint"/>-->  
59 -<!-- <el-table-column label="描述" align="center" prop="description"/>--> 58 + <!-- <el-table-column label="卖点" align="center" prop="sellPoint"/>-->
  59 + <!-- <el-table-column label="描述" align="center" prop="description"/>-->
60 <el-table-column label="分类id" align="center" prop="categoryId"/> 60 <el-table-column label="分类id" align="center" prop="categoryId"/>
61 <el-table-column label="商品主图地址" align="center" prop="picUrls"> 61 <el-table-column label="商品主图地址" align="center" prop="picUrls">
62 <template slot-scope="scope"> 62 <template slot-scope="scope">
@@ -67,7 +67,7 @@ @@ -67,7 +67,7 @@
67 <el-table-column label="点赞初始人数" align="center" prop="likeCount"/> 67 <el-table-column label="点赞初始人数" align="center" prop="likeCount"/>
68 <el-table-column label="价格 (分)" align="center" prop="price"/> 68 <el-table-column label="价格 (分)" align="center" prop="price"/>
69 <el-table-column label="库存数量" align="center" prop="quantity"/> 69 <el-table-column label="库存数量" align="center" prop="quantity"/>
70 -<!-- <el-table-column label="状态" align="center" prop="status"/>--> 70 + <!-- <el-table-column label="状态" align="center" prop="status"/>-->
71 <el-table-column label="创建时间" align="center" prop="createTime" width="180"> 71 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
72 <template slot-scope="scope"> 72 <template slot-scope="scope">
73 <span>{{ parseTime(scope.row.createTime) }}</span> 73 <span>{{ parseTime(scope.row.createTime) }}</span>
@@ -102,12 +102,12 @@ @@ -102,12 +102,12 @@
102 </el-form-item> 102 </el-form-item>
103 <el-form-item label="分类id" prop="categoryIds"> 103 <el-form-item label="分类id" prop="categoryIds">
104 <el-cascader 104 <el-cascader
105 - v-model="form.categoryIds"  
106 - placeholder="请输入分类id"  
107 - style="width: 100%"  
108 - :options="categoryList"  
109 - :props="propName"  
110 - clearable></el-cascader> 105 + v-model="form.categoryIds"
  106 + placeholder="请输入分类id"
  107 + style="width: 100%"
  108 + :options="categoryList"
  109 + :props="propName"
  110 + clearable></el-cascader>
111 </el-form-item> 111 </el-form-item>
112 <el-form-item label="商品主图地址" prop="picUrls"> 112 <el-form-item label="商品主图地址" prop="picUrls">
113 <ImageUpload v-model="form.picUrls" :limit="10"/> 113 <ImageUpload v-model="form.picUrls" :limit="10"/>
@@ -115,17 +115,17 @@ @@ -115,17 +115,17 @@
115 <el-form-item label="商品规格"> 115 <el-form-item label="商品规格">
116 <el-button size="mini" @click="shopTagInput()">添加规格</el-button> 116 <el-button size="mini" @click="shopTagInput()">添加规格</el-button>
117 <div v-for="(tag, tagIndex) in skuTags" :key="tagIndex"> 117 <div v-for="(tag, tagIndex) in skuTags" :key="tagIndex">
118 - <span>{{tag.name}}</span> 118 + <span>{{ tag.name }}</span>
119 <el-button style="margin-left: 10px" class="button-new-tag" type="text" icon="el-icon-delete" 119 <el-button style="margin-left: 10px" class="button-new-tag" type="text" icon="el-icon-delete"
120 @click="removeTag(tagIndex)">删除 120 @click="removeTag(tagIndex)">删除
121 </el-button> 121 </el-button>
122 <br/> 122 <br/>
123 <el-tag 123 <el-tag
124 - v-for="(tagItem, tagItemIndex) in tag.selectValues"  
125 - :key="tagItem"  
126 - style="margin-right: 10px"  
127 - :disable-transitions="false">  
128 - {{tagItem}} 124 + v-for="(tagItem, tagItemIndex) in tag.selectValues"
  125 + :key="tagItem"
  126 + style="margin-right: 10px"
  127 + :disable-transitions="false">
  128 + {{ tagItem }}
129 </el-tag> 129 </el-tag>
130 <!-- <el-input--> 130 <!-- <el-input-->
131 <!-- class="input-new-tag"--> 131 <!-- class="input-new-tag"-->
@@ -143,10 +143,10 @@ @@ -143,10 +143,10 @@
143 <el-select v-model="addTagInput.name" filterable allow-create default-first-option placeholder="请选择" 143 <el-select v-model="addTagInput.name" filterable allow-create default-first-option placeholder="请选择"
144 @change="handleTagClick"> 144 @change="handleTagClick">
145 <el-option 145 <el-option
146 - v-for="item in unUseTags"  
147 - :key="item.id"  
148 - :label="item.name"  
149 - :value="item.name"> 146 + v-for="item in unUseTags"
  147 + :key="item.id"
  148 + :label="item.name"
  149 + :value="item.name">
150 </el-option> 150 </el-option>
151 </el-select> 151 </el-select>
152 </el-col> 152 </el-col>
@@ -156,10 +156,10 @@ @@ -156,10 +156,10 @@
156 <el-select v-model="addTagInput.selectValues" multiple filterable allow-create default-first-option 156 <el-select v-model="addTagInput.selectValues" multiple filterable allow-create default-first-option
157 placeholder="请选择"> 157 placeholder="请选择">
158 <el-option 158 <el-option
159 - v-for="item in dbTagValues"  
160 - :key="item.id"  
161 - :label="item.name"  
162 - :value="item.name"> 159 + v-for="item in dbTagValues"
  160 + :key="item.id"
  161 + :label="item.name"
  162 + :value="item.name">
163 </el-option> 163 </el-option>
164 </el-select> 164 </el-select>
165 </el-col> 165 </el-col>
@@ -170,13 +170,13 @@ @@ -170,13 +170,13 @@
170 </el-form-item> 170 </el-form-item>
171 <el-form-item v-if="form.skus.length>0"> 171 <el-form-item v-if="form.skus.length>0">
172 <el-table 172 <el-table
173 - :data="form.skus"  
174 - border  
175 - style="width: 100%; margin-top: 20px"  
176 - :span-method="tableSpanMethod"> 173 + :data="form.skus"
  174 + border
  175 + style="width: 100%; margin-top: 20px"
  176 + :span-method="tableSpanMethod">
177 <el-table-column v-for="(leftTitle, index) in skuTags" :key="index" :label="leftTitle.name"> 177 <el-table-column v-for="(leftTitle, index) in skuTags" :key="index" :label="leftTitle.name">
178 <template slot-scope="scope"> 178 <template slot-scope="scope">
179 - {{scope.row.propertyChildNames[index]}} 179 + {{ scope.row.propertyChildNames[index] }}
180 </template> 180 </template>
181 </el-table-column> 181 </el-table-column>
182 <el-table-column v-if="skuTags.length" 182 <el-table-column v-if="skuTags.length"
@@ -189,62 +189,63 @@ @@ -189,62 +189,63 @@
189 </template> 189 </template>
190 </el-table-column> 190 </el-table-column>
191 <el-table-column 191 <el-table-column
192 - prop="prodName"  
193 - label="条形码"  
194 - width="250" v-if="skuTags.length"> 192 + prop="prodName"
  193 + label="条形码"
  194 + width="250" v-if="skuTags.length">
195 <template slot-scope="scope"> 195 <template slot-scope="scope">
196 - <el-input v-model="scope.row.barCode" type="textarea" :disabled="scope.row.status===1"></el-input> 196 + <el-input v-model="scope.row.barCode" type="textarea" :disabled="scope.row.status==1"></el-input>
197 </template> 197 </template>
198 </el-table-column> 198 </el-table-column>
199 <el-table-column 199 <el-table-column
200 - prop="price"  
201 - label="销售价"> 200 + prop="price"
  201 + label="销售价">
202 <template slot-scope="scope"> 202 <template slot-scope="scope">
203 <el-input-number 203 <el-input-number
204 - size="small"  
205 - v-model="scope.row.price"  
206 - controls-position="right"  
207 - :precision="2"  
208 - :max="1000000000"  
209 - :min="0.01"  
210 - :disabled="scope.row.status===1"> 204 + size="small"
  205 + v-model="scope.row.price"
  206 + controls-position="right"
  207 + :precision="2"
  208 + :max="1000000000"
  209 + :min="0.01"
  210 + :disabled="scope.row.status==1">
211 </el-input-number> 211 </el-input-number>
212 </template> 212 </template>
213 </el-table-column> 213 </el-table-column>
214 <el-table-column 214 <el-table-column
215 - prop="oriPrice"  
216 - label="成本价"> 215 + prop="oriPrice"
  216 + label="成本价">
217 <template slot-scope="scope"> 217 <template slot-scope="scope">
218 <el-input-number 218 <el-input-number
219 - size="small"  
220 - v-model="scope.row.costPrice"  
221 - controls-position="right"  
222 - :precision="2"  
223 - :max="1000000000"  
224 - :min="0.01"  
225 - :disabled="scope.row.status===1"> 219 + size="small"
  220 + v-model="scope.row.costPrice"
  221 + controls-position="right"
  222 + :precision="2"
  223 + :max="1000000000"
  224 + :min="0.01"
  225 + :disabled="scope.row.status==1">
226 </el-input-number> 226 </el-input-number>
227 </template> 227 </template>
228 </el-table-column> 228 </el-table-column>
229 <el-table-column 229 <el-table-column
230 - prop="oriPrice"  
231 - label="原价"> 230 + prop="oriPrice"
  231 + label="原价">
232 <template slot-scope="scope"> 232 <template slot-scope="scope">
233 <el-input-number 233 <el-input-number
234 - size="small"  
235 - v-model="scope.row.originalPrice"  
236 - controls-position="right"  
237 - :precision="2"  
238 - :max="1000000000"  
239 - :min="0.01"  
240 - :disabled="scope.row.status===1"> 234 + size="small"
  235 + v-model="scope.row.originalPrice"
  236 + controls-position="right"
  237 + :precision="2"
  238 + :max="1000000000"
  239 + :min="0.01"
  240 + :disabled="scope.row.status==1">
241 </el-input-number> 241 </el-input-number>
242 </template> 242 </template>
243 </el-table-column> 243 </el-table-column>
244 <el-table-column 244 <el-table-column
245 - label="操作"> 245 + label="操作">
246 <template slot-scope="scope"> 246 <template slot-scope="scope">
247 - <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" v-if="scope.row.status===0"> 247 + <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)"
  248 + v-if="scope.row.status===0">
248 正常 249 正常
249 </el-button> 250 </el-button>
250 <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" v-else>已禁用</el-button> 251 <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" v-else>已禁用</el-button>
@@ -280,456 +281,564 @@ @@ -280,456 +281,564 @@
280 </template> 281 </template>
281 282
282 <script> 283 <script>
283 - import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu";  
284 - import {  
285 - createCategory,  
286 - deleteCategory,  
287 - exportCategoryExcel,  
288 - getCategory,  
289 - listCategory,  
290 - updateCategory  
291 - } from "@/api/mall/product/category";  
292 - import {  
293 - createProperty,  
294 - updateProperty,  
295 - deleteProperty,  
296 - getProperty,  
297 - getPropertyPage,  
298 - exportPropertyExcel  
299 - } from "@/api/mall/product/property"; 284 +import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu";
  285 +import {
  286 + createCategory,
  287 + deleteCategory,
  288 + exportCategoryExcel,
  289 + getCategory,
  290 + listCategory,
  291 + updateCategory
  292 +} from "@/api/mall/product/category";
  293 +import {
  294 + createProperty,
  295 + updateProperty,
  296 + deleteProperty,
  297 + getProperty,
  298 + getPropertyPage,
  299 + exportPropertyExcel
  300 +} from "@/api/mall/product/property";
300 301
301 - import Editor from '@/components/Editor';  
302 - import ImageUpload from '@/components/ImageUpload'; 302 +import Editor from '@/components/Editor';
  303 +import ImageUpload from '@/components/ImageUpload';
303 304
304 - export default {  
305 - name: "Spu",  
306 - components: {  
307 - Editor, ImageUpload  
308 - },  
309 - data() {  
310 - return {  
311 - tableLeftTitles: [],  
312 - dbTagValues: [],  
313 - allhistoryTags: [],  
314 - unUseTags: [],  
315 - propertyPageList: [],  
316 - isShowTagInput: false,  
317 - addTagInput: {  
318 - name: '',  
319 - propertyId: '',  
320 - selectValues: [],  
321 - selectValueIds: [],  
322 - },  
323 - skuTags: [],  
324 - propName: {  
325 - checkStrictly: true,  
326 - label: 'name',  
327 - value: 'id'  
328 - },  
329 - categoryList: [],  
330 - // 遮罩层  
331 - loading: true,  
332 - // 导出遮罩层  
333 - exportLoading: false,  
334 - // 显示搜索条件  
335 - showSearch: true,  
336 - // 总条数  
337 - total: 0,  
338 - // 商品spu列表  
339 - list: [],  
340 - // 弹出层标题  
341 - title: "",  
342 - // 是否显示弹出层  
343 - open: false,  
344 - // 查询参数  
345 - queryParams: {  
346 - pageNo: 1,  
347 - pageSize: 10,  
348 - name: null,  
349 - sellPoint: null,  
350 - description: null,  
351 - categoryId: null,  
352 - picUrls: null,  
353 - sort: null,  
354 - likeCount: null,  
355 - price: null,  
356 - quantity: null,  
357 - status: null,  
358 - createTime: []  
359 - },  
360 - // 表单参数  
361 - form: {  
362 - id: undefined,  
363 - name: undefined,  
364 - sellPoint: undefined,  
365 - description: undefined,  
366 - categoryId: undefined,  
367 - categoryIds: [],  
368 - picUrls: undefined,  
369 - sort: undefined,  
370 - likeCount: undefined,  
371 - price: undefined,  
372 - quantity: undefined,  
373 - status: undefined,  
374 - isShowTagInput: undefined,  
375 - skus:[],  
376 - },  
377 - // 表单校验  
378 - rules: {  
379 - sellPoint: [{required: true, message: "卖点不能为空", trigger: "blur"}],  
380 - description: [{required: true, message: "描述不能为空", trigger: "blur"}],  
381 - categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"}],  
382 - picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}],  
383 - sort: [{required: true, message: "排序字段不能为空", trigger: "blur"}],  
384 - },  
385 - tagIndex:0,  
386 - };  
387 - },  
388 - created() { 305 +export default {
  306 + name: "Spu",
  307 + components: {
  308 + Editor, ImageUpload
  309 + },
  310 + data() {
  311 + return {
  312 + tableLeftTitles: [],
  313 + dbTagValues: [],
  314 + allhistoryTags: [],
  315 + unUseTags: [],
  316 + propertyPageList: [],
  317 + isShowTagInput: false,
  318 + addTagInput: {
  319 + name: '',
  320 + propertyId: '',
  321 + selectValues: [],
  322 + selectValueIds: [],
  323 + selectObect:[],
  324 + },
  325 + skuTags: [],
  326 + propName: {
  327 + checkStrictly: true,
  328 + label: 'name',
  329 + value: 'id'
  330 + },
  331 + categoryList: [],
  332 + // 遮罩层
  333 + loading: true,
  334 + // 导出遮罩层
  335 + exportLoading: false,
  336 + // 显示搜索条件
  337 + showSearch: true,
  338 + // 总条数
  339 + total: 0,
  340 + // 商品spu列表
  341 + list: [],
  342 + // 弹出层标题
  343 + title: "",
  344 + // 是否显示弹出层
  345 + open: false,
  346 + dateRangeCreateTime: [],
  347 + // 查询参数
  348 + queryParams: {
  349 + pageNo: 1,
  350 + pageSize: 10,
  351 + name: null,
  352 + sellPoint: null,
  353 + description: null,
  354 + categoryId: null,
  355 + picUrls: null,
  356 + sort: null,
  357 + likeCount: null,
  358 + price: null,
  359 + quantity: null,
  360 + status: null,
  361 + },
  362 + // 表单参数
  363 + form: {
  364 + id: undefined,
  365 + name: undefined,
  366 + sellPoint: undefined,
  367 + description: undefined,
  368 + categoryId: undefined,
  369 + categoryIds: [],
  370 + picUrls: undefined,
  371 + sort: undefined,
  372 + likeCount: undefined,
  373 + price: undefined,
  374 + quantity: undefined,
  375 + status: undefined,
  376 + isShowTagInput: undefined,
  377 + skus: [],
  378 + },
  379 + // 表单校验
  380 + rules: {
  381 + sellPoint: [{required: true, message: "卖点不能为空", trigger: "blur"}],
  382 + description: [{required: true, message: "描述不能为空", trigger: "blur"}],
  383 + categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"}],
  384 + picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}],
  385 + sort: [{required: true, message: "排序字段不能为空", trigger: "blur"}],
  386 + },
  387 + tagIndex: 0,
  388 + };
  389 + },
  390 + created() {
389 391
390 - this.getList(); 392 + this.getList();
  393 + this.getPropertyPageList();
  394 + this.getListCategory();
  395 + },
  396 + methods: {
  397 + getTableSpecData() {
  398 + return this.value
  399 + },
  400 + tableSpanMethod({row, column, rowIndex, columnIndex}) {
391 401
392 - },  
393 - methods: {  
394 - getTableSpecData() {  
395 - return this.value  
396 - },  
397 - tableSpanMethod({row, column, rowIndex, columnIndex}) { 402 + },
  403 + changeSkuStatus(tagIndex) {
  404 + if (this.form.skus[tagIndex].status == 0) {
  405 + this.form.skus[tagIndex].status = 1;
  406 + } else {
  407 + this.form.skus[tagIndex].status = 0;
  408 + }
398 409
399 - },  
400 - changeSkuStatus(tagIndex) {  
401 - if(this.form.skus[tagIndex].status === 0){  
402 - this.form.skus[tagIndex].status = 1 ;  
403 - }else {  
404 - this.form.skus[tagIndex].status = 0 ;  
405 - } 410 + },
  411 + skuAddProdName() {
  412 + if (this.initing) {
  413 + return
  414 + }
  415 + let skuList = []
  416 + for (let i = 0; i < this.value.length; i++) {
  417 + const sku = Object.assign({}, this.value[i])
  418 + if (!sku.properties) {
  419 + return
  420 + }
  421 + sku.skuName = ''
  422 + let properties = sku.properties.split(';')
  423 + for (const propertiesKey in properties) {
  424 + sku.skuName += properties[propertiesKey].split(':')[1] + ' '
  425 + }
  426 + sku.prodName = this.prodName + ' ' + sku.skuName
  427 + skuList.push(sku)
  428 + }
  429 + this.$emit('input', skuList)
  430 + },
  431 + handleTagClose(tagIndex, tagItemIndex) {
406 432
407 - },  
408 - skuAddProdName() {  
409 - if (this.initing) {  
410 - return  
411 - }  
412 - let skuList = []  
413 - for (let i = 0; i < this.value.length; i++) {  
414 - const sku = Object.assign({}, this.value[i])  
415 - if (!sku.properties) {  
416 - return  
417 - }  
418 - sku.skuName = ''  
419 - let properties = sku.properties.split(';')  
420 - for (const propertiesKey in properties) {  
421 - sku.skuName += properties[propertiesKey].split(':')[1] + ' '  
422 - }  
423 - sku.prodName = this.prodName + ' ' + sku.skuName  
424 - skuList.push(sku)  
425 - }  
426 - this.$emit('input', skuList)  
427 - },  
428 - handleTagClose(tagIndex, tagItemIndex) {  
429 - },  
430 - //确定添加sku规格  
431 - addTag() {  
432 - let skus = this.unUseTags.map(function (item, index) {  
433 - return item.name  
434 - });  
435 - console.log("skus=="+JSON.stringify(skus))  
436 - let index = skus.indexOf(this.addTagInput.name);  
437 - console.log("index=="+index)  
438 - console.log("skus[index].id=="+this.unUseTags[index].id)  
439 - console.log("this.unUseTags[index].propertyValueList=="+JSON.stringify(this.unUseTags[index].propertyValueList))  
440 - this.addTagInput.propertyId = this.unUseTags[index].id;  
441 - for (let i = 0; i < this.addTagInput.selectValues.length; i++) {  
442 - for (let j = 0; j < this.unUseTags[index].propertyValueList.length; j++) {  
443 - if (this.addTagInput.selectValues[i] === this.unUseTags[index].propertyValueList[j].name) {  
444 - this.addTagInput.selectValueIds.push(this.unUseTags[index].propertyValueList[j].id)  
445 - }  
446 - }  
447 - }  
448 - let addTagInput = JSON.parse(JSON.stringify(this.addTagInput))  
449 - console.log("addTagInput=="+JSON.stringify(addTagInput))  
450 - this.skuTags.push(addTagInput);  
451 - this.unUseTags.splice(index, 1);  
452 - this.isShowTagInput = false;  
453 - this.getTable();  
454 - },  
455 - getTable(){  
456 - this.form.skus=[];  
457 - let skuTags = JSON.parse(JSON.stringify(this.skuTags));  
458 - let sku1s = [];  
459 - let skuIds = [];  
460 - let propertyIds = [];  
461 - let propertyNames = [];  
462 - for (let i = 0; i < skuTags.length; i++) {  
463 - sku1s.push(skuTags[i].selectValues);  
464 - skuIds.push(skuTags[i].selectValueIds);  
465 - propertyIds.push(skuTags[i].propertyId);  
466 - propertyNames.push(skuTags[i].name);  
467 - }  
468 - let skuAll = sku1s.reduce((x,y) =>{  
469 - let arr = [];  
470 - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))  
471 - return arr;  
472 - },[[]])  
473 - console.log(skuAll); 433 + },
  434 + //确定添加sku规格
  435 + addTag() {
474 436
475 - let skuIdAll = skuIds.reduce((x,y) =>{  
476 - let arr = [];  
477 - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))  
478 - return arr;  
479 - },[[]])  
480 - console.log(skuIdAll);  
481 - for (let i = 0; i < skuAll.length; i++) {  
482 - let han = {  
483 - propertyNames:propertyNames,  
484 - propertyIds:propertyIds,  
485 - propertyChildNames:skuAll[i],  
486 - propertyChildIds:skuIdAll[i],  
487 - properties: [],  
488 - picUrl: '',  
489 - costPrice: '',  
490 - originalPrice: '',  
491 - spuId: '',  
492 - prodName: '',  
493 - price: '',  
494 - barCode: '',  
495 - status: '0',  
496 - }  
497 - this.form.skus.push(han);  
498 - }  
499 - this.form.skus.forEach(x=>{  
500 - x.properties=[];  
501 - for (let i = 0; i <x.propertyIds.length ; i++) {  
502 - x.properties.push({  
503 - propertyId:x.propertyIds[i],  
504 - valueId:x.propertyChildIds[i]  
505 - })  
506 - }  
507 - }) 437 + let skus = this.unUseTags.map(function (item, index) {
  438 + return item.name
  439 + });
  440 + let index = skus.indexOf(this.addTagInput.name);
508 441
509 - console.log("this.skus=="+JSON.stringify(this.form.skus))  
510 - },  
511 - hideTagInput() {  
512 - this.isShowTagInput = false;  
513 - this.addTagInput = {  
514 - name: '',  
515 - propertyId: '',  
516 - selectValues: [],  
517 - selectValueIds: [],  
518 - };  
519 - },  
520 - shopTagInput() {  
521 - if (this.unUseTags.length <= 0) {  
522 - return this.$message.error("规格已经添加完毕")  
523 - }  
524 - this.isShowTagInput = true;  
525 - this.addTagInput = {  
526 - name: '',  
527 - propertyId: '',  
528 - selectValues: [],  
529 - selectValueIds: [],  
530 - };  
531 - },  
532 - //删除已选的规格  
533 - removeTag(row) {  
534 - let skus = this.allhistoryTags.map(function (item, index) {  
535 - return item.name  
536 - })  
537 - let index = skus.indexOf(this.skuTags[row].name);  
538 - this.unUseTags.push(this.allhistoryTags[index]);  
539 - this.skuTags.splice(row, 1);  
540 - this.getTable();  
541 - },  
542 - handleTagClick(row) {  
543 - for (let i = 0; i < this.propertyPageList.length; i++) {  
544 - if (row == this.propertyPageList[i].name) {  
545 - this.dbTagValues = this.propertyPageList[i].propertyValueList  
546 - }  
547 - }  
548 - },  
549 - /** 查询规格 */  
550 - getPropertyPageList() {  
551 - // 执行查询  
552 - getPropertyPage().then(response => {  
553 - this.propertyPageList = response.data.list; 442 + this.addTagInput.propertyId = this.unUseTags[index].id;
  443 + for (let i = 0; i < this.addTagInput.selectValues.length; i++) {
  444 + for (let j = 0; j < this.unUseTags[index].propertyValueList.length; j++) {
  445 + if (this.addTagInput.selectValues[i] === this.unUseTags[index].propertyValueList[j].name) {
  446 + this.addTagInput.selectValueIds.push(this.unUseTags[index].propertyValueList[j].id)
  447 + this.addTagInput.selectObect.push({
  448 + id:this.unUseTags[index].propertyValueList[j].id,
  449 + name:this.unUseTags[index].propertyValueList[j].name,
  450 + })
  451 + }
  452 + }
  453 + }
  454 + let addTagInput = JSON.parse(JSON.stringify(this.addTagInput))
  455 + this.skuTags.push(addTagInput);
554 456
555 - this.unUseTags = this.propertyPageList.map(function (item, index) {  
556 - return item  
557 - })  
558 - this.allhistoryTags = JSON.parse(JSON.stringify(this.unUseTags));  
559 - console.log(this.propertyPageList)  
560 - });  
561 - },  
562 - /** 查询分类 */  
563 - getListCategory() {  
564 - // 执行查询  
565 - listCategory().then(response => {  
566 - this.categoryList = this.handleTree(response.data, "id", "parentId"); 457 + // if (this.skuTags.length > 1) {
  458 + this.skuTags = this.skuTags.sort((a, b) => a.propertyId - b.propertyId);
  459 + this.skuTags.forEach(function (item,index) {
  460 + item.selectObect = item.selectObect.sort((a, b) => a.id - b.id)
  461 + })
567 462
568 - });  
569 - },  
570 - /** 查询列表 */  
571 - getList() {  
572 - this.loading = true;  
573 - // 执行查询  
574 - getSpuPage(this.queryParams).then(response => {  
575 - this.list = response.data.list;  
576 - this.total = response.data.total;  
577 - this.loading = false;  
578 - });  
579 - },  
580 - /** 取消按钮 */  
581 - cancel() {  
582 - this.open = false;  
583 - this.reset();  
584 - },  
585 - /** 表单重置 */  
586 - reset() { 463 + for (let i = 0; i <this.skuTags.length ; i++) {
  464 + let selectValueIds=[];
  465 + let selectValues=[];
  466 + for (let j = 0; j < this.skuTags[i].selectObect.length; j++) {
  467 + selectValueIds.push(this.skuTags[i].selectObect[j].id);
  468 + selectValues.push(this.skuTags[i].selectObect[j].name);
  469 + }
  470 + this.skuTags[i].selectValues = selectValues;
  471 + this.skuTags[i].selectValueIds = selectValueIds;
  472 + }
  473 +
  474 + this.unUseTags.splice(index, 1);
  475 + this.isShowTagInput = false;
  476 + this.getTable();
  477 + },
  478 + getTable() {
  479 + this.form.skus = [];
  480 + let skuTags = JSON.parse(JSON.stringify(this.skuTags));
  481 + let sku1s = [];
  482 + let skuIds = [];
  483 + let propertyIds = [];
  484 + let propertyNames = [];
  485 + for (let i = 0; i < skuTags.length; i++) {
  486 + sku1s.push(skuTags[i].selectValues);
  487 + skuIds.push(skuTags[i].selectValueIds);
  488 + propertyIds.push(skuTags[i].propertyId);
  489 + propertyNames.push(skuTags[i].name);
  490 + }
587 491
588 - this.form = {  
589 - id: undefined,  
590 - name: undefined,  
591 - sellPoint: undefined,  
592 - description: undefined,  
593 - categoryId: undefined,  
594 - categoryIds: [],  
595 - picUrls: undefined,  
596 - sort: undefined,  
597 - likeCount: undefined,  
598 - price: undefined,  
599 - quantity: undefined,  
600 - status: undefined,  
601 - isShowTagInput: undefined,  
602 - skus:[],  
603 - };  
604 - this.skuTags=[];  
605 - this.resetForm("form");  
606 - },  
607 - /** 搜索按钮操作 */  
608 - handleQuery() {  
609 - this.queryParams.pageNo = 1;  
610 - this.getList();  
611 - },  
612 - /** 重置按钮操作 */  
613 - resetQuery() {  
614 - this.dateRangeCreateTime = [];  
615 - this.resetForm("queryForm");  
616 - this.handleQuery();  
617 - },  
618 - /** 新增按钮操作 */  
619 - handleAdd() {  
620 - this.reset();  
621 - this.open = true;  
622 - this.title = "添加商品spu";  
623 - this.getListCategory();  
624 - this.getPropertyPageList();  
625 - },  
626 - /** 修改按钮操作 */  
627 - handleUpdate(row) {  
628 - this.reset();  
629 - getSpu(row.id).then(response => {  
630 - console.log(">>>>>> response.data:" + JSON.stringify(response.data))  
631 - let dataSpu = response.data;  
632 - this.form = {  
633 - id: dataSpu.id,  
634 - name: dataSpu.name,  
635 - sellPoint: dataSpu.sellPoint,  
636 - description: dataSpu.sellPoint,  
637 - categoryId: dataSpu.sellPoint,  
638 - categoryIds: dataSpu.categoryIds,  
639 - picUrls: dataSpu.picUrls,  
640 - sort: dataSpu.sort,  
641 - likeCount: dataSpu.likeCount,  
642 - price: dataSpu.price,  
643 - quantity: dataSpu.quantity,  
644 - status: dataSpu.status,  
645 - isShowTagInput:undefined,  
646 - skus:dataSpu.skus  
647 - // skus:dataSpu.productSkuRespVOS,  
648 - };  
649 - this.open = true;  
650 - this.title = "修改商品spu";  
651 - });  
652 - }, 492 + let skuAll = sku1s.reduce((x, y) => {
  493 + let arr = [];
  494 + x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
  495 + return arr;
  496 + }, [[]])
653 497
654 - /** 提交按钮 */  
655 - submitForm() {  
656 - console.log(this.form.picUrls.split(','));  
657 - this.$refs["form"].validate(valid => {  
658 - if (!valid) {  
659 - return;  
660 - }  
661 - this.form.picUrls = this.form.picUrls.split(',');  
662 - this.form.categoryId = this.form.categoryIds[(this.form.categoryIds.length - 1)];  
663 - this.form.status = Number(this.form.status);  
664 - // 修改的提交  
665 - if (this.form.id != null) {  
666 - updateSpu(this.form).then(response => {  
667 - this.$modal.msgSuccess("修改成功");  
668 - this.open = false;  
669 - this.getList();  
670 - });  
671 - return;  
672 - }  
673 - // 添加的提交  
674 - createSpu(this.form).then(response => {  
675 - this.$modal.msgSuccess("新增成功");  
676 - this.open = false;  
677 - this.getList();  
678 - });  
679 - });  
680 - },  
681 - /** 删除按钮操作 */  
682 - handleDelete(row) {  
683 - const id = row.id;  
684 - this.$modal.confirm('是否确认删除商品spu编号为"' + id + '"的数据项?').then(function () {  
685 - return deleteSpu(id);  
686 - }).then(() => {  
687 - this.getList();  
688 - this.$modal.msgSuccess("删除成功");  
689 - }).catch(() => {  
690 - });  
691 - },  
692 - /** 导出按钮操作 */  
693 - handleExport() {  
694 - // 处理查询参数  
695 - let params = {...this.queryParams};  
696 - params.pageNo = undefined;  
697 - params.pageSize = undefined;  
698 - // 执行导出  
699 - this.$modal.confirm('是否确认导出所有商品spu数据项?').then(() => {  
700 - this.exportLoading = true;  
701 - return exportSpuExcel(params);  
702 - }).then(response => {  
703 - this.$download.excel(response, '商品spu.xls');  
704 - this.exportLoading = false;  
705 - }).catch(() => {  
706 - });  
707 - } 498 + let skuIdAll = skuIds.reduce((x, y) => {
  499 + let arr = [];
  500 + x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
  501 + return arr;
  502 + }, [[]])
  503 +
  504 + for (let i = 0; i < skuAll.length; i++) {
  505 + let han = {
  506 + propertyNames: propertyNames,
  507 + propertyIds: propertyIds,
  508 + propertyChildNames: skuAll[i],
  509 + propertyChildIds: skuIdAll[i],
  510 + properties: [],
  511 + picUrl: '',
  512 + costPrice: '',
  513 + originalPrice: '',
  514 + spuId: '',
  515 + prodName: '',
  516 + price: '',
  517 + barCode: '',
  518 + status: '0',
708 } 519 }
709 - }; 520 + this.form.skus.push(han);
  521 + }
  522 + this.form.skus.forEach(x => {
  523 + x.properties = [];
  524 + for (let i = 0; i < x.propertyIds.length; i++) {
  525 + x.properties.push({
  526 + propertyId: x.propertyIds[i],
  527 + valueId: x.propertyChildIds[i]
  528 + })
  529 + }
  530 + })
  531 +
  532 + },
  533 + hideTagInput() {
  534 + this.isShowTagInput = false;
  535 + this.addTagInput = {
  536 + name: '',
  537 + propertyId: '',
  538 + selectValues: [],
  539 + selectValueIds: [],
  540 + selectObect: [],
  541 + };
  542 + },
  543 + shopTagInput() {
  544 + if (this.unUseTags.length <= 0) {
  545 + return this.$message.error("规格已经添加完毕")
  546 + }
  547 + this.isShowTagInput = true;
  548 + this.addTagInput = {
  549 + name: '',
  550 + propertyId: '',
  551 + selectValues: [],
  552 + selectValueIds: [],
  553 + selectObect: [],
  554 + };
  555 + },
  556 + //删除已选的规格
  557 + removeTag(row) {
  558 + let skus = this.allhistoryTags.map(function (item, index) {
  559 + return item.name
  560 + })
  561 + let index = skus.indexOf(this.skuTags[row].name);
  562 + this.unUseTags.push(this.allhistoryTags[index]);
  563 + this.skuTags.splice(row, 1);
  564 + this.getTable();
  565 + },
  566 + handleTagClick(row) {
  567 + for (let i = 0; i < this.propertyPageList.length; i++) {
  568 + if (row == this.propertyPageList[i].name) {
  569 + this.dbTagValues = this.propertyPageList[i].propertyValueList
  570 + }
  571 + }
  572 + },
  573 + /** 查询规格 */
  574 + getPropertyPageList() {
  575 + // 执行查询
  576 + getPropertyPage().then(response => {
  577 + this.propertyPageList = response.data.list;
  578 +
  579 + this.unUseTags = this.propertyPageList.map(function (item, index) {
  580 + return item
  581 + })
  582 + this.allhistoryTags = JSON.parse(JSON.stringify(this.unUseTags));
  583 + });
  584 + },
  585 + /** 查询分类 */
  586 + getListCategory() {
  587 + // 执行查询
  588 + listCategory().then(response => {
  589 + this.categoryList = this.handleTree(response.data, "id", "parentId");
  590 +
  591 + });
  592 + },
  593 + /** 查询列表 */
  594 + getList() {
  595 + this.loading = true;
  596 + // 处理查询参数
  597 + let params = {...this.queryParams};
  598 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  599 + // 执行查询
  600 + getSpuPage(params).then(response => {
  601 + this.list = response.data.list;
  602 + this.total = response.data.total;
  603 + this.loading = false;
  604 + });
  605 + },
  606 + /** 取消按钮 */
  607 + cancel() {
  608 + this.open = false;
  609 + this.reset();
  610 + },
  611 + /** 表单重置 */
  612 + reset() {
  613 +
  614 + this.form = {
  615 + id: undefined,
  616 + name: undefined,
  617 + sellPoint: undefined,
  618 + description: undefined,
  619 + categoryId: undefined,
  620 + categoryIds: [],
  621 + picUrls: undefined,
  622 + sort: undefined,
  623 + likeCount: undefined,
  624 + price: undefined,
  625 + quantity: undefined,
  626 + status: undefined,
  627 + isShowTagInput: undefined,
  628 + skus: [],
  629 + };
  630 + this.skuTags = [];
  631 + this.resetForm("form");
  632 + },
  633 + /** 搜索按钮操作 */
  634 + handleQuery() {
  635 + this.queryParams.pageNo = 1;
  636 + this.getList();
  637 + },
  638 + /** 重置按钮操作 */
  639 + resetQuery() {
  640 + this.dateRangeCreateTime = [];
  641 + this.resetForm("queryForm");
  642 + this.handleQuery();
  643 + },
  644 + /** 新增按钮操作 */
  645 + handleAdd() {
  646 + this.reset();
  647 + this.open = true;
  648 + this.title = "添加商品spu";
  649 + this.getPropertyPageList();
  650 + },
  651 + /** 修改按钮操作 */
  652 + handleUpdate(row) {
  653 + this.reset();
  654 + const id = row.id;
  655 + getSpu(id).then(response => {
  656 + let dataSpu = response.data;
  657 + this.form = {
  658 + id: dataSpu.id,
  659 + name: dataSpu.name,
  660 + sellPoint: dataSpu.sellPoint,
  661 + description: dataSpu.sellPoint,
  662 + categoryId: dataSpu.sellPoint,
  663 + categoryIds: dataSpu.categoryIds,
  664 + picUrls: dataSpu.picUrls,
  665 + sort: dataSpu.sort,
  666 + likeCount: dataSpu.likeCount,
  667 + price: dataSpu.price,
  668 + quantity: dataSpu.quantity,
  669 + status: dataSpu.status,
  670 + isShowTagInput: undefined,
  671 + skus: [],
  672 + skusList: dataSpu.skus,
  673 + productPropertyViews: dataSpu.productPropertyViews,
  674 + // skus:dataSpu.productSkuRespVOS,
  675 + };
  676 + this.getDataHandle();
  677 + this.open = true;
  678 + this.title = "修改商品spu";
  679 + });
  680 + },
  681 + getDataHandle() {
  682 + let that = this;
  683 + let productPropertyViews = JSON.parse(JSON.stringify(this.form.productPropertyViews));
  684 + productPropertyViews = productPropertyViews.sort((a, b) => a.propertyId - b.propertyId);
  685 + productPropertyViews.forEach(item => {
  686 + item.propertyValues = item.propertyValues.sort((a, b) => a.v1 - b.v1);
  687 + })
  688 + let skuIds = [];
  689 + for (let i = 0; i < productPropertyViews.length; i++) {
  690 + let han = {
  691 + name: productPropertyViews[i].name,
  692 + propertyId: productPropertyViews[i].propertyId,
  693 + selectValues: [],
  694 + selectValueIds: [],
  695 + }
  696 + for (let j = 0; j < productPropertyViews[i].propertyValues.length; j++) {
  697 + han.selectValues.push(productPropertyViews[i].propertyValues[j].v2);
  698 + han.selectValueIds.push(productPropertyViews[i].propertyValues[j].v1);
  699 + }
  700 + skuIds.push(han)
  701 + }
  702 + this.skuTags = skuIds;
  703 + this.unUseTags = this.allhistoryTags.filter((v) =>
  704 + skuIds.every((val) => val.name != v.name)
  705 + )
  706 + this.getHandleTable();
  707 + },
  708 + getHandleTable() {
  709 + this.form.skus = [];
  710 + let skuTags = JSON.parse(JSON.stringify(this.skuTags));
  711 + let sku1s = [];
  712 + let skuIds = [];
  713 + let propertyIds = [];
  714 + let propertyNames = [];
  715 + for (let i = 0; i < skuTags.length; i++) {
  716 + sku1s.push(skuTags[i].selectValues);
  717 + skuIds.push(skuTags[i].selectValueIds);
  718 + propertyIds.push(skuTags[i].propertyId);
  719 + propertyNames.push(skuTags[i].name);
  720 + }
  721 + let skuAll = sku1s.reduce((x, y) => {
  722 + let arr = [];
  723 + x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
  724 + return arr;
  725 + }, [[]])
  726 +
  727 + let skuIdAll = skuIds.reduce((x, y) => {
  728 + let arr = [];
  729 + x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
  730 + return arr;
  731 + }, [[]])
  732 +
  733 + for (let i = 0; i < skuAll.length; i++) {
  734 + let han = {
  735 + propertyNames: propertyNames,
  736 + propertyIds: propertyIds,
  737 + propertyChildNames: skuAll[i],
  738 + propertyChildIds: skuIdAll[i],
  739 + properties: this.form.skusList[i].properties,
  740 + picUrl: this.form.skusList[i].picUrl,
  741 + costPrice: this.form.skusList[i].costPrice,
  742 + originalPrice: this.form.skusList[i].originalPrice,
  743 + spuId: this.form.skusList[i].spuId,
  744 + prodName: this.form.skusList[i].prodName,
  745 + price: this.form.skusList[i].price,
  746 + barCode: this.form.skusList[i].barCode,
  747 + status: this.form.skusList[i].status,
  748 + }
  749 + this.form.skus.push(han);
  750 + }
  751 + this.form.skus.forEach(x => {
  752 + x.properties = [];
  753 + for (let i = 0; i < x.propertyIds.length; i++) {
  754 + x.properties.push({
  755 + propertyId: x.propertyIds[i],
  756 + valueId: x.propertyChildIds[i]
  757 + })
  758 + }
  759 + })
  760 +
  761 + },
  762 + /** 提交按钮 */
  763 + submitForm() {
  764 +
  765 + this.$refs["form"].validate(valid => {
  766 + if (!valid) {
  767 + return;
  768 + }
  769 + this.form.picUrls = this.form.picUrls.split(',');
  770 + this.form.categoryId = this.form.categoryIds[(this.form.categoryIds.length - 1)];
  771 + this.form.status = Number(this.form.status);
  772 + // 修改的提交
  773 + if (this.form.id != null) {
  774 + updateSpu(this.form).then(response => {
  775 + this.$modal.msgSuccess("修改成功");
  776 + this.open = false;
  777 + this.getList();
  778 + });
  779 + return;
  780 + }
  781 + // 添加的提交
  782 + createSpu(this.form).then(response => {
  783 + this.$modal.msgSuccess("新增成功");
  784 + this.open = false;
  785 + this.getList();
  786 + });
  787 + });
  788 + },
  789 + /** 删除按钮操作 */
  790 + handleDelete(row) {
  791 + const id = row.id;
  792 + this.$modal.confirm('是否确认删除商品spu编号为"' + id + '"的数据项?').then(function () {
  793 + return deleteSpu(id);
  794 + }).then(() => {
  795 + this.getList();
  796 + this.$modal.msgSuccess("删除成功");
  797 + }).catch(() => {
  798 + });
  799 + },
  800 + /** 导出按钮操作 */
  801 + handleExport() {
  802 + // 处理查询参数
  803 + let params = {...this.queryParams};
  804 + params.pageNo = undefined;
  805 + params.pageSize = undefined;
  806 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  807 + // 执行导出
  808 + this.$modal.confirm('是否确认导出所有商品spu数据项?').then(() => {
  809 + this.exportLoading = true;
  810 + return exportSpuExcel(params);
  811 + }).then(response => {
  812 + this.$download.excel(response, '商品spu.xls');
  813 + this.exportLoading = false;
  814 + }).catch(() => {
  815 + });
  816 + }
  817 + }
  818 +};
710 </script> 819 </script>
711 <style lang="scss"> 820 <style lang="scss">
712 - .app-container {  
713 - .el-tag + .el-tag {  
714 - margin-left: 10px;  
715 - } 821 +.app-container {
  822 + .el-tag + .el-tag {
  823 + margin-left: 10px;
  824 + }
716 825
717 - .button-new-tag {  
718 - margin-left: 10px;  
719 - height: 32px;  
720 - line-height: 30px;  
721 - padding-top: 0;  
722 - padding-bottom: 0;  
723 - } 826 + .button-new-tag {
  827 + margin-left: 10px;
  828 + height: 32px;
  829 + line-height: 30px;
  830 + padding-top: 0;
  831 + padding-bottom: 0;
  832 + }
724 833
725 - .input-new-tag {  
726 - width: 90px;  
727 - margin-left: 10px;  
728 - vertical-align: bottom;  
729 - } 834 + .input-new-tag {
  835 + width: 90px;
  836 + margin-left: 10px;
  837 + vertical-align: bottom;
  838 + }
730 839
731 - .img-height {  
732 - height: 65px;  
733 - } 840 + .img-height {
  841 + height: 65px;
734 } 842 }
  843 +}
735 </style> 844 </style>
yudao-ui-app/api/category.js 0 → 100644
  1 +//请求工具参考https://ext.dcloud.net.cn/plugin?id=392
  2 +const { http } = uni.$u
  3 +
  4 +// 查询分类列表
  5 +export const categoryListData = params => http.get('product/category/list', { params })
yudao-ui-app/api/product.js 0 → 100644
  1 +//请求工具参考https://ext.dcloud.net.cn/plugin?id=392
  2 +const { http } = uni.$u
  3 +
  4 +// 查询商品spu列表
  5 +export const productSpuPage = params => http.get('product/spu/page', { params })
  6 +
  7 +// 查询商品
  8 +export const productSpu = params => http.get('product/spu/', { params })
yudao-ui-app/pages.json
@@ -12,6 +12,14 @@ @@ -12,6 +12,14 @@
12 "navigationBarTitleText": "分类" 12 "navigationBarTitleText": "分类"
13 } 13 }
14 }, 14 },
  15 + {
  16 + "path": "pages/category/product-list",
  17 + "style": {
  18 + "navigationBarTitleText": "",
  19 + "navigationStyle": "custom",
  20 + "navigationBarTextStyle": "white"
  21 + }
  22 + },
15 { 23 {
16 "path": "pages/cart/cart", 24 "path": "pages/cart/cart",
17 "style": { 25 "style": {
@@ -112,7 +120,7 @@ @@ -112,7 +120,7 @@
112 "globalStyle": { 120 "globalStyle": {
113 "navigationBarTextStyle": "black", 121 "navigationBarTextStyle": "black",
114 "navigationBarTitleText": "yudao-ui-app", 122 "navigationBarTitleText": "yudao-ui-app",
115 - "navigationBarBackgroundColor": "#F8F8F8",  
116 - "backgroundColor": "#FFFFFF" 123 + "navigationBarBackgroundColor": "#ffffff",
  124 + "backgroundColor": "#ffffff"
117 } 125 }
118 } 126 }
yudao-ui-app/pages/category/category.vue
1 <template> 1 <template>
2 <view class="container"> 2 <view class="container">
  3 + <!-- 搜索框 -->
3 <view class="search-wrap"> 4 <view class="search-wrap">
4 - <u-search placeholder="搜索" disabled height="32" :show-action="false" @click="handleSearchClick"></u-search> 5 + <u-search placeholder="搜索" disabled height="32" bgColor="#f2f2f2" margin="0 20rpx" :show-action="false"
  6 + @click="handleSearchClick"></u-search>
5 </view> 7 </view>
  8 +
  9 + <!-- 分类内容 -->
6 <view class="category-box"> 10 <view class="category-box">
7 - <view class="box-left">  
8 - <view>  
9 - <view class="category-item" v-for="(item, index) in categoryList" :key="item.id">  
10 - <view class="item-title" :class="{ active: currentIndex === index }" @click="handleCategoryClick(index)">  
11 - <text>{{ item.name }}</text>  
12 - </view> 11 + <!-- 左侧导航栏 -->
  12 + <scroll-view scroll-y="true" class='box-left'>
  13 + <view class="category-item" v-for="(item, index) in categoryList" :key="item.id">
  14 + <view class="item-title" :class="{ active: currentIndex === index }" @click="handleCategoryClick(index)">
  15 + <text>{{ item.name }}</text>
13 </view> 16 </view>
14 </view> 17 </view>
15 - </view>  
16 - <view class="box-right">  
17 - <image class="category-image" :showLoading="true" :src="categoryList[currentIndex].image" width="530rpx" height="160rpx" @click="click"></image> 18 + </scroll-view>
  19 +
  20 + <!-- 右侧分类内容 -->
  21 + <scroll-view scroll-y="true" class="box-right">
  22 + <view class="category-image">
  23 + <image :showLoading="true" :src="categoryList[currentIndex].bannerUrl" mode='widthFix' @click="click"></image>
  24 + </view>
  25 +
18 <view class="sub-category-box" v-for="(item, index) in categoryList[currentIndex].children" :key="item.id"> 26 <view class="sub-category-box" v-for="(item, index) in categoryList[currentIndex].children" :key="item.id">
19 <view class="sub-category-header"> 27 <view class="sub-category-header">
20 - <view class="title">{{ item.title }}</view>  
21 - <view class="more">查看更多</view> 28 + <view class="title">{{ item.name }}</view>
  29 + <view class="more" @click="handleCategory(item, 0)">查看更多</view>
  30 + </view>
  31 +
  32 + <view class="sub-category-grid">
  33 + <u-grid col="3">
  34 + <u-grid-item v-for="(subItem, subIndex) in item.children" :key="subItem.id">
  35 + <view class="sub-category-item" @click="handleCategory(item, subIndex)">
  36 + <u-icon name="photo" :size="80" v-if="subItem.bannerUrl === null"></u-icon>
  37 + <image :src="item.bannerUrl" v-if="subItem.bannerUrl != null" mode='widthFix' />
  38 + <text class="sub-category-title">{{ subItem.name }}</text>
  39 + </view>
  40 + </u-grid-item>
  41 + </u-grid>
22 </view> 42 </view>
23 - <u-grid class="sub-category-grid" col="3">  
24 - <u-grid-item v-for="(subItem, subIndex) in item.category" :key="subItem.id">  
25 - <view class="sub-category-item">  
26 - <u-icon name="photo" :size="80"></u-icon>  
27 - <text class="sub-category-title">{{ subItem.title }}</text>  
28 - </view>  
29 - </u-grid-item>  
30 - </u-grid>  
31 </view> 43 </view>
32 - </view> 44 + </scroll-view>
33 </view> 45 </view>
34 </view> 46 </view>
35 </template> 47 </template>
36 48
37 <script> 49 <script>
38 -export default {  
39 - data() {  
40 - return {  
41 - currentIndex: 0,  
42 - categoryList: []  
43 - }  
44 - },  
45 - onLoad() {  
46 - for (let i = 0; i < 10; i++) {  
47 - this.categoryList.push({  
48 - id: i,  
49 - image: 'https://cdn.uviewui.com/uview/swiper/swiper1.png',  
50 - name: '商品分类' + i,  
51 - children: [  
52 - {  
53 - id: 0,  
54 - title: '分类' + i + '-1',  
55 - category: [  
56 - {  
57 - id: 0,  
58 - image: '',  
59 - title: '分类' + i + '-1-1'  
60 - },  
61 - {  
62 - id: 2,  
63 - image: '',  
64 - title: '分类' + i + '-1-2'  
65 - },  
66 - {  
67 - id: 3,  
68 - image: '',  
69 - title: '分类' + i + '-1-3'  
70 - }  
71 - ]  
72 - },  
73 - {  
74 - id: 1,  
75 - title: '分类' + i + '-2',  
76 - category: [  
77 - {  
78 - id: 0,  
79 - image: '',  
80 - title: '分类' + i + '-2-1'  
81 - },  
82 - {  
83 - id: 2,  
84 - image: '',  
85 - title: '分类' + i + '-2-2'  
86 - },  
87 - {  
88 - id: 3,  
89 - image: '',  
90 - title: '分类' + i + '-2-3'  
91 - }  
92 - ]  
93 - }  
94 - ]  
95 - })  
96 - }  
97 - },  
98 - methods: {  
99 - handleSearchClick(e) {  
100 - uni.$u.route('/pages/search/search') 50 + import { categoryListData } from '../../api/category';
  51 + import { handleTree, convertTree } from '../../utils/tree.js';
  52 +
  53 + export default {
  54 + data() {
  55 + return {
  56 + currentIndex: 0,
  57 + categoryList: []
  58 + }
101 }, 59 },
102 - handleCategoryClick(index) {  
103 - if (this.currentIndex !== index) {  
104 - this.currentIndex = index 60 + onLoad() {
  61 + this.handleCategoryList();
  62 + },
  63 + methods: {
  64 + // 点击搜索框
  65 + handleSearchClick(e) {
  66 + uni.$u.route('/pages/search/search')
  67 + },
  68 + // 点击左侧导航栏
  69 + handleCategoryClick(index) {
  70 + if (this.currentIndex !== index) {
  71 + this.currentIndex = index
  72 + }
  73 + },
  74 + // 获取分类列表并构建树形结构
  75 + handleCategoryList() {
  76 + categoryListData().then(res => {
  77 + this.categoryList = handleTree(res.data, "id", "parentId");
  78 + })
  79 + },
  80 + handleCategory(item, index){
  81 + // console.log(item)
  82 + // console.log(index)
  83 + uni.navigateTo({
  84 + url:"./product-list?item="+encodeURIComponent(JSON.stringify(item))+"&index="+index
  85 + })
105 } 86 }
106 } 87 }
107 } 88 }
108 -}  
109 </script> 89 </script>
110 90
111 <style lang="scss" scoped> 91 <style lang="scss" scoped>
  92 + .search-wrap {
  93 + background: #ffffff;
  94 + position: fixed;
  95 + top: 0;
  96 + left: 0;
  97 + box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.07);
  98 + padding: 20rpx 0;
  99 + width: 100%;
  100 + z-index: 3;
  101 + }
  102 +
  103 + .category-box {
  104 + position: fixed;
  105 + display: flex;
  106 + overflow: hidden;
  107 + margin-top: 100rpx;
  108 + height: calc(100% - 100rpx);
  109 +
  110 + .box-left {
  111 + width: 200rpx;
  112 + padding-top: 5rpx;
  113 + overflow: scroll;
  114 + z-index: 2;
  115 + background-color: #f2f2f2;
  116 +
  117 + .category-item {
  118 + line-height: 80rpx;
  119 + height: 80rpx;
  120 + text-align: center;
  121 + color: #777;
112 122
113 -.search-wrap {  
114 - background: $custom-bg-color;  
115 - padding: 20rpx;  
116 -}  
117 -  
118 -.category-box {  
119 - display: flex;  
120 - .box-left {  
121 - width: 200rpx;  
122 - padding-top: 20rpx;  
123 - border-right: $custom-border-style;  
124 - .category-item {  
125 - border-bottom: $custom-border-style;  
126 - padding: 20rpx 0;  
127 - .item-title {  
128 - padding-left: 30rpx;  
129 - font-size: 28rpx;  
130 - &.active {  
131 - border-left: 6rpx solid $u-primary;  
132 - font-weight: 700; 123 + .item-title {
  124 + font-size: 28rpx;
  125 +
  126 + &.active {
  127 + font-size: 28rpx;
  128 + font-weight: bold;
  129 + position: relative;
  130 + background: #fff;
  131 + color: $u-primary;
  132 + }
  133 +
  134 + &.active::before {
  135 + position: absolute;
  136 + left: 0;
  137 + content: "";
  138 + width: 8rpx;
  139 + height: 32rpx;
  140 + top: 25rpx;
  141 + background: $u-primary;
  142 + }
133 } 143 }
134 } 144 }
135 } 145 }
136 - }  
137 - .box-right {  
138 - flex: 1;  
139 - .category-image {  
140 - width: 510rpx;  
141 - height: 160rpx;  
142 - padding: 20rpx;  
143 - }  
144 146
145 - .sub-category-box {  
146 - .sub-category-header {  
147 - @include flex-space-between;  
148 - padding: 30rpx 20rpx; 147 + .box-right {
  148 + width: 550rpx;
  149 + height: 100%;
  150 + box-sizing: border-box;
  151 + z-index: 1;
149 152
150 - .title {  
151 - font-size: 28rpx;  
152 - font-weight: 700;  
153 - }  
154 - .more {  
155 - font-size: 22rpx;  
156 - color: #939393; 153 + .category-image {
  154 + width: 510rpx;
  155 + box-sizing: border-box;
  156 + overflow: hidden;
  157 + position: relative;
  158 + margin: 30rpx 20rpx 0;
  159 +
  160 + image {
  161 + width: 100%;
157 } 162 }
158 } 163 }
159 164
160 - .sub-category-grid {  
161 - padding: 0 15rpx; 165 + .sub-category-box {
  166 + .sub-category-header {
  167 + @include flex-space-between;
  168 + padding: 20rpx 20rpx;
  169 +
  170 + .title {
  171 + font-size: 28rpx;
  172 + font-weight: bolder;
  173 + }
  174 +
  175 + .more {
  176 + font-size: 22rpx;
  177 + color: #939393;
  178 + }
  179 + }
  180 +
  181 + .sub-category-grid {
  182 + padding: 0 15rpx;
  183 +
  184 + .sub-category-item {
  185 + @include flex-center(column);
  186 + background: #fff;
162 187
163 - .sub-category-item {  
164 - @include flex-center(column);  
165 - background: #fff; 188 + image {
  189 + text-align: center;
  190 + width: 150rpx;
  191 + height: 150rpx;
  192 + line-height: 150rpx;
  193 + font-size: 0;
  194 + }
166 195
167 - .sub-category-title {  
168 - margin: 15rpx 0;  
169 - font-size: 24rpx; 196 + .sub-category-title {
  197 + margin: 15rpx 0;
  198 + font-size: 22rpx;
  199 + }
170 } 200 }
171 } 201 }
172 } 202 }
173 } 203 }
174 } 204 }
175 -}  
176 </style> 205 </style>
yudao-ui-app/pages/category/product-list.vue 0 → 100644
  1 +<template>
  2 + <view class="container">
  3 + <u-navbar :title="title" :autoBack="true" placeholder="true" titleStyle="font-size: 28rpx">
  4 + </u-navbar>
  5 + <view class="context">
  6 + <view class="tabs-top">
  7 + <u-tabs :list="categoryList" @click="changeTabs" :current="current" lineHeight="2" lineWidth="85rpx"
  8 + itemStyle="padding-left: 15px; padding-right: 15px; height: 85rpx;"></u-tabs>
  9 + </view>
  10 + <scroll-view scroll-y="true" class="product-list" enable-flex="true">
  11 + <view class="flex-box">
  12 + <block v-for="(item, index) in productList[current]" :key="index">
  13 + <view class="product-item">
  14 + <view class="product-image">
  15 + <image :src="item.picUrls[0]" mode='widthFix' />
  16 + </view>
  17 + <view class="product-button">
  18 + <view class="product-text">【{{ item.sellPoint }}】{{ item.name }}</view>
  19 + <view class="product-price-button">
  20 + <text class="product-price">¥
  21 + <text class="price-size">{{ towNumber(item.price) }}</text></text>
  22 + <text class="product-like-ccount">销量 {{ item.likeCount }}</text>
  23 + </view>
  24 + </view>
  25 + </view>
  26 + </block>
  27 + </view>
  28 + </scroll-view>
  29 + </view>
  30 + </view>
  31 +</template>
  32 +
  33 +<script>
  34 + import {
  35 + productSpuPage
  36 + } from '../../api/product';
  37 +
  38 + export default {
  39 + data() {
  40 + return {
  41 + title: "",
  42 + current: 0,
  43 + categoryList: [],
  44 + productList: {}
  45 + }
  46 + },
  47 + onLoad(option) {
  48 + const item = JSON.parse(decodeURIComponent(option.item))
  49 + this.title = item.name
  50 + this.categoryList = item.children
  51 + this.handleProductSpu(option.index);
  52 + },
  53 + methods: {
  54 + changeTabs(item) {
  55 + if (item.index != this.current) {
  56 + this.handleProductSpu(item.index)
  57 + }
  58 + },
  59 + handleProductSpu(index) {
  60 + let param = {}
  61 + param.categoryId = this.categoryList[index].id
  62 + console.log(this.categoryList)
  63 + console.log(index)
  64 + productSpuPage(param).then(res => {
  65 + this.productList[index] = res.data.list
  66 + this.current = index
  67 + })
  68 + },
  69 + towNumber(val) {
  70 + return (val / 100).toFixed(2)
  71 + }
  72 + }
  73 + }
  74 +</script>
  75 +
  76 +<style lang="scss" scoped>
  77 + .context {
  78 + width: 100vw;
  79 + position: fixed;
  80 + top: 160rpx;
  81 + left: 0;
  82 + }
  83 +
  84 + .tabs-top {
  85 + position: relative;
  86 + top: 0;
  87 + width: 100%;
  88 + height: 85rpx;
  89 + }
  90 +
  91 + .product-list {
  92 + position: relative;
  93 + background-color: #f2f2f2;
  94 + height: calc(100vh - 88rpx - 100rpx - var(--status-bar-height));
  95 + width: 100%;
  96 +
  97 + .flex-box {
  98 + width: 730rpx;
  99 + margin: 0 auto;
  100 + @include flex;
  101 + flex-wrap: wrap;
  102 + justify-content: left;
  103 +
  104 + .product-item {
  105 + width: 345rpx;
  106 + height: 450rpx;
  107 + background-color: #ffffff;
  108 + margin: 20rpx 10rpx 0;
  109 + border-radius: 20rpx;
  110 +
  111 + .product-image {
  112 + width: 100%;
  113 + height: 300rpx;
  114 + overflow: hidden;
  115 + border-radius: 20rpx;
  116 + image {
  117 + width: 100%;
  118 + }
  119 + }
  120 +
  121 + .product-button {
  122 + width: 330rpx;
  123 + margin: 15rpx auto 0;
  124 +
  125 + .product-text {
  126 + font-size: 25rpx;
  127 + height: 70rpx;
  128 + overflow: hidden;
  129 + -webkit-line-clamp: 2;
  130 + text-overflow: ellipsis;
  131 + display: -webkit-box;
  132 + -webkit-box-orient: vertical;
  133 + }
  134 +
  135 + .product-price-button {
  136 + font-size: 20rpx;
  137 + margin-top: 20rpx;
  138 +
  139 + .product-price {
  140 + color: red;
  141 +
  142 + .price-size {
  143 + font-size: 26rpx;
  144 + }
  145 + }
  146 +
  147 + .product-like-ccount {
  148 + font-size: 16rpx;
  149 + margin-left: 10rpx;
  150 + }
  151 + }
  152 +
  153 + }
  154 + }
  155 +
  156 + }
  157 +
  158 + // }
  159 +
  160 + }
  161 +</style>
yudao-ui-app/pages/index/index.vue
@@ -169,8 +169,8 @@ export default { @@ -169,8 +169,8 @@ export default {
169 } 169 }
170 }, 170 },
171 onLoad() { 171 onLoad() {
172 - //this.loadBannerData();  
173 - //this.loadNoticeData(); 172 + this.loadBannerData();
  173 + this.loadNoticeData();
174 }, 174 },
175 methods: { 175 methods: {
176 loadBannerData() { 176 loadBannerData() {
@@ -302,7 +302,7 @@ export default { @@ -302,7 +302,7 @@ export default {
302 margin: 10rpx; 302 margin: 10rpx;
303 background: #ffffff; 303 background: #ffffff;
304 border-radius: 10rpx; 304 border-radius: 10rpx;
305 - box-shadow: -1rpx 1rpx 2rpx #afd3f5, 1rpx 1rpx 0rpx #afd3f5; 305 + box-shadow: 0rpx 6rpx 8rpx rgba(58,134,185,0.2);
306 .prod-image { 306 .prod-image {
307 width: 224rpx; 307 width: 224rpx;
308 height: 224rpx; 308 height: 224rpx;
yudao-ui-app/pages/product/product.vue
@@ -43,7 +43,7 @@ @@ -43,7 +43,7 @@
43 <u-popup :show="skuPopup" :round="10" :closeable="true" :closeOnClickOverlay="false" @close="skuPopup = false"> 43 <u-popup :show="skuPopup" :round="10" :closeable="true" :closeOnClickOverlay="false" @close="skuPopup = false">
44 <view class="sku-popup-slot"> 44 <view class="sku-popup-slot">
45 <view class="current-sku-info"> 45 <view class="current-sku-info">
46 - <u--image class="current-sku-img" :showLoading="true" :src="product.sku[currentSkuIndex].image" width="120rpx" height="120rpx"></u--image> 46 + <u--image class="current-sku-img" :showLoading="true" :src="product.sku[currentSkuIndex].picUrl" width="120rpx" height="120rpx"></u--image>
47 <view class="current-sku-desc"> 47 <view class="current-sku-desc">
48 <view class="name">{{ product.sku[currentSkuIndex].desc }}</view> 48 <view class="name">{{ product.sku[currentSkuIndex].desc }}</view>
49 <custom-text-price color="red" size="12" intSize="18" :price="product.sku[currentSkuIndex].price"></custom-text-price> 49 <custom-text-price color="red" size="12" intSize="18" :price="product.sku[currentSkuIndex].price"></custom-text-price>
@@ -178,6 +178,8 @@ @@ -178,6 +178,8 @@
178 </template> 178 </template>
179 179
180 <script> 180 <script>
  181 + import { productSpu } from '../../api/product';
  182 +
181 export default { 183 export default {
182 data() { 184 data() {
183 return { 185 return {
@@ -194,19 +196,19 @@ export default { @@ -194,19 +196,19 @@ export default {
194 sku: [ 196 sku: [
195 { 197 {
196 id: 0, 198 id: 0,
197 - image: 'https://cdn.uviewui.com/uview/album/1.jpg', 199 + picUrl: 'https://cdn.uviewui.com/uview/album/1.jpg',
198 price: 13.0, 200 price: 13.0,
199 desc: '山不在高,有仙则名。' 201 desc: '山不在高,有仙则名。'
200 }, 202 },
201 { 203 {
202 id: 1, 204 id: 1,
203 - image: 'https://cdn.uviewui.com/uview/album/2.jpg', 205 + picUrl: 'https://cdn.uviewui.com/uview/album/2.jpg',
204 price: 11.0, 206 price: 11.0,
205 desc: '水不在深,有龙则灵。' 207 desc: '水不在深,有龙则灵。'
206 }, 208 },
207 { 209 {
208 id: 2, 210 id: 2,
209 - image: 'https://cdn.uviewui.com/uview/album/3.jpg', 211 + picUrl: 'https://cdn.uviewui.com/uview/album/3.jpg',
210 price: 10.0, 212 price: 10.0,
211 desc: '斯是陋室,惟吾德馨。' 213 desc: '斯是陋室,惟吾德馨。'
212 } 214 }
@@ -302,7 +304,18 @@ export default { @@ -302,7 +304,18 @@ export default {
302 } 304 }
303 }, 305 },
304 methods: { 306 methods: {
305 - loadProductData() {}, 307 + loadProductData() {
  308 + let param = {}
  309 + param.spuId = this.product.id
  310 + productSpu(param).then(res => {
  311 + this.product.images = res.data.picUrls;
  312 + this.product.sku = res.data.skus;
  313 + this.product.desc = res.data.description.replace(/<[^>]*>/g,'');
  314 + this.product.price = res.data.price;
  315 + this.product.title = res.data.name;
  316 + console.log(res)
  317 + })
  318 + },
306 handleSkuItemClick(index) { 319 handleSkuItemClick(index) {
307 this.currentSkuIndex = index 320 this.currentSkuIndex = index
308 }, 321 },
yudao-ui-app/utils/tree.js 0 → 100644
  1 +/**
  2 + * 构造树型结构数据
  3 + * @param {*} data 数据源
  4 + * @param {*} id id字段 默认 'id'
  5 + * @param {*} parentId 父节点字段 默认 'parentId'
  6 + * @param {*} children 孩子节点字段 默认 'children'
  7 + * @param {*} rootId 根Id 默认 0
  8 + */
  9 +export function handleTree(data, id, parentId, children, rootId) {
  10 + id = id || 'id'
  11 + parentId = parentId || 'parentId'
  12 + children = children || 'children'
  13 + rootId = rootId || Math.min.apply(Math, data.map(item => {
  14 + return item[parentId]
  15 + })) || 0
  16 + //对源数据深度克隆
  17 + const cloneData = JSON.parse(JSON.stringify(data))
  18 + //循环所有项
  19 + const treeData = cloneData.filter(father => {
  20 + let branchArr = cloneData.filter(child => {
  21 + //返回每一项的子级数组
  22 + return father[id] === child[parentId]
  23 + });
  24 + branchArr.length > 0 ? father.children = branchArr : '';
  25 + //返回第一层
  26 + return father[parentId] === rootId;
  27 + });
  28 + return treeData !== '' ? treeData : data;
  29 +}
  30 +
  31 +/**
  32 + * 树形结构进行删除深度不够的分支
  33 + * 目前只删除了不够三层的分支
  34 + * 对于高于三层的部分目前不做处理
  35 + * todo 暴力遍历,可用递归修改
  36 + * @param {*} data 树形结构
  37 + */
  38 +export function convertTree(data) {
  39 + //对源数据深度克隆
  40 + const cloneData = JSON.parse(JSON.stringify(data))
  41 + // 遍历克隆数据,对源数据进行删除操作
  42 + for (let first = 0; first < cloneData.length; first++) {
  43 + for (let second = 0; second < cloneData[first].children.length; second++) {
  44 + for (let three = 0; three < cloneData[first].children[second].children.length; three++) {
  45 + if (data[first].children[second].children[three].children == undefined ||
  46 + data[first].children[second].children[three].children === 0) {
  47 + data[first].children[second].children.splice(second, 1);
  48 + }
  49 + }
  50 + if (data[first].children[second].children == undefined || data[first].children[second].children === 0) {
  51 + data[first].children.splice(second, 1);
  52 + }
  53 + }
  54 + if (data[first].children == undefined || data[first].children.length === 0) {
  55 + data.splice(first, 1);
  56 + }
  57 + }
  58 + return data;
  59 +}