refactor: standalone dashboard folders with index.html, zip-based import/export (.tsd/.tss/.tsp)

- Each dashboard is now a self-contained folder: manifest.json + index.html
- Auto-scan dashboards/ and data/dashboards/ on startup
- Export: .tsd (dashboards), .tss (scenes), .tsp (game plugins) - all zip format
- Dashboard index.html is complete standalone page (WS + data binding)
- Aspect ratio constraints handled in each dashboard's own JS
- Removed template-based dashboard rendering in favor of static serve
- Import via file upload endpoints, export via direct file download
This commit is contained in:
2026-07-25 15:35:08 +08:00
parent d61bb61a83
commit 63e3c8d607
21 changed files with 752 additions and 380 deletions
-3
View File
@@ -43,7 +43,6 @@ const API = {
async updateDashboard(id, data) { return this.put(`/dashboards/${id}`, data); },
async deleteDashboard(id) { return this.del(`/dashboards/${id}`); },
async exportDashboard(id) { return this.get(`/dashboards/${id}/export`); },
async importDashboard(data) { return this.post('/dashboards/import', data); },
async getScenes(gameId) { return this.get(`/scenes?game_id=${gameId || ''}`); },
async getScene(id) { return this.get(`/scenes/${id}`); },
@@ -51,13 +50,11 @@ const API = {
async updateScene(id, data) { return this.put(`/scenes/${id}`, data); },
async deleteScene(id) { return this.del(`/scenes/${id}`); },
async exportScene(id) { return this.get(`/scenes/${id}/export`); },
async importScene(data) { return this.post('/scenes/import', data); },
async startTelemetry() { return this.post('/telemetry/start'); },
async stopTelemetry() { return this.post('/telemetry/stop'); },
async getLatestTelemetry() { return this.get('/telemetry/latest'); },
async installGamePlugin(data) { return this.post('/games/install', data); },
async removeGamePlugin(id) { return this.del(`/games/${id}`); },
async exportGamePlugin(id) { return this.get(`/games/${id}/export`); },
async reloadGamePlugins() { return this.post('/games/reload'); },