修改费用计算代码

This commit is contained in:
chentianrui
2025-08-22 18:13:09 +08:00
parent 8d595b339c
commit be848c3e78
20 changed files with 2569 additions and 360 deletions
+87 -13
View File
@@ -1,5 +1,6 @@
import os
from abc import ABC, abstractmethod
from memory_profiler import profile
from typing import Dict, List, Any, Optional, Tuple
from equipment_calculation.software_types import SoftwareType
from equipment_calculation.find_project_nodes import get_project_divisions_list
@@ -7,6 +8,8 @@ from equipment_calculation.quantity_fee_calculator import calculate_quantity_fee
from equipment_calculation.resource_fee_calculator import calculate_resource_fees as base_calculate_resource_fees
from equipment_calculation.calculation_strategy import CalculationStrategy, DefaultCalculationStrategy
import json
import psutil
from datetime import datetime
class CalculatorBase(ABC):
@@ -57,10 +60,45 @@ class CalculatorBase(ABC):
if hasattr(self.calculation_strategy, "set_output_dir"):
self.calculation_strategy.set_output_dir(output_dir)
def _append_log(self, text: str, filename: str = "performance_memory_log.txt") -> str:
"""将文本即时追加写入输出目录下的日志文件,并返回日志路径。"""
try:
out_dir = self.get_output_dir()
os.makedirs(out_dir, exist_ok=True)
log_path = os.path.join(out_dir, filename)
with open(log_path, "a", encoding="utf-8") as f:
f.write(text + "\n")
f.flush()
return log_path
except Exception as e:
# 即使写日志失败,也不要影响主流程
print(f"写入性能日志失败: {e}")
return ""
def _print_memory_usage(self, prefix: str = "") -> None:
"""记录当前进程的内存占用情况(MB)到输出目录日志文件。"""
try:
process = psutil.Process(os.getpid())
mem_info = process.memory_info()
rss = mem_info.rss / (1024**2) # 物理内存(MB
vms = mem_info.vms / (1024**2) # 虚拟内存(MB
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
header = f"[{ts}]" + (f" [{prefix}]" if prefix else "")
lines = [
f"{header} 当前进程占用的物理内存: {rss:.2f} MB",
f"{header} 当前进程占用的虚拟内存: {vms:.2f} MB",
]
for line in lines:
self._append_log(line)
except Exception as e:
# 日志失败不影响主流程
print(f"记录内存信息失败: {e}")
def calculate_quantity_fee_tables(
self,
json_file_path: str,
project_name: str = None,
project_type: Optional[str] = None,
) -> None:
"""
计算工程量取费表
@@ -76,12 +114,30 @@ class CalculatorBase(ABC):
if callable(preprocess_func): # 检查返回值是否可调用
preprocess_func(json_file_path) # 调用预处理函数
# 外层只读取一次 JSON
with open(json_file_path, "r", encoding="utf-8") as _f:
_json_data = json.load(_f)
# 外层只初始化一次 BCL 计算器
from equipment_calculation.bcl_utils import init_bcl_calculator
init_bcl_calculator(
software_category=self.software_type.category.value,
engineering_type=self.software_type.engineering_type.value,
calculation_type="工程量",
project_type=project_type,
)
if project_name:
# 处理单个项目划分
print(f"处理单个项目划分: {project_name}")
output_file = self._calculate_quantity_fees(json_file_path, project_name, engineering_type)
output_file = self._calculate_quantity_fees(
json_file_path, project_name, engineering_type, project_guid=None, json_data=_json_data
)
if output_file:
print(f"已完成 {project_name} 的工程量取费表计算,结果保存在 {output_file}")
# 性能打印:每个项目划分完成后打印内存占用
self._print_memory_usage(prefix=f"工程量-{project_name}")
else:
# 处理所有项目划分
project_divisions = get_project_divisions_list(json_file_path)
@@ -90,9 +146,13 @@ class CalculatorBase(ABC):
for i, (proj_name, proj_guid) in enumerate(project_divisions, 1):
# 使用命令行参数中指定的调差类型,而不是从JSON文件中获取的调差类型
print(f"处理 {i}/{len(project_divisions)}: {proj_name} (GUID: {proj_guid})")
output_file = self._calculate_quantity_fees(json_file_path, proj_name, engineering_type, proj_guid)
output_file = self._calculate_quantity_fees(
json_file_path, proj_name, engineering_type, proj_guid, json_data=_json_data
)
if output_file:
print(f"已完成 {proj_name} (GUID: {proj_guid}) 的工程量取费表计算")
# 性能打印:每个项目划分完成后打印内存占用
self._print_memory_usage(prefix=f"工程量-{proj_name}")
print(f"所有项目划分节点的工程量取费表计算完成,结果保存在 {self.get_output_dir()} 目录")
@@ -110,14 +170,30 @@ class CalculatorBase(ABC):
# 在计算前应用软件特定的规则
self.apply_resource_fee_rules()
# 外层只读取一次 JSON
with open(json_file_path, "r", encoding="utf-8") as _f:
_json_data = json.load(_f)
# 外层只初始化一次 BCL 计算器(人材机)
from equipment_calculation.bcl_utils import init_bcl_calculator
init_bcl_calculator(
software_category=self.software_type.category.value,
engineering_type=self.software_type.engineering_type.value,
calculation_type="人材机",
)
if project_name:
# 处理单个项目划分
output_file = self._calculate_resource_fees(
json_file_path,
project_name,
json_data=_json_data,
)
if output_file:
print(f"已完成 {project_name} 的人材机合价计算,结果保存在 {output_file}")
# 性能打印:每个项目划分完成后打印内存占用
self._print_memory_usage(prefix=f"人材机-{project_name}")
else:
# 处理所有项目划分
project_divisions = get_project_divisions_list(json_file_path)
@@ -125,9 +201,11 @@ class CalculatorBase(ABC):
for i, (proj_name, proj_guid) in enumerate(project_divisions, 1):
print(f"处理 {i}/{len(project_divisions)}: {proj_name} (GUID: {proj_guid})")
output_file = self._calculate_resource_fees(json_file_path, proj_name, proj_guid)
output_file = self._calculate_resource_fees(json_file_path, proj_name, proj_guid, json_data=_json_data)
if output_file:
print(f"已完成 {proj_name} (GUID: {proj_guid}) 的人材机合价计算")
# 性能打印:每个项目划分完成后打印内存占用
self._print_memory_usage(prefix=f"人材机-{proj_name}")
print(f"所有项目划分节点的人材机合价计算完成,结果保存在 {self.get_output_dir()} 目录")
@@ -137,6 +215,7 @@ class CalculatorBase(ABC):
project_name: str,
engineering_type: str,
project_guid: str = None,
json_data: dict | None = None,
) -> str:
"""
计算工程量取费表,并应用软件特定的后处理规则
@@ -153,17 +232,8 @@ class CalculatorBase(ABC):
# 确保输出目录存在
os.makedirs(self.get_output_dir(), exist_ok=True)
# 初始化BCL计算器,传递软件类型和计算类型
from equipment_calculation.bcl_utils import init_bcl_calculator
init_bcl_calculator(
software_category=self.software_type.category.value,
engineering_type=self.software_type.engineering_type.value,
calculation_type="工程量",
)
# 打印计算策略信息
print(f"使用计算策略: {self.calculation_strategy.__class__.__name__}")
# print(f"使用计算策略: {self.calculation_strategy.__class__.__name__}")
# 调用基础计算函数,传入计算策略和项目GUID
output_file = base_calculate_quantity_fees(
@@ -172,6 +242,8 @@ class CalculatorBase(ABC):
engineering_type,
project_guid=project_guid,
calculation_strategy=self.calculation_strategy,
software_type=self.software_type.category.value,
json_data=json_data,
)
# 应用软件特定的后处理规则
@@ -185,6 +257,7 @@ class CalculatorBase(ABC):
json_file_path: str,
project_name: str,
project_guid: str = None,
json_data: dict | None = None,
) -> str:
"""
计算人材机合价,并应用软件特定的后处理规则
@@ -216,6 +289,7 @@ class CalculatorBase(ABC):
project_name,
project_guid=project_guid,
calculation_strategy=self.calculation_strategy,
json_data=json_data,
)
# 应用软件特定的后处理规则