class_name ABGRiskBoardPageController extends RefCounted ## UI-independent Risk Board view-data assembly. ## ## FormationRiskService remains responsible for loading and persisting the ## accepted party. Risk Commitment remains the next-page authority. This ## controller only validates and copies the frozen facts the RSK-001 View ## renders, plus local selection/Review eligibility. const REQUIRED_OPTION_COUNT := 3 func snapshot( company: Dictionary, formation: Dictionary, selected_risk_id := "", locale := "zh_CN" ) -> Dictionary: if company.is_empty(): return {"ok": false, "code": "COMPANY_REQUIRED"} var raw_recruits = company.get("owned_recruits", []) if not raw_recruits is Array: return {"ok": false, "code": "COMPANY_INVALID"} var raw_contract = company.get("active_contract", {}) if not raw_contract is Dictionary or Dictionary(raw_contract).is_empty(): return {"ok": false, "code": "RISK_CONTRACT_REQUIRED"} if formation.is_empty(): return {"ok": false, "code": "RISK_FORMATION_REQUIRED"} if String(formation.get("status", "")) != "ready": return {"ok": false, "code": "RISK_READINESS_REQUIRED"} var raw_snapshot = formation.get("accepted_party_snapshot", {}) if not raw_snapshot is Dictionary or Dictionary(raw_snapshot).is_empty(): return {"ok": false, "code": "RISK_PARTY_SNAPSHOT_REQUIRED"} var contract: Dictionary = Dictionary(raw_contract).duplicate(true) var members := _members_by_id(raw_recruits) var capacity := int(formation.get("line_capacity", contract.get("line_capacity", 0))) var party_snapshot: Dictionary = Dictionary(raw_snapshot).duplicate(true) var party_ids = party_snapshot.get("front_to_rear_ids", formation.get("saved_front_to_rear_ids", [])) if not party_ids is Array or party_ids.is_empty(): return {"ok": false, "code": "RISK_PARTY_ORDER_REQUIRED"} var order_validation := _validate_order(party_ids, members, capacity) if not order_validation.ok: return order_validation var raw_options = formation.get("risk_options", []) if not raw_options is Array or raw_options.size() != REQUIRED_OPTION_COUNT: return {"ok": false, "code": "RISK_OPTIONS_INVALID"} var options: Array[Dictionary] = [] var option_ids: Array = [] for raw_option in raw_options: if not raw_option is Dictionary: return {"ok": false, "code": "RISK_OPTION_INVALID"} var option: Dictionary = Dictionary(raw_option).duplicate(true) var option_id := String(option.get("risk_option_id", "")) if option_id.is_empty(): return {"ok": false, "code": "RISK_OPTION_ID_INVALID"} if option_id in option_ids: return {"ok": false, "code": "RISK_OPTION_DUPLICATE"} option_ids.append(option_id) options.append(option) var selected := String(selected_risk_id) if String(selected_risk_id) in option_ids else "" var copied_relations: Array = _copy_array(party_snapshot.get("relations", formation.get("relations", []))) var copied_coverage: Dictionary = Dictionary(party_snapshot.get("coverage", formation.get("coverage", {}))).duplicate(true) var relation_by_id := _relations_by_id(copied_relations) var ordered_recruits: Array[Dictionary] = [] for position in range(order_validation.ids.size()): var recruit_id := String(order_validation.ids[position]) ordered_recruits.append({ "position": position, "recruit_id": recruit_id, "recruit": Dictionary(members[recruit_id]).duplicate(true), "relation": Dictionary(relation_by_id.get(recruit_id, {})).duplicate(true), }) var copied_options: Array[Dictionary] = [] for option in options: var copied: Dictionary = option.duplicate(true) copied["selected"] = String(copied.get("risk_option_id", "")) == selected copied_options.append(copied) var contract_data := { "contract_id": String(contract.get("contract_id", "")), "run_id": String(contract.get("run_id", "")), "difficulty": String(contract.get("difficulty", "standard")), "coin": int(contract.get("coin", 0)), "line_capacity": int(contract.get("line_capacity", capacity)), } var company_data := { "company_id": String(company.get("company_id", "")), "owned_count": members.size(), "line_capacity": capacity, } return { "ok": true, "page_id": "risk_board", "locale": String(locale), "company": company_data, "contract": contract_data, "party": { "snapshot_id": String(party_snapshot.get("snapshot_id", "")), "snapshot_hash": String(party_snapshot.get("snapshot_hash", "")), "order_hash": String(party_snapshot.get("order_hash", "")), "front_to_rear_ids": order_validation.ids.duplicate(true), "ordered_recruits": ordered_recruits, "orientation": String(party_snapshot.get("orientation", formation.get("orientation", "rear_left_front_right"))), "front_position": int(party_snapshot.get("front_position", formation.get("front_position", 0))), "line_capacity": capacity, "relations": copied_relations, "coverage": copied_coverage, "first_threat": Dictionary(formation.get("first_threat", {})).duplicate(true), }, "options": { "items": copied_options, "ids": option_ids.duplicate(true), "count": copied_options.size(), }, "selection": { "selected_risk_id": selected, "state": "selected" if not selected.is_empty() else "no_selection", "auto_selected": false, "selection_reason": "selected" if not selected.is_empty() else "no_selection", }, "commands": { "review_enabled": not selected.is_empty(), "back_enabled": true, "settings_enabled": true, }, } func _validate_order(values: Array, members: Dictionary, capacity: int) -> Dictionary: if capacity <= 0 or values.size() != capacity: return {"ok": false, "code": "RISK_PARTY_COUNT_INVALID"} var ids: Array = [] for value in values: var recruit_id := String(value) if not members.has(recruit_id): return {"ok": false, "code": "RISK_PARTY_RECRUIT_UNKNOWN"} if recruit_id in ids: return {"ok": false, "code": "RISK_PARTY_RECRUIT_DUPLICATE"} ids.append(recruit_id) return {"ok": true, "code": "RISK_PARTY_ORDER_VALID", "ids": ids} func _members_by_id(values) -> Dictionary: var result := {} for value in values: if value is Dictionary: var copied: Dictionary = Dictionary(value).duplicate(true) var recruit_id := String(copied.get("recruit_id", "")) if not recruit_id.is_empty(): result[recruit_id] = copied return result func _relations_by_id(values: Array) -> Dictionary: var result := {} for value in values: if value is Dictionary: result[String(value.get("recruit_id", ""))] = Dictionary(value).duplicate(true) return result func _copy_array(values) -> Array: var result: Array = [] if not values is Array: return result for value in values: result.append(value.duplicate(true) if value is Dictionary or value is Array else value) return result