docx_function_impl.py 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849
  1. from docx import Document
  2. from docx.shared import Inches, Pt, RGBColor, Cm
  3. from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
  4. from docx.enum.section import WD_SECTION_START, WD_ORIENTATION
  5. from docx.enum.table import WD_ALIGN_VERTICAL
  6. from docx.oxml.ns import qn
  7. from docx.table import _Cell
  8. from docx.oxml import OxmlElement
  9. from docx.oxml.shared import qn
  10. import os
  11. import openpyxl
  12. # 全局文档对象
  13. _document = None
  14. def get_document():
  15. """获取当前文档对象,如果不存在则创建新文档"""
  16. global _document
  17. if _document is None:
  18. _document = Document()
  19. return _document
  20. # 基本文档操作
  21. def create_new_document():
  22. """创建一个新的Word文档"""
  23. global _document
  24. _document = Document()
  25. return "已创建新文档"
  26. def save_document(file_path):
  27. """保存Word文档"""
  28. doc = get_document()
  29. doc.save(file_path)
  30. return f"文档已保存为 {file_path}"
  31. def open_document(file_path):
  32. """打开现有的Word文档"""
  33. global _document
  34. if not os.path.exists(file_path):
  35. return f"错误:文件 {file_path} 不存在"
  36. _document = Document(file_path)
  37. return f"已打开文档 {file_path}"
  38. # 内容添加函数
  39. def add_paragraph_to_docx(text):
  40. """向Word文档添加段落"""
  41. doc = get_document()
  42. doc.add_paragraph(text)
  43. return "段落已添加"
  44. # 设置全局字体
  45. def set_global_font(font_name=None, font_size=None, font_color=None):
  46. """
  47. 设置文档的全局字体
  48. 参数:
  49. font_name: 字体名称
  50. font_size: 字体大小(磅)
  51. font_color: 字体颜色(RGB格式,如"FF0000"表示红色)
  52. 返回:
  53. 成功或错误信息
  54. """
  55. try:
  56. doc = get_document()
  57. # 遍历文档中的所有段落
  58. for paragraph in doc.paragraphs:
  59. for run in paragraph.runs:
  60. if font_name:
  61. run.font.name = font_name
  62. if font_size is not None:
  63. run.font.size = Pt(font_size)
  64. if font_color:
  65. run.font.color.rgb = RGBColor.from_string(font_color)
  66. # 遍历文档中的所有表格
  67. for table in doc.tables:
  68. for row in table.rows:
  69. for cell in row.cells:
  70. for paragraph in cell.paragraphs:
  71. for run in paragraph.runs:
  72. if font_name:
  73. run.font.name = font_name
  74. if font_size is not None:
  75. run.font.size = Pt(font_size)
  76. if font_color:
  77. run.font.color.rgb = RGBColor.from_string(font_color)
  78. return "已设置全局字体"
  79. except Exception as e:
  80. return f"设置全局字体时出错: {str(e)}"
  81. def add_heading(text, level=1):
  82. """添加标题"""
  83. doc = get_document()
  84. doc.add_heading(text, level=level)
  85. return f"已添加{level}级标题: {text}"
  86. def add_table(rows, cols, data=None):
  87. """添加表格"""
  88. doc = get_document()
  89. table = doc.add_table(rows=rows, cols=cols)
  90. # 如果提供了数据,填充表格
  91. if data:
  92. for i in range(min(len(data), rows)):
  93. row_data = data[i]
  94. for j in range(min(len(row_data), cols)):
  95. table.cell(i, j).text = str(row_data[j])
  96. return f"已添加{rows}行{cols}列的表格"
  97. def add_picture(image_path, width=None, height=None):
  98. """添加图片"""
  99. doc = get_document()
  100. if not os.path.exists(image_path):
  101. return f"错误:图片文件 {image_path} 不存在"
  102. if width and height:
  103. doc.add_picture(image_path, width=Cm(width), height=Cm(height))
  104. elif width:
  105. doc.add_picture(image_path, width=Cm(width))
  106. elif height:
  107. doc.add_picture(image_path, height=Cm(height))
  108. else:
  109. doc.add_picture(image_path)
  110. return f"已添加图片: {image_path}"
  111. def add_page_break():
  112. """添加分页符"""
  113. doc = get_document()
  114. doc.add_page_break()
  115. return "已添加分页符"
  116. # 样式和格式设置
  117. def set_paragraph_style(paragraph_index, style_name):
  118. """设置段落样式"""
  119. doc = get_document()
  120. if paragraph_index >= len(doc.paragraphs):
  121. return f"错误:段落索引 {paragraph_index} 超出范围"
  122. try:
  123. doc.paragraphs[paragraph_index].style = style_name
  124. return f"已将段落 {paragraph_index} 的样式设置为 {style_name}"
  125. except Exception as e:
  126. return f"设置样式失败: {str(e)}"
  127. def set_font(paragraph_index, run_index, font_name=None, font_size=None,
  128. bold=None, italic=None, underline=None, color=None):
  129. """设置文本字体"""
  130. doc = get_document()
  131. if paragraph_index >= len(doc.paragraphs):
  132. return f"错误:段落索引 {paragraph_index} 超出范围"
  133. paragraph = doc.paragraphs[paragraph_index]
  134. if run_index >= len(paragraph.runs):
  135. return f"错误:文本运行索引 {run_index} 超出范围"
  136. run = paragraph.runs[run_index]
  137. if font_name:
  138. run.font.name = font_name
  139. # 设置中文字体
  140. run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
  141. if font_size is not None:
  142. run.font.size = Pt(font_size)
  143. if bold is not None:
  144. run.font.bold = bold
  145. if italic is not None:
  146. run.font.italic = italic
  147. if underline is not None:
  148. run.font.underline = underline
  149. if color:
  150. # 将十六进制颜色转换为RGB
  151. if color.startswith('#'):
  152. color = color[1:]
  153. r = int(color[0:2], 16)
  154. g = int(color[2:4], 16)
  155. b = int(color[4:6], 16)
  156. run.font.color.rgb = RGBColor(r, g, b)
  157. return "已设置字体属性"
  158. def set_paragraph_alignment(paragraph_index, alignment):
  159. """设置段落对齐方式"""
  160. doc = get_document()
  161. if paragraph_index >= len(doc.paragraphs):
  162. return f"错误:段落索引 {paragraph_index} 超出范围"
  163. paragraph = doc.paragraphs[paragraph_index]
  164. alignment_map = {
  165. "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
  166. "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
  167. "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT,
  168. "JUSTIFY": WD_ALIGN_PARAGRAPH.JUSTIFY
  169. }
  170. if alignment not in alignment_map:
  171. return f"错误:不支持的对齐方式 {alignment}"
  172. paragraph.alignment = alignment_map[alignment]
  173. return f"已将段落 {paragraph_index} 的对齐方式设置为 {alignment}"
  174. def set_paragraph_spacing(paragraph_index, before=None, after=None, line_spacing=None):
  175. """设置段落间距"""
  176. doc = get_document()
  177. if paragraph_index >= len(doc.paragraphs):
  178. return f"错误:段落索引 {paragraph_index} 超出范围"
  179. paragraph = doc.paragraphs[paragraph_index]
  180. if before is not None:
  181. paragraph.paragraph_format.space_before = Pt(before)
  182. if after is not None:
  183. paragraph.paragraph_format.space_after = Pt(after)
  184. if line_spacing is not None:
  185. paragraph.paragraph_format.line_spacing = line_spacing
  186. paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
  187. return f"已设置段落 {paragraph_index} 的间距"
  188. # 节和页面设置
  189. def add_section(start_type="NEW_PAGE"):
  190. """添加新的节"""
  191. doc = get_document()
  192. start_type_map = {
  193. "NEW_PAGE": WD_SECTION_START.NEW_PAGE,
  194. "EVEN_PAGE": WD_SECTION_START.EVEN_PAGE,
  195. "ODD_PAGE": WD_SECTION_START.ODD_PAGE,
  196. "CONTINUOUS": WD_SECTION_START.CONTINUOUS
  197. }
  198. if start_type not in start_type_map:
  199. return f"错误:不支持的节开始类型 {start_type}"
  200. doc.add_section(start_type_map[start_type])
  201. return f"已添加新节,开始类型为 {start_type}"
  202. def set_section_orientation(section_index, orientation):
  203. """设置节的页面方向"""
  204. doc = get_document()
  205. if section_index >= len(doc.sections):
  206. return f"错误:节索引 {section_index} 超出范围"
  207. section = doc.sections[section_index]
  208. orientation_map = {
  209. "PORTRAIT": WD_ORIENTATION.PORTRAIT,
  210. "LANDSCAPE": WD_ORIENTATION.LANDSCAPE
  211. }
  212. if orientation not in orientation_map:
  213. return f"错误:不支持的页面方向 {orientation}"
  214. section.orientation = orientation_map[orientation]
  215. return f"已将节 {section_index} 的页面方向设置为 {orientation}"
  216. def set_section_page_size(section_index, width, height):
  217. """设置节的页面大小"""
  218. doc = get_document()
  219. if section_index >= len(doc.sections):
  220. return f"错误:节索引 {section_index} 超出范围"
  221. section = doc.sections[section_index]
  222. section.page_width = Cm(width)
  223. section.page_height = Cm(height)
  224. return f"已将节 {section_index} 的页面大小设置为 {width}cm x {height}cm"
  225. def set_section_margins(section_index, top=None, right=None, bottom=None, left=None):
  226. """设置节的页边距"""
  227. doc = get_document()
  228. if section_index >= len(doc.sections):
  229. return f"错误:节索引 {section_index} 超出范围"
  230. section = doc.sections[section_index]
  231. if top is not None:
  232. section.top_margin = Cm(top)
  233. if right is not None:
  234. section.right_margin = Cm(right)
  235. if bottom is not None:
  236. section.bottom_margin = Cm(bottom)
  237. if left is not None:
  238. section.left_margin = Cm(left)
  239. return f"已设置节 {section_index} 的页边距"
  240. # 页眉页脚
  241. def add_header(section_index, text):
  242. """添加页眉"""
  243. doc = get_document()
  244. if section_index >= len(doc.sections):
  245. return f"错误:节索引 {section_index} 超出范围"
  246. section = doc.sections[section_index]
  247. header = section.header
  248. header.paragraphs[0].text = text
  249. return f"已为节 {section_index} 添加页眉: {text}"
  250. def add_footer(section_index, text):
  251. """添加页脚"""
  252. doc = get_document()
  253. if section_index >= len(doc.sections):
  254. return f"错误:节索引 {section_index} 超出范围"
  255. section = doc.sections[section_index]
  256. footer = section.footer
  257. footer.paragraphs[0].text = text
  258. return f"已为节 {section_index} 添加页脚: {text}"
  259. def add_page_number(section_index, position="FOOTER", alignment="CENTER", format=None):
  260. """添加页码"""
  261. doc = get_document()
  262. if section_index >= len(doc.sections):
  263. return f"错误:节索引 {section_index} 超出范围"
  264. section = doc.sections[section_index]
  265. # 获取页眉或页脚
  266. if position == "HEADER":
  267. container = section.header
  268. else: # FOOTER
  269. container = section.footer
  270. # 清除现有内容
  271. for paragraph in container.paragraphs:
  272. paragraph.clear()
  273. # 添加新段落
  274. paragraph = container.paragraphs[0]
  275. # 设置对齐方式
  276. alignment_map = {
  277. "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
  278. "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
  279. "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT
  280. }
  281. if alignment in alignment_map:
  282. paragraph.alignment = alignment_map[alignment]
  283. # 添加页码字段
  284. run = paragraph.add_run()
  285. # 这里使用一个简单的方法来模拟页码
  286. # 实际上,python-docx对页码字段的支持有限
  287. # 这里只是添加一个占位符文本
  288. if format:
  289. run.text = format.format("X") # 使用X作为页码占位符
  290. else:
  291. run.text = "Page X"
  292. return f"已为节 {section_index} 添加页码"
  293. # 表格操作
  294. def merge_table_cells(table_index, start_row, start_col, end_row, end_col):
  295. """合并表格单元格"""
  296. doc = get_document()
  297. if table_index >= len(doc.tables):
  298. return f"错误:表格索引 {table_index} 超出范围"
  299. table = doc.tables[table_index]
  300. # 检查行列索引是否有效
  301. if start_row < 0 or start_col < 0 or end_row >= len(table.rows) or end_col >= len(table.columns):
  302. return "错误:行列索引超出范围"
  303. # 获取要合并的单元格
  304. start_cell = table.cell(start_row, start_col)
  305. end_cell = table.cell(end_row, end_col)
  306. # 合并单元格
  307. start_cell.merge(end_cell)
  308. return f"已合并表格 {table_index} 的单元格 ({start_row},{start_col}) 到 ({end_row},{end_col})"
  309. def set_table_cell_text(table_index, row, col, text):
  310. """设置表格单元格文本"""
  311. doc = get_document()
  312. if table_index >= len(doc.tables):
  313. return f"错误:表格索引 {table_index} 超出范围"
  314. table = doc.tables[table_index]
  315. # 检查行列索引是否有效
  316. if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
  317. return "错误:行列索引超出范围"
  318. # 设置单元格文本
  319. table.cell(row, col).text = text
  320. return f"已设置表格 {table_index} 单元格 ({row},{col}) 的文本"
  321. def set_table_style(table_index, style_name):
  322. """设置表格样式"""
  323. doc = get_document()
  324. if table_index >= len(doc.tables):
  325. return f"错误:表格索引 {table_index} 超出范围"
  326. table = doc.tables[table_index]
  327. try:
  328. table.style = style_name
  329. return f"已将表格 {table_index} 的样式设置为 {style_name}"
  330. except Exception as e:
  331. return f"设置表格样式失败: {str(e)}"
  332. def set_table_cell_background(table_index, row, col, color):
  333. """设置表格单元格背景色"""
  334. doc = get_document()
  335. if table_index >= len(doc.tables):
  336. return f"错误:表格索引 {table_index} 超出范围"
  337. table = doc.tables[table_index]
  338. # 检查行列索引是否有效
  339. if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
  340. return "错误:行列索引超出范围"
  341. # 获取单元格
  342. cell = table.cell(row, col)
  343. # 设置背景色
  344. # 注意:这需要使用低级API
  345. try:
  346. shading_elm = cell._element.get_or_add_tcPr().get_or_add_shd()
  347. shading_elm.set(qn('w:fill'), color)
  348. return f"已设置表格 {table_index} 单元格 ({row},{col}) 的背景色为 {color}"
  349. except Exception as e:
  350. return f"设置单元格背景色失败: {str(e)}"
  351. def set_table_cell_vertical_alignment(table_index, row, col, alignment):
  352. """设置表格单元格垂直对齐方式"""
  353. doc = get_document()
  354. if table_index >= len(doc.tables):
  355. return f"错误:表格索引 {table_index} 超出范围"
  356. table = doc.tables[table_index]
  357. # 检查行列索引是否有效
  358. if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
  359. return "错误:行列索引超出范围"
  360. # 获取单元格
  361. cell = table.cell(row, col)
  362. # 设置垂直对齐方式
  363. alignment_map = {
  364. "TOP": WD_ALIGN_VERTICAL.TOP,
  365. "CENTER": WD_ALIGN_VERTICAL.CENTER,
  366. "BOTTOM": WD_ALIGN_VERTICAL.BOTTOM
  367. }
  368. if alignment not in alignment_map:
  369. return f"错误:不支持的垂直对齐方式 {alignment}"
  370. cell.vertical_alignment = alignment_map[alignment]
  371. return f"已设置表格 {table_index} 单元格 ({row},{col}) 的垂直对齐方式为 {alignment}"
  372. def set_table_width(table_index, width):
  373. """设置表格宽度"""
  374. doc = get_document()
  375. if table_index >= len(doc.tables):
  376. return f"错误:表格索引 {table_index} 超出范围"
  377. table = doc.tables[table_index]
  378. # 设置表格宽度
  379. # 注意:python-docx对表格宽度的支持有限
  380. # 这里使用一个近似的方法
  381. table.autofit = False
  382. table.width = Cm(width)
  383. return f"已将表格 {table_index} 的宽度设置为 {width}cm"
  384. def set_table_column_width(table_index, col, width):
  385. """设置表格列宽"""
  386. doc = get_document()
  387. if table_index >= len(doc.tables):
  388. return f"错误:表格索引 {table_index} 超出范围"
  389. table = doc.tables[table_index]
  390. # 检查列索引是否有效
  391. if col < 0 or col >= len(table.columns):
  392. return "错误:列索引超出范围"
  393. # 设置列宽
  394. for cell in table.columns[col].cells:
  395. cell.width = Cm(width)
  396. return f"已将表格 {table_index} 列 {col} 的宽度设置为 {width}cm"
  397. # 高级功能
  398. def add_hyperlink(paragraph_index, text, url):
  399. """添加超链接"""
  400. doc = get_document()
  401. if paragraph_index >= len(doc.paragraphs):
  402. return f"错误:段落索引 {paragraph_index} 超出范围"
  403. paragraph = doc.paragraphs[paragraph_index]
  404. # 添加超链接
  405. # 注意:python-docx对超链接的支持有限
  406. # 这里使用一个简单的方法
  407. run = paragraph.add_run(text)
  408. run.font.underline = True
  409. run.font.color.rgb = RGBColor(0, 0, 255) # 蓝色
  410. # 实际上,这并不是真正的超链接,只是模拟了超链接的外观
  411. # 要添加真正的超链接,需要使用更低级的API
  412. return f"已为段落 {paragraph_index} 添加超链接: {text} -> {url}"
  413. def add_bookmark(paragraph_index, bookmark_name, text):
  414. """添加书签"""
  415. doc = get_document()
  416. if paragraph_index >= len(doc.paragraphs):
  417. return f"错误:段落索引 {paragraph_index} 超出范围"
  418. paragraph = doc.paragraphs[paragraph_index]
  419. # 添加书签
  420. # 注意:python-docx对书签的支持有限
  421. # 这里只是添加文本,而不是真正的书签
  422. paragraph.add_run(text)
  423. return f"已为段落 {paragraph_index} 添加书签: {bookmark_name} -> {text}"
  424. def add_table_of_contents(title, levels=3):
  425. """添加目录"""
  426. doc = get_document()
  427. # 添加目录标题
  428. doc.add_heading(title, level=1)
  429. # 添加目录占位符段落
  430. paragraph = doc.add_paragraph()
  431. run = paragraph.add_run("目录将在Word中自动生成")
  432. return f"已添加目录占位符,标题为 {title},包含 {levels} 级标题"
  433. # 添加设置表格边框的函数
  434. def set_table_borders(table_index, border_style="single", border_width=1, border_color="000000",
  435. apply_to="all", first_row=False, first_column=False, last_row=False, last_column=False):
  436. """设置表格边框样式"""
  437. doc = get_document()
  438. if table_index >= len(doc.tables):
  439. return f"错误:表格索引 {table_index} 超出范围"
  440. table = doc.tables[table_index]
  441. # 边框样式映射
  442. style_map = {
  443. "single": "single",
  444. "thick": "thick",
  445. "double": "double",
  446. "dotted": "dotted",
  447. "dashed": "dashed",
  448. "none": "nil"
  449. }
  450. if border_style not in style_map:
  451. return f"错误:不支持的边框样式 {border_style}"
  452. border_style = style_map[border_style]
  453. # 应用边框的位置映射
  454. positions = []
  455. if apply_to == "all":
  456. positions = ["top", "bottom", "left", "right", "insideH", "insideV"]
  457. elif apply_to == "outside":
  458. positions = ["top", "bottom", "left", "right"]
  459. elif apply_to == "inside":
  460. positions = ["insideH", "insideV"]
  461. elif apply_to in ["top", "bottom", "left", "right"]:
  462. positions = [apply_to]
  463. else:
  464. return f"错误:不支持的边框应用位置 {apply_to}"
  465. # 为表格设置边框
  466. tbl = table._tbl
  467. # 获取表格属性
  468. tblPr = tbl.xpath('./w:tblPr')
  469. if not tblPr:
  470. tblPr = OxmlElement('w:tblPr')
  471. tbl.insert(0, tblPr)
  472. else:
  473. tblPr = tblPr[0]
  474. # 创建边框元素
  475. tblBorders = OxmlElement('w:tblBorders')
  476. # 添加各个位置的边框
  477. for position in positions:
  478. border = OxmlElement(f'w:{position}')
  479. border.set(qn('w:val'), border_style)
  480. border.set(qn('w:sz'), str(border_width * 8)) # 8 = 1pt
  481. border.set(qn('w:space'), '0')
  482. border.set(qn('w:color'), border_color)
  483. tblBorders.append(border)
  484. # 移除现有边框并添加新边框
  485. existing_borders = tblPr.xpath('./w:tblBorders')
  486. if existing_borders:
  487. tblPr.remove(existing_borders[0])
  488. tblPr.append(tblBorders)
  489. # 处理特殊行列边框
  490. if first_row or first_column or last_row or last_column:
  491. # 创建表格样式属性
  492. tblLook = OxmlElement('w:tblLook')
  493. tblLook.set(qn('w:val'), '0000')
  494. tblLook.set(qn('w:firstRow'), '1' if first_row else '0')
  495. tblLook.set(qn('w:lastRow'), '1' if last_row else '0')
  496. tblLook.set(qn('w:firstColumn'), '1' if first_column else '0')
  497. tblLook.set(qn('w:lastColumn'), '1' if last_column else '0')
  498. tblLook.set(qn('w:noHBand'), '0')
  499. tblLook.set(qn('w:noVBand'), '0')
  500. # 移除现有样式并添加新样式
  501. existing_tblLook = tblPr.xpath('./w:tblLook')
  502. if existing_tblLook:
  503. tblPr.remove(existing_tblLook[0])
  504. tblPr.append(tblLook)
  505. return f"已设置表格 {table_index} 的边框样式"
  506. # 修改 set_cell_borders 函数
  507. def set_cell_borders(table_index, row, col, border_style="single", border_width=1, border_color="000000",
  508. apply_to="all"):
  509. """设置单元格边框样式"""
  510. doc = get_document()
  511. if table_index >= len(doc.tables):
  512. return f"错误:表格索引 {table_index} 超出范围"
  513. table = doc.tables[table_index]
  514. # 检查行列索引是否有效
  515. if row < 0 or col < 0 or row >= len(table.rows) or col >= len(table.columns):
  516. return "错误:行列索引超出范围"
  517. # 获取单元格
  518. cell = table.cell(row, col)
  519. # 边框样式映射
  520. style_map = {
  521. "single": "single",
  522. "thick": "thick",
  523. "double": "double",
  524. "dotted": "dotted",
  525. "dashed": "dashed",
  526. "none": "nil"
  527. }
  528. if border_style not in style_map:
  529. return f"错误:不支持的边框样式 {border_style}"
  530. border_style = style_map[border_style]
  531. # 应用边框的位置
  532. positions = []
  533. if apply_to == "all":
  534. positions = ["top", "bottom", "left", "right"]
  535. elif apply_to in ["top", "bottom", "left", "right"]:
  536. positions = [apply_to]
  537. else:
  538. return f"错误:不支持的边框应用位置 {apply_to}"
  539. # 为单元格设置边框
  540. tc = cell._tc
  541. # 获取单元格属性
  542. tcPr = tc.xpath('./w:tcPr')
  543. if not tcPr:
  544. tcPr = OxmlElement('w:tcPr')
  545. tc.insert(0, tcPr)
  546. else:
  547. tcPr = tcPr[0]
  548. # 创建边框元素
  549. tcBorders = OxmlElement('w:tcBorders')
  550. # 添加各个位置的边框
  551. for position in positions:
  552. border = OxmlElement(f'w:{position}')
  553. border.set(qn('w:val'), border_style)
  554. border.set(qn('w:sz'), str(border_width * 8)) # 8 = 1pt
  555. border.set(qn('w:space'), '0')
  556. border.set(qn('w:color'), border_color)
  557. tcBorders.append(border)
  558. # 移除现有边框并添加新边框
  559. existing_borders = tcPr.xpath('./w:tcBorders')
  560. if existing_borders:
  561. tcPr.remove(existing_borders[0])
  562. tcPr.append(tcBorders)
  563. return f"已设置表格 {table_index} 单元格 ({row},{col}) 的边框样式"
  564. # 添加一个新的函数,用于一次性为整个表格添加标准边框
  565. def add_table_standard_borders(table_index):
  566. """为表格添加标准边框(所有单元格都有边框)"""
  567. doc = get_document()
  568. if table_index >= len(doc.tables):
  569. return f"错误:表格索引 {table_index} 超出范围"
  570. table = doc.tables[table_index]
  571. # 为表格设置标准边框
  572. for row in table.rows:
  573. for cell in row.cells:
  574. # 获取单元格的XML元素
  575. tc = cell._tc
  576. # 获取单元格属性
  577. tcPr = tc.xpath('./w:tcPr')
  578. if not tcPr:
  579. tcPr = OxmlElement('w:tcPr')
  580. tc.insert(0, tcPr)
  581. else:
  582. tcPr = tcPr[0]
  583. # 创建边框元素
  584. tcBorders = OxmlElement('w:tcBorders')
  585. # 添加四个方向的边框
  586. for position in ["top", "bottom", "left", "right"]:
  587. border = OxmlElement(f'w:{position}')
  588. border.set(qn('w:val'), 'single')
  589. border.set(qn('w:sz'), '4') # 0.5pt
  590. border.set(qn('w:space'), '0')
  591. border.set(qn('w:color'), '000000')
  592. tcBorders.append(border)
  593. # 移除现有边框并添加新边框
  594. existing_borders = tcPr.xpath('./w:tcBorders')
  595. if existing_borders:
  596. tcPr.remove(existing_borders[0])
  597. tcPr.append(tcBorders)
  598. return f"已为表格 {table_index} 添加标准边框"
  599. def add_border(cell):
  600. """为单元格添加边框"""
  601. tcPr = cell._element.tcPr
  602. if tcPr is None:
  603. tcPr = OxmlElement('w:tcPr')
  604. cell._element.append(tcPr)
  605. # 添加边框
  606. tcBorders = OxmlElement('w:tcBorders')
  607. for border in ['top', 'left', 'bottom', 'right']:
  608. border_element = OxmlElement(f'w:{border}')
  609. border_element.set(qn('w:val'), 'single')
  610. border_element.set(qn('w:sz'), '4') # 边框宽度
  611. border_element.set(qn('w:space'), '0')
  612. border_element.set(qn('w:color'), '000000') # 边框颜色
  613. tcBorders.append(border_element)
  614. tcPr.append(tcBorders)
  615. def copy_cell_style(excel_cell, word_cell):
  616. """复制单元格样式"""
  617. # 获取Excel单元格的字体
  618. if excel_cell.font:
  619. run = word_cell.paragraphs[0].runs
  620. if not run:
  621. run = word_cell.paragraphs[0].add_run()
  622. else:
  623. run = run[0]
  624. # 设置字体名称
  625. if excel_cell.font.name:
  626. run.font.name = excel_cell.font.name
  627. # 设置字体大小
  628. if excel_cell.font.size:
  629. # Excel字体大小与Word字体大小的转换
  630. run.font.size = Pt(excel_cell.font.size)
  631. # 设置粗体
  632. if excel_cell.font.bold:
  633. run.font.bold = True
  634. # 设置斜体
  635. if excel_cell.font.italic:
  636. run.font.italic = True
  637. # 设置下划线
  638. if excel_cell.font.underline:
  639. run.font.underline = True
  640. # 设置字体颜色
  641. if excel_cell.font.color and excel_cell.font.color.rgb:
  642. color = excel_cell.font.color.rgb
  643. if isinstance(color, str) and len(color) == 8: # ARGB格式
  644. rgb = color[2:] # 去掉Alpha通道
  645. run.font.color.rgb = RGBColor.from_string(rgb)
  646. # 设置单元格对齐方式
  647. if excel_cell.alignment:
  648. paragraph = word_cell.paragraphs[0]
  649. # 水平对齐
  650. if excel_cell.alignment.horizontal:
  651. if excel_cell.alignment.horizontal == 'center':
  652. paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
  653. elif excel_cell.alignment.horizontal == 'right':
  654. paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
  655. elif excel_cell.alignment.horizontal == 'left':
  656. paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
  657. # 添加边框
  658. add_border(word_cell)
  659. def copy_excel_to_word(excel_path, word_path, sheet_name=None, output_path=None):
  660. """
  661. 将Excel表格复制到Word文档
  662. 参数:
  663. excel_path: Excel文件路径
  664. word_path: Word文件路径,如果为None则创建新文档
  665. sheet_name: 要复制的工作表名称,如果为None则复制第一个工作表
  666. output_path: 输出Word文件路径,如果为None则覆盖原文件
  667. """
  668. try:
  669. # 加载Excel文件
  670. if not os.path.exists(excel_path):
  671. return {"error": f"Excel文件不存在: {excel_path}"}
  672. wb = openpyxl.load_workbook(excel_path, data_only=True)
  673. # 选择工作表
  674. if sheet_name:
  675. if sheet_name not in wb.sheetnames:
  676. return {"error": f"工作表 '{sheet_name}' 不存在"}
  677. ws = wb[sheet_name]
  678. else:
  679. ws = wb.active
  680. # 加载或创建Word文档
  681. if word_path and os.path.exists(word_path):
  682. doc = Document(word_path)
  683. else:
  684. doc = Document()
  685. # 获取Excel表格的行数和列数
  686. max_row = ws.max_row
  687. max_col = ws.max_column
  688. if max_row == 0 or max_col == 0:
  689. return {"error": "Excel表格为空"}
  690. # 在Word文档中创建表格
  691. table = doc.add_table(rows=max_row, cols=max_col)
  692. table.style = 'Table Grid' # 应用网格样式
  693. # 复制数据和样式
  694. for i in range(max_row):
  695. for j in range(max_col):
  696. # Excel单元格索引从1开始
  697. excel_cell = ws.cell(row=i+1, column=j+1)
  698. # Word表格索引从0开始
  699. word_cell = table.cell(i, j)
  700. # 复制单元格内容
  701. word_cell.text = str(excel_cell.value) if excel_cell.value is not None else ""
  702. # 复制单元格样式
  703. copy_cell_style(excel_cell, word_cell)
  704. # 保存Word文档
  705. save_path = output_path if output_path else (word_path if word_path else "output.docx")
  706. doc.save(save_path)
  707. return {
  708. "message": f"已将Excel表格复制到Word文档",
  709. "excel_path": excel_path,
  710. "sheet_name": sheet_name if sheet_name else ws.title,
  711. "output_path": save_path
  712. }
  713. except Exception as e:
  714. return {"error": f"复制Excel表格到Word文档失败: {str(e)}"}
  715. def copy_excel_range_to_word(excel_path, word_path, sheet_name, range_str, output_path=None):
  716. """
  717. 将Excel表格的指定区域复制到Word文档
  718. 参数:
  719. excel_path: Excel文件路径
  720. word_path: Word文件路径,如果为None则创建新文档
  721. sheet_name: 要复制的工作表名称
  722. range_str: 要复制的单元格区域,如'A1:C5'
  723. output_path: 输出Word文件路径,如果为None则覆盖原文件
  724. """
  725. try:
  726. from openpyxl.utils.cell import range_boundaries
  727. # 加载Excel文件
  728. if not os.path.exists(excel_path):
  729. return {"error": f"Excel文件不存在: {excel_path}"}
  730. wb = openpyxl.load_workbook(excel_path, data_only=True)
  731. # 选择工作表
  732. if sheet_name not in wb.sheetnames:
  733. return {"error": f"工作表 '{sheet_name}' 不存在"}
  734. ws = wb[sheet_name]
  735. # 解析区域范围
  736. try:
  737. min_col, min_row, max_col, max_row = range_boundaries(range_str)
  738. except ValueError:
  739. return {"error": f"无效的区域范围: {range_str}"}
  740. # 计算行数和列数
  741. rows = max_row - min_row + 1
  742. cols = max_col - min_col + 1
  743. if rows <= 0 or cols <= 0:
  744. return {"error": "指定的区域无效"}
  745. # 加载或创建Word文档
  746. if word_path and os.path.exists(word_path):
  747. doc = Document(word_path)
  748. else:
  749. doc = Document()
  750. # 在Word文档中创建表格
  751. table = doc.add_table(rows=rows, cols=cols)
  752. table.style = 'Table Grid' # 应用网格样式
  753. # 复制数据和样式
  754. for i in range(rows):
  755. for j in range(cols):
  756. # Excel单元格索引
  757. excel_row = min_row + i
  758. excel_col = min_col + j
  759. # 获取Excel单元格
  760. excel_cell = ws.cell(row=excel_row, column=excel_col)
  761. # Word表格索引从0开始
  762. word_cell = table.cell(i, j)
  763. # 复制单元格内容
  764. word_cell.text = str(excel_cell.value) if excel_cell.value is not None else ""
  765. # 复制单元格样式
  766. copy_cell_style(excel_cell, word_cell)
  767. # 保存Word文档
  768. save_path = output_path if output_path else (word_path if word_path else "output.docx")
  769. doc.save(save_path)
  770. return {
  771. "message": f"已将Excel表格区域复制到Word文档",
  772. "excel_path": excel_path,
  773. "sheet_name": sheet_name,
  774. "range": range_str,
  775. "output_path": save_path
  776. }
  777. except Exception as e:
  778. return {"error": f"复制Excel表格区域到Word文档失败: {str(e)}"}
  779. def add_table_row(table_index=0, position=None):
  780. """
  781. 在Word文档中的表格添加一行
  782. 参数:
  783. table_index: 表格索引,默认为第一个表格
  784. position: 要插入行的位置,如果为None则添加到表格末尾
  785. 返回:
  786. 成功或错误信息
  787. """
  788. try:
  789. doc = get_document()
  790. if not doc.tables or table_index >= len(doc.tables):
  791. return f"错误:文档中没有索引为 {table_index} 的表格"
  792. table = doc.tables[table_index]
  793. if position is None:
  794. # 添加到表格末尾
  795. table.add_row()
  796. return f"已在表格 {table_index} 末尾添加一行"
  797. else:
  798. # 在指定位置插入行
  799. row_count = len(table.rows)
  800. if position < 0 or position > row_count:
  801. return f"错误:行索引超出范围,有效范围为0-{row_count}"
  802. # 创建新行
  803. new_row = table.add_row()
  804. # 如果不是添加到末尾,需要移动行
  805. if position < row_count:
  806. # 将新行移动到指定位置
  807. for i in range(row_count, position, -1):
  808. # 复制上一行的内容到当前行
  809. for j in range(len(table.columns)):
  810. table.cell(i, j).text = table.cell(i-1, j).text
  811. # 清空目标位置的行
  812. for j in range(len(table.columns)):
  813. table.cell(position, j).text = ""
  814. return f"已在表格 {table_index} 的位置 {position} 插入一行"
  815. except Exception as e:
  816. return f"添加表格行时出错: {str(e)}"
  817. def add_table_column(table_index=0, position=None):
  818. """
  819. 在Word文档中的表格添加一列
  820. 参数:
  821. table_index: 表格索引,默认为第一个表格
  822. position: 要插入列的位置,如果为None则添加到表格末尾
  823. 返回:
  824. 成功或错误信息
  825. """
  826. try:
  827. doc = get_document()
  828. if not doc.tables or table_index >= len(doc.tables):
  829. return f"错误:文档中没有索引为 {table_index} 的表格"
  830. table = doc.tables[table_index]
  831. # 获取当前列数
  832. col_count = len(table.columns)
  833. if position is None:
  834. position = col_count
  835. elif position < 0 or position > col_count:
  836. return f"错误:列索引超出范围,有效范围为0-{col_count}"
  837. # 为每一行添加一个单元格
  838. for i, row in enumerate(table.rows):
  839. # 获取表格行的XML元素
  840. tr = row._tr
  841. # 创建新的单元格元素
  842. tc = OxmlElement('w:tc')
  843. # 添加段落到单元格
  844. p = OxmlElement('w:p')
  845. tc.append(p)
  846. # 添加单元格属性
  847. tcPr = OxmlElement('w:tcPr')
  848. tc.append(tcPr)
  849. # 确定插入位置
  850. if position == col_count:
  851. # 添加到末尾
  852. tr.append(tc)
  853. else:
  854. # 在指定位置插入
  855. ref_tc = tr.findall('.//w:tc', namespaces=tr.nsmap)[position]
  856. ref_tc.addprevious(tc)
  857. return f"已在表格 {table_index} 的位置 {position} 插入一列"
  858. except Exception as e:
  859. return f"添加表格列时出错: {str(e)}"
  860. def delete_table_row(table_index=0, row_index=None):
  861. """
  862. 删除Word文档中表格的一行
  863. 参数:
  864. table_index: 表格索引,默认为第一个表格
  865. row_index: 要删除的行索引
  866. 返回:
  867. 成功或错误信息
  868. """
  869. try:
  870. doc = get_document()
  871. if not doc.tables or table_index >= len(doc.tables):
  872. return f"错误:文档中没有索引为 {table_index} 的表格"
  873. table = doc.tables[table_index]
  874. row_count = len(table.rows)
  875. if row_index is None or row_index < 0 or row_index >= row_count:
  876. return f"错误:行索引超出范围,有效范围为0-{row_count-1}"
  877. # 获取要删除的行
  878. tr = table.rows[row_index]._tr
  879. # 从表格中删除行
  880. tr.getparent().remove(tr)
  881. return f"已删除表格 {table_index} 的第 {row_index} 行"
  882. except Exception as e:
  883. return f"删除表格行时出错: {str(e)}"
  884. def delete_table_column(table_index=0, column_index=None):
  885. """
  886. 删除Word文档中表格的一列
  887. 参数:
  888. table_index: 表格索引,默认为第一个表格
  889. column_index: 要删除的列索引
  890. 返回:
  891. 成功或错误信息
  892. """
  893. try:
  894. doc = get_document()
  895. if not doc.tables or table_index >= len(doc.tables):
  896. return f"错误:文档中没有索引为 {table_index} 的表格"
  897. table = doc.tables[table_index]
  898. col_count = len(table.columns)
  899. if column_index is None or column_index < 0 or column_index >= col_count:
  900. return f"错误:列索引超出范围,有效范围为0-{col_count-1}"
  901. # 遍历每一行,删除指定列的单元格
  902. for row in table.rows:
  903. # 获取行的XML元素
  904. tr = row._tr
  905. # 找到要删除的单元格
  906. cells = tr.findall('.//w:tc', namespaces=tr.nsmap)
  907. if column_index < len(cells):
  908. # 删除单元格
  909. tr.remove(cells[column_index])
  910. return f"已删除表格 {table_index} 的第 {column_index} 列"
  911. except Exception as e:
  912. return f"删除表格列时出错: {str(e)}"
  913. def get_table_dimensions(table_index=0):
  914. """
  915. 获取表格的维度(行数和列数)
  916. 参数:
  917. table_index: 表格索引,默认为第一个表格
  918. 返回:
  919. 表格的行数和列数
  920. """
  921. try:
  922. doc = get_document()
  923. if not doc.tables or table_index >= len(doc.tables):
  924. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  925. table = doc.tables[table_index]
  926. rows = len(table.rows)
  927. cols = len(table.columns)
  928. return {
  929. "rows": rows,
  930. "columns": cols
  931. }
  932. except Exception as e:
  933. return {"error": f"获取表格维度时出错: {str(e)}"}
  934. def get_table_cell_text(table_index=0, row=0, col=0):
  935. """
  936. 获取表格单元格的文本内容
  937. 参数:
  938. table_index: 表格索引,默认为第一个表格
  939. row: 行索引
  940. col: 列索引
  941. 返回:
  942. 单元格的文本内容
  943. """
  944. try:
  945. doc = get_document()
  946. if not doc.tables or table_index >= len(doc.tables):
  947. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  948. table = doc.tables[table_index]
  949. if row < 0 or row >= len(table.rows) or col < 0 or col >= len(table.columns):
  950. return {"error": f"单元格索引 ({row}, {col}) 超出范围"}
  951. cell_text = table.cell(row, col).text
  952. return {
  953. "text": cell_text
  954. }
  955. except Exception as e:
  956. return {"error": f"获取单元格文本时出错: {str(e)}"}
  957. def get_table_row(table_index=0, row=0):
  958. """
  959. 获取表格中一行的所有单元格文本
  960. 参数:
  961. table_index: 表格索引,默认为第一个表格
  962. row: 行索引
  963. 返回:
  964. 行中所有单元格的文本内容列表
  965. """
  966. try:
  967. doc = get_document()
  968. if not doc.tables or table_index >= len(doc.tables):
  969. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  970. table = doc.tables[table_index]
  971. if row < 0 or row >= len(table.rows):
  972. return {"error": f"行索引 {row} 超出范围"}
  973. row_cells = []
  974. for cell in table.rows[row].cells:
  975. row_cells.append(cell.text)
  976. return {
  977. "cells": row_cells
  978. }
  979. except Exception as e:
  980. return {"error": f"获取表格行时出错: {str(e)}"}
  981. def get_table_column(table_index=0, col=0):
  982. """
  983. 获取表格中一列的所有单元格文本
  984. 参数:
  985. table_index: 表格索引,默认为第一个表格
  986. col: 列索引
  987. 返回:
  988. 列中所有单元格的文本内容列表
  989. """
  990. try:
  991. doc = get_document()
  992. if not doc.tables or table_index >= len(doc.tables):
  993. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  994. table = doc.tables[table_index]
  995. if col < 0 or col >= len(table.columns):
  996. return {"error": f"列索引 {col} 超出范围"}
  997. column_cells = []
  998. for row in table.rows:
  999. column_cells.append(row.cells[col].text)
  1000. return {
  1001. "cells": column_cells
  1002. }
  1003. except Exception as e:
  1004. return {"error": f"获取表格列时出错: {str(e)}"}
  1005. def get_table_range(table_index=0, start_row=0, start_col=0, end_row=None, end_col=None):
  1006. """
  1007. 获取表格中指定范围的单元格文本
  1008. 参数:
  1009. table_index: 表格索引,默认为第一个表格
  1010. start_row: 起始行索引
  1011. start_col: 起始列索引
  1012. end_row: 结束行索引,如果为None则取最后一行
  1013. end_col: 结束列索引,如果为None则取最后一列
  1014. 返回:
  1015. 指定范围内所有单元格的文本内容二维数组
  1016. """
  1017. try:
  1018. doc = get_document()
  1019. if not doc.tables or table_index >= len(doc.tables):
  1020. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1021. table = doc.tables[table_index]
  1022. # 设置默认结束位置
  1023. if end_row is None:
  1024. end_row = len(table.rows) - 1
  1025. if end_col is None:
  1026. end_col = len(table.columns) - 1
  1027. # 检查索引范围
  1028. if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
  1029. return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
  1030. if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
  1031. return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
  1032. # 获取范围内的单元格文本
  1033. range_data = []
  1034. for row in range(start_row, end_row + 1):
  1035. row_data = []
  1036. for col in range(start_col, end_col + 1):
  1037. row_data.append(table.cell(row, col).text)
  1038. range_data.append(row_data)
  1039. return {
  1040. "data": range_data
  1041. }
  1042. except Exception as e:
  1043. return {"error": f"获取表格范围时出错: {str(e)}"}
  1044. def get_all_tables_info():
  1045. """
  1046. 获取文档中所有表格的基本信息
  1047. 返回:
  1048. 所有表格的行数和列数信息
  1049. """
  1050. try:
  1051. doc = get_document()
  1052. tables_info = []
  1053. for i, table in enumerate(doc.tables):
  1054. tables_info.append({
  1055. "table_index": i,
  1056. "rows": len(table.rows),
  1057. "columns": len(table.columns)
  1058. })
  1059. return {
  1060. "tables_count": len(doc.tables),
  1061. "tables": tables_info
  1062. }
  1063. except Exception as e:
  1064. return {"error": f"获取表格信息时出错: {str(e)}"}
  1065. def set_table_data(table_index=0, data=None, start_row=0, start_col=0, clear_existing=False):
  1066. """
  1067. 批量设置表格数据
  1068. 参数:
  1069. table_index: 表格索引,默认为第一个表格
  1070. data: 二维数组数据
  1071. start_row: 起始行索引
  1072. start_col: 起始列索引
  1073. clear_existing: 是否清除现有内容
  1074. 返回:
  1075. 成功或错误信息
  1076. """
  1077. try:
  1078. doc = get_document()
  1079. if not doc.tables or table_index >= len(doc.tables):
  1080. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1081. if not data or not isinstance(data, list):
  1082. return {"error": "数据必须是非空的二维数组"}
  1083. table = doc.tables[table_index]
  1084. rows = len(table.rows)
  1085. cols = len(table.columns)
  1086. # 检查数据是否超出表格范围
  1087. data_rows = len(data)
  1088. if data_rows == 0:
  1089. return {"error": "数据不能为空"}
  1090. data_cols = max(len(row) for row in data)
  1091. if start_row < 0 or start_row + data_rows > rows:
  1092. return {"error": f"数据行超出表格范围,表格有 {rows} 行,数据需要 {start_row + data_rows} 行"}
  1093. if start_col < 0 or start_col + data_cols > cols:
  1094. return {"error": f"数据列超出表格范围,表格有 {cols} 列,数据需要 {start_col + data_cols} 列"}
  1095. # 填充数据
  1096. for i, row_data in enumerate(data):
  1097. row_idx = start_row + i
  1098. for j, cell_value in enumerate(row_data):
  1099. col_idx = start_col + j
  1100. cell = table.cell(row_idx, col_idx)
  1101. # 如果需要清除现有内容
  1102. if clear_existing:
  1103. cell.text = ""
  1104. # 设置单元格文本
  1105. if cell_value is not None:
  1106. if cell.text and not clear_existing:
  1107. cell.text += "\n" + str(cell_value)
  1108. else:
  1109. cell.text = str(cell_value)
  1110. return {
  1111. "message": f"已设置表格 {table_index} 的数据,从 ({start_row}, {start_col}) 开始,共 {data_rows} 行 {data_cols} 列"
  1112. }
  1113. except Exception as e:
  1114. return {"error": f"设置表格数据时出错: {str(e)}"}
  1115. def set_table_row_data(table_index=0, row=0, data=None, start_col=0, clear_existing=False):
  1116. """
  1117. 设置表格一行的数据
  1118. 参数:
  1119. table_index: 表格索引,默认为第一个表格
  1120. row: 行索引
  1121. data: 一维数组数据
  1122. start_col: 起始列索引
  1123. clear_existing: 是否清除现有内容
  1124. 返回:
  1125. 成功或错误信息
  1126. """
  1127. try:
  1128. doc = get_document()
  1129. if not doc.tables or table_index >= len(doc.tables):
  1130. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1131. if not data or not isinstance(data, list):
  1132. return {"error": "数据必须是非空的一维数组"}
  1133. table = doc.tables[table_index]
  1134. if row < 0 or row >= len(table.rows):
  1135. return {"error": f"行索引 {row} 超出范围"}
  1136. cols = len(table.columns)
  1137. data_cols = len(data)
  1138. if start_col < 0 or start_col + data_cols > cols:
  1139. return {"error": f"数据列超出表格范围,表格有 {cols} 列,数据需要 {start_col + data_cols} 列"}
  1140. # 填充数据
  1141. for j, cell_value in enumerate(data):
  1142. col_idx = start_col + j
  1143. cell = table.cell(row, col_idx)
  1144. # 如果需要清除现有内容
  1145. if clear_existing:
  1146. cell.text = ""
  1147. # 设置单元格文本
  1148. if cell_value is not None:
  1149. if cell.text and not clear_existing:
  1150. cell.text += "\n" + str(cell_value)
  1151. else:
  1152. cell.text = str(cell_value)
  1153. return {
  1154. "message": f"已设置表格 {table_index} 的第 {row} 行数据,从列 {start_col} 开始,共 {data_cols} 列"
  1155. }
  1156. except Exception as e:
  1157. return {"error": f"设置表格行数据时出错: {str(e)}"}
  1158. def set_table_column_data(table_index=0, col=0, data=None, start_row=0, clear_existing=False):
  1159. """
  1160. 设置表格一列的数据
  1161. 参数:
  1162. table_index: 表格索引,默认为第一个表格
  1163. col: 列索引
  1164. data: 一维数组数据
  1165. start_row: 起始行索引
  1166. clear_existing: 是否清除现有内容
  1167. 返回:
  1168. 成功或错误信息
  1169. """
  1170. try:
  1171. doc = get_document()
  1172. if not doc.tables or table_index >= len(doc.tables):
  1173. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1174. if not data or not isinstance(data, list):
  1175. return {"error": "数据必须是非空的一维数组"}
  1176. table = doc.tables[table_index]
  1177. if col < 0 or col >= len(table.columns):
  1178. return {"error": f"列索引 {col} 超出范围"}
  1179. rows = len(table.rows)
  1180. data_rows = len(data)
  1181. if start_row < 0 or start_row + data_rows > rows:
  1182. return {"error": f"数据行超出表格范围,表格有 {rows} 行,数据需要 {start_row + data_rows} 行"}
  1183. # 填充数据
  1184. for i, cell_value in enumerate(data):
  1185. row_idx = start_row + i
  1186. cell = table.cell(row_idx, col)
  1187. # 如果需要清除现有内容
  1188. if clear_existing:
  1189. cell.text = ""
  1190. # 设置单元格文本
  1191. if cell_value is not None:
  1192. if cell.text and not clear_existing:
  1193. cell.text += "\n" + str(cell_value)
  1194. else:
  1195. cell.text = str(cell_value)
  1196. return {
  1197. "message": f"已设置表格 {table_index} 的第 {col} 列数据,从行 {start_row} 开始,共 {data_rows} 行"
  1198. }
  1199. except Exception as e:
  1200. return {"error": f"设置表格列数据时出错: {str(e)}"}
  1201. def clear_table_range(table_index=0, start_row=0, start_col=0, end_row=None, end_col=None):
  1202. """
  1203. 清除表格中指定范围的内容
  1204. 参数:
  1205. table_index: 表格索引,默认为第一个表格
  1206. start_row: 起始行索引
  1207. start_col: 起始列索引
  1208. end_row: 结束行索引,如果为None则取最后一行
  1209. end_col: 结束列索引,如果为None则取最后一列
  1210. 返回:
  1211. 成功或错误信息
  1212. """
  1213. try:
  1214. doc = get_document()
  1215. if not doc.tables or table_index >= len(doc.tables):
  1216. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1217. table = doc.tables[table_index]
  1218. # 设置默认结束位置
  1219. if end_row is None:
  1220. end_row = len(table.rows) - 1
  1221. if end_col is None:
  1222. end_col = len(table.columns) - 1
  1223. # 检查索引范围
  1224. if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
  1225. return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
  1226. if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
  1227. return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
  1228. # 清除范围内的单元格文本
  1229. for row in range(start_row, end_row + 1):
  1230. for col in range(start_col, end_col + 1):
  1231. table.cell(row, col).text = ""
  1232. return {
  1233. "message": f"已清除表格 {table_index} 的区域 ({start_row}, {start_col}) 到 ({end_row}, {end_col})"
  1234. }
  1235. except Exception as e:
  1236. return {"error": f"清除表格区域时出错: {str(e)}"}
  1237. def get_table_detail_by_id(table_index=0):
  1238. """
  1239. 获取表格的详细信息,包括所有单元格的内容
  1240. 参数:
  1241. table_index: 表格索引,默认为第一个表格
  1242. 返回:
  1243. 表格的基本信息和单元格内容的多维数组
  1244. """
  1245. try:
  1246. doc = get_document()
  1247. if not doc.tables or table_index >= len(doc.tables):
  1248. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1249. table = doc.tables[table_index]
  1250. rows = len(table.rows)
  1251. cols = len(table.columns)
  1252. # 获取所有单元格内容
  1253. cells_content = []
  1254. for i in range(rows):
  1255. row_content = []
  1256. for j in range(cols):
  1257. cell = table.cell(i, j)
  1258. row_content.append(cell.text)
  1259. cells_content.append(row_content)
  1260. # 构建表格详细信息
  1261. table_detail = {
  1262. "table_index": table_index,
  1263. "rows": rows,
  1264. "columns": cols,
  1265. "content": cells_content
  1266. }
  1267. return table_detail
  1268. except Exception as e:
  1269. return {"error": f"获取表格详细信息时出错: {str(e)}"}
  1270. def set_table_font(table_index=0, font_name=None, font_size=None, bold=None, italic=None,
  1271. color=None, start_row=0, end_row=None, start_col=0, end_col=None):
  1272. """
  1273. 设置表格中指定范围单元格的字体属性
  1274. 参数:
  1275. table_index: 表格索引,默认为第一个表格
  1276. font_name: 字体名称
  1277. font_size: 字体大小(磅)
  1278. bold: 是否加粗
  1279. italic: 是否斜体
  1280. color: 字体颜色(十六进制格式,如"FF0000"表示红色)
  1281. start_row: 起始行索引
  1282. end_row: 结束行索引,如果为None则取最后一行
  1283. start_col: 起始列索引
  1284. end_col: 结束列索引,如果为None则取最后一列
  1285. 返回:
  1286. 成功或错误信息
  1287. """
  1288. try:
  1289. doc = get_document()
  1290. if not doc.tables or table_index >= len(doc.tables):
  1291. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1292. table = doc.tables[table_index]
  1293. # 设置默认结束位置
  1294. if end_row is None:
  1295. end_row = len(table.rows) - 1
  1296. if end_col is None:
  1297. end_col = len(table.columns) - 1
  1298. # 检查索引范围
  1299. if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
  1300. return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
  1301. if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
  1302. return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
  1303. # 遍历指定范围的单元格
  1304. for row in range(start_row, end_row + 1):
  1305. for col in range(start_col, end_col + 1):
  1306. cell = table.cell(row, col)
  1307. # 遍历单元格中的所有段落
  1308. for paragraph in cell.paragraphs:
  1309. # 如果段落没有文本运行,添加一个空的运行
  1310. if not paragraph.runs:
  1311. paragraph.add_run()
  1312. # 设置每个文本运行的字体属性
  1313. for run in paragraph.runs:
  1314. if font_name:
  1315. run.font.name = font_name
  1316. # 设置中文字体
  1317. run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
  1318. if font_size is not None:
  1319. run.font.size = Pt(font_size)
  1320. if bold is not None:
  1321. run.font.bold = bold
  1322. if italic is not None:
  1323. run.font.italic = italic
  1324. if color:
  1325. # 将十六进制颜色转换为RGB
  1326. if color.startswith('#'):
  1327. color = color[1:]
  1328. r = int(color[0:2], 16)
  1329. g = int(color[2:4], 16)
  1330. b = int(color[4:6], 16)
  1331. run.font.color.rgb = RGBColor(r, g, b)
  1332. return {
  1333. "message": f"已设置表格 {table_index} 的字体属性,范围: ({start_row},{start_col}) 到 ({end_row},{end_col})"
  1334. }
  1335. except Exception as e:
  1336. return {"error": f"设置表格字体时出错: {str(e)}"}
  1337. def set_table_cell_alignment(table_index=0, start_row=0, end_row=None, start_col=0, end_col=None,
  1338. horizontal_alignment="CENTER", vertical_alignment="CENTER"):
  1339. """
  1340. 设置表格单元格的水平和垂直对齐方式
  1341. 参数:
  1342. table_index: 表格索引,默认为第一个表格
  1343. start_row: 起始行索引
  1344. end_row: 结束行索引,如果为None则取最后一行
  1345. start_col: 起始列索引
  1346. end_col: 结束列索引,如果为None则取最后一列
  1347. horizontal_alignment: 水平对齐方式,可选值:"LEFT", "CENTER", "RIGHT", "JUSTIFY"
  1348. vertical_alignment: 垂直对齐方式,可选值:"TOP", "CENTER", "BOTTOM"
  1349. 返回:
  1350. 成功或错误信息
  1351. """
  1352. try:
  1353. doc = get_document()
  1354. if not doc.tables or table_index >= len(doc.tables):
  1355. return {"error": f"文档中没有索引为 {table_index} 的表格"}
  1356. table = doc.tables[table_index]
  1357. # 设置默认结束位置
  1358. if end_row is None:
  1359. end_row = len(table.rows) - 1
  1360. if end_col is None:
  1361. end_col = len(table.columns) - 1
  1362. # 检查索引范围
  1363. if start_row < 0 or start_row > end_row or end_row >= len(table.rows):
  1364. return {"error": f"行索引范围 ({start_row}, {end_row}) 无效"}
  1365. if start_col < 0 or start_col > end_col or end_col >= len(table.columns):
  1366. return {"error": f"列索引范围 ({start_col}, {end_col}) 无效"}
  1367. # 水平对齐方式映射
  1368. h_alignment_map = {
  1369. "LEFT": WD_ALIGN_PARAGRAPH.LEFT,
  1370. "CENTER": WD_ALIGN_PARAGRAPH.CENTER,
  1371. "RIGHT": WD_ALIGN_PARAGRAPH.RIGHT,
  1372. "JUSTIFY": WD_ALIGN_PARAGRAPH.JUSTIFY
  1373. }
  1374. # 垂直对齐方式映射
  1375. v_alignment_map = {
  1376. "TOP": WD_ALIGN_VERTICAL.TOP,
  1377. "CENTER": WD_ALIGN_VERTICAL.CENTER,
  1378. "BOTTOM": WD_ALIGN_VERTICAL.BOTTOM
  1379. }
  1380. # 检查对齐方式是否有效
  1381. if horizontal_alignment not in h_alignment_map:
  1382. return {"error": f"不支持的水平对齐方式: {horizontal_alignment}"}
  1383. if vertical_alignment not in v_alignment_map:
  1384. return {"error": f"不支持的垂直对齐方式: {vertical_alignment}"}
  1385. # 设置指定范围内单元格的对齐方式
  1386. for row in range(start_row, end_row + 1):
  1387. for col in range(start_col, end_col + 1):
  1388. cell = table.cell(row, col)
  1389. # 设置垂直对齐方式
  1390. cell.vertical_alignment = v_alignment_map[vertical_alignment]
  1391. # 设置水平对齐方式(应用于单元格中的所有段落)
  1392. for paragraph in cell.paragraphs:
  1393. paragraph.alignment = h_alignment_map[horizontal_alignment]
  1394. return {
  1395. "message": f"已设置表格 {table_index} 单元格的对齐方式,范围: ({start_row},{start_col}) 到 ({end_row},{end_col})"
  1396. }
  1397. except Exception as e:
  1398. return {"error": f"设置表格单元格对齐方式时出错: {str(e)}"}
  1399. # 函数映射表,用于根据函数名调用相应的函数
  1400. function_map = {
  1401. "create_new_document": create_new_document,
  1402. "set_global_font": set_global_font,
  1403. "save_document": save_document,
  1404. "open_document": open_document,
  1405. "add_paragraph_to_docx": add_paragraph_to_docx,
  1406. "add_heading": add_heading,
  1407. "add_table": add_table,
  1408. "add_picture": add_picture,
  1409. "add_page_break": add_page_break,
  1410. "set_paragraph_style": set_paragraph_style,
  1411. "set_font": set_font,
  1412. "set_paragraph_alignment": set_paragraph_alignment,
  1413. "set_paragraph_spacing": set_paragraph_spacing,
  1414. "add_section": add_section,
  1415. "set_section_orientation": set_section_orientation,
  1416. "set_section_page_size": set_section_page_size,
  1417. "set_section_margins": set_section_margins,
  1418. "add_header": add_header,
  1419. "add_footer": add_footer,
  1420. "add_page_number": add_page_number,
  1421. "merge_table_cells": merge_table_cells,
  1422. "set_table_cell_text": set_table_cell_text,
  1423. "set_table_style": set_table_style,
  1424. "set_table_cell_background": set_table_cell_background,
  1425. "set_table_cell_vertical_alignment": set_table_cell_vertical_alignment,
  1426. "set_table_width": set_table_width,
  1427. "set_table_column_width": set_table_column_width,
  1428. "add_hyperlink": add_hyperlink,
  1429. "add_bookmark": add_bookmark,
  1430. "add_table_of_contents": add_table_of_contents,
  1431. "set_table_borders": set_table_borders,
  1432. "set_cell_borders": set_cell_borders,
  1433. "add_table_standard_borders": add_table_standard_borders,
  1434. "copy_excel_to_word": copy_excel_to_word,
  1435. "copy_excel_range_to_word": copy_excel_range_to_word,
  1436. "add_table_row": add_table_row,
  1437. "add_table_column": add_table_column,
  1438. "delete_table_row": delete_table_row,
  1439. "delete_table_column": delete_table_column,
  1440. "get_table_dimensions": get_table_dimensions,
  1441. "get_table_cell_text": get_table_cell_text,
  1442. "get_table_row": get_table_row,
  1443. "get_table_column": get_table_column,
  1444. "get_table_range": get_table_range,
  1445. "get_all_tables_info": get_all_tables_info,
  1446. "set_table_data": set_table_data,
  1447. "set_table_row_data": set_table_row_data,
  1448. "set_table_column_data": set_table_column_data,
  1449. "clear_table_range": clear_table_range,
  1450. "get_table_detail_by_id": get_table_detail_by_id,
  1451. "set_table_font": set_table_font,
  1452. "set_table_cell_alignment": set_table_cell_alignment
  1453. }
  1454. def execute_docx_function(function_name, **kwargs):
  1455. """执行指定的函数"""
  1456. if function_name not in function_map:
  1457. return f"错误:未知的函数 {function_name}"
  1458. try:
  1459. return function_map[function_name](**kwargs)
  1460. except Exception as e:
  1461. return f"执行函数 {function_name} 时出错: {str(e)}"