上传代码
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,233 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[neo4j]
|
||||||
|
uri: bolt://10.1.6.34:7687
|
||||||
|
user: neo4j
|
||||||
|
password: password
|
||||||
+85
-24
@@ -1,41 +1,102 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import chardet
|
||||||
|
|
||||||
|
|
||||||
def convert_json_to_readable(input_file, output_file=None):
|
def detect_encoding(file_path):
|
||||||
"""
|
"""
|
||||||
将JSON文件转换为可读格式并保存
|
检测文件编码,优先考虑中文编码兼容性
|
||||||
|
|
||||||
参数:
|
|
||||||
input_file: 输入JSON文件路径
|
|
||||||
output_file: 输出文件路径,如果为None则自动生成
|
|
||||||
"""
|
"""
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
raw_data = f.read()
|
||||||
|
result = chardet.detect(raw_data)
|
||||||
|
encoding = result["encoding"]
|
||||||
|
print(f"初步检测编码: {encoding}")
|
||||||
|
return encoding
|
||||||
|
|
||||||
|
|
||||||
|
def convert_json_to_readable(input_folder, output_folder=None):
|
||||||
|
"""
|
||||||
|
批量将文件夹下所有JSON文件转换为可读格式(UTF-8 + 缩进美化)
|
||||||
|
支持 GBK/GB2312/gb18030 等中文编码
|
||||||
|
"""
|
||||||
|
if not os.path.exists(input_folder):
|
||||||
|
print(f"错误:输入文件夹不存在: {input_folder}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if output_folder is None:
|
||||||
|
output_folder = input_folder
|
||||||
|
os.makedirs(output_folder, exist_ok=True)
|
||||||
|
|
||||||
|
json_files = [f for f in os.listdir(input_folder) if f.lower().endswith(".json")]
|
||||||
|
|
||||||
|
if not json_files:
|
||||||
|
print(f"警告:在 {input_folder} 中未找到任何 JSON 文件。")
|
||||||
|
return
|
||||||
|
|
||||||
|
processed_count = 0
|
||||||
|
failed_files = []
|
||||||
|
|
||||||
|
# 中文编码优先列表
|
||||||
|
chinese_encodings = ["utf-8", "gb18030", "gbk", "gb2312"]
|
||||||
|
|
||||||
|
for filename in json_files:
|
||||||
|
input_file = os.path.join(input_folder, filename)
|
||||||
|
output_file = os.path.join(output_folder, filename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 读取JSON文件
|
print(f"正在处理: {filename}")
|
||||||
with open(input_file, "r", encoding="utf-8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
# 如果未指定输出文件,则自动生成
|
# 先尝试 chardet 检测
|
||||||
if output_file is None:
|
detected_encoding = detect_encoding(input_file)
|
||||||
base_name = os.path.splitext(input_file)[0]
|
|
||||||
output_file = f"{base_name}_readable.json"
|
|
||||||
|
|
||||||
# 以美化格式写入新文件
|
# 构建尝试的编码列表:检测结果 + 常见中文编码
|
||||||
|
encodings_to_try = []
|
||||||
|
if detected_encoding:
|
||||||
|
encodings_to_try.append(detected_encoding.lower())
|
||||||
|
encodings_to_try.extend([enc for enc in chinese_encodings if enc.lower() != detected_encoding])
|
||||||
|
|
||||||
|
data = None
|
||||||
|
content_str = None
|
||||||
|
|
||||||
|
for enc in encodings_to_try:
|
||||||
|
try:
|
||||||
|
with open(input_file, "r", encoding=enc) as f:
|
||||||
|
content_str = f.read()
|
||||||
|
data = json.loads(content_str)
|
||||||
|
print(f" 使用编码 '{enc}' 成功解码并解析 JSON")
|
||||||
|
break
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print(f" 编码 '{enc}' 解码失败,尝试下一个...")
|
||||||
|
continue
|
||||||
|
except json.JSONDecodeError as je:
|
||||||
|
print(f" 编码 '{enc}' 解码成功,但 JSON 格式错误: {je}")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f" 使用编码 '{enc}' 失败: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
raise ValueError(f"所有编码尝试均失败: {encodings_to_try}")
|
||||||
|
|
||||||
|
# 成功解析后,以标准 UTF-8 保存美化格式
|
||||||
with open(output_file, "w", encoding="utf-8") as f:
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
print(f"转换成功!可读格式的文件已保存为: {output_file}")
|
print(f"✅ 转换成功: {output_file}")
|
||||||
return output_file
|
processed_count += 1
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"转换过程中出现错误: {str(e)}")
|
print(f"❌ 转换失败: {filename} -> 错误: {str(e)}")
|
||||||
return None
|
failed_files.append(filename)
|
||||||
|
|
||||||
|
print(f"\n--- 处理完成 ---")
|
||||||
|
print(f"共处理 {len(json_files)} 个文件,成功 {processed_count} 个。")
|
||||||
|
if failed_files:
|
||||||
|
print(f"失败文件: {failed_files}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 指定输入文件路径
|
input_folder = r"project2json/outputs/json"
|
||||||
input_file = (
|
|
||||||
r"E:/文件/LLM_model/RAG/code/Engineering_data_KG-1/equipment_dataset/数据工程/技改/预算/通信线路检修国网.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 调用转换函数
|
convert_json_to_readable(input_folder)
|
||||||
convert_json_to_readable(input_file)
|
|
||||||
|
|||||||
+176
-32
@@ -27,45 +27,102 @@ def calculate_similarity(a, b):
|
|||||||
return SequenceMatcher(None, a, b).ratio()
|
return SequenceMatcher(None, a, b).ratio()
|
||||||
|
|
||||||
|
|
||||||
def load_calculation_results(json_file_path):
|
def load_calculation_results(json_file_path, project_type: str = "budget"):
|
||||||
"""读取计算结果 JSON,返回费用总和字典"""
|
"""读取计算结果 JSON,返回费用总和字典
|
||||||
|
|
||||||
|
- budget(预算工程): 期望结构为 { node: { cost_name: number, ... }, ... }
|
||||||
|
逐项累加 cost_name -> number。
|
||||||
|
- inventory(清单工程): 结构通常为 { category: { item: { metric_name: number, ... } } }
|
||||||
|
将最内层 metrics(如“合价/直接费/人工费/材料费/机械费/措施费/间接费/安全文明施工费”等)按 metric_name 汇总累计。
|
||||||
|
"""
|
||||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
total_costs = {}
|
total_costs = {}
|
||||||
for node_name, cost_dict in data.items():
|
|
||||||
|
if project_type == "inventory":
|
||||||
|
# 三级结构:大类 -> 清单项 -> 指标dict
|
||||||
|
for _, items in (data or {}).items():
|
||||||
|
if isinstance(items, dict):
|
||||||
|
for _, metrics in items.items():
|
||||||
|
if isinstance(metrics, dict):
|
||||||
|
for metric_name, metric_val in metrics.items():
|
||||||
|
# 仅累计数值型
|
||||||
|
if isinstance(metric_val, (int, float)):
|
||||||
|
total_costs[metric_name] = total_costs.get(metric_name, 0) + float(metric_val)
|
||||||
|
else:
|
||||||
|
# 预算:两级结构:节点 -> 费用名: 数值
|
||||||
|
for _, cost_dict in (data or {}).items():
|
||||||
|
if isinstance(cost_dict, dict):
|
||||||
for cost_name, value in cost_dict.items():
|
for cost_name, value in cost_dict.items():
|
||||||
total_costs[cost_name] = total_costs.get(cost_name, 0) + value
|
if isinstance(value, (int, float)):
|
||||||
|
total_costs[cost_name] = total_costs.get(cost_name, 0) + float(value)
|
||||||
return total_costs
|
return total_costs
|
||||||
|
|
||||||
|
|
||||||
def find_node_by_guid(expense_preview, target_guid):
|
def find_node_by_guid(expense_preview, target_guid):
|
||||||
"""在 expensePreview 中递归查找 GUID 对应的节点"""
|
"""在 expensePreview 中递归查找 GUID 对应的节点,并返回其 sum 列表用于对比。
|
||||||
|
|
||||||
def search_recursive(items):
|
适配新结构:每个 GUID 节点包含三个列表:
|
||||||
for item in items:
|
- sum: 费用条目(含 id/cost)——用于对比
|
||||||
current_guid = item.get("GUID", "").strip("{}").upper()
|
- children: 递归子节点列表(继续下钻)
|
||||||
|
- rcj: 其他数据(此处忽略)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def search_recursive(node):
|
||||||
|
"""统一遍历任意层级结构(dict/list),匹配 GUID 并返回其 children 列表"""
|
||||||
|
if isinstance(node, dict):
|
||||||
|
# 当前节点如果带 GUID,先判断自身是否命中
|
||||||
|
current_guid = node.get("GUID", "")
|
||||||
|
if isinstance(current_guid, str) and current_guid:
|
||||||
|
current_guid = current_guid.strip("{}").upper()
|
||||||
if current_guid == target_guid:
|
if current_guid == target_guid:
|
||||||
return item.get("children", [])
|
# 命中后返回 sum 列表作为对比项来源
|
||||||
if "children" in item:
|
return node.get("sum", [])
|
||||||
result = search_recursive(item["children"])
|
|
||||||
|
# 若存在 children,优先深入 children(继续查找更深层 GUID)
|
||||||
|
if "children" in node and isinstance(node["children"], list):
|
||||||
|
result = search_recursive(node["children"])
|
||||||
|
if result is not None:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 继续遍历其它所有键的值,以覆盖类似 {"建筑工程": {"拆除": [ ... ]}} 的层级
|
||||||
|
for value in node.values():
|
||||||
|
result = search_recursive(value)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for category_name, items in expense_preview.items():
|
if isinstance(node, list):
|
||||||
if isinstance(items, list):
|
for item in node:
|
||||||
result = search_recursive(items)
|
result = search_recursive(item)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 其他类型(如 str/number/None)无需处理
|
||||||
|
return None
|
||||||
|
|
||||||
|
return search_recursive(expense_preview)
|
||||||
|
|
||||||
|
|
||||||
def load_project_data_and_find_costs(project_json_path, target_guid):
|
def load_project_data_and_find_costs(project_json_path, target_guid):
|
||||||
"""读取 project_data.json 并查找对应 GUID 的费用列表"""
|
"""读取 project_data.json 并查找对应 GUID 的费用列表
|
||||||
|
|
||||||
|
集成项目类型判断:
|
||||||
|
- 若判定为预算工程(budget):沿用当前逻辑
|
||||||
|
- 若判定为清单工程(inventory):暂时也沿用相同逻辑(如需差异处理可再扩展)
|
||||||
|
"""
|
||||||
with open(project_json_path, "r", encoding="utf-8") as f:
|
with open(project_json_path, "r", encoding="utf-8") as f:
|
||||||
project_data = json.load(f)
|
project_data = json.load(f)
|
||||||
|
|
||||||
|
# 判断项目类型
|
||||||
|
project_type = _determine_project_type(project_data)
|
||||||
|
if project_type == "budget":
|
||||||
|
print("项目类型:预算工程(按现有逻辑处理)")
|
||||||
|
else:
|
||||||
|
print("项目类型:清单工程(暂按预算同样逻辑处理,若需差异化请告知)")
|
||||||
|
|
||||||
expense_preview = project_data.get("projectData", {}).get("expensePreview", {})
|
expense_preview = project_data.get("projectData", {}).get("expensePreview", {})
|
||||||
children = find_node_by_guid(expense_preview, target_guid)
|
children = find_node_by_guid(expense_preview, target_guid)
|
||||||
|
|
||||||
@@ -167,31 +224,87 @@ def save_comparison_to_txt(comparison, output_txt_path):
|
|||||||
print(f"✅ 对比结果已保存至: {output_txt_path}")
|
print(f"✅ 对比结果已保存至: {output_txt_path}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def _determine_project_type(data):
|
||||||
# ================== 配置路径 ==================
|
"""
|
||||||
# 存放所有 calculation_results.json 的文件夹
|
根据basicData中的"项目类型"或"工程类型"判断工程类型
|
||||||
calc_results_folder = "project2json/outputs/bclresults/变电检修国网"
|
:param data: 项目数据
|
||||||
|
:return: 'inventory' 表示清单工程,'budget' 表示预算工程
|
||||||
|
"""
|
||||||
|
# 项目类型名称映射字典:将各种变体映射到标准类型(预算/清单)
|
||||||
|
PROJECT_TYPE_MAPPING = {
|
||||||
|
"概预算工程": "预算",
|
||||||
|
"初步设计概算": "预算",
|
||||||
|
"可行性研究投资估算": "预算",
|
||||||
|
"施工图预算": "预算",
|
||||||
|
"配网定额计价": "预算",
|
||||||
|
"招标控制价": "清单",
|
||||||
|
"投标报价": "清单",
|
||||||
|
"招投标工程": "清单",
|
||||||
|
"配网清单招投标计价": "清单",
|
||||||
|
}
|
||||||
|
|
||||||
# 主 project_data.json 路径(参考数据源)
|
# 获取 basicData
|
||||||
project_data_json_path = "project2json/outputs/json/变电检修国网.json"
|
basic_data = data.get("basicData") or {}
|
||||||
|
|
||||||
# 输出对比结果的文件夹
|
# 尝试获取 "项目类型",若不存在则尝试获取 "工程类型"
|
||||||
output_folder = "project2json/outputs/comparison_results"
|
engineering_type = basic_data.get("项目类型") or basic_data.get("工程类型") or basic_data.get("工程类别")
|
||||||
|
|
||||||
|
if engineering_type:
|
||||||
|
# 去除前后空格
|
||||||
|
engineering_type = engineering_type.strip()
|
||||||
|
# 查找映射
|
||||||
|
mapped_type = PROJECT_TYPE_MAPPING.get(engineering_type)
|
||||||
|
if mapped_type == "预算":
|
||||||
|
print(f"根据项目类型 '{engineering_type}' 判断为预算工程")
|
||||||
|
return "budget"
|
||||||
|
elif mapped_type == "清单":
|
||||||
|
print(f"根据项目类型 '{engineering_type}' 判断为清单工程")
|
||||||
|
return "inventory"
|
||||||
|
else:
|
||||||
|
print(f"项目类型 '{engineering_type}' 未在映射中定义,跳过")
|
||||||
|
|
||||||
|
# 默认按预算工程处理,以保持当前对比逻辑不变
|
||||||
|
print("未能可靠判断项目类型,默认按预算工程处理")
|
||||||
|
return "budget"
|
||||||
|
|
||||||
|
|
||||||
|
def compare_costs_batch(calc_results_folder: str, project_data_json_path: str):
|
||||||
|
"""批量对比 calculation_results.json 与项目 JSON。
|
||||||
|
|
||||||
|
- 输出目录:在 calc_results_folder 下创建 comparison_results 保存结果。
|
||||||
|
- 根据 project_data_json_path 判定工程类型(预算/清单),以选择解析方式。
|
||||||
|
"""
|
||||||
|
# 输出对比结果的文件夹放在 calc_results_folder 内
|
||||||
|
output_folder = os.path.join(calc_results_folder, "comparison_results")
|
||||||
os.makedirs(output_folder, exist_ok=True)
|
os.makedirs(output_folder, exist_ok=True)
|
||||||
|
|
||||||
# 支持的文件名关键词(可根据实际命名调整)
|
# 支持的文件名关键词(可根据实际命名调整)
|
||||||
result_file_keyword = "_calculation_results.json"
|
result_file_keyword = "_calculation_results.json"
|
||||||
|
|
||||||
# ==================================================
|
# 预读取项目 JSON 并判定工程类型(供计算结果解析使用)
|
||||||
|
try:
|
||||||
|
with open(project_data_json_path, "r", encoding="utf-8") as f:
|
||||||
|
project_data_for_type = json.load(f)
|
||||||
|
project_type = _determine_project_type(project_data_for_type)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"读取项目文件以判定类型失败,将默认按预算处理,错误: {e}")
|
||||||
|
project_type = "budget"
|
||||||
|
|
||||||
print(f"开始批量处理文件夹: {calc_results_folder}")
|
print(f"开始批量处理文件夹: {calc_results_folder}(项目类型: { '清单' if project_type=='inventory' else '预算' })")
|
||||||
processed_count = 0
|
processed_count = 0
|
||||||
|
|
||||||
for filename in os.listdir(calc_results_folder):
|
# 递归扫描 calc_results_folder 下所有子目录,寻找结果文件
|
||||||
if not filename.endswith(".json") or result_file_keyword not in filename:
|
matched_files = []
|
||||||
continue
|
for root, _dirs, files in os.walk(calc_results_folder):
|
||||||
|
for filename in files:
|
||||||
|
if filename.endswith(".json") and result_file_keyword in filename:
|
||||||
|
matched_files.append(os.path.join(root, filename))
|
||||||
|
|
||||||
calc_json_path = os.path.join(calc_results_folder, filename)
|
if not matched_files:
|
||||||
|
print("未在任何子目录中发现 '*_calculation_results.json' 文件,请确认 BCL 结果输出位置与命名。")
|
||||||
|
|
||||||
|
for calc_json_path in matched_files:
|
||||||
|
filename = os.path.basename(calc_json_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 提取 GUID
|
# 提取 GUID
|
||||||
@@ -203,8 +316,8 @@ def main():
|
|||||||
print(f"\n📄 处理文件: {filename}")
|
print(f"\n📄 处理文件: {filename}")
|
||||||
print(f" 提取 GUID: {guid}")
|
print(f" 提取 GUID: {guid}")
|
||||||
|
|
||||||
# 读取计算结果
|
# 读取计算结果(按工程类型解析)
|
||||||
calc_costs = load_calculation_results(calc_json_path)
|
calc_costs = load_calculation_results(calc_json_path, project_type=project_type)
|
||||||
print(f" 加载 {len(calc_costs)} 个计算费用项")
|
print(f" 加载 {len(calc_costs)} 个计算费用项")
|
||||||
|
|
||||||
# 从主 JSON 获取参考费用
|
# 从主 JSON 获取参考费用
|
||||||
@@ -230,5 +343,36 @@ def main():
|
|||||||
print(f"📊 所有对比结果已保存至: {output_folder}")
|
print(f"📊 所有对比结果已保存至: {output_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# 测试入口:直接运行本文件
|
||||||
|
# --------------------------
|
||||||
|
# --------------------------
|
||||||
|
# 测试入口:直接运行本文件(简化版)
|
||||||
|
# --------------------------
|
||||||
|
def _main():
|
||||||
|
"""直接运行费用对比,无需命令行或输入"""
|
||||||
|
|
||||||
|
# ✅ 在这里直接填写你要测试的路径(可自行修改)
|
||||||
|
calc_dir = r"data/output/bclresults/电缆检修国网"
|
||||||
|
proj_json = r"data/output/merged/电缆检修国网.json"
|
||||||
|
|
||||||
|
# 检查路径是否存在
|
||||||
|
if not os.path.exists(calc_dir):
|
||||||
|
print(f"❌ BCL 结果文件夹不存在: {calc_dir}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.exists(proj_json):
|
||||||
|
print(f"❌ 项目 JSON 文件不存在: {proj_json}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"✅ BCL 计算结果目录: {calc_dir}")
|
||||||
|
print(f"✅ 项目 JSON 文件: {proj_json}")
|
||||||
|
print("🚀 开始执行费用对比...")
|
||||||
|
|
||||||
|
# 调用你的主函数
|
||||||
|
compare_costs_batch(calc_dir, proj_json)
|
||||||
|
print("🎉 费用对比完成!")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
_main()
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -11,12 +11,11 @@ import re
|
|||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
|
||||||
# 配置logging
|
# 配置logging(不在导入时绑定固定文件,具体文件由调用方配置)
|
||||||
logging.basicConfig(
|
_root_logger = logging.getLogger()
|
||||||
level=logging.INFO,
|
if not _root_logger.handlers:
|
||||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
# 避免 "No handler could be found" 警告
|
||||||
handlers=[logging.FileHandler("bcl_calculator.log"), logging.StreamHandler()],
|
_root_logger.addHandler(logging.NullHandler())
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class BCLVariantType(Enum):
|
class BCLVariantType(Enum):
|
||||||
@@ -1609,30 +1608,63 @@ class BCLCalculator:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
var_name = var_node.get("text")
|
var_name = var_node.get("text")
|
||||||
variables[var_name] = self._get_variable_value(var_name, context)
|
var_value_obj = self._get_variable_value(var_name, context)
|
||||||
|
variables[var_name] = var_value_obj
|
||||||
|
|
||||||
# 构建表达式字符串
|
# 构建表达式字符串
|
||||||
expr_str = expr_node.get("text")
|
expr_str = expr_node.get("text", "<unknown>")
|
||||||
|
if not expr_str:
|
||||||
|
expr_str = "<empty>"
|
||||||
|
|
||||||
|
# 构造符号表,转换为 float
|
||||||
symbols = {}
|
symbols = {}
|
||||||
for var_name, var_value in variables.items():
|
var_values_log = {}
|
||||||
symbols[var_name] = float("0" if not var_value.get_value() else var_value.get_value())
|
for var_name, var_value_obj in variables.items():
|
||||||
|
raw_value = var_value_obj.get_value()
|
||||||
|
try:
|
||||||
|
# 安全转换为 float
|
||||||
|
float_value = float("0" if not raw_value else raw_value)
|
||||||
|
symbols[var_name] = float_value
|
||||||
|
var_values_log[var_name] = float_value
|
||||||
|
except (ValueError, TypeError) as e:
|
||||||
|
var_values_log[var_name] = f"无法转换为float: {raw_value} (类型: {type(raw_value).__name__})"
|
||||||
|
|
||||||
|
logging.debug(f"开始计算表达式: '{expr_str}'")
|
||||||
|
logging.debug(f"变量绑定值: {var_values_log}")
|
||||||
|
|
||||||
calculator = ExpressionCalculator()
|
calculator = ExpressionCalculator()
|
||||||
parse_success = calculator.parse_expression(expr_str)
|
parse_success = calculator.parse_expression(expr_str)
|
||||||
if not parse_success:
|
if not parse_success:
|
||||||
logging.error(f"表达式解析失败: {calculator.get_last_error()}")
|
error_msg = calculator.get_last_error()
|
||||||
raise ValueError(f"表达式解析失败: {calculator.get_last_error()}")
|
logging.error(
|
||||||
|
f"[表达式解析失败] " f"表达式='{expr_str}', " f"变量值={var_values_log}, " f"错误详情='{error_msg}'"
|
||||||
|
)
|
||||||
|
raise ValueError(f"表达式解析失败: {error_msg}")
|
||||||
|
|
||||||
# 执行四则运算并返回结果
|
# 执行四则运算并返回结果
|
||||||
result, value = calculator.evaluate(symbols)
|
result, value = calculator.evaluate(symbols)
|
||||||
if not result:
|
if not result:
|
||||||
logging.error(f"表达式计算失败: {calculator.get_last_error()}")
|
error_msg = calculator.get_last_error()
|
||||||
raise ValueError(f"表达式计算失败: {calculator.get_last_error()}")
|
logging.error(
|
||||||
|
f"[表达式计算失败] "
|
||||||
|
f"表达式='{expr_str}', "
|
||||||
|
f"变量值={var_values_log}, "
|
||||||
|
f"错误类型='{error_msg}', "
|
||||||
|
)
|
||||||
|
raise ValueError(f"表达式计算失败: {expr_str} (变量: {var_values_log}) => 错误: {error_msg}")
|
||||||
|
|
||||||
|
logging.debug(f"表达式计算成功: '{expr_str}' => {value}")
|
||||||
return BCLVariant(value)
|
return BCLVariant(value)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
# 捕获所有异常,打印完整堆栈和上下文
|
||||||
|
logging.error(
|
||||||
|
f"[_evaluate_expression] 未预期异常: {str(e)}\n"
|
||||||
|
f"表达式节点文本: {expr_node.get('text', 'N/A')}\n"
|
||||||
|
f"变量上下文: {[child.get('text') for child in expr_node if child.get('type') == '变量']}\n"
|
||||||
|
f"完整堆栈:\n{traceback.format_exc()}"
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
def _call_function(self, func_name: str, node: ET.Element, context: BCLContext) -> BCLVariant:
|
def _call_function(self, func_name: str, node: ET.Element, context: BCLContext) -> BCLVariant:
|
||||||
|
|
||||||
|
|||||||
@@ -395,50 +395,77 @@ def create_equipment_from_node(node: dict[str, any]) -> Equipment:
|
|||||||
return equipment
|
return equipment
|
||||||
|
|
||||||
|
|
||||||
def init_bcl_calculator(software_category, engineering_type, calculation_type, project_type: Optional[str] = None):
|
def init_bcl_calculator(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
初始化BCL计算器
|
初始化BCL计算器
|
||||||
|
|
||||||
Args:
|
新接口(推荐):
|
||||||
software_category: 软件类别(主网/配网/技改)
|
init_bcl_calculator(bcl_dir_path: str) -> bool
|
||||||
engineering_type: 工程类型(预算/清单)
|
|
||||||
calculation_type: 计算类型(工程量/人材机)
|
兼容旧接口:
|
||||||
project_type: 项目类型(如 变电/线路 等);仅用于工程量时筛选要加载的XML文件
|
init_bcl_calculator(software_category, engineering_type, calculation_type, project_type: Optional[str] = None)
|
||||||
|
|
||||||
|
兼容极旧/无参调用:
|
||||||
|
init_bcl_calculator() # 不执行加载,直接返回 True,避免旧代码报错
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否成功初始化
|
bool: 是否成功初始化
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# 构建计算配置路径
|
|
||||||
# 格式:计算配置/软件类型(主网,配网,技改)/计算类型(工程量,人材机)/工程类型(预算,清单)
|
|
||||||
config_path = f"equipment_calculation/计算配置/{software_category}/{calculation_type}/{engineering_type}"
|
|
||||||
|
|
||||||
print(f"加载计算配置: {config_path}")
|
|
||||||
|
|
||||||
# 检查目录是否存在
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# 解析参数:优先使用新接口的单一路径
|
||||||
|
bcl_dir_path: Optional[str] = None
|
||||||
|
software_category = None
|
||||||
|
engineering_type = None
|
||||||
|
calculation_type = None
|
||||||
|
project_type = None
|
||||||
|
|
||||||
|
# 新接口:单一位置参数为路径
|
||||||
|
if len(args) == 1 and isinstance(args[0], str):
|
||||||
|
bcl_dir_path = args[0]
|
||||||
|
# 旧接口:按原有签名位置参数
|
||||||
|
elif len(args) >= 3:
|
||||||
|
software_category, engineering_type, calculation_type = args[:3]
|
||||||
|
project_type = args[3] if len(args) >= 4 else None
|
||||||
|
else:
|
||||||
|
# 也尝试从kwargs读取
|
||||||
|
bcl_dir_path = kwargs.get("bcl_dir_path")
|
||||||
|
software_category = kwargs.get("software_category")
|
||||||
|
engineering_type = kwargs.get("engineering_type")
|
||||||
|
calculation_type = kwargs.get("calculation_type")
|
||||||
|
project_type = kwargs.get("project_type")
|
||||||
|
|
||||||
|
# 无参极旧调用:直接返回 True(不加载任何脚本,避免中断旧流程)
|
||||||
|
if bcl_dir_path is None and software_category is None and engineering_type is None and calculation_type is None:
|
||||||
|
print("init_bcl_calculator: 无参数调用,跳过加载(兼容模式)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 确定配置目录
|
||||||
|
if bcl_dir_path:
|
||||||
|
config_path = bcl_dir_path
|
||||||
|
print(f"加载计算配置(新接口): {config_path}")
|
||||||
|
else:
|
||||||
|
# 保持旧接口逻辑
|
||||||
|
config_path = f"equipment_calculation/计算配置/{software_category}/{calculation_type}/{engineering_type}"
|
||||||
|
print(f"加载计算配置(旧接口): {config_path}")
|
||||||
|
|
||||||
|
# 目录存在性处理
|
||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
print(f"计算配置目录不存在: {config_path}")
|
print(f"计算配置目录不存在: {config_path}")
|
||||||
# 尝试创建目录
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(config_path, exist_ok=True)
|
os.makedirs(config_path, exist_ok=True)
|
||||||
print(f"已创建计算配置目录: {config_path}")
|
print(f"已创建计算配置目录: {config_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"创建计算配置目录失败: {e}")
|
print(f"创建计算配置目录失败: {e}")
|
||||||
|
|
||||||
# 如果目录不存在,使用默认配置
|
# 旧逻辑下的默认回退
|
||||||
default_path = "equipment_calculation/计算配置/主网/工程量/预算"
|
default_path = "equipment_calculation/计算配置/主网/工程量/预算"
|
||||||
print(f"使用默认计算配置: {default_path}")
|
print(f"使用默认计算配置: {default_path}")
|
||||||
|
|
||||||
# 检查默认配置目录是否存在
|
|
||||||
if not os.path.exists(default_path):
|
if not os.path.exists(default_path):
|
||||||
print(f"默认计算配置目录不存在: {default_path}")
|
print(f"默认计算配置目录不存在: {default_path}")
|
||||||
# 尝试使用原始默认配置
|
|
||||||
original_default_path = "equipment_calculation/计算配置/主网/主网预算"
|
original_default_path = "equipment_calculation/计算配置/主网/主网预算"
|
||||||
print(f"尝试使用原始默认计算配置: {original_default_path}")
|
print(f"尝试使用原始默认计算配置: {original_default_path}")
|
||||||
|
|
||||||
if os.path.exists(original_default_path):
|
if os.path.exists(original_default_path):
|
||||||
config_path = original_default_path
|
config_path = original_default_path
|
||||||
else:
|
else:
|
||||||
@@ -448,13 +475,12 @@ def init_bcl_calculator(software_category, engineering_type, calculation_type, p
|
|||||||
config_path = default_path
|
config_path = default_path
|
||||||
|
|
||||||
# 加载脚本
|
# 加载脚本
|
||||||
# 对于工程量,若提供了project_type且存在映射,则仅加载映射中指定的XML
|
|
||||||
result = True
|
result = True
|
||||||
use_filtered_files = False
|
use_filtered_files = False
|
||||||
try:
|
|
||||||
import os
|
|
||||||
|
|
||||||
if calculation_type == "工程量" and project_type:
|
# 仅当旧接口+工程量+提供project_type时,启用按映射筛选
|
||||||
|
try:
|
||||||
|
if (not bcl_dir_path) and calculation_type == "工程量" and project_type:
|
||||||
target_list = PROJECT_TYPE_XML_MAP.get(software_category, {}).get(project_type) or []
|
target_list = PROJECT_TYPE_XML_MAP.get(software_category, {}).get(project_type) or []
|
||||||
if target_list:
|
if target_list:
|
||||||
use_filtered_files = True
|
use_filtered_files = True
|
||||||
@@ -482,7 +508,6 @@ def init_bcl_calculator(software_category, engineering_type, calculation_type, p
|
|||||||
else:
|
else:
|
||||||
print(f"未找到映射项,按目录全部加载: 软件={software_category}, 项目类型={project_type}")
|
print(f"未找到映射项,按目录全部加载: 软件={software_category}, 项目类型={project_type}")
|
||||||
except Exception as _e:
|
except Exception as _e:
|
||||||
# 映射/筛选流程异常时,退回目录加载
|
|
||||||
print(f"按项目类型筛选加载发生异常,退回目录加载: {_e}")
|
print(f"按项目类型筛选加载发生异常,退回目录加载: {_e}")
|
||||||
use_filtered_files = False
|
use_filtered_files = False
|
||||||
|
|
||||||
@@ -490,17 +515,13 @@ def init_bcl_calculator(software_category, engineering_type, calculation_type, p
|
|||||||
result = calculator.load_scripts_dir(config_path)
|
result = calculator.load_scripts_dir(config_path)
|
||||||
if False == result:
|
if False == result:
|
||||||
print(f"加载脚本错误: {calculator.get_last_error()}")
|
print(f"加载脚本错误: {calculator.get_last_error()}")
|
||||||
# 尝试使用默认配置
|
# 默认回退
|
||||||
default_path = "equipment_calculation/计算配置/主网/工程量/预算"
|
default_path = "equipment_calculation/计算配置/主网/工程量/预算"
|
||||||
print(f"尝试使用默认计算配置: {default_path}")
|
print(f"尝试使用默认计算配置: {default_path}")
|
||||||
|
|
||||||
# 检查默认配置目录是否存在
|
|
||||||
if not os.path.exists(default_path):
|
if not os.path.exists(default_path):
|
||||||
print(f"默认计算配置目录不存在: {default_path}")
|
print(f"默认计算配置目录不存在: {default_path}")
|
||||||
# 尝试使用原始默认配置
|
|
||||||
original_default_path = "equipment_calculation/计算配置/主网/主网预算"
|
original_default_path = "equipment_calculation/计算配置/主网/主网预算"
|
||||||
print(f"尝试使用原始默认计算配置: {original_default_path}")
|
print(f"尝试使用原始默认计算配置: {original_default_path}")
|
||||||
|
|
||||||
if os.path.exists(original_default_path):
|
if os.path.exists(original_default_path):
|
||||||
result = calculator.load_scripts_dir(original_default_path)
|
result = calculator.load_scripts_dir(original_default_path)
|
||||||
if False == result:
|
if False == result:
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ class CalculatorBase(ABC):
|
|||||||
self.calculation_strategy = self.create_calculation_strategy()
|
self.calculation_strategy = self.create_calculation_strategy()
|
||||||
# 默认输出目录
|
# 默认输出目录
|
||||||
self.output_dir = os.path.join("计算结果", self.software_type.name)
|
self.output_dir = os.path.join("计算结果", self.software_type.name)
|
||||||
|
# 新增:BCL 脚本目录(优先使用新接口)
|
||||||
|
self.bcl_dir: str | None = None
|
||||||
|
|
||||||
def create_calculation_strategy(self) -> CalculationStrategy:
|
def create_calculation_strategy(self) -> CalculationStrategy:
|
||||||
"""
|
"""
|
||||||
@@ -60,6 +62,15 @@ class CalculatorBase(ABC):
|
|||||||
if hasattr(self.calculation_strategy, "set_output_dir"):
|
if hasattr(self.calculation_strategy, "set_output_dir"):
|
||||||
self.calculation_strategy.set_output_dir(output_dir)
|
self.calculation_strategy.set_output_dir(output_dir)
|
||||||
|
|
||||||
|
def set_bcl_dir(self, bcl_dir: str) -> None:
|
||||||
|
"""
|
||||||
|
设置 BCL 脚本目录路径(新接口)。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bcl_dir: BCL 目录路径
|
||||||
|
"""
|
||||||
|
self.bcl_dir = bcl_dir
|
||||||
|
|
||||||
def _append_log(self, text: str, filename: str = "performance_memory_log.txt") -> str:
|
def _append_log(self, text: str, filename: str = "performance_memory_log.txt") -> str:
|
||||||
"""将文本即时追加写入输出目录下的日志文件,并返回日志路径。"""
|
"""将文本即时追加写入输出目录下的日志文件,并返回日志路径。"""
|
||||||
try:
|
try:
|
||||||
@@ -121,12 +132,16 @@ class CalculatorBase(ABC):
|
|||||||
# 外层只初始化一次 BCL 计算器
|
# 外层只初始化一次 BCL 计算器
|
||||||
from equipment_calculation.bcl_utils import init_bcl_calculator
|
from equipment_calculation.bcl_utils import init_bcl_calculator
|
||||||
|
|
||||||
init_bcl_calculator(
|
if getattr(self, "bcl_dir", None):
|
||||||
software_category=self.software_type.category.value,
|
init_bcl_calculator(self.bcl_dir)
|
||||||
engineering_type=self.software_type.engineering_type.value,
|
# else:
|
||||||
calculation_type="工程量",
|
# # 兼容老接口
|
||||||
project_type=project_type,
|
# 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:
|
if project_name:
|
||||||
# 处理单个项目划分
|
# 处理单个项目划分
|
||||||
@@ -177,11 +192,15 @@ class CalculatorBase(ABC):
|
|||||||
# 外层只初始化一次 BCL 计算器(人材机)
|
# 外层只初始化一次 BCL 计算器(人材机)
|
||||||
from equipment_calculation.bcl_utils import init_bcl_calculator
|
from equipment_calculation.bcl_utils import init_bcl_calculator
|
||||||
|
|
||||||
init_bcl_calculator(
|
if getattr(self, "bcl_dir", None):
|
||||||
software_category=self.software_type.category.value,
|
init_bcl_calculator(self.bcl_dir)
|
||||||
engineering_type=self.software_type.engineering_type.value,
|
# else:
|
||||||
calculation_type="人材机",
|
# # 兼容老接口
|
||||||
)
|
# init_bcl_calculator(
|
||||||
|
# software_category=self.software_type.category.value,
|
||||||
|
# engineering_type=self.software_type.engineering_type.value,
|
||||||
|
# calculation_type="人材机",
|
||||||
|
# )
|
||||||
|
|
||||||
if project_name:
|
if project_name:
|
||||||
# 处理单个项目划分
|
# 处理单个项目划分
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ExpressionCalculator:
|
|||||||
"""将表达式字符串分解为标记列表"""
|
"""将表达式字符串分解为标记列表"""
|
||||||
token_spec = [
|
token_spec = [
|
||||||
("NUMBER", r"\d+(\.\d*)?"), # 整数或小数
|
("NUMBER", r"\d+(\.\d*)?"), # 整数或小数
|
||||||
("VARIABLE", r"@?[a-zA-Z_\u4e00-\u9fa5][\w.@\u4e00-\u9fa5]+"), # 支持带点的复合变量
|
("VARIABLE", r"@?[a-zA-Z_\u4e00-\u9fa5][\w.@\u4e00-\u9fa5]*"), # 支持带点的复合变量,允许单字符变量
|
||||||
("OPERATOR", r"[+\-*/()]"), # 运算符
|
("OPERATOR", r"[+\-*/()]"), # 运算符
|
||||||
("SKIP", r"\s+"), # 跳过空格
|
("SKIP", r"\s+"), # 跳过空格
|
||||||
("MISMATCH", r"."), # 其他字符
|
("MISMATCH", r"."), # 其他字符
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
from memory_profiler import profile
|
from memory_profiler import profile
|
||||||
from typing import Dict, List, Any, Optional, Tuple
|
from typing import Dict, List, Any, Optional, Tuple
|
||||||
from equipment_calculation.software_types import (
|
from equipment_calculation.software_types import (
|
||||||
@@ -32,8 +33,15 @@ CATEGORY_MAPPING = {
|
|||||||
|
|
||||||
# 项目类型名称映射字典,将各种变体映射到标准类型(预算/清单)
|
# 项目类型名称映射字典,将各种变体映射到标准类型(预算/清单)
|
||||||
PROJECT_TYPE_MAPPING = {
|
PROJECT_TYPE_MAPPING = {
|
||||||
# 预算类变体
|
|
||||||
"概预算工程": "预算",
|
"概预算工程": "预算",
|
||||||
|
"初步设计概算": "预算",
|
||||||
|
"可行性研究投资估算": "预算",
|
||||||
|
"施工图预算": "预算",
|
||||||
|
"配网定额计价": "预算",
|
||||||
|
"招标控制价": "清单",
|
||||||
|
"投标报价": "清单",
|
||||||
|
"招投标工程": "清单",
|
||||||
|
"配网清单招投标计价": "清单",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -55,8 +63,8 @@ def parse_json_content(json_file_path: str) -> Tuple[Optional[str], Optional[str
|
|||||||
# 提取 basicData
|
# 提取 basicData
|
||||||
basic_data = data.get("basicData", {}) if isinstance(data, dict) else {}
|
basic_data = data.get("basicData", {}) if isinstance(data, dict) else {}
|
||||||
# 软件类别(优先 软件类别,其次 软件名称)
|
# 软件类别(优先 软件类别,其次 软件名称)
|
||||||
category = basic_data.get("软件名称") or basic_data.get("软件名称")
|
category = basic_data.get("软件类别") or basic_data.get("软件名称")
|
||||||
engineering_type = basic_data.get("项目类型")
|
engineering_type = basic_data.get("项目类型") or basic_data.get("工程类型") or basic_data.get("工程类别")
|
||||||
# 规范化项目类型为 预算/清单
|
# 规范化项目类型为 预算/清单
|
||||||
if engineering_type:
|
if engineering_type:
|
||||||
mapped_pt = PROJECT_TYPE_MAPPING.get(engineering_type)
|
mapped_pt = PROJECT_TYPE_MAPPING.get(engineering_type)
|
||||||
@@ -88,7 +96,13 @@ def parse_json_content(json_file_path: str) -> Tuple[Optional[str], Optional[str
|
|||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
def process_json_file(json_file_path: str, output_dir: str, calculate_type: str, project_name: str = None) -> bool:
|
def process_json_file(
|
||||||
|
json_file_path: str,
|
||||||
|
output_dir: str,
|
||||||
|
calculate_type: str,
|
||||||
|
project_name: str = None,
|
||||||
|
bcl_dir_path: str | None = None,
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
处理单个JSON文件
|
处理单个JSON文件
|
||||||
|
|
||||||
@@ -127,6 +141,9 @@ def process_json_file(json_file_path: str, output_dir: str, calculate_type: str,
|
|||||||
|
|
||||||
# 获取计算器
|
# 获取计算器
|
||||||
calculator = get_calculator(software_type)
|
calculator = get_calculator(software_type)
|
||||||
|
# 若提供了 bcl 目录,优先使用新接口
|
||||||
|
if hasattr(calculator, "set_bcl_dir") and bcl_dir_path:
|
||||||
|
calculator.set_bcl_dir(bcl_dir_path)
|
||||||
if not calculator:
|
if not calculator:
|
||||||
print(f"错误: 未找到软件类型 {software_type.name} 的计算器")
|
print(f"错误: 未找到软件类型 {software_type.name} 的计算器")
|
||||||
return False
|
return False
|
||||||
@@ -184,6 +201,9 @@ def process_json_file(json_file_path: str, output_dir: str, calculate_type: str,
|
|||||||
|
|
||||||
# 创建自定义输出目录的计算器
|
# 创建自定义输出目录的计算器
|
||||||
custom_calculator = CustomOutputCalculator(calculator, custom_output_dir)
|
custom_calculator = CustomOutputCalculator(calculator, custom_output_dir)
|
||||||
|
# 自定义计算器同样继承 bcl_dir 设置
|
||||||
|
if hasattr(custom_calculator, "set_bcl_dir") and bcl_dir_path:
|
||||||
|
custom_calculator.set_bcl_dir(bcl_dir_path)
|
||||||
|
|
||||||
# 根据计算类型执行计算
|
# 根据计算类型执行计算
|
||||||
if calculate_type in ["all", "quantity"]:
|
if calculate_type in ["all", "quantity"]:
|
||||||
@@ -212,7 +232,9 @@ def process_json_file(json_file_path: str, output_dir: str, calculate_type: str,
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def process_directory(input_dir: str, output_dir: str, calculate_type: str = "quantity") -> None:
|
def process_directory(
|
||||||
|
input_dir: str, output_dir: str, calculate_type: str = "quantity", bcl_dir_path: str | None = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
批量处理目录中的JSON文件
|
批量处理目录中的JSON文件
|
||||||
|
|
||||||
@@ -239,13 +261,15 @@ def process_directory(input_dir: str, output_dir: str, calculate_type: str = "qu
|
|||||||
json_file_path = os.path.join(input_dir, json_file)
|
json_file_path = os.path.join(input_dir, json_file)
|
||||||
print(f"处理文件 {i}/{len(json_files)}: {json_file}")
|
print(f"处理文件 {i}/{len(json_files)}: {json_file}")
|
||||||
|
|
||||||
if process_json_file(json_file_path, output_dir, calculate_type):
|
if process_json_file(json_file_path, output_dir, calculate_type, bcl_dir_path=bcl_dir_path):
|
||||||
success_count += 1
|
success_count += 1
|
||||||
|
|
||||||
print(f"处理完成,成功: {success_count}/{len(json_files)}")
|
print(f"处理完成,成功: {success_count}/{len(json_files)}")
|
||||||
|
|
||||||
|
|
||||||
def bcl_calculate(input_dir: str, output_dir: str, calculate_type: str = "quantity") -> None:
|
def bcl_calculate(
|
||||||
|
input_dir: str, output_dir: str, calculate_type: str = "quantity", bcl_dir_path: str | None = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
主函数,处理指定目录中的所有JSON文件
|
主函数,处理指定目录中的所有JSON文件
|
||||||
|
|
||||||
@@ -254,10 +278,54 @@ def bcl_calculate(input_dir: str, output_dir: str, calculate_type: str = "quanti
|
|||||||
output_dir: 输出目录路径
|
output_dir: 输出目录路径
|
||||||
calculate_type: 计算类型(all: 全部, quantity: 工程量取费, resource: 人材机合价)
|
calculate_type: 计算类型(all: 全部, quantity: 工程量取费, resource: 人材机合价)
|
||||||
"""
|
"""
|
||||||
|
# 将日志写入本次工程的 bclresults 目录
|
||||||
|
_configure_bcl_logging(output_dir)
|
||||||
|
|
||||||
print(f"开始处理目录: {input_dir}")
|
print(f"开始处理目录: {input_dir}")
|
||||||
print(f"输出目录: {output_dir}")
|
print(f"输出目录: {output_dir}")
|
||||||
print(f"计算类型: {calculate_type}")
|
print(f"计算类型: {calculate_type}")
|
||||||
|
|
||||||
process_directory(input_dir, output_dir, calculate_type)
|
process_directory(input_dir, output_dir, calculate_type, bcl_dir_path=bcl_dir_path)
|
||||||
|
|
||||||
print("所有文件处理完成")
|
print("所有文件处理完成")
|
||||||
|
|
||||||
|
|
||||||
|
def _configure_bcl_logging(log_dir: str):
|
||||||
|
"""将 bcl 计算日志写入指定目录下的 bcl_calculator.log。
|
||||||
|
|
||||||
|
- 清理先前的 FileHandler,避免多次叠加/重复输出。
|
||||||
|
- 保留/添加一个 StreamHandler 以在控制台输出。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
|
log_path = os.path.join(log_dir, "bcl_calculator.log")
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 移除已有的 FileHandler,避免写到旧位置或重复写
|
||||||
|
for h in list(logger.handlers):
|
||||||
|
if isinstance(h, logging.FileHandler):
|
||||||
|
logger.removeHandler(h)
|
||||||
|
try:
|
||||||
|
h.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||||
|
|
||||||
|
file_handler = logging.FileHandler(log_path, mode="w", encoding="utf-8")
|
||||||
|
file_handler.setLevel(logging.INFO)
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
# 确保有一个控制台输出
|
||||||
|
if not any(isinstance(h, logging.StreamHandler) for h in logger.handlers):
|
||||||
|
stream_handler = logging.StreamHandler()
|
||||||
|
stream_handler.setLevel(logging.INFO)
|
||||||
|
stream_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(stream_handler)
|
||||||
|
|
||||||
|
print(f"日志输出重定向到: {log_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"配置日志输出失败,将继续使用默认日志配置: {e}")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
BEGIN:单价_定额重算
|
|
||||||
${
|
|
||||||
sum(source, "定额", ?round(定额.人工费*定额.人工系数*定额.定额系数+定额.材料费*定额.材料系数*定额.定额系数+定额.机械费*定额.机械系数*定额.定额系数, 2))
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
BEGIN:单价_定额重算
|
|
||||||
${
|
|
||||||
sum(source, "定额", ?round(定额.人工费*定额.人工系数*定额.定额系数+定额.材料费*定额.材料系数*定额.材料综合系数*定额.定额系数+定额.机械费*定额.机械系数*定额.机械综合系数*定额.定额系数, 2))
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
|
|
||||||
/////////////////定额人工工日计算过滤函数////////////////////////////////
|
|
||||||
|
|
||||||
BEGIN:_过滤人工工日
|
|
||||||
${
|
|
||||||
filter(source ,"人材机",?人材机.type == "人工" && 人材机.单位 == "工日")
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////定额人材机重算调用函数 ////////////////////////////////
|
|
||||||
/////////////////////////////目前采用资源库中定义的通用算法 仅提供人工工日的计算配置 ////////////////////////////////
|
|
||||||
|
|
||||||
BEGIN:_定额_人工工日
|
|
||||||
${
|
|
||||||
sum(_过滤人工工日(), "人材机", ? 人材机.数量 )
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// 定额重算(与技改平台兼容的代码)
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
BEGIN:_普通人工费_定额重算
|
|
||||||
${ _普通人工费_非%_计价_() + _普通人工费_%_()}
|
|
||||||
|
|
||||||
BEGIN:人工费_定额重算
|
|
||||||
${ _定额_人工费@算法2_() }
|
|
||||||
|
|
||||||
BEGIN:_普通材料费_定额重算
|
|
||||||
${ _普通材料费_%_算法2_()}
|
|
||||||
|
|
||||||
BEGIN:_其他材料费_定额重算
|
|
||||||
${ _其他费_材料_%_算法2_() }
|
|
||||||
|
|
||||||
BEGIN:材料费_定额重算
|
|
||||||
${
|
|
||||||
_定额_材料费@算法2_()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:甲供材料费_定额重算
|
|
||||||
${
|
|
||||||
_定额_甲供材料费@算法2_()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:甲供材料费_定额重算_含税
|
|
||||||
${
|
|
||||||
_变量_甲供材料费@算法2_()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_甲供普通材料费_定额重算
|
|
||||||
${
|
|
||||||
_甲供普通材料费_%_算法2_()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_甲供其他材料费_定额重算
|
|
||||||
${
|
|
||||||
_甲供其他费_材料_%_算法2_()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_普通机械费_定额重算
|
|
||||||
${ _普通机械费_%_算法2_()}
|
|
||||||
|
|
||||||
BEGIN:_其他机械费_定额重算
|
|
||||||
${_其他费_机械_%_算法2_() }
|
|
||||||
|
|
||||||
BEGIN:机械费_定额重算
|
|
||||||
${ _定额_机械费@算法2_() }
|
|
||||||
|
|
||||||
BEGIN:基价_定额重算
|
|
||||||
${
|
|
||||||
sum(source, "定额", ?round(定额.人工费+定额.材料费+定额.机械费, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:拆分材料父级预算价_定额重算
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级人工预算合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级机械预算合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级材料预算合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:拆分材料父级市场价_定额重算
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级人工市场价合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级机械市场价合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级材料市场价合价_消材
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:拆分父级预算价_定额重算
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级人工预算合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级机械预算合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级材料预算合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:拆分父级市场价_定额重算
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级人工市场价合价
|
|
||||||
${ 0.0 }
|
|
||||||
BEGIN:_拆分子级机械市场价合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级材料市场价合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:拆分父级原价_定额重算
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级人工原价合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级机械原价合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
BEGIN:_拆分子级材料原价合价
|
|
||||||
${ 0.0 }
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,218 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// 材机分析汇总变量计算
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
BEGIN:_统计水超运数量_人力运输
|
|
||||||
${
|
|
||||||
?@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.人力运输
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计水超运数量_汽车运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.汽车运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计水超运数量_船舶运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.船舶运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计水超运数量_拖拉机运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.拖拉机运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * 0.36 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_人力运输
|
|
||||||
${
|
|
||||||
?@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.人力运输
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_汽车运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.汽车运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_船舶运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.船舶运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_拖拉机运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.拖拉机运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计拆除工地运输数量_人力运输
|
|
||||||
${
|
|
||||||
?@统计项.数量 * @统计项.单重 / 1000 * @统计参数.人力运输
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计拆除工地运输数量_汽车运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * @统计参数.汽车运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计拆除工地运输数量_船舶运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * @统计参数.船舶运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计拆除工地运输数量_拖拉机运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * @统计参数.拖拉机运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_往复式索道运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.往复式索道运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计工地运输数量_循环式索道运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.循环式索道运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * @统计项.单重 / 1000 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------余土外运-------------------------------------------
|
|
||||||
BEGIN:_统计余土外运数量_人力运输
|
|
||||||
${
|
|
||||||
?@统计项.数量 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.人力运输
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计余土外运数量_汽车运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01) * @统计参数.汽车运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计余土外运数量_船舶运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01)* (1 + @统计项.包装系数 * 0.01) * @统计参数.船舶运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计余土外运数量_拖拉机运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01) * @统计参数.拖拉机运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计余土外运数量_往复式索道运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01) * @统计参数.往复式索道运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_统计余土外运数量_循环式索道运输
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@统计项.装卸 == "0"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01) * @统计参数.循环式索道运输;
|
|
||||||
->@统计项.装卸 == "1"
|
|
||||||
:
|
|
||||||
@统计项.数量 * ( 1 + @统计项.损耗 * 0.01) * (1 + @统计项.包装系数 * 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
BEGIN:建筑拆除脚手架搭拆费代码
|
|
||||||
${ "" }
|
|
||||||
|
|
||||||
BEGIN:拆分人工代码
|
|
||||||
${ "" }
|
|
||||||
|
|
||||||
BEGIN:脚手架记取定额范围
|
|
||||||
${
|
|
||||||
"PT13-1~200,PT14-1~152,PT15-1~195,PT16-1~203,PT17-1~55,PT18-1~49,XYT15-1~189,XYT16-1~106,XYT17-1~133,XYT18-1~104,XYT19-1~35"
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:建筑调试费代码(计取接地调试费)
|
|
||||||
${
|
|
||||||
"PT14-114~130,PT14-135~151"
|
|
||||||
}
|
|
||||||
BEGIN:建筑调试费代码(计取消防调试费)
|
|
||||||
${
|
|
||||||
"PT15-1~195"
|
|
||||||
}
|
|
||||||
BEGIN:建筑调试费代码(计取通风调试费)
|
|
||||||
${
|
|
||||||
"PT16-1~31,PT16-54~66,PT16-108~203"
|
|
||||||
}
|
|
||||||
BEGIN:建筑调试费代码(计取采暖调试费)
|
|
||||||
${
|
|
||||||
"PT17-1~50,PT17-53~55"
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
///////////////////////////////////广东差异变量//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
BEGIN:_设计费_基础费用_宏变量
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->@通用设计费.工程划分 == "充配电工程"
|
|
||||||
: 设计费_充配电基本设计费_宏变量();
|
|
||||||
->@通用设计费.工程划分 == "线路工程"
|
|
||||||
: 设计费_线路基本设计费_宏变量();
|
|
||||||
->@通用设计费.工程划分 == "混合"
|
|
||||||
: 设计费_充配电基本设计费_宏变量() + 设计费_线路基本设计费_宏变量();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////贵州差异变量//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
BEGIN:一笔性费用
|
|
||||||
${
|
|
||||||
?一笔性费用含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:一笔性费用含税
|
|
||||||
${
|
|
||||||
sum(_过滤一笔性费用(), "一笔性费用", ? 一笔性费用.数量 * 一笔性费用.市场价含税 * _项目划分费率() )
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:一笔性费用不含税
|
|
||||||
${
|
|
||||||
sum(_过滤一笔性费用(), "一笔性费用", ? 一笔性费用.数量 * 一笔性费用.市场价不含税 * _项目划分费率() )
|
|
||||||
}
|
|
||||||
@@ -1,529 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// 材机分析汇总变量计算
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
BEGIN:_工程费用小数位数
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
-> @工程信息.工程费用小数位数 == "整数"
|
|
||||||
:
|
|
||||||
0.0;
|
|
||||||
-> @工程信息.工程费用小数位数 == "1位小数"
|
|
||||||
:
|
|
||||||
1.0;
|
|
||||||
-> @工程信息.工程费用小数位数 == "2位小数"
|
|
||||||
:
|
|
||||||
2.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工价差
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 - 人材机.预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工价差合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价不含税 - 人材机.预算价不含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工市场价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工预算价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.预算价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械价差
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 - 人材机.预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械价差合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价不含税 - 人材机.预算价不含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机机械差值不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.结算价不含税 - 人材机.市场价不含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机机械市场价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机机械结算价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.结算价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机机械预算价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.预算价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料价差含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价含税 - 人材机.预算价含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料价差不含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 - 人材机.预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料价差合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价含税 - 人材机.预算价含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料价差合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价不含税 - 人材机.预算价不含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料差值含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.结算价含税 - 人材机.市场价含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料差值不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.结算价不含税 - 人材机.市场价不含税) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料市场价合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料市场价合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料结算价合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.结算价含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料结算价合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.结算价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料预算价合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.预算价含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料预算价合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.预算价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材价差
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 - 人材机.预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材价差合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价不含税 - 人材机.预算价不含税) * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材市场价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材预算价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.预算价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备运杂费
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 )
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备市场价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备运杂费合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件运杂费
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 )
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件原价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.原价 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件市场价合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件价差
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.市场价不含税 - 人材机.原价)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件价差合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.市场价不含税 - 人材机.原价) * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机配件运杂费合价
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备合价含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备合价不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.市场价不含税 * 人材机.数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//***********数量计算***********************************************
|
|
||||||
|
|
||||||
BEGIN:_材机主材总重
|
|
||||||
${
|
|
||||||
sum(source,"主材",?主材.单重 * 主材.数量)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------合并材机数量---------------20230128修改通信定额范围以及拆分人工的机械增加------------------------------//
|
|
||||||
//****2023年11月9日 运输定额的地形区分人运、汽车拖拉机计算*****//
|
|
||||||
|
|
||||||
BEGIN:_材机_定额地形系数_人工增加
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"JYX1-1~16")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.工地运输混凝土杆);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"JYX1-17~22")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.工地运输金具);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && (in(parent.编码,"JYX1-23~108") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.工汽拖运输);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX1-1~4")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.基础工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX2-1~40")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.杆塔工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX3-1~27")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.架线一般);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX3-28~42")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.架线张力);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX4-1~131")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.附件工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"JYX1-1~16")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.工地运输混凝土杆);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"JYX1-17~22")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.工地运输金具);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && (in(parent.编码,"JYX1-23~108") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.工汽拖运输);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX1-1~4")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.基础工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX2-1~40")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.杆塔工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX3-1~27")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.架线一般);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX3-28~42")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.架线张力);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX4-1~131")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.附件工程);
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && (in(parent.编码,"PZ1-87~129")|| in(parent.编码,"PGZ1-61~88"))
|
|
||||||
:
|
|
||||||
(_工程地形综合系数材机() );
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && strFind(parent.编码,"BG-PX7") == 0
|
|
||||||
:
|
|
||||||
(_工程地形综合系数材机() );
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && (strFind(parent.编码,"PX") == 0 || strFind(parent.编码,"PXG") == 0) &&(strFind(parent.编码,"PX1") != 0) && in(parent.编码,"PX5-77~86")==0
|
|
||||||
:
|
|
||||||
(_工程地形综合系数材机());
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && in(parent.编码,"PX1-1~6")
|
|
||||||
:
|
|
||||||
(_运输地形综合系数材机_不含城区());
|
|
||||||
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && (in(parent.编码,"PX1-7~30") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(_运输地形综合系数材机汽车拖拉机());
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && strFind(parent.编码,"PX1") == 0 && in(parent.编码,"PX1-1~30") == 0 && strFind(parent.名称,"装卸") == -1
|
|
||||||
:
|
|
||||||
(_运输地形综合系数材机());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机_定额地形系数_机械增加
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"JYX1-1~16")
|
|
||||||
:
|
|
||||||
0;
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"JYX1-17~22")
|
|
||||||
:
|
|
||||||
0;
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && (in(parent.编码,"JYX1-23~108") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.工汽拖运输);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX1-1~4")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.基础工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX2-1~40")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.杆塔工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX3-1~27")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.架线一般);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX3-28~42")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.架线张力);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "架空线路" && in(parent.编码,"CYX4-1~131")
|
|
||||||
:
|
|
||||||
(@拆除架空线路地形系数.附件工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"JYX1-1~16")
|
|
||||||
:
|
|
||||||
0;
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"JYX1-17~22")
|
|
||||||
:
|
|
||||||
0;
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && (in(parent.编码,"JYX1-23~108") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.工汽拖运输);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX1-1~4")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.基础工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX2-1~40")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.杆塔工程);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX3-1~27")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.架线一般);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX3-28~42")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.架线张力);
|
|
||||||
->parent.parent.专业类型 == "拆除" && parent.专业属性 == "通信线路" && in(parent.编码,"CYX4-1~131")
|
|
||||||
:
|
|
||||||
(@拆除通信线路地形系数.附件工程);
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && (in(parent.编码,"PZ1-87~129")|| in(parent.编码,"PGZ1-61~88"))
|
|
||||||
:
|
|
||||||
(_工程地形综合系数材机() );
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && strFind(parent.编码,"BG-PX7") == 0
|
|
||||||
:
|
|
||||||
(_工程地形综合系数材机() );
|
|
||||||
->parent.parent.专业类型 != "拆除" && parent.parent.专业类型 != "余物清理" && (strFind(parent.编码,"PX") == 0 || strFind(parent.编码,"PXG") == 0) &&(strFind(parent.编码,"PX1") != 0) && in(parent.编码,"PX5-77~86")==0
|
|
||||||
:
|
|
||||||
iif(in(parent.编码,"PX2-8~18,PX2-23~27,PX2-38~45,PX2-51~59,PX2-65~72"), 0, (_工程地形综合系数材机()));
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && in(parent.编码,"PX1-1~6")
|
|
||||||
:
|
|
||||||
0;
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && (in(parent.编码,"PX1-7~30") && strFind(parent.名称,"装卸") == -1)
|
|
||||||
:
|
|
||||||
(_运输地形综合系数材机汽车拖拉机());
|
|
||||||
|
|
||||||
->parent.专业类型 != "拆除" && parent.专业类型 != "余物清理" && strFind(parent.编码,"PX1") == 0 && in(parent.编码,"PX1-1~30") == 0 && strFind(parent.名称,"装卸") == -1
|
|
||||||
:
|
|
||||||
(_运输地形综合系数材机());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//****20230119,电缆线路改为通信线路**//
|
|
||||||
|
|
||||||
BEGIN:_工程地形综合系数材机
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.专业属性 == "架空线路"
|
|
||||||
:@工程地形系数.架空线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "通信线路"
|
|
||||||
:@工程地形系数.通信线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "10kV架空线路"
|
|
||||||
:@工程地形系数.10kV架空线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "400V及以下架空线路"
|
|
||||||
:@工程地形系数.400V及以下架空线路;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//****20231109,新增人力运输、汽车拖拉机运输地形**//
|
|
||||||
BEGIN:_运输地形综合系数材机
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.专业属性 == "架空线路"
|
|
||||||
:@运输地形系数.架空线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "通信线路"
|
|
||||||
:@运输地形系数.通信线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "10kV架空线路"
|
|
||||||
:@运输地形系数.10kV架空线路;
|
|
||||||
|
|
||||||
->parent.专业属性 == "400V及以下架空线路"
|
|
||||||
:@运输地形系数.400V及以下架空线路;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//****20230120,新增不含城区地形系数**//
|
|
||||||
|
|
||||||
BEGIN:_运输地形综合系数材机_不含城区
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.专业属性 == "架空线路"
|
|
||||||
:@运输地形系数.架空线路_其中:人力运输.不含城区;
|
|
||||||
->parent.专业属性 == "通信线路"
|
|
||||||
:@运输地形系数.通信线路_其中:人力运输.不含城区;
|
|
||||||
->parent.专业属性 == "10kV架空线路"
|
|
||||||
:@运输地形系数.10kV架空线路_其中:人力运输.不含城区;
|
|
||||||
->parent.专业属性 == "400V及以下架空线路"
|
|
||||||
:@运输地形系数.400V及以下架空线路_其中:人力运输.不含城区;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//****20231109,新增以下变量,为了区分出汽车拖拉机运输地形的取值**//
|
|
||||||
BEGIN:_运输地形综合系数材机汽车拖拉机
|
|
||||||
${
|
|
||||||
?#{
|
|
||||||
->parent.专业属性 == "架空线路"
|
|
||||||
:@运输地形系数.架空线路_其中:汽车拖拉机运输;
|
|
||||||
|
|
||||||
->parent.专业属性 == "通信线路"
|
|
||||||
:@运输地形系数.通信线路_其中:汽车拖拉机运输;
|
|
||||||
|
|
||||||
->parent.专业属性 == "10kV架空线路"
|
|
||||||
:@运输地形系数.10kV架空线路_其中:汽车拖拉机运输;
|
|
||||||
|
|
||||||
->parent.专业属性 == "400V及以下架空线路"
|
|
||||||
:@运输地形系数.400V及以下架空线路_其中:汽车拖拉机运输;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机合并机械数量
|
|
||||||
${
|
|
||||||
sum(source, "机械",?#{
|
|
||||||
->机械.type == "主材"
|
|
||||||
:
|
|
||||||
机械.数量 * _项目划分费率();
|
|
||||||
-> parent.type == "项目划分"
|
|
||||||
:
|
|
||||||
机械.数量;
|
|
||||||
-> parent.type != "项目划分"
|
|
||||||
:
|
|
||||||
parent.数量 * _项目划分费率() * 机械.数量 * parent.机械系数 * parent.定额系数 * ( 1 + _材机_定额地形系数_机械增加() / 100);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机合并人工数量
|
|
||||||
${
|
|
||||||
sum(source, "人工",?#{
|
|
||||||
->人工.type == "主材"
|
|
||||||
:
|
|
||||||
人工.数量 * _项目划分费率();
|
|
||||||
-> parent.type == "项目划分"
|
|
||||||
:
|
|
||||||
人工.数量;
|
|
||||||
-> parent.type != "项目划分"
|
|
||||||
:
|
|
||||||
parent.数量 * _项目划分费率() * 人工.数量 * parent.人工系数 * parent.定额系数 * ( 1 + _材机_定额地形系数_人工增加() / 100);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机合并主材数量
|
|
||||||
${
|
|
||||||
sum(source, "主材",?主材.数量)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机合并设备数量
|
|
||||||
${
|
|
||||||
sum(source, "设备",?设备.数量)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机合并材料数量
|
|
||||||
${
|
|
||||||
sum(source, "材料",?#{
|
|
||||||
-> parent.type == "项目划分"
|
|
||||||
:
|
|
||||||
材料.数量;
|
|
||||||
//普通材料
|
|
||||||
->parent.type == "定额"
|
|
||||||
:
|
|
||||||
parent.数量 * _项目划分费率() * 材料.数量 * parent.材料系数 * parent.定额系数;
|
|
||||||
//配合比材料
|
|
||||||
-> parent.type == "材料"
|
|
||||||
:
|
|
||||||
parent.数量 * parent.parent.数量 * _项目划分费率() * 材料.数量 * parent.parent.材料系数 * parent.parent.定额系数;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机合并定额数量
|
|
||||||
${
|
|
||||||
sum(source, "定额",?定额.数量)
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
//-------------------------------------人工审前变量---------------------------------------------
|
|
||||||
BEGIN:_材机人工审前价差不含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.审前市场价不含税 - 人材机.审前预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工审前市场价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工审前预算价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前预算价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工审前价差合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.审前市场价不含税 - 人材机.审前预算价不含税) * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工核增核减市场价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机人工市场价合价()-_材机人工审前市场价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机人工核增核减预算价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机人工预算价合价()-_材机人工审前预算价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------机械审前变量---------------------------------------------
|
|
||||||
BEGIN:_材机机械审前价差不含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.审前市场价不含税 - 人材机.审前预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械审前市场价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械审前预算价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前预算价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械审前价差合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.审前市场价不含税 - 人材机.审前预算价不含税) * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械核增核减市场价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机机械市场价合价()-_材机机械审前市场价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机机械核增核减预算价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机机械预算价合价()-_材机机械审前预算价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------材料审前变量---------------------------------------------
|
|
||||||
BEGIN:_材机材料审前价差含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.审前市场价含税 - 人材机.审前预算价含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前价差不含税
|
|
||||||
${
|
|
||||||
sum(source,"人材机",?人材机.审前市场价不含税 - 人材机.审前预算价不含税)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前市场价合价_含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前市场价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前预算价合价_含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前预算价含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前预算价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前预算价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前价差合价_含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.审前市场价含税 - 人材机.审前预算价含税) * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料审前价差合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?(人材机.审前市场价不含税 - 人材机.审前预算价不含税) * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN:_材机材料核增核减市场价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机材料市场价合价不含税()-_材机材料审前市场价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料核增核减市场价合价_含税
|
|
||||||
${
|
|
||||||
?_材机材料市场价合价含税()-_材机材料审前市场价合价_含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料核增核减预算价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机材料预算价合价不含税()-_材机材料审前预算价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机材料核增核减预算价合价_含税
|
|
||||||
${
|
|
||||||
?_材机材料预算价合价含税()-_材机材料审前预算价合价_含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------主材审前变量---------------------------------------------
|
|
||||||
BEGIN:_材机主材审前市场价合价_含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价含税 * 人材机.审前数量 ), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材审前市场价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材核增核减市场价合价_含税
|
|
||||||
${
|
|
||||||
?_材机主材合价含税()-_材机主材审前市场价合价_含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机主材核增核减市场价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机主材合价不含税()-_材机主材审前市场价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------设备审前变量---------------------------------------------
|
|
||||||
BEGIN:_材机设备审前市场价合价_含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备审前市场价合价_不含税
|
|
||||||
${
|
|
||||||
round(?sum(source,"人材机",?人材机.审前市场价不含税 * 人材机.审前数量), _工程费用小数位数)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备核增核减市场价合价_含税
|
|
||||||
${
|
|
||||||
?_材机设备合价含税()-_材机设备审前市场价合价_含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机设备核增核减市场价合价_不含税
|
|
||||||
${
|
|
||||||
?_材机设备合价不含税()-_材机设备审前市场价合价_不含税()
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
BEGIN:_材机合并主材审前数量
|
|
||||||
${
|
|
||||||
sum(source, "主材",?主材.审前数量)
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN:_材机合并设备审前数量
|
|
||||||
${
|
|
||||||
sum(source, "设备",?设备.审前数量)
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -112,7 +112,9 @@
|
|||||||
|
|
||||||
from equipment_calculation.main import bcl_calculate
|
from equipment_calculation.main import bcl_calculate
|
||||||
|
|
||||||
input_dir = "project2json/outputs/merged"
|
input_dir = "data/output/merged"
|
||||||
output_dir = "project2json/outputs/bclresults"
|
output_dir = "data/output/bclresults"
|
||||||
|
bcl_dir_path = "data/output/bcl"
|
||||||
|
|
||||||
bcl_calculate(input_dir, output_dir)
|
# 可选:指定 BCL 目录;此处不指定,沿用默认配置或调用方传入
|
||||||
|
bcl_calculate(input_dir, output_dir, bcl_dir_path=bcl_dir_path)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -7,12 +7,22 @@ import json
|
|||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
import atexit
|
import atexit
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
# ==================== BCL 工具配置 ====================
|
||||||
|
# 相对于本脚本所在目录的 BwZipBCLTool.exe 路径(位于 `project2json/解压计算配置工具/` 下)
|
||||||
|
BCL_TOOL_RELATIVE_PATH = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"解压计算配置工具",
|
||||||
|
"BwZipBCLTool.exe",
|
||||||
|
)
|
||||||
|
# ======================================================
|
||||||
|
|
||||||
# ==================== 配置区 ====================
|
# ==================== 配置区 ====================
|
||||||
JAVA_WORKING_DIR = "D:/eclipseworkspace/bwyAnalysis2.3.2/analysis-server"
|
JAVA_WORKING_DIR = "D:/eclipseworkspace/bwyAnalysis2.3.2/analysis-server"
|
||||||
JAR_NAME = "booway-analysis-server-null.jar"
|
JAR_NAME = "booway-analysis-server-null.jar"
|
||||||
SERVER_URL = "http://localhost:8090/api/doAnalysis"
|
SERVER_URL = "http://localhost:8090/api/doAnalysis"
|
||||||
# ==============================================
|
# ================================================
|
||||||
|
|
||||||
# 全局变量:Java 进程
|
# 全局变量:Java 进程
|
||||||
java_process = None
|
java_process = None
|
||||||
@@ -81,37 +91,218 @@ def check_server_ready(timeout=30):
|
|||||||
|
|
||||||
def convert_json_to_readable(input_file, output_file=None):
|
def convert_json_to_readable(input_file, output_file=None):
|
||||||
"""
|
"""
|
||||||
将JSON文件转换为可读格式并保存
|
升级版:支持编码检测和容错
|
||||||
|
|
||||||
参数:
|
|
||||||
input_file: 输入JSON文件路径
|
|
||||||
output_file: 输出文件路径,如果为None则自动生成
|
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
with open(input_file, "r", encoding="utf-8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
if output_file is None:
|
if output_file is None:
|
||||||
base_name = os.path.splitext(input_file)[0]
|
base_name = os.path.splitext(input_file)[0]
|
||||||
output_file = f"{base_name}.json"
|
output_file = f"{base_name}_pretty.json"
|
||||||
|
|
||||||
|
# 确保输出目录存在
|
||||||
|
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else ".", exist_ok=True)
|
||||||
|
|
||||||
|
encodings = ["utf-8", "gbk", "gb18030", "latin1"] # 常见编码
|
||||||
|
data = None
|
||||||
|
|
||||||
|
for enc in encodings:
|
||||||
|
try:
|
||||||
|
with open(input_file, "r", encoding=enc) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
print(f"✔ 使用编码 {enc} 成功读取 {input_file}")
|
||||||
|
break
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 读取失败 {input_file}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
print(f"❌ 所有编码尝试失败: {input_file}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
with open(output_file, "w", encoding="utf-8") as f:
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||||
|
print(f"✅ 美化成功: {output_file}")
|
||||||
print(f"✅ JSON美化成功: {output_file}")
|
|
||||||
return output_file
|
return output_file
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 转换JSON失败 {input_file}: {e}")
|
print(f"❌ 写入失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def convert_project_to_json(input_folder, output_folder):
|
def _parse_version_key(name: str):
|
||||||
|
"""将形如 '1.20' 的版本字符串转换为可比较的元组。(主, 次, 补丁...)
|
||||||
|
非法格式将返回一个极小值以便被忽略。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
parts = [int(p) for p in name.strip().split(".") if p.isdigit()]
|
||||||
|
if not parts:
|
||||||
|
return (-1,)
|
||||||
|
return tuple(parts)
|
||||||
|
except Exception:
|
||||||
|
return (-1,)
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_dir_contents(src_dir: str, dst_dir: str):
|
||||||
|
"""将 src_dir 下的所有文件/子目录复制到 dst_dir(不包含 src_dir 这一层目录)。"""
|
||||||
|
os.makedirs(dst_dir, exist_ok=True)
|
||||||
|
for entry in os.listdir(src_dir):
|
||||||
|
s = os.path.join(src_dir, entry)
|
||||||
|
d = os.path.join(dst_dir, entry)
|
||||||
|
if os.path.isdir(s):
|
||||||
|
# 复制子目录
|
||||||
|
if os.path.exists(d):
|
||||||
|
shutil.rmtree(d)
|
||||||
|
shutil.copytree(s, d)
|
||||||
|
else:
|
||||||
|
shutil.copy2(s, d)
|
||||||
|
|
||||||
|
|
||||||
|
def run_bcl_tool_and_copy_best(
|
||||||
|
project_path: str,
|
||||||
|
final_copy_dir: str,
|
||||||
|
desktop_base: str = None,
|
||||||
|
exe_path: str = None,
|
||||||
|
exts: tuple[str, ...] | None = None,
|
||||||
|
cleanup_temp: bool = True,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
运行 BwZipBCLTool.exe 解析 BCL,并将临时输出目录下“版本号最大”的子文件夹内容复制到 final_copy_dir。
|
||||||
|
|
||||||
|
参数:
|
||||||
|
project_path: .zwqd 工程文件路径或包含该文件的目录
|
||||||
|
final_copy_dir: 版本号最大的文件夹内的所有文件复制到的最终目录
|
||||||
|
desktop_base: 临时输出目录所在的桌面路径,默认为当前用户桌面
|
||||||
|
exe_path: BwZipBCLTool.exe 的完整路径,默认使用 BCL_TOOL_RELATIVE_PATH
|
||||||
|
|
||||||
|
返回:
|
||||||
|
(bool, str): (是否成功, 最佳版本目录路径或错误信息)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
exe_path = exe_path or BCL_TOOL_RELATIVE_PATH
|
||||||
|
if not os.path.exists(exe_path):
|
||||||
|
return False, f"未找到 BCL 工具: {exe_path}"
|
||||||
|
|
||||||
|
# 构建候选工程文件列表
|
||||||
|
# 默认:尝试目录内所有文件;若传入 exts,则只筛选指定后缀
|
||||||
|
candidates: list[str] = []
|
||||||
|
if os.path.isfile(project_path):
|
||||||
|
candidates = [project_path]
|
||||||
|
elif os.path.isdir(project_path):
|
||||||
|
names = sorted(os.listdir(project_path))
|
||||||
|
if exts:
|
||||||
|
lower_exts = tuple(e.lower() for e in exts)
|
||||||
|
candidates.extend([os.path.join(project_path, n) for n in names if n.lower().endswith(lower_exts)])
|
||||||
|
else:
|
||||||
|
candidates.extend(
|
||||||
|
[os.path.join(project_path, n) for n in names if os.path.isfile(os.path.join(project_path, n))]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False, f"路径不存在: {project_path}"
|
||||||
|
|
||||||
|
if not candidates:
|
||||||
|
return False, f"在 '{project_path}' 未找到可供解析的工程文件"
|
||||||
|
|
||||||
|
last_error = None
|
||||||
|
for eng_file in candidates:
|
||||||
|
# 临时目录放到桌面
|
||||||
|
if desktop_base is None:
|
||||||
|
desktop_base = os.path.join(os.path.expanduser("~"), "Desktop")
|
||||||
|
os.makedirs(desktop_base, exist_ok=True)
|
||||||
|
temp_out_dir = tempfile.mkdtemp(prefix="bcl_", dir=desktop_base)
|
||||||
|
|
||||||
|
print(f"🚀 调用 BCL 工具: {exe_path}")
|
||||||
|
print(f" ├─ 工程文件: {eng_file}")
|
||||||
|
print(f" └─ 临时输出: {temp_out_dir}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 运行外部工具
|
||||||
|
result = subprocess.run(
|
||||||
|
[exe_path, eng_file, temp_out_dir],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
shell=False,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
stderr = (result.stderr or "").strip()
|
||||||
|
stdout = (result.stdout or "").strip()
|
||||||
|
last_error = f"BCL 工具执行失败 (code={result.returncode})\nSTDOUT: {stdout}\nSTDERR: {stderr}"
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 在临时目录下查找版本号子目录
|
||||||
|
subdirs = [d for d in os.listdir(temp_out_dir) if os.path.isdir(os.path.join(temp_out_dir, d))]
|
||||||
|
if not subdirs:
|
||||||
|
last_error = f"BCL 工具未在输出目录生成任何子目录: {temp_out_dir}"
|
||||||
|
continue
|
||||||
|
|
||||||
|
best_dir_name = max(subdirs, key=_parse_version_key)
|
||||||
|
best_dir_path = os.path.join(temp_out_dir, best_dir_name)
|
||||||
|
print(f"🏆 发现最佳版本目录: {best_dir_name}")
|
||||||
|
|
||||||
|
# 若下层只有单一子目录则继续下探;若存在多个子目录,且其名称像版本号(如 1.2.13),则选取版本号最大者继续下探
|
||||||
|
def _descend_if_single_subdir(path: str) -> str:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
entries = [os.path.join(path, e) for e in os.listdir(path)]
|
||||||
|
files = [p for p in entries if os.path.isfile(p)]
|
||||||
|
dirs = [p for p in entries if os.path.isdir(p)]
|
||||||
|
if files:
|
||||||
|
return path
|
||||||
|
if len(dirs) == 1:
|
||||||
|
path = dirs[0]
|
||||||
|
continue
|
||||||
|
if len(dirs) > 1:
|
||||||
|
# 如果多子目录都像版本号,则选择最大的版本继续下探
|
||||||
|
dir_names = [os.path.basename(d) for d in dirs]
|
||||||
|
|
||||||
|
def looks_like_version(name: str) -> bool:
|
||||||
|
parts = name.split(".")
|
||||||
|
if not parts:
|
||||||
|
return False
|
||||||
|
return all(p.isdigit() for p in parts)
|
||||||
|
|
||||||
|
version_like = [d for d, n in zip(dirs, dir_names) if looks_like_version(n)]
|
||||||
|
if version_like:
|
||||||
|
best_dir = max(version_like, key=lambda p: _parse_version_key(os.path.basename(p)))
|
||||||
|
path = best_dir
|
||||||
|
continue
|
||||||
|
# 否则停止下探,返回当前层
|
||||||
|
return path
|
||||||
|
return path
|
||||||
|
except Exception:
|
||||||
|
return path
|
||||||
|
|
||||||
|
copy_root = _descend_if_single_subdir(best_dir_path)
|
||||||
|
|
||||||
|
# 复制内容到最终目录
|
||||||
|
os.makedirs(final_copy_dir, exist_ok=True)
|
||||||
|
_copy_dir_contents(copy_root, final_copy_dir)
|
||||||
|
print(f"✅ 已将最佳版本目录内的文件复制到: {final_copy_dir}")
|
||||||
|
|
||||||
|
return True, copy_root
|
||||||
|
finally:
|
||||||
|
if cleanup_temp:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(temp_out_dir, ignore_errors=True)
|
||||||
|
# print(f"🧹 已清理临时目录: {temp_out_dir}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 所有候选均失败
|
||||||
|
return False, (last_error or "未找到可用的工程文件以执行 BCL 工具")
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"运行 BCL 工具出错: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def convert_project_to_json(input_folder, output_folder, best_version_dest_folder=None):
|
||||||
"""
|
"""
|
||||||
将工程文件夹转换为JSON,并移动到输出文件夹(含美化)
|
将工程文件夹转换为JSON,并移动到输出文件夹(含美化)
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
input_folder: 工程文件所在目录(包含 .zwzj 文件)
|
input_folder: 工程文件所在目录(包含 .zwzj 文件)
|
||||||
output_folder: 转换后的 JSON 文件输出目录
|
output_folder: 转换后的 JSON 文件输出目录
|
||||||
|
best_version_dest_folder: 若提供,则会在流程开始前运行 BCL 工具,并将最佳版本目录内容复制到该路径
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
tuple(bool, int): (是否成功, 成功转移并美化的文件数量)
|
tuple(bool, int): (是否成功, 成功转移并美化的文件数量)
|
||||||
@@ -147,13 +338,21 @@ def convert_project_to_json(input_folder, output_folder):
|
|||||||
print(f"❌ 创建输出目录失败: {e}")
|
print(f"❌ 创建输出目录失败: {e}")
|
||||||
return False, 0
|
return False, 0
|
||||||
|
|
||||||
# 3. 启动 Java 服务
|
# 3. 若用户指定了 BCL 最终复制目录,则先进行 BCL 解析与复制
|
||||||
|
if best_version_dest_folder:
|
||||||
|
ok, info = run_bcl_tool_and_copy_best(input_folder, best_version_dest_folder)
|
||||||
|
if ok:
|
||||||
|
print(f"🧩 BCL 解析已完成,最佳版本输出目录: {info}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ BCL 解析步骤失败: {info}")
|
||||||
|
|
||||||
|
# 4. 启动 Java 服务
|
||||||
if not start_java_server():
|
if not start_java_server():
|
||||||
return False, 0
|
return False, 0
|
||||||
if not check_server_ready():
|
if not check_server_ready():
|
||||||
return False, 0
|
return False, 0
|
||||||
|
|
||||||
# 4. 调用 API 开始分析
|
# 5. 调用 API 开始分析
|
||||||
params = {"filePath": input_folder.replace("\\", "/")}
|
params = {"filePath": input_folder.replace("\\", "/")}
|
||||||
print(f"🌐 调用 API: {SERVER_URL}?{requests.compat.urlencode(params)}")
|
print(f"🌐 调用 API: {SERVER_URL}?{requests.compat.urlencode(params)}")
|
||||||
|
|
||||||
@@ -171,10 +370,10 @@ def convert_project_to_json(input_folder, output_folder):
|
|||||||
print(f"❌ 调用 API 出错: {e}")
|
print(f"❌ 调用 API 出错: {e}")
|
||||||
return False, 0
|
return False, 0
|
||||||
|
|
||||||
# 5. 等待并检测 JSON 文件生成完成(改进版)
|
# 6. 等待并检测 JSON 文件生成完成(改进版)
|
||||||
print("⏳ 正在等待 JSON 文件生成完成...")
|
print("⏳ 正在等待 JSON 文件生成完成...")
|
||||||
json_files = []
|
json_files = []
|
||||||
max_wait_time = 600
|
max_wait_time = 6000
|
||||||
check_interval = 2
|
check_interval = 2
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@@ -209,7 +408,7 @@ def convert_project_to_json(input_folder, output_folder):
|
|||||||
print(f"❌ 在 {max_wait_time} 秒内未生成任何 JSON 文件。")
|
print(f"❌ 在 {max_wait_time} 秒内未生成任何 JSON 文件。")
|
||||||
return False, 0
|
return False, 0
|
||||||
|
|
||||||
# 6. 查找所有 .json 文件
|
# 7. 查找所有 .json 文件
|
||||||
json_files = [f for f in os.listdir(input_folder) if f.endswith(".json")]
|
json_files = [f for f in os.listdir(input_folder) if f.endswith(".json")]
|
||||||
if not json_files:
|
if not json_files:
|
||||||
print(f"❌ 未在 {input_folder} 中生成 JSON 文件。")
|
print(f"❌ 未在 {input_folder} 中生成 JSON 文件。")
|
||||||
@@ -217,7 +416,7 @@ def convert_project_to_json(input_folder, output_folder):
|
|||||||
|
|
||||||
print(f"📄 发现 {len(json_files)} 个 JSON 文件: {json_files}")
|
print(f"📄 发现 {len(json_files)} 个 JSON 文件: {json_files}")
|
||||||
|
|
||||||
# 7. 转换为可读格式并移动到输出目录
|
# 8. 转换为可读格式并移动到输出目录
|
||||||
transferred_count = 0
|
transferred_count = 0
|
||||||
for file_name in json_files:
|
for file_name in json_files:
|
||||||
src_path = os.path.join(input_folder, file_name)
|
src_path = os.path.join(input_folder, file_name)
|
||||||
@@ -255,10 +454,11 @@ atexit.register(cleanup)
|
|||||||
# ==================== 使用示例 ====================
|
# ==================== 使用示例 ====================
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 示例调用
|
# 示例调用
|
||||||
input_dir = r"project2json/uploads"
|
input_dir = r"data/output/uploads"
|
||||||
output_dir = r"project2json/outputs/json"
|
output_dir = r"data/output/json"
|
||||||
|
best_bcl_dest = r"data/output/bcl"
|
||||||
|
|
||||||
success = convert_project_to_json(input_dir, output_dir)
|
success, _count = convert_project_to_json(input_dir, output_dir, best_bcl_dest)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
print("\n🎉 ✅ 全部流程执行成功!")
|
print("\n🎉 ✅ 全部流程执行成功!")
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
BwZipBCLTool.exe C:\Users\Administrator\Downloads\变电检修国网\全口径-陆上电缆-国网2023规范.zwzj C:\Users\Administrator\Desktop
|
||||||
|
pause
|
||||||
+108
-75
@@ -29,30 +29,36 @@ def generate_session_id():
|
|||||||
return "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
return "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
||||||
|
|
||||||
|
|
||||||
# 创建会话工作目录
|
# 创建会话工作目录(仅会话根目录)
|
||||||
def create_session_directories(session_id):
|
def create_session_directories(session_id):
|
||||||
# 定义工作目录
|
# 仅创建会话根目录用于容纳每个文件的独立GUID临时目录
|
||||||
upload_dir = os.path.join(BASE_DIR, "uploads", session_id)
|
session_root = os.path.join(BASE_DIR, "outputs", session_id)
|
||||||
output_dir = os.path.join(BASE_DIR, "outputs", session_id)
|
os.makedirs(session_root, exist_ok=True)
|
||||||
json_dir = os.path.join(output_dir, "json")
|
|
||||||
merged_dir = os.path.join(output_dir, "merged")
|
|
||||||
bcl_results_dir = os.path.join(output_dir, "bclresults")
|
|
||||||
final_dir = os.path.join(output_dir, "final")
|
|
||||||
|
|
||||||
# 创建所有目录
|
|
||||||
for directory in [upload_dir, json_dir, merged_dir, bcl_results_dir, final_dir]:
|
|
||||||
os.makedirs(directory, exist_ok=True)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"upload_dir": upload_dir,
|
"session_root": session_root,
|
||||||
"json_dir": json_dir,
|
|
||||||
"merged_dir": merged_dir,
|
|
||||||
"bcl_results_dir": bcl_results_dir,
|
|
||||||
"final_dir": final_dir,
|
|
||||||
"output_dir": output_dir,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 为单个上传文件创建独立的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
|
||||||
|
|
||||||
|
|
||||||
# 清理会话目录
|
# 清理会话目录
|
||||||
def clean_session_directories(session_id):
|
def clean_session_directories(session_id):
|
||||||
upload_dir = os.path.join(BASE_DIR, "uploads", session_id)
|
upload_dir = os.path.join(BASE_DIR, "uploads", session_id)
|
||||||
@@ -78,79 +84,106 @@ def clean_session_directories(session_id):
|
|||||||
# 整合的转化流程函数,执行步骤1到步骤4
|
# 整合的转化流程函数,执行步骤1到步骤4
|
||||||
def convert_all_steps(files, progress=gr.Progress()):
|
def convert_all_steps(files, progress=gr.Progress()):
|
||||||
try:
|
try:
|
||||||
# 生成会话ID并创建工作目录
|
# 生成会话ID并创建会话根目录
|
||||||
session_id = generate_session_id()
|
session_id = generate_session_id()
|
||||||
print(f"生成会话ID: {session_id}")
|
print(f"生成会话ID: {session_id}")
|
||||||
|
session_dirs = create_session_directories(session_id)
|
||||||
|
session_root = session_dirs["session_root"]
|
||||||
|
|
||||||
dirs = create_session_directories(session_id)
|
# 连接Neo4j(提前连接,避免逐文件重复连接)
|
||||||
upload_dir = dirs["upload_dir"]
|
progress(0.05, desc="步骤0: 连接Neo4j数据库")
|
||||||
json_dir = dirs["json_dir"]
|
|
||||||
merged_dir = dirs["merged_dir"]
|
|
||||||
bcl_results_dir = dirs["bcl_results_dir"]
|
|
||||||
final_dir = dirs["final_dir"]
|
|
||||||
|
|
||||||
# 步骤1.1: 保存上传的文件
|
|
||||||
file_paths = []
|
|
||||||
progress(0.05, desc="保存上传文件")
|
|
||||||
for i, file in enumerate(files):
|
|
||||||
file_name = os.path.basename(file.name)
|
|
||||||
save_path = os.path.join(upload_dir, file_name)
|
|
||||||
shutil.copy(file.name, save_path)
|
|
||||||
file_paths.append(save_path)
|
|
||||||
progress(0.05 + (0.05 * (i + 1) / len(files)), desc=f"已保存 {i + 1}/{len(files)} 个文件")
|
|
||||||
|
|
||||||
# 步骤1.2: 转换为JSON
|
|
||||||
progress(0.1, desc="步骤1: 转换工程文件为JSON")
|
|
||||||
success, file_num = convert_project_to_json(upload_dir, json_dir)
|
|
||||||
|
|
||||||
# 步骤1.3: 处理JSON文件结构
|
|
||||||
progress(0.2, desc="处理JSON文件结构")
|
|
||||||
process_directory(json_dir)
|
|
||||||
|
|
||||||
# 步骤2: 费用向上汇总
|
|
||||||
progress(0.3, desc="步骤2: 费用向上汇总")
|
|
||||||
result_step2 = costsummary_upwards(json_dir, merged_dir)
|
|
||||||
|
|
||||||
# 步骤3.1: 计算工程量取费表
|
|
||||||
progress(0.5, desc="步骤3: 计算工程量取费表")
|
|
||||||
bcl_calculate(merged_dir, bcl_results_dir)
|
|
||||||
|
|
||||||
# 步骤3.2: 将BCL结果写入JSON
|
|
||||||
progress(0.6, desc="将计算结果写入JSON")
|
|
||||||
success_count_step3 = batch_write_BCLresult_into_json(merged_dir, bcl_results_dir, final_dir)
|
|
||||||
|
|
||||||
# 步骤4: 写入知识图谱
|
|
||||||
progress(0.7, desc="步骤4: 连接Neo4j数据库")
|
|
||||||
config = read_config()
|
config = read_config()
|
||||||
if not connect_to_neo4j(
|
if not connect_to_neo4j(
|
||||||
config.get("neo4j", "uri"), config.get("neo4j", "user"), config.get("neo4j", "password")
|
config.get("neo4j", "uri"), config.get("neo4j", "user"), config.get("neo4j", "password")
|
||||||
):
|
):
|
||||||
# 清理会话目录
|
|
||||||
clean_session_directories(session_id)
|
clean_session_directories(session_id)
|
||||||
return "转化失败:无法连接到Neo4j数据库。", []
|
return "转化失败:无法连接到Neo4j数据库。", []
|
||||||
|
|
||||||
progress(0.9, desc="创建知识图谱")
|
total_files = len(files) if files else 0
|
||||||
|
if total_files == 0:
|
||||||
|
clean_session_directories(session_id)
|
||||||
|
return "未选择任何文件。", []
|
||||||
|
|
||||||
|
# 结果累计
|
||||||
|
total_converted_to_json = 0
|
||||||
|
total_cost_files = 0
|
||||||
|
total_bcl_json_write = 0
|
||||||
|
total_kg_created = 0
|
||||||
|
total_kg_expected = 0
|
||||||
|
all_deleted_projects = []
|
||||||
|
|
||||||
|
# 逐文件处理
|
||||||
|
for idx, file in enumerate(files, start=1):
|
||||||
|
file_name = os.path.basename(file.name)
|
||||||
|
stage_base = (idx - 1) / total_files
|
||||||
|
stage_span = 0.9 / total_files # 从0.1到1.0之间分配给各文件
|
||||||
|
|
||||||
|
# 创建该文件的独立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"]
|
||||||
|
final_dir = fdirs["final_dir"]
|
||||||
|
|
||||||
|
# 步骤1.1: 保存上传的该文件
|
||||||
|
progress(stage_base + stage_span * 0.05, desc=f"[{idx}/{total_files}] 保存上传文件: {file_name}")
|
||||||
|
save_path = os.path.join(upload_dir, file_name)
|
||||||
|
shutil.copy(file.name, save_path)
|
||||||
|
|
||||||
|
# 步骤1.2: 转换为JSON
|
||||||
|
progress(stage_base + stage_span * 0.15, desc=f"[{idx}/{total_files}] 步骤1: 转换为JSON")
|
||||||
|
success, file_num = convert_project_to_json(upload_dir, json_dir)
|
||||||
|
total_converted_to_json += file_num if success else 0
|
||||||
|
|
||||||
|
# 步骤1.3: 处理JSON文件结构
|
||||||
|
progress(stage_base + stage_span * 0.30, desc=f"[{idx}/{total_files}] 处理JSON结构")
|
||||||
|
process_directory(json_dir)
|
||||||
|
|
||||||
|
# 步骤2: 费用向上汇总
|
||||||
|
progress(stage_base + stage_span * 0.45, desc=f"[{idx}/{total_files}] 步骤2: 费用向上汇总")
|
||||||
|
result_step2 = costsummary_upwards(json_dir, merged_dir)
|
||||||
|
total_cost_files += len(result_step2) if result_step2 else 0
|
||||||
|
|
||||||
|
# 步骤3.1: 计算工程量取费表
|
||||||
|
progress(stage_base + stage_span * 0.65, desc=f"[{idx}/{total_files}] 步骤3: 计算工程量取费表")
|
||||||
|
# 传入该文件工作区的 bcl 目录
|
||||||
|
bcl_calculate(merged_dir, bcl_results_dir, bcl_dir_path=fdirs["bcl_dir"])
|
||||||
|
|
||||||
|
# 步骤3.2: 将BCL结果写入JSON
|
||||||
|
progress(stage_base + stage_span * 0.80, desc=f"[{idx}/{total_files}] 写入BCL结果到JSON")
|
||||||
|
success_count_step3 = batch_write_BCLresult_into_json(merged_dir, bcl_results_dir, final_dir)
|
||||||
|
total_bcl_json_write += success_count_step3 if success_count_step3 else 0
|
||||||
|
|
||||||
|
# 步骤4: 写入知识图谱(针对该文件的final目录)
|
||||||
|
progress(stage_base + stage_span * 0.95, desc=f"[{idx}/{total_files}] 创建知识图谱")
|
||||||
success_count_step4, total_count_step4, deleted_projects = create_KGs_from_folder(final_dir)
|
success_count_step4, total_count_step4, deleted_projects = create_KGs_from_folder(final_dir)
|
||||||
|
total_kg_created += success_count_step4 if success_count_step4 else 0
|
||||||
|
total_kg_expected += total_count_step4 if total_count_step4 else 0
|
||||||
|
if deleted_projects:
|
||||||
|
all_deleted_projects.extend(deleted_projects)
|
||||||
|
|
||||||
# 清理所有会话目录
|
# 清理所有会话目录
|
||||||
progress(0.95, desc="清理所有临时文件")
|
progress(0.98, desc="清理所有临时文件")
|
||||||
clean_session_directories(session_id)
|
clean_session_directories(session_id)
|
||||||
|
|
||||||
progress(1.0, desc="转化完成")
|
progress(1.0, desc="转化完成")
|
||||||
|
|
||||||
# 返回处理结果摘要
|
# 汇总结果
|
||||||
deleted_msg = ""
|
deleted_msg = ""
|
||||||
if deleted_projects:
|
if all_deleted_projects:
|
||||||
deleted_msg = f"\n已删除 {len(deleted_projects)} 个同名工程:{', '.join(deleted_projects)}"
|
deleted_msg = f"\n已删除 {len(all_deleted_projects)} 个同名工程:{', '.join(all_deleted_projects)}"
|
||||||
|
|
||||||
result_summary = f"""转化完成!
|
result_summary = (
|
||||||
步骤1: 成功转换 {file_num} 个工程文件到JSON
|
f"转化完成!\n"
|
||||||
步骤2: 成功处理 {len(result_step2) if result_step2 else 0} 个费用汇总文件
|
f"步骤1: 成功转换 {total_converted_to_json} 个工程文件到JSON\n"
|
||||||
步骤3: 成功处理 {success_count_step3} 个BCL计算结果
|
f"步骤2: 成功处理 {total_cost_files} 个费用汇总文件\n"
|
||||||
步骤4: 成功创建 {success_count_step4}/{total_count_step4} 个知识图谱{deleted_msg}
|
f"步骤3: 成功处理 {total_bcl_json_write} 个BCL计算结果\n"
|
||||||
所有临时文件已清理。
|
f"步骤4: 成功创建 {total_kg_created}/{total_kg_expected} 个知识图谱"
|
||||||
|
f"{deleted_msg}\n"
|
||||||
请在下方选择知识图谱并点击"导出到Excel"按钮下载。"""
|
f"所有临时文件已清理。\n\n"
|
||||||
|
f'请在下方选择知识图谱并点击"导出到Excel"按钮下载。'
|
||||||
|
)
|
||||||
|
|
||||||
# 获取知识图谱列表
|
# 获取知识图谱列表
|
||||||
kg_list = get_engineering_data_nodes()
|
kg_list = get_engineering_data_nodes()
|
||||||
@@ -448,8 +481,8 @@ def create_interface():
|
|||||||
# 主函数
|
# 主函数
|
||||||
def main():
|
def main():
|
||||||
# 确保基础目录存在
|
# 确保基础目录存在
|
||||||
os.makedirs(os.path.join(BASE_DIR, "uploads"), exist_ok=True)
|
# os.makedirs(os.path.join(BASE_DIR, "uploads"), exist_ok=True)
|
||||||
os.makedirs(os.path.join(BASE_DIR, "outputs"), exist_ok=True)
|
# os.makedirs(os.path.join(BASE_DIR, "outputs"), exist_ok=True)
|
||||||
|
|
||||||
# 创建并启动Gradio界面
|
# 创建并启动Gradio界面
|
||||||
app = create_interface()
|
app = create_interface()
|
||||||
|
|||||||
+34
-37
@@ -333,50 +333,47 @@ class ExpenseProcessor:
|
|||||||
return successful_files
|
return successful_files
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
def _determine_project_type(data):
|
def _determine_project_type(data):
|
||||||
"""
|
"""
|
||||||
根据division字段判断工程类型
|
根据basicData中的"项目类型"或"工程类型"判断工程类型
|
||||||
:param data: 项目数据
|
:param data: 项目数据
|
||||||
:return: 'inventory' 表示清单工程,'budget' 表示预算工程
|
:return: 'inventory' 表示清单工程,'budget' 表示预算工程
|
||||||
"""
|
"""
|
||||||
# 清单工程关键词
|
# 项目类型名称映射字典:将各种变体映射到标准类型(预算/清单)
|
||||||
inventory_keywords = ["清单", "结算", "招标控制价", "招投标工程", "清单计价"]
|
PROJECT_TYPE_MAPPING = {
|
||||||
# 预算工程关键词
|
"概预算工程": "预算",
|
||||||
budget_keywords = ["概预算", "定额", "定额计价", "概算", "概预算工程"]
|
"初步设计概算": "预算",
|
||||||
|
"可行性研究投资估算": "预算",
|
||||||
|
"施工图预算": "预算",
|
||||||
|
"配网定额计价": "预算",
|
||||||
|
"招标控制价": "清单",
|
||||||
|
"投标报价": "清单",
|
||||||
|
"招投标工程": "清单",
|
||||||
|
"配网清单招投标计价": "清单",
|
||||||
|
}
|
||||||
|
|
||||||
# 尝试从数据中获取division字段
|
# 获取 basicData
|
||||||
division = None
|
basic_data = data.get("basicData") or {}
|
||||||
if "division" in data:
|
|
||||||
division = data["division"]
|
|
||||||
parts = division.split("-")
|
|
||||||
|
|
||||||
# 如果找到division字段
|
# 尝试获取 "项目类型",若不存在则尝试获取 "工程类型"
|
||||||
if division:
|
engineering_type = basic_data.get("项目类型") or basic_data.get("工程类型") or basic_data.get("工程类别")
|
||||||
# 去掉"主网-"前缀
|
|
||||||
if len(parts) == 2:
|
|
||||||
division_type = parts[1].strip()
|
|
||||||
else:
|
|
||||||
division_type = parts[2].strip()
|
|
||||||
|
|
||||||
# 判断是否为清单工程
|
if engineering_type:
|
||||||
for keyword in inventory_keywords:
|
# 去除前后空格
|
||||||
if keyword in division_type:
|
engineering_type = engineering_type.strip()
|
||||||
print(f"根据division字段 '{division}' 判断为清单工程")
|
# 查找映射
|
||||||
return "inventory"
|
mapped_type = PROJECT_TYPE_MAPPING.get(engineering_type)
|
||||||
|
if mapped_type == "预算":
|
||||||
# 判断是否为预算工程
|
print(f"根据项目类型 '{engineering_type}' 判断为预算工程")
|
||||||
for keyword in budget_keywords:
|
|
||||||
if keyword in division_type:
|
|
||||||
print(f"根据division字段 '{division}' 判断为预算工程")
|
|
||||||
return "budget"
|
return "budget"
|
||||||
|
elif mapped_type == "清单":
|
||||||
# 如果无法通过division字段判断,则尝试通过数据结构判断
|
print(f"根据项目类型 '{engineering_type}' 判断为清单工程")
|
||||||
is_inventory_project = False
|
return "inventory"
|
||||||
for key in data.keys():
|
else:
|
||||||
if re.search(r"[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", key, re.IGNORECASE):
|
print(f"项目类型 '{engineering_type}' 未在映射中定义,跳过")
|
||||||
is_inventory_project = True
|
|
||||||
print("通过数据结构判断为清单工程")
|
|
||||||
break
|
|
||||||
|
|
||||||
return "inventory" if is_inventory_project else "budget"
|
return "inventory" if is_inventory_project else "budget"
|
||||||
|
|
||||||
@@ -388,8 +385,8 @@ def costsummary_upwards(
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
input_directory = "project2json/outputs/json"
|
input_directory = "data/output/json"
|
||||||
output_directory = "project2json/outputs/merged"
|
output_directory = "data/output/merged"
|
||||||
# 自动判断工程类型
|
# 自动判断工程类型
|
||||||
result = costsummary_upwards(input_directory, output_directory)
|
result = costsummary_upwards(input_directory, output_directory)
|
||||||
if result:
|
if result:
|
||||||
|
|||||||
@@ -6,33 +6,90 @@ import uuid
|
|||||||
|
|
||||||
def _determine_project_type(data):
|
def _determine_project_type(data):
|
||||||
"""
|
"""
|
||||||
根据division字段判断工程类型
|
根据basicData中的"软件类别"或"软件名称"判断工程类型
|
||||||
:param data: 项目数据
|
:param data: 项目数据,包含 basicData 字段
|
||||||
:return: 主网, 配网, 技改
|
:return: 主网, 配网, 技改;如果无法匹配则返回 None
|
||||||
"""
|
"""
|
||||||
|
# 软件类别名称映射字典,将各种变体映射到标准类别
|
||||||
|
CATEGORY_MAPPING = {
|
||||||
|
# 主网及其变体
|
||||||
|
"主网": "主网",
|
||||||
|
"主网工程": "主网",
|
||||||
|
"主网项目": "主网",
|
||||||
|
# 配网及其变体
|
||||||
|
"配网": "配网",
|
||||||
|
"配网造价": "配网",
|
||||||
|
"配网清单": "配网",
|
||||||
|
# 技改及其变体
|
||||||
|
"技改": "技改",
|
||||||
|
"技改工程": "技改",
|
||||||
|
"技改项目": "技改",
|
||||||
|
"技改造价": "技改",
|
||||||
|
"技改清单": "技改",
|
||||||
|
}
|
||||||
|
|
||||||
# 尝试从数据中获取division字段
|
# 获取 basicData
|
||||||
division = None
|
basic_data = data.get("basicData") or {}
|
||||||
if "division" in data:
|
|
||||||
division = data["division"]
|
|
||||||
|
|
||||||
# 如果找到division字段
|
# 尝试获取 "软件类别",若不存在则尝试获取 "软件名称"
|
||||||
if division:
|
category = basic_data.get("软件类别") or basic_data.get("软件名称")
|
||||||
# 去掉"主网-"前缀
|
|
||||||
if "-" in division:
|
|
||||||
division_type = division.split("-")[0]
|
|
||||||
else:
|
|
||||||
division_type = division
|
|
||||||
|
|
||||||
if division_type in ["主网", "主网线路"]:
|
|
||||||
return "主网"
|
|
||||||
elif division_type in ["配网", "配网造价", "配网清单"]:
|
|
||||||
return "配网"
|
|
||||||
elif division_type in ["技改", "技改造价", "技改清单"]:
|
|
||||||
return "技改"
|
|
||||||
|
|
||||||
|
if not category:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 去除前后空格并查找映射
|
||||||
|
category = category.strip()
|
||||||
|
return CATEGORY_MAPPING.get(category)
|
||||||
|
|
||||||
|
|
||||||
|
# 新增:按工程类型为 projectData.projectInfo 增补键值对的映射与函数
|
||||||
|
# 可按需扩展不同工程类型需要自动补充的字段
|
||||||
|
PROJECT_INFO_ADDITIONS = {
|
||||||
|
# 主网:如需新增字段,请在此处补充,示例:"示例字段": "" 或默认值
|
||||||
|
"主网": {
|
||||||
|
# 在此处按需添加主网专属字段,例如:
|
||||||
|
# "主网示例字段": ""
|
||||||
|
},
|
||||||
|
# 配网:如需新增字段,请在此处补充
|
||||||
|
"配网": {
|
||||||
|
# "配网示例字段": ""
|
||||||
|
},
|
||||||
|
# 技改:需求示例——同时支持以下两个字段,缺哪个补哪个
|
||||||
|
"技改": {
|
||||||
|
"建筑材机按系数调差": "",
|
||||||
|
"建筑修缮材机按系数调差": "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def add_project_info_fields(data):
|
||||||
|
"""
|
||||||
|
根据工程类型(主网/配网/技改),为 data["projectData"]["projectInfo"] 增补字段。
|
||||||
|
- 若 projectInfo 不存在则创建。
|
||||||
|
- 仅在键不存在时补充,不覆盖已有值。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
project_type = _determine_project_type(data)
|
||||||
|
except Exception:
|
||||||
|
project_type = None
|
||||||
|
|
||||||
|
if not project_type:
|
||||||
|
return
|
||||||
|
|
||||||
|
additions = PROJECT_INFO_ADDITIONS.get(project_type) or {}
|
||||||
|
if not additions:
|
||||||
|
return
|
||||||
|
|
||||||
|
project_data = data.setdefault("projectData", {})
|
||||||
|
project_info = project_data.get("projectInfo")
|
||||||
|
if not isinstance(project_info, dict):
|
||||||
|
project_info = {}
|
||||||
|
project_data["projectInfo"] = project_info
|
||||||
|
|
||||||
|
for k, v in additions.items():
|
||||||
|
if k not in project_info:
|
||||||
|
project_info[k] = v
|
||||||
|
|
||||||
|
|
||||||
def transform_expense_preview(input_file, output_file):
|
def transform_expense_preview(input_file, output_file):
|
||||||
"""
|
"""
|
||||||
@@ -235,6 +292,9 @@ def transform_expense_preview(input_file, output_file):
|
|||||||
# 更新data中的expensePreview
|
# 更新data中的expensePreview
|
||||||
data["projectData"]["expensePreview"] = new_expense_preview
|
data["projectData"]["expensePreview"] = new_expense_preview
|
||||||
|
|
||||||
|
# 新增:按工程类型为 projectInfo 补充字段
|
||||||
|
add_project_info_fields(data)
|
||||||
|
|
||||||
# 保存转换后的文件
|
# 保存转换后的文件
|
||||||
print(f"正在保存文件: {output_file}")
|
print(f"正在保存文件: {output_file}")
|
||||||
with open(output_file, "w", encoding="utf-8") as f:
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
@@ -572,6 +632,10 @@ def transform_json_types(input_file_path, output_file_path=None):
|
|||||||
if device_type in device_type_mapping:
|
if device_type in device_type_mapping:
|
||||||
obj["设备类型"] = device_type_mapping[device_type]
|
obj["设备类型"] = device_type_mapping[device_type]
|
||||||
|
|
||||||
|
# 若节点存在“类型”但没有“type”,则补充一个“type”属性,其值等于当前“类型”的值
|
||||||
|
if "类型" in obj and "type" not in obj:
|
||||||
|
obj["type"] = obj["类型"]
|
||||||
|
|
||||||
# 递归处理所有值
|
# 递归处理所有值
|
||||||
for value in obj.values():
|
for value in obj.values():
|
||||||
traverse(value)
|
traverse(value)
|
||||||
@@ -582,6 +646,9 @@ def transform_json_types(input_file_path, output_file_path=None):
|
|||||||
# 执行转换
|
# 执行转换
|
||||||
traverse(data)
|
traverse(data)
|
||||||
|
|
||||||
|
# 新增:按工程类型为 projectInfo 补充字段
|
||||||
|
add_project_info_fields(data)
|
||||||
|
|
||||||
# 确定输出路径
|
# 确定输出路径
|
||||||
if output_file_path is None:
|
if output_file_path is None:
|
||||||
output_file_path = input_file_path
|
output_file_path = input_file_path
|
||||||
@@ -731,5 +798,5 @@ if __name__ == "__main__":
|
|||||||
# traceback.print_exc()
|
# traceback.print_exc()
|
||||||
|
|
||||||
# 批量处理目录
|
# 批量处理目录
|
||||||
json_directory = "project2json/outputs/json"
|
json_directory = "data/output/json"
|
||||||
process_directory(json_directory)
|
process_directory(json_directory)
|
||||||
|
|||||||
Reference in New Issue
Block a user