|
|
@@ -1019,7 +1019,10 @@ def _render_table_block(doc: Document, block: dict, style_map: dict):
|
|
1019
|
1019
|
return
|
|
1020
|
1020
|
|
|
1021
|
1021
|
# 使用 col_widths 确定真实列数(而不是第一行的单元格数)
|
|
1022
|
|
- col_widths = table_data.get('col_widths', [])
|
|
|
1022
|
+ # 注意: col_widths 应该从 metadata 中获取, 而不是 content
|
|
|
1023
|
+ metadata = block.get('metadata', {})
|
|
|
1024
|
+ col_widths = metadata.get('col_widths', [])
|
|
|
1025
|
+
|
|
1023
|
1026
|
if col_widths:
|
|
1024
|
1027
|
num_cols = len(col_widths)
|
|
1025
|
1028
|
else:
|
|
|
@@ -1058,10 +1061,47 @@ def _render_table_block(doc: Document, block: dict, style_map: dict):
|
|
1058
|
1061
|
table.alignment = WD_TABLE_ALIGNMENT.RIGHT
|
|
1059
|
1062
|
|
|
1060
|
1063
|
# 设置列宽
|
|
|
1064
|
+ # 注意: col_widths 中存储的是百分比值(如 [50, 50] 表示两列各占50%)
|
|
|
1065
|
+ # 需要根据表格总宽度计算实际列宽(磅值)
|
|
1061
|
1066
|
if col_widths:
|
|
1062
|
|
- for col_idx, width in enumerate(col_widths):
|
|
|
1067
|
+ # 获取表格总宽度设置
|
|
|
1068
|
+ table_width = metadata.get('table_width', 100)
|
|
|
1069
|
+ table_width_unit = metadata.get('table_width_unit', 'percent')
|
|
|
1070
|
+
|
|
|
1071
|
+ # 计算表格实际宽度(磅)
|
|
|
1072
|
+ if table_width_unit == 'percent':
|
|
|
1073
|
+ # 百分比模式:基于页面可用宽度计算
|
|
|
1074
|
+ # 假设 A4 纸张,页面宽度约 595磅(21cm),左右边距各约71磅(2.5cm)
|
|
|
1075
|
+ # 可用宽度 = 595 - 71 - 71 = 453 磅
|
|
|
1076
|
+ page_available_width_pt = 453.0 # 可以从 style_data 中的 page_setup 获取更精确的值
|
|
|
1077
|
+ actual_table_width_pt = page_available_width_pt * (table_width / 100.0)
|
|
|
1078
|
+ elif table_width_unit == 'cm':
|
|
|
1079
|
+ # 厘米转磅: 1cm = 28.35磅
|
|
|
1080
|
+ actual_table_width_pt = table_width * 28.35
|
|
|
1081
|
+ elif table_width_unit == 'inch':
|
|
|
1082
|
+ # 英寸转磅: 1inch = 72磅
|
|
|
1083
|
+ actual_table_width_pt = table_width * 72.0
|
|
|
1084
|
+ else:
|
|
|
1085
|
+ # 默认使用百分比模式
|
|
|
1086
|
+ page_available_width_pt = 453.0
|
|
|
1087
|
+ actual_table_width_pt = page_available_width_pt * (table_width / 100.0)
|
|
|
1088
|
+
|
|
|
1089
|
+ # 计算列宽百分比总和,用于归一化
|
|
|
1090
|
+ col_widths_sum = sum(col_widths)
|
|
|
1091
|
+
|
|
|
1092
|
+ # 根据百分比计算每列的实际宽度并设置
|
|
|
1093
|
+ # 注意:为了避免因百分比总和不为100而导致的问题,我们基于实际总和进行归一化
|
|
|
1094
|
+ for col_idx, width_percent in enumerate(col_widths):
|
|
1063
|
1095
|
if col_idx < len(table.columns):
|
|
1064
|
|
- table.columns[col_idx].width = Pt(width)
|
|
|
1096
|
+ # 归一化:基于实际的百分比总和计算每列占表格宽度的比例
|
|
|
1097
|
+ # 例如:如果7列各14%,总和98%,则每列实际占 14/98 的表格宽度
|
|
|
1098
|
+ if col_widths_sum > 0:
|
|
|
1099
|
+ col_width_pt = actual_table_width_pt * (width_percent / col_widths_sum)
|
|
|
1100
|
+ else:
|
|
|
1101
|
+ # 如果总和为0,平均分配
|
|
|
1102
|
+ col_width_pt = actual_table_width_pt / len(col_widths)
|
|
|
1103
|
+
|
|
|
1104
|
+ table.columns[col_idx].width = Pt(col_width_pt)
|
|
1065
|
1105
|
|
|
1066
|
1106
|
# 填充内容并处理合并单元格
|
|
1067
|
1107
|
merge_map = {} # {(row, col): (end_row, end_col)} 记录合并区域
|
|
|
@@ -1075,58 +1115,49 @@ def _render_table_block(doc: Document, block: dict, style_map: dict):
|
|
1075
|
1115
|
|
|
1076
|
1116
|
cells_data = row_data.get('cells', [])
|
|
1077
|
1117
|
|
|
1078
|
|
- # 构建一个映射:col_index -> cell_data
|
|
1079
|
|
- cells_by_col = {}
|
|
1080
|
|
- for cell_data in cells_data:
|
|
1081
|
|
- col_idx = cell_data.get('col_index', None)
|
|
1082
|
|
- if col_idx is not None:
|
|
1083
|
|
- cells_by_col[col_idx] = cell_data
|
|
1084
|
|
-
|
|
1085
|
|
- # 遍历所有列
|
|
1086
|
|
- for col_idx in range(num_cols):
|
|
1087
|
|
- # 检查这个位置是否被占用(被上方的合并单元格占用)
|
|
1088
|
|
- if occupied.get((r_idx, col_idx), False):
|
|
1089
|
|
- continue # 跳过被占用的位置
|
|
1090
|
|
-
|
|
1091
|
|
- # 检查是否有数据要填充到这个位置
|
|
1092
|
|
- if col_idx not in cells_by_col:
|
|
1093
|
|
- continue # 这个位置没有数据
|
|
|
1118
|
+ # 遍历单元格数据
|
|
|
1119
|
+ # 注意:单元格在 cells 数组中的索引就是它的列索引(col_idx)
|
|
|
1120
|
+ col_offset = 0 # 当前应该填充到哪一列
|
|
|
1121
|
+ for cell_idx, cell_data in enumerate(cells_data):
|
|
|
1122
|
+ # 跳过被上方合并单元格占用的列
|
|
|
1123
|
+ while occupied.get((r_idx, col_offset), False):
|
|
|
1124
|
+ col_offset += 1
|
|
|
1125
|
+ if col_offset >= num_cols:
|
|
|
1126
|
+ break
|
|
1094
|
1127
|
|
|
1095
|
|
- cell_data = cells_by_col[col_idx]
|
|
|
1128
|
+ if col_offset >= num_cols:
|
|
|
1129
|
+ break # 超出列数,停止处理
|
|
1096
|
1130
|
|
|
1097
|
|
- # 跳过被合并的单元格(rowspan=0 表示这个单元格被上面的单元格合并了)
|
|
|
1131
|
+ # 跳过被合并的单元格(rowspan=0 或 colspan=0 表示这个单元格被合并了)
|
|
1098
|
1132
|
rowspan = cell_data.get('rowspan', 1)
|
|
1099
|
|
- if rowspan == 0:
|
|
1100
|
|
- continue
|
|
1101
|
|
-
|
|
1102
|
1133
|
colspan = cell_data.get('colspan', 1)
|
|
1103
|
1134
|
|
|
1104
|
|
- # 确保不越界
|
|
1105
|
|
- if col_idx >= num_cols:
|
|
|
1135
|
+ if rowspan == 0 or colspan == 0:
|
|
|
1136
|
+ # 这个单元格已被合并,跳过
|
|
1106
|
1137
|
continue
|
|
1107
|
1138
|
|
|
1108
|
1139
|
# 获取起始单元格
|
|
1109
|
|
- start_cell = table.rows[r_idx].cells[col_idx]
|
|
|
1140
|
+ start_cell = table.rows[r_idx].cells[col_offset]
|
|
1110
|
1141
|
|
|
1111
|
1142
|
# 处理合并单元格
|
|
1112
|
1143
|
if colspan > 1 or rowspan > 1:
|
|
1113
|
1144
|
# 计算结束位置
|
|
1114
|
|
- end_col = min(col_idx + colspan - 1, num_cols - 1)
|
|
|
1145
|
+ end_col = min(col_offset + colspan - 1, num_cols - 1)
|
|
1115
|
1146
|
end_row = min(r_idx + rowspan - 1, num_rows - 1)
|
|
1116
|
1147
|
|
|
1117
|
1148
|
# 合并单元格
|
|
1118
|
|
- if end_col > col_idx or end_row > r_idx:
|
|
|
1149
|
+ if end_col > col_offset or end_row > r_idx:
|
|
1119
|
1150
|
try:
|
|
1120
|
1151
|
end_cell = table.rows[end_row].cells[end_col]
|
|
1121
|
1152
|
start_cell.merge(end_cell)
|
|
1122
|
|
- merge_map[(r_idx, col_idx)] = (end_row, end_col)
|
|
|
1153
|
+ merge_map[(r_idx, col_offset)] = (end_row, end_col)
|
|
1123
|
1154
|
|
|
1124
|
1155
|
# 标记被合并的单元格位置为已占用
|
|
1125
|
1156
|
for merge_r in range(r_idx, end_row + 1):
|
|
1126
|
|
- for merge_c in range(col_idx, end_col + 1):
|
|
1127
|
|
- if merge_r != r_idx or merge_c != col_idx: # 不标记起始单元格
|
|
|
1157
|
+ for merge_c in range(col_offset, end_col + 1):
|
|
|
1158
|
+ if merge_r != r_idx or merge_c != col_offset: # 不标记起始单元格
|
|
1128
|
1159
|
occupied[(merge_r, merge_c)] = True
|
|
1129
|
|
- except Exception:
|
|
|
1160
|
+ except Exception as e:
|
|
1130
|
1161
|
pass # 合并失败,继续
|
|
1131
|
1162
|
|
|
1132
|
1163
|
# 设置单元格宽度(如果有)
|
|
|
@@ -1191,7 +1222,9 @@ def _render_table_block(doc: Document, block: dict, style_map: dict):
|
|
1191
|
1222
|
run = para.add_run(str(cell_text))
|
|
1192
|
1223
|
# 应用单元格 run 级样式
|
|
1193
|
1224
|
_apply_run_style(run, cell_style)
|
|
1194
|
|
-
|
|
|
1225
|
+
|
|
|
1226
|
+ # 移动到下一列位置(考虑colspan)
|
|
|
1227
|
+ col_offset += colspan
|
|
1195
|
1228
|
|
|
1196
|
1229
|
def _render_image_block(doc: Document, block: dict, style_map: dict = None):
|
|
1197
|
1230
|
"""渲染图片块(支持 Base64 Data URL 和 Word 样式)"""
|