diff --git a/shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/controller/DirectoryController.java b/shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/controller/DirectoryController.java index c6bcff5..474bab9 100644 --- a/shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/controller/DirectoryController.java +++ b/shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/controller/DirectoryController.java @@ -1,7 +1,7 @@ package com.keyware.shandan.bianmu.controller; import cn.hutool.core.bean.BeanUtil; -import com.keyware.shandan.bianmu.dto.DirCopyDTO; +import com.keyware.shandan.bianmu.dto.DirOperateDTO; import com.keyware.shandan.bianmu.entity.DirectoryVo; import com.keyware.shandan.bianmu.enums.DirectoryType; import com.keyware.shandan.bianmu.enums.ReviewStatus; @@ -18,13 +18,11 @@ import com.keyware.shandan.system.service.SysFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -149,35 +147,39 @@ public class DirectoryController extends BaseController dirCopy(DirCopyDTO dirCopy) { - saveLinkDirTree(dirCopy.getTree(), dirCopy.getTargetId()); + @PostMapping("/link") + public Result dirCopy(@RequestBody String targetId, @RequestBody String sourceId) { + saveLinkDirTree(sourceId, targetId); dirPermissionService.refreshCache(); return Result.of(true); } + /** + * @param targetId + * @param sourceIds + * @return + */ @PostMapping("/move") - public Result dirMove(DirCopyDTO copyObj) { - DirectoryVo targetDir = directoryService.getById(copyObj.getTargetId()); - DirectoryVo sourceDir = directoryService.getById(copyObj.getRoots().get(0).getId()); - copyObj.getRoots().forEach(item -> { - DirectoryVo dir = directoryService.getById(item.getId()); + public Result dirMove(@RequestBody String targetId, @RequestBody String sourceIds) { + DirectoryVo targetDir = directoryService.getById(targetId); + List idList = Arrays.asList(sourceIds.split(",")); + List sourceDirs = directoryService.listByIds(idList); + for (DirectoryVo dir : sourceDirs) { DirectoryVo newDir = new DirectoryVo(); BeanUtil.copyProperties(dir, newDir); newDir.setParentId(targetDir.getId()); - replaceNewAttribute(newDir, sourceDir, targetDir); + replaceNewAttribute(newDir, dir, targetDir); directoryService.updateById(newDir); - //List children = directoryService.childrenLists(dir); - //2023/1/5 移动目录时,修改目录下文件所属目录 List children = directoryService.allChildrenLists(dir); children.forEach(child -> { - replaceNewAttribute(child, sourceDir, targetDir); + replaceNewAttribute(child, dir, targetDir); }); directoryService.updateBatchById(children); - }); + } dirPermissionService.refreshCache(); return Result.of("成功"); } @@ -185,18 +187,20 @@ public class DirectoryController extends BaseController items, String parentId) { - if (items != null && items.size() > 0) { - items.forEach(item -> { - DirectoryVo dir = buildLinkDir(item, parentId); - directoryService.save(dir); - log.debug("保存目录:{}", dir.toString()); - saveLinkDirTree(item.getChildren(), dir.getId()); - }); + private void saveLinkDirTree(String sourceId, String targetId) { + DirectoryVo sourceDir = directoryService.getById(sourceId); + DirectoryVo dir; + if (DirectoryType.METADATA == sourceDir.getDirectoryType() || DirectoryType.LINK_METADATA == sourceDir.getDirectoryType()) { + dir = directoryBuilder.buildMetadataLinkDir(targetId, sourceDir.getId()); + } else if (DirectoryType.FILE == sourceDir.getDirectoryType() || DirectoryType.LINK_FILE == sourceDir.getDirectoryType()) { + dir = directoryBuilder.buildFileLinkDir(targetId, sourceDir.getId()); + } else { + dir = directoryBuilder.buildLinkDir(targetId, sourceDir.getId()); } + directoryService.save(dir); } @@ -214,20 +218,4 @@ public class DirectoryController extends BaseController{ + refreshPermis().then(() => { layer.close(index); refreshDirectoryNode(tempNode, res.data); callback && callback(); @@ -152,32 +152,30 @@ function startRender() { * 增加移动文件功能 */ metaListTable.addTableRowEvent('moveLink', function () { - var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'), data = checkStatus.data; - if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')){ - layer.msg('没有权限'); - return; + var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'), + datas = checkStatus.data || []; + if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')) { + showErrorMsg('没有权限'); + return false; } - if (data.length < 1) { - layer.confirm("请选择要移动的文件!", function (index) { - layer.close(index); - return; - }) - } else { - layer.confirm('是否确定移动该数据?', {}, function (index) { - layer.close(index); - moveData(); - }) + if (datas.length === 0) { + showErrorMsg('请选择要移动的文件'); + return false; } - function moveData() { - openDirectoryMoveLayer(data).then(res => { - refreshPermis().then(() => { - metaListTable.reloadTable(); - }) - }).catch(e => { - - }) - } + const ids = datas.map(data => data.directoryId); + const parentIdSet = new Set(); + datas.forEach(data => parentIdSet.add(data.parentId)) + openDirectorySelectLayer('move', (node)=>{ + if([...parentIdSet.values()].includes(node.id)){ + showErrorMsg('不能选择当前目录'); + return false; + } + return true; + }).then(nodes => { + const targetId = nodes[0].id; + moveResource(ids.join(','), targetId).then(res => refreshPermis().then(() => metaListTable.reloadTable())); + }) }) metaListTable.addTableRowEvent('removeLink', function (obj) { if (basicData.reviewStatus === ReviewStatus.PASS) { @@ -193,7 +191,7 @@ function startRender() { Util.send(`/business/directory/delete/${obj.directoryId}`, {}, 'delete').then(res => { if (res.flag) { showOkMsg('删除成功'); - refreshPermis().then(()=>{ + refreshPermis().then(() => { metaListTable.reloadTable(); //refreshDirectoryNode(tempNode, res.data); }) @@ -228,7 +226,7 @@ function startRender() { }) function upload(basicData, url, callback) { - if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')){ + if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')) { layer.msg('没有权限'); return; } @@ -297,7 +295,7 @@ function startRender() { }, }); - }else{ + } else { showErrorMsg('数据表不支持下载'); } }) @@ -514,14 +512,24 @@ function startRender() { title: "移动目录", handler: function (node, elem) { const {basicData, id, parentId, context} = node; - openDirectoryCopyLayer(basicData, 'move').then(res => { - refreshPermis().then(() => { - dirTree.partialRefreshAdd(elem); + openDirectorySelectLayer('move', (node) => { + if (node.id === id) { + showErrorMsg('不能选择自己'); + return false; + } + if (node.basicData.directoryPath.startsWith(basicData.directoryPath + '/')) { + showErrorMsg('不能选择子级目录'); + return false; + } + return true; + }).then(nodes => { + const targetId = nodes[0].id; + moveResource(id, targetId).then(res => refreshPermis().then(() => { + dirTree.partialRefreshAdd($(`div[data-id="${parentId}"]`)); + dirTree.partialRefreshAdd($(`div[data-id="${targetId}"]`)); metaListTable.reloadTable(); - }) - }).catch(e => { - - }) + })); + }); } }, { @@ -556,14 +564,29 @@ function startRender() { title: "关联目录或文件", handler: function (node, elem) { const {basicData, id, parentId, context} = node; - openDirectoryCopyLayer(basicData).then(res => { - refreshPermis().then(() => { - dirTree.partialRefreshAdd(elem); - metaListTable.reloadTable(); - }) - }).catch(e => { - - }) + openDirectorySelectLayer('link', (node)=>{ + if(node.id === id){ + showErrorMsg('不能选择自己'); + return false; + } + if(node.id === parentId){ + showErrorMsg('已经存在于该目录') + return false; + } + if(node.basicData.directoryPath.startsWith(basicData.directoryPath)){ + showErrorMsg('不能选择子级目录') + return false; + } + return true; + }).then(nodes=>{ + const chooseNode = nodes[0]; + linkResource(chooseNode.id, id).then(res=>{ + refreshPermis().then(() => { + dirTree.partialRefreshAdd($(`div[data-id="${id}"]`)); + metaListTable.reloadTable(); + }); + }); + }) } }, /*{ @@ -663,101 +686,25 @@ function startRender() { dom.click(); } - let copyItems = []; - - function openDirectoryCopyLayer(dirData, isMove) { - return new Promise(((resolve, reject) => { - layer.open({ - type: 1, - title: isMove ? '请选择目标目录' : '选择目录资源', - area: ['700px'], - btn: ['保存', '取消'], - content: `
    `, - success: function (layerObj, index) { - let copyTreeOps = globalTree.init({ - id: 'copyDirTree', - url: treeChildrenUrl + '&all=true', - // type: 'all', - cache: true, - scroll: '#copyDirTreeBox', - width: '100%', - checkbar: true, - checkbarType: isMove ? 'only' : 'p-casc', - checkbarFun: { - chooseBefore: function ($i, node) { - if (!isMove && node.id == DIR_ROOT_ID) { - showErrorMsg('不能选择根节点!') - return false; - } - if (dirData.id == node.id) { - showErrorMsg('不能选择自己!') - return false; - } - if (dirData.id == node.parentId) { - showErrorMsg('该节点已存在!') - return false; - } - // 选中前的回调 - return true; - }, - chooseDone: function (nodes) { //复选框点击事件完毕后,返回该树关于复选框操作的全部信息。 - // 选中后的回调 - nodes = nodes || []; - copyItems = nodes.map(node => { - let basicData = node.basicData || {}; - let {id, parentId, directoryType, resourceId} = basicData; - const resourceTypes = ['METADATA', 'LINK_METADATA', 'FILE', 'LINK_FILE']; - if (resourceTypes.includes(directoryType)) { - id = resourceId; - } - return {id, directoryType, parentId}; - }).filter(id => id !== DIR_ROOT_ID); - } - }, - done: res => { - } - }); - }, - yes: function (index) { - let params = {targetId: dirData.id, items: copyItems} - if (isMove) { - params.targetId = copyItems[0].id; - params.items = [{id: dirData.id, directoryType: 'DIRECTORY', parentId: ''}] - } - Util.post(isMove ? '/business/directory/move' : '/business/directory/copy', params).then(res => { - if (res.flag) { - showOkMsg('保存成功'); - if (isMove) { - window.location.reload() - } - } else { - showErrorMsg(); - } - }) - resolve && resolve(); - layer.close(index); - }, - cancel: function (index) { - reject && reject(); - layer.close(index); - } - }) - })) - } + function openDirectorySelectLayer(operateType, disabledIds) { + let chooseBeforeHandler, selectNodes = []; + if (disabledIds instanceof Function) { + chooseBeforeHandler = disabledIds; + disabledIds = undefined; + } - function openDirectoryMoveLayer(data) { return new Promise(((resolve, reject) => { + let directorySelectTree; layer.open({ type: 1, - title: '请选择目标目录', + title: '请选择目录', area: ['700px'], btn: ['保存', '取消'], content: `
      `, success: function (layerObj, index) { - let moveFileTreeOps = globalTree.init({ + directorySelectTree = globalTree.init({ id: 'moveFileTree', - url: treeChildrenUrl + '&all=true', - // type: 'all', + url: `${treeChildrenUrl}&all=${operateType !== 'move'}`, cache: true, scroll: '#moveFileTreeBox', width: '100%', @@ -765,57 +712,32 @@ function startRender() { checkbarType: 'only', checkbarFun: { chooseBefore: function ($i, node) { - if (node.id == DIR_ROOT_ID) { + const chooseDir = node.basicData; + if (node.id === DIR_ROOT_ID && (operateType === 'link')) { showErrorMsg('不能选择根节点!') return false; } - if (data[0].parentId == node.id) { - showErrorMsg('不能选择自己!') - return false; - } - if (data[0].id == node.parentId) { - showErrorMsg('该节点已存在!') - return false; + if (chooseBeforeHandler) { + return chooseBeforeHandler(node); } // 选中前的回调 return true; }, - chooseDone: function (nodes) { //复选框点击事件完毕后,返回该树关于复选框操作的全部信息。 + chooseDone: function (nodes) { // 选中后的回调 - nodes = nodes || []; - copyItems = nodes.map(node => { - let basicData = node.basicData || {}; - let {id, parentId, directoryType, resourceId} = basicData; - const resourceTypes = ['METADATA', 'LINK_METADATA', 'FILE', 'LINK_FILE']; - if (resourceTypes.includes(directoryType)) { - id = resourceId; - } - return {id, directoryType, parentId}; - }).filter(id => id !== DIR_ROOT_ID); + selectNodes = nodes || []; } }, done: res => { + } }); }, yes: function (index) { - let params = {targetId: copyItems[0].id, items: []} - for (var i = 0; i < data.length; i++) { - params.items.push({id: data[i].directoryId, directoryType: 'FILE', parentId: ''}) - } - Util.post('/business/directory/move', params).then(res => { - if (res.flag) { - showOkMsg('保存成功'); - window.location.reload() - } else { - showErrorMsg(); - } - }) - resolve && resolve(); layer.close(index); + resolve(selectNodes); }, cancel: function (index) { - reject && reject(); layer.close(index); } }) @@ -942,3 +864,43 @@ function startRender() { initViewDirectoryTree(); } + +/** + * 关联资源 + * @param sourceId 源资源ID + * @param targetId 目标资源ID + */ +function linkResource(sourceId, targetId) { + const params = {targetId, sourceId}; + return new Promise((resolve, rejects) => { + Util.post('/business/directory/link', params).then(res => { + if (res.flag) { + showOkMsg('保存成功'); + resolve(res); + } else { + showErrorMsg(); + rejects(); + } + }).catch(rejects); + }) +} + +/** + * 移动资源 + * @param sourceIds 源资源id集合 + * @param targetId 目标id + */ +function moveResource(sourceIds, targetId) { + const params = {targetId, sourceIds}; + return new Promise((resolve, rejects) => { + Util.post('/business/directory/move', params).then(res => { + if (res.flag) { + showOkMsg('保存成功'); + resolve(res); + } else { + showErrorMsg(); + rejects(); + } + }).catch(rejects); + }) +} \ No newline at end of file diff --git a/shandan-system/src/main/java/com/keyware/shandan/bianmu/service/DirectoryTreeService.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/service/DirectoryTreeService.java index a5434d8..47a642b 100644 --- a/shandan-system/src/main/java/com/keyware/shandan/bianmu/service/DirectoryTreeService.java +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/service/DirectoryTreeService.java @@ -50,11 +50,15 @@ public class DirectoryTreeService { public List tree(String parentId, String reviewStatus, boolean hasMetadata, String permis, boolean allChild, int busType) { final String pid = StringUtils.hasText(parentId) ? parentId : ""; DirectoryVo parentDir = null; + DirectoryVo linkSourceDir = null; if (StringUtils.hasText(pid)) { parentDir = directoryService.getById(pid); + if (parentDir != null && parentDir.getDirectoryType() == DirectoryType.LINK_DIR) { + linkSourceDir = directoryService.getById(parentDir.getResourceId()); + } } // 获取子级节点 - List directoryList = getDirectoryList(parentDir, allChild, hasMetadata, busType); + List directoryList = getDirectoryList(linkSourceDir == null ? parentDir : linkSourceDir, allChild, hasMetadata, busType); // 审核状态 ReviewStatus status = StringUtils.hasText(reviewStatus) ? ReviewStatus.valueOf(reviewStatus) : null; // 当前用户 @@ -94,10 +98,20 @@ public class DirectoryTreeService { // 转换为Dtree对象 List treeVoList = StreamUtil.as(dpb.build().get()).map(DirectoryUtil::dir2Tree).toList(); + boolean isLink = linkSourceDir != null; + String nodeParentId = isLink ? linkSourceDir.getId() : pid, + replacePath = isLink ? linkSourceDir.getDirectoryPath() : null, + sourcePath = isLink ? parentDir.getDirectoryPath() : null; // 构建树形结构 - treeVoList = StreamUtil.as(TreeUtil.buildDirTree(treeVoList, pid)) + treeVoList = StreamUtil.as(TreeUtil.buildDirTree(treeVoList, nodeParentId)) // 过滤根节点的垃圾数据 - .filter(dir -> (dir.getParentId().equals(pid))) + .filter(dir -> (dir.getParentId().equals(nodeParentId))) + .peek(dir -> { + if (isLink) { + String path = dir.getPath(); + dir.setPath(path.replace(replacePath, sourcePath)); + } + }) .toList(); return treeVoList.stream().filter(tree -> !tree.getId().equals("ROOT_THEME")).collect(Collectors.toList());