update
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Asset Log Prototype</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body data-page="asset-log">
|
||||
<div class="site-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-kicker">Mission Ops Prototype</span>
|
||||
<span class="brand-name">Asset Log</span>
|
||||
</a>
|
||||
<nav class="topbar-nav">
|
||||
<a href="./index.html">Overview</a>
|
||||
<a href="./status-board.html">Status Board</a>
|
||||
<a href="./location-board.html">Location Board</a>
|
||||
<a class="active" href="./asset-log.html">Asset Log</a>
|
||||
<a href="./timeline-view.html">Timeline View</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Single Asset Detail</p>
|
||||
<h1>让单个资产的事件点和状态段在一页里同时可读</h1>
|
||||
<p>这页不是普通日志表,而是当前状态、未来计划、历史记录和录入入口的组合页。这里用 XH-02 Taibai 作为样例对象。</p>
|
||||
</div>
|
||||
<div class="hero-side">
|
||||
<section class="time-card">
|
||||
<span class="label">Simulation Time</span>
|
||||
<p class="time-value" data-sim-time-display>2060-03-12 09:00</p>
|
||||
<p class="hero-note">Current state block and highlighted entry are both interpreted against this clock.</p>
|
||||
</section>
|
||||
<div class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Current Status</span>
|
||||
<strong class="metric-value" data-current-state>Transit</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Next Event</span>
|
||||
<strong class="metric-value" data-next-event-date>03-29</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Entries</span>
|
||||
<strong class="metric-value">8</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel toolbar">
|
||||
<div class="toolbar-row">
|
||||
<label class="clock-field">
|
||||
<span class="eyebrow">Simulation Time</span>
|
||||
<input type="datetime-local" data-sim-time-input>
|
||||
</label>
|
||||
<button class="ghost-button" type="button" data-time-shift="-30">- 30d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="-7">- 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="7">+ 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="30">+ 30d</button>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
<span class="pill">Relative labels are derived from selected time</span>
|
||||
<span class="pill">No manual Confirmed / Planned field on the log view</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="split-layout">
|
||||
<main class="stack">
|
||||
<section class="panel stack">
|
||||
<div class="asset-summary-grid">
|
||||
<article class="asset-summary-card stack">
|
||||
<div class="asset-summary-head">
|
||||
<div>
|
||||
<p class="eyebrow">Asset Summary</p>
|
||||
<h2>XH-02 Taibai</h2>
|
||||
<p class="subtle">Exploration Mothership · Mars Expedition Program</p>
|
||||
</div>
|
||||
<span class="status-pill" data-current-state-pill>In Transit</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Current Location</dt>
|
||||
<dd data-current-location>Earth to Mars Transfer</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Current Mission</dt>
|
||||
<dd>Support Mars One Campus</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd data-current-window>2060-02-26 06:00 → 2060-03-29 18:00</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Planned Event</dt>
|
||||
<dd data-next-event>Mars Arrival · 2060-03-29 18:00</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="asset-chip-row">
|
||||
<span class="chip strong">Crew Transfer Support</span>
|
||||
<span class="chip">Mars System</span>
|
||||
<span class="chip">Heavy Logistics</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="asset-current-card stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Current Derived State</p>
|
||||
<h2>Operational Snapshot</h2>
|
||||
</div>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Status</dt>
|
||||
<dd>In Transit</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Planned Arrival</dt>
|
||||
<dd data-next-event-short>2060-03-29</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Transfer Duration</dt>
|
||||
<dd data-current-duration>31 days</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Relative Mode</dt>
|
||||
<dd data-relative-mode>Derived from selected clock</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">History</p>
|
||||
<h2>Timeline Entries</h2>
|
||||
<p>Event Point 和 State Interval 混排,但视觉上明确区分。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="entry-list">
|
||||
<article class="entry event" data-kind="event" data-start="2058-03-15T10:20" data-title="First module delivered to Star Port" data-location="Star Port">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2058-03-15 10:20</span>
|
||||
<h3>First module delivered to Star Port</h3>
|
||||
</div>
|
||||
<span class="tone-pill completed" data-entry-badge>Event Point</span>
|
||||
</div>
|
||||
<p>Core transfer spine and habitat ring unloaded for final assembly at Star Port.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry event" data-kind="event" data-start="2059-08-06T09:00" data-title="Commissioned" data-location="Star Port">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2059-08-06 09:00</span>
|
||||
<h3>Commissioned</h3>
|
||||
</div>
|
||||
<span class="tone-pill completed" data-entry-badge>Event Point</span>
|
||||
</div>
|
||||
<p>Flight certification signed. Taibai was cleared for Mars transport duties.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry state" data-kind="state" data-start="2059-08-08T04:10" data-end="2059-10-17T13:40" data-title="Outbound transfer carrying Mars Expedition 3" data-location="Earth to Mars Transfer" data-state-label="Outbound Transfer">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2059-08-08 04:10 → 2059-10-17 13:40</span>
|
||||
<h3>Outbound transfer carrying Mars Expedition 3</h3>
|
||||
</div>
|
||||
<span class="tone-pill completed" data-entry-badge>State Interval</span>
|
||||
</div>
|
||||
<p>Departure from Earth with full crew and descent stack attached. This is the kind of interval that should drive board state during the whole travel window.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry event" data-kind="event" data-start="2059-10-17T13:40" data-title="Mars Arrival" data-location="Mars Orbit">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2059-10-17 13:40</span>
|
||||
<h3>Mars Arrival</h3>
|
||||
</div>
|
||||
<span class="tone-pill completed" data-entry-badge>Event Point</span>
|
||||
</div>
|
||||
<p>Insertion burn nominal. Crew descent staging began next day.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry state" data-kind="state" data-start="2059-10-18T08:00" data-end="2059-10-19T06:10" data-title="Mars orbit standby and crew pickup window" data-location="Mars Orbit" data-state-label="Mars Orbit Standby">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2059-10-18 08:00 → 2059-10-19 06:10</span>
|
||||
<h3>Mars orbit standby and crew pickup window</h3>
|
||||
</div>
|
||||
<span class="tone-pill completed" data-entry-badge>State Interval</span>
|
||||
</div>
|
||||
<p>Received Mars Expedition 1 return crew after descent vehicle separation.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry state" data-kind="state" data-start="2060-02-26T06:00" data-end="2060-03-29T18:00" data-title="Support mission transfer to Mars One Campus" data-location="Earth to Mars Transfer" data-state-label="Support Transit">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2060-02-26 06:00 → 2060-03-29 18:00</span>
|
||||
<h3>Support mission transfer to Mars One Campus</h3>
|
||||
</div>
|
||||
<span class="tone-pill active" data-entry-badge>State Interval</span>
|
||||
</div>
|
||||
<p>Carrying structural truss and greenhouse kit; 105 km/s, 31-day transition. This interval is the one currently lighting up Status Board.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="entry event" data-kind="event" data-start="2060-03-29T18:00" data-title="Mars Arrival" data-location="Mars Orbit">
|
||||
<div class="entry-rail"><span class="entry-dot"></span></div>
|
||||
<div class="entry-copy">
|
||||
<div class="entry-head">
|
||||
<div>
|
||||
<span class="entry-time">2060-03-29 18:00</span>
|
||||
<h3>Mars Arrival</h3>
|
||||
</div>
|
||||
<span class="tone-pill planned" data-entry-badge>Event Point</span>
|
||||
</div>
|
||||
<p>Planned capture burn and cargo handoff to surface fleet.</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<aside class="stack">
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Authoring</p>
|
||||
<h2>Entry Composer Mock</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="composer">
|
||||
<label>
|
||||
<span class="eyebrow">Mode</span>
|
||||
<select>
|
||||
<option>State Interval</option>
|
||||
<option>Event Point</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Current Location</span>
|
||||
<input type="text" value="Earth to Mars Transfer">
|
||||
</label>
|
||||
<label class="span-2">
|
||||
<span class="eyebrow">Title</span>
|
||||
<input type="text" value="Support mission transfer to Mars One Campus">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Start</span>
|
||||
<input type="text" value="2060-02-26 06:00">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">End</span>
|
||||
<input type="text" value="2060-03-29 18:00">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">From</span>
|
||||
<input type="text" value="Earth">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">To</span>
|
||||
<input type="text" value="Mars">
|
||||
</label>
|
||||
<label class="span-2">
|
||||
<span class="eyebrow">Summary</span>
|
||||
<textarea>Carrying structural truss and greenhouse kit; 105 km/s, 31-day transition.</textarea>
|
||||
</label>
|
||||
<span class="button span-2">Save Prototype Entry</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Future</p>
|
||||
<h2>Why This Page Matters</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-list subtle">
|
||||
<p>当前状态不必单独维护一份,因为它可以从日志自动推导。</p>
|
||||
<p>手动修正状态以后可以加,但第一版应该以日志推导为主。</p>
|
||||
<p>Event Point 和 State Interval 分开录入,能显著减少歧义。</p>
|
||||
<p>Past / Current / Upcoming 标签应当是相对于当前 Simulation Time 自动计算,而不是手工选 Confirmed 或 Planned。</p>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,206 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Mission Operations Prototype</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body data-page="overview">
|
||||
<div class="site-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-kicker">KSP Static Prototype</span>
|
||||
<span class="brand-name">Mission Operations</span>
|
||||
</a>
|
||||
<nav class="topbar-nav">
|
||||
<a class="active" href="./index.html">Overview</a>
|
||||
<a href="./status-board.html">Status Board</a>
|
||||
<a href="./location-board.html">Location Board</a>
|
||||
<a href="./asset-log.html">Asset Log</a>
|
||||
<a href="./timeline-view.html">Timeline View</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Standalone Review Build</p>
|
||||
<h1>载具与设施任务运营原型</h1>
|
||||
<p>这是一套独立静态原型,不依赖 Flask 模板渲染。你现在双击这些 HTML 文件,浏览器里看到的就是页面设计本身,而不是 Jinja 源码。</p>
|
||||
<div class="pill-row">
|
||||
<span class="pill">Asset-first model</span>
|
||||
<span class="pill">Event Point + State Interval</span>
|
||||
<span class="pill">Simulation Time driven</span>
|
||||
<span class="pill">Planned + Current + Past</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-side">
|
||||
<section class="time-card">
|
||||
<span class="label">Prototype Clock</span>
|
||||
<p class="time-value" data-sim-time-display>2060-03-12 09:00</p>
|
||||
<p class="hero-note">原型里所有当前状态、未来事件和时间线高亮,都围绕这个手动设置的 Simulation Time 进行解释。</p>
|
||||
</section>
|
||||
<div class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Tracked Assets</span>
|
||||
<strong class="metric-value">14</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Active Missions</span>
|
||||
<strong class="metric-value">6</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Upcoming 30d</span>
|
||||
<strong class="metric-value">9</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel toolbar">
|
||||
<div class="toolbar-row">
|
||||
<label class="clock-field">
|
||||
<span class="eyebrow">Simulation Time</span>
|
||||
<input type="datetime-local" data-sim-time-input>
|
||||
</label>
|
||||
<button class="ghost-button" type="button" data-time-shift="-30">- 30d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="-7">- 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="7">+ 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="30">+ 30d</button>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
<span class="pill">Current state and next event are always relative to selected clock</span>
|
||||
<span class="pill">Overview now includes recent past and upcoming event lists</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="command-layout">
|
||||
<main class="stack">
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Mission Center</p>
|
||||
<h2>当前正在运行的关键任务</h2>
|
||||
<p>首页主区域不再是页面目录,而是更像值班台,优先告诉你当前系统里什么任务正在跑。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ops-list" id="active-ops-list">
|
||||
<article class="ops-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Loading active operations</h3>
|
||||
<p class="asset-type">Preparing mission center feed</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="summary-text">This list will update relative to the selected clock.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Attention Queue</p>
|
||||
<h2>接下来需要处理的事项</h2>
|
||||
<p>这一栏更接近任务队列,不是简单的未来事件列表。它应该告诉你“值班时下一步要盯什么”。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="attention-list" id="attention-queue-list">
|
||||
<article class="attention-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Loading attention queue</h3>
|
||||
<p class="asset-type">Preparing next actions</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="summary-text">This queue will show near-term actions relative to the selected clock.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Operational Shortcuts</p>
|
||||
<h2>工作面板入口</h2>
|
||||
<p>四个详细页面仍然保留,但在首页里它们应该是任务中心的工作入口,而不是首页主内容本身。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shortcut-grid">
|
||||
<a class="link-card" href="./status-board.html">
|
||||
<strong>Status Board</strong>
|
||||
<h3>按状态看当前全局</h3>
|
||||
<p>快速扫描“现在有哪些资产正在干什么”。</p>
|
||||
</a>
|
||||
<a class="link-card" href="./location-board.html">
|
||||
<strong>Location Board</strong>
|
||||
<h3>按地点看资产分布</h3>
|
||||
<p>适合从 Earth System / Mars System 角度看当前部署。</p>
|
||||
</a>
|
||||
<a class="link-card" href="./asset-log.html">
|
||||
<strong>Asset Log</strong>
|
||||
<h3>进入单个资产日志</h3>
|
||||
<p>查看某个站、舰船、基地完整的事件和状态演变。</p>
|
||||
</a>
|
||||
<a class="link-card" href="./timeline-view.html">
|
||||
<strong>Timeline View</strong>
|
||||
<h3>多资产并行时间线</h3>
|
||||
<p>在时间范围内看多个关键资产的联动关系。</p>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<aside class="stack">
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Recent Past</p>
|
||||
<h2>最近发生的事件</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upcoming-list" id="recent-past-events">
|
||||
<article class="upcoming-item">
|
||||
<time>Loading...</time>
|
||||
<h3>Preparing recent events</h3>
|
||||
<p class="subtle">This feed will update relative to the selected clock.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Upcoming</p>
|
||||
<h2>接下来将发生的事件</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upcoming-list" id="recent-future-events">
|
||||
<article class="upcoming-item">
|
||||
<time>Loading...</time>
|
||||
<h3>Preparing future events</h3>
|
||||
<p class="subtle">This feed will update relative to the selected clock.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Control Notes</p>
|
||||
<h2>任务中心的设计原则</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-list subtle">
|
||||
<p>首页应该先回答“当前要盯什么”,而不是“系统里有几页”。</p>
|
||||
<p>当前运行任务和待处理事项应占据主舞台。</p>
|
||||
<p>过去与未来事件保留在右侧,作为辅助判断时间上下文的侧栏。</p>
|
||||
<p>四个详细页面退到工作面板入口,符合 Mission Control 的使用习惯。</p>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
</section>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,260 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Location Board Prototype</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body data-page="location-board">
|
||||
<div class="site-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-kicker">Mission Ops Prototype</span>
|
||||
<span class="brand-name">Location Board</span>
|
||||
</a>
|
||||
<nav class="topbar-nav">
|
||||
<a href="./index.html">Overview</a>
|
||||
<a href="./status-board.html">Status Board</a>
|
||||
<a class="active" href="./location-board.html">Location Board</a>
|
||||
<a href="./asset-log.html">Asset Log</a>
|
||||
<a href="./timeline-view.html">Timeline View</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Location-first Board</p>
|
||||
<h1>按地点分组看每个系统当前都聚集了什么资产</h1>
|
||||
<p>这张板子和 Status Board 是并列关系,不是一个页面里的切换模式。它更适合回答“Earth System 现在有什么、Mars System 现在有什么”。</p>
|
||||
</div>
|
||||
<div class="hero-side">
|
||||
<section class="time-card">
|
||||
<span class="label">Simulation Time</span>
|
||||
<p class="time-value" data-sim-time-display>2060-03-12 09:00</p>
|
||||
<p class="hero-note">Grouping is based on current location hierarchy. Status still appears on each card so the operational meaning remains visible.</p>
|
||||
</section>
|
||||
<div class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Location Groups</span>
|
||||
<strong class="metric-value">4</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Earth System</span>
|
||||
<strong class="metric-value">3</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Mars System</span>
|
||||
<strong class="metric-value">2</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel toolbar">
|
||||
<div class="toolbar-row">
|
||||
<label class="clock-field">
|
||||
<span class="eyebrow">Simulation Time</span>
|
||||
<input type="datetime-local" data-sim-time-input>
|
||||
</label>
|
||||
<button class="ghost-button" type="button" data-time-shift="-30">- 30d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="-7">- 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="7">+ 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="30">+ 30d</button>
|
||||
</div>
|
||||
<div class="toolbar-grid">
|
||||
<label>
|
||||
<span class="eyebrow">Location Layer</span>
|
||||
<select>
|
||||
<option>Top-level Systems</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Status Filter</span>
|
||||
<select>
|
||||
<option>All Active States</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Asset Type</span>
|
||||
<select>
|
||||
<option>All Asset Types</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Visibility</span>
|
||||
<select>
|
||||
<option>Confirmed + Planned</option>
|
||||
</select>
|
||||
</label>
|
||||
<span class="button">Apply</span>
|
||||
<span class="ghost-button">Reset</span>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
<span class="pill">Grouping: Location hierarchy</span>
|
||||
<span class="pill">Status preserved on each asset card</span>
|
||||
<span class="pill">Supports Station, Port, Surface Site later</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="split-layout">
|
||||
<main class="stack">
|
||||
<section class="panel stack">
|
||||
<div class="location-head">
|
||||
<div>
|
||||
<p class="eyebrow">Location Group</p>
|
||||
<h2>Earth System</h2>
|
||||
<p>Ports, orbital stations, and near-Earth transfer lanes.</p>
|
||||
</div>
|
||||
<span class="count-badge">3 Assets</span>
|
||||
</div>
|
||||
<div class="location-grid">
|
||||
<article class="location-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Lingxiao Station</h3>
|
||||
<p class="asset-type">Station</p>
|
||||
</div>
|
||||
<span class="status-pill">Docked / On Station</span>
|
||||
</div>
|
||||
<p class="summary-text">Low Kerbin Orbit. Continuous habitation and logistics hub.</p>
|
||||
<div class="location-foot">
|
||||
<span>Next: Expedition 16 Arrival · 2060-03-30</span>
|
||||
<span>Current crew handover prep</span>
|
||||
</div>
|
||||
</article>
|
||||
<article class="location-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>XH-03 Zhuque</h3>
|
||||
<p class="asset-type">Shuttle</p>
|
||||
</div>
|
||||
<span class="status-pill">At Port</span>
|
||||
</div>
|
||||
<p class="summary-text">Star Port. Refit phase for Jupiter relay deployment mission.</p>
|
||||
<div class="location-foot">
|
||||
<span>Next: Rollout Review · 2060-04-12</span>
|
||||
<span>Bay 4</span>
|
||||
</div>
|
||||
</article>
|
||||
<article class="location-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Amalthea Crew Vehicle 4</h3>
|
||||
<p class="asset-type">Shuttle</p>
|
||||
</div>
|
||||
<span class="status-pill">In Transit</span>
|
||||
</div>
|
||||
<p class="summary-text">LKO transfer corridor. Planned crew rotation for Lingxiao Station.</p>
|
||||
<div class="location-foot">
|
||||
<span>Next: Docking Window · 2060-03-30</span>
|
||||
<span>10 crew manifest</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="location-head">
|
||||
<div>
|
||||
<p class="eyebrow">Location Group</p>
|
||||
<h2>Mars System</h2>
|
||||
<p>Orbital operations and deployed surface infrastructure around Mars.</p>
|
||||
</div>
|
||||
<span class="count-badge">2 Assets</span>
|
||||
</div>
|
||||
<div class="location-grid">
|
||||
<article class="location-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Mars One Campus Alpha</h3>
|
||||
<p class="asset-type">Surface Outpost</p>
|
||||
</div>
|
||||
<span class="status-pill">Surface Ops</span>
|
||||
</div>
|
||||
<p class="summary-text">Primary surface site. Habitat expansion, ISRU staging, and logistics intake point.</p>
|
||||
<div class="location-foot">
|
||||
<span>Next: Taibai Supply Window · 2060-03-29</span>
|
||||
<span>Needs truss + greenhouse kit</span>
|
||||
</div>
|
||||
</article>
|
||||
<article class="location-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>XH-02 Taibai</h3>
|
||||
<p class="asset-type">Exploration Mothership</p>
|
||||
</div>
|
||||
<span class="status-pill">In Transit</span>
|
||||
</div>
|
||||
<p class="summary-text">Mars transfer lane. Support mission inbound for Mars One Campus surface expansion.</p>
|
||||
<div class="location-foot">
|
||||
<span>Next: Mars Arrival · 2060-03-29</span>
|
||||
<span>31-day transfer</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="location-head">
|
||||
<div>
|
||||
<p class="eyebrow">Location Group</p>
|
||||
<h2>Deep Space / Future Hooks</h2>
|
||||
<p>Reserved for future hierarchy like Jupiter System, relay chains, and transit corridors.</p>
|
||||
</div>
|
||||
<span class="count-badge">Prototype Placeholder</span>
|
||||
</div>
|
||||
<div class="warning-list subtle">
|
||||
<article class="warning-item">
|
||||
<strong>Location hierarchy will matter</strong>
|
||||
Earth, Star Port, Low Kerbin Orbit, Lingxiao Station should eventually form a parent-child location structure.
|
||||
</article>
|
||||
<article class="warning-item">
|
||||
<strong>Facilities are first-class assets</strong>
|
||||
Stations, ports, and surface outposts appear here exactly like ships, which is why the model must be Asset-first.
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<aside class="stack">
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Interpretation</p>
|
||||
<h2>Board Reading Notes</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-list subtle">
|
||||
<p>这张板子优先回答“地点上现在有什么”,不是“资产现在什么状态”。</p>
|
||||
<p>状态信息仍然保留在卡片右上角,避免地点视图失去任务语义。</p>
|
||||
<p>层级地点会在正式开发里成为关键模型,而不是临时筛选项。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Upcoming</p>
|
||||
<h2>Upcoming Mars-side Events</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upcoming-list">
|
||||
<article class="upcoming-item">
|
||||
<time>2060-03-29</time>
|
||||
<h3>XH-02 Taibai Mars Arrival</h3>
|
||||
<p class="subtle">Mars System</p>
|
||||
</article>
|
||||
<article class="upcoming-item">
|
||||
<time>2060-04-03</time>
|
||||
<h3>Campus Alpha Structural Unload</h3>
|
||||
<p class="subtle">Mars Surface</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+629
@@ -0,0 +1,629 @@
|
||||
const SIM_TIME_STORAGE_KEY = "mission-ops-sim-time";
|
||||
const DEFAULT_SIM_TIME = "2060-03-12T09:00";
|
||||
|
||||
const OVERVIEW_EVENTS = [
|
||||
{ when: "2059-12-27 09:00", title: "XH-02 Taibai parked to Star Port", scope: "Earth System" },
|
||||
{ when: "2059-12-27 12:00", title: "Mars Expedition 1 crew returned to Earth", scope: "Earth System" },
|
||||
{ when: "2060-02-26 06:00", title: "XH-02 Taibai departed Star Port for Mars support mission", scope: "Earth System" },
|
||||
{ when: "2060-03-18 10:00", title: "Tianhe Cargo Pod 7 undock from Lingxiao Station", scope: "Lingxiao Station" },
|
||||
{ when: "2060-03-29 18:00", title: "XH-02 Taibai arrives at Mars", scope: "Mars System" },
|
||||
{ when: "2060-03-30 08:00", title: "Expedition 16 crew arrives via Amalthea Crew Vehicle", scope: "Lingxiao Station" },
|
||||
{ when: "2060-04-02 09:00", title: "Expedition 15 crew departs Lingxiao Station", scope: "Lingxiao Station" },
|
||||
{ when: "2060-04-12 14:00", title: "XH-03 Zhuque rollout review", scope: "Star Port" },
|
||||
].map((event) => ({
|
||||
...event,
|
||||
date: parseDateTime(event.when),
|
||||
}));
|
||||
|
||||
const OVERVIEW_ACTIVE_OPERATIONS = [
|
||||
{
|
||||
asset: "XH-02 Taibai",
|
||||
assetType: "Exploration Mothership",
|
||||
location: "Earth to Mars Transfer",
|
||||
mission: "Support Mars One Campus",
|
||||
start: "2060-02-26T06:00",
|
||||
end: "2060-03-29T18:00",
|
||||
next: "Mars Arrival · 2060-03-29 18:00",
|
||||
note: "Carrying structural truss, greenhouse kit, and support cargo.",
|
||||
},
|
||||
{
|
||||
asset: "Lingxiao Station",
|
||||
assetType: "Station",
|
||||
location: "Low Kerbin Orbit",
|
||||
mission: "Continuous habitation and logistics hub",
|
||||
start: "2059-07-23T00:00",
|
||||
end: "",
|
||||
next: "Expedition 16 Arrival · 2060-03-30 08:00",
|
||||
note: "Crew handover preparation and consumables balancing in progress.",
|
||||
},
|
||||
{
|
||||
asset: "Tianhe Cargo Pod 7",
|
||||
assetType: "Cargo Shuttle",
|
||||
location: "Lingxiao Forward Berth",
|
||||
mission: "Dry cargo replenishment",
|
||||
start: "2060-03-01T12:00",
|
||||
end: "2060-03-18T10:00",
|
||||
next: "Undock · 2060-03-18 10:00",
|
||||
note: "Return trash loading remains before departure.",
|
||||
},
|
||||
{
|
||||
asset: "XH-03 Zhuque",
|
||||
assetType: "Shuttle",
|
||||
location: "Star Port",
|
||||
mission: "Jupiter relay refit",
|
||||
start: "2060-01-08T09:00",
|
||||
end: "2060-04-12T14:00",
|
||||
next: "Rollout Review · 2060-04-12 14:00",
|
||||
note: "Main engine refurbishment at bay 4 and payload integration queued.",
|
||||
},
|
||||
{
|
||||
asset: "Mars One Campus Alpha",
|
||||
assetType: "Surface Outpost",
|
||||
location: "Mars Surface",
|
||||
mission: "Habitat expansion and ISRU staging",
|
||||
start: "2059-10-20T08:00",
|
||||
end: "",
|
||||
next: "Taibai Supply Window · 2060-03-29 18:00",
|
||||
note: "Awaiting new structural truss and greenhouse package delivery.",
|
||||
},
|
||||
];
|
||||
|
||||
const OVERVIEW_ATTENTION_ITEMS = [
|
||||
{
|
||||
title: "Review Tianhe Cargo Pod 7 undock checklist",
|
||||
asset: "Tianhe Cargo Pod 7",
|
||||
priority: "high",
|
||||
due: "2060-03-18T10:00",
|
||||
summary: "Finalize return trash manifest and station berth reconfiguration.",
|
||||
},
|
||||
{
|
||||
title: "Finalize Expedition 16 docking prep",
|
||||
asset: "Lingxiao Station",
|
||||
priority: "high",
|
||||
due: "2060-03-26T18:00",
|
||||
summary: "Confirm medical bay allocation, handover timeline, and EVA support window.",
|
||||
},
|
||||
{
|
||||
title: "Prepare XH-02 Taibai Mars arrival burn package",
|
||||
asset: "XH-02 Taibai",
|
||||
priority: "high",
|
||||
due: "2060-03-29T18:00",
|
||||
summary: "Review capture burn, cargo handoff staging, and surface drop order.",
|
||||
},
|
||||
{
|
||||
title: "Approve XH-03 Zhuque rollout readiness package",
|
||||
asset: "XH-03 Zhuque",
|
||||
priority: "medium",
|
||||
due: "2060-04-12T14:00",
|
||||
summary: "Complete avionics validation and relay payload handling plan.",
|
||||
},
|
||||
];
|
||||
|
||||
const TIMELINE_ASSET_CATALOG = [
|
||||
{ id: "taibai", name: "XH-02 Taibai", type: "Exploration Mothership", region: "Mars System", note: "Mars support transfer" },
|
||||
{ id: "lingxiao", name: "Lingxiao Station", type: "Station", region: "Earth System", note: "Crew rotation hub" },
|
||||
{ id: "campus-alpha", name: "Mars One Campus Alpha", type: "Surface Outpost", region: "Mars System", note: "Surface habitat expansion" },
|
||||
{ id: "amalthea-4", name: "Amalthea Crew Vehicle 4", type: "Shuttle", region: "Earth System", note: "Crew rotation shuttle" },
|
||||
{ id: "zhuque", name: "XH-03 Zhuque", type: "Shuttle", region: "Earth System", note: "Relay deployment refit" },
|
||||
{ id: "tianhe-7", name: "Tianhe Cargo Pod 7", type: "Cargo Shuttle", region: "Earth System", note: "Station logistics shuttle" },
|
||||
];
|
||||
|
||||
const TIMELINE_PRESETS = {
|
||||
active: ["taibai", "lingxiao", "campus-alpha"],
|
||||
earth: ["lingxiao", "amalthea-4", "zhuque", "tianhe-7"],
|
||||
mars: ["taibai", "campus-alpha"],
|
||||
crew: ["lingxiao", "amalthea-4", "taibai"],
|
||||
};
|
||||
|
||||
let selectedTimelineAssets = new Set(["taibai", "lingxiao", "campus-alpha"]);
|
||||
|
||||
function parseDateTime(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.includes("T") ? value : value.replace(" ", "T");
|
||||
const parsed = new Date(normalized);
|
||||
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
||||
}
|
||||
|
||||
function padNumber(value) {
|
||||
return String(value).padStart(2, "0");
|
||||
}
|
||||
|
||||
function toInputValue(date) {
|
||||
return [
|
||||
date.getFullYear(),
|
||||
"-",
|
||||
padNumber(date.getMonth() + 1),
|
||||
"-",
|
||||
padNumber(date.getDate()),
|
||||
"T",
|
||||
padNumber(date.getHours()),
|
||||
":",
|
||||
padNumber(date.getMinutes()),
|
||||
].join("");
|
||||
}
|
||||
|
||||
function toDisplayValue(date) {
|
||||
return [
|
||||
date.getFullYear(),
|
||||
"-",
|
||||
padNumber(date.getMonth() + 1),
|
||||
"-",
|
||||
padNumber(date.getDate()),
|
||||
" ",
|
||||
padNumber(date.getHours()),
|
||||
":",
|
||||
padNumber(date.getMinutes()),
|
||||
].join("");
|
||||
}
|
||||
|
||||
function toShortDate(date) {
|
||||
return [padNumber(date.getMonth() + 1), "-", padNumber(date.getDate())].join("");
|
||||
}
|
||||
|
||||
function shiftDays(date, dayOffset) {
|
||||
const nextDate = new Date(date);
|
||||
nextDate.setDate(nextDate.getDate() + dayOffset);
|
||||
return nextDate;
|
||||
}
|
||||
|
||||
function formatRelativeDayLabel(simDate, targetDate) {
|
||||
const dayDelta = Math.round((targetDate - simDate) / (1000 * 60 * 60 * 24));
|
||||
if (dayDelta < 0) {
|
||||
return `${Math.abs(dayDelta)}d ago`;
|
||||
}
|
||||
if (dayDelta === 0) {
|
||||
return "Today";
|
||||
}
|
||||
return `in ${dayDelta}d`;
|
||||
}
|
||||
|
||||
function renderEventFeed(container, events, emptyLabel) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!events.length) {
|
||||
container.innerHTML = `
|
||||
<article class="upcoming-item">
|
||||
<time>No events</time>
|
||||
<h3>${emptyLabel}</h3>
|
||||
<p class="subtle">Change the simulation time to inspect a different period.</p>
|
||||
</article>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = events
|
||||
.map(
|
||||
(event) => `
|
||||
<article class="upcoming-item">
|
||||
<time>${event.when}</time>
|
||||
<h3>${event.title}</h3>
|
||||
<p class="subtle">${event.scope}</p>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderOverviewOperations(simDate) {
|
||||
const container = document.getElementById("active-ops-list");
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeOperations = OVERVIEW_ACTIVE_OPERATIONS.filter((item) => {
|
||||
const start = parseDateTime(item.start);
|
||||
const end = parseDateTime(item.end || "");
|
||||
return start && start <= simDate && (!end || simDate < end);
|
||||
});
|
||||
|
||||
if (!activeOperations.length) {
|
||||
container.innerHTML = `
|
||||
<article class="ops-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>No active operations</h3>
|
||||
<p class="asset-type">No State Interval covers the selected clock</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = activeOperations
|
||||
.map(
|
||||
(item) => `
|
||||
<article class="ops-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>${item.asset}</h3>
|
||||
<p class="asset-type">${item.assetType}</p>
|
||||
</div>
|
||||
<span class="status-pill">${item.location}</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>${item.mission}</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>${item.next}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">${item.note}</p>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderAttentionQueue(simDate) {
|
||||
const container = document.getElementById("attention-queue-list");
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const queueItems = OVERVIEW_ATTENTION_ITEMS
|
||||
.map((item) => ({ ...item, dueDate: parseDateTime(item.due) }))
|
||||
.filter((item) => item.dueDate && item.dueDate >= shiftDays(simDate, -7))
|
||||
.sort((left, right) => left.dueDate - right.dueDate)
|
||||
.slice(0, 4);
|
||||
|
||||
if (!queueItems.length) {
|
||||
container.innerHTML = `
|
||||
<article class="attention-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>No pending queue items</h3>
|
||||
<p class="asset-type">Nothing falls into the current operational window</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = queueItems
|
||||
.map((item) => {
|
||||
const priorityClass = item.dueDate < simDate ? "overdue" : item.priority;
|
||||
const priorityLabel = item.dueDate < simDate ? "Overdue" : item.priority;
|
||||
return `
|
||||
<article class="attention-item">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>${item.title}</h3>
|
||||
<p class="asset-type">${item.asset}</p>
|
||||
</div>
|
||||
<span class="priority-chip ${priorityClass}">${priorityLabel}</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Due</dt>
|
||||
<dd>${toDisplayValue(item.dueDate)}</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Relative</dt>
|
||||
<dd>${formatRelativeDayLabel(simDate, item.dueDate)}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">${item.summary}</p>
|
||||
</article>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
function updateOverview(simDate) {
|
||||
if (document.body.dataset.page !== "overview") {
|
||||
return;
|
||||
}
|
||||
|
||||
const pastEvents = OVERVIEW_EVENTS
|
||||
.filter((event) => event.date && event.date <= simDate)
|
||||
.sort((left, right) => right.date - left.date)
|
||||
.slice(0, 4)
|
||||
.map((event) => ({ ...event, when: toDisplayValue(event.date) }));
|
||||
|
||||
const futureEvents = OVERVIEW_EVENTS
|
||||
.filter((event) => event.date && event.date > simDate)
|
||||
.sort((left, right) => left.date - right.date)
|
||||
.slice(0, 4)
|
||||
.map((event) => ({ ...event, when: toDisplayValue(event.date) }));
|
||||
|
||||
renderOverviewOperations(simDate);
|
||||
renderAttentionQueue(simDate);
|
||||
renderEventFeed(document.getElementById("recent-past-events"), pastEvents, "No recent past events");
|
||||
renderEventFeed(document.getElementById("recent-future-events"), futureEvents, "No upcoming events");
|
||||
}
|
||||
|
||||
function updateAssetLog(simDate) {
|
||||
if (document.body.dataset.page !== "asset-log") {
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = Array.from(document.querySelectorAll(".entry[data-start]"));
|
||||
let currentStateEntry = null;
|
||||
let nextEventEntry = null;
|
||||
|
||||
entries.forEach((entry) => {
|
||||
const badge = entry.querySelector("[data-entry-badge]");
|
||||
const start = parseDateTime(entry.dataset.start);
|
||||
const end = parseDateTime(entry.dataset.end || "");
|
||||
const kind = entry.dataset.kind;
|
||||
|
||||
if (!badge || !start) {
|
||||
return;
|
||||
}
|
||||
|
||||
badge.classList.remove("completed", "planned", "active");
|
||||
|
||||
if (kind === "state") {
|
||||
if (start <= simDate && (!end || simDate < end)) {
|
||||
badge.textContent = "Current Interval";
|
||||
badge.classList.add("active");
|
||||
currentStateEntry = entry;
|
||||
} else if (simDate < start) {
|
||||
badge.textContent = "Upcoming Interval";
|
||||
badge.classList.add("planned");
|
||||
} else {
|
||||
badge.textContent = "Past Interval";
|
||||
badge.classList.add("completed");
|
||||
}
|
||||
} else if (simDate < start) {
|
||||
badge.textContent = "Upcoming Event";
|
||||
badge.classList.add("planned");
|
||||
} else {
|
||||
badge.textContent = "Past Event";
|
||||
badge.classList.add("completed");
|
||||
}
|
||||
|
||||
if (start > simDate && (!nextEventEntry || start < parseDateTime(nextEventEntry.dataset.start))) {
|
||||
nextEventEntry = entry;
|
||||
}
|
||||
});
|
||||
|
||||
const currentStateText = document.querySelector("[data-current-state]");
|
||||
const currentStatePill = document.querySelector("[data-current-state-pill]");
|
||||
const currentLocation = document.querySelector("[data-current-location]");
|
||||
const currentWindow = document.querySelector("[data-current-window]");
|
||||
const nextEventText = document.querySelector("[data-next-event]");
|
||||
const nextEventShort = document.querySelector("[data-next-event-short]");
|
||||
const nextEventDate = document.querySelector("[data-next-event-date]");
|
||||
const currentDuration = document.querySelector("[data-current-duration]");
|
||||
const relativeMode = document.querySelector("[data-relative-mode]");
|
||||
|
||||
if (currentStateEntry) {
|
||||
const start = parseDateTime(currentStateEntry.dataset.start);
|
||||
const end = parseDateTime(currentStateEntry.dataset.end || "");
|
||||
const stateLabel = currentStateEntry.dataset.stateLabel || currentStateEntry.dataset.title;
|
||||
if (currentStateText) currentStateText.textContent = stateLabel;
|
||||
if (currentStatePill) currentStatePill.textContent = stateLabel;
|
||||
if (currentLocation) currentLocation.textContent = currentStateEntry.dataset.location || "Unknown";
|
||||
if (currentWindow) currentWindow.textContent = `${toDisplayValue(start)} → ${end ? toDisplayValue(end) : "Open"}`;
|
||||
if (currentDuration && end) {
|
||||
const totalDays = Math.round((end - start) / (1000 * 60 * 60 * 24));
|
||||
currentDuration.textContent = `${totalDays} days`;
|
||||
}
|
||||
if (relativeMode) relativeMode.textContent = "Derived from active State Interval";
|
||||
} else {
|
||||
if (currentStateText) currentStateText.textContent = "No Active Interval";
|
||||
if (currentStatePill) currentStatePill.textContent = "No Active Interval";
|
||||
if (currentLocation) currentLocation.textContent = "Unknown";
|
||||
if (currentWindow) currentWindow.textContent = "No interval covers selected time";
|
||||
if (currentDuration) currentDuration.textContent = "-";
|
||||
if (relativeMode) relativeMode.textContent = "Derived: no active interval at selected time";
|
||||
}
|
||||
|
||||
if (nextEventEntry) {
|
||||
const nextDate = parseDateTime(nextEventEntry.dataset.start);
|
||||
const nextLabel = `${nextEventEntry.dataset.title} · ${toDisplayValue(nextDate)}`;
|
||||
if (nextEventText) nextEventText.textContent = nextLabel;
|
||||
if (nextEventShort) nextEventShort.textContent = toDisplayValue(nextDate);
|
||||
if (nextEventDate) nextEventDate.textContent = toShortDate(nextDate);
|
||||
} else {
|
||||
if (nextEventText) nextEventText.textContent = "No future event recorded";
|
||||
if (nextEventShort) nextEventShort.textContent = "-";
|
||||
if (nextEventDate) nextEventDate.textContent = "-";
|
||||
}
|
||||
}
|
||||
|
||||
function getTimelineFilteredAssets() {
|
||||
const searchInput = document.querySelector("[data-asset-search]");
|
||||
const typeFilter = document.querySelector("[data-asset-type-filter]");
|
||||
const regionFilter = document.querySelector("[data-asset-region-filter]");
|
||||
const searchTerm = (searchInput?.value || "").trim().toLowerCase();
|
||||
const selectedType = typeFilter?.value || "all";
|
||||
const selectedRegion = regionFilter?.value || "all";
|
||||
|
||||
return TIMELINE_ASSET_CATALOG.filter((asset) => {
|
||||
const matchesSearch = !searchTerm || `${asset.name} ${asset.type} ${asset.region} ${asset.note}`.toLowerCase().includes(searchTerm);
|
||||
const matchesType = selectedType === "all" || asset.type === selectedType;
|
||||
const matchesRegion = selectedRegion === "all" || asset.region === selectedRegion;
|
||||
return matchesSearch && matchesType && matchesRegion;
|
||||
});
|
||||
}
|
||||
|
||||
function updateTimelineSelection() {
|
||||
if (document.body.dataset.page !== "timeline") {
|
||||
return;
|
||||
}
|
||||
|
||||
const rows = Array.from(document.querySelectorAll(".timeline-row[data-asset]"));
|
||||
const selectedAssets = Array.from(selectedTimelineAssets);
|
||||
const selectedNames = TIMELINE_ASSET_CATALOG.filter((asset) => selectedTimelineAssets.has(asset.id)).map((asset) => asset.name);
|
||||
|
||||
rows.forEach((row) => {
|
||||
row.classList.toggle("is-hidden", !selectedAssets.includes(row.dataset.asset));
|
||||
});
|
||||
|
||||
const selectedCount = document.querySelector("[data-selected-count]");
|
||||
const selectedSummary = document.querySelector("[data-selected-assets]");
|
||||
|
||||
if (selectedCount) {
|
||||
selectedCount.textContent = String(selectedAssets.length);
|
||||
}
|
||||
|
||||
if (selectedSummary) {
|
||||
selectedSummary.textContent = selectedNames.length ? `Selected: ${selectedNames.join(", ")}` : "Selected: none";
|
||||
}
|
||||
}
|
||||
|
||||
function renderTimelineSelector() {
|
||||
if (document.body.dataset.page !== "timeline") {
|
||||
return;
|
||||
}
|
||||
|
||||
const resultsContainer = document.querySelector("[data-asset-results]");
|
||||
const selectedContainer = document.querySelector("[data-selected-asset-list]");
|
||||
if (!resultsContainer || !selectedContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredAssets = getTimelineFilteredAssets();
|
||||
const selectedAssetsData = TIMELINE_ASSET_CATALOG.filter((asset) => selectedTimelineAssets.has(asset.id));
|
||||
|
||||
resultsContainer.innerHTML = filteredAssets.length
|
||||
? filteredAssets
|
||||
.map(
|
||||
(asset) => `
|
||||
<article class="asset-result-card">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>${asset.name}</h3>
|
||||
<p class="asset-type">${asset.type}</p>
|
||||
</div>
|
||||
<span class="status-pill">${asset.region}</span>
|
||||
</div>
|
||||
<p class="summary-text">${asset.note}</p>
|
||||
<div class="asset-result-foot">
|
||||
<span>${selectedTimelineAssets.has(asset.id) ? "Already selected" : "Available to add"}</span>
|
||||
<button class="selector-add" type="button" data-add-asset="${asset.id}" ${selectedTimelineAssets.has(asset.id) ? "disabled" : ""}>${selectedTimelineAssets.has(asset.id) ? "Added" : "Add to Timeline"}</button>
|
||||
</div>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
.join("")
|
||||
: `
|
||||
<article class="asset-result-card">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>No matching assets</h3>
|
||||
<p class="asset-type">Try another search or filter combination</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
|
||||
selectedContainer.innerHTML = selectedAssetsData.length
|
||||
? selectedAssetsData
|
||||
.map(
|
||||
(asset) => `
|
||||
<article class="selected-asset-card">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>${asset.name}</h3>
|
||||
<p class="asset-type">${asset.type}</p>
|
||||
</div>
|
||||
<span class="status-pill">${asset.region}</span>
|
||||
</div>
|
||||
<div class="selected-asset-foot">
|
||||
<span>${asset.note}</span>
|
||||
<button class="selector-remove" type="button" data-remove-asset="${asset.id}">Remove</button>
|
||||
</div>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
.join("")
|
||||
: `
|
||||
<article class="selected-asset-card">
|
||||
<strong>No assets selected</strong>
|
||||
<p class="summary-text">Add assets from the search results to build the current timeline focus set.</p>
|
||||
</article>
|
||||
`;
|
||||
|
||||
resultsContainer.querySelectorAll("[data-add-asset]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
selectedTimelineAssets.add(button.dataset.addAsset);
|
||||
renderTimelineSelector();
|
||||
updateTimelineSelection();
|
||||
});
|
||||
});
|
||||
|
||||
selectedContainer.querySelectorAll("[data-remove-asset]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
selectedTimelineAssets.delete(button.dataset.removeAsset);
|
||||
renderTimelineSelector();
|
||||
updateTimelineSelection();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setupTimelineSelection() {
|
||||
if (document.body.dataset.page !== "timeline") {
|
||||
return;
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-asset-search], [data-asset-type-filter], [data-asset-region-filter]").forEach((control) => {
|
||||
control.addEventListener(control.tagName === "INPUT" ? "input" : "change", renderTimelineSelector);
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-asset-preset]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
selectedTimelineAssets = new Set(TIMELINE_PRESETS[button.dataset.assetPreset] || []);
|
||||
renderTimelineSelector();
|
||||
updateTimelineSelection();
|
||||
});
|
||||
});
|
||||
|
||||
renderTimelineSelector();
|
||||
updateTimelineSelection();
|
||||
}
|
||||
|
||||
function syncSimulationTime(simDate) {
|
||||
const inputValue = toInputValue(simDate);
|
||||
const displayValue = toDisplayValue(simDate);
|
||||
|
||||
document.querySelectorAll("[data-sim-time-input]").forEach((input) => {
|
||||
if (input.value !== inputValue) {
|
||||
input.value = inputValue;
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-sim-time-display]").forEach((display) => {
|
||||
display.textContent = displayValue;
|
||||
});
|
||||
|
||||
localStorage.setItem(SIM_TIME_STORAGE_KEY, inputValue);
|
||||
updateOverview(simDate);
|
||||
updateAssetLog(simDate);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let simDate = parseDateTime(localStorage.getItem(SIM_TIME_STORAGE_KEY)) || parseDateTime(DEFAULT_SIM_TIME);
|
||||
|
||||
document.querySelectorAll("[data-sim-time-input]").forEach((input) => {
|
||||
input.addEventListener("input", (event) => {
|
||||
const nextDate = parseDateTime(event.target.value);
|
||||
if (!nextDate) {
|
||||
return;
|
||||
}
|
||||
simDate = nextDate;
|
||||
syncSimulationTime(simDate);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-time-shift]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
simDate = shiftDays(simDate, Number(button.dataset.timeShift));
|
||||
syncSimulationTime(simDate);
|
||||
});
|
||||
});
|
||||
|
||||
syncSimulationTime(simDate);
|
||||
setupTimelineSelection();
|
||||
});
|
||||
@@ -0,0 +1,398 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Status Board Prototype</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body data-page="status-board">
|
||||
<div class="site-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-kicker">Mission Ops Prototype</span>
|
||||
<span class="brand-name">Status Board</span>
|
||||
</a>
|
||||
<nav class="topbar-nav">
|
||||
<a href="./index.html">Overview</a>
|
||||
<a class="active" href="./status-board.html">Status Board</a>
|
||||
<a href="./location-board.html">Location Board</a>
|
||||
<a href="./asset-log.html">Asset Log</a>
|
||||
<a href="./timeline-view.html">Timeline View</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Current State Board</p>
|
||||
<h1>按状态分组看当前有哪些资产在执行什么任务</h1>
|
||||
<p>这个页面只回答一件事:在当前 Simulation Time 下,每个 Asset 正处于哪个状态、在哪里、在做什么,以及下一个关键事件是什么。</p>
|
||||
</div>
|
||||
<div class="hero-side">
|
||||
<section class="time-card">
|
||||
<span class="label">Simulation Time</span>
|
||||
<p class="time-value" data-sim-time-display>2060-03-12 09:00</p>
|
||||
<p class="hero-note">Current status is derived from active State Interval. Planned events remain visible on the board.</p>
|
||||
</section>
|
||||
<div class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Active Assets</span>
|
||||
<strong class="metric-value">8</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">In Transit</span>
|
||||
<strong class="metric-value">2</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Upcoming 7d</span>
|
||||
<strong class="metric-value">3</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel toolbar">
|
||||
<div class="toolbar-row">
|
||||
<label class="clock-field">
|
||||
<span class="eyebrow">Simulation Time</span>
|
||||
<input type="datetime-local" data-sim-time-input>
|
||||
</label>
|
||||
<button class="ghost-button" type="button" data-time-shift="-30">- 30d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="-7">- 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="7">+ 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="30">+ 30d</button>
|
||||
</div>
|
||||
<div class="toolbar-row">
|
||||
<span class="button">Set Simulation Time</span>
|
||||
</div>
|
||||
<div class="toolbar-grid">
|
||||
<label>
|
||||
<span class="eyebrow">Asset Type</span>
|
||||
<select>
|
||||
<option>All Asset Types</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Location Filter</span>
|
||||
<select>
|
||||
<option>Earth System</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Program</span>
|
||||
<select>
|
||||
<option>All Programs</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Records</span>
|
||||
<select>
|
||||
<option>Confirmed + Planned</option>
|
||||
</select>
|
||||
</label>
|
||||
<span class="button">Apply</span>
|
||||
<span class="ghost-button">Reset</span>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
<span class="pill">Grouping: Current State</span>
|
||||
<span class="pill">Location used as secondary filter</span>
|
||||
<span class="pill">Future planned events remain visible</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="split-layout">
|
||||
<main class="stack">
|
||||
<section class="panel stack">
|
||||
<div class="group-head">
|
||||
<div>
|
||||
<p class="eyebrow">State Group</p>
|
||||
<h2>In Transit</h2>
|
||||
<p>Assets currently travelling between systems or operational nodes.</p>
|
||||
</div>
|
||||
<span class="count-badge">2 Assets</span>
|
||||
</div>
|
||||
|
||||
<div class="group-stack">
|
||||
<article class="status-card blue">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>XH-02 Taibai</h3>
|
||||
<p class="asset-type">Exploration Mothership</p>
|
||||
</div>
|
||||
<span class="tone-pill active">Confirmed</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>Earth to Mars Transfer</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Support Mars One Campus</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2060-02-26 → 2060-03-29</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Mars Arrival · 2060-03-29</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">31-day transition carrying structural truss, greenhouse kit, and support consumables for Mars One Campus Alpha.</p>
|
||||
<div class="card-foot">
|
||||
<span>Derived from active State Interval</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="status-card amber">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Amalthea Crew Vehicle 4</h3>
|
||||
<p class="asset-type">Shuttle</p>
|
||||
</div>
|
||||
<span class="tone-pill planned">Planned</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>LKO Transfer Corridor</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Expedition 16 Crew Rotation</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2060-03-28 → 2060-03-30</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Docking Window · 2060-03-30</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">Planned departure with 10-crew manifest for Lingxiao Station rotation and medical cargo transfer.</p>
|
||||
<div class="card-foot">
|
||||
<span>Visible before execution because Planned stays on board</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="group-head">
|
||||
<div>
|
||||
<p class="eyebrow">State Group</p>
|
||||
<h2>Docked / On Station</h2>
|
||||
<p>Stationary orbital assets and docked support craft.</p>
|
||||
</div>
|
||||
<span class="count-badge">2 Assets</span>
|
||||
</div>
|
||||
|
||||
<div class="group-stack">
|
||||
<article class="status-card teal">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Lingxiao Station</h3>
|
||||
<p class="asset-type">Station</p>
|
||||
</div>
|
||||
<span class="tone-pill active">Active</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>Low Kerbin Orbit</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Continuous habitation and logistics hub</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2059-07-23 → Present</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Expedition 16 Crew Arrival · 2060-03-30</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">Expedition 15 currently onboard. Crew handover prep and life-support reserve balancing underway.</p>
|
||||
<div class="card-foot">
|
||||
<span>Can later host nested docked assets</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="status-card soft">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Tianhe Cargo Pod 7</h3>
|
||||
<p class="asset-type">Cargo Shuttle</p>
|
||||
</div>
|
||||
<span class="tone-pill completed">Confirmed</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>Lingxiao Forward Berth</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Dry cargo replenishment</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2060-03-01 → 2060-03-18</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Undock · 2060-03-18</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">Food, EVA packs, filter cartridges, and station spares are already unloaded. Return trash loading remains.</p>
|
||||
<div class="card-foot">
|
||||
<span>Useful test case for attached support craft</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack">
|
||||
<div class="group-head">
|
||||
<div>
|
||||
<p class="eyebrow">State Group</p>
|
||||
<h2>At Port / Surface Ops</h2>
|
||||
<p>Idle, refit, maintenance, and deployed surface infrastructure.</p>
|
||||
</div>
|
||||
<span class="count-badge">2 Assets</span>
|
||||
</div>
|
||||
|
||||
<div class="group-stack">
|
||||
<article class="status-card soft">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>XH-03 Zhuque</h3>
|
||||
<p class="asset-type">Shuttle</p>
|
||||
</div>
|
||||
<span class="tone-pill active">Confirmed</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>Star Port</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Refit for Jupiter relay deployment</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2060-01-08 → 2060-04-12</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Rollout Review · 2060-04-12</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">Main engine refurbishment at bay 4. Payload integration queued after avionics test completion.</p>
|
||||
<div class="card-foot">
|
||||
<span>Example of a non-flight operational state</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="status-card teal">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Mars One Campus Alpha</h3>
|
||||
<p class="asset-type">Surface Outpost</p>
|
||||
</div>
|
||||
<span class="tone-pill active">Active</span>
|
||||
</div>
|
||||
<dl class="meta-grid">
|
||||
<div class="meta-item">
|
||||
<dt>Location</dt>
|
||||
<dd>Mars Surface</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Mission</dt>
|
||||
<dd>Habitat expansion and ISRU staging</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>State Window</dt>
|
||||
<dd>2059-10-20 → Present</dd>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<dt>Next Event</dt>
|
||||
<dd>Taibai Supply Window · 2060-03-29</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="summary-text">Surface crew awaiting structural truss shipment, greenhouse package, and two new power skids.</p>
|
||||
<div class="card-foot">
|
||||
<span>Long-duration persistent state example</span>
|
||||
<span>Open asset log</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<aside class="stack">
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Upcoming</p>
|
||||
<h2>Upcoming Events</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upcoming-list">
|
||||
<article class="upcoming-item">
|
||||
<time>2060-03-18</time>
|
||||
<h3>Tianhe Cargo Pod 7 Undock</h3>
|
||||
<p class="subtle">Lingxiao Station</p>
|
||||
</article>
|
||||
<article class="upcoming-item">
|
||||
<time>2060-03-29</time>
|
||||
<h3>XH-02 Taibai Mars Arrival</h3>
|
||||
<p class="subtle">Mars System</p>
|
||||
</article>
|
||||
<article class="upcoming-item">
|
||||
<time>2060-03-30</time>
|
||||
<h3>Expedition 16 Crew Arrival</h3>
|
||||
<p class="subtle">Lingxiao Station</p>
|
||||
</article>
|
||||
<article class="upcoming-item">
|
||||
<time>2060-04-02</time>
|
||||
<h3>Expedition 15 Crew Departure</h3>
|
||||
<p class="subtle">Lingxiao Station</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Integrity</p>
|
||||
<h2>Warnings</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-list subtle">
|
||||
<article class="warning-item">
|
||||
<strong>No conflicts in current preview</strong>
|
||||
This is where overlapping State Intervals or missing end markers should appear later.
|
||||
</article>
|
||||
<article class="warning-item">
|
||||
<strong>Planned event visibility</strong>
|
||||
Status Board intentionally keeps future-planned events visible beside currently active states.
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,281 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Timeline View Prototype</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body data-page="timeline">
|
||||
<div class="site-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-kicker">Mission Ops Prototype</span>
|
||||
<span class="brand-name">Timeline View</span>
|
||||
</a>
|
||||
<nav class="topbar-nav">
|
||||
<a href="./index.html">Overview</a>
|
||||
<a href="./status-board.html">Status Board</a>
|
||||
<a href="./location-board.html">Location Board</a>
|
||||
<a href="./asset-log.html">Asset Log</a>
|
||||
<a class="active" href="./timeline-view.html">Timeline View</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Multi-Asset Range View</p>
|
||||
<h1>把多个资产在同一时间范围内的行为画到一张真正可读的时间线里</h1>
|
||||
<p>这里是甘特式原型。State Interval 用长条表示,Event Point 用节点表示,当前生效中的状态段会高亮。</p>
|
||||
</div>
|
||||
<div class="hero-side">
|
||||
<section class="time-card">
|
||||
<span class="label">Simulation Time</span>
|
||||
<p class="time-value" data-sim-time-display>2060-03-12 09:00</p>
|
||||
<p class="hero-note">Current active state segment is highlighted relative to 2060-03-12 09:00.</p>
|
||||
</section>
|
||||
<div class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Selected Assets</span>
|
||||
<strong class="metric-value" data-selected-count>3</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">State Segments</span>
|
||||
<strong class="metric-value">7</strong>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-label">Event Points</span>
|
||||
<strong class="metric-value">9</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel toolbar">
|
||||
<div class="toolbar-row">
|
||||
<label class="clock-field">
|
||||
<span class="eyebrow">Simulation Time</span>
|
||||
<input type="datetime-local" data-sim-time-input>
|
||||
</label>
|
||||
<button class="ghost-button" type="button" data-time-shift="-30">- 30d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="-7">- 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="7">+ 7d</button>
|
||||
<button class="ghost-button" type="button" data-time-shift="30">+ 30d</button>
|
||||
</div>
|
||||
<div class="toolbar-grid">
|
||||
<label>
|
||||
<span class="eyebrow">Start</span>
|
||||
<input type="text" value="2059-08-01 00:00">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">End</span>
|
||||
<input type="text" value="2060-03-31 23:59">
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Records</span>
|
||||
<select>
|
||||
<option>Completed + Planned</option>
|
||||
</select>
|
||||
</label>
|
||||
<span class="button">Apply</span>
|
||||
<span class="ghost-button">Export</span>
|
||||
</div>
|
||||
<div class="legend-row">
|
||||
<span class="legend-item"><span class="legend-swatch transit"></span>Transit</span>
|
||||
<span class="legend-item"><span class="legend-swatch ops"></span>Continuous Ops</span>
|
||||
<span class="legend-item"><span class="legend-swatch hold"></span>Hold / Port / Orbit</span>
|
||||
<span class="legend-item"><span class="legend-swatch current"></span>Current State Highlight</span>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
<span class="pill" data-selected-assets>Selected: XH-02 Taibai, Lingxiao Station, Mars One Campus Alpha</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel stack" style="margin-top: 16px;">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<p class="eyebrow">Asset Selection</p>
|
||||
<h2>用搜索、筛选和已选集合来组织 Timeline 对象</h2>
|
||||
<p>如果以后 Asset 很多,就不能把所有对象直接平铺出来。所以这里改成一个更接近“选择工作区”的原型。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selector-controls-grid">
|
||||
<label>
|
||||
<span class="eyebrow">Search Asset</span>
|
||||
<input type="search" placeholder="Search by asset name" data-asset-search>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">Asset Type</span>
|
||||
<select data-asset-type-filter>
|
||||
<option value="all">All Types</option>
|
||||
<option value="Exploration Mothership">Exploration Mothership</option>
|
||||
<option value="Station">Station</option>
|
||||
<option value="Surface Outpost">Surface Outpost</option>
|
||||
<option value="Shuttle">Shuttle</option>
|
||||
<option value="Cargo Shuttle">Cargo Shuttle</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="eyebrow">System / Region</span>
|
||||
<select data-asset-region-filter>
|
||||
<option value="all">All Regions</option>
|
||||
<option value="Earth System">Earth System</option>
|
||||
<option value="Mars System">Mars System</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="preset-chip-row">
|
||||
<button class="ghost-button selector-preset" type="button" data-asset-preset="active">Active Missions</button>
|
||||
<button class="ghost-button selector-preset" type="button" data-asset-preset="earth">Earth System</button>
|
||||
<button class="ghost-button selector-preset" type="button" data-asset-preset="mars">Mars System</button>
|
||||
<button class="ghost-button selector-preset" type="button" data-asset-preset="crew">Crew Logistics</button>
|
||||
</div>
|
||||
<div class="selector-layout">
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head compact-head">
|
||||
<div>
|
||||
<p class="eyebrow">Search Results</p>
|
||||
<h2>Matching Assets</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selector-results-list" data-asset-results>
|
||||
<article class="asset-result-card">
|
||||
<div class="card-top">
|
||||
<div>
|
||||
<h3>Loading asset search</h3>
|
||||
<p class="asset-type">Preparing searchable asset catalog</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mini-panel stack">
|
||||
<div class="section-head compact-head">
|
||||
<div>
|
||||
<p class="eyebrow">Selected Assets</p>
|
||||
<h2>Timeline Focus Set</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selected-assets-list" data-selected-asset-list>
|
||||
<article class="selected-asset-card">
|
||||
<strong>Loading selected assets</strong>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel timeline-panel" style="margin-top: 16px;">
|
||||
<div class="timeline-toolbar">
|
||||
<div>
|
||||
<p class="eyebrow">Timeline Canvas</p>
|
||||
<h2>Mission Flow Across Assets</h2>
|
||||
<p>每个 Asset 一条泳道,节点用于关键事件,条带用于持续状态。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-scroll">
|
||||
<div class="timeline-frame">
|
||||
<div class="timeline-scale">
|
||||
<div></div>
|
||||
<div class="timeline-scale-strip">
|
||||
<span>2059-08</span>
|
||||
<span>2059-09</span>
|
||||
<span>2059-10</span>
|
||||
<span>2059-11</span>
|
||||
<span>2059-12</span>
|
||||
<span>2060-01</span>
|
||||
<span>2060-02</span>
|
||||
<span>2060-03</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-rows">
|
||||
<div class="timeline-row" data-asset="taibai">
|
||||
<article class="timeline-row-label">
|
||||
<h3>XH-02 Taibai</h3>
|
||||
<p>Exploration Mothership</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment transit" style="grid-column: 6 / span 22;">Outbound Transfer</div>
|
||||
<div class="timeline-segment hold" style="grid-column: 29 / span 6;">Mars Orbit Standby</div>
|
||||
<div class="timeline-segment transit" style="grid-column: 38 / span 21;">Return Transfer</div>
|
||||
<div class="timeline-segment hold" style="grid-column: 61 / span 8;">Star Port Stay</div>
|
||||
<div class="timeline-segment transit current" style="grid-column: 73 / span 22;">Support Transit to Mars</div>
|
||||
|
||||
<div class="timeline-event" style="grid-column: 2;"><span>Commissioned</span></div>
|
||||
<div class="timeline-event" style="grid-column: 28;"><span>Mars Arrival</span></div>
|
||||
<div class="timeline-event" style="grid-column: 59;"><span>Earth Arrival</span></div>
|
||||
<div class="timeline-event" style="grid-column: 95;"><span>Next Mars Arrival</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-row" data-asset="lingxiao">
|
||||
<article class="timeline-row-label">
|
||||
<h3>Lingxiao Station</h3>
|
||||
<p>Station</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment ops current" style="grid-column: 1 / span 96;">Continuous Station Operations</div>
|
||||
|
||||
<div class="timeline-event" style="grid-column: 10;"><span>Crew 9 Arrival</span></div>
|
||||
<div class="timeline-event" style="grid-column: 62;"><span>Expedition 15 Arrival</span></div>
|
||||
<div class="timeline-event" style="grid-column: 88;"><span>Expedition 16 Arrival</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-row" data-asset="campus-alpha">
|
||||
<article class="timeline-row-label">
|
||||
<h3>Mars One Campus Alpha</h3>
|
||||
<p>Surface Outpost</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment ops" style="grid-column: 34 / span 62;">Surface Expansion and ISRU Staging</div>
|
||||
|
||||
<div class="timeline-event" style="grid-column: 37;"><span>First Crew Descent</span></div>
|
||||
<div class="timeline-event" style="grid-column: 95;"><span>Taibai Supply Window</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-row is-hidden" data-asset="amalthea-4">
|
||||
<article class="timeline-row-label">
|
||||
<h3>Amalthea Crew Vehicle 4</h3>
|
||||
<p>Shuttle</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment transit" style="grid-column: 84 / span 8;">Crew Rotation Transfer</div>
|
||||
<div class="timeline-event" style="grid-column: 92;"><span>Lingxiao Docking</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-row is-hidden" data-asset="zhuque">
|
||||
<article class="timeline-row-label">
|
||||
<h3>XH-03 Zhuque</h3>
|
||||
<p>Shuttle</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment hold" style="grid-column: 64 / span 22;">Port Refit</div>
|
||||
<div class="timeline-segment transit" style="grid-column: 88 / span 8;">Relay Deployment Window</div>
|
||||
<div class="timeline-event" style="grid-column: 86;"><span>Rollout Review</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-row is-hidden" data-asset="tianhe-7">
|
||||
<article class="timeline-row-label">
|
||||
<h3>Tianhe Cargo Pod 7</h3>
|
||||
<p>Cargo Shuttle</p>
|
||||
</article>
|
||||
<div class="timeline-lane">
|
||||
<div class="timeline-segment hold" style="grid-column: 74 / span 6;">Station Docked Stay</div>
|
||||
<div class="timeline-event" style="grid-column: 80;"><span>Undock</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user