# 审查意见文档字体强制设置 ## 背景(2026-07-02 肃言+恭兴合同返工) review-rules.md 规定审查意见文档:中文统一仿宋体,英文Times New Roman。 **问题**:模板文件(`朱家角 审查意见【模板】.docx`)的表头行有显式eastAsia=仿宋,但新建的数据行字体设置不一致: - 恭兴审查意见:editor给数据行设了 ascii=仿宋 hAnsi=仿宋(错:英文也变仿宋了) - 肃言审查意见:editor压根没给数据行设ascii/hAnsi(只有eastAsia=仿宋) **根因**:LLM每次独立session生成代码,字体设置逻辑不稳定。 ## 强制修复代码(生成审查意见后必跑) ```python from docx import Document from docx.oxml.ns import qn from docx.oxml import OxmlElement def enforce_review_opinion_fonts(doc_path, save=True): """审查意见文档生成后强制设置所有run的字体。 中文=仿宋, 英文=Times New Roman """ doc = Document(doc_path) fixed = 0 # Fix all table cells for table in doc.tables: for row in table.rows: for cell in row.cells: for p in cell.paragraphs: for run in p.runs: fixed += _fix_run_font(run._element) # Fix all paragraphs outside tables for p in doc.paragraphs: for run in p.runs: fixed += _fix_run_font(run._element) if save: doc.save(doc_path) return fixed def _fix_run_font(run_element): """Ensure run has eastAsia=仿宋, ascii/hAnsi=Times New Roman""" rPr = run_element.find(qn('w:rPr')) if rPr is None: rPr = OxmlElement('w:rPr') run_element.insert(0, rPr) rFonts = rPr.find(qn('w:rFonts')) if rFonts is None: rFonts = OxmlElement('w:rFonts') rPr.insert(0, rFonts) changed = False # eastAsia must be 仿宋 if rFonts.get(qn('w:eastAsia')) != '仿宋': rFonts.set(qn('w:eastAsia'), '仿宋') changed = True # ascii must be Times New Roman (NOT 仿宋) if rFonts.get(qn('w:ascii')) != 'Times New Roman': rFonts.set(qn('w:ascii'), 'Times New Roman') changed = True # hAnsi must be Times New Roman (NOT 仿宋) if rFonts.get(qn('w:hAnsi')) != 'Times New Roman': rFonts.set(qn('w:hAnsi'), 'Times New Roman') changed = True return 1 if changed else 0 ``` ## 验证方法 ```python def verify_review_opinion_fonts(doc_path): """验证审查意见文档字体全部正确""" from docx import Document from docx.oxml.ns import qn doc = Document(doc_path) errors = [] for table in doc.tables: for i, row in enumerate(table.rows): for j, cell in enumerate(row.cells): for p in cell.paragraphs: for run in p.runs: rpr = run._element.find(qn('w:rPr')) if rpr is None: errors.append(f'Row{i}Col{j}: no rPr') continue rf = rpr.find(qn('w:rFonts')) if rf is None: errors.append(f'Row{i}Col{j}: no rFonts') continue ea = rf.get(qn('w:eastAsia')) ascii_f = rf.get(qn('w:ascii')) hAnsi = rf.get(qn('w:hAnsi')) if ea != '仿宋': errors.append(f'Row{i}Col{j}: eastAsia={ea} (should be 仿宋)') if ascii_f != 'Times New Roman': errors.append(f'Row{i}Col{j}: ascii={ascii_f} (should be TNR)') if hAnsi != 'Times New Roman': errors.append(f'Row{i}Col{j}: hAnsi={hAnsi} (should be TNR)') return errors ``` ## 常见错误 | 错误 | 后果 | 根因 | |------|------|------| | ascii/hAnsi=仿宋 | 英文/数字渲染用仿宋(无西文字形,显示异常) | LLM把"统一仿宋"理解为所有属性都设仿宋 | | 数据行无ascii/hAnsi | 英文回退系统默认字体(可能是宋体/黑体) | 只设了eastAsia,忘设西文字体 | | 只有表头有字体 | 数据行全部回退默认 | 模板限制:只有表头行有显式字体 | ## 预防方案 最佳方案:修改模板文件的**Normal样式或Table Grid样式**定义,预设完整字体。但模板可能被多场景共用,最稳妥还是生成后强制设置。