diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java index 95341a24d..4474ccd96 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java @@ -2,10 +2,11 @@ package org.dromara.workflow.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.EditGroup; import org.dromara.common.excel.utils.ExcelUtil; @@ -25,7 +26,6 @@ import java.util.List; * 流程分类 * * @author may - * @date 2023-06-28 */ @Validated @RequiredArgsConstructor @@ -33,16 +33,16 @@ import java.util.List; @RequestMapping("/workflow/category") public class FlwCategoryController extends BaseController { - private final IFlwCategoryService FlowCategoryService; + private final IFlwCategoryService flwCategoryService; /** * 查询流程分类列表 */ + @SaCheckPermission("workflow:category:list") @GetMapping("/list") public R> list(FlowCategoryBo bo) { - List list = FlowCategoryService.queryList(bo); + List list = flwCategoryService.queryList(bo); return R.ok(list); - } /** @@ -52,19 +52,20 @@ public class FlwCategoryController extends BaseController { @Log(title = "流程分类", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(FlowCategoryBo bo, HttpServletResponse response) { - List list = FlowCategoryService.queryList(bo); + List list = flwCategoryService.queryList(bo); ExcelUtil.exportExcel(list, "流程分类", FlowCategoryVo.class, response); } /** * 获取流程分类详细信息 * - * @param id 主键 + * @param categoryId 主键 */ - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { - return R.ok(FlowCategoryService.queryById(id)); + @SaCheckPermission("workflow:category:query") + @GetMapping("/{categoryId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) { + flwCategoryService.checkCategoryDataScope(categoryId); + return R.ok(flwCategoryService.queryById(categoryId)); } /** @@ -74,8 +75,11 @@ public class FlwCategoryController extends BaseController { @Log(title = "流程分类", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo bo) { - return toAjax(FlowCategoryService.insertByBo(bo)); + public R add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) { + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } + return toAjax(flwCategoryService.insertByBo(category)); } /** @@ -85,20 +89,39 @@ public class FlwCategoryController extends BaseController { @Log(title = "流程分类", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo bo) { - return toAjax(FlowCategoryService.updateByBo(bo)); + public R edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) { + Long categoryId = category.getCategoryId(); + flwCategoryService.checkCategoryDataScope(categoryId); + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } else if (category.getParentId().equals(categoryId)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,上级流程分类不能是自己"); + } else if (StringUtils.equals(SystemConstants.DISABLE, category.getStatus())) { + if (flwCategoryService.selectNormalChildrenCategoryById(categoryId) > 0) { + return R.fail("该流程分类包含未停用的子流程分类!"); + } else if (flwCategoryService.checkCategoryExistDefinition(categoryId)) { + return R.fail("该部门下存在已分配流程定义,不能禁用!"); + } + } + return toAjax(flwCategoryService.updateByBo(category)); } /** * 删除流程分类 * - * @param ids 主键串 + * @param categoryId 主键 */ @SaCheckPermission("workflow:category:remove") @Log(title = "流程分类", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(FlowCategoryService.deleteWithValidByIds(List.of(ids), true)); + @DeleteMapping("/{categoryId}") + public R remove(@PathVariable Long categoryId) { + if (flwCategoryService.hasChildByCategoryId(categoryId)) { + return R.warn("存在下级流程分类,不允许删除"); + } + if (flwCategoryService.checkCategoryExistDefinition(categoryId)) { + return R.warn("流程分类存在流程定义,不允许删除"); + } + return toAjax(flwCategoryService.deleteWithValidById(categoryId)); } + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java index dcda2ac54..5e33f639b 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java @@ -1,5 +1,6 @@ package org.dromara.workflow.controller; +import cn.hutool.core.lang.tree.Tree; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; @@ -11,7 +12,9 @@ import org.dromara.common.web.core.BaseController; import org.dromara.warm.flow.core.entity.Definition; import org.dromara.warm.flow.core.service.DefService; import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.domain.bo.FlowCategoryBo; import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.service.IFlwCategoryService; import org.dromara.workflow.service.IFlwDefinitionService; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -32,6 +35,7 @@ import java.util.List; @RequestMapping("/workflow/definition") public class FlwDefinitionController extends BaseController { + private final IFlwCategoryService flwCategoryService; private final IFlwDefinitionService iFlwDefinitionService; private final DefService defService; @@ -45,6 +49,14 @@ public class FlwDefinitionController extends BaseController { return iFlwDefinitionService.page(flowDefinition, pageQuery); } + /** + * 获取流程分类树列表 + */ + @GetMapping("/categoryTree") + public R>> categoryTree(FlowCategoryBo dept) { + return R.ok(flwCategoryService.selectCategoryTreeList(dept)); + } + /** * 获取历史流程定义列表 * diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java index ba4b3fc87..36c65ea77 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java @@ -99,7 +99,6 @@ public class FlwTaskController extends BaseController { * @param flowTaskBo 参数 * @param pageQuery 分页 */ - @GetMapping("/pageByAllTaskFinish") public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java index 84f804961..d84f3b1ae 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java @@ -1,6 +1,7 @@ package org.dromara.workflow.domain; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -23,25 +24,45 @@ public class FlowCategory extends TenantEntity { private static final long serialVersionUID = 1L; /** - * 主键 + * 流程分类ID */ - @TableId(value = "id") - private Long id; + @TableId(value = "category_id") + private Long categoryId; /** - * 分类名称 - */ - private String categoryName; - - /** - * 父级id + * 父流程分类id */ private Long parentId; /** - * 排序 + * 祖级列表 */ - private Long sortNum; + private String ancestors; + /** + * 流程分类名称 + */ + private String categoryName; + + /** + * 流程分类编码 + */ + private String categoryCode; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 流程分类状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java index e22f93638..c1f62f93d 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java @@ -22,26 +22,36 @@ import org.dromara.workflow.domain.FlowCategory; public class FlowCategoryBo extends BaseEntity { /** - * 主键 + * 流程分类ID */ - @NotNull(message = "主键不能为空", groups = {EditGroup.class}) - private Long id; + @NotNull(message = "流程分类ID不能为空", groups = { EditGroup.class }) + private Long categoryId; /** - * 分类名称 + * 父流程分类id */ - @NotBlank(message = "分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) - private String categoryName; - - /** - * 父级id - */ - @NotNull(message = "父级id不能为空", groups = {AddGroup.class, EditGroup.class}) + @NotNull(message = "父流程分类id不能为空", groups = {AddGroup.class, EditGroup.class}) private Long parentId; /** - * 排序 + * 流程分类名称 */ - private Long sortNum; + @NotBlank(message = "流程分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryName; + + /** + * 流程分类编码 + */ + private String categoryCode; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 流程分类状态(0正常 1停用) + */ + private String status; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java index 63739ceab..45e29a985 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java @@ -4,10 +4,13 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; import org.dromara.workflow.domain.FlowCategory; import java.io.Serial; import java.io.Serializable; +import java.util.Date; /** @@ -25,28 +28,55 @@ public class FlowCategoryVo implements Serializable { private static final long serialVersionUID = 1L; /** - * 主键 + * 流程分类ID */ - @ExcelProperty(value = "主键") - private Long id; + @ExcelProperty(value = "流程分类ID") + private Long categoryId; /** - * 分类名称 + * 父部门id */ - @ExcelProperty(value = "分类名称") - private String categoryName; - - /** - * 父级id - */ - @ExcelProperty(value = "父级id") private Long parentId; /** - * 排序 + * 父部门名称 */ - @ExcelProperty(value = "排序") - private Long sortNum; + private String parentName; + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + @ExcelProperty(value = "流程分类名称") + private String categoryName; + + /** + * 流程分类编码 + */ + @ExcelProperty(value = "流程分类编码") + private String categoryCode; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long orderNum; + + /** + * 流程分类状态(0正常 1停用) + */ + @ExcelProperty(value = "流程分类状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java index 8ef357e87..bad2465ac 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java @@ -1,5 +1,7 @@ package org.dromara.workflow.mapper; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.workflow.domain.FlowCategory; import org.dromara.workflow.domain.vo.FlowCategoryVo; @@ -12,4 +14,15 @@ import org.dromara.workflow.domain.vo.FlowCategoryVo; */ public interface FlwCategoryMapper extends BaseMapperPlus { + /** + * 统计指定流程分类ID的分类数量 + * + * @param categoryId 流程分类ID + * @return 该流程分类ID的分类数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "createDept") + }) + long countCategoryById(Long categoryId); + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java index c38266e53..9bc97c0ee 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java @@ -1,42 +1,102 @@ package org.dromara.workflow.service; +import cn.hutool.core.lang.tree.Tree; import org.dromara.workflow.domain.bo.FlowCategoryBo; import org.dromara.workflow.domain.vo.FlowCategoryVo; -import java.util.Collection; import java.util.List; /** * 流程分类Service接口 * * @author may - * @date 2023-06-28 */ public interface IFlwCategoryService { /** * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 */ - FlowCategoryVo queryById(Long id); - + FlowCategoryVo queryById(Long categoryId); /** - * 查询流程分类列表 + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 */ List queryList(FlowCategoryBo bo); /** - * 新增流程分类 + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 */ - Boolean insertByBo(FlowCategoryBo bo); + List> selectCategoryTreeList(FlowCategoryBo category); + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + void checkCategoryDataScope(Long categoryId); + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + boolean checkCategoryNameUnique(FlowCategoryBo category); + + /** + * 根据ID查询所有子流程分类数(正常状态) + * + * @param categoryId 流程分类ID + * @return 子流程分类数 + */ + long selectNormalChildrenCategoryById(Long categoryId); + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkCategoryExistDefinition(Long categoryId); + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + boolean hasChildByCategoryId(Long categoryId); + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + int insertByBo(FlowCategoryBo bo); /** * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 */ - Boolean updateByBo(FlowCategoryBo bo); + int updateByBo(FlowCategoryBo bo); /** - * 校验并批量删除流程分类信息 + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 */ - Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + int deleteWithValidById(Long categoryId); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java index 52e1c5203..6bef2348a 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -1,44 +1,66 @@ package org.dromara.workflow.service.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; -import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; import org.dromara.workflow.domain.FlowCategory; import org.dromara.workflow.domain.bo.FlowCategoryBo; import org.dromara.workflow.domain.vo.FlowCategoryVo; import org.dromara.workflow.mapper.FlwCategoryMapper; import org.dromara.workflow.service.IFlwCategoryService; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.Collection; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * 流程分类Service业务层处理 * * @author may - * @date 2023-06-28 */ @RequiredArgsConstructor @Service public class FlwCategoryServiceImpl implements IFlwCategoryService { private final FlwCategoryMapper baseMapper; + private final DefService defService; /** * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 */ @Override - public FlowCategoryVo queryById(Long id) { - return baseMapper.selectVoById(id); + public FlowCategoryVo queryById(Long categoryId) { + FlowCategoryVo category = baseMapper.selectVoById(categoryId); + if (ObjectUtil.isNull(category)) { + return null; + } + FlowCategoryVo parentCategory = baseMapper.selectVoOne(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, category.getParentId())); + category.setParentName(ObjectUtils.notNullGetter(parentCategory, FlowCategoryVo::getCategoryName)); + return category; } - /** - * 查询流程分类列表 + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 */ @Override public List queryList(FlowCategoryBo bo) { @@ -46,52 +68,220 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService { return baseMapper.selectVoList(lqw); } + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + @Override + public List> selectCategoryTreeList(FlowCategoryBo category) { + LambdaQueryWrapper lqw = buildQueryWrapper(category); + List categorys = baseMapper.selectVoList(lqw); + if (CollUtil.isEmpty(categorys)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (FlowCategoryVo d : categorys) { + Long parentId = d.getParentId(); + FlowCategoryVo categoryVo = StreamUtils.findFirst(categorys, it -> it.getCategoryId().longValue() == parentId); + if (ObjectUtil.isNull(categoryVo)) { + List> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) -> + tree.setId(dept.getCategoryId()) + .setParentId(dept.getParentId()) + .setName(dept.getCategoryName()) + .setWeight(dept.getOrderNum()) + .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus()))); + Tree tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getCategoryId()); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + @Override + public void checkCategoryDataScope(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countCategoryById(categoryId) == 0) { + throw new ServiceException("没有权限访问流程分类数据!"); + } + } + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + @Override + public boolean checkCategoryNameUnique(FlowCategoryBo category) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getCategoryName, category.getCategoryName()) + .eq(FlowCategory::getParentId, category.getParentId()) + .ne(ObjectUtil.isNotNull(category.getCategoryId()), FlowCategory::getCategoryId, category.getCategoryId())); + return !exist; + } + + /** + * 根据ID查询所有子流程分类数(正常状态) + * + * @param categoryId 流程分类ID + * @return 子流程分类数 + */ + @Override + public long selectNormalChildrenCategoryById(Long categoryId) { + return baseMapper.selectCount(new LambdaQueryWrapper() + .eq(FlowCategory::getStatus, SystemConstants.NORMAL) + .apply(DataBaseHelper.findInSet(categoryId, "ancestors"))); + } + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkCategoryExistDefinition(Long categoryId) { + FlowDefinition definition = new FlowDefinition(); + definition.setCategory(categoryId.toString()); + return defService.exists(definition); + } + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + @Override + public boolean hasChildByCategoryId(Long categoryId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getParentId, categoryId)); + } + private LambdaQueryWrapper buildQueryWrapper(FlowCategoryBo bo) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId()); lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName()); + lqw.like(StringUtils.isNotBlank(bo.getCategoryCode()), FlowCategory::getCategoryCode, bo.getCategoryCode()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FlowCategory::getStatus, bo.getStatus()); + lqw.orderByAsc(FlowCategory::getAncestors); + lqw.orderByAsc(FlowCategory::getParentId); + lqw.orderByAsc(FlowCategory::getOrderNum); + lqw.orderByAsc(FlowCategory::getCategoryId); return lqw; } /** * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 */ @Override - public Boolean insertByBo(FlowCategoryBo bo) { - FlowCategory add = MapstructUtils.convert(bo, FlowCategory.class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); + public int insertByBo(FlowCategoryBo bo) { + FlowCategory info = baseMapper.selectById(bo.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!SystemConstants.NORMAL.equals(info.getStatus())) { + throw new ServiceException("流程分类停用,不允许新增"); } - return flag; + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId()); + return baseMapper.insert(category); } /** * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 */ @Override - @Transactional(rollbackFor = Exception.class) - public Boolean updateByBo(FlowCategoryBo bo) { - FlowCategory update = MapstructUtils.convert(bo, FlowCategory.class); - validEntityBeforeSave(update); - return baseMapper.updateById(update) > 0; - } - - /** - * 保存前的数据校验 - */ - private void validEntityBeforeSave(FlowCategory entity) { - // 做一些数据校验,如唯一约束 - } - - /** - * 批量删除流程分类 - */ - @Override - public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - // 做一些业务上的校验,判断是否需要校验 + public int updateByBo(FlowCategoryBo bo) { + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId()); + if (ObjectUtil.isNull(oldCategory)) { + throw new ServiceException("流程分类不存在,无法修改"); } - return baseMapper.deleteByIds(ids) > 0; + if (!oldCategory.getParentId().equals(category.getParentId())) { + // 如果是新父流程分类 则校验是否具有新父流程分类权限 避免越权 + this.checkCategoryDataScope(category.getParentId()); + FlowCategory newParentCategory = baseMapper.selectById(category.getParentId()); + if (ObjectUtil.isNotNull(newParentCategory)) { + String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId(); + String oldAncestors = oldCategory.getAncestors(); + category.setAncestors(newAncestors); + updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors); + } + } else { + category.setAncestors(oldCategory.getAncestors()); + } + int result = baseMapper.updateById(category); + if (SystemConstants.NORMAL.equals(category.getStatus()) && StringUtils.isNotEmpty(category.getAncestors()) + && !StringUtils.equals(SystemConstants.NORMAL, category.getAncestors())) { + // 如果该流程分类是启用状态,则启用该流程分类的所有上级流程分类 + updateParentCategoryStatusNormal(category); + } + return result; + } + + /** + * 修改子元素关系 + * + * @param categoryId 被修改的流程分类ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(categoryId, "ancestors"))); + List list = new ArrayList<>(); + for (FlowCategory child : children) { + FlowCategory category = new FlowCategory(); + category.setCategoryId(child.getCategoryId()); + category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(category); + } + if (CollUtil.isNotEmpty(list)) { + baseMapper.updateBatchById(list); + } + } + + /** + * 修改该流程分类的父级流程分类状态 + * + * @param category 当前流程分类 + */ + private void updateParentCategoryStatusNormal(FlowCategory category) { + String ancestors = category.getAncestors(); + Long[] categoryIds = Convert.toLongArray(ancestors); + baseMapper.update(null, new LambdaUpdateWrapper() + .set(FlowCategory::getStatus, SystemConstants.NORMAL) + .in(FlowCategory::getCategoryId, Arrays.asList(categoryIds))); + } + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + @Override + public int deleteWithValidById(Long categoryId) { + return baseMapper.deleteById(categoryId); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml index 10c948d85..e9918f1f2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml @@ -4,4 +4,8 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql index 3e7f0295a..93ccecc09 100644 --- a/script/sql/ry_workflow.sql +++ b/script/sql/ry_workflow.sql @@ -151,22 +151,24 @@ CREATE TABLE `flow_user` -- ---------------------------- create table flow_category ( - id bigint(20) not null comment '流程分类ID', - tenant_id varchar(20) default '000000' comment '租户编号', - category_name varchar(255) null comment '分类名称', - category_code varchar(255) null comment '分类编码', - parent_id bigint null comment '父级id', - sort_num int(19) null comment '排序', - create_dept bigint(20) null comment '创建部门', - create_by bigint(20) null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint(20) null comment '更新者', - update_time datetime null comment '更新时间', - constraint uni_category_code unique (category_code), - primary key (id) + category_id bigint(20) not null comment '流程分类ID', + tenant_id varchar(20) default '000000' comment '租户编号', + parent_id bigint(20) default 0 comment '父流程分类id', + ancestors varchar(500) default '' comment '祖级列表', + category_name varchar(30) not null comment '流程分类名称', + category_code varchar(100) default '' comment '流程分类编码', + order_num int(4) default 0 comment '显示顺序', + status char(1) default '0' comment '流程分类状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_dept bigint(20) null comment '创建部门', + create_by bigint(20) null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint(20) null comment '更新者', + update_time datetime null comment '更新时间', + primary key (category_id) ) engine = innodb comment = '流程分类'; -INSERT INTO flow_category values (1, '000000', 'OA', 'OA', 0, 0, 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (1, '000000', 0, '0', 'OA', 'OA', 0, '0', '0', 103, 1, sysdate(), null, null); -- ---------------------------- -- 请假单信息