master:系统商品分类功能完善;

pull/1121/head
liujiang 2025-04-13 15:54:11 +08:00
parent 50c97f9b0e
commit 5d7af38398
15 changed files with 622 additions and 10 deletions

View File

@ -43,7 +43,7 @@ import java.util.List;
* @author ruoyi
*/
@RequiredArgsConstructor
@Api(tags = "字典数据明细")
@Api(tags = "系统基础数据 - 字典数据明细")
@RestController
@RequestMapping("/system/dict/data")
public class SysDictDataController extends BaseController {

View File

@ -35,7 +35,7 @@ import java.util.Optional;
*
* @author ruoyi
*/
@Api(tags = "字典类型")
@Api(tags = "系统基础数据 - 字典类型")
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/dict/type")

View File

@ -0,0 +1,91 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.vo.productCategory.ProdCateListVO;
import com.ruoyi.common.core.domain.vo.productCategory.ProdCateVO;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListResDTO;
import com.ruoyi.system.service.ISysProductCategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
*
*
* @author ruoyi
*/
@Api(tags = "系统基础数据 - 商品分类")
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/prod-cate")
public class SysProductCategoryController extends XktBaseController {
final ISysProductCategoryService prodCateService;
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:category:add')")
@ApiOperation(value = "新增商品分类", httpMethod = "POST", response = R.class)
@Log(title = "新增商品分类", businessType = BusinessType.INSERT)
@PostMapping
public R<Integer> create(@Validated @RequestBody ProdCateVO prodCateVO) {
return R.ok(prodCateService.create(BeanUtil.toBean(prodCateVO, ProdCateDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:category:edit')")
@ApiOperation(value = "修改商品分类", httpMethod = "PUT", response = R.class)
@Log(title = "修改商品分类", businessType = BusinessType.UPDATE)
@PutMapping
public R<Integer> update(@Validated @RequestBody ProdCateVO prodCateVO) {
return R.ok(prodCateService.update(BeanUtil.toBean(prodCateVO, ProdCateDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:category:remove')")
@ApiOperation(value = "删除商品分类", httpMethod = "DELETE", response = R.class)
@Log(title = "删除商品分类", businessType = BusinessType.DELETE)
@DeleteMapping("/{prodCateId}")
public R<Integer> delete(@PathVariable Long prodCateId) {
return R.ok(prodCateService.delete(prodCateId));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:category:query')")
@ApiOperation(value = "查询商品分类详细", httpMethod = "GET", response = R.class)
@GetMapping(value = "/{prodCateId}")
public R<ProdCateVO> getInfo(@PathVariable Long prodCateId) {
return R.ok(BeanUtil.toBean(prodCateService.selectById(prodCateId), ProdCateVO.class));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:category:list')")
@ApiOperation(value = "获取商品分类列表", httpMethod = "POST", response = R.class)
@PostMapping("/list")
public R<List<ProdCateListResDTO>> list(@RequestBody ProdCateListVO listVO) {
return R.ok(BeanUtil.copyToList(prodCateService.selectList(BeanUtil.toBean(listVO, ProdCateListDTO.class)), ProdCateListResDTO.class));
}
}

View File

@ -0,0 +1,63 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.XktBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* sys_product_category
*
* @author ruoyi
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SysProductCategory extends XktBaseEntity {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
*
*/
@Excel(name = "字典名称")
private String name;
/**
* ID
*/
private Long parentId;
/**
*
*/
private Integer orderNum;
/**
* 0 1
*/
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
private String status;
/**
*
*/
private String remark;
@Override
public String toString() {
return "SysProductCategory{" +
"id=" + id +
", name='" + name + '\'' +
", parentId=" + parentId +
", orderNum=" + orderNum +
", status='" + status + '\'' +
", remark='" + remark + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.common.core.domain.vo.productCategory;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.domain.entity.SysMenu;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类列表")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateListResVO {
@ApiModelProperty(value = "商品分类主键, 新增不传 编辑必传")
private Long prodCateId;
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "分类名称")
private Long parentId;
@ApiModelProperty(name = "显示顺序")
private Integer orderNum;
@ApiModelProperty(name = "状态")
private String status;
@ApiModelProperty(name = "备注")
private String remark;
@ApiModelProperty(name = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@ApiModelProperty(name = "子分类")
private List<ProdCateListResVO> children;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.common.core.domain.vo.productCategory;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类列表")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateListVO {
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "状态")
private String status;
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.common.core.domain.vo.productCategory;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateVO {
@ApiModelProperty(value = "商品分类主键, 新增不传 编辑必传")
private Long prodCateId;
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "分类名称")
private Long parentId;
@ApiModelProperty(name = "显示顺序")
private Integer orderNum;
@ApiModelProperty(name = "状态")
private String status;
@ApiModelProperty(name = "备注")
private String remark;
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.system.domain.dto.productCategory;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateDTO {
@ApiModelProperty(value = "商品分类主键, 新增不传 编辑必传")
private Long prodCateId;
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "分类名称")
private Long parentId;
@ApiModelProperty(name = "显示顺序")
private Integer orderNum;
@ApiModelProperty(name = "状态")
private String status;
@ApiModelProperty(name = "备注")
private String remark;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.system.domain.dto.productCategory;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类列表")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateListDTO {
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "状态")
private String status;
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.system.domain.dto.productCategory;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统商品分类列表")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProdCateListResDTO {
@ApiModelProperty(value = "商品分类主键")
@JsonProperty(value = "prodCateId")
private Long id;
@ApiModelProperty(name = "分类名称")
private String name;
@ApiModelProperty(name = "分类名称")
private Long parentId;
@ApiModelProperty(name = "显示顺序")
private Integer orderNum;
@ApiModelProperty(name = "状态")
private String status;
@ApiModelProperty(name = "备注")
private String remark;
@ApiModelProperty(name = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@ApiModelProperty(name = "子分类")
private List<ProdCateListResDTO> children;
}

View File

@ -0,0 +1,13 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.SysProductCategory;
/**
*
*
* @author ruoyi
*/
public interface SysProductCategoryMapper extends BaseMapper<SysProductCategory> {
}

View File

@ -0,0 +1,55 @@
package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.vo.productCategory.ProdCateVO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListResDTO;
import java.util.List;
/**
*
*
* @author ruoyi
*/
public interface ISysProductCategoryService {
/**
*
*
* @param cateDTO
* @return Integer
*/
Integer create(ProdCateDTO cateDTO);
/**
*
*
* @param cateDTO
* @return Integer
*/
Integer update(ProdCateDTO cateDTO);
/**
*
*
* @param prodCateId ID
* @return Integer
*/
Integer delete(Long prodCateId);
/**
*
* @param prodCateId ID
* @return ProdCateDTO
*/
ProdCateDTO selectById(Long prodCateId);
/**
*
* @param listDTO
* @return List<ProdCateListResDTO>
*/
List<ProdCateListResDTO> selectList(ProdCateListDTO listDTO);
}

View File

@ -18,11 +18,10 @@ import com.ruoyi.system.domain.dto.dictData.DictDataResDTO;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ -45,6 +44,9 @@ public class SysDictDataServiceImpl implements ISysDictDataService {
@Override
@Transactional
public Integer create(DictDataDTO dataDTO) {
if (ObjectUtils.isNotEmpty(dataDTO.getDictDataId())) {
throw new ServiceException("新增字典数据dictDataId必须为空!", HttpStatus.ERROR);
}
SysDictData dictData = BeanUtil.toBean(dataDTO, SysDictData.class);
dictData.setCreateBy(getUsername());
return this.dictDataMapper.insert(dictData);
@ -54,8 +56,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService {
@Transactional
public Integer update(DictDataDTO dataDTO) {
SysDictData dict = Optional.ofNullable(this.dictDataMapper.selectOne(new LambdaQueryWrapper<SysDictData>()
.eq(SysDictData::getId, dataDTO.getDictDataId()).eq(SysDictData::getDelFlag, Constants.UNDELETED)
.eq(SysDictData::getStatus, dataDTO.getStatus())))
.eq(SysDictData::getId, dataDTO.getDictDataId()).eq(SysDictData::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("字典数据不存在!", HttpStatus.ERROR));
dict.setUpdateBy(getUsername());
BeanUtil.copyProperties(dataDTO, dict);

View File

@ -82,6 +82,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService {
@Override
@Transactional
public Integer create(DictTypeDTO typeDTO) {
if (ObjectUtils.isNotEmpty(typeDTO.getDictId())) {
throw new ServiceException("新增字典类型dictId必须为空!", HttpStatus.ERROR);
}
// 如果字典名称已存在,则报错
if (!this.checkDictTypeUnique(typeDTO)) {
throw new ServiceException("新增字典'" + typeDTO.getDictName() + "'失败,字典类型已存在", HttpStatus.ERROR);
@ -107,8 +110,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService {
throw new ServiceException("修改字典'" + typeDTO.getDictName() + "'失败,字典类型已存在", HttpStatus.ERROR);
}
SysDictType dict = Optional.ofNullable(this.dictTypeMapper.selectOne(new LambdaQueryWrapper<SysDictType>()
.eq(SysDictType::getDictId, typeDTO.getDictId()).eq(SysDictType::getDelFlag, Constants.UNDELETED)
.eq(SysDictType::getStatus, typeDTO.getStatus())))
.eq(SysDictType::getDictId, typeDTO.getDictId()).eq(SysDictType::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("字典类型不存在!", HttpStatus.ERROR));
dict.setUpdateBy(getUsername());
BeanUtil.copyProperties(typeDTO, dict);
@ -180,8 +182,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService {
@Transactional(readOnly = true)
public DictTypeResDTO selectById(Long dictId) {
SysDictType dict = Optional.ofNullable(this.dictTypeMapper.selectOne(new LambdaQueryWrapper<SysDictType>()
.eq(SysDictType::getDictId, dictId).eq(SysDictType::getDelFlag, Constants.UNDELETED)
.eq(SysDictType::getStatus, STATUS_NORMAL)))
.eq(SysDictType::getDictId, dictId).eq(SysDictType::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("字典类型不存在!", HttpStatus.ERROR));
return BeanUtil.toBean(dict, DictTypeResDTO.class);
}

View File

@ -0,0 +1,193 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysProductCategory;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListDTO;
import com.ruoyi.system.domain.dto.productCategory.ProdCateListResDTO;
import com.ruoyi.system.mapper.SysProductCategoryMapper;
import com.ruoyi.system.service.ISysProductCategoryService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.ruoyi.common.utils.SecurityUtils.getUsername;
/**
*
*
* @author ruoyi
*/
@Service
@RequiredArgsConstructor
public class SysProductCategoryServiceImpl implements ISysProductCategoryService {
final SysProductCategoryMapper prodCateMapper;
/**
*
*
* @param cateDTO
* @return Integer
*/
@Override
@Transactional
public Integer create(ProdCateDTO cateDTO) {
if (ObjectUtils.isNotEmpty(cateDTO.getProdCateId())) {
throw new ServiceException("新增商品分类 prodCateId必须为空!", HttpStatus.ERROR);
}
return this.prodCateMapper.insert(BeanUtil.toBean(cateDTO, SysProductCategory.class));
}
/**
*
*
* @param cateDTO
* @return Integer
*/
@Override
@Transactional
public Integer update(ProdCateDTO cateDTO) {
SysProductCategory prodCate = Optional.ofNullable(this.prodCateMapper.selectOne(new LambdaQueryWrapper<SysProductCategory>()
.eq(SysProductCategory::getId, cateDTO.getProdCateId()).eq(SysProductCategory::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("商品分类不存在!", HttpStatus.ERROR));
prodCate.setUpdateBy(getUsername());
BeanUtil.copyProperties(cateDTO, prodCate);
return this.prodCateMapper.updateById(prodCate);
}
/**
*
*
* @param prodCateId ID
* @return Integer
*/
@Override
@Transactional
public Integer delete(Long prodCateId) {
SysProductCategory prodCate = Optional.ofNullable(this.prodCateMapper.selectOne(new LambdaQueryWrapper<SysProductCategory>()
.eq(SysProductCategory::getId, prodCateId).eq(SysProductCategory::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("商品分类不存在!", HttpStatus.ERROR));
prodCate.setDelFlag(Constants.DELETED);
return this.prodCateMapper.updateById(prodCate);
}
/**
*
*
* @param prodCateId ID
* @return ProdCateDTO
*/
@Override
@Transactional(readOnly = true)
public ProdCateDTO selectById(Long prodCateId) {
SysProductCategory prodCate = Optional.ofNullable(this.prodCateMapper.selectOne(new LambdaQueryWrapper<SysProductCategory>()
.eq(SysProductCategory::getId, prodCateId).eq(SysProductCategory::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("商品分类不存在!", HttpStatus.ERROR));
return BeanUtil.toBean(prodCate, ProdCateDTO.class);
}
/**
*
*
* @param listDTO
* @return List<ProdCateListDTO>
*/
@Override
@Transactional(readOnly = true)
public List<ProdCateListResDTO> selectList(ProdCateListDTO listDTO) {
LambdaQueryWrapper<SysProductCategory> queryWrapper = new LambdaQueryWrapper<SysProductCategory>()
.eq(SysProductCategory::getDelFlag, Constants.UNDELETED)
.orderByAsc(SysProductCategory::getOrderNum);
if (StringUtils.isNotBlank(listDTO.getName())) {
queryWrapper.like(SysProductCategory::getName, listDTO.getName());
}
if (StringUtils.isNotBlank(listDTO.getStatus())) {
queryWrapper.eq(SysProductCategory::getStatus, listDTO.getStatus());
}
List<SysProductCategory> prodCateList = this.prodCateMapper.selectList(queryWrapper);
if (CollectionUtils.isEmpty(prodCateList)) {
return new ArrayList<>();
}
List<ProdCateListResDTO> resList = BeanUtil.copyToList(prodCateList, ProdCateListResDTO.class);
return this.buildCateTree(resList);
}
/**
*
*
* @param cateList
* @return List<ProdCateListResDTO>
*/
private List<ProdCateListResDTO> buildCateTree(List<ProdCateListResDTO> cateList) {
List<ProdCateListResDTO> returnList = new ArrayList<>();
List<Long> tempList = cateList.stream().map(ProdCateListResDTO::getId).collect(Collectors.toList());
for (Iterator<ProdCateListResDTO> iterator = cateList.iterator(); iterator.hasNext(); ) {
ProdCateListResDTO category = iterator.next();
// 如果是顶级节点, 遍历该父节点的所有子节点
if (!tempList.contains(category.getParentId())) {
recursionFn(cateList, category);
returnList.add(category);
}
}
if (returnList.isEmpty()) {
returnList = cateList;
}
return returnList;
}
/**
*
*
* @param cateList
* @param cate
*/
private void recursionFn(List<ProdCateListResDTO> cateList, ProdCateListResDTO cate) {
// 得到子节点列表
List<ProdCateListResDTO> childList = getChildList(cateList, cate);
cate.setChildren(childList);
for (ProdCateListResDTO tChild : childList) {
if (hasChild(cateList, tChild)) {
recursionFn(cateList, tChild);
}
}
}
/**
*
*/
private List<ProdCateListResDTO> getChildList(List<ProdCateListResDTO> cateList, ProdCateListResDTO cate) {
List<ProdCateListResDTO> tlist = new ArrayList<>();
Iterator<ProdCateListResDTO> it = cateList.iterator();
while (it.hasNext()) {
ProdCateListResDTO n = it.next();
if (n.getParentId().longValue() == cate.getId().longValue()) {
tlist.add(n);
}
}
return tlist;
}
/**
*
*/
private boolean hasChild(List<ProdCateListResDTO> list, ProdCateListResDTO cate) {
return getChildList(list, cate).size() > 0;
}
}