Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
E
EMS
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hejie
EMS
Commits
a5409e05
提交
a5409e05
authored
4月 22, 2025
作者:
詹银鑫
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 菜单管理添加
上级
5e5223dc
隐藏空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
886 行增加
和
21 行删除
+886
-21
system.ts
src/api/system.ts
+8
-1
index.vue
src/views/login/index.vue
+1
-1
hook.tsx
src/views/systems/dep/utils/hook.tsx
+1
-2
form.vue
src/views/systems/menu/form.vue
+342
-0
index.vue
src/views/systems/menu/index.vue
+155
-16
enums.ts
src/views/systems/menu/utils/enums.ts
+108
-0
hook.tsx
src/views/systems/menu/utils/hook.tsx
+227
-0
rule.ts
src/views/systems/menu/utils/rule.ts
+10
-0
types.ts
src/views/systems/menu/utils/types.ts
+30
-0
vite.config.ts
vite.config.ts
+4
-1
没有找到文件。
src/api/system.ts
浏览文件 @
a5409e05
...
...
@@ -41,7 +41,14 @@ export const getRoleList = (data?: object) => {
/** 获取系统管理-菜单管理列表 */
export
const
getMenuList
=
(
data
?:
object
)
=>
{
return
http
.
request
<
Result
>
(
"post"
,
"/menu"
,
{
data
});
return
http
.
request
<
Result
>
(
"post"
,
"/api/menu/find-menu-list-by-page"
,
{
data
});
};
/** 新增菜单-菜单管理列表 */
export
const
addMenu
=
(
data
?:
object
)
=>
{
return
http
.
request
<
Result
>
(
"post"
,
"/api/menu/add-menu"
,
{
data
});
};
/** 获取系统管理-部门管理列表 */
...
...
src/views/login/index.vue
浏览文件 @
a5409e05
...
...
@@ -66,7 +66,7 @@ const { locale, translationCh, translationEn } = useTranslationLang();
const
ruleForm
=
reactive
({
username
:
"zhangxiaoming"
,
password
:
"
string
"
,
password
:
"
123456
"
,
verifyCode
:
""
});
...
...
src/views/systems/dep/utils/hook.tsx
浏览文件 @
a5409e05
...
...
@@ -79,8 +79,7 @@ export function useDept() {
pageNum
:
1
,
pageSize
:
200
};
const
{
data
}
=
await
getDeptList
(
params
);
// 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
console
.
log
(
"data"
,
data
);
const
{
data
}
=
await
getDeptList
(
params
);
let
newData
=
(
data
as
any
).
records
;
if
(
!
isAllEmpty
(
form
.
name
))
{
// 前端搜索部门名称
...
...
src/views/systems/menu/form.vue
0 → 100644
浏览文件 @
a5409e05
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
"vue"
;
import
ReCol
from
"@/components/ReCol"
;
import
{
formRules
}
from
"./utils/rule"
;
import
{
FormProps
}
from
"./utils/types"
;
import
{
transformI18n
}
from
"@/plugins/i18n"
;
import
{
IconSelect
}
from
"@/components/ReIcon"
;
import
Segmented
from
"@/components/ReSegmented"
;
import
ReAnimateSelector
from
"@/components/ReAnimateSelector"
;
import
{
menuTypeOptions
,
showLinkOptions
,
fixedTagOptions
,
keepAliveOptions
,
hiddenTagOptions
,
showParentOptions
,
frameLoadingOptions
}
from
"./utils/enums"
;
const
props
=
withDefaults
(
defineProps
<
FormProps
>
(),
{
formInline
:
()
=>
({
menuType
:
0
,
higherMenuOptions
:
[],
parentId
:
0
,
title
:
""
,
name
:
""
,
path
:
""
,
component
:
""
,
rank
:
99
,
redirect
:
""
,
icon
:
""
,
extraIcon
:
""
,
enterTransition
:
""
,
leaveTransition
:
""
,
activePath
:
""
,
auths
:
""
,
frameSrc
:
""
,
frameLoading
:
true
,
keepAlive
:
false
,
hiddenTag
:
false
,
fixedTag
:
false
,
showLink
:
true
,
showParent
:
false
})
});
const
ruleFormRef
=
ref
();
const
newFormInline
=
ref
(
props
.
formInline
);
function
getRef
()
{
return
ruleFormRef
.
value
;
}
defineExpose
({
getRef
});
</
script
>
<
template
>
<el-form
ref=
"ruleFormRef"
:model=
"newFormInline"
:rules=
"formRules"
label-width=
"82px"
>
<el-row
:gutter=
"30"
>
<re-col>
<el-form-item
label=
"菜单类型"
>
<Segmented
v-model=
"newFormInline.menuType"
:options=
"menuTypeOptions"
/>
</el-form-item>
</re-col>
<re-col>
<el-form-item
label=
"上级菜单"
>
<el-cascader
v-model=
"newFormInline.parentId"
class=
"w-full"
:options=
"newFormInline.higherMenuOptions"
:props=
"
{
value: 'id',
label: 'name',
emitPath: false,
checkStrictly: true
}"
clearable
filterable
placeholder="请选择上级菜单"
>
<template
#
default=
"
{ node, data }">
<span>
{{
transformI18n
(
data
.
name
)
}}
</span>
<span
v-if=
"!node.isLeaf"
>
(
{{
data
.
children
.
length
}}
)
</span>
</
template
>
</el-cascader>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"菜单名称"
prop=
"title"
>
<el-input
v-model=
"newFormInline.title"
clearable
placeholder=
"请输入菜单名称"
/>
</el-form-item>
</re-col>
<re-col
v-if=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"路由名称"
prop=
"name"
>
<el-input
v-model=
"newFormInline.name"
clearable
placeholder=
"请输入路由名称"
/>
</el-form-item>
</re-col>
<re-col
v-if=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"路由路径"
prop=
"path"
>
<el-input
v-model=
"newFormInline.path"
clearable
placeholder=
"请输入路由路径"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType === 0"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"组件路径"
>
<el-input
v-model=
"newFormInline.component"
clearable
placeholder=
"请输入组件路径"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"菜单排序"
>
<el-input-number
v-model=
"newFormInline.rank"
class=
"w-full!"
:min=
"1"
:max=
"9999"
controls-position=
"right"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType === 0"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"路由重定向"
>
<el-input
v-model=
"newFormInline.redirect"
clearable
placeholder=
"请输入默认跳转地址"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"菜单图标"
>
<IconSelect
v-model=
"newFormInline.icon"
class=
"w-full"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"右侧图标"
>
<el-input
v-model=
"newFormInline.extraIcon"
clearable
placeholder=
"菜单名称右侧的额外图标"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType < 2"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"进场动画"
>
<ReAnimateSelector
v-model=
"newFormInline.enterTransition"
placeholder=
"请选择页面进场加载动画"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType < 2"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"离场动画"
>
<ReAnimateSelector
v-model=
"newFormInline.leaveTransition"
placeholder=
"请选择页面离场加载动画"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType === 0"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"菜单激活"
>
<el-input
v-model=
"newFormInline.activePath"
clearable
placeholder=
"请输入需要激活的菜单"
/>
</el-form-item>
</re-col>
<re-col
v-if=
"newFormInline.menuType === 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<!-- 按钮级别权限设置 -->
<el-form-item
label=
"权限标识"
prop=
"auths"
>
<el-input
v-model=
"newFormInline.auths"
clearable
placeholder=
"请输入权限标识"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType === 1"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<!-- iframe -->
<el-form-item
label=
"链接地址"
>
<el-input
v-model=
"newFormInline.frameSrc"
clearable
placeholder=
"请输入 iframe 链接地址"
/>
</el-form-item>
</re-col>
<re-col
v-if=
"newFormInline.menuType === 1"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"加载动画"
>
<Segmented
:modelValue=
"newFormInline.frameLoading ? 0 : 1"
:options=
"frameLoadingOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.frameLoading = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"菜单"
>
<Segmented
:modelValue=
"newFormInline.showLink ? 0 : 1"
:options=
"showLinkOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.showLink = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType !== 3"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"父级菜单"
>
<Segmented
:modelValue=
"newFormInline.showParent ? 0 : 1"
:options=
"showParentOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.showParent = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType < 2"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"缓存页面"
>
<Segmented
:modelValue=
"newFormInline.keepAlive ? 0 : 1"
:options=
"keepAliveOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.keepAlive = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType < 2"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"标签页"
>
<Segmented
:modelValue=
"newFormInline.hiddenTag ? 1 : 0"
:options=
"hiddenTagOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.hiddenTag = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show=
"newFormInline.menuType < 2"
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"固定标签页"
>
<Segmented
:modelValue=
"newFormInline.fixedTag ? 0 : 1"
:options=
"fixedTagOptions"
@
change=
"
({ option: { value } }) => {
newFormInline.fixedTag = value;
}
"
/>
</el-form-item>
</re-col>
</el-row>
</el-form>
</template>
src/views/systems/menu/index.vue
浏览文件 @
a5409e05
<
template
>
<div
class=
"systems"
>
<h2>
Systems
</h2>
<slot
/>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
// 组件逻辑部分
import
{
ref
}
from
"vue"
;
import
{
useMenu
}
from
"./utils/hook"
;
import
{
transformI18n
}
from
"@/plugins/i18n"
;
import
{
PureTableBar
}
from
"@/components/RePureTableBar"
;
import
{
useRenderIcon
}
from
"@/components/ReIcon/src/hooks"
;
const
count
=
ref
(
0
);
import
Delete
from
"~icons/ep/delete"
;
import
EditPen
from
"~icons/ep/edit-pen"
;
import
Refresh
from
"~icons/ep/refresh"
;
import
AddFill
from
"~icons/ri/add-circle-line"
;
const
increment
=
()
=>
{
count
.
value
++
;
};
defineOptions
({
name
:
"SystemMenu"
});
const
formRef
=
ref
();
const
tableRef
=
ref
();
const
{
form
,
loading
,
columns
,
dataList
,
onSearch
,
resetForm
,
openDialog
,
handleDelete
,
handleSelectionChange
}
=
useMenu
();
function
onFullscreen
()
{
// 重置表格高度
tableRef
.
value
.
setAdaptive
();
}
</
script
>
<
style
scoped
lang=
"scss"
>
.systems
{
padding
:
20px
;
border
:
1px
solid
#ccc
;
<
template
>
<div
class=
"main"
>
<el-form
ref=
"formRef"
:inline=
"true"
:model=
"form"
class=
"search-form bg-bg_color w-full pl-8 pt-[12px] overflow-auto"
>
<el-form-item
label=
"菜单名称:"
prop=
"title"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入菜单名称"
clearable
class=
"w-[180px]!"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
:icon=
"useRenderIcon('ri/search-line')"
:loading=
"loading"
@
click=
"onSearch"
>
搜索
</el-button>
<el-button
:icon=
"useRenderIcon(Refresh)"
@
click=
"resetForm(formRef)"
>
重置
</el-button>
</el-form-item>
</el-form>
<PureTableBar
title=
"菜单管理(仅演示,操作后不生效)"
:columns=
"columns"
:isExpandAll=
"false"
:tableRef=
"tableRef?.getTableRef()"
@
refresh=
"onSearch"
@
fullscreen=
"onFullscreen"
>
<template
#
buttons
>
<el-button
type=
"primary"
:icon=
"useRenderIcon(AddFill)"
@
click=
"openDialog()"
>
新增菜单
</el-button>
</
template
>
<
template
v-slot=
"{ size, dynamicColumns }"
>
<pure-table
ref=
"tableRef"
adaptive
:adaptiveConfig=
"
{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
>
<template
#
operation=
"
{ row }">
<el-button
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(EditPen)"
@
click=
"openDialog('修改', row)"
>
修改
</el-button>
<el-button
v-show=
"row.menuType !== 3"
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(AddFill)"
@
click=
"openDialog('新增',
{ parentId: row.id } as any)"
>
新增
</el-button>
<el-popconfirm
:title=
"`是否确认删除菜单名称为$
{transformI18n(row.title)}的这条数据${row?.children?.length > 0 ? '。注意下级菜单也会一并删除,请谨慎操作' : ''}`"
@confirm="handleDelete(row)"
>
<template
#
reference
>
<el-button
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(Delete)"
>
删除
</el-button>
</
template
>
</el-popconfirm>
</template>
</pure-table>
</template>
</PureTableBar>
</div>
</template>
<
style
lang=
"scss"
scoped
>
:deep
(
.el-table__inner-wrapper
::before
)
{
height
:
0
;
}
.main-content
{
margin
:
24px
24px
0
!
important
;
}
.search-form
{
:deep
(
.el-form-item
)
{
margin-bottom
:
12px
;
}
}
</
style
>
src/views/systems/menu/utils/enums.ts
0 → 100644
浏览文件 @
a5409e05
import
type
{
OptionsType
}
from
"@/components/ReSegmented"
;
const
menuTypeOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"菜单"
,
value
:
0
},
{
label
:
"iframe"
,
value
:
1
},
{
label
:
"外链"
,
value
:
2
},
{
label
:
"按钮"
,
value
:
3
}
];
const
showLinkOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"显示"
,
tip
:
"会在菜单中显示"
,
value
:
true
},
{
label
:
"隐藏"
,
tip
:
"不会在菜单中显示"
,
value
:
false
}
];
const
fixedTagOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"固定"
,
tip
:
"当前菜单名称固定显示在标签页且不可关闭"
,
value
:
true
},
{
label
:
"不固定"
,
tip
:
"当前菜单名称不固定显示在标签页且可关闭"
,
value
:
false
}
];
const
keepAliveOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"缓存"
,
tip
:
"会保存该页面的整体状态,刷新后会清空状态"
,
value
:
true
},
{
label
:
"不缓存"
,
tip
:
"不会保存该页面的整体状态"
,
value
:
false
}
];
const
hiddenTagOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"允许"
,
tip
:
"当前菜单名称或自定义信息允许添加到标签页"
,
value
:
false
},
{
label
:
"禁止"
,
tip
:
"当前菜单名称或自定义信息禁止添加到标签页"
,
value
:
true
}
];
const
showParentOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"显示"
,
tip
:
"会显示父级菜单"
,
value
:
true
},
{
label
:
"隐藏"
,
tip
:
"不会显示父级菜单"
,
value
:
false
}
];
const
frameLoadingOptions
:
Array
<
OptionsType
>
=
[
{
label
:
"开启"
,
tip
:
"有首次加载动画"
,
value
:
true
},
{
label
:
"关闭"
,
tip
:
"无首次加载动画"
,
value
:
false
}
];
export
{
menuTypeOptions
,
showLinkOptions
,
fixedTagOptions
,
keepAliveOptions
,
hiddenTagOptions
,
showParentOptions
,
frameLoadingOptions
};
src/views/systems/menu/utils/hook.tsx
0 → 100644
浏览文件 @
a5409e05
import
editForm
from
"../form.vue"
;
import
{
handleTree
}
from
"@/utils/tree"
;
import
{
message
}
from
"@/utils/message"
;
import
{
getMenuList
,
addMenu
}
from
"@/api/system"
;
import
{
transformI18n
}
from
"@/plugins/i18n"
;
import
{
addDialog
}
from
"@/components/ReDialog"
;
import
{
reactive
,
ref
,
onMounted
,
h
}
from
"vue"
;
import
type
{
FormItemProps
}
from
"../utils/types"
;
import
{
useRenderIcon
}
from
"@/components/ReIcon/src/hooks"
;
import
{
cloneDeep
,
isAllEmpty
,
deviceDetection
}
from
"@pureadmin/utils"
;
export
function
useMenu
()
{
const
form
=
reactive
({
name
:
""
});
const
formRef
=
ref
();
const
dataList
=
ref
([]);
const
loading
=
ref
(
true
);
const
getMenuType
=
(
type
,
text
=
false
)
=>
{
switch
(
type
)
{
case
1
:
return
text
?
"菜单"
:
"primary"
;
case
2
:
return
text
?
"目录"
:
"warning"
;
case
3
:
return
text
?
"外链"
:
"danger"
;
case
4
:
return
text
?
"按钮"
:
"info"
;
}
};
const
columns
:
TableColumnList
=
[
{
label
:
"菜单名称"
,
prop
:
"name"
,
align
:
"left"
,
cellRenderer
:
({
row
})
=>
(
<>
<
span
class=
"inline-block mr-1"
>
{
h
(
useRenderIcon
(
row
.
icon
),
{
style
:
{
paddingTop
:
"1px"
}
})
}
</
span
>
<
span
>
{
transformI18n
(
row
.
name
)
}
</
span
>
</>
)
},
{
label
:
"菜单类型"
,
prop
:
"menuType"
,
width
:
100
,
cellRenderer
:
({
row
,
props
})
=>
(
<
el
-
tag
size=
{
props
.
size
}
type=
{
getMenuType
(
row
.
type
)
}
effect=
"plain"
>
{
getMenuType
(
row
.
type
,
true
)
}
</
el
-
tag
>
)
},
{
label
:
"路由路径"
,
prop
:
"path"
},
{
label
:
"组件路径"
,
prop
:
"component"
,
formatter
:
({
path
,
component
})
=>
isAllEmpty
(
component
)
?
path
:
component
},
{
label
:
"权限标识"
,
prop
:
"auths"
},
{
label
:
"排序"
,
prop
:
"rank"
,
width
:
100
},
{
label
:
"隐藏"
,
prop
:
"showLink"
,
formatter
:
({
showLink
})
=>
(
showLink
?
"否"
:
"是"
),
width
:
100
},
{
label
:
"操作"
,
fixed
:
"right"
,
width
:
210
,
slot
:
"operation"
}
];
function
handleSelectionChange
(
val
)
{
console
.
log
(
"handleSelectionChange"
,
val
);
}
function
resetForm
(
formEl
)
{
if
(
!
formEl
)
return
;
// 手动清空菜单名称
form
.
name
=
""
;
formEl
.
resetFields
();
onSearch
();
}
async
function
onSearch
()
{
loading
.
value
=
true
;
const
{
data
}
=
await
getMenuList
({
name
:
""
,
pageNum
:
1
,
pageSize
:
100
});
// 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
let
newData
=
(
data
as
any
).
records
;
if
(
!
isAllEmpty
(
form
.
name
))
{
// 前端搜索菜单名称
newData
=
newData
.
filter
(
item
=>
transformI18n
(
item
.
name
).
includes
(
form
.
name
)
);
}
dataList
.
value
=
handleTree
(
newData
);
// 处理成树结构
console
.
log
(
"dataList"
,
dataList
.
value
);
setTimeout
(()
=>
{
loading
.
value
=
false
;
},
500
);
}
function
formatHigherMenuOptions
(
treeList
)
{
if
(
!
treeList
||
!
treeList
.
length
)
return
;
const
newTreeList
=
[];
for
(
let
i
=
0
;
i
<
treeList
.
length
;
i
++
)
{
treeList
[
i
].
name
=
transformI18n
(
treeList
[
i
].
name
);
formatHigherMenuOptions
(
treeList
[
i
].
children
);
newTreeList
.
push
(
treeList
[
i
]);
}
return
newTreeList
;
}
function
openDialog
(
title
=
"新增"
,
row
?:
FormItemProps
)
{
addDialog
({
title
:
`
${
title
}
菜单`
,
props
:
{
formInline
:
{
menuType
:
row
?.
menuType
??
0
,
higherMenuOptions
:
formatHigherMenuOptions
(
cloneDeep
(
dataList
.
value
)),
parentId
:
row
?.
parentId
??
0
,
// title: row?.title ?? "",
name
:
row
?.
name
??
""
,
path
:
row
?.
path
??
""
,
component
:
row
?.
component
??
""
,
rank
:
row
?.
rank
??
99
,
redirect
:
row
?.
redirect
??
""
,
icon
:
row
?.
icon
??
""
,
extraIcon
:
row
?.
extraIcon
??
""
,
enterTransition
:
row
?.
enterTransition
??
""
,
leaveTransition
:
row
?.
leaveTransition
??
""
,
activePath
:
row
?.
activePath
??
""
,
auths
:
row
?.
auths
??
""
,
frameSrc
:
row
?.
frameSrc
??
""
,
frameLoading
:
row
?.
frameLoading
??
true
,
keepAlive
:
row
?.
keepAlive
??
false
,
hiddenTag
:
row
?.
hiddenTag
??
false
,
fixedTag
:
row
?.
fixedTag
??
false
,
showLink
:
row
?.
showLink
??
true
,
showParent
:
row
?.
showParent
??
false
}
},
width
:
"45%"
,
draggable
:
true
,
fullscreen
:
deviceDetection
(),
fullscreenIcon
:
true
,
closeOnClickModal
:
false
,
contentRenderer
:
()
=>
h
(
editForm
,
{
ref
:
formRef
,
formInline
:
null
}),
beforeSure
:
(
done
,
{
options
})
=>
{
const
FormRef
=
formRef
.
value
.
getRef
();
const
curData
=
options
.
props
.
formInline
as
FormItemProps
;
function
chores
()
{
message
(
`您
${
title
}
了菜单名称为
${
transformI18n
(
curData
.
title
)}
的这条数据`
,
{
type
:
"success"
}
);
done
();
// 关闭弹框
onSearch
();
// 刷新表格数据
}
FormRef
.
validate
(
valid
=>
{
if
(
valid
)
{
console
.
log
(
"curData"
,
curData
);
// 表单规则校验通过
if
(
title
===
"新增"
)
{
addMenu
(
curData
).
then
(
res
=>
{
if
((
res
as
any
).
code
===
"0"
)
{
chores
();
}
});
}
else
{
// 实际开发先调用修改接口,再进行下面操作
chores
();
}
}
});
}
});
}
function
handleDelete
(
row
)
{
message
(
`您删除了菜单名称为
${
transformI18n
(
row
.
title
)}
的这条数据`
,
{
type
:
"success"
});
onSearch
();
}
onMounted
(()
=>
{
onSearch
();
});
return
{
form
,
loading
,
columns
,
dataList
,
/** 搜索 */
onSearch
,
/** 重置 */
resetForm
,
/** 新增、修改菜单 */
openDialog
,
/** 删除菜单 */
handleDelete
,
handleSelectionChange
};
}
src/views/systems/menu/utils/rule.ts
0 → 100644
浏览文件 @
a5409e05
import
{
reactive
}
from
"vue"
;
import
type
{
FormRules
}
from
"element-plus"
;
/** 自定义表单规则校验 */
export
const
formRules
=
reactive
(
<
FormRules
>
{
title
:
[{
required
:
true
,
message
:
"菜单名称为必填项"
,
trigger
:
"blur"
}],
name
:
[{
required
:
true
,
message
:
"路由名称为必填项"
,
trigger
:
"blur"
}],
path
:
[{
required
:
true
,
message
:
"路由路径为必填项"
,
trigger
:
"blur"
}],
auths
:
[{
required
:
true
,
message
:
"权限标识为必填项"
,
trigger
:
"blur"
}]
});
src/views/systems/menu/utils/types.ts
0 → 100644
浏览文件 @
a5409e05
interface
FormItemProps
{
/** 菜单类型(0代表菜单、1代表iframe、2代表外链、3代表按钮)*/
menuType
:
number
;
higherMenuOptions
:
Record
<
string
,
unknown
>
[];
parentId
:
number
;
title
:
string
;
name
:
string
;
path
:
string
;
component
:
string
;
rank
:
number
;
redirect
:
string
;
icon
:
string
;
extraIcon
:
string
;
enterTransition
:
string
;
leaveTransition
:
string
;
activePath
:
string
;
auths
:
string
;
frameSrc
:
string
;
frameLoading
:
boolean
;
keepAlive
:
boolean
;
hiddenTag
:
boolean
;
fixedTag
:
boolean
;
showLink
:
boolean
;
showParent
:
boolean
;
}
interface
FormProps
{
formInline
:
FormItemProps
;
}
export
type
{
FormItemProps
,
FormProps
};
vite.config.ts
浏览文件 @
a5409e05
...
...
@@ -28,7 +28,10 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
proxy
:
{
"/api"
:
{
// 这里填写后端地址
target
:
"http://192.168.1.194:5001"
,
// 熊熊哥地址
// target: "http://192.168.1.194:5001",
// 服务器地址
target
:
"http://192.168.1.248:5001"
,
changeOrigin
:
true
,
rewrite
:
path
=>
path
.
replace
(
/^
\/
api/
,
""
)
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论