feat(oa): export mobile PDF via upload and WeChat preview navigate
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
bf22b29d80
commit
8ac1eb3d40
1 file changed
+94
-50
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
import html2canvas from 'html2canvas'
|
||||
import { jsPDF } from 'jspdf'
|
||||
import { uploadAttachment, fetchAttachmentDownloadUrl } from '../../api/oa.js'
|
||||
import { attachmentFullUrl } from '../../utils/attachment.js'
|
||||
import { formatDeptDisplay } from '../kit/oa-dept-value.js'
|
||||
import { formatPersonDisplay } from '../kit/oa-person-value.js'
|
||||
import { formatIdNameDisplay } from '../../utils/id-name-value.js'
|
||||
@@ -871,68 +873,110 @@ function isWeChatMiniWebView() {
|
||||
return false
|
||||
}
|
||||
|
||||
function navigateToHostPdfPreview({ url, fileName }) {
|
||||
const q =
|
||||
'url=' +
|
||||
encodeURIComponent(url) +
|
||||
'&name=' +
|
||||
encodeURIComponent(fileName || 'approval.pdf')
|
||||
const path = '/pages/oa/pdf-preview/index?' + q
|
||||
try {
|
||||
if (typeof wx !== 'undefined' && wx.miniProgram?.navigateTo) {
|
||||
wx.miniProgram.navigateTo({ url: path })
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
if (typeof uni !== 'undefined' && uni.webView?.navigateTo) {
|
||||
uni.webView.navigateTo({ url: path })
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开可打印 HTML 并调用 window.print()。
|
||||
* @returns {Promise<{ ok: boolean, message?: string }>}
|
||||
* @returns {Promise<{ ok: boolean, message?: string, mode?: 'preview' | 'download' }>}
|
||||
*/
|
||||
export async function exportOaApprovalPdf(detail, opts = {}) {
|
||||
if (!detail) {
|
||||
return { ok: false, message: '暂无审批详情,无法打印' }
|
||||
return { ok: false, message: '暂无审批详情,无法导出 PDF' }
|
||||
}
|
||||
|
||||
const model = buildOaPrintModel(detail, {
|
||||
printerName: opts.printerName || ''
|
||||
})
|
||||
const html = buildPrintHtml(model)
|
||||
|
||||
// 微信小程序 web-view 内系统打印能力普遍不可用
|
||||
if (isWeChatMiniWebView()) {
|
||||
return {
|
||||
ok: false,
|
||||
message: '微信内暂不支持系统打印,请用手机浏览器打开或到电脑端导出'
|
||||
}
|
||||
}
|
||||
|
||||
let frame = null
|
||||
let blob
|
||||
let filename
|
||||
try {
|
||||
frame = document.createElement('iframe')
|
||||
frame.setAttribute('title', 'oa-print')
|
||||
frame.style.cssText =
|
||||
'position:fixed;right:0;bottom:0;width:0;height:0;border:0;opacity:0;pointer-events:none;'
|
||||
document.body.appendChild(frame)
|
||||
|
||||
const doc = frame.contentDocument || frame.contentWindow?.document
|
||||
if (!doc || !frame.contentWindow) {
|
||||
throw new Error('print frame unavailable')
|
||||
}
|
||||
doc.open()
|
||||
doc.write(html)
|
||||
doc.close()
|
||||
|
||||
await new Promise((r) => setTimeout(r, 80))
|
||||
const win = frame.contentWindow
|
||||
if (typeof win.print !== 'function') {
|
||||
throw new Error('print not supported')
|
||||
}
|
||||
win.focus()
|
||||
win.print()
|
||||
return { ok: true }
|
||||
;({ blob, filename } = await generateOaApprovalPdfBlob(detail, opts))
|
||||
} catch (e) {
|
||||
return {
|
||||
ok: false,
|
||||
message:
|
||||
(e && e.message) ||
|
||||
'当前环境无法调起打印,请用手机浏览器打开或到电脑端导出'
|
||||
message: (e && e.message) || '生成 PDF 失败'
|
||||
}
|
||||
} finally {
|
||||
if (frame) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
frame.remove()
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
if (isWeChatMiniWebView()) {
|
||||
try {
|
||||
const file = new File([blob], filename, { type: 'application/pdf' })
|
||||
const res = await uploadAttachment(file)
|
||||
const fileUrl = String(res?.fileUrl || res?.data?.fileUrl || '').trim()
|
||||
if (!fileUrl) {
|
||||
return { ok: false, message: '上传 PDF 失败:无文件地址' }
|
||||
}
|
||||
|
||||
let openUrl = ''
|
||||
try {
|
||||
const dl = await fetchAttachmentDownloadUrl({
|
||||
fileUrl,
|
||||
fileName: filename
|
||||
})
|
||||
openUrl = String(dl?.downloadUrl || dl?.data?.downloadUrl || '').trim()
|
||||
} catch {
|
||||
/* fall through */
|
||||
}
|
||||
if (!openUrl) {
|
||||
openUrl = attachmentFullUrl(fileUrl) || fileUrl
|
||||
}
|
||||
if (!/^https?:\/\//i.test(openUrl)) {
|
||||
return { ok: false, message: '无法打开 PDF:下载地址无效' }
|
||||
}
|
||||
|
||||
const navigated = navigateToHostPdfPreview({
|
||||
url: openUrl,
|
||||
fileName: filename
|
||||
})
|
||||
if (!navigated) {
|
||||
return {
|
||||
ok: false,
|
||||
message: '无法跳转预览页,请升级微信后重试'
|
||||
}
|
||||
}, 1500)
|
||||
}
|
||||
return { ok: true, mode: 'preview' }
|
||||
} catch (e) {
|
||||
return {
|
||||
ok: false,
|
||||
message: (e && e.message) || '上传或打开 PDF 失败'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const href = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = href
|
||||
a.download = filename
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
a.remove()
|
||||
setTimeout(() => URL.revokeObjectURL(href), 2000)
|
||||
return { ok: true, mode: 'download' }
|
||||
} catch (e) {
|
||||
return {
|
||||
ok: false,
|
||||
message: (e && e.message) || '下载 PDF 失败'
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user