{"record":{"id":"2e3f5edc399aec92","repo":"jeecgboot/JeecgBoot","slug":"error-2e3f5e","errorCode":null,"errorMessage":"不能拖拽到自身子部门","messagePattern":"不能拖拽到自身子部门","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java","lineNumber":2060,"sourceCode":"        //5. 清空缓存\n        redisUtil.removeAll(CommonConstant.DEPART_NAME_REDIS_KEY_PRE);\n    }\n\n    /**\n     * 验证拖拽操作是否合法\n     *\n     * @param dragDept     被拖拽的部门\n     * @param targetDept   目标部门\n     * @param dropPosition 拖拽位置\n     */\n    private void validateDragOperation(SysDepart dragDept, SysDepart targetDept, Integer dropPosition) {\n        // 禁止拖拽到自身\n        if (dragDept.getId().equals(targetDept.getId())) {\n            throw new RuntimeException(\"不能拖拽到自身\");\n        }\n        // 禁止拖拽到自身子部门\n        if (isDescendant(dragDept, targetDept.getId())) {\n            throw new RuntimeException(\"不能拖拽到自身子部门\");\n        }\n        //公司岗位判断\n        String orgCategory = targetDept.getOrgCategory();\n        String oldOrgCategory = dragDept.getOrgCategory();\n        //部门为公司\n        if(0 != dropPosition && DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(orgCategory)){\n            //当前部门不能为子公司、部门和岗位\n            if(!DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(oldOrgCategory)){\n                throw new JeecgBootBizTipException(\"当前部门类型为【\"+DepartCategoryEnum.getNameByValue(oldOrgCategory)+\"】,不允许移动到公司\");\n            }\n        }\n        //部门为岗位不允许移入\n        if(0 == dropPosition && DepartCategoryEnum.DEPART_CATEGORY_POST.getValue().equals(orgCategory)) {\n            throw new JeecgBootBizTipException(\"岗位不允许存在子级\");\n        }\n        //公司不能做为子级\n        if(oConvertUtils.isNotEmpty(targetDept.getParentId()) && DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(oldOrgCategory)){\n            throw new JeecgBootBizTipException(\"公司不允许作为子级\");","sourceCodeStart":2042,"sourceCodeEnd":2078,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java#L2042-L2078","documentation":"Thrown by validateDragOperation when isDescendant(dragDept, targetDept.getId()) returns true — the target is a child of the dragged department, which would create a cycle if the move were allowed. This RuntimeException is the second check after the self-drop guard, preventing circular parent-child relationships.","triggerScenarios":"Dragging a parent department onto one of its own descendants. The isDescendant method recursively checks children via departMapper.getDepartByParentId. This prevents creating a cycle where a node becomes its own ancestor.","commonSituations":"User drags a top-level department into a sub-department below it; large tree where the hierarchy isn't visually obvious; tree component allows dropping on any node without hierarchy awareness.","solutions":["Add a frontend check that disables drop on any descendant of the dragged node (traverse children client-side).","Provide clear visual feedback when hovering over an invalid (descendant) drop target.","Ensure the isDescendant check handles deep trees efficiently — if it's slow on large trees, consider caching the hierarchy."],"exampleFix":"// before\nif (isDescendant(dragDept, targetDept.getId())) {\n    throw new RuntimeException(\"不能拖拽到自身子部门\");\n}\n\n// after — frontend disables descendant drop targets\nfunction isDescendant(dragNode, candidateId) {\n    if (dragNode.id === candidateId) return true;\n    return (dragNode.children || []).some(c => isDescendant(c, candidateId));\n}\nfunction allowDrop(dragNode, dropNode) {\n    return !isDescendant(dragNode, dropNode.id);\n}","handlingStrategy":"validation","validationCode":"// Frontend: check if drop target is a descendant of drag node\nfunction isDescendantOf(dragNode, candidateId) {\n    if (dragNode.id === candidateId) return true;\n    return (dragNode.children || []).some(c => isDescendantOf(c, candidateId));\n}\nif (isDescendantOf(dragNode, dropNode.id)) {\n    ElMessage.warning('不能拖拽到自身子部门');\n    return;\n}","typeGuard":"public boolean isSafeDropTarget(SysDepart dragDept, String targetId) {\n    return !dragDept.getId().equals(targetId) && !isDescendant(dragDept, targetId);\n}","tryCatchPattern":"try {\n    service.updateChangeDepart(changeDepartVo);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"不能拖拽到自身子部门\")) {\n        return Result.error(\"目标部门是当前部门的子级，不允许拖拽\");\n    }\n    throw e;\n}","preventionTips":["Traverse the client-side tree to disable descendant drop targets.","Provide visual feedback (red highlight) on invalid drop targets.","Cache the department hierarchy for efficient descendant checks."],"tags":["jeecg-boot","department","drag-drop","cycle-prevention","validation"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}