马一丁

Improve SWOT pagination effect

... ... @@ -1178,6 +1178,11 @@ class HTMLRenderer:
def _render_swot_table(self, block: Dict[str, Any]) -> str:
"""
渲染四象限的SWOT专用表格,兼顾HTML与PDF的可读性。
PDF分页策略:
- 每个S/W/O/T象限内部禁止分页(break-inside: avoid)
- 允许在象限之间分页
- 卡片标题与第一个象限尽量保持在一起
"""
title = block.get("title") or "SWOT 分析"
summary = block.get("summary")
... ... @@ -1188,12 +1193,14 @@ class HTMLRenderer:
("threats", "威胁 Threats", "T", "threat"),
]
cells_html = ""
for key, label, code, css in quadrants:
for idx, (key, label, code, css) in enumerate(quadrants):
items = self._normalize_swot_items(block.get(key))
caption_text = f"{len(items)} 条要点" if items else "待补充"
list_html = "".join(self._render_swot_item(item) for item in items) if items else '<li class="swot-empty">尚未填入要点</li>'
# 第一个象限添加特殊类以便与标题保持在一起
first_cell_class = " swot-cell--first" if idx == 0 else ""
cells_html += f"""
<div class="swot-cell {css}">
<div class="swot-cell swot-cell--pageable {css}{first_cell_class}" data-swot-key="{key}">
<div class="swot-cell__meta">
<span class="swot-pill {css}">{self._escape_html(code)}</span>
<div>
... ... @@ -3208,20 +3215,61 @@ table th {{
color: var(--swot-muted);
opacity: 0.7;
}}
/* PDF/导出时的SWOT专用布局,避免圆角框重叠 */
/* PDF/导出时的SWOT专用布局,支持分页且避免圆角框重叠 */
body.exporting .swot-legend {{
display: none !important;
}}
body.exporting .swot-grid {{
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: stretch;
flex-direction: column;
gap: 16px;
}}
body.exporting .swot-cell {{
flex: 1 1 320px;
min-width: 240px;
width: 100%;
height: auto;
page-break-inside: avoid;
break-inside: avoid;
}}
body.exporting .swot-cell--first {{
page-break-before: avoid;
break-before: avoid;
}}
/* 打印模式下的SWOT分页控制 */
@media print {{
.swot-card {{
break-inside: auto;
page-break-inside: auto;
}}
.swot-card__head {{
break-after: avoid;
page-break-after: avoid;
}}
.swot-grid {{
display: flex;
flex-direction: column;
gap: 16px;
}}
.swot-cell {{
break-inside: avoid;
page-break-inside: avoid;
width: 100%;
}}
.swot-cell--first {{
break-before: avoid;
page-break-before: avoid;
}}
.swot-cell__meta {{
break-after: avoid;
page-break-after: avoid;
}}
.swot-list {{
break-inside: avoid;
page-break-inside: avoid;
}}
.swot-item {{
break-inside: avoid;
page-break-inside: avoid;
}}
}}
.callout {{
border-left: 4px solid var(--primary-color);
... ...
... ... @@ -1049,35 +1049,78 @@ body {{
min-height: 400px;
}}
/* SWOT:PDF导出隐藏四象限标注,并使用自适应布局避免重叠 */
/* ========== SWOT PDF分页优化 ========== */
/* 核心策略:S/W/O/T四个象限各自内部禁止分页,但允许象限之间分页 */
/* 隐藏四象限标注图例 */
.swot-legend {{
display: none !important;
}}
/* SWOT卡片容器:允许内部分页 */
.swot-card {{
/* 允许卡片内容在必要时分页,避免整体被抬到下一页 */
break-inside: auto !important;
page-break-inside: auto !important;
margin: 20px 0;
}}
/* 卡片头部(标题+摘要):避免紧跟其后分页,尽量与第一个象限保持在一起 */
.swot-card__head {{
break-after: avoid;
page-break-after: avoid;
break-after: avoid !important;
page-break-after: avoid !important;
break-inside: avoid !important;
page-break-inside: avoid !important;
}}
/* 网格容器:PDF模式下使用纵向flex布局,允许子元素间分页 */
.swot-grid {{
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: stretch;
break-before: avoid;
page-break-before: avoid;
break-inside: auto;
page-break-inside: auto;
display: flex !important;
flex-direction: column !important;
gap: 16px !important;
break-inside: auto !important;
page-break-inside: auto !important;
}}
.swot-grid .swot-cell {{
flex: 1 1 320px;
min-width: 240px;
height: auto;
page-break-inside: avoid;
break-inside: avoid;
/* 每个SWOT象限单元格:禁止内部分页,允许前后分页 */
.swot-cell {{
break-inside: avoid !important;
page-break-inside: avoid !important;
break-before: auto;
page-break-before: auto;
break-after: auto;
page-break-after: auto;
width: 100% !important;
max-width: 100% !important;
flex: none !important;
min-height: auto !important;
height: auto !important;
box-sizing: border-box;
}}
/* 第一个象限:避免在标题后立即分页 */
.swot-cell--first {{
break-before: avoid !important;
page-break-before: avoid !important;
}}
/* 象限内的meta区域(图标+标题):避免被分页切开 */
.swot-cell__meta {{
break-inside: avoid !important;
page-break-inside: avoid !important;
break-after: avoid !important;
page-break-after: avoid !important;
}}
/* 条目列表:允许列表整体分页 */
.swot-list {{
break-inside: avoid !important;
page-break-inside: avoid !important;
}}
/* 单个条目:避免被分页切开 */
.swot-item {{
break-inside: avoid !important;
page-break-inside: avoid !important;
}}
{optimized_css}
... ...