|
|
|
|
<!--
|
|
|
|
|
@ 作者: 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=document.location.origin;
|
|
|
|
|
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>
|