feat:动态权限
This commit is contained in:
@@ -43,4 +43,15 @@ class PermissionsController extends Controller
|
||||
{
|
||||
return $this->model->deleteBy($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable
|
||||
*
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function enable($id)
|
||||
{
|
||||
return $this->model->disOrEnable($id, 'hidden');
|
||||
}
|
||||
}
|
||||
|
@@ -55,4 +55,14 @@ class PermissionsModel extends Model
|
||||
{
|
||||
return self::query()->select($this->fieldsInList)->quickSearch()->get()->toTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* is hidden
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isHidden(): bool
|
||||
{
|
||||
return $this->hidden === 2;
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -12,6 +13,10 @@ return new class () extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasTable('roles')) {
|
||||
return ;
|
||||
}
|
||||
|
||||
Schema::create('roles', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('role_name', 30)->comment('角色名称');
|
||||
|
@@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -12,6 +13,10 @@ return new class () extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasTable('jobs')) {
|
||||
return ;
|
||||
}
|
||||
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('job_name', 50)->comment('岗位名称');
|
||||
|
@@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@@ -12,6 +13,10 @@ return new class () extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasTable('departments')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::create('departments', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('parent_id')->default(0)->comment('父级ID');
|
||||
|
@@ -1,48 +0,0 @@
|
||||
<?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('permissions', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('permission_name', 30)->comment('菜单名称');
|
||||
$table->integer('parent_id')->default('1')->comment('父级菜单');
|
||||
$table->string('route', 50)->comment('路由');
|
||||
$table->string('icon', 50)->comment('菜单 icon');
|
||||
$table->string('module', 50)->comment('所属模块');
|
||||
$table->string('permission_mark')->comment('权限标识');
|
||||
$table->string('component')->comment('组件');
|
||||
$table->string('redirect')->comment('组件跳转');
|
||||
$table->tinyInteger('keepalive')->default('1')->comment('1 缓存 2 不缓存');
|
||||
$table->tinyInteger('type')->default('1')->comment('1 菜单 2 按钮');
|
||||
$table->tinyInteger('hidden')->default('1')->comment('1 显示 2 隐藏');
|
||||
$table->integer('sort')->default('1')->comment('排序');
|
||||
$table->creatorId();
|
||||
$table->createdAt();
|
||||
$table->updatedAt();
|
||||
$table->deletedAt();
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->comment('权限模块');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('permissions');
|
||||
}
|
||||
};
|
@@ -12,6 +12,10 @@ return new class () extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasTable('permissions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::create('permissions', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('parent_id')->default(0)->comment('父级菜单');
|
||||
@@ -19,7 +23,7 @@ return new class () extends Migration {
|
||||
$table->string('route', 50)->comment('前端路由');
|
||||
$table->string('icon', 50)->comment('菜单 icon');
|
||||
$table->string('module', 50)->comment('所属模块');
|
||||
$table->string('permission_mark', 100)->comment('权限标识,使用 @ 分割');
|
||||
$table->string('permission_mark', 100)->default('')->comment('权限标识,使用 @ 分割');
|
||||
$table->string('component')->comment('组件');
|
||||
$table->string('redirect')->nullable()->comment('跳转地址');
|
||||
$table->tinyInteger('keepalive')->default('1')->comment('1 缓存 2 不缓存');
|
||||
|
@@ -0,0 +1,34 @@
|
||||
<?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(): void
|
||||
{
|
||||
Schema::create('user_has_roles', function (Blueprint $table) {
|
||||
$table->integer('user_id')->comment('users primary key');
|
||||
|
||||
$table->integer('role_id')->comment('roles primary key');
|
||||
|
||||
$table->comment('user relate roles');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
|
||||
}
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
<?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(): void
|
||||
{
|
||||
Schema::create('role_has_permissions', function (Blueprint $table) {
|
||||
$table->integer('role_id')->comment('roles primary key');
|
||||
|
||||
$table->integer('permission_id')->comment('permissions primary key');
|
||||
|
||||
$table->comment('role relate permissions');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
|
||||
}
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
<?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(): void
|
||||
{
|
||||
Schema::create('user_has_jobs', function (Blueprint $table) {
|
||||
$table->integer('user_id')->comment('users primary key');
|
||||
|
||||
$table->integer('job_id')->comment('jobs primary key');
|
||||
|
||||
$table->comment('user relate jobs');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
|
||||
}
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
<?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(): void
|
||||
{
|
||||
Schema::create('role_has_departments', function (Blueprint $table) {
|
||||
$table->integer('role_id')->comment('roles primary key');
|
||||
|
||||
$table->integer('department_id')->comment('departments primary key');
|
||||
|
||||
$table->comment('role relate departments');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
|
||||
}
|
||||
};
|
@@ -16,5 +16,6 @@ Route::prefix('permissions')->group(function () {
|
||||
Route::put('departments/enable/{id}', [DepartmentsController::class, 'enable']);
|
||||
|
||||
Route::apiResource('permissions', PermissionsController::class);
|
||||
Route::put('permissions/enable/{id}', [PermissionsController::class, 'enable']);
|
||||
//next
|
||||
});
|
||||
|
@@ -35,7 +35,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import Create from './form/create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||
|
@@ -37,7 +37,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import Create from './form/create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||
|
@@ -17,19 +17,53 @@
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单名称" prop="permission_name">
|
||||
<el-input v-model="formData.permission_name" name="permission_name" clearable />
|
||||
<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" />
|
||||
<el-input v-model="formData.permission_name" name="permission_name" clearable v-else />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属模块" prop="module">
|
||||
<Select v-model="formData.module" clearable api="modules" class="w-full" filterable />
|
||||
<el-form-item label="所属模块" prop="module" :rules="[{ required: true, message: '所属模块必须填写' }]" v-if="!isAction">
|
||||
<Select v-model="formData.module" api="modules" @clear="clearModule" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单路由" prop="route">
|
||||
<el-form-item label="路由Path" prop="route" :rules="[{ required: true, message: '路由Path必须填写' }]" v-if="!isAction">
|
||||
<el-input v-model="formData.route" name="route" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="Redirect" prop="redirect">
|
||||
<el-form-item label="Redirect" prop="redirect" v-if="!isAction">
|
||||
<el-input v-model="formData.redirect" name="redirect" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="Keepalive" prop="keepalive">
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" name="sort" :min="1" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="父级菜单" prop="parent_id">
|
||||
<el-cascader :options="permissions" name="parent_id" v-model="formData.parent_id" clearable :props="{ value: 'id', label: 'permission_name', checkStrictly: true }" class="w-full" />
|
||||
</el-form-item>
|
||||
<el-form-item label="权限标识" prop="permission_mark" :rules="[{ required: true, message: '权限标识必须填写' }]" v-if="!isTop">
|
||||
<Select v-model="formData.permission_mark" name="permission_mark" :options="actionMenuNames" allow-create v-if="isAction" />
|
||||
<Select v-model="formData.permission_mark" placeholder="请选择" api="controllers" :query="{ module: formData.module }" v-else />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单Icon" prop="icon" v-if="!isAction">
|
||||
<el-input v-model="formData.icon" name="icon" clearable @focus="open" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组件" prop="component" :rules="[{ required: true, message: '所属组件必须填写' }]" v-if="!isAction">
|
||||
<Select v-model="formData.component" placeholder="请选择" allow-create api="components" :query="{ module: formData.module }" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Hidden" prop="hidden" v-if="!isAction">
|
||||
<el-radio-group v-model="formData.hidden">
|
||||
<el-radio
|
||||
v-for="item in [
|
||||
{ label: '显示', value: 1 },
|
||||
{ label: '隐藏', value: 2 },
|
||||
]"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
name="hidden"
|
||||
>{{ item.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="Keepalive" prop="keepalive" v-if="!isAction">
|
||||
<el-radio-group v-model="formData.keepalive">
|
||||
<el-radio
|
||||
v-for="item in [
|
||||
@@ -44,48 +78,23 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="父级菜单" prop="parent_id">
|
||||
<el-cascader :options="permissions" name="parent_id" v-model="formData.parent_id" clearable :props="{ value: 'id', label: 'permission_name', checkStrictly: true }" class="w-full" />
|
||||
</el-form-item>
|
||||
<el-form-item label="权限标识" prop="permission_mark">
|
||||
<el-input v-model="formData.permission_mark" name="permission_mark" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单Icon" prop="icon">
|
||||
<el-input v-model="formData.icon" name="icon" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组件" prop="component">
|
||||
<el-select v-model="formData.component" placeholder="请选择" clearable class="w-full" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" name="sort" :min="1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Hidden" prop="hidden">
|
||||
<el-radio-group v-model="formData.hidden">
|
||||
<el-radio
|
||||
v-for="item in [
|
||||
{ label: '显示', value: 1 },
|
||||
{ label: '隐藏', value: 2 },
|
||||
]"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
name="hidden"
|
||||
>{{ item.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<Dialog v-model="visible" title="选择 Icon" width="1000px" destroy-on-close>
|
||||
<Icons v-model="formData.icon" @close="closeSelectIcon" />
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useCreate } from '/admin/composables/curd/useCreate'
|
||||
import { useShow } from '/admin/composables/curd/useShow'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import http from '/admin/support/http'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -94,12 +103,23 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const { formData, form, loading, submitForm, close, beforeCreate, beforeUpdate } = useCreate(props.api, props.primary)
|
||||
const { open, visible } = useOpen()
|
||||
|
||||
// 关闭选择
|
||||
const closeSelectIcon = () => {
|
||||
visible.value = false
|
||||
}
|
||||
// 初始化
|
||||
formData.value.sort = 1
|
||||
formData.value.keepalive = 1
|
||||
formData.value.type = 1
|
||||
formData.value.hidden = 1
|
||||
// 默认目录
|
||||
const isTop = ref<boolean>(true)
|
||||
const isMenu = ref<boolean>(false)
|
||||
const isAction = ref<boolean>(false)
|
||||
|
||||
// 回显示表单
|
||||
if (props.primary) {
|
||||
useShow(props.api, props.primary, formData)
|
||||
}
|
||||
@@ -110,14 +130,68 @@ onMounted(() => {
|
||||
http.get(props.api).then(r => {
|
||||
permissions.value = r.data.data
|
||||
})
|
||||
|
||||
// close dialog
|
||||
close(() => emit('close'))
|
||||
|
||||
// 监听 form data
|
||||
watch(
|
||||
formData,
|
||||
(value, oldValue) => {
|
||||
const type: number = formData.value.type
|
||||
|
||||
if (type === 1) {
|
||||
isTop.value = true
|
||||
isMenu.value = isAction.value = false
|
||||
} else if (type === 2) {
|
||||
isMenu.value = true
|
||||
isTop.value = isAction.value = false
|
||||
} else {
|
||||
isAction.value = true
|
||||
isTop.value = isMenu.value = false
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
})
|
||||
|
||||
// 菜单是菜单类型的时,清除模块,那么权限标识&组件也需要清除
|
||||
const clearModule = () => {
|
||||
if (formData.value.type === 1 || formData.value.type === 2) {
|
||||
formData.value.component = null
|
||||
}
|
||||
if (formData.value.type === 2) {
|
||||
formData.value.permission_mark = null
|
||||
}
|
||||
}
|
||||
|
||||
// 当菜单是按钮类型时, 定义两个初始值
|
||||
const actionMenuNames = [
|
||||
{ label: '列表', value: '列表' },
|
||||
{ label: '新增', value: '新增' },
|
||||
{ label: '读取', value: '读取' },
|
||||
{ label: '更新', value: '更新' },
|
||||
{ label: '删除', value: '删除' },
|
||||
{ label: '禁用/启用', value: '禁用/启用' },
|
||||
{ label: '导入', value: '导入' },
|
||||
{ label: '导出', value: '导出' },
|
||||
]
|
||||
|
||||
const actionMenuMark = [
|
||||
{ label: 'index', value: 'index' },
|
||||
{ label: 'store', value: 'store' },
|
||||
{ label: 'show', value: 'show' },
|
||||
{ label: 'update', value: 'update' },
|
||||
{ label: 'destroy', value: 'destroy' },
|
||||
{ label: 'enable', value: 'enable' },
|
||||
{ label: 'import', value: 'import' },
|
||||
{ label: 'export', value: 'export' },
|
||||
]
|
||||
// 创建前的钩子
|
||||
beforeCreate.value = () => {
|
||||
formData.value.parent_id = getParent(formData.value.parent_id)
|
||||
}
|
||||
|
||||
// 更新前的钩子
|
||||
beforeUpdate.value = () => {
|
||||
formData.value.parent_id = getParent(formData.value.parent_id)
|
||||
}
|
@@ -13,7 +13,11 @@
|
||||
<el-table-column prop="permission_name" label="菜单名称" />
|
||||
<el-table-column prop="route" label="菜单路由" />
|
||||
<el-table-column prop="permission_mark" label="权限标识" />
|
||||
<el-table-column prop="hidden" label="状态" />
|
||||
<el-table-column prop="hidden" label="状态">
|
||||
<template #default="scope">
|
||||
<Status v-model="scope.row.hidden" :id="scope.row.id" :api="api" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="创建时间" />
|
||||
<el-table-column label="操作" width="200">
|
||||
<template #default="scope">
|
||||
@@ -31,8 +35,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import { computed, onMounted } from 'vue'
|
||||
import Create from './form/create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||
|
@@ -32,7 +32,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import Create from './form/create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useOpen } from '/admin/composables/curd/useOpen'
|
||||
|
@@ -35,4 +35,4 @@ const router: RouteRecordRaw[] = [
|
||||
},
|
||||
]
|
||||
|
||||
export default router
|
||||
export default []
|
||||
|
Reference in New Issue
Block a user