feat(topology): add GHC06 layout and deploy docs
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,17 @@ import json
|
||||
from topology_api.db import write_cursor
|
||||
|
||||
THEME_KEY = "guanghan_light_engineering_v1"
|
||||
CANVAS_WIDTH = 1900
|
||||
CANVAS_HEIGHT = 1900
|
||||
CONTENT_X_OFFSET = 200
|
||||
LEGACY_CANVAS_WIDTH = 1900
|
||||
LEGACY_CANVAS_HEIGHT = 1900
|
||||
LEGACY_X_OFFSET = 200
|
||||
LEGACY_Y_OFFSET = 0
|
||||
|
||||
# GHC-06 and later use a separate future-ready canvas. Historical missions
|
||||
# keep the legacy coordinates, especially Wugang 2's GHC-05 greenhouse berth.
|
||||
FUTURE_CANVAS_WIDTH = 2900
|
||||
FUTURE_CANVAS_HEIGHT = 2350
|
||||
FUTURE_X_OFFSET = 500
|
||||
FUTURE_Y_OFFSET = 280
|
||||
|
||||
THEME_TOKENS = {
|
||||
"textColor": "#152033",
|
||||
@@ -99,7 +107,11 @@ def seed():
|
||||
theme_id = cur.fetchone()["id"]
|
||||
print(f"Theme: {theme_id}")
|
||||
|
||||
# Upsert layout
|
||||
# Keep the pre-GHC-06 layout as the default/fallback layout.
|
||||
cur.execute(
|
||||
"UPDATE diagram_layouts SET is_default = false WHERE base_id = %(base)s",
|
||||
{"base": base_id},
|
||||
)
|
||||
cur.execute("""
|
||||
INSERT INTO diagram_layouts (id, base_id, layout_key, name,
|
||||
canvas_width, canvas_height, is_default, theme_id)
|
||||
@@ -114,8 +126,8 @@ def seed():
|
||||
RETURNING id
|
||||
""", {
|
||||
"base": base_id,
|
||||
"canvas_width": CANVAS_WIDTH,
|
||||
"canvas_height": CANVAS_HEIGHT,
|
||||
"canvas_width": LEGACY_CANVAS_WIDTH,
|
||||
"canvas_height": LEGACY_CANVAS_HEIGHT,
|
||||
"theme": theme_id,
|
||||
})
|
||||
layout_id = cur.fetchone()["id"]
|
||||
@@ -239,6 +251,21 @@ def seed():
|
||||
("wugang_2", 40, 495, 210, 150, "vehicle-card", None, 3,
|
||||
"Block 2 载人着陆器", "温室远端接口", {}, ["wugang_2"]),
|
||||
|
||||
# GHC-06 northern expansion. The engineering overview keeps the
|
||||
# pre-GHC-06 core cross stable and places the new branch to its
|
||||
# upper-right so historical mission snapshots do not jump.
|
||||
("expansion_hub", 40, 490, 210, 170, "core-card", "十字扩展节点", 9,
|
||||
"扩展区中枢", "南部接口预留", {}, ["expansion_hub"]),
|
||||
("storage_module", 35, 220, 220, 140, "node-card", "存储模块", 5,
|
||||
"十字扩展节点北口", "温湿度受控存储", {}, ["storage_module"]),
|
||||
("greenhouse_2", 280, 490, 220, 170, "node-card", "温室二号", 5,
|
||||
"东接温室模块 · 西接十字节点", "堆肥循环系统", {},
|
||||
["greenhouse_2", "compost_module"]),
|
||||
("habitat_3", -190, 505, 200, 140, "node-card", "居住舱段三号", 5,
|
||||
"十字扩展节点西口", "4 铺位 · 总容量 14 人", {}, ["habitat_3"]),
|
||||
("wugang_3", 645, 40, 210, 150, "vehicle-card", "吴刚三号", 3,
|
||||
"Block 2 载人着陆器", "居住舱二号北部停泊位", {}, ["wugang_3"]),
|
||||
|
||||
# Power cross
|
||||
("power_module_hub", 650, 1260, 200, 180, "power-node-card",
|
||||
"电力模块", 8, "四向安装节点", "核电与资源中枢", {},
|
||||
@@ -247,7 +274,7 @@ def seed():
|
||||
"北部模块", 5, "电力模块存储支架", "加压走道端",
|
||||
{"radiator": True}, ["power_storage_rack"]),
|
||||
("nuclear_reactor", 620, 1540, 260, 150, "power-card",
|
||||
"南部模块", 5, "核反应堆", "30%功率",
|
||||
"南部模块", 5, "核反应堆", "35%功率",
|
||||
{"radiator": True}, ["nuclear_reactor"]),
|
||||
|
||||
# Power west/east groups (multiple DB components per SVG node)
|
||||
@@ -269,48 +296,96 @@ def seed():
|
||||
"电力模块东侧", "Block 2", {}, ["binglun_3"]),
|
||||
]
|
||||
|
||||
# Delete existing nodes and re-insert
|
||||
cur.execute("DELETE FROM diagram_nodes WHERE layout_id = %(lid)s",
|
||||
{"lid": layout_id})
|
||||
|
||||
for (
|
||||
node_key, x, y, w, h, style, label, z, display_meta,
|
||||
display_hint, decorations, member_keys,
|
||||
) in nodes:
|
||||
primary_component_id = (
|
||||
comp_map[member_keys[0]] if len(member_keys) == 1 else None
|
||||
)
|
||||
cur.execute("""
|
||||
INSERT INTO diagram_nodes
|
||||
(id, layout_id, component_id, node_key, x, y,
|
||||
width, height, style_key, label_override, z_index,
|
||||
display_meta, display_hint, decorations)
|
||||
VALUES (gen_random_uuid(), %(lid)s, %(cid)s, %(nkey)s,
|
||||
%(x)s, %(y)s, %(w)s, %(h)s,
|
||||
%(style)s, %(label)s, %(z)s,
|
||||
%(meta)s, %(hint)s, %(decorations)s)
|
||||
RETURNING id
|
||||
""", {
|
||||
"lid": layout_id, "cid": primary_component_id,
|
||||
"nkey": node_key,
|
||||
"x": x + CONTENT_X_OFFSET, "y": y, "w": w, "h": h,
|
||||
"style": style, "label": label, "z": z,
|
||||
"meta": display_meta, "hint": display_hint,
|
||||
"decorations": json.dumps(decorations),
|
||||
})
|
||||
node_id = cur.fetchone()["id"]
|
||||
for display_order, member_key in enumerate(member_keys):
|
||||
def insert_nodes(target_layout_id, target_nodes, x_offset, y_offset):
|
||||
cur.execute("DELETE FROM diagram_nodes WHERE layout_id = %(lid)s",
|
||||
{"lid": target_layout_id})
|
||||
for (
|
||||
node_key, x, y, w, h, style, label, z, display_meta,
|
||||
display_hint, decorations, member_keys,
|
||||
) in target_nodes:
|
||||
primary_component_id = (
|
||||
comp_map[member_keys[0]] if len(member_keys) == 1 else None
|
||||
)
|
||||
cur.execute("""
|
||||
INSERT INTO diagram_node_members
|
||||
(diagram_node_id, component_id, display_order)
|
||||
VALUES (%(node)s, %(component)s, %(display_order)s)
|
||||
INSERT INTO diagram_nodes
|
||||
(id, layout_id, component_id, node_key, x, y,
|
||||
width, height, style_key, label_override, z_index,
|
||||
display_meta, display_hint, decorations)
|
||||
VALUES (gen_random_uuid(), %(lid)s, %(cid)s, %(nkey)s,
|
||||
%(x)s, %(y)s, %(w)s, %(h)s,
|
||||
%(style)s, %(label)s, %(z)s,
|
||||
%(meta)s, %(hint)s, %(decorations)s)
|
||||
RETURNING id
|
||||
""", {
|
||||
"node": node_id,
|
||||
"component": comp_map[member_key],
|
||||
"display_order": display_order,
|
||||
"lid": target_layout_id, "cid": primary_component_id,
|
||||
"nkey": node_key, "x": x + x_offset, "y": y + y_offset,
|
||||
"w": w, "h": h, "style": style, "label": label, "z": z,
|
||||
"meta": display_meta, "hint": display_hint,
|
||||
"decorations": json.dumps(decorations),
|
||||
})
|
||||
node_id = cur.fetchone()["id"]
|
||||
for display_order, member_key in enumerate(member_keys):
|
||||
cur.execute("""
|
||||
INSERT INTO diagram_node_members
|
||||
(diagram_node_id, component_id, display_order)
|
||||
VALUES (%(node)s, %(component)s, %(display_order)s)
|
||||
""", {
|
||||
"node": node_id,
|
||||
"component": comp_map[member_key],
|
||||
"display_order": display_order,
|
||||
})
|
||||
|
||||
print(f"Nodes inserted: {len(nodes)}")
|
||||
insert_nodes(layout_id, nodes, LEGACY_X_OFFSET, LEGACY_Y_OFFSET)
|
||||
print(f"Legacy nodes inserted: {len(nodes)}")
|
||||
|
||||
# Create the GHC-06+ layout without changing historical coordinates.
|
||||
cur.execute("""
|
||||
INSERT INTO diagram_layouts (id, base_id, layout_key, name,
|
||||
canvas_width, canvas_height, is_default, theme_id)
|
||||
VALUES (gen_random_uuid(), %(base)s, 'engineering_overview_ghc06_v1',
|
||||
'工程总图 GHC-06+', %(width)s, %(height)s, false, %(theme)s)
|
||||
ON CONFLICT (base_id, layout_key) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
canvas_width = EXCLUDED.canvas_width,
|
||||
canvas_height = EXCLUDED.canvas_height,
|
||||
is_default = false,
|
||||
theme_id = EXCLUDED.theme_id
|
||||
RETURNING id
|
||||
""", {
|
||||
"base": base_id, "width": FUTURE_CANVAS_WIDTH,
|
||||
"height": FUTURE_CANVAS_HEIGHT, "theme": theme_id,
|
||||
})
|
||||
future_layout_id = cur.fetchone()["id"]
|
||||
|
||||
future_positions = {
|
||||
"core_cabin": (970, 470), "habitat_2": (970, 220),
|
||||
"habitat_1": (970, 760), "greenhouse": (700, 490),
|
||||
"lab_module": (1260, 490), "wugang_2": (1570, 495),
|
||||
"expansion_hub": (40, 490), "storage_module": (35, 220),
|
||||
"greenhouse_2": (280, 490), "habitat_3": (-190, 505),
|
||||
"wugang_3": (985, 40), "power_module_hub": (990, 1260),
|
||||
"power_storage_rack": (940, 990), "nuclear_reactor": (960, 1540),
|
||||
"power_west_group": (620, 1250), "power_east_group": (1300, 1250),
|
||||
"binglun_1": (370, 1280), "binglun_2": (985, 1740),
|
||||
"binglun_3": (1600, 1280),
|
||||
}
|
||||
future_copy = {
|
||||
"greenhouse": ("核心舱西部安装口", "加压走道接温室二号"),
|
||||
"lab_module": ("核心舱东部安装口", "东向扩建轴 · 远端接吴刚二号"),
|
||||
"wugang_2": ("Block 2 载人着陆器", "实验舱东部停泊位"),
|
||||
}
|
||||
future_nodes = []
|
||||
for node in nodes:
|
||||
updated = list(node)
|
||||
updated[1], updated[2] = future_positions[updated[0]]
|
||||
if updated[0] in future_copy:
|
||||
updated[8], updated[9] = future_copy[updated[0]]
|
||||
future_nodes.append(tuple(updated))
|
||||
|
||||
insert_nodes(
|
||||
future_layout_id, future_nodes, FUTURE_X_OFFSET, FUTURE_Y_OFFSET
|
||||
)
|
||||
print(f"GHC-06+ nodes inserted: {len(future_nodes)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user