1. nobu-maple

    No comment

    nobu-maple
Changes in body
Source | HTML | Preview
@@ -1,487 +1,489 @@
Laravel でユーザ認証した後、Vue側でRouter使ってページを切り替えてみる
ユーザ管理(社員管理)のページとしてデータテーブルを使えるように Vuetify も使ったページを作成する
環境設定他これまでの記事はこちら
[Qiita: Laravel5.6 + Vue2.5 でLaravelからVueにデータを渡す](https://qiita.com/nobu-maple/items/a704fe70809b0394b5c9)
[Qiita: Laravel5.6 + Vue2.5 でLaravel ユーザでログインして Vue画面を表示する](https://qiita.com/nobu-maple/items/f0ee9324eacfed6eddd7)
[Qiita: Laravel5.6 + Vue2.5 でユーザ権限によってvueコンポーネントを出しわける](https://qiita.com/nobu-maple/items/3eb735c148a698585fa3)
#■1.各パッケージをインストール
npm でサクッと
今後のために日付処理系の [moment.js](https://momentjs.com/) も入れておく
```bash
npm install vue-router
npm install vuetify
npm install css-loader
npm install material-design-icons-iconfont
npm install moment
```
インストール後はこんな感じ
```json:package.json
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.18",
"bootstrap": "^4.1.2",
"cross-env": "^5.2.0",
"jquery": "^3.2",
"laravel-mix": "^2.0",
"lodash": "^4.17.4",
"popper.js": "^1.12",
"vue": "^2.5.7"
},
"dependencies": {
"css-loader": "^1.0.0",
"material-design-icons-iconfont": "^3.0.3",
"moment": "^2.22.2",
"vue-router": "^3.0.1",
"vuetify": "^1.1.5"
}
}
```
#■2.読み込み設定
追加したパッケージを読み込むように設定
```javascript:resources/assets/js/app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
★1 window.Vuetify = require('vuetify');
★1 Vue.use(Vuetify);
★2 import 'vuetify/dist/vuetify.min.css';
★2 import 'material-design-icons-iconfont/dist/material-design-icons.css';
★3 import VueRouter from 'vue-router';
★3 Vue.use(VueRouter);
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.component('admin-component', require('./components/AdminComponent.vue'));
★4 const router = new VueRouter({
★4 mode: 'history',
★4 routes: [
★4 { path: '/', component: require('./components/DashboardComponent.vue')},
★4 { path: '/admin/user', component: require('./components/Admin/UserComponent.vue' )},
★4 ]
★4 });
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
★4 router,
});
```
★1 Vuetify 読み込み設定
★2 Vuetify 関連のCSS読み込み設定
★3 router 読み込み設定
★4 router ルーティング設定
#■3.routerで切り替えるベースコンポーネント作成
vue-routerで切り替えるページのベースとなるコンポーネントを作成する
レイアウトは Vuetify のテンプレートを利用させてもらう
```html:resources/assets/js/components/AdminComponent.vue
<template>
<v-app id="app">
<v-navigation-drawer v-model="drawer" clipped fixed app >
<v-list dense>
<router-link to="/home">
<v-list-tile @click="drawer = !drawer">
<v-list-tile-action> <v-icon>home</v-icon> </v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>HOME</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</router-link>
<router-link to="/admin/user">
<v-list-tile @click="drawer = !drawer">
<v-list-tile-action> <v-icon>supervisor_account</v-icon> </v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>社員管理</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</router-link>
</v-list>
</v-navigation-drawer>
<v-toolbar color="indigo" dark fixed app clipped-left>
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-toolbar-title>Application</v-toolbar-title>
<v-spacer></v-spacer>
{{ name }}
<v-btn icon @click="axiosLogout()">
<v-tooltip left>
<v-icon slot="activator" color="white" dark >exit_to_app</v-icon>
<span>ログアウト</span>
</v-tooltip>
</v-btn>
</v-toolbar>
<v-fade-transition mode="out-in">
<router-view></router-view>
</v-fade-transition>
<v-footer color="indigo" dark app fixed>
<span class="white--text ml-3">
&copy; 2018
<a class="white--text" href="https://qiita.com/nobu-maple">Qiita nobu-maple</a>
</span>
</v-footer>
</v-app>
</template>
<script>
export default {
data: () => ({
drawer: false,
}),
props: {
id: String,
name: String,
role: String,
logout: String,
},
mounted() {
console.log('Component mounted.')
},
methods: {
axiosLogout: function() {
var params = new URLSearchParams()
axios.post(this.logout, params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then( function (response) {
console.log(response)
}.bind(this))
.catch(function (error) {
if (error.response.status === 401) {
var parser = new URL(this.logout)
location.href=parser.origin
}
console.log(error.response)
}.bind(this))
},
},
}
</script>
```
#■4.home コンポーネント作成
とりあえず空のコンポーネント
Vuetifyで書いておく
```html:resources/assets/js/components/HomeComponent.vue
<template>
<v-content>
<v-container fluid fill-height>
<v-layout justify-center fluid>
<v-flex xs12 offset-mx5>
Home Component.
</v-flex>
</v-layout>
</v-container>
</v-content>
</template>
<script>
export default {
data: () => ({
}),
props: {
},
created() {
console.log('Component created.')
this.initialize()
},
mounted() {
console.log('Component mounted.')
},
methods: {
initialize: function() {
},
},
}
</script>
```
#■5.ユーザ一覧を表示するコンポーネントを作成
Vuetify の[データテーブル](https://vuetifyjs.com/ja/components/data-tables)を利用します
ユーザ一覧は axios で取ってきてテーブルにデータをセット
検索とページングとソートの設定もしときます
```html:resources/assets/js/components/Admin/UserComponent.vue
<template>
<v-content>
<v-container fluid fill-height>
<v-layout justify-center fluid>
<v-flex xs12 offset-mx5>
<v-card xs12>
<v-card-title class="title">
<v-icon class="ml-2">supervisor_account</v-icon> 社員管理
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="users"
:pagination.sync="pagination"
:rows-per-page-items='[10,25,50,{"text":"All","value":-1}]'
:loading="loading"
:search="search"
class="elevation-0"
>
<v-progress-linear slot="progress" color="blue" indeterminate></v-progress-linear>
<template slot="items" slot-scope="props">
<tr @click="props.expanded = !props.expanded">
<td class="text-xs-center" xs1>{{ (props.index + 1) + (pagination.page - 1) * pagination.rowsPerPage }}</td>
<td class="text-xs-left">{{ props.item.loginid }}</td>
<td class="text-xs-left">{{ props.item.name }}</td>
<td class="text-xs-left">{{ props.item.role }} - {{ props.item.role == '10' ? 'ユーザ' : '管理者' }}</td>
</tr>
</template>
</v-data-table>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content>
</template>
<script>
export default {
data: () => ({
loading: true,
search: '',
pagination: { sortBy: 'name', descending: true, },
users: [],
headers: [
{ align: 'center', sortable: false, text: 'No', },
{ align: 'left', sortable: true, text: '社員ID', value: 'loginid' },
{ align: 'left', sortable: true, text: '氏名', value: 'name' },
{ align: 'left', sortable: true, text: '権限', value: 'role' },
],
}),
props: {
},
created() {
console.log('Component created.')
this.initialize()
},
mounted() {
console.log('Component mounted.')
},
methods: {
initialize: function() {
this.getUsers()
},
getUsers: function() {
var params = new URLSearchParams()
this.loading = true
axios.post('/api/admin/user/', params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then( function (response) {
this.loading = false
console.log(response)
this.users = response.data.users
}.bind(this))
.catch(function (error) {
this.loading = false
console.log(error.response)
}.bind(this))
},
},
}
</script>
```
#■6.ユーザ用コントローラを作成
ひな形をまず作って
```bash
php artisan make:controller UserController
```
一覧のデータとして全件を返す index を定義しときます
```php:app/Http/Controllers/UserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class UserController extends Controller
{
public function index()
{
$users = User::all();
return ['users' => $users];
}
}
```
#■7.Laravel側のルーティング設定
管理者以外はアクセスできないように定義したGATEで制限もかけときます
```php:routes/web.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('home');
})->middleware('auth');
//Auth::routes();
// Authentication Routes...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');
Route::get('/home', 'HomeController@index')->name('home');
Route::group(['middleware' => ['auth', 'can:admin-higher']], function () {
Route::post('/api/admin/user', 'UserController@index')->name('admin/user');
});
Route::get('/{any}', function () {
Route::auth();
return view('home');
})->where('any', '.*');
```
#■8.動作確認
コンパイルして、サーバを起動して
```bash
npm run dev
php artisan serve --host=172.16.0.100 --port=8000
```
ブラウザでアクセスして
http://172.16.0.100:8000/
↓↓
ログインページへ飛ばされて
http://172.16.0.100:8000/login
![login.png](https://qiita-image-store.s3.amazonaws.com/0/153259/8d0ccfbc-d759-ce7e-7838-578453181406.png)
↓↓
User の権限でログインしたら今までの Vue コンポーネントが表示されて
![user.png](https://qiita-image-store.s3.amazonaws.com/0/153259/06e6a83d-b865-ea2b-4c23-f37e8f42cc35.png)
↓↓
ログアウトして 今度は Admin の管理者権限でログインしたら
![login_admin.png](https://qiita-image-store.s3.amazonaws.com/0/153259/0d79e024-8fa2-6334-3717-b6fddc50644c.png)
↓↓
Vuetify で作った Adminコンポーネントが表示されて
![admin_top.png](https://qiita-image-store.s3.amazonaws.com/0/153259/f97b2f83-3672-935b-7ba2-3ffba0691d30.png)
↓↓
メニューから 「社員管理」を選ぶと vue-router の機能で一覧のコンポーネントに切り替わり
![admin_menu.png](https://qiita-image-store.s3.amazonaws.com/0/153259/f8efdea8-0036-74a9-b4e4-a9fdf36081bc.png)
↓↓
User情報を axios が取ってきて Vuetify のデータテーブルにセットして表示
![admin_userlist.png](https://qiita-image-store.s3.amazonaws.com/0/153259/e513867d-0315-55fa-cda3-1353d6fbe7e6.png)
+検索とかページングとかソートとかの動作もうまく動いているようです
+