47 1 tydzień temu
rodzic
commit
8587803de2

BIN
public/templates/ceshi.docx


+ 4 - 1
src/api/system/studentSelectSupervisorRecord/index.ts

@@ -66,6 +66,9 @@ export const studentSelectSupervisorRecordApi = {
   withdrawStudentSelectSupervisorRecord: async (data: studentSelectSupervisorRecordVO) => {
     return await request.put({ url: `/system/student-select-supervisor-record/withdraw`, data })
   },
-
+  // 互选表打印数据列表
+  getSelectionBookList: async (data: studentSelectSupervisorRecordVO) => {
+    return await request.put({ url: `/system/student-select-supervisor-record/getSelectionBookList`, data })
+  },
 
 }

+ 80 - 89
src/utils/doc.js

@@ -1,96 +1,87 @@
-import Docxtemplater from 'docxtemplater'
-import PizZip from 'pizzip'
-import JSZipUtils from 'jszip-utils'
-import { saveAs } from 'file-saver'
+import JSZip from 'jszip';
+import { saveAs } from 'file-saver';
+import JSZipUtils from 'jszip-utils';
+import PizZip from 'pizzip';
+import Docxtemplater from 'docxtemplater';
 import ImageModule from 'docxtemplater-image-module-free'
-import expressions from 'angular-expressions'
- 
-/**
- 4. 导出docx
- 5. @param { String } tempDocxPath 模板文件路径
- 6. @param { Object } data 文件中传入的数据
- 7. @param { String } fileName 导出文件名称
-*/
 
-export const exportDocx = (tempDocxPath, data, fileName) => {
-  // 读取并获得模板文件的二进制内容
-  JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
-    if (error) {
-        console.error("获取文件时出现错误:", error);
-        throw error;
-    }
-    console.log("Content type:", typeof content);
-    console.log("获取到的内容:", content); 
-    console.log("获取到的内容长度:", content.byteLength);
-    const uint8Array = new Uint8Array(content);
-    console.log("文件内容字节:", uint8Array);
-    const zip = new PizZip(content)
-    // 处理图片
-    const imageModule = new ImageModule({
-      getImage: async (tagValue) => {
-        if (tagValue.startsWith('studentSignature')) {
-          const imagePath = data.images[tagValue]; // 获取学生签名路径
-          console.log(`学生签名路径: ${imagePath}`);
-          return await loadImage(imagePath);
-        } else if (tagValue.startsWith('supervisorSignature')) {
-          const imagePath = data.images[tagValue]; // 获取导师签名路径
-          console.log(`导师签名路径: ${imagePath}`);
-          return await loadImage(imagePath);
+// function base64ToUint8Array(base64) {
+//   const base64Data = base64.split(',')[1]; // 去掉前缀 "data:image/png;base64,"
+//   const binaryString = atob(base64Data); // 解码 Base64
+//   const length = binaryString.length;
+//   const uint8Array = new Uint8Array(length);
+//   for (let i = 0; i < length; i++) {
+//     uint8Array[i] = binaryString.charCodeAt(i);
+//   }
+//   return uint8Array;
+// }
+export const exportDocx = async (tempDocxPath, dataList, zipFileName) => {
+  try {
+    // 加载模板文件
+    const content = await new Promise((resolve, reject) => {
+      JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
+        if (error) {
+          reject(error);
+        } else {
+          resolve(content);
         }
-        console.error(`未找到图片路径: ${tagValue}`);
-        return null;
-      },
-      getSize: (img, tagValue) => {
-        return [100, 100]; // 宽高调整
-      }
+      });
     });
-    const doc = new Docxtemplater().loadZip(zip)
-    console.log(doc)
-    doc.setData(data)
-    try {
-      // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
-      doc.render()
-    } catch (error) {
-      const e = {
-        message: error.message,
-        name: error.name,
-        stack: error.stack,
-        properties: error.properties
+
+    // 初始化 JSZip 实例,用于打包多个文件
+    const zip = new JSZip();
+
+    // 遍历每一条数据,生成单独的 .docx 文件
+    for (let i = 0; i < dataList.length; i++) {
+      const data = dataList[i];
+      // if (data.studentSignature) {
+      //   data.studentSignature = {
+      //     data: base64ToUint8Array(data.studentSignature),
+      //     width: 100, // 图片宽度(单位:像素)
+      //     height: 50, // 图片高度(单位:像素)
+      //   };
+      // }
+      // if (data.supervisorSignature) {
+      //   data.supervisorSignature = {
+      //     data: base64ToUint8Array(data.supervisorSignature),
+      //     width: 100, // 图片宽度(单位:像素)
+      //     height: 50, // 图片高度(单位:像素)
+      //   };
+      // }
+      const zipInstance = new PizZip(content);
+      const doc = new Docxtemplater().loadZip(zipInstance);
+       // 加载图片模块
+      //  const imageModule = new ImageModule({
+      //   centered: false, // 图片是否居中
+      //   getImage: (tagValue) => tagValue.data, // 获取图片数据
+      //   getSize: (tagValue) => [tagValue.width, tagValue.height], // 获取图片尺寸
+      // });
+      // doc.attachModule(imageModule);
+      doc.setData(data);
+
+      try {
+        doc.render(); // 渲染模板
+      } catch (error) {
+        console.error(`渲染第 ${i + 1} 条数据时出错:`, error);
+        throw error;
       }
-      console.log({
-        error: e
-      })
-      // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
-      throw error
-    }
-    const out = doc.getZip().generate({
-      type: 'blob',
-      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
-    }) // Output the document using Data-URI
-    saveAs(out, fileName)
-  })
-}
-/**
- * 加载图片
- * @param { String } url 图片的 URL 或 Base64 编码
- * @returns { Promise<Uint8Array> } 图片的 Uint8Array 数据
- */
-const loadImage = async (url) => {
-  if (url.startsWith('data:image')) {
-    // 处理 Base64 编码
-    const base64Data = url.split(',')[1];
-    const byteCharacters = atob(base64Data);
-    const byteNumbers = new Array(byteCharacters.length);
-    for (let i = 0; i < byteCharacters.length; i++) {
-      byteNumbers[i] = byteCharacters.charCodeAt(i);
-    }
-    return new Uint8Array(byteNumbers);
-  } else {
-    // 处理 URL
-    const response = await fetch(url);
-    if (!response.ok) {
-      throw new Error(`加载图片时出现错误: ${response.statusText}`);
+
+      // 生成 .docx 文件
+      const out = doc.getZip().generate({
+        type: 'blob',
+        mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+      });
+
+      // 将生成的 .docx 文件添加到 zip 包中
+      zip.file(`document_${i + 1}.docx`, out);
     }
-    return new Uint8Array(await response.arrayBuffer());
+
+    // 生成 zip 文件并保存
+    const zipBlob = await zip.generateAsync({ type: 'blob' });
+    saveAs(zipBlob, zipFileName);
+    console.log(`文件已成功生成并打包为 ${zipFileName}`);
+  } catch (error) {
+    console.error('导出文件时出错:', error);
+    throw error;
   }
-}
+};

+ 9 - 33
src/views/system/studentSelectSupervisorRecord/record.vue

@@ -91,7 +91,7 @@
           <el-form-item>
             <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
             <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-            <el-button
+            <!-- <el-button
               type="success"
               plain
               @click="handleExport"
@@ -99,7 +99,7 @@
               v-hasPermi="['system:student-select-supervisor-record:export']"
             >
               <Icon icon="ep:download" class="mr-5px" /> 导出
-            </el-button>
+            </el-button> -->
             <el-button type="primary" @click="exportWordTemplate" :loading="exportLoading">批量导出互选表</el-button>
           </el-form-item>
         </el-form>
@@ -294,29 +294,13 @@ watch(selectedRows, (newSelection) => {
 });
 
 /** 导出按钮操作 */
-// const rows = selectedRows.value;
-// const ibj = rows.map((row) => ({
-//   studentName: row.studentName,
-//   userNumber: row.userNumber,
-//   major: row.major,
-//   mobile: row.mobile,
-//   nickname: row.nickname,
-//   title: row.title,
-//   studentAchievementRequirement: row.studentAchievementRequirement,
-//   studentSignature: row.studentSignature,
-//   studentSignDate: row.studentSignDate,
-//   supervisorSignature: row.supervisorSignature,
-//   supervisorSignDate: row.supervisorSignDate
-// }));
-// console.log("导出的数据对象:", ibj);
-
 const exportWordTemplate = async () => {
   if (selectedRows.value.length === 0) {
     message.error('请先选择需要导出的数据!');
     return;
    }
 
-  const ibj = selectedRows.value.map((row, index) => ({
+  const dataList = selectedRows.value.map((row) => ({
     studentName: row.studentName,
     userNumber: row.userNumber,
     major: row.major,
@@ -326,23 +310,15 @@ const exportWordTemplate = async () => {
     studentAchievementRequirement: row.studentAchievementRequirement,
     studentSignDate: row.studentSignDate,
     supervisorSignDate: row.supervisorSignDate,
-    studentSignature: `studentSignature_${index + 1}`, // 使用占位符
-    supervisorSignature: `supervisorSignature_${index + 1}` // 使用占位符
+    studentSignature: row.studentSignature,
+    supervisorSignature: row.supervisorSignature
   }));
-  const images = {};
-  selectedRows.value.forEach((row, index) => {
-    images[`studentSignature_${index + 1}`] = row.studentSignature; // 确保这是图片的 URL 或 Base64 编码
-    images[`supervisorSignature_${index + 1}`] = row.supervisorSignature; // 确保这是图片的 URL 或 Base64 编码
-  });
-  console.log("导出的数据对象:", ibj);
 
-  const data = {
-    records: ibj,
-    images: images
-  };
-  const fileName = '师生互选表.docx';
+  console.log("导出的数据对象:", dataList);
+    
+  const zipFileName = '师生互选表.zip';
   try {
-    exportDocx("/templates/ceshi.docx", data, fileName);
+    exportDocx("/templates/ceshi.docx", dataList, zipFileName);
   } catch (error) {
     console.error('导出文档失败:', error);
   }