1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2015 Jens Segers
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,67 @@
# laravel-admin
[![Build Status](https://travis-ci.org/z-song/laravel-admin.svg?branch=master)](https://travis-ci.org/z-song/laravel-admin)
[![StyleCI](https://styleci.io/repos/48796179/shield)](https://styleci.io/repos/48796179)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/z-song/laravel-admin/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/z-song/laravel-admin/?branch=master)
[![Packagist](https://img.shields.io/packagist/l/encore/laravel-admin.svg?maxAge=2592000)](https://packagist.org/packages/encore/laravel-admin)
[![Total Downloads](https://img.shields.io/packagist/dt/encore/laravel-admin.svg?style=flat-square)](https://packagist.org/packages/encore/laravel-admin)
`laravel-admin` 是一个可以快速帮你构建后台管理的工具,它提供的页面组件和表单元素等功能,能帮助你使用很少的代码就实现功能完善的后台管理功能。
> 当前版本(1.5)需要安装`PHP 7+`和`Laravel 5.5`, 如果你使用更早的版本,请参考文档: [1.4](http://laravel-admin.org/docs/v1.4/#/zh/)
## 特性
+ 内置用户和权限系统
+ `model-grid`支持快速构建数据表格
+ `model-form`支持快速构建数据表单
+ `model-tree`支持快速构建树状数据
+ 内置40+种form元素组件、以及支持扩展组件
+ 支持`Laravel`的多种模型关系
+ `mysql``mongodb``pgsql`等多数据库支持
+ 支持引入第三方前端库
+ 数据库和artisan命令行工具的web实现
+ 支持自定义图表
+ 多种常用web组件
+ 支持本地和oss文件上传
## Demo
打开`http://laravel-admin.org/demo/`,用账号密码`admin/admin`登陆
# 依赖
`laravel-admin` 基于以下组件或者服务:
+ [Laravel](https://laravel.com/)
+ [AdminLTE](https://almsaeedstudio.com/)
+ [Datetimepicker](http://eonasdan.github.io/bootstrap-datetimepicker/)
+ [font-awesome](http://fontawesome.io)
+ [moment](http://momentjs.com/)
+ [Google map](https://www.google.com/maps)
+ [Tencent map](http://lbs.qq.com/)
+ [bootstrap-fileinput](https://github.com/kartik-v/bootstrap-fileinput)
+ [jquery-pjax](https://github.com/defunkt/jquery-pjax)
+ [Nestable](http://dbushell.github.io/Nestable/)
+ [toastr](http://codeseven.github.io/toastr/)
+ [X-editable](http://github.com/vitalets/x-editable)
+ [bootstrap-number-input](https://github.com/wpic/bootstrap-number-input)
+ [fontawesome-iconpicker](https://github.com/itsjavi/fontawesome-iconpicker)
## 交流
QQ群:278455482(已满)、635881319(已满)、533701919
> 为了避免广告及不看文档用户请先到github star此项目然后附上github账号申请入群
> 另外我已经屏蔽群私聊,所以请不要找我私聊,也请尽量不要在群里面 @我 🙏
## 支持
如果觉得这个项目帮你节约了时间,不妨支持一下;)
![-1](https://cloud.githubusercontent.com/assets/1479100/23287423/45c68202-fa78-11e6-8125-3e365101a313.jpg)
## License
`laravel-admin` is licensed under [The MIT License (MIT)](zh/LICENSE).

View File

@@ -0,0 +1,35 @@
- 入门
- [安装](/zh/installation.md)
- [快速开始](/zh/quick-start.md)
- [页面内容和布局](/zh/content-layout.md)
- 模型表格
- [基本使用](/zh/model-grid.md)
- [行的使用和扩展](/zh/model-grid-actions.md)
- [列的使用和扩展](/zh/model-grid-column.md)
- [自定义工具](/zh/model-grid-custom-tools.md)
- [修改表格数据源](/zh/model-grid-data.md)
- [查询过滤](/zh/model-grid-filters.md)
- [数据导出](/zh/model-grid-export.md)
- 模型表单
- [基本使用](/zh/model-form.md)
- [图片/文件上传](/zh/model-form-upload.md)
- [Form组件使用](/zh/model-form-fields.md)
- [Form组件管理](/zh/model-form-field-management.md)
- [表单验证](/zh/model-form-validation.md)
- [保存回调](/zh/model-form-callback.md)
- [数据模型树](/zh/model-tree.md)
- Admin扩展
- [帮助工具](/zh/extension-helpers.md)
- [文件管理](/zh/extension-media-manager.md)
- [API tester](/zh/extension-api-tester.md)
- [配置管理](/zh/extension-config.md)
- [计划任务](/zh/extension-scheduling.md)
- [前端组件](/zh/widgets.md)
- [权限控制](/zh/permission.md)
- [自定义登陆认证](/zh/custom-authentication.md)
- [自定义头部导航](/zh/custom-navbar.md)
- [自定义图表](/zh/custom-chart.md)
- [常见问题](/zh/qa.md)
- [升级注意事项](/zh/upgrade.md)
- [Change log](/zh/change-log.md)

View File

@@ -0,0 +1,13 @@
# Change log
## v1.2.9、v1.3.3、v1.4.1
- 添加用户设置和修改头像功能
- model-form自定义工具[参考](zh/model-form.md?id=自定义工具)
- 内嵌表单支持[参考](zh/model-form-fields.md?id=embeds)
- 支持自定义导航条(右上角)[参考](https://github.com/z-song/laravel-admin/issues/392)
- 添加脚手架、数据库命令行工具、web artisan帮助工具[参考](zh/helpers.md)
- 支持自定义登陆页面和登陆逻辑[参考](zh/qa.md?id=自定义登陆页面和登陆逻辑)
- 表单支持设置宽度、设置action[参考](zh/model-form.md?id=其它方法)
- 优化表格过滤器
- 修复bug优化代码和逻辑

View File

@@ -0,0 +1,141 @@
# 页面内容
`laravel-admin`的布局可参考后台首页的布局文件[HomeController.php](https://github.com/z-song/laravel-admin/blob/master/src/Console/stubs/HomeController.stub)的`index()`方法。
`Encore\Admin\Layout\Content`类用来实现内容区的布局。`Content::body($content)`方法用来添加页面内容:
一个简单的后台页面代码如下:
```php
public function index()
{
return Admin::content(function (Content $content) {
// 选填
$content->header('填写页面头标题');
// 选填
$content->description('填写页面描述小标题');
// 添加面包屑导航 since v1.5.7
$content->breadcrumb(
['text' => '首页', 'url' => '/admin'],
['text' => '用户管理', 'url' => '/admin/users'],
['text' => '编辑用户']
);
// 填充页面body部分这里可以填入任何可被渲染的对象
$content->body('hello world');
});
}
```
其中`$content->body();`方法可以接受任何可字符串化的对象作为参数,可以是字符串、数字、包含了`__toString`方法的对象,实现了`Renderable``Htmlable`接口的对象包括laravel的视图。
## 布局
`laravel-admin`的布局使用bootstrap的栅格系统每行的长度是12下面是几个简单的示例
添加一行内容:
```php
$content->row('hello')
---------------------------------
|hello |
| |
| |
| |
| |
| |
---------------------------------
```
行内添加多列:
```php
$content->row(function(Row $row) {
$row->column(4, 'foo');
$row->column(4, 'bar');
$row->column(4, 'baz');
});
----------------------------------
|foo |bar |baz |
| | | |
| | | |
| | | |
| | | |
| | | |
----------------------------------
$content->row(function(Row $row) {
$row->column(4, 'foo');
$row->column(8, 'bar');
});
----------------------------------
|foo |bar |
| | |
| | |
| | |
| | |
| | |
----------------------------------
```
列中添加行:
```php
$content->row(function (Row $row) {
$row->column(4, 'xxx');
$row->column(8, function (Column $column) {
$column->row('111');
$column->row('222');
$column->row('333');
});
});
----------------------------------
|xxx |111 |
| |---------------------|
| |222 |
| |---------------------|
| |333 |
| | |
----------------------------------
```
列中添加行, 行内再添加列:
```php
$content->row(function (Row $row) {
$row->column(4, 'xxx');
$row->column(8, function (Column $column) {
$column->row('111');
$column->row('222');
$column->row(function(Row $row) {
$row->column(6, '444');
$row->column(6, '555');
});
});
});
----------------------------------
|xxx |111 |
| |---------------------|
| |222 |
| |---------------------|
| |444 |555 |
| | | |
----------------------------------
```

View File

@@ -0,0 +1,111 @@
# 自定义登陆
如果不使用`laravel-admin`内置的认证登陆逻辑,可以参考下面的方式自定义登陆认证逻辑
首先要先定义一个`user provider`,用来获取用户身份, 比如`app/Providers/CustomUserProvider.php`
```php
<?php
namespace App\Providers;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
class CustomUserProvider implements UserProvider
{
public function retrieveById($identifier)
{}
public function retrieveByToken($identifier, $token)
{}
public function updateRememberToken(Authenticatable $user, $token)
{}
public function retrieveByCredentials(array $credentials)
{
// 用$credentials里面的用户名密码去获取用户信息然后返回Illuminate\Contracts\Auth\Authenticatable对象
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
// 用$credentials里面的用户名密码校验用户返回true或false
}
}
```
在方法`retrieveByCredentials``validateCredentials`中, 传入的`$credentials`就是登陆页面提交的用户名和密码数组,然后你可以使用`$credentials`去实现自己的登陆逻辑
Interface `Illuminate\Contracts\Auth\Authenticatable`的定义如下:
```php
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable {
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
```
上面interface每个方法的解释参考[adding-custom-user-providers](https://laravel.com/docs/5.5/authentication#adding-custom-user-providers)
定义好了`User provider`之后,打开`app/Providers/AuthServiceProvider.php`注册它:
```php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('custom', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new CustomUserProvider();
});
}
}
```
最后修改一下配置,打开`config/admin.php`,找到`auth`部分修改:
```php
'auth' => [
'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'admin',
]
],
// 修改下面
'providers' => [
'admin' => [
'driver' => 'custom',
]
],
],
```
这样就完成了自定义登陆认证的逻辑自定义登陆算是laravel中比较复杂的部分需要开发者有耐心的一步步调试完成。

View File

@@ -0,0 +1,79 @@
# 自定义图表
`laravel-admin 1.5`已经移除了所有的图表组件,如果要在页面中加入图表组件,可以参考下面的流程
`chartjs`举例,首先要下载[chartjs](http://chartjs.org/)放到public目录下面比如放在`public/vendor/chartjs`目录
然后在`app/Admin/bootstrap.php`引入组件:
```php
use Encore\Admin\Facades\Admin;
Admin::js('/vendor/chartjs/dist/Chart.min.js');
```
新建视图文件 `resources/views/admin/charts/bar.blade.php`
```php
<canvas id="myChart" width="400" height="400"></canvas>
<script>
$(function () {
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
});
</script>
```
然后就可以在页面的任何地方引入这个图表视图了:
```php
public function index()
{
return Admin::content(function (Content $content) {
$content->header('chart');
$content->description('.....');
$content->body(view('admin.charts.bar'));
});
}
```
按照上面的方式可以引入任意图表库,多图表页面的布局,参考[视图布局](/zh/layout.md)

View File

@@ -0,0 +1,148 @@
# 自定义头部导航条
从版本`1.5.6`开始可以在顶部导航条上添加html元素了, 打开`app/Admin/bootstrap.php`
```php
use Encore\Admin\Facades\Admin;
Admin::navbar(function (\Encore\Admin\Widgets\Navbar $navbar) {
$navbar->left('html...');
$navbar->right('html...');
});
```
`left``right`方法分别用来在头部的左右两边添加内容,方法参数可以是任何可以渲染的对象(实现了`Htmlable``Renderable`接口或者包含`__toString()`方法的对象)或字符串
## 左侧添加示例
举个例子比如在左边添加一个搜索条先创建一个blade视图`resources/views/search-bar.blade.php`
```php
<style>
.search-form {
width: 250px;
margin: 10px 0 0 20px;
border-radius: 3px;
float: left;
}
.search-form input[type="text"] {
color: #666;
border: 0;
}
.search-form .btn {
color: #999;
background-color: #fff;
border: 0;
}
</style>
<form action="/admin/posts" method="get" class="search-form" pjax-container>
<div class="input-group input-group-sm ">
<input type="text" name="title" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
```
然后加入头部导航条:
```php
$navbar->left(view('search-bar'));
```
## 右侧添加示例
导航右侧只能添加`<li>`标签, 比如要添加一些提示图标,新建渲染对象`app/Admin/Extensions/Nav/Links.php`
```php
<?php
namespace App\Admin\Extensions\Nav;
class Links
{
public function __toString()
{
return <<<HTML
<li>
<a href="#">
<i class="fa fa-envelope-o"></i>
<span class="label label-success">4</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-bell-o"></i>
<span class="label label-warning">7</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-flag-o"></i>
<span class="label label-danger">9</span>
</a>
</li>
HTML;
}
}
```
然后加入头部导航条:
```php
$navbar->right(new \App\Admin\Extensions\Nav\Links());
```
或者用下面的html加入下拉菜单
```html
<li class="dropdown notifications-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-bell-o"></i>
<span class="label label-warning">10</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 10 notifications</li>
<li>
<!-- inner menu: contains the actual data -->
<ul class="menu">
<li>
<a href="#">
<i class="fa fa-users text-aqua"></i> 5 new members joined today
</a>
</li>
<li>
<a href="#">
<i class="fa fa-warning text-yellow"></i> Very long description here that may not fit into the
page and may cause design problems
</a>
</li>
<li>
<a href="#">
<i class="fa fa-users text-red"></i> 5 new members joined
</a>
</li>
<li>
<a href="#">
<i class="fa fa-shopping-cart text-green"></i> 25 sales made
</a>
</li>
<li>
<a href="#">
<i class="fa fa-user text-red"></i> You changed your username
</a>
</li>
</ul>
</li>
<li class="footer"><a href="#">View all</a></li>
</ul>
</li>
```
更多的组件可以参考[Bootstrap](https://getbootstrap.com/)

View File

@@ -0,0 +1,60 @@
# Laravel API测试
`api-tester`是专门针对`laravel`开发的API测试工具能够帮助你像`postman`一样测试你的laravel API。
![wx20170809-164424](https://user-images.githubusercontent.com/1479100/29112946-1e32971c-7d22-11e7-8cc0-5b7ad25d084e.png)
## 安装
```shell
$ composer require laravel-admin-ext/api-tester -vvv
$ php artisan vendor:publish --tag=api-tester
```
然后运行下面的命令导入菜单和权限(也可以手动添加)
```shell
$ php artisan admin:import api-tester
```
然后就能在后台的左侧菜单找到入口链接,`http://localhost/admin/api-tester`
## 使用
打开`routes/api.php`试着添加一个api:
```php
Route::get('test', function () {
return 'hello world';
});
```
打开`api-tester`页面,就能在左侧看到`api/test`, 选择它然后点击右侧的`Send`就能请求这个API下面会输出请求结果,
### Login as
`Login as`填写你要登陆的用户的id, 就可以以这个用户的身份登陆来请求API加入下面的API
```php
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('user', function (Request $request) {
return $request->user();
});
```
`Login as`填写用户ID请求接口后就能返回这个用户的模型
### Parameters
用来填写接口的请求参数,类型可以是字符串或者文件, 添加下面的API
```php
use Illuminate\Http\Request;
Route::get('parameters', function (Request $request) {
return $request->all();
});
```
然后填写参数可以看到效果

View File

@@ -0,0 +1,47 @@
# 配置管理
这个工具将配置数据存在数据库中然后在能在Laravel中能像普通配置一样使用
![wx20170810-100226](https://user-images.githubusercontent.com/1479100/29151322-0879681a-7db3-11e7-8005-03310686c884.png)
## 安装
```
$ composer require laravel-admin-ext/config
$ php artisan migrate
```
打开`app/Providers/AppServiceProvider.php`, 在`boot`方法中添加`Config::load();`:
```php
<?php
namespace App\Providers;
use Encore\Admin\Config\Config;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Config::load(); // 加上这一行
}
}
```
最后运行命令导入菜单和权限(也可以手动添加)
```
$ php artisan admin:import config
```
然后打开`http://localhost/admin/config`访问.
## 使用
打开`http://localhost/admin/config`,添加一项配置,填写`Name``Value`、和`Description`, `Name`是配置的`key`,`Description`是选填的配置注释
最后在程序中使用`config($key)`来获取配置,注意,配置的`Name`不要和`config`目录中的已存在的配置冲突,不然会覆盖掉系统的配置

View File

@@ -0,0 +1,43 @@
# 帮助工具
在最新的版本中新增了面向开发人员的帮助工具,能在开发中提供帮助提高效率,目前提供`脚手架``数据库命令行``artisan命令行`三个工具,如果有更好的其它实用工具的想法,欢迎提供建议。
安装:
```php
composer require laravel-admin-ext/helpers
php artisan admin:import helpers
```
> 工具的部分功能会在项目中创建或删除文件,可能会出现文件或目录权限的问题,这个问题需要自行解决。
> 另外部分数据库和artisan命令无法在web环境下使用。
## 脚手架工具
脚手架工具能帮你一键生成控制器、模型、迁移文件,并运行迁移文件,访问`http://localhost/admin/helpers/scaffold`打开。
其中设置迁移表结构的时候,主键字段是自动生成的不需要填写。
![qq20170220-2](https://cloud.githubusercontent.com/assets/1479100/23147949/cbf03e84-f81d-11e6-82b7-d7929c3033a0.png)
## 数据库命令行
数据库命令行工具的web集成目前支持`mysql``mongodb``redis`,访问`http://localhost/admin/helpers/terminal/database`打开。
在右上角的`select`选择框切换数据库连接,然后在底部的输入框输入对应数据库的查询语句然后回车,就能得到查询结果:
![qq20170220-3](https://cloud.githubusercontent.com/assets/1479100/23147951/ce08e5d6-f81d-11e6-8b20-605e8cd06167.png)
实用方式和终端上操作数据库是一致的,可以运行所选择数据库的所支持的查询语句。
## artisan命令行工具
`Laravel``artisan`命令的web实现可以在上面运行artisan命令访问`http://localhost/admin/helpers/terminal/artisan`打开。
![qq20170220-1](https://cloud.githubusercontent.com/assets/1479100/23147963/da8a5d30-f81d-11e6-97b9-239eea900ad3.png)
## 路由列表
这个工具能用用比较直观的展现出系统的所有路由包括路由的uri、方法和中间件等还能查询路由。访问`http://localhost/admin/helpers/routes`打开。
![helpers_routes](https://user-images.githubusercontent.com/1479100/30899066-e8bdd5ca-a390-11e7-809d-4ceccd0da27f.png)

View File

@@ -0,0 +1,50 @@
# 文件管理
文件管理是一个对本地文件的可视化管理的工具
![wx20170809-170104](https://user-images.githubusercontent.com/1479100/29113762-99886c32-7d24-11e7-922d-5981a5849c7a.png)
## 安装
```
$ composer require laravel-admin-ext/media-manager -vvv
$ php artisan admin:import media-manager
```
## 配置
打开`config/admin.php`指定你要管理的disk
```php
'extensions' => [
'media-manager' => [
'disk' => 'public' // 指向config/filesystem.php中设置的disk
],
],
```
`disk``config/filesystem.php`中设置的本地disk然后打开`http://localhost/admin/media`访问.
注意如果要预览disk中的图片必须在disk中设置访问url前缀
`config/filesystem.php`
```php
'disks' => [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage', // 设置文件访问url
'visibility' => 'public',
],
...
]
```

View File

@@ -0,0 +1,34 @@
# 定时任务
这个工具是管理Laravel计划任务的web管理页面
![wx20170810-101048](https://user-images.githubusercontent.com/1479100/29151552-8affc0b2-7db4-11e7-932a-a10d8a42ec50.png)
## 安装
```
$ composer require laravel-admin-ext/scheduling -vvv
$ php artisan admin:import scheduling
```
打开`http://localhost/admin/scheduling`访问。
## 添加任务
打开`app/Console/Kernel.php` 试着添加两项计划任务:
```php
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')->everyTenMinutes();
$schedule->command('route:list')->dailyAt('02:00');
}
}
```
然后就能在后台看到这两项计划任务的详细情况,也能直接运行这两个计划任务。

View File

@@ -0,0 +1,54 @@
# 安装
> 当前版本(1.5)需要安装`PHP 7+`和`Laravel 5.5`, 如果你使用更早的版本,请参考文档: [1.4](http://laravel-admin.org/docs/v1.4/#/zh/)
首先确保安装好了`laravel`,并且数据库连接设置正确。
```
composer require encore/laravel-admin "1.5.*"
```
然后运行下面的命令来发布资源:
```
php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
```
在该命令会生成配置文件`config/admin.php`,可以在里面修改安装的地址、数据库连接、以及表名,建议都是用默认配置不修改。
然后运行下面的命令完成安装:
```
php artisan admin:install
```
启动服务后,在浏览器打开 `http://localhost/admin/` ,使用用户名 `admin` 和密码 `admin`登陆.
## 生成的文件
安装完成之后,会在项目目录中生成以下的文件:
### 配置文件
安装完成之后,`laravel-admin`所有的配置都在`config/admin.php`文件中。
### 后台项目文件
安装完成之后,后台的安装目录为`app/Admin`,之后大部分的后台开发编码工作都是在这个目录下进行。
```
app/Admin
├── Controllers
│   ├── ExampleController.php
│   └── HomeController.php
├── bootstrap.php
└── routes.php
```
`app/Admin/routes.php`文件用来配置后台路由。
`app/Admin/bootstrap.php``laravel-admin`的启动文件, 使用方法请参考文件里面的注释.
`app/Admin/Controllers`目录用来存放后台控制器文件,该目录下的`HomeController.php`文件是后台首页的显示控制器,`ExampleController.php`为实例文件。
### 静态文件
后台所需的前端静态文件在`/public/vendor/laravel-admin`目录下.

View File

@@ -0,0 +1,89 @@
# 模型表单回调
`model-form`目前提供了两个方法来接收回调函数:
```php
//保存前回调
$form->saving(function (Form $form) {
//...
});
//保存后回调
$form->saved(function (Form $form) {
//...
});
```
可以从回调参数`$form`中获取当前提交的表单数据:
```php
$form->saving(function (Form $form) {
dump($form->username);
});
```
获取获取模型中的数据
```php
$form->saved(function (Form $form) {
$form->model()->id;
});
```
可以直接在回调中返回`Symfony\Component\HttpFoundation\Response`的实例,来跳转或进入页面:
```php
$form->saving(function (Form $form) {
// 返回一个简单response
return response('xxxx');
});
$form->saving(function (Form $form) {
// 跳转页面
return redirect('/admin/users');
});
$form->saving(function (Form $form) {
// 抛出异常
throw new \Exception('出错啦。。。');
});
```
返回错误或者成功信息在页面上:
```php
use Illuminate\Support\MessageBag;
// 抛出错误信息
$form->saving(function ($form) {
$error = new MessageBag([
'title' => 'title...',
'message' => 'message....',
]);
return back()->with(compact('error'));
});
// 抛出成功信息
$form->saving(function ($form) {
$success = new MessageBag([
'title' => 'title...',
'message' => 'message....',
]);
return back()->with(compact('success'));
});
```

View File

@@ -0,0 +1,280 @@
# 组件管理
## 移除已有组件
form表单内置的`map``editor`组件通过cdn的方式引用了前端文件如果网络方面有问题可以通过下面的方式将它们移除
找到文件`app/Admin/bootstrap.php`,如果文件不存在,请更新`laravel-admin`,然后新建该文件
```php
<?php
use Encore\Admin\Form;
Form::forget('map');
Form::forget('editor');
// or
Form::forget(['map', 'editor']);
```
这样就去掉了这两个组件,可以通过该方式去掉其它组件。
## 扩展自定义组件
### 集成富文本编辑器wangEditor
[wangEditor](http://www.wangeditor.com/)是一个优秀的国产的轻量级富文本编辑器,如果`laravel-admin`自带的基于`ckeditor`的编辑器组件使用上有问题,可以通过下面的步骤可以集成它,并覆盖掉`ckeditor`
先下载前端库文件[wangEditor](https://github.com/wangfupeng1988/wangEditor/releases),解压到目录`public/vendor/wangEditor-3.0.9`
然后新建组件类`app/Admin/Extensions/WangEditor.php`
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Form\Field;
class WangEditor extends Field
{
protected $view = 'admin.wang-editor';
protected static $css = [
'/vendor/wangEditor-3.0.9/release/wangEditor.min.css',
];
protected static $js = [
'/vendor/wangEditor-3.0.9/release/wangEditor.min.js',
];
public function render()
{
$name = $this->formatName($this->column);
$this->script = <<<EOT
var E = window.wangEditor
var editor = new E('#{$this->id}');
editor.customConfig.zIndex = 0
editor.customConfig.uploadImgShowBase64 = true
editor.customConfig.onchange = function (html) {
$('input[name=$name]').val(html);
}
editor.create()
EOT;
return parent::render();
}
}
```
新建视图文件`resources/views/admin/wang-editor.blade.php`
```php
<div class="form-group {!! !$errors->has($label) ?: 'has-error' !!}">
<label for="{{$id}}" class="col-sm-2 control-label">{{$label}}</label>
<div class="{{$viewClass['field']}}">
@include('admin::form.error')
<div id="{{$id}}" style="width: 100%; height: 100%;">
<p>{!! old($column, $value) !!}</p>
</div>
<input type="hidden" name="{{$name}}" value="{{ old($column, $value) }}" />
</div>
</div>
```
然后注册进`laravel-admin`,在`app/Admin/bootstrap.php`中添加以下代码:
```php
<?php
use App\Admin\Extensions\WangEditor;
use Encore\Admin\Form;
Form::extend('editor', WangEditor::class);
```
调用:
```
$form->editor('body');
```
### 集成富文本编辑器ckeditor
先下载[ckeditor](http://ckeditor.com/download) 并解压到/public目录比如放在`/public/packages/`目录下。
然后新建扩展文件`app/Admin/Extensions/Form/CKEditor.php`:
```php
<?php
namespace App\Admin\Extensions\Form;
use Encore\Admin\Form\Field;
class CKEditor extends Field
{
public static $js = [
'/packages/ckeditor/ckeditor.js',
'/packages/ckeditor/adapters/jquery.js',
];
protected $view = 'admin.ckeditor';
public function render()
{
$this->script = "$('textarea.{$this->getElementClass()}').ckeditor();";
return parent::render();
}
}
```
新建view `resources/views/admin/ckeditor.blade.php`:
```php
<div class="form-group {!! !$errors->has($errorKey) ?: 'has-error' !!}">
<label for="{{$id}}" class="col-sm-2 control-label">{{$label}}</label>
<div class="col-sm-6">
@include('admin::form.error')
<textarea class="form-control {{ $class }}" name="{{$name}}" placeholder="{{ $placeholder }}" {!! $attributes !!} >{{ old($column, $value) }}</textarea>
@include('admin::form.help-block')
</div>
</div>
```
然后在`app/Admin/bootstrap.php`中引入扩展:
```php
use App\Admin\Extensions\Form\CKEditor;
use Encore\Admin\Form;
Form::extend('ckeditor', CKEditor::class);
```
然后就能在form中使用了:
```php
$form->ckeditor('content');
```
### 集成PHP editor
通过下面的步骤来扩展一个基于[codemirror](http://codemirror.net/index.html)的PHP代码编辑器效果参考[PHP mode](http://codemirror.net/mode/php/)。
先将[codemirror](http://codemirror.net/codemirror.zip)库下载并解压到前端资源目录下,比如放在`public/packages/codemirror-5.20.2`目录下。
新建组件类`app/Admin/Extensions/PHPEditor.php`:
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Form\Field;
class PHPEditor extends Field
{
protected $view = 'admin.php-editor';
protected static $css = [
'/packages/codemirror-5.20.2/lib/codemirror.css',
];
protected static $js = [
'/packages/codemirror-5.20.2/lib/codemirror.js',
'/packages/codemirror-5.20.2/addon/edit/matchbrackets.js',
'/packages/codemirror-5.20.2/mode/htmlmixed/htmlmixed.js',
'/packages/codemirror-5.20.2/mode/xml/xml.js',
'/packages/codemirror-5.20.2/mode/javascript/javascript.js',
'/packages/codemirror-5.20.2/mode/css/css.js',
'/packages/codemirror-5.20.2/mode/clike/clike.js',
'/packages/codemirror-5.20.2/mode/php/php.js',
];
public function render()
{
$this->script = <<<EOT
CodeMirror.fromTextArea(document.getElementById("{$this->id}"), {
lineNumbers: true,
mode: "text/x-php",
extraKeys: {
"Tab": function(cm){
cm.replaceSelection(" " , "end");
}
}
});
EOT;
return parent::render();
}
}
```
>类中的静态资源也同样可以从外部引入,参考[Editor.php](https://github.com/z-song/laravel-admin/blob/1.3/src/Form/Field/Editor.php)
创建视图`resources/views/admin/php-editor.blade.php`:
```php
<div class="form-group {!! !$errors->has($label) ?: 'has-error' !!}">
<label for="{{$id}}" class="col-sm-2 control-label">{{$label}}</label>
<div class="col-sm-6">
@include('admin::form.error')
<textarea class="form-control" id="{{$id}}" name="{{$name}}" placeholder="{{ trans('admin::lang.input') }} {{$label}}" {!! $attributes !!} >{{ old($column, $value) }}</textarea>
</div>
</div>
```
最后找到文件`app/Admin/bootstrap.php`,如果文件不存在,请更新`laravel-admin`,然后新建该文件,添加下面代码:
```
<?php
use App\Admin\Extensions\PHPEditor;
use Encore\Admin\Form;
Form::extend('php', PHPEditor::class);
```
这样就能在[model-form](/zh/model-form.md)中使用PHP编辑器了
```
$form->php('code');
```
通过这种方式可以添加任意你想要添加的form组件。

View File

@@ -0,0 +1,702 @@
# 表单组件
`model-form`中内置了大量的form组件来帮助你快速的构建form表单
## 公共方法
### 设置保存值
```php
$form->text('title')->value('text...');
```
### 设置默认值
```php
$form->text('title')->default('text...');
```
### 设置help信息
```php
$form->text('title')->help('help...');
```
### 设置属性
```php
$form->text('title')->attribute(['data-title' => 'title...']);
$form->text('title')->attribute('data-title', 'title...');
```
### 设置placeholder
```php
$form->text('title')->placeholder('请输入。。。');
```
### model-form-tab
如果表单元素太多,会导致form页面太长, 这种情况下可以使用tab来分隔form:
```php
$form->tab('Basic info', function ($form) {
$form->text('username');
$form->email('email');
})->tab('Profile', function ($form) {
$form->image('avatar');
$form->text('address');
$form->mobile('phone');
})->tab('Jobs', function ($form) {
$form->hasMany('jobs', function () {
$form->text('company');
$form->date('start_date');
$form->date('end_date');
});
})
```
## 文本输入框
```php
$form->text($column, [$label]);
// 添加提交验证规则
$form->text($column, [$label])->rules('required|min:10');
```
## select选择框
```php
$form->select($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
```
或者从api中获取选项列表
```php
$form->select($column[, $label])->options('/api/users');
// 使用ajax并显示所选项目
$form->select($column[, $label])->options(Model::class)->ajax('/api/users');
// 或指定名称和ID
$form->select($column[, $label])->options(Model::class, 'name', 'id')->ajax('/api/users');
```
其中api接口的格式必须为下面格式
```php
[
{
"id": 9,
"text": "xxx"
},
{
"id": 21,
"text": "xxx"
},
...
]
```
如果选项过多可通过ajax方式动态分页载入选项
```php
$form->select('user_id')->options(function ($id) {
$user = User::find($id);
if ($user) {
return [$user->id => $user->name];
}
})->ajax('/admin/api/users');
```
<sub>注:如果你修改了`config/admin.php`配置文件中`route.prefix`的值,此处的接口路由应该修改为`config('admin.route.prefix').'/api/users'`</sub>
API `/admin/api/users`接口的代码:
```php
public function users(Request $request)
{
$q = $request->get('q');
return User::where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
}
```
接口返回的数据结构为
```
{
"total": 4,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"next_page_url": null,
"prev_page_url": null,
"from": 1,
"to": 3,
"data": [
{
"id": 9,
"text": "xxx"
},
{
"id": 21,
"text": "xxx"
},
{
"id": 42,
"text": "xxx"
},
{
"id": 48,
"text": "xxx"
}
]
}
```
### select 联动
`select`组件支持父子关系的单向联动:
```php
$form->select('province')->options(...)->load('city', '/api/city');
$form->select('city');
```
其中`load('city', '/api/city');`的意思是在当前select的选项切换之后会把当前选项的值通过参数`q`, 调用接口`/api/city`并把api返回的数据填充为city选择框的选项其中api`/api/city`返回的数据格式必须符合:
```php
[
{
"id": 9,
"text": "xxx"
},
{
"id": 21,
"text": "xxx"
},
...
]
```
控制器action的代码示例如下
```php
public function city(Request $request)
{
$provinceId = $request->get('q');
return ChinaArea::city()->where('parent_id', $provinceId)->get(['id', DB::raw('name as text')]);
}
```
## 多选框
```php
$form->multipleSelect($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
// 使用ajax并显示所选项目
$form->multipleSelect($column[, $label])->options(Model::class)->ajax('ajax_url');
// 或指定名称和ID
$form->multipleSelect($column[, $label])->options(Model::class, 'name', 'id')->ajax('ajax_url');
```
多选框可以处理两种情况,第一种是`ManyToMany`的关系。
```
class Post extends Models
{
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
$form->multipleSelect('tags')->options(Tag::all()->pluck('name', 'id'));
```
第二种是将选项数组存储到单字段中,如果字段是字符串类型,那就需要在模型里面为该字段定义[访问器和修改器](https://laravel.com/docs/5.5/eloquent-mutators)来存储和读取了。
如果选项过多可通过ajax方式动态分页载入选项
```php
$form->select('friends')->options(function ($ids) {
return User::find($ids)->pluck('name', 'id');
})->ajax('/admin/api/users');
```
<sub>注:如果你修改了`config/admin.php`配置文件中`route.prefix`的值,此处的接口路由应该修改为`config('admin.route.prefix').'/api/users'`</sub>
API `/admin/api/users`接口的代码:
```php
public function users(Request $request)
{
$q = $request->get('q');
return User::where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
}
```
接口返回的数据结构为
```
{
"total": 4,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"next_page_url": null,
"prev_page_url": null,
"from": 1,
"to": 3,
"data": [
{
"id": 9,
"text": "xxx"
},
{
"id": 21,
"text": "xxx"
},
{
"id": 42,
"text": "xxx"
},
{
"id": 48,
"text": "xxx"
}
]
}
```
## listbox
使用方法和`multipleSelect`类似
```php
$form->listbox($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
```
## textarea输入框
```php
$form->textarea($column[, $label])->rows(10);
```
## radio选择
```php
$form->radio($column[, $label])->options(['m' => 'Female', 'f'=> 'Male'])->default('m');
// 竖排
$form->radio($column[, $label])->options(['m' => 'Female', 'f'=> 'Male'])->stacked();
```
## checkbox选择
`checkbox`能处理两种数据存储情况,参考[多选框](#多选框)
`options()`方法用来设置选择项:
```php
$form->checkbox($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
// 竖排
$form->checkbox($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name'])->stacked();
```
## email个数输入框
```php
$form->email($column[, $label]);
```
## 密码输入框
```php
$form->password($column[, $label]);
```
## url输入框
```php
$form->url($column[, $label]);
```
## ip输入框
```php
$form->ip($column[, $label]);
```
## 电话号码输入框
```php
$form->mobile($column[, $label])->options(['mask' => '999 9999 9999']);
```
## 颜色选择框
```php
$form->color($column[, $label])->default('#ccc');
```
## 时间输入框
```php
$form->time($column[, $label]);
// 设置时间格式更多格式参考http://momentjs.com/docs/#/displaying/format/
$form->time($column[, $label])->format('HH:mm:ss');
```
## 日期输入框
```php
$form->date($column[, $label]);
// 设置日期格式更多格式参考http://momentjs.com/docs/#/displaying/format/
$form->date($column[, $label])->format('YYYY-MM-DD');
```
## 日期时间输入框
```php
$form->datetime($column[, $label]);
// 设置日期格式更多格式参考http://momentjs.com/docs/#/displaying/format/
$form->datetime($column[, $label])->format('YYYY-MM-DD HH:mm:ss');
```
## 时间范围选择框
`$startTime``$endTime`为开始和结束时间字段:
```php
$form->timeRange($startTime, $endTime, 'Time Range');
```
## 日期范围选框
`$startDate``$endDate`为开始和结束日期字段:
```php
$form->dateRange($startDate, $endDate, 'Date Range');
```
## 时间日期范围选择框
`$startDateTime``$endDateTime`为开始和结束时间日期:
```php
$form->datetimeRange($startDateTime, $endDateTime, 'DateTime Range');
```
## 货币输入框
```php
$form->currency($column[, $label]);
// 设置单位符号
$form->currency($column[, $label])->symbol('¥');
```
## 数字输入框
```php
$form->number($column[, $label]);
```
## 比例输入框
```php
$form->rate($column[, $label]);
```
## 图片上传
使用图片上传功能之前需要先完成上传配置,请参考:[图片/文件上传](/zh/model-form-upload.md).
图片上传目录在文件`config/admin.php`中的`upload.image`中配置,如果目录不存在,需要创建该目录并开放写权限。
可以使用压缩、裁切、添加水印等各种方法,需要先安装[intervention/image](http://image.intervention.io/getting_started/installation).
更多使用方法请参考[[Intervention](http://image.intervention.io/getting_started/introduction)]
```php
$form->image($column[, $label]);
// 修改图片上传路径和文件名
$form->image($column[, $label])->move($dir, $name);
// 剪裁图片
$form->image($column[, $label])->crop(int $width, int $height, [int $x, int $y]);
// 加水印
$form->image($column[, $label])->insert($watermark, 'center');
// 添加图片删除按钮
$form->image($column[, $label])->removable();
```
## 文件上传
使用图片上传功能之前需要先完成上传配置,请参考:[图片/文件上传](/zh/model-form-upload.md).
文件上传目录在文件`config/admin.php`中的`upload.file`中配置,如果目录不存在,需要创建该目录并开放写权限。
```php
$form->file($column[, $label]);
// 修改文件上传路径和文件名
$form->file($column[, $label])->move($dir, $name);
// 并设置上传文件类型
$form->file($column[, $label])->rules('mimes:doc,docx,xlsx');
// 添加文件删除按钮
$form->file($column[, $label])->removable();
```
## 多图/文件上传
```php
// 多图
$form->multipleImage($column[, $label]);
// 添加删除按钮
$form->multipleImage($column[, $label])->removable();
// 多文件
$form->multipleFile($column[, $label]);
// 添加删除按钮
$form->multipleFile($column[, $label])->removable();
```
多图/文件上传的时候提交的数据为文件路径数组,可以直接用mysql的`JSON`类型字段存储,如果用mongodb的话也能直接存储,但是如果用字符串类型来存储的话,就需要指定数据的存储格式了,
比如,如果要用json字符串来存储文件数据,就需要在模型中定义字段的mutator,比如字段名为`pictures`,定义mutator:
```php
public function setPicturesAttribute($pictures)
{
if (is_array($pictures)) {
$this->attributes['pictures'] = json_encode($pictures);
}
}
public function getPicturesAttribute($pictures)
{
return json_decode($pictures, true);
}
```
当然你也可以指定其它任何格式.
## 地图控件
地图组件引用了网络资源,默认关闭,如果要开启这个组件参考[form组件管理](/zh/model-form-field-management.md)
地图控件,用来选择经纬度,`$latitude`, `$longitude`为经纬度字段,`Laravel``locale`设置为`zh_CN`的时候使用腾讯地图否则使用Google地图
```php
$form->map($latitude, $longitude, $label);
```
## 滑动选择控件
可以用来数字类型字段的选择,比如年龄:
```php
$form->slider($column[, $label])->options(['max' => 100, 'min' => 1, 'step' => 1, 'postfix' => 'years old']);
```
更多options请参考:https://github.com/IonDen/ion.rangeSlider#settings
## 富文本编辑框
编辑器组件引用了网络资源,默认关闭,如果要开启这个组件参考[form组件管理](/zh/model-form-field-management.md).
```php
$form->editor($column[, $label]);
```
## 隐藏域
```php
$form->hidden($column);
```
## 开关选择
`on``off`对用开关的两个值`1``0`:
```php
$states = [
'on' => ['value' => 1, 'text' => '打开', 'color' => 'success'],
'off' => ['value' => 0, 'text' => '关闭', 'color' => 'danger'],
];
$form->switch($column[, $label])->states($states);
```
## 显示字段
只显示字段,不做任何操作:
```php
$form->display($column[, $label]);
//更复杂的显示
$form->display($column[, $label])->with(function ($value) {
return "<img src="$value" />";
});
```
## 分割线
```php
$form->divide();
```
## Html
插入html内容参数可以是实现了`Htmlable``Renderable`或者实现了`__toString()`方法的类
```php
$form->html('你的html内容', $label = '');
```
## 标签
插入逗号(,)隔开的字符串`tags`
```php
$form->tags('keywords');
```
`tags`同样支持`ManyToMany`的关系,示例如下:
```php
$form->tags('tags', '文章标签')
->pluck('name', 'id') // name 为需要显示的 Tag 模型的字段id 为主键
->options(Tag::all());// 下拉框选项
```
注意:处理`ManyToMany`关系时必须调用`pluck`方法,指定显示的字段名和主键。
此外 `options` 方法传入一个`Collection`对象时,`options`会自动调用该对象的`pluck`方法转为`['主键名' => '显示字段名']` 数组,作为下拉框选项。或者可以直接使用`['主键名' => '显示字段名']`这样的数组作为参数。
`tags`还支持`saving`方法用于处理提交的数据,示例如下:
```php
$form->tags('tags', '文章标签')
->pluck('name', 'id')
->options(Tag::all())
->saving(function ($value) {
return $value;
});
```
`saving` 方法接收一个「参数为 tags 的提交值,返回值为修改后的 tags 提交值」的闭包,可以用于实现自动创建新 tag 或其它功能。
## 图标
选择`font-awesome`图标
```php
$form->icon('icon');
```
## 一对多
一对多内嵌表格,用于处理一对多的关系,下面是个简单的例子:
有两张表是一对多关系:
```sql
CREATE TABLE `demo_painters` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`bio` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `demo_paintings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`painter_id` int(10) unsigned NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`body` text COLLATE utf8_unicode_ci NOT NULL,
`completed_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY painter_id (`painter_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
表的模型为:
```php
<?php
namespace App\Models\Demo;
use Illuminate\Database\Eloquent\Model;
class Painter extends Model
{
public function paintings()
{
return $this->hasMany(Painting::class, 'painter_id');
}
}
<?php
namespace App\Models\Demo;
use Illuminate\Database\Eloquent\Model;
class Painting extends Model
{
protected $fillable = ['title', 'body', 'completed_at'];
public function painter()
{
return $this->belongsTo(Painter::class, 'painter_id');
}
}
```
构建表单代码如下:
```php
$form->display('id', 'ID');
$form->text('username')->rules('required');
$form->textarea('bio')->rules('required');
$form->hasMany('paintings', function (Form\NestedForm $form) {
$form->text('title');
$form->image('body');
$form->datetime('completed_at');
});
$form->display('created_at', 'Created At');
$form->display('updated_at', 'Updated At');
// 也可以设置label
$form->hasMany('paintings', '画作', function (Form\NestedForm $form) {
});
```
## 内嵌
用于处理`mysql``JSON`类型字段数据或者`mongodb``object`类型数据也可以将多个field的数据值以`JSON`字符串的形式存储在`mysql`的字符串类型字段中
比如`orders`表中的`JSON`或字符串类型的`extra`字段用来存储多个field的数据先定义model:
```php
class Order extends Model
{
protected $casts = [
'extra' => 'json',
];
}
```
然后在form中使用
```php
$form->embeds('extra', function ($form) {
$form->text('extra1')->rules('required');
$form->email('extra2')->rules('required');
$form->mobile('extra3');
$form->datetime('extra4');
$form->dateRange('extra5', 'extra6', '范围')->rules('required');
});
// 自定义标题
$form->embeds('extra', '附加信息', function ($form) {
...
});
```
回调函数里面构建表单元素的方法调用和外面是一样的。

View File

@@ -0,0 +1,113 @@
# 文件/图片上传
[model-form](/zh/model-form.md)通过以下的调用来生成form元素。
```php
$form->file('file_column');
$form->image('image_column');
```
## 修改存储路径或文件名
```php
// 修改上传目录
$form->image('picture')->move('public/upload/image1/');
// 使用随机生成文件名 (md5(uniqid()).extension)
$form->image('picture')->uniqueName();
// 自定义文件名
$form->image('picture')->name(function ($file) {
return 'test.'.$file->guessExtension();
});
```
[model-form](/zh/model-form.md)支持本地和云存储的文件上传
## 本地上传
先添加存储配置,`config/filesystems.php` 添加一项`disk`:
```php
'disks' => [
... ,
'admin' => [
'driver' => 'local',
'root' => public_path('uploads'),
'visibility' => 'public',
'url' => env('APP_URL').'/uploads',
],
],
```
设置上传的路径为`public/uploads`(public_path('uploads'))。
然后选择上传的`disk`,打开`config/admin.php`找到:
```php
'upload' => [
'disk' => 'admin',
'directory' => [
'image' => 'images',
'file' => 'files',
]
],
```
`disk`设置为上面添加的`admin``directory.image``directory.file`分别为用`$form->image($column)``$form->file($column)`上传的图片和文件的上传目录。
## 云盘上传
如果需要上传到云存储,需要安装对应`laravel storage`的适配器,拿七牛云存储举例
首先安装 [zgldh/qiniu-laravel-storage](https://github.com/zgldh/qiniu-laravel-storage)
同样配置好disk`config/filesystems.php` 添加一项:
```php
'disks' => [
... ,
'qiniu' => [
'driver' => 'qiniu',
'domains' => [
'default' => 'xxxxx.com1.z0.glb.clouddn.com', //你的七牛域名
'https' => 'dn-yourdomain.qbox.me', //你的HTTPS域名
'custom' => 'static.abc.com', //你的自定义域名
],
'access_key'=> '', //AccessKey
'secret_key'=> '', //SecretKey
'bucket' => '', //Bucket名字
'notify_url'=> '', //持久化处理回调地址
'url' => 'http://of8kfibjo.bkt.clouddn.com/', // 填写文件访问根url
],
],
```
然后修改`laravel-admin`的上传配置,打开`config/admin.php`找到:
```php
'upload' => [
'disk' => 'qiniu',
'directory' => [
'image' => 'image',
'file' => 'file',
],
],
```
`disk`选择上面配置的`qiniu`

View File

@@ -0,0 +1,36 @@
表单验证
========
`model-form`使用laravel的验证规则来验证表单提交的数据
```php
$form->text('title')->rules('required|min:3');
// 复杂的验证规则可以在回调里面实现
$form->text('title')->rules(function ($form) {
// 如果不是编辑状态,则添加字段唯一验证
if (!$id = $form->model()->id) {
return 'unique:users,email_address';
}
});
```
也可以给验证规则自定义错误提示消息:
```php
$form->text('code')->rules('required|regex:/^\d+$/|min:10', [
'regex' => 'code必须全部为数字',
'min' => 'code不能少于10个字符',
]);
```
如果要允许字段为空,首先要在数据库的表里面对该字段设置为`NULL`,然后
```php
$form->text('title')->rules('nullable');
```
更多规则请参考[Validation](https://laravel.com/docs/5.5/validation).

View File

@@ -0,0 +1,180 @@
# 基于数据模型的表单
`Encore\Admin\Form`类用于生成基于数据模型的表单,先来个例子,数据库中有`movies`
```sql
CREATE TABLE `movies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`director` int(10) unsigned NOT NULL,
`describe` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`rate` tinyint unsigned NOT NULL,
`released` enum(0, 1),
`release_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
对应的数据模型为`App\Models\Movie`,下面的代码可以生成`movies`的数据表单:
```php
use App\Models\Movie;
use Encore\Admin\Form;
use Encore\Admin\Facades\Admin;
$grid = Admin::form(Movie::class, function(Form $form){
// 显示记录id
$form->display('id', 'ID');
// 添加text类型的input框
$form->text('title', '电影标题');
$directors = [
1 => 'John',
2 => 'Smith',
3 => 'Kate',
];
$form->select('director', '导演')->options($directors);
// 添加describe的textarea输入框
$form->textarea('describe', '简介');
// 数字输入框
$form->number('rate', '打分');
// 添加开关操作
$form->switch('released', '发布?');
// 添加日期时间选择框
$form->dateTime('release_at', '发布时间');
// 两个时间显示
$form->display('created_at', '创建时间');
$form->display('updated_at', '修改时间');
});
```
## 自定义工具
表单右上角默认有返回和跳转列表两个按钮工具, 可以使用下面的方式修改它:
```php
$form->tools(function (Form\Tools $tools) {
// 去掉返回按钮
$tools->disableBackButton();
// 去掉跳转列表按钮
$tools->disableListButton();
// 添加一个按钮, 参数可以是字符串, 或者实现了Renderable或Htmlable接口的对象实例
$tools->add('<a class="btn btn-sm btn-danger"><i class="fa fa-trash"></i>&nbsp;&nbsp;delete</a>');
});
```
## 其它方法
去掉提交按钮:
```php
$form->disableSubmit();
```
去掉重置按钮:
```php
$form->disableReset();
```
忽略掉不需要保存的字段
```php
$form->ignore(['column1', 'column2', 'column3']);
```
设置宽度
```php
$form->setWidth(10, 2);
```
设置表单提交的action
```php
$form->setAction('admin/users');
```
## 关联模型
### 一对一
`users`表和`profiles`表通过`profiles.user_id`字段生成一对一关联
```sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `profiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`age` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`gender` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
对应的数据模分别为:
```php
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
```
通过下面的代码可以关联在一个form里面:
```php
Admin::form(User::class, function (Form $form) {
$form->display('id');
$form->text('name');
$form->text('email');
$form->text('profile.age');
$form->text('profile.gender');
$form->datetime('created_at');
$form->datetime('updated_at');
});
```

View File

@@ -0,0 +1,91 @@
# 模型表格行操作
`model-grid`默认有三个行操作`编辑``删除``详情`,可以通过下面的方式关闭它们:
```php
$grid->actions(function ($actions) {
$actions->disableDelete();
$actions->disableEdit();
$actions->disableView();
});
```
可以通过传入的`$actions`参数来获取当前行的数据:
```php
$grid->actions(function ($actions) {
// 当前行的数据数组
$actions->row;
// 获取当前行主键值
$actions->getKey();
});
```
如果有自定义的操作按钮,可以通过下面的方式添加:
```php
$grid->actions(function ($actions) {
// append一个操作
$actions->append('<a href=""><i class="fa fa-eye"></i></a>');
// prepend一个操作
$actions->prepend('<a href=""><i class="fa fa-paper-plane"></i></a>');
}
```
如果有比较复杂的操作,可以参考下面的方式:
先定义操作类
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Admin;
class CheckRow
{
protected $id;
public function __construct($id)
{
$this->id = $id;
}
protected function script()
{
return <<<SCRIPT
$('.grid-check-row').on('click', function () {
// Your code.
console.log($(this).data('id'));
});
SCRIPT;
}
protected function render()
{
Admin::script($this->script());
return "<a class='btn btn-xs btn-success fa fa-check grid-check-row' data-id='{$this->id}'></a>";
}
public function __toString()
{
return $this->render();
}
}
```
然后添加操作:
```php
$grid->actions(function ($actions) {
// 添加操作
$actions->append(new CheckRow($actions->getKey()));
});
```

View File

@@ -0,0 +1,343 @@
# 列操作
`model-grid`内置了很多对于列的操作方法,可以通过这些方法很灵活的操作列数据。
`Encore\Admin\Grid\Column`对象内置了`display()`方法来通过传入的回调函数来处理当前列的值,
```php
$grid->column('title')->display(function ($title) {
return "<span style='color:blue'>$title</span>";
});
```
在传入的匿名函数中可以通过任何方式对数据进行处理,另外匿名函数绑定了当前列的数据作为父对象,可以在函数中调用当前行的数据:
```php
$grid->first_name();
$grid->last_name();
// 不存在的`full_name`字段
$grid->column('full_name')->display(function () {
return $this->first_name . ' ' . $this->last_name;
});
```
> `value()`方法作为`display()`方法的别名存在
## 内置方法
`model-grid`内置了若干方法来帮助你扩展列功能
### editable
通过`editable.js`的帮助,可以让你在表格中直接编辑数据,使用方法如下
```php
$grid->title()->editable();
$grid->title()->editable('textarea');
$grid->title()->editable('select', [1 => 'option1', 2 => 'option2', 3 => 'option3']);
// select 支持传递闭包作为参数,该闭包接收参数为当前行对应的模型
$grid->title()->editable('select', function($row) {
if ($row->title === 'test') {
return ['test1', 'test2'];
}
return ['test3', 'test4'];
});
$grid->birth()->editable('date');
$grid->published_at()->editable('datetime');
$grid->column('year')->editable('year');
$grid->column('month')->editable('month');
$grid->column('day')->editable('day');
```
### switch
> 注意:在`grid`中对某字段设置了`switch`,同时需要在`form`里面对该字段设置同样的`switch`
快速将列变成开关组件,使用方法如下:
```php
$grid->status()->switch();
// 设置text、color、和存储值
$states = [
'on' => ['value' => 1, 'text' => '打开', 'color' => 'primary'],
'off' => ['value' => 2, 'text' => '关闭', 'color' => 'default'],
];
$grid->status()->switch($states);
```
### switchGroup
> 注意:在`grid`中对某些字段设置了`switch`,同时需要在`form`里面对这些字段设置同样的`switch`
快速将列变成开关组件组,使用方法如下:
```php
$states = [
'on' => ['text' => 'YES'],
'off' => ['text' => 'NO'],
];
$grid->column('switch_group')->switchGroup([
'hot' => '热门',
'new' => '最新',
'recommend' => '推荐',
'image.show' => '显示图片', // 更新对应关联模型
], $states);
```
### select
```php
$grid->options()->select([
1 => 'Sed ut perspiciatis unde omni',
2 => 'voluptatem accusantium doloremque',
3 => 'dicta sunt explicabo',
4 => 'laudantium, totam rem aperiam',
]);
```
`select` 也支持参数为闭包,使用方法和`editable``select`类似。
### radio
```php
$grid->options()->radio([
1 => 'Sed ut perspiciatis unde omni',
2 => 'voluptatem accusantium doloremque',
3 => 'dicta sunt explicabo',
4 => 'laudantium, totam rem aperiam',
]);
```
`radio` 也支持参数为闭包,使用方法和`editable``select`类似。
### checkbox
```php
$grid->options()->checkbox([
1 => 'Sed ut perspiciatis unde omni',
2 => 'voluptatem accusantium doloremque',
3 => 'dicta sunt explicabo',
4 => 'laudantium, totam rem aperiam',
]);
```
`checkbox` 也支持参数为闭包,使用方法和`editable``select`类似。
### image
```php
$grid->picture()->image();
//设置服务器和宽高
$grid->picture()->image('http://xxx.com', 100, 100);
// 显示多图
$grid->pictures()->display(function ($pictures) {
return json_decode($pictures, true);
})->image('http://xxx.com', 100, 100);
```
### label
```php
$grid->name()->label();
//设置颜色,默认`success`,可选`danger`、`warning`、`info`、`primary`、`default`、`success`
$grid->name()->label('danger');
// 接收数组
$grid->keywords()->label();
```
### badge
```php
$grid->name()->badge();
//设置颜色,默认`success`,可选`danger`、`warning`、`info`、`primary`、`default`、`success`
$grid->name()->badge('danger');
// 接收数组
$grid->keywords()->badge();
```
## 扩展列功能
可以通过两种方式扩展列功能,第一种是通过匿名函数的方式。
`app/Admin/bootstrap.php`加入以下代码:
```php
use Encore\Admin\Grid\Column;
Column::extend('color', function ($value, $color) {
return "<span style='color: $color'>$value</span>"
});
```
然后在`model-grid`中使用这个扩展:
```php
$grid->title()->color('#ccc');
```
如果列显示逻辑比较复杂,可以通过扩展类来实现。
扩展类`app/Admin/Extensions/Popover.php`:
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Admin;
use Encore\Admin\Grid\Displayers\AbstractDisplayer;
class Popover extends AbstractDisplayer
{
public function display($placement = 'left')
{
Admin::script("$('[data-toggle=\"popover\"]').popover()");
return <<<EOT
<button type="button"
class="btn btn-secondary"
title="popover"
data-container="body"
data-toggle="popover"
data-placement="$placement"
data-content="{$this->value}"
>
弹出提示
</button>
EOT;
}
}
```
然后在`app/Admin/bootstrap.php`注册扩展类:
```php
use Encore\Admin\Grid\Column;
use App\Admin\Extensions\Popover;
Column::extend('popover', Popover::class);
```
然后就能在`model-grid`中使用了:
```php
$grid->desciption()->popover('right');
```
## 帮助方法
### 字符串操作
如果当前里的输出数据为字符串,那么可以通过链式方法调用`Illuminate\Support\Str`的方法。
比如有如下一列,显示`title`字段的字符串值:
```php
$grid->title();
```
`title`列输出的字符串基础上调用`Str::limit()`方法
```php
$grid->title()->limit(30);
```
调用方法之后输出的还是字符串,所以可以继续调用`Illuminate\Support\Str`的方法:
```php
$grid->title()->limit(30)->ucfirst();
$grid->title()->limit(30)->ucfirst()->substr(1, 10);
```
### 数组操作
如果当前列输出的是数组,可以直接链式调用`Illuminate\Support\Collection`方法。
比如`tags`列是从一对多关系取出来的数组数据:
```php
$grid->tags();
array (
0 =>
array (
'id' => '16',
'name' => 'php',
'created_at' => '2016-11-13 14:03:03',
'updated_at' => '2016-12-25 04:29:35',
),
1 =>
array (
'id' => '17',
'name' => 'python',
'created_at' => '2016-11-13 14:03:09',
'updated_at' => '2016-12-25 04:30:27',
),
)
```
调用`Collection::pluck()`方法取出数组的中的`name`
```php
$grid->tags()->pluck('name');
array (
0 => 'php',
1 => 'python',
),
```
取出`name`列之后输出的还是数组,还能继续调用用`Illuminate\Support\Collection`的方法
```php
$grid->tags()->pluck('name')->map('ucwords');
array (
0 => 'Php',
1 => 'Python',
),
```
将数组输出为字符串
```php
$grid->tags()->pluck('name')->map('ucwords')->implode('-');
"Php-Python"
```
### 混合使用
在上面两种类型的方法调用中,只要上一步输出的是确定类型的值,便可以调用类型对应的方法,所以可以很灵活的混合使用。
比如`images`字段是存储多图片地址数组的JSON格式字符串类型
```php
$grid->images();
"['foo.jpg', 'bar.png']"
// 链式方法调用来显示多图
$grid->images()->display(function ($images) {
return json_decode($images, true);
})->map(function ($path) {
return 'http://localhost/images/'. $path;
})->image();
```

View File

@@ -0,0 +1,174 @@
# 自定义工具
`model-grid`的头部默认有`批量删除``刷新`两个操作工具,如果有更多的操作需求,`model-grid`提供了自定义工具的功能,下面的示例添加一个性别分类选择的按钮组工具。
先定义工具类`app/Admin/Extensions/Tools/UserGender.php`
```php
<?php
namespace App\Admin\Extensions\Tools;
use Encore\Admin\Admin;
use Encore\Admin\Grid\Tools\AbstractTool;
use Illuminate\Support\Facades\Request;
class UserGender extends AbstractTool
{
protected function script()
{
$url = Request::fullUrlWithQuery(['gender' => '_gender_']);
return <<<EOT
$('input:radio.user-gender').change(function () {
var url = "$url".replace('_gender_', $(this).val());
$.pjax({container:'#pjax-container', url: url });
});
EOT;
}
public function render()
{
Admin::script($this->script());
$options = [
'all' => 'All',
'm' => 'Male',
'f' => 'Female',
];
return view('admin.tools.gender', compact('options'));
}
}
```
视图`admin.tools.gender`文件为`resources/views/admin/tools/gender.blade.php`:
```php
<div class="btn-group" data-toggle="buttons">
@foreach($options as $option => $label)
<label class="btn btn-default btn-sm {{ \Request::get('gender', 'all') == $option ? 'active' : '' }}">
<input type="radio" class="user-gender" value="{{ $option }}">{{$label}}
</label>
@endforeach
</div>
```
`model-grid`引入这个工具:
```php
$grid->tools(function ($tools) {
$tools->append(new UserGender());
});
```
`model-grid`定义中接收到`gender`参数后,做好数据查询就可以了:
```php
if (in_array(Request::get('gender'), ['m', 'f'])) {
$grid->model()->where('gender', Request::get('gender'));
}
```
可以参考上面的方式来添加自己的工具。
## 批量操作
目前默认实现了批量删除操作的功能,如果要关掉批量删除操作:
```php
$grid->tools(function ($tools) {
$tools->batch(function ($batch) {
$batch->disableDelete();
});
});
```
如果要添加自定义的批量操作,可以参考下面的例子。
下面是扩展一个对文章批量发布的功能:
先定义操作类`app/Admin/Extensions/Tools/ReleasePost.php`
```php
<?php
namespace App\Admin\Extensions\Tools;
use Encore\Admin\Grid\Tools\BatchAction;
class ReleasePost extends BatchAction
{
protected $action;
public function __construct($action = 1)
{
$this->action = $action;
}
public function script()
{
return <<<EOT
$('{$this->getElementClass()}').on('click', function() {
$.ajax({
method: 'post',
url: '{$this->resource}/release',
data: {
_token:LA.token,
ids: selectedRows(),
action: {$this->action}
},
success: function () {
$.pjax.reload('#pjax-container');
toastr.success('操作成功');
}
});
});
EOT;
}
}
```
看代码的实现通过click操作发送一个post请求把选中的行数据`id`通过数组的形式传给后端接口,后端接口拿到`id`列表和要修改的状态来更新数据,然后前端刷新页面(pjax reload),并弹出`toastr`提示操作成功。
`model-grid`中加入这个批量操作功能:
```php
$grid->tools(function ($tools) {
$tools->batch(function ($batch) {
$batch->add('发布文章', new ReleasePost(1));
$batch->add('文章下线', new ReleasePost(0));
});
});
```
这样批量操作下拉按钮下面就会添加两个操作项,最后一步就是添加一个接口来处理批量操作的请求了,接口代码如下:
```php
class PostController extends Controller
{
...
public function release(Request $request)
{
foreach (Post::find($request->get('ids')) as $post) {
$post->released = $request->get('action');
$post->save();
}
}
...
}
```
然后添加路由指向上面的接口:
```php
$router->post('posts/release', 'PostController@release');
```
这样整个流程就完成了。

View File

@@ -0,0 +1,121 @@
# 表格数据源
## 数据来自模型
如果使用模型来获取数据,那么修改来源数据就非常简单:
```php
// 添加默认查询条件
$grid->model()->where('id', '>', 100);
// 设置初始排序条件
$grid->model()->orderBy('id', 'desc');
...
```
其它查询方法可以参考`eloquent`的查询方法.
## 数据来自外部API
如果数据是来自外部的API需要展示在数据表格中那么可以建立model,然后覆盖掉模型的几个获取数据的方法来实现, 下面的例子用`豆瓣电影`的API获取并展示数据
```php
<?php
namespace App\Models\Movie;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Request;
class InTheater extends Model
{
public function paginate()
{
$perPage = Request::get('per_page', 10);
$page = Request::get('page', 1);
$start = ($page-1)*$perPage;
$data = file_get_contents("https://api.douban.com/v2/movie/in_theaters?city=上海&start=$start&count=$perPage");
$data = json_decode($data, true);
extract($data);
$movies = static::hydrate($subjects);
$paginator = new LengthAwarePaginator($movies, $total, $perPage);
$paginator->setPath(url()->current());
return $paginator;
}
public static function with($relations)
{
return new static;
}
}
```
通过覆盖模型的`paginate``with`方法获取API数据, 通过`findOrFail`方法来获取单项数据展示在表单中
同理如果要在form表单中获取或者保存数据那么也可以通过覆盖相应的方法来实现
```php
// 获取单项数据展示在form中
public function findOrFail($id)
{
$data = file_get_contents("http://api.douban.com/v2/movie/subject/$id");
$data = json_decode($data, true);
return static::newFromBuilder($data);
}
// 保存提交的form数据
public function save(array $options = [])
{
$attributes = $this->getAttributes();
// save $attributes
}
```
## 数据来自复杂SQL查询
如果来源数据需要执行比较复杂的SQL语句获取那么有两个办法, 第一个办法就是上面的方法覆盖掉model的方法实现
```php
public function paginate()
{
$perPage = Request::get('per_page', 10);
$page = Request::get('page', 1);
$start = ($page-1)*$perPage;
// 运行sql获取数据数组
$sql = 'select * from ...';
$result = DB::select($sql);
$movies = static::hydrate($result);
$paginator = new LengthAwarePaginator($movies, $total, $perPage);
$paginator->setPath(url()->current());
return $paginator;
}
public static function with($relations)
{
return new static;
}
```
第二个方式是在数据库中建立视图和model绑定未测试过理论上可行

View File

@@ -0,0 +1,57 @@
数据导出
=======
`model-grid`内置的导出功能只是实现了简单的csv格式文件的导出如果遇到文件编码问题或者满足不了自己需求的情况可以按照下面的步骤来自定义导出功能
本示例用[Laravel-Excel](https://github.com/Maatwebsite/Laravel-Excel)作为excel操作库当然也可以使用任何其他excel库
首先安装好它:
```shell
composer require maatwebsite/excel:~2.1.0
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"
```
然后新建自定义导出类,比如`app/Admin/Extensions/ExcelExpoter.php`:
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Grid\Exporters\AbstractExporter;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Arr;
class ExcelExpoter extends AbstractExporter
{
public function export()
{
Excel::create('Filename', function($excel) {
$excel->sheet('Sheetname', function($sheet) {
// 这段逻辑是从表格数据中取出需要导出的字段
$rows = collect($this->getData())->map(function ($item) {
return Arr::only($item, ['id', 'title', 'content', 'rate', 'keywords']);
});
$sheet->rows($rows);
});
})->export('xls');
}
}
```
然后在`model-grid`中使用这个导出类:
```php
use App\Admin\Extensions\ExcelExpoter;
$grid->exporter(new ExcelExpoter());
```
有关更多`Laravel-Excel`的使用方法,参考[laravel-excel/docs](http://www.maatwebsite.nl/laravel-excel/docs)

View File

@@ -0,0 +1,33 @@
# 自定义导出
laravel-admin的数据表格默认支持导出csv文件
```php
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Grid\Exporters\AbstractExporter;
class CustomExporter extends AbstractExporter
{
public function export()
{
$filename = $this->getTable().'.csv';
$data = $this->getData();
$output = '';
$headers = [
'Content-Encoding' => 'UTF-8',
'Content-Type' => 'text/csv;charset=UTF-8',
'Content-Disposition' => "attachment; filename=\"$filename\"",
];
response(rtrim($output, "\n"), 200, $headers)->send();
exit;
}
}
```

View File

@@ -0,0 +1,242 @@
# 数据查询过滤
`model-grid`提供了一系列的方法实现表格数据的查询过滤:
```php
$grid->filter(function($filter){
// 去掉默认的id过滤器
$filter->disableIdFilter();
// 自定义id过滤器在去掉默认id过滤器后必须调用 setId 方法,
// 并设置一个和主键不同的值自定义的id过滤器才会显示。
$filter->equal('id', '产品序列号')->setId('product_id');
// 在这里添加字段过滤器
$filter->like('name', 'name');
...
});
```
## 查询类型
目前支持的过滤类型有下面这些:
### equal
`sql: ... WHERE `column` = "$input"`
```php
$filter->equal('column', $label);
```
### not equal
`sql: ... WHERE `column` != "$input"`
```php
$filter->notEqual('column', $label);
```
### like
`sql: ... WHERE `column` LIKE "%$input%"`
```php
$filter->like('column', $label);
```
### ilike
`sql: ... WHERE `column` ILIKE "%$input%"`
```php
$filter->ilike('column', $label);
```
### 大于
`sql: ... WHERE `column` > "$input"`
```php
$filter->gt('column', $label);
```
### 小于
`sql: ... WHERE `column` < "$input"`
```php
$filter->lt('column', $label);
```
### between
`sql: ... WHERE `column` BETWEEN "$start" AND "$end"`
```php
$filter->between('column', $label);
// 设置datetime类型
$filter->between('column', $label)->datetime();
// 设置time类型
$filter->between('column', $label)->time();
```
### in
`sql: ... WHERE `column` in (...$inputs)`
```php
$filter->in('column', $label)->multipleSelect(['key' => 'value']);
```
### notIn
`sql: ... WHERE `column` not in (...$inputs)`
```php
$filter->notIn('column', $label)->multipleSelect(['key' => 'value']);
```
### date
`sql: ... WHERE DATE(`column`) = "$input"`
```php
$filter->date('column', $label);
```
### day
`sql: ... WHERE DAY(`column`) = "$input"`
```php
$filter->day('column', $label);
```
### month
`sql: ... WHERE MONTH(`column`) = "$input"`
```php
$filter->month('column', $label);
```
### year
`sql: ... WHERE YEAR(`column`) = "$input"`
```php
$filter->year('column', $label);
```
### where
可以用where来构建比较复杂的查询过滤
`sql: ... WHERE `title` LIKE "%$input" OR `content` LIKE "%$input"`
```php
$filter->where(function ($query) {
$query->where('title', 'like', "%{$this->input}%")
->orWhere('content', 'like', "%{$this->input}%");
}, 'Text');
```
`sql: ... WHERE `rate` >= 6 AND `created_at` = {$input}`:
```php
$filter->where(function ($query) {
$query->whereRaw("`rate` >= 6 AND `created_at` = {$this->input}");
}, 'Text');
```
关系查询,查询对应关系`profile`的字段:
```php
$filter->where(function ($query) {
$query->whereHas('profile', function ($query) {
$query->where('address', 'like', "%{$this->input}%")->orWhere('email', 'like', "%{$this->input}%");
});
}, '地址或手机号');
```
## 表单类型
### text
表单类型默认是text input可以设置placeholder
```php
$filter->equal('column')->placeholder('请输入。。。');
```
也可以通过下面的一些方法来限制用户输入格式:
```php
$filter->equal('column')->url();
$filter->equal('column')->email();
$filter->equal('column')->integer();
$filter->equal('column')->ip();
$filter->equal('column')->mac();
$filter->equal('column')->mobile();
// $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
$filter->equal('column')->decimal($options = []);
// $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
$filter->equal('column')->currency($options = []);
// $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
$filter->equal('column')->percentage($options = []);
// $options 参考 https://github.com/RobinHerbots/Inputmask, $icon为input前面的图标
$filter->equal('column')->inputmask($options = [], $icon = 'pencil');
```
### select
```php
$filter->equal('column')->select(['key' => 'value'...]);
// 或者从api获取数据api的格式参考model-form的select组件
$filter->equal('column')->select('api/users');
```
### multipleSelect
一般用来配合`in``notIn`两个需要查询数组的查询类型使用,也可以在`where`类型的查询中使用:
```php
$filter->in('column')->multipleSelect(['key' => 'value'...]);
// 或者从api获取数据api的格式参考model-form的multipleSelect组件
$filter->in('column')->multipleSelect('api/users');
```
### radio
比较常见的场景是选择分类
```php
$filter->equal('released')->radio([
'' => 'All',
0 => 'Unreleased',
1 => 'Released',
]);
```
### checkbox
比较常见的场景是配合`whereIn`来做范围筛选
```php
$filter->in('gender')->checkbox([
'm' => 'Male',
'f' => 'Female',
]);
```
### datetime
通过日期时间组件来查询,`$options`的参数和值参考[bootstrap-datetimepicker](http://eonasdan.github.io/bootstrap-datetimepicker/Options/)
```php
$filter->equal('column')->datetime($options);
// `date()` 相当于 `datetime(['format' => 'YYYY-MM-DD'])`
$filter->equal('column')->date();
// `time()` 相当于 `datetime(['format' => 'HH:mm:ss'])`
$filter->equal('column')->time();
// `day()` 相当于 `datetime(['format' => 'DD'])`
$filter->equal('column')->day();
// `month()` 相当于 `datetime(['format' => 'MM'])`
$filter->equal('column')->month();
// `year()` 相当于 `datetime(['format' => 'YYYY'])`
$filter->equal('column')->year();
```

View File

@@ -0,0 +1,404 @@
# 基于数据模型的表格
`Encore\Admin\Grid`类用于生成基于数据模型的表格,先来个例子,数据库中有`movies`
```sql
CREATE TABLE `movies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`director` int(10) unsigned NOT NULL,
`describe` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`rate` tinyint unsigned NOT NULL,
`released` enum(0, 1),
`release_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
对应的数据模型为`App\Models\Movie`,下面的代码可以生成表`movies`的数据表格:
```php
use App\Models\Movie;
use Encore\Admin\Grid;
use Encore\Admin\Facades\Admin;
$grid = Admin::grid(Movie::class, function(Grid $grid){
// 第一列显示id字段并将这一列设置为可排序列
$grid->id('ID')->sortable();
// 第二列显示title字段由于title字段名和Grid对象的title方法冲突所以用Grid的column()方法代替
$grid->column('title');
// 第三列显示director字段通过display($callback)方法设置这一列的显示内容为users表中对应的用户名
$grid->director()->display(function($userId) {
return User::find($userId)->name;
});
// 第四列显示为describe字段
$grid->describe();
// 第五列显示为rate字段
$grid->rate();
// 第六列显示released字段通过display($callback)方法来格式化显示输出
$grid->released('上映?')->display(function ($released) {
return $released ? '是' : '否';
});
// 下面为三个时间字段的列显示
$grid->release_at();
$grid->created_at();
$grid->updated_at();
// filter($callback)方法用来设置表格的简单搜索框
$grid->filter(function ($filter) {
// 设置created_at字段的范围查询
$filter->between('created_at', 'Created Time')->datetime();
});
});
```
## 基本使用方法
#### 添加列
```php
// 直接通过字段名`username`添加列
$grid->username('用户名');
// 效果和上面一样
$grid->column('username', '用户名');
// 添加多列
$grid->columns('email', 'username' ...);
```
#### 修改来源数据
```php
$grid->model()->where('id', '>', 100);
$grid->model()->orderBy('id', 'desc');
$grid->model()->take(100);
...
```
其它查询方法可以参考`eloquent`的查询方法.
#### 设置每页显示行数
```php
// 默认为每页20条
$grid->paginate(15);
```
#### 修改显示输出
```php
use Illuminate\Support\Str;
$grid->text()->display(function($text) {
return Str::limit($text, 30, '...');
});
$grid->name()->display(function ($name) {
return "<span class='label'>$name</span>";
});
$grid->email()->display(function ($email) {
return "mailto:$email";
});
// 添加不存在的字段
$grid->column('column_not_in_table')->display(function () {
return 'blablabla....';
});
```
`display()`方法接收的匿名函数绑定了当前行的数据对象,可以在里面调用当前行的其它字段数据
```php
$grid->first_name();
$grid->last_name();
// 不存的字段列
$grid->column('full_name')->display(function () {
return $this->first_name.' '.$this->last_name;
});
```
#### 禁用创建按钮
```php
$grid->disableCreateButton();
```
#### 禁用分页条
```php
$grid->disablePagination();
```
#### 禁用查询过滤器
```php
$grid->disableFilter();
```
#### 禁用导出数据按钮
```php
$grid->disableExport();
```
#### 禁用行选择checkbox
```php
$grid->disableRowSelector();
```
#### 禁用行操作列
```php
$grid->disableActions();
```
#### 设置分页选择器选项
```php
$grid->perPages([10, 20, 30, 40, 50]);
```
## 关联模型
### 一对一
`users`表和`profiles`表通过`profiles.user_id`字段生成一对一关联
```sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `profiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`age` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`gender` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
对应的数据模分别为:
```php
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
```
通过下面的代码可以关联在一个grid里面:
```php
Admin::grid(User::class, function (Grid $grid) {
$grid->id('ID')->sortable();
$grid->name();
$grid->email();
$grid->column('profile.age');
$grid->column('profile.gender');
//or
$grid->profile()->age();
$grid->profile()->gender();
$grid->created_at();
$grid->updated_at();
});
```
### 一对多
`posts`表和`comments`表通过`comments.post_id`字段生成一对多关联
```sql
CREATE TABLE `posts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`content` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `comments` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`post_id` int(10) unsigned NOT NULL,
`content` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
```
对应的数据模分别为:
```php
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
```
通过下面的代码可以让两个模型在grid里面互相关联:
```php
return Admin::grid(Post::class, function (Grid $grid) {
$grid->id('id')->sortable();
$grid->title();
$grid->content();
$grid->comments('评论数')->display(function ($comments) {
$count = count($comments);
return "<span class='label label-warning'>{$count}</span>";
});
$grid->created_at();
$grid->updated_at();
});
return Admin::grid(Comment::class, function (Grid $grid) {
$grid->id('id');
$grid->post()->title();
$grid->content();
$grid->created_at()->sortable();
$grid->updated_at();
});
```
### 多对多
`users``roles`表通过中间表`role_users`产生多对多关系
```sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(190) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_username_unique` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`slug` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `roles_name_unique` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `role_users` (
`role_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
KEY `role_users_role_id_user_id_index` (`role_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
```
对应的数据模分别为:
```php
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
class Role extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
}
```
通过下面的代码可以让两个模型在grid里面互相关联:
```php
return Admin::grid(User::class, function (Grid $grid) {
$grid->id('ID')->sortable();
$grid->username();
$grid->name();
$grid->roles()->display(function ($roles) {
$roles = array_map(function ($role) {
return "<span class='label label-success'>{$role['name']}</span>";
}, $roles);
return join('&nbsp;', $roles);
});
$grid->created_at();
$grid->updated_at();
});
```

View File

@@ -0,0 +1,118 @@
# 模型树
可以通过`model-tree`来实现一个树状组件,可以用拖拽的方式实现数据的层级、排序等操作,下面是基本的用法.
## 表结构和模型
要使用`model-tree`,要遵守约定的表结构:
```sql
CREATE TABLE `demo_categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL DEFAULT '0',
`order` int(11) NOT NULL DEFAULT '0',
`title` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
```
上面的表格结构里面有三个必要的字段`parent_id``order``title`,其它字段没有要求。
对应的模型为`app/Models/Category.php`:
```php
<?php
namespace App\Models\Demo;
use Encore\Admin\Traits\AdminBuilder;
use Encore\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use ModelTree, AdminBuilder;
protected $table = 'demo_categories';
}
```
表结构中的三个字段`parent_id``order``title`的字段名也是可以修改的:
```php
<?php
namespace App\Models\Demo;
use Encore\Admin\Traits\AdminBuilder;
use Encore\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use ModelTree, AdminBuilder;
protected $table = 'demo_categories';
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->setParentColumn('pid');
$this->setOrderColumn('sort');
$this->setTitleColumn('name');
}
}
```
## 使用方法
然后就是在页面中使用`model-tree`了:
```php
<?php
namespace App\Admin\Controllers\Demo;
use App\Http\Controllers\Controller;
use App\Models\Category;
use Encore\Admin\Form;
use Encore\Admin\Facades\Admin;
use Encore\Admin\Layout\Content;
use Encore\Admin\Controllers\ModelForm;
use Encore\Admin\Tree;
class CategoryController extends Controller
{
use ModelForm;
public function index()
{
return Admin::content(function (Content $content) {
$content->header('树状模型');
$content->body(Category::tree());
});
}
}
```
可以通过下面的方式来修改行数据的显示:
```php
Category::tree(function ($tree) {
$tree->branch(function ($branch) {
$src = config('admin.upload.host') . '/' . $branch['logo'] ;
$logo = "<img src='$src' style='max-width:30px;max-height:30px' class='img'/>";
return "{$branch['id']} - {$branch['title']} $logo";
});
})
```
在回调函数中返回的字符串类型数据,就是在树状组件中的每一行的显示内容,`$branch`参数是当前行的数据数组。
如果要修改模型的查询,用下面的方式
```php
Category::tree(function ($tree) {
$tree->query(function ($model) {
return $model->where('type', 1);
});
})
```
```

View File

@@ -0,0 +1,141 @@
# 权限控制
`laravel-admin`已经内置了`RBAC`权限控制模块,展开左侧边栏的`Auth`,下面有用户、角色、权限三项的管理面板,权限控制的使用如下:
## 路由控制
`laravel-admin 1.5`中,权限和路由是绑定在一起的,在编辑权限页面里面设置当前权限能访问的路由,在`HTTP方法`select框中选择访问路由的方法`HTTP路径`textarea中填写能访问的路径。
比如要添加一个权限,该权限可以以`GET`方式访问路径`/admin/users`,那么`HTTP方法`选择`GET``HTTP路径`填写`/users`
如果要访问前缀是`/admin/users`的所有路径,那么`HTTP路径`填写`/users*`,如果权限包括多个访问路径,换行填写每条路径。
## 页面控制
如果你要在页面中控制用户的权限,可以参考下面的例子
### 场景1
比如现在有一个场景,对文章发布模块做权限管理,以创建文章为例
首先创建一项权限,进入`http://localhost/admin/auth/permissions`权限标识slug填写`create-post`,权限名称填写`创建文章`,这样权限就创建好了。
第二步可以把这个权限直接附加给个人或者角色,在用户编辑页面可以直接把上面创建好的权限附加给当前编辑用户,也可以在编辑角色页面附加给某个角色。
第三步,在创建文章控制器里面添加控制代码:
```php
use Encore\Admin\Auth\Permission;
class PostController extends Controller
{
public function create()
{
// 检查权限有create-post权限的用户或者角色可以访问创建文章页面
Permission::check('create-post');
}
}
```
这样就完成了一个页面的权限控制。
### 场景2
如果你要在表格中控制用户对元素的显示,那么需要先定义两个权限,比如权限标示`delete-image`、和`view-title-column`分别用来控制有删除图片的权限和显示某一列的权限把这两个权限赋给你设置的角色然后在grid中加入代码
```php
$grid->actions(function ($actions) {
// 没有`delete-image`权限的角色不显示删除按钮
if (!Admin::user()->can('delete-image')) {
$actions->disableDelete();
}
});
// 只有具有`view-title-column`权限的用户才能显示`title`这一列
if (Admin::user()->can('view-title-column')) {
$grid->column('title');
}
```
## 相关方法
获取当前用户对象
```php
Admin::user();
```
获取当前用户id
```php
Admin::user()->id;
```
获取用户角色
```php
Admin::user()->roles;
```
获取用户的权限
```php
Admin::user()->permissions;
```
用户是否某个角色
```php
Admin::user()->isRole('developer');
```
是否有某个权限
```php
Admin::user()->can('create-post');
```
是否没有某个权限
```php
Admin::user()->cannot('delete-post');
```
是否是超级管理员
```php
Admin::user()->isAdministrator();
```
是否是其中的角色
```php
Admin::user()->inRoles(['editor', 'developer']);
```
## 权限中间件
可以在路由配置上结合权限中间件来控制路由的权限
```php
// 允许administrator、editor两个角色访问group里面的路由
Route::group([
'middleware' => 'admin.permission:allow,administrator,editor',
], function ($router) {
$router->resource('users', UserController::class);
...
});
// 禁止developer、operator两个角色访问group里面的路由
Route::group([
'middleware' => 'admin.permission:deny,developer,operator',
], function ($router) {
$router->resource('users', UserController::class);
...
});
// 有edit-post、create-post、delete-post三个权限的用户可以访问group里面的路由
Route::group([
'middleware' => 'admin.permission:check,edit-post,create-post,delete-post',
], function ($router) {
$router->resource('posts', PostController::class);
...
});
```
权限中间件和其它中间件使用方法一致。

View File

@@ -0,0 +1,59 @@
# 常见问题汇总
## 重写内置视图
如果有需要自己修改view但是不方便直接修改`laravel-admin`的情况,可以用下面的办法解决
复制`vendor/encore/laravel-admin/views`到项目的`resources/views/admin`,然后在`app/Admin/bootstrap.php`文件中加入代码:
```php
app('view')->prependNamespace('admin', resource_path('views/admin'));
```
这样就用`resources/views/admin`下的视图覆盖了`laravel-admin`的视图,要注意的问题是,更新`laravel-admin`的时候,如果遇到视图方面的问题,需要重新复制`vendor/encore/laravel-admin/views`到项目的`resources/views/admin`中,注意备份原来已经修改过的视图。
## 设置语言
完成安装之后,默认语言为英文(en),如果要使用中文,打开`config/app.php`,将`locale`设置为`zh-CN`即可。
## 关于扩展自定义组件
`laravel-admin`默认引用了大量前端资源,如果有网络问题或者有不需要使用的组件,可以参考[form组件管理](/zh/model-form-field-management.md)将其移除。
关于富文本编辑器,由于静态资源包文件普遍太大,所以`laravel-admin`默认通过cdn的方式引用`ckeditor`,建议大家根据自己的需求扩展编辑器,自行配置。
## 关于前端资源问题
如果需要使用自己的前端文件,可以在`app/Admin/bootstrap.php`中引入:
```php
Admin::css('path/to/your/css');
Admin::css('path/to/your/js');
```
## 重写登陆页面和登陆逻辑
在路由文件`app/Admin/routes.php`中,覆盖掉登陆页面和登陆逻辑的路由,即可实现自定义的功能
```php
Route::group([
'prefix' => config('admin.prefix'),
'namespace' => Admin::controllerNamespace(),
'middleware' => ['web', 'admin'],
], function (Router $router) {
$router->get('auth/login', 'AuthController@getLogin');
$router->post('auth/login', 'AuthController@postLogin');
});
```
在自定义的路由器AuthController中的`getLogin``postLogin`方法里分别实现自己的登陆页面和登陆逻辑。
参考控制器文件[AuthController.php](https://github.com/z-song/laravel-admin/blob/master/src/Controllers/AuthController.php),视图文件[login.blade.php](https://github.com/z-song/laravel-admin/blob/master/views/login.blade.php)
## 更新静态资源
如果遇到更新之后,部分组件不能正常使用,那有可能是`laravel-admin`自带的静态资源有更新了,需要运行命令`php artisan vendor:publish --tag=laravel-admin-assets --force`来重新发布前端资源,发布之后不要忘记清理浏览器缓存.

View File

@@ -0,0 +1,63 @@
# 快速开始
## 数据表结构
`Laravel`自带的`users`表举例,表结构为:
```sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
```
对应的数据模型为文件 `App\User.php`
`laravel-admin`可以通过使用以下几步来快速生成`users`表的`CURD`操作页面:
## 添加路由器
使用下面的命令来创建一个对应`App\User`模型的路由器
```php
php artisan admin:make UserController --model=App\\User
// 在windows系统中
php artisan admin:make UserController --model=App\User
```
上面的命令会创建路由器文件`app/Admin/Controllers/UserController.php`.
## 添加路由配置
`laravel-admin`的路由配置文件`app/Admin/routes.php`里添加一行:
```
$router->resource('users', UserController::class);
```
## 添加左侧菜单栏连接
打开`http://localhost:8000/admin/auth/menu`添加对应的menu, 然后就能在后台管理页面的左侧边栏看到用户管理页面的链接入口了。
> 其中`uri`填写不包含路由前缀的的路径部分,比如完整路径是`http://localhost:8000/admin/demo/users`, 那么就填`demo/users`如果要添加外部链接只要填写完整的url即可比如`http://laravel-admin.org/`.
### 菜单翻译
在您的语言文件的menu_titles索引中追加菜单标题。
例如“工作单位”标题:
在resources/lang/es/admin.php中
```php
...
// 用_小写并用_替换空格
'menu_titles' => [
'work_units' => 'Unidades de trabajo'
],
```
## 创建表格表单
剩下的工作就是构建数据表格和表单了,打开 `app/Admin/Contollers/UserController.php`,找到`form()``grid()`方法,然添加构建代码更多详细使用请查看[model-grid](/zh/model-grid.md)和[model-form](/zh/model-form.md)。

View File

@@ -0,0 +1,10 @@
# 升级注意事项
因为laravel-admin 1.5的内置表结构有修改所以建议大家重新安装laravel 5.5和laravel-admin 1.5,然后再将代码迁移过来
代码迁移需要注意的事项:
- 表结构有修改 请参考 [tables.php](https://github.com/z-song/laravel-admin/blob/master/database/migrations/2016_01_04_173148_create_admin_tables.php)
- 路由文件结构有修改 请参考 [routes.stub](https://github.com/z-song/laravel-admin/blob/master/src/Console/stubs/routes.stub)
- 配置文件结构有修改 请参考 [admin.php](https://github.com/z-song/laravel-admin/blob/master/config/admin.php)
- 图表组件已经移除,不能再使用,参考 [自定义图表](/zh/custom-chart.md)

View File

@@ -0,0 +1,156 @@
# 前端组件
## Box组件
`Encore\Admin\Widgets\Box`用来生成box组件
```php
use Encore\Admin\Widgets\Box;
$box = new Box('Box标题', 'Box内容');
$box->removable();
$box->collapsable();
$box->style('info');
$box->solid();
echo $box;
```
`Box::__construct($title, $content)`,`$title`参数为Box组件的标题`$content`参数为Box的内容元素可以是实现了`Illuminate\Contracts\Support\Renderable`接口的对象或者其他可打印变量。
`Box::title($title)`方法用来设置Box组件标题。
`Box::content($content)`方法用来设置Box组件的内容元素。
`Box::removable()`方法将Box组件设置为可关闭。
`Box::collapsable()`方法将Box组件设置为可展开和收起。
`Box::style($style)`方法设置Box组件的样式可填值为`primary`,`info`,`danger`,`warning`,`success`,`default`
`Box::solid()`方法为Box组件添加边框。
## Collapse组件
`Encore\Admin\Widgets\Collapse`类用来生成折叠插件:
```php
use Encore\Admin\Widgets\Collapse;
$collapse = new Collapse();
$collapse->add('Bar', 'xxxxx');
$collapse->add('Orders', new Table());
echo $collapse->render();
```
`Collapse::add($title, $content)`方法用来给折叠组件添加一个折叠项,`$title`参数设置该折叠项的标题,`$content`参数用来舍子折叠区的内用。
## 表单
`Encore\Admin\Widgets\Form`类用来快速构建表单:
```php
$form = new Form();
$form->action('example');
$form->email('email')->default('qwe@aweq.com');
$form->password('password');
$form->text('name', '输入框');
$form->url('url');
$form->color('color');
$form->map('lat', 'lng');
$form->date('date');
$form->json('val');
$form->dateRange('created_at', 'updated_at');
echo $form->render();
```
`Form::__construct($data = [])`生成一个form对象如果传入了`$data`参数,`$data`数组中的元素将会按照`key`对应填入`form`对应name的表单中。
`Form::action($uri)`方法用来设置表单提交地址。
`Form::method($method)`方法用来设置form表单的提交方法,默认为`POST`方法。
`Form::disablePjax()` 不使用pjax方式提交表单。
## Infobox组件
`Encore\Admin\Widgets\InfoBox`类用来生成信息展示块:
```php
use Encore\Admin\Widgets\InfoBox;
$infoBox = new InfoBox('New Users', 'users', 'aqua', '/admin/users', '1024');
echo $infoBox->render();
```
效果请参考后台首页的布局文件[HomeController.php](https://github.com/z-song/laravel-admin/blob/master/src/Console/stubs/HomeController.stub)的`index()`方法中,关于`InfoBox`的部分。
## Tab组件
`Encore\Admin\Widgets\Tab`类用来生成选项卡组件:
```php
use Encore\Admin\Widgets\Tab;
$tab = new Tab();
$tab->add('Pie', $pie);
$tab->add('Table', new Table());
$tab->add('Text', 'blablablabla....');
echo $tab->render();
```
`Tab::add($title, $content)`方法用来添加一个选项卡,`$title`为选项标题,`$content`选项卡内容。
## Table
`Encore\Admin\Widgets\Table`类用来生成表格:
```php
use Encore\Admin\Widgets\Table;
// table 1
$headers = ['Id', 'Email', 'Name', 'Company'];
$rows = [
[1, 'labore21@yahoo.com', 'Ms. Clotilde Gibson', 'Goodwin-Watsica'],
[2, 'omnis.in@hotmail.com', 'Allie Kuhic', 'Murphy, Koepp and Morar'],
[3, 'quia65@hotmail.com', 'Prof. Drew Heller', 'Kihn LLC'],
[4, 'xet@yahoo.com', 'William Koss', 'Becker-Raynor'],
[5, 'ipsa.aut@gmail.com', 'Ms. Antonietta Kozey Jr.'],
];
$table = new Table($headers, $rows);
echo $table->render();
// table 2
$headers = ['Keys', 'Values'];
$rows = [
'name' => 'Joe',
'age' => 25,
'gender' => 'Male',
'birth' => '1989-12-05',
];
$table = new Table($headers, $rows);
echo $table->render();
```