| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- """扫描项目档案目录,识别合同期文件夹并生成续签链清单(CSV)。"""
- from __future__ import annotations
- import csv
- import re
- import sys
- from datetime import date, timedelta
- from pathlib import Path
- sys.stdout.reconfigure(encoding="utf-8")
- ROOT = Path(r"E:\申勤物业项目资料")
- OUT = Path(r"E:\CODE\knowledge_agent\output\续签链-档案目录.csv")
- PAT = re.compile(r"^(\d{4})\.(\d{1,2})\.(\d{1,2})-(\d{4})\.(\d{1,2})\.(\d{1,2})(.*)$")
- def _d(y: str, m: str, d: str) -> date:
- return date(int(y), int(m), int(d))
- def _norm_subject(name: str) -> str:
- """归一化合同主体:去掉扩展名、点招/补充标记与空白。"""
- s = name
- for suf in (".pdf", ".doc", ".docx", ".xls", ".xlsx"):
- s = s.replace(suf, "")
- s = re.sub(r"[((]?(点招|补充)[))]?", "", s)
- s = re.sub(r"[—-].*(点招|补充)$", "", s)
- return re.sub(r"\s+", "", s)
- def main() -> None:
- rows = []
- chains = 0
- period_total = 0
- for region in sorted(p for p in ROOT.iterdir() if p.is_dir() and not p.name.startswith(("6-", "7-"))):
- for proj in sorted(p for p in region.iterdir() if p.is_dir()):
- periods = []
- # 项目目录下可能直接是合同期文件夹,也可能再套一层项目名
- for cand in sorted(p for p in proj.iterdir() if p.is_dir()):
- m = PAT.match(cand.name)
- if m:
- periods.append((cand.name, m))
- else:
- for sub in sorted(p for p in cand.iterdir() if p.is_dir()):
- m2 = PAT.match(sub.name)
- if m2:
- periods.append((sub.name, m2))
- if not periods:
- continue
- periods.sort(key=lambda x: (_d(x[1].group(1), x[1].group(2), x[1].group(3)), x[0]))
- period_total += len(periods)
- num = proj.name.split("-")[0] if "-" in proj.name else ""
- prev: tuple[date, str, str] | None = None
- for name, m in periods:
- start = _d(m.group(1), m.group(2), m.group(3))
- end = _d(m.group(4), m.group(5), m.group(6))
- subject = _norm_subject(m.group(7))
- renewal = ""
- if prev is not None:
- contig = start <= prev[0] + timedelta(days=3)
- same_subj = prev[2] == subject or not prev[2] or not subject
- if contig and same_subj:
- renewal = f"是(上一期: {prev[1]})"
- chains += 1
- rows.append([
- region.name, proj.name, num, name,
- start.isoformat(), end.isoformat(), subject, renewal,
- ])
- prev = (end, name, subject)
- with OUT.open("w", newline="", encoding="utf-8-sig") as f:
- w = csv.writer(f)
- w.writerow(["区域", "项目目录", "目录编号", "合同期文件夹", "开始日期", "结束日期", "合同主体(归一)", "续签自上一期"])
- w.writerows(rows)
- print(f"扫描根目录: {ROOT}")
- print(f"合同期文件夹总数: {period_total}")
- print(f"识别到续签衔接: {chains} 条")
- print(f"输出: {OUT}")
- # 示例
- print("\n示例(青浦区图书馆):")
- for r in rows:
- if "102-青浦区图书馆" in r[1]:
- print(" ", " | ".join(r[2:]))
- if __name__ == "__main__":
- main()
|