vue-element-admin/src/components/ADempiere/Field/FieldOptions/index.vue

517 lines
14 KiB
Vue

<!--
ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution
Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A.
Contributor(s): Edwin Betancourt EdwinBetanc0urt@oulook.com www.erpya.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https:www.gnu.org/licenses/>.
-->
<template>
<div>
<el-dropdown
v-if="isMobile"
key="options-mobile"
size="mini"
hide-on-click
trigger="click"
:style="'text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width:' + labelStyle + '%'"
@command="handleCommand"
@click="false"
>
<div style="display: flex;width: auto;">
<span :style="metadata.required && isEmptyValue(valueField) ? 'border: aqua; color: #f34b4b' : 'border: aqua;'">
<span key="is-field-name">
<!-- label or name of field in mobile -->
{{ metadata.name }}
</span>
</span>
</div>
<el-dropdown-menu slot="dropdown">
<template
v-for="(option, key) in optionsList"
>
<el-dropdown-item
v-if="option.enabled"
:key="key"
:command="option"
divided
>
<div class="contents">
<div
v-if="option.svg"
key="icon-svg-mobile"
style="margin-right: 5%"
>
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</div>
<div
v-else
key="icon-mobile"
style="margin-right: 5%;padding-top: 3%;"
>
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div>
<span class="contents">
<b class="label">
{{ option.name }}
</b>
</span>
</div>
</div>
</el-dropdown-item>
</template>
</el-dropdown-menu>
</el-dropdown>
<el-menu
v-else-if="!isMobile && metadata.panelType !== 'form'"
key="options-desktop"
class="el-menu-demo"
mode="horizontal"
unique-opened
style="z-index: 0"
:menu-trigger="triggerMenu"
@open="handleOpen"
@close="handleClose"
@select="handleSelect"
>
<el-submenu index="menu">
<template slot="title">
<div style="display: block;">
<span :style="metadata.required && isEmptyValue(valueField) ? 'border: aqua; color: #f34b4b' : 'border: aqua;'">
<span key="is-field-name">
<!-- label or name of field in desktop -->
{{ metadata.name }}
</span>
</span>
</div>
</template>
<el-menu-item
v-for="(option, key) in optionsList"
:key="key"
:index="option.name"
>
<el-popover
placement="top"
trigger="click"
style="padding: 0px; max-width: 400px"
@hide="closePopover"
>
<component
:is="option.componentRender"
v-if="visibleForDesktop && showPanelFieldOption"
:field-attributes="fieldAttributes"
:field-value="valueField"
/>
<el-button slot="reference" type="text" style="color: #606266;">
<div class="contents">
<div
v-if="option.svg"
key="icon-svg-desktop"
style="margin-right: 5%;; padding-left: 2%;"
>
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</div>
<div
v-else
key="icon-desktop"
style="margin-right: 5%;padding-top: 3%;"
>
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div>
<span class="contents">
<b class="label">
{{ option.name }}
</b>
</span>
</div>
</div>
</el-button>
</el-popover>
</el-menu-item>
</el-submenu>
</el-menu>
<span v-else key="options-form">
<!-- label or name of field in form -->
{{ metadata.name }}
</span>
</div>
</template>
<script>
import { defineComponent, computed, ref, watch } from '@vue/composition-api'
import {
optionsListStandad, optionsListAdvancedQuery,
documentStatusOptionItem, translateOptionItem,
zoomInOptionItem, calculatorOptionItem
} from '@/components/ADempiere/Field/FieldOptions/fieldOptionsList.js'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
export default defineComponent({
name: 'FieldOptions',
props: {
metadata: {
type: Object
}
},
setup(props, { root }) {
const visibleForDesktop = ref(false)
const showPopoverPath = ref(false)
const triggerMenu = ref('click')
const optionColumnName = ref(root.$route.query.fieldColumnName)
const isMobile = computed(() => {
return root.$store.state.app.device === 'mobile'
})
const valueField = computed(() => {
const { parentUuid, containerUuid, columnName } = props.metadata
return root.$store.getters.getValueOfField({
parentUuid,
containerUuid,
columnName
})
})
setTimeout(() => {
if (isMobile.value && optionColumnName.value === props.metadata.columnName) {
root.$store.commit('changeShowRigthPanel', true)
root.$store.dispatch('setOptionField', {
fieldAttributes: props.metadata,
name: root.$route.query.typeAction,
valueField: valueField.value
})
} else {
showPopoverPath.value = true
}
}, 2000)
const panelContextMenu = computed(() => {
return root.$store.state.contextMenu.isShowRightPanel
})
const showPanelFieldOption = computed(() => {
return root.$store.state.contextMenu.isShowOptionField
})
const labelStyle = computed(() => {
if (props.metadata.name.length >= 25) {
return '35'
} else if (props.metadata.name.length >= 20) {
return '50'
}
return '110'
})
const permissionRoutes = computed(() => {
return root.$store.getters.permission_routes
})
const redirect = ({ window }) => {
const viewSearch = recursiveTreeSearch({
treeData: permissionRoutes.value,
attributeValue: window.uuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
root.$router.push({
name: viewSearch.name,
query: {
action: 'advancedQuery',
tabParent: 0,
[props.metadata.columnName]: valueField
}
}, () => {})
} else {
root.$message({
type: 'error',
showClose: true,
message: root.$t('notifications.noRoleAccess')
})
}
}
const handleCommand = (command) => {
root.$store.commit('setRecordAccess', false)
if (command.name === root.$t('table.ProcessActivity.zoomIn')) {
if (!root.isEmptyValue(props.metadata.reference.zoomWindows)) {
redirect({
window: props.metadata.reference.zoomWindows[0]
})
}
return
}
if (isMobile.value) {
root.$store.commit('changeShowRigthPanel', true)
} else {
visibleForDesktop.value = true
}
root.$store.commit('changeShowPopoverField', true)
root.$store.dispatch('setOptionField', {
...command,
fieldAttributes: props.metadata
})
}
const isContextInfo = computed(() => {
const field = props.metadata
if (!field.isPanelWindow) {
return false
}
return Boolean(field.contextInfo &&
field.contextInfo.isActive) ||
Boolean(field.reference &&
!root.isEmptyValue(field.reference.zoomWindows))
})
const isDocuemntStatus = computed(() => {
if (props.metadata.isPanelWindow && !props.metadata.isAdvancedQuery) {
const { parentUuid, containerUuid, columnName } = props.metadata
if (columnName === 'DocStatus') {
const statusValue = root.$store.getters.getValueOfField({
parentUuid,
containerUuid,
columnName
})
// if (!root.isEmptyValue(root.$store.getters.getOrders)) {
if (!root.isEmptyValue(statusValue)) {
return true
}
}
}
return false
})
const optionsList = computed(() => {
const menuOptions = []
if (props.metadata.isNumericField) {
menuOptions.push(calculatorOptionItem)
}
// infoOption, operatorOption
if (props.metadata.isAdvancedQuery) {
return menuOptions.concat(optionsListAdvancedQuery)
}
if (isContextInfo.value) {
menuOptions.push(zoomInOptionItem)
}
if (props.metadata.isPanelWindow) {
if (props.metadata.isTranslatedField) {
menuOptions.push(translateOptionItem)
}
if (isDocuemntStatus.value) {
menuOptions.push(documentStatusOptionItem)
}
}
return menuOptions.concat(optionsListStandad)
})
const openOptionField = computed({
get() {
const option = optionsList.value.find(option => {
return root.$route.query.typeAction === option.name
})
if (!root.isEmptyValue(root.$route.query) && option) {
return true
}
return false
},
set(value) {
if (!value) {
showPopoverPath.value = false
root.$router.push({
name: root.$route.name,
query: {
...root.$route.query,
typeAction: '',
fieldColumnName: ''
}
}, () => {})
}
}
})
const closePopover = () => {
root.$router.push({
name: root.$route.name,
query: {
...root.$route.query,
typeAction: '',
fieldColumnName: ''
}
}, () => {})
}
const handleOpen = (key, keyPath) => {
triggerMenu.value = 'hover'
}
const handleClose = (key, keyPath) => {
triggerMenu.value = 'click'
}
const handleSelect = (key, keyPath) => {
if (key === root.$t('table.ProcessActivity.zoomIn')) {
redirect({
window: props.metadata.reference.zoomWindows[0]
})
return
}
if (isMobile.value) {
root.$store.commit('changeShowRigthPanel', true)
} else {
root.$store.commit('changeShowOptionField', true)
visibleForDesktop.value = true
root.$router.push({
name: root.$route.name,
query: {
...root.$route.query,
typeAction: key,
fieldColumnName: props.metadata.columnName
}
}, () => {})
}
root.$store.commit('changeShowPopoverField', true)
const option = optionsList.value.find(option => {
return option.name === key
})
root.$store.dispatch('setOptionField', {
...option,
valueField: valueField.value,
fieldAttributes: props.metadata
})
triggerMenu.value = 'hover'
}
watch(panelContextMenu, (newValue, oldValue) => {
visibleForDesktop.value = false
})
watch(openOptionField, (newValue, oldValue) => {
if (!newValue) {
showPopoverPath.value = false
}
})
const fieldAttributes = ref(props.metadata)
return {
isMobile,
labelStyle,
fieldAttributes,
optionsList,
closePopover,
openOptionField,
handleCommand,
handleOpen,
handleClose,
handleSelect,
isDocuemntStatus,
visibleForDesktop,
valueField,
triggerMenu,
showPanelFieldOption
}
}
})
</script>
<style>
.el-popover {
position: fixed;
padding: 0px;
}
.el-textarea {
position: relative;
width: 100%;
vertical-align: bottom;
font-size: 14px;
display: flex;
}
.el-menu--horizontal > .el-submenu .el-submenu__title {
height: 60px;
line-height: 60px;
border-bottom: 2px solid transparent;
color: #535457e3;
}
</style>
<style scoped>
.el-form--label-top .el-form-item__label {
padding-bottom: 0px !important;
display: block;
}
.el-menu.el-menu--horizontal {
border-bottom: solid 0px #E6E6E6;
}
.svg-icon {
width: 1em;
height: 1.5em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.el-dropdown .el-button-group {
display: flex;
}
.el-dropdown-menu {
position: absolute;
top: 0;
left: 0;
z-index: 10;
padding: 0px;
margin: 0px;
background-color: #FFFFFF;
border: 1px solid #e6ebf5;
border-radius: 4px;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
max-height: 250px;
max-width: 220px;
overflow: auto;
}
.el-dropdown-menu--mini .el-dropdown-menu__item {
line-height: 14px;
padding: 0px 15px;
padding-top: 1%;
padding-right: 15px;
padding-bottom: 1%;
padding-left: 15px;
font-size: 10px;
}
.el-dropdown-menu__item--divided {
position: relative;
/* margin-top: 6px; */
border-top: 1px solid #e6ebf5;
}
.label {
font-size: 14px;
margin-top: 0% !important;
margin-left: 0px;
text-align: initial;
}
.description {
margin: 0px;
font-size: 12px;
text-align: initial;
}
.contents {
display: inline-flex;
}
</style>