10 changed files with 385 additions and 28 deletions
@ -0,0 +1,89 @@ |
|||||
|
<script lang="ts" setup> |
||||
|
import { useRoute } from 'vue-router' |
||||
|
import { DocumentEditor } from "@onlyoffice/document-editor-vue"; |
||||
|
import { useUserStore } from "@/store/modules/user"; |
||||
|
|
||||
|
const route = useRoute() |
||||
|
const userStore = useUserStore(); |
||||
|
const siteHost=document.location.origin; |
||||
|
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api" |
||||
|
const onlyOfficeHost= import.meta.env.VITE_ONLYOFFICE_HOST |
||||
|
const props = withDefaults(defineProps<{ |
||||
|
fileurl:string |
||||
|
}>(),{}) |
||||
|
|
||||
|
const config=ref({ |
||||
|
document: { |
||||
|
title: "Example Document Title.docx", |
||||
|
url:"", //云盘服务文件地址 |
||||
|
key:"" |
||||
|
}, |
||||
|
|
||||
|
documentType: "word", |
||||
|
editorConfig: { |
||||
|
"lang": "zh-CN",//"en-US", |
||||
|
mode: "view",//设置编辑模式,view, edit,review |
||||
|
callbackUrl: `${siteHost}${apiURL}/matter/save`, //当前网站的域名 |
||||
|
user: { |
||||
|
id: userStore.userInfoCont.number, |
||||
|
name: userStore.userInfoCont.nickname, |
||||
|
}, |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
function onLoadComponentError (errorCode:number, errorDescription:string) { |
||||
|
switch(errorCode) { |
||||
|
case -1: // Unknown error loading component |
||||
|
alert(errorDescription); |
||||
|
break; |
||||
|
case -2: // Error load DocsAPI from http://documentserver/ |
||||
|
alert(errorDescription); |
||||
|
break; |
||||
|
case -3: // DocsAPI is not defined |
||||
|
alert(errorDescription); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(()=>{ |
||||
|
const query = route.query |
||||
|
if (query.fileurl){ |
||||
|
const info=query.info?.toString()??"error" |
||||
|
const _info=decodeURIComponent(atob(info)) |
||||
|
const _url=decodeURIComponent(query.fileurl) |
||||
|
const name=query.name?.toString()??"" |
||||
|
const dtype=query.dtype?.toString()??"word" |
||||
|
//验证一下文件名是否合规 |
||||
|
if (_info.includes(name)){ |
||||
|
config.value.document.url=_url |
||||
|
config.value.document.title=name |
||||
|
const _key=_url.match(/(\w+-\w+-\w+)/)![0] |
||||
|
if(_key) config.value.document.key=_key //合作编辑必须要有一个unique key |
||||
|
config.value.documentType=dtype |
||||
|
config.value.editorConfig.callbackUrl+=`?info=${_info}` |
||||
|
//设置编辑模式 |
||||
|
if(!query.verify) return; |
||||
|
const _verify = atob(query.verify) |
||||
|
//1:必须是验证通过,以true结尾 2:校验uuid是否匹配 |
||||
|
if(_verify.endsWith("true") && _key.includes(_verify.replace("true",""))){ |
||||
|
config.value.editorConfig.mode="edit" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<DocumentEditor |
||||
|
id="docEditor" |
||||
|
style="height: inherit;" |
||||
|
:documentServerUrl="onlyOfficeHost" |
||||
|
:config="config" |
||||
|
:onLoadComponentError="onLoadComponentError" |
||||
|
/> |
||||
|
</template> |
||||
|
<style> |
||||
|
|
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,160 @@ |
|||||
|
<script lang="ts" setup> |
||||
|
import { |
||||
|
Document, |
||||
|
Delete, |
||||
|
Edit, |
||||
|
View, |
||||
|
} from '@element-plus/icons-vue' |
||||
|
import { shareItem} from "@/api/doc/type" |
||||
|
import {fileType } from "./tools" |
||||
|
|
||||
|
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api" |
||||
|
const siteHost=document.location.origin; |
||||
|
const officeHost=import.meta.env.VITE_OFFICE_HOST |
||||
|
const currentHoverRow=ref("") //当前选择的table行 |
||||
|
const visitList=ref<shareItem[]>([]) |
||||
|
let _db:Object; //indexedDB |
||||
|
|
||||
|
const props = withDefaults(defineProps<{ |
||||
|
uid:string, |
||||
|
udprt:string, |
||||
|
}>(),{}) |
||||
|
|
||||
|
//在线预览 |
||||
|
function onlyOfficeView(row:shareItem){ |
||||
|
const _type=fileType(row.name!) |
||||
|
if(_type!==""){ //office file |
||||
|
const info =btoa(encodeURIComponent(`${row.userUuid}/root${row.matters[0].path}`)) |
||||
|
const _url=`${siteHost}${apiURL}/share/zip?shareUuid=${row.uuid}&code=${row.code}&uid=${props.uid}&dprt=${props.udprt}&puuid=root&rootUuid=root` |
||||
|
window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&fileurl=`+encodeURIComponent(_url),"_blank") |
||||
|
}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=${props.uid}&dprt=${props.udprt}&puuid=root&rootUuid=root&fullfilename=${a}` |
||||
|
window.open(`${officeHost}/kkpreview/onlinePreview?url=`+window.btoa(encodeURIComponent(_url)),"_blank") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//在线编辑 |
||||
|
function onlyOfficeEdit(row:shareItem){ |
||||
|
const _type=fileType(row.name!) |
||||
|
if(_type===""){ |
||||
|
alert("暂不支持该类型编辑") |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
const pstate=(row.permitList?.includes(props.uid)|| row.userUuid===atob(props.uid)) |
||||
|
if (!pstate){ |
||||
|
alert("你没有权限编辑") |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
ElMessageBox.confirm("线上资源有限,确定继续线上编辑吗", "提示", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
//office file |
||||
|
//base64 encode for MASK |
||||
|
const _verify = btoa(row.uuid.match(/(\w+-\w+)/)[0]+`${pstate}`) //增加一个权限验证的标记 |
||||
|
const info =btoa(encodeURIComponent(`${row.userUuid}/root${row.matters[0].path}`)) |
||||
|
const _url=`${siteHost}${apiURL}/share/zip?shareUuid=${row.uuid}&code=${row.code}&uid=${props.uid}&dprt=${props.udprt}&puuid=root&rootUuid=root` |
||||
|
window.open(`/#/onlyoffice?name=${row.name}&dtype=${_type}&info=${info}&verify=${_verify}&fileurl=`+encodeURIComponent(_url),"_blank") |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//前端indexedDB的记录删除操作 |
||||
|
function onClearHistory(row:shareItem){ |
||||
|
_db.transaction('vlist','readwrite').objectStore("vlist").delete(row.uuid); |
||||
|
visitList.value=visitList.value.filter((item)=>{ |
||||
|
return item.uuid!==row.uuid |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function handleMouseEnter(row:any){ |
||||
|
currentHoverRow.value=row.uuid |
||||
|
} |
||||
|
|
||||
|
onMounted(()=>{ |
||||
|
const request = indexedDB.open('visitList') |
||||
|
request.onupgradeneeded = (event) => { |
||||
|
// 首次创建或升级版本时触发 |
||||
|
_db = event.target.result; |
||||
|
if (!_db.objectStoreNames.contains('vlist')) { |
||||
|
// 创建对象仓库(类似表) |
||||
|
const store = _db.createObjectStore('vlist', { |
||||
|
keyPath: 'uuid', // 主键 |
||||
|
}); |
||||
|
} |
||||
|
}; |
||||
|
request.onsuccess = (e) => { |
||||
|
if (!_db) _db= e.target.result; |
||||
|
const store = _db.transaction('vlist', 'readonly').objectStore("vlist"); |
||||
|
|
||||
|
store.openCursor().onsuccess = (event) => { |
||||
|
const cursor = event.target.result; |
||||
|
if (cursor) { |
||||
|
visitList.value.push(cursor.value); |
||||
|
cursor.continue(); |
||||
|
} |
||||
|
}; |
||||
|
}; |
||||
|
}) |
||||
|
|
||||
|
onUnmounted(()=>{ |
||||
|
if (_db) _db.close() |
||||
|
}) |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<el-row :gutter="24"> |
||||
|
<el-table |
||||
|
stripe |
||||
|
:data="visitList" |
||||
|
:header-cell-style="{ background: '#f5f8fd' }" |
||||
|
style="width: 100%" |
||||
|
row-key="uuid" |
||||
|
:row-style ="() => ({ height: '30px' })" |
||||
|
@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="20"><component :is="Document" /></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.uuid"> |
||||
|
<el-button size="small" :icon="View" circle @click="onlyOfficeView(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Edit" circle @click="onlyOfficeEdit(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Delete" circle @click="onClearHistory(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(0,16) }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</el-row> |
||||
|
</template> |
||||
|
<style> |
||||
|
|
||||
|
</style> |
||||
Loading…
Reference in new issue