Parcourir la source

前端批量下载报告

zhangjie il y a 2 ans
Parent
commit
f255350772

+ 37 - 0
src/api/allAnalysisPage.ts

@@ -52,3 +52,40 @@ export function batchExportProjectReport(params: {
 }) {
   return httpApp.post("/api/ess/project/report/export", {}, { params });
 }
+
+// 报告导出流程api ----->
+// 获取报告导出任务信息
+export function getProjectReportTask(params: {
+  compareProjectId?: number;
+  projectId: number;
+}) {
+  return httpApp.post<
+    any,
+    {
+      data: {
+        paperIds: number[];
+        taskId: number;
+      };
+    }
+  >("/api/ess/report/task/export", {}, { params });
+}
+// 上传报告html内容,后台生成报告pdf
+export function uploadProjectReportCont(params: {
+  taskId: number;
+  paperId: number;
+  htmlContent: string;
+}) {
+  return httpApp.post("/api/ess/report/task/html", { params });
+}
+// 报告文件生成进度结果查询
+export function getProjectReportResult(taskId: number) {
+  return httpApp.post<
+    any,
+    {
+      data: {
+        filePath: string;
+        status: string;
+      };
+    }
+  >("/api/ess/report/task/result", { taskId });
+}

+ 2 - 29
src/features/allAnalysis/AllAnalysis2.vue

@@ -9,7 +9,7 @@
       <span class="tw-mr-4"></span>
       <a-button @click="exportExcel">导出excel</a-button>
       <span class="tw-mr-4"></span>
-      <a-button @click="exportReport">导出报告</a-button>
+      <!-- <a-button @click="exportReport">导出报告</a-button> -->
 
       <div class="tw-float-right tw-flex tw-gap-2">
         <!-- <a-button @click="goProjectPapers(projectId)"> 试卷列表 </a-button> -->
@@ -56,8 +56,6 @@
         <ScoreFirstTryRate :courseId="courseId" />
       </div>
     </div>
-
-    <SelectProject ref="selectProjectRef" @confirm="projectSelected" />
   </div>
 </template>
 
@@ -67,16 +65,11 @@ import { goBack, downloadFileURL } from "@/utils/utils";
 import { onMounted } from "vue";
 import { useRoute } from "vue-router";
 import router from "@/router";
-import {
-  getSasPaperList,
-  batchExportProjectReport,
-} from "@/api/allAnalysisPage";
+import { getSasPaperList } from "@/api/allAnalysisPage";
 import { getProjectList } from "@/api/projectManagementPage";
 // import EventBus from "@/plugins/eventBus";
 import ScoreRate from "./ScoreRate.vue";
 import ScoreFirstTryRate from "./ScoreFirstTryRate.vue";
-import SelectProject from "../paperAnalysis/SelectProject.vue";
-import { message } from "ant-design-vue";
 
 import { SASPaper, Project } from "@/types";
 
@@ -306,8 +299,6 @@ async function tableChange(
 //   });
 // }
 
-let selectProjectRef = $ref(null);
-
 async function getProject() {
   const res = await getProjectList({
     id: projectId,
@@ -317,22 +308,4 @@ async function getProject() {
   });
   curProject = res.data.content[0];
 }
-function exportReport() {
-  if (curProject && curProject.needCompute) {
-    void message.info("有数据更新请重新计算");
-    return;
-  }
-  // @ts-ignore
-  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-  selectProjectRef.showModal();
-}
-async function projectSelected(compareProjectId: number) {
-  console.log(compareProjectId);
-
-  await batchExportProjectReport({
-    projectId,
-    compareProjectId,
-  });
-  void message.success("导出任务已经提交,请在任务管理中查询导出结果!");
-}
 </script>

+ 243 - 0
src/features/report/ReportBatchDownload.vue

@@ -0,0 +1,243 @@
+<template>
+  <a-button @click="exportReport">导出报告</a-button>
+
+  <!-- card-view-frame -->
+  <div v-if="reportPreviewUrl" class="report-preview-frame">
+    <iframe :src="reportPreviewUrl" frameborder="0"></iframe>
+  </div>
+
+  <SelectProject ref="selectProjectRef" @confirm="projectSelected" />
+
+  <a-modal
+    v-model:visible="loadModalVisible"
+    dialogClass="report-load-modal"
+    centered
+    :closable="false"
+    :keyboard="false"
+    :maskClosable="false"
+  >
+    <div class="report-load-body">
+      <LoadingOutlined />
+      <div class="report-load-progress">
+        <p v-for="(item, index) in progressList" :key="index">
+          {{ item.title }}...
+          <span v-if="item.loading">
+            <LoadingOutlined /><i v-if="item.progress"
+              >{{ item.progress }}%</i
+            ></span
+          >
+          <span v-else>完成</span>
+        </p>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script setup lang="ts">
+import { Project } from "@/types";
+import { message } from "ant-design-vue";
+import SelectProject from "../paperAnalysis/SelectProject.vue";
+import {
+  getProjectReportTask,
+  uploadProjectReportCont,
+  getProjectReportResult,
+} from "@/api/allAnalysisPage";
+import { useRouter } from "vue-router";
+import { onBeforeMount, onMounted } from "vue";
+const router = useRouter();
+
+interface ProgressItemType {
+  title: string;
+  progress: number;
+  loading: boolean;
+}
+
+const props = defineProps<{
+  curProject: Project;
+}>();
+
+let selectProjectRef = $ref(null);
+let taskId = $ref(undefined as unknown as number);
+let compareProjectId = $ref(undefined as unknown as number);
+let curPaperId = $ref<number>();
+let paperIds = $shallowRef<number[]>([]);
+let finishPaperIds = $shallowRef<number[]>([]);
+let reportPreviewUrl = $ref<string>("");
+let setTs = $shallowRef<number[]>([]);
+let progressList = $ref<ProgressItemType[]>([]);
+let totalTaskCount = $ref(1);
+let loadModalVisible = $ref(false);
+
+function addProgress(data: ProgressItemType) {
+  progressList.push(data);
+}
+function updateProgress(progress: number) {
+  let data = progressList[progressList.length - 1];
+  data.progress = progress;
+  if (progress === 100) data.loading = false;
+}
+function getPaperProgress() {
+  return Math.floor((10000 * finishPaperIds.length) / totalTaskCount) / 100;
+}
+
+function closeLoadModal() {
+  loadModalVisible = false;
+  progressList = [];
+  paperIds = [];
+  finishPaperIds = [];
+  clearSetTs();
+}
+
+function clearSetTs() {
+  if (!setTs.length) return;
+  setTs.forEach((t) => clearTimeout(t));
+  setTs = [];
+}
+
+function exportReport() {
+  if (props.curProject && props.curProject.needCompute) {
+    void message.info("有数据更新请重新计算");
+    return;
+  }
+  // @ts-ignore
+  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+  selectProjectRef.showModal();
+}
+async function projectSelected(projectId: number) {
+  loadModalVisible = true;
+  compareProjectId = projectId;
+  addProgress({
+    title: "构建任务",
+    progress: 0,
+    loading: true,
+  });
+  const res = await getProjectReportTask({
+    projectId: props.curProject.id,
+    compareProjectId: projectId,
+  }).catch(() => {
+    closeLoadModal();
+  });
+  if (!res) return;
+  taskId = res.data.taskId;
+  paperIds = res.data.paperIds;
+  totalTaskCount = paperIds.length;
+
+  if (!paperIds.length) {
+    closeLoadModal();
+    void message.error("没有需要导出的报告!");
+    return;
+  }
+
+  updateProgress(100);
+
+  addProgress({
+    title: "构建报告数据",
+    progress: 0,
+    loading: true,
+  });
+  await startTask();
+}
+
+async function startTask() {
+  if (!paperIds.length) {
+    addProgress({
+      title: "获取报告pdf",
+      progress: 0,
+      loading: true,
+    });
+    await finishTask();
+    return;
+  }
+  curPaperId = paperIds.shift();
+
+  const { href } = router.resolve({
+    name: "PaperReport",
+    params: {
+      projectId: props.curProject.id,
+      paperId: curPaperId,
+      compareProjectId,
+      viewType: "frame",
+    },
+    query: {
+      t: Date.now(),
+    },
+  });
+  reportPreviewUrl = href;
+}
+
+async function finishTask() {
+  clearSetTs();
+  const res = await getProjectReportResult(taskId as number).catch(() => {
+    closeLoadModal();
+  });
+  if (!res) return;
+  if (res.data.status === "SUCCESS" && res.data.filePath) {
+    updateProgress(100);
+    closeLoadModal();
+    void message.info("开始下载报告!");
+    window.open(res.data.filePath);
+    return;
+  }
+  if (res.data.status === "FAILED") {
+    closeLoadModal();
+    void message.error("报告导出失败,请重新尝试!");
+    return;
+  }
+
+  setTs.push(setTimeout(finishTask, 3 * 1000));
+}
+
+function registWindowSubmit() {
+  // @ts-ignore
+  window.submitReportTemp = async (
+    success: boolean,
+    errorMsg: string,
+    htmlContent: string
+  ) => {
+    if (!success) {
+      void message.error(errorMsg);
+      reportPreviewUrl = "";
+      closeLoadModal();
+      return;
+    }
+
+    const res = await uploadProjectReportCont({
+      taskId,
+      paperId: curPaperId as number,
+      htmlContent,
+    }).catch(() => false);
+    if (!res) return;
+
+    finishPaperIds.push(curPaperId as number);
+    updateProgress(getPaperProgress());
+    await startTask();
+  };
+}
+
+onMounted(() => {
+  registWindowSubmit();
+});
+onBeforeMount(() => {
+  clearSetTs();
+  // @ts-ignore
+  delete window.submitReportTemp;
+});
+</script>
+
+<style>
+.report-load-body {
+  width: 200px;
+  margin: 0 auto;
+}
+.report-load-body > i {
+  display: block;
+  font-size: 100px;
+  margin: 0 auto 40px;
+}
+.report-load-body > p {
+  margin: 0;
+  line-height: 24px;
+  color: #fff;
+  font-size: 14px;
+}
+</style>

+ 7 - 5
src/features/report/ReportMain.vue

@@ -128,11 +128,13 @@ onMounted(async () => {
     compareProjectId = +route.params.compareProjectId;
     viewType = route.params.viewType as string;
 
-    const key = window.location.href.split("?")[1];
-    if (!key) return;
-    let keyVal = window.atob(key);
-    let user = JSON.parse(keyVal);
-    store.setUserInfo(user);
+    if (viewType !== "frame") {
+      const key = window.location.href.split("?")[1];
+      if (!key) return;
+      let keyVal = window.atob(key);
+      let user = JSON.parse(keyVal);
+      store.setUserInfo(user);
+    }
   }
 
   await fetchData();