# -*- coding: utf-8 -*- """ 单校区梳理表生成器模板 / Single-Campus Review Table Builder ========================================================== 照抄改值即可,别每个校区从头裸写 openpyxl(Pitfall 18:禁止裸做)。 2026-06-26 八个校区验证通过。 改这些就够了(搜 TODO): · ws.title / 大标题 / 项目信息行(r2) · r5 租赁数据行的 D5..L5、r8 物业数据行的 D8..L8(如无物业合同则跳过r6-r8) · 整体段(如无物业则整体段在r6-r7) · 输出路径 out 🔴 地基四铁律(开工前必默念): 1.逐字逐句 2.整体理解 3.上下文联系 4.逻辑分析 OCR乱码→vision核实,不准猜值;地址不一致→搜注册地址;租金跳变→做算术。 铁律内化点(已固化进结构,别违反): ① 12列:K=法律风险 / L=模版差异。建表后必跑 kl-separation-check.py。 ② 列宽以人民中路定稿为唯一基准。 ③ H列四检(交付前必过):条款号/月租换算/付款推算/❗标注。 ④ K列必含「提前退租法律后果分析」段(每校区必做)。 ④b K列禁用"模版"一词(含"制式模版"等复合形式)→改用"制式合同""制式文本"。 kl-separation-check.py 的 regex 无法区分语境,一律触发。龙信0703已验证。 ⑤ 纯文本❗做标记,不用富文本红字。 ⑥ 末尾必有「整体风险分析与建议」段。 ⑦ 列归类规则(详见 references/column-allocation-rules.md): · H列只放纯费用,违约金归I列(核心内容) · K列聚焦风险,"对乙方有利条款"放整体段续签建议="建议保留" · K列退租分析:有约定写约定,无约定写法律规定,禁无锚点推测 ⑧ 多租赁物时按租赁物分板块(非按合同类型),每板块内租赁前物业后。 详见 references/column-rules-0701.md「多租赁物表结构」。 模板脚本需手动调整板块结构(段标题=租赁物描述,非合同类型)。 """ import os, sys # ---- 事前拦截:物理依赖链检查 ---- # 建表前必须确认OCR已补全 + 模版比对已完成,否则脚本直接中止 WORKDIR = os.environ.get('CAMPUS_WORKDIR', '') if WORKDIR: _checkpoints = { 'step1.verified': 'OCR完整性未通过(先运行 ocr-integrity-check.py)', 'step2b.verified': '模版比对未完成(先 delegate subagent 做动作B,再运行 template-diff-verify.py)', } for ckpt, msg in _checkpoints.items(): path = os.path.join(WORKDIR, ckpt) if not os.path.exists(path): print(f"⛔ 建表中止:{msg}") print(f" 缺少checkpoint: {path}") sys.exit(1) print(f"✅ 事前拦截通过:{WORKDIR} 的OCR和模版比对checkpoint均存在") # 如果未设CAMPUS_WORKDIR则跳过检查(向后兼容),但delivery-gate事后仍会拦 import openpyxl from openpyxl.styles import Font, PatternFill, Alignment, Border, Side # ---- 样式常量(人民中路定稿基准:酒红主色 + 微软雅黑10)---- F = Font(name='微软雅黑', size=10) FB = Font(name='微软雅黑', size=10, bold=True) TITLE = Font(name='微软雅黑', size=14, bold=True, color='FFFFFFFF') SUB = Font(name='微软雅黑', size=10, bold=True, color='FF404040') SEC = Font(name='微软雅黑', size=11, bold=True, color='FFFFFFFF') fill_title = PatternFill(start_color='FF8B1A2B', fill_type='solid') fill_sec = PatternFill(start_color='FFC0504D', fill_type='solid') fill_hdr = PatternFill(start_color='FFE2EFDA', fill_type='solid') fill_sub = PatternFill(start_color='FFF2F2F2', fill_type='solid') thin = Side(style='thin') border = Border(left=thin, right=thin, top=thin, bottom=thin) AL = Alignment(horizontal='left', vertical='top', wrap_text=True) AC = Alignment(horizontal='center', vertical='center', wrap_text=True) wb = openpyxl.Workbook() ws = wb.active ws.title = '校区名' # TODO widths = dict(A=5, B=20, C=17, D=27, E=23, F=9, G=21, H=36.33, I=34, J=8, K=50, L=35) for c, w in widths.items(): ws.column_dimensions[c].width = w def merge_row(r, text, font, fill, h=None, al=AC): ws.merge_cells(f'A{r}:L{r}') cell = ws.cell(r, 1, text) cell.font = font cell.fill = fill cell.alignment = al for col in range(1, 13): ws.cell(r, col).fill = fill ws.cell(r, col).border = border if h: ws.row_dimensions[r].height = h # ---- r1 大标题 ---- merge_row(1, '校区名 — 租赁合同梳理', TITLE, fill_title, 30) # TODO # ---- r2 项目信息 ---- proj = ('物业项目:……\n' '出租方(租赁甲方):…… | 物业方(物业乙方):……\n' '承租方(乙方):……') # TODO merge_row(2, proj, SUB, fill_sub, 76, AL) # ---- r3 板块一 ---- merge_row(3, '一、房屋租赁合同', SEC, fill_sec, 22, Alignment(horizontal='left', vertical='center', wrap_text=True)) HDR = ['序号', '文件名称', '合同类型', '合同当事人', '租赁标的/服务范围', '面积(㎡)', '合同期限', '金额/费用', '核心内容', '当前状态', '法律风险(站乙方立场)', '与07标准模版差异'] for ci, h in enumerate(HDR, 1): c = ws.cell(4, ci, h) c.font = FB c.fill = fill_hdr c.alignment = AC c.border = border ws.row_dimensions[4].height = 30 # ---- r5 租赁数据行 ---- # TODO 填 D5..L5。 # H列四检:①条款号 ②月租换算(≈X个月) ③付款推算(各期具体日期) ④❗标注(未付期次) # H5 只放纯费用(租金/物业费/保证金/水电费标准),违约金归I列 # 🔴 I5 租赁合同必检21类目(有就写没有不写,直接摘原文,格式=· [类目] 原文(条款号)): # 用途/转租/装修改造/广告标识/非竞争/维修责任/保险要求/物业服务联动/配套设施/ # 出租方变更/解除权机制/违约金机制/不可抗力/征收拆迁/房屋抵押查封/政策变化/ # 到期处理/恢复原状/优先权/管辖/备案 # 🔴 I列物业合同必检15类目: # 物业服务内容/服务标准/公共能耗费/特约服务/共用设施管理/装修管理/安保措施/ # 消防安全/保险要求/联动终止/违约责任/退出交接/免责条款/不可抗力/管辖 # K5 独立审查:从"本合同第X条这样约定→对乙方什么后果"起笔 # K5 必含:需注意风险点 + 提前退租法律后果(有约定写约定,无约定写法律规定,禁推测) # K5 禁放"对乙方有利条款" → 移到整体段续签建议="建议保留" # L5 纯客观:只摆文本差异事实,禁止"风险/建议/不利/详见" row5 = ['1', '租赁合同.pdf', '房屋租赁合同', 'D5…', 'E5…', '面积', 'G5…', 'H5…', 'I5…', '履行中', 'K5…', 'L5…'] for ci, v in enumerate(row5, 1): c = ws.cell(5, ci, v) c.font = F c.alignment = (AC if ci in (1, 3, 6, 10) else AL) c.border = border ws.row_dimensions[5].height = 409.5 # ---- r6-r8 物业板块(如无物业合同则跳过,整体段改为r6-r7)---- merge_row(6, '二、物业管理服务合同', SEC, fill_sec, 22, Alignment(horizontal='left', vertical='center', wrap_text=True)) for ci, h in enumerate(HDR, 1): c = ws.cell(7, ci, h) c.font = FB c.fill = fill_hdr c.alignment = AC c.border = border ws.row_dimensions[7].height = 30 # TODO 填 D8..L8。物业合同新东方常为甲方,与租赁当事人方向相反,D8加注。 row8 = ['2', '物业合同.pdf', '物业管理服务合同', 'D8…', 'E8…', '面积', 'G8…', 'H8…', 'I8…', '履行中', 'K8…', '物业服务协议,无对应07标准模版。'] for ci, v in enumerate(row8, 1): c = ws.cell(8, ci, v) c.font = F c.alignment = (AC if ci in (1, 3, 6, 10) else AL) c.border = border ws.row_dimensions[8].height = 200 # ---- r9-r10 整体风险分析与建议(必含板块)---- merge_row(9, '三、校区整体风险分析与建议', SEC, fill_sec, 22, Alignment(horizontal='left', vertical='center', wrap_text=True)) # TODO 结构:【整体评价】→【需客户核实】→【提前退租法律后果】→【其他关注点】→【有利条款】→【续签建议】 overall = '【整体评价】\n……' # TODO merge_row(10, overall, F, PatternFill(start_color='FFFFFFFF', fill_type='solid'), 350, AL) ws.cell(10, 1).font = F ws.freeze_panes = 'A5' out = '/tmp/<校区>/校区名-梳理-MJ-YYYYMMDD.xlsx' # TODO wb.save(out) print('saved', out) # 建表后必做:1) python3 scripts/kl-separation-check.py 验K/L分工 # 2) python3 scripts/i-column-coverage-check.py 验I列类目覆盖(详见 references/i-column-standard-0703.md) # 3) H列四检逐项过 # 4) x2t渲染PDF + pdftotext拍平grep验文字 + vision验视觉