certflow.config.models 源代码

"""配置数据模型

使用 Pydantic 定义配置数据结构,提供类型验证和自动补全.
"""

from __future__ import annotations

import tempfile
from typing import Any

from pydantic import BaseModel, Field, field_validator


class _StrictModel(BaseModel):
    """所有配置子模型的基类:extra=forbid(§15.3 阶段3 严格校验收官)。

    任何未在模型中声明的键,会在启动期 ConfigLoader.load()(内部以原始合并 dict
    构造 RootConfig)触发 ValidationError,从机制上杜绝「配置静默失效」——
    即键写错/漏建模却被 _cfg 读取、永远取默认值的隐性缺陷(见 STRICT_VALIDATION_AUDIT.md)。

    例外(不继承或覆盖为 allow):
    - UIConfig:作为 ui 段运行时兜底容器,保守保持 extra=allow,便于 ui.yaml 后续扩展;
      其顶层键的 forbid 校验由独立的 ``UIConfigModel``(ui_config.py,Phase 2.4 新增)
      在 ``UIConfig.load`` 加载期把关,二者分工:容器宽松、闸门严格。
    - RootConfig:顶层已于任务 2.3 闭环为 extra=forbid(ui.yaml 经 !include 并入的 12 个
      UI 顶层键已全部建模为宽松 dict/list 字段,由 forbid 闸门把关)。

    说明:前两批(feat/wf15-strict-forbid[-batch2])已显式开 forbid 的子模型,其自身
    model_config 与本基类一致(冗余但无害),保留以记录 4 个静默失效 bug 的修复历史。
    """

    model_config = {"extra": "forbid"}


[文档] class AppConfig(_StrictModel): """应用基础配置模型 定义应用程序的基本信息,包括名称、版本、组织等元数据. Attributes: name: 应用程序名称,默认为"CertFlow" version: 应用程序版本号,默认为"2.0.0" year: 版权年份,默认为2026 organization: 组织名称,默认为"CertFlow Team" debug: 是否启用调试模式,默认为False """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} name: str = "CertFlow" version: str = "2.0.0" year: int = 2026 organization: str = "CertFlow Team" debug: bool = False
class DatabasePaths(_StrictModel): """数据库路径配置模型 定义数据库文件的存储目录和文件名,以及调试库/基线库路径. Attributes: dir: 数据库文件所在目录,默认为"database" name: 数据库文件名,默认为"certflow.db" debug: 调试库路径,默认为"database/debug/certflow-debug.db" baseline_local: 本地私有基线库路径,默认为"database/baseline.db" baseline_sample: 匿名脱敏样本基线库路径(Git LFS),默认为"database/samples/baseline.sample.db" """ dir: str = "database" name: str = "certflow.db" debug: str = "database/debug/certflow-debug.db" baseline_local: str = "database/baseline.db" baseline_sample: str = "database/samples/baseline.sample.db" class TempPaths(_StrictModel): """临时目录配置模型 定义各类临时文件的存储子目录. Attributes: base: 临时文件根目录,默认为系统临时目录(tempfile.gettempdir(),云环境正确)。 本地开发若想在项目中观察临时文件,于 paths.local.yaml 写 paths.temp.base 覆盖为项目内相对/绝对目录即可(见 paths.local.yaml.example)。 excel: Excel临时文件目录,默认为"excel" reports: 报告临时文件目录,默认为"reports" images: 图片临时文件目录,默认为"images" scans: 扫描件临时文件目录,默认为"scans" """ base: str = tempfile.gettempdir() excel: str = "excel" reports: str = "reports" images: str = "images" scans: str = "scans"
[文档] class TemplatePaths(_StrictModel): """模板路径配置模型 定义各类模板文件的存储路径. Attributes: base: 模板文件根目录,默认为"data/templates/" certificate_chinese: 中文合格证模板路径 certificate_bilingual: 中英文合格证模板路径 certificate_russian: 俄文合格证模板路径 test_report_small: 试压报告模板(少)路径 test_report_medium: 试压报告模板(中)路径 quality_cert_file: 质保书模板路径 report_master: 报告母版工作簿路径(T6 配置化,原硬编码 data/xlsx/*.xlsx) """ base: str = "data/templates/" certificate_chinese: str = "data/templates/中文合格证模板.xlsx" certificate_bilingual: str = "data/templates/中英文合格证模板.xlsx" certificate_russian: str = "" test_report_small: str = "" test_report_medium: str = "" quality_cert_file: str = "" report_master: str = "data/xlsx/各种报告的xlsx文件模板.xlsx"
class ReportFolderConfig(_StrictModel): """项目文件夹命名配置(逐字复用 VBA Mod_GCreatFloder.新建文件夹,蓝图 §7.2) 全部由 config.yaml 驱动,后期调整归档目录结构只改 yaml、不搜改代码: pattern: 目录相对 root 的命名模板,占位符 {ym}/{rq}/{customer}/{project} tokens: 占位符求值模板(str.format,可用 {year}{month:02d}{day:02d}) empty_project_placeholder: 项目名称为空时的兜底文本 """ pattern: str = "{ym}计划项目资料/{rq}_{customer}_{project}项目资料" tokens: dict[str, str] = Field(default_factory=dict) empty_project_placeholder: str = "【空白项目名称】" class ReportArchiveConfig(_StrictModel): """报告归档配置(VBA 风格文件夹 + 电子印章,蓝图 §7) Attributes: root: 归档根目录(VBA 的 D:\\F\\备份\\...\\质量证明书\\ 统一为可配置单根) folder: 项目文件夹命名配置(pattern/tokens/兜底文本,yaml 驱动) seal_default: 全局默认电子印章(PNG/透明底);空字符串则不嵌章 seal: 印章在 PDF 上的叠加位置(page=-1 末页;x/y/width 单位 PDF 点) """ root: str = "output/项目资料" folder: ReportFolderConfig = Field(default_factory=ReportFolderConfig) seal_default: str = "" seal: dict[str, Any] = Field(default_factory=dict)
[文档] class PathsConfig(_StrictModel): """路径配置集合模型 聚合所有文件路径相关的配置,包括数据库、临时文件、日志等路径. Attributes: database: 数据库路径配置 temp: 临时文件路径配置 logs: 日志文件目录,默认为"logs" resources: 资源文件目录,默认为"resources" templates: 模板文件路径配置 sales_plan: 销售计划文件路径映射(V2) qualified_list: 合格清单文件路径映射(V2) nameplate_db: 铭牌数据库路径映射(V2) quality_cert: 质量证书路径映射(V2) transfer_docs: 交接文档路径映射(V2) backup: 备份文件路径映射(V2) output: 输出文件路径映射(V2) excel_layout: Excel布局配置(V2) images: 图片文件路径映射(V2) """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} database: DatabasePaths = Field(default_factory=DatabasePaths) temp: TempPaths = Field(default_factory=TempPaths) logs: str = "logs" resources: str = "resources" templates: TemplatePaths = Field(default_factory=TemplatePaths) # V2 新增路径 sales_plan: dict[str, str] | None = None qualified_list: dict[str, str] | None = None nameplate_db: dict[str, str] | None = None quality_cert: dict[str, str] | None = None transfer_docs: dict[str, str] | None = None backup: dict[str, str] | None = None output: dict[str, str] | None = None excel_layout: dict[str, Any] | None = None images: dict[str, str] | None = None fonts: dict[str, Any] | None = None # 报告归档(VBA 风格文件夹 + 电子印章,蓝图 §7) report_archive: ReportArchiveConfig = Field(default_factory=lambda: ReportArchiveConfig()) report_templates_dir: str = "templates/reports"
class ColumnMappingConfig(_StrictModel): """列映射配置模型 定义Excel列名到数据字段的映射关系,支持直接映射和别名映射. Attributes: direct: 直接列映射,键为数据字段名,值为Excel列名 aliases: 列别名映射,键为Excel列名,值为可能的别名列表 """ direct: dict[str, str] = Field(default_factory=dict) aliases: dict[str, list[str]] = Field(default_factory=dict) class ValidRowCheck(_StrictModel): """有效行检查配置模型 定义用于判断Excel行是否为有效数据的检查规则. Attributes: enabled: 是否启用有效行检查,默认为True key_fields: 用于判断行有效性的关键字段列表 """ enabled: bool = True key_fields: list[str] = Field(default_factory=list)
[文档] class ExcelReadConfig(_StrictModel): """Excel 读取配置模型 定义 Excel 文件读取时的基本参数. Attributes: sheet_name: 工作表索引或名称,默认为 0 header_row: 表头行号(0-indexed),默认为 1 skip_rows: 跳过的行数,None 表示不跳过 use_cols: 使用的列范围,None 表示全部 """ sheet_name: str | int = 0 header_row: int = 1 skip_rows: int | None = None use_cols: str | None = None
[文档] class HeaderDetectionConfig(_StrictModel): """表头自动检测配置模型 定义表头检测的启停和匹配规则. Attributes: enabled: 是否启用表头自动检测 keywords: 用于匹配表头的关键词列表 max_rows: 最大扫描行数 """ enabled: bool = True keywords: list[str] = Field(default_factory=list) max_rows: int = 20
class PnConvertConfig(_StrictModel): """公称压力 Lb→MPa 换算配置(#30 P0 DN/PN 字典 DB 化) 替代 VBA 型号压力转换表的 Lb→MPa 硬规则(150Lb=2 / 300Lb=5 / ...), 全部 yaml 化,后期只改配置不搜改代码。键为 LB 磅级(字符串整数),值为 MPa。 """ lb_to_mpa: dict[str, float] = Field( default_factory=lambda: { "150": 2.0, "300": 5.0, "600": 10.0, "800": 13.0, "900": 15.0, "1500": 25.0, "2500": 42.0, } ) keep_as_string: list[str] = Field(default_factory=lambda: ["2.5Kpa", "-----", "/", "*Lb"]) class ImportGateConfig(_StrictModel): """导入门控配置(#30 P1 导入门控,yaml 驱动跳过/隔离无单号行) 替代 VBA「要货单号='假'/空 → 整行跳过」逻辑,全配置驱动: - enabled: 总开关 - order_identity_fields: 现代要货单号来源字段(2025+ 行凭此逃逸门控,如 ["sales_order_no", "production_order_no"]) - legacy_field: legacy 要货单号来源字段(pre-2025 行凭 plan_no(计划单号4位) 逃逸门控,VBA 即依 计划单号+计划日期年月 派生要货单号) - skip_when_missing: 兼容旧名(=order_identity_fields 别名) - mode: skip=直接丢弃 / isolate=隔离到待复核(返回 gated 列表)/ warn=仍导入但标黄 - match_keys: 门控匹配维度(隔离时用于与既有行归并的键,预留) 门控语义(业务正确):仅当「全部订单身份字段(含 legacy_field)均缺失」时, 该行才视为「无单号」无效行被门控;任一身份字段非空即逃逸(不误杀 pre-2025 行)。 """ enabled: bool = False order_identity_fields: list[str] = Field(default_factory=list) legacy_field: str = "" skip_when_missing: list[str] = Field(default_factory=list) # 兼容别名 mode: str = "isolate" # skip | isolate | warn match_keys: list[str] = Field(default_factory=list)
[文档] class DualFieldMappingConfig(_StrictModel): """双字段映射配置(合同信息 ↔ 合格证打印信息),蓝图 §4.2.1。 Attributes: pairs: contract→cert 字段对列表,每项 {contract, cert} import_mode: copy / override / lazy(默认 lazy,不破坏既有行为) - copy:合同值同时写入 cert_*(杜绝"改合同静默跟随"风险) - override:仅当 Excel 显式提供 cert 列时才写 cert_* - lazy:保持现状(cert_* 留空,打印时回退合同值) """ pairs: list[dict[str, str]] = Field(default_factory=list) import_mode: str = "lazy"
[文档] class SalesPlanConfig(_StrictModel): """销售计划配置模型 定义销售计划Excel文件的解析规则,包括列映射、表头位置等. Attributes: excel_config: Excel 读取配置 column_mapping: 列映射配置 header_detection: 表头自动检测配置 styled_import_columns: 带格式导入时保留的列名列表 header_row: 表头所在行号(从1开始),默认为2 data_start_row: 数据起始行号(从1开始),默认为3 required_fields: 必填字段列表 valid_row_check: 有效行检查配置 pn_convert: 公称压力 Lb→MPa 换算(#30 P0 DN/PN 字典 DB 化) import_gate: 导入门控(#30 P1 无单号行跳过/隔离/标黄) dual_field_mapping: 双字段映射(合同信息 ↔ 合格证打印信息),蓝图 §4.2.1 """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} excel_config: ExcelReadConfig = Field(default_factory=ExcelReadConfig) column_mapping: ColumnMappingConfig = Field(default_factory=ColumnMappingConfig) header_detection: HeaderDetectionConfig | None = None styled_import_columns: list[str] = Field(default_factory=list) header_row: int = 2 data_start_row: int = 3 required_fields: list[str] = Field(default_factory=list) valid_row_check: ValidRowCheck = Field(default_factory=ValidRowCheck) pn_convert: PnConvertConfig = Field(default_factory=PnConvertConfig) import_gate: ImportGateConfig = Field(default_factory=ImportGateConfig) # 双字段映射(合同信息 ↔ 合格证打印信息),蓝图 §4.2.1 dual_field_mapping: DualFieldMappingConfig = Field(default_factory=DualFieldMappingConfig)
[文档] class SuffixRule(_StrictModel): """合格证后缀规则模型 根据关键词匹配规则生成证书编号后缀. Attributes: field: 可选,指定匹配的字段名 keywords: 触发该后缀的关键词列表 suffix: 匹配成功时使用的后缀字符串 exclude: 可选,排除的关键词列表,匹配时不生成后缀 """ field: str | None = None keywords: list[str] suffix: str exclude: list[str] | None = None
class CertificateModeRule(_StrictModel): """编码模式判定规则(步骤 6.2) 按 when_field 字段值命中 keywords 中任一关键词 → 采用 mode(number_model). Attributes: when_field: 参与判定的字段名(如 customer);兼容旧键 field field: when_field 的兼容别名 keywords: 触发该模式的关键词列表 mode: 命中时采用的编码模式数值(复用 printer.numbering_modes) sn_kks_position: 双编码位置约定(仅 mode 5/6 双编码有意义,对齐 VBA ar(2,8) 单元格),取值为 "B12单元格为产品编号,B13单元格为KKS编码" 或 "B12单元格为KKS编码,B13单元格为产品编号";空串=默认不互换。 """ when_field: str | None = None field: str | None = None keywords: list[str] = Field(default_factory=list) mode: int = 0 sn_kks_position: str = "" class CertificateNumberingConfig(_StrictModel): """合格证编号时机与编码模式配置(步骤 6:蓝图 §4.4) Attributes: timing: 编号时机,on_demand(默认)/ on_import range_regex: 范围编码解析正则,空则用内置默认 default_mode: 未命中任何 mode 规则时的默认编码模式 modes: 编码模式判定规则列表 """ timing: str = "on_demand" range_regex: str = "" default_mode: int = 0 modes: list[CertificateModeRule] = Field(default_factory=list) # 自动续号(默认 True):打印视图编号组在「目标年月」变化时,自动把「起始」 # 填为该月已用最大流水 + 1;关闭则默认手动填写(起始流水手填覆盖)。 auto_continue: bool = True # 分隔符双约定(§5.7.2-B / 维度5):编号阶段用 separator_stage(默认 "---"), # 保存清单/写证用 separator_list(默认 "-")。对齐 VBA:E2 填 G 列用 "-", # 模块20 批量打印生成 "---" 并在写清单时替换为 "-"。 separator_stage: str = "---" separator_list: str = "-" # 前缀(编号年月)来源(§5.7.2-G / 维度15): # now = datetime.now() 实时年月(默认,现状语义) # plan_date = 取 SalePlan.plan_date 的年月(=计划年月) # shipped_date = 取 SalePlan.shipped_date 的年月(=生产发货年月,最贴近 VBA 语义) # 注:manual 由 prefix_override 显式覆盖,不在此枚举。 prefix_source: str = "now" # 军工三位流水前缀(§5.7.2-D / 维度13,mode:7):无 V+YYMM 的军工前缀, # 自动编号时用作三位流水前缀(如 "JG" → JG001A)。手动编号由调用方传 prefix。 military_prefix: str = "JG" # 自动计算口径压力开关(§5.7.2-E / 维度8,对齐 VBA 模块工作表 G11): # true = 打印前自动从型号解析口径(DN)/压力(PN) 并预填(现状,默认); # false = 关闭自动推算,仅用已存值、不就口径/压力缺失弹补充对话框。 # 默认 true 保持与既有行为零差异。 auto_calc_dn_pn: bool = True class InspectorIdConfig(_StrictModel): """检验工号默认配置(配置驱动,BUG-006 I / H3) Attributes: enabled: 是否启用自动填充检验工号(默认 True) defaults: 按模板语言族映射默认工号(如 全中文→检5,其余→No 5) fallback: 未匹配语言族时的默认工号 """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} enabled: bool = True defaults: dict[str, str] = Field(default_factory=dict) fallback: str = "检5" class PrintDuplicateCheckConfig(_StrictModel): """打印存库重复检测配置(§5.7.2-C / 维度11,对齐 VBA「大连大高重复跳过存库」)。 Attributes: enabled: 是否启用检测(默认 False → 零差异,所有客户照常落库) customers: 触发去重的客户关键词列表(DingHuoDanWei 命中其一即检测) compare_fields: 比对的 PrintLog 字段集(匹配数 = 字段值相等个数) threshold: 最小匹配字段数阈值(≥ 此值判为重复,跳过落库) """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} enabled: bool = False customers: list[str] = Field(default_factory=list) compare_fields: list[str] = Field(default_factory=list) threshold: int = 0
[文档] class CertificateConfig(_StrictModel): """合格证配置模型 定义合格证编号的生成规则. Attributes: prefix: 证书编号前缀,默认为"CERT" date_format: 日期格式字符串,默认为"%Y%m%d" format_template: 编号格式模板,支持{prefix}、{date}、{seq}占位符 suffix_rules: 后缀匹配规则列表 defaults: 默认值字典 numbering: 编号时机与编码模式配置(步骤 6) """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} prefix: str = "CERT" date_format: str = "%Y%m%d" format_template: str = "{prefix}{date}{seq:04d}" suffix_rules: list[SuffixRule] = Field(default_factory=list) defaults: dict[str, Any] = Field(default_factory=dict) numbering: CertificateNumberingConfig = Field(default_factory=CertificateNumberingConfig) # 出厂日期年月来源(BUG-006 J,配置驱动): # sync_numbering_ym(默认)= 同步产品编号年月;current_ym = 取当前年月 issue_date_source: str = "sync_numbering_ym" # 检验工号默认(配置驱动,默认启用) inspector_id: InspectorIdConfig = Field(default_factory=InspectorIdConfig) # 打印存库重复检测(§5.7.2-C / 维度11,默认关闭 → 零差异) print_duplicate_check: PrintDuplicateCheckConfig = Field( default_factory=PrintDuplicateCheckConfig )
[文档] class ImportDeduplicationConfig(_StrictModel): """导入去重配置模型 定义数据导入时的重复检测和处理策略. Attributes: strategy: 去重策略,"skip"表示跳过重复项,"overwrite"表示覆盖 check_within_file: 是否检查文件内重复,默认为True check_against_db: 是否检查与数据库重复,默认为True unique_key_fields: 用于判断唯一性的字段列表 update_on_duplicate: 重复时是否检测变更并更新,默认为True monitored_fields: 监控变更的字段列表 duplicate_handling: 重复处理扩展配置(V2) unique_key_generation: 唯一键生成配置(V2) field_normalization: 字段规范化配置(V2) """ # §15.3 阶段3:严格校验——未建模键将在启动期报 ValidationError,防止 on_collision 类静默失效复现 model_config = {"extra": "forbid"} strategy: str = "skip" check_within_file: bool = True check_against_db: bool = True unique_key_fields: list[str] = Field(default_factory=list) update_on_duplicate: bool = True monitored_fields: list[str] = Field(default_factory=list) # 批内撞键(同 unique_key)处理策略:quarantine(隔离,默认) | merge_max(取大数量) | merge_sum(数量求和) # 建模后由 cfg("import_deduplication.on_collision") 读取,修复此前被 extra=ignore 静默丢弃的失效配置 on_collision: str = "quarantine" # V2 新增: 扩展去重配置 duplicate_handling: dict[str, Any] | None = None unique_key_generation: dict[str, Any] | None = None field_normalization: dict[str, Any] | None = None
[文档] class DatabaseConfig(_StrictModel): """数据库配置模型 定义数据库连接参数和行为. Attributes: type: 数据库类型,默认为"sqlite" echo: 是否打印SQL语句日志,默认为False pool_size: 数据库连接池大小,默认为5 max_overflow: 连接池最大溢出连接数,默认为10 """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} type: str = "sqlite" echo: bool = False pool_size: int = 5 max_overflow: int = 10
[文档] class LoggingConfig(_StrictModel): """日志配置模型 定义日志输出格式、轮转策略等参数. Attributes: level: 日志级别,可选值为DEBUG、INFO、WARNING、ERROR、CRITICAL file: 日志文件路径,默认为"logs/certflow.log" format: 日志格式字符串 rotation: 日志文件轮转条件,如"10 MB"表示10MB轮转 retention: 日志保留时间,如"30 days"表示保留30天 compression: 日志压缩格式,默认为"zip" debug_modules: DEBUG 黑名单列表,支持模块名或"模块名:函数名"格式 """ # §15.3 阶段3:严格校验(收紧:此前为 allow,探测确认无未建模子键) model_config = {"extra": "forbid"} level: str = "INFO" file: str = "logs/certflow.log" format: str = "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}" rotation: str = "10 MB" retention: str = "30 days" compression: str = "zip" debug_modules: list[str] = Field(default_factory=list)
class WindowConfig(_StrictModel): """窗口配置模型 定义应用程序主窗口的外观和行为. Attributes: title: 窗口标题,默认为"CertFlow - 证书管理系统" min_width: 窗口最小宽度,默认为1000像素 min_height: 窗口最小高度,默认为618像素 default_width: 窗口默认宽度,默认为1200像素 default_height: 窗口默认高度,默认为800像素 """ title: str = "CertFlow - 证书管理系统" min_width: int = 1000 min_height: int = 618 default_width: int = 1200 default_height: int = 800 class TableConfig(_StrictModel): """表格配置模型 定义数据表格的显示行为. Attributes: alternating_row_colors: 是否使用交替行颜色,默认为True sorting_enabled: 是否启用排序功能,默认为True stretch_last_section: 是否拉伸最后一列,默认为True """ alternating_row_colors: bool = True sorting_enabled: bool = True stretch_last_section: bool = True class StatusBarConfig(_StrictModel): """状态栏配置模型 定义状态栏的显示内容. Attributes: ready_message: 就绪状态显示的消息,默认为"✅ 系统就绪" """ ready_message: str = "✅ 系统就绪"
[文档] class UIConfig(_StrictModel): """UI配置集合模型 聚合所有用户界面相关的配置. Attributes: window: 窗口配置 table: 表格配置 status_bar: 状态栏配置 query_page: 查询页面配置(视图模板、操作符、字段映射等) """ # §15.3 阶段3:UI 段经 ui.yaml !include 并入大量未建模顶层键(main_window/title_bar/ # nav_buttons/log_page/print_page/styles/welcome_page 等,见审计报告 §3),UIConfig 作为 # 该段兜底容器须保持 allow,不能开 forbid,否则整体加载崩溃。 model_config = {"extra": "allow"} window: WindowConfig = Field(default_factory=WindowConfig) table: TableConfig = Field(default_factory=TableConfig) status_bar: StatusBarConfig = Field(default_factory=StatusBarConfig) query_page: dict = Field(default_factory=dict)
[文档] class ColorMappingConfig(_StrictModel): """颜色映射配置模型 定义状态和优先级到颜色的映射关系. Attributes: status_colors: 状态到颜色的映射字典 priority_colors: 优先级到颜色的映射字典 vba_colors: VBA颜色索引到颜色的映射(V2) font_color_to_shipping: 字体颜色到发货状态的映射(V2) bg_color_to_status: 背景颜色到状态的映射(V2) theme_font_colors: THEME 字体颜色到状态的映射(V3) font_colors: 字体颜色 hex 字符串映射 bg_colors: 背景颜色 hex 字符串映射 """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} status_colors: dict[str, str] = Field(default_factory=dict) priority_colors: dict[str, str] = Field(default_factory=dict) # V2 新增: VBA 颜色映射 vba_colors: dict[int, str] | None = None font_color_to_shipping: dict[int, str] | None = None bg_color_to_status: dict[int, str] | None = None # V3 新增: THEME 颜色和 hex 颜色映射 theme_font_colors: dict[str, str] | None = None font_colors: dict[str, str] | None = None bg_colors: dict[str, str] | None = None
# ============================================================ # V2 新增配置模型 # ============================================================
[文档] class NumberingSuffixRule(_StrictModel): """编号后缀规则模型(V2新增) 根据字段值或关键词匹配规则生成编号后缀. Attributes: field: 用于匹配的字段名 keywords: 触发该后缀的关键词列表 suffix: 匹配成功时使用的后缀字符串 exclude: 排除的关键词列表,匹配时不生成后缀 """ field: str | None = None keywords: list[str] = Field(default_factory=list) suffix: str = "" exclude: list[str] | None = None
[文档] class NumberingConfig(_StrictModel): """编号规则配置模型(V2新增) 定义V2版本的自动编号生成规则. Attributes: prefix: 编号前缀,默认为"V" format: 编号格式模板 suffixes: 后缀映射字典 auto_number_mode: 自动编号模式配置 suffix_rules: 后缀规则列表 no_cert_categories: 免编号品类关键词(螺栓/密封圈等免出证铭牌件) yellow_skip_enabled: 是否按源表黄底(65535)跳过编号(默认 False) """ prefix: str = "V" format: str = "{prefix}{year}{month}{seq:03d}{suffix}" suffixes: dict[str, str] = Field(default_factory=dict) auto_number_mode: dict[str, Any] | None = None suffix_rules: list[NumberingSuffixRule] = Field(default_factory=list) # 维度16/H:对齐 VBA 黄底跳过语义——导入期命中免编号品类的记录 # needs_numbering=False,编号(auto/manual)时跳过以压低流水位数。 no_cert_categories: list[str] = Field(default_factory=list) yellow_skip_enabled: bool = False
[文档] class DuplicateCheckConfig(_StrictModel): """重复检查配置模型(V2新增) 定义数据重复检查的字段列表. Attributes: fields: 用于重复检查的字段名列表 """ fields: list[str] = Field(default_factory=list)
[文档] class UniqueKeyField(_StrictModel): """唯一键字段模型(V2新增) 定义构成唯一键的字段及其约束. Attributes: name: 字段名称 required: 该字段是否为必填,默认为False """ name: str required: bool = False
class UniqueKeyTier(_StrictModel): """去重身份键分层配置(§9 落地待办①) 每一层描述一组用于生成去重身份键的字段。modern_2025 用于 2025+ 双号齐全, legacy 用于 pre-2025 降级。字段集不含 quantity(分批发货靠 _detect_changes 取大合并)。 """ description: str = "" fields: list[str] = Field(default_factory=list)
[文档] class UniqueKeyConfig(_StrictModel): """唯一标识规则配置模型(V2新增) 定义唯一键的生成规则. Attributes: separator: 字段值连接符,默认为"|" date_to_serial: 是否将日期转换为序列号,默认为True fields: 构成唯一键的字段列表(V2 旧格式,兼容保留) key_field_fallbacks: 唯一键字段的回退映射 tiers: 去重身份键分层字段(§9 落地待办①,单一真相源) require_numbered: 仅匹配已编号行才判重(565 行语义,§9 待办①) """ separator: str = "|" date_to_serial: bool = True fields: list[UniqueKeyField] = Field(default_factory=list) key_field_fallbacks: dict[str, list[str]] | None = None tiers: dict[str, UniqueKeyTier] | None = None require_numbered: bool = False
[文档] class GroupingNumberingConfig(_StrictModel): """分组序号配置""" use_global_prefix: bool = True prefix_format: str = "G{:03d}" seq_format: str = "{:03d}" separator: str = "-" full_seq_field: str = "group_seq" group_index_field: str = "_group_index" group_key_field: str = "_group_key"
[文档] class GroupingConfig(_StrictModel): """分组配置(V3新增) 第一层分组:按业务键分组,生成组内序号 """ group_keys: list[str] = Field(default_factory=list) group_keys_no_project: list[str] = Field(default_factory=list) numbering: GroupingNumberingConfig = Field(default_factory=GroupingNumberingConfig)
[文档] class SortingKey(_StrictModel): """排序键配置(V3新增)""" field: str order: str = "asc"
[文档] class SortingConfig(_StrictModel): """排序配置(V3新增) 第二层排序:组内按产品键排序 """ keys: list[SortingKey] = Field(default_factory=list)
[文档] class PriorityRulesConfig(_StrictModel): """优先级规则配置模型(V2新增) 定义基于金额的优先级判定规则和颜色. Attributes: high_threshold: 高优先级阈值,金额大于此值为高优先级,默认为10000 medium_threshold: 中优先级阈值,金额大于此值为中优先级,默认为5000 high_label: 高优先级标签,默认为"高" medium_label: 中优先级标签,默认为"中" low_label: 低优先级标签,默认为"低" high_color: 高优先级颜色(十六进制),默认为"#e74c3c" medium_color: 中优先级颜色(十六进制),默认为"#f39c12" low_color: 低优先级颜色(十六进制),默认为"#27ae60" """ high_threshold: int = 10000 medium_threshold: int = 5000 high_label: str = "高" medium_label: str = "中" low_label: str = "低" high_color: str = "#e74c3c" medium_color: str = "#f39c12" low_color: str = "#27ae60"
class ExportAccessConfig(_StrictModel): """Access 导出开关配置 Attributes: enabled: 是否启用 Access 导出(需安装 pyodbc + Access ODBC 驱动) """ # §15.3 阶段3:严格校验 model_config = {"extra": "forbid"} enabled: bool = False
[文档] class ExportConfig(_StrictModel): """导出配置模型(V2新增) 定义数据导出的格式和行为. Attributes: hyperlink_column: 超链接所在列号(从1开始),默认为44 hyperlink_ref_prefix: 超链接引用前缀,默认为"AR" hyperlink_width: 超链接列宽度,默认为20字符 summary: 汇总导出配置 access: Access 导出开关(export.access.enabled) """ # §15.3 阶段3:严格校验——未建模键将在启动期报 ValidationError,防止 export.access 类静默失效复现 model_config = {"extra": "forbid"} hyperlink_column: int = 44 hyperlink_ref_prefix: str = "AR" hyperlink_width: int = 20 summary: dict[str, Any] | None = None # 建模后由 cfg("export.access.enabled") 读取,修复此前被 extra=ignore 静默丢弃导致 Access 导出无法开启的失效配置 access: ExportAccessConfig | None = None
class FieldFallbackConfig(_StrictModel): """字段回退链配置模型(V2新增) 占位模型,实际使用Dict[str, List[str]]表示字段回退关系. """ pass
[文档] class ImportMappingConfig(_StrictModel): """数据导入列映射配置模型(V2新增) 定义Excel导入时的预处理、列映射和默认值. Attributes: preprocessor: 预处理器配置 column_mapping: 列映射规则列表 default_values: 默认值映射 """ preprocessor: dict[str, Any] | None = None column_mapping: list[dict[str, Any]] | None = None default_values: dict[str, str] | None = None
[文档] class SalesImporterConfig(_StrictModel): """销售计划导入器配置模型(V2新增) 定义销售计划Excel导入的字段映射和颜色列配置. Attributes: field_mapping: 字段映射字典,键为Excel列名,值为数据字段名 color_columns: 颜色列配置 selection_info_columns: 选择信息列列表 """ field_mapping: dict[str, str] = Field(default_factory=dict) color_columns: dict[str, Any] | None = None selection_info_columns: list[str] | None = None
[文档] class VBAImportConfig(_StrictModel): """VBA导入逻辑配置模型(V2新增) 定义VBA导入功能的文件路径、字段映射和重复检查规则. Attributes: sales_plan_files: 销售计划文件路径映射 qualified_list: 合格清单文件路径映射 field_mapping: 字段映射字典 color_mapping: 颜色映射配置 duplicate_check_fields: 重复检查字段列表 """ sales_plan_files: dict[str, str] | None = None qualified_list: dict[str, str] | None = None field_mapping: dict[str, str] = Field(default_factory=dict) color_mapping: dict[str, Any] | None = None duplicate_check_fields: list[str] | None = None
[文档] class PrintLayoutConfig(_StrictModel): """打印布局配置模型 定义打印坐标、偏移和字体大小. Attributes: label_x: 标签 X 坐标 value_x: 值 X 坐标 start_y: 起始 Y 坐标 line_spacing: 行间距 font_size: 字体大小 x_offset: 打印机物理偏移修正 (mm) y_offset: 打印机物理偏移修正 (mm) """ label_x: float = 3 value_x: float = 20 start_y: float = 22 line_spacing: float = 6.5 font_size: float = 9 x_offset: float = 14 y_offset: float = 0
[文档] class PrintFontConfig(_StrictModel): """打印字体配置模型 Attributes: name: 字体名称 weight: 字体粗细 """ name: str = "SimSun" weight: int = 400
[文档] class PrintFieldConfig(_StrictModel): """打印字段配置模型 Attributes: label: 字段标签 key: 字段键名 offset: 偏移量 """ label: str key: str offset: int = 0
[文档] class TestReportConfig(_StrictModel): """试压报告配置模型(V2新增) 定义试压报告的相关配置. Attributes: company_name: 公司名称 form_code: 表单代码 """ company_name: str = "" form_code: str = ""
[文档] class PrinterConfig(_StrictModel): """打印机配置模型(V2新增) 定义默认打印机设置. Attributes: default: 默认打印机名称 """ default: str = ""
[文档] class EnvironmentConfig(_StrictModel): """环境信息配置模型(V2新增) 定义运行时环境信息,支持环境变量替换. Attributes: computer_name: 计算机名称,支持${COMPUTERNAME:Unknown}语法 username: 用户名,支持${USERNAME:Unknown}语法 """ computer_name: str = "${COMPUTERNAME:Unknown}" username: str = "${USERNAME:Unknown}"
[文档] class ColorsConfig(_StrictModel): """颜色常量值配置模型(V2新增) 定义VBA中使用的颜色常量值. Attributes: yellow: 黄色的RGB整数值,默认为65535 blue: 蓝色的RGB整数值,默认为16711680 red: 红色的RGB整数值,默认为255 green: 绿色的RGB整数值,默认为65280 light_blue: 浅蓝色的RGB整数值,默认为15773696 """ yellow: int = 65535 blue: int = 16711680 red: int = 255 green: int = 65280 light_blue: int = 15773696
[文档] class CompletedOrdersBackfillConfig(_StrictModel): """已完成工单回填配置模型 定义从"已完成工单"Excel的月份工作表中读取"供货类型"字段并回填到数据库的规则。 核心设计: - 只处理月份工作表(2026-01~2026-12) - 按字段名称(列标题)匹配,不依赖列号/列字母 - 通过 production_order_no 匹配(同一生产令号所有记录回填相同值) """ file_path: str = "temp/excel/已完成工单【202601--202612】.xlsx" match_field: str = "生产令号" # Excel 中用于匹配的列名 source_field: str = "供货类型" # Excel 中要读取的源字段列名 db_match_field: str = "production_order_no" # DB 匹配字段 db_target_field: str = "supply_type" # DB 目标字段 overwrite_existing: bool = False backup_before_update: bool = True backup_suffix: str = "_before_supply_type_backfill"
# ============================================================ # 生产状态配置模型 # ============================================================
[文档] class ProductionStatusUILabel(_StrictModel): """生产状态 UI 标签模型""" icon: str = "" label: str = ""
[文档] class ProductionStatusAutoUpgradeRule(_StrictModel): """自动升级规则模型 定义文档完成后自动升级生产状态的规则,按顺序匹配,命中即停止. condition 是 Python 表达式,可用变量: progress_percent, is_ready_to_ship, production_status. """ condition: str set_to: str | None = None set_all_docs_done: bool | None = None
[文档] class ProductionStatusInferenceRule(_StrictModel): """状态推断规则模型 从 execution_status 自由文本中通过正则匹配推断生产状态. """ patterns: list[str] set_to: str
[文档] class ProductionStatusUIConfig(_StrictModel): """生产状态 UI 显示配置""" show_raw_execution_tooltip: bool = True show_icon_for_inferred: bool = True inferred_icon: str = "📋"
[文档] class ProductionStatusContextMenu(_StrictModel): """生产状态右键菜单配置""" view_raw_execution: dict[str, Any] | None = None
[文档] class ProductionStatusConfig(_StrictModel): """生产状态配置模型 所有状态值、图标、流转规则、自动升级规则均由此模型定义, 新增状态只需修改 config.yaml,无需改动任何代码. """ # §15.3 阶段3:严格校验——未建模键将在启动期报 ValidationError,防止 shipped_actions 类静默失效复现 model_config = {"extra": "forbid"} values: list[str] = Field(default_factory=list) default: str = "待生产" ui_labels: dict[str, ProductionStatusUILabel] | None = None transitions: dict[str, list[str]] | None = None auto_upgrade: list[ProductionStatusAutoUpgradeRule] | None = None inference_rules: list[ProductionStatusInferenceRule] | None = None query_keywords: dict[str, str] | None = None ui: ProductionStatusUIConfig | None = None context_menu: ProductionStatusContextMenu | None = None # 已发货处理(三层数据生命周期)的归档/导出配置,由 ui_config 经 # _pscfg("production_status.shipped_actions") 读取;建模后修复此前被 extra=ignore # 静默丢弃导致「已发货」菜单回退硬编码默认值的问题 shipped_actions: dict[str, Any] | None = None
# ============================================================ # ID 生成器配置模型 # ============================================================
[文档] class IdGeneratorConfig(_StrictModel): """唯一键生成策略配置模型 定义用于生成数据记录唯一键的字段组合和空值标记前缀. """ empty_marker_prefix: str = "【空白" new_data_fields: list[str] = Field(default_factory=list) old_data_fields: list[str] = Field(default_factory=list)
# ============================================================ # 导入配置模型 # ============================================================
[文档] class ImportColumnConfig(_StrictModel): """导入列配置模型""" field: str label: str type: str | None = None required: bool = False
[文档] class ImportViewConfig(_StrictModel): """导入视图配置模型""" name: str = "" icon: str = "" required_fields: list[str] = Field(default_factory=list) columns: list[ImportColumnConfig] | None = None
[文档] class ImportConfig(_StrictModel): """导入配置模型(与 QueryView 风格一致)""" default_strategy: str = "smart" auto_save: bool = True views: dict[str, ImportViewConfig] | None = None
[文档] class ImportPlaceholderConfig(_StrictModel): """导入期占位目录配置(B0-4 — 批次0 B-CreateDIR/F 已定稿) 决策(2026-07-14):测试期整表批量导入会在测试机泛滥生成大量空订单目录, 故改为配置驱动开关、默认关闭。 Attributes: create_placeholder_dirs: 是否恢复 VBA 式导入期按订单组预建占位项目文件夹。 False(默认):导入只写 SQLite,绝不碰磁盘;下游写文件时由写端 os.makedirs(parents=True, exist_ok=True) 惰性建目录。 True:导入期按订单组(计划日期+订货单位+项目名称)预建空项目资料文件夹, 命名统一沿用 paths.report_archive.folder 的 pattern/tokens/兜底文本。 """ # §15.3 阶段3:严格校验——未建模键将在启动期报 ValidationError,防止 skip_confirm_when_no_conflict 类静默失效复现 model_config = {"extra": "forbid"} create_placeholder_dirs: bool = False # 0 冲突/0 隔离时跳过确认对话框,直接导入并弹一次完成提示(蓝图 §4.1.3) # 建模后由 cfg("import.skip_confirm_when_no_conflict") 读取,修复此前被 extra=ignore 静默丢弃的失效配置 skip_confirm_when_no_conflict: bool = True
class BomImportConfig(_StrictModel): """BOM 导入控件配置(配置驱动 UI 初始态) 对应 ``BomImportWidget``(计划导入页的「BOM导入(目录扫描)」标签页)。 Attributes: default_folder: 材料清单目录默认值(绝对路径,或含 ``${ENV:default}``)。 留空则 UI 不预填,用户须点「浏览」选择。支持环境变量替换。 default_mode: 默认导入模式,决定 UI 打开时预选的单选按钮,取值须为 ``clear`` / ``append`` / ``refresh`` / ``skip`` 之一。 默认 ``skip``(增量跳过已导入,最安全最快,适合日常只扫新文件); 需要重建全表时再改为 ``clear`` 或在 UI 手动切换。 """ model_config = {"extra": "forbid"} default_folder: str = "" default_mode: str = "skip" # ============================================================ # 打印引擎配置模型 # ============================================================
[文档] class PrintEscpConfig(_StrictModel): """ESC/P-K 打印配置""" x_offset: float = 14 y_offset: float = 0
class PrintBatchConfig(_StrictModel): """批量打印配置(原 certificate_print.batch 迁移至 print.batch,见 §16.3)""" batch_size: int = 100 delay_seconds: float = 2 preview_delay_seconds: float = 10 first_direct_print: bool = True
[文档] class PrintConfig(_StrictModel): """打印引擎配置模型(合并后) 注意:与 ``certflow.config.print_config.RuntimePrintConfig``(运行时聚合类)同名, 本类为 pydantic 引擎配置模型,仅描述 ``print`` 段结构。 """ engine: str = "escp" default_printer: str = "EPSON LQ-635KII ESC/P2" default_copies: int = 1 # 默认打印模板(设置页可改;显示标签需匹配 PrintView 模板下拉项,如"全中文合格证模板") default_template: str = "全中文合格证模板" escp: PrintEscpConfig | None = None # 🆕 打印版式(canonical,原 certificate_print.paper/layout/font 迁移至此,见 §16.3) paper: dict[str, float] | None = None layout: PrintLayoutConfig | None = None font: PrintFontConfig | None = None # 🆕 批量打印参数(原 certificate_print.batch 迁移至此) batch: PrintBatchConfig | None = None # 🆕 打印字段定义(原 certificate_print.print_fields 迁移至此,cert_print_engine 消费) print_fields: list[PrintFieldConfig] | None = None # 🆕 预览选项(预印合格证:可关标题只显示值) preview: PrintPreviewConfig | None = None # 🆕 打印防错护栏 + 字典自学习配置(见 docs/PRINT_BLUEPRINT.md) guard: PrintGuardConfig | None = None # 🆕 入队前 raw 字节抓取配置(调试/分析用,默认关闭,见 PRINT_BLUEPRINT.md §14) raw_capture: PrintRawCaptureConfig | None = None
class PrintPreviewConfig(_StrictModel): """合格证预览选项(仅影响 GUI 预览渲染,不影响 ESC/P 实际打印)""" show_labels: bool = True class PrintRawCaptureConfig(_StrictModel): """入队前 raw 字节抓取配置(调试/分析用,默认关闭,见 PRINT_BLUEPRINT.md §14) - enabled: 总开关,默认关;设 true 才在「入队」时抓取 ESC/P-K 原始字节。 - output_dir: 落盘目录(相对运行目录;不存在则自动创建)。 - save_json: 是否同时保存结构化 JSON(字段值+模板+编号)便于人工分析。 """ enabled: bool = False output_dir: str = "raw_print" save_json: bool = True # ============================================================ # 打印防错护栏 + 字典自学习配置(docs/PRINT_BLUEPRINT.md) # print.guard 段必须在此建模,否则 PrintConfig(_StrictModel=forbid) 会丢弃该段 # ============================================================ class GuardRequiredFieldConfig(_StrictModel): """单个必填字段的校验配置(print.guard.required_fields[])""" key: str required: bool = True reconfirm: bool = False # 即使有值也弹 InputBox 二次确认(如 temperature) class GuardConfirmationConfig(_StrictModel): """确认闸口配置(print.guard.confirmation)""" single_batch: bool = True # 单张/单计划批量也弹确认 multi_batch: bool = True # 多计划批量每批发前弹确认 summary_fields: list[str] = Field(default_factory=list) class GuardLearnBackConfig(_StrictModel): """学回字典配置(print.guard.learn_back)""" enabled: bool = True strategy: str = "conservative" # conservative | last_write_wins | field_level overwrite_manual: bool = False # manual 来源条目永不自动覆盖 fields: list[str] = Field(default_factory=list) # 仅学这 4 个模型级字段 class GuardAutofillInspectorDefaultConfig(_StrictModel): """检验工号空值兜底配置(print.guard.autofill.inspector_default)""" chinese: str = "检5" # 中文合格证(全中文模板)默认检验工号 other: str = "No 5" # 其他合格证(中/俄/全英文模板)默认检验工号 class GuardAutofillConfig(_StrictModel): """加载自动带出配置(print.guard.autofill):表单字段 -> model_param_mappings 列""" enabled: bool = True fields: dict[str, str] = Field(default_factory=dict) inspector_default: GuardAutofillInspectorDefaultConfig | None = None class PrintGuardConfig(_StrictModel): """打印防错护栏总配置(print.guard)""" autofill: GuardAutofillConfig = Field(default_factory=GuardAutofillConfig) required_fields: list[GuardRequiredFieldConfig] = Field(default_factory=list) confirmation: GuardConfirmationConfig = Field(default_factory=GuardConfirmationConfig) learn_back: GuardLearnBackConfig = Field(default_factory=GuardLearnBackConfig) # ⑤ 与历史差异校验闸(§11.3 决议):取同型号上次实际打印值比对, # 字段在当前值 != 历史值时强制人眼确认(不只拦空值)。默认最全集。 reconfirm_on_diff: list[str] = Field( default_factory=lambda: ["temperature", "medium", "check_standard", "pn", "dn"] ) # ============================================================ # 统一输出配置(OutputView 配置驱动,见 docs/PRINT_BLUEPRINT.md §11.5) # 打印/扫描/报告共用同一套护栏(shared.guard_ref)与历史回填兜底(shared.history_backfill) # ============================================================ class ScanDualCodeConfig(_StrictModel): """扫描件双编码(SN 短码 / KKS 长码)渲染开关配置 默认关闭(普通用户扫描件不含 SN/KKS,与既有行为一致);仅特殊用户/项目场景 置 enabled: true 时,扫描件才会渲染双编码,字段由逐台单号派生(对齐打印侧 _derive_sn_and_kks),电厂件真 KKS 受保护优先采用 SalePlan.kks_code。 """ enabled: bool = False
[文档] class OutputTargetConfig(_StrictModel): """单个输出目标配置(output.targets.<name>)""" engine: str = "escp" # 输出动作类型: escp | pil | report controls: list[str] = Field(default_factory=list) # OutputView 动态渲染的控件集 run: str = "" # 输出动作入口的服务函数引用键(OutputView dispatch 据此调用) # 输出动作前完整性闸门必检字段(替代旧 scan_view 硬编码 _SCAN_REQUIRED_FIELDS,配置驱动) required_fields: list[str] = Field(default_factory=list) # 控件默认值(配置驱动):ScanView/OutputView 启动时读取并应用;缺省走代码回退值。 # 支持键:template_type / format / rows(每列张数) / cols(每行张数) / # paper_width_mm / paper_height_mm / output_dir。 defaults: dict[str, Any] = Field(default_factory=dict) # 双编码(SN/KKS)渲染开关(仅扫描目标使用,默认关闭) dual_code: ScanDualCodeConfig = Field(default_factory=ScanDualCodeConfig) # 打印目标复选框默认态(配置驱动,PrintView 启动时读取;缺省走代码回退 True) # 支持键:auto_fill / save_log / preview_labels(均为 bool) options: dict[str, Any] = Field(default_factory=dict)
[文档] class HistoryBackfillConfig(_StrictModel): """历史回填兜底配置(output.shared.history_backfill,§11.2)""" enabled: bool = True source: str = "print_logs" # 复用 PrintLog 作历史源(零新表) key: list[str] = Field(default_factory=lambda: ["product_model", "product_spec"]) fallback_fields: list[str] = Field( default_factory=lambda: ["temperature", "medium", "check_standard", "pn", "dn"] )
[文档] class OutputSharedConfig(_StrictModel): """统一输出共享配置(output.shared)""" guard_ref: str = "print.guard" # 护栏复用 print.guard 段(不重复定义) history_backfill: HistoryBackfillConfig = Field(default_factory=HistoryBackfillConfig)
class LayoutGroupConfig(_StrictModel): """常用布局配置驱动组(D 延后仅预留接口)。 每个组是一套效果集的命名组合(目标+模板+拼版等),后期 UI 用单选框/ 命令按钮加载某组即一键套用整套效果;底层各配置控件底座照常保留。 """ name: str = "" enabled: bool = False target: str = "" # 输出目标(print/scan) template: str = "" # 模板族(全中文/中英文) layout: str = "" # 拼版推荐值 label(对应 targets.scan.defaults.layout_presets)
[文档] class OutputConfig(_StrictModel): """统一输出总配置(output.*,驱动 OutputView)""" shared: OutputSharedConfig = Field(default_factory=OutputSharedConfig) targets: dict[str, OutputTargetConfig] = Field(default_factory=dict) default_target: str = "print" layout_groups: list[LayoutGroupConfig] = Field(default_factory=list)
# ============================================================ # 同步配置模型 # ============================================================
[文档] class SyncWebdavConfig(_StrictModel): """WebDAV 同步配置""" url: str = "" username: str = "" password: str = "" remote_path: str = "/certflow.db"
[文档] class SyncConfig(_StrictModel): """数据库同步配置模型""" webdav: SyncWebdavConfig | None = None
# ============================================================ # 底板预览配置模型 # ============================================================
[文档] class BackgroundConfig(_StrictModel): """底板预览配置模型""" show_in_preview: bool = True opacity: float = 0.3 image_path: str = ""
# ============================================================ # 销售计划批量填充配置模型 # ============================================================
[文档] class SalesPlanFillColumn(_StrictModel): """销售计划填充列配置""" name: str
[文档] class SalesPlanFillConfig(_StrictModel): """销售计划批量填充配置模型""" columns: list[SalesPlanFillColumn] | None = None
# ============================================================ # 导出调试配置模型 # ============================================================
[文档] class ExportDebugField(_StrictModel): """导出调试字段配置""" field: str use_fallback: bool = False
[文档] class ExportDebugConfig(_StrictModel): """导出调试配置模型""" fields: list[ExportDebugField] | None = None
# ============================================================ # 字段填充规则配置模型 # ============================================================
[文档] class FieldFillTransform(_StrictModel): """字段填充转换规则""" field: str = "" transform: str = ""
[文档] class FieldFillRule(_StrictModel): """单条字段填充规则""" source: str = "auto" pattern: str = "" transforms: dict[str, FieldFillTransform] | None = None
# ============================================================ # 打印日志空值默认标记配置模型 # ============================================================
[文档] class PrintLogEmptyMarkersConfig(_StrictModel): """打印日志空值默认标记配置模型 对应 VBA 将打印内容添加到Access数据库() 中的 Br(1..51) 赋值. """ customer: str = "【空白订货单位】" project_name: str = "【空白项目名称】" product_name: str = "【空白产品名称】" product_model: str = "【空白产品型号】" dn: str = "空白公称通径" pn: str = "空白公称压力" medium: str = "【空白适用介质】" temperature: str = "【空白适用温度】" body_material: str = "【未录入阀体材质】" stem_material: str = "【未录入阀杆材质】" disc_material: str = "【未录入启闭件材质】" tech_requirements: str = "【空白技术要求】" equipment_no: str = "【空白设备位号】" sub_project: str = "【空白子项目】" sales_sn: str = "【空白销售部产品编号】" category: str = "【空白销售部种类】" weight: str = "【空白销售部重量要求】" seq_no: str = "【空白序号】" requisition_no: str = "【空白营销部要货单号】" max_inlet_head: str = "【空白】" max_boost_head: str = "【空白】"
# ============================================================================ # §15 严格校验收尾(A-C):4 个业务段未建模顶层键补模型 # 原属审计报告 §3 的 14 个未建模顶层键中的业务段(dictionary/lookup_tables/ # quarantine/sort_rules),此前经 !include 并入 RootConfig 顶层、靠 extra=allow # 透传并被 cfg() 自由读取。现建模为子模型(继承 _StrictModel=forbid), # 使其受严格校验保护,杜绝子键拼写错误/死配置静默失效。 # UI 段 12 个顶层键(main_window/title_bar/...)已于任务 2.3 建模为宽松字段并配合 # RootConfig 顶层 forbid 闭环,不再是 allow 例外。 # ============================================================================ class DictionaryModelParamMappingConfig(_StrictModel): """型号参数字典(model_param_mappings)的解析配置(仅描述数据位置与格式,不含数据本身)。""" csv: str = "scripts/data/model_param_mappings.csv" encoding: str = "utf-8-sig" delimiter: str = "," header: list[str] = Field(default_factory=list) normalize_standard: bool = True fallback_raw_data: bool = True xlsx_source: str = "data/xlsx/型号压力对照.xlsx" class DictionaryMaterialGradesConfig(_StrictModel): """材质牌号字典(material_grades)的解析配置(wf2 B2,DB 快照 CSV)。""" csv: str = "scripts/data/material_grades.csv" encoding: str = "utf-8-sig" delimiter: str = "," header: list[str] = Field(default_factory=list) fallback_raw_data: bool = False xlsx_source: str = "data/xlsx/材质数据源.xlsx" class DictionaryCaliberMappingsConfig(_StrictModel): """口径映射字典(caliber_mappings)的解析配置(wf2 B3,RAW_DATA 外部化为 CSV)。""" csv: str = "scripts/data/caliber_mappings.csv" encoding: str = "utf-8-sig" delimiter: str = "," header: list[str] = Field(default_factory=list) fallback_raw_data: bool = True xlsx_source: str = "" class DictionaryConfig(_StrictModel): """基础字典配置(dictionary.*,对应 dictionaries.yaml)。""" model_param_mappings: DictionaryModelParamMappingConfig = Field( default_factory=DictionaryModelParamMappingConfig ) material_grades: DictionaryMaterialGradesConfig = Field( default_factory=DictionaryMaterialGradesConfig ) caliber_mappings: DictionaryCaliberMappingsConfig = Field( default_factory=DictionaryCaliberMappingsConfig ) class LookupTableContextMenuItemConfig(_StrictModel): """基础对照表右键菜单项。""" action: str table: str label: str class LookupTableContextMenuConfig(_StrictModel): """查询结果表「维护基础数据」子菜单配置(lookup_tables.context_menu)。""" enabled: bool = True label: str = "" items: list[LookupTableContextMenuItemConfig] = Field(default_factory=list) class LookupTableQuickFilterConfig(_StrictModel): """单条「快速筛选」按钮配置(lookup_tables.quick_filters.<table>[])。 点击即在筛选条追加一条预置条件;``value`` 可为字符串(如 ``"False"``) 或数值,``operator`` 默认 ``eq``。 """ label: str = "" field: str = "" operator: str = "eq" value: Any = None class LookupTablesConfig(_StrictModel): """基础对照表驱动配置(lookup_tables.*,对应 quarantine.yaml 中的 lookup_tables 段)。""" context_menu: LookupTableContextMenuConfig = Field(default_factory=LookupTableContextMenuConfig) # 各基础对照表的「快速筛选」按钮(数据驱动,便于增减,无需改代码); # key 与 context_menu.items[].table 一致,value 为该表按钮列表 quick_filters: dict[str, list[LookupTableQuickFilterConfig]] = Field(default_factory=dict) class QuarantineActionConfig(_StrictModel): """隔离视图功能键/右键菜单项。""" key: str label: str method: str danger: bool = False class QuarantineViewConfig(_StrictModel): """隔离视图 UI 配置(quarantine.view)。""" label: str = "" actions: list[QuarantineActionConfig] = Field(default_factory=list) context_menu: list[QuarantineActionConfig] = Field(default_factory=list) class QuarantineReleaseConfig(_StrictModel): """隔离释放行为配置(quarantine.release)。""" require_order_identity: bool = True rebuild_as: str = "sale_plan" class QuarantineConfig(_StrictModel): """隔离/释放配置(quarantine.*,对应 quarantine.yaml 中的 quarantine 段)。""" view: QuarantineViewConfig = Field(default_factory=QuarantineViewConfig) release: QuarantineReleaseConfig = Field(default_factory=QuarantineReleaseConfig) class SortRuleConfig(_StrictModel): """单条排序规则(sort_rules.keys[])。""" field: str order: str = "asc" class SortRulesConfig(_StrictModel): """旧版排序规则配置(sort_rules.*,对应 grouping.yaml 中的 sort_rules 段)。""" keys: list[SortRuleConfig] = Field(default_factory=list)
[文档] class RootConfig(_StrictModel): """根配置模型 所有配置的顶层容器,聚合所有子配置模块. 顶层已闭环为 extra='forbid'(任务 2.3 / §六 UI 域严格校验),未建模键触发 ValidationError,杜绝顶层键拼写错误/死配置静默失效;嵌套 UI 段结构由 UIConfigModel 顶层闸门二次把关(见 ui_config.py)。 Attributes: app: 应用基础配置 paths: 路径配置 sales_plan: 销售计划配置 certificate: 合格证配置 import_deduplication: 导入去重配置 database: 数据库配置 logging: 日志配置 ui: UI配置 color_mapping: 颜色映射配置 numbering: 编号规则配置(V2) duplicate_check: 重复检查配置(V2) unique_key: 唯一键配置(V2) priority_rules: 优先级规则配置(V2) export: 导出配置(V2) sales_plan_fill: 销售计划填充配置(V2) field_fallbacks: 字段回退链配置(V2) field_fill_rules: 字段填充规则配置(V2) sales_importer: 销售计划导入器配置(V2) import_mapping: 导入列映射配置(V2) export_debug: 导出调试配置(V2) test_report: 试压报告配置(V2) printer: 打印机配置(V2) environment: 环境信息配置(V2) colors: 颜色常量配置(V2) vba_import: VBA导入配置(V2) id_generator: 唯一键生成策略配置 production_status: 生产状态配置 import_config: 导入配置(与 QueryView 风格一致) sync: 数据库同步配置(WebDAV) print: 打印引擎配置 background: 底板预览配置 print_log_empty_markers: 打印日志空值默认标记配置 """ # 任务 2.3(§15.3 阶段3 收官 / §六 UI 域严格校验闭环):顶层改为 extra=forbid。 # ui.yaml 经 !include 并入的 UI 顶层键(main_window/window/title_bar/nav_buttons/ # correction_queue/welcome_page/import_page/log_page/status_bar/styles/query_page) # 已全部建模为宽松 dict/list 字段(见下方「UI 段顶层键」分组),由 forbid 闸门杜绝顶层键 # 拼写错误/死配置静默失效;嵌套结构仍松散(与 UIConfigModel 顶层 forbid 闸门分工一致)。 model_config = {"extra": "forbid"} app: AppConfig = Field(default_factory=AppConfig) paths: PathsConfig = Field(default_factory=PathsConfig) sales_plan: SalesPlanConfig = Field(default_factory=SalesPlanConfig) certificate: CertificateConfig = Field(default_factory=CertificateConfig) import_deduplication: ImportDeduplicationConfig = Field( default_factory=ImportDeduplicationConfig ) database: DatabaseConfig = Field(default_factory=DatabaseConfig) logging: LoggingConfig = Field(default_factory=LoggingConfig) ui: UIConfig = Field(default_factory=UIConfig) color_mapping: ColorMappingConfig = Field(default_factory=ColorMappingConfig) # V2 新增顶层配置段(全部 Optional,保持向后兼容) numbering: NumberingConfig | None = None duplicate_check: DuplicateCheckConfig | None = None unique_key: UniqueKeyConfig | None = None priority_rules: PriorityRulesConfig | None = None export: ExportConfig | None = None sales_plan_fill: SalesPlanFillConfig | None = None field_fallbacks: dict[str, list[str]] | None = None field_fill_rules: dict[str, list[FieldFillRule]] | None = None sales_importer: SalesImporterConfig | None = None qualified_list: dict[str, Any] | None = ( None # 向后兼容,settings.py 中仍通过 cfg("qualified_list.*") 访问 ) import_mapping: ImportMappingConfig | None = None export_debug: ExportDebugConfig | None = None test_report: TestReportConfig | None = None report: dict[str, Any] = Field( default_factory=dict ) # report.yaml 顶层键(任务 2.3:补建模以闭环 forbid) printer: PrinterConfig | None = None environment: EnvironmentConfig | None = None colors: ColorsConfig | None = None field_templates: dict[str, Any] | None = ( None # 字段回填模板(Excel 字段映射格式,结构复杂保留 dict) ) print_templates: dict[str, Any] | None = ( None # 打印模板坐标(来自 templates/coordinates.yaml,结构复杂保留 dict) ) vba_import: VBAImportConfig | None = None completed_orders_backfill: CompletedOrdersBackfillConfig | None = None query_page: dict[str, Any] = Field(default_factory=dict) # ── UI 段顶层键(任务 2.3:原为 !include 并入 RootConfig 顶层、靠 extra=allow 透传的 # 未建模键;现建模为宽松字段并配合顶层 forbid 闭环,杜绝顶层键拼写错误/死配置静默失效)── main_window: dict[str, Any] = Field(default_factory=dict) window: dict[str, Any] = Field(default_factory=dict) title_bar: dict[str, Any] = Field(default_factory=dict) nav_buttons: list[Any] = Field(default_factory=list) correction_queue: dict[str, Any] = Field(default_factory=dict) welcome_page: dict[str, Any] = Field(default_factory=dict) import_page: dict[str, Any] = Field(default_factory=dict) log_page: dict[str, Any] = Field(default_factory=dict) status_bar: dict[str, Any] = Field(default_factory=dict) styles: dict[str, Any] = Field(default_factory=dict) # V3 新增分组排序配置 grouping: GroupingConfig | None = None sorting: SortingConfig | None = None # ── 新增模型化字段 ── id_generator: IdGeneratorConfig | None = None # 唯一键生成策略 production_status: ProductionStatusConfig | None = None # 生产状态配置 import_config: ImportConfig | None = None # 导入配置 import_placeholder: ImportPlaceholderConfig | None = Field( default_factory=ImportPlaceholderConfig, alias="import" ) # 导入期占位目录开关(B0-4) bom_import: BomImportConfig | None = Field( default_factory=BomImportConfig ) # BOM 导入控件配置(默认目录/默认模式) sync: SyncConfig | None = None # 数据库同步配置(WebDAV) print: PrintConfig | None = None # 打印引擎配置 background: BackgroundConfig | None = None # 底板预览配置 print_log_empty_markers: PrintLogEmptyMarkersConfig | None = None # 打印日志空标记 output: OutputConfig | None = None # 统一输出配置(OutputView 配置驱动,§11.5) # §15 严格校验收尾(A-C):为 4 个业务段未建模顶层键补模型,使其受 forbid 保护 dictionary: DictionaryConfig = Field(default_factory=DictionaryConfig) lookup_tables: LookupTablesConfig = Field(default_factory=LookupTablesConfig) quarantine: QuarantineConfig = Field(default_factory=QuarantineConfig) sort_rules: SortRulesConfig = Field(default_factory=SortRulesConfig)
[文档] @field_validator("logging") @classmethod def validate_log_level(cls, v: LoggingConfig) -> LoggingConfig: """验证日志级别是否有效 Args: v: 待验证的日志配置对象 Returns: LoggingConfig: 验证通过的日志配置对象 Raises: ValueError: 当日志级别不在有效值范围内时抛出 """ valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} if v.level.upper() not in valid_levels: raise ValueError(f"Invalid log level: {v.level}") return v
# 导出所有模型 __all__ = [ "RootConfig", "AppConfig", "PathsConfig", "TemplatePaths", "SalesPlanConfig", "ExcelReadConfig", "HeaderDetectionConfig", "DualFieldMappingConfig", "SuffixRule", "CertificateConfig", "ImportDeduplicationConfig", "DatabaseConfig", "LoggingConfig", "UIConfig", "ColorMappingConfig", # V2 新增 "NumberingConfig", "NumberingSuffixRule", "DuplicateCheckConfig", "UniqueKeyConfig", "UniqueKeyField", "PriorityRulesConfig", "ExportConfig", "SalesImporterConfig", "VBAImportConfig", "PrintLayoutConfig", "PrintFontConfig", "PrintFieldConfig", "TestReportConfig", "PrinterConfig", "EnvironmentConfig", "ColorsConfig", "ImportMappingConfig", # V3 新增 "GroupingConfig", "GroupingNumberingConfig", "SortingConfig", "SortingKey", "CompletedOrdersBackfillConfig", # 配置驱动新增 "ProductionStatusConfig", "ProductionStatusUILabel", "ProductionStatusAutoUpgradeRule", "ProductionStatusInferenceRule", "ProductionStatusUIConfig", "ProductionStatusContextMenu", "IdGeneratorConfig", "ImportConfig", "ImportViewConfig", "ImportColumnConfig", "ImportPlaceholderConfig", "PrintConfig", "PrintEscpConfig", "SyncConfig", "SyncWebdavConfig", "BackgroundConfig", "SalesPlanFillConfig", "SalesPlanFillColumn", "ExportDebugConfig", "ExportDebugField", "FieldFillRule", "FieldFillTransform", "PrintLogEmptyMarkersConfig", # 统一输出配置驱动(§11.5) "OutputConfig", "OutputTargetConfig", "HistoryBackfillConfig", "OutputSharedConfig", ]