hookehuyr

feat(pdf): 添加pdf-vue3依赖并实现新版PDF查看组件

添加pdf-vue3依赖包用于PDF文件预览
创建PdfViewer组件替换原有PdfPreview组件
优化PDF加载性能并添加进度显示和错误处理
在StudyDetailPage中使用新组件并添加文件大小显示
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
35 "browser-md5-file": "^1.1.1", 35 "browser-md5-file": "^1.1.1",
36 "dayjs": "^1.11.13", 36 "dayjs": "^1.11.13",
37 "lodash": "^4.17.21", 37 "lodash": "^4.17.21",
38 + "pdf-vue3": "^1.0.12",
38 "swiper": "^11.2.6", 39 "swiper": "^11.2.6",
39 "uuid": "^11.1.0", 40 "uuid": "^11.1.0",
40 "vant": "^4.9.19", 41 "vant": "^4.9.19",
......
...@@ -18,6 +18,7 @@ declare module 'vue' { ...@@ -18,6 +18,7 @@ declare module 'vue' {
18 CourseCard: typeof import('./components/ui/CourseCard.vue')['default'] 18 CourseCard: typeof import('./components/ui/CourseCard.vue')['default']
19 CourseImageCard: typeof import('./components/ui/CourseImageCard.vue')['default'] 19 CourseImageCard: typeof import('./components/ui/CourseImageCard.vue')['default']
20 CourseList: typeof import('./components/courses/CourseList.vue')['default'] 20 CourseList: typeof import('./components/courses/CourseList.vue')['default']
21 + FilePreviewPopup: typeof import('./components/ui/FilePreviewPopup.vue')['default']
21 FormPage: typeof import('./components/infoEntry/formPage.vue')['default'] 22 FormPage: typeof import('./components/infoEntry/formPage.vue')['default']
22 FrostedGlass: typeof import('./components/ui/FrostedGlass.vue')['default'] 23 FrostedGlass: typeof import('./components/ui/FrostedGlass.vue')['default']
23 GradientHeader: typeof import('./components/ui/GradientHeader.vue')['default'] 24 GradientHeader: typeof import('./components/ui/GradientHeader.vue')['default']
...@@ -25,6 +26,7 @@ declare module 'vue' { ...@@ -25,6 +26,7 @@ declare module 'vue' {
25 MenuItem: typeof import('./components/ui/MenuItem.vue')['default'] 26 MenuItem: typeof import('./components/ui/MenuItem.vue')['default']
26 OfficeViewer: typeof import('./components/ui/OfficeViewer.vue')['default'] 27 OfficeViewer: typeof import('./components/ui/OfficeViewer.vue')['default']
27 PdfPreview: typeof import('./components/ui/PdfPreview.vue')['default'] 28 PdfPreview: typeof import('./components/ui/PdfPreview.vue')['default']
29 + PdfViewer: typeof import('./components/ui/PdfViewer.vue')['default']
28 ReviewPopup: typeof import('./components/courses/ReviewPopup.vue')['default'] 30 ReviewPopup: typeof import('./components/courses/ReviewPopup.vue')['default']
29 RouterLink: typeof import('vue-router')['RouterLink'] 31 RouterLink: typeof import('vue-router')['RouterLink']
30 RouterView: typeof import('vue-router')['RouterView'] 32 RouterView: typeof import('vue-router')['RouterView']
......
...@@ -79,12 +79,29 @@ const initPdfViewer = () => { ...@@ -79,12 +79,29 @@ const initPdfViewer = () => {
79 // customPdfOption是 pdfjs getDocument 函数中一些配置参数 具体可参考 https://mozilla.github.io/pdf.js/api/draft/module-pdfjsLib.html#~DocumentInitParameters 79 // customPdfOption是 pdfjs getDocument 函数中一些配置参数 具体可参考 https://mozilla.github.io/pdf.js/api/draft/module-pdfjsLib.html#~DocumentInitParameters
80 cMapPacked: true, //指定 CMap 是否是二进制打包的 80 cMapPacked: true, //指定 CMap 是否是二进制打包的
81 cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/", //预定义 Adob​​e CMaps 所在的 URL。可解决字体加载错误 81 cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/", //预定义 Adob​​e CMaps 所在的 URL。可解决字体加载错误
82 + // 内存优化配置
83 + disableAutoFetch: true, // 启用自动获取,提升加载速度
84 + disableStream: true, // 启用流式加载
85 + disableRange: true, // 启用范围请求,支持分片下载
86 + // maxImageSize: 1 * 1024 * 1024, // 限制图片最大尺寸为1MB
87 + isEvalSupported: false, // 禁用eval,提升安全性和性能
88 + // 启用懒加载,减少内存占用
89 + enableXfa: true, // 禁用XFA表单支持,减少内存占用
90 + // 添加更多性能优化配置
91 + useOnlyCssZoom: true, // 仅使用CSS缩放,减少重新渲染
92 + verbosity: 0, // 减少日志输出,提升性能
93 + // 微信浏览器优化配置
94 + useWorkerFetch: true, // 在微信浏览器中禁用Worker fetch,避免兼容性问题
95 + disableFontFace: true, // 保持字体渲染,但可能需要根据情况调整
96 + // 内存管理配置
97 + pdfBug: true, // 禁用调试模式,减少内存占用
98 + stopAtErrors: true, // 不要在错误时停止,让错误回调处理
82 }, 99 },
83 // 禁用右键菜单和文本选择 100 // 禁用右键菜单和文本选择
84 selectConfig: undefined, // 禁用文本选择功能 101 selectConfig: undefined, // 禁用文本选择功能
85 } 102 }
86 }); 103 });
87 - 104 +
88 // 添加额外的事件监听器来防止长按保存 105 // 添加额外的事件监听器来防止长按保存
89 const pdfContainer = document.querySelector("#pdf-container"); 106 const pdfContainer = document.querySelector("#pdf-container");
90 if (pdfContainer) { 107 if (pdfContainer) {
...@@ -93,13 +110,13 @@ const initPdfViewer = () => { ...@@ -93,13 +110,13 @@ const initPdfViewer = () => {
93 e.preventDefault(); 110 e.preventDefault();
94 return false; 111 return false;
95 }); 112 });
96 - 113 +
97 // 防止长按选择 114 // 防止长按选择
98 pdfContainer.addEventListener('selectstart', (e) => { 115 pdfContainer.addEventListener('selectstart', (e) => {
99 e.preventDefault(); 116 e.preventDefault();
100 return false; 117 return false;
101 }); 118 });
102 - 119 +
103 // 防止拖拽 120 // 防止拖拽
104 pdfContainer.addEventListener('dragstart', (e) => { 121 pdfContainer.addEventListener('dragstart', (e) => {
105 e.preventDefault(); 122 e.preventDefault();
......
1 +<!--
2 + * @Date: 2025-01-21
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-10-21 14:33:07
5 + * @FilePath: /mlaj/src/components/ui/PdfViewer.vue
6 + * @Description: PDF预览组件 - 使用pdf-vue3库
7 +-->
8 +<template>
9 + <van-popup v-if="show" :show="show" @update:show="emit('update:show', $event)" position="right"
10 + :style="{ height: '100%', width: '100%' }">
11 + <div class="pdf-viewer-container">
12 + <!-- PDF内容区域 -->
13 + <div class="pdf-content" :class="{ 'pdf-no-select': preventSave }">
14 + <PDF v-if="url && show && !loadingError" :src="url" :showProgress="true" :progressColor="'#1989fa'"
15 + :showPageTooltip="true" :showBackToTopBtn="true" :scrollThreshold="300" :pdfWidth="'100%'"
16 + :rowGap="8" :page="1" :cMapUrl="'https://unpkg.com/pdfjs-dist@3.7.107/cmaps/'"
17 + :withCredentials="false" :useSystemFonts="true" :stopAtErrors="false" :disableFontFace="false"
18 + :disableRange="false" :disableStream="false" :disableAutoFetch="false" @onProgress="handleProgress"
19 + @onComplete="handleComplete" @onScroll="handleScroll" @onPageChange="handlePageChange"
20 + @onPdfInit="handlePdfInit" @onError="handlePdfError" />
21 +
22 + <!-- 错误状态显示 -->
23 + <div v-if="loadingError" class="error-container">
24 + <div class="error-content">
25 + <van-icon name="warning-o" size="48" color="#ff4444" />
26 + <div class="error-title">加载失败</div>
27 + <div class="error-message">{{ errorMessage }}</div>
28 + <van-button type="primary" size="small" @click="retryLoad" class="retry-btn">
29 + 重新加载
30 + </van-button>
31 + </div>
32 + </div>
33 + </div>
34 +
35 + <!-- 关闭按钮 -->
36 + <van-button class="close-btn" type="default" icon="cross" round @click="emit('update:show', false)" />
37 +
38 + <!-- 加载遮罩 -->
39 + <van-overlay :show="loading && !loadingError">
40 + <div class="wrapper" @click.stop>
41 + <div class="loading-content">
42 + <!-- 进度环形图 -->
43 + <div class="progress-circle">
44 + <div class="progress-percent">{{ loadingProgress }}%</div>
45 + </div>
46 +
47 + <!-- 加载文字 -->
48 + <div class="loading-text">
49 + <div class="loading-title">正在加载PDF文档</div>
50 + <div class="loading-subtitle">
51 + {{ loadingProgress < 10 ? '正在连接服务器...' : loadingProgress < 50 ? '正在下载文件...' :
52 + loadingProgress < 90 ? '正在解析文档...' : '即将完成...' }} </div>
53 + </div>
54 + </div>
55 + </div>
56 + </van-overlay>
57 + </div>
58 + </van-popup>
59 +</template>
60 +
61 +<script setup>
62 +import { ref, watch, nextTick } from 'vue';
63 +import PDF from "pdf-vue3";
64 +
65 +/**
66 + * 组件属性定义
67 + */
68 +const props = defineProps({
69 + // 是否显示弹窗
70 + show: {
71 + type: Boolean,
72 + default: false
73 + },
74 + // PDF文件URL
75 + url: {
76 + type: String,
77 + default: ''
78 + },
79 + // PDF标题
80 + title: {
81 + type: String,
82 + default: ''
83 + },
84 + // 是否防止保存(禁用右键、长按等)
85 + preventSave: {
86 + type: Boolean,
87 + default: true
88 + }
89 +});
90 +
91 +/**
92 + * 事件定义
93 + */
94 +const emit = defineEmits(['update:show', 'onLoad', 'onProgress', 'onComplete']);
95 +
96 +// 响应式数据
97 +const loading = ref(true);
98 +const loadingProgress = ref(0);
99 +const loadingError = ref(false);
100 +const errorMessage = ref('');
101 +
102 +/**
103 + * 监听show属性变化,控制PDF加载
104 + */
105 +watch(() => props.show, (newVal) => {
106 + if (newVal && props.url) {
107 + // 重置所有状态
108 + loading.value = true;
109 + loadingError.value = false;
110 + loadingProgress.value = 0;
111 + errorMessage.value = '';
112 + } else if (!newVal) {
113 + // 弹窗关闭时重置状态
114 + loading.value = true;
115 + loadingError.value = false;
116 + loadingProgress.value = 0;
117 + errorMessage.value = '';
118 + }
119 +});
120 +
121 +/**
122 + * 监听URL变化,重新加载PDF
123 + */
124 +watch(() => props.url, (newUrl) => {
125 + if (newUrl && props.show) {
126 + // URL变化时重置状态
127 + loading.value = true;
128 + loadingError.value = false;
129 + loadingProgress.value = 0;
130 + errorMessage.value = '';
131 + }
132 +});
133 +
134 +/**
135 + * 处理PDF下载进度
136 + * @param {number} loadRatio - 加载进度 0-100
137 + */
138 +const handleProgress = (loadRatio) => {
139 + loadingProgress.value = Math.round(loadRatio);
140 + emit('onProgress', loadRatio);
141 +};
142 +
143 +/**
144 + * 处理PDF下载完成
145 + */
146 +const handleComplete = () => {
147 + loading.value = false;
148 + loadingError.value = false;
149 + loadingProgress.value = 100;
150 + emit('onLoad', false);
151 + emit('onComplete');
152 +};
153 +
154 +/**
155 + * 处理PDF滚动事件
156 + * @param {number} scrollOffset - 滚动偏移量
157 + */
158 +const handleScroll = (scrollOffset) => {
159 + // 可以在这里处理滚动事件
160 +};
161 +
162 +/**
163 + * 处理页面变化事件
164 + * @param {number} page - 当前页码
165 + */
166 +const handlePageChange = (page) => {
167 + // 可以在这里处理页面变化事件
168 +};
169 +
170 +/**
171 + * 处理PDF初始化完成
172 + * @param {Object} pdf - PDF文档对象
173 + */
174 +const handlePdfInit = (pdf) => {
175 + // PDF初始化完成后的处理
176 + loadingError.value = false;
177 + nextTick(() => {
178 + if (props.preventSave) {
179 + // 添加防止保存的事件监听器
180 + addPreventSaveListeners();
181 + }
182 + });
183 +};
184 +
185 +/**
186 + * 处理PDF加载错误
187 + * @param {Error} error - 错误对象
188 + */
189 +const handlePdfError = (error) => {
190 + console.error('PDF加载失败:', error);
191 + loading.value = false;
192 + loadingError.value = true;
193 + loadingProgress.value = 0;
194 +
195 + // 根据错误类型设置不同的错误信息
196 + if (error.name === 'NetworkError' || error.message.includes('network')) {
197 + errorMessage.value = '网络连接失败,请检查网络后重试';
198 + } else if (error.name === 'InvalidPDFException' || error.message.includes('Invalid PDF')) {
199 + errorMessage.value = 'PDF文件格式错误或已损坏';
200 + } else if (error.message.includes('404') || error.message.includes('Not Found')) {
201 + errorMessage.value = '文件不存在或已被删除';
202 + } else if (error.message.includes('403') || error.message.includes('Forbidden')) {
203 + errorMessage.value = '没有权限访问此文件';
204 + } else {
205 + errorMessage.value = '文件加载失败,请重试';
206 + }
207 +};
208 +
209 +/**
210 + * 重试加载PDF
211 + */
212 +const retryLoad = () => {
213 + loadingError.value = false;
214 + loading.value = true;
215 + loadingProgress.value = 0;
216 + errorMessage.value = '';
217 +};
218 +
219 +/**
220 + * 添加防止保存的事件监听器
221 + */
222 +const addPreventSaveListeners = () => {
223 + const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content');
224 + if (pdfContainer) {
225 + // 防止上下文菜单(右键菜单)
226 + pdfContainer.addEventListener('contextmenu', (e) => {
227 + e.preventDefault();
228 + return false;
229 + });
230 +
231 + // 防止长按选择
232 + pdfContainer.addEventListener('selectstart', (e) => {
233 + e.preventDefault();
234 + return false;
235 + });
236 +
237 + // 防止拖拽
238 + pdfContainer.addEventListener('dragstart', (e) => {
239 + e.preventDefault();
240 + return false;
241 + });
242 +
243 + // 防止触摸回调(移动端长按)
244 + pdfContainer.addEventListener('touchstart', (e) => {
245 + if (e.touches.length > 1) {
246 + e.preventDefault();
247 + }
248 + });
249 +
250 + // 防止双指缩放等手势
251 + pdfContainer.addEventListener('gesturestart', (e) => {
252 + e.preventDefault();
253 + });
254 + }
255 +};
256 +</script>
257 +
258 +<style scoped>
259 +.pdf-viewer-container {
260 + width: 100%;
261 + height: 100%;
262 + position: relative;
263 + background-color: #f5f5f5;
264 +}
265 +
266 +.pdf-content {
267 + width: 100%;
268 + height: 100%;
269 + overflow: auto;
270 +}
271 +
272 +/* 防止PDF内容被选择和保存的样式 */
273 +.pdf-no-select {
274 + -webkit-user-select: none;
275 + /* Safari */
276 + -moz-user-select: none;
277 + /* Firefox */
278 + -ms-user-select: none;
279 + /* IE10+/Edge */
280 + user-select: none;
281 + /* Standard */
282 + -webkit-touch-callout: none;
283 + /* iOS Safari */
284 + -webkit-tap-highlight-color: transparent;
285 + /* 移除点击高亮 */
286 + pointer-events: auto;
287 + /* 保持可点击 */
288 +}
289 +
290 +/* 深度选择器,防止PDF内部元素被保存 */
291 +:deep(.pdf-no-select img) {
292 + -webkit-user-select: none;
293 + -moz-user-select: none;
294 + -ms-user-select: none;
295 + user-select: none;
296 + -webkit-touch-callout: none;
297 + -webkit-tap-highlight-color: transparent;
298 + pointer-events: none;
299 + /* 禁用图片的所有交互 */
300 + -webkit-user-drag: none;
301 + /* 禁止拖拽 */
302 + -khtml-user-drag: none;
303 + -moz-user-drag: none;
304 + -o-user-drag: none;
305 + user-drag: none;
306 +}
307 +
308 +/* 防止Canvas元素被保存 */
309 +:deep(.pdf-no-select canvas) {
310 + -webkit-user-select: none;
311 + -moz-user-select: none;
312 + -ms-user-select: none;
313 + user-select: none;
314 + -webkit-touch-callout: none;
315 + -webkit-tap-highlight-color: transparent;
316 + pointer-events: none;
317 + -webkit-user-drag: none;
318 + -khtml-user-drag: none;
319 + -moz-user-drag: none;
320 + -o-user-drag: none;
321 + user-drag: none;
322 +}
323 +
324 +/* 关闭按钮样式 */
325 +.close-btn {
326 + position: fixed;
327 + right: 20px;
328 + top: 20px;
329 + z-index: 100;
330 + width: 40px;
331 + height: 40px;
332 + padding: 0;
333 + border-radius: 50%;
334 + background: rgba(0, 0, 0, 0.6);
335 + color: #fff;
336 +}
337 +
338 +/* 加载遮罩样式 */
339 +.wrapper {
340 + display: flex;
341 + align-items: center;
342 + justify-content: center;
343 + height: 100%;
344 + background: rgba(0, 0, 0, 0.7);
345 + backdrop-filter: blur(4px);
346 +}
347 +
348 +/* 加载内容样式 */
349 +.loading-content {
350 + display: flex;
351 + flex-direction: column;
352 + align-items: center;
353 + justify-content: center;
354 + text-align: center;
355 + color: #fff;
356 +}
357 +
358 +.progress-circle {
359 + width: 80px;
360 + height: 80px;
361 + background-color: white;
362 + border-radius: 50%;
363 + display: flex;
364 + align-items: center;
365 + justify-content: center;
366 + margin: 0 auto 20px;
367 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
368 +}
369 +
370 +.progress-percent {
371 + font-size: 18px;
372 + font-weight: bold;
373 + color: #1989fa;
374 +}
375 +
376 +.loading-text {
377 + max-width: 200px;
378 +}
379 +
380 +.loading-title {
381 + font-size: 16px;
382 + font-weight: 500;
383 + margin-bottom: 8px;
384 + color: #fff;
385 +}
386 +
387 +.loading-subtitle {
388 + font-size: 14px;
389 + color: rgba(255, 255, 255, 0.8);
390 + line-height: 1.4;
391 +}
392 +
393 +/* 错误状态样式 */
394 +.error-container {
395 + display: flex;
396 + align-items: center;
397 + justify-content: center;
398 + height: 100%;
399 + background: #f8f9fa;
400 +}
401 +
402 +.error-content {
403 + display: flex;
404 + flex-direction: column;
405 + align-items: center;
406 + justify-content: center;
407 + text-align: center;
408 + padding: 40px 20px;
409 + max-width: 300px;
410 +}
411 +
412 +.error-title {
413 + font-size: 18px;
414 + font-weight: 600;
415 + color: #333;
416 + margin: 16px 0 8px 0;
417 +}
418 +
419 +.error-message {
420 + font-size: 14px;
421 + color: #666;
422 + line-height: 1.5;
423 + margin-bottom: 20px;
424 +}
425 +
426 +.retry-btn {
427 + min-width: 100px;
428 +}
429 +</style>
...@@ -261,7 +261,7 @@ ...@@ -261,7 +261,7 @@
261 </van-popup> 261 </van-popup>
262 262
263 <!-- PDF预览 --> 263 <!-- PDF预览 -->
264 - <PdfPreview v-model:show="pdfShow" :url="pdfUrl" :title="pdfTitle" @onLoad="onPdfLoad" /> 264 + <PdfViewer v-model:show="pdfShow" :url="pdfUrl" :title="pdfTitle" @onLoad="onPdfLoad" @onProgress="onPdfProgress" @onComplete="onPdfComplete" />
265 265
266 <!-- Office 文档预览弹窗 --> 266 <!-- Office 文档预览弹窗 -->
267 <van-popup 267 <van-popup
...@@ -536,6 +536,7 @@ ...@@ -536,6 +536,7 @@
536 <div class="flex items-center gap-1"> 536 <div class="flex items-center gap-1">
537 <van-icon name="label-o" size="12" style="margin-right: 0.25rem;"/> 537 <van-icon name="label-o" size="12" style="margin-right: 0.25rem;"/>
538 <span>{{ getFileType(file.title || file.name) }}</span> 538 <span>{{ getFileType(file.title || file.name) }}</span>
539 + <span class="ml-2">{{ file.size ? (file.size / 1024 / 1024).toFixed(2) + 'MB' : '' }}</span>
539 </div> 540 </div>
540 <!-- 复制地址按钮 --> 541 <!-- 复制地址按钮 -->
541 <!-- <button 542 <!-- <button
...@@ -656,7 +657,7 @@ import { formatDate, wxInfo } from '@/utils/tools' ...@@ -656,7 +657,7 @@ import { formatDate, wxInfo } from '@/utils/tools'
656 import axios from 'axios'; 657 import axios from 'axios';
657 import { v4 as uuidv4 } from "uuid"; 658 import { v4 as uuidv4 } from "uuid";
658 import { useIntersectionObserver } from '@vueuse/core'; 659 import { useIntersectionObserver } from '@vueuse/core';
659 -import PdfPreview from '@/components/ui/PdfPreview.vue'; 660 +import PdfViewer from '@/components/ui/PdfViewer.vue';
660 import { showToast } from 'vant'; 661 import { showToast } from 'vant';
661 662
662 // 导入接口 663 // 导入接口
...@@ -986,6 +987,21 @@ const onPdfLoad = (load) => { ...@@ -986,6 +987,21 @@ const onPdfLoad = (load) => {
986 }; 987 };
987 988
988 /** 989 /**
990 + * PDF下载进度回调
991 + * @param {number} progress - 下载进度 0-100
992 + */
993 +const onPdfProgress = (progress) => {
994 + // console.log('PDF下载进度:', progress);
995 +};
996 +
997 +/**
998 + * PDF下载完成回调
999 + */
1000 +const onPdfComplete = () => {
1001 + // console.log('PDF下载完成');
1002 +};
1003 +
1004 +/**
989 * Office 文档渲染完成回调 1005 * Office 文档渲染完成回调
990 */ 1006 */
991 const onOfficeRendered = () => { 1007 const onOfficeRendered = () => {
......
...@@ -2124,6 +2124,11 @@ pathe@^2.0.1, pathe@^2.0.2, pathe@^2.0.3: ...@@ -2124,6 +2124,11 @@ pathe@^2.0.1, pathe@^2.0.2, pathe@^2.0.3:
2124 resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" 2124 resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716"
2125 integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== 2125 integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
2126 2126
2127 +pdf-vue3@^1.0.12:
2128 + version "1.0.12"
2129 + resolved "https://registry.npmjs.org/pdf-vue3/-/pdf-vue3-1.0.12.tgz#8b2c4346cd75a7d3307aa6117c591c047549f4ed"
2130 + integrity sha512-7SMTx1RfRwdc+2WPniDzqM8MxJLqTNNzdyV0SeQTxeRLJGndb5Wv/fz5afO13oBSIvvaqcbZ/S3gF+XjqkSb9g==
2131 +
2127 pdfjs-dist@3.4.120: 2132 pdfjs-dist@3.4.120:
2128 version "3.4.120" 2133 version "3.4.120"
2129 resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-3.4.120.tgz#6f4222117157498f179c95dc4569fad6336a8fdd" 2134 resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-3.4.120.tgz#6f4222117157498f179c95dc4569fad6336a8fdd"
......