From bd8fef9a04a85eedf71f463f7063e0a0a1bdf1af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com>
Date: Fri, 27 Oct 2023 16:59:25 +0800
Subject: [PATCH] =?UTF-8?q?1.=E5=AE=8C=E6=88=90=E6=96=B0=E7=89=88=E8=8F=9C?=
=?UTF-8?q?=E5=8D=95=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/application/settings.py | 4 +-
.../dvadmin/system/fixtures/initSerializer.py | 2 +-
.../dvadmin/system/fixtures/init_menu.json | 34 +-
backend/dvadmin/system/models.py | 19 +-
backend/dvadmin/system/views/column.py | 5 +-
backend/dvadmin/system/views/menu.py | 42 +-
.../views/role_menu_button_permission.py | 2 +-
backend/dvadmin/utils/pagination.py | 3 +-
web/src/settings.ts | 29 +-
web/src/utils/dictionary.ts | 18 +-
web/src/views/plugins/index.ts | 2 +-
.../views/system/dictionary/subDict/index.vue | 3 +-
web/src/views/system/menu/api.ts | 9 +-
web/src/views/system/menu/crud.ts | 364 ++++++++++++++++++
web/src/views/system/menu/index.vue | 240 ++++++------
15 files changed, 570 insertions(+), 206 deletions(-)
create mode 100644 web/src/views/system/menu/crud.ts
diff --git a/backend/application/settings.py b/backend/application/settings.py
index f59140f..124d7f9 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -178,6 +178,7 @@ CHANNEL_LAYERS = {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
+REDIS_URL = locals().get('REDIS_URL', "")
# CHANNEL_LAYERS = {
# 'default': {
# 'BACKEND': 'channels_redis.core.RedisChannelLayer',
@@ -399,10 +400,11 @@ TENANT_SHARED_APPS = []
PLUGINS_URL_PATTERNS = []
# ********** 一键导入插件配置开始 **********
# 例如:
-# from dvadmin_upgrade_center.settings import * # 升级中心
+from dvadmin3_upgrade_center.settings import * # 升级中心
# from dvadmin_celery.settings import * # celery 异步任务
# from dvadmin_third.settings import * # 第三方用户管理
# from dvadmin_ak_sk.settings import * # 秘钥管理管理
# from dvadmin_tenants.settings import * # 租户管理
+# from dvadmin_uniapp.settings import *
# ...
# ********** 一键导入插件配置结束 **********
diff --git a/backend/dvadmin/system/fixtures/initSerializer.py b/backend/dvadmin/system/fixtures/initSerializer.py
index fc701bc..35cf5f3 100644
--- a/backend/dvadmin/system/fixtures/initSerializer.py
+++ b/backend/dvadmin/system/fixtures/initSerializer.py
@@ -112,7 +112,7 @@ class MenuInitSerializer(CustomModelSerializer):
class Meta:
model = Menu
- fields = ['name', 'icon', 'sort', 'is_link', 'is_catalog', 'web_path', 'component', 'component_name', 'status',
+ fields = ['name', 'icon', 'sort', 'is_link', 'menu_type', 'web_path', 'component', 'component_name', 'status',
'cache', 'visible', 'parent', 'children', 'menu_button', 'creator', 'dept_belong_id']
extra_kwargs = {
'creator': {'write_only': True},
diff --git a/backend/dvadmin/system/fixtures/init_menu.json b/backend/dvadmin/system/fixtures/init_menu.json
index 9d514fe..6e1c898 100644
--- a/backend/dvadmin/system/fixtures/init_menu.json
+++ b/backend/dvadmin/system/fixtures/init_menu.json
@@ -4,7 +4,7 @@
"icon": "iconfont icon-xitongshezhi",
"sort": 1,
"is_link": false,
- "is_catalog": true,
+ "menu_type": 0,
"web_path": "/system",
"component": "",
"component_name": "",
@@ -17,7 +17,7 @@
"icon": "iconfont icon-caidan",
"sort": 1,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/menu",
"component": "system/menu/index",
"component_name": "menu",
@@ -87,7 +87,7 @@
"icon": "dot-circle-o",
"sort": 2,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/menuButton",
"component": "system/menuButton/index",
"component_name": "menuButton",
@@ -127,7 +127,7 @@
"icon": "ele-OfficeBuilding",
"sort": 3,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/dept",
"component": "system/dept/index",
"component_name": "dept",
@@ -203,7 +203,7 @@
"icon": "ele-ColdDrink",
"sort": 4,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/role",
"component": "system/role/index",
"component_name": "role",
@@ -255,7 +255,7 @@
"icon": "iconfont icon-bolangneng",
"sort": 5,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/columns",
"component": "system/columns/index",
"component_name": "columns",
@@ -313,7 +313,7 @@
"icon": "iconfont icon-icon-",
"sort": 6,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/user",
"component": "system/user/index",
"component_name": "user",
@@ -383,7 +383,7 @@
"icon": "iconfont icon-xiaoxizhongxin",
"sort": 7,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/messageCenter",
"component": "system/messageCenter/index",
"component_name": "messageCenter",
@@ -429,7 +429,7 @@
"icon": "ele-SetUp",
"sort": 8,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/apiWhiteList",
"component": "system/whiteList/index",
"component_name": "whiteList",
@@ -478,7 +478,7 @@
"icon": "iconfont icon-configure",
"sort": 2,
"is_link": false,
- "is_catalog": true,
+ "menu_type": 0,
"web_path": "/generalConfig",
"component": "",
"component_name": "",
@@ -491,7 +491,7 @@
"icon": "iconfont icon-system",
"sort": 0,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/config",
"component": "system/config/index",
"component_name": "config",
@@ -537,7 +537,7 @@
"icon": "iconfont icon-dict",
"sort": 1,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/dictionary",
"component": "system/dictionary/index",
"component_name": "dictionary",
@@ -583,7 +583,7 @@
"icon": "iconfont icon-Area",
"sort": 2,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/areas",
"component": "system/areas/index",
"component_name": "areas",
@@ -629,7 +629,7 @@
"icon": "iconfont icon-file",
"sort": 3,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/file",
"component": "system/fileList/index",
"component_name": "file",
@@ -672,7 +672,7 @@
"icon": "iconfont icon-rizhi",
"sort": 3,
"is_link": false,
- "is_catalog": true,
+ "menu_type": 0,
"web_path": "/log",
"component": "",
"component_name": "",
@@ -685,7 +685,7 @@
"icon": "iconfont icon-guanlidenglurizhi",
"sort": 1,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/loginLog",
"component": "system/log/loginLog/index",
"component_name": "loginLog",
@@ -713,7 +713,7 @@
"icon": "iconfont icon-caozuorizhi",
"sort": 2,
"is_link": false,
- "is_catalog": false,
+ "menu_type": 1,
"web_path": "/operationLog",
"component": "system/log/operationLog/index",
"component_name": "operationLog",
diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py
index ed728ea..26abd1e 100644
--- a/backend/dvadmin/system/models.py
+++ b/backend/dvadmin/system/models.py
@@ -156,22 +156,24 @@ class Menu(CoreModel):
help_text="上级菜单",
)
icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标")
- name = models.CharField(max_length=64, verbose_name="菜单名称", help_text="菜单名称")
+ name = models.CharField(max_length=64, verbose_name="目录名称/菜单名称/按钮名称", help_text="目录名称/菜单名称/按钮名称")
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
- ISLINK_CHOICES = (
- (0, "否"),
- (1, "是"),
- )
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
- is_catalog = models.BooleanField(default=False, verbose_name="是否目录", help_text="是否目录")
+ MENU_TYPE_CHOICES =(
+ (0, "目录"),
+ (1, "菜单"),
+ (2, "按钮"),
+ )
+ menu_type = models.IntegerField(default=0, verbose_name="菜单类型", help_text="菜单类型")
web_path = models.CharField(max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址")
- component = models.CharField(max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址")
+ component = models.CharField(max_length=200, verbose_name="组件地址/按钮权限值", null=True, blank=True, help_text="组件地址/按钮权限值")
component_name = models.CharField(max_length=50, verbose_name="组件名称", null=True, blank=True,
help_text="组件名称")
status = models.BooleanField(default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态")
cache = models.BooleanField(default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存")
visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示",
help_text="侧边栏中是否显示")
+ frame_out = models.BooleanField(default=False, blank=True, verbose_name="是否主框架外", help_text="是否主框架外")
class Meta:
db_table = table_prefix + "system_menu"
@@ -184,7 +186,6 @@ class Columns(CoreModel):
role = models.ForeignKey(to='Role', on_delete=models.CASCADE, verbose_name='角色', db_constraint=False)
app = models.CharField(max_length=64, verbose_name='应用名')
model = models.CharField(max_length=64, verbose_name='表名')
- menu = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name='菜单', db_constraint=False)
field_name = models.CharField(max_length=64, verbose_name='模型表字段名')
title = models.CharField(max_length=64, verbose_name='字段显示名')
is_query = models.BooleanField(default=1, verbose_name='是否可查询')
@@ -457,7 +458,7 @@ class SystemConfig(CoreModel):
help_text="父级",
)
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
- key = models.CharField(max_length=20, verbose_name="键", help_text="键", db_index=True)
+ key = models.CharField(max_length=50, verbose_name="键", help_text="键", db_index=True)
value = models.JSONField(max_length=100, verbose_name="值", help_text="值", null=True, blank=True)
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
diff --git a/backend/dvadmin/system/views/column.py b/backend/dvadmin/system/views/column.py
index a23d27c..5b9024c 100644
--- a/backend/dvadmin/system/views/column.py
+++ b/backend/dvadmin/system/views/column.py
@@ -32,10 +32,9 @@ class ColumnViewSet(CustomModelViewSet):
role_id = request.query_params.get('role')
app_name = request.query_params.get('app')
model_name = request.query_params.get('model')
- menu = request.query_params.get('menu')
- if not role_id or not model_name or not app_name or not menu:
+ if not role_id or not model_name or not app_name:
return SuccessResponse([])
- queryset = self.filter_queryset(self.get_queryset().filter(role_id=role_id, model=model_name, app=app_name,menu_id=menu))
+ queryset = self.filter_queryset(self.get_queryset().filter(role_id=role_id, model=model_name, app=app_name))
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True, request=request)
diff --git a/backend/dvadmin/system/views/menu.py b/backend/dvadmin/system/views/menu.py
index 6899646..88dd52f 100644
--- a/backend/dvadmin/system/views/menu.py
+++ b/backend/dvadmin/system/views/menu.py
@@ -11,7 +11,7 @@ from rest_framework.decorators import action
from dvadmin.system.models import Menu, RoleMenuPermission
from dvadmin.system.views.menu_button import MenuButtonSerializer
-from dvadmin.utils.json_response import SuccessResponse, ErrorResponse
+from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
@@ -21,7 +21,7 @@ class MenuSerializer(CustomModelSerializer):
菜单表的简单序列化器
"""
menuPermission = serializers.SerializerMethodField(read_only=True)
- hasChild = serializers.SerializerMethodField()
+ hasChildren = serializers.SerializerMethodField()
def get_menuPermission(self, instance):
queryset = instance.menuPermission.order_by('-name').values('id', 'name', 'value')
@@ -31,7 +31,7 @@ class MenuSerializer(CustomModelSerializer):
else:
return None
- def get_hasChild(self, instance):
+ def get_hasChildren(self, instance):
hasChild = Menu.objects.filter(parent=instance.id)
if hasChild:
return True
@@ -71,7 +71,7 @@ class WebRouterSerializer(CustomModelSerializer):
class Meta:
model = Menu
fields = (
- 'id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'is_catalog', 'web_path', 'component',
+ 'id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'menu_type', 'web_path', 'component',
'component_name', 'cache', 'visible', 'status')
read_only_fields = ["id"]
@@ -90,37 +90,31 @@ class MenuViewSet(CustomModelViewSet):
create_serializer_class = MenuCreateSerializer
update_serializer_class = MenuCreateSerializer
search_fields = ['name', 'status']
- filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'is_catalog']
+ filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'menu_type']
- def list(self, request):
+ @action(methods=['get'], detail=False)
+ def tree(self, request):
"""懒加载"""
- request.query_params._mutable = True
params = request.query_params
- parent = params.get('parent', None)
- page = params.get('page', None)
- limit = params.get('limit', None)
- if page:
- del params['page']
- if limit:
- del params['limit']
- if params:
- if parent:
- queryset = self.queryset.filter(parent=parent)
- else:
- queryset = self.queryset.filter()
- else:
- queryset = self.queryset.filter(parent__isnull=True)
- queryset = self.filter_queryset(queryset)
+ menu_type = params.get('menu_type', 0)
+ queryset = Menu.objects.filter(menu_type=menu_type).order_by('sort')
serializer = MenuSerializer(queryset, many=True, request=request)
data = serializer.data
- return SuccessResponse(data=data)
+ return DetailResponse(data=data)
+
+ @action(methods=['get'], detail=True)
+ def getChildren(self,request,pk):
+ queryset = Menu.objects.filter(parent=pk)
+ serializer = MenuSerializer(queryset, many=True, request=request)
+ data = serializer.data
+ return DetailResponse(data=data)
@action(methods=['GET'], detail=False, permission_classes=[])
def web_router(self, request):
"""用于前端获取当前角色的路由"""
user = request.user
is_admin = user.role.values_list('admin', flat=True)
- if user.is_superuser or True in is_admin:
+ if user.is_superuser:
queryset = self.queryset.filter(status=1)
else:
role_list = user.role.values_list('id', flat=True)
diff --git a/backend/dvadmin/system/views/role_menu_button_permission.py b/backend/dvadmin/system/views/role_menu_button_permission.py
index 109b27b..f43b4ee 100644
--- a/backend/dvadmin/system/views/role_menu_button_permission.py
+++ b/backend/dvadmin/system/views/role_menu_button_permission.py
@@ -100,7 +100,7 @@ class RoleMenuPermissionSerializer(CustomModelSerializer):
def get_columns(self, instance):
params = self.request.query_params
- col_list = Columns.objects.filter(role__id=params.get('role'),menu__id=instance['id'])
+ col_list = Columns.objects.filter(role__id=params.get('role'))
serializer = RoleColumnsSerializer(col_list,many=True,request=self.request)
return serializer.data
diff --git a/backend/dvadmin/utils/pagination.py b/backend/dvadmin/utils/pagination.py
index 52bf143..5e80e57 100644
--- a/backend/dvadmin/utils/pagination.py
+++ b/backend/dvadmin/utils/pagination.py
@@ -79,6 +79,5 @@ class CustomPagination(PageNumberPagination):
('total', total),
('is_next', is_next),
('is_previous', is_previous),
- ('data', data),
- ('permission', self.request.permission_fields)
+ ('data', data)
]))
diff --git a/web/src/settings.ts b/web/src/settings.ts
index b43526e..2e79056 100644
--- a/web/src/settings.ts
+++ b/web/src/settings.ts
@@ -9,7 +9,7 @@ import { request } from '/@/utils/service';
//扩展包
import { FsExtendsEditor,FsExtendsUploader } from '@fast-crud/fast-extends';
import '@fast-crud/fast-extends/dist/style.css';
-import { successMessage, successNotification } from '/@/utils/message';
+import { ElMessage } from "element-plus";
export default {
async install(app: any, options: any) {
// 先安装ui
@@ -18,9 +18,9 @@ export default {
app.use(FastCrud, {
//i18n, //i18n配置,可选,默认使用中文,具体用法请看demo里的 src/i18n/index.js 文件
// 此处配置公共的dictRequest(字典请求)
- async dictRequest({ dict }: any) {
+ async dictRequest({ url }: any) {
//根据dict的url,异步返回一个字典数组
- return await request({ url: dict.url, params: dict.params || {} }).then((res:any)=>{
+ return await request({ url: url, }).then((res:any)=>{
return res.data
});
},
@@ -41,14 +41,21 @@ export default {
transformRes: ({ res }: any) => {
//将pageRequest的返回数据,转换为fast-crud所需要的格式
//return {records,currentPage,pageSize,total};
- return { records: res.data, currentPage: res.page, pageSize: res.limit, total: res.total };
+ if(res.page){
+ return { records: res.data, currentPage: res.page, pageSize: res.limit, total: res.total };
+ }else{
+ return { records: res.data,currentPage: 1, pageSize: res.data.length, total: res.data.length };
+ }
+
},
},
form: {
- afterSubmit(ctx: any) {
- // 增加crud提示
- if (ctx.res.code == 2000) {
- successNotification(ctx.res.msg);
+ afterSubmit(ctx:any ) {
+ const {mode} = ctx
+ if (mode === "add") {
+ ElMessage.success({ message: "添加成功" });
+ } else if (mode === "edit") {
+ ElMessage.success({ message: "保存成功" });
}
},
},
@@ -100,10 +107,12 @@ export default {
});
},
successHandle(ret) {
+ console.log(111,ret)
// 上传完成后的结果处理, 此处应返回格式为{url:xxx,key:xxx}
return {
- url: getBaseURL() + ret.data.url,
- key: ret.data.id
+ url: ret.data.url,
+ key: ret.data.id,
+ ...ret.data
};
}
}
diff --git a/web/src/utils/dictionary.ts b/web/src/utils/dictionary.ts
index e35a205..0305891 100644
--- a/web/src/utils/dictionary.ts
+++ b/web/src/utils/dictionary.ts
@@ -1,11 +1,19 @@
import { toRaw } from 'vue';
import { DictionaryStore } from '/@/stores/dictionary';
-/**
- * @method 获取指定name字典
+/**
+ * @method 获取指定name字典
*/
-export const dictionary = (name: string) => {
+export const dictionary = (key: string,value:string|number) => {
const dict = DictionaryStore()
const dictionary = toRaw(dict.data)
- return dictionary[name]
-}
\ No newline at end of file
+ if(value!==null || value !==''){
+ for (let item of dictionary[key]) {
+ if (item.value === value) {
+ return item.label
+ }
+ }
+ return ''
+ }
+ return dictionary[key]
+}
diff --git a/web/src/views/plugins/index.ts b/web/src/views/plugins/index.ts
index 7ba8bf9..5e1d1fd 100644
--- a/web/src/views/plugins/index.ts
+++ b/web/src/views/plugins/index.ts
@@ -12,5 +12,5 @@ export const scanAndInstallPlugins = (app: any) => {
pluginNames.add(pluginsName);
}
pluginsAll = Array.from(pluginNames);
- console.log('已发现插件:', pluginsAll);
+ console.table('已注册插件:', pluginsAll);
};
diff --git a/web/src/views/system/dictionary/subDict/index.vue b/web/src/views/system/dictionary/subDict/index.vue
index 65dd400..12d9b6c 100644
--- a/web/src/views/system/dictionary/subDict/index.vue
+++ b/web/src/views/system/dictionary/subDict/index.vue
@@ -1,8 +1,6 @@
-
-
@@ -25,6 +23,7 @@ const handleClose = (done: () => void) => {
})
.then(() => {
done();
+
})
.catch(() => {
// catch error
diff --git a/web/src/views/system/menu/api.ts b/web/src/views/system/menu/api.ts
index da6afb2..4182155 100644
--- a/web/src/views/system/menu/api.ts
+++ b/web/src/views/system/menu/api.ts
@@ -5,12 +5,19 @@ export const apiPrefix = '/api/system/menu/';
export function GetList(query: UserPageQuery) {
return request({
- url: apiPrefix,
+ url: apiPrefix+"tree/",
method: 'get',
params: query,
});
}
+export function GetChildren(id: InfoReq) {
+ return request({
+ url: apiPrefix + id + '/getChildren/',
+ method: 'get',
+ });
+}
+
export function GetObj(id: InfoReq) {
return request({
url: apiPrefix + id + '/',
diff --git a/web/src/views/system/menu/crud.ts b/web/src/views/system/menu/crud.ts
new file mode 100644
index 0000000..0dc7a78
--- /dev/null
+++ b/web/src/views/system/menu/crud.ts
@@ -0,0 +1,364 @@
+import * as api from './api';
+import { CreateCrudOptionsProps, CreateCrudOptionsRet, dict, useCompute } from '@fast-crud/fast-crud';
+const { compute } = useCompute();
+import { shallowRef } from "vue";
+import IconSelector from "/@/components/IconSelector/index.vue"
+export default function ({ crudExpose, onAddCatalog, onAddChildren, onAddButton }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+ const pageRequest = async (query) => {
+ return await api.GetList(query);
+ };
+ const editRequest = async ({ form, row }) => {
+ form.id = row.id;
+ await api.UpdateObj(form);
+ if (row.parent) {
+ //刷新父节点的状态
+ reloadTreeChildren(row.parent);
+ }
+ };
+ const delRequest = async ({ row }:any) => {
+ await api.DelObj(row.id);
+ if (row.parent) {
+ //刷新父节点的状态
+ reloadTreeChildren(row.parent);
+ }
+ };
+
+ const addRequest = async (context:any) => {
+ return await api.AddObj(context.form);
+ };
+
+ //刷新父节点状态
+ function reloadTreeChildren(parent:string|number) {
+ const data = crudExpose.getBaseTableRef().store.states.treeData;
+ if (data.value != null) {
+ const item = data.value[parent];
+ if (item != null) {
+ item.loaded = false;
+ item.expanded = false;
+ }
+ }
+ }
+
+ const createFilter = (queryString: string) => {
+ return (file: any) => {
+ return file.value.toLowerCase().indexOf(queryString.toLowerCase()) !== -1;
+ };
+ };
+
+ // 获取组件地址
+ const getCompoent = (queryString: string, cb: any) => {
+ const files: any = import.meta.glob('@views/**/*.vue');
+ let fileLists: Array = [];
+ Object.keys(files).forEach((queryString: string) => {
+ fileLists.push({
+ label: queryString.replace(/(\.\/|\.vue)/g, ''),
+ value: queryString.replace(/(\.\/|\.vue)/g, ''),
+ });
+ });
+ const results = queryString ? fileLists.filter(createFilter(queryString)) : fileLists;
+ // 统一去掉/src/views/前缀
+ results.forEach((val) => {
+ val.label = val.label.replace('/src/views/', '');
+ val.value = val.value.replace('/src/views/', '');
+ });
+ cb(results);
+ };
+
+ // 验证路由地址
+ const { getFormData } = crudExpose;
+ const validateWebPath = (rule: any, value: string, callback: Function) => {
+ let pattern = /^\/.*?/;
+ let patternUrl = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
+ const reg = getFormData().is_link ? patternUrl.test(value) : pattern.test(value);
+ if (reg) {
+ callback();
+ } else {
+ callback(new Error('请输入正确的地址'));
+ }
+ };
+
+ return {
+ crudOptions: {
+ request: {
+ pageRequest,
+ addRequest,
+ editRequest,
+ delRequest,
+ },
+ pagination: {
+ show: false,
+ },
+ form: {
+ labelWidth: '120px',
+ row: { gutter: 20 },
+ // group: {
+ // groupType: 'tabs', //collapse, tabs
+ // accordion: false,
+ // groups: {
+ // catalog: {
+ // label: '目录',
+ // icon: 'el-icon-goods',
+ // columns: ['name', 'icon', 'sort', 'status'],
+ // },
+ // menu: {
+ // label: '菜单',
+ // icon: 'el-icon-price-tag',
+ // columns: ['parent', 'name', 'icon', 'is_link', 'web_path', 'component', 'cache', 'visible', 'frame_out', 'sort', 'status'],
+ // },
+ // info: {
+ // label: '按钮',
+ // collapsed: true, //默认折叠
+ // icon: 'el-icon-warning-outline',
+ // columns: ['name', 'component'],
+ // },
+ // },
+ // },
+ },
+ table: {
+ lazy: true,
+ load: async (row: any, treeNode: unknown, resolve: (date: any[]) => void) => {
+ //懒加载,更新和删除后,需要刷新父节点的状态,见上方
+ const obj = await api.GetChildren(row.id);
+ resolve([...obj.data]);
+ },
+ },
+ columns: {
+ id: {
+ title: 'ID',
+ key: 'id',
+ type: 'number',
+ column: {
+ width: 100,
+ },
+ form: {
+ show: false,
+ },
+ },
+ menu_type: {
+ title: '类型',
+ type: 'dict-radio',
+ dict: dict({
+ data: [
+ { label: '目录', value: 0 },
+ { label: '菜单', value: 1 },
+ { label: '按钮', value: 2 },
+ ],
+ }),
+ form: {
+ value:0,
+ valueChange({ form, value, getComponentRef }) {
+ if (value) {
+ getComponentRef("parent").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典
+ }
+ }
+ },
+ column: {
+ show: false,
+ },
+ },
+ parent: {
+ title: '父级',
+ dict: dict({
+ prototype: true,
+ url({form}){
+ if(form && form.menu_type===1){
+ return '/api/system/menu/tree/?menu_type=0'
+ }else{
+ return `/api/system/menu/tree/?menu_type=1`
+ }
+ return undefined
+ },
+ label: 'name',
+ value: 'id',
+ }),
+ type: 'dict-select',
+ form: {
+ show:compute(({form})=>{
+ return [1,2].includes(form.menu_type);
+ }),
+ rules: [{ required: true, message: '必填项' }],
+ component: {},
+ },
+ column: {
+ show: false,
+ },
+ },
+ name: {
+ title: '名称',
+ search: { show: true },
+ type: 'text',
+ form: {
+ rules: [{ required: true, message: '请输入名称' }],
+ component: {
+ placeholder: '请输入名称',
+ },
+ },
+ },
+ icon: {
+ title: '图标',
+ form:{
+ show:compute(({form})=>{
+ return [0,1].includes(form.menu_type);
+ }),
+ component:{
+ name: shallowRef(IconSelector),
+ vModel: "modelValue",
+ }
+ },
+ column: {
+ component: {
+ style: 'font-size:18px',
+ },
+ },
+ },
+ sort: {
+ title: '排序',
+ type: 'number',
+ form: {
+ value: 1,
+ show:compute(({form})=>{
+ return [0,1].includes(form.menu_type);
+ }),
+ },
+ },
+ is_link: {
+ title: '外链接',
+ type: 'dict-switch',
+ dict: dict({
+ data: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ }),
+ form: {
+ value: false,
+ show:compute(({form})=>{
+ return [1].includes(form.menu_type);
+ }),
+ },
+ },
+ web_path: {
+ title: '路由地址',
+ form: {
+ show:compute(({form})=>{
+ return [1].includes(form.menu_type);
+ }),
+ helper: compute(({ form }) => {
+ return form.is_link ? '请输入http开头的地址' : '浏览器中url的地址,请以/开头';
+ }),
+ rules: [{ required: true, message: '请输入路由地址', validator: validateWebPath, trigger: 'blur' }],
+ component: {
+ placeholder: '请输入路由地址',
+ },
+ },
+ column: {
+ show: false,
+ },
+ },
+ component: {
+ title: '组件地址',
+ form: {
+ show: compute(({ form }) => {
+ return [1,2].includes(form.menu_type)
+ }),
+ helper: compute(({ form }) => {
+ return form.menu_type === 1 ? 'src/views下的文件夹地址' : '按钮权限值是唯一的标识';
+ }),
+ rules: [{ required: true, message: '请输入组件地址', trigger: 'blur' }],
+ component: {
+ style: {
+ width: '100%',
+ },
+ disabled: compute(({ form }) => {
+ if(form.is_link&&form.menu_type===1){
+ form.component ="无"
+ return form.is_link
+ }
+ form.component =null
+ return false
+ }),
+ name: compute(({ form }) => {
+ return [1,2].includes(form.menu_type)? 'el-autocomplete' : 'el-input';
+ }),
+ triggerOnFocus: false,
+ fetchSuggestions: (query, cb) => {
+ return getCompoent(query, cb);
+ },
+ },
+ },
+ column: {
+ show: false,
+ },
+ },
+ visible: {
+ title: '侧边可见',
+ search: { show: true },
+ type: 'dict-radio',
+ dict: dict({
+ data: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ }),
+ form: {
+ value: true,
+ show:compute(({form})=>{
+ return [1].includes(form.menu_type)
+ }),
+ },
+ },
+ cache: {
+ title: '是否缓存',
+ search: { show: true },
+ type: 'dict-radio',
+ dict: dict({
+ data: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ }),
+ form: {
+ value: false,
+ show:compute(({form})=>{
+ return [1].includes(form.menu_type)
+ }),
+ },
+ },
+ frame_out: {
+ title: '主框架外展示',
+ search: { show: true },
+ type: 'dict-radio',
+ dict: dict({
+ data: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ }),
+ form: {
+ value: false,
+ show:compute(({form})=>{
+ return [1].includes(form.menu_type)
+ }),
+ },
+ },
+ status: {
+ title: '状态',
+ search: { show: true },
+ type: 'dict-radio',
+ dict: dict({
+ data: [
+ { label: '启用', value: true },
+ { label: '禁用', value: false },
+ ],
+ }),
+ form: {
+ value: true,
+ show:compute(({form})=>{
+ return [0,1].includes(form.menu_type);
+ }),
+ },
+ },
+ },
+ },
+ };
+}
diff --git a/web/src/views/system/menu/index.vue b/web/src/views/system/menu/index.vue
index 97e26c3..c71d378 100644
--- a/web/src/views/system/menu/index.vue
+++ b/web/src/views/system/menu/index.vue
@@ -1,142 +1,124 @@
-
-
-
-
-
-
-
+
+
+
-
-
-