askbot-dragon 1.8.34-beta → 1.8.35-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/js/common.js +30 -0
- package/src/components/preview/pdfView.vue +256 -90
package/package.json
CHANGED
package/src/assets/js/common.js
CHANGED
|
@@ -256,6 +256,36 @@ function newInitWaterMark(elId, textValue) {
|
|
|
256
256
|
})
|
|
257
257
|
document.getElementById(elId).appendChild(oTemp);
|
|
258
258
|
}
|
|
259
|
+
const getAllParams = (href) => {
|
|
260
|
+
let query = href.substring(href.indexOf("?") + 1);
|
|
261
|
+
let vars = query.split("&");
|
|
262
|
+
let obj = {};
|
|
263
|
+
for (let i = 0; i < vars.length; i++) {
|
|
264
|
+
let pair = vars[i].split("=");
|
|
265
|
+
// 将参数名和参数值分别作为对象的属性名和属性值
|
|
266
|
+
obj[pair[0]] = pair[1];
|
|
267
|
+
}
|
|
268
|
+
return obj;
|
|
269
|
+
}
|
|
270
|
+
export const setTimestamp = (url) => {
|
|
271
|
+
if(url.indexOf('?') !== -1) {
|
|
272
|
+
let newUrl = url.split('?')[0];
|
|
273
|
+
let params = getAllParams(url)
|
|
274
|
+
params['timestamp'] = new Date().getTime();
|
|
275
|
+
let count = 0;
|
|
276
|
+
for(let key in params) {
|
|
277
|
+
if(count === 0) {
|
|
278
|
+
newUrl += '?' + key + '=' + params[key];
|
|
279
|
+
} else {
|
|
280
|
+
newUrl += '&' + key + '=' + params[key];
|
|
281
|
+
}
|
|
282
|
+
count++;
|
|
283
|
+
}
|
|
284
|
+
return newUrl;
|
|
285
|
+
} else {
|
|
286
|
+
return url
|
|
287
|
+
}
|
|
288
|
+
}
|
|
259
289
|
export {
|
|
260
290
|
imageTypeObj,
|
|
261
291
|
newInitWaterMark
|
|
@@ -78,7 +78,7 @@ if(pdfjsLib) {
|
|
|
78
78
|
pdfjsLib.GlobalWorkerOptions.workerSrc = window['pdfjs-dist/build/pdf.worker']
|
|
79
79
|
}
|
|
80
80
|
const { TextLayerBuilder } = window['pdfjs-dist/web/pdf_viewer']
|
|
81
|
-
import { newInitWaterMark } from "../../assets/js/common.js";
|
|
81
|
+
import { newInitWaterMark,setTimestamp } from "../../assets/js/common.js";
|
|
82
82
|
import Vue from 'vue';
|
|
83
83
|
export default {
|
|
84
84
|
name: "PdfViewer",
|
|
@@ -88,8 +88,7 @@ export default {
|
|
|
88
88
|
pdf: null,
|
|
89
89
|
numPages: 0,
|
|
90
90
|
scale: 1, // 初始缩小比例
|
|
91
|
-
|
|
92
|
-
pages: [], // { pageNumber: number, loaded: boolean, canvas: ref, loading: boolean }
|
|
91
|
+
pages: [], // { pageNumber: number, loaded: boolean, canvas: ref, loading: boolean, retryCount: number }
|
|
93
92
|
// 静态高亮(坐标采用顶部为原点)
|
|
94
93
|
highlights: [],
|
|
95
94
|
searchQuery: "",
|
|
@@ -164,6 +163,7 @@ export default {
|
|
|
164
163
|
},
|
|
165
164
|
async initPdf() {
|
|
166
165
|
if (!this.pdfFile) return;
|
|
166
|
+
this.pdfFile = setTimestamp(this.pdfFile)
|
|
167
167
|
// this.pdf = await pdfjsLib.getDocument(this.pdfFile).promise;
|
|
168
168
|
this.loadingTask = pdfjsLib.getDocument(this.pdfFile);
|
|
169
169
|
await this.loadingTask.promise.then(async pdf => {
|
|
@@ -178,6 +178,7 @@ export default {
|
|
|
178
178
|
loaded: false,
|
|
179
179
|
canvas: null,
|
|
180
180
|
loading: false,
|
|
181
|
+
retryCount: 0,
|
|
181
182
|
}));
|
|
182
183
|
// 清空搜索高亮
|
|
183
184
|
this.searchHighlights = [];
|
|
@@ -204,7 +205,7 @@ export default {
|
|
|
204
205
|
if (entry.isIntersecting) {
|
|
205
206
|
const index = Number(entry.target.getAttribute('data-index'));
|
|
206
207
|
const page = this.pages[index];
|
|
207
|
-
if (!page.loaded && !page.loading) {
|
|
208
|
+
if (page && !page.loaded && !page.loading) {
|
|
208
209
|
this.renderPage(page.pageNumber);
|
|
209
210
|
}
|
|
210
211
|
this.updateCurrentPage();
|
|
@@ -249,73 +250,189 @@ export default {
|
|
|
249
250
|
await this.updateCurrentPage();
|
|
250
251
|
}
|
|
251
252
|
},
|
|
252
|
-
async renderPage(pageNumber) {
|
|
253
|
-
if (!this.pdf
|
|
253
|
+
async renderPage(pageNumber, retry = false) {
|
|
254
|
+
if (!this.pdf) return;
|
|
254
255
|
const pageIndex = pageNumber - 1;
|
|
255
256
|
const pageData = this.pages[pageIndex];
|
|
256
|
-
if (pageData
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
canvas.height = viewport.height * devicePixelRatio;
|
|
270
|
-
canvas.style.width = `${viewport.width}px`;
|
|
271
|
-
canvas.style.height = `${viewport.height}px`;
|
|
272
|
-
context.scale(devicePixelRatio, devicePixelRatio);
|
|
273
|
-
|
|
274
|
-
this.$set(pageData,'loading',true)
|
|
275
|
-
this.renderInProgress = true;
|
|
276
|
-
const renderTask = page.render({ canvasContext: context, viewport });
|
|
277
|
-
// await renderTask.promise;
|
|
278
|
-
let hasDoc = document.getElementById('textLayer' + pageNumber)
|
|
279
|
-
if (hasDoc){
|
|
280
|
-
hasDoc.parentNode.removeChild(hasDoc);
|
|
281
|
-
// await renderTask.promise;
|
|
282
|
-
// return
|
|
257
|
+
if (!pageData) return;
|
|
258
|
+
|
|
259
|
+
// 如果正在加载且不是重试,避免重复渲染
|
|
260
|
+
if (pageData.loading && !retry) return;
|
|
261
|
+
// 如果已加载且不是重试,直接返回
|
|
262
|
+
if (pageData.loaded && !retry) return;
|
|
263
|
+
|
|
264
|
+
// 重试机制:最多重试 3 次
|
|
265
|
+
const maxRetries = 3;
|
|
266
|
+
if (retry && pageData.retryCount >= maxRetries) {
|
|
267
|
+
console.error(`Max retries reached for page ${pageNumber}`);
|
|
268
|
+
this.$set(pageData, 'loading', false);
|
|
269
|
+
return;
|
|
283
270
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
271
|
+
|
|
272
|
+
this.pageNumber = pageNumber;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const page = await this.pdf.getPage(pageNumber);
|
|
276
|
+
let pdfWidth = page.getViewport({ scale: 1}).width;
|
|
277
|
+
const viewport = page.getViewport({ scale: this.calculateScale(pdfWidth) });
|
|
278
|
+
this.viewport = viewport;
|
|
279
|
+
|
|
280
|
+
const canvas = pageData.canvas;
|
|
281
|
+
if (!canvas) {
|
|
282
|
+
console.warn(`Canvas not found for page ${pageNumber}, will retry...`);
|
|
283
|
+
// 如果 canvas 不存在,增加重试计数并延迟重试
|
|
284
|
+
if (!retry) {
|
|
285
|
+
this.$set(pageData, 'retryCount', (pageData.retryCount || 0) + 1);
|
|
286
|
+
setTimeout(() => {
|
|
287
|
+
this.renderPage(pageNumber, true);
|
|
288
|
+
}, 200);
|
|
289
|
+
}
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const context = canvas.getContext("2d");
|
|
294
|
+
if (!context) {
|
|
295
|
+
console.warn(`Failed to get context for page ${pageNumber}, will retry...`);
|
|
296
|
+
// 如果无法获取 context,增加重试计数并延迟重试
|
|
297
|
+
if (!retry) {
|
|
298
|
+
this.$set(pageData, 'retryCount', (pageData.retryCount || 0) + 1);
|
|
299
|
+
setTimeout(() => {
|
|
300
|
+
this.renderPage(pageNumber, true);
|
|
301
|
+
}, 200);
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
this.context = context;
|
|
307
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
308
|
+
canvas.width = (viewport.width) * devicePixelRatio;
|
|
309
|
+
canvas.height = viewport.height * devicePixelRatio;
|
|
310
|
+
canvas.style.width = `${viewport.width}px`;
|
|
311
|
+
canvas.style.height = `${viewport.height}px`;
|
|
312
|
+
context.scale(devicePixelRatio, devicePixelRatio);
|
|
313
|
+
|
|
314
|
+
// 设置加载状态
|
|
315
|
+
this.$set(pageData, 'loading', true);
|
|
316
|
+
|
|
317
|
+
// 清理旧的文本层
|
|
318
|
+
let hasDoc = document.getElementById('textLayer' + pageNumber);
|
|
319
|
+
if (hasDoc && hasDoc.parentNode) {
|
|
320
|
+
hasDoc.parentNode.removeChild(hasDoc);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 渲染 PDF 页面
|
|
324
|
+
const renderTask = page.render({ canvasContext: context, viewport });
|
|
325
|
+
|
|
326
|
+
// 等待渲染完成后再处理文本层和高亮
|
|
327
|
+
await renderTask.promise.then(async () => {
|
|
328
|
+
// 获取文本内容
|
|
329
|
+
const textContent = await page.getTextContent();
|
|
330
|
+
|
|
331
|
+
// 创建文本层
|
|
332
|
+
const textDiv = document.createElement('div');
|
|
333
|
+
textDiv.setAttribute('class', 'textLayer');
|
|
334
|
+
textDiv.setAttribute('id', 'textLayer' + pageNumber);
|
|
335
|
+
let textLayer = new TextLayerBuilder({
|
|
336
|
+
textLayerDiv: textDiv,
|
|
337
|
+
pageIndex: pageIndex,
|
|
338
|
+
viewport: viewport,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// 设置文本层样式 - 移除高度限制和 overflow hidden,避免文字被裁剪
|
|
342
|
+
textDiv.style.width = `${viewport.width}px`;
|
|
343
|
+
// 不设置固定高度,让内容自然展开,或者设置为足够大的值
|
|
344
|
+
// textDiv.style.height = `${viewport.height}px`; // 移除固定高度
|
|
345
|
+
textDiv.style.minHeight = `${viewport.height}px`; // 使用最小高度
|
|
346
|
+
textDiv.style.overflow = 'visible'; // 改为 visible,避免裁剪文字
|
|
347
|
+
textDiv.style.whiteSpace = 'pre-wrap';
|
|
348
|
+
textDiv.style.position = 'absolute';
|
|
349
|
+
textDiv.style.top = '0';
|
|
350
|
+
textDiv.style.left = '0';
|
|
351
|
+
textDiv.style.fontSize = '20px';
|
|
352
|
+
textDiv.style.color = 'black';
|
|
353
|
+
textDiv.style.pointerEvents = 'none'; // 确保文本层不阻挡交互
|
|
354
|
+
|
|
355
|
+
// 将文本 div 先添加到覆盖层中(TextLayerBuilder 需要 DOM 元素存在)
|
|
356
|
+
let pagesDiv = document.getElementById('canvas-wrapper' + pageIndex);
|
|
357
|
+
if (!pagesDiv) {
|
|
358
|
+
console.warn(`Canvas wrapper not found for page ${pageNumber}`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
pagesDiv.appendChild(textDiv);
|
|
362
|
+
|
|
363
|
+
// 设置文本内容并渲染
|
|
364
|
+
textLayer.setTextContent(textContent);
|
|
365
|
+
textLayer.render();
|
|
366
|
+
|
|
367
|
+
// 等待文本层渲染完成(使用 nextTick 和 setTimeout 确保 DOM 完全更新)
|
|
368
|
+
await this.$nextTick();
|
|
369
|
+
// 额外等待一小段时间,确保 TextLayerBuilder 完成渲染
|
|
370
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
371
|
+
|
|
372
|
+
// 确保容器有足够的高度来显示所有文本
|
|
373
|
+
// 获取文本层的实际高度(包括所有子元素)
|
|
374
|
+
const textLayerHeight = Math.max(
|
|
375
|
+
textDiv.scrollHeight,
|
|
376
|
+
textDiv.offsetHeight,
|
|
377
|
+
viewport.height
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
// 如果文本层实际高度超过 viewport,调整容器和 canvas 的高度
|
|
381
|
+
if (textLayerHeight > viewport.height) {
|
|
382
|
+
// 调整 canvas wrapper 的最小高度
|
|
383
|
+
if (pagesDiv) {
|
|
384
|
+
pagesDiv.style.minHeight = `${textLayerHeight}px`;
|
|
385
|
+
}
|
|
386
|
+
// 调整 canvas 的显示高度(如果需要)
|
|
387
|
+
const canvas = pageData.canvas;
|
|
388
|
+
if (canvas && canvas.parentElement) {
|
|
389
|
+
canvas.parentElement.style.minHeight = `${textLayerHeight}px`;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// 在文本层渲染完成后,再渲染高亮区域
|
|
394
|
+
// 注意:高亮是在 canvas 上绘制的,不会遮挡文本层(文本层在 canvas 上方)
|
|
395
|
+
// 渲染已有高亮区域(静态highlights)
|
|
396
|
+
this.renderHighlights(context, pageNumber, viewport);
|
|
397
|
+
// 渲染搜索高亮区域
|
|
398
|
+
this.renderSearchHighlights(context, pageNumber, viewport);
|
|
399
|
+
|
|
400
|
+
// 重置重试计数
|
|
401
|
+
this.$set(pageData, 'retryCount', 0);
|
|
402
|
+
// 更新页面状态
|
|
403
|
+
this.$set(pageData, 'loading', false);
|
|
404
|
+
this.$set(pageData, 'loaded', true);
|
|
405
|
+
}).catch((error) => {
|
|
406
|
+
console.error(`Error rendering page ${pageNumber}:`, error);
|
|
407
|
+
// 如果渲染失败,尝试重试
|
|
408
|
+
if (!retry && (pageData.retryCount || 0) < maxRetries) {
|
|
409
|
+
this.$set(pageData, 'retryCount', (pageData.retryCount || 0) + 1);
|
|
410
|
+
this.$set(pageData, 'loading', false);
|
|
411
|
+
// 延迟后重试
|
|
412
|
+
setTimeout(() => {
|
|
413
|
+
this.renderPage(pageNumber, true);
|
|
414
|
+
}, 500);
|
|
415
|
+
} else {
|
|
416
|
+
// 确保在错误时也更新状态
|
|
417
|
+
this.$set(pageData, 'loading', false);
|
|
418
|
+
this.$set(pageData, 'loaded', false);
|
|
419
|
+
}
|
|
294
420
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
})
|
|
311
|
-
this.renderInProgress = false;
|
|
312
|
-
this.$set(pageData,'loading',false)
|
|
313
|
-
this.$set(pageData,'loaded',true)
|
|
314
|
-
|
|
315
|
-
// 渲染已有高亮区域(静态highlights)
|
|
316
|
-
this.renderHighlights(context, pageNumber, viewport);
|
|
317
|
-
// 渲染搜索高亮区域
|
|
318
|
-
this.renderSearchHighlights(context, pageNumber, viewport);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
console.error(`Error loading page ${pageNumber}:`, error);
|
|
423
|
+
// 如果加载失败,尝试重试
|
|
424
|
+
if (!retry && (pageData.retryCount || 0) < maxRetries) {
|
|
425
|
+
this.$set(pageData, 'retryCount', (pageData.retryCount || 0) + 1);
|
|
426
|
+
this.$set(pageData, 'loading', false);
|
|
427
|
+
// 延迟后重试
|
|
428
|
+
setTimeout(() => {
|
|
429
|
+
this.renderPage(pageNumber, true);
|
|
430
|
+
}, 500);
|
|
431
|
+
} else {
|
|
432
|
+
this.$set(pageData, 'loading', false);
|
|
433
|
+
this.$set(pageData, 'loaded', false);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
319
436
|
},
|
|
320
437
|
calculateScale(pdfWidth) {
|
|
321
438
|
const containerWidth = document.getElementById('pdfViewPage').clientWidth - 50;
|
|
@@ -347,6 +464,8 @@ export default {
|
|
|
347
464
|
});
|
|
348
465
|
},
|
|
349
466
|
drawHighlight(context, viewport, position, fillStyle, fromSearch = false) {
|
|
467
|
+
if (!context || !position || position.length < 4) return;
|
|
468
|
+
|
|
350
469
|
const [x1, y1, x2, y2] = position;
|
|
351
470
|
const scale = viewport.scale;
|
|
352
471
|
const pageHeight = viewport.height / viewport.scale;
|
|
@@ -364,16 +483,32 @@ export default {
|
|
|
364
483
|
canvasY1 = y1 * scale;
|
|
365
484
|
canvasY2 = y2 * scale;
|
|
366
485
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
486
|
+
|
|
487
|
+
// 确保坐标在有效范围内
|
|
488
|
+
const minX = Math.min(canvasX1, canvasX2);
|
|
489
|
+
const minY = Math.min(canvasY1, canvasY2);
|
|
490
|
+
const width = Math.abs(canvasX2 - canvasX1);
|
|
491
|
+
const height = Math.abs(canvasY2 - canvasY1);
|
|
492
|
+
|
|
493
|
+
// 检查坐标是否在 canvas 范围内
|
|
494
|
+
if (minX < 0 || minY < 0 || minX + width > viewport.width || minY + height > viewport.height) {
|
|
495
|
+
// 如果超出范围,进行裁剪
|
|
496
|
+
const clippedX = Math.max(0, minX);
|
|
497
|
+
const clippedY = Math.max(0, minY);
|
|
498
|
+
const clippedWidth = Math.min(width, viewport.width - clippedX);
|
|
499
|
+
const clippedHeight = Math.min(height, viewport.height - clippedY);
|
|
500
|
+
|
|
501
|
+
if (clippedWidth > 0 && clippedHeight > 0) {
|
|
502
|
+
context.beginPath();
|
|
503
|
+
context.fillStyle = fillStyle;
|
|
504
|
+
context.fillRect(clippedX, clippedY, clippedWidth, clippedHeight);
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
// 正常绘制
|
|
508
|
+
context.beginPath();
|
|
509
|
+
context.fillStyle = fillStyle;
|
|
510
|
+
context.fillRect(minX, minY, width, height);
|
|
511
|
+
}
|
|
377
512
|
},
|
|
378
513
|
handleFileUpload(event) {
|
|
379
514
|
const file = event.target.files[0];
|
|
@@ -384,10 +519,26 @@ export default {
|
|
|
384
519
|
}
|
|
385
520
|
},
|
|
386
521
|
async setCanvasRef() {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
522
|
+
// 使用 $nextTick 确保 DOM 已更新
|
|
523
|
+
await this.$nextTick();
|
|
524
|
+
|
|
525
|
+
// 如果 refs 还没有准备好,等待一段时间后重试
|
|
526
|
+
if (!this.$refs.canvases || this.$refs.canvases.length === 0) {
|
|
527
|
+
return new Promise((resolve) => {
|
|
528
|
+
setTimeout(async () => {
|
|
529
|
+
await this.setCanvasRef();
|
|
530
|
+
resolve();
|
|
531
|
+
}, 100);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// 设置 canvas 引用
|
|
536
|
+
this.pages.forEach((page, index) => {
|
|
537
|
+
if (this.$refs.canvases && this.$refs.canvases[index]) {
|
|
538
|
+
this.$set(this.pages[index], 'canvas', this.$refs.canvases[index]);
|
|
539
|
+
} else {
|
|
540
|
+
console.warn(`Canvas ref not found for page ${index + 1}`);
|
|
541
|
+
}
|
|
391
542
|
});
|
|
392
543
|
},
|
|
393
544
|
clearPages() {
|
|
@@ -469,7 +620,9 @@ export default {
|
|
|
469
620
|
},
|
|
470
621
|
zoomIn() {
|
|
471
622
|
this.updateCurrentPage();
|
|
472
|
-
|
|
623
|
+
// 检查是否有页面正在加载
|
|
624
|
+
const hasLoadingPage = this.pages.some(p => p.loading);
|
|
625
|
+
if (hasLoadingPage) return;
|
|
473
626
|
const container = this.$refs.pdfContainer;
|
|
474
627
|
const currentScroll = container.scrollTop;
|
|
475
628
|
this.scale += 0.1;
|
|
@@ -477,7 +630,9 @@ export default {
|
|
|
477
630
|
},
|
|
478
631
|
zoomOut() {
|
|
479
632
|
this.updateCurrentPage();
|
|
480
|
-
|
|
633
|
+
// 检查是否有页面正在加载
|
|
634
|
+
const hasLoadingPage = this.pages.some(p => p.loading);
|
|
635
|
+
if (hasLoadingPage) return;
|
|
481
636
|
const container = this.$refs.pdfContainer;
|
|
482
637
|
const currentScroll = container.scrollTop;
|
|
483
638
|
this.scale = Math.max(this.scale - 0.1, 0.1);
|
|
@@ -487,10 +642,11 @@ export default {
|
|
|
487
642
|
const pages = Vue.observable(this.pages)
|
|
488
643
|
pages.forEach((p) => {
|
|
489
644
|
p.loaded = false;
|
|
490
|
-
this.$set(p,'loading',false)
|
|
645
|
+
this.$set(p, 'loading', false);
|
|
646
|
+
this.$set(p, 'retryCount', 0);
|
|
491
647
|
if (p.canvas) {
|
|
492
648
|
const ctx = p.canvas.getContext('2d');
|
|
493
|
-
ctx.clearRect(0,0,p.canvas.width,p.canvas.height);
|
|
649
|
+
ctx.clearRect(0, 0, p.canvas.width, p.canvas.height);
|
|
494
650
|
}
|
|
495
651
|
});
|
|
496
652
|
|
|
@@ -522,7 +678,9 @@ export default {
|
|
|
522
678
|
},
|
|
523
679
|
async doSearch() {
|
|
524
680
|
if (!this.pdf || !this.searchQuery) return;
|
|
525
|
-
|
|
681
|
+
// 检查是否有页面正在加载
|
|
682
|
+
const hasLoadingPage = this.pages.some(p => p.loading);
|
|
683
|
+
if (hasLoadingPage) return;
|
|
526
684
|
|
|
527
685
|
this.searchHighlights = [];
|
|
528
686
|
const numPages = this.numPages;
|
|
@@ -585,7 +743,8 @@ export default {
|
|
|
585
743
|
const currentScroll = container.scrollTop;
|
|
586
744
|
this.pages.forEach((p) => {
|
|
587
745
|
p.loaded = false;
|
|
588
|
-
this.$set(p,'loading',false)
|
|
746
|
+
this.$set(p, 'loading', false);
|
|
747
|
+
this.$set(p, 'retryCount', 0);
|
|
589
748
|
if (p.canvas) {
|
|
590
749
|
const ctx = p.canvas.getContext("2d");
|
|
591
750
|
ctx.clearRect(0, 0, p.canvas.width, p.canvas.height);
|
|
@@ -615,16 +774,19 @@ export default {
|
|
|
615
774
|
onResize() {
|
|
616
775
|
clearTimeout(this.resizeTimeout);
|
|
617
776
|
this.resizeTimeout = setTimeout(() => {
|
|
618
|
-
|
|
777
|
+
// 检查是否有页面正在加载
|
|
778
|
+
const hasLoadingPage = this.pages.some(p => p.loading);
|
|
779
|
+
if (hasLoadingPage) return;
|
|
619
780
|
const container = this.$refs.pdfContainer;
|
|
620
781
|
const currentScroll = container.scrollTop;
|
|
621
782
|
const pages = Vue.observable(this.pages)
|
|
622
783
|
pages.forEach((p) => {
|
|
623
784
|
p.loaded = false;
|
|
624
|
-
this.$set(p,'loading',false)
|
|
785
|
+
this.$set(p, 'loading', false);
|
|
786
|
+
this.$set(p, 'retryCount', 0);
|
|
625
787
|
if (p.canvas) {
|
|
626
788
|
const ctx = p.canvas.getContext('2d');
|
|
627
|
-
ctx.clearRect(0,0,p.canvas.width,p.canvas.height);
|
|
789
|
+
ctx.clearRect(0, 0, p.canvas.width, p.canvas.height);
|
|
628
790
|
}
|
|
629
791
|
});
|
|
630
792
|
this.$nextTick(() => {
|
|
@@ -712,11 +874,15 @@ export default {
|
|
|
712
874
|
display: flex;
|
|
713
875
|
justify-content: center;
|
|
714
876
|
width: 100%;
|
|
877
|
+
min-height: fit-content; /* 确保容器能容纳所有内容 */
|
|
878
|
+
overflow: visible; /* 允许内容超出,避免裁剪 */
|
|
715
879
|
}
|
|
716
880
|
|
|
717
881
|
.canvas-wrapper {
|
|
718
882
|
position: relative;
|
|
719
883
|
width: 100%;
|
|
884
|
+
min-height: 100%; /* 确保容器有足够高度 */
|
|
885
|
+
overflow: visible; /* 允许内容超出,避免裁剪 */
|
|
720
886
|
}
|
|
721
887
|
|
|
722
888
|
/* 在loading时覆盖canvas显示加载动画 */
|