The overview API reads live MariaDB since 2026-07-02; sample:true is only the standalone dev fallback. Replaced the "wire it (TODO)" section with the live column sources + resolved the notVerladen open question. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
155 lines
7.1 KiB
Markdown
155 lines
7.1 KiB
Markdown
# SPA_TemperProductionOverview — Temper-Linie · Live-Übersicht
|
|
|
|
A **login-free, read-only** whole-line temper overview, built as a Vue 3 SPA that
|
|
the **SPRO Universal Gateway** serves as a static page-module under
|
|
`/module/temper_overview/` and that is **embedded into Grafana via an `<iframe>`**.
|
|
|
|
> **Standalone orientation.** This repo is developed on its own (like `FastPress`,
|
|
> `PressV`, `sp-ui-kit` — sibling repos), but it only comes fully alive when mounted
|
|
> into the gateway as a git submodule at `modules/temper_overview/`. This README
|
|
> bakes in everything a fresh session needs — you shouldn't need the gateway repo
|
|
> open to work on the frontend.
|
|
|
|
Board it renders (dark, one connected line): **Pressen → (cyan ↓) → Ofen →
|
|
(green ↓) → Fertig**, carts hanging under their origin press, oven trays whose
|
|
background fills with dwell progress, a finished band, and a time-range picker that
|
|
scopes only the "Fertig" figures. Run `npm run dev` to see it.
|
|
|
|
---
|
|
|
|
## Quick start (standalone dev)
|
|
|
|
Package manager is **yarn 1.22.22** (pinned via `packageManager`; matches PressV /
|
|
the fleet). `corepack` provides it — no global yarn install needed.
|
|
|
|
```bash
|
|
# 0) let corepack honour the pinned yarn (one-time per machine)
|
|
corepack enable
|
|
|
|
# 1) auth for the private @sp-ui-kit design-token package (one-time)
|
|
cp .npmrc.example .npmrc # then paste a Gitea PAT with "package: Read" scope
|
|
# (yarn v1 reads .npmrc for the scoped registry)
|
|
|
|
# 2) install + run
|
|
yarn install
|
|
yarn dev # http://localhost:5173/module/temper_overview/
|
|
```
|
|
|
|
With **no gateway backend running**, the store falls back to **bundled sample data**
|
|
(`src/data/sample.ts`), so `yarn dev` shows the full design immediately (a
|
|
`DEMO-DATEN` tag appears in the header). `yarn build` → `dist/` (committed).
|
|
|
|
---
|
|
|
|
## How it's wired into the gateway (page-module contract)
|
|
|
|
This is a gateway module per `agent_docs/vue-page-modules.md` in the gateway repo.
|
|
The **repo root is a Python package** (`__init__.py`) so the kernel's module loader
|
|
can `import temper_overview` and call `register(app)`:
|
|
|
|
| File | Role |
|
|
|---|---|
|
|
| `__init__.py` | `register(app)` — mounts `dist/` at `MODULE_PREFIX` + includes the API router |
|
|
| `_db.py` | kernel DB seam (`run_select_query`) — used once real SQL is wired |
|
|
| `api/routes.py` | the no-auth read API (`GET /module/temper_overview/api/overview`) |
|
|
| `dist/` | **committed** build output — the gateway serves this (deploy host has no Node) |
|
|
| `src/` etc. | the Vue app source |
|
|
|
|
**URL prefix lives in two places that MUST match** — change both together:
|
|
`vite.config.ts` → `base: '/module/temper_overview/'` and `__init__.py` →
|
|
`MODULE_PREFIX = "/module/temper_overview"`. The frontend derives its API base from
|
|
`import.meta.env.BASE_URL`, so it follows the prefix automatically.
|
|
|
|
Add it to a gateway checkout:
|
|
|
|
```bash
|
|
# in the gateway repo (fastAPI)
|
|
git submodule add https://git.sprodat.eu/Erik/SPA_TemperProductionOverview.git modules/temper_overview
|
|
# MODULES_ENABLED in .env must include temper_overview (or be empty = load all)
|
|
```
|
|
|
|
Restart the gateway; the log shows `loaded module: temper_overview`. Smoke-test
|
|
(mind the trailing slash): `http://localhost:8800/module/temper_overview/` and
|
|
`…/api/overview`.
|
|
|
|
> **Deploy rule:** always `yarn build` and **commit `dist/`** when the app changes,
|
|
> then bump the submodule pin in the gateway repo. Never build on the gateway host.
|
|
|
|
---
|
|
|
|
## Data API contract
|
|
|
|
`GET /module/temper_overview/api/overview?range=12h|1d|7d|14d|30d` → one JSON
|
|
payload for the whole line. The TypeScript shape is authoritative:
|
|
[`src/types/overview.ts`](src/types/overview.ts); the Python side builds the same
|
|
shape in [`api/routes.py`](api/routes.py). `range` scopes **only** the `finished`
|
|
figures — presses / on-the-way / oven are always real-time.
|
|
|
|
```jsonc
|
|
{
|
|
"plant": "Werk 1", "generatedAt": "…", "range": "1d",
|
|
"ovenTempC": 185, "ovenAvgMin": 120, "sample": true,
|
|
"presses": [{ "name":"P1","status":"run","orders":[{"orderNo":"O-4471","colorIndex":0}],
|
|
"good":1240,"cycleTime":"4.2","notVerladen":34,"note":null,"placeholder":false }],
|
|
"onWay": { "P3":[{ "cartId":"C-014a","orders":[{"orderNo":"O-4471","qty":54,"colorIndex":0}],"etaMin":3 }] },
|
|
"oven": [{ "cartId":"C-011","orders":[],"totalMin":120,"remainingMin":42 }],
|
|
"finished": { "carts":47,"parts":5120,"scrap":63,"avgOvenMin":118,
|
|
"byOrder":[{"orderNo":"O-4471","colorIndex":0,"parts":1680}] },
|
|
"finishedList": [{ "cartId":"C-010","orders":[],"ago":"vor 8 min" }]
|
|
}
|
|
```
|
|
|
|
### Live data wiring
|
|
|
|
`api/routes.py` reads live MariaDB (`sample:true` only appears in the standalone
|
|
dev fallback with no backend). Details + the exact column sources are in the gateway
|
|
memory `.claude/memory/temper-line-overview.md`. In short: it uses the kernel proxy
|
|
`from .._db import run_select_query` (read-only), un-scoped across **all** presses for
|
|
plant `PLANT_NAME` — press list from `press_settings.presses`; good/chips from
|
|
`active_orders`+`rejects`; run/stop/idle from `cycles_new` recency; carts +
|
|
`notVerladen` from `production.temper_tracking` with position derived in SQL from the
|
|
planned timestamps vs `NOW()` (reprints excluded). `finished` is scoped by `range` on
|
|
`ttOutOfOvenAt`. Oven temperature is omitted (no sensor). Never echo customer/price
|
|
fields.
|
|
|
|
---
|
|
|
|
## Tech stack (matches PressV / the fleet)
|
|
|
|
Vue 3.5 · Vite 8 · TypeScript 5.9 · Pinia 3 · vue-router 4 (hash) · vue-i18n 10
|
|
(de default, `?lang=en`) · PrimeVue 4.5 (Nora + custom **Industrial** preset, sky
|
|
primary) · Tailwind v4 (CSS-first) · `@sp-ui-kit/tokens` (shared design tokens,
|
|
private registry) · Inter Variable. **Dark-first**, flat 2px corners, 0s
|
|
transitions, `prefers-reduced-motion` disables the conveyor animations.
|
|
|
|
**Store pattern** (mirrors PressV `productionOverview`): `src/stores/temperOverview.ts`
|
|
does `loadCache()` (sessionStorage) → `hydrate()` (spinner only on cold start) →
|
|
`refresh()` (background) → `startPolling(12000)`. Robust to a dev server's SPA
|
|
fallback: a response without a `presses[]` array is treated as "no backend" → sample.
|
|
|
|
### Design tokens (recognisable across SPRO apps)
|
|
|
|
Flow accents match PressV `--c-*`: press/machine `#a78bfa`, on-the-way/cart
|
|
`#22d3ee`, oven `#f97316` (hot `#ef4444`), finished `#34d399`. Order chips (from
|
|
PressV `orderColors.ts`): `#5794F2 #E8825A #B57EDC #4FB7A8`. Defined in
|
|
`src/style.css` (`:root` dark + `html:not(.dark)` light) and `src/data/orderColors.ts`.
|
|
|
|
> Not yet used but part of the fleet stack — add when needed: `@sp-ui-kit/ui-core`
|
|
> components and `echarts`/`vue-echarts`. The board's by-order bars are CSS today.
|
|
|
|
---
|
|
|
|
## Grafana embedding
|
|
|
|
The gateway sets no `X-Frame-Options`/CSP, so a Grafana **Text** panel (HTML mode,
|
|
`disable_sanitize_html = true`) can iframe it:
|
|
|
|
```html
|
|
<iframe src="http://<gateway-host>:8800/module/temper_overview/#/"
|
|
width="100%" height="900" style="border:0"></iframe>
|
|
```
|
|
|
|
Append `?lang=en` before the `#` for English. Design is locked as design #4
|
|
"Shop-floor Schematic" — see `.claude/memory/temper-line-overview.md` and the
|
|
prototype at `modules/fastpress/reference/temper-overview/` in the gateway repo.
|