feat(purchase): 添加PDF预览功能
- 集成vue-pdf-embed组件实现PDF预览功能 - 添加PDF预览弹窗界面和样式 - 实现PDF文件检测和预览逻辑 - 添加PDF加载成功和失败的处理机制 - 更新依赖包配置,添加pdfjs-dist和vue-pdf-embed - 修复包依赖顺序和重复项问题master
parent
09513911ae
commit
14726a5592
18
package.json
18
package.json
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue