于杰
2025-10-20 a54533effa355753fedbd53508d8f29964320a6a
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/OptimizationRectPrint.vue
@@ -1,11 +1,11 @@
<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>
@@ -36,10 +36,18 @@
      </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"
@@ -81,10 +89,13 @@
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 = {
@@ -180,7 +191,7 @@
      });
};
const printReports = async() => {
const generateReport = async() => {
  try {
    // 确保有数据可以提交
    if (!processId) {
@@ -191,15 +202,15 @@
    // 映射 rowTypes 到 layoutRows
    const layoutRowsMap = {
      '一行': 1,
      '两行': 2
      '两行': 2,
      '三行': 3,
      '四行': 4
    };
    // 映射 columnTypes 到 layoutColumns
    const layoutColumnsMap = {
      '一列': 1,
      '两列': 2,
      '三列': 3,
      '四列': 4
    };
    // 映射 glassInfo 到 glassInfoShow
@@ -248,13 +259,260 @@
      }
    });
    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: '两列',
@@ -299,7 +557,7 @@
  currentGh.value = dimensions.height;
  currentPrintWidth.value = dimensions.width;
  currentPrintHeight.value = dimensions.height;
  if (rectRenderer.value) {
    rectRenderer.value.updateLayout();
  }