certflow.views.material_grade_manager_view 源代码

"""材质牌号管理界面

可视化维护 material_grades 表(牌号 / 标准号 / 材料形态 / 阀门零件类别 / 元素 / 性能范围)。
作为模态对话框从主窗口导航栏打开,内部通过 MaterialGradeController 完成 CRUD。

UI 复用通用基类 ``LookupTableManagerView``(列定义驱动 + 共享控件),
本模块仅声明列/字段定义与「载入示例」扩展动作,避免重复造轮子。

字段维度说明:
- 材料形态:category_large / category_medium(铸件类/锻件类/板材类/棒材类)
- 阀门零件类别:category(body/stem/disc/common),用于打印对话框分组
- 元素性能:element + standard_min/max + actual_min/max + decimal_places
"""

from __future__ import annotations

from typing import Any

from PySide6.QtWidgets import QLabel, QMessageBox

from certflow.controllers.material_grade_controller import MaterialGradeController
from certflow.utils.logger import logger
from certflow.views.bases.lookup_table_manager_view import (
    ColumnSpec,
    FieldSpec,
    LookupTableManagerView,
)

# 表格列定义:(标题, 模型字段, 是否可编辑展示, 字段类型)
_COLUMNS = [
    ColumnSpec("ID", "id", False),
    ColumnSpec("牌号", "grade"),
    ColumnSpec("标准号", "standard_code"),
    ColumnSpec("材料大类", "category_large"),
    ColumnSpec("材料中类", "category_medium"),
    ColumnSpec("零件类别", "category"),
    ColumnSpec("类型", "kind"),
    ColumnSpec("元素/性能", "element"),
    ColumnSpec("标准最小", "standard_min", field_type="float"),
    ColumnSpec("标准最大", "standard_max", field_type="float"),
    ColumnSpec("小数位", "decimal_places", field_type="int"),
    ColumnSpec("虚拟最小", "actual_min", field_type="float"),
    ColumnSpec("虚拟最大", "actual_max", field_type="float"),
    ColumnSpec("启用", "is_active", field_type="bool"),
]

# 编辑表单字段定义
_EDIT_FIELDS = [
    FieldSpec("grade", "牌号 *", required=True, placeholder="如 WCB, CF8, 304"),
    FieldSpec("standard_code", "标准号 *", required=True, placeholder="如 GB/T12229-2005"),
    FieldSpec("element", "元素/性能 *", required=True, placeholder="如 碳(C)%"),
    FieldSpec(
        "category_large", "材料大类", empty_as_none=True, placeholder="铸件类/锻件类/板材类/棒材类"
    ),
    FieldSpec("category_medium", "材料中类", empty_as_none=True, placeholder="普通碳钢/低温钢"),
    FieldSpec("standard_min", "标准最小", field_type="float", empty_as_none=True),
    FieldSpec("standard_max", "标准最大", field_type="float", empty_as_none=True),
    FieldSpec("decimal_places", "小数位", field_type="int", default=2),
    FieldSpec("actual_min", "虚拟最小", field_type="float", empty_as_none=True),
    FieldSpec("actual_max", "虚拟最大", field_type="float", empty_as_none=True),
    FieldSpec(
        "category", "零件类别", field_type="choice", choices=["", "common", "body", "stem", "disc"]
    ),
    FieldSpec("kind", "数据类型", field_type="choice", choices=["chemical", "mechanical"]),
    FieldSpec("is_active", "启用", field_type="bool", default=True),
]


[文档] class MaterialGradeManagerView(LookupTableManagerView): """材质牌号管理对话框(通用基类 + 材质牌号专属配置)""" def __init__( self, db_manager: Any = None, session: Any = None, dict_key: str | None = "material_grades", parent: Any = None, ) -> None: """初始化管理对话框 Args: db_manager: 数据库管理器(优先);传入后控制器持有独立会话并自行提交 session: 外部会话(与 db_manager 二选一) dict_key: 字典键名(``dictionary.<key>.csv``),缺省 ``material_grades`` parent: 父窗口 """ if db_manager is not None: controller = MaterialGradeController(db_manager=db_manager) else: controller = MaterialGradeController(db_session=session) # 先占位,避免基类 __init__ 末尾调用 refresh() 时状态栏尚未创建 self._status_label: QLabel | None = None super().__init__( controller=controller, columns=_COLUMNS, edit_fields=_EDIT_FIELDS, title="材质牌号", window_title="材质牌号管理", extra_actions=[("📥 载入示例", self._on_seed, False)], dict_key=dict_key, table_key="material_grade", parent=parent, ) # C3:数据质量状态栏——揭示「启用但范围缺失」的记录数(缺失范围会让报告列恒空) self._status_label = QLabel("") self._status_label.setStyleSheet("font-size: 11px;") layout = self.layout() assert layout is not None # 基类 __init__ 已设置 QVBoxLayout 为顶层布局 layout.addWidget(self._status_label) self._update_status() def _update_status(self) -> None: """刷新数据质量状态栏(总数/启用/缺失范围)。""" if self._status_label is None: # 基类 __init__ 期间 refresh() 早于状态栏创建 return try: summary = self._controller.get_data_quality_summary() except Exception as e: # 防御:状态栏失败不影响主功能 logger.debug(f"读取材质数据质量概览失败(忽略): {e}") return incomplete = summary["incomplete"] text = ( f"共 {summary['total']} 条 启用 {summary['active']} " f"停用 {summary['inactive']} " f"⚠ 范围缺失 {incomplete}" ) color = "#c0392b" if incomplete else "#2e7d32" self._status_label.setStyleSheet(f"font-size: 11px; color: {color};") self._status_label.setText(text)
[文档] def refresh(self) -> None: """重载表格后同步更新数据质量状态栏。""" super().refresh() self._update_status()
def _on_seed(self) -> None: """载入常见牌号示例(化学成分 + 力学性能),幂等""" try: count = self._controller.seed_common_grades() except Exception as e: logger.error(f"载入示例失败: {e}") QMessageBox.critical(self, "错误", f"载入示例失败: {e}") return if count == 0: QMessageBox.information(self, "提示", "库中已有数据,未重复写入。") else: QMessageBox.information(self, "成功", f"已载入 {count} 条示例数据。") self.refresh()