From 78ab1e396208419948db4eb5d89295f014dd3abd Mon Sep 17 00:00:00 2001 From: Voge1imkafig <2390349500@qq.com> Date: Thu, 31 Jul 2025 18:10:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=A0=87=E9=A2=98=E5=88=86?= =?UTF-8?q?=E7=BA=A7=E6=A0=B7=E5=BC=8F=E9=85=8D=E7=BD=AE=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=A8=AA=E5=90=91=E9=A1=B5=E9=9D=A2=EF=BC=8C=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=B7=BB=E5=8A=A0=E9=87=91=E9=A3=8E=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E7=9A=84=E5=87=BD=E6=95=B0=E3=80=82=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E6=9F=90=E4=BA=9B=E5=87=BD=E6=95=B0=E7=9A=84=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E8=8E=B7=E5=8F=96=E7=AD=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Generate_Report.py | 2 +- Jf_report.py | 80 ++++++-- __pycache__/Jf_report.cpython-310.pyc | Bin 9168 -> 9731 bytes core/__pycache__/tables.cpython-310.pyc | Bin 7242 -> 7559 bytes core/tables.py | 17 +- muban/jfempty.docx | Bin 0 -> 5949 bytes ...一期012号2025年07月31日版41.docx} | Bin 140854 -> 141263 bytes test.py | 117 +++++++++++ .../__pycache__/content_tools.cpython-310.pyc | Bin 13740 -> 13771 bytes tools/__pycache__/defines.cpython-310.pyc | Bin 5889 -> 8552 bytes .../document_tools.cpython-310.pyc | Bin 26029 -> 28036 bytes tools/content_tools.py | 43 ++++- tools/defines.py | 91 ++++++++- tools/document_tools.py | 181 ++++++++++++------ 14 files changed, 445 insertions(+), 86 deletions(-) create mode 100644 muban/jfempty.docx rename output/{三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月30日版.docx => 三峡能源阿城万兴风电场防雷通道检测项目项目叶片外观、内部、防雷检查报告一期012号2025年07月31日版41.docx} (84%) create mode 100644 test.py 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 86bf4361c2e1bd1ebb0c7cb9530644d53dd6c903..402e19a3643ea67e7a01653d23f9ffb1dd46e960 100644 GIT binary patch delta 2847 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 delta 1759 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 delta 17500 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%0AgMTj#z!UyGFB3M7|E9QO~hDf=; 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 delta 1183 zcmY+COH30%7{_O}?b6p$+S2k+KqFd3B_K5hqsC{9G4UY22*ze%3iP$Dv#UIu1{5C< zW7Le|gDAzL(F5thizkg5U(tBnm>9hn^9V=bLZl`{w)Rb?QM%$tsE) ziRa7J$-&~ha!gU5ijn>tBXk-Yh@lCbN29WVnIx2S7-?QRG9<&+FOAe-1aCJYxC;#- zCJ`xx^d;hNOWElPVrS9}B91$@E@aq~j)Kh49M;$ISIQ#aR^nuKG3$ca(JB5**)#SM zqkIKMqdm+~P#B)Wc_(uuD@kP?V$PV4Ig?eySBLU0QpH>`KXWAmh2R{@yP3OCE&d+j zBmQ(K6V7`vVxB?`^OC>>Cc!yLj3GOT&Kk9(dIF2Jb+LNQFRUS9y)Ufc@ISM>(22jP z>{Pyp)D)4LLh6l0#enZ4t~BL+S(;JPRFn!G;1T~6Ud-qH-AheHB_x(psX9Q_+@LAz z#z;D@(^la}*9q`Q;DawM#3k|RhXkZ?E(creZpn*zG#J6@;?dwU?4W(%y(%=+nh=5} z0V#kNPyxsQU}w|0H$Jk9(k!JKKi*N#e}vpsI?Nh?9e^SJIZ%r;yfM5PXNpI|podittdyU)WA&|rTd*ciF0?2d4M@{E!o++Wf!5yU+`R-*u zk1WVo7)8`xJ*OIj^ai;6uSo%h(}0_RTL3HAZBSP18KF%1WSl1YN9bLCrFj!R%ilJ) z%dpEf=5ZxPueCGdf*mox2-?lupJ!MMEL0Mc2V-b>|wW^W3%m$sax%C$|6q diff --git a/tools/__pycache__/defines.cpython-310.pyc b/tools/__pycache__/defines.cpython-310.pyc index 029859049a571a6bafdc05a635500093dd626b7b..3d80324c4679fc70178a19ef96fcef64799c95d1 100644 GIT binary patch delta 3005 zcmaJ@Yfu~471munSUnI3iMNfNOdCf|2IIJC{lt+#U}{-Vfy1B~M-9HJ9|bG3vN~9l2crRhvPo&4yJ=FxL@*Fc=9S@z?* z=broBv*+9go#kn_HJqJo(!ftv(bd!Q+pbx+kbf<_W+D2$w4CnZ8%QCaLtc*A=)OSS zDGl8}Ndk6yAm9Lg5O{vAh907o7d5o9iwP9a?euV4VS7=ah-iSn)uwMR4ipm&c)6$> zyxgIpE^VNMR?*i(23p-ks4Y}-w)E^4>KWD1no%aORqbzC<2M4i z+X1masM5+R{w6L$M7|GoTp0}Kwjpc>NLiX%8tSTC-XQ;1TakmS09y^bU+4f>jfHR( zyv^o-bQ#%wV1mqiPsvQPtImDgsf)V7D%=}N-@hQjl;czI)#=r~e{^)FyLvKr`!csD z#o;+&U|JlFi^)sSOkZ3`4?IDKyBDOD$I@&ZvvTyiGD5r;yo7;1DLMQ!c}tkS02bgV z6WgRC3|tXsCZyzTA=!bNieNqp_CJ#1m*uL>NPTlkfYD~92g(L{&D{7%xH$v!hBbM`}qO3Fqhi_ zlX&6f4kGOMKS}g?Fo}k!MF|OmJ7wL2PTw-D}HN(;wWFMjot7sm*6AD1GmdG_n9=h5l>OO`}Uv;FXv+0^YP>)j}6=J7I=K zc$Gq9%Lm8I-?I;yaWBd1fZGXcqKMyPwU=l?aCs-avQ@!G*8~!Hx4CHdZ$Uk9b_w9{&k2Myvpv zBY-{b0h7+~%?0iNZlihB4m=;YgXYr$;03@7X%Q_3UI@GdpDt}I zP!uYrrF6?hO&5WG3%0_=T9z_Zhfn@e&QTu+YRQ- zHwYaFQwUcPaA9O-5k5x{5k5uuBLeQdOgX}Ngrykbe-MTc@LJ0>Aj~2B7~wAnxO+48 z2-5&3p=j$r$nnLUATR0PXwJfJcM=~ITmOr9+oBsX^=H3CsZS)hu70T`;Hmon3PT==~Zcm7vgH-x<@4g45u zjB#NwK7==d$043OmKQ(TXZ?)UO61Yp+b}X?25{;)`A$6sobw@I?VJqPf;@nHd&*Yr zsc{|mHU-_TM$h6)`NgCKcWFu&f<4N$qbKH9k?ui;ai?U}kJwHuZ< zzGK;=TKIpP^K;mP?O_^i3svGuiG0Sl7Wm1l{8B;HK0BQ73`?xUQeYvugxSWx;l;r5 SrTfzGHDmr(%e2ulef>XcML9(P delta 587 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 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