askbot-dragon 1.5.56-beta → 1.5.58-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.
Files changed (88) 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 +59 -58
  5. package/public/index.html +74 -74
  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 +89 -100
  14. package/src/assets/js/obsBrowser.js +63 -0
  15. package/src/assets/js/script.js +36 -36
  16. package/src/assets/less/common.css +6773 -6773
  17. package/src/assets/less/converSationContainer/common.less +192 -199
  18. package/src/assets/less/converSationContainer/converSatonContainer.less +493 -493
  19. package/src/assets/less/iconfont.css +37 -37
  20. package/src/assets/less/ticketMessage.less +294 -294
  21. package/src/components/ActionAlertIframe.vue +112 -112
  22. package/src/components/AiGuide.vue +467 -467
  23. package/src/components/AnswerDocknowledge.vue +492 -504
  24. package/src/components/AnswerVoice.vue +285 -285
  25. package/src/components/AskIFrame.vue +15 -15
  26. package/src/components/ConversationContainer.vue +5089 -5120
  27. package/src/components/FileType.vue +86 -86
  28. package/src/components/Message.vue +27 -27
  29. package/src/components/actionSatisfaction.vue +107 -107
  30. package/src/components/actionSendToBot.vue +62 -62
  31. package/src/components/answerDissatisfaction.vue +62 -62
  32. package/src/components/answerRadio.vue +131 -131
  33. package/src/components/ask-components/DissatisfactionOptions.vue +57 -57
  34. package/src/components/ask-components/Msgloading.vue +37 -37
  35. package/src/components/ask-components/SatisfactionV2.vue +15 -15
  36. package/src/components/askVideo.vue +141 -138
  37. package/src/components/assetDetails.vue +370 -370
  38. package/src/components/assetMessage.vue +228 -228
  39. package/src/components/associationIntention.vue +349 -349
  40. package/src/components/attachmentPreview.vue +90 -90
  41. package/src/components/botActionSatisfactor.vue +68 -68
  42. package/src/components/chatContent.vue +513 -513
  43. package/src/components/feedBack.vue +136 -136
  44. package/src/components/fielListView.vue +351 -351
  45. package/src/components/file/AliyunOssComponents.vue +108 -108
  46. package/src/components/formTemplate.vue +3562 -3557
  47. package/src/components/kkview.vue +1138 -1138
  48. package/src/components/loadingProcess.vue +164 -164
  49. package/src/components/message/ActionAlertIframe.vue +112 -112
  50. package/src/components/message/ShopMessage.vue +164 -164
  51. package/src/components/message/TextMessage.vue +924 -924
  52. package/src/components/message/TicketMessage.vue +201 -201
  53. package/src/components/message/swiper/index.js +4 -4
  54. package/src/components/message/swiper/ticketSwiper.vue +503 -503
  55. package/src/components/message/swiper/ticketSwiperItem.vue +61 -61
  56. package/src/components/msgLoading.vue +231 -231
  57. package/src/components/myPopup.vue +70 -70
  58. package/src/components/pdfPosition.vue +1322 -1363
  59. package/src/components/popup.vue +227 -227
  60. package/src/components/previewDoc.vue +242 -242
  61. package/src/components/previewPdf.vue +302 -310
  62. package/src/components/receiverMessagePlatform.vue +65 -65
  63. package/src/components/recommend.vue +89 -80
  64. package/src/components/selector/hOption.vue +20 -20
  65. package/src/components/selector/hSelector.vue +199 -199
  66. package/src/components/selector/hWrapper.vue +216 -216
  67. package/src/components/senderMessagePlatform.vue +50 -50
  68. package/src/components/source/BotMessage.vue +24 -24
  69. package/src/components/source/CustomMessage.vue +24 -24
  70. package/src/components/test.vue +260 -260
  71. package/src/components/tree.vue +294 -294
  72. package/src/components/utils/AliyunIssUtil.js +81 -81
  73. package/src/components/utils/ckeditor.js +177 -174
  74. package/src/components/utils/ckeditorImageUpload/command.js +111 -109
  75. package/src/components/utils/ckeditorImageUpload/editing.js +11 -11
  76. package/src/components/utils/ckeditorImageUpload/plugin-image.js +11 -11
  77. package/src/components/utils/ckeditorImageUpload/toolbar-ui.js +40 -40
  78. package/src/components/utils/ckeditorfileUpload/common.js +173 -180
  79. package/src/components/utils/ckeditorfileUpload/editing.js +11 -11
  80. package/src/components/utils/ckeditorfileUpload/plugin_file.js +11 -11
  81. package/src/components/utils/ckeditorfileUpload/toolbar_ui.js +34 -34
  82. package/src/components/utils/format_date.js +25 -25
  83. package/src/components/utils/index.js +6 -6
  84. package/src/components/utils/math_utils.js +29 -29
  85. package/src/components/voiceComponent.vue +119 -119
  86. package/src/main.js +60 -60
  87. package/vue.config.js +55 -55
  88. package/src/components/newPdfPosition.vue +0 -878
@@ -1,1364 +1,1323 @@
1
- <template>
2
- <div id="pdf_view" class="pdf_view" :style="{
3
- marginTop: isPC ? '50px' : '',
4
- marginBottom: tagIds.length > 1 ? '60px' : '0px',
5
- height: setHeight
6
- }">
7
- <div class="change_scale" v-if="isPC">
8
- <section @click="changeScale('reduce')">
9
- <i class="el-icon-minus"></i>
10
- </section>
11
- <el-divider direction="vertical"></el-divider>
12
- <section @click="changeScale('zoom')">
13
- <i class="el-icon-plus"></i>
14
- </section>
15
- <el-select size="small" v-model="handScale" @change="changeScale" placeholder="请选择">
16
- <el-option v-for="item in scaleList" :key="item.value" :label="item.label" :value="item.value">
17
- </el-option>
18
- </el-select>
19
- </div>
20
- <div class="pdf_container_view" id="pdf_container_view" @scroll="pdfScroll" ref="pdfView"></div>
21
- <div class="btn_footer" v-if="tagIds.length > 1 && !isPC">
22
- <div class="prev" @click="prev">上一段</div>
23
- <div class="next" @click="next">下一段</div>
24
- </div>
25
- <div id="pagination" v-if="tagIds.length > 1 && isPC">
26
- <el-pagination :current-page="currentPage + 1" @current-change="currentChange" @prev-click="prev"
27
- @next-click="next" layout="slot, prev, pager, next" :page-size="1" :total="tagIds.length">
28
- <span class="total-class">答案由{{ tagIds.length }}段内容生成</span>
29
- </el-pagination>
30
- </div>
31
- </div>
32
- </template>
33
-
34
- <script>
35
- import _ from 'lodash'
36
- // import * as pdfjsLib from 'pdfjs-dist'
37
- // pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker';
38
- // import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
39
- // EventBus pdf_viewer 支持绑定自定义事件,一版不做
40
- // import 'pdfjs-dist/web/pdf_viewer.css'
41
- /* eslint-disable */
42
- const pdfjsLib = window['pdfjsLib']
43
- if (pdfjsLib) {
44
- pdfjsLib.GlobalWorkerOptions.workerSrc = window['pdfjs-dist/build/pdf.worker']
45
- // 'pdfjs-dist/build/pdf.worker';
46
- }
47
- const { TextLayerBuilder } = window['pdfjs-dist/web/pdf_viewer']
48
- const CSS_UNITS = 96.0 / 72.0
49
- // import { zoomElement } from '../assets/js/hammer'
50
- export default {
51
- name: 'pdfView',
52
- props: ['tagIds', 'isMessageRecord','fileName'],
53
- data () {
54
- return {
55
- url: '',
56
- pages: [],
57
- pageLoadStatus: {
58
- WAIT: 0,
59
- LOADED: 1,
60
- },
61
- scale: 1,
62
- rotation: 0,
63
- pageSize: {},
64
- PAGE_INTVERVAL: 15,
65
- SLICE_COUNT: 5,
66
- contentView: null,
67
- fisrtLoad: true,
68
- TextLayerBuilder: null,
69
- totalPageCount: 0,
70
- identifyTextPostion: {
71
- top: 0,
72
- left: 0,
73
- width: 100,
74
- height: 0,
75
- page: 1,
76
- pageHeight: 0,
77
- pageWidth: 0,
78
- extractInfo: {},
79
- currentPageAllLine: []
80
- },
81
- currentPageAllLine: [],
82
- pdfUrl: '',
83
- cachePdf: [],
84
- newViewer: null,
85
- currentPage: 0,
86
- changetoolbar: false,
87
- allTr: [],
88
- preViewType: 'pdf',
89
- displacement: {
90
- pageX: 0,
91
- pageY: 0,
92
- moveable: false,
93
- pageX2: 0,
94
- pageY2: 0,
95
- originScale: 1,
96
- },
97
- isTouchMoved: false,
98
- transformSalce: null,
99
- defaultTransform:0.8,
100
- isPC: false,
101
- handScale: 'auto',
102
- scaleList: [
103
- {
104
- label: '自动缩放',
105
- value: 'auto'
106
- },
107
- {
108
- label: '实际比例',
109
- value: 'reality'
110
- },
111
- {
112
- label: '100%',
113
- value: 1
114
- },
115
- {
116
- label: '120%',
117
- value: 1.2
118
- },
119
- {
120
- label: '150%',
121
- value: 1.5
122
- },
123
- {
124
- label: '170%',
125
- value: 1.7
126
- }
127
- ,
128
- {
129
- label: '200%',
130
- value: 2
131
- }
132
- ],
133
- scrollTop: 0,
134
- scrollLeft: 0
135
- }
136
- },
137
- methods: {
138
- getpdfResloutePage (pdfResloute) {
139
- // 根据当前页面宽度设置缩放比例
140
- // this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
141
- if (this.isMessageRecord) {
142
- this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
143
- } else {
144
- this.scale = 2
145
- }
146
- // 从后端获取到当前分片后所有的pdf页码,初始化数组,数组下{} 对应每页pdf文件
147
- this.pdfUrl = pdfResloute.publicPageFileUrl.substring(0, pdfResloute.publicPageFileUrl.lastIndexOf('/') + 1)
148
- this.initPages(pdfResloute.total)
149
- // 定位功能,加载对应页码位置
150
- this.loadPdfData(pdfResloute.page)
151
- },
152
- async loadPdfData (loadPage) {
153
- if (this.pages[loadPage - 1] && ((this.pages[loadPage - 1].dom && this.pages[loadPage - 1].dom.children.length > 0) || this.pages[loadPage - 1].loadStatus)) {
154
- return
155
- } else {
156
- if (this.changetoolbar) {
157
- this.$nextTick(() => {
158
- this.renderHighlights()
159
- })
160
- this.changetoolbar = false
161
- }
162
- }
163
- // 记录开始缓存的状态
164
- // pdfjsLib.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/legacy/build/pdf.worker.entry.js");
165
- // 拿到第一个分片
166
- const { startPage, url } = await this.fetchPdfFragment(loadPage);
167
- let loadingTask = pdfjsLib.getDocument(url)
168
- loadingTask.promise.then(async (pdfDoc) => {
169
- // 将已经下载的分片保存到 pages 数组中
170
- // for (let i = 0; i < pdfDoc.numPages; i += 1) {
171
- // const pageIndex = startPage + i;
172
- // const page = this.pages[pageIndex - 1];
173
- // // // 不在缓存列表内,重新获取本页pdf
174
- // // if (page.loadStatus !== this.pageLoadStatus.LOADED) {
175
-
176
- // // } else {
177
- // // if (this.changetoolbar) {
178
- // // this.$nextTick(() => {
179
- // // this.renderHighlights()
180
- // // })
181
- // // this.changetoolbar = false
182
- // // }
183
- // // }
184
- // }
185
- const page = this.pages[loadPage - 1]
186
- await pdfDoc.getPage(1).then(async (pdfPage) => {
187
- this.pages[loadPage - 1].loadStatus = true
188
- this.pages[loadPage - 1].pdfPage = pdfPage;
189
- // 通知可以进行渲染了
190
- await this.startRenderPages(pdfPage, page, loadPage)
191
- });
192
- });
193
- },
194
- initPages (totalPage) {
195
- // const pages = [];
196
- this.totalPageCount = totalPage
197
- for (let i = 0; i < totalPage; i += 1) {
198
- this.pages.push({
199
- pageNo: i + 1,
200
- loadStatus: false,
201
- pdfPage: null,
202
- dom: null
203
- });
204
- }
205
- },
206
- async fetchPdfFragment (pageIndex) {
207
- // 置换加签后的文件地址。
208
- let obj = {}
209
- await this.$http.post(
210
- '/knowledge-api/temporary-certificate/or-origin?expired=30',
211
- this.pdfUrl + pageIndex + '.pdf',
212
- {
213
- headers: {
214
- "Content-Type": "application/json",
215
- },
216
- }).then(async res => {
217
- if (res.bodyText) {
218
- // 最后返回一个 包含这4个参数的对象
219
- obj = await {
220
- "startPage": pageIndex, // 分片的开始页码
221
- "endPage": pageIndex + 5, // 分片结束页码
222
- "totalPage": this.totalPageCount, // pdf 总页数
223
- "url": res.bodyText // 分片内容下载地址
224
- }
225
- }
226
- if (res.data) {
227
- // 最后返回一个 包含这4个参数的对象
228
- obj = await {
229
- "startPage": pageIndex, // 分片的开始页码
230
- "endPage": pageIndex + 5, // 分片结束页码
231
- "totalPage": this.totalPageCount, // pdf 总页数
232
- "url": res.data // 分片内容下载地址
233
- }
234
- }
235
- })
236
- return obj
237
- },
238
- startRenderPages (pdfPage, page, pageIndex) {
239
- if (Object.keys(this.pageSize).length == 0) {
240
- const viewport = pdfPage.getViewport({
241
- scale: this.scale, // 缩放的比例
242
- rotation: this.rotation, // 旋转的角度
243
- });
244
- // 记录pdf页面高度
245
- const pageSize = {
246
- width: viewport.width,
247
- height: viewport.height,
248
- }
249
- this.pageSize = pageSize
250
- // 创建内容绘制区,并设置大小
251
- if (this.$refs.pdfView.clientWidth / this.pageSize.width >= 1 || this.isMessageRecord) {
252
- this.contentView.style.width = `${pageSize.width - 10}px`;
253
- this.contentView.style.height = `${(this.totalPageCount * (pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
254
- } else {
255
- this.transformSalce = this.$refs.pdfView.clientWidth / this.pageSize.width
256
- this.contentView.style.width = `${pageSize.width * this.transformSalce - 10}px`;
257
- this.contentView.style.height = `${(this.totalPageCount * (pageSize.height * (this.transformSalce) + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
258
- }
259
- this.contentView.style.margin = '0 auto 0'
260
- this.contentView.style.position = 'relative'
261
- this.contentView.style.paddingBottom = '60px'
262
- // contentView.style.overflowY = 'auto'
263
- this.$refs.pdfView.appendChild(this.contentView);
264
- }
265
- this.renderPages(pageIndex)
266
- },
267
- // 渲染需要展示的页面,不需展示的页码将其清除
268
- renderPages (pageIndex) {
269
- const pagesToRender = this.getRenderScope(pageIndex);
270
- for (const i of this.pages) {
271
- if (pagesToRender.some(p => { return p.pageNo == i.pageNo })) {
272
- if (i.loadStatus === true) {
273
- this.renderPageContent(i, i.pageNo)
274
- } else {
275
- this.renderPageLoading(i, i.pageNo)
276
- }
277
- } else {
278
- this.clearPage(i);
279
- }
280
- }
281
-
282
- },
283
- async renderPageContent (page, pageIndex) {
284
- const { pdfPage, pageNo, dom } = page;
285
- // dom 元素已存在,无须重新渲染,直接返回
286
- if ((dom && dom.children.length != 0) || page.loading) {
287
- return;
288
- }
289
- page.loading = true
290
- const viewport = pdfPage.getViewport({
291
- scale: this.scale,
292
- rotation: this.rotation,
293
- });
294
- // 创建新的canvas
295
- const canvas = document.createElement('canvas');
296
- const context = canvas.getContext('2d');
297
- // canvas.getContext('2d');
298
- canvas.height = this.pageSize.height * (this.fileName ? CSS_UNITS : 1);
299
- canvas.width = this.pageSize.width * (this.fileName ? CSS_UNITS : 1);
300
- canvas.style.position = 'relative'
301
- canvas.style.top = -3 + 'px'
302
- // 创建渲染的dom
303
- const pageDom = document.createElement('div');
304
- pageDom.style.position = 'absolute';
305
- pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1)) + this.PAGE_INTVERVAL}px`;
306
- pageDom.style.width = `${this.pageSize.width * (this.fileName ? CSS_UNITS : 1)}px`;
307
- pageDom.style.height = `${this.pageSize.height * (this.fileName ? CSS_UNITS : 1)}px`;
308
- pageDom.setAttribute('data-id', 'page' + pageNo)
309
- // pageDom.appendChild(canvas);
310
- // 渲染内容
311
- let renderContext = {
312
- canvasContext: context,
313
- viewport: viewport,
314
- transform: this.fileName ? [CSS_UNITS, 0, 0, CSS_UNITS, 0, 0] : '',
315
- }
316
- await pdfPage.render(renderContext).promise.then(() => {
317
- const html = canvas.toDataURL();
318
- let image = document.createElement('img');
319
- image.setAttribute('src',html)
320
- pageDom.appendChild(image);
321
- return pdfPage.getTextContent()
322
- }).then(async (textContent) => {
323
- const textLayerDiv = document.createElement('div');
324
- textLayerDiv.setAttribute('class', 'textLayer');
325
- // 将文本图层div添加至每页pdf的div中
326
- // 创建新的TextLayerBuilder实例
327
- let textLayer = new TextLayerBuilder({
328
- textLayerDiv: textLayerDiv,
329
- pageIndex: pdfPage._pageIndex,
330
- viewport: viewport,
331
- });
332
- let findPage = this.currentPageAllLine.find(l => { return l.page == pageIndex })
333
- let rectdomTop = 0
334
- if (findPage) {
335
- let AllLines = findPage.allLines
336
- // setTimeout(() => {
337
- if (AllLines.length > 0) {
338
- for (let j = 0; j < AllLines.length; j++) {
339
- let lines = AllLines[j].lines
340
- let rectdom = document.createElement('div')
341
- rectdom.setAttribute('react-count', AllLines[j].pageCount);
342
- rectdom.style.position = 'absolute';
343
- rectdom.style.top = 0
344
- rectdom.style.left = 0
345
- rectdom.classList.add('rectdom')
346
- for (let index = 0; index < lines.length; index++) {
347
- if (!/^\s+$/g.test(lines[index].content)) {
348
- let postionArr = lines[index].location
349
- let div = document.createElement('div')
350
- div.style.position = 'absolute';
351
- div.style.left = postionArr[0] * this.scale * (this.fileName ? CSS_UNITS : 1) + 'px',
352
- // 后端返回的坐标有基线对齐的问题,top 值是后端算好(基线top - 文字高度),在此加上文字高度的 1/9 (大致比例)为实际展示出文字的top值
353
- div.style.top = postionArr[1] * this.scale * (this.fileName ? CSS_UNITS : 1) + 'px'
354
- div.style.height = postionArr[3] * this.scale * (this.fileName ? CSS_UNITS : 1) + 'px';
355
- div.style.width = postionArr[2] * this.scale * (this.fileName ? CSS_UNITS : 1) + 'px'
356
- div.style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
357
- div.classList.add('lineHeight')
358
- rectdom.appendChild(div)
359
- if (index == 0 && j == 0) {
360
- if (this.transformSalce !== null) {
361
- rectdomTop = postionArr[1]* this.scale * (this.fileName ? CSS_UNITS : 1) * this.transformSalce
362
- } else {
363
- rectdomTop = postionArr[1] * this.scale * (this.fileName ? CSS_UNITS : 1) * this.defaultTransform
364
- }
365
- // if(this.isPC) {
366
- // rectdomTop = rectdomTop - 50 < 0 ? 0 : rectdomTop - 50
367
- // }
368
- }
369
- }
370
- }
371
- if (rectdom.children.length > 0) {
372
- pageDom.appendChild(rectdom)
373
- }
374
- }
375
- }
376
- }
377
- textLayer.setTextContent(textContent);
378
- textLayer.render()
379
- pageDom.appendChild(textLayerDiv);
380
- let backgroundDom = document.getElementById('backgroundLoad' + pageNo)
381
- if (backgroundDom) {
382
- this.contentView.removeChild(backgroundDom);
383
- }
384
- page.dom = await pageDom;
385
- page.loading = false
386
- this.contentView.appendChild(pageDom);
387
- let pdf_view = document.getElementsByClassName('pdf_view');
388
- if (pdf_view && pdf_view[0]){
389
- pdf_view[0].style.backgroundImage = 'none'
390
- }
391
- let postionArr = []
392
- if (findPage){
393
- let AllLines = findPage.allLines
394
- if (AllLines.length){
395
- postionArr = AllLines[0].lines[0].location
396
- }
397
- }
398
- if(this.transformSalce !== null && this.fileName) {
399
- this.contentView.style.transform = `scale(${this.transformSalce}, ${this.transformSalce})`
400
- if (postionArr.length){
401
- // document.getElementById('pdf_container_view').scrollLeft = (document.getElementById('pdf_container_view').scrollWidth - document.getElementById('pdf_container_view').clientWidth) / 2
402
- // this.contentView.style.left = (postionArr[0] * this.scale * CSS_UNITS * (this.transformSalce) * -1) + 10 + 'px';
403
- }
404
- } else {
405
- this.contentView.style.transform = `scale(${this.defaultTransform})`;
406
- if (postionArr.length){
407
- // this.contentView.style.left = (postionArr[0] * this.scale * CSS_UNITS * (this.defaultTransform) * -1) / 2 + 'px';
408
- }
409
- }
410
- if (this.changetoolbar) {
411
- setTimeout(() => {
412
- this.renderHighlights()
413
- this.changetoolbar = false
414
- }, 500)
415
- }
416
- if (this.fisrtLoad) {
417
- setTimeout(() => {
418
- let pageoffsetHeight = 0
419
- if (this.transformSalce !== null) {
420
- pageoffsetHeight = (this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce * (this.fileName ? CSS_UNITS : 1)
421
- } else {
422
- pageoffsetHeight = (this.pageSize.height + this.PAGE_INTVERVAL) * this.defaultTransform *(this.fileName ? CSS_UNITS : 1)
423
- }
424
- if (this.$refs.pdfView.clientHeight - pageoffsetHeight > 0 && pageIndex == 1) {
425
- const height = this.$refs.pdfView.clientHeight;
426
- let startNum = 0
427
- let endNum = 0
428
- if (this.transformSalce !== null) {
429
- startNum = Math.ceil(this.$refs.pdfView.scrollTop / ((this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce* (this.fileName ? CSS_UNITS : 1)))
430
- endNum = startNum + Math.ceil(height / ((this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce* (this.fileName ? CSS_UNITS : 1)))
431
- } else {
432
- startNum = Math.ceil(this.$refs.pdfView.scrollTop / ((this.pageSize.height + this.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1) * this.defaultTransform))
433
- endNum = startNum + Math.ceil(height / ((this.pageSize.height + this.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1) * this.defaultTransform))}
434
- console.log(this.$refs.pdfView.scrollTop, startNum, endNum, 'endNumendNum');
435
- for (let pageIndex = startNum; pageIndex <= endNum; pageIndex++) {
436
- if (pageIndex > 0 && pageIndex <= this.pages.length) {
437
- this.loadPdfData(pageIndex)
438
- }
439
- }
440
- }
441
- if (this.$refs.pdfView.scrollTop == Math.floor((pageNo - 1) * pageoffsetHeight)) {
442
- this.$refs.pdfView.scrollTop = rectdomTop
443
- this.fisrtLoad = false
444
- } else {
445
- this.$refs.pdfView.scrollTop = `${((pageNo - 1) * pageoffsetHeight) + rectdomTop - this.PAGE_INTVERVAL}`
446
- this.fisrtLoad = false
447
- }
448
- this.renderHighlights()
449
- // zoomElement(this.contentView)
450
- }, 100)
451
- }
452
- })
453
- },
454
- // 监听容器的滚动事件,触发 scrollPdf 方法
455
- // 这里加了防抖保证不会一次产生过多请求
456
- debounceScrollPdf: _.debounce(function (e, that) {
457
- if (this.fisrtLoad) {
458
- this.fisrtLoad = false
459
- return
460
- }
461
- const scrollTop = e.target.scrollTop;
462
- const height = e.target.clientHeight;
463
- let startNum = 0
464
- let endNum = 0
465
- if (this.transformSalce !== null) {
466
- startNum = Math.ceil(scrollTop / ((that.pageSize.height + that.PAGE_INTVERVAL) * this.transformSalce * (this.fileName ? CSS_UNITS : 1)))
467
- endNum = startNum + Math.ceil(height / ((that.pageSize.height + that.PAGE_INTVERVAL) * this.transformSalce * (this.fileName ? CSS_UNITS : 1)))
468
- } else {
469
- startNum = Math.ceil(scrollTop / ((that.pageSize.height + that.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1) * this.defaultTransform))
470
- endNum = startNum + Math.ceil(height / ((that.pageSize.height + that.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1) * this.defaultTransform))
471
- }
472
- for (let pageIndex = startNum; pageIndex < endNum; pageIndex++) {
473
- if (pageIndex > 0 && pageIndex <= that.pages.length) {
474
- that.loadPdfData(pageIndex)
475
- }
476
- }
477
- }, 200),
478
- directScrolling (e, that) {
479
- if (this.fisrtLoad) {
480
- this.fisrtLoad = false
481
- return
482
- }
483
- const scrollTop = e.target.scrollTop;
484
- const height = e.target.clientHeight;
485
- // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
486
- const pageIndex = scrollTop > 0 ?
487
- Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
488
- 1;
489
- this.loadPdfData(pageIndex)
490
- },
491
- pdfScroll (e) {
492
- if (this.preViewType !== 'pdf' || this.isTouchMoved) {
493
- return
494
- }
495
- if (this.scrollLeft != e.target.scrollLeft) {
496
- this.scrollLeft = e.target.scrollLeft
497
- }
498
- if (this.scrollTop != e.target.scrollTop) {
499
- this.scrollTop = e.target.scrollTop
500
- this.debounceScrollPdf(e, this)
501
- }
502
- },
503
- // 分片每次只做一次处理,所以不考虑多片情况
504
- loadBefore (pageIndex) {
505
- this.loadPdfData(pageIndex)
506
- },
507
- loadAfter (pageIndex) {
508
- this.loadPdfData(pageIndex)
509
- },
510
- // 首先我们获取到需要渲染的范围
511
- // 根据当前的可视范围内的页码,我们前后只保留 8 页
512
- getRenderScope (pageIndex) {
513
- const pagesToRender = [];
514
- let i = pageIndex - 1;
515
- let j = pageIndex + 1;
516
- // pageIndex - 1 表示当前页码数 对应的下标位置
517
- pagesToRender.push(this.pages[pageIndex - 1]);
518
- while (pagesToRender.length < 8 && pagesToRender.length < this.pages.length) {
519
- if (i > 0) {
520
- pagesToRender.push(this.pages[i - 1]);
521
- i -= 1;
522
- }
523
- if (pagesToRender.length >= 8) {
524
- break;
525
- }
526
- if (j <= this.pages.length) {
527
- pagesToRender.push(this.pages[j - 1]);
528
- j += 1;
529
- }
530
- }
531
- // for (let index = 0; index < array.length; index++) {
532
- // const element = array[index];
533
-
534
- // }
535
- return pagesToRender;
536
- },
537
-
538
- // 清除页面 dom
539
- clearPage (page) {
540
- if (this.contentView.contains(page.dom) && page.dom) {
541
- this.contentView.removeChild(page.dom);
542
- page.loadStatus = false
543
- page.loading = false
544
- page.dom = undefined;
545
- }
546
- },
547
- // 页面正在下载时渲染loading视图
548
- renderPageLoading (page) {
549
- const { pageNo, dom } = page;
550
- if (dom && dom.children.length != 0) {
551
- return;
552
- }
553
- let backgroundDom = document.getElementById('backgroundLoad' + pageNo)
554
- if (this.contentView.contains(backgroundDom)) {
555
- return
556
- }
557
- const pageDom = document.createElement('div');
558
- pageDom.style.width = `${this.pageSize.width * (this.fileName ? CSS_UNITS : 1)}px`;
559
- pageDom.style.height = `${this.pageSize.height * (this.fileName ? CSS_UNITS : 1)}px`;
560
- pageDom.style.position = 'absolute';
561
- pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL) * (this.fileName ? CSS_UNITS : 1)) + this.PAGE_INTVERVAL
562
- }px`;
563
- pageDom.style.backgroundImage = `url('https://guoranopen-zjk.oss-cn-zhangjiakou.aliyuncs.com/cdn-common/images/loading.gif')`
564
- pageDom.style.backgroundPosition = 'center'
565
- pageDom.style.backgroundRepeat = 'no-repeat'
566
- pageDom.style.backgroundColor = '#FFF'
567
- pageDom.setAttribute('id', 'backgroundLoad' + pageNo)
568
- page.dom = pageDom;
569
- this.contentView.appendChild(pageDom);
570
- },
571
- prev () {
572
- this.currentPage--
573
- if (this.currentPage < 0) {
574
- this.currentPage = 0
575
- if (!this.isPC) {
576
- this.$toast({
577
- message: '当前已经是第一段了',
578
- duration: 2000,
579
- })
580
- return
581
- }
582
- }
583
- if (this.preViewType == 'pdf') {
584
- this.scrollToUplaodePage(this.currentPage)
585
- } else {
586
- this.scrollToExcalTop(this.currentPage)
587
- }
588
- // this.getpdfResloutePage(this.cachePdf[this.currentPage - 1])
589
- },
590
- next () {
591
- this.currentPage++
592
- if (this.currentPage >= this.tagIds.length) {
593
- this.currentPage = this.tagIds.length - 1
594
- if (!this.isPC) {
595
- this.$toast({
596
- message: '当前已经是最后一段了',
597
- duration: 2000,
598
- })
599
- return
600
- }
601
- }
602
- if (this.preViewType == 'pdf') {
603
- this.scrollToUplaodePage(this.currentPage)
604
- } else {
605
- this.scrollToExcalTop(this.currentPage)
606
- }
607
- },
608
- currentChange (value) {
609
- this.currentPage = value - 1
610
- if (this.preViewType == 'pdf') {
611
- this.scrollToUplaodePage(this.currentPage)
612
- } else {
613
- this.scrollToExcalTop(this.currentPage)
614
- }
615
- },
616
- scrollToUplaodePage (currentPage) {
617
- this.changetoolbar = true
618
- if (this.preViewType !== 'pdf') {
619
- return
620
- }
621
-
622
- let pdfResloute = this.cachePdf[currentPage]
623
- this.identifyTextPostion.extractInfo = pdfResloute.extractInfo
624
- this.identifyTextPostion.left = pdfResloute.extractInfo.location[0]
625
- this.identifyTextPostion.top = pdfResloute.extractInfo.location[1]
626
- this.identifyTextPostion.width = pdfResloute.extractInfo.location[2]
627
- this.identifyTextPostion.height = pdfResloute.extractInfo.location[3]
628
- this.identifyTextPostion.page = pdfResloute.page
629
- this.identifyTextPostion.pageHeight = pdfResloute.pageHeight
630
- this.identifyTextPostion.pageWidth = pdfResloute.pageWidth
631
- // 在当前段落在最后一页pdf时,根据计算的高度并不能触发滚动,在此执行重新渲染方法,非次情况会执行两次,待优化
632
- this.$nextTick(() => {
633
- this.renderHighlights()
634
- })
635
- if (this.transformSalce !== null) {
636
- this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce) + (this.identifyTextPostion.top * this.scale * this.transformSalce)}`
637
- } else {
638
- this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + (this.identifyTextPostion.top * this.scale * this.defaultTransform)}`
639
- }
640
- },
641
- scrollToExcalTop (currentPage) {
642
- for (let index = 0; index < this.allTr.length; index++) {
643
- if (index == currentPage) {
644
- Array.from(this.allTr[index].children).forEach(item => {
645
- item.style.background = 'rgba(255, 136, 0, 0.6)'
646
- item.classList.add('animation')
647
- setTimeout(() => {
648
- item.classList.remove('animation')
649
- }, 4000)
650
- })
651
- // getBoundingClientRect().top 当前元素距离屏幕顶部的高度 + 弹窗header 高度
652
- if (!this.isPC) {
653
- let top = this.allTr[index].getBoundingClientRect().top - this.$refs.pdfView.getBoundingClientRect().top
654
- this.$refs.pdfView.scrollTop = top
655
- } else {
656
- let top = this.allTr[index].getBoundingClientRect().top
657
- this.$refs.pdfView.scrollTop = top - 50
658
- }
659
- } else {
660
- Array.from(this.allTr[index].children).forEach(item => {
661
- item.style.background = 'rgba(54, 106, 255, 0.6)'
662
- item.classList.remove('animation')
663
- })
664
- }
665
- }
666
- },
667
- // pdf是否需要重新渲染高亮位置
668
- renderHighlights () {
669
- let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
670
- if (lineHeightDom) {
671
- lineHeightDom.forEach((d) => {
672
- for (let i = 0; i < d.children.length; i++) {
673
- if (d.getAttribute('react-count') == this.currentPage) {
674
- d.children[i].style.backgroundColor = 'rgba(255, 136, 0, 0.3)'
675
- d.children[i].classList.add('animation')
676
- setTimeout(() => {
677
- d.children[i].classList.remove('animation')
678
- }, 4000)
679
- } else {
680
- d.children[i].style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
681
- d.children[i].classList.remove('animation')
682
- }
683
- }
684
- })
685
- }
686
- },
687
- displayHiglight (pageIndex) {
688
- let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
689
- if (lineHeightDom) {
690
- lineHeightDom.forEach((d) => {
691
- if (d.getAttribute('page-index') == pageIndex) {
692
- d.style.display = 'none'
693
- }
694
- })
695
- }
696
- },
697
- // 前端暂时缓存多页
698
- autoLoadMore (pageIndex) {
699
- let pdfResloute = this.cachePdf.find(cache => {
700
- return cache.page == pageIndex
701
- })
702
- if (pdfResloute) {
703
- this.getpdfResloutePage(pdfResloute)
704
- } else {
705
- this.loadPdfData(pageIndex)
706
- }
707
- },
708
- setPageAllLine (arr) {
709
- this.currentPageAllLine = []
710
- arr.forEach((item, index) => {
711
- let i = this.currentPageAllLine.findIndex(l => { return l.page && l.page == item.page })
712
- if (i != -1) {
713
- // this.currentPageAllLine[i].allLines.lines.push(item.extractInfo.lines)
714
- this.currentPageAllLine[i].allLines.push({
715
- pageCount: index,
716
- lines: item.extractInfo.lines
717
- })
718
- } else {
719
- this.currentPageAllLine.push({
720
- page: item.page,
721
- allLines: [{
722
- pageCount: index,
723
- lines: item.extractInfo.lines
724
- }],
725
- })
726
- }
727
- })
728
- },
729
- openTouch () {
730
- // this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行
731
- let that = this;
732
- this.$nextTick(() => {
733
- // setInterval(() => {
734
- // this.scale = this.scale + 0.1
735
- // that.pages.forEach((item, index) =>{
736
- // if(item.dom) {
737
- // item.dom.children.forEach( childDom =>{
738
- // if(childDom.getAttribute('react-count')) {
739
- // childDom.style.transform = "scale(" + this.scale + ")";
740
- // childDom.style.transformOrigin = "0px 0px 0px";
741
- // } else {
742
- // item.dom = null
743
- // this.startRenderPages(item.pdfPage, null, index)
744
- // }
745
- // } )
746
- // }
747
- // })
748
- // }, 100);
749
- // 获取放大或缩小的区域DOM
750
- let matrix_box = this.contentView
751
- matrix_box.addEventListener("touchstart", function (event) {
752
- this.isTouchMoved = true
753
- let touches = event.touches;
754
- let events = touches[0];
755
- let events2 = touches[1];
756
-
757
- // event.preventDefault();
758
-
759
- // 第一个触摸点的坐标
760
- that.displacement.pageX = events.pageX;
761
- that.displacement.pageY = events.pageY;
762
-
763
- that.displacement.moveable = true;
764
-
765
- if (events2) {
766
- that.displacement.pageX2 = events2.pageX;
767
- that.displacement.pageY2 = events2.pageY;
768
- }
769
-
770
- that.displacement.originScale = this.scale || 1;
771
- });
772
- document.addEventListener("touchmove", function (event) {
773
- if (!that.displacement.moveable) {
774
- return;
775
- }
776
- // event.preventDefault();
777
- let touches = event.touches;
778
- let events = touches[0];
779
- let events2 = touches[1];
780
- // 双指移动
781
- if (events2) {
782
- // 第2个指头坐标在touchmove时候获取
783
- if (!that.displacement.pageX2) {
784
- that.displacement.pageX2 = events2.pageX;
785
- }
786
- if (!that.displacement.pageY2) {
787
- that.displacement.pageY2 = events2.pageY;
788
- }
789
- // 双指缩放比例计算
790
- let zoom = that.getDistance({
791
- x: events.pageX,
792
- y: events.pageY
793
- },
794
- {
795
- x: events2.pageX,
796
- y: events2.pageY
797
- }
798
- ) / that.getDistance(
799
- {
800
- x: that.displacement.pageX,
801
- y: that.displacement.pageY
802
- },
803
- {
804
- x: that.displacement.pageX2,
805
- y: that.displacement.pageY2
806
- }
807
- );
808
- // 应用在元素上的缩放比例
809
- let newScale = that.displacement.originScale * zoom;
810
- // 最大缩放比例限制
811
- if (newScale > 2) {
812
- newScale = 2;
813
- }
814
- // 最大缩放比例限制
815
- if (newScale < 1) {
816
- newScale = 1;
817
- }
818
- // 记住使用的缩放值
819
- that.displacement.scale = newScale;
820
- // console.log(newScale);
821
- matrix_box.style.transform = "scale(" + newScale + ")";
822
- // 设置旋转元素的基点位置
823
- matrix_box.style.transformOrigin = "0px 0px 0px";
824
- }
825
- }, { passive: false });
826
- document.addEventListener('touchend', function () {
827
- that.isTouchMoved = false
828
- }, { passive: false })
829
- });
830
- },
831
- getDistance (start, stop) {
832
- // Math.hypot()计算参数的平方根
833
- return Math.hypot(stop.x - start.x, stop.y - start.y);
834
- },
835
- setupCanvas (canvas, width, height) {
836
- const dpr = 1;
837
- // const rect = canvas.getBoundingClientRect();
838
- canvas.width = width
839
- canvas.height = height
840
- const ctx = canvas.getContext('2d');
841
- ctx?.scale(dpr, dpr);
842
- return ctx;
843
- },
844
- changeScale (value) {
845
- if (value == 'zoom') {
846
- this.handScale = 'auto'
847
- this.transformSalce = (this.transformSalce + 0.2).toFixed(1)
848
- } else if (value == 'reduce') {
849
- if ((this.transformSalce - 0.2).toFixed(1) <= 0) {
850
- return
851
- }
852
- this.handScale = 'auto'
853
- this.transformSalce = (this.transformSalce - 0.2).toFixed(1)
854
- } else if (value == 'auto') {
855
- this.transformSalce = this.$refs.pdfView.clientWidth / this.pageSize.width
856
- } else if (value == 'reality') {
857
- this.transformSalce = 0.5
858
- } else {
859
- this.transformSalce = (value / 2).toFixed(1)
860
- }
861
- this.transformSalce = Number(this.transformSalce)
862
- this.contentView.style.transform = 'scale(' + this.transformSalce + ')';
863
- // this.getpdfResloutePage(this.cachePdf[0])
864
- },
865
- },
866
- computed: {
867
- perviewUrl () {
868
- return '/web/viewer.html?file=' + '/pdflist/pdf4split-1.pdf'
869
- },
870
- setHeight () {
871
- if (this.tagIds.length > 1) {
872
- if (this.isPC) {
873
- return 'calc(100% - 110px)'
874
- } else {
875
- return 'calc(100% - 60px)'
876
- }
877
- } else {
878
- if (this.isPC) {
879
- return 'calc(100% - 50px)'
880
- } else {
881
- return '100%'
882
- }
883
- }
884
- }
885
- },
886
- watch: {
887
- tagIds: {
888
- handler (value) {
889
- if (value && value.length) {
890
- // 在 pdf_view 下创建 所有canvs的容器
891
- this.contentView = document.createElement('div')
892
- this.contentView.setAttribute('id','contentView')
893
- this.contentView.style.transformOrigin = '0px 0px 0px'
894
- this.$http.get('/knowledge-api/knowledge/knowledge-part-location-info/list?ids=' + value.join(',')).then(res => {
895
- // res.data = {"data":[{"id":"64591b7d8bb8ab1b91c65f24","knowledgeId":"64591a9c8da27649473f3b4b","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":3,"total":18,"pageHeight":540.0,"pageWidth":960.00946,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/11/55/18/64591b638bb8ab1b91c65eed/3.pdf","extractInfo":{"location":[280.488,161.32,398.71573,61.99298],"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距北京市区65公里,是以奇而著称,融山川、碧水、古长城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","lines":[{"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距","location":[280.488,161.32,398.71573,15.9869995]},{"content":"北京市区65公里,是以奇而著称,融山川、碧水、古长","location":[283.691,184.30899,392.3055,15.9869995]},{"content":"城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","location":[282.699,207.32599,394.3033,15.9869995]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
896
- // res.data = {"data":[{"id":"64590ce1eb1320043401cc90","knowledgeId":"64590cd5017b461d67e282e1","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":2,"total":5,"pageHeight":841.8898,"pageWidth":595.30396,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/10/53/20/64590ce0eb1320043401cc7b/2.pdf","extractInfo":{"location":[89.32981,638.1907,415.15512,98.63251],"content":":北京地铁 13\r号线 :藤黄\r色 :西直门站—\r东直门站 :17 :41.\r5 :6\r准\rB :2002年\r09月\r28日 ","lines":[{"content":":北京地铁 13\r号线 ","location":[89.32981,638.1907,99.44599,98.63251]},{"content":":藤黄\r色 ","location":[188.7758,638.1907,46.79959,98.63251]},{"content":":西直门站—\r东直门站 ","location":[235.5754,638.1907,86.09996,98.63251]},{"content":":17 ","location":[321.67535,638.1907,36.200012,98.63251]},{"content":":41.\r5 ","location":[357.87537,638.1907,39.400696,98.63251]},{"content":":6\r准\rB ","location":[397.27606,638.1907,41.099,98.63251]},{"content":":2002年\r09月\r28日 ","location":[438.37506,638.1907,66.10986,98.63251]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
897
- // res.data = {"data":[{"id":"64591b7d8bb8ab1b91c65f24","knowledgeId":"64591a9c8da27649473f3b4b","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":3,"total":18,"pageHeight":540.0,"pageWidth":960.00946,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/11/55/18/64591b638bb8ab1b91c65eed/3.pdf","extractInfo":{"location":[280.488,161.32,398.71573,61.99298],"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距北京市区65公里,是以奇而著称,融山川、碧水、古长城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","lines":[{"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距","location":[280.488,161.32,398.71573,15.9869995]},{"content":"北京市区65公里,是以奇而著称,融山川、碧水、古长","location":[283.691,184.30899,392.3055,15.9869995]},{"content":"城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","location":[282.699,207.32599,394.3033,15.9869995]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
898
- // res.data = {"data":[{"id":"6475eab868110215ab821a80","knowledgeId":"6475e7eac724c54c46cbfa2d","mainId":"5ecf2fcd704541149201ab9c1c31162d","page":0,"total":1,"pageHeight":0.0,"pageWidth":0.0,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/5ecf2fcd704541149201ab9c1c31162d/2023/05/30/08/23/20/6475eab63339db423f26b196/0.html","extractInfo":{"location":null,"content":"产品:系统配置,产品型号:存储,VX30:4G+16G,VX50:16G+256G","lines":null,"tagId":"6475eab868110215ab821a80"}}],"code":"0","msg":null,"traceId":null}
899
- // res.data = {"data":[{"id":"6475e9393339db423f26af01","knowledgeId":"6475e44fc724c54c46cbfa21","mainId":"5ecf2fcd704541149201ab9c1c31162d","page":2,"total":2,"pageHeight":510.25,"pageWidth":1559.05,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/5ecf2fcd704541149201ab9c1c31162d/2023/05/30/08/00/29/6475e55d3339db423f26a9b8/2.pdf","extractInfo":{"location":[327.70532,288.0498,414.9734,12.241608],"content":"三、指示灯状态说明1.白色常亮:开机/开机中2.红色常亮:待机3.白色呼吸:息屏4.红色闪烁:升级1.LAN:通过网线连接到主机的Camera端口2.电源开关:电源切换开关","lines":[{"content":"三、指示灯状态说明","location":[634.3203,288.0498,108.3584,12.0]},{"content":"1.白色常亮:开机/开机中","location":[634.3203,320.08978,108.23407,9.0]},{"content":"2.红色常亮:待机","location":[634.3204,341.3298,78.597046,9.0]},{"content":"3.白色呼吸:息屏","location":[634.32043,362.45282,78.597046,9.0]},{"content":"4.红色闪烁:升级","location":[634.3205,383.6928,78.597046,9.0]},{"content":"1.LAN:通过网线连接到主机的","location":[327.70535,291.2914,144.35995,9.0]},{"content":"Camera端口","location":[327.70532,306.88843,55.322998,9.0]},{"content":"2.电源开关:电源切换开关","location":[482.74832,291.2914,105.36301,9.0]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
900
- // if(value.length === 1) {
901
- // this.$refs.pdfView.style.height = 'calc(100% - 50px)'
902
- // }
903
- // res.data = {
904
- // "data": [
905
- // {
906
- // "id": "64e746120372d778849d2e8e",
907
- // "knowledgeId": "64e30035edffac0ec96a2d39",
908
- // "mainId": "e0f6898c6b0d47fa98e8f71ceab1bde8",
909
- // "page": 14,
910
- // "total": 60,
911
- // "pageHeight": 728.504,
912
- // "pageWidth": 515.906,
913
- // "publicPageFileUrl": "https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/e0f6898c6b0d47fa98e8f71ceab1bde8/2023/08/21/02/12/07/64e300378c3dfb3bc434f51a/15.pdf",
914
- // "extractInfo": {
915
- // "location": [
916
- // 52.665375,
917
- // 312.01306,
918
- // 404.98618,
919
- // 142.5199
920
- // ],
921
- // "content": null,
922
- // "lines": [
923
- // {
924
- // "content": null,
925
- // "location": [
926
- // 52.665375,
927
- // 312.01306,
928
- // 404.98618,
929
- // 142.5199
930
- // ]
931
- // }
932
- // ],
933
- // "tagId": null
934
- // },
935
- // "block": {
936
- // "type": "TEXT",
937
- // "location": [
938
- // 52.665375,
939
- // 312.01306,
940
- // 404.98618,
941
- // 142.5199
942
- // ],
943
- // "color": "#366AFF",
944
- // "flowChart": {
945
- // "content": ""
946
- // },
947
- // "image": {
948
- // "url": null,
949
- // "desc": ""
950
- // },
951
- // "table": {
952
- // "title": null,
953
- // "table": null
954
- // },
955
- // "text": {
956
- // "originText": "① 头部防护:安全帽\n佩戴要求:\n①存在坠物或对头部产生碰撞风险的作业场所需要佩戴安全帽 ;\n②安全帽必须戴正、戴牢、不能晃动,要系紧下颏带,调节好后箍以\n防安全帽脱落 ;\n③受强力撞击及超过有效期的安全帽必须更换。",
957
- // "indexText": "① 头部防护:安全帽\n佩戴要求:\n①存在坠物或对头部产生碰撞风险的作业场所需要佩戴安全帽 ;\n②安全帽必须戴正、戴牢、不能晃动,要系紧下颏带,调节好后箍以\n防安全帽脱落 ;\n③受强力撞击及超过有效期的安全帽必须更换。",
958
- // "lines": [
959
- // {
960
- // "location": [
961
- // 69.08148,
962
- // 368.92072,
963
- // 65.90851,
964
- // 10.5
965
- // ]
966
- // },
967
- // {
968
- // "location": [
969
- // 86.290985,
970
- // 384.67072,
971
- // 31.5,
972
- // 10.5
973
- // ]
974
- // },
975
- // {
976
- // "location": [
977
- // 286.2992,
978
- // 315.73584,
979
- // 37.656006,
980
- // 12.0
981
- // ]
982
- // },
983
- // {
984
- // "location": [
985
- // 324.6939,
986
- // 316.79932,
987
- // 122.74487,
988
- // 10.5
989
- // ]
990
- // },
991
- // {
992
- // "location": [
993
- // 286.2954,
994
- // 336.0458,
995
- // 149.625,
996
- // 10.5
997
- // ]
998
- // },
999
- // {
1000
- // "location": [
1001
- // 286.2954,
1002
- // 356.0483,
1003
- // 161.15405,
1004
- // 10.5
1005
- // ]
1006
- // },
1007
- // {
1008
- // "location": [
1009
- // 286.2954,
1010
- // 376.0508,
1011
- // 161.15405,
1012
- // 10.5
1013
- // ]
1014
- // },
1015
- // {
1016
- // "location": [
1017
- // 286.2954,
1018
- // 396.0533,
1019
- // 76.125,
1020
- // 10.5
1021
- // ]
1022
- // },
1023
- // {
1024
- // "location": [
1025
- // 286.2954,
1026
- // 416.05582,
1027
- // 161.17517,
1028
- // 10.5
1029
- // ]
1030
- // },
1031
- // {
1032
- // "location": [
1033
- // 286.2954,
1034
- // 436.8038,
1035
- // 52.5,
1036
- // 10.5
1037
- // ]
1038
- // },
1039
- // {
1040
- // "location": [
1041
- // 338.7992,
1042
- // 435.73584,
1043
- // 12.0,
1044
- // 12.0
1045
- // ]
1046
- // }
1047
- // ]
1048
- // }
1049
- // }
1050
- // }
1051
- // ],
1052
- // "code": "0",
1053
- // "msg": null,
1054
- // "traceId": null
1055
- // }
1056
- if (res.data.code == 0) {
1057
- // tagIds 会按照gpt识别的生成有序的数组,前端直接按照下标的顺序取就可以了
1058
- // 缓存拿到的所有数据
1059
- this.cachePdf = res.data.data
1060
- let publicPageFileUrl = res.data.data[0].publicPageFileUrl
1061
- this.currentPage = 0
1062
- if (publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')) === '.pdf') {
1063
- this.preViewType = 'pdf'
1064
- this.setPageAllLine(this.cachePdf)
1065
- this.getpdfResloutePage(res.data.data[0])
1066
- } else {
1067
- this.preViewType = 'excal'
1068
- this.$http.post(
1069
- '/knowledge-api/temporary-certificate/or-origin?expired=30',
1070
- publicPageFileUrl,
1071
- {
1072
- headers: {
1073
- "Content-Type": "application/json",
1074
- },
1075
- }).then(res => {
1076
- // 使用原声请求方式 axios会带有不需要的请求头
1077
- let xhr = new XMLHttpRequest();
1078
- xhr.open('GET', res.data || res.bodyText, true);
1079
- // 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
1080
- xhr.onload = ({ currentTarget }) => {
1081
- // 请求完成
1082
- if (currentTarget.status === 200) { // 返回200
1083
- let pdf_view = document.getElementsByClassName('pdf_view');
1084
- if (pdf_view && pdf_view[0]){
1085
- pdf_view[0].style.backgroundImage = 'none'
1086
- }
1087
- this.contentView.innerHTML = currentTarget.response
1088
- this.contentView.style.padding = '10px'
1089
- // this.contentView.style.position = 'relative'
1090
- this.$refs.pdfView.style.backgroundColor = '#FFFFFF'
1091
- this.$refs.pdfView.appendChild(this.contentView)
1092
-
1093
- let allTr = Array.from(this.$refs.pdfView.getElementsByTagName('tr'))
1094
- this.allTr = []
1095
- for (let index = 0; index < allTr.length; index++) {
1096
- if (value.includes(allTr[index].getAttribute('tag-id'))) {
1097
- this.allTr.push(allTr[index])
1098
- }
1099
- }
1100
- this.currentChange(1)
1101
-
1102
- }
1103
- }
1104
- xhr.send();
1105
- })
1106
- }
1107
- } else {
1108
- let div = document.createElement('div')
1109
- div.innerText = '文件加载异常'
1110
- this.contentView.appendChild(div)
1111
- this.$refs.pdfView.appendChild(this.contentView)
1112
- }
1113
- })
1114
- }
1115
- },
1116
- deep: true,
1117
- immediate: true
1118
- }
1119
- },
1120
- mounted () {
1121
- if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
1122
- this.isPC = false
1123
- } else {
1124
- this.isPC = true
1125
- }
1126
- }
1127
- }
1128
- </script>
1129
-
1130
- <style lang="less" scoped>
1131
- .pdf_view {
1132
- width: 100%;
1133
- height: calc(100% - 110px);
1134
- overflow: auto;
1135
- //overflow-y: scroll;
1136
- background-color: #f5f7fb;
1137
- // margin-bottom: 60px;
1138
- box-sizing: border-box;
1139
- background-image: url('https://guoranopen-zjk.oss-cn-zhangjiakou.aliyuncs.com/cdn-common/images/loading.gif');
1140
- background-position: center;
1141
- background-size: 50px;
1142
- background-repeat: no-repeat;
1143
- // position: relative;
1144
- // > div {
1145
- // width: 100%;
1146
- // height: 100%;
1147
- // overflow: hidden;
1148
- // overflow-y: auto;
1149
- // position: relative;
1150
- // }
1151
- >iframe {
1152
- width: 100%;
1153
- height: 100%;
1154
- }
1155
-
1156
- a:link {
1157
- color: none;
1158
- }
1159
-
1160
- a:visited {
1161
- color: none;
1162
- }
1163
-
1164
- a:hover {
1165
- color: none;
1166
- }
1167
-
1168
- a:active {
1169
- color: none;
1170
- }
1171
- .btn_footer {
1172
- width: 100%;
1173
- height: 60px;
1174
- display: flex;
1175
- align-items: center;
1176
- justify-content: space-around;
1177
- position: absolute;
1178
- bottom: 0px;
1179
- left: 0;
1180
- z-index: 999;
1181
- background: #ffffff;
1182
-
1183
- .prev,
1184
- .next {
1185
- width: 35%;
1186
- height: 40px;
1187
- display: flex;
1188
- align-items: center;
1189
- justify-content: center;
1190
- border-radius: 50px;
1191
- cursor: pointer;
1192
- }
1193
-
1194
- .prev {
1195
- background: #F2F5FA;
1196
- color: #000;
1197
- }
1198
-
1199
- .next {
1200
- background: #366aff;
1201
- color: #ffffff;
1202
- }
1203
- }
1204
-
1205
- #pagination {
1206
- .total-class {
1207
- margin-right: 13px;
1208
- font-weight: 400;
1209
- }
1210
-
1211
- position: absolute;
1212
- bottom: 0px;
1213
- right: 0;
1214
- width: 100%;
1215
- display: flex;
1216
- align-items: center;
1217
- justify-content: center;
1218
- height: 50px;
1219
- background-color: white;
1220
- box-shadow: 0px 0px 18px 0px rgba(29, 55, 129, 0.07);
1221
- border-radius: 5px;
1222
- z-index: 1000;
1223
-
1224
-
1225
-
1226
- /deep/.el-pagination {
1227
- margin-right: 110px;
1228
- }
1229
-
1230
- /deep/.el-pager {
1231
- background: #EDF0F6;
1232
- border-radius: 15px;
1233
- }
1234
-
1235
- /deep/.el-pagination.is-background .btn-next {
1236
- width: 30px;
1237
- height: 30px;
1238
- background: #EDF0F6;
1239
- border-radius: 50%;
1240
- }
1241
-
1242
- /deep/.el-pagination .btn-next {
1243
- width: 30px;
1244
- height: 30px;
1245
- background: #EDF0F6;
1246
- border-radius: 50%;
1247
- padding-left: 0;
1248
- margin-left: 5px;
1249
- }
1250
-
1251
- /deep/.el-pagination .btn-prev {
1252
- width: 30px;
1253
- height: 30px;
1254
- background: #EDF0F6;
1255
- border-radius: 50%;
1256
- padding-right: 0;
1257
- margin-right: 5px;
1258
- }
1259
-
1260
- /deep/.el-pagination button {
1261
- padding: 0;
1262
- min-width: 30px;
1263
- }
1264
-
1265
- /deep/.el-pager li {
1266
- background: #EDF0F6;
1267
- height: 30px;
1268
- min-width: 30px;
1269
- line-height: 30px;
1270
- font-size: 12px;
1271
- color: #717b90;
1272
- }
1273
-
1274
- /deep/.el-pager li:first-child {
1275
- border-bottom-left-radius: 15px !important;
1276
- border-top-left-radius: 15px !important;
1277
- }
1278
-
1279
- /deep/.el-pager li:last-child {
1280
- border-top-right-radius: 15px !important;
1281
- border-bottom-right-radius: 15px !important;
1282
- }
1283
-
1284
- /deep/.el-pager li.active {
1285
- width: 30px;
1286
- height: 30px;
1287
- min-width: 30px;
1288
- background: #366AFF;
1289
- border: 3px solid #A1B9FF;
1290
- border-radius: 50%;
1291
- line-height: 24px;
1292
- color: white;
1293
- }
1294
-
1295
- /deep/.el-pagination.is-background .el-pager li:not(.disabled).active {
1296
- background: #366AFF;
1297
- }
1298
- }
1299
-
1300
- .change_scale {
1301
- width: 100%;
1302
- height: 50px;
1303
- position: absolute;
1304
- top: 50px;
1305
- left: 0;
1306
- background: #ffffff;
1307
- display: flex;
1308
- align-items: center;
1309
- padding: 0 10px;
1310
- box-sizing: border-box;
1311
-
1312
- section {
1313
- cursor: pointer;
1314
- width: 30px;
1315
- height: 30px;
1316
- margin-right: 5px;
1317
- border-radius: 5px;
1318
- display: flex;
1319
- align-items: center;
1320
- justify-content: center;
1321
-
1322
- i {
1323
- font-weight: 900;
1324
- }
1325
- }
1326
-
1327
- section:hover {
1328
- background: rgba(221, 222, 223, 1);
1329
- }
1330
- }
1331
- .pdf_container_view{
1332
- height: 100%;
1333
- width: 100%;
1334
- position: relative;
1335
- overflow: auto;
1336
- }
1337
- }
1338
- </style>
1339
- <style lang="less">
1340
- .animation {
1341
- animation-name: highlight;
1342
- animation-duration: 4s;
1343
- }
1344
-
1345
- @keyframes highlight {
1346
- 0% {
1347
- background: rgba(255, 136, 0, 0.3);
1348
- }
1349
- 25% {
1350
- background: rgba(255, 136, 0, 0.6);
1351
- }
1352
-
1353
- 50% {
1354
- background: rgba(255, 136, 0, 0.3);
1355
- }
1356
-
1357
- 75% {
1358
- background: rgba(255, 136, 0, 0.6);
1359
- }
1360
-
1361
- 100% {
1362
- background: rgba(255, 136, 0, 0.3);
1363
- }
1
+ <template>
2
+ <div class="pdf_view" ref="pdfView" @scroll="pdfScroll" :style="{
3
+ marginTop: isPC ? '50px' : '',
4
+ marginBottom: tagIds.length > 1 ? '60px' : '0px',
5
+ height: setHeight
6
+ }">
7
+ <div class="change_scale" v-if="isPC">
8
+ <section @click="changeScale('reduce')">
9
+ <i class="el-icon-minus"></i>
10
+ </section>
11
+ <el-divider direction="vertical"></el-divider>
12
+ <section @click="changeScale('zoom')">
13
+ <i class="el-icon-plus"></i>
14
+ </section>
15
+ <el-select size="small" v-model="handScale" @change="changeScale" placeholder="请选择">
16
+ <el-option v-for="item in scaleList" :key="item.value" :label="item.label" :value="item.value">
17
+ </el-option>
18
+ </el-select>
19
+ </div>
20
+ <div class="btn_footer" v-if="tagIds.length > 1 && !isPC">
21
+ <div class="prev" @click="prev">上一段</div>
22
+ <div class="next" @click="next">下一段</div>
23
+ </div>
24
+ <div id="pagination" v-if="tagIds.length > 1 && isPC">
25
+ <el-pagination :current-page="currentPage + 1" @current-change="currentChange" @prev-click="prev"
26
+ @next-click="next" layout="slot, prev, pager, next" :page-size="1" :total="tagIds.length">
27
+ <span class="total-class">答案由{{ tagIds.length }}段内容生成</span>
28
+ </el-pagination>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script>
34
+ import _ from 'lodash'
35
+ // import * as pdfjsLib from 'pdfjs-dist'
36
+ // pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker';
37
+ // import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
38
+ // EventBus pdf_viewer 支持绑定自定义事件,一版不做
39
+ // import 'pdfjs-dist/web/pdf_viewer.css'
40
+ /* eslint-disable */
41
+ const pdfjsLib = window['pdfjsLib']
42
+ if (pdfjsLib) {
43
+ pdfjsLib.GlobalWorkerOptions.workerSrc = window['pdfjs-dist/build/pdf.worker']
44
+ // 'pdfjs-dist/build/pdf.worker';
45
+ }
46
+ const { TextLayerBuilder } = window['pdfjs-dist/web/pdf_viewer']
47
+ // import { zoomElement } from '../assets/js/hammer'
48
+ export default {
49
+ name: 'pdfView',
50
+ props: ['tagIds', 'isMessageRecord'],
51
+ data () {
52
+ return {
53
+ url: '',
54
+ pages: [],
55
+ pageLoadStatus: {
56
+ WAIT: 0,
57
+ LOADED: 1,
58
+ },
59
+ scale: 1,
60
+ rotation: 0,
61
+ pageSize: {},
62
+ PAGE_INTVERVAL: 15,
63
+ SLICE_COUNT: 5,
64
+ contentView: null,
65
+ fisrtLoad: true,
66
+ TextLayerBuilder: null,
67
+ totalPageCount: 0,
68
+ identifyTextPostion: {
69
+ top: 0,
70
+ left: 0,
71
+ width: 100,
72
+ height: 0,
73
+ page: 1,
74
+ pageHeight: 0,
75
+ pageWidth: 0,
76
+ extractInfo: {},
77
+ currentPageAllLine: []
78
+ },
79
+ currentPageAllLine: [],
80
+ pdfUrl: '',
81
+ cachePdf: [],
82
+ newViewer: null,
83
+ currentPage: 0,
84
+ changetoolbar: false,
85
+ allTr: [],
86
+ preViewType: 'pdf',
87
+ displacement: {
88
+ pageX: 0,
89
+ pageY: 0,
90
+ moveable: false,
91
+ pageX2: 0,
92
+ pageY2: 0,
93
+ originScale: 1,
94
+ },
95
+ isTouchMoved: false,
96
+ transformSalce: null,
97
+ isPC: false,
98
+ handScale: 'auto',
99
+ scaleList: [
100
+ {
101
+ label: '自动缩放',
102
+ value: 'auto'
103
+ },
104
+ {
105
+ label: '实际比例',
106
+ value: 'reality'
107
+ },
108
+ {
109
+ label: '100%',
110
+ value: 1
111
+ },
112
+ {
113
+ label: '120%',
114
+ value: 1.2
115
+ },
116
+ {
117
+ label: '150%',
118
+ value: 1.5
119
+ },
120
+ {
121
+ label: '170%',
122
+ value: 1.7
123
+ }
124
+ ,
125
+ {
126
+ label: '200%',
127
+ value: 2
128
+ }
129
+ ],
130
+ scrollTop: 0,
131
+ scrollLeft: 0
132
+ }
133
+ },
134
+ methods: {
135
+ getpdfResloutePage (pdfResloute) {
136
+ // 根据当前页面宽度设置缩放比例
137
+ // this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
138
+ if (this.isMessageRecord) {
139
+ this.scale = Math.round(this.$refs.pdfView.clientWidth / pdfResloute.pageWidth * 100) / 100
140
+ } else {
141
+ this.scale = 2
142
+ }
143
+ // 从后端获取到当前分片后所有的pdf页码,初始化数组,数组下{} 对应每页pdf文件
144
+ this.pdfUrl = pdfResloute.publicPageFileUrl.substring(0, pdfResloute.publicPageFileUrl.lastIndexOf('/') + 1)
145
+ this.initPages(pdfResloute.total)
146
+ // 定位功能,加载对应页码位置
147
+ this.loadPdfData(pdfResloute.page)
148
+ },
149
+ async loadPdfData (loadPage) {
150
+ if (this.pages[loadPage - 1] && ((this.pages[loadPage - 1].dom && this.pages[loadPage - 1].dom.children.length > 0) || this.pages[loadPage - 1].loadStatus)) {
151
+ return
152
+ } else {
153
+ if (this.changetoolbar) {
154
+ this.$nextTick(() => {
155
+ this.renderHighlights()
156
+ })
157
+ this.changetoolbar = false
158
+ }
159
+ }
160
+ // 记录开始缓存的状态
161
+ // pdfjsLib.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/legacy/build/pdf.worker.entry.js");
162
+ // 拿到第一个分片
163
+ const { startPage, url } = await this.fetchPdfFragment(loadPage);
164
+ let loadingTask = pdfjsLib.getDocument(url)
165
+ loadingTask.promise.then(async (pdfDoc) => {
166
+ // 将已经下载的分片保存到 pages 数组中
167
+ // for (let i = 0; i < pdfDoc.numPages; i += 1) {
168
+ // const pageIndex = startPage + i;
169
+ // const page = this.pages[pageIndex - 1];
170
+ // // // 不在缓存列表内,重新获取本页pdf
171
+ // // if (page.loadStatus !== this.pageLoadStatus.LOADED) {
172
+
173
+ // // } else {
174
+ // // if (this.changetoolbar) {
175
+ // // this.$nextTick(() => {
176
+ // // this.renderHighlights()
177
+ // // })
178
+ // // this.changetoolbar = false
179
+ // // }
180
+ // // }
181
+ // }
182
+ const page = this.pages[loadPage - 1]
183
+ await pdfDoc.getPage(1).then(async (pdfPage) => {
184
+ this.pages[loadPage - 1].loadStatus = true
185
+ this.pages[loadPage - 1].pdfPage = pdfPage;
186
+ // 通知可以进行渲染了
187
+ await this.startRenderPages(pdfPage, page, loadPage)
188
+ });
189
+ });
190
+ },
191
+ initPages (totalPage) {
192
+ // const pages = [];
193
+ this.totalPageCount = totalPage
194
+ for (let i = 0; i < totalPage; i += 1) {
195
+ this.pages.push({
196
+ pageNo: i + 1,
197
+ loadStatus: false,
198
+ pdfPage: null,
199
+ dom: null
200
+ });
201
+ }
202
+ },
203
+ async fetchPdfFragment (pageIndex) {
204
+ // 置换加签后的文件地址。
205
+ let obj = {}
206
+ await this.$http.post(
207
+ '/knowledge-api/temporary-certificate/or-origin?expired=30',
208
+ this.pdfUrl + pageIndex + '.pdf',
209
+ {
210
+ headers: {
211
+ "Content-Type": "application/json",
212
+ },
213
+ }).then(async res => {
214
+ if (res.bodyText) {
215
+ // 最后返回一个 包含这4个参数的对象
216
+ obj = await {
217
+ "startPage": pageIndex, // 分片的开始页码
218
+ "endPage": pageIndex + 5, // 分片结束页码
219
+ "totalPage": this.totalPageCount, // pdf 总页数
220
+ "url": res.bodyText // 分片内容下载地址
221
+ }
222
+ }
223
+ if (res.data) {
224
+ // 最后返回一个 包含这4个参数的对象
225
+ obj = await {
226
+ "startPage": pageIndex, // 分片的开始页码
227
+ "endPage": pageIndex + 5, // 分片结束页码
228
+ "totalPage": this.totalPageCount, // pdf 总页数
229
+ "url": res.data // 分片内容下载地址
230
+ }
231
+ }
232
+ })
233
+ return obj
234
+ },
235
+ startRenderPages (pdfPage, page, pageIndex) {
236
+ if (Object.keys(this.pageSize).length == 0) {
237
+ const viewport = pdfPage.getViewport({
238
+ scale: this.scale, // 缩放的比例
239
+ rotation: this.rotation, // 旋转的角度
240
+ });
241
+ // 记录pdf页面高度
242
+ const pageSize = {
243
+ width: viewport.width,
244
+ height: viewport.height,
245
+ }
246
+ this.pageSize = pageSize
247
+ // 创建内容绘制区,并设置大小
248
+ if (this.$refs.pdfView.clientWidth / this.pageSize.width >= 1 || this.isMessageRecord) {
249
+ this.contentView.style.width = `${pageSize.width - 10}px`;
250
+ this.contentView.style.height = `${(this.totalPageCount * (pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
251
+ } else {
252
+ this.transformSalce = this.$refs.pdfView.clientWidth / this.pageSize.width
253
+ this.contentView.style.width = `${pageSize.width * this.transformSalce - 10}px`;
254
+ this.contentView.style.height = `${(this.totalPageCount * (pageSize.height * (this.transformSalce) + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
255
+ }
256
+ this.contentView.style.margin = '0 auto 0'
257
+ this.contentView.style.position = 'relative'
258
+ this.contentView.style.paddingBottom = '60px'
259
+ // contentView.style.overflowY = 'auto'
260
+ this.$refs.pdfView.appendChild(this.contentView);
261
+ }
262
+ this.renderPages(pageIndex)
263
+ },
264
+ // 渲染需要展示的页面,不需展示的页码将其清除
265
+ renderPages (pageIndex) {
266
+ const pagesToRender = this.getRenderScope(pageIndex);
267
+ for (const i of this.pages) {
268
+ if (pagesToRender.some(p => { return p.pageNo == i.pageNo })) {
269
+ if (i.loadStatus === true) {
270
+ this.renderPageContent(i, i.pageNo)
271
+ } else {
272
+ this.renderPageLoading(i, i.pageNo)
273
+ }
274
+ } else {
275
+ this.clearPage(i);
276
+ }
277
+ }
278
+
279
+ },
280
+ async renderPageContent (page, pageIndex) {
281
+ const { pdfPage, pageNo, dom } = page;
282
+ // dom 元素已存在,无须重新渲染,直接返回
283
+ if ((dom && dom.children.length != 0) || page.loading) {
284
+ return;
285
+ }
286
+ page.loading = true
287
+ const viewport = pdfPage.getViewport({
288
+ scale: this.scale,
289
+ rotation: this.rotation,
290
+ });
291
+ // 创建新的canvas
292
+ const canvas = document.createElement('canvas');
293
+ const context = canvas.getContext('2d');
294
+ // canvas.getContext('2d');
295
+ canvas.height = this.pageSize.height;
296
+ canvas.width = this.pageSize.width;
297
+ canvas.style.position = 'relative'
298
+ canvas.style.top = -3 + 'px'
299
+ // 创建渲染的dom
300
+ const pageDom = document.createElement('div');
301
+ pageDom.style.position = 'absolute';
302
+ pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL}px`;
303
+ pageDom.style.width = `${this.pageSize.width}px`;
304
+ pageDom.style.height = `${this.pageSize.height}px`;
305
+ pageDom.setAttribute('data-id', 'page' + pageNo)
306
+ pageDom.appendChild(canvas);
307
+ // 渲染内容
308
+ let renderContext = {
309
+ canvasContext: context,
310
+ viewport: viewport,
311
+ }
312
+ await pdfPage.render(renderContext).promise.then(() => {
313
+ return pdfPage.getTextContent()
314
+ }).then(async (textContent) => {
315
+ const textLayerDiv = document.createElement('div');
316
+ textLayerDiv.setAttribute('class', 'textLayer');
317
+ // 将文本图层div添加至每页pdf的div中
318
+ // 创建新的TextLayerBuilder实例
319
+ let textLayer = new TextLayerBuilder({
320
+ textLayerDiv: textLayerDiv,
321
+ pageIndex: pdfPage._pageIndex,
322
+ viewport: viewport,
323
+ });
324
+ let findPage = this.currentPageAllLine.find(l => { return l.page == pageIndex })
325
+ let rectdomTop = 0
326
+ if (findPage) {
327
+ let AllLines = findPage.allLines
328
+ // setTimeout(() => {
329
+ if (AllLines.length > 0) {
330
+ for (let j = 0; j < AllLines.length; j++) {
331
+ let lines = AllLines[j].lines
332
+ let rectdom = document.createElement('div')
333
+ rectdom.setAttribute('react-count', AllLines[j].pageCount);
334
+ rectdom.style.position = 'absolute';
335
+ rectdom.style.top = 0
336
+ rectdom.style.left = 0
337
+ rectdom.classList.add('rectdom')
338
+ for (let index = 0; index < lines.length; index++) {
339
+ if (!/^\s+$/g.test(lines[index].content)) {
340
+ let postionArr = lines[index].location
341
+ let div = document.createElement('div')
342
+ div.style.position = 'absolute';
343
+ div.style.left = postionArr[0] * this.scale + 'px',
344
+ // 后端返回的坐标有基线对齐的问题,top 值是后端算好(基线top - 文字高度),在此加上文字高度的 1/9 (大致比例)为实际展示出文字的top值
345
+ div.style.top = postionArr[1] * this.scale + 'px'
346
+ div.style.height = postionArr[3] * this.scale + 'px';
347
+ div.style.width = postionArr[2] * this.scale + 'px'
348
+ div.style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
349
+ div.classList.add('lineHeight')
350
+ rectdom.appendChild(div)
351
+ if (index == 0 && j == 0) {
352
+ if (this.transformSalce !== null) {
353
+ rectdomTop = postionArr[1] * this.scale * this.transformSalce
354
+ } else {
355
+ rectdomTop = postionArr[1] * this.scale
356
+ }
357
+ // if(this.isPC) {
358
+ // rectdomTop = rectdomTop - 50 < 0 ? 0 : rectdomTop - 50
359
+ // }
360
+ }
361
+ }
362
+ }
363
+ if (rectdom.children.length > 0) {
364
+ pageDom.appendChild(rectdom)
365
+ }
366
+ }
367
+ }
368
+ }
369
+ textLayer.setTextContent(textContent);
370
+ textLayer.render()
371
+ pageDom.appendChild(textLayerDiv);
372
+
373
+ let backgroundDom = document.getElementById('backgroundLoad' + pageNo)
374
+ if (backgroundDom) {
375
+ this.contentView.removeChild(backgroundDom);
376
+ }
377
+ page.dom = await pageDom;
378
+ page.loading = false
379
+ this.contentView.appendChild(pageDom);
380
+ if (this.transformSalce !== null) {
381
+ this.contentView.style.transform = `scale(${this.transformSalce}, ${this.transformSalce})`
382
+ }
383
+ if (this.changetoolbar) {
384
+ setTimeout(() => {
385
+ this.renderHighlights()
386
+ this.changetoolbar = false
387
+ }, 500)
388
+ }
389
+ if (this.fisrtLoad) {
390
+ setTimeout(() => {
391
+ let pageoffsetHeight = 0
392
+ if (this.transformSalce !== null) {
393
+ pageoffsetHeight = (this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce
394
+ } else {
395
+ pageoffsetHeight = (this.pageSize.height + this.PAGE_INTVERVAL)
396
+ }
397
+ if (this.$refs.pdfView.clientHeight - pageoffsetHeight > 0 && pageIndex == 1) {
398
+ const height = this.$refs.pdfView.clientHeight;
399
+ let startNum = 0
400
+ let endNum = 0
401
+ if (this.transformSalce !== null) {
402
+ startNum = Math.ceil(this.$refs.pdfView.scrollTop / ((this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce))
403
+ endNum = startNum + Math.ceil(height / ((this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce))
404
+ } else {
405
+ startNum = Math.ceil(this.$refs.pdfView.scrollTop / (this.pageSize.height + this.PAGE_INTVERVAL))
406
+ endNum = startNum + Math.ceil(height / (this.pageSize.height + this.PAGE_INTVERVAL))
407
+
408
+ }
409
+ for (let pageIndex = startNum; pageIndex <= endNum; pageIndex++) {
410
+ if (pageIndex > 0 && pageIndex <= this.pages.length) {
411
+ this.loadPdfData(pageIndex)
412
+ }
413
+ }
414
+ }
415
+ if (this.$refs.pdfView.scrollTop == Math.floor((pageNo - 1) * pageoffsetHeight)) {
416
+ this.$refs.pdfView.scrollTop = rectdomTop
417
+ this.fisrtLoad = false
418
+ } else {
419
+ this.$refs.pdfView.scrollTop = `${((pageNo - 1) * pageoffsetHeight) + rectdomTop - this.PAGE_INTVERVAL}`
420
+ this.fisrtLoad = false
421
+ }
422
+ this.renderHighlights()
423
+ // zoomElement(this.contentView)
424
+ }, 100)
425
+ }
426
+ })
427
+ },
428
+ // 监听容器的滚动事件,触发 scrollPdf 方法
429
+ // 这里加了防抖保证不会一次产生过多请求
430
+ debounceScrollPdf: _.debounce(function (e, that) {
431
+ if (this.fisrtLoad) {
432
+ this.fisrtLoad = false
433
+ return
434
+ }
435
+ const scrollTop = e.target.scrollTop;
436
+ const height = e.target.clientHeight;
437
+ let startNum = 0
438
+ let endNum = 0
439
+ if (this.transformSalce !== null) {
440
+ startNum = Math.ceil(scrollTop / ((that.pageSize.height + that.PAGE_INTVERVAL) * this.transformSalce))
441
+ endNum = startNum + Math.ceil(height / ((that.pageSize.height + that.PAGE_INTVERVAL) * this.transformSalce))
442
+ } else {
443
+ startNum = Math.ceil(scrollTop / (that.pageSize.height + that.PAGE_INTVERVAL))
444
+ endNum = startNum + Math.ceil(height / (that.pageSize.height + that.PAGE_INTVERVAL))
445
+ }
446
+ for (let pageIndex = startNum; pageIndex < endNum; pageIndex++) {
447
+ if (pageIndex > 0 && pageIndex < that.pages.length) {
448
+ that.loadPdfData(pageIndex)
449
+ }
450
+ }
451
+ }, 200),
452
+ directScrolling (e, that) {
453
+ if (this.fisrtLoad) {
454
+ this.fisrtLoad = false
455
+ return
456
+ }
457
+ const scrollTop = e.target.scrollTop;
458
+ const height = e.target.clientHeight;
459
+ // 根据内容可视区域中心点计算页码, 没有滚动时,指向第一页
460
+ const pageIndex = scrollTop > 0 ?
461
+ Math.ceil((scrollTop + (height / 2)) / (that.pageSize.height + that.PAGE_INTVERVAL)) :
462
+ 1;
463
+ this.loadPdfData(pageIndex)
464
+ },
465
+ pdfScroll (e) {
466
+ if (this.preViewType !== 'pdf' || this.isTouchMoved) {
467
+ return
468
+ }
469
+ if (this.scrollLeft != e.target.scrollLeft) {
470
+ this.scrollLeft = e.target.scrollLeft
471
+ }
472
+ if (this.scrollTop != e.target.scrollTop) {
473
+ this.scrollTop = e.target.scrollTop
474
+ this.debounceScrollPdf(e, this)
475
+ }
476
+ },
477
+ // 分片每次只做一次处理,所以不考虑多片情况
478
+ loadBefore (pageIndex) {
479
+ this.loadPdfData(pageIndex)
480
+ },
481
+ loadAfter (pageIndex) {
482
+ this.loadPdfData(pageIndex)
483
+ },
484
+ // 首先我们获取到需要渲染的范围
485
+ // 根据当前的可视范围内的页码,我们前后只保留 8 页
486
+ getRenderScope (pageIndex) {
487
+ const pagesToRender = [];
488
+ let i = pageIndex - 1;
489
+ let j = pageIndex + 1;
490
+ // pageIndex - 1 表示当前页码数 对应的下标位置
491
+ pagesToRender.push(this.pages[pageIndex - 1]);
492
+ while (pagesToRender.length < 8 && pagesToRender.length < this.pages.length) {
493
+ if (i > 0) {
494
+ pagesToRender.push(this.pages[i - 1]);
495
+ i -= 1;
496
+ }
497
+ if (pagesToRender.length >= 8) {
498
+ break;
499
+ }
500
+ if (j <= this.pages.length) {
501
+ pagesToRender.push(this.pages[j - 1]);
502
+ j += 1;
503
+ }
504
+ }
505
+ // for (let index = 0; index < array.length; index++) {
506
+ // const element = array[index];
507
+
508
+ // }
509
+ return pagesToRender;
510
+ },
511
+
512
+ // 清除页面 dom
513
+ clearPage (page) {
514
+ if (this.contentView.contains(page.dom) && page.dom) {
515
+ this.contentView.removeChild(page.dom);
516
+ page.loadStatus = false
517
+ page.loading = false
518
+ page.dom = undefined;
519
+ }
520
+ },
521
+ // 页面正在下载时渲染loading视图
522
+ renderPageLoading (page) {
523
+ const { pageNo, dom } = page;
524
+ if (dom && dom.children.length != 0) {
525
+ return;
526
+ }
527
+ let backgroundDom = document.getElementById('backgroundLoad' + pageNo)
528
+ if (this.contentView.contains(backgroundDom)) {
529
+ return
530
+ }
531
+ const pageDom = document.createElement('div');
532
+ pageDom.style.width = `${this.pageSize.width}px`;
533
+ pageDom.style.height = `${this.pageSize.height}px`;
534
+ pageDom.style.position = 'absolute';
535
+ pageDom.style.top = `${((pageNo - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + this.PAGE_INTVERVAL
536
+ }px`;
537
+ pageDom.style.backgroundImage = `url('https://guoranopen-zjk.oss-cn-zhangjiakou.aliyuncs.com/cdn-common/images/loading.gif')`
538
+ pageDom.style.backgroundPosition = 'center'
539
+ pageDom.style.backgroundRepeat = 'no-repeat'
540
+ pageDom.style.backgroundColor = '#FFF'
541
+ pageDom.setAttribute('id', 'backgroundLoad' + pageNo)
542
+ page.dom = pageDom;
543
+ this.contentView.appendChild(pageDom);
544
+ },
545
+ prev () {
546
+ this.currentPage--
547
+ if (this.currentPage < 0) {
548
+ this.currentPage = 0
549
+ if (!this.isPC) {
550
+ this.$toast({
551
+ message: '当前已经是第一段了',
552
+ duration: 2000,
553
+ })
554
+ return
555
+ }
556
+ }
557
+ if (this.preViewType == 'pdf') {
558
+ this.scrollToUplaodePage(this.currentPage)
559
+ } else {
560
+ this.scrollToExcalTop(this.currentPage)
561
+ }
562
+ // this.getpdfResloutePage(this.cachePdf[this.currentPage - 1])
563
+ },
564
+ next () {
565
+ this.currentPage++
566
+ if (this.currentPage >= this.tagIds.length) {
567
+ this.currentPage = this.tagIds.length - 1
568
+ if (!this.isPC) {
569
+ this.$toast({
570
+ message: '当前已经是最后一段了',
571
+ duration: 2000,
572
+ })
573
+ return
574
+ }
575
+ }
576
+ if (this.preViewType == 'pdf') {
577
+ this.scrollToUplaodePage(this.currentPage)
578
+ } else {
579
+ this.scrollToExcalTop(this.currentPage)
580
+ }
581
+ },
582
+ currentChange (value) {
583
+ this.currentPage = value - 1
584
+ if (this.preViewType == 'pdf') {
585
+ this.scrollToUplaodePage(this.currentPage)
586
+ } else {
587
+ this.scrollToExcalTop(this.currentPage)
588
+ }
589
+ },
590
+ scrollToUplaodePage (currentPage) {
591
+ this.changetoolbar = true
592
+ if (this.preViewType !== 'pdf') {
593
+ return
594
+ }
595
+
596
+ let pdfResloute = this.cachePdf[currentPage]
597
+ this.identifyTextPostion.extractInfo = pdfResloute.extractInfo
598
+ this.identifyTextPostion.left = pdfResloute.extractInfo.location[0]
599
+ this.identifyTextPostion.top = pdfResloute.extractInfo.location[1]
600
+ this.identifyTextPostion.width = pdfResloute.extractInfo.location[2]
601
+ this.identifyTextPostion.height = pdfResloute.extractInfo.location[3]
602
+ this.identifyTextPostion.page = pdfResloute.page
603
+ this.identifyTextPostion.pageHeight = pdfResloute.pageHeight
604
+ this.identifyTextPostion.pageWidth = pdfResloute.pageWidth
605
+ // 在当前段落在最后一页pdf时,根据计算的高度并不能触发滚动,在此执行重新渲染方法,非次情况会执行两次,待优化
606
+ this.$nextTick(() => {
607
+ this.renderHighlights()
608
+ })
609
+ if (this.transformSalce !== null) {
610
+ this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL) * this.transformSalce) + (this.identifyTextPostion.top * this.scale * this.transformSalce)}`
611
+ } else {
612
+ this.$refs.pdfView.scrollTop = `${((pdfResloute.page - 1) * (this.pageSize.height + this.PAGE_INTVERVAL)) + (this.identifyTextPostion.top * this.scale * this.transformSalce)}`
613
+ }
614
+ },
615
+ scrollToExcalTop (currentPage) {
616
+ for (let index = 0; index < this.allTr.length; index++) {
617
+ if (index == currentPage) {
618
+ Array.from(this.allTr[index].children).forEach(item => {
619
+ item.style.background = 'rgba(255, 136, 0, 0.6)'
620
+ item.classList.add('animation')
621
+ setTimeout(() => {
622
+ item.classList.remove('animation')
623
+ }, 4000)
624
+ })
625
+ // getBoundingClientRect().top 当前元素距离屏幕顶部的高度 + 弹窗header 高度
626
+ if (!this.isPC) {
627
+ let top = this.allTr[index].getBoundingClientRect().top - this.$refs.pdfView.getBoundingClientRect().top
628
+ this.$refs.pdfView.scrollTop = top
629
+ } else {
630
+ let top = this.allTr[index].getBoundingClientRect().top
631
+ this.$refs.pdfView.scrollTop = top - 50
632
+ }
633
+ } else {
634
+ Array.from(this.allTr[index].children).forEach(item => {
635
+ item.style.background = 'rgba(54, 106, 255, 0.6)'
636
+ item.classList.remove('animation')
637
+ })
638
+ }
639
+ }
640
+ },
641
+ // pdf是否需要重新渲染高亮位置
642
+ renderHighlights () {
643
+ let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
644
+ if (lineHeightDom) {
645
+ lineHeightDom.forEach((d) => {
646
+ for (let i = 0; i < d.children.length; i++) {
647
+ if (d.getAttribute('react-count') == this.currentPage) {
648
+ d.children[i].style.backgroundColor = 'rgba(255, 136, 0, 0.3)'
649
+ d.children[i].classList.add('animation')
650
+ setTimeout(() => {
651
+ d.children[i].classList.remove('animation')
652
+ }, 4000)
653
+ } else {
654
+ d.children[i].style.backgroundColor = 'rgba(54, 106, 255, 0.3)'
655
+ d.children[i].classList.remove('animation')
656
+ }
657
+ }
658
+ })
659
+ }
660
+ },
661
+ displayHiglight (pageIndex) {
662
+ let lineHeightDom = Array.from(document.getElementsByClassName('rectdom'))
663
+ if (lineHeightDom) {
664
+ lineHeightDom.forEach((d) => {
665
+ if (d.getAttribute('page-index') == pageIndex) {
666
+ d.style.display = 'none'
667
+ }
668
+ })
669
+ }
670
+ },
671
+ // 前端暂时缓存多页
672
+ autoLoadMore (pageIndex) {
673
+ let pdfResloute = this.cachePdf.find(cache => {
674
+ return cache.page == pageIndex
675
+ })
676
+ if (pdfResloute) {
677
+ this.getpdfResloutePage(pdfResloute)
678
+ } else {
679
+ this.loadPdfData(pageIndex)
680
+ }
681
+ },
682
+ setPageAllLine (arr) {
683
+ this.currentPageAllLine = []
684
+ arr.forEach((item, index) => {
685
+ let i = this.currentPageAllLine.findIndex(l => { return l.page && l.page == item.page })
686
+ if (i != -1) {
687
+ // this.currentPageAllLine[i].allLines.lines.push(item.extractInfo.lines)
688
+ this.currentPageAllLine[i].allLines.push({
689
+ pageCount: index,
690
+ lines: item.extractInfo.lines
691
+ })
692
+ } else {
693
+ this.currentPageAllLine.push({
694
+ page: item.page,
695
+ allLines: [{
696
+ pageCount: index,
697
+ lines: item.extractInfo.lines
698
+ }],
699
+ })
700
+ }
701
+ })
702
+ },
703
+ openTouch () {
704
+ // this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行
705
+ let that = this;
706
+ this.$nextTick(() => {
707
+ // setInterval(() => {
708
+ // this.scale = this.scale + 0.1
709
+ // that.pages.forEach((item, index) =>{
710
+ // if(item.dom) {
711
+ // item.dom.children.forEach( childDom =>{
712
+ // if(childDom.getAttribute('react-count')) {
713
+ // childDom.style.transform = "scale(" + this.scale + ")";
714
+ // childDom.style.transformOrigin = "0px 0px 0px";
715
+ // } else {
716
+ // item.dom = null
717
+ // this.startRenderPages(item.pdfPage, null, index)
718
+ // }
719
+ // } )
720
+ // }
721
+ // })
722
+ // }, 100);
723
+ // 获取放大或缩小的区域DOM
724
+ let matrix_box = this.contentView
725
+ matrix_box.addEventListener("touchstart", function (event) {
726
+ this.isTouchMoved = true
727
+ let touches = event.touches;
728
+ let events = touches[0];
729
+ let events2 = touches[1];
730
+
731
+ // event.preventDefault();
732
+
733
+ // 第一个触摸点的坐标
734
+ that.displacement.pageX = events.pageX;
735
+ that.displacement.pageY = events.pageY;
736
+
737
+ that.displacement.moveable = true;
738
+
739
+ if (events2) {
740
+ that.displacement.pageX2 = events2.pageX;
741
+ that.displacement.pageY2 = events2.pageY;
742
+ }
743
+
744
+ that.displacement.originScale = this.scale || 1;
745
+ });
746
+ document.addEventListener("touchmove", function (event) {
747
+ if (!that.displacement.moveable) {
748
+ return;
749
+ }
750
+ // event.preventDefault();
751
+ let touches = event.touches;
752
+ let events = touches[0];
753
+ let events2 = touches[1];
754
+ // 双指移动
755
+ if (events2) {
756
+ // 第2个指头坐标在touchmove时候获取
757
+ if (!that.displacement.pageX2) {
758
+ that.displacement.pageX2 = events2.pageX;
759
+ }
760
+ if (!that.displacement.pageY2) {
761
+ that.displacement.pageY2 = events2.pageY;
762
+ }
763
+ // 双指缩放比例计算
764
+ let zoom = that.getDistance({
765
+ x: events.pageX,
766
+ y: events.pageY
767
+ },
768
+ {
769
+ x: events2.pageX,
770
+ y: events2.pageY
771
+ }
772
+ ) / that.getDistance(
773
+ {
774
+ x: that.displacement.pageX,
775
+ y: that.displacement.pageY
776
+ },
777
+ {
778
+ x: that.displacement.pageX2,
779
+ y: that.displacement.pageY2
780
+ }
781
+ );
782
+ // 应用在元素上的缩放比例
783
+ let newScale = that.displacement.originScale * zoom;
784
+ // 最大缩放比例限制
785
+ if (newScale > 2) {
786
+ newScale = 2;
787
+ }
788
+ // 最大缩放比例限制
789
+ if (newScale < 1) {
790
+ newScale = 1;
791
+ }
792
+ // 记住使用的缩放值
793
+ that.displacement.scale = newScale;
794
+ // console.log(newScale);
795
+ matrix_box.style.transform = "scale(" + newScale + ")";
796
+ // 设置旋转元素的基点位置
797
+ matrix_box.style.transformOrigin = "0px 0px 0px";
798
+ }
799
+ }, { passive: false });
800
+ document.addEventListener('touchend', function () {
801
+ that.isTouchMoved = false
802
+ }, { passive: false })
803
+ });
804
+ },
805
+ getDistance (start, stop) {
806
+ // Math.hypot()计算参数的平方根
807
+ return Math.hypot(stop.x - start.x, stop.y - start.y);
808
+ },
809
+ setupCanvas (canvas, width, height) {
810
+ const dpr = 1;
811
+ // const rect = canvas.getBoundingClientRect();
812
+ canvas.width = width
813
+ canvas.height = height
814
+ const ctx = canvas.getContext('2d');
815
+ ctx?.scale(dpr, dpr);
816
+ return ctx;
817
+ },
818
+ changeScale (value) {
819
+ if (value == 'zoom') {
820
+ this.handScale = 'auto'
821
+ this.transformSalce = (this.transformSalce + 0.2).toFixed(1)
822
+ } else if (value == 'reduce') {
823
+ if ((this.transformSalce - 0.2).toFixed(1) <= 0) {
824
+ return
825
+ }
826
+ this.handScale = 'auto'
827
+ this.transformSalce = (this.transformSalce - 0.2).toFixed(1)
828
+ } else if (value == 'auto') {
829
+ this.transformSalce = this.$refs.pdfView.clientWidth / this.pageSize.width
830
+ } else if (value == 'reality') {
831
+ this.transformSalce = 0.5
832
+ } else {
833
+ this.transformSalce = (value / 2).toFixed(1)
834
+ }
835
+ this.transformSalce = Number(this.transformSalce)
836
+ this.contentView.style.transform = 'scale(' + this.transformSalce + ')';
837
+ // this.getpdfResloutePage(this.cachePdf[0])
838
+ },
839
+ },
840
+ computed: {
841
+ perviewUrl () {
842
+ return '/web/viewer.html?file=' + '/pdflist/pdf4split-1.pdf'
843
+ },
844
+ setHeight () {
845
+ if (this.tagIds.length > 1) {
846
+ if (this.isPC) {
847
+ return 'calc(100% - 110px)'
848
+ } else {
849
+ return 'calc(100% - 60px)'
850
+ }
851
+ } else {
852
+ if (this.isPC) {
853
+ return 'calc(100% - 50px)'
854
+ } else {
855
+ return '100%'
856
+ }
857
+ }
858
+ }
859
+ },
860
+ watch: {
861
+ tagIds: {
862
+ handler (value) {
863
+ if (value && value.length) {
864
+ // 在 pdf_view 下创建 所有canvs的容器
865
+ this.contentView = document.createElement('div')
866
+ this.contentView.style.transformOrigin = '0px 0px 0px'
867
+ this.$http.get('/knowledge-api/knowledge/knowledge-part-location-info/list?ids=' + value.join(',')).then(res => {
868
+ // res.data = {"data":[{"id":"64591b7d8bb8ab1b91c65f24","knowledgeId":"64591a9c8da27649473f3b4b","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":3,"total":18,"pageHeight":540.0,"pageWidth":960.00946,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/11/55/18/64591b638bb8ab1b91c65eed/3.pdf","extractInfo":{"location":[280.488,161.32,398.71573,61.99298],"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距北京市区65公里,是以奇而著称,融山川、碧水、古长城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","lines":[{"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距","location":[280.488,161.32,398.71573,15.9869995]},{"content":"北京市区65公里,是以奇而著称,融山川、碧水、古长","location":[283.691,184.30899,392.3055,15.9869995]},{"content":"城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","location":[282.699,207.32599,394.3033,15.9869995]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
869
+ // res.data = {"data":[{"id":"64590ce1eb1320043401cc90","knowledgeId":"64590cd5017b461d67e282e1","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":2,"total":5,"pageHeight":841.8898,"pageWidth":595.30396,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/10/53/20/64590ce0eb1320043401cc7b/2.pdf","extractInfo":{"location":[89.32981,638.1907,415.15512,98.63251],"content":":北京地铁 13\r号线 :藤黄\r色 :西直门站—\r东直门站 :17 :41.\r5 :6\r准\rB :2002年\r09月\r28日 ","lines":[{"content":":北京地铁 13\r号线 ","location":[89.32981,638.1907,99.44599,98.63251]},{"content":":藤黄\r色 ","location":[188.7758,638.1907,46.79959,98.63251]},{"content":":西直门站—\r东直门站 ","location":[235.5754,638.1907,86.09996,98.63251]},{"content":":17 ","location":[321.67535,638.1907,36.200012,98.63251]},{"content":":41.\r5 ","location":[357.87537,638.1907,39.400696,98.63251]},{"content":":6\r准\rB ","location":[397.27606,638.1907,41.099,98.63251]},{"content":":2002年\r09月\r28日 ","location":[438.37506,638.1907,66.10986,98.63251]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
870
+ // res.data = {"data":[{"id":"64591b7d8bb8ab1b91c65f24","knowledgeId":"64591a9c8da27649473f3b4b","mainId":"fb348d095c0b4fd7bbd37826563dac7d","page":3,"total":18,"pageHeight":540.0,"pageWidth":960.00946,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/fb348d095c0b4fd7bbd37826563dac7d/2023/05/08/11/55/18/64591b638bb8ab1b91c65eed/3.pdf","extractInfo":{"location":[280.488,161.32,398.71573,61.99298],"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距北京市区65公里,是以奇而著称,融山川、碧水、古长城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","lines":[{"content":"黄花城水长城旅游区位于北京市怀柔区九渡河镇境内,距","location":[280.488,161.32,398.71573,15.9869995]},{"content":"北京市区65公里,是以奇而著称,融山川、碧水、古长","location":[283.691,184.30899,392.3055,15.9869995]},{"content":"城为一体的旅游休闲胜地。而这里的“三绝景”更是引人入","location":[282.699,207.32599,394.3033,15.9869995]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
871
+ // res.data = {"data":[{"id":"6475eab868110215ab821a80","knowledgeId":"6475e7eac724c54c46cbfa2d","mainId":"5ecf2fcd704541149201ab9c1c31162d","page":0,"total":1,"pageHeight":0.0,"pageWidth":0.0,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/5ecf2fcd704541149201ab9c1c31162d/2023/05/30/08/23/20/6475eab63339db423f26b196/0.html","extractInfo":{"location":null,"content":"产品:系统配置,产品型号:存储,VX30:4G+16G,VX50:16G+256G","lines":null,"tagId":"6475eab868110215ab821a80"}}],"code":"0","msg":null,"traceId":null}
872
+ // res.data = {"data":[{"id":"6475e9393339db423f26af01","knowledgeId":"6475e44fc724c54c46cbfa21","mainId":"5ecf2fcd704541149201ab9c1c31162d","page":2,"total":2,"pageHeight":510.25,"pageWidth":1559.05,"publicPageFileUrl":"https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/5ecf2fcd704541149201ab9c1c31162d/2023/05/30/08/00/29/6475e55d3339db423f26a9b8/2.pdf","extractInfo":{"location":[327.70532,288.0498,414.9734,12.241608],"content":"三、指示灯状态说明1.白色常亮:开机/开机中2.红色常亮:待机3.白色呼吸:息屏4.红色闪烁:升级1.LAN:通过网线连接到主机的Camera端口2.电源开关:电源切换开关","lines":[{"content":"三、指示灯状态说明","location":[634.3203,288.0498,108.3584,12.0]},{"content":"1.白色常亮:开机/开机中","location":[634.3203,320.08978,108.23407,9.0]},{"content":"2.红色常亮:待机","location":[634.3204,341.3298,78.597046,9.0]},{"content":"3.白色呼吸:息屏","location":[634.32043,362.45282,78.597046,9.0]},{"content":"4.红色闪烁:升级","location":[634.3205,383.6928,78.597046,9.0]},{"content":"1.LAN:通过网线连接到主机的","location":[327.70535,291.2914,144.35995,9.0]},{"content":"Camera端口","location":[327.70532,306.88843,55.322998,9.0]},{"content":"2.电源开关:电源切换开关","location":[482.74832,291.2914,105.36301,9.0]}],"tagId":null}}],"code":"0","msg":null,"traceId":null}
873
+ // if(value.length === 1) {
874
+ // this.$refs.pdfView.style.height = 'calc(100% - 50px)'
875
+ // }
876
+ // res.data = {
877
+ // "data": [
878
+ // {
879
+ // "id": "64e746120372d778849d2e8e",
880
+ // "knowledgeId": "64e30035edffac0ec96a2d39",
881
+ // "mainId": "e0f6898c6b0d47fa98e8f71ceab1bde8",
882
+ // "page": 14,
883
+ // "total": 60,
884
+ // "pageHeight": 728.504,
885
+ // "pageWidth": 515.906,
886
+ // "publicPageFileUrl": "https://askbot-pdf-all.oss-cn-zhangjiakou.aliyuncs.com/e0f6898c6b0d47fa98e8f71ceab1bde8/2023/08/21/02/12/07/64e300378c3dfb3bc434f51a/15.pdf",
887
+ // "extractInfo": {
888
+ // "location": [
889
+ // 52.665375,
890
+ // 312.01306,
891
+ // 404.98618,
892
+ // 142.5199
893
+ // ],
894
+ // "content": null,
895
+ // "lines": [
896
+ // {
897
+ // "content": null,
898
+ // "location": [
899
+ // 52.665375,
900
+ // 312.01306,
901
+ // 404.98618,
902
+ // 142.5199
903
+ // ]
904
+ // }
905
+ // ],
906
+ // "tagId": null
907
+ // },
908
+ // "block": {
909
+ // "type": "TEXT",
910
+ // "location": [
911
+ // 52.665375,
912
+ // 312.01306,
913
+ // 404.98618,
914
+ // 142.5199
915
+ // ],
916
+ // "color": "#366AFF",
917
+ // "flowChart": {
918
+ // "content": ""
919
+ // },
920
+ // "image": {
921
+ // "url": null,
922
+ // "desc": ""
923
+ // },
924
+ // "table": {
925
+ // "title": null,
926
+ // "table": null
927
+ // },
928
+ // "text": {
929
+ // "originText": "① 头部防护:安全帽\n佩戴要求:\n①存在坠物或对头部产生碰撞风险的作业场所需要佩戴安全帽 ;\n②安全帽必须戴正、戴牢、不能晃动,要系紧下颏带,调节好后箍以\n防安全帽脱落 ;\n③受强力撞击及超过有效期的安全帽必须更换。",
930
+ // "indexText": "① 头部防护:安全帽\n佩戴要求:\n①存在坠物或对头部产生碰撞风险的作业场所需要佩戴安全帽 ;\n②安全帽必须戴正、戴牢、不能晃动,要系紧下颏带,调节好后箍以\n防安全帽脱落 ;\n③受强力撞击及超过有效期的安全帽必须更换。",
931
+ // "lines": [
932
+ // {
933
+ // "location": [
934
+ // 69.08148,
935
+ // 368.92072,
936
+ // 65.90851,
937
+ // 10.5
938
+ // ]
939
+ // },
940
+ // {
941
+ // "location": [
942
+ // 86.290985,
943
+ // 384.67072,
944
+ // 31.5,
945
+ // 10.5
946
+ // ]
947
+ // },
948
+ // {
949
+ // "location": [
950
+ // 286.2992,
951
+ // 315.73584,
952
+ // 37.656006,
953
+ // 12.0
954
+ // ]
955
+ // },
956
+ // {
957
+ // "location": [
958
+ // 324.6939,
959
+ // 316.79932,
960
+ // 122.74487,
961
+ // 10.5
962
+ // ]
963
+ // },
964
+ // {
965
+ // "location": [
966
+ // 286.2954,
967
+ // 336.0458,
968
+ // 149.625,
969
+ // 10.5
970
+ // ]
971
+ // },
972
+ // {
973
+ // "location": [
974
+ // 286.2954,
975
+ // 356.0483,
976
+ // 161.15405,
977
+ // 10.5
978
+ // ]
979
+ // },
980
+ // {
981
+ // "location": [
982
+ // 286.2954,
983
+ // 376.0508,
984
+ // 161.15405,
985
+ // 10.5
986
+ // ]
987
+ // },
988
+ // {
989
+ // "location": [
990
+ // 286.2954,
991
+ // 396.0533,
992
+ // 76.125,
993
+ // 10.5
994
+ // ]
995
+ // },
996
+ // {
997
+ // "location": [
998
+ // 286.2954,
999
+ // 416.05582,
1000
+ // 161.17517,
1001
+ // 10.5
1002
+ // ]
1003
+ // },
1004
+ // {
1005
+ // "location": [
1006
+ // 286.2954,
1007
+ // 436.8038,
1008
+ // 52.5,
1009
+ // 10.5
1010
+ // ]
1011
+ // },
1012
+ // {
1013
+ // "location": [
1014
+ // 338.7992,
1015
+ // 435.73584,
1016
+ // 12.0,
1017
+ // 12.0
1018
+ // ]
1019
+ // }
1020
+ // ]
1021
+ // }
1022
+ // }
1023
+ // }
1024
+ // ],
1025
+ // "code": "0",
1026
+ // "msg": null,
1027
+ // "traceId": null
1028
+ // }
1029
+ if (res.data.code == 0) {
1030
+ // tagIds 会按照gpt识别的生成有序的数组,前端直接按照下标的顺序取就可以了
1031
+ // 缓存拿到的所有数据
1032
+ this.cachePdf = res.data.data
1033
+ let publicPageFileUrl = res.data.data[0].publicPageFileUrl
1034
+ this.currentPage = 0
1035
+ if (publicPageFileUrl.substring(publicPageFileUrl.lastIndexOf('.')) === '.pdf') {
1036
+ this.preViewType = 'pdf'
1037
+ this.setPageAllLine(this.cachePdf)
1038
+ this.getpdfResloutePage(res.data.data[0])
1039
+ } else {
1040
+ this.preViewType = 'excal'
1041
+ this.$http.post(
1042
+ '/knowledge-api/temporary-certificate/or-origin?expired=30',
1043
+ publicPageFileUrl,
1044
+ {
1045
+ headers: {
1046
+ "Content-Type": "application/json",
1047
+ },
1048
+ }).then(res => {
1049
+ // 使用原声请求方式 axios会带有不需要的请求头
1050
+ let xhr = new XMLHttpRequest();
1051
+ xhr.open('GET', res.data || res.bodyText, true);
1052
+ // 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
1053
+ xhr.onload = ({ currentTarget }) => {
1054
+ // 请求完成
1055
+ if (currentTarget.status === 200) { // 返回200
1056
+ this.contentView.innerHTML = currentTarget.response
1057
+ this.contentView.style.padding = '10px'
1058
+ // this.contentView.style.position = 'relative'
1059
+ this.$refs.pdfView.style.backgroundColor = '#FFFFFF'
1060
+ this.$refs.pdfView.appendChild(this.contentView)
1061
+ let allTr = Array.from(this.$refs.pdfView.getElementsByTagName('tr'))
1062
+ this.allTr = []
1063
+ for (let index = 0; index < allTr.length; index++) {
1064
+ if (value.includes(allTr[index].getAttribute('tag-id'))) {
1065
+ this.allTr.push(allTr[index])
1066
+ }
1067
+ }
1068
+ this.currentChange(1)
1069
+
1070
+ }
1071
+ }
1072
+ xhr.send();
1073
+ })
1074
+ }
1075
+ } else {
1076
+ let div = document.createElement('div')
1077
+ div.innerText = '文件加载异常'
1078
+ this.contentView.appendChild(div)
1079
+ this.$refs.pdfView.appendChild(this.contentView)
1080
+ }
1081
+ })
1082
+ }
1083
+ },
1084
+ deep: true,
1085
+ immediate: true
1086
+ }
1087
+ },
1088
+ mounted () {
1089
+ if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
1090
+ this.isPC = false
1091
+ } else {
1092
+ this.isPC = true
1093
+ }
1094
+ }
1095
+ }
1096
+ </script>
1097
+
1098
+ <style lang="less" scoped>
1099
+ .pdf_view {
1100
+ width: 100%;
1101
+ height: calc(100% - 110px);
1102
+ overflow: auto;
1103
+ background-color: #f5f7fb;
1104
+ // margin-bottom: 60px;
1105
+ box-sizing: border-box;
1106
+
1107
+ // position: relative;
1108
+ // > div {
1109
+ // width: 100%;
1110
+ // height: 100%;
1111
+ // overflow: hidden;
1112
+ // overflow-y: auto;
1113
+ // position: relative;
1114
+ // }
1115
+ >iframe {
1116
+ width: 100%;
1117
+ height: 100%;
1118
+ }
1119
+
1120
+ a:link {
1121
+ color: none;
1122
+ }
1123
+
1124
+ a:visited {
1125
+ color: none;
1126
+ }
1127
+
1128
+ a:hover {
1129
+ color: none;
1130
+ }
1131
+
1132
+ a:active {
1133
+ color: none;
1134
+ }
1135
+ .btn_footer {
1136
+ width: 100%;
1137
+ height: 60px;
1138
+ display: flex;
1139
+ align-items: center;
1140
+ justify-content: space-around;
1141
+ position: absolute;
1142
+ bottom: 0px;
1143
+ left: 0;
1144
+ z-index: 999;
1145
+ background: #ffffff;
1146
+
1147
+ .prev,
1148
+ .next {
1149
+ width: 35%;
1150
+ height: 40px;
1151
+ display: flex;
1152
+ align-items: center;
1153
+ justify-content: center;
1154
+ border-radius: 50px;
1155
+ cursor: pointer;
1156
+ }
1157
+
1158
+ .prev {
1159
+ background: #F2F5FA;
1160
+ color: #000;
1161
+ }
1162
+
1163
+ .next {
1164
+ background: #366aff;
1165
+ color: #ffffff;
1166
+ }
1167
+ }
1168
+
1169
+ #pagination {
1170
+ .total-class {
1171
+ margin-right: 13px;
1172
+ font-weight: 400;
1173
+ }
1174
+
1175
+ position: absolute;
1176
+ bottom: 0px;
1177
+ right: 0;
1178
+ width: 100%;
1179
+ display: flex;
1180
+ align-items: center;
1181
+ justify-content: center;
1182
+ height: 50px;
1183
+ background-color: white;
1184
+ box-shadow: 0px 0px 18px 0px rgba(29, 55, 129, 0.07);
1185
+ border-radius: 5px;
1186
+ z-index: 1000;
1187
+
1188
+
1189
+
1190
+ /deep/.el-pagination {
1191
+ margin-right: 110px;
1192
+ }
1193
+
1194
+ /deep/.el-pager {
1195
+ background: #EDF0F6;
1196
+ border-radius: 15px;
1197
+ }
1198
+
1199
+ /deep/.el-pagination.is-background .btn-next {
1200
+ width: 30px;
1201
+ height: 30px;
1202
+ background: #EDF0F6;
1203
+ border-radius: 50%;
1204
+ }
1205
+
1206
+ /deep/.el-pagination .btn-next {
1207
+ width: 30px;
1208
+ height: 30px;
1209
+ background: #EDF0F6;
1210
+ border-radius: 50%;
1211
+ padding-left: 0;
1212
+ margin-left: 5px;
1213
+ }
1214
+
1215
+ /deep/.el-pagination .btn-prev {
1216
+ width: 30px;
1217
+ height: 30px;
1218
+ background: #EDF0F6;
1219
+ border-radius: 50%;
1220
+ padding-right: 0;
1221
+ margin-right: 5px;
1222
+ }
1223
+
1224
+ /deep/.el-pagination button {
1225
+ padding: 0;
1226
+ min-width: 30px;
1227
+ }
1228
+
1229
+ /deep/.el-pager li {
1230
+ background: #EDF0F6;
1231
+ height: 30px;
1232
+ min-width: 30px;
1233
+ line-height: 30px;
1234
+ font-size: 12px;
1235
+ color: #717b90;
1236
+ }
1237
+
1238
+ /deep/.el-pager li:first-child {
1239
+ border-bottom-left-radius: 15px !important;
1240
+ border-top-left-radius: 15px !important;
1241
+ }
1242
+
1243
+ /deep/.el-pager li:last-child {
1244
+ border-top-right-radius: 15px !important;
1245
+ border-bottom-right-radius: 15px !important;
1246
+ }
1247
+
1248
+ /deep/.el-pager li.active {
1249
+ width: 30px;
1250
+ height: 30px;
1251
+ min-width: 30px;
1252
+ background: #366AFF;
1253
+ border: 3px solid #A1B9FF;
1254
+ border-radius: 50%;
1255
+ line-height: 24px;
1256
+ color: white;
1257
+ }
1258
+
1259
+ /deep/.el-pagination.is-background .el-pager li:not(.disabled).active {
1260
+ background: #366AFF;
1261
+ }
1262
+ }
1263
+
1264
+ .change_scale {
1265
+ width: 100%;
1266
+ height: 50px;
1267
+ position: absolute;
1268
+ top: 50px;
1269
+ left: 0;
1270
+ background: #ffffff;
1271
+ display: flex;
1272
+ align-items: center;
1273
+ padding: 0 10px;
1274
+ box-sizing: border-box;
1275
+
1276
+ section {
1277
+ cursor: pointer;
1278
+ width: 30px;
1279
+ height: 30px;
1280
+ margin-right: 5px;
1281
+ border-radius: 5px;
1282
+ display: flex;
1283
+ align-items: center;
1284
+ justify-content: center;
1285
+
1286
+ i {
1287
+ font-weight: 900;
1288
+ }
1289
+ }
1290
+
1291
+ section:hover {
1292
+ background: rgba(221, 222, 223, 1);
1293
+ }
1294
+ }
1295
+ }
1296
+ </style>
1297
+ <style lang="less">
1298
+ .animation {
1299
+ animation-name: highlight;
1300
+ animation-duration: 4s;
1301
+ }
1302
+
1303
+ @keyframes highlight {
1304
+ 0% {
1305
+ background: rgba(255, 136, 0, 0.3);
1306
+ }
1307
+
1308
+ 25% {
1309
+ background: rgba(255, 136, 0, 0.6);
1310
+ }
1311
+
1312
+ 50% {
1313
+ background: rgba(255, 136, 0, 0.3);
1314
+ }
1315
+
1316
+ 75% {
1317
+ background: rgba(255, 136, 0, 0.6);
1318
+ }
1319
+
1320
+ 100% {
1321
+ background: rgba(255, 136, 0, 0.3);
1322
+ }
1364
1323
  }</style>