| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- # -*- coding: utf-8 -*-
- """按原 xlsx 格式补全业务表字段类型与描述,输出到桌面与 docs。"""
- import json
- from openpyxl import Workbook, load_workbook
- from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
- from openpyxl.utils import get_column_letter
- from pathlib import Path
- ROOT = Path(r"c:\Users\Liumouren\Desktop\临时文件\元以科技\松江\松江农民退养补贴")
- SRC = ROOT / "docs" / "松江农民土地退补系统字段名称.xlsx"
- FRESH = ROOT / "docs" / "_dms_fields_fresh_20260904.json"
- OUT_DESKTOP = Path(r"c:\Users\Liumouren\Desktop") / "松江农民土地退补系统字段名称.xlsx"
- OUT_DOCS = ROOT / "docs" / "松江农民土地退补系统字段名称.xlsx"
- models = json.loads(FRESH.read_text(encoding="utf-8"))
- TYPE_CN = {
- "text": "文本",
- "double": "数值(小数)",
- "integer": "数值(整数)",
- "timestamp": "日期时间",
- "long": "长整型",
- "float": "数值(小数)",
- }
- FRONT_CN = {
- "content": "文本框",
- "float_num": "小数",
- "int_num": "整数",
- "date_time": "日期时间",
- "date": "日期",
- }
- def type_label(f):
- t = f.get("type") or ""
- ft = f.get("frontType") or ""
- base = TYPE_CN.get(t, t or "")
- if ft and ft in FRONT_CN:
- return f"{base}/{FRONT_CN[ft]}" if base else FRONT_CN[ft]
- return base
- index = []
- for key, m in models.items():
- for f in m["fields"]:
- index.append((key, f))
- def find_field(name_hints, prefer_keys=None):
- hints = [h for h in name_hints if h]
- prefer_keys = prefer_keys or []
- candidates = []
- for key, f in index:
- alias = (f.get("alias") or "").strip()
- name = (f.get("name") or "").strip()
- short = name[2:] if name.startswith("c_") else name
- for h in hints:
- h = str(h).strip()
- if not h:
- continue
- target = h if h.startswith("c_") else ("c_" + h)
- if alias == h or name == h or short == h or name == target:
- candidates.append((key, f, 0))
- elif h in alias or (alias and alias in h):
- candidates.append((key, f, 1))
- if prefer_keys:
- for pk in prefer_keys:
- for c in candidates:
- if c[0] == pk:
- return c
- return candidates[0] if candidates else None
- EXPLICIT = {
- "人员姓名": (["personnel"], ["姓名", "c_name"]),
- "人员身份证号码": (["personnel"], ["身份证号", "c_id_number"]),
- "社会保险登记号": (["personnel"], ["个人社会保险登记码", "c_social_insurance_code"]),
- "手机号": (["personnel"], ["手机号", "c_phone_number"]),
- "联系地址": (["personnel"], ["家庭住址", "c_address"]),
- "户籍性质": (["personnel"], ["户籍性质", "c_household_type"]),
- "街镇": (["personnel"], ["街镇ID", "c_town_id"]),
- "村居": (["personnel"], ["村居ID", "c_village_id"]),
- "村委代码": (["personnel"], ["村委代码", "c_village_code"]),
- "委托方案代码": (["personnel", "region"], ["委托方案代码", "c_entrust_plan_code"]),
- "委托方案名称": (["personnel"], ["委托方案名称", "c_entrust_plan_name"]),
- "收款人名称": (["personnel"], ["收款人名称", "c_payee_name"]),
- "银行卡号": (["personnel"], ["银行卡号", "c_bank_card_number"]),
- "发放银行": (["personnel", "batchStat", "batch"], ["开户行", "c_bank_name", "发放银行"]),
- "收款银行行号": (["personnel"], ["收款银行行号", "c_bank_branch_code"]),
- "退养资格类型": (["personnel"], ["退养资格类型", "c_retire_qualify_type"]),
- "居保状态": (["personnel"], ["居保养老状态", "c_insurance_status"]),
- "死亡状态": (["personnel"], ["死亡状态", "c_death_status"]),
- "死亡日期": (["personnel"], ["死亡日期", "c_death_date"]),
- "继承人姓名": (["personnel"], ["继承人姓名", "c_heir_name"]),
- "继承人与逝者关系": (["personnel"], ["继承人关系", "c_heir_relation"]),
- "继承人联系方式": (["personnel"], ["继承人电话", "c_heir_phone"]),
- "继承人身份证": (["personnel"], ["继承人身份证", "c_heir_id_number"]),
- "继承人银行卡": (["personnel"], ["继承人银行卡", "c_heir_bank_card"]),
- "丧葬费补差额": (["personnel"], ["丧葬费补差额", "c_funeral_diff_amount"]),
- "丧葬是否已发放": (["personnel", "payment"], ["c_remarks"]),
- "补贴金额": (["standard"], ["金额", "c_amount"]),
- "丧葬金额": (["standard"], ["丧葬金额", "c_funeral_amount"]),
- "生效时间": (["standard"], ["生效时间", "c_date_time"]),
- "失效时间": (["standard"], ["失效时间", "c_expire_time"]),
- "标准类型": (["standard"], ["标准类型", "c_standard_type"]),
- "是否当前有效": (["standard"], ["是否当前有效", "c_current_flag"]),
- "调整原因": (["standard"], ["调整原因", "c_adjust_reason"]),
- "享受起始年月": (["personnel"], ["享受起始年月", "代发起始年月", "c_enjoy_start_month"]),
- "代发截止年月": (["personnel"], ["代发截止年月", "c_enjoy_end_month"]),
- "补发开始年月": (["personnel"], ["补发开始年月", "c_supplement_start_month"]),
- "下次发放起始年月": (["personnel"], ["下次发放起始年月", "c_next_pay_start_month"]),
- "区级资金承担比例": (["region"], ["区级资金承担比例", "c_district_share_percent"]),
- "镇级资金承担比例": (["region"], ["镇级资金承担比例", "c_town_share_percent"]),
- "是否已出盘": (["batch", "payment"], ["是否已出盘", "出盘", "c_disk_out"]),
- "实发金额": (["payment"], ["实发金额", "c_actual_amount"]),
- "回盘是否成功": (["payment"], ["回盘是否成功", "c_return_success"]),
- "回盘结果": (["payment"], ["回盘结果", "c_return_result"]),
- "调标前月补": (["payment"], ["调标前月补", "c_old_monthly_amount"]),
- "调标后月补": (["payment"], ["调标后月补", "c_new_monthly_amount"]),
- "调标应发月数": (["payment"], ["调标应发月数", "c_adjust_months"]),
- "告警等级": (["alert"], ["告警等级", "c_level"]),
- "告警类型": (["alert"], ["告警类型", "c_type"]),
- "告警内容": (["alert"], ["告警内容", "c_content"]),
- "失败原因码": (["alert", "payment"], ["失败原因码", "c_fail_code"]),
- "处理状态": (["alert", "process"], ["处理状态", "c_status"]),
- "处理结果": (["alert", "process"], ["处理结果", "c_result"]),
- "发起人": (["alert", "process"], ["发起人", "c_initiator"]),
- "接收人": (["alert", "process"], ["接收人", "c_receiver"]),
- "流程id": (["process", "alert"], ["流程ID", "流程id", "c_process_id"]),
- "处理人": (["alert", "process"], ["处理人", "c_handler"]),
- "处理时间": (["alert", "process"], ["处理时间", "c_handle_time"]),
- "文件地址": (["alert", "batch"], ["文件地址", "c_file_url"]),
- "备注描述": (["alert", "process"], ["备注", "c_remarks"]),
- "关联批次ID": (["batchStat", "payment", "batch"], ["关联批次ID", "批次ID", "c_batch_id"]),
- "批次号": (["batch", "batchStat", "payment"], ["批次号", "c_batch_number"]),
- "汇总表编号": (["batchStat"], ["汇总表编号", "c_summary_no"]),
- "发放年月": (["batch", "batchStat", "payment"], ["发放年月", "c_pay_month"]),
- "镇id": (["batchStat", "batch", "personnel"], ["街镇ID", "镇ID", "c_town_id"]),
- "村id": (["batchStat", "batch", "personnel"], ["村居ID", "村ID", "c_village_id"]),
- "统计粒度": (["batchStat"], ["统计粒度", "c_stat_level"]),
- "应支付人数": (["batchStat", "batch"], ["应支付人数", "c_payable_count"]),
- "应支付总额": (["batchStat", "batch"], ["应支付总额", "c_payable_amount"]),
- "实支付人数": (["batchStat", "batch"], ["实支付人数", "c_paid_count"]),
- "实支付总额": (["batchStat", "batch"], ["实支付总额", "c_paid_amount"]),
- "支付未成功人数": (["batchStat", "batch"], ["支付未成功人数", "失败人数", "c_fail_count"]),
- "支付未成功总额": (["batchStat", "batch"], ["支付未成功总额", "c_fail_amount"]),
- "标准金额": (["batchStat", "payment"], ["标准金额", "月补金额", "c_standard_amount"]),
- "死亡金额": (["batchStat", "payment"], ["死亡金额", "丧葬金额", "c_funeral_amount"]),
- "补充金额": (["batchStat", "payment"], ["补充金额", "c_extra_amount"]),
- "补发金额": (["batchStat", "payment"], ["补发金额", "c_supplement_amount"]),
- "回盘日期": (["batch", "batchStat", "payment"], ["回盘日期", "c_return_date"]),
- "经办人": (["batch", "batchStat"], ["经办人", "c_operator"]),
- "复核人": (["batch", "batchStat"], ["复核人", "c_reviewer"]),
- "备注": (["batchStat", "batch", "personnel"], ["备注", "c_remarks"]),
- "人数": (["batch", "batchStat"], ["人数", "c_person_count"]),
- }
- CAT_DEFAULT = {
- "人员基本信息": ("村合作社填报", "随时更新"),
- "区划与委托": ("系统维护/村合作社填报", "按需更新"),
- "银行信息": ("村合作社填报", "随时更新"),
- "退养资格": ("镇经发填报", "随时更新"),
- "居保匹配": ("大数据匹配", "随时更新"),
- "死亡状态匹配": ("大数据匹配", "随时更新"),
- "死亡与继承": ("镇社区事务受理中心/系统计算", "随时更新"),
- "金额标准": ("政策文件/系统计算", "一年一次或按业务"),
- "告警": ("系统计算", "每月更新"),
- "批次统计": ("系统计算", "每月更新"),
- }
- TABLE_META = {
- "personnel": ("人员基本信息表", "村合作社/镇社区/系统", "随时更新"),
- "region": ("区划表", "系统维护", "按需更新"),
- "standard": ("金额标准表", "政策文件/镇经发", "一年一次或调标时"),
- "alert": ("告警表", "系统计算", "随时更新"),
- "process": ("流程/特殊业务表", "业务部门填报", "随时更新"),
- "batch": ("批次表", "系统计算", "每月更新"),
- "batchStat": ("批次统计表", "系统计算", "每月更新"),
- "payment": ("发放明细表", "系统计算/回盘导入", "每月更新"),
- }
- SPECIAL_NOTES = {
- "丧葬是否已发放": "当前多用人员备注 FUNERAL_PAID 标记,非独立字段",
- "生效时间": "对应标准表 c_date_time",
- "是否当前有效": "对应标准表 c_current_flag",
- "死亡状态": "取值:正常/已死亡;与业务态 c_biz_status=FUNERAL 并存",
- "街镇": "存业务ID,界面展示中文名",
- "村居": "存业务ID,界面展示中文名",
- "镇id": "存业务ID,界面展示中文名",
- "村id": "存业务ID,界面展示中文名",
- "发放银行": "人员表对应开户行 c_bank_name",
- }
- wb0 = load_workbook(SRC)
- ws0 = wb0.active
- orig = []
- for i, row in enumerate(ws0.iter_rows(values_only=True), 1):
- if i == 1:
- continue
- vals = list(row)
- while len(vals) < 7:
- vals.append(None)
- cat, name, typ, src, freq, note, must = vals[:7]
- orig.append(
- {
- "cat": cat,
- "name": name,
- "type": typ,
- "source": src,
- "freq": freq,
- "note": note,
- "must": must,
- }
- )
- cur_cat = None
- for r in orig:
- if r["cat"]:
- cur_cat = r["cat"]
- else:
- r["cat"] = cur_cat
- enriched = []
- used_fields = set()
- for r in orig:
- name = r["name"]
- prefer, hints = EXPLICIT.get(name, (None, [name]))
- hit = find_field(hints, prefer) if prefer is not None else None
- if hit is None:
- hit = find_field([name] + list(hints or []), prefer)
- note_parts = []
- if r["note"]:
- note_parts.append(str(r["note"]))
- typ = r["type"]
- must = r["must"]
- src = r["source"]
- freq = r["freq"]
- if hit:
- key, f, _ = hit
- used_fields.add((key, f["name"]))
- typ = type_label(f)
- if must is None and f.get("must"):
- must = "是"
- m = models[key]
- note_parts.append(f"DMS:{m['label']} {f['name']}")
- desc = f.get("describe") or ""
- if desc and desc not in ("格式为富文本", "number", "时间戳"):
- note_parts.append(str(desc))
- if name in SPECIAL_NOTES:
- note_parts.append(SPECIAL_NOTES[name])
- else:
- note_parts.append("未在DMS单字段精确匹配,请核对业务口径")
- if name in SPECIAL_NOTES:
- note_parts.append(SPECIAL_NOTES[name])
- if not src or not freq:
- ds, df = CAT_DEFAULT.get(r["cat"], ("业务填报", "按需更新"))
- src = src or ds
- freq = freq or df
- enriched.append(
- [
- r["cat"],
- name,
- typ,
- src,
- freq,
- ";".join([p for p in note_parts if p]),
- must or "",
- ]
- )
- rows_sheet1 = []
- prev = None
- for row in enriched:
- cat = row[0]
- show_cat = cat if cat != prev else None
- prev = cat
- rows_sheet1.append([show_cat, row[1], row[2], row[3], row[4], row[5], row[6]])
- # 人员表其余未出现字段
- extra_rows = []
- append_cat = "人员表补充字段"
- for f in models["personnel"]["fields"]:
- if ("personnel", f["name"]) in used_fields:
- continue
- used_fields.add(("personnel", f["name"]))
- note = f"DMS:人员基本信息表 {f['name']}"
- if f["name"] == "c_death_status":
- note += ";取值正常/已死亡;与 c_biz_status=FUNERAL 并存"
- extra_rows.append(
- [
- None,
- f.get("alias") or f["name"],
- type_label(f),
- "系统/业务填报",
- "随时更新",
- note,
- "是" if f.get("must") else "",
- ]
- )
- if extra_rows:
- extra_rows[0][0] = append_cat
- thin = Border(
- left=Side(style="thin", color="B0B0B0"),
- right=Side(style="thin", color="B0B0B0"),
- top=Side(style="thin", color="B0B0B0"),
- bottom=Side(style="thin", color="B0B0B0"),
- )
- header_fill = PatternFill("solid", fgColor="1F4E79")
- header_font = Font(color="FFFFFF", bold=True, name="微软雅黑", size=11)
- cat_fill = PatternFill("solid", fgColor="D6E3F0")
- body_font = Font(name="微软雅黑", size=10)
- wrap = Alignment(wrap_text=True, vertical="center")
- HEADERS7 = ["类别", "字段名", "字段类型", "数据来源", "更新频率", "备注", "是否必须满足"]
- HEADERS_FULL = HEADERS7 + ["字段编码", "业务表", "栏目ID", "模型ID"]
- def style_header(ws, headers):
- for col, h in enumerate(headers, 1):
- cell = ws.cell(1, col, h)
- cell.fill = header_fill
- cell.font = header_font
- cell.alignment = Alignment(horizontal="center", vertical="center")
- cell.border = thin
- ws.row_dimensions[1].height = 22
- ws.freeze_panes = "A2"
- ws.auto_filter.ref = f"A1:{get_column_letter(len(headers))}1"
- def autosize(ws, widths):
- for i, w in enumerate(widths, 1):
- ws.column_dimensions[get_column_letter(i)].width = w
- def write_rows(ws, rows, headers):
- style_header(ws, headers)
- for r_i, row in enumerate(rows, 2):
- for c_i, val in enumerate(row, 1):
- cell = ws.cell(r_i, c_i, "" if val is None else val)
- cell.font = body_font
- cell.alignment = wrap
- cell.border = thin
- if c_i == 1 and val:
- cell.fill = cat_fill
- cell.font = Font(name="微软雅黑", size=10, bold=True)
- wb = Workbook()
- ws1 = wb.active
- ws1.title = "业务字段清单"
- write_rows(ws1, rows_sheet1, HEADERS7)
- autosize(ws1, [16, 18, 16, 22, 12, 55, 12])
- if extra_rows:
- r0 = len(rows_sheet1) + 3
- tip = ws1.cell(r0 - 1, 1, "—— 以下为对照 DMS 后补充的人员表字段 ——")
- tip.font = Font(name="微软雅黑", bold=True, color="C00000")
- for i, row in enumerate(extra_rows):
- for c_i, val in enumerate(row, 1):
- cell = ws1.cell(r0 + i, c_i, "" if val is None else val)
- cell.font = body_font
- cell.alignment = wrap
- cell.border = thin
- if c_i == 1 and val:
- cell.fill = cat_fill
- cell.font = Font(name="微软雅黑", size=10, bold=True)
- ws2 = wb.create_sheet("业务表字段全量")
- full_rows = []
- for key in ["personnel", "region", "standard", "payment", "batch", "batchStat", "alert", "process"]:
- m = models[key]
- tname, src, freq = TABLE_META[key]
- first = True
- for f in m["fields"]:
- note = f"字段编码 {f['name']}"
- desc = f.get("describe") or ""
- if desc and desc not in ("格式为富文本", "number", "时间戳"):
- note += ";" + str(desc)
- if f["name"] == "c_death_status":
- note += ";取值正常/已死亡;与 c_biz_status=FUNERAL 并存"
- if f["name"] == "c_return_success":
- note += ";回盘失败以 false + 备注回盘失败|RETURN_FAIL 为准"
- full_rows.append(
- [
- tname if first else None,
- f.get("alias") or f["name"],
- type_label(f),
- src,
- freq,
- note,
- "是" if f.get("must") else "",
- f["name"],
- m["tableCode"],
- m["columnId"],
- m["modelId"],
- ]
- )
- first = False
- write_rows(ws2, full_rows, HEADERS_FULL)
- autosize(ws2, [18, 20, 16, 22, 14, 50, 12, 28, 18, 10, 10])
- ws3 = wb.create_sheet("业务表索引")
- style_header(ws3, ["业务表", "表编码", "栏目ID", "模型ID", "字段数", "说明"])
- idx_rows = [
- ("人员基本信息表", "sjnmtybt_ryjbxx", 1847, 1970, len(models["personnel"]["fields"]), "人员底数、资格、居保、死亡继承等"),
- ("区划表", "sjnmtybt_xzqh", 1842, 1965, len(models["region"]["fields"]), "区/镇/村及资金比例、委托方案"),
- ("金额标准表", "sjnmtybt_jebz", 1843, 1966, len(models["standard"]["fields"]), "月补/丧葬标准、调标"),
- ("发放明细表", "sjnmtybt_ffmx", 1849, 1974, len(models["payment"]["fields"]), "应发实发、回盘、调标差额明细"),
- ("批次表", "sjnmtybt_pcb", 1845, 1968, len(models["batch"]["fields"]), "全区/村月批、出盘回盘状态"),
- ("批次统计表", "sjnmtybt_pctj", 1846, 1969, len(models["batchStat"]["fields"]), "镇/村汇总统计"),
- ("告警表", "sjnmtybt_alart", 1841, 1964, len(models["alert"]["fields"]), "死亡/回盘失败等告警"),
- ("流程/特殊业务表", "sjnmtybt_lcb", 1844, 1967, len(models["process"]["fields"]), "特殊业务审批与流程"),
- ]
- for i, row in enumerate(idx_rows, 2):
- for c, v in enumerate(row, 1):
- cell = ws3.cell(i, c, v)
- cell.font = body_font
- cell.border = thin
- cell.alignment = wrap
- autosize(ws3, [18, 22, 10, 10, 10, 40])
- ws4 = wb.create_sheet("填写说明")
- notes = [
- "本文件在《松江农民土地退补系统字段名称》原表格式基础上补全:字段类型、备注(含DMS字段编码/表归属)、以及业务表全量字段。",
- "原表列:类别、字段名、字段类型、数据来源、更新频率、备注、是否必须满足。",
- "「业务字段清单」:保留原业务口径字段顺序并补类型/备注;文末追加人员表其余未列出字段。",
- "「业务表字段全量」:8 张核心业务表全部自定义字段(同原列格式,并增加字段编码/业务表/栏目ID/模型ID)。",
- "字段类型示例:文本/文本框、数值(小数)/小数、数值(整数)/整数、日期时间/日期时间。",
- "死亡状态 c_death_status 与业务态 c_biz_status=FUNERAL 并存;回盘失败以 c_return_success=false + 备注为准。",
- "生成日期:2026-09-04;数据来源:生产 DMS 模型 getModelById。",
- ]
- for i, t in enumerate(notes, 1):
- cell = ws4.cell(i, 1, t)
- cell.font = body_font
- cell.alignment = wrap
- ws4.column_dimensions["A"].width = 120
- wb.save(OUT_DESKTOP)
- wb.save(OUT_DOCS)
- print("saved", OUT_DESKTOP)
- print("saved", OUT_DOCS)
- print("sheet1_orig", len(rows_sheet1), "personnel_extra", len(extra_rows), "full", len(full_rows))
|