Browse Source

成绩单打印、错题打印新标签打开

liurongli 2 tuần trước cách đây
mục cha
commit
c75ff89bc8
3 tập tin đã thay đổi với 36 bổ sung và 95 xóa
  1. 15 45
      src/components/ErrorsTablePdf.vue
  2. 15 44
      src/components/ScorePdf.vue
  3. 6 6
      src/views/analysis/score.vue

+ 15 - 45
src/components/ErrorsTablePdf.vue

@@ -600,15 +600,6 @@ const DownloadPdf = async () => {
     emit("PdfLoadEnd");
     return;
   }
-  // 在用户手势内同步打开空白窗口,避免被浏览器拦截
-  const win = window.open("", "_blank");
-  if (!win) {
-    ElMessage.warning("浏览器拦截了弹窗,请允许后重试");
-    return;
-  }
-  win.document.write(
-    "<p style='font-family:sans-serif;text-align:center;padding-top:40px'>错题名单 PDF 生成中…</p>",
-  );
   const pdf = new jsPDF("p", "pt", "a4");
   const pdfWidth = pdf.internal.pageSize.getWidth();
   const pdfHeight = pdf.internal.pageSize.getHeight();
@@ -712,48 +703,27 @@ const DownloadPdf = async () => {
   //   new File([blob], filename, { type: "application/pdf" }),
   // );
   // win.location.replace(url);
-  // 在浏览器新窗口打开生成的PDF(中转页方案:窗口标题、下载文件名均使用指定名称)
+  // PDF 全部生成完后再开新标签,直接打开 PDF(不提前开窗、不写中转页、不用 iframe)
   const filename = `${props.examName}_${props.subjectName}_${props.className}错题名单.pdf`;
+  pdf.setProperties({ title: filename.replace(/\.pdf$/, "") });
   const blob = pdf.output("blob");
   const url = URL.createObjectURL(
     new File([blob], filename, { type: "application/pdf" }),
   );
-  // 转义文件名中的特殊字符,防止破坏 HTML
-  const safeName = filename
-    .replace(/&/g, "&amp;")
-    .replace(/</g, "&lt;")
-    .replace(/>/g, "&gt;")
-    .replace(/"/g, "&quot;");
-  // 清空"生成中"占位页,写入中转页
-  win.document.open();
-  win.document.write(
-    `<!DOCTYPE html>
-<html lang="zh-CN">
-<head>
-<meta charset="utf-8">
-<title>${safeName}</title>
-<style>
-  body{margin:0;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;}
-  .bar{height:48px;display:flex;align-items:center;gap:12px;padding:0 16px;background:#f5f6f7;border-bottom:1px solid #dcdfe6;box-sizing:border-box;}
-  .bar .fname{flex:1;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
-  .bar .btn{color:#fff;background:#2e64fa;border:0;padding:6px 16px;border-radius:4px;font-size:13px;cursor:pointer;flex-shrink:0;text-decoration:none;display:inline-block;}
-  iframe{width:100%;height:calc(100vh - 48px);border:0;display:block;}
-  @media print{
-    .bar{display:none;}
-    iframe{height:100vh;}
+  // 此时已不在用户手势里,可能被弹窗拦截;被拦就退化为直接下载
+  const win = window.open(url, "_blank");
+  if (!win) {
+    const a = document.createElement("a");
+    a.href = url;
+    a.download = filename;
+    document.body.appendChild(a);
+    a.click();
+    a.remove();
+    ElMessage.success("浏览器拦截了新标签页,已改为直接下载 PDF");
+  } else {
+    // 焦点留在当前页,不跳走
+    window.focus();
   }
-</style>
-</head>
-<body>
-  <div class="bar">
-    <span class="fname">${safeName}</span>
-    <a class="btn" href="${url}" download="${safeName}">下载PDF</a>
-  </div>
-  <iframe src="${url}"></iframe>
-</body>
-</html>`,
-  );
-  win.document.close();
   emit("PdfLoadEnd");
 };
 // 错题分析  合并单元格

+ 15 - 44
src/components/ScorePdf.vue

@@ -357,16 +357,6 @@ const ExportPdf = async () => {
     ElMessage.warning("未找到可导出的页面内容,请先加载数据!");
     return;
   }
-  // 在用户手势内同步打开空白窗口,避免被浏览器拦截
-  const win = window.open("", "_blank");
-  if (!win) {
-    ElMessage.warning("浏览器拦截了弹窗,请允许后重试");
-    return;
-  }
-  win.document.write(
-    "<p style='font-family:sans-serif;text-align:center;padding-top:40px'>成绩单 PDF 生成中…</p>",
-  );
-
   // 1. 确保页面 DOM 渲染完成(只在最开始等一次,不再逐页等待)
   await nextTick();
 
@@ -468,46 +458,27 @@ const ExportPdf = async () => {
     );
   });
 
-  // 中转页方案保持不变
+  // PDF 全部生成完后再开新标签,直接打开 PDF(不提前开窗、不写中转页、不用 iframe)
   const filename = `${examName.value}_${analysisStore?.filterObject?.subjectName || ''}_${analysisStore?.filterObject?.classGroupName || ''}成绩单.pdf`;
+  pdf.setProperties({ title: filename.replace(/\.pdf$/, "") });
   const blob = pdf.output("blob");
   const url = URL.createObjectURL(
     new File([blob], filename, { type: "application/pdf" }),
   );
-  const safeName = filename
-    .replace(/&/g, "&amp;")
-    .replace(/</g, "&lt;")
-    .replace(/>/g, "&gt;")
-    .replace(/"/g, "&quot;");
-  win.document.open();
-  win.document.write(
-    `<!DOCTYPE html>
-<html lang="zh-CN">
-<head>
-<meta charset="utf-8">
-<title>${safeName}</title>
-<style>
-  body{margin:0;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;}
-  .bar{height:48px;display:flex;align-items:center;gap:12px;padding:0 16px;background:#f5f6f7;border-bottom:1px solid #dcdfe6;box-sizing:border-box;}
-  .bar .fname{flex:1;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
-  .bar .btn{color:#fff;background:#2e64fa;border:0;padding:6px 16px;border-radius:4px;font-size:13px;cursor:pointer;flex-shrink:0;text-decoration:none;display:inline-block;}
-  iframe{width:100%;height:calc(100vh - 48px);border:0;display:block;}
-  @media print{
-    .bar{display:none;}
-    iframe{height:100vh;}
+  // 此时已不在用户手势里,可能被弹窗拦截;被拦就退化为直接下载
+  const win = window.open(url, "_blank");
+  if (!win) {
+    const a = document.createElement("a");
+    a.href = url;
+    a.download = filename;
+    document.body.appendChild(a);
+    a.click();
+    a.remove();
+    ElMessage.success("浏览器拦截了新标签页,已改为直接下载 PDF");
+  } else {
+    // 焦点留在当前页,不跳走
+    window.focus();
   }
-</style>
-</head>
-<body>
-  <div class="bar">
-    <span class="fname">${safeName}</span>
-    <a class="btn" href="${url}" download="${safeName}">下载PDF</a>
-  </div>
-  <iframe src="${url}"></iframe>
-</body>
-</html>`,
-  );
-  win.document.close();
 };
 // 加载数据并导出PDF(供父组件一步调用)
 const LoadAndExportPdf = async (

+ 6 - 6
src/views/analysis/score.vue

@@ -464,13 +464,13 @@ const PrintPdf = () => {
     showClassPop.value = false;//不显示弹框
     reportModuleRef.value?.SetPrintLoading?.(true);
     const classIdCode = analysisStore?.filterObject?.classIdCode;
-    selectClassList.value = classIdCode? [classIdCode] : [];
-    scorePdfRef.value?.LoadAndExportPdf(state.keyWord, selectClassList.value)
-      .finally(() => {
-        reportModuleRef.value?.SetPrintLoading?.(false);
-      });//加载并导出PDF
+    // selectClassList.value = classIdCode? [classIdCode] : [];
+    // scorePdfRef.value?.LoadAndExportPdf(state.keyWord, selectClassList.value)
+    //   .finally(() => {
+    //     reportModuleRef.value?.SetPrintLoading?.(false);
+    //   });//加载并导出PDF
     radioSelectClassList.value = classIdCode;
-    scorePdfRef.value?.LoadAndExportPdf(state.keyWord, radioSelectClassList.value)
+    scorePdfRef.value?.LoadAndExportPdf(state.keyWord, [radioSelectClassList.value])
       .finally(() => {
         reportModuleRef.value?.SetPrintLoading?.(false);
       });//加载并导出PDF