12-05-2026 admin, Panel Displays
This commit is contained in:
parent
0762e3beac
commit
6a65354f4c
43 changed files with 3273 additions and 410 deletions
|
|
@ -30,6 +30,17 @@ class DisplayFactory extends Factory
|
|||
'name' => fake()->words(2, true),
|
||||
'location' => fake()->optional()->words(3, true),
|
||||
'is_active' => true,
|
||||
'is_test' => false,
|
||||
'preview_token' => null,
|
||||
];
|
||||
}
|
||||
|
||||
public function test(): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'is_test' => true,
|
||||
'name' => 'Test-Display',
|
||||
'location' => 'Vorschau / Test',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
51
database/factories/DisplayPlaylistFactory.php
Normal file
51
database/factories/DisplayPlaylistFactory.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Display;
|
||||
use App\Models\DisplayPlaylist;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @template TModel of \App\Models\DisplayPlaylist
|
||||
*
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel>
|
||||
*/
|
||||
class DisplayPlaylistFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* @var class-string<TModel>
|
||||
*/
|
||||
protected $model = DisplayPlaylist::class;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'display_id' => Display::factory(),
|
||||
'status' => DisplayPlaylist::STATUS_PUBLISHED,
|
||||
'published_at' => now(),
|
||||
'published_by' => null,
|
||||
'notes' => null,
|
||||
];
|
||||
}
|
||||
|
||||
public function draft(): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'status' => DisplayPlaylist::STATUS_DRAFT,
|
||||
'published_at' => null,
|
||||
'published_by' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function published(): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'status' => DisplayPlaylist::STATUS_PUBLISHED,
|
||||
'published_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
database/factories/DisplayPlaylistItemFactory.php
Normal file
33
database/factories/DisplayPlaylistItemFactory.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\DisplayPlaylist;
|
||||
use App\Models\DisplayPlaylistItem;
|
||||
use App\Models\DisplayVersion;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @template TModel of \App\Models\DisplayPlaylistItem
|
||||
*
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel>
|
||||
*/
|
||||
class DisplayPlaylistItemFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* @var class-string<TModel>
|
||||
*/
|
||||
protected $model = DisplayPlaylistItem::class;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'display_playlist_id' => DisplayPlaylist::factory(),
|
||||
'display_version_id' => DisplayVersion::factory(),
|
||||
'sort_order' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* Erweitert die displays-Tabelle um:
|
||||
* - is_test: Kennzeichnet ein Display als Test-Display (eigene Kachel im Admin,
|
||||
* beliebige Module/Bespielungen können dort gefahrlos kombiniert werden).
|
||||
* - preview_token: Eindeutiger Token für die Vorschau einer Entwurfs-Bespielung
|
||||
* über /preview/{token} – ohne Login.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('displays', function (Blueprint $table) {
|
||||
$table->boolean('is_test')->default(false)->after('is_active');
|
||||
$table->string('preview_token', 64)->nullable()->unique()->after('is_test');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('displays', function (Blueprint $table) {
|
||||
$table->dropUnique(['preview_token']);
|
||||
$table->dropColumn(['is_test', 'preview_token']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* Eine Display-Bespielung – pro Display existiert maximal eine Live-Bespielung
|
||||
* (status = published) und optional eine Entwurfs-Bespielung (status = draft).
|
||||
*
|
||||
* Der Player liest immer die published-Playlist. Die Vorschau-Route greift
|
||||
* über den preview_token des Displays auf die draft-Playlist zu.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('display_playlists', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('display_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('status'); // 'published' | 'draft'
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->foreignId('published_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->text('notes')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['display_id', 'status']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('display_playlists');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* Eintrag in einer Display-Bespielung. Ersetzt funktional die alte
|
||||
* Pivot-Tabelle display_display_version. display_versions selbst bleibt
|
||||
* unverändert – Module sind weiterhin wiederverwendbar (shared) zwischen
|
||||
* Displays.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('display_playlist_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('display_playlist_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('display_version_id')->constrained()->cascadeOnDelete();
|
||||
$table->unsignedInteger('sort_order')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['display_playlist_id', 'sort_order']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('display_playlist_items');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* Überführt bestehende Pivot-Daten aus display_display_version in die neue
|
||||
* Struktur display_playlists + display_playlist_items. Pro Display wird eine
|
||||
* Live-Bespielung (status = published) erzeugt und die bestehende Reihenfolge
|
||||
* 1:1 übernommen. Die alte Pivot-Tabelle bleibt erhalten und wird erst in
|
||||
* Phase 7 dropped (Bestandsfunktionen müssen weiterlaufen).
|
||||
*
|
||||
* Idempotent: Existiert bereits eine Published-Playlist für ein Display, wird
|
||||
* sie übersprungen.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('display_display_version')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pivots = DB::table('display_display_version')
|
||||
->orderBy('display_id')
|
||||
->orderBy('sort_order')
|
||||
->get()
|
||||
->groupBy('display_id');
|
||||
|
||||
$now = now();
|
||||
|
||||
foreach ($pivots as $displayId => $entries) {
|
||||
$existing = DB::table('display_playlists')
|
||||
->where('display_id', $displayId)
|
||||
->where('status', 'published')
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlistId = DB::table('display_playlists')->insertGetId([
|
||||
'display_id' => $displayId,
|
||||
'status' => 'published',
|
||||
'published_at' => $now,
|
||||
'published_by' => null,
|
||||
'notes' => 'Initial-Import aus display_display_version',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
DB::table('display_playlist_items')->insert([
|
||||
'display_playlist_id' => $playlistId,
|
||||
'display_version_id' => $entry->display_version_id,
|
||||
'sort_order' => $entry->sort_order,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::table('display_playlist_items')->delete();
|
||||
DB::table('display_playlists')->delete();
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue