"""字段映射模块 — 将 Excel 列名映射到页面 DOM 元素 ID。 所有中文名→DOM ID 的对应关系写死在 BUILTIN_FIELD_MAP 中。 config.json 的 field_mapping 用于追加/覆盖自定义映射。 """ import json from pathlib import Path from typing import Any # 内置字段映射:中文名 → 页面 DOM 元素 ID(写死在代码中) BUILTIN_FIELD_MAP: dict[str, str] = { # ── 业务字段 ── "单号": "waybillNo", "运单号": "waybillNo", "产品名称": "bizProductName", "客户名称": "senders", # ── 收件人 ── "收件人": "receiverLinker", "收件人手机": "receiverMobile", "收件地址": "receiverAddr", "收件邮编": "receiverPostcode", "收件人固话": "receiverFixtel", # ── 寄件人 ── "寄件人": "senderLinker", "寄件人手机": "senderMobile", "寄件地址": "senderAddr", "寄件邮编": "senderPostcode", "寄件人固话": "senderFixtel", # ── 货物 ── "重量": "realWeight", "内件品名": "reserved5", # ── 电商 / 支付 ── "电商平台": "ecommerceNo", "付款方式": "paymentMode", "证件类型": "consignorIdType", "保价金额": "insuranceAmount", "代收货款": "codAmount", # ── 系统保留字段(通常不需要在 Excel 中填写,只用默认值)── "运输类型": "transferType", "内件属性": "contentsAttribute", "件数": "quantity", "保价标志": "insuranceFlag", "回单标志": "receiptFlag", "代收标志": "codFlag", "投递方式": "deliverType", # ── 其他 ── "寄达地": "receiverArriveOrgName", "寄达地区划": "receiverDistrictNo", "备注": "senderNotes", } def load_config(config_path: str = "config.json") -> dict[str, Any]: """加载配置文件。""" # 支持开发环境和 PyInstaller 打包后的路径 paths_to_try = [ Path(config_path), Path(__file__).parent / config_path, Path.cwd() / config_path, ] # PyInstaller _MEIPASS import sys if getattr(sys, "frozen", False): paths_to_try.insert(0, Path(sys._MEIPASS) / config_path) for p in paths_to_try: if p.exists(): with open(p, "r", encoding="utf-8") as f: return json.load(f) raise FileNotFoundError(f"配置文件未找到: {config_path}") def get_field_mapping(config: dict) -> dict[str, str]: """获取 Excel 列名 → DOM ID 的映射(内置 + 配置覆盖)。""" mapping = dict(BUILTIN_FIELD_MAP) mapping.update(config.get("field_mapping", {})) return mapping def get_defaults(config: dict) -> dict[str, str]: """获取默认值(中文键 → 值)。""" return config.get("defaults", {}) def get_system_config(config: dict) -> dict[str, Any]: """获取系统配置。""" return config.get("system", {}) def get_timing_config(config: dict) -> dict[str, Any]: """获取延时配置。""" return config.get("timing", {}) def get_fixed_values(config: dict) -> dict[str, dict]: """获取固定值设置,返回 {字段名: {value, force}}。""" return config.get("fixed_values", {}) def get_fixed_value_str(fixed_values: dict[str, dict], field: str) -> str: """从固定值配置中提取字段的字符串值。""" return fixed_values.get(field, {}).get("value", "") # 中文显示名 → 系统内部编码(用于默认值/固定值的翻译) # 数据来源:data.har 抓包分析 CODE_MAP: dict[str, dict[str, str]] = { "电商平台": { "无": "WU", "菜鸟电子面单": "TAOBAOWAYBILL", "淘宝": "TAOBAO", "拼多多": "PINDUODUO", "电子面单": "DZMD", "大客户订单接口": "DKH", "云打印": "CLOUD", "批量导入": "IMPO", "客户端": "EMSRM", "公安部": "GAB", "电子返单": "DZFD", "仓库配送": "CKPS", "无": "WU", }, "付款方式": { "寄付": "1", "到付": "2", }, "证件类型": { "身份证": "01", }, "运输类型": { "陆运": "1", }, "内件属性": { "其他": "00", "身份证": "01", "录取通知书": "02", "法院专递": "03", "护照": "04", "通行证": "05", "签证": "06", "驾驶证": "07", "保险文书": "08", "银行票据": "09", "行驶证": "10", "交通违章通知书": "11", "纳税申报": "12", "到货通知书": "13", "公证书": "14", "学生档案": "15", "准考证": "16", "成绩单": "17", "药监批件": "18", "移动配送": "19", "劳动仲裁": "20", "合格证": "21", "健康证": "22", "火车票": "23", "房证": "24", "企业代码证": "25", "教材": "26", "福利彩票": "27", "病历": "28", "银企对账单": "29", "学位证书": "30", "车辆档案": "31", "交房通知书": "32", "车牌": "36", "信用卡": "41", "检察专递": "53", "法院专递回执": "54", }, "保价标志": { "不保价": "1", }, "回单标志": { "无回单": "1", }, "代收标志": { "不代收": "9", }, "投递方式": { "普通投递": "3", }, } def translate_value(excel_col: str, chinese_value: str) -> str: """将中文显示名翻译为系统内部编码(如 "寄付" → "1")。 如果该字段没有翻译表,或值已经是编码格式,直接返回原值。 """ if not chinese_value: return chinese_value mapping = CODE_MAP.get(excel_col, {}) return mapping.get(chinese_value, chinese_value) def reverse_translate(excel_col: str, code_value: str) -> str: """将系统编码翻译回中文显示名(如 "1" → "寄付")。""" if not code_value: return code_value mapping = CODE_MAP.get(excel_col, {}) for chinese, code in mapping.items(): if code == code_value: return chinese return code_value def resolve_field_value( row: dict[str, str], excel_col: str, defaults: dict[str, str], fixed_values: dict[str, str] = None, ) -> str: """解析字段值,优先级:固定值 > Excel > 默认值。结果自动翻译为系统编码。""" fixed_values = fixed_values or {} fixed = fixed_values.get(excel_col, "") if fixed: return translate_value(excel_col, fixed) value = row.get(excel_col, "").strip() if value: return translate_value(excel_col, value) return translate_value(excel_col, defaults.get(excel_col, ""))