Laravel Vue Admin - #1 Admin panel Setup
首先,用到了laravel ui扩展包 及基础的 vue 脚手架:
执行:
composer require laravel/ui
执行:
php artisan ui vue --auth
执行:
npm install & npm run watch
介绍一下Laravel Permission 扩展包:
A package to add roles and permissions to Laravel
https://github.com/spatie/laravel-permission
因为自Laravel 5.1.1版本开始就提供了很不错的授权功能,用起来比较简洁,检查用户是否有操作的权限也是超级简单。这个Laravel Permission扩展包就是以Jeffrey's code 为基础,发展起来的,可以很方便的给用户授予角色,权限。
参考:https://docs.spatie.be/laravel-permission/v3/introduction/
// Adding permissions to a user $user->givePermissionTo('edit articles'); // Adding permissions via a role $user->assignRole('writer'); $role->givePermissionTo('edit articles');
前言
由于这个扩展包提供所有的权限都是注册于Laravel Gate之上。
只要你的User模型类实现了 Illuminate\Contracts\Auth\Access\Authorizable【这个是默认的Illuminate\Foundation\Auth\User中实现了的】,那么默认提供的can方法也是可以使用的:
$user->can('edit articles');blade中也可以使用:
@can('edit articles') ... @endcan记得User模型类中需要使用HasRoles这个trait来实现扩展包的功能。
所以至少你的User模型类应该有这个:
use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { use HasRoles; // ... }
另外,你的User模型不能有role或者roles属性以及roles()方法,且数据库中也不能有这两个字段。
因为HasRoles trait已经提供了,否则你重写的方法可能造成不当的结果。
同样,你的User模型类也不能有permission或者permissions属性或者permissions()方法,数据库中也不能有这两个字段。
因为HasRoles trait中的 HasPermissions trait已经提供了。
这个安装包会生成config/permission.php文件。如果你有一个自建文件和这个文件同名,那移动到其他位置或者重命名一下,否则会冲突。视个人的需要也可以添加自己的方法到里面。
安装:
执行:
composer require spatie/laravel-permission
config/app.php修改如下:
'providers' => [ // ... Spatie\Permission\PermissionServiceProvider::class, ];
然后执行:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
生成了permission.php文件,以及一个create_permission_tables.php文件:
如果需要UUID请看:UUID
执行migrate之前确保env中DB_DATABASE设置正确,否则会报错:
我的database是vue
所以:
然后执行:
php artisan migrate
最后,按照前言中的要求,修改User模型类。
Vuetify安装:
参考: Webpack install 执行:
npm i vuetify --save
然后需要引用vuetify:
js/app.js添加:
import Vuetify from "vuetify"; Vue.use(Vuetify); import 'vuetify/dist/vuetify.min.css';
为了让修改的样式不受缓存影响,在webpack.mix.js后添加一个version();
然后layout/app.blade.php中 asset()方法改为mix()方法:
参考https://vuetifyjs.com/en/getting-started/quick-start/#bootstrapping-the-vuetify-object:
添加下面代码到webpack.mix.js中:
// webpack.config.js module.exports = { rules: [ { test: /\.s(c|a)ss$/, use: [ 'vue-style-loader', 'css-loader', { loader: 'sass-loader', // Requires sass-loader@^7.0.0 options: { implementation: require('sass'), fiber: require('fibers'), indentedSyntax: true // optional }, // Requires sass-loader@^8.0.0 options: { implementation: require('sass'), sassOptions: { fiber: require('fibers'), indentedSyntax: true // optional }, }, }, ], }, ], }
创建一插件文件:src/plugins/vuetify.js
// src/plugins/vuetify.js import Vue from 'vue' import Vuetify from 'vuetify' import 'vuetify/dist/vuetify.min.css' Vue.use(Vuetify) const opts = {} export default new Vuetify(opts)
然后修改app.js对vuetify的引用:
路由:
web.php中添加:
Route::any('/admin/{any?}', 'AdminController@index')->where('any', '.*')->middleware('auth');
控制器:
执行:
php artisan make:controller AdminController
新建的控制器添加方法:
public function __construct() { $this->middleware('auth'); } // public function index(Request $request) { return view('admin'); }
index方法返回admin这个view视图,现在来新建这个视图文件:
如果不用layouts.app基础框架那么 拷贝一下layouts.app中的内容 替换div#app中的内容:
注意这里添加了一个Admin的vue component【vue组件】,所以开始处理这个vue组件:
在components文件夹下新建一个Admin.vue文件:
Admin.vue直接用vuetify的模板:Pre-made layouts 暂时选了 Dark附上代码链接。
初步的Admin.vue:
<template> <v-app id="inspire"> <v-navigation-drawer v-model="drawer" app clipped > <v-list dense> <v-list-item link> <v-list-item-action> <v-icon>mdi-view-dashboard</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Dashboard</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link> <v-list-item-action> <v-icon>mdi-settings</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Settings</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> </v-navigation-drawer> <v-app-bar app clipped-left > <v-app-bar-nav-icon @click.stop="drawer = !drawer"/> <v-toolbar-title>Application</v-toolbar-title> </v-app-bar> <v-content> <v-container class="fill-height" fluid > <v-row align="center" justify="center" > <v-col class="shrink"> <v-tooltip right> <template v-slot:activator="{ on }"> <v-btn :href="source" icon large target="_blank" v-on="on" > <v-icon large>mdi-code-tags</v-icon> </v-btn> </template> <span>Source</span> </v-tooltip> <v-tooltip right> <template v-slot:activator="{ on }"> <v-btn icon large href="https://codepen.io/johnjleider/pen/bXNzZL" target="_blank" v-on="on" > <v-icon large>mdi-codepen</v-icon> </v-btn> </template> <span>Codepen</span> </v-tooltip> </v-col> </v-row> </v-container> </v-content> <v-footer app> <span>© 2019</span> </v-footer> </v-app> </template> <script> export default { name: "Admin", props: { source: String, user: Object, }, data: function () { return { drawer: null, } }, created() { this.$vuetify.theme.dark = true; }, } </script> <style scoped> </style>
Vue-router
安装:
执行:
npm i vue-router
安装完成:
然后app.js中引用:
因为admin route及AdminController都经过了auth中间件,所以注册一个用户是必须的:
然后登录 :
注意执行:
npm install & npm run watch-poll
打开链接:http://vue.test/admin 即可看到:
接下来添加vue的route文件:
先添加,再编辑:
app.js里面需要添加代码应用这几个route:
import Dashboard from "./components/pages/Dashboard"; import Users from "./components/pages/Users"; import Settings from "./components/pages/Settings"; import Roles from "./components/pages/Roles"; import Permissions from "./components/pages/Permissions"; const routes = [ { path: '/admin/', component: Dashboard, }, { path: '/admin/users', component: Users, }, { path: '/admin/roles', component: Roles, }, { path: '/admin/settings', component: Settings, }, { path: '/admin/permissions', component: Permissions, }, ]; const router = new VueRouter({ mode: 'history', routes, });
并且vue实例需要配置这个router:
const app = new Vue({ el: '#app', vuetify, router, });
接下来 用户点击dashboard按钮 setting按钮的跳转,以及添加用户的users roles permissions按钮:
需要修改Admin.vue:
<template> <v-app id="inspire"> <v-navigation-drawer v-model="drawer" app clipped > <v-list dense> <v-list-item link to="/admin"> <v-list-item-action> <v-icon>mdi-view-dashboard</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Dashboard</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-group no-action> <v-list-item slot="activator"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>User Management</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/users"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Users</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/roles"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Roles</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/permissions"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Permissions</v-list-item-title> </v-list-item-content> </v-list-item> </v-list-group> <v-list-item link to="/admin/settings"> <v-list-item-action> <v-icon>mdi-settings</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Settings</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> </v-navigation-drawer> <v-app-bar app clipped-left > <v-app-bar-nav-icon @click.stop="drawer = !drawer"/> <v-toolbar-title>Application</v-toolbar-title> </v-app-bar> <v-content> <v-container class="fill-height" fluid > <v-row align="center" justify="center" > <v-col class="shrink"> <v-tooltip right> <template v-slot:activator="{ on }"> <v-btn :href="source" icon large target="_blank" v-on="on" > <v-icon large>mdi-code-tags</v-icon> </v-btn> </template> <span>Source</span> </v-tooltip> <v-tooltip right> <template v-slot:activator="{ on }"> <v-btn icon large href="https://codepen.io/johnjleider/pen/bXNzZL" target="_blank" v-on="on" > <v-icon large>mdi-codepen</v-icon> </v-btn> </template> <span>Codepen</span> </v-tooltip> </v-col> </v-row> </v-container> </v-content> <v-footer app> <span>© 2019</span> </v-footer> </v-app> </template> <script> export default { name: "Admin", props: { source: String, user: Object, }, data: function () { return { drawer: null, } }, created() { this.$vuetify.theme.dark = true }, } </script> <style scoped> </style>
vue-router会在点击按钮的时候跳转到对应的route加载component,但是目前代码中缺少一个展示加载的component的代码:添加
<router-view></router-view>
到内容的地方:
<template> <v-app id="inspire"> <v-navigation-drawer v-model="drawer" app clipped > <v-list dense> <v-list-item link to="/admin"> <v-list-item-action> <v-icon>mdi-view-dashboard</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Dashboard</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-group no-action> <v-list-item slot="activator"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>User Management</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/users"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Users</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/roles"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Roles</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item link to="/admin/permissions"> <v-list-item-action> <v-icon>mdi-account</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Permissions</v-list-item-title> </v-list-item-content> </v-list-item> </v-list-group> <v-list-item link to="/admin/settings"> <v-list-item-action> <v-icon>mdi-settings</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Settings</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> </v-navigation-drawer> <v-app-bar app clipped-left > <v-app-bar-nav-icon @click.stop="drawer = !drawer"/> <v-toolbar-title>Application</v-toolbar-title> </v-app-bar> <v-content> <v-container class="fill-height" fluid > <v-row align="center" justify="center" > <v-col class="shrink"> <router-view></router-view> </v-col> </v-row> </v-container> </v-content> <v-footer app> <span>© 2019</span> </v-footer> </v-app> </template> <script> export default { name: "Admin", props: { source: String, user: Object, }, data: function () { return { drawer: null, } }, created() { this.$vuetify.theme.dark = true }, } </script> <style scoped> </style>
最后效果: