234 lines
8.9 KiB
Python
234 lines
8.9 KiB
Python
import os
|
||
import shutil
|
||
import time
|
||
from pathlib import Path
|
||
import traceback
|
||
import uuid
|
||
import random
|
||
import string
|
||
import argparse
|
||
|
||
# 导入各个步骤需要的函数
|
||
from project2json.project_converter import convert_project_to_json
|
||
from transform_expense_preview import process_directory
|
||
from supplement_kg import costsummary_upwards
|
||
from equipment_calculation.main import bcl_calculate
|
||
from cost_comparison import compare_costs_batch
|
||
import tempfile
|
||
|
||
# 基础目录
|
||
BASE_DIR = "project2json"
|
||
TEMP_DIR = tempfile.gettempdir() # 使用临时目录
|
||
|
||
|
||
# 生成随机8位ID
|
||
def generate_session_id():
|
||
return "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
||
|
||
|
||
# 创建会话工作目录(仅会话根目录)
|
||
def create_session_directories(session_id):
|
||
# 仅创建会话根目录用于容纳每个文件的独立GUID临时目录
|
||
session_root = os.path.join(BASE_DIR, "outputs", session_id)
|
||
os.makedirs(session_root, exist_ok=True)
|
||
return {
|
||
"session_root": session_root,
|
||
}
|
||
|
||
|
||
# 为单个上传文件创建独立的GUID临时目录,包含六个子目录
|
||
def create_file_workdirs(session_id):
|
||
file_guid = uuid.uuid4().hex
|
||
root = os.path.join(BASE_DIR, "outputs", session_id, file_guid)
|
||
dirs = {
|
||
"root": root,
|
||
"upload_dir": os.path.join(root, "uploads"), # 生成json前的上传文件夹
|
||
"bcl_dir": os.path.join(root, "bcl"), # bcl计算文件文件夹(备用,当前流程未直接使用)
|
||
"json_dir": os.path.join(root, "json"), # 生成后的json文件夹
|
||
"merged_dir": os.path.join(root, "merged"),
|
||
"bcl_results_dir": os.path.join(root, "bclresults"),
|
||
"final_dir": os.path.join(root, "final"),
|
||
}
|
||
|
||
for d in dirs.values():
|
||
os.makedirs(d, exist_ok=True)
|
||
|
||
return dirs
|
||
|
||
|
||
# 整合的转化流程函数(无前端),执行步骤1到步骤3,并将步骤3.2/4替换为 compare_costs_batch
|
||
def convert_all_steps(files):
|
||
"""处理传入的工程文件列表,输出成功执行的文件数量。
|
||
|
||
流程:
|
||
1) 保存上传 -> 转JSON
|
||
2) 处理JSON结构并费用向上汇总(merged_dir)
|
||
3) BCL计算(输出到 bcl_results_dir)
|
||
4) 调用 compare_costs_batch(bcl_results_dir, project_json) 进行费用对比
|
||
"""
|
||
try:
|
||
session_id = generate_session_id()
|
||
print(f"生成会话ID: {session_id}")
|
||
session_dirs = create_session_directories(session_id)
|
||
session_root = session_dirs["session_root"]
|
||
|
||
total_files = len(files) if files else 0
|
||
if total_files == 0:
|
||
print("未选择任何文件。")
|
||
return 0
|
||
|
||
total_success = 0
|
||
|
||
for idx, file in enumerate(files, start=1):
|
||
try:
|
||
file_name = os.path.basename(file if isinstance(file, str) else file.name)
|
||
print(f"[{idx}/{total_files}] 处理文件: {file_name}")
|
||
|
||
# 创建该文件的独立GUID临时目录
|
||
fdirs = create_file_workdirs(session_id)
|
||
upload_dir = fdirs["upload_dir"]
|
||
json_dir = fdirs["json_dir"]
|
||
merged_dir = fdirs["merged_dir"]
|
||
bcl_results_dir = fdirs["bcl_results_dir"]
|
||
|
||
# 步骤1.1: 保存上传的该文件
|
||
save_path = os.path.join(upload_dir, file_name)
|
||
shutil.copy(file if isinstance(file, str) else file.name, save_path)
|
||
|
||
# 步骤1.2: 转换为JSON
|
||
success, file_num = convert_project_to_json(upload_dir, json_dir, fdirs["bcl_dir"])
|
||
if not success:
|
||
raise RuntimeError("转换为JSON失败")
|
||
|
||
# 步骤1.3: 处理JSON文件结构
|
||
process_directory(json_dir)
|
||
|
||
# 步骤2: 费用向上汇总
|
||
result_step2 = costsummary_upwards(json_dir, merged_dir)
|
||
if not result_step2:
|
||
print("警告:未生成任何汇总JSON")
|
||
|
||
# 步骤3.1: 计算工程量取费表
|
||
bcl_calculate(merged_dir, bcl_results_dir, bcl_dir_path=fdirs["bcl_dir"])
|
||
|
||
# 选择项目JSON:从 merged_dir 中选择一个主 JSON(若多个则取第一个)
|
||
merged_jsons = [
|
||
os.path.join(merged_dir, f) for f in os.listdir(merged_dir) if f.lower().endswith(".json")
|
||
]
|
||
if not merged_jsons:
|
||
raise FileNotFoundError("在 merged_dir 中未找到项目 JSON")
|
||
project_data_json_path = merged_jsons[0]
|
||
|
||
# 步骤3.2/4: 调用 compare_costs_batch 进行费用对比
|
||
compare_costs_batch(bcl_results_dir, project_data_json_path)
|
||
|
||
total_success += 1
|
||
except Exception as fe:
|
||
print(f"处理文件 {file_name} 失败: {fe}\n{traceback.format_exc()}")
|
||
|
||
print(f"成功执行 {total_success} 个文件。")
|
||
return total_success
|
||
except Exception as e:
|
||
error_msg = f"执行流程出错: {str(e)}\n{traceback.format_exc()}"
|
||
print(error_msg)
|
||
return 0
|
||
|
||
|
||
# ========= 批处理与命令行入口(文件末尾追加) =========
|
||
def create_named_workdirs(output_base_dir: str, base_name: str):
|
||
"""在输出根目录下创建 '<工程名>+<GUID>' 的工作目录结构。"""
|
||
guid = uuid.uuid4().hex
|
||
root_name = f"{base_name}+{guid}"
|
||
root = os.path.join(output_base_dir, root_name)
|
||
dirs = {
|
||
"root": root,
|
||
"upload_dir": os.path.join(root, "uploads"),
|
||
"bcl_dir": os.path.join(root, "bcl"),
|
||
"json_dir": os.path.join(root, "json"),
|
||
"merged_dir": os.path.join(root, "merged"),
|
||
"bcl_results_dir": os.path.join(root, "bclresults"),
|
||
"final_dir": os.path.join(root, "final"),
|
||
}
|
||
for d in dirs.values():
|
||
os.makedirs(d, exist_ok=True)
|
||
return dirs
|
||
|
||
|
||
def run_batch_with_io(input_dir: str, output_dir: str) -> int:
|
||
"""批量处理输入目录下的工程文件,输出到指定的输出根目录。"""
|
||
input_dir = os.path.abspath(input_dir)
|
||
output_dir = os.path.abspath(output_dir)
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
|
||
candidates = [
|
||
os.path.join(input_dir, f) for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))
|
||
]
|
||
if not candidates:
|
||
print(f"输入目录无文件: {input_dir}")
|
||
return 0
|
||
|
||
total_success = 0
|
||
for idx, file_path in enumerate(candidates, start=1):
|
||
base_name = os.path.basename(file_path)
|
||
stem = os.path.splitext(base_name)[0]
|
||
print(f"[{idx}/{len(candidates)}] 处理文件: {base_name}")
|
||
|
||
try:
|
||
# 1) 为该工程创建独立工作区
|
||
fdirs = create_named_workdirs(output_dir, stem)
|
||
upload_dir = fdirs["upload_dir"]
|
||
json_dir = fdirs["json_dir"]
|
||
merged_dir = fdirs["merged_dir"]
|
||
bcl_results_dir = fdirs["bcl_results_dir"]
|
||
bcl_dir = fdirs["bcl_dir"]
|
||
|
||
# 2) 保存上传
|
||
save_path = os.path.join(upload_dir, base_name)
|
||
shutil.copy(file_path, save_path)
|
||
|
||
# 3) 转换为JSON(并将 BCL 最佳版本复制到 bcl_dir)
|
||
success, _file_num = convert_project_to_json(upload_dir, json_dir, bcl_dir)
|
||
if not success:
|
||
raise RuntimeError("转换为JSON失败")
|
||
|
||
# 4) 处理JSON结构
|
||
process_directory(json_dir)
|
||
|
||
# 5) 费用向上汇总
|
||
result_step2 = costsummary_upwards(json_dir, merged_dir)
|
||
if not result_step2:
|
||
print("警告:未生成任何汇总JSON")
|
||
|
||
# 6) 计算工程量取费表(读取 bcl_dir,输出到 bcl_results_dir)
|
||
bcl_calculate(merged_dir, bcl_results_dir, bcl_dir_path=bcl_dir)
|
||
|
||
# 7) 选择一个项目 JSON 进行费用对比
|
||
merged_jsons = [os.path.join(merged_dir, f) for f in os.listdir(merged_dir) if f.lower().endswith(".json")]
|
||
if not merged_jsons:
|
||
raise FileNotFoundError("在 merged_dir 中未找到项目 JSON")
|
||
project_data_json_path = merged_jsons[0]
|
||
|
||
# 8) 费用对比
|
||
compare_costs_batch(bcl_results_dir, project_data_json_path)
|
||
|
||
total_success += 1
|
||
except Exception as fe:
|
||
print(f"处理文件 {base_name} 失败: {fe}\n{traceback.format_exc()}")
|
||
|
||
print(f"成功执行 {total_success}/{len(candidates)} 个文件。输出根目录: {output_dir}")
|
||
return total_success
|
||
|
||
|
||
if __name__ == "__main__":
|
||
|
||
input_dir = r"data/input" # 请修改为你的实际输入路径
|
||
output_dir = r"data/output" # 请修改为你的实际输出路径
|
||
|
||
t0 = time.time()
|
||
try:
|
||
count = run_batch_with_io(input_dir, output_dir)
|
||
print(f"\n🎉 ✅ 处理完成,共成功 {count} 个。耗时: {int(time.time() - t0)} 秒")
|
||
except Exception as e:
|
||
print(f"\n❌ 执行失败: {e}\n{traceback.format_exc()}")
|
||
raise
|