wip: load file and replace

This commit is contained in:
zzs 2025-03-22 11:49:12 +08:00
parent 68c77b35d7
commit e502cf6881
3 changed files with 143 additions and 29 deletions

View File

@ -26,9 +26,27 @@ onMounted(() => {
}, 300) }, 300)
}) })
function sendMessageToIframe(message: any) {
console.log('proxy func exec, sendMessageToIframe')
if (frameRef.value && frameRef.value.contentWindow) {
console.log(`proxy func exec, message send ${JSON.stringify(message)}`)
frameRef.value.contentWindow.postMessage(message, '*')
}
}
defineExpose({ defineExpose({
frameRef, frameRef,
sendMessageToIframe,
}) })
// onMounted(() => {
// //
// window.addEventListener('message', (event) => {
// //
// if (event.data)
// console.warn(event.data)
// })
// })
</script> </script>
<template> <template>

View File

@ -14,13 +14,14 @@ import { getConfigKey } from '@/api/infra/config'
import type { FileDO } from '@/types/axios' import type { FileDO } from '@/types/axios'
import { useGlobSetting } from '@/hooks/setting' import { useGlobSetting } from '@/hooks/setting'
import { getAccessToken } from '@/utils/auth' import { getAccessToken } from '@/utils/auth'
import { extractMethodName } from '@/views/infra/bookmark/logic'
defineOptions({ name: 'BookmarkReplace' }) defineOptions({ name: 'BookmarkReplace' })
const isEmbed = isInIframe() const isEmbed = isInIframe()
const globSetting = useGlobSetting() const globSetting = useGlobSetting()
const previewUrl = ref<string | undefined>(undefined) const previewUrl = ref<string | undefined>(undefined)
const frameComponent = ref<{ frameRef: HTMLIFrameElement } | null>(null) const iframeRef = ref<InstanceType<typeof IFrame> | null>(null)
const { createMessage } = useMessage() const { createMessage } = useMessage()
@ -29,6 +30,8 @@ const wopi_server = ref(undefined)
const editStatus = ref<{ Modified: boolean }>({ Modified: false }) const editStatus = ref<{ Modified: boolean }>({ Modified: false })
const currentEditFile = ref<FileDO | undefined>(undefined) const currentEditFile = ref<FileDO | undefined>(undefined)
const isPostMessageRead = ref<boolean>(false)
onMounted(async () => { onMounted(async () => {
wopi_client.value = await getConfigKey('wopi_client_addr') wopi_client.value = await getConfigKey('wopi_client_addr')
wopi_server.value = await getConfigKey('wopi_server_ip_addr') wopi_server.value = await getConfigKey('wopi_server_ip_addr')
@ -47,27 +50,37 @@ onMounted(async () => {
if (typeof e.data === 'object') if (typeof e.data === 'object')
data = e.data data = e.data
if (!data)
return
const ActionId = data.ActionId const ActionId = data.ActionId
const MessageId = data.MessageId const MessageId = data.MessageId
// Event // Event
switch (ActionId) { switch (ActionId) {
case 'OPEN_FILE': case 'OpenFile':
await handleFileBinary(e) await handleFileBinary(data)
break
case 'QueryAllWithJSON':
proxyQueryBookmark()
break
case 'ReplaceWithJSON':
proxyReplaceWithJSON(data)
break break
} }
console.warn(`MessageId:${MessageId}`)
// WOPI Client // WOPI Client
switch (MessageId) { switch (MessageId) {
// //
case 'Doc_ModifiedStatus': case 'Doc_ModifiedStatus':
handleUpdateModifiedStatus(e) handleUpdateModifiedStatus(data)
break break
// //
case 'UI_Save': case 'UI_Save':
console.warn('UI_Save')
handleUserSaveOp() handleUserSaveOp()
break break
case 'CallPythonScript-Result':
handlePythonScriptCallBack(data)
break
} }
}) })
}) })
@ -76,18 +89,16 @@ onMounted(async () => {
* 更新是否编辑状态 * 更新是否编辑状态
* 保存后会更新是否编辑为否正常编辑后会更新是否编辑为是 * 保存后会更新是否编辑为否正常编辑后会更新是否编辑为是
* 用于区分是否要向第三方发送保存文件的回调 * 用于区分是否要向第三方发送保存文件的回调
* @param e * @param data
*/ */
function handleUpdateModifiedStatus(e: MessageEvent) { function handleUpdateModifiedStatus(data: any) {
editStatus.value.Modified = JSON.parse(e.data).Values.Modified editStatus.value.Modified = data.Values.Modified
} }
let pollingInterval: NodeJS.Timeout | null = null let pollingInterval: NodeJS.Timeout | null = null
let lastCallTime: number | null = null let lastCallTime: number | null = null
async function handleUserSaveOp() { async function handleUserSaveOp() {
console.warn('handleUserSaveOp')
// 1: // 1:
if (!editStatus.value.Modified) { if (!editStatus.value.Modified) {
// //
@ -136,8 +147,6 @@ function cleanup() {
* 下载当前编辑的文件发送给调用者 * 下载当前编辑的文件发送给调用者
*/ */
async function downloadAndSendCurrentEditFile() { async function downloadAndSendCurrentEditFile() {
console.warn('downloadAndSendCurrentEditFile')
if (!currentEditFile.value) if (!currentEditFile.value)
return return
try { try {
@ -173,10 +182,10 @@ async function downloadAndSendCurrentEditFile() {
/** /**
* 第三方上传文件 * 第三方上传文件
* @param e * @param data
*/ */
async function handleFileBinary(e: MessageEvent) { async function handleFileBinary(data: any) {
const { name, type, buffer } = e.data.Payload const { name, type, buffer } = data.Payload
const blob = new Blob([buffer], { type }) const blob = new Blob([buffer], { type })
const uploadResult = await uploadOneFile({ const uploadResult = await uploadOneFile({
filename: name, filename: name,
@ -186,21 +195,61 @@ async function handleFileBinary(e: MessageEvent) {
previewUrl.value = await initFilePreviewUrl(currentEditFile.value.id, wopi_client.value, wopi_server.value) previewUrl.value = await initFilePreviewUrl(currentEditFile.value.id, wopi_client.value, wopi_server.value)
} }
/**
* 第三方调用查询所有书签
*/
function proxyQueryBookmark() {
sendMessageToWopiClient({
MessageId: 'CallPythonScript',
SendTime: Date.now(),
ScriptFile: 'BookmarkOP.py',
Function: 'QueryAllWithJSON',
})
}
/**
* 第三方调用书签替换
* @param data
*/
function proxyReplaceWithJSON(data: any) {
sendMessageToWopiClient({
MessageId: 'CallPythonScript',
SendTime: Date.now(),
ScriptFile: 'BookmarkOP.py',
Function: 'ReplaceWithJSON',
Values: {
params: {
type: 'string',
value: JSON.stringify(data.Payload),
},
},
})
}
/** /**
* 发送消息给WopiClient * 发送消息给WopiClient
* 用于执行书签相关操作 * 用于执行书签相关操作
*/ */
// function sendMessageToWopiClient(data: any) { function sendMessageToWopiClient(data: any) {
// if (!frameComponent.value?.frameRef.contentWindow) try {
// createMessage.error('WOPI Client iframe ') if (!isPostMessageRead.value) {
// try { console.log('Host准备好')
// frameComponent.value?.frameRef.contentWindow?.postMessage(data, '*') iframeRef.value?.sendMessageToIframe(JSON.stringify({
// } MessageId: 'Host_PostmessageReady',
// catch (e) { SendTime: Date.now(),
// console.error(e) }))
// createMessage.error(``) isPostMessageRead.value = true
// } }
// }
iframeRef.value?.sendMessageToIframe(JSON.stringify(data))
console.log('已向WOPI_Client发送消息')
console.log(JSON.stringify(data))
}
catch (e) {
console.error(e)
createMessage.error(`消息发送失败,查看控制台日志!`)
}
}
/** /**
* 发送消息给第三方调用者 * 发送消息给第三方调用者
@ -209,7 +258,11 @@ async function handleFileBinary(e: MessageEvent) {
function sendMessageToCaller(data: any) { function sendMessageToCaller(data: any) {
try { try {
const targetWindow = window.parent const targetWindow = window.parent
targetWindow.postMessage(data, '*') if (typeof data === 'string')
targetWindow.postMessage(data, '*')
if (typeof data === 'object')
targetWindow.postMessage(JSON.stringify(data), '*')
} }
catch (e) { catch (e) {
console.error(e) console.error(e)
@ -217,6 +270,27 @@ function sendMessageToCaller(data: any) {
} }
} }
/**
* Python脚本执行回调
* @param data
*/
function handlePythonScriptCallBack(data: any) {
const Values = data.Values
const success = Values.success as boolean
const commandName = Values.commandName
if (success) {
const jsonData = JSON.parse(Values.result.value)
sendMessageToCaller({
ActionId: extractMethodName(commandName),
Payload: jsonData,
})
}
else {
console.error(data)
createMessage.error(`执行Python脚本失败: ${data.Values.result.value}`)
}
}
function logEvent(e: MessageEvent) { function logEvent(e: MessageEvent) {
console.log('=============receive message start=======') console.log('=============receive message start=======')
console.log(e.data) console.log(e.data)
@ -229,7 +303,7 @@ function logEvent(e: MessageEvent) {
<div class="flex flex-col" :class="{ 'p-2 pt-4': !isEmbed }"> <div class="flex flex-col" :class="{ 'p-2 pt-4': !isEmbed }">
<div class="w-full flex flex-row" :class="{ 'h-[calc(100vh)]': isEmbed, 'h-[calc(100vh-105px)]': !isEmbed }"> <div class="w-full flex flex-row" :class="{ 'h-[calc(100vh)]': isEmbed, 'h-[calc(100vh-105px)]': !isEmbed }">
<div class="w-full flex flex-row bg-white dark:bg-black"> <div class="w-full flex flex-row bg-white dark:bg-black">
<i-frame v-if="previewUrl" ref="frameComponent" class="w-full bg-white dark:bg-black" :src="previewUrl" :height="isEmbed ? 'calc(100vh)' : 'calc(100vh) - 105px'" /> <i-frame v-if="previewUrl" ref="iframeRef" class="w-full bg-white dark:bg-black" :src="previewUrl" :height="isEmbed ? 'calc(100vh)' : 'calc(100vh) - 105px'" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,22 @@
/**
*
* vnd.sun.star.script:BookmarkOP.py$QueryAllWithJSON?language=Python&location=share
* @param input
*/
export function extractMethodName(input: string): string | null {
// 查找最后一个 $ 的位置
const dollarIndex = input.lastIndexOf('$')
if (dollarIndex === -1)
return null
// 截取 $ 之后的部分
const afterDollar = input.slice(dollarIndex + 1)
// 查找参数分隔符 ?
const questionMarkIndex = afterDollar.indexOf('?')
// 返回方法名部分
return questionMarkIndex === -1
? afterDollar
: afterDollar.substring(0, questionMarkIndex)
}