codeartlv/joona

为 Laravel 项目提供简单后端模板

1.1.4 2024-09-23 11:43 UTC

README

Joona 是 Laravel 的一个实用包,旨在提升后端开发。它包含用户管理、权限设置和活动日志。前端集成了 Bootstrap 5 和额外的 UI 组件,以改善界面设计。它提供了一种快速启动任何需要管理界面的项目的方法。与其他管理面板(如 Filament)不同,它鼓励通过不限制视图输出内容的用法来创建高度定制的用户界面。该项目基于 Bootstrap + Alpine.js + HTMX 堆栈构建。

要求

此包针对与全新的 Laravel 10.x 安装无缝集成而定制,但也可集成到现有项目中。包中包含创建表的必要迁移。然而,需要注意的是,如果您的当前项目中已经存在同名表,可能会出现潜在冲突。

安装

  1. 使用 Composer 安装包: composer require codeartlv/joona
  2. 发布资源: php artisan joona:publish。注意,这将导出 UI 资产到 public/vendor/joona 目录。如果您在管道或生产环境中构建资源,应将此目录添加到 .gitignore 文件中。
  3. config/app.php 中添加服务提供者 App\Providers\JoonaServiceProvider::class,
  4. 运行迁移: php artisan migrate
  5. 默认种子: php artisan joona:seed
  6. 为了支持在您的项目中扩展 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 防护者添加到配置中。在添加额外的防护者或提供者时,请考虑此命名。