添加知识分类

This commit is contained in:
Pancaihua 2024-07-22 21:06:20 +08:00
parent 37c9da5426
commit d471524ee6
10 changed files with 482 additions and 1 deletions

View File

@ -74,5 +74,12 @@ public interface ErrorCodeConstants {
// ========== BPM 流程表达式 1-009-014-000 ==========
ErrorCode PROCESS_EXPRESSION_NOT_EXISTS = new ErrorCode(1_009_014_000, "流程表达式不存在");
// ========== 知识分类 1_009_015_000 ==========
ErrorCode KNOWTYPE_NOT_EXISTS = new ErrorCode(1_009_015_000, "知识分类不存在");
ErrorCode KNOWTYPE_EXITS_CHILDREN = new ErrorCode(1_009_015_001, "存在存在子知识分类,无法删除");
ErrorCode KNOWTYPE_PARENT_NOT_EXITS = new ErrorCode(1_009_015_002,"父级知识分类不存在");
ErrorCode KNOWTYPE_PARENT_ERROR = new ErrorCode(1_009_015_003, "不能设置自己为父知识分类");
ErrorCode KNOWTYPE_NODE_NAME_DUPLICATE = new ErrorCode(1_009_015_004, "已经存在该节点名称的知识分类");
ErrorCode KNOWTYPE_PARENT_IS_CHILD = new ErrorCode(1_009_015_005, "不能设置自己的子Knowtype为父Knowtype");
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.bpm.controller.admin.knows;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
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.List;
import cn.iocoder.yudao.module.bpm.controller.admin.knows.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.knows.KnowtypeDO;
import cn.iocoder.yudao.module.bpm.service.knows.KnowtypeService;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 知识分类")
@RestController
@RequestMapping("/bpm/knowtype")
@Validated
public class KnowtypeController {
@Resource
private KnowtypeService knowtypeService;
@PostMapping("/create")
@Operation(summary = "创建知识分类")
@PreAuthorize("@ss.hasPermission('bpm:knowtype:create')")
public CommonResult<Long> createKnowtype(@Valid @RequestBody KnowtypeSaveReqVO createReqVO) {
return success(knowtypeService.createKnowtype(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新知识分类")
@PreAuthorize("@ss.hasPermission('bpm:knowtype:update')")
public CommonResult<Boolean> updateKnowtype(@Valid @RequestBody KnowtypeSaveReqVO updateReqVO) {
knowtypeService.updateKnowtype(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除知识分类")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:knowtype:delete')")
public CommonResult<Boolean> deleteKnowtype(@RequestParam("id") Long id) {
knowtypeService.deleteKnowtype(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得知识分类")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('bpm:knowtype:query')")
public CommonResult<KnowtypeRespVO> getKnowtype(@RequestParam("id") Long id) {
KnowtypeDO knowtype = knowtypeService.getKnowtype(id);
return success(BeanUtils.toBean(knowtype, KnowtypeRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得知识分类列表")
@PreAuthorize("@ss.hasPermission('bpm:knowtype:query')")
public CommonResult<List<KnowtypeRespVO>> getKnowtypeList(@Valid KnowtypeListReqVO listReqVO) {
List<KnowtypeDO> list = knowtypeService.getKnowtypeList(listReqVO);
return success(BeanUtils.toBean(list, KnowtypeRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出知识分类 Excel")
@PreAuthorize("@ss.hasPermission('bpm:knowtype:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportKnowtypeExcel(@Valid KnowtypeListReqVO listReqVO,
HttpServletResponse response) throws IOException {
List<KnowtypeDO> list = knowtypeService.getKnowtypeList(listReqVO);
// 导出 Excel
ExcelUtils.write(response, "知识分类.xls", "数据", KnowtypeRespVO.class,
BeanUtils.toBean(list, KnowtypeRespVO.class));
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.bpm.controller.admin.knows.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.time.LocalDateTime;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 知识分类列表 Request VO")
@Data
public class KnowtypeListReqVO {
@Schema(description = "父id", example = "18269")
private Long parentId;
@Schema(description = "节点名称", example = "芋艿")
private String nodeName;
@Schema(description = "显示顺序")
private Integer orderNum;
@Schema(description = "知识状态0正常 1停用", example = "1")
private String status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.bpm.controller.admin.knows.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 知识分类 Response VO")
@Data
@ExcelIgnoreUnannotated
public class KnowtypeRespVO {
@Schema(description = "分类id", requiredMode = Schema.RequiredMode.REQUIRED, example = "899")
@ExcelProperty("分类id")
private Long id;
@Schema(description = "父id", example = "18269")
@ExcelProperty("父id")
private Long parentId;
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@ExcelProperty("节点名称")
private String nodeName;
@Schema(description = "显示顺序")
@ExcelProperty("显示顺序")
private Integer orderNum;
@Schema(description = "知识状态0正常 1停用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "知识状态0正常 1停用", converter = DictConvert.class)
@DictFormat("common_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private String status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.bpm.controller.admin.knows.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotEmpty;
@Schema(description = "管理后台 - 知识分类新增/修改 Request VO")
@Data
public class KnowtypeSaveReqVO {
@Schema(description = "分类id", requiredMode = Schema.RequiredMode.REQUIRED, example = "899")
private Long id;
@Schema(description = "父id", example = "18269")
private Long parentId;
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@NotEmpty(message = "节点名称不能为空")
private String nodeName;
@Schema(description = "显示顺序")
private Integer orderNum;
@Schema(description = "知识状态0正常 1停用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "知识状态0正常 1停用不能为空")
private String status;
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.knows;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 知识分类 DO
*
* @author pch
*/
@TableName("des_knowtype")
@KeySequence("des_knowtype_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class KnowtypeDO extends BaseDO {
public static final Long PARENT_ID_ROOT = 0L;
/**
* 分类id
*/
@TableId
private Long id;
/**
* 父id
*/
private Long parentId;
/**
* 节点名称
*/
private String nodeName;
/**
* 显示顺序
*/
private Integer orderNum;
/**
* 知识状态0正常 1停用
*
* 枚举 {@link TODO common_status 对应的类}
*/
private String status;
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.knows;
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.bpm.dal.dataobject.knows.KnowtypeDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.bpm.controller.admin.knows.vo.*;
/**
* 知识分类 Mapper
*
* @author pch
*/
@Mapper
public interface KnowtypeMapper extends BaseMapperX<KnowtypeDO> {
default List<KnowtypeDO> selectList(KnowtypeListReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<KnowtypeDO>()
.eqIfPresent(KnowtypeDO::getParentId, reqVO.getParentId())
.likeIfPresent(KnowtypeDO::getNodeName, reqVO.getNodeName())
.eqIfPresent(KnowtypeDO::getOrderNum, reqVO.getOrderNum())
.eqIfPresent(KnowtypeDO::getStatus, reqVO.getStatus())
.betweenIfPresent(KnowtypeDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(KnowtypeDO::getId));
}
default KnowtypeDO selectByParentIdAndNodeName(Long parentId, String nodeName) {
return selectOne(KnowtypeDO::getParentId, parentId, KnowtypeDO::getNodeName, nodeName);
}
default Long selectCountByParentId(Long parentId) {
return selectCount(KnowtypeDO::getParentId, parentId);
}
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.bpm.service.knows;
import java.util.*;
import javax.validation.Valid;
import cn.iocoder.yudao.module.bpm.controller.admin.knows.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.knows.KnowtypeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 知识分类 Service 接口
*
* @author pch
*/
public interface KnowtypeService {
/**
* 创建知识分类
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createKnowtype(@Valid KnowtypeSaveReqVO createReqVO);
/**
* 更新知识分类
*
* @param updateReqVO 更新信息
*/
void updateKnowtype(@Valid KnowtypeSaveReqVO updateReqVO);
/**
* 删除知识分类
*
* @param id 编号
*/
void deleteKnowtype(Long id);
/**
* 获得知识分类
*
* @param id 编号
* @return 知识分类
*/
KnowtypeDO getKnowtype(Long id);
/**
* 获得知识分类列表
*
* @param listReqVO 查询条件
* @return 知识分类列表
*/
List<KnowtypeDO> getKnowtypeList(KnowtypeListReqVO listReqVO);
}

View File

@ -0,0 +1,137 @@
package cn.iocoder.yudao.module.bpm.service.knows;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.bpm.controller.admin.knows.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.knows.KnowtypeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.dal.mysql.knows.KnowtypeMapper;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
* 知识分类 Service 实现类
*
* @author pch
*/
@Service
@Validated
public class KnowtypeServiceImpl implements KnowtypeService {
@Resource
private KnowtypeMapper knowtypeMapper;
@Override
public Long createKnowtype(KnowtypeSaveReqVO createReqVO) {
// 校验父id的有效性
validateParentKnowtype(null, createReqVO.getParentId());
// 校验节点名称的唯一性
validateKnowtypeNodeNameUnique(null, createReqVO.getParentId(), createReqVO.getNodeName());
// 插入
KnowtypeDO knowtype = BeanUtils.toBean(createReqVO, KnowtypeDO.class);
knowtypeMapper.insert(knowtype);
// 返回
return knowtype.getId();
}
@Override
public void updateKnowtype(KnowtypeSaveReqVO updateReqVO) {
// 校验存在
validateKnowtypeExists(updateReqVO.getId());
// 校验父id的有效性
validateParentKnowtype(updateReqVO.getId(), updateReqVO.getParentId());
// 校验节点名称的唯一性
validateKnowtypeNodeNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getNodeName());
// 更新
KnowtypeDO updateObj = BeanUtils.toBean(updateReqVO, KnowtypeDO.class);
knowtypeMapper.updateById(updateObj);
}
@Override
public void deleteKnowtype(Long id) {
// 校验存在
validateKnowtypeExists(id);
// 校验是否有子知识分类
if (knowtypeMapper.selectCountByParentId(id) > 0) {
throw exception(KNOWTYPE_EXITS_CHILDREN);
}
// 删除
knowtypeMapper.deleteById(id);
}
private void validateKnowtypeExists(Long id) {
if (knowtypeMapper.selectById(id) == null) {
throw exception(KNOWTYPE_NOT_EXISTS);
}
}
private void validateParentKnowtype(Long id, Long parentId) {
if (parentId == null || KnowtypeDO.PARENT_ID_ROOT.equals(parentId)) {
return;
}
// 1. 不能设置自己为父知识分类
if (Objects.equals(id, parentId)) {
throw exception(KNOWTYPE_PARENT_ERROR);
}
// 2. 父知识分类不存在
KnowtypeDO parentKnowtype = knowtypeMapper.selectById(parentId);
if (parentKnowtype == null) {
throw exception(KNOWTYPE_PARENT_NOT_EXITS);
}
// 3. 递归校验父知识分类如果父知识分类是自己的子知识分类则报错避免形成环路
if (id == null) { // id 为空说明新增不需要考虑环路
return;
}
for (int i = 0; i < Short.MAX_VALUE; i++) {
// 3.1 校验环路
parentId = parentKnowtype.getParentId();
if (Objects.equals(id, parentId)) {
throw exception(KNOWTYPE_PARENT_IS_CHILD);
}
// 3.2 继续递归下一级父知识分类
if (parentId == null || KnowtypeDO.PARENT_ID_ROOT.equals(parentId)) {
break;
}
parentKnowtype = knowtypeMapper.selectById(parentId);
if (parentKnowtype == null) {
break;
}
}
}
private void validateKnowtypeNodeNameUnique(Long id, Long parentId, String nodeName) {
KnowtypeDO knowtype = knowtypeMapper.selectByParentIdAndNodeName(parentId, nodeName);
if (knowtype == null) {
return;
}
// 如果 id 为空说明不用比较是否为相同 id 的知识分类
if (id == null) {
throw exception(KNOWTYPE_NODE_NAME_DUPLICATE);
}
if (!Objects.equals(knowtype.getId(), id)) {
throw exception(KNOWTYPE_NODE_NAME_DUPLICATE);
}
}
@Override
public KnowtypeDO getKnowtype(Long id) {
return knowtypeMapper.selectById(id);
}
@Override
public List<KnowtypeDO> getKnowtypeList(KnowtypeListReqVO listReqVO) {
return knowtypeMapper.selectList(listReqVO);
}
}

View File

@ -34,7 +34,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService {
/**
* OA 请假对应的流程定义 KEY
*/
public static final String PROCESS_KEY = "my-test-flow02";
public static final String PROCESS_KEY = "oa_leave";
@Resource
private BpmOALeaveMapper leaveMapper;