调试关联目录文件功能

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. 264
      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;
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<DirectoryService, Direct
/**
* 关联其他目录以及数据
*
* @param dirCopy 关联参数
* @param targetId
* @param sourceId
* @return
*/
@PostMapping("/copy")
public Result<Object> dirCopy(DirCopyDTO dirCopy) {
saveLinkDirTree(dirCopy.getTree(), dirCopy.getTargetId());
@PostMapping("/link")
public Result<Object> 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<Object> 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<Object> dirMove(@RequestBody String targetId, @RequestBody String sourceIds) {
DirectoryVo targetDir = directoryService.getById(targetId);
List<String> idList = Arrays.asList(sourceIds.split(","));
List<DirectoryVo> 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<DirectoryVo> children = directoryService.childrenLists(dir);
//2023/1/5 移动目录时,修改目录下文件所属目录
List<DirectoryVo> 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<DirectoryService, Direct
/**
* 保存软连接目录树
*
* @param items 目录树
* @param parentId 父级ID
* @param sourceId
* @param targetId
*/
private void saveLinkDirTree(List<DirCopyDTO.Item> 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<DirectoryService, Direct
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
public class DirCopyDTO implements Serializable {
public class DirOperateDTO implements Serializable {
private static final long serialVersionUID = 6457656734510446800L;

@ -152,32 +152,30 @@ function startRender() {
* 增加移动文件功能
*/
metaListTable.addTableRowEvent('moveLink', function () {
var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'), data = checkStatus.data;
var table = layui.table, checkStatus = table.checkStatus('dirMetadataTable'),
datas = checkStatus.data || [];
if (basicData.id === 'ROOT' && !USER_ROLES.includes('ROLE_SA')) {
layer.msg('没有权限');
return;
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) {
@ -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,13 +564,28 @@ function startRender() {
title: "关联目录或文件",
handler: function (node, elem) {
const {basicData, id, parentId, context} = node;
openDirectoryCopyLayer(basicData).then(res => {
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(elem);
dirTree.partialRefreshAdd($(`div[data-id="${id}"]`));
metaListTable.reloadTable();
})
}).catch(e => {
});
});
})
}
},
@ -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: `<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 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: `<div style="width: 100%; height: 700px; border-bottom: 1px solid #eee;" id="moveFileTreeBox"><ul id="moveFileTree"></ul></div>`,
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);
})
}

@ -50,11 +50,15 @@ public class DirectoryTreeService {
public List<TreeVo> 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<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;
// 当前用户
@ -94,10 +98,20 @@ public class DirectoryTreeService {
// 转换为Dtree对象
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();
return treeVoList.stream().filter(tree -> !tree.getId().equals("ROOT_THEME")).collect(Collectors.toList());