Pārlūkot izejas kodu

品牌代码生成

JeromeSoar 3 gadi atpakaļ
vecāks
revīzija
cc6c3d2759
21 mainītis faili ar 1147 papildinājumiem un 8 dzēšanām
  1. 33 1
      sql/mall.sql
  2. 3 0
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
  3. 100 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/BrandController.java
  4. 37 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandBaseVO.java
  5. 14 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandCreateReqVO.java
  6. 45 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandExcelVO.java
  7. 32 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandExportReqVO.java
  8. 34 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandPageReqVO.java
  9. 19 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandRespVO.java
  10. 18 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandUpdateReqVO.java
  11. 34 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/BrandConvert.java
  12. 55 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/BrandDO.java
  13. 6 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/CategoryDO.java
  14. 38 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/BrandMapper.java
  15. 70 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/BrandService.java
  16. 82 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/BrandServiceImpl.java
  17. 175 0
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/BrandServiceImplTest.java
  18. 3 1
      yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql
  19. 18 1
      yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql
  20. 54 0
      yudao-ui-admin/src/api/mall/product/brand.js
  21. 277 0
      yudao-ui-admin/src/views/mall/product/brand/index.vue

+ 33 - 1
sql/mall.sql

@@ -40,10 +40,32 @@ CREATE TABLE `product_category`
     PRIMARY KEY (`id`) USING BTREE
 ) ENGINE=InnoDB COMMENT='商品分类';
 
+-- ----------------------------
+-- Table structure for product_brand
+-- ----------------------------
+DROP TABLE IF EXISTS `product_brand`;
+CREATE TABLE `product_brand`
+(
+    `id`          bigint       NOT NULL AUTO_INCREMENT COMMENT '品牌编号',
+    `category_id` bigint       NOT NULL COMMENT '分类编号',
+    `name`        varchar(255) NOT NULL COMMENT '品牌名称',
+    `banner_url`  varchar(255) NOT NULL COMMENT '品牌图片',
+    `sort`        int                   DEFAULT '0' COMMENT '品牌排序',
+    `description` varchar(1024)         DEFAULT NULL COMMENT '品牌描述',
+    `status`      tinyint      NOT NULL COMMENT '状态',
+    `creator`     varchar(64)           DEFAULT '' COMMENT '创建者',
+    `create_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `updater`     varchar(64)           DEFAULT '' COMMENT '更新者',
+    `update_time` datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    `deleted`     bit(1)       NOT NULL DEFAULT b'0' COMMENT '是否删除',
+    `tenant_id`   bigint       NOT NULL DEFAULT '0' COMMENT '租户编号',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB COMMENT='品牌';
+
 -- TODO 父级菜单的 id 处理
 INSERT INTO `system_menu` (`id`, `name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES (2000, '商城', '', 1, 1, 0, '/mall', 'merchant', NULL, 0);
 INSERT INTO `system_menu` (`id`, `name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES (2001, '商品管理', '', 1, 1, 2000, 'product', 'dict', NULL, 0);
--- 菜单 SQL
+-- 商品分类 菜单 SQL
 INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('商品分类管理', '', 2, 0, 2001, 'category', '', 'mall/product/category/index', 0);
 -- 按钮父菜单ID
 SELECT @parentId := LAST_INSERT_ID();
@@ -53,3 +75,13 @@ INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`
 INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('商品分类更新', 'product:category:update', 3, 3, @parentId, '', '', '', 0);
 INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('商品分类删除', 'product:category:delete', 3, 4, @parentId, '', '', '', 0);
 INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('商品分类导出', 'product:category:export', 3, 5, @parentId, '', '', '', 0);
+-- 品牌管理 菜单 SQL
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌管理', '', 2, 0, 2001, 'brand', '', 'mall/product/brand/index', 0);
+-- 按钮父菜单ID
+SELECT @parentId := LAST_INSERT_ID();
+-- 按钮 SQL
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌查询', 'product:brand:query', 3, 1, @parentId, '', '', '', 0);
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌创建', 'product:brand:create', 3, 2, @parentId, '', '', '', 0);
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌更新', 'product:brand:update', 3, 3, @parentId, '', '', '', 0);
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌删除', 'product:brand:delete', 3, 4, @parentId, '', '', '', 0);
+INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌导出', 'product:brand:export', 3, 5, @parentId, '', '', '', 0);

+ 3 - 0
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java

@@ -11,4 +11,7 @@ public interface ErrorCodeConstants {
 
     // ========== 商品分类相关  1008001000============
     ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");
+
+    // ========== 品牌相关编号 1008002000 ==========
+    ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
 }

+ 100 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/BrandController.java

@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.annotations.*;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+import cn.iocoder.yudao.module.product.convert.brand.BrandConvert;
+import cn.iocoder.yudao.module.product.service.brand.BrandService;
+
+@Api(tags = "管理后台 - 品牌")
+@RestController
+@RequestMapping("/product/brand")
+@Validated
+public class BrandController {
+
+    @Resource
+    private BrandService brandService;
+
+    @PostMapping("/create")
+    @ApiOperation("创建品牌")
+    @PreAuthorize("@ss.hasPermission('product:brand:create')")
+    public CommonResult<Long> createBrand(@Valid @RequestBody BrandCreateReqVO createReqVO) {
+        return success(brandService.createBrand(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新品牌")
+    @PreAuthorize("@ss.hasPermission('product:brand:update')")
+    public CommonResult<Boolean> updateBrand(@Valid @RequestBody BrandUpdateReqVO updateReqVO) {
+        brandService.updateBrand(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除品牌")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('product:brand:delete')")
+    public CommonResult<Boolean> deleteBrand(@RequestParam("id") Long id) {
+        brandService.deleteBrand(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @ApiOperation("获得品牌")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('product:brand:query')")
+    public CommonResult<BrandRespVO> getBrand(@RequestParam("id") Long id) {
+        BrandDO brand = brandService.getBrand(id);
+        return success(BrandConvert.INSTANCE.convert(brand));
+    }
+
+    @GetMapping("/list")
+    @ApiOperation("获得品牌列表")
+    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
+    @PreAuthorize("@ss.hasPermission('product:brand:query')")
+    public CommonResult<List<BrandRespVO>> getBrandList(@RequestParam("ids") Collection<Long> ids) {
+        List<BrandDO> list = brandService.getBrandList(ids);
+        return success(BrandConvert.INSTANCE.convertList(list));
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("获得品牌分页")
+    @PreAuthorize("@ss.hasPermission('product:brand:query')")
+    public CommonResult<PageResult<BrandRespVO>> getBrandPage(@Valid BrandPageReqVO pageVO) {
+        PageResult<BrandDO> pageResult = brandService.getBrandPage(pageVO);
+        return success(BrandConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/export-excel")
+    @ApiOperation("导出品牌 Excel")
+    @PreAuthorize("@ss.hasPermission('product:brand:export')")
+    @OperateLog(type = EXPORT)
+    public void exportBrandExcel(@Valid BrandExportReqVO exportReqVO,
+              HttpServletResponse response) throws IOException {
+        List<BrandDO> list = brandService.getBrandList(exportReqVO);
+        // 导出 Excel
+        List<BrandExcelVO> datas = BrandConvert.INSTANCE.convertList02(list);
+        ExcelUtils.write(response, "品牌.xls", "数据", BrandExcelVO.class, datas);
+    }
+
+}

+ 37 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandBaseVO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+/**
+* 品牌 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class BrandBaseVO {
+
+    @ApiModelProperty(value = "分类编号", required = true, example = "1")
+    @NotNull(message = "分类编号不能为空")
+    private Long categoryId;
+
+    @ApiModelProperty(value = "品牌名称", required = true, example = "芋道")
+    @NotNull(message = "品牌名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "品牌图片", required = true)
+    @NotNull(message = "品牌图片不能为空")
+    private String bannerUrl;
+
+    @ApiModelProperty(value = "品牌排序", example = "1")
+    private Integer sort;
+
+    @ApiModelProperty(value = "品牌描述", example = "描述")
+    private String description;
+
+    @ApiModelProperty(value = "状态", required = true, example = "0")
+    @NotNull(message = "状态不能为空")
+    private Integer status;
+
+}

+ 14 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 品牌创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrandCreateReqVO extends BrandBaseVO {
+
+}

+ 45 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandExcelVO.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+
+
+/**
+ * 品牌 Excel VO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class BrandExcelVO {
+
+    @ExcelProperty("品牌编号")
+    private Long id;
+
+    @ExcelProperty("分类编号")
+    private Long categoryId;
+
+    @ExcelProperty("品牌名称")
+    private String name;
+
+    @ExcelProperty("品牌图片")
+    private String bannerUrl;
+
+    @ExcelProperty("品牌排序")
+    private Integer sort;
+
+    @ExcelProperty("品牌描述")
+    private String description;
+
+    @ExcelProperty(value = "状态", converter = DictConvert.class)
+    @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
+    private Integer status;
+
+    @ExcelProperty("创建时间")
+    private Date createTime;
+
+}

+ 32 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandExportReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel(value = "管理后台 - 品牌 Excel 导出 Request VO", description = "参数和 BrandPageReqVO 是一致的")
+@Data
+public class BrandExportReqVO {
+
+    @ApiModelProperty(value = "分类编号", example = "1")
+    private Long categoryId;
+
+    @ApiModelProperty(value = "品牌名称", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "状态", example = "0")
+    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;
+
+}

+ 34 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandPageReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 品牌分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrandPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "分类编号", example = "1")
+    private Long categoryId;
+
+    @ApiModelProperty(value = "品牌名称", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "状态", example = "0")
+    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;
+
+}

+ 19 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandRespVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+@ApiModel("管理后台 - 品牌 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrandRespVO extends BrandBaseVO {
+
+    @ApiModelProperty(value = "品牌编号", required = true, example = "1")
+    private Long id;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+}

+ 18 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/BrandUpdateReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 品牌更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrandUpdateReqVO extends BrandBaseVO {
+
+    @ApiModelProperty(value = "品牌编号", required = true, example = "1")
+    @NotNull(message = "品牌编号不能为空")
+    private Long id;
+
+}

+ 34 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/BrandConvert.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.product.convert.brand;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+
+/**
+ * 品牌 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BrandConvert {
+
+    BrandConvert INSTANCE = Mappers.getMapper(BrandConvert.class);
+
+    BrandDO convert(BrandCreateReqVO bean);
+
+    BrandDO convert(BrandUpdateReqVO bean);
+
+    BrandRespVO convert(BrandDO bean);
+
+    List<BrandRespVO> convertList(List<BrandDO> list);
+
+    PageResult<BrandRespVO> convertPage(PageResult<BrandDO> page);
+
+    List<BrandExcelVO> convertList02(List<BrandDO> list);
+
+}

+ 55 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/BrandDO.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.product.dal.dataobject.brand;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+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 芋道源码
+ */
+@TableName("product_brand")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BrandDO extends BaseDO {
+
+    /**
+     * 品牌编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 分类编号
+     */
+    private Long categoryId;
+    /**
+     * 品牌名称
+     */
+    private String name;
+    /**
+     * 品牌图片
+     */
+    private String bannerUrl;
+    /**
+     * 品牌排序
+     */
+    private Integer sort;
+    /**
+     * 品牌描述
+     */
+    private String description;
+    /**
+     * 状态
+     * <p>
+     * 枚举 {@link CommonStatusEnum}
+     */
+    private Integer status;
+
+}

+ 6 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/CategoryDO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.product.dal.dataobject.category;
 
-import lombok.*;
-import java.util.*;
-import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
 
 /**
  * 商品分类 DO
@@ -50,8 +51,8 @@ public class CategoryDO extends BaseDO {
     private String description;
     /**
      * 开启状态
-     *
-     * 枚举 {@link TODO common_status 对应的类}
+     * <p>
+     * 枚举 {@link CommonStatusEnum}
      */
     private Integer status;
 

+ 38 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/BrandMapper.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.product.dal.mysql.brand;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+
+/**
+ * 品牌 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BrandMapper extends BaseMapperX<BrandDO> {
+
+    default PageResult<BrandDO> selectPage(BrandPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<BrandDO>()
+                .eqIfPresent(BrandDO::getCategoryId, reqVO.getCategoryId())
+                .likeIfPresent(BrandDO::getName, reqVO.getName())
+                .eqIfPresent(BrandDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(BrandDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(BrandDO::getId));
+    }
+
+    default List<BrandDO> selectList(BrandExportReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<BrandDO>()
+                .eqIfPresent(BrandDO::getCategoryId, reqVO.getCategoryId())
+                .likeIfPresent(BrandDO::getName, reqVO.getName())
+                .eqIfPresent(BrandDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(BrandDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(BrandDO::getId));
+    }
+
+}

+ 70 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/BrandService.java

@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.product.service.brand;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+/**
+ * 品牌 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface BrandService {
+
+    /**
+     * 创建品牌
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createBrand(@Valid BrandCreateReqVO createReqVO);
+
+    /**
+     * 更新品牌
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateBrand(@Valid BrandUpdateReqVO updateReqVO);
+
+    /**
+     * 删除品牌
+     *
+     * @param id 编号
+     */
+    void deleteBrand(Long id);
+
+    /**
+     * 获得品牌
+     *
+     * @param id 编号
+     * @return 品牌
+     */
+    BrandDO getBrand(Long id);
+
+    /**
+     * 获得品牌列表
+     *
+     * @param ids 编号
+     * @return 品牌列表
+     */
+    List<BrandDO> getBrandList(Collection<Long> ids);
+
+    /**
+     * 获得品牌分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 品牌分页
+     */
+    PageResult<BrandDO> getBrandPage(BrandPageReqVO pageReqVO);
+
+    /**
+     * 获得品牌列表, 用于 Excel 导出
+     *
+     * @param exportReqVO 查询条件
+     * @return 品牌列表
+     */
+    List<BrandDO> getBrandList(BrandExportReqVO exportReqVO);
+
+}

+ 82 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/BrandServiceImpl.java

@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.product.service.brand;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.*;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import cn.iocoder.yudao.module.product.convert.brand.BrandConvert;
+import cn.iocoder.yudao.module.product.dal.mysql.brand.BrandMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
+
+/**
+ * 品牌 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class BrandServiceImpl implements BrandService {
+
+    @Resource
+    private BrandMapper brandMapper;
+
+    @Override
+    public Long createBrand(BrandCreateReqVO createReqVO) {
+        // 插入
+        BrandDO brand = BrandConvert.INSTANCE.convert(createReqVO);
+        brandMapper.insert(brand);
+        // 返回
+        return brand.getId();
+    }
+
+    @Override
+    public void updateBrand(BrandUpdateReqVO updateReqVO) {
+        // 校验存在
+        this.validateBrandExists(updateReqVO.getId());
+        // 更新
+        BrandDO updateObj = BrandConvert.INSTANCE.convert(updateReqVO);
+        brandMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteBrand(Long id) {
+        // 校验存在
+        this.validateBrandExists(id);
+        // 删除
+        brandMapper.deleteById(id);
+    }
+
+    private void validateBrandExists(Long id) {
+        if (brandMapper.selectById(id) == null) {
+            throw exception(BRAND_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public BrandDO getBrand(Long id) {
+        return brandMapper.selectById(id);
+    }
+
+    @Override
+    public List<BrandDO> getBrandList(Collection<Long> ids) {
+        return brandMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public PageResult<BrandDO> getBrandPage(BrandPageReqVO pageReqVO) {
+        return brandMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<BrandDO> getBrandList(BrandExportReqVO exportReqVO) {
+        return brandMapper.selectList(exportReqVO);
+    }
+
+}

+ 175 - 0
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/BrandServiceImplTest.java

@@ -0,0 +1,175 @@
+package cn.iocoder.yudao.module.product.service.brand;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.BrandDO;
+import cn.iocoder.yudao.module.product.dal.mysql.brand.BrandMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+* {@link BrandServiceImpl} 的单元测试类
+*
+* @author 芋道源码
+*/
+@Import(BrandServiceImpl.class)
+public class BrandServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private BrandServiceImpl brandService;
+
+    @Resource
+    private BrandMapper brandMapper;
+
+    @Test
+    public void testCreateBrand_success() {
+        // 准备参数
+        BrandCreateReqVO reqVO = randomPojo(BrandCreateReqVO.class);
+
+        // 调用
+        Long brandId = brandService.createBrand(reqVO);
+        // 断言
+        assertNotNull(brandId);
+        // 校验记录的属性是否正确
+        BrandDO brand = brandMapper.selectById(brandId);
+        assertPojoEquals(reqVO, brand);
+    }
+
+    @Test
+    public void testUpdateBrand_success() {
+        // mock 数据
+        BrandDO dbBrand = randomPojo(BrandDO.class);
+        brandMapper.insert(dbBrand);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        BrandUpdateReqVO reqVO = randomPojo(BrandUpdateReqVO.class, o -> {
+            o.setId(dbBrand.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        brandService.updateBrand(reqVO);
+        // 校验是否更新正确
+        BrandDO brand = brandMapper.selectById(reqVO.getId()); // 获取最新的
+        assertPojoEquals(reqVO, brand);
+    }
+
+    @Test
+    public void testUpdateBrand_notExists() {
+        // 准备参数
+        BrandUpdateReqVO reqVO = randomPojo(BrandUpdateReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> brandService.updateBrand(reqVO), BRAND_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteBrand_success() {
+        // mock 数据
+        BrandDO dbBrand = randomPojo(BrandDO.class);
+        brandMapper.insert(dbBrand);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbBrand.getId();
+
+        // 调用
+        brandService.deleteBrand(id);
+       // 校验数据不存在了
+       assertNull(brandMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteBrand_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> brandService.deleteBrand(id), BRAND_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetBrandPage() {
+       // mock 数据
+       BrandDO dbBrand = randomPojo(BrandDO.class, o -> { // 等会查询到
+           o.setCategoryId(null);
+           o.setName(null);
+           o.setStatus(null);
+           o.setCreateTime(null);
+       });
+       brandMapper.insert(dbBrand);
+       // 测试 categoryId 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCategoryId(null)));
+       // 测试 name 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setName(null)));
+       // 测试 status 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setStatus(null)));
+       // 测试 createTime 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCreateTime(null)));
+       // 准备参数
+       BrandPageReqVO reqVO = new BrandPageReqVO();
+       reqVO.setCategoryId(null);
+       reqVO.setName(null);
+       reqVO.setStatus(null);
+       reqVO.setBeginCreateTime(null);
+       reqVO.setEndCreateTime(null);
+
+       // 调用
+       PageResult<BrandDO> pageResult = brandService.getBrandPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbBrand, pageResult.getList().get(0));
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetBrandList() {
+       // mock 数据
+       BrandDO dbBrand = randomPojo(BrandDO.class, o -> { // 等会查询到
+           o.setCategoryId(null);
+           o.setName(null);
+           o.setStatus(null);
+           o.setCreateTime(null);
+       });
+       brandMapper.insert(dbBrand);
+       // 测试 categoryId 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCategoryId(null)));
+       // 测试 name 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setName(null)));
+       // 测试 status 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setStatus(null)));
+       // 测试 createTime 不匹配
+       brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCreateTime(null)));
+       // 准备参数
+       BrandExportReqVO reqVO = new BrandExportReqVO();
+       reqVO.setCategoryId(null);
+       reqVO.setName(null);
+       reqVO.setStatus(null);
+       reqVO.setBeginCreateTime(null);
+       reqVO.setEndCreateTime(null);
+
+       // 调用
+       List<BrandDO> list = brandService.getBrandList(reqVO);
+       // 断言
+       assertEquals(1, list.size());
+       assertPojoEquals(dbBrand, list.get(0));
+    }
+
+}

+ 3 - 1
yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql

@@ -1 +1,3 @@
-DELETE FROM "product_category";
+DELETE FROM "product_category";
+
+DELETE FROM "product_brand";

+ 18 - 1
yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql

@@ -14,4 +14,21 @@ CREATE TABLE IF NOT EXISTS "product_category" (
     "deleted" bit NOT NULL DEFAULT FALSE,
     "tenant_id" bigint(20) NOT NULL,
     PRIMARY KEY ("id")
-) COMMENT '商品分类';
+) COMMENT '商品分类';
+
+CREATE TABLE IF NOT EXISTS "product_brand" (
+    "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "category_id" bigint(20) NOT NULL,
+    "name" varchar(255) NOT NULL,
+    "banner_url" varchar(255) NOT NULL,
+    "sort" int(11),
+    "description" varchar(1024),
+    "status" tinyint(4) NOT NULL,
+    "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 NOT NULL DEFAULT FALSE,
+    "tenant_id" bigint(20) NOT NULL,
+    PRIMARY KEY ("id")
+) COMMENT '品牌';

+ 54 - 0
yudao-ui-admin/src/api/mall/product/brand.js

@@ -0,0 +1,54 @@
+import request from '@/utils/request'
+
+// 创建品牌
+export function createBrand(data) {
+  return request({
+    url: '/product/brand/create',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新品牌
+export function updateBrand(data) {
+  return request({
+    url: '/product/brand/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除品牌
+export function deleteBrand(id) {
+  return request({
+    url: '/product/brand/delete?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 获得品牌
+export function getBrand(id) {
+  return request({
+    url: '/product/brand/get?id=' + id,
+    method: 'get'
+  })
+}
+
+// 获得品牌分页
+export function getBrandPage(query) {
+  return request({
+    url: '/product/brand/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出品牌 Excel
+export function exportBrandExcel(query) {
+  return request({
+    url: '/product/brand/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}

+ 277 - 0
yudao-ui-admin/src/views/mall/product/brand/index.vue

@@ -0,0 +1,277 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="分类编号" prop="categoryId">
+        <el-input v-model="queryParams.categoryId" placeholder="请输入分类编号" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="品牌名称" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入品牌名称" clearable @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 this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @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="['product:brand:create']">新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
+                   :loading="exportLoading"
+                   v-hasPermi="['product:brand: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"/>
+      <el-table-column label="分类编号" align="center" prop="categoryId"/>
+      <el-table-column label="品牌名称" align="center" prop="name"/>
+      <el-table-column label="品牌图片" align="center" prop="bannerUrl"/>
+      <el-table-column label="品牌排序" align="center" prop="sort"/>
+      <el-table-column label="品牌描述" align="center" prop="description"/>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <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-edit" @click="handleUpdate(scope.row)"
+                     v-hasPermi="['product:brand:update']">修改
+          </el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                     v-hasPermi="['product:brand: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="categoryId">
+          <el-input v-model="form.categoryId" placeholder="请输入分类编号"/>
+        </el-form-item>
+        <el-form-item label="品牌名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入品牌名称"/>
+        </el-form-item>
+        <el-form-item label="品牌图片">
+          <imageUpload v-model="form.bannerUrl" :limit="1"/>
+        </el-form-item>
+        <el-form-item label="品牌排序" prop="sort">
+          <el-input v-model="form.sort" placeholder="请输入品牌排序"/>
+        </el-form-item>
+        <el-form-item label="品牌描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入内容"/>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态">
+            <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
+                       :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
+          </el-select>
+        </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 {
+  createBrand,
+  deleteBrand,
+  exportBrandExcel,
+  getBrand,
+  getBrandPage,
+  updateBrand
+} from "@/api/mall/product/brand";
+import ImageUpload from '@/components/ImageUpload';
+
+export default {
+  name: "Brand",
+  components: {
+    ImageUpload,
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 品牌列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      dateRangeCreateTime: [],
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        categoryId: null,
+        name: null,
+        status: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        categoryId: [{required: true, message: "分类编号不能为空", trigger: "blur"}],
+        name: [{required: true, message: "品牌名称不能为空", trigger: "blur"}],
+        bannerUrl: [{required: true, message: "品牌图片不能为空", trigger: "blur"}],
+        status: [{required: true, message: "状态不能为空", trigger: "change"}],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      getBrandPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        categoryId: undefined,
+        name: undefined,
+        bannerUrl: undefined,
+        sort: undefined,
+        description: undefined,
+        status: undefined,
+      };
+      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 = "添加品牌";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getBrand(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改品牌";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateBrand(this.form).then(response => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createBrand(this.form).then(response => {
+          this.$modal.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal.confirm('是否确认删除品牌编号为"' + id + '"的数据项?').then(function () {
+        return deleteBrand(id);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      // 处理查询参数
+      let params = {...this.queryParams};
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行导出
+      this.$modal.confirm('是否确认导出所有品牌数据项?').then(() => {
+        this.exportLoading = true;
+        return exportBrandExcel(params);
+      }).then(response => {
+        this.$download.excel(response, "品牌.xls");
+        this.exportLoading = false;
+      }).catch(() => {
+      });
+    }
+  }
+};
+</script>