加入權限機制, Auth相關views, 後台views及相關機制
This commit is contained in:
parent
8684bd1d21
commit
ca7e23e6de
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,6 +4,9 @@
|
||||
/public/storage
|
||||
/public/js
|
||||
/public/css
|
||||
/public/fonts/vendor
|
||||
/public/images/vendor
|
||||
/public/mix-manifest.json
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
|
||||
50
app/Console/Commands/CreateAdminAccount.php
Normal file
50
app/Console/Commands/CreateAdminAccount.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Repositories\UserRepository;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CreateAdminAccount extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'account:create-admin {email} {password}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create an admin account';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$email = $this->argument('email');
|
||||
$password = $this->argument('password');
|
||||
|
||||
$userRepo = app(UserRepository::class);
|
||||
|
||||
$userRepo->createAdminAccount($email, $password);
|
||||
|
||||
$this->info("Account: $email has been created");
|
||||
}
|
||||
}
|
||||
24
app/Http/Controllers/AdminPageController.php
Normal file
24
app/Http/Controllers/AdminPageController.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
/**
|
||||
* 後台頁面的Controller,選單項目之外的其他頁面
|
||||
*
|
||||
* Class AdminPageController
|
||||
* @package App\Http\Controllers
|
||||
*/
|
||||
class AdminPageController extends Controller
|
||||
{
|
||||
private $mainManuPagePrefix;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mainManuPagePrefix = config('admin.route_name_prefix') . config('admin.menu.route_name_prefix');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('admin.index');
|
||||
}
|
||||
}
|
||||
@ -61,6 +61,7 @@ class Kernel extends HttpKernel
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'admin.area' => \App\Http\Middleware\AdminAreaGuard::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
35
app/Http/Middleware/AdminAreaGuard.php
Normal file
35
app/Http/Middleware/AdminAreaGuard.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* 判斷後台權限
|
||||
*
|
||||
* Class AdminAreaGuard
|
||||
* @package App\Http\Middleware
|
||||
*/
|
||||
class AdminAreaGuard
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$user = $request->user();
|
||||
if($user) {
|
||||
if($user->can('admin area')) {
|
||||
return $next($request);
|
||||
} else {
|
||||
abort(403); // 有登入但無權限
|
||||
}
|
||||
} else {
|
||||
abort(404); // 無登入回應404,顯示找不到頁面
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const HOME = '/home';
|
||||
public const HOME = '/';
|
||||
|
||||
/**
|
||||
* Define your route model bindings, pattern filters, etc.
|
||||
|
||||
95
app/Reposotories/BaseRepository.php
Normal file
95
app/Reposotories/BaseRepository.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\TranslatableModel;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
abstract class BaseRepository
|
||||
{
|
||||
/**
|
||||
* @var Model
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* @return Model
|
||||
*/
|
||||
public function getModel()
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
public function setModel(Model $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得Model的class name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModelClass()
|
||||
{
|
||||
return get_class($this->model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建一個Model的instance
|
||||
*
|
||||
* @return Model
|
||||
*/
|
||||
public function createModel()
|
||||
{
|
||||
return app($this->getModelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查詢所有
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function queryAll()
|
||||
{
|
||||
$modelClass = $this->getModelClass();
|
||||
return $modelClass::all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查詢特定ID
|
||||
*
|
||||
* @param $id
|
||||
* @return Model|null
|
||||
*/
|
||||
public function findModel($id)
|
||||
{
|
||||
return $this->getModel()->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刪除特定id
|
||||
*
|
||||
* @param $id
|
||||
* @return bool|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deleteModel($id)
|
||||
{
|
||||
return $this->findModel($id)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function hasModel($id)
|
||||
{
|
||||
return $this->getModel()->where('id', $id)->exists();
|
||||
}
|
||||
}
|
||||
44
app/Reposotories/UserRepository.php
Normal file
44
app/Reposotories/UserRepository.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Str;
|
||||
|
||||
/**
|
||||
* Class UserRepository
|
||||
* @package App\Repositories
|
||||
*
|
||||
* @property \App\User $model
|
||||
* @method \App\User getModel()
|
||||
*/
|
||||
class UserRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->setModel($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立管理員帳號
|
||||
*
|
||||
* @param string $email
|
||||
* @param string $password
|
||||
* @return void
|
||||
*/
|
||||
public function createAdminAccount($email, $password)
|
||||
{
|
||||
if($email && $password) {
|
||||
$user = $this->model->create([
|
||||
'email' => $email,
|
||||
'password' => Hash::make($password),
|
||||
'api_token' => Str::random(36)
|
||||
]);
|
||||
|
||||
$user->assignRole('administrator');
|
||||
|
||||
return $user->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ namespace App;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
/**
|
||||
* App\User
|
||||
@ -34,6 +35,7 @@ class User extends Authenticatable
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
use HasRoles;
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
|
||||
@ -11,12 +11,14 @@
|
||||
"php": "^7.2",
|
||||
"fideloper/proxy": "^4.0",
|
||||
"laravel/framework": "^6.2",
|
||||
"laravel/tinker": "^2.0"
|
||||
"laravel/tinker": "^2.0",
|
||||
"spatie/laravel-permission": "^3.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-ide-helper": "^2.6",
|
||||
"facade/ignition": "^1.4",
|
||||
"fzaninotto/faker": "^1.9.1",
|
||||
"laravel/ui": "^1.2",
|
||||
"mockery/mockery": "^1.0",
|
||||
"nunomaduro/collision": "^3.0",
|
||||
"phpunit/phpunit": "^8.0"
|
||||
@ -37,6 +39,7 @@
|
||||
},
|
||||
"classmap": [
|
||||
"database/seeds",
|
||||
"database/seeds/Preset",
|
||||
"database/factories"
|
||||
]
|
||||
},
|
||||
|
||||
124
composer.lock
generated
124
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d823097c9a46903a75367077995590b2",
|
||||
"content-hash": "7315d6229270be366528dbffc0c6864c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "dnoegel/php-xdg-base-dir",
|
||||
@ -1459,6 +1459,74 @@
|
||||
],
|
||||
"time": "2020-02-21T04:36:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-permission",
|
||||
"version": "3.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-permission.git",
|
||||
"reference": "2339b6fae8f8aa5af047e1a0c54b6fb37546058a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/2339b6fae8f8aa5af047e1a0c54b6fb37546058a",
|
||||
"reference": "2339b6fae8f8aa5af047e1a0c54b6fb37546058a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/auth": "^5.8|^6.0|^7.0",
|
||||
"illuminate/container": "^5.8|^6.0|^7.0",
|
||||
"illuminate/contracts": "^5.8|^6.0|^7.0",
|
||||
"illuminate/database": "^5.8|^6.0|^7.0",
|
||||
"php": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^3.8|^4.0|^5.0",
|
||||
"phpunit/phpunit": "^8.0",
|
||||
"predis/predis": "^1.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\Permission\\PermissionServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Permission\\": "src"
|
||||
},
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Permission handling for Laravel 5.8 and up",
|
||||
"homepage": "https://github.com/spatie/laravel-permission",
|
||||
"keywords": [
|
||||
"acl",
|
||||
"laravel",
|
||||
"permission",
|
||||
"permissions",
|
||||
"rbac",
|
||||
"roles",
|
||||
"security",
|
||||
"spatie"
|
||||
],
|
||||
"time": "2020-02-18T21:16:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v6.2.3",
|
||||
@ -4118,6 +4186,60 @@
|
||||
],
|
||||
"time": "2019-09-25T14:49:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/ui",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/ui.git",
|
||||
"reference": "bb64fca681566ca94457d490a00f899516e75664"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/ui/zipball/bb64fca681566ca94457d490a00f899516e75664",
|
||||
"reference": "bb64fca681566ca94457d490a00f899516e75664",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "~5.8|^6.0",
|
||||
"illuminate/filesystem": "~5.8|^6.0",
|
||||
"illuminate/support": "~5.8|^6.0",
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
"phpunit/phpunit": "^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Ui\\UiServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Ui\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Laravel UI utilities and presets.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"ui"
|
||||
],
|
||||
"time": "2020-02-13T21:12:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.3.1",
|
||||
|
||||
9
config/admin.php
Normal file
9
config/admin.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
use App\Http\Controllers\Admin\Menu;
|
||||
|
||||
return [
|
||||
// 後台的登入路徑
|
||||
'route' => 'adm',
|
||||
// 後台的Route Name前綴
|
||||
'route_name_prefix' => 'admin.',
|
||||
];
|
||||
@ -166,6 +166,7 @@ return [
|
||||
* Package Service Providers...
|
||||
*/
|
||||
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
|
||||
Spatie\Permission\PermissionServiceProvider::class,
|
||||
/*
|
||||
* Application Service Providers...
|
||||
*/
|
||||
|
||||
17
config/data-presets.php
Normal file
17
config/data-presets.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
return [
|
||||
'roles' => [
|
||||
['name' => 'administrator', 'displayName' => 'administrator'],
|
||||
['name' => 'editor', 'displayName' => 'editor'],
|
||||
],
|
||||
'permissions' => [
|
||||
[
|
||||
//進入後台
|
||||
'name' => 'admin area',
|
||||
'displayName' => 'adminArea',
|
||||
'assignTo' => [
|
||||
'administrator', 'editor'
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
129
config/permission.php
Normal file
129
config/permission.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Spatie\Permission\Models\Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Spatie\Permission\Models\Role::class,
|
||||
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the required permission/role names are added to the exception
|
||||
* message. This could be considered an information leak in some contexts, so
|
||||
* the default setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* When checking for a permission against a model by passing a Permission
|
||||
* instance to the check, this key determines what attribute on the
|
||||
* Permissions model is used to cache against.
|
||||
*
|
||||
* Ideally, this should match your preferred way of checking permissions, eg:
|
||||
* `$user->can('view-posts')` would be 'name'.
|
||||
*/
|
||||
|
||||
'model_key' => 'name',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
||||
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreatePermissionTables extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->comment('名稱');
|
||||
$table->string('display_name')->comment('用來顯示的名稱');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->comment('名稱');
|
||||
$table->string('display_name')->comment('用來顯示的名稱');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames) {
|
||||
$table->unsignedInteger('permission_id');
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type', ]);
|
||||
|
||||
$table->foreign('permission_id')
|
||||
->references('id')
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary(['permission_id', $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames) {
|
||||
$table->unsignedInteger('role_id');
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type', ]);
|
||||
|
||||
$table->foreign('role_id')
|
||||
->references('id')
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary(['role_id', $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
|
||||
$table->unsignedInteger('permission_id');
|
||||
$table->unsignedInteger('role_id');
|
||||
|
||||
$table->foreign('permission_id')
|
||||
->references('id')
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign('role_id')
|
||||
->references('id')
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary(['permission_id', 'role_id']);
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,6 @@ class DatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// $this->call(UsersTableSeeder::class);
|
||||
$this->call(RolesAndPermissionsSeeder::class);
|
||||
}
|
||||
}
|
||||
|
||||
45
database/seeds/Preset/RolesAndPermissionsSeeder.php
Normal file
45
database/seeds/Preset/RolesAndPermissionsSeeder.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
class RolesAndPermissionsSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
//清除Role與Permission的cache
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
//讀取Config檔案
|
||||
$presetConfig = config('data-presets');
|
||||
$roles = $presetConfig['roles'];
|
||||
$permissions = $presetConfig['permissions'];
|
||||
|
||||
//建立Roles
|
||||
foreach ($roles as $role) {
|
||||
$_role = Role::create([
|
||||
'name' => $role['name'],
|
||||
'display_name' => $role['displayName']
|
||||
]);
|
||||
}
|
||||
|
||||
//建立Permissions
|
||||
foreach ($permissions as $permission) {
|
||||
$_permission = Permission::create([
|
||||
'name' => $permission['name'],
|
||||
'display_name' => $permission['displayName']
|
||||
]);
|
||||
if(!empty($permission['assignTo'])) {
|
||||
foreach ($permission['assignTo'] as $roleName) {
|
||||
$_permission->assignRole($roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
201
package-lock.json
generated
201
package-lock.json
generated
@ -919,6 +919,47 @@
|
||||
"to-fast-properties": "2.0.0"
|
||||
}
|
||||
},
|
||||
"@coreui/coreui": {
|
||||
"version": "2.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@coreui/coreui/-/coreui-2.1.16.tgz",
|
||||
"integrity": "sha512-1YOnQAlcX2bIgnaX3k9GKaN4lD+wKam7tdDfFj7/ZQTN1XG3dwDELHp4aagWQs78ix2CCO1LyeLrzGpsMcLW3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@coreui/coreui-plugin-npm-postinstall": "1.0.2",
|
||||
"bootstrap": "4.4.1",
|
||||
"core-js": "3.6.4",
|
||||
"regenerator-runtime": "0.13.3"
|
||||
}
|
||||
},
|
||||
"@coreui/coreui-plugin-chartjs-custom-tooltips": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@coreui/coreui-plugin-chartjs-custom-tooltips/-/coreui-plugin-chartjs-custom-tooltips-1.3.1.tgz",
|
||||
"integrity": "sha512-ovNE9QygRdB7IkE7gZNRx79lSk77STtNOFS4NRpjljoRcAseR156ZYV0i/dSoiwZwRJ+dHzWeXy1IMcXcdnAww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@coreui/coreui-plugin-npm-postinstall": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@coreui/coreui-plugin-npm-postinstall/-/coreui-plugin-npm-postinstall-1.0.2.tgz",
|
||||
"integrity": "sha512-yeeoWp+bNS84nP1977Y8UCiQ9pssO+f4QuVj3i0/gYZFjjvOgxx0dnyWhtowD5sLYnCRMPlPpqyjwXze3SlkYg==",
|
||||
"dev": true
|
||||
},
|
||||
"@coreui/icons": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@coreui/icons/-/icons-0.4.1.tgz",
|
||||
"integrity": "sha512-k3U1zzJwwKIH+LgSBD1y+GTbB3Rqen567GyNHNKxHHTke6r67n/s3K2nxgD8vX53WirfXzsz+8+mRipnzkplCA==",
|
||||
"dev": true
|
||||
},
|
||||
"@mrmlnc/readdir-enhanced": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
@ -1718,6 +1759,15 @@
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"block-ui": {
|
||||
"version": "2.70.1",
|
||||
"resolved": "https://registry.npmjs.org/block-ui/-/block-ui-2.70.1.tgz",
|
||||
"integrity": "sha1-yGLWTuYoj7eBIzd8ZoC8erJiED8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jquery": "3.4.1"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
@ -1785,6 +1835,12 @@
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz",
|
||||
"integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -1914,8 +1970,8 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"caniuse-lite": "1.0.30001028",
|
||||
"electron-to-chromium": "1.3.356",
|
||||
"node-releases": "1.1.49"
|
||||
"electron-to-chromium": "1.3.358",
|
||||
"node-releases": "1.1.50"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
@ -2083,6 +2139,35 @@
|
||||
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
|
||||
"dev": true
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
|
||||
"integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chartjs-color": "2.4.1",
|
||||
"moment": "2.24.0"
|
||||
}
|
||||
},
|
||||
"chartjs-color": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
|
||||
"integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chartjs-color-string": "0.6.0",
|
||||
"color-convert": "1.9.3"
|
||||
}
|
||||
},
|
||||
"chartjs-color-string": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
|
||||
"integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
|
||||
@ -2464,6 +2549,12 @@
|
||||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
||||
"dev": true
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
|
||||
"integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
|
||||
"dev": true
|
||||
},
|
||||
"core-js-compat": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz",
|
||||
@ -2858,6 +2949,46 @@
|
||||
"type": "1.2.0"
|
||||
}
|
||||
},
|
||||
"datatables.net": {
|
||||
"version": "1.10.20",
|
||||
"resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.20.tgz",
|
||||
"integrity": "sha512-4E4S7tTU607N3h0fZPkGmAtr9mwy462u+VJ6gxYZ8MxcRIjZqHy3Dv1GNry7i3zQCktTdWbULVKBbkAJkuHEnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jquery": "3.4.1"
|
||||
}
|
||||
},
|
||||
"datatables.net-bs4": {
|
||||
"version": "1.10.20",
|
||||
"resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.20.tgz",
|
||||
"integrity": "sha512-kQmMUMsHMOlAW96ztdoFqjSbLnlGZQ63iIM82kHbmldsfYdzuyhbb4hTx6YNBi481WCO3iPSvI6YodNec46ZAw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"datatables.net": "1.10.20",
|
||||
"jquery": "3.4.1"
|
||||
}
|
||||
},
|
||||
"datatables.net-responsive": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/datatables.net-responsive/-/datatables.net-responsive-2.2.3.tgz",
|
||||
"integrity": "sha512-8D6VtZcyuH3FG0Hn5A4LPZQEOX3+HrRFM7HjpmsQc/nQDBbdeBLkJX4Sh/o1nzFTSneuT1Wh/lYZHVPpjcN+Sw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"datatables.net": "1.10.20",
|
||||
"jquery": "3.4.1"
|
||||
}
|
||||
},
|
||||
"datatables.net-responsive-bs4": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/datatables.net-responsive-bs4/-/datatables.net-responsive-bs4-2.2.3.tgz",
|
||||
"integrity": "sha512-SQaWI0uLuPcaiBBin9zX+MuQfTSIkK1bYxbXqUV6NLkHCVa6PMQK7Rvftj0ywG4R7uOtjbzY8nSVqxEKvQI0Vg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"datatables.net-bs4": "1.10.20",
|
||||
"datatables.net-responsive": "2.2.3",
|
||||
"jquery": "3.4.1"
|
||||
}
|
||||
},
|
||||
"de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||
@ -3169,9 +3300,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.356",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.356.tgz",
|
||||
"integrity": "sha512-qW4YHMfOFjvx0jkSK2vjaHoLjk1+uJIV5tqtLDo7P5y3/kM8KQP23YBU0Y5fCSW4jIbDvEzeHDaY4+4vEaqqOw==",
|
||||
"version": "1.3.358",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.358.tgz",
|
||||
"integrity": "sha512-y9xvv+9PplXSUkOSxgtOfwNrqD/948VIScyWURnY27PXprg3PmRl7e8ekRJhnksDNjxLVyBYY6I2nQmNBzdi6g==",
|
||||
"dev": true
|
||||
},
|
||||
"elliptic": {
|
||||
@ -3884,6 +4015,12 @@
|
||||
"resolve-dir": "1.0.1"
|
||||
}
|
||||
},
|
||||
"flag-icon-css": {
|
||||
"version": "3.4.6",
|
||||
"resolved": "https://registry.npmjs.org/flag-icon-css/-/flag-icon-css-3.4.6.tgz",
|
||||
"integrity": "sha512-rF69rt19Hr63SRQTiPBzQABaYB20LAgZhDkr/AxqSdgmCIN+tC5PRMz56Y0gxehFXJmdRwv55+GMi7R1fCRTwg==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
|
||||
@ -3903,6 +4040,12 @@
|
||||
"debug": "3.1.0"
|
||||
}
|
||||
},
|
||||
"font-awesome": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -5531,6 +5674,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
|
||||
"integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==",
|
||||
"dev": true
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -6085,6 +6234,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.24.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
||||
"dev": true
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@ -6250,9 +6405,9 @@
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "1.1.49",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.49.tgz",
|
||||
"integrity": "sha512-xH8t0LS0disN0mtRCh+eByxFPie+msJUBL/lJDBuap53QGiYPa9joh83K4pCZgWJ+2L4b9h88vCVdXQ60NO2bg==",
|
||||
"version": "1.1.50",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.50.tgz",
|
||||
"integrity": "sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "6.3.0"
|
||||
@ -6731,6 +6886,12 @@
|
||||
"sha.js": "2.4.11"
|
||||
}
|
||||
},
|
||||
"perfect-scrollbar": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz",
|
||||
"integrity": "sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
@ -6761,6 +6922,12 @@
|
||||
"find-up": "3.0.0"
|
||||
}
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"portfinder": {
|
||||
"version": "1.0.25",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
|
||||
@ -8104,6 +8271,12 @@
|
||||
"integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
|
||||
"dev": true
|
||||
},
|
||||
"select2": {
|
||||
"version": "4.0.13",
|
||||
"resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz",
|
||||
"integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==",
|
||||
"dev": true
|
||||
},
|
||||
"selfsigned": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
|
||||
@ -8326,6 +8499,12 @@
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"dev": true
|
||||
},
|
||||
"simple-line-icons": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-line-icons/-/simple-line-icons-2.4.1.tgz",
|
||||
"integrity": "sha1-t1vFoNh+UwkowszaVzUnS7JW8jQ=",
|
||||
"dev": true
|
||||
},
|
||||
"simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
@ -9468,6 +9647,12 @@
|
||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vue": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz",
|
||||
"integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vue-hot-reload-api": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||
|
||||
26
package.json
26
package.json
@ -10,13 +10,29 @@
|
||||
"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": {
|
||||
"@coreui/coreui": "^2.1.16",
|
||||
"@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.3.1",
|
||||
"@coreui/icons": "^0.4.1",
|
||||
"axios": "^0.19",
|
||||
"cross-env": "^7.0",
|
||||
"block-ui": "^2.70.1",
|
||||
"bootstrap": "^4.0.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"cross-env": "^7.0.0",
|
||||
"datatables.net-bs4": "^1.10.20",
|
||||
"datatables.net-responsive-bs4": "^2.2.3",
|
||||
"flag-icon-css": "^3.4.6",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jquery": "^3.2",
|
||||
"laravel-mix": "^5.0.1",
|
||||
"lodash": "^4.17.13",
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"sass": "^1.15.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"perfect-scrollbar": "^1.5.0",
|
||||
"popper.js": "^1.12",
|
||||
"resolve-url-loader": "^3.1.1",
|
||||
"sass": "^1.20.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"select2": "^4.0.13",
|
||||
"simple-line-icons": "^2.4.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
}
|
||||
}
|
||||
|
||||
1
resources/js/admin/app.js
vendored
Normal file
1
resources/js/admin/app.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
import './lib';
|
||||
36
resources/js/admin/lib.js
vendored
Normal file
36
resources/js/admin/lib.js
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import $ from 'jquery';
|
||||
window.$ = window.jQuery = $;
|
||||
|
||||
import Popper from 'popper.js';
|
||||
window.Popper = Popper;
|
||||
|
||||
import 'select2';
|
||||
|
||||
import 'bootstrap';
|
||||
|
||||
import _ from 'lodash'
|
||||
window._ = _;
|
||||
|
||||
import Axios from 'axios';
|
||||
window.axios = Axios;
|
||||
|
||||
import Vue from 'vue';
|
||||
window.Vue = Vue;
|
||||
|
||||
import 'perfect-scrollbar';
|
||||
import '@coreui/coreui';
|
||||
import 'chart.js';
|
||||
import '@coreui/coreui-plugin-chartjs-custom-tooltips';
|
||||
|
||||
try {
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
let token = document.head.querySelector('meta[name="csrf-token"]');
|
||||
if (token) {
|
||||
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
|
||||
} else {
|
||||
console.error('Meta CSRF token not found');
|
||||
}
|
||||
|
||||
} catch(e) {}
|
||||
29
resources/js/bootstrap.js
vendored
29
resources/js/bootstrap.js
vendored
@ -1,28 +1,13 @@
|
||||
window._ = require('lodash');
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
try {
|
||||
window.Popper = require('popper.js').default;
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
|
||||
require('bootstrap');
|
||||
} catch (e) {}
|
||||
|
||||
|
||||
window.axios = require('axios');
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// window.Pusher = require('pusher-js');
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: process.env.MIX_PUSHER_APP_KEY,
|
||||
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
|
||||
// forceTLS: true
|
||||
// });
|
||||
|
||||
19
resources/sass/_variables.scss
vendored
Normal file
19
resources/sass/_variables.scss
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Body
|
||||
$body-bg: #f8fafc;
|
||||
|
||||
// Typography
|
||||
$font-family-sans-serif: 'Nunito', sans-serif;
|
||||
$font-size-base: 0.9rem;
|
||||
$line-height-base: 1.6;
|
||||
|
||||
// Colors
|
||||
$blue: #3490dc;
|
||||
$indigo: #6574cd;
|
||||
$purple: #9561e2;
|
||||
$pink: #f66d9b;
|
||||
$red: #e3342f;
|
||||
$orange: #f6993f;
|
||||
$yellow: #ffed4a;
|
||||
$green: #38c172;
|
||||
$teal: #4dc0b5;
|
||||
$cyan: #6cb2eb;
|
||||
3
resources/sass/admin/_bootstrap.scss
vendored
Normal file
3
resources/sass/admin/_bootstrap.scss
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins";
|
||||
19
resources/sass/admin/_variables.scss
vendored
Normal file
19
resources/sass/admin/_variables.scss
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Body
|
||||
$body-bg: #f8fafc;
|
||||
|
||||
// Typography
|
||||
$font-family-sans-serif: 'Nunito', sans-serif;
|
||||
$font-size-base: 0.9rem;
|
||||
$line-height-base: 1.6;
|
||||
|
||||
// Colors
|
||||
$blue: #3490dc;
|
||||
$indigo: #6574cd;
|
||||
$purple: #9561e2;
|
||||
$pink: #f66d9b;
|
||||
$red: #e3342f;
|
||||
$orange: #f6993f;
|
||||
$yellow: #ffed4a;
|
||||
$green: #38c172;
|
||||
$teal: #4dc0b5;
|
||||
$cyan: #6cb2eb;
|
||||
10
resources/sass/admin/app.scss
vendored
Normal file
10
resources/sass/admin/app.scss
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
//Boostrap函式庫
|
||||
@import "bootstrap";
|
||||
//元件
|
||||
@import "components/datatables";
|
||||
@import "components/blockui";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
5
resources/sass/admin/components/_blockui.scss
vendored
Normal file
5
resources/sass/admin/components/_blockui.scss
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.blockUI {
|
||||
&.blockOverlay {
|
||||
z-index: 1098 !important;
|
||||
}
|
||||
}
|
||||
14
resources/sass/admin/components/_datatables.scss
vendored
Normal file
14
resources/sass/admin/components/_datatables.scss
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//結果數目
|
||||
div.dataTables_wrapper {
|
||||
div.dataTables_info {
|
||||
white-space: unset;
|
||||
}
|
||||
}
|
||||
//搜尋框
|
||||
div.dataTables_wrapper {
|
||||
div.dataTables_filter {
|
||||
@include media-breakpoint-down(sm) {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
resources/sass/admin/lib.scss
vendored
Normal file
37
resources/sass/admin/lib.scss
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
Fonts
|
||||
*/
|
||||
@import url('https://fonts.googleapis.com/css?family=Nunito');
|
||||
/**
|
||||
Variables
|
||||
*/
|
||||
@import 'variables';
|
||||
/**
|
||||
Bootstrap
|
||||
*/
|
||||
@import '~bootstrap/scss/bootstrap';
|
||||
/**
|
||||
Core UI
|
||||
*/
|
||||
@import "~@coreui/coreui/scss/coreui-standalone";
|
||||
/**
|
||||
CoreUI Icons
|
||||
*/
|
||||
@import "~@coreui/icons/scss/free";
|
||||
/**
|
||||
Flag Icons
|
||||
*/
|
||||
@import "~flag-icon-css/sass/flag-icon";
|
||||
/**
|
||||
Font Awesome
|
||||
*/
|
||||
@import "~font-awesome/scss/font-awesome";
|
||||
/**
|
||||
Simple Line Icons
|
||||
*/
|
||||
@import "~simple-line-icons/scss/simple-line-icons";
|
||||
/**
|
||||
DataTables
|
||||
*/
|
||||
@import "~datatables.net-bs4/css/dataTables.bootstrap4.min.css";
|
||||
@import "~datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css";
|
||||
9
resources/sass/app.scss
vendored
9
resources/sass/app.scss
vendored
@ -1 +1,8 @@
|
||||
//
|
||||
// Fonts
|
||||
@import url('https://fonts.googleapis.com/css?family=Nunito');
|
||||
|
||||
// Variables
|
||||
@import 'variables';
|
||||
|
||||
// Bootstrap
|
||||
@import '~bootstrap/scss/bootstrap';
|
||||
|
||||
3
resources/views/admin/index.blade.php
Normal file
3
resources/views/admin/index.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', 'Admin Area')
|
||||
74
resources/views/admin/layouts/app.blade.php
Normal file
74
resources/views/admin/layouts/app.blade.php
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app()->getLocale() }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
@stack('admin-app-head-scripts')
|
||||
|
||||
@section('admin-app-styles')
|
||||
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600" rel="stylesheet" type="text/css">
|
||||
<link href="{{ asset('css/admin/lib.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset('css/admin/app.css') }}" rel="stylesheet">
|
||||
@show
|
||||
@stack('admin-app-styles')
|
||||
</head>
|
||||
<body class="app admin-area sidebar-lg-show header-fixed sidebar-fixed aside-menu-fixed footer-fixed">
|
||||
<header id="app-header" class="app-header navbar">
|
||||
<button class="navbar-toggler sidebar-toggler d-lg-none mr-auto" type="button" data-toggle="sidebar-show">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<button class="navbar-toggler sidebar-toggler d-md-down-none" type="button" data-toggle="sidebar-lg-show">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="nav-item px-3">
|
||||
<a href="{{ route('index') }}" class="nav-link">Front Stage</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
</ul>
|
||||
|
||||
<button class="navbar-toggler aside-menu-toggler d-md-down-none" type="button" data-toggle="aside-menu-lg-show">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<button class="navbar-toggler aside-menu-toggler d-lg-none" type="button" data-toggle="aside-menu-show">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<form action="{{ route('logout') }}" method="post">
|
||||
@csrf
|
||||
<button class="btn btn-outline-danger btn-sm">登出</button>
|
||||
</form>
|
||||
</header>
|
||||
<div id="app-body" class="app-body">
|
||||
{{-- 左側主選單--}}
|
||||
<div class="sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<ul class="nav">
|
||||
</ul>
|
||||
</nav>
|
||||
<button class="sidebar-minimizer brand-minimizer" type="button"></button>
|
||||
</div>
|
||||
{{-- 主頁面 --}}
|
||||
<main class="main">
|
||||
<div class="container-fluid p-2 p-sm-3 p-md-3">
|
||||
@yield('admin-page-content')
|
||||
</div>
|
||||
</main>
|
||||
{{-- 右側選單 --}}
|
||||
<aside class="aside-menu">
|
||||
</aside>
|
||||
</div>
|
||||
<footer id="app-footer" class="app-footer">
|
||||
|
||||
</footer>
|
||||
@section('admin-app-scripts')
|
||||
<script src="{{ asset('js/admin/app.js') }}"></script>
|
||||
@show
|
||||
@stack('admin-app-scripts')
|
||||
</body>
|
||||
</html>
|
||||
73
resources/views/auth/login.blade.php
Normal file
73
resources/views/auth/login.blade.php
Normal file
@ -0,0 +1,73 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Login') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
|
||||
|
||||
<label class="form-check-label" for="remember">
|
||||
{{ __('Remember Me') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-8 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Login') }}
|
||||
</button>
|
||||
|
||||
@if (Route::has('password.request'))
|
||||
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||
{{ __('Forgot Your Password?') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
49
resources/views/auth/passwords/confirm.blade.php
Normal file
49
resources/views/auth/passwords/confirm.blade.php
Normal file
@ -0,0 +1,49 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Confirm Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
{{ __('Please confirm your password before continuing.') }}
|
||||
|
||||
<form method="POST" action="{{ route('password.confirm') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-8 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Confirm Password') }}
|
||||
</button>
|
||||
|
||||
@if (Route::has('password.request'))
|
||||
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||
{{ __('Forgot Your Password?') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
47
resources/views/auth/passwords/email.blade.php
Normal file
47
resources/views/auth/passwords/email.blade.php
Normal file
@ -0,0 +1,47 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('password.email') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Send Password Reset Link') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
65
resources/views/auth/passwords/reset.blade.php
Normal file
65
resources/views/auth/passwords/reset.blade.php
Normal file
@ -0,0 +1,65 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('password.update') }}">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Reset Password') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
77
resources/views/auth/register.blade.php
Normal file
77
resources/views/auth/register.blade.php
Normal file
@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Register') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('register') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
|
||||
|
||||
@error('name')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Register') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
28
resources/views/auth/verify.blade.php
Normal file
28
resources/views/auth/verify.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Verify Your Email Address') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('resent'))
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ __('A fresh verification link has been sent to your email address.') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ __('Before proceeding, please check your email for a verification link.') }}
|
||||
{{ __('If you did not receive the email') }},
|
||||
<form class="d-inline" method="POST" action="{{ route('verification.resend') }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-link p-0 m-0 align-baseline">{{ __('click here to request another') }}</button>.
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
50
resources/views/components/nav.blade.php
Normal file
50
resources/views/components/nav.blade.php
Normal file
@ -0,0 +1,50 @@
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url('/') }}">
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<!-- Left Side Of Navbar -->
|
||||
<ul class="navbar-nav mr-auto">
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Right Side Of Navbar -->
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<!-- Authentication Links -->
|
||||
@guest
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
|
||||
</li>
|
||||
@if (Route::has('register'))
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
|
||||
</li>
|
||||
@endif
|
||||
@else
|
||||
<li class="nav-item dropdown">
|
||||
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
|
||||
{{ Auth::user()->name }} <span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="{{ route('logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
{{ __('Logout') }}
|
||||
</a>
|
||||
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
||||
@csrf
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
@endguest
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@ -1 +1,23 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content-body')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">Dashboard</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
You are logged in!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@ -19,8 +19,13 @@
|
||||
</head>
|
||||
<body>
|
||||
@section('content-header')
|
||||
@include('components.nav')
|
||||
@show
|
||||
@yield('content-body')
|
||||
|
||||
<main>
|
||||
@yield('content-body')
|
||||
</main>
|
||||
|
||||
@section('content-footer')
|
||||
@show
|
||||
|
||||
|
||||
@ -11,6 +11,20 @@
|
||||
|
|
||||
*/
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('home');
|
||||
/**
|
||||
* Authenticate routes
|
||||
*/
|
||||
Auth::routes(['verify' => true]);
|
||||
|
||||
/**
|
||||
* Static page routes
|
||||
*/
|
||||
Route::view('/', 'home')->name('index');
|
||||
|
||||
/**
|
||||
* Admin routes
|
||||
*/
|
||||
Route::group(['prefix' => config('admin.route'), 'middleware' => ['admin.area'], 'as' => config('admin.route_name_prefix')], function() {
|
||||
Route::get('/', 'AdminPageController@index')->name('index');
|
||||
});
|
||||
|
||||
|
||||
15
webpack.mix.js
vendored
15
webpack.mix.js
vendored
@ -11,5 +11,16 @@ const mix = require('laravel-mix');
|
||||
|
|
||||
*/
|
||||
|
||||
mix.js('resources/js/app.js', 'public/js')
|
||||
.sass('resources/sass/app.scss', 'public/css');
|
||||
let publicJsDir = 'public/js',
|
||||
publicCssDir = 'public/css',
|
||||
publicAdminJsDir = 'public/js/admin',
|
||||
publicAdminCssDir = 'public/css/admin'
|
||||
|
||||
mix.js('resources/js/app.js', publicJsDir)
|
||||
|
||||
mix.sass('resources/sass/app.scss', publicCssDir);
|
||||
|
||||
mix.js('resources/js/admin/app.js', publicAdminJsDir)
|
||||
|
||||
mix.sass('resources/sass/admin/lib.scss', publicAdminCssDir)
|
||||
.sass('resources/sass/admin/app.scss', publicAdminCssDir)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user