76 lines
3.4 KiB
Vue
76 lines
3.4 KiB
Vue
<template>
|
||
<view class="contract-document">
|
||
<text class="contract-document__title">{{ fileName }}</text>
|
||
<text>{{ message }}</text>
|
||
<button :disabled="busy || !documentInfo" @click="openDocument">{{ busy ? '正在打开…' : '打开文档' }}</button>
|
||
<text class="contract-document__hint">打开后可从右上角菜单转发文件;打印请将 PDF 交给支持打印的应用或电脑。</text>
|
||
<button @click="goBack">返回合同</button>
|
||
</view>
|
||
</template>
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onLoad, onUnload } from '@dcloudio/uni-app'
|
||
import { MINIO_BASE_URL } from '@/config/env'
|
||
import { validateContractDocument, contractDownloadErrorMessage } from '@/utils/contract-document'
|
||
const fileName = ref('合同文档')
|
||
const message = ref('正在准备文档…')
|
||
const busy = ref(false)
|
||
const documentInfo = ref(null)
|
||
let localPath = ''
|
||
let alive = true
|
||
let downloadTask
|
||
function removeTemp(path) {
|
||
if (!path) return
|
||
try { uni.getFileSystemManager().unlink({ filePath: path, fail() {} }) } catch {}
|
||
}
|
||
function goBack() { uni.navigateBack({ delta: 1 }) }
|
||
async function openDocument() {
|
||
if (busy.value || !documentInfo.value) return
|
||
busy.value = true
|
||
message.value = '正在下载并打开文档…'
|
||
try {
|
||
if (!localPath) {
|
||
localPath = await new Promise((resolve, reject) => {
|
||
downloadTask = uni.downloadFile({
|
||
url: documentInfo.value.url,
|
||
success: (res) => {
|
||
if (!alive) { removeTemp(res.tempFilePath); reject(new Error('已关闭')); return }
|
||
if (res.statusCode !== 200) { removeTemp(res.tempFilePath); reject(new Error('文件下载失败,请返回合同重新生成')); return }
|
||
resolve(res.tempFilePath)
|
||
},
|
||
fail: (error) => reject(new Error(contractDownloadErrorMessage(error, documentInfo.value.url)))
|
||
})
|
||
})
|
||
}
|
||
if (!alive) return
|
||
await new Promise((resolve, reject) => uni.openDocument({
|
||
filePath: localPath,
|
||
fileType: documentInfo.value.type,
|
||
showMenu: true,
|
||
success: resolve,
|
||
fail: () => reject(new Error('无法打开文档,请重试'))
|
||
}))
|
||
message.value = '文档已打开,可再次打开或返回继续编辑合同。'
|
||
} catch (error) {
|
||
if (alive) message.value = error.message || '打开失败,请重试'
|
||
} finally { if (alive) busy.value = false }
|
||
}
|
||
onLoad((query) => {
|
||
try {
|
||
// uni-app 页面参数按平台可能已解码,最多解码一次完整 URL。
|
||
const url = /^https?:\/\//.test(query?.url || '') ? query.url : decodeURIComponent(query?.url || '')
|
||
documentInfo.value = validateContractDocument({ ...query, url }, MINIO_BASE_URL)
|
||
fileName.value = documentInfo.value.name
|
||
try { fileName.value = decodeURIComponent(fileName.value) } catch { /* 参数可能已由宿主解码 */ }
|
||
void openDocument()
|
||
} catch (error) { message.value = error.message || '无效的文档地址' }
|
||
})
|
||
onUnload(() => { alive = false; downloadTask?.abort(); removeTemp(localPath) })
|
||
</script>
|
||
<style scoped>
|
||
.contract-document { padding: 24px 16px; display: flex; flex-direction: column; gap: 16px; color: #243b33; }
|
||
.contract-document__title { font-size: 18px; font-weight: 600; word-break: break-all; }
|
||
.contract-document button { width: 100%; min-height: 44px; color: #0a9f6d; background: #e9f9f2; }
|
||
.contract-document__hint { font-size: 13px; color: #6b7b74; line-height: 1.6; }
|
||
</style>
|