From 1689019ff6d33d1566ed24d85bec3538fc13e017 Mon Sep 17 00:00:00 2001 From: han2015 <1019850453@qq.com> Date: Thu, 7 Aug 2025 11:08:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E7=A9=BA=E9=97=B4=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/doc/space.ts | 13 --- src/api/doc/type.ts | 17 +++- src/views/doc/agent.vue | 1 - src/views/doc/manage.vue | 167 ++++++++++++++++++++++++++++++++------- src/views/doc/space.vue | 54 ++++++------- 5 files changed, 178 insertions(+), 74 deletions(-) diff --git a/src/api/doc/space.ts b/src/api/doc/space.ts index 52a8e28..5985b3a 100644 --- a/src/api/doc/space.ts +++ b/src/api/doc/space.ts @@ -31,19 +31,6 @@ export function doCreateSpaceDir(uid:string,data?: createDir){ data: data }); } -/** - * 文件上传 - */ -export function doFileUpload(params:FormData,_url:string): AxiosPromise { - return request({ - url: _url, - method: 'post', - data: params, - headers: { - 'Content-Type': 'multipart/form-data' - } - }); -} export function doCreateAiagent(uid:string,data?: {space:string,matter:string}){ return request({ diff --git a/src/api/doc/type.ts b/src/api/doc/type.ts index d6ef417..1ae85eb 100644 --- a/src/api/doc/type.ts +++ b/src/api/doc/type.ts @@ -3,7 +3,8 @@ * @ 时间: 2025-05-12 15:39:13 * @ 备注: 文档管理api 结构定义 */ - +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; /** * 拉去首页文件列表 */ @@ -74,4 +75,18 @@ export interface respCreateShare{ expireTime?:string; name?:string; uuid?:string; +} + +/** + * 文件上传 + */ +export function doFileUpload(params:FormData,_url:string): AxiosPromise { + return request({ + url: _url, + method: 'post', + data: params, + headers: { + 'Content-Type': 'multipart/form-data' + } + }); } \ No newline at end of file diff --git a/src/views/doc/agent.vue b/src/views/doc/agent.vue index b245509..21ece31 100644 --- a/src/views/doc/agent.vue +++ b/src/views/doc/agent.vue @@ -13,7 +13,6 @@ import {ElText,ElInput, ButtonInstance} from "element-plus"; import { VueMarkdown } from '@crazydos/vue-markdown' import rehypeRaw from 'rehype-raw' import remarkGfm from 'remark-gfm' -import { display } from 'html2canvas/dist/types/css/property-descriptors/display'; //选中的咨询模式 const checkedModel = ref([]) diff --git a/src/views/doc/manage.vue b/src/views/doc/manage.vue index 42086d2..e703cfe 100644 --- a/src/views/doc/manage.vue +++ b/src/views/doc/manage.vue @@ -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 { + 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[]) => { 根目录/ - {{ currentNode.name }} + {{ currentNode.name }} + + + + + - - 上传 - - +
+ + 文件上传 +
+ +
+ + 文件夹上传 +
新建目录 分享 删除 - 刷新 分享目录 删除目录
- - - - -
@@ -599,7 +707,7 @@ const handleSelectionChange = (val:matterInfo[]) => {