codeartlv / joona
为 Laravel 项目提供简单后端模板
Requires
- php: ^8.2
- jenssegers/agent: ^2.6
- tightenco/ziggy: ^2.0
README
Joona 是 Laravel 的一个实用包,旨在提升后端开发。它包含用户管理、权限设置和活动日志。前端集成了 Bootstrap 5 和额外的 UI 组件,以改善界面设计。它提供了一种快速启动任何需要管理界面的项目的方法。与其他管理面板(如 Filament)不同,它鼓励通过不限制视图输出内容的用法来创建高度定制的用户界面。该项目基于 Bootstrap + Alpine.js + HTMX 堆栈构建。
要求
此包针对与全新的 Laravel 10.x 安装无缝集成而定制,但也可集成到现有项目中。包中包含创建表的必要迁移。然而,需要注意的是,如果您的当前项目中已经存在同名表,可能会出现潜在冲突。
安装
- 使用 Composer 安装包:
composer require codeartlv/joona
- 发布资源:
php artisan joona:publish
。注意,这将导出 UI 资产到public/vendor/joona
目录。如果您在管道或生产环境中构建资源,应将此目录添加到 .gitignore 文件中。 - 在
config/app.php
中添加服务提供者App\Providers\JoonaServiceProvider::class,
- 运行迁移:
php artisan migrate
- 默认种子:
php artisan joona:seed
- 为了支持在您的项目中扩展 CSS/JS,请在您的文件中添加依赖项
您的 SCSS 文件
/* Import base config */ @import '../../vendor/codeartlv/joona/resources/assets/scss/config.scss'; // or if using Vite and defined alias // @import '@joona/scss/config.scss'; /** * You can override the theme settings here */ /* Import main stylesheet */ @import '../../vendor/codeartlv/joona/resources/assets/scss/main.scss'; // or if using Vite and defined alias // @import '@joona/scss/main.scss'; // At this point, include your custom SCSS files. All Bootstrap mixins and variables are available.
您的 JavaScript 入口点
import './../../vendor/codeartlv/joona/resources/assets/js/main.js'; // or if using Vite and defined alias // import '@joona/js/main.js'; // Add your Alpine components or any other JS code. window.Alpine.start();
如果您使用 Vite,基本设置可能如下所示
// vite.config.js import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import path from 'path'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/js/app.js', 'resources/scss/main.scss', ], refresh: true, }), ], resolve: { alias: { '@joona': path.resolve( __dirname, 'vendor/codeartlv/joona/resources/assets' ), '@joona-modules': path.resolve( __dirname, 'vendor/codeartlv/joona/node_modules' ), }, }, });
定义 CSS/JS 文件后,构建项目
npx vite build
到此为止,设置应该已完成。导航到 /admin
并使用以下凭据登录
Email: admin@localhost 密码: password
请注意,实际的密码策略更为严格。建议您更改默认用户密码,因为所需的密码复杂度会更高。
用法
该包引入了几个中间件和模板,以便集成到后端界面中。它使用自定义 auth
守卫,用户将通过数据库进行身份验证。
后端使用的应用程序标题来自 app.name
配置设置。
在后台创建路由
在后台界面中,既有已认证的路由,也有未认证的路由。已认证路由需要用户身份验证,而未认证路由不需要,但它们应用额外的设置,如颜色主题、区域等。要包含未认证路由,请将 admin.web
中间件应用于路由。
Route::middleware(['admin.web'])->group(function(){ Route::get('/set-region', [ExampleController::class, 'action']); });
要添加已认证路由,请使用中间件 admin.auth
Route::middleware(['admin.auth'])->group(function(){ Route::get('/blog', [ExampleController::class, 'action']); });
请注意,这仍然需要 admin.web
中间件提供基本设置。您可以为您的后端路由创建一个组
Route::middleware(['admin.web'])->group(function(){ // Unauthenticated routes Route::middleware(['admin.auth'])->group(function () { // Authenticated routes }); });
像往常一样编写控制器。
视图
该包提供两种布局 - 简单布局和带侧边栏的布局。侧边栏布局用于添加各种数据筛选控件。侧边栏布局已设计为响应式,可用于移动设备。
简单视图
要使用简单视图,您会编写模板如下
@extends('joona::simple')
@section('page_title', 'Page title')
@section('main')
The main content goes here
@endsection
@section('foot')
The footer of the page. Add additional controls here like paginator etc.
@endsection
@section('controls')
This block resides at the header of page. Add CTA button here.
@endsection
并非所有部分都需要填写,但主要内容应位于 main
部分。
侧边栏布局
块布局与简单布局相同,但侧边栏内容有专门的块
@section('sidebar')
Sidebar content goes here
@endsection
包括元数据
即使视图完全从包内渲染,您可能还需要向 <head>
注入额外的数据。只需创建 resources/views/vendor/joona/head.blade.php
文件,Laravel 将将其包含在 <head>
中。
与 UI 组件协作
由于 Alpine 和 HTMX 已经包含在面板中,因此对如何编写组件没有限制。
路由
该包使用 Ziggy 在 JavaScript 中提供路由。只需调用函数 route
并像在 Laravel 中一样使用它。
JavaScript UI 组件
该包提供了一些常用组件,可以包含在视图中。
模态对话框
通过远程请求加载的模态对话框。
import Modal from '@joona/js/components/modal.js'; let modalDialog = new Modal(); modalDialog.open('/page', { animations : true, }).then(() => { // modal is opened // close by calling modalDialog.close(); });
确认对话框
import ConfirmDialog from '@joona/js/components/confirm-dialog.js'; const caption = 'Confirm'; const message = 'Are you sure you want to delete this record?'; const buttons = [ {caption:'Cancel', role:'secondary', callback:()=>{}}, {caption:'Yes', role:'primary', callback:()=>{}}, ]; let confirmDialog = new ConfirmDialog(caption, message, buttons);
确认对话框在按下任何按钮后自动关闭。
后端提供了一个非常简单的 JS 框架,用于将视图与 JS 代码分离。它利用 HTML 元素上的 data
属性,将每个组件绑定到这些属性上。您不必使用此框架,但对于简单的交互,它可能比部署 React/Vue 等框架更快。无论如何,这取决于您。
创建新组件处理器
首先,如果您需要向元素添加交互,您创建一个 JavaScript 类,该类收集针对问题域的一组函数。假设您有一个博客,需要在后端添加组件。首先创建博客组件处理器。
// resources/js/blog.js import Handler from '@joona/js/handler'; export default class Blog extends Handler { static get pluginName() { return 'blog'; } }
在应用程序中注册处理器
// resource/js/app.js import Blog from 'blog'; // Add your custom handlers Joona.addHandlers(Blog);
pluginName
是处理器的一个必需函数。现在,假设您需要围绕某些 HTML 代码创建功能。您通过 data
属性引用处理器。
<div data-bind="blog.edit-form" data-id="1"> </div>
在这里,data-bind
由两部分组成 - 第一部分是处理器名称(pluginName
返回的值)和第二部分是处理器函数名称。基于此示例,我们可以编写如下处理器:
// resources/js/blog.js export default class Blog extends Handler { static get pluginName() { return 'blog'; } editForm(element, parameters, runtime) { // add your functionality // element is HTML Node // parameters contains {"id":1} } }
处理器名称将被转换为驼峰式。例如,edit-form
变为 editForm
。每个处理器函数接收 3 个参数:element - 被分配 data-bind
的 DOM 节点的引用;parameters - 节点上的任何额外的 data
参数;runtime - 运行时类的实例。
获取其他组件的实例
如果处理器函数返回一个对象,它将被存储以供以后访问。这样,您可以从页面的任何位置或特定范围内获取其他绑定的组件。假设您有两个处理器函数:
<div data-bind="blog.edit-form"> <div data-bind="blog.user-component"></div> </div>
// resources/js/blog.js export default class Blog extends Handler { static get pluginName() { return 'blog'; } userComponent(element, parameters, runtime) { return new function(){ this.hello = (name) => { alert(name); }; }(); } editForm(element, parameters, runtime) { runtime.getInstance(element, 'blog.user-component').then((userComponent) => { userComponent.hello('Bob'); }); } }
window.Runtime.getInstance
在提供的范围(element
)内搜索绑定的组件,第二个参数是处理器的全名。请注意,组件必须返回一个函数或对象以供解析。window.Runtime.getInstance
返回第一个找到的组件。如果您假设可以有多个实例,请使用 runtime.getInstances
。
动态绑定处理器
如果您动态加载内容,在向 DOM 中插入新节点后,请在新的 HTML 节点上调用 window.Runtime.init(context)
。其中 context
是您能引用的最高 DOM 节点,它包含新的 HTML。
HTML 组件
分页器
输出分页器组件。传递 total
(总行数)和 size
(每页的项目数)。
<x-paginator :total="$total" :size="$size" />
表单
创建动态表单。表单通过 Ajax 提交。
<x-joona-form method="post" action="" class=""> <!-- Form elements --> <x-joona-form>
在向表单提交提供响应时,使用 FormResponse
类。
use Codeart\Joona\View\Components\Form\FormResponse; // Inside your controller $form = new FormResponse(); // Form submitted successfully $form->setSuccess('Data saved!'); // Set error on field $form->setError('Value required.', 'name'); // Add action on a form. The action gets executed only if there are no errors. // Multiple actions can be added. $form->setAction('reload', true); // Reload page $form->setAction('redurect', '/home'); // Redirect user to the URL $form->setAction('close_popup', true); // Closes opened modal dialog $form->setAction('reset', true); // Resets form to default state. // Attaching additional data $form->addData(['id' => 1]); // Render form return response()->json($form);
当在表单字段上设置错误时,会搜索提供名称的任何输入。如果提供空字段名称,则消息将渲染到专用的警报组件中。如果表单元素不能具有特定的名称,您可以通过添加来定义表单错误渲染的位置
<div data-field="name"></div>
按钮
显示按钮。
<x-button caption="Submit" type="submit" role="primary" icon="check" :attr="['custom-attribute' => 'yes']" />
警报
显示警报消息。
<x-alert role="info" message="Hello World!" />
对话框
在输出对话框内容时应包含。
<x-dialog :caption="Caption"> <p>Dialog content</p> <x-slot name="footer"> Optional footer </x-slot> </x-dialog>
带有表单和保存按钮的对话框示例
<x-form :action="route('blog.save')"> <x-dialog :caption="Edit post"> <div> <div data-role="form.response"></div> <!-- Form fields --> </div> <x-slot name="footer"> <x-button :caption="Save" icon="check" /> </x-slot> </x-dialog> </x-form>
上传器
创建文件上传器。设置上传的文件时,使用 Codeart\Joona\View\Components\Form\UploadedFile
的实例。上传文件时,返回同一类的响应。
<x-uploader uploadroute="files.upload" deleteroute="files.delete" limit="5" submitbtn="#test-button" :files="$files"></x-uploader>
命令
该包添加了额外的控制台命令。请参阅每个命令的描述。
joona:seed
- 创建默认凭证。运行此命令后,您可以使用电子邮件 admin@localhost
和密码 password
在后端面板中进行授权。joona:publish
- 发布后端模板资产和相关包的资产。
请在您的调度器中添加 $schedule->command('joona:update-session')->everyTenMinutes();
。这将使更新管理员用户会话数据更加精确。
注意事项
该包将 admin
防护者添加到 auth.php
,并将 joona
防护者添加到配置中。在添加额外的防护者或提供者时,请考虑此命名。