调试关联目录文件功能

master
guoxin 1 year ago
parent 32960b1b01
commit 4e9aa4aab8
  1. 78
      shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/controller/DirectoryController.java
  2. 2
      shandan-bianmu/src/main/java/com/keyware/shandan/bianmu/dto/DirOperateDTO.java
  3. 284
      shandan-bianmu/src/main/resources/static/js/business/directory/directory.js
  4. 20
      shandan-system/src/main/java/com/keyware/shandan/bianmu/service/DirectoryTreeService.java

@ -1,7 +1,7 @@
package com.keyware.shandan.bianmu.controller; package com.keyware.shandan.bianmu.controller;
import cn.hutool.core.bean.BeanUtil; 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.entity.DirectoryVo;
import com.keyware.shandan.bianmu.enums.DirectoryType; import com.keyware.shandan.bianmu.enums.DirectoryType;
import com.keyware.shandan.bianmu.enums.ReviewStatus; import com.keyware.shandan.bianmu.enums.ReviewStatus;
@ -18,13 +18,11 @@ import com.keyware.shandan.system.service.SysFileService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
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.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -149,35 +147,39 @@ public class DirectoryController extends BaseController<DirectoryService, Direct
/** /**
* 关联其他目录以及数据 * 关联其他目录以及数据
* *
* @param dirCopy 关联参数 * @param targetId
* @param sourceId
* @return * @return
*/ */
@PostMapping("/copy") @PostMapping("/link")
public Result<Object> dirCopy(DirCopyDTO dirCopy) { public Result<Object> dirCopy(@RequestBody String targetId, @RequestBody String sourceId) {
saveLinkDirTree(dirCopy.getTree(), dirCopy.getTargetId()); saveLinkDirTree(sourceId, targetId);
dirPermissionService.refreshCache(); dirPermissionService.refreshCache();
return Result.of(true); return Result.of(true);
} }
/**
* @param targetId
* @param sourceIds
* @return
*/
@PostMapping("/move") @PostMapping("/move")
public Result<Object> dirMove(DirCopyDTO copyObj) { public Result<Object> dirMove(@RequestBody String targetId, @RequestBody String sourceIds) {
DirectoryVo targetDir = directoryService.getById(copyObj.getTargetId()); DirectoryVo targetDir = directoryService.getById(targetId);
DirectoryVo sourceDir = directoryService.getById(copyObj.getRoots().get(0).getId()); List<String> idList = Arrays.asList(sourceIds.split(","));
copyObj.getRoots().forEach(item -> { List<DirectoryVo> sourceDirs = directoryService.listByIds(idList);
DirectoryVo dir = directoryService.getById(item.getId()); for (DirectoryVo dir : sourceDirs) {
DirectoryVo newDir = new DirectoryVo(); DirectoryVo newDir = new DirectoryVo();
BeanUtil.copyProperties(dir, newDir); BeanUtil.copyProperties(dir, newDir);
newDir.setParentId(targetDir.getId()); newDir.setParentId(targetDir.getId());
replaceNewAttribute(newDir, sourceDir, targetDir); replaceNewAttribute(newDir, dir, targetDir);
directoryService.updateById(newDir); directoryService.updateById(newDir);
//List<DirectoryVo> children = directoryService.childrenLists(dir);
//2023/1/5 移动目录时,修改目录下文件所属目录
List<DirectoryVo> children = directoryService.allChildrenLists(dir); List<DirectoryVo> children = directoryService.allChildrenLists(dir);
children.forEach(child -> { children.forEach(child -> {
replaceNewAttribute(child, sourceDir, targetDir); replaceNewAttribute(child, dir, targetDir);
}); });
directoryService.updateBatchById(children); directoryService.updateBatchById(children);
}); }
dirPermissionService.refreshCache(); dirPermissionService.refreshCache();
return Result.of("成功"); return Result.of("成功");
} }
@ -185,18 +187,20 @@ public class DirectoryController extends BaseController<DirectoryService, Direct
/** /**
* 保存软连接目录树 * 保存软连接目录树
* *
* @param items 目录树 * @param sourceId
* @param parentId 父级ID * @param targetId
*/ */
private void saveLinkDirTree(List<DirCopyDTO.Item> items, String parentId) { private void saveLinkDirTree(String sourceId, String targetId) {
if (items != null && items.size() > 0) { DirectoryVo sourceDir = directoryService.getById(sourceId);
items.forEach(item -> { DirectoryVo dir;
DirectoryVo dir = buildLinkDir(item, parentId); if (DirectoryType.METADATA == sourceDir.getDirectoryType() || DirectoryType.LINK_METADATA == sourceDir.getDirectoryType()) {
directoryService.save(dir); dir = directoryBuilder.buildMetadataLinkDir(targetId, sourceDir.getId());
log.debug("保存目录:{}", dir.toString()); } else if (DirectoryType.FILE == sourceDir.getDirectoryType() || DirectoryType.LINK_FILE == sourceDir.getDirectoryType()) {
saveLinkDirTree(item.getChildren(), dir.getId()); 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<DirectoryService, Direct
current.setPermisChild(target.getPermisChild());*/ current.setPermisChild(target.getPermisChild());*/
} }
/**
* 生成软连接目录
*
* @param item 参数
* @param parentId 父级ID
* @return
*/
private DirectoryVo buildLinkDir(DirCopyDTO.Item item, String parentId) {
if (DirectoryType.METADATA == item.getDirectoryType() || DirectoryType.LINK_METADATA == item.getDirectoryType()) {
return directoryBuilder.buildMetadataLinkDir(parentId, item.getId());
} else if (DirectoryType.FILE == item.getDirectoryType() || DirectoryType.LINK_FILE == item.getDirectoryType()) {
return directoryBuilder.buildFileLinkDir(parentId, item.getId());
} else {
return directoryBuilder.buildLinkDir(parentId, item.getId());
}
}
} }

@ -16,7 +16,7 @@ import java.util.List;
* 目录复制功能接口数据传输对象 * 目录复制功能接口数据传输对象
*/ */
@Data @Data
public class DirCopyDTO implements Serializable { public class DirOperateDTO implements Serializable {
private static final long serialVersionUID = 6457656734510446800L; private static final long serialVersionUID = 6457656734510446800L;

@ -49,7 +49,7 @@ function startRender() {
}, function (res) { }, function (res) {
if (res.flag) { if (res.flag) {
layer.msg('保存成功'); layer.msg('保存成功');
refreshPermis().then(()=>{ refreshPermis().then(() => {
layer.close(index); layer.close(index);
refreshDirectoryNode(tempNode, res.data); refreshDirectoryNode(tempNode, res.data);
callback && callback(); callback && callback();
@ -152,32 +152,30 @@ function startRender() {
* 增加移动文件功能 * 增加移动文件功能
*/ */
metaListTable.addTableRowEvent('moveLink', function () { metaListTable.addTableRowEvent('moveLink', function () {
var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'), data = checkStatus.data; var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'),
if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')){ datas = checkStatus.data || [];
layer.msg('没有权限'); if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')) {
return; showErrorMsg('没有权限');
return false;
} }
if (data.length < 1) { if (datas.length === 0) {
layer.confirm("请选择要移动的文件!", function (index) { showErrorMsg('请选择要移动的文件');
layer.close(index); return false;
return;
})
} else {
layer.confirm('是否确定移动该数据?', {}, function (index) {
layer.close(index);
moveData();
})
} }
function moveData() { const ids = datas.map(data => data.directoryId);
openDirectoryMoveLayer(data).then(res => { const parentIdSet = new Set();
refreshPermis().then(() => { datas.forEach(data => parentIdSet.add(data.parentId))
metaListTable.reloadTable(); openDirectorySelectLayer('move', (node)=>{
}) if([...parentIdSet.values()].includes(node.id)){
}).catch(e => { 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) { metaListTable.addTableRowEvent('removeLink', function (obj) {
if (basicData.reviewStatus === ReviewStatus.PASS) { if (basicData.reviewStatus === ReviewStatus.PASS) {
@ -193,7 +191,7 @@ function startRender() {
Util.send(`/business/directory/delete/${obj.directoryId}`, {}, 'delete').then(res => { Util.send(`/business/directory/delete/${obj.directoryId}`, {}, 'delete').then(res => {
if (res.flag) { if (res.flag) {
showOkMsg('删除成功'); showOkMsg('删除成功');
refreshPermis().then(()=>{ refreshPermis().then(() => {
metaListTable.reloadTable(); metaListTable.reloadTable();
//refreshDirectoryNode(tempNode, res.data); //refreshDirectoryNode(tempNode, res.data);
}) })
@ -228,7 +226,7 @@ function startRender() {
}) })
function upload(basicData, url, callback) { 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('没有权限'); layer.msg('没有权限');
return; return;
} }
@ -297,7 +295,7 @@ function startRender() {
}, },
}); });
}else{ } else {
showErrorMsg('数据表不支持下载'); showErrorMsg('数据表不支持下载');
} }
}) })
@ -514,14 +512,24 @@ function startRender() {
title: "移动目录", title: "移动目录",
handler: function (node, elem) { handler: function (node, elem) {
const {basicData, id, parentId, context} = node; const {basicData, id, parentId, context} = node;
openDirectoryCopyLayer(basicData, 'move').then(res => { openDirectorySelectLayer('move', (node) => {
refreshPermis().then(() => { if (node.id === id) {
dirTree.partialRefreshAdd(elem); 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(); metaListTable.reloadTable();
}) }));
}).catch(e => { });
})
} }
}, },
{ {
@ -556,14 +564,29 @@ function startRender() {
title: "关联目录或文件", title: "关联目录或文件",
handler: function (node, elem) { handler: function (node, elem) {
const {basicData, id, parentId, context} = node; const {basicData, id, parentId, context} = node;
openDirectoryCopyLayer(basicData).then(res => { openDirectorySelectLayer('link', (node)=>{
refreshPermis().then(() => { if(node.id === id){
dirTree.partialRefreshAdd(elem); showErrorMsg('不能选择自己');
metaListTable.reloadTable(); return false;
}) }
}).catch(e => { 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(); dom.click();
} }
let copyItems = []; function openDirectorySelectLayer(operateType, disabledIds) {
let chooseBeforeHandler, selectNodes = [];
function openDirectoryCopyLayer(dirData, isMove) { if (disabledIds instanceof Function) {
return new Promise(((resolve, reject) => { chooseBeforeHandler = disabledIds;
layer.open({ disabledIds = undefined;
type: 1, }
title: isMove ? '请选择目标目录' : '选择目录资源',
area: ['700px'],
btn: ['保存', '取消'],
content: `<div style="width: 100%; height: 700px; border-bottom: 1px solid #eee;" id="copyDirTreeBox"><ul id="copyDirTree"></ul></div>`,
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 openDirectoryMoveLayer(data) {
return new Promise(((resolve, reject) => { return new Promise(((resolve, reject) => {
let directorySelectTree;
layer.open({ layer.open({
type: 1, type: 1,
title: '请选择目标目录', title: '请选择目录',
area: ['700px'], area: ['700px'],
btn: ['保存', '取消'], btn: ['保存', '取消'],
content: `<div style="width: 100%; height: 700px; border-bottom: 1px solid #eee;" id="moveFileTreeBox"><ul id="moveFileTree"></ul></div>`, content: `<div style="width: 100%; height: 700px; border-bottom: 1px solid #eee;" id="moveFileTreeBox"><ul id="moveFileTree"></ul></div>`,
success: function (layerObj, index) { success: function (layerObj, index) {
let moveFileTreeOps = globalTree.init({ directorySelectTree = globalTree.init({
id: 'moveFileTree', id: 'moveFileTree',
url: treeChildrenUrl + '&all=true', url: `${treeChildrenUrl}&all=${operateType !== 'move'}`,
// type: 'all',
cache: true, cache: true,
scroll: '#moveFileTreeBox', scroll: '#moveFileTreeBox',
width: '100%', width: '100%',
@ -765,57 +712,32 @@ function startRender() {
checkbarType: 'only', checkbarType: 'only',
checkbarFun: { checkbarFun: {
chooseBefore: function ($i, node) { chooseBefore: function ($i, node) {
if (node.id == DIR_ROOT_ID) { const chooseDir = node.basicData;
if (node.id === DIR_ROOT_ID && (operateType === 'link')) {
showErrorMsg('不能选择根节点!') showErrorMsg('不能选择根节点!')
return false; return false;
} }
if (data[0].parentId == node.id) { if (chooseBeforeHandler) {
showErrorMsg('不能选择自己!') return chooseBeforeHandler(node);
return false;
}
if (data[0].id == node.parentId) {
showErrorMsg('该节点已存在!')
return false;
} }
// 选中前的回调 // 选中前的回调
return true; return true;
}, },
chooseDone: function (nodes) { //复选框点击事件完毕后,返回该树关于复选框操作的全部信息。 chooseDone: function (nodes) {
// 选中后的回调 // 选中后的回调
nodes = nodes || []; selectNodes = 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 => { done: res => {
} }
}); });
}, },
yes: function (index) { 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); layer.close(index);
resolve(selectNodes);
}, },
cancel: function (index) { cancel: function (index) {
reject && reject();
layer.close(index); layer.close(index);
} }
}) })
@ -942,3 +864,43 @@ function startRender() {
initViewDirectoryTree(); 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);
})
}

@ -50,11 +50,15 @@ public class DirectoryTreeService {
public List<TreeVo> tree(String parentId, String reviewStatus, boolean hasMetadata, String permis, boolean allChild, int busType) { public List<TreeVo> tree(String parentId, String reviewStatus, boolean hasMetadata, String permis, boolean allChild, int busType) {
final String pid = StringUtils.hasText(parentId) ? parentId : ""; final String pid = StringUtils.hasText(parentId) ? parentId : "";
DirectoryVo parentDir = null; DirectoryVo parentDir = null;
DirectoryVo linkSourceDir = null;
if (StringUtils.hasText(pid)) { if (StringUtils.hasText(pid)) {
parentDir = directoryService.getById(pid); parentDir = directoryService.getById(pid);
if (parentDir != null && parentDir.getDirectoryType() == DirectoryType.LINK_DIR) {
linkSourceDir = directoryService.getById(parentDir.getResourceId());
}
} }
// 获取子级节点 // 获取子级节点
List<DirectoryVo> directoryList = getDirectoryList(parentDir, allChild, hasMetadata, busType); List<DirectoryVo> directoryList = getDirectoryList(linkSourceDir == null ? parentDir : linkSourceDir, allChild, hasMetadata, busType);
// 审核状态 // 审核状态
ReviewStatus status = StringUtils.hasText(reviewStatus) ? ReviewStatus.valueOf(reviewStatus) : null; ReviewStatus status = StringUtils.hasText(reviewStatus) ? ReviewStatus.valueOf(reviewStatus) : null;
// 当前用户 // 当前用户
@ -94,10 +98,20 @@ public class DirectoryTreeService {
// 转换为Dtree对象 // 转换为Dtree对象
List<TreeVo> treeVoList = StreamUtil.as(dpb.build().get()).map(DirectoryUtil::dir2Tree).toList(); List<TreeVo> 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(); .toList();
return treeVoList.stream().filter(tree -> !tree.getId().equals("ROOT_THEME")).collect(Collectors.toList()); return treeVoList.stream().filter(tree -> !tree.getId().equals("ROOT_THEME")).collect(Collectors.toList());