element tree控件制作文件目录 .net core 3.1
对于core 3.1 来说我们.net中常用的取文件的虚拟目录是没发用的例如:
Request.MapPath("");
所以对于core来说我们只能在项目跑起来的时候告诉它,我们站点有这么一个虚拟文件夹,这个文件夹对应我们项目的真实物理路径文件夹,所以我们可以在我们的appsettings.json当中写好我们的配置
*记住以下真实路径在电脑中一定要存在,如果不存在的话项目跑起来的时候会报错的,发布项目如果碰见了 500.30 报错的话请检查你的路径
"VirtualPath": [
{
"RealPath": "E:\\trunk\\Site\\Site_NetCore\\SafetoForwarder\\upload\\Files", //真实路径
"RequestPath": "/upload",
"Alias": "jw"
},
{
"RealPath": "E:\\Pub\\Resource_Dev_Pub\\Files", //真实路径
"RequestPath": "/upload",
"Alias": "dev"
},
{
"RealPath": "E:\\Pub\\Resource_Dev_Pub\\Files", //真实路径
"RequestPath": "/upload",
"Alias": "dev_pub"
}
] // 配置虚拟路径对应真实路径
为了我们可以随意的调用我们配置好的多个虚拟路径这时我们应该对应配置文件写对应的Model:
public class PathConten
{
/// <summary>
/// 物理真实地址
/// </summary>
public string RealPath { get; set; }
/// <summary>
/// 请求地址
/// </summary>
public string RequestPath { get; set; }
/// <summary>
/// 地址对应别名
/// </summary>
public string Alias { get; set; }
}
/// <summary>
/// 映射实体
/// </summary>
public class VirtualPathConfig
{
public List<PathConten> VirtualPath { get; set; }
}
上面我们虚拟路径对应真实路径的配置这一块就完成了,下一步,我们需要将这个路径配置告诉我们项目吧,接下来我们就需要对我们项目进行注册将真实物理路径注册为虚拟路径的这么一个服务。
在注册之前我们需要写好我们路径转化的提供者:
public class FileProvider : PhysicalFileProvider
{
public FileProvider(string root, string alias) : base(root)
{
this.Alias = alias;
}
public FileProvider(string root, Microsoft.Extensions.FileProviders.Physical.ExclusionFilters filters, string alias) : base(root, filters)
{
this.Alias = alias;
}
/// <summary>
/// 别名
/// </summary>
public string Alias { get; set; }
}
完成这些之后呢,再将我们的提供者进行服务注入在Startup的配置服务当中ConfigureServices
#region 将真实物理路径注册为虚拟路径
services.Configure<VirtualPathConfig>(Configuration);
var config = Configuration.Get<VirtualPathConfig>().VirtualPath;
config.ForEach(d =>
{
services.AddSingleton(new FileProvider(d.RealPath, d.Alias));
});
#endregion
在之后我们要讲这个服务启动起来吧 Configure。
记住我们的 app.UseStaticFiles();一定要写上,这是取静态文件的
app.UseStaticFiles();// 静态文件(H5,js,css等)
var config = Configuration.Get<VirtualPathConfig>().VirtualPath;
config.ForEach(d =>
{
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(d.RealPath),
RequestPath = d.RequestPath
});
});
完成这些之后呢,那我们虚拟路径是已经完成设置了。接下来就是取文件目录的正式代码:
首先我们需要取到我们已经设置好的虚拟路径:
public class FileStoreController : BaseController
{
// 在statups当中已经配置好的文件路径数据
private readonly VirtualPathConfig virtualPathConfig;
private int oldLevel;
// 文件基地址
private string fileBaseUrl = "";
public FileStoreController(IOptions<VirtualPathConfig> options)
{
virtualPathConfig = options.Value;
fileBaseUrl = virtualPathConfig.VirtualPath.Find(d => d.Alias.Contains(SiteHelper.ENV))?.RealPath;
}
}
接下来可以写好一个你们前台需要文件属性的一个model:
/// <summary>
/// 显示文件夹目录
/// </summary>
public class FileDirectoryModel
{
/// <summary>
/// 当前文件名显示等级
/// </summary>
public int Level { get; set; }
/// <summary>
/// 当前文件父级文件夹名称
/// </summary>
public string ParentName { get; set; }
/// <summary>
/// 文件名称
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 当前文件是否为文件夹
/// </summary>
public int IsDirectory { get; set; }
/// <summary>
/// 实体路径
/// </summary>
public string EntityPath { get; set; }
}
取到你想要的文件夹中所有的文件夹包括文件:
/// <summary>
/// 获取文件夹目录
/// </summary>
/// <param name="jobNo"></param>
/// <returns></returns>
[HttpGet]
public IActionResult GetFileDirectory(string jobNo)
{
var _result = new ApiResponseMsg { success = true };
string msg = string.Empty;
string filePath = IO.Path.Combine(fileBaseUrl + "\\Erp", jobNo);
// 创建文件目录
msg = CreateFolder(filePath);
// 记录当前路径下所有文件
var fileDirectoruList = new List<FileDirectoryModel>();
IO.DirectoryInfo folder = new IO.DirectoryInfo(filePath);
#region 获取folder下所有的文件
var _cloneFileDirModel = new FileDirectoryModel { IsDirectory = 0 };
_cloneFileDirModel.Level = 0;
_cloneFileDirModel.FileName = folder.Name;
_cloneFileDirModel.EntityPath = folder.FullName.Split("Files")[1];
fileDirectoruList.Add(_cloneFileDirModel);
AddFiles(folder, 0, ref fileDirectoruList);
#endregion
// 获取当前文件夹下所有子文件夹
var dirInfo = folder.GetDirectories();
if (dirInfo.Length > 0)
{
GetFileDirList(dirInfo, 1, ref fileDirectoruList);
}
_result.data = fileDirectoruList;
return Json(_result);
}
/// <summary>
/// 获取文件夹List
/// </summary>
/// <param name="dirInfo"></param>
/// <param name="fileDirectoruList"></param>
/// <param name="level"></param>
/// <returns></returns>
private void GetFileDirList(IO.DirectoryInfo[] dirInfo, int level, ref List<FileDirectoryModel> fileDirectoruList)
{
try
{
foreach (var item in dirInfo)
{
oldLevel = level;
var _cloneFileDirModel = new FileDirectoryModel { IsDirectory = 0 };
_cloneFileDirModel.FileName = item.Name;
_cloneFileDirModel.Level = level;
_cloneFileDirModel.EntityPath = item.FullName.Split("Files")[1];
_cloneFileDirModel.ParentName = item.Parent.Name;
if (item.GetDirectories().Length > 0)
{
// 递归回调
GetFileDirList(item.GetDirectories(), ++oldLevel, ref fileDirectoruList);
}
fileDirectoruList.Add(_cloneFileDirModel);
AddFiles(item, level, ref fileDirectoruList);
}
}
catch (Exception ex)
{
Common.LogAppMsg("FileStoreController", "GetFileDirList", Common.FormatErrMsg(ex));
throw;
}
}
/// <summary>
/// 获取文件夹中的文件list
/// </summary>
/// <param name="directoryInfo"></param>
/// <param name="level"></param>
/// <param name="fileDirectoryModels"></param>
private void AddFiles(IO.DirectoryInfo directoryInfo, int level, ref List<FileDirectoryModel> fileDirectoryModels)
{
level++;
var _fileDirModels = new List<FileDirectoryModel>();
directoryInfo.GetFiles().ToList().ForEach(item =>
{
var _cloneFileDirModel = new FileDirectoryModel { IsDirectory = 1 };
_cloneFileDirModel.Level = level;
_cloneFileDirModel.ParentName = IO.Directory.GetParent(item.FullName).Name;
_cloneFileDirModel.EntityPath = item.FullName.Split("Files")[1];
_cloneFileDirModel.FileName = item.Name;
_fileDirModels.Add(_cloneFileDirModel);
});
if (_fileDirModels.Count > 0)
fileDirectoryModels = fileDirectoryModels.Concat(_fileDirModels).ToList();
}
就这样简单的文件目录其实已经出来了,这时我们需要和我们的前台代码进行结合,页面有点丑但是还是可以优化了,这一块没花什么时间先贴前台代码吧:
<div v-loading="isLoading" class="comp-tree erp-upLoad" @@click="hiddenMenu" Height="8200">
<el-tree :props="props"
:load="loadNode"
@@node-contextmenu="rightClick"
lazy>
<div class="comp-tr-node" slot-scope="{ node, data }">
<!-- 编辑状态 -->
<template v-if="node.isEdit">
<el-input v-model="data.fileName"
autofocus
size="mini"
:ref="'slotTreeInput'+ node.id"
@@keyup.enter.native="handleInput(node, data)"
@@blur="handleInput(node, data)">
</el-input>
</template>
<!-- 非编辑状态 -->
<template v-else>
<!-- 名称: 新增节点增加class(is-new) -->
<span>
<span v-if="data.isDirectory">
<el-button type="text"
size="mini"
@@click="() => handleFilePreview(data)">
{{ node.label }}
</el-button>
</span>
<span v-else class="el-icon-folder">
{{ node.label }}
</span>
</span>
</template>
</div>
</el-tree>
<!-- 鼠标右键产生的选项 -->
<div v-show="menuVisible" id="menu">
<el-menu class="el-menu-vertical rightClickMenu"
@@select="handleRightSelect"
text-color="#303133"
active-text-color="#303133">
<el-menu-item index="0" class="menuItem">
<el-upload class="upload-demo"
action="#"
auto-upload
multiple
:http-request="handleUploadFile"
:before-upload="handleBeforeUpload"
:data="{IsUploadFile:0,ParentPath:DATA.entityPath,Level:NODE.level}">
<i class="el-icon-upload2"> <span slot="title">添加文件</span></i>
@*<el-button size="small" type="primary">添加文件</el-button>*@
</el-upload>
</el-menu-item>
<el-menu-item index="4" class="menuItem" v-if="DATA.isDirectory">
<i class="el-icon-download"></i>
<span slot="title">下载</span>
</el-menu-item>
<el-menu-item index="1" class="menuItem">
<i class="el-icon-edit"></i>
<span slot="title">重命名</span>
</el-menu-item>
<el-menu-item index="2" class="menuItem">
<i class="el-icon-folder-add"></i>
<span slot="title">新建文件夹</span>
</el-menu-item>
<el-menu-item index="3" class="menuItem">
<i class="el-icon-delete"></i>
<span slot="title">删除</span>
</el-menu-item>
</el-menu>
</div>
@*上传文件查看模态窗*@
<el-dialog :visible.sync="fileVisible" append-to-body :close-on-click-modal="false">
<img width="100%" :src="dialogFileUrl" alt="">
</el-dialog>
</div>
JS
var vm = new Vue({
el: '#app',
data: {
isLoading: false, // 是否加载
menuVisible: false, // 菜单展示弹窗
objectID: null, // 当前树节点记录ID
DATA: {}, // 当前右击节点对应数据
NODE: {}, // 当前右击节点node
MAX_LEVEL: 4, // 允许文件存在最大层数
fileData: [], // 所有文件名Data
props: {
label: 'fileName',
children: 'children',
isLeaf: 'leaf'
},
treeModel: {
children: [], // 当下子节点
fileName: "", // 文件名称
isDirectory: "", // 当前是都为文件夹
entityPath: "", // 文件的实体路径
leaf: false, // 是否无子节点
},
oldFileName: "", // 旧的文件名称
dialogFileUrl: "", // 模态窗文件显示路径
fileVisible: false, // 文件显示窗是否打开
folderName: "新建文件夹", // 记录新建文件夹名称
subscript: 1 // 重复文件下标
},
created: function () {
var _self = this;
$.ajax({
type: 'get',
url: "/FileStore/GetFileDirectory",
data: {
jobNo: "CM2008KJ080"
},
success: function (cndata) {
if (cndata.success) {
_self.fileData = cndata.data;
} else {
ChkUtil.Tip(cndata.msg);
}
},
async: false
});
},
watch: {
},
computed: {
},
mounted: function () {
},
methods: {
/**
* 管理权限组树状图懒加载
* @param {any} node
* @param {any} resolve
*/
loadNode: function (node, resolve) {
var _self = this;
var treeList = [];
var _cloneTree = deepClone(_self.treeModel);
if (node.level === 0) {
var _dataList = _self.fileData.filter(d => d.Level == 0);
_dataList.forEach(item => {
_cloneTree.fileName = item.FileName;
_cloneTree.isDirectory = item.IsDirectory;
_cloneTree.entityPath = item.EntityPath;
_cloneTree.leaf = false;
treeList.push(deepClone(_cloneTree));
});
} else {
var _dataList = _self.fileData.filter(d => d.ParentName === node.data.fileName);
_dataList.forEach(item => {
_cloneTree.fileName = item.FileName;
_cloneTree.isDirectory = item.IsDirectory;
_cloneTree.entityPath = item.EntityPath;
_cloneTree.leaf = _self.fileData.filter(d => d.ParentName === item.FileName).length < 1;
treeList.push(deepClone(_cloneTree));
});
};
return resolve(treeList);
},
/**
* 修改节点
* @param {any} node
* @param {any} data
*/
handleInput(node, data) {
var _self = this;
// 退出编辑状态
if (node.isEdit) {
_self.$set(node, 'isEdit', false)
}
if (_self.oldFileName === data.fileName) {
} else {
ChkUtil.Ajax("/FileStore/ChangeFileDirectoryName",
"post",
{
entityPath: data.entityPath,
oldFileName: _self.oldFileName,
newFileName: data.fileName
},
function (cndata) {
if (cndata.success) {
data.entityPath = data.entityPath.replace(_self.oldFileName, data.fileName);
//ChkUtil.Tip("重命名成功!");
} else {
//ChkUtil.Tip("重命名失败!");
}
});
}
},
/**
* 重命名方法
* @param {any} node
* @param {any} data
*/
handleEdit(node, data) {
var _self = this;
// 模板文件夹名称不能重命名
if (data.isTemplate === 1) {
_self.$message.error('该文件夹无法重命名');
} else {
// 设置编辑状态
if (!node.isEdit) {
_self.$set(node, 'isEdit', true);
};
// 输入框聚焦
_self.$nextTick(() => {
if (_self.$refs['slotTreeInput' + node.id]) {
_self.$refs['slotTreeInput' + node.id].$refs.input.focus()
}
});
_self.oldFileName = data.fileName;
}
},
/**
* 新增节点
* @param {any} node
* @param {any} data
*/
handleAdd(node, data) {
var _self = this;
// 判断层级
if (node.level >= _self.MAX_LEVEL) {
_self.$message.warning("当前已达到" + _self.MAX_LEVEL + "级,无法新增!");
return false;
};
// 判断字段是否存在
if (!data.children) {
_self.$set(data, 'children', []);
};
// 校验当前文件名在父文件夹中是否重复,并进行修改
var _childData = node.childNodes.length > 0
? node.childNodes
: _self.fileData.filter(d => d.Level == (data.isDirectory ? node.level - 1 : node.level));
_self.checkLoadlRepeat(_childData);
var _parentPath = data.isDirectory
? node.parent.data.entityPath
: data.entityPath;
var _level = data.isDirectory
? node.level
: ++node.level;
// 新增文件夹需要的参数
var _addFloderData = {
file: "",
data: {
IsUploadFile: 1,
ParentPath: _parentPath,
FolderName: _self.folderName,
Level: _level
}
};
// 新增文件夹
interPhyVm.uploadFile(_addFloderData);
var _data = interPhyVm.FileDirList;
if (!ChkUtil.isNull(_data)) {
$.each(_data,
function (idx, item) {
_self.fileData.push(_data);
var _cloneTree = deepClone(_self.treeModel);
_cloneTree.fileName = item.FileName;
_cloneTree.isDirectory = item.IsDirectory;
_cloneTree.entityPath = item.EntityPath;
_cloneTree.leaf = true;
// 新增数据
data.isDirectory
? _self.NODE.parent.data.children.push(deepClone(_cloneTree))
: data.children.push(deepClone(_cloneTree));
});
// 展开节点
data.isDirectory ? node.parent.expand() : node.expand();
}
},
/**
* 校验数据中loadl文件名重复
* @param {any} data
* @param {any} fileName 仅仅针对校验上传文件
*/
checkLoadlRepeat(data, fileName) {
var _self = this;
var isFile = !ChkUtil.isNull(fileName);
var _folderName = isFile
? fileName
: _self.folderName + _self.subscript;
var _dobData = data.filter(d => d.label == _folderName || d.FileName == _folderName);
// 如果为文件时直接返回是否有重复文件
if (isFile) return _dobData.length < 1;
if (_dobData.length < 1) return _self.folderName = _self.folderName + _self.subscript;
_self.subscript++;
_self.checkLoadlRepeat(data);
},
/**
* 删除文件节点
* @param {any} node
* @param {any} data
*/
handleDelete(node, data) {
_self = this;
if (data.children && data.children.length !== 0) {
this.$message.error('此文件夹内含有其他文件夹,不可删除!');
return;
};
var paraData = {
IsDeleteFile: data.isDirectory ? 0 : 1,
ParentPath: node.parent.data.entityPath,
FolderName: data.fileName
};
this.$confirm(`是否删除${node.label}?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
interPhyVm.handleRemove("", paraData);
if (interPhyVm.DeleteSuc) {
var _delData = _self.fileData.filter(d => d.FileName == data.fileName && d.EntityPath == data.entityPath)[0];
ChkUtil.removeFromArr(_self.fileData, _delData);
ChkUtil.removeFromArr(node.parent.childNodes, node);
node.parent.expand();
}
}).catch(() => { });
},
/**
* 鼠标右击事件出现菜单栏
* @param {any} event
* @param {any} object
* @param {any} value
* @param {any} element
*/
rightClick(event, object, value, element) {
var _self = this;
_self.oldFileName = object.fileName;
if (_self.objectID !== value.id) {
_self.objectID = value.id;
_self.menuVisible = true;
_self.DATA = object;
_self.NODE = value;
} else {
_self.menuVisible = !_self.menuVisible;
};
document.addEventListener('click', (e) => {
_self.menuVisible = false;
});
_self.hiddenMenu();
let menu = document.querySelector('.rightClickMenu');
/* 菜单定位基于鼠标点击位置 */
let height = document.documentElement.clientHeight || document.body.clientHeight;
if (event.clientY + 168 > height) {
menu.style.left = event.clientX - 5 + 'px';
menu.style.top = event.clientY - 10 - 168 + 'px';
} else {
menu.style.left = event.clientX + 10 + 'px';
menu.style.top = event.clientY + 5 + 'px';
};
// 为新建的DIV创建绝对定位
menu.style.position = 'fixed';
},
/**
* 鼠标右键选择菜单事件
* @param {any} key
*/
handleRightSelect(key) {
var _self = this;
var _key = parseInt(key);
_self.menuVisible = false;
switch (_key) {
case 1:
_self.handleEdit(_self.NODE, _self.DATA);
break;
case 2:
_self.handleAdd(_self.NODE, _self.DATA);
break;
case 3:
_self.handleDelete(_self.NODE, _self.DATA);
break;
case 4:
_self.handleDownload();
break;
}
},
/*
* 隐藏菜单
*/
hiddenMenu() {
document.addEventListener('click', this.hide, true);
document.removeEventListener('click', this.hide);
},
/**
* 隐藏菜单
*/
hide() {
this.menuVisible = false
},
/**
* 文件预览
* @param {any} file
*/
handleFilePreview: function (data) {
this.dialogFileUrl = `${window.location.origin}/upload${data.entityPath}`;
this.fileVisible = true;
},
/**
* 文件上传
* @param {any} event
*/
handleUploadFile: function (event) {
var _self = this;
interPhyVm.uploadFile(event);
var _data = interPhyVm.FileDirList;
if (!ChkUtil.isNull(_data)) {
var data = _self.DATA;
$.each(_data,
function (idx, item) {
_self.fileData.push(_data);
var _cloneTree = deepClone(_self.treeModel);
_cloneTree.fileName = item.FileName;
_cloneTree.isDirectory = item.IsDirectory;
_cloneTree.entityPath = item.EntityPath;
_cloneTree.leaf = true;
// 新增数据
data.isDirectory
? _self.NODE.parent.data.children.push(deepClone(_cloneTree))
: data.children.push(deepClone(_cloneTree));
});
// 展开节点
data.isDirectory ? _self.NODE.parent.expand() : _self.NODE.expand();
};
},
/**
* 文件上传前校验
* @param {any} file
*/
handleBeforeUpload: function (file) {
var _self = this;
var data = _self.DATA;
var node = _self.NODE;
var _childData = data.isDirectory
? node.parent.childNodes
: (node.childNodes.length > 0
? node.childNodes
: _self.fileData.filter(d => d.Level == node.level)
);
var _hasDobFile = !_self.checkLoadlRepeat(_childData, file.name);
if (_hasDobFile) {
alert("请勿重复上传文件或删除重复文件!");
return false;
}
},
/**
* 文件下载
*/
handleDownload: function () {
var _self = this;
window.open(`${window.location.origin}${downloadFile}?storagePath=${_self.DATA.entityPath}&fileName=${_self.DATA.fileName}`);
}
}
});
这样简单的文件目录就出来了 可以上传文件,下载,重命名,新建文件夹,删除等功能,都已完成,不过还需要做更加详细的优化,有建议大家可以提一下哦