You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
834 lines
27 KiB
834 lines
27 KiB
<!--
|
|
@ 作者: han2015
|
|
@ 时间: 2025-05-12 15:39:13
|
|
@ 备注: 共享空间组件
|
|
-->
|
|
<script lang="ts" setup>
|
|
import { getFileIcon, readableSize,fileType} from "./tools"
|
|
import sharePermission from './sharePermission.vue';
|
|
import spacePermission from './spacePermission.vue';
|
|
import { matterPage,matterInfo,matterTree,doFileUpload,matterPermit} from "@/api/doc/type"
|
|
import { doAccessManage,getSpaceMatterList,doCreateSpaceDir,doDelSpaceMatter,
|
|
doAiTraining ,spaceMatterRename} from "@/api/doc/space"
|
|
import { h } from 'vue'
|
|
import {
|
|
Delete,
|
|
View,
|
|
Download,
|
|
Plus,Search,
|
|
Edit,
|
|
Setting,
|
|
Grid,List,
|
|
} from '@element-plus/icons-vue'
|
|
import {ElMessage,UploadFile,UploadFiles,ElPagination, ElProgress} from "element-plus";
|
|
import aiagent from './agent.vue';
|
|
import uploadlog from './uploadlog.vue';
|
|
import router from "@/router";
|
|
import SvgIcon from "@/components/SvgIcon/index.vue";
|
|
import { useOrgMemberStore } from "@/store/modules/orgMember";
|
|
const orgMembers = useOrgMemberStore() //为了初始化
|
|
|
|
const defaultAiAgent=import.meta.env.VITE_DEFAULT_AI_AGENT
|
|
const matterList = ref<matterInfo[]>([])
|
|
const searchname=ref("") //按文件名查找文件
|
|
const newdirName=ref("") //创建新目录时的目录名
|
|
const currentHoverRow=ref("") //table 行的按钮控制
|
|
const breadcrumbList=ref<matterInfo[]>([{name:"根目录",uuid:"root", dir:true}]) //面包屑导航
|
|
|
|
const tabSelected=ref<matterInfo[]>([]) //table组件多选数据维护
|
|
const currentNode=ref<matterInfo>({}) //打开的路径层次
|
|
let isNewNode=true //用来减少父组件树的重置
|
|
|
|
const dynamicVNode = ref<VNode | null>(null) //permission 组件的父组件
|
|
const paginInfo = ref({ page: 0, total: 0 })
|
|
|
|
const CutLevelPermit=ref(0)
|
|
const modListOrGrild=ref(true) //列表显示还是栅格显示
|
|
|
|
const percentage=ref(0)
|
|
const onprogress=ref(true)
|
|
|
|
enum PERMITS {
|
|
FORBID, //0
|
|
VIEW, //1
|
|
DOWNLOAD, //2
|
|
UPLOAD, //3
|
|
UPANDDOWNLOAD, //4
|
|
EDIT, //5
|
|
MANAGER, //6
|
|
}
|
|
|
|
//-----------AI---------------------
|
|
const currentAgent=ref<{model:boolean,name:string,uuid:string,path:string}>({})
|
|
|
|
//---------------------------------
|
|
|
|
const props = withDefaults(defineProps<{
|
|
uid:string, //当前用户的uuid,注意已经且必须通过base64编码,因为后端获取Identifier后,会base64解码
|
|
rawUid:string,
|
|
//tree:object,
|
|
spaceid:string,
|
|
spacename:string,
|
|
officeHost:string,
|
|
siteHost:string,
|
|
owner:string,
|
|
apiURL:string,
|
|
listOrGrid:boolean,
|
|
ismanager:boolean,
|
|
spacePermit:matterPermit,
|
|
|
|
flushSpaceTree:(uuid:string,data:matterTree[])=>void
|
|
}>(),{})
|
|
|
|
//属性变更,特别是为了处理空间切换的状态更新
|
|
watch(props,()=>{
|
|
currentNode.value.uuid="root"
|
|
currentNode.value.name="根目录"
|
|
currentAgent.value.path="root"
|
|
onLoadMatterList()
|
|
})
|
|
|
|
const uploadFormData = computed(() => {
|
|
return {
|
|
space: props.spaceid,
|
|
puuid: currentNode.value.uuid, // 父目录的uuid,基目录为root
|
|
}
|
|
});
|
|
|
|
function updateListOrGrid(val:boolean){
|
|
modListOrGrild.value=val
|
|
if(val){
|
|
localStorage.setItem("listOrGrid","true")
|
|
}else{
|
|
localStorage.setItem("listOrGrid","false")
|
|
}
|
|
}
|
|
|
|
//--------------权限控制&添加空间成员-------------
|
|
function onAccessManage(){
|
|
//迁移到了manage文件中,暂时不需要了
|
|
dynamicVNode.value = h(sharePermission, {
|
|
uid: props.uid,
|
|
uuid: "",
|
|
spaceid:props.spaceid, //
|
|
confirmFunc: (_list: string[],_infos:string[]) => {
|
|
// 组织权限数据
|
|
//_len=_list.length
|
|
let permited = btoa(_list.join("|"))
|
|
doAccessManage(props.uid,{
|
|
"space":props.spaceid,
|
|
"roles":permited,
|
|
"owner":props.owner,
|
|
"len":_list.length
|
|
}).then(()=>{
|
|
|
|
})
|
|
},
|
|
closeFunc: () => {
|
|
dynamicVNode.value=null
|
|
}
|
|
})
|
|
}
|
|
|
|
//文档权限控制管理
|
|
function onSpacePManage(row:matterInfo){
|
|
dynamicVNode.value=h(spacePermission,{
|
|
uid:props.rawUid, //当前用户的uuid
|
|
uuid:row.uuid, //文档的uuid
|
|
suid:props.owner,
|
|
spaceid:props.spaceid, //空间uuid
|
|
closeFunc:()=>dynamicVNode.value=null
|
|
})
|
|
}
|
|
|
|
|
|
//----------------------------------------
|
|
//删除
|
|
function onDelMatter(row:matterInfo){
|
|
if (row.uuid){
|
|
ElMessageBox.confirm(`确认删除( ${row.name}) ?删除后不可恢复!取消则放弃删除操作。`, "警告", {
|
|
confirmButtonText: "确定",
|
|
cancelButtonText: "取消",
|
|
type: "warning",
|
|
}).then(()=>{
|
|
doDelSpaceMatter(props.uid,{
|
|
"uuid":row.uuid,
|
|
"space":props.spaceid,
|
|
}).then(()=>{
|
|
currentNode.value.uuid = row.puuid ?? ""
|
|
onLoadMatterList()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function onDownload(row:matterInfo){
|
|
ElMessageBox.confirm("确认下载此数据项?", "提示", {
|
|
confirmButtonText: "确定",
|
|
cancelButtonText: "取消",
|
|
type: "warning",
|
|
}).then(()=>{
|
|
if (row.uuid){
|
|
let _url= props.apiURL+`/space/download/${row.uuid}/${row.name}?space=${props.spaceid}`
|
|
window.open(_url)
|
|
}
|
|
})
|
|
}
|
|
|
|
//加载目录文件列表
|
|
function onLoadMatterList(name?:string){
|
|
percentage.value=0
|
|
onprogress.value=false
|
|
|
|
let _page: matterPage= {
|
|
page: paginInfo.value.page,
|
|
pageSize: 50,
|
|
orderCreateTime: "DESC",
|
|
orderDir: "DESC",
|
|
puuid:currentNode.value.uuid,
|
|
deleted:false,
|
|
space:props.spaceid,
|
|
};
|
|
|
|
if(name){
|
|
_page={
|
|
pageSize: 50,
|
|
orderCreateTime: "DESC",
|
|
orderDir: "DESC",
|
|
deleted:false,
|
|
name:name,
|
|
space:props.spaceid,
|
|
}
|
|
}
|
|
|
|
|
|
getSpaceMatterList(props.uid,_page).then((resp)=>{
|
|
//page+1 是由于分页的起始index是1,而后端api的分页index起始是0
|
|
paginInfo.value={total:resp.data.totalPages, page:resp.data.page}
|
|
if (props.ismanager) {
|
|
resp.data.data.forEach(item => {
|
|
item.permitVal=PERMITS.MANAGER
|
|
})
|
|
matterList.value=resp.data.data
|
|
}else{
|
|
matterList.value=resp.data.data.filter(item=>{ //具体的权限验证和过滤
|
|
|
|
if(item.permits.ID==0){
|
|
item.permitVal=CutLevelPermit.value
|
|
}else{
|
|
//如果该文档有设定权限,解析该文档的具体权限
|
|
let _pert: Record<string, number>
|
|
_pert = JSON.parse(item.permits!.data)
|
|
let val=_pert[props.rawUid.replace("p0","")]
|
|
if(val){
|
|
item.permitVal = val
|
|
}else{
|
|
item.permitVal = PERMITS.FORBID //没有权限!!
|
|
}
|
|
}
|
|
|
|
if(item.permitVal>0){
|
|
return true
|
|
}
|
|
|
|
return false
|
|
})
|
|
}
|
|
|
|
|
|
//展开的时候暂时不做目录更新,看以后的使用情况
|
|
let node_data = matterList.value.filter(item=> {
|
|
return item.dir
|
|
}).map(val => {
|
|
const copy = structuredClone(toRaw(val))
|
|
copy.dir = !copy.dir
|
|
copy.manager=props.ismanager
|
|
return copy
|
|
})
|
|
|
|
if(isNewNode) {
|
|
//由于支持目录树的原因,所有的空间根目录uuid都是root,这样树组件就有问题,所以用了spaceid作为其uuid
|
|
//但是云盘的根目录是root,所以当uuid是spaceid时,自动替换为root
|
|
if(currentNode.value.uuid=="root") props.flushSpaceTree(props.spaceid,node_data);
|
|
else props.flushSpaceTree(currentNode.value.uuid,node_data);
|
|
}
|
|
})
|
|
}
|
|
//----------for dir-----------
|
|
//该函数仅操作前端,为新文件夹命名
|
|
function createDir(){
|
|
matterList.value?.unshift({
|
|
name:"",
|
|
userUuid:props.spaceid,
|
|
puuid:"",
|
|
uuid:"",
|
|
dir:true,
|
|
size:0,
|
|
deleted:false,
|
|
})
|
|
}
|
|
//该函数为实际创建文件夹的函数
|
|
function onCreateDir(){
|
|
doCreateSpaceDir(props.uid,{
|
|
puuid:currentNode.value.uuid,
|
|
name:newdirName.value,
|
|
space:props.spaceid,
|
|
}).then((resp)=> {
|
|
newdirName.value=""
|
|
onLoadMatterList()
|
|
})
|
|
.catch((e)=>{
|
|
ElMessage.error(e.msg)
|
|
})
|
|
}
|
|
|
|
//文件重命名
|
|
function onSpaceMatterRename(row:matterInfo){
|
|
const newname=ref(row.name)
|
|
ElMessageBox({
|
|
title:"请输入新的文件名",
|
|
confirmButtonText: "确定",
|
|
cancelButtonText: "取消",
|
|
message: () => h(ElInput, {
|
|
style: { width:'360px' },
|
|
modelValue: newname.value,
|
|
'onUpdate:modelValue': (val) => {
|
|
newname.value = val
|
|
},
|
|
}),
|
|
}).then(() => {
|
|
if(newname.value&&newname.value!=""){
|
|
spaceMatterRename(props.uid,{
|
|
space:props.spaceid,
|
|
uuid:row.uuid,
|
|
name:newname.value,
|
|
}).then(()=>onLoadMatterList())
|
|
}
|
|
})
|
|
}
|
|
|
|
//------------------------------------------
|
|
// @cell-dblclick="handleDoubleClick" 取消了目录双击打开功能
|
|
//打开一个目录
|
|
function handleDoubleClick(row:matterInfo,ind?:number){
|
|
if(row.dir){
|
|
//设置当前文件夹的权限等级
|
|
if(row.permitVal){
|
|
CutLevelPermit.value=row.permitVal
|
|
}else{
|
|
if (props.ismanager) {
|
|
CutLevelPermit.value=9
|
|
}else{
|
|
let _pert: Record<string, number>
|
|
_pert = JSON.parse(row.permits!.data)
|
|
let val=_pert[props.rawUid.replace("p0","")]
|
|
if(val){
|
|
CutLevelPermit.value = val
|
|
}else{
|
|
CutLevelPermit.value = PERMITS.FORBID //没有权限!!
|
|
}
|
|
}
|
|
}
|
|
|
|
if(row.agent){
|
|
currentAgent.value={name:row.name,model:false,uuid:row.uuid,path:row.path}
|
|
}else if(row.uuid=="root"){
|
|
currentAgent.value={name:"通用AI",model:false,uuid:defaultAiAgent,path:"root"}
|
|
}
|
|
isNewNode=true
|
|
//1:如果是当前目录的父组件没必要更新目录树
|
|
//2: 如果当前目录是当前空间根目录,没必要更新目录树
|
|
if(currentNode.value.puuid==row.uuid || row.uuid=="root") isNewNode=false
|
|
currentNode.value=row
|
|
paginInfo.value.page=0,
|
|
onLoadMatterList()
|
|
|
|
/* 由于添加了父级树组件,breadcrumblis的功能废弃
|
|
//table的双击事件也在此方法处理
|
|
if(typeof(ind)==="number"){
|
|
//返回某一级,面包屑组件的点击处理
|
|
if(breadcrumbList.value.length>1){
|
|
breadcrumbList.value=breadcrumbList.value.slice(0,ind+1)
|
|
currentNode.value=breadcrumbList.value[breadcrumbList.value.length-1]
|
|
onLoadMatterList()
|
|
}
|
|
}else{
|
|
//进入下一级
|
|
//如果目录是一个智能体,把当前智能体设置为该目录
|
|
currentNode.value=row
|
|
breadcrumbList.value.push(row)
|
|
onLoadMatterList()
|
|
}
|
|
*/
|
|
}else{
|
|
onPrivateView(row)
|
|
}
|
|
}
|
|
|
|
function handleMouseEnter(row:any){
|
|
currentHoverRow.value=row.name
|
|
}
|
|
//上传成功
|
|
function handleSingleUpload(response:any){
|
|
handleAiUpload(response.data)
|
|
onLoadMatterList()
|
|
}
|
|
interface uploadError{
|
|
msg:string
|
|
}
|
|
//上传失败
|
|
function handleSigLoadErr(error: Error, uploadFile: UploadFile, uploadFiles:UploadFiles){
|
|
ElMessage.error(JSON.parse(error.message).msg)
|
|
}
|
|
|
|
//自定义上传,目的是支持多文件上传, 使用原生组件,是为了解决并发问题
|
|
async function onCustomUpload(e:Event){
|
|
const files = e.target!.files??[]
|
|
const count=files.length
|
|
let result=""
|
|
for(let index = 0; index < count; index++){
|
|
onprogress.value=true
|
|
const ff = files[index]
|
|
await handleSingleFile(ff).catch((err)=>{
|
|
console.log(err)
|
|
result+=err
|
|
})
|
|
percentage.value = Number(((index + 1) / count).toPrecision(2)) * 100
|
|
}
|
|
if(result!=""){
|
|
dynamicVNode.value=h(uploadlog,{
|
|
content:result
|
|
})
|
|
}
|
|
|
|
onLoadMatterList() //刷新
|
|
}
|
|
|
|
async function handleSingleFile(ff:File){
|
|
const fields=new FormData()
|
|
fields.append("space",uploadFormData.value.space)
|
|
fields.append("puuid",uploadFormData.value.puuid)
|
|
fields.append("file",ff)
|
|
|
|
const res = await doFileUpload(fields,'/hxpan/api/space/upload')
|
|
if(res.code!=200){
|
|
console.log(ff.name+"上传失败! ")
|
|
throw new Error(ff.name+"上传失败!<br> ")
|
|
}
|
|
|
|
//上传后继续AI服务训练
|
|
handleAiUpload(res.data)
|
|
}
|
|
|
|
//文件夹上传,原理:自定义的input组件,一次拿到所有需要上传的文件列表,然后依次上传
|
|
//能减少并发问题
|
|
async function uploadFolder(e:Event){
|
|
onprogress.value=true
|
|
const files = e.target!.files??[]
|
|
const count=files.length
|
|
let result=""
|
|
for(let index = 0; index < count; index++){
|
|
onprogress.value=true
|
|
const f = files[index]
|
|
await handleFolderFile(f).catch((err)=>{
|
|
console.log(err)
|
|
result+= (f as File).name+"上传失败<br>"
|
|
})
|
|
percentage.value = Number(((index + 1) / count).toPrecision(2)) * 100
|
|
}
|
|
if(result!=""){
|
|
dynamicVNode.value=h(uploadlog,{
|
|
content:result
|
|
})
|
|
}
|
|
|
|
onLoadMatterList() //刷新
|
|
}
|
|
|
|
|
|
async function handleFolderFile(option:File){
|
|
//根据路径,来判断需不需要重建目录
|
|
const _path = option.webkitRelativePath
|
|
const _dir=_path.replace(/\/[^/]+\w+$/,"") //只保留文件夹目录,[^/]就是用来限制,只能是最后一个目录
|
|
const node = matterList.value.filter((item)=>{
|
|
return item.dir && _dir.endsWith(item.name!)
|
|
})
|
|
|
|
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 && _dir.endsWith(item.name!) //item.path?.endsWith(_dir)
|
|
})
|
|
if(newnodes.length>0){
|
|
puuid=newnodes[0].uuid
|
|
}else{
|
|
console.log(_path+"上传失败! ")
|
|
throw new Error(_path +" 上传失败!<br> ")
|
|
}
|
|
}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/space/upload')
|
|
if(res.code!=200){
|
|
console.log(_path+"上传失败! ")
|
|
throw new Error(_path+"上传失败!<br> ")
|
|
}
|
|
|
|
//上传后继续AI服务训练,是不是需要上传,在handleAiUpload里面有检测
|
|
handleAiUpload(res.data)
|
|
|
|
}
|
|
|
|
//创建多级目录,并返回matterinfos数组
|
|
async function doCreateMultyDir(path:string,uuid:string){
|
|
const list=[];
|
|
const dirs=path.split("/")
|
|
for(let i=0;i<dirs.length;i++){
|
|
const node = matterList.value.filter((item)=>{
|
|
return item.dir && dirs[i].endsWith(item.name!)
|
|
})
|
|
if(node.length>0) {
|
|
uuid = node[0].uuid
|
|
continue;
|
|
}
|
|
await doCreateSpaceDir(props.uid,{
|
|
puuid:uuid,
|
|
name:dirs[i],
|
|
space:props.spaceid,
|
|
}).then((resp)=> {
|
|
uuid=resp.data.uuid //第一级别的uuid, 是第二级的puuid
|
|
list.push(resp.data)
|
|
})
|
|
}
|
|
return list
|
|
}
|
|
|
|
//-------------------------AI section--------------
|
|
|
|
function handleAiUpload(info:matterInfo){
|
|
//只有当前路径是智能体,上传文件才会进行训练
|
|
if (info.path?.startsWith(currentAgent.value.path)){
|
|
doAiTraining(`/agents/${currentAgent.value.uuid}/updates`,{"matter":info.uuid}).then(resp=>{
|
|
ElMessage({
|
|
message: '已成功安排训练',
|
|
type: 'success',
|
|
plain: true,
|
|
})
|
|
})
|
|
}else{
|
|
console.log("当前路径没有智能体,不需要训练")
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
|
|
//-------------------edit & preive file for space---------------------
|
|
//文件预览
|
|
function onPrivateView(row:matterInfo){
|
|
const _type=fileType(row.name!)
|
|
if(_type!==""){ //office file
|
|
const info =btoa(encodeURIComponent(`${row.name}`)) //预览模式不需要绝对路径,只核对一下文件名即可
|
|
const _url=`${props.siteHost}${props.apiURL}/space/download/${row.uuid}/${row.name}?space=${props.spaceid}`
|
|
//前半部分内容是为了校验信息,主要内容是fileurl
|
|
window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&fileurl=`+window.btoa(encodeURIComponent(_url)),"_blank")
|
|
}else{
|
|
alert("暂不支持该类型预览")
|
|
}
|
|
}
|
|
|
|
//onlyoffice在线编辑
|
|
async function onlyOfficeEdit(row:matterInfo){
|
|
const _type=fileType(row.name!)
|
|
if(_type===""){
|
|
alert("暂不支持该类型编辑")
|
|
return
|
|
}
|
|
|
|
ElMessageBox.confirm("线上资源有限,确定继续线上编辑吗", "提示", {
|
|
confirmButtonText: "确定",
|
|
cancelButtonText: "取消",
|
|
type: "warning",
|
|
}).then(()=>{
|
|
//office file
|
|
//base64 encode for MASK
|
|
const _verify = btoa(row.uuid.match(/(\w+-\w+)/)![0]+"true") //增加一个权限验证的标记
|
|
const info =btoa(encodeURIComponent(`${row.userUuid}/root${row.path}`)) //编辑模式必须要全路径
|
|
const _url=`${props.siteHost}${props.apiURL}/space/download/${row.uuid}/${row.name}?space=${props.spaceid}`
|
|
window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&verify=${_verify}&fileurl=`+window.btoa(encodeURIComponent(_url)),"_blank")
|
|
}).catch(()=>{
|
|
console.log("close")
|
|
})
|
|
}
|
|
|
|
function getSpaceImageViewURL(_uuid:string,_name:string){
|
|
return `${props.apiURL}/space/download/${_uuid}/${_name}?space=${props.spaceid}&ir=fill_100_100&`
|
|
}
|
|
|
|
function getSpaceImageDURL(_uuid:string,_name:string){
|
|
return `${props.apiURL}/space/download/${_uuid}/${_name}?space=${props.spaceid}`
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
|
|
//渲染完页面再执行
|
|
onMounted(() => {
|
|
currentNode.value.uuid="root"
|
|
//设置默认的AI智能体
|
|
currentAgent.value={name:"通用AI",model:false,uuid:defaultAiAgent,path:"root"}
|
|
|
|
let val =localStorage.getItem("listOrGrid")
|
|
if(val&&val=="false"){
|
|
modListOrGrild.value=false
|
|
}else{
|
|
modListOrGrild.value=true
|
|
}
|
|
|
|
if (props.ismanager) {
|
|
CutLevelPermit.value=PERMITS.MANAGER
|
|
}else{
|
|
let _pert: Record<string, number>
|
|
_pert = JSON.parse(props.spacePermit.data)
|
|
let val=_pert[props.rawUid.replace("p0","")]
|
|
if(val){
|
|
CutLevelPermit.value = val
|
|
}else{
|
|
CutLevelPermit.value = PERMITS.FORBID //没有权限!!
|
|
}
|
|
}
|
|
|
|
onLoadMatterList()
|
|
});
|
|
|
|
const handleSelectionChange = (val:matterInfo[]) => {
|
|
tabSelected.value = val
|
|
}
|
|
|
|
defineExpose({handleDoubleClick,onDelMatter,onSpaceMatterRename})
|
|
|
|
//判断是不是空间的所有者
|
|
function isOwner(){
|
|
return props.uid===btoa(props.owner)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<el-row :gutter="24" style="margin: 12px 0px;">
|
|
<span class="el-breadcrumb" style="font-weight: bold; align-content: center;">[ {{ props.spacename }} ] : </span>
|
|
<el-breadcrumb separator="/" style="align-content: center;">
|
|
<el-breadcrumb-item v-for="(item,index) in breadcrumbList"
|
|
:key="index" @click="handleDoubleClick(item,index)">
|
|
<span style="font-weight: bold;cursor: pointer;">{{ item.name }}</span>
|
|
</el-breadcrumb-item>
|
|
</el-breadcrumb>
|
|
<span v-if="currentNode.uuid!='root'" 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="onLoadMatterList(searchname)"></el-button>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="24">
|
|
<el-col :span="14" v-if="CutLevelPermit>=PERMITS.UPLOAD">
|
|
<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>
|
|
</el-col>
|
|
<el-button style="margin-left: auto;" @click="()=>currentAgent.model=true">AI助手</el-button>
|
|
|
|
<!-- <el-button-group v-if="isOwner()" class="control" style="margin: 0 10px;">
|
|
<el-button :icon="Plus" @click="onAiAgent">创建智能体</el-button>
|
|
</el-button-group> -->
|
|
<el-button-group style="margin-right:20px;">
|
|
<el-button :icon="List" @click="updateListOrGrid(true)"></el-button>
|
|
<el-button :icon="Grid" @click="updateListOrGrid(false)"></el-button>
|
|
</el-button-group>
|
|
</el-row>
|
|
|
|
<el-dialog v-model="onprogress" width="50%" title="上传进度">
|
|
请勿关闭页面。。。
|
|
<el-progress style="width: 90%;" :text-inside="true" :stroke-width="26" :percentage="percentage" />
|
|
</el-dialog>
|
|
|
|
<el-row :gutter="24" style="overflow-y: auto;height: 90%;">
|
|
<el-table v-if="modListOrGrild"
|
|
stripe
|
|
:data="matterList"
|
|
:header-cell-style="{ background: '#f5f8fd' }"
|
|
style="width: 100%"
|
|
row-key="uuid"
|
|
:row-style ="() => ({ lineHeight: '36px' })"
|
|
@selection-change="handleSelectionChange"
|
|
@cell-mouse-enter="handleMouseEnter">
|
|
<!-- <el-table-column type="selection" width="50" /> -->
|
|
<el-table-column width="450" property="name" label="文件名">
|
|
<template #default="scope">
|
|
<input v-if="scope.row.name===''" v-model="newdirName" type="text" autofocus placeholder="文件夹名" style="border:groove;height:30px;" @change="onCreateDir" />
|
|
<div v-else style="display: flex; align-items: center;" @dblclick="handleDoubleClick(scope.row)" >
|
|
<svg-icon v-if="scope.row.dir" icon-class="folder-icon" :size="30"/>
|
|
<el-image v-else-if="getFileIcon(scope.row.name)==='img'" style="width: 30px;" :preview-src-list="[getSpaceImageDURL(scope.row.uuid,scope.row.name)]" :src="getSpaceImageViewURL(scope.row.uuid,scope.row.name)" />
|
|
<svg-icon v-else :icon-class="getFileIcon(scope.row.name)+'-icon'" :size="30" />
|
|
<span style="margin-left: 10px">{{ scope.row.name }}</span>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column width="350">
|
|
<template #default="scope" >
|
|
<el-tag v-if="scope.row.agent" effect="dark" size="small" type="success" round >智能体</el-tag>
|
|
<div v-show="currentHoverRow === scope.row.name" style="display:inline; margin-left:15px">
|
|
<el-button v-if="getFileIcon(scope.row.name)!='img'" size="small" :icon="View" circle @click="onPrivateView(scope.row)"></el-button>
|
|
<el-button v-if="scope.row.permitVal>=PERMITS.DOWNLOAD" size="small" :icon="Download" circle @click="onDownload(scope.row)"></el-button>
|
|
<span v-if="scope.row.permitVal>=PERMITS.MANAGER" class="manager_span" >
|
|
<el-button v-if="!scope.row.dir" size="small" circle @click="handleAiUpload(scope.row)">AI</el-button>
|
|
<el-button size="small" :icon="Delete" circle @click="onDelMatter(scope.row)"></el-button>
|
|
<el-button size="small" :icon="Setting" circle @click="onSpacePManage(scope.row)"></el-button>
|
|
</span>
|
|
<span v-if="scope.row.permitVal>=PERMITS.EDIT" class="manager_span">
|
|
<el-button size="small" :icon="Edit" circle @click="onlyOfficeEdit(scope.row)"></el-button>
|
|
<el-button size="small" circle @click="onSpaceMatterRename(scope.row)">改</el-button>
|
|
</span>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="size" width="100" :formatter="readableSize" label="大小" />
|
|
|
|
<el-table-column prop="updateTime" label="修改日期">
|
|
<template #default="scope">
|
|
<span v-if="scope.row.updateTime">{{ scope.row.updateTime.slice(0,16) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<div class="table-grid" v-else>
|
|
<div class="grid-item" v-for="row in matterList">
|
|
<div class="grid">
|
|
<div v-if="row.name===''">
|
|
<svg-icon icon-class="folder-icon" size="80px"/>
|
|
<input v-model="newdirName" type="text" autofocus placeholder="文件夹名" style="border:groove;height:30px;" @change="onCreateDir" />
|
|
</div>
|
|
|
|
<div v-else class="grid-box" @dblclick="handleDoubleClick(row)" @contextmenu.prevent="handleMouseEnter(row)" >
|
|
<svg-icon v-if="row.dir" icon-class="folder-icon" size="80px"/>
|
|
<el-image v-else-if="getFileIcon(row.name)==='img'" style="width: 80px;" :preview-src-list="[getSpaceImageDURL(row.uuid,row.name)]" :src="getSpaceImageViewURL(row.uuid,row.name)" />
|
|
<svg-icon v-else :icon-class="getFileIcon(row.name)+'-icon'" size="80px"/>
|
|
<span style="margin: 5px 0;text-wrap-mode:nowrap;">{{ row.name }}</span>
|
|
<el-tag v-if="row.agent" effect="dark" size="small" type="success" round >智能体</el-tag>
|
|
</div>
|
|
</div>
|
|
<ul v-if="row.name!=''" class="grid-menus" v-show="currentHoverRow === row.name" @mouseleave="currentHoverRow=''">
|
|
<li v-if="getFileIcon(row.name)!='img'" @click="onPrivateView(row)">预览</li>
|
|
<li v-if="row.permitVal! >= PERMITS.DOWNLOAD" @click="onDownload(row)">下载</li>
|
|
<span v-if="row.permitVal! >= PERMITS.EDIT" >
|
|
<li @click="onlyOfficeEdit(row)">编辑</li>
|
|
<li @click="onSpaceMatterRename(row)">重命名</li>
|
|
</span>
|
|
<span v-if="row.permitVal! >= PERMITS.MANAGER" >
|
|
<li @click="onDelMatter(row)">删除</li>
|
|
<li @click="onSpacePManage(row)">权限</li>
|
|
</span>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</el-row>
|
|
|
|
<el-row v-if="paginInfo.total>1" style="justify-content: center;">
|
|
<el-pagination size="small" background layout="prev, pager, next" :current-page="paginInfo.page+1" @current-change="(value:number)=>{paginInfo.page=value-1;onLoadMatterList();}" :page-count="paginInfo.total" class="mt-4"/>
|
|
</el-row>
|
|
|
|
<aiagent :agent="currentAgent" :userid="uid" :closefunc="()=>{currentAgent.model=false}"></aiagent>
|
|
|
|
<div v-if="dynamicVNode">
|
|
<component :is="dynamicVNode" />
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.shareDialog{
|
|
--el-messagebox-width:'800px';
|
|
padding:40px;
|
|
.el-text{
|
|
align-self: flex-start;
|
|
}
|
|
}
|
|
.search{
|
|
margin-left: auto;
|
|
margin-right: -4px;
|
|
display:inherit;
|
|
}
|
|
|
|
.table-grid{
|
|
display: flex;
|
|
flex-wrap: wrap; /* 关键属性,允许子元素自动换行 */
|
|
align-content: flex-start;
|
|
.grid-item{
|
|
position: relative;
|
|
width: 134px;
|
|
height: 135px;
|
|
margin: 5px;
|
|
.grid-box{
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
align-items: center;
|
|
text-align:center;
|
|
}
|
|
.grid-menus{
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 72px;
|
|
background-color: #ffffff;
|
|
width: 60px;
|
|
line-height: 27px;
|
|
text-align: center;
|
|
color: #878989;
|
|
z-index: 90;
|
|
box-shadow:0px 0px 12px rgba(0,0,0,0.12);
|
|
li{
|
|
cursor: pointer;
|
|
border-bottom: 1px solid #ccc;
|
|
}
|
|
}
|
|
.grid{
|
|
:hover {
|
|
background-color: #c4c4c4; /* 悬停时的背景色 */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.manager_span{
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.dynamic-width-message-box-byme .el-message-box__message{
|
|
width: 100%;
|
|
}
|
|
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
.el-table--default .el-table__cell{
|
|
padding: 10px 0;
|
|
}
|
|
</style>
|