Browse Source

Merge remote-tracking branch 'origin/master'

yzx 1 tháng trước cách đây
mục cha
commit
3636f3d07c

+ 5 - 2
package.json

@@ -22,7 +22,7 @@
     "lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
     "lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
     "lint:style": "stylelint --fix \"./src/**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
-    "lint:lint-staged": "lint-staged -c "
+    "lint:lint-staged": "lint-staged -c " 
   },
   "dependencies": {
     "@element-plus/icons-vue": "^2.1.0",
@@ -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",
@@ -156,4 +159,4 @@
     "node": ">= 16.0.0",
     "pnpm": ">=8.6.0"
   }
-}
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 237 - 201
pnpm-lock.yaml


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 })
+  },
 
 }

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


+ 1 - 1
src/router/modules/remaining.ts

@@ -166,7 +166,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
     children: [
       {
         path: '/redirect/:path(.*)',
-        name: 'Redirect',
+        name: 'RedirectDetail',
         component: () => import('@/views/Redirect/Redirect.vue'),
         meta: {}
       }

+ 76 - 47
src/utils/doc.js

@@ -1,50 +1,79 @@
-import Docxtemplater from 'docxtemplater'
-import PizZip from 'pizzip'
-import JSZipUtils from 'jszip-utils'
-import { saveAs } from 'file-saver'
- 
-/**
- 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;
+import JSZip from 'jszip';
+import { saveAs } from 'file-saver';
+import JSZipUtils from 'jszip-utils';
+import Docxtemplater from 'docxtemplater';
+import ImageModule from 'docxtemplater-image-module-free';
+
+const loadImage = async (tagValue) => {
+  try {
+    const response = await fetch(tagValue);
+    if (!response.ok) {
+      throw new Error('Network response was not ok');
     }
-    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 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
+    const blob = await response.blob();
+    return URL.createObjectURL(blob);
+  } catch (error) {
+    console.error('There was a problem with the fetch operation:', error);
+    return null; // 返回 null 或者合适的错误处理
+  }
+};
+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);
+        }
+      });
+    });
+
+    // 初始化 JSZip 实例,用于打包多个文件
+    const zip = new JSZip();
+
+    // 遍历每一条数据,生成单独的 .docx 文件
+    for (let i = 0; i < dataList.length; i++) {
+      const data = dataList[i];
+
+      const imageOptions = {
+        async getImage(tagValue) {
+          const imageUrl = await loadImage(tagValue);
+          console.log(imageUrl, "我在这里");
+          return imageUrl;
+        },
+        getSize() {
+          return [150, 150];
+        },
+      };
+      const doc = new Docxtemplater(zip, {
+        modules: new ImageModule(imageOptions),
+      });
+      doc.render({
+        image: "logo.png",
+      });
+      const zipContent = doc.getZip(); // 获取 zip 对象
+      if (!zipContent) {
+        throw new Error('Docxtemplater failed to load zip content.');
       }
-      console.log({
-        error: e
-      })
-      // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
-      throw error
+
+      // 生成 .docx 文件
+      const out = await zipContent.generateAsync({
+        type: 'blob',
+        mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+      });
+
+      // 将生成的 .docx 文件添加到 zip 包中
+      zip.file(`document_${i + 1}.docx`, out);
     }
-    const out = doc.getZip().generate({
-      type: 'blob',
-      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
-    }) // Output the document using Data-URI
-    saveAs(out, fileName)
-  })
-}
+
+    // 生成 zip 文件并保存
+    const zipBlob = await zip.generateAsync({ type: 'blob' });
+    saveAs(zipBlob, zipFileName);
+    console.log(`文件已成功生成并打包为 ${zipFileName}`);
+  } catch (error) {
+    console.error('导出文件时出错:', error);
+    throw error;
+  }
+};

+ 1 - 1
src/views/Redirect/Redirect.vue

@@ -2,7 +2,7 @@
   <div></div>
 </template>
 <script lang="ts" setup>
-defineOptions({ name: 'Redirect' })
+defineOptions({ name: 'RedirectDetail' })
 
 const { currentRoute, replace } = useRouter()
 const { params, query } = unref(currentRoute)

+ 33 - 22
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>
@@ -210,6 +210,8 @@ import {DICT_TYPE} from "@/utils/dict";
 import studentSelectSupervisorRecordForm from './studentSelectSupervisorRecordForm.vue'
 import {studentSelectionProjectApi} from "@/api/system/studentSelectionProject"
 import { exportDocx } from '@/utils/doc.js';
+import { selectionBookApi } from '@/api/system/studentSelectSupervisorRecord/selectionBook';
+
 // import docxtemplater from "docxtemplater"
 // import PizZip from "pizzip"
 // import JSZipUtils from "jszip-utils"
@@ -294,32 +296,41 @@ watch(selectedRows, (newSelection) => {
 });
 
 /** 导出按钮操作 */
-const ibj = ref({
-  name: '示例名称',
-  conditionCons: [
-    {
-      groupName: '条件组 1',
-      cont: '条件内容 1'
-    },
-    {
-      groupName: '条件组 2',
-      cont: '条件内容 2'
-    }
-  ]
-});
 const exportWordTemplate = async () => {
-  const fileName = '导出文档.docx';
-  try {
-    const response = await axios.get('/templates/templete.docx', {
-      responseType: 'blob' // 确保以 blob 形式获取文件
-    });
+  if (selectedRows.value.length === 0) {
+    message.error('请先选择需要导出的数据!');
+    return;
+  }
+  const dataList = await Promise.all(selectedRows.value.map(async (row) => {
+    // 获取每一行的详细信息
+    const selectionBook = await selectionBookApi.getSelectionBook(row.id);
+    console.log(selectionBook);
+    return {
+      studentName: selectionBook.studentName,
+      userNumber: selectionBook.studentNumber,
+      major: selectionBook.major,
+      mobile: selectionBook.studentMobile,
+      nickname: selectionBook.supervisor,
+      // title: selectionBook.title,
+      title: selectionBook.supervisor,
+      studentAchievementRequirement: selectionBook.studentAchievementRequirement,
+      studentSignDate: new Date(selectionBook.studentSignDate).toLocaleDateString(),
+      supervisorSignDate: new Date(selectionBook.supervisorSignDate).toLocaleDateString(),
+      // studentSignature: selectionBook.studentSignature,
+      supervisorSignature: selectionBook.supervisorSignature,
+      studentSignature: "/logo.png"
+    };
+  }));
+  console.log("导出的数据对象:", dataList);
     
-    // 使用你之前的 exportDocx 方法处理文件
-    exportDocx(URL.createObjectURL(response.data), ibj.value, fileName);
+  const zipFileName = '师生互选表.zip';
+  try {
+    exportDocx("/templates/ceshi.docx", dataList, zipFileName);
   } catch (error) {
     console.error('导出文档失败:', error);
   }
 };
+
 // const exportWordTemplate = async () => {
 //   if (selectedRows.value.length === 0) {
 //     message.error('请先选择需要导出的数据!');

+ 3 - 3
src/views/system/userDetail/teacher.vue

@@ -21,7 +21,7 @@
         </el-form-item>
       </el-col>
     </el-row>
-    <el-row>
+    <el-row v-if="userInfo.userType==='5'">
       <el-col :span="24" >
         <el-form-item label="外聘导师" style="font-weight: 550;">
           <p></p>
@@ -33,14 +33,14 @@
         </el-form-item>
       </el-col>
     </el-row>
-    <el-row  >
+    <el-row v-if="userInfo.userType==='5'">
       <el-col :span="24">
         <el-form-item label="合作的校内导师" prop="supervisor">
           <el-input v-model="formData.supervisor" placeholder="自动链接" :disabled="!isSupervisor"/>
         </el-form-item>
       </el-col>
     </el-row>
-    <el-row  >
+    <el-row>
       <el-col :span="24">
         <el-form-item label="研究方向" prop="major">
           <el-input v-model="formData.major" placeholder="请输入研究方向" :disabled="!isSupervisor" />

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác