47 il y a 1 semaine
Parent
commit
fdd12a2c7b

+ 3 - 0
package.json

@@ -35,6 +35,7 @@
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^5.1.10",
     "@zxcvbn-ts/core": "^3.0.4",
+    "angular-expressions": "^1.4.3",
     "animate.css": "^4.1.1",
     "axios": "^1.6.8",
     "benz-amr-recorder": "^1.1.5",
@@ -45,6 +46,8 @@
     "dayjs": "^1.11.10",
     "diagram-js": "^12.8.0",
     "docxtemplater": "^3.55.8",
+    "docxtemplater-image-module": "^3.1.0",
+    "docxtemplater-image-module-free": "^1.1.1",
     "driver.js": "^1.3.1",
     "echarts": "^5.5.0",
     "echarts-wordcloud": "^2.1.0",

+ 39 - 0
pnpm-lock.yaml

@@ -38,6 +38,9 @@ importers:
       '@zxcvbn-ts/core':
         specifier: ^3.0.4
         version: 3.0.4
+      angular-expressions:
+        specifier: ^1.4.3
+        version: 1.4.3
       animate.css:
         specifier: ^4.1.1
         version: 4.1.1
@@ -68,6 +71,12 @@ importers:
       docxtemplater:
         specifier: ^3.55.8
         version: 3.55.8
+      docxtemplater-image-module:
+        specifier: ^3.1.0
+        version: 3.1.0
+      docxtemplater-image-module-free:
+        specifier: ^1.1.1
+        version: 1.1.1
       driver.js:
         specifier: ^1.3.1
         version: 1.3.1
@@ -2266,6 +2275,9 @@ packages:
   ajv@8.17.1:
     resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
 
+  angular-expressions@1.4.3:
+    resolution: {integrity: sha512-r7j+dqOuHy0OYiR5AazDixU/Us3TDN2FfuxGX4Dq6d61Y2MhBQHMdUNBfkkLPjDqVm2Is394h31gC3bcBwy9zw==}
+
   animate.css@4.1.1:
     resolution: {integrity: sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==}
 
@@ -3020,6 +3032,16 @@ packages:
     resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
     engines: {node: '>=6.0.0'}
 
+  docxtemplater-image-module-free@1.1.1:
+    resolution: {integrity: sha512-aWOzVQN7ggDYjfoy3pTTNrcrZ7/CJrQcI9cT+hmyHE6nRLR67nt5yPFPe9hm9VWbfYIED2fi+3itOnF0TE/RWQ==}
+
+  docxtemplater-image-module@3.1.0:
+    resolution: {integrity: sha512-dFzuGOhCXgZpzAO7hGJvGbjzUCvid+3L4lSjbBta+TnXuBb/55pqDQWeRZ38yMviu+QTaYreSHHdYHF1XvQlBA==}
+    deprecated: |-
+      This module has been deprecated, No new releases will be made to it.
+
+      There is an up to date paid version of the module which you can find on https://docxtemplater.com/modules/image/
+
   docxtemplater@3.55.8:
     resolution: {integrity: sha512-sDfZA//rrycVK2nSL763ek5+q9O3yzBhJTB+GWG+NBERL/PbYZGVeFl1+nj+fkFblMWo07NCVqM+HVyuHYbQ9Q==}
     engines: {node: '>=0.10'}
@@ -5695,6 +5717,11 @@ packages:
     resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
     engines: {node: '>=12'}
 
+  xmldom@0.1.31:
+    resolution: {integrity: sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==}
+    engines: {node: '>=0.1'}
+    deprecated: Deprecated due to CVE-2021-21366 resolved in 0.5.0
+
   y18n@4.0.3:
     resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
 
@@ -8044,6 +8071,8 @@ snapshots:
       json-schema-traverse: 1.0.0
       require-from-string: 2.0.2
 
+  angular-expressions@1.4.3: {}
+
   animate.css@4.1.1: {}
 
   ansi-escapes@7.0.0:
@@ -8884,6 +8913,14 @@ snapshots:
     dependencies:
       esutils: 2.0.3
 
+  docxtemplater-image-module-free@1.1.1:
+    dependencies:
+      xmldom: 0.1.31
+
+  docxtemplater-image-module@3.1.0:
+    dependencies:
+      xmldom: 0.1.31
+
   docxtemplater@3.55.8:
     dependencies:
       '@xmldom/xmldom': 0.9.6
@@ -11848,6 +11885,8 @@ snapshots:
 
   xml-name-validator@4.0.0: {}
 
+  xmldom@0.1.31: {}
+
   y18n@4.0.3: {}
 
   y18n@5.0.8: {}

BIN
public/templates/ceshi.docx


+ 0 - 0
public/templates/templete.docx → src/assets/templete.docx


+ 46 - 0
src/utils/doc.js

@@ -2,6 +2,8 @@ import Docxtemplater from 'docxtemplater'
 import PizZip from 'pizzip'
 import JSZipUtils from 'jszip-utils'
 import { saveAs } from 'file-saver'
+import ImageModule from 'docxtemplater-image-module-free'
+import expressions from 'angular-expressions'
  
 /**
  4. 导出docx
@@ -9,6 +11,7 @@ import { saveAs } from 'file-saver'
  6. @param { Object } data 文件中传入的数据
  7. @param { String } fileName 导出文件名称
 */
+
 export const exportDocx = (tempDocxPath, data, fileName) => {
   // 读取并获得模板文件的二进制内容
   JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
@@ -22,6 +25,25 @@ export const exportDocx = (tempDocxPath, data, fileName) => {
     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);
+        }
+        console.error(`未找到图片路径: ${tagValue}`);
+        return null;
+      },
+      getSize: (img, tagValue) => {
+        return [100, 100]; // 宽高调整
+      }
+    });
     const doc = new Docxtemplater().loadZip(zip)
     console.log(doc)
     doc.setData(data)
@@ -47,4 +69,28 @@ export const exportDocx = (tempDocxPath, data, fileName) => {
     }) // 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}`);
+    }
+    return new Uint8Array(await response.arrayBuffer());
+  }
 }

+ 47 - 20
src/views/system/studentSelectSupervisorRecord/record.vue

@@ -294,28 +294,55 @@ watch(selectedRows, (newSelection) => {
 });
 
 /** 导出按钮操作 */
-const ibj = ref({
-  name: '示例名称',
-  conditionCons: [
-    {
-      groupName: '条件组 1',
-      cont: '条件内容 1'
-    },
-    {
-      groupName: '条件组 2',
-      cont: '条件内容 2'
-    }
-  ]
-});
+// 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 () => {
-  const fileName = '导出文档.docx';
+  if (selectedRows.value.length === 0) {
+    message.error('请先选择需要导出的数据!');
+    return;
+   }
+
+  const ibj = selectedRows.value.map((row, index) => ({
+    studentName: row.studentName,
+    userNumber: row.userNumber,
+    major: row.major,
+    mobile: row.mobile,
+    nickname: row.nickname,
+    title: row.title,
+    studentAchievementRequirement: row.studentAchievementRequirement,
+    studentSignDate: row.studentSignDate,
+    supervisorSignDate: row.supervisorSignDate,
+    studentSignature: `studentSignature_${index + 1}`, // 使用占位符
+    supervisorSignature: `supervisorSignature_${index + 1}` // 使用占位符
+  }));
+  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';
   try {
-    const response = await axios.get('/templates/templete.docx', {
-      responseType: 'blob' // 确保以 blob 形式获取文件
-    });
-    
-    // 使用你之前的 exportDocx 方法处理文件
-    exportDocx(URL.createObjectURL(response.data), ibj.value, fileName);
+    exportDocx("/templates/ceshi.docx", data, fileName);
   } catch (error) {
     console.error('导出文档失败:', error);
   }