zhaoen il y a 4 mois
Parent
commit
7994494f70

+ 1 - 1
src/config/net.config.js

@@ -5,7 +5,7 @@ const network = {
   // 默认的接口地址 如果是开发环境和生产环境走vab-mock-server,当然你也可以选择自己配置成需要的接口地址
   baseURL:
     process.env.NODE_ENV === "development"
-      ? "http://10.168.1.152:7000/evods"
+      ? "http://10.168.1.152:7000/sl-boot"
       : "/sl-boot",
   //配后端数据的接收方式application/json;charset=UTF-8或者application/x-www-form-urlencoded;charset=UTF-8
   contentType: "application/json;charset=UTF-8",

+ 10 - 2
src/views/planningSchem/comprehensive/index.vue

@@ -80,6 +80,7 @@ import DarkLayout from '@/components/GlobalComponents/DarkLayout.vue'
 import InterferenceCard from '@/components/Components/InterferenceCard.vue'
 import DarkDialog from "@/components/Components/DarkDialog.vue";
 import {planningSchemePage} from "@/api/planningScheme";
+import {exportSolutionToWord} from "@/views/planningSchem/comprehensive/wordExporter";
 
 export default {
   components: {
@@ -195,9 +196,16 @@ export default {
       this.$router.push({ path: '/planningSchem/overallPlanDesign',query:{batchId:plan.batchId} })
     },
     //导出
-    handleExportPlan() {
-      this.$message.success("导出成功!")
+    async handleExportPlan(plan) {
+      try {
+        await exportSolutionToWord(plan.batchId);
+        this.$message.success('导出Word成功');
+      } catch (error) {
+        this.$message.error(error.message || '导出Word失败');
+      }
+      // this.$message.success("导出成功!")
     },
+
     async handleQuery() {
       // 查询逻辑
       const res = await planningSchemePage({

Fichier diff supprimé car celui-ci est trop grand
+ 456 - 405
src/views/planningSchem/comprehensive/overallPlanDesign.vue


+ 310 - 0
src/views/planningSchem/comprehensive/wordExporter.js

@@ -0,0 +1,310 @@
+import { saveAs } from 'file-saver';
+import { schemeChapterTree } from "@/api/planningScheme";
+
+/**
+ * 导出指定批次的靶标保障方案为Word文档(优化排版版)
+ * @param {string} batchId - 批次ID
+ * @param {string} [docName='靶标保障方案'] - 自定义文档名称(可选)
+ */
+export async function exportSolutionToWord(batchId, docName = '靶标保障方案') {
+    try {
+        // 获取并处理数据
+        const treeData = await getSchemeTree(batchId);
+        const createDate = formatDate(new Date());
+        const version = "V1.0";
+
+        // 生成带优化排版的HTML
+        const htmlContent = generateOptimizedHtml(docName, version, createDate, treeData);
+
+        // 生成Word文档
+        const blob = new Blob(['\ufeff', htmlContent], {
+            type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+        });
+        saveAs(blob, `${docName}_${createDate}.docx`);
+        return true;
+    } catch (error) {
+        console.error('导出Word失败:', error);
+        throw new Error('导出Word文档失败,请重试');
+    }
+}
+
+/**
+ * 获取方案树形结构数据
+ */
+async function getSchemeTree(batchId) {
+    try {
+        const res = await schemeChapterTree({ batchId });
+        const treeList = res.data || [];
+        processTreeData(treeList);
+        return treeList;
+    } catch (error) {
+        console.error('获取方案数据失败:', error);
+        throw new Error('获取方案数据失败');
+    }
+}
+
+/**
+ * 处理树形结构数据
+ */
+function processTreeData(nodes) {
+    nodes.forEach(node => {
+        // 处理表格类型数据
+        if (node.chapterType === '0' && node.chapterValue) {
+            try {
+                const data = JSON.parse(node.chapterValue);
+                node.data = data.data || [];
+                node.columns = data.columns || [];
+            } catch (e) {
+                console.warn('解析表格数据失败', e);
+                node.data = [];
+                node.columns = [];
+            }
+        }
+
+        // 递归处理子节点
+        if (node.children && node.children.length) {
+            processTreeData(node.children);
+        }
+    });
+}
+
+/**
+ * 格式化日期为yyyy-mm-dd格式
+ */
+function formatDate(date) {
+    return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
+}
+
+/**
+ * 生成优化排版的HTML内容
+ */
+function generateOptimizedHtml(title, version, createDate, treeList) {
+    // 文档样式定义 - 重点优化图片大小控制
+    const styles = `
+    <style>
+      /* 基础样式 */
+      body {
+        font-family: "SimSun", "宋体", serif;
+        font-size: 14px;
+        line-height: 1.5;
+        margin: 0;
+        padding: 50px; /* 页边距 */
+        color: #333333;
+      }
+      
+      /* 页面设置 */
+      @page {
+        size: A4;
+        margin: 2.5cm 2cm;
+        @top-center { content: "${title}"; font-size: 12px; color: #666; }
+        @bottom-center { content: "第 " counter(page) " 页"; font-size: 12px; color: #666; }
+      }
+      
+      /* 标题样式 */
+      .document-title { text-align: center; font-size: 22px; font-weight: bold; margin: 0 0 40px 0; padding-bottom: 10px; border-bottom: 2px solid #333; }
+      .document-meta { text-align: center; margin: 0 0 50px 0; font-size: 14px; line-height: 2; }
+      
+      /* 章节标题样式 */
+      .heading-1 { font-size: 18px; font-weight: bold; margin: 30px 0 15px 0; page-break-after: avoid; }
+      .heading-2 { font-size: 16px; font-weight: bold; margin: 25px 0 12px 0; padding-left: 20px; page-break-after: avoid; }
+      .heading-3 { font-size: 15px; font-weight: bold; margin: 20px 0 10px 0; padding-left: 40px; page-break-after: avoid; }
+      
+      /* 段落样式 */
+      p { margin: 0 0 16px 0; text-align: justify; text-justify: inter-ideograph; }
+      
+      /* 表格样式 */
+      .data-table { border-collapse: collapse; width: 100%; margin: 20px 0; page-break-inside: avoid; }
+      .data-table th, .data-table td { border: 1px solid #333; padding: 8px 12px; text-align: center; vertical-align: middle; }
+      .data-table th { background-color: #f2f2f2; font-weight: bold; }
+      .data-table tr:nth-child(even) td { background-color: #f9f9f9; }
+      
+      /* 图片样式 - 增强Word兼容性 */
+      .image-container {
+        height: 300px;
+        margin: 25px 0;
+        text-align: center;
+        page-break-inside: avoid;
+      }
+      
+      /* 基础图片样式 - 使用width而非max-width提高兼容性 */
+      .document-image {
+        width: 50%;
+        height: auto;
+        border: 1px solid #ddd;
+        padding: 5px;
+        margin: 10px 0;
+      }
+      
+      /* 小型图片样式 */
+      .document-image.small {
+        width: 50%;
+      }
+      
+      /* 大型图片强制缩小 */
+      .document-image.large {
+        width: 60%;
+      }
+      
+      .image-caption {
+        font-size: 13px;
+        color: #666;
+        margin-top: 5px;
+        text-align: center;
+      }
+      
+      /* 内容区块样式 */
+      .section { margin-bottom: 25px; }
+      .rich-content { margin-bottom: 20px; }
+      .rich-content ul, .rich-content ol { margin: 10px 0 10px 20px; padding-left: 20px; }
+      .rich-content li { margin-bottom: 8px; }
+    </style>
+  `;
+
+    // 生成HTML主体内容
+    let html = `
+    <html xmlns:o="urn:schemas-microsoft-com:office:office"
+          xmlns:w="urn:schemas-microsoft-com:office:word"
+          xmlns="http://www.w3.org/TR/REC-html40">
+      <head>
+        <meta charset="UTF-8">
+        <title>${title}</title>
+        <!-- Word特定设置 -->
+        <!--[if gte mso 9]><xml>
+          <w:WordDocument>
+            <w:View>Print</w:View>
+            <w:Zoom>100</w:Zoom>
+            <w:PunctuationKerning/>
+            <w:ValidateAgainstSchemas/>
+            <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
+            <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
+            <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
+            <w:DoNotPromoteQF/>
+            <w:LidThemeOther>EN-US</w:LidThemeOther>
+            <w:LidThemeAsian>ZH-CN</w:LidThemeAsian>
+            <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
+          </w:WordDocument>
+        </xml><![endif]-->
+        ${styles}
+      </head>
+      <body>
+        <h1 class="document-title">${title}</h1>
+        <div class="document-meta">
+          <p>版本:${version}</p>
+          <p>生成日期:${createDate}</p>
+        </div>
+        
+        ${generateSectionsHtml(treeList, 1)}
+      </body>
+    </html>
+  `;
+
+    return html;
+}
+
+/**
+ * 生成章节HTML(带层级结构)
+ */
+function generateSectionsHtml(nodes, level) {
+    if (!nodes || nodes.length === 0) return '';
+
+    let html = '';
+    nodes.forEach((node, index) => {
+        // 生成章节标题(带层级)
+        const headingClass = `heading-${level}`;
+        const headingTag = `h${Math.min(level, 6)}`;
+
+        html += `<div class="section">`;
+        html += `<${headingTag} class="${headingClass}">${node.chapterName || '未命名章节'}</${headingTag}>`;
+
+        // 富文本内容
+        if (node.chapterType === '1' && node.chapterValue) {
+            html += `<div class="rich-content">${node.chapterValue}</div>`;
+        }
+
+        // 表格内容
+        if (node.chapterType === '0' && node.data && node.columns && node.columns.length) {
+            html += '<table class="data-table">';
+            html += '<thead><tr>';
+            node.columns.forEach(col => {
+                html += `<th>${col.label || ''}</th>`;
+            });
+            html += '</tr></thead>';
+            html += '<tbody>';
+            node.data.forEach((row, rowIndex) => {
+                html += `<tr class="${rowIndex % 2 === 0 ? 'even-row' : 'odd-row'}">`;
+                node.columns.forEach(col => {
+                    html += `<td>${row[col.prop] !== undefined && row[col.prop] !== null ? row[col.prop] : ''}</td>`;
+                });
+                html += '</tr>';
+            });
+            html += '</tbody></table>';
+        }
+
+        // 图片内容 - 增强大小控制
+        if (node.chapterType === '2' && node.fileJson) {
+            try {
+                const files = JSON.parse(node.fileJson);
+                if (files && files.length) {
+                    html += '<div class="images-section">';
+                    files.forEach((file, imgIndex) => {
+                        if (file.fileHttp) {
+                            // 根据图片尺寸选择合适的样式类
+                            let imageClass = 'document-image';
+
+                            // 如果有尺寸信息,使用更精确的控制
+                            if (file.width && file.height) {
+                                // 宽高比大于2的图片视为宽图,进一步缩小
+                                const aspectRatio = file.width / file.height;
+                                if (aspectRatio > 2) {
+                                    imageClass += ' small';
+                                }
+                            }
+                            // 没有尺寸信息则根据文件大小判断
+                            else if (file.fileSize) {
+                                // 大于3MB的图片强制缩小
+                                if (file.fileSize > 3 * 1024 * 1024) {
+                                    imageClass += ' large';
+                                }
+                            }
+
+                            // 添加Word特定的尺寸控制标记
+                            html += `
+                <div class="image-container">
+                  <!--[if gte mso 9]><xml>
+                    <o:OfficeDocumentSettings>
+                      <o:AllowPNG/>
+                    </o:OfficeDocumentSettings>
+                  </xml><![endif]-->
+                  <img src="${file.fileHttp}" class="${imageClass}"  height="200"
+                       alt="${file.fileName || `图片${imgIndex + 1}`}"
+                       ${file.width ? `width="${Math.min(file.width, 600)}"` : ''}>
+                  ${file.fileName ? `<div class="image-caption">图 ${getImageNumber(node, imgIndex)}:${file.fileName}</div>` : ''}
+                </div>
+              `;
+                        }
+                    });
+                    html += '</div>';
+                }
+            } catch (e) {
+                console.warn('解析图片数据失败', e);
+                html += '<p class="error-message">图片数据解析失败</p>';
+            }
+        }
+
+        // 递归处理子节点
+        if (node.children && node.children.length) {
+            html += generateSectionsHtml(node.children, level + 1);
+        }
+
+        html += `</div>`;
+    });
+    return html;
+}
+
+/**
+ * 生成图片编号
+ */
+function getImageNumber(node, imgIndex) {
+    return `${imgIndex + 1}`;
+}
+

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff