1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849 |
- from docx import Document
- from docx.shared import Inches, Pt, RGBColor, Cm
- from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
- from docx.enum.section import WD_SECTION_START, WD_ORIENTATION
- from docx.enum.table import WD_ALIGN_VERTICAL
- from docx.oxml.ns import qn
- from docx.table import _Cell
- from docx.oxml import OxmlElement
- from docx.oxml.shared import qn
- import os
- import openpyxl
- # 全局文档对象
- _document = None
- def get_document():
- """获取当前文档对象,如果不存在则创建新文档"""
- global _document
- if _document is None:
- _document = Document()
- return _document
- # 基本文档操作
- def create_new_document():
- """创建一个新的Word文档"""
- global _document
- _document = Document()
- return "已创建新文档"
- def save_document(file_path):
- """保存Word文档"""
- doc = get_document()
- doc.save(file_path)
- return f"文档已保存为 {file_path}"
- def open_document(file_path):
- """打开现有的Word文档"""
- global _document
- if not os.path.exists(file_path):
- return f"错误:文件 {file_path} 不存在"
- _document = Document(file_path)
- return f"已打开文档 {file_path}"
- # 内容添加函数
- def add_paragraph_to_docx(text):
- """向Word文档添加段落"""
- doc = get_document()
- doc.add_paragraph(text)
- return "段落已添加"
- # 设置全局字体
- def set_global_font(font_name=None, font_size=None, font_color=None):
- """
- 设置文档的全局字体
-
- 参数:
- font_name: 字体名称
- font_size: 字体大小(磅)
- font_color: 字体颜色(RGB格式,如"FF0000"表示红色)
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
-
- # 遍历文档中的所有段落
- for paragraph in doc.paragraphs:
- for run in paragraph.runs:
- if font_name:
- run.font.name = font_name
- if font_size is not None:
- run.font.size = Pt(font_size)
- if font_color:
- run.font.color.rgb = RGBColor.from_string(font_color)
-
- # 遍历文档中的所有表格
- for table in doc.tables:
- for row in table.rows:
- for cell in row.cells:
- for paragraph in cell.paragraphs:
- for run in paragraph.runs:
- if font_name:
- run.font.name = font_name
- if font_size is not None:
- run.font.size = Pt(font_size)
- if font_color:
- run.font.color.rgb = RGBColor.from_string(font_color)
-
- return "已设置全局字体"
- except Exception as e:
- return f"设置全局字体时出错: {str(e)}"
- def add_heading(text, level=1):
- """添加标题"""
- doc = get_document()
- doc.add_heading(text, level=level)
- return f"已添加{level}级标题: {text}"
- def add_table(rows, cols, data=None):
- """添加表格"""
- doc = get_document()
- table = doc.add_table(rows=rows, cols=cols)
-
- # 如果提供了数据,填充表格
- if data:
- for i in range(min(len(data), rows)):
- row_data = data[i]
- for j in range(min(len(row_data), cols)):
- table.cell(i, j).text = str(row_data[j])
-
- return f"已添加{rows}行{cols}列的表格"
- def add_picture(image_path, width=None, height=None):
- """添加图片"""
- doc = get_document()
-
- if not os.path.exists(image_path):
- return f"错误:图片文件 {image_path} 不存在"
-
- if width and height:
- doc.add_picture(image_path, width=Cm(width), height=Cm(height))
- elif width:
- doc.add_picture(image_path, width=Cm(width))
- elif height:
- doc.add_picture(image_path, height=Cm(height))
- else:
- doc.add_picture(image_path)
-
- return f"已添加图片: {image_path}"
- def add_page_break():
- """添加分页符"""
- doc = get_document()
- doc.add_page_break()
- return "已添加分页符"
- # 样式和格式设置
- def set_paragraph_style(paragraph_index, style_name):
- """设置段落样式"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- try:
- doc.paragraphs[paragraph_index].style = style_name
- return f"已将段落 {paragraph_index} 的样式设置为 {style_name}"
- except Exception as e:
- return f"设置样式失败: {str(e)}"
- def set_font(paragraph_index, run_index, font_name=None, font_size=None,
- bold=None, italic=None, underline=None, color=None):
- """设置文本字体"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- paragraph = doc.paragraphs[paragraph_index]
-
- if run_index >= len(paragraph.runs):
- return f"错误:文本运行索引 {run_index} 超出范围"
-
- run = paragraph.runs[run_index]
-
- if font_name:
- run.font.name = font_name
- # 设置中文字体
- run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
-
- if font_size is not None:
- run.font.size = Pt(font_size)
-
- if bold is not None:
- run.font.bold = bold
-
- if italic is not None:
- run.font.italic = italic
-
- if underline is not None:
- run.font.underline = underline
-
- if color:
- # 将十六进制颜色转换为RGB
- if color.startswith('#'):
- color = color[1:]
- r = int(color[0:2], 16)
- g = int(color[2:4], 16)
- b = int(color[4:6], 16)
- run.font.color.rgb = RGBColor(r, g, b)
-
- return "已设置字体属性"
- def set_paragraph_alignment(paragraph_index, alignment):
- """设置段落对齐方式"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- paragraph = doc.paragraphs[paragraph_index]
-
- alignment_map = {
- "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
- "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
- "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT,
- "JUSTIFY": WD_ALIGN_PARAGRAPH.JUSTIFY
- }
-
- if alignment not in alignment_map:
- return f"错误:不支持的对齐方式 {alignment}"
-
- paragraph.alignment = alignment_map[alignment]
- return f"已将段落 {paragraph_index} 的对齐方式设置为 {alignment}"
- def set_paragraph_spacing(paragraph_index, before=None, after=None, line_spacing=None):
- """设置段落间距"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- paragraph = doc.paragraphs[paragraph_index]
-
- if before is not None:
- paragraph.paragraph_format.space_before = Pt(before)
-
- if after is not None:
- paragraph.paragraph_format.space_after = Pt(after)
-
- if line_spacing is not None:
- paragraph.paragraph_format.line_spacing = line_spacing
- paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
-
- return f"已设置段落 {paragraph_index} 的间距"
- # 节和页面设置
- def add_section(start_type="NEW_PAGE"):
- """添加新的节"""
- doc = get_document()
-
- start_type_map = {
- "NEW_PAGE": WD_SECTION_START.NEW_PAGE,
- "EVEN_PAGE": WD_SECTION_START.EVEN_PAGE,
- "ODD_PAGE": WD_SECTION_START.ODD_PAGE,
- "CONTINUOUS": WD_SECTION_START.CONTINUOUS
- }
-
- if start_type not in start_type_map:
- return f"错误:不支持的节开始类型 {start_type}"
-
- doc.add_section(start_type_map[start_type])
- return f"已添加新节,开始类型为 {start_type}"
- def set_section_orientation(section_index, orientation):
- """设置节的页面方向"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
-
- orientation_map = {
- "PORTRAIT": WD_ORIENTATION.PORTRAIT,
- "LANDSCAPE": WD_ORIENTATION.LANDSCAPE
- }
-
- if orientation not in orientation_map:
- return f"错误:不支持的页面方向 {orientation}"
-
- section.orientation = orientation_map[orientation]
- return f"已将节 {section_index} 的页面方向设置为 {orientation}"
- def set_section_page_size(section_index, width, height):
- """设置节的页面大小"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
-
- section.page_width = Cm(width)
- section.page_height = Cm(height)
-
- return f"已将节 {section_index} 的页面大小设置为 {width}cm x {height}cm"
- def set_section_margins(section_index, top=None, right=None, bottom=None, left=None):
- """设置节的页边距"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
-
- if top is not None:
- section.top_margin = Cm(top)
-
- if right is not None:
- section.right_margin = Cm(right)
-
- if bottom is not None:
- section.bottom_margin = Cm(bottom)
-
- if left is not None:
- section.left_margin = Cm(left)
-
- return f"已设置节 {section_index} 的页边距"
- # 页眉页脚
- def add_header(section_index, text):
- """添加页眉"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
- header = section.header
- header.paragraphs[0].text = text
-
- return f"已为节 {section_index} 添加页眉: {text}"
- def add_footer(section_index, text):
- """添加页脚"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
- footer = section.footer
- footer.paragraphs[0].text = text
-
- return f"已为节 {section_index} 添加页脚: {text}"
- def add_page_number(section_index, position="FOOTER", alignment="CENTER", format=None):
- """添加页码"""
- doc = get_document()
-
- if section_index >= len(doc.sections):
- return f"错误:节索引 {section_index} 超出范围"
-
- section = doc.sections[section_index]
-
- # 获取页眉或页脚
- if position == "HEADER":
- container = section.header
- else: # FOOTER
- container = section.footer
-
- # 清除现有内容
- for paragraph in container.paragraphs:
- paragraph.clear()
-
- # 添加新段落
- paragraph = container.paragraphs[0]
-
- # 设置对齐方式
- alignment_map = {
- "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
- "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
- "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT
- }
-
- if alignment in alignment_map:
- paragraph.alignment = alignment_map[alignment]
-
- # 添加页码字段
- run = paragraph.add_run()
-
- # 这里使用一个简单的方法来模拟页码
- # 实际上,python-docx对页码字段的支持有限
- # 这里只是添加一个占位符文本
- if format:
- run.text = format.format("X") # 使用X作为页码占位符
- else:
- run.text = "Page X"
-
- return f"已为节 {section_index} 添加页码"
- # 表格操作
- def merge_table_cells(table_index, start_row, start_col, end_row, end_col):
- """合并表格单元格"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查行列索引是否有效
- if start_row < 0 or start_col < 0 or end_row >= len(table.rows) or end_col >= len(table.columns):
- return "错误:行列索引超出范围"
-
- # 获取要合并的单元格
- start_cell = table.cell(start_row, start_col)
- end_cell = table.cell(end_row, end_col)
-
- # 合并单元格
- start_cell.merge(end_cell)
-
- return f"已合并表格 {table_index} 的单元格 ({start_row},{start_col}) 到 ({end_row},{end_col})"
- def set_table_cell_text(table_index, row, col, text):
- """设置表格单元格文本"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查行列索引是否有效
- if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
- return "错误:行列索引超出范围"
-
- # 设置单元格文本
- table.cell(row, col).text = text
-
- return f"已设置表格 {table_index} 单元格 ({row},{col}) 的文本"
- def set_table_style(table_index, style_name):
- """设置表格样式"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- try:
- table.style = style_name
- return f"已将表格 {table_index} 的样式设置为 {style_name}"
- except Exception as e:
- return f"设置表格样式失败: {str(e)}"
- def set_table_cell_background(table_index, row, col, color):
- """设置表格单元格背景色"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查行列索引是否有效
- if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
- return "错误:行列索引超出范围"
-
- # 获取单元格
- cell = table.cell(row, col)
-
- # 设置背景色
- # 注意:这需要使用低级API
- try:
- shading_elm = cell._element.get_or_add_tcPr().get_or_add_shd()
- shading_elm.set(qn('w:fill'), color)
- return f"已设置表格 {table_index} 单元格 ({row},{col}) 的背景色为 {color}"
- except Exception as e:
- return f"设置单元格背景色失败: {str(e)}"
- def set_table_cell_vertical_alignment(table_index, row, col, alignment):
- """设置表格单元格垂直对齐方式"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查行列索引是否有效
- if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
- return "错误:行列索引超出范围"
-
- # 获取单元格
- cell = table.cell(row, col)
-
- # 设置垂直对齐方式
- alignment_map = {
- "TOP": WD_ALIGN_VERTICAL.TOP,
- "CENTER": WD_ALIGN_VERTICAL.CENTER,
- "BOTTOM": WD_ALIGN_VERTICAL.BOTTOM
- }
-
- if alignment not in alignment_map:
- return f"错误:不支持的垂直对齐方式 {alignment}"
-
- cell.vertical_alignment = alignment_map[alignment]
-
- return f"已设置表格 {table_index} 单元格 ({row},{col}) 的垂直对齐方式为 {alignment}"
- def set_table_width(table_index, width):
- """设置表格宽度"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 设置表格宽度
- # 注意:python-docx对表格宽度的支持有限
- # 这里使用一个近似的方法
- table.autofit = False
- table.width = Cm(width)
-
- return f"已将表格 {table_index} 的宽度设置为 {width}cm"
- def set_table_column_width(table_index, col, width):
- """设置表格列宽"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查列索引是否有效
- if col < 0 or col >= len(table.columns):
- return "错误:列索引超出范围"
-
- # 设置列宽
- for cell in table.columns[col].cells:
- cell.width = Cm(width)
-
- return f"已将表格 {table_index} 列 {col} 的宽度设置为 {width}cm"
- # 高级功能
- def add_hyperlink(paragraph_index, text, url):
- """添加超链接"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- paragraph = doc.paragraphs[paragraph_index]
-
- # 添加超链接
- # 注意:python-docx对超链接的支持有限
- # 这里使用一个简单的方法
- run = paragraph.add_run(text)
- run.font.underline = True
- run.font.color.rgb = RGBColor(0, 0, 255) # 蓝色
-
- # 实际上,这并不是真正的超链接,只是模拟了超链接的外观
- # 要添加真正的超链接,需要使用更低级的API
-
- return f"已为段落 {paragraph_index} 添加超链接: {text} -> {url}"
- def add_bookmark(paragraph_index, bookmark_name, text):
- """添加书签"""
- doc = get_document()
-
- if paragraph_index >= len(doc.paragraphs):
- return f"错误:段落索引 {paragraph_index} 超出范围"
-
- paragraph = doc.paragraphs[paragraph_index]
-
- # 添加书签
- # 注意:python-docx对书签的支持有限
- # 这里只是添加文本,而不是真正的书签
- paragraph.add_run(text)
-
- return f"已为段落 {paragraph_index} 添加书签: {bookmark_name} -> {text}"
- def add_table_of_contents(title, levels=3):
- """添加目录"""
- doc = get_document()
-
- # 添加目录标题
- doc.add_heading(title, level=1)
-
- # 添加目录占位符段落
- paragraph = doc.add_paragraph()
- run = paragraph.add_run("目录将在Word中自动生成")
-
- return f"已添加目录占位符,标题为 {title},包含 {levels} 级标题"
- # 添加设置表格边框的函数
- def set_table_borders(table_index, border_style="single", border_width=1, border_color="000000",
- apply_to="all", first_row=False, first_column=False, last_row=False, last_column=False):
- """设置表格边框样式"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 边框样式映射
- style_map = {
- "single": "single",
- "thick": "thick",
- "double": "double",
- "dotted": "dotted",
- "dashed": "dashed",
- "none": "nil"
- }
-
- if border_style not in style_map:
- return f"错误:不支持的边框样式 {border_style}"
-
- border_style = style_map[border_style]
-
- # 应用边框的位置映射
- positions = []
- if apply_to == "all":
- positions = ["top", "bottom", "left", "right", "insideH", "insideV"]
- elif apply_to == "outside":
- positions = ["top", "bottom", "left", "right"]
- elif apply_to == "inside":
- positions = ["insideH", "insideV"]
- elif apply_to in ["top", "bottom", "left", "right"]:
- positions = [apply_to]
- else:
- return f"错误:不支持的边框应用位置 {apply_to}"
-
- # 为表格设置边框
- tbl = table._tbl
-
- # 获取表格属性
- tblPr = tbl.xpath('./w:tblPr')
- if not tblPr:
- tblPr = OxmlElement('w:tblPr')
- tbl.insert(0, tblPr)
- else:
- tblPr = tblPr[0]
-
- # 创建边框元素
- tblBorders = OxmlElement('w:tblBorders')
-
- # 添加各个位置的边框
- for position in positions:
- border = OxmlElement(f'w:{position}')
- border.set(qn('w:val'), border_style)
- border.set(qn('w:sz'), str(border_width * 8)) # 8 = 1pt
- border.set(qn('w:space'), '0')
- border.set(qn('w:color'), border_color)
- tblBorders.append(border)
-
- # 移除现有边框并添加新边框
- existing_borders = tblPr.xpath('./w:tblBorders')
- if existing_borders:
- tblPr.remove(existing_borders[0])
- tblPr.append(tblBorders)
-
- # 处理特殊行列边框
- if first_row or first_column or last_row or last_column:
- # 创建表格样式属性
- tblLook = OxmlElement('w:tblLook')
- tblLook.set(qn('w:val'), '0000')
- tblLook.set(qn('w:firstRow'), '1' if first_row else '0')
- tblLook.set(qn('w:lastRow'), '1' if last_row else '0')
- tblLook.set(qn('w:firstColumn'), '1' if first_column else '0')
- tblLook.set(qn('w:lastColumn'), '1' if last_column else '0')
- tblLook.set(qn('w:noHBand'), '0')
- tblLook.set(qn('w:noVBand'), '0')
-
- # 移除现有样式并添加新样式
- existing_tblLook = tblPr.xpath('./w:tblLook')
- if existing_tblLook:
- tblPr.remove(existing_tblLook[0])
- tblPr.append(tblLook)
-
- return f"已设置表格 {table_index} 的边框样式"
- # 修改 set_cell_borders 函数
- def set_cell_borders(table_index, row, col, border_style="single", border_width=1, border_color="000000",
- apply_to="all"):
- """设置单元格边框样式"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 检查行列索引是否有效
- if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
- return "错误:行列索引超出范围"
-
- # 获取单元格
- cell = table.cell(row, col)
-
- # 边框样式映射
- style_map = {
- "single": "single",
- "thick": "thick",
- "double": "double",
- "dotted": "dotted",
- "dashed": "dashed",
- "none": "nil"
- }
-
- if border_style not in style_map:
- return f"错误:不支持的边框样式 {border_style}"
-
- border_style = style_map[border_style]
-
- # 应用边框的位置
- positions = []
- if apply_to == "all":
- positions = ["top", "bottom", "left", "right"]
- elif apply_to in ["top", "bottom", "left", "right"]:
- positions = [apply_to]
- else:
- return f"错误:不支持的边框应用位置 {apply_to}"
-
- # 为单元格设置边框
- tc = cell._tc
-
- # 获取单元格属性
- tcPr = tc.xpath('./w:tcPr')
- if not tcPr:
- tcPr = OxmlElement('w:tcPr')
- tc.insert(0, tcPr)
- else:
- tcPr = tcPr[0]
-
- # 创建边框元素
- tcBorders = OxmlElement('w:tcBorders')
-
- # 添加各个位置的边框
- for position in positions:
- border = OxmlElement(f'w:{position}')
- border.set(qn('w:val'), border_style)
- border.set(qn('w:sz'), str(border_width * 8)) # 8 = 1pt
- border.set(qn('w:space'), '0')
- border.set(qn('w:color'), border_color)
- tcBorders.append(border)
-
- # 移除现有边框并添加新边框
- existing_borders = tcPr.xpath('./w:tcBorders')
- if existing_borders:
- tcPr.remove(existing_borders[0])
- tcPr.append(tcBorders)
-
- return f"已设置表格 {table_index} 单元格 ({row},{col}) 的边框样式"
- # 添加一个新的函数,用于一次性为整个表格添加标准边框
- def add_table_standard_borders(table_index):
- """为表格添加标准边框(所有单元格都有边框)"""
- doc = get_document()
-
- if table_index >= len(doc.tables):
- return f"错误:表格索引 {table_index} 超出范围"
-
- table = doc.tables[table_index]
-
- # 为表格设置标准边框
- for row in table.rows:
- for cell in row.cells:
- # 获取单元格的XML元素
- tc = cell._tc
-
- # 获取单元格属性
- tcPr = tc.xpath('./w:tcPr')
- if not tcPr:
- tcPr = OxmlElement('w:tcPr')
- tc.insert(0, tcPr)
- else:
- tcPr = tcPr[0]
-
- # 创建边框元素
- tcBorders = OxmlElement('w:tcBorders')
-
- # 添加四个方向的边框
- for position in ["top", "bottom", "left", "right"]:
- border = OxmlElement(f'w:{position}')
- border.set(qn('w:val'), 'single')
- border.set(qn('w:sz'), '4') # 0.5pt
- border.set(qn('w:space'), '0')
- border.set(qn('w:color'), '000000')
- tcBorders.append(border)
-
- # 移除现有边框并添加新边框
- existing_borders = tcPr.xpath('./w:tcBorders')
- if existing_borders:
- tcPr.remove(existing_borders[0])
- tcPr.append(tcBorders)
-
- return f"已为表格 {table_index} 添加标准边框"
- def add_border(cell):
- """为单元格添加边框"""
- tcPr = cell._element.tcPr
- if tcPr is None:
- tcPr = OxmlElement('w:tcPr')
- cell._element.append(tcPr)
-
- # 添加边框
- tcBorders = OxmlElement('w:tcBorders')
- for border in ['top', 'left', 'bottom', 'right']:
- border_element = OxmlElement(f'w:{border}')
- border_element.set(qn('w:val'), 'single')
- border_element.set(qn('w:sz'), '4') # 边框宽度
- border_element.set(qn('w:space'), '0')
- border_element.set(qn('w:color'), '000000') # 边框颜色
- tcBorders.append(border_element)
-
- tcPr.append(tcBorders)
- def copy_cell_style(excel_cell, word_cell):
- """复制单元格样式"""
- # 获取Excel单元格的字体
- if excel_cell.font:
- run = word_cell.paragraphs[0].runs
- if not run:
- run = word_cell.paragraphs[0].add_run()
- else:
- run = run[0]
-
- # 设置字体名称
- if excel_cell.font.name:
- run.font.name = excel_cell.font.name
-
- # 设置字体大小
- if excel_cell.font.size:
- # Excel字体大小与Word字体大小的转换
- run.font.size = Pt(excel_cell.font.size)
-
- # 设置粗体
- if excel_cell.font.bold:
- run.font.bold = True
-
- # 设置斜体
- if excel_cell.font.italic:
- run.font.italic = True
-
- # 设置下划线
- if excel_cell.font.underline:
- run.font.underline = True
-
- # 设置字体颜色
- if excel_cell.font.color and excel_cell.font.color.rgb:
- color = excel_cell.font.color.rgb
- if isinstance(color, str) and len(color) == 8: # ARGB格式
- rgb = color[2:] # 去掉Alpha通道
- run.font.color.rgb = RGBColor.from_string(rgb)
-
- # 设置单元格对齐方式
- if excel_cell.alignment:
- paragraph = word_cell.paragraphs[0]
-
- # 水平对齐
- if excel_cell.alignment.horizontal:
- if excel_cell.alignment.horizontal == 'center':
- paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
- elif excel_cell.alignment.horizontal == 'right':
- paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
- elif excel_cell.alignment.horizontal == 'left':
- paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
-
- # 添加边框
- add_border(word_cell)
- def copy_excel_to_word(excel_path, word_path, sheet_name=None, output_path=None):
- """
- 将Excel表格复制到Word文档
-
- 参数:
- excel_path: Excel文件路径
- word_path: Word文件路径,如果为None则创建新文档
- sheet_name: 要复制的工作表名称,如果为None则复制第一个工作表
- output_path: 输出Word文件路径,如果为None则覆盖原文件
- """
- try:
- # 加载Excel文件
- if not os.path.exists(excel_path):
- return {"error": f"Excel文件不存在: {excel_path}"}
-
- wb = openpyxl.load_workbook(excel_path, data_only=True)
-
- # 选择工作表
- if sheet_name:
- if sheet_name not in wb.sheetnames:
- return {"error": f"工作表 '{sheet_name}' 不存在"}
- ws = wb[sheet_name]
- else:
- ws = wb.active
-
- # 加载或创建Word文档
- if word_path and os.path.exists(word_path):
- doc = Document(word_path)
- else:
- doc = Document()
-
- # 获取Excel表格的行数和列数
- max_row = ws.max_row
- max_col = ws.max_column
-
- if max_row == 0 or max_col == 0:
- return {"error": "Excel表格为空"}
-
- # 在Word文档中创建表格
- table = doc.add_table(rows=max_row, cols=max_col)
- table.style = 'Table Grid' # 应用网格样式
-
- # 复制数据和样式
- for i in range(max_row):
- for j in range(max_col):
- # Excel单元格索引从1开始
- excel_cell = ws.cell(row=i+1, column=j+1)
-
- # Word表格索引从0开始
- word_cell = table.cell(i, j)
-
- # 复制单元格内容
- word_cell.text = str(excel_cell.value) if excel_cell.value is not None else ""
-
- # 复制单元格样式
- copy_cell_style(excel_cell, word_cell)
-
- # 保存Word文档
- save_path = output_path if output_path else (word_path if word_path else "output.docx")
- doc.save(save_path)
-
- return {
- "message": f"已将Excel表格复制到Word文档",
- "excel_path": excel_path,
- "sheet_name": sheet_name if sheet_name else ws.title,
- "output_path": save_path
- }
- except Exception as e:
- return {"error": f"复制Excel表格到Word文档失败: {str(e)}"}
- def copy_excel_range_to_word(excel_path, word_path, sheet_name, range_str, output_path=None):
- """
- 将Excel表格的指定区域复制到Word文档
-
- 参数:
- excel_path: Excel文件路径
- word_path: Word文件路径,如果为None则创建新文档
- sheet_name: 要复制的工作表名称
- range_str: 要复制的单元格区域,如'A1:C5'
- output_path: 输出Word文件路径,如果为None则覆盖原文件
- """
- try:
- from openpyxl.utils.cell import range_boundaries
-
- # 加载Excel文件
- if not os.path.exists(excel_path):
- return {"error": f"Excel文件不存在: {excel_path}"}
-
- wb = openpyxl.load_workbook(excel_path, data_only=True)
-
- # 选择工作表
- if sheet_name not in wb.sheetnames:
- return {"error": f"工作表 '{sheet_name}' 不存在"}
- ws = wb[sheet_name]
-
- # 解析区域范围
- try:
- min_col, min_row, max_col, max_row = range_boundaries(range_str)
- except ValueError:
- return {"error": f"无效的区域范围: {range_str}"}
-
- # 计算行数和列数
- rows = max_row - min_row + 1
- cols = max_col - min_col + 1
-
- if rows <= 0 or cols <= 0:
- return {"error": "指定的区域无效"}
-
- # 加载或创建Word文档
- if word_path and os.path.exists(word_path):
- doc = Document(word_path)
- else:
- doc = Document()
-
- # 在Word文档中创建表格
- table = doc.add_table(rows=rows, cols=cols)
- table.style = 'Table Grid' # 应用网格样式
-
- # 复制数据和样式
- for i in range(rows):
- for j in range(cols):
- # Excel单元格索引
- excel_row = min_row + i
- excel_col = min_col + j
-
- # 获取Excel单元格
- excel_cell = ws.cell(row=excel_row, column=excel_col)
-
- # Word表格索引从0开始
- word_cell = table.cell(i, j)
-
- # 复制单元格内容
- word_cell.text = str(excel_cell.value) if excel_cell.value is not None else ""
-
- # 复制单元格样式
- copy_cell_style(excel_cell, word_cell)
-
- # 保存Word文档
- save_path = output_path if output_path else (word_path if word_path else "output.docx")
- doc.save(save_path)
-
- return {
- "message": f"已将Excel表格区域复制到Word文档",
- "excel_path": excel_path,
- "sheet_name": sheet_name,
- "range": range_str,
- "output_path": save_path
- }
- except Exception as e:
- return {"error": f"复制Excel表格区域到Word文档失败: {str(e)}"}
- def add_table_row(table_index=0, position=None):
- """
- 在Word文档中的表格添加一行
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- position: 要插入行的位置,如果为None则添加到表格末尾
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return f"错误:文档中没有索引为 {table_index} 的表格"
-
- table = doc.tables[table_index]
-
- if position is None:
- # 添加到表格末尾
- table.add_row()
- return f"已在表格 {table_index} 末尾添加一行"
- else:
- # 在指定位置插入行
- row_count = len(table.rows)
- if position < 0 or position > row_count:
- return f"错误:行索引超出范围,有效范围为0-{row_count}"
-
- # 创建新行
- new_row = table.add_row()
-
- # 如果不是添加到末尾,需要移动行
- if position < row_count:
- # 将新行移动到指定位置
- for i in range(row_count, position, -1):
- # 复制上一行的内容到当前行
- for j in range(len(table.columns)):
- table.cell(i, j).text = table.cell(i-1, j).text
-
- # 清空目标位置的行
- for j in range(len(table.columns)):
- table.cell(position, j).text = ""
-
- return f"已在表格 {table_index} 的位置 {position} 插入一行"
- except Exception as e:
- return f"添加表格行时出错: {str(e)}"
- def add_table_column(table_index=0, position=None):
- """
- 在Word文档中的表格添加一列
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- position: 要插入列的位置,如果为None则添加到表格末尾
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return f"错误:文档中没有索引为 {table_index} 的表格"
-
- table = doc.tables[table_index]
-
- # 获取当前列数
- col_count = len(table.columns)
-
- if position is None:
- position = col_count
- elif position < 0 or position > col_count:
- return f"错误:列索引超出范围,有效范围为0-{col_count}"
-
- # 为每一行添加一个单元格
- for i, row in enumerate(table.rows):
- # 获取表格行的XML元素
- tr = row._tr
-
- # 创建新的单元格元素
- tc = OxmlElement('w:tc')
-
- # 添加段落到单元格
- p = OxmlElement('w:p')
- tc.append(p)
-
- # 添加单元格属性
- tcPr = OxmlElement('w:tcPr')
- tc.append(tcPr)
-
- # 确定插入位置
- if position == col_count:
- # 添加到末尾
- tr.append(tc)
- else:
- # 在指定位置插入
- ref_tc = tr.findall('.//w:tc', namespaces=tr.nsmap)[position]
- ref_tc.addprevious(tc)
-
- return f"已在表格 {table_index} 的位置 {position} 插入一列"
- except Exception as e:
- return f"添加表格列时出错: {str(e)}"
- def delete_table_row(table_index=0, row_index=None):
- """
- 删除Word文档中表格的一行
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- row_index: 要删除的行索引
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return f"错误:文档中没有索引为 {table_index} 的表格"
-
- table = doc.tables[table_index]
-
- row_count = len(table.rows)
- if row_index is None or row_index < 0 or row_index >= row_count:
- return f"错误:行索引超出范围,有效范围为0-{row_count-1}"
-
- # 获取要删除的行
- tr = table.rows[row_index]._tr
-
- # 从表格中删除行
- tr.getparent().remove(tr)
-
- return f"已删除表格 {table_index} 的第 {row_index} 行"
- except Exception as e:
- return f"删除表格行时出错: {str(e)}"
- def delete_table_column(table_index=0, column_index=None):
- """
- 删除Word文档中表格的一列
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- column_index: 要删除的列索引
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return f"错误:文档中没有索引为 {table_index} 的表格"
-
- table = doc.tables[table_index]
-
- col_count = len(table.columns)
- if column_index is None or column_index < 0 or column_index >= col_count:
- return f"错误:列索引超出范围,有效范围为0-{col_count-1}"
-
- # 遍历每一行,删除指定列的单元格
- for row in table.rows:
- # 获取行的XML元素
- tr = row._tr
-
- # 找到要删除的单元格
- cells = tr.findall('.//w:tc', namespaces=tr.nsmap)
- if column_index < len(cells):
- # 删除单元格
- tr.remove(cells[column_index])
-
- return f"已删除表格 {table_index} 的第 {column_index} 列"
- except Exception as e:
- return f"删除表格列时出错: {str(e)}"
- def get_table_dimensions(table_index=0):
- """
- 获取表格的维度(行数和列数)
-
- 参数:
- table_index: 表格索引,默认为第一个表格
-
- 返回:
- 表格的行数和列数
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
- rows = len(table.rows)
- cols = len(table.columns)
-
- return {
- "rows": rows,
- "columns": cols
- }
- except Exception as e:
- return {"error": f"获取表格维度时出错: {str(e)}"}
- def get_table_cell_text(table_index=0, row=0, col=0):
- """
- 获取表格单元格的文本内容
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- row: 行索引
- col: 列索引
-
- 返回:
- 单元格的文本内容
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- if row < 0 or row >= len(table.rows) or col < 0 or col >= len(table.columns):
- return {"error": f"单元格索引 ({row}, {col}) 超出范围"}
-
- cell_text = table.cell(row, col).text
-
- return {
- "text": cell_text
- }
- except Exception as e:
- return {"error": f"获取单元格文本时出错: {str(e)}"}
- def get_table_row(table_index=0, row=0):
- """
- 获取表格中一行的所有单元格文本
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- row: 行索引
-
- 返回:
- 行中所有单元格的文本内容列表
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- if row < 0 or row >= len(table.rows):
- return {"error": f"行索引 {row} 超出范围"}
-
- row_cells = []
- for cell in table.rows[row].cells:
- row_cells.append(cell.text)
-
- return {
- "cells": row_cells
- }
- except Exception as e:
- return {"error": f"获取表格行时出错: {str(e)}"}
- def get_table_column(table_index=0, col=0):
- """
- 获取表格中一列的所有单元格文本
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- col: 列索引
-
- 返回:
- 列中所有单元格的文本内容列表
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- if col < 0 or col >= len(table.columns):
- return {"error": f"列索引 {col} 超出范围"}
-
- column_cells = []
- for row in table.rows:
- column_cells.append(row.cells[col].text)
-
- return {
- "cells": column_cells
- }
- except Exception as e:
- return {"error": f"获取表格列时出错: {str(e)}"}
- def get_table_range(table_index=0, start_row=0, start_col=0, end_row=None, end_col=None):
- """
- 获取表格中指定范围的单元格文本
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- start_row: 起始行索引
- start_col: 起始列索引
- end_row: 结束行索引,如果为None则取最后一行
- end_col: 结束列索引,如果为None则取最后一列
-
- 返回:
- 指定范围内所有单元格的文本内容二维数组
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- # 设置默认结束位置
- if end_row is None:
- end_row = len(table.rows) - 1
- if end_col is None:
- end_col = len(table.columns) - 1
-
- # 检查索引范围
- if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
- return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
- if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
- return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
-
- # 获取范围内的单元格文本
- range_data = []
- for row in range(start_row, end_row + 1):
- row_data = []
- for col in range(start_col, end_col + 1):
- row_data.append(table.cell(row, col).text)
- range_data.append(row_data)
-
- return {
- "data": range_data
- }
- except Exception as e:
- return {"error": f"获取表格范围时出错: {str(e)}"}
- def get_all_tables_info():
- """
- 获取文档中所有表格的基本信息
-
- 返回:
- 所有表格的行数和列数信息
- """
- try:
- doc = get_document()
- tables_info = []
-
- for i, table in enumerate(doc.tables):
- tables_info.append({
- "table_index": i,
- "rows": len(table.rows),
- "columns": len(table.columns)
- })
-
- return {
- "tables_count": len(doc.tables),
- "tables": tables_info
- }
- except Exception as e:
- return {"error": f"获取表格信息时出错: {str(e)}"}
- def set_table_data(table_index=0, data=None, start_row=0, start_col=0, clear_existing=False):
- """
- 批量设置表格数据
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- data: 二维数组数据
- start_row: 起始行索引
- start_col: 起始列索引
- clear_existing: 是否清除现有内容
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- if not data or not isinstance(data, list):
- return {"error": "数据必须是非空的二维数组"}
-
- table = doc.tables[table_index]
- rows = len(table.rows)
- cols = len(table.columns)
-
- # 检查数据是否超出表格范围
- data_rows = len(data)
- if data_rows == 0:
- return {"error": "数据不能为空"}
-
- data_cols = max(len(row) for row in data)
- if start_row < 0 or start_row + data_rows > rows:
- return {"error": f"数据行超出表格范围,表格有 {rows} 行,数据需要 {start_row + data_rows} 行"}
-
- if start_col < 0 or start_col + data_cols > cols:
- return {"error": f"数据列超出表格范围,表格有 {cols} 列,数据需要 {start_col + data_cols} 列"}
-
- # 填充数据
- for i, row_data in enumerate(data):
- row_idx = start_row + i
- for j, cell_value in enumerate(row_data):
- col_idx = start_col + j
- cell = table.cell(row_idx, col_idx)
-
- # 如果需要清除现有内容
- if clear_existing:
- cell.text = ""
-
- # 设置单元格文本
- if cell_value is not None:
- if cell.text and not clear_existing:
- cell.text += "\n" + str(cell_value)
- else:
- cell.text = str(cell_value)
-
- return {
- "message": f"已设置表格 {table_index} 的数据,从 ({start_row}, {start_col}) 开始,共 {data_rows} 行 {data_cols} 列"
- }
- except Exception as e:
- return {"error": f"设置表格数据时出错: {str(e)}"}
- def set_table_row_data(table_index=0, row=0, data=None, start_col=0, clear_existing=False):
- """
- 设置表格一行的数据
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- row: 行索引
- data: 一维数组数据
- start_col: 起始列索引
- clear_existing: 是否清除现有内容
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- if not data or not isinstance(data, list):
- return {"error": "数据必须是非空的一维数组"}
-
- table = doc.tables[table_index]
-
- if row < 0 or row >= len(table.rows):
- return {"error": f"行索引 {row} 超出范围"}
-
- cols = len(table.columns)
- data_cols = len(data)
-
- if start_col < 0 or start_col + data_cols > cols:
- return {"error": f"数据列超出表格范围,表格有 {cols} 列,数据需要 {start_col + data_cols} 列"}
-
- # 填充数据
- for j, cell_value in enumerate(data):
- col_idx = start_col + j
- cell = table.cell(row, col_idx)
-
- # 如果需要清除现有内容
- if clear_existing:
- cell.text = ""
-
- # 设置单元格文本
- if cell_value is not None:
- if cell.text and not clear_existing:
- cell.text += "\n" + str(cell_value)
- else:
- cell.text = str(cell_value)
-
- return {
- "message": f"已设置表格 {table_index} 的第 {row} 行数据,从列 {start_col} 开始,共 {data_cols} 列"
- }
- except Exception as e:
- return {"error": f"设置表格行数据时出错: {str(e)}"}
- def set_table_column_data(table_index=0, col=0, data=None, start_row=0, clear_existing=False):
- """
- 设置表格一列的数据
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- col: 列索引
- data: 一维数组数据
- start_row: 起始行索引
- clear_existing: 是否清除现有内容
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- if not data or not isinstance(data, list):
- return {"error": "数据必须是非空的一维数组"}
-
- table = doc.tables[table_index]
-
- if col < 0 or col >= len(table.columns):
- return {"error": f"列索引 {col} 超出范围"}
-
- rows = len(table.rows)
- data_rows = len(data)
-
- if start_row < 0 or start_row + data_rows > rows:
- return {"error": f"数据行超出表格范围,表格有 {rows} 行,数据需要 {start_row + data_rows} 行"}
-
- # 填充数据
- for i, cell_value in enumerate(data):
- row_idx = start_row + i
- cell = table.cell(row_idx, col)
-
- # 如果需要清除现有内容
- if clear_existing:
- cell.text = ""
-
- # 设置单元格文本
- if cell_value is not None:
- if cell.text and not clear_existing:
- cell.text += "\n" + str(cell_value)
- else:
- cell.text = str(cell_value)
-
- return {
- "message": f"已设置表格 {table_index} 的第 {col} 列数据,从行 {start_row} 开始,共 {data_rows} 行"
- }
- except Exception as e:
- return {"error": f"设置表格列数据时出错: {str(e)}"}
- def clear_table_range(table_index=0, start_row=0, start_col=0, end_row=None, end_col=None):
- """
- 清除表格中指定范围的内容
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- start_row: 起始行索引
- start_col: 起始列索引
- end_row: 结束行索引,如果为None则取最后一行
- end_col: 结束列索引,如果为None则取最后一列
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- # 设置默认结束位置
- if end_row is None:
- end_row = len(table.rows) - 1
- if end_col is None:
- end_col = len(table.columns) - 1
-
- # 检查索引范围
- if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
- return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
- if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
- return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
-
- # 清除范围内的单元格文本
- for row in range(start_row, end_row + 1):
- for col in range(start_col, end_col + 1):
- table.cell(row, col).text = ""
-
- return {
- "message": f"已清除表格 {table_index} 的区域 ({start_row}, {start_col}) 到 ({end_row}, {end_col})"
- }
- except Exception as e:
- return {"error": f"清除表格区域时出错: {str(e)}"}
- def get_table_detail_by_id(table_index=0):
- """
- 获取表格的详细信息,包括所有单元格的内容
-
- 参数:
- table_index: 表格索引,默认为第一个表格
-
- 返回:
- 表格的基本信息和单元格内容的多维数组
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
- rows = len(table.rows)
- cols = len(table.columns)
-
- # 获取所有单元格内容
- cells_content = []
- for i in range(rows):
- row_content = []
- for j in range(cols):
- cell = table.cell(i, j)
- row_content.append(cell.text)
- cells_content.append(row_content)
-
- # 构建表格详细信息
- table_detail = {
- "table_index": table_index,
- "rows": rows,
- "columns": cols,
- "content": cells_content
- }
-
- return table_detail
- except Exception as e:
- return {"error": f"获取表格详细信息时出错: {str(e)}"}
- def set_table_font(table_index=0, font_name=None, font_size=None, bold=None, italic=None,
- color=None, start_row=0, end_row=None, start_col=0, end_col=None):
- """
- 设置表格中指定范围单元格的字体属性
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- font_name: 字体名称
- font_size: 字体大小(磅)
- bold: 是否加粗
- italic: 是否斜体
- color: 字体颜色(十六进制格式,如"FF0000"表示红色)
- start_row: 起始行索引
- end_row: 结束行索引,如果为None则取最后一行
- start_col: 起始列索引
- end_col: 结束列索引,如果为None则取最后一列
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- # 设置默认结束位置
- if end_row is None:
- end_row = len(table.rows) - 1
- if end_col is None:
- end_col = len(table.columns) - 1
-
- # 检查索引范围
- if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
- return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
- if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
- return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
-
- # 遍历指定范围的单元格
- for row in range(start_row, end_row + 1):
- for col in range(start_col, end_col + 1):
- cell = table.cell(row, col)
-
- # 遍历单元格中的所有段落
- for paragraph in cell.paragraphs:
- # 如果段落没有文本运行,添加一个空的运行
- if not paragraph.runs:
- paragraph.add_run()
-
- # 设置每个文本运行的字体属性
- for run in paragraph.runs:
- if font_name:
- run.font.name = font_name
- # 设置中文字体
- run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
-
- if font_size is not None:
- run.font.size = Pt(font_size)
-
- if bold is not None:
- run.font.bold = bold
-
- if italic is not None:
- run.font.italic = italic
-
- if color:
- # 将十六进制颜色转换为RGB
- if color.startswith('#'):
- color = color[1:]
- r = int(color[0:2], 16)
- g = int(color[2:4], 16)
- b = int(color[4:6], 16)
- run.font.color.rgb = RGBColor(r, g, b)
-
- return {
- "message": f"已设置表格 {table_index} 的字体属性,范围: ({start_row},{start_col}) 到 ({end_row},{end_col})"
- }
- except Exception as e:
- return {"error": f"设置表格字体时出错: {str(e)}"}
- def set_table_cell_alignment(table_index=0, start_row=0, end_row=None, start_col=0, end_col=None,
- horizontal_alignment="CENTER", vertical_alignment="CENTER"):
- """
- 设置表格单元格的水平和垂直对齐方式
-
- 参数:
- table_index: 表格索引,默认为第一个表格
- start_row: 起始行索引
- end_row: 结束行索引,如果为None则取最后一行
- start_col: 起始列索引
- end_col: 结束列索引,如果为None则取最后一列
- horizontal_alignment: 水平对齐方式,可选值:"LEFT", "CENTER", "RIGHT", "JUSTIFY"
- vertical_alignment: 垂直对齐方式,可选值:"TOP", "CENTER", "BOTTOM"
-
- 返回:
- 成功或错误信息
- """
- try:
- doc = get_document()
- if not doc.tables or table_index >= len(doc.tables):
- return {"error": f"文档中没有索引为 {table_index} 的表格"}
-
- table = doc.tables[table_index]
-
- # 设置默认结束位置
- if end_row is None:
- end_row = len(table.rows) - 1
- if end_col is None:
- end_col = len(table.columns) - 1
-
- # 检查索引范围
- if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
- return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
- if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
- return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
-
- # 水平对齐方式映射
- h_alignment_map = {
- "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
- "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
- "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT,
- "JUSTIFY": WD_ALIGN_PARAGRAPH.JUSTIFY
- }
-
- # 垂直对齐方式映射
- v_alignment_map = {
- "TOP": WD_ALIGN_VERTICAL.TOP,
- "CENTER": WD_ALIGN_VERTICAL.CENTER,
- "BOTTOM": WD_ALIGN_VERTICAL.BOTTOM
- }
-
- # 检查对齐方式是否有效
- if horizontal_alignment not in h_alignment_map:
- return {"error": f"不支持的水平对齐方式: {horizontal_alignment}"}
- if vertical_alignment not in v_alignment_map:
- return {"error": f"不支持的垂直对齐方式: {vertical_alignment}"}
-
- # 设置指定范围内单元格的对齐方式
- for row in range(start_row, end_row + 1):
- for col in range(start_col, end_col + 1):
- cell = table.cell(row, col)
-
- # 设置垂直对齐方式
- cell.vertical_alignment = v_alignment_map[vertical_alignment]
-
- # 设置水平对齐方式(应用于单元格中的所有段落)
- for paragraph in cell.paragraphs:
- paragraph.alignment = h_alignment_map[horizontal_alignment]
-
- return {
- "message": f"已设置表格 {table_index} 单元格的对齐方式,范围: ({start_row},{start_col}) 到 ({end_row},{end_col})"
- }
- except Exception as e:
- return {"error": f"设置表格单元格对齐方式时出错: {str(e)}"}
- # 函数映射表,用于根据函数名调用相应的函数
- function_map = {
- "create_new_document": create_new_document,
- "set_global_font": set_global_font,
- "save_document": save_document,
- "open_document": open_document,
- "add_paragraph_to_docx": add_paragraph_to_docx,
- "add_heading": add_heading,
- "add_table": add_table,
- "add_picture": add_picture,
- "add_page_break": add_page_break,
- "set_paragraph_style": set_paragraph_style,
- "set_font": set_font,
- "set_paragraph_alignment": set_paragraph_alignment,
- "set_paragraph_spacing": set_paragraph_spacing,
- "add_section": add_section,
- "set_section_orientation": set_section_orientation,
- "set_section_page_size": set_section_page_size,
- "set_section_margins": set_section_margins,
- "add_header": add_header,
- "add_footer": add_footer,
- "add_page_number": add_page_number,
- "merge_table_cells": merge_table_cells,
- "set_table_cell_text": set_table_cell_text,
- "set_table_style": set_table_style,
- "set_table_cell_background": set_table_cell_background,
- "set_table_cell_vertical_alignment": set_table_cell_vertical_alignment,
- "set_table_width": set_table_width,
- "set_table_column_width": set_table_column_width,
- "add_hyperlink": add_hyperlink,
- "add_bookmark": add_bookmark,
- "add_table_of_contents": add_table_of_contents,
- "set_table_borders": set_table_borders,
- "set_cell_borders": set_cell_borders,
- "add_table_standard_borders": add_table_standard_borders,
- "copy_excel_to_word": copy_excel_to_word,
- "copy_excel_range_to_word": copy_excel_range_to_word,
- "add_table_row": add_table_row,
- "add_table_column": add_table_column,
- "delete_table_row": delete_table_row,
- "delete_table_column": delete_table_column,
- "get_table_dimensions": get_table_dimensions,
- "get_table_cell_text": get_table_cell_text,
- "get_table_row": get_table_row,
- "get_table_column": get_table_column,
- "get_table_range": get_table_range,
- "get_all_tables_info": get_all_tables_info,
- "set_table_data": set_table_data,
- "set_table_row_data": set_table_row_data,
- "set_table_column_data": set_table_column_data,
- "clear_table_range": clear_table_range,
- "get_table_detail_by_id": get_table_detail_by_id,
- "set_table_font": set_table_font,
- "set_table_cell_alignment": set_table_cell_alignment
- }
- def execute_docx_function(function_name, **kwargs):
- """执行指定的函数"""
- if function_name not in function_map:
- return f"错误:未知的函数 {function_name}"
-
- try:
- return function_map[function_name](**kwargs)
- except Exception as e:
- return f"执行函数 {function_name} 时出错: {str(e)}"
|