廖井涛
5 小时以前 f7a2fcdda7f1120498c5c5f75c5a99955fc54b43
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/OptimizationRectPrint.vue
@@ -1,47 +1,48 @@
<template>
  <div>
    <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="printReport" style="position: fixed; top: 90px; right: 20px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;">-->
<!--    <el-button id="button" type="primary" @click="printReports" 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="previewReport"
        :loading="loading"      style="position: fixed; top: 90px; right: 40px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;"
        :disabled="loading">
      {{ loading ? '生成中...' : '预览' }}
    </el-button>
    <div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px;">
      <span>工程编号:</span>
      <el-input readonly placeholder="" style="width: 150px" v-model="processId"></el-input>&nbsp;
      <el-checkbox v-model="config.printLayouts">
        打印版图
      </el-checkbox>
      <el-checkbox v-model="config.printReport">
        打印报告
      </el-checkbox>
      <div style="margin-right: 30px;"></div>
      <span>布局选择:</span>
      <el-select v-model="config.columnTypes"  style="width: 120px;">
        <el-option v-for="type in columnTypes" :key="type" :value="type" />
      </el-select>
      <el-select v-model="config.rowTypes"  style="width: 120px;">
        <el-option v-for="type in rowTypes" :key="type" :value="type" />
      </el-select>
    </div>
    <div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px;">
      <span>显示小片信息:</span>
      <el-select v-model="config.glassInfo"  style="width: 120px;">
        <el-option v-for="type in glassInfo" :key="type" :value="type" />
      </el-select>
      <span>显示切割信息:</span>
      <el-select v-model="config.cutInfo"  style="width: 120px;">
        <el-option v-for="type in cutInfo" :key="type" :value="type" />
      </el-select>
    </div>
    <div v-if="pdfUrl" style="margin-top: 20px;">
    <div v-if="pdfUrl || pdfLoading" style="margin-top: 20px;">
      <!-- PDF加载时显示美化后的加载动画 -->
      <div v-if="pdfLoading" style="display: flex; justify-content: center; align-items: center; height: 800px; border: 1px solid #ddd; background-color: #f5f5f5;">
        <div style="text-align: center;">
          <div class="loading-animation">
            <div class="dot-flashing"></div>
          </div>
          <p style="margin-top: 20px; font-size: 18px; color: #666;">PDF文档加载中...</p>
          <p style="font-size: 14px; color: #999; margin-top: 10px;">正在为您准备预览内容</p>
        </div>
      </div>
      <!-- PDF加载完成时显示PDF -->
      <iframe
          :src="pdfUrl"
          style="width: 100%; height: 800px; border: 1px solid #ddd;"
          v-else
          :src="pdfUrl"          style="width: 100%; height: 780px; border: 1px solid #ddd;"
          title="PDF预览">
      </iframe>
    </div>
    <div v-else style="margin-top: 20px;">
      <div style="display: flex; justify-content: center; align-items: center; height: 780px; border: 1px solid #ddd; background-color: white;">
        <div style="text-align: center; color: #999;">
          <p style="font-size: 20px; margin-bottom: 10px;">优化报告预览区</p>
          <p style="font-size: 14px;">点击上方"预览"按钮生成并查看优化报告</p>
        </div>
      </div>
    </div>
    <div ref="printContainer" style="position: relative;">
@@ -70,6 +71,9 @@
import request from "@/utils/request";
import {ElMessage, ElMessageBox} from "element-plus";
import requestOptimize from "@/utils/requestOptimize";
import useUserInfoStore from "@/stores/userInfo";
const userStore = useUserInfoStore();
const props = defineProps({
  project : null,
@@ -82,18 +86,22 @@
const layoutData = ref();
const optimizeUse = ref();
const reportData = ref();
const layoutSet = ref();
const materialList = ref();
const productList = ref();
const dataLoaded = ref(false);
const materialDetails = ref();
const injectedProjectNo = inject('projectNo', null);
const state = ref();
const columnTypes = ['一列', '两列']
const rowTypes = ['一行', '两行', '三行', '四行']
const glassInfo = ['不显示', '显示在右侧', '显示在下侧']
const cutInfo = ['不显示', '显示']
const filePath = ref('');
const loading = ref(false);
const pdfLoading = ref(false);
const printLayouts = ref();
const printReport = ref();
const layoutRows = ref();
const layoutColumns = ref();
const glassInfoShow = ref();
const cutInfoShow = ref();
const username = userStore.user.userName;
const pdfUrl = ref('');
@@ -152,6 +160,30 @@
      });
};
const fetchSettings = async (username) => {
  try {
    const response = await request.post(`/glassOptimize/selectOptimizeParms/${username}`);
    if (response.code == 200) {
      if (!response.data) {
        console.error('响应数据为空');
        return;
      }
      const parsedData = JSON.parse(response.data);
      console.log('设置内容:', parsedData);
      printLayouts.value = parsedData.server.printLayouts;
      printReport.value = parsedData.server.printReport;
      layoutRows.value = parsedData.server.layoutRows;
      layoutColumns.value = parsedData.server.layoutColumns;
      glassInfoShow.value = parsedData.server.glassInfoShow;
      cutInfoShow.value = parsedData.server.cutInfoShow;
    } else {
      console.error('请求失败,状态码:', response.code);
    }
  } catch (error) {
    console.error('请求发生错误:', error);
  }
};
const selectMaterialData= () => {
  request.post(`/glassOptimize/materialInfo/${processId.value}`)
@@ -199,33 +231,6 @@
      return;
    }
    // 映射 rowTypes 到 layoutRows
    const layoutRowsMap = {
      '一行': 1,
      '两行': 2,
      '三行': 3,
      '四行': 4
    };
    // 映射 columnTypes 到 layoutColumns
    const layoutColumnsMap = {
      '一列': 1,
      '两列': 2,
    };
    // 映射 glassInfo 到 glassInfoShow
    const glassInfoMap = {
      '不显示': 0,
      '显示在右侧': 1,
      '显示在下侧': 2
    };
    // 映射 cutInfo 到 cutInfoShow
    const cutInfoMap = {
      '不显示': 0,
      '显示': 1
    };
    const response = await requestOptimize.post('/api/reports', {
      fileName: processId.value,
      projectNo: processId.value,
@@ -233,8 +238,8 @@
      glassThickness : optimizeUse.value.thickness,
      glassType : optimizeUse.value.model,
      quantity : String(optimizeUse.value.processingQuantity),
      printLayouts : config.printLayouts ? '1' : '0',
      printReport : config.printReport ? '1' : '0',
      printLayouts : printLayouts.value || '0',
      printReport : printReport.value || '0',
      layouts : layoutData.value,
      reportData:{
        rectangleQuantity: reportData.value.rectangleQuantity,
@@ -247,10 +252,10 @@
        productList: productList.value,
      },
      layoutSet: {
        layoutRows: layoutRowsMap[config.rowTypes] || 1,
        layoutColumns: layoutColumnsMap[config.columnTypes] || 1,
        glassInfoShow: glassInfoMap[config.glassInfo] || 0,
        cutInfoShow: cutInfoMap[config.cutInfo] || 0
        layoutRows: parseInt(layoutRows.value) || 2,
        layoutColumns: parseInt(layoutColumns.value) || 2,
        glassInfoShow: parseInt(glassInfoShow.value) || 0,
        cutInfoShow: parseInt(cutInfoShow.value) || 0
      }
    }, {
@@ -273,7 +278,7 @@
  }
};
const printReport = async () => {
const printReports = async () => {
  try {
    await generateReport();
    if (!filePath.value) {
@@ -393,12 +398,18 @@
const previewReport = async () => {
  try {
    loading.value = true;
    ElMessage.info('正在生成报告,请稍候...')
    await generateReport();
    if (!filePath.value) {
      ElMessage.error('未收到有效的PDF文件路径');
      loading.value = false;
      return;
    }
    const encodedFilePath = encodeURIComponent(filePath.value);
    // 设置PDF加载状态为true
    pdfLoading.value = true;
    const response = await request.get('/glassOptimize/reports/pdf', {
      params: { filePath: encodedFilePath },
@@ -411,6 +422,8 @@
    // 检查响应数据是否存在且有效
    if (!response) {
      ElMessage.error('未能获取到PDF数据');
      loading.value = false;
      pdfLoading.value = false; // 设置PDF加载状态为false
      return;
    }
@@ -419,6 +432,8 @@
    // 检查 blob 是否有效
    if (blob.size === 0) {
      ElMessage.error('接收到空的PDF文件');
      loading.value = false;
      pdfLoading.value = false; // 设置PDF加载状态为false
      return;
    }
@@ -427,12 +442,17 @@
    pdfUrl.value = url;
    ElMessage.success('报告生成成功,正在预览...');
    loading.value = false;
    // 可选:添加清理机制,当组件卸载时清理URL
    // 这里可以使用 onUnmounted 钩子进行清理
    // 延迟一小段时间后设置PDF加载完成,确保用户能看到加载状态
    setTimeout(() => {
      pdfLoading.value = false;
    }, 500);
  } catch (error) {
    console.error('预览流程异常:', error);
    loading.value = false;
    pdfLoading.value = false; // 设置PDF加载状态为false
    if (error.response) {
      const status = error.response.status;
      if (status === 400) {
@@ -449,70 +469,6 @@
    }
  }
};
// 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: '两列',
@@ -541,7 +497,9 @@
    selectReportData();
    selectMaterialData();
    selectProductData();
    fetchSettings(username);
  }
});
const handlePrint = () => {
@@ -568,3 +526,56 @@
  handleLayoutChange();
});
</script>
<style scoped>
.loading-animation {
  display: flex;
  justify-content: center;
  align-items: center;
}
.dot-flashing {
  position: relative;
  width: 10px;
  height: 10px;
  border-radius: 5px;
  background-color: #409eff;
  color: #409eff;
  animation: dotFlashing 1s infinite linear alternate;
  animation-delay: .5s;
}
.dot-flashing::before, .dot-flashing::after {
  content: '';
  display: inline-block;
  position: absolute;
  top: 0;
  width: 10px;
  height: 10px;
  border-radius: 5px;
  background-color: #409eff;
  color: #409eff;
}
.dot-flashing::before {
  left: -15px;
  animation: dotFlashing 1s infinite alternate;
  animation-delay: 0s;
}
.dot-flashing::after {
  left: 15px;
  animation: dotFlashing 1s infinite alternate;
  animation-delay: 1s;
}
@keyframes dotFlashing {
  0% {
    background-color: #409eff;
  }
  50%,
  100% {
    background-color: #c0d9f7;
  }
}
</style>