Commit Graph

46 Commits

Author SHA1 Message Date
caoqianming 8e52a327f5 fix(events): load system events on page refresh in ops view
Events were only loaded when switching to config view, but the
system events panel lives in ops view, leaving it empty on refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 10:41:27 +08:00
caoqianming 4338895e0a refactor(ops): use units-embedded equipments, lazy-load config data
Ops view now reads equipment+role_points from state.units (returned by
unit list API) instead of state.equipments, eliminating the loadEquipments()
call on bootstrap.

Config data (sources, equipments, events, points) is deferred until the
user first switches to config view. On WS reconnect, loadEquipments is
only refreshed when config view is active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 10:33:19 +08:00
caoqianming 0b7f2401bd feat(ws): refresh units and equipments on WebSocket reconnect
After a disconnect/reconnect, re-fetch units (runtimes) and equipments
(monitor data) so the UI reflects current server state without requiring
a page reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 09:37:00 +08:00
caoqianming e304fd342d feat(ops): embed role_points in equipment list, remove unit detail API calls
Equipment list response now includes signal-role points with monitor data,
so the ops view can render signal dots directly from state.equipments
without fetching /api/unit/:id/detail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 09:34:59 +08:00
caoqianming 0e8d194a70 fix(web): remove duplicate loadAllEquipmentCards call in startOps
startOps() was calling loadAllEquipmentCards() redundantly — the
units-loaded event listener already calls it after loadUnits()
completes. This caused two parallel requests to /api/unit/:id/detail
for every unit on page load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 09:23:09 +08:00
caoqianming 08add0d087 refactor(api): embed runtime in unit list/get/detail responses
Remove the standalone GET /api/unit/runtimes endpoint in favour of
embedding runtime directly in existing responses:
- GET /api/unit          → each item now includes `runtime` field
- GET /api/unit/:id      → returns UnitWithRuntime
- GET /api/unit/:id/detail → UnitDetail now includes `runtime`

runtime is null when the engine has not yet initialised the unit.
Frontend loadUnits() reads the embedded runtime field to populate
state.runtimes — one request instead of two.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 09:18:14 +08:00
caoqianming 42cdbbc0cc fix(web): fetch all unit runtimes on page load
Root cause: state.runtimes was empty after refresh because the engine
only pushes UnitRuntimeChanged on state transitions — if the engine
is mid-wait-phase, no push occurs and badges show OFFLINE.

Fix: add GET /api/unit/runtimes batch endpoint (returns all known
runtimes as { unit_id: UnitRuntime }) and call it in parallel with
the unit list fetch inside loadUnits(), so runtime badges are correct
immediately after page load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 09:11:47 +08:00
caoqianming 4ce91adf60 refactor(web): remove dead code and translate plan docs to Chinese
- ops.js: remove unused `formatValue` import
- logs.js: remove `export` from internal-only `appendLog`
- state.js: fix stale comment ({ valueEl, qualityEl } → { dotEl })
- docs: rewrite both plan docs in Chinese; update dual-view-web plan to
  reflect actual implementation (sigDotClass dots, loadAllEquipmentCards,
  syncEquipmentButtonsForUnit, batch auto buttons in startOps)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:57:29 +08:00
caoqianming 8c1b7b636d refactor(engine): replace 500ms ticker with per-unit event-driven tasks
- Engine now spawns one async task per enabled unit (supervised every 10s)
- wait_phase uses sleep_until + select! for precise timing; 500ms fault-tick
  runs inside each phase so fault/comm is still checked promptly
- WS UnitRuntimeChanged pushed only on state transitions, not every tick
- ControlRuntimeStore gains notify_unit/get_or_create_notify for instant
  wake-up when handlers change auto_enabled or fault_locked
- UnitRuntime: remove last_tick_at, current_run/stop/distributor_elapsed_sec;
  add display_acc_sec (snapshot at transition, avoids mid-cycle jitter)
- accumulated_run_sec now increments by exact run_time_sec*1000 per cycle
- unit.state_changed events no longer written to DB (too frequent)
- Frontend: show display_acc_sec instead of accumulated_run_sec
- styles: event-card flex-shrink:0 fixes text overlap under flex column

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:33:00 +08:00
caoqianming da03441c11 refactor(events): display each event on a single line
Flatten two-row card (meta + message) into one flex row:
badge | time | event_type | message (ellipsis overflow)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 16:40:43 +08:00
caoqianming a8d36578fa feat: ws backoff, signal dots, dom cap, unwrap fix, batch size limit
- logs.js: WS reconnect exponential backoff 1s→2s→4s…30s
- ops.js: replace badge+text signal display with red/green/yellow dots
  (sig-on=green, sig-fault=red, sig-warn=yellow, gray=off)
- events.js: cap live-prepended event cards at 100 DOM nodes
- source.rs: fix attach_children unwrap() → Option<TreeNode>/filter_map
- point.rs: add max=500 validation to all batch Vec<Uuid> fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 16:37:14 +08:00
caoqianming 13c4b515d7 fix(docs): widen API drawer and fix TOC scroll hijacking window
- Add .api-drawer (1100px) so content area is ~880px instead of ~540px
- Replace scrollIntoView with apiDocContent.scrollBy to avoid scrolling
  the window and collapsing the drawer layout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 14:41:17 +08:00
caoqianming bc6e6e889f feat(events): infinite scroll with page_size=10, replace full re-render
Replace bulk load+re-render with scroll-based pagination: load 10 items
on init, append next page when scrolling near the bottom. prependEvent
now inserts directly into DOM instead of rebuilding from state.events.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:23:18 +08:00
caoqianming 2a247dd70b fix(toast): remove shake class before hiding to ensure animationend fires
When dismiss() was called on a persistent+shaking toast, the .shake CSS
rule (declared after .hiding) overrode toast-out animation. If shake had
already finished, no animationend fired and the element was never removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:16:50 +08:00
caoqianming b7d55fed81 refactor(web): unify toast — remove duplicate, reuse api.js showToast
- Deleted redundant toast.js (was duplicating api.js's toast with conflicting CSS)
- Extended api.js showToast: returns {dismiss}, supports shake option, guards
  against double-dismiss
- Removed duplicate #toastContainer CSS block from styles.css; added shake
  animation to existing toast CSS
- logs.js: import showToast from api.js; WS disconnect shows persistent error
  toast with shake, reconnect shows success toast

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:11:23 +08:00
caoqianming 69ae0b05b7 feat(web): add toast notifications + WS disconnect alert
- New toast.js module: showToast(message, type, duration)
  - types: error / warning / success / info
  - duration=0 → persistent until dismissed or manually closed
  - click to dismiss early
  - shake animation on appear
- WS disconnect: persistent red error toast "后端连接断开,正在重连…"
- WS reconnect: dismisses disconnect toast, shows green "连接已恢复" for 3s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:08:14 +08:00
caoqianming 757d6f9a3a feat(control): batch start/stop auto control for all enabled units
Backend:
- POST /api/control/unit/batch-start-auto — starts auto on all enabled
  units that are not fault/comm locked and not already running auto
- POST /api/control/unit/batch-stop-auto — stops auto on all units

Frontend (ops view):
- Add "全部启动" / "全部停止" buttons in the unit sidebar header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 13:05:23 +08:00
caoqianming b28ac23520 feat(web): show WS connection status indicator in topbar
Green dot + "已连接" when socket is open; red dot + "连接断开,重连中…"
on close/error. Reconnect timer (2s) already in place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 12:41:50 +08:00
caoqianming b832d98196 fix(control): block manual commands during auto, fix engine stop_time=0 bug, add sim feedback
- validator: reject equipment start/stop when unit auto_enabled
- engine: fix stop_time_sec==0 causing infinite Stopped state (never starts)
- engine: call simulate_run_feedback after auto commands when SIMULATE_PLC=true
- command: extract simulate_run_feedback to shared module (was private in handler)
- web: disable Start/Stop buttons when unit auto is active; sync on WS runtime update

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 12:37:43 +08:00
caoqianming 36cfe9ecfc feat(web): add runtime badge and auto/ack buttons to ops unit list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 10:47:09 +08:00
caoqianming 4076f6575e feat(web): dual-view UI — 运维/配置 tab, ops equipment cards with live signal values
- Add 运维/配置 tab switch; grid-ops / grid-config layout classes
- New ops-panel: unit sidebar + equipment card grid (REM/RUN/FLT signals)
- All equipment cards shown by default; unit click acts as filter
- Signal cells seed from point_monitor cache on render, then update via WS PointNewValue
- New log-stream-panel: SSE realtime log stream, active only in config view
- Backend: get_unit_detail now includes point_monitor (current value) in each point

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 10:25:20 +08:00
caoqianming dae5bdcb9e fix(web): fix node count showing 2x by counting only details elements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 08:27:06 +08:00
caoqianming 622d010cb1 fix(server): add Cache-Control: no-store to static file responses
Prevents browser from caching JS/CSS modules, so frontend changes take
effect immediately on page refresh without needing hard refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:57:39 +08:00
caoqianming 3e277cdb52 refactor(web): event card layout to 2-line (meta row + message row)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:46:32 +08:00
caoqianming a405623ec1 refactor(web): remove realtime log stream, compact event list to single line
- Remove SSE log stream (EventSource /api/logs/stream) and logView panel
- System events panel now occupies the full bottom-middle panel
- Each event renders as a single flex row: level badge, type, message, timestamp
- Remove logSource from state, logView from dom, startLogs from app bootstrap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:39:01 +08:00
caoqianming d88d8375fd fix(frontend): pre-select active unit when opening new equipment modal
When a unit is selected in the sidebar, the create-equipment modal now
pre-fills the unit dropdown with that unit. Previously it always reset
to empty, so newly created equipment got unit_id=null and was hidden by
the unit filter after save.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:35:33 +08:00
caoqianming d1131c4e2d fix(frontend): show fault/comm locked state in runtime badge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 15:04:17 +08:00
caoqianming 0c2ce48d23 feat(frontend): handle UnitRuntimeChanged WebSocket message 2026-03-24 14:58:29 +08:00
caoqianming 21f6008cba feat(frontend): add start/stop control buttons to equipment cards 2026-03-24 14:58:16 +08:00
caoqianming 89023e867b feat(frontend): show runtime state and auto/ack buttons on unit cards 2026-03-24 14:58:07 +08:00
caoqianming 31ccf49b75 feat(frontend): add runtimes map to state 2026-03-24 14:57:41 +08:00
caoqianming 49a4afa4a4 feat(web): auto-toast on API errors with dismissible notifications
Add showToast() utility in api.js and a matching toast stylesheet.
apiFetch now automatically shows a toast for any 400+ response before
re-throwing, so callers can still .catch() for additional handling.

Toasts stack at the bottom-right, auto-dismiss after 4s, and support
error/warning/success/info levels via a left-border colour accent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:43:57 +08:00
caoqianming a38204511a refactor(control): align point roles and equipment kind 2026-03-24 13:17:53 +08:00
caoqianming c50127b9d0 feat(event): stream created events over websocket 2026-03-24 12:28:12 +08:00
caoqianming 1f29eb3871 feat(web): add unit and event management views 2026-03-24 10:56:57 +08:00
caoqianming 4d53ee0337 refactor(web): split index html into flat fragments 2026-03-23 14:14:19 +08:00
caoqianming 6cdc51a249 refactor(point): fold binding into edit action 2026-03-23 13:20:03 +08:00
caoqianming e55c1d5efb fix(chart): restore realtime updates and axes 2026-03-23 12:55:12 +08:00
caoqianming fec7b60d6b feat(web): reorganize equipment layout and point flows 2026-03-23 12:49:26 +08:00
caoqianming 06ace5e67d refactor(app): split services and web modules 2026-03-23 11:31:38 +08:00
caoqianming a691f07e8e feat(web): add API.md drawer preview 2026-03-20 19:00:46 +08:00
caoqianming 920e37f759 feat(web): add inline point chart panel 2026-03-20 10:54:20 +08:00
caoqianming 7e6c7a7e4c feat(reconnect): add retry backoff and manual reconnect 2026-03-17 08:15:54 +08:00
caoqianming dd110919dd style(web): remove rounded corners and localize card titles 2026-03-16 10:25:32 +08:00
caoqianming ae134c722a refactor(ui): redesign web interface with flat modern style
Made-with: Cursor
2026-03-16 08:48:12 +08:00
caoqianming efed6aa816 feat: add page 2026-03-11 13:23:05 +08:00