增加了知识图谱导出excel
This commit is contained in:
@@ -28,11 +28,12 @@ from equipment_calculation.item_acquisition import (
|
||||
# 缓存已计算过的费用
|
||||
calculated_fees = {}
|
||||
|
||||
# 添加一个全局变量和一个缓存字典来存储清单数量
|
||||
_BILL_QUANTITY = 1.0
|
||||
bill_quantity_cache = {}
|
||||
# # 添加一个全局变量和一个缓存字典来存储清单数量
|
||||
# _BILL_QUANTITY = 1.0
|
||||
# bill_quantity_cache = {}
|
||||
|
||||
|
||||
# 主网处理地形系数
|
||||
def process_DXdata(json_data):
|
||||
"""
|
||||
处理 projectData 中的线路特征段数据,计算每条 bpBillZhXsTable 记录的加权值,
|
||||
@@ -102,40 +103,39 @@ def process_DXdata(json_data):
|
||||
|
||||
|
||||
# 在create_list_from_node函数后添加一个包装函数
|
||||
def create_list_from_node_with_quantity(node, quantity=None):
|
||||
"""创建清单对象并设置数量"""
|
||||
def create_list_from_node_with_bill_quantity(node, quantity=None):
|
||||
"""创建清单对象并设置数量,不使用全局变量"""
|
||||
from equipment_calculation.bcl_utils import create_list_from_node
|
||||
|
||||
bill_obj = create_list_from_node(node)
|
||||
|
||||
# 设置清单数量
|
||||
bill_quantity = quantity if quantity is not None else node.get("数量")
|
||||
if quantity is not None:
|
||||
bill_quantity = quantity
|
||||
elif "数量" in node:
|
||||
try:
|
||||
bill_quantity = float(node["数量"])
|
||||
except (ValueError, TypeError):
|
||||
bill_quantity = 1.0
|
||||
else:
|
||||
bill_quantity = 1.0
|
||||
|
||||
# 设置到对象属性
|
||||
bill_obj.quantity = bill_quantity
|
||||
|
||||
# 保存到全局变量和缓存
|
||||
global _BILL_QUANTITY
|
||||
_BILL_QUANTITY = bill_quantity
|
||||
|
||||
# 如果节点有ID,保存到缓存
|
||||
bill_id = node.get("id") or node.get("GUID")
|
||||
if bill_id:
|
||||
bill_quantity_cache[bill_id] = bill_quantity
|
||||
|
||||
# 设置环境变量作为后备方案
|
||||
os.environ["BILL_QUANTITY"] = str(bill_quantity)
|
||||
|
||||
if hasattr(bill_obj, "quantity"):
|
||||
bill_obj.quantity = bill_quantity
|
||||
else:
|
||||
# 如果对象没有quantity属性,尝试设置到其他可能的属性
|
||||
try:
|
||||
setattr(bill_obj, "quantity", bill_quantity)
|
||||
except:
|
||||
pass
|
||||
print(f"设置清单对象数量: {bill_quantity}")
|
||||
print(f"全局变量_BILL_QUANTITY: {_BILL_QUANTITY}")
|
||||
if bill_id:
|
||||
print(f"缓存清单{bill_id}的数量: {bill_quantity_cache[bill_id]}")
|
||||
|
||||
return bill_obj
|
||||
|
||||
|
||||
# 递归查找取费表中包含"取费基数"的节点
|
||||
def find_fee_base_nodes(node: Dict[str, Any], result: List = None) -> List[Dict[str, Any]]:
|
||||
def find_fee_base_nodes(node: Dict[str, Any], result: List[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
递归查找取费表中包含"取费基数"的节点或有子节点的费用项
|
||||
|
||||
@@ -449,21 +449,11 @@ def calculate_all_fees(
|
||||
calculation_strategy=None,
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
计算项目节点的所有费用
|
||||
|
||||
Args:
|
||||
project_node: 工程量节点
|
||||
cost_table: 取费表
|
||||
json_file_path: JSON文件路径,用于获取工程信息
|
||||
engineering_type: 工程类型,如"清单工程"或"预算工程"
|
||||
calculation_strategy: 计算策略,如果为None则使用默认策略
|
||||
|
||||
Returns:
|
||||
Dict[str, float]: 费用计算结果
|
||||
计算项目节点的所有费用,确保清单数量正确传递
|
||||
"""
|
||||
results = {}
|
||||
|
||||
# 1. 工程信息上下文 ,在这里暂时先将参数项目划分名称固定
|
||||
# 1. 工程信息上下文
|
||||
project_context = create_project_contexts(json_file_path=json_file_path)
|
||||
|
||||
with open(json_file_path, "r", encoding="utf-8") as file:
|
||||
@@ -478,9 +468,9 @@ def calculate_all_fees(
|
||||
# 获取清单节点
|
||||
bill_id = project_node.get("bill_id")
|
||||
bill_name = project_node.get("bill_name")
|
||||
bill_node = project_node.get("bill_node")
|
||||
if not bill_node:
|
||||
bill_node = {
|
||||
bill_node_data = project_node.get("bill_node")
|
||||
if not bill_node_data:
|
||||
bill_node_data = {
|
||||
"id": bill_id,
|
||||
"GUID": bill_id,
|
||||
"清单名称": bill_name,
|
||||
@@ -491,16 +481,9 @@ def calculate_all_fees(
|
||||
}
|
||||
|
||||
# 使用包装函数创建清单对象
|
||||
# bill_obj = create_list_from_node_with_quantity(bill_node)
|
||||
bill_obj = create_list_from_node(bill_node)
|
||||
# 如果清单节点有数量,确保它被保存到bill_obj
|
||||
if "数量" in bill_node:
|
||||
bill_obj.quantity = float(bill_node["数量"])
|
||||
print(f"设置清单对象数量: {bill_obj.quantity}")
|
||||
bill_obj = create_list_from_node_with_bill_quantity(bill_node_data)
|
||||
|
||||
# 创建工程量对象
|
||||
from equipment_calculation.bcl_utils import create_node_from_type
|
||||
|
||||
project_obj = create_node_from_type(project_node)
|
||||
|
||||
dxitem_context = BCLDataSourceContext(DXITEM, project_context)
|
||||
@@ -508,17 +491,23 @@ def calculate_all_fees(
|
||||
|
||||
# 递归数据源链式上下文
|
||||
billItem = BCLDataSourceItem(bill_obj)
|
||||
# 设置一个显式的数量属性
|
||||
# billItem.bill_quantity = float(bill_node.get("数量", 1.0))
|
||||
# print(f"设置清单数据源项数量: {billItem.bill_quantity}")
|
||||
|
||||
# 将清单数量直接设置到billItem对象上
|
||||
if hasattr(bill_obj, "quantity"):
|
||||
billItem.bill_quantity = bill_obj.quantity
|
||||
print(f"设置清单数据源项数量: {billItem.bill_quantity}")
|
||||
|
||||
QuantityItem = BCLDataSourceItem(project_obj, billItem)
|
||||
bill_context = BCLDataSourceContext([billItem], dxitem_context)
|
||||
context = BCLDataSourceContext([QuantityItem], bill_context)
|
||||
|
||||
# 如果计算策略存在,设置清单数量
|
||||
if calculation_strategy and hasattr(calculation_strategy, "set_bill_quantity"):
|
||||
if hasattr(bill_obj, "quantity"):
|
||||
calculation_strategy.set_bill_quantity(bill_obj.quantity)
|
||||
print(f"设置计算策略的清单数量: {bill_obj.quantity}")
|
||||
else:
|
||||
# 非清单工程 - 工程信息 -> 工程量节点
|
||||
from equipment_calculation.bcl_utils import create_node_from_type
|
||||
|
||||
project_obj = create_node_from_type(project_node)
|
||||
|
||||
dxitem_context = BCLDataSourceContext(DXITEM, project_context)
|
||||
@@ -527,16 +516,10 @@ def calculate_all_fees(
|
||||
QuantityItem = BCLDataSourceItem(project_obj)
|
||||
context = BCLDataSourceContext([QuantityItem], dxitem_context)
|
||||
|
||||
# 打印项目节点信息,用于调试
|
||||
node_name = project_node.get("项目名称", project_node.get("name", "未知节点"))
|
||||
print(f"\n处理项目节点: {node_name}")
|
||||
|
||||
# 查找包含取费基数的节点
|
||||
fee_base_nodes = find_fee_base_nodes(cost_table)
|
||||
|
||||
# 计算每个费用项
|
||||
# 先计算基本费用项,再计算复合费用项
|
||||
# 这里简单按照节点在列表中的顺序计算,可能需要更复杂的依赖解析
|
||||
for node in fee_base_nodes:
|
||||
fee_name = node.get("费用名称", node.get("name", "未知费用"))
|
||||
fee_code = node.get("代码", "")
|
||||
@@ -715,17 +698,7 @@ def calculate_quantity_fees(
|
||||
calculation_strategy=None,
|
||||
) -> str:
|
||||
"""
|
||||
计算工程量取费表
|
||||
|
||||
Args:
|
||||
json_file_path: JSON文件路径
|
||||
project_name: 项目名称
|
||||
engineering_type: 工程类型
|
||||
project_guid: 项目GUID,用于区分同名项目
|
||||
calculation_strategy: 计算策略,如果为None则使用默认策略
|
||||
|
||||
Returns:
|
||||
str: 输出文件路径
|
||||
计算工程量取费表,不使用全局变量,并按清单节点组织结果
|
||||
"""
|
||||
# 如果没有提供计算策略,使用默认策略
|
||||
if calculation_strategy is None:
|
||||
@@ -734,7 +707,13 @@ def calculate_quantity_fees(
|
||||
calculation_strategy = DefaultCalculationStrategy()
|
||||
|
||||
# 设置输出目录和文件名
|
||||
output_dir = "计算结果"
|
||||
# 检查calculation_strategy是否有get_output_dir方法
|
||||
if hasattr(calculation_strategy, "get_output_dir"):
|
||||
output_dir = calculation_strategy.get_output_dir()
|
||||
else:
|
||||
# 兼容旧代码,使用默认目录
|
||||
output_dir = "计算结果"
|
||||
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# 获取项目划分节点的GUID
|
||||
@@ -781,8 +760,10 @@ def calculate_quantity_fees(
|
||||
f"{safe_project_name}{safe_project_guid}_{engineering_type}_calculation_results.json",
|
||||
)
|
||||
|
||||
# 在处理清单工程时,保存清单数量供后续使用
|
||||
# 创建一个字典来存储清单数量
|
||||
bill_quantities = {}
|
||||
# 创建一个字典来存储清单信息
|
||||
bill_info = {}
|
||||
|
||||
# 根据工程类型获取取费表和项目节点
|
||||
if engineering_type == "预算工程":
|
||||
@@ -809,6 +790,7 @@ def calculate_quantity_fees(
|
||||
|
||||
# 获取清单节点信息
|
||||
bill_id = project_node.get("bill_id")
|
||||
bill_name = project_node.get("bill_name", "未命名清单")
|
||||
fee_table_name = project_node.get("取费表名称")
|
||||
|
||||
if not bill_id:
|
||||
@@ -819,9 +801,17 @@ def calculate_quantity_fees(
|
||||
print(f"工程量节点 '{node_name}' 没有取费表名称")
|
||||
continue
|
||||
|
||||
# 保存清单信息
|
||||
if bill_id not in bill_info:
|
||||
bill_info[bill_id] = {
|
||||
"name": bill_name,
|
||||
"fee_table_name": fee_table_name,
|
||||
"guid": bill_id.replace("{", "").replace("}", "") if bill_id else "",
|
||||
}
|
||||
|
||||
# 使用清单节点的取费表名称直接查找取费表
|
||||
if bill_id not in cost_tables:
|
||||
print(f"查找清单节点 '{project_node.get('bill_name', '未命名清单')}' 的取费表: {fee_table_name}")
|
||||
print(f"查找清单节点 '{bill_name}' 的取费表: {fee_table_name}")
|
||||
|
||||
# 查找取费表
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
@@ -843,7 +833,7 @@ def calculate_quantity_fees(
|
||||
continue
|
||||
|
||||
cost_tables[bill_id] = cost_table_children
|
||||
print(f"成功获取清单节点 '{project_node.get('bill_name', '未命名清单')}' 的取费表")
|
||||
print(f"成功获取清单节点 '{bill_name}' 的取费表")
|
||||
|
||||
# 在读取JSON文件后,遍历项目中的清单节点,获取并保存清单数量
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
@@ -853,10 +843,7 @@ def calculate_quantity_fees(
|
||||
bill_data = project_data.get("bill", {})
|
||||
|
||||
# 递归函数获取所有清单节点
|
||||
def get_bill_nodes(node, results=None):
|
||||
if results is None:
|
||||
results = []
|
||||
|
||||
def get_bill_nodes(node):
|
||||
if isinstance(node, dict):
|
||||
# 检查是否是清单节点
|
||||
is_bill = (
|
||||
@@ -864,39 +851,36 @@ def calculate_quantity_fees(
|
||||
)
|
||||
|
||||
if is_bill and ("id" in node or "GUID" in node):
|
||||
bill_id = node.get("id") or node.get("GUID")
|
||||
# 强制使用GUID而不是ID
|
||||
bill_id = node.get("GUID") or node.get("guid") or node.get("id")
|
||||
quantity = 1.0 # 默认值
|
||||
if "数量" in node:
|
||||
try:
|
||||
quantity = float(node["数量"])
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
results.append((bill_id, quantity))
|
||||
# 保存到字典
|
||||
bill_quantities[bill_id] = quantity
|
||||
|
||||
# 直接设置到全局变量和缓存
|
||||
global _BILL_QUANTITY
|
||||
_BILL_QUANTITY = quantity
|
||||
bill_quantity_cache[bill_id] = quantity
|
||||
# 补充清单信息
|
||||
if bill_id not in bill_info:
|
||||
bill_info[bill_id] = {
|
||||
"name": node.get("清单名称", "未命名清单"),
|
||||
"fee_table_name": node.get("取费表名称", ""),
|
||||
"guid": bill_id.replace("{", "").replace("}", "") if bill_id else "",
|
||||
}
|
||||
|
||||
# 设置环境变量
|
||||
os.environ["BILL_QUANTITY"] = str(quantity)
|
||||
|
||||
print(f"设置清单 {bill_id} 的数量为全局变量: {quantity}")
|
||||
print(f"保存清单 {bill_id} 的数量: {quantity}")
|
||||
|
||||
# 递归处理子节点
|
||||
if "children" in node and isinstance(node["children"], list):
|
||||
for child in node["children"]:
|
||||
get_bill_nodes(child, results)
|
||||
|
||||
return results
|
||||
get_bill_nodes(child)
|
||||
|
||||
# 获取和设置清单数量
|
||||
get_bill_nodes(bill_data)
|
||||
|
||||
# 如果有计算策略,设置清单数量
|
||||
if calculation_strategy and hasattr(calculation_strategy, "set_bill_quantity"):
|
||||
calculation_strategy.set_bill_quantity(_BILL_QUANTITY)
|
||||
|
||||
else:
|
||||
print(f"不支持的工程类型: {engineering_type}")
|
||||
return None
|
||||
@@ -919,41 +903,89 @@ def calculate_quantity_fees(
|
||||
# 初始化缓存
|
||||
calculated_fees.clear() # 使用全局缓存,而不是计算策略中的缓存
|
||||
|
||||
# 计算每个项目节点的费用
|
||||
all_results = {}
|
||||
# 创建一个新的结果结构,按清单节点组织
|
||||
structured_results = {}
|
||||
|
||||
# 辅助函数:处理ID,移除花括号并保留完整ID
|
||||
def process_id(id_str):
|
||||
if not id_str:
|
||||
return ""
|
||||
# 移除花括号
|
||||
return id_str.replace("{", "").replace("}", "")
|
||||
|
||||
# 计算每个项目节点的费用
|
||||
for project_node in project_children:
|
||||
# 为每个节点清空缓存,确保计算独立
|
||||
calculated_fees.clear()
|
||||
|
||||
node_name = project_node.get("项目名称", project_node.get("name", "未知节点"))
|
||||
# 强制使用GUID而不是ID
|
||||
node_id = project_node.get("GUID") or project_node.get("guid") or project_node.get("id", "")
|
||||
|
||||
# 添加清单数量信息
|
||||
# 处理节点ID
|
||||
processed_node_id = process_id(node_id)
|
||||
|
||||
# 创建唯一的节点键
|
||||
node_key = node_name
|
||||
if processed_node_id:
|
||||
node_key = f"{node_name}_{processed_node_id}"
|
||||
|
||||
# 添加清单数量信息到项目节点
|
||||
if engineering_type == "清单工程":
|
||||
bill_id = project_node.get("bill_id")
|
||||
# 强制使用GUID而不是ID
|
||||
bill_id = project_node.get("bill_guid") or project_node.get("bill_id")
|
||||
if bill_id in bill_quantities:
|
||||
project_node["bill_quantity"] = bill_quantities[bill_id]
|
||||
print(f"为工程量节点 '{node_name}' 设置清单数量: {bill_quantities[bill_id]}")
|
||||
|
||||
# 如果计算策略支持,设置清单数量
|
||||
if calculation_strategy and hasattr(calculation_strategy, "set_bill_quantity"):
|
||||
calculation_strategy.set_bill_quantity(bill_quantities[bill_id])
|
||||
|
||||
# 根据工程类型获取对应的取费表
|
||||
if engineering_type == "预算工程":
|
||||
# 预算工程 - 使用项目划分节点的取费表
|
||||
node_results = calculation_strategy.calculate_all_fees(
|
||||
project_node, {"children": cost_table_children}, json_file_path, engineering_type
|
||||
)
|
||||
|
||||
# 直接使用节点键作为结果键
|
||||
structured_results[node_key] = node_results
|
||||
|
||||
else: # 清单工程
|
||||
# 清单工程 - 使用清单节点的取费表
|
||||
parent_id = project_node.get("parent_id")
|
||||
if parent_id and parent_id in cost_tables:
|
||||
# 强制使用GUID而不是ID
|
||||
bill_id = project_node.get("bill_guid") or project_node.get("bill_id")
|
||||
if bill_id and bill_id in cost_tables:
|
||||
node_results = calculation_strategy.calculate_all_fees(
|
||||
project_node, {"children": cost_tables[parent_id]}, json_file_path, engineering_type
|
||||
project_node, {"children": cost_tables[bill_id]}, json_file_path, engineering_type
|
||||
)
|
||||
|
||||
# 获取清单信息
|
||||
bill_name = bill_info.get(bill_id, {}).get("name", "未命名清单")
|
||||
|
||||
# 处理清单ID - 强制使用GUID
|
||||
processed_bill_id = process_id(bill_id)
|
||||
|
||||
# 创建清单的唯一键 - 强制使用GUID
|
||||
bill_key = bill_name
|
||||
if processed_bill_id:
|
||||
# 获取清单的guid而不是id
|
||||
bill_guid = bill_info.get(bill_id, {}).get("guid", processed_bill_id)
|
||||
if not bill_guid:
|
||||
bill_guid = processed_bill_id
|
||||
bill_key = f"{bill_name}_{bill_guid}"
|
||||
|
||||
# 如果清单节点不存在于结果中,创建它
|
||||
if bill_key not in structured_results:
|
||||
structured_results[bill_key] = {}
|
||||
|
||||
# 将工程量节点的计算结果添加到对应的清单节点下
|
||||
structured_results[bill_key][node_key] = node_results
|
||||
else:
|
||||
print(f"无法获取工程量节点 '{node_name}' 的取费表")
|
||||
continue
|
||||
|
||||
all_results[node_name] = node_results
|
||||
|
||||
# 输出计算结果
|
||||
print(f"费用计算结果:")
|
||||
for fee_name, fee_value in node_results.items():
|
||||
@@ -961,7 +993,7 @@ def calculate_quantity_fees(
|
||||
|
||||
# 保存计算结果到JSON文件
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
json.dump(all_results, f, ensure_ascii=False, indent=2)
|
||||
json.dump(structured_results, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n计算结果已保存到 {output_file}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user