feat: 菜单新增 active_menu 字段
This commit is contained in:
parent
b81d4796ff
commit
bcf3d9ec34
@ -26,6 +26,7 @@ use Modules\Permissions\Enums\MenuType;
|
|||||||
* @property $type
|
* @property $type
|
||||||
* @property $hidden
|
* @property $hidden
|
||||||
* @property $sort
|
* @property $sort
|
||||||
|
* @property $active_menu
|
||||||
* @property $creator_id
|
* @property $creator_id
|
||||||
* @property $created_at
|
* @property $created_at
|
||||||
* @property $updated_at
|
* @property $updated_at
|
||||||
@ -35,19 +36,19 @@ class Permissions extends Model
|
|||||||
{
|
{
|
||||||
protected $table = 'permissions';
|
protected $table = 'permissions';
|
||||||
|
|
||||||
protected $fillable = ['id', 'parent_id', 'permission_name', 'route', 'icon', 'module', 'permission_mark', 'component', 'redirect', 'keepalive', 'type', 'hidden', 'is_inner', 'sort', 'creator_id', 'created_at', 'updated_at', 'deleted_at'];
|
protected $fillable = ['id', 'parent_id', 'permission_name', 'route', 'icon', 'module', 'permission_mark', 'component', 'redirect', 'keepalive', 'type', 'hidden', 'active_menu', 'sort', 'creator_id', 'created_at', 'updated_at', 'deleted_at'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected array $fields = ['id','parent_id','permission_name','route','icon','module','permission_mark','component','redirect','keepalive','type','hidden','is_inner','sort','created_at','updated_at'];
|
protected array $fields = ['id','parent_id','permission_name','route','icon','module','permission_mark','component','redirect','keepalive','type','hidden','active_menu','sort','created_at','updated_at'];
|
||||||
|
|
||||||
protected bool $isPaginate = false;
|
protected bool $isPaginate = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected array $form = ['parent_id','permission_name','route','icon','module','permission_mark','component','redirect','keepalive','type','is_inner', 'hidden','sort'];
|
protected array $form = ['parent_id','permission_name','route','icon','module','permission_mark','component','redirect','keepalive','type','active_menu', 'hidden','sort'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
|
@ -28,7 +28,6 @@ return new class () extends Migration {
|
|||||||
$table->string('redirect')->nullable()->comment('跳转地址');
|
$table->string('redirect')->nullable()->comment('跳转地址');
|
||||||
$table->tinyInteger('keepalive')->default(1)->comment('1 缓存 2 不缓存');
|
$table->tinyInteger('keepalive')->default(1)->comment('1 缓存 2 不缓存');
|
||||||
$table->tinyInteger('type')->default(1)->comment('1 目录 2 菜单 3 按钮');
|
$table->tinyInteger('type')->default(1)->comment('1 目录 2 菜单 3 按钮');
|
||||||
$table->tinyInteger('is_inner')->default(2)->comment('1 是 2 否');
|
|
||||||
$table->tinyInteger('hidden')->default(1)->comment('1 显示 2 隐藏');
|
$table->tinyInteger('hidden')->default(1)->comment('1 显示 2 隐藏');
|
||||||
$table->integer('sort')->default(1)->comment('排序');
|
$table->integer('sort')->default(1)->comment('排序');
|
||||||
$table->creatorId();
|
$table->creatorId();
|
||||||
|
@ -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::table('permissions', function (Blueprint $table) {
|
||||||
|
if (Schema::hasColumn('permissions', 'is_inner')) {
|
||||||
|
$table->removeColumn('is_inner');
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->string('active_menu')->default('')->comment('访问内页时,需要激活的菜单栏')->after('sort');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
@ -32,20 +32,6 @@
|
|||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="排序" prop="sort">
|
||||||
<el-input-number v-model="formData.sort" name="sort" :min="1" />
|
<el-input-number v-model="formData.sort" name="sort" :min="1" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="内页" prop="is_inner" v-if="isMenu">
|
|
||||||
<el-radio-group v-model="formData.is_inner">
|
|
||||||
<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>
|
<div>
|
||||||
<el-form-item label="父级菜单" prop="parent_id">
|
<el-form-item label="父级菜单" prop="parent_id">
|
||||||
@ -92,6 +78,16 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-form-item label="激活菜单" prop="active_menu" v-if="isMenu">
|
||||||
|
<div class="w-full flex flex-row">
|
||||||
|
<el-input v-model="formData.active_menu" name="active_menu" clearable class="w-3/4" />
|
||||||
|
<el-tooltip effect="dark" :content="activeMenuIntro" raw-content placement="top">
|
||||||
|
<div class="text-red-500 cursor-pointer w-1/4 ml-2 justify-center flex">说明</div>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
|
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -115,6 +111,9 @@ const props = defineProps({
|
|||||||
api: String,
|
api: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const activeMenuIntro =
|
||||||
|
'<div>如果是访问内页的菜单路由,例如创建文章 create/post, 虽然它隶属于文章列表,但实际上并不会嵌套在文章列表路由里</div><div>而是单独的一个路由,并且是不显示在左侧菜单的。所以在访问它的时候,需要左侧菜单高亮,则需要设置该参数</div>'
|
||||||
|
|
||||||
const { formData, form, loading, submitForm, close, beforeCreate, beforeUpdate } = useCreate(props.api, props.primary)
|
const { formData, form, loading, submitForm, close, beforeCreate, beforeUpdate } = useCreate(props.api, props.primary)
|
||||||
|
|
||||||
// 选择 icon
|
// 选择 icon
|
||||||
@ -128,13 +127,12 @@ const closeSelectIcon = () => {
|
|||||||
const defaultSort = 1
|
const defaultSort = 1
|
||||||
const defaultKeepalive = 1
|
const defaultKeepalive = 1
|
||||||
const defaultHidden = 1
|
const defaultHidden = 1
|
||||||
const defaultIsInner = 2
|
|
||||||
// 初始化
|
// 初始化
|
||||||
formData.value.sort = defaultSort
|
formData.value.sort = defaultSort
|
||||||
formData.value.keepalive = defaultKeepalive
|
formData.value.keepalive = defaultKeepalive
|
||||||
formData.value.type = MenuType.TOP_TYPE
|
formData.value.type = MenuType.TOP_TYPE
|
||||||
formData.value.hidden = defaultHidden
|
formData.value.hidden = defaultHidden
|
||||||
formData.value.is_inner = defaultIsInner
|
|
||||||
|
|
||||||
// 默认目录
|
// 默认目录
|
||||||
const isTop = ref<boolean>(true)
|
const isTop = ref<boolean>(true)
|
||||||
|
@ -19,9 +19,9 @@ const breadcrumbs = ref<string[]>([])
|
|||||||
|
|
||||||
// 监听当前路由的变化
|
// 监听当前路由的变化
|
||||||
watch(router.currentRoute, (newValue, oldValue) => {
|
watch(router.currentRoute, (newValue, oldValue) => {
|
||||||
// 如果是内页,则不切换激活菜单
|
// 激活菜单
|
||||||
if (newValue.meta.is_inner === undefined || !newValue.meta.is_inner) {
|
if (newValue.meta.active_menu) {
|
||||||
appStore.setActiveMenu(newValue.path)
|
appStore.setActiveMenu(newValue.meta.active_menu)
|
||||||
}
|
}
|
||||||
getBreadcrumbs(newValue)
|
getBreadcrumbs(newValue)
|
||||||
})
|
})
|
||||||
@ -29,7 +29,12 @@ watch(router.currentRoute, (newValue, oldValue) => {
|
|||||||
// get init breadcrumb
|
// get init breadcrumb
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (router.currentRoute.value.path !== '/') {
|
if (router.currentRoute.value.path !== '/') {
|
||||||
appStore.setActiveMenu(router.currentRoute.value.path)
|
// 如果是内页,并且设置激活菜单
|
||||||
|
if (router.currentRoute.value.meta.active_menu) {
|
||||||
|
appStore.setActiveMenu(router.currentRoute.value.meta.active_menu)
|
||||||
|
} else {
|
||||||
|
appStore.setActiveMenu(router.currentRoute.value.path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getBreadcrumbs(router.currentRoute.value)
|
getBreadcrumbs(router.currentRoute.value)
|
||||||
|
@ -1,103 +1,110 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Editor :api-key="aipKey" :init="config" v-model="content"/>
|
<Editor :api-key="aipKey" :init="config" v-model="content" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Editor from "@tinymce/tinymce-vue";
|
import Editor from '@tinymce/tinymce-vue'
|
||||||
import { env } from '/admin/support/helper'
|
import { env } from '/admin/support/helper'
|
||||||
import Http from "/admin/support/http"
|
import Http from '/admin/support/http'
|
||||||
import Message from '/admin/support/message'
|
import Message from '/admin/support/message'
|
||||||
import {ref, watch, watchEffect} from "vue";
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
require: true,
|
require: true,
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: false,
|
required: false,
|
||||||
default: 'auto'
|
default: 'auto',
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: false,
|
required: false,
|
||||||
default: 'auto'
|
default: 'auto',
|
||||||
},
|
},
|
||||||
language: {
|
language: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'zh_CN'
|
default: 'zh_CN',
|
||||||
},
|
},
|
||||||
|
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '在这里输入内容'
|
default: '在这里输入内容',
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: {
|
plugins: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code ' +
|
default:
|
||||||
'codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount autosave emoticons'
|
'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code ' +
|
||||||
},
|
'codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount autosave emoticons',
|
||||||
toolbar: {
|
},
|
||||||
type: Array,
|
toolbar: {
|
||||||
default: ["undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link anchor alignleft aligncenter alignright alignjustify outdent indent bullist numlist blockquote subscript superscript removeformat styleselect formatselect fontselect fontsizeselect " +
|
type: Array,
|
||||||
"table upload image axupimgs media emoticons charmap hr pagebreak insertdatetime " +
|
default: [
|
||||||
"selectall visualblocks searchreplace code print preview indent2em fullscreen"]
|
'undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link anchor alignleft aligncenter alignright alignjustify outdent indent bullist numlist blockquote subscript superscript removeformat styleselect formatselect fontselect fontsizeselect ' +
|
||||||
}
|
'table upload image axupimgs media emoticons charmap hr pagebreak insertdatetime ' +
|
||||||
|
'selectall visualblocks searchreplace code print preview indent2em fullscreen',
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const aipKey: string = 's1ntkmnev0ggx0hhaqnubrdxhv0ly99uyrdbckeaycx7iz6v'
|
const aipKey: string = 's1ntkmnev0ggx0hhaqnubrdxhv0ly99uyrdbckeaycx7iz6v'
|
||||||
const uploaded = (blobInfo, progress) => new Promise((resolve, reject) => {
|
const uploaded = (blobInfo, progress) =>
|
||||||
if(blobInfo.blob().size/1024/1024 > 10){
|
new Promise((resolve, reject) => {
|
||||||
Message.error('上传失败,图片大小请控制在 10M 以内')
|
if (blobInfo.blob().size / 1024 / 1024 > 10) {
|
||||||
|
Message.error('上传失败,图片大小请控制在 10M 以内')
|
||||||
} else {
|
} else {
|
||||||
let params = new FormData()
|
let params = new FormData()
|
||||||
params.append('image', blobInfo.blob())
|
params.append('image', blobInfo.blob())
|
||||||
Http.post(env('VITE_BASE_URL') + 'upload/image', params).then(res=>{
|
Http.post(env('VITE_BASE_URL') + 'upload/image', params)
|
||||||
console.log(res)
|
.then(res => {
|
||||||
if (res.data.code === 10000) {
|
console.log(res)
|
||||||
resolve(res.data.data.path)
|
if (res.data.code === 10000) {
|
||||||
} else {
|
resolve(res.data.data.path)
|
||||||
Message.error(res.message)
|
} else {
|
||||||
}
|
Message.error(res.message)
|
||||||
}).catch(()=>{
|
}
|
||||||
Message.error('Server Error!')
|
})
|
||||||
|
.catch(() => {
|
||||||
|
Message.error('Server Error!')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const config = {
|
const config = {
|
||||||
language: props.language,
|
language: props.language,
|
||||||
placeholder: props.placeholder,
|
placeholder: props.placeholder,
|
||||||
width: props.width,
|
width: props.width,
|
||||||
height: props.height,
|
height: props.height,
|
||||||
plugins: props.plugins,
|
plugins: props.plugins,
|
||||||
toolbar: props.toolbar,
|
toolbar: props.toolbar,
|
||||||
branding: false,
|
branding: false,
|
||||||
// menubar: false,
|
// menubar: false,
|
||||||
images_upload_handler: uploaded
|
images_upload_handler: uploaded,
|
||||||
}
|
}
|
||||||
|
|
||||||
const emits = defineEmits(['update:value'])
|
const emits = defineEmits(['update:modelValue'])
|
||||||
const content = ref(props.value)
|
const content = ref(props.modelValue)
|
||||||
watch(content, (value) => {
|
watch(content, value => {
|
||||||
emits('update:value',value);
|
emits('update:modelValue', value)
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tinymce-boxz > textarea {
|
.tinymce-boxz > textarea {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
/* 隐藏apikey没有绑定这个域名的提示 */
|
/* 隐藏apikey没有绑定这个域名的提示 */
|
||||||
.tox-notifications-container .tox-notification--warning {
|
.tox-notifications-container .tox-notification--warning {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tox{z-index:9999!important;}
|
.tox {
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -138,7 +138,7 @@ export const usePermissionsStore = defineStore('PermissionsStore', {
|
|||||||
name: permission.module + '_' + permission.permission_mark,
|
name: permission.module + '_' + permission.permission_mark,
|
||||||
component: importComponent,
|
component: importComponent,
|
||||||
redirect: permission.redirect,
|
redirect: permission.redirect,
|
||||||
meta: Object.assign({ title: permission.permission_name, icon: permission.icon, hidden: permission.hidden, is_inner: permission.is_inner }),
|
meta: Object.assign({ title: permission.permission_name, icon: permission.icon, hidden: permission.hidden, active_menu: permission.active_menu }),
|
||||||
})
|
})
|
||||||
|
|
||||||
// child menu
|
// child menu
|
||||||
|
@ -19,16 +19,12 @@ html.dark {
|
|||||||
|
|
||||||
/* 自定义深色背景颜色 */
|
/* 自定义深色背景颜色 */
|
||||||
--el-bg-color: var(--sider-sub-menu-hover-bg-color);
|
--el-bg-color: var(--sider-sub-menu-hover-bg-color);
|
||||||
|
|
||||||
--el-fill-color-blank: var(--sider-bg-color);
|
--el-fill-color-blank: var(--sider-bg-color);
|
||||||
|
|
||||||
--el-bg-color-overlay: var(--sider-bg-color);
|
--el-bg-color-overlay: var(--sider-bg-color);
|
||||||
|
|
||||||
--header-bg-color: var(--sider-bg-color);
|
--header-bg-color: var(--sider-bg-color);
|
||||||
|
|
||||||
// border color
|
// border color
|
||||||
--el-border-color-lighter: #3b4253;
|
--el-border-color-lighter: #3b4253;
|
||||||
|
|
||||||
--el-fill-color-light: #161d31;
|
--el-fill-color-light: #161d31;
|
||||||
|
|
||||||
// side sub menu margin
|
// side sub menu margin
|
||||||
|
@ -141,6 +141,8 @@ class Http {
|
|||||||
|
|
||||||
// set ajax request
|
// set ajax request
|
||||||
this.headers['X-Requested-With'] = 'XMLHttpRequest'
|
this.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||||
|
// set dashboard request
|
||||||
|
this.headers['Request-from'] = 'Dashboard'
|
||||||
this.config.headers = this.headers
|
this.config.headers = this.headers
|
||||||
|
|
||||||
return this.config
|
return this.config
|
||||||
|
@ -14,7 +14,7 @@ export interface Meta {
|
|||||||
|
|
||||||
keepalive?: boolean
|
keepalive?: boolean
|
||||||
|
|
||||||
is_inner?: boolean
|
active_menu?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -11,5 +11,5 @@ export interface Permission {
|
|||||||
redirect: string
|
redirect: string
|
||||||
keepAlive: boolean
|
keepAlive: boolean
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
is_inner: boolean
|
active_menu: string
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user