refactor(ops): add ops web scaffold and update router for split dirs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f9f9915012
commit
797e96cbb5
|
|
@ -3,14 +3,30 @@ use tower_http::services::ServeDir;
|
||||||
|
|
||||||
use crate::app::AppState;
|
use crate::app::AppState;
|
||||||
|
|
||||||
const WEB_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/web");
|
async fn no_cache(
|
||||||
|
req: axum::extract::Request,
|
||||||
|
next: axum::middleware::Next,
|
||||||
|
) -> axum::response::Response {
|
||||||
|
let mut response = next.run(req).await;
|
||||||
|
response.headers_mut().insert(
|
||||||
|
axum::http::header::CACHE_CONTROL,
|
||||||
|
axum::http::HeaderValue::from_static("no-store"),
|
||||||
|
);
|
||||||
|
response
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_router(state: AppState) -> Router {
|
pub fn build_router(state: AppState) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/api/health", get(health_check))
|
.route("/api/health", get(health_check))
|
||||||
.nest_service(
|
.nest(
|
||||||
"/ui",
|
"/ui",
|
||||||
ServeDir::new(WEB_ROOT).append_index_html_on_directories(true),
|
Router::new()
|
||||||
|
.fallback_service(
|
||||||
|
ServeDir::new("web/ops")
|
||||||
|
.append_index_html_on_directories(true)
|
||||||
|
.fallback(ServeDir::new("web/core")),
|
||||||
|
)
|
||||||
|
.layer(axum::middleware::from_fn(no_cache)),
|
||||||
)
|
)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>PLC Control Operation System</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<h1>Operation System</h1>
|
|
||||||
<p>This web root is a placeholder for the operation-system app skeleton.</p>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="title">运转系统</div>
|
||||||
|
<div class="topbar-actions">
|
||||||
|
<div class="status" id="statusText">
|
||||||
|
<span class="ws-dot" id="wsDot"></span>
|
||||||
|
<span id="wsLabel">连接中…</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>运转系统</title>
|
||||||
|
<link rel="stylesheet" href="/ui/styles.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div data-partial="/ui/html/topbar.html"></div>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="muted" style="padding:2rem;text-align:center">运转系统页面开发中</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script type="module" src="/ui/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
function bootstrap() {
|
||||||
|
console.log("Operation system app initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap();
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
async function loadPartial(slot) {
|
||||||
|
const response = await fetch(slot.dataset.partial);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to load partial: ${slot.dataset.partial}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
slot.insertAdjacentHTML("beforebegin", html);
|
||||||
|
slot.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bootstrapPage() {
|
||||||
|
const slots = Array.from(document.querySelectorAll("[data-partial]"));
|
||||||
|
await Promise.all(slots.map((slot) => loadPartial(slot)));
|
||||||
|
await import("./app.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrapPage().catch((error) => {
|
||||||
|
document.body.innerHTML = `<pre>${error.message || String(error)}</pre>`;
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue