"""生成 Excel 数据模板:每份文件只含一个数据表(+ 一份填写说明)。 设计原则: - 一份文件 = 一个数据域,避免人工跨表填写; - 关联字段用「项目名称/姓名」填写,编号由系统解析,人工无需查编码; - 参考字典(班次/岗位薪资/科目余额)由系统侧维护,不占用模板。 """ from __future__ import annotations import csv import sys from pathlib import Path from openpyxl import Workbook from openpyxl.comments import Comment from openpyxl.styles import Alignment, Border, Font, PatternFill, Side from openpyxl.utils import get_column_letter from openpyxl.worksheet.datavalidation import DataValidation sys.stdout.reconfigure(encoding="utf-8") OUT_DIR = Path(r"E:\CODE\knowledge_agent\data\templates") OUT_DIR.mkdir(parents=True, exist_ok=True) SRC_MKT = r"7-其他数据\20260529_申勤提供数据\市场部\2026年4月项目管理当期年化数据统计(1).xlsx" SRC_BIZ = r"7-其他数据\业务大表-申勤物业202607123-龚天晓字段补充.xlsx" SRC_RECON = r"7-其他数据\收到的数据\申勤市场部项目梳理表-20260616.xlsx" SRC_EMP = r"7-其他数据\收到的数据\人事部\员工信息.xlsx" SRC_ATT_DIR = r"7-其他数据\20260529_申勤提供数据\人事部\青东片区 排班、考勤\考勤26年1月-4月" SRC_SHIFT = r"7-其他数据\20260529_申勤提供数据\人事部\青东片区 排班、考勤\排班:青浦-赵巷公园、赵巷文体中心、赵巷镇政府、赵巷品牌公司系统排班(2026年1-4月).xlsx" SRC_SHIFT_XJ = r"7-其他数据\20260529_申勤提供数据\人事部\青东片区 排班、考勤\排班:青浦-徐泾卫生中心系统排班(2026年1-4月).xlsx" SRC_SHIFT_ZQ = r"7-其他数据\20260529_申勤提供数据\人事部\青东片区 排班、考勤\排班:青浦-赵巷、重固城建中心系统排班(2026年1-4月).xlsx" SRC_FIN = r"7-其他数据\20260529_申勤提供数据\财务部\2026按合同物业收费进程26.5.17(1).xlsx" SRC_EQ_QD = r"7-其他数据\20260529_申勤提供数据\运营部\01 现场工单、设备维保业务台账\项目设备台账\青浦-工业园区设备台账.xlsx" SRC_EQ_XH = r"7-其他数据\20260529_申勤提供数据\运营部\01 现场工单、设备维保业务台账\项目设备台账\徐汇-环境监测中心台账.xlsx" SRC_STAFF = r"7-其他数据\收到的数据\运营部\9-项目岗位编制汇总.xlsx" SRC_PUR_DIR = r"7-其他数据\收到的数据\人事部\采购部常用表格" SRC_CONS = r"7-其他数据\收到的数据\人事部\采购部常用表格\2026年耗材汇总\2026年度耗材汇总.xlsx" SRC_MAINT = r"7-其他数据\收到的数据\人事部\采购部常用表格\维保合同台账.xls" SRC_FIX = r"7-其他数据\收到的数据\人事部\采购部常用表格\固定资产台账汇总表.xlsx" SRC_QC = r"7-其他数据\20260529_申勤提供数据\运营部\02 品质巡检及整改记录台账\申勤物业服务质量检查标准(青浦公共卫生中心)整改.xlsx" HEADER_FILL = PatternFill("solid", fgColor="2F5597") REQUIRED_FILL = PatternFill("solid", fgColor="C00000") HEADER_FONT = Font(name="微软雅黑", size=10, bold=True, color="FFFFFF") BODY_FONT = Font(name="微软雅黑", size=10) NOTE_FONT = Font(name="微软雅黑", size=9, color="808080") THIN = Side(style="thin", color="BFBFBF") BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN) def _make_file(filename: str, title: str, headers: list[str], widths: list[int], notes: list[str], validations: dict[int, list[str]] | None = None, comments: dict[int, str] | None = None, required_cols: list[int] | None = None, examples: list[list] | None = None, field_sources: list[tuple[str, str]] | None = None) -> None: """一份文件 = 一个 CSV 数据表。""" if filename.lower().endswith(".xlsx"): filename = filename[:-5] + ".csv" path = OUT_DIR / filename with path.open("w", newline="", encoding="utf-8-sig") as f: writer = csv.writer(f) writer.writerow(headers) if examples: for row in examples: writer.writerow(row) def main() -> None: day_headers = [f"{i}日" for i in range(1, 32)] day_widths = [5] * 31 # 1. 项目信息 _make_file( "项目信息.xlsx", "项目主表", ["项目编号*", "项目名称*", "项目简称(选填)", "上级项目编号", "续签前项目编号", "项目起止时间", "省份", "市(区)", "细分业态", "汇总业态", "委托方式", "计费方式", "合同面积(㎡)", "合同金额(元)", "年化合同额(元)", "合同额具体信息", "服务期限", "合同状况", "首次服务日期", "年化合同收入(元)", "客户满意度(0-100)", "客户投诉(条)", "甲方名称", "项目地址", "项目负责人", "项目负责人工号*", "实际毛利率(%)", "服务状态", "备注"], [26, 18, 20, 22, 22, 24, 10, 10, 12, 12, 12, 12, 14, 16, 16, 20, 18, 12, 14, 16, 16, 12, 28, 24, 14, 16, 14, 12, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "青浦-区图书馆", "", "", "2026-02-28~2027-02-27", "上海", "青浦", "场馆", "公众物业", "多项单委", "包干", 16562, 3199128, 3199110.84, "当期合同额 3199110.84", "服务期一年(公开)", "已签", "2020-01-01", 3199110.84, "", "", "上海市青浦区图书馆", "青浦区青龙路60号", "张某某", "", "", "服务中", "示例"], ], field_sources=[ ("项目编号", f"{SRC_MKT} →「金蝶编码」;无编码项目用档案目录编号(融合)"), ("项目名称", f"{SRC_BIZ}(表1_2026总表)→「项目名称」"), ("项目简称", f"{SRC_MKT} →「项目简称」"), ("上级项目编号", "新增(融合):由业务大表层级序号推导从属关系"), ("续签前项目编号", "新增(融合):由档案目录续签链推导(scripts/analyze_renewal_folders.py)"), ("项目起止时间", f"{SRC_MKT} →「合同起止日期」(如 2026.02.28-2027.02.27)"), ("省份 / 市(区)", f"{SRC_BIZ}(表1_2026总表)→「省份(直辖市)」「市(区)」"), ("细分业态 / 汇总业态", f"{SRC_BIZ}(表1_2026总表)→「细分业态(建议使用点选方式)」「汇总业态(建议使用点选方式)」"), ("委托方式", f"{SRC_BIZ}(表1_2026总表)→「委托方式(建议使用点选方式)」"), ("计费方式", f"{SRC_BIZ}(表1_2026总表)→「计费方式(建议使用点选方式)」"), ("合同面积", f"{SRC_BIZ}(表1_2026总表)→「合同面积(万平米)」(模板统一为㎡,注意换算)"), ("合同金额 / 年化合同额", f"{SRC_MKT} →「合同金额」「年化合同额」"), ("合同额具体信息", f"{SRC_MKT} →「当期合同额(元)/预估合同额(元)/存量合同额(元)/新增合同额(元)」"), ("服务期限", f"{SRC_MKT} →「服务期限」"), ("合同状况", f"{SRC_MKT} →「合同状况」(子列:线上/线下)"), ("首次服务日期", f"{SRC_BIZ}(表1_2026总表)→「首次服务日期(建议精确到月)」"), ("年化合同收入", f"{SRC_BIZ}(表1_2026总表)→「年化合同收入(万元)(含税)」(模板统一为元,注意换算)"), ("客户满意度 / 客户投诉", "7-其他数据\\20260529_申勤提供数据\\运营部\\03 客户满意度及投诉记录\\客户满意度\\申勤物业服务满意度评价问卷报告(2025年度).docx →「满意度得分/回收答卷数」(聚合为项目属性);投诉来自 …\\客户投诉\\SHSQ-JGJL-02-0301客户投诉受理单.doc 等"), ("甲方名称", f"{SRC_MKT} →「甲方名称」"), ("项目地址", f"{SRC_MKT} →「项目地址」"), ("项目负责人", f"{SRC_BIZ}(表1_2026总表)→「项目点状负责人」"), ("项目负责人工号", "新增(融合):必填,人员唯一标识,避免重名;工号来源于员工信息.xlsx「员工编码」"), ("实际毛利率", f"{SRC_BIZ}(表1_2026总表)→「项目当年实际毛利率」"), ("服务状态", f"新增(融合):{SRC_RECON} →「服务中项目/历史项目」分类"), ("备注", "—"), ], notes=[ "一行 = 一个项目;项目编号是全局唯一关联键,必填——续签项目的名称/简称可能相同,但编号一定不同。", "上级项目编号:子项目填父项目编号,生成 (父)-[:包含]->(子) 边;顶层项目留空。", "续签前项目编号:续签项目填上一期项目编号(生成 新-续签自-旧 边);非续签留空。", "项目编号建议沿用金蝶编码(如 XMSQ0102);无金蝶编码的可按 XMSQ-<层级序号> 或自定义唯一编号。", "项目所属片区不在此表填写,见「项目片区关系.xlsx」(一个项目可属于多个片区);片区负责人见「片区信息.xlsx」。", "合同面积统一用 ㎡;金额统一用 元(来源表是万㎡/万元的注意换算)。", "服务状态取值:服务中/即将到期/已到期/历史。", ], validations={12: ["全委", "多项单委", "单一单委"], 19: ["线上", "线下"], 29: ["服务中", "即将到期", "已到期", "历史"]}, comments={1: "必填,全局唯一关联键(续签项目名称相同但编号不同)", 4: "父项目编号,生成包含边", 5: "上一期项目编号,生成续签自边"}, required_cols=[1, 2, 26], ) # 1.5 片区信息 + 项目片区关系 _make_file( "片区信息.xlsx", "片区主表", ["片区编号*", "片区名称*", "片区负责人工号*", "片区负责人(选填)", "备注"], [16, 20, 16, 14, 20], examples=[["PQ-001", "青东片区", "KWL2699022", "李片区", "示例"]], field_sources=[ ("片区编号", "新增(融合):片区唯一标识(如 PQ-001)"), ("片区名称", f"{SRC_BIZ}(表1_2026总表)→「管理区域(内部口径)」/ 8-项目信息汇总表 →「区域」"), ("片区负责人工号", "员工信息.xlsx →「员工编码」;必填,片区管理责任到人"), ("片区负责人", "新增(融合):可读性核对列,由工号解析"), ("备注", "—"), ], notes=[ "一行 = 一个片区;片区是区域管理维度,项目通过「项目片区关系.xlsx」关联到片区。", "片区编号为唯一键(如 PQ-001),项目片区关系表引用它。", ], required_cols=[1, 2, 3], ) _make_file( "项目片区关系.xlsx", "项目片区关系", ["项目编号*", "项目名称(选填)", "片区编号*", "片区名称(选填)", "备注"], [20, 26, 16, 20, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "PQ-003", "青中2区", "示例"], ["XMSQ0146", "青浦区赵巷公园", "PQ-001", "青东片区", "示例(一个项目可属于多个片区)"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("片区编号", "关联「片区信息」表(必填)"), ("片区名称", "新增(融合):可读性核对列"), ("备注", "—"), ], notes=[ "一行 = 一个项目与一个片区的归属关系(M:N);一个项目可多行(属于多个片区),一个片区可对应多个项目。", "导入后生成 (项目)-[:属于片区]->(片区) 边。", ], required_cols=[1, 3], ) # 13. 人员证书 _make_file( "人员证书.xlsx", "人员证书", ["工号*", "姓名(选填)", "专业类别", "证书类别", "证书名称*", "备注"], [16, 14, 14, 14, 32, 20], examples=[ ["KWL2306998", "陆雷雷", "安防", "从业资格证", "保安员(三级)", "示例"], ["KWL2699003", "测试丙", "工程", "从业资格证", "高压电工作业", "示例"], ], field_sources=[ ("工号", "员工信息.xlsx →「员工编码」;必填,人员唯一键(登记表申勤 sheet 缺工号,需按姓名在花名册补全)"), ("姓名", "新增(融合):可读性核对列,由工号解析"), ("专业类别", "合景悠活职称及资格证书管理登记表(2026年第一季度)→「专业类别」(安防/工程/综合管理/其他)"), ("证书类别", "同一登记表 →「证书类别」(从业资格证/职称证/执业资格证/其他)"), ("证书名称", "同一登记表 →「证书名称」(严格按证书填写,不能缩写或错字;一人可多行)"), ("备注", "—"), ], notes=[ "一行 = 一人持有的一张证书;一人可多行(多张证书)。", "证书名称必填且尽量规范(如 低压电工作业、物业管理师);同人同证书不重复填写。", "生成 (人员)-[:持有]->(证书) 边,支持“某人有哪些证/持某证的人/某项目持证情况”查询。", ], required_cols=[1, 5], ) # 2. 项目月度财务 _make_file( "项目月度财务.xlsx", "项目财务明细", ["项目编号*", "项目名称(选填)", "年月(YYYY-MM)*", "开票金额(元)", "收款金额(元)", "口径说明", "财务经办人工号*", "财务经办人(选填)", "备注"], [20, 26, 16, 16, 16, 30, 16, 14, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "2026-03", 266594, 266594, "示例口径", "KWL2699012", "财务员甲", "示例"], ["XMSQ0153", "青浦工业园区大楼", "2026-01", 150000, 140000, "示例口径", "KWL2699012", "财务员甲", "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("年月", "新增(时间键,格式 YYYY-MM)"), ("开票金额", f"{SRC_FIN} →「期内开票」或「1月物业费…12月物业费」"), ("收款金额", f"{SRC_FIN} →「期内收款」或「1月物业费…12月物业费」"), ("口径说明", "新增(融合):标注 应收/实收 等口径"), ("财务经办人工号", "员工信息.xlsx →「员工编码」;必填,用于追溯财务当事人"), ("财务经办人", "新增(融合):可读性核对列,由工号解析"), ("备注", "—"), ], notes=[ "一行 = 一个项目一个月的财务记录,与项目通过「项目编号」关联;项目名称作核对。", "年月格式:YYYY-MM(如 2026-03)。", "开票金额、收款金额分开填写;口径(应收/实收)在「口径说明」列注明。", "同一项目同一月份不要重复填写,重复会导致金额翻倍。", ], comments={3: "时间键,格式 YYYY-MM"}, required_cols=[1, 3, 7], ) # 2.5 月度快照(由考勤/排班/项目月度财务聚合的月度总览) _make_file( "月度快照.xlsx", "月度快照", ["项目编号*", "项目名称(选填)", "年月(YYYY-MM)*", "在岗人数", "排班人次", "考勤人次", "开票金额(元)", "收款金额(元)", "备注"], [20, 26, 16, 12, 12, 12, 16, 16, 24], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "2026-03", 18, 460, 438, 266594, 266594, "示例"], ["XMSQ0153", "青浦工业园区大楼", "2026-02", 12, 240, 236, 150000, 140000, "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("年月", "新增(时间键,格式 YYYY-MM)"), ("在岗人数", "由「考勤与人员财务」按项目+年月统计不同工号数,或按「岗位编制」在岗人数核对"), ("排班人次", "由「排班月报」按项目+年月统计行数"), ("考勤人次", "由「考勤与人员财务」按项目+年月统计行数"), ("开票金额", "由「项目月度财务」汇总或财务收费进程表"), ("收款金额", "由「项目月度财务」汇总或财务收费进程表"), ("备注", "—"), ], notes=[ "一行 = 一个项目一个月的经营快照,用于月度总览与横向对比。", "年月格式:YYYY-MM(如 2026-03)。", "在岗人数/排班人次/考勤人次应与明细表汇总结果一致;不能对齐时优先以明细表为准。", "同一项目同一月份不要重复填写。", ], comments={3: "时间键,格式 YYYY-MM"}, required_cols=[1, 3], ) # 2.6 科目余额 _make_file( "科目余额.xlsx", "科目余额", ["项目编号*", "项目名称(选填)", "期间(YYYY-MM)*", "科目编码*", "科目名称", "借方发生额(元)", "贷方发生额(元)", "期末余额(元)", "备注"], [20, 26, 16, 16, 22, 16, 16, 16, 24], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "2026-03", "6602", "物业费收入", 0, 266594, 266594, "示例"], ["XMSQ0102", "上海市青浦区图书馆", "2026-03", "6401", "主营业务成本", 120000, 0, 120000, "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("期间", "科目余额表期间,格式 YYYY-MM"), ("科目编码 / 科目名称", "财务部科目余额表 →「科目编码」「科目名称」"), ("借方发生额 / 贷方发生额 / 期末余额", "财务部科目余额表 → 对应发生额/余额列"), ("备注", "—"), ], notes=[ "一行 = 项目 × 会计科目 × 期间,用于科目级财务追溯。", "期间格式:YYYY-MM(如 2026-03)。", "科目编码为唯一组合键之一,同一项目同一期间同一科目不要重复填写。", "借贷方向按财务口径填写:借方发生额、贷方发生额、期末余额。", ], comments={3: "期间,格式 YYYY-MM", 4: "项目内期间内唯一"}, required_cols=[1, 3, 4], ) # 3. 投标记录 _make_file( "投标记录.xlsx", "投标记录", ["项目编号*", "项目名称(选填)", "年份*", "投标类型", "中标结果", "中标日期", "投标金额(元)", "文档路径", "投标经办人工号*", "投标经办人(选填)", "备注"], [20, 26, 10, 14, 12, 14, 16, 50, 16, 14, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", 2026, "中标通知书", "中标", "2026-02-01", 3199128, "1-青浦区域/102-青浦区图书馆", "KWL2699010", "陈某某", "示例"], ["XMSQ0108", "国家税务总局上海市青浦区税务局", 2026, "中标通知书", "中标", "2025-12-20", 7943908, "1-青浦区域/108-青浦区税务局", "KWL2699010", "陈某某", "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("年份", f"{SRC_BIZ}(表2 中标情况)→「招标年份」;或档案目录合同期文件夹名(如 2026.2.28-2027.2.27)"), ("投标类型", "新增(融合):档案文档类型 招标公告/投标文件/中标公告/中标通知书"), ("中标结果", f"{SRC_BIZ}(表2 中标情况)→「是否中标」"), ("中标日期", "E:\\申勤物业项目资料\\…\\中标通知书(如 …\\102-青浦区图书馆\\…\\中标(成交)结果公告.pdf)"), ("投标金额", f"{SRC_BIZ}(表2 中标情况)或 {SRC_MKT} →「合同金额」"), ("文档路径", "E:\\申勤物业项目资料\\(原始文件相对路径)"), ("投标经办人工号", "员工信息.xlsx →「员工编码」;必填,用于追溯投标当事人"), ("投标经办人", "新增(融合):可读性核对列,由工号解析"), ("备注", "—"), ], notes=[ "一行 = 一个项目一个年份的投标事件;同一年可多条(招标公告/投标/中标公告/中标通知书)。", "中标结果取值:中标/未中标/未知。", "文档路径指向档案目录(E:\\申勤物业项目资料)中的原始文件,用于溯源。", ], validations={3: ["招标公告", "投标文件", "中标公告", "中标通知书"], 4: ["中标", "未中标", "未知"]}, comments={1: "关联项目编号", 8: "档案目录相对路径"}, required_cols=[1, 3, 9], ) # 4. 人员信息 _make_file( "人员信息.xlsx", "人员主表", ["姓名*", "工号*", "组织名称", "岗位名称*", "当前服务项目编号(选填)", "服务起始年月", "服务结束年月", "职级", "员工层级", "所属组织名称", "入职日期", "离职日期", "司龄", "性别", "出生日期", "政治面貌", "联系电话", "备注"], [14, 16, 14, 20, 22, 14, 14, 10, 16, 14, 14, 14, 10, 8, 14, 12, 16, 20], examples=[ ["陆雷雷", "KWL2306998", "保安部", "保安_领班", "XMSQ0146", "2026-01", "2026-12", "P3", "一线员工", "保安部", "2025-01-01", "", "1.5年", "男", "1980-05-12", "汉族", "", "示例"], ["董一青", "KWL2307024", "管理处", "项目经理", "XMSQ01141", "2026-01", "2026-04", "P5", "项目管理人员", "管理处", "2023-02-01", "", "3年", "男", "1978-11-20", "汉族", "", "示例(1-2月赵巷镇政府,3-4月北斗园区)"], ], field_sources=[ ("姓名", f"{SRC_EMP} →「姓名」"), ("工号", f"{SRC_EMP} →「员工编码」(KWL 前缀);或考勤表 →「员工编码」"), ("组织名称", f"{SRC_SHIFT} →「组织名称(Organization Name)」(如 保洁部/保安部)"), ("岗位名称", f"{SRC_EMP} →「岗位名称」;或考勤表 →「岗位」;与「岗位编制」表的岗位用同一规范名(如 保安_领班)"), ("当前服务项目编号", "新增(融合):可用员工信息「五级公司」映射项目编号"), ("服务起始/结束年月", "新增(融合):填了直接生成服务于边;不填由考勤/排班月报推导"), ("职级", f"{SRC_EMP} →「职级」(如 P1/P3/P5)"), ("员工层级", f"{SRC_EMP} →「员工层级」(如 一线员工/项目管理人员)"), ("所属组织名称", f"{SRC_EMP} →「所属组织名称」(如 保洁部/管理处)"), ("入职日期", f"{SRC_EMP} →「入职日期」(如 20171113)"), ("离职日期", "新增(融合):选填,员工信息/花名册如有则填"), ("司龄", f"{SRC_EMP} →「司龄」(如 8.4年)"), ("性别 / 出生日期 / 政治面貌", f"{SRC_EMP} →「性别」「出生日期」「民族」「政治面貌」"), ("联系电话", f"{SRC_EMP}(花名册,如含电话列)"), ("备注", "—"), ], notes=[ "一行 = 一名员工;工号是全局唯一关联键(必填,KWL 前缀,来自人事花名册/考勤表)。", "岗位名称 = 实际工作岗位(必填),与「岗位编制」表的岗位用同一套规范名;员工层级为该岗位所属分类(一线员工/项目管理人员等),由岗位字典映射校验。", "服务起始年月/服务结束年月:填了就直接生成 (人员)-[:服务于]->(项目) 边,跨项目人员可填多行(同一年月范围一行)。", "服务期不填时,系统用考勤/排班月报自动推导。", "组织名称取值:保洁部/保安部/会务部/管理处/工程部/其他。", ], validations={3: ["保洁部", "保安部", "会务部", "管理处", "工程部", "其他"]}, comments={1: "姓名", 2: "必填,全局唯一关联键", 4: "当前服务项目编号", 5: "服务起始年月,格式 YYYY-MM"}, required_cols=[1, 2, 4], ) # 5. 考勤与人员财务(与原始考勤表同构) _make_file( "考勤与人员财务.xlsx", "考勤与人员财务", ["姓名*", "工号*", "项目编号*", "项目名称(选填)", "年月(YYYY-MM)*", *day_headers, "上班天数", "平时加班小时", "国定加班小时", "餐费补助金额(元)", "加班超时费金额(元)", "国定加班费金额(元)", "值班费金额(元)", "税后工资(元)", "备注"], [14, 16, 20, 26, 16, *day_widths, 10, 12, 12, 16, 18, 18, 16, 16, 20], examples=[ ["陆雷雷", "KWL2306998", "XMSQ0146", "青浦区赵巷公园", "2026-01", *["日1" if i <= 22 else "" for i in range(1, 32)], 22, 74, 0, 308, 1748.25, 0, 4896.25, "", "示例"], ], field_sources=[ ("姓名 / 工号", f"{SRC_ATT_DIR}\\青浦-赵巷公园-员工岗位考勤表2026年1月-4月员工岗位考勤表.xls →「姓名」「员工编码」"), ("项目编号", "关联「项目信息」表(必填);可由考勤表表头“项目:青浦-北斗园区”推导"), ("项目名称", "新增(融合):可读性核对列"), ("年月", "考勤表 sheet 名(如“1月”)+ 表头年份(新增时间键)"), ("1-31日", "考勤表 → 每日列(1日…31日),值如 常/夜/日1/日值/OFF/缺勤/请假"), ("上班天数", "考勤表 →「上班天数」"), ("平时加班小时 / 国定加班小时", "考勤表 →「平时加班小时」「国定加班小时」"), ("餐费补助金额", "考勤表 →「餐费补助金额」"), ("加班超时费金额 / 国定加班费金额 / 值班费金额", "考勤表 →「加班超时费金额」「国定加班费金额」「值班费金额」"), ("税后工资", "考勤表 →「备注」列中如含税后工资则填(如 税后工资5270.32)"), ("备注", "—"), ], notes=[ "一行 = 一名员工一个月的考勤 + 当月工资/补贴构成,与原始考勤表结构一致。", "1-31日列填每日状态:常=正常出勤;夜=夜班;日1=日班;日值=日值班;OFF=休息;缺勤/请假按实际填写,无记录留空。", "工号 + 项目编号 + 年月 三者定位一条记录;跨项目流动 = 不同月份填不同项目编号。", "上班天数、加班小时与每日状态需一致;金额列按实填写。", "服务期(服务于边)由本表连续月份自动推导。", ], comments={3: "该项目在当月实际服务的项目编号", 4: "项目名称,作核对"}, required_cols=[1, 2, 3, 5], ) # 6. 排班月报 _make_file( "排班月报.xlsx", "排班月报", ["姓名*", "工号*", "项目编号*", "项目名称(选填)", "年月(YYYY-MM)*", *day_headers, "备注"], [14, 16, 20, 26, 16, *day_widths, 20], examples=[ ["陆雷雷", "KWL2306998", "XMSQ0146", "青浦区赵巷公园", "2026-01", *["A003" if i <= 22 else "OFF" for i in range(1, 32)], "示例"], ], field_sources=[ ("姓名 / 工号", f"{SRC_SHIFT} →「姓名(Name)」「工号(Employee ID)」"), ("项目编号", "关联「项目信息」表(必填);由排班文件名 + 组织代码×考勤交叉推断(scripts/analyze_shift_mapping.py)"), ("项目名称", "新增(融合):可读性核对列"), ("年月", "排班表 sheet 名(如“1月”)+ 表头年份(新增时间键)"), ("1-31日", f"排班文件 → 每日列「班次代码(Shift Code)」;代码字典见同文件「班次列表」sheet。文件:{SRC_SHIFT_XJ}(班次列表23条)、{SRC_SHIFT_ZQ}(班次列表753条)、{SRC_SHIFT}"), ("备注", "—"), ], notes=[ "一行 = 一名员工一个月的排班;1-31日列填班次代码。", "常用班次代码对照:A003=不考勤班(无餐费);常=常班;日1=日班;日值=日值班;夜=夜班;OFF=休息;SQ-C13=常8(8小时);SQ-C16=C8;SQ-Z03=早11:00-19:00(餐费7);SQ-C21=常9;SQ-Z9=中班9小时;SQ-RZ03=日值11小时;SQ-Y19=夜12(无餐费);C8-096/065/087=常班8小时。", "完整班次字典见排班文件「班次列表」sheet(代码→名称→时间段);新增代码直接填写并在备注注明含义,系统自动收录。", ], comments={3: "该项目在当月实际服务的项目编号", 4: "项目名称,作核对"}, required_cols=[1, 2, 3, 5], ) # 7. 岗位编制 _make_file( "岗位编制.xlsx", "岗位编制", ["项目编号*", "项目名称(选填)", "岗位", "预算编制", "项目编制", "标准工时人数", "在岗人数", "备注"], [20, 26, 20, 10, 10, 14, 12, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "保安_领班", 1, 1, 1, 1, "示例"], ["XMSQ0102", "上海市青浦区图书馆", "保洁_主管", 2, 2, 2, 2, "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("岗位", f"{SRC_STAFF} → 岗位列(如 保安_领班、保洁_主管)"), ("预算编制", f"{SRC_STAFF} → 行“预算编制”"), ("项目编制", f"{SRC_STAFF} → 行“项目编制”"), ("标准工时人数", f"{SRC_STAFF} → 行“标准工时人数”"), ("在岗人数", f"{SRC_STAFF} → 行“项目在岗人数”"), ("备注", "—"), ], notes=[ "一行 = 项目 × 岗位 的编制与在岗情况,支持编制 vs 在岗差异分析。", "岗位按实际岗位名填写(如 保安主管、保洁_领班、工程_强电、会务_接待)。", ], required_cols=[1], ) # 8. 设备信息 _make_file( "设备信息.xlsx", "设备主表", ["项目编号*", "项目名称(选填)", "设备编号*", "设备类型", "名称", "规格型号参数", "制造厂商", "安装位置", "出厂日期", "启用日期", "入项目日期", "退项目日期", "出厂编号", "完好状况", "原值(元)", "设备责任人工号*", "设备责任人(选填)", "备注"], [20, 26, 20, 12, 16, 26, 24, 22, 14, 14, 14, 14, 16, 14, 14, 16, 14, 20], examples=[ ["XMSQ0153", "青浦工业园区大楼", "XF-PLB-01-B1-01", "消防", "喷淋泵", "200T/H 110M 55KW", "上海熊猫", "主楼地下水泵房", "2004-12", "2005-09", "2005-09", "", "10379", "使用正常", "", "KWL2699013", "设备员甲", "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填);可由设备台账表头“管理处:”推导"), ("项目名称", "新增(融合):可读性核对列"), ("设备编号", f"{SRC_EQ_QD} →「编号」"), ("设备类型", f"{SRC_EQ_QD} →「设备类别」(如 消防/电梯/给排水/配电/空调)"), ("名称", f"{SRC_EQ_QD} →「名称」"), ("规格型号参数", f"{SRC_EQ_QD} →「型号、规格 / 主要参数」;{SRC_EQ_XH} →「型号、规格、主要参数」"), ("制造厂商", f"{SRC_EQ_QD} →「制造厂名(国名)」"), ("安装位置", f"{SRC_EQ_QD} →「安装位置」"), ("出厂日期 / 启用日期", f"{SRC_EQ_QD} →「出厂日期」「启用日期」"), ("出厂编号", f"{SRC_EQ_QD} →「出厂编号」;{SRC_EQ_XH} →「产品编号、设备代码」"), ("完好状况", f"{SRC_EQ_QD} →「完好状况」(如 使用正常)"), ("原值", f"{SRC_EQ_QD} →「原值(必要时,填写)」"), ("设备责任人工号", "新增(融合):设备管理责任到人;工号来源于员工信息.xlsx「员工编码」"), ("设备责任人", "新增(融合):可读性核对列,由工号解析"), ("入项目日期 / 退项目日期", "新增(时间建模):入项目可用启用日期代替,退项目选填"), ("备注", "—"), ], notes=[ "一行 = 一台设备;项目名称关联项目,设备编号项目内唯一。", "入项目日期是设备-项目时间关系的起点(无确切日期可用启用日期代替);退项目日期选填。", "日期格式:YYYY-MM-DD。", ], validations={3: ["消防", "电梯", "给排水", "配电", "空调"], 13: ["使用正常", "维修中", "停用", "报废"]}, comments={1: "关联项目编号", 3: "项目内唯一"}, required_cols=[1, 3, 16], ) # 9. 采购与维保(供应商/维保合同/耗材采购/固定资产 共用一张表) _make_file( "采购与维保.xlsx", "采购与维保", ["记录类型*", "项目编号*", "项目名称(选填)", "供应商名称", "供应商编号(选填)", "类别", "名称/合同名称", "数量", "单位", "单价(元)", "金额(元)", "合同年限", "月份/日期", "当前状态", "经办人工号*", "经办人(选填)", "备注"], [14, 20, 26, 24, 14, 16, 24, 10, 8, 12, 14, 10, 14, 12, 16, 14, 20], examples=[ ["供应商", "", "", "上海熊猫", "SUP0001", "设备厂家", "", "", "", "", "", "", "", "", "KWL2699011", "采购员甲", "示例"], ["维保合同", "XMSQ0153", "青浦工业园区大楼", "上海熊猫", "SUP0001", "电梯维保", "电梯维保合同", "", "", "", 125000, 3, "2026-01", "", "KWL2699011", "采购员甲", "示例"], ["耗材采购", "XMSQ0102", "上海市青浦区图书馆", "洁力清洁用品", "SUP0005", "保洁耗材", "垃圾袋", 500, "卷", 2.5, 1250, "", "2026-02", "", "KWL2699011", "采购员甲", "示例"], ], field_sources=[ ("记录类型", "新增(融合):供应商/维保合同/耗材采购/固定资产"), ("项目编号", "关联「项目信息」表(必填;供应商记录留空)"), ("项目名称", "新增(融合):可读性核对列"), ("供应商名称", f"{SRC_CONS} →「供应商」;{SRC_MAINT} →「维保单位」"), ("供应商编号", "新增(融合):供应商唯一标识,避免同名供应商;编号规则 SUP+序号,须与供应商记录行一致"), ("类别", f"{SRC_CONS} → 品类分类(保洁/工程/办公/秩序/绿化耗材);{SRC_MAINT} →「维保类别」"), ("名称/合同名称", f"{SRC_PUR_DIR}\\2026年耗材汇总\\月度\\2026年度保洁耗材1-2月.xlsx →「耗材品类名称」;{SRC_MAINT} →「合同名称」"), ("数量 / 单位 / 单价 / 金额", f"{SRC_PUR_DIR}\\2026年耗材汇总\\月度\\2026年度保洁耗材1-2月.xlsx →「数量」「单价」「金额」"), ("合同年限", f"{SRC_MAINT} →「合同年限」"), ("月份/日期", f"{SRC_CONS} →「月份」;{SRC_FIX} →「采购日期」"), ("当前状态", f"{SRC_FIX} →「当前状态」(在用/闲置/报废/调拨)"), ("经办人工号", "员工信息.xlsx →「员工编码」;必填,用于追溯采购/维保/固定资产当事人(供应商行填登记人)"), ("经办人", "新增(融合):可读性核对列,由工号解析"), ("备注", "—"), ], notes=[ "一张表记录四类采购/维保业务,按「记录类型」区分,只填对应列:", "· 供应商:供应商名称、类别(项目编号/项目名称留空);", "· 维保合同:项目编号、供应商名称、类别、名称/合同名称、金额、合同年限、月份/日期;", "· 耗材采购:项目编号、供应商名称、类别、名称、数量、单位、单价、金额、月份/日期;", "· 固定资产:项目编号、名称、数量、单位、金额、月份/日期(采购日期)、当前状态。", "供应商名称全局唯一,同一供应商多项目采购时名称保持一致。", ], validations={1: ["供应商", "维保合同", "耗材采购", "固定资产"], 12: ["在用", "闲置", "报废", "调拨"]}, required_cols=[1, 2, 15], ) # 10. 检查记录 _make_file( "检查记录.xlsx", "检查记录", ["项目编号*", "项目名称(选填)", "检查类型", "检查日期", "检查得分(0-100)", "问题描述", "整改情况", "整改完成日期", "检查人工号*", "检查人(选填)", "备注"], [20, 26, 14, 14, 16, 40, 30, 14, 16, 12, 20], examples=[ ["XMSQ0102", "上海市青浦区图书馆", "品质检查", "2026-03-15", 92, "大厅地面清洁不及时", "已整改", "2026-03-20", "KWL2699005", "张三", "示例"], ], field_sources=[ ("项目编号", "关联「项目信息」表(必填)"), ("项目名称", "新增(融合):可读性核对列"), ("检查类型", "新增(分类):品质/安全/防汛/消防"), ("检查得分", f"{SRC_QC}(评估汇总表)→「各项目检查总得分/分项得分」"), ("检查日期", f"{SRC_QC} →「检查日期」;或 5-节前安全自查表 → 检查时间"), ("问题描述", f"{SRC_QC} →「检查存在的问题」;安全自查表 →「问题描述」"), ("整改情况 / 整改完成日期", f"{SRC_QC} →「整改完成情况(管理处填写)→ 整改情况/未完成」"), ("检查人工号", "员工信息.xlsx →「员工编码」;必填,用于关联人员节点避免重名"), ("检查人", "新增(融合):可读性核对列,由工号解析"), ("备注", "—"), ], notes=[ "一行 = 一次检查(品质/安全/防汛/消防等),用于问答项目品质与整改情况。", "得分无则留空;问题描述尽量具体,整改完成后填整改情况与完成日期。", ], validations={2: ["品质检查", "安全检查", "防汛检查", "消防检查", "满意度调查"]}, required_cols=[1, 9], ) print("模板已生成(CSV 格式):") for f in sorted(OUT_DIR.glob("*.csv")): print(f" {f.name}") if __name__ == "__main__": main()