mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 04:08:43 +08:00 
			
		
		
		
	feature(uniapp分类): 分类列表以及商品加载
This commit is contained in:
		@@ -0,0 +1,40 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.controller.app.category;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.convert.category.CategoryConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.service.category.CategoryService;
 | 
			
		||||
import io.swagger.annotations.Api;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
 | 
			
		||||
@Api(tags = "用户 APP - 商品分类")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/product/category")
 | 
			
		||||
@Validated
 | 
			
		||||
public class AppCategoryController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CategoryService categoryService;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    @ApiOperation("获得商品分类列表")
 | 
			
		||||
    public CommonResult<List<AppCategoryListRespVO>> listByQuery() {
 | 
			
		||||
        List<CategoryDO> list = categoryService.getCategoryList();
 | 
			
		||||
        list.sort(Comparator.comparing(CategoryDO::getSort));
 | 
			
		||||
        return success(CategoryConvert.INSTANCE.convertList03(list));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.controller.app.category.vo;
 | 
			
		||||
 | 
			
		||||
import io.swagger.annotations.ApiModel;
 | 
			
		||||
import io.swagger.annotations.ApiModelProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotBlank;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@ApiModel(value = "App - 商品分类 列表 Request VO", description = "参数和 CategoryBaseVO 是一致的")
 | 
			
		||||
public class AppCategoryListRespVO {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类编号", required = true, example = "2")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "父分类编号", required = true, example = "1")
 | 
			
		||||
    @NotNull(message = "父分类编号不能为空")
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类名称", required = true, example = "办公文具")
 | 
			
		||||
    @NotBlank(message = "分类名称不能为空")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类图标")
 | 
			
		||||
    @NotBlank(message = "分类图标不能为空")
 | 
			
		||||
    private String icon;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类图片", required = true)
 | 
			
		||||
    @NotBlank(message = "分类图片不能为空")
 | 
			
		||||
    private String bannerUrl;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类排序", required = true, example = "1")
 | 
			
		||||
    private Integer sort;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类描述", required = true, example = "描述")
 | 
			
		||||
    private String description;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.controller.app.spu;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
 | 
			
		||||
import io.swagger.annotations.Api;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestBody;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
 | 
			
		||||
@Api(tags = "用户 APP -  商品spu")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/product/spu")
 | 
			
		||||
@Validated
 | 
			
		||||
public class AppProductSpuController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ProductSpuService spuService;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    @ApiOperation("获得商品spu分页")
 | 
			
		||||
    public CommonResult<PageResult<AppSpuPageRespVO>> getSpuPage(@Valid AppSpuPageReqVO pageVO) {
 | 
			
		||||
        return success(spuService.getSpuPage(pageVO));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.controller.app.spu.vo;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import io.swagger.annotations.ApiModel;
 | 
			
		||||
import io.swagger.annotations.ApiModelProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
 | 
			
		||||
@ApiModel("App - 商品spu分页 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@ToString(callSuper = true)
 | 
			
		||||
public class AppSpuPageReqVO extends PageParam {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类id")
 | 
			
		||||
    private Long categoryId;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.controller.app.spu.vo;
 | 
			
		||||
 | 
			
		||||
import io.swagger.annotations.ApiModel;
 | 
			
		||||
import io.swagger.annotations.ApiModelProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@ApiModel("App - 商品spu分页 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
public class AppSpuPageRespVO  {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "主键", required = true, example = "1")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "商品名称")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "卖点", required = true)
 | 
			
		||||
    @NotNull(message = "卖点不能为空")
 | 
			
		||||
    private String sellPoint;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "描述", required = true)
 | 
			
		||||
    @NotNull(message = "描述不能为空")
 | 
			
		||||
    private String description;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "分类id", required = true)
 | 
			
		||||
    @NotNull(message = "分类id不能为空")
 | 
			
		||||
    private Long categoryId;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张", required = true)
 | 
			
		||||
    @NotNull(message = "商品主图地址,* 数组,以逗号分隔,最多上传15张不能为空")
 | 
			
		||||
    private List<String> picUrls;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "排序字段", required = true)
 | 
			
		||||
    @NotNull(message = "排序字段不能为空")
 | 
			
		||||
    private Integer sort;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "点赞初始人数")
 | 
			
		||||
    private Integer likeCount;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "价格 单位使用:分")
 | 
			
		||||
    private Integer price;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "库存数量")
 | 
			
		||||
    private Integer quantity;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
 | 
			
		||||
    private Boolean status;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -4,6 +4,7 @@ import java.util.*;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.*;
 | 
			
		||||
@@ -31,4 +32,5 @@ public interface CategoryConvert {
 | 
			
		||||
 | 
			
		||||
    List<CategoryExcelVO> convertList02(List<CategoryDO> list);
 | 
			
		||||
 | 
			
		||||
    List<AppCategoryListRespVO> convertList03(List<CategoryDO> list);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import java.util.*;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.Mapping;
 | 
			
		||||
import org.mapstruct.Named;
 | 
			
		||||
@@ -40,6 +42,11 @@ public interface ProductSpuConvert {
 | 
			
		||||
 | 
			
		||||
    List<SpuExcelVO> convertList02(List<ProductSpuDO> list);
 | 
			
		||||
 | 
			
		||||
    SpuPageReqVO convert(AppSpuPageReqVO bean);
 | 
			
		||||
 | 
			
		||||
    @Mapping(source = "picUrls", target = "picUrls", qualifiedByName = "tokenizeToStringArray")
 | 
			
		||||
    AppSpuPageRespVO convertAppResp(ProductSpuDO list);
 | 
			
		||||
 | 
			
		||||
    @Named("tokenizeToStringArray")
 | 
			
		||||
    default List<String> translatePicUrlsArrayFromString(String picUrls) {
 | 
			
		||||
        return Arrays.asList(StringUtils.tokenizeToStringArray(picUrls, ","));
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.service.category;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.*;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;
 | 
			
		||||
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
@@ -83,4 +84,11 @@ public interface CategoryService {
 | 
			
		||||
     * @param categoryId 分类id
 | 
			
		||||
     */
 | 
			
		||||
    void validatedCategoryById(Long categoryId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * app端获得商品分类列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return 商品分类列表
 | 
			
		||||
     */
 | 
			
		||||
    List<CategoryDO> getCategoryList();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.product.service.category;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
@@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
 | 
			
		||||
@@ -106,4 +108,13 @@ public class CategoryServiceImpl implements CategoryService {
 | 
			
		||||
        return categoryMapper.selectList(treeListReqVO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<CategoryDO> getCategoryList() {
 | 
			
		||||
        return categoryMapper.selectList()
 | 
			
		||||
                .stream()
 | 
			
		||||
                .filter(v->v.getStatus().equals(CommonStatusEnum.ENABLE.getStatus()))
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.product.service.spu;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import javax.validation.*;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
 | 
			
		||||
@@ -67,4 +69,13 @@ public interface ProductSpuService {
 | 
			
		||||
     */
 | 
			
		||||
    List<ProductSpuDO> getSpuList(SpuExportReqVO exportReqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得商品spu分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageReqVO 分页查询
 | 
			
		||||
     * @return 商品spu分页
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,10 @@ import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
 | 
			
		||||
@@ -175,4 +176,17 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 | 
			
		||||
        return ProductSpuMapper.selectList(exportReqVO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO) {
 | 
			
		||||
        PageResult<ProductSpuDO> productSpuDOPageResult = ProductSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
 | 
			
		||||
        PageResult<AppSpuPageRespVO> pageResult = new PageResult<>();
 | 
			
		||||
        List<AppSpuPageRespVO> collect = productSpuDOPageResult.getList()
 | 
			
		||||
                .stream()
 | 
			
		||||
                .map(ProductSpuConvert.INSTANCE::convertAppResp)
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
        pageResult.setList(collect);
 | 
			
		||||
        pageResult.setTotal(productSpuDOPageResult.getTotal());
 | 
			
		||||
        return pageResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								yudao-ui-app/api/category.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								yudao-ui-app/api/category.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
//请求工具参考https://ext.dcloud.net.cn/plugin?id=392
 | 
			
		||||
const { http } = uni.$u
 | 
			
		||||
 | 
			
		||||
// 查询分类列表
 | 
			
		||||
export const categoryListData = params => http.get('product/category/list', { params })
 | 
			
		||||
							
								
								
									
										5
									
								
								yudao-ui-app/api/product.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								yudao-ui-app/api/product.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
//请求工具参考https://ext.dcloud.net.cn/plugin?id=392
 | 
			
		||||
const { http } = uni.$u
 | 
			
		||||
 | 
			
		||||
// 查询商品spu列表
 | 
			
		||||
export const productSpuPage = params => http.get('/product/spu/page', { params })
 | 
			
		||||
@@ -12,6 +12,14 @@
 | 
			
		||||
				"navigationBarTitleText": "分类"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
    {
 | 
			
		||||
    	"path": "pages/category/product-list",
 | 
			
		||||
    	"style": {
 | 
			
		||||
        "navigationBarTitleText": "",
 | 
			
		||||
        "navigationStyle": "custom",
 | 
			
		||||
        "navigationBarTextStyle": "white"
 | 
			
		||||
    	}
 | 
			
		||||
    },
 | 
			
		||||
		{
 | 
			
		||||
			"path": "pages/cart/cart",
 | 
			
		||||
			"style": {
 | 
			
		||||
@@ -112,7 +120,7 @@
 | 
			
		||||
	"globalStyle": {
 | 
			
		||||
		"navigationBarTextStyle": "black",
 | 
			
		||||
		"navigationBarTitleText": "yudao-ui-app",
 | 
			
		||||
		"navigationBarBackgroundColor": "#F8F8F8",
 | 
			
		||||
		"backgroundColor": "#FFFFFF"
 | 
			
		||||
		"navigationBarBackgroundColor": "#ffffff",
 | 
			
		||||
		"backgroundColor": "#ffffff"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,176 +1,205 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <view class="container">
 | 
			
		||||
    <!-- 搜索框 -->
 | 
			
		||||
    <view class="search-wrap">
 | 
			
		||||
      <u-search placeholder="搜索" disabled height="32" :show-action="false" @click="handleSearchClick"></u-search>
 | 
			
		||||
      <u-search placeholder="搜索" disabled height="32" bgColor="#f2f2f2" margin="0 20rpx" :show-action="false"
 | 
			
		||||
        @click="handleSearchClick"></u-search>
 | 
			
		||||
    </view>
 | 
			
		||||
 | 
			
		||||
    <!-- 分类内容 -->
 | 
			
		||||
    <view class="category-box">
 | 
			
		||||
      <view class="box-left">
 | 
			
		||||
        <view>
 | 
			
		||||
          <view class="category-item" v-for="(item, index) in categoryList" :key="item.id">
 | 
			
		||||
            <view class="item-title" :class="{ active: currentIndex === index }" @click="handleCategoryClick(index)">
 | 
			
		||||
              <text>{{ item.name }}</text>
 | 
			
		||||
            </view>
 | 
			
		||||
      <!-- 左侧导航栏 -->
 | 
			
		||||
      <scroll-view scroll-y="true" class='box-left'>
 | 
			
		||||
        <view class="category-item" v-for="(item, index) in categoryList" :key="item.id">
 | 
			
		||||
          <view class="item-title" :class="{ active: currentIndex === index }" @click="handleCategoryClick(index)">
 | 
			
		||||
            <text>{{ item.name }}</text>
 | 
			
		||||
          </view>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="box-right">
 | 
			
		||||
        <image class="category-image" :showLoading="true" :src="categoryList[currentIndex].image" width="530rpx" height="160rpx" @click="click"></image>
 | 
			
		||||
      </scroll-view>
 | 
			
		||||
 | 
			
		||||
      <!-- 右侧分类内容 -->
 | 
			
		||||
      <scroll-view scroll-y="true" class="box-right">
 | 
			
		||||
        <view class="category-image">
 | 
			
		||||
          <image :showLoading="true" :src="categoryList[currentIndex].bannerUrl" mode='widthFix' @click="click"></image>
 | 
			
		||||
        </view>
 | 
			
		||||
 | 
			
		||||
        <view class="sub-category-box" v-for="(item, index) in categoryList[currentIndex].children" :key="item.id">
 | 
			
		||||
          <view class="sub-category-header">
 | 
			
		||||
            <view class="title">{{ item.title }}</view>
 | 
			
		||||
            <view class="more">查看更多</view>
 | 
			
		||||
            <view class="title">{{ item.name }}</view>
 | 
			
		||||
            <view class="more" @click="handleCategory(item, 0)">查看更多</view>
 | 
			
		||||
          </view>
 | 
			
		||||
 | 
			
		||||
          <view class="sub-category-grid">
 | 
			
		||||
            <u-grid col="3">
 | 
			
		||||
              <u-grid-item v-for="(subItem, subIndex) in item.children" :key="subItem.id">
 | 
			
		||||
                <view class="sub-category-item" @click="handleCategory(item, subIndex)">
 | 
			
		||||
                  <u-icon name="photo" :size="80" v-if="subItem.bannerUrl === null"></u-icon>
 | 
			
		||||
                  <image :src="item.bannerUrl" v-if="subItem.bannerUrl != null" mode='widthFix' />
 | 
			
		||||
                  <text class="sub-category-title">{{ subItem.name }}</text>
 | 
			
		||||
                </view>
 | 
			
		||||
              </u-grid-item>
 | 
			
		||||
            </u-grid>
 | 
			
		||||
          </view>
 | 
			
		||||
          <u-grid class="sub-category-grid" col="3">
 | 
			
		||||
            <u-grid-item v-for="(subItem, subIndex) in item.category" :key="subItem.id">
 | 
			
		||||
              <view class="sub-category-item">
 | 
			
		||||
                <u-icon name="photo" :size="80"></u-icon>
 | 
			
		||||
                <text class="sub-category-title">{{ subItem.title }}</text>
 | 
			
		||||
              </view>
 | 
			
		||||
            </u-grid-item>
 | 
			
		||||
          </u-grid>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      </scroll-view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      currentIndex: 0,
 | 
			
		||||
      categoryList: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    for (let i = 0; i < 10; i++) {
 | 
			
		||||
      this.categoryList.push({
 | 
			
		||||
        id: i,
 | 
			
		||||
        image: 'https://cdn.uviewui.com/uview/swiper/swiper1.png',
 | 
			
		||||
        name: '商品分类' + i,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            id: 0,
 | 
			
		||||
            title: '分类' + i + '-1',
 | 
			
		||||
            category: [
 | 
			
		||||
              {
 | 
			
		||||
                id: 0,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-1-1'
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 2,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-1-2'
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 3,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-1-3'
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            id: 1,
 | 
			
		||||
            title: '分类' + i + '-2',
 | 
			
		||||
            category: [
 | 
			
		||||
              {
 | 
			
		||||
                id: 0,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-2-1'
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 2,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-2-2'
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 3,
 | 
			
		||||
                image: '',
 | 
			
		||||
                title: '分类' + i + '-2-3'
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleSearchClick(e) {
 | 
			
		||||
      uni.$u.route('/pages/search/search')
 | 
			
		||||
  import { categoryListData } from '../../api/category';
 | 
			
		||||
  import { handleTree, convertTree } from '../../utils/tree.js';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        currentIndex: 0,
 | 
			
		||||
        categoryList: []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleCategoryClick(index) {
 | 
			
		||||
      if (this.currentIndex !== index) {
 | 
			
		||||
        this.currentIndex = index
 | 
			
		||||
    onLoad() {
 | 
			
		||||
      this.handleCategoryList();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      // 点击搜索框
 | 
			
		||||
      handleSearchClick(e) {
 | 
			
		||||
        uni.$u.route('/pages/search/search')
 | 
			
		||||
      },
 | 
			
		||||
      // 点击左侧导航栏
 | 
			
		||||
      handleCategoryClick(index) {
 | 
			
		||||
        if (this.currentIndex !== index) {
 | 
			
		||||
          this.currentIndex = index
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      // 获取分类列表并构建树形结构
 | 
			
		||||
      handleCategoryList() {
 | 
			
		||||
        categoryListData().then(res => {
 | 
			
		||||
          this.categoryList = handleTree(res.data, "id", "parentId");
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleCategory(item, index){
 | 
			
		||||
        // console.log(item)
 | 
			
		||||
        // console.log(index)
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url:"./product-list?item="+encodeURIComponent(JSON.stringify(item))+"&index="+index
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
 | 
			
		||||
.search-wrap {
 | 
			
		||||
  background: $custom-bg-color;
 | 
			
		||||
  padding: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.category-box {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  .box-left {
 | 
			
		||||
    width: 200rpx;
 | 
			
		||||
    padding-top: 20rpx;
 | 
			
		||||
    border-right: $custom-border-style;
 | 
			
		||||
    .category-item {
 | 
			
		||||
      border-bottom: $custom-border-style;
 | 
			
		||||
      padding: 20rpx 0;
 | 
			
		||||
      .item-title {
 | 
			
		||||
        padding-left: 30rpx;
 | 
			
		||||
        font-size: 28rpx;
 | 
			
		||||
        &.active {
 | 
			
		||||
          border-left: 6rpx solid $u-primary;
 | 
			
		||||
          font-weight: 700;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  .search-wrap {
 | 
			
		||||
    background: #ffffff;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.07);
 | 
			
		||||
    padding: 20rpx 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    z-index: 3;
 | 
			
		||||
  }
 | 
			
		||||
  .box-right {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    .category-image {
 | 
			
		||||
      width: 510rpx;
 | 
			
		||||
      height: 160rpx;
 | 
			
		||||
      padding: 20rpx;
 | 
			
		||||
 | 
			
		||||
  .category-box {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    margin-top: 100rpx;
 | 
			
		||||
    height: calc(100% - 100rpx);
 | 
			
		||||
 | 
			
		||||
    .box-left {
 | 
			
		||||
      width: 200rpx;
 | 
			
		||||
      padding-top: 5rpx;
 | 
			
		||||
      overflow: scroll;
 | 
			
		||||
      z-index: 2;
 | 
			
		||||
      background-color: #f2f2f2;
 | 
			
		||||
 | 
			
		||||
      .category-item {
 | 
			
		||||
        line-height: 80rpx;
 | 
			
		||||
        height: 80rpx;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        color: #777;
 | 
			
		||||
 | 
			
		||||
        .item-title {
 | 
			
		||||
          font-size: 28rpx;
 | 
			
		||||
 | 
			
		||||
          &.active {
 | 
			
		||||
            font-size: 28rpx;
 | 
			
		||||
            font-weight: bold;
 | 
			
		||||
            position: relative;
 | 
			
		||||
            background: #fff;
 | 
			
		||||
            color: $u-primary;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &.active::before {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            left: 0;
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 8rpx;
 | 
			
		||||
            height: 32rpx;
 | 
			
		||||
            top: 25rpx;
 | 
			
		||||
            background: $u-primary;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .sub-category-box {
 | 
			
		||||
      .sub-category-header {
 | 
			
		||||
        @include flex-space-between;
 | 
			
		||||
        padding: 30rpx 20rpx;
 | 
			
		||||
    .box-right {
 | 
			
		||||
      width: 550rpx;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
          font-size: 28rpx;
 | 
			
		||||
          font-weight: 700;
 | 
			
		||||
        }
 | 
			
		||||
        .more {
 | 
			
		||||
          font-size: 22rpx;
 | 
			
		||||
          color: #939393;
 | 
			
		||||
      .category-image {
 | 
			
		||||
        width: 510rpx;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        margin: 30rpx 20rpx 0;
 | 
			
		||||
 | 
			
		||||
        image {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .sub-category-grid {
 | 
			
		||||
        padding: 0 15rpx;
 | 
			
		||||
      .sub-category-box {
 | 
			
		||||
        .sub-category-header {
 | 
			
		||||
          @include flex-space-between;
 | 
			
		||||
          padding: 20rpx 20rpx;
 | 
			
		||||
 | 
			
		||||
        .sub-category-item {
 | 
			
		||||
          @include flex-center(column);
 | 
			
		||||
          background: #fff;
 | 
			
		||||
          .title {
 | 
			
		||||
            font-size: 28rpx;
 | 
			
		||||
            font-weight: bolder;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .sub-category-title {
 | 
			
		||||
            margin: 15rpx 0;
 | 
			
		||||
            font-size: 24rpx;
 | 
			
		||||
          .more {
 | 
			
		||||
            font-size: 22rpx;
 | 
			
		||||
            color: #939393;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .sub-category-grid {
 | 
			
		||||
          padding: 0 15rpx;
 | 
			
		||||
 | 
			
		||||
          .sub-category-item {
 | 
			
		||||
            @include flex-center(column);
 | 
			
		||||
            background: #fff;
 | 
			
		||||
 | 
			
		||||
            image {
 | 
			
		||||
              text-align: center;
 | 
			
		||||
              width: 150rpx;
 | 
			
		||||
              height: 150rpx;
 | 
			
		||||
              line-height: 150rpx;
 | 
			
		||||
              font-size: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .sub-category-title {
 | 
			
		||||
              margin: 15rpx 0;
 | 
			
		||||
              font-size: 22rpx;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										161
									
								
								yudao-ui-app/pages/category/product-list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								yudao-ui-app/pages/category/product-list.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <view class="container">
 | 
			
		||||
    <u-navbar :title="title" :autoBack="true" placeholder="true" titleStyle="font-size: 28rpx">
 | 
			
		||||
    </u-navbar>
 | 
			
		||||
    <view class="context">
 | 
			
		||||
      <view class="tabs-top">
 | 
			
		||||
        <u-tabs :list="categoryList" @click="changeTabs" :current="current" lineHeight="2" lineWidth="85rpx"
 | 
			
		||||
          itemStyle="padding-left: 15px; padding-right: 15px; height: 85rpx;"></u-tabs>
 | 
			
		||||
      </view>
 | 
			
		||||
      <scroll-view scroll-y="true" class="product-list" enable-flex="true">
 | 
			
		||||
        <view class="flex-box">
 | 
			
		||||
          <block v-for="(item, index) in productList[current]" :key="index">
 | 
			
		||||
            <view class="product-item">
 | 
			
		||||
              <view class="product-image">
 | 
			
		||||
                <image :src="item.picUrls[0]" mode='widthFix' />
 | 
			
		||||
              </view>
 | 
			
		||||
              <view class="product-button">
 | 
			
		||||
                <view class="product-text">【{{ item.sellPoint }}】{{ item.name }}</view>
 | 
			
		||||
                <view class="product-price-button">
 | 
			
		||||
                  <text class="product-price">¥
 | 
			
		||||
                    <text class="price-size">{{ towNumber(item.price) }}</text></text>
 | 
			
		||||
                  <text class="product-like-ccount">销量 {{ item.likeCount }}</text>
 | 
			
		||||
                </view>
 | 
			
		||||
              </view>
 | 
			
		||||
            </view>
 | 
			
		||||
          </block>
 | 
			
		||||
        </view>
 | 
			
		||||
      </scroll-view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import {
 | 
			
		||||
    productSpuPage
 | 
			
		||||
  } from '../../api/product';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        title: "",
 | 
			
		||||
        current: 0,
 | 
			
		||||
        categoryList: [],
 | 
			
		||||
        productList: {}
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(option) {
 | 
			
		||||
      const item = JSON.parse(decodeURIComponent(option.item))
 | 
			
		||||
      this.title = item.name
 | 
			
		||||
      this.categoryList = item.children
 | 
			
		||||
      this.handleProductSpu(option.index);
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      changeTabs(item) {
 | 
			
		||||
        if (item.index != this.current) {
 | 
			
		||||
          this.handleProductSpu(item.index)
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      handleProductSpu(index) {
 | 
			
		||||
        let param = {}
 | 
			
		||||
        param.categoryId = this.categoryList[index].id
 | 
			
		||||
        console.log(this.categoryList)
 | 
			
		||||
        console.log(index)
 | 
			
		||||
        productSpuPage(param).then(res => {
 | 
			
		||||
          this.productList[index] = res.data.list
 | 
			
		||||
          this.current = index
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      towNumber(val) {
 | 
			
		||||
        return (val / 100).toFixed(2)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .context {
 | 
			
		||||
    width: 100vw;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 160rpx;
 | 
			
		||||
    left: 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tabs-top {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 85rpx;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .product-list {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    background-color: #f2f2f2;
 | 
			
		||||
    height: calc(100vh - 88rpx - 100rpx - var(--status-bar-height));
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
    .flex-box {
 | 
			
		||||
      width: 730rpx;
 | 
			
		||||
      margin: 0 auto;
 | 
			
		||||
      @include flex;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
      justify-content: left;
 | 
			
		||||
 | 
			
		||||
      .product-item {
 | 
			
		||||
        width: 345rpx;
 | 
			
		||||
        height: 450rpx;
 | 
			
		||||
        background-color: #ffffff;
 | 
			
		||||
        margin: 20rpx 10rpx 0;
 | 
			
		||||
        border-radius: 20rpx;
 | 
			
		||||
 | 
			
		||||
        .product-image {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 300rpx;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          border-radius: 20rpx;
 | 
			
		||||
          image {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .product-button {
 | 
			
		||||
          width: 330rpx;
 | 
			
		||||
          margin: 15rpx auto 0;
 | 
			
		||||
 | 
			
		||||
          .product-text {
 | 
			
		||||
            font-size: 25rpx;
 | 
			
		||||
            height: 70rpx;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            -webkit-line-clamp: 2;
 | 
			
		||||
            text-overflow: ellipsis;
 | 
			
		||||
            display: -webkit-box;
 | 
			
		||||
            -webkit-box-orient: vertical;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .product-price-button {
 | 
			
		||||
            font-size: 20rpx;
 | 
			
		||||
            margin-top: 20rpx;
 | 
			
		||||
 | 
			
		||||
            .product-price {
 | 
			
		||||
              color: red;
 | 
			
		||||
 | 
			
		||||
              .price-size {
 | 
			
		||||
                font-size: 26rpx;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .product-like-ccount {
 | 
			
		||||
              font-size: 16rpx;
 | 
			
		||||
              margin-left: 10rpx;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
		Reference in New Issue
	
	Block a user