new feature
This commit is contained in:
7
bootstrap/cache/packages.php
vendored
7
bootstrap/cache/packages.php
vendored
@@ -1,11 +1,4 @@
|
|||||||
<?php return array (
|
<?php return array (
|
||||||
'catchadmin/core' =>
|
|
||||||
array (
|
|
||||||
'providers' =>
|
|
||||||
array (
|
|
||||||
0 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'laravel/tinker' =>
|
'laravel/tinker' =>
|
||||||
array (
|
array (
|
||||||
'providers' =>
|
'providers' =>
|
||||||
|
45
bootstrap/cache/services.php
vendored
45
bootstrap/cache/services.php
vendored
@@ -23,18 +23,17 @@
|
|||||||
19 => 'Illuminate\\Translation\\TranslationServiceProvider',
|
19 => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
20 => 'Illuminate\\Validation\\ValidationServiceProvider',
|
20 => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
21 => 'Illuminate\\View\\ViewServiceProvider',
|
21 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
22 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
22 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
23 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
23 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
24 => 'Carbon\\Laravel\\ServiceProvider',
|
24 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
25 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
25 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
26 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
26 => 'Pest\\Laravel\\PestServiceProvider',
|
||||||
27 => 'Pest\\Laravel\\PestServiceProvider',
|
27 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
|
||||||
28 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
|
28 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
||||||
29 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
29 => 'App\\Providers\\AppServiceProvider',
|
||||||
30 => 'App\\Providers\\AppServiceProvider',
|
30 => 'App\\Providers\\AuthServiceProvider',
|
||||||
31 => 'App\\Providers\\AuthServiceProvider',
|
31 => 'App\\Providers\\EventServiceProvider',
|
||||||
32 => 'App\\Providers\\EventServiceProvider',
|
32 => 'App\\Providers\\RouteServiceProvider',
|
||||||
33 => 'App\\Providers\\RouteServiceProvider',
|
|
||||||
),
|
),
|
||||||
'eager' =>
|
'eager' =>
|
||||||
array (
|
array (
|
||||||
@@ -48,17 +47,16 @@
|
|||||||
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
||||||
8 => 'Illuminate\\Session\\SessionServiceProvider',
|
8 => 'Illuminate\\Session\\SessionServiceProvider',
|
||||||
9 => 'Illuminate\\View\\ViewServiceProvider',
|
9 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
10 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
10 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
11 => 'Carbon\\Laravel\\ServiceProvider',
|
11 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
12 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
12 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
13 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
13 => 'Pest\\Laravel\\PestServiceProvider',
|
||||||
14 => 'Pest\\Laravel\\PestServiceProvider',
|
14 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
|
||||||
15 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
|
15 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
||||||
16 => 'Catch\\Providers\\CatchAdminServiceProvider',
|
16 => 'App\\Providers\\AppServiceProvider',
|
||||||
17 => 'App\\Providers\\AppServiceProvider',
|
17 => 'App\\Providers\\AuthServiceProvider',
|
||||||
18 => 'App\\Providers\\AuthServiceProvider',
|
18 => 'App\\Providers\\EventServiceProvider',
|
||||||
19 => 'App\\Providers\\EventServiceProvider',
|
19 => 'App\\Providers\\RouteServiceProvider',
|
||||||
20 => 'App\\Providers\\RouteServiceProvider',
|
|
||||||
),
|
),
|
||||||
'deferred' =>
|
'deferred' =>
|
||||||
array (
|
array (
|
||||||
@@ -69,7 +67,6 @@
|
|||||||
'Illuminate\\Contracts\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
'Illuminate\\Contracts\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
'Illuminate\\Contracts\\Bus\\QueueingDispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
'Illuminate\\Contracts\\Bus\\QueueingDispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
'Illuminate\\Bus\\BatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
'Illuminate\\Bus\\BatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
'Illuminate\\Bus\\DatabaseBatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
|
||||||
'cache' => 'Illuminate\\Cache\\CacheServiceProvider',
|
'cache' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
'cache.store' => 'Illuminate\\Cache\\CacheServiceProvider',
|
'cache.store' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
'cache.psr6' => 'Illuminate\\Cache\\CacheServiceProvider',
|
'cache.psr6' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"catchadmin/core": "dev-main",
|
|
||||||
"doctrine/dbal": "^3.4",
|
"doctrine/dbal": "^3.4",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"laravel/framework": "^9.33",
|
"laravel/framework": "^9.33",
|
||||||
|
1574
composer.lock
generated
1574
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@ class Schemas extends CatchModel
|
|||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected array $mergeCasts = [
|
protected $casts = [
|
||||||
'is_soft_delete' => Status::class
|
'is_soft_delete' => Status::class
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ class Components implements OptionInterface
|
|||||||
public function get(): array
|
public function get(): array
|
||||||
{
|
{
|
||||||
if ($module = request()->get('module')) {
|
if ($module = request()->get('module')) {
|
||||||
$components = File::glob(CatchAdmin::getModuleViewsPath($module).'*/*.vue');
|
$components = File::glob(CatchAdmin::getModuleViewsPath($module).'*'.DIRECTORY_SEPARATOR.'*.vue');
|
||||||
|
|
||||||
foreach ($components as $component) {
|
foreach ($components as $component) {
|
||||||
$this->components[] = [
|
$this->components[] = [
|
||||||
|
@@ -4,14 +4,16 @@ namespace Modules\Permissions\Middlewares;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Modules\Permissions\Exceptions\PermissionForbidden;
|
use Modules\Permissions\Exceptions\PermissionForbidden;
|
||||||
|
use Modules\Permissions\Models\LogOperate;
|
||||||
use Modules\User\Models\User;
|
use Modules\User\Models\User;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class PermissionGate
|
class PermissionGate
|
||||||
{
|
{
|
||||||
public function handle(Request $request, \Closure $next)
|
public function handle(Request $request, \Closure $next)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
if ($request->isMethod('get')) {
|
||||||
return $next($request);
|
// return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @var User $user */
|
/* @var User $user */
|
||||||
@@ -23,4 +25,17 @@ class PermissionGate
|
|||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* terminate
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function terminate(Request $request, Response $response): void
|
||||||
|
{
|
||||||
|
app(LogOperate::class)->log($request, $response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
121
modules/Permissions/Models/LogOperate.php
Normal file
121
modules/Permissions/Models/LogOperate.php
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Permissions\Models;
|
||||||
|
|
||||||
|
use Catch\CatchAdmin;
|
||||||
|
use Catch\Traits\DB\BaseOperate;
|
||||||
|
use Catch\Traits\DB\ScopeTrait;
|
||||||
|
use Catch\Traits\DB\Trans;
|
||||||
|
use Illuminate\Contracts\Http\Kernel;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Modules\Permissions\Exceptions\PermissionForbidden;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class LogOperate extends Model
|
||||||
|
{
|
||||||
|
use BaseOperate, Trans, ScopeTrait;
|
||||||
|
|
||||||
|
protected $table = 'log_operate';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'module',
|
||||||
|
'operate',
|
||||||
|
'route',
|
||||||
|
'params',
|
||||||
|
'ip',
|
||||||
|
'http_method',
|
||||||
|
'http_method',
|
||||||
|
'start_at',
|
||||||
|
'time_taken',
|
||||||
|
'creator_id',
|
||||||
|
'created_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function log(Request $request, Response $response): void
|
||||||
|
{
|
||||||
|
if (! $response->isOk() && $response->exception instanceof PermissionForbidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = Auth::guard(getGuardName())->user();
|
||||||
|
|
||||||
|
$userModel = getAuthUserModel();
|
||||||
|
|
||||||
|
if (! $user instanceof $userModel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$user->getAttribute('permissions')->each(function ($permission) use ($user, $request, $response) {
|
||||||
|
if ($permission->isAction()) {
|
||||||
|
[$controller, $action] = explode('@', $permission->permission_mark);
|
||||||
|
|
||||||
|
if (! CatchAdmin::getModuleControllerNamespace($permission->module).$controller.'Controller@'.$action == Route::currentRouteAction()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestStartAt = app(Kernel::class)->requestStartedAt()->timestamp;
|
||||||
|
|
||||||
|
$params = $request->all();
|
||||||
|
// 如果参数过长则不记录
|
||||||
|
if (!empty($params)) {
|
||||||
|
if (strlen($encodeParams = \json_encode($params, JSON_UNESCAPED_UNICODE)) > 5000) {
|
||||||
|
$params = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storeBy([
|
||||||
|
'module' => $permission->module,
|
||||||
|
|
||||||
|
'operate' => $permission->permission_name,
|
||||||
|
|
||||||
|
'route' => $permission->permission_mark,
|
||||||
|
|
||||||
|
'creator_id' => $user->id,
|
||||||
|
|
||||||
|
'http_method' => $request->method(),
|
||||||
|
|
||||||
|
'http_code' => $response->getStatusCode(),
|
||||||
|
|
||||||
|
'start_at' => $requestStartAt,
|
||||||
|
|
||||||
|
'time_taken' => time() - $requestStartAt,
|
||||||
|
|
||||||
|
'ip' => $request->ip(),
|
||||||
|
|
||||||
|
'params' => !empty($params) ? $encodeParams : '',
|
||||||
|
|
||||||
|
'created_at' => time()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Attribute
|
||||||
|
*/
|
||||||
|
protected function timeTaken(): Attribute
|
||||||
|
{
|
||||||
|
return new Attribute(
|
||||||
|
get: fn($value) => $value . 's',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -93,6 +93,16 @@ class PermissionsModel extends Model
|
|||||||
return $this->type == MenuType::Action;
|
return $this->type == MenuType::Action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is top menu
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isTopMenu(): bool
|
||||||
|
{
|
||||||
|
return $this->type == MenuType::Top;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* actions
|
* actions
|
||||||
*
|
*
|
||||||
@@ -121,8 +131,33 @@ class PermissionsModel extends Model
|
|||||||
$model->setAttribute('component', '');
|
$model->setAttribute('component', '');
|
||||||
$model->setAttribute('redirect', '');
|
$model->setAttribute('redirect', '');
|
||||||
return $model->setCreatorId()->save();
|
return $model->setCreatorId()->save();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if ($model->isTopMenu()) {
|
||||||
|
$data['route'] = '/' . trim($data['route'], '/');
|
||||||
|
}
|
||||||
|
|
||||||
return parent::storeBy($data);
|
return parent::storeBy($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update data
|
||||||
|
*
|
||||||
|
* @param $id
|
||||||
|
* @param array $data
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function updateBy($id, array $data): mixed
|
||||||
|
{
|
||||||
|
$model = $this->fill($data);
|
||||||
|
|
||||||
|
if ($model->isAction()) {
|
||||||
|
/* @var PermissionsModel $parentMenu */
|
||||||
|
$parentMenu = $this->firstBy($model->parent_id, 'id');
|
||||||
|
$data['permission_mark'] = $parentMenu->permission_mark . '@' . $data['permission_mark'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::updateBy($id, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ namespace Modules\Permissions\Providers;
|
|||||||
use Catch\CatchAdmin;
|
use Catch\CatchAdmin;
|
||||||
use Catch\Providers\CatchModuleServiceProvider;
|
use Catch\Providers\CatchModuleServiceProvider;
|
||||||
use Modules\Permissions\Middlewares\PermissionGate;
|
use Modules\Permissions\Middlewares\PermissionGate;
|
||||||
|
use Modules\Permissions\Models\LogOperate;
|
||||||
|
|
||||||
class PermissionsServiceProvider extends CatchModuleServiceProvider
|
class PermissionsServiceProvider extends CatchModuleServiceProvider
|
||||||
{
|
{
|
||||||
@@ -34,4 +35,7 @@ class PermissionsServiceProvider extends CatchModuleServiceProvider
|
|||||||
// TODO: Implement path() method.
|
// TODO: Implement path() method.
|
||||||
return CatchAdmin::getModuleRoutePath('Permissions');
|
return CatchAdmin::getModuleRoutePath('Permissions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,8 @@ return new class () extends Migration {
|
|||||||
$table->updatedAt();
|
$table->updatedAt();
|
||||||
$table->deletedAt();
|
$table->deletedAt();
|
||||||
|
|
||||||
|
$table->index(['module', 'permission_mark']);
|
||||||
|
|
||||||
$table->engine = 'InnoDB';
|
$table->engine = 'InnoDB';
|
||||||
$table->comment('权限表');
|
$table->comment('权限表');
|
||||||
});
|
});
|
||||||
|
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('log_operate', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('module', 50)->comment('操作');
|
||||||
|
$table->string('operate', 50)->comment('操作');
|
||||||
|
$table->string('route', 50)->comment('路由');
|
||||||
|
$table->text('params')->comment('参数');
|
||||||
|
$table->string('ip')->comment('ip 地址');
|
||||||
|
$table->string('http_method', 10)->comment('http 请求方式');
|
||||||
|
$table->string('http_code')->comment('http status code');
|
||||||
|
$table->string('start_at')->comment('请求开始时间');
|
||||||
|
$table->string('time_taken')->comment('请求消耗时间/s');
|
||||||
|
$table->creatorId();
|
||||||
|
$table->createdAt();
|
||||||
|
|
||||||
|
$table->engine='InnoDB';
|
||||||
|
$table->comment('操作日志');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('log_operate');
|
||||||
|
}
|
||||||
|
};
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form :model="formData" label-width="80px" ref="form" v-loading="loading" class="pr-4">
|
<el-form :model="formData" label-width="85px" ref="form" v-loading="loading" class="pr-4">
|
||||||
<div class="flex flex-row justify-between">
|
<div class="flex flex-row justify-between">
|
||||||
<div>
|
<div>
|
||||||
<el-form-item label="菜单类型" prop="type">
|
<el-form-item label="菜单类型" prop="type">
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单名称" prop="permission_name" :rules="[{ required: true, message: '菜单名称必须填写' }]">
|
<el-form-item label="菜单名称" prop="permission_name" :rules="[{ required: true, message: '菜单名称必须填写' }]">
|
||||||
<Select v-model="formData.permission_name" name="permission_name" :options="actionMenuNames" v-if="isAction" />
|
<Select v-model="formData.permission_name" name="permission_name" allow-create :options="actionMenuNames" v-if="isAction" />
|
||||||
<el-input v-model="formData.permission_name" name="permission_name" clearable v-else />
|
<el-input v-model="formData.permission_name" name="permission_name" clearable v-else />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="所属模块" prop="module" :rules="[{ required: true, message: '所属模块必须填写' }]" v-if="!isAction">
|
<el-form-item label="所属模块" prop="module" :rules="[{ required: true, message: '所属模块必须填写' }]" v-if="!isAction">
|
||||||
@@ -93,9 +93,9 @@
|
|||||||
import { useCreate } from '/admin/composables/curd/useCreate'
|
import { useCreate } from '/admin/composables/curd/useCreate'
|
||||||
import { useShow } from '/admin/composables/curd/useShow'
|
import { useShow } from '/admin/composables/curd/useShow'
|
||||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||||
|
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { onMounted, ref, watch } from 'vue'
|
||||||
import http from '/admin/support/http'
|
import http from '/admin/support/http'
|
||||||
|
import { MenuType } from '/admin/enum/app'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
primary: String | Number,
|
primary: String | Number,
|
||||||
@@ -109,11 +109,15 @@ const { open, visible } = useOpen()
|
|||||||
const closeSelectIcon = () => {
|
const closeSelectIcon = () => {
|
||||||
visible.value = false
|
visible.value = false
|
||||||
}
|
}
|
||||||
|
const defaultSort = 1
|
||||||
|
const defaultKeepalive = 1
|
||||||
|
const defaultHidden = 1
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
formData.value.sort = 1
|
formData.value.sort = defaultSort
|
||||||
formData.value.keepalive = 1
|
formData.value.keepalive = defaultKeepalive
|
||||||
formData.value.type = 1
|
formData.value.type = MenuType.TOP_TYPE
|
||||||
formData.value.hidden = 1
|
formData.value.hidden = defaultHidden
|
||||||
// 默认目录
|
// 默认目录
|
||||||
const isTop = ref<boolean>(true)
|
const isTop = ref<boolean>(true)
|
||||||
const isMenu = ref<boolean>(false)
|
const isMenu = ref<boolean>(false)
|
||||||
@@ -121,7 +125,14 @@ const isAction = ref<boolean>(false)
|
|||||||
|
|
||||||
// 回显示表单
|
// 回显示表单
|
||||||
if (props.primary) {
|
if (props.primary) {
|
||||||
useShow(props.api, props.primary, formData)
|
const { afterShow } = useShow(props.api, props.primary, formData)
|
||||||
|
|
||||||
|
afterShow.value = formData => {
|
||||||
|
console.log(formData.value.permission_mark)
|
||||||
|
if (formData.value.permission_mark.indexOf('@') !== -1) {
|
||||||
|
formData.value.permission_mark = formData.value.permission_mark.split('@')[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
@@ -130,7 +141,7 @@ onMounted(() => {
|
|||||||
http.get(props.api).then(r => {
|
http.get(props.api).then(r => {
|
||||||
permissions.value = r.data.data
|
permissions.value = r.data.data
|
||||||
})
|
})
|
||||||
// close dialog
|
|
||||||
close(() => emit('close'))
|
close(() => emit('close'))
|
||||||
|
|
||||||
// 监听 form data
|
// 监听 form data
|
||||||
@@ -138,11 +149,10 @@ onMounted(() => {
|
|||||||
formData,
|
formData,
|
||||||
() => {
|
() => {
|
||||||
const type: number = formData.value.type
|
const type: number = formData.value.type
|
||||||
|
if (type === MenuType.TOP_TYPE) {
|
||||||
if (type === 1) {
|
|
||||||
isTop.value = true
|
isTop.value = true
|
||||||
isMenu.value = isAction.value = false
|
isMenu.value = isAction.value = false
|
||||||
} else if (type === 2) {
|
} else if (type === MenuType.PAGE_TYPE) {
|
||||||
isMenu.value = true
|
isMenu.value = true
|
||||||
isTop.value = isAction.value = false
|
isTop.value = isAction.value = false
|
||||||
} else {
|
} else {
|
||||||
@@ -156,10 +166,10 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 菜单是菜单类型的时,清除模块,那么权限标识&组件也需要清除
|
// 菜单是菜单类型的时,清除模块,那么权限标识&组件也需要清除
|
||||||
const clearModule = () => {
|
const clearModule = () => {
|
||||||
if (formData.value.type === 1 || formData.value.type === 2) {
|
if (formData.value.type === MenuType.TOP_TYPE || formData.value.type === MenuType.PAGE_TYPE) {
|
||||||
formData.value.component = null
|
formData.value.component = null
|
||||||
}
|
}
|
||||||
if (formData.value.type === 2) {
|
if (formData.value.type === MenuType.PAGE_TYPE) {
|
||||||
formData.value.permission_mark = null
|
formData.value.permission_mark = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,6 +207,10 @@ beforeUpdate.value = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getParent = (parentId: any) => {
|
const getParent = (parentId: any) => {
|
||||||
|
if (typeof parentId === 'number') {
|
||||||
|
return parentId
|
||||||
|
}
|
||||||
|
|
||||||
return typeof parentId === 'undefined' ? 0 : parentId[parentId.length - 1]
|
return typeof parentId === 'undefined' ? 0 : parentId[parentId.length - 1]
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -14,8 +14,8 @@
|
|||||||
<el-table-column prop="route" label="菜单路由" />
|
<el-table-column prop="route" label="菜单路由" />
|
||||||
<el-table-column prop="permission_mark" label="权限标识" width="300">
|
<el-table-column prop="permission_mark" label="权限标识" width="300">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div v-if="scope.row.actions.length" class="flex gap gap-1">
|
<div v-if="scope.row.actions.length" class="flex grid gap-1 grid-cols-4">
|
||||||
<el-tag v-for="action in scope.row.actions" class="cursor-pointer" @click="open(action.id)" closable @close="destroy(api, action.id)">{{ action.permission_name }}</el-tag>
|
<el-tag v-for="action in scope.row.actions" class="cursor-pointer min-w-fit" @click="open(action.id)" closable @close="destroy(api, action.id)">{{ action.permission_name }}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -46,6 +46,7 @@ import Create from './form/create.vue'
|
|||||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||||
|
import { MenuType } from '/admin/enum/app'
|
||||||
|
|
||||||
const api = 'permissions/permissions'
|
const api = 'permissions/permissions'
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ use Catch\Support\Module\ModuleRepository;
|
|||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Modules\Permissions\Models\PermissionsModel;
|
||||||
|
|
||||||
trait UserRelations
|
trait UserRelations
|
||||||
{
|
{
|
||||||
@@ -50,15 +51,21 @@ trait UserRelations
|
|||||||
*/
|
*/
|
||||||
public function withPermissions(): self
|
public function withPermissions(): self
|
||||||
{
|
{
|
||||||
/* @var \Modules\Permissions\Models\PermissionsModel $permissionsModel */
|
/* @var PermissionsModel $permissionsModel */
|
||||||
$permissionsModel = app($this->getPermissionsModel());
|
$permissionsModel = app($this->getPermissionsModel());
|
||||||
|
|
||||||
if ($this->isSuperAdmin()) {
|
if ($this->isSuperAdmin()) {
|
||||||
$permissions = $permissionsModel->get();
|
$permissions = $permissionsModel->get();
|
||||||
} else {
|
} else {
|
||||||
$roles = app($this->getRolesModel())->with(['permissions'])->get();
|
$permissions = Collection::make();
|
||||||
|
|
||||||
$permissions = [];
|
app($this->getRolesModel())->with(['permissions'])->get()
|
||||||
|
|
||||||
|
->each(function ($role) use (&$permissions){
|
||||||
|
$permissions = $permissions->concat($role->permissions);
|
||||||
|
});
|
||||||
|
|
||||||
|
$permissions = $permissions->unique();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setAttribute('permissions', $permissions->each(fn ($permission) => $permission->setAttribute('hidden', $permission->isHidden())));
|
$this->setAttribute('permissions', $permissions->each(fn ($permission) => $permission->setAttribute('hidden', $permission->isHidden())));
|
||||||
@@ -80,14 +87,14 @@ trait UserRelations
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isSuperAdmin()) {
|
if ($this->isSuperAdmin()) {
|
||||||
return true;
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->withPermissions();
|
$this->withPermissions();
|
||||||
|
|
||||||
$actions = Collection::make();
|
$actions = Collection::make();
|
||||||
|
|
||||||
$this->permissions->each(function ($permission) use (&$actions) {
|
$this->getAttribute('permissions')->each(function ($permission) use (&$actions) {
|
||||||
if ($permission->isAction()) {
|
if ($permission->isAction()) {
|
||||||
[$controller, $action] = explode('@', $permission->permission_mark);
|
[$controller, $action] = explode('@', $permission->permission_mark);
|
||||||
|
|
||||||
|
44
package.json
44
package.json
@@ -9,12 +9,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/vue": "^2.0.13",
|
"@heroicons/vue": "^2.0.13",
|
||||||
"@vueuse/core": "^9.5.0",
|
"@vueuse/core": "^9.7.0",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"element-plus": "^2.2.25",
|
"element-plus": "^2.2.27",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.27",
|
"pinia": "^2.0.28",
|
||||||
"postcss": "^8.4.18",
|
"postcss": "^8.4.20",
|
||||||
"tailwindcss": "^3.2.2",
|
"tailwindcss": "^3.2.2",
|
||||||
"terser": "^5.15.1",
|
"terser": "^5.15.1",
|
||||||
"vue": "^3.2.44",
|
"vue": "^3.2.44",
|
||||||
@@ -23,30 +23,30 @@
|
|||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/logos": "^1.1.18",
|
"@iconify-json/logos": "^1.1.19",
|
||||||
"@rollup/plugin-alias": "^4.0.2",
|
"@rollup/plugin-alias": "^4.0.2",
|
||||||
"@types/mockjs": "^1.0.7",
|
"@types/mockjs": "^1.0.7",
|
||||||
"@types/node": "^18.11.9",
|
"@types/node": "^18.11.16",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
||||||
"@typescript-eslint/parser": "^5.42.1",
|
"@typescript-eslint/parser": "^5.46.1",
|
||||||
"@vitejs/plugin-vue": "^3.2.0",
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
"@vitejs/plugin-vue-jsx": "^2.1.1",
|
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.2.1",
|
||||||
"eslint": "^8.27.0",
|
"eslint": "^8.30.0",
|
||||||
"eslint-config-standard": "^17.0.0",
|
"eslint-config-standard": "^17.0.0",
|
||||||
"eslint-plugin-import": "^2.25.2",
|
"eslint-plugin-import": "^2.25.2",
|
||||||
"eslint-plugin-n": "^15.5.1",
|
"eslint-plugin-n": "^15.6.0",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-vue": "^9.7.0",
|
"eslint-plugin-vue": "^9.8.0",
|
||||||
"prettier": "2.8.0",
|
"prettier": "2.8.1",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.57.0",
|
||||||
"typescript": "^4.8.4",
|
"typescript": "^4.9.4",
|
||||||
"unplugin-auto-import": "^0.11.4",
|
"unplugin-auto-import": "^0.12.1",
|
||||||
"unplugin-icons": "^0.14.13",
|
"unplugin-icons": "^0.14.15",
|
||||||
"unplugin-vue-components": "^0.22.9",
|
"unplugin-vue-components": "^0.22.12",
|
||||||
"vite": "^3.2.3",
|
"vite": "^4.0.1",
|
||||||
"vite-plugin-html": "^3.2.0",
|
"vite-plugin-html": "^3.2.0",
|
||||||
"vue-tsc": "^1.0.9"
|
"vue-tsc": "^1.0.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,8 +44,9 @@ const guard = (router: Router) => {
|
|||||||
}
|
}
|
||||||
next({ ...to, replace: true })
|
next({ ...to, replace: true })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
removeAuthToken()
|
removeAuthToken()
|
||||||
next({ path: `${WhiteListPage.LOGIN_PATH}?redirect=${to.path}` })
|
next({ path: `${WhiteListPage.LOGIN_PATH}?redirect=/${to.path}` })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ export const useUserStore = defineStore('UserStore', {
|
|||||||
return {
|
return {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
||||||
nickname: '',
|
username: '',
|
||||||
|
|
||||||
avatar: '',
|
avatar: '',
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ export const useUserStore = defineStore('UserStore', {
|
|||||||
return this.id
|
return this.id
|
||||||
},
|
},
|
||||||
getNickname(): string {
|
getNickname(): string {
|
||||||
return this.nickname
|
return this.username
|
||||||
},
|
},
|
||||||
|
|
||||||
getAvatar(): string {
|
getAvatar(): string {
|
||||||
@@ -52,8 +52,8 @@ export const useUserStore = defineStore('UserStore', {
|
|||||||
isSuperAdmin(): boolean {
|
isSuperAdmin(): boolean {
|
||||||
return this.id === 1
|
return this.id === 1
|
||||||
},
|
},
|
||||||
setNickname(nickname: string) {
|
setUsername(username: string) {
|
||||||
this.nickname = nickname
|
this.username = username
|
||||||
},
|
},
|
||||||
|
|
||||||
setId(id: number) {
|
setId(id: number) {
|
||||||
@@ -130,10 +130,10 @@ export const useUserStore = defineStore('UserStore', {
|
|||||||
http
|
http
|
||||||
.get('/user/online')
|
.get('/user/online')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const { id, nickname, email, avatar, permissions, roles, rememberToken, status } = response.data.data
|
const { id, username, email, avatar, permissions, roles, rememberToken, status } = response.data.data
|
||||||
// set user info
|
// set user info
|
||||||
this.setId(id)
|
this.setId(id)
|
||||||
this.setNickname(nickname)
|
this.setUsername(username)
|
||||||
this.setEmail(email)
|
this.setEmail(email)
|
||||||
this.setRoles(roles)
|
this.setRoles(roles)
|
||||||
this.setRememberToken(rememberToken)
|
this.setRememberToken(rememberToken)
|
||||||
|
@@ -188,6 +188,7 @@ class Http {
|
|||||||
router.push('/login')
|
router.push('/login')
|
||||||
})
|
})
|
||||||
} else if (code === Code.LOGIN_BLACKLIST || code === Code.USER_FORBIDDEN) {
|
} else if (code === Code.LOGIN_BLACKLIST || code === Code.USER_FORBIDDEN) {
|
||||||
|
console.log(123123)
|
||||||
Message.error(message || 'Error')
|
Message.error(message || 'Error')
|
||||||
removeAuthToken()
|
removeAuthToken()
|
||||||
// to login page
|
// to login page
|
||||||
|
@@ -1,22 +1,21 @@
|
|||||||
|
|
||||||
// login user type
|
// login user type
|
||||||
|
|
||||||
import { Permission } from './permission'
|
import { Permission } from './permission'
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number,
|
id: number
|
||||||
|
|
||||||
nickname: string,
|
username: string
|
||||||
|
|
||||||
avatar: string,
|
avatar: string
|
||||||
|
|
||||||
email: string,
|
email: string
|
||||||
|
|
||||||
status: number,
|
status: number
|
||||||
|
|
||||||
remember_token: string,
|
remember_token: string
|
||||||
|
|
||||||
roles?: string[],
|
roles?: string[]
|
||||||
|
|
||||||
permissions?: Permission[]
|
permissions?: Permission[]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user