fix(ppt): 表格行高按内容估算逐行设置——显式换行强制断行+CJK/ASCII显示宽度估算换行数+行距余量1.45;根治实测长文本(含换行项目符号列表)在行底被截断;总高超页截行加提示不跨页拆表

This commit is contained in:
yumoqing 2026-09-11 17:18:58 +08:00
parent 47f191fc81
commit 09d77f7483

View File

@ -233,33 +233,65 @@ def _content_header(slide, title, kicker=""):
# ══════════════════════ 表格渲染(真 Table非文本 ══════════════════════
def _disp_w(s):
"""显示宽度CJK=1.0、ASCII≈0.55 字符单位),用于估算换行数。"""
return sum(1.0 if ord(ch) > 0x2E7F else 0.55 for ch in (s or ""))
def _add_table(slide, rows, top, width=None):
"""渲染 markdown 表格为 pptx Table返回占用高度英寸。超宽自动缩字号。"""
"""渲染 markdown 表格为 pptx Table返回占用高度英寸。超宽自动缩字号。
行高按内容估算逐行设置2026-09-11 实测教训统一行高时 LibreOffice/WPS
不按换行撑行 长文本在行底被截断总高超页则截行加提示不跨页拆表
保持单表完整可读
"""
from pptx.util import Inches, Pt
import math
if not rows or not rows[0]:
return 0.0
width = width or (SW - 2 * MARGIN_X)
ncol = max(len(r) for r in rows)
rows = [r + [""] * (ncol - len(r)) for r in rows]
nrow = len(rows)
row_h = 0.36
avail = SH - 0.95 - top
max_rows = max(2, int(avail / row_h))
if nrow > max_rows:
rows = rows[:max_rows - 1] + [["… 其余 %d 行见平台详情页" % (nrow - max_rows + 1)] + [""] * (ncol - 1)]
nrow = len(rows)
total_h = min(row_h * nrow, avail)
gf = slide.shapes.add_table(nrow, ncol, Inches(MARGIN_X), Inches(top),
Inches(width), Inches(total_h))
tbl = gf.table
# 列宽:首列略宽(多为名称),其余均分
first = min(width * 0.30, 4.6)
rest = (width - first) / max(1, ncol - 1)
for ci in range(ncol):
tbl.columns[ci].width = Inches(first if ci == 0 else rest)
col_w = [first if ci == 0 else rest for ci in range(ncol)]
fs = 11 if ncol <= 5 else (10 if ncol <= 7 else 9)
line_h = fs * 1.45 / 72.0 # 每行文本高度(英寸,含行距余量)
pad = 0.12 # 单元格上下边距+余量
def row_height(row_vals):
lines = 1
for ci, val in enumerate(row_vals):
cap = max(2.0, (col_w[ci] - 0.16) * 72.0 / fs) # 每行可容纳字符单位
n = 0
for seg in (val or "")[:180].split("\n"): # 显式换行强制断行
n += max(1, math.ceil(_disp_w(seg) / cap))
lines = max(lines, n)
return lines * line_h + pad
heights = [row_height(r) for r in rows]
total_h = sum(heights)
if total_h > avail:
# 从尾行往前砍到放得下(至少留表头+1 数据行+提示行)
keep = nrow
while keep > 3 and sum(heights[:keep]) + row_height(
[""] + [""] * (ncol - 1)) > avail:
keep -= 1
cut = nrow - keep
rows = rows[:keep] + [["… 其余 %d 行见平台详情页" % cut] + [""] * (ncol - 1)]
heights = heights[:keep] + [row_height(rows[-1])]
nrow = len(rows)
total_h = sum(heights)
gf = slide.shapes.add_table(nrow, ncol, Inches(MARGIN_X), Inches(top),
Inches(width), Inches(total_h))
tbl = gf.table
for ci in range(ncol):
tbl.columns[ci].width = Inches(col_w[ci])
for ri, row in enumerate(rows):
tbl.rows[ri].height = Inches(total_h / nrow)
tbl.rows[ri].height = Inches(heights[ri])
for ci, val in enumerate(row):
cell = tbl.cell(ri, ci)
cell.margin_left = cell.margin_right = Inches(0.07)