webpage打包index.html引入目录路径修改

博客提到打包后路径不对,表达了希望路径正确的诉求,但未给出更多详细信息。

打包之后是这样的路径就不对的

我希望是

 

来到

PDF 下载错误详情:, TypeError: undefined is not a function (near '...uni.base64ToPath...') at pages/home/components/Imagepreview.vue:800 __ERROR <template> <view class="evidence-card-container"> <!-- 原有卡片布局 --> <view class="card-row"> <view class="card-item" v-for="(item, index) in evidenceList.slice(0, 3)" :key="index" @click="handleClick(item)" > <image v-if="item.icon" class="item-icon" :src="item.icon" mode="aspectFit" /> <text class="item-text">{{ item.text }}</text> </view> </view> <view class="card-row"> <view class="card-item" v-for="(item, index) in evidenceList.slice(3, 6)" :key="index + 3" @click="handleClick(item)" > <image v-if="item.icon" class="item-icon" :src="item.icon" mode="aspectFit" /> <text class="item-text">{{ item.text }}</text> </view> </view> <!-- 拍照预览弹窗 --> <view v-if="showPhotoPreview" class="photo-preview-mask"> <view class="preview-content"> <!-- 图片预览区域 --> <image class="preview-image" :src="currentPreviewImg" mode="aspectFit" @click="handleImageClick" ></image> <!-- 底部操作按钮 --> <view class="preview-footer"> <button class="preview-btn cancel-btn" @click="cancelPreview">取消</button> <button class="preview-btn confirm-btn" @click="confirmPreview">固化</button> </view> </view> </view> </view> </template> <script setup lang="ts"> import { ref } from 'vue' const showPhotoPreview = ref(false) // 控制预览弹窗显示 const currentPreviewImg = ref('') // 当前预览的图片地址 const tempPhotoPath = ref('') // 临时存储拍照路径(用于H5) // 定义单个卡片数据结构 interface EvidenceItem { text: string icon?: string // 图标地址,可选 action?: () => void // 点击回调,可选 } // 合并所有取证选项到一个列表 const evidenceList = ref<EvidenceItem[]>([ { text: '拍照取证', icon: '/static/home/ObtainEvidence/takepictures.svg' }, { text: '录像取证', icon: '/static/home/ObtainEvidence/picturerecording.svg' }, { text: '录音取证', icon: '/static/home/ObtainEvidence/soundrecording.svg' }, { text: '网页取证', icon: '/static/home/ObtainEvidence/Webpage.svg' }, { text: '录屏取证', icon: '/static/home/ObtainEvidence/screencap.svg' }, { text: '委托取证', icon: '/static/home/ObtainEvidence/commission.svg' }, ]) const showProgress = ref(false) // 控制进度条是否显示 const progress = ref(0) // 上传进度(0-100) const isUploading = ref(false) // 标记是否正在上传(避免重复上传) // 录像取证 const uploadVideo = (filePath: string, duration: number, size: number) => { // 1. 处理文件名 const originalFileName = filePath.substring(filePath.lastIndexOf('/') + 1) const fileExtension = originalFileName.includes('.') ? originalFileName.split('.').pop() : 'mp4' const timestamp = new Date().getTime() const newFileName = `video_evidence_${timestamp}.${fileExtension}` // 2. 显示进度 showProgress.value = true progress.value = 0 isUploading.value = true // 3. 显示加载提示 let loadingVisible = false // 标记loading是否显示 const showLoading = (title: string) => { if (!loadingVisible) { uni.showLoading({ title, mask: true }) loadingVisible = true } else { // uni.setLoadingText(title); // 已有loading时,只更新文本 } } showLoading('准备上传...') // 4. 创建上传任务 const uploadTask = uni.uploadFile({ // url: 'http://192.168.1.80:1592/api/upload', url: 'http://192.168.0.111:1592/api/upload', filePath: filePath, name: 'file', formData: { originalFileName: originalFileName, customFileName: newFileName, duration: duration, size: size, type: 'video', uploadTime: new Date().toISOString(), }, header: { // 'Authorization': 'Bearer your-token-here' // 如果需要身份验证 }, timeout: 300000, // 5分钟超时 success: (uploadRes) => { console.log('上传成功,原始响应:', uploadRes.data) try { const data = JSON.parse(uploadRes.data) if (data.code === 200) { if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示成功提示 uni.showModal({ title: '固化成功!', content: '您的证据已保存至“我的证据”', confirmText: '查看证据', cancelText: '继续取证', success: (res) => { if (res.confirm) { // 后端返回的单个证据对象(含 base64Data、webpagePdfBase64 等字段) const singleEvidence = { ...data.data, // 合并previewImage、filePreview等基础信息 // 明确提取PDF相关字段(关键:以你的后端实际返回层级为准) pdfData : data.data.pdfData, // 若后端在data.data下 webpagePdfBase64: data.data.webpagePdfBase64 , // 补充必要字段(确保详情页能正常显示) evidenceType: data.data.evidenceType, evidenceName: data.data.evidenceName, acquisitionTime: data.data.acquisitionTime, // 取证时间(后端未返回则前端生成) timestamp: new Date().getTime() // 用于生成唯一storageKey }; const storageKey = `evidence_single_${singleEvidence.timestamp}`; // 存储完整数据到本地 uni.setStorageSync(storageKey, singleEvidence); console.log('存储的完整证据数据:', singleEvidence); // 跳转时传递 storageKey uni.navigateTo({ url: `/pages/home/components/Imagepreview?storageKey=${storageKey}` }); // 清理临时数据 cancelPreview(); } else { uni.navigateTo({ url: '/pages/home/home' }); } } }); } else { throw new Error(data.msg || `上传失败,状态码: ${data.code}`) } } catch (e) { console.error('解析响应失败', e) if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示错误提示 uni.showToast({ title: e.message || '处理响应失败', icon: 'none', duration: 3000, }) } }, fail: (err) => { console.error('上传失败:', err) if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示失败提示 uni.showToast({ title: `上传失败: ${err.errMsg || '网络错误'}`, icon: 'none', duration: 3000, }) }, complete: () => { // 确保loading被关闭 if (loadingVisible) { uni.hideLoading() loadingVisible = false } showProgress.value = false isUploading.value = false }, }) // 5. 监听上传进度 uploadTask.onProgressUpdate((res) => { console.log('上传进度:', res.progress) progress.value = res.progress }) } //拍照取证 const takePhotoAndPreviewPDF = () => { // #ifdef APP uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['camera'], // 仅调用相机 success: (res) => { console.log('APP端拍照成功,临时路径:', res.tempFilePaths[0]); const tempFilePath = res.tempFilePaths[0]; tempPhotoPath.value = tempFilePath; currentPreviewImg.value = tempFilePath; showPhotoPreview.value = true; // 显示预览弹窗 }, fail: (err) => { console.error('APP端相机调用失败:', err); // 若用户拒绝权限,引导去设置页 if (err.errMsg.includes('deny') || err.errMsg.includes('denied')) { uni.showModal({ title: '权限不足', content: '拍照取证需要相机权限,请在手机设置中开启', confirmText: '去设置', success: (res) => { if (res.confirm) uni.openSetting(); // 打开应用设置 } }); } else { uni.showToast({ title: `拍照失败:${err.errMsg}`, icon: 'none' }); } } }); // #endif // #ifdef H5 uni.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['camera'], success: async (res) => { console.log('H5拍照结果:', res.tempFilePaths) const tempFilePath = res.tempFilePaths[0] tempPhotoPath.value = tempFilePath // 存储临时路径 currentPreviewImg.value = tempFilePath // 直接使用本地临时路径预览 showPhotoPreview.value = true // 显示预览弹窗 }, fail: (err) => { console.error('H5拍照失败:', err) uni.showToast({ title: '拍照失败', icon: 'none' }) } }) //// #endif } const handleImageClick = () => { // showPhotoPreview.value = false } // 取消预览 const cancelPreview = () => { showPhotoPreview.value = false currentPreviewImg.value = '' tempPhotoPath.value = '' } // 确认预览(可扩展为提交证据等操作) const confirmPreview = () => { // 1. 校验:无图片路径或正在上传时,不执行操作 if (!tempPhotoPath.value || isUploading.value) return; // 2. 处理文件名(与APP端格式一致) const originalFileName = tempPhotoPath.value.substring(tempPhotoPath.value.lastIndexOf('/') + 1); const fileExtension = originalFileName.includes('.') ? originalFileName.split('.').pop() : 'jpg'; const timestamp = new Date().getTime(); const newFileName = `evidence_${timestamp}.${fileExtension}`; // 3. 初始化上传状态 showProgress.value = true; progress.value = 0; isUploading.value = true; uni.showLoading({ title: '图片上传中...', mask: true }); // 4. 调用后端接口上传图片 const uploadTask = uni.uploadFile({ // url: 'http://192.168.1.80:1592/api/upload', url: 'http://192.168.0.111:1592/api/upload', filePath: tempPhotoPath.value, name: 'file', formData: { originalFileName: originalFileName, customFileName: newFileName, type: 'image', uploadTime: new Date().toISOString() }, timeout: 15000, // 15秒超时(图片上传合理时长) success: (uploadFileRes) => { console.log('确认上传-后端原始响应:', uploadFileRes.data); try { const data = JSON.parse(uploadFileRes.data); if (data.code === 200) { uni.navigateTo({ url: '/pages/home/home' }); uni.showModal({ title: '固化成功!', content: '您的证据已保存至“我的证据”', confirmText: '查看证据', cancelText: '继续取证', success: (res) => { if (res.confirm) { // 后端返回的单个证据对象(含 base64Data、webpagePdfBase64 等字段) const singleEvidence = { ...data.data, // 合并previewImage、filePreview等基础信息 // 明确提取PDF相关字段(关键:以你的后端实际返回层级为准) pdfData : data.data.pdfData, // 若后端在data.data下 webpagePdfBase64: data.data.webpagePdfBase64 , // 补充必要字段(确保详情页能正常显示) evidenceType: data.data.evidenceType, evidenceName: data.data.evidenceName, acquisitionTime: data.data.acquisitionTime, // 取证时间(后端未返回则前端生成) timestamp: new Date().getTime() // 用于生成唯一storageKey }; const storageKey = `evidence_single_${singleEvidence.timestamp}`; // 存储完整数据到本地 uni.setStorageSync(storageKey, singleEvidence); console.log('存储的完整证据数据:', singleEvidence); // 跳转时传递 storageKey uni.navigateTo({ url: `/pages/home/components/Imagepreview?storageKey=${storageKey}` }); // 清理临时数据 cancelPreview(); } else { uni.navigateTo({ url: '/pages/home/home' }); } } }); uni.hideLoading() } else { throw new Error(data.msg || `上传失败,状态码: ${data.code}`); } } catch (e) { uni.hideLoading(); uni.showToast({ title: `解析失败: ${e.message}`, icon: 'none', duration: 3000 }); } }, fail: (err) => { // 9. 上传失败处理(网络错误等) console.error('H5确认上传-失败:', err); uni.hideLoading(); uni.showToast({ title: `上传失败: ${err.errMsg}`, icon: 'none', duration: 3000 }); }, complete: () => { // 10. 无论成功失败,重置状态 showProgress.value = false; isUploading.value = false; } }); // 11. 监听上传进度(更新进度条) uploadTask.onProgressUpdate((res) => { progress.value = res.progress; }); }; //视频取证 const takevideo = () => { uni.chooseVideo({ sourceType: ['camera'], compressed: true, maxDuration: 180, camera: 'back', success: (res) => { console.log('录像结果:', res.tempFilePath) if (!res.tempFilePath) { uni.showToast({ title: '未获取到视频文件', icon: 'none' }) return } // 检查视频大小 (限制为100MB) if (res.size > 100 * 1024 * 1024) { uni.showToast({ title: '视频大小不能超过100MB', icon: 'none' }) return } // 准备上传 uploadVideo(res.tempFilePath, res.duration, res.size) }, fail: (err) => { console.error('录像失败:', err) uni.showToast({ title: '录像失败', icon: 'none', }) }, }) } // const downloadAndPreview = (pdfUrl) => { uni.downloadFile({ url: pdfUrl, success: (res) => { if (res.statusCode === 200) { uni.openDocument({ filePath: res.tempFilePath, success: () => console.log('预览成功'), fail: (err) => console.error('打开失败', err), }) } }, }) } // 点击事件处理 const handleClick = (item: EvidenceItem) => { console.log(`点击了:${item.text}`) if (item.action) { item.action() // 如果有自定义回调,优先执行 return } // 默认处理逻辑 switch (item.text) { case '拍照取证': takePhotoAndPreviewPDF() break case '录像取证': takevideo() break case '录音取证': uni.showToast({ title: '录音取证功能开发中', icon: 'none', }) break case '网页取证': uni.navigateTo({ url: '/pages/home/components/Webforensics' }) break case '录屏取证': // uni.showToast({ // title: '录屏取证功能开发中', // icon: 'none' // }); uni.navigateTo({ url: '/pages/home/components/Screenrecord' }) break case '委托取证': uni.showToast({ title: '请联系客服', icon: 'none', }) break default: console.warn('未知的取证类型:', item.text) } } </script> <style scoped> .evidence-card-container { } .card-row { display: flex; flex-direction: row; justify-content: space-around; margin-bottom: 30rpx; } .card-row:last-child { margin-bottom: 0; } .card-item { width: 30%; background-color: #ffffff; display: flex; flex-direction: column; align-items: center; border-radius: 16rpx; text-align: center; margin-right: 20rpx; padding: 20rpx 10rpx; box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); transition: all 0.3s ease; } .card-item:last-child { margin-right: 0; } /* .card-item:hover { transform: translateY(-3rpx); box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15); } */ .item-icon { width: 80rpx; height: 80rpx; margin-bottom: 10rpx; } .item-text { font-size: 24rpx; color: #333; line-height: 1.4; } .photo-preview-mask { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 1); z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; } .preview-content { width: 90%; max-width: 600px; position: relative; } .preview-image { width: 100%; height: 90vh; object-fit: contain; margin-bottom: 20px; border-radius: 8px; } .preview-footer { width: 100%; display: flex; justify-content: space-between; } .preview-btn { flex: 1; height: 44px; line-height: 44px; border-radius: 8px; font-size: 16px; margin: 0 10px; } .cancel-btn { background-color: #2e8bff; color: #fff; } .confirm-btn { background-color: #2e8bff; color: #fff; } </style>
最新发布
08-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

An_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值