6 changed files with 853 additions and 1 deletions
@ -0,0 +1,143 @@ |
|||||
|
/** |
||||
|
* @ 作者: han2015 |
||||
|
* @ 时间: 2025-05-12 15:39:13 |
||||
|
* @ 备注: 文档管理API |
||||
|
*/ |
||||
|
|
||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { matterPage,matterResutList,createDir,createShare,respCreateShare} from './type'; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取分享列表 |
||||
|
*/ |
||||
|
export function getShareList( uid:string,data?: matterPage): AxiosPromise<matterResutList> { |
||||
|
return request({ |
||||
|
url: '/hxpan/api/share/page', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* share browse |
||||
|
*/ |
||||
|
export function getShareBrowse( uid:string,data?: matterPage): AxiosPromise<respCreateShare> { |
||||
|
return request({ |
||||
|
url: '/hxpan/api/share/browse', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* share delete |
||||
|
*/ |
||||
|
export function postShareDelete( uid:string,data?: matterPage): AxiosPromise<respCreateShare> { |
||||
|
return request({ |
||||
|
url: '/hxpan/api/share/delete', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取目录文件 |
||||
|
*/ |
||||
|
export function getMatterList( uid:string,data?: matterPage): AxiosPromise<matterResutList> { |
||||
|
return request({ |
||||
|
url: '/hxpan/api/matter/page', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
/** |
||||
|
* 新建目录 |
||||
|
*/ |
||||
|
export function postCreateDir(uid:string,data?: createDir){ |
||||
|
return request({ |
||||
|
url: '/hxpan/api/matter/create/directory', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除文件或目录 |
||||
|
*/ |
||||
|
export function postDelMatter(uid:string,data?: any){ |
||||
|
return request({ |
||||
|
url: '/hxpan/api/matter/delete', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
/** |
||||
|
* 批量删除文件或目录 |
||||
|
*/ |
||||
|
export function postDelMatBatch(uid:string,data?: any){ |
||||
|
return request({ |
||||
|
url: '/hxpan/api/matter/delete/batch', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分享单个文件 |
||||
|
*/ |
||||
|
export function postCreateShare(uid:string,data?: createShare): AxiosPromise<respCreateShare>{ |
||||
|
return request({ |
||||
|
url: '/hxpan/api/share/create', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更改文件名 |
||||
|
*/ |
||||
|
export function postMatterRename(uid:string,data?: {uuid:string;name:string}){ |
||||
|
return request({ |
||||
|
url: '/hxpan/api/matter/rename', |
||||
|
method: 'post', |
||||
|
headers: { |
||||
|
'User-Id':uid, |
||||
|
'Content-Type': 'application/x-www-form-urlencoded' |
||||
|
}, |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
/** |
||||
|
* @ 作者: han2015 |
||||
|
* @ 时间: 2025-05-12 15:39:13 |
||||
|
* @ 备注: 文档管理api 结构定义 |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* 拉去首页文件列表 |
||||
|
*/ |
||||
|
export interface matterPage{ |
||||
|
page?:number; |
||||
|
pageSize?:number; |
||||
|
puuid?:string; |
||||
|
deleted?:boolean; |
||||
|
orderDir?:string; |
||||
|
name?:string; |
||||
|
orderCreateTime?:string; |
||||
|
} |
||||
|
|
||||
|
export interface matterInfo{ |
||||
|
name?:string; |
||||
|
updateTime?:string; |
||||
|
uuid:string; //文件uuid
|
||||
|
userUuid?:string; //owner uuid
|
||||
|
puuid?:string; // parent dir uuid
|
||||
|
path?:string; |
||||
|
size?:number; |
||||
|
dir?:boolean; |
||||
|
deleted?:boolean; |
||||
|
expireInfinity?:boolean; |
||||
|
expireTime?:string; |
||||
|
} |
||||
|
|
||||
|
export type matterResutList = PageResult<matterInfo[]> |
||||
|
|
||||
|
export interface createDir{ |
||||
|
userUuid:string; |
||||
|
puuid:string; |
||||
|
name:string; |
||||
|
} |
||||
|
|
||||
|
export interface createShare{ |
||||
|
matterUuids:string; |
||||
|
expireInfinity:boolean; |
||||
|
expireTime:string; |
||||
|
} |
||||
|
|
||||
|
export interface respCreateShare{ |
||||
|
code?:string; |
||||
|
shareType?:string; |
||||
|
expireTime?:string; |
||||
|
name?:string; |
||||
|
uuid?:string; |
||||
|
} |
||||
@ -0,0 +1,403 @@ |
|||||
|
<!-- |
||||
|
@ 作者: han2015 |
||||
|
@ 时间: 2025-05-12 15:39:13 |
||||
|
@ 备注: 文档管理组件 |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
import { getExpirTime, getFileIcon, readableSize} from "./tools" |
||||
|
import { useUserStore } from "@/store/modules/user"; |
||||
|
import { getMatterList,postCreateDir,postDelMatter,postCreateShare,postMatterRename,postDelMatBatch} from "@/api/doc/index" |
||||
|
import { matterPage,matterInfo,respCreateShare } from "@/api/doc/type" |
||||
|
import { h } from 'vue' |
||||
|
import { |
||||
|
Delete, |
||||
|
Download, |
||||
|
Share, |
||||
|
Search, |
||||
|
Edit, |
||||
|
Promotion, |
||||
|
Folder, |
||||
|
} from '@element-plus/icons-vue' |
||||
|
import {ElSelect,ElOption, ElText,ElInput,TableInstance,ElMessage,UploadFile,UploadFiles,ElPagination} from "element-plus"; |
||||
|
import { number } from "echarts"; |
||||
|
|
||||
|
//TODO: add file icons done! |
||||
|
//TODO: click on table-item, 1)preview on file ..................... |
||||
|
// 2) go into dir-item done! |
||||
|
// 3)search file done! |
||||
|
//TODO: rename matters done! |
||||
|
|
||||
|
//TODO: get share list done! |
||||
|
//TODO: visit share link done! |
||||
|
|
||||
|
//TODO: select on table items for batch opts 1)delete done! |
||||
|
// 2)share done! |
||||
|
//TODO: test on Pagination done! |
||||
|
|
||||
|
const userStore = useUserStore(); |
||||
|
const uid="p0"+userStore.userInfoCont.userId; |
||||
|
const siteHost=import.meta.env.VITE_APP_BASE_URL; |
||||
|
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api" |
||||
|
|
||||
|
const matterList = ref<matterInfo[]>([]) |
||||
|
const searchname=ref("") |
||||
|
const currentUuid=ref("root") //打开的路径层次 |
||||
|
const newdir=ref("") |
||||
|
const currentHoverRow=ref("") |
||||
|
const breadcrumbList=ref<matterInfo[]>([{name:"根目录",uuid:"root", dir:true}]) //面包屑导航 |
||||
|
const selectedValue = ref("sixhour") |
||||
|
const tabSelected=ref<matterInfo[]>([]) |
||||
|
const multipleTableRef = ref<TableInstance>() |
||||
|
const paginInfo = ref({ page: 0, total: 0 }) |
||||
|
const formHeaders=ref({ |
||||
|
"user-id":uid, |
||||
|
}) |
||||
|
const uploadFormData = computed(() => { |
||||
|
return { |
||||
|
userUuid: uid, // 用户的uuid |
||||
|
puuid: currentUuid.value, // 父目录的uuid,基目录为root |
||||
|
} |
||||
|
}); |
||||
|
const fileList=ref([])//upload files |
||||
|
|
||||
|
//--------------单文件分享------------- |
||||
|
function onShareMatter(row?:matterInfo){ |
||||
|
ElMessageBox({ |
||||
|
title: '请选择分享有效时间', |
||||
|
message: () => h(ElSelect, { |
||||
|
defaultFirstOption:true, |
||||
|
modelValue: selectedValue.value, |
||||
|
'onUpdate:modelValue': (value) => { |
||||
|
selectedValue.value = value |
||||
|
}, |
||||
|
valueKey: "value", |
||||
|
fallbackPlacements:['bottom-start'], |
||||
|
style: { width:'360px' } |
||||
|
},() => [ |
||||
|
h(ElOption, { label: '六小时',key: 'sixhour', value: 'sixhour' }), |
||||
|
h(ElOption, { label: '一 天', key: 'oneday', value: 'oneday' }), |
||||
|
h(ElOption, { label: '三 天', key: 'threeday', value: 'threeday' }), |
||||
|
h(ElOption, { label: '一 周', key: 'oneweek', value: 'oneweek' }), |
||||
|
h(ElOption, { label: '一 月', key: 'onemonth', value: 'onemonth' }), |
||||
|
h(ElOption, { label: '三 月', key: 'threemonth', value: 'threemonth' }), |
||||
|
h(ElOption, { label: '永 久', key: 'permanent', value: 'permanent' }), |
||||
|
]), |
||||
|
showCancelButton: true |
||||
|
}).then(() => { |
||||
|
let param; |
||||
|
if (row){ |
||||
|
param={matterUuids:row.uuid,expireInfinity:false,expireTime:""} |
||||
|
}else if (tabSelected.value.length>1){ |
||||
|
param={matterUuids:tabSelected.value.map((item:matterInfo)=>item.uuid).join(","),expireInfinity:false,expireTime:""} |
||||
|
} |
||||
|
|
||||
|
if(param){ |
||||
|
if(selectedValue.value==='permanent'){ |
||||
|
param.expireInfinity=true |
||||
|
}else{ |
||||
|
param.expireTime=getExpirTime(selectedValue.value) |
||||
|
} |
||||
|
|
||||
|
postCreateShare(uid,param).then((resp)=>{ |
||||
|
showShareMessage(resp.data) |
||||
|
}) |
||||
|
onLoadMatterList() |
||||
|
selectedValue.value="sixhour" |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
selectedValue.value='sixhour' |
||||
|
return |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function showShareMessage(row:respCreateShare){ |
||||
|
let _shareURL=`${siteHost}/#/doc/share/?uuid=${row.uuid}&code=${row.code}` |
||||
|
ElMessageBox({ |
||||
|
title: '分享详情', |
||||
|
customStyle: { '--el-messagebox-width':'800px',padding:'40px'}, |
||||
|
message: () => h('div',{style:{display:'flex','flex-direction':'column','line-height':'34px', width:'600px'}},[ |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>row.name), |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>"失效时间:"+row.expireTime), |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>"链接:"+_shareURL) |
||||
|
]), |
||||
|
confirmButtonText: '复制分享链接', |
||||
|
showCancelButton: true |
||||
|
}).then(()=>{ |
||||
|
navigator.clipboard.writeText(_shareURL) |
||||
|
}).catch(() => {}); |
||||
|
} |
||||
|
|
||||
|
//---------------------------------------- |
||||
|
//删除 |
||||
|
function onDelMatter(row:matterInfo){ |
||||
|
if (row.uuid){ |
||||
|
ElMessageBox.confirm("确认删除此数据项?删除后不可恢复!", "警告", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
postDelMatter(uid,{ |
||||
|
"uuid":row.uuid |
||||
|
}).then(()=>onLoadMatterList()) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function onDelMatBatch(){ |
||||
|
ElMessageBox.confirm("确认删除选择的内容?", "警告", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
postDelMatBatch(uid,{ |
||||
|
"uuids":tabSelected.value.map((item:matterInfo)=>item.uuid).join(",") |
||||
|
}).then(()=>onLoadMatterList()) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function onDownload(row:matterInfo){ |
||||
|
ElMessageBox.confirm("确认下载此数据项?", "提示", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
if (row.uuid){ |
||||
|
let _url= apiURL+`/alien/download/${row.uuid}/${row.name}` |
||||
|
window.open(_url) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function onMatterRename(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(() => { |
||||
|
postMatterRename(uid,{ |
||||
|
uuid:row.uuid, |
||||
|
name:newname.value, |
||||
|
}).then(()=>onLoadMatterList()) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//加载文件列表 |
||||
|
function onLoadMatterList(name?:string){ |
||||
|
let _page: matterPage = { |
||||
|
page: paginInfo.value.page, |
||||
|
pageSize: 50, |
||||
|
orderCreateTime: "DESC", |
||||
|
orderDir: "DESC" |
||||
|
}; |
||||
|
//如果有搜索条件,说明是按名称搜索,这里要把puuid清空;如果没有搜索条件,说明是普通目录查询 |
||||
|
if(name){ |
||||
|
_page.name=name |
||||
|
}else{ |
||||
|
_page.puuid=currentUuid.value |
||||
|
_page.deleted=false |
||||
|
} |
||||
|
|
||||
|
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 |
||||
|
}) |
||||
|
} |
||||
|
//----------for dir----------- |
||||
|
function createDir(){ |
||||
|
matterList.value?.unshift({ |
||||
|
name:"", |
||||
|
userUuid:uid, |
||||
|
puuid:"", |
||||
|
uuid:"", |
||||
|
dir:true, |
||||
|
size:0, |
||||
|
deleted:false, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function onCreateDir(){ |
||||
|
postCreateDir(uid,{ |
||||
|
userUuid:uid, |
||||
|
puuid:currentUuid.value, |
||||
|
name:newdir.value, |
||||
|
}).then(()=> { |
||||
|
newdir.value="" |
||||
|
onLoadMatterList() |
||||
|
}) |
||||
|
.catch((e)=>{ |
||||
|
ElMessage.error(e.msg) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function handleDoubleClick(row:matterInfo,ind?:number){ |
||||
|
if(row.dir){ |
||||
|
//table的双击事件也在此方法处理 |
||||
|
if(typeof(ind)==="number"){ |
||||
|
//返回某一级 |
||||
|
if(breadcrumbList.value.length>1){ |
||||
|
breadcrumbList.value=breadcrumbList.value.slice(0,ind+1) |
||||
|
currentUuid.value=breadcrumbList.value[breadcrumbList.value.length-1].uuid |
||||
|
onLoadMatterList() |
||||
|
} |
||||
|
}else{ |
||||
|
//进入下一级 |
||||
|
currentUuid.value=row.uuid |
||||
|
breadcrumbList.value.push(row) |
||||
|
onLoadMatterList() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function handleMouseEnter(row:any){ |
||||
|
currentHoverRow.value=row.name |
||||
|
} |
||||
|
//上传成功 |
||||
|
function handleSingleUpload(response:any){ |
||||
|
fileList.value=[] |
||||
|
onLoadMatterList() |
||||
|
} |
||||
|
interface uploadError{ |
||||
|
msg:string |
||||
|
} |
||||
|
//上传失败 |
||||
|
function handleSigLoadErr(error: Error, uploadFile: UploadFile, uploadFiles:UploadFiles){ |
||||
|
ElMessage.error(JSON.parse(error.message).msg) |
||||
|
} |
||||
|
|
||||
|
//http://172.20.2.87:6010/api/alien/preview/5a10aaf6-396e-4d9a-7e87-3c5c8029d4db/123.png?ir=fill_100_100 |
||||
|
//渲染完页面再执行 |
||||
|
onMounted(() => { |
||||
|
onLoadMatterList() |
||||
|
}); |
||||
|
|
||||
|
const handleSelectionChange = (val:matterInfo[]) => { |
||||
|
tabSelected.value = val |
||||
|
} |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="app_container"> |
||||
|
<el-row :gutter="24" style="margin: 12px 0px;"> |
||||
|
<el-breadcrumb separator="/"> |
||||
|
<el-breadcrumb-item v-for="(item,index) in breadcrumbList" |
||||
|
:key="index" @click="index===breadcrumbList.length-1?'': handleDoubleClick(item,index)"> |
||||
|
<span style="font-weight: bold;">{{ item.name }}</span> |
||||
|
</el-breadcrumb-item> |
||||
|
</el-breadcrumb> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-row :gutter="24"> |
||||
|
<el-col :span="14"> |
||||
|
<el-upload class="el-button el-button--default" :file-list="fileList" |
||||
|
:headers="formHeaders" |
||||
|
: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> --> |
||||
|
<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-col> |
||||
|
|
||||
|
<el-col :span="8" 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" style="height: 84%;overflow-y: auto;"> |
||||
|
<el-table |
||||
|
stripe |
||||
|
:data="matterList" |
||||
|
ref="multipleTableRef" |
||||
|
:header-cell-style="{ background: '#f5f8fd' }" |
||||
|
style="width: 100%" |
||||
|
row-key="uuid" |
||||
|
:row-style ="() => ({ lineHeight: '36px' })" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
@cell-dblclick="handleDoubleClick" |
||||
|
@cell-mouse-enter="handleMouseEnter"> |
||||
|
<el-table-column type="selection" width="50" /> |
||||
|
<el-table-column width="650" property="name" label="文件名"> |
||||
|
<template #default="scope"> |
||||
|
<input type="text" autofocus placeholder="文件夹名" style="border:groove;height:30px;" v-model="newdir" @change="onCreateDir" v-if="scope.row.name===''" /> |
||||
|
<div v-if="scope.row.name" style="display: flex; align-items: center;"> |
||||
|
<el-icon :size="26"> |
||||
|
<component v-if="scope.row.dir" :is="Folder" /> |
||||
|
<component v-else :is="getFileIcon(scope.row.name)" /> |
||||
|
</el-icon> |
||||
|
<span style="margin-left: 10px">{{ scope.row.name }}</span> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<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="Share" circle @click="onShareMatter(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Download" circle @click="onDownload(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Edit" circle @click="onMatterRename(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Delete" circle @click="onDelMatter(scope.row)"></el-button> |
||||
|
</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> |
||||
|
</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> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.app_container { |
||||
|
padding: 10px 30px 0px 30px; |
||||
|
height: calc(100% - 10px); |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
width: 100%; |
||||
|
|
||||
|
} |
||||
|
.search{ |
||||
|
margin-right: 20px; |
||||
|
display:inherit; |
||||
|
} |
||||
|
.shareDialog{ |
||||
|
--el-messagebox-width:'800px'; |
||||
|
padding:40px; |
||||
|
.el-text{ |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
} |
||||
|
.dynamic-width-message-box-byme .el-message-box__message{ |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,161 @@ |
|||||
|
<!-- |
||||
|
@ 作者: han2015 |
||||
|
@ 时间: 2025-05-12 15:39:13 |
||||
|
@ 备注: 文档管理组件 |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
|
||||
|
import { useRoute } from 'vue-router' |
||||
|
|
||||
|
import { useUserStore } from "@/store/modules/user"; |
||||
|
import { getShareList,postDelMatter,getShareBrowse,postShareDelete} from "@/api/doc/index" |
||||
|
import { matterPage,matterInfo,respCreateShare } from "@/api/doc/type" |
||||
|
import { h } from 'vue' |
||||
|
import { |
||||
|
Delete, |
||||
|
Folder, |
||||
|
Share, |
||||
|
} from '@element-plus/icons-vue' |
||||
|
import {ElText } from "element-plus"; |
||||
|
import { getExpirTime, getFileIcon,checkExpirTime } from "./tools" |
||||
|
|
||||
|
const route = useRoute() |
||||
|
const userStore = useUserStore(); |
||||
|
const uid="p0"+userStore.userInfoCont.userId; |
||||
|
const siteHost=import.meta.env.VITE_APP_BASE_URL |
||||
|
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api" |
||||
|
const matterList = ref<matterInfo[]>() |
||||
|
const browerMode=ref(false) //share模式 1)self-list(default) 2)brower |
||||
|
const currentHoverRow=ref("") |
||||
|
|
||||
|
|
||||
|
function showShareMessage(row:{uuid:string,code:string,name:string,expireTime:string}){ |
||||
|
let _shareURL=`${siteHost}/#/doc/share?uuid=${row.uuid}&code=${row.code}` |
||||
|
ElMessageBox({ |
||||
|
title: '分享详情', |
||||
|
customStyle: { '--el-messagebox-width':'800px',padding:'40px'}, |
||||
|
message: () => h('div',{style:{display:'flex','flex-direction':'column','line-height':'34px', width:'600px'}},[ |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>row.name), |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>"失效时间:"+row.expireTime), |
||||
|
h(ElText,{style:{'align-self':'flex-start'}},()=>"链接:"+_shareURL), |
||||
|
h(ElButton, { |
||||
|
type: 'primary', |
||||
|
style: { width: '20%' }, |
||||
|
onClick: () => { |
||||
|
let _url=apiURL+`/share/zip?shareUuid=${row.uuid}&code=${row.code}&puuid=root&rootUuid=root` |
||||
|
window.open(_url) |
||||
|
} |
||||
|
},()=>'下载') |
||||
|
]), |
||||
|
confirmButtonText: '复制分享链接', |
||||
|
showCancelButton: true |
||||
|
}).then(()=>{ |
||||
|
navigator.clipboard.writeText(_shareURL) |
||||
|
}).catch(() => { |
||||
|
if (browerMode.value){ |
||||
|
location.href=`/#/doc/share` |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//---------------------------------------- |
||||
|
//删除分享 |
||||
|
function onShareDelete(row:matterInfo){ |
||||
|
if (row.uuid){ |
||||
|
ElMessageBox.confirm("确认要取消此文件分享!", "警告", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
postShareDelete(uid,{ |
||||
|
"uuid":row.uuid |
||||
|
}).then(()=>onLoadShareList()) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//加载文件列表 |
||||
|
function onLoadShareList(){ |
||||
|
let _page: matterPage = { |
||||
|
page: 0, |
||||
|
pageSize: 100, |
||||
|
orderCreateTime: "DESC", |
||||
|
orderDir: "DESC", |
||||
|
} |
||||
|
|
||||
|
getShareList(uid,_page).then((resp)=>{ |
||||
|
matterList.value=resp.data.data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function handleMouseEnter(row:any){ |
||||
|
currentHoverRow.value=row.name |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
const query = route.query |
||||
|
//只是分享链接的请求 |
||||
|
if (query.uuid && query.code){ |
||||
|
browerMode.value=true |
||||
|
getShareBrowse("",{shareUuid:query.uuid,code:query.code,puuid:'root',rootUuid:'root'}).then((resp)=>{ |
||||
|
showShareMessage(resp.data) |
||||
|
}) |
||||
|
return |
||||
|
} |
||||
|
browerMode.value=false |
||||
|
onLoadShareList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="app_container"> |
||||
|
<el-row :gutter="24" v-if="!browerMode"> |
||||
|
<el-table |
||||
|
stripe |
||||
|
:data="matterList" |
||||
|
:header-cell-style="{ background: '#f5f8fd' }" |
||||
|
style="width: 100%" |
||||
|
row-key="value" |
||||
|
:row-style ="() => ({ height: '55px' })" |
||||
|
@cell-mouse-enter="handleMouseEnter"> |
||||
|
<el-table-column style="width: 70%;" property="name" label="文件名"> |
||||
|
<template #default="scope"> |
||||
|
<div style="display: flex; align-items: center"> |
||||
|
<el-icon :size="26"> |
||||
|
<component v-if="scope.row.dir" :is="Folder" /> |
||||
|
<component v-else :is="getFileIcon(scope.row.name)" /> |
||||
|
</el-icon> |
||||
|
<span style="margin-left: 10px">{{ checkExpirTime(scope.row)?scope.row.name+' (已过期)':scope.row.name }}</span> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column width="250" align="center"> |
||||
|
<template #default="scope"> |
||||
|
<div v-show="currentHoverRow === scope.row.name"> |
||||
|
<el-button size="small" :icon="Share" circle @click="showShareMessage(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Delete" circle @click="onShareDelete(scope.row)"></el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column prop="expireTime" label="失效日期"> |
||||
|
<template #default="scope"> |
||||
|
<span v-if="scope.row.expireTime">{{ scope.row.expireInfinity? '永久有效': scope.row.expireTime.slice(0,16) }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.app_container { |
||||
|
padding: 10px 30px 0px 30px; |
||||
|
height: calc(100% - 10px); |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,91 @@ |
|||||
|
import { |
||||
|
Document, |
||||
|
Picture, |
||||
|
VideoPlay, |
||||
|
Headset, |
||||
|
Files, |
||||
|
Tickets, |
||||
|
} from '@element-plus/icons-vue' |
||||
|
import { matterInfo } from "@/api/doc/type" |
||||
|
|
||||
|
export function getExpirTime(val:string){ |
||||
|
let now= Date.now() //haomiao
|
||||
|
switch(val){ |
||||
|
case "sixhour": |
||||
|
now+=6*3600*1000 |
||||
|
break |
||||
|
case "oneday": |
||||
|
now+=24*3600*1000 |
||||
|
break |
||||
|
case "threeday": |
||||
|
now+=3*24*3600*1000 |
||||
|
break |
||||
|
case "oneweek": |
||||
|
now+=7*24*3600*1000 |
||||
|
break |
||||
|
case "onemonth": |
||||
|
now+=30*24*3600*1000 |
||||
|
break |
||||
|
case "threemonth": |
||||
|
now+=90*24*3600*1000 |
||||
|
break |
||||
|
default: |
||||
|
now+=6*3600*1000 |
||||
|
} |
||||
|
let nt=new Date(now) |
||||
|
|
||||
|
return nt.toISOString().slice(0,10)+" "+nt.toLocaleTimeString() |
||||
|
} |
||||
|
export function checkExpirTime(val:matterInfo){ |
||||
|
if (val.expireInfinity) return false |
||||
|
if (val.expireTime) { |
||||
|
let now = Date.now() //haomiao
|
||||
|
let expireTime = new Date(val.expireTime).getTime() |
||||
|
if (expireTime > now) return false |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
export const getFileIcon = (fileName:string) => { |
||||
|
const extension = fileName?.split('.').pop()?.toLowerCase(); |
||||
|
|
||||
|
switch(extension) { |
||||
|
case 'pdf': |
||||
|
case 'doc': |
||||
|
case 'docx': |
||||
|
case 'xls': |
||||
|
case 'xlsx': |
||||
|
return Document; |
||||
|
case 'jpg': |
||||
|
case 'jpeg': |
||||
|
case 'png': |
||||
|
case 'gif': |
||||
|
case 'svg': |
||||
|
return Picture; |
||||
|
case 'mp4': |
||||
|
case 'mov': |
||||
|
case 'avi': |
||||
|
return VideoPlay; |
||||
|
case 'mp3': |
||||
|
case 'wav': |
||||
|
return Headset; |
||||
|
case 'zip': |
||||
|
case 'rar': |
||||
|
case '7z': |
||||
|
return Files; |
||||
|
default: |
||||
|
return Tickets; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function readableSize(val:matterInfo){ |
||||
|
if(val.size<1024) return "1 Kb" |
||||
|
//1024*1024
|
||||
|
if(val.size<1048576) return (val.size/1024).toFixed(1)+"Kb" |
||||
|
//1024*1024*1024
|
||||
|
if(val.size<1073741824) return (val.size/1048576).toFixed(1)+"Mb" |
||||
|
//1024*1024*1024*1024
|
||||
|
if(val.size<1099511627776) return (val.size/1073741824).toFixed(1)+"Gb" |
||||
|
|
||||
|
return "BIG" |
||||
|
} |
||||
Loading…
Reference in new issue