parent
662ec8510f
commit
a7d18b2d5e
@ -0,0 +1,290 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
:title="!dataForm.id ? '新增' : '修改'"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="dataFormRef"
|
||||||
|
:model="dataForm"
|
||||||
|
:rules="dataRule"
|
||||||
|
label-width="80px"
|
||||||
|
@keyup.enter="onSubmit()"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="类型"
|
||||||
|
prop="type"
|
||||||
|
>
|
||||||
|
<el-radio-group v-model="dataForm.type">
|
||||||
|
<el-radio
|
||||||
|
v-for="(type, index) in dataForm.typeList"
|
||||||
|
:key="index"
|
||||||
|
:label="index"
|
||||||
|
>
|
||||||
|
{{ type }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="dataForm.typeList[dataForm.type] + '名称'"
|
||||||
|
prop="name"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="dataForm.name"
|
||||||
|
:placeholder="dataForm.typeList[dataForm.type] + '名称'"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="上级菜单">
|
||||||
|
<el-cascader
|
||||||
|
v-model="selectedMenu"
|
||||||
|
expand-trigger="hover"
|
||||||
|
:options="menuList"
|
||||||
|
:props="menuListTreeProps"
|
||||||
|
change-on-select
|
||||||
|
@change="handleSelectMenuChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="dataForm.type === 1"
|
||||||
|
label="菜单路由"
|
||||||
|
prop="url"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="dataForm.url"
|
||||||
|
placeholder="菜单路由"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="dataForm.type !== 0"
|
||||||
|
label="授权标识"
|
||||||
|
prop="perms"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="dataForm.perms"
|
||||||
|
placeholder="多个用逗号分隔, 如: user:list,user:create"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="dataForm.type !== 2"
|
||||||
|
label="排序号"
|
||||||
|
prop="orderNum"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
v-model="dataForm.orderNum"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
label="排序号"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="dataForm.type !== 2"
|
||||||
|
label="菜单图标"
|
||||||
|
prop="icon"
|
||||||
|
>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-input
|
||||||
|
ref="iconInputRef"
|
||||||
|
v-model="dataForm.icon"
|
||||||
|
:virtual-ref="iconListPopoverRef"
|
||||||
|
placeholder="菜单图标名称"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<el-popover
|
||||||
|
ref="iconListPopoverRef"
|
||||||
|
style="width: 390px"
|
||||||
|
:virtual-ref="iconInputRef"
|
||||||
|
placement="bottom-start"
|
||||||
|
trigger="click"
|
||||||
|
:popper-style="iconPopoverClass"
|
||||||
|
virtual-triggering
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-for="(item, index) in iconList"
|
||||||
|
:key="index"
|
||||||
|
style="padding: 8px; margin: 8px 0 0 8px"
|
||||||
|
:class="{ 'is-active': item === dataForm.icon }"
|
||||||
|
@click="iconActiveHandle(item)"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
:icon-class="`${item}`"
|
||||||
|
/>
|
||||||
|
</el-button>
|
||||||
|
</el-popover>
|
||||||
|
</el-col>
|
||||||
|
<el-col
|
||||||
|
:span="2"
|
||||||
|
class="icon-list__tips"
|
||||||
|
>
|
||||||
|
<el-tooltip
|
||||||
|
placement="top"
|
||||||
|
effect="light"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div>全站推荐使用SVG Sprite, 详细请参考:icons/index.js 描述</div>
|
||||||
|
</template>
|
||||||
|
<i class="el-icon-warning" />
|
||||||
|
</el-tooltip>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="onSubmit()"
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { treeDataTranslate, idList } from '@/utils'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
const emit = defineEmits(['refreshDataList'])
|
||||||
|
const iconInputRef = ref(null)
|
||||||
|
const iconListPopoverRef = ref(null)
|
||||||
|
const iconPopoverClass = computed(() => {
|
||||||
|
return {
|
||||||
|
width: '396px'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const dataForm = reactive({
|
||||||
|
id: 0,
|
||||||
|
type: 1,
|
||||||
|
typeList: ['目录', '菜单', '按钮'],
|
||||||
|
name: '',
|
||||||
|
parentId: 0,
|
||||||
|
url: '',
|
||||||
|
perms: '',
|
||||||
|
orderNum: 0,
|
||||||
|
icon: '',
|
||||||
|
iconList: []
|
||||||
|
})
|
||||||
|
const menuList = ref([])
|
||||||
|
const selectedMenu = ref([])
|
||||||
|
const menuListTreeProps = {
|
||||||
|
value: 'menuId',
|
||||||
|
label: 'name'
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const validateUrl = (rule, value, callback) => {
|
||||||
|
if (dataForm.type === 1 && !/\S/.test(value)) {
|
||||||
|
callback(new Error('菜单URL不能为空'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dataRule = ref({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '菜单名称不能为空', trigger: 'blur' },
|
||||||
|
{ pattern: /\s\S+|S+\s|\S/, message: '请输入正确的菜单名称', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
url: [
|
||||||
|
{ validator: validateUrl, trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
onLoadIcons()
|
||||||
|
})
|
||||||
|
const iconList = []
|
||||||
|
// 加载图标
|
||||||
|
const onLoadIcons = () => {
|
||||||
|
const icons = import.meta.glob('@/icons/svg/*.svg')
|
||||||
|
for (const icon in icons) {
|
||||||
|
const iconName = icon.split('/src/icons/svg/')[1].split('.svg')[0]
|
||||||
|
iconList.push(iconName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataFormRef = ref(null)
|
||||||
|
const init = (id) => {
|
||||||
|
dataForm.id = id || 0
|
||||||
|
http({
|
||||||
|
url: http.adornUrl('/sys/menu/list'),
|
||||||
|
method: 'get',
|
||||||
|
params: http.adornParams()
|
||||||
|
})
|
||||||
|
.then(({ data }) => {
|
||||||
|
menuList.value = treeDataTranslate(data, 'menuId')
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
visible.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
if (dataForm.id) {
|
||||||
|
// 修改
|
||||||
|
http({
|
||||||
|
url: http.adornUrl(`/sys/menu/info/${dataForm.id}`),
|
||||||
|
method: 'get',
|
||||||
|
params: http.adornParams()
|
||||||
|
}).then(({ data }) => {
|
||||||
|
dataForm.id = data.menuId
|
||||||
|
dataForm.type = data.type
|
||||||
|
dataForm.name = data.name
|
||||||
|
dataForm.parentId = data.parentId
|
||||||
|
dataForm.url = data.url
|
||||||
|
dataForm.perms = data.perms
|
||||||
|
dataForm.orderNum = data.orderNum
|
||||||
|
dataForm.icon = data.icon
|
||||||
|
selectedMenu.value = idList(menuList.value, data.parentId, 'menuId', 'children').reverse()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
selectedMenu.value = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({ init })
|
||||||
|
|
||||||
|
const handleSelectMenuChange = (val) => {
|
||||||
|
dataForm.parentId = val[val.length - 1]
|
||||||
|
}
|
||||||
|
// 图标选中
|
||||||
|
const iconActiveHandle = (iconName) => {
|
||||||
|
dataForm.icon = iconName
|
||||||
|
}
|
||||||
|
// 表单提交
|
||||||
|
const onSubmit = Debounce(() => {
|
||||||
|
dataFormRef.value?.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
http({
|
||||||
|
url: http.adornUrl('/sys/menu'),
|
||||||
|
method: dataForm.id ? 'put' : 'post',
|
||||||
|
data: http.adornData({
|
||||||
|
menuId: dataForm.id || undefined,
|
||||||
|
type: dataForm.type,
|
||||||
|
name: dataForm.name,
|
||||||
|
parentId: dataForm.parentId,
|
||||||
|
url: dataForm.url,
|
||||||
|
perms: dataForm.perms,
|
||||||
|
orderNum: dataForm.orderNum,
|
||||||
|
icon: dataForm.icon
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
ElMessage({
|
||||||
|
message: '操作成功',
|
||||||
|
type: 'success',
|
||||||
|
duration: 1500,
|
||||||
|
onClose: () => {
|
||||||
|
visible.value = false
|
||||||
|
emit('refreshDataList')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mod-menu">
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="dataForm"
|
||||||
|
>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
v-if="isAuth('sys:menu:save')"
|
||||||
|
type="primary"
|
||||||
|
@click="onAddOrUpdate()"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table
|
||||||
|
:data="dataList"
|
||||||
|
border
|
||||||
|
style="width: 100%;"
|
||||||
|
row-key="menuId"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
header-align="center"
|
||||||
|
tree-key="menuId"
|
||||||
|
width="150"
|
||||||
|
label="名称"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
label="图标"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<svg-icon
|
||||||
|
:icon-class="`icon-${scope.row.icon}`"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="type"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
label="类型"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag
|
||||||
|
v-if="scope.row.type === 0"
|
||||||
|
>
|
||||||
|
目录
|
||||||
|
</el-tag>
|
||||||
|
<el-tag
|
||||||
|
v-else-if="scope.row.type === 1"
|
||||||
|
|
||||||
|
type="success"
|
||||||
|
>
|
||||||
|
菜单
|
||||||
|
</el-tag>
|
||||||
|
<el-tag
|
||||||
|
v-else-if="scope.row.type === 2"
|
||||||
|
|
||||||
|
type="info"
|
||||||
|
>
|
||||||
|
按钮
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="orderNum"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
label="排序号"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="url"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
width="150"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
label="菜单URL"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.url || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="perms"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
width="150"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
label="授权标识"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.perms || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
fixed="right"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
width="150"
|
||||||
|
label="操作"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
v-if="isAuth('sys:menu:update')"
|
||||||
|
type="text"
|
||||||
|
|
||||||
|
@click="onAddOrUpdate(scope.row.menuId)"
|
||||||
|
>
|
||||||
|
修改
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isAuth('sys:menu:delete')"
|
||||||
|
type="text"
|
||||||
|
|
||||||
|
@click="onDelete(scope.row.menuId)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 弹窗, 新增 / 修改 -->
|
||||||
|
<add-or-update
|
||||||
|
v-if="addOrUpdateVisible"
|
||||||
|
ref="addOrUpdateRef"
|
||||||
|
@refresh-data-list="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { treeDataTranslate, isAuth } from '@/utils'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import AddOrUpdate from './add-or-update.vue'
|
||||||
|
|
||||||
|
const dataForm = ref({})
|
||||||
|
onMounted(() => {
|
||||||
|
getDataList()
|
||||||
|
})
|
||||||
|
|
||||||
|
const dataList = ref([])
|
||||||
|
/**
|
||||||
|
* 获取数据列表
|
||||||
|
*/
|
||||||
|
const getDataList = () => {
|
||||||
|
http({
|
||||||
|
url: http.adornUrl('/sys/menu/table'),
|
||||||
|
method: 'get',
|
||||||
|
params: http.adornParams()
|
||||||
|
}).then(({ data }) => {
|
||||||
|
dataList.value = treeDataTranslate(data, 'menuId')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const addOrUpdateRef = ref(null)
|
||||||
|
const addOrUpdateVisible = ref(false)
|
||||||
|
/**
|
||||||
|
* 新增 / 修改
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
const onAddOrUpdate = (id) => {
|
||||||
|
addOrUpdateVisible.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
addOrUpdateRef.value?.init(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
const onDelete = (id) => {
|
||||||
|
ElMessageBox.confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
http({
|
||||||
|
url: http.adornUrl(`/sys/menu/${id}`),
|
||||||
|
method: 'delete',
|
||||||
|
data: http.adornData()
|
||||||
|
}).then(() => {
|
||||||
|
ElMessage({
|
||||||
|
message: '操作成功',
|
||||||
|
type: 'success',
|
||||||
|
duration: 1500,
|
||||||
|
onClose: () => {
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
Loading…
Reference in new issue