diff --git a/Generate_Report.py b/Generate_Report.py index b501cea..34c5181 100644 --- a/Generate_Report.py +++ b/Generate_Report.py @@ -31,7 +31,7 @@ def main(): elif merged['json2']['choose_template'] == 'JF': asyncio.run(generate_jf_report(merged['json1'], merged['json2'])) else: - print('指定了不存在的,请检查配置文件') + print('指定了不存在的模板,请检查配置文件') print('文档生成完毕') if __name__ == '__main__': diff --git a/Jf_report.py b/Jf_report.py index b37d8ea..934f880 100644 --- a/Jf_report.py +++ b/Jf_report.py @@ -1,15 +1,15 @@ # 文档处理工具 from tools.document_tools import ( create_document, add_documents,add_table_and_replace, - add_table_to_document,add_dynamic_table, + add_table_to_document,add_dynamic_table,add_section, process_server_images_table,add_header,add_landscape_section, - merge_documents,add_table,add_defect_info_table,add_table_title + merge_documents,add_table,add_defect_info_table,add_table_title, + add_title,change_heading,add_auto_toc_at_end ) # 内容处理工具 from tools.content_tools import ( - add_picture,split_table_by_row_content, - search_and_replace + search_and_replace,add_heading ) from tools.get_pictures import ( @@ -146,6 +146,7 @@ async def generate_jf_report(base_info, baogao_info): neirong2 = [] use_tool_table = [] table_index = 1 + typical_picture_description = [] #获取对应枚举字段 if if_waibu: baogao_label.append("外观") @@ -166,6 +167,7 @@ async def generate_jf_report(base_info, baogao_info): jiancha.append("无人机外观检查") neirong.append(f"、".join(Y_Code) + f"共{len(Y_Code)}支叶片的前缘、后缘、迎风面、背风面。") neirong2.append("前缘、后缘、迎风面、背风面。") + typical_picture_description.extend(TEMPLATE_HEADER.JINFENG_HEADER.WAIBU.TYPICAL_LIST) if if_neibu: baogao_label.append("内部") image_source_to_find.append(baogao_info['neibu_enum']) @@ -184,6 +186,7 @@ async def generate_jf_report(base_info, baogao_info): jiancha.append("叶片内部检查") neirong.append(f"、".join(Y_Code) + f"共{len(Y_Code)}支叶片的内部导雷卡、腹板、透光、人孔盖版、叶根盖板...") neirong2.append("内部导雷卡、腹板、透光、人孔盖版、叶根盖板...") + typical_picture_description.extend(TEMPLATE_HEADER.JINFENG_HEADER.NEIBU.TYPICAL_LIST) if if_fanglei: baogao_label.append("防雷") image_source_to_find.append(baogao_info['fanglei_enum']) @@ -202,7 +205,8 @@ async def generate_jf_report(base_info, baogao_info): jiancha.append("叶片导通测试") neirong.append(f"轮毂至塔基导通、内部导线线阻、外部导线线阻...") neirong2.append("轮毂至塔基导通、内部导线线阻、外部导线线阻...") - + typical_picture_description.extend(TEMPLATE_HEADER.JINFENG_HEADER.FANGLEI.TYPICAL_LIST) + #获取缺陷图列表和典型图列表 filtered_picture_data, total_picture_num = process_picture_data(picture_data, image_source_to_find) #获取所有缺陷记录 @@ -223,7 +227,8 @@ async def generate_jf_report(base_info, baogao_info): if not os.path.exists(shengcheng_dir): print(f"生成路径{shengcheng_dir}不存在") return - + + baogao_name = "叶片" + "、".join(baogao_label) + "检查报告" output_dir = os.path.normpath(f"{shengcheng_dir}/{project_name}项目{baogao_name}{jizu_bianhao}{baogao_date.split(' ')[0]}版.docx") @@ -254,6 +259,10 @@ async def generate_jf_report(base_info, baogao_info): "top_margin" : JF_T_MARGIN, "bottom_margin" : JF_B_MARGIN, })) + #标题样式 + change_heading(output_dir, "Heading 1") + change_heading(output_dir, "Heading 2", HEADING_2_CONFIG) + change_heading(output_dir, "Heading 3", HEADING_3_CONFIG) #加封面 merge_documents(output_dir, add_list) #页眉 @@ -299,14 +308,55 @@ async def generate_jf_report(base_info, baogao_info): #缺陷信息表格2 - table_list = tree_dict_to_table_data(defect_part_type_list) - table_list = defect_list_addtitle(table_list, jizu_bianhao) - print(table_list) - add_table_title(output_dir, DEFECT_TABLE_TITLE) - table_json = list_to_json_with_merges(table_list, style_config=STYLE_CONFIG, merge_columns=2) - json_to_docx(table_json, output_dir).save(output_dir) + table_list = tree_dict_to_table_data(defect_part_type_list) # 服务器获取的树形结构转化为表格数据 + table_list = defect_list_addtitle(table_list, jizu_bianhao) # 增加每列标题,机组 + add_table_title(output_dir, DEFECT_TABLE_TITLE) # 增加表格标题 + table_json = list_to_json_with_merges(table_list, style_config=STYLE_CONFIG, merge_columns=2) #将list转换为json形式,前两列检查相同合并 + json_to_docx(table_json, output_dir).save(output_dir) #jsontodocx #使用器具记录表 - add_table_title(output_dir, USE_TOOL_TABLE_TITLE) - print(use_tool_table) - json_to_docx(list_to_json_with_merges(use_tool_table, style_config=STYLE_CONFIG, detect_merges=False),output_dir).save(output_dir) \ No newline at end of file + add_table_title(output_dir, USE_TOOL_TABLE_TITLE) + json_to_docx(list_to_json_with_merges(use_tool_table, style_config=STYLE_CONFIG, detect_merges=False),output_dir).save(output_dir) + + #添加目录节 + add_section(output_dir).save(output_dir) + + #添加目录 + #add_auto_toc_at_end(output_dir) + + #添加横向节(展示图片) + add_landscape_section(output_dir).save(output_dir) + + print(add_heading(output_dir, f"1. 机组号:{jizu_bianhao}", 1)) + print(add_heading(output_dir, f"1.1 叶片编号:{Y_Code[0]}", 2)) + #add_header(output_dir, TEMPLATE_HEADER.JINFENG_HEADER.ENUM, if_section=False, text = " " + TEMPLATE_HEADER.JINFENG_HEADER.PARA) + add_table_to_document( + output_dir, + get_resource_path(MUBAN_DIR + '/jfempty.docx'), + 3, + 5, + total_table_num, + if_merge=False, + Report_Enum=TEMPLATE_HEADER.JINFENG_HEADER.ENUM, + if_para=False + ) + """ + 典型图片dict 典型图片的描述固定 + { + 图片描述 : 图片地址, #情况一 + 描述部位缺陷数量 : 缺陷类型数量, #情况二 + ... + } + 缺陷图片dict 缺陷图片的描述从信息来源获取 + { + 图片描述 : 图片地址, + } + """ + typical_picture_list = [] + typical_picture_dict = {} + for description, url in zip(typical_picture_description, typical_picture_list): + typical_picture_dict[description] = url + print(typical_picture_dict) + defect_picture_dict = {} + + diff --git a/__pycache__/Jf_report.cpython-310.pyc b/__pycache__/Jf_report.cpython-310.pyc index 86bf436..402e19a 100644 Binary files a/__pycache__/Jf_report.cpython-310.pyc and b/__pycache__/Jf_report.cpython-310.pyc differ diff --git a/core/__pycache__/tables.cpython-310.pyc b/core/__pycache__/tables.cpython-310.pyc index f489995..49989f1 100644 Binary files a/core/__pycache__/tables.cpython-310.pyc and b/core/__pycache__/tables.cpython-310.pyc differ diff --git a/core/tables.py b/core/tables.py index d0fbf6e..ea727cc 100644 --- a/core/tables.py +++ b/core/tables.py @@ -116,6 +116,21 @@ def copy_table(source_table, target_doc, ifadjustheight=True, height = 1, if_mer """ # Create a new table with the same dimensions new_table = target_doc.add_table(rows=len(source_table.rows), cols=len(source_table.columns)) + # 获取表格属性 + tbl_pr = new_table._tbl.tblPr + + # 设置表格边框 + tbl_borders = OxmlElement('w:tblBorders') + for border_name in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + border = OxmlElement(f'w:{border_name}') + border.set(qn('w:val'), 'single') # 边框类型 + border.set(qn('w:sz'), '4') # 边框粗细(1-96,8代表1磅) + border.set(qn('w:space'), '0') # 边框间距 + border.set(qn('w:color'), 'auto') # 边框颜色 + tbl_borders.append(border) + + tbl_pr.append(tbl_borders) + # Try to apply the same style try: if source_table.style: @@ -145,7 +160,7 @@ def copy_table(source_table, target_doc, ifadjustheight=True, height = 1, if_mer #new_table.cell(i,j).width = cell.width if REPORT_ENUM == 'JF': new_table.cell(i,j).paragraphs[0].runs[0]._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体') #设置中文字体 - new_table.cell(i,j).paragraphs[0].runs[0].font.size = Pt(12) # 字体大小 + new_table.cell(i,j).paragraphs[0].runs[0].font.size = Pt(8) # 字体大小 """ 待添加:如何让表格自适应大小(autofit目前不知为何没有作用) """ diff --git a/muban/jfempty.docx b/muban/jfempty.docx new file mode 100644 index 0000000..e741bcb Binary files /dev/null and b/muban/jfempty.docx differ diff --git a/output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月30日版.docx b/output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月31日版41.docx similarity index 84% rename from output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月30日版.docx rename to output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月31日版41.docx index 7ee206c..a76202e 100644 Binary files a/output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月30日版.docx and b/output/三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月31日版41.docx differ diff --git a/test.py b/test.py new file mode 100644 index 0000000..347c360 --- /dev/null +++ b/test.py @@ -0,0 +1,117 @@ +from typing import Dict +import os +from docx import Document +from tools.document_tools import add_picture_to_table, add_table_to_document +def add_jf_picture_table( + typical_picture_dict: Dict[str, str], + defect_picture_dict: Dict[str, str], + TYPICAL_MUBAN_DIR: str, + DEFECT_MUBAN_DIR: str, + output_dir: str, +): + """添加金风版本的图片展示表格""" + # 初始化文档对象 + doc = Document() + target_filename = os.path.join(output_dir, "output.docx") + + # 处理典型图 + typical_data = [] + defect_keys = [] # 记录有缺陷的典型图key + + # 准备典型图数据 + for key, value in typical_picture_dict.items(): + if "损伤" in key or "损伤" in value: + # 情况二:有缺陷 + defect_count = int(value.split("损伤类型")[1].split("处")[0]) + typical_data.append([key, "损伤{}处,详见下表".format(defect_count), value]) + defect_keys.append((key, defect_count)) + else: + # 情况一:正常图片 + typical_data.append([key, value, ""]) # 第三行留空 + + # 添加典型图表格 + if typical_data: + # 将数据转换为适合表格的格式(3行×n列) + # 需要将数据从行优先转为列优先 + cols = len(typical_data) + table_data = [[], [], []] + for col_data in typical_data: + for i in range(3): + table_data[i].append(col_data[i] if i < len(col_data) else "") + + # 添加典型图表格 + add_table_to_document( + target_filename=target_filename, + source_filename=TYPICAL_MUBAN_DIR, + rows=3, + cols=cols, + table_num=0, + data=table_data + ) + + # 添加典型图中的图片 + doc = Document(target_filename) + for col_idx, (key, value) in enumerate(typical_picture_dict.items()): + if "损伤" not in key and "损伤" not in value: # 只有正常图片才添加 + add_picture_to_table( + target_doc=doc, + target_filename=target_filename, + row=1, # 第二行是图片 + col=col_idx, + image_path=value + ) + doc.save(target_filename) + + # 处理缺陷图 + if defect_keys: + # 遍历所有有缺陷的典型图 + for typical_key, defect_count in defect_keys: + # 计算需要多少个缺陷图表格(每表5列) + table_count = (defect_count + 4) // 5 # 向上取整 + + for table_idx in range(table_count): + # 计算当前表格的列数 + cols_in_table = min(5, defect_count - table_idx * 5) + + # 准备缺陷图数据 + defect_data = [] + for i in range(cols_in_table): + defect_idx = table_idx * 5 + i + defect_key = list(defect_picture_dict.keys())[defect_idx] + defect_value = list(defect_picture_dict.values())[defect_idx] + defect_data.append([defect_key, defect_value]) + + # 将数据转换为适合表格的格式(2行×n列) + table_data = [[], []] + for col_data in defect_data: + for i in range(2): + table_data[i].append(col_data[i] if i < len(col_data) else "") + + # 添加缺陷图表格 + add_table_to_document( + target_filename=target_filename, + source_filename=DEFECT_MUBAN_DIR, + rows=2, + cols=cols_in_table, + table_num=0, + data=table_data + ) + + # 添加缺陷图中的图片 + doc = Document(target_filename) + for col_idx in range(cols_in_table): + defect_idx = table_idx * 5 + col_idx + defect_value = list(defect_picture_dict.values())[defect_idx] + add_picture_to_table( + target_doc=doc, + target_filename=target_filename, + row=1, # 第二行是图片 + col=col_idx, + image_path=defect_value + ) + doc.save(target_filename) + + return target_filename + + +add_jf_picture_table({""}) \ No newline at end of file diff --git a/tools/__pycache__/content_tools.cpython-310.pyc b/tools/__pycache__/content_tools.cpython-310.pyc index ef43d10..97642e3 100644 Binary files a/tools/__pycache__/content_tools.cpython-310.pyc and b/tools/__pycache__/content_tools.cpython-310.pyc differ diff --git a/tools/__pycache__/defines.cpython-310.pyc b/tools/__pycache__/defines.cpython-310.pyc index 0298590..3d80324 100644 Binary files a/tools/__pycache__/defines.cpython-310.pyc and b/tools/__pycache__/defines.cpython-310.pyc differ diff --git a/tools/__pycache__/document_tools.cpython-310.pyc b/tools/__pycache__/document_tools.cpython-310.pyc index 8b950c5..e0d3a9c 100644 Binary files a/tools/__pycache__/document_tools.cpython-310.pyc and b/tools/__pycache__/document_tools.cpython-310.pyc differ diff --git a/tools/content_tools.py b/tools/content_tools.py index 4c76a88..67f6ca7 100644 --- a/tools/content_tools.py +++ b/tools/content_tools.py @@ -138,7 +138,7 @@ def split_table_by_row_content( return f"处理表格时出错: {str(e)}" -async def add_heading(filename: str, text: str, level: int = 1) -> str: +def add_heading(filename: str, text: str, level: int = 1) -> str: """对文档增加标题 Args: @@ -179,10 +179,10 @@ async def add_heading(filename: str, text: str, level: int = 1) -> str: doc.save(filename) return f"Heading '{text}' (level {level}) added to {filename}" except Exception as style_error: + print("style-based approach fails, use direct formatting") # If style-based approach fails, use direct formatting - paragraph = doc.add_paragraph(text) - paragraph.style = doc.styles['Normal'] - run = paragraph.runs[0] + paragraph = doc.add_paragraph() + run = paragraph.add_run(text) run.bold = True rPr = run.element.get_or_add_rPr() rFonts = rPr.get_or_add_rFonts() @@ -657,3 +657,38 @@ def search_and_replace(filename: str, find_text: str, replace_text: str) -> str: except Exception as e: return f"Failed to search and replace: {str(e)}" +def add_jf_picture_table( + typical_picture_dict : dict, + defect_picture_dict : dict, + TYPICAL_MUBAN_DIR : str, + DEFECT_MUBAN_DIR : str, + output_dir : str, + ): + """添加金风版本的图片展示表格 + 逻辑: + 典型图模板是三行五列的表格。一列对应一张典型图图片信息。 + 缺陷图模板是二行五列的表格。一列对应一张缺陷图图片信息。 + 1.每次循环添加一次典型图片。 + 第一行为dict的key + 第二行为图片,如有缺陷,则不是图片url,而是字符串 损伤n处,详见下表。此时要有变量记录总损伤数。 + 第三行看情况,如果正常,则保持默认,如果有缺陷,则字段为: 损伤类型n处。 + 2.如果上一次循环没有缺陷图,则回到1,否则前往3。 + 3.如果上一次循环中,有缺陷图存在,则进入对应的缺陷图添加模式,使用缺陷图表格模板。 + 根据上一行每列的总缺陷数遍历缺陷字典。 + 当缺陷数大于5时,也要调用模板进行下一行的添加。 + 缺陷图表格使用缺陷图模板。第一行为defect_picture_dict的key,第二行为图片url,第三行为损伤类型。 + + Args: + typical_picture_dict: #有两种情况 + { + str(图片描述) : str(图片地址), #情况一 + str(损伤有n处,见下表) : str({缺陷类型}n处), #情况二 + ... + } + defect_picture_dict: #只有一种情况 + { + str(图片描述) : str(图片地址), + } + TYPICAL_MUBAN_DIR: 典型图模板路径 + DEFECT_MUBAN_DIR: 缺陷图模板路径 + """ \ No newline at end of file diff --git a/tools/defines.py b/tools/defines.py index ed9410e..0977ef5 100644 --- a/tools/defines.py +++ b/tools/defines.py @@ -67,6 +67,28 @@ class TEMPLATE_HEADER: QN = qn('w:eastAsia') FONT = 'Arial' PT = Pt(9) + class FANGLEI: + TYPICAL_LIST = [ + "防雷导通测试\n叶尖至塔基测试阻值({Resistance} mΩ)", + "防雷导通测试\n叶尖与无人吊篮平台接触良好", + "防雷导通测试\n叶尖至塔基检测导线线组值" + ] + class WAIBU: + TYPICAL_LIST = [ + "外观检查(迎、背风面是否有漆面脱落、裂纹等)", + "外观检查(前、后缘;如前缘漆面脱落、合模缝开裂等)", + "叶片防雨环检查", + "叶尖接闪器、排水孔检查,如接闪器损伤、雷击熔融;流水孔堵塞", + ] + class NEIBU: + TYPICAL_LIST = [ + "叶片铭牌", + "根部检查(挡板、盖板检查是否损坏、金属件是否丢失等)", + "避雷系统检查(避雷线是否断裂、雷电记录卡是否缺失等)", + "前后缘检查(前缘粘接及补强是否有开裂、裂纹)", + "上下蒙皮检查(蒙皮是否有褶皱、发白、折痕、分层、裂纹等)", + "腹板检查(腹板是否变形、偏移,腹板粘接是否开裂、裂纹等)", + ] class DT_HEADER: ENUM = 'DT' @@ -92,7 +114,7 @@ STYLE_CONFIG = { "alignment": "center", "font": { "name": "宋体", - "size": 12, + "size": 8, "bold": False, }, "border": { @@ -109,7 +131,7 @@ TITLE_STYLE_CONFIG = { "alignment": "center", "font": { "name": "宋体", - "size": 12, + "size": 9, "bold": False, }, "border": { @@ -122,6 +144,8 @@ TITLE_STYLE_CONFIG = { "color": "FFFFFF" } } + + DEFECT_TABLE_TITLE = '叶片故障信息表' DEFECT_TABLE = ['机组号', '叶片编号', '损伤名称', '损坏描述', '面积/S', '备注'] @@ -147,4 +171,65 @@ class USE_TOOL_ENUM: ["活动扳手", "17-19", "2", "拆卸·禁锢盖板螺栓"], ["手机", "/", "2", "拍照记录"], ["叶片内部爬壁机器人", "DT02", "1", "拍照记录"] - ] \ No newline at end of file + ] + +from enum import Enum +from docx.shared import RGBColor +class DocxColors(Enum): + """常用颜色枚举""" + BLACK = RGBColor(0, 0, 0) + WHITE = RGBColor(255, 255, 255) + RED = RGBColor(255, 0, 0) + GREEN = RGBColor(0, 255, 0) + BLUE = RGBColor(0, 0, 255) + YELLOW = RGBColor(255, 255, 0) + PURPLE = RGBColor(128, 0, 128) + ORANGE = RGBColor(255, 165, 0) + GRAY = RGBColor(128, 128, 128) + DARK_RED = RGBColor(139, 0, 0) + DARK_GREEN = RGBColor(0, 100, 0) + DARK_BLUE = RGBColor(0, 0, 139) + LIGHT_BLUE = RGBColor(173, 216, 230) + PINK = RGBColor(255, 192, 203) + BROWN = RGBColor(165, 42, 42) + + # 微软Office常用颜色 + MS_BLUE = RGBColor(46, 116, 181) + MS_ORANGE = RGBColor(247, 150, 70) + MS_GREEN = RGBColor(80, 175, 74) + MS_RED = RGBColor(217, 83, 79) + MS_GRAY = RGBColor(166, 166, 166) + + # 获取颜色值 + @property + def rgb(self): + return self.value + +HEADING_1_CONFIG = { + "alignment": "left", + "font" : { + "name" : "宋体", + "size" : Pt(11), + "bold" : True, + "color" : DocxColors.BLACK.rgb + }, +} + +HEADING_2_CONFIG = { + "alignment": "left", + "font" : { + "name" : "宋体", + "size" : Pt(10), + "bold" : True, + "color" : DocxColors.BLACK.rgb + }, +} +HEADING_3_CONFIG = { + "alignment": "left", + "font" : { + "name" : "宋体", + "size" : Pt(9), + "bold" : True, + "color" : DocxColors.BLACK.rgb + }, +} diff --git a/tools/document_tools.py b/tools/document_tools.py index 5ec53b3..97cb1a6 100644 --- a/tools/document_tools.py +++ b/tools/document_tools.py @@ -219,6 +219,7 @@ def write_table(target_filename: str, rows: int, cols: int, table_num: int, data data: 表格数据,二维列表,每个单元格为字符串 ifadjustheight: bool,为真则表格行高自动调整 """ + table_num = -1 target_filename = ensure_docx_extension(target_filename) # Check if target file is writeable is_writeable, error_message = check_file_writeable(target_filename) @@ -289,7 +290,7 @@ def set_document_para(target_doc: Document) -> Document: return target_doc -def add_table_to_document(target_filename: str, source_filename: str, rows: int, cols: int, table_num: int, data: Optional[List[List[str]]] = None, ifadjustheight: Optional[bool] = True, height: Optional[float] = 1, key_words: re.Pattern[str] = None, ALIGMENT: Optional[str] = 'CENTER') -> str: +def add_table_to_document(target_filename: str, source_filename: str, rows: int, cols: int, table_num: int, data: Optional[List[List[str]]] = None, ifadjustheight: Optional[bool] = True, height: Optional[float] = 1, key_words: re.Pattern[str] = None, ALIGMENT: Optional[str] = 'CENTER', if_merge : Optional[bool] = True, Report_Enum = 'DT', if_para : Optional[bool] = True) -> str: """复制源文件中的文字与表格(先文字后表格格式)到目标文档 Args: target_filename: 目标文档路径 @@ -305,62 +306,59 @@ def add_table_to_document(target_filename: str, source_filename: str, rows: int, source_filename = ensure_docx_extension(source_filename) source_doc = Document(source_filename) target_doc = Document(target_filename) - target_doc.add_paragraph() - try: - # Copy all paragraphs - for paragraph in source_doc.paragraphs: - # Create a new paragraph with the same text and style - new_paragraph = target_doc.add_paragraph(paragraph.text) - - new_paragraph.style = target_doc.styles['Normal'] # Default style - #获取合并等样式2025427 - new_paragraph.alignment = paragraph.alignment + if if_para: + try: + # Copy all paragraphs + for paragraph in source_doc.paragraphs: + # Create a new paragraph with the same text and style + new_paragraph = target_doc.add_paragraph(paragraph.text) + + new_paragraph.style = target_doc.styles['Normal'] # Default style + #获取合并等样式2025427 + new_paragraph.alignment = paragraph.alignment - # 复制段落分页属性 - new_paragraph.paragraph_format.page_break_before = paragraph.paragraph_format.page_break_before - # Try to match the style if possible - try: - if paragraph.style and paragraph.style.name in target_doc.styles: - new_paragraph.style = target_doc.styles[paragraph.style.name] - except: - pass - - - # Copy run formatting - for i, run in enumerate(paragraph.runs): - if i < len(new_paragraph.runs): - new_run = new_paragraph.runs[i] - # Copy basic formatting - new_run.bold = run.bold - new_run.italic = run.italic - new_run.underline = run.underline - #添加同时合并字体2025427 - new_run.font.name = run.font.name - rPr = new_run.element.get_or_add_rPr() - rFonts = rPr.get_or_add_rFonts() - # 检查 run.font.name 是否为 None - if run.font.name is None: - # 设置默认的中文字体名称 - run.font.name = '宋体(中文正文)' # 或者使用其他你喜欢的中文字体 - rFonts.set(qn('w:eastAsia'), run.font.name) - new_run.font.color.rgb = run.font.color.rgb + # 复制段落分页属性 + new_paragraph.paragraph_format.page_break_before = paragraph.paragraph_format.page_break_before + # Try to match the style if possible + try: + if paragraph.style and paragraph.style.name in target_doc.styles: + new_paragraph.style = target_doc.styles[paragraph.style.name] + except: + pass + + + # Copy run formatting + for i, run in enumerate(paragraph.runs): + if i < len(new_paragraph.runs): + new_run = new_paragraph.runs[i] + # Copy basic formatting + new_run.bold = run.bold + new_run.italic = run.italic + new_run.underline = run.underline + #添加同时合并字体2025427 + new_run.font.name = run.font.name + rPr = new_run.element.get_or_add_rPr() + rFonts = rPr.get_or_add_rFonts() + # 检查 run.font.name 是否为 None + if run.font.name is None: + # 设置默认的中文字体名称 + run.font.name = '宋体(中文正文)' # 或者使用其他你喜欢的中文字体 + rFonts.set(qn('w:eastAsia'), run.font.name) + new_run.font.color.rgb = run.font.color.rgb - # Font size if specified - if run.font.size: - new_run.font.size = run.font.size + # Font size if specified + if run.font.size: + new_run.font.size = run.font.size - except Exception as e: - print(f"添加表格前文章失败:{str(e)}") + except Exception as e: + print(f"添加表格前文章失败:{str(e)}") try:# Copy all tables - copy_table(source_doc.tables[0], target_doc, ifadjustheight, height) + copy_table(source_doc.tables[0], target_doc, ifadjustheight, height, if_merge, REPORT_ENUM=Report_Enum) except Exception as e: print(f"添加表格失败:{str(e)}") print(f"{target_doc}写入表格{source_doc.tables[0]}成功") - target_doc = set_document_para(target_doc) - target_doc.save(target_filename) - target_doc = Document(target_filename) if data: try: target_doc = write_table(target_filename, rows, cols, table_num, data, ifadjustheight, height, key_words, ALIGMENT) @@ -755,7 +753,7 @@ async def process_server_images_table(data_list, image_source_list, output_dir, print(message) return i # 返回最后使用的表格序号 -def add_header(target_dir : str, report_enum : str, if_clear_header : Optional[bool] = True): +def add_header(target_dir : str, report_enum : str, if_clear_header : Optional[bool] = True, if_section : Optional[bool] = True, text : str = None): """添加页眉,添加封面后调用此函数,会分离页面和后续页面的节。 Args: @@ -770,35 +768,43 @@ def add_header(target_dir : str, report_enum : str, if_clear_header : Optional[b for section in document.sections: # 遍历所有节的页眉 clear_header(section) # 清除页眉的段落 - print(f"文档节数:{len(document.sections)},开始往当前节后添加页眉") - document.sections[0].header.is_linked_to_previous = False # 取消页眉与上一页关联 + if if_section: + print(f"文档节数:{len(document.sections)},开始往当前节后添加页眉") + document.sections[0].header.is_linked_to_previous = False # 取消页眉与上一页关联 - document.add_section(WD_SECTION.NEW_PAGE) - header = document.sections[1].header + document.add_section(WD_SECTION.NEW_PAGE) + header = document.sections[1].header - header.is_linked_to_previous = False # 取消页眉与上一页关联 + header.is_linked_to_previous = False # 取消页眉与上一页关联 + else: + header = document.sections[-1].header + header.is_linked_to_previous = False # 取消页眉与上一页关联 paragraph = header.paragraphs[0] # 获取页眉的第一个段落 run = paragraph.add_run() if report_enum == 'JF': print("添加金风模板的页眉") pic = run.add_picture(get_template_pic(TEMPLATE_HEADER.JINFENG_HEADER.PIC_DIR)) - run = paragraph.add_run(TEMPLATE_HEADER.JINFENG_HEADER.PARA) + if text: + run = paragraph.add_run(text) + else: + run = paragraph.add_run(TEMPLATE_HEADER.JINFENG_HEADER.PARA) run.font.name = TEMPLATE_HEADER.JINFENG_HEADER.FONT run.font.size = TEMPLATE_HEADER.JINFENG_HEADER.PT - document.save(target_dir) # 保存文档 elif report_enum == 'DT': print("添加迪特模板的页眉") pic = run.add_picture(get_template_pic(TEMPLATE_HEADER.DT_HEADER.PIC_DIR)) - run = paragraph.add_run(TEMPLATE_HEADER.DT_HEADER.PARA) + if text: + run = paragraph.add_run(text) + else: + run = paragraph.add_run(TEMPLATE_HEADER.DT_HEADER.PARA) run.font.name = TEMPLATE_HEADER.DT_HEADER.FONT run.font.size = TEMPLATE_HEADER.DT_HEADER.PT - document.save(target_dir) # 保存文档 else: print("未知模板,不添加页眉") - # 定义边框的 XML 字符串 + # 定义边框的 XML 字符串 border_xml = """ @@ -811,17 +817,37 @@ def add_header(target_dir : str, report_enum : str, if_clear_header : Optional[b pPr.append(pBdr) print(f"文档节数:{len(document.sections)}") + document.save(target_dir) # 保存文档 from docx.enum.section import WD_ORIENT from docx.enum.text import WD_BREAK - +from docx.document import Document as Document_ def add_landscape_section(target_dir : str): # 添加横向节 doc = Document(target_dir) section = doc.add_section() section.orientation = WD_ORIENT.LANDSCAPE section.page_width, section.page_height = section.page_height, section.page_width + print(f"文档:{target_dir},添加了新横向节,页宽:{section.page_width}, 页高:{section.page_height}") + return doc +def add_section(target_dir : str) -> Document_: + doc = Document(target_dir) + section = doc.add_section() + return doc + +def add_title(target_dir : str, title : str, style_config : dict = {}): + doc = Document(target_dir) + para = doc.add_paragraph() + run = para.add_run(title) + font_config = style_config.get('font', {}) + run.font.name = font_config.get('name', "宋体") + run.element.get_or_add_rPr().get_or_add_rFonts().set(qn('w:eastAsia'), font_config.get('name', "宋体")) + run.font.size = font_config.get('size', Pt(14)) + run.bold = font_config.get('bold', False) + para.alignment = style_config.get('alignment', WD_ALIGN_PARAGRAPH.CENTER) + print(f"添加新标题:{title},字体:{run.font.name},大小:{run.font.size},是否加粗:{run.bold}") + return doc def merge_documents(target_dir : str, source_dirs : List[str]): """合并多个文档、图片 @@ -924,11 +950,42 @@ def add_defect_info_table(output_dir, defect_info, MUBAN_DIR, total_table_num, R return total_table_num from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.shared import RGBColor def add_table_title(output_dir, TITLE): doc = Document(output_dir) table = doc.add_table(rows=1, cols=6, style='Table Grid') table.cell(0,0).merge(table.cell(0,5)) para = table.cell(0,0).paragraphs[0] - para.text = TITLE + run = para.add_run(TITLE) + run.font.name = "宋体" + run.font.size = Pt(9) para.alignment = WD_ALIGN_PARAGRAPH.CENTER - doc.save(output_dir) \ No newline at end of file + print(f"添加了标题表格:{TITLE}") + doc.save(output_dir) + +def change_heading(output_dir, style_name, style_config = {}): + doc = Document(output_dir) + heading_style = doc.styles[style_name] + font_config = style_config.get('font', {}) + heading_style.font.name = font_config.get('name', "宋体") + heading_style.element.get_or_add_rPr().get_or_add_rFonts().set(qn('w:eastAsia'), font_config.get('name', "宋体")) + heading_style.font.size = font_config.get('size', Pt(11)) + heading_style.bold = font_config.get('bold', True) + heading_style.font.color.rgb = font_config.get('color', DocxColors.BLACK.rgb) + print(f"修改了标题样式:{style_name},字体:{heading_style.font.name},大小:{heading_style.font.size},是否加粗:{heading_style.bold}") + doc.save(output_dir) + +from docxtpl import DocxTemplate + +def add_auto_toc_at_end(doc_path): + """使用 python-docx-template 在末尾自动生成目录""" + doc = DocxTemplate(doc_path) + + # 渲染模板(r.toc=True 会触发目录生成) + context = { + 'r': { + 'toc': True # 自动生成目录 + } + } + doc.render(context) + doc.save(doc_path) \ No newline at end of file