更新代码
This commit is contained in:
@@ -222,56 +222,114 @@ def process_project_children(children, software_type=None):
|
||||
resource_nodes = []
|
||||
|
||||
# 内部工具:在人材机存在拆分时展开其子节点,删除中间父级人材机节点
|
||||
|
||||
def _flatten_resource_splits_in_place(node: dict):
|
||||
"""
|
||||
递归+迭代地展开任意深度的人材机拆分:
|
||||
- 如果某个子节点是人材机(人工/材料/机械/2/3/4)且其自身有children:
|
||||
* 将其children上提为当前层的children;
|
||||
* 被上提的每个子节点的 类型/type 设为与父节点相同;
|
||||
* 移除该父级人材机节点本身;
|
||||
- 对非被移除的子节点递归处理;
|
||||
通过 while 循环保证多层嵌套被完全展开。
|
||||
递归+迭代地展开任意深度的人材机拆分,依据新规则:
|
||||
- 材料:仅当 "拆分"=1 时展开子项并删除父节点;否则保留父节点、删除 children
|
||||
- 机械:仅当 "拆分"=0 时保留父节点、删除 children;否则展开子项并删除父节点
|
||||
- 人工:始终展开(无拆分控制)
|
||||
- 商品砼=1:最高优先级,保留父节点,删除 children
|
||||
- 同时处理 node["children"] 和 node["材机列表"]
|
||||
"""
|
||||
if not isinstance(node, dict):
|
||||
return
|
||||
if "children" not in node or not node["children"]:
|
||||
|
||||
# 提前退出:无 children 且无 材机列表
|
||||
if ("children" not in node or not node["children"]) and ("材机列表" not in node or not node["材机列表"]):
|
||||
return
|
||||
|
||||
def _is_resource_type(t):
|
||||
return t in ("人工", "材料", "机械", "2", "3", "4")
|
||||
if t in ("人工", "材料", "机械"):
|
||||
return True
|
||||
return str(t) in ("2", "3", "4")
|
||||
|
||||
# 中英文类型映射
|
||||
# 类型映射
|
||||
str2code = {"人工": "2", "材料": "3", "机械": "4"}
|
||||
code2str = {v: k for k, v in str2code.items()}
|
||||
|
||||
def _get_normalized_type(t):
|
||||
"""将类型统一转为中文(用于判断材料/机械/人工)"""
|
||||
if t in ("人工", "材料", "机械"):
|
||||
return t
|
||||
if str(t) == "2":
|
||||
return "人工"
|
||||
if str(t) == "3":
|
||||
return "材料"
|
||||
if str(t) == "4":
|
||||
return "机械"
|
||||
return None
|
||||
|
||||
def _process_node_list(node_list):
|
||||
if not node_list:
|
||||
return node_list, False
|
||||
changed = False
|
||||
new_list = []
|
||||
for ch in node_list:
|
||||
if isinstance(ch, dict):
|
||||
t = ch.get("类型") or ch.get("type")
|
||||
normalized_type = _get_normalized_type(t)
|
||||
|
||||
# 只处理人材机类型
|
||||
if normalized_type and ch.get("children"):
|
||||
# 规则1:商品砼=1 → 保留父节点,清空 children(最高优先级)
|
||||
sg_concrete = ch.get("商品砼")
|
||||
if sg_concrete == "1" or sg_concrete == 1:
|
||||
ch.pop("children", None)
|
||||
new_list.append(ch)
|
||||
changed = True
|
||||
continue
|
||||
|
||||
# 规则2:根据类型和“拆分”字段决定行为
|
||||
split_flag = ch.get("拆分")
|
||||
|
||||
should_expand = False
|
||||
if normalized_type == "人工":
|
||||
# 人工:始终展开
|
||||
should_expand = True
|
||||
elif normalized_type == "材料":
|
||||
# 材料:仅当 拆分=1 时展开
|
||||
should_expand = split_flag == "1" or split_flag == 1
|
||||
elif normalized_type == "机械":
|
||||
# 机械:仅当 拆分≠0 时展开(即 拆分=0 时不展开)
|
||||
should_expand = not (split_flag == "0" or split_flag == 0)
|
||||
|
||||
if should_expand:
|
||||
# 展开:上提 children,丢弃父节点;保持子级原有 type/类型 不变
|
||||
for gc in ch.get("children", []) or []:
|
||||
new_list.append(gc)
|
||||
changed = True
|
||||
continue
|
||||
else:
|
||||
# 不展开:保留父节点,删除 children
|
||||
ch.pop("children", None)
|
||||
new_list.append(ch)
|
||||
changed = True
|
||||
continue
|
||||
|
||||
# 非人材机类型,或无人材机 children:递归处理并保留
|
||||
_flatten_resource_splits_in_place(ch)
|
||||
new_list.append(ch)
|
||||
else:
|
||||
new_list.append(ch)
|
||||
return new_list, changed
|
||||
|
||||
# 迭代直到稳定
|
||||
changed = True
|
||||
while changed:
|
||||
changed = False
|
||||
new_children = []
|
||||
for ch in node["children"]:
|
||||
if isinstance(ch, dict):
|
||||
t = ch.get("类型") or ch.get("type")
|
||||
# 命中“人材机且存在children”,则将其子节点上提并继承类型
|
||||
if _is_resource_type(t) and ch.get("children"):
|
||||
parent_code = str2code.get(t, t) # 若 t 已是代码则保持
|
||||
parent_str = code2str.get(t, t) # 若 t 已是中文则保持
|
||||
for gc in ch.get("children", []) or []:
|
||||
if isinstance(gc, dict):
|
||||
gc["type"] = parent_code
|
||||
gc["类型"] = parent_str
|
||||
new_children.append(gc)
|
||||
else:
|
||||
new_children.append(gc)
|
||||
# 丢弃父级人材机节点
|
||||
changed = True
|
||||
continue
|
||||
else:
|
||||
# 对未被移除的子节点继续递归展开
|
||||
_flatten_resource_splits_in_place(ch)
|
||||
new_children.append(ch)
|
||||
else:
|
||||
new_children.append(ch)
|
||||
node["children"] = new_children
|
||||
|
||||
if "children" in node and node["children"]:
|
||||
new_children, c1 = _process_node_list(node["children"])
|
||||
if c1:
|
||||
node["children"] = new_children
|
||||
changed = True
|
||||
|
||||
if "材机列表" in node and node["材机列表"]:
|
||||
new_materials, c2 = _process_node_list(node["材机列表"])
|
||||
if c2:
|
||||
node["材机列表"] = new_materials
|
||||
changed = True
|
||||
|
||||
for child in children:
|
||||
# 先复制两份:一份用于工程量树(quantity_node),一份用于资源提取(resource_node_src)
|
||||
@@ -428,6 +486,8 @@ def process_project_children(children, software_type=None):
|
||||
if new_type:
|
||||
# 不改写原始字段,直接将条目拷贝加入,类型由下游对象构造派生
|
||||
new_node = deepcopy(it)
|
||||
# 修正:并入前应用拆分展开逻辑,确保 商品砼=1 的资源不再携带 children
|
||||
_flatten_resource_splits_in_place(new_node)
|
||||
quantity_nodes.append(new_node)
|
||||
try:
|
||||
nm = (
|
||||
@@ -467,9 +527,12 @@ def process_project_children(children, software_type=None):
|
||||
return True
|
||||
return False
|
||||
|
||||
# 主材/设备直接计入(以标准化类型入列,避免后续 BCL 过滤不到)
|
||||
if current_node_type in ("主材", "设备", "1", "5"):
|
||||
# 主材/设备/一笔性费用直接计入(以标准化类型入列,避免后续 BCL 过滤不到)
|
||||
if current_node_type in ("主材", "设备", "一笔性费用", "1", "5"):
|
||||
to_append = deepcopy(original_quantity_node)
|
||||
# 修正:对即将入列的节点应用人材机拆分展开逻辑,
|
||||
# 以生效“商品砼=1:保留父节点并去除其 children”的规则
|
||||
_flatten_resource_splits_in_place(to_append)
|
||||
quantity_nodes.append(to_append)
|
||||
try:
|
||||
nm = (
|
||||
@@ -486,16 +549,20 @@ def process_project_children(children, software_type=None):
|
||||
# 定额按条件计入
|
||||
elif is_quota_node:
|
||||
if _children_have_no_children(quantity_node) or _mj_has_hit(quantity_node):
|
||||
quantity_nodes.append(original_quantity_node)
|
||||
to_append = deepcopy(original_quantity_node)
|
||||
# 修正:定额节点入列时也先应用拆分展开逻辑,
|
||||
# 保证“商品砼=1 的资源子项不含 children”
|
||||
_flatten_resource_splits_in_place(to_append)
|
||||
quantity_nodes.append(to_append)
|
||||
try:
|
||||
nm = (
|
||||
original_quantity_node.get("项目名称")
|
||||
or original_quantity_node.get("清单名称")
|
||||
or original_quantity_node.get("name")
|
||||
or original_quantity_node.get("材料名称")
|
||||
to_append.get("项目名称")
|
||||
or to_append.get("清单名称")
|
||||
or to_append.get("name")
|
||||
or to_append.get("材料名称")
|
||||
or "<未命名>"
|
||||
)
|
||||
tp = original_quantity_node.get("类型") or original_quantity_node.get("type")
|
||||
tp = to_append.get("类型") or to_append.get("type")
|
||||
# print(f"[DEBUG] 入列工程量节点(定额): 名称={nm} | 类型={tp}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user