yanyan 1 year ago
parent
commit
f44e651ae5
  1. 2
      package-lock.json
  2. 2
      package.json
  3. 378
      src/views/common/pdfPreview.vue
  4. 2
      src/views/enforce/enforcementPlan.vue

2
package-lock.json

@ -22,7 +22,7 @@
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"pdfh5": "^1.4.9",
"pdfjs-dist": "^4.0.379",
"pdfjs-dist": "^4.10.38",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"playwright": "^1.48.2",

2
package.json

@ -29,7 +29,7 @@
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"pdfh5": "^1.4.9",
"pdfjs-dist": "^4.0.379",
"pdfjs-dist": "^4.10.38",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"playwright": "^1.48.2",

378
src/views/common/pdfPreview.vue

@ -1,326 +1,64 @@
<template>
<div class="pdf-preview-container">
<!-- 头部导航栏 -->
<div class="page-navigation">
<div class="page-controls">
<div class="page-tool">
<div class="page-tool-item" @click="prevPage">上一页</div>
<div class="page-tool-item">{{state.pageNum}}/{{state.numPages}}</div>
<div class="page-tool-item" @click="nextPage">下一页</div>
</div>
</div>
</div>
<!-- PDF预览区域 -->
<div class="pdf-content">
<!-- PDF内容显示区域 -->
<div class="pdf-display-area">
<div v-for="item in state.numPages" :key="item" class='pdf-item' :id="`pdf-page-${item}`">
<vue-pdf-embed :source="state.source" class="vue-pdf-embed" :page="item" style="width: 98%;"/>
</div>
</div>
</div>
</div>
<div id="pdfContainer" ref="pdfContainer" style="width: 100%; height: 100%; overflow: auto;"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, computed, reactive } from 'vue';
import VuePdfEmbed from "vue-pdf-embed";
import { createLoadingTask } from "vue3-pdfjs";
<script >
import {baseUrl} from "@/config/env";
import {useRoute} from "vue-router";
const pdfFile = 'http://192.168.110.36:85/profile/upload/2024/03/29/40eb1a97ca27c3369370e90632d92db0.pdf'
const route = useRoute();
const state = reactive({
source: pdfFile, // pdf
pageNum: 1, //
scale: 1, //
numPages: 0, //
});
const loadingTask: any = ref(null)
const pdfInit = () => {
loadingTask.value = createLoadingTask(state.source);
loadingTask.value.promise.then((pdf: { numPages: number }) => {
state.numPages = pdf.numPages;
});
}
//
let isManualNavigation = false;
const scrollToPage = (page: number) => {
//
isManualNavigation = true;
//
const validPage = Math.max(1, Math.min(page, state.numPages));
state.pageNum = validPage;
//
const element = document.getElementById(`pdf-page-${validPage}`);
if (element) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
//
setTimeout(() => {
isManualNavigation = false;
}, 1000);
};
//
const prevPage = (): void => {
if (state.pageNum > 1) {
scrollToPage(state.pageNum - 1);
}
};
//
const nextPage = (): void => {
const nextPage = state.pageNum + 1;
if (nextPage <= state.numPages) {
scrollToPage(nextPage);
}
};
const pageZoomOut = (): void => {
loadingTask.value = createLoadingTask(state.source);
loadingTask.value.promise.then(pages => {
pages[0].getViewport({ scale: 1.5 });
});
}
const pageZoomIn = (): void => {
loadingTask.value = createLoadingTask(state.source);
loadingTask.value.promise.then(pages => {
pages[0].getViewport({ scale: 0.5 });
});
}
//
const goToPage = (): void => {
//
let page = parseInt(String(state.pageNum));
if (isNaN(page) || page < 1) {
page = 1;
} else if (page > state.numPages) {
page = state.numPages;
}
//
state.pageNum = page;
scrollToPage(page);
};
//
let scrollTimeout: number | null = null;
const handleScroll = () => {
//
if (isManualNavigation) return;
if (scrollTimeout) {
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(() => {
const container = document.querySelector('.pdf-content');
if (!container) return;
const scrollPosition = container.scrollTop;
const items = document.querySelectorAll('.pdf-item');
const containerHeight = container.clientHeight;
const threshold = containerHeight * 0.3; // 30%
let currentPage = state.pageNum;
//
items.forEach((item) => {
const pageNum = parseInt(item.id.replace('pdf-page-', ''));
const rect = item.getBoundingClientRect();
//
if (rect.top >= -threshold && rect.top <= threshold) {
currentPage = pageNum;
import * as pdfjsLib from 'pdfjs-dist';
const screenWidth = window.innerWidth;
export default {
name: 'PdfViewer',
data() {
return {
pageNums: 0,
//
pdfUrl: "http://192.168.110.36:85/profile/upload/2024/03/29/40eb1a97ca27c3369370e90632d92db0.pdf",
};
},
props: {
pdfSrc: {
type: String,
required: true,
},
},
mounted() {
this.pdfUrl =baseUrl+ this.$route.query.url;
console.log("pdf地址", this.pdfUrl)
this.loadPdf();
},
methods: {
async loadPdf() {
// pdfjsLib.GlobalWorkerOptions.workerSrc = '../../api/pdf.worker.js'
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('../../api/pdf.worker.min.mjs', import.meta.url).href;
// getDocument url PDF PDFDocumentLoadingTask
const loadingTask = pdfjsLib.getDocument(this.pdfUrl);
const pdf = await loadingTask.promise;
this.pageNums = pdf.numPages;
var pdfContainer = document.getElementById('pdfContainer');
// PDF
for (var i = 1; i <= this.pageNums; i++) {
pdf.getPage(i).then(async function (page) {
var scale = 1;
var viewport = page.getViewport({scale: scale});
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var scale1 = screenWidth / viewport.width; // scale
var adjustedViewport = page.getViewport({scale: scale1});
// canvas
pdfContainer.appendChild(canvas);
// PDFcanvas
var renderContext = {
canvasContext: context,
viewport: adjustedViewport
};
page.render(renderContext);
});
}
});
//
if (currentPage !== state.pageNum) {
state.pageNum = currentPage;
}
}, 150) as unknown as number; //
},
},
};
//
onMounted(() => {
state.source = baseUrl +route?.query?.url;
// PDF
const isPdfSupported = 'application/pdf' in navigator.mimeTypes;
console.log('浏览器原生支持PDF:', isPdfSupported);
//
const contentEl = document.querySelector('.pdf-content');
if (contentEl) {
contentEl.addEventListener('scroll', handleScroll);
}
pdfInit();
});
onBeforeUnmount(() => {
//
const contentEl = document.querySelector('.pdf-content');
if (contentEl) {
contentEl.removeEventListener('scroll', handleScroll);
}
});
</script>
<style lang="scss" scoped>
.pdf-preview-container {
display: flex;
flex-direction: column;
height: 100%;
background-color: #fff;
border-radius: 4px;
overflow: hidden;
.pdf-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
background-color: #fff;
border-bottom: 1px solid #e0e0e0;
.back-button {
cursor: pointer;
display: inline-block;
padding: 5px 5px 0px;
border-radius: 4px;
transition: background-color 0.2s;
&:hover {
background-color: #f0f0f0;
}
}
.pdf-actions {
display: flex;
gap: 10px;
}
.page-navigation {
display: flex;
align-items: center;
.page-controls {
display: flex;
align-items: center;
padding: 2px 8px;
.page-input {
width: 50px;
margin: 0 5px;
:deep(.el-input__inner) {
text-align: center;
padding: 0 5px;
}
}
}
.total-pages {
margin-left: 5px;
color: #606266;
}
}
}
.pdf-content {
flex: 1;
overflow: auto;
/* 自定义滚动条样式 */
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.05);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.15);
border-radius: 3px;
transition: background 0.2s;
&:hover {
background: rgba(0, 0, 0, 0.25);
}
}
.pdf-loading,
.pdf-error {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.pdf-display-area {
position: relative;
width: 100%;
.pdf-item {
margin: 16px 0px;
}
}
}
@media (max-width: 768px) {
.pdf-display-area {
width: 98%; /* 在小屏幕上稍微减小宽度 */
}
}
.page-tool {
position: absolute;
bottom: 35px;
padding-left: 8px;
padding-right: 8px;
display: flex;
align-items: center;
background: rgb(66, 66, 66);
color: white;
border-radius: 19px;
z-index: 100;
cursor: pointer;
margin-left: 50%;
transform: translateX(-50%);
}
.page-tool-item {
padding: 8px 15px;
padding-left: 10px;
cursor: pointer;
}
}
</style>
</script>

2
src/views/enforce/enforcementPlan.vue

@ -217,7 +217,7 @@
if (null != url) {
router.push(
{
path: "/pdfView",
path: "/pdfPreview",
query: {
url: url
}

Loading…
Cancel
Save