完成商品管理模块下的 商品分类管理,完成单元测试
This commit is contained in:
parent
cc6b7f1bb1
commit
ac54a32dd5
|
@ -0,0 +1,122 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.*;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.convert.product.MallProductCategoryConvert;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.service.product.MallProductCategoryService;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@Api(tags = "商品分类")
|
||||
@RestController
|
||||
@RequestMapping("/mall/product-category")
|
||||
@Validated
|
||||
public class MallProductCategoryController {
|
||||
|
||||
@Resource
|
||||
private MallProductCategoryService productCategoryService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:create')")
|
||||
public CommonResult<Long> createProductCategory(@Valid @RequestBody MallProductCategoryCreateReqVO createReqVO) {
|
||||
return success(productCategoryService.createProductCategory(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("更新商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:update')")
|
||||
public CommonResult<Boolean> updateProductCategory(@Valid @RequestBody MallProductCategoryUpdateReqVO updateReqVO) {
|
||||
productCategoryService.updateProductCategory(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@ApiOperation("修改商品分类状态")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-attr-key:update')")
|
||||
public CommonResult<Boolean> updateProductAttrStatus(@Valid @RequestBody MallProductCategoryUpdateStatusReqVO reqVO) {
|
||||
productCategoryService.updateProductBrandStatus(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@ApiOperation("删除商品分类")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:delete')")
|
||||
public CommonResult<Boolean> deleteProductCategory(@RequestParam("id") Long id) {
|
||||
productCategoryService.deleteProductCategory(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@ApiOperation("获得商品分类")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:query')")
|
||||
public CommonResult<MallProductCategoryRespVO> getProductCategory(@RequestParam("id") Long id) {
|
||||
MallProductCategoryDO productCategory = productCategoryService.getProductCategory(id);
|
||||
return success(MallProductCategoryConvert.INSTANCE.convert(productCategory));
|
||||
}
|
||||
|
||||
@GetMapping("/get-roots")
|
||||
@ApiOperation("获得商品顶级")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:query')")
|
||||
public CommonResult<List<MallProductSimpleCategoryRespVO>> getProductCategoryRoots() {
|
||||
List<MallProductCategoryDO> categoryRoots = productCategoryService.getProductCategoryRoots();
|
||||
return success(MallProductCategoryConvert.INSTANCE.convertRootList(categoryRoots));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获得商品分类列表")
|
||||
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:query')")
|
||||
public CommonResult<List<MallProductCategoryRespVO>> getProductCategoryList(
|
||||
@RequestParam("ids") Collection<Long> ids) {
|
||||
List<MallProductCategoryDO> list = productCategoryService.getProductCategoryList(ids);
|
||||
return success(MallProductCategoryConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@ApiOperation("获得商品分类分页")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:query')")
|
||||
public CommonResult<PageResult<MallProductCategoryRespVO>> getProductCategoryPage(
|
||||
@Valid MallProductCategoryPageReqVO pageVO) {
|
||||
PageResult<MallProductCategoryDO> pageResult = productCategoryService.getProductCategoryPage(pageVO);
|
||||
return success(MallProductCategoryConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@ApiOperation("导出商品分类 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('mall:product-category:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportProductCategoryExcel(@Valid MallProductCategoryExportReqVO exportReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
List<MallProductCategoryDO> list = productCategoryService.getProductCategoryList(exportReqVO);
|
||||
// 导出 Excel
|
||||
List<MallProductCategoryExcelVO> datas = MallProductCategoryConvert.INSTANCE.convertList02(list);
|
||||
ExcelUtils.write(response, "商品分类.xls", "数据", MallProductCategoryExcelVO.class, datas);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,11 +3,6 @@ package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.brand;
|
|||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
|
@ -19,21 +14,7 @@ public class MallProductBrandExportReqVO {
|
|||
@ApiModelProperty(value = "品牌名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "品牌描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "品牌名图片")
|
||||
private String picUrl;
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@ApiModelProperty(value = "开始创建时间")
|
||||
private Date beginCreateTime;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@ApiModelProperty(value = "结束创建时间")
|
||||
private Date endCreateTime;
|
||||
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@ import io.swagger.annotations.ApiModelProperty;
|
|||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
|
@ -24,21 +19,7 @@ public class MallProductBrandPageReqVO extends PageParam {
|
|||
@ApiModelProperty(value = "品牌名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "品牌描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "品牌名图片")
|
||||
private String picUrl;
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@ApiModelProperty(value = "开始创建时间")
|
||||
private Date beginCreateTime;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@ApiModelProperty(value = "结束创建时间")
|
||||
private Date endCreateTime;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 商品分类 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Data
|
||||
public class MallProductCategoryBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "父分类编号", required = true)
|
||||
@NotNull(message = "父分类编号不能为空")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "分类名称", required = true)
|
||||
@NotNull(message = "分类名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "分类描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "分类图片")
|
||||
private String picUrl;
|
||||
|
||||
@ApiModelProperty(value = "分类排序", required = true)
|
||||
@NotNull(message = "分类排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "状态", required = true)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("商品分类创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MallProductCategoryCreateReqVO extends MallProductCategoryBaseVO {
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 商品分类 Excel VO
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Data
|
||||
public class MallProductCategoryExcelVO {
|
||||
|
||||
@ExcelProperty("分类编号")
|
||||
private Long id;
|
||||
|
||||
@ExcelProperty("父分类编号")
|
||||
private Long pid;
|
||||
|
||||
@ExcelProperty("分类名称")
|
||||
private String name;
|
||||
|
||||
@ExcelProperty("分类描述")
|
||||
private String description;
|
||||
|
||||
@ExcelProperty("分类图片")
|
||||
private String picUrl;
|
||||
|
||||
@ExcelProperty("分类排序")
|
||||
private Integer sort;
|
||||
|
||||
@DictFormat("sys_common_status")
|
||||
@ExcelProperty(value = "状态", converter = DictConvert.class)
|
||||
private Integer status;
|
||||
|
||||
@ExcelProperty("创建时间")
|
||||
private Date createTime;
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel(value = "商品分类 Excel 导出 Request VO", description = "参数和 MallProductCategoryPageReqVO 是一致的")
|
||||
@Data
|
||||
public class MallProductCategoryExportReqVO {
|
||||
|
||||
@ApiModelProperty(value = "父分类编号")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "分类名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("商品分类分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MallProductCategoryPageReqVO extends PageParam {
|
||||
|
||||
@ApiModelProperty(value = "父分类编号,不传递默认为根目录")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "分类名称,查询当前目录下的")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("商品分类 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MallProductCategoryRespVO extends MallProductCategoryBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "分类编号", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "创建时间", required = true)
|
||||
private Date createTime;
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("商品分类更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MallProductCategoryUpdateReqVO extends MallProductCategoryBaseVO {
|
||||
|
||||
@ApiModelProperty(value = "分类编号", required = true)
|
||||
@NotNull(message = "分类编号不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("修改商品状态 Request VO")
|
||||
@Data
|
||||
public class MallProductCategoryUpdateStatusReqVO {
|
||||
|
||||
@ApiModelProperty(value = "商品类别编号", required = true, example = "1024")
|
||||
@NotNull(message = "商品类别编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SysCommonStatusEnum 枚举")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author aquan
|
||||
*/
|
||||
@ApiModel("商品分类简单信息 Response VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class MallProductSimpleCategoryRespVO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "分类编号", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "分类名称", required = true)
|
||||
@NotNull(message = "分类名称不能为空")
|
||||
private String name;
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.convert.product;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.*;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品分类 Convert
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Mapper
|
||||
public interface MallProductCategoryConvert {
|
||||
|
||||
MallProductCategoryConvert INSTANCE = Mappers.getMapper(MallProductCategoryConvert.class);
|
||||
|
||||
MallProductCategoryDO convert(MallProductCategoryUpdateStatusReqVO bean);
|
||||
|
||||
MallProductCategoryDO convert(MallProductCategoryCreateReqVO bean);
|
||||
|
||||
MallProductCategoryDO convert(MallProductCategoryUpdateReqVO bean);
|
||||
|
||||
MallProductCategoryRespVO convert(MallProductCategoryDO bean);
|
||||
|
||||
List<MallProductCategoryRespVO> convertList(List<MallProductCategoryDO> list);
|
||||
|
||||
List<MallProductSimpleCategoryRespVO> convertRootList(List<MallProductCategoryDO> list);
|
||||
|
||||
PageResult<MallProductCategoryRespVO> convertPage(PageResult<MallProductCategoryDO> page);
|
||||
|
||||
List<MallProductCategoryExcelVO> convertList02(List<MallProductCategoryDO> list);
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 商品分类 DO
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@TableName("mall_product_category")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MallProductCategoryDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 分类编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 父分类编号
|
||||
*/
|
||||
private Long pid;
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 分类描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 分类图片
|
||||
*/
|
||||
private String picUrl;
|
||||
/**
|
||||
* 分类排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.dal.mysql.product;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryExportReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryPageReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.enums.MallProductCategoryConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品分类 Mapper
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Mapper
|
||||
public interface MallProductCategoryMapper extends BaseMapperX<MallProductCategoryDO> {
|
||||
|
||||
default PageResult<MallProductCategoryDO> selectPage(MallProductCategoryPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new QueryWrapperX<MallProductCategoryDO>()
|
||||
.eqIfPresent("pid", reqVO.getPid())
|
||||
.likeIfPresent("name", reqVO.getName())
|
||||
.eqIfPresent("status", reqVO.getStatus())
|
||||
.orderByDesc("id"));
|
||||
}
|
||||
|
||||
default List<MallProductCategoryDO> selectList(MallProductCategoryExportReqVO reqVO) {
|
||||
return selectList(new QueryWrapperX<MallProductCategoryDO>()
|
||||
.eqIfPresent("pid", reqVO.getPid())
|
||||
.likeIfPresent("name", reqVO.getName())
|
||||
.eqIfPresent("status", reqVO.getStatus())
|
||||
.orderByDesc("id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询顶级商品分类列表
|
||||
*
|
||||
* @return 顶级商品分类列表
|
||||
*/
|
||||
default List<MallProductCategoryDO> selectRoots(){
|
||||
return selectList(new LambdaQueryWrapper<MallProductCategoryDO>()
|
||||
.eq(MallProductCategoryDO::getPid, MallProductCategoryConstants.CATEGORY_ROOT_PID));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前类别下的子类目数量
|
||||
* @param id 类目 ID
|
||||
* @return 子类目数量
|
||||
*/
|
||||
default Long selectLeavesCount(Long id) {
|
||||
return selectCount(new LambdaQueryWrapper<MallProductCategoryDO>().eq(MallProductCategoryDO::getPid,id));
|
||||
}
|
||||
}
|
|
@ -22,4 +22,12 @@ public interface MallErrorCodeConstants {
|
|||
* ========== 商品品牌模块 1-009-000-000 ==========
|
||||
*/
|
||||
ErrorCode PRODUCT_BRAND_NOT_EXISTS = new ErrorCode(1009000001, "商品品牌不存在");
|
||||
|
||||
/**
|
||||
* ========== 商品分类模块 1-010-000-000 ==========
|
||||
*/
|
||||
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1010000001, "商品分类不存在");
|
||||
|
||||
ErrorCode PRODUCT_CATEGORY_LEAVERS_EXISTS_CANT_DELETE = new ErrorCode(1010000002, "当前商品分类存在子分类,无法删除");
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.enums;
|
||||
|
||||
/**
|
||||
* 商品类别常量枚举
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
public interface MallProductCategoryConstants {
|
||||
|
||||
/**
|
||||
* 分类根 PID 值
|
||||
*/
|
||||
Long CATEGORY_ROOT_PID = 0L;
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.service.product;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.*;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品分类 Service 接口
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
public interface MallProductCategoryService {
|
||||
|
||||
/**
|
||||
* 创建商品分类
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createProductCategory(@Valid MallProductCategoryCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新商品分类
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateProductCategory(@Valid MallProductCategoryUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 更新商品分类状态
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateProductBrandStatus(MallProductCategoryUpdateStatusReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除商品分类
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteProductCategory(Long id);
|
||||
|
||||
/**
|
||||
* 获得商品分类
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 商品分类
|
||||
*/
|
||||
MallProductCategoryDO getProductCategory(Long id);
|
||||
|
||||
/**
|
||||
* 获取顶级商品分类简单信息列表
|
||||
*
|
||||
* @return 顶级商品分类列表
|
||||
*/
|
||||
List<MallProductCategoryDO> getProductCategoryRoots();
|
||||
|
||||
/**
|
||||
* 获得商品分类列表
|
||||
*
|
||||
* @param ids 编号
|
||||
* @return 商品分类列表
|
||||
*/
|
||||
List<MallProductCategoryDO> getProductCategoryList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得商品分类分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 商品分类分页
|
||||
*/
|
||||
PageResult<MallProductCategoryDO> getProductCategoryPage(MallProductCategoryPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得商品分类列表, 用于 Excel 导出
|
||||
*
|
||||
* @param exportReqVO 查询条件
|
||||
* @return 商品分类列表
|
||||
*/
|
||||
List<MallProductCategoryDO> getProductCategoryList(MallProductCategoryExportReqVO exportReqVO);
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.service.product.impl;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.*;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.convert.product.MallProductCategoryConvert;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.mysql.product.MallProductCategoryMapper;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.enums.MallProductCategoryConstants;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.service.product.MallProductCategoryService;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.adminserver.modules.mall.enums.MallErrorCodeConstants.PRODUCT_CATEGORY_LEAVERS_EXISTS_CANT_DELETE;
|
||||
import static cn.iocoder.yudao.adminserver.modules.mall.enums.MallErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 商品分类 Service 实现类
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class MallProductCategoryServiceImpl implements MallProductCategoryService {
|
||||
|
||||
@Resource
|
||||
private MallProductCategoryMapper productCategoryMapper;
|
||||
|
||||
@Override
|
||||
public Long createProductCategory(MallProductCategoryCreateReqVO createReqVO) {
|
||||
// 插入
|
||||
MallProductCategoryDO productCategory = MallProductCategoryConvert.INSTANCE.convert(createReqVO);
|
||||
productCategoryMapper.insert(productCategory);
|
||||
// 返回
|
||||
return productCategory.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProductCategory(MallProductCategoryUpdateReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
this.validateProductCategoryExists(updateReqVO.getId());
|
||||
// 更新
|
||||
MallProductCategoryDO updateObj = MallProductCategoryConvert.INSTANCE.convert(updateReqVO);
|
||||
productCategoryMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商品分类状态
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
@Override
|
||||
public void updateProductBrandStatus(MallProductCategoryUpdateStatusReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
this.validateProductCategoryExists(updateReqVO.getId());
|
||||
// 更新
|
||||
MallProductCategoryDO updateObj = MallProductCategoryConvert.INSTANCE.convert(updateReqVO);
|
||||
productCategoryMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProductCategory(Long id) {
|
||||
// 校验存在
|
||||
this.validateProductCategoryExists(id);
|
||||
// 校验是否存在子类目
|
||||
this.validateProductCategoryContainsLeaves(id);
|
||||
// 删除
|
||||
productCategoryMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void validateProductCategoryExists(Long id) {
|
||||
if (productCategoryMapper.selectById(id) == null) {
|
||||
throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateProductCategoryContainsLeaves(Long id) {
|
||||
if (productCategoryMapper.selectLeavesCount(id) > 0) {
|
||||
throw exception(PRODUCT_CATEGORY_LEAVERS_EXISTS_CANT_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MallProductCategoryDO getProductCategory(Long id) {
|
||||
return productCategoryMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MallProductCategoryDO> getProductCategoryRoots() {
|
||||
return productCategoryMapper.selectRoots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MallProductCategoryDO> getProductCategoryList(Collection<Long> ids) {
|
||||
return productCategoryMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<MallProductCategoryDO> getProductCategoryPage(MallProductCategoryPageReqVO pageReqVO) {
|
||||
// 对栏父栏目ID做处理,如果是空的则表示为根栏目
|
||||
if (pageReqVO.getPid() == null) {
|
||||
pageReqVO.setPid(MallProductCategoryConstants.CATEGORY_ROOT_PID);
|
||||
}
|
||||
return productCategoryMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MallProductCategoryDO> getProductCategoryList(MallProductCategoryExportReqVO exportReqVO) {
|
||||
// 对栏父栏目ID做处理,如果是空的则表示为根栏目
|
||||
if (exportReqVO.getPid() == null) {
|
||||
exportReqVO.setPid(MallProductCategoryConstants.CATEGORY_ROOT_PID);
|
||||
}
|
||||
return productCategoryMapper.selectList(exportReqVO);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package cn.iocoder.yudao.adminserver.modules.mall.service.product;
|
||||
|
||||
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryCreateReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryExportReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryPageReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.controller.product.vo.category.MallProductCategoryUpdateReqVO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.dataobject.product.MallProductCategoryDO;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.dal.mysql.product.MallProductCategoryMapper;
|
||||
import cn.iocoder.yudao.adminserver.modules.mall.service.product.impl.MallProductCategoryServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.adminserver.modules.mall.enums.MallErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
|
||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* {@link MallProductCategoryServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author aquan
|
||||
*/
|
||||
@Import(MallProductCategoryServiceImpl.class)
|
||||
public class MallProductCategoryServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private MallProductCategoryServiceImpl productCategoryService;
|
||||
|
||||
@Resource
|
||||
private MallProductCategoryMapper productCategoryMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateProductCategory_success() {
|
||||
// 准备参数
|
||||
MallProductCategoryCreateReqVO reqVO = randomPojo(MallProductCategoryCreateReqVO.class,
|
||||
o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
|
||||
// 调用
|
||||
Long productCategoryId = productCategoryService.createProductCategory(reqVO);
|
||||
// 断言
|
||||
assertNotNull(productCategoryId);
|
||||
// 校验记录的属性是否正确
|
||||
MallProductCategoryDO productCategory = productCategoryMapper.selectById(productCategoryId);
|
||||
assertPojoEquals(reqVO, productCategory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProductCategory_success() {
|
||||
// mock 数据
|
||||
MallProductCategoryDO dbProductCategory = randomPojo(MallProductCategoryDO.class,
|
||||
o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
productCategoryMapper.insert(dbProductCategory);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
MallProductCategoryUpdateReqVO reqVO = randomPojo(MallProductCategoryUpdateReqVO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
o.setId(dbProductCategory.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
productCategoryService.updateProductCategory(reqVO);
|
||||
// 校验是否更新正确
|
||||
MallProductCategoryDO productCategory = productCategoryMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, productCategory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProductCategory_notExists() {
|
||||
// 准备参数
|
||||
MallProductCategoryUpdateReqVO reqVO = randomPojo(MallProductCategoryUpdateReqVO.class,
|
||||
o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> productCategoryService.updateProductCategory(reqVO), PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteProductCategory_success() {
|
||||
// mock 数据
|
||||
MallProductCategoryDO dbProductCategory = randomPojo(MallProductCategoryDO.class,
|
||||
o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
productCategoryMapper.insert(dbProductCategory);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbProductCategory.getId();
|
||||
|
||||
// 调用
|
||||
productCategoryService.deleteProductCategory(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(productCategoryMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteProductCategory_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> productCategoryService.deleteProductCategory(id), PRODUCT_CATEGORY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetProductCategoryPage() {
|
||||
// mock 数据
|
||||
MallProductCategoryDO dbProductCategory = randomPojo(MallProductCategoryDO.class, o -> { // 等会查询到
|
||||
o.setPid(0L);
|
||||
o.setName("彩电");
|
||||
o.setDescription("家庭电器");
|
||||
o.setPicUrl("https://127.0.0.1/file/111.jpg");
|
||||
o.setSort(0);
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCreateTime(buildTime(2022, 1, 3));
|
||||
});
|
||||
productCategoryMapper.insert(dbProductCategory);
|
||||
// 测试 pid 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setPid(2L)));
|
||||
// 测试 name 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setName("服装")));
|
||||
// 测试 status 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 准备参数
|
||||
MallProductCategoryPageReqVO reqVO = new MallProductCategoryPageReqVO();
|
||||
reqVO.setPid(0L);
|
||||
reqVO.setName("彩电");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
PageResult<MallProductCategoryDO> pageResult = productCategoryService.getProductCategoryPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbProductCategory, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetProductCategoryList() {
|
||||
// mock 数据
|
||||
MallProductCategoryDO dbProductCategory = randomPojo(MallProductCategoryDO.class, o -> { // 等会查询到
|
||||
o.setPid(0L);
|
||||
o.setName("彩电");
|
||||
o.setDescription("家庭电器");
|
||||
o.setPicUrl("https://127.0.0.1/file/111.jpg");
|
||||
o.setSort(0);
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCreateTime(buildTime(2022, 1, 3));
|
||||
});
|
||||
productCategoryMapper.insert(dbProductCategory);
|
||||
// 测试 pid 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setPid(2L)));
|
||||
// 测试 name 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setName("服装")));
|
||||
// 测试 status 不匹配
|
||||
productCategoryMapper.insert(cloneIgnoreId(dbProductCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 准备参数
|
||||
MallProductCategoryExportReqVO reqVO = new MallProductCategoryExportReqVO();
|
||||
reqVO.setPid(0L);
|
||||
reqVO.setName("彩电");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
List<MallProductCategoryDO> list = productCategoryService.getProductCategoryList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbProductCategory, list.get(0));
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,7 @@ DELETE FROM pay_refund;
|
|||
DELETE FROM mall_product_attr_key;
|
||||
DELETE FROM mall_product_attr_value;
|
||||
DELETE FROM mall_product_brand;
|
||||
DELETE FROM mall_product_category;
|
||||
|
||||
-- bpm 开头的 DB
|
||||
DELETE FROM "bpm_form";
|
||||
|
|
|
@ -668,3 +668,19 @@ CREATE TABLE `mall_product_brand`
|
|||
PRIMARY KEY (`id`)
|
||||
) COMMENT = '商品品牌';
|
||||
|
||||
CREATE TABLE `mall_product_category`
|
||||
(
|
||||
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
`pid` bigint(20) NOT NULL,
|
||||
`name` varchar(16) NOT NULL DEFAULT '',
|
||||
`description` varchar(250) DEFAULT NULL,
|
||||
`pic_url` varchar(1024) DEFAULT NULL,
|
||||
`sort` int(11) NOT NULL,
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`creator` varchar(64) DEFAULT '',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updater` varchar(64) DEFAULT '',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted` bit(1) NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (`id`)
|
||||
) COMMENT = '商品分类表'
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 创建商品分类
|
||||
export function createProductCategory(data) {
|
||||
return request({
|
||||
url: '/mall/product-category/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新商品分类
|
||||
export function updateProductCategory(data) {
|
||||
return request({
|
||||
url: '/mall/product-category/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新商品分类状态
|
||||
export function updateProductCategoryStatus(id, status) {
|
||||
const data = {
|
||||
id,
|
||||
status
|
||||
}
|
||||
return request({
|
||||
url: '/mall/product-category/update-status',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除商品分类
|
||||
export function deleteProductCategory(id) {
|
||||
return request({
|
||||
url: '/mall/product-category/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品分类
|
||||
export function getProductCategory(id) {
|
||||
return request({
|
||||
url: '/mall/product-category/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品顶级分类
|
||||
export function getProductRootCategory() {
|
||||
return request({
|
||||
url: '/mall/product-category/get-roots',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 获得商品分类分页
|
||||
export function getProductCategoryPage(query) {
|
||||
return request({
|
||||
url: '/mall/product-category/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出商品分类 Excel
|
||||
export function exportProductCategoryExcel(query) {
|
||||
return request({
|
||||
url: '/mall/product-category/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
|
@ -42,7 +42,7 @@
|
|||
<el-table-column label="品牌名图片" align="center" prop="picUrl">
|
||||
<template slot-scope="scope">
|
||||
<el-image style="width: 100px; height: 100px"
|
||||
:src="scope.row.picUrl" :fit="fill" :preview-src-list="imageList">
|
||||
:src="scope.row.picUrl" fit="fit" :preview-src-list="imageList">
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
|
|
@ -0,0 +1,401 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
|
||||
<el-form-item label="父类目名称" prop="pid">
|
||||
<el-select v-model="queryParams.pid" filterable placeholder="请选择" clearable>
|
||||
<el-option v-for="item in rootCategories" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入分类名称" clearable size="small"
|
||||
@keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
|
||||
<el-option v-for="dict in commonStatusDatum" :key="parseInt(dict.value)" :label="dict.label"
|
||||
:value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['mall:product-category:create']">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
|
||||
v-hasPermi="['mall:product-category:export']">导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id" width="90"/>
|
||||
<el-table-column label="名称" align="center" prop="name" width="360px"/>
|
||||
<el-table-column label="图片" align="center" prop="picUrl" width="100px">
|
||||
<template slot-scope="scope">
|
||||
<el-image style="width: 80px; height: 80px"
|
||||
:src="scope.row.picUrl" fit="fit" :preview-src-list="imageList">
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" align="center" prop="description" width="150" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1"
|
||||
@change="handleStatusChange(scope.row)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" align="center" prop="sort"/>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" :disabled="scope.row.pid !== 0"
|
||||
@click="handleChildQuery(scope.row)" v-hasPermi="['mall:product-category:query']">查看下级
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['mall:product-category:update']">修改
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mall:product-category:delete']">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="分类栏目" prop="pid">
|
||||
<el-select v-model="form.pid" filterable placeholder="请选择" clearable>
|
||||
<el-option :value="parseInt(0)" label="顶级栏目"></el-option>
|
||||
<el-option v-for="item in rootCategories" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入分类名称"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" prop="picUrl">
|
||||
<el-upload ref="upload" action="#"
|
||||
list-type="picture-card" :limit="1" :file-list="uploadList"
|
||||
:before-upload="handleBeforeUpload" :http-request="handleUpload"
|
||||
:on-exceed="handleExceed" :on-preview="handlePictureCardPreview">
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="form.sort" placeholder="请输入分类排序"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in commonStatusDatum" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}" v-model="form.description"
|
||||
placeholder="请输入品牌描述"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createProductCategory,
|
||||
updateProductCategory,
|
||||
updateProductCategoryStatus,
|
||||
deleteProductCategory,
|
||||
getProductCategory,
|
||||
getProductRootCategory,
|
||||
getProductCategoryPage,
|
||||
exportProductCategoryExcel
|
||||
} from "@/api/mall/product/category";
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import {uploadFile} from "@/api/infra/file";
|
||||
import {SysCommonStatusEnum} from "@/utils/constants";
|
||||
|
||||
const defaultForm = {
|
||||
id: null,
|
||||
pid: null,
|
||||
name: '',
|
||||
description: '',
|
||||
picUrl: '',
|
||||
sort: null,
|
||||
status: null,
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "ProductCategory",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 商品分类列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
dateRangeCreateTime: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
pid: null,
|
||||
name: null,
|
||||
description: null,
|
||||
picUrl: null,
|
||||
sort: null,
|
||||
status: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: JSON.parse(JSON.stringify(defaultForm)),
|
||||
// 表单校验
|
||||
rules: {
|
||||
pid: [{required: true, message: "父分类编号不能为空", trigger: "blur"}],
|
||||
name: [{required: true, message: "分类名称不能为空", trigger: "blur"}],
|
||||
sort: [{required: true, message: "分类排序不能为空", trigger: "blur"}],
|
||||
status: [{required: true, message: "状态不能为空", trigger: "blur"}],
|
||||
},
|
||||
// 跟类目分类列表
|
||||
rootCategories: [],
|
||||
// 图片列表
|
||||
imageList: [],
|
||||
// 通用状态
|
||||
commonStatusDatum: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
|
||||
// 表单loading
|
||||
formLoading: false,
|
||||
// 表单loading 文本
|
||||
formLoadingText: '',
|
||||
// 预览图片状态
|
||||
pictureCardPreviewOpen: false,
|
||||
// 预览图片URL
|
||||
pictureCardPreviewUrl: '',
|
||||
// 上传文件列表
|
||||
uploadList: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getCategoryRoots();
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
// 执行查询
|
||||
getProductCategoryPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.imageList = [];
|
||||
response.data.list.forEach(o => this.imageList.push(o.picUrl));
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = JSON.parse(JSON.stringify(defaultForm));
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加商品分类";
|
||||
if (this.queryParams.pid !== null) {
|
||||
this.form.pid = this.queryParams.pid;
|
||||
}
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
getProductCategory(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.uploadList = [{
|
||||
name: response.data.picUrl,
|
||||
url: response.data.picUrl
|
||||
}];
|
||||
this.open = true;
|
||||
this.title = "修改商品分类";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateProductCategory(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.form = JSON.parse(JSON.stringify(defaultForm));
|
||||
this.getList();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createProductCategory(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.form = JSON.parse(JSON.stringify(defaultForm));
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id;
|
||||
this.$confirm('是否确认删除商品分类编号为"' + id + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function () {
|
||||
return deleteProductCategory(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
params.pageNo = undefined;
|
||||
params.pageSize = undefined;
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
// 执行导出
|
||||
this.$confirm('是否确认导出所有商品分类数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function () {
|
||||
return exportProductCategoryExcel(params);
|
||||
}).then(response => {
|
||||
this.downloadExcel(response, '商品分类.xls');
|
||||
})
|
||||
},
|
||||
/** 获取顶级分类列表 */
|
||||
getCategoryRoots() {
|
||||
getProductRootCategory().then(res => {
|
||||
this.rootCategories = res.data;
|
||||
})
|
||||
},
|
||||
/** 执行修改状态 */
|
||||
handleStatusChange(row) {
|
||||
let text = row.status === SysCommonStatusEnum.ENABLE ? "启用" : "停用";
|
||||
// '确认要"' + text + '""' + row.name + '"当前商品品牌吗?'
|
||||
this.$confirm(`确定要[${text}] "${row.name}"当商品分类吗?`, "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return updateProductCategoryStatus(row.id, row.status);
|
||||
}).then(() => {
|
||||
this.msgSuccess(text + "成功");
|
||||
}).catch(function() {
|
||||
row.status = row.status === SysCommonStatusEnum.ENABLE ? SysCommonStatusEnum.DISABLE
|
||||
: SysCommonStatusEnum.ENABLE;
|
||||
});
|
||||
},
|
||||
/** 执行子类目搜索 */
|
||||
handleChildQuery(row) {
|
||||
this.queryParams.pid = row.id;
|
||||
this.queryParams.name = '';
|
||||
this.queryParams.status = null;
|
||||
this.getList();
|
||||
},
|
||||
/**图片超出限制*/
|
||||
handleExceed() {
|
||||
this.$message.warning("图片选择已达上限,请删除后重新选择");
|
||||
},
|
||||
/**图片上传之前的逻辑处理*/
|
||||
handleBeforeUpload(file) {
|
||||
if (file.type.indexOf("image/") === -1) {
|
||||
this.$message.error("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
|
||||
} else {
|
||||
this.formLoading = true;
|
||||
this.formLoadingText = "图片上传中。。。";
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
this.form.picUrl = reader.result;
|
||||
};
|
||||
}
|
||||
},
|
||||
/**重新图片上传逻辑*/
|
||||
handleUpload(file) {
|
||||
let formData = new FormData();
|
||||
let path = new Date().getTime() + file.file.name.substring(file.file.name.lastIndexOf("."));
|
||||
formData.append("file", file.file);
|
||||
formData.append("path", path)
|
||||
uploadFile(formData).then(res => {
|
||||
this.form.picUrl = res.data;
|
||||
this.$message.success("图片上传成功");
|
||||
this.formLoading = false;
|
||||
}).catch(error => {
|
||||
this.formLoading = true;
|
||||
this.$message.error(error.msg());
|
||||
})
|
||||
},
|
||||
/**图片预览*/
|
||||
handlePictureCardPreview(file) {
|
||||
this.pictureCardPreviewUrl = file.url;
|
||||
this.pictureCardPreviewOpen = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Reference in New Issue