| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- # -*- coding: utf-8 -*-
- """给导入的各仿真页注入统一外壳: 顶栏 + 配色 token + 返回链接。
- 只做**加法**(追加一段 style + 在 body 开头插一个顶栏), 不改页面原有 DOM 与 JS,
- 所以不会破坏各页自己的 canvas 绘制逻辑。canvas 内部配色由各页 JS 决定, 本层不动 —— 这是已知边界。"""
- import pathlib, re, sys
- SIM = pathlib.Path("/Users/yuanying/guanlan-rudong-v2/outputs/rudong/windscada/_demo/sim")
- MARK = "guanlan-shell-v1"
- PAGES = {
- "涡激共振模拟器.html": ("涡激共振模拟器", "机理通识 · 十二款机型预设"),
- "涡激实测核验.html": ("涡激实测核验", "实测 · 九台秒级"),
- "偏航滑移事件回放.html": ("偏航滑移事件回放", "实测 · 单台"),
- "故障分布三维视图.html": ("故障分布三维视图", "实测 · 机组 × 系统 × 月份"),
- "变流器故障仿真.html": ("变流器故障仿真", "注入 · 波形为合成"),
- "变桨故障仿真.html": ("变桨故障仿真", "注入 · 波形为合成"),
- "整机联调台_1.5MW.html": ("整机联调台 · 1.5 MW", "正演 · 控制核心层参数"),
- "整机联调台_4MW.html": ("整机联调台 · 4 MW", "正演 · 控制核心层参数"),
- }
- SHELL_CSS = """
- <style id="%s">
- :root{--gl-bg:#edf7f9;--gl-ink:#133047;--gl-ink2:#28536b;--gl-ink3:#61788b;
- --gl-line:#cbe2eb;--gl-spec:#0e8898;--gl-meas:#2077a8}
- .gl-top{position:sticky;top:0;z-index:9999;display:flex;align-items:center;gap:14px;
- padding:11px 26px;background:linear-gradient(110deg,#10384d,#0e6470);color:#fff;
- font:14px/1.5 "PingFang SC","Hiragino Sans GB","Microsoft YaHei",ui-sans-serif,system-ui,sans-serif;
- box-shadow:0 2px 12px rgba(12,80,102,.16)}
- .gl-top .gl-logo{width:30px;height:30px;border-radius:8px;background:rgba(255,255,255,.16);
- display:grid;place-items:center;font-weight:700;font-size:15px;flex:0 0 auto}
- .gl-top b{font-size:14.5px;letter-spacing:.02em}
- .gl-top small{display:block;font:11px "SF Mono",Menlo,Consolas,monospace;opacity:.75;letter-spacing:.1em}
- .gl-top .gl-back{margin-left:auto;color:#e8fbff;text-decoration:none;border:1px solid #a7dce3;
- border-radius:999px;padding:6px 14px;font-size:12.5px;white-space:nowrap}
- .gl-top .gl-back:hover{background:rgba(255,255,255,.12)}
- body{background:var(--gl-bg)!important}
- </style>
- """ % MARK
- def shell(title, sub):
- return (f'<div class="gl-top"><div class="gl-logo">观</div>'
- f'<div><b>{title}</b><small>{sub}</small></div>'
- f'<a class="gl-back" href="./仿真集成台.html">← 返回仿真集成台</a></div>')
- def apply(path, title, sub):
- s = path.read_text(encoding="utf-8")
- if MARK in s:
- # 幂等剥离。注意: 不能用 <div class="gl-top">.*?</div></div> —— 非贪婪会一路扫进页面正文,
- # 把内容一起删掉(曾把一页删掉 4 KB)。改用唯一的结束锚: 顶栏最后是 </a></div>。
- s = re.sub(r'<style id="%s">.*?</style>\s*' % MARK, "", s, flags=re.S)
- s = re.sub(r'<div class="gl-top">.*?返回仿真集成台</a></div>\s*', "", s, flags=re.S, count=1)
- # 主路径: 有 </head> / <body>
- m = re.search(r"</head\s*>", s, re.I)
- if m:
- s = s[:m.start()] + SHELL_CSS + s[m.start():]
- else:
- # 回退: 片段式 HTML (无 head/body 标签, 浏览器容忍)。锚到 <title> 或最后一个 </style> 之后
- a = re.search(r"</title\s*>", s, re.I) or re.search(r"</style\s*>(?![\s\S]*</style\s*>)", s, re.I)
- if not a: return None
- s = s[:a.end()] + "\n" + SHELL_CSS + s[a.end():]
- b = re.search(r"<body[^>]*>", s, re.I)
- if b:
- s = s[:b.end()] + "\n" + shell(title, sub) + s[b.end():]
- else:
- # 回退: 插在最后一个 </style> 之后 (即样式区结束、可见内容开始处)
- c = None
- for c in re.finditer(r"</style\s*>", s, re.I): pass
- if not c: return None
- s = s[:c.end()] + "\n" + shell(title, sub) + s[c.end():]
- path.write_text(s, encoding="utf-8"); return len(s)
- ok = 0
- for f,(t,sub) in PAGES.items():
- p = SIM/f
- if not p.exists(): print(f" 缺: {f}"); continue
- n = apply(p, t, sub)
- if n: ok += 1; print(f" ✓ {f} ({n//1024} KB)")
- else: print(f" ✗ {f} 结构不符, 未注入")
- print(f"\n注入 {ok}/{len(PAGES)} 页")
|