123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- <template>
- <div class="pageWrap">
- <el-aside v-loading="menuLoading" width="300px" style="background: #fff; margin-right: 10px">
- <el-container style="height: 100%">
- <header style="padding: 13px 15px; border-bottom: 1px solid var(--el-border-color-light)">
- <el-input v-model="menuFilterText" placeholder="输入关键字进行过滤" clearable></el-input>
- </header>
- <el-main class="nopadding">
- <el-tree
- ref="menuRef"
- class="menu-tree"
- node-key="id"
- :data="menuList"
- :props="menuProps"
- highlight-current
- :expand-on-click-node="false"
- check-strictly
- show-checkbox
- :filter-node-method="menuFilterNode"
- @node-click="menuClick"
- >
- <template #default="{ node, data }">
- <span class="custom-tree-node el-tree-node__label">
- <span class="label">
- {{ generateTitle(node.label) }}
- </span>
- <span class="do">
- <el-icon @click.stop="add(node, data)"><Plus /></el-icon>
- </span>
- </span>
- </template>
- </el-tree>
- </el-main>
- <el-footer style="height: 51px">
- <el-button :icon="Refresh" @click="getMenu()"></el-button>
- <el-button type="primary" :icon="Plus" @click="add()"></el-button>
- <el-button type="danger" plain :icon="Delete" @click="delMenu"></el-button>
- </el-footer>
- </el-container>
- </el-aside>
- <el-container style="background: #fff" class="container-bg">
- <el-main ref="mainRef" class="nopadding" style="padding: 20px">
- <save ref="saveRef" :menu="menuList"></save>
- </el-main>
- </el-container>
- </div>
- </template>
- <script setup name="menu">
- import Save from './save'
- import resource from '@/api/system/resource'
- import { Plus, Refresh, Delete } from '@element-plus/icons-vue'
- import { onMounted, ref } from 'vue'
- import { ElMessage, ElMessageBox } from 'element-plus'
- import { generateTitle } from '@/utils/i18n'
- const menuLoading = ref(false)
- const menuList = ref([])
- const menuFilterText = ref('')
- const mainRef = ref(null) // 右侧的大容器
- const saveRef = ref(null) // 右侧的表单
- const menuRef = ref(null) // 左侧菜单树
- const menuProps = {
- label: data => {
- return data.title
- }
- }
- let newMenuIndex = 1
- // methods
- const getMenu = async () => {
- //加载树数据
- menuLoading.value = true
- try {
- let data = await resource.resourceListTreeApi()
- menuLoading.value = false
- menuList.value = data
- } catch (e) {
- console.log(e)
- menuLoading.value = false
- }
- }
- const menuClick = (data, node) => {
- //树点击
- let pid = +node.level === 1 ? undefined : node.parent.data.id
- saveRef.value.setData(data, pid)
- mainRef.value.$el.scrollTop = 0
- }
- const menuFilterNode = (value, data) => {
- //树过滤
- if (!value) return true
- let targetText = data.title
- return targetText.indexOf(value) !== -1
- }
- const add = async (node, data) => {
- let newMenuName = '未命名' + newMenuIndex++
- let newMenuData = {
- pid: '0',
- parentName: '',
- path: '',
- component: '',
- title: newMenuName,
- type: '0'
- }
- if (data) {
- newMenuData.pid = data.id
- newMenuData.parentName = data.title
- }
- menuLoading.value = true
- try {
- let res = await resource.resourceAddOrEditSaveApi(newMenuData)
- menuLoading.value = false
- newMenuData.id = res
- menuRef.value.append(newMenuData, node)
- menuRef.value.setCurrentKey(newMenuData.id)
- let pid = node ? node.data.id : ''
- saveRef.value.setData(newMenuData, pid)
- } catch (e) {
- menuLoading.value = false
- console.log(e, '新增菜单失败')
- }
- }
- const delMenu = () => {
- //删除菜单
- let checkedNodes = menuRef.value.getCheckedNodes()
- if (!checkedNodes.length) {
- return ElMessage.warning('请选择需要删除的项')
- }
- ElMessageBox.confirm(`确认删除已选择的菜单吗?`, '提示', {
- type: 'warning',
- confirmButtonText: '删除',
- confirmButtonClass: 'el-button--danger'
- })
- .then(async () => {
- menuLoading.value = true
- let reqData = checkedNodes.map(item => item.id)
- try {
- await resource.resourceDeleteApi(reqData)
- checkedNodes.forEach(item => {
- let node = menuRef.value.getNode(item)
- if (node.isCurrent) {
- saveRef.value.setData({})
- }
- menuRef.value.remove(item)
- })
- menuLoading.value = false
- } catch (e) {
- menuLoading.value = false
- console.log('删除左侧菜单失败', e)
- }
- })
- .catch(() => {})
- }
- onMounted(() => {
- getMenu()
- })
- </script>
- <style scoped lang="scss">
- .pageWrap {
- flex: 1;
- display: flex;
- height: 100%;
- //background: #fff;
- }
- // 角色的树结构样式
- :deep(.menu-tree) {
- .el-tree-node__content {
- height: 36px;
- }
- .el-tree-node__content .el-tree-node__label .icon {
- margin-right: 5px;
- }
- }
- .nopadding {
- padding: 0px;
- }
- .content-warp {
- flex: 1;
- //width: calc(100% - 250px);
- width: calc(100% - 210px);
- }
- .container-bg {
- background: var(--el-bg-color-overlay);
- }
- .custom-tree-node {
- display: flex;
- flex: 1;
- align-items: center;
- justify-content: space-between;
- font-size: 14px;
- padding-right: 24px;
- height: 100%;
- }
- .custom-tree-node .label {
- display: flex;
- align-items: center;
- height: 100%;
- }
- .custom-tree-node .label .el-tag {
- margin-left: 5px;
- }
- .custom-tree-node .do {
- display: none;
- }
- .custom-tree-node .do i {
- margin-left: 5px;
- color: #999;
- padding: 5px;
- font-size: 24px;
- }
- .custom-tree-node .do i:hover {
- color: #333;
- }
- .custom-tree-node:hover .do {
- display: inline-block;
- }
- </style>
|