# 组件库分类、发现与读取规范 v1 状态:已在 `experimental` 临时组件库实施 适用范围:`app/simulation/components`、组件注册中心、System XML 和 React Flow 组件库 当前试验库:`experimental`(界面名称:临时测试组件库) ## 0. 文档定位 本文档只负责“模型如何被系统发现和读取”。模型方程、状态、参数和结果应如何编写, 统一参见[组件模型建模规范 v1](component-model-authoring-spec-v1.md)。 人工或 AI 排查组件读取问题时,按以下顺序读取: 1. `app/simulation/registry.py` 中的 `ENABLED_COMPONENT_LIBRARIES`。 2. 被启用组件库的 `library.py`。 3. `library.py/models` 明确列出的模型类。 4. 模型类的 `DISPLAY / PORTS / PARAMETERS`。 5. `build_component_catalog()` 的输出。 6. 前端 `normalizeComponentCatalog()`。 当前事实来源优先级: | 信息 | 唯一事实来源 | 不能作为事实来源 | | --- | --- | --- | | 启用哪些库 | `ENABLED_COMPONENT_LIBRARIES` | 目录中碰巧存在的文件夹 | | 库分类和模型清单 | 各库 `library.py` | 前端组件列表 | | 模型类型和版本 | 模型类 | 文件名或中文名称 | | 物理端口 | 模型类 `PORTS` | `DISPLAY.ports` 或画布方向 | | 参数默认值和边界 | 模型类 `PARAMETERS` | 前端兜底定义 | | 图标和端口位置 | 模型类 `DISPLAY` | 物理方程 | | 前端运行目录 | `/api/components/catalog` | 手工扫描 Python 包 | 如果文档、代码和目录响应不一致,应在同一次修改中修复并增加测试,不能通过复制 另一份映射临时绕过。 ## 1. 目标 本规范用于统一以下内容: 1. 后端组件库如何声明自身信息和分类。 2. 单个模型如何声明端口、参数、结果变量和界面显示信息。 3. 后端如何发现、校验、注册并实例化模型。 4. 前端如何通过统一目录接口自动生成左侧组件库和参数面板。 5. System XML 中的模型类型如何稳定映射到 Python 实现。 目标工作流如下: ```mermaid flowchart LR A["ENABLED_COMPONENT_LIBRARIES"] --> B["library.py"] B --> C["受控导入模型类"] C --> D["启动契约校验"] D --> E["组件注册表"] E --> F["GET /api/components/catalog"] F --> G["React Flow 组件库和参数面板"] E --> H["System XML 模型实例化"] ``` 新增一个符合本规范的模型后,前端不应再修改 `App.tsx` 中的组件列表、参数列表 或分类列表。只有新增一种前端尚不支持的图形渲染方式时,才需要补充前端图标组件。 ## 2. 术语和层级 组件目录采用四个相互独立的概念: | 层级 | 示例 | 含义 | | --- | --- | --- | | 组件库 Library | `experimental` | 一组具有共同发布、维护和版本边界的模型 | | 界面分类 Category | `storage` | 只用于组件面板分组和排序 | | 物理域 Domain | `pneumatic` | 决定端口能否连接以及采用哪组连接方程 | | 模型 Model | `cylinder` | 可实例化并写入 System XML 的稳定模型类型 | 分类和物理域禁止混用。例如,`storage` 是界面分类,`pneumatic` 是物理域; 一个“储能元件”也可以属于液压域,不能根据分类推断端口连接规则。 标准层级为: ```text Library Category Model Port Port variable Parameter Result variable ``` ## 3. 推荐目录结构 每个组件库使用独立 Python 包: ```text app/simulation/components/ experimental/ __init__.py library.py storage/ __init__.py cylinder.py tank.py flow/ __init__.py orifice.py resistive_pipe.py junctions/ __init__.py tee.py ``` 规则如下: - `library.py` 是组件库唯一清单入口。 - 分类目录名必须与分类 ID 一致。 - 一个公开模型原则上放在一个独立 `.py` 文件中。 - 求解器、介质、通用方程和状态对象不得放入组件库目录。 - 未准备对外注册的实验类可以保留在库内,但不得加入库清单。 - 禁止通过扫描任意 `.py` 文件并执行其中代码来发现模型;必须使用库清单进行受控导入。 ## 4. 标识符和版本 ### 4.1 标识符 以下字段使用稳定的英文机器标识: - `library.id` - `category.id` - `MODEL_TYPE` - 端口名 - 参数名 - 结果变量名 标识符应使用 `snake_case`,只允许小写英文字母、数字和下划线,并以字母开头。 已有工程约定中的 `T`、`U` 等热力学变量可以保留。 界面中文名称单独保存在 `label` 中。修改 `label` 不影响工程兼容性;修改机器标识 会影响工程文件、System XML、结果文件和后端注册,因此发布后不得直接改名。 ### 4.2 版本 每个组件库和模型都应具有版本: ```python LIBRARY_VERSION = "0.1.0" MODEL_VERSION = "1.0.0" ``` 版本遵循 `主版本.次版本.修订版本`: - 修订版本:只修复实现,不改变输入输出契约。 - 次版本:向后兼容地新增参数、结果或能力。 - 主版本:端口、参数语义或方程发生不兼容变化。 当前 System XML v2 尚未保存模型版本。正式发布组件库前,应在 XML 中增加 `library` 和 `modelVersion`,并提供旧工程迁移规则。 ## 5. 组件库清单 每个库必须提供 `library.py`,并使用有类型的不可变声明: ```python from app.simulation.core.catalog import ( ComponentCategorySpec, ComponentLibrarySpec, ) LIBRARY = ComponentLibrarySpec( id="experimental", label="临时测试组件库", version="0.1.0", source_package="app.simulation.components.experimental", temporary=True, order=100, categories=( ComponentCategorySpec( id="storage", label="储能元件", order=10, ), ComponentCategorySpec( id="flow", label="流动元件", order=20, ), ComponentCategorySpec( id="junctions", label="连接元件", order=30, ), ), models=( "app.simulation.components.experimental.storage.cylinder:Cylinder", "app.simulation.components.experimental.storage.tank:Tank", "app.simulation.components.experimental.flow.resistive_pipe:ResistivePipe", "app.simulation.components.experimental.flow.orifice:Orifice", "app.simulation.components.experimental.junctions.tee:Tee", ), ) ``` `models` 是唯一允许注册到系统的模型清单。它同时解决以下问题: - 避免导入测试脚本或内部辅助类。 - 控制模型加载顺序。 - 避免同一个 `MODEL_TYPE` 被多个实现重复注册。 - 可以只加载部署环境允许使用的组件库。 - 启动错误能明确定位到具体库和模型。 当前 `experimental/library.py` 已按此格式声明库、分类和五个公开模型; `experimental/__init__.py` 只保留旧常量的兼容别名。 ## 6. 模型类契约 一个可注册模型必须显式声明: ```python class ExampleComponent(Component): MODEL_TYPE = "example_component" MODEL_VERSION = "1.0.0" PORTS = (...) PARAMETERS = (...) RESULT_VARIABLES = (...) DISPLAY = ... ``` 字段含义: | 字段 | 是否必须 | 用途 | | --- | --- | --- | | `MODEL_TYPE` | 必须 | System XML、注册表和结果元数据中的稳定类型 | | `MODEL_VERSION` | 必须 | 模型契约和迁移版本 | | `PORTS` | 必须 | 物理或信号连接契约 | | `PARAMETERS` | 必须,可为空 | 用户输入参数及校验边界 | | `RESULT_VARIABLES` | 必须,可为空 | 组件级可展示结果 | | `DISPLAY` | 必须 | 前端名称、分类、图标、排序和端口布局 | 模型实现还必须满足: 1. 构造函数调用 `super().__init__(name)`。 2. 使用 `set_parameter_values()` 保存所有规范化后的参数。 3. 使用 `register_declared_port()` 创建 `PORTS` 中声明的端口。 4. 组件级结果键必须与 `RESULT_VARIABLES` 完全一致。 5. 所有内部计算均使用 SI 基准值。 6. 模型不能直接依赖 FastAPI、React Flow 或 XML DOM。 7. 模型的方程不能依赖图标方向、界面分类或画布位置。 完整方程示例参见 [`app/simulation/components/example.md`](../app/simulation/components/example.md)。 ## 7. 界面显示声明 `DISPLAY` 只描述模型在前端的呈现,不参与物理求解: ```python from app.simulation.core.catalog import ( ComponentDisplaySpec, PortDisplaySpec, ) DISPLAY = ComponentDisplaySpec( label="示例容腔", library_id="experimental", category_id="storage", symbol="cylinder", order=90, ports=( PortDisplaySpec( name="port_a", side="left", order=10, ), ), ) ``` 字段规则: - `label`:组件库中的显示名称。 - `library_id`:必须引用已加载的库。 - `category_id`:必须引用该库已声明的分类。 - `symbol`:前端图形渲染器的稳定标识。 - `order`:同一分类中的排序值。 - `ports`:只声明端口在图形中的位置和顺序。 `DISPLAY.ports` 中的端口名必须与模型的 `PORTS` 完全一致,不能缺少、增加或改名。 旋转和镜像只改变前端计算后的视觉方位,不改变端口机器名和物理语义。 前端遇到未知 `symbol` 时必须显示通用占位图标,同时保留模型拖拽、参数编辑、 连线和 XML 生成功能,不能因为缺少专用图形而丢弃整个模型。 ## 8. 端口规范 端口由 `PortDefinition` 声明: ```python PORTS = ( PortDefinition.pneumatic( "port_a", nominal_role="bidirectional", ), ) ``` 每个端口必须包含: - 稳定端口名。 - `kind`:`physical` 或 `signal`。 - `domain`:例如 `pneumatic`。 - `nominal_role`:用于界面提示,不决定实际流向。 - `positive_flow_direction`:物理流量变量的符号约定。 - 端口变量及各自连接规则。 当前气动功率端口包含: | 变量 | 角色 | 连接规则 | 单位 | | --- | --- | --- | --- | | `p` | effort | `equal` | `Pa` | | `m_flow` | flow | `sumToZero` | `kg/s` | | `h_outflow` | stream | `streamMix` | `J/kg` | 气动端口统一约定 `m_flow > 0` 表示质量流入当前组件。`inlet`、`outlet` 是标称角色, 不应阻止反向流动;实际方向由求解结果中的流量符号决定。 连接校验至少包括: 1. 两个端口均存在。 2. 端口不能连接自身。 3. `kind` 相同。 4. `domain` 相同。 5. 端口变量集合及连接规则兼容。 6. 同一物理端口的连接数量符合当前网络编译器能力。 ## 9. 参数规范 参数使用 `ParameterDefinition` 声明: ```python PARAMETERS = ( ParameterDefinition( name="volume", label="容积", quantity="volume", unit="m3", default=0.1, minimum=0.0, minimum_exclusive=True, ), ) ``` 规则如下: - `name` 是模型构造、XML 和工程文件共同使用的稳定名称。 - `label` 是界面文案。 - `quantity` 是受控物理量标识,用于前端匹配可换算单位。 - `unit` 是后端 SI 单位。 - `default` 必须能够直接创建合法模型。 - 边界必须与方程有效范围一致。 - 无量纲量使用 `quantity="dimensionless"` 和 `unit=""`。 - 用户输入可以使用其他公制单位,但提交后端前必须换算为 SI。 - 文本框编辑中的临时字符串不立即判错,失焦、回车或运行仿真时再执行数值校验。 后端不得静默忽略未知参数。缺少参数时可使用声明的默认值;出现未知参数时必须 返回包含组件 ID 和参数名的明确错误。 ## 10. 结果变量规范 组件结果和端口结果分开管理: - 组件结果来自 `RESULT_VARIABLES`。 - 端口结果根据 `PORTS` 中 `result_visible=True` 的端口变量自动生成。 - 求解器缓存、残差和调试量默认不进入用户结果。 每个结果变量必须提供: - `name` - `label` - `quantity` - `unit` - `category` - `order` 仿真结果必须输出结构化元数据,前端禁止拆解结果键或按字符串关键词猜测: ```json { "key": "cylinder_1.port_b.p", "componentId": "cylinder_1", "componentType": "cylinder", "scope": "port", "portName": "port_b", "name": "p", "label": "压力", "quantity": "pressure", "unit": "Pa", "category": "effort", "order": 10 } ``` 结果页应按 `componentId`、`scope`、`portName`、`quantity` 等结构化字段筛选, 而不是从 `key` 中推断组件、端口和变量。 ## 11. 标准模型创建入口 注册中心通过统一入口创建模型,避免长期维护集中式 `_cylinder_factory`、 `_tank_factory` 等适配函数。当前接口为: ```python @classmethod def create( cls, *, name: str, medium: IdealGasMedium, parameters: Mapping[str, float], ) -> Component: ... ``` 创建流程: 1. 注册中心按 `PARAMETERS` 填充默认值。 2. 校验数值有限性和上下限。 3. 拒绝未知参数。 4. 调用模型类的 `create()`。 5. 验证实例的模型类型、端口和参数快照。 6. 将实例交给网络编译器。 这种方式允许 Python 构造参数保留内部命名,同时对外始终使用规范中的参数名。 ## 12. 自动发现与注册 后端启动时按以下顺序建立注册表: ```text 读取启用的 library.py -> 校验库 ID、版本和分类 -> 按 models 清单导入模型类 -> 读取模型静态契约 -> 执行跨字段校验 -> 建立 library registry -> 建立 model registry -> 构建前端 catalog ``` 当前使用显式启用列表: ```python ENABLED_COMPONENT_LIBRARIES = ( "app.simulation.components.experimental.library:LIBRARY", ) ``` 禁止以下发现方式: - 在整个仓库递归导入所有 Python 文件。 - 依赖文件名自动推断 `MODEL_TYPE`。 - 由前端硬编码后端类路径。 - 导入失败后悄悄跳过模型。 - 多个实现重复注册同一个模型类型并由加载顺序决定最终结果。 发现或校验失败时,FastAPI 应拒绝启动并给出库 ID、模型类型、字段和原因。 ## 13. 启动校验规则 注册表完成前必须执行以下校验: ### 13.1 库与分类 - 库 ID 全局唯一。 - 库版本格式有效。 - 分类 ID 在库内唯一。 - 所有排序值为整数。 - 所有模型引用已存在的库和分类。 ### 13.2 模型 - `MODEL_TYPE` 全局唯一,且与注册键一致。 - 模型版本格式有效。 - 模型继承框架要求的基类。 - 模型提供统一创建入口。 - 默认参数能够成功创建实例。 ### 13.3 端口 - 端口名在模型内唯一。 - 显示端口集合与物理端口集合完全一致。 - 端口物理域、变量角色和连接规则有效。 - 实例实际注册的端口与静态声明一致。 ### 13.4 参数 - 参数名在模型内唯一。 - 默认值有限且满足边界。 - `minimum <= maximum`。 - `quantity` 和 `unit` 的组合已登记。 - 实例保留所有规范化参数,不得静默修改或丢失。 ### 13.5 结果 - 结果变量名在对应作用域内唯一。 - `quantity` 和单位有效。 - `component_result_values()` 的键与声明一致。 - 端口结果只来自声明为可见的端口变量。 ## 14. 前端组件目录协议 前端只通过以下接口读取组件库: ```http GET /api/components/catalog ``` 目录顶层必须具有版本: ```json { "schemaVersion": 1, "libraries": [] } ``` 单个模型至少包含: ```json { "type": "cylinder", "modelType": "cylinder", "modelVersion": "1.0.0", "label": "气瓶", "symbol": "cylinder", "order": 10, "category": { "id": "storage", "label": "储能元件", "order": 10 }, "ports": [], "parameters": [] } ``` 前端读取规则: 1. 按库 `order`、分类 `order`、模型 `order` 排序。 2. 使用 `type` 作为拖拽数据和工程文件中的稳定类型。 3. 使用 `label` 显示中文名称。 4. 使用 `ports` 生成 React Flow Handle。 5. 使用 `parameters` 生成参数输入和单位选择控件。 6. 使用 `symbol` 选择图标渲染器。 7. 不在前端重新定义参数默认值、边界或端口语义。 目录协议提供以下可选的 AMESim 介质扩展字段: - 参数的 `editor: "amesimGasReference"` 表示该数值不是普通连续量,而是 项目介质定义的 `gi` 引用。前端应保留索引 `0`,并从当前画布的介质定义 组件生成其余下拉项;索引下拉项只显示数值,不拼接介质名称或中文说明。 - 参数的 `editor: "amesimGasPropertyModel"` 表示该参数选择介质定义内部的 物性计算模型。参数同时提供 `options: [{"value": 0, "label": "理想气体"}]` 一类目录数据,前端据此生成下拉栏;后续增加算法时由介质模型注册新的选项, 前端不硬编码算法名称。 - 模型的 `role: "amesimGasMediumDefinition"` 表示该模型是项目级介质定义。 此类模型允许 `ports: []`,在 System XML v2 中仍按普通零端口 `Component` 保存。 这些字段在目录对象中均为可选。宽松读取目录的消费者可以把未知编辑器参数 退化为普通数值输入;按本仓库 JSON Schema 严格校验的消费者必须与后端成套 升级,才能识别新增的 `editor` 值和 `options` 字段。正式前端必须依据目录字段 生成控件,不能硬编码具体 AMESim 模型名。 `property_model` 是每种介质组件内部的稳定选项编号,不等同于 AMESim 原始 `eosType`。例如空气组件的 `property_model=0` 表示理想气体,并映射到 `fluidType=2/eosType=1`;氦气组件的 `property_model=0` 表示 Peng-Robinson,并映射到 `fluidType=12/eosType=6`。编译层负责保存这种映射, 前端只使用目录选项。 当前前端保留内置兜底目录,用于后端未启动时继续打开工程。兜底只是一种开发期 容错机制,不能成为新增模型的正式注册方式;正式环境应明确提示目录加载失败。 ### 14.1 前端实际读取步骤 React Flow 启动时: 1. 使用 `no-store` 请求 `/api/components/catalog`。 2. 检查 `schemaVersion == 1`。 3. 检查库、模型、端口和参数结构。 4. 检查模型 `type` 是否全局重复。 5. 将参数数组转换为参数面板定义。 6. 按库、分类和模型的 `order` 排序。 7. 成功时显示“后端目录”。 8. 请求或格式校验失败时显示“内置兜底”并使用开发期兜底目录。 前端兜底目录不保证包含新模型。新增公开模型后,只要 FastAPI 正常提供目录,前端 就能读取;若要求后端离线时也显示新模型,才需要有意识地同步兜底定义。兜底定义 仍不能成为端口、参数或默认值的权威来源。 ### 14.2 修改后如何生效 修改 Python 模型、库清单或注册器后必须重启 FastAPI: ```powershell cd F:\Master\SystemSimulationApp .\.venv-win\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 ``` 只刷新浏览器无法让已运行的 Python 进程重新导入模型。前端源代码由 Vite 开发服务 热更新;普通目录内容变化不需要重启 Vite。 ## 15. System XML 映射 System XML 中: ```xml ``` 映射规则: - `id`:工程内唯一的组件实例 ID。 - `name`:用户可修改的组件实例名称。 - `type`:必须匹配唯一的 `MODEL_TYPE`。 - `componentType`:当前为兼容字段,应与 `type` 相同。 - ``:必须存在于模型的 `PORTS`。 - ``:必须存在于模型的 `PARAMETERS`。 介质定义组件不通过物理端口连接。编译器先收集目录角色为 `amesimGasMediumDefinition` 的零端口组件,再解析带 `editor="amesimGasReference"` 参数的组件引用;介质定义组件本身不进入数值 仿真网络。System XML 语义校验会在编译前检查介质索引的整数范围、定义唯一 性、正索引引用完整性,以及同一气动连通分量的引用一致性。 XML 解析器只负责结构、引用和契约校验;模型注册中心负责选择 Python 类并创建实例; 模型自身负责方程和状态。三层职责不得混合。 ## 16. 测试要求 每个新模型至少需要: 1. 元数据测试:模型类型、端口、参数和结果声明合法。 2. 目录测试:模型出现在正确库和分类中。 3. 默认创建测试:默认参数能构造模型。 4. 参数边界测试:非法值被拒绝,错误信息包含组件和参数。 5. 端口测试:实例端口与声明完全一致。 6. XML 测试:最小系统能解析并映射到正确模型。 7. 方程测试:至少验证一个稳态、残差或守恒关系。 8. 最小仿真测试:一个短时算例能产生有限结果和结构化结果元数据。 库级测试还应检查: - 库清单中的所有类均可导入。 - 所有模型类型全局唯一。 - 无遗漏或重复分类。 - `GET /api/components/catalog` 满足目录 schema。 ## 17. 新增模型操作清单 开发者新增模型时只执行以下步骤: 1. 在目标库的正确分类目录中新建模型文件。 2. 实现 `MODEL_TYPE`、`MODEL_VERSION`、`PORTS`、`PARAMETERS`、 `RESULT_VARIABLES` 和 `DISPLAY`。 3. 实现统一 `create()` 和模型方程。 4. 将模型类路径加入该库 `library.py` 的 `models`。 5. 添加模型单元测试和最小 XML/仿真测试。 6. 运行注册校验和完整测试。 7. 重启 FastAPI,刷新前端确认目录来源为“后端目录”。 正常情况下不需要修改: - React Flow 左侧组件列表。 - 参数面板字段。 - System XML 模型类型分派代码。 - 结果变量关键词映射。 - 集中式模型工厂表。 ### 17.1 AI 修改约束 AI 在处理组件库读取任务时必须: 1. 先确认目标是新增模型、修改模型还是新增库。 2. 读取当前启用列表和目标库清单。 3. 只把公开模型加入 `library.py/models`。 4. 不通过递归扫描替代显式清单。 5. 不在前端重新声明后端契约作为正式实现。 6. 不静默跳过加载失败的模型。 7. 保留未知 `symbol` 的通用图标回退能力。 8. 修改后检查目录响应,并运行注册表和前端构建测试。 9. 告知用户需要重启 FastAPI。 AI 不应仅因为某个 `.py` 文件位于组件目录,就假定它是公开模型。公开性的唯一判断 依据是该类是否出现在已启用库的 `models` 清单中。 ## 18. 当前实现与目标规范的差异 | 能力 | 当前状态 | 目标 | | --- | --- | --- | | 库 ID、名称、版本、分类和模型清单 | 已实现 | 由各库 `library.py` 维护 | | 库和模型注册表 | 已实现 | 由已启用库清单自动构建 | | 前端目录接口 | 已实现 | 已包含库版本和模型版本 | | 前端动态分类和参数读取 | 已实现 | 新增已支持图标的模型无需改组件列表 | | 端口与参数契约 | 已实现 | 保持为唯一事实来源 | | 结构化结果元数据 | 已实现 | 保持为唯一事实来源 | | `DISPLAY` | 已实现 | 由公开模型类自行声明 | | 模型工厂 | 已实现 | 模型类统一 `create()` | | 模型发现 | 已实现 | 按库清单受控发现 | | 启动校验 | 已实现首版 | 覆盖版本、分类、端口、参数、单位和默认实例 | | XML/工程中的模型版本与迁移 | 未实现 | 正式库发布前补齐 | | 目录 JSON Schema | 已实现 | `schemas/component-catalog-v1.schema.json` | ## 19. 推荐实施顺序 1. 已完成:声明类型已放入独立的 `core/catalog.py`。 2. 已完成:`experimental/library.py` 已成为临时库唯一清单入口。 3. 已完成:五个公开模型自行声明 `DISPLAY` 和 `MODEL_VERSION`。 4. 已完成:公开模型统一实现 `create()`,集中式工厂函数已删除。 5. 已完成:注册表由库清单构建,并在导入时执行契约和默认实例校验。 6. 已完成:已增加组件目录 JSON Schema。 7. 待完成:在 System XML 和工程文件中保存模型版本,并设计迁移机制。 8. 待完成:规范稳定后新建正式组件库,不再向 `experimental` 增加生产模型。 该顺序可以保证每一步都保持现有前端和 System XML 可用,不需要一次性重写模型、 解析器和界面。 ## 20. 改动影响表 | 想做的改动 | 必须修改 | 通常不需要修改 | | --- | --- | --- | | 新增同库同分类模型 | 模型文件、`library.py/models`、测试 | 注册表、前端参数列表 | | 新增分类 | 库 `categories`、模型 `DISPLAY.category_id`、测试 | 物理端口和求解器 | | 新增组件库 | 新库包和 `library.py`、启用列表、测试 | 已有库清单 | | 修改参数默认值或范围 | 模型 `PARAMETERS`、测试、必要的版本 | 前端参数硬编码 | | 修改端口 | 模型 `PORTS`、`DISPLAY.ports`、XML/网络测试、版本迁移 | 库分类 | | 新增专用图标 | 模型 `DISPLAY.symbol`、前端图标渲染器 | 参数和物理方程 | | 新增物理域 | 端口协议、网络、求解器、XML、前端兼容规则和测试 | 仅修改分类名称 | | 修改目录响应结构 | 后端序列化、JSON Schema、前端解析、协议版本和测试 | 单个模型方程 | ## 21. 读取故障排查 | 现象 | 优先检查 | | --- | --- | | 模型完全没有出现在目录响应 | 模型类路径是否加入已启用库的 `models` | | FastAPI 无法启动 | 启动错误中的库、模型和字段;通常是契约校验失败 | | 接口有模型但前端没有 | `schemaVersion`、前端控制台、目录规范化错误 | | 前端显示“内置兜底” | 8000 端口、`/api/components/catalog`、后端是否重启 | | 分类错误 | `DISPLAY.category_id` 与库 `categories` | | 端口数量或位置错误 | `PORTS` 与 `DISPLAY.ports` 是否完全一致 | | 参数面板缺字段 | 模型 `PARAMETERS` 和目录响应,不先改前端 | | XML 报不支持类型 | XML `type` 是否精确匹配 `MODEL_TYPE` | | 图标是通用图形 | `symbol` 尚无专用前端渲染器,但模型仍应可用 | 最小诊断命令: ```powershell .\.venv-win\Scripts\python.exe -c "from app.simulation.registry import build_component_catalog; print(build_component_catalog())" .\.venv-win\Scripts\python.exe -m unittest tests.test_component_registry tests.test_component_catalog ```