mirror of
https://gitee.com/gz-yami/mall4v.git
synced 2026-03-22 08:07:17 +08:00
增加 系统管理-菜单管理 页面
This commit is contained in:
@@ -96,7 +96,7 @@ router.beforeEach((to, from, next) => {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
params: http.adornParams()
|
params: http.adornParams()
|
||||||
}).then(({ data }) => {
|
}).then(({ data }) => {
|
||||||
sessionStorage.setItem('Authorization', JSON.stringify(data.authorities || '[]'))
|
sessionStorage.setItem('Authorities', JSON.stringify(data.authorities || '[]'))
|
||||||
fnAddDynamicMenuRoutes(data.menuList)
|
fnAddDynamicMenuRoutes(data.menuList)
|
||||||
router.options.isAddDynamicMenuRoutes = true
|
router.options.isAddDynamicMenuRoutes = true
|
||||||
const rList = []
|
const rList = []
|
||||||
@@ -168,7 +168,7 @@ function fnCurrentRouteType (route, globalRoutes = []) {
|
|||||||
*/
|
*/
|
||||||
function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
|
function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
|
||||||
let temp = []
|
let temp = []
|
||||||
const modules = import.meta.glob('../views/modules/**/**.vue')
|
const modules = import.meta.glob('../views/modules/**/index.vue')
|
||||||
for (let i = 0; i < menuList.length; i++) {
|
for (let i = 0; i < menuList.length; i++) {
|
||||||
if (menuList[i].list && menuList[i].list.length >= 1) {
|
if (menuList[i].list && menuList[i].list.length >= 1) {
|
||||||
temp = temp.concat(menuList[i].list)
|
temp = temp.concat(menuList[i].list)
|
||||||
@@ -193,7 +193,7 @@ function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
|
|||||||
route.meta.iframeUrl = menuList[i].url
|
route.meta.iframeUrl = menuList[i].url
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
route.component = modules[`../views/modules/${menuList[i].url}.vue`] || null
|
route.component = modules[`../views/modules/${menuList[i].url}/index.vue`] || null
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
routes.push(route)
|
routes.push(route)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ const http = axios.create({
|
|||||||
http.interceptors.request.use(
|
http.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
config.headers.Authorization = cookie.get('Authorization') // 请求头带上token
|
config.headers.Authorization = cookie.get('Authorization') // 请求头带上token
|
||||||
config.headers.locale = localStorage.getItem('b2cLang') || 'zh_CN'
|
|
||||||
// 只针对get方式进行序列化
|
// 只针对get方式进行序列化
|
||||||
if (config.method === 'get' || config.method === 'GET') {
|
if (config.method === 'get' || config.method === 'GET') {
|
||||||
config.paramsSerializer = function (params) {
|
config.paramsSerializer = function (params) {
|
||||||
@@ -68,7 +67,7 @@ http.interceptors.response.use(
|
|||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('============== 请求异常 ==============', '\n', `接口地址: ${response.config.url.replace(import.meta.env.VITE_APP_BASE_API, '')}`, '\n', `异常信息: ${res}`, '\n', '============== 请求异常 end ==========')
|
console.error('============== 请求异常 ==============', '\n', `接口地址: ${response.config.url.replace(import.meta.env.VITE_APP_BASE_API, '')}`, '\n', `异常信息: ${res}`, '\n', '============== 请求异常 end ==========')
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: $t('utils.serverErr'),
|
message: '服务器出了点小差,请稍后再试',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 1.5 * 1000,
|
duration: 1.5 * 1000,
|
||||||
customClass: 'element-error-message-zindex'
|
customClass: 'element-error-message-zindex'
|
||||||
@@ -94,7 +93,7 @@ http.interceptors.response.use(
|
|||||||
break
|
break
|
||||||
case 405:
|
case 405:
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: $t('utils.requestErr'),
|
message: 'http请求方式有误',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
customClass: 'element-error-message-zindex'
|
customClass: 'element-error-message-zindex'
|
||||||
@@ -102,7 +101,7 @@ http.interceptors.response.use(
|
|||||||
break
|
break
|
||||||
case 500:
|
case 500:
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: $t('utils.serverErr'),
|
message: '服务器出了点小差,请稍后再试',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
customClass: 'element-error-message-zindex'
|
customClass: 'element-error-message-zindex'
|
||||||
@@ -110,7 +109,7 @@ http.interceptors.response.use(
|
|||||||
break
|
break
|
||||||
case 501:
|
case 501:
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: $t('utils.serverNoSupp'),
|
message: '服务器不支持当前请求所需要的某个功能',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
customClass: 'element-error-message-zindex'
|
customClass: 'element-error-message-zindex'
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function getUUID () {
|
|||||||
* @param {*} key
|
* @param {*} key
|
||||||
*/
|
*/
|
||||||
export function isAuth (key) {
|
export function isAuth (key) {
|
||||||
const authorities = JSON.parse(sessionStorage.getItem('b2cAuthorities') || '[]')
|
const authorities = JSON.parse(sessionStorage.getItem('Authorities') || '[]')
|
||||||
if (authorities.length) {
|
if (authorities.length) {
|
||||||
for (const i in authorities) {
|
for (const i in authorities) {
|
||||||
const element = authorities[i]
|
const element = authorities[i]
|
||||||
@@ -33,3 +33,57 @@ export function clearLoginInfo () {
|
|||||||
cookie.remove('Authorization')
|
cookie.remove('Authorization')
|
||||||
router.options.isAddDynamicMenuRoutes = false
|
router.options.isAddDynamicMenuRoutes = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 树形数据转换
|
||||||
|
* @param {*} data
|
||||||
|
* @param {*} id
|
||||||
|
* @param {*} pid
|
||||||
|
*/
|
||||||
|
export function treeDataTranslate (data, id = 'id', pid = 'parentId') {
|
||||||
|
const res = []
|
||||||
|
const temp = {}
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
temp[data[i][id]] = data[i]
|
||||||
|
}
|
||||||
|
for (let k = 0; k < data.length; k++) {
|
||||||
|
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
|
||||||
|
if (!temp[data[k][pid]].children) {
|
||||||
|
temp[data[k][pid]].children = []
|
||||||
|
}
|
||||||
|
if (!temp[data[k][pid]]._level) {
|
||||||
|
temp[data[k][pid]]._level = 1
|
||||||
|
}
|
||||||
|
data[k]._level = temp[data[k][pid]]._level + 1
|
||||||
|
temp[data[k][pid]].children.push(data[k])
|
||||||
|
} else {
|
||||||
|
res.push(data[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
function idListFromTree (data, val, res = [], id = 'id', children = 'children') {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const element = data[i]
|
||||||
|
if (element[children]) {
|
||||||
|
if (idListFromTree(element[children], val, res, id, children)) {
|
||||||
|
res.push(element[id])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (element[id] === val) {
|
||||||
|
res.push(element[id])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将数组中的parentId列表取出,倒序排列
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
export function idList (data, val, id = 'id', children = 'children') {
|
||||||
|
const res = []
|
||||||
|
idListFromTree(data, val, res, id)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|||||||
@@ -146,40 +146,49 @@ const getCaptcha = () => {
|
|||||||
background: url('../../../assets/img/login-bg.png') no-repeat;
|
background: url('../../../assets/img/login-bg.png') no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
.login-box {
|
||||||
.login .login-box {
|
position: absolute;
|
||||||
position: absolute;
|
left: 50%;
|
||||||
left: 50%;
|
transform: translateX(-50%);
|
||||||
transform: translateX(-50%);
|
height: 100%;
|
||||||
height: 100%;
|
padding-top: 10%;
|
||||||
padding-top: 10%;
|
.top {
|
||||||
}
|
margin-bottom: 30px;
|
||||||
.login .login-box .top {
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
.logo {
|
||||||
text-align: center;
|
font-size: 0;
|
||||||
}
|
max-width: 50%;
|
||||||
.login .login-box .top .logo {
|
margin: 0 auto;
|
||||||
font-size: 0;
|
}
|
||||||
max-width: 50%;
|
&:deep(.company) {
|
||||||
margin: 0 auto;
|
font-size: 16px;
|
||||||
}
|
margin-top: 10px;
|
||||||
.login .login-box .top :deep(.company) {
|
}
|
||||||
font-size: 16px;
|
}
|
||||||
margin-top: 10px;
|
.mid {
|
||||||
}
|
font-size: 14px;
|
||||||
.login .login-box .mid {
|
.item-btn {
|
||||||
font-size: 14px;
|
width: 410px;
|
||||||
}
|
margin-top: 20px;
|
||||||
.login .login-box .mid .item-btn {
|
input {
|
||||||
margin-top: 20px;
|
border: 0;
|
||||||
}
|
width: 100%;
|
||||||
.login .login-box .mid .item-btn input {
|
height: 40px;
|
||||||
border: 0;
|
background: #1f87e8;
|
||||||
width: 100%;
|
color: #fff;
|
||||||
height: 40px;
|
border-radius: 3px;
|
||||||
background: #1f87e8;
|
}
|
||||||
color: #fff;
|
}
|
||||||
border-radius: 3px;
|
}
|
||||||
|
.bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10%;
|
||||||
|
width: 100%;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
width: 410px;
|
width: 410px;
|
||||||
@@ -187,12 +196,4 @@ const getCaptcha = () => {
|
|||||||
:deep(.login-captcha) {
|
:deep(.login-captcha) {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
.login .login-box .bottom {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10%;
|
|
||||||
width: 100%;
|
|
||||||
color: #999;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
290
src/views/modules/sys/menu/add-or-update.vue
Normal file
290
src/views/modules/sys/menu/add-or-update.vue
Normal file
@@ -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>
|
||||||
196
src/views/modules/sys/menu/index.vue
Normal file
196
src/views/modules/sys/menu/index.vue
Normal file
@@ -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>
|
||||||
Reference in New Issue
Block a user