5 changed files with 394 additions and 12 deletions
@ -0,0 +1,376 @@ |
|||||
|
<!-- |
||||
|
@ 作者: han2015 |
||||
|
@ 时间: 2025-05-12 15:39:13 |
||||
|
@ 备注: 文档管理组件 |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
|
||||
|
import { getShareList,getShareBrowse,postShareDelete} from "@/api/doc/index" |
||||
|
import { matterPage,matterInfo,respCreateShare } from "@/api/doc/type" |
||||
|
import { h } from 'vue' |
||||
|
import router from "@/utils/router"; |
||||
|
import { useRoute } from 'vue-router' |
||||
|
import { userStror } from "@/utils/pinia/stores/modules/userOrders"; |
||||
|
import { |
||||
|
ArrowLeft, |
||||
|
Avatar, |
||||
|
} from '@element-plus/icons-vue' |
||||
|
import {ElText,ElButton } from "element-plus"; |
||||
|
import {getFileIcon,checkExpirTime,fileType } from "./tools" |
||||
|
import sharePermission from './sharePermission.vue'; |
||||
|
import preview from './preview.vue'; |
||||
|
|
||||
|
const userStore = userStror(); |
||||
|
const uid=btoa("p0"+userStore.userInfoCont.userId); |
||||
|
const siteHost=document.location.origin; |
||||
|
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api" |
||||
|
const udprt=btoa("d"+userStore.userInfoCont.department); |
||||
|
const route = useRoute() |
||||
|
|
||||
|
const officeHost=import.meta.env.VITE_OFFICE_HOST |
||||
|
const matterList = ref<matterInfo[]>() //文件列表 |
||||
|
const browerMode=ref(false) //share模式 1)self-list(default) 2)brower |
||||
|
// const drawerModel=ref(false) //右侧隐藏抽屉组件的状态控制 |
||||
|
// const permitListRef=ref("") //右侧抽屉组件中文档成员列表的key数组字符串 |
||||
|
|
||||
|
//-------------手机底部悬浮窗控制----------- |
||||
|
const showPopup=ref(false) |
||||
|
const currentHoverRow=ref<matterInfo>({}) //table 行的按钮控制 |
||||
|
//---------------------------------- |
||||
|
|
||||
|
import type { VNode } from 'vue' |
||||
|
const dynamicVNode = ref<VNode | null>(null) //permission 组件的父组件 |
||||
|
|
||||
|
|
||||
|
function showShareMessage(row:{uuid:string,code:string,name:string,expireTime:string}){ |
||||
|
let _shareURL=`${siteHost}/#/docshare?uuid=${row.uuid}&code=${row.code}` |
||||
|
ElMessageBox({ |
||||
|
title: '分享详情', |
||||
|
customStyle: { padding:'20px'}, |
||||
|
message: () => h('div',{style:{display:'flex','flex-direction':'column','line-height':'34px'}},[ |
||||
|
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('div',[ |
||||
|
h(ElButton, { |
||||
|
type: 'primary', |
||||
|
style: { width: '100px' }, |
||||
|
onClick: () => { |
||||
|
let _url=apiURL+`/share/zip?shareUuid=${row.uuid}&code=${row.code}&dprt=${udprt}&puuid=root&rootUuid=root` |
||||
|
window.open(_url) |
||||
|
} |
||||
|
},()=>'下载'), |
||||
|
h(ElButton, { |
||||
|
type: 'primary', |
||||
|
style: { width: '100px',margin:'0 10px' }, |
||||
|
onClick: () => { |
||||
|
onShareView(row) |
||||
|
} |
||||
|
},()=>'预览') |
||||
|
]) |
||||
|
]), |
||||
|
confirmButtonText: '复制分享链接', |
||||
|
showCancelButton: true |
||||
|
}).then(()=>{ |
||||
|
if(!navigator.clipboard) alert("clipboard 不可用") |
||||
|
navigator.clipboard.writeText(_shareURL) |
||||
|
}).catch(() => { |
||||
|
if (browerMode.value){ |
||||
|
location.href=`/#/docshare` |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//---------------------------------------- |
||||
|
//删除分享 |
||||
|
function onShareDelete(row:matterInfo){ |
||||
|
if (row.uuid){ |
||||
|
ElMessageBox.confirm("确认要取消此文件分享!", "警告", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
postShareDelete(uid,{ |
||||
|
"uuid":row.uuid |
||||
|
}).then(()=>onLoadShareList()) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//编辑分享成员 |
||||
|
function onShareMember(row:matterInfo){ |
||||
|
dynamicVNode.value=h(sharePermission,{ |
||||
|
uid:uid, |
||||
|
uuid:row.uuid, |
||||
|
closeFunc:(refresh?:boolean)=>{ |
||||
|
dynamicVNode.value=null |
||||
|
if (refresh) { |
||||
|
permitListRef.value="" |
||||
|
drawerModel.value=false |
||||
|
onLoadShareList() |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//文件预览 |
||||
|
function onShareView(row:matterInfo){ |
||||
|
const _type=fileType(row.name!) |
||||
|
if(_type!==""){ //office file |
||||
|
const info =btoa(encodeURIComponent(`${row.name}`)) //预览模式不需要绝对路径,只核对一下文件名即可 |
||||
|
const _url=`${siteHost}${apiURL}/share/zip?shareUuid=${row.uuid}&code=${row.code}&uid=${uid}&dprt=${udprt}&puuid=root&rootUuid=root` |
||||
|
//window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&fileurl=`+window.btoa(encodeURIComponent(_url)),"_blank") |
||||
|
router.push({ path: "/onlyoffice",query:{fa:7,name:row.name,dtype:_type,info:info,fileurl: window.btoa(encodeURIComponent(_url)) }}); |
||||
|
}else{ |
||||
|
//by kkFilePreview |
||||
|
let a = row.name ?? ''; |
||||
|
if(a.endsWith('...')){ |
||||
|
a=`${row.uuid}-${row.code}.zip` |
||||
|
} |
||||
|
|
||||
|
//由于预览服务在缓存文件时,直接按文件名缓存,所以同名文件就会出现覆盖错乱的问题 |
||||
|
a=a.match("(\.[a-zA-Z]+)$") |
||||
|
if (a && a.length>0) { |
||||
|
a=`${row.uuid}-${row.code}${a[0]}` |
||||
|
}else{ |
||||
|
a=`${row.uuid}${row.name}` |
||||
|
} |
||||
|
|
||||
|
let _url=`${siteHost}${apiURL}/share/zip?shareUuid=${row.uuid}&code=${row.code}&uid=${uid}&dprt=${udprt}&puuid=root&rootUuid=root&fullfilename=${a}` |
||||
|
//window.open(`${officeHost}/kkpreview/onlinePreview?url=`+window.btoa(encodeURIComponent(_url)),"_blank") |
||||
|
dynamicVNode.value=h(preview,{ |
||||
|
url:`${officeHost}/kkpreview/onlinePreview?url=`+window.btoa(unescape(encodeURIComponent(_url))), |
||||
|
closeFunc:()=>dynamicVNode.value=null |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
function onDownload(row:matterInfo){ |
||||
|
ElMessageBox.confirm("确认下载此数据项?", "提示", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
if (row.uuid){ |
||||
|
let _url=apiURL+`/share/zip?shareUuid=${row.uuid}&code=${row.code}&dprt=${udprt}&puuid=root&rootUuid=root` |
||||
|
window.open(_url) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//加载文件列表 |
||||
|
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.uuid |
||||
|
} |
||||
|
|
||||
|
function getItemSpan(str:string){ |
||||
|
let span=parseInt(str.split(":")[0])-3 //为何要减3,因为系统公司层级的level从3开始,层级递增4,5,6... |
||||
|
if(span<0) span=0 |
||||
|
return `margin-left:${span*20}px` |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
const query = route.query |
||||
|
//只是分享链接的请求 |
||||
|
if (query.uuid && query.code){ |
||||
|
browerMode.value=true |
||||
|
getShareBrowse("",{shareUuid:query.uuid,code:query.code,puuid:'root',rootUuid:'root',dprt:udprt}).then((resp)=>{ |
||||
|
showShareMessage(resp.data) |
||||
|
// const request = indexedDB.open('visitList') |
||||
|
// request.onsuccess = (e) => { |
||||
|
// const db = e.target.result; |
||||
|
// const store = db.transaction('vlist','readwrite').objectStore("vlist"); |
||||
|
// store.put(resp.data) |
||||
|
// db.close() |
||||
|
// } |
||||
|
}) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
browerMode.value=false |
||||
|
onLoadShareList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="navBtn"> |
||||
|
<el-button type="text" :icon="ArrowLeft" @click="router.back()">返回</el-button> |
||||
|
</div> |
||||
|
<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="uuid" |
||||
|
:row-style ="() => ({ height: '55px' })" |
||||
|
> |
||||
|
<el-table-column property="name" label="我的文件分享"> |
||||
|
<template #default="scope"> |
||||
|
<div style="display: flex; align-items: center"> |
||||
|
<svg-icon v-if="scope.row.dir" icon-class="folder-icon" :size="26"/> |
||||
|
<svg-icon v-else :icon-class="getFileIcon(scope.row.name)+'-icon'" :size="26" /> |
||||
|
<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.uuid"> |
||||
|
<el-button size="small" :icon="Avatar" circle @click="()=>{drawerModel=true; permitListRef=scope.row.permitInfos}"></el-button> |
||||
|
<el-button size="small" :icon="View" circle @click="onShareView(scope.row)"></el-button> |
||||
|
<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 width="100" prop="expireTime" label="失效日期"> |
||||
|
<template #default="scope"> |
||||
|
<span v-if="scope.row.expireTime">{{ scope.row.expireInfinity? '永久': scope.row.expireTime.slice(5,10) }}</span> |
||||
|
<el-button class="setBtn" type="text" icon="MoreFilled" size="small" |
||||
|
@click="(e)=>{e.stopPropagation(); showPopup=true; currentHoverRow=scope.row;}"></el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
</el-table> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
|
||||
|
<div v-if="showPopup" class="mask" @click="showPopup = false"></div> |
||||
|
<!-- 主体 --> |
||||
|
<Transition name="popuper"> |
||||
|
<div v-if="showPopup" class="bs-wrapper"> |
||||
|
<div class="popupTitle"> |
||||
|
<svg-icon v-if="currentHoverRow.dir" icon-class="folder-icon" size="30px"/> |
||||
|
<svg-icon v-else :icon-class="getFileIcon(currentHoverRow.name)+'-icon'" size="30px"/> |
||||
|
{{ currentHoverRow.name }} |
||||
|
<el-button type="text" @click="showPopup=false">关闭</el-button> |
||||
|
</div> |
||||
|
<hr> |
||||
|
<div class="blocker-list"> |
||||
|
<span class="blocker" @click="onShareView(currentHoverRow)"> |
||||
|
<View class="plus-icon"></View>预览</span> |
||||
|
<span class="blocker" @click="showShareMessage(currentHoverRow)"> |
||||
|
<View class="plus-icon"></View>详情</span> |
||||
|
<span class="blocker" @click="onDownload(currentHoverRow)"> |
||||
|
<Download class="plus-icon"></Download>下载</span> |
||||
|
<span class="blocker" @click="onShareDelete(currentHoverRow)"> |
||||
|
<Delete class="plus-icon"></Delete>删除</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</Transition> |
||||
|
|
||||
|
<div v-if="dynamicVNode" style="height: inherit;"> |
||||
|
<component :is="dynamicVNode" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.app_container { |
||||
|
padding: 10px; |
||||
|
height: calc(100% - 10px); |
||||
|
overflow-y: auto; |
||||
|
width: 100%; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.navBtn{ |
||||
|
position: fixed; |
||||
|
background-color: #ffffff94; |
||||
|
width: 100%; |
||||
|
z-index: 55; |
||||
|
} |
||||
|
|
||||
|
//---------------animation |
||||
|
/* 遮罩: popup 的遮罩 */ |
||||
|
.mask{ |
||||
|
position: fixed; |
||||
|
inset: 0; |
||||
|
background:rgba(0,0,0,.4); |
||||
|
z-index:999; |
||||
|
} |
||||
|
|
||||
|
.bs-wrapper{ |
||||
|
position: fixed; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
left:0; |
||||
|
right:0; |
||||
|
bottom:0; |
||||
|
height:36vh; /* 半屏停住 */ |
||||
|
background:#f1f1f1; |
||||
|
border-radius:16px 16px 0 0; |
||||
|
z-index:1000; |
||||
|
overflow-y:auto; |
||||
|
padding: 8px 16px; |
||||
|
hr{ |
||||
|
margin: 8px 0; |
||||
|
border: none; |
||||
|
width: 88%; |
||||
|
align-self: center; |
||||
|
background: #63616145; |
||||
|
} |
||||
|
} |
||||
|
.popupTitle{ |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
button{ |
||||
|
margin-left: auto; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
} |
||||
|
.blocker-list{ |
||||
|
display: grid; |
||||
|
grid-template-columns: 1fr 1fr 1fr 1fr; |
||||
|
font-size: small; |
||||
|
.blocker{ |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
padding-top: 15px; |
||||
|
background-color: white; |
||||
|
border-radius: 5px; |
||||
|
margin: 6px; |
||||
|
width: 70px; |
||||
|
height: 70px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.popuper-enter-from{ |
||||
|
transform:translateY(100%); |
||||
|
opacity:0; |
||||
|
} |
||||
|
/* 进入过程 */ |
||||
|
.popuper-enter-active{ |
||||
|
transition:all .3s ease-out; |
||||
|
} |
||||
|
/* 离开后:回到下方 */ |
||||
|
.popuper-leave-to{ |
||||
|
transform:translateY(50px); |
||||
|
opacity:0; |
||||
|
} |
||||
|
.popuper-leave-active{ |
||||
|
transition:all .3s ease-in; |
||||
|
} |
||||
|
|
||||
|
.plus-icon{ |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
} |
||||
|
//--------------------------- |
||||
|
</style> |
||||
Loading…
Reference in new issue