增加了知识图谱导出excel

This commit is contained in:
chentianrui
2025-08-18 15:14:37 +08:00
parent ce2986fbe2
commit 3fd0b2af0c
610 changed files with 6062 additions and 4932473 deletions
+136 -104
View File
@@ -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}")