Files
yinnihailiang_one/lms/nladmin-ui/src/views/system/menu/index.vue
2026-01-07 19:43:06 +08:00

375 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input
v-model="query.blurry"
clearable
size="mini"
:placeholder="$t('common.fuzzy_search')"
style="width: 200px;margin-bottom: 10px"
class="filter-item"
@keyup.enter.native="queryBlurry"
/>
<el-select
v-model="query.system_type"
style="width: 100px; height: 35px;top: -5px;"
:placeholder="$t('sys_menu.owned_system')"
@change="changetype"
>
<el-option
v-for="item in dict.system_type"
:label="item.label"
:value="item.value"
/>
</el-select>
<rrOperation />
</div>
<crudOperation :permission="permission" />
</div>
<!--表单渲染-->
<el-dialog
append-to-body
:close-on-click-modal="false"
:before-close="crud.cancelCU"
:visible.sync="crud.status.cu > 0"
:title="crud.status.title"
width="650px"
>
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="mini" label-width="80px">
<el-form-item :label="$t('sys_menu.type')" prop="type">
<el-radio-group v-model="form.type" size="mini">
<el-radio-button label="1">{{$t('sys_menu.type_system')}}</el-radio-button>
<el-radio-button label="2">{{$t('sys_menu.type_directory')}}</el-radio-button>
<el-radio-button label="3">{{$t('sys_menu.type_menu')}}</el-radio-button>
<el-radio-button label="4">{{$t('sys_menu.type_button')}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-show="form.type.toString() !== '1' && form.type.toString() !== '4' " :label="$t('sys_menu.icon')" prop="icon">
<el-popover
placement="bottom-start"
width="450"
trigger="click"
@show="$refs['iconSelect'].reset()"
>
<IconSelect ref="iconSelect" @selected="selected" />
<el-input slot="reference" v-model="form.icon" style="width: 450px;" :placeholder="$t('sys_menu.click_select_icon')" readonly>
<svg-icon
v-if="form.icon"
slot="prefix"
:icon-class="form.icon"
class="el-input__icon"
style="height: 32px;width: 16px;"
/>
<i v-else slot="prefix" class="el-icon-search el-input__icon" />
</el-input>
</el-popover>
</el-form-item>
<el-form-item v-show="form.type.toString() !== '2' && form.type.toString() !== '1'" :label="$t('sys_menu.iframe')" prop="iframe">
<el-radio-group v-model="form.iframe" size="mini">
<el-radio-button label="true">{{$t('common.Yes')}}</el-radio-button>
<el-radio-button label="false">{{$t('common.No')}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-show="form.type.toString() === '3'" :label="$t('sys_menu.cache')" prop="cache">
<el-radio-group v-model="form.cache" size="mini">
<el-radio-button label="true">{{$t('common.Yes')}}</el-radio-button>
<el-radio-button label="false">{{$t('common.No')}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-show="form.type.toString() !== '2' && form.type.toString() !== '1' " :label="$t('sys_menu.hidden')" prop="hidden">
<el-radio-group v-model="form.hidden" size="mini">
<el-radio-button label="false">{{$t('common.Yes')}}</el-radio-button>
<el-radio-button label="true">{{$t('common.No')}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.type.toString() !== '2'" :label="$t('sys_menu.title')" prop="title">
<el-input
v-model="form.title"
:style=" form.type.toString() === '0' ? 'width: 450px' : 'width: 190px'"
:placeholder="$t('sys_menu.title')"
/>
</el-form-item>
<el-form-item v-if="form.type.toString() === '2'" :label="$t('sys_menu.button_name')" prop="title">
<el-input v-model="form.title" :placeholder="$t('sys_menu.button_name')" style="width: 190px;" />
</el-form-item>
<el-form-item v-show="form.type.toString() !== '1' " :label="$t('sys_menu.permission')" prop="permission">
<el-input v-model="form.permission" :disabled="form.iframe" :placeholder="$t('sys_menu.permission')" style="width: 190px;" />
</el-form-item>
<el-form-item v-if="form.type.toString() !== '1' && form.type.toString() !== '2'" :label="$t('sys_menu.path')" prop="path">
<el-input v-model="form.path" :placeholder="$t('sys_menu.path')" style="width: 190px;" />
</el-form-item>
<el-form-item :label="$t('sys_menu.menu_sort')" prop="menu_sort">
<el-input-number
v-model.number="form.menu_sort"
:min="0"
:max="999"
controls-position="right"
style="width: 190px;"
/>
</el-form-item>
<el-form-item v-show="!form.iframe && form.type.toString() === '3' " :label="$t('sys_menu.component_name')" prop="component_name">
<el-input v-model="form.component_name" style="width: 190px;" :placeholder="$t('sys_menu.match_component_name')" />
</el-form-item>
<el-form-item v-show="!form.iframe && (form.type.toString() === '2' ||form.type.toString() === '3' ) " :label="$t('sys_menu.component')" prop="component">
<el-input v-model="form.component" style="width: 190px;" :placeholder="$t('sys_menu.component')" />
</el-form-item>
<el-form-item :label="$t('sys_menu.parent_category')" prop="pid">
<!-- normalizer转换- loadMenus 点击扩展的时候会调用该方法-->
<treeselect
v-model="form.pid"
:options="menus"
:load-options="loadMenus"
:normalizer="normalizer"
style="width: 450px;"
:placeholder="$t('sys_menu.select_parent_category')"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">{{$t('common.Cancel')}}</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">{{$t('common.Confirm')}}</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table
ref="table"
v-loading="crud.loading"
lazy
:load="getMenus"
:auto-load-root-options="false"
:data="crud.data"
:tree-props="{children: 'children', hasChildren: 'has_children'}"
row-key="menu_id"
@select="crud.selectChange"
@select-all="crud.selectAllChange"
@selection-change="crud.selectionChangeHandler"
>
<el-table-column type="selection" width="55" />
<el-table-column :label="$t('sys_menu.title')" prop="title" :min-width="100" />
<el-table-column :label="$t('sys_menu.system_type')" prop="system_type" :min-width="flexWidth('system_type',crud.data,$t('sys_menu.system_type'))">
<template slot-scope="scope">
{{ dict.label.system_type[scope.row.system_type] }} : {{scope.row.system_type}}
</template>
</el-table-column>
<el-table-column prop="icon" :label="$t('sys_menu.icon')" align="center" :min-width="flexWidth('icon',crud.data,$t('sys_menu.icon'))">
<template slot-scope="scope">
<svg-icon :icon-class="scope.row.icon ? scope.row.icon : ''" />
</template>
</el-table-column>
<el-table-column prop="menu_sort" align="center" :label="$t('sys_menu.menu_sort')" :min-width="flexWidth('menu_sort',crud.data,$t('sys_menu.menu_sort'))">
<template slot-scope="scope">
{{ scope.row.menu_sort }}
</template>
</el-table-column>
<el-table-column prop="permission" :label="$t('sys_menu.permission')" :min-width="flexWidth('permission',crud.data,$t('sys_menu.permission'))" />
<el-table-column prop="component" :label="$t('sys_menu.component')" min-width="120" />
<el-table-column prop="iframe" :label="$t('sys_menu.iframe')" :formatter="crud.formatIsOrNot" :min-width="flexWidth('iframe',crud.data,$t('sys_menu.iframe'))">
<template slot-scope="scope">
<span v-if="scope.row.iframe">{{$t('common.Yes')}}</span>
<span v-else>{{$t('common.No')}}</span>
</template>
</el-table-column>
<el-table-column prop="cache" :label="$t('sys_menu.cache')" :formatter="crud.formatIsOrNot" :min-width="flexWidth('cache',crud.data,$t('sys_menu.cache'))">
<template slot-scope="scope">
<span v-if="scope.row.cache">{{$t('common.Yes')}}</span>
<span v-else>{{$t('common.No')}}</span>
</template>
</el-table-column>
<el-table-column prop="hidden" :label="$t('sys_menu.hidden')" :formatter="crud.formatIsOrNot" :min-width="flexWidth('hidden',crud.data,$t('sys_menu.hidden'))">
<template slot-scope="scope">
<span v-if="scope.row.hidden">{{$t('common.No')}}</span>
<span v-else>{{$t('common.Yes')}}</span>
</template>
</el-table-column>
<el-table-column prop="create_time" :label="$t('common.create_time')" :min-width="flexWidth('create_time',crud.data,$t('common.create_time'))" />
<el-table-column
v-permission="['admin','menu:edit','menu:del']"
:label="$t('common.Operate')"
width="130px"
align="center"
fixed="right"
>
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
:msg="$t('sys_menu.confirm_delete_msg')"
/>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import crudMenu from './menu'
import IconSelect from '@/components/IconSelect'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import udOperation from '@crud/UD.operation'
import DateRangePicker from '@/components/DateRangePicker'
import Dict from '../../../components/Dict/Dict'
// crud交由presenter持有
const defaultForm = {
menu_id: null,
title: null,
menu_sort: 999,
path: null,
system_type: null,
category: null,
component: null,
component_name: null,
iframe: false,
roles: [],
pid: 0,
icon: null,
cache: false,
hidden: false,
type: 0,
permission: null
}
export default {
name: 'Menu',
components: { Treeselect, IconSelect, crudOperation, rrOperation, udOperation, DateRangePicker },
cruds() {
return CRUD({ title: '菜单', idField: 'menu_id', sort: 'menu_id,asc', url: 'api/sysMenu', crudMethod: { ...crudMenu }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
dicts: ['system_type'],
data() {
return {
typeList: [],
defaultType: '',
menus: [],
permission: {
add: ['admin', 'menu:add'],
edit: ['admin', 'menu:edit'],
del: ['admin', 'menu:del']
},
rules: {
title: [
{ required: true, message: '请输入标题', trigger: 'blur' }
],
path: [
{ required: true, message: '请输入地址', trigger: 'blur' }
]
}
}
},
methods: {
normalizer(node) {
return {
id: node.menu_id,
label: node.title,
children: node.children
}
},
queryBlurry() {
if (this.query.blurry) {
this.query.pid = null
}
this.crud.toQuery()
},
changetype() {
const sysType = this.dict.dict.system_type[this.query.system_type]
this.query.pid = sysType.para1
this.crud.toQuery()
},
[CRUD.HOOK.beforeRefresh]() {
// if (this.crud.query.system_type == null) {
// this.crud.query.system_type = '1'
// }
return true
},
// 新增与编辑前做的操作
[CRUD.HOOK.afterToCU](crud, form) {
this.menus = []
if (form.menu_id) { // 修改
if (!form.pid) { // 一级菜单一级的父级菜单的pid为0.
form.pid = 0
}
this.getSupMenus(form.menu_id)
} else { // 新增
this.menus.push({ menu_id: 0, title: '顶级类目', children: null })
}
},
[CRUD.HOOK.afterSubmit](crud, form) {
if (this.$options.dicts instanceof Array) {
new Dict(this.dict).init(this.$options.dicts, () => {
this.$nextTick(() => {
this.$emit('dictReady')
})
})
}
},
[CRUD.HOOK.afterDelete](crud, form) {
if (this.$options.dicts instanceof Array) {
new Dict(this.dict).init(this.$options.dicts, () => {
this.$nextTick(() => {
this.$emit('dictReady')
})
})
}
},
getMenus(tree, treeNode, resolve) {
const params = { pid: tree.menu_id, system_type: tree.system_type }
setTimeout(() => {
crudMenu.getMenus(params).then(res => {
resolve(res.content)
})
}, 100)
},
getSupMenus(menu_id) {
crudMenu.getMenuSuperior(menu_id).then(res => {
const children = res.map(function(obj) {
if (!obj.leaf && !obj.children) {
obj.children = null
}
return obj
})
this.menus = [{ menu_id: 0, title: '顶级类目', children: children }]
})
},
loadMenus({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
crudMenu.getMenusTree(parentNode.menu_id).then(res => {
parentNode.children = res.map(function(obj) {
if (!obj.leaf) {
obj.children = null
}
return obj
})
setTimeout(() => {
callback()
}, 100)
})
}
},
// 选中图标
selected(name) {
this.form.icon = name
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
::v-deep .el-input-number .el-input__inner {
text-align: left;
}
::v-deep .vue-treeselect__control, ::v-deep .vue-treeselect__placeholder, ::v-deep .vue-treeselect__single-value {
height: 30px;
line-height: 30px;
}
</style>