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)}"