|
|
@@ -9,23 +9,38 @@
|
|
|
>
|
|
|
<iframe
|
|
|
:src="fileUrl"
|
|
|
- width="100%"
|
|
|
v-if="showEditFlag"
|
|
|
- style="height: calc(100vh - 100px); position: absolute; left: -1000000px"
|
|
|
+ style="height: 100vh; width: 100%; position: absolute; left: -1000000px; top: 0;"
|
|
|
frameborder="0"
|
|
|
allowfullscreen="true"
|
|
|
ref="Iframe"
|
|
|
id="Iframe"
|
|
|
></iframe>
|
|
|
|
|
|
- <seal ref="sealRef" @pdf-generated="pdfGenerated"></seal>
|
|
|
+ <div class="seal-wrapper" :class="{ 'is-locking': !allPagesLoaded }">
|
|
|
+ <seal ref="sealRef" @pdf-generated="pdfGenerated"></seal>
|
|
|
+
|
|
|
+ <div v-if="!allPagesLoaded" class="seal-lock-hint">
|
|
|
+ <i class="el-icon-loading seal-lock-spinner"></i>
|
|
|
+ <span class="seal-lock-text">
|
|
|
+ PDF 只加载了前 2 页,点击下方"加载全部页"按钮后可盖印到任意页
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
<template slot="footer">
|
|
|
+ <el-button
|
|
|
+ size="small"
|
|
|
+ @click="renderAllPages"
|
|
|
+ :disabled="allPagesLoaded"
|
|
|
+ >{{ allPagesLoaded ? '已加载全部页' : '加载全部页' }}</el-button
|
|
|
+ >
|
|
|
+
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
size="small"
|
|
|
@click="handleSave"
|
|
|
- :disabled="false"
|
|
|
+ :disabled="!allPagesLoaded"
|
|
|
>保存</el-button
|
|
|
>
|
|
|
|
|
|
@@ -44,7 +59,8 @@
|
|
|
return {
|
|
|
fileUrl: '',
|
|
|
showEditFlag: false,
|
|
|
- restoreData: null
|
|
|
+ restoreData: null,
|
|
|
+ allPagesLoaded: false // 是否已加载全部页(控制"加载全部页"按钮 + 盖章交互的启用)
|
|
|
};
|
|
|
},
|
|
|
components: { seal },
|
|
|
@@ -88,36 +104,153 @@
|
|
|
setFileUrl(row) {
|
|
|
let file = row.stampStoragePath[0] || row.storagePath[0];
|
|
|
let fileNames = file.storePath.split('/');
|
|
|
+ // kkFileView 部署在远程,需用远程地址拼 URL(VUE_APP_API_BASE_HOST 已配置为 http://aiot.zoomwin.com.cn:51001)
|
|
|
+ const apiBaseHost =
|
|
|
+ process.env.VUE_APP_API_BASE_HOST || window.location.origin;
|
|
|
let url =
|
|
|
- window.location.origin +
|
|
|
+ apiBaseHost +
|
|
|
'/api/main/file/getFile?objectName=' +
|
|
|
file.storePath +
|
|
|
'&fullfilename=' +
|
|
|
fileNames[fileNames.length - 1];
|
|
|
this.fileUrl = '/kkfile/onlinePreview?url=' + btoa(url);
|
|
|
+ this.allPagesLoaded = false;
|
|
|
+
|
|
|
this.$nextTick(() => {
|
|
|
this.$refs.Iframe.onload = () => {
|
|
|
- var iframe = document.getElementById('Iframe');
|
|
|
- console.log(iframe);
|
|
|
- var iframeDocument = iframe.contentWindow.document;
|
|
|
- console.log(iframeDocument);
|
|
|
-
|
|
|
- var container = iframeDocument.querySelectorAll('.container');
|
|
|
- console.log(container);
|
|
|
-
|
|
|
- this.$refs.sealRef.init(
|
|
|
- container[0].innerHTML.replace(
|
|
|
- /src="https?:\/\/[^\/]+(\/[^"]*)"/g,
|
|
|
- `src="${window.location.origin}$1"`
|
|
|
- ),
|
|
|
- {
|
|
|
- droppedImages: row.droppedImages || ''
|
|
|
+ setTimeout(() => {
|
|
|
+ // 检查 PDF 总页数(kkFileView 在 .container 内为每页生成一个 .page / img)
|
|
|
+ var iframeDoc = this.$refs.Iframe.contentWindow.document;
|
|
|
+ var pages = iframeDoc.querySelectorAll(
|
|
|
+ '.container .page, .container img'
|
|
|
+ );
|
|
|
+ console.log('PDF 检测到总页数:', pages.length);
|
|
|
+ if (pages.length > 0 && pages.length <= 2) {
|
|
|
+ // ≤ 2 页:无需加载全部,直接视为已加载
|
|
|
+ console.log('PDF ≤ 2 页,自动标记为已加载,跳过手动加载步骤');
|
|
|
+ this.allPagesLoaded = true;
|
|
|
}
|
|
|
- );
|
|
|
+ this.extractAndInit('初始');
|
|
|
+ }, 800);
|
|
|
};
|
|
|
});
|
|
|
+ },
|
|
|
+ renderAllPages() {
|
|
|
+ if (this.allPagesLoaded) return;
|
|
|
+ var iframe = document.getElementById('Iframe');
|
|
|
+ if (!iframe) return;
|
|
|
+ var iframeWin = iframe.contentWindow;
|
|
|
+ var iframeDoc = iframeWin.document;
|
|
|
+
|
|
|
+ var scrollHeight = Math.max(
|
|
|
+ iframeDoc.documentElement.scrollHeight,
|
|
|
+ iframeDoc.body.scrollHeight
|
|
|
+ );
|
|
|
+
|
|
|
+ console.log('开始反向滚动让所有页面渲染,scrollHeight=', scrollHeight);
|
|
|
+
|
|
|
+ // 从底反向滚到顶,让 pdfjs 把所有 page canvas 渲染到 viewport
|
|
|
+ var scrolled = scrollHeight;
|
|
|
+ var step = -300;
|
|
|
+ var delay = 60;
|
|
|
+ var interval = setInterval(() => {
|
|
|
+ scrolled += step;
|
|
|
+ iframeWin.scrollTo(0, Math.max(0, scrolled));
|
|
|
+ if (scrolled <= 0) {
|
|
|
+ clearInterval(interval);
|
|
|
+ iframeWin.scrollTo(0, scrollHeight);
|
|
|
+ setTimeout(() => {
|
|
|
+ this.extractAndInit('全渲染完成');
|
|
|
+ this.allPagesLoaded = true;
|
|
|
+ }, 800);
|
|
|
+ }
|
|
|
+ }, delay);
|
|
|
+
|
|
|
+ // 30s 兜底
|
|
|
+ setTimeout(() => {
|
|
|
+ clearInterval(interval);
|
|
|
+ iframeWin.scrollTo(0, scrollHeight);
|
|
|
+ this.extractAndInit('全渲染超时');
|
|
|
+ this.allPagesLoaded = true;
|
|
|
+ }, 30000);
|
|
|
+ },
|
|
|
+ extractAndInit(stage) {
|
|
|
+ var iframe = document.getElementById('Iframe');
|
|
|
+ if (!iframe) return;
|
|
|
+ var iframeDoc = iframe.contentWindow.document;
|
|
|
+ var container = iframeDoc.querySelectorAll('.container');
|
|
|
+ console.log(
|
|
|
+ '[' + (stage || '未知阶段') + '] container NodeList 长度:',
|
|
|
+ container.length
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!container[0]) {
|
|
|
+ console.warn(
|
|
|
+ '[' +
|
|
|
+ (stage || '未知阶段') +
|
|
|
+ '] 未找到 .container 元素。可能原因:\n' +
|
|
|
+ '1. kkFileView 服务未部署或 /kkfile 代理路径不对\n' +
|
|
|
+ '2. URL ' +
|
|
|
+ this.fileUrl +
|
|
|
+ ' 返回的不是 kkFileView 的 HTML'
|
|
|
+ );
|
|
|
+ console.log(
|
|
|
+ 'iframe body innerHTML 前 500 字符:',
|
|
|
+ ((iframeDoc.body && iframeDoc.body.innerHTML) || '').slice(0, 500)
|
|
|
+ );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$refs.sealRef.init(
|
|
|
+ container[0].innerHTML.replace(
|
|
|
+ // 把 kkFileView 输出的绝对/协议相对 URL 改为相对路径
|
|
|
+ // 这样浏览器从父页面 localhost:8083 加载,走 /kkfile 代理到 51001(浏览器感知同源,无 CORS)
|
|
|
+ /src="(?:https?:)?\/\/[^/]+(\/[^"]*)"/g,
|
|
|
+ `src="$1"`
|
|
|
+ ),
|
|
|
+ {
|
|
|
+ droppedImages:
|
|
|
+ (this.restoreData && this.restoreData.droppedImages) || ''
|
|
|
+ }
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
-<style scoped lang="scss"></style>
|
|
|
+<style scoped lang="scss">
|
|
|
+ .seal-wrapper {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ // PDF 未全部加载时,禁用盖章区域所有交互(视觉不变)
|
|
|
+ .seal-wrapper.is-locking {
|
|
|
+ pointer-events: none;
|
|
|
+ user-select: none;
|
|
|
+ }
|
|
|
+ .seal-lock-hint {
|
|
|
+ position: absolute;
|
|
|
+ top: 12px;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ z-index: 10;
|
|
|
+ background: rgba(64, 158, 255, 0.92);
|
|
|
+ color: #fff;
|
|
|
+ padding: 8px 18px;
|
|
|
+ border-radius: 20px;
|
|
|
+ font-size: 13px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ }
|
|
|
+ .seal-lock-spinner {
|
|
|
+ font-size: 14px;
|
|
|
+ animation: seal-spin 1s linear infinite;
|
|
|
+ }
|
|
|
+ @keyframes seal-spin {
|
|
|
+ to {
|
|
|
+ transform: rotate(360deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|