Explorar o código

添加评价账号和评价进度的excel导出

lm hai 6 días
pai
achega
fa3731e8b5

+ 2 - 1
src/api/evaluationProgressComponent.ts

@@ -33,7 +33,8 @@ export const reviewAccountDataExportExcelApi = (data:any) => {
     return request({
         url: `${teacherPrefix}/api/v1/progress/exportEvaluationData`,
         method: 'post',
-        data
+        data,
+        responseType: 'blob' 
     })
 }
 

+ 97 - 0
src/baseComponents/useTableExcelExport.ts

@@ -0,0 +1,97 @@
+import ExcelJS from 'exceljs';
+
+
+
+// 单sheet页导出
+//前端 导出 Excel
+export const useTableExcelExport = async (tableColumn:any[],tableData:any[],sheetName='sheet',excelName='excel' ) => {
+  // 1. 提取表头
+  const headers = tableColumn.map(column => column.label || column.name);
+
+  // 2. 创建工作簿和工作表
+  const workbook = new ExcelJS.Workbook();
+  const worksheet = workbook.addWorksheet(sheetName);
+
+  // 3. 添加表头行
+  const headerRow = worksheet.addRow(headers);
+  
+  // 4. 定义表头样式
+  headerRow.eachCell((cell) => {
+    cell.style = {
+      font: { name: 'Microsoft YaHei', size: 12, bold: true, color: { argb: 'FF333333' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4F6F8' } },
+      border: {
+        top: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+        left: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+        bottom: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+        right: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+      },
+      alignment: { vertical: 'middle', horizontal: 'left', wrapText: true },
+    };
+  });
+
+  // 5. 添加数据行 __ 这个需要修改 ——待完善 ,数组形式 和 普通字符串形式
+  tableData.forEach(row => {
+    
+    const rowData = tableColumn.map(column => {
+      const cellValue = row[column.name];
+      if (cellValue && Array.isArray(cellValue) && cellValue.length > 0) {
+        // 数组形式的处理方式,待定
+        return '-'
+        return cellValue.map((item: any) => item.label || '').join('\n');
+      }
+      return cellValue != null ? String(cellValue) : '-';
+    });
+
+    const excelRow = worksheet.addRow(rowData);
+
+    // 6. 定义数据行样式
+    excelRow.eachCell({ includeEmpty: true }, (cell) => {
+      cell.style = {
+        font: { name: 'Microsoft YaHei', size: 12, color: { argb: 'FF333333' } },
+        border: {
+          top: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+          left: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+          bottom: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+          right: { style: 'thin', color: { argb: 'FFD9D9D9' } },
+        },
+        alignment: { vertical: 'top', horizontal: 'left', wrapText: true },
+      };
+    });
+
+    // 7. 处理分组表头样式(仅针对每行的第一个单元格)
+    if (row.isHeader) {
+        // 获取该行的第一个单元格(列索引从 1 开始)
+        const firstCell = excelRow.getCell(1); 
+        // 合并原有字体样式并加粗
+        firstCell.font = { ...firstCell.font, bold: true };
+        // 设置背景色
+        firstCell.fill = { 
+            type: 'pattern', 
+            pattern: 'solid', 
+            fgColor: { argb: 'FFF4F6F8' } 
+        };
+    }
+  });
+
+  // 8. 设置列宽
+  worksheet.columns = headers.map(() => ({ width: 25 }));
+
+  // 9. 导出文件
+  const buffer = await workbook.xlsx.writeBuffer();
+  const blob = new Blob([buffer], { 
+    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
+  });
+  
+  const url = URL.createObjectURL(blob);
+  const link = document.createElement('a');
+  link.href = url;
+  link.download = `${excelName}_${new Date().toISOString().slice(0, 10)}.xlsx`;
+  link.style.visibility = 'hidden';
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+  URL.revokeObjectURL(url);
+};
+
+

+ 29 - 13
src/utils/request.ts

@@ -32,22 +32,38 @@ service.interceptors.response.use(
   (response: AxiosResponse) => {
     const res = response.data
 
-    if (res.code !== 200) {
-      ElMessage({
-        message: res.msg || '请求失败',
-        type: 'error',
-        duration: 5 * 1000
-      })
+    // 如果是文件流,走另外的判断
+    if(!(res instanceof  Blob)){
+      if (res.code !== 200) {
+        ElMessage({
+          message: res.msg || '请求失败',
+          type: 'error',
+          duration: 5 * 1000
+        })
 
-      // 特殊状态码处理,如 token 失效等
-      if (res.code === 401) {
-        // 跳转登录页
-        window.location.href = '/'
-      }
+        // 特殊状态码处理,如 token 失效等
+        if (res.code === 401) {
+          // 跳转登录页
+          window.location.href = '/'
+        }
 
-      return Promise.reject(res.msg || '请求失败')
+        return Promise.reject(res.msg || '请求失败')
+      }
+    }else{
+      if(response.status !== 200){
+        ElMessage({
+          message: res.msg || '请求失败',
+          type: 'error',
+          duration: 5 * 1000
+        })
+        return Promise.reject(res.msg || '请求失败')
+      }else{
+        return {
+          data:res,
+          code:200
+        }
+      }
     }
-
     return res
   },
   (error) => {

+ 17 - 8
src/views/reviewManagement/stepComponent/evaluationProgressComponent/ReviewAccountTableData.vue

@@ -12,7 +12,7 @@
                         @searchChange="HandleSearchChange">
                     </FormSearchGroup>
                  
-                    <el-button class="el-button-refresh" @click="HandleExportExcel">导出Excel</el-button>
+                    <el-button class="button_refresh" @click="HandleExportExcel">导出Excel</el-button>
                 </div>
             </div>
         </div>
@@ -141,23 +141,32 @@ const GetGradeList = async ()=> {
 }
 
 
-// 处理excel导出  —— 待完善
+// 处理excel导出
 const HandleExportExcel = async ()=>{
      let params = {
         evaluationGenderStatus:null,  //性别 必传,值为空
         evaluationId: route.query.id,
         evaluationGradeId: searchParams.value.grade == 'all' ? '' : searchParams.value.grade,  //年级id
-        pageNum: currentPage.value,
-        pageSize: pageSize.value,
         evaluationStatus: searchParams.value.status == 'all' ? '' : searchParams.value.status     // 评价码状态
     }
     let res = await reviewAccountDataExportExcelApi(params)
-
     if(res?.code == 200){
-        // 待完善
-
+        const blob =  new Blob([res.data], {
+            type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
+        });
+
+        // 3. 创建指向该 Blob 的临时 URL
+        const url = window.URL.createObjectURL(blob);
+        const link = document.createElement('a');
+        link.href = url;
+        link.download = '评价账号使用统计表.xlsx'; 
+        document.body.appendChild(link);
+        link.click();
+
+        // 清理内存
+        document.body.removeChild(link);
+        window.URL.revokeObjectURL(url);
     }
-
 }
 
 onMounted(async()=>{

+ 19 - 6
src/views/reviewManagement/stepComponent/evaluationProgressComponent/ReviewProcessTableData.vue

@@ -8,7 +8,7 @@
                         <div class="grade_title">年级评价进度统计表</div>
                     </div>
                     <div class="content_right">
-                        <el-button class="el-button-refresh">导出Excel</el-button>
+                        <el-button class="button_refresh" @click="HandleExportExcel('grade')">导出Excel</el-button>
                     </div>
                 </div>
             </div>
@@ -28,7 +28,7 @@
                     </div>
                     <div class="content_right">
                         <el-select 
-                            @change="(val)=>handleSelectChange(val)"
+                            @change="(val)=>HandleSelectChange(val)"
                             v-model="gradeSearchId"  placeholder="请选择">
                             <el-option
                                 v-for="selectItem in gradeOptionList"
@@ -37,7 +37,7 @@
                                 :value="selectItem.value"
                             />
                         </el-select>
-                        <el-button class="el-button-refresh">导出Excel</el-button>
+                        <el-button class="button_refresh" @click="HandleExportExcel('class')">导出Excel</el-button>
                     </div>
                 </div>
             </div>
@@ -58,6 +58,7 @@ import { useRoute } from 'vue-router';
 import { getEvaluationProgressStatisticsApi } from '@/api/evaluationProgressComponent.js';
 import {reviewProcessTableColumns} from  './table'
 
+import {useTableExcelExport} from '@/baseComponents/useTableExcelExport'
 
 const route = useRoute()
 
@@ -72,9 +73,8 @@ const gradeSearchId = ref('')  //默认的年级筛选项
 const gradeOptionList = ref([])  //年级下拉项
 
 const classTableData = ref([])
-const handleSelectChange = (val) =>{
-
-
+const HandleSelectChange = (val) =>{
+    classTableData.value = classReviewBarData?.[val]
 }
 
 // 获取评价进度统计表数据
@@ -95,6 +95,19 @@ const GetReviewProcessTableData = async () =>{
             classReviewBarData[item.id] = item.classData
         })
         classTableData.value = classReviewBarData?.[gradeSearchId.value]
+        
+    }
+}
+
+const HandleExportExcel = (type)=>{
+    let finalTableColumn = reviewProcessTableColumns.value.slice(1)
+    switch(type){
+        case 'grade':
+            useTableExcelExport(finalTableColumn,gradeTableData.value,'年级评价进度统计表','年级评价进度统计表')
+            break
+        case 'class':
+            useTableExcelExport(finalTableColumn,classTableData.value,'班级评价进度统计表','班级评价进度统计表')
+            break;
     }
 }