# topology_api/seed/seed_layout.py """Seed diagram layout and node positions for the engineering overview SVG.""" import json from topology_api.db import write_cursor def seed(): with write_cursor() as cur: # Get base cur.execute("SELECT id FROM bases WHERE code = 'guanghan'") base_id = cur.fetchone()["id"] # Upsert layout cur.execute(""" INSERT INTO diagram_layouts (id, base_id, layout_key, name, canvas_width, canvas_height, is_default) VALUES (gen_random_uuid(), %(base)s, 'engineering_overview_v1', '工程总图 v1', 1500, 1900, true) ON CONFLICT (base_id, layout_key) DO UPDATE SET name = EXCLUDED.name, is_default = true RETURNING id """, {"base": base_id}) layout_id = cur.fetchone()["id"] print(f"Layout: {layout_id}") # Component key → component_id mapping cur.execute("SELECT component_key, id FROM components WHERE base_id = %(base)s", {"base": base_id}) comp_map = {r["component_key"]: r["id"] for r in cur.fetchall()} # SVG node positions extracted from guanghan_topology_demo.html # node_key → (x, y, width, height, style_key, label_override, z_index) nodes = [ # Core cross ("core_cabin", comp_map.get("core_cabin"), 630, 470, 240, 200, "core-card", None, 10), ("habitat_2", comp_map.get("habitat_2"), 630, 220, 240, 140, "node-card", None, 5), ("habitat_1", comp_map.get("habitat_1"), 630, 760, 240, 120, "node-card", None, 5), ("greenhouse", comp_map.get("greenhouse"), 330, 490, 220, 160, "node-card", None, 5), ("lab_module", comp_map.get("lab_module"), 950, 490, 220, 160, "node-card", None, 5), ("wugang_2", comp_map.get("wugang_2"), 40, 495, 210, 150, "vehicle-card", None, 3), # Power cross ("power_module_hub", comp_map.get("power_module_hub"), 650, 1260, 200, 180, "power-node-card", None, 8), ("power_storage_rack", comp_map.get("power_storage_rack"), 600, 990, 300, 160, "power-card", "北部模块", 5), ("nuclear_reactor", comp_map.get("nuclear_reactor"), 620, 1540, 260, 150, "power-card", "南部模块", 5), # Power west/east groups (multiple DB components per SVG node) # power-west groups: isru_module, mining_module, ore_fuel_storage ("power_west_group", None, 280, 1250, 260, 200, "power-card", "西部模块", 5), # power-east groups: fuel_storage_mod, centrifuge_mod ("power_east_group", None, 960, 1250, 260, 200, "power-card", "东部模块", 5), # Bingluns ("binglun_1", comp_map.get("binglun_1"), 30, 1280, 210, 140, "vehicle-card", None, 2), ("binglun_2", comp_map.get("binglun_2"), 645, 1740, 210, 120, "vehicle-card", None, 2), ("binglun_3", comp_map.get("binglun_3"), 1260, 1280, 210, 140, "vehicle-card", None, 2), ] # Delete existing nodes and re-insert cur.execute("DELETE FROM diagram_nodes WHERE layout_id = %(lid)s", {"lid": layout_id}) for node_key, comp_id, x, y, w, h, style, label, z in nodes: cur.execute(""" INSERT INTO diagram_nodes (id, layout_id, component_id, node_key, x, y, width, height, style_key, label_override, z_index) VALUES (gen_random_uuid(), %(lid)s, %(cid)s, %(nkey)s, %(x)s, %(y)s, %(w)s, %(h)s, %(style)s, %(label)s, %(z)s) """, { "lid": layout_id, "cid": comp_id, "nkey": node_key, "x": x, "y": y, "w": w, "h": h, "style": style, "label": label, "z": z, }) print(f"Nodes inserted: {len(nodes)}") # Node group mappings (for modal details aggregation) groups = { "power_west_group": ["isru_module", "mining_module", "ore_fuel_storage"], "power_east_group": ["fuel_storage_mod", "centrifuge_mod"], } print(f"Node groups: {json.dumps(groups, ensure_ascii=False)}") if __name__ == "__main__": seed()