import os from abc import ABC, abstractmethod from typing import Dict, List, Any, Optional, Tuple from software_types import SoftwareType from find_project_nodes import get_project_divisions_list from quantity_fee_calculator import calculate_quantity_fees as base_calculate_quantity_fees from resource_fee_calculator import calculate_resource_fees as base_calculate_resource_fees from calculation_strategy import CalculationStrategy, DefaultCalculationStrategy import json class CalculatorBase(ABC): """计算器基类""" def __init__(self, software_type: SoftwareType): """ 初始化计算器 Args: software_type: 软件类型 """ self.software_type = software_type self.config_dir = software_type.config_dir # 使用默认计算策略 self.calculation_strategy = self.create_calculation_strategy() def create_calculation_strategy(self) -> CalculationStrategy: """ 创建计算策略 子类可以重写此方法,返回特定的计算策略实现 Returns: CalculationStrategy: 计算策略实例 """ return DefaultCalculationStrategy() def get_default_input_file(self) -> str: """获取默认输入文件路径""" return os.path.join(self.software_type.test_dir) def get_output_dir(self) -> str: """获取输出目录路径""" base_dir = "计算结果" return os.path.join(base_dir, self.software_type.name) def calculate_quantity_fee_tables( self, json_file_path: str, project_name: str = None, ) -> None: """ 计算工程量取费表 Args: json_file_path: JSON文件路径 project_name: 项目名称,如果为None则处理所有项目 """ engineering_type = self.software_type.engineering_type.value + "工程" # 在计算前应用软件特定的规则 preprocess_func = self.apply_quantity_fee_rules() if callable(preprocess_func): # 检查返回值是否可调用 preprocess_func(json_file_path) # 调用预处理函数 if project_name: # 处理单个项目划分 print(f"处理单个项目划分: {project_name}") output_file = self._calculate_quantity_fees(json_file_path, project_name, engineering_type) if output_file: print(f"已完成 {project_name} 的工程量取费表计算,结果保存在 {output_file}") else: # 处理所有项目划分 project_divisions = get_project_divisions_list(json_file_path) print(f"找到 {len(project_divisions)} 个项目划分节点,开始处理工程量取费表...") 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) if output_file: print(f"已完成 {proj_name} (GUID: {proj_guid}) 的工程量取费表计算") print(f"所有项目划分节点的工程量取费表计算完成,结果保存在 {self.get_output_dir()} 目录") def calculate_resource_fee_tables(self, json_file_path: str, project_name: str = None) -> None: """ 计算人材机合价 Args: json_file_path: JSON文件路径 project_name: 项目名称,如果为None则处理所有项目 """ # 获取工程类型 engineering_type = self.software_type.engineering_type.value + "工程" # 在计算前应用软件特定的规则 self.apply_resource_fee_rules() if project_name: # 处理单个项目划分 output_file = self._calculate_resource_fees( json_file_path, project_name, ) if output_file: print(f"已完成 {project_name} 的人材机合价计算,结果保存在 {output_file}") else: # 处理所有项目划分 project_divisions = get_project_divisions_list(json_file_path) print(f"找到 {len(project_divisions)} 个项目划分节点,开始处理人材机合价...") 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) if output_file: print(f"已完成 {proj_name} (GUID: {proj_guid}) 的人材机合价计算") print(f"所有项目划分节点的人材机合价计算完成,结果保存在 {self.get_output_dir()} 目录") def _calculate_quantity_fees( self, json_file_path: str, project_name: str, engineering_type: str, project_guid: str = None, ) -> str: """ 计算工程量取费表,并应用软件特定的后处理规则 Args: json_file_path: JSON文件路径 project_name: 项目名称 engineering_type: 工程类型 project_guid: 项目GUID,用于区分同名项目 Returns: str: 输出文件路径 """ # 确保输出目录存在 os.makedirs(self.get_output_dir(), exist_ok=True) # 初始化BCL计算器,传递软件类型和计算类型 from 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__}") # 调用基础计算函数,传入计算策略和项目GUID output_file = base_calculate_quantity_fees( json_file_path, project_name, engineering_type, project_guid=project_guid, calculation_strategy=self.calculation_strategy, ) # 应用软件特定的后处理规则 if output_file: self.post_process_quantity_fees(output_file, project_name) return output_file def _calculate_resource_fees( self, json_file_path: str, project_name: str, project_guid: str = None, ) -> str: """ 计算人材机合价,并应用软件特定的后处理规则 Args: json_file_path: JSON文件路径 project_name: 项目名称 engineering_type: 工程类型 project_guid: 项目GUID,用于区分同名项目 Returns: str: 输出文件路径 """ # 确保输出目录存在 os.makedirs(self.get_output_dir(), exist_ok=True) # 初始化BCL计算器,传递软件类型和计算类型 from 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="人材机", ) # 调用基础计算函数,传入计算策略和项目GUID output_file = base_calculate_resource_fees( json_file_path, project_name, project_guid=project_guid, calculation_strategy=self.calculation_strategy, ) # 应用软件特定的后处理规则 if output_file: self.post_process_resource_fees(output_file, project_name) return output_file def apply_quantity_fee_rules(self) -> None: """应用软件特定的工程量取费规则(在计算前)""" pass def apply_resource_fee_rules(self) -> None: """应用软件特定的人材机合价规则(在计算前)""" pass def post_process_quantity_fees(self, output_file: str, project_name: str) -> None: """ 应用软件特定的工程量取费后处理规则 Args: output_file: 输出文件路径 project_name: 项目名称 """ pass def post_process_resource_fees(self, output_file: str, project_name: str) -> None: """ 应用软件特定的人材机合价后处理规则 Args: output_file: 输出文件路径 project_name: 项目名称 """ pass