mylaraveltools/panel 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mylaraveltools/panel

Composer 安装命令:

composer require mylaraveltools/panel

包简介

Panel — declarative monochrome admin panel for Laravel with Livewire and Tailwind

README 文档

README

Panel de administración declarativo y monocromático para Laravel. API de Resources al estilo Filament/Nova, con Livewire 3, Tailwind CSS, auth integrada, permisos Spatie, import/export y navegación SPA.

Parte del ecosistema My Laravel Tools (junto con mylaraveltools/alertas).

composer require mylaraveltools/panel

Migración: si usabas mylaraveltools/minimalist, sustituye por mylaraveltools/panel. El namespace PHP sigue siendo MyLaravelTools\Panel — no cambia tu código.

Tabla de contenidos

  1. Requisitos
  2. Instalación paso a paso
  3. Tu primer CRUD en 5 minutos
  4. Configuración (config/panel.php)
  5. Autenticación y perfil
  6. Permisos (Spatie) y suplantación
  7. Navegación y páginas custom
  8. Importar y exportar datos
  9. Dashboard y widgets
  10. Relaciones entre modelos
  11. Tema, layout y SPA
  12. Comandos Artisan
  13. Personalizar vistas
  14. Solución de problemas
  15. Proyecto demo
  16. Desarrollo y tests
  17. Roadmap
  18. Licencia

Requisitos

Requisito Versión
PHP 8.2+
Laravel 11, 12 o 13
Livewire 3.5+
Tailwind CSS 3+ en la app host

Opcionales: spatie/laravel-permission, mylaraveltools/alertas.

Instalación paso a paso

Paso 1 — Composer

composer require mylaraveltools/panel

Desarrollo local (path repository):

{
  "repositories": [
    { "type": "path", "url": "../minimalist-panel-library" }
  ],
  "require": {
    "mylaraveltools/panel": "@dev"
  }
}

Paso 2 — Instalar el panel

php artisan panel:install

Esto publica config/panel.php, registra rutas en /admin y prepara Livewire.

Paso 3 — Tailwind

En tailwind.config.js incluye las vistas del paquete y activa modo oscuro por clase:

export default {
  darkMode: 'class',
  content: [
    './resources/views/**/*.blade.php',
    './vendor/mylaraveltools/panel/resources/views/**/*.blade.php',
  ],
};

Paso 4 — Alpine + Livewire

En resources/js/app.js, no importes Alpine en rutas del panel (/admin/*). Livewire lo gestiona:

const panelPath = '/admin';

if (!window.location.pathname.startsWith(panelPath)) {
  import('alpinejs').then(({ default: Alpine }) => {
    window.Alpine = Alpine;
    Alpine.start();
  });
}

Importar Alpine en /admin/login rompe wire:submit (el formulario no envía nada).

Paso 5 — Compilar y probar

npm run build
php artisan serve

Abre http://127.0.0.1:8000/admin — verás login/registro si auth.enabled es true.

APP_URL debe coincidir con host y puerto (http://127.0.0.1:8000).

Tu primer CRUD en 5 minutos

1. Crear el Resource

php artisan panel:make-resource Product --model=Product

2. Definir formulario y tabla

// app/Panel/Resources/ProductResource.php
final class ProductResource extends Resource
{
    protected static string $model = Product::class;
    protected static ?string $label = 'Productos';
    protected static ?string $icon = 'package';

    public static function form(): array
    {
        return [
            TextField::make('name')->label('Nombre')->required(),
            NumberField::make('price')->label('Precio')->min(0),
        ];
    }

    public static function table(): array
    {
        return [
            TextColumn::make('name')->label('Nombre')->searchable()->sortable(),
            TextColumn::make('price')->label('Precio')->sortable(),
        ];
    }
}

3. Listo

Auto-discovery en app/Panel/Resources/ (configurable). URL: /admin/resources/products (slug = kebab del modelo; puedes fijarlo con protected static ?string $slug = 'productos';).

Configuración (config/panel.php)

Toda la configuración vive en este archivo (compatible con config:cache). No hace falta .env, aunque puedes usarlo si prefieres.

Clave Descripción Default
path Prefijo URL admin
guard Guard de auth web
brand.name Nombre en sidebar Panel
brand.logo URL del logo (null = icono) null
per_page Registros por página 15
forms_in_modal Crear/editar en modal true
discovery Auto-discovery Resources enabled
pages Auto-discovery Pages enabled
permissions Spatie/Gate disabled
navigation Menú lateral (null = auto) null
widgets Dashboard []
import Import CSV/Excel enabled + preview
impersonation Suplantar usuarios disabled
theme.preset Preset visual (minimal, corporate, contrast, ocean) minimal
extensions Vistas custom de campos/columnas y widgets []
version Texto en sidebar (null = paquete) null

Tema monocromático

'theme' => [
    'default' => 'dark',
    'font' => 'Plus Jakarta Sans',
    'colors' => [
        'primary' => '#000000',
        'primary_dark' => '#ffffff',
        'accent' => '#525252',
        'success' => '#16a34a',
        'danger' => '#dc2626',
        'warning' => '#ca8a04',
    ],
    'light' => [ /* bg, surface, card, border, heading, text, muted… */ ],
    'dark' => [ /* … */ ],
],

Variables CSS: --panel-primary, --panel-bg, etc. Toggle claro/oscuro en el footer del sidebar (persiste en localStorage).

Presets de tema

'theme' => [
    'preset' => 'corporate',  // minimal | corporate | contrast | ocean
    'colors' => [
        'primary' => '#ff0000',  // sobrescribe solo el preset
    ],
],

Extensibilidad (campos, columnas, widgets)

Por config (config/panel.phpextensions):

'extensions' => [
    'field_views' => ['rating' => 'panel-custom.fields.rating'],
    'column_views' => ['rating' => 'panel-custom.columns.rating'],
    'widgets' => [],
],

Por código (AppServiceProvider::boot):

use MyLaravelTools\Panel\Facades\PanelExtensions;

PanelExtensions::registrarVistaCampo('rating', 'panel-custom.fields.rating');
PanelExtensions::registrarWidget(StatWidget::make('Total', fn () => Model::count()));

Campo custom en un Resource:

CustomField::make('payload')
    ->type('json-editor')
    ->view('panel-custom.fields.json-editor')
    ->label('Datos JSON'),

Campos integrados nuevos: ColorField, DateTimeField, KeyValueField (pares clave/valor → JSON).

Actualizar vistas publicadas:

php artisan panel:upgrade-views --dry-run
php artisan panel:upgrade-views --force

Layout y apariencia

'layout' => [
    'density' => 'compact',           // comfortable | compact
    'content_width' => 'boxed',       // full | boxed
    'sidebar_collapsible' => true,
    'show_breadcrumbs' => true,
    'footer_links' => [
        ['label' => 'Ayuda', 'route' => 'panel.dashboard'],
        ['label' => 'Web', 'url' => 'https://ejemplo.com', 'external' => true],
    ],
],

'brand' => [
    'name' => 'Mi Panel',
    'logo' => '/img/logo.svg',
    'logo_height' => '2.5rem',
    'favicon' => '/favicon.ico',
    'tagline' => 'Gestiona tu negocio',
],

'auth_ui' => [
    'layout' => 'split',              // centered | split
    'image' => '/img/auth-side.jpg',
    'background' => 'linear-gradient(135deg, #0f172a, #1e3a5f)',
    'show_tagline' => true,
],

'customization' => [
    'css' => '.panel-sidebar { border-right-width: 2px; }',
    'head_view' => 'panel-custom.head',
],

RepeaterField — filas con varias columnas (JSON):

RepeaterField::make('lineas')
    ->columns(['concepto' => 'Concepto', 'importe' => 'Importe'])
    ->minRows(1)
    ->maxRows(10),

Máxima personalización (v0.24)

Modos de layoutsidebar (por defecto), topbar o dual (barra superior + lateral):

'layout' => [
    'mode' => 'sidebar',              // sidebar | topbar | dual
    'sidebar_position' => 'left',     // left | right
    'table_striped' => true,
    'table_compact' => false,
    'global_search' => true,
    'per_page_options' => [15, 25, 50, 100],
],

Slots Blade — inyecta vistas en puntos del layout sin publicar todo el paquete:

'slots' => [
    'sidebar.before' => 'mi-app.panel.slots.aviso',
    'main.after' => 'mi-app.panel.slots.analytics',
    'topbar.end' => 'mi-app.panel.slots.acciones',
],

Slots disponibles: sidebar.before, sidebar.after, main.before, main.after, topbar.start, topbar.end, footer.before.

También vía código en AppServiceProvider:

use MyLaravelTools\Panel\Support\PanelExtensions;

PanelExtensions::registrarSlot('main.before', 'mi-app.panel.banner');

Import upsert — actualiza registros existentes en lugar de fallar:

'import' => [
    'upsert' => true,
    'upsert_key' => 'email',          // global; el Resource puede sobreescribir
],
// En tu Resource
public static function importUpsertKey(): ?string
{
    return 'sku';
}

Hooks en Resources:

public static function navigationBadge(): ?string
{
    return (string) static::model()::where('is_active', false)->count();
}

public static function hiddenFromNavigation(): bool
{
    return ! auth()->user()?->can('view settings');
}

public static function perPageOptions(): array
{
    return [10, 25, 50];
}

Presets de tema propios — archivo PHP que devuelve un array de presets:

'theme' => [
    'preset' => 'mi-marca',
    'presets_file' => config_path('panel-theme-presets.php'),
],

Instalación con demo:

php artisan panel:install --demo

Autenticación y perfil

Auth integrada en /admin/login y /admin/register (tabla users de Laravel):

'auth' => [
    'enabled' => true,
    'register' => true,
    'register_role' => 'viewer',      // Spatie, opcional
    'password_reset' => true,
    'email_verification' => false,    // requiere MustVerifyEmail
],
  • Auth externa (Breeze/Fortify): 'enabled' => false, 'login_route' => 'login'.
  • Tras login: recarga completa al dashboard (sin loader SPA). Botón «Entrando» con puntos animados solo durante el POST.
  • Recuperar contraseña: /admin/forgot-password.
  • Perfil: /admin/profile'profile.enabled' => true.

Permisos (Spatie) y suplantación

Spatie Laravel Permission

composer require spatie/laravel-permission
'permissions' => [
    'enabled' => true,
    'panel_access' => 'access panel',
    'resources' => true,              // RoleResource + PermissionResource
    'manage_permission' => 'manage users',
],
  • RolesField / RolesColumn en usuarios.
  • PermissionsField / PermissionsColumn en roles.
  • En Pages: protected static ?string $permission = 'view reports'.
  • Policies: php artisan panel:make-policy Product → extiende ResourcePolicy (deny-by-default).

Suplantación de usuario

Navega el panel como otro usuario (permisos, menú y policies reales):

'impersonation' => [
    'enabled' => true,
    'permission' => 'impersonate users',
    'exclude_ids' => [],
    'banner' => true,
],
  1. En el resource del modelo User, menú ⋮ → Entrar como.
  2. Aparece una tarjeta en el sidebar (encima del perfil) con botón Salir.
  3. Requiere permiso Spatie/Gate. No puedes suplantarte a ti mismo.

Navegación y páginas custom

Menú con grupos

// config/panel.php
'navigation' => require __DIR__.'/panel-navigation.php',
return [
    ['resource' => ProductResource::class],
    ['page' => SettingsPage::class],
    [
        'type' => 'group',
        'label' => 'Catálogo',
        'icon' => 'package',
        'children' => [
            ['resource' => ProductResource::class],
            ['resource' => CategoryResource::class],
        ],
    ],
];
  • Búsqueda global: Cmd/Ctrl+K.
  • No uses route() al cargar el config; usa la clave 'route' => 'panel.dashboard'.

Páginas custom (no CRUD)

php artisan panel:make-page Settings
final class SettingsPage extends Page
{
    protected static ?string $label = 'General';
    protected static ?string $slug = 'settings-general';

    public static function view(): string
    {
        return 'panel.pages.settings-general';
    }
}

Ruta: /admin/pages/{slug}. Vista con <x-panel::page-header>.

Importar y exportar datos

Export

Botones CSV, XLSX y PDF en listados. Con filas seleccionadas, exporta solo la selección.

Import (con vista previa)

'import' => [
    'enabled' => true,
    'preview' => true,
    'upsert' => true,
    'upsert_key' => null,
],
  1. Botón Importar en el listado (permiso create).
  2. Sube .csv, .txt, .xlsx, .xls.
  3. Revisa filas válidas/errores → confirma.
  4. Con upsert activo: crea nuevos y actualiza existentes según importUpsertKey() del Resource.

Personaliza columnas con Field::importable(false) o Resource::import().

Dashboard y widgets

'widgets' => [
    ResourceCountWidget::make(ProductResource::class),
    StatWidget::make('Activos', fn () => Product::where('is_active', true)->count())
        ->icon('check-circle'),
    ChartWidget::make('Ventas', 'bar', fn () => [
        'labels' => ['Ene', 'Feb'],
        'values' => [12, 19],
    ])->themeColors(),
    ViewWidget::make('Custom', 'panel.widgets.mi-vista', fn () => ['total' => 100])
        ->columnSpan(2),
],

Tipos ChartWidget: bar, line, pie, doughnut, progression. Gráficos reactivos al tema y SPA.

Relaciones entre modelos

Desde la vista Ver del registro padre:

public static function relations(): array
{
    return [
        RelationManager::make('products', ProductResource::class),
        RelationManager::hasOne('profile', ProfileResource::class),
        RelationManager::belongsToMany('tags', TagResource::class),
        RelationManager::morphMany('reviews', ReviewResource::class),
        RelationManager::morphToMany('tags', TagResource::class),
    ];
}

Tema, layout y SPA

  • Sin header global — cada vista usa <x-panel::page-header> (título + breadcrumbs).
  • Sidebar footer: perfil, idioma, tema, versión, logout.
  • SPA: wire:navigate, loader con porcentaje 0%100%, sidebar persistente.
  • Livewire: mantén navigate.show_progress_bar => true en config/livewire.php (la barra NProgress se oculta vía CSS del panel).

Fields y Columns

Fields: TextField, EmailField, PasswordField, TextareaField, BooleanField, SelectField, BelongsToField, NumberField, DateField, DateTimeField, ColorField, KeyValueField, CustomField, FileField, ImageField, RichTextField, RolesField, PermissionsField.

Columns: TextColumn, BooleanColumn, DateTimeColumn, BadgeColumn, ColorColumn, BelongsToColumn, ImageColumn, RolesColumn, PermissionsColumn.

Filtros: SelectFilter, BooleanFilter, DateRangeFilter, MultiSelectFilter.

Formularios: Section::make(), Tab::make(), soft deletes, bulk actions, RowAction.

Comandos Artisan

Comando Descripción
php artisan panel:install Instalar panel
php artisan panel:install --demo Instalar + navigation stub y PostResource ejemplo
php artisan panel:make-resource Name Crear Resource
php artisan panel:make-page Name Crear página custom
php artisan panel:make-policy Name Crear Policy
php artisan panel:make-widget Name --type=chart Crear clase widget para el dashboard
php artisan panel:doctor Diagnosticar instalación del panel
php artisan panel:upgrade-views Actualizar vistas publicadas
php artisan vendor:publish --tag=panel-config Publicar config
php artisan vendor:publish --tag=panel-views Publicar vistas Blade
php artisan vendor:publish --tag=panel-documentation Copiar documentation/panel/ al proyecto

Documentación interactiva (playground)

Ruta pública /playground (sin login) — documentation.enabled y documentation.path:

  • Panel FAKE a pantalla completa + controles laterales
  • Catálogo de todas las opciones de config/panel.php
  • Vista previa en vivo (layout, marca, tema…)
  • Markdown: documentation/panel/README.md

Personalizar vistas

Si publicas vistas en resources/views/vendor/panel/, sobreescriben las del paquete.

Tras actualizar el paquete:

php artisan vendor:publish --tag=panel-views --force
php artisan view:clear

Si no publicas vistas, Laravel usa las del vendor directamente (recomendado hasta que edites Blade).

Solución de problemas

Problema Solución
Login no envía el formulario No importes Alpine en rutas /admin/*
Alpine is not defined show_progress_bar => true en config/livewire.php
Estilos rotos Incluye vistas del paquete en tailwind.config.js y npm run build
Feature nueva no aparece Republica vistas con --force o borra resources/views/vendor/panel/
404 en /admin/resources/users El slug por defecto es user (singular); define $slug = 'users'
«Entrar como» no visible Permiso impersonate users + php artisan db:seed con ese permiso
Redirecciones raras en login APP_URL con host y puerto correctos

Proyecto demo

Carpeta panel-demo/ con catálogo, ventas, Spatie, gráficos, import y suplantación.

cd panel-demo
composer install && npm install && npm run build
php artisan migrate:fresh --seed
php artisan serve
Usuario Email Password
Admin admin@panel.test password
Editor editor@panel.test password

Ver panel-demo/README.md para rutas y features de prueba.

Desarrollo y tests

cd minimalist-panel-library
composer test

Roadmap

  • CRUD, SPA, Excel/PDF, búsqueda global, i18n, tests, CI
  • RowAction, modales, skeletons, filtros avanzados
  • Forms en modal, tabs, export PDF
  • Policies, páginas custom, permisos Spatie
  • Auth integrada, reset password, perfil
  • Import con preview, ChartWidget, ViewWidget, email verify
  • Auth UX (v0.20), suplantación de usuario (v0.21)
  • Packagist — mylaraveltools/panel
  • Extensibilidad — presets tema, PanelExtensions, campos custom (v0.22)
  • Layout — densidad, boxed, sidebar colapsable, auth split, RepeaterField (v0.23)
  • Máxima personalización — topbar/dual, slots, upsert, tablas, presets propios (v0.24)
  • Playground público, gráficos interactivos, panel:doctor, panel:make-widget (v0.25)
  • Layout móvil pulido — mobile-bar, drawer, modos sidebar/topbar/dual (v0.26)
  • Multi-panel, starter kit completo

Licencia

MIT — Alberto Gallardo Morales

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-22

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固