|
@@ -7,7 +7,16 @@
|
|
|
<el-button class="m-l-base" type="primary" :loading="loading" @click="onSubmit">保存</el-button>
|
|
|
</div>
|
|
|
<div class="flex-1 p-base m-t-large fill-lighter full-scroll-y-auto privilege-tree">
|
|
|
- <el-tree ref="treeRef" show-checkbox node-key="index" :data="menuTree || []" @check-change="onCheckChange">
|
|
|
+ <!-- <el-tree ref="treeRef" show-checkbox node-key="index" :data="menuTree || []" @check-change="onCheckChange"> -->
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ show-checkbox
|
|
|
+ node-key="id"
|
|
|
+ :data="myTreeData || []"
|
|
|
+ :props="treeProps"
|
|
|
+ :render-content="renderContent"
|
|
|
+ @check-change="onCheckChange"
|
|
|
+ >
|
|
|
</el-tree>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -23,12 +32,15 @@ import useFetch from '@/hooks/useFetch'
|
|
|
import useMainLayoutStore from '@/store/layout'
|
|
|
import BaseSelect from '@/components/element/BaseSelect.vue'
|
|
|
import { cloneDeep } from 'lodash'
|
|
|
-
|
|
|
+import { ROLE_BUTTON_CODES } from '@/constants/app'
|
|
|
import type { ExtractApiResponse } from '@/api/api'
|
|
|
|
|
|
type MenuItem = MainLayoutStore.MenuItem
|
|
|
|
|
|
type MenuItemWithId = MenuItem & { id: number }
|
|
|
+function createNum(m: number, n: number) {
|
|
|
+ return Math.floor(Math.random() * (m - n)) + n
|
|
|
+}
|
|
|
const ROLE_OPTION = ref<any[]>([])
|
|
|
useFetch('getRoleList')
|
|
|
.fetch()
|
|
@@ -85,20 +97,83 @@ watch(
|
|
|
},
|
|
|
{ immediate: true }
|
|
|
)
|
|
|
-
|
|
|
-watch(privilege, () => {
|
|
|
- let treeData = getTreeList(privilege.value)
|
|
|
- let pIds: any[] = []
|
|
|
+const myTreeData = ref<any[]>([])
|
|
|
+const treeProps = ref({
|
|
|
+ label: 'name',
|
|
|
+})
|
|
|
+const renderContent = (h: any, { node, data, store }: any) => {
|
|
|
+ if (data.originId) {
|
|
|
+ return h(
|
|
|
+ 'span',
|
|
|
+ {
|
|
|
+ class: 'custom-tree-node',
|
|
|
+ },
|
|
|
+ h('span', { class: 'is-page' }, '页面')
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (ROLE_BUTTON_CODES.includes(data.code)) {
|
|
|
+ return h(
|
|
|
+ 'span',
|
|
|
+ {
|
|
|
+ class: 'custom-tree-node',
|
|
|
+ },
|
|
|
+ h('span', null, data.name),
|
|
|
+ h('span', { class: 'is-btn' }, '按钮')
|
|
|
+ )
|
|
|
+ }
|
|
|
+ return data.name
|
|
|
+}
|
|
|
+const getPIds = (treeData: any, pIds: any = []) => {
|
|
|
for (let i = 0; i < treeData.length; i++) {
|
|
|
- let item = treeData[i]
|
|
|
+ let item: any = treeData[i]
|
|
|
if (item.children && item.children.length) {
|
|
|
pIds.push(item.id)
|
|
|
+ getPIds(item.children, pIds)
|
|
|
}
|
|
|
}
|
|
|
+ return pIds
|
|
|
+}
|
|
|
+const newFlatArr = ref<any[]>([])
|
|
|
+watch(privilege, () => {
|
|
|
+ let data = cloneDeep(privilege.value || [])
|
|
|
+ data.forEach((item: any) => {
|
|
|
+ if (ROLE_BUTTON_CODES.includes(item.code)) {
|
|
|
+ item.type = 'button'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ let hasPermBtnPageNodes: any[] = []
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
+ let node = data[i]
|
|
|
+ if (ROLE_BUTTON_CODES.includes(node.code)) {
|
|
|
+ let pNode: any = data.find((v: any) => v.id == node.parentId) || {}
|
|
|
+ if (!hasPermBtnPageNodes.find((v: any) => v.code == node.code + '_in_page')) {
|
|
|
+ let id = createNum(-100000, -10000)
|
|
|
+ hasPermBtnPageNodes.push(
|
|
|
+ Object.assign({}, node, {
|
|
|
+ code: node.code + '_in_page',
|
|
|
+ nodeCode: node.nodeCode + '_in_page',
|
|
|
+ name: '页面',
|
|
|
+ hasPrivilege: !!pNode.hasPrivilege,
|
|
|
+ id,
|
|
|
+ nodeId: id + '',
|
|
|
+ originId: node.id,
|
|
|
+ type: 'page',
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let concatData = [...hasPermBtnPageNodes, ...data]
|
|
|
+ newFlatArr.value = cloneDeep(concatData)
|
|
|
+ let treeData = getTreeList(concatData)
|
|
|
+ myTreeData.value = treeData
|
|
|
+
|
|
|
+ let pIds = getPIds(treeData)
|
|
|
|
|
|
nextTick(() => {
|
|
|
treeRef?.value?.setCheckedKeys(
|
|
|
- privilege?.value?.filter((d) => d.hasPrivilege && pIds.indexOf(d.id) == -1)?.map((d) => d.code)
|
|
|
+ newFlatArr.value?.filter((d) => d.hasPrivilege && pIds.indexOf(d.id) == -1)?.map((d) => d.id)
|
|
|
)
|
|
|
})
|
|
|
})
|
|
@@ -122,9 +197,33 @@ const menuTree = computed(() => {
|
|
|
return menus.concat(filterPrivilege(menu, privilege.value || []) || [])
|
|
|
}, [] as MenuItem[])
|
|
|
})
|
|
|
+const onCheckChange = (a: any, b: any) => {
|
|
|
+ let resultKeys: any = treeRef?.value?.getCheckedKeys(true)
|
|
|
+ if (a.type == 'page') {
|
|
|
+ let underPageBtnKeys: any[] = []
|
|
|
+ if (!b) {
|
|
|
+ for (let i = 0; i < newFlatArr.value.length; i++) {
|
|
|
+ let item = newFlatArr.value[i]
|
|
|
+ if (item.parentId == a.parentId && item.type === 'button') {
|
|
|
+ underPageBtnKeys.push(item.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resultKeys = resultKeys?.filter((k: any) => !underPageBtnKeys.includes(k))
|
|
|
+ treeRef?.value?.setCheckedKeys(resultKeys)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (a.type == 'button') {
|
|
|
+ if (!!b) {
|
|
|
+ let page = newFlatArr.value.find((item: any) => item.type === 'page' && item.parentId == a.parentId)
|
|
|
|
|
|
-const onCheckChange = () => {
|
|
|
- checkedMenus.value = (treeRef?.value?.getCheckedNodes() as MenuItemWithId[]) || []
|
|
|
+ if (!resultKeys?.includes(page.id)) {
|
|
|
+ treeRef?.value?.setCheckedKeys([...resultKeys, page.id])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ checkedMenus.value = (treeRef?.value?.getCheckedNodes() as MenuItemWithId[]) || []
|
|
|
+ }, 1)
|
|
|
}
|
|
|
|
|
|
/** 保存 */
|
|
@@ -132,7 +231,11 @@ const onSubmit = async () => {
|
|
|
try {
|
|
|
const checkedNodes = treeRef?.value?.getCheckedNodes() || []
|
|
|
const checkedHalfNodes = treeRef?.value?.getHalfCheckedNodes() || []
|
|
|
- const privilegeIds = checkedNodes.concat(checkedHalfNodes).map((d) => d.id)
|
|
|
+ const privilegeIds = checkedNodes
|
|
|
+ .concat(checkedHalfNodes)
|
|
|
+ .map((d) => d.id)
|
|
|
+ .filter((id) => id > -1)
|
|
|
+
|
|
|
await setPrivilege({ role: role.value, privilegeIds })
|
|
|
ElMessage.success('保存成功')
|
|
|
} catch (error) {
|
|
@@ -145,5 +248,18 @@ const onSubmit = async () => {
|
|
|
.privilege-tree {
|
|
|
width: 660px;
|
|
|
min-height: 320px;
|
|
|
+ :deep(.custom-tree-node) {
|
|
|
+ .is-page,
|
|
|
+ .is-btn {
|
|
|
+ padding: 0 5px;
|
|
|
+ font-size: 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #67c23a;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ .is-btn {
|
|
|
+ margin-left: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|