certflow.services.pressure_calc_service 源代码

"""物理计算引擎 —— 试压报告的压力与保压时间计算

对标 VBA `Fun_计算压力时间` 模块,提供:
1. Lb 压力等级 → MPa 换算(150Lb→2.0, 300Lb→5.17, 600Lb→10.34)
2. 强度试验压力(按标准号 × 公称压力倍率)
3. 上密封试验压力(按标准号 × 公称压力倍率,止回阀/蝶阀特殊处理)
4. 主密封试验压力(按标准号 × 公称压力倍率)
5. 四种保压时间查表(强度 / 上密封 / 主密封,按标准号 + 口径)

设计原则:
- 纯函数,无副作用,无 DB / 文件 I/O 依赖
- 对标 VBA 逐行语义,不一致处标注差异
- 未匹配标准号 → 返回 None / "≥",不伪造数据
"""

from __future__ import annotations

import math
from collections.abc import Callable
from dataclasses import dataclass, field
from decimal import ROUND_HALF_UP, Decimal
from typing import Any

# ============================================================
# Lb → MPa 换算表(对标 VBA Lb2MPa() 第14-54行)
# ============================================================
# VBA 原文仅实现 150/300/600 三档,其余为空白占位(Case Else → Stop)。
# CertFlow 按 config.yaml sales_plan.pn_convert.lb_to_mpa 可扩展;
# 此处内置与 PNService.LB_TO_MPA_MAP 保持一致,避免重复维护。
LB_TO_MPA: dict[int, float] = {
    150: 2.0,
    300: 5.17,
    600: 10.34,
    800: 13.0,
    900: 15.0,
    1500: 25.0,
    2500: 42.0,
}


[文档] def lb_to_mpa(lb_level: int) -> float | None: """Lb 压力等级 → MPa 数值 Args: lb_level: 压力等级(150/300/600/800/900/1500/2500) Returns: float: MPa 值,未匹配返回 None(VBA 中为 Stop) """ return LB_TO_MPA.get(lb_level)
# ============================================================ # 标准号别名归一化映射 # ============================================================ # VBA 使用 UCase(Trim(...)) 后用 Select Case Is = 逐条匹配, # 大量变体散落在各个 Case 中。此处将所有已知别名归一为规范名。 _STANDARD_ALIASES: dict[str, str] = { # API 598 系列 "API598": "API 598", "API598:2009": "API 598", "API 598-2009": "API 598", "API 598": "API 598", # GB/T 13927 系列 "GB/T 13927-2022": "GB/T 13927", "GB/T 13927-2008": "GB/T 13927", "GB/T13927": "GB/T 13927", # GB/T 26480 系列 "GB/T 26480-2011": "GB/T 26480", "GB/T26480": "GB/T 26480", # JB/T 9092 系列 "JB/T 9092-1999": "JB/T 9092", "JB/T9092": "JB/T 9092", "JB/T9092-1999": "JB/T 9092", # JB/T 3595 系列 "JB/T 3595-2002": "JB/T 3595", "JB/T3595": "JB/T 3595", # GB/T 12465 系列 "GB/T 12465-2007": "GB/T 12465", "GB/T 12465-2017": "GB/T 12465", "GB/T12465-2007": "GB/T 12465", "GB/T12465-2017": "GB/T 12465", # GB/T 12245 系列(减压阀) "GB/T 12245-2006": "GB/T 12245", "GB/T 12245-89": "GB/T 12245", "GB/T 12245-1989": "GB/T 12245", "GB/T12245-89": "GB/T 12245", "GB/T12245-1989": "GB/T 12245", "GB/T12245-06": "GB/T 12245", "GB/T12245-2006": "GB/T 12245", # GB/T 14382 系列 "GB/T 14382-2008": "GB/T 14382", "GB/T14382": "GB/T 14382", # GB/T 14478 系列 "GB/T 14478-2012": "GB/T 14478", "GB/T14478": "GB/T 14478", # GB/T 12251 系列(蒸汽疏水阀) "GB/T 12251-2005": "GB/T 12251", "GB/T 12251-1989": "GB/T 12251", "GB12251-1989": "GB/T 12251", # NB/T 47044 系列 "NB/T 47044-2014": "NB/T 47044", "NB/T47044": "NB/T 47044", # 其他 "GB12242": "GB 12242", "SL553-2011": "SL 553", "SL 553": "SL 553", "DL/T 5190.5-2019": "DL/T 5190.5", "DL/T5190.5": "DL/T 5190.5", "JB/T 7387-1994": "JB/T 7387", "JB/T7387": "JB/T 7387", "GB/T 24917-2010": "GB/T 24917", "JB/T 6446-2004": "JB/T 6446", "GB/T 10869-2008": "GB/T 10869", "背压阀外购厂家企业标准": "背压阀外购", } def _normalize_standard(standard: str) -> str: """将标准号字符串归一化为规范名。 Args: standard: 原始标准号字符串 Returns: str: 规范名,未匹配返回原始字符串的 uppercase trim """ if not standard: return "" key = standard.strip() # 先尝试精确匹配 if key in _STANDARD_ALIASES: return _STANDARD_ALIASES[key] # 再尝试 uppercase 后匹配(VBA 使用 UCase) key_upper = key.upper() for alias, canonical in _STANDARD_ALIASES.items(): if alias.upper() == key_upper: return canonical return key_upper # ============================================================ # 数据类定义 # ============================================================
[文档] @dataclass class PressureCalcInput: """物理计算输入参数 Attributes: standard: 试压标准号(如 "GB/T 13927-2022", "API 598") nominal_pressure_mpa: 公称压力(MPa 数值),英制已换算 caliber_mm: 口径(mm 数值),如 50, 100, 150 is_check_valve: 是否止回阀 is_butterfly_valve: 是否蝶阀 is_metric: 是否公制单位(True=公制, False=英制) is_imperial: 是否英制型号(用于保压时间判断) """ standard: str = "" nominal_pressure_mpa: float = 0.0 caliber_mm: float = 0.0 is_check_valve: bool = False is_butterfly_valve: bool = False is_metric: bool = True is_imperial: bool = False
[文档] @dataclass class PressureCalcResult: """物理计算结果 Attributes: strength_test_pressure: 强度试验压力(MPa 数值,None 表示无法计算) strength_test_pressure_display: 强度试验压力显示文本 upper_seal_pressure: 上密封试验压力(None 表示无此项目,如 "/") upper_seal_pressure_display: 上密封试验压力显示文本 main_seal_pressure: 主密封试验压力 main_seal_pressure_display: 主密封试验压力显示文本 strength_hold_time: 强度保压时间(如 "≥15", "≥60", "≥") upper_seal_hold_time: 上密封保压时间 main_seal_hold_time: 主密封保压时间 errors: 计算过程中的警告/错误信息列表 """ strength_test_pressure: float | None = None strength_test_pressure_display: str = "" upper_seal_pressure: float | None = None upper_seal_pressure_display: str = "" main_seal_pressure: float | None = None main_seal_pressure_display: str = "" strength_hold_time: str = "≥" upper_seal_hold_time: str = "≥" main_seal_hold_time: str = "≥" errors: list[str] = field(default_factory=list)
# ============================================================ # 压力计算 # ============================================================
[文档] class PressureCalcService: """物理计算服务 —— 试压报告的压力与保压时间计算 对标 VBA `Fun_计算压力时间` 模块的 7 个函数。 所有方法均为纯函数(无状态、无副作用),可直接用于报告生成管线。 Examples: >>> svc = PressureCalcService() >>> result = svc.calculate(PressureCalcInput( ... standard="GB/T 13927-2022", ... nominal_pressure_mpa=2.5, ... caliber_mm=100, ... )) >>> result.strength_test_pressure 3.75 >>> result.strength_hold_time '≥60' """ # ---- 核心入口 ----
[文档] def calculate(self, inp: PressureCalcInput) -> PressureCalcResult: """一次性计算所有试压参数(压力 + 保压时间) Args: inp: 输入参数 Returns: PressureCalcResult: 完整计算结果 """ result = PressureCalcResult() standard_norm = _normalize_standard(inp.standard) # 压力计算 result.strength_test_pressure = self.calc_strength_pressure( standard_norm, inp.nominal_pressure_mpa ) result.strength_test_pressure_display = _format_pressure(result.strength_test_pressure) result.upper_seal_pressure = self.calc_upper_seal_pressure( standard_norm, inp.nominal_pressure_mpa, inp.is_check_valve, inp.is_butterfly_valve, ) result.upper_seal_pressure_display = _format_pressure( result.upper_seal_pressure, none_marker="/" ) result.main_seal_pressure = self.calc_main_seal_pressure( standard_norm, inp.nominal_pressure_mpa, inp.is_check_valve, inp.is_butterfly_valve, ) result.main_seal_pressure_display = _format_pressure( result.main_seal_pressure, none_marker="" ) # 保压时间计算 result.strength_hold_time = self.calc_strength_hold_time( standard_norm, inp.caliber_mm, inp.is_check_valve, inp.is_metric ) result.upper_seal_hold_time = self.calc_upper_seal_hold_time( standard_norm, inp.caliber_mm, inp.is_metric ) result.main_seal_hold_time = self.calc_main_seal_hold_time( standard_norm, inp.caliber_mm, inp.is_check_valve, inp.is_metric ) # 标准号为空 → 所有时间返回 "≥"(VBA 第328/550/678行) if not inp.standard or not inp.standard.strip(): result.strength_hold_time = "≥" result.upper_seal_hold_time = "≥" result.main_seal_hold_time = "≥" return result
# ---- 强度试验压力(对标 VBA 第56-121行) ----
[文档] @staticmethod def calc_strength_pressure(standard_norm: str, nominal_pressure_mpa: float) -> float | None: """计算强度试验压力 标准倍率规则(对标 VBA `根据标准号计算强度试验压力`): ==================== ===== =================================== 标准号 倍率 备注 ==================== ===== =================================== API 598 1.5x Lb 已在调用前换算为 MPa GB/T 13927 1.5x GB/T 26480 1.5x JB/T 9092 1.5x JB/T 3595 1.5x GB/T 12465 1.5x GB/T 12245 1.5x 减压阀 GB/T 14382 1.5x GB/T 14478 1.5x GB 12242 1.5x 水流指示器 GB/T 12251 1.5x 蒸汽疏水阀 SL 553 1.5x DL/T 5190.5 1.5x NB/T 47044 见下 电站阀门(分级) ≤4 MPa 1.5x (等同 JB/T 3595) 4-10 MPa 1.5x (等同 GB/T 26480) 10-17 MPa 3.0x =17 MPa 48.0 (固定值, PW55 170V) 背压阀外购 4.0x ==================== ===== =================================== """ if not standard_norm or nominal_pressure_mpa <= 0: return None p = nominal_pressure_mpa # 1.5x 标准族 _1_5X_STANDARDS = { "API 598", "GB/T 13927", "GB/T 26480", "JB/T 9092", "JB/T 3595", "GB/T 12465", "GB/T 12245", "GB/T 14382", "GB/T 14478", "GB 12242", "GB/T 12251", "SL 553", "DL/T 5190.5", } if standard_norm in _1_5X_STANDARDS: return round(p * 1.5, 2) # NB/T 47044 电站阀门(分级) if standard_norm == "NB/T 47044": if p <= 4 or p < 10: return round(p * 1.5, 2) if p < 17: return round(p * 3.0, 2) if math.isclose(p, 17.0, rel_tol=0.01): return 48.0 # PW55 170V 固定值 return round(p * 1.5, 2) # 背压阀外购 if standard_norm == "背压阀外购": return round(p * 4.0, 2) # 真空阀门 / 眼镜阀 / 电站调节阀 — VBA 中无明确强度压力(空 Case) _NO_STRENGTH_STANDARDS = { "GB/T 24917", "JB/T 6446", "GB/T 10869", } if standard_norm in _NO_STRENGTH_STANDARDS: return None # 未匹配标准号 → 返回 None(VBA 返回 0,此处更安全) return None
# ---- 上密封试验压力(对标 VBA 第123-204行) ----
[文档] @staticmethod def calc_upper_seal_pressure( standard_norm: str, nominal_pressure_mpa: float, is_check_valve: bool = False, is_butterfly_valve: bool = False, # noqa: ARG004 保留参数以对齐 VBA 接口 ) -> float | None: """计算上密封试验压力 返回 None 表示无上密封试验项目(对标 VBA 返回 "/")。 返回 0.0 表示压力为 0(VBA 返回 0,如 GB/T 12465)。 关键规则: - 止回阀(check valve):多数标准无上密封 → "/" - 减压阀(GB/T 12245):无上密封 → "/" - 伸缩节(GB/T 12465):无上密封 → 0 - 蒸汽疏水阀(GB/T 12251):只有强度试验 → "/" - 背压阀外购:无上密封 → "/" - GB/T 14382:无上密封 → "/" """ if not standard_norm or nominal_pressure_mpa <= 0: return None handler = _UPPER_SEAL_PRESSURE_TABLE.get(standard_norm) if handler is None: return None # 未匹配标准号 → None(VBA 返回 0) return handler(nominal_pressure_mpa, is_check_valve)
# ---- 主密封试验压力(对标 VBA 第206-300行) ----
[文档] @staticmethod def calc_main_seal_pressure( standard_norm: str, nominal_pressure_mpa: float, is_check_valve: bool = False, is_butterfly_valve: bool = False, ) -> float | None: """计算主密封试验压力 关键规则: - API 598:所有阀门 1.1x - GB/T 26480 / JB/T 9092:止回阀 1.0x,其他 1.1x - NB/T 47044:止回阀/蝶阀 1.0x,其他按公称压力分级 - GB/T 12465 / GB/T 14382 / DL/T 5190.5:1.25x - GB 12242(水流指示器):1.2x - 背压阀外购:1.2x - GB/T 12251(蒸汽疏水阀):0(只有强度试验) - GB/T 14478:需用户输入最大净水头(此处返回 None 需人工) """ if not standard_norm or nominal_pressure_mpa <= 0: return None handler = _MAIN_SEAL_PRESSURE_TABLE.get(standard_norm) if handler is None: return None # 未匹配 → None return handler(nominal_pressure_mpa, is_check_valve, is_butterfly_valve)
# ============================================================ # 保压时间计算 # ============================================================
[文档] @staticmethod def calc_strength_hold_time( standard_norm: str, caliber_mm: float, is_check_valve: bool = False, is_metric: bool = True, ) -> str: """计算强度试验最短保压时间 对标 VBA `查找强度试验最短保压时间`(第658-861行)。 按标准号 + 口径查表,英制单位仅支持 API 598。 Returns: str: 如 "≥15", "≥60", "≥120", "≥300", "≥1800", "≥" """ if not standard_norm: return "≥" # 英制单位仅处理 API 598 if not is_metric: return _strength_time_api598(caliber_mm) if standard_norm == "API 598" else "≥" handler = _STRENGTH_HOLD_TABLE.get(standard_norm) if handler is None: return "≥" return handler(caliber_mm, is_check_valve)
[文档] @staticmethod def calc_upper_seal_hold_time( standard_norm: str, caliber_mm: float, is_metric: bool = True, ) -> str: """计算上密封试验最短保压时间 对标 VBA `查找上密封试验最短保压时间`(第530-656行)。 无上密封试验项目 → 返回 "/" 或 "≥" """ if not standard_norm: return "≥" # 英制单位仅处理 API 598 if not is_metric: if standard_norm == "API 598": return "≥15" if caliber_mm <= 50 else "≥60" return "≥" handler = _UPPER_SEAL_HOLD_TABLE.get(standard_norm) if handler is None: return "≥" return handler(caliber_mm)
[文档] @staticmethod def calc_main_seal_hold_time( standard_norm: str, caliber_mm: float, is_check_valve: bool = False, is_metric: bool = True, ) -> str: """计算主密封试验最短保压时间 对标 VBA `查找主密封试验最短保压时间`(第303-528行)。 """ if not standard_norm: return "≥" # 英制单位仅处理 API 598 if not is_metric: return ( _main_seal_time_api598(caliber_mm, is_check_valve) if standard_norm == "API 598" else "≥" ) handler = _MAIN_SEAL_HOLD_TABLE.get(standard_norm) if handler is None: return "≥" return handler(caliber_mm, is_check_valve)
# ============================================================ # 保压时间辅助函数(按标准号细分) # ============================================================ def _strength_time_api598(d: float) -> str: """API 598 强度保压时间""" if d <= 50: return "≥15" if d <= 150: return "≥60" if d <= 300: return "≥120" return "≥300" def _strength_time_13927(d: float) -> str: """GB/T 13927 强度保压时间""" if d <= 50: return "≥15" if d <= 150: return "≥60" if d <= 300: return "≥120" return "≥300" def _strength_time_26480_other(d: float) -> str: """GB/T 26480 非止回阀强度保压时间""" if d <= 50: return "≥15" if d <= 150: return "≥60" if d <= 300: return "≥120" return "≥300" def _strength_time_47044(d: float) -> str: """NB/T 47044 强度保压时间""" if d <= 50: return "≥30" if d <= 150: return "≥120" if d <= 300: return "≥180" return "≥240" def _strength_time_3595(d: float) -> str: """JB/T 3595 强度保压时间""" if d <= 125: return "≥120" if d <= 400: return "≥180" return "≥240" def _main_seal_time_api598(d: float, is_check_valve: bool = False) -> str: """API 598 主密封保压时间""" if is_check_valve: return "≥60" if d <= 150 else "≥120" if d <= 50: return "≥15" if d <= 150: return "≥60" return "≥120" def _main_seal_time_13927(d: float, is_check_valve: bool = False) -> str: """GB/T 13927 主密封保压时间""" if is_check_valve: return "≥60" if d <= 150 else "≥120" if d <= 50: return "≥15" if d <= 150: return "≥60" return "≥120" def _main_seal_time_26480_other(d: float) -> str: """GB/T 26480 非止回阀主密封保压时间""" if d <= 50: return "≥15" if d <= 150: return "≥60" return "≥120" def _main_seal_time_47044(d: float) -> str: """NB/T 47044 主密封保压时间""" if d <= 50: return "≥30" if d <= 150: return "≥60" if d <= 300: return "≥120" return "≥180" def _main_seal_time_3595(d: float) -> str: """JB/T 3595 主密封保压时间""" if d <= 125: return "≥60" if d <= 400: return "≥120" return "≥180" # ============================================================ # 压力 / 保压时间派发表(对标 VBA Select Case,按标准号分发) # 将 calc_* 中的长 if 标准号==X 分支链改为查表,复杂度更低且更易核对。 # ============================================================ def _upper_seal_pressure_47044(p: float, is_check_valve: bool = False) -> float | None: """NB/T 47044 上密封压力(分级,对标 VBA)""" if p <= 4 or p < 10: return round(p * 1.1, 2) if p < 17: return round(p * 2.2, 2) if math.isclose(p, 17.0, rel_tol=0.01): return 36.0 # PW55 170V 固定值 return round(p * 1.1, 2) def _main_seal_pressure_47044( p: float, is_check_valve: bool = False, is_butterfly_valve: bool = False ) -> float | None: """NB/T 47044 主密封压力(分级 + 止回阀/蝶阀)""" if is_check_valve or is_butterfly_valve: return round(p * 1.0, 2) if p <= 4 or p < 10: return round(p * 1.1, 2) if p < 17: return round(p * 2.2, 2) if math.isclose(p, 17.0, rel_tol=0.01): return 36.0 # PW55 170V 固定值 return round(p * 1.1, 2) def _strength_hold_26480_9092(d: float, is_check_valve: bool = False) -> str: """GB/T 26480 / JB/T 9092 强度保压(止回阀特殊)""" if is_check_valve: return "≥60" if d <= 300 else "≥120" return _strength_time_26480_other(d) def _strength_hold_12251(d: float, is_check_valve: bool = False) -> str: """GB/T 12251 蒸汽疏水阀强度保压""" if d <= 50: return "≥15" if d <= 150: return "≥60" return "≥" def _upper_seal_hold_47044(d: float) -> str: """NB/T 47044 上密封保压""" if d <= 150: return "≥15" if d <= 300: return "≥20" return "≥60" def _main_seal_hold_26480_9092(d: float, is_check_valve: bool = False) -> str: """GB/T 26480 / JB/T 9092 主密封保压(止回阀特殊)""" if is_check_valve: return "≥60" if d <= 300 else "≥120" return _main_seal_time_26480_other(d) def _main_seal_hold_12245(d: float, is_check_valve: bool = False) -> str: """GB/T 12245 减压阀主密封保压""" if d <= 50: return "≥60" if d <= 125: return "≥120" return "≥180" # 上密封试验压力派发表:标准号 -> handler(p, is_check_valve) _UPPER_SEAL_PRESSURE_TABLE: dict[str, Callable[[float, bool], float | None]] = { "API 598": lambda p, c=False: None if c else round(p * 1.1, 2), "GB/T 13927": lambda p, c=False: round(p * 1.1, 2), "JB/T 7387": lambda p, c=False: round(p * 1.1, 2), "JB/T 3595": lambda p, c=False: round(p * 1.1, 2), "GB/T 26480": lambda p, c=False: None if c else round(p * 1.1, 2), "JB/T 9092": lambda p, c=False: None if c else round(p * 1.1, 2), "GB/T 12465": lambda p, c=False: 0.0, "GB/T 14478": lambda p, c=False: 0.0, "SL 553": lambda p, c=False: 0.0, "NB/T 47044": _upper_seal_pressure_47044, "GB/T 12251": lambda p, c=False: None, "GB/T 12245": lambda p, c=False: None, "GB/T 14382": lambda p, c=False: None, "背压阀外购": lambda p, c=False: None, "DL/T 5190.5": lambda p, c=False: round(p * 1.25, 2), } # 主密封试验压力派发表:标准号 -> handler(p, is_check_valve, is_butterfly_valve) _MAIN_SEAL_PRESSURE_TABLE: dict[str, Callable[[float, bool, bool], float | None]] = { "API 598": lambda p, c=False, b=False: round(p * 1.1, 2), "GB 12242": lambda p, c=False, b=False: round(p * 1.2, 2), "GB/T 13927": lambda p, c=False, b=False: round(p * 1.1, 2), "JB/T 3595": lambda p, c=False, b=False: round(p * 1.1, 2), "SL 553": lambda p, c=False, b=False: round(p * 1.1, 2), "GB/T 26480": lambda p, c=False, b=False: round(p * 1.0, 2) if c else round(p * 1.1, 2), "JB/T 9092": lambda p, c=False, b=False: round(p * 1.0, 2) if c else round(p * 1.1, 2), "GB/T 12465": lambda p, c=False, b=False: round(p * 1.25, 2), "GB/T 14382": lambda p, c=False, b=False: round(p * 1.25, 2), "DL/T 5190.5": lambda p, c=False, b=False: round(p * 1.25, 2), "GB/T 14478": lambda p, c=False, b=False: round(p * 1.1, 2), "NB/T 47044": _main_seal_pressure_47044, "GB/T 12251": lambda p, c=False, b=False: 0.0, "JB/T 7387": lambda p, c=False, b=False: 0.0, "GB/T 12245": lambda p, c=False, b=False: round(p * 1.1, 2), "背压阀外购": lambda p, c=False, b=False: round(p * 1.2, 2), } # 强度保压时间派发表:标准号 -> handler(d, is_check_valve) _STRENGTH_HOLD_TABLE: dict[str, Callable[[float, bool], str]] = { "API 598": lambda d, c=False: _strength_time_api598(d), "GB 12242": lambda d, c=False: "≥60", "GB/T 13927": lambda d, c=False: _strength_time_13927(d), "GB/T 26480": _strength_hold_26480_9092, "JB/T 9092": _strength_hold_26480_9092, "NB/T 47044": lambda d, c=False: _strength_time_47044(d), "JB/T 3595": lambda d, c=False: _strength_time_3595(d), "GB/T 12465": lambda d, c=False: "≥300", "GB/T 14478": lambda d, c=False: "≥1800", "SL 553": lambda d, c=False: "≥1800", "GB/T 12251": _strength_hold_12251, "GB/T 12245": lambda d, c=False: _strength_time_13927(d), "GB/T 14382": lambda d, c=False: "≥600", "背压阀外购": lambda d, c=False: "≥180", "DL/T 5190.5": lambda d, c=False: _strength_time_47044(d), "JB/T 7387": lambda d, c=False: "≥", } # 上密封保压时间派发表:标准号 -> handler(d) _UPPER_SEAL_HOLD_TABLE: dict[str, Callable[[float], str]] = { "API 598": lambda d: "≥15" if d <= 50 else "≥60", "GB 12242": lambda d: "水流指示器没有上密封检测项目", "GB/T 13927": lambda d: "≥15" if d <= 50 else "≥60", "GB/T 26480": lambda d: "≥15" if d <= 50 else "≥60", "JB/T 9092": lambda d: "≥15" if d <= 50 else "≥60", "GB/T 12465": lambda d: "/", "GB/T 14478": lambda d: "/", "SL 553": lambda d: "/", "NB/T 47044": _upper_seal_hold_47044, "JB/T 3595": lambda d: "/", "GB/T 12251": lambda d: "\\", "JB/T 7387": lambda d: "≥180", "GB/T 12245": lambda d: "/", "GB/T 14382": lambda d: "/", "背压阀外购": lambda d: "/", "DL/T 5190.5": lambda d: _strength_time_47044(d), } # 主密封保压时间派发表:标准号 -> handler(d, is_check_valve) _MAIN_SEAL_HOLD_TABLE: dict[str, Callable[[float, bool], str]] = { "API 598": lambda d, c=False: _main_seal_time_api598(d, c), "GB 12242": lambda d, c=False: "≥30", "GB/T 13927": lambda d, c=False: _main_seal_time_13927(d, c), "GB/T 26480": _main_seal_hold_26480_9092, "JB/T 9092": _main_seal_hold_26480_9092, "NB/T 47044": lambda d, c=False: _main_seal_time_47044(d), "JB/T 3595": lambda d, c=False: _main_seal_time_3595(d), "GB/T 12465": lambda d, c=False: "≥300", "GB/T 14478": lambda d, c=False: "≥1800", "SL 553": lambda d, c=False: "≥1800", "GB/T 12251": lambda d, c=False: "\\", "JB/T 7387": lambda d, c=False: "≥", "GB/T 12245": _main_seal_hold_12245, "GB/T 14382": lambda d, c=False: "≥600", "背压阀外购": lambda d, c=False: "≥120", "DL/T 5190.5": lambda d, c=False: _main_seal_time_47044(d), } # ============================================================ # 显示格式化 # ============================================================ def _format_pressure(value: float | None, none_marker: str = "") -> str: """将压力数值格式化为显示字符串。 Args: value: 压力数值(MPa),None 表示无法计算 none_marker: None 时的占位符(上密封用 "/") Returns: str: 如 "3.75", "48.0", "/", "" """ if value is None: return none_marker if value == 0.0: return "0" # 保留最多 2 位小数,去掉末尾无意义的 0; # 使用 decimal 做四舍五入,保证 5.17*1.5=7.755 → 7.76(向远离零方向进位)。 quantized = Decimal(str(value)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) return f"{quantized:.2f}".rstrip("0").rstrip(".") # ============================================================ # 便捷函数(供 report_service 直接调用) # ============================================================
[文档] def compute_pressure_params( standard: str, nominal_pressure_mpa: float, caliber_mm: float, is_check_valve: bool = False, is_butterfly_valve: bool = False, is_imperial: bool = False, ) -> dict[str, Any]: """便捷函数:一次性计算所有试压参数,返回字典。 供 report_service.py 直接调用,无需创建 PressureCalcInput 对象。 Args: standard: 试压标准号 nominal_pressure_mpa: 公称压力(MPa) caliber_mm: 口径(mm) is_check_valve: 是否止回阀 is_butterfly_valve: 是否蝶阀 is_imperial: 是否英制型号 Returns: dict: 包含所有压力和时间字段的字典,可直接 merge 到 report_data """ svc = PressureCalcService() result = svc.calculate( PressureCalcInput( standard=standard or "", nominal_pressure_mpa=nominal_pressure_mpa, caliber_mm=caliber_mm, is_check_valve=is_check_valve, is_butterfly_valve=is_butterfly_valve, is_metric=not is_imperial, is_imperial=is_imperial, ) ) return { "strength_test_pressure": result.strength_test_pressure_display, "strength_hold_time": result.strength_hold_time, "upper_seal_pressure": result.upper_seal_pressure_display, "upper_seal_hold_time": result.upper_seal_hold_time, "main_seal_pressure": result.main_seal_pressure_display, "main_seal_hold_time": result.main_seal_hold_time, }