feat(purchase): 添加PDF预览功能

- 集成vue-pdf-embed组件实现PDF预览功能
- 添加PDF预览弹窗界面和样式
- 实现PDF文件检测和预览逻辑
- 添加PDF加载成功和失败的处理机制
- 更新依赖包配置,添加pdfjs-dist和vue-pdf-embed
- 修复包依赖顺序和重复项问题
master
chenhao 2026-01-06 09:18:43 +08:00
parent 09513911ae
commit 14726a5592
2 changed files with 86 additions and 9 deletions

View File

@ -11,12 +11,14 @@
"type-check": "vue-tsc --noEmit" "type-check": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"vue": "^3.3.4", "@vant/touch-emulator": "^1.4.0",
"vue-router": "^4.2.4", "axios": "^1.5.0",
"pdfjs-dist": "^5.4.449",
"pinia": "^2.1.6", "pinia": "^2.1.6",
"vant": "^4.6.6", "vant": "^4.6.6",
"axios": "^1.5.0", "vue": "^3.3.4",
"@vant/touch-emulator": "^1.4.0" "vue-pdf-embed": "^2.1.3",
"vue-router": "^4.2.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.5.9", "@types/node": "^20.5.9",
@ -29,9 +31,9 @@
"prettier": "^3.0.2", "prettier": "^3.0.2",
"sass": "^1.66.1", "sass": "^1.66.1",
"typescript": "~5.1.6", "typescript": "~5.1.6",
"vite": "^4.4.9",
"vue-tsc": "^1.8.8",
"unplugin-auto-import": "^0.16.6", "unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.2" "unplugin-vue-components": "^0.25.2",
"vite": "^4.4.9",
"vue-tsc": "^1.8.8"
} }
} }

View File

@ -276,6 +276,26 @@
</div> </div>
</div> </div>
</van-popup> </van-popup>
<!-- PDF预览弹窗 -->
<van-popup
v-model:show="pdfPreviewVisible"
position="bottom"
round
:style="{ height: '90%' }"
closeable
>
<div class="pdf-preview-container">
<div class="pdf-content">
<vue-pdf-embed
v-if="pdfUrl"
:source="pdfUrl"
class="vue-pdf-embed"
@loaded="handlePdfLoaded"
@loading-failed="handlePdfError"
/>
</div>
</div>
</van-popup>
</div> </div>
</template> </template>
@ -288,6 +308,13 @@ import { usePurchaseStore } from '@/store/purchase'
import { getPurchaseApprovalHistory, submitPurchaseApproval } from '@/api/purchase' import { getPurchaseApprovalHistory, submitPurchaseApproval } from '@/api/purchase'
import { formatAmount, formatDate, getApprovalStatusColor, getFilePreviewUrl } from '@/utils' import { formatAmount, formatDate, getApprovalStatusColor, getFilePreviewUrl } from '@/utils'
import type {ApprovalStatus, ApproveBtn, AttachmentFile, FileType} from '@/types' import type {ApprovalStatus, ApproveBtn, AttachmentFile, FileType} from '@/types'
import VuePdfEmbed from 'vue-pdf-embed'
import * as pdfjsLib from 'pdfjs-dist'
// PDF worker
// 使 import.meta.url Vite worker
const workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString()
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -302,6 +329,9 @@ const approvalHistory = ref<any[]>([])
// //
const approvalDialogVisible = ref(false) const approvalDialogVisible = ref(false)
const pdfPreviewVisible = ref(false)
const pdfUrl = ref('')
const pdfLoading = ref(false)
const approvalOpinion = ref('') const approvalOpinion = ref('')
const currentApprovalStatus = ref<ApproveBtn>(3) const currentApprovalStatus = ref<ApproveBtn>(3)
const submitting = ref(false) const submitting = ref(false)
@ -347,7 +377,25 @@ const previewFile = (file: AttachmentFile) => {
} }
const url = getFilePreviewUrl(file.filePath) const url = getFilePreviewUrl(file.filePath)
window.open(url, '_blank') const isPdf = file.fileName?.toLowerCase().endsWith('.pdf') || file.filePath?.toLowerCase().endsWith('.pdf')
if (isPdf) {
pdfUrl.value = url
pdfPreviewVisible.value = true
pdfLoading.value = true
} else {
window.open(url, '_blank')
}
}
const handlePdfLoaded = () => {
pdfLoading.value = true
}
const handlePdfError = (error: any) => {
console.error('PDF加载失败:', error)
pdfLoading.value = false
showToast('PDF加载失败')
} }
// //
@ -887,4 +935,31 @@ onMounted(async () => {
background: var(--background-color-secondary); background: var(--background-color-secondary);
} }
} }
.pdf-preview-container {
height: 100%;
padding-top: 40px;
background: var(--background-color-secondary);
overflow-y: auto;
-webkit-overflow-scrolling: touch;
position: relative;
}
.pdf-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
.pdf-content {
min-height: 100%;
background: white;
}
.vue-pdf-embed {
width: 100%;
display: block;
}
</style> </style>