askbot-dragon 1.3.85 → 1.3.87

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.
Files changed (85) hide show
  1. package/README.md +27 -27
  2. package/babel.config.js +6 -6
  3. package/dragon.iml +7 -7
  4. package/package.json +58 -58
  5. package/public/index.html +59 -59
  6. package/src/App.vue +31 -31
  7. package/src/api/index.js +1 -1
  8. package/src/api/mock.http +2 -2
  9. package/src/api/requestUrl.js +185 -185
  10. package/src/assets/js/AliyunlssUtil.js +92 -92
  11. package/src/assets/js/Base64Util.js +22 -22
  12. package/src/assets/js/common.js +11 -11
  13. package/src/assets/js/hammer.js +71 -71
  14. package/src/assets/js/script.js +36 -36
  15. package/src/assets/less/common.css +6773 -6773
  16. package/src/assets/less/converSationContainer/common.less +191 -191
  17. package/src/assets/less/converSationContainer/converSatonContainer.less +493 -493
  18. package/src/assets/less/iconfont.css +37 -37
  19. package/src/assets/less/ticketMessage.less +211 -211
  20. package/src/components/ActionAlertIframe.vue +112 -112
  21. package/src/components/AiGuide.vue +467 -467
  22. package/src/components/AnswerDocknowledge.vue +428 -428
  23. package/src/components/AnswerVoice.vue +280 -280
  24. package/src/components/AskIFrame.vue +15 -15
  25. package/src/components/ConversationContainer.vue +4106 -4106
  26. package/src/components/FileType.vue +86 -86
  27. package/src/components/Message.vue +27 -27
  28. package/src/components/actionSatisfaction.vue +107 -107
  29. package/src/components/actionSendToBot.vue +62 -62
  30. package/src/components/answerDissatisfaction.vue +62 -62
  31. package/src/components/answerRadio.vue +76 -76
  32. package/src/components/ask-components/DissatisfactionOptions.vue +57 -57
  33. package/src/components/ask-components/Msgloading.vue +37 -37
  34. package/src/components/ask-components/SatisfactionV2.vue +15 -15
  35. package/src/components/askVideo.vue +138 -138
  36. package/src/components/assetDetails.vue +370 -370
  37. package/src/components/assetMessage.vue +228 -228
  38. package/src/components/associationIntention.vue +331 -331
  39. package/src/components/attachmentPreview.vue +90 -90
  40. package/src/components/botActionSatisfactor.vue +68 -68
  41. package/src/components/chatContent.vue +513 -513
  42. package/src/components/feedBack.vue +136 -136
  43. package/src/components/fielListView.vue +349 -349
  44. package/src/components/file/AliyunOssComponents.vue +108 -108
  45. package/src/components/formTemplate.vue +3362 -3363
  46. package/src/components/loadingProcess.vue +164 -164
  47. package/src/components/message/ActionAlertIframe.vue +112 -112
  48. package/src/components/message/ShopMessage.vue +164 -164
  49. package/src/components/message/TextMessage.vue +924 -924
  50. package/src/components/message/TicketMessage.vue +177 -177
  51. package/src/components/message/swiper/index.js +4 -4
  52. package/src/components/message/swiper/ticketSwiper.vue +503 -503
  53. package/src/components/message/swiper/ticketSwiperItem.vue +61 -61
  54. package/src/components/msgLoading.vue +231 -231
  55. package/src/components/myPopup.vue +70 -70
  56. package/src/components/pdfPosition.vue +783 -783
  57. package/src/components/popup.vue +227 -227
  58. package/src/components/previewDoc.vue +228 -228
  59. package/src/components/previewPdf.vue +260 -260
  60. package/src/components/receiverMessagePlatform.vue +65 -65
  61. package/src/components/recommend.vue +89 -89
  62. package/src/components/selector/hOption.vue +20 -20
  63. package/src/components/selector/hSelector.vue +199 -199
  64. package/src/components/selector/hWrapper.vue +216 -216
  65. package/src/components/senderMessagePlatform.vue +50 -50
  66. package/src/components/source/BotMessage.vue +24 -24
  67. package/src/components/source/CustomMessage.vue +24 -24
  68. package/src/components/test.vue +260 -260
  69. package/src/components/tree.vue +294 -294
  70. package/src/components/utils/AliyunIssUtil.js +72 -72
  71. package/src/components/utils/ckeditor.js +155 -155
  72. package/src/components/utils/ckeditorImageUpload/command.js +109 -109
  73. package/src/components/utils/ckeditorImageUpload/editing.js +11 -11
  74. package/src/components/utils/ckeditorImageUpload/plugin-image.js +11 -11
  75. package/src/components/utils/ckeditorImageUpload/toolbar-ui.js +40 -40
  76. package/src/components/utils/ckeditorfileUpload/common.js +133 -111
  77. package/src/components/utils/ckeditorfileUpload/editing.js +11 -11
  78. package/src/components/utils/ckeditorfileUpload/plugin_file.js +11 -11
  79. package/src/components/utils/ckeditorfileUpload/toolbar_ui.js +34 -34
  80. package/src/components/utils/format_date.js +25 -25
  81. package/src/components/utils/index.js +6 -6
  82. package/src/components/utils/math_utils.js +29 -29
  83. package/src/components/voiceComponent.vue +119 -119
  84. package/src/main.js +60 -60
  85. package/vue.config.js +55 -55
@@ -1,784 +1,784 @@
1
- <template>
2
- <div class="pdf_view" ref="pdfView" @scroll="pdfScroll">
3
- <div class="btn_footer" v-if="tagIds.length > 1">
4
- <div class="prev" @click="prev">上一段</div>
5
- <div class="next" @click="next">下一段</div>
6
- </div>
7
- </div>
8
- </template>
9
-
10
- <script>
11
- import _ from 'lodash'
12
- // import * as pdfjsLib from 'pdfjs-dist'
13
- // pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker';
14
- // import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
15
- // EventBus pdf_viewer 支持绑定自定义事件,一版不做
16
- // import 'pdfjs-dist/web/pdf_viewer.css'
17
- /* eslint-disable */
18
- const pdfjsLib = window['pdfjsLib']
19
- if(pdfjsLib) {
20
- pdfjsLib.GlobalWorkerOptions.workerSrc = window['pdfjs-dist/build/pdf.worker']
21
- // 'pdfjs-dist/build/pdf.worker';
22
- }
23
- const { TextLayerBuilder } = window['pdfjs-dist/web/pdf_viewer']
24
- // import { zoomElement } from '../assets/js/hammer'
25
- export default {
26
- name: 'pdfView',
27
- props:['tagIds'],
28
- data() {
29
- return {
30
- url: '',
31
- // pdfjsLib: window['pdfjs-dist/build/pdf'],
32
- // pdfjsLib: pdfjsLib,
33
- pages: [],
34
- pageLoadStatus: {
35
- WAIT: 0,
36
- LOADED: 1,
37
- },
38
- scale: 1,
39
- rotation: 0,
40
- pageSize: {},
41
- PAGE_INTVERVAL: 15,
42
- SLICE_COUNT: 5,
43
- contentView: null,
44
- fisrtLoad: true,
45
- TextLayerBuilder: null,
46
- totalPageCount: 0,
47
- identifyTextPostion: {
48
- top: 0,
49
- left: 0,
50
- width: 100,
51
- height: 0,
52
- page: 1,
53
- pageHeight: 0,
54
- pageWidth: 0,
55
- extractInfo: {},
56
- currentPageAllLine: []
57
- },
58
- currentPageAllLine: [],
59
- pdfUrl: '',
60
- cachePdf: [],
61
- newViewer: null,
62
- currentPage: 0,
63
- changetoolbar: false,
64
- allTr:[],
65
- preViewType: 'pdf',
66
- displacement:{
67
- pageX:0,
68
- pageY:0,
69
- moveable:false,
70
- pageX2:0,
71
- pageY2:0,
72
- originScale:1,
73
- },
74
- isTouchMoved: false
75
- }
76
- },
77
- methods: {
78
- getpdfResloutePage (pdfResloute) {
79
- // 根据当前页面宽度设置缩放比例
80
- // this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
81
- // console.log(this.scale,'this.scale');
82
- this.scale = 1
83
- // 从后端获取到当前分片后所有的pdf页码,初始化数组,数组下{} 对应每页pdf文件
84
- this.pdfUrl = pdfResloute.publicPageFileUrl.substring(0, pdfResloute.publicPageFileUrl.lastIndexOf('/') + 1)
85
- this.initPages(pdfResloute.total)
86
- // 定位功能,加载对应页码位置
87
- this.loadPdfData(pdfResloute.page)
88
- },
89
- async loadPdfData (loadPage) {
90
- if(this.pages[loadPage - 1] && this.pages[loadPage - 1].dom && this.pages[loadPage - 1].dom.children.length > 0) {
91
- return
92
- }
93
- // pdfjsLib.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/legacy/build/pdf.worker.entry.js");
94
- // 拿到第一个分片
95
- const { startPage, url } = await this.fetchPdfFragment(loadPage);
96
- let loadingTask = pdfjsLib.getDocument(url)
97
- loadingTask.promise.then((pdfDoc) => {
98
- // 将已经下载的分片保存到 pages 数组中
99
- for (let i = 0; i < pdfDoc.numPages; i += 1) {
100
- const pageIndex = startPage + i;
101
- const page = this.pages[pageIndex - 1];
102
- // 不在缓存列表内,重新获取本页pdf
103
- if (page.loadStatus !== this.pageLoadStatus.LOADED) {
104
- pdfDoc.getPage(i + 1).then((pdfPage) => {
105
- page.pdfPage = pdfPage;
106
- page.loadStatus = this.pageLoadStatus.LOADED;
107
- // 通知可以进行渲染了
108
- this.startRenderPages(pdfPage, page, pageIndex)
109
- });
110
- } else {
111
- if (this.changetoolbar) {
112
- this.$nextTick(() => {
113
- this.renderHighlights()
114
- })
115
- this.changetoolbar = false
116
- }
117
- }
118
- }
119
- });
120
- },
121
- initPages (totalPage) {
122
- // const pages = [];
123
- this.totalPageCount = totalPage
124
- for (let i = 0; i < totalPage; i += 1) {
125
- this.pages.push({
126
- pageNo: i + 1,
127
- loadStatus: this.pageLoadStatus.WAIT,
128
- pdfPage: null,
129
- dom: null
130
- });
131
- }
132
- },
133
- async fetchPdfFragment (pageIndex) {
134
- // 置换加签后的文件地址。
135
- let obj = {}
136
- await this.$http.post(
137
- '/knowledge-api/temporary-certificate/or-origin?expired=30',
138
- this.pdfUrl + pageIndex + '.pdf',
139
- {
140
- headers: {
141
- "Content-Type": "application/json",
142
- },
143
- }).then(async res => {
144
- if(res.bodyText) {
145
- // 最后返回一个 包含这4个参数的对象
146
- obj = await {
147
- "startPage": pageIndex, // 分片的开始页码
148
- "endPage": pageIndex + 5, // 分片结束页码
149
- "totalPage": this.totalPageCount, // pdf 总页数
150
- "url": res.bodyText // 分片内容下载地址
151
- }
152
- }
153
- if (res.data) {
154
- // 最后返回一个 包含这4个参数的对象
155
- obj = await {
156
- "startPage": pageIndex, // 分片的开始页码
157
- "endPage": pageIndex + 5, // 分片结束页码
158
- "totalPage": this.totalPageCount, // pdf 总页数
159
- "url": res.data // 分片内容下载地址
160
- }
161
- }
162
- })
163
- return obj
164
- },
165
- startRenderPages (pdfPage, page, pageIndex) {
166
- const viewport = pdfPage.getViewport({
167
- scale: this.scale, // 缩放的比例
168
- rotation: this.rotation, // 旋转的角度
169
- });
170
- // 记录pdf页面高度
171
- const pageSize = {
172
- width: viewport.width,
173
- height: viewport.height,
174
- }
175
- this.pageSize = pageSize
176
- // 创建内容绘制区,并设置大小
177
- this.contentView.style.width = `${pageSize.width}px`;
178
- this.contentView.style.height = `${(this.totalPageCount * (pageSize.height + this.PAGE_INTVERVAL)) * (this.$refs.pdfView.clientWidth / pageSize.width) + this.PAGE_INTVERVAL}px`;
179
- this.contentView.style.margin = '0 auto 0'
180
- this.contentView.style.position = 'relative'
181
- // contentView.style.overflowY = 'auto'
182
- this.$refs.pdfView.appendChild(this.contentView);
183
- this.renderPages(pageIndex)
184
- },
185
- renderPageContent (page, pageIndex) {
186
- const { pdfPage, pageNo, dom } = page;
187
- // dom 元素已存在,无须重新渲染,直接返回
188
- console.log(dom, 'dom');
189
- if (dom && dom.children.length != 0) {
190
- return;
191
- }
192
- const viewport = pdfPage.getViewport({
193
- scale: this.scale,
194
- rotation: this.rotation,
195
- });
196
- // 创建新的canvas
197
- const canvas = document.createElement('canvas');
198
- const context = canvas.getContext('2d');
199
- // canvas.getContext('2d');
200
- canvas.height = this.pageSize.height;
201
- canvas.width = this.pageSize.width;
202
- // 创建渲染的dom
203
- const pageDom = document.createElement('div');
204
- pageDom.style.position = 'absolute';
205
- pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
206
- pageDom.style.width = `${this.pageSize.width}px`;
207
- pageDom.style.height = `${this.pageSize.height}px`;
208
- pageDom.appendChild(canvas);
209
- // 渲染内容
210
- let renderContext = {
211
- canvasContext: context,
212
- viewport: viewport,
213
- }
214
- pdfPage.render(renderContext).promise.then(() => {
215
- console.log(pdfPage.getTextContent(), 'getTextContent');
216
- return pdfPage.getTextContent()
217
- }).then((textContent) => {
218
- const textLayerDiv = document.createElement('div');
219
- textLayerDiv.setAttribute('class', 'textLayer');
220
- // 将文本图层div添加至每页pdf的div中
221
- // 创建新的TextLayerBuilder实例
222
- let textLayer = new TextLayerBuilder({
223
- textLayerDiv: textLayerDiv,
224
- pageIndex: pdfPage._pageIndex,
225
- viewport: viewport,
226
- });
227
- let findPage = this.currentPageAllLine.find(l => { return l.page == pageIndex })
228
- if (findPage) {
229
- let AllLines = findPage.allLines
230
- // setTimeout(() => {
231
- if (AllLines.length > 0) {
232
- for (let j = 0; j < AllLines.length; j++) {
233
- let lines = AllLines[j].lines
234
- let rectdom = document.createElement('div')
235
- rectdom.setAttribute('react-count', AllLines[j].pageCount);
236
- rectdom.style.position = 'absolute';
237
- rectdom.style.top = 0
238
- rectdom.style.left = 0
239
- rectdom.classList.add('rectdom')
240
- for (let index = 0; index < lines.length; index++) {
241
- if (!/^\s+$/g.test(lines[index].content)) {
242
- let postionArr = lines[index].location
243
- let div = document.createElement('div')
244
- div.style.position = 'absolute';
245
- div.style.left = postionArr[0] * this.scale + 'px',
246
- // 后端返回的坐标有基线对齐的问题,top 值是后端算好(基线top - 文字高度),在此加上文字高度的 1/9 (大致比例)为实际展示出文字的top值
247
- div.style.top = (postionArr[1] + postionArr[3] / 9) * this.scale + 'px'
248
- div.style.height = postionArr[3] * this.scale + 'px';
249
- div.style.width = postionArr[2] * this.scale + 'px'
250
- div.style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
251
- div.classList.add('lineHeight')
252
- rectdom.appendChild(div)
253
- }
254
- }
255
- if (rectdom.children.length > 0) {
256
- pageDom.appendChild(rectdom)
257
- }
258
- }
259
- }
260
- }
261
- textLayer.setTextContent(textContent);
262
- textLayer.render()
263
- pageDom.appendChild(textLayer.textLayerDiv);
264
- page.dom = pageDom;
265
- this.contentView.appendChild(pageDom);
266
- this.contentView.style.transform = `scale(${this.$refs.pdfView.clientWidth / this.pageSize.width}, ${this.$refs.pdfView.clientWidth / this.pageSize.width})`
267
-
268
- if (this.changetoolbar) {
269
- setTimeout(() => {
270
- this.renderHighlights()
271
- this.changetoolbar = false
272
- }, 100)
273
- }
274
- if (this.fisrtLoad) {
275
- setTimeout(() => {
276
- if (this.$refs.pdfView.clientHeight - (this.pageSize.height + this.PAGE_INTVERVAL) > (this.pageSize.height + this.PAGE_INTVERVAL)) {
277
- let loadNum = Math.ceil(this.$refs.pdfView.clientHeight / (this.pageSize.height + this.PAGE_INTVERVAL))
278
- for (let n = 0; n < loadNum; n++) {
279
- this.loadPdfData(pageNo + n)
280
- }
281
- } else {
282
- this.renderHighlights()
283
- }
284
- if (this.$refs.pdfView.scrollTop == Math.floor((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))) {
285
- this.fisrtLoad = false
286
- } else {
287
- this.$refs.pdfView.scrollTop = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))}`
288
- }
289
- // zoomElement(this.contentView)
290
- }, 100)
291
- }
292
- })
293
- },
294
- // 监听容器的滚动事件,触发 scrollPdf 方法
295
- // 这里加了防抖保证不会一次产生过多请求
296
- debounceScrollPdf: _.debounce(function (e, that) {
297
- if (this.fisrtLoad) {
298
- this.fisrtLoad = false
299
- return
300
- }
301
- const scrollTop = e.target.scrollTop;
302
- const height = e.target.clientHeight;
303
- // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
304
- const pageIndex = scrollTop > 0 ?
305
- Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
306
- 1;
307
-
308
- pageIndex - 1 != 0 && that.loadPdfData(pageIndex - 1)
309
- that.loadPdfData(pageIndex)
310
- pageIndex + 1 <= that.totalPageCount && that.loadPdfData(pageIndex + 1)
311
- }, 200),
312
- directScrolling (e, that) {
313
- if (this.fisrtLoad) {
314
- this.fisrtLoad = false
315
- return
316
- }
317
- const scrollTop = e.target.scrollTop;
318
- const height = e.target.clientHeight;
319
- // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
320
- const pageIndex = scrollTop > 0 ?
321
- Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
322
- 1;
323
- this.loadPdfData(pageIndex)
324
- },
325
- pdfScroll (e) {
326
- if(this.preViewType !== 'pdf' || this.isTouchMoved) {
327
- return
328
- }
329
- this.debounceScrollPdf(e, this)
330
- },
331
- // 分片每次只做一次处理,所以不考虑多片情况
332
- loadBefore (pageIndex) {
333
- this.loadPdfData(pageIndex)
334
- // const start = (Math.floor(pageIndex / this.SLICE_COUNT) * this.SLICE_COUNT) - (this.SLICE_COUNT - 1);
335
- // if (start > 0) {
336
- // // const prevPage = this.pages[start - 1] || {};
337
- // this.loadPdfData(start)
338
- // // prevPage.loadStatus === this.pageLoadStatus.WAIT && this.loadPdfData(start);
339
- // }
340
- },
341
- loadAfter (pageIndex) {
342
- this.loadPdfData(pageIndex)
343
- // const start = (Math.floor(pageIndex / this.SLICE_COUNT) * this.SLICE_COUNT) + 1;
344
- // if (start <= this.pages.length) {
345
- // // const nextPage = this.pages[start - 1] || {};
346
- // this.loadPdfData(start)
347
- // // nextPage.loadStatus === this.pageLoadStatus.WAIT && this.loadPdfData(start);
348
- // }
349
- },
350
- // 首先我们获取到需要渲染的范围
351
- // 根据当前的可视范围内的页码,我们前后只保留 8 页
352
- getRenderScope (pageIndex) {
353
- const pagesToRender = [];
354
- let i = pageIndex - 1;
355
- let j = pageIndex + 1;
356
- // pageIndex - 1 表示当前页码数 对应的下标位置
357
- pagesToRender.push(this.pages[pageIndex - 1]);
358
- while (pagesToRender.length < 10 && pagesToRender.length < this.pages.length) {
359
- if (i > 0) {
360
- pagesToRender.push(this.pages[i - 1]);
361
- i -= 1;
362
- }
363
- if (pagesToRender.length >= 10) {
364
- break;
365
- }
366
- if (j <= this.pages.length) {
367
- pagesToRender.push(this.pages[j - 1]);
368
- j += 1;
369
- }
370
- }
371
- return pagesToRender;
372
- },
373
- // 渲染需要展示的页面,不需展示的页码将其清除
374
- renderPages (pageIndex) {
375
- const pagesToRender = this.getRenderScope(pageIndex);
376
- for (const i of this.pages) {
377
- if (pagesToRender.includes(i)) {
378
- i.loadStatus === this.pageLoadStatus.LOADED ?
379
- this.renderPageContent(i, pageIndex) :
380
- this.renderPageLoading(i);
381
- } else {
382
- this.clearPage(i);
383
- }
384
- }
385
- },
386
- // 清除页面 dom
387
- clearPage (page) {
388
- if (page.dom) {
389
- this.contentView.removeChild(page.dom);
390
- page.loadStatus = 0
391
- page.dom = undefined;
392
- }
393
- },
394
- // 页面正在下载时渲染loading视图
395
- renderPageLoading (page) {
396
- const { pageNo, dom } = page;
397
- if (dom && dom.children.length != 0) {
398
- return;
399
- }
400
- const pageDom = document.createElement('div');
401
- pageDom.style.width = `${this.pageSize.width}px`;
402
- pageDom.style.height = `${this.pageSize.height}px`;
403
- pageDom.style.position = 'absolute';
404
- pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL
405
- }px`;
406
- pageDom.style.backgroundImage = `url('https://guoranopen-zjk.oss-cn-zhangjiakou.aliyuncs.com/cdn-common/images/loading.gif')`
407
- pageDom.style.backgroundPosition = 'center'
408
- pageDom.style.backgroundRepeat = 'no-repeat'
409
- pageDom.style.backgroundColor = '#FFF'
410
- page.dom = pageDom;
411
- this.contentView.appendChild(pageDom);
412
- },
413
- prev () {
414
- this.currentPage--
415
- if (this.currentPage < 0) {
416
- // this.currentPage = this.tagIds.length - 1
417
- this.currentPage = 0
418
- }
419
- if(this.preViewType == 'pdf') {
420
- this.scrollToUplaodePage(this.currentPage)
421
- } else {
422
- this.scrollToExcalTop(this.currentPage)
423
- }
424
- // this.getpdfResloutePage(this.cachePdf[this.currentPage - 1])
425
- },
426
- next () {
427
- this.currentPage++
428
- if (this.currentPage >= this.tagIds.length) {
429
- this.currentPage = 0
430
- }
431
- if(this.preViewType == 'pdf') {
432
- this.scrollToUplaodePage(this.currentPage)
433
- } else {
434
- this.scrollToExcalTop(this.currentPage)
435
- }
436
- },
437
- currentChange (value) {
438
- this.currentPage = value - 1
439
- if(this.preViewType == 'pdf') {
440
- this.scrollToUplaodePage(this.currentPage)
441
- } else {
442
- this.scrollToExcalTop(this.currentPage)
443
- }
444
- },
445
- scrollToUplaodePage (currentPage) {
446
- this.changetoolbar = true
447
- if(this.preViewType !== 'pdf') {
448
- return
449
- }
450
- let pdfResloute = this.cachePdf[currentPage]
451
- this.identifyTextPostion.extractInfo = pdfResloute.extractInfo
452
- this.identifyTextPostion.left = pdfResloute.extractInfo.location[0]
453
- this.identifyTextPostion.top = pdfResloute.extractInfo.location[1]
454
- this.identifyTextPostion.width = pdfResloute.extractInfo.location[2]
455
- this.identifyTextPostion.height = pdfResloute.extractInfo.location[3]
456
- this.identifyTextPostion.page = pdfResloute.page
457
- this.identifyTextPostion.pageHeight = pdfResloute.pageHeight
458
- this.identifyTextPostion.pageWidth = pdfResloute.pageWidth
459
- // 在当前段落在最后一页pdf时,根据计算的高度并不能触发滚动,在此执行重新渲染方法,非次情况会执行两次,待优化
460
- this.$nextTick(() => {
461
- this.renderHighlights()
462
- })
463
- this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))}`
464
- },
465
- scrollToExcalTop(currentPage) {
466
- for (let index = 0; index < this.allTr.length; index++) {
467
- if(index == currentPage) {
468
- this.allTr[index].children.forEach(item =>{
469
- item.style.background = 'rgba(255, 136, 0, 0.6)'
470
- })
471
- this.$refs.pdfView.scrollTop = this.allTr[index].offsetTop
472
- } else {
473
- this.allTr[index].children.forEach(item =>{
474
- item.style.background = 'rgba(54, 106, 255, 0.6)'
475
- })
476
- }
477
- }
478
- },
479
- // pdf是否需要重新渲染高亮位置
480
- renderHighlights () {
481
- let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
482
- console.log(lineHeightDom, this.currentPage, 'this.currentPage');
483
- if (lineHeightDom) {
484
- lineHeightDom.forEach((d) => {
485
- for (let i = 0; i < d.children.length; i++) {
486
- if (d.getAttribute('react-count') == this.currentPage) {
487
- d.children[i].style.backgroundColor = 'rgba(255, 136, 0, 0.3)'
488
- } else {
489
- d.children[i].style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
490
- }
491
- }
492
- })
493
- }
494
- },
495
- displayHiglight (pageIndex) {
496
- let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
497
- if (lineHeightDom) {
498
- lineHeightDom.forEach((d) => {
499
- if (d.getAttribute('page-index') == pageIndex) {
500
- d.style.display = 'none'
501
- }
502
- })
503
- }
504
- },
505
- // 前端暂时缓存多页
506
- autoLoadMore (pageIndex) {
507
- let pdfResloute = this.cachePdf.find(cache => {
508
- return cache.page == pageIndex
509
- })
510
- if (pdfResloute) {
511
- this.getpdfResloutePage(pdfResloute)
512
- } else {
513
- this.loadPdfData(pageIndex)
514
- }
515
- },
516
- setPageAllLine (arr) {
517
- this.currentPageAllLine = []
518
- arr.forEach((item, index) => {
519
- let i = this.currentPageAllLine.findIndex(l => { return l.page && l.page == item.page })
520
- if (i != -1) {
521
- // this.currentPageAllLine[i].allLines.lines.push(item.extractInfo.lines)
522
- this.currentPageAllLine[i].allLines.push({
523
- pageCount: index,
524
- lines: item.extractInfo.lines
525
- })
526
- } else {
527
- this.currentPageAllLine.push({
528
- page: item.page,
529
- allLines: [{
530
- pageCount: index,
531
- lines: item.extractInfo.lines
532
- }],
533
- })
534
- }
535
- })
536
- },
537
- openTouch() {
538
- // this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行
539
- let that = this;
540
- this.$nextTick(() => {
541
- // setInterval(() => {
542
- // this.scale = this.scale + 0.1
543
- // that.pages.forEach((item, index) =>{
544
- // if(item.dom) {
545
- // item.dom.children.forEach( childDom =>{
546
- // if(childDom.getAttribute('react-count')) {
547
- // childDom.style.transform = "scale(" + this.scale + ")";
548
- // childDom.style.transformOrigin = "0px 0px 0px";
549
- // } else {
550
- // item.dom = null
551
- // this.startRenderPages(item.pdfPage, null, index)
552
- // }
553
- // } )
554
- // }
555
- // })
556
- // }, 100);
557
- // 获取放大或缩小的区域DOM
558
- let matrix_box = this.contentView
559
- matrix_box.addEventListener("touchstart", function (event) {
560
- this.isTouchMoved = true
561
- let touches = event.touches;
562
- let events = touches[0];
563
- let events2 = touches[1];
564
-
565
- // event.preventDefault();
566
-
567
- // 第一个触摸点的坐标
568
- that.displacement.pageX = events.pageX;
569
- that.displacement.pageY = events.pageY;
570
-
571
- that.displacement.moveable = true;
572
-
573
- if (events2) {
574
- that.displacement.pageX2 = events2.pageX;
575
- that.displacement.pageY2 = events2.pageY;
576
- }
577
-
578
- that.displacement.originScale = this.scale || 1;
579
- // console.log(that.displacement);
580
- });
581
- document.addEventListener("touchmove", function (event) {
582
- if (!that.displacement.moveable) {
583
- return;
584
- }
585
- // event.preventDefault();
586
- let touches = event.touches;
587
- let events = touches[0];
588
- let events2 = touches[1];
589
- // 双指移动
590
- if (events2) {
591
- // 第2个指头坐标在touchmove时候获取
592
- if (!that.displacement.pageX2) {
593
- that.displacement.pageX2 = events2.pageX;
594
- }
595
- if (!that.displacement.pageY2) {
596
- that.displacement.pageY2 = events2.pageY;
597
- }
598
- // 双指缩放比例计算
599
- let zoom = that.getDistance({
600
- x: events.pageX,
601
- y: events.pageY
602
- },
603
- {
604
- x: events2.pageX,
605
- y: events2.pageY
606
- }
607
- ) / that.getDistance(
608
- {
609
- x: that.displacement.pageX,
610
- y: that.displacement.pageY
611
- },
612
- {
613
- x: that.displacement.pageX2,
614
- y: that.displacement.pageY2
615
- }
616
- );
617
- // 应用在元素上的缩放比例
618
- let newScale = that.displacement.originScale * zoom;
619
- console.log(zoom, newScale , this.scale, 'newScale');
620
- // 最大缩放比例限制
621
- if (newScale > 2) {
622
- newScale = 2;
623
- }
624
- // 最大缩放比例限制
625
- if(newScale < 1) {
626
- newScale = 1;
627
- }
628
- // 记住使用的缩放值
629
- that.displacement.scale = newScale;
630
- // console.log(newScale);
631
- matrix_box.style.transform = "scale(" + newScale + ")";
632
- // 设置旋转元素的基点位置
633
- matrix_box.style.transformOrigin = "0px 0px 0px";
634
- }
635
- },{ passive: false });
636
- document.addEventListener('touchend',function() {
637
- that.isTouchMoved = false
638
- },{ passive: false })
639
- });
640
- },
641
- getDistance(start, stop) {
642
- // Math.hypot()计算参数的平方根
643
- return Math.hypot(stop.x - start.x, stop.y - start.y);
644
- },
645
- setupCanvas(canvas, width, height) {
646
- const dpr = 1;
647
- // const rect = canvas.getBoundingClientRect();
648
- canvas.width = width
649
- canvas.height = height
650
- const ctx = canvas.getContext('2d');
651
- console.log(canvas.width, canvas.height, dpr, this.scale);
652
- ctx?.scale(dpr, dpr );
653
- return ctx;
654
- },
655
- },
656
- computed:{
657
- perviewUrl() {
658
- return '/web/viewer.html?file=' + '/pdflist/pdf4split-1.pdf'
659
- }
660
- },
661
- watch:{
662
- tagIds: {
663
- handler(value) {
664
- if(value && value.length) {
665
- // 在 pdf_view 下创建 所有canvs的容器
666
- this.contentView = document.createElement('div')
667
- this.contentView.style.transformOrigin = '0px 0px 0px'
668
- this.$http.get('/knowledge-api/knowledge/knowledge-part-location-info/list?ids=' + value.join(',')).then(res =>{
669
- if (res.data.code == 0) {
670
- // tagIds 会按照gpt识别的生成有序的数组,前端直接按照下标的顺序取就可以了
671
- // 缓存拿到的所有数据
672
- this.cachePdf = res.data.data
673
- let publicPageFileUrl = res.data.data[0].publicPageFileUrl
674
- this.currentPage = 0
675
- // console.log(publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')));
676
- if (publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')) === '.pdf') {
677
- this.preViewType = 'pdf'
678
- this.setPageAllLine(this.cachePdf)
679
- this.getpdfResloutePage(res.data.data[0])
680
- } else {
681
- this.preViewType = 'excal'
682
- this.$http.post(
683
- '/knowledge-api/temporary-certificate/or-origin?expired=30',
684
- publicPageFileUrl,
685
- {
686
- headers: {
687
- "Content-Type": "application/json",
688
- },
689
- }).then(res => {
690
- // 使用原声请求方式 axios会带有不需要的请求头
691
- let xhr = new XMLHttpRequest();
692
- xhr.open('GET', res.data, true);
693
- // 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
694
- xhr.onload = ({ currentTarget }) => {
695
- // 请求完成
696
- if (currentTarget.status === 200) { // 返回200
697
- this.contentView.innerHTML = currentTarget.response
698
- this.contentView.style.padding = '10px'
699
- this.$refs.pdfView.style.backgroundColor = '#FFFFFF'
700
- this.$refs.pdfView.appendChild(this.contentView)
701
- let allTr = Array.from(this.$refs.pdfView.getElementsByTagName('tr'))
702
- this.allTr = []
703
- for (let index = 0; index < allTr.length; index++) {
704
- if(value.includes(allTr[index].getAttribute('tag-id'))) {
705
- this.allTr.push(allTr[index])
706
- }
707
- }
708
- this.currentChange(1)
709
-
710
- }
711
- }
712
- xhr.send();
713
- })
714
- }
715
-
716
- } else {
717
- let div = document.createElement('div')
718
- div.innerText = '文件加载异常'
719
- this.contentView.appendChild(div)
720
- this.$refs.pdfView.appendChild(this.contentView)
721
- }
722
- })
723
- }
724
- },
725
- deep:true,
726
- immediate:true
727
- }
728
- },
729
- mounted () {
730
- }
731
- }
732
- </script>
733
-
734
- <style lang="less" scoped>
735
- .pdf_view {
736
- width: 100%;
737
- height: calc(100% - 51px);
738
- overflow: auto;
739
- background-color: #f5f7fb;
740
- padding-bottom: 60px;
741
- box-sizing: border-box;
742
- // position: relative;
743
- // > div {
744
- // width: 100%;
745
- // height: 100%;
746
- // overflow: hidden;
747
- // overflow-y: auto;
748
- // position: relative;
749
- // }
750
- > iframe {
751
- width: 100%;
752
- height: 100%;
753
- }
754
- .btn_footer {
755
- width: 100%;
756
- height: 60px;
757
- display: flex;
758
- align-items: center;
759
- justify-content: space-around;
760
- position: absolute;
761
- bottom: 0px;
762
- left: 0;
763
- z-index: 999;
764
- background: #ffffff;
765
- .prev, .next {
766
- width: 35%;
767
- height: 40px;
768
- display: flex;
769
- align-items: center;
770
- justify-content: center;
771
- border-radius: 50px;
772
- cursor: pointer;
773
- }
774
- .prev {
775
- background: #F2F5FA;
776
- color: #000;
777
- }
778
- .next {
779
- background: #366aff;
780
- color: #ffffff;
781
- }
782
- }
783
- }
1
+ <template>
2
+ <div class="pdf_view" ref="pdfView" @scroll="pdfScroll">
3
+ <div class="btn_footer" v-if="tagIds.length > 1">
4
+ <div class="prev" @click="prev">上一段</div>
5
+ <div class="next" @click="next">下一段</div>
6
+ </div>
7
+ </div>
8
+ </template>
9
+
10
+ <script>
11
+ import _ from 'lodash'
12
+ // import * as pdfjsLib from 'pdfjs-dist'
13
+ // pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker';
14
+ // import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
15
+ // EventBus pdf_viewer 支持绑定自定义事件,一版不做
16
+ // import 'pdfjs-dist/web/pdf_viewer.css'
17
+ /* eslint-disable */
18
+ const pdfjsLib = window['pdfjsLib']
19
+ if(pdfjsLib) {
20
+ pdfjsLib.GlobalWorkerOptions.workerSrc = window['pdfjs-dist/build/pdf.worker']
21
+ // 'pdfjs-dist/build/pdf.worker';
22
+ }
23
+ const { TextLayerBuilder } = window['pdfjs-dist/web/pdf_viewer']
24
+ // import { zoomElement } from '../assets/js/hammer'
25
+ export default {
26
+ name: 'pdfView',
27
+ props:['tagIds'],
28
+ data() {
29
+ return {
30
+ url: '',
31
+ // pdfjsLib: window['pdfjs-dist/build/pdf'],
32
+ // pdfjsLib: pdfjsLib,
33
+ pages: [],
34
+ pageLoadStatus: {
35
+ WAIT: 0,
36
+ LOADED: 1,
37
+ },
38
+ scale: 1,
39
+ rotation: 0,
40
+ pageSize: {},
41
+ PAGE_INTVERVAL: 15,
42
+ SLICE_COUNT: 5,
43
+ contentView: null,
44
+ fisrtLoad: true,
45
+ TextLayerBuilder: null,
46
+ totalPageCount: 0,
47
+ identifyTextPostion: {
48
+ top: 0,
49
+ left: 0,
50
+ width: 100,
51
+ height: 0,
52
+ page: 1,
53
+ pageHeight: 0,
54
+ pageWidth: 0,
55
+ extractInfo: {},
56
+ currentPageAllLine: []
57
+ },
58
+ currentPageAllLine: [],
59
+ pdfUrl: '',
60
+ cachePdf: [],
61
+ newViewer: null,
62
+ currentPage: 0,
63
+ changetoolbar: false,
64
+ allTr:[],
65
+ preViewType: 'pdf',
66
+ displacement:{
67
+ pageX:0,
68
+ pageY:0,
69
+ moveable:false,
70
+ pageX2:0,
71
+ pageY2:0,
72
+ originScale:1,
73
+ },
74
+ isTouchMoved: false
75
+ }
76
+ },
77
+ methods: {
78
+ getpdfResloutePage (pdfResloute) {
79
+ // 根据当前页面宽度设置缩放比例
80
+ // this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
81
+ // console.log(this.scale,'this.scale');
82
+ this.scale = 1
83
+ // 从后端获取到当前分片后所有的pdf页码,初始化数组,数组下{} 对应每页pdf文件
84
+ this.pdfUrl = pdfResloute.publicPageFileUrl.substring(0, pdfResloute.publicPageFileUrl.lastIndexOf('/') + 1)
85
+ this.initPages(pdfResloute.total)
86
+ // 定位功能,加载对应页码位置
87
+ this.loadPdfData(pdfResloute.page)
88
+ },
89
+ async loadPdfData (loadPage) {
90
+ if(this.pages[loadPage - 1] && this.pages[loadPage - 1].dom && this.pages[loadPage - 1].dom.children.length > 0) {
91
+ return
92
+ }
93
+ // pdfjsLib.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/legacy/build/pdf.worker.entry.js");
94
+ // 拿到第一个分片
95
+ const { startPage, url } = await this.fetchPdfFragment(loadPage);
96
+ let loadingTask = pdfjsLib.getDocument(url)
97
+ loadingTask.promise.then((pdfDoc) => {
98
+ // 将已经下载的分片保存到 pages 数组中
99
+ for (let i = 0; i < pdfDoc.numPages; i += 1) {
100
+ const pageIndex = startPage + i;
101
+ const page = this.pages[pageIndex - 1];
102
+ // 不在缓存列表内,重新获取本页pdf
103
+ if (page.loadStatus !== this.pageLoadStatus.LOADED) {
104
+ pdfDoc.getPage(i + 1).then((pdfPage) => {
105
+ page.pdfPage = pdfPage;
106
+ page.loadStatus = this.pageLoadStatus.LOADED;
107
+ // 通知可以进行渲染了
108
+ this.startRenderPages(pdfPage, page, pageIndex)
109
+ });
110
+ } else {
111
+ if (this.changetoolbar) {
112
+ this.$nextTick(() => {
113
+ this.renderHighlights()
114
+ })
115
+ this.changetoolbar = false
116
+ }
117
+ }
118
+ }
119
+ });
120
+ },
121
+ initPages (totalPage) {
122
+ // const pages = [];
123
+ this.totalPageCount = totalPage
124
+ for (let i = 0; i < totalPage; i += 1) {
125
+ this.pages.push({
126
+ pageNo: i + 1,
127
+ loadStatus: this.pageLoadStatus.WAIT,
128
+ pdfPage: null,
129
+ dom: null
130
+ });
131
+ }
132
+ },
133
+ async fetchPdfFragment (pageIndex) {
134
+ // 置换加签后的文件地址。
135
+ let obj = {}
136
+ await this.$http.post(
137
+ '/knowledge-api/temporary-certificate/or-origin?expired=30',
138
+ this.pdfUrl + pageIndex + '.pdf',
139
+ {
140
+ headers: {
141
+ "Content-Type": "application/json",
142
+ },
143
+ }).then(async res => {
144
+ if(res.bodyText) {
145
+ // 最后返回一个 包含这4个参数的对象
146
+ obj = await {
147
+ "startPage": pageIndex, // 分片的开始页码
148
+ "endPage": pageIndex + 5, // 分片结束页码
149
+ "totalPage": this.totalPageCount, // pdf 总页数
150
+ "url": res.bodyText // 分片内容下载地址
151
+ }
152
+ }
153
+ if (res.data) {
154
+ // 最后返回一个 包含这4个参数的对象
155
+ obj = await {
156
+ "startPage": pageIndex, // 分片的开始页码
157
+ "endPage": pageIndex + 5, // 分片结束页码
158
+ "totalPage": this.totalPageCount, // pdf 总页数
159
+ "url": res.data // 分片内容下载地址
160
+ }
161
+ }
162
+ })
163
+ return obj
164
+ },
165
+ startRenderPages (pdfPage, page, pageIndex) {
166
+ const viewport = pdfPage.getViewport({
167
+ scale: this.scale, // 缩放的比例
168
+ rotation: this.rotation, // 旋转的角度
169
+ });
170
+ // 记录pdf页面高度
171
+ const pageSize = {
172
+ width: viewport.width,
173
+ height: viewport.height,
174
+ }
175
+ this.pageSize = pageSize
176
+ // 创建内容绘制区,并设置大小
177
+ this.contentView.style.width = `${pageSize.width}px`;
178
+ this.contentView.style.height = `${(this.totalPageCount * (pageSize.height + this.PAGE_INTVERVAL)) * (this.$refs.pdfView.clientWidth / pageSize.width) + this.PAGE_INTVERVAL}px`;
179
+ this.contentView.style.margin = '0 auto 0'
180
+ this.contentView.style.position = 'relative'
181
+ // contentView.style.overflowY = 'auto'
182
+ this.$refs.pdfView.appendChild(this.contentView);
183
+ this.renderPages(pageIndex)
184
+ },
185
+ renderPageContent (page, pageIndex) {
186
+ const { pdfPage, pageNo, dom } = page;
187
+ // dom 元素已存在,无须重新渲染,直接返回
188
+ console.log(dom, 'dom');
189
+ if (dom && dom.children.length != 0) {
190
+ return;
191
+ }
192
+ const viewport = pdfPage.getViewport({
193
+ scale: this.scale,
194
+ rotation: this.rotation,
195
+ });
196
+ // 创建新的canvas
197
+ const canvas = document.createElement('canvas');
198
+ const context = canvas.getContext('2d');
199
+ // canvas.getContext('2d');
200
+ canvas.height = this.pageSize.height;
201
+ canvas.width = this.pageSize.width;
202
+ // 创建渲染的dom
203
+ const pageDom = document.createElement('div');
204
+ pageDom.style.position = 'absolute';
205
+ pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
206
+ pageDom.style.width = `${this.pageSize.width}px`;
207
+ pageDom.style.height = `${this.pageSize.height}px`;
208
+ pageDom.appendChild(canvas);
209
+ // 渲染内容
210
+ let renderContext = {
211
+ canvasContext: context,
212
+ viewport: viewport,
213
+ }
214
+ pdfPage.render(renderContext).promise.then(() => {
215
+ console.log(pdfPage.getTextContent(), 'getTextContent');
216
+ return pdfPage.getTextContent()
217
+ }).then((textContent) => {
218
+ const textLayerDiv = document.createElement('div');
219
+ textLayerDiv.setAttribute('class', 'textLayer');
220
+ // 将文本图层div添加至每页pdf的div中
221
+ // 创建新的TextLayerBuilder实例
222
+ let textLayer = new TextLayerBuilder({
223
+ textLayerDiv: textLayerDiv,
224
+ pageIndex: pdfPage._pageIndex,
225
+ viewport: viewport,
226
+ });
227
+ let findPage = this.currentPageAllLine.find(l => { return l.page == pageIndex })
228
+ if (findPage) {
229
+ let AllLines = findPage.allLines
230
+ // setTimeout(() => {
231
+ if (AllLines.length > 0) {
232
+ for (let j = 0; j < AllLines.length; j++) {
233
+ let lines = AllLines[j].lines
234
+ let rectdom = document.createElement('div')
235
+ rectdom.setAttribute('react-count', AllLines[j].pageCount);
236
+ rectdom.style.position = 'absolute';
237
+ rectdom.style.top = 0
238
+ rectdom.style.left = 0
239
+ rectdom.classList.add('rectdom')
240
+ for (let index = 0; index < lines.length; index++) {
241
+ if (!/^\s+$/g.test(lines[index].content)) {
242
+ let postionArr = lines[index].location
243
+ let div = document.createElement('div')
244
+ div.style.position = 'absolute';
245
+ div.style.left = postionArr[0] * this.scale + 'px',
246
+ // 后端返回的坐标有基线对齐的问题,top 值是后端算好(基线top - 文字高度),在此加上文字高度的 1/9 (大致比例)为实际展示出文字的top值
247
+ div.style.top = (postionArr[1] + postionArr[3] / 9) * this.scale + 'px'
248
+ div.style.height = postionArr[3] * this.scale + 'px';
249
+ div.style.width = postionArr[2] * this.scale + 'px'
250
+ div.style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
251
+ div.classList.add('lineHeight')
252
+ rectdom.appendChild(div)
253
+ }
254
+ }
255
+ if (rectdom.children.length > 0) {
256
+ pageDom.appendChild(rectdom)
257
+ }
258
+ }
259
+ }
260
+ }
261
+ textLayer.setTextContent(textContent);
262
+ textLayer.render()
263
+ pageDom.appendChild(textLayer.textLayerDiv);
264
+ page.dom = pageDom;
265
+ this.contentView.appendChild(pageDom);
266
+ this.contentView.style.transform = `scale(${this.$refs.pdfView.clientWidth / this.pageSize.width}, ${this.$refs.pdfView.clientWidth / this.pageSize.width})`
267
+
268
+ if (this.changetoolbar) {
269
+ setTimeout(() => {
270
+ this.renderHighlights()
271
+ this.changetoolbar = false
272
+ }, 100)
273
+ }
274
+ if (this.fisrtLoad) {
275
+ setTimeout(() => {
276
+ if (this.$refs.pdfView.clientHeight - (this.pageSize.height + this.PAGE_INTVERVAL) > (this.pageSize.height + this.PAGE_INTVERVAL)) {
277
+ let loadNum = Math.ceil(this.$refs.pdfView.clientHeight / (this.pageSize.height + this.PAGE_INTVERVAL))
278
+ for (let n = 0; n < loadNum; n++) {
279
+ this.loadPdfData(pageNo + n)
280
+ }
281
+ } else {
282
+ this.renderHighlights()
283
+ }
284
+ if (this.$refs.pdfView.scrollTop == Math.floor((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))) {
285
+ this.fisrtLoad = false
286
+ } else {
287
+ this.$refs.pdfView.scrollTop = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))}`
288
+ }
289
+ // zoomElement(this.contentView)
290
+ }, 100)
291
+ }
292
+ })
293
+ },
294
+ // 监听容器的滚动事件,触发 scrollPdf 方法
295
+ // 这里加了防抖保证不会一次产生过多请求
296
+ debounceScrollPdf: _.debounce(function (e, that) {
297
+ if (this.fisrtLoad) {
298
+ this.fisrtLoad = false
299
+ return
300
+ }
301
+ const scrollTop = e.target.scrollTop;
302
+ const height = e.target.clientHeight;
303
+ // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
304
+ const pageIndex = scrollTop > 0 ?
305
+ Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
306
+ 1;
307
+
308
+ pageIndex - 1 != 0 && that.loadPdfData(pageIndex - 1)
309
+ that.loadPdfData(pageIndex)
310
+ pageIndex + 1 <= that.totalPageCount && that.loadPdfData(pageIndex + 1)
311
+ }, 200),
312
+ directScrolling (e, that) {
313
+ if (this.fisrtLoad) {
314
+ this.fisrtLoad = false
315
+ return
316
+ }
317
+ const scrollTop = e.target.scrollTop;
318
+ const height = e.target.clientHeight;
319
+ // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
320
+ const pageIndex = scrollTop > 0 ?
321
+ Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
322
+ 1;
323
+ this.loadPdfData(pageIndex)
324
+ },
325
+ pdfScroll (e) {
326
+ if(this.preViewType !== 'pdf' || this.isTouchMoved) {
327
+ return
328
+ }
329
+ this.debounceScrollPdf(e, this)
330
+ },
331
+ // 分片每次只做一次处理,所以不考虑多片情况
332
+ loadBefore (pageIndex) {
333
+ this.loadPdfData(pageIndex)
334
+ // const start = (Math.floor(pageIndex / this.SLICE_COUNT) * this.SLICE_COUNT) - (this.SLICE_COUNT - 1);
335
+ // if (start > 0) {
336
+ // // const prevPage = this.pages[start - 1] || {};
337
+ // this.loadPdfData(start)
338
+ // // prevPage.loadStatus === this.pageLoadStatus.WAIT && this.loadPdfData(start);
339
+ // }
340
+ },
341
+ loadAfter (pageIndex) {
342
+ this.loadPdfData(pageIndex)
343
+ // const start = (Math.floor(pageIndex / this.SLICE_COUNT) * this.SLICE_COUNT) + 1;
344
+ // if (start <= this.pages.length) {
345
+ // // const nextPage = this.pages[start - 1] || {};
346
+ // this.loadPdfData(start)
347
+ // // nextPage.loadStatus === this.pageLoadStatus.WAIT && this.loadPdfData(start);
348
+ // }
349
+ },
350
+ // 首先我们获取到需要渲染的范围
351
+ // 根据当前的可视范围内的页码,我们前后只保留 8 页
352
+ getRenderScope (pageIndex) {
353
+ const pagesToRender = [];
354
+ let i = pageIndex - 1;
355
+ let j = pageIndex + 1;
356
+ // pageIndex - 1 表示当前页码数 对应的下标位置
357
+ pagesToRender.push(this.pages[pageIndex - 1]);
358
+ while (pagesToRender.length < 10 && pagesToRender.length < this.pages.length) {
359
+ if (i > 0) {
360
+ pagesToRender.push(this.pages[i - 1]);
361
+ i -= 1;
362
+ }
363
+ if (pagesToRender.length >= 10) {
364
+ break;
365
+ }
366
+ if (j <= this.pages.length) {
367
+ pagesToRender.push(this.pages[j - 1]);
368
+ j += 1;
369
+ }
370
+ }
371
+ return pagesToRender;
372
+ },
373
+ // 渲染需要展示的页面,不需展示的页码将其清除
374
+ renderPages (pageIndex) {
375
+ const pagesToRender = this.getRenderScope(pageIndex);
376
+ for (const i of this.pages) {
377
+ if (pagesToRender.includes(i)) {
378
+ i.loadStatus === this.pageLoadStatus.LOADED ?
379
+ this.renderPageContent(i, pageIndex) :
380
+ this.renderPageLoading(i);
381
+ } else {
382
+ this.clearPage(i);
383
+ }
384
+ }
385
+ },
386
+ // 清除页面 dom
387
+ clearPage (page) {
388
+ if (page.dom) {
389
+ this.contentView.removeChild(page.dom);
390
+ page.loadStatus = 0
391
+ page.dom = undefined;
392
+ }
393
+ },
394
+ // 页面正在下载时渲染loading视图
395
+ renderPageLoading (page) {
396
+ const { pageNo, dom } = page;
397
+ if (dom && dom.children.length != 0) {
398
+ return;
399
+ }
400
+ const pageDom = document.createElement('div');
401
+ pageDom.style.width = `${this.pageSize.width}px`;
402
+ pageDom.style.height = `${this.pageSize.height}px`;
403
+ pageDom.style.position = 'absolute';
404
+ pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL
405
+ }px`;
406
+ pageDom.style.backgroundImage = `url('https://guoranopen-zjk.oss-cn-zhangjiakou.aliyuncs.com/cdn-common/images/loading.gif')`
407
+ pageDom.style.backgroundPosition = 'center'
408
+ pageDom.style.backgroundRepeat = 'no-repeat'
409
+ pageDom.style.backgroundColor = '#FFF'
410
+ page.dom = pageDom;
411
+ this.contentView.appendChild(pageDom);
412
+ },
413
+ prev () {
414
+ this.currentPage--
415
+ if (this.currentPage < 0) {
416
+ // this.currentPage = this.tagIds.length - 1
417
+ this.currentPage = 0
418
+ }
419
+ if(this.preViewType == 'pdf') {
420
+ this.scrollToUplaodePage(this.currentPage)
421
+ } else {
422
+ this.scrollToExcalTop(this.currentPage)
423
+ }
424
+ // this.getpdfResloutePage(this.cachePdf[this.currentPage - 1])
425
+ },
426
+ next () {
427
+ this.currentPage++
428
+ if (this.currentPage >= this.tagIds.length) {
429
+ this.currentPage = 0
430
+ }
431
+ if(this.preViewType == 'pdf') {
432
+ this.scrollToUplaodePage(this.currentPage)
433
+ } else {
434
+ this.scrollToExcalTop(this.currentPage)
435
+ }
436
+ },
437
+ currentChange (value) {
438
+ this.currentPage = value - 1
439
+ if(this.preViewType == 'pdf') {
440
+ this.scrollToUplaodePage(this.currentPage)
441
+ } else {
442
+ this.scrollToExcalTop(this.currentPage)
443
+ }
444
+ },
445
+ scrollToUplaodePage (currentPage) {
446
+ this.changetoolbar = true
447
+ if(this.preViewType !== 'pdf') {
448
+ return
449
+ }
450
+ let pdfResloute = this.cachePdf[currentPage]
451
+ this.identifyTextPostion.extractInfo = pdfResloute.extractInfo
452
+ this.identifyTextPostion.left = pdfResloute.extractInfo.location[0]
453
+ this.identifyTextPostion.top = pdfResloute.extractInfo.location[1]
454
+ this.identifyTextPostion.width = pdfResloute.extractInfo.location[2]
455
+ this.identifyTextPostion.height = pdfResloute.extractInfo.location[3]
456
+ this.identifyTextPostion.page = pdfResloute.page
457
+ this.identifyTextPostion.pageHeight = pdfResloute.pageHeight
458
+ this.identifyTextPostion.pageWidth = pdfResloute.pageWidth
459
+ // 在当前段落在最后一页pdf时,根据计算的高度并不能触发滚动,在此执行重新渲染方法,非次情况会执行两次,待优化
460
+ this.$nextTick(() => {
461
+ this.renderHighlights()
462
+ })
463
+ this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL))}`
464
+ },
465
+ scrollToExcalTop(currentPage) {
466
+ for (let index = 0; index < this.allTr.length; index++) {
467
+ if(index == currentPage) {
468
+ this.allTr[index].children.forEach(item =>{
469
+ item.style.background = 'rgba(255, 136, 0, 0.6)'
470
+ })
471
+ this.$refs.pdfView.scrollTop = this.allTr[index].offsetTop
472
+ } else {
473
+ this.allTr[index].children.forEach(item =>{
474
+ item.style.background = 'rgba(54, 106, 255, 0.6)'
475
+ })
476
+ }
477
+ }
478
+ },
479
+ // pdf是否需要重新渲染高亮位置
480
+ renderHighlights () {
481
+ let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
482
+ console.log(lineHeightDom, this.currentPage, 'this.currentPage');
483
+ if (lineHeightDom) {
484
+ lineHeightDom.forEach((d) => {
485
+ for (let i = 0; i < d.children.length; i++) {
486
+ if (d.getAttribute('react-count') == this.currentPage) {
487
+ d.children[i].style.backgroundColor = 'rgba(255, 136, 0, 0.3)'
488
+ } else {
489
+ d.children[i].style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
490
+ }
491
+ }
492
+ })
493
+ }
494
+ },
495
+ displayHiglight (pageIndex) {
496
+ let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
497
+ if (lineHeightDom) {
498
+ lineHeightDom.forEach((d) => {
499
+ if (d.getAttribute('page-index') == pageIndex) {
500
+ d.style.display = 'none'
501
+ }
502
+ })
503
+ }
504
+ },
505
+ // 前端暂时缓存多页
506
+ autoLoadMore (pageIndex) {
507
+ let pdfResloute = this.cachePdf.find(cache => {
508
+ return cache.page == pageIndex
509
+ })
510
+ if (pdfResloute) {
511
+ this.getpdfResloutePage(pdfResloute)
512
+ } else {
513
+ this.loadPdfData(pageIndex)
514
+ }
515
+ },
516
+ setPageAllLine (arr) {
517
+ this.currentPageAllLine = []
518
+ arr.forEach((item, index) => {
519
+ let i = this.currentPageAllLine.findIndex(l => { return l.page && l.page == item.page })
520
+ if (i != -1) {
521
+ // this.currentPageAllLine[i].allLines.lines.push(item.extractInfo.lines)
522
+ this.currentPageAllLine[i].allLines.push({
523
+ pageCount: index,
524
+ lines: item.extractInfo.lines
525
+ })
526
+ } else {
527
+ this.currentPageAllLine.push({
528
+ page: item.page,
529
+ allLines: [{
530
+ pageCount: index,
531
+ lines: item.extractInfo.lines
532
+ }],
533
+ })
534
+ }
535
+ })
536
+ },
537
+ openTouch() {
538
+ // this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行
539
+ let that = this;
540
+ this.$nextTick(() => {
541
+ // setInterval(() => {
542
+ // this.scale = this.scale + 0.1
543
+ // that.pages.forEach((item, index) =>{
544
+ // if(item.dom) {
545
+ // item.dom.children.forEach( childDom =>{
546
+ // if(childDom.getAttribute('react-count')) {
547
+ // childDom.style.transform = "scale(" + this.scale + ")";
548
+ // childDom.style.transformOrigin = "0px 0px 0px";
549
+ // } else {
550
+ // item.dom = null
551
+ // this.startRenderPages(item.pdfPage, null, index)
552
+ // }
553
+ // } )
554
+ // }
555
+ // })
556
+ // }, 100);
557
+ // 获取放大或缩小的区域DOM
558
+ let matrix_box = this.contentView
559
+ matrix_box.addEventListener("touchstart", function (event) {
560
+ this.isTouchMoved = true
561
+ let touches = event.touches;
562
+ let events = touches[0];
563
+ let events2 = touches[1];
564
+
565
+ // event.preventDefault();
566
+
567
+ // 第一个触摸点的坐标
568
+ that.displacement.pageX = events.pageX;
569
+ that.displacement.pageY = events.pageY;
570
+
571
+ that.displacement.moveable = true;
572
+
573
+ if (events2) {
574
+ that.displacement.pageX2 = events2.pageX;
575
+ that.displacement.pageY2 = events2.pageY;
576
+ }
577
+
578
+ that.displacement.originScale = this.scale || 1;
579
+ // console.log(that.displacement);
580
+ });
581
+ document.addEventListener("touchmove", function (event) {
582
+ if (!that.displacement.moveable) {
583
+ return;
584
+ }
585
+ // event.preventDefault();
586
+ let touches = event.touches;
587
+ let events = touches[0];
588
+ let events2 = touches[1];
589
+ // 双指移动
590
+ if (events2) {
591
+ // 第2个指头坐标在touchmove时候获取
592
+ if (!that.displacement.pageX2) {
593
+ that.displacement.pageX2 = events2.pageX;
594
+ }
595
+ if (!that.displacement.pageY2) {
596
+ that.displacement.pageY2 = events2.pageY;
597
+ }
598
+ // 双指缩放比例计算
599
+ let zoom = that.getDistance({
600
+ x: events.pageX,
601
+ y: events.pageY
602
+ },
603
+ {
604
+ x: events2.pageX,
605
+ y: events2.pageY
606
+ }
607
+ ) / that.getDistance(
608
+ {
609
+ x: that.displacement.pageX,
610
+ y: that.displacement.pageY
611
+ },
612
+ {
613
+ x: that.displacement.pageX2,
614
+ y: that.displacement.pageY2
615
+ }
616
+ );
617
+ // 应用在元素上的缩放比例
618
+ let newScale = that.displacement.originScale * zoom;
619
+ console.log(zoom, newScale , this.scale, 'newScale');
620
+ // 最大缩放比例限制
621
+ if (newScale > 2) {
622
+ newScale = 2;
623
+ }
624
+ // 最大缩放比例限制
625
+ if(newScale < 1) {
626
+ newScale = 1;
627
+ }
628
+ // 记住使用的缩放值
629
+ that.displacement.scale = newScale;
630
+ // console.log(newScale);
631
+ matrix_box.style.transform = "scale(" + newScale + ")";
632
+ // 设置旋转元素的基点位置
633
+ matrix_box.style.transformOrigin = "0px 0px 0px";
634
+ }
635
+ },{ passive: false });
636
+ document.addEventListener('touchend',function() {
637
+ that.isTouchMoved = false
638
+ },{ passive: false })
639
+ });
640
+ },
641
+ getDistance(start, stop) {
642
+ // Math.hypot()计算参数的平方根
643
+ return Math.hypot(stop.x - start.x, stop.y - start.y);
644
+ },
645
+ setupCanvas(canvas, width, height) {
646
+ const dpr = 1;
647
+ // const rect = canvas.getBoundingClientRect();
648
+ canvas.width = width
649
+ canvas.height = height
650
+ const ctx = canvas.getContext('2d');
651
+ console.log(canvas.width, canvas.height, dpr, this.scale);
652
+ ctx?.scale(dpr, dpr );
653
+ return ctx;
654
+ },
655
+ },
656
+ computed:{
657
+ perviewUrl() {
658
+ return '/web/viewer.html?file=' + '/pdflist/pdf4split-1.pdf'
659
+ }
660
+ },
661
+ watch:{
662
+ tagIds: {
663
+ handler(value) {
664
+ if(value && value.length) {
665
+ // 在 pdf_view 下创建 所有canvs的容器
666
+ this.contentView = document.createElement('div')
667
+ this.contentView.style.transformOrigin = '0px 0px 0px'
668
+ this.$http.get('/knowledge-api/knowledge/knowledge-part-location-info/list?ids=' + value.join(',')).then(res =>{
669
+ if (res.data.code == 0) {
670
+ // tagIds 会按照gpt识别的生成有序的数组,前端直接按照下标的顺序取就可以了
671
+ // 缓存拿到的所有数据
672
+ this.cachePdf = res.data.data
673
+ let publicPageFileUrl = res.data.data[0].publicPageFileUrl
674
+ this.currentPage = 0
675
+ // console.log(publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')));
676
+ if (publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')) === '.pdf') {
677
+ this.preViewType = 'pdf'
678
+ this.setPageAllLine(this.cachePdf)
679
+ this.getpdfResloutePage(res.data.data[0])
680
+ } else {
681
+ this.preViewType = 'excal'
682
+ this.$http.post(
683
+ '/knowledge-api/temporary-certificate/or-origin?expired=30',
684
+ publicPageFileUrl,
685
+ {
686
+ headers: {
687
+ "Content-Type": "application/json",
688
+ },
689
+ }).then(res => {
690
+ // 使用原声请求方式 axios会带有不需要的请求头
691
+ let xhr = new XMLHttpRequest();
692
+ xhr.open('GET', res.data, true);
693
+ // 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
694
+ xhr.onload = ({ currentTarget }) => {
695
+ // 请求完成
696
+ if (currentTarget.status === 200) { // 返回200
697
+ this.contentView.innerHTML = currentTarget.response
698
+ this.contentView.style.padding = '10px'
699
+ this.$refs.pdfView.style.backgroundColor = '#FFFFFF'
700
+ this.$refs.pdfView.appendChild(this.contentView)
701
+ let allTr = Array.from(this.$refs.pdfView.getElementsByTagName('tr'))
702
+ this.allTr = []
703
+ for (let index = 0; index < allTr.length; index++) {
704
+ if(value.includes(allTr[index].getAttribute('tag-id'))) {
705
+ this.allTr.push(allTr[index])
706
+ }
707
+ }
708
+ this.currentChange(1)
709
+
710
+ }
711
+ }
712
+ xhr.send();
713
+ })
714
+ }
715
+
716
+ } else {
717
+ let div = document.createElement('div')
718
+ div.innerText = '文件加载异常'
719
+ this.contentView.appendChild(div)
720
+ this.$refs.pdfView.appendChild(this.contentView)
721
+ }
722
+ })
723
+ }
724
+ },
725
+ deep:true,
726
+ immediate:true
727
+ }
728
+ },
729
+ mounted () {
730
+ }
731
+ }
732
+ </script>
733
+
734
+ <style lang="less" scoped>
735
+ .pdf_view {
736
+ width: 100%;
737
+ height: calc(100% - 51px);
738
+ overflow: auto;
739
+ background-color: #f5f7fb;
740
+ padding-bottom: 60px;
741
+ box-sizing: border-box;
742
+ // position: relative;
743
+ // > div {
744
+ // width: 100%;
745
+ // height: 100%;
746
+ // overflow: hidden;
747
+ // overflow-y: auto;
748
+ // position: relative;
749
+ // }
750
+ > iframe {
751
+ width: 100%;
752
+ height: 100%;
753
+ }
754
+ .btn_footer {
755
+ width: 100%;
756
+ height: 60px;
757
+ display: flex;
758
+ align-items: center;
759
+ justify-content: space-around;
760
+ position: absolute;
761
+ bottom: 0px;
762
+ left: 0;
763
+ z-index: 999;
764
+ background: #ffffff;
765
+ .prev, .next {
766
+ width: 35%;
767
+ height: 40px;
768
+ display: flex;
769
+ align-items: center;
770
+ justify-content: center;
771
+ border-radius: 50px;
772
+ cursor: pointer;
773
+ }
774
+ .prev {
775
+ background: #F2F5FA;
776
+ color: #000;
777
+ }
778
+ .next {
779
+ background: #366aff;
780
+ color: #ffffff;
781
+ }
782
+ }
783
+ }
784
784
  </style>