// 格式化价格,保留两位小数 export const formatPrice = (value) => { if (!value && value !== 0) return '0.00' return Number(value).toFixed(2) } import { securityFileDownload } from '@/api/FileUpload/FileUpload.js'; import * as pdfjsLib from 'pdfjs-dist'; // 设置PDF.js worker路径(使用CDN) pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js'; // 存储当前页面的弹框实例 let popupInstance = null; let styleInjected = false; // 注入CSS样式 const injectPdfStyle = () => { if (styleInjected) return; const styleId = 'pdf_preview_style'; if (!document.getElementById(styleId)) { const style = document.createElement('style'); style.id = styleId; style.innerHTML = ` .pdf-preview-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 9999; } .pdf-preview-container { width: 95vw; max-width: 900px; height: 90vh; background-color: #fff; border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; animation: pdfFadeIn 0.3s; } @keyframes pdfFadeIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } .pdf-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #eee; background-color: #fff; } .pdf-title { font-size: 16px; font-weight: bold; color: #333; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .pdf-close { font-size: 28px; color: #999; cursor: pointer; padding: 0 8px; line-height: 1; } .pdf-close:hover { color: #333; } .pdf-content { flex: 1; background-color: #525659; position: relative; overflow: auto; padding: 20px; box-sizing: border-box; } .pdf-canvas-container { display: flex; flex-direction: column; align-items: center; gap: 15px; } .pdf-page-canvas { width: 100%; height: auto; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-radius: 4px; background-color: white; } .pdf-footer { display: flex; justify-content: flex-end; padding: 12px 16px; border-top: 1px solid #eee; background-color: #fff; } .pdf-footer button { margin: 0 0 0 8px; min-width: 80px; padding: 8px 16px; border-radius: 4px; border: 1px solid #dcdfe6; background-color: #fff; color: #606266; cursor: pointer; font-size: 14px; } .pdf-footer button:hover { background-color: #f5f7fa; } .pdf-footer button.primary { background-color: #409eff; color: #fff; border-color: #409eff; } .pdf-footer button.primary:hover { background-color: #66b1ff; } .pdf-loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #fff; font-size: 16px; text-align: center; } .pdf-pagination { display: flex; justify-content: center; align-items: center; padding: 12px; background-color: #fff; border-top: 1px solid #eee; } .pdf-pagination button { margin: 0 8px; padding: 4px 12px; border: 1px solid #dcdfe6; background-color: #fff; border-radius: 4px; cursor: pointer; } .pdf-pagination button:disabled { opacity: 0.5; cursor: not-allowed; } .pdf-pagination span { margin: 0 8px; color: #606266; } `; document.head.appendChild(style); styleInjected = true; } }; // H5环境:使用Canvas渲染PDF const createH5Popup = (url, fileName) => { // 先关闭已存在的弹框 if (popupInstance) { document.body.removeChild(popupInstance); popupInstance = null; } // 注入样式 injectPdfStyle(); // 创建遮罩层 const overlay = document.createElement('div'); overlay.className = 'pdf-preview-overlay'; // 创建弹框容器 const container = document.createElement('div'); container.className = 'pdf-preview-container'; // 创建头部 const header = document.createElement('div'); header.className = 'pdf-header'; const title = document.createElement('span'); title.className = 'pdf-title'; title.textContent = fileName || 'PDF预览'; const closeBtn = document.createElement('span'); closeBtn.className = 'pdf-close'; closeBtn.textContent = '×'; closeBtn.onclick = () => { document.body.removeChild(overlay); if (url && url.startsWith('blob:')) { URL.revokeObjectURL(url); } popupInstance = null; }; header.appendChild(title); // header.appendChild(closeBtn); // 创建内容区域 const content = document.createElement('div'); content.className = 'pdf-content'; // 创建Canvas容器 const canvasContainer = document.createElement('div'); canvasContainer.className = 'pdf-canvas-container'; content.appendChild(canvasContainer); // 添加加载提示 const loadingDiv = document.createElement('div'); loadingDiv.className = 'pdf-loading'; loadingDiv.textContent = '正在加载PDF文档...'; content.appendChild(loadingDiv); container.appendChild(header); container.appendChild(content); // 创建底部 const footer = document.createElement('div'); footer.className = 'pdf-footer'; const closeFooterBtn = document.createElement('button'); closeFooterBtn.textContent = '关闭'; closeFooterBtn.onclick = closeBtn.onclick; const downloadBtn = document.createElement('button'); downloadBtn.textContent = '下载'; downloadBtn.className = 'primary'; downloadBtn.onclick = () => { window.open(url); }; // footer.appendChild(downloadBtn); footer.appendChild(closeFooterBtn); container.appendChild(footer); overlay.appendChild(container); document.body.appendChild(overlay); // 使用PDF.js渲染PDF pdfjsLib.getDocument(url).promise.then(pdf => { // 移除加载提示 if (content.contains(loadingDiv)) { content.removeChild(loadingDiv); } // 添加分页控制器 const paginationDiv = document.createElement('div'); paginationDiv.className = 'pdf-pagination'; let currentPage = 1; const totalPages = pdf.numPages; const prevBtn = document.createElement('button'); prevBtn.textContent = '上一页'; prevBtn.disabled = true; const nextBtn = document.createElement('button'); nextBtn.textContent = '下一页'; const pageInfo = document.createElement('span'); pageInfo.textContent = `${currentPage} / ${totalPages}`; prevBtn.onclick = () => { if (currentPage > 1) { currentPage--; renderPage(currentPage); pageInfo.textContent = `${currentPage} / ${totalPages}`; prevBtn.disabled = currentPage === 1; nextBtn.disabled = currentPage === totalPages; } }; nextBtn.onclick = () => { if (currentPage < totalPages) { currentPage++; renderPage(currentPage); pageInfo.textContent = `${currentPage} / ${totalPages}`; prevBtn.disabled = currentPage === 1; nextBtn.disabled = currentPage === totalPages; } }; // paginationDiv.appendChild(prevBtn); // paginationDiv.appendChild(pageInfo); // paginationDiv.appendChild(nextBtn); // content.appendChild(paginationDiv); // 创建Canvas元素 const canvas = document.createElement('canvas'); canvas.className = 'pdf-page-canvas'; canvasContainer.appendChild(canvas); // 渲染指定页面 const renderPage = (pageNumber) => { pdf.getPage(pageNumber).then(page => { // 根据容器宽度计算缩放比例 const containerWidth = content.clientWidth - 40; // 减去padding const viewport = page.getViewport({ scale: 1.0 }); const scale = containerWidth / viewport.width; const scaledViewport = page.getViewport({ scale }); canvas.height = scaledViewport.height; canvas.width = scaledViewport.width; const context = canvas.getContext('2d'); const renderContext = { canvasContext: context, viewport: scaledViewport }; return page.render(renderContext).promise; }); }; // 渲染第一页 renderPage(1); // 监听窗口大小变化,重新渲染 const resizeHandler = () => { renderPage(currentPage); }; window.addEventListener('resize', resizeHandler); // 清理事件监听 const originalClose = closeBtn.onclick; closeBtn.onclick = () => { window.removeEventListener('resize', resizeHandler); originalClose.call(closeBtn); }; }).catch(error => { console.error('PDF渲染失败:', error); if (content.contains(loadingDiv)) { content.removeChild(loadingDiv); } content.innerHTML = `
⚠️ PDF预览失败
${error.message || '未知错误'}
`; }); popupInstance = overlay; overlay.addEventListener('click', (e) => { if (e.target === overlay) { closeBtn.onclick(); } }); return overlay; }; // APP环境:保存Blob到临时文件 const saveBlobToFile = (blob, fileName) => { return new Promise((resolve, reject) => { // #ifdef APP-PLUS const reader = new FileReader(); reader.onload = (e) => { const base64Data = e.target.result.split(',')[1]; const filePath = '_doc/' + Date.now() + '_' + fileName; plus.io.writeFile({ filename: filePath, data: base64Data, success: () => { resolve(filePath); }, fail: (err) => { reject(err); } }); }; reader.onerror = (err) => { reject(err); }; reader.readAsDataURL(blob); // #endif // #ifndef APP-PLUS reject(new Error('非APP环境')); // #endif }); }; // APP环境:使用本地文件预览 const createAppPopup = (filePath, fileName) => { // #ifdef APP-PLUS if (popupInstance) { popupInstance.close(); popupInstance = null; } const popupId = 'pdf_preview_' + Date.now(); const html = `
${fileName || 'PDF预览'} ×
正在加载PDF...