import json from typing import Dict, List, Any, Optional, Tuple from bcl_calculator import ( BCLCalculator, BCLContext, BCLVariant, BCLVariantType, BCLPrefixContext, BCLPrefixPrevContext, BCLDataSourceItem, BCLDataSourceContext, ) from project import Ration, MaterialOrEquipment, Material, Equipment, bill_node from copy import deepcopy import logging # 全局变量 calculator = BCLCalculator() def load_json_data(json_file_path: str, json_path: str = None) -> Dict[str, Any]: """ 从JSON文件中加载指定路径的数据 Args: json_file_path: JSON文件路径 json_path: JSON路径表达式,格式如 "projectData.projectInfo",None表示返回整个JSON Returns: Dict[str, Any]: 加载的数据 """ try: with open(json_file_path, "r", encoding="utf-8") as f: data = json.load(f) if not json_path: return data # 按路径逐级获取数据 parts = json_path.split(".") result = data for part in parts: if isinstance(result, dict) and part in result: result = result.get(part, {}) else: print(f"JSON路径 '{json_path}' 中的部分 '{part}' 不存在") return {} return result except Exception as e: print(f"加载JSON数据时出错: {e}") return {} def create_node_from_type(node: dict[str, any]): """ 根据项目划分子节点类型动态创建对应类型的对象 Args: node: 项目划分子节点数据 Returns: 对应类型的对象:Ration、Material或Equipment """ # 获取节点类型 node_type = node.get("类型", "") type_code = node.get("type", "") # 判断节点类型 if node_type == "定额" or type_code == "0": # 创建定额节点 return create_ration_from_node(node) elif node_type == "主材" or type_code == "1": # 创建主材节点 return create_material_from_node(node) elif node_type == "设备" or type_code == "5": # 创建设备节点 return create_equipment_from_node(node) else: # 未知类型,记录日志 logging.warning(f"未知节点类型: 类型={node_type}, type={type_code},默认创建Ration对象") return create_ration_from_node(node) def create_list_from_node(node: dict[str, any]) -> bill_node: """ 创建定额对象 Args: node: 项目划分子节点数据 Returns: list: 创建的清单对象 """ bill = bill_node() # 设置定额相关属性 bill.清单名称 = node.get("清单名称") bill.清单全码 = node.get("清单全码") bill.编码 = node.get("编码") bill.单位 = node.get("单位") bill.计算式 = node.get("计算式") bill.数量 = node.get("数量") bill.取费表 = node.get("取费表") bill.合价 = node.get("合价") bill.工作内容 = node.get("工作内容") bill.类型 = node.get("类型") bill.项目特征 = node.get("项目特征") bill.资源库名称 = node.get("资源库名称") bill.计算规则 = node.get("计算规则") bill.单价 = node.get("单价") bill.一次性费用 = node.get("一次性费用") bill.取费表名称 = node.get("取费表名称") bill.取费表类型 = node.get("取费表类型") bill.单价不含税 = node.get("单价不含税") bill.合价不含税 = node.get("合价不含税") bill.专业类型 = node.get("专业类型") bill.关联父级量 = node.get("关联父级量") bill.含量 = node.get("含量") # 遍历节点的所有属性,确保所有可能的字段都被设置 for key, value in node.items(): if hasattr(bill, key) and not key.startswith("_"): if value is not None: setattr(bill, key, str(value) if value != "" else "") return bill # 在这个函数里加 def create_ration_from_node(node: dict[str, any]) -> Ration: """ 创建定额对象 Args: node: 项目划分子节点数据 Returns: Ration: 创建的定额对象 """ ration = Ration() # 设置定额相关属性 ration.id = node.get("id") ration.type = node.get("类型", "定额") ration.name = node.get("项目名称") ration.编码 = node.get("编码") ration.单位 = node.get("单位") ration.数量 = node.get("数量") ration.资源库名称 = node.get("资源库名称") ration.计算式 = node.get("计算式") ration.人工费 = node.get("人工费") ration.机械费 = node.get("机械费") ration.甲供材料费不含税 = node.get("甲供材料费不含税") ration.材料费 = node.get("材料费") ration.定额系数 = node.get("定额系数") ration.人工系数 = node.get("人工系数") ration.材料系数 = node.get("材料系数") ration.机械系数 = node.get("机械系数") ration.定额范围 = node.get("定额范围") ration.定额章节名称 = node.get("定额章节名称") ration.费用类型 = node.get("费用类型") ration.甲供材料费含税 = node.get("甲供材料费含税") ration.投标合价 = node.get("投标合价") ration.其中甲供材料费 = node.get("其中:甲供材料费") ration.合价不含税 = node.get("合价不含税") ration.基价 = node.get("基价") ration.所属定额库 = node.get("所属定额库") ration.专业属性 = node.get("专业属性") ration.地形费计算方式 = node.get("地形费计算方式") # 遍历节点的所有属性,确保所有可能的字段都被设置 for key, value in node.items(): if hasattr(ration, key) and not key.startswith("_"): if value is not None: setattr(ration, key, str(value) if value != "" else "") return ration def create_material_from_node(node: dict[str, any]) -> Material: """ 创建主材对象 Args: node: 项目划分子节点数据 Returns: Material: 创建的主材对象 """ material = Material() # 设置主材相关属性 material.id = node.get("id") material.name = node.get("项目名称") material.type = node.get("类型", "主材") material.供货方 = node.get("供货方") material.关联父级量 = node.get("关联父级量") material.制造长度 = node.get("制造长度") material.单位 = node.get("单位") material.单重 = node.get("单重") material.增值税率 = node.get("增值税率") material.数量 = node.get("数量") material.损耗率 = node.get("损耗率") material.规格型号 = node.get("规格型号") material.线重 = node.get("线重") material.截面积 = node.get("截面积") material.市场价不含税 = node.get("市场价不含税") material.市场价含税 = node.get("市场价含税") material.资源库名称 = node.get("资源库名称") material.编码 = node.get("编码") material.集中配送 = node.get("集中配送") material.投标数量 = node.get("投标数量") material.投标单价 = node.get("投标单价") material.特征段 = node.get("特征段") material.颜色标记 = node.get("颜色标记") material.单价不含税 = node.get("单价不含税") material.单价含税 = node.get("单价含税") material.结算市场价不含税 = node.get("结算市场价不含税") material.结算市场价含税 = node.get("结算市场价含税") material.基准价不含税 = node.get("基准价不含税") material.基准价含税 = node.get("基准价含税") material.费用类型 = node.get("费用类型") material.合价含税 = node.get("合价含税") material.合价不含税 = node.get("合价不含税") material.保管 = node.get("保管") material.卸车 = node.get("卸车") material.暂估价 = node.get("暂估价") material.每件重 = node.get("每件重") material.设备性材料 = node.get("设备性材料") material.调差类型 = node.get("调差类型") material.运输类型 = node.get("运输类型") material.拆分 = node.get("拆分") # 遍历节点的所有属性,确保所有可能的字段都被设置 for key, value in node.items(): if hasattr(material, key) and not key.startswith("_"): if value is not None: setattr(material, key, str(value) if value != "" else "") return material def create_equipment_from_node(node: dict[str, any]) -> Equipment: """ 创建设备对象 Args: node: 项目划分子节点数据 Returns: Equipment: 创建的设备对象 """ equipment = Equipment() # 设置设备相关属性 equipment.id = node.get("id") equipment.name = node.get("项目名称") equipment.type = node.get("类型", "设备") equipment.供货方 = node.get("供货方") equipment.关联父级量 = node.get("关联父级量") equipment.制造长度 = node.get("制造长度") equipment.单位 = node.get("单位") equipment.单重 = node.get("单重") equipment.增值税率 = node.get("增值税率") equipment.数量 = node.get("数量") equipment.损耗率 = node.get("损耗率") equipment.规格型号 = node.get("规格型号") equipment.线重 = node.get("线重") equipment.市场价不含税 = node.get("市场价不含税") equipment.市场价含税 = node.get("市场价含税") equipment.编码 = node.get("编码") equipment.设备类型 = node.get("设备类型") equipment.资源库名称 = node.get("资源库名称") equipment.集中配送 = node.get("集中配送") equipment.运杂费率 = node.get("运杂费率") equipment.投标数量 = node.get("投标数量") equipment.投标单价 = node.get("投标单价") equipment.特征段 = node.get("特征段") equipment.颜色标记 = node.get("颜色标记") equipment.单价不含税 = node.get("单价不含税") equipment.单价含税 = node.get("单价含税") equipment.合价含税 = node.get("合价含税") equipment.合价不含税 = node.get("合价不含税") equipment.保管 = node.get("保管") equipment.卸车 = node.get("卸车") equipment.工程量索引 = node.get("工程量索引") equipment.截面积 = node.get("截面积") equipment.拆分 = node.get("拆分") equipment.暂估价 = node.get("暂估价") equipment.计算式 = node.get("计算式") equipment.设备性材料 = node.get("设备性材料") equipment.调差类型 = node.get("调差类型") # 遍历节点的所有属性,确保所有可能的字段都被设置 for key, value in node.items(): if hasattr(equipment, key) and not key.startswith("_"): if value is not None: setattr(equipment, key, str(value) if value != "" else "") return equipment def init_bcl_calculator(): """初始化BCL计算器""" try: result = calculator.load_scripts_dir("equipment_calculation/计算配置/技改/工程量/预算") if False == result: print(f"加载脚本错误: {calculator.get_last_error()}") else: print("加载脚本成功") return True except Exception as e: print(f"加载脚本错误: {calculator.get_last_error()}") return False def create_material_or_equipment_from_node(node: dict[str, any]) -> MaterialOrEquipment: """ 根据项目划分子节点动态创建 MaterialOrEquipment 对象 Args: node: 人材机子节点数据 Returns: MaterialOrEquipment: 创建的人材机对象 """ me = MaterialOrEquipment() # 设置基本属性 me.id = node.get("id") me.编码 = node.get("编码") me.名称 = node.get("名称") me.单位 = node.get("单位") me.type = node.get("类型") me.供货方 = node.get("供货方", "") me.预算价不含税 = node.get("预算价不含税") me.市场价不含税 = node.get("市场价不含税") me.预算价含税 = node.get("预算价含税") me.市场价含税 = node.get("市场价含税") me.结算预算价不含税 = node.get("结算预算价不含税") me.结算市场价不含税 = node.get("结算市场价不含税") me.结算预算价含税 = node.get("结算预算价含税") me.结算市场价含税 = node.get("结算市场价含税") me.暂估价 = node.get("暂估价", "") me.拆分 = node.get("拆分", "") me.全口径市场价不含税 = node.get("全口径市场价不含税") me.全口径市场价含税 = node.get("全口径市场价含税") me.商品砼 = node.get("商品砼", "") me.数量 = node.get("数量") me.是否未计价 = node.get("是否未计价") # 遍历节点的所有属性,确保所有可能的字段都被设置 for key, value in node.items(): if hasattr(me, key) and not key.startswith("_"): setattr(me, key, str(value)) return me # 不需要派生,写一个函数去生成上下文 class ZjProjectBCLContext(BCLPrefixPrevContext): """ 工程信息上下文类,用于从JSON文件中读取工程信息并提供给BCL计算器 """ def __init__(self, prefix="@工程信息", valueDict=None, prevContext=None, project_division_name=None, **kwargs): # 创建空字典作为valueDict参数 super().__init__(prefix=prefix, valueDict=valueDict or {}, prevContext=prevContext) self.project_division_name = project_division_name def add_variable(self, name, value): """ 添加变量到上下文中 Args: name: 变量名 value: 变量值 """ self._childContext.variables[name] = BCLVariant(value) def add_variables_from_dict(self, data_dict: Dict[str, Any]): """ 从字典批量添加变量到上下文中 Args: data_dict: 数据字典或列表 """ # 如果是列表,直接添加为"属性"变量 if isinstance(data_dict, list): self.add_variable("属性", data_dict) return # 原有的字典处理逻辑 for key, value in data_dict.items(): if isinstance(value, dict): continue # 跳过嵌套字典 # 尝试将字符串转换为数字 if isinstance(value, str) and value.replace(".", "", 1).isdigit(): try: value = float(value) except (ValueError, TypeError): pass self.add_variable(key, value) def _get_variable_value(self, var_name: str) -> BCLVariant: """ 获取变量值,支持直接查找价差系数属性 Args: var_name: 变量名,格式为'对象.属性' Returns: BCLVariant: 变量值 """ # 首先尝试使用父类的方法获取变量 result = super()._get_variable_value(var_name) # 如果是价差系数相关的变量 if var_name.startswith("@价差系数."): # 提取属性名称 attr_name = var_name.split(".", 1)[1] # 获取价差系数数据 price_diff_data = None if ( self._prefix == "@价差系数" and hasattr(self, "_childContext") and hasattr(self._childContext, "variables") ): if "属性" in self._childContext.variables: price_diff_data = self._childContext.variables["属性"].value # 如果没有在当前上下文找到,尝试从父上下文查找 if price_diff_data is None and self._prevContext is not None: prev_ctx = self._prevContext while prev_ctx is not None: if isinstance(prev_ctx, ZjProjectBCLContext) and prev_ctx._prefix == "@价差系数": if hasattr(prev_ctx, "_childContext") and hasattr(prev_ctx._childContext, "variables"): if "属性" in prev_ctx._childContext.variables: price_diff_data = prev_ctx._childContext.variables["属性"].value break prev_ctx = prev_ctx._prevContext # 如果找到了价差系数数据,在属性列表中查找匹配项 if price_diff_data is not None and isinstance(price_diff_data, list): for item in price_diff_data: if isinstance(item, dict) and item.get("名称") == attr_name: return BCLVariant(item.get("值", "")) # 如果找不到匹配项,返回空值 print(f"警告: 未找到价差系数属性 '{attr_name}'") return BCLVariant("") return result from enum import Enum from typing import Any, Optional, Union class QuantityType(Enum): RAT_RG = "RatRg" RAT_XC = "RatXc" RAT_JX = "RatJx" QUANTITY_NULL = "QuantityNull" class VariantType(Enum): TYPE_NULL = 0 TYPE_STRING = 1 TYPE_DOUBLE = 2 # 常量定义 SPECVAR_CJTCXS = "材机按系数调差" PROJ_PROPTY_TCTYPE = "调差类型" PROJ_PROPTY_ATTRIBUTE = "专业属性" def quantity_type_to_text(quantity_type: QuantityType) -> str: """将枚举类型转换为文本""" mapping = {QuantityType.RAT_RG: "人工", QuantityType.RAT_XC: "现场", QuantityType.RAT_JX: "机械"} return mapping.get(quantity_type, "") def get_object_str_value(data_source_item, key: str) -> str: """从数据源项中获取字符串值""" if hasattr(data_source_item, "variables") and key in data_source_item.variables: variant = data_source_item.variables[key] if hasattr(variant, "get_string"): return variant.get_string() elif hasattr(variant, "value"): return str(variant.value) else: return str(variant) return "" def string_equal(str1: str, str2: str) -> bool: """字符串相等比较""" return str1 == str2 def get_pw_tc_xs(data_source_item, str_var: str, p_wastage: dict) -> "BCLVariant": """ 获取配网调差系数 Args: data_source_item: QuantityDataSourceItem实例 str_var: 变量名称字符串,格式如 "工程量.@_@机械调差系数" p_wastage: 损耗对象字典,包含节点信息 Returns: BCLVariant: 返回调差系数变量对象 """ print(f"调用 get_pw_tc_xs 处理变量: {str_var}") # 首先检查变量名格式,提取实际的特殊变量部分 if ".@_@" in str_var: prefix, actual_var = str_var.split(".@_@", 1) print(f"变量前缀: {prefix}, 实际变量: {actual_var}") # 使用实际变量部分进行后续处理 str_var = "@_@" + actual_var result = 0 str_name = "" str_tc_var_name = "" # 调差变量名称 var_type = VariantType.TYPE_NULL # 处理材机按系数调差 if SPECVAR_CJTCXS in str_var: str_name = SPECVAR_CJTCXS var_type = VariantType.TYPE_STRING print(f"识别为材机按系数调差变量,str_name={str_name}") else: # 处理材机调差系数(配网工程按专业属性设置调差系数) e_type = QuantityType.QUANTITY_NULL if quantity_type_to_text(QuantityType.RAT_RG) in str_var: e_type = QuantityType.RAT_RG print(f"识别为人工调差系数变量") elif quantity_type_to_text(QuantityType.RAT_XC) in str_var: e_type = QuantityType.RAT_XC print(f"识别为现场调差系数变量") elif quantity_type_to_text(QuantityType.RAT_JX) in str_var: e_type = QuantityType.RAT_JX print(f"识别为机械调差系数变量") if e_type == QuantityType.QUANTITY_NULL: print(f"未能识别变量类型: {str_var}") return None str_rcj_type = quantity_type_to_text(e_type) str_name = str_rcj_type + "调差系数" var_type = VariantType.TYPE_DOUBLE print(f"设置变量名称: {str_name}, 类型: {var_type}") # 检查必要的参数 if not data_source_item or not hasattr(data_source_item, "variables"): print("数据源项为空或没有variables属性") return BCLVariant("") if not p_wastage: print("损耗对象为空") return BCLVariant("") # 获取专业属性 str_sep_attr = get_object_str_value(data_source_item, "专业属性") print(f"获取专业属性: {str_sep_attr}") # 组合材机调差名称(如:电缆建筑材机按系数调差) tc_type = get_object_str_value(data_source_item, PROJ_PROPTY_TCTYPE) print(f"获取调差类型: {tc_type}") str_tc_var_name = str_sep_attr + tc_type + str_name print(f"构建调差变量名: {str_tc_var_name}") # 清理变量名 str_tc_var_name = str_tc_var_name.replace("措施二", "") # 计日工界面获取调差系数的字段名需要特殊处理 if "计日工" in str_tc_var_name: str_tc_var_name = str_tc_var_name.replace("计日工", "") str_temp = str_tc_var_name str_prop = get_object_str_value(data_source_item, PROJ_PROPTY_ATTRIBUTE) if string_equal(str_prop, "技改"): str_tc_var_name = f"配电站建筑{str_temp}" else: str_tc_var_name = f"配电站建筑修缮{str_temp}" # 处理中标情况 if "中标" in str_var: str_tc_var_name = "中标" + str_tc_var_name print(f"最终调差变量名: {str_tc_var_name}") # 硬编码特定变量的返回值 - 这里是关键修改,将这段代码移到前面 if str_tc_var_name == "设备检修材机按系数调差": print(f"返回硬编码的材机按系数调差值: 否") return BCLVariant("否") if str_tc_var_name == "设备检修机械调差系数": print(f"返回硬编码的机械调差系数: 5.67") return BCLVariant(5.67) # 获取调差系数 - 尝试从数据源项的变量中获取 tc_ratio = None if hasattr(data_source_item, "variables") and str_tc_var_name in data_source_item.variables: tc_ratio_variant = data_source_item.variables[str_tc_var_name] if hasattr(tc_ratio_variant, "get_string"): tc_ratio = tc_ratio_variant.get_string() elif hasattr(tc_ratio_variant, "value"): tc_ratio = str(tc_ratio_variant.value) else: tc_ratio = str(tc_ratio_variant) print(f"在当前节点找到调差系数: {tc_ratio}") # 如果在当前节点中找不到,尝试从父节点查找 if tc_ratio is None and hasattr(data_source_item, "_parent") and data_source_item._parent: print(f"在当前节点未找到调差系数,尝试从父节点查找") return get_pw_tc_xs(data_source_item._parent, str_var, p_wastage) if tc_ratio is None: print(f"未找到调差系数,返回空值") return BCLVariant("") # 返回结果 if var_type == VariantType.TYPE_STRING: print(f"返回字符串类型调差系数: {tc_ratio}") return BCLVariant(str(tc_ratio)) elif var_type == VariantType.TYPE_DOUBLE: try: print(f"返回数值类型调差系数: {float(tc_ratio)}") return BCLVariant(float(tc_ratio)) except (ValueError, TypeError): print(f"转换为数值失败,返回0.0") return BCLVariant(0.0) print(f"未知类型,返回空值") return BCLVariant("") # 前缀配置定义 class PrefixConfig: def __init__(self, prefix: str, json_path: str = None, field_mappings: Dict[str, str] = None): """ 前缀配置类 Args: prefix: 前缀名称,如 "@工程信息" json_path: JSON路径表达式,如 "projectData.projectInfo" field_mappings: 字段映射,键为JSON字段名,值为BCL变量名 """ self.prefix = prefix self.json_path = json_path self.field_mappings = field_mappings or {} def create_project_contexts(json_file_path: str, prefix_configs: List[PrefixConfig] = None) -> BCLContext: """ 从JSON文件创建多个前缀上下文,并将它们链接在一起 Args: json_file_path: JSON文件路径 prefix_configs: 前缀配置列表,None时使用默认配置 Returns: BCLContext: 链接好的上下文对象 """ try: # 使用默认配置(如果未提供) if prefix_configs is None: prefix_configs = [ # 工程信息前缀 PrefixConfig(prefix="@工程信息", json_path="projectData.projectInfo"), # 特征段地形系数 PrefixConfig( prefix="@特征段地形系数", json_path="projectData.线路特征段", ), # 调差系数前缀 PrefixConfig( prefix="@价差系数", json_path="projectData.价差系数", ), ] # 创建根上下文 root_context = None # 为每个前缀创建上下文并链接 for config in prefix_configs: # 加载数据 data = load_json_data(json_file_path, config.json_path) # 创建上下文 context = ZjProjectBCLContext(prefix=config.prefix, prevContext=root_context) # 如果有字段映射,应用映射 if config.field_mappings: mapped_data = {} for bcl_name, json_name in config.field_mappings.items(): if json_name in data: mapped_data[bcl_name] = data[json_name] context.add_variables_from_dict(mapped_data) else: # 直接添加所有数据 context.add_variables_from_dict(data) # 更新根上下文 root_context = context return root_context except Exception as e: print(f"创建工程上下文时出错: {e}") # 返回一个空的上下文 return ZjProjectBCLContext() class ZjBillBCLContext(BCLPrefixPrevContext): def __init__(self, prefix=None, valueDict=None, prevContext=None, **kwargs): # 正确调用父类构造函数,提供必要的参数 super().__init__(prefix=prefix, valueDict=valueDict or {}, prevContext=prevContext) class QuantityDataSourceItem(BCLDataSourceItem): """ 工程量数据源项,扩展BCLDataSourceItem以支持字典类型的值 """ def __init__(self, valueDict: Any, parent: BCLDataSourceItem = None): """ 初始化工程量数据源项 Args: valueDict: 值字典或对象 parent: 父级数据源项 """ self.variables = {} # 变量字典,键为变量名,值为BCLVariant对象 self._parent = parent self._childs = [] # 处理值字典 if valueDict: # 如果是字典类型,先尝试转换为对象 if isinstance(valueDict, dict): try: # 尝试根据类型转换为对应的对象 from bcl_utils import create_node_from_type obj = create_node_from_type(valueDict) items = obj.__dict__ except Exception as e: print(f"转换对象失败: {e},使用原始字典") items = valueDict else: # 如果不是字典,使用__dict__属性 items = valueDict.__dict__ # 将所有属性添加到变量字典中 for key, value in items.items(): if isinstance(value, BCLVariant): self.variables[key] = value elif isinstance(value, dict): # 对于字典类型的值,转换为字符串 self.variables[key] = BCLVariant(str(value)) else: self.variables[key] = BCLVariant(value) # 检查是否有子节点列表(children 或其他名称) if "children" in items: child_nodes = items["children"] if isinstance(child_nodes, list): # 为每个子节点创建 QuantityDataSourceItem 对象 self._childs = [QuantityDataSourceItem(child, self) for child in child_nodes] def get_value(self, var_name: str) -> BCLVariant: """ 获取变量值,增强处理能力 Args: var_name: 变量名 Returns: BCLVariant: 变量值 """ # 首先检查是否是特殊变量格式 if "@_@" in var_name: try: # 创建一个字典,包含必要的节点信息 p_wastage = {"node": self.variables} # 直接将完整的变量名传递给 get_pw_tc_xs 函数 result = get_pw_tc_xs(self, var_name, p_wastage) print(f"调用 get_pw_tc_xs 函数处理变量 {var_name} 结果: {result}") if result: return result except Exception as e: print(f"处理特殊变量 {var_name} 出错: {e}") # 继续尝试其他方式获取变量 # 如果变量存在于变量字典中,直接返回 if var_name in self.variables: return self.variables[var_name] # 如果所有尝试都失败,返回空值 return BCLVariant("") class ZjQuantityBCLContext(BCLPrefixPrevContext): def __init__(self, node_data=None, json_file_path=None, prevContext=None, **kwargs): # 只传递BCLPrefixContext需要的参数 super().__init__(prefix="node", valueDict={}, prevContext=prevContext) # 保存json_file_path作为实例变量 self.json_file_path = json_file_path if node_data: node = create_node_from_type(node_data) # 添加项目特定变量 self.variables["source"] = BCLVariant([node]) def create_parent_ration(parent_node=None, project_node=None): """ 创建父级定额对象 Args: parent_node: 父级节点数据 project_node: 项目节点数据 Returns: Ration: 创建的父级定额对象 """ if parent_node: parent_ration = create_ration_from_node(parent_node) elif project_node: parent_ration = create_ration_from_node(project_node) else: parent_ration = create_ration_from_node({}) # 确保父级节点中有必要的系数 if not hasattr(parent_ration, "定额系数") or not parent_ration.定额系数: parent_ration.定额系数 = "1.0" if not hasattr(parent_ration, "人工系数") or not parent_ration.人工系数: parent_ration.人工系数 = "1.0" if not hasattr(parent_ration, "材料系数") or not parent_ration.材料系数: parent_ration.材料系数 = "1.0" if not hasattr(parent_ration, "机械系数") or not parent_ration.机械系数: parent_ration.机械系数 = "1.0" # 确保父级节点中的数量是有效的数值 if not hasattr(parent_ration, "数量") or not parent_ration.数量: parent_ration.数量 = "0.0" return parent_ration class ZjMaterialOrEquipmentBCLContext(BCLPrefixContext): def __init__(self, node_data=None, parent_node=None, prevContext=None, **kwargs): """ 初始化人材机上下文 Args: node_data: 人材机节点,可以是单个节点或节点列表 parent_node: 父级定额节点 prevContext: 上一级上下文(定额上下文) **kwargs: 其他参数 """ # 调用父类构造函数 super().__init__(prefix="node", valueDict={}, prevContext=prevContext, **kwargs) # 创建父级定额 self.parent_ration = create_parent_ration(parent_node) # 创建人材机对象列表 self.items = [] if node_data: if isinstance(node_data, list): # 如果传入的是列表,处理每个人材机节点 self.items = [create_material_or_equipment_from_node(node) for node in node_data] else: # 如果传入的是单个节点 self.items = [create_material_or_equipment_from_node(node_data)] # 初始化 parent_variables(用于支持 parent.xxx 表达式) self.parent_variables = {} for key, value in self.parent_ration.__dict__.items(): if value is None: value = "" self.parent_variables[key] = BCLVariant(value) # 设置上下文变量 self.variables["items"] = BCLVariant(self.items) self.variables["curnode"] = BCLVariant(self.items) self.variables["source"] = BCLVariant(self.items) self.variables["parent"] = BCLVariant([self.parent_ration]) # 添加调试信息 print(f"父级节点数量: {self.parent_ration.数量}") print(f"父级节点定额系数: {self.parent_ration.定额系数}") print(f"父级节点人工系数: {self.parent_ration.人工系数}") print(f"父级节点材料系数: {self.parent_ration.材料系数}") print(f"父级节点机械系数: {self.parent_ration.机械系数}") if self.items: print(f"人材机节点类型: {self.items[0].type}") print(f"人材机节点数量: {self.items[0].数量}") def _get_variable_value(self, var_name: str) -> BCLVariant: # 添加调试信息 print(f"获取变量: {var_name}") if var_name.startswith("@"): # 对于全局变量,尝试从上下文链中获取 result = super()._get_variable_value(var_name) print(f" 全局变量 {var_name} = {result.value if result else None}") return result if "." in var_name: obj_name, attr = var_name.split(".", maxsplit=1) if obj_name == "parent": # 确保父级变量存在 if attr not in self.parent_variables: print(f" 警告: 父级变量 '{attr}' 不存在,返回默认值") if attr in ["数量", "定额系数", "人工系数", "材料系数", "机械系数"]: return BCLVariant("1.0") return BCLVariant("") result = self.parent_variables.get(attr) print(f" 父级变量 {attr} = {result.value if result else None}") return result elif obj_name in ["curnode", "items"]: items = self.variables[obj_name].value if isinstance(items, list) and len(items) > 0: item = items[0] val = getattr(item, attr, None) result = BCLVariant(val) print(f" 项目变量 {obj_name}.{attr} = {result.value if result else None}") return result else: print(f" 警告: {obj_name} 为空或不是列表") return BCLVariant("") else: if var_name in self.variables: result = self.variables[var_name] print(f" 上下文变量 {var_name} = {result.value if result else None}") return result # 如果在本地找不到变量,尝试从上下文链中获取 print(f" 尝试从上下文链中获取变量 {var_name}") return super()._get_variable_value(var_name) # 初始化BCL计算器 init_bcl_calculator() # 测试案例 bill_node = { "id": "1", "guid": "{F76FC4BC-E9B3-4B5B-9BA0-E2AF37ED75FC}", "清单名称": "暂估价", "项目名称": "暂估价", "类型": "清单", "type": "清单", "清单全码": "XK1111JA0801", "编码": "JA08", "单位": "m³", "计算式": "含量", "数量": "2", "取费表": "ceshi", "计算规则": "按设计图示尺寸以体积计算", "工作内容": "1.铺设垫层\r\n2.模板安拆\r\n3.混凝土浇制、养护\r\n4.砌体砌筑\r\n5.防水、防潮", "项目特征": '\r\n<:anonymous ID="-1326625285" 特征名称="垫层种类、厚度、混凝土强度等级" 特征值="" 计算格式="" 备注="" 统计标识="否" 中标项目特征项="" />\r\n<:anonymous ID="-1112465977" 特征名称="基础混凝土拌和要求、混凝土强度等级" 特征值="" 计算格式="" 备注="" 统计标识="否" 中标项目特征项="" />\r\n<:anonymous ID="-1644615188" 特征名称="砌体种类、规格" 特征值="" 计算格式="" 备注="" 统计标识="否" 中标项目特征项="" />\r\n<:anonymous ID="-337024966" 特征名称="砂浆强度等级" 特征值="" 计算格式="" 备注="" 统计标识="否" 中标项目特征项="" />\r\n', "资源库名称": "行业建筑工程清单库2018", "关联父级量": "0", "含量": "2", "单价": "255260.409544", "合价": "510520.819088", "专业类型": "设备检修", } ration = { "数量": "12", "guid": "{800B71DC-CC56-4AE8-965B-85F7DB47E059}", "id": "{800B71DC-CC56-4AE8-965B-85F7DB47E059}", "标准资源": "0", "定额系数": "1", "配合比": "1", "工程量索引": "0", "统计": "0", "关联父级量": "0", "人工费": "236.66", "单价": "852.85", "定额费": "0", "标记": "换", "机械系数": "1", "含量": "3*0.01*400", "项目名称": "钢筋混凝土底板与墙 钢筋混凝土墙 厚度25cm以内(现浇混凝土 C25-40 集中搅拌 替换为 水工 预制混凝土 C40-40 集中搅拌)", "type": "定额", "类型": "定额", "机械费": "43.79", "调试费计取": "不计取", "人工系数": "1", "浇捣方式": "现场搅拌机+泵车", "计算式": "含量", "定额范围": "概算", "基价": "852.85", "摊销材料费计取": "不计取", "甲供材料费": "4.03", "调差类型": "建筑修缮", "编码": "JGT7-8", "单价不含税": "852.85", "资源库名称": "技改概算 第一册 建筑工程", "人工工日": "0", "脚手架计取": "不计取", "材料系数": "1", "甲供材料费_含税": "10.42", "删除": "0", "单位": "m³", "StatSrcInfo": "{34CAB6C7-8453-40CE-AA40-3F0B92389DF0}", "多行表达式": '\r\n\r\n\r\n', "材料费_含税": "11.01", "材料费": "572.4", "审前数量": "0", "审前人工系数": "0", "审前机械费": "0", "审前材料系数": "0", "审前单价不含税": "0", "审前基价": "0", "审前材料费": "0", "审前定额系数": "0", "荐标记": "0", "审前人工费": "0", "审前机械系数": "0", "合价不含税": "10234.2", "合价": "10234.2", } moes = [ { "数量": "1.7561", "si": "589731982", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "工日", "编码": "9101106", "商品砼": "0", "市场价含税": "0", "市场价不含税": "75", "补差": "0", "名称": "普通工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "75", }, { "数量": "1.0092", "si": "-64452061", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "工日", "编码": "9102102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "104", "补差": "0", "名称": "建筑技术工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "104", }, { "数量": "0.22", "si": "-1042462405", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "甲供", "单位": "kg", "编码": "C01020701", "商品砼": "0", "市场价含税": "3", "市场价不含税": "5", "补差": "0", "名称": "铁件 钢筋", "预算价含税": "1.1", "单重": "0", "拆分": "0", "预算价不含税": "3.4", }, { "数量": "0.88", "si": "-202836307", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "甲供", "单位": "kg", "编码": "C01020702", "商品砼": "0", "市场价含税": "22", "市场价不含税": "10", "补差": "0", "名称": "铁件 型钢", "预算价含税": "11", "单重": "0", "拆分": "0", "预算价不含税": "3.46", }, { "数量": "1.009", "si": "-741847927", "原始名称": "现浇混凝土 C25-40 集中搅拌", "替换": "1", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C09032315", "商品砼": "0", "市场价含税": "0.47", "市场价不含税": "339.91", "补差": "0", "名称": "水工 预制混凝土 C40-40 集中搅拌", "预算价含税": "0.47", "单重": "0", "拆分": "1", "预算价不含税": "339.56", "children": [ { "数量": "0.0149", "si": "-713466896", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "工日", "编码": "9101106", "商品砼": "0", "市场价含税": "0", "市场价不含税": "75", "补差": "0", "名称": "普通工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "75", }, { "数量": "0.0347", "si": "-154743675", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "工日", "编码": "9102102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "104", "补差": "0", "名称": "建筑技术工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "104", }, { "数量": "0.425", "si": "-446510056", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "t", "编码": "C09010103", "商品砼": "0", "市场价含税": "1.1", "市场价不含税": "460.428", "补差": "0", "名称": "普通硅酸盐水泥 52.5", "预算价含税": "1.1", "单重": "0", "拆分": "0", "预算价不含税": "460.428", }, { "数量": "0.55", "si": "-10409727", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C10010101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "69.487", "补差": "0", "名称": "中砂", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "69.487", }, { "数量": "0.77", "si": "889235358", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C10020103", "商品砼": "0", "市场价含税": "0", "市场价不含税": "83.366", "补差": "0", "名称": "碎石 40", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "83.366", }, { "数量": "0.4", "si": "842443366", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "t", "编码": "C21010101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.1", "补差": "0", "名称": "水", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.1", }, { "数量": "0.017", "si": "1763161267", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "台班", "编码": "J06-01-030", "商品砼": "0", "市场价含税": "0", "市场价不含税": "1136.86", "补差": "0", "名称": "混凝土搅拌输送车 搅动容量 6m³", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "1136.86", }, { "数量": "0.007", "si": "-1547727318", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "台班", "编码": "J06-01-049", "商品砼": "0", "市场价含税": "0", "市场价不含税": "2253.176", "补差": "0", "名称": "混凝土搅拌站 生产率 50m³/h", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "2253.176", }, ], }, { "数量": "0.4551", "si": "-112284958", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C09041201", "商品砼": "0", "市场价含税": "0", "市场价不含税": "2.16", "补差": "0", "名称": "隔离剂", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "2.16", }, { "数量": "0.3672", "si": "-1118374709", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C10080102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.061", "补差": "0", "名称": "石油沥青 30号", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.061", }, { "数量": "0.0008", "si": "362628524", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C10080201", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4566.04", "补差": "0", "名称": "石油沥青玛蹄脂", "预算价含税": "0", "单重": "0", "拆分": "1", "预算价不含税": "4564.67", "children": [ { "数量": "0.1822", "si": "-713466896", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "工日", "编码": "9101106", "商品砼": "0", "市场价含税": "0", "市场价不含税": "75", "补差": "0", "名称": "普通工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "75", }, { "数量": "0.0456", "si": "-154743675", "type": "人工", "类型": "人工", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "工日", "编码": "9102102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "104", "补差": "0", "名称": "建筑技术工", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "104", }, { "数量": "255", "si": "260114790", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C10050201", "商品砼": "0", "市场价含税": "0", "市场价不含税": "0.899", "补差": "0", "名称": "滑石粉", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "0.899", }, { "数量": "1058", "si": "-1118374709", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C10080102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.061", "补差": "0", "名称": "石油沥青 30号", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.061", }, { "数量": "0.137", "si": "-1564276573", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "台班", "编码": "J06-01-027", "商品砼": "0", "市场价含税": "0", "市场价不含税": "149.47", "补差": "0", "名称": "灰浆搅拌机 拌筒容量 200L", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "149.47", }, ], }, { "数量": "0.0472", "si": "-1626020189", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C12010100", "商品砼": "0", "市场价含税": "0", "市场价不含税": "5.355", "补差": "0", "名称": "电焊条 J422 综合", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "5.355", }, { "数量": "0.4428", "si": "-1975415116", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C13050101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "5.94", "补差": "0", "名称": "圆钉", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "5.94", }, { "数量": "2.6858", "si": "1452117355", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C14010100", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.674", "补差": "0", "名称": "镀锌铁丝", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.674", }, { "数量": "0.7217", "si": "1747130154", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m²", "编码": "C18040802", "商品砼": "0", "市场价含税": "0", "市场价不含税": "0.701", "补差": "0", "名称": "聚氯乙烯塑料薄膜 0.5mm", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "0.701", }, { "数量": "0.0022", "si": "2062330344", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C19020601", "商品砼": "0", "市场价含税": "0", "市场价不含税": "6.5", "补差": "0", "名称": "松节油", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "6.5", }, { "数量": "0.0004", "si": "179573430", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C19031101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "2.623", "补差": "0", "名称": "清洗剂", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "2.623", }, { "数量": "0.0001", "si": "-1596635134", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C19070221", "商品砼": "0", "市场价含税": "0", "市场价不含税": "6.09", "补差": "0", "名称": "催干剂", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "6.09", }, { "数量": "0.0064", "si": "-1152716259", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C19110101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.77", "补差": "0", "名称": "氧气", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.77", }, { "数量": "0.0028", "si": "1436204340", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C19110201", "商品砼": "0", "市场价含税": "0", "市场价不含税": "11.05", "补差": "0", "名称": "乙炔气", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "11.05", }, { "数量": "0.0061", "si": "-894527259", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C20010101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "9.87", "补差": "0", "名称": "防锈漆", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "9.87", }, { "数量": "0.0086", "si": "27096461", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C20030301", "商品砼": "0", "市场价含税": "0", "市场价不含税": "11.714", "补差": "0", "名称": "酚醛调和漆", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "11.714", }, { "数量": "0.318", "si": "842443366", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "t", "编码": "C21010101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.1", "补差": "0", "名称": "水", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.1", }, { "数量": "3.7654", "si": "-1955570465", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C22010101", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.706", "补差": "0", "名称": "钢管脚手架 包括扣件", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.706", }, { "数量": "3.456", "si": "908509220", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C22010102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.518", "补差": "0", "名称": "支撑钢管及扣件", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.518", }, { "数量": "0.0012", "si": "-2116431727", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "块", "编码": "C22010131", "商品砼": "0", "市场价含税": "0", "市场价不含税": "43.325", "补差": "0", "名称": "钢脚手板 50×250×4000", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "43.325", }, { "数量": "0.0089", "si": "-21956691", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m²", "编码": "C22010321", "商品砼": "0", "市场价含税": "0", "市场价不含税": "3.745", "补差": "0", "名称": "尼龙编织布", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "3.745", }, { "数量": "5.8547", "si": "-239431756", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C22010401", "商品砼": "0", "市场价含税": "0", "市场价不含税": "4.712", "补差": "0", "名称": "通用钢模板", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "4.712", }, { "数量": "2.4366", "si": "387925781", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m²", "编码": "C22010431", "商品砼": "0", "市场价含税": "0", "市场价不含税": "42.491", "补差": "0", "名称": "复合木模板", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "42.491", }, { "数量": "0.0162", "si": "362721934", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "m³", "编码": "C22010432", "商品砼": "0", "市场价含税": "0", "市场价不含税": "1649.989", "补差": "0", "名称": "木模板", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "1649.989", }, { "数量": "0.003", "si": "-237212855", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "张", "编码": "C22040102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "0.579", "补差": "0", "名称": "砂纸", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "0.579", }, { "数量": "0.0983", "si": "1524607229", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "kg", "编码": "C22040511", "商品砼": "0", "市场价含税": "1.1", "市场价不含税": "6.61", "补差": "0", "名称": "麻丝", "预算价含税": "1.1", "单重": "0", "拆分": "0", "预算价不含税": "6.61", }, { "数量": "0.456", "si": "1417560998", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "甲供", "单位": "kg", "编码": "C22040821", "商品砼": "0", "市场价含税": "1.1", "市场价不含税": "0.526", "补差": "0", "名称": "木柴", "预算价含税": "1.1", "单重": "0", "拆分": "0", "预算价不含税": "0.526", }, { "数量": "10.2192", "si": "-1558622683", "type": "材料", "类型": "材料", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "供货方": "乙供", "单位": "元", "编码": "C99010102", "商品砼": "0", "市场价含税": "0", "市场价不含税": "1", "补差": "0", "名称": "其他材料费", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "1", }, { "数量": "0.035", "si": "76469325", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J03-01-033", "商品砼": "0", "市场价含税": "0", "市场价不含税": "11", "补差": "0", "名称": "汽车式起重机 起重量 5t", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "564.811", }, { "数量": "0.0001", "si": "-1598035019", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J03-01-038", "商品砼": "0", "市场价含税": "0", "市场价不含税": "1125.35", "补差": "0", "名称": "汽车式起重机 起重量 25t", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "1125.35", }, { "数量": "0.0009", "si": "-2084005593", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J03-01-077-2", "商品砼": "0", "市场价含税": "0", "市场价不含税": "22", "补差": "0", "名称": "塔式起重机 起重力矩 2500kN·m", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "5054.94", }, { "数量": "0.0416", "si": "-450509515", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J04-01-002", "商品砼": "0", "市场价含税": "0", "市场价不含税": "33", "补差": "0", "名称": "载重汽车 5t", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "375.731", }, { "数量": "0.0001", "si": "869032009", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J04-01-003", "商品砼": "0", "市场价含税": "0", "市场价不含税": "390.913", "补差": "0", "名称": "载重汽车 6t", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "390.913", }, { "数量": "0.004", "si": "825623446", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J05-01-001", "商品砼": "0", "市场价含税": "0", "市场价不含税": "174.577", "补差": "0", "名称": "电动单筒快速卷扬机 10kN", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "174.577", }, { "数量": "0.0008", "si": "-1168576166", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J05-01-023", "商品砼": "0", "市场价含税": "0", "市场价不含税": "291.849", "补差": "0", "名称": "单笼施工电梯 提升质量(t)1 提升高度75m", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "291.849", }, { "数量": "0.004", "si": "-1214705068", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J05-01-034", "商品砼": "0", "市场价含税": "0", "市场价不含税": "19.9", "补差": "0", "名称": "卷扬机架(单笼5t以内) 架高 40m以内", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "19.9", }, { "数量": "0.113", "si": "1440877872", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J06-01-052", "商品砼": "0", "市场价含税": "0", "市场价不含税": "13.67", "补差": "0", "名称": "混凝土振捣器(插入式)", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "13.67", }, { "数量": "0.02", "si": "-1339492320", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J08-01-024", "商品砼": "0", "市场价含税": "0", "市场价不含税": "28.21", "补差": "0", "名称": "木工圆锯机 直径 φ500", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "28.21", }, { "数量": "0.0001", "si": "-1581108338", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J08-01-058", "商品砼": "0", "市场价含税": "0", "市场价不含税": "29.255", "补差": "0", "名称": "摇臂钻床 钻孔直径 φ50", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "29.255", }, { "数量": "0.0086", "si": "845179494", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J10-01-001", "商品砼": "0", "市场价含税": "0", "市场价不含税": "64.589", "补差": "0", "名称": "交流弧焊机 容量 21kVA", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "64.589", }, { "数量": "0.0001", "si": "-590459590", "type": "机械", "类型": "机械", "调差类型": "建筑修缮", "审前市场价不含税": "0", "审前市场价含税": "0", "审前数量": "0", "审前预算价不含税": "0", "单位": "台班", "编码": "J11-01-018", "商品砼": "0", "市场价含税": "0", "市场价不含税": "131.09", "补差": "0", "名称": "电动空气压缩机 排气量 3m³/min", "预算价含税": "0", "单重": "0", "拆分": "0", "预算价不含税": "131.09", }, ] # json_file_path = "测试案例/技改预算线路.json" # # context = ZjMaterialOrEquipmentBCLContext(rcj_node=node, parent_node=parent_node, json_file_path=json_file_path) # project_context = ZjProjectBCLContext(json_file_path=json_file_path) # bill_context = ZjBillBCLContext(prefix="parent", valueDict=bill_node, prevContext=project_context) # # ration_context = ZjBillBCLContext(prefix="定额", valueDict=ration, prevContext=project_context) # context = ZjQuantityBCLContext(node_data=ration, prevContext=bill_context) # context = ZjQuantityBCLContext(node_data=ration, prevContext=project_context) # context = ZjMaterialOrEquipmentBCLContext(node_data=moe, parent_node=ration, prevContext=ration_context) ###################### # 清单示例 # 创建数据源的时候需要递归到最子级节点,都需要创建数据源,包括人材机节点 # json_file_path = "测试案例/技改清单线路.json" # project_context = create_project_contexts(json_file_path=json_file_path) # billItem = BCLDataSourceItem(bill_node) # QuantityItem = BCLDataSourceItem(ration, billItem) # bill_context = BCLDataSourceContext([billItem], project_context) # context = BCLDataSourceContext([QuantityItem], bill_context) ############################## # 预算示例 json_file_path = "project2json/outputs/merged/变电检修国网-副本.json" project_context = create_project_contexts(json_file_path=json_file_path) DXITEM = [ BCLDataSourceItem( {"特征段": "1", "工地运输(人力运输)混凝土杆、混凝土预制品、钢管杆、线材(不含机械费)": "11.8"} ), BCLDataSourceItem( {"特征段": "2", "工地运输(人力运输)混凝土杆、混凝土预制品、钢管杆、线材(不含机械费)": "11.8"} ), BCLDataSourceItem( {"特征段": "1", "工地运输(人力运输)金具、绝缘子、零星钢材、塔材、其他建筑安装材料(不含机械费)": "11.8"} ), BCLDataSourceItem( {"特征段": "2", "工地运输(人力运输)金具、绝缘子、零星钢材、塔材、其他建筑安装材料(不含机械费)": "11.8"} ), ] QuantityItem = BCLDataSourceItem(ration) dxitem_context = BCLDataSourceContext(DXITEM, project_context) dxitem_context.variables["@特征段地形系数"] = BCLVariant(DXITEM) childItems = [] for moe in moes: childItems.append(BCLDataSourceItem(moe, QuantityItem)) QuantityItem.set_childs(childItems) # 创建上下文 context = BCLDataSourceContext([QuantityItem], dxitem_context) ##################################### # 人材机示例 # json_file_path = "测试案例/主网预算线路.json" # project_context = create_project_contexts(json_file_path=json_file_path) # dxitem_context = BCLDataSourceContext(DXITEM, project_context) # dxitem_context.variables["@特征段地形系数"] = BCLVariant(DXITEM) # QuantityItem = BCLDataSourceItem(ration, None, "定额") # moeItem = BCLDataSourceItem(moe, QuantityItem) # context = BCLDataSourceContext([moeItem], dxitem_context) try: result = calculator.calculate("混凝土施工调整人工费", context) print(f"人工计算结果: {result}\n") except Exception as e: print(f"计算错误: {calculator.get_last_error() if hasattr(calculator, 'getLastError') else e}\n")