|
|
|
@ -8,7 +8,7 @@ import { getExpirTime, getFileIcon, readableSize} from "./tools" |
|
|
|
import sharePermission from './sharePermission.vue'; |
|
|
|
import { useUserStore } from "@/store/modules/user"; |
|
|
|
import { getMatterList,postCreateDir,postDelMatter,postCreateShare,postMatterRename,postDelMatBatch,getMySpaces,doCreateSpace} from "@/api/doc/index" |
|
|
|
import { matterPage,matterInfo,respCreateShare,matterTree } from "@/api/doc/type" |
|
|
|
import { matterPage,matterInfo,respCreateShare,matterTree, doFileUpload} from "@/api/doc/type" |
|
|
|
import { h } from 'vue' |
|
|
|
import { |
|
|
|
Delete, |
|
|
|
@ -22,8 +22,7 @@ import { |
|
|
|
Avatar, |
|
|
|
Plus |
|
|
|
} from '@element-plus/icons-vue' |
|
|
|
import {ElSelect,ElOption, ElText,ElInput,TableInstance,ElMessage,UploadFile,UploadFiles,ElPagination,ElTree,TreeInstance} from "element-plus"; |
|
|
|
import type { TreeNode } from 'element-plus/es/components/tree/src/tree.type' |
|
|
|
import {ElSelect,ElOption, ElText,ElInput,TableInstance,ElMessage,UploadFile,UploadFiles,ElPagination,ElTree,TreeNode} from "element-plus"; |
|
|
|
import preview from './preview.vue'; |
|
|
|
import space from './space.vue'; |
|
|
|
|
|
|
|
@ -284,9 +283,11 @@ function onLoadMatterList(){ |
|
|
|
getMatterList(uid,_page).then((resp)=>{ |
|
|
|
//page+1 是由于分页的起始index是1,而后端api的分页index起始是0 |
|
|
|
paginInfo.value={total:resp.data.totalPages,page:resp.data.page} |
|
|
|
matterList.value=resp.data.data.filter((item)=>{ |
|
|
|
return !item.dir |
|
|
|
}) |
|
|
|
matterList.value=resp.data.data |
|
|
|
//2025-08-07: 保持space一样,文件夹一并显示 |
|
|
|
// .filter((item)=>{ |
|
|
|
// return !item.dir |
|
|
|
// }) |
|
|
|
}) |
|
|
|
} |
|
|
|
//----------for dir----------- |
|
|
|
@ -338,14 +339,16 @@ function onNodeExpand(node: TreeNode, resolve: (data: matterTree[]) => void, rej |
|
|
|
|
|
|
|
getMatterList(uid, _page).then((resp) => { |
|
|
|
paginInfo.value = { total: resp.data.totalPages, page: resp.data.page } |
|
|
|
matterList.value = resp.data.data.filter((item)=>{ |
|
|
|
return !item.dir |
|
|
|
}) |
|
|
|
matterList.value = resp.data.data |
|
|
|
// .filter((item)=>{ |
|
|
|
// return !item.dir |
|
|
|
// }) |
|
|
|
let node_data = resp.data.data.filter((item) => { |
|
|
|
return item.dir |
|
|
|
}).map((item) => { |
|
|
|
item.dir = !item.dir |
|
|
|
return item |
|
|
|
}).map((val) => { |
|
|
|
const copy = structuredClone(val) |
|
|
|
copy.dir = !copy.dir |
|
|
|
return copy |
|
|
|
}) |
|
|
|
|
|
|
|
resolve(node_data) |
|
|
|
@ -397,6 +400,10 @@ function onNodeClick(data:matterTree,node:TreeNode,self:any,env:any){ |
|
|
|
|
|
|
|
//文件预览 |
|
|
|
function onPrivateView(row:matterInfo){ |
|
|
|
if(row.dir){ |
|
|
|
alert("目录不支持预览") |
|
|
|
return |
|
|
|
} |
|
|
|
let a = `${row.uuid}${row.name}` |
|
|
|
let _token=document.cookie.match(/hxpan=([\w-]*)/) |
|
|
|
if (_token&&_token.length>1){ |
|
|
|
@ -411,6 +418,96 @@ function onPrivateView(row:matterInfo){ |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
//--------------UPGRADE: multy file upload section---------------- |
|
|
|
|
|
|
|
//自定义上传,目的是支持多文件上传, 使用html原生组件,是为了解决并发问题 |
|
|
|
async function onCustomUpload(e:Event){ |
|
|
|
const files = e.target!.files??[] |
|
|
|
for(let ff of files){ |
|
|
|
await handleSingleFile(ff) |
|
|
|
} |
|
|
|
onLoadMatterList() //刷新 |
|
|
|
} |
|
|
|
|
|
|
|
async function handleSingleFile(ff:File){ |
|
|
|
const fields=new FormData() |
|
|
|
fields.append("userUuid",uploadFormData.value.userUuid) |
|
|
|
fields.append("puuid",uploadFormData.value.puuid) |
|
|
|
fields.append("file",ff) |
|
|
|
|
|
|
|
const res = await doFileUpload(fields,'/hxpan/api/matter/upload') |
|
|
|
if(res.code!=200){ |
|
|
|
console.log(ff.name+"上传失败! ") |
|
|
|
alert(ff.name+"上传失败! ") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//文件夹上传,原理:自定义的input组件,一次拿到所有需要上传的文件列表,然后依次上传 |
|
|
|
//能减少并发问题 |
|
|
|
async function uploadFolder(e:Event){ |
|
|
|
const files = e.target!.files??[] |
|
|
|
for(let f of files){ |
|
|
|
await handleFolderFile(f) |
|
|
|
} |
|
|
|
onLoadMatterList() //刷新 |
|
|
|
} |
|
|
|
|
|
|
|
async function handleFolderFile(option:File){ |
|
|
|
//根据路径,来判断需不需要重建目录 |
|
|
|
const _path = option.webkitRelativePath |
|
|
|
const _dir=_path.replace(/\/[^/]+\w+$/,"") //只保留文件夹目录,[^/]就是用来限制,只能是最后一个目录 |
|
|
|
const node = matterList.value.filter((item)=>{ |
|
|
|
return item.dir && item.path?.endsWith(_dir) |
|
|
|
}) |
|
|
|
|
|
|
|
let puuid="" |
|
|
|
//说明是新的目录,需要新建;如果存在,直接上传文件即可 |
|
|
|
if(node.length==0){ |
|
|
|
const subs= await doCreateMultyDir(_dir,currentNode.value.uuid) |
|
|
|
matterList.value.push(...subs) //这里如果子文件夹多的时候,可能会造成第一级路径多次创建,只是造成资源浪费,问题不大 |
|
|
|
|
|
|
|
const newnodes=matterList.value.filter((item)=>{ |
|
|
|
return item.dir && item.path?.endsWith(_dir) |
|
|
|
}) |
|
|
|
if(newnodes.length>0){ |
|
|
|
puuid=newnodes[0].uuid |
|
|
|
}else{ |
|
|
|
console.log(_path+"上传失败! ") |
|
|
|
alert(_path +" 上传失败! ") |
|
|
|
return |
|
|
|
} |
|
|
|
}else{ |
|
|
|
puuid=node[0].uuid |
|
|
|
} |
|
|
|
|
|
|
|
const fields = new FormData() |
|
|
|
fields.append('file', option) |
|
|
|
fields.append("space",uploadFormData.value.space) |
|
|
|
fields.append("puuid",puuid) |
|
|
|
const res = await doFileUpload(fields,'/hxpan/api/matter/upload') |
|
|
|
if(res.code!=200){ |
|
|
|
console.log(_path+"上传失败! ") |
|
|
|
alert(_path +" 上传失败! ") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//创建多级目录,并返回matterinfos数组 |
|
|
|
async function doCreateMultyDir(path:string,uuid:string){ |
|
|
|
const list=[]; |
|
|
|
const dirs=path.split("/") |
|
|
|
for(let i=0;i<dirs.length;i++){ |
|
|
|
await postCreateDir(uid,{ |
|
|
|
userUuid:uid, |
|
|
|
puuid:uuid, |
|
|
|
name:dirs[i], |
|
|
|
}).then((resp)=> { |
|
|
|
uuid=resp.data.uuid //第一级别的uuid, 是第二级的puuid |
|
|
|
list.push(resp.data) |
|
|
|
}) |
|
|
|
} |
|
|
|
return list |
|
|
|
} |
|
|
|
|
|
|
|
function handleMouseEnter(row:any){ |
|
|
|
currentHoverRow.value=row.name |
|
|
|
} |
|
|
|
@ -419,6 +516,7 @@ function handleSingleUpload(response:any){ |
|
|
|
fileList.value=[] |
|
|
|
onLoadMatterList() |
|
|
|
} |
|
|
|
|
|
|
|
interface uploadError{ |
|
|
|
msg:string |
|
|
|
} |
|
|
|
@ -426,6 +524,9 @@ interface uploadError{ |
|
|
|
function handleSigLoadErr(error: Error, uploadFile: UploadFile, uploadFiles:UploadFiles){ |
|
|
|
ElMessage.error(JSON.parse(error.message).msg) |
|
|
|
} |
|
|
|
//----------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
//-------------------space feature--------------------- |
|
|
|
function onNewSpace(){ |
|
|
|
const newname=ref("") |
|
|
|
@ -451,6 +552,9 @@ function onNewSpace(){ |
|
|
|
} |
|
|
|
|
|
|
|
function onSpaceNodeClick(data:matterTree,node:TreeNode,self:any,env:any){ |
|
|
|
if(PRIVATESPACE.value) { //如果打开了个人空间,突然点击共享空间,要及时切换状态 |
|
|
|
PRIVATESPACE.value=false |
|
|
|
} |
|
|
|
//如果在单个组件上重复点击,不在刷新请求 |
|
|
|
if(spaceNodeUid==data.uuid) return; |
|
|
|
spaceNodeUid=data.uuid |
|
|
|
@ -541,35 +645,39 @@ const handleSelectionChange = (val:matterInfo[]) => { |
|
|
|
<el-link v-if="currentNode.name!=='root'" @click="onNodeClick(treeData[0], null as unknown as TreeNode, null, null)"> |
|
|
|
<span style="font-weight: bold;margin-right: 5px;">根目录</span>/ |
|
|
|
</el-link> |
|
|
|
<span style="font-weight: bold;margin:0 5px;">{{ currentNode.name }}</span> |
|
|
|
<span style="font-weight: bold;margin:0 5px;align-content:center;">{{ currentNode.name }}</span> |
|
|
|
|
|
|
|
<el-col :span="6" class="search"> |
|
|
|
<el-input placeholder="搜索文件" v-model="searchname" @blur="searchname===''?onLoadMatterList():''"/> |
|
|
|
<el-button :icon="Search" @click="onSearchFile(searchname)"></el-button> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
|
|
|
|
<el-row :gutter="24"> |
|
|
|
<el-col :span="14"> |
|
|
|
<el-upload class="el-button el-button--default" :file-list="fileList" |
|
|
|
:data="uploadFormData" |
|
|
|
:on-success="handleSingleUpload" |
|
|
|
:on-error="handleSigLoadErr" |
|
|
|
:show-file-list="false" |
|
|
|
:action="apiURL+'/matter/upload'" :limit="1"> |
|
|
|
<span>上传</span> |
|
|
|
</el-upload> |
|
|
|
<!-- <el-button>上传文件夹</el-button> --> |
|
|
|
<div class="el-button el-button--default" style="position: relative;"> |
|
|
|
<input type="file" style="position: absolute;opacity: 0;width: 50px;" |
|
|
|
@change="onCustomUpload" multiple /> |
|
|
|
文件上传 |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="el-button el-button--default" style="position: relative;"> |
|
|
|
<input type="file" style="position: absolute;opacity: 0;width: 50px;" |
|
|
|
@change="uploadFolder" |
|
|
|
webkitdirectory |
|
|
|
multiple |
|
|
|
/> |
|
|
|
文件夹上传 |
|
|
|
</div> |
|
|
|
<el-button @click="createDir">新建目录</el-button> |
|
|
|
<span v-if="tabSelected.length>1" style="margin:12px"> |
|
|
|
<el-button @click="onShareMatter()">分享</el-button> |
|
|
|
<el-button @click="onDelMatBatch">删除</el-button> |
|
|
|
</span> |
|
|
|
<el-button @click="onLoadMatterList()">刷新</el-button> |
|
|
|
<el-button type="danger" plain @click="onShareMatter({uuid:currentNode.uuid,name:currentNode.name})">分享目录</el-button> |
|
|
|
<el-button type="danger" plain @click="onDelMatter({uuid:currentNode.uuid,name:currentNode.name,dir:true, |
|
|
|
puuid:currentNode.puuid,path:currentNode.path})">删除目录</el-button> |
|
|
|
</el-col> |
|
|
|
|
|
|
|
<el-col :span="8" class="search"> |
|
|
|
<el-input placeholder="搜索文件" v-model="searchname" @blur="searchname===''?onLoadMatterList():''"/> |
|
|
|
<el-button :icon="Search" @click="onSearchFile(searchname)"></el-button> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
|
|
|
|
<el-row :gutter="24" style="height: 84%;overflow-y: auto;"> |
|
|
|
@ -599,7 +707,7 @@ const handleSelectionChange = (val:matterInfo[]) => { |
|
|
|
<el-table-column width="250" align="center"> |
|
|
|
<template #default="scope"> |
|
|
|
<div v-show="currentHoverRow === scope.row.name"> |
|
|
|
<el-button size="small" :icon="Promotion" circle ></el-button> |
|
|
|
<!-- <el-button size="small" :icon="Promotion" circle ></el-button> --> |
|
|
|
<el-button size="small" :icon="View" circle @click="onPrivateView(scope.row)"></el-button> |
|
|
|
<el-button size="small" :icon="Share" circle @click="onShareMatter(scope.row)"></el-button> |
|
|
|
<el-button size="small" :icon="Download" circle @click="onDownload(scope.row)"></el-button> |
|
|
|
@ -658,6 +766,7 @@ const handleSelectionChange = (val:matterInfo[]) => { |
|
|
|
} |
|
|
|
|
|
|
|
.search{ |
|
|
|
margin-left: auto; |
|
|
|
margin-right: 20px; |
|
|
|
display:inherit; |
|
|
|
} |
|
|
|
|