| | |
| | | <template> |
| | | <div> |
| | | <el-button id="button" type="primary" @click="printReports" style="background: #409eff; position: fixed; top: 90px; right: 90px; padding: 20px; color: white; border: none; cursor: pointer; margin-right: 10px;"> |
| | | <el-button id="button" type="primary" @click="previewReport" style="position: fixed; top: 90px; right: 40px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;"> |
| | | 预览 |
| | | </el-button> |
| | | <el-button id="button" type="primary" @click="handlePrint" style="position: fixed; top: 90px; right: 20px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;"> |
| | | 打印 |
| | | </el-button> |
| | | <!-- <el-button id="button" type="primary" @click="printReport" style="position: fixed; top: 90px; right: 20px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;">--> |
| | | <!-- 打印--> |
| | | <!-- </el-button>--> |
| | | |
| | | <div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px;"> |
| | | <span>工程编号:</span> |
| | |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div v-if="pdfUrl" style="margin-top: 20px;"> |
| | | <iframe |
| | | :src="pdfUrl" |
| | | style="width: 100%; height: 800px; border: 1px solid #ddd;" |
| | | title="PDF预览"> |
| | | </iframe> |
| | | </div> |
| | | |
| | | <div ref="printContainer" style="position: relative;"> |
| | | <RectRenderer |
| | | <RectRenderer |
| | | ref="rectRenderer" |
| | | :layoutData="layoutData" |
| | | :layoutData="layoutData" |
| | | :gw="currentGw" |
| | | :gh="currentGh" |
| | | :printLayout="printLayout" |
| | |
| | | const materialDetails = ref(); |
| | | const injectedProjectNo = inject('projectNo', null); |
| | | const state = ref(); |
| | | const columnTypes = ['一列', '两列', '三列', '四列'] |
| | | const rowTypes = ['一行', '两行'] |
| | | const columnTypes = ['一列', '两列'] |
| | | const rowTypes = ['一行', '两行', '三行', '四行'] |
| | | const glassInfo = ['不显示', '显示在右侧', '显示在下侧'] |
| | | const cutInfo = ['不显示', '显示'] |
| | | const filePath = ref(''); |
| | | |
| | | const pdfUrl = ref(''); |
| | | |
| | | // 定义不同布局对应的尺寸 |
| | | const layoutDimensions = { |
| | |
| | | }); |
| | | }; |
| | | |
| | | const printReports = async() => { |
| | | const generateReport = async() => { |
| | | try { |
| | | // 确保有数据可以提交 |
| | | if (!processId) { |
| | |
| | | // 映射 rowTypes 到 layoutRows |
| | | const layoutRowsMap = { |
| | | '一行': 1, |
| | | '两行': 2 |
| | | '两行': 2, |
| | | '三行': 3, |
| | | '四行': 4 |
| | | }; |
| | | |
| | | // 映射 columnTypes 到 layoutColumns |
| | | const layoutColumnsMap = { |
| | | '一列': 1, |
| | | '两列': 2, |
| | | '三列': 3, |
| | | '四列': 4 |
| | | }; |
| | | |
| | | // 映射 glassInfo 到 glassInfoShow |
| | |
| | | } |
| | | }); |
| | | |
| | | if (response.code == 200) { |
| | | ElMessage.success('保存成功'); |
| | | filePath.value = response.data[0]; |
| | | console.log('filePath:', filePath.value); |
| | | } else { |
| | | ElMessage.error('保存失败,请稍后再试'); |
| | | } |
| | | |
| | | } catch (error) { |
| | | console.error('保存失败:', error); |
| | | ElMessage.error('保存失败,请稍后再试'); |
| | | } |
| | | }; |
| | | |
| | | const printReport = async () => { |
| | | try { |
| | | await generateReport(); |
| | | if (!filePath.value) { |
| | | ElMessage.error('未收到有效的PDF文件路径'); |
| | | return; |
| | | } |
| | | const encodedFilePath = encodeURIComponent(filePath.value); |
| | | |
| | | const response = await request.get('/glassOptimize/reports/pdf', { |
| | | params: { filePath: encodedFilePath }, |
| | | responseType: 'blob', |
| | | headers: { |
| | | 'Accept': 'application/pdf' |
| | | } |
| | | }); |
| | | |
| | | // 检查响应数据是否存在且有效 |
| | | if (!response) { |
| | | ElMessage.error('未能获取到PDF数据'); |
| | | return; |
| | | } |
| | | |
| | | const blob = new Blob([response], { type: 'application/pdf' }); |
| | | |
| | | // 检查 blob 是否有效 |
| | | if (blob.size === 0) { |
| | | ElMessage.error('接收到空的PDF文件'); |
| | | return; |
| | | } |
| | | |
| | | const url = URL.createObjectURL(blob); |
| | | |
| | | // 创建隐藏的 iframe |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.position = 'fixed'; |
| | | iframe.style.left = '0'; |
| | | iframe.style.top = '0'; |
| | | iframe.style.width = '0'; |
| | | iframe.style.height = '0'; |
| | | iframe.style.border = 'none'; |
| | | iframe.src = url; |
| | | |
| | | // 标记是否已经清理过资源 |
| | | let isCleanedUp = false; |
| | | // 清理资源函数 |
| | | const cleanup = () => { |
| | | if (isCleanedUp) return; |
| | | isCleanedUp = true; |
| | | URL.revokeObjectURL(url); |
| | | if (iframe.parentNode) { |
| | | iframe.parentNode.removeChild(iframe); |
| | | } |
| | | }; |
| | | |
| | | iframe.onload = () => { |
| | | setTimeout(() => { |
| | | try { |
| | | // 确保 iframe 内容已加载完成 |
| | | if (iframe.contentWindow) { |
| | | iframe.contentWindow.focus(); |
| | | |
| | | // 监听打印事件(某些浏览器支持) |
| | | const handleAfterPrint = () => { |
| | | window.removeEventListener('afterprint', handleAfterPrint); |
| | | // 延迟清理,确保打印完成 |
| | | setTimeout(cleanup, 3000); |
| | | }; |
| | | |
| | | window.addEventListener('afterprint', handleAfterPrint); |
| | | |
| | | // 执行打印 |
| | | iframe.contentWindow.print(); |
| | | ElMessage.success('报告生成成功,已启动打印...'); |
| | | |
| | | // 如果浏览器不支持 afterprint 事件,设置超时清理 |
| | | setTimeout(cleanup, 10000); |
| | | } |
| | | } catch (printError) { |
| | | console.error('打印过程中出错:', printError); |
| | | // 如果程序化打印失败,至少打开 PDF 供用户手动打印 |
| | | window.open(url, '_blank'); |
| | | ElMessage.info('已打开PDF文件,请手动打印'); |
| | | cleanup(); |
| | | } |
| | | }, 1000); // 给更多时间确保PDF完全渲染 |
| | | }; |
| | | |
| | | iframe.onerror = () => { |
| | | console.error('PDF 加载失败'); |
| | | ElMessage.error('PDF 文件加载失败,请重试'); |
| | | cleanup(); |
| | | }; |
| | | |
| | | document.body.appendChild(iframe); |
| | | |
| | | } catch (error) { |
| | | console.error('打印流程异常:', error); |
| | | |
| | | if (error.response) { |
| | | const status = error.response.status; |
| | | if (status === 400) { |
| | | ElMessage.error('文件路径无效或不是PDF'); |
| | | } else if (status === 404) { |
| | | ElMessage.error('PDF 文件不存在'); |
| | | } else { |
| | | ElMessage.error(`服务器错误 (${status}),请稍后再试`); |
| | | } |
| | | } else if (error.request) { |
| | | ElMessage.error('网络错误,请检查连接'); |
| | | } else { |
| | | ElMessage.error('打印失败,请稍后再试'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | const previewReport = async () => { |
| | | try { |
| | | await generateReport(); |
| | | if (!filePath.value) { |
| | | ElMessage.error('未收到有效的PDF文件路径'); |
| | | return; |
| | | } |
| | | const encodedFilePath = encodeURIComponent(filePath.value); |
| | | |
| | | const response = await request.get('/glassOptimize/reports/pdf', { |
| | | params: { filePath: encodedFilePath }, |
| | | responseType: 'blob', |
| | | headers: { |
| | | 'Accept': 'application/pdf' |
| | | } |
| | | }); |
| | | |
| | | // 检查响应数据是否存在且有效 |
| | | if (!response) { |
| | | ElMessage.error('未能获取到PDF数据'); |
| | | return; |
| | | } |
| | | |
| | | const blob = new Blob([response], { type: 'application/pdf' }); |
| | | |
| | | // 检查 blob 是否有效 |
| | | if (blob.size === 0) { |
| | | ElMessage.error('接收到空的PDF文件'); |
| | | return; |
| | | } |
| | | |
| | | // 创建PDF URL并赋值给pdfUrl用于界面显示 |
| | | const url = URL.createObjectURL(blob); |
| | | pdfUrl.value = url; |
| | | |
| | | ElMessage.success('报告生成成功,正在预览...'); |
| | | |
| | | // 可选:添加清理机制,当组件卸载时清理URL |
| | | // 这里可以使用 onUnmounted 钩子进行清理 |
| | | } catch (error) { |
| | | console.error('预览流程异常:', error); |
| | | |
| | | if (error.response) { |
| | | const status = error.response.status; |
| | | if (status === 400) { |
| | | ElMessage.error('文件路径无效或不是PDF'); |
| | | } else if (status === 404) { |
| | | ElMessage.error('PDF 文件不存在'); |
| | | } else { |
| | | ElMessage.error(`服务器错误 (${status}),请稍后再试`); |
| | | } |
| | | } else if (error.request) { |
| | | ElMessage.error('网络错误,请检查连接'); |
| | | } else { |
| | | ElMessage.error('预览失败,请稍后再试'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const autoPreviewReport = async () => { |
| | | try { |
| | | await generateReport(); |
| | | if (!filePath.value) { |
| | | // 如果没有文件路径,不执行预览 |
| | | return; |
| | | } |
| | | const encodedFilePath = encodeURIComponent(filePath.value); |
| | | |
| | | const response = await request.get('/glassOptimize/reports/pdf', { |
| | | params: { filePath: encodedFilePath }, |
| | | responseType: 'blob', |
| | | headers: { |
| | | 'Accept': 'application/pdf' |
| | | } |
| | | }); |
| | | |
| | | // 检查响应数据是否存在且有效 |
| | | if (!response) { |
| | | ElMessage.error('未能获取到PDF数据'); |
| | | return; |
| | | } |
| | | |
| | | const blob = new Blob([response], { type: 'application/pdf' }); |
| | | |
| | | // 检查 blob 是否有效 |
| | | if (blob.size === 0) { |
| | | ElMessage.error('接收到空的PDF文件'); |
| | | return; |
| | | } |
| | | |
| | | // 创建PDF URL并赋值给 pdfUrl 用于界面显示 |
| | | const url = URL.createObjectURL(blob); |
| | | pdfUrl.value = url; |
| | | |
| | | } catch (error) { |
| | | console.error('自动预览流程异常:', error); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // 优先使用注入的 projectNo,其次使用 props,最后使用 localStorage |
| | | if (injectedProjectNo) { |
| | | processId.value = injectedProjectNo.value || injectedProjectNo; |
| | | } else if (props.project) { |
| | | processId.value = props.project.projectNumber || ''; |
| | | state.value = props.state; |
| | | } else if (savedProjectNo) { |
| | | processId.value = savedProjectNo; |
| | | } |
| | | |
| | | if (processId.value) { |
| | | selectLayout(); |
| | | selectReportData(); |
| | | selectMaterialData(); |
| | | selectProductData(); |
| | | |
| | | // 数据加载完成后自动预览 |
| | | setTimeout(() => { |
| | | autoPreviewReport(); |
| | | }, 1000); // 延迟1秒确保所有数据加载完成 |
| | | } |
| | | }); |
| | | |
| | | const config = reactive({ |
| | | columnTypes: '两列', |
| | |
| | | currentGh.value = dimensions.height; |
| | | currentPrintWidth.value = dimensions.width; |
| | | currentPrintHeight.value = dimensions.height; |
| | | |
| | | |
| | | if (rectRenderer.value) { |
| | | rectRenderer.value.updateLayout(); |
| | | } |