Commit e2a6530acb94de6a36be483162bc3b66804c4a2c
1 parent
f3c83488
feature(uniapp分类): 分类列表以及商品加载
Showing
16 changed files
with
585 additions
and
139 deletions
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.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuPageReqVO; | |
| 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.service.spu.ProductSpuService; | |
| 10 | +import io.swagger.annotations.Api; | |
| 11 | +import io.swagger.annotations.ApiOperation; | |
| 12 | +import org.springframework.validation.annotation.Validated; | |
| 13 | +import org.springframework.web.bind.annotation.GetMapping; | |
| 14 | +import org.springframework.web.bind.annotation.RequestBody; | |
| 15 | +import org.springframework.web.bind.annotation.RequestMapping; | |
| 16 | +import org.springframework.web.bind.annotation.RestController; | |
| 17 | + | |
| 18 | +import javax.annotation.Resource; | |
| 19 | +import javax.validation.Valid; | |
| 20 | + | |
| 21 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 22 | + | |
| 23 | +@Api(tags = "用户 APP - 商品spu") | |
| 24 | +@RestController | |
| 25 | +@RequestMapping("/product/spu") | |
| 26 | +@Validated | |
| 27 | +public class AppProductSpuController { | |
| 28 | + | |
| 29 | + @Resource | |
| 30 | + private ProductSpuService spuService; | |
| 31 | + | |
| 32 | + @GetMapping("/page") | |
| 33 | + @ApiOperation("获得商品spu分页") | |
| 34 | + public CommonResult<PageResult<AppSpuPageRespVO>> getSpuPage(@Valid AppSpuPageReqVO pageVO) { | |
| 35 | + return success(spuService.getSpuPage(pageVO)); | |
| 36 | + } | |
| 37 | +} | ... | ... |
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/convert/category/CategoryConvert.java
| ... | ... | @@ -4,6 +4,7 @@ import java.util.*; |
| 4 | 4 | |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | |
| 7 | +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO; | |
| 7 | 8 | import org.mapstruct.Mapper; |
| 8 | 9 | import org.mapstruct.factory.Mappers; |
| 9 | 10 | import cn.iocoder.yudao.module.product.controller.admin.category.vo.*; |
| ... | ... | @@ -31,4 +32,5 @@ public interface CategoryConvert { |
| 31 | 32 | |
| 32 | 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 | 4 | |
| 5 | 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 | 9 | import org.mapstruct.Mapper; |
| 8 | 10 | import org.mapstruct.Mapping; |
| 9 | 11 | import org.mapstruct.Named; |
| ... | ... | @@ -40,6 +42,11 @@ public interface ProductSpuConvert { |
| 40 | 42 | |
| 41 | 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 | 50 | @Named("tokenizeToStringArray") |
| 44 | 51 | default List<String> translatePicUrlsArrayFromString(String picUrls) { |
| 45 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.product.controller.admin.category.vo.*; |
| 5 | +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryListRespVO; | |
| 5 | 6 | import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO; |
| 6 | 7 | |
| 7 | 8 | import javax.validation.Valid; |
| ... | ... | @@ -83,4 +84,11 @@ public interface CategoryService { |
| 83 | 84 | * @param categoryId 分类id |
| 84 | 85 | */ |
| 85 | 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 | 1 | package cn.iocoder.yudao.module.product.service.category; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| ... | ... | @@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated; |
| 13 | 14 | import javax.annotation.Resource; |
| 14 | 15 | import java.util.Collection; |
| 15 | 16 | import java.util.List; |
| 17 | +import java.util.stream.Collectors; | |
| 16 | 18 | |
| 17 | 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 18 | 20 | import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; |
| ... | ... | @@ -106,4 +108,13 @@ public class CategoryServiceImpl implements CategoryService { |
| 106 | 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 | 3 | import java.util.*; |
| 4 | 4 | import javax.validation.*; |
| 5 | 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 | 8 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 7 | 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 10 | |
| ... | ... | @@ -67,4 +69,13 @@ public interface ProductSpuService { |
| 67 | 69 | */ |
| 68 | 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
| ... | ... | @@ -8,9 +8,10 @@ import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; |
| 8 | 8 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; |
| 10 | 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; | |
| 11 | 13 | import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; |
| 12 | 14 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; |
| 13 | -import cn.iocoder.yudao.module.product.dal.dataobject.category.CategoryDO; | |
| 14 | 15 | import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; |
| 15 | 16 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 16 | 17 | import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; |
| ... | ... | @@ -175,4 +176,17 @@ public class ProductSpuServiceImpl implements ProductSpuService { |
| 175 | 176 | return ProductSpuMapper.selectList(exportReqVO); |
| 176 | 177 | } |
| 177 | 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 | + | |
| 178 | 192 | } | ... | ... |
yudao-ui-app/api/category.js
0 → 100644
yudao-ui-app/api/product.js
0 → 100644
yudao-ui-app/pages.json
| ... | ... | @@ -12,6 +12,14 @@ |
| 12 | 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 | 24 | "path": "pages/cart/cart", |
| 17 | 25 | "style": { |
| ... | ... | @@ -112,7 +120,7 @@ |
| 112 | 120 | "globalStyle": { |
| 113 | 121 | "navigationBarTextStyle": "black", |
| 114 | 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 | 1 | <template> |
| 2 | 2 | <view class="container"> |
| 3 | + <!-- 搜索框 --> | |
| 3 | 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 | 7 | </view> |
| 8 | + | |
| 9 | + <!-- 分类内容 --> | |
| 6 | 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 | 16 | </view> |
| 14 | 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 | 26 | <view class="sub-category-box" v-for="(item, index) in categoryList[currentIndex].children" :key="item.id"> |
| 19 | 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 | 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 | 43 | </view> |
| 32 | - </view> | |
| 44 | + </scroll-view> | |
| 33 | 45 | </view> |
| 34 | 46 | </view> |
| 35 | 47 | </template> |
| 36 | 48 | |
| 37 | 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 | 89 | </script> |
| 110 | 90 | |
| 111 | 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 | 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> | ... | ... |