|
|
@@ -1457,48 +1457,113 @@ class ExamPdfExportService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 【新增】构建统一的HTML文档(保留原始结构)
|
|
|
- * 保留第一个HTML的完整head和样式,只在body之间插入分页符
|
|
|
+ * 【优化重构】构建统一的HTML文档(容器结构 + 消除空白页)
|
|
|
+ * 使用容器结构替代空的 page-break div,避免中间出现空白页
|
|
|
*/
|
|
|
private function buildUnifiedHtmlWithOriginalStructure(string $examHead, string $examBody, string $gradingBody): string
|
|
|
{
|
|
|
- // 保留原始head内容,添加分页符样式
|
|
|
+ // 清洗内容:移除可能存在的分页符,避免双重分页
|
|
|
+ $examBody = $this->stripPageBreakElements($examBody);
|
|
|
+ $gradingBody = $this->stripPageBreakElements($gradingBody);
|
|
|
+
|
|
|
+ // 构建优化的HTML结构,使用容器控制分页
|
|
|
$headContent = $examHead . '
|
|
|
<style>
|
|
|
- /* 分页符样式 - 插入到原始样式之后 */
|
|
|
- .page-break {
|
|
|
- page-break-before: always;
|
|
|
- page-break-after: always;
|
|
|
+ /* 容器基础样式 - 保持现有页面边距 */
|
|
|
+ .exam-part,
|
|
|
+ .grading-part {
|
|
|
+ width: 100%;
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 核心分页控制:只在 grading-part 上设置 */
|
|
|
+ .grading-part {
|
|
|
+ /* CSS3 新标准 */
|
|
|
break-before: page;
|
|
|
- break-after: page;
|
|
|
+ /* 兼容旧版 WebKit */
|
|
|
+ page-break-before: always;
|
|
|
+ /* 确保顶部没有额外边距 */
|
|
|
+ margin-top: 0;
|
|
|
+ padding-top: 0;
|
|
|
}
|
|
|
|
|
|
- /* 确保分页符在打印时生效 */
|
|
|
- @media print {
|
|
|
- .page-break {
|
|
|
- page-break-before: always;
|
|
|
- }
|
|
|
+ /* 防止试卷部分末尾分页 */
|
|
|
+ .exam-part {
|
|
|
+ /* 确保试卷内容连续 */
|
|
|
+ break-after: auto;
|
|
|
+ page-break-after: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 避免在关键元素中间分页 */
|
|
|
+ .exam-part h1, .exam-part h2,
|
|
|
+ .grading-part h1, .grading-part h2 {
|
|
|
+ break-after: avoid;
|
|
|
+ page-break-after: avoid;
|
|
|
+ }
|
|
|
+
|
|
|
+ .exam-part table, .exam-part .question-item,
|
|
|
+ .grading-part table, .grading-part .answer-item {
|
|
|
+ break-inside: avoid;
|
|
|
+ page-break-inside: avoid;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 防止孤儿行 */
|
|
|
+ .exam-part p, .exam-part li,
|
|
|
+ .grading-part p, .grading-part li {
|
|
|
+ orphans: 2;
|
|
|
+ widows: 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 数学公式优化 */
|
|
|
+ .katex {
|
|
|
+ break-inside: avoid;
|
|
|
+ page-break-inside: avoid;
|
|
|
}
|
|
|
</style>';
|
|
|
|
|
|
return '<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <title>试卷与判卷合并</title>
|
|
|
' . $headContent . '
|
|
|
</head>
|
|
|
<body>
|
|
|
- <!-- 第一部分:试卷(不含答案) -->
|
|
|
- ' . $examBody . '
|
|
|
-
|
|
|
- <!-- 分页符:第二部分从这里开始 -->
|
|
|
- <div class="page-break"></div>
|
|
|
-
|
|
|
- <!-- 第二部分:判卷(含答案与解析) -->
|
|
|
- ' . $gradingBody . '
|
|
|
+ <!-- 试卷部分 - 连续显示 -->
|
|
|
+ <div class="exam-part">
|
|
|
+' . $examBody . '
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 判卷部分 - 强制新页面开始(不使用空的 page-break div) -->
|
|
|
+ <div class="grading-part">
|
|
|
+' . $gradingBody . '
|
|
|
+ </div>
|
|
|
</body>
|
|
|
</html>';
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 【新增】清洗HTML内容中的分页符元素
|
|
|
+ * 移除可能存在的 page-break 元素,避免双重分页导致空白页
|
|
|
+ */
|
|
|
+ private function stripPageBreakElements(string $content): string
|
|
|
+ {
|
|
|
+ // 只移除空的 page-break div 元素(通常是 <div class="page-break"></div>)
|
|
|
+ // 使用更精确的正则,只匹配空内容或纯空白内容的 div
|
|
|
+ $patterns = [
|
|
|
+ '/<div[^>]*class="[^"]*page-break[^"]*"[^>]*>\s*<\/div>/si',
|
|
|
+ '/<div[^>]*style="[^"]*page-break[^"]*"[^>]*>\s*<\/div>/si',
|
|
|
+ ];
|
|
|
+
|
|
|
+ foreach ($patterns as $pattern) {
|
|
|
+ $content = preg_replace($pattern, '', $content);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $content;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 【新增】获取PDF通用样式
|
|
|
*/
|