1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-12 22:29:59 +08:00

fix: Relations in context menu. (#545)

* fix: Relations in context menu.

* fix comments.

Co-authored-by: EdwinBetanc0urt <EdwinBetanco0urt@outlook.com>
This commit is contained in:
Edwin Betancourt 2020-11-23 10:17:02 -04:00 committed by GitHub
parent d55dbb1bab
commit d6f52a70e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 161 additions and 90 deletions

View File

@ -11,18 +11,20 @@
unique-opened unique-opened
@shortkey.native="actionContextMenu" @shortkey.native="actionContextMenu"
> >
<el-submenu v-if="!isEmptyValue(relationsList)" class="el-menu-item" index="1"> <!-- menu relations -->
<el-submenu v-if="!isEmptyChilds" class="el-menu-item" index="1">
<template slot="title"> <template slot="title">
{{ $t('components.contextMenuRelations') }} {{ $t('components.contextMenuRelations') }}
</template> </template>
<el-scrollbar wrap-class="scroll"> <el-scrollbar wrap-class="scroll">
<item v-for="(relation, index) in relationsList" :key="index" :item="relation" /> <items-relations v-for="(relation, index) in relationsList" :key="index" :item="relation" />
</el-scrollbar> </el-scrollbar>
</el-submenu> </el-submenu>
<el-menu-item v-else disabled index="relations"> <el-menu-item v-else disabled index="relations">
{{ $t('components.contextMenuRelations') }} {{ $t('components.contextMenuRelations') }}
</el-menu-item> </el-menu-item>
<!-- actions or process on container -->
<el-submenu v-if="!isEmptyValue(actions)" class="el-menu-item" index="actions" @click.native="runAction(actions[0])"> <el-submenu v-if="!isEmptyValue(actions)" class="el-menu-item" index="actions" @click.native="runAction(actions[0])">
<template slot="title"> <template slot="title">
{{ $t('components.contextMenuActions') }} {{ $t('components.contextMenuActions') }}
@ -100,6 +102,7 @@
{{ $t('components.contextMenuActions') }} {{ $t('components.contextMenuActions') }}
</el-menu-item> </el-menu-item>
<!-- references of record -->
<el-submenu <el-submenu
:disabled="!(isReferecesContent && isLoadedReferences)" :disabled="!(isReferecesContent && isLoadedReferences)"
class="el-menu-item" class="el-menu-item"

View File

@ -1,13 +1,17 @@
import { showNotification } from '@/utils/ADempiere/notification.js' import { showNotification } from '@/utils/ADempiere/notification.js'
import Item from './items' import ItemsRelations from './itemsRelations'
import { convertFieldsListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js' import { convertFieldsListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil.js' import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil.js'
import ROUTES from '@/utils/ADempiere/zoomWindow' import ROUTES from '@/utils/ADempiere/zoomWindow'
import relationsMixin from './relationsMixin.js'
export default { export default {
name: 'MixinContextMenu', name: 'MixinContextMenu',
mixins: [
relationsMixin
],
components: { components: {
Item ItemsRelations
}, },
props: { props: {
menuParentUuid: { menuParentUuid: {
@ -94,17 +98,6 @@ export default {
} }
return [] return []
}, },
relationsList() {
let menuUuid = this.$route.params.menuParentUuid
if (this.isEmptyValue(menuUuid)) {
menuUuid = this.menuParentUuid
}
const relations = this.$store.getters.getRelations(menuUuid)
if (relations) {
return relations.children
}
return []
},
permissionRoutes() { permissionRoutes() {
return this.$store.getters.permission_routes return this.$store.getters.permission_routes
}, },

View File

@ -13,18 +13,23 @@
unique-opened unique-opened
style="width: 258px; float: right;" style="width: 258px; float: right;"
> >
<el-submenu index="relations"> <!-- menu relations -->
<el-submenu v-if="!isEmptyChilds" index="relations">
<template slot="title"> <template slot="title">
<svg-icon icon-class="tree" /> <svg-icon icon-class="tree" />
{{ $t('components.contextMenuRelations') }} {{ $t('components.contextMenuRelations') }}
</template> </template>
<el-menu-item-group> <el-menu-item-group>
<el-scrollbar wrap-class="scroll"> <el-scrollbar wrap-class="scroll">
<item v-for="(relation, index) in relationsList" :key="index" :item="relation" /> <items-relations v-for="(relation, index) in relationsList" :key="index" :item="relation" />
</el-scrollbar> </el-scrollbar>
</el-menu-item-group> </el-menu-item-group>
</el-submenu> </el-submenu>
<el-menu-item v-else disabled index="relations">
{{ $t('components.contextMenuRelations') }}
</el-menu-item>
<!-- actions or process on container -->
<el-submenu index="actions"> <el-submenu index="actions">
<template slot="title"> <template slot="title">
<svg-icon icon-class="link" /> <svg-icon icon-class="link" />
@ -93,6 +98,7 @@
</el-menu-item-group> </el-menu-item-group>
</el-submenu> </el-submenu>
<!-- references of record -->
<el-submenu :disabled="!(isReferecesContent && isLoadedReferences)" class="el-menu-item" index="references"> <el-submenu :disabled="!(isReferecesContent && isLoadedReferences)" class="el-menu-item" index="references">
<template slot="title"> <template slot="title">
{{ $t('components.contextMenuReferences') }} {{ $t('components.contextMenuReferences') }}

View File

@ -1,4 +1,5 @@
<template> <template>
<!-- summary elememts view -->
<el-submenu <el-submenu
v-if="item.meta.type === 'summary'" v-if="item.meta.type === 'summary'"
key="is-summary" key="is-summary"
@ -9,10 +10,18 @@
<svg-icon v-if="isMobile" icon-class="nested" /> <svg-icon v-if="isMobile" icon-class="nested" />
{{ item.meta.title }} {{ item.meta.title }}
</template> </template>
<item v-for="(child, subKey) in item.children" :key="subKey" :item="child"> <el-scrollbar wrap-class="scroll-child">
{{ child.meta.title }} <el-menu-item
</item> v-for="(child, subKey) in getChilds(item)"
:key="subKey"
:index="child.meta.uuid"
>
{{ child.meta.title }}
</el-menu-item>
</el-scrollbar>
</el-submenu> </el-submenu>
<!-- item menu views -->
<el-menu-item <el-menu-item
v-else v-else
v-show="item.meta.uuid !== $route.meta.uuid" v-show="item.meta.uuid !== $route.meta.uuid"
@ -29,7 +38,7 @@
import { icon } from '@/components/ADempiere/ContextMenu/icon' import { icon } from '@/components/ADempiere/ContextMenu/icon'
export default { export default {
name: 'Item', name: 'ItemsContextMenu',
props: { props: {
item: { item: {
type: Object, type: Object,
@ -55,6 +64,15 @@ export default {
tabParent: 0 tabParent: 0
} }
}, () => {}) }, () => {})
},
getChilds(item) {
if (!this.isEmptyValue(item.children)) {
return item.children
}
if (item.meta && !this.isEmptyValue(item.meta.childs)) {
return item.meta.childs
}
return []
} }
} }
} }

View File

@ -0,0 +1,44 @@
export default {
name: 'RelationsMixin',
computed: {
relationsList() {
let menuUuid = this.$route.params.menuParentUuid
if (this.isEmptyValue(menuUuid)) {
menuUuid = this.menuParentUuid
}
const relations = this.$store.getters.getRelations(menuUuid)
if (!this.isEmptyValue(relations.children)) {
return relations.children
}
if (relations.meta && !this.isEmptyValue(relations.meta.childs)) {
return relations.meta.childs
}
return []
},
isEmptyChilds() {
const childs = this.relationsList
const len = childs.length
if (len < 1) {
return true
}
if (len === 1) {
// diferent to current view
return childs[0].meta.uuid === this.$route.meta.uuid
}
return false
}
},
methods: {
getChilds(item) {
if (!this.isEmptyValue(item.children)) {
return item.children
}
if (item.meta && !this.isEmptyValue(item.meta.childs)) {
return item.meta.childs
}
return []
}
}
}

View File

@ -1,5 +1,5 @@
<template> <template>
<el-col v-if="items.children" key="is-desktop-dropdown" :span="24"> <el-col v-if="!isEmptyValue(items.children)" key="is-desktop-dropdown" :span="24">
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<el-collapse-item :title="title" name="1" class="collapse-item"> <el-collapse-item :title="title" name="1" class="collapse-item">
<el-row justify="space-around"> <el-row justify="space-around">
@ -46,7 +46,7 @@
<script> <script>
export default { export default {
name: 'Dropdown', name: 'DropdownMenu',
props: { props: {
items: { items: {
type: Object, type: Object,

View File

@ -4,7 +4,13 @@ import staticRoutes from '@/router/modules/ADempiere/staticRoutes.js'
/* Layout */ /* Layout */
import Layout from '@/layout' import Layout from '@/layout'
// Get Menu from server /**
* Get Menu from server
* @author Edwin Betancourt <EdwinBetanc0urt@outlook.com>
* @param {string} sessionUuid
* @param {string} roleUuid
* @param {string} organizationUuid
*/
export function loadMainMenu({ export function loadMainMenu({
sessionUuid, sessionUuid,
roleUuid = 0, roleUuid = 0,
@ -32,7 +38,6 @@ export function loadMainMenu({
organizationUuid organizationUuid
}) })
optionMenu.children.push(childsSumaryConverted) optionMenu.children.push(childsSumaryConverted)
optionMenu.children[0].meta.childs.push(childsSumaryConverted)
optionMenu.meta.childs.push(childsSumaryConverted) optionMenu.meta.childs.push(childsSumaryConverted)
}) })
} else { } else {
@ -58,15 +63,16 @@ export function loadMainMenu({
/** /**
* Get Only Child * Get Only Child
* @author Edwin Betancourt <EdwinBetanc0urt@outlook.com>
* @param {object} menu * @param {object} menu
* @param {number} index * @param {number} index
* @param {number} roleUuid * @param {string} roleUuid
* @param {number} organizationUuid * @param {string} organizationUuid
*/ */
function getChildFromAction({ menu, index, roleUuid, organizationUuid }) { function getChildFromAction({ menu, index, roleUuid, organizationUuid }) {
const { component, icon, name, isIndex } = convertAction(menu.action) const { component, icon, name: type } = convertAction(menu.action)
const routeIdentifier = name + '/' + menu.id const routeIdentifier = type + '/' + menu.id
const isIndex = menu.is_summary
const option = { const option = {
path: '/' + roleUuid + '/' + organizationUuid + '/' + routeIdentifier, path: '/' + roleUuid + '/' + organizationUuid + '/' + routeIdentifier,
component, component,
@ -85,14 +91,14 @@ function getChildFromAction({ menu, index, roleUuid, organizationUuid }) {
referenceUuid: menu.reference_uuid, referenceUuid: menu.reference_uuid,
tabUuid: '', tabUuid: '',
title: menu.name, title: menu.name,
type: name, type,
uuid: menu.reference_uuid, uuid: menu.reference_uuid,
childs: [] childs: []
} },
children: []
} }
if (isIndex || name === 'summary') { if (isIndex) {
option['children'] = []
menu.childs.forEach(child => { menu.childs.forEach(child => {
const menuConverted = getChildFromAction({ const menuConverted = getChildFromAction({
menu: child, menu: child,
@ -111,50 +117,34 @@ function getChildFromAction({ menu, index, roleUuid, organizationUuid }) {
/** /**
* Convert menu item from server to Route * Convert menu item from server to Route
* @author elsiosanchez <elsiosanches@gmail.com> * @author elsiosanchez <elsiosanches@gmail.com>
* @author Edwin Betancourt <EdwinBetanc0urt@outlook.com>
* @param {object} menu * @param {object} menu
* @param {number} roleUuid * @param {string} roleUuid
* @param {number} organizationUuid * @param {string} organizationUuid
*/ */
function getRouteFromMenuItem({ menu, roleUuid, organizationUuid }) { function getRouteFromMenuItem({ menu, roleUuid, organizationUuid }) {
const { component, icon, name, isIndex } = convertAction(menu.action) // use component of convertAction
const { icon, name: type } = convertAction(menu.action)
const isIndex = menu.is_summary
const optionMenu = { const optionMenu = {
path: '/' + roleUuid + '/' + organizationUuid + '/' + menu.id, path: '/' + roleUuid + '/' + organizationUuid + '/' + menu.id,
redirect: '/' + menu.id + '/index', redirect: '/' + menu.id,
component: Layout, component: Layout,
name: menu.uuid, name: menu.uuid,
meta: { meta: {
description: menu.description, description: menu.description,
icon, icon,
isIndex,
isReadOnly: menu.is_read_only, isReadOnly: menu.is_read_only,
isSummary: menu.is_summary, isSummary: menu.is_summary,
isSalesTransaction: menu.is_sales_transaction, isSalesTransaction: menu.is_sales_transaction,
noCache: true, noCache: true,
referenceUuid: menu.reference_uuid, referenceUuid: menu.reference_uuid,
title: menu.name, title: menu.name,
type: name, type,
childs: [] childs: []
}, },
children: [{ children: []
path: 'index',
component,
name: menu.uuid + '-index',
hidden: true,
meta: {
breadcrumb: false,
description: menu.description,
icon,
isIndex,
isReadOnly: menu.is_read_only,
isSalesTransaction: menu.is_sales_transaction,
noCache: true,
parentUuid: menu.uuid,
referenceUuid: menu.reference_uuid,
title: menu.name,
type: name,
childs: []
}
}]
} }
return optionMenu return optionMenu
} }

View File

@ -145,12 +145,12 @@ const contextMenu = {
getContextMenu: (state) => (containerUuid) => { getContextMenu: (state) => (containerUuid) => {
return state.contextMenu.find(item => item.containerUuid === containerUuid) return state.contextMenu.find(item => item.containerUuid === containerUuid)
}, },
getRelations: (state, getters, rootState, rootGetters) => (containerUuid) => { getRelations: (state, getters, rootState, rootGetters) => (containerOrMenuUuid) => {
const dataTree = rootGetters.permission_routes const dataTree = rootGetters.permission_routes
return recursiveTreeSearch({ return recursiveTreeSearch({
treeData: dataTree, treeData: dataTree,
attributeName: 'name', attributeName: 'name',
attributeValue: containerUuid, attributeValue: containerOrMenuUuid,
attributeChilds: 'children' attributeChilds: 'children'
}) })
}, },

View File

@ -24,30 +24,25 @@ const mutations = {
} }
const actions = { const actions = {
generateRoutes({ commit, rootGetters }, organizationId = 0) { generateRoutes({ commit, rootGetters }) {
return new Promise(resolve => { return new Promise(resolve => {
const organization = rootGetters['user/getOrganization'] const organization = rootGetters['user/getOrganization']
let organizationUuid let organizationUuid
if (!isEmptyValue(organization)) { if (!isEmptyValue(organization)) {
organizationId = organization.id
organizationUuid = organization.uuid organizationUuid = organization.uuid
} }
const role = rootGetters['user/getRole'] const role = rootGetters['user/getRole']
let roleUuid let roleUuid
let clientId = 0
if (!isEmptyValue(role)) { if (!isEmptyValue(role)) {
roleUuid = role.uuid roleUuid = role.uuid
clientId = role.clientId
} }
const sessionUuid = getToken() const sessionUuid = getToken()
loadMainMenu({ loadMainMenu({
sessionUuid, sessionUuid,
clientId,
roleUuid, roleUuid,
organizationId,
organizationUuid organizationUuid
}).then(menuResponse => { }).then(menuResponse => {
commit('SET_ROUTES', menuResponse) commit('SET_ROUTES', menuResponse)
@ -55,7 +50,7 @@ const actions = {
}) })
}) })
}, },
sendRequestMenu({ commit, dispatch }, organizationId = null) { sendRequestMenu({ commit, dispatch }) {
commit('clearTimeOutMenu') commit('clearTimeOutMenu')
const timeOutMenu = setTimeout(async() => { const timeOutMenu = setTimeout(async() => {
NProgress NProgress
@ -66,7 +61,7 @@ const actions = {
.start() .start()
resetRouter() resetRouter()
dispatch('generateRoutes', organizationId) dispatch('generateRoutes')
.then(accessRoutes => { .then(accessRoutes => {
router.addRoutes(accessRoutes) router.addRoutes(accessRoutes)
}) })

View File

@ -424,7 +424,7 @@ const actions = {
console.warn(`Error change role: ${error.message}. Code: ${error.code}.`) console.warn(`Error change role: ${error.message}. Code: ${error.code}.`)
}) })
.finally(() => { .finally(() => {
dispatch('permission/sendRequestMenu', organizationId, { dispatch('permission/sendRequestMenu', null, {
root: true root: true
}) })
}) })

View File

@ -177,29 +177,35 @@ export function convertFieldsListToShareLink(fieldsList) {
/** /**
* Find element in an array recursively * Find element in an array recursively
* @param {object|array} treeData * @author Edwin Betancourt <EdwinBetanc0urt@outlook.com>
* @param {string} attributeName, key to get value, default id * @param {object|array} treeData object recursive array
* @param {string} attributeName, key to get value, default 'id'
* @param {string} secondAttributeName, key to get value, default 'meta'
* @param {mixed} attributeValue, value to compare with search * @param {mixed} attributeValue, value to compare with search
* @param {string} attributeChilds, childs list into element * @param {string} attributeChilds, 'childs' list into element
*/ */
export const recursiveTreeSearch = ({ export const recursiveTreeSearch = ({
treeData, treeData,
attributeValue, attributeValue,
attributeName = 'id', attributeName = 'id',
secondAttribute = false, secondAttributeName = '',
attributeChilds = 'childsList', attributeChilds = 'childsList',
isParent = false isParent = false
}) => { }) => {
if (Array.isArray(treeData)) { if (Array.isArray(treeData)) {
// search in childs attribute
let index = 0 let index = 0
const length = treeData.length const length = treeData.length
while (index < length) { while (index < length) {
let value = treeData[index] let value = treeData[index]
if (!isEmptyValue(value) && Object.prototype.hasOwnProperty.call(value, attributeName)) { if (!isEmptyValue(value) &&
Object.prototype.hasOwnProperty.call(value, attributeName)) {
value = value[attributeName] value = value[attributeName]
} }
if (!isEmptyValue(value) && secondAttribute && Object.prototype.hasOwnProperty.call(value, secondAttribute)) { if (!isEmptyValue(value) &&
value = value[secondAttribute] secondAttributeName &&
Object.prototype.hasOwnProperty.call(value, secondAttributeName)) {
value = value[secondAttributeName]
} }
// compare item to search // compare item to search
@ -208,11 +214,12 @@ export const recursiveTreeSearch = ({
} }
if (treeData[index] && treeData[index][attributeChilds]) { if (treeData[index] && treeData[index][attributeChilds]) {
const newTree = treeData[index][attributeChilds]
const found = recursiveTreeSearch({ const found = recursiveTreeSearch({
treeData: treeData[index][attributeChilds], treeData: newTree,
attributeValue, attributeValue,
attributeName, attributeName,
secondAttribute, secondAttributeName,
attributeChilds, attributeChilds,
isParent isParent
}) })
@ -223,12 +230,16 @@ export const recursiveTreeSearch = ({
index++ index++
} }
} else { } else {
// search into meta attribute
let value = treeData let value = treeData
if (!isEmptyValue(value) && Object.prototype.hasOwnProperty.call(value, attributeName)) { if (!isEmptyValue(value) &&
Object.prototype.hasOwnProperty.call(value, attributeName)) {
value = value[attributeName] value = value[attributeName]
} }
if (!isEmptyValue(value) && secondAttribute && Object.prototype.hasOwnProperty.call(value, secondAttribute)) { if (!isEmptyValue(value) &&
value = value[secondAttribute] secondAttributeName &&
Object.prototype.hasOwnProperty.call(value, secondAttributeName)) {
value = value[secondAttributeName]
} }
// compare item to search // compare item to search
@ -240,7 +251,7 @@ export const recursiveTreeSearch = ({
treeData: treeData[attributeChilds], treeData: treeData[attributeChilds],
attributeValue, attributeValue,
attributeName, attributeName,
secondAttribute, secondAttributeName,
attributeChilds attributeChilds
}) })
return found return found
@ -400,6 +411,7 @@ export function tagStatus(tag) {
} }
return type return type
} }
/** /**
* add a tab depending on the status of the document * add a tab depending on the status of the document
* @param {string} tag, document status key * @param {string} tag, document status key

View File

@ -10,14 +10,24 @@
/> />
<h3 v-popover:routeDescription class="description">{{ $route.meta.title }}</h3> <h3 v-popover:routeDescription class="description">{{ $route.meta.title }}</h3>
<el-row :gutter="10"> <el-row :gutter="10">
<template v-if="optionList.children"> <template v-if="!isEmptyValue(optionList.children)">
<template v-for="(item, key) in optionList.children"> <template v-for="(item, key) in optionList.children">
<dropdown v-if="$route.name !== item.name" :key="key" :items="item" :title="item.meta.title" /> <dropdown-menu
v-if="$route.name !== item.name"
:key="key"
:items="item"
:title="item.meta.title"
/>
</template> </template>
</template> </template>
<template v-else> <template v-else>
<template v-for="(item, key) in optionList"> <template v-for="(item, key) in optionList">
<dropdown v-if="$route.name !== item.name" :key="key" :items="item" :title="item.meta.title" /> <dropdown-menu
v-if="$route.name !== item.name"
:key="key"
:items="item"
:title="item.meta.title"
/>
</template> </template>
</template> </template>
</el-row> </el-row>
@ -28,12 +38,12 @@
</template> </template>
<script> <script>
import Dropdown from '@/components/ADempiere/Dropdown' import DropdownMenu from '@/components/ADempiere/DropdownMenu'
export default { export default {
name: 'Summary', name: 'SummaryView',
components: { components: {
Dropdown DropdownMenu
}, },
data() { data() {
return { return {